Serious-Engine/Sources/Engine/World/World.cpp
Daniel Gibson 72edf1c720 Commented out unused functions and variables
many unused functions and variables are now commented out

You'll still get tons of warnings, which should mostly fall in one of
the following categories:
1. Unnecessary variables or values generated from .es scripts
2. Pointers assigned to from functions with side-effects: DO NOT REMOVE!
   Like CEntity *penNew = CreateEntity_t(...); - even if penNew isn't
   used, CreateEntity() must be called there!
2016-05-09 18:51:03 +02:00

1162 lines
34 KiB
C++

/* 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 <Engine/Base/Console.h>
#include <Engine/Math/Float.h>
#include <Engine/World/World.h>
#include <Engine/World/WorldEditingProfile.h>
#include <Engine/Graphics/RenderScene.h>
#include <Engine/World/WorldSettings.h>
#include <Engine/Entities/EntityClass.h>
#include <Engine/Entities/Precaching.h>
#include <Engine/Entities/EntityProperties.h>
#include <Engine/Base/ListIterator.inl>
#include <Engine/Templates/DynamicContainer.cpp>
#include <Engine/Graphics/Color.h>
#include <Engine/Brushes/BrushArchive.h>
#include <Engine/Terrain/TerrainArchive.h>
#include <Engine/Entities/InternalClasses.h>
#include <Engine/Network/Network.h>
#include <Engine/Network/SessionState.h>
#include <Engine/Templates/DynamicArray.cpp>
#include <Engine/Brushes/Brush.h>
#include <Engine/Light/LightSource.h>
#include <Engine/Base/ProgressHook.h>
#include <Engine/Templates/StaticArray.cpp>
#include <Engine/Templates/Selection.cpp>
#include <Engine/Terrain/Terrain.h>
#include <Engine/Templates/Stock_CEntityClass.h>
template class CDynamicContainer<CEntity>;
template class CSelection<CBrushPolygon, BPOF_SELECTED>;
template class CSelection<CBrushSector, BSCF_SELECTED>;
template class CSelection<CEntity, ENF_SELECTED>;
extern BOOL _bPortalSectorLinksPreLoaded;
extern BOOL _bEntitySectorLinksPreLoaded;
extern INDEX _ctPredictorEntities;
#if 0 // DG: unused.
// calculate ray placement from origin and target positions (obsolete?)
static inline CPlacement3D CalculateRayPlacement(
const FLOAT3D &vOrigin, const FLOAT3D &vTarget)
{
CPlacement3D plRay;
// ray position is at origin
plRay.pl_PositionVector = vOrigin;
// calculate ray direction vector
FLOAT3D vDirection = vTarget-vOrigin;
// calculate ray orientation from the direction vector
vDirection.Normalize();
DirectionVectorToAngles(vDirection, plRay.pl_OrientationAngle);
return plRay;
}
#endif // 0
/* Constructor. */
CTextureTransformation::CTextureTransformation(void)
{
tt_strName = "";
}
/* Constructor. */
CTextureBlending::CTextureBlending(void)
{
tb_strName = "";
tb_ubBlendingType = STXF_BLEND_OPAQUE;
tb_colMultiply = C_WHITE|0xFF;
}
/*
* Constructor.
*/
CWorld::CWorld(void)
: wo_pecWorldBaseClass(NULL) // worldbase class must be obtained before using the world
, wo_baBrushes(*new CBrushArchive)
, wo_taTerrains(*new CTerrainArchive)
, wo_colBackground(C_lGRAY) // clear background color
, wo_ulSpawnFlags(0)
, wo_bPortalLinksUpToDate(FALSE) // portal-sector links must be updated
{
wo_baBrushes.ba_pwoWorld = this;
wo_taTerrains.ta_pwoWorld = this;
// create empty texture movements
wo_attTextureTransformations.New(256);
wo_atbTextureBlendings.New(256);
wo_astSurfaceTypes.New(256);
wo_actContentTypes.New(256);
wo_aetEnvironmentTypes.New(256);
wo_aitIlluminationTypes.New(256);
// initialize collision grid
InitCollisionGrid();
wo_slStateDictionaryOffset = 0;
wo_strBackdropUp = "";
wo_strBackdropFt = "";
wo_strBackdropRt = "";
wo_strBackdropObject = "";
wo_fUpW = wo_fUpL = 1.0f; wo_fUpCX = wo_fUpCZ = 0.0f;
wo_fFtW = wo_fFtH = 1.0f; wo_fFtCX = wo_fFtCY = 0.0f;
wo_fRtL = wo_fRtH = 1.0f; wo_fRtCZ = wo_fRtCY = 0.0f;
wo_ulNextEntityID = 1;
// set default placement
wo_plFocus = CPlacement3D( FLOAT3D(3.0f, 4.0f, 10.0f),
ANGLE3D(AngleDeg( 20.0f), AngleDeg( -20.0f), 0));
wo_fTargetDistance = 10.0f;
// set default thumbnail placement
wo_plThumbnailFocus = CPlacement3D( FLOAT3D(3.0f, 4.0f, 10.0f),
ANGLE3D(AngleDeg( 20.0f), AngleDeg( -20.0f), 0));
wo_fThumbnailTargetDistance = 10.0f;
}
/*
* Destructor.
*/
CWorld::~CWorld()
{
// clear all arrays
Clear();
// destroy collision grid
DestroyCollisionGrid();
delete &wo_baBrushes;
delete &wo_taTerrains;
}
/*
* Clear all arrays.
*/
void CWorld::Clear(void)
{
// detach worldbase class
if (wo_pecWorldBaseClass!=NULL) {
if ( wo_pecWorldBaseClass->ec_pdecDLLClass!=NULL
&&wo_pecWorldBaseClass->ec_pdecDLLClass->dec_OnWorldEnd!=NULL) {
wo_pecWorldBaseClass->ec_pdecDLLClass->dec_OnWorldEnd(this);
}
wo_pecWorldBaseClass=NULL;
}
{
// must be in 24bit mode when managing entities
CSetFPUPrecision FPUPrecision(FPT_24BIT);
// clear background viewer
SetBackgroundViewer(NULL);
// make a new container of entities
CDynamicContainer<CEntity> cenToDestroy = wo_cenEntities;
// for each of the entities
{FOREACHINDYNAMICCONTAINER(cenToDestroy, CEntity, iten) {
// destroy it
iten->Destroy();
}}
// the original container must be empty
ASSERT(wo_cenEntities.Count()==0);
ASSERT(wo_cenAllEntities.Count()==0);
wo_cenEntities.Clear();
wo_cenAllEntities.Clear();
cenToDestroy.Clear();
wo_ulNextEntityID = 1;
}
// clear brushes
wo_baBrushes.ba_abrBrushes.Clear();
// clear terrains
wo_taTerrains.ta_atrTerrains.Clear();
extern void ClearMovableEntityCaches(void);
ClearMovableEntityCaches();
// clear collision grid
ClearCollisionGrid();
}
/*
* Create a new entity of given class.
*/
CEntity *CWorld::CreateEntity(const CPlacement3D &plPlacement, CEntityClass *pecClass)
{
// must be in 24bit mode when managing entities
CSetFPUPrecision FPUPrecision(FPT_24BIT);
// if the world base class is not yet remembered and this class is world base
if (wo_pecWorldBaseClass==NULL
&& stricmp(pecClass->ec_pdecDLLClass->dec_strName, "WorldBase")==0) {
// remember it
wo_pecWorldBaseClass = pecClass;
// execute the class attach function
if (pecClass->ec_pdecDLLClass->dec_OnWorldInit!=NULL) {
pecClass->ec_pdecDLLClass->dec_OnWorldInit(this);
}
}
// gather CRCs of that class
pecClass->AddToCRCTable();
// ask the class to instance a new member
CEntity *penEntity = pecClass->New();
// add the reference made by the entity itself
penEntity->AddReference();
// set the entity's world pointer to this world
penEntity->en_pwoWorld = this;
// add the new member to this world's entity container
wo_cenEntities.Add(penEntity);
wo_cenAllEntities.Add(penEntity);
// set a new identifier
penEntity->en_ulID = wo_ulNextEntityID++;
// set up the placement
penEntity->en_plPlacement = plPlacement;
// calculate rotation matrix
MakeRotationMatrixFast(penEntity->en_mRotation, penEntity->en_plPlacement.pl_OrientationAngle);
// if now predicting
if (_pNetwork->IsPredicting()) {
// mark entity as a temporary predictor
penEntity->en_ulFlags |= ENF_PREDICTOR|ENF_TEMPPREDICTOR;
wo_cenPredictor.Add(penEntity);
_ctPredictorEntities++;
}
// return it
return penEntity;
}
/*
* Create a new entity of given class.
*/
CEntity *CWorld::CreateEntity_t(const CPlacement3D &plPlacement,
const CTFileName &fnmClass) // throw char *
{
// obtain a new entity class from global stock
CEntityClass *pecClass = _pEntityClassStock->Obtain_t(fnmClass);
// create entity with that class (obtains it once more)
CEntity *penNew = CreateEntity(plPlacement, pecClass);
// release the class
_pEntityClassStock->Release(pecClass);
// return the entity
return penNew;
}
/*
* Destroy one entities.
*/
void CWorld::DestroyOneEntity( CEntity *penToDestroy)
{
// if the entity is targetable
if (penToDestroy->IsTargetable()) {
// remove all eventual pointers to it
UntargetEntity( penToDestroy);
}
// destroy it
penToDestroy->Destroy();
}
/*
* Destroy a selection of entities.
*/
void CWorld::DestroyEntities(CEntitySelection &senToDestroy)
{
// must be in 24bit mode when managing entities
CSetFPUPrecision FPUPrecision(FPT_24BIT);
// for each entity in selection
FOREACHINDYNAMICCONTAINER(senToDestroy, CEntity, iten) {
// if the entity is targetable
if (iten->IsTargetable()) {
// remove all eventual pointers to it
UntargetEntity(iten);
}
// destroy it
iten->Destroy();
}
// clear the selection on the container level
/* NOTE: we must not clear the selection directly, since the entity objects
contained there are already freed and deselecting them would make an access
violation.
*/
senToDestroy.CDynamicContainer<CEntity>::Clear();
}
/*
* Clear all entity pointers that point to this entity.
*/
void CWorld::UntargetEntity(CEntity *penToUntarget)
{
// for all entities in this world
FOREACHINDYNAMICCONTAINER(wo_cenEntities, CEntity, itenInWorld){
// get the DLL class of this entity
CDLLEntityClass *pdecDLLClass = itenInWorld->en_pecClass->ec_pdecDLLClass;
// for all classes in hierarchy of this entity
for(;
pdecDLLClass!=NULL;
pdecDLLClass = pdecDLLClass->dec_pdecBase) {
// for all properties
for(INDEX iProperty=0; iProperty<pdecDLLClass->dec_ctProperties; iProperty++) {
CEntityProperty &epProperty = pdecDLLClass->dec_aepProperties[iProperty];
// if the property type is entity pointer
if (epProperty.ep_eptType == CEntityProperty::EPT_ENTITYPTR) {
// get the pointer
CEntityPointer &penPointed = ENTITYPROPERTY(&*itenInWorld, epProperty.ep_slOffset, CEntityPointer);
// if it points to the entity to be untargeted
if (penPointed == penToUntarget) {
itenInWorld->End();
// clear the pointer
penPointed = NULL;
itenInWorld->Initialize();
}
}
}
}
}
// if the entity is background viewer
if (wo_penBackgroundViewer==penToUntarget) {
// reset background viewer
SetBackgroundViewer(NULL);
}
}
/*
* Find an entity with given character.
*/
CPlayerEntity *CWorld::FindEntityWithCharacter(CPlayerCharacter &pcCharacter)
{
ASSERT(pcCharacter.pc_strName != "");
// for each entity
FOREACHINDYNAMICCONTAINER(wo_cenEntities, CEntity, iten) {
CEntity *pen = &*iten;
// if it is player entity
if (IsDerivedFromClass(pen, "PlayerEntity")) {
CPlayerEntity *penPlayer = (CPlayerEntity *)pen;
// if it has got that character
if (penPlayer->en_pcCharacter == pcCharacter) {
// return its pointer
return penPlayer;
}
}
}
// otherwise, none exists
return NULL;
}
/*
* Add an entity to list of thinkers.
*/
void CWorld::AddTimer(CRationalEntity *penThinker)
{
ASSERT(penThinker->en_timeTimer>=_pTimer->CurrentTick());
ASSERT(GetFPUPrecision()==FPT_24BIT);
// if the entity is already in the list
if (penThinker->en_lnInTimers.IsLinked()) {
// remove it
penThinker->en_lnInTimers.Remove();
}
// for each entity in the thinker list
FOREACHINLISTKEEP(CRationalEntity, en_lnInTimers, wo_lhTimers, iten) {
// if the entity in list has greater or same think time than the one to add
if (iten->en_timeTimer>=penThinker->en_timeTimer) {
// stop searching
break;
}
}
// add the new entity before current one
iten.InsertBeforeCurrent(penThinker->en_lnInTimers);
}
// set overdue timers to be due in current time
void CWorld::AdjustLateTimers(TIME tmCurrentTime)
{
// must be in 24bit mode when managing entities
CSetFPUPrecision FPUPrecision(FPT_24BIT);
// for each entity in the thinker list
FOREACHINLIST(CRationalEntity, en_lnInTimers, wo_lhTimers, iten) {
CRationalEntity &en = *iten;
// if the entity in list is overdue
if (en.en_timeTimer<tmCurrentTime) {
// set it to current time
en.en_timeTimer = tmCurrentTime;
}
}
}
/*
* Lock all arrays.
*/
void CWorld::LockAll(void)
{
wo_cenEntities.Lock();
wo_cenAllEntities.Lock();
// lock the brush archive
wo_baBrushes.ba_abrBrushes.Lock();
// lock the terrain archive
wo_taTerrains.ta_atrTerrains.Lock();
}
/*
* Unlock all arrays.
*/
void CWorld::UnlockAll(void)
{
wo_cenEntities.Unlock();
wo_cenAllEntities.Unlock();
// unlock the brush archive
wo_baBrushes.ba_abrBrushes.Unlock();
// unlock the brush archive
wo_taTerrains.ta_atrTerrains.Unlock();
}
/* Get background color for this world. */
COLOR CWorld::GetBackgroundColor(void)
{
return wo_colBackground;
}
/* Set background color for this world. */
void CWorld::SetBackgroundColor(COLOR colBackground)
{
wo_colBackground = colBackground;
}
/* Set background viewer entity for this world. */
void CWorld::SetBackgroundViewer(CEntity *penEntity)
{
wo_penBackgroundViewer = penEntity;
}
/* Get background viewer entity for this world. */
CEntity *CWorld::GetBackgroundViewer(void)
{
// if the background viewer entity is deleted
if (wo_penBackgroundViewer!=NULL && wo_penBackgroundViewer->en_ulFlags&ENF_DELETED) {
// clear the pointer
wo_penBackgroundViewer = NULL;
}
return wo_penBackgroundViewer;
}
/* Set description for this world. */
void CWorld::SetDescription(const CTString &strDescription)
{
wo_strDescription = strDescription;
}
/* Get description for this world. */
const CTString &CWorld::GetDescription(void)
{
return wo_strDescription;
}
// get/set name of the world
void CWorld::SetName(const CTString &strName)
{
wo_strName = strName;
}
const CTString &CWorld::GetName(void)
{
return wo_strName;
}
// get/set spawn flags for the world
void CWorld::SetSpawnFlags(ULONG ulFlags)
{
wo_ulSpawnFlags = ulFlags;
}
ULONG CWorld::GetSpawnFlags(void)
{
return wo_ulSpawnFlags;
}
/////////////////////////////////////////////////////////////////////
// Shadow manipulation functions
/*
* Recalculate all shadow maps that are not valid or of smaller precision.
*/
void CWorld::CalculateDirectionalShadows(void)
{
extern INDEX _ctShadowLayers;
extern INDEX _ctShadowClusters;
CTimerValue tvStart;
// clear shadow rendering stats
tvStart = _pTimer->GetHighPrecisionTimer();
_ctShadowLayers=0;
_ctShadowClusters=0;
// for each shadow map that is queued for calculation
FORDELETELIST(CBrushShadowMap, bsm_lnInUncalculatedShadowMaps,
wo_baBrushes.ba_lhUncalculatedShadowMaps, itbsm) {
// calculate shadows on it
itbsm->GetBrushPolygon()->MakeShadowMap(this, TRUE);
}
// report shadow rendering stats
CTimerValue tvStop = _pTimer->GetHighPrecisionTimer();
CPrintF("Shadow calculation: total %d clusters in %d layers, %fs\n",
_ctShadowClusters,
_ctShadowLayers,
(tvStop-tvStart).GetSeconds());
}
void CWorld::CalculateNonDirectionalShadows(void)
{
// for each shadow map that is queued for calculation
FORDELETELIST(CBrushShadowMap, bsm_lnInUncalculatedShadowMaps,
wo_baBrushes.ba_lhUncalculatedShadowMaps, itbsm) {
// calculate shadows on it
itbsm->GetBrushPolygon()->MakeShadowMap(this, FALSE);
}
}
/* Find all shadow layers near a certain position. */
void CWorld::FindShadowLayers(
const FLOATaabbox3D &boxNear,
BOOL bSelectedOnly /*=FALSE*/,
BOOL bDirectional /*= TRUE*/)
{
_pfWorldEditingProfile.StartTimer(CWorldEditingProfile::PTI_FINDSHADOWLAYERS);
// for each entity in the world
FOREACHINDYNAMICCONTAINER(wo_cenEntities, CEntity, iten) {
// if it is light entity and it influences the given range
CLightSource *pls = iten->GetLightSource();
if (pls!=NULL) {
FLOATaabbox3D boxLight(iten->en_plPlacement.pl_PositionVector, pls->ls_rFallOff);
if ( bDirectional && (pls->ls_ulFlags &LSF_DIRECTIONAL)
||boxLight.HasContactWith(boxNear)) {
// find layers for that light source
pls->FindShadowLayers(bSelectedOnly);
}
}
}
_pfWorldEditingProfile.StopTimer(CWorldEditingProfile::PTI_FINDSHADOWLAYERS);
}
/* Discard shadows on all brush polygons in the world. */
void CWorld::DiscardAllShadows(void)
{
FLOATaabbox3D box;
// for each entity in the world
FOREACHINDYNAMICCONTAINER(wo_cenEntities, CEntity, iten) {
// if it is brush entity
if (iten->en_RenderType == CEntity::RT_BRUSH) {
// for each mip in its brush
FOREACHINLIST(CBrushMip, bm_lnInBrush, iten->en_pbrBrush->br_lhBrushMips, itbm) {
box|=itbm->bm_boxBoundingBox;
// for all sectors in this mip
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc) {
// for each polygon in the sector
FOREACHINSTATICARRAY(itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo) {
// discard its shadow map
itbpo->DiscardShadows();
}
}
}
}
}
// find all shadow layers in the world
FindShadowLayers(box);
}
/////////////////////////////////////////////////////////////////////
// Hide/Show functions
/*
* Hide entities contained in given selection.
*/
void CWorld::HideSelectedEntities(CEntitySelection &selenEntitiesToHide)
{
// for all entities in the selection
FOREACHINDYNAMICCONTAINER(selenEntitiesToHide, CEntity, iten) {
if( iten->IsSelected(ENF_SELECTED) &&
!((iten->en_RenderType==CEntity::RT_BRUSH) && (iten->en_ulFlags&ENF_ZONING)) )
{
// hide the entity
iten->en_ulFlags |= ENF_HIDDEN;
}
}
}
/*
* Hide all unselected entities.
*/
void CWorld::HideUnselectedEntities(void)
{
// for each entity in the world
FOREACHINDYNAMICCONTAINER(wo_cenEntities, CEntity, iten)
{
if( !iten->IsSelected(ENF_SELECTED) &&
!((iten->en_RenderType==CEntity::RT_BRUSH)&&(iten->en_ulFlags&ENF_ZONING)) )
{
// hide it
iten->en_ulFlags |= ENF_HIDDEN;
}
}
}
/*
* Show all entities.
*/
void CWorld::ShowAllEntities(void)
{
// for each entity in the world
FOREACHINDYNAMICCONTAINER(wo_cenEntities, CEntity, iten)
{
iten->en_ulFlags &= ~ENF_HIDDEN;
}
}
/*
* Hide sectors contained in given selection.
*/
void CWorld::HideSelectedSectors(CBrushSectorSelection &selbscSectorsToHide)
{
// for all sectors in the selection
FOREACHINDYNAMICCONTAINER(selbscSectorsToHide, CBrushSector, itbsc) {
// hide the sector
itbsc->bsc_ulFlags |= BSCF_HIDDEN;
}
}
/*
* Hide all unselected sectors.
*/
void CWorld::HideUnselectedSectors(void)
{
// for each entity in the world
FOREACHINDYNAMICCONTAINER(wo_cenEntities, CEntity, iten) {
// if it is brush entity
if (iten->en_RenderType == CEntity::RT_BRUSH) {
// for each mip in its brush
FOREACHINLIST(CBrushMip, bm_lnInBrush, iten->en_pbrBrush->br_lhBrushMips, itbm) {
// for all sectors in this mip
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc) {
// if the sector is not selected
if (!itbsc->IsSelected(BSCF_SELECTED)) {
// hide it
itbsc->bsc_ulFlags |= BSCF_HIDDEN;
}
}
}
}
}
}
/*
* Show all sectors.
*/
void CWorld::ShowAllSectors(void)
{
// for each entity in the world
FOREACHINDYNAMICCONTAINER(wo_cenEntities, CEntity, iten) {
// if it is brush entity
if (iten->en_RenderType == CEntity::RT_BRUSH) {
// for each mip in its brush
FOREACHINLIST(CBrushMip, bm_lnInBrush, iten->en_pbrBrush->br_lhBrushMips, itbm) {
// for all sectors in this mip
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc) {
// show the sector
itbsc->bsc_ulFlags &= ~BSCF_HIDDEN;
}
}
}
}
}
/*
* Select all polygons in selected sectors with same texture.
*/
void CWorld::SelectByTextureInSelectedSectors(
CTFileName fnTexture, CBrushPolygonSelection &selbpoSimilar, INDEX iTexture)
{
// for each entity in the world
FOREACHINDYNAMICCONTAINER(wo_cenEntities, CEntity, iten) {
// if it is brush entity
if (iten->en_RenderType == CEntity::RT_BRUSH) {
// for each mip in its brush
FOREACHINLIST(CBrushMip, bm_lnInBrush, iten->en_pbrBrush->br_lhBrushMips, itbm) {
// for all sectors in this mip
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc) {
// if sector is selected
if (itbsc->IsSelected(BSCF_SELECTED)) {
// for all polygons in sector
FOREACHINSTATICARRAY(itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo)
{
// if it is not portal and is not selected and has same texture
if ( (!(itbpo->bpo_ulFlags&BPOF_PORTAL) || (itbpo->bpo_ulFlags&(BPOF_TRANSLUCENT|BPOF_TRANSPARENT))) &&
!itbpo->IsSelected(BPOF_SELECTED) &&
(itbpo->bpo_abptTextures[iTexture].bpt_toTexture.GetData() != NULL) &&
(itbpo->bpo_abptTextures[iTexture].bpt_toTexture.GetData()->GetName()
== fnTexture) )
// select this polygon
selbpoSimilar.Select(*itbpo);
}
}
}
}
}
}
}
/*
* Select all polygons in world with same texture.
*/
void CWorld::SelectByTextureInWorld(
CTFileName fnTexture, CBrushPolygonSelection &selbpoSimilar, INDEX iTexture)
{
// for each entity in the world
FOREACHINDYNAMICCONTAINER(wo_cenEntities, CEntity, iten) {
// if it is brush entity
if (iten->en_RenderType == CEntity::RT_BRUSH) {
// for each mip in its brush
FOREACHINLIST(CBrushMip, bm_lnInBrush, iten->en_pbrBrush->br_lhBrushMips, itbm) {
// for all sectors in this mip
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc) {
// for all polygons in sector
FOREACHINSTATICARRAY(itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo)
{
// if it is not non translucent portal and is not selected and has same texture
if ( (!(itbpo->bpo_ulFlags&BPOF_PORTAL) || (itbpo->bpo_ulFlags&(BPOF_TRANSLUCENT|BPOF_TRANSPARENT))) &&
!itbpo->IsSelected(BPOF_SELECTED) &&
(itbpo->bpo_abptTextures[iTexture].bpt_toTexture.GetData() != NULL) &&
(itbpo->bpo_abptTextures[iTexture].bpt_toTexture.GetData()->GetName()
== fnTexture) )
// select this polygon
selbpoSimilar.Select(*itbpo);
}
}
}
}
}
}
/*
* Reinitialize entities from their properties. (use only in WEd!)
*/
void CWorld::ReinitializeEntities(void)
{
_pfWorldEditingProfile.StartTimer(CWorldEditingProfile::PTI_REINITIALIZEENTITIES);
// must be in 24bit mode when managing entities
CSetFPUPrecision FPUPrecision(FPT_24BIT);
CTmpPrecachingNow tpn;
// for each entity in the world
FOREACHINDYNAMICCONTAINER(wo_cenEntities, CEntity, iten) {
// reinitialize it
iten->Reinitialize();
}
_pfWorldEditingProfile.StopTimer(CWorldEditingProfile::PTI_REINITIALIZEENTITIES);
}
/* Precache data needed by entities. */
void CWorld::PrecacheEntities_t(void)
{
// for each entity in the world
INDEX ctEntities = wo_cenEntities.Count();
INDEX iEntity = 0;
FOREACHINDYNAMICCONTAINER(wo_cenEntities, CEntity, iten) {
// precache
CallProgressHook_t(FLOAT(iEntity)/ctEntities);
iten->Precache();
iEntity++;
}
}
// delete all entities that don't fit given spawn flags
void CWorld::FilterEntitiesBySpawnFlags(ULONG ulFlags)
{
// must be in 24bit mode when managing entities
CSetFPUPrecision FPUPrecision(FPT_24BIT);
BOOL bOldAllowRandom = _pNetwork->ga_sesSessionState.ses_bAllowRandom;
_pNetwork->ga_sesSessionState.ses_bAllowRandom = TRUE;
// create an empty selection of entities
CEntitySelection senToDestroy;
// for each entity in the world
{FOREACHINDYNAMICCONTAINER(wo_cenEntities, CEntity, iten) {
// if brush
if (iten->en_RenderType==CEntity::RT_BRUSH
||iten->en_RenderType==CEntity::RT_FIELDBRUSH) {
// skip it (brushes must not be deleted on the fly)
continue;
}
// if it shouldn't exist
ULONG ulEntityFlags = iten->GetSpawnFlags();
if (!(ulEntityFlags&ulFlags&SPF_MASK_DIFFICULTY)
||!(ulEntityFlags&ulFlags&SPF_MASK_GAMEMODE)) {
// add it to the selection
senToDestroy.Select(*iten);
}
}}
// destroy all selected entities
DestroyEntities(senToDestroy);
_pNetwork->ga_sesSessionState.ses_bAllowRandom = bOldAllowRandom;
}
// create links between zoning-brush sectors and non-zoning entities in sectors
void CWorld::LinkEntitiesToSectors(void)
{
_pfWorldEditingProfile.StartTimer(CWorldEditingProfile::PTI_LINKENTITIESTOSECTORS);
// must be in 24bit mode when managing entities
CSetFPUPrecision FPUPrecision(FPT_24BIT);
// for each entity in the world
FOREACHINDYNAMICCONTAINER(wo_cenEntities, CEntity, iten) {
CEntity &en = *iten;
// cache eventual collision info
en.FindCollisionInfo();
en.UpdateSpatialRange();
// link it
if (!_bEntitySectorLinksPreLoaded) {
en.FindSectorsAroundEntity();
}
}
// NOTE: this is here to force relinking for all moving zoning brushes after loading!
// for each entity in the world
{FOREACHINDYNAMICCONTAINER(wo_cenEntities, CEntity, iten) {
CEntity &en = *iten;
if (en.en_RenderType==CEntity::RT_BRUSH &&
(en.en_ulFlags&ENF_ZONING) && (en.en_ulPhysicsFlags&EPF_MOVABLE)){
// recalculate all bounding boxes relative to new position
extern BOOL _bDontDiscardLinks;
_bDontDiscardLinks = TRUE;
en.en_pbrBrush->CalculateBoundingBoxes();
_bDontDiscardLinks = FALSE;
// FPU must be in 53-bit mode
CSetFPUPrecision FPUPrecision(FPT_53BIT);
// for all brush mips
FOREACHINLIST(CBrushMip, bm_lnInBrush, en.en_pbrBrush->br_lhBrushMips, itbm) {
// for all sectors in the mip
{FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc) {
// find entities in sector
itbsc->FindEntitiesInSector();
}}
}
}
}}
_pfWorldEditingProfile.StopTimer(CWorldEditingProfile::PTI_LINKENTITIESTOSECTORS);
}
// rebuild all links in world
void CWorld::RebuildLinks(void)
{
wo_baBrushes.LinkPortalsAndSectors();
_bEntitySectorLinksPreLoaded = FALSE;
LinkEntitiesToSectors();
}
/* Update sectors during brush vertex moving */
void CWorld::UpdateSectorsDuringVertexChange( CBrushVertexSelection &selVertex)
{
// create container of sectors that will need to be updated
CDynamicContainer<CBrushSector> cbscToUpdate;
{FOREACHINDYNAMICCONTAINER( selVertex, CBrushVertex, itbvx)
{
// add the sector of that vertex to list for updating
if (!cbscToUpdate.IsMember(itbvx->bvx_pbscSector)) {
cbscToUpdate.Add(itbvx->bvx_pbscSector);
}
}}
// for each sector to be updated
{FOREACHINDYNAMICCONTAINER( cbscToUpdate, CBrushSector, itbsc){
// recalculate planes for polygons from their vertices
itbsc->MakePlanesFromVertices();
}}
}
/* Update sectors after brush vertex moving */
void CWorld::UpdateSectorsAfterVertexChange( CBrushVertexSelection &selVertex)
{
// create container of sectors that will need to be updated
CDynamicContainer<CBrushSector> cbscToUpdate;
{FOREACHINDYNAMICCONTAINER( selVertex, CBrushVertex, itbvx)
{
// add the sector of that vertex to list for updating
if (!cbscToUpdate.IsMember(itbvx->bvx_pbscSector)) {
cbscToUpdate.Add(itbvx->bvx_pbscSector);
}
}}
// for each sector to be updated
{FOREACHINDYNAMICCONTAINER( cbscToUpdate, CBrushSector, itbsc){
// update it
itbsc->UpdateVertexChanges();
}}
}
/* Triangularize polygons that contain vertices from given selection */
void CWorld::TriangularizeForVertices( CBrushVertexSelection &selVertex)
{
// create container of sectors that contain polygons that need to be triangularized
CDynamicContainer<CBrushSector> cbscToTriangularize;
{FOREACHINDYNAMICCONTAINER( selVertex, CBrushVertex, itbvx)
{
// add the sector of that vertex to list for triangularizing
if (!cbscToTriangularize.IsMember(itbvx->bvx_pbscSector)) {
cbscToTriangularize.Add(itbvx->bvx_pbscSector);
}
}}
// for each sector to be updated
{FOREACHINDYNAMICCONTAINER( cbscToTriangularize, CBrushSector, itbsc){
// update it
itbsc->TriangularizeForVertices(selVertex);
}}
}
// add this entity to prediction
void CEntity::AddToPrediction(void)
{
// this function may be called even for NULLs - so ignore it
if (this==NULL) {
return;
}
// if already added
if (en_ulFlags&ENF_WILLBEPREDICTED) {
// do nothing
return;
}
// mark as added
en_ulFlags|=ENF_WILLBEPREDICTED;
en_pwoWorld->wo_cenWillBePredicted.Add(this);
// add your dependents
AddDependentsToPrediction();
}
// mark all predictable entities that will be predicted using user-set criterions
void CWorld::MarkForPrediction(void)
{
extern INDEX cli_bPredictIfServer;
extern INDEX cli_bPredictLocalPlayers;
extern INDEX cli_bPredictRemotePlayers;
extern FLOAT cli_fPredictEntitiesRange;
static CStaticStackArray<FLOAT3D> avLocalPlayers;
avLocalPlayers.PopAll();
// for each player
for (INDEX iPlayer=0; iPlayer<CEntity::GetMaxPlayers(); iPlayer++) {
CEntity *pen = CEntity::GetPlayerEntity(iPlayer);
// if it exists
if (pen!=NULL) {
// find whether it is local
BOOL bLocal = _pNetwork->IsPlayerLocal(pen);
// if allowed for prediction
if ( bLocal && cli_bPredictLocalPlayers
|| !bLocal && cli_bPredictRemotePlayers) {
// add it
pen->AddToPrediction();
}
// if local
if (bLocal) {
// remember coordinates of the original entity, and eventual predictor coords
avLocalPlayers.Push() = pen->GetPlacement().pl_PositionVector;
avLocalPlayers.Push() = _pNetwork->ga_sesSessionState.GetPlayerPredictorPosition(iPlayer);
}
}
}
TIME tmNow = _pNetwork->ga_sesSessionState.ses_tmPredictionHeadTick;
// for each predictable entity
{FOREACHINDYNAMICCONTAINER(wo_cenPredictable, CEntity, iten){
CEntity &en = *iten;
// it must not be void (so that its coordinates are relevant)
ASSERT(en.GetRenderType()!=CEntity::RT_VOID);
// get its upper time limit for prediction
TIME tmLimit = en.GetPredictionTime();
// if now inside time prediction interval
if (tmNow<tmLimit) {
// add it to prediction
iten->AddToPrediction();
continue;
}
// if predicting entities by range
if (cli_fPredictEntitiesRange>0) {
FLOAT fRange = en.GetPredictionRange();
if (fRange<=0) {
continue;
}
fRange = Min(fRange, cli_fPredictEntitiesRange);
// get its coordinates and maximal prediction range
const FLOAT3D &v = en.GetPlacement().pl_PositionVector;
// check if it is within range of any local player
BOOL bInRange = FALSE;
for(INDEX i=0; i<avLocalPlayers.Count(); i++) {
if ((avLocalPlayers[i]-v).Length()<fRange) {
bInRange = TRUE;
break;
}
}
// if it is within the range
if (bInRange) {
// add it
iten->AddToPrediction();
}
}
}}
}
// unmark all predictable entities marked for prediction
void CWorld::UnmarkForPrediction(void)
{
// for each entity marked
{FOREACHINDYNAMICCONTAINER(wo_cenWillBePredicted, CEntity, iten){
// unmark for prediction
iten->en_ulFlags&=~ENF_WILLBEPREDICTED;
}}
wo_cenWillBePredicted.Clear();
}
// create predictors for predictable entities that are marked for prediction
void CWorld::CreatePredictors(void)
{
CDynamicContainer<CEntity> cenForPrediction;
// for each entity marked
{FOREACHINDYNAMICCONTAINER(wo_cenWillBePredicted, CEntity, iten){
// if not deleted
if (!(iten->en_ulFlags&ENF_DELETED)) {
// add to container
cenForPrediction.Add(iten);
}
// unmark
iten->en_ulFlags&=~ENF_WILLBEPREDICTED;
}}
wo_cenWillBePredicted.Clear();
// CPrintF("for prediction: %d\n", cenForPrediction.Count());
// create copies of those entities as predictors
CopyEntitiesToPredictors(cenForPrediction);
}
// delete all predictor entities
void CWorld::DeletePredictors(void)
{
// must be in 24bit mode when managing entities
CSetFPUPrecision FPUPrecision(FPT_24BIT);
// first remember eventual predicted player positions
_pNetwork->ga_sesSessionState.RememberPlayerPredictorPositions();
// make a copy of predictor container (for safe iteration)
CDynamicContainer<CEntity> cenPredictor = wo_cenPredictor;
// for each predictor
{FOREACHINDYNAMICCONTAINER( cenPredictor, CEntity, iten){
CEntity &en = *iten;
ASSERT(en.IsPredictor());
// destroy it
en.Destroy();
}}
// for each predicted
{FOREACHINDYNAMICCONTAINER( wo_cenPredicted, CEntity, iten){
CEntity &en = *iten;
ASSERT(en.IsPredicted());
// kill its pointer to predictor
en.SetPredictionPair(NULL);
// mark as not predicted
en.en_ulFlags&=~ENF_PREDICTED;
}}
ASSERT(_ctPredictorEntities==0);
wo_cenPredictor.Clear();
wo_cenPredicted.Clear();
// for each entity in the world
FOREACHINDYNAMICCONTAINER(wo_cenEntities, CEntity, iten) {
CEntity &en = *iten;
ASSERT(!en.IsPredictor());
}
}
// get entity by its ID
CEntity *CWorld::EntityFromID(ULONG ulID)
{
FOREACHINDYNAMICCONTAINER(wo_cenAllEntities, CEntity, iten) {
if (iten->en_ulID==ulID) {
return iten;
}
}
ASSERT(FALSE);
return NULL;
}
/* Triangularize selected polygons. */
void CWorld::TriangularizePolygons(CDynamicContainer<CBrushPolygon> &dcPolygons)
{
ClearMarkedForUseFlag();
CDynamicContainer<CBrushSector> cbscToProcess;
// for each polyon in selection
FOREACHINDYNAMICCONTAINER(dcPolygons, CBrushPolygon, itbpo)
{
CBrushPolygon &bp=*itbpo;
bp.bpo_ulFlags |= BPOF_MARKED_FOR_USE;
CBrushSector *pbsc=bp.bpo_pbscSector;
if( !cbscToProcess.IsMember( pbsc))
{
cbscToProcess.Add( pbsc);
}
}
FOREACHINDYNAMICCONTAINER(cbscToProcess, CBrushSector, itbsc)
{
itbsc->TriangularizeMarkedPolygons();
itbsc->UpdateVertexChanges();
}
}
// Clear marked for use flag on all polygons in world
void CWorld::ClearMarkedForUseFlag(void)
{
// for each entity in the world
FOREACHINDYNAMICCONTAINER(wo_cenEntities, CEntity, iten) {
// if it is brush entity
if (iten->en_RenderType == CEntity::RT_BRUSH) {
// for each mip in its brush
FOREACHINLIST(CBrushMip, bm_lnInBrush, iten->en_pbrBrush->br_lhBrushMips, itbm) {
// for all sectors in this mip
FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc) {
// for each polygon in the sector
FOREACHINSTATICARRAY(itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo) {
// discard marked for use flag
itbpo->bpo_ulFlags &= ~BPOF_MARKED_FOR_USE;
}
}
}
}
}
}