/* =========================================================================== Doom 3 GPL Source Code Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). Doom 3 Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Doom 3 Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Doom 3 Source Code. If not, see . In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. =========================================================================== */ #include "idlib/containers/PlaneSet.h" #include "idlib/MapFile.h" #include "cm/CollisionModel.h" #include "renderer/tr_local.h" typedef struct primitive_s { struct primitive_s *next; // only one of these will be non-NULL struct bspbrush_s * brush; struct mapTri_s * tris; } primitive_t; typedef struct { struct optimizeGroup_s *groups; // we might want to add other fields later } uArea_t; typedef struct { idMapEntity * mapEntity; // points into mapFile_t data idVec3 origin; primitive_t * primitives; struct tree_s * tree; int numAreas; uArea_t * areas; } uEntity_t; // chains of mapTri_t are the general unit of processing typedef struct mapTri_s { struct mapTri_s * next; const idMaterial * material; void * mergeGroup; // we want to avoid merging triangles // from different fixed groups, like guiSurfs and mirrors int planeNum; // not set universally, just in some areas idDrawVert v[3]; const struct hashVert_s *hashVert[3]; struct optVertex_s *optVert[3]; } mapTri_t; typedef struct { int width, height; idDrawVert * verts; } mesh_t; #define MAX_PATCH_SIZE 32 #define PLANENUM_LEAF -1 typedef struct parseMesh_s { struct parseMesh_s *next; mesh_t mesh; const idMaterial * material; } parseMesh_t; typedef struct bspface_s { struct bspface_s * next; int planenum; bool portal; // all portals will be selected before // any non-portals bool checked; // used by SelectSplitPlaneNum() idWinding * w; } bspface_t; typedef struct { idVec4 v[2]; // the offset value will always be in the 0.0 to 1.0 range } textureVectors_t; typedef struct side_s { int planenum; const idMaterial * material; textureVectors_t texVec; idWinding * winding; // only clipped to the other sides of the brush idWinding * visibleHull; // also clipped to the solid parts of the world } side_t; typedef struct bspbrush_s { struct bspbrush_s * next; struct bspbrush_s * original; // chopped up brushes will reference the originals int entitynum; // editor numbering for messages int brushnum; // editor numbering for messages const idMaterial * contentShader; // one face's shader will determine the volume attributes int contents; bool opaque; int outputNumber; // set when the brush is written to the file list idBounds bounds; int numsides; side_t sides[6]; // variably sized } uBrush_t; typedef struct drawSurfRef_s { struct drawSurfRef_s * nextRef; int outputNumber; } drawSurfRef_t; typedef struct node_s { // both leafs and nodes int planenum; // -1 = leaf node struct node_s * parent; idBounds bounds; // valid after portalization // nodes only side_t * side; // the side that created the node struct node_s * children[2]; int nodeNumber; // set after pruning // leafs only bool opaque; // view can never be inside uBrush_t * brushlist; // fragments of all brushes in this leaf // needed for FindSideForPortal int area; // determined by flood filling up to areaportals int occupied; // 1 or greater can reach entity uEntity_t * occupant; // for leak file testing struct uPortal_s * portals; // also on nodes during construction } node_t; typedef struct uPortal_s { idPlane plane; node_t *onnode; // NULL = outside box node_t *nodes[2]; // [0] = front side of plane struct uPortal_s *next[2]; idWinding *winding; } uPortal_t; // a tree_t is created by FaceBSP() typedef struct tree_s { node_t *headnode; node_t outside_node; idBounds bounds; } tree_t; #define MAX_QPATH 256 // max length of a game pathname typedef struct { idRenderLightLocal def; char name[MAX_QPATH]; // for naming the shadow volume surface and interactions srfTriangles_t *shadowTris; } mapLight_t; #define MAX_GROUP_LIGHTS 16 typedef struct optimizeGroup_s { struct optimizeGroup_s *nextGroup; idBounds bounds; // set in CarveGroupsByLight // all of these must match to add a triangle to the triList bool smoothed; // curves will never merge with brushes int planeNum; int areaNum; const idMaterial * material; int numGroupLights; mapLight_t * groupLights[MAX_GROUP_LIGHTS]; // lights effecting this list void * mergeGroup; // if this differs (guiSurfs, mirrors, etc), the // groups will not be combined into model surfaces // after optimization textureVectors_t texVec; bool surfaceEmited; mapTri_t * triList; mapTri_t * regeneratedTris; // after each island optimization idVec3 axis[2]; // orthogonal to the plane, so optimization can be 2D } optimizeGroup_t; // all primitives from the map are added to optimzeGroups, creating new ones as needed // each optimizeGroup is then split into the map areas, creating groups in each area // each optimizeGroup is then divided by each light, creating more groups // the final list of groups is then tjunction fixed against all groups, then optimized internally // multiple optimizeGroups will be merged together into .proc surfaces, but no further optimization // is done on them //============================================================================= // dmap.cpp typedef enum { SO_NONE, // 0 SO_MERGE_SURFACES, // 1 SO_CULL_OCCLUDED, // 2 SO_CLIP_OCCLUDERS, // 3 SO_CLIP_SILS, // 4 SO_SIL_OPTIMIZE // 5 } shadowOptLevel_t; typedef struct { // mapFileBase will contain the qpath without any extension: "maps/test_box" char mapFileBase[1024]; idMapFile *dmapFile; idPlaneSet mapPlanes; int num_entities; uEntity_t *uEntities; int entityNum; idList mapLights; bool verbose; bool glview; bool noOptimize; bool verboseentities; bool noCurves; bool fullCarve; bool noModelBrushes; bool noTJunc; bool nomerge; bool noFlood; bool noClipSides; // don't cut sides by solid leafs, use the entire thing bool noLightCarve; // extra triangle subdivision by light frustums shadowOptLevel_t shadowOptLevel; bool noShadow; // don't create optimized shadow volumes idBounds drawBounds; bool drawflag; int totalShadowTriangles; int totalShadowVerts; } dmapGlobals_t; extern dmapGlobals_t dmapGlobals; int FindFloatPlane( const idPlane &plane, bool *fixedDegeneracies = NULL ); //============================================================================= // brush.cpp #ifndef CLIP_EPSILON #define CLIP_EPSILON 0.1f #endif #define PSIDE_FRONT 1 #define PSIDE_BACK 2 #define PSIDE_BOTH (PSIDE_FRONT|PSIDE_BACK) #define PSIDE_FACING 4 int CountBrushList (uBrush_t *brushes); uBrush_t *AllocBrush (int numsides); void FreeBrush (uBrush_t *brushes); void FreeBrushList (uBrush_t *brushes); uBrush_t *CopyBrush (uBrush_t *brush); void DrawBrushList (uBrush_t *brush); void PrintBrush (uBrush_t *brush); bool BoundBrush (uBrush_t *brush); bool CreateBrushWindings (uBrush_t *brush); uBrush_t *BrushFromBounds( const idBounds &bounds ); float BrushVolume (uBrush_t *brush); void WriteBspBrushMap( const char *name, uBrush_t *list ); void FilterBrushesIntoTree( uEntity_t *e ); void SplitBrush( uBrush_t *brush, int planenum, uBrush_t **front, uBrush_t **back); node_t *AllocNode( void ); //============================================================================= // map.cpp bool LoadDMapFile( const char *filename ); void FreeOptimizeGroupList( optimizeGroup_t *groups ); void FreeDMapFile( void ); //============================================================================= // draw.cpp -- draw debug views either directly, or through glserv.exe void Draw_ClearWindow( void ); void DrawWinding( const idWinding *w ); void DrawAuxWinding( const idWinding *w ); void DrawLine( idVec3 v1, idVec3 v2, int color ); void GLS_BeginScene( void ); void GLS_Winding( const idWinding *w, int code ); void GLS_Triangle( const mapTri_t *tri, int code ); void GLS_EndScene( void ); //============================================================================= // portals.cpp #define MAX_INTER_AREA_PORTALS 1024 typedef struct { int area0, area1; side_t *side; } interAreaPortal_t; extern interAreaPortal_t interAreaPortals[MAX_INTER_AREA_PORTALS]; extern int numInterAreaPortals; bool FloodEntities( tree_t *tree ); void FillOutside( uEntity_t *e ); void FloodAreas( uEntity_t *e ); void MakeTreePortals( tree_t *tree ); void FreePortal( uPortal_t *p ); //============================================================================= // glfile.cpp -- write a debug file to be viewd with glview.exe void OutputWinding( idWinding *w, idFile *glview ); void WriteGLView( tree_t *tree, char *source ); //============================================================================= // leakfile.cpp void LeakFile( tree_t *tree ); //============================================================================= // facebsp.cpp tree_t *AllocTree( void ); void FreeTree( tree_t *tree ); void FreeTree_r( node_t *node ); void FreeTreePortals_r( node_t *node ); bspface_t *MakeStructuralBspFaceList( primitive_t *list ); bspface_t *MakeVisibleBspFaceList( primitive_t *list ); tree_t *FaceBSP( bspface_t *list ); //============================================================================= // surface.cpp mapTri_t *CullTrisInOpaqueLeafs( mapTri_t *triList, tree_t *tree ); void ClipSidesByTree( uEntity_t *e ); void SplitTrisToSurfaces( mapTri_t *triList, tree_t *tree ); void PutPrimitivesInAreas( uEntity_t *e ); void Prelight( uEntity_t *e ); //============================================================================= // tritjunction.cpp struct hashVert_s *GetHashVert( idVec3 &v ); void HashTriangles( optimizeGroup_t *groupList ); void FreeTJunctionHash( void ); int CountGroupListTris( const optimizeGroup_t *groupList ); void FixEntityTjunctions( uEntity_t *e ); void FixAreaGroupsTjunctions( optimizeGroup_t *groupList ); void FixGlobalTjunctions( uEntity_t *e ); //============================================================================= // optimize.cpp -- trianlge mesh reoptimization // the shadow volume optimizer call internal optimizer routines, normal triangles // will just be done by OptimizeEntity() typedef struct optVertex_s { idDrawVert v; idVec3 pv; // projected against planar axis, third value is 0 struct optEdge_s *edges; struct optVertex_s *islandLink; bool addedToIsland; bool emited; // when regenerating triangles } optVertex_t; typedef struct optEdge_s { optVertex_t *v1, *v2; struct optEdge_s *islandLink; bool addedToIsland; bool created; // not one of the original edges bool combined; // combined from two or more colinear edges struct optTri_s *frontTri, *backTri; struct optEdge_s *v1link, *v2link; } optEdge_t; typedef struct optTri_s { struct optTri_s *next; idVec3 midpoint; optVertex_t *v[3]; bool filled; } optTri_t; typedef struct { optimizeGroup_t *group; optVertex_t *verts; optEdge_t *edges; optTri_t *tris; } optIsland_t; void OptimizeEntity( uEntity_t *e ); void OptimizeGroupList( optimizeGroup_t *groupList ); //============================================================================= // tritools.cpp mapTri_t *AllocTri( void ); void FreeTri( mapTri_t *tri ); int CountTriList( const mapTri_t *list ); mapTri_t *MergeTriLists( mapTri_t *a, mapTri_t *b ); mapTri_t *CopyTriList( const mapTri_t *a ); void FreeTriList( mapTri_t *a ); mapTri_t *CopyMapTri( const mapTri_t *tri ); float MapTriArea( const mapTri_t *tri ); mapTri_t *RemoveBadTris( const mapTri_t *tri ); void BoundTriList( const mapTri_t *list, idBounds &b ); void DrawTri( const mapTri_t *tri ); void FlipTriList( mapTri_t *tris ); void TriVertsFromOriginal( mapTri_t *tri, const mapTri_t *original ); void PlaneForTri( const mapTri_t *tri, idPlane &plane ); idWinding *WindingForTri( const mapTri_t *tri ); mapTri_t *WindingToTriList( const idWinding *w, const mapTri_t *originalTri ); void ClipTriList( const mapTri_t *list, const idPlane &plane, float epsilon, mapTri_t **front, mapTri_t **back ); //============================================================================= // output.cpp srfTriangles_t *ShareMapTriVerts( const mapTri_t *tris ); void WriteOutputFile( void ); //============================================================================= // shadowopt.cpp srfTriangles_t *CreateLightShadow( optimizeGroup_t *shadowerGroups, const mapLight_t *light ); void FreeBeamTree( struct beamTree_s *beamTree ); void CarveTriByBeamTree( const struct beamTree_s *beamTree, const mapTri_t *tri, mapTri_t **lit, mapTri_t **unLit );