/* Copyright (c) 2002-2012 Croteam Ltd. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation This program 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 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "Engine/StdH.h" #include #include #include #include #include #include #include #include #include #include #include static CEntity *penField; static CBrushSector *_pbsc; static CStaticStackArray _apenActive; static BOOL EntityIsInside(CEntity *pen) { // get bounding sphere FLOAT fSphereRadius = pen->en_fSpatialClassificationRadius; const FLOAT3D &vSphereCenter = pen->en_plPlacement.pl_PositionVector; // if the entity touches sector's bounding box if (_pbsc->bsc_boxBoundingBox.TouchesSphere(vSphereCenter, fSphereRadius)) { // make oriented bounding box of the entity const FLOAT3D &v = pen->en_plPlacement.pl_PositionVector; const FLOATmatrix3D &m = pen->en_mRotation; FLOATobbox3D boxEntity = FLOATobbox3D(pen->en_boxSpatialClassification, v, m); // if the box touches the sector's BSP if (boxEntity.HasContactWith(FLOATobbox3D(_pbsc->bsc_boxBoundingBox)) && _pbsc->bsc_bspBSPTree.TestBox(boxEntity)<=0) { // for each collision sphere CStaticArray &absSpheres = pen->en_pciCollisionInfo->ci_absSpheres; for(INDEX iSphere=0; iSpherebsc_bspBSPTree.TestSphere( ms.ms_vRelativeCenter0, ms.ms_fR)<=0) { return TRUE; } } } } // otherwise it doesn't touch return FALSE; } // find first entity touching a field (this entity must be a field brush) CEntity *CEntity::TouchingEntity(BOOL (*ConsiderEntity)(CEntity *), CEntity *penHintMaybeInside) { // if not a field brush if (en_RenderType!=RT_FIELDBRUSH) { // error ASSERT(FALSE); return NULL; } // remember the entity and its first sector penField = this; CBrushMip *pbm = en_pbrBrush->GetBrushMipByDistance(0.0f); _pbsc = NULL; {FOREACHINDYNAMICARRAY(pbm->bm_abscSectors, CBrushSector, itbsc) { _pbsc = itbsc; break; }} // if illegal number of sectors if (_pbsc==NULL || pbm->bm_abscSectors.Count()>1) { // error CPrintF("Field doesn't have exactly one sector - ignoring!\n"); return NULL; } // if a specific entity to check is given if (penHintMaybeInside!=NULL) { // if it is inside if (EntityIsInside(penHintMaybeInside)) { // return it return penHintMaybeInside; } } CEntity *penTouched = NULL; // no entities active initially _apenActive.PopAll(); // for each zoning sector that this entity is in {FOREACHSRCOFDST(en_rdSectors, CBrushSector, bsc_rsEntities, pbsc) // for all movable model entities that should be considered in the sector {FOREACHDSTOFSRC(pbsc->bsc_rsEntities, CEntity, en_rdSectors, pen) if (!(pen->en_ulPhysicsFlags&EPF_MOVABLE) || (pen->en_RenderType!=RT_MODEL&&pen->en_RenderType!=RT_EDITORMODEL) || (!ConsiderEntity(pen))) { continue; } // if already active if (pen->en_ulFlags&ENF_FOUNDINGRIDSEARCH) { // skip it continue; } // if it is inside if (EntityIsInside(pen)) { // stop the search penTouched = pen; break; } // add it to active _apenActive.Push() = pen; pen->en_ulFlags |= ENF_FOUNDINGRIDSEARCH; }} ENDFOR} // mark all as inactive {for (INDEX ien=0; ien<_apenActive.Count(); ien++) { CEntity *pen = _apenActive[ien]; pen->en_ulFlags &= ~ENF_FOUNDINGRIDSEARCH; }} _apenActive.PopAll(); return penTouched; }