/* =========================================================================== 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 "../../../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; idPlane frustumPlanes[6]; // RB: should be calculated after R_DeriveLightData() } 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(); //============================================================================= // map.cpp bool LoadDMapFile( const char* filename ); void FreeOptimizeGroupList( optimizeGroup_t* groups ); void FreeDMapFile(); //============================================================================= // draw.cpp -- draw debug views either directly, or through glserv.exe void Draw_ClearWindow(); void DrawWinding( const idWinding* w ); void DrawAuxWinding( const idWinding* w ); void DrawLine( idVec3 v1, idVec3 v2, int color ); void GLS_BeginScene(); void GLS_Winding( const idWinding* w, int code ); void GLS_Triangle( const mapTri_t* tri, int code ); void GLS_EndScene(); //============================================================================= // 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 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 ); node_t* NodeForPoint( node_t* node, const idVec3& origin ); //============================================================================= // 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(); int CountGroupListTris( const optimizeGroup_t* groupList ); void FixEntityTjunctions( uEntity_t* e ); void FixAreaGroupsTjunctions( optimizeGroup_t* groupList ); void FixGlobalTjunctions( uEntity_t* e ); //============================================================================= // optimize.cpp -- triangle 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 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(); //============================================================================= // 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 );