/* Copyright (c) 2002-2012 Croteam Ltd. All rights reserved. */ #include "stdh.h" #include #include #include #include #include #include #include #include #include #include // constructor CBrush3D::CBrush3D(void) { br_penEntity = NULL; br_pfsFieldSettings = NULL; br_ulFlags = 0; } // destructor CBrush3D::~CBrush3D(void) { } /* Delete a brush mip with given factor. */ void CBrush3D::DeleteBrushMip(CBrushMip *pbmToDelete) { ASSERT(pbmToDelete!=NULL); ASSERT(pbmToDelete->bm_pbrBrush == this); // if there is only one brush mip if (br_lhBrushMips.Count()<=1) { // do nothing; return; } // remove it from list pbmToDelete->bm_lnInBrush.Remove(); // destroy it delete pbmToDelete; } /* Create a new brush mip. */ CBrushMip *CBrush3D::NewBrushMipAfter(CBrushMip *pbmOld, BOOL bCopy) { ASSERT(pbmOld!=NULL); ASSERT(pbmOld->bm_pbrBrush == this); // create one brush mip CBrushMip *pbmNew = new CBrushMip; pbmNew->bm_pbrBrush = this; // add it to the brush pbmOld->bm_lnInBrush.AddAfter(pbmNew->bm_lnInBrush); // copy the original to it if (bCopy) { pbmNew->Copy(*pbmOld, 1.0f, FALSE); } // respread the mips after old one pbmOld->SpreadFurtherMips(); return pbmNew; } CBrushMip *CBrush3D::NewBrushMipBefore(CBrushMip *pbmOld, BOOL bCopy) { ASSERT(pbmOld!=NULL); ASSERT(pbmOld->bm_pbrBrush == this); // create one brush mip CBrushMip *pbmNew = new CBrushMip; pbmNew->bm_pbrBrush = this; // add it to the brush pbmOld->bm_lnInBrush.AddBefore(pbmNew->bm_lnInBrush); // copy the original to it if (bCopy) { // copy the original to it pbmNew->Copy(*pbmOld, 1.0f, FALSE); } // get factor of mip before the new one FLOAT fFactorBefore = 0.0f; CBrushMip *pbmBefore = pbmNew->GetPrev(); if (pbmBefore!=NULL) { fFactorBefore = pbmBefore->bm_fMaxDistance; } // calculate factor for new one to be between those two pbmNew->bm_fMaxDistance = (fFactorBefore+pbmOld->bm_fMaxDistance)/2.0f; return pbmNew; } // make 'for' construct for walking a list reversely #define FOREACHINLIST_R(baseclass, member, head, iter) \ for ( LISTITER(baseclass, member) iter(head.IterationTail()); \ !iter->member.IsHeadMarker(); iter.MoveToPrev() ) /* * Get a brush mip for given mip-factor. */ CBrushMip *CBrush3D::GetBrushMipByDistance(FLOAT fMipDistance) { // initially there is no brush mip CBrushMip *pbmLastGood=NULL; // for all brush mips in brush reversely FOREACHINLIST_R(CBrushMip, bm_lnInBrush, br_lhBrushMips, itbm) { CBrushMip &bm = *itbm; // if this mip cannot be of given factor if (bm.bm_fMaxDistancebm_lnInBrush); pbmBrushMip->bm_pbrBrush = this; // copy the brush mip from original pbmBrushMip->Copy(*itbmOther, fStretch, bMirrorX); } } /* * Prepare a projection from brush space to absolute space. */ void CBrush3D::PrepareRelativeToAbsoluteProjection( CSimpleProjection3D_DOUBLE &prRelativeToAbsolute) { // brush that does not have an entity is initialized at origin if(br_penEntity==NULL) { prRelativeToAbsolute.ObjectPlacementL().pl_PositionVector = FLOAT3D(0.0f, 0.0f, 0.0f); prRelativeToAbsolute.ObjectPlacementL().pl_OrientationAngle = ANGLE3D(0, 0, 0); } else { prRelativeToAbsolute.ObjectPlacementL() = br_penEntity->en_plPlacement; } prRelativeToAbsolute.ViewerPlacementL().pl_PositionVector = FLOAT3D(0.0f, 0.0f, 0.0f); prRelativeToAbsolute.ViewerPlacementL().pl_OrientationAngle = ANGLE3D(0, 0, 0); prRelativeToAbsolute.Prepare(); } /* * Calculate bounding boxes in all brush mips. */ void CBrush3D::CalculateBoundingBoxes(void) { CalculateBoundingBoxesForOneMip(NULL); } void CBrush3D::CalculateBoundingBoxesForOneMip(CBrushMip *pbmOnly) // for only one mip { // set FPU to double precision CSetFPUPrecision FPUPrecision(FPT_53BIT); // prepare a projection from brush space to absolute space CSimpleProjection3D_DOUBLE prBrushToAbsolute; PrepareRelativeToAbsoluteProjection(prBrushToAbsolute); // for all brush mips FOREACHINLIST(CBrushMip, bm_lnInBrush, br_lhBrushMips, itbm) { CBrushMip *pbm = itbm; if (pbmOnly==NULL || pbm==pbmOnly) { // calculate its boxes pbm->CalculateBoundingBoxes(prBrushToAbsolute); } } // if this brush is zoning if (br_penEntity!=NULL && (br_penEntity->en_ulFlags&ENF_ZONING)) { // portal links must be updated also extern BOOL _bPortalSectorLinksPreLoaded; extern BOOL _bDontDiscardLinks; br_penEntity->en_pwoWorld->wo_bPortalLinksUpToDate = _bPortalSectorLinksPreLoaded||_bDontDiscardLinks; } br_penEntity->UpdateSpatialRange(); } // switch from zoning to non-zoning void CBrush3D::SwitchToNonZoning(void) { CalculateBoundingBoxes(); // for all brush mips FOREACHINLIST(CBrushMip, bm_lnInBrush, br_lhBrushMips, itbm) { // for all sectors in the mip {FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc) { // unset spatial clasification itbsc->bsc_rsEntities.Clear(); }} } } // switch from non-zoning to zoning void CBrush3D::SwitchToZoning(void) { CalculateBoundingBoxes(); // for all brush mips FOREACHINLIST(CBrushMip, bm_lnInBrush, br_lhBrushMips, itbm) { // for all sectors in the mip {FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc) { // find entities in sector itbsc->FindEntitiesInSector(); }} } }