Files
FC1/Cry3DEngine/terrain_damage.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

229 lines
6.9 KiB
C++

////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: terrain_damage.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: terrain deformations
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "terrain_sector.h"
#include "detail_grass.h"
#include "objman.h"
void CTerrain::ExplodeTerrain(Vec3d vExploPos, float fExploRadius, CObjManager * pObjManager, bool bDeformTerrain)
{
// calc area
int x1=int(vExploPos.x-fExploRadius-CTerrain::GetHeightMapUnitSize());
int y1=int(vExploPos.y-fExploRadius-CTerrain::GetHeightMapUnitSize());
int x2=int(vExploPos.x+fExploRadius+CTerrain::GetHeightMapUnitSize());
int y2=int(vExploPos.y+fExploRadius+CTerrain::GetHeightMapUnitSize());
int nUnitSize = GetHeightMapUnitSize();
x1=x1/nUnitSize*nUnitSize;
x2=x2/nUnitSize*nUnitSize;
y1=y1/nUnitSize*nUnitSize;
y2=y2/nUnitSize*nUnitSize;
// limits
if(x1<0) x1=0;
if(y1<0) y1=0;
if(x2>=CTerrain::GetTerrainSize()) x2=CTerrain::GetTerrainSize()-1;
if(y2>=CTerrain::GetTerrainSize()) y2=CTerrain::GetTerrainSize()-1;
fExploRadius -= (float)fabs(vExploPos.z - GetZ(int((x1+x2)/2.f),int((y1+y2)/2.f)));
if(fExploRadius<0.125f)
return; // to hight
// get near sectors
list2<CSectorInfo*> lstNearSecInfos;
for(int x=x1; x<=x2; x++)
for(int y=y1; y<=y2; y++)
{
CSectorInfo * pInfo = GetSecInfo(x,y);
if(pInfo && lstNearSecInfos.Find(pInfo)<0)
lstNearSecInfos.Add(pInfo);
}
{
CSectorInfo * pInfo = GetSecInfo(0,0);
if(pInfo && lstNearSecInfos.Find(pInfo)<0)
lstNearSecInfos.Add(pInfo);
}
// remove small objects around
int s;
for( s=0; s<lstNearSecInfos.Count(); s++)
{
CSectorInfo * pSecInfo = lstNearSecInfos[s];
for(int i=0; i<pSecInfo->m_lstEntities[STATIC_ENTITIES].Count(); i++)
{
IEntityRender * pEntityRender = pSecInfo->m_lstEntities[STATIC_ENTITIES][i];
Vec3d vEntBoxMin,vEntBoxMax;
pEntityRender->GetBBox(vEntBoxMin,vEntBoxMax);
float fEntRadius = vEntBoxMin.GetDistance(vEntBoxMax)*0.5f;
Vec3d vEntCenter = (vEntBoxMin+vEntBoxMax)*0.5;
float fDist = GetDistance(vExploPos,vEntCenter);
if(fDist < fExploRadius+fEntRadius &&
Overlap::Sphere_AABB(Sphere(vExploPos,fExploRadius), AABB(vEntBoxMin,vEntBoxMax)))
{
if(fDist>=fExploRadius)
{ //
Matrix44 objMat;
CStatObj * pStatObj = (CStatObj *)pEntityRender->GetEntityStatObj(0,&objMat);
if(!pStatObj)
continue;
objMat.Invert44();
Vec3d vOSExploPos = objMat.TransformPointOLD(vExploPos);
Vec3d vScaleTest(0,0,1.f);
vScaleTest = objMat.TransformVectorOLD(vScaleTest);
float fObjScaleInv = vScaleTest.len();
if(!pStatObj->IsSphereOverlap(Sphere(vOSExploPos,fExploRadius*fObjScaleInv)))
continue;
}
if(1)
{
if(pEntityRender->GetEntityRenderType() == eERType_Vegetation && fEntRadius < fExploRadius)
{ // remove this object
pSecInfo->m_lstEntities[STATIC_ENTITIES].Delete(i);
delete pEntityRender;
i--;
}
else
{ // if something was imposible to destroy - disable deformation
bDeformTerrain = false;
}
}
}
}
}
if(GetCVars()->e_decals == 2)
UpdateLoadingScreen("CTerrain::ExplodeTerrain: %s", bDeformTerrain ? "Yes" : "No");
// find min max of result
float fResultZMin, fResultZMax;
fResultZMin = fResultZMax = GetHMValue(x1,y1)*TERRAIN_Z_RATIO;
// modify hightfield
for(int x=x1; x<=x2; x+=CTerrain::GetHeightMapUnitSize())
for(int y=y1; y<=y2; y+=CTerrain::GetHeightMapUnitSize())
{
ushort & sValue = GetHMValue(x,y);
float fDamage = (fExploRadius - GetDistance(vExploPos,Vec3d((float)x,(float)y,GetZ(x,y))))/fExploRadius;
if(fDamage<0)
continue;
if(sValue*TERRAIN_Z_RATIO > fResultZMax)
fResultZMax = sValue*TERRAIN_Z_RATIO;
// remember flags
int flags = sValue & (INFO_BITS_MASK);
if(bDeformTerrain && sValue > GetWaterLevel()*256+0.25f*256) // do not change hmap if there are trees here
{
sValue -= short(fDamage*2/TERRAIN_Z_RATIO);
if(sValue < GetWaterLevel()*256+0.25f*256)
sValue = short(GetWaterLevel()*256+0.25f*256);
}
if(fDamage>0.5f)
flags |= EXPLO_BIT_MASK;
// restore flags
sValue = (sValue & ~(INFO_BITS_MASK)) | flags ;
m_bHightMapModified = true;
if(sValue*TERRAIN_Z_RATIO < fResultZMin)
fResultZMin = sValue*TERRAIN_Z_RATIO;
}
// update terrain video buffers
for(s=0; s<lstNearSecInfos.Count(); s++)
{
CSectorInfo * pSecInfo = lstNearSecInfos[s];
if(pSecInfo)
{
pSecInfo->ReleaseHeightMapVertBuffer();
pSecInfo->SetMinMaxMidZ();
}
}
// update detail texture layers
m_nDetailTexFocusX=m_nDetailTexFocusY=-CTerrain::GetTerrainSize();
if(m_pDetailObjects)
m_pDetailObjects->UpdateGrass();
// delete decals what can not be correctly updated
Get3DEngine()->DeleteDecalsInRange( Vec3d((float)x1,(float)y1,fResultZMin), Vec3d((float)x2,(float)y2,fResultZMax+1.f), false );
}
void CTerrain::GetObjectsAround(Vec3d vExploPos, float fExploRadius, list2<IEntityRender*> * pEntList)
{
assert(pEntList);
// calc area
int x1=int(vExploPos.x-fExploRadius-TERRAIN_SECTORS_MAX_OVERLAPPING);
int y1=int(vExploPos.y-fExploRadius-TERRAIN_SECTORS_MAX_OVERLAPPING);
int x2=int(vExploPos.x+fExploRadius+TERRAIN_SECTORS_MAX_OVERLAPPING);
int y2=int(vExploPos.y+fExploRadius+TERRAIN_SECTORS_MAX_OVERLAPPING);
int nUnitSize = GetHeightMapUnitSize();
x1=x1/nUnitSize*nUnitSize;
x2=x2/nUnitSize*nUnitSize;
y1=y1/nUnitSize*nUnitSize;
y2=y2/nUnitSize*nUnitSize;
// limits
if(x1<0) x1=0;
if(y1<0) y1=0;
if(x2>=CTerrain::GetTerrainSize()) x2=CTerrain::GetTerrainSize()-nUnitSize;
if(y2>=CTerrain::GetTerrainSize()) y2=CTerrain::GetTerrainSize()-nUnitSize;
// get near outdoor sectors
list2<CSectorInfo*> lstNearSecInfos;
for(int x=x1; x<=x2; x+=nUnitSize)
for(int y=y1; y<=y2; y+=nUnitSize)
{
CSectorInfo * pInfo = GetSecInfo(x,y);
if(pInfo && lstNearSecInfos.Find(pInfo)<0)
lstNearSecInfos.Add(pInfo);
}
{ // add 0,0 outdoor sector
CSectorInfo * pInfo = GetSecInfo(0,0);
if(pInfo && lstNearSecInfos.Find(pInfo)<0)
lstNearSecInfos.Add(pInfo);
}
// find static objects around
for( int s=0; s<lstNearSecInfos.Count(); s++)
{
CSectorInfo * pSecInfo = lstNearSecInfos[s];
for(int i=0; i<pSecInfo->m_lstEntities[STATIC_ENTITIES].Count(); i++)
{
IEntityRender * pEntityRender = pSecInfo->m_lstEntities[STATIC_ENTITIES][i];
Vec3d vEntBoxMin, vEntBoxMax;
pEntityRender->GetBBox(vEntBoxMin, vEntBoxMax);
if(Overlap::Sphere_AABB(Sphere(vExploPos,fExploRadius), AABB(vEntBoxMin,vEntBoxMax)))
if(pEntList->Find(pEntityRender)<0)
pEntList->Add(pEntityRender);
}
}
}