Serious-Engine/Sources/Engine/Entities/EntityCopying.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

748 lines
23 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/Entities/Entity.h>
#include <Engine/Entities/LastPositions.h>
#include <Engine/Entities/EntityProperties.h>
#include <Engine/Entities/EntityClass.h>
#include <Engine/Base/Translation.h>
#include <Engine/Base/Timer.h>
#include <Engine/Base/Console.h>
#include <Engine/Base/ListIterator.inl>
#include <Engine/Base/ErrorReporting.h>
#include <Engine/World/World.h>
#include <Engine/Math/Float.h>
#include <Engine/Math/Quaternion.h>
#include <Engine/Brushes/BrushArchive.h>
#include <Engine/Light/LightSource.h>
#include <Engine/Entities/ShadingInfo.h>
#include <Engine/Models/ModelObject.h>
#include <Engine/Sound/SoundObject.h>
#include <Engine/Templates/DynamicContainer.cpp>
#include <Engine/Templates/StaticArray.cpp>
#include <Engine/Templates/Selection.cpp>
class CPointerRemapping {
public:
CEntity *pr_penOriginal;
CEntity *pr_penCopy;
inline void Clear(void) {};
};
static CStaticArray<CPointerRemapping> _aprRemaps;
static BOOL _bRemapPointersToNULLs = TRUE;
BOOL _bReinitEntitiesWhileCopying = TRUE;
static BOOL _bMirrorAndStretch = FALSE;
static FLOAT _fStretch = 1.0f;
static enum WorldMirrorType _wmtMirror = WMT_NONE;
extern INDEX _ctPredictorEntities;
// mirror a placement of one entity
static void MirrorAndStretchPlacement(CPlacement3D &pl)
{
ASSERT(_wmtMirror==WMT_X||_wmtMirror==WMT_Y||_wmtMirror==WMT_Z||_wmtMirror==WMT_NONE);
// if there should be mirror
if (_wmtMirror!=WMT_NONE) {
// make rotation matrix for the placement
FLOATmatrix3D m;
MakeRotationMatrix(m, pl.pl_OrientationAngle);
// get row vectors, with object x flipped
FLOAT3D vX(-m(1,1),m(1,2),m(1,3));
FLOAT3D vY(-m(2,1),m(2,2),m(2,3));
FLOAT3D vZ(-m(3,1),m(3,2),m(3,3));
// flip needed axis
switch(_wmtMirror) {
case WMT_X:
pl.pl_PositionVector(1) = -pl.pl_PositionVector(1);
vX = -vX;
break;
case WMT_Y:
pl.pl_PositionVector(2) = -pl.pl_PositionVector(2);
vY = -vY;
break;
case WMT_Z:
pl.pl_PositionVector(3) = -pl.pl_PositionVector(3);
vZ = -vZ;
break;
default: ASSERT(FALSE);
}
// compose matrix back from the vectors
m(1,1) = vX(1); m(2,1) = vY(1); m(3,1) = vZ(1);
m(1,2) = vX(2); m(2,2) = vY(2); m(3,2) = vZ(2);
m(1,3) = vX(3); m(2,3) = vY(3); m(3,3) = vZ(3);
// decompose matrix into angles
DecomposeRotationMatrix(pl.pl_OrientationAngle, m);
}
pl.pl_PositionVector*=_fStretch;
}
CEntity *CEntity::FindRemappedEntityPointer(CEntity *penOriginal)
{
// if original is null
if (penOriginal==NULL) {
// copy is null
return NULL;
}
// try to find valid remap
{FOREACHINSTATICARRAY(_aprRemaps, CPointerRemapping, itpr) {
if (itpr->pr_penOriginal==penOriginal) {
return itpr->pr_penCopy;
}
}}
// if none found, copy is either null or original
return _bRemapPointersToNULLs?NULL:penOriginal;
}
/*
* Copy entity from another entity of same class.
* NOTES:
* - Doesn't copy placement, it must be done on creation.
* - Entity must be initialized afterwards.
*/
void CEntity::Copy(CEntity &enOther, ULONG ulFlags)
{
BOOL bRemapPointers = ulFlags & COPY_REMAP;
BOOL bMakePredictor = ulFlags & COPY_PREDICTOR;
// copy base class data
en_RenderType = enOther.en_RenderType;
en_ulPhysicsFlags = enOther.en_ulPhysicsFlags;
en_ulCollisionFlags = enOther.en_ulCollisionFlags;
en_ulFlags = enOther.en_ulFlags &
~(ENF_SELECTED|ENF_FOUNDINGRIDSEARCH|ENF_VALIDSHADINGINFO|ENF_INRENDERING);
en_ulSpawnFlags = enOther.en_ulSpawnFlags;
// if prediction
if (bMakePredictor) {
// set flags
en_ulFlags = (en_ulFlags&~(ENF_PREDICTED|ENF_PREDICTABLE))|ENF_PREDICTOR;
enOther.en_ulFlags = (enOther.en_ulFlags&~ENF_PREDICTOR)|ENF_PREDICTED;
} else {
en_ulFlags = (en_ulFlags&~(ENF_PREDICTED|ENF_PREDICTABLE|ENF_PREDICTOR));
}
// if this is a brush
if ( enOther.en_RenderType == RT_BRUSH || en_RenderType == RT_FIELDBRUSH) {
// there must be no existing brush
ASSERT(en_pbrBrush == NULL);
// create a new empty brush in the brush archive of current world
en_pbrBrush = en_pwoWorld->wo_baBrushes.ba_abrBrushes.New();
en_pbrBrush->br_penEntity = this;
// copy the brush
if (_bMirrorAndStretch) {
en_pbrBrush->Copy(*enOther.en_pbrBrush, _fStretch, _wmtMirror!=WMT_NONE);
} else {
en_pbrBrush->Copy(*enOther.en_pbrBrush, 1.0f, FALSE);
}
// if this is a terrain
} else if( enOther.en_RenderType == RT_TERRAIN) {
#pragma message(">> CEntity::Copy")
ASSERT(FALSE);
// if this is a model
} if ( enOther.en_RenderType == RT_MODEL || en_RenderType == RT_EDITORMODEL) {
// if will not initialize
if (!(ulFlags&COPY_REINIT)) {
// create a new model object
en_pmoModelObject = new CModelObject;
en_psiShadingInfo = new CShadingInfo;
en_ulFlags &= ~ENF_VALIDSHADINGINFO;
// copy it
en_pmoModelObject->Copy(*enOther.en_pmoModelObject);
}
// if this is ska model
} else if ( enOther.en_RenderType == RT_SKAMODEL || en_RenderType == RT_SKAEDITORMODEL) {
en_psiShadingInfo = new CShadingInfo;
en_ulFlags &= ~ENF_VALIDSHADINGINFO;
en_pmiModelInstance = CreateModelInstance("Temp");
// copy it
GetModelInstance()->Copy(*enOther.GetModelInstance());
}
// copy the parent pointer
if (bRemapPointers) {
en_penParent = FindRemappedEntityPointer(enOther.en_penParent);
} else {
en_penParent = enOther.en_penParent;
}
// if the entity has a parent
if (en_penParent!=NULL) {
// create relative offset
en_plRelativeToParent = en_plPlacement;
en_plRelativeToParent.AbsoluteToRelativeSmooth(en_penParent->en_plPlacement);
// link to parent
en_penParent->en_lhChildren.AddTail(en_lnInParent);
}
// copy the derived class properties
CopyEntityProperties(enOther, ulFlags);
// if prediction
if (bMakePredictor) {
// create cross-links and add to containers
SetPredictionPair(&enOther);
enOther.SetPredictionPair(this);
enOther.en_pwoWorld->wo_cenPredicted.Add(&enOther);
enOther.en_pwoWorld->wo_cenPredictor.Add(this);
// copy last positions
if (enOther.en_plpLastPositions!=NULL) {
en_plpLastPositions = new CLastPositions(*enOther.en_plpLastPositions);
}
}
}
/*
* Copy one entity property from property of another entity.
*/
void CEntity::CopyOneProperty( CEntityProperty &epPropertySrc, CEntityProperty &epPropertyDest,
CEntity &enOther, ULONG ulFlags)
{
// a helper macro
#define COPYPROPERTY(type) \
(type &)ENTITYPROPERTY(this, epPropertyDest.ep_slOffset, type) \
= (type &)ENTITYPROPERTY(&enOther, epPropertySrc.ep_slOffset, type)
// depending on the property type
switch (epPropertySrc.ep_eptType) {
// if it is BOOL
case CEntityProperty::EPT_BOOL:
// copy BOOL
COPYPROPERTY(INDEX);
break;
// if it is INDEX
case CEntityProperty::EPT_INDEX:
case CEntityProperty::EPT_ENUM:
case CEntityProperty::EPT_FLAGS:
case CEntityProperty::EPT_ANIMATION:
case CEntityProperty::EPT_ILLUMINATIONTYPE:
case CEntityProperty::EPT_COLOR:
case CEntityProperty::EPT_ANGLE:
// copy INDEX
COPYPROPERTY(INDEX);
break;
// if it is FLOAT
case CEntityProperty::EPT_FLOAT:
case CEntityProperty::EPT_RANGE:
// copy FLOAT
COPYPROPERTY(FLOAT);
break;
// if it is STRING
case CEntityProperty::EPT_STRING:
case CEntityProperty::EPT_STRINGTRANS:
// copy STRING
COPYPROPERTY(CTString);
break;
// if it is FILENAME
case CEntityProperty::EPT_FILENAME:
// copy FILENAME
COPYPROPERTY(CTFileName);
break;
// if it is FILENAMENODEP
case CEntityProperty::EPT_FILENAMENODEP:
// copy FILENAMENODEP
COPYPROPERTY(CTFileNameNoDep);
break;
// if it is FLOATAABBOX3D
case CEntityProperty::EPT_FLOATAABBOX3D:
// copy FLOATAABBOX3D
COPYPROPERTY(FLOATaabbox3D);
break;
// if it is FLOATMATRIX3D
case CEntityProperty::EPT_FLOATMATRIX3D:
// copy FLOATMATRIX3D
COPYPROPERTY(FLOATmatrix3D);
break;
// if it is FLOAT3D
case CEntityProperty::EPT_FLOAT3D:
// copy FLOAT3D
COPYPROPERTY(FLOAT3D);
break;
// if it is ANGLE3D
case CEntityProperty::EPT_ANGLE3D:
// copy ANGLE3D
COPYPROPERTY(ANGLE3D);
break;
// if it is QUATERNION3D
case CEntityProperty::EPT_FLOATQUAT3D:
// copy ANGLE3D
COPYPROPERTY(FLOATquat3D);
break;
// if it is FLOATplane3D
case CEntityProperty::EPT_FLOATplane3D:
// copy FLOATplane3D
COPYPROPERTY(FLOATplane3D);
break;
// if it is ENTITYPTR
case CEntityProperty::EPT_ENTITYPTR:
// remap and copy the pointer
if (ulFlags & COPY_REMAP) {
ENTITYPROPERTY(this, epPropertyDest.ep_slOffset, CEntityPointer) =
FindRemappedEntityPointer(ENTITYPROPERTY(&enOther, epPropertySrc.ep_slOffset, CEntityPointer));
// copy CEntityPointer
} else {
COPYPROPERTY(CEntityPointer);
}
break;
// if it is MODELOBJECT
case CEntityProperty::EPT_MODELOBJECT:
// copy CModelObject
ENTITYPROPERTY(this, epPropertyDest.ep_slOffset, CModelObject).
Copy(ENTITYPROPERTY(&enOther, epPropertySrc.ep_slOffset, CModelObject));
// model objects are not copied, but should be initialized in Main()
break;
// if it is MODELINSTANCE
case CEntityProperty::EPT_MODELINSTANCE:
// copy CModelInstance
ENTITYPROPERTY(this, epPropertyDest.ep_slOffset, CModelInstance).
Copy(ENTITYPROPERTY(&enOther, epPropertySrc.ep_slOffset, CModelInstance));
// model objects are not copied, but should be initialized in Main()
break;
// if it is ANIMOBJECT
case CEntityProperty::EPT_ANIMOBJECT:
// copy CAnimObject
ENTITYPROPERTY(this, epPropertyDest.ep_slOffset, CAnimObject).
Copy(ENTITYPROPERTY(&enOther, epPropertySrc.ep_slOffset, CAnimObject));
break;
// if it is SOUNDOBJECT
case CEntityProperty::EPT_SOUNDOBJECT:
{
if (!(ulFlags & COPY_PREDICTOR)) {
// copy CSoundObject
CSoundObject &so = ENTITYPROPERTY(this, epPropertyDest.ep_slOffset, CSoundObject);
so.Copy(ENTITYPROPERTY(&enOther, epPropertySrc.ep_slOffset, CSoundObject));
so.so_penEntity = this;
}
}
break;
// if it is CPlacement3D
case CEntityProperty::EPT_PLACEMENT3D:
// copy CPlacement3D
COPYPROPERTY(CPlacement3D);
break;
default:
ASSERTALWAYS("Unknown property type");
}
}
/*
* Copy entity properties from another entity of same class.
*/
void CEntity::CopyEntityProperties(CEntity &enOther, ULONG ulFlags)
{
// other entity must have same class
ASSERT(enOther.en_pecClass == en_pecClass);
// for all classes in hierarchy of this entity
for(CDLLEntityClass *pdecDLLClass = en_pecClass->ec_pdecDLLClass;
pdecDLLClass!=NULL;
pdecDLLClass = pdecDLLClass->dec_pdecBase) {
// for all properties
for(INDEX iProperty=0; iProperty<pdecDLLClass->dec_ctProperties; iProperty++) {
CEntityProperty &epProperty = pdecDLLClass->dec_aepProperties[iProperty];
CopyOneProperty( epProperty, epProperty, enOther, ulFlags);
}
}
}
/* Copy container of entities from another world to this one and select them. */
void CWorld::CopyEntities(CWorld &woOther, CDynamicContainer<CEntity> &cenToCopy,
CEntitySelection &senCopied, const CPlacement3D &plOtherSystem)
{
INDEX ctEntities = cenToCopy.Count();
if (ctEntities<=0) {
return;
}
CSetFPUPrecision FPUPrecision(FPT_24BIT);
ULONG ulCopyFlags = COPY_REMAP;
if(_bReinitEntitiesWhileCopying) {
ulCopyFlags|=COPY_REINIT;
};
// create array of pointer remaps
_aprRemaps.Clear();
_aprRemaps.New(ctEntities);
// PASS 1: create entities
// for each entity to copy
INDEX iRemap = 0;
{FOREACHINDYNAMICCONTAINER(cenToCopy, CEntity, itenToCopy) {
CEntity &enToCopy = *itenToCopy;
CEntity *penNew;
CPlacement3D plEntity;
// thansform the entity placement from the system of other world
plEntity = enToCopy.en_plPlacement;
plEntity.RelativeToAbsolute(plOtherSystem);
// mirror and stretch placement if needed
if (_bMirrorAndStretch) {
MirrorAndStretchPlacement(plEntity);
}
/*
* NOTE: We must use CreateEntity_t() overload with class name instead with class pointer
* because the entity class must be obtained by the target world too!
*/
// try to
try {
// create an entity of same class as the one to copy
penNew = CreateEntity_t(plEntity, enToCopy.en_pecClass->GetName());
// if not successfull
} catch (char *strError) {
(void)strError;
ASSERT(FALSE); // this should not happen
FatalError(TRANS("Cannot CopyEntity():\n%s"), strError);
}
// remember its remap pointer
_aprRemaps[iRemap].pr_penOriginal = &enToCopy;
_aprRemaps[iRemap].pr_penCopy = penNew;
iRemap++;
}}
// PASS 2: copy properties
// for each of the created entities
{FOREACHINSTATICARRAY(_aprRemaps, CPointerRemapping, itpr) {
CEntity *penOriginal = itpr->pr_penOriginal;
CEntity *penCopy = itpr->pr_penCopy;
// copy the entity from its original
penCopy->Copy(*penOriginal, ulCopyFlags);
// if this is a brush
if ( penOriginal->en_RenderType == CEntity::RT_BRUSH ||
penOriginal->en_RenderType == CEntity::RT_FIELDBRUSH) {
// update the bounding boxes of the brush
penCopy->en_pbrBrush->CalculateBoundingBoxes();
}
if (_bMirrorAndStretch) {
penCopy->MirrorAndStretch(_fStretch, _wmtMirror!=WMT_NONE);
}
}}
// PASS 3: initialize
// for each of the created entities
{FOREACHINSTATICARRAY(_aprRemaps, CPointerRemapping, itpr) {
//CEntity *penOriginal = itpr->pr_penOriginal;
CEntity *penCopy = itpr->pr_penCopy;
if (_bReinitEntitiesWhileCopying) {
// init the new copy
penCopy->Initialize();
} else {
penCopy->UpdateSpatialRange();
penCopy->FindCollisionInfo();
// set spatial clasification
penCopy->FindSectorsAroundEntity();
}
}}
// PASS 4: find shadows
// for each of the created entities
{FOREACHINSTATICARRAY(_aprRemaps, CPointerRemapping, itpr) {
//CEntity *penOriginal = itpr->pr_penOriginal;
CEntity *penCopy = itpr->pr_penCopy;
// if this is a brush
if ( penCopy->en_RenderType == CEntity::RT_BRUSH ||
penCopy->en_RenderType == CEntity::RT_FIELDBRUSH) {
// find possible shadow layers near affected area
FindShadowLayers(penCopy->en_pbrBrush->GetFirstMip()->bm_boxBoundingBox);
}
// if this is a light source
{CLightSource *pls = penCopy->GetLightSource();
if (pls!=NULL) {
// find all shadow maps that should have layers from this light source
pls->FindShadowLayers(FALSE);
// update shadow map on terrains
pls->UpdateTerrains();
}}
// select it
senCopied.Select(*penCopy);
}}
// make sure someone doesn't reuse the remap array accidentially
_aprRemaps.Clear();
}
/* Copy one entity from another world into this one. */
CEntity *CWorld::CopyOneEntity(CEntity &enToCopy, const CPlacement3D &plOtherSystem)
{
// prepare container for copying
CDynamicContainer<CEntity> cenToCopy;
cenToCopy.Add(&enToCopy);
// copy the entities in container
CEntitySelection senCopied;
CopyEntities(*enToCopy.en_pwoWorld, cenToCopy, senCopied, plOtherSystem);
{FOREACHINDYNAMICCONTAINER(senCopied, CEntity, itenCopied) {
return itenCopied;
}}
ASSERT(FALSE);
return NULL;
}
/*
* Copy all entities except one from another world to this one.
*/
void CWorld::CopyAllEntitiesExceptOne(CWorld &woOther, CEntity &enExcepted,
const CPlacement3D &plOtherSystem)
{
// prepare container for copying, without excepted entity
CDynamicContainer<CEntity> cenToCopy;
cenToCopy = woOther.wo_cenEntities;
cenToCopy.Remove(&enExcepted);
// copy the entities in container and ignore the selection (we don't need it)
CEntitySelection senCopied;
CopyEntities(woOther, cenToCopy, senCopied, plOtherSystem);
senCopied.Clear();
}
/* Copy entity in world. */
CEntity *CWorld::CopyEntityInWorld(CEntity &enOriginal, const CPlacement3D &plOtherEntity,
BOOL bWithDescendants /*= TRUE*/)
{
// new entity
CEntity *penNew;
/*
* NOTE: We must use CreateEntity_t() overload with class name instead with class pointer
* because the entity class must be obtained by the target world too!
*/
// try to
try {
// create an entity of same class as the one to copy
penNew = CreateEntity_t(plOtherEntity, enOriginal.en_pecClass->GetName());
// if not successfull
} catch (char *strError) {
(void)strError;
ASSERT(FALSE); // this should not happen
FatalError(TRANS("Cannot CopyEntity():\n%s"), strError);
}
// copy the entity from its original
penNew->Copy(enOriginal, COPY_REINIT);
// if this is a brush
if ( enOriginal.en_RenderType == CEntity::RT_BRUSH ||
enOriginal.en_RenderType == CEntity::RT_FIELDBRUSH) {
// update the bounding boxes of the brush
penNew->en_pbrBrush->CalculateBoundingBoxes();
}
// init the new copy
penNew->Initialize();
// if this is a brush
if ( penNew->en_RenderType == CEntity::RT_BRUSH ||
penNew->en_RenderType == CEntity::RT_FIELDBRUSH) {
// find possible shadow layers near affected area
FindShadowLayers(penNew->en_pbrBrush->GetFirstMip()->bm_boxBoundingBox);
}
// if this is a light source
{CLightSource *pls = penNew->GetLightSource();
if (pls!=NULL) {
// find all shadow maps that should have layers from this light source
pls->FindShadowLayers(FALSE);
}}
// if descendants should be copied too
if (bWithDescendants) {
// for each child of this entity
{FOREACHINLIST(CEntity, en_lnInParent, enOriginal.en_lhChildren, itenChild) {
// copy it relatively to the new entity
CPlacement3D plChild = itenChild->en_plRelativeToParent;
plChild.RelativeToAbsoluteSmooth(penNew->en_plPlacement);
CEntity *penNewChild = CopyEntityInWorld(*itenChild, plChild, TRUE);
// add new child to its new parent
penNewChild->SetParent(penNew);
}}
}
return penNew;
}
// mirror and stretch another world into this one
void CWorld::MirrorAndStretch(CWorld &woOriginal, FLOAT fStretch, enum WorldMirrorType wmt)
{
_bMirrorAndStretch = TRUE;
_fStretch = fStretch;
_wmtMirror = wmt;
// clear this world
Clear();
// make container for copying
CDynamicContainer<CEntity> cenToCopy;
cenToCopy = woOriginal.wo_cenEntities;
// dummy selection for copied entities, we don't need that info
CEntitySelection senCopied;
// make mirroring placement
CPlacement3D plOtherSystem;
plOtherSystem = CPlacement3D(FLOAT3D(0,0,0), ANGLE3D(0,0,0));
// copy entities with mirror and stretch
CopyEntities(woOriginal, cenToCopy, senCopied, plOtherSystem);
// update all links
{
CSetFPUPrecision FPUPrecision(FPT_53BIT);
wo_baBrushes.LinkPortalsAndSectors();
}
_bMirrorAndStretch = FALSE;
}
/* Copy entities for prediction. */
void CWorld::CopyEntitiesToPredictors(CDynamicContainer<CEntity> &cenToCopy)
{
INDEX ctEntities = cenToCopy.Count();
if (ctEntities<=0) {
return;
}
extern INDEX cli_bReportPredicted;
if (cli_bReportPredicted) {
CPrintF( TRANS("Predicting %d entities:\n"), ctEntities);
{FOREACHINDYNAMICCONTAINER(cenToCopy, CEntity, itenToCopy) {
CEntity &enToCopy = *itenToCopy;
CPrintF(" %s:%s\n", enToCopy.GetClass()->ec_pdecDLLClass->dec_strName, (const char*)enToCopy.GetName());
}}
}
// clear current tick to prevent timer setting from assertions
TIME tmCurrentTickOld = _pTimer->CurrentTick();
_pTimer->SetCurrentTick(0.0f);
ULONG ulCopyFlags = COPY_REMAP|COPY_PREDICTOR;
// create array of pointer remaps
_aprRemaps.Clear();
_aprRemaps.New(ctEntities);
// PASS 1: create entities
// for each entity to copy
INDEX iRemap = 0;
{FOREACHINDYNAMICCONTAINER(cenToCopy, CEntity, itenToCopy) {
CEntity &enToCopy = *itenToCopy;
CEntity *penNew;
// create an entity of same class as the one to copy
penNew = CreateEntity(enToCopy.en_plPlacement, enToCopy.en_pecClass);
// remember its remap pointer
_aprRemaps[iRemap].pr_penOriginal = &enToCopy;
_aprRemaps[iRemap].pr_penCopy = penNew;
iRemap++;
_ctPredictorEntities++;
}}
// unfound pointers must be kept unremapped
_bRemapPointersToNULLs = FALSE;
// PASS 2: copy properties
// for each of the created entities
{FOREACHINSTATICARRAY(_aprRemaps, CPointerRemapping, itpr) {
CEntity *penOriginal = itpr->pr_penOriginal;
CEntity *penCopy = itpr->pr_penCopy;
// copy the entity from its original
penCopy->Copy(*penOriginal, ulCopyFlags);
// if this is a brush
if ( penOriginal->en_RenderType == CEntity::RT_BRUSH ||
penOriginal->en_RenderType == CEntity::RT_FIELDBRUSH) {
ASSERT(FALSE); // should we allow prediction of brushes?
// update the bounding boxes of the brush
//penCopy->en_pbrBrush->CalculateBoundingBoxes();
}
}}
// PASS 3: initialize
// for each of the created entities
{FOREACHINSTATICARRAY(_aprRemaps, CPointerRemapping, itpr) {
CEntity *penOriginal = itpr->pr_penOriginal;
CEntity *penCopy = itpr->pr_penCopy;
// copy spatial classification
penCopy->en_fSpatialClassificationRadius = penOriginal->en_fSpatialClassificationRadius;
penCopy->en_boxSpatialClassification = penOriginal->en_boxSpatialClassification;
// copy collision info
penCopy->CopyCollisionInfo(*penOriginal);
// for each sector around the original
{FOREACHSRCOFDST(penOriginal->en_rdSectors, CBrushSector, bsc_rsEntities, pbsc)
// copy the link
if (penOriginal->en_RenderType==CEntity::RT_BRUSH
||penOriginal->en_RenderType==CEntity::RT_FIELDBRUSH
||penOriginal->en_RenderType==CEntity::RT_TERRAIN) { // brushes first
AddRelationPairHeadHead(pbsc->bsc_rsEntities, penCopy->en_rdSectors);
} else {
AddRelationPairTailTail(pbsc->bsc_rsEntities, penCopy->en_rdSectors);
}
ENDFOR}
}}
// PASS 4: find shadows
// for each of the created entities
{FOREACHINSTATICARRAY(_aprRemaps, CPointerRemapping, itpr) {
//CEntity *penOriginal = itpr->pr_penOriginal;
CEntity *penCopy = itpr->pr_penCopy;
// if this is a brush
if ( penCopy->en_RenderType == CEntity::RT_BRUSH ||
penCopy->en_RenderType == CEntity::RT_FIELDBRUSH) {
ASSERT(FALSE); // should we allow prediction of brushes?
// find possible shadow layers near affected area
//FindShadowLayers(penCopy->en_pbrBrush->GetFirstMip()->bm_boxBoundingBox);
}
// if this is a light source
{CLightSource *pls = penCopy->GetLightSource();
if (pls!=NULL) {
// find all shadow maps that should have layers from this light source
pls->FindShadowLayers(FALSE);
}}
}}
// make sure someone doesn't reuse the remap array accidentially
_aprRemaps.Clear();
_bRemapPointersToNULLs = TRUE;
// return current tick
_pTimer->SetCurrentTick(tmCurrentTickOld);
}