// Copyright (C) 2002-2012 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h #ifndef __C_Q3_LEVEL_MESH_H_INCLUDED__ #define __C_Q3_LEVEL_MESH_H_INCLUDED__ #include "IQ3LevelMesh.h" #include "IReadFile.h" #include "IFileSystem.h" #include "SMesh.h" #include "SMeshBufferLightMap.h" #include "IVideoDriver.h" #include "irrString.h" #include "ISceneManager.h" #include "os.h" namespace irr { namespace scene { class CQ3LevelMesh : public IQ3LevelMesh { public: //! constructor CQ3LevelMesh(io::IFileSystem* fs, scene::ISceneManager* smgr, const quake3::Q3LevelLoadParameter &loadParam); //! destructor virtual ~CQ3LevelMesh(); //! loads a level from a .bsp-File. Also tries to load all //! needed textures. Returns true if successful. bool loadFile(io::IReadFile* file); //! returns the amount of frames in milliseconds. If the amount //! is 1, it is a static (=non animated) mesh. virtual u32 getFrameCount() const _IRR_OVERRIDE_; //! Gets the default animation speed of the animated mesh. /** \return Amount of frames per second. If the amount is 0, it is a static, non animated mesh. */ virtual f32 getAnimationSpeed() const _IRR_OVERRIDE_ { return FramesPerSecond; } //! Gets the frame count of the animated mesh. /** \param fps Frames per second to play the animation with. If the amount is 0, it is not animated. The actual speed is set in the scene node the mesh is instantiated in.*/ virtual void setAnimationSpeed(f32 fps) _IRR_OVERRIDE_ { FramesPerSecond=fps; } //! returns the animated mesh based on a detail level. 0 is the //! lowest, 255 the highest detail. Note, that some Meshes will //! ignore the detail level. virtual IMesh* getMesh(s32 frameInMs, s32 detailLevel=255, s32 startFrameLoop=-1, s32 endFrameLoop=-1) _IRR_OVERRIDE_; //! Returns an axis aligned bounding box of the mesh. //! \return A bounding box of this mesh is returned. virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; virtual void setBoundingBox( const core::aabbox3df& box) _IRR_OVERRIDE_; //! Returns the type of the animated mesh. virtual E_ANIMATED_MESH_TYPE getMeshType() const _IRR_OVERRIDE_; //! loads the shader definition void getShader( io::IReadFile* file ); //! loads the shader definition virtual const quake3::IShader * getShader( const c8 * filename, bool fileNameIsValid=true ) _IRR_OVERRIDE_; //! returns a already loaded Shader virtual const quake3::IShader * getShader( u32 index ) const _IRR_OVERRIDE_; //! loads a configuration file void getConfiguration( io::IReadFile* file ); //! get's an interface to the entities virtual quake3::tQ3EntityList & getEntityList() _IRR_OVERRIDE_; //! returns the requested brush entity virtual IMesh* getBrushEntityMesh(s32 num) const _IRR_OVERRIDE_; //! returns the requested brush entity virtual IMesh* getBrushEntityMesh(quake3::IEntity &ent) const _IRR_OVERRIDE_; //Link to held meshes? ... //! returns amount of mesh buffers. virtual u32 getMeshBufferCount() const _IRR_OVERRIDE_ { return 0; } //! returns pointer to a mesh buffer virtual IMeshBuffer* getMeshBuffer(u32 nr) const _IRR_OVERRIDE_ { return 0; } //! Returns pointer to a mesh buffer which fits a material /** \param material: material to search for \return Pointer to the mesh buffer or 0 if there is no such mesh buffer. */ virtual IMeshBuffer* getMeshBuffer( const video::SMaterial &material) const _IRR_OVERRIDE_ { return 0; } virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) _IRR_OVERRIDE_ { return; } //! set the hardware mapping hint, for driver virtual void setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) _IRR_OVERRIDE_ { return; } //! flags the meshbuffer as changed, reloads hardware buffers virtual void setDirty(E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) _IRR_OVERRIDE_ { return; } private: void constructMesh(); void solveTJunction(); void loadTextures(); scene::SMesh** buildMesh(s32 num); struct STexShader { video::ITexture* Texture; s32 ShaderID; }; core::array< STexShader > Tex; core::array Lightmap; enum eLumps { kEntities = 0, // Stores player/object positions, etc... kShaders = 1, // Stores texture information kPlanes = 2, // Stores the splitting planes kNodes = 3, // Stores the BSP nodes kLeafs = 4, // Stores the leafs of the nodes kLeafFaces = 5, // Stores the leaf's indices into the faces kLeafBrushes = 6, // Stores the leaf's indices into the brushes kModels = 7, // Stores the info of world models kBrushes = 8, // Stores the brushes info (for collision) kBrushSides = 9, // Stores the brush surfaces info kVertices = 10, // Stores the level vertices kMeshVerts = 11, // Stores the model vertices offsets kFogs = 12, // Stores the shader files (blending, anims..) kFaces = 13, // Stores the faces for the level kLightmaps = 14, // Stores the lightmaps for the level kLightGrid = 15, // Stores extra world lighting information kVisData = 16, // Stores PVS and cluster info (visibility) kLightArray = 17, // RBSP kMaxLumps // A constant to store the number of lumps }; enum eBspSurfaceType { BSP_MST_BAD, BSP_MST_PLANAR, BSP_MST_PATCH, BSP_MST_TRIANGLE_SOUP, BSP_MST_FLARE, BSP_MST_FOLIAGE }; struct tBSPHeader { s32 strID; // This should always be 'IBSP' s32 version; // This should be 0x2e for Quake 3 files }; tBSPHeader header; struct tBSPLump { s32 offset; s32 length; }; struct tBSPVertex { f32 vPosition[3]; // (x, y, z) position. f32 vTextureCoord[2]; // (u, v) texture coordinate f32 vLightmapCoord[2]; // (u, v) lightmap coordinate f32 vNormal[3]; // (x, y, z) normal vector u8 color[4]; // RGBA color for the vertex }; struct tBSPFace { s32 textureID; // The index into the texture array s32 fogNum; // The index for the effects (or -1 = n/a) s32 type; // 1=polygon, 2=patch, 3=mesh, 4=billboard s32 vertexIndex; // The index into this face's first vertex s32 numOfVerts; // The number of vertices for this face s32 meshVertIndex; // The index into the first meshvertex s32 numMeshVerts; // The number of mesh vertices s32 lightmapID; // The texture index for the lightmap s32 lMapCorner[2]; // The face's lightmap corner in the image s32 lMapSize[2]; // The size of the lightmap section f32 lMapPos[3]; // The 3D origin of lightmap. f32 lMapBitsets[2][3]; // The 3D space for s and t unit vectors. f32 vNormal[3]; // The face normal. s32 size[2]; // The bezier patch dimensions. }; struct tBSPTexture { c8 strName[64]; // The name of the texture w/o the extension u32 flags; // The surface flags (unknown) u32 contents; // The content flags (unknown) }; struct tBSPLightmap { u8 imageBits[128][128][3]; // The RGB data in a 128x128 image }; struct tBSPNode { s32 plane; // The index into the planes array s32 front; // The child index for the front node s32 back; // The child index for the back node s32 mins[3]; // The bounding box min position. s32 maxs[3]; // The bounding box max position. }; struct tBSPLeaf { s32 cluster; // The visibility cluster s32 area; // The area portal s32 mins[3]; // The bounding box min position s32 maxs[3]; // The bounding box max position s32 leafface; // The first index into the face array s32 numOfLeafFaces; // The number of faces for this leaf s32 leafBrush; // The first index for into the brushes s32 numOfLeafBrushes; // The number of brushes for this leaf }; struct tBSPPlane { f32 vNormal[3]; // Plane normal. f32 d; // The plane distance from origin }; struct tBSPVisData { s32 numOfClusters; // The number of clusters s32 bytesPerCluster; // Bytes (8 bits) in the cluster's bitset c8 *pBitsets; // Array of bytes holding the cluster vis. }; struct tBSPBrush { s32 brushSide; // The starting brush side for the brush s32 numOfBrushSides; // Number of brush sides for the brush s32 textureID; // The texture index for the brush }; struct tBSPBrushSide { s32 plane; // The plane index s32 textureID; // The texture index }; struct tBSPModel { f32 min[3]; // The min position for the bounding box f32 max[3]; // The max position for the bounding box. s32 faceIndex; // The first face index in the model s32 numOfFaces; // The number of faces in the model s32 brushIndex; // The first brush index in the model s32 numOfBrushes; // The number brushes for the model }; struct tBSPFog { c8 shader[64]; // The name of the shader file s32 brushIndex; // The brush index for this shader s32 visibleSide; // the brush side that ray tests need to clip against (-1 == none }; core::array < STexShader > FogMap; struct tBSPLights { u8 ambient[3]; // This is the ambient color in RGB u8 directional[3]; // This is the directional color in RGB u8 direction[2]; // The direction of the light: [phi,theta] }; void loadTextures (tBSPLump* l, io::IReadFile* file); // Load the textures void loadLightmaps (tBSPLump* l, io::IReadFile* file); // Load the lightmaps void loadVerts (tBSPLump* l, io::IReadFile* file); // Load the vertices void loadFaces (tBSPLump* l, io::IReadFile* file); // Load the faces void loadPlanes (tBSPLump* l, io::IReadFile* file); // Load the Planes of the BSP void loadNodes (tBSPLump* l, io::IReadFile* file); // load the Nodes of the BSP void loadLeafs (tBSPLump* l, io::IReadFile* file); // load the Leafs of the BSP void loadLeafFaces (tBSPLump* l, io::IReadFile* file); // load the Faces of the Leafs of the BSP void loadVisData (tBSPLump* l, io::IReadFile* file); // load the visibility data of the clusters void loadEntities (tBSPLump* l, io::IReadFile* file); // load the entities void loadModels (tBSPLump* l, io::IReadFile* file); // load the models void loadMeshVerts (tBSPLump* l, io::IReadFile* file); // load the mesh vertices void loadBrushes (tBSPLump* l, io::IReadFile* file); // load the brushes of the BSP void loadBrushSides (tBSPLump* l, io::IReadFile* file); // load the brushsides of the BSP void loadLeafBrushes(tBSPLump* l, io::IReadFile* file); // load the brushes of the leaf void loadFogs (tBSPLump* l, io::IReadFile* file); // load the shaders //bi-quadratic bezier patches void createCurvedSurface_bezier(SMeshBufferLightMap* meshBuffer, s32 faceIndex, s32 patchTesselation, s32 storevertexcolor); void createCurvedSurface_nosubdivision(SMeshBufferLightMap* meshBuffer, s32 faceIndex, s32 patchTesselation, s32 storevertexcolor); struct S3DVertex2TCoords_64 { core::vector3d Pos; core::vector3d Normal; video::SColorf Color; core::vector2d TCoords; core::vector2d TCoords2; void copy( video::S3DVertex2TCoords &dest ) const; S3DVertex2TCoords_64() {} S3DVertex2TCoords_64(const core::vector3d& pos, const core::vector3d& normal, const video::SColorf& color, const core::vector2d& tcoords, const core::vector2d& tcoords2) : Pos(pos), Normal(normal), Color(color), TCoords(tcoords), TCoords2(tcoords2) {} S3DVertex2TCoords_64 getInterpolated_quadratic(const S3DVertex2TCoords_64& v2, const S3DVertex2TCoords_64& v3, const f64 d) const { return S3DVertex2TCoords_64 ( Pos.getInterpolated_quadratic ( v2.Pos, v3.Pos, d ), Normal.getInterpolated_quadratic ( v2.Normal, v3.Normal, d ), Color.getInterpolated_quadratic ( v2.Color, v3.Color, (f32) d ), TCoords.getInterpolated_quadratic ( v2.TCoords, v3.TCoords, d ), TCoords2.getInterpolated_quadratic ( v2.TCoords2, v3.TCoords2, d )); } }; inline void copy( video::S3DVertex2TCoords * dest, const tBSPVertex * source, s32 vertexcolor ) const; void copy( S3DVertex2TCoords_64 * dest, const tBSPVertex * source, s32 vertexcolor ) const; struct SBezier { SMeshBufferLightMap *Patch; S3DVertex2TCoords_64 control[9]; void tesselate(s32 level); private: core::array column[3]; }; SBezier Bezier; quake3::Q3LevelLoadParameter LoadParam; tBSPLump Lumps[kMaxLumps]; tBSPTexture* Textures; s32 NumTextures; tBSPLightmap* LightMaps; s32 NumLightMaps; tBSPVertex* Vertices; s32 NumVertices; tBSPFace* Faces; s32 NumFaces; tBSPModel* Models; s32 NumModels; tBSPPlane* Planes; s32 NumPlanes; tBSPNode* Nodes; s32 NumNodes; tBSPLeaf* Leafs; s32 NumLeafs; s32 *LeafFaces; s32 NumLeafFaces; s32 *MeshVerts; // The vertex offsets for a mesh s32 NumMeshVerts; tBSPBrush* Brushes; s32 NumBrushes; scene::SMesh** BrushEntities; scene::SMesh* Mesh[quake3::E_Q3_MESH_SIZE]; video::IVideoDriver* Driver; core::stringc LevelName; io::IFileSystem* FileSystem; // needs because there are no file extenstions stored in .bsp files. // Additional content scene::ISceneManager* SceneManager; enum eToken { Q3_TOKEN_UNRESOLVED = 0, Q3_TOKEN_EOF = 1, Q3_TOKEN_START_LIST, Q3_TOKEN_END_LIST, Q3_TOKEN_ENTITY, Q3_TOKEN_TOKEN, Q3_TOKEN_EOL, Q3_TOKEN_COMMENT, Q3_TOKEN_MATH_DIVIDE, Q3_TOKEN_MATH_ADD, Q3_TOKEN_MATH_MULTIPY }; struct SQ3Parser { const c8 *source; u32 sourcesize; u32 index; core::stringc token; eToken tokenresult; }; SQ3Parser Parser; typedef void( CQ3LevelMesh::*tParserCallback ) ( quake3::SVarGroupList *& groupList, eToken token ); void parser_parse( const void * data, u32 size, tParserCallback callback ); void parser_nextToken(); void dumpVarGroup( const quake3::SVarGroup * group, s32 stack ) const; void scriptcallback_entity( quake3::SVarGroupList *& grouplist, eToken token ); void scriptcallback_shader( quake3::SVarGroupList *& grouplist, eToken token ); void scriptcallback_config( quake3::SVarGroupList *& grouplist, eToken token ); core::array < quake3::IShader > Shader; core::array < quake3::IShader > Entity; //quake3::tQ3EntityList Entity; quake3::tStringList ShaderFile; void InitShader(); void ReleaseShader(); void ReleaseEntity(); s32 setShaderMaterial( video::SMaterial & material, const tBSPFace * face ) const; s32 setShaderFogMaterial( video::SMaterial &material, const tBSPFace * face ) const; struct SToBuffer { s32 takeVertexColor; u32 index; }; void cleanMeshes(); void cleanMesh(SMesh *m, const bool texture0important = false); void cleanLoader (); void calcBoundingBoxes(); c8 buf[128]; f32 FramesPerSecond; }; } // end namespace scene } // end namespace irr #endif