/* ** gl_setup.cpp ** Initializes the data structures required by the GL renderer to handle ** a level ** **--------------------------------------------------------------------------- ** Copyright 2005 Christoph Oelckers ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions ** are met: ** ** 1. Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** 2. Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in the ** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be ** covered by the terms of the GNU Lesser General Public License as published ** by the Free Software Foundation; either version 2.1 of the License, or (at ** your option) any later version. ** 5. Full disclosure of the entire project's source code, except for third ** party libraries is mandatory. (NOTE: This clause is non-negotiable!) ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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. **--------------------------------------------------------------------------- ** */ #include "gl/system/gl_system.h" #include "doomtype.h" #include "colormatcher.h" #include "i_system.h" #include "p_local.h" #include "p_spec.h" #include "p_lnspec.h" #include "c_dispatch.h" #include "r_sky.h" #include "sc_man.h" #include "w_wad.h" #include "gi.h" #include "p_setup.h" #include "g_level.h" #include "gl/renderer/gl_renderer.h" #include "gl/data/gl_data.h" #include "gl/data/gl_vertexbuffer.h" #include "gl/dynlights/gl_dynlight.h" #include "gl/dynlights/gl_glow.h" #include "gl/utility/gl_clock.h" #include "gl/gl_functions.h" void InitGLRMapinfoData(); //========================================================================== // // // //========================================================================== static TArray MapSectionCollector; static void DoSetMapSection(subsector_t *sub, int num) { MapSectionCollector.Resize(1); MapSectionCollector[0] = sub; sub->mapsection = num; for (unsigned a = 0; a < MapSectionCollector.Size(); a++) { sub = MapSectionCollector[a]; for (DWORD i = 0; i < sub->numlines; i++) { seg_t * seg = sub->firstline + i; if (seg->PartnerSeg) { subsector_t * sub2 = seg->PartnerSeg->Subsector; if (sub2->mapsection != num) { assert(sub2->mapsection == 0); sub2->mapsection = num; MapSectionCollector.Push(sub2); } } } } MapSectionCollector.Clear(); } //========================================================================== // // Merge sections. This is needed in case the map contains errors // like overlapping lines resulting in abnormal subsectors. // // This function ensures that any vertex position can only be in one section. // //========================================================================== struct cvertex_t { double X, Y; operator int() const { return xs_FloorToInt(X) + 65536 * xs_FloorToInt(Y); } bool operator!= (const cvertex_t &other) const { return fabs(X - other.X) >= EQUAL_EPSILON || fabs(Y - other.Y) >= EQUAL_EPSILON; } cvertex_t& operator =(const vertex_t *v) { X = v->fX(); Y = v->fY(); return *this; } }; typedef TMap FSectionVertexMap; static int MergeMapSections(int num) { FSectionVertexMap vmap; FSectionVertexMap::Pair *pair; TArray sectmap; TArray sectvalid; sectmap.Resize(num); sectvalid.Resize(num); for(int i=0;iSubsector->mapsection; for(int j=0;j<2;j++) { vt = j==0? seg->v1:seg->v2; vmap[vt] = section; } } // second step: Check if any seg references more than one mapsection, either by subsector or by vertex for(DWORD i=0;i<(DWORD)numsegs;i++) { seg_t * seg = &segs[i]; int section = seg->Subsector->mapsection; for(int j=0;j<2;j++) { vt = j==0? seg->v1:seg->v2; int vsection = vmap[vt]; if (vsection != section) { // These 2 sections should be merged for(int k=0;kValue == vsection) pair->Value = section; } sectvalid[vsection-1] = false; } } } for(int i=0;inumlines;i++) { seg_t * seg = sub->firstline + i; if (seg->PartnerSeg) { subsector_t * sub2 = seg->PartnerSeg->Subsector; if (!(sub2->hacked&1) && sub2->render_sector == sub->render_sector) { sub2->hacked|=1; sub->hacked &= ~4; SpreadHackedFlag (sub2); } } } } //========================================================================== // // // //========================================================================== static void PrepareSectorData() { int i; TArray undetermined; subsector_t * ss; // now group the subsectors by sector subsector_t ** subsectorbuffer = new subsector_t * [numsubsectors]; for(i=0, ss=subsectors; irender_sector->subsectorcount++; } for (i=0; irender_sector->subsectors[ss->render_sector->subsectorcount++]=ss; } // marks all malformed subsectors so rendering tricks using them can be handled more easily for (i = 0; i < numsubsectors; i++) { if (subsectors[i].sector == subsectors[i].render_sector) { seg_t * seg = subsectors[i].firstline; for(DWORD j=0;jSubsector->render_sector) { DPrintf(DMSG_NOTIFY, "Found hack: (%f,%f) (%f,%f)\n", seg[j].v1->fX(), seg[j].v1->fY(), seg[j].v2->fX(), seg[j].v2->fY()); subsectors[i].hacked|=5; SpreadHackedFlag(&subsectors[i]); } if (seg[j].PartnerSeg==NULL) subsectors[i].hacked|=2; // used for quick termination checks } } } SetMapSections(); } //========================================================================== // // Some processing for transparent door hacks using a floor raised by 1 map unit // - This will be used to lower the floor of such sectors by one map unit // //========================================================================== static void PrepareTransparentDoors(sector_t * sector) { bool solidwall=false; int notextures=0; int nobtextures=0; int selfref=0; int i; sector_t * nextsec=NULL; #ifdef _DEBUG if (sector-sectors==34) { int a = 0; } #endif P_Recalculate3DFloors(sector); if (sector->subsectorcount==0) return; sector->transdoorheight=sector->GetPlaneTexZ(sector_t::floor); sector->transdoor= !(sector->e->XFloor.ffloors.Size() || sector->heightsec || sector->floorplane.isSlope()); if (sector->transdoor) { for (i=0; ilinecount; i++) { if (sector->lines[i]->frontsector==sector->lines[i]->backsector) { selfref++; continue; } sector_t * sec=getNextSector(sector->lines[i], sector); if (sec==NULL) { solidwall=true; continue; } else { nextsec=sec; int side = sector->lines[i]->sidedef[0]->sector == sec; if (sector->GetPlaneTexZ(sector_t::floor)!=sec->GetPlaneTexZ(sector_t::floor)+1. || sec->floorplane.isSlope()) { sector->transdoor=false; return; } if (!sector->lines[i]->sidedef[1-side]->GetTexture(side_t::top).isValid()) notextures++; if (!sector->lines[i]->sidedef[1-side]->GetTexture(side_t::bottom).isValid()) nobtextures++; } } if (sector->GetTexture(sector_t::ceiling)==skyflatnum) { sector->transdoor=false; return; } if (selfref+nobtextures!=sector->linecount) { sector->transdoor=false; } if (selfref+notextures!=sector->linecount) { // This is a crude attempt to fix an incorrect transparent door effect I found in some // WolfenDoom maps but considering the amount of code required to handle it I left it in. // Do this only if the sector only contains one-sided walls or ones with no lower texture. if (solidwall) { if (solidwall+nobtextures+selfref==sector->linecount && nextsec) { sector->heightsec=nextsec; sector->heightsec->MoreFlags=0; } sector->transdoor=false; } } } } //========================================================================== // // // //========================================================================== static void AddToVertex(const sector_t * sec, TArray & list) { int secno = int(sec-sectors); for(unsigned i=0;i * vt_sectorlists; int i,j,k; vt_sectorlists = new TArray[numvertexes]; for(i=0;iv1 : line->v2; for(k=0;k<2;k++) { sector_t * sec = k==0? line->frontsector : line->backsector; if (sec) { extsector_t::xfloor &x = sec->e->XFloor; AddToVertex(sec, vt_sectorlists[v-vertexes]); if (sec->heightsec) AddToVertex(sec->heightsec, vt_sectorlists[v-vertexes]); } } } } for(i=0;i1) { vertexes[i].numsectors= cnt; vertexes[i].sectors=new sector_t*[cnt]; vertexes[i].heightlist = new float[cnt*2]; for(int j=0;jsidedef[0] == &sides[sdnum]) { *v1 = ln->v1->fPos(); *v2 = ln->v2->fPos(); } else { *v2 = ln->v1->fPos(); *v1 = ln->v2->fPos(); } } static int segcmp(const void *a, const void *b) { seg_t *A = *(seg_t**)a; seg_t *B = *(seg_t**)b; return xs_RoundToInt(FRACUNIT*(A->sidefrac - B->sidefrac)); } //========================================================================== // // Group segs to sidedefs // //========================================================================== static void PrepareSegs() { int *segcount = new int[numsides]; int realsegs = 0; // Get floatng point coordinates of vertices for(int i = 0; i < numvertexes; i++) { vertexes[i].dirty = true; } // count the segs memset(segcount, 0, numsides * sizeof(int)); // set up the extra data in case the map was loaded with regular nodes that might pass as GL nodes. if (glsegextras == NULL) { for(int i=0;iPartnerSeg = &segs[partner]; else seg->PartnerSeg = NULL; seg->Subsector = glsegextras[i].Subsector; } } for(int i=0;isidedef == NULL) continue; // miniseg int sidenum = int(seg->sidedef - sides); realsegs++; segcount[sidenum]++; DVector2 sidestart, sideend, segend = seg->v2->fPos(); GetSideVertices(sidenum, &sidestart, &sideend); sideend -=sidestart; segend -= sidestart; seg->sidefrac = float(segend.Length() / sideend.Length()); } // allocate memory sides[0].segs = new seg_t*[realsegs]; sides[0].numsegs = 0; for(int i = 1; i < numsides; i++) { sides[i].segs = sides[i-1].segs + segcount[i-1]; sides[i].numsegs = 0; } delete [] segcount; // assign the segs for(int i=0;isidedef != NULL) seg->sidedef->segs[seg->sidedef->numsegs++] = seg; } // sort the segs for(int i = 0; i < numsides; i++) { if (sides[i].numsegs > 1) qsort(sides[i].segs, sides[i].numsegs, sizeof(seg_t*), segcmp); } } //========================================================================== // // Initialize the level data for the GL renderer // //========================================================================== extern int restart; void gl_PreprocessLevel() { int i; PrepareSegs(); PrepareSectorData(); InitVertexData(); int *checkmap = new int[numvertexes]; memset(checkmap, -1, sizeof(int)*numvertexes); for(i=0;isidedef[0]->Flags & WALLF_POLYOBJ) continue; // don't bother with polyobjects int vtnum1 = int(l->v1 - vertexes); int vtnum2 = int(l->v2 - vertexes); if (checkmap[vtnum1] < i) { checkmap[vtnum1] = i; sectors[i].e->vertices.Push(&vertexes[vtnum1]); vertexes[vtnum1].dirty = true; } if (checkmap[vtnum2] < i) { checkmap[vtnum2] = i; sectors[i].e->vertices.Push(&vertexes[vtnum2]); vertexes[vtnum2].dirty = true; } } } delete[] checkmap; gl_InitPortals(); if (GLRenderer != NULL) { GLRenderer->SetupLevel(); } #if 0 gl_CreateSections(); #endif InitGLRMapinfoData(); } //========================================================================== // // Cleans up all the GL data for the last level // //========================================================================== void gl_CleanLevelData() { // Dynamic lights must be destroyed before the sector information here is deleted. TThinkerIterator it(STAT_DLIGHT); AActor * mo=it.Next(); while (mo) { AActor * next = it.Next(); mo->Destroy(); mo=next; } if (vertexes != NULL) { for(int i = 0; i < numvertexes; i++) if (vertexes[i].numsectors > 0) { if (vertexes[i].sectors != NULL) { delete [] vertexes[i].sectors; vertexes[i].sectors = NULL; } if (vertexes[i].heightlist != NULL) { delete [] vertexes[i].heightlist; vertexes[i].heightlist = NULL; } } } if (sides && sides[0].segs) { delete [] sides[0].segs; sides[0].segs = NULL; } if (sectors && sectors[0].subsectors) { delete [] sectors[0].subsectors; sectors[0].subsectors = NULL; } for (int i=0;isectornum, int(subsectors[j].firstline->linedef-lines)); break; } } } }