This commit is contained in:
romkazvo
2023-08-07 19:29:24 +08:00
commit 34d6c5d489
4832 changed files with 1389451 additions and 0 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,423 @@
/*
=====================================================================
FILE : 3dEngineScreenEffects.cpp
DESC : Screen processing effects
PROJ : Crytek Engine
CODER: Tiago Sousa
Last Update: 09/12/2003
TODO:
.Clean up code...
.Remove all SCREEN_PROCESS stuff (Set/GetParameter, etc)
=====================================================================
*/
#include "stdafx.h"
#include "3dEngine.h"
#include "objman.h"
#include "../RenderDll/Common/RendElements/CREScreenCommon.h"
// some helper macros
#define GET_ACTIVEPARAMETER(pProcess) \
*((bool*)m_pREScreenProcess->mfGetParameter((pProcess), SCREENPROCESS_ACTIVE)) \
#define GET_CVAR(pVar)\
(GetConsole()->GetCVar((pVar)))\
// interfaces for script usage
// set screen mask texture
void C3DEngine:: SetBlurMask(ITexPic *pMask)
{
if(!m_pBlurObj)
{
return;
}
//m_pBlurObj->SetBlurMask((STexPic*) pMask);
}
// set screen mask texture
void C3DEngine:: SetScreenMask(ITexPic *pMask)
{
if(!m_pScreenObj)
{
return;
}
//m_pScreenObj->SetScreenMask((STexPic*) pMask);
}
// setup current screen fx
void C3DEngine:: SetScreenFx(const char *pEffectName, int iActive)
{
bool bActive=iActive? 1:0;
// to avoid an untreackable crash in mscvdll strcmp
if (!pEffectName)
{
return;
}
if(!strcmp(pEffectName, "NightVision"))
{
int iActive=bActive;
m_pREScreenProcess->mfSetParameter(SCREENPROCESS_NIGHTVISION, SCREENPROCESS_ACTIVE, &iActive);
}
else
if(!strcmp(pEffectName, "HeatVision"))
{
int iActive=bActive;
m_pREScreenProcess->mfSetParameter(SCREENPROCESS_HEATVISION, SCREENPROCESS_ACTIVE, &iActive);
}
else
if(!strcmp(pEffectName, "ScreenBlur"))
{
m_pREScreenProcess->mfSetParameter(SCREENPROCESS_BLUR, SCREENPROCESS_ACTIVE, &bActive);
}
else
if(!strcmp(pEffectName, "FlashBang"))
{
m_pREScreenProcess->mfSetParameter(SCREENPROCESS_FLASHBANG, SCREENPROCESS_ACTIVE, &bActive);
}
else
if(!strcmp(pEffectName, "ScreenFade"))
{
m_pREScreenProcess->mfSetParameter(SCREENPROCESS_FADE, SCREENPROCESS_ACTIVE, &bActive);
}
}
// Setup current screen fx parameter
void C3DEngine:: SetScreenFxParam(const char *pEffectName, const char *pEffectParam, void *pValue)
{
// <<TODO>> add required/missing parameters
// to avoid an untreackable crash in mscvdll strcmp
if (!pEffectName || !pEffectParam)
{
return;
}
// set parameters for screen fade
if(!stricmp(pEffectName, "ScreenFade"))
{
if(!stricmp(pEffectParam, "ScreenFadeTime")) // set screen fade flag
{
m_pREScreenProcess->mfSetParameter(SCREENPROCESS_FADE, SCREENPROCESS_TRANSITIONTIME, pValue);
}
else
if(!stricmp(pEffectParam, "ScreenPreFadeTime")) // set screen pre fade flag (count number of frames, before start fading)
{
m_pREScreenProcess->mfSetParameter(SCREENPROCESS_FADE, SCREENPROCESS_PRETRANSITIONTIME, pValue);
}
}
else
if(!stricmp(pEffectName, "ScreenBlur")) // set parameters for screen blur
{
if(!stricmp(pEffectParam, "ScreenBlurAmount")) // screen blur amount
{
m_pREScreenProcess->mfSetParameter(SCREENPROCESS_BLUR, SCREENPROCESS_BLURAMOUNT, pValue);
}
else
if(!stricmp(pEffectParam, "ScreenBlurColorRed")) // screen blur color red..
{
m_pREScreenProcess->mfSetParameter(SCREENPROCESS_BLUR, SCREENPROCESS_BLURCOLORRED, pValue);
}
else
if(!stricmp(pEffectParam, "ScreenBlurColorGreen")) // screen blur color green..
{
m_pREScreenProcess->mfSetParameter(SCREENPROCESS_BLUR, SCREENPROCESS_BLURCOLORGREEN, pValue);
}
else
if(!stricmp(pEffectParam, "ScreenBlurColorBlue")) // screen blur color blue..
{
m_pREScreenProcess->mfSetParameter(SCREENPROCESS_BLUR, SCREENPROCESS_BLURCOLORBLUE, pValue);
}
}
else // get parameters for flashbang
if(!stricmp(pEffectName, "FlashBang"))
{
if(!stricmp(pEffectParam, "FlashBangTimeScale")) // flashbang timeout
{
m_pREScreenProcess->mfSetParameter(SCREENPROCESS_FLASHBANG, SCREENPROCESS_FLASHBANGTIMESCALE, pValue);
}
else
if(!stricmp(pEffectParam, "FlashBangFlashPosX")) // flashbangflash position x
{
m_pREScreenProcess->mfSetParameter(SCREENPROCESS_FLASHBANG, SCREENPROCESS_FLASHBANGFLASHPOSX, pValue);
}
else
if(!stricmp(pEffectParam, "FlashBangFlashPosY")) // flashbangflash position y
{
m_pREScreenProcess->mfSetParameter(SCREENPROCESS_FLASHBANG, SCREENPROCESS_FLASHBANGFLASHPOSY, pValue);
}
else
if(!stricmp(pEffectParam, "FlashBangFlashSizeX")) // flashbangflash size x
{
m_pREScreenProcess->mfSetParameter(SCREENPROCESS_FLASHBANG, SCREENPROCESS_FLASHBANGFLASHSIZEX, pValue);
}
else
if(!stricmp(pEffectParam, "FlashBangFlashSizeY")) // flashbangflash size y
{
m_pREScreenProcess->mfSetParameter(SCREENPROCESS_FLASHBANG, SCREENPROCESS_FLASHBANGFLASHSIZEY, pValue);
}
else
if(!stricmp(pEffectParam, "FlashBangForce")) // force flashbang after image texture creation
{
m_pREScreenProcess->mfSetParameter(SCREENPROCESS_FLASHBANG, SCREENPROCESS_FLASHBANGFORCEAFTERIMAGE, pValue);
}
}
}
int C3DEngine::GetScreenFx(const char *pEffectName)
{
// to avoid an untreackable crash in mscvdll strcmp
if (!pEffectName)
{
return -1;
}
if(!strcmp(pEffectName, "NightVision"))
{
bool bVal=*((bool*)m_pREScreenProcess->mfGetParameter(SCREENPROCESS_NIGHTVISION, SCREENPROCESS_ACTIVE));
return bVal;
}
else
if(!strcmp(pEffectName, "HeatVision"))
{
bool bVal=*((bool*)m_pREScreenProcess->mfGetParameter(SCREENPROCESS_HEATVISION, SCREENPROCESS_ACTIVE));
return bVal;
}
else
if(!strcmp(pEffectName, "ScreenBlur"))
{
bool bVal=*((bool*)m_pREScreenProcess->mfGetParameter(SCREENPROCESS_BLUR, SCREENPROCESS_ACTIVE));
return bVal;
}
else
if(!strcmp(pEffectName, "FlashBang"))
{
bool bVal=*((bool*)m_pREScreenProcess->mfGetParameter(SCREENPROCESS_FLASHBANG, SCREENPROCESS_ACTIVE));
return (int)bVal;
}
else
if(!strcmp(pEffectName, "ScreenFade"))
{
bool bVal=*((bool*)m_pREScreenProcess->mfGetParameter(SCREENPROCESS_FADE, SCREENPROCESS_ACTIVE));
return bVal;
}
return -1;
}
int C3DEngine::GetScreenFxParam(const char *pEffectName, const char *pEffectParam, void *&pValue)
{
// to avoid an untreackable crash in mscvdll strcmp
if (!pEffectName || !pEffectParam)
{
return 0;
}
// get parameters for screen fade
if(!stricmp(pEffectName, "ScreenFade"))
{
if(!stricmp(pEffectParam, "ScreenFadeTime")) // set screen fade flag
{
pValue=m_pREScreenProcess->mfGetParameter(SCREENPROCESS_FADE, SCREENPROCESS_TRANSITIONTIME);
}
else
if(!stricmp(pEffectParam, "ScreenPreFadeTime")) // set screen pre fade flag (count number of frames, before start fading)
{
pValue=m_pREScreenProcess->mfGetParameter(SCREENPROCESS_FADE, SCREENPROCESS_PRETRANSITIONTIME);
}
else
{
// parameter doens't exist
return -1;
}
}
else
if(!stricmp(pEffectName, "ScreenBlur")) // get parameters for screen blur
{
if(!stricmp(pEffectParam, "ScreenBlurAmount")) // screen blur amount
{
pValue=m_pREScreenProcess->mfGetParameter(SCREENPROCESS_BLUR, SCREENPROCESS_BLURAMOUNT);
}
else
if(!stricmp(pEffectParam, "ScreenBlurColorRed")) // screen blur color red..
{
pValue=m_pREScreenProcess->mfGetParameter(SCREENPROCESS_BLUR, SCREENPROCESS_BLURCOLORRED);
}
else
if(!stricmp(pEffectParam, "ScreenBlurColorGreen")) // screen blur color green..
{
pValue=m_pREScreenProcess->mfGetParameter(SCREENPROCESS_BLUR, SCREENPROCESS_BLURCOLORGREEN);
}
else
if(!stricmp(pEffectParam, "ScreenBlurColorBlue")) // screen blur color blue..
{
pValue=m_pREScreenProcess->mfGetParameter(SCREENPROCESS_BLUR, SCREENPROCESS_BLURCOLORBLUE);
}
else
{
// parameter doens't exist
return -1;
}
}
else
if(!stricmp(pEffectName, "FlashBang")) // get parameters for flashbang
{
if(!stricmp(pEffectParam, "FlashBangTimeScale")) // flashbang timeout
{
pValue=m_pREScreenProcess->mfGetParameter(SCREENPROCESS_FLASHBANG, SCREENPROCESS_FLASHBANGTIMESCALE);
}
else
if(!stricmp(pEffectParam, "FlashBangFlashPosX")) // flashbangflash position x
{
pValue=m_pREScreenProcess->mfGetParameter(SCREENPROCESS_FLASHBANG, SCREENPROCESS_FLASHBANGFLASHPOSX);
}
else
if(!stricmp(pEffectParam, "FlashBangFlashPosY")) // flashbangflash position y
{
pValue=m_pREScreenProcess->mfGetParameter(SCREENPROCESS_FLASHBANG, SCREENPROCESS_FLASHBANGFLASHPOSY);
}
else
if(!stricmp(pEffectParam, "FlashBangFlashSizeX")) // flashbangflash size x
{
pValue=m_pREScreenProcess->mfGetParameter(SCREENPROCESS_FLASHBANG, SCREENPROCESS_FLASHBANGFLASHSIZEX);
}
else
if(!stricmp(pEffectParam, "FlashBangFlashSizeY")) // flashbangflash size y
{
pValue=m_pREScreenProcess->mfGetParameter(SCREENPROCESS_FLASHBANG, SCREENPROCESS_FLASHBANGFLASHSIZEY);
}
else
if(!stricmp(pEffectParam, "FlashBangTimeOut")) // get current time out time
{
pValue=m_pREScreenProcess->mfGetParameter(SCREENPROCESS_FLASHBANG, SCREENPROCESS_FLASHBANGTIMEOUT);
}
else
if(!stricmp(pEffectParam, "FlashBangForce")) // force flashbang after image texture creation
{
pValue=m_pREScreenProcess->mfGetParameter(SCREENPROCESS_FLASHBANG, SCREENPROCESS_FLASHBANGFORCEAFTERIMAGE);
}
else
{
// parameter doens't exist
return -1;
}
}
else
{
// parameter doens't exist
return -1;
}
return 1;
}
// reset current screen effects
void C3DEngine::ResetScreenFx(void)
{
if(m_pREScreenProcess)
{
m_pREScreenProcess->mfReset();
}
}
// process all screen space special fx's
void C3DEngine::ProcessScreenEffects()
{
// don't allow this in recursive rendering..
if(m_pObjManager->m_nRenderStackLevel!=0 || !m_pREScreenProcess)
{
return;
}
FUNCTION_PROFILER( GetSystem(), PROFILE_RENDERER );
// get console vars
static ICVar *pDisableSfx=GET_CVAR("r_DisableSfx");
static ICVar *pResetSfx=GET_CVAR("r_ResetScreenFx");
// reset screen effects state
if(pResetSfx->GetIVal()!=0)
{
m_pREScreenProcess->mfReset();
}
// disable fx's
if(!pDisableSfx->GetIVal())
{
static ICVar *pNormalGlare=GET_CVAR("r_Glare");
static ICVar *pMotionBlur=GET_CVAR("r_MotionBlur");
static ICVar *pScreenColorTransfer=GET_CVAR("r_ScreenColorTransfer");
static ICVar *pMotionBlurAmount=GET_CVAR("r_MotionBlurAmount");
static ICVar *pMotionBlurDisplace=GET_CVAR("r_MotionBlurDisplace");
static ICVar *pRenderMode=GET_CVAR("r_RenderMode");
// get console vars values
int iUseMotionBlur=pMotionBlur->GetIVal();
int iRenderMode=pRenderMode->GetIVal();
int iUseGlare=((pNormalGlare->GetIVal()) && (iRenderMode>0));
// activate fx's
m_pREScreenProcess->mfSetParameter(SCREENPROCESS_MOTIONBLUR, SCREENPROCESS_ACTIVE, &iUseMotionBlur);
m_pREScreenProcess->mfSetParameter(SCREENPROCESS_GLARE, SCREENPROCESS_ACTIVE, &iUseGlare);
// cartoon render mode active ?
bool bCartoon=0;
if(iRenderMode==4)
{
bCartoon=1;
}
m_pREScreenProcess->mfSetParameter(SCREENPROCESS_CARTOON, SCREENPROCESS_ACTIVE, &bCartoon);
// get screen texture if necessary
if(GET_ACTIVEPARAMETER(SCREENPROCESS_FLASHBANG) || GET_ACTIVEPARAMETER(SCREENPROCESS_COLORTRANSFER) ||
GET_ACTIVEPARAMETER(SCREENPROCESS_BLUR) || GET_ACTIVEPARAMETER(SCREENPROCESS_NIGHTVISION) ||
GET_ACTIVEPARAMETER(SCREENPROCESS_HEATVISION) || GET_ACTIVEPARAMETER(SCREENPROCESS_GLARE) ||
GET_ACTIVEPARAMETER(SCREENPROCESS_CARTOON) ||GET_ACTIVEPARAMETER(SCREENPROCESS_MOTIONBLUR))
{
CCObject *pScreenObj=GetRenderer()->EF_GetObject(true, -1);
pScreenObj->m_Matrix.SetIdentity();
GetRenderer()->EF_AddEf(0, m_pREDummy, m_pSHScreenTexMap, NULL, pScreenObj, 0, NULL, eS_Glare);
}
// process screen glare/set glare parameters
if(GET_ACTIVEPARAMETER(SCREENPROCESS_GLARE))
{
IVisArea *pCurrLocation= GetVisAreaFromPos(GetViewCamera().GetPos());
static ICVar *pGlareQuality=GET_CVAR("r_GlareQuality");
if(pGlareQuality->GetIVal()!=4)
{
if(!pCurrLocation)
{
pNormalGlare->Set(2);
}
else
{
pNormalGlare->Set(3);
}
}
}
// activate motion blur
if(GET_ACTIVEPARAMETER(SCREENPROCESS_MOTIONBLUR))
{
// get console variables
float fMotionBlurAmount=pMotionBlurAmount->GetFVal();
int iMotionBlurDisplace=pMotionBlurDisplace->GetIVal();
// pass parameters and activate effect
m_pREScreenProcess->mfSetParameter(SCREENPROCESS_MOTIONBLUR, SCREENPROCESS_MOTIONBLURDISPLACE, &iMotionBlurDisplace);
m_pREScreenProcess->mfSetParameter(SCREENPROCESS_MOTIONBLUR, SCREENPROCESS_MOTIONBLURAMOUNT, &fMotionBlurAmount);
m_pREScreenProcess->mfSetParameter(SCREENPROCESS_MOTIONBLUR, SCREENPROCESS_MOTIONBLURTYPE, &iUseMotionBlur);
m_pREScreenProcess->mfActivate(SCREENPROCESS_MOTIONBLUR);
}
}
CCObject *pScreenProcessObj=GetRenderer()->EF_GetObject(true, -1);
pScreenProcessObj->m_Matrix.SetIdentity();
GetRenderer()->EF_AddEf(0, m_pREScreenProcess, m_pSHScreenProcess, NULL, pScreenProcessObj, 0, NULL, eS_Glare);
}

2637
Cry3DEngine/3dEngine.cpp Normal file

File diff suppressed because it is too large Load Diff

510
Cry3DEngine/3dEngine.h Normal file
View File

@@ -0,0 +1,510 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: 3dengine.h
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#ifndef C3DENGINE_H
#define C3DENGINE_H
#if _MSC_VER > 1000
# pragma once
#endif
class CTerrain;
class CObjManager;
class CRESky;
class CPartManager;
class CDecalManager;
class CBFManager;
class CryCharManager;
struct ICryCharInstance;
class CRainManager;
struct CVisAreaManager;
struct IMatInfo;
// this class is used for additional view port rendering (view from camera of another player)
struct SRenderCamera
{
CCamera m_Camera;
float m_fX;
float m_fY;
float m_fWidth;
float m_fHeight;
};
struct SNodeInfo;
struct DLightAmount{ CDLight * pDLight; float fAmount; };
class CMatMan : public Cry3DEngineBase
{
public:
CMatMan();
~CMatMan();
IMatInfo* CreateMatInfo( const char *sMtlName = NULL );
void DeleteMatInfo(IMatInfo * pMatInfo);
void RenameMatInfo( IMatInfo *pMtl,const char *sNewName );
IMatInfo* FindMatInfo( const char *sMtlName ) const;
void LoadMaterialsLibrary( const char *sMtlFile,XmlNodeRef &levelDataRoot );
private:
IMatInfo* LoadMaterial( XmlNodeRef mtlNode,const char *sLibraryName,IMatInfo* pParent );
bool LoadMaterialShader( IMatInfo *pMtl,const char *sShader,int mtlFlags,unsigned int nShaderGenMask,SInputShaderResources &sr,SLightMaterial &lm,XmlNodeRef &publicsNode );
void ParsePublicParams( TArray<SShaderParam> &params,XmlNodeRef paramsNode );
typedef std::set<_smart_ptr<IMatInfo> > MtlSet;
typedef std::map<string,IMatInfo*,stl::less_stricmp<string> > MtlNameMap;
MtlSet m_mtlSet;
MtlNameMap m_mtlNameMap;
};
struct CLightEntity : public IEntityRender, public Cry3DEngineBase
{
virtual const char * GetEntityClassName(void) const { return "LightEntityClass"; }
virtual float GetScale(void) const { return 1.f; }
virtual const char *GetName(void) const { return "LightEntityName"; }
virtual const Vec3d &GetPos(bool) const;
virtual const Vec3d &GetAngles(int) const;
virtual void GetRenderBBox(Vec3d &,Vec3d &);
virtual float GetRenderRadius(void) const;
virtual bool DrawEntity(const SRendParams &) { return true; };
virtual bool IsStatic(void) const { return false; };
virtual bool IsEntityHasSomethingToRender(void) { return false; }
virtual bool IsEntityAreasVisible(void) { return true; }
virtual IPhysicalEntity *GetPhysics(void) const { return 0; }
virtual void SetPhysics(IPhysicalEntity *) { }
virtual void SetMaterial(IMatInfo *) { }
virtual IMatInfo *GetMaterial(void) const { return 0; }
virtual class CDLight * GetLight() { return m_pLight; }
virtual float GetMaxViewDist();
virtual void PreloadInstanceResources(Vec3d vPrevPortalPos, float fPrevPortalDistance, float fTime){}
CLightEntity();
~CLightEntity();
CDLight * m_pLight;
Vec3d m_vPos;
};
struct SLevelInfo
{
float
m_fSkyBoxAngle,
m_fSkyBoxStretching,
m_fSunHeightScale,
m_fWaterTranspRatio,
m_fWaterReflectRatio,
m_fWaterBumpAmountX,
m_fWaterBumpAmountY,
m_fWaterBorderTranspRatio,
m_fUnderWaterFogDistance;
float
m_fFogNearDist,
m_fFogFarDist,
m_fMaxViewDist;
float
m_fDefFogNearDist,
m_fDefFogFarDist,
m_fDefMaxViewDist;
float m_fWorldColorRatio;
Vec3d m_vUnderWaterFogColor;
Vec3d m_vFogColor;
Vec3d m_vDefFogColor;
Vec3d m_vSunPosition;
Vec3d m_vWorldColorConst;
Vec3d m_vWindForce;
IShader *m_pSHFullScreenQuad;
int m_nWaterBottomTexId;
int m_nShadowSpotTexId;
bool m_bOceanCaustics;
};
struct SLevelShaders
{
IShader
* m_pTerrainWaterShader,
* m_pSunRoadShader,
* m_pSHTerrainParticles;
};
struct SRenderElements
{
CRESky * m_pRESky;
//CREOutSpace * m_pREOutSpace;
CREShadowMapGen * m_pREShadowMapGenerator;
CREDummy * m_pREDummy;
CRETerrainParticles * m_pRETerrainParticles;
CRE2DQuad * m_pRE2DQuad;
CLeafBuffer * m_pFogTopPlane;
// tiago: added
CREScreenProcess * m_pREScreenProcess;
IShader * m_pSHDefault;
IShader * m_pSHScreenTexMap;
IShader * m_pSHScreenProcess;
IShader * m_pSHOutSpace;
IShader * m_pSHFarTreeSprites;
IShader * m_pSHClearStencil;
IShader * m_pSHShadowMapGen;
IShader * m_pSHBinocularDistortMask;
IShader * m_pSHScreenDistort;
IShader * m_pSHSniperDistortMask;
IShader * m_pSHRainMap;
IShader * m_pSHStencil;
IShader * m_pSHStencilState;
IShader * m_pSHStencilStateInv;
IShader * m_pSHSky;
IShader * m_pSHLensFlares;
};
//////////////////////////////////////////////////////////////////////
class C3DEngine : public I3DEngine,
public SLevelInfo,
public SLevelShaders,
public SRenderElements,
public Cry3DEngineBase
{
// IProcess Implementation
void SetFlags(int flags) { m_nFlags=flags; }
int GetFlags(void) { return m_nFlags; }
int m_nFlags;
public:
// I3DEngine interface implementation
virtual void Enable(bool bEnable) { m_bEnabled = bEnable; };
virtual bool Init();
virtual void Update();
virtual void Draw();
virtual void ShutDown(bool bEditorMode=false);
virtual void Release() { delete this; };
virtual void SetLevelPath( const char * szFolderName );
virtual bool LoadLevel(const char * szFolderName, const char * szMissionName, bool bEditorMode);
virtual void SetCamera(const CCamera &cam, bool bToTheScreen); // The game set this camera
virtual void DisplayInfo(float & fTextPosX, float & fTextPosY, float & fTextStepY);
virtual void SetupDistanceFog();
virtual IStatObj * MakeObject(const char * szFileName, const char * szGeomName = 0,
EVertsSharing eVertsSharing = evs_ShareAndSortForCache,
bool bLoadAdditinalInfo = true,
bool bKeepInLocalSpace = false);
virtual IStatObj* MakeObject();
virtual bool ReleaseObject(IStatObj * pObject);
virtual void RegisterEntity( IEntityRender * pEntityRS );
virtual bool UnRegisterEntity( IEntityRender * pEntityRS );
virtual float GetWaterLevel(const Vec3d * pvPos = NULL, Vec3d * pvFlowDir = NULL);
virtual float GetWaterLevel(IEntityRender * pEntityRender, Vec3d * pvFlowDir = NULL);
virtual void SpawnParticles(const ParticleParams & SpawnParticleParams);
virtual void CreateDecal( const CryEngineDecalInfo& Decal );
virtual void DrawTerrainDetailTextureLayers();
virtual void DrawFarTrees();
virtual void DrawTerrainParticles(IShader * pShader);
virtual void SetRenderCallback(void (*pFunc)(void *pParams), void *pParams) { m_pRenderCallbackFunc = pFunc; m_pRenderCallbackParams = pParams; }
virtual void DrawLowDetail(const int & DrawFlags);
virtual float GetTerrainElevation(float x, float y);
virtual float GetTerrainZ(int x, int y);
virtual int GetHeightMapUnitSize();
virtual int GetTerrainSize();
virtual float GetMaxViewDist();
virtual void ActivateLight(const char *szName,bool bActivate);
virtual bool IsCharacterFile(const char * szCGFileName);
virtual bool IsPointInWater(Vec3d vPos); // todo: remove it
virtual Vec3d GetSunPosition(bool bMoveUp = true);
virtual ICryCharInstance * MakeCharacter(const char * cid_file_name, unsigned int dwFlags = 0);
virtual void RemoveCharacter(ICryCharInstance * pCryCharInstance);
virtual Vec3d GetWorldColor( bool bScaled=true );
virtual void SetWorldColor(Vec3d vColor);
virtual void SetOutdoorAmbientColor(Vec3d vColor);
virtual void SetWorldColorRatio(float fWorldColorRatio);
virtual float GetWorldColorRatio();
virtual void SetSkyBox(const char * szSkyBoxShaderName);
virtual void OnExplosion(Vec3d vPos, Vec3 vHitDir, float fRadius, int nTexID, bool bDeformTerrain);
virtual void SetScreenShader(const char * szShaderName);
//! For editor
virtual bool AddStaticObject(int nObjectID, const Vec3d & vPos, const float fScale, uchar ucBright);
virtual bool RemoveStaticObject(int nObjectID, const Vec3d & vPos);
virtual bool PhysicalizeStaticObject(void *pForeignData,int iForeignData,int iForeignFlags);
virtual void RemoveAllStaticObjects();
virtual void SetTerrainSurfaceType(int x, int y, int nType);
virtual int GetTerrainSurfaceType(int x, int y);
virtual void SetTerainHightMapBlock(int x1, int y1, int nSizeX, int nSizeY, ushort * TerrainBlock, ushort nUpdateMask);
virtual int LockTerrainSectorTexture(int nSectorOriginX, int nSectorOriginY, int & nTexDim);
virtual void SetPhysMaterialEnumerator(IPhysMaterialEnumerator * pPhysMaterialEnumerator);
virtual IPhysMaterialEnumerator * GetPhysMaterialEnumerator();
virtual void LoadEnvironmentSettingsFromXML(const char * szMissionName, bool bEditorMode, const char * szMissionXMLString, bool bUpdateLightingOnVegetations);
virtual void AddDynamicLightSource(const class CDLight & LSource, IEntityRender * pEnt, int nEntityLightId=-1, const Matrix44 * pMatrix=NULL);
virtual void ApplyForceToEnvironment(Vec3d vPos, float fRadius, float fAmountOfForce);
virtual bool UnRegisterInAllSectors(IEntityRender * pEntityRS);
virtual bool MakeSectorLightMap(int nSectorOriginX, int nSectorOriginY, unsigned char * pImage, int nImageSize);
virtual void SetMaxViewDistance(float fMaxViewDistance);
virtual float GetMaxViewDistance( );
virtual void SetFogColor(const Vec3d& vFogColor);
virtual void SetFogStart(const float fFogStart);
virtual void SetFogEnd(const float fFogEnd);
virtual Vec3d GetFogColor( );
virtual float GetFogStart( );
virtual float GetFogEnd( );
virtual float GetDistanceToSectorWithWater();
virtual void SetSkyBoxAlpha(float fAlpha);
virtual void SetBFCount(int nCount);
virtual int GetBFCount();
virtual void SetGrasshopperCount(int nCount);
virtual int GetGrasshopperCount();
virtual Vec3d GetOutdoorAmbientColor();
virtual Vec3d GetSunColor();
virtual uint GetLightMaskFromPosition(const Vec3d & vPos, float fRadius);
virtual Vec3d GetAmbientColorFromPosition(const Vec3d & vPos, float fRadius);
virtual void ClearRenderResources(bool bEditor);
virtual void FreeEntityRenderState(IEntityRender * pEntityRS);
virtual IEntityRenderState * MakeEntityRenderState();
virtual void SetGrasshopperCGF( int nSlot, IStatObj * pStatObj );
virtual IParticleEmitter* CreateParticleEmitter();
virtual void DeleteParticleEmitter(IParticleEmitter* pPartEmitter);
virtual const char * GetLevelFilePath(const char * szFileName);
virtual void MakeUnderWaterSmoothHMap(int nWaterUnitSize);
virtual ushort * GetUnderWaterSmoothHMap(int & nDimensions);
virtual void SetTerrainBurnedOut(int x, int y, bool bBurnedOut);
virtual bool IsTerrainBurnedOut(int x, int y);
virtual void UpdateDetailObjects();
virtual int GetTerrainSectorSize();
virtual void AddWaterSplash (Vec3d vPos, eSplashType eST, float fForce, int Id);
virtual class IEdgeConnectivityBuilder *GetNewConnectivityBuilder( void );
//! creates a connectivity object that can be used to deserialize the connectivity data
virtual class IStencilShadowConnectivity *NewConnectivity();
virtual class IEdgeConnectivityBuilder *GetNewStaticConnectivityBuilder( void );
virtual class IEdgeDetector *GetEdgeDetector( void );
virtual void LoadTerrainSurfacesFromXML(void * pDoc);
virtual void EnableHeatVision(bool bEnable);
virtual int GetTerrainTextureDim();
virtual bool SetStatInstGroup(int nGroupId, const IStatInstGroup & siGroup);
virtual bool GetStatInstGroup(int nGroupId, IStatInstGroup & siGroup);
virtual void ActivatePortal(const Vec3d &vPos, bool bActivate, IEntityRender *pEntity);
virtual void GetMemoryUsage(class ICrySizer * pSizer);
virtual IWaterVolume * CreateWaterVolume();
virtual void DeleteWaterVolume(IWaterVolume * pWaterVolume);
virtual IWaterVolume * FindWaterVolumeByName(const char * szName);
virtual IVisArea * CreateVisArea();
virtual void DeleteVisArea(IVisArea * pVisArea);
virtual void UpdateVisArea(IVisArea * pArea, const Vec3d * pPoints, int nCount, const char * szName, float fHeight, const Vec3d & vAmbientColor, bool bAfectedByOutLights, bool bSkyOnly, const Vec3 & vDynAmbientColor, float fViewDistRatio, bool bDoubleSide, bool bUseDeepness, bool bUseInIndoors);
virtual int GetFogVolumeIdFromBBox(const Vec3d & vBoxMin, const Vec3d & vBoxMax); // todo: remove
virtual void ResetParticlesAndDecals( );
virtual IEntityRender * CreateEntityRender();
virtual IEntityRender * CreateVegetation();
virtual void DeleteEntityRender(IEntityRender * pEntityRender);
virtual void DrawRain();
virtual void SetRainAmount( float fAmount );
virtual void SetWindForce( const Vec3d & vWindForce );
virtual float GetLightAmountForEntity(IEntityRender * pEntity, bool bOnlyVisibleLights);
virtual float GetAmbientLightAmountForEntity(IEntityRender * pEntity);
virtual IVisArea * GetVisAreaFromPos(const Vec3d &vPos);
virtual bool IsVisAreasConnected(IVisArea * pArea1, IVisArea * pArea2, int nMaxReqursion, bool bSkipDisabledPortals);
virtual ILMSerializationManager * CreateLMSerializationManager();
void EnableOceanRendering(bool bOcean, bool bShore); // todo: remove
//////////////////////////////////////////////////////////////////////////
// Materials access.
virtual IMatInfo* CreateMatInfo();
virtual void DeleteMatInfo(IMatInfo * pMatInfo);
virtual void RenameMatInfo( IMatInfo *pMtl,const char *sNewName );
virtual IMatInfo* FindMaterial( const char *sMaterialName );
//////////////////////////////////////////////////////////////////////////
// ParticleEffect
virtual IParticleEffect* CreateParticleEffect();
virtual void DeleteParticleEffect( IParticleEffect* pEffect );
virtual IParticleEffect* FindParticleEffect( const char *sEffectName );
//////////////////////////////////////////////////////////////////////////
virtual INT_PTR AddStaticLightSource(const class CDLight & LSource, IEntityRender * pCreator, ICryCharInstance * pCryCharInstance, const char * szBoneName); //AMD Port
virtual bool DeleteStaticLightSource(INT_PTR nLightId); //AMD Port
virtual const list2<CDLight*> * GetStaticLightSources();
virtual bool IsTerainHightMapModifiedByGame();
virtual bool IsPotentiallyVisible(IEntityRender * pEntityRender, float fAdditionRadius=0 );
virtual void UpdateBeaches();
virtual void RestoreTerrainFromDisk();
virtual void CheckMemoryHeap();
virtual void RecompileBeaches();
virtual float GetObjectsLODRatio();
virtual float GetObjectsViewDistRatio();
virtual bool SetMaterialFloat( char * szMatName, int nSubMatId, int nTexSlot, char * szParamName, float fValue );
virtual void CloseTerrainTextureFile();
virtual int GetLoadedObjectCount();
virtual void DeleteEntityDecals(IEntityRender * pEntity);
virtual void DeleteDecalsInRange( Vec3d vBoxMin, Vec3d vBoxMax, bool bDeleteBigTerrainDecals = true);
virtual const void * GetShoreGeometry(int & nPosStride, int & nVertCount, int nSectorX, int nSectorY);
virtual void OnLevelLoaded();
virtual void LockCGFResources();
virtual void UnlockCGFResources();
virtual float GetObjectsMinViewDist();
// tiago: added
virtual void SetBlurMask(ITexPic *pMask);
virtual void SetScreenMask(ITexPic *pMask);
virtual void SetScreenFx(const char *pEffectName, int iActive);
virtual void SetScreenFxParam(const char *pEffectName, const char *pEffectParam, void *pValue);
virtual int GetScreenFx(const char *pEffectName);
virtual int GetScreenFxParam(const char *pEffectName, const char *pEffectParam, void *&pValue);
virtual void ResetScreenFx(void);
bool SaveCGF(std::vector<IStatObj *>& pObjs);
int GetCurrentSpec()
{
if (m_pSysSpec)
return m_pSysSpec->GetIVal();
return 3; // very high spec.
}
int GetCurrentLightSpec()
{
if (m_pLightQuality)
return m_pLightQuality->GetIVal();
return 3; // very high spec.
}
public:
C3DEngine( ISystem * pSystem );
~C3DEngine();
void RenderScene(unsigned int dwDrawFlags);
CDLight * CheckDistancesToLightSources(uint & nDLightMask, const Vec3d vObjPos, const float fObjRadius, IEntityRender * pEntityRender = 0, int nMaxLightBitsNum = 8, CDLight ** pSelectedLights = NULL, int nMaxSelectedLights = 0, Vec3d * pvSummLightAmmount = NULL);
uint GetFullLightMask();
bool IsOutdoorVisible();
void RenderSkyBox(IShader *pSH);
void RenderOutSpace();
// access to components
CTerrain * GetTerrain() { return m_pTerrain; }
CObjManager * GetObjManager() { return m_pObjManager; }
CVars * GetCVars() { return m_pCVars; }
CVisAreaManager * GetVisAreaManager() { return m_pVisAreaManager; }
CMatMan * GetMatMan() { return m_pMatMan; }
private:
// misc
CCObject *m_SunObject[8],
*m_pBlurObj,
*m_pScreenObj;
int m_nStreamingIconTexID, m_nBlackTexID;
char m_sGetLevelFilePathTmpBuff[MAX_PATH_LENGTH];
char m_szLevelFolder[_MAX_PATH];
list2<DLightAmount> m_lstDL_CDTLS;
static double m_dLoadLevelTime;
bool m_bOcean; // todo: remove
bool m_bShore; // todo: remove
int m_bTerrainLightMapGenError;
bool m_bEnabled;
// interfaces
IPhysMaterialEnumerator * m_pPhysMaterialEnumerator;
// this is the shared instance that will calculate the shadows
// created/freed during class initialization/deinitialization
class IEdgeDetector * m_pShadowEdgeDetector; //!< to get rid of the new/delete
class IEdgeConnectivityBuilder * m_pConnectivityBuilder; //!< to get rid of the new/delete
class IEdgeConnectivityBuilder * m_pStaticConnectivityBuilder;
// data containers
list2<CDLight> m_lstDynLights;
list2<CDLight> m_lstDynLightsNoLight;
int m_nRealLightsNum;
list2<CLightEntity*> m_lstStaticLights;
#define MAX_LIGHTS_NUM 32
CCamera m_arrCameraProjectors[MAX_LIGHTS_NUM];
// 3dengine components
CTerrain * m_pTerrain;
CObjManager * m_pObjManager;
CPartManager * m_pPartManager;
CDecalManager * m_pDecalManager;
// CBFManager * m_pBFManager;
CRainManager * m_pRainManager;
CVisAreaManager* m_pVisAreaManager;
CVars * m_pCVars;
CMatMan * m_pMatMan;
ICVar* m_pSysSpec;
ICVar* m_pLightQuality;
// not sorted
void (*m_pRenderCallbackFunc)(void *pParams);
void *m_pRenderCallbackParams;
//! Saving of cgf file
bool WriteMaterials(TArray<CHUNK_HEADER>& Chunks, TArray<IShader *>& Shaders, FILE *out, int &MatChunk);
bool WriteNodes(TArray<CHUNK_HEADER>& Chunks, TArray<NODE_CHUNK_DESC>& Nodes, FILE *out, TArray<SNodeInfo>& NI, int& MatChunk, int& ExpFrame, std::vector<IStatObj *>& pObjs);
bool WriteMesh(TArray<CHUNK_HEADER>& Chunks, TArray<NODE_CHUNK_DESC>& Nodes, TArray<IShader *>& Shaders, FILE *out, TArray<SNodeInfo>& NI, int& MatChunk, int& ExpFrame);
bool WriteNodeMesh(int nNode, MESH_CHUNK_DESC *chunk, FILE *out, TArray<IShader *>& Shaders, TArray<SNodeInfo>& NI, struct CStatObj *pObj);
bool WriteLights(TArray<CHUNK_HEADER>& Chunks, TArray<NODE_CHUNK_DESC>& Nodes, FILE *out, std::vector<IStatObj *>& pObjs);
void DrawFullScreenQuad(IShader *pShader, bool bRectangle, EF_Sort eSort = eS_Unknown);
void LoadMissionSettingsFromXML(struct XDOM::IXMLDOMNode *pInputNode, bool bEditorMode, bool bUpdateLightingOnVegetations);
char * GetXMLAttribText(XDOM::IXMLDOMNode * pInputNode, const char * szLevel0,const char * szLevel1,const char * szLevel2,const char * szDefaultValue);
void RegisterLightSourceInSectors(CDLight * pDynLight);
void LightSourcesDebug();
void RenderVolumeFogTopPlane();
Vec3d GetTerrainSurfaceNormal(Vec3d vPos) { return m_pTerrain ? m_pTerrain->GetTerrainSurfaceNormal(vPos) : Vec3d(0,0,0); }
void RenderTerrainParticles();
bool IsBoxVisibleOnTheScreen(const Vec3d & vBoxMin, const Vec3d & vBoxMax, OcclusionTestClient * pOcclusionTestClient );
bool IsSphereVisibleOnTheScreen(const Vec3d & vPos, const float fRadius, OcclusionTestClient * pOcclusionTestClient );
bool IsCameraAnd3DEngineInvalid(const CCamera cam, const char * szCaller);
void LoadFogVolumesFromXML(XDOM::IXMLDOMDocumentPtr pDoc);
void UpdateScene(bool bAddStaticLights = true, bool bAlwaysAddSun = false);
void MakeHiResScreenShot();
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
void SetupLightScissors(CDLight *pLight);
bool IsOutdoorsVisible();
void UpdateStaticLightSources();
void DeleteAllStaticLightSources();
bool LoadStaticLightSources(const char *pszFileName);
void LoadParticleEffects( XmlNodeRef &levelDataRoot,bool bEditorMode );
public:
void UpdateLightSources();
void PrepareLightSourcesForRendering();
void FreeLightSourceComponents(CDLight *pLight);
void RemoveEntityLightSources(IEntityRender * pEntity);
void CheckPhysicalized(const Vec3d & vBoxMin, const Vec3d & vBoxMax);
list2<CDLight> * GetDynamicLightSources() { return &m_lstDynLights; }
void ProcessScreenEffects();
int GetRealLightsNum() { return m_nRealLightsNum; }
void CaptureFrameBufferToFile();
void DrawShadowSpotOnTerrain(Vec3d vPos, float fRadius);
void SetupClearColor();
void DrawText(float x, float y, const char * format, ...);
};
#endif // C3DENGINE_H

View File

@@ -0,0 +1,792 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: 3dengineload.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: Level loading
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "3dEngine.h"
#include "objman.h"
#include "visareas.h"
#include "terrain_water.h"
#include "CryStaticModel.h"
#include "partman.h"
#include "DecalManager.h"
#include "bflyes.h"
#include "detail_grass.h"
#include "rain.h"
#include <IXMLDOM.h>
#include "watervolumes.h"
#include "brush.h"
#include "LMCompStructures.h"
#define LEVEL_DATA_FILE "LevelData.xml"
#define CUSTOM_MATERIALS_FILE "Materials.xml"
#define PARTICLES_FILE "particles.lst"
#define EFFECTS_FOLDER "Effects"
#define SHARED_PARTICLES_EXPLOSIONS "Explosions"
#define SHARED_PARTICLES_WATER "Water"
#define SHARED_PARTICLES_SMOKE "Smoke"
#define SHARED_PARTICLES_BLOOD "Blood"
#define SHARED_PARTICLES_BULLET "Bullet"
#define SHARED_PARTICLES_MISC "Misc"
#define SHARED_PARTICLES_FIRE "Fire"
double C3DEngine::m_dLoadLevelTime = 0;
//////////////////////////////////////////////////////////////////////////
void C3DEngine::ClearRenderResources( bool bEditorMode )
{
// GetLog()->Log("\003*** Clearing render resources ***");
// GetSystem()->GetIAnimationSystem()-> ;
// ShutDown(false);
//if(GetRenderer())
// GetRenderer()->FreeResources(FRR_SHADERS | FRR_TEXTURES | FRR_RESTORE);
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
if(m_pVisAreaManager)
{
UpdateLoadingScreen("Deleting VisAreaManager ...");
delete m_pVisAreaManager;
UpdateLoadingScreenPlus(" Ok");
m_pVisAreaManager=0;
}
if (m_pObjManager)
{
SAFE_DELETE( m_pObjManager->m_pCWaterVolumes );
}
// delete terrain
if(m_pTerrain)
{
UpdateLoadingScreen("Deleting terrain ...");
SAFE_DELETE( m_pTerrain );
UpdateLoadingScreenPlus(" Ok");
}
// free vegetations
if(!bEditorMode)
{
if (m_pObjManager)
m_pObjManager->UnloadVegetations();
}
if (m_pPartManager)
{
m_pPartManager->Reset();
if (!bEditorMode)
{
SAFE_DELETE( m_pPartManager );
}
}
SAFE_DELETE( m_pDecalManager );
// Load Materials Library from LevelData.xml
if (!bEditorMode)
{
SAFE_DELETE( m_pMatMan );
m_pMatMan = new CMatMan();
}
//////////////////////////////////////////////////////////////////////////
// Purge destroyed physics entities.
//////////////////////////////////////////////////////////////////////////
GetSystem()->GetIPhysicalWorld()->PurgeDeletedEntities();
// print warnings
if (m_pObjManager)
m_pObjManager->CheckObjectLeaks();
GetRenderer()->PreLoad();
}
//////////////////////////////////////////////////////////////////////////
void C3DEngine::SetLevelPath( const char * szFolderName )
{
// make folder path
assert(strlen(szFolderName) < 1024);
strcpy( m_szLevelFolder,szFolderName );
if (strlen(m_szLevelFolder) > 0)
{
if (m_szLevelFolder[strlen(m_szLevelFolder)-1] != '/')
strcat( m_szLevelFolder,"/" );
}
}
//////////////////////////////////////////////////////////////////////////
bool C3DEngine::LoadLevel(const char * szFolderName, const char * szMissionName, bool bEditorMode)
{
AUTO_PROFILE_SECTION(GetTimer(), m_dLoadLevelTime);
m_bIgnoreFakeMaterialsInCGF = !bEditorMode;
m_bEditorMode = bEditorMode;
GetRenderer()->MakeCurrent();
if(!szFolderName || !szFolderName[0])
{ Warning( 0,0,"C3DEngine::LoadLevel: Level name is not specified"); return 0; }
if(!szMissionName || !szMissionName[0])
{ Warning( 0,0,"C3DEngine::LoadLevel: Mission name is not specified"); }
char szMissionNameBody[256] = "NoMission";
if(!szMissionName)
szMissionName = szMissionNameBody;
SetLevelPath( szFolderName );
if(!bEditorMode)
{ // check is LevelData.xml file exist
char sMapFileName[_MAX_PATH];
strcpy(sMapFileName,m_szLevelFolder);
strcat(sMapFileName,LEVEL_DATA_FILE);
if(!CXFile::IsFileExist(sMapFileName))
{ UpdateLoadingScreen("Error: Level not found: %s", sMapFileName); return 0; }
}
if(!m_pObjManager)
m_pObjManager = new CObjManager (this);
if(!bEditorMode)
{
if(m_pVisAreaManager)
{
UpdateLoadingScreen("Deleting VisAreaManager ...");
delete m_pVisAreaManager;
UpdateLoadingScreenPlus(" Ok");
m_pVisAreaManager=0;
}
}
if(!m_pVisAreaManager)
m_pVisAreaManager = new CVisAreaManager( );
assert (GetSystem()->GetIAnimationSystem());
if(!bEditorMode)
{
int nCellSize = 4;
GetPhysicalWorld()->SetupEntityGrid(2,vectorf(0,0,0), // this call will destroy all physicalized stuff
CTerrain::GetTerrainSize()/nCellSize,CTerrain::GetTerrainSize()/nCellSize,(float)nCellSize,(float)nCellSize);
}
// cache prev terrain objects
list2<struct IEntityRender*> lstTerrainObjects;
if(bEditorMode && m_pTerrain)
m_pTerrain->GetObjects(&lstTerrainObjects);
// delete terrain
if(m_pTerrain)
{
UpdateLoadingScreen("Deleting terrain ...");
delete m_pTerrain; m_pTerrain=0;
UpdateLoadingScreenPlus(" Ok");
}
// free vegetations
if(!bEditorMode)
m_pObjManager->UnloadVegetations();
// print level name into console
char header[512];
snprintf(header, sizeof(header),
"\001---------------------- Loading level %s, mission %s ------------------------------------",
szFolderName, szMissionName);
header[100]=0;
UpdateLoadingScreen(header);
// print warnings
m_pObjManager->CheckObjectLeaks();
// create terrain
m_pTerrain = new CTerrain( );
m_pObjManager->m_pTerrain = m_pTerrain;
if(m_pTerrain && !m_pTerrain->LoadTerrain(bEditorMode))
{ // terrain not found
delete m_pTerrain;
m_pTerrain = 0;
}
// restore prev terrain objects
for(int i=0; i<lstTerrainObjects.Count(); i++)
{
lstTerrainObjects[i]->m_pSector = 0;
Get3DEngine()->RegisterEntity(lstTerrainObjects[i]);
}
lstTerrainObjects.Reset();
//
m_pObjManager->m_lstVegetContainer.Reset();
m_pObjManager->m_lstBrushContainer.Reset();
//////////////////////////////////////////////////////////////////////////
// Load LevelData.xml File.
XmlNodeRef levelDataRoot = GetSystem()->LoadXmlFile( GetLevelFilePath(LEVEL_DATA_FILE) );
//////////////////////////////////////////////////////////////////////////
// Load Materials Library from LevelData.xml
if (!bEditorMode)
{
delete m_pMatMan;
m_pMatMan = new CMatMan();
m_pMatMan->LoadMaterialsLibrary( GetLevelFilePath(CUSTOM_MATERIALS_FILE),levelDataRoot );
}
{ // recreate particles and decals
if(m_pPartManager)
m_pPartManager->Reset();
else
m_pPartManager = new CPartManager();
delete m_pDecalManager;
m_pDecalManager = new CDecalManager (this);
}
LoadParticleEffects( levelDataRoot,bEditorMode );
// load leveldata.xml
m_pTerrainWaterShader=m_pSunRoadShader=0;
m_nWaterBottomTexId=0;
LoadEnvironmentSettingsFromXML(szMissionName, bEditorMode, 0, true);
// init water if not initialized already (if no mission was found)
if(m_pTerrain && !m_pTerrain->m_pWater)
m_pTerrain->InitTerrainWater(bEditorMode,
m_pTerrainWaterShader, m_nWaterBottomTexId, m_pSunRoadShader,
m_fWaterTranspRatio, m_fWaterReflectRatio,
m_fWaterBumpAmountX, m_fWaterBumpAmountY, m_fWaterBorderTranspRatio);
m_pObjManager->m_pTerrain = m_pTerrain;
/* if (!m_pTerrain)
{
// [marco] Vlad check why it crashes here
CryError("3dengine:Cannot Load terrain - report this to Vladimir Kajalin");
}*/
if(m_pTerrain)
m_pTerrain->SetObjManager(m_pObjManager);
m_pVisAreaManager->SetupFogVolumes(m_pTerrain);
if(m_pObjManager->m_pCWaterVolumes)
m_pObjManager->m_pCWaterVolumes->InitWaterVolumes();
if(!bEditorMode)
{
// load static object bodies
m_pObjManager->LoadVegetationModels(szMissionName,bEditorMode);
// load lsources used for lightmaps
#if !defined(LINUX64)//fails due to different size of CDLight (pointers have 8 bytes)
LoadStaticLightSources(GetLevelFilePath("StatLights.dat"));
#endif
// bushes bodies and instances
m_pObjManager->LoadBrushes();
// merge brushes grouped in the editor
m_pObjManager->MergeBrushes();
// load positions of static objects, update sectors bboxes
m_pTerrain->LoadStatObjInstances();
}
// recreate bugs
/* if(m_pTerrain)
{
delete m_pTerrain->m_pBugsManager;
m_pTerrain->m_pBugsManager = new CBugsManager( );
}*/
// physicalise instances of static objects and buildings
// m_pObjManager->CreatePhysicalEntitys();
for(int i=0; i<m_pObjManager->m_lstBrushContainer.Count(); i++)
{
if (!(m_pObjManager->m_lstBrushContainer[i]->m_dwRndFlags & ERF_MERGED))
{
Get3DEngine()->UnRegisterEntity(m_pObjManager->m_lstBrushContainer[i]);
Get3DEngine()->RegisterEntity(m_pObjManager->m_lstBrushContainer[i]);
}
}
for(int i=0; i<m_pObjManager->m_lstVegetContainer.Count(); i++)
{
Get3DEngine()->UnRegisterEntity(m_pObjManager->m_lstVegetContainer[i]);
Get3DEngine()->RegisterEntity(m_pObjManager->m_lstVegetContainer[i]);
}
if(!bEditorMode)
{
m_pTerrain->SortStaticInstancesBySize();
m_pVisAreaManager->SortStaticInstancesBySize();
}
if(GetCVars()->e_stream_areas)
{ // all data can be streamed from disk now
for(int i=0; i<m_pObjManager->m_lstBrushContainer.Count(); i++)
delete m_pObjManager->m_lstBrushContainer[i];
m_pObjManager->m_lstBrushContainer.Reset();
for(int i=0; i<m_pObjManager->m_lstVegetContainer.Count(); i++)
delete m_pObjManager->m_lstVegetContainer[i];
m_pObjManager->m_lstVegetContainer.Reset();
}
else
{
// from now objects will be stored in the sectors
m_pObjManager->m_lstVegetContainer.Reset();
m_pObjManager->m_lstBrushContainer.Reset();
}
// restore game state
SetRainAmount(0);
EnableOceanRendering(true,true);
SetSkyBoxAlpha(1.f);
m_pObjManager->m_bLockCGFResources = false;
return (true);
}
void C3DEngine::LoadTerrainSurfacesFromXML(void * _pDoc)
{
UpdateLoadingScreen("Loading terrain detail textures ...");
XDOM::IXMLDOMNodeListPtr pDetTexTagList;
XDOM::IXMLDOMNodePtr pDetTexTag;
XDOM::IXMLDOMDocumentPtr pDoc = _pDoc ? *((XDOM::IXMLDOMDocumentPtr*)_pDoc) : (XDOM::IXMLDOMDocumentPtr)0;
if(!_pDoc)
{ // load current LevelData if pDoc not specified
pDoc = GetSystem()->CreateXMLDocument();
if(!pDoc->load(Get3DEngine()->GetLevelFilePath(LEVEL_DATA_FILE)))
return;
}
pDetTexTagList = pDoc->getElementsByTagName("SurfaceTypes");
if (pDetTexTagList)
{
pDetTexTagList->reset();
pDetTexTag = pDetTexTagList->nextNode();
XDOM::IXMLDOMNodeListPtr pDetTexList;
pDetTexList = pDetTexTag->getElementsByTagName("SurfaceType");
if (pDetTexList)
{
pDetTexList->reset();
XDOM::IXMLDOMNodePtr pDetTex;
int nId = 0;
while (pDetTex = pDetTexList->nextNode())
{
XDOM::IXMLDOMNodePtr pDetailTextureName = pDetTex->getAttribute("DetailTexture");
XDOM::IXMLDOMNodePtr pScaleX = pDetTex->getAttribute("DetailScaleX");
XDOM::IXMLDOMNodePtr pScaleY = pDetTex->getAttribute("DetailScaleY");
XDOM::IXMLDOMNodePtr pProjAxis = pDetTex->getAttribute("ProjAxis");
XDOM::IXMLDOMNodePtr pSurfaceName = pDetTex->getAttribute("Name");
if(pDetailTextureName) if(pScaleX) if(pScaleY) if(pSurfaceName)
{
m_pTerrain->SetDetailTextures(nId, pDetailTextureName->getText(),
(float)atof(pScaleX->getText()), (float)atof(pScaleY->getText()),
pProjAxis ? (pProjAxis->getText())[0] : 0, pSurfaceName->getText());
}
nId++;
}
}
// recreate detail objects
delete m_pTerrain->m_pDetailObjects;
m_pTerrain->m_pDetailObjects = new CDetailGrass(pDetTexTagList);
}
m_pTerrain->InitDetailTextureLayers();
UpdateLoadingScreenPlus(" ok");
}
void C3DEngine::LoadFogVolumesFromXML(XDOM::IXMLDOMDocumentPtr pDoc)
{
if(!m_pTerrain)
return;
m_pTerrain->m_lstFogVolumes.Clear();
{ // make hardcoded volume for ocean
VolumeInfo volumeInfo;
volumeInfo.vBoxMax = Vec3d( 1000000, 1000000, m_pTerrain->GetWaterLevel());
volumeInfo.vBoxMin = Vec3d(-1000000, -1000000, -1000000);
// volumeInfo.pShader = 0;
volumeInfo.pShader = GetRenderer()->EF_LoadShader("FogLayer", eSH_World, EF_SYSTEM);
volumeInfo.vColor = m_vUnderWaterFogColor;
volumeInfo.fMaxViewDist = m_fUnderWaterFogDistance;
volumeInfo.bOcean = true;
volumeInfo.m_bCaustics = m_bOceanCaustics;
// add volume to list
m_pTerrain->m_lstFogVolumes.Add(volumeInfo);
}
XDOM::IXMLDOMNodeListPtr pNodeTagList;
XDOM::IXMLDOMNodePtr pNodeTag;
pNodeTagList = pDoc->getElementsByTagName("Objects");
if (pNodeTagList)
{
pNodeTagList->reset();
pNodeTag = pNodeTagList->nextNode();
XDOM::IXMLDOMNodeListPtr pNodeList;
pNodeList = pNodeTag->getElementsByTagName("Object");
if (pNodeList)
{
pNodeList->reset();
XDOM::IXMLDOMNodePtr pNode;
while (pNode = pNodeList->nextNode())
{
XDOM::IXMLDOMNodePtr pName = pNode->getAttribute("Type");
if (pName)
{
if (strstr(pName->getText(),"FogVolume"))
{
XDOM::IXMLDOMNodePtr pAttr;
VolumeInfo volumeInfo;
pAttr = pNode->getAttribute("Pos");
if(pAttr)
{
Vec3d vPos = StringToVector(pAttr->getText());
// get properties
// XDOM::IXMLDOMNodeListPtr pObjectsTagList = pNode->getElementsByTagName("Properties");
// if(pObjectsTagList)
{
XDOM::IXMLDOMNodePtr pAttr1,pAttr2,pAttr3,pAttr4,pAttr5;
pAttr1 = pNode->getAttribute("ViewDistance");
if(pAttr1)
volumeInfo.fMaxViewDist = (float)atof(pAttr1->getText());
pAttr1 = pNode->getAttribute("Width");
pAttr2 = pNode->getAttribute("Length");
pAttr3 = pNode->getAttribute("Height");
pAttr4 = pNode->getAttribute("Shader");
pAttr5 = pNode->getAttribute("Color");
if(pAttr1!=0 && pAttr2!=0 && pAttr3!=0 && pAttr4!=0 && pAttr5!=0)
{
Vec3d vSize((float)atof(pAttr1->getText()), (float)atof(pAttr2->getText()), (float)atof(pAttr3->getText()));
volumeInfo.vBoxMax = vPos + Vec3d(vSize.x*0.5f, vSize.y*0.5f, vSize.z);
volumeInfo.vBoxMin = vPos - Vec3d(vSize.x*0.5f, vSize.y*0.5f, 0);
volumeInfo.pShader = (char*)pAttr4->getText()[0] ? GetRenderer()->EF_LoadShader((char*)pAttr4->getText(), eSH_World, EF_SYSTEM) : GetRenderer()->EF_LoadShader("FogLayer", eSH_World, EF_SYSTEM);
volumeInfo.vColor = StringToVector(pAttr5->getText());
// add volume to list
m_pTerrain->m_lstFogVolumes.Add(volumeInfo);
}
}
}
}
}
}
}
}
}
void C3DEngine::LoadEnvironmentSettingsFromXML(const char * szMissionName, bool bEditorMode, const char * szMissionXMLString, bool bUpdateLightingOnVegetations)
{
if(!m_pTerrain)
{
Warning( 0,0,"Calling C3DEngine::LoadEnvironmentSettingsFromXML while level is not loaded");
return;
}
GetRenderer()->MakeCurrent();
// if xml string specified - load settings just from this string
if(szMissionXMLString)
{
XDOM::IXMLDOMDocumentPtr pMissionDoc;
pMissionDoc=GetSystem()->CreateXMLDocument();
// add empty <Mission> tag
char * szMissionXMLStringWithMissionTag = new char [strlen(szMissionXMLString)+256];
strcpy(szMissionXMLStringWithMissionTag, "<Mission>\n");
strcat(szMissionXMLStringWithMissionTag, szMissionXMLString);
strcat(szMissionXMLStringWithMissionTag, "</Mission>");
if (pMissionDoc->loadXML(szMissionXMLStringWithMissionTag))
{
LoadMissionSettingsFromXML(pMissionDoc, bEditorMode, bUpdateLightingOnVegetations);
// load fog volumes (mission shared data)
// LoadFogVolumesFromXML(pMissionDoc);
// m_pTerrain->InitFogVolumes();
}
delete [] szMissionXMLStringWithMissionTag;
return;
}
// load environment settings
XDOM::IXMLDOMDocumentPtr pDoc = GetSystem()->CreateXMLDocument();
// set default values
m_vFogColor(1,1,1);
m_fDefMaxViewDist = m_fMaxViewDist = 1024;
m_vDefFogColor = m_vFogColor;
m_fDefFogNearDist = m_fFogNearDist=50;
m_fDefFogFarDist = m_fFogFarDist = 1500;
//char buff[128];
// GetCurrentDirectory(128, buff);
if(pDoc->load(Get3DEngine()->GetLevelFilePath(LEVEL_DATA_FILE)))
{
// load detail textures (mission shared data)
LoadTerrainSurfacesFromXML(&pDoc);
// mission environment
if (szMissionName && szMissionName[0])
{
XDOM::IXMLDOMNodeListPtr pMissionTagList;
XDOM::IXMLDOMNodePtr pMissionTag;
pMissionTagList = pDoc->getElementsByTagName("Missions");
if (pMissionTagList)
{
pMissionTagList->reset();
pMissionTag = pMissionTagList->nextNode();
XDOM::IXMLDOMNodeListPtr pMissionList;
pMissionList = pMissionTag->getElementsByTagName("Mission");
if (pMissionList)
{
pMissionList->reset();
XDOM::IXMLDOMNodePtr pMission;
while (pMission = pMissionList->nextNode())
{
XDOM::IXMLDOMNodePtr pName = pMission->getAttribute("Name");
if (pName)
{
if (!stricmp(pName->getText(),szMissionName))
{ // get mission XML file name and open mission file
XDOM::IXMLDOMNodePtr pMissionFileName = pMission->getAttribute("File");
if (pMissionFileName)
{
XDOM::IXMLDOMDocumentPtr pMissionDoc;
pMissionDoc=GetSystem()->CreateXMLDocument();
if (pMissionDoc->load(Get3DEngine()->GetLevelFilePath(pMissionFileName->getText())))
{
LoadMissionSettingsFromXML(pMissionDoc, bEditorMode, bUpdateLightingOnVegetations);
// load fog volumes (mission shared data)
LoadFogVolumesFromXML(pMissionDoc);
m_pTerrain->InitFogVolumes();
if(!bEditorMode)
{
if(!m_pObjManager->m_pCWaterVolumes)
m_pObjManager->m_pCWaterVolumes = new CWaterVolumeManager( );
m_pObjManager->m_pCWaterVolumes->LoadWaterVolumesFromXML(pMissionDoc);
m_pVisAreaManager->LoadVisAreaShapeFromXML(pMissionDoc);
}
m_pVisAreaManager->LoadVisAreaBoxFromXML(pMissionDoc);
}
break;
}
}
}
}
}
}
}
else
Warning(0,0,"C3DEngine::LoadEnvironmentSettingsFromXML: Mission name is not defined");
}
}
char * C3DEngine::GetXMLAttribText(XDOM::IXMLDOMNode * pInputNode, const char * szLevel0,const char * szLevel1,const char * szLevel2,const char * szDefaultValue)
{
static char szResText[128];
strncpy(szResText,szDefaultValue,128);
XDOM::IXMLDOMNodeListPtr pObjectsTagList = pInputNode->getElementsByTagName(szLevel0);
if (!pObjectsTagList)
return szResText;
pObjectsTagList->reset();
XDOM::IXMLDOMNodePtr pObjectsTag = pObjectsTagList->nextNode();
XDOM::IXMLDOMNodeListPtr pNodes = pObjectsTag->getElementsByTagName(szLevel1);
if(pNodes)
{
XDOM::IXMLDOMNodePtr pNode;
pNodes->reset();
while(pNode = pNodes->nextNode())
{
XDOM::IXMLDOMNodePtr pAttr = pNode->getAttribute(szLevel2);
if(pAttr)
strncpy(szResText, pAttr->getText(), sizeof(szResText));
break;
}
}
return szResText;
}
void C3DEngine::LoadMissionSettingsFromXML(XDOM::IXMLDOMNode *pInputNode, bool bEditorMode, bool bUpdateLightingOnVegetations)
{
Vec3d vColor = StringToVector(GetXMLAttribText(pInputNode,"Environment","Fog","Color","255,255,255"));
m_vDefFogColor[0] = m_vFogColor[0] = vColor[0]/255.f;
m_vDefFogColor[1] = m_vFogColor[1] = vColor[1]/255.f;
m_vDefFogColor[2] = m_vFogColor[2] = vColor[2]/255.f;
GetRenderer()->SetClearColor(m_vFogColor);
// fog distance
m_fDefFogNearDist = m_fFogNearDist= (float)atol(GetXMLAttribText(pInputNode,"Environment","Fog","Start","64"));
m_fDefFogFarDist = m_fFogFarDist = (float)atol(GetXMLAttribText(pInputNode,"Environment","Fog","End","1500"));
// max view distance
m_fDefMaxViewDist = m_fMaxViewDist = (float)atol(GetXMLAttribText(pInputNode,"Environment","Fog","ViewDistance","1024"));
// Shaders
char szSkyBoxShaderName[128];
strncpy(szSkyBoxShaderName, GetXMLAttribText(pInputNode, "Environment", "Shaders", "SkyBox", "InfRedGal"), sizeof(szSkyBoxShaderName));
SAFE_RELEASE(m_pSHSky);
m_pSHSky = szSkyBoxShaderName[0] ? GetRenderer()->EF_LoadShader(szSkyBoxShaderName, eSH_World) : NULL;
// set terrain water, sun road and bottom shaders
char szTerrainWaterShaderName[256]="";
strncpy(szTerrainWaterShaderName, GetXMLAttribText(pInputNode,"Environment","Shaders","Water", "terrainwater"), sizeof(szTerrainWaterShaderName));
m_pTerrainWaterShader = szTerrainWaterShaderName[0] ? GetRenderer()->EF_LoadShader(szTerrainWaterShaderName, eSH_World, EF_SYSTEM) : 0;
char szSunRoadShaderName[256]="";
strncpy(szSunRoadShaderName, GetXMLAttribText(pInputNode,"Environment","Shaders","SunWaterRefl", "BumpSunGlow"), sizeof(szSunRoadShaderName));
m_pSunRoadShader = szSunRoadShaderName[0] ? GetRenderer()->EF_LoadShader(szSunRoadShaderName, eSH_World, EF_SYSTEM) : 0;
// load water bottom texture
char szWaterBottomTexName[256]="";
strncpy(szWaterBottomTexName, GetXMLAttribText(pInputNode,"Environment","Ocean","BottomTexture", "terrain/water/oceanfloorcolor.bmp"),sizeof(szWaterBottomTexName));
ITexPic * pPic = GetRenderer()->EF_LoadTexture(szWaterBottomTexName,FT_NOREMOVE,0,eTT_Base);
m_nWaterBottomTexId = pPic->GetTextureID();
// load default zoom texture
char szDefZoomTexName[256]="";
strncpy(szDefZoomTexName, GetXMLAttribText(pInputNode, "Environment", "HeightMap", "DefaultZoomTexture", ""),sizeof(szDefZoomTexName));
if(szDefZoomTexName[0])
{
pPic = GetRenderer()->EF_LoadTexture(szDefZoomTexName,FT_NOREMOVE,0,eTT_Base);
m_pTerrain->m_nDefZoomTexId = pPic->GetTextureID();
}
else
m_pTerrain->m_nDefZoomTexId = 0;
// Ocean
m_pTerrain->m_fShoreSize = (float)atof(GetXMLAttribText(pInputNode,"Environment","Ocean","ShoreSize", "2.0"));
m_fWaterTranspRatio = (float)atof(GetXMLAttribText(pInputNode,"Environment","Ocean","SurfaceTranspRatio", "1.0"));
m_fWaterReflectRatio = (float)atof(GetXMLAttribText(pInputNode,"Environment","Ocean","SurfaceReflectRatio","1.0"));
m_fWaterBumpAmountX = (float)atof(GetXMLAttribText(pInputNode,"Environment","Ocean","SurfaceBumpAmountX", "0.08"));
m_fWaterBumpAmountY = (float)atof(GetXMLAttribText(pInputNode,"Environment","Ocean","SurfaceBumpAmountY", "0.12"));
m_fWaterBorderTranspRatio = (float)atof(GetXMLAttribText(pInputNode,"Environment","Ocean","BorderTranspRatio", "0.5"));
m_vUnderWaterFogColor = StringToVector(GetXMLAttribText(pInputNode,"Environment","Ocean","FogColor","51,90,102"))/255;
m_fUnderWaterFogDistance = (float)atof(GetXMLAttribText(pInputNode,"Environment","Ocean","FogDistance", "8"));
m_bOceanCaustics = atol(GetXMLAttribText(pInputNode,"Environment","Ocean","Caustics", "1"))==1;
m_fSkyBoxAngle = (float)atof(GetXMLAttribText(pInputNode,"Environment","EnvState","SkyBoxAngle","0.0"));
m_fSunHeightScale = (float)atof(GetXMLAttribText(pInputNode,"Environment","EnvState","SunHeightScale","1.0"));
m_fSkyBoxStretching = (float)atof(GetXMLAttribText(pInputNode,"Environment","EnvState","SkyBoxStretching","1.0"));
m_pTerrain->InitTerrainWater(bEditorMode, m_pTerrainWaterShader, m_nWaterBottomTexId, m_pSunRoadShader, m_fWaterTranspRatio, m_fWaterReflectRatio, m_fWaterBumpAmountX, m_fWaterBumpAmountY, m_fWaterBorderTranspRatio);
char szLensFlaresShaderName[128];
strncpy(szLensFlaresShaderName, GetXMLAttribText(pInputNode,"Environment","Shaders","SunLensFlares","CryLight"), sizeof(szLensFlaresShaderName));
if(szLensFlaresShaderName[0])
m_pSHLensFlares = GetRenderer()->EF_LoadShader(szLensFlaresShaderName, eSH_World, EF_SYSTEM);
else
m_pSHLensFlares = NULL;
char szShoreShaderName[128];
strncpy(szShoreShaderName, GetXMLAttribText(pInputNode,"Environment","Shaders","Shore", "terrainwaterbeach"), sizeof(szShoreShaderName));
m_pTerrain->m_pSHShore = szShoreShaderName[0] ? GetRenderer()->EF_LoadShader(szShoreShaderName, eSH_World, EF_SYSTEM) : 0;
// State
vColor = StringToVector(GetXMLAttribText(pInputNode,"Environment","EnvState","EnvColor","128,128,128"));
m_vWorldColorConst = vColor/255.f;
// GetCVars()->e_rain_amount = strstr(GetXMLAttribText(pInputNode,"Environment","EnvState","Rain",""),"True")!=0;
// GetCVars()->e_bflyes = GetCVars()->e_bflyes && strstr(GetXMLAttribText(pInputNode,"Environment","EnvState","BFlyes",""),"True")!=0;
// set sun position
m_vSunPosition = StringToVector(GetXMLAttribText(pInputNode,"Environment","Lighting","SunVector","0,5,-5"));
m_vSunPosition *= -1.0f;
m_vSunPosition.Normalize();
float x=m_vSunPosition.x;
m_vSunPosition.x = m_vSunPosition.y;
m_vSunPosition.y=x;
if(m_vSunPosition.x == 0 && m_vSunPosition.y == 0)
m_vSunPosition = Vec3d(5,5,10000);
else
m_vSunPosition = GetNormalized(m_vSunPosition)*10000;
m_pObjManager->m_vOutdoorAmbientColor =
StringToVector(GetXMLAttribText(pInputNode,"Environment","EnvState","OutdoorAmbientColor","64,64,64"))/255;
m_pObjManager->m_vSunColor =
StringToVector(GetXMLAttribText(pInputNode,"Environment","EnvState","SunColor","128,128,128"))/255;
if(!GetISystem()->IsDedicated())
m_pObjManager->UpdateCustomLighting( GetNormalized(GetSunPosition()) );
// get wind
m_pObjManager->m_fWindForce = (float)atof(GetXMLAttribText(pInputNode,"Environment","EnvState","WindForce","0.15"));
// get terrain lods
float fGeometryLodRatio = (float)atof(GetXMLAttribText(pInputNode,"Environment","HeightMap","GeometryLodRatio","1.0"));
if(GetCVars()->e_cgf_load_lods == 0 && fGeometryLodRatio>1.f) // ised only for very high spec
fGeometryLodRatio = 1.f+(fGeometryLodRatio-1.f)*0.5f;
ICVar * pCVar = GetConsole()->GetCVar("e_terrain_lod_ratio");
if(pCVar)
pCVar->Set(fGeometryLodRatio);
m_pTerrain->m_fTextureLodRatio = (float)atof(GetXMLAttribText(pInputNode,"Environment","HeightMap","TextureLodRatio", "1.0"));
}
//////////////////////////////////////////////////////////////////////////
void C3DEngine::LoadParticleEffects( XmlNodeRef &levelDataRoot,bool bEditorMode )
{
if (!m_pPartManager)
return;
m_pPartManager->LoadSharedParticleLibrary( EFFECTS_FOLDER,SHARED_PARTICLES_EXPLOSIONS );
m_pPartManager->LoadSharedParticleLibrary( EFFECTS_FOLDER,SHARED_PARTICLES_WATER );
m_pPartManager->LoadSharedParticleLibrary( EFFECTS_FOLDER,SHARED_PARTICLES_SMOKE );
m_pPartManager->LoadSharedParticleLibrary( EFFECTS_FOLDER,SHARED_PARTICLES_BLOOD );
m_pPartManager->LoadSharedParticleLibrary( EFFECTS_FOLDER,SHARED_PARTICLES_BULLET );
m_pPartManager->LoadSharedParticleLibrary( EFFECTS_FOLDER,SHARED_PARTICLES_MISC );
m_pPartManager->LoadSharedParticleLibrary( EFFECTS_FOLDER,SHARED_PARTICLES_FIRE );
if (levelDataRoot)
m_pPartManager->LoadParticlesLibs( EFFECTS_FOLDER,levelDataRoot );
CCryFile file;
if (file.Open( GetLevelFilePath(PARTICLES_FILE),"rb" ))
{
m_pPartManager->LoadParticles( file );
}
}

51
Cry3DEngine/Array2d.h Normal file
View File

@@ -0,0 +1,51 @@
#ifndef _ARRAY2D_H_
#define _ARRAY2D_H_
// Dynamic replacement for static 2d array
template <class T> struct Array2d
{
Array2d()
{
m_nSize = 0;
m_pData = 0;
}
void GetMemoryUsage(ICrySizer*pSizer)
{
pSizer->AddObject (m_pData, m_nSize*m_nSize*sizeof(T));
}
void Allocate(int nSize)
{
if(m_nSize == nSize)
return;
delete m_pData;
m_nSize = nSize;
m_pData = new T [nSize*nSize];
memset(m_pData, 0, nSize*nSize*sizeof(T));
}
~Array2d()
{
delete [] m_pData;
}
T * m_pData;
int m_nSize;
T * operator [] (const int & nPos) const
{
assert(nPos>=0 && nPos<m_nSize);
return &m_pData[nPos*m_nSize];
}
void operator = (const Array2d & other)
{
Allocate(other.m_nSize);
memcpy(m_pData,other.m_pData,m_nSize*m_nSize*sizeof(T));
}
};
#endif // _ARRAY2D_H_

42
Cry3DEngine/BaseObj.h Normal file
View File

@@ -0,0 +1,42 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: baseobj.h
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_BASEOBJ_H__2D817DB5_34FA_4C73_8588_867E88C9CFB3__INCLUDED_)
#define AFX_BASEOBJ_H__2D817DB5_34FA_4C73_8588_867E88C9CFB3__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CBaseObj
{
public:
CHUNK_HEADER m_ChunkHeader;
bool m_bBinded;
int m_nUsers;
CBaseObj()
{
memset(&m_ChunkHeader,0,sizeof(m_ChunkHeader));
m_bBinded = false;
m_nUsers = 0;
}
virtual ~CBaseObj(){};
virtual bool Load(CXFile *f, int pos) { return false; }
virtual void Bind(CBaseObj **all_objects, int n_obj){}
};
#endif // !defined(AFX_BASEOBJ_H__2D817DB5_34FA_4C73_8588_867E88C9CFB3__INCLUDED_)

889
Cry3DEngine/BasicArea.cpp Normal file
View File

@@ -0,0 +1,889 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: statobjman.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: objects container, streaming, common part for indoor and outdoor sectors
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "StatObj.h"
#include "objman.h"
#include "visareas.h"
#include "terrain_sector.h"
#include "cbuffer.h"
#include "3DEngine.h"
#include "meshidx.h"
#include "watervolumes.h"
#include "brush.h"
#include "LMCompStructures.h"
void CBasicArea::SerializeArea(bool bSave)
{
char szFileName[256]="";
sprintf(szFileName,"visarea_objects_%.1f_%.1f_%.1f_%.1f.cache", m_vBoxMin.x, m_vBoxMin.y, m_vBoxMax.x, m_vBoxMax.y);
FILE * f = GetPak()->FOpen(Get3DEngine()->GetFilePath(szFileName), bSave ? "wb" : "rb");
if(!f)
return;
if(bSave)
{
for(int i=0; i<m_lstEntities[STATIC_ENTITIES].Count(); i++)
{
EERType eType = m_lstEntities[STATIC_ENTITIES].GetAt(i)->GetEntityRenderType();
if(eType == eERType_Brush || eType == eERType_Vegetation)
{
GetPak()->FWrite(&eType,sizeof(eType),1,f);
// if(m_lstEntities[STATIC_ENTITIES].GetAt(i)->GetEntityRS())
{
m_lstEntities[STATIC_ENTITIES].GetAt(i)->m_pVisArea = 0;
m_lstEntities[STATIC_ENTITIES].GetAt(i)->m_pSector = 0;
}
m_lstEntities[STATIC_ENTITIES].GetAt(i)->Dephysicalize();
m_lstEntities[STATIC_ENTITIES].GetAt(i)->Dematerialize();
m_lstEntities[STATIC_ENTITIES].GetAt(i)->Serialize(bSave,GetPak(),f);
}
}
m_lstEntities[STATIC_ENTITIES].Reset();
}
else
{
assert(m_lstEntities[STATIC_ENTITIES].Count()==0);
m_lstEntities[STATIC_ENTITIES].Reset();
m_eSStatus = eSStatus_Ready;
while(1)
{
EERType eType = eERType_Unknown;
if(GetPak()->FRead(&eType,sizeof(eType),1,f)!=1)
break;
IEntityRender * pEntityRender = 0;
if(eType == eERType_Brush)
pEntityRender = new CBrush();
else if(eType == eERType_Vegetation)
pEntityRender = new CStatObjInst();
if(pEntityRender)
{
pEntityRender->Serialize(bSave,GetPak(),f);
pEntityRender->GetEntityRS() = new IEntityRenderState;
pEntityRender->Physicalize();
Get3DEngine()->RegisterEntity(pEntityRender);
}
}
}
GetPak()->FClose(f);
}
void CBasicArea::UnmakeAreaBrush()
{
for( int i=0; i<m_lstAreaBrush.Count(); i++ )
FreeAreaBrush(m_lstAreaBrush[i]);
// mark all objects as unmerged
if(m_lstAreaBrush.Count())
for( int i=0; i<m_lstEntities[STATIC_ENTITIES].Count(); i++ )
{
IEntityRender * pEntityRender = m_lstEntities[STATIC_ENTITIES].GetAt(i);
pEntityRender->m_dwRndFlags &= ~ERF_MERGED;
assert(!(pEntityRender->m_dwRndFlags & ERF_MERGED));
}
m_lstAreaBrush.Clear();
}
void CBasicArea::DrawEntities( int nFogVolumeID, int nDLightMask,
bool bLMapGeneration, const CCamera & EntViewCamera, Vec3d * pvAmbColor, Vec3d * pvDynAmbColor,
VolumeInfo * pFogVolume, bool bNotAllInFrustum, float fSectorMinDist,
CObjManager * pObjManager, bool bAllowBrushMerging, char*fake, uint nStatics)
{
FUNCTION_PROFILER_FAST( GetSystem(),PROFILE_3DENGINE,m_bProfilerEnabled );
if(!GetCVars()->e_objects)
return;
if(GetCVars()->e_stream_areas && GetCVars()->e_stream_for_visuals && CStatObj::m_fStreamingTimePerFrame<CGF_STREAMING_MAX_TIME_PER_FRAME)
{
m_nLastUsedFrameId = GetFrameID();
if(m_eSStatus != eSStatus_Ready)
{
CStatObj::m_fStreamingTimePerFrame -= GetTimer()->GetAsyncCurTime();
SerializeArea(false);
CStatObj::m_fStreamingTimePerFrame += GetTimer()->GetAsyncCurTime();
}
}
// apply zoom factor
fSectorMinDist *= pObjManager->m_fZoomFactor;
// make lmask for vegetations
int nDLightMaskNoSun = nDLightMask;
list2<CDLight> * pSources = ((C3DEngine*)m_p3DEngine)->GetDynamicLightSources();
for(int i=0; i<pSources->Count(); i++)
{
CDLight * pDynLight = pSources->Get(i);
assert(pDynLight->m_Id == i || pDynLight->m_Id == -1);
if(pDynLight->m_Flags & DLF_SUN)
{
nDLightMaskNoSun &= ~(1<<pDynLight->m_Id);
break;
}
}
if(nStatics && m_StaticEntitiesSorted && GetCVars()->e_optimized_render_object &&
!bLMapGeneration && pObjManager->m_fZoomFactor >= 0.99f)
{ // render statics compiled
const Vec3d vCamPos = EntViewCamera.GetPos();
const Plane PlaneR = *EntViewCamera.GetFrustumPlane(FR_PLANE_RIGHT);
const Plane PlaneL = *EntViewCamera.GetFrustumPlane(FR_PLANE_LEFT);
static list2<IEntityRenderInfo*> TmpEntList; TmpEntList.Clear();
list2<struct IEntityRender*> & SrcEntList = m_lstEntities[STATIC_ENTITIES];
if(GetCVars()->e_vegetation)
{ // fill simple vegetations
// FRAME_PROFILER( "*fill simple vegetations", GetSystem(), PROFILE_3DENGINE );
for( int i=0; i<m_lstStatEntInfoVegetNoCastersNoVolFog.Count(); i++ )
{
IEntityRenderInfo & inf = m_lstStatEntInfoVegetNoCastersNoVolFog[i];
if(fSectorMinDist >= inf.m_fWSMaxViewDist)
break;
// check max view distance sq
const Vec3d vCamPos = EntViewCamera.GetPos();
const float dx = vCamPos.x-inf.m_vWSCenter.x;
const float dy = vCamPos.y-inf.m_vWSCenter.y;
const float fEntDistanceSQ = (dx*dx+dy*dy); // must be 2d for sprites
if(fEntDistanceSQ > inf.m_fWSMaxViewDistSQ)
continue;
// early sphere test agains left and right camera planes
if( bNotAllInFrustum &&
PlaneR.DistFromPlane(inf.m_vWSCenter) > inf.m_fWSRadius ||
PlaneR.DistFromPlane(inf.m_vWSCenter) > inf.m_fWSRadius )
continue;
// get view distance
inf.m_fEntDistance = cry_sqrtf(fEntDistanceSQ);
assert(inf.m_fEntDistance>=0 && _finite(inf.m_fEntDistance));
assert(inf.m_fEntDistance <= inf.m_fWSMaxViewDist);
TmpEntList.Add(&inf);
}
// render simple vegetations
// FRAME_PROFILER( "*render simple vegetations", GetSystem(), PROFILE_3DENGINE );
for( int i=0; i<TmpEntList.Count(); i++ )
{
IEntityRender * pEntityRender = TmpEntList.GetAt(i)->m_pEntityRender;
if (i+1 < TmpEntList.Count())
{ // prefech next element
IEntityRender * pNext = TmpEntList.GetAt(i+1)->m_pEntityRender;
cryPrefetchT0SSE(pNext);
}
assert(fSectorMinDist < pEntityRender->m_fWSMaxViewDist);
pObjManager->RenderObjectVegetationNonCastersNoFogVolume( pEntityRender,
nDLightMaskNoSun, EntViewCamera, bNotAllInFrustum,
pEntityRender->m_fWSMaxViewDist, TmpEntList.GetAt(i));
}
}
TmpEntList.Clear();
if(GetCVars()->e_vegetation || GetCVars()->e_brushes)
{ // fill complex objects
// FRAME_PROFILER( "*fill complex objects", GetSystem(), PROFILE_3DENGINE );
for( int i=0; i<m_lstStatEntInfoOthers.Count(); i++ )
{
IEntityRenderInfo & inf = m_lstStatEntInfoOthers[i];
if(fSectorMinDist >= inf.m_fWSMaxViewDist)
break;
// check max view distance sq
const Vec3d vCamPos = EntViewCamera.GetPos();
const float dx = vCamPos.x-inf.m_vWSCenter.x;
const float dy = vCamPos.y-inf.m_vWSCenter.y;
const float fEntDistanceSQ = (dx*dx+dy*dy); // must be 2d for sprites
if(fEntDistanceSQ > inf.m_fWSMaxViewDistSQ)
continue;
// early sphere test agains left and right camera planes
if( bNotAllInFrustum &&
PlaneR.DistFromPlane(inf.m_vWSCenter) > inf.m_fWSRadius+TERRAIN_SECTORS_MAX_OVERLAPPING ||
PlaneR.DistFromPlane(inf.m_vWSCenter) > inf.m_fWSRadius+TERRAIN_SECTORS_MAX_OVERLAPPING )
continue;
// get view distance
inf.m_fEntDistance = cry_sqrtf(fEntDistanceSQ);
assert(inf.m_fEntDistance>=0 && _finite(inf.m_fEntDistance));
assert(inf.m_fEntDistance <= inf.m_fWSMaxViewDist);
TmpEntList.Add(&inf);
}
// render complex objects
// FRAME_PROFILER( "*render complex objects", GetSystem(), PROFILE_3DENGINE );
for( int i=0; i<TmpEntList.Count(); i++ )
{
IEntityRender * pEntityRender = TmpEntList.GetAt(i)->m_pEntityRender;
if (i+1 < TmpEntList.Count())
{ // prefech next element
IEntityRender * pNext = TmpEntList.GetAt(i+1)->m_pEntityRender;
cryPrefetchT0SSE(pNext);
}
assert(fSectorMinDist < pEntityRender->m_fWSMaxViewDist);
pObjManager->RenderObject( pEntityRender, nFogVolumeID,
nDLightMask, bLMapGeneration, EntViewCamera, pvAmbColor, pvDynAmbColor, pFogVolume, bNotAllInFrustum,
pEntityRender->m_fWSMaxViewDist, TmpEntList.GetAt(i));
}
}
}
else if(nStatics && m_StaticEntitiesSorted && !bLMapGeneration)
{
#ifdef VEGETATION_MEM_STATS
static int64 t0=0,t1=0,t2=0;
#endif // VEGETATION_MEM_STATS
list2<struct IEntityRender*> & EntList = m_lstEntities[STATIC_ENTITIES];
for( int i=0; i<EntList.Count(); i++ )
{
IEntityRender * pEntityRender = EntList.GetAt(i);
if (i+1 < EntList.Count())
{ // prefech next element
IEntityRender * pNext = EntList.GetAt(i+1);
cryPrefetchT0SSE(pNext);
}
#ifdef VEGETATION_MEM_STATS
if (i+1 < EntList.Count())
{
IEntityRender * pNext = EntList.GetAt(i+1);
IEntityRender * pThis = EntList.GetAt(i);
if(pNext>pThis)
{
if(((int64)pNext-(int64)pThis)<=128)
t0++;
else
t1++;
}
else
t2++;
}
#endif // VEGETATION_MEM_STATS
if(fSectorMinDist > pEntityRender->m_fWSMaxViewDist)
break;
pObjManager->RenderObject( pEntityRender, nFogVolumeID,
nDLightMask, bLMapGeneration, EntViewCamera, pvAmbColor, pvDynAmbColor, pFogVolume, bNotAllInFrustum,
pEntityRender->m_fWSMaxViewDist);
}
#ifdef VEGETATION_MEM_STATS
static int fr=0;
if((GetFrameID()&63)==0 && fr!=GetFrameID())
{
fr=GetFrameID();
if(t0+t1+t2)
GetLog()->Log(
"<128 = %.1f, >128 = %.1f, NEG = %.1f",
0.1f*float((t0*1000/(t0+t1+t2))),
0.1f*float((t1*1000/(t0+t1+t2))),
0.1f*float((t2*1000/(t0+t1+t2))));
}
#endif // VEGETATION_MEM_STATS
}
else if(nStatics || GetCVars()->e_entities)
{ // render dynamics or statics uncompiled
assert(!m_StaticEntitiesSorted || !nStatics);
list2<struct IEntityRender*> & EntList = m_lstEntities[nStatics];
for( int i=0; i<EntList.Count(); i++ )
{
IEntityRender * pEntityRender = EntList.GetAt(i);
pEntityRender->m_fWSMaxViewDist = pEntityRender->GetMaxViewDist();
if(fSectorMinDist > pEntityRender->m_fWSMaxViewDist)
continue;
pObjManager->RenderObject( pEntityRender, nFogVolumeID,
nDLightMask, bLMapGeneration, EntViewCamera, pvAmbColor, pvDynAmbColor, pFogVolume, bNotAllInFrustum,
pEntityRender->m_fWSMaxViewDist);
}
}
}
void CBasicArea::Unload(bool bUnloadOnlyVegetations, const Vec3d & vVegetPos)
{
if(bUnloadOnlyVegetations)
{
for(int i=0; i<m_lstEntities[STATIC_ENTITIES].Count(); i++)
{
EERType eType = m_lstEntities[STATIC_ENTITIES].GetAt(i)->GetEntityRenderType();
if(eType == eERType_Vegetation)
{
Vec3d vEntPos = m_lstEntities[STATIC_ENTITIES].GetAt(i)->GetPos();
float fDist = (vVegetPos==Vec3d(0,0,0)) ? 0 : GetDist2D(vVegetPos.x,vVegetPos.y,vEntPos.x,vEntPos.y);
if(fDist<0.01f)
{
int nCountBefore = m_lstEntities[STATIC_ENTITIES].Count();
delete m_lstEntities[STATIC_ENTITIES].GetAt(i); // will also remove it from this list
assert(m_lstEntities[STATIC_ENTITIES].Count() == (nCountBefore-1));
i--;
}
}
}
}
else
{
while(m_lstEntities[STATIC_ENTITIES].Count())
{
EERType eType = m_lstEntities[STATIC_ENTITIES].GetAt(0)->GetEntityRenderType();
assert(eType == eERType_Brush || eType == eERType_Vegetation);
int nCountBefore = m_lstEntities[STATIC_ENTITIES].Count();
if(eType != eERType_Vegetation)
Get3DEngine()->ReleaseObject(m_lstEntities[STATIC_ENTITIES].GetAt(0)->GetEntityStatObj(0));
m_lstEntities[STATIC_ENTITIES].GetAt(0)->SetEntityStatObj(0,0);
IEntityRender * pEntityRender = m_lstEntities[STATIC_ENTITIES].GetAt(0); // will also remove it from this list
delete pEntityRender; // will also remove it from this list
assert(m_lstEntities[STATIC_ENTITIES].Count() == (nCountBefore-1));
}
assert(m_lstEntities[STATIC_ENTITIES].Count()==0);
m_eSStatus = eSStatus_Unloaded;
}
UnmakeAreaBrush();
}
bool CBasicArea::CheckUnload()
{
if(CStatObj::m_fStreamingTimePerFrame>=CGF_STREAMING_MAX_TIME_PER_FRAME)
return (m_eSStatus == eSStatus_Ready);
CStatObj::m_fStreamingTimePerFrame -= GetTimer()->GetAsyncCurTime();
if(m_nLastUsedFrameId < GetFrameID() - 100)// && m_lstEntities[STATIC_ENTITIES].Count())
{ // unload
Unload();
}
CStatObj::m_fStreamingTimePerFrame += GetTimer()->GetAsyncCurTime();
return (m_eSStatus == eSStatus_Ready);
}
void CBasicArea::CheckPhysicalized()
{
if(m_eSStatus != eSStatus_Ready)
SerializeArea(false);
for(int i=0; i<m_lstEntities[STATIC_ENTITIES].Count(); i++)
m_lstEntities[STATIC_ENTITIES][i]->CheckPhysicalized();
m_nLastUsedFrameId = GetFrameID();
}
void CBasicArea::PreloadResources(Vec3d vPrevPortalPos, float fPrevPortalDistance)
{
FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE );
int nFrameId = GetFrameID();
for(int nStatic=0; nStatic<2; nStatic++)
for( int i=0; i<m_lstEntities[nStatic].Count() && GetCurTimeSec()<(m_fPreloadStartTime+0.010f); i++ )
{
if((nFrameId%8) == (i%8))
m_lstEntities[nStatic].GetAt(i)->PreloadInstanceResources(vPrevPortalPos, fPrevPortalDistance, 1.f);
}
}
void CBasicArea::UnregisterDynamicEntities()
{
while(m_lstEntities[DYNAMIC_ENTITIES].Count())
{
EERType eType = m_lstEntities[DYNAMIC_ENTITIES].GetAt(0)->GetEntityRenderType();
assert(eType != eERType_Brush && eType != eERType_Vegetation);
int nCountBefore = m_lstEntities[DYNAMIC_ENTITIES].Count();
// delete m_lstEntities[DYNAMIC_ENTITIES].GetAt(0); // will also remove it from this list
Get3DEngine()->UnRegisterEntity(m_lstEntities[DYNAMIC_ENTITIES].GetAt(0));
assert(m_lstEntities[DYNAMIC_ENTITIES].Count() == (nCountBefore-1));
}
assert(m_lstEntities[DYNAMIC_ENTITIES].Count()==0);
}
int __cdecl CObjManager__Cmp_EntTmpDistance(const void* v1, const void* v2);
void CBasicArea::SortStaticInstancesBySize(VolumeInfo * pFogVolume)
{
// sort lists instances in sector by size ( for rendering speed up )
for( int i=0; i<m_lstEntities[STATIC_ENTITIES].Count(); i++)
{
m_lstEntities[STATIC_ENTITIES][i]->GetEntityRS()->fTmpDistance =
-m_lstEntities[STATIC_ENTITIES][i]->GetMaxViewDist();
m_lstEntities[STATIC_ENTITIES][i]->m_fWSMaxViewDist = m_lstEntities[STATIC_ENTITIES][i]->GetMaxViewDist();
}
// sort
if(m_lstEntities[STATIC_ENTITIES].Count())
qsort(m_lstEntities[STATIC_ENTITIES].GetElements(), m_lstEntities[STATIC_ENTITIES].Count(),
sizeof(m_lstEntities[STATIC_ENTITIES][0]), CObjManager__Cmp_EntTmpDistance);
m_lstStaticShadowMapCasters.Clear();
for( int i=0; i<m_lstEntities[STATIC_ENTITIES].Count(); i++)
{
IEntityRender * pEntityRender = m_lstEntities[STATIC_ENTITIES][i];
if(pEntityRender->GetRndFlags()&ERF_CASTSHADOWMAPS)
m_lstStaticShadowMapCasters.Add(pEntityRender);
}
m_lstStatEntInfoVegetNoCastersNoVolFog.Clear();
m_lstStatEntInfoOthers.Clear();
for( int i=0; i<m_lstEntities[STATIC_ENTITIES].Count(); i++)
{
IEntityRender * pEntityRender = m_lstEntities[STATIC_ENTITIES][i];
IEntityRenderInfo inf(pEntityRender);
bool bInFogVolume = false;
if(pFogVolume)
{ // fog is set only for outdoors
Vec3d vBoxMin,vBoxMax;
assert(pEntityRender->m_pSector);
pEntityRender->GetBBox(vBoxMin,vBoxMax);
if(pFogVolume->IntersectBBox(vBoxMin,vBoxMax))
bInFogVolume = true;
}
if( !(pEntityRender->GetRndFlags() & (ERF_CASTSHADOWMAPS|ERF_CASTSHADOWVOLUME|ERF_RECVSHADOWMAPS|ERF_SELFSHADOW)) &&
pEntityRender->GetEntityRenderType() == eERType_Vegetation &&
!bInFogVolume)
m_lstStatEntInfoVegetNoCastersNoVolFog.Add(inf);
else
m_lstStatEntInfoOthers.Add(inf);
}
m_StaticEntitiesSorted = true;
// swap to disk
if(GetCVars()->e_stream_areas)
SerializeArea(true);
}
int __cdecl CBasicArea__Cmp_MatChunks(const void* v1, const void* v2)
{
CMatInfo * pMat1 = (CMatInfo*)v1;
CMatInfo * pMat2 = (CMatInfo*)v2;
// shader
if(pMat1->shaderItem.m_pShader->GetTemplate(-1) > pMat2->shaderItem.m_pShader->GetTemplate(-1))
return 1;
else if(pMat1->shaderItem.m_pShader->GetTemplate(-1) < pMat2->shaderItem.m_pShader->GetTemplate(-1))
return -1;
// shader resources
if(pMat1->shaderItem.m_pShaderResources > pMat2->shaderItem.m_pShaderResources)
return 1;
else if(pMat1->shaderItem.m_pShaderResources < pMat2->shaderItem.m_pShaderResources)
return -1;
// lm tex id
if(pMat1->m_Id > pMat2->m_Id)
return 1;
else if(pMat1->m_Id < pMat2->m_Id)
return -1;
return 0;
/*
const char * pName1 = ((*(((*(pMat1)).shaderItem).m_pShaderResources)).m_Textures)[0] ? (*(((*(((*(pMat1)).shaderItem).m_pShaderResources)).m_Textures)[0])).m_Name.c_str() : "";
const char * pName2 = ((*(((*(pMat2)).shaderItem).m_pShaderResources)).m_Textures)[0] ? (*(((*(((*(pMat2)).shaderItem).m_pShaderResources)).m_Textures)[0])).m_Name.c_str() : "";
return strcmp(pName1,pName2);*/
}
struct LMTexCoord
{
float s,t;
};
void CBasicArea::MakeAreaBrush()
{
const Vec3d vCamPos = GetViewCamera().GetPos();
int nEntityId=0;
int nNextStartId=-1;
while(nEntityId<m_lstEntities[STATIC_ENTITIES].Count() || nNextStartId>=0)
{
static list2<struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F> lstVerts;lstVerts.Clear();
static list2<LMTexCoord> lstLMTexCoords; lstLMTexCoords.Clear();
static list2<ushort> lstIndices; lstIndices.Clear();
static list2<ushort> lstIndicesSorted; lstIndicesSorted.Clear();
static list2<CMatInfo> lstChunks; lstChunks.Clear();
static list2<CMatInfo> lstChunksMerged; lstChunksMerged.Clear();
static list2<SPipTangents> lstTangBasises; lstTangBasises.Clear();
Vec3d vBoxMax(-10000,-10000,-10000);
Vec3d vBoxMin( 10000, 10000, 10000);
int nLMTexId=-1;
int nHDRLMTexId=-1;
int nLMDirTexId=-1;
int nCurVertsNum=0;
if(nNextStartId>=0)
nEntityId = nNextStartId;
nNextStartId=-1;
for( ; nEntityId<m_lstEntities[STATIC_ENTITIES].Count(); nEntityId++)
{
IEntityRender * pEntityRender = m_lstEntities[STATIC_ENTITIES][nEntityId];
if( pEntityRender->m_dwRndFlags & ERF_MERGED ||
pEntityRender->m_dwRndFlags & ERF_CASTSHADOWVOLUME ||
pEntityRender->m_dwRndFlags & ERF_CASTSHADOWMAPS)
continue;
// Vec3d vCenter = (pEntityRender->m_vWSBoxMin+pEntityRender->m_vWSBoxMax)*0.5f;
// float fEntDistance = GetDist2D( vCamPos.x, vCamPos.y, vCenter.x, vCenter.y );
// if(fEntDistance > pEntityRender->GetMaxViewDist())
// continue;
// if(fEntDistance > GetCVars()->e_area_merging_distance)
// continue;
if(nLMTexId<0)
{
nLMTexId = pEntityRender->GetLightmap(0) ? pEntityRender->GetLightmap(0)->GetColorLerpTex() : 0;
nHDRLMTexId = pEntityRender->GetLightmap(0) ? pEntityRender->GetLightmap(0)->GetHDRColorLerpTex() : 0;
nLMDirTexId = pEntityRender->GetLightmap(0) ? pEntityRender->GetLightmap(0)->GetDomDirectionTex() : 0;
}
else
{
if(nLMTexId != (pEntityRender->GetLightmap(0) ? pEntityRender->GetLightmap(0)->GetColorLerpTex() : 0) ||
nLMDirTexId != (pEntityRender->GetLightmap(0) ? pEntityRender->GetLightmap(0)->GetDomDirectionTex() : 0) ||
nHDRLMTexId != (pEntityRender->GetLightmap(0) ? pEntityRender->GetLightmap(0)->GetHDRColorLerpTex() : 0))
{
if(nNextStartId<0)
nNextStartId = nEntityId;
continue;
}
}
Matrix44 mat;
mat.SetIdentity();
mat*=0;
IStatObj * pStatObj = pEntityRender->GetEntityStatObj(0,&mat);
if(!pStatObj)
continue;
EERType eType = pEntityRender->GetEntityRenderType();
if(eType == eERType_Vegetation)
{
Matrix33diag diag = Vec3(pEntityRender->GetScale(),pEntityRender->GetScale(),pEntityRender->GetScale()); //use diag-matrix for scaling
mathCalcMatrix(mat, pEntityRender->GetPos(), Vec3d(0,0,0),
Vec3d(pEntityRender->GetScale(),pEntityRender->GetScale(),pEntityRender->GetScale()),
Cry3DEngineBase::m_CpuFlags);
}
if(!CBrush::IsMatrixValid(mat))
continue;
CLeafBuffer * pLMLB = pEntityRender->GetLightmapTexCoord(0);
CLeafBuffer * pLB = pStatObj->GetLeafBuffer();
if(!pLB->m_SecVertCount)
continue;
if(nCurVertsNum + pLB->m_SecVertCount>65000)
break;
int nIndCount=0;
pLB->GetIndices(&nIndCount);
if(nIndCount > GetCVars()->e_area_merging_max_tris_in_input_brush*3)
continue;
int nInitVertCout = lstVerts.Count();
for(int m=0; m<pLB->m_pMats->Count(); m++)
{
CMatInfo newMatInfo = *pLB->m_pMats->Get(m);
if(GetCVars()->e_materials)
{ // Override default material
CMatInfo * pCustMat = (CMatInfo *)pEntityRender->GetMaterial();
if (pCustMat)
{
int nMatId = newMatInfo.m_nCGFMaterialID;
if(nMatId<0)
continue;
if (nMatId == 0)
pCustMat = (CMatInfo*)pCustMat;
else if (nMatId-1 < pCustMat->GetSubMtlCount())
pCustMat = (CMatInfo*)pCustMat->GetSubMtl(nMatId-1);
newMatInfo.shaderItem = pCustMat->shaderItem;
}
}
// copy indices
for(int i=newMatInfo.nFirstIndexId; i<newMatInfo.nFirstIndexId+newMatInfo.nNumIndices; i++)
lstIndices.Add(pLB->GetIndices(0)[i]+nInitVertCout);
newMatInfo.nFirstIndexId = lstIndices.Count() - newMatInfo.nNumIndices;
// copy verts
int nPosStride=0;
const byte * pPos = pLB->GetPosPtr(nPosStride,0,true);
int nTexStride=0;
const byte * pTex = pLB->GetUVPtr(nTexStride,0,true);
// get tengent basis
int nTangStride=0;
const byte * pTang = pLB->GetTangentPtr(nTangStride,0,true);
int nTnormStride=0;
const byte * pTNorm = pLB->GetTNormalPtr(nTnormStride,0,true);
int nBNormStride=0;
const byte * pBNorm = pLB->GetBinormalPtr(nBNormStride,0,true);
int nColorStride=0;
const byte * pColor = pLB->GetColorPtr(nColorStride,0,true);
// get LM TexCoords
int nLMStride=0;
const byte * pLMTexCoords = pLMLB ? pLMLB->GetPosPtr(nLMStride,0,true) : 0;
for(int v=newMatInfo.nFirstVertId; v<newMatInfo.nFirstVertId+newMatInfo.nNumVerts; v++)
{
struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F vert;
// set pos
Vec3d vPos = *(Vec3d*)&pPos[nPosStride*v];
vPos = mat.TransformPointOLD(vPos);
vert.xyz = vPos;
// set uv
float * pUV = (float*)&pTex[nTexStride*v];
vert.st[0] = pUV[0];
vert.st[1] = pUV[1];
vert.color.dcolor = *(DWORD*)&pColor[nColorStride*v+0];
// calc bbox
vBoxMin.CheckMin(vPos);
vBoxMax.CheckMax(vPos);
lstVerts.Add(vert);
// add tbasis
SPipTangents basis;
basis.m_Tangent = mat.TransformVectorOLD(*(Vec3d*)&pTang[nTangStride*v]);
basis.m_TNormal = mat.TransformVectorOLD(*(Vec3d*)&pTNorm[nTnormStride*v]);
basis.m_Binormal= mat.TransformVectorOLD(*(Vec3d*)&pBNorm[nBNormStride*v]);
lstTangBasises.Add(basis);
// add LM texcoords
LMTexCoord vLMTC;
if(pLMTexCoords)
vLMTC = *(LMTexCoord*)&pLMTexCoords[nLMStride*v];
else
vLMTC.s = vLMTC.t = 0;
lstLMTexCoords.Add(vLMTC);
}
// set vert range
newMatInfo.nFirstVertId = lstVerts.Count() - newMatInfo.nNumVerts;
newMatInfo.pRE = 0;
newMatInfo.m_Id = pEntityRender->GetLightmap(0) ? pEntityRender->GetLightmap(0)->GetColorLerpTex() : 0;
if(newMatInfo.nNumIndices)
{
lstChunks.Add(newMatInfo);
}
else
assert(!newMatInfo.nNumVerts);
}
nCurVertsNum += pLB->m_SecVertCount;
pEntityRender->m_dwRndFlags |= ERF_MERGED;
}
CBrush * pAreaBrush = 0;
if(!lstVerts.Count())
{ // make empty brush - no geometry in sector
pAreaBrush = new CBrush;
m_lstAreaBrush.Add(pAreaBrush);
return;
}
// sort
if(lstChunks.Count())
qsort(lstChunks.GetElements(), lstChunks.Count(),
sizeof(lstChunks[0]), CBasicArea__Cmp_MatChunks);
// merge chunks
for(int nChunk=0; nChunk<lstChunks.Count(); nChunk++)
{
if(!nChunk || CBasicArea__Cmp_MatChunks(&lstChunks[nChunk], &lstChunks[nChunk-1]))
{ // not equal materials - add new chunk
lstChunksMerged.Add(lstChunks[nChunk]);
lstChunksMerged.Last().nFirstIndexId = lstIndicesSorted.Count();
lstChunksMerged.Last().nNumIndices = 0;
lstChunksMerged.Last().nFirstVertId = 0;
lstChunksMerged.Last().nNumVerts = lstVerts.Count();
}
// add indices
for(int nId=lstChunks[nChunk].nFirstIndexId; nId<lstChunks[nChunk].nFirstIndexId+lstChunks[nChunk].nNumIndices; nId++)
lstIndicesSorted.Add(lstIndices[nId]);
// update start/stop pos
lstChunksMerged.Last().nNumIndices += lstChunks[nChunk].nNumIndices;
}
lstChunks = lstChunksMerged;
lstIndices = lstIndicesSorted;
// make leaf buffer
CLeafBuffer * pAreaLB = GetRenderer()->CreateLeafBufferInitialized(
lstVerts.GetElements(), lstVerts.Count(), VERTEX_FORMAT_P3F_COL4UB_TEX2F,
lstIndices.GetElements(), lstIndices.Count(), R_PRIMV_TRIANGLES,
"AreaLB", eBT_Static, lstChunks.Count());
pAreaLB->UpdateTangBuffer(lstTangBasises.GetElements());
for(int i=0; i<lstChunks.Count(); i++)
{
pAreaLB->SetChunk(lstChunks[i].GetShaderItem().m_pShader,
lstChunks[i].nFirstVertId, lstChunks[i].nNumVerts,
lstChunks[i].nFirstIndexId, lstChunks[i].nNumIndices, i, true);
assert(lstChunks[i].GetShaderItem().m_pShaderResources);
assert(lstChunks[i].GetShaderItem().m_pShader);
pAreaLB->m_pMats->Get(i)->shaderItem = lstChunks[i].GetShaderItem();
pAreaLB->m_pMats->Get(i)->shaderItem.m_pShader->AddRef();
pAreaLB->m_pMats->Get(i)->shaderItem.m_pShaderResources->AddRef();
}
// make statobj
CStatObj * pAreaStatObj = new CStatObj();
pAreaStatObj->m_nLoadedTrisCount = lstIndices.Count()/3;
pAreaStatObj->SetLeafBuffer(pAreaLB);
pAreaStatObj->SetBBoxMin(vBoxMin);
pAreaStatObj->SetBBoxMax(vBoxMax);
pAreaStatObj->RegisterUser();
// make brush
pAreaBrush = new CBrush();
// if(m_pAreaBrush == (CBrush*)0x0e968358)
// int b=0;
Matrix44 mat;
mat.SetIdentity();
pAreaBrush->SetEntityStatObj(0,pAreaStatObj,&mat);
pAreaBrush->m_vWSBoxMin = vBoxMin;
pAreaBrush->m_vWSBoxMax = vBoxMax;
pAreaBrush->m_fWSRadius = vBoxMin.GetDistance(vBoxMax)*0.5f;
// Make leafbuffer and fill it with texture coordinates
if(nLMTexId && (nLMDirTexId || (GetCVars()->e_light_maps_quality==0)))
{
RenderLMData * pLMData = new RenderLMData(GetRenderer(), nLMTexId, nHDRLMTexId, nLMDirTexId);
pAreaBrush->SetLightmap(pLMData, (float*)lstLMTexCoords.GetElements(), lstLMTexCoords.Count(), 0);
pLMData->AddRef();
pAreaBrush->SetRndFlags(ERF_USELIGHTMAPS,true);
}
Get3DEngine()->UnRegisterEntity(pAreaBrush);
Get3DEngine()->RegisterEntity(pAreaBrush);
// find distance to the camera
const Vec3d vCamPos = GetViewCamera().GetPos();
Vec3d vCenter = (pAreaBrush->m_vWSBoxMin+pAreaBrush->m_vWSBoxMax)*0.5f;
float fEntDistance = GetDist2D( vCamPos.x, vCamPos.y, vCenter.x, vCenter.y );
assert(fEntDistance>=0);
assert(_finite(fEntDistance));
m_lstAreaBrush.Add(pAreaBrush);
}
}
void CBasicArea::FreeAreaBrush(CBrush * pAreaBrush)
{
if(!pAreaBrush)
return;
Get3DEngine()->UnRegisterEntity(pAreaBrush);
// if(m_pAreaBrush == (CBrush*)0x0e968358)
// int b=0;
CStatObj * pAreaStatObj = (CStatObj *)pAreaBrush->GetEntityStatObj(0);
if(pAreaStatObj)
{
pAreaBrush->SetEntityStatObj(0,0);
pAreaStatObj->UnregisterUser();
CLeafBuffer * pAreaLB = pAreaStatObj->GetLeafBuffer();
pAreaStatObj->SetLeafBuffer(0);
GetRenderer()->DeleteLeafBuffer(pAreaLB);
delete pAreaStatObj;
}
delete pAreaBrush;
pAreaBrush=0;
}
CBasicArea::~CBasicArea()
{
for( int i=0; i<m_lstAreaBrush.Count(); i++ )
FreeAreaBrush(m_lstAreaBrush[i]);
m_lstAreaBrush.Clear();
}
int CBasicArea::GetLastStaticElementIdWithInMaxViewDist(float fMaxViewDist)
{ // use binary search to find range of elements visible on fMaxViewDist
int nCount = m_lstEntities[STATIC_ENTITIES].Count();
int nCurrId = m_lstEntities[STATIC_ENTITIES].Count()/2;
for(int nJump=2; (nCount>>nJump); nJump++)
{
IEntityRender * pCaster = m_lstEntities[STATIC_ENTITIES][nCurrId];
if(pCaster->m_fWSMaxViewDist<fMaxViewDist)
nCurrId -= nCount>>nJump;
else
nCurrId += nCount>>nJump;
}
return min(nCurrId+2,m_lstEntities[STATIC_ENTITIES].Count());
}

66
Cry3DEngine/BasicArea.h Normal file
View File

@@ -0,0 +1,66 @@
#ifndef _BASICAREA_H_
#define _BASICAREA_H_
#define DYNAMIC_ENTITIES 0
#define STATIC_ENTITIES 1
enum ESStatus
{
eSStatus_Unloaded,
eSStatus_Ready
};
struct IEntityRenderInfo
{
IEntityRenderInfo(IEntityRender*pEntityRender)
{
m_fWSMaxViewDist = pEntityRender->m_fWSMaxViewDist;
m_fWSMaxViewDistSQ = pEntityRender->m_fWSMaxViewDist*pEntityRender->m_fWSMaxViewDist;
m_vWSCenter =(pEntityRender->m_vWSBoxMin+pEntityRender->m_vWSBoxMax)*0.5f;
m_fWSRadius = pEntityRender->m_fWSRadius;
m_pEntityRender = pEntityRender;
m_fEntDistance = 0;
}
float m_fWSMaxViewDistSQ;
float m_fWSMaxViewDist;
Vec3 m_vWSCenter;
float m_fEntDistance;
float m_fWSRadius;
struct IEntityRender*m_pEntityRender;
};
struct CBasicArea : public Cry3DEngineBase
{
CBasicArea() { m_nLastUsedFrameId=0; m_eSStatus=eSStatus_Unloaded; m_vBoxMin=m_vBoxMax=m_vAreaBrushFocusPos=Vec3d(0,0,0); m_StaticEntitiesSorted=false; }
~CBasicArea();
list2<struct IEntityRender*> m_lstEntities[2];
list2<IEntityRenderInfo> m_lstStatEntInfoVegetNoCastersNoVolFog, m_lstStatEntInfoOthers;
list2<struct IEntityRender*> m_lstStaticShadowMapCasters;
Vec3d m_vBoxMin, m_vBoxMax;
int m_nLastUsedFrameId;
ESStatus m_eSStatus;
bool m_StaticEntitiesSorted;
void SerializeArea(bool bSave);
void DrawEntities(int nFogVolumeID, int nDLightMask,
bool bLMapGeneration, const CCamera & EntViewCamera, Vec3d * pvAmbColor, Vec3d * pvDynAmbColor,
VolumeInfo * pFogVolume, bool bNotAllInFrustum, float fSectorMinDist,
CObjManager * pObjManager, bool bAllowBrushMerging, char*fake, uint nStatics);
bool CheckUnload();
void CheckPhysicalized();
void Unload(bool bUnloadOnlyVegetations = false, const Vec3d & vPos = Vec3d(0,0,0));
void PreloadResources(Vec3d vPrevPortalPos, float fPrevPortalDistance);
void UnregisterDynamicEntities();
void SortStaticInstancesBySize(VolumeInfo * pFogVolume = NULL);
void MakeAreaBrush();
void UnmakeAreaBrush();
void FreeAreaBrush(class CBrush * pAreaBrush);
int GetLastStaticElementIdWithInMaxViewDist(float fMaxViewDist);
list2<class CBrush *> m_lstAreaBrush;
Vec3d m_vAreaBrushFocusPos;
};
#endif // _BASICAREA_H_

1519
Cry3DEngine/Brush.cpp Normal file

File diff suppressed because it is too large Load Diff

120
Cry3DEngine/Brush.h Normal file
View File

@@ -0,0 +1,120 @@
#ifndef _3DENGINE_BRUSH_H_
#define _3DENGINE_BRUSH_H_
#include "ObjMan.H"
#if defined(LINUX)
#include "LMCompStructures.h"
#include "platform.h"
#else
struct RenderLMData;
#endif
TYPEDEF_AUTOPTR(RenderLMData);
struct SLMData
{
SLMData() { m_pLMTCBuffer=0; }
RenderLMData_AutoPtr m_pLMData;
struct CLeafBuffer * m_pLMTCBuffer;
};
class CBrush : public IEntityRender, public Cry3DEngineBase
{
public:
CBrush();
virtual ~CBrush();
virtual const char * GetEntityClassName() const;
virtual const Vec3d & GetPos(bool bWorldOnly = true) const;
virtual const Vec3d & GetAngles(int realA=0) const;
virtual float GetScale() const;
virtual const char *GetName() const;
virtual void GetRenderBBox( Vec3d &mins,Vec3d &maxs );
virtual float GetRenderRadius() const;
virtual bool HasChanged();
virtual bool DrawEntity(const struct SRendParams & EntDrawParams);
virtual bool IsStatic() const;
virtual struct IStatObj * GetEntityStatObj( unsigned int nSlot, Matrix44 * pMatrix = NULL, bool bReturnOnlyVisible = false);
virtual struct ICryCharInstance* GetEntityCharacter( unsigned int nSlot, Matrix44 * pMatrix = NULL );
virtual void SetEntityStatObj( unsigned int nSlot, IStatObj * pStatObj, Matrix44 * pMatrix = NULL );
virtual void SetLightmap(RenderLMData *pLMData, float *pTexCoords, UINT iNumTexCoords, int nLod);
//special call from lightmap serializer/compiler to set occlusion map values
virtual void SetLightmap(RenderLMData *pLMData, float *pTexCoords, UINT iNumTexCoords, const unsigned char cucOcclIDCount, const std::vector<std::pair<EntityId, EntityId> >& aIDs);
virtual bool HasLightmap(int nLod)
{
// only 2 conditions are valid
//assert((m_pLMData != NULL && m_pLMTCBuffer != NULL) || (m_pLMData == NULL && m_pLMTCBuffer == NULL));
#if !defined(LINUX64)
if (m_arrLMData[nLod].m_pLMData == NULL || m_arrLMData[nLod].m_pLMTCBuffer == NULL)
#else
if (m_arrLMData[nLod].m_pLMData == 0 || m_arrLMData[nLod].m_pLMTCBuffer == 0)
#endif
return false; // return to avoid crash somewhere if in release mode
return true;
};
virtual RenderLMData * GetLightmap(int nLod) { return m_arrLMData[nLod].m_pLMData; };
virtual struct CLeafBuffer * GetLightmapTexCoord(int nLod) { return m_arrLMData[nLod].m_pLMTCBuffer; };
virtual bool IsEntityHasSomethingToRender();
virtual bool IsEntityAreasVisible();
virtual IPhysicalEntity* GetPhysics() const ;
virtual void SetPhysics( IPhysicalEntity* pPhys );
static bool IsMatrixValid(const Matrix44 & mat);
void DeleteLMTC();
void Dephysicalize( );
virtual void Physicalize(bool bInstant=false);
//! Assign override material to this entity.
virtual void SetMaterial( IMatInfo *pMatInfo );
virtual void SetMaterialId( int nId ) { m_nMaterialId = nId; }
virtual IMatInfo* GetMaterial() const;
int GetEditorObjectId() { return m_nEditorObjectId; }
void SetEditorObjectId(int nEditorObjectId) { m_nEditorObjectId = nEditorObjectId; }
virtual void CheckPhysicalized();
int DestroyPhysicalEntityCallback(IPhysicalEntity *pent);
// int GetPhysGeomId(int nSlotId) { return m_arrPhysGeomId[nSlotId]; }
virtual float GetMaxViewDist();
virtual void Serialize(bool bSave, ICryPak * pPak, FILE * f);
virtual EERType GetEntityRenderType() { return eERType_Brush; }
void SetStatObjGroupId(int nStatObjInstanceGroupId) { m_nObjectTypeID = nStatObjInstanceGroupId; }
void SetMergeId(int nId) { m_nMergeID = nId; }
int GetMergeId() { return m_nMergeID; }
static list2<IStatObj*> m_lstBrushTypes;
void SetMatrix( Matrix44* pMatrix );
void Dematerialize( );
virtual int GetMemoryUsage();
static list2<SExportedBrushMaterial> m_lstSExportedBrushMaterials;
virtual void PreloadInstanceResources(Vec3d vPrevPortalPos, float fPrevPortalDistance, float fTime);
protected:
void CalcWholeBBox();
Vec3d m_vPos, m_vAngles;
float m_fScale;
// struct IStatObj * m_pStatObj;
Matrix44 m_Matrix;
IPhysicalEntity * m_pPhysEnt;
//! Override material.
_smart_ptr<IMatInfo> m_pMaterial;
int m_nMaterialId;
#define MAX_BRUSH_LODS_NUM 3
SLMData m_arrLMData[MAX_BRUSH_LODS_NUM];
int m_nEditorObjectId;
int m_nObjectTypeID;
int m_nMergeID;
//needed for occlusion maps
// std::vector<std::pair<EntityId, EntityId> > m_vnOcclIndices;//first one is real EntityID, second one is (entity)light index in StatLights.dat
IEntityRender * m_arrOcclusionLightOwners[4];
};
#endif // _3DENGINE_BRUSH_H_

135
Cry3DEngine/BrushLM.cpp Normal file
View File

@@ -0,0 +1,135 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: brushlm.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "StatObj.h"
#include "objman.h"
#include "visareas.h"
#include "terrain_sector.h"
#include "cbuffer.h"
#include "3DEngine.h"
#include "meshidx.h"
#include "watervolumes.h"
#include "LMCompStructures.h"
#include "brush.h"
#include "IEntitySystem.h"
void CBrush::SetLightmap(RenderLMData *pLMData, float *pTexCoords, UINT iNumTexCoords, const unsigned char cucOcclIDCount, const std::vector<std::pair<EntityId, EntityId> >& aIDs)
{
assert(cucOcclIDCount <= 4);
memset(m_arrOcclusionLightOwners,0,sizeof(m_arrOcclusionLightOwners));
if(GetCVars()->e_light_maps_occlusion)
{
if(m_bEditorMode)
{
for(int i=0; i<4 && i<cucOcclIDCount; ++i)
{
EntityId nEntId = aIDs[i].first;
IEntityRender * pEnt;
if(nEntId == (EntityId)-1)
pEnt = (IEntityRender*)-1; // sun
else
pEnt = GetSystem()->GetIEntitySystem()->GetEntity(nEntId);
// assert(pEnt);
m_arrOcclusionLightOwners[i] = pEnt;
}
}
else
{
const list2<CDLight*> * pStaticLights = Get3DEngine()->GetStaticLightSources();
for(int i=0; (i<4) && (i<cucOcclIDCount) && (pStaticLights->Count()); ++i)
{
EntityId nEntId = aIDs[i].second;
IEntityRender * pEnt;
if(nEntId == (EntityId)-1)
pEnt = (IEntityRender*)-1; // sun
else
pEnt = pStaticLights->GetAt(nEntId)->m_pOwner;
assert(pEnt);
m_arrOcclusionLightOwners[i] = pEnt;
}
}
}
SetLightmap(pLMData, pTexCoords, iNumTexCoords, 0);
}
void CBrush::SetLightmap(RenderLMData *pLMData, float *pTexCoords, UINT iNumTexCoords, int nLod)
{
// ---------------------------------------------------------------------------------------------
// Set a referenece of a DOT3 Lightmap object for this GLM
// ---------------------------------------------------------------------------------------------
IRenderer *pIRenderer = GetRenderer();
assert(iNumTexCoords);
assert(!IsBadReadPtr(pTexCoords, sizeof(float) * 2 * iNumTexCoords));
m_arrLMData[nLod].m_pLMData = pLMData;
if (m_arrLMData[nLod].m_pLMTCBuffer)
{
pIRenderer->DeleteLeafBuffer(m_arrLMData[nLod].m_pLMTCBuffer);
m_arrLMData[nLod].m_pLMTCBuffer = NULL;
}
IStatObj *pIStatObj = GetEntityStatObj(0, NULL);
if (pIStatObj == NULL)
return;
if(!pIStatObj->EnableLightamapSupport())
return;
CLeafBuffer *pLeafBuffer = pIStatObj->GetLeafBuffer();
if (pLeafBuffer == NULL)
return;
// Renderer expect 2 floats
std::vector<float> vTexCoord2;
vTexCoord2.reserve(iNumTexCoords * 2);
UINT i;
for (i=0; i<iNumTexCoords; i++)
{
vTexCoord2.push_back(pTexCoords[i * 2 + 0]); // S
vTexCoord2.push_back(pTexCoords[i * 2 + 1]); // T
}
if (pLeafBuffer->m_SecVertCount != iNumTexCoords)
{
char szBuffer[1024];
sprintf(szBuffer, "Error: CBrush::SetLightmap: Object at position (%f, %f, %f) has" \
" texture mismatch (%i coordinates supplied, %i required)\r\n",
GetPos().x, GetPos().y, GetPos().z,
iNumTexCoords, pLeafBuffer->m_SecVertCount);
Warning(0,pIStatObj->GetFileName(),szBuffer);
// assert(pLeafBuffer->m_SecVertCount == iNumTexCoords);
return;
}
// Make leafbuffer and fill it with texture coordinates
m_arrLMData[nLod].m_pLMTCBuffer = GetRenderer()->CreateLeafBufferInitialized(
&vTexCoord2[0], pLeafBuffer->m_SecVertCount, VERTEX_FORMAT_TEX2F,
0/*pLeafBuffer->GetIndices(0)*/, 0/*pLeafBuffer->m_Indices.m_nItems*/,
R_PRIMV_TRIANGLES, "LMapTexCoords", eBT_Static, 1, 0, NULL, NULL, false, false);
C3DEngine *pEng = (C3DEngine *)Get3DEngine();
m_arrLMData[nLod].m_pLMTCBuffer->SetChunk(pEng->m_pSHDefault,
0,pLeafBuffer->m_SecVertCount, 0,pLeafBuffer->m_Indices.m_nItems);
}

164
Cry3DEngine/Cry3DEngine.cpp Normal file
View File

@@ -0,0 +1,164 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: cry3dengine.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: Defines the DLL entry point, implements access to other modules
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
// init memory pool usage
#ifndef GAMECUBE
#ifndef _XBOX
//#if !defined(LINUX)
_ACCESS_POOL;
//#endif//LINUX
#endif //_XBOX
#endif
#include "3dengine.h"
#define MAX_ERROR_STRING 4096
//////////////////////////////////////////////////////////////////////
#include "StencilShadowConnectivity.h"
#include "StencilShadowConnectivityBuilder.h" // CStencilShadowConnectivityBuilder
#include "StencilShadowEdgeDetector.h" // CStencilShadowEdgeDetector
//////////////////////////////////////////////////////////////////////////
// Pointer to Global ISystem.
ISystem* GetISystem()
{
return Cry3DEngineBase::m_pSys;
}
//////////////////////////////////////////////////////////////////////////
#if !defined(GAMECUBE) && !defined(PS2) && !defined(_XBOX) && !defined(LINUX)
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )
{
return TRUE;
}
#endif
//#include <time.h>
I3DEngine * CreateCry3DEngine(ISystem * pSystem, const char * szInterfaceVersion)
{/*
__time64_t ltime1, ltime2;
_time64( &ltime1 );
int nElemNum = 100000*64/sizeof(float);
unsigned short * pShorts = new unsigned short[nElemNum];
float * pFloats = new float[nElemNum];
for(int t=0; t<1000; t++)
{
for(int i=0; i<nElemNum; i++)
{
pFloats[i] = 0.01f*pShorts[i];
}
}
_time64( &ltime2 );
float fTimeDif = float(ltime2 - ltime1);
delete [] pShorts;
delete [] pFloats;
char buff[32];
snprintf(buff,"%.2f",fTimeDif/1000);
MessageBox(0, buff, "aa", MB_OK);
return 0;
*/
#if !defined(LINUX)
if(strcmp(szInterfaceVersion,g3deInterfaceVersion))
pSystem->GetIConsole()->Exit("Error: CreateCry3DEngine(): 3dengine interface version error");
#endif
C3DEngine * p3DEngine = new C3DEngine(pSystem);
return p3DEngine;
}
void Cry3DEngineBase::UpdateLoadingScreen(const char *command,...)
{
if(command)
{
va_list arglist;
char buf[512];
va_start(arglist, command);
vsnprintf(buf, sizeof(buf), command, arglist);
va_end(arglist);
GetLog()->UpdateLoadingScreen(buf);
}
else
GetLog()->UpdateLoadingScreen(0);
}
void Cry3DEngineBase::UpdateLoadingScreenPlus(const char *command,...)
{
va_list arglist;
char buf[512];
va_start(arglist, command);
vsnprintf(buf, sizeof(buf), command, arglist);
va_end(arglist);
GetLog()->UpdateLoadingScreenPlus(buf);
}
//IRenderer *Cry3DEngineBase::GetRenderer()
//{ return GetSystem()->GetIRenderer(); }
//ITimer *Cry3DEngineBase::GetTimer()
//{ return GetSystem()->GetITimer(); }
//ILog *Cry3DEngineBase::GetLog()
//{ return GetSystem()->GetILog(); }
//IPhysicalWorld *Cry3DEngineBase::GetPhysicalWorld()
//{ return GetSystem()->GetIPhysicalWorld(); }
CCamera & Cry3DEngineBase::GetViewCamera()
{ return m_pSys->GetViewCamera(); }
float Cry3DEngineBase::GetCurTimeSec()
{ return (m_pSys->GetITimer()->GetCurrTime()); }
float Cry3DEngineBase::GetCurAsyncTimeSec()
{ return (m_pSys->GetITimer()->GetAsyncCurTime()); }
//IConsole * Cry3DEngineBase::GetConsole()
//{ return GetSystem()->GetIConsole(); }
//I3DEngine * Cry3DEngineBase::Get3DEngine()
//{ return GetSystem()->GetI3DEngine(); }
//CVars * Cry3DEngineBase::GetCVars()
//{ return ((C3DEngine*)GetSystem()->GetI3DEngine())->GetCVars(); }
CVisAreaManager * Cry3DEngineBase::GetVisAreaManager()
{ return ((C3DEngine*)m_pSys->GetI3DEngine())->GetVisAreaManager(); }
//////////////////////////////////////////////////////////////////////////
void Cry3DEngineBase::Warning( int flags,const char *file,const char *format,... )
{
va_list ArgList;
char szBuffer[MAX_ERROR_STRING];
va_start(ArgList, format);
vsprintf(szBuffer, format, ArgList);
va_end(ArgList);
// Call to validating warning of system.
m_pSys->Warning( VALIDATOR_MODULE_3DENGINE,VALIDATOR_WARNING,flags,file,"%s",szBuffer );
}
#include <CrtDebugStats.h>

View File

@@ -0,0 +1,749 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="Cry3DEngine"
ProjectGUID="{7D1FD0B0-A81D-4A7D-B399-37F8B9107D3F}"
SccProjectName="Perforce Project"
SccAuxPath=""
SccLocalPath="."
SccProvider="MSSCCI:Perforce SCM"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="D:\Games\FC\Bin32"
IntermediateDirectory="Debug"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
OptimizeForProcessor="0"
AdditionalIncludeDirectories="..\CryCommon"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;CRY3DENGINE_EXPORTS"
MinimalRebuild="TRUE"
BasicRuntimeChecks="0"
RuntimeLibrary="3"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
UsePrecompiledHeader="3"
WarningLevel="3"
Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
SuppressStartupBanner="TRUE"
GenerateDebugInformation="TRUE"
SubSystem="0"
ImportLibrary="$(IntDir)/$(TargetName).lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="D:\Games\FC\Bin32"
IntermediateDirectory="Release"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="3"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
FavorSizeOrSpeed="1"
OmitFramePointers="TRUE"
EnableFiberSafeOptimizations="FALSE"
OptimizeForProcessor="2"
AdditionalIncludeDirectories="..\CryCommon"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;CRY3DENGINE_EXPORTS"
StringPooling="TRUE"
RuntimeLibrary="2"
BufferSecurityCheck="FALSE"
EnableFunctionLevelLinking="FALSE"
EnableEnhancedInstructionSet="0"
UsePrecompiledHeader="3"
WarningLevel="3"
Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/Cry3DEngine.dll"
LinkIncremental="1"
GenerateDebugInformation="TRUE"
SubSystem="0"
OptimizeReferences="2"
EnableCOMDATFolding="2"
BaseAddress="0x20000000"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Profile|Win32"
OutputDirectory="D:\Games\FC\Bin32"
IntermediateDirectory="Profile"
ConfigurationType="2"
CharacterSet="2"
WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
Optimization="3"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
FavorSizeOrSpeed="1"
OmitFramePointers="TRUE"
EnableFiberSafeOptimizations="FALSE"
OptimizeForProcessor="2"
AdditionalIncludeDirectories="..\CryCommon"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;CRY3DENGINE_EXPORTS"
StringPooling="TRUE"
RuntimeLibrary="2"
BufferSecurityCheck="FALSE"
EnableFunctionLevelLinking="FALSE"
EnableEnhancedInstructionSet="0"
UsePrecompiledHeader="3"
WarningLevel="3"
Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="TRUE"
SubSystem="0"
OptimizeReferences="2"
EnableCOMDATFolding="2"
BaseAddress="0x30000000"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release64|Win32"
OutputDirectory="D:\Games\FC\Bin32"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="2"
CharacterSet="2"
WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/fp:fast
"
Optimization="2"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
FavorSizeOrSpeed="1"
OmitFramePointers="TRUE"
EnableFiberSafeOptimizations="FALSE"
OptimizeForProcessor="0"
AdditionalIncludeDirectories="..\CryCommon"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;CRY3DENGINE_EXPORTS;WIN64;_AMD64_"
StringPooling="TRUE"
RuntimeLibrary="2"
BufferSecurityCheck="FALSE"
EnableFunctionLevelLinking="FALSE"
EnableEnhancedInstructionSet="0"
UsePrecompiledHeader="3"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalOptions="/xxLTCG:PGI /xxxPGD:C:\MasterCD\Bin64\Cry3DEngine.pgd"
AdditionalDependencies="../CryCommon/fSinCos64.lib"
LinkIncremental="1"
GenerateDebugInformation="TRUE"
SubSystem="0"
OptimizeReferences="2"
EnableCOMDATFolding="2"
BaseAddress="0x20000000"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Debug64|Win32"
OutputDirectory="D:\Games\FC\Bin32"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
OptimizeForProcessor="0"
AdditionalIncludeDirectories="..\CryCommon"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;CRY3DENGINE_EXPORTS;WIN64;_AMD64_"
MinimalRebuild="TRUE"
BasicRuntimeChecks="0"
RuntimeLibrary="3"
BufferSecurityCheck="FALSE"
EnableFunctionLevelLinking="TRUE"
UsePrecompiledHeader="3"
WarningLevel="3"
Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalOptions="/MACHINE:AMD64"
AdditionalDependencies="../CryCommon/fSinCos64.lib"
LinkIncremental="2"
SuppressStartupBanner="TRUE"
GenerateDebugInformation="TRUE"
SubSystem="0"
ImportLibrary="$(IntDir)/$(TargetName).lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Ini Files"
Filter="">
</Filter>
<Filter
Name="CFGLoader"
Filter="">
<File
RelativePath="BaseObj.h">
</File>
<File
RelativePath="CryStaticModel.cpp">
</File>
<File
RelativePath="CryStaticModel.h">
</File>
<File
RelativePath="File.cpp">
</File>
<File
RelativePath="File.h">
</File>
<File
RelativePath="Geom.cpp">
</File>
<File
RelativePath="Geom.h">
</File>
<File
RelativePath="Helper.cpp">
</File>
<File
RelativePath="Helper.h">
</File>
<File
RelativePath="Light.cpp">
</File>
<File
RelativePath="Light.h">
</File>
<File
RelativePath="Meshidx.cpp">
</File>
<File
RelativePath="Node.cpp">
</File>
<File
RelativePath="Node.h">
</File>
</Filter>
<Filter
Name="StatObj"
Filter="">
<File
RelativePath="StatObj.h">
</File>
<File
RelativePath="StatObjCompiler.cpp">
</File>
<File
RelativePath="StatObjConstr.cpp">
</File>
<File
RelativePath="StatObjFar.cpp">
</File>
<File
RelativePath="StatObjLoad.cpp">
</File>
<File
RelativePath="StatObjPhys.cpp">
</File>
<File
RelativePath="StatObjRend.cpp">
</File>
<File
RelativePath="StatObjSerialize.cpp">
</File>
<File
RelativePath="StatObjShadow.cpp">
</File>
<File
RelativePath="StatObjShadowVolumes.cpp">
</File>
<File
RelativePath="StatObjStream.cpp">
</File>
</Filter>
<Filter
Name="Effects"
Filter="">
<Filter
Name="Decals"
Filter="">
<File
RelativePath="Decal.cpp">
</File>
<File
RelativePath="DecalManager.cpp">
</File>
<File
RelativePath="DecalManager.h">
</File>
</Filter>
<Filter
Name="Particles"
Filter="">
<File
RelativePath="particle.cpp">
</File>
<File
RelativePath="ParticleEffect.cpp">
</File>
<File
RelativePath="ParticleEffect.h">
</File>
<File
RelativePath="ParticleEmitter.cpp">
</File>
<File
RelativePath="ParticleEmitter.h">
</File>
<File
RelativePath="partman.cpp">
</File>
<File
RelativePath="partman.h">
</File>
<File
RelativePath="partpolygon.cpp">
</File>
<File
RelativePath="SpriteManager.cpp">
</File>
</Filter>
<Filter
Name="Rain"
Filter="">
<File
RelativePath="rain.cpp">
</File>
<File
RelativePath="rain.h">
</File>
</Filter>
<Filter
Name="Detail Objects"
Filter="">
<File
RelativePath="detail_grass.cpp">
</File>
<File
RelativePath="detail_grass.h">
</File>
</Filter>
</Filter>
<Filter
Name="Terrain"
Filter="">
<File
RelativePath="terrain.cpp">
</File>
<File
RelativePath="terrain.h">
</File>
<File
RelativePath="terrain_damage.cpp">
</File>
<File
RelativePath="terrain_det_tex.cpp">
</File>
<File
RelativePath="terrain_hmap.cpp">
</File>
<File
RelativePath="terrain_init.cpp">
</File>
<File
RelativePath="terrain_light.cpp">
</File>
<File
RelativePath="terrain_load.cpp">
</File>
<File
RelativePath="terrain_render.cpp">
</File>
<File
RelativePath="terrain_tex_pool.cpp">
</File>
<File
RelativePath="terran_edit.cpp">
</File>
<Filter
Name="Sector"
Filter="">
<File
RelativePath="terrain_sector.cpp">
</File>
<File
RelativePath="terrain_sector.h">
</File>
<File
RelativePath="terrain_sector_beach.cpp">
</File>
<File
RelativePath="terrain_sector_render.cpp">
</File>
<File
RelativePath="terrain_sector_tex.cpp">
</File>
</Filter>
</Filter>
<Filter
Name="Water"
Filter="">
<File
RelativePath="terrain_water.h">
</File>
<File
RelativePath="terrain_water_quad.cpp">
</File>
<File
RelativePath="WaterVolumes.cpp">
</File>
<File
RelativePath="WaterVolumes.h">
</File>
</Filter>
<Filter
Name="Vegetation"
Filter="">
<File
RelativePath="Vegetation.cpp">
</File>
<File
RelativePath="Vegetation.h">
</File>
</Filter>
<Filter
Name="Brush"
Filter="">
<File
RelativePath="Brush.cpp">
</File>
<File
RelativePath="Brush.h">
</File>
<File
RelativePath="BrushLM.cpp">
</File>
</Filter>
<Filter
Name="LightMaps"
Filter="">
<File
RelativePath="dds.h">
</File>
<File
RelativePath="LMSerializationManager2.cpp">
</File>
<File
RelativePath="LMSerializationManager2.h">
</File>
</Filter>
<Filter
Name="ObjManager"
Filter="">
<File
RelativePath="ObjMan.cpp">
</File>
<File
RelativePath="ObjMan.h">
</File>
<File
RelativePath="ObjManDraw.cpp">
</File>
<File
RelativePath="ObjManDrawEntity.cpp">
</File>
<File
RelativePath="ObjManFar.cpp">
</File>
<File
RelativePath="ObjManShadows.cpp">
</File>
<File
RelativePath="ObjManStreaming.cpp">
</File>
</Filter>
<Filter
Name="StencilShadows"
Filter="">
<File
RelativePath="IndoorShadowVolumes.h">
</File>
<File
RelativePath="IndoorVolumes.h">
</File>
<File
RelativePath="ShadowVolumeEdge.h">
</File>
<File
RelativePath="StencilShadowConnectivity.h">
</File>
<File
RelativePath="StencilShadowConnectivityBuilder.cpp">
</File>
<File
RelativePath="StencilShadowConnectivityBuilder.h">
</File>
<File
RelativePath="StencilShadowEdgeDetector.cpp">
</File>
<File
RelativePath="StencilShadowEdgeDetector.h">
</File>
</Filter>
<Filter
Name="3DEngine"
Filter="">
<File
RelativePath="3dEngine.cpp">
</File>
<File
RelativePath="3dEngine.h">
</File>
<File
RelativePath="3dEngineLight.cpp">
</File>
<File
RelativePath="3dEngineLoad.cpp">
</File>
<File
RelativePath="3dEngineRender.cpp">
</File>
<File
RelativePath="3dEngineScreenEffects.cpp">
</File>
<File
RelativePath="MatMan.cpp">
</File>
</Filter>
<Filter
Name="VisAreas"
Filter="">
<File
RelativePath="BasicArea.cpp">
</File>
<File
RelativePath="BasicArea.h">
</File>
<File
RelativePath="VisAreaMan.cpp">
</File>
<File
RelativePath="VisAreas.cpp">
</File>
<File
RelativePath="VisAreas.h">
</File>
</Filter>
<Filter
Name="CVars"
Filter="">
<File
RelativePath="cvars.cpp">
</File>
<File
RelativePath="cvars.h">
</File>
</Filter>
<Filter
Name="CBuffer"
Filter="">
<File
RelativePath="cbuffer.cpp">
</File>
<File
RelativePath="cbuffer.h">
</File>
</Filter>
<Filter
Name="Containers"
Filter="">
<File
RelativePath="Array2d.h">
</File>
</Filter>
<Filter
Name="Interfaces"
Filter="">
</Filter>
<File
RelativePath="Cry3DEngine.cpp">
</File>
<File
RelativePath="Cry3DEngineBase.h">
</File>
<File
RelativePath="LightMan.cpp">
</File>
<File
RelativePath="StdAfx.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="Profile|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="Release64|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="Debug64|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
</File>
<File
RelativePath="StdAfx.h">
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = "file:F:\\Crytek\\Cry3DEngine\\Cry3DEngine.vcproj"
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
}

View File

@@ -0,0 +1,85 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: cry3denginebase.h
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: Access to external stuff used by 3d engine. Most 3d engine classes
// are derived from this base class to access other interfaces
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#ifndef _Cry3DEngineBase_h_
#define _Cry3DEngineBase_h_
struct ISystem;
struct IRenderer;
struct ILog;
class IPhysicalWorld;
struct ITimer;
struct IConsole;
struct I3DEngine;
struct CVars;
struct CVisAreaManager;
struct Cry3DEngineBase
{
static ISystem * m_pSys;
static IRenderer * m_pRenderer;
static ITimer * m_pTimer;
static ILog * m_pLog;
static IPhysicalWorld * m_pPhysicalWorld;
static IConsole * m_pConsole;
static I3DEngine * m_p3DEngine;
static CVars * m_pCVars;
static ICryPak * m_pCryPak;
static int m_nRenderStackLevel;
static int m_dwRecursionDrawFlags[2];
static int m_nRenderFrameID;
static bool m_bProfilerEnabled;
static float m_fPreloadStartTime;
static int m_CpuFlags;
static double m_SecondsPerCycle;
static ESystemConfigSpec m_configSpec;
static ESystemConfigSpec m_LightConfigSpec;
static bool m_bIgnoreFakeMaterialsInCGF;
static bool m_bEditorMode;
static ISystem * GetSystem() { return m_pSys; }
static IRenderer * GetRenderer() { return m_pRenderer; }
static ITimer * GetTimer() { return m_pTimer; }
static ILog * GetLog() { return m_pLog; }
static IPhysicalWorld * GetPhysicalWorld() { return m_pPhysicalWorld;}
static IConsole * GetConsole() { return m_pConsole; }
static I3DEngine * Get3DEngine() { return m_p3DEngine; }
static CVars * GetCVars() { return m_pCVars; }
static CVisAreaManager* GetVisAreaManager();
static ICryPak * GetPak() { return m_pCryPak; }
static int GetFrameID() { return m_nRenderFrameID; };
CCamera & GetViewCamera() ;
float GetCurTimeSec();
float GetCurAsyncTimeSec();
void UpdateLoadingScreen(const char *command,...);
void UpdateLoadingScreenPlus(const char *command,...);
// Validator warning.
static void Warning( int flags,const char *file,const char *format,... );
CCObject * GetIdentityCCObject()
{
CCObject * pCCObject = GetRenderer()->EF_GetObject(true);
pCCObject->m_Matrix.SetIdentity();
return pCCObject;
}
};
#endif // _Cry3DEngineBase_h_

View File

@@ -0,0 +1,605 @@
<?xml version="1.0" encoding = "windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.00"
Name="Cry3DEngine_XBox"
SccProjectName="&quot;$/Game01/Cry3DEngine&quot;, HXRAAAAA"
SccAuxPath=""
SccLocalPath="."
SccProvider="MSSCCI:Microsoft Visual SourceSafe">
<Platforms>
<Platform
Name="Xbox"/>
</Platforms>
<Configurations>
<Configuration
Name="Release|Xbox"
OutputDirectory="Release_XBox"
IntermediateDirectory="Release_XBox"
ConfigurationType="4"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
ImproveFloatingPointConsistency="FALSE"
FavorSizeOrSpeed="1"
OmitFramePointers="TRUE"
AdditionalIncludeDirectories="..\CryCommon"
PreprocessorDefinitions="_XBOX;_LIB"
StringPooling="TRUE"
RuntimeLibrary="4"
EnableFunctionLevelLinking="TRUE"
UsePrecompiledHeader="3"
PrecompiledHeaderThrough="stdafx.h"
PrecompiledHeaderFile="$(IntDir)/Cry3DEngine.pch"
AssemblerListingLocation="$(IntDir)/"
ObjectFile="$(IntDir)/"
ProgramDataBaseFileName="$(IntDir)/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="TRUE"
DebugInformationFormat="2"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/$Cry3DEngine.lib"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
</Configuration>
<Configuration
Name="Profile|Xbox"
OutputDirectory="Profile"
IntermediateDirectory="Profile"
ConfigurationType="4"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
FavorSizeOrSpeed="1"
OmitFramePointers="TRUE"
AdditionalIncludeDirectories="..\CryCommon"
PreprocessorDefinitions="_XBOX;_LIB"
StringPooling="TRUE"
BufferSecurityCheck="FALSE"
UsePrecompiledHeader="3"
PrecompiledHeaderThrough="stdafx.h"
PrecompiledHeaderFile=".\Profile/Cry3DEngine.pch"
AssemblerListingLocation=".\Profile/"
ObjectFile=".\Profile/"
ProgramDataBaseFileName=".\Profile/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="TRUE"
DebugInformationFormat="3"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/$Cry3DEngine.lib"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
</Configuration>
<Configuration
Name="Debug|Xbox"
OutputDirectory="Debug_XBox"
IntermediateDirectory="Debug_XBox"
ConfigurationType="4"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\CryCommon"
PreprocessorDefinitions="_DEBUG;_XBOX;_LIB"
BasicRuntimeChecks="3"
RuntimeLibrary="5"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
UsePrecompiledHeader="3"
PrecompiledHeaderThrough="stdafx.h"
PrecompiledHeaderFile=".\Debug_XBox/Cry3DEngine.pch"
AssemblerListingLocation=".\Debug_XBox/"
ObjectFile=".\Debug_XBox/"
ProgramDataBaseFileName=".\Debug_XBox/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="TRUE"
DebugInformationFormat="4"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/$Cry3DEngine.lib"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
</Configuration>
</Configurations>
<Files>
<Filter
Name="CGF Loader"
Filter="">
<File
RelativePath=".\CryStaticModel.cpp">
</File>
<File
RelativePath=".\File.cpp">
</File>
<File
RelativePath=".\Meshidx.cpp">
</File>
<Filter
Name="Loader_h"
Filter="">
<File
RelativePath=".\CryStaticModel.h">
</File>
<File
RelativePath=".\File.h">
</File>
</Filter>
<Filter
Name="Chunks"
Filter="">
<File
RelativePath=".\Geom.cpp">
</File>
<File
RelativePath=".\Helper.cpp">
</File>
<File
RelativePath=".\Light.cpp">
</File>
<File
RelativePath=".\Node.cpp">
</File>
<Filter
Name="Chunks_h"
Filter="">
<File
RelativePath=".\BaseObj.h">
</File>
<File
RelativePath=".\Geom.h">
</File>
<File
RelativePath=".\Helper.h">
</File>
<File
RelativePath=".\Light.h">
</File>
<File
RelativePath=".\Node.h">
</File>
</Filter>
</Filter>
</Filter>
<Filter
Name="StatObj"
Filter="">
<File
RelativePath=".\StatObj.h">
</File>
<File
RelativePath=".\StatObjConstr.cpp">
</File>
<File
RelativePath=".\StatObjFar.cpp">
</File>
<File
RelativePath=".\StatObjPhys.cpp">
</File>
<File
RelativePath=".\StatObjRend.cpp">
</File>
<File
RelativePath="StatObjSerialize.cpp">
</File>
<File
RelativePath=".\StatObjShadow.cpp">
</File>
<File
RelativePath="StatObjShadowVolumes.cpp">
</File>
</Filter>
<Filter
Name="Terrain"
Filter="">
<File
RelativePath=".\terrain.cpp">
</File>
<File
RelativePath=".\terrain.h">
</File>
<File
RelativePath=".\terrain_damage.cpp">
</File>
<File
RelativePath=".\terrain_det_tex.cpp">
</File>
<File
RelativePath="terrain_hmap.cpp">
</File>
<File
RelativePath="terrain_init.cpp">
</File>
<File
RelativePath="terrain_light.cpp">
</File>
<File
RelativePath=".\terrain_load.cpp">
</File>
<File
RelativePath=".\terrain_render.cpp">
</File>
<File
RelativePath="terrain_tex_pool.cpp">
</File>
<File
RelativePath=".\terran_edit.cpp">
</File>
<Filter
Name="Sector"
Filter="">
<File
RelativePath=".\terrain_sector.cpp">
</File>
<File
RelativePath=".\terrain_sector.h">
</File>
<File
RelativePath=".\terrain_sector_beach.cpp">
</File>
<File
RelativePath=".\terrain_sector_render.cpp">
</File>
<File
RelativePath=".\terrain_sector_tex.cpp">
</File>
</Filter>
</Filter>
<Filter
Name="Objects Manager"
Filter="">
<File
RelativePath="LMSerializationManager.cpp">
</File>
<File
RelativePath="ObjMan.cpp">
</File>
<File
RelativePath="ObjMan.h">
</File>
<File
RelativePath="ObjManDraw.cpp">
</File>
<File
RelativePath="ObjManDrawEntity.cpp">
</File>
<File
RelativePath="ObjManFar.cpp">
</File>
<File
RelativePath="ObjManPhys.cpp">
</File>
<File
RelativePath="ObjManShadows.cpp">
</File>
<File
RelativePath="ObjManStreaming.cpp">
</File>
</Filter>
<Filter
Name="3DEngine"
Filter="">
<File
RelativePath=".\3dEngine.cpp">
</File>
<File
RelativePath=".\3dEngine.h">
</File>
<File
RelativePath="3dEngineLight.cpp">
</File>
<File
RelativePath=".\3dEngineLoad.cpp">
</File>
<File
RelativePath=".\3dEngineRender.cpp">
</File>
<File
RelativePath="3dEngineScreenEffects.cpp">
</File>
<File
RelativePath="cbuffer.cpp">
</File>
<File
RelativePath="cbuffer.h">
</File>
</Filter>
<Filter
Name="Effects"
Filter="">
<File
RelativePath=".\bflyes.cpp">
</File>
<File
RelativePath=".\bugs.cpp">
</File>
<File
RelativePath=".\detail_grass.cpp">
</File>
<File
RelativePath=".\rain.cpp">
</File>
<Filter
Name="Effects_h"
Filter="">
<File
RelativePath=".\bflyes.h">
</File>
<File
RelativePath=".\bugs.h">
</File>
<File
RelativePath=".\detail_grass.h">
</File>
<File
RelativePath=".\rain.h">
</File>
</Filter>
<Filter
Name="Particles"
Filter="">
<File
RelativePath=".\particle.cpp">
</File>
<File
RelativePath=".\partman.cpp">
</File>
<File
RelativePath=".\partman.h">
</File>
<File
RelativePath="partpolygon.cpp">
</File>
<File
RelativePath="partspray.cpp">
</File>
</Filter>
<Filter
Name="Decals"
Filter="">
<File
RelativePath="Decal.cpp">
</File>
<File
RelativePath="DecalManager.cpp">
</File>
<File
RelativePath="DecalManager.h">
</File>
</Filter>
</Filter>
<Filter
Name="Ini Files"
Filter="">
<File
RelativePath="C:\MasterCD\gamecfg.lua">
</File>
<File
RelativePath="C:\MasterCD\log.txt">
</File>
<File
RelativePath="C:\MasterCD\playercfg.lua">
</File>
<File
RelativePath="C:\MasterCD\systemcfg.lua">
</File>
<File
RelativePath="C:\MasterCD\systemcfgoverride.lua">
</File>
</Filter>
<Filter
Name="CVars"
Filter="">
<File
RelativePath=".\cvars.cpp">
</File>
<File
RelativePath=".\cvars.h">
</File>
</Filter>
<Filter
Name="Stencil Shadows"
Filter="">
<File
RelativePath="StencilShadowConnectivity.h">
</File>
<File
RelativePath="StencilShadowConnectivityBuilder.cpp">
</File>
<File
RelativePath="StencilShadowConnectivityBuilder.h">
</File>
<File
RelativePath="StencilShadowEdgeDetector.cpp">
</File>
<File
RelativePath="StencilShadowEdgeDetector.h">
</File>
<Filter
Name="other"
Filter="">
<File
RelativePath="IndoorShadowVolumes.h">
</File>
<File
RelativePath="IndoorVolumes.h">
</File>
<File
RelativePath="ShadowVolumeEdge.h">
</File>
</Filter>
</Filter>
<Filter
Name="Interfaces"
Filter="">
<File
RelativePath="..\CryCommon\I3DEngine.h">
</File>
<File
RelativePath="..\crycommon\IEntityRenderState.h">
</File>
<File
RelativePath="..\crycommon\IStatObj.h">
</File>
</Filter>
<Filter
Name="Water"
Filter="">
<File
RelativePath="WaterVolumes.cpp">
</File>
<File
RelativePath="WaterVolumes.h">
</File>
<File
RelativePath=".\terrain_water.h">
</File>
<File
RelativePath="terrain_water_quad.cpp">
</File>
</Filter>
<Filter
Name="VisAreas"
Filter="">
<File
RelativePath="BasicArea.cpp">
</File>
<File
RelativePath="BasicArea.h">
</File>
<File
RelativePath="VisAreaMan.cpp">
</File>
<File
RelativePath="VisAreas.cpp">
</File>
<File
RelativePath="VisAreas.h">
</File>
</Filter>
<Filter
Name="Brush"
Filter="">
<File
RelativePath="Brush.cpp">
</File>
<File
RelativePath="Brush.h">
</File>
<File
RelativePath="BrushLM.cpp">
</File>
<File
RelativePath="LMSerializationManager.h">
</File>
</Filter>
<Filter
Name="LightMan"
Filter="">
<File
RelativePath="LightLoad.cpp">
</File>
<File
RelativePath="LightMan.cpp">
</File>
<File
RelativePath="LightMan.h">
</File>
</Filter>
<Filter
Name="Containers"
Filter="">
<File
RelativePath="Array2d.h">
</File>
<File
RelativePath="..\CryCommon\list2.h">
</File>
</Filter>
<Filter
Name="Vegetation"
Filter="">
<File
RelativePath="Vegetation.cpp">
</File>
<File
RelativePath="Vegetation.h">
</File>
</Filter>
<File
RelativePath=".\Cry3DEngine.cpp">
</File>
<File
RelativePath=".\Cry3DEngineBase.h">
</File>
<File
RelativePath="MatMan.cpp">
</File>
<File
RelativePath=".\StdAfx.cpp">
<FileConfiguration
Name="Release|Xbox">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="Profile|Xbox">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Xbox">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
</File>
<File
RelativePath=".\StdAfx.h">
</File>
<File
RelativePath=".\todo.txt">
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = "file:F:\\Crytek\\Cry3DEngine\\Cry3DEngine_XBox.vcproj"
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
}

View File

@@ -0,0 +1,498 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: crystaticmodel.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: load cgf file
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "CryStaticModel.h"
#include "baseobj.h"
#include "node.h"
#include "geom.h"
#include "helper.h"
#include "light.h"
#include "file.h"
CryStaticModel::CryStaticModel()
{
memset( this,0,sizeof(*this) );
}
CryStaticModel::~CryStaticModel()
{
for( int i=0; i<m_nNewObjs; i++)
{
CNodeCGF * pNode = (CNodeCGF*)m_ppNewObjs[i];
delete pNode;
}
if(m_ppNewObjs)
free(m_ppNewObjs);
m_ppNewObjs=0;
}
void CryStaticModel::LoadMaterials(CXFile*f, int pos)
{
if(f->FSeek(pos,SEEK_SET))
return;
CHUNK_HEADER ch;
int res = f->FRead(&ch,1,sizeof(ch));
if (ch.ChunkVersion == MTL_CHUNK_DESC_0746::VERSION)
{
f->FSeek(pos,SEEK_SET);
MTL_CHUNK_DESC_0746 chunk;
int res=f->FRead(&chunk,1,sizeof(chunk));
if(res!=sizeof(chunk))
return;
MAT_ENTITY me;
memset(&me, 0, sizeof(MAT_ENTITY));
me.opacity = 1.0f;
me.alpharef = 0;
me.m_New = 2;
strcpy(me.name, chunk.name);
switch (chunk.MtlType)
{
case MTL_STANDARD:
me.IsStdMat = true;
me.col_d = chunk.col_d;
me.col_a = chunk.col_a;
me.col_s = chunk.col_s;
me.specLevel = chunk.specLevel;
me.specShininess = chunk.specShininess*100;
me.opacity = chunk.opacity;
me.selfIllum = chunk.selfIllum;
me.flags = chunk.flags;
if (me.flags & MTLFLAG_CRYSHADER)
me.alpharef = chunk.alphaTest;
me.Dyn_Bounce = chunk.Dyn_Bounce;
me.Dyn_StaticFriction = chunk.Dyn_StaticFriction;
me.Dyn_SlidingFriction = chunk.Dyn_SlidingFriction;
/* //Timur[10/24/2001]
strcpy(me.map_a, chunk.tex_a.name);
strcpy(me.map_d, chunk.tex_d.name);
strcpy(me.map_o, chunk.tex_o.name);
strcpy(me.map_b, chunk.tex_b.name);
strcpy(me.map_s, chunk.tex_s.name);
strcpy(me.map_g, chunk.tex_g.name);
strcpy(me.map_c, chunk.tex_c.name);
strcpy(me.map_e, chunk.tex_rl.name);
strcpy(me.map_rr, chunk.tex_rr.name);
strcpy(me.map_det, chunk.tex_det.name);
*/
me.map_a = chunk.tex_a;
me.map_d = chunk.tex_d;
me.map_o = chunk.tex_o;
me.map_b = chunk.tex_b;
me.map_s = chunk.tex_s;
me.map_g = chunk.tex_g;
me.map_detail = chunk.tex_fl;
me.map_e = chunk.tex_rl;
me.map_subsurf = chunk.tex_subsurf;
me.map_displ = chunk.tex_det;
me.nChildren = chunk.nChildren;
m_lstMaterials.Add(me);
break;
/* case MTL_MULTI:
me.IsStdMat = 0;
me.nChildren = chunk.nChildren;
me.children = new int [chunk.nChildren];
int res=f->FRead(me.children,sizeof(int),chunk.nChildren);
if (res != chunk.nChildren)
return;*/
}
}
else
if (ch.ChunkVersion == MTL_CHUNK_DESC_0745::VERSION)
{
f->FSeek(pos,SEEK_SET);
MTL_CHUNK_DESC_0745 chunk;
int res=f->FRead(&chunk,1,sizeof(chunk));
if(res!=sizeof(chunk))
return;
MAT_ENTITY me;
memset(&me, 0, sizeof(MAT_ENTITY));
me.opacity = 1.0f;
me.alpharef = 0;
me.m_New = 1;
strcpy(me.name, chunk.name);
switch (chunk.MtlType)
{
case MTL_STANDARD:
me.IsStdMat = true;
me.col_d = chunk.col_d;
me.col_a = chunk.col_a;
me.col_s = chunk.col_s;
me.specLevel = chunk.specLevel;
me.specShininess = chunk.specShininess*100;
me.opacity = chunk.opacity;
me.selfIllum = chunk.selfIllum;
me.flags = chunk.flags;
me.Dyn_Bounce = chunk.Dyn_Bounce;
me.Dyn_StaticFriction = chunk.Dyn_StaticFriction;
me.Dyn_SlidingFriction = chunk.Dyn_SlidingFriction;
/* //Timur[10/24/2001]
strcpy(me.map_a, chunk.tex_a.name);
strcpy(me.map_d, chunk.tex_d.name);
strcpy(me.map_o, chunk.tex_o.name);
strcpy(me.map_b, chunk.tex_b.name);
strcpy(me.map_s, chunk.tex_s.name);
strcpy(me.map_g, chunk.tex_g.name);
strcpy(me.map_c, chunk.tex_c.name);
strcpy(me.map_e, chunk.tex_rl.name);
strcpy(me.map_rr, chunk.tex_rr.name);
strcpy(me.map_det, chunk.tex_det.name);
*/
me.map_a = chunk.tex_a;
me.map_d = chunk.tex_d;
me.map_o = chunk.tex_o;
me.map_b = chunk.tex_b;
me.map_s = chunk.tex_s;
me.map_g = chunk.tex_g;
me.map_detail = chunk.tex_c;
me.map_e = chunk.tex_rl;
me.map_subsurf = chunk.tex_subsurf;
me.map_displ = chunk.tex_det;
me.nChildren = chunk.nChildren;
m_lstMaterials.Add(me);
break;
/* case MTL_MULTI:
me.IsStdMat = 0;
me.nChildren = chunk.nChildren;
me.children = new int [chunk.nChildren];
int res=f->FRead(me.children,sizeof(int),chunk.nChildren);
if (res != chunk.nChildren)
return;*/
}
}
else
if (ch.ChunkVersion == MTL_CHUNK_DESC_0744::VERSION)
{
f->FSeek(pos,SEEK_SET);
MTL_CHUNK_DESC_0744 chunk;
int res=f->FRead(&chunk,1,sizeof(chunk));
if(res!=sizeof(chunk))
return;
MAT_ENTITY me;
memset(&me, 0, sizeof(MAT_ENTITY));
me.opacity = 1.0f;
me.alpharef = 0;
strcpy(me.name, chunk.name);
switch (chunk.MtlType)
{
case MTL_STANDARD:
me.IsStdMat = true;
me.col_d = chunk.col_d;
me.col_a = chunk.col_a;
me.col_s = chunk.col_s;
me.Dyn_Bounce = chunk.Dyn_Bounce;
me.Dyn_StaticFriction = chunk.Dyn_StaticFriction;
me.Dyn_SlidingFriction = chunk.Dyn_SlidingFriction;
strcpy(me.map_d.name, chunk.tex_d.name);
strcpy(me.map_o.name, chunk.tex_o.name);
strcpy(me.map_b.name, chunk.tex_b.name);
me.nChildren = chunk.nChildren;
m_lstMaterials.Add(me);
break;
case MTL_MULTI:
me.IsStdMat = 0;
me.nChildren = chunk.nChildren;
me.m_pMaterialChildren = new int [chunk.nChildren];//leak
int res=f->FRead(me.m_pMaterialChildren,sizeof(int),chunk.nChildren);
if (res != chunk.nChildren)
return;
}
}
}
bool CryStaticModel::OnLoadgeom(char * FileName, const char * szGeomName, bool bLoadMats, bool bKeepInLocalSpace)
{
CXFile * f = new CXFile(GetSystem()->GetIPak());
// preload all data
if(!f->FLoad(FileName))
{
delete f; return 0;
}
//read the file header
FILE_HEADER fh;
int res = f->FRead(&fh,sizeof(fh),1);
if(res!=1)
return 0;
if(fh.Version != GeomFileVersion)
{
f->FClose(); delete f; f=0;
Warning(0,FileName,"CGF file version error: %s", FileName);
return 0;
}
if(fh.FileType != FileType_Geom)
{
f->FClose(); delete f; f=0;
Warning(0,FileName,"CGF file version error: %s", FileName);
return 0;
}
//read the chunk table
f->FSeek(fh.ChunkTableOffset,SEEK_SET);
int n_chunks=100000;
res = f->FRead(&n_chunks,sizeof(n_chunks),1);
if(res!=1)
return 0;
if(n_chunks>=100000)
{
f->FClose(); delete f; f=0;
Warning(0,FileName,"CGF File corrupted: %s, (n_chunks>=100000)", FileName);
return 0;
}
CHUNK_HEADER * pChunks;
pChunks=(CHUNK_HEADER *)malloc(sizeof(CHUNK_HEADER)*n_chunks);
assert(pChunks);
res = f->FRead(pChunks,sizeof(CHUNK_HEADER),n_chunks);
if(res!=n_chunks)
return 0;
/////////////////////////////////////////////////////////////////////////////
// Create and load objects
/////////////////////////////////////////////////////////////////////////////
m_ppNewObjs = (CBaseObj **)malloc(n_chunks*sizeof(CBaseObj*));
memset(m_ppNewObjs,0,n_chunks*sizeof(CBaseObj*));
assert(m_ppNewObjs);
m_nNewObjs=0;
int nGeomToLoadID = -1;
int i;
for(i=0;i<n_chunks;i++)
{
switch(pChunks[i].ChunkType)
{
case ChunkType_Node:
m_ppNewObjs[m_nNewObjs]=new CNodeCGF();
break;
case ChunkType_Mesh:
if(!szGeomName || nGeomToLoadID == i)
m_ppNewObjs[m_nNewObjs]=new CGeom();
break;
case ChunkType_Helper:
m_ppNewObjs[m_nNewObjs]=new CHelper();
break;
case ChunkType_Light:
m_ppNewObjs[m_nNewObjs]=new CLight();
break;
case ChunkType_Mtl:
if(bLoadMats)
LoadMaterials(f,pChunks[i].FileOffset);
break;
}
if(m_ppNewObjs[m_nNewObjs])
{
m_ppNewObjs[m_nNewObjs]->Load(f,pChunks[i].FileOffset);
// find chunk id of needed geom
if(pChunks[i].ChunkType == ChunkType_Node)
if(szGeomName && strcmp(szGeomName,((CNodeCGF*)m_ppNewObjs[m_nNewObjs])->m_Chunk.name)==0)
nGeomToLoadID = ((CNodeCGF*)m_ppNewObjs[m_nNewObjs])->m_Chunk.ObjectID;
m_nNewObjs++;
}
}
//Do pointer and name list bindings
for(i=0;i<m_nNewObjs;i++)
{
if(!m_ppNewObjs[i])
continue;
m_ppNewObjs[i]->Bind(m_ppNewObjs, m_nNewObjs);
}
f->FClose(); delete f; f=0;
if(pChunks)
free(pChunks);
pChunks=0;
/////////////////////////////////////////////////////////////////////////////
// Make objects
/////////////////////////////////////////////////////////////////////////////
list2<NAME_ENTITY> lstOtherNames;
for( i=0; i<m_nNewObjs; i++)
{
CNodeCGF * pNode = (CNodeCGF*)m_ppNewObjs[i];
if(pNode->m_ChunkHeader.ChunkType != ChunkType_Node)
continue;
// make list of mesh names
NAME_ENTITY geomname;
strcpy(geomname.name, pNode->m_Chunk.name);
lstOtherNames.Add(geomname);
if(!pNode->m_pObj)
continue;
if(pNode->m_pObj->m_nUsers>1)
{
Warning( 0,FileName,"Loading of instances from cgf not supported, geom skipped: %s, %s",FileName, pNode->GetName() );
}
// Accumulate this and all parent nodes transformations
// TODO: get rid of the obsolete CryMatrix here
//CHANGED_BY_IVO
//CryMatrix matNodeMatrix = pNode->m_Chunk.tm;
Matrix44 matNodeMatrix = pNode->m_Chunk.tm;
for(CNodeCGF * pCurNode = pNode->m_pParent; pCurNode; pCurNode = pCurNode->m_pParent)
//CHANGED_BY_IVO
//matNodeMatrix = matNodeMatrix * (CryMatrix&)(pCurNode->m_Chunk.tm);
matNodeMatrix = matNodeMatrix * (pCurNode->m_Chunk.tm);
if(pNode->m_pObj->m_ChunkHeader.ChunkType == ChunkType_Mesh)
if(pNode->m_pObj->m_nUsers<=1)
{ // geoms
// make list of mesh names
NAME_ENTITY geomname;
strcpy(geomname.name, pNode->m_Chunk.name);
m_lstGeomNames.Add(geomname);
lstOtherNames.DeleteLast();
CGeom * pGeom = (CGeom*)pNode->m_pObj;
// transform geometry from this node space into CGFs space
if(!bKeepInLocalSpace)
for(int v=0; v<pGeom->m_Chunk.nVerts; v++)
{
//CHANGED_BY_IVO
//pGeom->m_pVertices[v].p = matNodeMatrix*pGeom->m_pVertices[v].p;
//pGeom->m_pVertices[v].n = matNodeMatrix/pGeom->m_pVertices[v].n;
pGeom->m_pVertices[v].p = matNodeMatrix.TransformPointOLD(pGeom->m_pVertices[v].p);
pGeom->m_pVertices[v].n = matNodeMatrix.TransformVectorOLD(pGeom->m_pVertices[v].n);
}
if(!szGeomName || strcmp(pNode->GetName(),szGeomName)==0)
m_lstGeoms.Add(pGeom);
}
if(pNode->m_pObj->m_ChunkHeader.ChunkType == ChunkType_Light)
{ // make light
CLight * pLight = (CLight*)pNode->m_pObj;
LightInstance inst;
memcpy(&inst.Chunk,&pLight->m_Chunk,sizeof(LIGHT_CHUNK_DESC));
inst.Chunk = pLight->m_Chunk;
if(bKeepInLocalSpace)
//inst.vPos.Set(&pNode->m_Chunk.pos.x);
inst.vPos.Set(pNode->m_Chunk.pos[0],pNode->m_Chunk.pos[1],pNode->m_Chunk.pos[2]);
else
//CHANGED_BY_IVO
//inst.vPos = Vec3d(matNodeMatrix.data[3]);
inst.vPos = matNodeMatrix.GetTranslationOLD();
if(!pNode->m_pParent)
assert( IsEquivalent(pNode->m_Chunk.pos,inst.vPos,VEC_EPSILON) );
strncpy(inst.szName,pNode->m_Chunk.name, sizeof(inst.szName));
// load proj texture
if(inst.Chunk.szLightImage[0])
{
inst.pLightImage = GetRenderer()->EF_LoadTexture(inst.Chunk.szLightImage, FT_CLAMP, FT2_FORCECUBEMAP, eTT_Cubemap);
if (!inst.pLightImage->IsTextureLoaded())
inst.pLightImage = NULL;
}
else
inst.pLightImage = NULL;
m_lstLights.Add(inst);
}
if(pNode->m_pObj->m_ChunkHeader.ChunkType == ChunkType_Helper)
{ // make helper
CHelper * pHelper = (CHelper*)pNode->m_pObj;
HelperInstance inst;
inst.Chunk = pHelper->m_Chunk;
if(bKeepInLocalSpace)
inst.tMat.SetIdentity();
else
//CHANGED_BY_IVO
//inst.tMat = Matrix(matNodeMatrix.matrix);
inst.tMat = matNodeMatrix;
/*
if(!pNode->m_pParent)
{
assert(inst.vPos == pNode->m_Chunk.pos);
float dot = inst.qRot.Dot(pNode->m_Chunk.rot);
dot=dot;
}
*/
strncpy(inst.szName,pNode->m_Chunk.name, sizeof(inst.szName));
m_lstHelpers.Add(inst);
}
}
m_lstGeomNames.AddList (lstOtherNames);
return 1;
}
/*
CHelperInstance * CryStaticModel::GetHelper(const char * name)
{
for(int i=0; i<m_Helpers.Count(); i++)
{
if(!strcmp(m_Helpers[i].name,name))
return &m_Helpers[i];
}
return 0;
}
*/
// this timer measures the time spent in the CGF Loader
//double g_dTimeLoadCGF;

View File

@@ -0,0 +1,71 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: crystaticmodel.h
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: cgf file loader
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#ifndef CryStaticModel_H
#define CryStaticModel_H
class CBaseObj;
class CGeom;
#include "../Cry3DEngine/Cry3DEngineBase.h"
struct LightInstance
{
LIGHT_CHUNK_DESC Chunk;
Vec3d vPos;
char szName[64];
struct ITexPic * pLightImage;
};
struct HelperInstance
{
HELPER_CHUNK_DESC Chunk;
// Vec3d vPos;
// CryQuat qRot;
char szName[64];
Matrix44 tMat;
};
class CXFile;
struct CryStaticModel : public Cry3DEngineBase
{
CryStaticModel();
~CryStaticModel();
char m_FileName[256];
list2<CGeom*> m_lstGeoms;
list2<MAT_ENTITY> m_lstMaterials;
list2<NAME_ENTITY> m_lstGeomNames;
list2<LightInstance> m_lstLights;
list2<HelperInstance> m_lstHelpers;
bool OnLoadgeom(char * filename, const char * geom_name, bool bLoadMats, bool bKeepInLocalSpace);
float m_fBoundingRadius;
float m_fCenterZ;
void LoadMaterials(CXFile*f, int pos);
int m_nNewObjs;
CBaseObj ** m_ppNewObjs;
/// static CXFile * m_pXFile;
};
// timers that are used for precision very low cost profiling of load times
// this timer measures the time spent in the CGF Loader
//extern double g_dTimeLoadCGF;
#endif // CryStaticModel_H

307
Cry3DEngine/Decal.cpp Normal file
View File

@@ -0,0 +1,307 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: decals.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: draw, create decals on the world
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "DecalManager.h"
#include "3dengine.h"
#include "objman.h"
void CDecal::Process(bool & active, IRenderer * pIRenderer, const float fCurTime, C3DEngine * p3DEngine, IShader * pShader, CCamera* pCamera, float fSortOffset)
{
// todo: take entity orientation into account
m_nDynLMask = ((I3DEngine*)p3DEngine)->GetLightMaskFromPosition(m_pDecalOwner ? m_pDecalOwner->GetPos()+m_vPos : m_vPos, m_fSize);
uint nDynLightMask = m_nDynLMask;
// render StatObj decal
if(m_pStatObj)
{
Render3DObject();
return;
}
// Get decal alpha from life time
float fLifeTime = m_fLifeEndTime - fCurTime;
float fAlpha = fLifeTime*2;
if(fAlpha > 1.f)
fAlpha = 1.f;
else if(fAlpha<0)
{ // kill
active=0;
pIRenderer->DeleteLeafBuffer(m_pBigDecalLeafBuffer);
m_pBigDecalLeafBuffer=0;
return;
}
float fSizeK;
if(m_fGrowTime)
fSizeK = min(1.f, cry_sqrtf((fCurTime - m_fLifeBeginTime)/m_fGrowTime));
else
fSizeK = 1.f;
// if there is owner - transform decal from owner space into world space
if(m_pDecalOwner)
{
// if there is information about decal geometry - render complex decal and project texture on it
if(m_pBigDecalLeafBuffer && m_pBigDecalLeafBuffer->m_Indices.m_nItems)
{
// setup transformation
CCObject * pObj = pIRenderer->EF_GetObject(true);
pObj->m_SortId = fSortOffset;
Matrix44 objMat;
if(!m_pDecalOwner->GetEntityStatObj(m_nDecalOwnerComponentId, &objMat))
{
// GetLog()->Log("Error: CDecal::Process: m_nDecalOwnerComponentId is out of range: %d", m_nDecalOwnerComponentId);
assert(0);
return;
}
pObj->m_Matrix = objMat;
pObj->m_ObjFlags |= FOB_TRANS_MASK;
p3DEngine->CheckDistancesToLightSources(nDynLightMask,m_pDecalOwner->GetPos(),m_pDecalOwner->GetRenderRadius(),m_pDecalOwner);
// pIRenderer->DrawBall(objMat.GetTranslation(),1) ;
pObj->m_DynLMMask = nDynLightMask;
// somehow it's need's to be twice bigger to be same as simple decals
float fSize2 = m_fSize*fSizeK*2.f;///m_pDecalOwner->GetScale();
if(fSize2<0.05f)
return;
// todo: transform basis into world space ?
// setup texgen
// S component
m_arrBigDecalCustomData[0] = m_vUp.x/fSize2;
m_arrBigDecalCustomData[1] = m_vUp.y/fSize2;
m_arrBigDecalCustomData[2] = m_vUp.z/fSize2;
float D0 =
m_arrBigDecalCustomData[0]*m_vPos.x +
m_arrBigDecalCustomData[1]*m_vPos.y +
m_arrBigDecalCustomData[2]*m_vPos.z;
m_arrBigDecalCustomData[3] = -D0+0.5f;
// T component
m_arrBigDecalCustomData[4] = m_vRight.x/fSize2;
m_arrBigDecalCustomData[5] = m_vRight.y/fSize2;
m_arrBigDecalCustomData[6] = m_vRight.z/fSize2;
float D1 =
m_arrBigDecalCustomData[4]*m_vPos.x +
m_arrBigDecalCustomData[5]*m_vPos.y +
m_arrBigDecalCustomData[6]*m_vPos.z;
m_arrBigDecalCustomData[7] = -D1+0.5f;
// pass attenuation info
m_arrBigDecalCustomData[8] = m_vPos.x;
m_arrBigDecalCustomData[9] = m_vPos.y;
m_arrBigDecalCustomData[10]= m_vPos.z;
m_arrBigDecalCustomData[11]= m_fSize;
if(m_pDecalOwner->GetEntityRenderType() == eERType_Vegetation)
{
CObjManager * pObjManager = ((C3DEngine*)p3DEngine)->GetObjManager();
CStatObjInst * pStatObjInst = (CStatObjInst *)m_pDecalOwner;
CStatObj * pBody = pObjManager->m_lstStaticTypes[pStatObjInst->m_nObjectTypeID].GetStatObj();
assert(pObjManager && pStatObjInst && pBody);
if(pObjManager && pStatObjInst && pBody && pStatObjInst->m_fFinalBending)
{
pBody->SetupBending(pObj,pStatObjInst->m_fFinalBending);
}
}
// draw complex decal using new indices and original object vertices
m_pBigDecalLeafBuffer->SetRECustomData(m_arrBigDecalCustomData, 0, fAlpha);
m_pBigDecalLeafBuffer->AddRenderElements(pObj);
}
else
{
// transform decal in software from owner space into world space and render as quad
Matrix44 objMat;
IStatObj * pEntObject = m_pDecalOwner->GetEntityStatObj(m_nDecalOwnerComponentId, &objMat);
assert(pEntObject);
Vec3d vPos = objMat.TransformPointOLD(m_vPos);
Vec3d vRight = objMat.TransformVectorOLD(m_vRight*m_fSize/m_pDecalOwner->GetScale());
Vec3d vUp = objMat.TransformVectorOLD(m_vUp*m_fSize/m_pDecalOwner->GetScale());
CDLight * pStrongestLightForTranspGeom = NULL;
p3DEngine->CheckDistancesToLightSources(nDynLightMask,vPos,m_fSize,0,1,&pStrongestLightForTranspGeom,1);
UCol uCol;
if(pStrongestLightForTranspGeom && pStrongestLightForTranspGeom->m_fRadius)
{
float fAtten = min(1.f,pStrongestLightForTranspGeom->m_fRadius/pStrongestLightForTranspGeom->m_Origin.GetDistance(m_vWSPos));
float fDot = max(0,(pStrongestLightForTranspGeom->m_Origin-m_vWSPos).normalized().Dot(m_vFront));
uCol.bcolor[0] = uchar(min(255.f,355.f*fDot*fAtten*pStrongestLightForTranspGeom->m_Color.r));
uCol.bcolor[1] = uchar(min(255.f,355.f*fDot*fAtten*pStrongestLightForTranspGeom->m_Color.g));
uCol.bcolor[2] = uchar(min(255.f,355.f*fDot*fAtten*pStrongestLightForTranspGeom->m_Color.b));
}
else
uCol.dcolor = 0;
uCol.bcolor[3] = fastftol_positive(fAlpha*255);
p3DEngine->GetObjManager()->AddPolygonToRenderer( m_nTexId, pShader, nDynLightMask,
vRight*fSizeK, vUp*fSizeK, uCol, ParticleBlendType_AlphaBased, m_vAmbient, vPos,
0,0,0,0,fSortOffset,0,0,
m_pDecalOwner->GetEntityRenderType() == eERType_Vegetation ? (CStatObjInst*)m_pDecalOwner : NULL);
}
}
else if(!m_bOnTheGround)
{ // draw small world space decal untransformed
CDLight * pStrongestLightForTranspGeom = NULL;
p3DEngine->CheckDistancesToLightSources(nDynLightMask,m_vPos,m_fSize,0,1,&pStrongestLightForTranspGeom,1);
UCol uCol;
if(pStrongestLightForTranspGeom && pStrongestLightForTranspGeom->m_fRadius)
{
float fAtten = min(1.f,pStrongestLightForTranspGeom->m_fRadius/pStrongestLightForTranspGeom->m_Origin.GetDistance(m_vWSPos));
float fDot = max(0,(pStrongestLightForTranspGeom->m_Origin-m_vWSPos).normalized().Dot(m_vFront));
uCol.bcolor[0] = uchar(min(255.f,355.f*fDot*fAtten*pStrongestLightForTranspGeom->m_Color.r));
uCol.bcolor[1] = uchar(min(255.f,355.f*fDot*fAtten*pStrongestLightForTranspGeom->m_Color.g));
uCol.bcolor[2] = uchar(min(255.f,355.f*fDot*fAtten*pStrongestLightForTranspGeom->m_Color.b));
}
else
uCol.dcolor = 0;
uCol.bcolor[3] = fastftol_positive(fAlpha*255);
p3DEngine->GetObjManager()->AddPolygonToRenderer( m_nTexId, pShader, nDynLightMask,
m_vRight*m_fSize*fSizeK, m_vUp*m_fSize*fSizeK, uCol, ParticleBlendType_AlphaBased, m_vAmbient, m_vPos,
0,0,0,0,fSortOffset);
}
/*{
Vec3d vPos = m_vPos + (m_pDecalOwner ? m_pDecalOwner->GetPos() : Vec3d(0,0,0));
pIRenderer->Draw3dBBox(vPos,vPos+m_vFront);
}*/
// process life time and disable decal when needed
// m_fLifeTime -= fFrameTime;
if(m_fLifeEndTime<fCurTime)
{
active=0;
pIRenderer->DeleteLeafBuffer(m_pBigDecalLeafBuffer);
m_pBigDecalLeafBuffer=0;
}
}
void CDecal::Render3DObject()
{
// draw
if(m_pStatObj)
{
Vec3d vAngles = m_vFront;
vAngles=ConvertVectorToCameraAngles(vAngles);
vAngles.x+=90;
//Matrix mat,mat1;
//mat.Identity();
//mat=GetRotationZYX44(-gf_DEGTORAD*vAngles)*mat; //NOTE: angles in radians and negated
//mat1.Identity();
//mat1=GetTranslationMat(m_vPos)*mat1;
//mat = mat * mat1;
//OPTIMISED_BY_IVO
Matrix44 mat = Matrix34::CreateRotationXYZ( Deg2Rad(vAngles), m_vPos );
mat = GetTransposed44(mat); //TODO: remove this after E3 and use Matrix34 instead of Matrix44
SRendParams rParms;
rParms.pMatrix = &mat;
rParms.dwFObjFlags |= FOB_TRANS_MASK;
m_pStatObj->Render(rParms,Vec3(zero),0);
}
}
void CDecal::DrawBigDecalOnTerrain(C3DEngine * p3DEngine, IRenderer * pIRenderer, float fCurrTime)
{
// Get decal alpha from life time
float fLifeTime = m_fLifeEndTime - fCurrTime;
float fAlpha = fLifeTime*2;
if(fAlpha > 1.f)
fAlpha = 1.f;
else if(fAlpha<0)
return;
Vec3d vColor = p3DEngine->GetWorldColor();
pIRenderer->SetMaterialColor(vColor.x,vColor.y,vColor.z,fAlpha);
// calc area
int x1=int(m_vPos.x-m_fSize*0.85)/CTerrain::GetHeightMapUnitSize()*CTerrain::GetHeightMapUnitSize();
int y1=int(m_vPos.y-m_fSize*0.85)/CTerrain::GetHeightMapUnitSize()*CTerrain::GetHeightMapUnitSize();
int x2=int(m_vPos.x+CTerrain::GetHeightMapUnitSize()+m_fSize*0.85)/CTerrain::GetHeightMapUnitSize()*CTerrain::GetHeightMapUnitSize();
int y2=int(m_vPos.y+CTerrain::GetHeightMapUnitSize()+m_fSize*0.85)/CTerrain::GetHeightMapUnitSize()*CTerrain::GetHeightMapUnitSize();
float fSizeK;
if(m_fGrowTime)
fSizeK = min(1.f, cry_sqrtf((fCurrTime - m_fLifeBeginTime)/m_fGrowTime));
else
fSizeK = 1.f;
float fRadius = m_fSize*fSizeK*2.f;
if(fRadius<0.05f)
return;
// limits
if(x1<0) x1=0;
if(y1<0) y1=0;
if(x2>=CTerrain::GetTerrainSize()) x2=CTerrain::GetTerrainSize();
if(y2>=CTerrain::GetTerrainSize()) y2=CTerrain::GetTerrainSize();
// fill buffer and draw
list2<struct_VERTEX_FORMAT_P3F_TEX2F> verts;
struct_VERTEX_FORMAT_P3F_TEX2F tmp;
Vec3d vOffset(0,0,0);
if(((C3DEngine*)p3DEngine)->GetObjManager())
vOffset = (pIRenderer->GetCamera().GetPos()-m_vPos)*0.01f*((C3DEngine*)p3DEngine)->GetObjManager()->m_fZoomFactor;
for(int x=x1; x<x2; x+=CTerrain::GetHeightMapUnitSize())
{
verts.Clear();
for(int y=y1; y<=y2; y+=CTerrain::GetHeightMapUnitSize())
{
tmp.xyz.x = (float)x;
tmp.xyz.y = (float)y;
tmp.xyz.z = p3DEngine->GetTerrainZ(x,y)+0.07f;
tmp.st[0] = (((float)x)-m_vPos.x)/fRadius+0.5f;
tmp.st[1] = 1.f-((((float)y)-m_vPos.y)/fRadius+0.5f);
tmp.xyz+=vOffset;
verts.Add(tmp);
tmp.xyz.x = (float)(x+CTerrain::GetHeightMapUnitSize());
tmp.xyz.y = (float)y;
tmp.xyz.z = p3DEngine->GetTerrainZ((x+CTerrain::GetHeightMapUnitSize()),y)+0.07f;
tmp.st[0] = (((float)(x+CTerrain::GetHeightMapUnitSize()))-m_vPos.x)/fRadius+0.5f;
tmp.st[1] = 1.f-((((float)y)-m_vPos.y)/fRadius+0.5f);
tmp.xyz+=vOffset;
verts.Add(tmp);
}
if(verts.Count())
{
pIRenderer->SetTexture(m_nTexId);
pIRenderer->SetTexClampMode(true);
pIRenderer->DrawTriStrip(&(CVertexBuffer (&verts[0].xyz.x,VERTEX_FORMAT_P3F_TEX2F)),verts.Count());
}
}
}

View File

@@ -0,0 +1,715 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: decals.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: draw, create decals on the world
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "DecalManager.h"
#include "3dengine.h"
#include <IStatObj.h>
#include "ObjMan.h"
#define COMPLEX_DECAL_MIN_SIZE 0.1f
CDecalManager::CDecalManager(C3DEngine * p3DEngine)
{
m_nCurDecal = 0;
memset(m_arrbActiveDecals,0,sizeof(m_arrbActiveDecals));
m_p3DEngine = p3DEngine;
m_pShader_ParticleLight = GetRenderer()->EF_LoadShader("ParticleLight", eSH_World, EF_SYSTEM);
m_pShader_Decal_VP = GetRenderer()->EF_LoadShader("Decal_VP", eSH_World, EF_SYSTEM);
m_pShader_Decal_2D_VP = GetRenderer()->EF_LoadShader("Decal_2D_VP", eSH_World, EF_SYSTEM);
}
// called from the renderer, draws immideately
void CDecalManager::DrawBigDecalsOnTerrain()
{
if(!GetCVars()->e_decals)
return;
//GetRenderer()->ResetToDefault();
GetRenderer()->SetState(GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA);
GetRenderer()->SetColorOp(eCO_MODULATE, eCO_MODULATE, eCA_Texture|(eCA_Constant<<3), eCA_Texture|(eCA_Constant<<3));
GetRenderer()->SetCullMode(R_CULL_DISABLE);
Vec3d vColor = GetSystem()->GetI3DEngine()->GetWorldColor();//*
GetRenderer()->SetMaterialColor(vColor.x,vColor.y,vColor.z,1);
float fCurrTime = GetTimer()->GetCurrTime();
for(int i=0; i<DECAL_COUNT; i++)
if(m_arrbActiveDecals[i])
{
if(!m_arrDecals[i].m_pStatObj && m_arrDecals[i].m_bOnTheGround)
if( GetViewCamera().IsSphereVisibleFast( Sphere(m_arrDecals[i].m_vPos, m_arrDecals[i].m_fSize)) )
m_arrDecals[i].DrawBigDecalOnTerrain(m_p3DEngine, GetRenderer(), fCurrTime);
}
//GetRenderer()->ResetToDefault();
}
bool CDecalManager::AdjustDecalPosition( CryEngineDecalInfo & DecalInfo, bool bMakeFatTest )
{
Matrix44 objMat, objMatInv;
int nPartID = DecalInfo.nPartID;
IStatObj * pEntObject = DecalInfo.pDecalOwner->GetEntityStatObj(nPartID, &objMat, true);
while(!pEntObject && nPartID<16)
{ // find first visible entity component
pEntObject = DecalInfo.pDecalOwner->GetEntityStatObj(++nPartID, &objMat, true);
}
if(!pEntObject || !pEntObject->GetLeafBuffer()|| nPartID>=16)
return false;
// transform decal into object space
objMatInv = objMat;
objMatInv.Invert44();
// put into normal object space hit direction of projection
Vec3d vObjSpaceHitDirection = objMatInv.TransformVectorOLD(DecalInfo.vHitDirection);
// put into position object space hit position
Vec3d vObjSpacePos = objMatInv.TransformPointOLD(DecalInfo.vPos);
// get decal directions
Vec3d vRi(0,0,0), vUp(0,0,0);
if(fabs(vObjSpaceHitDirection.Dot(Vec3d(0,0,1)))>0.999f)
{ // horiz surface
vRi = Vec3d(0,1,0);
vUp = Vec3d(1,0,0);
}
else
{
vRi = vObjSpaceHitDirection.Cross(Vec3d(0,0,1));
vRi.Normalize();
vUp = vObjSpaceHitDirection.Cross(vRi);
vUp.Normalize();
}
vRi*=DecalInfo.fSize;
vUp*=DecalInfo.fSize;
Vec3d vObjSpaceOutPos(0,0,0), vObjSpaceOutNormal(0,0,0), vTmp;
CLeafBuffer * pLB = pEntObject->GetLeafBuffer();
if( pLB && pLB->m_pSecVertBuffer && pLB->m_SecVertCount &&
RayLeafBufferIntersection(pLB, vObjSpacePos, vObjSpaceHitDirection*0.1f, vObjSpaceOutPos, vObjSpaceOutNormal) )
{ // now check that none of decal sides will not fly in the air
Vec3d vDecalNormal = vObjSpaceOutNormal*DecalInfo.fSize;
if( !bMakeFatTest || (
RayLeafBufferIntersection(pLB, vObjSpaceOutPos+vUp, -vDecalNormal, vTmp, vTmp) &&
RayLeafBufferIntersection(pLB, vObjSpaceOutPos-vUp, -vDecalNormal, vTmp, vTmp) &&
RayLeafBufferIntersection(pLB, vObjSpaceOutPos+vRi, -vDecalNormal, vTmp, vTmp) &&
RayLeafBufferIntersection(pLB, vObjSpaceOutPos-vRi, -vDecalNormal, vTmp, vTmp) ))
{
DecalInfo.vPos = objMat.TransformPointOLD(vObjSpaceOutPos);
DecalInfo.vNormal = objMat.TransformVectorOLD(vObjSpaceOutNormal);
return true;
}
}
return false;
}
struct HitPosInfo {
HitPosInfo() { memset(this,0,sizeof(HitPosInfo)); }
Vec3d vPos,vNormal;
float fDistance;
};
int __cdecl CDecalManager__CmpHitPos(const void* v1, const void* v2)
{
HitPosInfo * p1 = (HitPosInfo*)v1;
HitPosInfo * p2 = (HitPosInfo*)v2;
if(p1->fDistance > p2->fDistance)
return 1;
else if(p1->fDistance < p2->fDistance)
return -1;
return 0;
}
bool CDecalManager::RayLeafBufferIntersection(CLeafBuffer * pLeafBuffer, const Vec3d & vInPos, const Vec3d & vInDir, Vec3d & vOutPos, Vec3d & vOutNormal)
{
// get position offset and stride
int nPosStride = 0;
byte * pPos = pLeafBuffer->GetPosPtr(nPosStride, 0, true);
// get indices
ushort *pInds = pLeafBuffer->GetIndices(0);
int nInds = pLeafBuffer->m_Indices.m_nItems;
assert(nInds%3 == 0);
HitPosInfo arrResult[16];
memset(arrResult,0,sizeof(arrResult));
int nResultCount=0;
// find faces
for(int i=0; i<nInds && nResultCount<16; i+=3)
{
// get tri vertices
Vec3d v0 = *((Vec3d*)&pPos[nPosStride*pInds[i+0]]);
Vec3d v1 = *((Vec3d*)&pPos[nPosStride*pInds[i+1]]);
Vec3d v2 = *((Vec3d*)&pPos[nPosStride*pInds[i+2]]);
// make line triangle intersection
Vec3d vResPos(0,0,0);
if( Intersect::Lineseg_Triangle(Lineseg(vInPos+vInDir, vInPos-vInDir), v0, v1, v2, vResPos) ||
Intersect::Lineseg_Triangle(Lineseg(vInPos-vInDir, vInPos+vInDir), v0, v1, v2, vResPos) )
{
arrResult[nResultCount].vPos = vResPos;
arrResult[nResultCount].vNormal = (v1-v0).Cross(v2-v0);
arrResult[nResultCount].vNormal.Normalize();
arrResult[nResultCount].fDistance = (vInPos-vInDir).GetDistance(vResPos);
nResultCount++;
}
}
if(nResultCount)
{ // return closest to the shooter
qsort(&arrResult, nResultCount, sizeof(arrResult[0]), CDecalManager__CmpHitPos);
vOutPos = arrResult[0].vPos;
vOutNormal = arrResult[0].vNormal;
}
return nResultCount!=0;
}
void CDecalManager::Spawn( CryEngineDecalInfo DecalInfo, float fMaxViewDistance, CTerrain * pTerrain )
{
Vec3d vCamPos = GetViewCamera().GetPos();
// DecalInfo.fLifeTime = 1000000000;
// DecalInfo.fSize = .5f;
// DecalInfo.m_fGrowTime = 4.f;
// DecalInfo.nPartID = -1;
// do not spawn if too far
float fZoom = m_p3DEngine->GetObjManager() ? m_p3DEngine->GetObjManager()->m_fZoomFactor : 1.f;
float fDecalDistance = L1Distance2D(DecalInfo.vPos, vCamPos);
if( fDecalDistance>fMaxViewDistance || fDecalDistance*fZoom>DecalInfo.fSize*ENTITY_DECAL_DIST_FACTOR*3.f )
return;
/* if(DecalInfo.pDecalOwner && DecalInfo.pDecalOwner->GetEntityRenderType() == eERType_Vegetation)
{
CStatObjInst * pStatObjInst = (CStatObjInst*)DecalInfo.pDecalOwner;
if(pStatObjInst->m_fFinalBending)
return; // do not spawn on bendable vegetations
}*/
// project decal to visible geoemtry
if(DecalInfo.bAdjustPos && DecalInfo.nPartID>=0 && DecalInfo.pDecalOwner && !AdjustDecalPosition( DecalInfo, DecalInfo.fSize<=COMPLEX_DECAL_MIN_SIZE ))
return;
// clamp all decal textures
GetRenderer()->SetTexture(DecalInfo.nTid);
GetRenderer()->SetTexClampMode(true);
// don't go crazy
if(DecalInfo.fSize > 4)
DecalInfo.fSize = 4;
if(DecalInfo.fSize > 1 && GetCVars()->e_decals_neighbor_max_life_time)
{ // force near decals to fade faster
float fCurrTime = GetTimer()->GetCurrTime();
for(int i=0; i<DECAL_COUNT; i++)
if(m_arrbActiveDecals[i])
{
if(m_arrDecals[i].m_vWSPos.GetDistance(DecalInfo.vPos) < m_arrDecals[i].m_fWSSize+DecalInfo.fSize)
if((m_arrDecals[i]).m_fLifeBeginTime < fCurrTime-0.1f)
if(m_arrDecals[i].m_fLifeEndTime > fCurrTime+GetCVars()->e_decals_neighbor_max_life_time)
m_arrDecals[i].m_fLifeEndTime = fCurrTime+GetCVars()->e_decals_neighbor_max_life_time;
}
}
// loop position in array
if(m_nCurDecal>=DECAL_COUNT)
m_nCurDecal=0;
// free old LB
GetRenderer()->DeleteLeafBuffer(m_arrDecals[m_nCurDecal].m_pBigDecalLeafBuffer);
m_arrDecals[m_nCurDecal].m_pBigDecalLeafBuffer=0;
// just in case
DecalInfo.vNormal.Normalize();
bool bBigDecalOnTheGround = false;
// remember object we need to follow
m_arrDecals[m_nCurDecal].m_nDecalOwnerComponentId = DecalInfo.nPartID;
m_arrDecals[m_nCurDecal].m_vWSPos = DecalInfo.vPos;
m_arrDecals[m_nCurDecal].m_fWSSize = DecalInfo.fSize;
// If owner entity and object is specified - make decal use entity geometry
float fObjScale = 1.f;
if(DecalInfo.pDecalOwner && DecalInfo.nPartID>=0 && DecalInfo.fSize>COMPLEX_DECAL_MIN_SIZE)
{ // get object pointer
Matrix44 objMat;
IStatObj * pEntObject = DecalInfo.pDecalOwner->GetEntityStatObj(DecalInfo.nPartID, &objMat);
if(pEntObject)
{
CLeafBuffer * pSourceLeafBuffer = pEntObject->GetLeafBuffer();
// transform decal into object space
objMat.Invert44();
// put into normal object space hit direction of projection
DecalInfo.vNormal = -objMat.TransformVectorOLD(DecalInfo.vHitDirection);
// put into position object space hit position
DecalInfo.vPos = objMat.TransformPointOLD(DecalInfo.vPos);
// find object scale
if(DecalInfo.pDecalOwner->GetEntityRenderType()==eERType_Vegetation)
fObjScale = DecalInfo.pDecalOwner->GetScale();
else
{
Vec3d vTest(0,0,1.f);
vTest = objMat.TransformVectorOLD(vTest);
fObjScale = 1.f/vTest.len();
}
if(fObjScale<0.01f)
return;
// transform size into object space
DecalInfo.fSize/=fObjScale;
// make decal geometry
m_arrDecals[m_nCurDecal].m_pBigDecalLeafBuffer = MakeBigDecalLeafBuffer(pSourceLeafBuffer, DecalInfo.vPos,
DecalInfo.fSize, DecalInfo.vNormal, DecalInfo.nTid);
if(!m_arrDecals[m_nCurDecal].m_pBigDecalLeafBuffer)
return; // no geometry found
ITexPic * pTexPic = GetRenderer()->EF_GetTextureByID(DecalInfo.nTid);
if(pTexPic)
{
pTexPic->SetFilter(FILTER_LINEAR);
pTexPic->SetClamp(true);
}
}
else
{
Warning( 0,0,"CDecalManager::Spawn: nPartID points to empty object");
return;
}
}
else if(DecalInfo.pDecalOwner &&
(!DecalInfo.pDecalOwner->IsStatic() || DecalInfo.pDecalOwner->GetEntityRenderType() == eERType_Vegetation) &&
DecalInfo.nPartID>=0)
{ // transform decal from world space into entity space
Matrix44 objMat;
IStatObj * pEntObject = DecalInfo.pDecalOwner->GetEntityStatObj(DecalInfo.nPartID, &objMat);
assert(pEntObject);
objMat.Invert44();
DecalInfo.vNormal = objMat.TransformVectorOLD(DecalInfo.vNormal);
DecalInfo.vNormal.Normalize();
DecalInfo.vPos = objMat.TransformPointOLD(DecalInfo.vPos);
// find object scale
if(DecalInfo.pDecalOwner->GetEntityRenderType()==eERType_Vegetation)
fObjScale = DecalInfo.pDecalOwner->GetScale();
else
{
Vec3d vTest(0,0,1.f);
vTest = objMat.TransformVectorOLD(vTest);
fObjScale = 1.f/vTest.len();
}
ITexPic * pTexPic = GetRenderer()->EF_GetTextureByID(DecalInfo.nTid);
if(pTexPic)
{
pTexPic->SetFilter(FILTER_LINEAR);
pTexPic->SetClamp(true);
}
}
else
{
if(DecalInfo.fSize>COMPLEX_DECAL_MIN_SIZE && !DecalInfo.pDecalOwner &&
(DecalInfo.vPos.z-pTerrain->GetZApr(DecalInfo.vPos.x,DecalInfo.vPos.y))<DecalInfo.fSize)
{
int nUnitSize = CTerrain::GetHeightMapUnitSize();
int x1 = int(DecalInfo.vPos.x-DecalInfo.fSize)/nUnitSize*nUnitSize-nUnitSize;
int x2 = int(DecalInfo.vPos.x+DecalInfo.fSize)/nUnitSize*nUnitSize+nUnitSize;
int y1 = int(DecalInfo.vPos.y-DecalInfo.fSize)/nUnitSize*nUnitSize-nUnitSize;
int y2 = int(DecalInfo.vPos.y+DecalInfo.fSize)/nUnitSize*nUnitSize+nUnitSize;
for(int x=x1; x<=x2; x+=CTerrain::GetHeightMapUnitSize())
for(int y=y1; y<=y2; y+=CTerrain::GetHeightMapUnitSize())
if(pTerrain->GetHoleSafe(x,y))
return;
bBigDecalOnTheGround = true;
ITexPic * pTexPic = GetRenderer()->EF_GetTextureByID(DecalInfo.nTid);
if(pTexPic)
{
pTexPic->SetFilter(FILTER_LINEAR);
pTexPic->SetClamp(true);
}
}
DecalInfo.pDecalOwner = NULL;
}
DecalInfo.vNormal.Normalize();
// spawn
m_arrDecals[m_nCurDecal].m_vPos = DecalInfo.vPos;
m_arrDecals[m_nCurDecal].m_vPos += DecalInfo.vNormal*0.01f/fObjScale;
m_arrDecals[m_nCurDecal].m_bOnTheGround = bBigDecalOnTheGround;
if(fabs(DecalInfo.vNormal.Dot(Vec3d(0,0,1)))>0.999f)
{ // horiz surface
m_arrDecals[m_nCurDecal].m_vRight = Vec3d(0,1,0);
m_arrDecals[m_nCurDecal].m_vUp = Vec3d(1,0,0);
}
else
{
m_arrDecals[m_nCurDecal].m_vRight = DecalInfo.vNormal.Cross(Vec3d(0,0,1));
m_arrDecals[m_nCurDecal].m_vRight.Normalize();
m_arrDecals[m_nCurDecal].m_vUp = DecalInfo.vNormal.Cross(m_arrDecals[m_nCurDecal].m_vRight);
m_arrDecals[m_nCurDecal].m_vUp.Normalize();
}
/*
// check that decal will look ok here
if(!DecalInfo.pDecalOwner && DecalInfo.fSize<=COMPLEX_DECAL_MIN_SIZE)
{
ray_hit hit;
float fSize = DecalInfo.fSize*2;
if(GetPhysicalWorld()->RayWorldIntersection(
DecalInfo.vPos - DecalInfo.vNormal*fSize + m_arrDecals[m_nCurDecal].m_vUp*fSize, DecalInfo.vNormal*fSize*2,
ent_all, rwi_stop_at_pierceable,&hit,1)
&& GetPhysicalWorld()->RayWorldIntersection(
DecalInfo.vPos - DecalInfo.vNormal*fSize - m_arrDecals[m_nCurDecal].m_vUp*fSize, DecalInfo.vNormal*fSize*2,
ent_all, rwi_stop_at_pierceable,&hit,1)
&& GetPhysicalWorld()->RayWorldIntersection(
DecalInfo.vPos - DecalInfo.vNormal*fSize + m_arrDecals[m_nCurDecal].m_vRight*fSize, DecalInfo.vNormal*fSize*2,
ent_all, rwi_stop_at_pierceable,&hit,1)
&& GetPhysicalWorld()->RayWorldIntersection(
DecalInfo.vPos - DecalInfo.vNormal*fSize - m_arrDecals[m_nCurDecal].m_vRight*fSize, DecalInfo.vNormal*fSize*2,
ent_all, rwi_stop_at_pierceable,&hit,1))
{
int t=0; // ok
}
else
return; // position is bad
}
*/
// rotate vectors
AngleAxis rotation(DecalInfo.fAngle,DecalInfo.vNormal);
m_arrDecals[m_nCurDecal].m_vRight = rotation*m_arrDecals[m_nCurDecal].m_vRight;
m_arrDecals[m_nCurDecal].m_vUp = rotation*m_arrDecals[m_nCurDecal].m_vUp;
m_arrDecals[m_nCurDecal].m_vFront = DecalInfo.vNormal;
m_arrDecals[m_nCurDecal].m_fSize = DecalInfo.fSize;
m_arrDecals[m_nCurDecal].m_fLifeEndTime = GetTimer()->GetCurrTime() + DecalInfo.fLifeTime*GetCVars()->e_decals_life_time_scale;
m_arrDecals[m_nCurDecal].m_nTexId = DecalInfo.nTid;
m_arrDecals[m_nCurDecal].m_fAngle = DecalInfo.fAngle;
m_arrDecals[m_nCurDecal].m_pStatObj = DecalInfo.pStatObj;
m_arrDecals[m_nCurDecal].m_vAmbient = Get3DEngine()->GetAmbientColorFromPosition(DecalInfo.vPos);
m_arrDecals[m_nCurDecal].m_pDecalOwner = DecalInfo.pDecalOwner;
m_arrDecals[m_nCurDecal].m_fGrowTime = DecalInfo.m_fGrowTime;
m_arrDecals[m_nCurDecal].m_fLifeBeginTime = GetTimer()->GetCurrTime();
if(DecalInfo.pStatObj)
{
DecalInfo.pStatObj->RegisterUser();
CDecal tmp;
tmp.m_vPos = DecalInfo.vPos;
tmp.m_vFront = DecalInfo.vNormal;
tmp.m_nTexId = DecalInfo.nTid;
tmp.m_fSize = DecalInfo.fSize;
m_LightHoles.Add(tmp);
}
m_arrbActiveDecals[m_nCurDecal] = true;
m_nCurDecal++;
}
void CDecalManager::SubmitLightHolesToRenderer()
{
if(!this)
return;
for(int i=0; i<m_LightHoles.Count(); i++)
GetRenderer()->EF_SetLightHole(m_LightHoles[i].m_vPos,
m_LightHoles[i].m_vFront, m_LightHoles[i].m_nTexId, m_LightHoles[i].m_fSize);
m_LightHoles.Clear();
}
void CDecalManager::Render()
{
FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE );
if(!GetCVars()->e_decals || !m_p3DEngine->GetObjManager() || m_p3DEngine->GetCurrentLightSpec() < 1)
return;
CCamera * pCamera = &GetViewCamera();
Vec3d vCamPos = pCamera->GetPos();
float fCurrTime = GetTimer()->GetCurrTime();
IRenderer * pIRenderer = GetRenderer();
CObjManager * pObjManager = m_p3DEngine->GetObjManager();
float fZoom = m_p3DEngine->GetObjManager()->m_fZoomFactor;
float fWaterLevel = m_p3DEngine->GetWaterLevel();
// draw
for(int i=0; i<DECAL_COUNT; i++)
if(m_arrbActiveDecals[i])
{
CDecal * pDecal = &m_arrDecals[i];
if(L1Distance2D(vCamPos, pDecal->m_vWSPos)*fZoom < pDecal->m_fWSSize*ENTITY_DECAL_DIST_FACTOR)
{
float fSortOffset = pObjManager->GetSortOffset(pDecal->m_vWSPos,vCamPos,fWaterLevel);
pDecal->Process(m_arrbActiveDecals[i], pIRenderer, fCurrTime, m_p3DEngine, m_pShader_ParticleLight, pCamera, fSortOffset);
}
}
}
void CDecalManager::OnEntityDeleted(IEntityRender * pEntityRender)
{
/* if(pEntityRender && pEntityRender->GetEntityRenderType()!=eERType_Unknown)
{ // remove all decals, can happend only during editing or level unloading
memset(m_arrbActiveDecals,0,sizeof(m_arrbActiveDecals));
return;
}
*/
// remove decals of this entity
for(int i=0; i<DECAL_COUNT; i++)
if(m_arrbActiveDecals[i])
{
if(m_arrDecals[i].m_pDecalOwner == pEntityRender)
{
assert(pEntityRender->GetEntityRS());
m_arrbActiveDecals[i] = false;
if(m_arrDecals[i].m_pBigDecalLeafBuffer)
{
GetRenderer()->DeleteLeafBuffer(m_arrDecals[i].m_pBigDecalLeafBuffer);
m_arrDecals[i].m_pBigDecalLeafBuffer=0;
}
m_arrDecals[i].m_pDecalOwner = 0;
}
}
}
void CDecalManager::FillBigDecalIndices(CLeafBuffer * pLeafBuffer, Vec3d vPos, float fRadius, Vec3d vProjDir, list2<ushort> * plstIndices)
{
// get position offset and stride
int nPosStride = 0, nNormStride = 0;
byte * pPos = pLeafBuffer->GetPosPtr(nPosStride, 0, true);
byte * pNorm = pLeafBuffer->GetNormalPtr(nNormStride, 0, true);
ushort *pInds = pLeafBuffer->GetIndices(0);
int nInds = pLeafBuffer->m_Indices.m_nItems;
assert(nInds%3 == 0);
plstIndices->Clear();
vProjDir.Normalize();
// Plane plane = GetPlane(vProjDir,vPos);
// fill decal indices
for(int i=0; i<nInds; i+=3)
{
// get tri vertices
Vec3d v0 = *((Vec3d*)&pPos[nPosStride*pInds[i+0]]);
Vec3d v1 = *((Vec3d*)&pPos[nPosStride*pInds[i+1]]);
Vec3d v2 = *((Vec3d*)&pPos[nPosStride*pInds[i+2]]);
// get tri normals
Vec3d n0 = *((Vec3d*)&pNorm[nNormStride*pInds[i+0]]);
Vec3d n1 = *((Vec3d*)&pNorm[nNormStride*pInds[i+1]]);
Vec3d n2 = *((Vec3d*)&pNorm[nNormStride*pInds[i+2]]);
// find bbox
Vec3d vBoxMin = v0; vBoxMin.CheckMin(v1); vBoxMin.CheckMin(v2);
Vec3d vBoxMax = v0; vBoxMax.CheckMax(v1); vBoxMax.CheckMax(v2);
if(vProjDir.IsZero())
{ // explo mode
// get dir to triangle
// Vec3d vCenter = (v0+v1+v2)*0.33333f;
// test the face
float fDot0 = (vPos-v0).Dot(n0);
float fDot1 = (vPos-v1).Dot(n1);
float fDot2 = (vPos-v2).Dot(n2);
float fTest = -0.15f;
if(fDot0 < fTest && fDot1 < fTest && fDot2 < fTest)
continue;
}
else
{
// get triangle normal
Vec3d vNormal = (v1-v0).Cross(v2-v0);
vNormal.Normalize();
// test the face
if(vNormal.Dot(vProjDir)<0)
continue;
}
if(Overlap::Sphere_AABB(Sphere(vPos, fRadius), AABB(vBoxMin,vBoxMax)))
{
plstIndices->Add(pInds[i+0]);
plstIndices->Add(pInds[i+1]);
plstIndices->Add(pInds[i+2]);
}
}
}
CLeafBuffer * CDecalManager::MakeBigDecalLeafBuffer(CLeafBuffer * pSourceLeafBuffer, Vec3d vPos, float fRadius, Vec3d vProjDir, int nTexID)
{
if(!pSourceLeafBuffer || pSourceLeafBuffer->m_SecVertCount==0)
return 0;
// make indices of this decal
list2<ushort> lstIndices;
if(pSourceLeafBuffer && pSourceLeafBuffer->m_pSecVertBuffer && pSourceLeafBuffer->m_SecVertCount)
FillBigDecalIndices(pSourceLeafBuffer, vPos, fRadius, vProjDir, &lstIndices);
if(!lstIndices.Count())
return 0;
// make fake vert buffer with one vertex // todo: remove this
list2<struct_VERTEX_FORMAT_P3F_COL4UB> EmptyVertBuffer;
EmptyVertBuffer.Add(struct_VERTEX_FORMAT_P3F_COL4UB());
CLeafBuffer * pLeafBuffer = GetRenderer()->CreateLeafBufferInitialized(
EmptyVertBuffer.GetElements(), EmptyVertBuffer.Count(), VERTEX_FORMAT_P3F_COL4UB,
lstIndices.GetElements(), lstIndices.Count(),
R_PRIMV_TRIANGLES, "BigDecal", eBT_Static, 1, nTexID);
pLeafBuffer->SetVertexContainer(pSourceLeafBuffer);
IShader * pShader = vProjDir.IsZero() ? m_pShader_Decal_VP : m_pShader_Decal_2D_VP;
pLeafBuffer->SetChunk(pShader, 0, pSourceLeafBuffer->m_SecVertCount, 0, lstIndices.Count());
pLeafBuffer->SetShader(pShader,nTexID);
return pLeafBuffer;
}
/*
CLeafBuffer * CDecalManager::MakeBigDecalLeafBuffer(CLeafBuffer * pSourceLeafBuffer, Vec3d vPos, float fRadius, Vec3d vProjDir, int nTexID)
{
if(!pSourceLeafBuffer || pSourceLeafBuffer->m_SecVertCount==0)
return 0;
// make indices of this decal
list2<ushort> lstIndices;
if(pSourceLeafBuffer && pSourceLeafBuffer->m_pSecVertBuffer && pSourceLeafBuffer->m_SecVertCount)
FillBigDecalIndices(pSourceLeafBuffer, vPos, fRadius, vProjDir, &lstIndices);
if(!lstIndices.Count())
return 0;
// make fake vert buffer with one vertex // todo: remove this
list2<struct_VERTEX_FORMAT_P3F_N> VertBuffer;
VertBuffer.PreAllocate(pSourceLeafBuffer->m_SecVertCount);
int nPosStride=0, nNormStride=0;
void * pPos = pSourceLeafBuffer->GetPosPtr(nPosStride);
void * pNorm = pSourceLeafBuffer->GetPosPtr(nNormStride);
for(int i=0; i<pSourceLeafBuffer->m_SecVertCount; i++)
{
struct_VERTEX_FORMAT_P3F_N vert;
vert.xyz = *(Vec3d*)((uchar*)pPos+nPosStride*i);
vert.normal = *(Vec3d*)((uchar*)pNorm+nNormStride*i);
vert.normal = vert.normal*5;
VertBuffer.Add(vert);
}
CLeafBuffer * pLeafBuffer = GetRenderer()->CreateLeafBufferInitialized(
VertBuffer.GetElements(), VertBuffer.Count(), VERTEX_FORMAT_P3F_N,
lstIndices.GetElements(), lstIndices.Count(),
R_PRIMV_TRIANGLES, "BigDecal", eBT_Static, 1, nTexID);
pLeafBuffer->SetChunk(m_pShader_Decal_VP, 0, pSourceLeafBuffer->m_SecVertCount, 0, lstIndices.Count());
pLeafBuffer->SetShader(m_pShader_Decal_VP,nTexID);
return pLeafBuffer;
}
*/
void CDecalManager::GetMemoryUsage(ICrySizer*pSizer)
{
pSizer->Add (*this);
pSizer->AddContainer (m_LightHoles);
}
void CDecalManager::DeleteDecalsInRange( Vec3d vBoxMin, Vec3d vBoxMax, bool bDeleteBigTerrainDecals )
{
for(int i=0; i<DECAL_COUNT; i++)
if(m_arrbActiveDecals[i] && !m_arrDecals[i].m_bOnTheGround)
{
if(!m_arrDecals[i].m_pDecalOwner &&
m_arrDecals[i].m_vPos.x<vBoxMax.x &&
m_arrDecals[i].m_vPos.y<vBoxMax.y &&
m_arrDecals[i].m_vPos.z<vBoxMax.z &&
m_arrDecals[i].m_vPos.x>vBoxMin.x &&
m_arrDecals[i].m_vPos.y>vBoxMin.y &&
m_arrDecals[i].m_vPos.z>vBoxMin.z )
{
m_arrbActiveDecals[i] = false;
GetRenderer()->DeleteLeafBuffer(m_arrDecals[i].m_pBigDecalLeafBuffer);
m_arrDecals[i].m_pBigDecalLeafBuffer=0;
}
}
}
/*
struct CDebugLine
{
Vec3d v0,v1;
int nFrameId;
};
list2<CDebugLine> lstDebugLines;
void AddDebugLine(Vec3d v0, Vec3d v1, int nFrameId)
{
CDebugLine l;
l.v0 = v0;
l.v1 = v1;
l.nFrameId = nFrameId;
lstDebugLines.Add(l);
}
void DrawDebugLines(IRenderer*pRenderer)
{
for(int i=0; i<lstDebugLines.Count(); i++)
{
pRenderer->Draw3dPrim(lstDebugLines[i].v0,lstDebugLines[i].v1,DPRIM_LINE);
if(pRenderer->GetFrameID()>lstDebugLines[i].nFrameId+1000)
{
lstDebugLines.Delete(i);
i--;
}
}
}*/

View File

@@ -0,0 +1,86 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: decalmanager.h
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#ifndef DECAL_MANAGER
#define DECAL_MANAGER
#define DECAL_COUNT (512)
#define ENTITY_DECAL_DIST_FACTOR (200)
class C3DEngine;
class CDecal
{
public:
// cur state
Vec3d m_vPos;
Vec3d m_vRight, m_vUp, m_vFront;
float m_fSize;
Vec3d m_vWSPos;
float m_fWSSize;
// life style
float m_fLifeEndTime;
int m_nTexId;
float m_fAngle;
IStatObj * m_pStatObj;
uint m_nDynLMask;
Vec3d m_vAmbient;
IEntityRender * m_pDecalOwner;
int m_nDecalOwnerComponentId;
bool m_bOnTheGround;
float m_fGrowTime;
float m_fLifeBeginTime;
// todo: move it into separate structure
CLeafBuffer * m_pBigDecalLeafBuffer;
float m_arrBigDecalCustomData[16];
CDecal() { ZeroStruct(*this); }
void Process(bool & active, IRenderer * pIRenderer, const float fFrameTime, C3DEngine * p3DEngine, IShader * pShader, CCamera* pCamera, float fSortOffset);
void DrawBigDecalOnTerrain(C3DEngine * p3DEngine, IRenderer * pIRenderer, float fCurrTime);
void Render3DObject();
void DrawComplexDecal(IRenderer * pIRenderer);
};
class CDecalManager : public Cry3DEngineBase
{
CDecal m_arrDecals[DECAL_COUNT];
bool m_arrbActiveDecals[DECAL_COUNT];
int m_nCurDecal;
C3DEngine * m_p3DEngine;
list2<CDecal> m_LightHoles;
IShader * m_pShader_ParticleLight, * m_pShader_Decal_VP, * m_pShader_Decal_2D_VP;
public:
CDecalManager(C3DEngine * p3DEngine);
void Spawn(CryEngineDecalInfo Decal, float fMaxViewDistance, CTerrain * pTerrain);
void Render();
void SubmitLightHolesToRenderer();
void DrawBigDecalsOnTerrain();
void OnEntityDeleted(IEntityRender * pEntityRS);
// complex decals
void FillBigDecalIndices(CLeafBuffer * pLeafBuffer, Vec3d vPos, float fRadius, Vec3d vProjDir, list2<ushort> * plstIndices);
CLeafBuffer * MakeBigDecalLeafBuffer(CLeafBuffer * pSourceLeafBuffer, Vec3d vPos, float fRadius, Vec3d vProjDir, int nTexID);
void GetMemoryUsage(ICrySizer*pSizer);
void Reset() { memset(m_arrbActiveDecals,0,sizeof(m_arrbActiveDecals)); m_nCurDecal=0; }
void DeleteDecalsInRange( Vec3d vBoxMin, Vec3d vBoxMax, bool bDeleteBigTerrainDecals);
bool AdjustDecalPosition( CryEngineDecalInfo & DecalInfo, bool bMakeFatTest );
bool RayLeafBufferIntersection(CLeafBuffer * pLeafBuffer, const Vec3d & vInPos, const Vec3d & vInDir, Vec3d & vOutPos, Vec3d & vOutNormal);
};
#endif // DECAL_MANAGER

314
Cry3DEngine/File.cpp Normal file
View File

@@ -0,0 +1,314 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: file.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: ceached file access
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#if defined(LINUX)
#include <sys/io.h>
#else
#include <io.h>
#endif
#ifndef _XBOX
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif
#else
#include <xtl.h>
#endif
#include "File.h"
#include "ICryPak.h"
ICryPak * CXFile::m_pCryPak = 0;
//////////////////////////////////////////////////////////////////////
CXFile::CXFile(struct ICryPak * pCryPak)
{
m_pCryPak = pCryPak;
m_szFileStart=NULL;
m_nFileSize=0;
m_pCurrPos=0;
m_pEndOfFile=NULL;
m_sLoadedFileName[0]=0;
}
//////////////////////////////////////////////////////////////////////
int CXFile::FRead(void *pDest,int nSize,int nNumElems)
{
int nTotSize=nSize*nNumElems;
char *pTest=m_pCurrPos+nTotSize;
if (pTest>m_pEndOfFile)
return (0);
memcpy(pDest,m_pCurrPos,nTotSize);
m_pCurrPos+=nTotSize;
return (nNumElems);
}
//////////////////////////////////////////////////////////////////////
int CXFile::FSeek(int nOff,int nFrom)
{
if (nFrom==SEEK_SET)
{
m_pCurrPos=m_szFileStart+nOff;
if (m_pCurrPos>m_pEndOfFile)
return (1);
}
return (0);
}
//////////////////////////////////////////////////////////////////////
void CXFile::FClose()
{
if (m_szFileStart)
{
delete [] m_szFileStart;
m_szFileStart=NULL;
}
m_pCurrPos=NULL;
m_nFileSize=0;
m_pEndOfFile=NULL;
m_sLoadedFileName[0]=0;
}
//////////////////////////////////////////////////////////////////////
int CXFile::FLoad(const char * filename)
{
if(!m_szFileStart || strcmp(m_sLoadedFileName,filename)!=0)
{
FClose();
m_nFileSize=LoadInMemory(filename,(void**)&m_szFileStart);
strncpy(m_sLoadedFileName,filename,sizeof(m_sLoadedFileName));
}
m_pCurrPos=m_szFileStart;
m_pEndOfFile=m_szFileStart+m_nFileSize;
return (m_nFileSize);
}
//get filename's extension
//////////////////////////////////////////////////////////////////////
char *CXFile::GetExtension(const char *filename)
{
char *src = (char *)filename+strlen(filename)-1;
while (*src)
{
if (*src == '.')
{
return (++src);
}
src--;
}
return (NULL);
}
//remove extension from filename
//////////////////////////////////////////////////////////////////////
void CXFile::RemoveExtension(char *path)
{
char *src = path+strlen(path)-1;
while (*src)
{
if (*src == '.')
{
*src = 0; // remove extension
return;
}
src--;
}
}
//replace filename extension
//////////////////////////////////////////////////////////////////////
void CXFile::ReplaceExtension(char *path, const char *new_ext)
{
RemoveExtension(path);
strcat(path,".");
strcat(path,new_ext);
}
//check if file exist
//////////////////////////////////////////////////////////////////////
bool CXFile::IsFileExist(const char *filename)
{
return FileExist(filename);
}
//check if file exist
//////////////////////////////////////////////////////////////////////
bool CXFile::FileExist(const char *filename)
{
FILE * fp = m_pCryPak->FOpen(filename,"rb");
if (!fp)
return (false);
m_pCryPak->FClose(fp);
return (true);
}
//get length of the file
//return (-1) if error
//////////////////////////////////////////////////////////////////////
int CXFile::GetLength(const char *filename)
{
FILE * fp = m_pCryPak->FOpen(filename,"rb");
if (!fp)
return (-1);
int pos;
int end;
pos = m_pCryPak->FTell(fp);
m_pCryPak->FSeek(fp, 0, SEEK_END);
end = m_pCryPak->FTell(fp);
m_pCryPak->FSeek(fp, pos, SEEK_SET);
m_pCryPak->FClose(fp);
return (end);
}
//tell if filename1 is older than masterfile
//////////////////////////////////////////////////////////////////////
/*bool CXFile::IsOutOfDate(const char *pFileName1,const char *pMasterFile)
{
FILE * f = m_pCryPak->FOpen(pMasterFile,"rb");
if (f)
m_pCryPak->FClose(f);
else
return (false);
f = m_pCryPak->FOpen(pFileName1,"rb");
if (f)
m_pCryPak->FClose(f);
else
return (true);
#ifdef WIN32
HANDLE status1 = CreateFile(pFileName1,GENERIC_READ,FILE_SHARE_READ,
NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
HANDLE status2 = CreateFile(pMasterFile,GENERIC_READ,FILE_SHARE_READ,
NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
FILETIME writetime1,writetime2;
GetFileTime(status1,NULL,NULL,&writetime1);
GetFileTime(status2,NULL,NULL,&writetime2);
CloseHandle(status1);
CloseHandle(status2);
if (CompareFileTime(&writetime1,&writetime2)==-1)
return(true);
return (false);
#else
return (false);
#endif
}*/
//////////////////////////////////////////////////////////////////////
/*int CXFile::GetWriteTime(const char *pFileName1)
{
FILE * f = m_pCryPak->FOpen(pFileName1,"rb");
if (f)
m_pCryPak->FClose(f);
else
return (0);
#ifdef WIN32
HANDLE status1 = CreateFile(pFileName1,GENERIC_READ,FILE_SHARE_READ,
NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
FILETIME writetime1;
memset(&writetime1,0,sizeof(writetime1));
GetFileTime(status1,NULL,NULL,&writetime1);
CloseHandle(status1);
return (writetime1.dwHighDateTime + writetime1.dwLowDateTime);
#else
return (0);
#endif
} */
//////////////////////////////////////////////////////////////////////
int CXFile::GetLength(FILE *f)
{
int pos;
int end;
pos = m_pCryPak->FTell(f);
m_pCryPak->FSeek(f, 0, SEEK_END);
end = m_pCryPak->FTell(f);
m_pCryPak->FSeek(f, pos, SEEK_SET);
return end;
}
//////////////////////////////////////////////////////////////////////
void CXFile::SafeRead(FILE *f, void *buffer, int count)
{
(m_pCryPak->FRead(buffer, 1, count, f) != (unsigned)count);
}
//////////////////////////////////////////////////////////////////////
int CXFile::LoadInMemory(const char *filename, void **bufferptr)
{
FILE *f = m_pCryPak->FOpen(filename,"rb");
if (!f)
return (0);
int length = CXFile::GetLength(f);
void *buffer = new char[length+1];
SafeRead(f, buffer, length);
m_pCryPak->FClose(f);
char * bbp = (char *)buffer;
bbp[length] = 0; //null terminated
*bufferptr = buffer;
return (length);
}
//////////////////////////////////////////////////////////////////////
void CXFile::GetPath(char *path)
{
char *src = path+strlen(path)-1;
while (*src)
{
if (*src == '\\')
{
src++;
*src = 0; // remove extension
return;
}
src--;
}
}

71
Cry3DEngine/File.h Normal file
View File

@@ -0,0 +1,71 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: file.h
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: cecahed file access
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#ifndef PS2
#ifndef FILE_H
#define FILE_H
#define MAX_PATH_LENGTH 512
#include <stdio.h>
class CXFile
{
public:
CXFile(struct ICryPak * pCryPak);
~CXFile() { FClose(); }
int FRead(void *pDest,int nSize,int nNumElems);
static void SafeRead(FILE *f, void *buffer, int count);
int FSeek(int nOff,int nFrom);
int FLoad(const char *filename);
void FClose();
static bool FileExist(const char *filename);
static bool IsFileExist(const char *filename);
//-1 if file does not exist
static int GetLength(const char *filename);
static int GetLength(FILE *f);
static int LoadInMemory(const char *filename, void **bufferptr);
// static bool IsOutOfDate(const char *pFileName1,const char *pMasterFile);
// static int GetWriteTime(const char *pFileName1);
//utils
static void RemoveExtension (char *path);
static void ReplaceExtension(char *path, const char *new_ext);
static char *GetExtension (const char *filename);
static char *GetString (FILE *fp,const char *key);
static void GetPath(char *path);
//Tim code
static void SetLanguage (const char *command=NULL);
static char *ConvertFilename(const char *filename);
static void SetIPack(ICryPak * pCryPak) { m_pCryPak = pCryPak; }
private:
char *m_szFileStart,*m_pCurrPos,*m_pEndOfFile;
int m_nFileSize;
char m_sLoadedFileName[512];
static struct ICryPak * m_pCryPak;
};
#endif
#else //PS2
#include "..\CryCommon\File.h"
#endif

148
Cry3DEngine/Geom.cpp Normal file
View File

@@ -0,0 +1,148 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: geom.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: loading geometry from cgf
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Geom.h"
#include "file.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CGeom::CGeom() : CBaseObj()
{
memset(&m_Chunk,0,sizeof(m_Chunk));
m_pVertices =NULL;
m_pFaces =NULL;
// m_pLinks =NULL;
m_pUVs =NULL;
m_sPropstr =NULL;
// bones =NULL;
m_pTexFaces =NULL;
// m_pNumLinks =NULL;
// links =NULL;
m_pVcols =NULL;
// BoneNames =NULL;
}
CGeom::~CGeom()
{
/* if(links)
{
for(int i=0;i<m_Chunk.nVerts;i++) if(links[i]) free(links[i]);
free(links);
}*/
// if(bones) free(bones);
if(m_pFaces) free(m_pFaces);
if(m_pVertices)free(m_pVertices);
if(m_pUVs) free(m_pUVs);
if(m_sPropstr) free(m_sPropstr);
// if(nLinks) free(nLinks);
if(m_pVcols) free(m_pVcols);
if(m_pTexFaces)free(m_pTexFaces);
}
bool CGeom::Load(CXFile *f, int pos)
{
if(f->FSeek(pos,SEEK_SET)) return true;
int res=f->FRead(&m_Chunk,sizeof(m_Chunk),1);
if(res!=1) return true;
m_ChunkHeader=m_Chunk.chdr;
if(m_ChunkHeader.ChunkType != ChunkType_Mesh || m_ChunkHeader.ChunkVersion != MESH_CHUNK_DESC_VERSION)
{
memset(&m_Chunk,0,sizeof(m_Chunk));
return true;
}
//read verts
m_pVertices=(CryVertex*)malloc(sizeof(CryVertex)*m_Chunk.nVerts);
assert(m_pVertices);
res=f->FRead(m_pVertices,sizeof(CryVertex),m_Chunk.nVerts);
if(res!=m_Chunk.nVerts) return true;
//read m_pFaces
m_pFaces=(CryFace*)malloc(sizeof(CryFace)*m_Chunk.nFaces);
assert(m_pFaces);
res=f->FRead(m_pFaces,sizeof(CryFace),m_Chunk.nFaces);
if(res!=m_Chunk.nFaces) return true;
//read tverts
if(m_Chunk.nTVerts)
{
m_pUVs=(CryUV*)malloc(sizeof(CryUV)*m_Chunk.nTVerts);
assert(m_pUVs);
res=f->FRead(m_pUVs,sizeof(CryUV),m_Chunk.nTVerts);
if(res!=m_Chunk.nTVerts) return true;
// flip tex coords (since it was flipped in max?)
for(int t=0; t<m_Chunk.nTVerts; t++)
m_pUVs[t].v = 1.f-m_pUVs[t].v;
//read Tfaces
//if(m_Chunk.nVerts != m_Chunk.nTVerts)
if(m_Chunk.nVerts != 12 || pos != 692)//hack to make old grass objects working
{
m_pTexFaces=(CryTexFace*)malloc(sizeof(CryTexFace)*m_Chunk.nFaces);
assert(m_pTexFaces);
res=f->FRead(m_pTexFaces,sizeof(CryTexFace),m_Chunk.nFaces);
if(res!=m_Chunk.nFaces) return true;
}
}
//read Vertex Colors
if(m_Chunk.HasVertexCol)
{
m_pVcols=(CryIRGB *)malloc(m_Chunk.nVerts*sizeof(CryIRGB));
assert(m_pVcols);
int res=f->FRead(m_pVcols, sizeof(CryIRGB), m_Chunk.nVerts);
/*
for (int k=0;k<m_Chunk.nVerts;k++)
{
m_pVcols[k].r=255;
m_pVcols[k].g=0;
m_pVcols[k].b=0;
} //k
*/
if (res!=m_Chunk.nVerts)
return (true);
}
else
{
m_pVcols=0;
/*
m_pVcols=(CryIRGB *)malloc(m_Chunk.nVerts*sizeof(CryIRGB));
assert(m_pVcols);
for (int k=0;k<m_Chunk.nVerts;k++)
{
m_pVcols[k].r=255;
m_pVcols[k].g=0;
m_pVcols[k].b=0;
} //k
*/
}
return (false);
}

51
Cry3DEngine/Geom.h Normal file
View File

@@ -0,0 +1,51 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: geom.h
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_GEOM_H__D90B8CB0_DAA4_49C7_8D72_4A73FA38E640__INCLUDED_)
#define AFX_GEOM_H__D90B8CB0_DAA4_49C7_8D72_4A73FA38E640__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "baseobj.h"
class CGeom : public CBaseObj
{
public:
CryVertex *m_pVertices;
CryFace *m_pFaces;
CryUV *m_pUVs;
CryTexFace *m_pTexFaces;
CryIRGB *m_pVcols;
// int *m_pNumLinks;
// CryLink ** m_pLinks;
char * m_sPropstr;
MESH_CHUNK_DESC m_Chunk;
CGeom();
virtual ~CGeom();
//from BaseObj
bool Load(CXFile *f, int pos);
MESH_CHUNK_DESC * GetChunk() { return &m_Chunk; }
//CGeom methods
void Deform();
};
#endif // !defined(AFX_GEOM_H__D90B8CB0_DAA4_49C7_8D72_4A73FA38E640__INCLUDED_)

49
Cry3DEngine/Helper.cpp Normal file
View File

@@ -0,0 +1,49 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: helper.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: loading helper from cgf
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Helper.h"
#include "file.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CHelper::CHelper() : CBaseObj()
{
memset(&m_Chunk,0,sizeof(m_Chunk));
}
CHelper::~CHelper()
{
}
bool CHelper::Load(CXFile *f, int pos)
{
if(f->FSeek(pos,SEEK_SET)) return true;
int res=f->FRead(&m_Chunk,sizeof(m_Chunk),1);
if(res!=1) return true;
if(m_Chunk.chdr.ChunkType != ChunkType_Helper || m_Chunk.chdr.ChunkVersion != HELPER_CHUNK_DESC_VERSION)
{
memset(&m_Chunk,0,sizeof(m_Chunk));
return true;
}
m_ChunkHeader=m_Chunk.chdr;
return false;
}

36
Cry3DEngine/Helper.h Normal file
View File

@@ -0,0 +1,36 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: helper.h
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_HELPER_H__3A967DC3_988F_4A67_BC33_AC26573B86FA__INCLUDED_)
#define AFX_HELPER_H__3A967DC3_988F_4A67_BC33_AC26573B86FA__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "BaseObj.h"
class CHelper : public CBaseObj
{
public:
HELPER_CHUNK_DESC m_Chunk;
CHelper();
virtual ~CHelper();
virtual bool Load(CXFile *f, int pos);
};
#endif // !defined(AFX_HELPER_H__3A967DC3_988F_4A67_BC33_AC26573B86FA__INCLUDED_)

View File

@@ -0,0 +1,157 @@
//////////////////////////////////////////////////////////////////////
//
// Crytek Indoor Engine DLL source code
//
// File: IndoorShadowVolumes.h
//
// History:
// -August 28,2001:Created by Marco Corbetta
//
//////////////////////////////////////////////////////////////////////
#ifndef INDOORSHADOWVOLUMES_H
#define INDOORSHADOWVOLUMES_H
#if _MSC_VER > 1000
# pragma once
#endif
//////////////////////////////////////////////////////////////////////
#define FLAG_SKIP_SHADOWVOLUME 1
//forward declarations
//////////////////////////////////////////////////////////////////////
#include "IndoorVolumes.h"
#include "I3DEngine.h" // USE_SHADOW_VERSION
class CDLight;
class CRETriMeshShadow;
class IStencilShadowConnectivity;
//an entire shadow volume object containing many edges and faces
//////////////////////////////////////////////////////////////////////
class CShadowVolObject : public CVolume
{
public:
// constructor
CShadowVolObject()
{
// m_pFaceList=NULL;
m_pReMeshShadow=NULL;
m_pSystemVertexBuffer=NULL;
m_pEdgeConnectivity=0;
m_nNumVertices=0;
// m_nNumFaces=0;
};
//! destructor
~CShadowVolObject();
//!
bool CheckInside(const Vec3d &pos,bool bWorldSpace=true)
{
//temporary return false...will be a cool AI game play feature to know
//if we are in shadows
return (false);
}
//! precalculate the connectivity infos to build the object silouhette
bool CreateConnectivityInfo( void );
//! create/update a vertex buffer containing the shadow volume (for static lights)
void RebuildShadowVolumeBuffer( const CDLight &lSource, float fExtent );
Vec3d * GetSysVertBufer() { return m_pSystemVertexBuffer; }
int GetNumVertices() { return(m_nNumVertices); }
// int GetNumFaces() { return(m_nNumFaces); }
// Shader RenderElements for stencil
CRETriMeshShadow * m_pReMeshShadow; //!<
void CheckUnload();
IStencilShadowConnectivity * & GetEdgeConnectivity() { return m_pEdgeConnectivity; }
protected:
//! free the shadow volume buffers
void FreeVertexBuffers();
//list of faces from source objects, its always shared from the stat obj
// int m_nNumFaces; //!<
// CObjFace * m_pFaceList; //!< pointer to MeshIdx faces [0..m_nNumFaces-1]
//list of edges...can be shared from another shadow vol object
IStencilShadowConnectivity * m_pEdgeConnectivity; //!< stored edge connectivity for fast shadow edge extraction, could be 0, call ->Release() to free it
TFixedArray<unsigned short> m_arrIndices; //!<
unsigned m_nNumVertices; //!< number of vertices in SystemBuffer
//!
//! /param nNumIndices
//! /param nNumVertices
void PrepareShadowVolumeVertexBuffer( unsigned nNumIndices, unsigned nNumVertices );
//shadow volume renderer vertex buffer
Vec3d * m_pSystemVertexBuffer;
};
struct ItShadowVolume;
//////////////////////////////////////////////////////////////////////
struct tShadowVolume : public ItShadowVolume
{
tShadowVolume()
{
pSvObj=NULL;
}
CShadowVolObject *GetShadowVolume()
{
return (pSvObj);
}
void SetShadowVolume(CShadowVolObject *pParmSvObj)
{
pSvObj=pParmSvObj;
}
void Release()
{
if (pSvObj)
{
delete pSvObj;
pSvObj=NULL;
}
delete this;
}
//! get/set position
Vec3d GetPos()
{
return (pSvObj->GetPos());
}
void SetPos(const Vec3d &vPos)
{
pSvObj->SetPos(vPos);
}
//! recalculate the object's silouhette, mostly for dynamic lights
//! the light should always be in object space
void RebuildShadowVolumeBuffer( const CDLight &lSource, float fExtent )
{
pSvObj->RebuildShadowVolumeBuffer(lSource, fExtent);
}
Vec3d * GetSysVertBufer() { return pSvObj->GetSysVertBufer(); }
void CheckUnload() { pSvObj->CheckUnload(); }
CShadowVolObject *pSvObj;
};
#endif

151
Cry3DEngine/IndoorVolumes.h Normal file
View File

@@ -0,0 +1,151 @@
//////////////////////////////////////////////////////////////////////
//
// Crytek CryENGINE source code
//
// File: IndoorVolumes.h
//
// History:
// -August 28,2001:Created by Marco Corbetta
//
//////////////////////////////////////////////////////////////////////
#ifndef INDOORVOLUMES_H
#define INDOORVOLUMES_H
#if _MSC_VER > 1000
# pragma once
#endif
//////////////////////////////////////////////////////////////////////
#define FLAG_VOLUME_AREA 1
#define FLAG_VOLUME_PORTAL 2
#define FLAG_VOLUME_HULL 4
#define FLAG_VOLUME_FOG 8
#define FLAG_VOLUME_OBJECT 16
#define FLAG_VOLUME_DRAWN 32
#define FLAG_VOLUME_RECURSED 64
#define FLAG_GEOMETRY_SHARED 128
#define FLAG_OBJECT_VISIBLE_BY_PORTALS 256
#define FLAG_OBJECT_PRX 512 //this object is affected by per-pixel lighting by other lights
#define FLAG_OBJECT_PORTAL_ENTITY 1024
#define FLAG_OBJECT_DOUBLE_PORTAL 2048
//////////////////////////////////////////////////////////////////////
//#define FLAG2_DRAWN (1L<<17)
// this holds datas for volumes and areas
//////////////////////////////////////////////////////////////////////////
typedef struct s_Container
{
s_Container()
{
pObj=NULL;
pEnt=NULL;
pSV=NULL;
}
IStatObj *pObj;
IPhysicalEntity *pEnt;
class CShadowVolObject *pSV;
}tContainer;
//////////////////////////////////////////////////////////////////////
typedef std::vector<tContainer> ContainerList;
typedef std::vector<tContainer>::iterator ContainerListIt;
//////////////////////////////////////////////////////////////////////
typedef std::vector<IStatObj*> istatobjlist;
typedef std::vector<IStatObj*>::iterator istatobjit;
//////////////////////////////////////////////////////////////////////
typedef std::vector<IPhysicalEntity*> iphysobjlist;
typedef std::vector<IPhysicalEntity*>::iterator iphysobjit;
//////////////////////////////////////////////////////////////////////
class CVolume : public Cry3DEngineBase
{
public:
//constructors/destructors
//this constructor is only for building
CVolume()
{
m_dwFlags=0;
m_nObjCount=0;
m_vOrigin(0,0,0);
m_vMins=SetMaxBB();
m_vMaxs=SetMinBB();
}
/*
CVolume()
{
m_dwFlags=0;
m_nObjCount=0;
m_vOrigin(0,0,0);
m_vMins=SetMaxBB();
m_vMaxs=SetMinBB();
};
*/
virtual ~CVolume();
int GetFlags() { return(m_dwFlags); }
//////////////////////////////////////////////////////////////////////
//check if a point is inside the volume
virtual bool CheckInside(const Vec3d &pos,bool bWorldSpace) { return(false); }
void RemoveGeometry(IStatObj *pSource,ContainerListIt i);
//void SetGeometry(IStatObj *pSource);
//void AddGeometry(IStatObj *pSource,IPhysicalEntity *pEnt=NULL);
void AddGeometry(tContainer tCont);
Vec3d GetBBoxMin(bool bWorldSpace=false)
{
if (bWorldSpace)
{
Vec3d vWorldPos=m_vOrigin+m_vMins;
return(vWorldPos);
}
return(m_vMins);
}
Vec3d GetBBoxMax(bool bWorldSpace=false)
{
if (bWorldSpace)
{
Vec3d vWorldPos=m_vOrigin+m_vMaxs;
return(vWorldPos);
}
return(m_vMaxs);
}
//set new volume's position
//////////////////////////////////////////////////////////////////////
void SetPos(const Vec3d &vPos);
Vec3d GetPos() { return (m_vOrigin); }
//bounding box
Vec3d m_vMins;
Vec3d m_vMaxs;
//volume flags
int m_dwFlags;
//! the source geometry
//IStatObj *m_pSource;
int m_nObjCount;
ContainerList m_lstObjects;
//istatobjlist m_lstStatObjs;
//iphysobjlist m_lstPhysObjs;
protected:
//! volume origin
Vec3d m_vOrigin;
//Vec3d m_vWorldPos;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,222 @@
#ifndef __LM_SERIALIZATION_MANAGER_2_H__
#define __LM_SERIALIZATION_MANAGER_2_H__
#include <ILMSerializationManager.h>
#include "LMCompStructures.h"
#include "I3DEngine.h"
#include <map>
#ifdef WIN64
#pragma warning( push ) //AMD Port
#pragma warning( disable : 4267 )
#endif
class CTempFile
{
public:
CTempFile(unsigned nReserve = 0)
{
m_arrData.reserve (nReserve);
}
void WriteData (const void* pData, unsigned nSize)
{
if (nSize)
{
unsigned nOffset = m_arrData.size();
m_arrData.resize(nOffset + nSize);
memcpy (&m_arrData[nOffset], pData, nSize);
}
}
template <typename T>
void Write (const T& t)
{
WriteData (&t, sizeof(T));
}
template <typename T>
void Write (const T* pT, unsigned numElements)
{
WriteData (pT, numElements*sizeof(T));
}
unsigned GetSize() const {return m_arrData.size();}
void SetSize (unsigned n){m_arrData.resize (n);}
char* GetData() {return &m_arrData[0];}
void Clear() {m_arrData.clear();}
void Reserve (unsigned n) {m_arrData.reserve (n);}
void Init (unsigned nSize)
{
m_arrData.clear();
m_arrData.resize (nSize);
}
protected:
std::vector<char> m_arrData;
};
#ifdef WIN64
#pragma warning( pop ) //AMD Port
#endif
class CLMSerializationManager2 : public Cry3DEngineBase, public ILMSerializationManager
{
public:
CLMSerializationManager2( );
virtual ~CLMSerializationManager2();
// interface ILMSerializationManager ------------------------------------
virtual void Release() { delete this; };
virtual bool ApplyLightmapfile( const char *pszFileName, std::vector<IEntityRender *>& vIGLMs );
virtual bool Load(const char *pszFileName, const bool cbLoadTextures = true);
virtual unsigned int Save(const char *pszFileName, LMGenParam rParam, const bool cbAppend = false);
virtual void AddRawLMData(
const DWORD indwWidth, const DWORD indwHeight, const std::vector<int>& _cGLM_IDs_UsingPatch,
BYTE *_pColorLerp4, BYTE *_pHDRColorLerp4, BYTE *_pDomDirection3, BYTE *_pOccl2 = 0);
virtual void AddTexCoordData(const std::vector<TexCoord2Comp>& vTexCoords, int iGLM_ID_UsingTexCoord, const DWORD indwHashValue, const std::vector<std::pair<EntityId, EntityId> >& rOcclIDs);
virtual DWORD GetHashValue(const int iniGLM_ID_UsingTexCoord) const;
virtual bool ExportDLights(const char *pszFileName, const CDLight **ppLights, UINT iNumLights, bool bNewZip = true) const;
virtual bool LoadDLights(const char *pszFileName, CDLight **&ppLightsOut, UINT &iNumLightsOut) const;
RenderLMData * CreateLightmap(const string& strDirPath, int nItem,UINT iWidth, UINT iHeight, const bool cbLoadHDRMaps, const bool cbLoadOcclMaps = false);
//! Create a dot3 lightmap ColorLerp / DomDirection tetxure pair
virtual RenderLMData * CreateLightmap(const char *pszFileName, int nItem, UINT iWidth, UINT iHeight, BYTE *pColorLerp4, BYTE *pHDRColorLerp4, BYTE *pDomDirection3, BYTE *pOccl2 = 0);
// ----------------------------------------------
protected:
struct FileHeader
{
enum {MAGIC_NUMBER = 0x8F23123E};
enum {VERSION = 3};
FileHeader() { iMagicNumber = MAGIC_NUMBER;iVersion = VERSION; };
UINT iMagicNumber;
UINT iVersion;
UINT iNumLM_Pairs;
UINT iNumTexCoordSets;
UINT reserved[4];
};
struct LMHeader
{
// the dimensions of LM
UINT iWidth;
UINT iHeight;
// number of GLMs using this LM
UINT numGLMs;
};
struct UVSetHeader
{
UINT nIdGLM;
UINT nHashGLM;
UINT numUVs;
UVSetHeader() : nIdGLM(0), nHashGLM(0), numUVs(0){}
};
//new version available from ver 3 on
struct UVSetHeader3 : UVSetHeader
{
EntityId OcclIds[4*2]; //new: the occlusion map colour channel light id's, this corresponds to the std::pair<EntityId, EntityId>
unsigned char ucOcclCount/*1..4*/;
UVSetHeader3():ucOcclCount(0)
{
UVSetHeader::UVSetHeader();
OcclIds[0] = OcclIds[1] = OcclIds[2] = OcclIds[3] = 0;
}
};
struct RawLMData
{
//! /param _pColorLerp4 if !=0 this memory is copied
//! /param _pDomDirection3 if !=0 this memory is copied
RawLMData(const DWORD indwWidth, const DWORD indwHeight, const std::vector<int>& _vGLM_IDs_UsingPatch )
{
vGLM_IDs_UsingPatch = _vGLM_IDs_UsingPatch;
m_dwWidth=indwWidth;
m_dwHeight=indwHeight;
m_bUseOcclMaps = false;
};
enum BitmapEnum
{
TEX_COLOR,
TEX_DOMDIR,
TEX_OCCL,
TEX_HDR
};
// initializes from raw bitmaps
void initFromBMP (BitmapEnum t, const void* pSource);
// initializes from files
bool initFromDDS (BitmapEnum t, ICryPak* pPak, const string& szFileName);
std::vector<int> vGLM_IDs_UsingPatch; //!< vector of object ids that use this lightmap
// the color DDS, as is in the file
CTempFile m_ColorLerp4;
// the color DDS, as is in the file
CTempFile m_HDRColorLerp4;
// the dominant direction DDS, as is in the file
CTempFile m_DomDirection3;
// the occlusion map DDS, as is in the file
CTempFile m_Occl2;
DWORD m_dwWidth; //!<
DWORD m_dwHeight; //!<
bool m_bUseOcclMaps;
bool m_bUseHDRMaps;
private:
//! copy constructor (forbidden)
RawLMData( const RawLMData &a ) {}
//! assignment operator (forbidden)
RawLMData &operator=( const RawLMData &a ) { return(*this); }
};
struct RawTexCoordData
{
//! default constructor (needed for std::map)
RawTexCoordData() {}
RawTexCoordData( const std::vector<TexCoord2Comp>& _vTexCoords, const DWORD indwHashValue, const std::vector<std::pair<EntityId, EntityId> >& rOcclIDs )
{
vTexCoords = _vTexCoords;
m_dwHashValue=indwHashValue;
vOcclIDs = rOcclIDs;
};
RawTexCoordData( const std::vector<TexCoord2Comp>& _vTexCoords, const DWORD indwHashValue )
{
vTexCoords = _vTexCoords;
m_dwHashValue=indwHashValue;
vOcclIDs.clear();
};
std::vector<TexCoord2Comp> vTexCoords; //!<
DWORD m_dwHashValue; //!< to detect changes in the lighting (for incremental recompile)
std::vector<std::pair<EntityId, EntityId> > vOcclIDs; //!< occlusion indices corresponding to the 0..4 colour channels
};
std::vector<RawLMData *> m_vLightPatches; //!< class is responsible for deleteing this
std::map<int,RawTexCoordData> m_vTexCoords; //!<
// \param inpIGLMs pointer to the objects we want to assign the data(instance is not touched), 0 if we want to load it to the instance
bool _Load( const char *pszFileName, std::vector<IEntityRender *> *inpIGLMs, const bool cbLoadTextures = true);
void WriteString(const char *pszStr, CTempFile& f) const
{
UINT iStrLen = (UINT) strlen(pszStr);
f.Write (iStrLen);
f.WriteData(pszStr, iStrLen);
};
};
#endif // __LM_SERIALIZATION_MANAGER_H__

49
Cry3DEngine/Light.cpp Normal file
View File

@@ -0,0 +1,49 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: light.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: loading light source from cgf
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Light.h"
#include "file.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CLight::CLight()
{
memset(&m_Chunk,0,sizeof(m_Chunk));
}
CLight::~CLight()
{
}
bool CLight::Load(CXFile *f, int pos)
{
if(f->FSeek(pos,SEEK_SET)) return true;
int res=f->FRead(&m_Chunk,sizeof(m_Chunk),1);
if(res!=1) return true;
if(m_Chunk.chdr.ChunkType != ChunkType_Light || m_Chunk.chdr.ChunkVersion != LIGHT_CHUNK_DESC_VERSION)
{
memset(&m_Chunk,0,sizeof(m_Chunk));
return true;
}
m_ChunkHeader=m_Chunk.chdr;
return false;
}

36
Cry3DEngine/Light.h Normal file
View File

@@ -0,0 +1,36 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: light.h
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_LIGHT_H__ACF97045_6471_4C13_BC9F_F26C16A0590E__INCLUDED_)
#define AFX_LIGHT_H__ACF97045_6471_4C13_BC9F_F26C16A0590E__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "BaseObj.h"
class CLight : public CBaseObj
{
public:
LIGHT_CHUNK_DESC m_Chunk;
CLight();
virtual ~CLight();
virtual bool Load(CXFile *f, int pos);
};
#endif // !defined(AFX_LIGHT_H__ACF97045_6471_4C13_BC9F_F26C16A0590E__INCLUDED_)

11
Cry3DEngine/LightLoad.cpp Normal file
View File

@@ -0,0 +1,11 @@
#include "stdafx.h"
#include "3dEngine.h"
#include "objman.h"
#include "visareas.h"
#include "lightman.h"
#ifndef PI
#define PI 3.14159f
#endif

328
Cry3DEngine/LightMan.cpp Normal file
View File

@@ -0,0 +1,328 @@
#include "stdafx.h"
// New version of light sources management - not used yet
#include "3dEngine.h"
#include "objman.h"
#include "visareas.h"
#include "lightman.h"
#ifndef PI
#define PI 3.14159f
#endif
CLightManager::CLightManager()
{
m_arrLights = new std::map<int, LightsSet*>;
}
CLightManager::~CLightManager()
{
for (LightsMap::iterator it = m_arrLights->begin(); it != m_arrLights->end(); ++it)
{ // free lights lists
LightsSet * pCellLights = (*it).second;
delete pCellLights;
}
m_arrLights->clear();
delete m_arrLights;
}
void CLightManager::GetLightBounds(CDLight * pLight, int &min_x, int &min_y, int &max_x, int &max_y)
{
// find lights 2d bounds
Vec3d vRadius(pLight->m_fRadius,pLight->m_fRadius,pLight->m_fRadius);
Vec3d vBoxMin = pLight->m_Origin - vRadius;
Vec3d vBoxMax = pLight->m_Origin + vRadius;
// get 2d bounds in sectors array
min_x = (int)(((vBoxMin.x - 1.f)/LIGHT_GRID_SIZE));
min_y = (int)(((vBoxMin.y - 1.f)/LIGHT_GRID_SIZE));
max_x = (int)(((vBoxMax.x + 1.f)/LIGHT_GRID_SIZE));
max_y = (int)(((vBoxMax.y + 1.f)/LIGHT_GRID_SIZE));
int nTableSize = CTerrain::GetTerrainSize()/LIGHT_GRID_SIZE;
if( min_x<0 ) min_x = 0; else if( min_x>=nTableSize ) min_x = nTableSize-1;
if( min_y<0 ) min_y = 0; else if( min_y>=nTableSize ) min_y = nTableSize-1;
if( max_x<0 ) max_x = 0; else if( max_x>=nTableSize ) max_x = nTableSize-1;
if( max_y<0 ) max_y = 0; else if( max_y>=nTableSize ) max_y = nTableSize-1;
}
void CLightManager::AddLight(CDLight * pLight)
{
int min_x, min_y, max_x, max_y;
GetLightBounds(pLight, min_x, min_y, max_x, max_y);
int nTableSize = CTerrain::GetTerrainSize()/LIGHT_GRID_SIZE;
for(int x=min_x; x<=max_x; x++)
for(int y=min_y; y<=max_y; y++)
{
// find cell from position
int nXY = x+y*nTableSize;
LightsMap::iterator itTable = m_arrLights->find(nXY);
LightsSet * pLightsSet = 0;
if(itTable!=m_arrLights->end())
pLightsSet = (*itTable).second;
else
{ // allocate new set if needed
pLightsSet = new LightsSet;
m_arrLights->insert(LightsMap::value_type(nXY,pLightsSet));
}
// add light if not found
LightsSet::iterator itLightsSet = pLightsSet->find(pLight);
if(itLightsSet==pLightsSet->end())
pLightsSet->insert(pLight);
}
}
void CLightManager::DeleteLight(CDLight*pLight)
{
int min_x, min_y, max_x, max_y;
GetLightBounds(pLight, min_x, min_y, max_x, max_y);
int nTableSize = CTerrain::GetTerrainSize()/LIGHT_GRID_SIZE;
for(int x=min_x; x<=max_x; x++)
for(int y=min_y; y<=max_y; y++)
{
// find cell from position
int nXY = x+y*nTableSize;
LightsMap::iterator itTable = m_arrLights->find(nXY);
LightsSet * pLightsSet = 0;
if(itTable!=m_arrLights->end())
{
pLightsSet = (*itTable).second;
// delete light if found
LightsSet::iterator itLightsSet = pLightsSet->find(pLight);
if(itLightsSet!=pLightsSet->end())
{
pLightsSet->erase(itLightsSet);
if(pLightsSet->empty())
{
delete pLightsSet;
m_arrLights->erase(itTable);
}
}
}
}
}
void CLightManager::GetLightsAffectingBBox(const Vec3d & vBoxMin, const Vec3d & vBoxMax, LightsSet * pOutputList)
{
pOutputList->clear();
// get 2d bounds in sectors array
int min_x = (int)(((vBoxMin.x - 1.f)/LIGHT_GRID_SIZE));
int min_y = (int)(((vBoxMin.y - 1.f)/LIGHT_GRID_SIZE));
int max_x = (int)(((vBoxMax.x + 1.f)/LIGHT_GRID_SIZE));
int max_y = (int)(((vBoxMax.y + 1.f)/LIGHT_GRID_SIZE));
int nTableSize = CTerrain::GetTerrainSize()/LIGHT_GRID_SIZE;
if( min_x<0 ) min_x = 0; else if( min_x>=nTableSize ) min_x = nTableSize-1;
if( min_y<0 ) min_y = 0; else if( min_y>=nTableSize ) min_y = nTableSize-1;
if( max_x<0 ) max_x = 0; else if( max_x>=nTableSize ) max_x = nTableSize-1;
if( max_y<0 ) max_y = 0; else if( max_y>=nTableSize ) max_y = nTableSize-1;
for(int x=min_x; x<=max_x; x++)
for(int y=min_y; y<=max_y; y++)
{
// find cell from position
int nXY = x+y*nTableSize;
LightsMap::iterator itTable = m_arrLights->find(nXY);
LightsSet * pLightsSet = 0;
if(itTable!=m_arrLights->end())
{
pLightsSet = (*itTable).second;
// add lights into output list if found
for (LightsSet::iterator it = pLightsSet->begin(); it != pLightsSet->end(); ++it)
{
if(pOutputList->find(*it) == pOutputList->end())
pOutputList->insert(*it);
}
}
}
}
extern int __cdecl C3DEngine__Cmp_LightAmount(const void* v1, const void* v2);
int CLightManager::MakeLMaskFromPositionAndActivateLights( const Vec3d vObjPos, const float fObjRadius,
IEntityRender * pEntityRender, int nMaxLightBitsNum, CDLight ** pSelectedLights, int nMaxSelectedLights)
{
Vec3d vBoxMin, vBoxMax;
pEntityRender->GetRenderBBox(vBoxMin, vBoxMax);
GetLightsAffectingBBox(vBoxMin, vBoxMax, &m_setTmpDL_MMFP);
// make list of really affecting light sources
m_lstTmpDLA_MMFP.Clear();
for(LightsSet::iterator itLightsSet = m_setTmpDL_MMFP.begin(); itLightsSet != m_setTmpDL_MMFP.end(); ++itLightsSet)
{
CDLight * pDLight = (*itLightsSet);
if(!pDLight || pDLight->m_fRadius < 0.5f || pDLight->m_Flags & DLF_FAKE)
continue;
if (pDLight->m_pShader!=0 && (pDLight->m_pShader->GetLFlags() & LMF_DISABLE))
continue; // fake
if(pEntityRender && pDLight->m_Flags & DLF_LM && pEntityRender->GetRndFlags() & ERF_USELIGHTMAPS && pEntityRender->HasLightmap(0))
{ // in case of lightmaps
if(pDLight->m_SpecColor == Col_Black)
continue; // ignore specular only lights if specular disabled
if(pDLight->m_Flags & DLF_PROJECT)
continue; // ignore specular only lights if projector since specular projectors not supported
}
if(pDLight->m_Flags & DLF_PROJECT && pEntityRender)
{ // check projector frustum
// use pDLight->m_TextureMatrix to construct Plane
/*GetRenderer()->Draw3dBBox(pDLight->m_Origin, pDLight->m_Origin+pDLight->m_TextureMatrix.GetOrtX(), DPRIM_LINE);
GetRenderer()->DrawLabel(pDLight->m_Origin+pDLight->m_TextureMatrix.GetOrtX(),1,"x");
GetRenderer()->Draw3dBBox(pDLight->m_Origin, pDLight->m_Origin+pDLight->m_TextureMatrix.GetOrtY(), DPRIM_LINE);
GetRenderer()->DrawLabel(pDLight->m_Origin+pDLight->m_TextureMatrix.GetOrtY(),1,"y");
GetRenderer()->Draw3dBBox(pDLight->m_Origin, pDLight->m_Origin+pDLight->m_TextureMatrix.GetOrtZ(), DPRIM_LINE);
GetRenderer()->DrawLabel(pDLight->m_Origin+pDLight->m_TextureMatrix.GetOrtZ(),1,"z");*/
if(GetCVars()->e_projector_exact_test)
{ // test
CCamera cam; // construct light camera
cam.SetPos(pDLight->m_Origin);
Vec3d Angles(pDLight->m_ProjAngles[1], 0, pDLight->m_ProjAngles[2]+90.0f);
cam.SetAngle(Angles);
cam.Init(1, 1, (pDLight->m_fLightFrustumAngle*2)/180.0f*PI, pDLight->m_fRadius, 1.0f, 0.1f);
cam.Update();
Vec3d vBoxMin,vBoxMax;
pEntityRender->GetRenderBBox(vBoxMin,vBoxMax);
if (!cam.IsAABBVisibleFast(AABB(vBoxMin,vBoxMax)))
continue;
}
else
{
Plane p;
p.CalcPlane( pDLight->m_Origin, pDLight->m_Origin+pDLight->m_TextureMatrix.GetOrtY(), pDLight->m_Origin-pDLight->m_TextureMatrix.GetOrtZ() );
if( p.DistFromPlane(vObjPos) + fObjRadius < 0 )
continue;
}
}
// find amount of light
float fDist = GetDistance(pDLight->m_Origin,vObjPos);
float fLightAmount = 1.f - (fDist-fObjRadius) / (pDLight->m_fRadius);
fLightAmount *=
(pDLight->m_Color.r+pDLight->m_Color.g+pDLight->m_Color.b)*0.333f +
(pDLight->m_SpecColor.r+pDLight->m_SpecColor.g+pDLight->m_SpecColor.b)*0.333f;
if(fLightAmount>0.05f)
{
// if entity is inside some area - allow lightsources only from this area
if(pEntityRender)
if((pDLight->m_Flags & DLF_THIS_AREA_ONLY) /*|| (pDLight->m_Flags & DLF_SUN)*/)
{
if(pEntityRender->GetEntityVisArea() && pDLight->m_pOwner!=(IEntityRender*)-1)
{
if( pDLight->m_pOwner && pDLight->m_pOwner->GetEntityRS() && pDLight->m_pOwner->m_pVisArea)
{
CVisArea * pLightArea = pDLight->m_pOwner->m_pVisArea;
if(pEntityRender->GetEntityVisArea() != pLightArea)
{ // try also portal volumes
bool bNearFound = pEntityRender->m_pVisArea->FindVisArea(pLightArea, 1, true);
if(!bNearFound)
continue; // areas do not much
}
}
else
continue; // outdoor lsource
}
else // entity is outside
if( pDLight->m_pOwner && pDLight->m_pOwner!=(IEntityRender*)-1 && pDLight->m_pOwner->GetEntityVisArea() && pDLight->m_pOwner!=(IEntityRender*)-1)
continue; // indoor lsource should not affect outdoor entity
}
DLightAmount la;
la.pDLight = pDLight;
la.fAmount = fLightAmount;
m_lstTmpDLA_MMFP.Add(la);
}
}
int nDLightMask = 0;
if(!m_lstTmpDLA_MMFP.Count())
return 0; // no lsources found
// sort by light amount
qsort(&m_lstTmpDLA_MMFP[0], m_lstTmpDLA_MMFP.Count(), sizeof(m_lstTmpDLA_MMFP[0]), C3DEngine__Cmp_LightAmount);
// limit number of affective light sources
for(int n=0; n<nMaxLightBitsNum && n<GetCVars()->e_max_entity_lights && n<m_lstTmpDLA_MMFP.Count(); n++)
{
LightsSet::iterator itLightsSet = m_setActiveLights.find(m_lstTmpDLA_MMFP[n].pDLight);
if(itLightsSet==m_setActiveLights.end())
{
GetRenderer()->EF_ADDDlight(m_lstTmpDLA_MMFP[n].pDLight);
m_setActiveLights.insert(m_lstTmpDLA_MMFP[n].pDLight);
}
const int nId = m_lstTmpDLA_MMFP[n].pDLight->m_Id;
nDLightMask |= (1<<nId);
if(pSelectedLights && n<nMaxSelectedLights)
pSelectedLights[n] = m_lstTmpDLA_MMFP[n].pDLight;
}
return nDLightMask;
}
void CLightManager::ClearFrameLights()
{
m_setActiveLights.clear();
}
const Vec3d &CLightEntity::GetPos(bool) const
{
return m_vPos;//m_pLight->m_Origin;
}
const Vec3d &CLightEntity::GetAngles(int) const
{
return m_pLight->m_ProjAngles;
}
void CLightEntity::GetRenderBBox(Vec3d &vMin,Vec3d &vMax)
{
vMin = m_pLight->m_Origin - Vec3d(m_pLight->m_fRadius,m_pLight->m_fRadius,m_pLight->m_fRadius);
vMax = m_pLight->m_Origin + Vec3d(m_pLight->m_fRadius,m_pLight->m_fRadius,m_pLight->m_fRadius);
}
float CLightEntity::GetRenderRadius(void) const
{
return m_pLight->m_fRadius;
}
float CLightEntity::GetMaxViewDist()
{
return GetRenderRadius()*GetCVars()->e_obj_view_dist_ratio*GetViewDistRatioNormilized();
}
CLightEntity::CLightEntity()
{
m_pEntityRenderState = Get3DEngine()->MakeEntityRenderState();
m_vPos.Set(0,0,0);
}
CLightEntity::~CLightEntity()
{
Get3DEngine()->FreeEntityRenderState(this);
((C3DEngine*)Get3DEngine())->FreeLightSourceComponents(m_pLight);
Get3DEngine()->UnRegisterEntity(this);
((C3DEngine*)Get3DEngine())->RemoveEntityLightSources(this);
delete m_pLight; m_pLight = NULL;
}

35
Cry3DEngine/LightMan.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef _LIGHTMAN_H_
#define _LIGHTMAN_H_
#include "Array2d.h"
#define LIGHT_GRID_SIZE 16
class CLightManager : public Cry3DEngineBase
{
typedef std::set<class CDLight*> LightsSet;
typedef std::map<int, LightsSet*> LightsMap;
LightsMap * m_arrLights;
public:
CLightManager();
~CLightManager();
void AddLight(CDLight*pLight);
void DeleteLight(CDLight*pLight);
void GetLightBounds(CDLight * pLight, int &min_x, int &min_y, int &max_x, int &max_y);
void GetLightsAffectingBBox(const Vec3d & vBoxMin, const Vec3d & vBoxMax, LightsSet*pOutputList);
int MakeLMaskFromPositionAndActivateLights( const Vec3d vObjPos, const float fObjRadius,
IEntityRender * pEntityRender, int nMaxLightBitsNum,
CDLight ** pSelectedLights, int nMaxSelectedLights);
struct DLightAmount{ CDLight * pDLight; float fAmount; };
list2<DLightAmount> m_lstTmpDLA_MMFP;
LightsSet m_setTmpDL_MMFP;
LightsSet m_setActiveLights;
void ClearFrameLights();
};
#endif // _LIGHTMAN_H_

5
Cry3DEngine/MSSCCPRJ.SCC Normal file
View File

@@ -0,0 +1,5 @@
SCC = This is a source code control file
[Cry3DEngine.vcproj]
SCC_Aux_Path = "P4SCC#perforce:1666##marcoc_code##PC018"
SCC_Project_Name = Perforce Project

535
Cry3DEngine/MatMan.cpp Normal file
View File

@@ -0,0 +1,535 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: MatMan.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: Material Manager Implementation
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "3dEngine.h"
#include "objman.h"
#include "irenderer.h"
CMatMan::CMatMan( )
{
}
CMatMan::~CMatMan()
{
int nNotUsed=0, nNotUsedParents=0;
for (MtlSet::iterator it = m_mtlSet.begin(); it != m_mtlSet.end(); ++it)
{
IMatInfo *pMtl = *it;
SShaderItem Sh = pMtl->GetShaderItem();
if(Sh.m_pShader)
{
Sh.m_pShader->Release();
Sh.m_pShader = 0;
}
if(Sh.m_pShaderResources)
{
Sh.m_pShaderResources->Release();
Sh.m_pShaderResources = 0;
}
pMtl->SetShaderItem( Sh );
if(!(pMtl->GetFlags()&MIF_CHILD))
if(!(pMtl->GetFlags()&MIF_WASUSED))
{
GetLog()->Log("Warning: CMatMan::~CMatMan: Material was loaded but never used: %s", pMtl->GetName());
nNotUsed += (pMtl->GetSubMtlCount()+1);
nNotUsedParents++;
}
if (pMtl->GetNumRefs() > 1)
{
//
GetLog()->Log("Warning: CMatMan::~CMatMan: Material %s is being referenced", pMtl->GetName());
}
}
if(nNotUsed)
GetLog()->Log("Warning: CMatMan::~CMatMan: %d(%d) of %d materials was not used in level",
nNotUsedParents, nNotUsed, m_mtlSet.size());
}
IMatInfo * CMatMan::CreateMatInfo( const char *sMtlName )
{
IMatInfo *pMatInfo = new CMatInfo;
m_mtlSet.insert( pMatInfo );
if (sMtlName)
{
pMatInfo->SetName( sMtlName );
m_mtlNameMap[sMtlName] = pMatInfo;
}
return pMatInfo;
}
void CMatMan::DeleteMatInfo(IMatInfo * pMatInfo)
{
// Delete sub materials if present.
/* Not needed for now..
if (pMatInfo)
{
CMatInfo *mtl = (CMatInfo*)pMatInfo;
if (mtl->pSubMtls)
{
// Delete all sub materials.
for (int i = 0; i < mtl->pSubMtls->size(); i++)
{
DeleteMatInfo( mtl->pSubMtls[i] );
}
}
}
*/
assert( pMatInfo );
pMatInfo->SetFlags( pMatInfo->GetFlags()|MIF_INVALID );
m_mtlNameMap.erase( pMatInfo->GetName() );
m_mtlSet.erase( pMatInfo );
}
//////////////////////////////////////////////////////////////////////////
void CMatMan::RenameMatInfo( IMatInfo *pMtl,const char *sNewName )
{
assert( pMtl );
m_mtlNameMap.erase( pMtl->GetName() );
pMtl->SetName( sNewName );
m_mtlNameMap[sNewName] = pMtl;
}
//////////////////////////////////////////////////////////////////////////
IMatInfo* CMatMan::FindMatInfo( const char *sMtlName ) const
{
IMatInfo *pMtl = stl::find_in_map( m_mtlNameMap,sMtlName, (IMatInfo *)NULL );
return pMtl;
}
//////////////////////////////////////////////////////////////////////////
void CMatMan::LoadMaterialsLibrary( const char *sMtlFile,XmlNodeRef &levelDataRoot )
{
GetLog()->UpdateLoadingScreen("\003Loading materials ...");
// load environment settings
if (!levelDataRoot)
return;
XmlNodeRef mtlLibs = levelDataRoot->findChild( "MaterialsLibrary" );
if (mtlLibs)
{
// Enmerate material libraries.
for (int i = 0; i < mtlLibs->getChildCount(); i++)
{
XmlNodeRef mtlLib = mtlLibs->getChild(i);
XmlString libraryName = mtlLib->getAttr( "Name" );
for (int j =0; j < mtlLib->getChildCount(); j++)
{
XmlNodeRef mtlNode = mtlLib->getChild(j);
LoadMaterial( mtlNode,libraryName.c_str(),0 );
}
}
}
//////////////////////////////////////////////////////////////////////////
// Loading from external materials.xml file.
//////////////////////////////////////////////////////////////////////////
mtlLibs = GetSystem()->LoadXmlFile( sMtlFile );
if (mtlLibs)
{
// Enmerate material libraries.
for (int i = 0; i < mtlLibs->getChildCount(); i++)
{
XmlNodeRef mtlLib = mtlLibs->getChild(i);
if (!mtlLib->isTag("Library"))
continue;
XmlString libraryName = mtlLib->getAttr( "Name" );
for (int j =0; j < mtlLib->getChildCount(); j++)
{
XmlNodeRef mtlNode = mtlLib->getChild(j);
LoadMaterial( mtlNode,libraryName.c_str(),0 );
}
}
}
/*
// Load level data xml.
if (pDoc->load(Get3DEngine()->GetFilePath("LevelData.xml")))
{
XDOM::IXMLDOMNodeListPtr pLibsNode = pDoc->getElementsByTagName("MaterialsLibrary");
if (pLibsNode)
{
pLibsNode->reset();
XDOM::IXMLDOMNodePtr pLibNode;
while (pLibNode = pLibsNode->nextNode())
{
// For each library.
const char *sLibraryName = "";
XDOM::IXMLDOMNodePtr pName = pLibNode->getAttribute("Name");
if (pName)
sLibraryName = pName->getText();
/*
// Enumerate library.
XDOM::IXMLDOMNodeListPtr pMtlsListNode = pLibNode->getElementsByTagName("Material");
XDOM::IXMLDOMNodePtr pMtlNode;
pMtlsListNode->reset();
while (pMtlNode = pMtlListNode->nextNode())
{
// For each material.
LoadMaterial( pMtlNode,sLibraryName,0 );
}
}
}
}
*/
GetLog()->UpdateLoadingScreenPlus("\003 %d mats loaded", m_mtlSet.size());
}
static struct
{
int texId;
const char *name;
} sUsedTextures[] =
{
{ EFTT_DIFFUSE, "Diffuse" },
{ EFTT_GLOSS, "Specular" },
{ EFTT_BUMP, "Bumpmap" },
{ EFTT_NORMALMAP, "Normalmap" },
{ EFTT_CUBEMAP, "Cubemap" },
{ EFTT_DETAIL_OVERLAY,"Detail" },
{ EFTT_OPACITY, "Opacity" },
{ EFTT_DECAL_OVERLAY, "Decal" },
{ EFTT_SUBSURFACE, "SubSurface" },
};
inline CFColor ToCFColor( const Vec3 &col ) { return CFColor(col); }
//////////////////////////////////////////////////////////////////////////
IMatInfo* CMatMan::LoadMaterial( XmlNodeRef node,const char *sLibraryName,IMatInfo* pParent )
{
XmlString name,mtlName,shaderName,texmap,file;
int mtlFlags = 0;
unsigned int nShaderGenMask = 0;
SInputShaderResources sr;
SLightMaterial lm;
// Make new mat info.
mtlName = node->getAttr( "Name" );
if (pParent)
{
name = XmlString(pParent->GetName());
name += mtlName;
}
else
{
// Combine library name with item name to form a fully specified material name.
name = sLibraryName;
name += ".";
name += mtlName;
}
IMatInfo* pMtl = CreateMatInfo( name.c_str() );
if (pParent)
{
// Add as sub material if have parent.
pParent->AddSubMtl(pMtl);
}
// Loading from Material XML node.
shaderName = node->getAttr( "Shader" );
if (shaderName.empty())
{
// Replace empty shader with NoDraw shader.
shaderName = "NoDraw";
}
node->getAttr( "MtlFlags",mtlFlags );
node->getAttr( "GenMask",nShaderGenMask );
// Load lighting data.
Vec3 ambient,diffuse,specular,emissive;
node->getAttr( "Ambient",ambient );
node->getAttr( "Diffuse",diffuse );
node->getAttr( "Specular",specular );
node->getAttr( "Emissive",emissive );
node->getAttr( "Shininess",lm.Front.m_SpecShininess );
lm.Front.m_Ambient = ToCFColor(ambient);
lm.Front.m_Diffuse = ToCFColor(diffuse);
lm.Front.m_Specular = ToCFColor(specular);
lm.Front.m_Emission = ToCFColor(emissive);
node->getAttr( "Opacity",sr.m_Opacity );
node->getAttr( "AlphaTest",sr.m_AlphaRef );
// Load material textures.
XmlNodeRef texturesNode = node->findChild( "Textures" );
if (texturesNode)
{
for (int i = 0; i < texturesNode->getChildCount(); i++)
{
texmap = "";
XmlNodeRef texNode = texturesNode->getChild(i);
texmap = texNode->getAttr( "Map" );
int texId = -1;
for (int j = 0; j < sizeof(sUsedTextures)/sizeof(sUsedTextures[0]); j++)
{
if (stricmp(sUsedTextures[j].name,texmap) == 0)
{
texId = sUsedTextures[j].texId;
break;
}
}
if (texId < 0)
continue;
file = "";
file = texNode->getAttr( "File" );
// Correct texid found.
sr.m_Textures[texId].m_Name = file;
texNode->getAttr( "Amount",sr.m_Textures[texId].m_Amount );
texNode->getAttr( "IsTileU",sr.m_Textures[texId].m_bUTile );
texNode->getAttr( "IsTileV",sr.m_Textures[texId].m_bVTile );
texNode->getAttr( "TexType",sr.m_Textures[texId].m_TU.m_eTexType );
XmlNodeRef modNode = texNode->findChild( "TexMod" );
if (modNode)
{
SEfTexModificator &texm = sr.m_Textures[texId].m_TexModificator;
// Modificators
modNode->getAttr( "TileU",texm.m_Tiling[0] );
modNode->getAttr( "TileV",texm.m_Tiling[1] );
modNode->getAttr( "OffsetU",texm.m_Offs[0] );
modNode->getAttr( "OffsetV",texm.m_Offs[1] );
modNode->getAttr( "TexType",sr.m_Textures[texId].m_TU.m_eTexType );
float f;
modNode->getAttr( "TexMod_bTexGenProjected",texm.m_bTexGenProjected );
modNode->getAttr( "TexMod_UOscillatorType",texm.m_eUMoveType );
modNode->getAttr( "TexMod_VOscillatorType",texm.m_eVMoveType );
modNode->getAttr( "TexMod_RotateType",texm.m_eRotType );
modNode->getAttr( "TexMod_TexGenType",texm.m_eTGType );
if (modNode->getAttr( "RotateU",f ))
texm.m_Rot[0] = Degr2Word(f);
if (modNode->getAttr( "RotateV",f ))
texm.m_Rot[1] = Degr2Word(f);
if (modNode->getAttr( "RotateW",f ))
texm.m_Rot[2] = Degr2Word(f);
if (modNode->getAttr( "TexMod_URotateRate",f ))
texm.m_RotOscRate[0] = Degr2Word(f);
if (modNode->getAttr( "TexMod_VRotateRate",f ))
texm.m_RotOscRate[1] = Degr2Word(f);
if (modNode->getAttr( "TexMod_WRotateRate",f ))
texm.m_RotOscRate[2] = Degr2Word(f);
if (modNode->getAttr( "TexMod_URotatePhase",f ))
texm.m_RotOscPhase[0] = Degr2Word(f);
if (modNode->getAttr( "TexMod_VRotatePhase",f ))
texm.m_RotOscPhase[1] = Degr2Word(f);
if (modNode->getAttr( "TexMod_WRotatePhase",f ))
texm.m_RotOscPhase[2] = Degr2Word(f);
if (modNode->getAttr( "TexMod_URotateAmplitude",f ))
texm.m_RotOscAmplitude[0] = Degr2Word(f);
if (modNode->getAttr( "TexMod_VRotateAmplitude",f ))
texm.m_RotOscAmplitude[1] = Degr2Word(f);
if (modNode->getAttr( "TexMod_WRotateAmplitude",f ))
texm.m_RotOscAmplitude[2] = Degr2Word(f);
modNode->getAttr( "TexMod_URotateCenter",texm.m_RotOscCenter[0] );
modNode->getAttr( "TexMod_VRotateCenter",texm.m_RotOscCenter[1] );
modNode->getAttr( "TexMod_WRotateCenter",texm.m_RotOscCenter[2] );
modNode->getAttr( "TexMod_UOscillatorRate",texm.m_UOscRate );
modNode->getAttr( "TexMod_VOscillatorRate",texm.m_VOscRate );
modNode->getAttr( "TexMod_UOscillatorPhase",texm.m_UOscPhase );
modNode->getAttr( "TexMod_VOscillatorPhase",texm.m_VOscPhase );
modNode->getAttr( "TexMod_UOscillatorAmplitude",texm.m_UOscAmplitude );
modNode->getAttr( "TexMod_VOscillatorAmplitude",texm.m_VOscAmplitude );
}
}
}
// Load sub materials.
XmlNodeRef childsNode = node->findChild( "SubMaterials" );
if (childsNode)
{
for (int i = 0; i < childsNode->getChildCount(); i++)
{
XmlNodeRef mtlNode = childsNode->getChild(i);
LoadMaterial( mtlNode,sLibraryName,pMtl );
}
}
//////////////////////////////////////////////////////////////////////////
// Load public parameters.
//////////////////////////////////////////////////////////////////////////
XmlNodeRef publicsNode = node->findChild( "PublicParams" );
//////////////////////////////////////////////////////////////////////////
// Reload shader item with new resources and shader.
//////////////////////////////////////////////////////////////////////////
LoadMaterialShader( pMtl,shaderName.c_str(),mtlFlags,nShaderGenMask,sr,lm,publicsNode );
static int nTic=0;
if((++nTic%10)==0)
GetConsole()->TickProgressBar();
return pMtl;
}
//////////////////////////////////////////////////////////////////////////
// Material flags from Editor.
//////////////////////////////////////////////////////////////////////////
enum EMtlFlagsFromXml
{
MF_WIRE = 0x0001,
MF_2SIDED = 0x0002,
MF_ADDITIVE = 0x0004,
MF_ADDITIVE_DECAL = 0x0008,
MF_LIGHTING = 0x0010,
MF_NOSHADOW = 0x0020,
};
//////////////////////////////////////////////////////////////////////////
bool CMatMan::LoadMaterialShader( IMatInfo *pMtl,const char *sShader,int mtlFlags,unsigned int nShaderGenMask,SInputShaderResources &sr,SLightMaterial &lm,XmlNodeRef &publicsNode )
{
// Mark material invalid by default.
pMtl->SetFlags( pMtl->GetFlags()|MIF_INVALID );
if (mtlFlags & MF_LIGHTING)
sr.m_LMaterial = &lm;
else
sr.m_LMaterial = 0;
if (mtlFlags & MF_NOSHADOW)
pMtl->SetFlags( pMtl->GetFlags()|MIF_NOCASTSHADOWS );
sr.m_ResFlags = 0;
if (mtlFlags & MF_WIRE)
sr.m_ResFlags |= MTLFLAG_WIRE;
if (mtlFlags & MF_2SIDED)
sr.m_ResFlags |= MTLFLAG_2SIDED;
if (mtlFlags & MF_ADDITIVE)
sr.m_ResFlags |= MTLFLAG_ADDITIVE;
if (mtlFlags & MF_ADDITIVE_DECAL)
sr.m_ResFlags |= MTLFLAG_ADDITIVEDECAL;
/*
sr.m_ShaderParams.clear();
for (int i = 0; i < m_shaderParams.size(); i++)
{
sr.m_ShaderParams.push_back( m_shaderParams[i] );
}
*/
IShader *pTemplShader = 0;
// If we have public parameters, first load shader and parse public parameters.
if (publicsNode)
{
pTemplShader = GetSystem()->GetIRenderer()->EF_LoadShader( sShader,eSH_Misc,0,nShaderGenMask );
TArray<SShaderParam> &params = pTemplShader->GetPublicParams();
if (!params.empty())
{
// Parse public parameters, and assign them to source shader resources.
ParsePublicParams( params,publicsNode );
sr.m_ShaderParams.Reserve( params.size() );
for (unsigned int i = 0; i < params.size(); i++)
{
sr.m_ShaderParams.push_back(params[i]);
}
}
}
// Shader container name does not support '.', replace it with different character.
char sContainerName[1024];
strncpy( sContainerName,pMtl->GetName(),sizeof(sContainerName) );
sContainerName[sizeof(sContainerName)-1] = 0;
std::replace( sContainerName,sContainerName+strlen(sContainerName),'.','_' );
int nQBM = 0;
ICVar * pIVar = GetConsole()->GetCVar("r_Quality_BumpMapping");
if(pIVar)
nQBM = pIVar->GetIVal();
if ((GetSystem()->GetIRenderer()->GetFeatures() & RFT_HW_MASK) == RFT_HW_GF2 || nQBM == 0)
{
SLightMaterial mtl;
sr.m_LMaterial = &mtl;
}
SShaderItem shaderItem = GetSystem()->GetIRenderer()->EF_LoadShaderItem( "MaterialContainer",eSH_Misc,true,sShader,0,&sr,nShaderGenMask );
if (!shaderItem.m_pShader)
{
Warning( 0,0,"Failed to load shader %s in Material %s",sShader,sContainerName );
return false;
}
pMtl->SetShaderItem( shaderItem );
// If material shader was loaded successfully mark it as valid again.
pMtl->SetFlags( pMtl->GetFlags()&(~MIF_INVALID) );
if (pTemplShader)
{
// Release templ shader reference.
pTemplShader->Release();
}
return true;
}
//////////////////////////////////////////////////////////////////////////
void CMatMan::ParsePublicParams( TArray<SShaderParam> &params,XmlNodeRef paramsNode )
{
// Load shader params from xml node.
// Initialize shader params if thier number is changed.
if (params.empty())
return;
for (unsigned int i = 0; i < params.size(); i++)
{
SShaderParam *pParam = &params[i];
switch (pParam->m_Type)
{
case eType_BYTE:
paramsNode->getAttr( pParam->m_Name,pParam->m_Value.m_Byte );
break;
case eType_SHORT:
paramsNode->getAttr( pParam->m_Name,pParam->m_Value.m_Short );
break;
case eType_INT:
paramsNode->getAttr( pParam->m_Name,pParam->m_Value.m_Int );
break;
case eType_FLOAT:
paramsNode->getAttr( pParam->m_Name,pParam->m_Value.m_Float );
break;
//case eType_STRING:
//paramsNode->getAttr( pParam->m_Name,pParam->m_Value.m_String );
//break;
case eType_FCOLOR:
{
Vec3 v(pParam->m_Value.m_Color[0],pParam->m_Value.m_Color[1],pParam->m_Value.m_Color[2]);
paramsNode->getAttr( pParam->m_Name,v );
pParam->m_Value.m_Color[0] = v.x;
pParam->m_Value.m_Color[1] = v.y;
pParam->m_Value.m_Color[2] = v.z;
}
break;
case eType_VECTOR:
{
Vec3 v(pParam->m_Value.m_Vector[0],pParam->m_Value.m_Vector[1],pParam->m_Value.m_Vector[2]);
paramsNode->getAttr( pParam->m_Name,v );
pParam->m_Value.m_Vector[0] = v.x;
pParam->m_Value.m_Vector[1] = v.y;
pParam->m_Value.m_Vector[2] = v.z;
}
break;
}
}
}

1076
Cry3DEngine/Meshidx.cpp Normal file

File diff suppressed because it is too large Load Diff

125
Cry3DEngine/Node.cpp Normal file
View File

@@ -0,0 +1,125 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: node.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: loading node info from cgf
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Node.h"
#include "Geom.h"
#include "file.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CNodeCGF::CNodeCGF() : CBaseObj()
{
m_pObj = NULL;
// m_sPropStr = NULL;
// m_ppChildren = NULL;
// m_pnChildrenIds= NULL;
m_pParent = NULL;
// m_pMtl = NULL;
// m_pConRot = NULL;
// m_pConPos = NULL;
// m_pConScl = NULL;
memset(&m_Chunk,0,sizeof(m_Chunk));
}
CNodeCGF::~CNodeCGF()
{
// if(m_ppChildren) free(m_ppChildren);
// if(m_pnChildrenIds) free(m_pnChildrenIds);
// if(m_sPropStr) free(m_sPropStr);
}
bool CNodeCGF::Load(CXFile *f, int pos)
{
if(f->FSeek(pos,SEEK_SET)) return true;
int res=f->FRead(&m_Chunk,sizeof(m_Chunk),1);
if(res!=1) return true;
if(m_Chunk.chdr.ChunkType != ChunkType_Node || m_Chunk.chdr.ChunkVersion != NODE_CHUNK_DESC_VERSION)
{
memset(&m_Chunk,0,sizeof(m_Chunk));
return true;
}
m_ChunkHeader=m_Chunk.chdr;
// m_NodeMatrix = m_Chunk.tm;
//read propstr
/* if(m_Chunk.PropStrLen)
{
m_sPropStr=(char*)malloc(m_Chunk.PropStrLen+1);
assert(m_sPropStr);
res=f->FRead(m_sPropStr,m_Chunk.PropStrLen,1);
m_sPropStr[m_Chunk.PropStrLen]=0;
if(res!=1) return true;
}*/
//read m_ppChildren
/* if(m_Chunk.nChildren)
{
m_pnChildrenIds = (int*) malloc(m_Chunk.nChildren*sizeof(int));
assert(m_pnChildrenIds);
m_ppChildren = (CNodeCGF **) malloc(m_Chunk.nChildren*sizeof(CNodeCGF*));
assert(m_pnChildrenIds);
memset(m_ppChildren,0,m_Chunk.nChildren*sizeof(CNodeCGF*));
int res=f->FRead(m_pnChildrenIds,sizeof(int),m_Chunk.nChildren);
if(res!=m_Chunk.nChildren) return true;
}*/
return false;
}
void CNodeCGF::Bind(CBaseObj ** all_objects, int n_obj)
{
if(m_bBinded)
return;
for(int i=0;i<n_obj;i++)
{
CBaseObj * o = all_objects[i];
if(!o || o->m_ChunkHeader.ChunkID == -1)
continue;
if(o->m_ChunkHeader.ChunkID == m_Chunk.ObjectID)
{
m_pObj = o;
o->m_nUsers++;
}
else if(o->m_ChunkHeader.ChunkID == m_Chunk.ParentID)
m_pParent=(CNodeCGF *)o; /*
else if(o->m_ChunkHeader.ChunkID == m_Chunk.MatID)
m_pMtl=o;
else if(o->m_ChunkHeader.ChunkID == m_Chunk.pos_cont_id)
m_pConPos=(Controller *)o;
else if(o->m_ChunkHeader.ChunkID == m_Chunk.rot_cont_id)
m_pConRot=(Controller *)o;
else if(o->m_ChunkHeader.ChunkID == m_Chunk.scl_cont_id)
m_pConScl=(Controller *)o;
for(int j=0;j<m_Chunk.nChildren;j++)
{
if(o->m_ChunkHeader.ChunkID == m_pnChildrenIds[j])
m_ppChildren[j]=(CNodeCGF *)o;
}*/
}
m_bBinded = true;
}

51
Cry3DEngine/Node.h Normal file
View File

@@ -0,0 +1,51 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: node.h
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_NODE_H__8DFD8741_DBA1_4357_9F50_8E37EA039BCB__INCLUDED_)
#define AFX_NODE_H__8DFD8741_DBA1_4357_9F50_8E37EA039BCB__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "BaseObj.h"
class Controller;
class CNodeCGF : public CBaseObj
{
public:
NODE_CHUNK_DESC m_Chunk;
// int *m_pnChildrenIds;
CBaseObj *m_pObj;
/* char *m_sPropStr;
CNodeCGF ** m_ppChildren;*/
CNodeCGF *m_pParent;
/*CBaseObj *m_pMtl;
Controller *m_pConPos,*m_pConRot,*m_pConScl;*/
// CryMatrix m_NodeMatrix;
CNodeCGF();
virtual ~CNodeCGF();
virtual bool Load(CXFile *f, int pos);
virtual void Bind(CBaseObj **all_objects, int n_obj);
char * GetName() { return m_Chunk.name; }
float * GetMatrixData() { return m_Chunk.tm.GetData(); }
};
#endif // !defined(AFX_NODE_H__8DFD8741_DBA1_4357_9F50_8E37EA039BCB__INCLUDED_)

922
Cry3DEngine/ObjMan.cpp Normal file
View File

@@ -0,0 +1,922 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: statobjman.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: Loading trees, buildings, ragister/unregister entities for rendering
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "StatObj.h"
#include "objman.h"
#include "visareas.h"
#include "terrain_sector.h"
#include "cbuffer.h"
#include "3DEngine.h"
#include "meshidx.h"
#include "watervolumes.h"
#include "brush.h"
#include "LMCompStructures.h"
double CObjManager::m_dMakeObjectTime = 0;
double CObjManager::m_dCIndexedMesh__LoadMaterial = 0;
double CObjManager::m_dUpdateCustomLightingSpritesAndShadowMaps = 0;
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// Register / Unregister in sectors
//////////////////////////////////////////////////////////////////////////////////////////////////////////
void CObjManager::RegisterEntity( IEntityRender * pEntityRS )
{
if (!m_pTerrain)
return;
const char * szClass = pEntityRS->GetEntityClassName();
const char * szName = pEntityRS->GetName();
if(!szName[0] && !szClass[0])
return; // do not register undefined objects
// if(strstr(szName, "Merc"))
// int y=0;
// if(strstr(szName, "Player"))
// int y=0;
int nStatic = (pEntityRS->GetEntityRenderType() != eERType_Unknown);
// if draw near - register only in sector (0,0)
// if current sector will not be visible - weapon will be drawn from sector (0,0)
ICryCharInstance * cmodel = pEntityRS->GetEntityCharacter(0);
if (cmodel && (cmodel->GetFlags() & CS_FLAG_DRAW_MODEL) && (cmodel->GetFlags() & CS_FLAG_DRAW_NEAR))
{
list2<IEntityRender*> * pList = &m_pTerrain->m_arrSecInfoTable[0][0]->m_lstEntities[nStatic];
if(pList->Find(pEntityRS)<0)
pList->Add(pEntityRS);
pEntityRS->m_pSector = m_pTerrain->m_arrSecInfoTable[0][0];
pEntityRS->m_pVisArea = NULL;
return;
}
// find pos in sectors array
Vec3d vBMin,vBMax;
pEntityRS->GetRenderBBox(vBMin,vBMax);
Vec3d vCenter = (vBMin+vBMax)*0.5f;
/*
if(nStatic && vBMax.z<m_pTerrain->GetZSafe(vCenter.x,vCenter.y))
Warning(0,pEntityRS->GetName(),"%s is placed under the ground and not inside vis area: "
"pos=%.2f,%.2f,%.2f, "
"terrain elevation is %.2f, "
"object name is %s",
(pEntityRS->GetEntityRenderType()==eERType_Vegetation) ? "Vegetation" : "Brush",
pEntityRS->GetPos().x, pEntityRS->GetPos().y, pEntityRS->GetPos().z,
m_pTerrain->GetZSafe(vCenter.x,vCenter.y),
pEntityRS->GetName());
*/
// if(strstr(szName, "Player"))
// int y=0;
/*
if(pEntityRS->GetRndFlags()&ERF_CASTSHADOWVOLUME)
{ // adjust bbox by shadow
Vec3d vShadowOffset = m_p3DEngine->GetSunPosition().Normalized()*pEntityRS->GetRadius();
Vec3d vBoxMin2 = vBoxMin-vShadowOffset;
Vec3d vBoxMax2 = vBoxMax-vShadowOffset;
vBoxMin.CheckMin(vBoxMin2);
vBoxMax.CheckMax(vBoxMax2);
}
*/
// get 2d pos in sectors array
int x = (int)(((vCenter.x)/CTerrain::GetSectorSize()));
int y = (int)(((vCenter.y)/CTerrain::GetSectorSize()));
// if outside of the map, or too big - register in sector (0,0)
if( vCenter.x<0 || vCenter.y<0 ||
x<0 || x>=CTerrain::GetSectorsTableSize() || y<0 || y>=CTerrain::GetSectorsTableSize() ||
(vBMax.x - vBMin.x)>TERRAIN_SECTORS_MAX_OVERLAPPING*2 || (vBMax.y - vBMin.y)>TERRAIN_SECTORS_MAX_OVERLAPPING*2)
x = y = 0;
CSectorInfo * & pSector = pEntityRS->m_pSector;
if(pSector)
UnRegisterEntity( pEntityRS );
pSector = m_pTerrain->m_arrSecInfoTable[x][y];
// add if not added
if(pSector->m_lstEntities[nStatic].Find(pEntityRS)<0)
pSector->m_lstEntities[nStatic].Add(pEntityRS);
if(nStatic && pSector)
{
pSector->m_vBoxMin.CheckMin(vBMin);
pSector->m_vBoxMax.CheckMax(vBMax);
}
}
bool CObjManager::UnRegisterEntity( IEntityRender* pEntityRS )
{
if(!m_pTerrain)
return false;
#ifdef _DEBUG
const char * szName = pEntityRS->GetName();
if(strstr(szName, "Player"))
int y=0;
#endif // _DEBUG
bool bFound = false;
int nStatic = (pEntityRS->GetEntityRenderType() != eERType_Unknown);
// unregister objects outside of the map and 1 person weapon
if(m_pTerrain->m_arrSecInfoTable[0][0])
bFound |= m_pTerrain->m_arrSecInfoTable[0][0]->m_lstEntities[nStatic].Delete(pEntityRS);
// unregister from sectors
CSectorInfo * & pSector = pEntityRS->m_pSector;
if(!pSector)
return false;
// delete if found
bFound |= pSector->m_lstEntities[nStatic].Delete(pEntityRS);
if(nStatic)
{ // remove references to this entity
pSector->m_lstStaticShadowMapCasters.Delete(pEntityRS);
for(int i=0; i<pSector->m_lstStatEntInfoVegetNoCastersNoVolFog.Count(); i++)
if(pSector->m_lstStatEntInfoVegetNoCastersNoVolFog[i].m_pEntityRender == pEntityRS)
{
pSector->m_lstStatEntInfoVegetNoCastersNoVolFog.Delete(i);
i--;
}
for(int i=0; i<pSector->m_lstStatEntInfoOthers.Count(); i++)
if(pSector->m_lstStatEntInfoOthers[i].m_pEntityRender == pEntityRS)
{
pSector->m_lstStatEntInfoOthers.Delete(i);
i--;
}
}
pSector=0;
return bFound;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// Load static objects
//////////////////////////////////////////////////////////////////////////////////////////////////////////
bool CObjManager::LoadStaticObjectsFromXML()
{
XDOM::IXMLDOMNodeListPtr pVegetTagList;
XDOM::IXMLDOMNodePtr pVegetTag;
XDOM::IXMLDOMDocumentPtr pDoc = GetSystem()->CreateXMLDocument();
if(!pDoc->load(Get3DEngine()->GetLevelFilePath("LevelData.xml")))
return false;
pVegetTagList = pDoc->getElementsByTagName("Vegetation");
if (pVegetTagList)
{
pVegetTagList->reset();
pVegetTag = pVegetTagList->nextNode();
if (pVegetTag) // [marco] added this check - it was crashing here sometimes
{
XDOM::IXMLDOMNodeListPtr pVegetList;
pVegetList = pVegetTag->getElementsByTagName("Object");
if (pVegetList)
{
pVegetList->reset();
XDOM::IXMLDOMNodePtr pVeget;
int nGroupId=0;
while (pVeget = pVegetList->nextNode())
{
XDOM::IXMLDOMNodePtr pAlphaBlend = pVeget->getAttribute("AlphaBlend");
XDOM::IXMLDOMNodePtr pBending = pVeget->getAttribute("Bending");
XDOM::IXMLDOMNodePtr pBrightness = pVeget->getAttribute("Brightness");
XDOM::IXMLDOMNodePtr pCastShadow = pVeget->getAttribute("CastShadow");
XDOM::IXMLDOMNodePtr pFileName = pVeget->getAttribute("FileName");
XDOM::IXMLDOMNodePtr pHideable = pVeget->getAttribute("Hideable");
XDOM::IXMLDOMNodePtr pPhysNonColl = pVeget->getAttribute("PhysNonColl");
XDOM::IXMLDOMNodePtr pIndex = pVeget->getAttribute("Index");
XDOM::IXMLDOMNodePtr pPrecalcShadow = pVeget->getAttribute("PrecalcShadow");
XDOM::IXMLDOMNodePtr pRecvShadow = pVeget->getAttribute("RecvShadow");
XDOM::IXMLDOMNodePtr pSpriteDistRatio = pVeget->getAttribute("SpriteDistRatio");
XDOM::IXMLDOMNodePtr pShadowDistRatio = pVeget->getAttribute("ShadowDistRatio");
// XDOM::IXMLDOMNodePtr pUseLigthBit = pVeget->getAttribute("UseLigthBit");
// XDOM::IXMLDOMNodePtr pAmbScale = pVeget->getAttribute("AmbScale");
XDOM::IXMLDOMNodePtr pSpriteTexRes = pVeget->getAttribute("SpriteTexRes");
XDOM::IXMLDOMNodePtr pMaxViewDistRatio= pVeget->getAttribute("MaxViewDistRatio");
XDOM::IXMLDOMNodePtr pMaterialNode = pVeget->getAttribute("Material");
XDOM::IXMLDOMNodePtr pBackSideLevel = pVeget->getAttribute("BackSideLevel");
XDOM::IXMLDOMNodePtr pCalcLighting = pVeget->getAttribute("CalcLighting");
XDOM::IXMLDOMNodePtr pUseSprites = pVeget->getAttribute("UseSprites");
XDOM::IXMLDOMNodePtr pFadeSize = pVeget->getAttribute("FadeSize");
XDOM::IXMLDOMNodePtr pUpdateShadowEveryFrame = pVeget->getAttribute("RealTimeShadow");
{
IStatInstGroup siGroup;
if(pAlphaBlend)
siGroup.bUseAlphaBlending = atof(pAlphaBlend->getText()) != 0;
if(pBending)
siGroup.fBending = (float)atof(pBending->getText());
if(pBrightness)
siGroup.fBrightness = (float)atof(pBrightness->getText());
if(pCastShadow)
siGroup.bCastShadow = atof(pCastShadow->getText()) != 0;
if(pRecvShadow)
siGroup.bRecvShadow = atof(pRecvShadow->getText()) != 0;
if(pFileName)
siGroup.pStatObj = MakeObject(pFileName->getText(), NULL,
evs_ShareAndSortForCache, true, false, false );
if(siGroup.pStatObj)
siGroup.pStatObj->CheckValidVegetation();
if(siGroup.pStatObj && siGroup.pStatObj->GetLeafBuffer() && siGroup.pStatObj->GetLeafBuffer()->m_pMats && siGroup.pStatObj->GetLeafBuffer()->m_pMats->Count()>4)
GetLog()->Log("Warning: Number of materials in distributed object is %d",
siGroup.pStatObj->GetLeafBuffer()->m_pMats->Count());
if(pHideable)
siGroup.bHideability = atof(pHideable->getText()) != 0;
if(pPhysNonColl)
siGroup.bPhysNonColl = atof(pPhysNonColl->getText()) != 0;
if(pPrecalcShadow)
siGroup.bPrecShadow = atof(pPrecalcShadow->getText()) != 0;
if(pSpriteDistRatio)
siGroup.fSpriteDistRatio = (float)atof(pSpriteDistRatio->getText());
if(pShadowDistRatio)
siGroup.fShadowDistRatio = (float)atof(pShadowDistRatio->getText());
if(pMaxViewDistRatio)
siGroup.fMaxViewDistRatio = (float)atof(pMaxViewDistRatio->getText());
if(pSpriteTexRes)
siGroup.nSpriteTexRes = (int)atoi(pSpriteTexRes->getText());
if(pMaterialNode)
siGroup.pMaterial = Get3DEngine()->FindMaterial( pMaterialNode->getText() );
if(pBackSideLevel)
siGroup.fBackSideLevel = (float)atof(pBackSideLevel->getText());
if(pCalcLighting)
siGroup.bCalcLighting = atof(pCalcLighting->getText()) != 0;
if(pUseSprites)
siGroup.bUseSprites = atof(pUseSprites->getText()) != 0;
if(pFadeSize)
siGroup.bFadeSize = atof(pFadeSize->getText()) != 0;
if(pUpdateShadowEveryFrame)
siGroup.bUpdateShadowEveryFrame = atof(pUpdateShadowEveryFrame->getText()) != 0;
if(siGroup.pStatObj->GetLeafBuffer() && !((CStatObj*)siGroup.pStatObj)->IsSpritesCreated() && !GetSystem()->IsDedicated())
((CStatObj*)siGroup.pStatObj)->UpdateCustomLightingSpritesAndShadowMaps(m_vOutdoorAmbientColor, siGroup.nSpriteTexRes, siGroup.fBackSideLevel, siGroup.bCalcLighting );
((CStatObj*)siGroup.pStatObj)->FreeTriData(); // source geometry is needed only for stencil shadows
Get3DEngine()->SetStatInstGroup(nGroupId, siGroup);
nGroupId++;
}
}
}
}
}
return true;
}
IStatObj * CObjManager::GetStaticObjectByTypeID(int nTypeID)
{
if(nTypeID>=0 && nTypeID<m_lstStaticTypes.Count())
return m_lstStaticTypes[nTypeID].pStatObj;
return 0;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// Init / Release
//////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef _XBOX
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#else
#include <xtl.h>
#endif
#ifdef WIN64
#pragma warning( push ) //AMD Port
#pragma warning( disable : 4267 )
#endif
void CObjManager::LoadVegetationModels(const char *szMissionName,bool bEditorMode)
{
if(GetCVars()->e_vegetation)
{
int nCountStart = m_lstLoadedObjects.size();
float time = GetCurAsyncTimeSec();
LoadStaticObjectsFromXML();
UpdateLoadingScreen("%d of %d static objects loaded in %.2f seconds",
m_lstLoadedObjects.size()-nCountStart, m_lstLoadedObjects.size(), GetCurAsyncTimeSec()-time );
}
}
void CObjManager::UnloadVegetations()
{
// unload vegetation types
for(int i=0; i<m_lstStaticTypes.Count(); i++)
if( m_lstStaticTypes[i].GetStatObj() )
{
ReleaseObject( m_lstStaticTypes[i].GetStatObj() );
memset(&m_lstStaticTypes[i], 0, sizeof(m_lstStaticTypes[i]));
}
m_lstStaticTypes.Clear();
}
void CObjManager::CheckObjectLeaks(bool bDeleteAll)
{
// deleting leaked objects
if(m_lstLoadedObjects.size()>1)
GetLog()->Log("Warning: CObjManager::CheckObjectLeaks: %d object(s) found in memory", m_lstLoadedObjects.size());
for (ObjectsMap::iterator it = m_lstLoadedObjects.begin(); it != m_lstLoadedObjects.end(); ++it)
{
if(!(*it)->IsDefaultObject())
{
if((*it)->m_szGeomName[0])
GetLog()->Log("Warning: object not deleted: %s / %s", (*it)->m_szFileName, (*it)->m_szGeomName);
else
GetLog()->Log("Warning: object not deleted: %s", (*it)->m_szFileName);
}
if(bDeleteAll)
delete (*it);
}
if(bDeleteAll)
m_lstLoadedObjects.clear();
}
void CObjManager::UnloadObjects()
{
UnloadVegetations();
// delete leaked objects
CheckObjectLeaks(true);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// Create / delete object
//////////////////////////////////////////////////////////////////////////////////////////////////////////
CStatObj * CObjManager::MakeObject(const char * __szFileName,
const char * _szGeomName,
EVertsSharing eVertsSharing,
bool bLoadAdditinalInfo,
bool bKeepInLocalSpace,
bool bLoadLater)
{
AUTO_PROFILE_SECTION(GetTimer(), CObjManager::m_dMakeObjectTime);
if(!strcmp(__szFileName,"NOFILE"))
{ // make ampty object to be filled from outside
CStatObj * pObject = new CStatObj( );
pObject->RegisterUser();
m_lstLoadedObjects.insert(pObject);
return pObject;
}
assert(__szFileName && __szFileName[0]);
char szFileName[MAX_PATH_LENGTH];
// Normilize file name
char *pszDest=szFileName;
const char *pszSource=__szFileName;
while (*pszSource)
{
if (*pszSource=='/')
*pszDest++='\\';
else
*pszDest++=*pszSource;
pszSource++;
}
*pszDest=0;
if(strstr(szFileName,".ccgf"))
{
int nLen = strlen(szFileName);
strncpy(&szFileName[nLen-4],&szFileName[nLen-3],4);
}
// Construct tmp object for search
CStatObj tmp;
strcpy(tmp.m_szFileName, szFileName);
strcpy(tmp.m_szGeomName, _szGeomName ? _szGeomName : "");
tmp.m_bKeepInLocalSpace = bKeepInLocalSpace;
tmp.m_bLoadAdditinalInfo= bLoadAdditinalInfo;
tmp.m_eVertsSharing = eVertsSharing;
// tmp.m_bCalcLighting == s2->m_bCalcLighting);
// tmp.m_bMakePhysics == s2->m_bMakePhysics);
// Try to find already loaded object
if (!_szGeomName || !*_szGeomName || strcmp(_szGeomName,"cloth"))
{ // [Anton] - always use new cgf for objects used for cloth simulation
ObjectsMap::iterator it = m_lstLoadedObjects.find( &tmp );
if (it != m_lstLoadedObjects.end())
{
assert( stricmp((*it)->m_szFileName, szFileName)==0 && // compare file name
(!_szGeomName || stricmp((*it)->m_szGeomName, _szGeomName)==0)); // compare geom name
(*it)->RegisterUser();
return (*it);
}
// if ccfg was requested - change extension to cgf
tmp.m_szFileName[strlen(tmp.m_szFileName)-2]=0;
strcat(tmp.m_szFileName,"cgf");
// Try to find already loaded object
it = m_lstLoadedObjects.find( &tmp );
if (it != m_lstLoadedObjects.end())
{
assert( stricmp((*it)->m_szFileName, tmp.m_szFileName)==0 && // compare file name
(!_szGeomName || stricmp((*it)->m_szGeomName, _szGeomName)==0)); // compare geom name
(*it)->RegisterUser();
return (*it);
}
}
// Load new CGF
CStatObj * pObject = new CStatObj( );
if(!pObject->Load(szFileName, _szGeomName, eVertsSharing, bLoadAdditinalInfo, bKeepInLocalSpace, bLoadLater))
{
// object not found
// if geom name is specified - just return 0
if(_szGeomName && _szGeomName[0])
{
delete pObject;
return 0;
}
if (!m_pDefaultCGF)
GetConsole()->Exit ("Error: CObjManager::MakeObject: Default object not found");
// return default object
m_pDefaultCGF->RegisterUser();
delete pObject;
return m_pDefaultCGF;
}
// now try to load lods
pObject->LoadLowLODs(eVertsSharing,bLoadAdditinalInfo,bKeepInLocalSpace,bLoadLater);
// if(!bLoadLater && bGenSpritesAndShadowMap)
// pObject->UpdateCustomLightingSpritesAndShadowMaps(m_vOutdoorAmbientColor, 0, fBackSideLevel, bCalcLighting );
pObject->RegisterUser();
m_lstLoadedObjects.insert(pObject);
return pObject;
}
bool CObjManager::ReleaseObject(CStatObj * pObject)
{
// ObjectsMap::iterator it = m_lstLoadedObjects.find( pObject );
//if (it != m_lstLoadedObjects.end())
for (ObjectsMap::iterator it = m_lstLoadedObjects.begin(); it != m_lstLoadedObjects.end(); ++it)
if((CStatObj*)(*it) == pObject)
{
assert(pObject == (CStatObj*)(*it));
CStatObj* p = (CStatObj*)(*it);
pObject->UnregisterUser();
if(pObject->m_nUsers<=0 && !m_bLockCGFResources)
{
GetLog()->Log("Object unloaded: %s %s",pObject->m_szFileName, pObject->m_szGeomName);
m_lstLoadedObjects.erase(it);
#ifdef _DEBUG
// check that there is no other copies
// ObjectsMap::iterator it_test = m_lstLoadedObjects.find( pObject );
// assert(it_test == m_lstLoadedObjects.end());
for (ObjectsMap::iterator it2 = m_lstLoadedObjects.begin(); it2 != m_lstLoadedObjects.end(); ++it2)
assert((CStatObj*)(*it2) != pObject);
#endif
delete pObject;
}
return true;
}
return false; // not found
}
bool CObjManager::GetSectorBBox(list2<CStatObjInst> * stat_objects, Vec3d &sec_bbmin, Vec3d &sec_bbmax)
{
sec_bbmin=SetMaxBB();
sec_bbmax=SetMinBB();
for( int i=0; i<stat_objects->Count(); i++ )
{
CStatObjInst * o = &((*stat_objects)[i]);
if(o->m_nObjectTypeID>=m_lstStaticTypes.Count())
continue; // NOTE
if(!m_lstStaticTypes[o->m_nObjectTypeID].pStatObj)
continue; // NOTE
Vec3 ws_boxmin = m_lstStaticTypes[o->m_nObjectTypeID].GetStatObj()->m_vBoxMin*o->m_fScale;
Vec3 ws_boxmax = m_lstStaticTypes[o->m_nObjectTypeID].GetStatObj()->m_vBoxMax*o->m_fScale;
ws_boxmin += o->m_vPos;
ws_boxmax += o->m_vPos;
sec_bbmin.CheckMin(ws_boxmin);
sec_bbmax.CheckMax(ws_boxmax);
}
return stat_objects->Count()>0;
}
CObjManager::CObjManager(C3DEngine * p3DEngine):
m_pDefaultCGF (NULL)
{
m_p3DEngine = p3DEngine;
m_pTerrain=0;
m_fZoomFactor=1;
m_REFarTreeSprites = (CREFarTreeSprites*)GetRenderer()->EF_CreateRE(eDATA_FarTreeSprites);
m_fWindForce = 0.15f;
m_vOutdoorAmbientColor.Set(0,0,0);
m_vSunColor.Set(0,0,0);
m_pCoverageBuffer = new CCoverageBuffer(GetRenderer());
m_fMaxViewDistanceScale=1.f;
if( GetRenderer()->GetFeatures() & RFT_OCCLUSIONTEST )
m_pShaderOcclusionQuery = GetRenderer()->EF_LoadShader("OcclusionTest", eSH_World);
else
m_pShaderOcclusionQuery = 0;
m_pREClearStencil = (CREClearStencil*)GetRenderer()->EF_CreateRE(eDATA_ClearStencil);
m_pCWaterVolumes = 0;
CStatObjInst::m_pObjManager = this;
// prepare default object
m_pDefaultCGF = MakeObject("Objects\\default.cgf");
m_pDefaultCGF->m_bDefaultObject = true;
m_bLockCGFResources = false;
}
CObjManager::~CObjManager()
{
// free default object
ReleaseObject(m_pDefaultCGF);
m_pDefaultCGF=0;
// free brushes
assert(!m_lstBrushContainer.Count());
for(int i=0; i<m_lstBrushContainer.Count(); i++)
{
if(m_lstBrushContainer[i]->GetEntityStatObj(0))
ReleaseObject((CStatObj*)m_lstBrushContainer[i]->GetEntityStatObj(0));
delete m_lstBrushContainer[i];
}
m_lstBrushContainer.Reset();
UnloadObjects();
assert(m_lstLoadedObjects.size() == 0);
m_REFarTreeSprites->Release();
delete m_pCoverageBuffer;
m_pCoverageBuffer=0;
delete m_pCWaterVolumes;
m_pCWaterVolumes=0;
m_pREClearStencil->Release();
}
// update vertex lighting for satatic objects like trees
void CObjManager::UpdateCustomLighting(const Vec3d & vLight)
{
GetLog()->UpdateLoadingScreen("Updating lighting on vegetations ");
for(int i=0; i<m_lstStaticTypes.Count(); i++)
{
if(m_lstStaticTypes[i].GetStatObj())
{
m_lstStaticTypes[i].GetStatObj()->UpdateCustomLightingSpritesAndShadowMaps(m_vOutdoorAmbientColor,
m_lstStaticTypes[i].nSpriteTexRes, m_lstStaticTypes[i].fBackSideLevel, m_lstStaticTypes[i].bCalcLighting);
// if(!(i%4))
GetLog()->UpdateLoadingScreenPlus(".");
}
}
GetLog()->UpdateLoadingScreenPlus(" done");
}
// mostly xy size
float CObjManager::GetXYRadius(int type)
{
if((m_lstStaticTypes.Count()<=type || !m_lstStaticTypes[type].pStatObj))
return 0;
Vec3d vSize = m_lstStaticTypes[type].pStatObj->GetBoxMax() - m_lstStaticTypes[type].pStatObj->GetBoxMin();
vSize.z *= 0.5;
float fRadius = m_lstStaticTypes[type].pStatObj->GetRadius();
float fXYRadius = vSize.Length()*0.5f;
return fXYRadius;
}
bool CObjManager::GetStaticObjectBBox(int nType, Vec3d & vBoxMin, Vec3d & vBoxMax)
{
if((m_lstStaticTypes.Count()<=nType || !m_lstStaticTypes[nType].pStatObj))
return 0;
vBoxMin = m_lstStaticTypes[nType].pStatObj->GetBoxMin();
vBoxMax = m_lstStaticTypes[nType].pStatObj->GetBoxMax();
return true;
}
void CObjManager::AddPolygonToRenderer( const int nTexBindId,
IShader * pShader,
const int nDynLMask,
Vec3d right,
Vec3d up,
const UCol & ucResCol,
const ParticleBlendType eBlendType,
const Vec3d & vAmbientColor,
Vec3d vPos,
const SColorVert * pTailVerts,
const int nTailVertsNum,
const byte * pTailIndices,
const int nTailIndicesNum,
const float fSortId,
const int dwCCObjFlags,
IMatInfo * pCustomMaterial,
CStatObjInst * pStatObjInst,
list2<struct ShadowMapLightSourceInstance> * pShadowMapCasters)
{
if(pStatObjInst && pStatObjInst->m_fFinalBending)
{ // transfer decal into object space
Matrix44 objMat;
IStatObj * pEntObject = pStatObjInst->GetEntityStatObj(0, &objMat);
assert(pEntObject);
if(pEntObject)
{
objMat.Invert44();
vPos = objMat.TransformPointOLD(vPos);
right = objMat.TransformVectorOLD(right);
up = objMat.TransformVectorOLD(up);
}
}
// set positions and tex coords
SColorVert arrVerts[4];
arrVerts[0].vert = (-right-up) + vPos;
arrVerts[0].dTC[0] = 1;
arrVerts[0].dTC[1] = 0;
arrVerts[0].color = ucResCol;
arrVerts[1].vert = ( right-up) + vPos;
arrVerts[1].dTC[0] = 1;
arrVerts[1].dTC[1] = 1;
arrVerts[1].color = ucResCol;
arrVerts[2].vert = ( right+up) + vPos;
arrVerts[2].dTC[0] = 0;
arrVerts[2].dTC[1] = 1;
arrVerts[2].color = ucResCol;
arrVerts[3].vert = (-right+up) + vPos;
arrVerts[3].dTC[0] = 0;
arrVerts[3].dTC[1] = 0;
arrVerts[3].color = ucResCol;
if(nTexBindId <= 0 || nTexBindId >= 16384)
{
Warning( 0,0,"CObjManager::AddPolygonToRenderer: texture id is out of range: %d", nTexBindId);
return;
}
// calculate render state
uint nRenderState=0;
switch(eBlendType)
{
case ParticleBlendType_AlphaBased:
nRenderState = GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA | GS_ALPHATEST_GREATER0;
break;
case ParticleBlendType_ColorBased:
nRenderState = GS_BLSRC_ONE | GS_BLDST_ONEMINUSSRCCOL;
break;
case ParticleBlendType_Additive:
nRenderState = GS_BLSRC_ONE | GS_BLDST_ONE;
break;
}
// repeated objects are free imedeately in renderer
CCObject * pOb = GetIdentityCCObject();
if(pShadowMapCasters && pShadowMapCasters->Count())
{
pOb->m_pShadowCasters = pShadowMapCasters;
pOb->m_ObjFlags |= FOB_INSHADOW;
}
if(pStatObjInst && pStatObjInst->m_fFinalBending)
{
pStatObjInst->GetEntityStatObj(0,&pOb->m_Matrix);
pOb->m_ObjFlags |= FOB_TRANS_MASK;
CStatObj * pBody = m_lstStaticTypes[pStatObjInst->m_nObjectTypeID].GetStatObj();
assert(pBody);
if(pStatObjInst && pBody && pStatObjInst->m_fFinalBending)
pBody->SetupBending(pOb,pStatObjInst->m_fFinalBending);
}
pOb->m_DynLMMask = nDynLMask;
assert(nTexBindId>0);
pOb->m_NumCM = nTexBindId;
pOb->m_AmbColor = vAmbientColor;
pOb->m_RenderState = nRenderState;
if(GetRenderer()->EF_GetHeatVision())
pOb->m_ObjFlags |= FOB_HEATVISION;
pOb->m_ObjFlags |= dwCCObjFlags;
pOb->m_SortId = fSortId; // use m_SortId for sorting correction
pOb = GetRenderer()->EF_AddSpriteToScene(pShader->GetID(), 4, arrVerts, pOb);
if(pTailVerts && nTailVertsNum && pTailIndices && nTailIndicesNum)
GetRenderer()->EF_AddSpriteToScene(pShader->GetID(), nTailVertsNum,
(SColorVert*)pTailVerts, pOb, (byte*)pTailIndices, nTailIndicesNum);
}
int CObjManager::GetMemoryUsage(class ICrySizer * pSizer)
{
int nSize = 0;
nSize += lstEntList_MLSMCIA.GetMemoryUsage();
// nSize += lstStatInstList_MLSMCIA.GetMemoryUsage();
nSize += m_lstDebugEntityList.GetMemoryUsage();
nSize += m_lstStatEntitiesShadowMaps.GetMemoryUsage();
nSize += m_lstFarObjects[0].GetMemoryUsage();
nSize += m_lstFarObjects[1].GetMemoryUsage();
{
for(int i=0; i<MAX_LIGHTS_NUM; i++)
nSize += m_lstLightEntities[i].GetMemoryUsage();
// for(int i=0; i<MAX_LIGHTS_NUM; i++)
// nSize += m_lstShadowEntities[i].GetMemoryUsage();
}
nSize += m_lstLoadedObjects.size()*sizeof(CStatObj*);
for (ObjectsMap::iterator it = m_lstLoadedObjects.begin(); it != m_lstLoadedObjects.end(); ++it)
{
nSize += ((CStatObj*)(*it))->GetMemoryUsage();
nSize += sizeof(CStatObj);
}
nSize += m_lstStaticTypes.GetMemoryUsage();
// nSize += m_lstStatShadowsBuffer.GetMemoryUsage();
// nSize += m_lstTmpEntities_MESF.GetMemoryUsage();
nSize += m_lstTmpSectors_MELFP.GetMemoryUsage();
// nSize += m_lstTmpStatInstList_MESF.GetMemoryUsage();
/*
{
SIZER_COMPONENT_NAME(pSizer, "Brushes");
int nSizeBrushes=0;
nSizeBrushes += m_lstBrushContainer.GetMemoryUsage();
nSizeBrushes += m_lstBrushContainer.Count()*sizeof(CBrush);
pSizer->AddObject(&m_lstBrushContainer, nSizeBrushes);
{
SIZER_COMPONENT_NAME(pSizer, "BrushRS");
for(int i=0; i<m_lstBrushContainer.Count(); i++)
{
if(m_lstBrushContainer[i]->GetEntityRS())
pSizer->AddObject(m_lstBrushContainer[i]->GetEntityRS(), sizeof(*m_lstBrushContainer[i]->GetEntityRS()));
}
}
}
{
SIZER_COMPONENT_NAME(pSizer, "Veget");
int nSizeVeg=0;
nSizeVeg += m_lstVegetContainer.GetMemoryUsage();
nSizeVeg += m_lstVegetContainer.Count()*sizeof(CStatObjInst);
pSizer->AddObject(&m_lstVegetContainer, nSizeVeg);
{
SIZER_COMPONENT_NAME(pSizer, "VegetRS");
for(int i=0; i<m_lstVegetContainer.Count(); i++)
{
if(m_lstVegetContainer[i]->GetEntityRS())
pSizer->AddObject(m_lstVegetContainer[i]->GetEntityRS(), sizeof(*m_lstVegetContainer[i]->GetEntityRS()));
}
}
}
*/
nSize += sizeof(CDLight);
return nSize;
}
void CObjManager::ReregisterEntitiesInArea(Vec3d vBoxMin, Vec3d vBoxMax)
{
list2<IEntityRender*> lstEntitiesInArea;
if(m_pTerrain)
m_pTerrain->MoveAllEntitiesIntoList(&lstEntitiesInArea, vBoxMin, vBoxMax);
GetVisAreaManager()->MoveAllEntitiesIntoList(&lstEntitiesInArea, vBoxMin, vBoxMax);
int nChanged=0;
for(int i=0; i<lstEntitiesInArea.Count(); i++)
{
IVisArea * pPrevArea = lstEntitiesInArea[i]->GetEntityVisArea();
bool bFound = Get3DEngine()->UnRegisterEntity(lstEntitiesInArea[i]);
// assert(!bFound);
/* {
Get3DEngine()->Un RegisterInAllSectors(lstEntitiesInArea[i]);
bFound = Get3DEngine()->UnRegisterEntity(lstEntitiesInArea[i]);
if(lstEntitiesInArea[i]->IsStatic())
{
CBrush * pEnt = (CBrush *)lstEntitiesInArea[i];
Matrix mat;
CStatObj * pStatObj = (CStatObj*)lstEntitiesInArea[i]->GetEntityStatObj(0,&mat);
assert(CBrush::IsMatrixValid(mat));
}
}
*/
Get3DEngine()->RegisterEntity(lstEntitiesInArea[i]);
if(pPrevArea != lstEntitiesInArea[i]->GetEntityVisArea())
nChanged++;
}
GetLog()->Log(" CObjManager::ReregisterEntitiesInArea: %d of %d objects updated", nChanged, lstEntitiesInArea.Count());
}
/*
int CObjManager::CountPhysGeomUsage(CStatObj * pStatObjToFind)
{
int nRes=0;
for(int i=0; i<m_lstBrushContainer.Count(); i++)
{
CBrush * pBrush = m_lstBrushContainer[i];
IStatObj * pStatObj = pBrush->GetEntityStatObj(0);
// assert(((CStatObj*)pStatObj)->m_bStreamable);
if(pStatObjToFind == pStatObj)
{
if(pBrush->GetPhysGeomId(0)>=0 || pBrush->GetPhysGeomId(1)>=0)
nRes++;
}
}
return nRes;
}*/
#ifdef WIN64
#pragma warning( pop ) //AMD Port
#endif
void CObjManager::FreeNotUsedCGFs()
{
assert(!m_bLockCGFResources);
if (!m_bLockCGFResources)
{
//Timur, You MUST use next here, or with erase you invalidating
ObjectsMap::iterator next;
for (ObjectsMap::iterator it = m_lstLoadedObjects.begin(); it != m_lstLoadedObjects.end(); it = next)
{
next = it; next++;
CStatObj* p = (CStatObj*)(*it);
if(p->m_nUsers<=0)
{
GetLog()->Log("Object unloaded: %s %s",p->m_szFileName, p->m_szGeomName);
m_lstLoadedObjects.erase(it);
delete p;
}
}
}
}

269
Cry3DEngine/ObjMan.h Normal file
View File

@@ -0,0 +1,269 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: statobjman.h
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#ifndef CObjManager_H
#define CObjManager_H
#include "StatObj.h"
#include "../RenderDll/Common/shadow_renderer.h"
#include "terrain_sector.h"
#define ENTITY_MAX_DIST_FACTOR 100
struct CStatObj;
struct IIndoorBase;
struct IEntityRender;
struct ISystem;
class CStatObjInst;
class C3DEngine;
struct IMatInfo;
#define SMC_STATICS 1
#define SMC_DYNAMICS 2
#define SMC_ALLOW_PASSIVE_SHADOWMAP_CASTERS 4
//! contains stat obj instance group properies (vegetation object properties)
struct StatInstGroup : public IStatInstGroup
{
StatInstGroup() { pStatObj = 0; }
CStatObj * GetStatObj() { return (CStatObj*)pStatObj; }
void SetRndFlags()
{
m_dwRndFlags = 0;
if(bCastShadow)
m_dwRndFlags |= ERF_CASTSHADOWMAPS;
if(bRecvShadow)
m_dwRndFlags |= ERF_RECVSHADOWMAPS;
if(bPrecShadow)
m_dwRndFlags |= ERF_CASTSHADOWINTOLIGHTMAP;
if(bHideability)
m_dwRndFlags |= ERF_HIDABLE;
if(bPhysNonColl)
m_dwRndFlags |= ERF_PHYS_NONCOLL;
}
};
struct SExportedBrushMaterial
{
int size;
char material[64];
};
class CObjManager : public Cry3DEngineBase
{
public:
CObjManager(C3DEngine * p3DEngine);
~CObjManager();
void LoadVegetationModels(const char *szMissionName, bool bEditorMode);
void UnloadObjects();
void DrawFarObjects(float fMaxViewDist);
void RenderFarObjects();
void RegisterEntity( IEntityRender* pEntityRS );
bool UnRegisterEntity( IEntityRender* pEntityRS );
CStatObj * CObjManager::MakeObject(const char * __szFileName, const char * _szGeomName=0,
EVertsSharing eVertsSharing = evs_NoSharing,
bool bLoadAdditinalInfo = true,
bool bKeepInLocalSpace = false,
bool bLoadLater = false);
bool ReleaseObject(CStatObj * pObject);
bool GetSectorBBox(list2<CStatObjInst> * stat_objects, Vec3d &sec_bbmin, Vec3d &sec_bbmax);
list2<StatInstGroup> m_lstStaticTypes;
void MakeShadowMapInstancesList(IEntityRender * pEntityRS, float obj_distance,
list2<ShadowMapLightSourceInstance> * pLSourceInstances,
int dwAllowedTypes, CDLight * pLight);
float m_fZoomFactor;
CTerrain * m_pTerrain;
void UpdateCustomLighting(const Vec3d & vLight);
list2<CStatObjInst*> m_lstFarObjects[2];
protected:
struct string_less : public std::binary_function<CStatObj*,CStatObj*,bool>
{
bool operator()( CStatObj *s1,CStatObj *s2 ) const
{
int nFileCmpRes = stricmp(s1->m_szFileName,s2->m_szFileName);
if(!nFileCmpRes) // if file name is the same - compare just geom names
{
int nObjCmpRes = stricmp(s1->m_szGeomName,s2->m_szGeomName);
if(nObjCmpRes==0)
{
if(s1->m_eVertsSharing == s2->m_eVertsSharing)
{
assert(s1->m_bKeepInLocalSpace == s2->m_bKeepInLocalSpace);
// assert(s1->m_bMakePhysics == s2->m_bMakePhysics);
// assert(s1->m_bCalcLighting == s2->m_bCalcLighting);
return s1->m_bLoadAdditinalInfo < s2->m_bLoadAdditinalInfo;
}
return s1->m_eVertsSharing < s2->m_eVertsSharing;
}
return nObjCmpRes < 0;
}
return nFileCmpRes < 0;
}
};
typedef std::set<CStatObj*,string_less> ObjectsMap;
ObjectsMap m_lstLoadedObjects;
void InitFarState();
CREFarTreeSprites * m_REFarTreeSprites;
ShadowMapFrustum * MakeEntityShadowFrustum(ShadowMapFrustum * pFrustum,
ShadowMapLightSource * pLs, IEntityRender * pEntityRS, EShadowType nShadowType, int dwAllowedTypes);
list2<IEntityRender*> m_lstDebugEntityList;
void MakeShadowCastersList(IEntityRender * pEntityRS, list2<IEntityRender*> * pEntList,
int dwAllowedTypes, Vec3d vLightPos, float fLightRadius);
list2<CSectorInfo*> m_lstTmpSectors_MELFP;
#ifdef WIN64
#pragma warning( push ) //AMD Port
#pragma warning( disable : 4267 )
#endif
public:
int GetLoadedObjectCount() { return m_lstLoadedObjects.size(); }
#ifdef WIN64
#pragma warning( pop ) //AMD Port
#endif
void RenderObject( IEntityRender * o,
int nFogVolumeID, uint nDLightMask,
bool bLMapGeneration,
const CCamera & EntViewCamera,
Vec3d * pvAmbColor, Vec3d * pvDynAmbColor,
VolumeInfo * pFogVolume,
bool bNotAllInFrustum,
float fMaxViewDist, IEntityRenderInfo * pEntInfo = NULL);
float GetXYRadius(int nType);
bool GetStaticObjectBBox(int nType, Vec3d & vBoxMin, Vec3d & vBoxMax);
void DrawAllShadowsOnTheGroundInSector(list2<IEntityRender*> * pEntList);
float m_fWindForce; //!< used for bending plants
Vec3d m_vOutdoorAmbientColor; //!<
Vec3d m_vSunColor; //!<
IStatObj * GetStaticObjectByTypeID(int nTypeID);
float GetBendingRandomFactor();
C3DEngine * m_p3DEngine;
class CCoverageBuffer * m_pCoverageBuffer;
bool IsBoxOccluded(const Vec3d & vBoxMin, const Vec3d & vBoxMax, float fDistance, OcclusionTestClient * pOcclTestVars);
list2<IEntityRender*> m_lstStatEntitiesShadowMaps;
list2<IEntityRender*> m_lstEntitiesShadowSpots;
void RenderEntitiesShadowMapsOnTerrain(bool bLMapGeneration, class CREShadowMapGen * pREShadowMapGenerator);
void DrawEntitiesShadowSpotsOnTerrain();
void AddPolygonToRenderer(const int nTexBindId,
IShader * pShader,
const int nDynLMask,
Vec3d right,
Vec3d up,
const UCol & ucResCol,
const ParticleBlendType eBlendType,
const Vec3d & vAmbientColor,
Vec3d vPos,
const SColorVert * pTailVerts = NULL,
const int nTailVertsNum = 0,
const byte * pTailIndices = NULL,
const int nTailIndicesNum = 0,
const float fSortId = 0,
const int dwCCObjFlags = 0,
IMatInfo * pCustomMaterial = NULL,
CStatObjInst * pStatObjInst = NULL,
list2<struct ShadowMapLightSourceInstance> * pShadowMapCasters = NULL);
// tmp containers (replacement for local static vars)
list2<IEntityRender*> lstEntList_MLSMCIA;
void RenderEntityShadowOnTerrain(IEntityRender * pEntityRS, bool bLMapGeneration, CREShadowMapGen * pREShadowMapGenerator);
void DrawObjSpritesSorted(list2<CStatObjInst*> *pList, float fMaxViewDist, int useBending);
void ProcessActiveShadowReceiving(IEntityRender * pEnt, float fEntDistance, CDLight * pLight, bool bLMapGeneration);
void SetupEntityShadowMapping( IEntityRender * pEntityRS, SRendParams * pDrawParams, bool bLMapGeneration, float fEntDistance, CDLight * pDLight );
float m_fMaxViewDistanceScale;
IShader * m_pShaderOcclusionQuery;
bool LoadStaticObjectsFromXML();
CStatObj * m_pDefaultCGF;
#define MAX_LIGHTS_NUM 32
list2<IEntityRender*> m_lstLightEntities[MAX_LIGHTS_NUM];
void DrawEntitiesLightPass();
class CREClearStencil * m_pREClearStencil;
int GetMemoryUsage(class ICrySizer * pSizer);
struct CWaterVolumeManager * m_pCWaterVolumes;
float CalculateEntityShadowVolumeExtent(IEntityRender * pEntityRS, CDLight * pDLight);
list2<class CBrush*> m_lstBrushContainer;
list2<class CStatObjInst*> m_lstVegetContainer;
void LoadBrushes();
void MergeBrushes();
void ReregisterEntitiesInArea(Vec3d vBoxMin, Vec3d vBoxMax);
void ProcessEntityParticles(IEntityRender * pEntityRS, float fEntDistance);
void CheckUnload();
void PreloadNearObjects();
// time counters
static double m_dMakeObjectTime;
static double m_dCIndexedMesh__LoadMaterial;
static double m_dUpdateCustomLightingSpritesAndShadowMaps;
void MakeShadowBBox(Vec3d & vBoxMin, Vec3d & vBoxMax, const Vec3d & vLightPos, float fLightRadius, float fShadowVolumeExtent);
CFColor CalcShadowOnTerrainColor(float fAlpha, bool bLMapGeneration);
float GetSortOffset( const Vec3d & vPos, const Vec3d & vCamPos, float fUserWaterLevel = WATER_LEVEL_UNKNOWN );
void GetObjectsStreamingStatus(int & nReady, int & nTotalInStreaming, int & nTotal);
bool ProcessShadowMapCasting(IEntityRender * pEnt, CDLight * pDLight);
void UnloadVegetations();
void CheckObjectLeaks(bool bDeleteAll = false);
bool IsSphereAffectedByShadow(IEntityRender * pCaster, IEntityRender * pReceiver, CDLight * pLight);
void MakeShadowCastersListInArea(CBasicArea*pArea, IEntityRender * pReceiver,
list2<IEntityRender*> * pEntList, int dwAllowedTypes, Vec3d vLightPos, float fLightRadius);
void PrefechObjects();
void RequestEntityShadowMapGeneration(IEntityRender * pEntityRnd);
bool m_bLockCGFResources;
void FreeNotUsedCGFs();
void RenderObjectVegetationNonCastersNoFogVolume( IEntityRender * pEntityRS,uint nDLightMask,
const CCamera & EntViewCamera,
bool bNotAllInFrustum, float fMaxViewDist, IEntityRenderInfo * pEntInfo);
};
#endif // CObjManager_H

213
Cry3DEngine/ObjManDraw.cpp Normal file
View File

@@ -0,0 +1,213 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: statobjmandraw.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: Draw static objects (vegetations)
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "StatObj.h"
#include "objman.h"
#include "visareas.h"
#include "terrain_sector.h"
#include "3dengine.h"
#include "cbuffer.h"
bool CObjManager::IsBoxOccluded( const Vec3d & vBoxMin, const Vec3d & vBoxMax, float fDistance, OcclusionTestClient * pOcclTestVars )
{
FUNCTION_PROFILER_FAST( GetSystem(),PROFILE_3DENGINE,m_bProfilerEnabled );
assert(pOcclTestVars);
assert(fDistance>=0);
if(m_nRenderStackLevel)
return pOcclTestVars->bLastResult; // return result of base level test
if(pOcclTestVars->nLastVisibleFrameID < GetFrameID()-1)
{ // if was invisible last frames (because of frustum culling)
pOcclTestVars->ucOcclusionByObjectsFrames = 0; // force to test this frame
if(GetCVars()->e_terrain_occlusion_culling!=2)
pOcclTestVars->ucOcclusionByTerrainFrames = 0; // force to test this frame
}
{ // test occlusion by objects
if(!pOcclTestVars->ucOcclusionByObjectsFrames && fDistance>COVERAGEBUFFER_OCCLUSION_TESTERS_MIN_DISTANCE && GetCVars()->e_cbuffer)
{ // less distance do not work because objects are sorted wrong
if(!m_pCoverageBuffer->IsBBoxVisible(vBoxMin,vBoxMax))
{
pOcclTestVars->ucOcclusionByObjectsFrames = 0; // force to test next frame
pOcclTestVars->bLastResult = true;
return true;
}
}
pOcclTestVars->ucOcclusionByObjectsFrames += 4; // skip testing next frame
}
/*
{ // test occl by antiportals
if(GetVisAreaManager()->IsOccludedByOcclVolumes(vBoxMin,vBoxMax))
return true;
}
*/
{ // test occlusion by terrain
Vec3d vTopMax = vBoxMax;
Vec3d vTopMin = vBoxMin; vTopMin.z = vTopMax.z;
const Vec3d & vCamPos = GetViewCamera().GetPos();
vTopMax.CheckMin(Vec3d((float)CTerrain::GetTerrainSize(),(float)CTerrain::GetTerrainSize(),1024.f));
vTopMin.CheckMax(Vec3d(0,0,-1024.f));
vTopMin.CheckMin(Vec3d((float)CTerrain::GetTerrainSize(),(float)CTerrain::GetTerrainSize(),1024.f));
vTopMax.CheckMax(Vec3d(0,0,-1024.f));
if( !pOcclTestVars->ucOcclusionByTerrainFrames && GetCVars()->e_terrain_occlusion_culling )
{
int nMaxTestsToScip = (GetVisAreaManager()->m_pCurPortal) ? 3 : 10000;
// precision in meters for this object
float fMaxStep = fDistance*GetCVars()->e_terrain_occlusion_culling_precision;
if( (fMaxStep < (vTopMax.x - vTopMin.x)*2.f || fMaxStep < (vTopMax.y - vTopMin.y)*2.f) &&
// fDistance<700 &&
vBoxMin.x != vBoxMax.x && vBoxMin.y != vBoxMax.y )
{
bool bOccluded = true;
// todo: debug this
float dx = (vTopMax.x - vTopMin.x)*0.99999f;
while(dx>fMaxStep)
dx*=0.5f;
float dy = (vTopMax.y - vTopMin.y)*0.99999f;
while(dy>fMaxStep)
dy*=0.5f;
// todo: test only borders
for(float x=vTopMin.x; x<=vTopMax.x; x+=dx)
for(float y=vTopMin.y; y<=vTopMax.y; y+=dy)
{
if(!m_pTerrain->IsPointOccludedByTerrain(Vec3d(x, y, vTopMax.z), fDistance, vCamPos, nMaxTestsToScip))
{
bOccluded = false;
x=y=1000000;//break
}
}
if(bOccluded)
{
if(GetCVars()->e_terrain_occlusion_culling!=2)
pOcclTestVars->ucOcclusionByTerrainFrames = 0; // force to test next frame
pOcclTestVars->bLastResult = true;
return true;
}
}
else
{
Vec3d vTopMid = (vTopMin+vTopMax)*0.5f;
if( m_pTerrain->IsPointOccludedByTerrain(vTopMid, fDistance,vCamPos, nMaxTestsToScip))
{
if(GetCVars()->e_terrain_occlusion_culling!=2)
pOcclTestVars->ucOcclusionByTerrainFrames = 0; // force to test next frame
pOcclTestVars->bLastResult = true;
return true;
}
}
}
if(pOcclTestVars->ucOcclusionByTerrainFrames == 0) // && GetCVars()->e_terrain_occlusion_culling==3)
{ // randomize test time, do this only here otherwice ucOcclusionByTerrainFrames may never become 0 and next test will not happend
static int arrRnd[16] =
{
rand()%4+1, rand()%4+1, rand()%4+1, rand()%4+1,
rand()%4+1, rand()%4+1, rand()%4+1, rand()%4+1,
rand()%4+1, rand()%4+1, rand()%4+1, rand()%4+1,
rand()%4+1, rand()%4+1, rand()%4+1, rand()%4+1
};
static int nRndCounter = 0;
nRndCounter++;
if(nRndCounter>=16)
nRndCounter=0;
pOcclTestVars->ucOcclusionByTerrainFrames = arrRnd[nRndCounter]*4;
}
else
pOcclTestVars->ucOcclusionByTerrainFrames += 4; // skip testing next 64 frames
}
/* const Vec3d & vCamPos = GetViewCamera().GetPos();
bool bCameraInBBox =
vCamPos.x >= (vBoxMin.x-0.05f) && vCamPos.y >= (vBoxMin.y-0.05f) && vCamPos.z >= (vBoxMin.z-0.05f) &&
vCamPos.x <= (vBoxMax.x+0.05f) && vCamPos.y <= (vBoxMax.y+0.05f) && vCamPos.z <= (vBoxMax.z+0.05f);
// Make test only if camera outside of the box and if feature supported
if(fDistance>1 && !bCameraInBBox && GetCVars()->e_hw_occlusion_culling_objects && (GetRenderer()->GetFeatures() & RFT_OCCLUSIONTEST) )
{
// construct RE if needed
for(int i=0; i<2; i++)
{
if(!pOcclTestVars->arrREOcclusionQuery[i])
pOcclTestVars->arrREOcclusionQuery[i] =
(CREOcclusionQuery *)GetRenderer()->EF_CreateRE(eDATA_OcclusionQuery);
pOcclTestVars->arrREOcclusionQuery[i]->m_vBoxMin = vBoxMin;
pOcclTestVars->arrREOcclusionQuery[i]->m_vBoxMax = vBoxMax;
}
int nSlotId = GetFrameID()&1;
GetRenderer()->EF_AddEf(0, pOcclTestVars->arrREOcclusionQuery[nSlotId], m_pShaderOcclusionQuery, 0);
if(GetCVars()->e_hw_occlusion_culling_objects>1)
{
float fVis = (pOcclTestVars->arrREOcclusionQuery[!nSlotId]->m_nVisSamples >= 2);
float fCol[] = {fVis,!fVis,1,1};
GetRenderer()->DrawLabelEx((vBoxMin + vBoxMax)*0.5f,6, fCol, false, true, "%s",
fVis ? "V" : "N");
}
if(
pOcclTestVars->arrREOcclusionQuery[0]->m_nVisSamples < 2 &&
pOcclTestVars->arrREOcclusionQuery[1]->m_nVisSamples < 2 &&
1 >= abs( pOcclTestVars->arrREOcclusionQuery[0]->m_nCheckFrame -
pOcclTestVars->arrREOcclusionQuery[1]->m_nCheckFrame ) &&
GetFrameID()-2 <= pOcclTestVars->arrREOcclusionQuery[0]->m_nDrawFrame &&
GetFrameID()-2 <= pOcclTestVars->arrREOcclusionQuery[1]->m_nDrawFrame )
{ // return true only if last test is not older than 1 frame
pOcclTestVars->bLastResult = true;
return true;
}
}*/
pOcclTestVars->bLastResult = false;
pOcclTestVars->nLastVisibleFrameID = GetFrameID();
return false;
}
void CObjManager::PrefechObjects()
{
for (ObjectsMap::iterator it = m_lstLoadedObjects.begin(); it != m_lstLoadedObjects.end(); ++it)
{
CStatObj * pStatObj = (*it);
SRendParams params;
params.nDLightMask = 1;
GetRenderer()->EF_StartEf();
for(int i=0; i<3; i++)
pStatObj->Render(params,Vec3(zero),i);
GetRenderer()->EF_EndEf3D(0);
}
}

File diff suppressed because it is too large Load Diff

260
Cry3DEngine/ObjManFar.cpp Normal file
View File

@@ -0,0 +1,260 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: statobjmanfar.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: draw far objects as sprites
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "StatObj.h"
#include "objman.h"
#include "3dengine.h"
void CObjManager::RenderFarObjects()
{
FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE );
if (m_REFarTreeSprites && GetCVars()->e_vegetation_sprites && m_lstFarObjects[m_nRenderStackLevel].Count())
{
CCObject * pObj = GetRenderer()->EF_GetObject(true, -1);
pObj->m_Matrix.SetIdentity();
GetRenderer()->EF_AddEf(0, m_REFarTreeSprites, m_p3DEngine->m_pSHFarTreeSprites, NULL, pObj, 0, NULL,
/*(GetViewCamera().GetPos().z<m_pTerrain->GetWaterLevel()) ? */eS_Trees /*: eS_Sprites*/
);
}
}
/*
static _inline int Compare(CStatObjInst *& p1, CStatObjInst *& p2)
{
if(p1->m_fDistance > p2->m_fDistance)
return 1;
else
if(p1->m_fDistance < p2->m_fDistance)
return -1;
return 0;
} */
void CObjManager::DrawFarObjects(float fMaxViewDist)
{
if(!GetCVars()->e_vegetation_sprites)
return;
//////////////////////////////////////////////////////////////////////////////////////
// Draw all far
//////////////////////////////////////////////////////////////////////////////////////
list2<CStatObjInst*> * pList = &m_lstFarObjects[m_nRenderStackLevel];
if (pList->Count())
{
IRenderer * pRenderer = GetRenderer();
int useBending;
if (/*(GetRenderer()->GetFeatures() & RFT_HW_VS) &&*/ GetCVars()->e_vegetation_bending >= 2)
useBending = 2;
else
if (GetCVars()->e_vegetation_bending == 1)
useBending = 1;
else
useBending = 0;
if(useBending == 2)
GetRenderer()->DrawObjSprites(pList, fMaxViewDist, this);
else
DrawObjSpritesSorted(pList, fMaxViewDist, useBending);
}
for(int s=0; s<m_lstDebugEntityList.Count(); s++)
{
IRenderer * pRenderer = GetRenderer();
pRenderer->ResetToDefault();
ShadowMapLightSource * & pLsource = m_lstDebugEntityList[s]->GetEntityRS()->pShadowMapInfo->pShadowMapFrustumContainer;
GetRenderer()->PushMatrix();
GetRenderer()->TranslateMatrix(m_lstDebugEntityList[s]->GetPos());
pLsource->m_LightFrustums.Get(0)->DrawFrustum(pRenderer,m_lstDebugEntityList[s]->GetPos(),1.f);
GetRenderer()->PopMatrix();
Vec3d vMin,vMax;
m_lstDebugEntityList[s]->GetRenderBBox(vMin,vMax);
pRenderer->Draw3dBBox(vMin,vMax);
pRenderer->DrawBall(m_lstDebugEntityList[s]->GetPos(),0.1f);
pRenderer->ResetToDefault();
}
m_lstDebugEntityList.Clear();
}
void CObjManager::DrawObjSpritesSorted(list2<CStatObjInst*> *pList, float fMaxViewDist, int useBending)
{
#if 0
static list2<CStatObjInst*>* arrSortedInstances[8192];
{ // fill hash table
const Vec3d & vCamPos = GetViewCamera().GetPos();
const float rad2deg = 180.0f/gf_PI;
const float far_tex_angle = (FAR_TEX_ANGLE>>1);
for( int i=0; i<pList->Count(); i++ )
{
CStatObjInst * o = pList->GetAt(i);
CStatObj * pBody = m_lstStaticTypes[o->m_nObjectTypeID].GetStatObj();
const float DX = o->m_vPos.x - vCamPos.x;
const float DY = o->m_vPos.y - vCamPos.y;
int angle(int(rad2deg*atan2( DX, DY )+far_tex_angle));
while(angle<0) angle+=360;
assert(angle>=0 && angle/FAR_TEX_ANGLE<FAR_TEX_COUNT);
int tid = pBody->m_arrSpriteTexID[angle/FAR_TEX_ANGLE];
if(tid>=4096 && tid<8192)
{
if(!arrSortedInstances[tid])
arrSortedInstances[tid] = new list2<CStatObjInst*>;
arrSortedInstances[tid]->Add(o);
}
else
{
#if !defined(LINUX)
Warning( 0,0,"Error: CObjManager::DrawObjSpritesSorted: Texture id is out of range: %d", tid);
#endif
break;
}
}
}
pList->Clear();
// render sorted by texture
IRenderer * pRenderer = GetRenderer();
pRenderer->ResetToDefault();
pRenderer->EnableBlend(false);
pRenderer->EnableAlphaTest(true,0.5f);
pRenderer->SetEnviMode(R_MODE_MODULATE);
pRenderer->EnableDepthWrites(true);
pRenderer->SetCullMode(R_CULL_DISABLE);
Vec3d vWorldCol = GetSystem()->GetI3DEngine()->GetWorldColor();
pRenderer->SetMaterialColor(vWorldCol.x, vWorldCol.y, vWorldCol.z, 1.f);
float max_view_dist = fMaxViewDist;//*0.8f;
const Vec3d & vCamPos = GetViewCamera().GetPos();
const float rad2deg = 180.0f/gf_PI;
const float far_tex_angle = (FAR_TEX_ANGLE>>1);
static int nCurrBufId = 0;
// nCurrBufId=0;
for(int tid=4096; tid<8192; tid++)
if(arrSortedInstances[tid] && arrSortedInstances[tid]->Count())
{
#define MAX_BUFF_NUM 128
#define MAX_VERTS_NUM 1024
static CVertexBuffer * arrVideoBuffers[MAX_BUFF_NUM];
if(!arrVideoBuffers[0])
for(int i=0; i<MAX_BUFF_NUM; i++)
arrVideoBuffers[i] = pRenderer->CreateBuffer(MAX_VERTS_NUM,VERTEX_FORMAT_P3F_TEX2F,"CompiledTreeSprites",true);
static SVertexStream Inds;
if (!Inds.m_VData)
pRenderer->CreateIndexBuffer(&Inds, NULL, MAX_VERTS_NUM*3/2);
// Lock the index buffer
pRenderer->UpdateIndexBuffer(&Inds, NULL, 0, false);
ushort *pInds = (ushort *)Inds.m_VData;
pRenderer->UpdateBuffer(arrVideoBuffers[nCurrBufId],0,0,true);
for(int i=0; i<arrSortedInstances[tid]->Count(); i++)
{
CStatObjInst * o = arrSortedInstances[tid]->GetAt(i);
CStatObj * pBody = m_lstStaticTypes[o->m_nObjectTypeID].GetStatObj();
float max_dist = o->m_fMaxDist;
// note: move into sort by size
if(max_dist>max_view_dist)
max_dist=max_view_dist;
const float alpha = min(1.f,(1.f-(o->m_fDistance*m_fZoomFactor)/(max_dist))*8.f);
const float brigh = /*0.6666f + 0.3333f*o->m_bBright*/CHAR_TO_FLOAT*o->m_ucBright;
const float DX = o->m_vPos.x - vCamPos.x;
const float DY = o->m_vPos.y - vCamPos.y;
// pRenderer->SetMaterialColor(vWorldColor.x*brigh, vWorldColor.y*brigh, vWorldColor.z*brigh, alpha);
const float fSpriteScaleV = o->m_fScale*pBody->GetRadiusVert()*1.035f*alpha;
const float fSpriteScaleH = o->m_fScale*pBody->GetRadiusHors()*m_fZoomFactor*1.050f*alpha;
Vec3d vPos = o->m_vPos + pBody->GetCenter()*o->m_fScale;
/*
float fBending;
if (useBending)
fBending = (o->m_fCurrentBending)*pBody->m_fBending;
else
fBending = 0;
*/
struct_VERTEX_FORMAT_P3F_TEX2F * pVerts = (struct_VERTEX_FORMAT_P3F_TEX2F*)(arrVideoBuffers[nCurrBufId])->m_VS[VSF_GENERAL].m_VData;
assert(i*6 + 5 < (MAX_VERTS_NUM*3/2));
assert(i*4 + 3 < MAX_VERTS_NUM);
struct_VERTEX_FORMAT_P3F_TEX2F VertQuad[4];
float dy = DX*fSpriteScaleH/o->m_fDistance;
float dx = DY*fSpriteScaleH/o->m_fDistance;
float dz = fSpriteScaleV;
VertQuad[0].s = -1;
VertQuad[0].t = 0;
VertQuad[0].x = -dx+vPos.x; VertQuad[0].y = dy+vPos.y; VertQuad[0].z = -dz+vPos.z;
VertQuad[1].s = 0;
VertQuad[1].t = 0;
VertQuad[1].x = dx+vPos.x; VertQuad[1].y = -dy+vPos.y; VertQuad[1].z = -dz+vPos.z;
VertQuad[2].s = 0;
VertQuad[2].t = 1;
VertQuad[2].x = dx+vPos.x; VertQuad[2].y = -dy+vPos.y; VertQuad[2].z = dz+vPos.z;
VertQuad[3].s = -1;
VertQuad[3].t = 1;
VertQuad[3].x = -dx+vPos.x; VertQuad[3].y = dy+vPos.y; VertQuad[3].z = dz+vPos.z;
memcpy(&pVerts[i*4], VertQuad, sizeof(VertQuad));
pInds[i*6 + 0] = i*4 + 0;
pInds[i*6 + 1] = i*4 + 1;
pInds[i*6 + 2] = i*4 + 2;
pInds[i*6 + 3] = i*4 + 0;
pInds[i*6 + 4] = i*4 + 2;
pInds[i*6 + 5] = i*4 + 3;
}
// Unlock the index buffer
pRenderer->UpdateIndexBuffer(&Inds, NULL, 0, true);
pRenderer->SetTexture(tid);
pRenderer->DrawBuffer(arrVideoBuffers[nCurrBufId],&Inds,arrSortedInstances[tid]->Count()*6,0,R_PRIMV_TRIANGLES);
nCurrBufId++;
if(nCurrBufId>=MAX_BUFF_NUM)
nCurrBufId=0;
arrSortedInstances[tid]->Clear();
}
#endif
}

View File

@@ -0,0 +1,22 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: statobjmanphys.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: Physicalize static objects (trees, structures)
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "StatObj.h"
#include "objman.h"
#include "terrain_sector.h"
#include "3dengine.h"

View File

@@ -0,0 +1,360 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: statobjmanshadows.cpp
// Version: v1.00
// Created: 2/6/2002 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: Shadow casters/reseivers relations
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "objman.h"
#include "visareas.h"
#include "3dengine.h"
#include <AABBSV.h>
#define MIN_SHADOW_CASTER_VIEW_DIST 16
void CObjManager::MakeShadowCastersListInArea(CBasicArea*pArea, IEntityRender * pReceiver, list2<IEntityRender*> * pEntList, int dwAllowedTypes, Vec3d vLightPos, float fLightRadius)
{
FUNCTION_PROFILER_FAST( GetSystem(),PROFILE_3DENGINE,m_bProfilerEnabled );
bool bCmpCasterReceiverDistances = !(GetRenderer()->GetFeatures() & (RFT_DEPTHMAPS | RFT_SHADOWMAP_SELFSHADOW));
Shadowvolume ResShadowVolume;
{
Vec3d vBoxMin,vBoxMax;
pReceiver->GetBBox(vBoxMin,vBoxMax);
AABB aabbReceiver(vBoxMin,vBoxMax+Vec3d(0.01f,0.01f,0.01f));
NAABB_SV::AABB_ReceiverShadowVolume(vLightPos, aabbReceiver, ResShadowVolume);//, min(fDistFromLsToCaster+pCaster->GetRenderRadius()*4, fLightRadius));
}
float fDistFromLsToReceiver = GetDistance(vLightPos, pReceiver->GetPos());
int nStaticsAllowed = int(GetCVars()->e_shadow_maps_from_static_objects>0);
for(int nStatic=0; nStatic<=nStaticsAllowed; nStatic++)
{
list2<struct IEntityRender*> * pList = &pArea->m_lstEntities[nStatic];
if(nStatic && pArea->m_StaticEntitiesSorted && !(dwAllowedTypes&SMC_ALLOW_PASSIVE_SHADOWMAP_CASTERS))
pList = &pArea->m_lstStaticShadowMapCasters;
for(int e=0; e<pList->Count(); e++)
{
IEntityRender * pCaster = (*pList)[e];
if (e+1 < pList->Count())
{
IEntityRender * pNext = (*pList)[e+1];
cryPrefetchT0SSE(pNext);
}
if(pCaster->m_fWSMaxViewDist<MIN_SHADOW_CASTER_VIEW_DIST)
{
if(!nStatic || !pArea->m_StaticEntitiesSorted)
continue;
else
break; // break in sorted list
}
#ifdef _DEBUG
const char * szClass = pCaster->GetEntityClassName();
const char * szName = pCaster->GetName();
#endif // _DEBUG
int dwRndFlags = pCaster->GetRndFlags();
bool bTakeThisOne = false;
{ // take only allowed active shadow casters
if((pCaster->IsStatic() && (dwAllowedTypes & SMC_STATICS )) ||
(!pCaster->IsStatic() && (dwAllowedTypes & SMC_DYNAMICS)) )
{
if(dwAllowedTypes&SMC_ALLOW_PASSIVE_SHADOWMAP_CASTERS)
bTakeThisOne = true;
else
if(dwRndFlags & ERF_CASTSHADOWMAPS && pCaster->GetEntityRS()->pShadowMapInfo)
{
ShadowMapLightSource * pFrustumContainer = pCaster->GetShadowMapFrustumContainer();
if( pFrustumContainer && pFrustumContainer->m_LightFrustums.Count() && pFrustumContainer->m_LightFrustums.Get(0)->pLs )
bTakeThisOne = true;
}
}
}
if(bTakeThisOne && pCaster != pReceiver && !(dwRndFlags&ERF_HIDDEN) && (!pCaster->GetLight() || pCaster->GetContainer()))
{
float fDistFromLsToCaster = GetDistance(vLightPos, pCaster->GetPos());
if(bCmpCasterReceiverDistances)
if(fDistFromLsToReceiver < fDistFromLsToCaster)
continue;
if(fDistFromLsToReceiver - fDistFromLsToCaster > pCaster->GetRenderRadius()*4+pReceiver->GetRenderRadius())
continue;
// check if caster is in receiver frustum
Vec3d vBoxMin,vBoxMax;
pCaster->GetBBox(vBoxMin,vBoxMax);
AABB aabbCaster(vBoxMin,vBoxMax+Vec3d(0.01f,0.01f,0.01f));
bool bIntersect = NAABB_SV::Is_AABB_In_ShadowVolume(ResShadowVolume, aabbCaster);
if(bIntersect && pEntList->Find(pCaster)<0)
pEntList->Add(pCaster);
}
}
}
}
void CObjManager::MakeShadowCastersList(IEntityRender * pReceiver, list2<IEntityRender*> * pEntList, int dwAllowedTypes, Vec3d vLightPos, float fLightRadius)
{
FUNCTION_PROFILER_FAST( GetSystem(),PROFILE_3DENGINE,m_bProfilerEnabled );
assert(vLightPos.len()>1); // world space pos required
pEntList->Clear();
if(pReceiver->m_pVisArea && pReceiver->IsEntityAreasVisible())
MakeShadowCastersListInArea(pReceiver->m_pVisArea, pReceiver, pEntList, dwAllowedTypes, vLightPos, fLightRadius);
else
{ // make list of sectors around
// find 2d bounds in sectors array
Vec3d vBoxMin,vBoxMax;
pReceiver->GetBBox(vBoxMin,vBoxMax);
// get 2d bounds in sectors array
int min_x = (int)(((vBoxMin.x - 16.f)/CTerrain::GetSectorSize()));
int min_y = (int)(((vBoxMin.y - 16.f)/CTerrain::GetSectorSize()));
int max_x = (int)(((vBoxMax.x + 16.f)/CTerrain::GetSectorSize()));
int max_y = (int)(((vBoxMax.y + 16.f)/CTerrain::GetSectorSize()));
// limit bounds
if(min_x<0) min_x=0; else if(min_x>=CTerrain::GetSectorsTableSize()) min_x=CTerrain::GetSectorsTableSize()-1;
if(min_y<0) min_y=0; else if(min_y>=CTerrain::GetSectorsTableSize()) min_y=CTerrain::GetSectorsTableSize()-1;
if(max_x<0) max_x=0; else if(max_x>=CTerrain::GetSectorsTableSize()) max_x=CTerrain::GetSectorsTableSize()-1;
if(max_y<0) max_y=0; else if(max_y>=CTerrain::GetSectorsTableSize()) max_y=CTerrain::GetSectorsTableSize()-1;
m_lstTmpSectors_MELFP.Clear();
m_lstTmpSectors_MELFP.Add(m_pTerrain->m_arrSecInfoTable[0][0]);
for(int x=min_x; x<=max_x && x>=0 && x<=CTerrain::GetTerrainSize(); x++)
for(int y=min_y; y<=max_y && y>=0 && y<=CTerrain::GetTerrainSize(); y++)
{
CSectorInfo * pSectorInfo = m_pTerrain->m_arrSecInfoTable[x][y];
// check if sector cast shadow to the receiver
if(m_lstTmpSectors_MELFP.Find(pSectorInfo)<0 && pSectorInfo)
{
Shadowvolume sv;
Vec3d vBoxMin,vBoxMax;
pReceiver->GetBBox(vBoxMin,vBoxMax);
AABB aabbReceiver(vBoxMin,vBoxMax);
AABB aabbCaster(pSectorInfo->m_vBoxMin,pSectorInfo->m_vBoxMax);
aabbCaster.max.z += 0.01f;
NAABB_SV::AABB_ShadowVolume(vLightPos, aabbCaster, sv, fLightRadius);
bool bIntersect = NAABB_SV::Is_AABB_In_ShadowVolume(sv, aabbReceiver);
if(bIntersect)
m_lstTmpSectors_MELFP.Add(pSectorInfo);
}
}
// make list of entities
for(int s=0; s<m_lstTmpSectors_MELFP.Count(); s++)
MakeShadowCastersListInArea(m_lstTmpSectors_MELFP[s], pReceiver, pEntList, dwAllowedTypes, vLightPos, fLightRadius);
}
}
void CObjManager::MakeShadowMapInstancesList( IEntityRender * pReceiver, float obj_distance,
list2<ShadowMapLightSourceInstance> * pLSourceInstances, int dwAllowedTypes, CDLight * pLight)
{
if(!GetCVars()->e_shadow_maps || obj_distance > pReceiver->GetRenderRadius()*32)
return;
// get entities in area
lstEntList_MLSMCIA.Clear();
if(dwAllowedTypes)
MakeShadowCastersList(pReceiver, &lstEntList_MLSMCIA, dwAllowedTypes, pLight->m_Origin, pLight->m_fRadius);
lstEntList_MLSMCIA.Delete(pReceiver);
// add this entity if self shadowing allowed
if( GetCVars()->e_shadow_maps_self_shadowing &&
pReceiver->GetRndFlags() & ERF_SELFSHADOW &&
GetRenderer()->GetFeatures() & (RFT_DEPTHMAPS | RFT_SHADOWMAP_SELFSHADOW))
lstEntList_MLSMCIA.InsertBefore(pReceiver,0);
// make list of shadow casters
for(int e=0; e<lstEntList_MLSMCIA.Count(); e++)
{
const char * szClass = lstEntList_MLSMCIA[e]->GetEntityClassName();
const char * szName = lstEntList_MLSMCIA[e]->GetName();
if( !lstEntList_MLSMCIA[e]->GetShadowMapFrustumContainer() ||
!lstEntList_MLSMCIA[e]->GetShadowMapFrustumContainer()->m_LightFrustums.Count() ||
!(lstEntList_MLSMCIA[e]->GetRndFlags()&ERF_CASTSHADOWMAPS) )
continue;
ShadowMapLightSourceInstance LightSourceInfo;
LightSourceInfo.m_pLS = lstEntList_MLSMCIA[e]->GetShadowMapFrustumContainer();
LightSourceInfo.m_vProjTranslation = lstEntList_MLSMCIA[e]->GetPos();
LightSourceInfo.m_fProjScale = lstEntList_MLSMCIA[e]->GetScale();
Vec3d vThisEntityPos = pReceiver->GetPos();
LightSourceInfo.m_fDistance = GetDistance(vThisEntityPos,lstEntList_MLSMCIA[e]->GetPos()) - lstEntList_MLSMCIA[e]->GetRenderRadius()/3;
LightSourceInfo.m_pReceiver = pReceiver;
if(!LightSourceInfo.m_pLS->m_LightFrustums.Count())// || !LightSourceInfo.m_pLS->m_LightFrustums[0].depth_tex_id)
continue;
pLSourceInstances->Add(LightSourceInfo);
}
// select only closest
pLSourceInstances->SortByDistanceMember(true,1);
while(pLSourceInstances->Count()>GetCVars()->e_shadow_maps_max_casters_per_object)
pLSourceInstances->DeleteLast();
}
ShadowMapFrustum * CObjManager::MakeEntityShadowFrustum(ShadowMapFrustum * pFrustum,
ShadowMapLightSource * pLs, IEntityRender * pEnt, EShadowType nShadowType, int dwAllowedTypes)
{
Vec3d vMin,vMax;
pEnt->GetBBox(vMin,vMax);
Vec3d visual_center = (vMin+vMax)*0.5f - pEnt->GetPos();
float model_radius = GetDistance(vMax,vMin) * 0.5f;
float model_radiusXY = GetDistance(Vec3d(vMax.x,vMax.y,0),Vec3d(vMin.x,vMin.y,0)) * 0.5f;
pFrustum->target = visual_center;
Vec3d dir = pFrustum->target - pLs->vSrcPos;
float dist = dir.Length();
pFrustum->ProjRatio = model_radiusXY/model_radius;
if(pFrustum->ProjRatio>1.f)
pFrustum->ProjRatio=1.f;
pFrustum->FOV = (float)RAD2DEG(cry_atanf((model_radius+0.25f)/dist))*1.9f;
if(pFrustum->FOV>120.f)
pFrustum->FOV=120.f;
pFrustum->min_dist = dist - (model_radius + ((dwAllowedTypes&SMC_ALLOW_PASSIVE_SHADOWMAP_CASTERS) ? 32 : 0));
if(pFrustum->min_dist<0.25)
pFrustum->min_dist=0.25;
pFrustum->max_dist = dist + ((dwAllowedTypes&SMC_ALLOW_PASSIVE_SHADOWMAP_CASTERS) ? -0.75f : model_radius);
pFrustum->pLs = pLs;
pFrustum->shadow_type = nShadowType;
// make entities list
if(pFrustum->pEntityList)
pFrustum->pEntityList->Clear();
else
pFrustum->pEntityList = new list2<IEntityRender*>;
if(dwAllowedTypes)
MakeShadowCastersList(pEnt, pFrustum->pEntityList, dwAllowedTypes, pLs->vSrcPos+pEnt->GetPos(), pLs->fRadius);
else
pFrustum->pEntityList->Add(pEnt);
return pFrustum;
}
static int Cmp_Shadow_Size(const void* v1, const void* v2)
{
CStatObjInst* p1 = *((CStatObjInst**)(v1));
CStatObjInst* p2 = *((CStatObjInst**)(v2));
if(p1->m_fScale > p2->m_fScale)
return -1;
else if(p1->m_fScale < p2->m_fScale)
return 1;
return 0;
}
static int __cdecl CObjManager_Cmp_EntSize(const void* v1, const void* v2)
{
IEntityRender* p1 = *((IEntityRender**)(v1));
IEntityRender* p2 = *((IEntityRender**)(v2));
if(p1->GetRenderRadius() > p2->GetRenderRadius())
return -1;
else if(p1->GetRenderRadius() < p2->GetRenderRadius())
return 1;
return (p1>p2) ? 1 : -1;
}
void CObjManager::DrawAllShadowsOnTheGroundInSector(list2<IEntityRender*> * pEntList)
{
///////////////////////////////////////////////////////////////////////////////////////////////////////////
// Draw entity shadows
///////////////////////////////////////////////////////////////////////////////////////////////////////////
GetRenderer()->ResetToDefault();
GetRenderer()->ClearDepthBuffer();
GetRenderer()->ClearColorBuffer(Vec3d(1,1,1));
GetRenderer()->SetClearColor(Vec3d(1,1,1));
// sort by size to draw small shadows last or skip them
if(pEntList && pEntList->Count())
qsort(&(*pEntList)[0], (*pEntList).Count(), sizeof((*pEntList)[0]), CObjManager_Cmp_EntSize);
GetRenderer()->EF_StartEf();
int nRealCout=0;
for( int i=0; i<pEntList->Count(); i++ )
{
IEntityRender * pEnt = (*pEntList)[i];
if(!(pEnt->GetRndFlags() & ERF_HIDDEN))
if(pEnt->GetRndFlags() & ERF_CASTSHADOWINTOLIGHTMAP)
if(!pEnt->GetEntityVisArea())
{
assert(m_nRenderStackLevel == 0);
pEnt->SetDrawFrame(-100,m_nRenderStackLevel);
int nFlags = pEnt->GetRndFlags();
pEnt->SetRndFlags(nFlags|ERF_CASTSHADOWMAPS|ERF_RECVSHADOWMAPS);
pEnt->SetRndFlags(ERF_CASTSHADOWINTOLIGHTMAP,false);
int nRealLightsNum = ((C3DEngine*)Get3DEngine())->GetRealLightsNum();
assert(nRealLightsNum==1);
RenderObject(pEnt,0,1,true,GetViewCamera(),NULL,0,0,false,pEnt->GetMaxViewDist());
RenderEntitiesShadowMapsOnTerrain(true, 0);
// increase frame id to help shadow map menager in renderer
unsigned short * pPtr2FrameID = (unsigned short *)GetRenderer()->EF_Query(EFQ_Pointer2FrameID);
if(pPtr2FrameID)
(*pPtr2FrameID)++;
pEnt->SetRndFlags(nFlags);
nRealCout++;
if((GetRenderer()->GetType() == R_GL_RENDERER) && nRealCout>=64) // maximum number of shadow maps in frame is limited in ogl to MAX_DYNAMIC_SHADOW_MAPS_COUNT
break;
}
}
GetRenderer()->EF_EndEf3D(SHDF_SORT);
// free shadow pass leafbuffers
for( int i=0; i<pEntList->Count(); i++ )
{
IEntityRender * pEnt = (*pEntList)[i];
IEntityRenderState * pEntRendState = pEnt->m_pEntityRenderState;
if(pEntRendState && pEntRendState->pShadowMapInfo && pEntRendState->pShadowMapInfo->pShadowMapLeafBuffersList)
{
for(int i=0; i<pEntRendState->pShadowMapInfo->pShadowMapLeafBuffersList->Count(); i++)
{
if(pEntRendState->pShadowMapInfo->pShadowMapLeafBuffersList->GetAt(i))
{
GetRenderer()->DeleteLeafBuffer(pEntRendState->pShadowMapInfo->pShadowMapLeafBuffersList->GetAt(i));
pEntRendState->pShadowMapInfo->pShadowMapLeafBuffersList->GetAt(i)=0;
}
}
delete pEntRendState->pShadowMapInfo->pShadowMapLeafBuffersList;
pEntRendState->pShadowMapInfo->pShadowMapLeafBuffersList=0;
}
}
}

View File

@@ -0,0 +1,120 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: statobjman.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: Loading trees, buildings, ragister/unregister entities for rendering
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "StatObj.h"
#include "objman.h"
#include "visareas.h"
#include "terrain_sector.h"
#include "cbuffer.h"
#include "3DEngine.h"
#include "meshidx.h"
#include "watervolumes.h"
#include "brush.h"
#include "LMCompStructures.h"
void CObjManager::PreloadNearObjects()
{
// if(!GetCVars()->e_stream_cgf)
return;
CVisAreaManager * pVisAreaManager = GetVisAreaManager();
// CVisArea * pVisArea = pVisAreaManager->m_pCurArea ? pVisAreaManager->m_pCurArea : pVisAreaManager->m_pCurPortal;
if(CStatObj::m_fStreamingTimePerFrame<CGF_STREAMING_MAX_TIME_PER_FRAME)// && pVisArea)
{ // mark this and neighbor sectors
/* pVisArea->MarkForStreaming();
CVisArea * areaArray[8]={0,0,0,0,0,0,0,0};
int nCount = pVisArea->GetVisAreaConnections((IVisArea **)&areaArray,8);
for(int n=0; n<nCount; n++)
areaArray[n]->MarkForStreaming();
*/
// load marked objects
for (ObjectsMap::iterator it = m_lstLoadedObjects.begin(); it != m_lstLoadedObjects.end(); ++it)
{
if((*it)->m_bUseStreaming && !(*it)->GetLeafBuffer() && (*it)->m_nMarkedForStreamingFrameId > GetFrameID()+10)
{ // streaming
CStatObj::m_fStreamingTimePerFrame -= GetTimer()->GetAsyncCurTime();
bool bRes = (*it)->Load((*it)->m_szFileName, (*it)->m_szGeomName[0] ? (*it)->m_szGeomName : 0,
(*it)->m_eVertsSharing, (*it)->m_bLoadAdditinalInfo, (*it)->m_bKeepInLocalSpace, false);
(*it)->m_bUseStreaming=true;
CStatObj::m_fStreamingTimePerFrame += GetTimer()->GetAsyncCurTime();
}
if(CStatObj::m_fStreamingTimePerFrame>CGF_STREAMING_MAX_TIME_PER_FRAME)
break;
}
}
}
void CObjManager::CheckUnload()
{
if(GetCVars()->e_stream_cgf)
for (ObjectsMap::iterator it = m_lstLoadedObjects.begin(); it != m_lstLoadedObjects.end(); ++it)
{
CStatObj * pStatObj = (*it);
if(pStatObj->m_bUseStreaming && pStatObj->GetLeafBuffer() &&
max(pStatObj->m_nLastRendFrameId, pStatObj->m_nMarkedForStreamingFrameId) < GetFrameID()-100)
{
int p;
for(p=0; p<2; p++)
{ // check is phys geometry still in use
phys_geometry * pPhysGeom = pStatObj->GetPhysGeom(p);
if(pPhysGeom && pPhysGeom->nRefCount>1)
break;
}
if(p==2)
{
pStatObj->ShutDown();
pStatObj->Init();
GetLog()->Log("Unloaded: %s", pStatObj->m_szFileName);
break;
}
}
}
if(GetFrameID()%32==0)
for (ObjectsMap::iterator it = m_lstLoadedObjects.begin(); it != m_lstLoadedObjects.end(); ++it)
{
if((*it)->GetLeafBuffer() && (*it)->GetShadowVolume())
(*it)->GetShadowVolume()->CheckUnload();
}
}
void CObjManager::GetObjectsStreamingStatus(int & nReady, int & nTotalInStreaming, int & nTotal)
{
nReady=nTotalInStreaming=nTotal=0;
for (ObjectsMap::iterator it = m_lstLoadedObjects.begin(); it != m_lstLoadedObjects.end(); ++it)
{
nTotal++;
if((*it)->m_bUseStreaming)
{
nTotalInStreaming++;
if((*it)->GetLeafBuffer())
{
CStatObj * p = (*it);
nReady++;
}
}
else
{
CStatObj * p = (*it);
p=p;
p->m_szFileName;
}
}
}

View File

@@ -0,0 +1,395 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: particleeffect.cpp
// Version: v1.00
// Created: 10/7/2003 by Timur.
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "StdAfx.h"
#include "ParticleEffect.h"
#include "ParticleEmitter.h"
#include "PartMan.h"
#include "3DEngine.h"
#include "ISound.h"
//////////////////////////////////////////////////////////////////////////
CParticleEffect::CParticleEffect( CPartManager *pPartManager )
{
assert( pPartManager );
m_pPartManager = pPartManager;
m_bLoaded = false;
m_bEnabled = true;
m_soundVolume = 100;
m_soundMinRadius = 1;
m_soundMaxRadius = 10;
m_bSoundLoop = true;
m_bOnEverySpawn = false;
m_bAnimatedTexture[0] = false;
m_bAnimatedTexture[1] = false;
}
//////////////////////////////////////////////////////////////////////////
CParticleEffect::~CParticleEffect()
{
UnloadResources();
}
//////////////////////////////////////////////////////////////////////////
void CParticleEffect::SetName( const char *sName )
{
m_pPartManager->RenameEffect( this,sName );
m_name = sName;
}
//////////////////////////////////////////////////////////////////////////
void CParticleEffect::SetTexture( int process,const char *s )
{
if (m_texture[process] != s)
{
UnloadResources(false);
m_texture[process] = s;
}
};
//////////////////////////////////////////////////////////////////////////
void CParticleEffect::SetGeometry( int process,const char *s )
{
if (m_geometry[process] != s)
{
UnloadResources(false);
m_geometry[process] = s;
}
};
//////////////////////////////////////////////////////////////////////////
int CParticleEffect::GetChildCount() const
{
return (int)m_childs.size();
}
//////////////////////////////////////////////////////////////////////////
IParticleEffect* CParticleEffect::GetChild( int index ) const
{
assert( index >= 0 && index < (int)m_childs.size() );
return m_childs[index];
}
//////////////////////////////////////////////////////////////////////////
void CParticleEffect::AddChild( IParticleEffect *pEffect )
{
assert( pEffect );
m_childs.push_back(pEffect);
}
//////////////////////////////////////////////////////////////////////////
void CParticleEffect::RemoveChild( IParticleEffect *pEffect )
{
assert( pEffect );
stl::find_and_erase( m_childs,pEffect );
}
//////////////////////////////////////////////////////////////////////////
void CParticleEffect::ClearChilds()
{
m_childs.clear();
}
//////////////////////////////////////////////////////////////////////////
void CParticleEffect::InsertChild( int slot,IParticleEffect *pEffect )
{
if (slot < 0)
slot = 0;
if (slot > (int)m_childs.size())
slot = (int)m_childs.size();
assert( pEffect );
m_childs.insert( m_childs.begin() + slot,pEffect );
}
//////////////////////////////////////////////////////////////////////////
int CParticleEffect::FindChild( IParticleEffect *pEffect ) const
{
for (int i = 0; i < (int)m_childs.size(); i++)
{
if (m_childs[i] == pEffect)
{
return i;
}
}
return -1;
}
//////////////////////////////////////////////////////////////////////////
void CParticleEffect::LoadResources( bool bRecursive )
{
if (m_bLoaded)
return;
m_bLoaded = true;
for (int i = 0; i < NUM_PARTICLE_PROCESSES; i++)
{
if (!m_material[i].empty() && !m_pMaterials[i])
AssignMaterial( i );
bool bNeedAnimatedTex = m_particleParams[i].nTexAnimFramesCount > 0;
// First unload what is loaded.
if (m_particleParams[i].nTexId != 0)
{
GetRenderer()->RemoveTexture( m_particleParams[i].nTexId );
m_particleParams[i].nTexId = 0;
if(m_particleParams[i].pAnimTex)
GetRenderer()->RemoveAnimatedTexture(m_particleParams[i].pAnimTex);
m_particleParams[i].pAnimTex = 0;
}
if (m_particleParams[i].pStatObj)
{
Get3DEngine()->ReleaseObject( m_particleParams[i].pStatObj );
m_particleParams[i].pStatObj = 0;
}
// Load textures.
if (!m_texture[i].empty())
{
if (bNeedAnimatedTex)
{
int texid = GetRenderer()->LoadAnimatedTexture( m_texture[i].c_str(),m_particleParams[i].nTexAnimFramesCount );
m_particleParams[i].nTexId = texid;
m_particleParams[i].pAnimTex = GetRenderer()->GetAnimTexInfoFromId(texid);
if(!m_particleParams[i].pAnimTex)
{
#if !defined(LINUX)
Warning( 0,0,"ParticleEffect %s, Use Invalid Animated Texture Id %d",m_name.c_str(),texid );
#endif
return;
}
}
else
{
#if defined(NULL_RENDERER)
m_particleParams[i].nTexId = 0;
#else
m_particleParams[i].nTexId = GetRenderer()->LoadTexture( m_texture[i].c_str() );
#endif
m_particleParams[i].pAnimTex = 0;
}
m_bAnimatedTexture[i] = bNeedAnimatedTex;
}
// Load geometry.
if (!m_geometry[i].empty())
{
m_particleParams[i].pStatObj = Get3DEngine()->MakeObject( m_geometry[i].c_str() );
}
}
if (bRecursive)
{
for (int i = 0; i < (int)m_childs.size(); i++)
{
IParticleEffect *pChild = m_childs[i];
((CParticleEffect*)pChild)->LoadResources( bRecursive );
}
}
}
//////////////////////////////////////////////////////////////////////////
void CParticleEffect::UnloadResources( bool bRecursive )
{
if (!m_bLoaded)
return;
m_bLoaded = false;
for (int i = 0; i < NUM_PARTICLE_PROCESSES; i++)
{
if (m_particleParams[i].nTexId != 0)
{
GetRenderer()->RemoveTexture( m_particleParams[i].nTexId );
m_particleParams[i].nTexId = 0;
if(m_particleParams[i].pAnimTex)
GetRenderer()->RemoveAnimatedTexture(m_particleParams[i].pAnimTex);
m_particleParams[i].pAnimTex = 0;
}
if (m_particleParams[i].pStatObj)
{
Get3DEngine()->ReleaseObject( m_particleParams[i].pStatObj );
m_particleParams[i].pStatObj = 0;
}
}
if (bRecursive)
{
for (int i = 0; i < (int)m_childs.size(); i++)
{
IParticleEffect *pChild = m_childs[i];
((CParticleEffect*)pChild)->UnloadResources( bRecursive );
}
}
}
//////////////////////////////////////////////////////////////////////////
void CParticleEffect::SetSoundParams( const SoundParams &params )
{
m_sound = params.szSound;
m_soundVolume = params.volume;
m_soundMinRadius = params.minRadius;
m_soundMaxRadius = params.maxRadius;
m_bSoundLoop = params.bLoop;
m_bOnEverySpawn = params.bOnEverySpawn;
}
//////////////////////////////////////////////////////////////////////////
void CParticleEffect::GetSoundParams( SoundParams &params ) const
{
params.szSound = m_sound.c_str();
params.volume = m_soundVolume;
params.minRadius = m_soundMinRadius;
params.maxRadius = m_soundMaxRadius;
params.bLoop = m_bSoundLoop;
params.bOnEverySpawn = m_bOnEverySpawn;
}
//////////////////////////////////////////////////////////////////////////
void CParticleEffect::Spawn( const Vec3 &pos,const Vec3 &dir,float fScale )
{
if (m_bEnabled)
{
// Spawn emitter for this particle.
if (!IsResourcesLoaded())
{
LoadResources();
}
if (m_particleParams[1].nCount > 0)
{
m_particleParams[0].pChild = &m_particleParams[1];
}
else
m_particleParams[0].pChild = 0;
m_particleParams[0].pEntity = 0;
m_particleParams[1].pEntity = 0;
// Spawn particle system emitter.
CParticleEmitter *pEmitter = new CParticleEmitter(m_pPartManager);
pEmitter->m_bPermament = false;
pEmitter->AssignEffect( this,false );
pEmitter->SetPos( pos,dir,fScale );
}
// Spawn child effects.
for (int i = 0; i < (int)m_childs.size(); i++)
{
m_childs[i]->Spawn( pos,dir,fScale );
}
}
//////////////////////////////////////////////////////////////////////////
bool CParticleEffect::PrepareSpawn( const Vec3 &pos )
{
if (!m_bEnabled)
return false;
if (!IsResourcesLoaded())
{
LoadResources();
}
/*
// Play sound if not looped.
if (!m_bSoundLoop && !m_sound.empty())
{
ISound *pSound = GetSystem()->GetISoundSystem()->LoadSound( m_sound.c_str(),FLAG_SOUND_3D );
if (pSound)
{
pSound->SetVolume( (int)m_soundVolume );
pSound->SetMinMaxDistance( m_soundMinRadius,m_soundMaxRadius );
pSound->SetPosition(pos);
pSound->Play();
}
}
*/
// Init child process pointer.
if (m_particleParams[1].nCount > 0)
m_particleParams[0].pChild = &m_particleParams[1];
else
m_particleParams[0].pChild = 0;
return true;
}
//////////////////////////////////////////////////////////////////////////
bool CParticleEffect::IsResourcesLoaded()
{
bool bAnimatedTex0 = m_particleParams[0].nTexAnimFramesCount > 0;
bool bAnimatedTex1 = m_particleParams[1].nTexAnimFramesCount > 0;
if (bAnimatedTex0 != m_bAnimatedTexture[0] || bAnimatedTex1 != m_bAnimatedTexture[1])
{
UnloadResources(false);
}
return m_bLoaded;
}
//////////////////////////////////////////////////////////////////////////
void CParticleEffect::SetMaterial( int process,IMatInfo *pMaterial )
{
assert( process >= 0 && process < NUM_PARTICLE_PROCESSES );
m_pMaterials[process] = pMaterial;
if (pMaterial)
pMaterial->SetFlags(pMaterial->GetFlags()|MIF_WASUSED);
m_particleParams[process].pMaterial = pMaterial;
if (pMaterial)
{
m_material[process] = pMaterial->GetName();
}
else
m_material[process] = "";
}
//////////////////////////////////////////////////////////////////////////
void CParticleEffect::SetMaterialName( int process,const char *sMtlName )
{
assert( process >= 0 && process < NUM_PARTICLE_PROCESSES );
m_material[process] = sMtlName;
AssignMaterial( process );
}
//////////////////////////////////////////////////////////////////////////
const char* CParticleEffect::GetMaterialName( int process ) const
{
assert( process >= 0 && process < NUM_PARTICLE_PROCESSES );
return m_material[process].c_str();
}
//////////////////////////////////////////////////////////////////////////
void CParticleEffect::AssignMaterial( int process )
{
assert( process >= 0 && process < NUM_PARTICLE_PROCESSES );
IMatInfo *pMtl = 0;
if (m_material[process].empty())
{
pMtl = 0;
}
else
{
pMtl = Get3DEngine()->FindMaterial( m_material[process].c_str() );
if (!pMtl)
{
#if !defined(LINUX)
Warning( 0,0,"ParticleEffect %s material assign failed, Material %s not found",m_name.c_str(),m_material[process].c_str() );
#endif
}
}
if(pMtl)
pMtl->SetFlags(pMtl->GetFlags()|MIF_WASUSED);
m_pMaterials[process] = pMtl;
m_particleParams[process].pMaterial = pMtl;
}

View File

@@ -0,0 +1,143 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: ParticleEffect.h
// Version: v1.00
// Created: 10/7/2003 by Timur.
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#ifndef __particleeffect_h__
#define __particleeffect_h__
#pragma once
#include "I3DEngine.h"
class CPartManager;
class CParticleEmitter;
/*! CParticleEffect implements IParticleEffect interface and contain all components necesarry to
to create particluar effect with particles.
*/
class CParticleEffect : public IParticleEffect, public Cry3DEngineBase
{
public:
CParticleEffect( CPartManager *pPartManager );
~CParticleEffect();
virtual void Spawn( const Vec3 &pos,const Vec3 &dir,float fScale=1.0f );
virtual void SetName( const char *sName );
virtual const char* GetName() { return m_name.c_str(); };
virtual void SetEnabled( bool bEnabled ) { m_bEnabled = bEnabled; };
virtual bool IsEnabled() const { return m_bEnabled; };
//////////////////////////////////////////////////////////////////////////
// Child particle systems.
//////////////////////////////////////////////////////////////////////////
virtual int GetChildCount() const;
//! Get sub Particles child by index.
virtual IParticleEffect* GetChild( int index ) const;
//! Adds a new sub Particles.
virtual void AddChild( IParticleEffect *pEffect );
//! Remove specific sub Particles
virtual void RemoveChild( IParticleEffect *pEffect );
//! Remove all sub Particles.
virtual void ClearChilds();
//! Insert sub particles in between other child particles.
virtual void InsertChild( int slot,IParticleEffect *pEffect );
//! Find slot where sub Particles stored.
//! @retun slot index if Particles found, -1 if Particles not found.
virtual int FindChild( IParticleEffect *pEffect ) const;
//////////////////////////////////////////////////////////////////////////
ParticleParams& GetParticleParams( int process ) { return m_particleParams[process]; };
//////////////////////////////////////////////////////////////////////////
//virtual EffectParams& GetEffectParams() { return m_effectParams; };
//////////////////////////////////////////////////////////////////////////
// Texture and Geometry.
//////////////////////////////////////////////////////////////////////////
const char* GetTexture( int process ) const { return m_texture[process].c_str(); };
const char* GetGeometry( int process ) const { return m_geometry[process].c_str(); };
void SetTexture( int process,const char *s );
void SetGeometry( int process,const char *s );
//////////////////////////////////////////////////////////////////////////
// Materials
//////////////////////////////////////////////////////////////////////////
void SetMaterial( int process,IMatInfo *pMaterial );
IMatInfo* GetMaterial( int process ) const { return m_pMaterials[process]; };
virtual void SetMaterialName( int process,const char *sMtlName );
virtual const char* GetMaterialName( int process ) const;
//////////////////////////////////////////////////////////////////////////
//! Load resources, required by this particle effect (Textures and geometry).
void LoadResources( bool bRecursive = true );
//! Unload resources, required by this particle effect (Textures and geometry).
void UnloadResources( bool bRecursive = true );
//! Check if resources are loaded.
bool IsResourcesLoaded();
//////////////////////////////////////////////////////////////////////////
// Sound parameters.
//! Set Sound parameters for this particle effect.
virtual void SetSoundParams( const SoundParams &params );
//! Get Sound parameters for this particle effect.
virtual void GetSoundParams( SoundParams &params ) const;
//////////////////////////////////////////////////////////////////////////
//! Called to initialize effect just before particles spawned..
//! @return true if can spawn, false if cannot spawn this effect.
bool PrepareSpawn( const Vec3 &pos );
private:
void AssignMaterial( int process );
//////////////////////////////////////////////////////////////////////////
String m_name;
//! When enabled this particle system will be spawned.
bool m_bEnabled;
//! Indicated whenever this effect was already loaded.
mutable bool m_bLoaded;
//! Particle primary and child system spawning parameters.
ParticleParams m_particleParams[NUM_PARTICLE_PROCESSES];
String m_texture[NUM_PARTICLE_PROCESSES];
String m_geometry[NUM_PARTICLE_PROCESSES];
String m_material[NUM_PARTICLE_PROCESSES];
//////////////////////////////////////////////////////////////////////////
// Materials.
//////////////////////////////////////////////////////////////////////////
_smart_ptr<IMatInfo> m_pMaterials[NUM_PARTICLE_PROCESSES];
bool m_bAnimatedTexture[NUM_PARTICLE_PROCESSES];
//EffectParams m_effectParams;
//! Array of sub materials.
std::vector<IParticleEffect_AutoPtr> m_childs;
//! Creating particle manager.
CPartManager* m_pPartManager;
//! Effect's sound parameters.
String m_sound;
float m_soundVolume;
float m_soundMinRadius;
float m_soundMaxRadius;
bool m_bSoundLoop;
bool m_bOnEverySpawn;
};
#endif //__particleeffect_h__

View File

@@ -0,0 +1,403 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: particleemitter.cpp
// Version: v1.00
// Created: 18/7/2003 by Timur.
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "StdAfx.h"
#include "ParticleEmitter.h"
#include "partman.h"
//////////////////////////////////////////////////////////////////////////
CParticleEmitter::~CParticleEmitter()
{
if (m_bActive)
OnActivate(false);
ReleaseParams();
}
//////////////////////////////////////////////////////////////////////////
void CParticleEmitter::ReleaseParams()
{
if (m_pParams && m_pParams->pStatObj)
m_pParams->pStatObj->UnregisterUser();
if (m_pChildParams && m_pChildParams->pStatObj)
m_pChildParams->pStatObj->UnregisterUser();
if (m_pParams && m_bOwnParams)
{
delete m_pParams;
}
if (m_pChildParams && m_bOwnParams)
{
delete m_pChildParams;
}
m_pParams = 0;
m_pChildParams = 0;
}
//////////////////////////////////////////////////////////////////////////
void CParticleEmitter::SetParams( const ParticleParams &params )
{
ReleaseParams();
m_bOwnParams = true;
m_pParams = new ParticleParams;
float fCurTime = m_pPartManager->GetParticlesTime();
m_startTime = fCurTime + params.fSpawnDelay.GetVariantValue();
SetLifeTime(params.fEmitterLifeTime.GetVariantValue());
m_spawnPeriod = params.fSpawnPeriod;
m_lastActiveTime = m_startTime;
m_lastSpawnTime = -100000.0f; // Force to spawn first time.
*m_pParams = params;
m_pParams->pChild = 0;
if (params.pChild != NULL && params.pChild->nCount > 0)
{
m_pChildParams = new ParticleParams;
m_pParams->pChild = m_pChildParams;
*m_pChildParams = *params.pChild;
}
m_pMaterial = params.pMaterial;
m_pSpawnerEntity = params.pEntity;
m_pos = params.vPosition;
m_dir = params.vDirection;
m_bbox.min = m_bbox.max = m_pos;
//////////////////////////////////////////////////////////////////////////
// Keep object from suddenly deleting.
//////////////////////////////////////////////////////////////////////////
if (m_pParams && m_pParams->pStatObj)
m_pParams->pStatObj->RegisterUser();
if (m_pChildParams && m_pChildParams->pStatObj)
m_pChildParams->pStatObj->RegisterUser();
//////////////////////////////////////////////////////////////////////////
InitTexture( m_pParams );
if (m_pChildParams)
InitTexture( m_pChildParams );
CalculateWaterLevel();
}
void CParticleEmitter::InitTexture( ParticleParams *pParams )
{
//////////////////////////////////////////////////////////////////////////
// Initialize texure ids.
//////////////////////////////////////////////////////////////////////////
if (pParams->nTexAnimFramesCount>1 && pParams->nTexId)
{
AnimTexInfo *p = Cry3DEngineBase::GetRenderer()->GetAnimTexInfoFromId(pParams->nTexId);
if(!p)
{
#if !defined(LINUX)
Cry3DEngineBase::Warning( 0,0,"Invalid Animated Texture Id %d for Particles",pParams->nTexId );
#endif
return;
}
pParams->pAnimTex = p;
}
else if(!pParams->nTexId && !pParams->pStatObj)
{
pParams->nTexId = m_pPartManager->GetGlowTexID();
}
}
//////////////////////////////////////////////////////////////////////////
void CParticleEmitter::SetEffect( IParticleEffect *pEffect )
{
AssignEffect( pEffect,true );
}
//////////////////////////////////////////////////////////////////////////
void CParticleEmitter::AssignEffect( IParticleEffect *pEffect,bool bChildEffects )
{
ReleaseParams();
m_bOwnParams = false;
m_pEffect = pEffect;
m_pParams = &m_pEffect->GetParticleParams(0);
ParticleParams& childParams = m_pEffect->GetParticleParams(1);
float fCurTime = m_pPartManager->GetParticlesTime();
m_startTime = fCurTime + m_pParams->fSpawnDelay.GetVariantValue();
SetLifeTime(m_pParams->fEmitterLifeTime.GetVariantValue());
m_spawnPeriod = m_pParams->fSpawnPeriod;
m_lastActiveTime = m_startTime;
m_lastSpawnTime = -100000.0f; // Force to spawn first time.
if (m_pParams->pChild)
{
m_pChildParams = m_pParams->pChild;
}
else if (childParams.nCount > 0)
{
m_pChildParams = &childParams;
}
//////////////////////////////////////////////////////////////////////////
// Keep object from suddenly deleting.
//////////////////////////////////////////////////////////////////////////
if (m_pParams && m_pParams->pStatObj)
m_pParams->pStatObj->RegisterUser();
if (m_pChildParams && m_pChildParams->pStatObj)
m_pChildParams->pStatObj->RegisterUser();
//////////////////////////////////////////////////////////////////////////
//Not needed. m_pMaterial = m_pParams->pMaterial;
m_pSpawnerEntity = m_pParams->pEntity;
m_pos = m_pParams->vPosition;
m_dir = m_pParams->vDirection;
m_bbox.min = m_bbox.max = m_pos;
//////////////////////////////////////////////////////////////////////////
// Play looped sound for this particle emitter.
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// Create child effects
//////////////////////////////////////////////////////////////////////////
if (bChildEffects && pEffect->GetChildCount() > 0)
{
for (int i = 0; i < pEffect->GetChildCount(); i++)
{
// Create child emitter.
CParticleEmitter *pEmitter = new CParticleEmitter(m_pPartManager);
pEmitter->m_bChildEmitter = true;
pEmitter->m_bPermament = true;
m_childEmitters.push_back( pEmitter );
CParticleEffect *pChildEffect = (CParticleEffect*)pEffect->GetChild(i);
pEmitter->SetEffect(pChildEffect);
pEmitter->m_bbox.min = pEmitter->m_bbox.max = m_pos;
// If uncommented Sounds of child emitters not playing then..
// pEmitter->m_bActive = true;
}
}
}
//////////////////////////////////////////////////////////////////////////
void CParticleEmitter::UpdateChildSpawnTimes( float fCurrTime )
{
for (int i = 0; i < (int)m_childEmitters.size(); i++)
{
CParticleEmitter *pEmitter = m_childEmitters[i];
if (pEmitter && pEmitter->m_pParams)
{
pEmitter->m_bActiveChild = true;
pEmitter->m_startTime = fCurrTime + pEmitter->m_pParams->fSpawnDelay.GetVariantValue();
pEmitter->SetLifeTime(pEmitter->m_pParams->fEmitterLifeTime.GetVariantValue());
}
}
}
//////////////////////////////////////////////////////////////////////////
const ParticleParams& CParticleEmitter::GetParams() const
{
return *m_pParams;
}
//////////////////////////////////////////////////////////////////////////
void CParticleEmitter::SetPos( const Vec3 &vPos,const Vec3 &vDir,float fScale )
{
bool bPosChanged = false;
if (m_pos != vPos)
bPosChanged = true;
m_pos = vPos;
m_dir = vDir;
m_fScale = fScale;
m_lastActiveTime = m_pPartManager->GetParticlesTime();
if (bPosChanged)
{
if (!m_bActive)
{
m_bbox.min = vPos;
m_bbox.max = vPos;
}
if (m_pSound)
{
// Update sound position.
m_pSound->SetPosition( m_pos + m_pParams->vPositionOffset );
}
for (int i = 0; i < (int)m_childEmitters.size(); i++)
{
CParticleEmitter *pEmitter = m_childEmitters[i];
if (pEmitter)
{
pEmitter->SetPos(vPos,vDir,fScale);
}
}
CalculateWaterLevel();
}
if (!m_bChildEmitter)
{
// Make sure this emitter is active.
m_pPartManager->ActivateEmitter( this );
}
}
//////////////////////////////////////////////////////////////////////////
void CParticleEmitter::SetSpawnPeriod( float fSpawnPeriod )
{
m_spawnPeriod = fSpawnPeriod;
}
//////////////////////////////////////////////////////////////////////////
void CParticleEmitter::SetLifeTime( float fLifeTime )
{
m_endTime = m_startTime + max(fLifeTime,0);
m_bUseEndTime=true;
}
//////////////////////////////////////////////////////////////////////////
void CParticleEmitter::SetUnlimitedLife()
{
m_bUseEndTime=false; // Unlimited life time.
}
//////////////////////////////////////////////////////////////////////////
void CParticleEmitter::SetEntity( IEntityRender *pEntity )
{
m_pSpawnerEntity = pEntity;
CalculateWaterLevel();
}
//////////////////////////////////////////////////////////////////////////
void CParticleEmitter::SetMaterial( IMatInfo *pMaterial )
{
m_pMaterial = pMaterial;
m_pShader = NULL;
if (m_pMaterial)
{
IShader *pContainerShader = m_pMaterial->GetShaderItem().m_pShader;
m_pShader = pContainerShader->GetTemplate(-1);
}
if(m_pMaterial)
m_pMaterial->SetFlags(m_pMaterial->GetFlags()|MIF_WASUSED);
}
void CParticleEmitter::CalculateWaterLevel()
{
// remember water level to avoid calculating it for each particle
if(m_pSpawnerEntity)
m_fWaterLevel = Cry3DEngineBase::Get3DEngine()->GetWaterLevel(m_pSpawnerEntity);
else
m_fWaterLevel = Cry3DEngineBase::Get3DEngine()->GetWaterLevel(&m_pos);
}
//////////////////////////////////////////////////////////////////////////
void CParticleEmitter::OnActivate( bool bActive )
{
if (bActive == m_bActive)
return;
m_bActive = bActive;
if (bActive)
{
// Effect is activated.
// Play sound if have.
ISoundSystem *pISoundSystem = GetISystem()->GetISoundSystem();
#if !defined(LINUX64)
if (pISoundSystem != NULL && m_pEffect != NULL)
#else
if (pISoundSystem != 0 && m_pEffect != 0)
#endif
{
// Check if effect needs to play sounds.
IParticleEffect::SoundParams soundParams;
m_pEffect->GetSoundParams( soundParams );
if (strlen(soundParams.szSound) > 0)
{
int nSndFlags = FLAG_SOUND_3D | FLAG_SOUND_RADIUS | FLAG_SOUND_OCCLUSION;
if (soundParams.bLoop && m_bPermament)
{
m_bLoopSound = true;
nSndFlags |= FLAG_SOUND_LOOP;
}
else
m_bLoopSound = false;
m_pSound = pISoundSystem->LoadSound( soundParams.szSound,nSndFlags );
#if !defined(LINUX64)
if (m_pSound != NULL && !soundParams.bOnEverySpawn)
#else
if (m_pSound != 0 && !soundParams.bOnEverySpawn)
#endif
{
PlaySound();
}
}
}
}
else
{
// Effect is deactivated.
if (m_pSound != 0 && m_bLoopSound)
{
m_pSound->Stop();
m_pSound = NULL;
}
}
// Activate/deactivate childs.
for (int i = 0; i < (int)m_childEmitters.size(); i++)
{
CParticleEmitter *pEmitter = m_childEmitters[i];
if (pEmitter)
{
pEmitter->OnActivate( bActive );
}
}
}
//////////////////////////////////////////////////////////////////////////
void CParticleEmitter::PlaySound()
{
if (!m_pEffect || !m_pSound)
return;
IParticleEffect::SoundParams soundParams;
m_pEffect->GetSoundParams( soundParams );
m_pSound->SetVolume( (int)soundParams.volume );
m_pSound->SetMinMaxDistance( soundParams.minRadius,soundParams.maxRadius );
Vec3 vOffset = m_pParams->vPositionOffset;
m_pSound->SetPosition( m_pos + vOffset );
m_pSound->Play();
}
//////////////////////////////////////////////////////////////////////////
// Called when particles are spawned.
//////////////////////////////////////////////////////////////////////////
void CParticleEmitter::OnSpawnParticles( bool bChildProcess )
{
#if !defined(LINUX64)
if (!bChildProcess && m_pSound != NULL && m_pEffect != NULL)
#else
if (!bChildProcess && m_pSound != 0 && m_pEffect != 0)
#endif
{
IParticleEffect::SoundParams soundParams;
m_pEffect->GetSoundParams( soundParams );
if (soundParams.bOnEverySpawn)
{
PlaySound();
}
}
}

View File

@@ -0,0 +1,127 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: particleemitter.h
// Version: v1.00
// Created: 18/7/2003 by Timur.
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#ifndef __particleemitter_h__
#define __particleemitter_h__
#pragma once
#include <ISound.h>
/*! Temporary emitter position for ParticleEffects.
*/
class CParticleEmitter : public IParticleEmitter
{
public:
uint m_bOwnParams : 1; //!< True if particle created its own particle params.
uint m_bActive : 1; //!< True when this emitter is active.
uint m_bActiveChild : 1; //!< True when child emitter is active.
uint m_bPermament : 1; //!< True when this emitter is permament (temporary emitters not added to particle manager).
uint m_bLoopSound : 1; //!< True when playing looped sound.
uint m_bVisible : 1; //!< True if emitter is visible.
uint m_bUseEndTime : 1; //!< True if m_endTime is used
uint m_bChildEmitter : 1; //!< True if this child emitter (Only with permament parent emitter).
//! Position of the emitter.
Vec3 m_pos;
//! Direction of the emitter.
Vec3 m_dir;
//! Scale for particles at this emitter.
float m_fScale;
//! When this emitter must be activated.
float m_startTime;
//! When this emitter must be killed. (only used when m_bUseEndTime is true)
float m_endTime;
//! How often to spawn particles, time in seconds between 2 successing spawns.
float m_spawnPeriod;
// Last time when particles where spawned.
float m_lastSpawnTime;
//! Pointer to particle params. (ParticleEffect).
ParticleParams *m_pParams;
//! Pointer to child params of this emitter.
ParticleParams *m_pChildParams;
//! Notify time when position was last set on this emitter.
float m_lastActiveTime;
//! Particle effect used for this emitter.
IParticleEffect_AutoPtr m_pEffect;
//! Owner particle manager.
class CPartManager *m_pPartManager;
//! Override material for this emitter.
_smart_ptr<IMatInfo> m_pMaterial;
//! Entity who controls this emitter.
IEntityRender *m_pSpawnerEntity;
//! Custom shader from material.
_smart_ptr<IShader> m_pShader;
//! Bounding box.
AABB m_bbox;
//! Water level in position of emitter. Used to avoid calculating it for each particle.
float m_fWaterLevel;
//////////////////////////////////////////////////////////////////////////
std::vector<_smart_ptr<CParticleEmitter> > m_childEmitters;
//////////////////////////////////////////////////////////////////////////
// Particle emitter looped sound.
_smart_ptr<ISound> m_pSound;
//////////////////////////////////////////////////////////////////////////
// Methods.
//////////////////////////////////////////////////////////////////////////
CParticleEmitter( CPartManager *pPartManager ) : m_pos(0,0,0),m_dir(0,0,0)
{
m_pPartManager = pPartManager;
m_pSpawnerEntity = NULL;
m_startTime = m_endTime = m_lastActiveTime = m_spawnPeriod = m_lastSpawnTime = 0;
m_pParams = 0;
m_pChildParams = 0;
m_bOwnParams = false;
m_fScale = 1;
m_bActive = false;
m_bActiveChild = false;
m_bPermament = false;
m_bVisible = true;
m_fWaterLevel = WATER_LEVEL_UNKNOWN;
m_bLoopSound = false;
m_bUseEndTime=false;
m_bChildEmitter = false;
}
~CParticleEmitter();
void ReleaseParams();
void UpdateChildSpawnTimes( float fCurrTime );
// Only when not effect.
void InitTexture( ParticleParams *pParams );
void AssignEffect( IParticleEffect *pEffect,bool bChildEffects );
void CalculateWaterLevel();
void OnActivate( bool bActive );
void OnSpawnParticles( bool bChildProcess );
void PlaySound();
//////////////////////////////////////////////////////////////////////////
// IParticleEmitter interface implementation.
//////////////////////////////////////////////////////////////////////////
virtual void SetParams( const ParticleParams &params );
virtual void SetEffect( IParticleEffect *pEffect );
virtual const ParticleParams& GetParams() const;
virtual void SetPos( const Vec3 &vPos,const Vec3 &vDir,float fScale );
virtual void SetSpawnPeriod( float fSpawnPeriod );
virtual void SetLifeTime( const float fLifeTime );
virtual void SetUnlimitedLife();
virtual void SetEntity( IEntityRender *pEntity );
virtual void SetMaterial( IMatInfo *pMaterial );
};
#endif // __particleemitter_h__

491
Cry3DEngine/SaveCFG.cpp Normal file
View File

@@ -0,0 +1,491 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: savecfg.cpp
// Version: v1.00
// Created: 28/5/2002 by Andrey
// Compilers: Visual Studio.NET
// Description: cgf file writer
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "3dEngine.h"
#include "CryStaticModel.h"
#include "statobj.h"
#include "MeshIdx.h"
bool C3DEngine::WriteMaterials(TArray<CHUNK_HEADER>& Chunks, TArray<IShader *>& Shaders, FILE *out, int &MatChunk)
{
CHUNK_HEADER ch;
// the type and version of the material chunk
typedef MTL_CHUNK_DESC_0745 MTL_CHUNK_TYPE;
MTL_CHUNK_TYPE chunk;
memset (&chunk, 0, sizeof(chunk));
int Offs = ftell(out);
ch.ChunkType = ChunkType_Mtl;
ch.ChunkID = Chunks.Num();
MatChunk = ch.ChunkID;
ch.ChunkVersion = MTL_CHUNK_TYPE::VERSION;
ch.FileOffset = Offs;
Offs += sizeof(chunk) + sizeof(int) * Shaders.Num();
Chunks.AddElem(ch);
int i=0;
for (i=0; i<Shaders.Num(); i++)
{
ch.ChunkType = ChunkType_Mtl;
ch.ChunkID = Chunks.Num();
ch.ChunkVersion = MTL_CHUNK_TYPE::VERSION;
ch.FileOffset = Offs;
Offs += sizeof(chunk);
Chunks.AddElem(ch);
}
chunk.chdr = Chunks[MatChunk];
chunk.MtlType = MTL_MULTI;
strcpy(chunk.name, "Multi");
chunk.nChildren = Shaders.Num();
fwrite(&chunk, 1, sizeof(chunk), out);
for (i=0; i<Shaders.Num(); i++)
{
int nn = MatChunk+i;
fwrite(&nn, 1, sizeof(int), out);
}
/*for (i=0; i<Shaders.Num(); i++)
{
memset(&chunk, 0, sizeof(chunk));
chunk.chdr = Chunks[MatChunk+i+1];
chunk.MtlType = MTL_STANDARD;
IShader *sh = Shaders[i];
strcpy(chunk.name, sh->GetName());
if (sh->GetTemplates())
{
SEfTemplates *eft = sh->GetTemplates();
for (int j=0; j<16; j++)
{
if (!eft->m_TexInfo[j].m_Name.empty())
{
switch (j)
{
case EFTT_DECAL:
strcpy(chunk.tex_d.name, eft->m_TexInfo[j].m_Name);
break;
case EFTT_BUMP:
case EFTT_DSDTBUMP:
strcpy(chunk.tex_b.name, eft->m_TexInfo[j].m_Name);
break;
case EFTT_GLOSS:
strcpy(chunk.tex_g.name, eft->m_TexInfo[j].m_Name);
break;
case EFTT_OPACITY:
strcpy(chunk.tex_o.name, eft->m_TexInfo[j].m_Name);
break;
case EFTT_ENVIRONMENT:
case EFTT_REFLECTION:
strcpy(chunk.tex_rl.name, eft->m_TexInfo[j].m_Name);
break;
case EFTT_REFRACTION:
strcpy(chunk.tex_rr.name, eft->m_TexInfo[j].m_Name);
break;
case EFTT_CUBEMAP:
strcpy(chunk.tex_c.name, eft->m_TexInfo[j].m_Name);
break;
case EFTT_SPECULAR:
strcpy(chunk.tex_s.name, eft->m_TexInfo[j].m_Name);
break;
case EFTT_DETAIL:
strcpy(chunk.tex_det.name, eft->m_TexInfo[j].m_Name);
break;
}
}
}
}
else
strcpy(chunk.tex_d.name, chunk.name);
chunk.Dyn_Bounce = 1;
chunk.Dyn_StaticFriction = 1;
chunk.Dyn_SlidingFriction = 1;
chunk.nChildren = -1;
fwrite(&chunk, 1, sizeof(chunk), out);
}*/
return true;
}
struct SNodeInfo
{
int bGlobals;
int Sector;
CStatObj *pObj;
char name[64];
};
bool C3DEngine::WriteNodes(TArray<CHUNK_HEADER>& Chunks, TArray<NODE_CHUNK_DESC>& Nodes, FILE *out, TArray<SNodeInfo>& NI, int& MatChunk, int& ExpFrame, std::vector<IStatObj *>& pObjs)
{
CHUNK_HEADER ch;
int numMeshs = 0;
NODE_CHUNK_DESC nd;
SNodeInfo ni;
int i;
NI.Free();
ExpFrame++;
int nChildren;
std::vector<IStatObj*>::iterator n;
for (n=pObjs.begin();n!=pObjs.end();n++)
{
IStatObj *io = (*n);
CStatObj *co = (CStatObj *)io;
memset(&nd, 0, sizeof(NODE_CHUNK_DESC));
strcpy(nd.name, co->m_szGeomName);
nd.tm.SetIdentity();
nd.scl = Vec3(1.0,1.0,1.0);
nd.MatID = MatChunk;
nd.ObjectID = numMeshs++;
int nnd = Nodes.Num();
Nodes.AddElem(nd);
ni.bGlobals = 1;
ni.pObj = co;
strcpy(ni.name, nd.name);
NI.AddElem(ni);
nChildren = 0;
Nodes[nnd].nChildren = nChildren;
}
memset(&ch, 0, sizeof(CHUNK_HEADER));
int no = Chunks.Num() + Nodes.Num();
for (i=0; i<Nodes.Num(); i++)
{
Nodes[i].ObjectID += no;
ch.ChunkType = ChunkType_Node;
ch.ChunkID = Chunks.Num();
ch.ChunkVersion = NODE_CHUNK_DESC_VERSION;
ch.FileOffset = ftell(out);
Nodes[i].chdr = ch;
Chunks.AddElem(ch);
fwrite(&Nodes[i], sizeof(NODE_CHUNK_DESC), 1, out);
for (int j=0; j<Nodes[i].nChildren; j++)
{
int nn = Nodes[i].chdr.ChunkID+1+j;
fwrite(&nn, sizeof(int), 1, out);
}
}
return true;
}
bool C3DEngine::WriteNodeMesh(int nNode, MESH_CHUNK_DESC *chunk, FILE *out, TArray<IShader *>& Shaders, TArray<SNodeInfo>& NI, CStatObj *pObj)
{
TArray<CryVertex> Verts;
TArray<CryFace> Faces;
TArray<CryUV> UVs;
TArray<CryTexFace> TFaces;
TArray<CryIRGB> Colors;
int i, j;
SNodeInfo *ni = &NI[nNode];
CIndexedMesh *pMesh = pObj->GetTriData();
for (i=0; i<pMesh->m_nFaceCount; i++)
{
CryFace fc;
CryTexFace tf;
fc.v0 = pMesh->m_pFaces[i].v[0];
fc.v1 = pMesh->m_pFaces[i].v[1];
fc.v2 = pMesh->m_pFaces[i].v[2];
tf.t0 = pMesh->m_pFaces[i].t[0];
tf.t1 = pMesh->m_pFaces[i].t[1];
tf.t2 = pMesh->m_pFaces[i].t[2];
int ns = pMesh->m_pFaces[i].shader_id;
IShader *sh = pMesh->m_lstMatTable[ns].shaderItem.m_pShader;
for (j=0; j<Shaders.Num(); j++)
{
if (!stricmp(sh->GetName(), Shaders[j]->GetName()))
break;
}
assert (j != Shaders.Num());
fc.MatID = j;
fc.SmGroup = 0;
Faces.AddElem(fc);
TFaces.AddElem(tf);
}
for (i=0; i<pMesh->m_nVertCount; i++)
{
CryVertex vr;
CryIRGB rgb;
vr.p[0] = pMesh->m_pVerts[i].x * 100.0f;
vr.p[1] = pMesh->m_pVerts[i].y * 100.0f;
vr.p[2] = pMesh->m_pVerts[i].z * 100.0f;
vr.n[0] = pMesh->m_pNorms[i].x;
vr.n[1] = pMesh->m_pNorms[i].y;
vr.n[2] = pMesh->m_pNorms[i].z;
rgb.r = pMesh->m_pColor[i].r;
rgb.g = pMesh->m_pColor[i].g;
rgb.b = pMesh->m_pColor[i].b;
Verts.AddElem(vr);
Colors.AddElem(rgb);
}
for (i=0; i<pMesh->m_nCoorCount; i++)
{
CryUV uv;
uv.u = pMesh->m_pCoors[i].s;
uv.v = pMesh->m_pCoors[i].t;
UVs.AddElem(uv);
}
chunk->nFaces = Faces.Num();
chunk->nTVerts = UVs.Num();
chunk->nVerts = Verts.Num();
chunk->VertAnimID = 0;
if (Colors.Num())
chunk->HasVertexCol = 1;
else
chunk->HasVertexCol = 0;
fwrite(chunk, 1, sizeof(MESH_CHUNK_DESC), out);
fwrite(&Verts[0], sizeof(CryVertex), chunk->nVerts, out);
fwrite(&Faces[0], sizeof(CryFace), chunk->nFaces, out);
fwrite(&UVs[0], sizeof(CryUV), chunk->nTVerts, out);
fwrite(&TFaces[0], sizeof(CryTexFace), chunk->nFaces, out);
if (chunk->HasVertexCol)
fwrite(&Colors[0], sizeof(CryIRGB), chunk->nVerts, out);
return true;
}
bool C3DEngine::WriteMesh(TArray<CHUNK_HEADER>& Chunks, TArray<NODE_CHUNK_DESC>& Nodes, TArray<IShader *>& Shaders, FILE *out, TArray<SNodeInfo>& NI, int& MatChunk, int& ExpFrame)
{
MESH_CHUNK_DESC chunk;
CHUNK_HEADER ch;
ExpFrame++;
for (int i=0; i<Nodes.Num(); i++)
{
NODE_CHUNK_DESC *nd = &Nodes[i];
SNodeInfo *ni = &NI[i];
ch.ChunkType = ChunkType_Mesh;
ch.ChunkID = Chunks.Num();
ch.ChunkVersion = GeomFileVersion;
ch.FileOffset = ftell(out);
Chunks.AddElem(ch);
chunk.chdr = ch;
chunk.HasBoneInfo = 0;
chunk.HasVertexCol = 0;
WriteNodeMesh(i, &chunk, out, Shaders, NI, ni->pObj);
}
return true;
}
bool C3DEngine::WriteLights(TArray<CHUNK_HEADER>& Chunks, TArray<NODE_CHUNK_DESC>& Nodes, FILE *out, std::vector<IStatObj *>& pObjs)
{
LIGHT_CHUNK_DESC lcd;
CHUNK_HEADER ch;
NODE_CHUNK_DESC nd;
std::vector<IStatObj*>::iterator n;
for (n=pObjs.begin();n!=pObjs.end();n++)
{
IStatObj *io = (*n);
CStatObj *co = (CStatObj *)io;
// CIndexedMesh *im = co->GetTriData();
for (int j=0; j<co->m_lstLSources.Count(); j++)
{
CDLight *dl = &co->m_lstLSources[j];
memset(&lcd, 0, sizeof(LIGHT_CHUNK_DESC));
memset(&ch, 0, sizeof(CHUNK_HEADER));
memset(&nd, 0, sizeof(NODE_CHUNK_DESC));
int no = Chunks.Num();
ch.ChunkType = ChunkType_Node;
ch.ChunkID = Chunks.Num();
ch.ChunkVersion = NODE_CHUNK_DESC_VERSION;
ch.FileOffset = ftell(out);
Chunks.AddElem(ch);
nd.chdr = ch;
nd.ObjectID = Chunks.Num();
if (dl->m_Name)
strcpy(nd.name, dl->m_Name);
else
nd.name[0] = 0;
Vec3d Org;
/* if (dl->m_OrigLight)
Org = dl->m_OrigLight->m_Origin;
else
Org = dl->m_Origin;
*/ nd.pos.x = Org[0] * 100.0f;
nd.pos.y = Org[1] * 100.0f;
nd.pos.z = Org[2] * 100.0f;
nd.tm.SetIdentity();
nd.tm[3][0] = nd.pos.x;
nd.tm[3][1] = nd.pos.y;
nd.tm[3][2] = nd.pos.z;
nd.scl = Vec3(1.0f, 1.0f, 1.0f);
fwrite(&nd, sizeof(NODE_CHUNK_DESC), 1, out);
// Light
ch.ChunkType = ChunkType_Light;
ch.ChunkID = Chunks.Num();
ch.ChunkVersion = LIGHT_CHUNK_DESC_VERSION;
ch.FileOffset = ftell(out);
Chunks.AddElem(ch);
lcd.chdr = ch;
lcd.intens = dl->m_fRadius * 100.0f;
if (lcd.intens <= 0)
lcd.intens = 500;
lcd.attenEnd = lcd.intens;
UCol col;
col.dcolor = dl->m_Color.GetTrue();
lcd.color.r = col.bcolor[0];
lcd.color.g = col.bcolor[1];
lcd.color.b = col.bcolor[2];
lcd.vDirection = dl->m_ProjAngles;
lcd.fallsize = dl->m_fLightFrustumAngle;
if (dl->m_pLightImage)
{
strcpy(lcd.szLightImage, dl->m_pLightImage->GetName());
lcd.type = LT_OMNI;
}
else
if (dl->m_Flags & DLF_DIRECTIONAL)
lcd.type = LT_DIRECT;
else
if (dl->m_Flags & DLF_POINT)
{
lcd.useAtten = true;
lcd.type = LT_OMNI;
}
fwrite(&lcd, sizeof(LIGHT_CHUNK_DESC), 1, out);
}
}
return true;
}
bool C3DEngine::SaveCGF(std::vector<IStatObj *>& pObjs)
{
TArray<CHUNK_HEADER> Chunks;
TArray<NODE_CHUNK_DESC> Nodes;
TArray<IShader *> Shaders;
TArray<SNodeInfo> NI;
int ExpFrame = 0;
char fName[1024];
int res;
int i, j;
int MatChunk;
if (pObjs.empty())
return false;
IStatObj *io = pObjs.front();
CStatObj *so = (CStatObj *)io;
// Remove extension
char *in = so->m_szFileName;
char *o = fName;
char c;
while (*in)
{
if (*in=='.')
{
c = in[1];
if (c!='.' && c!='/' && c!='\\')
break;
}
*o++ = *in++;
}
*o = 0;
// Add default extension
strcat(fName, ".cgf");
FILE *out = fxopen(fName, "wb");
if (!out)
return false;
FILE_HEADER hd;
strcpy(hd.Signature, FILE_SIGNATURE);
hd.Version = GeomFileVersion;
hd.FileType = FileType_Geom;
//write the header
res = fwrite(&hd, sizeof(hd), 1, out);
if(res != 1)
return false;
std::vector<IStatObj*>::iterator n;
for (n=pObjs.begin();n!=pObjs.end();n++)
{
IStatObj *io = (*n);
CStatObj *co = (CStatObj *)io;
CLeafBuffer *lb = co->GetLeafBuffer();
// Prepare shaders for write
for (i=0; i<lb->m_pMats->Count(); i++)
{
IShader *e = (*lb->m_pMats)[i].shaderItem.m_pShader;
if (!e)
continue;
for (j=0; j<Shaders.Num(); j++)
{
if (!stricmp(e->GetName(), Shaders[j]->GetName()))
break;
}
if (j == Shaders.Num())
Shaders.AddElem(e);
}
}
WriteMaterials(Chunks, Shaders, out, MatChunk);
WriteNodes(Chunks, Nodes, out, NI, MatChunk, ExpFrame, pObjs);
WriteMesh(Chunks, Nodes, Shaders, out, NI, MatChunk, ExpFrame);
Nodes.Free();
WriteLights(Chunks, Nodes, out, pObjs);
hd.ChunkTableOffset = ftell(out);
int nn = Chunks.Num();
fwrite(&nn, sizeof(int), 1, out);
for (i=0; i<Chunks.Num(); i++)
{
fwrite(&Chunks[i], sizeof(CHUNK_HEADER), 1, out);
}
fseek(out, 0, SEEK_SET);
fwrite(&hd, sizeof(hd), 1, out);
fclose (out);
return true;
}
//============================================================================================

View File

@@ -0,0 +1,128 @@
//////////////////////////////////////////////////////////////////////
//
// Crytek Indoor Engine DLL source code
//
// File: ShadowVolumeEdge.h
//
// History:
// -September 29,2001:Created by Marco Corbetta
//
//////////////////////////////////////////////////////////////////////
#ifndef SHADOWVOLEDGE_H
#define SHADOWVOLEDGE_H
#if _MSC_VER > 1000
# pragma once
#endif
//////////////////////////////////////////////////////////////////////
//TODO: Move into Irenderer.h when changing that file it will not cause
//the entire workspace to be recompiled
//////////////////////////////////////////////////////////////////////
#define FLAG_FALSE_EDGE_SILOHUETTE 1
#define FLAG_IN_SURFACE_CONTACT_V0 2
#define FLAG_IN_SURFACE_CONTACT_V1 4
#define FLAG_BLACK_FACE 8
//////////////////////////////////////////////////////////////////////
struct CObjFace;
class CShadowVolEdge;
//this is put into a structure and allocated if necessary to
//save memory
//////////////////////////////////////////////////////////////////////
struct tAddEdgeInfo
{
tAddEdgeInfo()
{
m_dwFlags=0;
}
//! shadow plane + 4 volume edges plane's equation
Plane m_Planes[1];
//! silhouette direction
Vec3d m_vUp;
/*! since the edge is shared by more than 1 face, i have to keep
the right vectors here and not in the face
each face has vright information for both points of the edge
original vectors */
Vec3d m_vRight1[2];
Vec3d m_vRight2[2];
//! after interpolation,based on the faces lit by light
Vec3d m_vRightInterp1[2];
Vec3d m_vRightInterp2[2];
float m_fDist1[2];
float m_fDist2[2];
//! extruded edge (1 face only-in and out)
Vec3d m_vExtrOut[2];
Vec3d m_vExtrIn[2];
//center of the projected edge
Vec3d m_vCenter;
std::vector<CShadowVolEdge*> m_lstConnectedEdges1;
std::vector<CShadowVolEdge*> m_lstConnectedEdges2;
unsigned char m_dwFlags;
};
//shadow volume edge,used to build static or dynamic silouhette
//////////////////////////////////////////////////////////////////////
class CShadowVolEdge
{
public:
CShadowVolEdge()
{
m_pFace1=NULL;
m_pFace2=NULL;
m_nVNum0=m_nVNum1=0;
m_pAddEdge=NULL;
}
~CShadowVolEdge()
{
if (m_pAddEdge)
{
delete [] m_pAddEdge;
m_pAddEdge=NULL;
}
}
/*
//check if the point is on the extent of the shadow volume edge
bool PointOnEdge(const Vec3d &vPoint);
//clip with planes formed with the edges
bool ClipAdditionalEdge(Vec3d &vP1,Vec3d &vP2);
//to call once the edges and face plane are defined
void CreateAdditionalPlanes();
*/
//! orginal ednpoints of the silouhette edge
Vec3d m_vecV0;
Vec3d m_vecV1;
//! for dynamic models, to quick access modified vertices
int m_nVNum0;
int m_nVNum1;
//! projected edge
//Vec3d m_vecEv0,m_vecEv1,m_vecEv2,m_vecEv3;
Vec3d m_vecEv[4];
//! the two faces the edge belongs to
CObjFace *m_pFace1;
CObjFace *m_pFace2;
tAddEdgeInfo *m_pAddEdge;
};
typedef std::vector<CShadowVolEdge *>::iterator connedgeit;
#endif //shadowvoledge

View File

@@ -0,0 +1,410 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: spritemanager.cpp
// Version: v1.00
// Created: 18/7/2003 by Timur.
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History: Created by Vladimir
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "partman.h"
#include "objman.h"
#include "visareas.h"
//#include "ParticleEffect.h"
#include "3dEngine.h"
CSpriteManager::CSpriteManager( CPartManager *pPartManager )
{
m_nMaxSpritesCount = min(16384, max(16,GetCVars()->e_particles_max_count));
m_arrSprites = new CSprite[m_nMaxSpritesCount];
m_nCurSpritesCount=0;
memset(m_arrSprites,0,sizeof(CSprite)*m_nMaxSpritesCount);
m_pSystem = GetSystem();
m_p3DEngine = Get3DEngine();
m_pVisAreaManager = GetVisAreaManager();
m_pObjManager = ((C3DEngine*)m_p3DEngine)->GetObjManager();
m_pPartManager = pPartManager;
}
CSpriteManager::~CSpriteManager()
{
delete [] m_arrSprites;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CSpriteManager::Spawn( CParticleEmitter &emitter,bool bChildProcess )
{
FUNCTION_PROFILER_FAST( GetSystem(),PROFILE_3DENGINE,m_bProfilerEnabled );
// make sprites
ParticleParams &Params = (!bChildProcess) ? *emitter.m_pParams : *emitter.m_pParams->pChild;
if(!_finite(Params.vPosition.x) || !_finite(Params.vPosition.y) || !_finite(Params.vPosition.z))
{
// GetLog()->Log("Warning: CSpriteManager::Spawn: Particle emitter position is undefined");
return;
}
//////////////////////////////////////////////////////////////////////////
/* if(GetCVars()->e_particles_debug==1)
{
Params.fSpeed = Params.fSpeed / 10;
Params.fLifeTime = Params.fLifeTime*10;
Params.vGravity/=10;
}*/
/*
if (Params.fScale != 1.0f && Params.fScale > 0)
{
float fScale = Params.fScale;
// Adjust particle parameters by scale.
Params.fSize = Params.fSize*fScale;
Params.fPosRandomOffset *= fScale;
Params.vGravity *= fScale;
Params.vPositionOffset *= fScale;
Params.vRandomPositionOffset *= fScale;
Params.fSizeSpeed *= fScale;
Params.fSpeed = Params.fSpeed*fScale;
Params.fTailLenght *= fScale;
Params.fTurbulenceSize *= fScale;
//Params.fTurbulenceSpeed *= fScale;
if (Params.pChild)
{
Params.pChild->fSize = Params.pChild->fSize*fScale;
Params.pChild->fPosRandomOffset *= fScale;
Params.pChild->vGravity *= fScale;
Params.pChild->vPositionOffset *= fScale;
Params.pChild->vRandomPositionOffset *= fScale;
Params.pChild->fSizeSpeed *= fScale;
Params.pChild->fSpeed = Params.pChild->fSpeed*fScale;
Params.pChild->fTailLenght *= fScale;
Params.pChild->fTurbulenceSize *= fScale;
}
}
*/
float fCurrTime = m_pPartManager->GetParticlesTime();
int nCount = max(1,int(Params.nCount*GetCVars()->e_particles_lod));
// pass Params structure to CPartSpray::Spawn() nCount times
for(int i=0; i < nCount; i++)
{
if(m_nCurSpritesCount>=m_nMaxSpritesCount)
break;
CSprite * pSprite = &m_arrSprites[m_nCurSpritesCount];
// spawn one sprite
SpawnParticle( emitter,bChildProcess,fCurrTime,pSprite );
m_nCurSpritesCount++;
}
}
//////////////////////////////////////////////////////////////////////////
void CSpriteManager::SpawnParticle( CParticleEmitter &emitter,bool bChildProcess,float fCurrTime,CParticle *pPart )
{
if (!bChildProcess)
pPart->m_pParams = emitter.m_pParams;
else
pPart->m_pParams = emitter.m_pParams->pChild;
ParticleParams &Params = *pPart->m_pParams;
// Params.nParticleFlags |= PART_FLAG_LINEPARTICLE;
//Params.vDirection = Vec3d(0,100,0);
//pPart->m_pVisArea = m_pVisAreaManager->GetVisAreaFromPos(Params.vPosition);
pPart->m_pEmitter = &emitter;
pPart->m_pEmitter->AddRef();
// Get scale for this particle.
float fScale = emitter.m_fScale;
pPart->m_fScale = fScale;
pPart->m_nParticleFlags = Params.nParticleFlags;
if (Params.eBlendType == ParticleBlendType_Additive)
{
pPart->m_nParticleFlags |= CParticle::PARTICLE_COLOR_BASED | CParticle::PARTICLE_ADDITIVE;
}
else if (Params.eBlendType == ParticleBlendType_ColorBased)
{
pPart->m_nParticleFlags |= CParticle::PARTICLE_COLOR_BASED;
}
if (Params.nParticleFlags & PART_FLAG_RIGIDBODY)
{
// Also set no offset flag.
Params.nParticleFlags |= PART_FLAG_NO_OFFSET;
}
if (Params.nTexAnimFramesCount > 1)
pPart->m_nParticleFlags |= CParticle::PARTICLE_ANIMATED_TEXTURE;
// calculate focus and dir
if(Params.nParticleFlags & PART_FLAG_LINEPARTICLE)
pPart->m_vDelta = Params.vDirection;
else if(Params.nParticleFlags & PART_FLAG_FOCUS_PLANE)
{
// Distribute particles on plane.
Vec3 dir = Params.vDirection;
if(Params.nParticleFlags & PART_FLAG_SPEED_IN_GRAVITY_DIRECTION)
{
dir = -Params.vGravity;
if (dir.IsZero()) dir = Vec3(0,0,1);
dir.Normalize();
}
Vec3 n1 = Vec3(0,1,0);
if (n1 == dir)
n1 = Vec3(1,0,0);
n1 = dir.Cross(n1);
Vec3 n2 = dir.Cross(n1);
Matrix33 tm;
tm.SetMatFromVectors( dir,n1,n2 );
Vec3d vPartDir(2.0f*rnd()-1.0f,2.0f*rnd()-1.0f,2.0f*rnd()-1.0f);
float focus = max(0,min(1,Params.fFocus));
vPartDir.x *= focus;
vPartDir.Normalize();
vPartDir = tm * vPartDir;
vPartDir *= Params.fSpeed.GetVariantValue();
pPart->m_vDelta = vPartDir*fScale;
}
else if(Params.nParticleFlags & PART_FLAG_SPEED_IN_GRAVITY_DIRECTION)
{
Vec3d vGravityDir = -Params.vGravity;
Vec3d vPartDir(rnd()-0.5f,rnd()-0.5f,rnd()-0.5f);
if (vPartDir.IsZero()) vPartDir = Vec3(0,0,1);
if (vGravityDir.IsZero())
vGravityDir = Vec3(0,0,-1);
else
vGravityDir.Normalize();
vPartDir.Normalize();
vPartDir += vGravityDir*Params.fFocus;
vPartDir.Normalize();
vPartDir *= Params.fSpeed.GetVariantValue();/* * (0.75f+0.5f*rnd());*/
pPart->m_vDelta = vPartDir*fScale;
}
else
{
Vec3d vPartDir(rnd()-0.5f,rnd()-0.5f,rnd()-0.5f);
vPartDir.Normalize();
vPartDir += Params.vDirection*Params.fFocus;
vPartDir.Normalize();
vPartDir *= Params.fSpeed.GetVariantValue();/* * (0.75f+0.5f*rnd());*/
pPart->m_vDelta = vPartDir*fScale;
}
// do not move water waves in vertical direction
if(Params.nParticleFlags & PART_FLAG_HORIZONTAL)
pPart->m_vDelta.z = 0;
// set params
if(Params.nParticleFlags & PART_FLAG_SPACELOOP)
{
pPart->m_vPos = Params.vPosition + Vec3d(rnd()-0.5f,rnd()-0.5f,rnd()-0.5f)*32;
/*
float fModX = fabs(Params.vDirection.x);
float fModY = fabs(Params.vDirection.y);
float fModZ = fabs(Params.vDirection.z);
if(fModX>fModY && fModX>fModZ)
pPart->m_vPos.x = Params.vPosition.x + (Params.vDirection.x>0 ? -Params.vSpaceLoopBoxSize.x : Params.vSpaceLoopBoxSize.x);
else if(fModY>fModX && fModY>fModZ)
pPart->m_vPos.y = Params.vPosition.y + (Params.vDirection.y>0 ? -Params.vSpaceLoopBoxSize.y : Params.vSpaceLoopBoxSize.y);
else
pPart->m_vPos.z = Params.vPosition.z + (Params.vDirection.z>0 ? -Params.vSpaceLoopBoxSize.z : Params.vSpaceLoopBoxSize.z);*/
}
else if(Params.fPosRandomOffset)
{ // random offset
Vec3d vOffset(rnd()-0.5f,rnd()-0.5f,rnd()-0.5f);
vOffset *= (Params.fPosRandomOffset*2)*fScale;
pPart->m_vPos = Params.vPosition + vOffset;
}
else
{
pPart->m_vPos = Params.vPosition;
}
if (!Params.vRandomPositionOffset.IsZero())
{
Vec3 vrnd;
vrnd.x = (2.0f*rnd()-1.0f) * Params.vRandomPositionOffset.x;
vrnd.y = (2.0f*rnd()-1.0f) * Params.vRandomPositionOffset.y;
vrnd.z = (2.0f*rnd()-1.0f) * Params.vRandomPositionOffset.z;
pPart->m_vPos += vrnd*fScale;
}
pPart->m_vPos += Params.vPositionOffset*fScale;
pPart->m_fSizeOriginal = Params.fSize.GetVariantValue()*fScale;
pPart->m_fSize = pPart->m_fSizeOriginal;
pPart->m_vAngles = Params.vInitAngles.GetVariantValue();
pPart->m_vRotation = Params.vRotation.GetVariantValue();
pPart->m_fLifeTime = Params.fLifeTime.GetVariantValue();
pPart->m_fSpawnTime = fCurrTime;
if (Params.fTailLenght)
{
pPart->m_nTailSteps = Params.nTailSteps;
if (pPart->m_nTailSteps <= 0)
pPart->m_nTailSteps = 8; // Default steps.
if (pPart->m_nTailSteps > 16)
pPart->m_nTailSteps = 16; // Max steps (Renderer cant do more).
// init history stack
pPart->m_fTrailCurPos = 1.0f;
pPart->m_pArrvPosHistory = new Vec3[pPart->m_nTailSteps];
for(int t=0; t < pPart->m_nTailSteps; t++)
pPart->m_pArrvPosHistory[t] = Params.vPosition;
}
// init physical particle if requested
if(Params.bRealPhysics /* && GetCVars()->e_particles_allow_physics */)
pPart->Physicalize( Params,m_pSystem->GetIPhysicalWorld() );
pPart->m_fChildSpawnLastTime = fCurrTime;
// set statobj
// if(Params.pStatObj)
// Params.pStatObj->RegisterUser(); // prevent object deleting
// get ambient color
Vec3d vAmbientColor = m_p3DEngine->GetAmbientColorFromPosition(Params.vPosition);
Vec3d vWorldColor = Get3DEngine()->GetWorldColor();
vAmbientColor.x *= vWorldColor.x;
vAmbientColor.y *= vWorldColor.y;
vAmbientColor.z *= vWorldColor.z;
vAmbientColor.CheckMin(Vec3d(1,1,1));
pPart->m_cAmbientColor = pPart->Vec2Color(vAmbientColor);
//pPart->m_nDynLightMask = 0;//pSystem->GetI3DEngine()->GetLightMaskFromPosition(Params.vPosition);
//float fSize = pPart->m_fSize;
//pPart->m_nFogVolumeId = m_p3DEngine->GetFogVolumeIdFromBBox(
//Params.vPosition-Vec3d(fSize,fSize,fSize),
//Params.vPosition+Vec3d(fSize,fSize,fSize));
if (Params.pMaterial)
{
pPart->m_pMaterial = Params.pMaterial;
}
else
pPart->m_pMaterial = emitter.m_pMaterial;
pPart->m_pSpawnerEntity = emitter.m_pSpawnerEntity;
}
//////////////////////////////////////////////////////////////////////////
void CSpriteManager::Render(CObjManager * pObjManager, CTerrain * pTerrain, int nRecursionLevel, CPartManager * pPartManager, IShader * pPartLightShader)
{
// update max sprites count if console variable changed
if(m_nMaxSpritesCount != min(16384, max(16,GetCVars()->e_particles_max_count)))
{
m_nMaxSpritesCount = min(16384, max(16,GetCVars()->e_particles_max_count));
delete [] m_arrSprites;
m_arrSprites = new CSprite[m_nMaxSpritesCount];
memset(m_arrSprites,0,sizeof(CSprite)*m_nMaxSpritesCount);
m_nCurSpritesCount=0;
}
// get orientation for billboard particles
Matrix44 mat;
mat.SetIdentity();
GetRenderer()->GetModelViewMatrix(mat.GetData());
Vec3d vRight,vUp,vFront;
//CELL_CHANGED_BY_IVO
//vRight(mat.cell(0), mat.cell(4), mat.cell(8));
//vUp (mat.cell(1), mat.cell(5), mat.cell(9));
//vFront(mat.cell(2), mat.cell(6), mat.cell(10));
vRight = GetNormalized(mat.GetColumn(0));
vUp = GetNormalized(mat.GetColumn(1));
vFront = GetNormalized(mat.GetColumn(2));
Vec3d vCamPos = GetViewCamera().GetPos();
CCamera * pCamera = &GetViewCamera();
CVars * pCVars = GetCVars();
PartProcessParams ProcParams;
ProcParams.fCurTime = pPartManager->GetParticlesTime();;
ProcParams.fFrameTime = pPartManager->GetParticlesFrameTime();
ProcParams.vRight=vRight;
ProcParams.vUp=vUp;
ProcParams.vFront=vFront;
ProcParams.pIRenderer=GetRenderer();
ProcParams.pObjManager=pObjManager;
ProcParams.pTerrain=pTerrain;
ProcParams.pPhysicalWorld=GetPhysicalWorld();
ProcParams.pCamera=pCamera;
ProcParams.pVertBufChunk=0;
ProcParams.pSystem = GetSystem();
ProcParams.p3DEngine = (C3DEngine*)m_p3DEngine;
ProcParams.pPartManager = pPartManager;
ProcParams.vCamPos = pCamera->GetPos();
for( int i=0; i<m_nCurSpritesCount && i<m_nMaxSpritesCount; i++)
{
bool bActive = true;
CSprite *pSprite = &m_arrSprites[i];
if(!nRecursionLevel)
{
bActive = pSprite->Update(ProcParams);
//Vec3 vsz = Vec3(pSprite->m_fSize,pSprite->m_fSize,pSprite->m_fSize);
//pSprite->m_pEmitter->m_bbox.Add( pSprite->m_vPos - vsz );
//pSprite->m_pEmitter->m_bbox.Add( pSprite->m_vPos + vsz );
}
if (!nRecursionLevel || (!(pSprite->m_nParticleFlags & PART_FLAG_HORIZONTAL)) )
{
bool bVisible = false;
if(pSprite->m_nParticleFlags & PART_FLAG_LINEPARTICLE)
{ // find bbox
Vec3d vBoxMin = pSprite->m_vPos;
Vec3d vBoxMax = pSprite->m_vPos;
vBoxMin.CheckMin(pSprite->m_vPos + pSprite->m_vDelta);
vBoxMax.CheckMax(pSprite->m_vPos + pSprite->m_vDelta);
vBoxMin -= Vec3d(pSprite->m_fSize,pSprite->m_fSize,pSprite->m_fSize);
vBoxMax += Vec3d(pSprite->m_fSize,pSprite->m_fSize,pSprite->m_fSize);
bVisible = pCamera->IsAABBVisibleFast( AABB(vBoxMin,vBoxMax) );
}
else
bVisible = pCamera->IsSphereVisibleFast( Sphere(pSprite->m_vPos,pSprite->m_fSize) );
if ( bVisible && (!(pSprite->m_nParticleFlags & PART_FLAG_SPACELIMIT) || bActive))
pSprite->Render( ProcParams,pPartLightShader );
}
if (!bActive)
{ // remove
pSprite->DeActivateParticle(GetPhysicalWorld());
if(i < m_nCurSpritesCount-1)
{
m_arrSprites[i] = m_arrSprites[m_nCurSpritesCount-1];
memset(&m_arrSprites[m_nCurSpritesCount-1],0,sizeof(m_arrSprites[m_nCurSpritesCount-1]));
}
m_nCurSpritesCount--;
i--;
}
}
}

284
Cry3DEngine/StatObj.h Normal file
View File

@@ -0,0 +1,284 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: statobj.h
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#ifndef STAT_OBJ_H
#define STAT_OBJ_H
const int FAR_TEX_COUNT = 24; // number of sprites per object
const int FAR_TEX_ANGLE = (360/FAR_TEX_COUNT);
const int FAR_TEX_SIZE = 64;
class CIndexedMesh;
class CCObject;
#include "../Cry3DEngine/Cry3DEngineBase.h"
#include "list2.h"
struct CStatObjSV;
struct ItShadowVolume;
#include "istatobj.h"
#include "istreamengine.h"
#define STATOBJ_EFT_PLANT (EFT_USER_FIRST+1)
#define STATOBJ_EFT_PLANT_IN_SHADOW (EFT_USER_FIRST+2)
#define CGF_STREAMING_MAX_TIME_PER_FRAME 0.01f
struct CStatObj : public Cry3DEngineBase, public IStreamCallback, public IStatObj
{
CStatObj();
~CStatObj();
CIndexedMesh * m_pTriData;
CIndexedMesh * GetTriData() { return m_pTriData; }
int m_nLoadedTrisCount;
const Vec3d GetCenter() { return m_vBoxCenter; }
inline float GetRadius() { return m_fObjectRadius; }
char m_szFolderName[256];
char m_szFileName [256];
char m_szGeomName [256];
bool m_bDefaultObject;
bool m_bOpenEdgesTested;
TArray<int> m_lstShaderTemplates;
TArray <SShaderParam> m_ShaderParams;
uint m_arrSpriteTexID[FAR_TEX_COUNT];
float m_fObjectRadius;
void CalcRadiuses();
public:
// Loader
bool Load(const char * szFileName, const char * szGeomName, enum EVertsSharing eVertsSharing,
bool bLoadAdditinalInfo, bool bKeepInLocalSpace, bool bUseStreaming = false,
bool bMakePhysics = true);
//! Returns script material name
virtual const char * GetScriptMaterialName(int Id=-1);
virtual void Render(const SRendParams & rParams, const Vec3& t, int nLodLevel=0);
//virtual void RenderModel(const RenderParams *pParams);
// renders the shadow volumes of this whole object (together with attachments if any)
// the implementation may or may not implement the limit lod functionality: if it does,
// it will render the specified or lower LOD
virtual void RenderShadowVolumes(const SRendParams *pParams,int nLimitLod = -1);
//! Refresh object ( reload shaders or/and object geometry )
virtual void Refresh(int nFlags);
virtual bool SetShaderTemplate(int nTemplate, const char *TemplName, const char *ShaderName, bool bOnlyRegister=false, int * pnNewTemplateId = NULL);
virtual void SetShaderFloat(const char *Name, float Val);
//virtual void SetRefractFactor(float fRefr) { m_fRefractFactor = fRefr; }
//! Sets color parameter
virtual void SetColor(const char *Name, float fR, float fG, float fB, float fA);
//! set shadow volume
ItShadowVolume *GetShadowVolume() { return (m_pSvObj);}
//! get shadow volume
void SetShadowVolume(ItShadowVolume *pSvObj) { m_pSvObj=pSvObj;}
protected:
void Physicalize();
void CreateModelFarImages(int nTexRes);
CLeafBuffer * m_pLeafBuffer;
ItShadowVolume *m_pSvObj;
int m_dwFlags,m_dwFlags2;
public:
CLeafBuffer * GetLeafBuffer() { return m_pLeafBuffer; };
void SetLeafBuffer( CLeafBuffer *buf ) { m_pLeafBuffer = buf; };
Vec3d m_vBoxMin, m_vBoxMax, m_vBoxCenter;
bool m_bPhysicsExistInCompiledFile;
Vec3d m_vPhysBoxMin[4], m_vPhysBoxMax[4];
list2<Vec3d> m_lstProxyVerts[4];
list2<int> m_lstProxyInds[4];
list2<unsigned char> m_lstProxyFaceMaterials[4];
#define MAX_PHYS_GEOMS_IN_CGF 4
phys_geometry * m_arrPhysGeomInfo[MAX_PHYS_GEOMS_IN_CGF];
phys_geometry * GetPhysGeom(int n = 0) { return m_arrPhysGeomInfo[n]; }
const char *GetFolderName() { return (m_szFolderName); }
const char *GetFileName() { return (m_szFileName); }
const char *GetGeoName() { return (m_szGeomName); }
bool IsSameObject(const char * szFileName, const char * szGeomName);
//set object's min/max bbox
void SetBBoxMin(const Vec3d &vBBoxMin) { m_vBoxMin=vBBoxMin; }
void SetBBoxMax(const Vec3d &vBBoxMax) { m_vBoxMax=vBBoxMax; }
Vec3d GetBoxMin() { return m_vBoxMin; }
Vec3d GetBoxMax() { return m_vBoxMax; }
void GetBBox(Vec3d& Mins, Vec3d& Maxs)
{
Mins = m_vBoxMin;
Maxs = m_vBoxMax;
}
int m_nUsers; // reference counter
ShadowMapLightSource * m_pSMLSource;
void MakeShadowMaps(const Vec3d vSunPos);
protected:
void MakeLeafBuffer(bool bSortAndShareVerts);
void PrepareShadowMaps(const Vec3d & obj_pos, ShadowMapLightSource * pLSource);
public:
int GetAllocatedBytes();
void SetCurDynMask(int nCurDynMask);
int FindInPosBuffer(const Vec3d & opt, Vec3d * _vbuff, int _vcount, list2<int> * pHash);
void CompactPosBuffer(Vec3d * _vbuff, int * _vcount, list2<int> * pindices);
virtual Vec3d GetHelperPos(const char * szHelperName);
virtual const char *GetHelperById(int nId, Vec3d & vPos, Matrix44 * pMat, int * pnType);
virtual const Matrix44 * GetHelperMatrixByName(const char * szHelperName);
virtual void UpdateCustomLightingSpritesAndShadowMaps(Vec3d vStatObjAmbientColor, int nTexRes, float fBackSideLevel, bool bCalcLighting);
float m_fRadiusHors;
float m_fRadiusVert;
float & GetRadiusVert() { return m_fRadiusVert; }
float & GetRadiusHors() { return m_fRadiusHors; }
virtual void RegisterUser();
virtual void UnregisterUser();
virtual bool IsDefaultObject() { return (m_bDefaultObject); }
virtual bool MakeObjectPicture(unsigned char * pRGBAData, int nWidth);
#define MAX_STATOBJ_LODS_NUM 3
CStatObj * m_arrpLowLODs[MAX_STATOBJ_LODS_NUM];
void LoadLowLODs(EVertsSharing eVertsSharing, bool bLoadAdditinalInfo, bool bKeepInLocalSpace, bool bLoadLater);
int m_nLoadedLodsNum;
bool IsSpritesCreated() { return m_arrSpriteTexID[0]>0; }
float GetDistFromPoint(const Vec3d & vPoint);
int GetLoadedTrisCount() { return m_nLoadedTrisCount; }
int GetRenderTrisCount();
list2<Vec3d> m_lstOcclVolVerts;
list2<int> m_lstOcclVolInds;
virtual bool GetOcclusionVolume(list2<Vec3d> * & plstOcclVolVerts, list2<int> * & plstOcclVolInds)
{
plstOcclVolVerts = &m_lstOcclVolVerts;
plstOcclVolInds = &m_lstOcclVolInds;
return m_lstOcclVolInds.Count() >= 3;
}
list2<struct StatHelperInfo> m_lstHelpers;
list2<CDLight> m_lstLSources;
bool Serialize(int & nPos, uchar * pSerBuf, bool bSave, char * szFolderName);
virtual void FreeTriData();
virtual const CDLight * GetLightSources(int nId);
void RenderDebugInfo(const SRendParams & rParams, const class CCObject * pObj);
void DrawMatrix(const Matrix44 & pMat);
//! Release method.
void Release() { delete this; }
void GetMemoryUsage(class ICrySizer* pSizer);
int GetMemoryUsage();
void SpawnParticles( ParticleParams & SpawnParticleParams, const Matrix44 & matWorldSpace, bool bOnlyUpLookingFaces );
// connectivity object that gets pre-computed for each model once and then
// used to extract edge topology by the stencil shadowing module
class IStencilShadowConnectivity* m_pStencilShadowConnectivity;
// returns the cached connectivity object for stencil shadows
class IStencilShadowConnectivity* getStencilShadowConnectivity( );
//////////////////////////////////////////////////////////////////////////
// builds the connectivity object for stencil shadows
// PARAMETERS:
// iEdgeBuilder - the builder to use to create the connectivity info
// pbCastShadow - the array of flags, 1 flag per 1 material, if the flag is true, then this material casts shadow, otherwise not
// numMaterials - number of items in the pbCastShadow array
void ShutDown();
void Init();
void PhysicalizeCompiled();
bool CompileInNeeded();
// loading state
EVertsSharing m_eVertsSharing;
bool m_bLoadAdditinalInfo;
bool m_bKeepInLocalSpace;
int m_nLastRendFrameId;
int m_nMarkedForStreamingFrameId;
bool m_bUseStreaming;
bool m_bMakePhysics;
static float m_fStreamingTimePerFrame;
int m_nSpriteTexRes;
float m_fBackSideLevel;
bool m_bCalcLighting;
static ItShadowVolume * MakeConnectivityInfo(CIndexedMesh * pMesh, const Vec3d & vOrigin, CStatObj * pStatObj);
ItShadowVolume * MakeConnectivityInfoFromCompiledData(void * pStream, int & nPos, CStatObj * pStatObj);
bool CheckValidVegetation();
bool EnableLightamapSupport();
void CheckLoaded();
IStatObj * GetLodObject(int nLodLevel);
void StreamOnProgress (IReadStream* pStream);
void StreamOnComplete (IReadStream* pStream, unsigned nError);
void StreamCCGF(bool bFinishNow);
enum ECCGFStreamingStatus
{
ecss_NotLoaded,
ecss_LoadingInProgress,
ecss_Ready,
ecss_LoadingError,
ecss_GeomNotFound,
} m_eCCGFStreamingStatus;
IReadStreamPtr m_pReadStream;
bool LoadUncompiled(const char * szFileName,
const char * szGeomName,
EVertsSharing eVertsSharing,
bool bLoadAdditinalInfo,
bool bKeepInLocalSpace,
bool bLoadLater,
bool bMakePhysics);
void MakeCompiledFileName(char * szCompiledFileName, int nMaxLen);
int m_bCompilingNotAllowed;
void ProcessStreamOnCompleteError();
bool IsPhysicsExist();
void PreloadResources(float fDist, float fTime, int dwFlags);
void InitCompiledLightSource(CDLight * pDLight);
void SetupBending(CCObject * pObj, float fBending);
bool IsSphereOverlap(const Sphere& sSphere);
};
#endif // STAT_OBJ_H

View File

@@ -0,0 +1,166 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: statobjconstr.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: loading
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "StatObj.h"
#include "MeshIdx.h"
#include "irenderer.h"
#ifdef WIN64
#pragma warning( push ) //AMD Port
#pragma warning( disable : 4267 )
#endif
bool CStatObj::CompileInNeeded()
{
if(!GetCVars()->e_ccgf_make_if_not_found)
return true;
#ifdef WIN32
char szCompiledFileName[MAX_PATH_LENGTH];
MakeCompiledFileName(szCompiledFileName,MAX_PATH_LENGTH);
CCGFHeader fileHeader;
// read header from compiled first
FILE * f = GetSystem()->GetIPak()->FOpen(szCompiledFileName, "rb");
if(f)
{
int nReaded = GetSystem()->GetIPak()->FRead(&fileHeader, 1, sizeof(fileHeader), f);
assert(nReaded == sizeof(CCGFHeader));
GetSystem()->GetIPak()->FClose(f);
}
// get date of source file
FILE* fTmp = GetSystem()->GetIPak()->FOpen(m_szFileName, "rb");
if (!fTmp)
return false;
FILETIME ftSourceFileTime = GetSystem()->GetIPak()->GetModificationTime(fTmp);
GetSystem()->GetIPak()->FClose(fTmp);
if(ftSourceFileTime.dwHighDateTime == 0 && ftSourceFileTime.dwLowDateTime == 0)
return false; // source file not found
#ifdef _DEBUG
HANDLE _dbg_h = CreateFile (m_szFileName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
FILETIME _dbg_ft = {0,0};
if (_dbg_h != INVALID_HANDLE_VALUE)
GetFileTime (_dbg_h, &_dbg_ft, NULL, &_dbg_ft);
SYSTEMTIME _dbg_st1, _dbg_st2;
FileTimeToSystemTime(&fileHeader.SourceFileTime, &_dbg_st1);
FileTimeToSystemTime(&ftSourceFileTime, &_dbg_st2);
#endif
// compare date of source file and date of source file used to build this ccgf
if(!CompareFileTime(&fileHeader.SourceFileTime, &ftSourceFileTime))
if(!strcmp(fileHeader.szVersion,CCGF_FILE_VERSION))
if(fileHeader.nStructuresCheckSummm == CCGFHeader::GetStructuresCheckSummm())
{
if(!fileHeader.nDataSize)
{
assert(m_szGeomName[0]);
return false; // geom name was specified but not found in source sgf during compilation (valid state)
}
return true; // no recompilation required
}
// make command for execution
char szRemoteCmdLine[512];
snprintf(szRemoteCmdLine, sizeof(szRemoteCmdLine),
RC_EXECUTABLE " \"%s\" /GeomName=%s /Stripify=%d /LoadAdditinalInfo=%d /KeepInLocalSpace=%d /StaticCGF=1 /refresh",
m_szFileName, m_szGeomName,
int(m_eVertsSharing==evs_ShareAndSortForCache), int(m_bLoadAdditinalInfo), int(m_bKeepInLocalSpace)
);
STARTUPINFO si;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
si.dwX = 100;
si.dwY = 100;
si.dwFlags = STARTF_USEPOSITION;
PROCESS_INFORMATION pi;
ZeroMemory( &pi, sizeof(pi) );
// Start the child process.
GetLog()->UpdateLoadingScreen("Executing " RC_EXECUTABLE " for %s", m_szFileName);
GetLog()->Log("\004Command line: %s", szRemoteCmdLine);
if( !CreateProcess( NULL, // No module name (use command line).
szRemoteCmdLine, // Command line.
NULL, // Process handle not inheritable.
NULL, // Thread handle not inheritable.
FALSE, // Set handle inheritance to FALSE.
GetCVars()->e_ccgf_make_if_not_found == 2 ? 0 : CREATE_NO_WINDOW, // No creation flags.
NULL, // Use parent's environment block.
NULL/*szFolderName*/, // Set starting directory.
&si, // Pointer to STARTUPINFO structure.
&pi ) // Pointer to PROCESS_INFORMATION structure.
)
{
GetSystem()->Error( "CreateProcess failed: %s", szRemoteCmdLine);
}
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
// check compiled file
f = GetSystem()->GetIPak()->FOpen(szCompiledFileName, "rb");
if(f)
{
int nReaded = GetSystem()->GetIPak()->FRead(&fileHeader, 1, sizeof(fileHeader), f);
GetSystem()->GetIPak()->FClose(f);
if(nReaded == sizeof(CCGFHeader))
{
if( ftSourceFileTime.dwHighDateTime == fileHeader.SourceFileTime.dwHighDateTime &&
ftSourceFileTime.dwLowDateTime == fileHeader.SourceFileTime.dwLowDateTime)
{
if(strcmp(fileHeader.szVersion,CCGF_FILE_VERSION))
GetSystem()->Error(" " RC_EXECUTABLE " version error\n"
"File produced by resource compiler has wrong version [%s]\n"
"Must be [%s]\n"
"File name is %s",
fileHeader.szVersion, CCGF_FILE_VERSION, szCompiledFileName);
return true;
}
else
{
GetSystem()->Error(" " RC_EXECUTABLE " execution error\n"
"File produced by resource compiler has time stamp different from source file time\n"
"File name is %s", szCompiledFileName);
}
}
}
else
GetSystem()->Error(" " RC_EXECUTABLE " execution error\n"
"Resource compiler was not able to produce CCGF file\n"
"File name is %s", szCompiledFileName);
return false;
#endif // WIN32
}
#ifdef WIN64
#pragma warning( pop ) //AMD Port
#endif

View File

@@ -0,0 +1,620 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: statobjconstr.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: creation
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "StatObj.h"
#include "MeshIdx.h"
#include "../RenderDll/Common/shadow_renderer.h"
#include <irenderer.h>
#include <CrySizer.h>
#include "objman.h"
float CStatObj::m_fStreamingTimePerFrame=0;
void CStatObj::FreeTriData()
{
delete m_pTriData;
m_pTriData=0;
}
const char * CStatObj::GetScriptMaterialName(int Id)
{
CLeafBuffer *lb = m_pLeafBuffer;
if (Id < 0)
{
for (int i=0; i<lb->m_pMats->Count(); i++)
{
if ((*lb->m_pMats)[i].sScriptMaterial[0])
return (*lb->m_pMats)[i].sScriptMaterial;
}
return NULL;
}
else
if (Id < lb->m_pMats->Count() && (*lb->m_pMats)[Id].sScriptMaterial[0])
return (*lb->m_pMats)[Id].sScriptMaterial;
return NULL;
}
void CStatObj::CalcRadiuses()
{
m_vBoxCenter = (m_vBoxMax+m_vBoxMin)*0.5f;
m_fObjectRadius = GetDistance(m_vBoxMin, m_vBoxMax)*0.5f;
float dxh = (float)max( fabs(GetBoxMax().x), fabs(GetBoxMin().x));
float dyh = (float)max( fabs(GetBoxMax().y), fabs(GetBoxMin().y));
m_fRadiusHors = (float)cry_sqrtf(dxh*dxh+dyh*dyh);
m_fRadiusVert = (GetBoxMax().z - GetBoxMin().z)*0.5f;// never change this
}
CStatObj::CStatObj( )
{
m_nUsers = 0; // referense counter
m_bOpenEdgesTested = false;
m_eVertsSharing=evs_NoSharing;
m_bLoadAdditinalInfo=false;
m_bKeepInLocalSpace=false;
m_bUseStreaming=false;
m_bMakePhysics=false;
m_nSpriteTexRes=0;
ZeroStruct( m_szFolderName );
ZeroStruct( m_szFileName );
ZeroStruct( m_szGeomName );
m_pStencilShadowConnectivity=0;
m_nLastRendFrameId = 0;
m_nMarkedForStreamingFrameId = 0;
m_fBackSideLevel = 1.f;
m_bCalcLighting = false;
memset(m_arrpLowLODs,0,sizeof(m_arrpLowLODs));
m_nLoadedLodsNum=1;
m_bPhysicsExistInCompiledFile=false;
Init();
}
void CStatObj::Init()
{
m_pTriData = 0;
m_nLoadedTrisCount = 0;
m_fObjectRadius = 0;
m_fRadiusHors = 0;
m_fRadiusVert = 0;
m_pSvObj=NULL;
m_dwFlags=m_dwFlags2=0;
ZeroStruct( m_arrSpriteTexID );
m_vBoxMin.Set(0,0,0);
m_vBoxMax.Set(0,0,0);
m_vBoxCenter.Set(0,0,0);
memset(m_arrPhysGeomInfo, 0, sizeof(m_arrPhysGeomInfo));
m_pSMLSource = 0;
m_pLeafBuffer = 0;
m_bDefaultObject=false;
for(int i=0; i<MAX_STATOBJ_LODS_NUM; i++)
if(m_arrpLowLODs[i])
m_arrpLowLODs[i]->Init();
m_eCCGFStreamingStatus = ecss_NotLoaded;
m_pReadStream=0;
m_bCompilingNotAllowed=0;
}
CStatObj::~CStatObj()
{
ShutDown();
for(int i=0; i<MAX_STATOBJ_LODS_NUM; i++)
if(m_arrpLowLODs[i])
delete m_arrpLowLODs[i];
}
void CStatObj::ShutDown()
{
// assert (IsHeapValid());
m_pReadStream=0;
if(m_pTriData)
m_pTriData->FreeLMInfo();
// assert (IsHeapValid());
delete m_pTriData;
m_pTriData = 0;
// assert (IsHeapValid());
for(int n=0; n<2; n++)
if(m_arrPhysGeomInfo[n])
GetPhysicalWorld()->GetGeomManager()->UnregisterGeometry(m_arrPhysGeomInfo[n]);
// assert (IsHeapValid());
if(m_pSMLSource && m_pSMLSource->m_LightFrustums.Count() && m_pSMLSource->m_LightFrustums[0].pModelsList)
delete m_pSMLSource->m_LightFrustums[0].pModelsList;
delete m_pSMLSource;
// assert (IsHeapValid());
if(m_pLeafBuffer && !m_pLeafBuffer->m_bMaterialsWasCreatedInRenderer)
{
for (int i=0; i<(*m_pLeafBuffer->m_pMats).Count(); i++)
{
CMatInfo *mi = m_pLeafBuffer->m_pMats->Get(i);
if(mi->pRE)
mi->pRE->Release();
if (mi->shaderItem.m_pShader)
mi->shaderItem.m_pShader->Release();
if (mi->shaderItem.m_pShaderResources)
mi->shaderItem.m_pShaderResources->Release();
}
delete m_pLeafBuffer->m_pMats;
m_pLeafBuffer->m_pMats=0;
}
// assert (IsHeapValid());
GetRenderer()->DeleteLeafBuffer(m_pLeafBuffer);
m_pLeafBuffer=0;
// assert (IsHeapValid());
for(int i=0; i<FAR_TEX_COUNT; i++)
if(m_arrSpriteTexID[i])
GetRenderer()->RemoveTexture(m_arrSpriteTexID[i]);
if (m_pSvObj)
{
// assert (IsHeapValid());
m_pSvObj->Release();
m_pSvObj=NULL;
}
for(int i=0; i<MAX_STATOBJ_LODS_NUM; i++)
{
if(m_arrpLowLODs[i])
m_arrpLowLODs[i]->ShutDown();
}
m_ShaderParams.Free();
// free light source smart pointers
for(int i=0; i<m_lstLSources.Count(); i++)
{
m_lstLSources[i].m_pLightImage = NULL;
m_lstLSources[i].m_pShader = NULL;
}
}
/*
void CStatObj::BuildOcTree()
{
if(!m_pTriData->m_nFaceCount || m_pTriData->m_nFaceCount<=2)
return;
CBox parent_box( m_pTriData->m_vBoxMin, m_pTriData->m_vBoxMax );
parent_box.max += 0.01f;
parent_box.min +=-0.01f;
CObjFace ** allFaces = new CObjFace *[m_pTriData->m_nFaceCount];
for(int f=0; f<m_pTriData->m_nFaceCount; f++)
{
m_pTriData->m_pFaces[f].m_vCenter =
(Vec3d(&m_pTriData->m_pVerts[m_pTriData->m_pFaces[f].v[0]].x) +
Vec3d(&m_pTriData->m_pVerts[m_pTriData->m_pFaces[f].v[1]].x) +
Vec3d(&m_pTriData->m_pVerts[m_pTriData->m_pFaces[f].v[2]].x))/3.f;
allFaces[f] = &m_pTriData->m_pFaces[f];
}
const int max_tris_in_leaf = 2000;
const float leaf_min_size = stricmp(m_szGeomName,"sector_0") ? 16.f : 32.f;
text_to_log(" Generating octree ... ");
m_pOcTree = new octree_node( &parent_box, allFaces, triData->m_nFaceCount, triData, leaf_min_size, max_tris_in_leaf, 2);
text_to_log_plus("%d leafs created", octree_node::static_current_leaf_id);
m_pOcTree->update_bbox(triData);
delete [] allFaces;
}*/
//float M akeBuffersTime = 0;
void CStatObj::MakeLeafBuffer(bool bSortAndShareVerts)
{
if(GetSystem()->IsDedicated())
return;
assert(!m_pLeafBuffer);
m_pLeafBuffer = GetRenderer()->CreateLeafBuffer(eBT_Static,"StatObj");
m_pLeafBuffer->m_pMats = new list2<CMatInfo>;
m_pLeafBuffer->m_pMats->AddList(m_pTriData->m_lstMatTable);
if(bSortAndShareVerts)
bSortAndShareVerts=bSortAndShareVerts;
if(m_pTriData->m_nFaceCount)
m_pLeafBuffer->CreateBuffer(m_pTriData, bSortAndShareVerts, true, //false,);
m_pTriData->m_lstGeomNames.Count()>0 && strstr(m_pTriData->m_lstGeomNames[0],"cloth")!=0);
// remove materials without geometry
if(m_bIgnoreFakeMaterialsInCGF)
if(m_pLeafBuffer && !m_pLeafBuffer->m_bMaterialsWasCreatedInRenderer)
{
for (int i=0; i<(*m_pLeafBuffer->m_pMats).Count(); i++)
{
CMatInfo *mi = m_pLeafBuffer->m_pMats->Get(i);
if(!mi->pRE || !mi->nNumIndices || !mi->nNumVerts)
{
if (mi->shaderItem.m_pShader)
mi->shaderItem.m_pShader->Release();
if (mi->shaderItem.m_pShaderResources)
mi->shaderItem.m_pShaderResources->Release();
m_pLeafBuffer->m_pMats->Delete(i);
if(i<m_lstShaderTemplates.Num())
m_lstShaderTemplates.DelElem(i);
i--;
}
else
mi->pRE->m_pChunk = mi;
}
}
int nDeleted = m_pTriData->m_lstMatTable.Count() - m_pLeafBuffer->m_pMats->Count();
if(nDeleted)
CryLogComment(" %d not used material slots removed", nDeleted);
}
//////////////////////////////////////////////////////////////////////////
int CStatObj::GetAllocatedBytes()
{
int size = sizeof(*this) + m_pTriData ? m_pTriData->GetAllocatedBytes() : 0;
// for(int i=0; i<MAX_TREE_LEAFS_NUM; i++)
{
size += m_pLeafBuffer->GetAllocatedBytes(false);
}
return size;
}
///////////////////////////////////////////////////////////////////////////////////////
Vec3d CStatObj::GetHelperPos(const char * szHelperName)
{
for(int i=0; i<m_lstHelpers.Count(); i++)
if(!strcmp(m_lstHelpers[i].sName,szHelperName))
return m_lstHelpers[i].tMat.GetTranslationOLD();
return Vec3d(0,0,0);
}
///////////////////////////////////////////////////////////////////////////////////////
const Matrix44 * CStatObj::GetHelperMatrixByName(const char * szHelperName)
{
for(int i=0; i<m_lstHelpers.Count(); i++)
if(!strcmp(m_lstHelpers[i].sName,szHelperName))
return &(m_lstHelpers[i].tMat);
return 0;
}
///////////////////////////////////////////////////////////////////////////////////////
const char *CStatObj::GetHelperById(int nId, Vec3d & vPos, Matrix44* pMat, int * pnType)
{
if ( nId >= m_lstHelpers.Count() || nId<0 )
return (NULL);
vPos = m_lstHelpers[nId].tMat.GetTranslationOLD();
if(pnType)
*pnType = m_lstHelpers[nId].nType;
if(pMat)
*pMat = m_lstHelpers[nId].tMat;
return (m_lstHelpers[nId].sName);
}
/*
bool CStatObj::GetHelper(int id, char * szHelperName, int nMaxHelperNameSize, Vec3d * pPos, Vec3d * pRot)
{
if(id<0 || id>=triData->m_Helpers.Count())
return false;
strncpy(szHelperName, triData->m_Helpers[id].name, nMaxHelperNameSize);
*pPos = triData->m_Helpers[id].pos;
*pRot = triData->m_Helpers[id].rot;
return true;
} */
void CStatObj::UpdateCustomLightingSpritesAndShadowMaps(Vec3d vStatObjAmbientColor, int nTexRes, float fBackSideLevel, bool bCalcLighting)
{
AUTO_PROFILE_SECTION(GetTimer(), CObjManager::m_dUpdateCustomLightingSpritesAndShadowMaps);
m_nSpriteTexRes = nTexRes;
m_fBackSideLevel = fBackSideLevel;
m_bCalcLighting = bCalcLighting;
Vec3d vLight = GetSystem()->GetI3DEngine()->GetSunPosition();
vLight.Normalize();
// Vec3d vColor = GetSystem()->GetI3DEngine()->GetWorldColor();
float fSize = m_vBoxMax.z - m_vBoxMin.z;
// update lighting for full lod and lower lods
if(m_pLeafBuffer)
m_pLeafBuffer->UpdateCustomLighting( m_fBackSideLevel, vStatObjAmbientColor, vLight, bCalcLighting );
int nLowestLod=0;
for(int nLodLevel=1; nLodLevel<MAX_STATOBJ_LODS_NUM; nLodLevel++)
if(m_arrpLowLODs[nLodLevel])
{
if(m_arrpLowLODs[nLodLevel]->GetLeafBuffer())
{
m_arrpLowLODs[nLodLevel]->GetLeafBuffer()->UpdateCustomLighting( m_fBackSideLevel, vStatObjAmbientColor, vLight, bCalcLighting );
nLowestLod = nLodLevel;
}
}
// make sprites
if(nLowestLod)
{
// clear sprites in full lod
for(int i=0; i<FAR_TEX_COUNT; i++)
if(m_arrSpriteTexID[i])
{
GetRenderer()->RemoveTexture(m_arrSpriteTexID[i]);
m_arrSpriteTexID[i]=0;
}
// make new sprites in low lod
m_arrpLowLODs[nLowestLod]->CreateModelFarImages(nTexRes); // use lowest lod if present
// move sprite id from low inro into full lod
memcpy(m_arrSpriteTexID, m_arrpLowLODs[nLowestLod]->m_arrSpriteTexID, sizeof(m_arrSpriteTexID));
memset(m_arrpLowLODs[nLowestLod]->m_arrSpriteTexID, 0, sizeof(m_arrpLowLODs[nLowestLod]->m_arrSpriteTexID));
m_nSpriteTexRes = m_arrpLowLODs[nLowestLod]->m_nSpriteTexRes;
}
else
CreateModelFarImages(nTexRes);
MakeShadowMaps(vLight);
// if(m_pTriData && !m_pTriData->m_lstLSources.Count())
// FreeTriData();
}
/*
const char * CStatObj::GetPhysMaterialName(int nMatID)
{
if(m_pLeafBuffer && m_pLeafBuffer->m_pMats && nMatID < m_pLeafBuffer->m_pMats->Count())
return m_pLeafBuffer->m_pMats->Get(nMatID)->szPhysMat;
return 0;
}
bool CStatObj::SetPhysMaterialName(int nMatID, const char * szPhysMatName)
{
if(m_pLeafBuffer && m_pLeafBuffer->m_pMats && nMatID < m_pLeafBuffer->m_pMats->Count())
{
strncpy(m_pLeafBuffer->m_pMats->Get(nMatID)->szPhysMat, szPhysMatName, sizeof(m_pLeafBuffer->m_pMats->Get(nMatID)->szPhysMat));
return true;
}
return false;
}
*/
void CStatObj::RegisterUser()
{
m_nUsers++;
}
void CStatObj::UnregisterUser()
{
m_nUsers--;
}
float CStatObj::GetDistFromPoint(const Vec3d & vPoint)
{
float fMinDist = 4096;
for(int v=0; v<m_pTriData->m_nVertCount; v++)
{
float fDist = GetDistance(m_pTriData->m_pVerts[v],vPoint);
if(fDist < fMinDist)
fMinDist = fDist;
}
return fMinDist;
}
bool CStatObj::IsSameObject(const char * szFileName, const char * szGeomName)
{
// cmp object names
if (szGeomName)
{
// [Anton] - always use new cgf for objects used for cloth simulation
if (*szGeomName && stricmp(szGeomName,"cloth") == 0)
return false;
if(stricmp(szGeomName,m_szGeomName)!=0)
return false;
}
// Normilize file name
char szFileNameNorm[MAX_PATH_LENGTH]="";
char *pszDest = szFileNameNorm;
const char *pszSource = szFileName;
while (*pszSource)
{
if (*pszSource=='/')
*pszDest++='\\';
else
*pszDest++=*pszSource;
pszSource++;
}
*pszDest=0;
// cmp file names
if(stricmp(szFileNameNorm,m_szFileName)!=0)
return false;
return true;
}
void CStatObj::GetMemoryUsage(ICrySizer* pSizer)
{
pSizer->AddObject(this,GetMemoryUsage());
}
#ifdef WIN64
#pragma warning( push ) //AMD Port
#pragma warning( disable : 4267 )
#endif
int CStatObj::GetMemoryUsage()
{
int nSize=0;
for(int i=0; i<MAX_STATOBJ_LODS_NUM; i++)
if(m_arrpLowLODs[i])
nSize += m_arrpLowLODs[i]->GetMemoryUsage();
nSize += m_lstHelpers.GetMemoryUsage();
nSize += m_lstLSources.GetMemoryUsage();
nSize += m_lstOcclVolInds.GetMemoryUsage();
nSize += m_lstOcclVolVerts.GetMemoryUsage();
nSize += m_lstShaderTemplates.GetMemoryUsage();
nSize += m_pSMLSource ? sizeof(*m_pSMLSource) : 0;
nSize += m_pSvObj ? m_pSvObj->GetMemoryUsage() : 0;
nSize += m_pTriData ? m_pTriData->GetMemoryUsage() : 0;
nSize += m_ShaderParams.GetMemoryUsage() + m_ShaderParams.Num()*sizeof(SShaderParam);
return nSize;
}
#ifdef WIN64
#pragma warning( pop ) //AMD Port
#endif
bool CStatObj::CheckValidVegetation()
{
if(m_pLeafBuffer && m_pLeafBuffer->m_pMats)
for(int i=0; i<m_pLeafBuffer->m_pMats->Count(); i++)
{
CMatInfo * pMatInfo = m_pLeafBuffer->m_pMats->Get(i);
IShader * pShader = pMatInfo->shaderItem.m_pShader;
if(!pShader || !pMatInfo->nNumIndices)
continue;
pShader = pShader->GetTemplate(0);
const char * pTemplateName = pShader->GetName();
char buff[64];
strncpy(buff, pTemplateName, sizeof(buff)); buff[sizeof(buff)-1]=0;
strlwr(buff);
if( !strstr(buff,"templplants") &&
!strstr(buff,"nodraw") &&
!strstr(buff,"templdecal_vcolors") &&
!strstr(buff,"templdecalalphatest_vcolors"))
{
#if !defined(LINUX)//don't worry, we won't render anything under linux
Warning( 0,m_szFileName,"CStatObj::CheckValidVegetation: Shader template is undefined or can not be used for vegetations: %s [%s]",
pTemplateName, m_szFileName);
// return false;
#endif
}
}
return true;
}
bool CStatObj::EnableLightamapSupport()
{
assert(m_eVertsSharing == evs_NoSharing);
if(m_eVertsSharing == evs_NoSharing)
return true;
/*
GetLog()->Log("Activating lightamap support for %s", m_szFileName);
m_eVertsSharing = evs_NoSharing;
Refresh(FRO_GEOMETRY);
*/
return false;//!m_bDefaultObject;
}
IStatObj * CStatObj::GetLodObject(int nLodLevel)
{
if(nLodLevel<1)
return this;
if(nLodLevel<3)
return (IStatObj *)m_arrpLowLODs[nLodLevel];
return 0;
}
bool CStatObj::IsPhysicsExist()
{
return m_bPhysicsExistInCompiledFile || GetPhysGeom(0) || GetPhysGeom(1) || GetPhysGeom(2);
}
int CStatObj::GetRenderTrisCount()
{
int nCount=0;
if(GetLeafBuffer())
GetLeafBuffer()->GetIndices(&nCount);
return nCount/3;
}
bool CStatObj::IsSphereOverlap(const Sphere& sSphere)
{
if(m_pLeafBuffer && Overlap::Sphere_AABB(sSphere,AABB(m_vBoxMin,m_vBoxMax)))
{ // if inside bbox
int nInds = 0, nPosStride=0;
ushort *pInds = m_pLeafBuffer->GetIndices(&nInds);
const byte * pPos = m_pLeafBuffer->GetPosPtr(nPosStride,0,true);
if(pInds && pPos)
for(int i=0; (i+2)<nInds; i+=3)
{ // test all triangles of water surface strip
Vec3d v0 = *(Vec3d*)&pPos[nPosStride*pInds[i+0]];
Vec3d v1 = *(Vec3d*)&pPos[nPosStride*pInds[i+1]];
Vec3d v2 = *(Vec3d*)&pPos[nPosStride*pInds[i+2]];
Vec3d vBoxMin = v0; vBoxMin.CheckMin(v1); vBoxMin.CheckMin(v2);
Vec3d vBoxMax = v0; vBoxMax.CheckMax(v1); vBoxMax.CheckMax(v2);
if( Overlap::Sphere_AABB(sSphere,AABB(vBoxMin,vBoxMax)))
return true;
}
}
return false;
}

View File

@@ -0,0 +1,48 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: statobjfar.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: making sprites for object
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "StatObj.h"
void CStatObj::CreateModelFarImages(int nTexRes)
{
if(!nTexRes)
nTexRes = FAR_TEX_SIZE;
nTexRes /= (1<<GetCVars()->e_vegetation_sprites_texres);
for(int i=0; i<FAR_TEX_COUNT; i++)
{
GetRenderer()->ResetToDefault();
if(m_arrSpriteTexID[i])
{
GetRenderer()->RemoveTexture(m_arrSpriteTexID[i]);
m_arrSpriteTexID[i]=0;
}
m_arrSpriteTexID[i] = GetRenderer()->MakeSprite(18.f, nTexRes,
i*FAR_TEX_ANGLE+90.f, this, 0, m_arrSpriteTexID[i]);
}
GetRenderer()->ResetToDefault();
}
bool CStatObj::MakeObjectPicture(unsigned char * pRGBAData, int nWidth)
{
int nTid = GetRenderer()->MakeSprite(m_vBoxMax.z, nWidth,45,this,pRGBAData,0);
return nTid>0;
}

269
Cry3DEngine/StatObjLoad.cpp Normal file
View File

@@ -0,0 +1,269 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: statobjconstr.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: loading
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "StatObj.h"
#include "MeshIdx.h"
void CStatObj::Refresh(int nFlags)
{
if(nFlags & FRO_GEOMETRY)
{
bool bSpritesWasCreated = IsSpritesCreated();
ShutDown();
Init();
bool bRes = Load(m_szFileName, m_szGeomName[0] ? m_szGeomName : 0, m_eVertsSharing,
m_bLoadAdditinalInfo, m_bKeepInLocalSpace, false);
LoadLowLODs(m_eVertsSharing, m_bLoadAdditinalInfo, m_bKeepInLocalSpace, false);
if(bRes && bSpritesWasCreated)
{
Vec3d vColor = Get3DEngine()->GetAmbientColorFromPosition(Vec3d(-1000,-1000,-1000));
UpdateCustomLightingSpritesAndShadowMaps( vColor, m_nSpriteTexRes, m_fBackSideLevel, m_bCalcLighting );
}
if(!bRes)
{ // load default in case of error
ShutDown();
Init();
Load("Objects\\default.cgf", 0, m_eVertsSharing, m_bLoadAdditinalInfo, m_bKeepInLocalSpace);
m_bDefaultObject = true;
}
return;
}
if (nFlags & (FRO_TEXTURES | FRO_SHADERS))
{
CLeafBuffer *lb = m_pLeafBuffer;
for (int i=0; i<lb->m_pMats->Count(); i++)
{
IShader *e = (*lb->m_pMats)[i].shaderItem.m_pShader;
if (e && (*lb->m_pMats)[i].pRE && (*lb->m_pMats)[i].nNumIndices)
e->Reload(nFlags);
}
}
}
bool CStatObj::Load(const char * szFileName, const char * szGeomName,
EVertsSharing eVertsSharing,
bool bLoadAdditinalInfo,
bool bKeepInLocalSpace,
bool bUseStreaming,
bool bMakePhysics)
{
// Tick progress bar if we are now loading a level.
GetConsole()->TickProgressBar();
if(!szFileName[0])
GetSystem()->Error("CStatObj::Load: szFileName not specified");
if(!GetCVars()->e_ccgf_load)
return LoadUncompiled(szFileName, szGeomName, eVertsSharing, bLoadAdditinalInfo, bKeepInLocalSpace, false, bMakePhysics);
// remember file loading parameters
m_eVertsSharing = eVertsSharing;
m_bLoadAdditinalInfo = bLoadAdditinalInfo;
m_bKeepInLocalSpace = bKeepInLocalSpace;
m_bMakePhysics = bMakePhysics;
// remember names
strcpy(m_szFileName,szFileName);
strcpy(m_szGeomName, szGeomName && szGeomName[0] ? szGeomName : "");
strcpy(m_szFolderName,szFileName);
while(m_szFolderName[0])
{ // make folder name
if(m_szFolderName[strlen(m_szFolderName)-1] == '\\' || m_szFolderName[strlen(m_szFolderName)-1] == '/')
{ m_szFolderName[strlen(m_szFolderName)-1]=0; break; }
m_szFolderName[strlen(m_szFolderName)-1]=0;
}
// Create compiled file if needed
// This checks will slowdown loading but allows to avoid complex processing of errors during streaming
if(!CompileInNeeded())
return false; // unable to build file
// do not stream subobjects
if(bUseStreaming && !m_szGeomName[0])
{
Init();
// define fake bbox
m_vBoxMin = Vec3d(-1.f,-1.f,-1.f);
m_vBoxMax = Vec3d( 1.f, 1.f, 1.f);
m_vBoxCenter = Vec3d(0,0,0);
m_fRadiusHors = m_fRadiusVert = 1.f;
m_nLoadedTrisCount = 0;
m_bUseStreaming = true;
return true;
}
// load compiled file
StreamCCGF(true);
m_bUseStreaming = false;
return m_eCCGFStreamingStatus == ecss_Ready;
}
bool CStatObj::LoadUncompiled(const char * szFileName,
const char * szGeomName,
EVertsSharing eVertsSharing,
bool bLoadAdditinalInfo,
bool bKeepInLocalSpace,
bool bLoadLater,
bool bMakePhysics)
{
if(!szFileName[0])
GetSystem()->Error("CStatObj::LoadUncompiled: szFileName not specified");
m_eVertsSharing = eVertsSharing;
m_bLoadAdditinalInfo = bLoadAdditinalInfo;
m_bKeepInLocalSpace = bKeepInLocalSpace;
m_bUseStreaming = false;
m_bMakePhysics = bMakePhysics;
// make folder name
strcpy(m_szFolderName,szFileName);
while(m_szFolderName[0])
{
if(m_szFolderName[strlen(m_szFolderName)-1] == '\\' || m_szFolderName[strlen(m_szFolderName)-1] == '/')
{ m_szFolderName[strlen(m_szFolderName)-1]=0; break; }
m_szFolderName[strlen(m_szFolderName)-1]=0;
}
// remember file and geom names
strcpy(m_szFileName, szFileName);
strcpy(m_szGeomName, szGeomName && szGeomName[0] ? szGeomName : "");
// load uncompiled
m_nLoadedTrisCount = 0;
m_pTriData = new CIndexedMesh( GetSystem(), szFileName, (szGeomName && szGeomName[0]) ? szGeomName : 0, &m_nLoadedTrisCount, bLoadAdditinalInfo, bKeepInLocalSpace, m_bIgnoreFakeMaterialsInCGF );
if(!m_nLoadedTrisCount)
return false;
// copy helpers
m_lstHelpers.AddList(*m_pTriData->GetHelpers());
// copy lsources
for(int i=0; i<m_pTriData->GetLightSourcesList()->Count(); i++)
{
m_lstLSources.Add(*m_pTriData->GetLightSourcesList()->GetAt(i));
if(m_lstLSources.Last().m_pShader)
m_lstLSources.Last().m_pShader->AddRef();
if(m_lstLSources.Last().m_pLightImage)
m_lstLSources.Last().m_pLightImage->AddRef();
}
// set bbox and rediuses
m_vBoxMin = m_pTriData->m_vBoxMin;
m_vBoxMax = m_pTriData->m_vBoxMax;
CalcRadiuses();
if(bMakePhysics)
Physicalize(); // can remove some indices/faces
// create vert buffers
MakeLeafBuffer(eVertsSharing==evs_ShareAndSortForCache);
for (int i=0; m_pLeafBuffer && m_pLeafBuffer->m_pMats && i<m_pLeafBuffer->m_pMats->Count(); i++)
m_lstShaderTemplates.Add(-1);
if(!GetCVars()->e_stencil_shadows)
FreeTriData(); // source geometry is needed only for stencil shadows
else if(GetCVars()->e_stencil_shadows_build_on_load)
{
if (!GetShadowVolume())
{
if(m_pTriData)
{
SetShadowVolume(CStatObj::MakeConnectivityInfo(m_pTriData, Vec3d(0,0,0), this));
FreeTriData(); // source geometry is needed only for stencil shadows
}
}
}
return true;
}
void CStatObj::LoadLowLODs(EVertsSharing eVertsSharing,bool bLoadAdditinalInfo,bool bKeepInLocalSpace, bool bLoadLater)
{
m_nLoadedLodsNum = 1;
if(!GetCVars()->e_cgf_load_lods)
return;
for(int nLodLevel=1; nLodLevel<MAX_STATOBJ_LODS_NUM; nLodLevel++)
{
// make lod file name
char sLodFileName[512];
strncpy(sLodFileName, m_szFileName, sizeof(m_szFileName));
sLodFileName[strlen(sLodFileName)-4]=0;
strcat(sLodFileName,"_lod");
char sLodNum[8];
ltoa(nLodLevel,sLodNum,10);
strcat(sLodFileName,sLodNum);
strcat(sLodFileName,".cgf");
// try to load
FILE * fp = GetSystem()->GetIPak()->FOpen(sLodFileName,"r");
bool bRes = false;
if(fp)
{
if(!m_arrpLowLODs[nLodLevel])
m_arrpLowLODs[nLodLevel] = new CStatObj( );
bRes = m_arrpLowLODs[nLodLevel]->Load(sLodFileName, m_szGeomName, eVertsSharing, bLoadAdditinalInfo, bKeepInLocalSpace, bLoadLater, false);
GetSystem()->GetIPak()->FClose(fp);
}
if(!bRes)
{
delete m_arrpLowLODs[nLodLevel];
m_arrpLowLODs[nLodLevel]=0;
break;
}
if(m_arrpLowLODs[nLodLevel]->m_nLoadedTrisCount > m_nLoadedTrisCount / 1.5f)
{
#if !defined(LINUX)
Warning(0, sLodFileName,
"CStatObj::LoadLowLODs: Low lod model contains too many polygons comparing to full LOD model [%d agains %d], there is no sense to use it",
m_arrpLowLODs[nLodLevel]->m_nLoadedTrisCount, m_nLoadedTrisCount);
#endif
}
m_nLoadedLodsNum++;
}
}
void CStatObj::PreloadResources(float fDist, float fTime, int dwFlags)
{
FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE );
if(GetLeafBuffer())
GetRenderer()->EF_PrecacheResource(GetLeafBuffer(),fDist,fTime,0);
if(m_arrSpriteTexID[0])
for(int i=0; i<FAR_TEX_COUNT; i++)
{
if(m_arrSpriteTexID[i])
{
ITexPic * pTexPic = GetRenderer()->EF_GetTextureByID(m_arrSpriteTexID[i]);
if(pTexPic)
GetRenderer()->EF_PrecacheResource(pTexPic, 0, 1.f, 0);
}
}
}

498
Cry3DEngine/StatObjPhys.cpp Normal file
View File

@@ -0,0 +1,498 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: statobjphys.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: make physical representation
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "StatObj.h"
#include "MeshIdx.h"
#include "3dengine.h"
/////////////////////////////////////////////////////////////////////////////////////
// Buffer optimizer
/////////////////////////////////////////////////////////////////////////////////////
int CStatObj::FindInPosBuffer(const Vec3d & opt, Vec3d * _vbuff, int _vcount, list2<int> * pHash)
{
for(int i=0; i<pHash->Count(); i++)
{
if(
IsEquivalent(*((Vec3d*)(&_vbuff[(*pHash)[i]].x)), *((Vec3d*)(&opt.x)), VEC_EPSILON)
)
return (*pHash)[i];
}
return -1;
}
void CStatObj::CompactPosBuffer(Vec3d * _vbuff, int * _vcount, list2<int> * pindices)
{
int before = *_vcount; assert(before);
if(!before)
GetConsole()->Exit("Error: CStatObj::CompactPosBuffer: Input vertex count is zero");
Vec3d * tmp_buff = new Vec3d[*_vcount];
int tmp_count = 0;
pindices->Clear();
list2<int> pos_hash_table[256];//[256];
for(uint v=0; v<(uint)(*_vcount); v++)
{
list2<int> * pHash = &pos_hash_table[(unsigned char)(_vbuff[v].x*100)];//[(unsigned char)(_vbuff[v].y*100)];
int find = FindInPosBuffer( _vbuff[v], tmp_buff, tmp_count, pHash);
if(find<0)
{
tmp_buff[tmp_count] = _vbuff[v];
pindices->Add(tmp_count);
pos_hash_table[(unsigned char)(_vbuff[v].x*100)]/*[(unsigned char)(_vbuff[v].y*100)]*/.Add(tmp_count);
tmp_count++;
}
else
{
int u = (uint)find;
pindices->Add(u);
}
}
* _vcount = tmp_count;
memcpy( _vbuff, tmp_buff, tmp_count*sizeof(Vec3d));
delete [] tmp_buff;
}
// This function prepares 3 additional meshes:
// usual physical representation(mat_phys or bounce koeff),
// obstruct physical representation(mat_obstruct)
// and occlusion volume(mat_occl).
// Register physical stuff in physics engine.
void CStatObj::Physicalize()
{
bool bShowINfo = (m_pTriData->m_nFaceCount>10000);
if(bShowINfo)
GetLog()->UpdateLoadingScreen(" Creating buffer for physics ...");
// get phys material id's from game code
IPhysMaterialEnumerator * pPhysMaterialEnumerator = Get3DEngine()->GetPhysMaterialEnumerator();
// special mat id's
int nPhysMatID = -1;
list2<int> arrObstrMatIDs;
int nOcclMatID = -1;
list2<int> arrLeavesMatIDs;
for(int m=0; m<m_pTriData->m_lstMatTable.Count(); m++)
{
// get phys material id's from game code
if(pPhysMaterialEnumerator)
m_pTriData->m_lstMatTable[m].nGamePhysMatId = pPhysMaterialEnumerator->EnumPhysMaterial(m_pTriData->m_lstMatTable[m].sScriptMaterial);
// find phys material id
if(strstr(m_pTriData->m_lstMatTable[m].sScriptMaterial,"mat_phys"))
{ assert(nPhysMatID<0); nPhysMatID = m; }
// find obstruct material id
else if(strstr(m_pTriData->m_lstMatTable[m].sScriptMaterial,"mat_obstruct"))
{ arrObstrMatIDs.Add(m); }
// find obstruct material id
else if (pPhysMaterialEnumerator &&
!pPhysMaterialEnumerator->IsCollidable(m_pTriData->m_lstMatTable[m].nGamePhysMatId) &&
!(m_pTriData->m_lstMatTable[m].m_Flags & MIF_PHYSIC))
{ arrLeavesMatIDs.Add(m); }
// find occlusion material id
else if(strstr(m_pTriData->m_lstMatTable[m].sScriptMaterial,"mat_occl"))
{ assert(nOcclMatID<0); nOcclMatID = m; }
}
#define MESH_PHYSIC 0
#define MESH_OBSTRUCT 1
#define MESH_LEAVES 2
#define MESH_OCCLUSION 3
for(int nMesh = 0; nMesh<=3; nMesh++)
{ // fill physics indices
list2<int> lstPhysIndices;
list2<unsigned char> lstFaceMaterials;
if(nMesh == MESH_PHYSIC)
{ // find all physicalized faces
for(int i=0; i<m_pTriData->m_nFaceCount; i++)
{
if( ((m_pTriData->m_lstMatTable[m_pTriData->m_pFaces[i].shader_id].m_Flags & MIF_PHYSIC) && nPhysMatID<0) ||
m_pTriData->m_pFaces[i].shader_id == nPhysMatID )
{
for(int v=0; v<3; v++)
lstPhysIndices.Add(m_pTriData->m_pFaces[i].v[v]);
lstFaceMaterials.Add(m_pTriData->m_lstMatTable[m_pTriData->m_pFaces[i].shader_id].nGamePhysMatId);
if(m_pTriData->m_pFaces[i].shader_id == nPhysMatID)
{ // remove face from list (it's not needed for rendering)
if(m_pTriData->m_nFaceCount>1)
m_pTriData->m_pFaces[i] = m_pTriData->m_pFaces[m_pTriData->m_nFaceCount-1];
m_pTriData->m_nFaceCount--;
i--;
}
}
}
}
else if(nMesh == MESH_OBSTRUCT)
{ // find all obstruct faces
if(arrObstrMatIDs.Count())
{ // find all obstruct faces
for(int i=0; i<m_pTriData->m_nFaceCount; i++)
{
if( arrObstrMatIDs.Find(m_pTriData->m_pFaces[i].shader_id)>=0 )
{
for(int v=0; v<3; v++)
lstPhysIndices.Add(m_pTriData->m_pFaces[i].v[v]);
lstFaceMaterials.Add(m_pTriData->m_lstMatTable[m_pTriData->m_pFaces[i].shader_id].nGamePhysMatId);
// remove face from list (it's not needed for rendering)
if(arrObstrMatIDs.Find(m_pTriData->m_pFaces[i].shader_id)>=0)
{
if(m_pTriData->m_nFaceCount>1)
m_pTriData->m_pFaces[i] = m_pTriData->m_pFaces[m_pTriData->m_nFaceCount-1];
m_pTriData->m_nFaceCount--;
i--;
}
}
}
}
}
else if(nMesh == MESH_LEAVES)
{ // find all obstruct faces
if(arrLeavesMatIDs.Count())
{ // find all obstruct faces
for(int i=0; i<m_pTriData->m_nFaceCount; i++)
{
if( arrLeavesMatIDs.Find(m_pTriData->m_pFaces[i].shader_id)>=0 )
{
for(int v=0; v<3; v++)
lstPhysIndices.Add(m_pTriData->m_pFaces[i].v[v]);
lstFaceMaterials.Add(m_pTriData->m_lstMatTable[m_pTriData->m_pFaces[i].shader_id].nGamePhysMatId);
}
}
}
}
else if(nMesh == MESH_OCCLUSION)
{
if(nOcclMatID>=0)
{ // find all occlusion faces
for(int i=0; i<m_pTriData->m_nFaceCount; i++)
{
if(m_pTriData->m_pFaces[i].shader_id == nOcclMatID)
{
for(int v=0; v<3; v++)
lstPhysIndices.Add(m_pTriData->m_pFaces[i].v[v]);
lstFaceMaterials.Add(m_pTriData->m_lstMatTable[m_pTriData->m_pFaces[i].shader_id].nGamePhysMatId);
// remove face from list (it's not needed for rendering)
if(m_pTriData->m_nFaceCount>1)
m_pTriData->m_pFaces[i] = m_pTriData->m_pFaces[m_pTriData->m_nFaceCount-1];
m_pTriData->m_nFaceCount--;
i--;
}
}
}
}
if(lstPhysIndices.Count())
{
Vec3d * pExVerts;
int nInitVertCount;
if (m_pTriData->m_lstGeomNames.Count()>0 && strstr(m_pTriData->m_lstGeomNames[0],"cloth")!=0)
{
pExVerts = m_pTriData->m_pVerts;
nInitVertCount = m_pTriData->m_nVertCount;
}
else
{
pExVerts = new Vec3d[lstPhysIndices.Count()];
for(int i=0; i<lstPhysIndices.Count();i++)
pExVerts[i] = m_pTriData->m_pVerts[lstPhysIndices[i]];
if(bShowINfo)
GetLog()->UpdateLoadingScreen(" Compacting buffer ...");
nInitVertCount = lstPhysIndices.Count();
CompactPosBuffer(pExVerts, &nInitVertCount, &lstPhysIndices);
}
if(bShowINfo)
GetLog()->UpdateLoadingScreen(" Creating OBB tree ...");
if(GetPhysicalWorld() && (nMesh==MESH_PHYSIC || nMesh==MESH_OBSTRUCT || nMesh==MESH_LEAVES) && nInitVertCount>2)
{
int nPhysTris = lstPhysIndices.Count()/3;
if(GetCVars()->e_check_number_of_physicalized_polygons &&
nPhysTris > 100+m_pTriData->m_nFaceCount/2)
{
#if !defined(LINUX) //does not matter in dedicated server mode
GetLog()->Log("Physicalized geometry contains too many polygons(%d of %d), for CGF: %s",
nPhysTris, m_pTriData->m_nFaceCount, GetFileName() );
GetLog()->Log(" Number of physicalized tris is more than 100 + number of all tris divided by 2");
#endif
}
IGeomManager *pGeoman = GetPhysicalWorld()->GetGeomManager();
Vec3d ptmin=pExVerts[0],ptmax=pExVerts[0],sz;
for(int i=1;i<nInitVertCount;i++)
{
ptmin.x = min(ptmin.x,pExVerts[i].x);
ptmax.x = max(ptmax.x,pExVerts[i].x);
ptmin.y = min(ptmin.y,pExVerts[i].y);
ptmax.y = max(ptmax.y,pExVerts[i].y);
ptmin.z = min(ptmin.z,pExVerts[i].z);
ptmax.z = max(ptmax.z,pExVerts[i].z);
}
int nMinTrisPerNode=2, nMaxTrisPerNode=4;
sz = ptmax-ptmin;
int flags = mesh_multicontact1 | mesh_uchar_ids;
float tol = 0.05f;
flags |= lstPhysIndices.Count()<=60 ? mesh_SingleBB : mesh_OBB|mesh_AABB;
if (strstr(m_szGeomName,"wheel"))
{
flags |= mesh_approx_cylinder;
tol = 1.0f;
} else
flags |= mesh_approx_box | mesh_approx_sphere | mesh_approx_cylinder;
if (lstPhysIndices.Count()<600 && max(max(sz.x,sz.y),sz.z)>6) // make more dense OBBs for large (wrt terrain grid) objects
nMinTrisPerNode = nMaxTrisPerNode = 1;
assert(nMesh<MAX_PHYS_GEOMS_IN_CGF);
m_arrPhysGeomInfo[nMesh] = pGeoman->RegisterGeometry(pGeoman->CreateMesh((vectorf*)&pExVerts[0], &lstPhysIndices[0],
(short*)&lstFaceMaterials[0], lstPhysIndices.Count()/3, flags, true, true, tol, nMinTrisPerNode,nMaxTrisPerNode, 2.5f));
if (lstFaceMaterials.Count()>0)
m_arrPhysGeomInfo[nMesh]->surface_idx = lstFaceMaterials[0];
}
if(nOcclMatID>=0 && nMesh==MESH_OCCLUSION)
{
m_lstOcclVolVerts.AddList(pExVerts,nInitVertCount);
m_lstOcclVolInds.AddList(lstPhysIndices);
}
if (pExVerts!=m_pTriData->m_pVerts)
delete [] pExVerts;
}
}
if(bShowINfo)
GetLog()->UpdateLoadingScreenPlus("ok");
#undef MESH_PHYSIC
#undef MESH_OBSTRUCT
#undef MESH_OCCLUSION
#undef MESH_LEAVES
}
void CStatObj::PhysicalizeCompiled()
{
// if(bShowINfo)
// GetLog()->UpdateLoadingScreen(" Creating buffer for physics ...");
// get phys material id's from game code
IPhysMaterialEnumerator * pPhysMaterialEnumerator = Get3DEngine()->GetPhysMaterialEnumerator();
{
for(int i=0; pPhysMaterialEnumerator && i<m_pLeafBuffer->m_pMats->Count(); i++)
(*m_pLeafBuffer->m_pMats)[i].nGamePhysMatId = pPhysMaterialEnumerator->EnumPhysMaterial((*m_pLeafBuffer->m_pMats)[i].sScriptMaterial);
}
// find mat id's
int nPhysMatID = -1;
int nObstrMatID = -1;
int nOcclMatID = -1;
#define MESH_PHYSIC 0
#define MESH_OBSTRUCT 1
#define MESH_OCCLUSION 3
for(int nMesh = 0; nMesh<=3; nMesh++)
{ // fill physics indices
// list2<int> & lstPhysIndices =
// list2<unsigned char> & lstFaceMaterials;
// for(int i=0; i<3; i++)
// {
/* m_lstProxyVerts[nMesh];
list2<int> & lstPhysIndices = m_lstProxyInds[nMesh].LoadFromBuffer(pSerBuf,nPos);
LoadBuffer(m_vPhysBoxMin[i], sizeof(m_vPhysBoxMin[i]), pSerBuf, nPos);
LoadBuffer(m_vPhysBoxMin[i], sizeof(m_vPhysBoxMin[i]), pSerBuf, nPos);*/
// }
/*
if(nMesh == MESH_PHYSIC)
{ // find all physicalized faces
for(i=0; i<m_pTriData->m_nFaceCount; i++)
{
if( ((m_pTriData->m_lstMatTable[m_pTriData->m_pFaces[i].shader_id].m_Flags & MIF_PHYSIC) && nPhysMatID<0) ||
m_pTriData->m_pFaces[i].shader_id == nPhysMatID )
{
for(int v=0; v<3; v++)
lstPhysIndices.Add(m_pTriData->m_pFaces[i].v[v]);
lstFaceMaterials.Add(m_pTriData->m_lstMatTable[m_pTriData->m_pFaces[i].shader_id].nGamePhysMatId);
if(m_pTriData->m_pFaces[i].shader_id == nPhysMatID)
{ // remove face from list (it's not needed for rendering)
if(m_pTriData->m_nFaceCount>1)
m_pTriData->m_pFaces[i] = m_pTriData->m_pFaces[m_pTriData->m_nFaceCount-1];
m_pTriData->m_nFaceCount--;
i--;
}
}
}
}
else if(nMesh == MESH_OBSTRUCT)
{ // find all obstruct faces
if(nObstrMatID>=0)
{ // find all obstruct faces
for(i=0; i<m_pTriData->m_nFaceCount; i++)
{
if(m_pTriData->m_pFaces[i].shader_id == nObstrMatID)
{
for(int v=0; v<3; v++)
lstPhysIndices.Add(m_pTriData->m_pFaces[i].v[v]);
lstFaceMaterials.Add(m_pTriData->m_lstMatTable[m_pTriData->m_pFaces[i].shader_id].nGamePhysMatId);
// remove face from list (it's not needed for rendering)
if(m_pTriData->m_nFaceCount>1)
m_pTriData->m_pFaces[i] = m_pTriData->m_pFaces[m_pTriData->m_nFaceCount-1];
m_pTriData->m_nFaceCount--;
i--;
}
}
}
}
else if(nMesh == MESH_OCCLUSION)
{
if(nOcclMatID>=0)
{ // find all occlusion faces
for(i=0; i<m_pTriData->m_nFaceCount; i++)
{
if(m_pTriData->m_pFaces[i].shader_id == nOcclMatID)
{
for(int v=0; v<3; v++)
lstPhysIndices.Add(m_pTriData->m_pFaces[i].v[v]);
lstFaceMaterials.Add(m_pTriData->m_lstMatTable[m_pTriData->m_pFaces[i].shader_id].nGamePhysMatId);
// remove face from list (it's not needed for rendering)
if(m_pTriData->m_nFaceCount>1)
m_pTriData->m_pFaces[i] = m_pTriData->m_pFaces[m_pTriData->m_nFaceCount-1];
m_pTriData->m_nFaceCount--;
i--;
}
}
}
}
*/
list2<int> & lstPhysIndices = m_lstProxyInds[nMesh];//.LoadFromBuffer(pSerBuf,nPos);
// LoadBuffer(m_vPhysBoxMin[i], sizeof(m_vPhysBoxMin[i]), pSerBuf, nPos);
// LoadBuffer(m_vPhysBoxMin[i], sizeof(m_vPhysBoxMin[i]), pSerBuf, nPos);
if(lstPhysIndices.Count())
{
Vec3d * pExVerts = &m_lstProxyVerts[nMesh][0];
// if(bShowINfo)
// GetLog()->UpdateLoadingScreen(" Creating OBB tree ...");
if(GetPhysicalWorld() && (nMesh==MESH_PHYSIC || nMesh==MESH_OBSTRUCT))
{
int nPhysTris = lstPhysIndices.Count()/3;
int nFaceCount = 0;
m_pLeafBuffer->GetIndices(&nFaceCount);
nFaceCount/=3;
if(GetCVars()->e_check_number_of_physicalized_polygons &&
nPhysTris > 100+nFaceCount/2)
{
#if !defined(LINUX) //does not matter in dedicated server mode
GetLog()->Log("Physicalized geometry contains too many polygons(%d of %d), for CGF: %s",
nPhysTris, nFaceCount, GetFileName() );
GetLog()->Log(" Number of physicalized tris is more than 100 + number of all tris divided by 2");
#endif
}
list2<unsigned char> & lstFaceMaterials = m_lstProxyFaceMaterials[nMesh];
// remap shader id to game mat id
for(int f=0; f<lstFaceMaterials.Count(); f++)
{
CMatInfo * pMat = m_pLeafBuffer->m_pMats->Get(lstFaceMaterials[f]);
lstFaceMaterials[f] = pMat->nGamePhysMatId;
}
IGeomManager *pGeoman = GetPhysicalWorld()->GetGeomManager();
Vec3d & ptmin = m_vPhysBoxMin[nMesh];
Vec3d & ptmax = m_vPhysBoxMax[nMesh];
int nMinTrisPerNode=2, nMaxTrisPerNode=4;
Vec3d sz = ptmax - ptmin;
int flags = mesh_multicontact1 | mesh_uchar_ids;
float tol = 0.05f;
flags |= lstPhysIndices.Count()<=60 ? mesh_SingleBB : mesh_OBB|mesh_AABB;
if (strstr(m_szGeomName,"wheel"))
{
flags |= mesh_approx_cylinder;
tol = 1.0f;
} else
flags |= mesh_approx_box | mesh_approx_sphere | mesh_approx_cylinder;
if (lstPhysIndices.Count()<600 && max(max(sz.x,sz.y),sz.z)>6) // make more dense OBBs for large (wrt terrain grid) objects
nMinTrisPerNode = nMaxTrisPerNode = 1;
assert(!m_arrPhysGeomInfo[nMesh]);
m_arrPhysGeomInfo[nMesh] = pGeoman->RegisterGeometry(pGeoman->CreateMesh((vectorf*)&pExVerts[0], &lstPhysIndices[0],
(short*)&lstFaceMaterials[0], lstPhysIndices.Count()/3, flags, true, true, tol, nMinTrisPerNode,nMaxTrisPerNode, 2.5f));
assert(m_arrPhysGeomInfo[nMesh]->nRefCount == 1);
if (lstFaceMaterials.Count()>0)
m_arrPhysGeomInfo[nMesh]->surface_idx = lstFaceMaterials[0];
}
if(nOcclMatID>=0 && nMesh==MESH_OCCLUSION)
{
m_lstOcclVolVerts.AddList(m_lstProxyVerts[nMesh]);
m_lstOcclVolInds.AddList(lstPhysIndices);
}
// delete [] pExVerts;
}
/*else if(lstPhysIndices.Count())
{
Warning(0,GetFileName(),"CStatObj::Physicalize: proxy geometry contains more than 200 polygons - skipped, for CGF: %s",GetFileName() );
}*/
m_lstProxyInds[nMesh].Reset();
m_lstProxyVerts[nMesh].Reset();
m_lstProxyFaceMaterials[nMesh].Reset();
}
// if(bShowINfo)
// GetLog()->UpdateLoadingScreenPlus("ok");
#undef MESH_PHYSIC
#undef MESH_OBSTRUCT
#undef MESH_OCCLUSION
}

599
Cry3DEngine/StatObjRend.cpp Normal file
View File

@@ -0,0 +1,599 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: statobjrend.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: prepare and add render element into renderer
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "StatObj.h"
#include "../RenderDll/Common/shadow_renderer.h"
#include "LMCompStructures.h"
#include "MeshIdx.h"
#include "visareas.h"
//////////////////////////////////////////////////////////////////////
bool CStatObj::SetShaderTemplate(int nTemplate, const char *TemplName, const char *ShaderName, bool bOnlyRegister, int * pnNewTemplateId)
{
for(int i=0; i<MAX_STATOBJ_LODS_NUM; i++)
if(m_arrpLowLODs[i])
m_arrpLowLODs[i]->SetShaderTemplate(nTemplate, TemplName, ShaderName, bOnlyRegister);
CLeafBuffer *lb = m_pLeafBuffer;
if (!lb || (lb->m_pMats->Count() != m_lstShaderTemplates.Num()))
return false;
if (!ShaderName)
{
for (int i=0; i<lb->m_pMats->Count(); i++)
{
IShader * e = (*lb->m_pMats)[i].shaderItem.m_pShader;
SRenderShaderResources *sr = (*lb->m_pMats)[i].shaderItem.m_pShaderResources;
if (e && (*lb->m_pMats)[i].pRE && (*lb->m_pMats)[i].nNumIndices)
{
if(nTemplate < EFT_USER_FIRST && nTemplate >= 0)
e->AddTemplate(sr, nTemplate, NULL, false);
else
if (TemplName && TemplName[0])
{
if (nTemplate <= EFT_USER_FIRST)
nTemplate = EFT_USER_FIRST + 1;
e->AddTemplate(sr, nTemplate, TemplName, false);
}
if (!bOnlyRegister)
m_lstShaderTemplates[i] = nTemplate;
}
}
if(pnNewTemplateId)
*pnNewTemplateId = nTemplate;
return true;
}
bool bRes = false;
for (int i=0; i<m_lstShaderTemplates.Num(); i++)
{
if (!lb->m_pMats->Get(i)->shaderItem.m_pShader)
continue;
if (!stricmp(ShaderName, lb->m_pMats->Get(i)->shaderItem.m_pShader->GetName()))
{
SRenderShaderResources *sr = (*lb->m_pMats)[i].shaderItem.m_pShaderResources;
bRes = true;
if(nTemplate < EFT_USER_FIRST && nTemplate >= 0)
lb->m_pMats->Get(i)->shaderItem.m_pShader->AddTemplate(sr, nTemplate);
else
if (TemplName && TemplName[0])
lb->m_pMats->Get(i)->shaderItem.m_pShader->AddTemplate(sr, nTemplate, TemplName);
m_lstShaderTemplates[i] = nTemplate;
}
}
if(bRes && pnNewTemplateId)
*pnNewTemplateId = nTemplate;
return bRes;
}
void CStatObj::SetShaderFloat(const char *Name, float Val)
{
int i;
for(i=0; i<MAX_STATOBJ_LODS_NUM; i++)
if(m_arrpLowLODs[i])
m_arrpLowLODs[i]->SetShaderFloat(Name, Val);
char name[128];
strcpy(name, Name);
strlwr(name);
for (i=0; i<m_ShaderParams.Num(); i++)
{
if (!strcmp(name, m_ShaderParams[i].m_Name))
break;
}
if (i == m_ShaderParams.Num())
{
SShaderParam pr;
strncpy(pr.m_Name, name, 32);
m_ShaderParams.AddElem(pr);
}
m_ShaderParams[i].m_Type = eType_FLOAT;
m_ShaderParams[i].m_Value.m_Float = Val;
}
void CStatObj::SetColor(const char *Name, float fR, float fG, float fB, float fA)
{
}
void CStatObj::SetupBending(CCObject * pObj, float fBending)
{
pObj->m_fBending = fBending;
Vec3d vObjPos = pObj->GetTranslation();
SWaveForm2 *pWF[2];
pObj->AddWaves(pWF);
SWaveForm2 *wf = pWF[0];
wf->m_Level = 0.000f; // between 0.001 and 0.1
wf->m_Freq = 1.0f/m_fRadiusVert/8.0f+0.2f; // between 0.001 and 0.1
wf->m_Phase = vObjPos.x/8.0f;
wf->m_Amp = 0.002f;
wf = pWF[1];
wf->m_Level = 0.000f; // between 0.001 and 0.1
wf->m_Freq = 1.0f/m_fRadiusVert/7.0f+0.2f; // between 0.001 and 0.1
wf->m_Phase = vObjPos.y/8.0f;
wf->m_Amp = 0.002f;
pObj->m_ObjFlags |= FOB_BENDED;
}
//////////////////////////////////////////////////////////////////////
void CStatObj::Render(const SRendParams & rParams, const Vec3& t, int nLodLevel)
{
IRenderer * pRend = GetRenderer();
m_nLastRendFrameId = GetFrameID();
////////////////////////////////////////////////////////////////////////////////////////////////////
// Process LODs
////////////////////////////////////////////////////////////////////////////////////////////////////
if (nLodLevel >= m_nLoadedLodsNum)
nLodLevel = m_nLoadedLodsNum-1;
if (nLodLevel && m_arrpLowLODs[nLodLevel] && nLodLevel<m_nLoadedLodsNum && GetCVars()->e_cgf_load_lods)
{
m_arrpLowLODs[nLodLevel]->Render(rParams,Vec3(zero),0);
return;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Load object if not loaded
////////////////////////////////////////////////////////////////////////////////////////////////////
if(m_bUseStreaming && GetCVars()->e_stream_cgf)
StreamCCGF(false);
// if(m_bUseStreaming && m_fStreamingTimePerFrame<CGF_STREAMING_MAX_TIME_PER_FRAME)
// if(GetCVars()->e_stream_cgf && GetCVars()->e_stream_for_visuals)
// CheckLoaded();
if(!m_pLeafBuffer || !m_nLoadedTrisCount)
return; // object not loaded yet
////////////////////////////////////////////////////////////////////////////////////////////////////
// Specifiy transformation
////////////////////////////////////////////////////////////////////////////////////////////////////
CCObject * pObj;
pObj = pRend->EF_GetObject(true, -1);
pObj->m_fDistanceToCam = rParams.fSQDistance;
if (!rParams.pMatrix)
mathCalcMatrix(pObj->m_Matrix, rParams.vPos, rParams.vAngles, Vec3d(rParams.fScale,rParams.fScale,rParams.fScale), Cry3DEngineBase::m_CpuFlags);
else
pObj->m_Matrix = *rParams.pMatrix;
pObj->m_SortId = rParams.fCustomSortOffset;
////////////////////////////////////////////////////////////////////////////////////////////////////
// Set flags
////////////////////////////////////////////////////////////////////////////////////////////////////
pObj->m_ObjFlags |= rParams.dwFObjFlags;
pObj->m_fHeatFactor = rParams.fHeatAmount;
pObj->m_AmbColor = rParams.vAmbientColor;
assert(pObj->m_AmbColor.x>=0 && pObj->m_AmbColor.x<=1.f);
assert(pObj->m_AmbColor.y>=0 && pObj->m_AmbColor.y<=1.f);
assert(pObj->m_AmbColor.z>=0 && pObj->m_AmbColor.z<=1.f);
if (GetCVars()->e_shadow_maps)
pObj->m_pShadowCasters = rParams.pShadowMapCasters;
else
pObj->m_pShadowCasters=0;
// if (rParams.dwFlags & RPF_DRAWNEAR)
// pObj->m_ObjFlags |= FOB_NEAREST;
if (pObj->m_pShadowCasters)
pObj->m_ObjFlags |= FOB_INSHADOW;
pObj->m_Color = CFColor(
rParams.vColor.x,
rParams.vColor.y,
rParams.vColor.z,
rParams.fAlpha);
if (rParams.pShaderParams && rParams.pShaderParams->Num())
pObj->m_ShaderParams = rParams.pShaderParams;
else
if (m_ShaderParams.Num())
pObj->m_ShaderParams = &m_ShaderParams;
////////////////////////////////////////////////////////////////////////////////////////////////////
// Process bending
////////////////////////////////////////////////////////////////////////////////////////////////////
if (rParams.fBending)
SetupBending(pObj, rParams.fBending);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Add LOCAL lsources
////////////////////////////////////////////////////////////////////////////////////////////////////
int dwDynMaskLocal = 0;
for(int i=0; i<m_lstLSources.Count(); i++)
if(m_lstLSources[i].m_Flags & DLF_LOCAL)
if( ((m_lstLSources[i].m_Flags & DLF_HEATSOURCE) && pRend->EF_GetHeatVision()) ||
((m_lstLSources[i].m_Flags & DLF_LIGHTSOURCE)&& !pRend->EF_GetHeatVision()))
if(rParams.fDistance < 256)
{
if (rParams.pMatrix)
{
m_lstLSources[i].m_Origin =
rParams.pMatrix->TransformPointOLD(m_lstLSources[i].m_vObjectSpacePos);
}
else
{
//Matrix objMat;
//objMat.Identity();
//objMat=GetTranslationMat(rParams.vPos)*objMat;
//objMat=GetRotationZYX44(-gf_DEGTORAD*rParams.vAngles)*objMat; //NOTE: angles in radians and negated
//objMat=GetScale33( Vec3d(rParams.fScale,rParams.fScale,rParams.fScale) )*objMat;
//OPTIMISED_BY_IVO
Matrix33diag diag = Vec3d(rParams.fScale,rParams.fScale,rParams.fScale); //use diag-matrix for scaling
Matrix34 rt34 = Matrix34::CreateRotationXYZ(gf_DEGTORAD*rParams.vAngles, rParams.vPos ); //set scaling and translation in one function call
Matrix44 objMat = rt34*diag; //optimised concatenation: m34*diag
objMat = GetTransposed44(objMat); //TODO: remove this after E3 and use Matrix34 instead of Matrix44
m_lstLSources[i].m_Origin = objMat.TransformPointOLD(m_lstLSources[i].m_vObjectSpacePos);
}
pRend->EF_ADDDlight (&m_lstLSources[i]);
if(m_lstLSources[i].m_Id>=0)
dwDynMaskLocal |= (1<<m_lstLSources[i].m_Id);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Add helpers
////////////////////////////////////////////////////////////////////////////////////////////////////
/*
int i;
for (i=0; i<m_lstHelpers.Count(); i++)
{
HelperInfo *pHI = &m_lstHelpers[i];
if (pHI->m_pShader)
{
CCObject * pObject = pRend->EF_GetObject(true);
Matrix matr;
if (pObj->m_ObjFlags & FOB_USEMATRIX)
matr = pObj->m_Matrix;
else
{
matr.Identity();
matr.Translate(pObj->m_Trans);
matr.Rotate(pObj->m_Angs);
if (pObj->m_Scale != 1.0f)
matr.ScaleMatrix(pObj->m_Scale, pObj->m_Scale, pObj->m_Scale);
}
pObject->m_Trans = matr.TransformPoint(pHI->vPos);
pObject->m_Color = Col_White;
pObject->m_Angs = Vec3d(0,0,0);
for (int nr=0; nr<pHI->m_pShader->GetREs()->Num(); nr++)
{
pRend->EF_AddEf(0, pHI->m_pShader->GetREs()->Get(nr), pHI->m_pShader, pObject, -1);
}
}
}
*/
pObj->m_DynLMMask = rParams.nDLightMask;
pObj->m_DynLMMask |= dwDynMaskLocal;
#ifdef _DEBUG
int nCount = 0;
for(int i=0; i<32; i++)
{
if(pObj->m_DynLMMask & (1<<i))
nCount++;
}
if(nCount>16)
{
#if !defined(LINUX)
Warning( 0,0,"Warning: CStatObj::Render: no more than 16 lsources can be requested");
#endif
}
#endif
if(rParams.pLightMapInfo)
{
// set object lmaps and texture coordinates
pObj->m_pLMTCBufferO = rParams.pLMTCBuffer;
pObj->m_nLMId = rParams.pLightMapInfo->GetColorLerpTex();
pObj->m_nLMDirId = rParams.pLightMapInfo->GetDomDirectionTex();
pObj->m_nHDRLMId = rParams.pLightMapInfo->GetHDRColorLerpTex();
pObj->m_nOcclId = rParams.pLightMapInfo->GetOcclTex();
*(DWORD*)pObj->m_OcclLights = *(DWORD*)rParams.arrOcclusionLightIds;
}
/* if(!m_nRenderStackLevel)
{
pObj->m_nScissorX1 = rParams.nScissorX1;
pObj->m_nScissorY1 = rParams.nScissorY1;
pObj->m_nScissorX2 = rParams.nScissorX2;
pObj->m_nScissorY2 = rParams.nScissorY2;
}*/
////////////////////////////////////////////////////////////////////////////////////////////////////
// Add render elements
////////////////////////////////////////////////////////////////////////////////////////////////////
IMatInfo * pMaterial = NULL;
if (GetCVars()->e_materials && !m_bDefaultObject)
pMaterial = rParams.pMaterial;
bool bNotCurArea = false;
if(GetCVars()->e_overlay_geometry >= 2)
{
bNotCurArea = (!rParams.pCaller || !GetVisAreaManager() ||
((CVisArea *)rParams.pCaller->GetEntityVisArea() && !((CVisArea *)rParams.pCaller->GetEntityVisArea())->
FindVisArea((CVisArea *)GetVisAreaManager()->m_pCurArea,1, true)));
SetShaderFloat("offset", 0);
}
else if(GetCVars()->e_overlay_geometry < 2 )
m_ShaderParams.SetNum(0);
if(GetCVars()->e_debug_lights!=1.f)
m_pLeafBuffer->Render(rParams,pObj,m_lstShaderTemplates,GetCVars()->e_overlay_geometry,bNotCurArea,pMaterial, false);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Print debug info
////////////////////////////////////////////////////////////////////////////////////////////////////
if (GetCVars()->e_vegetation_debug)
RenderDebugInfo(rParams, pObj);
if(GetCVars()->e_debug_lights)
if(!(rParams.dwFObjFlags & FOB_LIGHTPASS || rParams.dwFObjFlags & FOB_FOGPASS))
m_pLeafBuffer->RenderDebugLightPass(pObj->m_Matrix, pObj->m_DynLMMask, GetCVars()->e_debug_lights);
}
/*
void CStatObj::RenderLeafBuffer(const SRendParams & rParams, CCObject * pObj)
{
// static int nAll=0,nUsed=0;
int nSortValue = rParams.bDrawNear ? eS_Nearest : rParams.nSortValue;
for (int i=0; i<m_pLeafBuffer->m_pMats->Count(); i++)
{
CMatInfo * pMat = m_pLeafBuffer->m_pMats->Get(i);
CRendElement * pREOcLeaf = pMat->pRE;
// nAll++;
// Override default material
if (rParams.pMaterial && GetCVars()->e_materials && !m_bDefaultObject)
{
int nMatId = pMat->m_nCGFMaterialID;
if(nMatId<0)
{
// assert(0);
continue;
}
// Assume that the root material is the first material, sub materials start from index 1.
if (nMatId == 0)
pMat = (CMatInfo*)rParams.pMaterial;
else if (nMatId-1 < rParams.pMaterial->GetSubMtlCount())
{
pMat = (CMatInfo*)rParams.pMaterial->GetSubMtl(nMatId-1);
}
}
IShader * e = pMat->shaderItem.m_pShader;
SRenderShaderResources* sr = pMat->shaderItem.m_pShaderResources;
// assert(e && pREOcLeaf);
if (pREOcLeaf && e)
{
// nUsed++;
int nTempl = rParams.nShaderTemplate;
if (nTempl == -2 && i<m_lstShaderTemplates.Num())
nTempl = m_lstShaderTemplates[i];
if(rParams.pfCustomData)
{
assert(!pREOcLeaf->m_CustomData);
pREOcLeaf->m_CustomData = rParams.pfCustomData;
}
if (rParams.nShaderTemplate>0)
e->AddTemplate(sr, (int)rParams.nShaderTemplate,NULL);
if(rParams.dwFObjFlags & FOB_FOGPASS)
if(e->GetTemplate(-1)->GetFlags() & EF_OVERLAY)
continue; // skip overlays during fog pass - it will be fogged by base geometry fog pass
bool bTransparent = pMat->shaderItem.IsTransparent();
IShader * pShader = rParams.pStateShader;
if(bTransparent)
{
if((rParams.dwFlags & RPF_LIGHTPASS) || (rParams.dwFObjFlags & FOB_FOGPASS) || (nTempl == EFT_INVLIGHT))
continue;
if(nSortValue==eS_FogShader)
nSortValue=eS_FogShader_Trans;
if(!GetCVars()->e_overlay_geometry)
if(e->GetTemplate(-1)->GetFlags() & EF_OVERLAY)
continue;
if(GetCVars()->e_overlay_geometry >= 2 && e->GetTemplate(-1)->GetFlags() & EF_OVERLAY)
{
if(!rParams.pCaller || !GetVisAreaManager() ||
((CVisArea *)rParams.pCaller->GetEntityVisArea() && !((CVisArea *)rParams.pCaller->GetEntityVisArea())->
FindVisArea((CVisArea *)GetVisAreaManager()->m_pCurArea,1, true)))
continue;
if(GetCVars()->e_overlay_geometry == 2)
{
if(int(GetTimer()->GetCurrTime()*5)&1)
pShader = GetRenderer()->EF_LoadShader("NoZTestState", eSH_World, EF_SYSTEM );
}
else
pShader = GetRenderer()->EF_LoadShader("ZTestGreaterState", eSH_World, EF_SYSTEM );
SetShaderFloat("offset", 0);
}
else if(GetCVars()->e_overlay_geometry < 2 )
m_ShaderParams.SetNum(0);
}
if( rParams.bRenderIntoShadowMap && (pMat->m_Flags & MIF_NOCASTSHADOWS) )
continue;
if( nSortValue == EFSLIST_STENCIL && bTransparent )
GetRenderer()->EF_AddEf(rParams.nFogVolumeID, pREOcLeaf, e, sr, pObj, nTempl, pShader, 0);
else
GetRenderer()->EF_AddEf(rParams.nFogVolumeID, pREOcLeaf, e, sr, pObj, nTempl, pShader, nSortValue);
}
} //i
}*/
void CStatObj::RenderDebugInfo(const SRendParams & rParams, const CCObject * pObj)
{
IRenderer * pRend = GetRenderer();
// bbox
pRend->SetMaterialColor(0,1,1,0.5f);
pRend->Draw3dBBox(m_vBoxMin*rParams.fScale+rParams.vPos,
m_vBoxMax*rParams.fScale+rParams.vPos);
// scaled bbox (frustum culling check)
if(GetCVars()->e_vegetation_debug==2)
{
pRend->SetMaterialColor(1,0,1,0.5f);
pRend->Draw3dBBox(m_vBoxMin*rParams.fScale*1.5f+rParams.vPos,
m_vBoxMax*rParams.fScale*1.5f+rParams.vPos);
}
{ // cgf's name and tris num
char szName[512];
strncpy(szName,m_szFileName,sizeof(szName));
while(strstr(szName,"\\"))
strcpy(szName, szName+1);
float color[4] = {0,1,1,1};
pRend->DrawLabelEx(rParams.vPos/*+GetCenter()*rParams.fScale*/,
0.75f,color,false,true,"%s(%d tris, %d mats)", szName, m_nLoadedTrisCount,
(m_pLeafBuffer && m_pLeafBuffer->m_pMats) ? m_pLeafBuffer->m_pMats->Count() : 0);
}
// helpers
for( int i=0; i<m_lstHelpers.Count(); i++)
{
StatHelperInfo *pHI = &m_lstHelpers[i];
// make object matrix
Matrix44 tMat;
tMat = pObj->m_Matrix;
// draw axes
DrawMatrix(tMat);
tMat = tMat*pHI->tMat;
Vec3d vTrans = tMat.GetTranslationOLD();
float color[4] = {1,1,0,1};
// text
pRend->DrawLabelEx(vTrans, 0.75f, color, false, true, "%s", pHI->sName);
// draw axes
DrawMatrix(tMat);
}
}
void CStatObj::DrawMatrix(const Matrix44 & tMat)
{
IRenderer * pRend = GetRenderer();
Vec3d vTrans = tMat.GetTranslationOLD();
float color[] = {1,1,1,1};
//CHANGED_BY_IVO
pRend->SetMaterialColor(1,0,0,0);
//pRend->Draw3dBBox( vTrans, vTrans+0.05f*Vec3d(tMat.m_values[0]), true );
//pRend->DrawLabelEx(vTrans+0.05f*Vec3d(tMat.m_values[0]), 0.75f,color,false,true,"x");
pRend->Draw3dBBox( vTrans, vTrans+0.05f*tMat.GetOrtX(), true );
pRend->DrawLabelEx(vTrans+0.05f*tMat.GetOrtX(), 0.75f,color,false,true,"x");
pRend->SetMaterialColor(0,1,0,0);
//pRend->Draw3dBBox( vTrans, vTrans+0.05f*Vec3d(tMat.m_values[1]), true );
//pRend->DrawLabelEx(vTrans+0.05f*Vec3d(tMat.m_values[1]), 0.75f,color,false,true,"y");
pRend->Draw3dBBox( vTrans, vTrans+0.05f*tMat.GetOrtY(), true );
pRend->DrawLabelEx(vTrans+0.05f*tMat.GetOrtY(), 0.75f,color,false,true,"y");
pRend->SetMaterialColor(0,0,1,0);
//pRend->Draw3dBBox( vTrans, vTrans+0.05f*Vec3d(tMat.m_values[2]), true );
//pRend->DrawLabelEx(vTrans+0.05f*Vec3d(tMat.m_values[2]), 0.75f,color,false,true,"z");
pRend->Draw3dBBox( vTrans, vTrans+0.05f*tMat.GetOrtZ(), true );
pRend->DrawLabelEx(vTrans+0.05f*tMat.GetOrtZ(), 0.75f,color,false,true,"z");
}
const CDLight * CStatObj::GetLightSources(int nId)
{
if(nId>=0 && nId<m_lstLSources.Count())
return &m_lstLSources[nId];
return 0;
}
void CStatObj::SpawnParticles( ParticleParams & SpawnParticleParams, const Matrix44 & matWorldSpace, bool bOnlyUpLookingFaces )
{
// select random vertex
int n=rand() % m_pLeafBuffer->m_SecVertCount;
// int n = int(rnd()*m_pLeafBuffer->m_SecVertCount);
// while(n>=m_pLeafBuffer->m_SecVertCount)
// n = int(rnd()*m_pLeafBuffer->m_SecVertCount);
// access pos and normal
int nPosStride = 0, nNormStride = 0;
byte * arrPos = m_pLeafBuffer->GetPosPtr(nPosStride);
byte * arrNor = m_pLeafBuffer->GetNormalPtr(nNormStride);
Vec3d * pPos = (Vec3d*)&arrPos[n*nPosStride];
Vec3d * pNorm = (Vec3d*)&arrNor[n*nNormStride];
// transform
Vec3d vWSPos = matWorldSpace.TransformPointOLD(*pPos);
Vec3d vWSNorm = matWorldSpace.TransformVectorOLD(*pNorm);
//Vec3d vWSNorm = GetTransposed44(matWorldSpace)*(*pNorm);
// spawn
if(!bOnlyUpLookingFaces || vWSNorm.z>0.25f)
{
Get3DEngine()->SpawnParticles(SpawnParticleParams);
SpawnParticleParams.vPosition = vWSPos;
SpawnParticleParams.vDirection = (SpawnParticleParams.vDirection+vWSNorm)*0.5f;
}
}

View File

@@ -0,0 +1,118 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: statobjconstr.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: loading
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "StatObj.h"
#include "MeshIdx.h"
#include "serializebuffer.h"
#include "objman.h"
bool CStatObj::Serialize(int & nPos, uchar * pSerBuf, bool bSave, char * szFolderName)
{
char szSignature[16];
if(!LoadBuffer(szSignature, 8, pSerBuf, nPos) || strcmp(szSignature,"StatObj"))
return false;
for(int i=0; i<3; i++)
{
m_lstProxyVerts[i].LoadFromBuffer(pSerBuf,nPos);
m_lstProxyInds[i].LoadFromBuffer(pSerBuf,nPos);
LoadBuffer(m_vPhysBoxMin[i], sizeof(m_vPhysBoxMin[i]), pSerBuf, nPos);
LoadBuffer(m_vPhysBoxMax[i], sizeof(m_vPhysBoxMax[i]), pSerBuf, nPos);
m_lstProxyFaceMaterials[i].LoadFromBuffer(pSerBuf,nPos);
}
LoadBuffer(&m_vBoxMin, sizeof(m_vBoxMin), pSerBuf, nPos);
LoadBuffer(&m_vBoxMax, sizeof(m_vBoxMax), pSerBuf, nPos);
assert(m_pSvObj == 0x00000000);
m_lstHelpers.LoadFromBuffer(pSerBuf,nPos);
m_lstLSources.LoadFromBuffer(pSerBuf,nPos);
// parse name and and load light shader if needed
for(int i=0; i<m_lstLSources.Count(); i++)
InitCompiledLightSource(&m_lstLSources[i]);
m_pLeafBuffer = GetRenderer()->CreateLeafBuffer(eBT_Static,"CompiledStatObj");
m_pLeafBuffer->Serialize(nPos, pSerBuf, bSave, m_szFolderName, m_szFileName, CObjManager::m_dCIndexedMesh__LoadMaterial);
SetShadowVolume(CStatObj::MakeConnectivityInfoFromCompiledData(pSerBuf, nPos, this));
return true;
}
void CStatObj::InitCompiledLightSource(CDLight * pDLight)
{
char *shName = NULL;
char *str;
char name[128];
char nameTgt[128];
strncpy(name, pDLight->m_Name, sizeof(name));
str = strstr(name, "->");
if (str)
{
name[str-name] = 0;
strncpy(nameTgt, &str[2], sizeof(nameTgt));
}
else
nameTgt[0] = 0;
if(str=strchr(name, '('))
{
name[str-name] = 0;
shName = &name[str-name+1];
if(str=strchr(shName, ')'))
shName[str-shName] = 0;
}
// strcpy(pDLight->m_Name, name);
if (nameTgt[0])
{
// strcpy(pDLight->m_TargetName, nameTgt);
}
pDLight->m_Flags &= ~(DLF_LIGHTSOURCE | DLF_HEATSOURCE);
if (!pDLight->Parse())
pDLight->m_Flags |= DLF_LIGHTSOURCE;
else
{
if (!strncmp(pDLight->m_Name, "local_hs", 8))
{
pDLight->m_fDirectFactor = 0;
pDLight->m_Flags |= DLF_LOCAL;
}
}
if (shName)
{
pDLight->m_pShader = GetRenderer()->EF_LoadShader(shName, eSH_Misc);
if (pDLight->m_pShader!=0 && (pDLight->m_pShader->GetFlags() & EF_NOTFOUND))
{
pDLight->m_pShader->Release();
pDLight->m_pShader = NULL;
pDLight->m_Flags |= DLF_FAKE;
#if !defined(LINUX)
Warning(0,m_szFileName,
"Error: CIndexedMesh::MakeLightSources: Shader %s not found for lsource %s",
shName, pDLight->m_Name);
#endif
}
if (pDLight->m_pShader!=0 && (pDLight->m_pShader->GetLFlags() & LMF_DISABLE))
pDLight->m_Flags |= DLF_FAKE;
}
pDLight->MakeBaseParams();
}

View File

@@ -0,0 +1,95 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: statobjshadow.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: shadow maps
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "StatObj.h"
#include "../RenderDll/Common/shadow_renderer.h"
void CStatObj::PrepareShadowMaps(const Vec3d & obj_pos, ShadowMapLightSource * pLSource)
{
if(!GetCVars()->e_shadow_maps)
return;
// reset frustums
int f;
for(f=0; f<pLSource->m_LightFrustums.Count(); f++)
{ delete pLSource->m_LightFrustums[f].pModelsList; pLSource->m_LightFrustums[f].pModelsList=0; }
pLSource->m_LightFrustums.Reset();
{ // define new frustum
ShadowMapFrustum new_lof;
// memset(&new_lof,0,sizeof(ShadowMapFrustum));
new_lof.pModelsList = new list2<IStatObj*>;
new_lof.pModelsList->PreAllocate(128);
list2<IStatObj*> so;
so.Add(this);
ShadowMapFrustum * lof = GetRenderer()->MakeShadowMapFrustum(&new_lof, pLSource, obj_pos+GetCenter()/*Vec3d(0,0,GetCenterZ())*/, &so, EST_DEPTH_BUFFER);
lof->pOwnerGroup = this;
if(lof)
{
pLSource->m_LightFrustums.Add(*lof);
}
// this lists are in another object now
new_lof.pModelsList=0;
new_lof.pEntityList=0;
}
int nTexSize = GetCVars()->e_max_shadow_map_size;
while(nTexSize > GetRadius()*200)
nTexSize/=2;
if(nTexSize<16)
nTexSize=16; // in case of error
pLSource->m_LightFrustums[f].nTexSize = nTexSize;
// make depth textures
//for( f=0; f<pLSource->m_LightFrustums.Count(); f++)
// GetRenderer()->PrepareDepthMap(&pLSource->m_LightFrustums[f], true);
}
void CStatObj::MakeShadowMaps(const Vec3d vSunPos)
{
if(m_pSMLSource)
{
for(int f=0; f<m_pSMLSource->m_LightFrustums.Count(); f++)
{
if(m_pSMLSource->m_LightFrustums[f].depth_tex_id)
{
// shadow maps can be deleted only on smaps pool destruction
// GetRenderer()->RemoveTexture(m_pSMLSource->m_LightFrustums[f].depth_tex_id);
m_pSMLSource->m_LightFrustums[f].depth_tex_id=0;
}
}
m_pSMLSource->m_LightFrustums.Reset();
}
delete m_pSMLSource;
m_pSMLSource = new ShadowMapLightSource;
memset(m_pSMLSource,0,sizeof(ShadowMapLightSource));
m_pSMLSource->fRadius = 500000;
m_pSMLSource->vSrcPos = GetNormalized(vSunPos)*10000;//0;
if(GetCVars()->e_shadow_maps)
PrepareShadowMaps(Vec3d(0,0,0), m_pSMLSource);
}

View File

@@ -0,0 +1,649 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: statobjshadow.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: shadow maps
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "StatObj.h"
#include "meshidx.h"
#include <IEdgeConnectivityBuilder.h> // IEdgeConnectivityBuilder
#include "StencilShadowConnectivity.h"
#include "IndoorVolumes.h"
#include "IndoorShadowVolumes.h"
#include "CRETriMeshShadow.h"
#include "3dengine.h"
ItShadowVolume * CStatObj::MakeConnectivityInfo(CIndexedMesh * pMesh, const Vec3d & vOrigin, CStatObj * pStatObj)
{
//if it doestn exists yet, create one
tShadowVolume * ptSvObj = new tShadowVolume;
ptSvObj->pSvObj = new CShadowVolObject( );
for (int i=0; i<pMesh->m_nFaceCount; i++)
{
CObjFace *cf=&pMesh->m_pFaces[i];
for (int v=0; v<3; v++)
{
cf->m_Vecs[v].x=pMesh->m_pVerts[pMesh->m_pFaces[i].v[v]].x;
cf->m_Vecs[v].y=pMesh->m_pVerts[pMesh->m_pFaces[i].v[v]].y;
cf->m_Vecs[v].z=pMesh->m_pVerts[pMesh->m_pFaces[i].v[v]].z;
} //v
//calc plane equation
cf->m_Plane.CalcPlane(cf->m_Vecs[2],cf->m_Vecs[1],cf->m_Vecs[0]);
} //i
//set the same light area geometry
tContainer tCont;
tCont.pObj = pStatObj;
tCont.pSV=NULL;
//ptSvObj->pSvObj->AddGeometry(this);
ptSvObj->pSvObj->AddGeometry(tCont);
//mark the geometry as shared
ptSvObj->pSvObj->m_dwFlags|=FLAG_GEOMETRY_SHARED;
//set the position of the shadow volumes
ptSvObj->pSvObj->SetPos(/*pParams->*/vOrigin);
//precalc edges
if(!ptSvObj->pSvObj->CreateConnectivityInfo())
{ // delete empty objects
ptSvObj->Release();
ptSvObj=NULL;
}
//assign to the istatobj
return (ptSvObj);
}
ItShadowVolume * CStatObj::MakeConnectivityInfoFromCompiledData(void * pStream, int & nPos, CStatObj * pStatObj)
{
//if it doestn exists yet, create one
tShadowVolume * ptSvObj = new tShadowVolume;
ptSvObj->pSvObj = new CShadowVolObject( );
tContainer tCont;
tCont.pObj = pStatObj;
tCont.pSV=NULL;
//ptSvObj->pSvObj->AddGeometry(this);
ptSvObj->pSvObj->AddGeometry(tCont);
//mark the geometry as shared
ptSvObj->pSvObj->m_dwFlags|=FLAG_GEOMETRY_SHARED;
//set the position of the shadow volumes
ptSvObj->pSvObj->SetPos(Vec3d(0,0,0));
IEdgeConnectivityBuilder * iBuilder = Get3DEngine()->GetNewConnectivityBuilder();
ptSvObj->pSvObj->GetEdgeConnectivity() = iBuilder->ConstructConnectivity();
nPos += ptSvObj->pSvObj->GetEdgeConnectivity()->Serialize(false,&((byte*)pStream)[nPos],1000000, NULL);//GetLog());
return (ptSvObj);
}
// NOTE: Current implementation doesn't take the limit LOD parameter into account
void CStatObj::RenderShadowVolumes(const SRendParams *pParams, int nLimitLod)
{
// assert(pParams->lSource);
CDLight tTempLight;
tTempLight = *(pParams->pShadowVolumeLightSource);
Matrix44 tInvRot;
if(pParams->pMatrix)
{
tInvRot=*pParams->pMatrix;
}
else
{
//tInvRot.Identity();
//tInvRot=GetTranslationMat(pParams->vPos)*tInvRot;
//tInvRot=GetRotationZYX44(-pParams->vAngles*gf_DEGTORAD)*tInvRot; //NOTE: angles in radians and negated
//OPTIMISED_BY_IVO
tInvRot = Matrix34::CreateRotationXYZ(pParams->vAngles*gf_DEGTORAD, pParams->vPos ); //set scaling and translation in one function call
tInvRot = GetTransposed44(tInvRot); //TODO: remove this after E3 and use Matrix34 instead of Matrix44
}
tInvRot.Invert44();
Vec3d vPos=tInvRot.TransformPointOLD(tTempLight.m_Origin);
tTempLight.m_vObjectSpacePos=vPos;
/*
{
char str[256];
snprintf(str,"'%s' %p (%.2f %.2f %.2f) (%.2f %.2f %.2f)\n",pParams->lSource->m_Name,this,
tTempLight.m_Origin.x,tTempLight.m_Origin.y,tTempLight.m_Origin.z,
vPos.x,vPos.y,vPos.z);
OutputDebugString(str);
}
*/
//FIXME: move this code in the conn. info calculation
//assign vertices and calc planes
CIndexedMesh *pMesh = GetTriData();
if (!GetShadowVolume())
{
if(pMesh)
{
SetShadowVolume(CStatObj::MakeConnectivityInfo(pMesh, Vec3d(0,0,0)/* pParams->vOrigin*/, this));
FreeTriData(); // source geometry is needed only for stencil shadows
}
else
return;
}
ItShadowVolume *ptSvObj=GetShadowVolume();
CShadowVolObject *pSvObj=ptSvObj->GetShadowVolume();
IStencilShadowConnectivity* pConnectivity = pSvObj->GetEdgeConnectivity();
if(!pParams->pShadowVolumeLightSource || !pConnectivity)
return;
if (/*!pSvObj->GetNumFaces() && */!pConnectivity->IsStandalone())
return;
if(!m_bOpenEdgesTested && pConnectivity->numOrphanEdges())
{
#if !defined(LINUX)
Warning(0,m_szFileName,"%d open edges found during shadow volume calculations for %s %s",
pConnectivity->numOrphanEdges(), m_szFileName, m_szGeomName );
#endif
m_bOpenEdgesTested = true;
}
//GetRenderer()->Draw3dBBox(Vec3d(vPos.x-0.5f,vPos.y-0.5f,vPos.z-0.5f),Vec3d(vPos.x+0.5f,vPos.y+0.5f,vPos.z+0.5f));
////////////////////////////////////////////////////////////////////////
//this will be done in RE right before rendering
//pSvObj->CalculateDynamicShadowVolume(tTempLight);
//pSvObj->CreateDynamicShadowVolumeBuffer();
if(!pSvObj->m_pReMeshShadow)
pSvObj->m_pReMeshShadow = (CRETriMeshShadow *)GetRenderer()->EF_CreateRE(eDATA_TriMeshShadow);
// draw shadow volumes
if(pSvObj->m_pReMeshShadow)
{
// get the object
CCObject *pObj;
pObj = GetRenderer()->EF_GetObject(true);
pObj->m_DynLMMask = pParams->nDLightMask;
/* if(!m_nRenderStackLevel)
{
pObj->m_nScissorX1 = pParams->nScissorX1;
pObj->m_nScissorY1 = pParams->nScissorY1;
pObj->m_nScissorX2 = pParams->nScissorX2;
pObj->m_nScissorY2 = pParams->nScissorY2;
}*/
// the translation is in the object, otherwise we get z-fighting
// with the shaders
// hh unused pSvObj->m_pReMeshShadow->m_vOrigin = Vec3d(0,0,0);
if (pParams->pMatrix)
pObj->m_Matrix = *pParams->pMatrix;
else
mathCalcMatrix(pObj->m_Matrix, pParams->vPos, pParams->vAngles, Vec3d(1,1,1), Cry3DEngineBase::m_CpuFlags);
pObj->m_ObjFlags |= FOB_TRANS_MASK;
//assign shadow volume resources
//allow the calculation to be done right before rendering
pSvObj->m_pReMeshShadow->m_pSvObj = ptSvObj;
pSvObj->m_pReMeshShadow->m_nCurrInst = -1;
pObj->m_CustomData = pParams->pCaller;
pObj->m_TempVars[0] = pParams->fShadowVolumeExtent;
IShader * pEff = ((C3DEngine*)Get3DEngine())->m_pSHStencil;
GetRenderer()->EF_AddEf(0, (CRendElement *)pSvObj->m_pReMeshShadow , pEff, NULL, pObj, -1, NULL, pParams->nSortValue);
}
}
CVolume::~CVolume()
{
for (ContainerListIt i=m_lstObjects.begin();i!=m_lstObjects.end();)
{
RemoveGeometry(NULL,i);
i=m_lstObjects.begin();
} //i
m_lstObjects.clear(); //for the sake of clarity
}
bool CShadowVolObject::CreateConnectivityInfo( void )
{
//IStatObj *ob=m_lstStatObjs[0]; assert(ob);
IStatObj *ob=m_lstObjects[0].pObj;
assert(ob);
CIndexedMesh *pMesh=ob->GetTriData();
if (!pMesh)
return false; // to prevent crash, this could be if the file versions are changing)
//list of faces is shared from statobj
CObjFace * pFaceList = pMesh->m_pFaces;
int nNumFaces=pMesh->m_nFaceCount;
Vec3d *pVert=pMesh->m_pVerts;
IEdgeConnectivityBuilder * iBuilder = Get3DEngine()->GetNewStaticConnectivityBuilder();
assert(iBuilder);
iBuilder->ReserveForTriangles(nNumFaces,pMesh->m_nVertCount);
for(int i=0;i<nNumFaces;i++)
{
CObjFace *cf = &pFaceList[i];
if(cf->m_dwFlags & FLAG_SKIP_SHADOWVOLUME)
continue;
// with welding
unsigned short a=cf->v[0],b=cf->v[1],c=cf->v[2];
iBuilder->AddTriangleWelded(a,b,c,pVert[a],pVert[b],pVert[c]);
}
m_pEdgeConnectivity=iBuilder->ConstructConnectivity();
DWORD dwVertCount=0,dwTriCount=0;
if(m_pEdgeConnectivity)
{
m_pEdgeConnectivity->GetStats(dwVertCount,dwTriCount);
/*
#ifdef _DEBUG
char str[256];
snprintf(str, sizeof(str), "StencilEdgeConnectivity Indoor Stats %p: %d/%d Vertices %d/%d Faces\n",m_pEdgeConnectivity,dwVertCount,pMesh->m_nVertCount,dwTriCount,nNumFaces);
OutputDebugString(str);
#endif*/
}
return dwVertCount && dwTriCount;
}
void CVolume::SetPos(const Vec3d &vPos)
{
m_vOrigin=vPos;
pe_params_pos par_pos;
par_pos.pos=vPos;
//for (iphysobjit i=m_lstPhysObjs.begin();i!=m_lstPhysObjs.end();i++)
for (ContainerListIt i=m_lstObjects.begin();i!=m_lstObjects.end();i++)
{
IPhysicalEntity *pEnt=(*i).pEnt;
if (pEnt)
pEnt->SetParams(&par_pos);
} //i
}
void CVolume::AddGeometry(tContainer tCont)
{
m_vMins.CheckMin(tCont.pObj->GetBoxMin());
m_vMaxs.CheckMax(tCont.pObj->GetBoxMax());
/*
m_lstStatObjs.push_back(pSource);
if (pEnt)
m_lstPhysObjs.push_back(pEnt);
*/
m_lstObjects.push_back(tCont);
m_nObjCount++;
}
CShadowVolObject::~CShadowVolObject()
{
/* //do not delete 'cause the source is a cstatobj
if (m_pFaceList)
{
delete [] m_pFaceList;
m_pFaceList=NULL;
}
*/
if(m_pEdgeConnectivity)
{
m_pEdgeConnectivity->Release();
m_pEdgeConnectivity=0;
}
FreeVertexBuffers();
}
void CShadowVolObject::FreeVertexBuffers()
{
if (m_pSystemVertexBuffer)
{
delete [] m_pSystemVertexBuffer;
m_pSystemVertexBuffer=0;
}
if (m_pReMeshShadow)
{
m_pReMeshShadow->Release();
m_pReMeshShadow=NULL;
}
/*if (m_pReMeshAdditionalShadow)
{
//FIXME:Move deallocation into renderelements
if (m_pReMeshAdditionalShadow->m_pShadowVolEdgesList)
{
//those edges are shared!
//delete [] m_pReMeshAdditionalShadow->m_pShadowVolEdgesList;
m_pReMeshAdditionalShadow->m_pShadowVolEdgesList=NULL;
}
m_pReMeshAdditionalShadow->Release();
m_pReMeshAdditionalShadow=NULL;
}*/
m_nNumVertices=0;
}
void CShadowVolObject::CheckUnload()
{
if(m_pReMeshShadow)
m_pReMeshShadow->mfCheckUnload();
}
void CShadowVolObject::RebuildShadowVolumeBuffer( const CDLight &lSource, float fReadyShadowVolumeExtent ) // lSource has to be object relative
{
#ifdef WIN64
#pragma warning( push ) //AMD Port
#pragma warning( disable : 4311 )
#endif
#ifdef WIN64
#pragma warning( pop ) //AMD Port
#endif
if(!m_pEdgeConnectivity || (/*!m_nNumFaces && */!m_pEdgeConnectivity->IsStandalone()))
{
// PrepareShadowVolumeVertexBuffer(0,0);
return;
}
//! M.M. for debugging stencil shadows (0 is default, use !=0 to force reacalculation of indoor stencil shadow volumes)
IEdgeDetector * iEdgeDetector = Get3DEngine()->GetEdgeDetector();
Vec3d vObjectSpaceLight=lSource.m_vObjectSpacePos;
Vec3d vWorldSpaceLight=lSource.m_Origin;
// baustelle
IStatObj *ob=m_lstObjects[0].pObj;
CIndexedMesh *pMesh=ob->GetTriData();
assert(m_pEdgeConnectivity->IsStandalone());
if (m_pEdgeConnectivity->IsStandalone())
{
iEdgeDetector->BuildSilhuetteFromPos(m_pEdgeConnectivity, vObjectSpaceLight, NULL);
}
/*else
{
unsigned *pTriOriBitfield=iEdgeDetector->getOrientationBitfield(m_nNumFaces);
for(int nFace = 0; nFace < m_nNumFaces;)
{
unsigned nOrientBit = 1;
do
{
CObjFace *cf=&m_pFaceList[nFace];
if (cf->m_dwFlags & FLAG_SKIP_SHADOWVOLUME)//! transparent surfaces don't cast shadows
{
nFace++;
continue;
}
float dist1=cf->m_Plane.DistFromPlane(vObjectSpaceLight);
if(dist1>0)
*pTriOriBitfield |= nOrientBit;
nOrientBit <<= 1;
}
while (((++nFace) < m_nNumFaces) && (nOrientBit) != 0);
++pTriOriBitfield;
}
if(!pMesh)
return; // to prevent crash, this could be if the file versions are changing
iEdgeDetector->BuildSilhuetteFromBitfield(m_pEdgeConnectivity,pMesh->m_pVerts);
}*/
unsigned nNumIndices = iEdgeDetector->numShadowVolumeIndices();
unsigned nNumVertices = iEdgeDetector->numShadowVolumeVertices();
// float fShadowVolumeExtent=20.0f;
/*
// [5/12/2002] Marco's NOTE: removed this part, because to allow shadows to cross
// portals, we should not check for the object being inside/outside the
// area / so the check is now unified like for outdoors
// extend as little as possible to save fill rate M.M. *********************************************************************** Start
// I have to be in indoor otherwise shadow volumes doesn't make sense
// to prevent crash, but this should never be - without this info I assume a big value would do it
if(inpArea)
{
Vec3d vMinObjBBox=GetBBoxMin(true),vMaxObjBBox=GetBBoxMax(true);
// debugging
// GetRenderer()->Draw3dBBox(vMinObjBBox,vMaxObjBBox);
// if the lightsource is inside the object, use big value
// - it's dangerous to extrude too much (althougth extrude to infinity is theoretical possible)
// calculate the minimum extrusion level (to get the object bounding box extruded outside of the room)
fShadowVolumeExtent = inpArea->CalculateMinimumShadowExtrusion(vWorldSpaceLight,vMinObjBBox,vMaxObjBBox);
// assert(fShadowVolumeExtent>=1.0f);
}
else
*/
{
// calculate optimal extent for outdoor entity
// todo take into account object scale
//Vec3d vMinObjBBox=GetBBoxMin(true),vMaxObjBBox=GetBBoxMax(true);
/* Vec3d vMinObjBBox=GetBBoxMin(),vMaxObjBBox=GetBBoxMax();
Vec3d vObjCenter = (vMinObjBBox+vMaxObjBBox)*0.5;
float fObjRadius = (vMaxObjBBox-vMinObjBBox).Length()*0.5f;
float fObjLightDist = GetDistance(vObjectSpaceLight, vObjCenter) - fObjRadius;
if(fObjLightDist<0.01f)
fObjLightDist=0.01f;
fShadowVolumeExtent = lSource.m_fRadius/fObjLightDist;
if(fShadowVolumeExtent<1.f)
fShadowVolumeExtent=1.f;
else if(fShadowVolumeExtent>20.f)
fShadowVolumeExtent=20.f;*/
}
// extend as little as possible to save fill rate M.M. *********************************************************************** End
PrepareShadowVolumeVertexBuffer(nNumIndices, nNumVertices);
if (nNumVertices > 1 && nNumIndices > 1)
{
// m_arrIndices.reinit(n)
iEdgeDetector->meshShadowVolume (vObjectSpaceLight, fReadyShadowVolumeExtent, (Vec3d *)m_pSystemVertexBuffer, &m_arrIndices[0]);
CRETriMeshShadow::ShadVolInstanceInfo * pSVI = &m_pReMeshShadow->m_arrLBuffers[m_pReMeshShadow->m_nCurrInst];
if( pSVI->pVB && pSVI->pVB->m_SecVertCount == (int)m_nNumVertices &&
pSVI->pVB->m_Indices.m_nItems == (int)nNumIndices )
{
pSVI->pVB->UpdateSysIndices(nNumIndices ? &m_arrIndices[0] : 0, nNumIndices);
pSVI->pVB->UpdateSysVertices(m_pSystemVertexBuffer,m_nNumVertices);
}
else
{
if(pSVI->pVB)
GetRenderer()->DeleteLeafBuffer(pSVI->pVB);
// hack: todo: make m_arrIndices list2
pSVI->pVB = GetRenderer()->CreateLeafBufferInitialized(
m_pSystemVertexBuffer, m_nNumVertices, VERTEX_FORMAT_P3F,
&m_arrIndices[0], nNumIndices, R_PRIMV_TRIANGLES, "ShadowVolume", eBT_Dynamic, 1 , 0, 0, this);
assert(m_nNumVertices && nNumIndices);
pSVI->pVB->SetChunk(0,0,m_nNumVertices,0,nNumIndices);
assert((*(pSVI->pVB)).m_pMats->Count());
}
/*
if(!pSVI->pVB)
pSVI->pVB = GetRenderer()->CreateBuffer(m_nNumVertices, VERTEX_FORMAT_P3F,
&pSVI->plstIndices->GetAt(0), pSVI->plstIndices->Count(), "InstanceShadowVolume");
GetRenderer()->UpdateBuffer(pSVI->pVB, m_pSystemVertexBuffer, m_nNumVertices,true);
GetRenderer()->UpdateIndices(pSVI->pVB, &m_arrIndices[0], m_arrIndices.size());
*/
/*
#ifdef _DEBUG
{
for (unsigned i = 0; i < nNumIndices; ++i)
assert(m_arrIndices[i] < nNumVertices);
}
#endif
*/
/*
m_pReMeshShadow->m_vOrigin=rParams->vPos;
m_pReMeshShadow->m_vAngles=rParams->vAngles;
//get the effect object from the renderer
CCObject *pObj = renderer->EF_GetObject(true);
pObj->m_Trans = rParams->vPos;
pObj->m_Angs = rParams->vAngles;
pObj->m_Scale = 1.0f;
m_pReMeshShadow->m_nNumIndices = nNumIndices;
m_pReMeshShadow->mfCheckUpdate();
//renderer->UpdateBuffer (m_pRenShadowVolumeBuffer, m_pMemShadowVolumeBuffer, nNumVertices, true, 0);
renderer->UpdateBuffer(m_pRenShadowVolumeLBuffer->m_pVertexBuffer,m_pMemShadowVolumeBuffer,nNumVertices,true);
renderer->UpdateIndices(m_pRenShadowVolumeLBuffer->m_pVertexBuffer,&m_arrIndices[0],nNumIndices);
renderer->EF_AddEf(0, (CRendElement *)m_pReMeshShadow , rParams->pEff, pObj, -1, NULL, rParams->nSortValue);
*/
// m_pReMeshShadow->m_nNumIndices = nNumIndices;
// m_pReMeshShadow->mfCheckUpdate(0); // call before update, to make sure video buffer is there
// assert(m_pRenShadowVolumeLBuffer);
// assert(m_pRenShadowVolumeLBuffer->m_pVertexBuffer);
// GetRenderer()->UpdateBuffer(m_pRenShadowVolumeLBuffer->m_pVertexBuffer,pSystemBuffer,nNumVertices,true);
// GetRenderer()->UpdateIndices(m_pRenShadowVolumeLBuffer->m_pVertexBuffer,&m_arrIndices[0],nNumIndices);
// m_pRenShadowVolumeLBuffer->m_UpdateVBufferMask &= ~1;
}
else
{
int i=0;
}
}
void CVolume::RemoveGeometry(IStatObj *pSource,ContainerListIt it/* =NULL */)
{
ContainerListIt i = m_lstObjects.end();
if (it!=m_lstObjects.end())
i=it;
else
{
for (ContainerListIt it2=m_lstObjects.begin();it2!=m_lstObjects.end();it2++)
{
tContainer tempCont=(*it2);
if (tempCont.pObj==pSource)
{
i=it2;
break;
}
} //it2
}
if (i!=m_lstObjects.end())
{
tContainer tempCont=(*i);
IStatObj *pSource=tempCont.pObj;
if (pSource && (!(m_dwFlags & FLAG_GEOMETRY_SHARED)))
Get3DEngine()->ReleaseObject(pSource);
IPhysicalEntity *pEnt=(tempCont.pEnt);
if (pEnt)
GetPhysicalWorld()->DestroyPhysicalEntity(pEnt);
m_lstObjects.erase(i);
}
}
// Prepare the resources for rendering shadow volumes
// This include:
// index and vertex in-memory arrays
// render object (m_pReMeshShadow, m_pRenShadowVolumeBuffer, whatever support they need)
void CShadowVolObject::PrepareShadowVolumeVertexBuffer( unsigned nNumIndices, unsigned nNumVertices )
{
if (!nNumIndices || !nNumVertices)
return;
bool bRecreate = false;
// Realloc index in-mem buffer
if (m_arrIndices.size() < nNumIndices)
{
m_arrIndices.reinit(nNumIndices);
bRecreate = true;
}
// Realloc vertex in-mem buffer
if (m_nNumVertices < nNumVertices)
{
m_nNumVertices = nNumVertices;
bRecreate = true;
}
if (bRecreate)
{
if (m_pSystemVertexBuffer)
{
delete [] m_pSystemVertexBuffer;
m_pSystemVertexBuffer=NULL;
}
}
assert(m_pReMeshShadow); // should be called from inside this object
// m_pReMeshShadow = (CRETriMeshShadow *)GetRenderer()->EF_CreateRE(eDATA_TriMeshShadow);
if(!m_pSystemVertexBuffer)
{
assert(m_nNumVertices);
m_pSystemVertexBuffer = new Vec3d[m_nNumVertices];
assert(m_pSystemVertexBuffer);
}
}

View File

@@ -0,0 +1,211 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: statobjconstr.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: loading
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "StatObj.h"
#include "MeshIdx.h"
#include "../RenderDll/Common/shadow_renderer.h"
#include <irenderer.h>
#include <CrySizer.h>
void CStatObj::StreamOnProgress (IReadStream* pStream)
{
}
void CStatObj::ProcessStreamOnCompleteError()
{ // file was not loaded successfully
m_eCCGFStreamingStatus = ecss_NotLoaded;
// try to rebuild compiled file if not tryed yet
/* if(!m_bCompilingNotAllowed)
{
char szCompiledFileName[MAX_PATH_LENGTH];
MakeCompiledFileName(szCompiledFileName,MAX_PATH_LENGTH);
bool bCompRes = CompileObject(szCompiledFileName, m_szFileName, m_szGeomName,
m_eVertsSharing, m_bLoadAdditinalInfo, m_bKeepInLocalSpace);
// load new compiled file
if(bCompRes)
{
m_bCompilingNotAllowed=1;
StreamCCGF(true);
m_bCompilingNotAllowed=0;
}
if(m_eCCGFStreamingStatus == ecss_Ready)
return; // success
}
else if(strstr(m_szFileName,"Objects\\default.cgf"))
GetSystem()->Error("Error loading default object");
// still error - make nice default object
m_eCCGFStreamingStatus = ecss_NotLoaded;
Load("Objects\\default.cgf","",evs_NoSharing,false,false,false,false);
assert( m_eCCGFStreamingStatus == ecss_Ready);
m_bDefaultObject=true;*/
assert(0);
GetSystem()->Error("Error loading CCGF for: %s", m_szFileName);
}
void CStatObj::StreamOnComplete(IReadStream* pStream, unsigned nError)
{
m_pReadStream = 0;
if(pStream->IsError())
{ // file was not loaded successfully
ProcessStreamOnCompleteError();
return;
}
// load header
CCGFHeader * pFileHeader = (CCGFHeader *)pStream->GetBuffer();
#if !defined(LINUX)
assert(pFileHeader->nDataSize == pStream->GetBytesRead()-sizeof(CCGFHeader));
#endif
if(!pFileHeader->nDataSize)
{ // should happend only in case of sync loading
assert(m_szGeomName[0]);
m_eCCGFStreamingStatus = ecss_GeomNotFound;
return; // geom name was specified but not found in source sgf during compilation
}
int nChecksum = CCGFHeader::GetStructuresCheckSummm();
if(pFileHeader->nStructuresCheckSummm != nChecksum)
{
m_eCCGFStreamingStatus = ecss_LoadingError;
GetConsole()->Exit("Error: CStatObj::StreamOnComplete: version of " RC_EXECUTABLE " is not compatible with engine: %s", m_szFileName);
return; // geom name was specified but not found in source sgf during compilation
}
// load data
uchar * pData = ((uchar *)pStream->GetBuffer()+sizeof(CCGFHeader));
int nPos=0;
Serialize(nPos, pData, false, m_szFolderName);
assert(nPos == pFileHeader->nDataSize);
// original tris count
m_nLoadedTrisCount = pFileHeader->nFacesInCGFNum;
assert(m_nLoadedTrisCount);
m_bPhysicsExistInCompiledFile = (pFileHeader->dwFlags & CCGFHF_PHYSICS_EXIST);
// get bbox
m_vBoxMin = pFileHeader->vBoxMin;
m_vBoxMax = pFileHeader->vBoxMax;
CalcRadiuses();
PhysicalizeCompiled();
m_eCCGFStreamingStatus = ecss_Ready;
if(GetCVars()->e_stream_cgf)
GetLog()->Log("CStatObj::StreamOnComplete: %s", m_szFileName);
}
void CStatObj::StreamCCGF(bool bFinishNow)
{
// if(strstr(m_szFileName,"de_bind.cgf"))
// int t=0;
if(m_eCCGFStreamingStatus != ecss_NotLoaded)
return;
char szCompiledFileName[MAX_PATH_LENGTH];
MakeCompiledFileName(szCompiledFileName,MAX_PATH_LENGTH);
if(bFinishNow)
GetLog()->UpdateLoadingScreen("\003Load compiled object: %s", szCompiledFileName);
else
GetLog()->UpdateLoadingScreen("\003Start streaming compiled object: %s", szCompiledFileName);
// start streaming
StreamReadParams params;
params.dwUserData = 0;
params.nSize = 0;
params.pBuffer = NULL;
params.nLoadTime = 10000;
params.nMaxLoadTime = 10000;
params.nFlags |= SRP_FLAGS_ASYNC_PROGRESS;
m_eCCGFStreamingStatus = ecss_LoadingInProgress;
m_pReadStream = m_pSys->GetStreamEngine()->StartRead("3DEngine", szCompiledFileName, this, &params);
if(bFinishNow)
m_pReadStream->Wait();
}
void CStatObj::CheckLoaded()
{
if(!m_bUseStreaming)
return;
m_nMarkedForStreamingFrameId = GetFrameID()+100;
if(m_eCCGFStreamingStatus == ecss_NotLoaded)
{ // load now
assert(m_bUseStreaming == true);
m_fStreamingTimePerFrame -= GetTimer()->GetAsyncCurTime();
bool bRes = Load(m_szFileName, m_szGeomName[0] ? m_szGeomName : 0, m_eVertsSharing,
m_bLoadAdditinalInfo, m_bKeepInLocalSpace, false, m_bMakePhysics);
m_bUseStreaming = true;
m_fStreamingTimePerFrame += GetTimer()->GetAsyncCurTime();
}
else if(m_eCCGFStreamingStatus == ecss_LoadingInProgress)
{ // finish now
m_pReadStream->Wait();
}
else
{ // object is ready
assert(m_eCCGFStreamingStatus == ecss_Ready);
assert(m_pLeafBuffer && m_nLoadedTrisCount);
}
}
#ifdef WIN64
#pragma warning( push ) //AMD Port
#pragma warning( disable : 4267 )
#endif
void CStatObj::MakeCompiledFileName(char * szCompiledFileName, int nMaxLen)
{
// make ccgf name
char szFileNameNoExt[512]="";
strcpy(szFileNameNoExt,m_szFileName);
// remove extension
for(int i=strlen(szFileNameNoExt)-1; i>0; i--) if(szFileNameNoExt[i]=='.')
{ szFileNameNoExt[i]=0; break; }
// replace slashes in geom name
char szGeomName[sizeof(m_szGeomName)]="";
strncpy(szGeomName,m_szGeomName,sizeof(szGeomName));
int nLen = strlen(szGeomName);
for(int i=0; i<nLen; i++)
if (szGeomName[i]=='/' || szGeomName[i]=='\\')
szGeomName[i] = '_';
_snprintf(szCompiledFileName, nMaxLen,
"%s\\%s_%s_%d_%d_%d.ccgf",
CCGF_CACHE_DIR_NAME, szFileNameNoExt, szGeomName,
int(m_eVertsSharing == evs_ShareAndSortForCache), (int)m_bLoadAdditinalInfo, (int)m_bKeepInLocalSpace);
}
#ifdef WIN64
#pragma warning( pop ) //AMD Port
#endif

19
Cry3DEngine/StdAfx.cpp Normal file
View File

@@ -0,0 +1,19 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: stdafx.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: Description: source file that includes just the standard includes
// Cry3DEngine.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"

214
Cry3DEngine/StdAfx.h Normal file
View File

@@ -0,0 +1,214 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: stdafx.h
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_STDAFX_H__8B93AD4E_EE86_4127_9BED_37AC6D0F978B__INCLUDED_3DENGINE)
#define AFX_STDAFX_H__8B93AD4E_EE86_4127_9BED_37AC6D0F978B__INCLUDED_3DENGINE
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
//////////////////////////////////////////////////////////////////////////
// THIS MUST BE AT THE VERY BEGINING OF STDAFX.H FILE.
// Disable STL threading support, (makes STL faster)
//////////////////////////////////////////////////////////////////////////
#define _NOTHREADS
#define _STLP_NO_THREADS
//////////////////////////////////////////////////////////////////////////
#include <platform.h>
#ifdef GAMECUBE
#include "GCDefines.h"
#endif
// Insert your headers here
#ifndef GAMECUBE
#ifndef _XBOX
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <windows.h>
#endif
#else
#include <xtl.h>
#endif
#endif
#include <stdlib.h>
#include <stdio.h>
// enable memory pool usage
#ifndef GAMECUBE
#define USE_NEWPOOL
#include <CryMemoryManager.h>
#endif
#ifndef uchar
typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned short ushort;
#endif
#if !defined(LINUX)
#include <assert.h>
#endif
#include <vector>
#include <list>
#include <map>
#include <set>
#include <algorithm>
#if defined(PS2) || defined(GAMECUBE)
using std::min;
using std::max;
#endif
#ifndef __forceinline
#define __forceinline inline
#endif
#if !defined(min) && !defined(LINUX)
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
#define ZeroStruct( t ) { memset( &t,0,sizeof(t) ); }
#define MAX_PATH_LENGTH 512
#ifndef stricmp
inline int __cdecl stricmp(const char *dst, const char *src)
{
int f,l;
do
{
if ( ((f=(unsigned char)(*(dst++))) >= 'A') && (f<='Z'))
f -= ('A' - 'a');
if ( ((l=(unsigned char)(*(src++))) >= 'A') && (l<='Z'))
l -= ('A' - 'a');
} while ( f && (f == l) );
return(f - l);
}
#endif
#ifndef strnicmp
inline int __cdecl strnicmp (const char * first, const char * last, size_t count)
{
int f,l;
if ( count )
{
do
{
if ( ((f=(unsigned char)(*(first++))) >= 'A') && (f<='Z') )
f -= 'A' - 'a';
if ( ((l=(unsigned char)(*(last++))) >= 'A') && (l<='Z'))
l -= 'A' - 'a';
} while ( --count && f && (f == l) );
return( f - l );
}
return 0;
}
#endif
#include <ITimer.h>
#include <IProcess.h>
#include "Cry_Math.h"
#include "Cry_XOptimise.h"
#include <Cry_Camera.h>
#include <ILog.h>
#include <ISystem.h>
#include <IConsole.h>
#include <IPhysics.h>
#include <IRenderer.h>
#include <IEntityRenderState.h>
#include <I3DEngine.h>
#include <IGame.h>
#include <icryanimation.h>
#include <icrypak.h>
#include <CryFile.h>
class IPhysicalWorld;
struct IEntityRender;
#if defined(WIN32) && defined(_DEBUG)
#include <crtdbg.h>
#define DEBUG_NEW_NORMAL_CLIENTBLOCK(file, line) new(_NORMAL_BLOCK, file, line)
#define new DEBUG_NEW_NORMAL_CLIENTBLOCK( __FILE__, __LINE__)
// memman
#define calloc(s,t) _calloc_dbg(s, t, _NORMAL_BLOCK, __FILE__, __LINE__)
#define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)
#define realloc(p, s) _realloc_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__)
#endif // defined(WIN32) && defined(_DEBUG)
//#include <StlDbgAlloc.h>
#include "TArrays.h"
#include "Cry_Math.h"
#include "CryHeaders.h"
#include "Cry3DEngineBase.h"
#include "file.h"
#include <float.h>
#include "TArrays.h"
#include "list2.h"
#include "terrain.h"
#include "cvars.h"
#include "crysizer.h"
#include "StlUtils.h"
inline float L1Distance2D(const Vec3 &v0, const Vec3 &v1) { return max(Ffabs(v0.x-v1.x),Ffabs(v0.y-v1.y)); }
inline float GetDist2D(float x1, float y1, float x2, float y2)
{
float xm = (x1-x2);
float ym = (y1-y2);
return cry_sqrtf(xm*xm + ym*ym);
}
#if !defined(LINUX) //than it does already exist
inline int vsnprintf(char * buf, int size, const char * format, va_list & args)
{
int res = _vsnprintf(buf, size, format, args);
assert(res>=0 && res<size); // just to know if there was problems in past
buf[size-1]=0;
return res;
}
#endif
inline int snprintf(char * buf, int size, const char * format, ...)
{
va_list arglist;
va_start(arglist, format);
int res = vsnprintf(buf, size, format, arglist);
va_end(arglist);
return res;
}
#endif // !defined(AFX_STDAFX_H__8B93AD4E_EE86_4127_9BED_37AC6D0F978B__INCLUDED_3DENGINE)

View File

@@ -0,0 +1,805 @@
//////////////////////////////////////////////////////////////////////
//
// CryEngine Source code
//
// File:StencilShadowConnectivity.h
// Declaration of class CStencilShadowConnectivity
//
// History:
// -:Created by Sergiy Migdalskiy <sergiy@crytek.de>
// 08/30/2002 include .cpp in header files, move to CryCommon, use in Cry3DEngine (Martin Mittring)
//
//////////////////////////////////////////////////////////////////////
// class CStencilShadowConnectivity
//
// This is pre-computed data for a model that's gonna cast stencil
// shadows, and whose vertices may change position ****, but the topology
// cannot change.
//
// Ok, to put it clear: for each model, you need one instance of this
// class initialized once. The model is allowed to deform, but is not
// allowed to change topology (add or remove faces as well as re-assign
// face vertices or even change face orientation).
//
// NOTE: The class is optimized for use with manifold geometry.
// This means you have to provide a model with unified normals and non-
// exploded triangles.
//
//
// IMPLEMENTATION NOTES should be in
// StencilShadowConnectivity.cpp
//
#pragma once
#ifndef _STENCIL_SHADOW_CONNECTIVITY_HDR_
#define _STENCIL_SHADOW_CONNECTIVITY_HDR_
#include <IEdgeConnectivityBuilder.h> // IStencilShadowConnectivity
// the empty connectivity info:
class CStencilShadowConnectivityNull:public IStencilShadowConnectivity
{
public:
//! don't forget to call Release for freeing the memory resources
virtual void Release( void ) {delete this;}
//! to keep the interface small and the access fast
//! /return pointer to the internal memory representation (only used within module 3DEngine)
const virtual CStencilShadowConnectivity *GetInternalRepresentation( void ) const {return NULL;}
//! for debugging and profiling
//! /param outVertexCount
//! /param outTriangleCount
virtual void GetStats( DWORD &outVertexCount, DWORD &outTriangleCount ) {outVertexCount = outTriangleCount = 0;}
//! Memorize the vertex buffer in this connectivity object. This is needed if a static object doesn't need this info
virtual void SetVertices(const Vec3d* pVertices, unsigned numVertices) {assert(0);}
//! Serializes this object to the given memory block; if it's NULL, only returns
//! the number of bytes required. If it's not NULL, returns the number of bytes written
//! (0 means error, insufficient space)
virtual unsigned Serialize (bool bSave, void* pStream, unsigned nSize, IMiniLog* pWarningLog = NULL)
{
return 0;
}
//! Calculates the size of this object
virtual void GetMemoryUsage (ICrySizer* pSizer) {}
#ifdef WIN32
//! /param szFilename filename with path (or relative) and extension
//! /return true=success, false otherwise
virtual bool DebugConnectivityInfo( const char *szFilename ){}
#endif
};
#ifdef WIN64
#pragma warning( push ) //AMD Port
#pragma warning( disable : 4267 )
#endif
class CStencilShadowConnectivity : public IStencilShadowConnectivity
{
public:
//! number of vertices in the array referenced by the mesh
//! /return vertex count
unsigned numVertices() const
{
return m_numVertices;
}
//! number of edges in the array of edges
//! /return edge count
unsigned numEdges() const
{
return m_numEdges;
}
//! number of orphaned (open) edges
//! /return orphaned (open) count
virtual unsigned numOrphanEdges() const
{
return m_numOrphanEdges;
}
//! total number of faces
//! /return face count
unsigned numFaces ()const
{
return m_numFaces;
}
// -----------------
// This is the basic edge representation: two vertex indices.
// This is capable of being sorted.
struct BasicEdge
{
//! default constructor
BasicEdge () {}
//! constructor
//! /param nV0 start vertex index
//! /param nV1 end vertex index
BasicEdge (vindex nV0, vindex nV1)
{
m_nVertex[0] = nV0;
m_nVertex[1] = nV1;
}
//! start and end vertex index of the edge
vindex m_nVertex[2];
// alphabet sorting implementation
//! /param rEdge right side of the operator term
inline bool operator < (const BasicEdge& rEdge)const
{
if (m_nVertex[0] < rEdge.m_nVertex[0])
return true;
else
if (m_nVertex[0] == rEdge.m_nVertex[0])
return m_nVertex[1] < rEdge.m_nVertex[1];
else
return false;
}
//! get teh start or end vertex index
//! /param nIndex 0/1
inline unsigned operator [] (int nIndex)const
{
assert(nIndex==0 || nIndex==1);
return m_nVertex[nIndex];
}
//! copy the basic edge, designed for ancestors
//! /param beEdge
void setBasicEdge (const BasicEdge& beEdge)
{
m_nVertex[0] = beEdge.m_nVertex[0];
m_nVertex[1] = beEdge.m_nVertex[1];
}
};
// -----------------
// connection of the edge to the face: may contain, depending on the implementation,
// the face index, pointer to it, vertex, pointer to it
struct EdgeFace
{
//! default constructor
EdgeFace (){}
//! constructor
//! /param nFace face index
//! /param nVertex vertex index
EdgeFace (vindex nFace, vindex nVertex): m_nFace(nFace), m_nVertex(nVertex) {}
//! /return face index
inline vindex getFaceIndex ()const {return m_nFace;}
//! /return vertex index
inline vindex getVertexIndex() const {return m_nVertex;}
vindex m_nFace; //!< face index
vindex m_nVertex; //!< face vertex
};
// -----------------
// This is a primary connectivity edge data structure:
// the basic edge (start and end vertices, inherited from BasicEdge)
// and the opposite face edges
class Edge: public BasicEdge
{
//! this and opposite face 3rd vertex.
//! in "this" face, the edge goes CCW (natural) direction [0],
//! and in "opposite" face it goes CW (reverse) direction [1]
EdgeFace m_Face[2];
public:
//! default constructor
Edge () {}
//! constructor
//! /param be edge datastructure
//! /param ef0 in this triangle the edge goes CCW (natural) direction
//! /param ef1 in this triangle the edge goes CW (reverse) direction
Edge (const BasicEdge& be, const EdgeFace& ef0, const EdgeFace& ef1):
BasicEdge(be)
{
m_Face[0] = ef0;
m_Face[1] = ef1;
}
//! /param nFace 0/1
//! /return reference to the face data structure
const EdgeFace& getFace(int nFace) const
{
assert(nFace==0 || nFace==1);
return m_Face[nFace];
}
//! /param nFace 0/1
//! /param ef reference to the edge datastructure
void setFace (int nFace, const EdgeFace& ef)
{
assert(nFace==0 || nFace==1);
m_Face[nFace] = ef;
}
};
// -----------------
// orphan edge - an edge with only one face attached to it (boundary)
class OrphanEdge: public BasicEdge
{
EdgeFace m_Face; //!<
public:
//! default constructor
OrphanEdge () {}
// constructor
OrphanEdge (const BasicEdge& be, const EdgeFace& ef):
BasicEdge (be),
m_Face (ef)
{}
const EdgeFace& getFace()const {return m_Face;}
void setFace (const EdgeFace& ef) {m_Face = ef;}
};
// -----------------
// face - 3 vertices
class Face
{
public:
vindex m_nVertex[3]; //!<
//! default constructur
Face () {}
//! constructor
//! /param nV0 first vertex index
//! /param nV1 second vertex index
//! /param nV2 thired vertex index
Face (vindex nV0, vindex nV1, vindex nV2)
{
m_nVertex[0] = nV0;
m_nVertex[1] = nV1;
m_nVertex[2] = nV2;
}
//! get the index of one triangle vertex
//! /param nVtx 0/1/2
//! /return index of that triangle vertex
const vindex getVertex (int nVtx) const
{
assert(nVtx==0 || nVtx==1 || nVtx==2);
return m_nVertex[nVtx];
}
//! set the index of one triangle vertex
//! /param nVtx 0/1/2
//! /param nIndex index of the triangle vertex no <nVtx>
void setVertex (int nVtx, vindex nIndex)
{
assert(nVtx==0 || nVtx==1 || nVtx==2);
m_nVertex[nVtx] = nIndex;
}
};
// -----------------
//! /aparam nEdge 0..m_numEdges-1
//! /return the nEdge'th edge
const Edge& getEdge (int nEdge)const
{
assert(m_pEdges);
assert(nEdge>=0);
assert((unsigned)nEdge<m_numEdges);
return m_pEdges[nEdge];
}
// returns the nEdge's orphaned edge
//! /param nEdge 0..m_numOrphanEdges-1
//! /return
const OrphanEdge& getOrphanEdge(int nEdge)const
{
assert(m_pOrphanEdges);
assert(nEdge>=0);
assert((unsigned)nEdge<m_numOrphanEdges);
return m_pOrphanEdges[nEdge];
}
//! returns the nFace's face
//! /param 0..m_numFaces-1
//! /return reference to the face
const Face& getFace (int nFace) const
{
assert(m_pFaces);
assert(nFace>=0);
assert((unsigned)nFace<m_numFaces);
return m_pFaces[nFace];
}
// copies the array of referred faces into internal array
// this is specially optimized for faster cooperation with the Builder
// The number of faces is determined from the earlier given edges, so
// NOTE: becareful to call the SetOrphanEdges BEFORE THIS FUNCTION
// DO NOT call twice, this is only designed to be called once after construction
void SetFaces (const std::vector<Face>& arrFaces)
{
assert (!m_pFaces && m_numFaces <= arrFaces.size());
if (!arrFaces.empty())
{
m_pFaces = new Face[m_numFaces = arrFaces.size()];
for (unsigned i = 0; i < m_numFaces; ++i)
m_pFaces[i] = arrFaces[i];
}
}
// destruct the object (it's only constructed by the Builder)
// the virtual ensures that the function releases the object in the same module where it was allocated:
// because the VTable was also allocated in the same module
virtual void Release ()
{
assert(this);
// this is a counterpart to the new that's called within the
// CStencilShadowConnectivityBuilder::ConstructConnectivity() method
delete this;
}
const virtual CStencilShadowConnectivity *GetInternalRepresentation( void ) const
{
return(this);
}
// from IStencilShadowConnectivity
virtual bool DebugConnectivityInfo( const char *szFilename )
{
// used only for debugging
FILE *out=fopen(szFilename,"w");
if(!out)return(false);
fprintf(out,"%d Edges:\n",m_numEdges);
for(unsigned i=0;i<m_numEdges;i++)
{
fprintf(out," face={%d,%d}, vertex={%d,%d}\n",
(m_pEdges[i].getFace(0)).getFaceIndex(),
(m_pEdges[i].getFace(1)).getFaceIndex(),
m_pEdges[i].m_nVertex[0],
m_pEdges[i].m_nVertex[1]);
}
fprintf(out,"%d OrphanEdges:\n",m_numOrphanEdges);
for(unsigned i=0;i<m_numOrphanEdges;i++)
#if !defined(LINUX)
fprintf(out," face={%d}, vertex={%d,%d}\n",m_pOrphanEdges[i].getFace(),m_pOrphanEdges[i].m_nVertex[0],m_pOrphanEdges[i].m_nVertex[1]);
#else
fprintf(out,", vertex={%d,%d}\n",m_pOrphanEdges[i].m_nVertex[0],m_pOrphanEdges[i].m_nVertex[1]);//face info does not compile, no time to make it more correct here
#endif//LINUX
fprintf(out,"%d Vertices:\n",m_numVertices);
fprintf(out,"Faces:\n",m_numFaces);
for(unsigned i=0;i<m_numFaces;i++)
fprintf(out," vertex indices={%d,%d,%d}\n",m_pFaces[i].getVertex(0),m_pFaces[i].getVertex(1),m_pFaces[i].getVertex(2));
fclose(out);
return(true);
}
//! constructor, only makes an empty object that's good for deserializing only
CStencilShadowConnectivity ()
{
m_numEdges = m_numOrphanEdges = m_numVertices = m_numFaces = 0;
m_pOrphanEdges = NULL;
m_pFaces = NULL;
m_pEdges = NULL;
m_pPlanes = NULL;
m_pVertices = NULL;
}
struct Plane
{
Vec3d vNormal;
float fDistance;
Plane(){}
Plane (const Vec3d& v0, const Vec3d& v1, const Vec3d& v2)
{
vNormal = (v1-v0)^(v2-v0);
fDistance = (v0*vNormal);
}
float apply (const Vec3d& v)const
{
return vNormal * v - fDistance;
}
};
//! Calculates the size of this object
void GetMemoryUsage(ICrySizer* pSizer)
{
pSizer->AddObject(this,Serialize (true, NULL,0));
}
protected:
//! constructor is only called within 3DEngine
//! /param pEdges - array of nNumEdges edges
//! /param nNumEdges
CStencilShadowConnectivity( const std::vector<Edge>& arrEdges)
{
m_pOrphanEdges=NULL;
m_pFaces=NULL;
m_numOrphanEdges=0;
// find the max vertex index to put it into m_nVertices
m_numVertices = 0;
m_numFaces = 0;
for (std::vector<Edge>::const_iterator it = arrEdges.begin(); it != arrEdges.end(); ++it)
{
UseBasicEdge (*it);
UseEdgeFace (it->getFace(0));
UseEdgeFace (it->getFace(1));
}
m_numEdges = arrEdges.size();
if(m_numEdges)
{
m_pEdges = new Edge[m_numEdges];
for (unsigned i = 0; i < m_numEdges; ++i)
m_pEdges[i] = arrEdges[i];
}
else
m_pEdges=0;
m_pPlanes = NULL;
m_pVertices = NULL;
}
void SetPlanes (const Plane* pPlanes, unsigned numPlanes)
{
if (m_pPlanes)
delete [] m_pPlanes;
if (pPlanes)
{
assert (numPlanes >= m_numFaces);
m_pPlanes = new Plane[m_numFaces];
memcpy (m_pPlanes, pPlanes, sizeof(Plane) * m_numFaces);
}
else
m_pPlanes = NULL;
}
void SetVertices(const Vec3d* pVertices, unsigned numVertices)
{
if (m_pVertices)
delete[]m_pVertices;
if (pVertices)
{
assert (numVertices >= m_numVertices);
m_pVertices = new Vec3d[m_numVertices];
memcpy (m_pVertices, pVertices, sizeof(Vec3d)*m_numVertices);
}
else
m_pVertices = NULL;
}
// remaps all vertex indices and memorizes the passed "new" vertex array (in new indexation)
void SetRemapVertices (const vindex*pMap, unsigned numMapEntries, const Vec3d* pNewVertices, unsigned numNewVertices)
{
if (m_pVertices)
delete[]m_pVertices;
assert (pNewVertices);
// we collected information about the vertices before . The number of used vertices is in
// m_numVertices. We assume the passed new vertex map can not make this number larger, because
// its sole purpose is optimization of number of vertex indices used (for storing the vertex info inside)
assert (numNewVertices <= m_numVertices);
m_numVertices = numNewVertices;
m_pVertices = new Vec3d[numNewVertices];
memcpy (m_pVertices, pNewVertices, sizeof(Vec3d)*numNewVertices);
remapVertexIndices (pMap, numMapEntries);
}
// can be destructed only from within Release()
virtual ~CStencilShadowConnectivity(void)
{
if (m_pEdges) delete[] m_pEdges;
if (m_pOrphanEdges) delete[] m_pOrphanEdges;
if (m_pFaces) delete[] m_pFaces;
if (m_pPlanes) delete[] m_pPlanes;
if (m_pVertices) delete[] m_pVertices;
}
// makes sure that the given vertex index fits into the range 0..m_nVertices
// by expanding (increasing) m_nVertices
void UseVertex(vindex nVertex)
{
if (nVertex >= m_numVertices)
m_numVertices = nVertex + 1;
}
// makes sure that the given face index fits into the range 0..m_nFaces
// by expanding (increasing) m_nFaces
void UseFace (vindex nFace)
{
if (nFace >= m_numFaces)
m_numFaces = nFace + 1;
}
// copies the list of orphaned edges into internal array
// this is specially optimized for faster cooperation with the Builder
// DO NOT call twice, this is only designed to be called once after construction
typedef std::map<BasicEdge, EdgeFace> OrphanEdgeMap;
// copies the list of orphaned edges into internal array
// this is specially optimized for faster cooperation with the Builder
// DO NOT call twice, this is only designed to be called once after construction
void SetOrphanEdges (const OrphanEdgeMap& mapOrphanEdge)
{
m_numOrphanEdges = mapOrphanEdge.size();
m_pOrphanEdges = new OrphanEdge[m_numOrphanEdges];
OrphanEdge* pEdge = m_pOrphanEdges;
// copy the content of the orphan edge map into the array
for (OrphanEdgeMap::const_iterator it = mapOrphanEdge.begin(); it != mapOrphanEdge.end(); ++it)
{
pEdge->setBasicEdge (it->first);
pEdge->setFace (it->second);
UseBasicEdge (*pEdge);
UseEdgeFace (pEdge->getFace());
++pEdge;
}
}
// makes sure that the vertices/faces referenced by the edge are in account by the m_numFaces and m_numVertices
void UseBasicEdge (const BasicEdge& beEdge)
{
UseVertex(beEdge[0]);
UseVertex(beEdge[1]);
}
// makes sure that the vertices/faces referenced by the edge are in account by the m_numFaces and m_numVertices
void UseEdgeFace (const EdgeFace& efEdge)
{
UseFace (efEdge.getFaceIndex());
UseVertex(efEdge.getVertexIndex());
}
//! for debugging and profiling
//! /param outVertexCount
//! /param outTriangleCount
virtual void GetStats( DWORD &outVertexCount, DWORD &outTriangleCount )
{
outVertexCount=m_numVertices;
outTriangleCount=m_numFaces;
}
public:
// the version of the stream
enum {g_nSerialVersion = 2};
//! Deserializes this object. Returns the number of bytes read. 0 means error
//! pWarningLog is used to put warnings about deserialized connectivity
unsigned Deserialize (void *pStream, unsigned nSize, IMiniLog* pWarningLog = NULL)
{
unsigned* pHeader = (unsigned*)pStream;
if (nSize < 5 * sizeof(unsigned))
return 0; // we should have the header in place
if (*(pHeader++) != g_nSerialVersion) // version is incompatible
return 0;
m_numEdges = *(pHeader++);
m_numOrphanEdges = *(pHeader++);
m_numVertices = *(pHeader++);
m_numFaces = *(pHeader++);
unsigned numPlanes = *(pHeader++);
assert (numPlanes == 0 || numPlanes == m_numFaces);
unsigned numVertices = *(pHeader++);
assert (numVertices == 0 || numVertices == m_numVertices);
unsigned nRequiredSize =
sizeof(unsigned) +
sizeof(m_numEdges) + m_numEdges * sizeof(Edge) +
sizeof(m_numOrphanEdges) + m_numOrphanEdges * sizeof(OrphanEdge) +
sizeof(m_numVertices) +
sizeof(m_numFaces) + m_numFaces * sizeof(Face) +
sizeof(numPlanes) + numPlanes * sizeof(Plane)+
sizeof(numVertices) + numVertices * sizeof(Vec3d);
if(m_pEdges) delete[] m_pEdges;
if(m_pOrphanEdges) delete[] m_pOrphanEdges;
if(m_pFaces) delete[] m_pFaces;
if(m_pPlanes) delete[] m_pPlanes;
if (m_pVertices) delete []m_pVertices;
if (nSize < nRequiredSize)
{
m_pEdges = NULL;
m_pOrphanEdges = NULL;
m_pFaces = NULL;
m_numEdges = 0;
m_numOrphanEdges = 0;
m_numVertices = 0;
m_numFaces = 0;
// incompatible stream
return 0;
}
m_pEdges = new Edge [m_numEdges];
m_pOrphanEdges = new OrphanEdge [m_numOrphanEdges];
m_pFaces = new Face [m_numFaces];
m_pPlanes = numPlanes?new Plane[numPlanes]:NULL;
m_pVertices = numVertices?new Vec3d[numVertices]:NULL;
Edge* pEdgeData = (Edge*)pHeader;
memcpy (m_pEdges, pEdgeData, m_numEdges*sizeof(Edge));
OrphanEdge* pOrphanEdgeData = (OrphanEdge*)(pEdgeData + m_numEdges);
memcpy (m_pOrphanEdges, pOrphanEdgeData, m_numOrphanEdges*sizeof(OrphanEdge));
Face* pFaceData = (Face*)(pOrphanEdgeData + m_numOrphanEdges);
memcpy (m_pFaces, pFaceData, m_numFaces * sizeof(Face));
Plane* pPlanes = (Plane*)(pFaceData+m_numFaces);
if (numPlanes)
memcpy (m_pPlanes, pPlanes, numPlanes* sizeof(Plane));
Vec3d* pVertices = (Vec3d*)(pPlanes + numPlanes);
if (numVertices)
memcpy (m_pVertices, pVertices, sizeof(Vec3d)*numVertices);
#if !defined(LINUX)
if (m_numOrphanEdges && pWarningLog)
pWarningLog->LogWarning("Connectivity warning: there are %d open edges (%d closed, %d faces, %d planes, %d vertices)", m_numOrphanEdges, m_numEdges, m_numFaces, numPlanes, numVertices);
#endif
return nRequiredSize;
}
//! Serializes this object to the given memory block; if it's NULL, only returns
//! the number of bytes required. If it's not NULL, returns the number of bytes written
//! (0 means error, insufficient space)
unsigned Serialize (bool bSave, void* pStream, unsigned nSize, IMiniLog* pWarningLog = NULL)
{
if (!bSave)
return Deserialize (pStream, nSize, pWarningLog);
// calculate the required size of the buffer
unsigned
numPlanes = m_pPlanes?m_numFaces:0,
numVertices = m_pVertices?m_numVertices:0,
nRequiredSize =
sizeof(unsigned) +
sizeof(m_numEdges) + m_numEdges * sizeof(Edge) +
sizeof(m_numOrphanEdges) + m_numOrphanEdges * sizeof(OrphanEdge) +
sizeof(m_numVertices) +
sizeof(m_numFaces) + m_numFaces * sizeof(Face) +
sizeof(numPlanes) + numPlanes * sizeof(Plane)+
sizeof(numVertices) + numVertices * sizeof(Vec3d);
if (pStream)
{
if (nSize < nRequiredSize)
return 0; // insufficient space in the pStream buffer
unsigned* pHeader = (unsigned*)pStream;
*(pHeader++) = g_nSerialVersion; // version of the stream
*(pHeader++) = m_numEdges;
*(pHeader++) = m_numOrphanEdges;
*(pHeader++) = m_numVertices;
*(pHeader++) = m_numFaces;
*(pHeader++) = numPlanes;
*(pHeader++) = numVertices;
Edge* pEdgeData = (Edge*)pHeader;
memcpy (pEdgeData, m_pEdges, m_numEdges*sizeof(Edge));
OrphanEdge* pOrphanEdgeData = (OrphanEdge*)(pEdgeData + m_numEdges);
memcpy (pOrphanEdgeData, m_pOrphanEdges, m_numOrphanEdges*sizeof(OrphanEdge));
Face* pFaceData = (Face*)(pOrphanEdgeData + m_numOrphanEdges);
memcpy (pFaceData, m_pFaces, m_numFaces * sizeof(Face));
Plane* pPlanes = (Plane*)(pFaceData+m_numFaces);
if (m_pPlanes)
memcpy (pPlanes, m_pPlanes, numPlanes * sizeof(Plane));
Vec3d* pVertices = (Vec3d*)(pPlanes+numPlanes);
if (m_pVertices)
memcpy (pVertices, m_pVertices, numVertices * sizeof(Vec3d));
}
return nRequiredSize;
}
// the plane equation, x*n+d == 0
bool hasPlanes() const {return m_pPlanes != NULL;}
const Plane&getPlane (unsigned i)const {assert(i<m_numFaces && m_pPlanes);return m_pPlanes[i];}
const Vec3d* getVertices() const {return m_pVertices;}
bool IsStandalone() const {return m_pPlanes != NULL && m_pVertices!= NULL;}
void remapVertexIndices(const vindex*pMap, unsigned nMapSize)
{
unsigned i;
#define REMAP(X) assert((X) < nMapSize);\
(X) = pMap[X];\
assert ((vindex)(X) != (vindex)-1 && (X) < m_numVertices)
for(i=0;i<m_numEdges;i++)
{
REMAP(m_pEdges[i].m_nVertex[0]);
REMAP(m_pEdges[i].m_nVertex[1]);
}
for(i=0;i<m_numOrphanEdges;i++)
{
REMAP(m_pOrphanEdges[i].m_nVertex[0]);
REMAP(m_pOrphanEdges[i].m_nVertex[1]);
}
for(i=0;i<m_numFaces;i++)
{
REMAP(m_pFaces[i].m_nVertex[0]);
REMAP(m_pFaces[i].m_nVertex[1]);
REMAP(m_pFaces[i].m_nVertex[2]);
}
#undef REMAP
}
private:
friend class CStencilShadowConnectivityBuilder;
friend class CStencilShadowStaticConnectivityBuilder;
// the array of normal edges (with two adjacent faces)
unsigned m_numEdges; //!<
Edge* m_pEdges; //!<
// the array of orphaned edges (with only one face attached)
unsigned m_numOrphanEdges; //!<
OrphanEdge* m_pOrphanEdges; //!<
private:
// number of vertices in the array referenced by the mesh
unsigned m_numVertices; //!<
// the faces
unsigned m_numFaces; //!< number of faces in the array referenced by the mesh
Face* m_pFaces; //!<
Plane* m_pPlanes; //!< if not NULL, then use these normals instead of computing them on the fly; 1 face - 1 normal
Vec3d* m_pVertices;
};
#ifdef WIN64
#pragma warning( pop ) //AMD Port
#endif
#endif // _STENCIL_SHADOW_CONNECTIVITY_HDR_

View File

@@ -0,0 +1,279 @@
#include "stdafx.h" // precompiled header
#include "StencilShadowConnectivity.h"
#include "StencilShadowConnectivityBuilder.h"
#ifdef WIN64
#pragma warning( push ) //AMD Port
#pragma warning( disable : 4267 )
#endif
// creates an empty mesh connectivity
CStencilShadowConnectivityBuilder::CStencilShadowConnectivityBuilder( void )
#ifdef DEBUG_STD_CONTAINERS
:m_mapSingleEdges("CStencilShadowConnectivityBuilder.SingleEdges")
,m_vDoubleEdges ("CStencilShadowConnectivityBuilder.DoubleEdges")
,m_vFaces("CStencilShadowConnectivityBuilder.Faces")
,m_mVertexWelder("CStencilShadowConnectivityBuilder.VertexWelder")
#endif
{
Reinit();
}
CStencilShadowConnectivityBuilder::~CStencilShadowConnectivityBuilder( void )
{
}
void CStencilShadowConnectivityBuilder::Reinit( void )
{
m_mapSingleEdges.clear();
m_vDoubleEdges.clear();
m_vFaces.clear();
m_mVertexWelder.clear();
m_dwNumUncompressedVertices=0;
// m_fWeldTolerance = 0;
}
///////////////////////////////////////////////////////////////////////////////////
// adds a single triangle to the mesh
// the tirangle is defined by three vertices, in counter-clockwise order
// these vertex indices will be used later when accessing the array of
// deformed character/model vertices to determine the shadow volume boundary
///////////////////////////////////////////////////////////////////////////////////
void CStencilShadowConnectivityBuilder::AddTriangle( unsigned short nV0, unsigned short nV1, unsigned short nV2 )
{
unsigned nNumFaces = m_vFaces.size();
AddNewEdge (BasicEdge(nV0, nV1), EdgeFace(nNumFaces, nV2));
AddNewEdge (BasicEdge(nV1, nV2), EdgeFace(nNumFaces, nV0));
AddNewEdge (BasicEdge(nV2, nV0), EdgeFace(nNumFaces, nV1));
m_vFaces.push_back(Face (nV0, nV1, nV2));
}
// this will try to find a close match to the given vertex, and
// if found, return its index (the actual index of the vertex that's very close or
// coincide with v in space). Otherwise, creates a new vertex reference in the map
// and returns the index nNewVertex
unsigned CStencilShadowConnectivityBuilder::WeldVertex (const Vec3d& v, unsigned nNewVertex)
{
// The easiest way: just find it directly
VertexWelderMap::iterator it;
it = m_mVertexWelder.find(v);
if (it != m_mVertexWelder.end())
return it->second;
else
{
/*
// scan and find some very close vertex
if (m_fWeldTolerance > 0)
for (it = m_mVertexWelder.begin(); it != m_mVertexWelder.end(); ++it)
{
if ((it->first-v).len2() < m_fWeldTolerance)
return it->second;
}
*/
m_mVertexWelder.insert (VertexWelderMap::value_type(v, nNewVertex));
return nNewVertex;
}
}
///////////////////////////////////////////////////////////////////////////////////
// Adds the triangle with the given vertex indices and vertex coordinates
// to the list of triangles that will cast shadows. Welds the vertices based on their
// coordinates
void CStencilShadowConnectivityBuilder::AddTriangleWelded(
unsigned short nV0, unsigned short nV1, unsigned short nV2,
const Vec3d &vV0, const Vec3d &vV1, const Vec3d &vV2 )
{
nV0=WeldVertex(vV0,nV0);
nV1=WeldVertex(vV1,nV1);
nV2=WeldVertex(vV2,nV2);
AddTriangle(nV0,nV1,nV2);
}
//////////////////////////////////////////////////////////////////////////////////////
// add a new edge, if there is no complementary single edge;
// otherwise, withdraw the edge from the list of single edges and add to double edges
// PARAMETERS:
// edge - start and end vertices of the edge going CCW along the face
// efFace - the opposite vertex/face the edge belongs to
//////////////////////////////////////////////////////////////////////////////////////
void CStencilShadowConnectivityBuilder::AddNewEdge (BasicEdge eEdge, EdgeFace efFace)
{
// first, try to find the complementary
BasicEdge eComplementary (eEdge[1], eEdge[0]);
SingleEdgeMap::iterator itComplementary = m_mapSingleEdges.find (eComplementary);
if (itComplementary == m_mapSingleEdges.end())
{
// complementeary edge not found. Add a new single edge
m_mapSingleEdges.insert (SingleEdgeMap::value_type(eEdge, efFace));
// nVEdgeG for nFaceVertex[1] is unknown and doesn't matter at the moment
}
else
{
// we found the complementary edge
Edge edgeNewDouble (eComplementary, itComplementary->second, efFace);
m_vDoubleEdges.push_back (edgeNewDouble);
m_mapSingleEdges.erase (itComplementary);
}
}
///////////////////////////////////////////////////////////////////////////////////
// constructs/compiles the optimum representation of the connectivity
// to be used in run-time
// WARNING: use Release method to dispose the connectivity object
///////////////////////////////////////////////////////////////////////////////////
IStencilShadowConnectivity *CStencilShadowConnectivityBuilder::ConstructConnectivity( void )
{
CStencilShadowConnectivity* pConnectivity = new CStencilShadowConnectivity(m_vDoubleEdges);
assert(pConnectivity); // low memeory?
pConnectivity->SetOrphanEdges(m_mapSingleEdges);
pConnectivity->SetFaces(m_vFaces);
// find all the used vertices
FaceArray::const_iterator pFace = m_vFaces.begin();
DWORD nFaceCount = m_vFaces.size();
#if 0
// test for serialization function
unsigned nBufSize = pConnectivity->Serialize(true, NULL, 0);
void* pBuf = malloc (nBufSize);
unsigned nSaved = pConnectivity->Serialize(true, pBuf, nBufSize);
assert (nSaved == nBufSize);
pConnectivity->Release();
pConnectivity = new CStencilShadowConnectivity ();
unsigned nLoaded = pConnectivity->Serialize(false, pBuf, nBufSize);
assert (nLoaded == nBufSize);
free (pBuf);
#endif
return((IStencilShadowConnectivity *)pConnectivity);
}
// returns the number of single (with no pair faces found) or orphaned edges
unsigned CStencilShadowConnectivityBuilder::numOrphanedEdges ()const
{
return(m_mapSingleEdges.size());
}
//! Returns the list of faces for orphaned edges into the given buffer;
//! For each orphaned edge, one face will be returned; some faces may be duplicated
void CStencilShadowConnectivityBuilder::getOrphanedEdgeFaces (unsigned* pBuffer)
{
for (SingleEdgeMap::iterator it = m_mapSingleEdges.begin(); it != m_mapSingleEdges.end(); ++it)
*(pBuffer++) = it->second.m_nFace;
}
// reserves space for the given number of triangles that are to be added
void CStencilShadowConnectivityBuilder::ReserveForTriangles( unsigned nNumTriangles, unsigned innNumVertices )
{
m_vDoubleEdges.reserve(nNumTriangles*3/2);
m_vFaces.reserve(nNumTriangles);
m_dwNumUncompressedVertices=innNumVertices;
}
CStencilShadowStaticConnectivityBuilder::CStencilShadowStaticConnectivityBuilder()
#ifdef DEBUG_STD_CONTAINERS
: m_vPlanes("CStencilShadowStaticConnectivityBuilder.Planes")
#endif
{
}
CStencilShadowStaticConnectivityBuilder::~CStencilShadowStaticConnectivityBuilder()
{
}
// reserves space for the given number of triangles that are to be added
void CStencilShadowStaticConnectivityBuilder::ReserveForTriangles( unsigned nNumTriangles, unsigned innNumVertices )
{
CStencilShadowConnectivityBuilder::ReserveForTriangles (nNumTriangles, innNumVertices);
m_vPlanes.reserve (nNumTriangles);
}
//! return to the state right after construction
void CStencilShadowStaticConnectivityBuilder::Reinit( void )
{
CStencilShadowConnectivityBuilder::Reinit();
m_vPlanes.clear();
}
//////////////////////////////////////////////////////////////////////////
// Adds the triangle with the given vertex indices and vertex coordinates
// to the list of triangles that will cast shadows. Welds the vertices based on their
// coordinates. Calculates and remembers the normals for each triangle
void CStencilShadowStaticConnectivityBuilder::AddTriangleWelded(
vindex nV0, vindex nV1, vindex nV2,
const Vec3d &vV0, const Vec3d &vV1, const Vec3d &vV2 )
{
CStencilShadowConnectivityBuilder::AddTriangleWelded (nV0, nV1, nV2, vV0, vV1, vV2);
m_vPlanes.push_back(Plane (vV0,vV1,vV2));
}
// constructs/compiles the optimum representation of the connectivity
// to be used in run-time
// WARNING: use Release method to dispose the connectivity object
//! /param inpVertexBuf vertex position buffer to check for solvable open edges (2 vertices with same position)
//! /return interface pointer, could be 0
class IStencilShadowConnectivity *CStencilShadowStaticConnectivityBuilder::ConstructConnectivity ()
{
if (m_vPlanes.empty())
return new CStencilShadowConnectivity();
CStencilShadowConnectivity * pConnectivity = (CStencilShadowConnectivity *)CStencilShadowConnectivityBuilder::ConstructConnectivity()->GetInternalRepresentation();
pConnectivity->SetPlanes(&m_vPlanes[0], m_vPlanes.size());
SetVertices (pConnectivity);
return pConnectivity;
};
//////////////////////////////////////////////////////////////////////////
// WARNING: This is only to be called when the whole construction process
// is finished, to modify already created connectivity
// Goes through all vertices used by the connectivity and constructs a continuous
// array out of them; reindexes the vertices in the connectivity object
// to use these vertices; puts the new vertex array into the connectivity object
void CStencilShadowStaticConnectivityBuilder::SetVertices (CStencilShadowConnectivity * pConnectivity)
{
// scan through all used vertices and put them into continuous array
std::vector<Vec3d> arrNewVertices; // the vertices array in new indexation
std::vector<CStencilShadowConnectivity::vindex> arrOldToNewMap; // the mapping old->new indexation
arrNewVertices.reserve (pConnectivity->numVertices());
arrOldToNewMap.resize (pConnectivity->numVertices(),-1);
for (VertexWelderMap::const_iterator it = m_mVertexWelder.begin(); it != m_mVertexWelder.end(); ++it)
{
#if 1
// this will remap the vertex indices
arrOldToNewMap[it->second] = arrNewVertices.size();
arrNewVertices.push_back(it->first);
#else
// this will not change indexation
arrOldToNewMap[it->second] = it->second;
if (arrNewVertices.size() <= it->second)
arrNewVertices.resize (it->second+1, Vec3d(0,0,0));
arrNewVertices[it->second] = it->first;
#endif
}
// now renumber the vertices
pConnectivity->SetRemapVertices(&arrOldToNewMap[0], arrOldToNewMap.size(), &arrNewVertices[0], arrNewVertices.size());
}
#ifdef WIN64
#pragma warning( pop ) //AMD Port
#endif

View File

@@ -0,0 +1,210 @@
//////////////////////////////////////////////////////////////////////
//
// CryEngine Source code
//
// File:StencilShadowConnectivityBuilder.h
// Declaration of class CStencilShadowConnectivityBuilder
//
// History:
// -:Created by Sergiy Migdalskiy <sergiy@crytek.de>
//
//////////////////////////////////////////////////////////////////////
// class CStencilShadowConnectivityBuilder
//
// This class is used to pre-compute the data for a model that's gonna cast stencil
// shadows, and whose vertices may change position, but the topology
// cannot change.
//
// Ok, to put it clear: for each model, you need one instance of
// class CStencilShadowConnectivity. To create that instance, use
// this class: create an object, push the mesh of the model into it,
// then ask this class to give out the CStencilShadowConnectivity.
//
// CStencilShadowConnectivity is build for maximum run-time performance and
// minimal memory footprint, whilst this class is build for convenient
// pre-calculations and flexibility.
//
// The model is allowed to deform, but is not
// allowed to change topology (add or remove faces as well as re-assign
// face vertices or even change face orientation).
/////////////////////////////////////////////////////////////////
//
// IMPLEMENTATION NOTES should be in
// StencilShadowConnectivityBuilder.cpp
//
#pragma once
#ifndef _STENCIL_SHADOW_CONNECTIVITY_BUILDER_HDR_
#define _STENCIL_SHADOW_CONNECTIVITY_BUILDER_HDR_
// the connectivity class is required for the declarations
// of the Face, Edge, EdgeFace and BasicEdge structures which are common for both
// the builder and the built class
#include "IEdgeConnectivityBuilder.h" // IEdgeConnectivityBuilder
#include "StencilShadowConnectivity.h" // CStencilShadowConnectivity
#include <map> // STL map<>
#include <functional>
#include <algorithm>
class CStencilShadowConnectivityBuilder : public IEdgeConnectivityBuilder
{
public:
typedef IStencilShadowConnectivity::vindex vindex;
//! default constructor
//! creates an empty mesh connectivity
CStencilShadowConnectivityBuilder(void);
//! destructor
virtual ~CStencilShadowConnectivityBuilder(void);
//! return to the state right after construction
virtual void Reinit( void );
// sets the maximum distance between two points that are allowed to be welded
//virtual void SetWeldTolerance (float fTolerance) {m_fWeldTolerance = fTolerance*fTolerance;}
// reserves space for the given number of triangles that are to be added
//! /param nNumTriangles 0..
//! /param innNumVertices 0..
virtual void ReserveForTriangles( unsigned nNumTriangles, unsigned innNumVertices );
// adds a single triangle to the mesh
// the triangle is defined by three vertices, in counter-clockwise order
// these vertex indices will be used later when accessing the array of
// deformed character/model vertices to determine the shadow volume boundary
//! /param nV0 vertex index one 0..0xffff
//! /param nV1 vertex index two 0..0xffff
//! /param nV2 vertex index three 0..0xffff
//! /param inpVertexPos pointer to the vertex array (to remove vertices on same position)
virtual void AddTriangle( vindex nV0, vindex nV1, vindex nV2 );
//!
//! /param nV0 vertex index one 0..0xffff
//! /param nV1 vertex index two 0..0xffff
//! /param nV2 vertex index three 0..0xffff
//! /param vV0 original vertex one position
//! /param vV1 original vertex two position
//! /param vV2 original vertex three position
//! slower but with the auto weld feature (if there are vertices with the same position your result is smaller and therefore faster)
virtual void AddTriangleWelded( vindex nV0, vindex nV1, vindex nV2, const Vec3d &vV0, const Vec3d &vV1, const Vec3d &vV2 );
// constructs/compiles the optimum representation of the connectivity
// to be used in run-time
// WARNING: use Release method to dispose the connectivity object
//! /param inpVertexBuf vertex position buffer to check for solvable open edges (2 vertices with same position)
//! /return interface pointer, could be 0
virtual class IStencilShadowConnectivity *ConstructConnectivity( void );
// returns the number of single (with no pair faces found) or orphaned edges
// /return 0..
virtual unsigned numOrphanedEdges ()const;
//! Returns the list of faces for orphaned edges into the given buffer;
//! For each orphaned edge, one face will be returned; some faces may be duplicated
virtual void getOrphanedEdgeFaces (unsigned* pBuffer);
protected:
// for the descriptions of the following shared structures, refer to
// File:StencilShadowConnectivity.h
typedef CStencilShadowConnectivity::BasicEdge BasicEdge;
typedef CStencilShadowConnectivity::Edge Edge;
typedef CStencilShadowConnectivity::EdgeFace EdgeFace;
typedef CStencilShadowConnectivity::Face Face;
// map of single edges - edge with only one face attached
typedef std::map<BasicEdge, EdgeFace> SingleEdgeMap;
SingleEdgeMap m_mapSingleEdges; //!<
// array of double-edges - edges with both faces attached/found
typedef std::vector<Edge> DoubleEdgeArray;
DoubleEdgeArray m_vDoubleEdges; //!<
// triangles added (used to extract index to reference edge to faces, and keep the topology)
typedef std::vector<Face> FaceArray;
FaceArray m_vFaces; //!<
DWORD m_dwNumUncompressedVertices; //!<
// helper to get order for Vec3d
struct CVec3dOrder: public std::binary_function< Vec3d, Vec3d, bool>
{
bool operator() ( const Vec3d &a, const Vec3d &b ) const
{
// first sort by x
if(a.x<b.x)return(true);
if(a.x>b.x)return(false);
// then by y
if(a.y<b.y)return(true);
if(a.y>b.y)return(false);
// then by z
if(a.z<b.z)return(true);
if(a.z>b.z)return(false);
return(false);
}
};
typedef std::map<Vec3d,unsigned,CVec3dOrder> VertexWelderMap;
VertexWelderMap m_mVertexWelder; //!< used for AddTriangleWelded
// this will try to find a close match to the given vertex, and
// if found, return its index (the actual index of the vertex that's very close or
// coincide with v in space). Otherwise, creates a new vertex reference in the map
// and returns the index nNewVertex
unsigned WeldVertex (const Vec3d& v, unsigned nNewVertex);
//float m_fWeldTolerance;
// this is 1 + the max index of the vertex in the original mesh vertex array, that
// is used by the currently being built connectivity
//unsigned m_numOrigMeshVerticesUsed; // this is unneeded because connectivity calculates this itself
protected:
// adds a new single edge, or finds an adjacent edge and puts the double-edge on record
// add a new edge, if there is no complementary single edge;
// otherwise, withdraw the edge from the list of single edges and add to double edges
//! /param eEdge
//! /param efFace
void AddNewEdge (BasicEdge eEdge, EdgeFace efFace);
};
// this is the builder of connectivity that can be used for static objects
// (with non-changing face normals)
class CStencilShadowStaticConnectivityBuilder :public CStencilShadowConnectivityBuilder
{
public:
CStencilShadowStaticConnectivityBuilder();
virtual ~CStencilShadowStaticConnectivityBuilder();
void AddTriangleWelded( vindex nV0, vindex nV1, vindex nV2, const Vec3d &vV0, const Vec3d &vV1, const Vec3d &vV2 );
//! return to the state right after construction
virtual void Reinit( void );
// reserves space for the given number of triangles that are to be added
//! /param nNumTriangles 0..
//! /param innNumVertices 0..
virtual void ReserveForTriangles( unsigned nNumTriangles, unsigned innNumVertices );
// constructs/compiles the optimum representation of the connectivity
// to be used in run-time
// WARNING: use Release method to dispose the connectivity object
//! /param inpVertexBuf vertex position buffer to check for solvable open edges (2 vertices with same position)
//! /return interface pointer, could be 0
virtual class IStencilShadowConnectivity *ConstructConnectivity( void );
protected:
// WARNING: This is only to be called when the whole construction process
// is finished, to modify already created connectivity
// Goes through all vertices used by the connectivity and constructs a continuous
// array out of them; reindexes the vertices in the connectivity object
// to use these vertices; puts the new vertex array into the connectivity object
void SetVertices (CStencilShadowConnectivity * pConnectivity);
typedef CStencilShadowConnectivity::Plane Plane;
std::vector<Plane> m_vPlanes;
};
#endif // _STENCIL_SHADOW_CONNECTIVITY_BUILDER_HDR_

View File

@@ -0,0 +1,496 @@
#include "stdafx.h"
#include "StencilShadowConnectivity.h"
#include "StencilShadowEdgeDetector.h"
CStencilShadowEdgeDetector::CStencilShadowEdgeDetector():
m_pConnectivity(NULL),
m_pModelVertices(NULL)
{
m_bBitFieldIsSet=false;
}
// Re-construct the whole object
// Use this object to reuse the EdgeDetector object multiple times for different
// connectivities and vertices. This can save on reallocating internal arrays this object uses at run time
void CStencilShadowEdgeDetector::reinit (
const IStencilShadowConnectivity* pConnectivity,
const Vec3d* pDeformedVertices
)
{
assert(pConnectivity);
m_pConnectivity = pConnectivity->GetInternalRepresentation();
m_pModelVertices = pDeformedVertices;
if (!m_pModelVertices || m_pConnectivity->IsStandalone())
m_pModelVertices = m_pConnectivity->getVertices();
assert (pDeformedVertices);
m_arrShadowEdges.clear();
m_arrShadowFaces.clear();
m_numShadowEdgeVertices = 0;
}
CStencilShadowEdgeDetector::~CStencilShadowEdgeDetector(void)
{
}
// fills in the internal array of faces and vertices
// - detected shadow faces for the given light source and model
void CStencilShadowEdgeDetector::detectShadowFaces ()
{
assert(m_pConnectivity);
if(!m_pConnectivity)
{
#if !defined(LINUX)
Warning(0,0,"CStencilShadowEdgeDetector::detectShadowFaces: !m_pConnectivity");
#endif
return;
}
if(m_arrFaceOrientations.empty())
{
#if !defined(LINUX)
Warning(0,0,"CStencilShadowEdgeDetector::detectShadowFaces: m_arrFaceOrientations.empty()");
#endif
return;
}
assert(!m_arrFaceOrientations.empty());
// scan all faces and fill the backfacing ones
unsigned nNumFaces = m_pConnectivity->numFaces();
unsigned* pFaceOrientBits = m_arrFaceOrientations.begin();
for (unsigned nFace = 0; nFace < nNumFaces; ++pFaceOrientBits)
{
unsigned nOrientBit = 1;
do
{
if ((*pFaceOrientBits & nOrientBit) == 0)
{
// the face is back-facing the light
const CStencilShadowConnectivity::Face& face = m_pConnectivity->getFace(nFace);
// revert orientation of the face 'cause the volumizer expects light-facing capping faces
AddFace(face.getVertex(0), face.getVertex(2), face.getVertex(1));
}
}
while (((++nFace) < nNumFaces) && (nOrientBit <<= 1) != 0);
}
m_bBitFieldIsSet=true;
}
// returns true if the given face faces the light, and false otherwise
bool CStencilShadowEdgeDetector::IsFaceTurnedToLight (unsigned nFace, const Vec3d& vLight)
{
assert(m_pModelVertices);
assert(m_pConnectivity);
assert(nFace>=0 && nFace<m_pConnectivity->numFaces());
if (m_pConnectivity->hasPlanes())
return m_pConnectivity->getPlane(nFace).apply (vLight) > 0;
const CStencilShadowConnectivity::Face& face = m_pConnectivity->getFace(nFace);
DWORD dwIndex[3]={ face.getVertex(0),
face.getVertex(1),
face.getVertex(2) };
const Vec3d& vFaceV0 = m_pModelVertices[dwIndex[0]];
Vec3d vNormal = (m_pModelVertices[dwIndex[1]] - vFaceV0) ^ (m_pModelVertices[dwIndex[2]] - vFaceV0);
return vNormal * (vLight - vFaceV0) > 0;
}
//////////////////////////////////////////////////////////////////////
// Calculates all face orientations into the bit array
// PARAMETERS:
// vLight - position of the light source to detect the edges for
//////////////////////////////////////////////////////////////////////
void CStencilShadowEdgeDetector::computeFaceOrientations (Vec3d vLight)
{
unsigned nModelNumFaces = m_pConnectivity->numFaces();
// mask that masks out the bits that address the bit in an unsigned
//const nBitIndexMask = (sizeof(m_arrFaceOrientations[0])*8) - 1;
// number of unsigneds to allocate in the bit array
unsigned nBitarraySize = (nModelNumFaces + 31u) >> 5;
if (m_arrFaceOrientations.size() < nBitarraySize)
m_arrFaceOrientations.reinit(nBitarraySize);
memset (m_arrFaceOrientations.begin(), 0, nBitarraySize * 4); // neccessary because we set only the 1 bits
// scan through all faces, in packets of 32 faces, and pack the orientations into
// bit array with 32-bit portions
unsigned nNumFaces = m_pConnectivity->numFaces();
unsigned* pFaceOrientBits = m_arrFaceOrientations.begin();
for (unsigned nFace = 0; nFace < nNumFaces; ++pFaceOrientBits)
{
unsigned nOrientBit = 1;
do
{
if (IsFaceTurnedToLight (nFace, vLight))
*pFaceOrientBits |= nOrientBit;
}
while (((++nFace) < nNumFaces) && (nOrientBit <<= 1) != 0);
}
m_bBitFieldIsSet=true;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// fills in the internal array of edges and vertices with appropriate data
// call computeFaceOrientations(vLight) before or create the triangle orientation bitfield yourself
// - detected shadow edges for the given light source and model
// ALGORITHM:
// scans each edge and determines signs of volumes formed with this edge and light source
// on one hand and the opposite vertex on the other hand
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CStencilShadowEdgeDetector::detectShadowEdges( void )
{
assert(m_bBitFieldIsSet); // call computeFaceOrientations(vLight) before or create the triangle orientation bitfield yourself
// number of vertices in the original model
unsigned nModelNumVertices = m_pConnectivity->numVertices();
//
// for each edge, insert it into m_arrShadowEdges if it's boundary;
// insert it in reverse order if it's reverse-boundary
// insert the vertex/-ices into the m_arrVertices array if necessary
//
// TODO: perhaps an optimization is possible, if we detect adjacent edges
// and then render triangle strips without indices
//
unsigned nEdge;
unsigned nEdgeCount = m_pConnectivity->numEdges();
for (nEdge = 0; nEdge < nEdgeCount; ++nEdge)
{
// this is the edge to check against being boundary
const CStencilShadowConnectivity::Edge& rEdge = m_pConnectivity->getEdge(nEdge);
// check the edge
switch (CheckEdgeType (
rEdge.getFace(0).getFaceIndex(),
rEdge.getFace(1).getFaceIndex()
))
{
case nET_Boundary:
AddEdge (rEdge[0], rEdge[1]);
break;
case nET_ReverseBoundary:
AddEdge (rEdge[1], rEdge[0]);
break;
}
}
// now check the orphan edges
nEdgeCount = m_pConnectivity->numOrphanEdges();
for (nEdge = 0; nEdge < nEdgeCount; ++nEdge)
{
// this is the edge to check against being boundary
const CStencilShadowConnectivity::OrphanEdge& rEdge = m_pConnectivity->getOrphanEdge(nEdge);
// check the edge
switch (CheckOrphanEdgeType (
rEdge.getFace().getFaceIndex()
))
{
case nET_Boundary:
AddEdge (rEdge[0], rEdge[1]);
break;
case nET_ReverseBoundary:
AddEdge (rEdge[1], rEdge[0]);
break;
}
}
m_bBitFieldIsSet=false;
m_numShadowEdgeVertices = m_pConnectivity->numVertices();
}
////////////////////////////////////////////////////////////////////////
// Adds the given shadow edge to the list of boundary edges
// PARAMETERS:
// nVertex[2] - indices of the edge vertices in the m_pModelVertices
// array (and in g_arrModelVtxIdxMap).
////////////////////////////////////////////////////////////////////////
void CStencilShadowEdgeDetector::AddEdge( vindex nVertex0, vindex nVertex1 )
{
// add to the list of edges
m_arrShadowEdges.push_back(nVertex0);
m_arrShadowEdges.push_back(nVertex1);
}
// adds the given shadow face, in the order that is passed
void CStencilShadowEdgeDetector::AddFace( vindex nVertex0, vindex nVertex1, vindex nVertex2 )
{
// add to the list of faces
m_arrShadowFaces.push_back(nVertex0);
m_arrShadowFaces.push_back(nVertex1);
m_arrShadowFaces.push_back(nVertex2);
}
// checks the edge type by the face indices: assumes that the face orientation bits have been calculated already
CStencilShadowEdgeDetector::EdgeTypeEnum
CStencilShadowEdgeDetector::CheckEdgeType (unsigned nFace0, unsigned nFace1)
{
assert(m_arrFaceOrientations.size());
if ((m_arrFaceOrientations[nFace0>>5]&(1<<(nFace0&0x1F))) == 0)
{
// the primary edge face is culled against the light
if ((m_arrFaceOrientations[nFace1>>5]&(1<<(nFace1&0x1F))) == 0)
{
// the opposite face is culled against the light,
// both are back-facing the light
return nET_Interior;
}
else
{
// the opposite face is facing the light
// we've got the rev-boundary edge
return nET_ReverseBoundary;
}
}
else
{
// the primary edge face is facing the light
if ((m_arrFaceOrientations[nFace1>>5]&(1<<(nFace1&0x1F))) == 0)
{
// the opposite face is culled against the light,
// we've got the boundary edge
return nET_Boundary;
}
else
{
// both are facing the light
return nET_Exterior;
}
}
}
CStencilShadowEdgeDetector::EdgeTypeEnum
CStencilShadowEdgeDetector::CheckOrphanEdgeType (unsigned nFace0)
{
assert(m_arrFaceOrientations.size());
if ((m_arrFaceOrientations[nFace0>>5]&(1<<(nFace0&0x1F))) == 0)
{
// the primary edge face is culled against the light
// we can either ignore the face and return nET_Interior
// or we can pretend we have a complementary face - so that the face casts
// the shadow with both its sides. then, return nET_ReverseBoundary
return nET_Interior;
//return nET_ReverseBoundary;
}
else
{
// the primary edge face is facing the light
// since we don't have any neighbor to check, pretend as if the neighbor were back-facing the light
return nET_Boundary;
}
}
#ifdef WIN64
#pragma warning( push ) //AMD Port
#pragma warning( disable : 4267 )
#endif
const CStencilShadowEdgeDetector::vindex *CStencilShadowEdgeDetector::getShadowEdgeArray( unsigned &outiNumEdges ) const
{
outiNumEdges=m_arrShadowEdges.size()/2;
if(!outiNumEdges)return(0);
return(&m_arrShadowEdges[0]);
}
#ifdef WIN64
#pragma warning( pop ) //AMD Port
#endif
void CStencilShadowEdgeDetector::BuildSilhuetteFromPos( const IStencilShadowConnectivity* pConnectivity, const Vec3d &invLightPos,
const Vec3d* inpDeformedVertices )
{
assert(pConnectivity);
m_pConnectivity = pConnectivity->GetInternalRepresentation();
m_pModelVertices = m_pConnectivity->getVertices();
if ( !pConnectivity->IsStandalone())
{
if (!m_pModelVertices)
m_pModelVertices = inpDeformedVertices;
}
assert(m_pModelVertices);
m_arrShadowEdges.clear();
m_arrShadowFaces.clear();
m_numShadowEdgeVertices = 0;
computeFaceOrientations(invLightPos);
detectShadowEdges(); // call computeFaceOrientations(vLight) before or create the triangle orientation bitfield yourself
detectShadowFaces();
// assert(m_bBitFieldIsSet);
if(!m_bBitFieldIsSet)
Warning(0,0,"CStencilShadowEdgeDetector::BuildSilhuetteFromPos: !m_bBitFieldIsSet");
}
void CStencilShadowEdgeDetector::BuildSilhuetteFromBitfield( const IStencilShadowConnectivity* pConnectivity, const Vec3d* inpVertices )
{
assert(pConnectivity);
assert(m_bBitFieldIsSet); // call computeFaceOrientations(vLight) before or create the triangle orientation bitfield yourself
m_pConnectivity = pConnectivity->GetInternalRepresentation();
m_pModelVertices = m_pConnectivity->getVertices();
if (!m_pModelVertices)
m_pModelVertices = inpVertices;
assert(m_pModelVertices);
m_arrShadowEdges.clear();
m_arrShadowFaces.clear();
m_numShadowEdgeVertices = 0;
// triangle orientation bitfield has to be provided by calling getOrientationBitfield
detectShadowEdges(); // call computeFaceOrientations(vLight) before or create the triangle orientation bitfield yourself
detectShadowFaces();
assert(m_bBitFieldIsSet); // call computeFaceOrientations(vLight) before or create the triangle orientation bitfield yourself
}
//!
unsigned *CStencilShadowEdgeDetector::getOrientationBitfield( int iniNumTriangles )
{
assert(iniNumTriangles);
// mask that masks out the bits that address the bit in an unsigned
//const nBitIndexMask = (sizeof(m_arrFaceOrientations[0])*8) - 1;
// number of unsigneds to allocate in the bit array
unsigned nBitarraySize = (iniNumTriangles + 31u) >> 5;
if (m_arrFaceOrientations.size() < nBitarraySize)
m_arrFaceOrientations.reinit(nBitarraySize);
m_bBitFieldIsSet=true;
memset (m_arrFaceOrientations.begin(), 0, nBitarraySize * 4); // neccessary because we set only the 1 bits
return(m_arrFaceOrientations.begin());
}
//////////////////////////////////////////////////////////////////////////////
// make up the shadow volume
// constructs the shadow volume mesh, and puts the mesh definition into the
// vertex buffer (vertices that define the mesh) and index buffer (triple
// integers defining the triangular faces, counterclockwise order)
// The size of the vertex buffer must be at least numVertices()
// The size of the index buffer must be at least numIndices()
//////////////////////////////////////////////////////////////////////////////
void CStencilShadowEdgeDetector::meshShadowVolume( Vec3d vLight, float fFactor, Vec3d* outpVertexBuf, unsigned short* pIndexBuf )
{
assert(outpVertexBuf);
// The Algorithm
// We have the edges and their vertex array in m_pShadowEdges
// For each edge, we generate a quad (2 trianges), out of the pair of vertices defining the edge:
// take the vertex, move it away from the light (this makes up the far vertex), this will define an extruded edge -- our actual quad
// 1. scan through all shadow edges, insert corresponding generated vertex indices into the index buffer;
// 2. scan through all vertices, generate far vertices (for each near vertex, there's a far vertex), fill in the vertex buffer
unsigned nNumVerts;
unsigned i;
nNumVerts = numShadowVolumeVertices()/2;
const Vec3d* pVertices = m_pModelVertices;
// go thougth all compressed vertices
{
Vec3d vLightFac=(1.0f-fFactor)*vLight; // optimized a little
for(i=0;i<nNumVerts;++i)
{
const Vec3d& vPos = pVertices[i];
outpVertexBuf[i] = vPos;
outpVertexBuf[nNumVerts+i] = vPos*fFactor + vLightFac; // == (vPos - vLight) * fFactor + vLight
}
}
unsigned short* pIndex = pIndexBuf;
unsigned nNumEdges;
const unsigned short* pEdgeArray = getShadowEdgeArray(nNumEdges);
// fill in the shadow volume quads (extruded vertices)
for (i = 0; i < nNumEdges; ++i)
{
unsigned short Edge1=*pEdgeArray++,Edge2=*pEdgeArray++;
assert (Edge1 < nNumVerts);
assert (Edge2 < nNumVerts);
*(pIndex++) = Edge2;
*(pIndex++) = Edge1;
*(pIndex++) = Edge1 + nNumVerts;
*(pIndex++) = Edge1 + nNumVerts;
*(pIndex++) = Edge2 + nNumVerts;
*(pIndex++) = Edge2;
}
if(m_arrShadowFaces.empty())
return; // vlad: otherwise crash
// fill in the shadow volume caps
unsigned nFaceIndices;
const unsigned short* pFaceIndex = getShadowFaceIndices(nFaceIndices);
const unsigned short* pFaceIndexEnd = pFaceIndex + nFaceIndices;
// fill the near cap
memcpy (pIndex, pFaceIndex, sizeof(*pFaceIndex)*nFaceIndices);
pIndex += nFaceIndices;
// fill the far cap
for (; pFaceIndex < pFaceIndexEnd; pFaceIndex += 3)
{
// for each face..
assert (pFaceIndex[0] < nNumVerts);
assert (pFaceIndex[1] < nNumVerts);
assert (pFaceIndex[2] < nNumVerts);
*(pIndex++) = pFaceIndex[0] + nNumVerts;
*(pIndex++) = pFaceIndex[2] + nNumVerts;
*(pIndex++) = pFaceIndex[1] + nNumVerts;
}
assert(numShadowVolumeVertices()==nNumVerts*2);
assert(numShadowVolumeIndices()==(int)(pIndex-pIndexBuf));
}

View File

@@ -0,0 +1,199 @@
//////////////////////////////////////////////////////////////////////
//
// CryEngine Source code
//
// File:StencilShadowEdgeDetector.h
// Declaration of class CStencilShadowEdgeDetector
//
// History:
// -:Created by Sergiy Migdalskiy <sergiy@crytek.de>
//
//////////////////////////////////////////////////////////////////////
// class CStencilShadowEdgeDetector
// AUTHOR: Sergiy Migdalskiy <sergiy@crytek.de>
//
// This is run-time (temporary, non-persistent) class that's used to construct
// the optimized shadow volume (optimized means only with the necessary boundary
// edges) for a concrete deformed model/character instance
//
// It ACCEPTS a Connectivity instance that must be pre-computed on per-model
// basis, and an array of deformed vertices.
// It OUTPUTS (constructs, prepares) a set of edges in the form prepared for
// fast construction of efficient shadow volume render data (vertex buffer)
//
#pragma once
#ifndef _STENCIL_SHADOW_EDGE_DETECTOR_HDR_
#define _STENCIL_SHADOW_EDGE_DETECTOR_HDR_
#include "StencilShadowConnectivity.h" // CStencilShadowConnectivity
#include "IEdgeConnectivityBuilder.h" // IEdgeDetector
#include "Cry3DEngineBase.h"
class CStencilShadowEdgeDetector : public IEdgeDetector, public Cry3DEngineBase
{
public:
//! default constructor
CStencilShadowEdgeDetector();
//! destructor
~CStencilShadowEdgeDetector(void);
// Re-construct the whole object
// Use this object to reuse the EdgeDetector object multiple times for different
// connectivities and vertices. This can save on reallocating internal arrays this object uses at run time
// /param pConnectivity, must not be 0 - don't use if there is nothing to do
// /param pDeformedVertices, must not be 0 - don't use if there is nothing to do
void reinit ( const IStencilShadowConnectivity* pConnectivity, const Vec3d* pDeformedVertices );
//! /param pConnectivity must not be 0
//! /param invLightPos in ???-space (World or Object)
//! /param pDeformedVertices must not be 0
virtual void BuildSilhuetteFromPos( const IStencilShadowConnectivity* pConnectivity, const Vec3d &invLightPos, const Vec3d* pDeformedVertices );
//! /param iniNumTriangles the size it should have, must not be 0 - don't use if there is nothing to do
//! /return pointer to the cleared (set to zero) bitfield where each bit represents the orientation of one triangle
virtual unsigned *getOrientationBitfield( int iniNumTriangles );
//!
//! /param pConnectivity must not be 0 - don't use if there is nothing to do
//! /param inpVertices must not be 0 - don't use if there is nothing to do
virtual void BuildSilhuetteFromBitfield( const IStencilShadowConnectivity* pConnectivity, const Vec3d* inpVertices );
//! returns a pointer to the the given shadow edges (array of 2 integers, defining the vertex indices)
//! /param
//! /return
virtual const vindex *getShadowEdgeArray( unsigned &outiNumEdges ) const;
//! number of vertices used to define the detected shadow edges
//! (at least nSE+1, at most nSE*2, where nSE is the number of shadow edges)
//! This may be less than total number of vertices since the edges may use less
//! vertices than faces
//! /return
_inline unsigned numShadowEdgeVertices() const
{
return m_numShadowEdgeVertices;
}
// number of vertices required to define the shadow volume,
// use this to determine the size of vertex buffer passed to meshShadowVolume (2*used vertices because of capping)
virtual unsigned numShadowVolumeVertices( void ) const
{
assert(m_pConnectivity);
return(m_pConnectivity->numVertices()*2);
}
#ifdef WIN64
#pragma warning( push ) //AMD Port
#pragma warning( disable : 4267 )
#endif
// pointer to the triplets defining shadow faces
virtual const vindex* getShadowFaceIndices( unsigned &outCount ) const
{
outCount=m_arrShadowFaces.size();
return &m_arrShadowFaces[0];
}
// number of indices required to define the shadow volume,
// use this to determine the size of index buffer passed to meshShadowVolume
// this is always a dividend of 3
virtual unsigned numShadowVolumeIndices()const
{
// each shadow edge requires 6 indices to define the shadow volume:
// it defines one quad => 2 triangles => 6 vertex references
unsigned numShadowEdges=m_arrShadowEdges.size()/2;
unsigned numShadowFaceIndices =m_arrShadowFaces.size();
return(numShadowEdges*6 + numShadowFaceIndices*2);
}
#ifdef WIN64
#pragma warning( pop ) //AMD Port
#endif
//! fills in the internal array of edges and vertices with appropriate data
//! call computeFaceOrientations(vLight) before or create the triangle orientation bitfield yourself
//! - detected shadow edges for the given light source and model
void detectShadowEdges();
//! fills in the internal array of faces and vertices
//! - detected shadow faces for the given light source and model
void detectShadowFaces ();
//! calculates all face orientations into the bit array
//! /param invLight position of the light source in ???-space (World or Object)
void computeFaceOrientations (Vec3d invLight);
// make up the shadow volume
// constructs the shadow volume mesh, and puts the mesh definition into the
// vertex buffer (vertices that define the mesh) and index buffer (triple
// integers defining the triangular faces, counterclockwise order)
// The size of the vertex buffer must be at least numVertices()
// The size of the index buffer must be at least numIndices()
virtual void meshShadowVolume (Vec3d vLight, float fFactor, Vec3d* outpVertexBuf, unsigned short* pIndexBuf );
protected:
const CStencilShadowConnectivity* m_pConnectivity; //!<
const Vec3d* m_pModelVertices; //!<
// number of vertices used to define edges
unsigned m_numShadowEdgeVertices;
// array of shadow edges, referring to the vertices in m_vVertices
// Now, edges are defined by pairs of integers. This may change in the future
std::vector <vindex> m_arrShadowEdges;
// array of shadow faces, referring to the vertices in m_vVertices
std::vector <vindex> m_arrShadowFaces;
// returns true if the given face faces the light, and false otherwise
bool IsFaceTurnedToLight( unsigned nFace, const Vec3d& vLight );
// adds the given shadow edge to the list of boundary edges
//! /param nVertex0 0..
//! /param nVertex1 0..
void AddEdge (vindex nVertex0, vindex nVertex1);
// adds the given shadow face, in the order that is passed
//! /param nVertex0 0..
//! /param nVertex1 0..
//! /param nVertex2 0..
void AddFace (vindex nVertex0, vindex nVertex1, vindex nVertex2);
// checks whether the given edge is boundary or reverse boundary
enum EdgeTypeEnum {
nET_Boundary, // normal boundary edge
nET_ReverseBoundary, // internal boundary edge, needs reversing before insertion into the edge list
nET_Exterior, // visible to the light surface interior edge
nET_Interior // invisible to the light surface interior edge
};
//! checks the edge type by the face indices: assumes that the face orientation bits have been calculated already
//! /param nFace0
//! /param nFace1
EdgeTypeEnum CheckEdgeType (unsigned nFace0, unsigned nFace1);
//! /param nFace0
EdgeTypeEnum CheckOrphanEdgeType (unsigned nFace0);
// face orientation bit array: for each face, there's a bit, which is 1 if it's facing the light and 0 otherwise
TFixedArray<unsigned> m_arrFaceOrientations;
bool m_bBitFieldIsSet; //! for debugging purpose
};
#endif

697
Cry3DEngine/Vegetation.cpp Normal file
View File

@@ -0,0 +1,697 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: statobjman.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: Loading trees, buildings, ragister/unregister entities for rendering
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "StatObj.h"
#include "objman.h"
#include "cbuffer.h"
#include "3DEngine.h"
void CStatObjInst::Serialize(bool bSave, ICryPak * pPak, FILE * f)
{
if(bSave)
pPak->FWrite(this,sizeof(*this),1,f);
else
pPak->FRead(this,sizeof(*this),1,f);
}
// Bending
static float CStatObjInst__sSpline(float x)
{
float fX = fabsf(x);
if(fX > 2.0f)
return 0;
if(fX > 1.0f)
return (2.0f-fX)*(2.0f-fX)*(2.0f-fX)/6.0f;
return 2.0f/3.0f-fX*fX+0.5f*fX*fX*fX;
}
float CStatObjInst::Interpolate(float& pprev, float& prev, float& next, float& nnext, float ppweight, float pweight, float nweight, float nnweight)
{
return pprev*ppweight + prev*pweight + next*nweight + nnext*nnweight;
}
float CStatObjInst::GetBendingRandomFactor()
{ // calculate random
static float sInterpValues[16] = {1.2f,1.0f,1.1f,0.8f,0.5f,0.7f,1.0f,1.3f,0.66f,0.8f,0.7f,0.9f,1.1f,1.4f,1.1f,1.3f};
float time = GetTimer()->GetCurrTime() * 0.666f;
int itime = fastftol_positive(time);
float pprev = sInterpValues[(itime-1)&15];
float prev = sInterpValues[(itime)&15];
float next = sInterpValues[(itime+1)&15];
float nnext = sInterpValues[(itime+2)&15];
float ppweight = CStatObjInst__sSpline(time-itime+1.0f);
float pweight = CStatObjInst__sSpline(time-itime+0.0f);
float nweight = CStatObjInst__sSpline(time-itime-1.0f);
float nnweight = CStatObjInst__sSpline(time-itime-2.0f);
return Interpolate(pprev, prev, next, nnext, ppweight, pweight, nweight, nnweight);
}
bool CStatObjInst::DrawEntity(const struct SRendParams & _EntDrawParams)
{
FUNCTION_PROFILER_FAST( GetSystem(),PROFILE_3DENGINE,m_bProfilerEnabled );
// if(!GetCVars()->e_vegetation)
// return false;
const Vec3d & vCamPos = GetViewCamera().GetPos();
float fDistance = m_arrfDistance[m_pObjManager->m_nRenderStackLevel];
/*
// calculate distance
float fPrevDist0 = m_fDistance0;
m_fDistance = GetDist2D( vCamPos.x, vCamPos.y, m_vPos.x, m_vPos.y )*m_pObjManager->m_fZoomFactor;
if(!m_pObjManager->m_nRenderStackLevel) // remember to be able to restore this value after reqursion drawing
m_fDistance0 = m_fDistance;*/
// float fMaxViewDist = GetMaxViewDist();
/* if(fDistance > fMaxViewDist)//*m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].f MaxViewDistRatio*GetCVars()->e_lod_ratio)
{
m_ucAngleSlotId = 255;
return false;
}*/
CStatObj * pBody = m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].GetStatObj();
if(!pBody)
return false;
// Vec3d vBoxMin = pBody->m_vBoxMin*m_fScale+m_vPos;
//Vec3d vBoxMax = pBody->m_vBoxMax*m_fScale+m_vPos;
/* assert(!_EntDrawParams.bAllInFrustum || cam.IsBoxVisible(vBoxMin,vBoxMax)); // test of bAllInFrustum flag
if( bNotAllIN && !cam.IsBoxVisibleFast( vBoxMin, vBoxMax)) // NOTE: bNotAllIN can work wrong
{
m_ucAngleSlotId = 255;
return;
}*/
// int nLastVisibleFrameID = m_OcclTestVars.nLastVisibleFrameID;
//assert(m_pObjManager->m_nRenderStackLevel || nLastVisibleFrameID != GetFrameID());
// recursion is handeled inside IsBoxOccluded()
// if(m_pObjManager->IsBoxOccluded(vBoxMin, vBoxMax, m_fDistance, &m_OcclTestVars))
// return;
// calculate switch to sprite distance
float near_far_dist = (18.f * pBody->GetRadiusVert() * m_fScale)
* max(0.5f,m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].fSpriteDistRatio)
+ 0.2f*(float)fabs((m_vPos.z + pBody->GetCenter().z*m_fScale) - vCamPos.z);
/*
static float fAverageSpriteDistRatio = 0.5f;
fAverageSpriteDistRatio += m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].fSpriteDistRatio;//(fAverageSpriteDistRatio + m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].fSpriteDistRatio)*0.5f;
if(m_nStatObjNumPerFrame%10000==0)
GetLog()->Log("m_nStatObjNumPerFrame = %.4f",fAverageSpriteDistRatio/m_nStatObjNumPerFrame);
*/
near_far_dist *= GetCVars()->e_vegetation_sprites_distance_ratio;
int nDynMask = _EntDrawParams.nDLightMask;
// remove sun bit
list2<CDLight> * pSources = ((C3DEngine*)m_p3DEngine)->GetDynamicLightSources();
for(int i=0; i<pSources->Count(); i++)
{
CDLight * pDynLight = pSources->Get(i);
assert(pDynLight->m_Id == i || pDynLight->m_Id == -1);
if(pDynLight->m_Flags & DLF_SUN)
{
nDynMask &= ~(1<<pDynLight->m_Id);
break;
}
}
if(near_far_dist < GetCVars()->e_vegetation_sprites_min_distance)
near_far_dist = GetCVars()->e_vegetation_sprites_min_distance;
// m_nStatObjNumPerFrame++;
// fade out bending amount
if(!m_pObjManager->m_nRenderStackLevel && m_fCurrentBending > 0)
m_fCurrentBending -= GetTimer()->GetFrameTime()*0.25f;
if(m_fCurrentBending < 0)
m_fCurrentBending = 0;
// calculate exact dynamic light mask
/* uint nThisDynLightMaskNoSun = nDynLightMaskNoSun;
if(nThisDynLightMaskNoSun)
{
m_pObjManager->m_p3DEngine->CheckDistancesToLightSources(nThisDynLightMaskNoSun,
pBody->GetCenter()*m_fScale+m_vPos, pBody->GetRadius()*m_fScale);
if(nThisDynLightMaskNoSun) // increase sprite distance if object affected by dynamic light
near_far_dist *= 2.5f;
}*/
// detect lod switch soon
const float fLodSwitchCountDown = GetCVars()->e_vegetation_sprites_slow_switch ?
min(1.f, fabsf(fDistance - near_far_dist)/(near_far_dist*0.33f)) : 1.f;
if(!m_pObjManager->m_nRenderStackLevel)
{ // calculate bending amount
if(m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].fBending)
{
float fBending = GetBendingRandomFactor() * m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].fBending;
m_fFinalBending = min(1.5f, 2.5f*(m_fCurrentBending + m_pObjManager->m_fWindForce)*fBending) / (pBody->GetRadiusVert()*m_fScale) * 1.8f;
m_fFinalBending *= fLodSwitchCountDown;
}
else
m_fFinalBending = 0;
}
/*
if(pBody->m_bStreamable && CStatObj::m_fStreamingTimePerFrame<CGF_STREAMING_MAX_TIME_PER_FRAME)
if(!pBody->GetLeafBuffer() || !pBody->m_nLoadedTrisCount)
if(GetCVars()->e_stream_cgf && GetCVars()->e_stream_for_visuals)
{ // streaming
CStatObj::m_fStreamingTimePerFrame -= GetTimer()->GetAsyncCurTime();
bool bRes = pBody->Load(
pBody->m_szFileName,
pBody->m_szGeomName[0] ? pBody->m_szGeomName : 0,
pBody->m_eVertsSharing,
pBody->m_bLoadAdditinalInfo,
pBody->m_bKeepInLocalSpace, false);
pBody->m_bStreamable=true;*/
/*
if(pBody->GetLeafBuffer() && !((CStatObj*)pBody)->IsSpritesCreated())
((CStatObj*)pBody)->UpdateCustomLightingSpritesAndShadowMaps(
m_pObjManager->m_vOutdoorAmbientColor,
m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].nSpriteTexRes,
m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].fBackSideLevel,
m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].bCalcLighting );
*/
/* CStatObj::m_fStreamingTimePerFrame += GetTimer()->GetAsyncCurTime();
}
pBody->m_nLastRendFrameId = GetFrameID();
*/
// do we need only 3d version
bool bUse3DOnly(!m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].bUseSprites || nDynMask);
// detect intersection with fog volume, note: use only center
// todo: do not calculate every frame and merge all if(!m_pObjManager->m_nRenderStackLevel) stuff
/* if(!m_pObjManager->m_nRenderStackLevel)
{
if(pFogVolume && pFogVolume->InsideBBox((vBoxMin+vBoxMax)*0.5f))
m_nFogVolumeID = pFogVolume->nRendererVolumeID;
else
m_nFogVolumeID = 0;
}*/
// render object in 3d
if( bUse3DOnly || fDistance < near_far_dist )
{
SRendParams rParms;
// set sort offset
rParms.fCustomSortOffset = m_pObjManager->GetSortOffset(m_vPos,vCamPos);
rParms.nFogVolumeID = m_nFogVolumeID;
if(GetRenderer()->EF_GetHeatVision())
{
rParms.nShaderTemplate = EFT_HEATVISION;
rParms.vAmbientColor = Vec3d(0.1f, 0.1f, 0.1f);
}
else
rParms.vAmbientColor = _EntDrawParams.vAmbientColor;
rParms.vPos = m_vPos;
rParms.fScale = m_fScale;
rParms.nDLightMask = nDynMask;
rParms.nStrongestDLightMask = nDynMask & _EntDrawParams.nStrongestDLightMask;
// bending
// if (useBending == 2)
rParms.fBending = m_fFinalBending;
// fade heat amount
rParms.fHeatAmount = min(2.f*(1.f - fDistance/near_far_dist),1.f);
// set alpha blend
if( m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].bUseAlphaBlending )
{
rParms.nSortValue = eS_TerrainDetailObjects;
if(m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].bUseSprites)
{ // set fixed alpha
rParms.fAlpha = 0.99f;
}
else
{ // fade alpha on distance
// float fAlpha = 1.f - fDistance / (fMaxViewDist);//*m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].fMaxViewDistRati o);
// rParms.fAlpha = min(0.99f,fAlpha*3);
rParms.fAlpha = min(0.99f,_EntDrawParams.fAlpha);
}
// entire object will use alpha blending so lets use only one light for it
rParms.nDLightMask = rParms.nStrongestDLightMask;
}
else
{ // no alpha blend
rParms.fAlpha = 1.f;
rParms.nSortValue = 0;
}
if(!GetCVars()->e_vegetation_debug)
{ // ignore editor colors per instance
rParms.vColor = Vec3d(CHAR_TO_FLOAT,CHAR_TO_FLOAT,CHAR_TO_FLOAT)*max((float)m_ucBright,32.f);
rParms.vColor *= m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].fBrightness;
rParms.vColor.CheckMin(Vec3d(1,1,1));
}
// use custom position when render into shadowmap
if(_EntDrawParams.dwFObjFlags & FOB_RENDER_INTO_SHADOWMAP)
rParms.vPos = _EntDrawParams.vPos;
// assign custom template
rParms.nShaderTemplate = _EntDrawParams.nShaderTemplate;
// Assign ovverride material.
rParms.pMaterial = m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].pMaterial;
// before switching into sprite - orient 3d object to much sprite image
Matrix44 objMatrix;
if(fLodSwitchCountDown<1.f && !m_pObjManager->m_nRenderStackLevel && !bUse3DOnly)
{
CStatObj * pBodyLow = pBody;
if(pBody->m_nLoadedLodsNum && pBody->m_arrpLowLODs[pBody->m_nLoadedLodsNum-1])
pBodyLow = pBody->m_arrpLowLODs[pBody->m_nLoadedLodsNum-1];
const float rad2deg = 180.0f/3.14159f;
const float far_tex_angle = (360.f/FAR_TEX_COUNT/2);
float DX = m_vPos.x + pBodyLow->GetCenter().x*m_fScale - vCamPos.x;
float DY = m_vPos.y + pBodyLow->GetCenter().y*m_fScale - vCamPos.y;
float DZ = m_vPos.z + pBodyLow->GetCenter().z*m_fScale - vCamPos.z;
float fRealAngle = rad2deg*cry_atan2f( DX, DY );
while(fRealAngle<0) fRealAngle+=360;
while(fRealAngle>=360) fRealAngle-=360;
assert(fRealAngle>=0 && fRealAngle<360.f);
float fNewAngle = (float)int(fRealAngle/FAR_TEX_ANGLE+0.5f)*FAR_TEX_ANGLE;
/* if(fPrevDist0 >= m_fDistance0 &&
m_ucAngleSlotId!=255 &&
nLastVisibleFrameID == GetFrameID()-1) // if camera move closer - continue to use last sprite angle
fNewAngle = (float)int(m_ucAngleSlotId)*FAR_TEX_ANGLE;
else*/
m_ucAngleSlotId = int(fRealAngle/FAR_TEX_ANGLE+0.5f);
float fDiffAngle = fNewAngle - fRealAngle;
while(fDiffAngle > 180)
fDiffAngle-=360;
while(fDiffAngle <= -180)
fDiffAngle+=360;
// assert(fDiffAngle<=0.5f*FAR_TEX_ANGLE); // can fail if we continue to use sprite angle
float fAngle1 = fDiffAngle*(1.f-fLodSwitchCountDown);
float fAngle2 = cry_atanf(DZ/fDistance)*gf_RADTODEG*(1.f-fLodSwitchCountDown);
objMatrix.SetIdentity();
objMatrix=GetTranslationMat(rParms.vPos+pBodyLow->GetCenter()*m_fScale)*objMatrix;
objMatrix=Matrix44::CreateRotationZYX(-gf_DEGTORAD*Vec3d(0,0,-fRealAngle))*objMatrix; //NOTE: angles in radians and negated
objMatrix=Matrix44::CreateRotationZYX(-gf_DEGTORAD*Vec3d(fAngle2,0,0))*objMatrix; //NOTE: angles in radians and negated
objMatrix=Matrix44::CreateRotationZYX( gf_DEGTORAD*Vec3d(0,0,-fRealAngle))*objMatrix; //NOTE: angles in radians and negated
objMatrix = Matrix44::CreateRotationZYX(-gf_DEGTORAD*Vec3d(0,0,fAngle1))*objMatrix; //NOTE: angles in radians and negated
objMatrix = GetTranslationMat(-pBodyLow->GetCenter()*m_fScale)*objMatrix;
objMatrix = Matrix33::CreateScale( Vec3d(rParms.fScale,rParms.fScale,rParms.fScale) )*objMatrix;
rParms.pMatrix = &objMatrix;
rParms.dwFObjFlags |= FOB_TRANS_MASK;
}
else
rParms.dwFObjFlags |= FOB_TRANS_TRANSLATE | FOB_TRANS_SCALE;
rParms.pShadowMapCasters = _EntDrawParams.pShadowMapCasters;
rParms.dwFObjFlags |= (_EntDrawParams.dwFObjFlags & ~FOB_TRANS_MASK);
// calculate lod and render the object
int nLod = max(0,(int)(fDistance*GetLodRatioNormilized()/(GetCVars()->e_obj_lod_ratio*GetRenderRadius())));
pBody->Render( rParms, Vec3(zero), nLod );//int(fDistance/near_far_dist*pBody->m_nLoadedLodsNum*pBody->m_nLoadedLodsNum) );
/*{ // speed test, render tree directly without shader pipeline - no speed difference
GetRenderer()->PushMatrix();
GetRenderer()->TranslateMatrix(rParms.vPos);
GetRenderer()->EnableAlphaTest(true,0.5f);
GetRenderer()->SetCullMode(R_CULL_NONE);
CLeafBuffer *lb = pBody->GetLeafBuffer();
for (int i=0; i<lb->m_pMats->Count(); i++)
{
CMatInfo * pMatInfo = &(*lb->m_pMats)[i];
IShader * e = (*lb->m_pMats)[i].pShader;
GetRenderer()->SetTexture(e->GetTexId());
GetRenderer()->DrawBuffer(lb->m_pVertexBuffer, &lb->m_Indices[pMatInfnFirstIndexId], pMatInfnNumIndices, 0);
}
GetRenderer()->PopMatrix();
}*/
// add object occlusion volume to the coverage buffer
if( fDistance<COVERAGEBUFFER_OCCLUDERS_MAX_DISTANCE &&
GetCVars()->e_cbuffer && pBody->GetLoadedTrisCount()==12 )
{
Vec3d vTopMax = m_vPos + pBody->m_vBoxMax*m_fScale;
Vec3d vTopMin = m_vPos + pBody->m_vBoxMin*m_fScale;
m_pObjManager->m_pCoverageBuffer->AddBBox(vTopMin,vTopMax,vCamPos-m_vPos);
}
}
else // process sprite
if( !bUse3DOnly && fDistance > near_far_dist)
{ // add to the list of far objects
if(m_pObjManager->m_lstFarObjects[m_pObjManager->m_nRenderStackLevel].Count()<16384)
{
if(!m_pObjManager->m_nRenderStackLevel)
{
if(fLodSwitchCountDown<1.f)
{
float DZ = m_vPos.z + pBody->GetCenter().z*m_fScale - vCamPos.z;
float fAngle2 = -cry_atanf(DZ/fDistance)*(1.f-fLodSwitchCountDown);
fAngle2 = max(0,min(1,(fAngle2+0.5f)));
m_ucLodAngle = uchar(fAngle2*255.f);
}
else
m_ucLodAngle = 127;
}
m_pObjManager->m_lstFarObjects[m_pObjManager->m_nRenderStackLevel].Add(this);
}
}
return true;
}
CObjManager * CStatObjInst::m_pObjManager = 0;
Vec3d CStatObjInst::m_vAngles(0,0,0);
void CStatObjInst::GetRenderBBox(Vec3d & vBoxMin,Vec3d & vBoxMax)
{
CStatObj * pBody = m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].GetStatObj();
if(pBody)
{
vBoxMin = pBody->m_vBoxMin*m_fScale+m_vPos;
vBoxMax = pBody->m_vBoxMax*m_fScale+m_vPos;
}
else
{
vBoxMin = m_vPos-Vec3d(1,1,1);
vBoxMax = m_vPos+Vec3d(1,1,1);
}
}
float CStatObjInst::GetRenderRadius(void) const
{
CStatObj * pBody = m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].GetStatObj();
if(pBody)
return pBody->GetRadius()*m_fScale;
assert(0);
return 0;
}
IStatObj * CStatObjInst::GetEntityStatObj( unsigned int nSlot, Matrix44 * pMatrix, bool bReturnOnlyVisible )
{
if(pMatrix)
{
Matrix33diag diag = Vec3d( GetScale(),GetScale(),GetScale() ); //use diag-matrix for scaling
Matrix34 rt34 = Matrix34::CreateRotationXYZ(gf_DEGTORAD*GetAngles(1), GetPos(true) ); //set scaling and translation in one function call
Matrix44 mat1 = rt34*diag; //optimised concatenation: m34*diag
*pMatrix = GetTransposed44(mat1); //TODO: remove this after E3 and use Matrix34 instead of Matrix44
}
return m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].GetStatObj();
}
CStatObj* CStatObjInst::GetStatObj() const
{
return m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].GetStatObj();
}
float CStatObjInst::GetMaxViewDist()
{
if (GetStatObj())
return max(GetCVars()->e_obj_min_view_dist, GetStatObj()->GetRadius()*m_fScale*GetCVars()->e_obj_view_dist_ratio*GetViewDistRatioNormilized());
return 0;
}
float CStatObjInst::GetViewDistRatioNormilized()
{
assert(GetStatObj());
return m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].fMaxViewDistRatio;
}
void CStatObjInst::Physicalize( bool bInstant )
{
assert(m_nObjectTypeID>=0);
CStatObj * pBody = m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].GetStatObj();
if(!pBody || !pBody->IsPhysicsExist())
return;
bool bHideability = m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].bHideability;
bool bPhysNonColl = m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].bPhysNonColl;
//////////////////////////////////////////////////////////////////////////
// Not create instance if no physical geometry.
if(!pBody->m_arrPhysGeomInfo[0])
if(!(pBody->m_arrPhysGeomInfo[1] && bHideability))
if(!(pBody->m_arrPhysGeomInfo[2] && bPhysNonColl))
return;
//////////////////////////////////////////////////////////////////////////
if (!GetCVars()->e_on_demand_physics)
bInstant = true;
/*
if( m_pObjManager->m_lstStaticTypes[nObjectTypeID].fSpriteDistRatio == 0 )
return; // do not phys 'sprite only' trees
CStatObj * pBody = m_pObjManager->m_lstStaticTypes[nObjectTypeID].GetStatObj();
bool bHideability = m_pObjManager->m_lstStaticTypes[nObjectTypeID].bHideability;
if(pBody && pBody->GetRadius()*m_fScale < 1.f && pBody->GetRadius())
return;
*/
if (!bInstant)
{
pe_status_placeholder spc;
if (m_pPhysEnt && m_pPhysEnt->GetStatus(&spc) && spc.pFullEntity)
GetSystem()->GetIPhysicalWorld()->DestroyPhysicalEntity(spc.pFullEntity);
pe_params_bbox pbb;
pbb.BBox[0] = m_vWSBoxMin;
pbb.BBox[1] = m_vWSBoxMax;
pe_params_foreign_data pfd;
pfd.pForeignData = this;
pfd.iForeignData = 1;
if (!m_pPhysEnt)
m_pPhysEnt = GetSystem()->GetIPhysicalWorld()->CreatePhysicalPlaceholder(PE_STATIC,&pbb);
else
m_pPhysEnt->SetParams(&pbb);
m_pPhysEnt->SetParams(&pfd);
return;
}
pBody->CheckLoaded();
// create new
pe_params_pos par_pos;
if (!m_pPhysEnt)
{
m_pPhysEnt = GetSystem()->GetIPhysicalWorld()->CreatePhysicalEntity(PE_STATIC,NULL,this,1);
if(!m_pPhysEnt)
return;
}
else if (bInstant) // this is on-demand creation, so entity pointer is automatically put into the placeholder
GetSystem()->GetIPhysicalWorld()->CreatePhysicalEntity(PE_STATIC,5.0f);
pe_action_remove_all_parts remove_all;
m_pPhysEnt->Action(&remove_all);
pe_geomparams params;
// collidable
if(pBody->m_arrPhysGeomInfo[0])
m_pPhysEnt->AddGeometry(pBody->m_arrPhysGeomInfo[0], &params);
params.flags = geom_colltype_ray;
// obstruct
if(pBody->m_arrPhysGeomInfo[1] && bHideability)
m_pPhysEnt->AddGeometry(pBody->m_arrPhysGeomInfo[1], &params);
// leaves
if(pBody->m_arrPhysGeomInfo[2] && bPhysNonColl)
m_pPhysEnt->AddGeometry(pBody->m_arrPhysGeomInfo[2], &params);
if(bHideability)
{
pe_params_foreign_data foreignData;
m_pPhysEnt->GetParams(&foreignData);
foreignData.iForeignFlags |= PFF_HIDABLE;
m_pPhysEnt->SetParams(&foreignData);
}
par_pos.pos = m_vPos;
par_pos.q.SetRotationXYZ( Vec3(0.f,0.f,0.f) );
par_pos.scale = m_fScale;
m_pPhysEnt->SetParams(&par_pos);
}
CStatObjInst::~CStatObjInst()
{
Dephysicalize( );
// Get3DEngine()->UnRegisterEntity(this);
Get3DEngine()->FreeEntityRenderState(this);
if(GetEntityRS() && GetEntityRS()->pShadowMapInfo)
GetEntityRS()->pShadowMapInfo->pShadowMapFrustumContainer = 0; // here was a pointer structure allocated in CStatObj
}
void CStatObjInst::Dematerialize( )
{
}
void CStatObjInst::Dephysicalize( )
{
// delete old physics
if(m_pPhysEnt)
GetSystem()->GetIPhysicalWorld()->DestroyPhysicalEntity(m_pPhysEnt);
m_pPhysEnt=0;
}
int CStatObjInst::GetMemoryUsage()
{
return sizeof(*this) + (m_pEntityRenderState ? sizeof(*m_pEntityRenderState) : 0);
}
unsigned int CStatObjInst::GetRndFlags()
{
assert(m_nObjectTypeID>=0 && m_nObjectTypeID<m_pObjManager->m_lstStaticTypes.Count());
return m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].m_dwRndFlags;
}
void CStatObjInst::SetRndFlags(unsigned int dwFlags)
{
assert(m_nObjectTypeID>=0 && m_nObjectTypeID<m_pObjManager->m_lstStaticTypes.Count());
m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].m_dwRndFlags = dwFlags;
}
void CStatObjInst::SetRndFlags(unsigned int dwFlags, bool bEnable)
{
assert(m_nObjectTypeID>=0 && m_nObjectTypeID<m_pObjManager->m_lstStaticTypes.Count());
if(bEnable)
m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].m_dwRndFlags |= dwFlags;
else
m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].m_dwRndFlags &= ~dwFlags;
}
/*
ShadowMapFrustum * CStatObjInst::GetShadowMapFrustum()
{
if(m_nObjectTypeID<0 && m_nObjectTypeID>=m_pObjManager->m_lstStaticTypes.Count())
return 0;
CStatObj * pBody = m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].GetStatObj();
if(pBody && pBody->m_pSMLSource && pBody->m_pSMLSource->m_LightFrustums.Count())
return &(pBody->m_pSMLSource->m_LightFrustums[0]);
return 0;
}
*/
struct ShadowMapLightSource * CStatObjInst::GetShadowMapFrustumContainer()
{
if(m_nObjectTypeID<0 && m_nObjectTypeID >= m_pObjManager->m_lstStaticTypes.Count())
return 0;
CStatObj * pBody = m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].GetStatObj();
if(pBody)
return pBody->m_pSMLSource;
return 0;
}
list2<ShadowMapLightSourceInstance> * CStatObjInst::GetShadowMapCasters()
{
if(!m_pEntityRenderState || !m_pEntityRenderState->pShadowMapInfo)
return 0;
if(!m_pEntityRenderState->pShadowMapInfo->pShadowMapCasters || !m_pEntityRenderState->pShadowMapInfo->pShadowMapCasters->Count())
{
if(m_nObjectTypeID<0 && m_nObjectTypeID >= m_pObjManager->m_lstStaticTypes.Count())
return 0;
CStatObj * pBody = m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].GetStatObj();
if(!m_pEntityRenderState->pShadowMapInfo->pShadowMapCasters)
m_pEntityRenderState->pShadowMapInfo->pShadowMapCasters = new list2<ShadowMapLightSourceInstance>;
else
m_pEntityRenderState->pShadowMapInfo->pShadowMapCasters->Clear();
ShadowMapLightSourceInstance LightSourceInfo;
LightSourceInfo.m_pLS = pBody->m_pSMLSource;
LightSourceInfo.m_vProjTranslation = m_vPos;
LightSourceInfo.m_fProjScale = m_fScale;
LightSourceInfo.m_fDistance = 0;
m_pEntityRenderState->pShadowMapInfo->pShadowMapCasters->Add(LightSourceInfo);
}
// update shadow every frame for nice shadow animations
if(GetCVars()->e_vegetation_update_shadow_every_frame && !m_nRenderStackLevel)
if(m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].bUpdateShadowEveryFrame)
if(float fMaxShadowDist = GetRenderRadius()*GetCVars()->e_shadow_maps_view_dist_ratio)
{
float fDistFade = m_arrfDistance[m_nRenderStackLevel]/fMaxShadowDist;
float fBending = m_fFinalBending * (1.f-fDistFade);
if(fDistFade<0.3333f)
{
CStatObj * pBody = m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].GetStatObj();
if(pBody && pBody->m_pSMLSource && pBody->m_pSMLSource->GetShadowMapFrustum())
{
pBody->m_pSMLSource->GetShadowMapFrustum()->bUpdateRequested = true;
if(fBending > pBody->m_pSMLSource->GetShadowMapFrustum()->m_fBending)
pBody->m_pSMLSource->GetShadowMapFrustum()->m_fBending = fBending;
}
}
}
return m_pEntityRenderState->pShadowMapInfo->pShadowMapCasters;
}
void CStatObjInst::PreloadInstanceResources(Vec3d vPrevPortalPos, float fPrevPortalDistance, float fTime)
{
if(!GetEntityStatObj(0) || !GetEntityStatObj(0)->GetLeafBuffer())
return;
float fDist = fPrevPortalDistance + m_vPos.GetDistance(vPrevPortalPos);
float fMaxViewDist = GetMaxViewDist();
if(fDist<fMaxViewDist && fDist<GetViewCamera().GetZMax())
GetEntityStatObj(0)->PreloadResources(fDist,fTime,0);
}
const char *CStatObjInst::GetName() const
{
return (m_nObjectTypeID>=0 && m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].GetStatObj() )?
m_pObjManager->m_lstStaticTypes[m_nObjectTypeID].GetStatObj()->GetFileName() : "StatObjNotSet";
}

88
Cry3DEngine/Vegetation.h Normal file
View File

@@ -0,0 +1,88 @@
//! Info about instance of static object (trees, rocks),
//! Every sector contain list of such structures
class CStatObjInst : public IEntityRender, public Cry3DEngineBase
{
public:
Vec3d m_vPos;
float m_fScale;
float m_fCurrentBending;
float m_fFinalBending;
IPhysicalEntity * m_pPhysEnt;
uchar m_nObjectTypeID;
uchar m_ucBright;
uchar m_ucLodAngle;
uchar m_ucAngleSlotId;
static CObjManager * m_pObjManager;
static Vec3d m_vAngles;
CStatObjInst()
{
m_nObjectTypeID=0;
m_ucBright=0;
m_ucLodAngle=0;
m_ucAngleSlotId=0;
m_vPos.Set(0,0,0);
m_fScale=0;
m_fCurrentBending=0;
m_fFinalBending=0;
m_pPhysEnt=0;
}
virtual ~CStatObjInst();
void Init( const Vec3d vPos, const int nObjectTypeID, const uchar ucBright, const float fScale )
{
assert(nObjectTypeID<256);
m_vPos = vPos;
m_nObjectTypeID = nObjectTypeID;
m_ucBright = ucBright;
m_fScale = fScale;
m_fCurrentBending=0;
m_fFinalBending=0;
m_pPhysEnt = 0;
m_ucLodAngle = 127;
m_ucAngleSlotId = 255;
}
void SetStatObjGroupId(int nStatObjInstanceGroupId) { m_nObjectTypeID = nStatObjInstanceGroupId; }
const char *GetEntityClassName(void) const { return "StatObjInst"; }
const Vec3d &GetPos(bool) const { return m_vPos; }
const Vec3d &GetAngles(int) const { return m_vAngles; }
float GetScale(void) const { return m_fScale; }
const char *GetName(void) const;
void GetRenderBBox(Vec3d &,Vec3d &);
float GetRenderRadius(void) const;
bool DrawEntity(const SRendParams & rendParams);
bool IsStatic(void) const { return true; }
bool IsEntityHasSomethingToRender(void) { return true; }
bool IsEntityAreasVisible(void) { return true; }
IPhysicalEntity *GetPhysics(void) const { return m_pPhysEnt; }
void SetPhysics(IPhysicalEntity * pPhysEnt) { m_pPhysEnt = pPhysEnt; }
void SetMaterial(IMatInfo *) {}
IMatInfo *GetMaterial(void) const { return 0; }
// bool DrawEntity(const struct SRendParams & _EntDrawParams);//bool bNotAllIN, const CCamera & cam, int nDynLightMaskNoSun, struct VolumeInfo * pFogVolume);
float GetBendingRandomFactor();
float Interpolate(float& pprev, float& prev, float& next, float& nnext, float ppweight, float pweight, float nweight, float nnweight);
void Physicalize( bool bInstant = false );
virtual float GetMaxViewDist();
IStatObj * GetEntityStatObj( unsigned int nSlot, Matrix44 * pMatrix = NULL, bool bReturnOnlyVisible = false);
CStatObj *GetStatObj() const;
virtual void Serialize(bool bSave, ICryPak * pPak, FILE * f);
virtual EERType GetEntityRenderType() { return eERType_Vegetation; }
void Dephysicalize( );
void Dematerialize( );
virtual int GetMemoryUsage();
virtual unsigned int GetRndFlags(); // get flags from StatObjGroup
virtual void SetRndFlags(unsigned int dwFlags); // there is no flags in the instance
virtual void SetRndFlags(unsigned int dwFlags, bool bEnable); // there is no flags in the instance
virtual struct ShadowMapLightSource * GetShadowMapFrustumContainer();
virtual list2<struct ShadowMapLightSourceInstance> * GetShadowMapCasters();
virtual void PreloadInstanceResources(Vec3d vPrevPortalPos, float fPrevPortalDistance, float fTime);
virtual float GetViewDistRatioNormilized();
};

1468
Cry3DEngine/VisAreaMan.cpp Normal file

File diff suppressed because it is too large Load Diff

935
Cry3DEngine/VisAreas.cpp Normal file
View File

@@ -0,0 +1,935 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: statobjmandraw.cpp
// Version: v1.00
// Created: 18/12/2002 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: Visibility areas
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "StatObj.h"
#include "objman.h"
#include "visareas.h"
#include "terrain_sector.h"
#include "3dengine.h"
#include "cbuffer.h"
#include "3dengine.h"
void CVisArea::Update(const Vec3d * pPoints, int nCount, const char * szName, float fHeight, const Vec3d & vAmbientColor, bool bAfectedByOutLights, bool bSkyOnly, const Vec3d & vDynAmbientColor, float fViewDistRatio, bool bDoubleSide, bool bUseDeepness, bool bUseInIndoors)
{
strncpy(m_sName, szName, sizeof(m_sName));
strlwr(m_sName);
m_fHeight = fHeight;
m_vAmbColor = vAmbientColor;
m_vDynAmbColor = vDynAmbientColor;
m_bAfectedByOutLights = bAfectedByOutLights;
m_bSkyOnly = bSkyOnly;
m_fViewDistRatio = fViewDistRatio;
m_bDoubleSide = bDoubleSide;
// m_bUseDeepness = bUseDeepness;
m_bUseInIndoors = bUseInIndoors;
m_lstShapePoints.PreAllocate(nCount,nCount);
if(nCount)
memcpy(&m_lstShapePoints[0], pPoints, sizeof(Vec3d)*nCount);
// update bbox
m_vBoxMax=SetMinBB();
m_vBoxMin=SetMaxBB();
for(int i=0; i<nCount; i++)
{
m_vBoxMax.CheckMax(pPoints[i]);
m_vBoxMin.CheckMin(pPoints[i]);
m_vBoxMax.CheckMax(pPoints[i]+Vec3d(0,0,m_fHeight));
m_vBoxMin.CheckMin(pPoints[i]+Vec3d(0,0,m_fHeight));
}
UpdateGeometryBBox();
}
#define PORTAL_GEOM_BBOX_EXTENT 3.f
void CVisArea::UpdateGeometryBBox()
{
m_vGeomBoxMax = m_vBoxMax;
m_vGeomBoxMin = m_vBoxMin;
if(IsPortal())
{ // fix for big objects passing portal
m_vGeomBoxMax+=Vec3d(PORTAL_GEOM_BBOX_EXTENT,PORTAL_GEOM_BBOX_EXTENT,PORTAL_GEOM_BBOX_EXTENT);
m_vGeomBoxMin-=Vec3d(PORTAL_GEOM_BBOX_EXTENT,PORTAL_GEOM_BBOX_EXTENT,PORTAL_GEOM_BBOX_EXTENT);
}
for(int i=0; i<m_lstEntities[STATIC_ENTITIES].Count(); i++)
if(m_lstEntities[STATIC_ENTITIES][i]->IsStatic())
{
Vec3d vEntBoxMin,vEntBoxMax;
m_lstEntities[STATIC_ENTITIES][i]->GetRenderBBox(vEntBoxMin,vEntBoxMax);
m_vGeomBoxMin.CheckMin(vEntBoxMin);
m_vGeomBoxMax.CheckMax(vEntBoxMax);
}
}
void CVisArea::MarkForStreaming()
{
for(int i=0; i<m_lstEntities[STATIC_ENTITIES].Count(); i++)
{
if(m_lstEntities[STATIC_ENTITIES][i]->GetEntityStatObj(0))
{
((CStatObj*)m_lstEntities[STATIC_ENTITIES][i]->GetEntityStatObj(0))->m_nMarkedForStreamingFrameId = GetFrameID()+100;
// m_lstEntities[STATIC_ENTITIES][i]->CheckPhysicalized();
}
}
}
CVisArea::CVisArea(bool bLoadedAsAreaBox)
{
m_vGeomBoxMin=m_vGeomBoxMax=m_vBoxMin=m_vBoxMax=Vec3d(0,0,0);
m_sName[0]=0;
m_nRndFrameId=-1;
m_bActive=true;
m_nFogVolumeId=0;
m_fHeight=0;
m_vAmbColor(0,0,0);
m_vDynAmbColor(0,0,0);
m_bLoadedAsAreaBox = bLoadedAsAreaBox;
m_vConnNormals[0]=m_vConnNormals[1]=Vec3d(0,0,0);
m_bAfectedByOutLights = false;
m_fDistance=0;
m_bSkyOnly=false;
m_pOcclCamera=0;
m_fViewDistRatio = 100.f;
m_bDoubleSide = true;
// m_bUseDeepness = false;
m_bUseInIndoors = false;
memset(m_arrvActiveVerts,0,sizeof(m_arrvActiveVerts));
}
CVisArea::~CVisArea()
{
Unload();
UnregisterDynamicEntities();
delete m_pOcclCamera;
m_pOcclCamera=0;
/*
for(int nStatic=0; nStatic<2; nStatic++)
for(int i=0; i<m_lstEntities[nStatic].Count(); i++)
if(m_lstEntities[nStatic][i]->m_pVisArea==this)
m_lstEntities[nStatic][i]->m_pVisArea=0;
*/
}
bool InsidePolygon(Vec3 *polygon,int N,Vec3 p)
{
int counter = 0;
int i;
double xinters;
Vec3 p1,p2;
p1 = polygon[0];
for (i=1;i<=N;i++) {
p2 = polygon[i % N];
if (p.y > min(p1.y,p2.y)) {
if (p.y <= max(p1.y,p2.y)) {
if (p.x <= max(p1.x,p2.x)) {
if (p1.y != p2.y) {
xinters = (p.y-p1.y)*(p2.x-p1.x)/(p2.y-p1.y)+p1.x;
if (p1.x == p2.x || p.x <= xinters)
counter++;
}
}
}
}
p1 = p2;
}
if (counter % 2 == 0)
return(false);
else
return(true);
}
bool CVisArea::IsPointInsideVisArea(const Vec3d & vPos)
{
if(Overlap::Point_AABB(vPos, m_vBoxMin, m_vBoxMax))
if(InsidePolygon(&m_lstShapePoints[0], m_lstShapePoints.Count(), vPos))
return true;
return false;
}
bool CVisArea::FindVisArea(IVisArea * pAnotherArea, int nMaxReqursion, bool bSkipDisabledPortals)
{ // todo: avoid going into parent
if(pAnotherArea == this)
return true;
if(nMaxReqursion>0)
for(int p=0; p<m_lstConnections.Count(); p++)
if(!bSkipDisabledPortals || m_lstConnections[p]->IsActive())
if(m_lstConnections[p]->FindVisArea(pAnotherArea, nMaxReqursion-1, bSkipDisabledPortals))
return true;
return false;
}
bool CVisArea::PreloadVisArea(int nMaxReqursion, bool * pbOutdoorFound, CVisArea * pParentToAvoid, Vec3d vPrevPortalPos, float fPrevPortalDistance)
{
FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE );
if(IsPortal())
{
fPrevPortalDistance += vPrevPortalPos.GetDistance((m_vBoxMin+m_vBoxMax)*0.5f);
vPrevPortalPos = (m_vBoxMin+m_vBoxMax)*0.5f;
}
PreloadResources(vPrevPortalPos, fPrevPortalDistance);
if(IsConnectedToOutdoor())
*pbOutdoorFound = true;
if(nMaxReqursion>0)
for(int p=0; p<m_lstConnections.Count(); p++)
if(m_lstConnections[p] != pParentToAvoid)
if(GetCurTimeSec()>(m_fPreloadStartTime+0.010f)||
m_lstConnections[p]->PreloadVisArea(nMaxReqursion-1, pbOutdoorFound, this, vPrevPortalPos, fPrevPortalDistance))
return true;
return false;
}
int CVisArea::GetVisFrameId()
{
return m_nRndFrameId;
}
bool CVisArea::IsConnectedToOutdoor()
{
if(IsPortal()) // check if this portal has just one conection
return m_lstConnections.Count()==1;
// find portals with just one conection
for(int p=0; p<m_lstConnections.Count(); p++)
{
CVisArea * pPortal = m_lstConnections[p];
if(pPortal->m_lstConnections.Count()==1)
return true;
}
return false;
}
bool Is2dLinesIntersect(float x1,float y1,float x2,float y2,float x3,float y3,float x4,float y4)
{
float ua = ((x4-x3)*(y1-y3)-(y4-y3)*(x1-x3))/((y4-y3)*(x2-x1)-(x4-x3)*(y2-y1));
float ub = ((x2-x1)*(y1-y3)-(y2-y1)*(x1-x3))/((y4-y3)*(x2-x1)-(x4-x3)*(y2-y1));
return ua>0 && ua<1 && ub>0 && ub<1;
}
Vec3d CVisArea::GetConnectionNormal(CVisArea * pPortal)
{
// if(strstr(pPortal->m_sName,"ab09_portal11"))
// int t=0;
assert(m_lstShapePoints.Count()>=3);
// find side of shape intersecting with portal
int nIntersNum = 0;
Vec3d arrNormals[2]={Vec3d(0,0,0),Vec3d(0,0,0)};
for(int v=0; v<m_lstShapePoints.Count(); v++)
{
nIntersNum=0;
arrNormals[0]=Vec3d(0,0,0);
arrNormals[1]=Vec3d(0,0,0);
for(int p=0; p<pPortal->m_lstShapePoints.Count(); p++)
{
const Vec3d & v0 = m_lstShapePoints[v];
const Vec3d & v1 = m_lstShapePoints[(v+1)%m_lstShapePoints.Count()];
const Vec3d & p0 = pPortal->m_lstShapePoints[p];
const Vec3d & p1 = pPortal->m_lstShapePoints[(p+1)%pPortal->m_lstShapePoints.Count()];
if(Is2dLinesIntersect(v0.x,v0.y,v1.x,v1.y,p0.x,p0.y,p1.x,p1.y))
{
Vec3d vNormal = GetNormalized(v0-v1).Cross(Vec3d(0,0,1.f));
if(nIntersNum<2)
arrNormals[nIntersNum++] = (IsShapeClockwise()) ? -vNormal : vNormal;
}
}
if(nIntersNum==2)
break;
}
if(nIntersNum == 2 &&
//IsEquivalent(arrNormals[0] == arrNormals[1])
IsEquivalent(arrNormals[0],arrNormals[1],VEC_EPSILON)
)
return arrNormals[0];
{
int nBottomPoints=0;
for(int p=0; p<pPortal->m_lstShapePoints.Count() && p<4; p++)
if(IsPointInsideVisArea(pPortal->m_lstShapePoints[p]))
nBottomPoints++;
int nUpPoints=0;
for(int p=0; p<pPortal->m_lstShapePoints.Count() && p<4; p++)
if(IsPointInsideVisArea(pPortal->m_lstShapePoints[p]+Vec3d(0,0,pPortal->m_fHeight)))
nUpPoints++;
if(nBottomPoints==0 && nUpPoints==4)
return Vec3d(0,0,1);
if(nBottomPoints==4 && nUpPoints==0)
return Vec3d(0,0,-1);
}
return Vec3d(0,0,0);
}
bool CVisArea::UpdatePortalCameraScissor(CCamera & cam, list2<Vec3d> * lstVerts, bool bMergeFrustums)
{
IRenderer * pRend = GetRenderer();
CVars * pCVars = GetCVars();
Vec3d arrScreenSpacePos[8];
memset(arrScreenSpacePos,0,sizeof(arrScreenSpacePos));
for(int i=0; i<lstVerts->Count() && i<8; i++)
{ // result is in range from 0 to 100
const Vec3d & v3d = lstVerts->GetAt(i);
if(pCVars->e_portals == 4)
pRend->Draw3dBBox(v3d-Vec3d(0.1f,0.1f,0.1f),v3d+Vec3d(0.1f,0.1f,0.1f));
pRend->ProjectToScreen(v3d.x, v3d.y, v3d.z,
&arrScreenSpacePos[i].x, &arrScreenSpacePos[i].y, &arrScreenSpacePos[i].z);
arrScreenSpacePos[i].x = arrScreenSpacePos[i].x*pRend->GetWidth()/100.f;
arrScreenSpacePos[i].y = arrScreenSpacePos[i].y*pRend->GetHeight()/100.f;
}
// find 2d bounds in screen space
Vec3d vMin2d = arrScreenSpacePos[0], vMax2d = arrScreenSpacePos[0];
for(int i=0; i<lstVerts->Count() && i<8; i++)
{
if(arrScreenSpacePos[i].x < vMin2d.x)
vMin2d.x = arrScreenSpacePos[i].x;
if(arrScreenSpacePos[i].x > vMax2d.x)
vMax2d.x = arrScreenSpacePos[i].x;
if(arrScreenSpacePos[i].y < vMin2d.y)
vMin2d.y = arrScreenSpacePos[i].y;
if(arrScreenSpacePos[i].y > vMax2d.y)
vMax2d.y = arrScreenSpacePos[i].y;
}
vMin2d.x = max(vMin2d.x,0);
vMin2d.y = max(vMin2d.y,0);
vMax2d.x = min(vMax2d.x,GetRenderer()->GetWidth());
vMax2d.y = min(vMax2d.y,GetRenderer()->GetHeight());
if(vMax2d.x <= vMin2d.x || vMax2d.y < vMin2d.y)
return false;
assert(vMin2d.x>=0 && vMin2d.x<=GetRenderer()->GetWidth());
assert(vMin2d.y>=0 && vMin2d.y<=GetRenderer()->GetHeight());
assert(vMax2d.x>=0 && vMax2d.x<=GetRenderer()->GetWidth());
assert(vMax2d.y>=0 && vMax2d.y<=GetRenderer()->GetHeight());
cam.m_ScissorInfo.x1 = ushort(vMin2d.x);
cam.m_ScissorInfo.y1 = ushort(vMin2d.y);
cam.m_ScissorInfo.x2 = ushort(vMax2d.x);
cam.m_ScissorInfo.y2 = ushort(vMax2d.y);
if(GetCVars()->e_scissor_debug)
{
float color[] = {1,0,0,1};
pRend->Draw2dLabel(vMax2d.x, vMax2d.y, 2 , color, false, "br");
pRend->Draw2dLabel(vMin2d.x, vMax2d.y, 2 , color, false, "bl");
pRend->Draw2dLabel(vMax2d.x, vMin2d.y, 2 , color, false, "tr");
pRend->Draw2dLabel(vMin2d.x, vMin2d.y, 2 , color, false, "tl");
}
return true;
}
void CVisArea::UpdatePortalCameraPlanes(CCamera & cam, Vec3d * pVerts, bool bMergeFrustums)
{ // todo: do also take into account GetViewCamera()
Vec3d vCamPos = GetViewCamera().GetPos();
Plane plane;
plane.CalcPlane(pVerts[0],pVerts[1],pVerts[2]);
cam.SetFrustumPlane(FR_PLANE_NEAR, plane);
plane = *GetViewCamera().GetFrustumPlane(FR_PLANE_FAR);
cam.SetFrustumPlane(FR_PLANE_FAR, plane);
plane.CalcPlane(vCamPos,pVerts[2],pVerts[3]); // update plane only if it reduces fov
if(!bMergeFrustums || plane.n.Dot(cam.GetFrustumPlane(FR_PLANE_LEFT)->n)<
cam.GetFrustumPlane(FR_PLANE_RIGHT)->n.Dot(cam.GetFrustumPlane(FR_PLANE_LEFT)->n))
cam.SetFrustumPlane(FR_PLANE_RIGHT, plane);
plane.CalcPlane(vCamPos,pVerts[0],pVerts[1]); // update plane only if it reduces fov
if(!bMergeFrustums || plane.n.Dot(cam.GetFrustumPlane(FR_PLANE_RIGHT)->n)<
cam.GetFrustumPlane(FR_PLANE_LEFT)->n.Dot(cam.GetFrustumPlane(FR_PLANE_RIGHT)->n))
cam.SetFrustumPlane(FR_PLANE_LEFT, plane);
plane.CalcPlane(vCamPos,pVerts[3],pVerts[0]); // update plane only if it reduces fov
if(!bMergeFrustums || plane.n.Dot(cam.GetFrustumPlane(FR_PLANE_TOP)->n)<
cam.GetFrustumPlane(FR_PLANE_BOTTOM)->n.Dot(cam.GetFrustumPlane(FR_PLANE_TOP)->n))
cam.SetFrustumPlane(FR_PLANE_BOTTOM, plane);
plane.CalcPlane(vCamPos,pVerts[1],pVerts[2]); // update plane only if it reduces fov
if(!bMergeFrustums || plane.n.Dot(cam.GetFrustumPlane(FR_PLANE_BOTTOM)->n)<
cam.GetFrustumPlane(FR_PLANE_TOP)->n.Dot(cam.GetFrustumPlane(FR_PLANE_BOTTOM)->n))
cam.SetFrustumPlane(FR_PLANE_TOP, plane);
Vec3d arrvPortVertsCamSpace[4];
for(int i=0; i<4; i++)
arrvPortVertsCamSpace[i] = pVerts[i]-cam.GetPos();
cam.SetFrustumVertices(arrvPortVertsCamSpace);
if(GetCVars()->e_portals==4)
{
float farrColor[4] = {1,1,1,1};
// GetRenderer()->SetMaterialColor(1,1,1,1);
GetRenderer()->Draw3dBBox(pVerts[0],pVerts[1],DPRIM_LINE);
GetRenderer()->DrawLabelEx(pVerts[0],1,farrColor,false,true,"0");
GetRenderer()->Draw3dBBox(pVerts[1],pVerts[2],DPRIM_LINE);
GetRenderer()->DrawLabelEx(pVerts[1],1,farrColor,false,true,"1");
GetRenderer()->Draw3dBBox(pVerts[2],pVerts[3],DPRIM_LINE);
GetRenderer()->DrawLabelEx(pVerts[2],1,farrColor,false,true,"2");
GetRenderer()->Draw3dBBox(pVerts[3],pVerts[0],DPRIM_LINE);
GetRenderer()->DrawLabelEx(pVerts[3],1,farrColor,false,true,"3");
}
}
int __cdecl CVisAreaManager__CmpDistToPortal(const void* v1, const void* v2);
void CVisArea::DrawVolume(CObjManager * pObjManager, int nReqursionLevel,
CCamera CurCamera, CVisArea * pParent, CVisArea * pCurPortal,
bool * pbOutdoorVisible, list2<CCamera> * plstOutPortCameras, bool * pbSkyVisible)
{
IRenderer * pRenderer = GetRenderer();
// mark as rendered
if(!pObjManager->m_nRenderStackLevel)
m_nRndFrameId = GetFrameID();
// get area light mask
Vec3d vCenter = (m_vBoxMin+m_vBoxMax)*0.5f;
float fRadius = (m_vBoxMax-m_vBoxMin).Length()*0.5f;
int nDLMask = Get3DEngine()->GetLightMaskFromPosition(vCenter, fRadius);
// todo: prepare flag once
bool bThisIsPortal = strstr(m_sName,"portal") != 0;
// remove sun bit if it not allowed on exit portal geometry
if(!bThisIsPortal || !m_bAfectedByOutLights || m_lstConnections.Count()!=1)
for(int nId=0; nId<32; nId++)
{
if(nDLMask & (1<<nId))
{
CDLight * pDLight = (CDLight*)pRenderer->EF_Query(EFQ_LightSource, nId);
if(pDLight && pDLight->m_Flags & DLF_SUN)
{
nDLMask = nDLMask & ~(1<<nId);
break;
}
if(!pObjManager->m_nRenderStackLevel) // light scissor can not be shared between reqursion levels because same CDlight objects are used
if(pDLight && pDLight->m_Flags & DLF_THIS_AREA_ONLY && pDLight->m_pOwner)
if(pDLight->m_pOwner->GetEntityVisArea() == this)
{
if(!pDLight->m_sWidth || pDLight->m_sWidth == (CurCamera.m_ScissorInfo.x2-CurCamera.m_ScissorInfo.x1))
{ // first time - set
pDLight->m_sX = CurCamera.m_ScissorInfo.x1;
pDLight->m_sY = CurCamera.m_ScissorInfo.y1;
pDLight->m_sWidth = CurCamera.m_ScissorInfo.x2-CurCamera.m_ScissorInfo.x1;
pDLight->m_sHeight = CurCamera.m_ScissorInfo.y2-CurCamera.m_ScissorInfo.y1;
}
else
{ // not first time - merge
int nMaxX = max(pDLight->m_sX + pDLight->m_sWidth, CurCamera.m_ScissorInfo.x2);
int nMaxY = max(pDLight->m_sY + pDLight->m_sHeight, CurCamera.m_ScissorInfo.y2);
pDLight->m_sX = min(pDLight->m_sX, CurCamera.m_ScissorInfo.x1);
pDLight->m_sY = min(pDLight->m_sY, CurCamera.m_ScissorInfo.y1);
pDLight->m_sWidth = nMaxX - pDLight->m_sX;
pDLight->m_sHeight = nMaxY - pDLight->m_sY;
}
}
}
}
// render area statics
DrawEntities( m_nFogVolumeId, nDLMask, 0, CurCamera,
m_lstShapePoints.Count() ? &m_vAmbColor : 0, m_lstShapePoints.Count() ? &m_vDynAmbColor : 0,
NULL, true, 0, pObjManager,
IsPointInsideVisArea(GetViewCamera().GetPos()), "", STATIC_ENTITIES);
// render area entities
DrawEntities( m_nFogVolumeId, nDLMask, 0, CurCamera,
m_lstShapePoints.Count() ? &m_vAmbColor : 0, m_lstShapePoints.Count() ? &m_vDynAmbColor : 0,
NULL, true, 0, pObjManager,
IsPointInsideVisArea(GetViewCamera().GetPos()), "", DYNAMIC_ENTITIES);
// limit recursion and portal activity
if(!nReqursionLevel || !m_bActive)
return;
if( bThisIsPortal && m_lstConnections.Count()==1 && // detect entrance
!IsPointInsideVisArea(GetViewCamera().GetPos()) && // detect camera in outdoors
!CurCamera.IsAABBVisibleFast( AABB(m_vGeomBoxMin,m_vGeomBoxMax) )) // if invisible
return; // stop recursion
bool bScisorValid = true;
// prepare new camera for next areas
if(bThisIsPortal && m_lstConnections.Count() && (this!=pCurPortal || !pCurPortal->IsPointInsideVisArea(CurCamera.GetPos())))
{
Vec3d vPortNorm = (!pParent || pParent == m_lstConnections[0] || m_lstConnections.Count()==1) ?
m_vConnNormals[0] : m_vConnNormals[1];
// exit/entrance portal has only one normal in direction to outdoors, so flip it to the camera
if(m_lstConnections.Count()==1 && !pParent)
vPortNorm = -vPortNorm;
// back face check
Vec3d vPortToCamDir = CurCamera.GetPos() - (m_vBoxMin+m_vBoxMax)*0.5f;
if(vPortToCamDir.Dot(vPortNorm)<0)
return;
if(!m_bDoubleSide)
if(vPortToCamDir.Dot(m_vConnNormals[0])<0)
return;
Vec3d arrPortVerts[4];
Vec3d arrPortVertsOtherSide[4];
bool barrPortVertsOtherSideValid = false;
if(pParent && !IsEquivalent(vPortNorm,Vec3d(0,0,0),VEC_EPSILON) && vPortNorm.z)
{ // up/down portal
int nEven = IsShapeClockwise();
if(vPortNorm.z>0)
nEven=!nEven;
for(int i=0; i<4; i++)
{
arrPortVerts[i] = m_lstShapePoints[nEven ? (3-i) : i]+Vec3d(0,0,m_fHeight)*(vPortNorm.z>0);
arrPortVertsOtherSide[i] = m_lstShapePoints[nEven ? (3-i) : i]+Vec3d(0,0,m_fHeight)*(vPortNorm.z<0);
}
barrPortVertsOtherSideValid = true;
}
else if(!IsEquivalent(vPortNorm,Vec3d(0,0,0),VEC_EPSILON) && vPortNorm.z==0)
{ // basic portal
Vec3d arrInAreaPoint[2]={Vec3d(0,0,0),Vec3d(0,0,0)};
int arrInAreaPointId[2]={-1,-1};
int nInAreaPointCounter=0;
// find 2 points of portal in this area (or in this outdoors)
for(int i=0; i<m_lstShapePoints.Count() && nInAreaPointCounter<2; i++)
{
Vec3d vTestPoint = m_lstShapePoints[i]+Vec3d(0,0,m_fHeight*0.5f);
CVisArea * pAnotherArea = m_lstConnections[0];
if((pParent && (pParent->IsPointInsideVisArea(vTestPoint))) ||
(!pParent && (!pAnotherArea->IsPointInsideVisArea(vTestPoint))) )
{
arrInAreaPointId[nInAreaPointCounter] = i;
arrInAreaPoint[nInAreaPointCounter++] = m_lstShapePoints[i];
}
}
if(nInAreaPointCounter==2)
{ // success, take into account volume and portal shape versts order
int nEven = IsShapeClockwise();
if(arrInAreaPointId[1]-arrInAreaPointId[0] != 1)
nEven = !nEven;
arrPortVerts[0] = arrInAreaPoint[nEven];
arrPortVerts[1] = arrInAreaPoint[nEven]+Vec3d(0,0,m_fHeight);
arrPortVerts[2] = arrInAreaPoint[!nEven]+Vec3d(0,0,m_fHeight);
arrPortVerts[3] = arrInAreaPoint[!nEven];
nEven = !nEven;
arrPortVertsOtherSide[0] = arrInAreaPoint[nEven];
arrPortVertsOtherSide[1] = arrInAreaPoint[nEven]+Vec3d(0,0,m_fHeight);
arrPortVertsOtherSide[2] = arrInAreaPoint[!nEven]+Vec3d(0,0,m_fHeight);
arrPortVertsOtherSide[3] = arrInAreaPoint[!nEven];
barrPortVertsOtherSideValid = true;
}
else
{ // something wrong
Warning(0,0,"CVisArea::DrawVolume: Invalid portal: %s", m_sName);
return;
}
}
else if(!pParent && vPortNorm.z==0 && m_lstConnections.Count()==1)
{ // basic entrance portal
Vec3d vBorder = GetNormalized(vPortNorm.Cross(Vec3d(0,0,1.f)))*fRadius;
arrPortVerts[0] = vCenter - Vec3d(0,0,1.f)*fRadius - vBorder;
arrPortVerts[1] = vCenter + Vec3d(0,0,1.f)*fRadius - vBorder;
arrPortVerts[2] = vCenter + Vec3d(0,0,1.f)*fRadius + vBorder;
arrPortVerts[3] = vCenter - Vec3d(0,0,1.f)*fRadius + vBorder;
}
else if(!pParent && vPortNorm.z!=0 && m_lstConnections.Count()==1)
{ // up/down entrance portal
Vec3d vBorder = GetNormalized(vPortNorm.Cross(Vec3d(0,1,0.f)))*fRadius;
arrPortVerts[0] = vCenter - Vec3d(0,1,0.f)*fRadius + vBorder;
arrPortVerts[1] = vCenter + Vec3d(0,1,0.f)*fRadius + vBorder;
arrPortVerts[2] = vCenter + Vec3d(0,1,0.f)*fRadius - vBorder;
arrPortVerts[3] = vCenter - Vec3d(0,1,0.f)*fRadius - vBorder;
}
else
{ // something wrong or areabox portal - use simple solution
if(
//vPortNorm == Vec3d(0,0,0)
IsEquivalent(vPortNorm,Vec3d(0,0,0),VEC_EPSILON)
)
vPortNorm = GetNormalized((vCenter - GetViewCamera().GetPos()));
Vec3d vBorder = GetNormalized(vPortNorm.Cross(Vec3d(0,0,1.f)))*fRadius;
arrPortVerts[0] = vCenter - Vec3d(0,0,1.f)*fRadius - vBorder;
arrPortVerts[1] = vCenter + Vec3d(0,0,1.f)*fRadius - vBorder;
arrPortVerts[2] = vCenter + Vec3d(0,0,1.f)*fRadius + vBorder;
arrPortVerts[3] = vCenter - Vec3d(0,0,1.f)*fRadius + vBorder;
}
if(GetCVars()->e_portals==4) // make color reqursion dependent
GetRenderer()->SetMaterialColor(1,1,pObjManager->m_nRenderStackLevel==0,1);
CCamera camParent = CurCamera;
UpdatePortalCameraPlanes(CurCamera, arrPortVerts, vPortNorm.z==0);
static list2<Vec3d> lstPortVertsClipped; // Timur, keep this list static so it is not reallocated every time.
lstPortVertsClipped.Clear();
lstPortVertsClipped.AddList(arrPortVerts, 4);
ClipPortalVerticesByCameraFrustum(&lstPortVertsClipped, camParent);
bScisorValid = UpdatePortalCameraScissor(CurCamera, &lstPortVertsClipped, vPortNorm.z==0);
if(bScisorValid && barrPortVertsOtherSideValid)
{
Vec3d vOtherSizeBoxMax = SetMinBB();
Vec3d vOtherSizeBoxMin = SetMaxBB();
for(int i=0; i<4; i++)
{
vOtherSizeBoxMin.CheckMin(arrPortVertsOtherSide[i]-Vec3d(0.01f,0.01f,0.01f));
vOtherSizeBoxMax.CheckMax(arrPortVertsOtherSide[i]+Vec3d(0.01f,0.01f,0.01f));
}
bScisorValid = CurCamera.IsAABBVisible_exact(AABB(vOtherSizeBoxMin,vOtherSizeBoxMax));
}
if(bScisorValid && pParent && m_lstConnections.Count()==1)
{ // set this camera for outdoor
if(nReqursionLevel>=1)
{
if(!m_bSkyOnly)
{
if(plstOutPortCameras)
{
plstOutPortCameras->Add(CurCamera);
plstOutPortCameras->Last().m_pPortal = this;
}
if(pbOutdoorVisible)
*pbOutdoorVisible = true;
}
else if(pbSkyVisible)
*pbSkyVisible = true;
}
return;
}
}
// sort portals by distance
if(!bThisIsPortal && m_lstConnections.Count())
{
for(int p=0; p<m_lstConnections.Count(); p++)
{
CVisArea * pNeibVolume = m_lstConnections[p];
pNeibVolume->m_fDistance = CurCamera.GetPos().GetDistance((pNeibVolume->m_vBoxMin+pNeibVolume->m_vBoxMax)*0.5f);
}
qsort(&m_lstConnections[0], m_lstConnections.Count(),
sizeof(m_lstConnections[0]), CVisAreaManager__CmpDistToPortal);
}
float fZoomFactor = 0.2f+0.8f*(RAD2DEG(CurCamera.GetFov())/90.f);
// recurse to connetions
for(int p=0; p<m_lstConnections.Count(); p++)
{
CVisArea * pNeibVolume = m_lstConnections[p];
if(pNeibVolume != pParent)
{
if(!bThisIsPortal)
{ // skip far portals
float fRadius = (pNeibVolume->m_vBoxMax-pNeibVolume->m_vBoxMin).Length()*0.5f;
if(pNeibVolume->m_fDistance*fZoomFactor > fRadius*pNeibVolume->m_fViewDistRatio)
continue;
}
if((bScisorValid || m_lstConnections.Count()==1) && (bThisIsPortal || CurCamera.IsAABBVisibleFast( AABB(pNeibVolume->m_vGeomBoxMin,pNeibVolume->m_vGeomBoxMax) )))
pNeibVolume->DrawVolume(pObjManager, nReqursionLevel-1, CurCamera, this, pCurPortal, pbOutdoorVisible, plstOutPortCameras, pbSkyVisible);
else
pNeibVolume->DrawVolume_NotThisAreaOnlyLights(pObjManager, nReqursionLevel-1, CurCamera, this, pCurPortal, pbOutdoorVisible, plstOutPortCameras, pbSkyVisible);
}
}
}
//! return list of visareas connected to specified visarea (can return portals and sectors)
int CVisArea::GetRealConnections(IVisArea ** pAreas, int nMaxConnNum, bool bSkipDisabledPortals)
{
int nOut = 0;
for(int nArea=0; nArea<m_lstConnections.Count(); nArea++)
{
if(nOut<nMaxConnNum)
pAreas[nOut] = (IVisArea*)m_lstConnections[nArea];
nOut++;
}
return nOut;
}
//! return list of sectors conected to specified sector or portal (returns sectors only)
// todo: change the way it returns data
int CVisArea::GetVisAreaConnections(IVisArea ** pAreas, int nMaxConnNum, bool bSkipDisabledPortals)
{
int nOut = 0;
if(IsPortal())
{
/* for(int nArea=0; nArea<m_lstConnections.Count(); nArea++)
{
if(nOut<nMaxConnNum)
pAreas[nOut] = (IVisArea*)m_lstConnections[nArea];
nOut++;
}*/
return min(nMaxConnNum,GetRealConnections(pAreas, nMaxConnNum, bSkipDisabledPortals));
}
else
{
for(int nPort=0; nPort<m_lstConnections.Count(); nPort++)
{
CVisArea * pPortal = m_lstConnections[nPort];
assert(pPortal->IsPortal());
for(int nArea=0; nArea<pPortal->m_lstConnections.Count(); nArea++)
{
if(pPortal->m_lstConnections[nArea]!=this)
if(!bSkipDisabledPortals || pPortal->IsActive())
{
if(nOut<nMaxConnNum)
pAreas[nOut] = (IVisArea*)pPortal->m_lstConnections[nArea];
nOut++;
break; // take first valid connection
}
}
}
}
return min(nMaxConnNum,nOut);
}
bool CVisArea::IsPortalValid()
{
if(m_lstConnections.Count()>2 || m_lstConnections.Count()==0)
return false;
for(int i=0; i<m_lstConnections.Count(); i++)
if(IsEquivalent(m_vConnNormals[i],Vec3d(0,0,0),VEC_EPSILON))
return false;
if(m_lstConnections.Count()>1)
if( m_vConnNormals[0].Dot(m_vConnNormals[1])>-0.99f )
return false;
return true;
}
bool CVisArea::IsPortalIntersectAreaInValidWay(CVisArea * pPortal)
{
const Vec3d & v1Min = pPortal->m_vBoxMin;
const Vec3d & v1Max = pPortal->m_vBoxMax;
const Vec3d & v2Min = m_vBoxMin;
const Vec3d & v2Max = m_vBoxMax;
if(v1Max.x>v2Min.x && v2Max.x>v1Min.x)
if(v1Max.y>v2Min.y && v2Max.y>v1Min.y)
if(v1Max.z>v2Min.z && v2Max.z>v1Min.z)
{
// vertical portal
for(int v=0; v<m_lstShapePoints.Count(); v++)
{
int nIntersNum=0;
bool arrIntResult[4] = { 0,0,0,0 };
for(int p=0; p<pPortal->m_lstShapePoints.Count() && p<4; p++)
{
const Vec3d & v0 = m_lstShapePoints[v];
const Vec3d & v1 = m_lstShapePoints[(v+1)%m_lstShapePoints.Count()];
const Vec3d & p0 = pPortal->m_lstShapePoints[p];
const Vec3d & p1 = pPortal->m_lstShapePoints[(p+1)%pPortal->m_lstShapePoints.Count()];
if(Is2dLinesIntersect(v0.x,v0.y,v1.x,v1.y,p0.x,p0.y,p1.x,p1.y))
{
nIntersNum++;
arrIntResult[p] = true;
}
}
if(nIntersNum==2 && arrIntResult[0]==arrIntResult[2] && arrIntResult[1]==arrIntResult[3])
return true;
}
// horisontal portal
{
int nBottomPoints=0, nUpPoints=0;
for(int p=0; p<pPortal->m_lstShapePoints.Count() && p<4; p++)
if(IsPointInsideVisArea(pPortal->m_lstShapePoints[p]))
nBottomPoints++;
for(int p=0; p<pPortal->m_lstShapePoints.Count() && p<4; p++)
if(IsPointInsideVisArea(pPortal->m_lstShapePoints[p]+Vec3d(0,0,pPortal->m_fHeight)))
nUpPoints++;
if(nBottomPoints==0 && nUpPoints==4)
return true;
if(nBottomPoints==4 && nUpPoints==0)
return true;
}
}
return false;
}
bool CVisArea::IsPortal()
{
bool bThisIsPortal = strstr(m_sName,"portal") != 0;
return bThisIsPortal;
}
/*
void CVisArea::SetTreeId(int nTreeId)
{
if(m_nTreeId == nTreeId)
return;
m_nTreeId = nTreeId;
for(int p=0; p<m_lstConnections.Count(); p++)
m_lstConnections[p]->SetTreeId(nTreeId);
}
*/
bool CVisArea::IsShapeClockwise()
{
float fClockWise =
(m_lstShapePoints[0].x-m_lstShapePoints[1].x)*(m_lstShapePoints[2].y-m_lstShapePoints[1].y)-
(m_lstShapePoints[0].y-m_lstShapePoints[1].y)*(m_lstShapePoints[2].x-m_lstShapePoints[1].x);
return fClockWise>0;
}
void CVisArea::DrawAreaBoundsIntoCBuffer(CCoverageBuffer * pCBuffer)
{
if(m_lstShapePoints.Count()!=4)
return;
Vec3d arrVerts[8];
int arrIndices[24];
int v=0;
int i=0;
for(int p=0; p<4 && p<m_lstShapePoints.Count(); p++)
{
arrVerts[v++] = m_lstShapePoints[p];
arrVerts[v++] = m_lstShapePoints[p] + Vec3d(0,0,m_fHeight);
arrIndices[i++] = (p*2+0)%8;
arrIndices[i++] = (p*2+1)%8;
arrIndices[i++] = (p*2+2)%8;
arrIndices[i++] = (p*2+3)%8;
arrIndices[i++] = (p*2+2)%8;
arrIndices[i++] = (p*2+1)%8;
}
Matrix44 mat;
mat.SetIdentity();
pCBuffer->AddMesh(arrVerts,8,arrIndices,24,&mat);
}
void CVisArea::ClipPortalVerticesByCameraFrustum(list2<Vec3d> * pPolygon, const CCamera & cam)
{
CCoverageBuffer::ClipPolygon(pPolygon, *cam.GetFrustumPlane(FR_PLANE_RIGHT));
CCoverageBuffer::ClipPolygon(pPolygon, *cam.GetFrustumPlane(FR_PLANE_LEFT));
CCoverageBuffer::ClipPolygon(pPolygon, *cam.GetFrustumPlane(FR_PLANE_TOP));
CCoverageBuffer::ClipPolygon(pPolygon, *cam.GetFrustumPlane(FR_PLANE_BOTTOM));
}
void CVisArea::GetMemoryUsage(ICrySizer*pSizer)
{
pSizer->AddContainer(m_lstEntities[STATIC_ENTITIES]);
pSizer->AddContainer(m_lstEntities[DYNAMIC_ENTITIES]);
int nSize=0;
for(int nStatic=0; nStatic<2; nStatic++)
for(int i=0; i<m_lstEntities[nStatic].Count(); i++)
nSize += m_lstEntities[nStatic][i]->GetMemoryUsage();
pSizer->AddObject(this,sizeof(*this)+nSize);
}
void CVisArea::DrawVolume_NotThisAreaOnlyLights(CObjManager * pObjManager, int nReqursionLevel, CCamera CurCamera, CVisArea * pParent, CVisArea * pCurPortal, bool * pbOutdoorVisible, list2<CCamera> * plstOutPortCameras, bool * pbSkyVisible)
{
if(!pParent)
return;
IRenderer * pRenderer = GetRenderer();
// mark as rendered
m_nRndFrameId = GetFrameID();
// render lsources
{
for( int i=0; i<m_lstEntities[DYNAMIC_ENTITIES].Count(); i++ )
{
IEntityRender * pEntityRender = m_lstEntities[DYNAMIC_ENTITIES].GetAt(i);
CDLight * pLight = pEntityRender->GetLight();
if(pLight && !(pLight->m_Flags & DLF_THIS_AREA_ONLY))
{ // process light sources
Vec3d vBoxMin,vBoxMax;
pEntityRender->GetRenderBBox(vBoxMin,vBoxMax);
if( AABB(pParent->m_vBoxMin,pParent->m_vBoxMax).IsIntersectBox( AABB(vBoxMin,vBoxMax)))
pObjManager->RenderObject( pEntityRender, 0, 0, false, CurCamera, 0, 0, 0, true,
pEntityRender->GetMaxViewDist());
}
else if(pEntityRender->GetRndFlags() & ERF_DONOTCHECKVIS)
{ // process 1p weapon
pEntityRender->m_fWSMaxViewDist = pEntityRender->GetMaxViewDist();
uint nDLightMask = ((C3DEngine*)Get3DEngine())->GetFullLightMask();
pObjManager->RenderObject( pEntityRender, m_nFogVolumeId,
nDLightMask, false, CurCamera, &m_vAmbColor, &m_vDynAmbColor, 0, true,
pEntityRender->m_fWSMaxViewDist);
}
}
}
// todo: prepare flag once
bool bThisIsPortal = strstr(m_sName,"portal") != 0;
if(bThisIsPortal && nReqursionLevel>0)
{ // recurse to not rendered connetions
for(int p=0; p<m_lstConnections.Count(); p++)
{
CVisArea * pNeibVolume = m_lstConnections[p];
if(pNeibVolume != pParent)
{
pNeibVolume->DrawVolume_NotThisAreaOnlyLights(pObjManager, nReqursionLevel-1, CurCamera, this, pCurPortal, pbOutdoorVisible, plstOutPortCameras, pbSkyVisible);
break;
}
}
}
}

129
Cry3DEngine/VisAreas.h Normal file
View File

@@ -0,0 +1,129 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: visareas.h
// Version: v1.00
// Created: 18/12/2002 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: visibility areas header
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#ifndef VisArea_H
#define VisArea_H
#include "basicarea.h"
struct CVisArea : public CBasicArea, public IVisArea
{
// editor interface
virtual void Update(const Vec3d * pPoints, int nCount, const char * szName, float fHeight, const Vec3d & vAmbientColor, bool bAfectedByOutLights, bool bSkyOnly, const Vec3d & vDynAmbientColor, float fViewDistRatio, bool bDoubleSide, bool bUseDeepness, bool bUseInIndoors);
CVisArea(bool bLoadedAsAreaBox);
~CVisArea();
bool IsPointInsideVisArea(const Vec3d & vPos);
bool FindVisArea(IVisArea * pAnotherArea, int nMaxReqursion, bool bSkipDisabledPortals);
int GetVisFrameId();
Vec3d GetConnectionNormal(CVisArea * pPortal);
void DrawVolume(CObjManager * pObjManager, int nReqursionLevel, CCamera CurCamera, CVisArea * pParent, CVisArea * pCurPortal, bool * pbOutdoorVisible, list2<CCamera> * plstOutPortCameras, bool * pbSkyVisible);
void DrawVolume_NotThisAreaOnlyLights(CObjManager * pObjManager, int nReqursionLevel, CCamera CurCamera, CVisArea * pParent, CVisArea * pCurPortal, bool * pbOutdoorVisible, list2<CCamera> * plstOutPortCameras, bool * pbSkyVisible);
void UpdatePortalCameraPlanes(CCamera & cam, Vec3d * pVerts, bool bMergeFrustums);
bool UpdatePortalCameraScissor(CCamera & cam, list2<Vec3d> * lstVerts, bool bMergeFrustums);
int GetVisAreaConnections(IVisArea ** pAreas, int nMaxConnNum, bool bSkipDisabledPortals = false);
int GetRealConnections(IVisArea ** pAreas, int nMaxConnNum, bool bSkipDisabledPortals = false);
bool IsPortalValid();
bool IsPortalIntersectAreaInValidWay(CVisArea * pPortal);
bool IsPortal();
bool IsShapeClockwise();
bool IsAfectedByOutLights() { return m_bAfectedByOutLights; }
bool IsActive() { return m_bActive; }
void UpdateGeometryBBox();
void MarkForStreaming();
void DrawAreaBoundsIntoCBuffer(CCoverageBuffer * pCBuffer);
void ClipPortalVerticesByCameraFrustum(list2<Vec3d> * pPolygon, const CCamera & cam);
void GetMemoryUsage(ICrySizer*pSizer);
bool IsConnectedToOutdoor();
const char * GetName() { return m_sName; }
bool PreloadVisArea(int nMaxReqursion, bool * pbOutdoorFound, CVisArea * pParentToAvoid, Vec3d vPrevPortalPos, float fPrevPortalDistance);
Vec3d m_vGeomBoxMin, m_vGeomBoxMax;
char m_sName[32];
list2<CVisArea*> m_lstConnections;
Vec3d m_vConnNormals[2];
int m_nRndFrameId;
bool m_bActive;
int m_nFogVolumeId;
list2<Vec3d> m_lstShapePoints;
float m_fHeight;
Vec3d m_vAmbColor, m_vDynAmbColor;
bool m_bLoadedAsAreaBox;
bool m_bAfectedByOutLights;
float m_fDistance;
bool m_bSkyOnly;
float m_fViewDistRatio;
bool m_bDoubleSide;
// bool m_bUseDeepness;
CCamera * m_pOcclCamera;
OcclusionTestClient m_OcclState;
Vec3d m_arrvActiveVerts[4];
bool m_bUseInIndoors;
};
struct CVisAreaManager : public Cry3DEngineBase
{
CVisArea * m_pCurArea, * m_pCurPortal;
list2<CVisArea * > m_lstActiveEntransePortals;
list2<CVisArea*> m_lstVisAreas;
list2<CVisArea*> m_lstPortals;
list2<CVisArea*> m_lstOcclAreas;
list2<CVisArea*> m_lstActiveOcclVolumes;
list2<CVisArea*> m_lstIndoorActiveOcclVolumes;
bool m_bOutdoorVisible;
bool m_bSkyVisible;
list2<CCamera> m_lstOutdoorPortalCameras;
CVisAreaManager();
~CVisAreaManager();
void SetCurAreas(CObjManager * pObjManager);
void LoadVisAreaBoxFromXML(XDOM::IXMLDOMDocumentPtr pDoc);
void PortalsDrawDebug();
bool IsEntityVisible(IEntityRender * pEntityRS);
bool IsOutdoorAreasVisible();
bool IsSkyVisible();
CVisArea * CreateVisArea();
bool DeleteVisArea(CVisArea * pVisArea);
bool SetEntityArea(IEntityRender* pEntityRS);
void Render(class CObjManager * pObjManager);
bool UnRegisterEntity(IEntityRender* pEntityRS);
void ActivatePortal(const Vec3d &vPos, bool bActivate, IEntityRender *pEntity);
void SetupFogVolumes(CTerrain * pTerrain);
void LoadVisAreaShapeFromXML(XDOM::IXMLDOMDocumentPtr pDoc);
void UpdateVisArea(CVisArea * pArea, const Vec3d * pPoints, int nCount, const char * szName, float fHeight, const Vec3d & vAmbientColor, bool bAfectedByOutLights, bool bSkyOnly, CTerrain*pTerrain, const Vec3 & vDynAmbientColor, float fViewDistRatio, bool bDoubleSide, bool bUseDeepness, bool bUseInIndoors);
void UpdateConnections();
void MoveAllEntitiesIntoList(list2<IEntityRender*> * plstVisAreasEntities, const Vec3d & vBoxMin, const Vec3d & vBoxMax);
IVisArea * GetVisAreaFromPos(const Vec3d &vPos);
// void DefineTrees();
bool IsEntityVisAreaVisible(IEntityRender * pEnt, bool nCheckNeighbors);
void SetAreaFogVolume(CTerrain * pTerrain, CVisArea * pVisArea);
void MakeActiveEntransePortalsList(const CCamera & CurCamera, list2<CVisArea *> & lstActiveEntransePortals, CVisArea * pThisPortal, CObjManager * pObjManager);
void MergeCameras(CCamera & cam, const CCamera & camPlus);
void DrawOcclusionAreasIntoCBuffer(CCoverageBuffer * pCBuffer);
bool IsValidVisAreaPointer(CVisArea * pVisArea);
void SortStaticInstancesBySize();
void CheckUnload();
int m_nLoadedSectors;
void GetStreamingStatus(int & nLoadedSectors, int & nTotalSectors);
void GetMemoryUsage(ICrySizer*pSizer);
bool UnRegisterInAllSectors(IEntityRender * pEntityRS);
bool PreloadResources();
bool IsOccludedByOcclVolumes(Vec3d vBoxMin, Vec3d vBoxMax, bool bCheckOnlyIndoorVolumes = false);
void Preceche(CObjManager * pObjManager);
void GetObjectsAround(Vec3d vExploPos, float fExploRadius, list2<IEntityRender*> * pEntList);
};
#endif // VisArea_H

View File

@@ -0,0 +1,784 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: objmanWaterVolumes.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: Loading water volumes, prepare water geometry
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "watervolumes.h"
#include "visareas.h"
#include "3dengine.h"
// Shader params ids.
enum {
SHP_WATER_FLOW_POS
};
CWaterVolumeManager::CWaterVolumeManager( )
{
// Add Water Flow Pos shader parameter.
SShaderParam pr;
pr.m_Type = eType_FLOAT;
pr.m_Value.m_Float = 0;
strcpy( pr.m_Name, "WaterFlowPos" );
m_shaderParams.Reserve(1);
m_shaderParams.AddElem(pr);
}
void CWaterVolumeManager::LoadWaterVolumesFromXML(XDOM::IXMLDOMDocumentPtr pDoc)
{
// reset old data
for(int i=0; i<m_lstWaterVolumes.Count(); i++)
{
m_lstWaterVolumes[i]->m_lstPoints.Reset();
GetRenderer()->DeleteLeafBuffer(m_lstWaterVolumes[i]->m_pLeafBuffer);
m_lstWaterVolumes[i]->m_pLeafBuffer=0;
delete m_lstWaterVolumes[i];
}
m_lstWaterVolumes.Reset();
// fill list of volumes of shape points
XDOM::IXMLDOMNodeListPtr pNodeTagList;
XDOM::IXMLDOMNodePtr pNodeTag;
pNodeTagList = pDoc->getElementsByTagName("Objects");
if (pNodeTagList)
{
pNodeTagList->reset();
pNodeTag = pNodeTagList->nextNode();
XDOM::IXMLDOMNodeListPtr pNodeList;
pNodeList = pNodeTag->getElementsByTagName("Object");
if (pNodeList)
{
pNodeList->reset();
XDOM::IXMLDOMNodePtr pNode;
while (pNode = pNodeList->nextNode())
{
XDOM::IXMLDOMNodePtr pType = pNode->getAttribute("Type");
if (pType)
{
if (strstr(pType->getText(),"WaterVolume"))
{
CWaterVolume * pNewVolume = new CWaterVolume( GetRenderer() );
m_lstWaterVolumes.Add(pNewVolume);
m_lstWaterVolumes.Last()->m_vBoxMax=SetMinBB();
m_lstWaterVolumes.Last()->m_vBoxMin=SetMaxBB();
XDOM::IXMLDOMNodePtr pAttr0,pAttr1,pAttr2,pAttr3,pAttr4,pMatAttr;
pAttr0 = pNode->getAttribute("Pos");
pAttr1 = pNode->getAttribute("Width");
pAttr2 = pNode->getAttribute("Height");
pAttr3 = pNode->getAttribute("Name");
pAttr4 = pNode->getAttribute("GroupId");
pMatAttr = pNode->getAttribute("Material");
if (pMatAttr)
{
IMatInfo *pMatInfo = GetSystem()->GetI3DEngine()->FindMaterial( pMatAttr->getText() );
if (pMatInfo)
pNewVolume->SetMaterial( pMatInfo );
}
// set shader
XDOM::IXMLDOMNodePtr pAttr5 = pNode->getAttribute("WaterShader");
if(pAttr5)
pNewVolume->m_pShader = pAttr5->getText()[0] ? GetRenderer()->EF_LoadShader(pAttr5->getText(), eSH_World, EF_SYSTEM) : NULL;
// set tesselation
XDOM::IXMLDOMNodePtr pAttrTriMinSize = pNode->getAttribute("TriMinSize");
XDOM::IXMLDOMNodePtr pAttrTriMaxSize = pNode->getAttribute("TriMaxSize");
float fTriMaxSize = pAttrTriMaxSize ? (float)atof(pAttrTriMaxSize->getText()) : 8.f;
if(pAttrTriMinSize)
pNewVolume->SetTriSizeLimits((float)atof(pAttrTriMinSize->getText()), fTriMaxSize);
// set flow speed
XDOM::IXMLDOMNodePtr pAttr6 = pNode->getAttribute("WaterSpeed");
if(pAttr6)
pNewVolume->m_fFlowSpeed = (float)atof(pAttr6->getText());
// set AffectToVolFog
XDOM::IXMLDOMNodePtr pAffectToVolFog = pNode->getAttribute("AffectToVolFog");
if(pAffectToVolFog)
pNewVolume->m_bAffectToVolFog = atoi(pAffectToVolFog->getText())!=0;
// load vertices
if(pAttr0!=0 && pAttr1!=0 && pAttr2!=0 && pAttr3!=0 && pAttr4!=0)
{
pNewVolume->SetName(pAttr3->getText());
pNewVolume->m_fHeight = (float)atof(pAttr2->getText());
XDOM::IXMLDOMNodeListPtr pNodeTagList;
XDOM::IXMLDOMNodePtr pNodeTag;
pNodeTagList = pNode->getElementsByTagName("Points");
if (pNodeTagList)
{
pNodeTagList->reset();
pNodeTag = pNodeTagList->nextNode();
XDOM::IXMLDOMNodeListPtr pNodeList;
pNodeList = pNodeTag->getElementsByTagName("Point");
if (pNodeList)
{
pNodeList->reset();
XDOM::IXMLDOMNodePtr pNode;
while (pNode = pNodeList->nextNode())
{
XDOM::IXMLDOMNodePtr pPos = pNode->getAttribute("Pos");
if (pPos)
{
Vec3d vPos = StringToVector(pPos->getText());
m_lstWaterVolumes.Last()->m_lstPoints.Add(vPos);
m_lstWaterVolumes.Last()->m_vBoxMax.CheckMax(vPos);
m_lstWaterVolumes.Last()->m_vBoxMin.CheckMin(vPos);
}
}
if( GetDistance(m_lstWaterVolumes.Last()->m_lstPoints.Last(), m_lstWaterVolumes.Last()->m_lstPoints[0])>0.1f )
m_lstWaterVolumes.Last()->m_lstPoints.Add(Vec3d(m_lstWaterVolumes.Last()->m_lstPoints[0]));
m_lstWaterVolumes.Last()->UpdateVisArea();
}
}
}
}
}
}
}
}
}
void MidVert(const struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F & v1, const struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F & v2, struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F & vRes)
{
vRes.xyz = 0.5f*v1.xyz + 0.5f*v2.xyz;
vRes.normal = 0.5f*v1.normal + 0.5f*v2.normal;
vRes.color.bcolor[0] = uchar(0.5f*v1.color.bcolor[0] + 0.5f*v2.color.bcolor[0]);
vRes.color.bcolor[1] = uchar(0.5f*v1.color.bcolor[1] + 0.5f*v2.color.bcolor[1]);
vRes.color.bcolor[2] = uchar(0.5f*v1.color.bcolor[2] + 0.5f*v2.color.bcolor[2]);
vRes.color.bcolor[3] = uchar(0.5f*v1.color.bcolor[3] + 0.5f*v2.color.bcolor[3]);
vRes.st[0] = 0.5f*v1.st[0] + 0.5f*v2.st[0];
vRes.st[1] = 0.5f*v1.st[1] + 0.5f*v2.st[1];
}
bool CWaterVolume::TesselateFace(list2<struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F> & lstVerts, list2<ushort> & lstIndices, int nFacePos, list2<Vec3d> & lstDirections)
{
int n0 = lstIndices[nFacePos+0];
int n1 = lstIndices[nFacePos+1];
int n2 = lstIndices[nFacePos+2];
struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F & v0 = lstVerts[n0];
struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F & v1 = lstVerts[n1];
struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F & v2 = lstVerts[n2];
// get edge lengts
float fDist01 = v0.xyz.GetDistance(v1.xyz);
float fDist12 = v1.xyz.GetDistance(v2.xyz);
float fDist20 = v2.xyz.GetDistance(v0.xyz);
float fMaxDist = max(max(fDist01,fDist12), fDist20);
float fCameraDist=200;
if(fMaxDist == fDist01)
fCameraDist = GetSquaredDistance(GetViewCamera().GetPos(), (v0.xyz+v1.xyz)*0.5f);
else if(fMaxDist == fDist12)
fCameraDist = GetSquaredDistance(GetViewCamera().GetPos(), (v1.xyz+v2.xyz)*0.5f);
else if(fMaxDist == fDist20)
fCameraDist = GetSquaredDistance(GetViewCamera().GetPos(), (v2.xyz+v0.xyz)*0.5f);
else
assert(0);
if(fMaxDist<m_fTriMaxSize)
{
if(fMaxDist<fCameraDist/25 && m_fTriMinSize<8.f)
return false;
if(fMaxDist<m_fTriMinSize)
return false;
}
// delete old face
// lstIndices.Delete(nFacePos,3);
lstIndices.DeleteFastUnsorted(nFacePos,3);
int nNewIndex = lstVerts.Count();
// tesselate longest
if(fDist01>fDist12 && fDist01>fDist20)
{ // 01
struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F v01;
MidVert(v0, v1, v01);
lstVerts.Add(v01);
lstDirections.Add((lstDirections[n0]+lstDirections[n1]).GetNormalized());
lstIndices.Add(n0);
lstIndices.Add(nNewIndex);
lstIndices.Add(n2);
lstIndices.Add(n2);
lstIndices.Add(nNewIndex);
lstIndices.Add(n1);
}
else
if(fDist12>fDist01 && fDist12>fDist20)
{ // 12
struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F v12;
MidVert(v1, v2, v12);
lstVerts.Add(v12);
lstDirections.Add((lstDirections[n1]+lstDirections[n2]).GetNormalized());
lstIndices.Add(n1);
lstIndices.Add(nNewIndex);
lstIndices.Add(n0);
lstIndices.Add(n0);
lstIndices.Add(nNewIndex);
lstIndices.Add(n2);
}
else
if(fDist20>fDist12 && fDist20>fDist01)
{ // 20
struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F v20;
MidVert(v2, v0, v20);
lstVerts.Add(v20);
lstDirections.Add((lstDirections[n2]+lstDirections[n0]).GetNormalized());
lstIndices.Add(n2);
lstIndices.Add(nNewIndex);
lstIndices.Add(n1);
lstIndices.Add(n1);
lstIndices.Add(nNewIndex);
lstIndices.Add(n0);
}
return true;
}
void CWaterVolume::TesselateStrip(list2<struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F> & lstVerts, list2<ushort> & lstIndices, list2<Vec3d> & lstDirections)
{
FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE );
lstIndices.Clear();
for(int i=0; i<lstVerts.Count()-2; i++)
{
if(i&1)
{
lstIndices.Add(i+2);
lstIndices.Add(i+1);
lstIndices.Add(i+0);
}
else
{
lstIndices.Add(i+0);
lstIndices.Add(i+1);
lstIndices.Add(i+2);
}
}
for(int i=0; i<lstIndices.Count() && i<10000; i+=3)
if(TesselateFace(lstVerts, lstIndices, i, lstDirections))
i-=3;
}
void CWaterVolumeManager::InitWaterVolumes()
{
for(int i=0; i<m_lstWaterVolumes.Count(); i++)
m_lstWaterVolumes[i]->CheckForUpdate(false);
}
void CWaterVolume::CheckForUpdate(bool bMakeLowestLod)
{
FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE );
Vec3d vCenter = (m_vBoxMin + m_vBoxMax) * 0.5f;
float fRadius = (m_vBoxMin - vCenter).Length();
if( m_fTriMinSize != m_fPrevTriMinSize || m_fTriMaxSize != m_fPrevTriMaxSize ||
((m_vCurrentCamPos.GetDistance(GetViewCamera().GetPos())>2 && (m_fTriMinSize<m_fTriMaxSize))))
{ // force to rebuild water volume geometry
m_vCurrentCamPos = GetViewCamera().GetPos();
GetRenderer()->DeleteLeafBuffer(m_pLeafBuffer);
m_pLeafBuffer=0;
}
if(!m_pLeafBuffer )
if( m_pShader )
if( m_lstPoints.Count() > 3 )
if( GetDistance(m_lstPoints.Last(),m_lstPoints[0]) < 1.f )
{
m_fPrevTriMaxSize = m_fTriMaxSize;
m_fPrevTriMinSize = m_fTriMinSize;
m_vCurrentCamPos = GetViewCamera().GetPos();
// make verts strip list
struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F tmp;
list2<struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F> lstVertices;
m_lstDirections.Clear();
Vec3d vNormal = (m_lstPoints[1]-m_lstPoints[0]).Cross(m_lstPoints[2]-m_lstPoints[0]);
for(int p=0; p<m_lstPoints.Count()/2; p++)
{
int p2 = m_lstPoints.Count() - p - 2;
if(p>=p2)
break;
// first
tmp.xyz = m_lstPoints[p]+m_vWaterLevelOffset;
tmp.normal = Vec3(0.f, 0.f, 1.f);
tmp.st[0] = (float)p;
tmp.st[1] = 0.f;
tmp.color.dcolor = -1;
lstVertices.Add(tmp);
// calc water move direction in this point
Vec3d vDir1 = (p+1>=p2) ? (m_lstPoints[p] - m_lstPoints[p-1]) : (m_lstPoints[p+1] - m_lstPoints[p]);
m_lstDirections.Add(GetNormalized(vDir1));
// second
tmp.xyz = m_lstPoints[p2]+m_vWaterLevelOffset;
tmp.st[0] = (float)p;
tmp.st[1] = 1.f;
lstVertices.Add(tmp);
Vec3d vDir2 = (p+1>=p2) ? (m_lstPoints[p2] - m_lstPoints[p2+1]) : (m_lstPoints[p2-1] - m_lstPoints[p2]);
m_lstDirections.Add(GetNormalized(vDir2));
}
// Tesselate to alllow nice reflections
list2<ushort> lstIndices;
TesselateStrip(lstVertices, lstIndices, m_lstDirections);
// for(int i=0; i<lstVertices.Count(); i++)
// GetRenderer()->DrawLabel(Vec3d(lstVertices[i].x,lstVertices[i].y,lstVertices[i].z),4,"%d", i);
m_pLeafBuffer = GetRenderer()->CreateLeafBufferInitialized(
lstVertices.GetElements(), lstVertices.Count(), VERTEX_FORMAT_P3F_N_COL4UB_TEX2F,
lstIndices.GetElements(), lstIndices.Count(), R_PRIMV_TRIANGLES,
"WaterVolume", eBT_Static);
m_pLeafBuffer->SetChunk(m_pShader,
0,lstVertices.Count(), 0,lstIndices.Count());
m_pLeafBuffer->m_pMats->Get(0)->m_vCenter = vCenter;
m_pLeafBuffer->m_pMats->Get(0)->m_fRadius = fRadius;
m_pLeafBuffer->m_vBoxMin = m_vBoxMin;
m_pLeafBuffer->m_vBoxMax = m_vBoxMax;
}
}
void CWaterVolumeManager::RenderWaterVolumes(bool bOutdoorVisible)
{
if(!GetCVars()->e_water_volumes || m_nRenderStackLevel)
return;
FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE );
for(int i=0; i<m_lstWaterVolumes.Count(); i++)
{
CWaterVolume * pWaterVolumes = m_lstWaterVolumes[i];
// check vis
if(!GetViewCamera().IsAABBVisibleFast( AABB(pWaterVolumes->m_vBoxMin,pWaterVolumes->m_vBoxMax)))
continue;
if(GetFrameID()%32==0) // hack
pWaterVolumes->UpdateVisArea();
if(m_lstWaterVolumes[i]->m_lstVisAreas.Count())
{ // water in indoors
if(!m_lstWaterVolumes[i]->IsWaterVolumeAreasVisible())
continue; // water area not visible
}
else if(!bOutdoorVisible)
continue; // water area (outdoor) not visible
// create geometry if not ready
m_lstWaterVolumes[i]->CheckForUpdate(false);
if(!m_lstWaterVolumes[i]->m_pLeafBuffer)
continue;
m_lstWaterVolumes[i]->m_nLastRndFrame = GetFrameID();
// draw debug
if(GetCVars()->e_water_volumes==2)
{
int nPosStride=0;
byte * pPos = (byte *)m_lstWaterVolumes[i]->m_pLeafBuffer->GetPosPtr(nPosStride);
for(int p=0; p<m_lstWaterVolumes[i]->m_pLeafBuffer->m_SecVertCount; p++)
{
Vec3d vPos = *(Vec3d*)&pPos[p*nPosStride];
GetRenderer()->SetMaterialColor(p==0, p!=0, 0.0f, 1);
GetRenderer()->Draw3dBBox(vPos-Vec3d(0.2f,0.2f,0.2f), vPos+Vec3d(0.2f,0.2f,0.2f));
GetRenderer()->DrawLabel(vPos,2,"%d",p);
GetRenderer()->Draw3dBBox(vPos+Vec3d(0,0,0.1f), vPos+m_lstWaterVolumes[i]->m_lstDirections[p]+Vec3d(0,0,0.1f),DPRIM_LINE);
}
GetRenderer()->SetMaterialColor(1, 1, 0, 1);
GetRenderer()->Draw3dBBox(pWaterVolumes->m_vBoxMin,pWaterVolumes->m_vBoxMax);
}
// draw volume geometry
CCObject * pObject = GetRenderer()->EF_GetObject(true);
// Assign water flow pos shader param to dynamic object.
m_shaderParams[SHP_WATER_FLOW_POS].m_Value.m_Float = -m_lstWaterVolumes[i]->m_fFlowSpeed * GetCurTimeSec();
pObject->m_ShaderParams = &m_shaderParams;
pObject->m_Matrix.SetIdentity();
// object should have some translation to simplify reflections processing in the renderer
pObject->m_Matrix.SetTranslationOLD(Vec3d(0,0,0.025f));
pObject->m_ObjFlags |= FOB_TRANS_TRANSLATE;
uint nDynMask = 0;
if(m_lstWaterVolumes[i]->m_lstVisAreas.Count())
{
nDynMask = (uint)-1;
// remove sun
for(int nId=0; nId<32; nId++)
{
if(nDynMask & (1<<nId))
{
CDLight * pDLight = (CDLight*)GetRenderer()->EF_Query(EFQ_LightSource, nId);
if(pDLight && pDLight->m_Flags & DLF_SUN)
{
nDynMask = nDynMask & ~(1<<nId);
break;
}
}
}
float fRadius = (m_lstWaterVolumes[i]->m_vBoxMax-m_lstWaterVolumes[i]->m_vBoxMin).len()*0.5f;
Vec3d vCenter = (m_lstWaterVolumes[i]->m_vBoxMin+m_lstWaterVolumes[i]->m_vBoxMax)*0.5f;
((C3DEngine*)Get3DEngine())->CheckDistancesToLightSources(nDynMask,vCenter,fRadius);
}
else
nDynMask=0;
pObject->m_Color.a = 0.99f;
m_lstWaterVolumes[i]->m_pLeafBuffer->AddRenderElements(pObject, nDynMask, -1, 0,
(GetViewCamera().GetPos().z>Get3DEngine()->GetWaterLevel()) ? eS_SeeThrough : eS_Water,
m_lstWaterVolumes[i]->m_pMaterial);
m_lstWaterVolumes[i]->m_pLeafBuffer->m_vBoxMax = m_lstWaterVolumes[i]->m_pLeafBuffer->m_vBoxMin = GetViewCamera().GetPos();
}
// release old
for(int i=0; i<m_lstWaterVolumes.Count(); i++)
{
CWaterVolume * pWaterVolumes = m_lstWaterVolumes[i];
if(pWaterVolumes->m_pLeafBuffer && m_lstWaterVolumes[i]->m_nLastRndFrame < GetFrameID()-100)
{
m_lstWaterVolumes[i]->CheckForUpdate(true);
// GetRenderer()->DeleteLeafBuffer(pWaterVolumes->m_pLeafBuffer);
// pWaterVolumes->m_pLeafBuffer=0;
}
}
}
float CWaterVolumeManager::GetWaterVolumeLevelFor2DPoint(const Vec3d & vPos, Vec3d * pvFlowDir)
{
float fResLevel = WATER_LEVEL_UNKNOWN;
// check all volumes bboxes
for(int i=0; i<m_lstWaterVolumes.Count(); i++)
{
CWaterVolume * pWaterVolumes = m_lstWaterVolumes[i];
Vec3d vBoxMin2d = pWaterVolumes->m_vBoxMin;
Vec3d vBoxMax2d = pWaterVolumes->m_vBoxMax;
vBoxMin2d.z=WATER_LEVEL_UNKNOWN;
vBoxMax2d.z=1024;
if(!pWaterVolumes->m_pLeafBuffer)
pWaterVolumes->CheckForUpdate(true);
if(pWaterVolumes->m_pLeafBuffer && Overlap::Point_AABB(vPos,vBoxMin2d,vBoxMax2d))
{ // if inside bbox
int nInds = 0;
ushort *pInds = pWaterVolumes->m_pLeafBuffer->GetIndices(&nInds);
int nPosStride=0;
const byte * pPos = pWaterVolumes->m_pLeafBuffer->GetPosPtr(nPosStride,0,true);
for(int i=0; (i+2)<nInds; i+=3)
{ // test all triangles of water surface strip
Vec3d v0 = *(Vec3d*)&pPos[nPosStride*pInds[i+0]];
Vec3d v1 = *(Vec3d*)&pPos[nPosStride*pInds[i+1]];
Vec3d v2 = *(Vec3d*)&pPos[nPosStride*pInds[i+2]];
v0.z = v1.z = v2.z = 0; // make triangle 2d
Vec3d vPos2d(vPos.x,vPos.y,0);
if(Overlap::PointInTriangle( vPos2d, v0,v1,v2,Vec3d(0,0,1.f)))
{ // triangle found
Plane plane;
plane.CalcPlane( // calc plane using real vertices
*(Vec3d*)&pPos[nPosStride*pInds[i+0]],
*(Vec3d*)&pPos[nPosStride*pInds[i+1]],
*(Vec3d*)&pPos[nPosStride*pInds[i+2]]);
float fDist = plane.DistFromPlane(vPos);
float fDot = plane.n.Dot(Vec3d(0,0,1.f));
if(fDot>0)
fDist = -fDist;
// check bottom bounds
if(pWaterVolumes->m_fHeight && fDist > -pWaterVolumes->m_fHeight)
continue;
if(GetCVars()->e_water_volumes==2)
{
GetLog()->Log("CameraLevel=%.2f, WaterVolumeLevel=%.2f %d",
GetViewCamera().GetPos().z, fDist, GetFrameID());
Vec3d vPos = vPos2d+Vec3d(0,0,fDist);
// GetRenderer()->Draw3dBBox(vPos-Vec3d(0.05f,0.05f,0.05f),vPos+Vec3d(0.05f,0.05f,0.05f),DPRIM_SOLID_SPHERE);
}
if(pvFlowDir)
{
// todo: calculate the barycentric coordinates of the triangle
/* float b0 = (v1.x - v0.x) * (v2.y - v0.y) - (v2.x - v0.x) * (v1.y - v0.y);
float b1 = ( v1.x * v2.y - v2.x * v1.y ) / b0 ;
float b2 = ( v2.x * v0.y - v0.x * v2.y ) / b0 ;
float b3 = ( v0.x * v1.y - v1.x * v0.y ) / b0 ;
Vec3d vReconstructed = b1 * v0 + b2 * v1 + b3 * v2;
vReconstructed=vReconstructed;*/
float fDist0 = GetDistance(vPos2d,v0);
float fDist1 = GetDistance(vPos2d,v1);
float fDist2 = GetDistance(vPos2d,v2);
float fSumm = fDist0 + fDist1 + fDist2;
fDist0 /= fSumm;
fDist1 /= fSumm;
fDist2 /= fSumm;
*pvFlowDir = pWaterVolumes->m_lstDirections[pInds[i+0]]*(1.f-fDist0)+
pWaterVolumes->m_lstDirections[pInds[i+1]]*(1.f-fDist1)+
pWaterVolumes->m_lstDirections[pInds[i+2]]*(1.f-fDist2);
if(GetCVars()->e_water_volumes==2)
GetRenderer()->Draw3dBBox(vPos, vPos+*pvFlowDir, DPRIM_LINE);
*pvFlowDir *= pWaterVolumes->m_fFlowSpeed;
}
if( (vPos.z+fDist) > fResLevel )
fResLevel = (vPos.z+fDist);
}
}
}
}
return fResLevel;
}
IWaterVolume * CWaterVolumeManager::CreateWaterVolume()
{
CWaterVolume * pNewVolume = new CWaterVolume( GetRenderer() );
m_lstWaterVolumes.Add(pNewVolume);
return pNewVolume;
}
void CWaterVolumeManager::DeleteWaterVolume(IWaterVolume * pWaterVolume)
{
GetRenderer()->DeleteLeafBuffer(((CWaterVolume*)pWaterVolume)->m_pLeafBuffer);
((CWaterVolume*)pWaterVolume)->m_pLeafBuffer=0;
delete pWaterVolume;
m_lstWaterVolumes.Delete((CWaterVolume*)pWaterVolume);
}
void CWaterVolumeManager::UpdateWaterVolumeVisAreas()
{
for(int i=0; i<m_lstWaterVolumes.Count(); i++)
m_lstWaterVolumes[i]->UpdateVisArea();
}
void CWaterVolume::UpdatePoints(const Vec3d * pPoints, int nCount, float fHeight)
{
m_lstPoints.PreAllocate(nCount+1,nCount);
m_fHeight = fHeight;
if(nCount)
{
memcpy(&m_lstPoints[0], pPoints, sizeof(Vec3d)*nCount);
if( GetDistance(m_lstPoints.Last(), m_lstPoints[0])>0.1f )
m_lstPoints.Add(m_lstPoints[0]); // loop
}
// update bbox
m_vBoxMax = SetMinBB();
m_vBoxMin = SetMaxBB();
for(int i=0; i<nCount; i++)
{
m_vBoxMax.CheckMax(pPoints[i]);
m_vBoxMin.CheckMin(pPoints[i]);
}
// remake leaf buffer
m_pRenderer->DeleteLeafBuffer(m_pLeafBuffer);
m_pLeafBuffer=0;
UpdateVisArea();
}
void CWaterVolume::SetShader(const char * szShaderName)
{
if(szShaderName[0])
m_pShader = m_pRenderer->EF_LoadShader(szShaderName,eSH_World, EF_SYSTEM);
else
m_pShader = NULL;//m_pRenderer->EF_LoadShader("default",eSH_World, EF_SYSTEM);
// remake leaf buffer
m_pRenderer->DeleteLeafBuffer(m_pLeafBuffer);
m_pLeafBuffer=0;
}
CWaterVolumeManager::~CWaterVolumeManager()
{
for(int i=0; i<m_lstWaterVolumes.Count(); i++)
{
CWaterVolume * pWaterVolume = m_lstWaterVolumes[i];
GetRenderer()->DeleteLeafBuffer(pWaterVolume->m_pLeafBuffer);
pWaterVolume->m_pLeafBuffer=0;
delete pWaterVolume;
}
m_lstWaterVolumes.Reset();
}
void CWaterVolume::UpdateVisArea()
{
m_lstVisAreas.Clear();
if(!m_lstPoints.Count())
return;
// scan water volume bbox for vis areas
const float dx = (m_vBoxMax.x - m_vBoxMin.x)/int(m_vBoxMax.x - m_vBoxMin.x) + 0.1f;
const float dy = (m_vBoxMax.y - m_vBoxMin.y)/int(m_vBoxMax.y - m_vBoxMin.y) + 0.1f;
// const float dz = (m_vBoxMax.z - m_vBoxMin.z)/int(m_vBoxMax.z - m_vBoxMin.z) + 0.1f;
float z = (m_vBoxMin.z+m_vBoxMax.z)*0.5f;
for(float x = m_vBoxMin.x; x<=m_vBoxMax.x; x+=dx*5)
for(float y = m_vBoxMin.y; y<=m_vBoxMax.y; y+=dy*5)
// for(float z = m_vBoxMin.z; z<=m_vBoxMax.z; z+=dz)
{
CVisArea * pVisArea = (CVisArea *)Get3DEngine()->GetVisAreaFromPos(Vec3d(x,y,z));
if(pVisArea && m_lstVisAreas.Find(pVisArea)<0)
{
m_lstVisAreas.Add(pVisArea);
if(m_bAffectToVolFog)
UpdateVisAreaFogVolumeLevel(pVisArea);
}
}
}
void CWaterVolume::UpdateVisAreaFogVolumeLevel(CVisArea*pVisArea)
{
CTerrain * pTerrain = ((C3DEngine*)Get3DEngine())->GetTerrain();
int f;
for(f=0; f<pTerrain->m_lstFogVolumes.Count(); f++)
if(pTerrain->m_lstFogVolumes[f].nRendererVolumeID == pVisArea->m_nFogVolumeId)
break;
if(f<pTerrain->m_lstFogVolumes.Count())
{
VolumeInfo * pFogVolume = &pTerrain->m_lstFogVolumes[f];
pFogVolume->vBoxMax.z = m_vBoxMax.z;
GetRenderer()->EF_RegisterFogVolume(pFogVolume->fMaxViewDist,pFogVolume->vBoxMax.z,pFogVolume->vColor,pFogVolume->nRendererVolumeID, pFogVolume->m_bCaustics);
}
}
//////////////////////////////////////////////////////////////////////////
void CWaterVolume::SetMaterial( IMatInfo *pMatInfo )
{
m_pMaterial = pMatInfo;
if(m_pMaterial)
m_pMaterial->SetFlags(m_pMaterial->GetFlags()|MIF_WASUSED);
}
IMatInfo * CWaterVolume::GetMaterial()
{
return m_pMaterial;
}
//////////////////////////////////////////////////////////////////////////
IWaterVolume * CWaterVolumeManager::FindWaterVolumeByName(const char * szName)
{
for(int i=0; i<m_lstWaterVolumes.Count(); i++)
{
CWaterVolume * pWaterVolume = m_lstWaterVolumes[i];
if(!stricmp(pWaterVolume->m_szName, szName))
return pWaterVolume;
}
return 0;
}
void CWaterVolume::SetPositionOffset(const Vec3d & vNewOffset)
{
m_vWaterLevelOffset = vNewOffset;
m_vBoxMax = SetMinBB();
m_vBoxMin = SetMaxBB();
for(int p=0; p<m_lstPoints.Count(); p++)
{
Vec3d vPos = m_lstPoints[p] + m_vWaterLevelOffset;
m_vBoxMax.CheckMax(vPos);
m_vBoxMin.CheckMin(vPos);
}
m_vBoxMax.z += 0.01f;
m_vBoxMin.z -= 0.01f;
GetRenderer()->DeleteLeafBuffer(m_pLeafBuffer);
m_pLeafBuffer=0;
UpdateVisArea();
}
bool CWaterVolume::IsWaterVolumeAreasVisible()
{
assert(m_lstVisAreas.Count());
// water in indoors
int v;
for(v=0; v<m_lstVisAreas.Count(); v++)
if(abs(((CVisArea*)m_lstVisAreas[v])->m_nRndFrameId - GetFrameID())<2)
break; // water area is visible
return v<m_lstVisAreas.Count();
}
void CWaterVolume::SetTriSizeLimits(float fTriMinSize, float fTriMaxSize)
{
m_fTriMinSize = max(0.25f,min(fTriMinSize, 8));
m_fTriMaxSize = max(0.25f,min(fTriMaxSize, 8));
// remake leaf buffer
m_pRenderer->DeleteLeafBuffer(m_pLeafBuffer);
m_pLeafBuffer=0;
}

View File

@@ -0,0 +1,81 @@
#ifndef CWaterVolumeManager_H
#define CWaterVolumeManager_H
class CWaterVolume : public IWaterVolume, public Cry3DEngineBase
{
public:
CWaterVolume(IRenderer * pRenderer)
{
m_pRenderer = pRenderer; m_pLeafBuffer = 0; m_pShader = 0;
m_fFlowSpeed = 0;
m_bAffectToVolFog = false;
m_fTriMaxSize = m_fTriMinSize = 8.f;
m_fPrevTriMaxSize = m_fPrevTriMinSize = 0;
m_fHeight = 0; m_vCurrentCamPos.Set(0,0,0); m_nLastRndFrame=0;
m_szName[0] = 0;
m_vWaterLevelOffset.Set(0,0,0);
}
void UpdatePoints(const Vec3d * pPoints, int nCount, float fHeight);
void SetFlowSpeed(float fSpeed) { m_fFlowSpeed = fSpeed; }
void SetAffectToVolFog(bool bAffectToVolFog) { m_bAffectToVolFog = bAffectToVolFog; }
void SetTriSizeLimits(float fTriMinSize, float fTriMaxSize);
void SetShader(const char * szShaderName);
void SetMaterial( IMatInfo *pMatInfo );
void SetName(const char * szName)
{
strncpy(m_szName,szName,64);
}
void SetPositionOffset(const Vec3d & vNewOffset);
IMatInfo * GetMaterial();
void UpdateVisArea();
void CheckForUpdate(bool bMakeLowestLod);
bool IsWaterVolumeAreasVisible();
void TesselateStrip(list2<struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F> & lstVerts, list2<ushort> & lstIndices, list2<Vec3d> & lstDirections);
bool TesselateFace(list2<struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F> & lstVerts, list2<ushort> & lstIndices, int nFacePos, list2<Vec3d> & lstDirections);
void UpdateVisAreaFogVolumeLevel(CVisArea*pVisArea);
list2<Vec3d> m_lstPoints;
Vec3d m_vWaterLevelOffset;
list2<Vec3d> m_lstDirections;
CLeafBuffer * m_pLeafBuffer;
Vec3d m_vBoxMin, m_vBoxMax;
IRenderer * m_pRenderer;
IShader * m_pShader;
char m_szName[64];
float m_fHeight;
float m_fTriMinSize, m_fTriMaxSize;
float m_fPrevTriMaxSize, m_fPrevTriMinSize;
_smart_ptr<IMatInfo> m_pMaterial;
float m_fFlowSpeed;
bool m_bAffectToVolFog;
list2<struct IVisArea *> m_lstVisAreas;
Vec3d m_vCurrentCamPos;
int m_nLastRndFrame;
};
struct CWaterVolumeManager : public Cry3DEngineBase
{
CWaterVolumeManager( );
~CWaterVolumeManager();
void LoadWaterVolumesFromXML(XDOM::IXMLDOMDocumentPtr pDoc);
list2<CWaterVolume*> m_lstWaterVolumes;
void InitWaterVolumes();
void RenderWaterVolumes(bool bOutdoorVisible);
float GetWaterVolumeLevelFor2DPoint(const Vec3d & vPos, Vec3d * pvFlowDir);
IWaterVolume * CreateWaterVolume();
void DeleteWaterVolume(IWaterVolume * pWaterVolume);
void UpdateWaterVolumeVisAreas();
IWaterVolume * FindWaterVolumeByName(const char * szName);
private:
// Local shader param.
TArray<SShaderParam> m_shaderParams;
};
#endif // CWaterVolumeManager_H

354
Cry3DEngine/bflyes.cpp Normal file
View File

@@ -0,0 +1,354 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: bflyes.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: draw volume with bflyes right in front of the camera
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
/*
#include "bflyes.h"
Cry_Butterfly::Cry_Butterfly()
{
ZeroStruct(*this);
m_vPos.x = rn()*BF_RANGE*2;
m_vPos.y = rn()*BF_RANGE*2;
m_fHigh = 1;
m_fLifeSpeed = 1;// + rn()/2;
m_fSize = 1;// + rn();
// m_fLifeSpeed = 1.f/m_fSize/2;
m_fSize *= 0.75f;
{
static int _X_ = 0;
static int _Y_ = 0;
_Y_++;
if(_Y_>3)
{
_Y_=0;
_X_=!_X_;
}
m_vCurWingPos.x = 0.25f*(_Y_);
m_vCurWingPos.y = 0.25f*(2+_X_);
}
}
bool Cry_Butterfly::IsPointInvalid(const Vec3d & pos)
{
// if(pTerrain->GetZSafe(fastftol(pos.x),fastftol(pos.y)) < pTerrain->GetWaterLevel())
// return true;
return false;
}
void Cry_Butterfly::Render(ITimer * pITimer, IRenderer * pIRenderer, const Vec3d & vCamPos, const bool & bEven, const Vec3d & vColor, struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * pVertBufChunk, CTerrain * pTerrain )
{
Vec3d start_pos = m_vPos;
{ // bf space loop
if((m_vPos.x-vCamPos.x)>BF_RANGE)
{
while((m_vPos.x-vCamPos.x)>BF_RANGE)
m_vPos.x-=BF_RANGEx2;
if(IsPointInvalid(m_vPos))
m_vPos.x+=BF_RANGEx2;
}
if((vCamPos.x-m_vPos.x)>BF_RANGE)
{
while((vCamPos.x-m_vPos.x)>BF_RANGE)
m_vPos.x+=BF_RANGEx2;
if(IsPointInvalid(m_vPos))
m_vPos.x-=BF_RANGEx2;
}
if((m_vPos.y-vCamPos.y)>BF_RANGE)
{
while((m_vPos.y-vCamPos.y)>BF_RANGE)
m_vPos.y-=BF_RANGEx2;
if(IsPointInvalid(m_vPos))
m_vPos.y+=BF_RANGEx2;
}
if((vCamPos.y-m_vPos.y)>BF_RANGE)
{
while((vCamPos.y-m_vPos.y)>BF_RANGE)
m_vPos.y+=BF_RANGEx2;
if(IsPointInvalid(m_vPos))
m_vPos.y-=BF_RANGEx2;
}
}
if(
//m_vPos!=start_pos
!IsEquivalent(m_vPos,start_pos,VEC_EPSILON)
)
m_fHigh = 0.5; // sit in the ea fix
////////////////////////////////////////////////////////////////////////////////////////////////////
// AI
////////////////////////////////////////////////////////////////////////////////////////////////////
{
m_fAngle += m_fAngleDelta*fBFPerformanceFactor;
m_fHigh += m_fHightDelta*fBFPerformanceFactor/15;
if(bEven)
{
m_fAngleDelta += rn();
Limit(&m_fAngleDelta,-3,3);
}
else
{
m_fHightDelta += rn();
Limit(&m_fHightDelta,-1,1);
}
Limit(&m_fHigh, -0.25,5);
bool water = pTerrain->GetZApr(m_vPos.x,m_vPos.y) < pTerrain->GetWaterLevel();
if(water && m_fHigh<0.2f)
m_fHigh=0.2f;
if(m_fHigh>GROUND_LEVEL)
{ // fly
if(m_fHigh<0.1f)
m_fHigh=0.1f;
float rad = (m_fAngle-90) * (gf_PI/180);
Vec2 D; // the cosine and sine, y is guaranteed to follow x
CosSin(rad, &D.x);
m_vPos.x += D.x*fBFPerformanceFactor*0.05f*m_fLifeSpeed;
m_vPos.y += D.y*fBFPerformanceFactor*0.05f*m_fLifeSpeed;
m_vPos.z = pTerrain->GetZApr(m_vPos.x,m_vPos.y);
if(m_vPos.z < pTerrain->GetWaterLevel())
m_vPos.z = pTerrain->GetWaterLevel();
m_vPos.z += m_fHigh;
}
// else
// pos.z += (pTerrain->GetZApr(pos.x,pos.y)+0.1f-pos.z)/100;
}
if(m_vPos.x>0 && m_vPos.y>0 && m_vPos.x<CTerrain::GetTerrainSize() && m_vPos.y<CTerrain::GetTerrainSize() &&
m_vPos.z < (pTerrain->GetWaterLevel()+82) )// !IsPointInFuncZone(m_vPos.x,m_vPos.y))
{
struct {float c, s;}
WingPos;
CosSin(m_fWingPos, &WingPos.c);
float c = WingPos.c;
float s = WingPos.s;
float wspeed = (1.1f*(float)fabs(c) + 0.25f)*(m_fLifeSpeed+m_fHightDelta*0.2f)/(1.f+(m_fHigh<GROUND_LEVEL)*7.f);
if(m_bMoveDir)
m_fWingPos += fBFPerformanceFactor*wspeed;
else
m_fWingPos -= fBFPerformanceFactor*wspeed;
if(m_fWingPos> 1.2f) // up wind pos
m_bMoveDir = 0;
else if(m_fWingPos < ((m_fHigh<GROUND_LEVEL) ? 0.2f : -1.0f)) // down wind pos
m_bMoveDir = 1;
float sh = 1;//0.5f + 0.5f*pTerrain->IsOnTheLight(fastftol(m_vPos.x),fastftol(m_vPos.y));
uchar r = uchar(vColor[0]*sh);
uchar g = uchar(vColor[1]*sh);
uchar b = uchar(vColor[2]*sh);
// pIRenderer->RotateMatrix(-10,1,0,0);
float R = 0.175f*m_fSize;
float
x1=0 +m_vCurWingPos.x,
x2=0.125f +m_vCurWingPos.x,
x3=0.25f +m_vCurWingPos.x;
float
y1=1.f-(0 +m_vCurWingPos.y),
y2=1.f-(0.125f +m_vCurWingPos.y),
y3=1.f-(0.25f +m_vCurWingPos.y);
struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F data[6] =
{
{-c*R, -R, R*s , r,g,b,255, x1, y3},
{-c*R, R, R*s , r,g,b,255, x1, y1},
{ 0, -R, -R*s/3, r,g,b,255, x2, y3},
{ 0, R, -R*s/3, r,g,b,255, x2, y1},
{ c*R, -R, R*s , r,g,b,255, x3, y3},
{ c*R, R, R*s , r,g,b,255, x3, y1}
};
if(m_fHigh<GROUND_LEVEL)
data[2].z = data[3].z = 0;
float rad = DEG2RAD(m_fAngle);
struct {float c,s;} radCS;
CosSin (rad, &radCS.c);
float fCos = radCS.c;// (float)cos(rad);
float fSin = radCS.s;// (float)sin(rad);
struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * pData = data;
for(int i=0; i<6; i++)
{
float x = fCos*pData->x - fSin*pData->y;
float y = fSin*pData->x + fCos*pData->y;
pData->x = x;
pData->y = y;
pData->x+=m_vPos.x;
pData->y+=m_vPos.y;
pData->z+=m_vPos.z;
pData++;
}
memcpy(pVertBufChunk,data,sizeof(data));
}
else
{
memset(pVertBufChunk,0,sizeof(struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F)*6);
}
}
CBFManager::CBFManager()
{
m_pBFArray = new Cry_Butterfly[MAX_BF_COUNT];
m_Indixes.Reset();
GetRenderer()->CreateIndexBuffer(&m_Indixes, NULL, MAX_BF_COUNT*12);
GetRenderer()->UpdateIndexBuffer(&m_Indixes, NULL, 0, false);
ushort *pInds = (ushort *)m_Indixes.m_VData;
m_nTexID = 0;
m_pVideoBuffer = 0;
int i=0;
for(int b=0; b<MAX_BF_COUNT; b++)
{
// 1st wing
pInds[i++] = b*6;
pInds[i++] = b*6+1;
pInds[i++] = b*6+2;
pInds[i++] = b*6+1;
pInds[i++] = b*6+2;
pInds[i++] = b*6+3;
// 2nd
pInds[i++] = b*6+2;
pInds[i++] = b*6+3;
pInds[i++] = b*6+4;
pInds[i++] = b*6+3;
pInds[i++] = b*6+4;
pInds[i++] = b*6+5;
// assert(i<BF_COUNT*12);
}
GetRenderer()->UpdateIndexBuffer(&m_Indixes, NULL, 0, true);
m_pVideoBuffer = GetRenderer()->CreateBuffer(MAX_BF_COUNT*6,VERTEX_FORMAT_P3F_COL4UB_TEX2F, "BFlyes");
m_nCurrentObjectsCount = 0;
}
CBFManager::~CBFManager()
{
delete [] m_pBFArray;
GetRenderer()->ReleaseIndexBuffer(&m_Indixes);
GetRenderer()->ReleaseBuffer(m_pVideoBuffer);
}
void CBFManager::Render(CTerrain * pTerrain)
{
if(!GetCVars()->e_bflyes || m_nCurrentObjectsCount==0)
return;
IRenderer * rend = GetRenderer();
rend->ResetToDefault();
Vec3d vCamPos = GetViewCamera().GetPos();
float terr_z = pTerrain->GetZSafe(vCamPos.x,vCamPos.y);
if(terr_z<pTerrain->GetWaterLevel())
terr_z = pTerrain->GetWaterLevel();
if(vCamPos.z > terr_z+48)
return;
rend->SetMaterialColor(1,1,1,1);
rend->SetColorOp(eCO_MODULATE, eCO_MODULATE, eCA_Texture|(eCA_Constant<<3), eCA_Texture|(eCA_Constant<<3));
rend->SetState(GS_ALPHATEST_GEQUAL64 | GS_DEPTHWRITE);
rend->SetCullMode(R_CULL_DISABLE);
int tex_type;
if(!m_nTexID)
m_nTexID = rend->LoadTexture("Textures\\bfly.jpg", &tex_type);
// else
// GetCVars()->e_bflyes = false;
rend->SetTexture(m_nTexID);
Matrix44 mat;
rend->GetModelViewMatrix(mat.GetData());
//CELL_CHANGED_BY_IVO
//m_vForward(-mat.cell(2), -mat.cell(6), -mat.cell(10));
m_vForward = -mat.GetColumn(2);
m_vForward.Normalize();
Vec3d vFocusPos = vCamPos + m_vForward*BF_CAMERA_SHIFT;
Vec3d vColor = GetSystem()->GetI3DEngine()->GetWorldColor();//*
// GetSystem()->GetI3DEngine()->GetWorldBrightnes();
vColor.x*=255;
vColor.y*=255;
vColor.z*=255;
// wait for fence
GetRenderer()->UpdateBuffer(m_pVideoBuffer,0,0,false);
for(int i=0; i<m_nCurrentObjectsCount && i<MAX_BF_COUNT; i++)
m_pBFArray[i].Render(GetTimer(), GetRenderer(), vFocusPos, m_bEven, vColor, &((struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F*)m_pVideoBuffer->m_VS[VSF_GENERAL].m_VData)[i*6], pTerrain);
m_bEven =! m_bEven;
GetRenderer()->DrawBuffer(m_pVideoBuffer,&m_Indixes,m_nCurrentObjectsCount*12,0,R_PRIMV_TRIANGLES);
rend->ResetToDefault();
}
void CBFManager::KillBF(const Vec3d & vExploPos, const float fRadius)
{
for(int i=0; i<MAX_BF_COUNT; i++)
{
if(fabs(m_pBFArray[i].m_vPos.x - vExploPos.x)<fRadius)
if(fabs(m_pBFArray[i].m_vPos.y - vExploPos.y)<fRadius)
if(fabs(m_pBFArray[i].m_vPos.z - vExploPos.z)<fRadius)
{
m_pBFArray[i].m_vPos.x = m_pBFArray[i].m_vPos.x + m_vForward.x*BF_CAMERA_SHIFT;
m_pBFArray[i].m_vPos.y = m_pBFArray[i].m_vPos.y + m_vForward.y*BF_CAMERA_SHIFT;
}
}
}*/

74
Cry3DEngine/bflyes.h Normal file
View File

@@ -0,0 +1,74 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: bflyes.h
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
/*
#ifndef _BFLIES_H
#define _BFLIES_H
#define MAX_BF_COUNT 256
#define BF_RANGE 16
const int BF_RANGEx2 = BF_RANGE*2;
const int BF_CAMERA_SHIFT = BF_RANGE-1;
#define rn() ((((float)rand())/RAND_MAX)-0.5f)
#define fBFPerformanceFactor (pITimer->GetFrameTime()*40)
#define GROUND_LEVEL 0.1f
class Cry_Butterfly
{
float m_fWingPos,m_fAngle,m_fAngleDelta,m_fHigh,m_fHightDelta,m_fLifeSpeed,m_fSize;
Vec3d m_vCurWingPos;
bool m_bMoveDir;
inline void Limit(float * val, float min, float max)
{
if(*val > max) *val = max;
else if(*val < min) *val = min;
}
bool IsPointInvalid(const Vec3d & pos);
public:
Cry_Butterfly();
void Render(ITimer * pITimer, IRenderer * pIRenderer, const Vec3d & vCamPos, const bool & bEven, const Vec3d & vColor, struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * pVertBufChunk, CTerrain * pTerrain );
Vec3d m_vPos;
};
class CBFManager : public Cry3DEngineBase
{
Cry_Butterfly * m_pBFArray;
CVertexBuffer * m_pVideoBuffer;
SVertexStream m_Indixes;
int m_nTexID;
bool m_bEven;
Vec3d m_vForward;
int m_nCurrentObjectsCount;
public:
CBFManager();
void Render(CTerrain * pTerrain);
~CBFManager();
void KillBF(const Vec3d & vExploPos, const float fRadius);
void SetCount(int nCount) { m_nCurrentObjectsCount = min(nCount, MAX_BF_COUNT); }
int GetCount() { return m_nCurrentObjectsCount; }
int GetMemoryUsage() { return sizeof(Cry_Butterfly)*MAX_BF_COUNT + sizeof(ushort)*MAX_BF_COUNT; }
};
#endif
*/

684
Cry3DEngine/cbuffer.cpp Normal file
View File

@@ -0,0 +1,684 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: cbuffer.cpp
// Version: v1.00
// Created: 30/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: Occlusion (coverage) buffer
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "cbuffer.h"
void CCoverageBuffer::TransformPoint(float out[4], const float m[16], const float in[4])
{
#define M(row,col) m[col*4+row]
out[0] = M(0, 0) * in[0] + M(0, 1) * in[1] + M(0, 2) * in[2] + M(0, 3) * in[3];
out[1] = M(1, 0) * in[0] + M(1, 1) * in[1] + M(1, 2) * in[2] + M(1, 3) * in[3];
out[2] = M(2, 0) * in[0] + M(2, 1) * in[1] + M(2, 2) * in[2] + M(2, 3) * in[3];
out[3] = M(3, 0) * in[0] + M(3, 1) * in[1] + M(3, 2) * in[2] + M(3, 3) * in[3];
#undef M
}
void CCoverageBuffer::MatMul4( float *product, const float *a, const float *b )
{
#define A(row,col) a[(col<<2)+row]
#define B(row,col) b[(col<<2)+row]
#define P(row,col) product[(col<<2)+row]
int i;
for (i=0; i<4; i++)
{
float ai0=A(i,0), ai1=A(i,1), ai2=A(i,2), ai3=A(i,3);
P(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0) + ai3 * B(3,0);
P(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1) + ai3 * B(3,1);
P(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2) + ai3 * B(3,2);
P(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3 * B(3,3);
}
#undef A
#undef B
#undef P
}
CCoverageBuffer::Point2d CCoverageBuffer::ProjectToScreen(const float & x, const float & y, const float & z)
{
Point2d res; float res_z;
float _in[4], out[4];
_in[0] = x;
_in[1] = y;
_in[2] = z;
_in[3] = 1.0;
TransformPoint(out, m_matCombined, _in);
if (out[3] == 0.0)
res.x = res.y = -1000; // mark vertex as bad - skip this triangle
else
{
res.x = out[0] / out[3];
res.y = out[1] / out[3];
res_z = out[2] / out[3];
res.x = m_matViewPort[0] + (1.f + res.x) * m_matViewPort[2] * 0.5f;
res.y = m_matViewPort[1] + (1.f + res.y) * m_matViewPort[3] * 0.5f;
res_z = (1.f + res_z) * 0.5f;
if( res_z < 0 || res_z > 1 )
res_z=res_z;//res.x = res.y = -1000; // mark vertex as bad - skip this triangle
}
return res;
}
void CCoverageBuffer::AddBBox(const Vec3d & mins, const Vec3d & maxs, const Vec3d & vDirToCamera)
{
Vec3d arrVerts3d[8] =
{
Vec3d(mins.x,mins.y,mins.z),
Vec3d(mins.x,maxs.y,mins.z),
Vec3d(maxs.x,mins.y,mins.z),
Vec3d(maxs.x,maxs.y,mins.z),
Vec3d(mins.x,mins.y,maxs.z),
Vec3d(mins.x,maxs.y,maxs.z),
Vec3d(maxs.x,mins.y,maxs.z),
Vec3d(maxs.x,maxs.y,maxs.z)
};
Point2d arrVerts[8] =
{ // transform into screen space
ProjectToScreen(mins.x,mins.y,mins.z),
ProjectToScreen(mins.x,maxs.y,mins.z),
ProjectToScreen(maxs.x,mins.y,mins.z),
ProjectToScreen(maxs.x,maxs.y,mins.z),
ProjectToScreen(mins.x,mins.y,maxs.z),
ProjectToScreen(mins.x,maxs.y,maxs.z),
ProjectToScreen(maxs.x,mins.y,maxs.z),
ProjectToScreen(maxs.x,maxs.y,maxs.z)
};
// find 2d bounds in screen space
Point2d min2d = arrVerts[0], max2d = arrVerts[0];
for(int i=0; i<8; i++)
{
if(arrVerts[i].x < min2d.x)
min2d.x = arrVerts[i].x;
if(arrVerts[i].x > max2d.x)
max2d.x = arrVerts[i].x;
if(arrVerts[i].y < min2d.y)
min2d.y = arrVerts[i].y;
if(arrVerts[i].y > max2d.y)
max2d.y = arrVerts[i].y;
}
// adjust 2d bounds to make it 1 pixel smaler
min2d.x += 1;
min2d.y += 1;
max2d.x -= 1;
max2d.y -= 1;
// adjust 2d vertices
for(int i=0; i<8; i++)
{
if(arrVerts[i].x < min2d.x)
arrVerts[i].x = min2d.x;
if(arrVerts[i].x > max2d.x)
arrVerts[i].x = max2d.x;
if(arrVerts[i].y < min2d.y)
arrVerts[i].y = min2d.y;
if(arrVerts[i].y > max2d.y)
arrVerts[i].y = max2d.y;
}
// render only front faces of box
if(vDirToCamera.x>0)
{
ScanTriangleWithCliping(arrVerts[2],arrVerts[3],arrVerts[6],arrVerts3d[2],arrVerts3d[3],arrVerts3d[6]);
ScanTriangleWithCliping(arrVerts[6],arrVerts[3],arrVerts[7],arrVerts3d[6],arrVerts3d[3],arrVerts3d[7]);
}
else
{
ScanTriangleWithCliping(arrVerts[1],arrVerts[0],arrVerts[4],arrVerts3d[1],arrVerts3d[0],arrVerts3d[4]);
ScanTriangleWithCliping(arrVerts[1],arrVerts[4],arrVerts[5],arrVerts3d[1],arrVerts3d[4],arrVerts3d[5]);
}
if(vDirToCamera.y>0)
{
ScanTriangleWithCliping(arrVerts[3],arrVerts[1],arrVerts[7],arrVerts3d[3],arrVerts3d[1],arrVerts3d[7]);
ScanTriangleWithCliping(arrVerts[7],arrVerts[1],arrVerts[5],arrVerts3d[7],arrVerts3d[1],arrVerts3d[5]);
}
else
{
ScanTriangleWithCliping(arrVerts[0],arrVerts[2],arrVerts[4],arrVerts3d[0],arrVerts3d[2],arrVerts3d[4]);
ScanTriangleWithCliping(arrVerts[4],arrVerts[2],arrVerts[6],arrVerts3d[4],arrVerts3d[2],arrVerts3d[6]);
}
}
void CCoverageBuffer::AddMesh(const Vec3d * arrVerts3dOS, int nVertCount, const int * pIndices, int nIndCount, Matrix44* pTranRotMatrix)
{
FUNCTION_PROFILER( GetISystem(),PROFILE_3DENGINE );
m_arrVerts3dWS_AddMesh.Clear();
m_arrVerts3dWS_AddMesh.PreAllocate(nVertCount,nVertCount);
m_arrVerts_AddMesh.Clear();
m_arrVerts_AddMesh.PreAllocate(nVertCount,nVertCount);
// transform vertices
for(int i=0; i<nVertCount; i++)
{
m_arrVerts3dWS_AddMesh[i] = pTranRotMatrix->TransformPointOLD(arrVerts3dOS[i]);
m_arrVerts_AddMesh[i] = ProjectToScreen(m_arrVerts3dWS_AddMesh[i].x,m_arrVerts3dWS_AddMesh[i].y,m_arrVerts3dWS_AddMesh[i].z);
}
/*
// find 2d bounds in screen space
Point2d min2d = m_arrVerts_AddMesh[0], max2d = m_arrVerts_AddMesh[0];
for(int i=0; i<nVertCount; i++)
{
if(m_arrVerts_AddMesh[i].x < min2d.x)
min2d.x = m_arrVerts_AddMesh[i].x;
if(m_arrVerts_AddMesh[i].x > max2d.x)
max2d.x = m_arrVerts_AddMesh[i].x;
if(m_arrVerts_AddMesh[i].y < min2d.y)
min2d.y = m_arrVerts_AddMesh[i].y;
if(m_arrVerts_AddMesh[i].y > max2d.y)
max2d.y = m_arrVerts_AddMesh[i].y;
}
// adjust 2d bounds to make it 1 pixel smaler
min2d.x += 1;
min2d.y += 1;
max2d.x -= 1;
max2d.y -= 1;
// adjust 2d vertices
for(int i=0; i<nVertCount; i++)
{
if(m_arrVerts_AddMesh[i].x < min2d.x)
m_arrVerts_AddMesh[i].x = min2d.x;
if(m_arrVerts_AddMesh[i].x > max2d.x)
m_arrVerts_AddMesh[i].x = max2d.x;
if(m_arrVerts_AddMesh[i].y < min2d.y)
m_arrVerts_AddMesh[i].y = min2d.y;
if(m_arrVerts_AddMesh[i].y > max2d.y)
m_arrVerts_AddMesh[i].y = max2d.y;
}
*/
// render tris
for(int i=0; i<nIndCount; i+=3)
{
assert(pIndices[i+0]<nVertCount);
assert(pIndices[i+1]<nVertCount);
assert(pIndices[i+2]<nVertCount);
/*
float x1 = arrVerts[pIndices[i+0]].x;
float y1 = arrVerts[pIndices[i+0]].y;
float x2 = arrVerts[pIndices[i+1]].x;
float y2 = arrVerts[pIndices[i+1]].y;
float x3 = arrVerts[pIndices[i+2]].x;
float y3 = arrVerts[pIndices[i+2]].y;
float fDot = (x1-x2)*(y3-y2)-(y1-y2)*(x3-x2);
if(fDot<0)*/
ScanTriangleWithCliping(
m_arrVerts_AddMesh[pIndices[i+0]],
m_arrVerts_AddMesh[pIndices[i+1]],
m_arrVerts_AddMesh[pIndices[i+2]],
m_arrVerts3dWS_AddMesh[pIndices[i+0]],
m_arrVerts3dWS_AddMesh[pIndices[i+1]],
m_arrVerts3dWS_AddMesh[pIndices[i+2]]);
}
}
bool CCoverageBuffer::IsBBoxVisible(const Vec3d & mins, const Vec3d & maxs)
{
if(!m_nTrisInBuffer)
return true;
Point2d verts[8] =
{ // transform into screen space
// todo: check only front faces
ProjectToScreen(mins.x,mins.y,mins.z),
ProjectToScreen(mins.x,maxs.y,mins.z),
ProjectToScreen(maxs.x,mins.y,mins.z),
ProjectToScreen(maxs.x,maxs.y,mins.z),
ProjectToScreen(mins.x,mins.y,maxs.z),
ProjectToScreen(mins.x,maxs.y,maxs.z),
ProjectToScreen(maxs.x,mins.y,maxs.z),
ProjectToScreen(maxs.x,maxs.y,maxs.z)
};
// find 2d bounds to use it as 2d quad
Point2d min2d = verts[0], max2d = verts[0];
for(int i=0; i<8; i++)
{
if(verts[i].x < min2d.x)
min2d.x = verts[i].x;
if(verts[i].x > max2d.x)
max2d.x = verts[i].x;
if(verts[i].y < min2d.y)
min2d.y = verts[i].y;
if(verts[i].y > max2d.y)
max2d.y = verts[i].y;
}
if(min2d.x<-900 || min2d.y<-900 || max2d.x<-900 || max2d.y<-900)
return true; // object intersect near plane
// make it little bigger to be sure that it's bigger than 1 pixel
min2d.x -= 0.25f;
min2d.y -= 0.25f;
max2d.x += 0.25f;
max2d.y += 0.25f;
return IsQuadVisible(min2d, max2d);
}
bool CCoverageBuffer::__IsSphereVisible(const Vec3d & vCenter, float fRadius, float fDistance)
{
if(!m_nTrisInBuffer)
return true;
Point2d Center2d = ProjectToScreen(vCenter.x,vCenter.y,vCenter.z);
float fRadius2d = fRadius * COVERAGEBUFFER_SIZE / fDistance / 2;
// find 2d quad
Point2d min2d(Center2d.x-fRadius2d, Center2d.y-fRadius2d*0.5f);
Point2d max2d(Center2d.x+fRadius2d, Center2d.y+fRadius2d*0.5f);
return IsQuadVisible(min2d, max2d);
}
bool CCoverageBuffer::IsQuadVisible(const Point2d & min2d, const Point2d & max2d)
{
// make ints
int x1 = fastfround(min2d.x);
int y1 = fastfround(min2d.y);
int x2 = fastfround(max2d.x);
int y2 = fastfround(max2d.y);
// clip quads by screen bounds and reject quads totaly outside of the screen
if(x1<0)
x1=0;
else if(x1>=COVERAGEBUFFER_SIZE)
return false;
if(y1<0)
y1=0;
else if(y1>=COVERAGEBUFFER_SIZE)
return false;
if(x2<0)
return false;
else if(x2>=COVERAGEBUFFER_SIZE)
x2=COVERAGEBUFFER_SIZE-1;
if(y2<0)
return false;
else if(y2>=COVERAGEBUFFER_SIZE)
y2=COVERAGEBUFFER_SIZE-1;
// check each pixel inside this quad, if some pixel is zero - quad is visible
for(int x=x1; x<=x2; x++)
for(int y=y1; y<=y2; y++)
if(!m_Buffer[x][y])
return true;
return 0;
}
bool CCoverageBuffer::IsPixelVisible(int nScreenX, int nScreenY)
{
if(!m_nTrisInBuffer)
return true;
nScreenX = nScreenX*COVERAGEBUFFER_SIZE/m_pRenderer->GetWidth();
nScreenY = nScreenY*COVERAGEBUFFER_SIZE/m_pRenderer->GetHeight();
if(nScreenX<0 || nScreenX>=COVERAGEBUFFER_SIZE)
return false;
if(nScreenY<0 || nScreenY>=COVERAGEBUFFER_SIZE)
return false;
return (!m_Buffer[nScreenX][nScreenY]);
}
void CCoverageBuffer::DrawDebug(int nStep)
{ // project buffer to the screen
if(!nStep)
return;
m_pRenderer->Set2DMode(true,COVERAGEBUFFER_SIZE,COVERAGEBUFFER_SIZE);
for(int x=0; x<COVERAGEBUFFER_SIZE; x+=nStep)
for(int y=0; y<COVERAGEBUFFER_SIZE; y+=nStep)
if(m_Buffer[x][y])
m_pRenderer->DrawPoint((float)x,COVERAGEBUFFER_SIZE-(float)y,0,1);
m_pRenderer->Set2DMode(false,COVERAGEBUFFER_SIZE,COVERAGEBUFFER_SIZE);
}
void CCoverageBuffer::ScanLine(int x1, int x2, int y, float & dxdyl, float & dxdyr)
{
if(y<0 || y>=COVERAGEBUFFER_SIZE)
return;
// if we reach left border - stop changing line start x
if(x1<0)
{
// dxdyl = 0;
x1 = 0;
}
// if we reach right border - stop changing line stop x
if(x2>=COVERAGEBUFFER_SIZE)
{
// dxdyr = 0;
x2 = COVERAGEBUFFER_SIZE-1;
}
// draw line
for(int x = x1; x <= x2; x++)
{
assert(x>=0 && x<COVERAGEBUFFER_SIZE);
m_Buffer[x][y]=1;
}
}
// return number of vertices to add
int CCoverageBuffer::ClipEdge(const Vec3d & v1, const Vec3d & v2, const Plane & ClipPlane, Vec3d & vRes1, Vec3d & vRes2)
{
float d1 = -ClipPlane.DistFromPlane(v1);
float d2 = -ClipPlane.DistFromPlane(v2);
if(d1<0 && d2<0)
return 0; // all clipped = do not add any vertices
if(d1>=0 && d2>=0)
{
vRes1 = v2;
return 1; // both not clipped - add second vertex
}
// calc new vertex
Vec3d vIntersectionPoint = v1 + (v2-v1)*(Ffabs(d1)/(Ffabs(d2)+Ffabs(d1)));
float fNewDist = -ClipPlane.DistFromPlane(vIntersectionPoint);
assert(fabs(fNewDist)<0.01f);
if(d1>=0 && d2<0)
{ // from vis to no vis
vRes1 = vIntersectionPoint;
return 1;
}
else if(d1<0 && d2>=0)
{ // from novis to vis
vRes1 = vIntersectionPoint;
vRes2 = v2;
return 2;
}
assert(0);
return 0;
}
void CCoverageBuffer::ClipPolygon(list2<Vec3d> * pPolygon, const Plane & ClipPlane)
{
static list2<Vec3d> PolygonOut; // Keep this list static to not perform reallocation every time.
PolygonOut.Clear();
// clip edges, make list ov new vertices
for(int i=0; i<pPolygon->Count(); i++)
{
Vec3d vNewVert1(0,0,0), vNewVert2(0,0,0);
if(int nNewVertNum = ClipEdge(pPolygon->GetAt(i), pPolygon->GetAt((i+1)%pPolygon->Count()), ClipPlane, vNewVert1, vNewVert2))
{
PolygonOut.Add(vNewVert1);
if(nNewVertNum>1)
PolygonOut.Add(vNewVert2);
}
}
// check result
for(int i=0; i<PolygonOut.Count(); i++)
{
float d1 = -ClipPlane.DistFromPlane(PolygonOut.GetAt(i));
assert(d1>=-0.01f);
}
assert(PolygonOut.Count()==0 || PolygonOut.Count() >= 3);
//Timur, optimizes memory allocation here.
pPolygon->Clear();
pPolygon->AddList( PolygonOut );
//*pPolygon = PolygonOut;
}
void CCoverageBuffer::ScanTriangleWithCliping(Point2d p1,Point2d p2,Point2d p3,
const Vec3d & v1,const Vec3d & v2,const Vec3d & v3)
{
if(IsEquivalent(v1,v2,VEC_EPSILON) || IsEquivalent(v1,v3,VEC_EPSILON) || IsEquivalent(v2,v3,VEC_EPSILON))
return; // skip degenerative triangles
// test if clipping needed
// todo: try to clip all triangles without this test (cache transformed vertices)
bool bClipingNeeded = false;
for(int p=0; p<6 ;p++)
{
float d1 = -m_Planes[p].DistFromPlane(v1);
float d2 = -m_Planes[p].DistFromPlane(v2);
float d3 = -m_Planes[p].DistFromPlane(v3);
if(d1<0 || d2<0 || d3<0)
{
bClipingNeeded = true;
break;
}
}
if(!bClipingNeeded)
{ // just use already calculated 2d points
ScanTriangle(p1,p2,p3);
return;
}
// make polygon
list2<Vec3d> arrTriangle;
arrTriangle.Clear();
arrTriangle.Add(v1);
arrTriangle.Add(v2);
arrTriangle.Add(v3);
assert(
!IsEquivalent(v1,v2,VEC_EPSILON) &&
!IsEquivalent(v1,v3,VEC_EPSILON) &&
!IsEquivalent(v2,v3,VEC_EPSILON)
);
// clip polygon
for(int p=0; p<6 ;p++)
{
ClipPolygon(&arrTriangle, m_Planes[p]);
}
// remove duplicates
for(int i=1; i<arrTriangle.Count(); i++)
{
if(
IsEquivalent(arrTriangle.GetAt(i),arrTriangle.GetAt(i-1),VEC_EPSILON)
)
{
arrTriangle.Delete(i);
i--;
}
}
assert(arrTriangle.Count()<8);
// scan
if(arrTriangle.Count()>2 && arrTriangle.Count()<8)
{
Point2d arrVerts[8];
for( int i=0; i<arrTriangle.Count(); i++ )
{ // transform into screen space
arrVerts[i] = ProjectToScreen(arrTriangle[i].x, arrTriangle[i].y, arrTriangle[i].z);
assert(arrVerts[i].x>-100);
assert(arrVerts[i].y>-100);
assert(arrVerts[i].x< 200);
assert(arrVerts[i].y< 200);
}
ScanTriangle(arrVerts[0],arrVerts[1],arrVerts[2]);
if(arrTriangle.Count()>3)
ScanTriangle(arrVerts[0],arrVerts[2],arrVerts[3]);
if(arrTriangle.Count()>4)
ScanTriangle(arrVerts[0],arrVerts[3],arrVerts[4]);
if(arrTriangle.Count()>5)
ScanTriangle(arrVerts[0],arrVerts[4],arrVerts[5]);
if(arrTriangle.Count()>6)
ScanTriangle(arrVerts[0],arrVerts[5],arrVerts[6]);
if(arrTriangle.Count()>7)
ScanTriangle(arrVerts[0],arrVerts[6],arrVerts[7]);
}
}
void CCoverageBuffer::ScanTriangle(Point2d p1,Point2d p2,Point2d p3)
{
// back face culling // todo: move one level up
float fDot = (p1.x-p2.x)*(p3.y-p2.y)-(p1.y-p2.y)*(p3.x-p2.x);
if(fDot>0)
return;
// make ints
p1.x = (float)fastfround(p1.x);
p1.y = (float)fastfround(p1.y);
p2.x = (float)fastfround(p2.x);
p2.y = (float)fastfround(p2.y);
p3.x = (float)fastfround(p3.x);
p3.y = (float)fastfround(p3.y);
// sort vertices by y
if(p2.y<p3.y)
{
Point2d tmp = p2;
p2 = p3;
p3 = tmp;
}
if(p1.y<p2.y)
{
Point2d tmp = p1;
p1 = p2;
p2 = tmp;
}
if(p2.y<p3.y)
{
Point2d tmp = p2;
p2 = p3;
p3 = tmp;
}
{ // draw top part
Point2d vLeft = (p1-p3);
Point2d vRight = (p1-p2);
float dxdyl = vLeft.x /vLeft.y;
float dxdyr = vRight.x/vRight.y;
float x1 = p1.x;
float x2 = p1.x;
if(dxdyl<dxdyr)
{ // swap
float x = x1;
x1 = x2;
x2 = x;
float d = dxdyl;
dxdyl = dxdyr;
dxdyr = d;
}
int y2 = max(fastfround(p2.y), 0); // limit by screen bottom
if(p1.y>p2.y && y2<COVERAGEBUFFER_SIZE) // if top side of triangle is visible
{
for( int y = fastfround(p1.y); y >= y2; y-- )
{
ScanLine(fastfround(x1), fastfround(x2), y, dxdyl, dxdyr);
x1 -= dxdyl;
x2 -= dxdyr;
}
}
}
{ // draw bottom part
Point2d vLeft = (p3-p1);
Point2d vRight = (p3-p2);
float dxdyl = vLeft.x /vLeft.y;
float dxdyr = vRight.x/vRight.y;
float x1 = p3.x;
float x2 = p3.x;
if(dxdyl>dxdyr)
{ // swap
float x = x1;
x1 = x2;
x2 = x;
float d = dxdyl;
dxdyl = dxdyr;
dxdyr = d;
}
int y2 = min(fastfround(p2.y),COVERAGEBUFFER_SIZE);// limit by screen top
if(p2.y>p3.y && y2>0) // if bottom side of triangle is visible ((y2) line was already drawn)
{
for( int y = fastfround(p3.y); y < y2; y++ ) // ((y2) line was already drawn)
{
ScanLine(fastfround(x1), fastfround(x2), y, dxdyl, dxdyr);
x1 += dxdyl;
x2 += dxdyr;
}
}
}
m_nTrisInBuffer++;
}
void CCoverageBuffer::BeginFrame(const CCamera & camera)
{
for(int p=0; p<6 ;p++)
m_Planes[p] = *camera.GetFrustumPlane(p);
// make matrices
m_matViewPort[0] = 0;
m_matViewPort[1] = 0;
m_matViewPort[2] = COVERAGEBUFFER_SIZE;
m_matViewPort[3] = COVERAGEBUFFER_SIZE;
float matModel[16];
float matProj[16];
m_pRenderer->GetModelViewMatrix(matModel);
m_pRenderer->GetProjectionMatrix(matProj);
MatMul4(m_matCombined,matProj,matModel);
// reset buffer
memset(m_Buffer,0,sizeof(m_Buffer));
m_nTrisInBuffer=0;
}

97
Cry3DEngine/cbuffer.h Normal file
View File

@@ -0,0 +1,97 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: cbuffer.h
// Version: v1.00
// Created: 30/5/2002 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: Occlusion buffer
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#ifndef _CBUFFER_H
#define _CBUFFER_H
#define COVERAGEBUFFER_SIZE 128
#define COVERAGEBUFFER_OCCLUDERS_MAX_DISTANCE 32
#define COVERAGEBUFFER_OCCLUSION_TESTERS_MIN_DISTANCE 32
class CCoverageBuffer
{
uchar m_Buffer[COVERAGEBUFFER_SIZE][COVERAGEBUFFER_SIZE];
IRenderer * m_pRenderer;
int m_matViewPort[4];
float m_matCombined[16];
Plane m_Planes[6];
struct Point2d
{
float x,y;
Point2d(){};
Point2d(float _x, float _y) { x=_x; y=_y; }
Point2d operator - (Point2d & o) { return Point2d (x - o.x,y - o.y); }
};
Point2d ProjectToScreen(const float & x, const float & y, const float & z);
void ScanTriangle(Point2d p1,Point2d p2,Point2d p3);
void ScanTriangleWithCliping(Point2d p1,Point2d p2,Point2d p3,
const Vec3d & v1,const Vec3d & v2,const Vec3d & v3);
void ScanLine(int x1, int x2, int y, float & dxdyl, float & dxdyr);
bool IsQuadVisible(const Point2d & min2d, const Point2d & max2d);
#if defined(WIN32) && defined(_CPU_X86)
inline int fastfround(float f) // note: only positive numbers works correct
{
int i;
__asm fld [f]
__asm fistp [i]
return i;
}
#else
inline int fastfround(float f) { int i; i=(int)(f+0.5f); return i; } // note: only positive numbers works correct
#endif
void TransformPoint(float out[4], const float m[16], const float in[4]);
void MatMul4( float *product, const float *a, const float *b );
static int ClipEdge(const Vec3d & v1, const Vec3d & v2, const Plane & ClipPlane, Vec3d & vRes1, Vec3d & vRes2);
// tmp containers
list2<Vec3d> m_arrVerts3dWS_AddMesh;
list2<Point2d> m_arrVerts_AddMesh;
int m_nTrisInBuffer;
public:
CCoverageBuffer(IRenderer * pRenderer)
{
m_pRenderer = pRenderer;
memset(m_Buffer,0,sizeof(m_Buffer));
m_nTrisInBuffer=0;
}
// start new frame
void BeginFrame(const CCamera & camera);
// render into buffer
void AddBBox(const Vec3d & vMins, const Vec3d & vMaxs, const Vec3d & vDirToCamera);
void AddMesh(const Vec3d * arrVerts3d, int nVertCount, const int * pIndices, int nIndCount, Matrix44 * pTranRotMatrix);
// test visibility
bool IsBBoxVisible(const Vec3d & vMins, const Vec3d & vMaxs);
bool __IsSphereVisible(const Vec3d & vCenter, float fRadius, float fDistance);
bool IsPixelVisible(int nScreenX, int nScreenY);
// draw content to the screen for debug
void DrawDebug(int nStep);
// can be used by other classes
static void ClipPolygon(list2<Vec3d> * pPolygon, const Plane & ClipPlane);
};
#endif

218
Cry3DEngine/cvars.cpp Normal file
View File

@@ -0,0 +1,218 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: cvars.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: console variables used in 3dengine
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "3dEngine.h"
#include "irenderer.h"
// can not be changed by user
#define INIT_CVAR_CHEAT(_var,_def_val,_comment)\
(_var) = GetConsole()->Register((#_var), &(_var), (_def_val), VF_CHEAT, _comment);
// can be changed in options menu, will be saved into ini file
#define INIT_CVAR_SER__( _var, _def_val,_comment )\
( _var ) = GetConsole()->Register( (#_var), &(_var), (_def_val), (e_allow_cvars_serialization ? VF_DUMPTODISK : 0), _comment );
// can be changed in options menu, will be saved into ini file, require level restart
#define INIT_CVAR_SER_R( _var, _def_val,_comment )\
( _var ) = GetConsole()->Register( (#_var), &(_var), (_def_val), (e_allow_cvars_serialization ? VF_DUMPTODISK : 0)|VF_REQUIRE_LEVEL_RELOAD, _comment );
#define INIT_CVAR_SER_R_NET( _var, _def_val,_comment )\
( _var ) = GetConsole()->Register( (#_var), &(_var), (_def_val), (e_allow_cvars_serialization ? VF_DUMPTODISK : 0)|VF_REQUIRE_LEVEL_RELOAD|VF_REQUIRE_NET_SYNC, _comment );
// can be changed by game or user
#define INIT_CVAR_PUBL_(_var,_def_val,_comment)\
(_var) = GetConsole()->Register((#_var), &(_var), (_def_val), 0, _comment);
void CVars::Init()
{
// Ints
INIT_CVAR_CHEAT(e_allow_cvars_serialization, 1, "If set to zero - will not save cvars to cfg file");
INIT_CVAR_CHEAT(e_detail_objects, 1, "Activates drawing of detail objects");
INIT_CVAR_CHEAT(e_fog, 1, "Activates distance based fog");
INIT_CVAR_CHEAT(e_motion_blur, 0, "Activates motion blur, values from 1 to 7 will change blur type");
INIT_CVAR_SER_R(e_beach, 1, "Activates drawing of shore on the border of the ocean");
INIT_CVAR_CHEAT(e_detail_texture, 1, "Activates drawing of detail textures on terrain ground");
INIT_CVAR_SER_R(e_detail_texture_quality, 1, "0 - use one single texture per entire level, 1 - use multiple textures");
INIT_CVAR_CHEAT(e_particles, 1, "Activates drawing of particles");
INIT_CVAR_CHEAT(e_particles_debug, 0, "Debug");
INIT_CVAR_SER__(e_particles_max_count, 2048, "Maximum number of particles");
INIT_CVAR_SER__(e_decals, 1, "Activates drawing of decals (marks from bullets and explosions)");
INIT_CVAR_CHEAT(e_bflyes, 1, "Activates drawing of butterflies around the camera");
INIT_CVAR_CHEAT(e_vegetation_bending, 2, "Debug");
INIT_CVAR_CHEAT(e_vegetation, 1, "Activates drawing of distributed objects like trees");
INIT_CVAR_CHEAT(e_vegetation_sprites, 1, "Activates drawing of sprites instead of distributed objects at far distance");
INIT_CVAR_CHEAT(e_entities, 1, "Activates drawing of entities and brushes");
INIT_CVAR_CHEAT(e_entities_debug, 0, "Debug");
INIT_CVAR_CHEAT(e_sky_box, 1, "Activates drawing of skybox and moving cloud layers");
INIT_CVAR_CHEAT(e_terrain, 1, "Activates drawing of terain ground");
INIT_CVAR_CHEAT(e_terrain_debug, 0, "Debug");
INIT_CVAR_SER_R(e_shadow_maps, 1, "Activates drawing of shadow maps");
INIT_CVAR_SER_R(e_shadow_maps_from_static_objects,1, "Activates drawing of shadow maps from distributed objects");
INIT_CVAR_CHEAT(e_water_ocean, 1, "Activates drawing of ocean");
INIT_CVAR_CHEAT(e_vegetation_debug, 0, "Debug");
INIT_CVAR_CHEAT(e_shadow_maps_frustums, 0, "Debug");
INIT_CVAR_CHEAT(e_terrain_occlusion_culling, 1, "heightmap occlusion culling with time coherency 0=off, 1=on(distant occluders not processed),\n"
"4=on(distant occluders still processed but with less precision) ]");
INIT_CVAR_CHEAT(e_terrain_texture_bind, 1, "Debug");
INIT_CVAR_CHEAT(e_terrain_log, 0, "Debug");
INIT_CVAR_CHEAT(e_out_space, 0, "Debug");
INIT_CVAR_CHEAT(e_sun, 1, "Activates sun light source");
INIT_CVAR_CHEAT(e_terrain_merge_far_sectors, 1, "Render far heightmap sectors as one mesh");
INIT_CVAR_CHEAT(e_terrain_texture_mipmaps, 0, "Debug");
INIT_CVAR_CHEAT(e_timedemo_frames, 0, "Will quit appication in X number of frames, r_DisplayInfo must be also enabled");
INIT_CVAR_CHEAT(e_timedemo_milliseconds, 0, "Will quit appication in X number of milliseconds");
INIT_CVAR_CHEAT(e_terrain_texture_pool, 0, "Debug");
#ifdef _DEBUG
INIT_CVAR_CHEAT(e_cbuffer, 0, "Activates usage of software coverage buffer");
#else
INIT_CVAR_CHEAT(e_cbuffer, 1, "Activates usage of software coverage buffer");
#endif
INIT_CVAR_SER_R(e_stencil_shadows, 1, "Activates drawing of shadow volumes");
INIT_CVAR_CHEAT(e_shadow_maps_debug, 0, "Debug");
INIT_CVAR_CHEAT(e_dynamic_light, 1, "Activates dynamic light sources");
INIT_CVAR_CHEAT(e_dynamic_light_exact_vis_test,1, "Use more exact visibility test (based on last draw frame)");
INIT_CVAR_CHEAT(e_dynamic_light_debug, 0, "Debug");
INIT_CVAR_CHEAT(e_hw_occlusion_culling_water, 1, "Activates usage of HW occlusion test for ocean");
INIT_CVAR_CHEAT(e_hw_occlusion_culling_objects,0, "Activates usage of HW occlusion test for objects");
INIT_CVAR_PUBL_(e_hires_screenshoot, 0, "Writes screenshot to disk, X is scale of image resolution relative to current one, big values can cause crash");
INIT_CVAR_CHEAT(e_portals, 1, "Activates drawing of visareas content (indoors), values 2,3,4 used for debugging");
INIT_CVAR_SER__(e_max_entity_lights, 4, "Set maximum number of lights affecting object");
INIT_CVAR_PUBL_(e_max_shadow_map_size, 512, "Set maximum resolution of shadow map, this value is alos limited by screen resolution in OpenGL");
INIT_CVAR_CHEAT(e_water_volumes, 1, "Activates drawing of water volumes");
INIT_CVAR_CHEAT(e_bboxes, 0, "Activates drawing of bounding boxes");
INIT_CVAR_CHEAT(e_register_in_sectors, 1, "Debug, can cause crash");
INIT_CVAR_CHEAT(e_stream_cgf, 0, "Debug");
INIT_CVAR_CHEAT(e_stream_for_physics, 1, "Debug");
INIT_CVAR_CHEAT(e_stream_for_visuals, 1, "Debug");
INIT_CVAR_CHEAT(e_scissor_debug, 0, "Debug");
INIT_CVAR_CHEAT(e_projector_exact_test, 1, "Debug");
INIT_CVAR_CHEAT(e_ccgf_load, 0, "Load CCGF if found");
INIT_CVAR_CHEAT(e_ccgf_make_if_not_found, 0, "Make CCGF if not found");
INIT_CVAR_CHEAT(e_check_number_of_physicalized_polygons, 1,
"Activates check (during loading) for number of tris in the objects physics representation\n Current maximum is 100 + overall number of tris divided by 2");
INIT_CVAR_CHEAT(e_materials, 1, "Activates material support for non animated objects");
INIT_CVAR_CHEAT(e_vegetation_sprites_slow_switch, 1, "Orient 3d vegetations and sprites to much each other");
INIT_CVAR_CHEAT(e_terrain_single_pass, 1, "Draw all terrain detail layers in single pass");
INIT_CVAR_CHEAT(e_light_maps, 1, "Use lightmaps on brushes");
INIT_CVAR_CHEAT(e_stream_areas, 0, "Stream content of terrain and indoor sectors");
INIT_CVAR_CHEAT(e_stream_preload_textures, 0, "If texture streaming in renderer enabled - dynamicaly preload textures in x neibhour indoor sectors");
INIT_CVAR_CHEAT(e_area_merging_distance, 0, "Merge sectror geometry in specified range for rendering speedup");
INIT_CVAR_CHEAT(e_area_merging_draw_merged_geometry_only, 0, "Do not draw not merged objects");
INIT_CVAR_CHEAT(e_brushes, 1, "Draw brushes");
INIT_CVAR_CHEAT(e_brushes_merging_debug, 0, "Print debug info of merged brushes");
INIT_CVAR_SER_R(e_brushes_merging, 1, "Merge marked brushes during loading");
INIT_CVAR_CHEAT(e_brushes_onlymerged, 0, "Show only merged brushes");
INIT_CVAR_CHEAT(e_on_demand_physics, 0, "Turns on on-demand physicalization");
INIT_CVAR_SER_R(e_light_maps_quality, 1, "define quality for lightmaps (0-2)");
INIT_CVAR_CHEAT(e_sleep, 0, "Sleep X in C3DEngine::Draw");
INIT_CVAR_CHEAT(e_objects, 1, "Render or not all objects on terrain");
INIT_CVAR_CHEAT(e_terrain_draw_this_sector_only, 0, "1 - render only sector where camera is and objects registered in sector 00, 2 - render only sector where camera is");
INIT_CVAR_CHEAT(e_sun_stencil, 0, "Enable stencil shadows from sun light");
INIT_CVAR_CHEAT(e_terrain_single_pass_vol_fog,0, "Use single pass volumetric fog on terrain where possible");
INIT_CVAR_CHEAT(e_occlusion_volumes, 1, "Enable occlusion volumes(antiportals)");
INIT_CVAR_CHEAT(e_terrain_texture_mip_offset, 0, "Allows to reduce terrain texture resolution by selecting more low mips from texture file");
INIT_CVAR_SER__(e_overlay_geometry, 1, "Enable rendering of overlay geometry");
INIT_CVAR_CHEAT(e_player, 1, "Draw main player");
INIT_CVAR_CHEAT(e_vegetation_sprites_texres, 0, "Sprite texture size modifier. 0 - no scale, 1 - scale 2 times down and so on");
INIT_CVAR_SER__(e_active_shadow_maps_receving,0, "Allow shadow map receiving from all objects");
INIT_CVAR_PUBL_(e_shadow_maps_fade_from_light_bit, 1, "Fade shadow maps on terrain if caster is in dark area");
INIT_CVAR_PUBL_(e_capture_frames, 0, "If set to 1 - will save every frame to tga file");
INIT_CVAR_PUBL_(e_water_ocean_tesselation, -1, "0 - default tesselation, 2 - high tesselation, -1 - select automatically depends on per pixel projection support");
INIT_CVAR_PUBL_(e_shadow_maps_size_ratio, 500,"Controls how shadow map resolution depends from distance to object from camera");
INIT_CVAR_SER__(e_shadow_spots, 0, "Draw shadow spot under entities");
INIT_CVAR_SER_R(e_use_global_fog_in_fog_volumes,0, "simulate ocean volume fog using global fog");
INIT_CVAR_CHEAT(e_precache_level, 1, "Pre-render objects right after level loading");
INIT_CVAR_PUBL_(e_shadow_maps_max_casters_per_object, 8, "Maximum number of active shadow casters per object");
INIT_CVAR_PUBL_(e_water_ocean_sun_reflection, 0, "Draw sun reflection in the ocean");
INIT_CVAR_CHEAT(e_objects_fade_on_distance, 1, "Objects fading out on distance");
INIT_CVAR_PUBL_(e_area_merging_max_tris_in_input_brush, 512, "Merge only objects containing no more than x triangles");
INIT_CVAR_SER__(e_stencil_shadows_only_from_strongest_light, 0, "Cast no more than one stencil shadow from object");
INIT_CVAR_SER_R(e_cgf_load_lods, 1, "Load LOD models for CGFs if found");
INIT_CVAR_CHEAT(e_optimized_render_object, 1, "test");
INIT_CVAR_CHEAT(e_stencil_shadows_build_on_load, 1, "Build connectivity during level loading");
INIT_CVAR_PUBL_(e_vegetation_update_shadow_every_frame, 1, "Allow updating vegetations shadow maps every frame");
INIT_CVAR_CHEAT(e_particles_receive_shadows, 0, "Enable shadow maps receiving for particles");
INIT_CVAR_CHEAT(e_light_maps_occlusion, 0, "Enable usage of occlusion maps");
INIT_CVAR_CHEAT(e_shadow_maps_self_shadowing, 0, "Allow self-shadowing with shadow maps");
INIT_CVAR_CHEAT(e_voxel_build, 0, "Regenerate voxel world");
INIT_CVAR_CHEAT(e_voxel_debug, 0, "Draw voxel debug info");
INIT_CVAR_CHEAT(e_voxel_realtime_light_update,0, "Recalculate voxel terrain vertex colors every frame");
INIT_CVAR_CHEAT(e_widescreen, 0, "Activate wide screen mode");
INIT_CVAR_PUBL_(e_shadow_maps_receiving, 1, "Allow shadow maps receiving by brushes, vegetation and entities");
// Floats
INIT_CVAR_PUBL_(e_vegetation_sprites_min_distance, 8.0f, "Sets minimal distance when distributed object can be replaced with sprite");
INIT_CVAR_PUBL_(e_rain_amount, 0.0f, "Values between 0 and 1 controls density of the rain");
INIT_CVAR_SER__(e_vegetation_sprites_distance_ratio, 1.0f, "Allows changing distance on what vegetation switch into sprite");
INIT_CVAR_SER__(e_obj_lod_ratio, 10.0f, "LOD for vegetation, brushes and entities");
INIT_CVAR_CHEAT(e_obj_view_dist_ratio, 55.0f, "View distance for vegetation, brushes and entities");
INIT_CVAR_CHEAT(e_dynamic_ambient_ratio, 1.0f, "Controls how object ambient level dependinds from surrounding lights");
INIT_CVAR_PUBL_(e_detail_texture_min_fov,0.55f,"If FOV is less - alternative version of terrain detail texturing will be used");
INIT_CVAR_SER_R_NET(e_vegetation_min_size, 0.0f, "Minimal size of static object, smaller objects will be not rendered");
INIT_CVAR_CHEAT(e_terrain_occlusion_culling_precision, 0.15f, "Density of rays");
INIT_CVAR_PUBL_(e_terrain_lod_ratio, 1.f, "Set heightmap LOD");
INIT_CVAR_SER__(e_particles_lod, 1.f, "1 - full LOD, 0.5 - scale frequency and count down twice");
INIT_CVAR_CHEAT(e_debug_lights, 0, "Use different colors for objects affected by different number of lights\n 0 - back, 1 - blue, 2 - green, 3 or more - red");
INIT_CVAR_SER__(e_shadow_maps_view_dist_ratio, 10, "View dist ratio for shadow maps");
INIT_CVAR_SER__(e_decals_life_time_scale, 1.f, "Allows to increase or reduce decals life time for different specs");
INIT_CVAR_CHEAT(e_obj_min_view_dist, 0.f, "Min distance on what far objects will be culled out");
INIT_CVAR_CHEAT(e_decals_neighbor_max_life_time, 4.f, "If not zero - new decals will force old decals to fade in X seconds");
INIT_CVAR_CHEAT(e_explosion_scale, 0.6666f, "Scale size of terrain deformations and explosion decals");
e_capture_folder = GetConsole()->CreateVariable("e_capture_folder", "CaptureOutput", 0, "Set output folder for video capturing");
e_capture_file_format = GetConsole()->CreateVariable("e_capture_file_format", "JPG", 0, "Set output image file format for video capturing. Can be JPG or TGA");
e_deformable_terrain = GetConsole()->CreateVariable("e_deformable_terrain","1",VF_REQUIRE_NET_SYNC,
"Toggles terrain deforming.\n"
"Usage: e_deformable_terrain [0/1]\n"
"Default is 1 (on). Terrain is deformed by explosions. Set\n"
"to 0 to disable terrain deforming.");
if(e_water_ocean_tesselation<0)
{
ICVar * pVar = GetConsole()->GetCVar("e_water_ocean_tesselation");
if(GetRenderer()->GetFeatures()&RFT_HW_ENVBUMPPROJECTED)
pVar->Set(0);
else
pVar->Set(1);
}
// vars validation
if(ICVar * pVar0 = GetConsole()->GetCVar("r_Quality_BumpMapping"))
if(pVar0->GetIVal()==0)
{
if(ICVar * pVar1 = GetConsole()->GetCVar("e_shadow_maps"))
pVar1->Set(0);
if(ICVar * pVar1 = GetConsole()->GetCVar("e_stencil_shadows"))
pVar1->Set(0);
}
int nGPU = GetRenderer()->GetFeatures() & RFT_HW_MASK;
if(nGPU == RFT_HW_GF2)
{
if(ICVar * pVar1 = GetConsole()->GetCVar("e_detail_texture_quality"))
pVar1->Set(0);
}
if(!(GetRenderer()->GetFeatures() & (RFT_DEPTHMAPS|RFT_SHADOWMAP_SELFSHADOW)))
{
if(ICVar * pVar1 = GetConsole()->GetCVar("e_shadow_maps_receiving"))
pVar1->Set(0);
}
}

171
Cry3DEngine/cvars.h Normal file
View File

@@ -0,0 +1,171 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: cvars.h
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#ifndef _3DENGINE_CVARS_H_
#define _3DENGINE_CVARS_H_
// console variables
struct CVars : public Cry3DEngineBase
{
CVars()
{ Init(); }
void Init();
int
e_allow_cvars_serialization,
e_shadow_maps,
e_shadow_maps_debug,
e_shadow_maps_from_static_objects,
e_shadow_maps_self_shadowing,
e_shadow_maps_receiving,
e_detail_objects,
e_fog,
e_motion_blur,
e_beach,
e_detail_texture,
e_detail_texture_quality,
e_particles,
e_particles_debug,
e_particles_max_count,
e_particles_receive_shadows,
e_decals,
e_bflyes,
e_vegetation_bending,
e_vegetation,
e_vegetation_sprites,
e_entities,
e_entities_debug,
e_sky_box,
e_terrain,
e_terrain_debug,
e_water_ocean,
e_vegetation_debug,
e_shadow_maps_frustums,
e_terrain_occlusion_culling,
e_terrain_texture_pool,
e_terrain_texture_bind,
e_terrain_log,
e_out_space,
e_video_buffer_stats,
e_sun,
e_terrain_merge_far_sectors,
e_terrain_texture_mipmaps,
e_terrain_texture_mip_offset,
// if set to non-0, then after the specified number of frames rendered,
// the game exits printing the average FPS value.
// NOTE:
// for this to work, the r_DisplayInfo must be "1"
e_timedemo_frames,
// if set to non-0, then after the specified number of milliseconds of rendering,
// the game exists unconditionally. This is used for automatic multipass profiling with VTune 6.x
e_timedemo_milliseconds,
e_cbuffer,
e_dynamic_light,
e_dynamic_light_exact_vis_test,
e_stencil_shadows,
e_dynamic_light_debug,
e_hw_occlusion_culling_water,
e_hw_occlusion_culling_objects,
e_hires_screenshoot,
e_portals,
e_max_entity_lights,
e_max_shadow_map_size,
e_water_volumes,
e_bboxes,
e_brushes,
e_brushes_merging_debug,
e_brushes_merging,
e_brushes_onlymerged,
e_register_in_sectors,
e_stream_cgf,
e_stream_for_physics,
e_stream_for_visuals,
e_stream_areas,
e_scissor_debug,
e_projector_exact_test,
e_ccgf_load,
e_ccgf_make_if_not_found,
e_check_number_of_physicalized_polygons,
e_materials,
e_vegetation_sprites_slow_switch,
e_terrain_single_pass,
e_stream_preload_textures,
e_area_merging_distance,
e_area_merging_draw_merged_geometry_only,
e_area_merging_max_tris_in_input_brush,
e_on_demand_physics,
e_light_maps,
e_light_maps_quality,
e_light_maps_occlusion,
e_sleep,
e_objects,
e_terrain_draw_this_sector_only,
e_sun_stencil,
e_terrain_single_pass_vol_fog,
e_occlusion_volumes,
e_overlay_geometry,
e_player,
e_vegetation_sprites_texres,
e_active_shadow_maps_receving,
e_shadow_maps_fade_from_light_bit,
e_capture_frames,
e_water_ocean_tesselation,
e_shadow_maps_size_ratio,
e_shadow_spots,
e_use_global_fog_in_fog_volumes,
e_precache_level,
e_shadow_maps_max_casters_per_object,
e_water_ocean_sun_reflection,
e_objects_fade_on_distance,
e_stencil_shadows_only_from_strongest_light,
e_cgf_load_lods,
e_optimized_render_object,
e_stencil_shadows_build_on_load,
e_vegetation_update_shadow_every_frame,
e_voxel_build,
e_voxel_debug,
e_voxel_realtime_light_update,
e_widescreen;
float
e_vegetation_sprites_min_distance,
e_rain_amount,
e_vegetation_sprites_distance_ratio,
e_obj_lod_ratio,
e_obj_view_dist_ratio,
e_dynamic_ambient_ratio,
e_detail_texture_min_fov,
e_terrain_occlusion_culling_precision,
e_vegetation_min_size,
e_terrain_lod_ratio,
e_particles_lod,
e_debug_lights,
e_shadow_maps_view_dist_ratio,
e_decals_life_time_scale,
e_decals_neighbor_max_life_time,
e_obj_min_view_dist,
e_explosion_scale;
ICVar
* e_capture_folder,
* e_capture_file_format,
* e_deformable_terrain;
};
#endif // _3DENGINE_CVARS_H_

103
Cry3DEngine/dds.h Normal file
View File

@@ -0,0 +1,103 @@
// dds.h
//
// This header defines constants and structures that are useful when parsing
// DDS files. DDS files were originally designed to use several structures
// and constants that are native to DirectDraw and are defined in ddraw.h,
// such as DDSURFACEDESC2 and DDSCAPS2. This file defines similar
// (compatible) constants and structures so that one can use DDS files
// without needing to include ddraw.h.
#ifndef _DDS_H_
#define _DDS_H_
struct DDS_PIXELFORMAT
{
DWORD dwSize;
DWORD dwFlags;
DWORD dwFourCC;
DWORD dwRGBBitCount;
DWORD dwRBitMask;
DWORD dwGBitMask;
DWORD dwBBitMask;
DWORD dwABitMask;
};
#define DDS_FOURCC 0x00000004 // DDPF_FOURCC
#define DDS_RGB 0x00000040 // DDPF_RGB
#define DDS_RGBA 0x00000041 // DDPF_RGB | DDPF_ALPHAPIXELS
const DDS_PIXELFORMAT DDSPF_DXT1 =
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','1'), 0, 0, 0, 0, 0 };
const DDS_PIXELFORMAT DDSPF_DXT2 =
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','2'), 0, 0, 0, 0, 0 };
const DDS_PIXELFORMAT DDSPF_DXT3 =
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','3'), 0, 0, 0, 0, 0 };
const DDS_PIXELFORMAT DDSPF_DXT4 =
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','4'), 0, 0, 0, 0, 0 };
const DDS_PIXELFORMAT DDSPF_DXT5 =
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','5'), 0, 0, 0, 0, 0 };
const DDS_PIXELFORMAT DDSPF_A8R8G8B8 =
{ sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 };
const DDS_PIXELFORMAT DDSPF_A1R5G5B5 =
{ sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00007c00, 0x000003e0, 0x0000001f, 0x00008000 };
const DDS_PIXELFORMAT DDSPF_A4R4G4B4 =
{ sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00000f00, 0x000000f0, 0x0000000f, 0x0000f000 };
const DDS_PIXELFORMAT DDSPF_R8G8B8 =
{ sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 };
const DDS_PIXELFORMAT DDSPF_R5G6B5 =
{ sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x0000f800, 0x000007e0, 0x0000001f, 0x00000000 };
#define DDS_HEADER_FLAGS_TEXTURE 0x00001007 // DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT
#define DDS_HEADER_FLAGS_MIPMAP 0x00020000 // DDSD_MIPMAPCOUNT
#define DDS_HEADER_FLAGS_VOLUME 0x00800000 // DDSD_DEPTH
#define DDS_HEADER_FLAGS_PITCH 0x00000008 // DDSD_PITCH
#define DDS_HEADER_FLAGS_LINEARSIZE 0x00080000 // DDSD_LINEARSIZE
#define DDS_SURFACE_FLAGS_TEXTURE 0x00001000 // DDSCAPS_TEXTURE
#define DDS_SURFACE_FLAGS_MIPMAP 0x00400008 // DDSCAPS_COMPLEX | DDSCAPS_MIPMAP
#define DDS_SURFACE_FLAGS_CUBEMAP 0x00000008 // DDSCAPS_COMPLEX
#define DDS_CUBEMAP_POSITIVEX 0x00000600 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX
#define DDS_CUBEMAP_NEGATIVEX 0x00000a00 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX
#define DDS_CUBEMAP_POSITIVEY 0x00001200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY
#define DDS_CUBEMAP_NEGATIVEY 0x00002200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY
#define DDS_CUBEMAP_POSITIVEZ 0x00004200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ
#define DDS_CUBEMAP_NEGATIVEZ 0x00008200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ
#define DDS_CUBEMAP_ALLFACES ( DDS_CUBEMAP_POSITIVEX | DDS_CUBEMAP_NEGATIVEX |\
DDS_CUBEMAP_POSITIVEY | DDS_CUBEMAP_NEGATIVEY |\
DDS_CUBEMAP_POSITIVEZ | DDS_CUBEMAP_NEGATIVEZ )
#define DDS_FLAGS_VOLUME 0x00200000 // DDSCAPS2_VOLUME
#define DDS_RESF1_NORMALMAP 0x01000000
#define DDS_RESF1_DSDT 0x02000000
struct DDS_HEADER
{
DWORD dwSize;
DWORD dwHeaderFlags;
DWORD dwHeight;
DWORD dwWidth;
DWORD dwPitchOrLinearSize;
DWORD dwDepth; // only if DDS_HEADER_FLAGS_VOLUME is set in dwHeaderFlags
DWORD dwMipMapCount;
DWORD dwReserved1[11];
DDS_PIXELFORMAT ddspf;
DWORD dwSurfaceFlags;
DWORD dwCubemapFlags;
DWORD dwReserved2[3];
};
#endif

View File

@@ -0,0 +1,679 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: detail_grass.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: create and draw grass/detail object volume right in front of camera
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "statobj.h"
#include "detail_grass.h"
#include <IXMLDOM.h>
// class to store vertex buffer for single grass object
struct GrassType : public Cry3DEngineBase
{
public:
struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * pVertices;
uint * uipIndices, nIndCount, nVertCount;
int nTexID;
char sObjectFileName[256];
CStatObj * m_pObject;
GrassType(char * fname)
{ // load object and make buffers
memset(this,0,sizeof(*this));
strncpy(sObjectFileName,fname,sizeof(sObjectFileName));
m_pObject = new CStatObj( );
if(!m_pObject->Load(fname, NULL, evs_ShareAndSortForCache, false, false))
{
delete m_pObject;
m_pObject=0;
return;
}
int tris_count = 0;
CLeafBuffer * pLeafBuffer = m_pObject->GetLeafBuffer();
if(!pLeafBuffer)
return; // objects may have no leaf buffer created on dedicated server
pLeafBuffer->GetIndices(&tris_count);
tris_count/=3;
if(tris_count>12)
{
#if !defined(LINUX)
Warning( 0,0,"Detail object has more than 12 triangles, skiped: %s (%d tris)",fname,tris_count );
#endif
return;
}
nVertCount = pLeafBuffer->m_SecVertCount;
pVertices = new struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F[nVertCount];
uipIndices = new uint[tris_count*3];
Vec3d vCenter = (m_pObject->GetBoxMax()+m_pObject->GetBoxMin())/2;
struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * pSecVerts = (struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F*)pLeafBuffer->m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData;
ushort *pInds = pLeafBuffer->GetIndices(NULL);
int nStrPos;
byte *pPos = pLeafBuffer->GetPosPtr(nStrPos, 0, true);
int nStrST;
byte *pST = pLeafBuffer->GetUVPtr(nStrST, 0, true);
for(int i=0; i<tris_count*3; i++)
{
uint id = pInds[i];
Vec3d *vSrcPos = (Vec3d *)&pPos[nStrPos*id];
float *fSrcST = (float *)&pST[nStrST*id];
pVertices[id].xyz.x = vSrcPos->x - vCenter.x;
pVertices[id].xyz.y = vSrcPos->y - vCenter.y;
pVertices[id].xyz.z = vSrcPos->z;// - pObject->GetBoxMin().z;
pVertices[id].st[0] = fSrcST[0];
pVertices[id].st[1] = fSrcST[1];
/* if(pLeafBuffer->m_pLoadedColors)
{
pVertices[id].r = pSecVerts[id].color[0];
pVertices[id].g = pSecVerts[id].color[1];
pVertices[id].b = pSecVerts[id].color[2];
pVertices[id].a = 255;
}
else*/
{
pVertices[id].color.dcolor = -1;
}
uipIndices[nIndCount++] = id;
}
if( m_pObject->GetLeafBuffer()->m_pMats->Count() &&
m_pObject->GetLeafBuffer()->m_pMats->Get(0)->shaderItem.m_pShader &&
m_pObject->GetLeafBuffer()->m_pMats->Get(0)->shaderItem.m_pShaderResources->m_Textures[EFTT_DIFFUSE] &&
m_pObject->GetLeafBuffer()->m_pMats->Get(0)->shaderItem.m_pShaderResources->m_Textures[EFTT_DIFFUSE]->m_TU.m_ITexPic )
{
nTexID = (m_pObject->GetLeafBuffer()->m_pMats->Get(0)->shaderItem.m_pShaderResources->m_Textures[EFTT_DIFFUSE]->m_TU.m_ITexPic)->GetTextureID();
}
else
{
nTexID = GetRenderer()->LoadTexture("none");
}
// assert(nTexID>=4096);
}
~GrassType()
{
delete m_pObject;
delete [] pVertices;
delete [] uipIndices;
}
int GetMemoryUsage()
{
return sizeof(struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F) * nVertCount + sizeof(uint) * nIndCount;
}
};
// load objects
CDetailGrass::CDetailGrass(XDOM::IXMLDOMNodeListPtr pDetTexTagList)
{
memset(this,0,sizeof(*this));
// m_pGrassVertices = 0;
m_GrassVerticesCount = 0;
m_GrassFocusX = m_GrassFocusY = -CTerrain::GetTerrainSize(); // grass focus
m_nGrassDensity = 2;
if( !m_nGrassDensity )
return;
UpdateLoadingScreen("Loading detail objects ...");
m_GrassModelsArray.Clear();
// load detail textures
if (pDetTexTagList)
{
XDOM::IXMLDOMNodePtr pDetTexTag;
pDetTexTagList->reset();
pDetTexTag = pDetTexTagList->nextNode();
XDOM::IXMLDOMNodeListPtr pDetTexList;
pDetTexList = pDetTexTag->getElementsByTagName("SurfaceType");
if (pDetTexList)
{
pDetTexList->reset();
XDOM::IXMLDOMNodePtr pDetTex;
int nId = 0;
while (pDetTex = pDetTexList->nextNode())
{
XDOM::IXMLDOMNodeListPtr pDetailObjectsList = pDetTex->getElementsByTagName("DetailObjects");
pDetailObjectsList->reset();
XDOM::IXMLDOMNodePtr pDetailObject;
while(pDetailObject = pDetailObjectsList->nextNode())
{
XDOM::IXMLDOMNodeListPtr pObjList = pDetailObject->getElementsByTagName("Object");
if(pObjList)
{
XDOM::IXMLDOMNodePtr pObj;
pObjList->reset();
while(pObj = pObjList->nextNode())
{
XDOM::IXMLDOMNodePtr pName = pObj->getAttribute("Name");
char sObjectsName[256];
strcpy(sObjectsName,pName->getText());
if(!sObjectsName[0])
break;
// try to find already loaded
int l=0;
for(l=0; l<m_GrassModelsArray.Count(); l++)
{
if(strcmp(m_GrassModelsArray[l]->sObjectFileName,sObjectsName)==0)
break;
}
if(l>=m_GrassModelsArray.Count())
{ // not found
GrassType * triData = new GrassType( sObjectsName );
if(triData && (*triData).nIndCount)
m_GrassModelsArray.Add(triData);
else
{
delete triData;
break;
}
m_arrlstSurfaceObjects[nId].Add(triData);
}
else
{ // use already loaded
m_arrlstSurfaceObjects[nId].Add(m_GrassModelsArray[l]);
}
}
}
}
nId++;
}
}
}
UpdateLoadingScreen(" %d detail objects loaded", m_GrassModelsArray.Count());
m_GrassTID = 4096;
for(int t=0; t<m_GrassModelsArray.Count(); t++)
{
if(m_GrassModelsArray[t]->nTexID && m_GrassModelsArray[t]->nTexID != 4096)
{ // if some valid texture found - ise it for all objects
m_GrassTID = m_GrassModelsArray[t]->nTexID;
break;
}
}
if(!m_GrassTID && m_GrassModelsArray.Count())
{
#if !defined(LINUX)
Warning( 0,0,"Texture for detail objects was not loaded");
#endif
m_GrassTID = 0x1000;
}
if(!m_GrassModelsArray.Count())
return;
m_pShader = GetRenderer()->EF_LoadShader("TerrainDetailObjects", eSH_World, 0);
// make leaf buffer
// m_pGrassVertices = new struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F[DETAIL_GRASS_PIP_BUFFER_SIZE];
m_GrassIndices.PreAllocate(DETAIL_GRASS_PIP_BUFFER_SIZE*3,DETAIL_GRASS_PIP_BUFFER_SIZE*3);
m_pLeafBuffer = GetRenderer()->CreateLeafBufferInitialized(
0/*m_pGrassVertices*/, DETAIL_GRASS_PIP_BUFFER_SIZE, VERTEX_FORMAT_P3F_COL4UB_TEX2F,
m_GrassIndices.GetElements(), m_GrassIndices.Count(), R_PRIMV_TRIANGLES, "Grass", eBT_Dynamic, 1 , 0, PrepareBufferCallback, this);
m_pLeafBuffer->SetRECustomData(m_arrfShaderInfo);
assert(m_pLeafBuffer);
m_pLeafBuffer->SetChunk(m_pShader,0,DETAIL_GRASS_PIP_BUFFER_SIZE,0,m_GrassIndices.Count(),0);
}
bool CDetailGrass::PrepareBufferCallback(CLeafBuffer * pLeafBuffer, bool bNeedTangents)
{
CDetailGrass * pThis = (CDetailGrass *)pLeafBuffer->m_pCustomData;
// if(pTerrain->m_nRenderStackLevel==0)
{
// Matrix44 mat;
// pThis->GetRenderer()->GetModelViewMatrix(mat.GetData());
Vec3d forward = -pThis->GetViewCamera().GetVCMatrixD3D9().GetColumn(2);
//CELL_CHANGED_BY_IVO
//forward(-mat.cell(2), -mat.cell(6), -mat.cell(10));
forward.Normalize();
if(!forward.x && !forward.y)
return false;
Vec3d vCamPos = pThis->GetViewCamera().GetPos();
int c_X = int(vCamPos.x + forward.x*CAMERA_GRASS_SHIFT);
int c_Y = int(vCamPos.y + forward.y*CAMERA_GRASS_SHIFT);
// GetRenderer()->DrawBall(c_X,c_Y,m_pTerrain->GetZApr(c_X,c_Y),1);
// check focus
float dx = float(c_X-pThis->m_GrassFocusX);
float dy = float(c_Y-pThis->m_GrassFocusY);
float d2 = (dx*dx+dy*dy);
if(d2>16 && pThis->m_pTerrain)
{
pThis->m_GrassFocusX = c_X;
pThis->m_GrassFocusY = c_Y;
if(pLeafBuffer->m_pVertexBuffer && pLeafBuffer->m_pVertexBuffer->m_vertexformat == VERTEX_FORMAT_P3F_COL4UB_TEX2F)
{
pThis->GetRenderer()->UpdateBuffer(pLeafBuffer->m_pVertexBuffer,0,0,0);
pThis->CreateSectorGrass(int(CAMERA_GRASS_SHIFT+2),int(1),
(struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F*)pLeafBuffer->m_pVertexBuffer->m_VS[VSF_GENERAL].m_VData);
// unlock
pThis->GetRenderer()->UpdateBuffer(pLeafBuffer->m_pVertexBuffer, NULL, 0, true, 0, 1);
//pLeafBuffer->UpdateSysIndices(pThis->m_GrassIndices.GetElements(), pThis->m_GrassIndices.Count());
pLeafBuffer->UpdateVidIndices(pThis->m_GrassIndices.GetElements(), pThis->m_GrassIndices.Count());
if(pThis->m_GrassIndices.Count()==0)
pLeafBuffer->SetChunk(pThis->m_pShader,0,-1,0,-1,0);
else
pLeafBuffer->SetChunk(pThis->m_pShader,0,pThis->m_GrassVerticesCount,0,pThis->m_GrassIndices.Count(),0);
pLeafBuffer->SetShader(pThis->m_pShader,pThis->m_GrassTID);
}
else
{
assert(0);
}
}
// set alpha glow texgen params
const float fDistFadeK = 1.f/(CAMERA_GRASS_SHIFT*4.f);
pThis->m_arrfShaderInfo[2] = fDistFadeK;
pThis->m_arrfShaderInfo[3] = 0.5f-vCamPos.y*fDistFadeK;
pThis->m_arrfShaderInfo[4] = 0.5f-vCamPos.x*fDistFadeK;
// assert(pThis->m_pLeafBuffer && pThis->m_pLeafBuffer == pLeafBuffer);
if(pThis->m_pLeafBuffer) // lb may be not created yet, this call can come from CreateLeafBufferInitialized()
pThis->m_pLeafBuffer->SetRECustomData(pThis->m_arrfShaderInfo);
}
return true;
}
CDetailGrass::~CDetailGrass()
{
for(int i=0; i<m_GrassModelsArray.Count(); i++)
delete m_GrassModelsArray[i];
m_GrassModelsArray.Reset();
if(m_pLeafBuffer)
GetRenderer()->DeleteLeafBuffer(m_pLeafBuffer);
m_pLeafBuffer=0;
// delete [] m_pGrassVertices; m_pGrassVertices=0;
/// GetRenderer()->RemoveTexture(m_GrassTID);
}
// copy object into buffer
void CDetailGrass::AddIndexedArray(GrassType * o, float X, float Y, float Z, float fObjBr,
float fSizeRatio, float fXSign, float fYSign, int nSwapXY,
struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * pGrassVertices)
{
if(fObjBr > 1.f)
fObjBr = 1.f;
fObjBr *= 255.f;
assert(o->nIndCount%3 == 0);
for( uint i=0; i<o->nIndCount; i+=3 )
{
assert(o->uipIndices[i]<o->nVertCount);
m_GrassIndices.Add(o->uipIndices[i+0] + m_GrassVerticesCount);
assert(o->uipIndices[i+1]<o->nVertCount);
m_GrassIndices.Add(o->uipIndices[i+1] + m_GrassVerticesCount);
assert(o->uipIndices[i+2]<o->nVertCount);
m_GrassIndices.Add(o->uipIndices[i+2] + m_GrassVerticesCount);
}
struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * pVert = &pGrassVertices[m_GrassVerticesCount];
struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * pSourceVert = &o->pVertices[0];
unsigned char grass_r = (unsigned char)fObjBr;
unsigned char grass_g = (unsigned char)fObjBr;
unsigned char grass_b = (unsigned char)fObjBr;
for(uint v=0; v<o->nVertCount; v++)
{
switch(nSwapXY)
{
case 0:
pVert->xyz.x = (pSourceVert->xyz.x*fSizeRatio)*fXSign + X;
pVert->xyz.y = (pSourceVert->xyz.y*fSizeRatio)*fYSign + Y;
pVert->xyz.z = (pSourceVert->xyz.z/fSizeRatio) + Z;
break;
case 1: // swap
pVert->xyz.x = (pSourceVert->xyz.y*fSizeRatio)*fXSign + X;
pVert->xyz.y = (pSourceVert->xyz.x*fSizeRatio)*fYSign + Y;
pVert->xyz.z = (pSourceVert->xyz.z/fSizeRatio) + Z;
break;
}
pVert->st[0] = pSourceVert->st[0];
pVert->st[1] = pSourceVert->st[1];
pVert->color.bcolor[0] = grass_r;
pVert->color.bcolor[1] = grass_g;
pVert->color.bcolor[2] = grass_b;
pVert->color.bcolor[3] = 255;
pVert++;
pSourceVert++;
}
m_GrassVerticesCount += o->nVertCount;
}
void CDetailGrass::CreateSectorGrassInUnit(const int x, const int y, const int nStep,
struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * pGrassVertices)
{
const float grass_level_min = m_pTerrain->GetWaterLevel() + 0.25f;
if(m_pTerrain->GetZSafe(m_GrassFocusX+x,m_GrassFocusY+y)<grass_level_min)
return;
if(m_GrassVerticesCount+4096 > DETAIL_GRASS_PIP_BUFFER_SIZE)
{
GetLog()->Log("CreateSectorGrass: grass buffer overflow");
GetLog()->Log("grass_verts = %d/%d", m_GrassVerticesCount, int(DETAIL_GRASS_PIP_BUFFER_SIZE));
return;
}
srand(((m_GrassFocusX+x)*(m_GrassFocusY+y)));
srand(rand());
srand(rand());
int nSurfaceID = 0;
int nUnitSize = CTerrain::GetHeightMapUnitSize();
// todo skip this if there is has_holes flag not set in sector
for(int _x = m_GrassFocusX+x-nUnitSize; _x <= m_GrassFocusX+x+nUnitSize; _x += nUnitSize)
for(int _y = m_GrassFocusY+y-nUnitSize; _y <= m_GrassFocusY+y+nUnitSize; _y += nUnitSize)
{
if(m_pTerrain->IsBurnedOut(_x-1,_y-1))
return;
nSurfaceID = m_pTerrain->GetSurfaceTypeID(_x-1,_y-1);
if(nSurfaceID == STYPE_HOLE)
return;
}
nSurfaceID = m_pTerrain->GetSurfaceTypeID(m_GrassFocusX+x,m_GrassFocusY+y);
if(nSurfaceID == STYPE_HOLE) return;
assert(nSurfaceID<MAX_SURFACE_TYPES_COUNT);
if(!m_arrlstSurfaceObjects[nSurfaceID].Count())
return;
assert(nStep == 1);
CVars * pCVars = GetCVars();
for(int i=0; i<m_nGrassDensity; i++)
{
float objX = (float)rnd() - 0.5f+(m_GrassFocusX+x);
float objY = (float)rnd() - 0.5f+(m_GrassFocusY+y);
/// if(m_pTerrain->IsBurnedOut((int)objX,(int)objY))
// continue;
int nObjIdId = rand() % m_arrlstSurfaceObjects[nSurfaceID].Count();
GrassType * o = m_arrlstSurfaceObjects[nSurfaceID][nObjIdId];
if(!o->nIndCount)
continue;
float objZ = m_pTerrain->GetZApr(objX,objY);
float fBr =
//pCVars->e_lighting_bit_test ?
//m_pTerrain->IsOnTheLight((int)objX,(int)objY) :
0.6f+0.4f*(float)m_pTerrain->IsOnTheLight((int)objX,(int)objY);
AddIndexedArray(o, objX,objY,objZ, fBr,
0.75f+rnd()*0.5f, // size, proportions
(rand() > RAND_MAX/2) ? 1.f : -1.f, // x sign
(rand() > RAND_MAX/2) ? 1.f : -1.f, // y sign
(rand() > RAND_MAX/2), // xy swap
pGrassVertices);
}
}
// generating sector grass mesh
void CDetailGrass::CreateSectorGrass(const int nRange, const int nStep, struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * pGrassVertices)
{
m_GrassVerticesCount = 0;
m_GrassIndices.Clear();
if(!m_GrassModelsArray.Count())
return;
m_GrassFocusX = m_GrassFocusX/nStep*nStep;
m_GrassFocusY = m_GrassFocusY/nStep*nStep;
if(m_GrassFocusX-nRange<0 || m_GrassFocusY-nRange<0)
return;
if(m_GrassFocusX+nRange>=CTerrain::GetTerrainSize() || m_GrassFocusY+nRange>=CTerrain::GetTerrainSize())
return;
int nRangeX = nRange;
int nRangeY = nRange;
int nStepX = nStep;
int nStepY = nStep;
Vec3d vCamPos = GetViewCamera().GetPos();
if(vCamPos.x > m_GrassFocusX)
{
if(vCamPos.y > m_GrassFocusY)
{
for(int x=-nRangeX; x<= nRangeX; x+=nStepX)
for(int y=-nRangeY; y<= nRangeY; y+=nStepY)
CreateSectorGrassInUnit(x, y , nStep, pGrassVertices);
}
else
{
for(int x=-nRangeX; x<= nRangeX; x+=nStepX)
for(int y= nRangeY; y>=-nRangeY; y-=nStepY)
CreateSectorGrassInUnit(x, y , nStep, pGrassVertices);
}
}
else
{
if(vCamPos.y > m_GrassFocusY)
{
for(int x= nRangeX; x>=-nRangeX; x-=nStepX)
for(int y=-nRangeY; y<= nRangeY; y+=nStepY)
CreateSectorGrassInUnit(x, y , nStep, pGrassVertices);
}
else
{
for(int x= nRangeX; x>=-nRangeX; x-=nStepX)
for(int y= nRangeY; y>=-nRangeY; y-=nStepY)
CreateSectorGrassInUnit(x, y , nStep, pGrassVertices);
}
}
// if(m_GrassVerticesCount>12000)
/* {
GetLog()->Log("grass_verts = %d/%d", m_GrassVerticesCount, int(DETAIL_GRASS_PIP_BUFFER_SIZE));
GetLog()->Log("grass_indic = %d", m_GrassIndices.Count());
}*/
}
void CDetailGrass::PreloadResources()
{
FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE );
ITexPic * pTexPic = GetRenderer()->EF_GetTextureByID(m_GrassTID);
if(pTexPic)
GetRenderer()->EF_PrecacheResource(pTexPic, 0, 1.f, 0);
}
// check focus and render
void CDetailGrass::RenderDetailGrass(CTerrain * pTerrain)
{
if( !GetCVars()->e_detail_objects || !m_nGrassDensity || !pTerrain || !m_pLeafBuffer )
return;
m_pTerrain = pTerrain;
if(!m_GrassTID)
return;
if(!(GetRenderer()->GetFeatures()&RFT_DIRECTACCESSTOVIDEOMEMORY))
return;
Vec3d vCamPos = GetViewCamera().GetPos();
const int map_border = 12;
if(vCamPos.x < map_border || vCamPos.x > CTerrain::GetTerrainSize()-map_border)
return;
if(vCamPos.y < map_border || vCamPos.y > CTerrain::GetTerrainSize()-map_border)
return;
// if(!m_pGrassVertices)
// return;
float camera_h = vCamPos.z - m_pTerrain->GetZSafe(vCamPos.x,vCamPos.y);
if(camera_h > 64 || camera_h < -8)
return;
/*
if(pTerrain->m_nRenderStackLevel==0)
{
Matrix44 mat;
GetRenderer()->GetModelViewMatrix(mat.GetData());
Vec3d forward = -mat.GetColumn(2);
//CELL_CHANGED_BY_IVO
//forward(-mat.cell(2), -mat.cell(6), -mat.cell(10));
forward.Normalize();
if(!forward.x && !forward.y)
return;
int c_X = int(vCamPos.x + forward.x*CAMERA_GRASS_SHIFT);
int c_Y = int(vCamPos.y + forward.y*CAMERA_GRASS_SHIFT);
// GetRenderer()->DrawBall(c_X,c_Y,m_pTerrain->GetZApr(c_X,c_Y),1);
// check focus
float dx = float(c_X-m_GrassFocusX);
float dy = float(c_Y-m_GrassFocusY);
float d2 = (dx*dx+dy*dy);
if(d2>16)
{
m_GrassFocusX = c_X;
m_GrassFocusY = c_Y;
PrepareBufferCallback(m_pLeafBuffer, 0, 0);
}
// set alpha glow texgen params
const float fDistFadeK = 1.f/(CAMERA_GRASS_SHIFT*4.f);
m_arrfShaderInfo[2] = fDistFadeK;
m_arrfShaderInfo[3] = 0.5f-vCamPos.y*fDistFadeK;
m_arrfShaderInfo[4] = 0.5f-vCamPos.x*fDistFadeK;
m_pLeafBuffer->SetRECustomData(m_arrfShaderInfo);
}
*/
// if(!m_GrassVerticesCount)
// return;
// find fog volume
Vec3d vPlus(30,30,30);
int nFogId;
for(nFogId = 0; nFogId<pTerrain->m_lstFogVolumes.Count(); nFogId++)
{
if(vCamPos.x > (pTerrain->m_lstFogVolumes[nFogId].vBoxMin-vPlus).x)
if(vCamPos.y > (pTerrain->m_lstFogVolumes[nFogId].vBoxMin-vPlus).y)
if(vCamPos.z > (pTerrain->m_lstFogVolumes[nFogId].vBoxMin-vPlus).z)
if(vCamPos.x < (pTerrain->m_lstFogVolumes[nFogId].vBoxMax+vPlus).x)
if(vCamPos.y < (pTerrain->m_lstFogVolumes[nFogId].vBoxMax+vPlus).y)
if(vCamPos.z < (pTerrain->m_lstFogVolumes[nFogId].vBoxMax+vPlus).z)
break;
}
int nDLMask = Get3DEngine()->GetLightMaskFromPosition(vCamPos, CAMERA_GRASS_SHIFT);
// render
CCObject * pObj = GetRenderer()->EF_GetObject(true);
if(GetRenderer()->EF_GetHeatVision())
pObj->m_ObjFlags |= FOB_HEATVISION;
pObj->m_Matrix.SetIdentity();
pObj->m_Color.a = 0.99f;
m_pLeafBuffer->m_vBoxMin = vCamPos;
m_pLeafBuffer->m_vBoxMax = vCamPos;
pObj->m_SortId = -1;
if(pTerrain->m_nRenderStackLevel==0)
m_pLeafBuffer->InvalidateVideoBuffer();
if(m_pLeafBuffer->m_Indices.m_nItems)
m_pLeafBuffer->AddRenderElements( pObj, nDLMask,-1, (nFogId<pTerrain->m_lstFogVolumes.Count()) ? pTerrain->m_lstFogVolumes[nFogId].nRendererVolumeID : 0, eS_TerrainDetailObjects );
else
{ // nothing to draw now but we must to add render element to be able to generate mesh right before rendering
m_pLeafBuffer->AddRenderElements( pObj, nDLMask,-1,
(nFogId<pTerrain->m_lstFogVolumes.Count()) ? pTerrain->m_lstFogVolumes[nFogId].nRendererVolumeID : 0 );
}
}
int CDetailGrass::GetMemoryUsage()
{
int nSize=0;
nSize += m_GrassIndices.GetMemoryUsage();
nSize += m_GrassModelsArray.GetMemoryUsage();
for(int i=0; i<m_GrassModelsArray.Count(); i++)
nSize += sizeof(*m_GrassModelsArray[i]) + m_GrassModelsArray[i]->GetMemoryUsage();
return nSize;
}

View File

@@ -0,0 +1,62 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: detail_grass.h
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#ifndef _DETAILGRASS_H_
#define _DETAILGRASS_H_
class CVertexBuffer;
struct GrassType;
class CTerrain;
struct CLeafBuffer;
const int DETAIL_GRASS_PIP_BUFFER_SIZE = 50000;
const float CAMERA_GRASS_SHIFT = 9;
class CDetailGrass : public Cry3DEngineBase
{
void CreateSectorGrass(const int range, const int step, struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * pGrassVertices);
void CreateSectorGrassInUnit(const int x, const int y, const int nStep,
struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * pGrassVertices);
void AddIndexedArray(GrassType * o, float X, float Y, float Z, float fbr, float fSizeRatio,
float fXSign, float fYSign, int nSwapXY, struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * pGrassVertices);
list2<unsigned short> m_GrassIndices;
// struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * m_pGrassVertices;
int m_GrassVerticesCount;
int m_GrassFocusX, m_GrassFocusY; // grass focus
int m_GrassTID;
list2<GrassType*> m_GrassModelsArray;
int m_nGrassDensity;
CTerrain * m_pTerrain;
list2<GrassType*> m_arrlstSurfaceObjects[MAX_SURFACE_TYPES_COUNT];
CLeafBuffer * m_pLeafBuffer;
IShader * m_pShader;
float m_arrfShaderInfo[16];
public:
CDetailGrass(XDOM::IXMLDOMNodeListPtr pDetTexTagList);
~CDetailGrass();
void RenderDetailGrass(CTerrain * pTerrain);
void UpdateGrass() { m_GrassFocusX=m_GrassFocusY=-CTerrain::GetTerrainSize(); }
void PreloadResources();
static bool PrepareBufferCallback(CLeafBuffer * pLeafBuffer, bool bNeedTangents);
// todo: update
//void GetMemoryUsage(ICrySizer*pSizer);
int GetMemoryUsage();
};
#endif // _DETAILGRASS_H_

614
Cry3DEngine/particle.cpp Normal file
View File

@@ -0,0 +1,614 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: particle.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: move, fill vertex buffer
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "partman.h"
#include "objman.h"
#include "3dengine.h"
#define OT_RIGID_PARTICLE 10
void CParticle::FillBuffer(const PartProcessParams & PPP)
{
float t = (PPP.fCurTime-m_fSpawnTime)/m_fLifeTime;
float alpha = (1.f - t);//*2;
if(alpha<0)
alpha=0;
Vec3d vColor = m_pParams->vColorStart*(1.f-t) + m_pParams->vColorEnd*t;
if (m_pParams->eBlendType != ParticleBlendType_AlphaBased)
{
vColor.x*=alpha;
vColor.y*=alpha;
vColor.z*=alpha;
}
Vec3d v1 = m_vPos + PPP.vUp *m_fSize;
Vec3d v2 = m_vPos + PPP.vRight *m_fSize;
Vec3d v3 = m_vPos - PPP.vRight *m_fSize;
Vec3d v4 = m_vPos - PPP.vUp *m_fSize;
UCol col;
col.bcolor[0] = FtoI(vColor.x*255.f);
col.bcolor[1] = FtoI(vColor.y*255.f);
col.bcolor[2] = FtoI(vColor.z*255.f);
col.bcolor[3] = FtoI(alpha*255.f);
PPP.pVertBufChunk[0].xyz = v1;
PPP.pVertBufChunk[0].color = col;
PPP.pVertBufChunk[0].st[0] = 0; PPP.pVertBufChunk[0].st[1] = 1;
PPP.pVertBufChunk[1].xyz = v2;
PPP.pVertBufChunk[1].color = col;
PPP.pVertBufChunk[1].st[0] = 0; PPP.pVertBufChunk[0].st[1] = 0;
PPP.pVertBufChunk[2].xyz = v3;
PPP.pVertBufChunk[2].color = col;
PPP.pVertBufChunk[2].st[0] = 1; PPP.pVertBufChunk[0].st[1] = 1;
PPP.pVertBufChunk[3].xyz = v4;
PPP.pVertBufChunk[3].color = col;
PPP.pVertBufChunk[3].st[0] = 1; PPP.pVertBufChunk[0].st[1] = 0;
}
bool CParticle::Update(const PartProcessParams & PPP)
{
////////////////////////////////////////////////////////////////////////////////////////////////
// Move
////////////////////////////////////////////////////////////////////////////////////////////////
Vec3 prevPos = m_vPos;
float fAge = PPP.fCurTime - m_fSpawnTime;
if(m_pParams->nParticleFlags & PART_FLAG_BIND_EMITTER_TO_CAMERA && m_pEmitter)
{
float fLen = m_pEmitter->GetParams().vSpaceLoopBoxSize.GetLength();
Vec3d vDir = PPP.pCamera->GetVCMatrixD3D9().GetOrtZ();
m_pEmitter->m_pos = PPP.pCamera->GetPos()-vDir*fLen*0.75;
}
if(m_pParams->nParticleFlags & PART_FLAG_SPACELOOP && m_pEmitter)
{ // process space loop
Vec3d vSpaceFocusPos = m_pEmitter->m_pos;
float fMaxX = m_pEmitter->GetParams().vSpaceLoopBoxSize.x;
float fMaxY = m_pEmitter->GetParams().vSpaceLoopBoxSize.y;
float fMaxZ = m_pEmitter->GetParams().vSpaceLoopBoxSize.z;
// X
while((m_vPos.x-vSpaceFocusPos.x)>fMaxX)
m_vPos.x-=fMaxX*2;
while((vSpaceFocusPos.x-m_vPos.x)>fMaxX)
m_vPos.x+=fMaxX*2;
// Y
while((m_vPos.y-vSpaceFocusPos.y)>fMaxY)
m_vPos.y-=fMaxY*2;
while((vSpaceFocusPos.y-m_vPos.y)>fMaxY)
m_vPos.y+=fMaxY*2;
// Z
while((m_vPos.z-vSpaceFocusPos.z)>fMaxZ)
m_vPos.z-=fMaxZ*2;
while((vSpaceFocusPos.z-m_vPos.z)>fMaxZ)
m_vPos.z+=(fMaxZ*2-rnd());
}
if(m_pParams->nParticleFlags & PART_FLAG_NO_INDOOR)
{
IVisArea * pArea = PPP.p3DEngine->GetVisAreaFromPos(m_vPos);
if(pArea)
return false;
}
if((m_pParams->nParticleFlags & PART_FLAG_SPACELIMIT) && m_pEmitter)
{
Vec3d vBoxMin = m_pEmitter->GetParams().vPosition - m_pEmitter->GetParams().vSpaceLoopBoxSize;
Vec3d vBoxMax = m_pEmitter->GetParams().vPosition + m_pEmitter->GetParams().vSpaceLoopBoxSize;
vBoxMin.CheckMin(m_pEmitter->GetParams().vPosition + m_pEmitter->GetParams().vSpaceLoopBoxSize);
vBoxMax.CheckMax(m_pEmitter->GetParams().vPosition - m_pEmitter->GetParams().vSpaceLoopBoxSize);
Vec3d vNextPos = m_vPos + m_vDelta * PPP.fFrameTime;
if( vNextPos.x < vBoxMin.x ||
vNextPos.y < vBoxMin.y ||
vNextPos.z < vBoxMin.z ||
vNextPos.x > vBoxMax.x ||
vNextPos.y > vBoxMax.y ||
vNextPos.z > vBoxMax.z )
return false;
}
if(m_pPhysEnt)
{ // use phys engine to control particle
pe_status_pos status_pos;
m_pPhysEnt->GetStatus(&status_pos);
m_vPos = status_pos.pos;
//CHANGED_BY_IVO (NOTE: order of angles is flipped!!!!)
//status_pos.q.get_Euler_angles_xyz(PPP.pPartSpray->m_vAngles.z,PPP.pPartSpray->m_vAngles.y,PPP.pPartSpray->m_vAngles.x);
//EULER_IVO
//Vec3 TempAng; PPP.pPartSpray->m_vAngles = status_pos.q.GetEulerAngles_XYZ(TempAng);
m_vAngles = Ang3::GetAnglesXYZ( matrix3x3f(status_pos.q) );
m_vAngles *= 180/gf_PI;
}
else
{ // process movement, size and rotation
if(!(m_pParams->nParticleFlags & PART_FLAG_LINEPARTICLE))
{
Vec3 vDelta = m_vDelta;
if (m_pParams->fSpeedFadeOut != 0)
{
// Fade out speed.
float t = m_fLifeTime - fAge;
if (t < m_pParams->fSpeedFadeOut)
{
float speedScale = (t/m_pParams->fSpeedFadeOut);
if (speedScale < 0) speedScale = 0;
if (speedScale > 1) speedScale = 1;
vDelta = vDelta*speedScale;
}
}
m_vPos += vDelta * PPP.fFrameTime;
if (m_pParams->fTurbulenceSize)
{
m_vPos += Vec3d( cry_cosf( fAge*m_pParams->fTurbulenceSpeed),
cry_sinf( fAge*m_pParams->fTurbulenceSpeed),
0)* PPP.fFrameTime * (max(1.f,fAge))*
m_pParams->fTurbulenceSize;
}
m_vDelta += m_pParams->vGravity*m_fScale * PPP.fFrameTime;
if (m_pParams->fSpeedAccel != 0)
{
if (!m_vDelta.IsZero())
{
Vec3 heading = GetNormalized(m_vDelta);
m_vDelta += heading*m_pParams->fSpeedAccel*m_fScale * PPP.fFrameTime;
}
}
if (m_pParams->fAirResistance != 0)
{
float fSpeed = GetLength(m_vDelta);
if (fSpeed != 0)
{
Vec3 heading = m_vDelta * (1.0f/fSpeed);
float fResistance = (fSpeed*fSpeed) * m_pParams->fAirResistance * PPP.fFrameTime; //D = Cd * A * .5 * r * V^2
if (fResistance > fSpeed)
fResistance = fSpeed;
m_vDelta -= heading*fResistance;
}
}
if(m_pParams->pStatObj)
m_vAngles += m_vRotation*PPP.fFrameTime*(180.0f/gf_PI);
else
m_vAngles.z += m_vRotation.z*PPP.fFrameTime*(180.0f/gf_PI);
}
if (m_pParams->fSizeSpeed != 0)
{
if(m_pParams->nParticleFlags & PART_FLAG_SIZE_LINEAR)
m_fSize += (m_pParams->fSizeSpeed*m_fScale) * PPP.fFrameTime;
else
{
float inc = (m_pParams->fSizeSpeed*m_fScale) * PPP.fFrameTime;;
if (m_fSize > 1)
inc = inc / m_fSize;
m_fSize += inc;
}
}
}
//////////////////////////////////////////////////////////////////////////
if (m_pParams->nParticleFlags & PART_FLAG_BIND_POSITION_TO_EMITTER)
{
m_vPos = m_pEmitter->m_pos;
}
//bool bScaleFadeInOut = false;
float scaleFade = 1.0f;
//////////////////////////////////////////////////////////////////////////
// Process Scale FadeIn/FadeOut of particle.
// Override m_fSize member.
//////////////////////////////////////////////////////////////////////////
if (m_pParams->fSizeFadeIn != 0)
{
// Fade in scale
float t = fAge;
if (t <= m_pParams->fSizeFadeIn)
{
scaleFade = (t/m_pParams->fSizeFadeIn);
if (scaleFade < 0) scaleFade = 0;
if (scaleFade > 1) scaleFade = 1;
//bScaleFadeInOut = true;
m_fSize = m_fSizeOriginal * scaleFade;
}
}
if (m_pParams->fSizeFadeOut != 0)
{
// Fade out scale.
float t = m_fLifeTime - fAge;
if (t < m_pParams->fSizeFadeOut)
{
if (t < 0) t = 0;
scaleFade *= (t/m_pParams->fSizeFadeOut);
if (scaleFade < 0) scaleFade = 0;
if (scaleFade > 1) scaleFade = 1;
//m_fSize = m_fSizeOriginal * scaleOut;
//bScaleFadeInOut = true;
m_fSize = m_fSizeOriginal * scaleFade;
}
}
// Restrict to minimal size.
if (m_fSize < 0.001f)
m_fSize = 0.0001f;
////////////////////////////////////////////////////////////////////////////////////////////////
// Simple collision with terrain simulation
////////////////////////////////////////////////////////////////////////////////////////////////
bool bContact = false;
if(m_pPhysEnt)
{ // use real physics
pe_status_collisions status;
coll_history_item item;
status.pHistory = &item;
status.age=1.f;
status.bClearHistory=1;
bContact = m_pPhysEnt->GetStatus(&status)!=0;
}
else if(m_vDelta.z<0)
{
const float fFriction = 0.15f;
/*
if (m_pVisArea)
{ // if inside the building
if(pCVars->e_particles_indoor_collisions)
{
IndoorRayIntInfo tRayInfo;
bool bRes = pObjManager->m_pBuildingManager->RayIntersection(m_vPos-(m_vDelta*fFrameTime), m_vPos, tRayInfo, nBuildingID);
if(bRes && m_vDelta.Dot(tRayInfo.vNormal)<0)
{ // if collides
float fLen = m_vDelta.Length()-fFriction;
if(fLen>fFriction)
{
m_vDelta = m_vDelta.Reflect(tRayInfo.vNormal);
m_vDelta.SetLen(fLen*PPP.pPartSpray->m_fBouncenes);
}
else
m_vDelta.Clear();
bContact = true;
}
}
}
else*/
if( PPP.pTerrain && _finite(m_vPos.x) && _finite(m_vPos.y)
&& m_vPos.z < PPP.pTerrain->GetZApr(m_vPos.x,m_vPos.y)
&& m_vPos.z > PPP.pTerrain->GetZApr(m_vPos.x,m_vPos.y)-0.1f
&& !(m_pParams->nParticleFlags & PART_FLAG_SPACELOOP))
{ // collide with terrain
int x = (int)m_vPos.x;
int y = (int)m_vPos.y;
if(!PPP.pTerrain->GetHoleSafe(x,y))
if(!PPP.pTerrain->GetHoleSafe(x+CTerrain::GetHeightMapUnitSize(),y+CTerrain::GetHeightMapUnitSize()))
if(!PPP.pTerrain->GetHoleSafe(x-CTerrain::GetHeightMapUnitSize(),y+CTerrain::GetHeightMapUnitSize()))
if(!PPP.pTerrain->GetHoleSafe(x+CTerrain::GetHeightMapUnitSize(),y-CTerrain::GetHeightMapUnitSize()))
if(!PPP.pTerrain->GetHoleSafe(x-CTerrain::GetHeightMapUnitSize(),y-CTerrain::GetHeightMapUnitSize()))
{
float fLen = (m_vDelta - m_pParams->vGravity*m_fScale*PPP.fFrameTime).Length()-fFriction;
if(fLen>fFriction)
{
m_vDelta.z = -m_vDelta.z;
m_vDelta.SetLen( fLen*m_pParams->fBouncenes);
}
else
{
m_vDelta(0,0,0);
m_vRotation(0,0,0);
}
bContact = true;
}
}
if(bContact && !IsEquivalent(m_vDelta,Vec3(0,0,0), 0.001f) )
{
Vec3d vVec(m_vDelta.x,m_vDelta.y,0);
if(vVec.Normalize())
{
vVec = vVec.Cross(Vec3d(0,0,1));
quaternionf q;
q=quaternionf(0, vVec.x,vVec.y,vVec.z );
//CHANGED_BY_IVO (NOTE: order of angles is flipped!!!!)
//q.get_Euler_angles_xyz( PPP.pPartSpray->m_vRotation.z,PPP.pPartSpray->m_vRotation.y,PPP.pPartSpray->m_vRotation.x );
//EULER_IVO
//Vec3 TempAng; PPP.pPartSpray->m_vRotation = q.GetEulerAngles_XYZ( TempAng );
m_vRotation = Ang3::GetAnglesXYZ( matrix3x3f(q) );
m_vRotation *= m_pParams->fBouncenes*2;
}
}
}
if(bContact)
{ // Run child process on collision
if (m_pParams->pChild && m_pParams->pChild->nCount > 0 && m_pParams->fChildSpawnPeriod < 0)
{
m_pParams->pChild->vPosition = m_vPos;
//m_pParams->pChild->pStatObj = 0;
m_pParams->pChild->vDirection = Vec3(0,0,1); // Up direction.
PPP.pPartManager->Spawn( m_pEmitter,true );
return false;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
// Run child process every X sec
////////////////////////////////////////////////////////////////////////////////////////////////
if (m_pParams->pChild && m_pParams->pChild->nCount > 0 &&
m_pParams->fChildSpawnPeriod >= 0 &&
PPP.fCurTime > m_fChildSpawnLastTime + m_pParams->fChildSpawnPeriod)
{
if (m_pParams->fChildSpawnTime <= 0 || fAge < m_pParams->fChildSpawnTime)
{
// Calc current movement direction.
if (m_vPos != prevPos)
m_pParams->pChild->vDirection = GetNormalized(m_vPos - prevPos);
m_pParams->pChild->vPosition = m_vPos;
//PPP.pPartSpray->m_ChildParams.pChild=0;
//PPP.pPartSpray->m_ChildParams.pStatObj=0;
// PPP.pPartSpray->m_pChildPartEmitter->Spawn( m_vPos );
PPP.pPartManager->Spawn( m_pEmitter,true );
m_fChildSpawnLastTime = PPP.fCurTime;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
// Remember prev positions for trail
////////////////////////////////////////////////////////////////////////////////////////////////
if (m_pArrvPosHistory)
{
//float fTailLength = (m_pParams->fTailLenght/m_nTailSteps) / m_fScale; // Here we must divide by scale because speed is scaled.
//m_fTrailCurPos += min(1.f, PPP.fFrameTime/fTailLength);
//m_pArrvPosHistory[ ((unsigned int)FtoI(m_fTrailCurPos))%m_nTailSteps ] = m_vPos;
/*
float t = PPP.fCurTime-m_fLastTailPosTime;
float dt = 0.3f;
float fTailLength = (m_pParams->fTailLenght/PART_HISTORY_ELEMENTS)*m_fScale;
if (t > dt)
{
//m_fTrailCurPos += min(1.f, PPP.fFrameTime/fTailLength);
//m_pArrvPosHistory[int(m_fTrailCurPos) & PART_HISTORY_ID_MASK] = m_vPos;
for (int i = 0; i < PART_HISTORY_ELEMENTS-1; i++)
{
m_pArrvPosHistory[i] = m_pArrvPosHistory[i+1];
}
m_pArrvPosHistory[PART_HISTORY_ELEMENTS-1] = m_vPos;
m_fLastTailPosTime = PPP.fCurTime;
}
else
{
float a = t / dt; // from 0-1.
a *= 0.05f;
// Smooth last to prev.
for (int i = 0; i < PART_HISTORY_ELEMENTS-1; i++)
{
Vec3 &last = m_pArrvPosHistory[i];
Vec3 &prev = m_pArrvPosHistory[i+1];
// //last = last*(1.0f-a) + (prev+Vec3(0,0,0))*a;
}
}
*/
}
////////////////////////////////////////////////////////////////////////////////////////////////
// Deactivate if too far or too int
////////////////////////////////////////////////////////////////////////////////////////////////
if( (PPP.fCurTime/*+PPP.fFrameTime*/) >= (m_fSpawnTime + m_fLifeTime) )
return false;
else
{
if(m_pParams->nParticleFlags & PART_FLAG_UNDERWATER && m_pEmitter->m_fWaterLevel>WATER_LEVEL_UNKNOWN)
if(m_vPos.z > m_pEmitter->m_fWaterLevel-m_fSize*0.5)
return false;
}
if((m_pParams->nParticleFlags & PART_FLAG_SPACELIMIT) && m_pEmitter)
{
Vec3d vBoxMin = m_pEmitter->GetParams().vPosition - m_pEmitter->GetParams().vSpaceLoopBoxSize;
Vec3d vBoxMax = m_pEmitter->GetParams().vPosition + m_pEmitter->GetParams().vSpaceLoopBoxSize;
vBoxMin.CheckMin(m_pEmitter->GetParams().vPosition + m_pEmitter->GetParams().vSpaceLoopBoxSize);
vBoxMax.CheckMax(m_pEmitter->GetParams().vPosition - m_pEmitter->GetParams().vSpaceLoopBoxSize);
float fRadius = m_fSize;
if(m_pParams->pStatObj)
{ // get world space radius of the object
float fObjScale = m_fSize;
if (m_pParams->fObjectScale)
fObjScale *= m_pParams->fObjectScale;
fRadius = m_pParams->pStatObj->GetRadius()*fObjScale;
}
Vec3d vHitPos = m_vPos + m_vDelta.GetNormalized()*fRadius;
// kill particle if position is out of bounds
if( vHitPos.x < vBoxMin.x ||
vHitPos.y < vBoxMin.y ||
vHitPos.z < vBoxMin.z ||
vHitPos.x > vBoxMax.x ||
vHitPos.y > vBoxMax.y ||
vHitPos.z > vBoxMax.z )
return false;
}
return true;
}
void CParticle::DeActivateParticle(IPhysicalWorld * pPhysicalWorld)
{
if(m_pPhysEnt)
{
pPhysicalWorld->DestroyPhysicalEntity(m_pPhysEnt);
m_pPhysEnt=0;
}
if (m_pEmitter)
{
m_pEmitter->Release();
m_pEmitter = 0;
}
if (m_pArrvPosHistory)
{
delete []m_pArrvPosHistory;
m_pArrvPosHistory = 0;
}
m_pSpawnerEntity = 0;
}
char GetMinAxis(const Vec3d & vVec)
{
float x = fabs(vVec.x);
float y = fabs(vVec.y);
float z = fabs(vVec.z);
if(x<y && x<z)
return 'x';
if(y<x && y<z)
return 'y';
return 'z';
}
void CParticle::Physicalize( ParticleParams &Params,IPhysicalWorld * pPhysicalWorld)
{
if (Params.nParticleFlags & PART_FLAG_RIGIDBODY)
{
if (!Params.pStatObj)
return;
float fObjScale = m_fSize;
if (m_pParams->fObjectScale)
fObjScale *= m_pParams->fObjectScale;
// Make Physical Rigid Body.
pe_params_pos par_pos;
par_pos.pos = m_vPos;
par_pos.q.SetRotationXYZ( m_vAngles*(gf_PI/180.0f) );
m_pPhysEnt = pPhysicalWorld->CreatePhysicalEntity(PE_RIGID,&par_pos,0,OT_RIGID_PARTICLE );
pe_params_flags pf;
pf.flagsOR = pef_never_affect_triggers;
m_pPhysEnt->SetParams(&pf);
pe_geomparams partpos;
//partpos.pos.Set(0,0,0);
partpos.density = Params.fThickness;
partpos.scale = fObjScale;
partpos.flags &= ~geom_colltype3; // don't collide with vehicles
partpos.flagsCollider = geom_colltype4;
m_pPhysEnt->AddGeometry( Params.pStatObj->GetPhysGeom(),&partpos,0 );
pe_simulation_params symparams;
//symparams.damping = 0.3f;
//symparams.dampingFreefall = 0.3f;
//symparams.gravity = Params.vGravity*m_fScale;
symparams.minEnergy = (0.2f)*(0.2f);
//symparams.softness = symparams.softnessGroup = 0.003f;
//symparams.softnessAngular = symparams.softnessAngularGroup = 0.01f;
//symparams.maxTimeStep = 0.05f;
m_pPhysEnt->SetParams(&symparams);
pe_action_set_velocity velparam;
velparam.v = m_vDelta;
velparam.w = m_vRotation;
m_pPhysEnt->Action(&velparam);
}
else
{
// Make Physical Particle.
pe_params_pos par_pos;
par_pos.pos = m_vPos;
m_pPhysEnt = pPhysicalWorld->CreatePhysicalEntity(PE_PARTICLE,&par_pos);
pe_params_particle params;
// Take particles size from bounding box of piece.
float fPartSize = 1.0f;
if (Params.pStatObj)
{
Vec3 vSize = Params.pStatObj->GetBoxMax() - Params.pStatObj->GetBoxMin();
fPartSize = max(max(vSize.x,vSize.y),vSize.z);
}
params.mass = 0.1f;
params.size = m_fSize*fPartSize;
if (Params.pStatObj)
{
params.size = Params.pStatObj->GetRadius()+0.05f;
if(m_pParams->fObjectScale)
params.size *= Params.fObjectScale;
}
params.thickness = Params.fThickness ? Params.fThickness : params.size*0.5f;
params.heading = GetNormalized(m_vDelta);
params.velocity = m_vDelta.Length();
params.wspin = m_vRotation*0.25f;
params.q0.SetRotationXYZ( m_vAngles*(gf_PI/180.0f) );
if(!Params.vNormal.IsZero())
params.normal = Params.vNormal;
else if(Params.pStatObj)
{
Vec3d vSize = Params.pStatObj->GetBoxMax() - Params.pStatObj->GetBoxMin();
char cMinAxis = GetMinAxis(vSize);
params.normal = Vec3d((cMinAxis=='x')?1.f:0,(cMinAxis=='y')?1.f:0,(cMinAxis=='z')?1.f:0);
}
params.surface_idx = Params.iPhysMat;
params.gravity = Params.vGravity*m_fScale;
params.flags = particle_no_roll|particle_no_path_alignment;
// params.acc_lift=0;
// params.k_air_resistance=0;
// params.acc_thrust=0;
// params.acc_lift=0;
// params.wspin = PPP.pPartSpray->m_vRotation;
// params.q0.set(0,0,0);
// params.collider_to_ignore=0;
m_pPhysEnt->SetParams(&params);
}
}

906
Cry3DEngine/partman.cpp Normal file
View File

@@ -0,0 +1,906 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: partman.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: manage particles and sprites
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "partman.h"
#include "objman.h"
#include "visareas.h"
#include "ParticleEffect.h"
#include "3dEngine.h"
#define PARTICLES_FILE_TYPE 2
#define PARTICLES_FILE_VERSION 4
#define PARTICLES_FILE_SIGNATURE "CRY"
#define ACTIVE_TIME 1
#define EFFECTS_FOLDER "CRY"
//////////////////////////////////////////////////////////////////////////
#pragma pack(push,1)
//////////////////////////////////////////////////////////////////////////
struct SExportedParticlesHeader
{
char signature[3]; // File signature.
int filetype; // File type.
int version; // File version.
};
struct SExportParticleSound
{
enum {
LOOP = 0x01,
EVERY_SPAWN = 0x02,
};
char soundfile[64];
float volume;
float minRadius;
float maxRadius;
char nSoundFlags;
};
enum EParticleExportFlags
{
PARTICLE_EFFECT_DISABLED = 0x01
};
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//! Particle system parameters
struct SExportParticleParams
{
Vec3 vPosition; // spawn position
Vec3 vDirection; // initial direction (normalization not important)
float fFocus; // if 0 - particles go in all directions, if more than 20 - particles go mostly in vDirection
Vec3 vColorStart; // initial color
Vec3 vColorEnd; // final color
FloatVariant fSpeed; // initial speed ( +- 25% random factor applyed, m/sec )
float fSpeedFadeOut; // Time in which before end of life time speed decreases from normal to 0.
float fSpeedAccel; // Constant speed acceleration along particle heading.
float fAirResistance; // Air resistance.
Vec3Variant vRotation; // rotation speed (degree/sec)
Vec3Variant vInitAngles; // initial rotation
int nCount; // number of particles to spawn
FloatVariant fSize; // initial size of particles
float fSizeSpeed; // particles will grow with this speed
float fSizeFadeIn; // Time in which at the begning of life time size goes from 0 to fSize.
float fSizeFadeOut; // Time in which at the end of life time size goes from fSize to 0.
float fThickness; // lying thickness - for physicalized particles only
FloatVariant fLifeTime; // time of life of particle
float fFadeInTime; // particle will fade in slowly during this time
int nTexAnimFramesCount; // number of frames in animated texture ( 0 if no animation )
ParticleBlendType eBlendType; // see ParticleBlendType
float fTailLenght; // delay of tail ( 0 - no tail, 1 meter if speed is 1 meter/sec )
float fStretch; // Stretch particles into moving direction.
int nParticleFlags; // see particle system flags
bool bRealPhysics; // use physics engine to control particles
float fChildSpawnPeriod; // if more than 0 - run child process every x seconds, if 0 - run it at collision
float fChildSpawnTime; // if more then 0, Spawn child process for max this ammount of time.
int nDrawLast; // add this element into second list and draw this list last
float fBouncenes; // if 0 - particle will not bounce from the ground, 0.5 is good in most cases
float fTurbulenceSize; // radius of turbulence
float fTurbulenceSpeed; // speed of rotation
float fDirVecScale; //the game need to store this(Alberto)
float fPosRandomOffset; // maximum distance of random offset from original position
//////////////////////////////////////////////////////////////////////////
// New parameters, used by Particle effects.
//////////////////////////////////////////////////////////////////////////
//! Spawn Position offset from effect spawn position.
Vec3 vPositionOffset;
//! Random offset of particle relative to spawn position.
Vec3 vRandomPositionOffset;
//! Delay actual spawn time by this ammount.
FloatVariant fSpawnDelay;
//! Life time of emitter.
FloatVariant fEmitterLifeTime;
//! When using emitter, spawn time between between 2 particle bursts.
float fSpawnPeriod;
//! Global effect scale. (0 ignored)
float fScale;
//! Object scale, multiplied with fSize to give scale adjustment between object and texture.
//! 0 not affect fSize.
float fObjectScale;
Vec3 vNormal; // lying normal - for physicalized particles only
int iPhysMat; // material for physicalized particles
Vec3 vGravity; // gravity(wind) vector
//////////////////////////////////////////////////////////////////////////
// Added.
//////////////////////////////////////////////////////////////////////////
unsigned short nTailSteps;
//////////////////////////////////////////////////////////////////////////
// Reserve space for new members.
//////////////////////////////////////////////////////////////////////////
char reserve[126];
};
struct SExportParticleEffect
{
char name[64];
char texture[2][64];
char geometry[2][64];
char material[2][64];
SExportParticleParams params[2]; // Primary and Child params.
SExportParticleSound sound;
int parent; // Index of parent particle.
int flags; // General flags.
};
#pragma pack(pop)
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
CPartManager::CPartManager( )
{
/*
// fill list of free particles
for(int i=0; i<MAX_PARTICLES_COUNT; i++)
{
m_arrParts[i].m_nId = i;
m_FreeParticles.Add(&m_arrParts[i]);
}
*/
m_currParticlesTime = 0;
m_currParticlesFrameTime = 0;
m_smoothTimeCount = 0;
memset(m_smoothTimes,0,sizeof(m_smoothTimes));
m_pSpriteMan = new CSpriteManager(this);
m_nGlowTexID = GetRenderer()->GenerateAlphaGlowTexture(1);
m_pPartLightShader = GetRenderer()->EF_LoadShader("ParticleLight", eSH_World, EF_SYSTEM);
// CPartSpray::InitVertBuffers(GetRenderer());
}
CPartManager::~CPartManager()
{
/* for(int i=0; i<m_lstpPartEmitters.Count(); i++)
{
m_lstpPartEmitters[i]->Shutdown();
delete m_lstpPartEmitters[i];
m_lstpPartEmitters.Delete(i);
i--;
}
*/
/*
while(m_FreeParticles.GetFirst())
m_FreeParticles.Remove(m_FreeParticles.GetFirst());
*/
Reset();
delete m_pSpriteMan;
//CPartSpray::DeleteVertBuffers(GetRenderer());
}
//////////////////////////////////////////////////////////////////////////
void CPartManager::Spawn( CParticleEmitter *pEmitter,bool bChildProcess )
{
if(!GetCVars()->e_particles)
return;
if(GetCVars()->e_particles_debug==2)
return;
//GetISystem()->VTuneResume();
if(pEmitter->m_pParams && pEmitter->m_pParams->nParticleFlags & PART_FLAG_NO_DRAW_UNDERWATER)
{
pEmitter->CalculateWaterLevel();
if(pEmitter->m_fWaterLevel>pEmitter->m_pos.z)
return;
}
//////////////////////////////////////////////////////////////////////////
Vec3d vCamPos = GetViewCamera().GetPos();
float fMaxViewDist = Get3DEngine()->GetMaxViewDist();
ParticleParams &Params = *pEmitter->m_pParams;
if (!bChildProcess)
{
Params.vPosition = pEmitter->m_pos;
Params.vDirection = pEmitter->m_dir;
//Params.pMaterial = pEmitter->m_pMaterial;
Params.pEntity = pEmitter->m_pSpawnerEntity;
// Check distance to camera with MaxViewDistance.
if (GetLengthSquared(Params.vPosition-vCamPos) > fMaxViewDist*fMaxViewDist)
return;
}
else
{
if (!pEmitter->m_pChildParams)
return;
// Check distance to camera with MaxViewDistance.
if (GetLengthSquared(pEmitter->m_pChildParams->vPosition-vCamPos) > fMaxViewDist*fMaxViewDist)
return;
}
// make sprites
pEmitter->OnSpawnParticles(bChildProcess);
m_pSpriteMan->Spawn( *pEmitter,bChildProcess );
//GetISystem()->VTunePause();
}
//////////////////////////////////////////////////////////////////////////
void CPartManager::Spawn( const ParticleParams &Params,float fMaxViewDist,CObjManager * pObjManager,bool bNoEmitter )
{
// if(Params.fLifeTime<0.5 && Params.pStatObj)
// return;
// Params.pStatObj = pObjManager->MakeObject("objects/box.cgf");
//Params.vInitAngles = Params.pEntity->GetAngles();
/*
if((Params.nParticleFlags & PART_FLAG_HORIZONTAL) && fabs(Params.vPosition.z - Get3DEngine()->GetWaterLevel())<1.f)
{
GetRenderer()->EF_AddSplash(Params.vPosition, EST_Water, Params.fSize+Params.fSizeSpeed);
return;
}
*/
if(!GetCVars()->e_particles)
return;
if(GetCVars()->e_particles_debug==2)
return;
IParticleEmitter *pEmitter = new CParticleEmitter( this );
pEmitter->SetParams( Params );
ActivateEmitter( (CParticleEmitter*)pEmitter );
}
void CPartManager::UpdateMan(CObjManager * pObjManager, CTerrain * pTerrain, int nRecursionLevel)
{
// function not used
assert(0);
// if(!GetCVars()->e_particles || nRecursionLevel)
return;
// GetRenderer()->ResetToDefault();
{ // update/render particle emitters
/* for(int i=0; i<m_lstpPartEmitters.Count(); i++)
if(!m_lstpPartEmitters[i]->Update(pObjManager, pTerrain, nRecursionLevel, &m_FreeParticles))
{ // remove if not used
m_lstpPartEmitters[i]->Shutdown();
delete m_lstpPartEmitters[i];
m_lstpPartEmitters.Delete(i);
i--;
}*/
}
// GetRenderer()->ResetToDefault();
// Draw sprites
// get orientation for billboard particles
Matrix44 mat;
GetRenderer()->GetModelViewMatrix(mat.GetData());
Vec3d
vRight = mat.GetColumn(0),
vUp = mat.GetColumn(1),
vFront = mat.GetColumn(2);
//CELL_CHANGED_BY_IVO
//vRight(mat.cell(0), mat.cell(4), mat.cell(8));
//vUp (mat.cell(1), mat.cell(5), mat.cell(9));
//vFront(mat.cell(2), mat.cell(6), mat.cell(10));
/*
// set rendering state
GetRenderer()->SetDepthFunc(R_LEQUAL);
GetRenderer()->EnableBlend(true);
GetRenderer()->EnableDepthWrites(false);
GetRenderer()->SetEnviMode(R_MODE_MODULATE);
GetRenderer()->SetCullMode(R_CULL_DISABLE);
// set world color
Vec3d vColor = GetSystem()->GetI3DEngine()->GetWorldColor();
GetRenderer()->SetMaterialColor(vColor.x,vColor.y,vColor.z,1);
*/
// float fTime = (float)GetCurTimeSec();
Vec3d vCamPos = GetViewCamera().GetPos();
//////////////////////////////////////////////////////////////////////////
//CCamera * pCamera = &GetViewCamera();
//bool bTestVis = (nRecursionLevel==0) && ((GetFrameID()&3)==0);
//CVars * pCVars = GetCVars();
m_pSpriteMan->Render(pObjManager, pTerrain, nRecursionLevel, this, m_pPartLightShader);
GetRenderer()->ResetToDefault();
}
int CPartManager::Count(int * pCurSpritesCount, int * pCurFreeCount, int * pCurEmitCount)
{
int nSumm=0;
// for(int i=0; i<m_lstpPartEmitters.Count(); i++)
// nSumm += m_lstpPartEmitters[i]->Count();
if(pCurSpritesCount)
*pCurSpritesCount = m_pSpriteMan->m_nCurSpritesCount;
/*
if(pCurFreeCount)
*pCurFreeCount = m_FreeParticles.Count();
*/
if(pCurEmitCount)
*pCurEmitCount = 0;//m_lstpPartEmitters.Count();
return nSumm;
}
void CPartManager::Render(CObjManager * pObjManager, CTerrain * pTerrain)
{
FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE );
int nRecursionLevel = pObjManager->m_nRenderStackLevel;
float fFrameTime = nRecursionLevel ? 0 : GetTimer()->GetFrameTime();
if(fFrameTime>0.2f)
fFrameTime=0.2f;
if(fFrameTime<0)
fFrameTime=0;
//////////////////////////////////////////////////////////////////////////
// Smooth frame time if not rendered in recursion.
//////////////////////////////////////////////////////////////////////////
if (nRecursionLevel == 0)
{
m_smoothTimes[m_smoothTimeCount] = fFrameTime;
m_smoothTimeCount++;
if(m_smoothTimeCount >= PARTICLES_SMOOTH_FRAMES)
m_smoothTimeCount = 0;
// average multiple frames together to smooth changes out a bit
float fTotalTime = 0;
for (int i = 0 ; i < PARTICLES_SMOOTH_FRAMES; i++ )
fTotalTime += m_smoothTimes[i];
fFrameTime = fTotalTime/PARTICLES_SMOOTH_FRAMES;
}
if (GetCVars()->e_particles_debug==2)
fFrameTime = 0;
if (nRecursionLevel == 0)
{
m_currParticlesTime += fFrameTime;
}
m_currParticlesFrameTime = fFrameTime;
//////////////////////////////////////////////////////////////////////////
// Update all emitters.
//////////////////////////////////////////////////////////////////////////
if (pObjManager->m_nRenderStackLevel == 0)
{
UpdateEmitters();
}
//GetISystem()->VTuneResume();
if(m_pSpriteMan)
m_pSpriteMan->Render(pObjManager, pTerrain, nRecursionLevel, this, m_pPartLightShader);
//GetISystem()->VTunePause();
}
/*
C_PartEmitter * CPartManager::CreateParticleEmitter(ParticleParams Params, float fSpawnPeriod, float fLifeTime)
{
if(!Params.nTexId)
Params.nTexId = m_nGlowTexID;
C_PartEmitter * pTmp = 0;//new C_PartEmitter(m_pSystem,this,Params, fSpawnPeriod, fLifeTime);
// m_lstpPartEmitters.Add(pTmp);
return pTmp;
} */
/*
void CPartManager::DeleteParticleEmitter(C_PartEmitter * pPartEmitter)
{
// delete pPartEmitter;
//m_lstpPartEmitters.Delete(pPartEmitter);
} */
void CPartManager::GetMemoryUsage(ICrySizer*pSizer)const
{
pSizer->Add (*this);
if(m_pSpriteMan)
pSizer->AddObject(m_pSpriteMan, sizeof(*m_pSpriteMan));
}
void CPartManager::Reset()
{
int i;
bool bActive = true;
IPhysicalWorld *pPhysWorld = Cry3DEngineBase::GetPhysicalWorld();
for (i = 0; i < m_pSpriteMan->m_nCurSpritesCount && i<m_pSpriteMan->m_nMaxSpritesCount; i++)
m_pSpriteMan->m_arrSprites[i].DeActivateParticle( pPhysWorld );
m_pSpriteMan->m_nCurSpritesCount=0;
// Clear all emitters.
for (ActiveEmitters::iterator it = m_activeEmitters.begin(); it != m_activeEmitters.end(); ++it)
{
CParticleEmitter *pEmitter = *it;
pEmitter->OnActivate( false );
}
m_activeEmitters.clear();
//////////////////////////////////////////////////////////////////////////
// Unload resources for all effects.
//////////////////////////////////////////////////////////////////////////
for (i = 0; i < (int)m_effects.size(); i++)
{
IParticleEffect *pEffect = m_effects[i];
((CParticleEffect*)pEffect)->UnloadResources(false);
}
}
void CPartManager::OnEntityDeleted(IEntityRender * pEntityRender)
{
if(m_pSpriteMan)
m_pSpriteMan->OnEntityDeleted(pEntityRender);
{ // delete active emitters of this entity
ActiveEmitters::iterator next;
for (ActiveEmitters::iterator it = m_activeEmitters.begin(); it != m_activeEmitters.end(); it = next)
{
next = it;
next++;
CParticleEmitter *pEmitter = *it;
if(pEmitter->m_pSpawnerEntity == pEntityRender)
{
pEmitter->OnActivate( false );
m_activeEmitters.erase(it);
}
}
}
{ // delete global emitters of this entity
ParticleEmitters::iterator next;
for (ParticleEmitters::iterator it = m_allEmitters.begin(); it != m_allEmitters.end(); it = next)
{
next = it;
next++;
CParticleEmitter *pEmitter = *it;
if(pEmitter->m_pSpawnerEntity == pEntityRender)
{
pEmitter->OnActivate( false );
m_allEmitters.erase( it );
}
}
}
}
void CSpriteManager::OnEntityDeleted(IEntityRender * pEntityRender)
{
for( int i=0; i<m_nCurSpritesCount && i<m_nMaxSpritesCount; i++)
{
if(m_arrSprites[i].m_pSpawnerEntity == pEntityRender)
{ // remove
m_arrSprites[i].DeActivateParticle( Cry3DEngineBase::GetPhysicalWorld());
m_arrSprites[i].m_pSpawnerEntity=0;
if(i < m_nCurSpritesCount-1)
{
m_arrSprites[i] = m_arrSprites[m_nCurSpritesCount-1];
memset(&m_arrSprites[m_nCurSpritesCount-1],0,sizeof(m_arrSprites[m_nCurSpritesCount-1]));
}
m_nCurSpritesCount--;
i--;
}
}
}
//////////////////////////////////////////////////////////////////////////
// Particle Effects.
//////////////////////////////////////////////////////////////////////////
IParticleEffect* CPartManager::CreateEffect()
{
IParticleEffect_AutoPtr pEffect = new CParticleEffect( this );
m_effects.push_back( pEffect );
return pEffect;
}
//////////////////////////////////////////////////////////////////////////
void CPartManager::RenameEffect( IParticleEffect *pEffect,const char *sNewName )
{
assert( pEffect );
const char *sOldName = pEffect->GetName();
if (strlen(sOldName) > 0)
{
// Delete old name.
m_effectsMap[sOldName] = 0;
}
if (strlen(sNewName) > 0)
{
// Add new name.
m_effectsMap[sNewName] = pEffect;
}
}
//////////////////////////////////////////////////////////////////////////
void CPartManager::RemoveEffect( IParticleEffect *pEffect )
{
assert( pEffect );
const char *sOldName = pEffect->GetName();
if (strlen(sOldName) > 0)
{
// Delete old name.
m_effectsMap[sOldName] = 0;
}
stl::find_and_erase( m_effects,pEffect );
}
//////////////////////////////////////////////////////////////////////////
IParticleEffect* CPartManager::FindEffect( const char *sEffectName )
{
IParticleEffect *pEffect = stl::find_in_map(m_effectsMap,sEffectName,(IParticleEffect*)NULL);
return pEffect;
}
//////////////////////////////////////////////////////////////////////////
void CPartManager::UpdateEmitters()
{
float fTime = GetParticlesTime();
CCamera *pCamera = &GetViewCamera();
ActiveEmitters::iterator next;
for (ActiveEmitters::iterator it = m_activeEmitters.begin(); it != m_activeEmitters.end(); it = next)
{
next = it;
next++;
_smart_ptr<CParticleEmitter> pEmitter = (*it);
CParticleEmitter &emitter = *pEmitter;
/*
// Check if emitter is visible.
if (pCamera->IsAABBVisibleFast(emitter.m_bbox))
emitter.m_bVisible = true;
else
emitter.m_bVisible = false;
// Reset bounding box.
emitter.m_bbox.Reset();
*/
float fSpawnPeriod = emitter.m_spawnPeriod/max(0.01f,GetCVars()->e_particles_lod) + (1.f-GetCVars()->e_particles_lod)*0.1f;
if (fTime > emitter.m_startTime || emitter.m_startTime == 0)
{
if (fTime - emitter.m_lastSpawnTime > fSpawnPeriod || fSpawnPeriod == 0)
{
// Remember last spawn time.
emitter.m_lastSpawnTime = fTime;
if (!pEmitter->m_childEmitters.empty())
pEmitter->UpdateChildSpawnTimes(fTime);
// Spawn particles from this emitter.
if (emitter.m_pEffect)
{
CParticleEffect* pEffect = (CParticleEffect*)((IParticleEffect*)emitter.m_pEffect);
if (!pEffect->PrepareSpawn( pEmitter->m_pos ))
continue;
}
Spawn( pEmitter );
}
}
if (!pEmitter->m_childEmitters.empty())
{
for (int i = 0; i < (int)pEmitter->m_childEmitters.size(); i++)
{
CParticleEmitter *pChildEmitter = pEmitter->m_childEmitters[i];
/*
// Check if emitter is visible.
if (pCamera->IsAABBVisibleFast(pChildEmitter->m_bbox))
pChildEmitter->m_bVisible = true;
else
pChildEmitter->m_bVisible = false;
pChildEmitter->m_bbox.Reset();
*/
if (!pChildEmitter->m_bActive || !pChildEmitter->m_bActiveChild)
continue;
if (fTime < pChildEmitter->m_startTime && emitter.m_startTime != 0)
continue;
// Check if needs to Deactivate emitter, on next update, spawn particles on this update anyway.
if (fTime > pChildEmitter->m_endTime)
pChildEmitter->m_bActiveChild = false;
float spawnPeriod = pChildEmitter->m_spawnPeriod/max(0.01f,GetCVars()->e_particles_lod) + (1.f-GetCVars()->e_particles_lod)*0.1f;
if (pChildEmitter->m_pParams->fEmitterLifeTime <= 0 && pChildEmitter->m_pParams->fSpawnDelay <= 0)
{
float spawnPeriodMul = pChildEmitter->m_pParams->fSpawnPeriod;
if (spawnPeriodMul == 0)
spawnPeriodMul = 1;
spawnPeriod = fSpawnPeriod * spawnPeriodMul;
}
if (fTime - pChildEmitter->m_lastSpawnTime > spawnPeriod)
{
// Remember last spawn time.
pChildEmitter->m_lastSpawnTime = fTime;
pChildEmitter->m_pos = pEmitter->m_pos;
pChildEmitter->m_dir = pEmitter->m_dir;
pChildEmitter->m_fScale = pEmitter->m_fScale;
// Spawn particles from this emitter.
if (emitter.m_pEffect)
{
CParticleEffect* pEffect = (CParticleEffect*)((IParticleEffect*)pChildEmitter->m_pEffect);
if (!pEffect->PrepareSpawn( pEmitter->m_pos ))
continue;
}
Spawn( pChildEmitter );
}
}
}
// If emitter end time == 0 do not kill this emitter.
if (fTime > emitter.m_endTime && emitter.m_bUseEndTime)
{
pEmitter->OnActivate( false );
// Times up, delete this emitter.
m_activeEmitters.erase( it );
// Also delete it from total emitters.
DeleteEmitter( pEmitter );
continue;
}
else
{
if (emitter.m_bPermament && fTime > emitter.m_lastActiveTime+ACTIVE_TIME)
{
// This emitter should get deactivated.
pEmitter->OnActivate( false );
m_activeEmitters.erase( it );
}
}
}
}
//////////////////////////////////////////////////////////////////////////
#define PATICLEPARAMS_COPY_HELPER( inparam,outparam,name ) outparam.name = inparam.name;
//////////////////////////////////////////////////////////////////////////
static void ExportDataToParticleParams( const SExportParticleParams &inp,ParticleParams &outp )
{
PATICLEPARAMS_COPY_HELPER( inp,outp,vPosition );
PATICLEPARAMS_COPY_HELPER( inp,outp,vDirection );
PATICLEPARAMS_COPY_HELPER( inp,outp,fFocus );
PATICLEPARAMS_COPY_HELPER( inp,outp,vColorStart );
PATICLEPARAMS_COPY_HELPER( inp,outp,vColorEnd );
PATICLEPARAMS_COPY_HELPER( inp,outp,fSpeed );
PATICLEPARAMS_COPY_HELPER( inp,outp,fSpeedFadeOut );
PATICLEPARAMS_COPY_HELPER( inp,outp,fSpeedAccel );
PATICLEPARAMS_COPY_HELPER( inp,outp,fAirResistance );
PATICLEPARAMS_COPY_HELPER( inp,outp,vRotation );
PATICLEPARAMS_COPY_HELPER( inp,outp,vInitAngles );
PATICLEPARAMS_COPY_HELPER( inp,outp,nCount );
PATICLEPARAMS_COPY_HELPER( inp,outp,fSize );
PATICLEPARAMS_COPY_HELPER( inp,outp,fSizeSpeed );
PATICLEPARAMS_COPY_HELPER( inp,outp,fSizeFadeIn );
PATICLEPARAMS_COPY_HELPER( inp,outp,fSizeFadeOut );
PATICLEPARAMS_COPY_HELPER( inp,outp,fThickness );
PATICLEPARAMS_COPY_HELPER( inp,outp,fLifeTime );
PATICLEPARAMS_COPY_HELPER( inp,outp,fFadeInTime );
PATICLEPARAMS_COPY_HELPER( inp,outp,nTexAnimFramesCount );
PATICLEPARAMS_COPY_HELPER( inp,outp,eBlendType );
PATICLEPARAMS_COPY_HELPER( inp,outp,fTailLenght );
PATICLEPARAMS_COPY_HELPER( inp,outp,nTailSteps );
PATICLEPARAMS_COPY_HELPER( inp,outp,fStretch );
PATICLEPARAMS_COPY_HELPER( inp,outp,nParticleFlags );
PATICLEPARAMS_COPY_HELPER( inp,outp,bRealPhysics );
PATICLEPARAMS_COPY_HELPER( inp,outp,fChildSpawnPeriod );
PATICLEPARAMS_COPY_HELPER( inp,outp,fChildSpawnTime );
PATICLEPARAMS_COPY_HELPER( inp,outp,nDrawLast );
PATICLEPARAMS_COPY_HELPER( inp,outp,fBouncenes );
PATICLEPARAMS_COPY_HELPER( inp,outp,fTurbulenceSize );
PATICLEPARAMS_COPY_HELPER( inp,outp,fTurbulenceSpeed );
PATICLEPARAMS_COPY_HELPER( inp,outp,fDirVecScale );
PATICLEPARAMS_COPY_HELPER( inp,outp,fPosRandomOffset );
PATICLEPARAMS_COPY_HELPER( inp,outp,vPositionOffset );
PATICLEPARAMS_COPY_HELPER( inp,outp,vRandomPositionOffset );
PATICLEPARAMS_COPY_HELPER( inp,outp,fSpawnDelay );
PATICLEPARAMS_COPY_HELPER( inp,outp,fEmitterLifeTime );
PATICLEPARAMS_COPY_HELPER( inp,outp,fSpawnPeriod );
PATICLEPARAMS_COPY_HELPER( inp,outp,fScale );
PATICLEPARAMS_COPY_HELPER( inp,outp,fObjectScale );
PATICLEPARAMS_COPY_HELPER( inp,outp,vNormal );
PATICLEPARAMS_COPY_HELPER( inp,outp,iPhysMat );
PATICLEPARAMS_COPY_HELPER( inp,outp,vGravity );
}
//////////////////////////////////////////////////////////////////////////
bool CPartManager::LoadParticles( CCryFile &file )
{
//UpdateLoadingScreen( "\003Loading Particle Effects..." );
SExportedParticlesHeader header;
file.Read( &header,sizeof(header) );
if (strncmp(header.signature,PARTICLES_FILE_SIGNATURE,sizeof(header.signature)) != 0)
{
// Bad signature.
Warning( 0,file.GetFilename(),"Cannot Load Particles,Wrong File Signature %s",file.GetFilename() );
return false;
}
if (header.filetype != PARTICLES_FILE_TYPE)
{
// Bad signature.
Warning( 0,file.GetFilename(),"Cannot Load Particles,Wrong File Type %s",file.GetFilename() );
return false;
}
if (header.version != PARTICLES_FILE_VERSION)
{
// Bad signature.
Warning( 0,file.GetFilename(),"Cannot Load Particles,Wrong File Version %s",file.GetFilename() );
return false;
}
int numItems;
file.Read( &numItems,sizeof(numItems) );
std::vector<SExportParticleEffect> exportedEffects;
std::vector<IParticleEffect*> libEffects;
exportedEffects.resize( numItems );
libEffects.resize( numItems );
int fileSize = file.GetLength();
if (numItems*sizeof(SExportParticleEffect) != fileSize-sizeof(header)-sizeof(numItems))
{
Warning( 0,file.GetFilename(),"Cannot Load Particles,Corrupted File %s",file.GetFilename() );
return false;
}
if (numItems > 0)
{
file.Read( &exportedEffects[0],numItems*sizeof(SExportParticleEffect) );
}
//UpdateLoadingScreen( "Loading Particles %s",file.GetFilename() );
int i;
// Initialize effects.
for (i = 0; i < numItems; i++)
{
IParticleEffect_AutoPtr pEffect = CreateEffect();
libEffects[i] = pEffect;
for (int p = 0; p < IParticleEffect::NUM_PARTICLE_PROCESSES; p++)
{
ParticleParams &params = pEffect->GetParticleParams(p);
ExportDataToParticleParams( exportedEffects[i].params[p],params );
// Reset data that must be loaded.
params.nTexId = 0;
params.pStatObj = 0;
params.pMaterial = 0;
params.pChild = 0;
params.pAnimTex = 0;
params.pEntity = 0;
params.pShader = 0;
pEffect->SetTexture( p,exportedEffects[i].texture[p] );
pEffect->SetGeometry( p,exportedEffects[i].geometry[p] );
pEffect->SetMaterialName( p,exportedEffects[i].material[p] );
// Load Resources at this point.
}
if (exportedEffects[i].flags & PARTICLE_EFFECT_DISABLED)
{
pEffect->SetEnabled(false);
}
IParticleEffect::SoundParams sndParams;
sndParams.szSound = exportedEffects[i].sound.soundfile;
sndParams.volume = exportedEffects[i].sound.volume;
sndParams.minRadius = exportedEffects[i].sound.minRadius;
sndParams.maxRadius = exportedEffects[i].sound.maxRadius;
sndParams.bLoop = (exportedEffects[i].sound.nSoundFlags & SExportParticleSound::LOOP) != 0;
sndParams.bOnEverySpawn = (exportedEffects[i].sound.nSoundFlags & SExportParticleSound::EVERY_SPAWN) != 0;
pEffect->SetSoundParams(sndParams);
pEffect->SetName( exportedEffects[i].name );
pEffect->LoadResources();
}
// Link to parents.
for (i = 0; i < (int)exportedEffects.size(); i++)
{
int parent = exportedEffects[i].parent;
if (parent >= 0)
{
IParticleEffect* pEffect = libEffects[i];
IParticleEffect* pParentEffect = libEffects[parent];
pParentEffect->AddChild( pEffect );
}
}
UpdateLoadingScreen( "\003Loaded %d Particle Effects from %s.",numItems,file.GetFilename() );
return true;
}
//////////////////////////////////////////////////////////////////////////
IParticleEmitter* CPartManager::CreateEmitter()
{
CParticleEmitter *pEmitter = new CParticleEmitter( this );
pEmitter->m_bPermament = true;
m_allEmitters.insert( pEmitter );
return pEmitter;
}
//////////////////////////////////////////////////////////////////////////
void CPartManager::DeleteEmitter( IParticleEmitter *pEmitter )
{
assert( pEmitter );
CParticleEmitter *pEmt = (CParticleEmitter*)pEmitter;
//////////////////////////////////////////////////////////////////////////
if (pEmt->m_bPermament)
m_allEmitters.erase( pEmt );
// delete emitter from list.
if (pEmt->m_bActive)
stl::find_and_erase( m_activeEmitters,pEmt );
}
//////////////////////////////////////////////////////////////////////////
void CPartManager::ActivateEmitter( CParticleEmitter *pEmitter )
{
if (pEmitter!=NULL && !pEmitter->m_bActive)
{
pEmitter->OnActivate( true );
m_activeEmitters.push_back( pEmitter );
}
}
//////////////////////////////////////////////////////////////////////////
void CPartManager::LoadSharedParticleLibrary( const char *sEffectsFolder,const char *sLibName )
{
if (m_loadedLibs.find(sLibName) != m_loadedLibs.end())
{
// Already loaded.
return;
}
char filename[_MAX_PATH];
_makepath( filename,NULL,sEffectsFolder,sLibName,"prt" );
CCryFile file;
if (file.Open( filename,"rb" ))
{
LoadParticles( file );
m_loadedLibs.insert( sLibName );
}
}
//////////////////////////////////////////////////////////////////////////
void CPartManager::LoadParticlesLibs( const char *sEffectsFolder,XmlNodeRef &levelDataRoot )
{
XmlNodeRef libs = levelDataRoot->findChild( "ParticlesLibrary" );
if (!libs)
return;
// Enmerate material libraries.
for (int i = 0; i < libs->getChildCount(); i++)
{
XmlNodeRef libNode = libs->getChild(i);
XmlString libraryName = libNode->getAttr( "Name");
LoadSharedParticleLibrary( sEffectsFolder,libraryName );
}
}

358
Cry3DEngine/partman.h Normal file
View File

@@ -0,0 +1,358 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: partman.h
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#ifndef PART_MANAGER
#define PART_MANAGER
#define MAX_PARTICLES_IN_VIDEO_BUFFER 16
#define MAX_VIDEO_BUFFERS_PER_SPRAY 4
#define PARTICLES_SMOOTH_FRAMES 20
#define PART_MAX_HISTORY_ELEMENTS 256
#define rn() ((((float)rand())/RAND_MAX)-0.5f)
#include "ParticleEffect.h"
#include "ParticleEmitter.h"
// particle proc params
struct PartProcessParams
{
PartProcessParams() { memset(this, 0, sizeof(PartProcessParams)); }
float fCurTime, fFrameTime;
Vec3d vRight, vUp, vFront;
IRenderer * pIRenderer;
CObjManager * pObjManager;
CTerrain * pTerrain;
IPhysicalWorld * pPhysicalWorld;
class C3DEngine *p3DEngine;
CCamera * pCamera;
struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * pVertBufChunk;
struct ISystem * pSystem;
class CPartManager * pPartManager;
Vec3 vCamPos;
Vec3d vSpaceFocusPos;
};
class CPartManager;
// dynamic particle data
class CParticle
{
public:
enum EAdvancedParticleFlags
{
PARTICLE_COLOR_BASED = 0x10000,
PARTICLE_ADDITIVE = 0x20000,
PARTICLE_ANIMATED_TEXTURE = 0x40000
};
//int m_nId; // debug
//CParticle *m_pNext, *m_pPrev;
// cur state
int m_nParticleFlags;
Vec3 m_vPos;
Vec3 m_vDelta;
float m_fSize;
float m_fSizeOriginal;
float m_fScale;
float m_fSpawnTime;
float m_fLifeTime;
float m_fChildSpawnLastTime;
float m_fTrailCurPos;
Vec3 m_vAngles;
Vec3 m_vRotation;
//int m_nDynLightMask;
//int m_nFogVolumeId;
unsigned int m_cAmbientColor;
//! Override material for this emitter.
IMatInfo *m_pMaterial;
//! Entity who controls this emitter.
IEntityRender *m_pSpawnerEntity;
//IVisArea * m_pVisArea;
IPhysicalEntity * m_pPhysEnt;
ParticleParams* m_pParams;
//! Emitter who spawned this entity.
CParticleEmitter* m_pEmitter;
// For patricles with tail, keeps history of previous positions.
Vec3 *m_pArrvPosHistory;
unsigned char m_nTailSteps;
char m_reserved[3]; // Fill to 32 byte.
CParticle()
{
//m_nId=0;
m_nParticleFlags = 0;
m_vPos(0,0,0);
m_vDelta(0,0,0);
m_fSize=0;
m_fSizeOriginal=0;
//m_pNext=m_pPrev=0;
m_fSpawnTime=0;
m_pPhysEnt=0;
m_fScale = 1;
m_fChildSpawnLastTime = 0;
//m_fTrailCurPos = 0;
m_vAngles(0,0,0);
m_vRotation(0,0,0);
m_cAmbientColor = 0;
//m_pVisArea = 0;
//m_nDynLightMask = 0;
//m_nFogVolumeId = 0;
m_pMaterial = 0;
m_pSpawnerEntity = 0;
m_pArrvPosHistory = 0;
m_fTrailCurPos = 0;
m_nTailSteps = 8;
m_reserved[0] = 0;
m_reserved[1] = 0;
m_reserved[2] = 0;
}
bool Update(const PartProcessParams & PPP);
void FillBuffer(const PartProcessParams & PPP);
void DeActivateParticle(IPhysicalWorld * pPhysicalWorld);
void Physicalize( ParticleParams &Params,IPhysicalWorld * pPhysicalWorld);
unsigned int Vec2Color( const Vec3 &v )
{
unsigned int r = (FtoI(v.x*255.0f)), g = FtoI(v.y*255.0f), b = FtoI(v.z*255.0f);
return r|(g<<8)|(b<<16);
}
Vec3 Color2Vec( unsigned int c )
{
return Vec3(
((unsigned char)(c))*0.00392156f,
((unsigned char)(c>>8))*0.00392156f,
((unsigned char)(c>>16))*0.00392156f );
}
};
/*
// linked list of particles
class CPartList
{
CParticle *m_pFirst, *m_pLast;
int m_nCount;
public:
CPartList() { memset(this,0,sizeof(CPartList)); }
~CPartList() { assert(!m_nCount && !m_pFirst); }
int Count() { return m_nCount; }
CParticle * GetFirst() { return m_pFirst; }
CParticle * GetLast() { return m_pLast; }
void Add(CParticle * pElem)
{
assert(!pElem->m_pNext && !pElem->m_pPrev);
if(!m_pFirst)
{ // insert first element
m_pFirst = m_pLast = pElem;
pElem->m_pNext = pElem->m_pPrev = 0;
assert(!m_nCount);
}
else
{
assert(!m_pLast->m_pNext && !m_pFirst->m_pPrev);
pElem->m_pPrev = m_pLast;
pElem->m_pNext = 0;
m_pLast->m_pNext = pElem;
m_pLast = pElem;
assert(m_nCount);
}
m_nCount++;
}
void Remove(CParticle * pElem)
{
if(m_pLast == pElem)
m_pLast = pElem->m_pPrev;
if(m_pFirst == pElem)
m_pFirst = pElem->m_pNext;
if(pElem->m_pNext)
{
assert(pElem->m_pNext->m_pPrev == pElem);
pElem->m_pNext->m_pPrev = pElem->m_pPrev;
}
if(pElem->m_pPrev)
{
assert(pElem->m_pPrev->m_pNext == pElem);
pElem->m_pPrev->m_pNext = pElem->m_pNext;
}
pElem->m_pPrev = pElem->m_pNext = 0;
m_nCount--;
}
};
*/
// sprite contain dynamic data and life style
class CSprite : public CParticle
{
public:
void Render( const PartProcessParams &PPP, IShader *pShader );
int FillTailVertBuffer( SColorVert * pTailVerts,
const Vec3d & vCamVec,
const UCol & ucColor );
};
// manager contain all sprites(in pool) and emitters
class CSpriteManager : public Cry3DEngineBase
{
public:
CSpriteManager(class CPartManager *pPartManager);
~CSpriteManager();
void Spawn( CParticleEmitter &emitter,bool bChildProcess );
void Render( CObjManager * pObjManager, CTerrain * pTerrain, int nRecursionLevel, CPartManager * pPartManager, IShader * pPartLightShader);
void OnEntityDeleted(IEntityRender * pEntityRender);
CSprite * m_arrSprites;//[MAX_SPRITES_COUNT];
int m_nCurSpritesCount;
int m_nMaxSpritesCount;
private:
void SpawnParticle( CParticleEmitter &emitter,bool bChildProcess,float fCurrTime,CParticle *pParticle );
ISystem* m_pSystem;
I3DEngine* m_p3DEngine;
CVisAreaManager *m_pVisAreaManager;
CObjManager *m_pObjManager;
CPartManager *m_pPartManager;
};
// contain part spray and reference counter
/*class C_PartEmitter : public Cry3DEngineBase, public IPartEmitter
{
CPartManager * m_pPartManager;
ParticleParams m_PartParams;
float m_fSpawnPeriod, m_fLastSpawnTime, m_fLifeEndTime;
public:
CPartSpray * m_pSpray;
int m_nUsers;
C_PartEmitter(CPartManager * pPartManager, const ParticleParams & Params, const float fSpawnPeriod, const float fLifeTime);
bool Update(CObjManager * pObjManager, CTerrain * pTerrain, int nRecursionLevel, CPartList * pFreeParticles);
virtual void Spawn(const Vec3d & vPos);
void Shutdown();
int Count() { return m_pSpray->Count(); }
};*/
// top class of particle system
class CPartManager : public Cry3DEngineBase
{
public:
CPartManager( );
~CPartManager();
void Spawn( const ParticleParams &Params,float fMaxViewDist, CObjManager * pObjManager,bool bNoEmitter=false );
void Spawn( CParticleEmitter *pEmitter,bool bChildProcess=false );
void UpdateMan(CObjManager * pObjManager, CTerrain * pTerrain, int nRecursionLevel);
void Render(CObjManager * pObjManager, CTerrain * pTerrain);
int Count(int * pCurSpritesCount, int * pCurFreeCount, int * pCurEmitCount);
// C_PartEmitter * CreateParticleEmitter(ParticleParams Params, float fSpawnPeriod = 1000000, float fLifeTime = 1000000);
//void DeleteParticleEmitter(C_PartEmitter * pPartEmitter);
void GetMemoryUsage(ICrySizer* pSizer)const;
void Reset();
void OnEntityDeleted(IEntityRender * pEntityRender);
int GetGlowTexID() const { return m_nGlowTexID; }
//////////////////////////////////////////////////////////////////////////
// Particle effects interface.
//////////////////////////////////////////////////////////////////////////
IParticleEffect* CreateEffect();
void RenameEffect( IParticleEffect *pEffect,const char *sNewName );
void RemoveEffect( IParticleEffect *pEffect );
IParticleEffect* FindEffect( const char *sEffectName );
//! Load particle effects from file.
//! @return true if succesfully loaded.
bool LoadParticles( CCryFile &file );
void LoadSharedParticleLibrary( const char *sEffectsFolder,const char *sLibName );
void LoadParticlesLibs( const char *sEffectsFolder,XmlNodeRef &levelDataRoot );
//////////////////////////////////////////////////////////////////////////
// Emitters.
//////////////////////////////////////////////////////////////////////////
IParticleEmitter* CreateEmitter();
void DeleteEmitter( IParticleEmitter *pEmitter );
void ActivateEmitter( CParticleEmitter *pEmitter );
//////////////////////////////////////////////////////////////////////////
// Particles timing.
//////////////////////////////////////////////////////////////////////////
float GetParticlesTime() const { return m_currParticlesTime; };
float GetParticlesFrameTime() const { return m_currParticlesFrameTime; };
//////////////////////////////////////////////////////////////////////////
void PlaySound( ISound *pSound );
protected:
void UpdateEmitters();
void UpdateSounds();
private:
//CPartList m_FreeParticles;
//CParticle m_arrParts[MAX_PARTICLES_COUNT];
CSpriteManager * m_pSpriteMan;
int m_nGlowTexID;
// list2<CPartEmitter*> m_lstpPartEmitters;
IShader * m_pPartLightShader;
//////////////////////////////////////////////////////////////////////////
//[Timur] Particle Effects.
//////////////////////////////////////////////////////////////////////////
//! Array of all registered particle effects.
std::vector<IParticleEffect_AutoPtr> m_effects;
//! Map of particle effect case insensetive name to interface pointer.
typedef std::map<String,IParticleEffect_AutoPtr,stl::less_stricmp<String> > EffectsMap;
EffectsMap m_effectsMap;
//////////////////////////////////////////////////////////////////////////
// Loaded particle libs.
std::set<String,stl::less_stricmp<String> > m_loadedLibs;
//////////////////////////////////////////////////////////////////////////
// Particle effects emitters.
//////////////////////////////////////////////////////////////////////////
typedef std::set<_smart_ptr<CParticleEmitter> > ParticleEmitters;
typedef std::list<_smart_ptr<CParticleEmitter> > ActiveEmitters;
ParticleEmitters m_allEmitters;
ActiveEmitters m_activeEmitters;
//////////////////////////////////////////////////////////////////////////
// Particle time smoothing.
//////////////////////////////////////////////////////////////////////////
float m_currParticlesTime;
float m_currParticlesFrameTime;
int m_smoothTimeCount;
float m_smoothTimes[PARTICLES_SMOOTH_FRAMES];
};
#endif // PART_MANAGER

436
Cry3DEngine/partpolygon.cpp Normal file
View File

@@ -0,0 +1,436 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: partpolygon.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: sprite particles, big independent polygons
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "partman.h"
#include "objman.h"
#include "3dEngine.h"
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
void CSprite::Render( const PartProcessParams &PPP,IShader *pShader )
{
float fCurTime = PPP.fCurTime;
uint nDynLightMask = 0;
if (m_pEmitter->m_pShader)
{
pShader = m_pEmitter->m_pShader;
}
else
{
if (m_pParams->pShader)
pShader = m_pParams->pShader;
else
{
if (m_pMaterial)
{
IShader *pShaderContainer = m_pMaterial->GetShaderItem().m_pShader;
if (pShaderContainer)
pShader = pShaderContainer->GetTemplate(-1);
}
}
}
// pRenderer->DrawLabel(m_vPos,2,"%d",nDynLightMask);
int dwCCObjFlags = 0;
if (m_pParams->nParticleFlags & PART_FLAG_DRAW_NEAR)
dwCCObjFlags = FOB_NEAREST;
// do not draw fire in the water
if(m_pParams->nParticleFlags & PART_FLAG_NO_DRAW_UNDERWATER && m_pEmitter->m_fWaterLevel>WATER_LEVEL_UNKNOWN)
if(m_vPos.z < m_pEmitter->m_fWaterLevel)
return;
// Render 3d object
if(m_pParams->pStatObj)
{
float fObjScale = m_fSize;
if (m_pParams->fObjectScale)
fObjScale *= m_pParams->fObjectScale;
nDynLightMask = PPP.p3DEngine->GetLightMaskFromPosition(m_vPos, fObjScale);
PPP.p3DEngine->CheckDistancesToLightSources(nDynLightMask,m_vPos,fObjScale,m_pSpawnerEntity,1);
//Matrix44 matPart2=GetTranslationMat(m_vPos);
Matrix44 matPart2=Matrix34::CreateTranslationMat(m_vPos);
matPart2=GetTransposed44(matPart2);
matPart2=Matrix33::CreateScale( Vec3d(fObjScale,fObjScale,fObjScale) )*matPart2;
if (m_pParams->nParticleFlags & PART_FLAG_SWAP_XY)
{
matPart2=Matrix33::CreateRotationAA( -m_vAngles.z*gf_DEGTORAD, Vec3d(0,0,1) )*matPart2; //NOTE: angles needs to be negated
matPart2=Matrix33::CreateRotationAA( -m_vAngles.x*gf_DEGTORAD, Vec3d(1,0,0) )*matPart2; //NOTE: angles needs to be negated
matPart2=Matrix33::CreateRotationAA( -m_vAngles.y*gf_DEGTORAD, Vec3d(0,1,0) )*matPart2; //NOTE: angles needs to be negated
}
else
matPart2=Matrix44::CreateRotationZYX(-gf_DEGTORAD*m_vAngles)*matPart2; //NOTE: angles in radians and negated
//-------------------------------------------------------------------
if(!(m_pParams->nParticleFlags & PART_FLAG_NO_OFFSET))
{
Vec3d vCenter = (m_pParams->pStatObj->GetBoxMax() + m_pParams->pStatObj->GetBoxMin())*0.5f;
//Matrix44 matOffSet=GetTranslationMat(-vCenter*fObjScale);
Matrix44 matOffSet=Matrix34::CreateTranslationMat(-vCenter*fObjScale);
matOffSet=GetTransposed44(matOffSet);
matPart2 = matOffSet * matPart2;
}
//-----------------------------------------------------------------------------------------------
SRendParams rParms;
rParms.pMatrix = &matPart2;
rParms.nDLightMask = nDynLightMask;
rParms.nStrongestDLightMask = nDynLightMask;
rParms.vAmbientColor = Color2Vec(m_cAmbientColor);
rParms.dwFObjFlags = FOB_IGNOREMATERIALAMBIENT | dwCCObjFlags;
// rParms.nFogVolumeID = m_nFogVolumeId;
rParms.pMaterial = m_pMaterial;
rParms.dwFObjFlags |= FOB_TRANS_MASK;
int nSortId = max(-4,min(4,m_pParams->nDrawLast));
nSortId = FtoI(PPP.pObjManager->GetSortOffset(m_vPos,PPP.vCamPos,m_pEmitter->m_fWaterLevel)) - nSortId;
rParms.fCustomSortOffset = (float)nSortId;
if(dwCCObjFlags & FOB_NEAREST)
rParms.nSortValue = EFSLIST_LAST;
float fAge = fCurTime-m_fSpawnTime;
float fAlpha = (1.f - (fAge - m_pParams->fFadeInTime)/(m_fLifeTime - m_pParams->fFadeInTime));//*2.f;
//if(fAlpha<0) fAlpha=0; else if(fAlpha>1) fAlpha=1;
// fadde in
if (fAge < m_pParams->fFadeInTime && fCurTime)
fAlpha *= fAge / m_pParams->fFadeInTime;
fAlpha*=1.5f;
if(fAlpha<0) fAlpha=0; else if(fAlpha>1) fAlpha=1;
rParms.fAlpha = fAlpha;
m_pParams->pStatObj->Render(rParms,Vec3(zero),0);
}
// render sprite
if (m_pParams->nTexId)
{
if (m_pParams->eBlendType != ParticleBlendType_Additive)
{
nDynLightMask = PPP.p3DEngine->GetLightMaskFromPosition(m_vPos, 0);
PPP.p3DEngine->CheckDistancesToLightSources(nDynLightMask,m_vPos,m_fSize,m_pSpawnerEntity,1);
}
// find vertex offsets from origin
Vec3d vFront, vRight, vUp;
Vec3d vParticlePos = m_vPos;
{
if(m_pParams->nParticleFlags & PART_FLAG_HORIZONTAL)
{
vRight = Vec3d(m_fSize,0,0);
vUp = Vec3d(0,m_fSize,0);
vFront = Vec3d(0,0,1);
}
else
{
vFront = PPP.vFront;
vRight = -PPP.vRight*m_fSize;
vUp = -PPP.vUp*m_fSize;
}
if(m_vAngles.z)
{
Matrix33 mat;
mat.SetRotationAA( DEG2RAD(m_vAngles.z), vFront ); //NOTE: angles needs to be negated
vRight = mat * vRight;
vUp = mat * vUp;
}
// Stretching to speed direction.
if (m_pParams->fStretch != 0)
{
float fSpeed = m_vDelta.GetLength();
if (fSpeed < 0.01f)
fSpeed = 0.01f;
vFront = PPP.pCamera->GetPos() - m_vPos;
vFront.Normalize();
Vec3d vVec1 = -vFront.Cross(m_vDelta/fSpeed);
Vec3d vVec2 = vVec1.Cross(vFront);
vRight = m_fSize * vVec1;
vUp = m_fSize * vVec2;
vUp = vUp + vUp*fSpeed*m_pParams->fStretch;
vParticlePos -= vUp; // Offset partcile.
}
}
int nSortId = max(-4,min(4,m_pParams->nDrawLast));
nSortId = FtoI(PPP.pObjManager->GetSortOffset(m_vPos,PPP.vCamPos,m_pEmitter->m_fWaterLevel)) - nSortId;
/*
if((vCamPos.z-pTerrain->Ge tWaterLevel())*(m_vPos.z-pTerrain->GetWaterLev el())>0)
nSortId += 10000;
else
nSortId -= 10000;
*/
////////////////////////////////////////////////////////////////////////////////////////////////
// Find color, texture and alpha
////////////////////////////////////////////////////////////////////////////////////////////////
int nTexBindId = m_pParams->nTexId;
float fAlpha = 1.f;
float t=0; // from 0 to 1
float fAge = fCurTime-m_fSpawnTime;
if ((m_nParticleFlags & PARTICLE_ANIMATED_TEXTURE) && m_pParams->pAnimTex)
{ // animated
t = fAge/m_fLifeTime;
if (t<0) t=0; else if(t>1) t=1;
float anim_time = t*(m_pParams->nTexAnimFramesCount-1);
AnimTexInfo *pAnimTexInfo = m_pParams->pAnimTex;
int cur_tid = 0;
cur_tid = ((int)anim_time) % pAnimTexInfo->nFramesCount;
nTexBindId = pAnimTexInfo->pBindIds[cur_tid];
//t = float(cur_tid)/(pAnimTexInfo->nFramesCount);
}
else if(m_pParams->nTexId>=0)
{ // one frame
nTexBindId = m_pParams->nTexId;
t = fAge/m_fLifeTime;
if (t<0) t=0; else if(t>1) t=1;
}
fAlpha = (1.f - (fAge - m_pParams->fFadeInTime)/(m_fLifeTime - m_pParams->fFadeInTime));//*2.f;
//if(fAlpha<0) fAlpha=0; else if(fAlpha>1) fAlpha=1;
if(!m_fLifeTime)
{
fAlpha = 1.f;
t = 0;
}
// fadde in
if (fAge < m_pParams->fFadeInTime && fCurTime)
fAlpha *= fAge / m_pParams->fFadeInTime;
fAlpha*=1.5f;
if(fAlpha<0) fAlpha=0; else if(fAlpha>1) fAlpha=1;
Vec3d vResColor;
vResColor = m_pParams->vColorStart*(1.f-t) + m_pParams->vColorEnd*t;
// find result color
if(nDynLightMask==0 && (!(m_nParticleFlags & CParticle::PARTICLE_ADDITIVE)))
{
vResColor.Set(0,0,0);
}
else
{
if (m_nParticleFlags & CParticle::PARTICLE_COLOR_BASED)
vResColor *= fAlpha*255.f;
else
vResColor *= 0.5f*255.f;
}
Vec3 vAmbientColor;
if (m_nParticleFlags & CParticle::PARTICLE_COLOR_BASED)
{
vAmbientColor.Set(0,0,0);
}
else
{
if(PPP.p3DEngine->GetFogEnd()>PPP.p3DEngine->GetFogStart())
{
float fDist = (L1Distance2D(m_vPos, PPP.vCamPos)-PPP.p3DEngine->GetFogStart())
/(PPP.p3DEngine->GetFogEnd()-PPP.p3DEngine->GetFogStart());
if(fDist>1.f)
fDist=1.f;
else if(fDist<0)
fDist=0;
fAlpha *= (1.f-fDist);
}
vAmbientColor = Color2Vec(m_cAmbientColor);
}
// fade if near the space bounds
float fAlphaSpaceLoopRatio = 1.f;
if(m_pParams->nParticleFlags & PART_FLAG_SPACELOOP && m_pEmitter)
{
float fDistFromCenterX = m_pParams->vSpaceLoopBoxSize.x - fabs(m_pEmitter->m_pos.x-m_vPos.x);
float fDistFromCenterY = m_pParams->vSpaceLoopBoxSize.y - fabs(m_pEmitter->m_pos.y-m_vPos.y);
float fDistFromCenterZ = m_pParams->vSpaceLoopBoxSize.z - fabs(m_pEmitter->m_pos.z-m_vPos.z);
float fMinDistToTheBorder = min(min(fDistFromCenterX,fDistFromCenterY),fDistFromCenterZ);
fAlphaSpaceLoopRatio = max(0,min(1.f,fMinDistToTheBorder*0.5f));
}
// make particle color
UCol ucResCol;
ucResCol.bcolor[0] = fastftol_positive(vResColor.x);
ucResCol.bcolor[1] = fastftol_positive(vResColor.y);
ucResCol.bcolor[2] = fastftol_positive(vResColor.z);
ucResCol.bcolor[3] = fastftol_positive(255.f*fAlpha*fAlphaSpaceLoopRatio);
if(m_pParams->nParticleFlags & PART_FLAG_LINEPARTICLE)
{ // line bullet trail
Vec3d vCamVec = PPP.pCamera->GetPos()-m_vPos;
vCamVec.Normalize();
Vec3d vSideStep = vCamVec.Cross(m_vDelta.normalized());
vSideStep.Normalize();
vSideStep.SetLen(m_fSize);
PPP.pObjManager->AddPolygonToRenderer( nTexBindId, pShader, nDynLightMask, vSideStep, m_vDelta*0.5f,
ucResCol,
m_pParams->eBlendType,
vAmbientColor,
vParticlePos+m_vDelta*0.5f, 0,0,0,0, (float)nSortId, dwCCObjFlags, m_pMaterial );
}
else if (m_pParams->fTailLenght)
{ // render with tail
SColorVert arrTailVerts[PART_MAX_HISTORY_ELEMENTS*2];
byte arrTailIndices[PART_MAX_HISTORY_ELEMENTS*6];
int nTailVertsNum=0, nTailIndsNum=0;
nTailVertsNum = FillTailVertBuffer( arrTailVerts, vFront, ucResCol );
if(nTailVertsNum>2)
{ // fill tail indices
nTailIndsNum = (nTailVertsNum/2-1)*6;
int nIdxId = 0;
for(int i=0; i<(nTailVertsNum/2-1); i++)
{
arrTailIndices[nIdxId++] = i*2+0;
arrTailIndices[nIdxId++] = i*2+1;
arrTailIndices[nIdxId++] = i*2+2;
arrTailIndices[nIdxId++] = i*2+1;
arrTailIndices[nIdxId++] = i*2+2;
arrTailIndices[nIdxId++] = i*2+3;
assert(i*2+3 < m_nTailSteps*2);
}
assert(nIdxId == nTailIndsNum);
}
// nTailIndsNum=0;
PPP.pObjManager->AddPolygonToRenderer( nTexBindId, pShader, nDynLightMask, vRight, vUp,
ucResCol,
m_pParams->eBlendType,
vAmbientColor,
vParticlePos, arrTailVerts, nTailVertsNum, arrTailIndices, nTailIndsNum, (float)nSortId, dwCCObjFlags, m_pMaterial);
if (m_pArrvPosHistory)
{
float fTailLength = (m_pParams->fTailLenght/m_nTailSteps) / m_fScale; // Here we must divide by scale because speed is scaled.
m_fTrailCurPos += min(1.f, PPP.fFrameTime/fTailLength);
m_pArrvPosHistory[FtoI(m_fTrailCurPos)%m_nTailSteps] = m_vPos;
}
}
else
{
list2<struct ShadowMapLightSourceInstance> * pShadowsList = NULL;
if(PPP.pObjManager->GetCVars()->e_particles_receive_shadows &&
m_pSpawnerEntity && m_pSpawnerEntity->GetEntityRS() && m_pSpawnerEntity->GetEntityRS()->pShadowMapInfo)
pShadowsList = m_pSpawnerEntity->GetEntityRS()->pShadowMapInfo->pShadowMapCasters;
// no tail
PPP.pObjManager->AddPolygonToRenderer( nTexBindId, pShader, nDynLightMask, vRight, vUp,
ucResCol,
m_pParams->eBlendType,
vAmbientColor,
vParticlePos, 0,0,0,0, (float)nSortId, dwCCObjFlags, m_pMaterial, NULL, pShadowsList );
}
}
}
int CSprite::FillTailVertBuffer( SColorVert * pTailVerts,
const Vec3d & vCamVec,
const UCol & ucColor )
{
int nVertCount=0;
if (m_pArrvPosHistory && m_pParams->fTailLenght && (m_vDelta!=Vec3(0.0f,0.0f,0.0f)) )
{
int nPos = FtoI(m_fTrailCurPos);
// if(nPos==1)
// return 0;
// Vec3d vCamVec = PPP.pCamera->GetPos()-m_vPos;
// vCamVec.Normalize();
Vec3d vSideStep,vSideStepPrev,vDelta,vSideStepReal;
//Vec3d vSideStepPrev,vSideStepReal;
//float fMaxItSteps = min( (float)(PART_HISTORY_ELEMENTS-1), m_fTrailCurPos-1);
float fInvMaxItHalfSteps = 0.5f/m_nTailSteps;
float fTC0=0.5f;
Vec3 vPrev = m_vPos;
// fill vert buffer
for(int it=0; it < m_nTailSteps && nPos >= 0; it++)
{
Vec3 vPos = m_pArrvPosHistory[ nPos % m_nTailSteps ];
vDelta = vPrev-vPos;
if (vDelta.IsZero())
vDelta = m_vDelta;
vSideStep = m_fSize*vCamVec.Cross(GetNormalized(vDelta));
//if (it > 0)
//vSideStepReal = (vSideStep + vSideStepPrev)*0.5f; // Average.
//else
//vSideStepReal = vSideStep;
//vSideStepPrev = vSideStep;
vPrev = vPos;
pTailVerts[nVertCount].vert = vPos + vSideStep;
pTailVerts[nVertCount].dTC[0] = fTC0;
pTailVerts[nVertCount].dTC[1] = 0;
pTailVerts[nVertCount].color = ucColor;
nVertCount++;
pTailVerts[nVertCount].vert = vPos - vSideStep;
pTailVerts[nVertCount].dTC[0] = fTC0;
pTailVerts[nVertCount].dTC[1] = 1;
pTailVerts[nVertCount].color = ucColor;
nVertCount++;
nPos--;
fTC0+=fInvMaxItHalfSteps;
}
}
return nVertCount;
}

286
Cry3DEngine/rain.cpp Normal file
View File

@@ -0,0 +1,286 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: rain.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: draw rain volume
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "rain.h"
#include "partman.h"
#include "objman.h"
#define rn() ((((float)rand())/RAND_MAX)-0.5f)
CRainItem::CRainItem()
{
ZeroStruct(*this);
m_vPos.x = rn()*RAIN_RANGEx2;
m_vPos.y = rn()*RAIN_RANGEx2;
m_vPos.z = rn()*RAIN_RANGEx2;
m_fSize=2.0f;
}
bool CRainItem::IsPointInvalid(const Vec3d & pos)
{
return 0;
}
void CRainItem::Process(Vec3d &right, Vec3d &up, Vec3d &front, const int & nTexID, const Vec3d & delta,
IRenderer * pIRenderer, ITimer * pITimer, const Vec3d & vFocusPos,
CPartManager * pPartManager, CTerrain * pTerrain,
class CObjManager * pObjManager, const Vec3d & _vCamPos)
{
{ // space loop
float fOldZ = m_vPos.z;
if((m_vPos.x-vFocusPos.x)>RAIN_RANGE)
{
while((m_vPos.x-vFocusPos.x)>RAIN_RANGE)
m_vPos.x-=RAIN_RANGEx2;
if(IsPointInvalid(m_vPos))
m_vPos.x+=RAIN_RANGEx2;
}
if((vFocusPos.x-m_vPos.x)>RAIN_RANGE)
{
while((vFocusPos.x-m_vPos.x)>RAIN_RANGE)
m_vPos.x+=RAIN_RANGEx2;
if(IsPointInvalid(m_vPos))
m_vPos.x-=RAIN_RANGEx2;
}
if((m_vPos.y-vFocusPos.y)>RAIN_RANGE)
{
while((m_vPos.y-vFocusPos.y)>RAIN_RANGE)
m_vPos.y-=RAIN_RANGEx2;
if(IsPointInvalid(m_vPos))
m_vPos.y+=RAIN_RANGEx2;
}
if((vFocusPos.y-m_vPos.y)>RAIN_RANGE)
{
while((vFocusPos.y-m_vPos.y)>RAIN_RANGE)
m_vPos.y+=RAIN_RANGEx2;
if(IsPointInvalid(m_vPos))
m_vPos.y-=RAIN_RANGEx2;
}
if((m_vPos.z-vFocusPos.z)>RAIN_RANGE)
{
while((m_vPos.z-vFocusPos.z)>RAIN_RANGE)
m_vPos.z-=RAIN_RANGEx2;
if(IsPointInvalid(m_vPos))
m_vPos.z+=(RAIN_RANGEx2-rnd());
}
if((vFocusPos.z-m_vPos.z)>RAIN_RANGE)
{
while((vFocusPos.z-m_vPos.z)>RAIN_RANGE)
m_vPos.z+=(RAIN_RANGEx2-rnd());
if(IsPointInvalid(m_vPos))
m_vPos.z-=RAIN_RANGEx2;
}
if(m_vPos.z != fOldZ)
{
m_vPos.x += rn()*RAIN_RANGE;
m_vPos.y += rn()*RAIN_RANGE;
}
}
// draw
pIRenderer->PushMatrix();
pIRenderer->TranslateMatrix(m_vPos);
pIRenderer->DrawQuad(right*m_fSize, up*m_fSize, Vec3d(0,0,0));
pIRenderer->PopMatrix();
////////////////////////////////////////////////////////////////////////////////////////////////
// Move
////////////////////////////////////////////////////////////////////////////////////////////////
// process movement and size
m_vPos += delta*pITimer->GetFrameTime();
if(0 && fabs((m_vPos.z + m_fSize) - pTerrain->GetZSafe(m_vPos.x,m_vPos.y))<0.1f && delta.z<0)
{
Vec3d vCollPos = m_vPos;
vCollPos.z = pTerrain->GetZApr(m_vPos.x,m_vPos.y)+0.05f;
float fDist = (float)max(
fabs(vCollPos.x - _vCamPos.x),max(fabs(vCollPos.y - _vCamPos.y), fabs(vCollPos.z - _vCamPos.z)));
fDist/=RAIN_RANGE;
float fDistAlpha = 1.f-fDist;
fDistAlpha*=2;
if(fDistAlpha<0)
fDistAlpha=0;
if(fDistAlpha>1.f)
fDistAlpha=1.f;
ParticleParams params;
/* params.fFocus = 1.f;
params.fLifeTime = 0.25f;
params.fSize = 0.5f;
params.fSizeSpeed = 0;
params.fSpeed = 0;
params.nCount = 1;
params.eBlendType = ParticleBlendType_ColorBased;
params.nTexId = pIRenderer->LoadAnimatedTexture("ANIMATED\\raindrop\\rda%02d.tga",7);
params.nTexAnimFramesCount = 7;
float fAlpha = fDistAlpha*pObjManager->GetCVars()->e_rain_amount;
params.vColorStart.Set(fAlpha,fAlpha,fAlpha);
params.vColorEnd.Set(fAlpha,fAlpha,fAlpha);
params.vDirection.Set(0,0,1);
params.vPosition = vCollPos;
*/
params.fFocus = 1.5f;
params.fLifeTime = 0.5f;
params.fSize = 0.02f;
params.fSizeSpeed = 0;
params.fSpeed = 1.f;
params.vGravity(0,0,-5.f);
params.nCount = 15;
params.eBlendType = ParticleBlendType_ColorBased;
params.nTexId = pIRenderer->LoadTexture("cloud");
float fAlpha = fDistAlpha*pObjManager->GetCVars()->e_rain_amount;
params.vColorStart(fAlpha,fAlpha,fAlpha);
params.vColorEnd(fAlpha,fAlpha,fAlpha);
params.vDirection(0,0,1);
params.vPosition = vCollPos;
params.fTailLenght = 0.25;
if(fDistAlpha>0)
pPartManager->Spawn(params,RAIN_RANGE,pObjManager);
m_vPos.x += rn()*RAIN_RANGE;
m_vPos.y += rn()*RAIN_RANGE;
m_vPos.z -= 0.2f;
}
}
void CRainManager::Render(CTerrain * pTerrain,
const Vec3d & vColor,
CObjManager * pObjManager,
CPartManager * pPartManager,
const Vec3d & vWindDir)
{
if(!GetCVars()->e_rain_amount)
return;
// get orientation
Matrix44 mat;
GetRenderer()->GetModelViewMatrix(mat.GetData());
Vec3d right,up,front;
//CELL_CHANGED_BY_IVO
//right(mat.cell(0), mat.cell(4), mat.cell(8));
//up (mat.cell(1), mat.cell(5), mat.cell(9));
//front(mat.cell(2), mat.cell(6), mat.cell(10));
right = mat.GetColumn(0);
up = mat.GetColumn(1);
front = mat.GetColumn(2);
Vec3d vCamPos = GetViewCamera().GetPos();
//CELL_CHANGED_BY_IVO
//front(-mat.cell(2), -mat.cell(6), -mat.cell(10));
front = -mat.GetColumn(2);
front.Normalize();
Vec3d vFocusPos = vCamPos + front*RAIN_RANGE;
if(!m_nRainTexID)
m_nRainTexID = GetRenderer()->LoadTexture("textures\\sprites\\rain.tga");
GetRenderer()->SetTexture(m_nRainTexID);
GetRenderer()->SetState(GS_BLSRC_ONE | GS_BLDST_ONE);
GetRenderer()->SetColorOp(eCO_MODULATE, eCO_MODULATE, eCA_Texture|(eCA_Constant<<3), eCA_Texture|(eCA_Constant<<3));
GetRenderer()->SetCullMode(R_CULL_DISABLE);
GetRenderer()->SetMaterialColor( 1, 1, 1, GetCVars()->e_rain_amount );
Vec3d vUp = GetNormalized(-vWindDir);
// draw
for(int i=0; i<RAIN_COUNT; i++)
m_arrItems[i].Process(right,vUp,front,m_nRainTexID,vWindDir,
GetRenderer(),GetTimer(),vFocusPos,pPartManager,pTerrain,pObjManager,vCamPos);
m_fDropTime += GetTimer()->GetFrameTime();
const float fDropPeriod = max(0.002f, (1.f-GetCVars()->e_rain_amount)/50.f);
while(m_fDropTime>fDropPeriod)
{
m_fDropTime -= fDropPeriod;
Vec3d vCollPos( vFocusPos.x + rn()*RAIN_RANGE*2, vFocusPos.y + rn()*RAIN_RANGE*2, 0);
vCollPos.z = pTerrain->GetZApr(vCollPos.x,vCollPos.y)+0.05f;
float fDist = (float)max(
fabs(vCollPos.x - vCamPos.x),max(fabs(vCollPos.y - vCamPos.y), fabs(vCollPos.z - vCamPos.z)));
fDist/=RAIN_RANGE;
float fDistAlpha = 1.f-fDist;
fDistAlpha*=3;
if(fDistAlpha<0)
continue;
if(fDistAlpha>1.f)
fDistAlpha=1.f;
ParticleParams params;
/* params.fFocus = 1.f;
params.fLifeTime = 0.25f;
params.fSize = 0.5f;
params.fSizeSpeed = 0;
params.fSpeed = 0;
params.nCount = 1;
params.eBlendType = ParticleBlendType_ColorBased;
params.nTexId = pIRenderer->LoadAnimatedTexture("ANIMATED\\raindrop\\rda%02d.tga",7);
params.nTexAnimFramesCount = 7;
float fAlpha = fDistAlpha*pObjManager->GetCVars()->e_rain_amount;
params.vColorStart.Set(fAlpha,fAlpha,fAlpha);
params.vColorEnd.Set(fAlpha,fAlpha,fAlpha);
params.vDirection.Set(0,0,1);
params.vPosition = vCollPos;
*/
params.fFocus = 1.5f;
params.fLifeTime = 0.5f;
params.fSize = 0.02f;
params.fSizeSpeed = 0;
params.fSpeed = 1.f;
params.vGravity(0,0,-5.f);
params.nCount = 15;
params.eBlendType = ParticleBlendType_ColorBased;
params.nTexId = GetRenderer()->LoadTexture("cloud");
float fAlpha = fDistAlpha*GetCVars()->e_rain_amount;
// params.vColorStart.Set(fAlpha,fAlpha,fAlpha);
// params.vColorEnd.Set(fAlpha,fAlpha,fAlpha);
params.vColorStart = Get3DEngine()->GetFogColor()*fAlpha;
params.vColorEnd = Get3DEngine()->GetFogColor()*fAlpha;
params.vDirection(0,0,1);
params.vPosition = vCollPos;
// params.fTailLenght = 1.f;
if(fAlpha>0.125)
pPartManager->Spawn(params,RAIN_RANGE,pObjManager);
}
}

58
Cry3DEngine/rain.h Normal file
View File

@@ -0,0 +1,58 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: rain.h
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#ifndef RAIN_MANAGER
#define RAIN_MANAGER
#define RAIN_COUNT 512
const float RAIN_RANGE = 8;
const float RAIN_RANGEx2 = RAIN_RANGE*2;
class CPartManager;
class CRainItem
{
public:
// cur state
Vec3d m_vPos;
float m_fSize;
CRainItem();
void Process(Vec3d &right, Vec3d &up, Vec3d &front, const int & nTexID, const Vec3d & delta,
IRenderer * pIRenderer, ITimer * pITimer, const Vec3d & vFocusPos,
CPartManager * pPartManager, CTerrain * pTerrain, class CObjManager * pObjManager, const Vec3d & vCamPos );
bool IsPointInvalid(const Vec3d & pos);
};
class CRainManager : public Cry3DEngineBase
{
CRainItem m_arrItems[RAIN_COUNT];
int m_nCurItem;
int m_nRainTexID;
float m_fDropTime;
public:
CRainManager()
{
m_nCurItem = 0;
m_nRainTexID = 0;
m_fDropTime = 0;
}
void Render(class CTerrain * pTerrain, const Vec3d & vColor, class CObjManager * pObjManager, class CPartManager * pPartManager, const Vec3d & vWindDir);
};
#endif // RAIN_MANAGER

780
Cry3DEngine/terrain.cpp Normal file
View File

@@ -0,0 +1,780 @@
////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: terrain.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: check vis
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "terrain_sector.h"
#include "StatObj.h"
#include "objman.h"
#include "cbuffer.h"
#include "terrain_water.h"
#include "detail_grass.h"
#include "VisAreas.h"
void CTerrain::PreCacheArea(const Vec3d & vPos, float fRadius)
{
// if(!m_pObjManager)
return;
#ifndef _DEBUG
#if !defined(_XBOX) && !defined(LINUX)
assert(GetConsole()->Exit("Assert should do nothing in release mode")); // just check
#endif // _XBOX
#endif // DEBUG
m_nUploadsInFrame = -10000;
GetLog()->UpdateLoadingScreen("Preloading terrain textures for (%.1f, %.1f, %.1f) ...",
vPos.x,vPos.y,vPos.z);
int nLoaded=0;
for( int x=0; x<CTerrain::GetSectorsTableSize(); x++)
for( int y=0; y<CTerrain::GetSectorsTableSize(); y++)
{
m_arrSecInfoTable[x][y]->m_fDistance =
GetDist2D(
float(m_arrSecInfoTable[x][y]->m_nOriginX+(CTerrain::GetSectorSize()>>1)),
float(m_arrSecInfoTable[x][y]->m_nOriginY+(CTerrain::GetSectorSize()>>1)),
vPos.x, vPos.y ) - (CTerrain::GetSectorSize()>>1);
if(m_arrSecInfoTable[x][y]->m_fDistance < fRadius)
{
m_arrSecInfoTable[x][y]->SetLOD();
if(IsSectorNonMergable(m_arrSecInfoTable[x][y]))
{
m_arrSecInfoTable[x][y]->SetTextures();
nLoaded++;
}
m_arrSecInfoTable[x][y]->m_cLastTimeUsed = fastftol_positive(GetCurTimeSec()) + 20;
}
}
GetLog()->LogPlus(" %d sectors loaded", nLoaded);
m_nUploadsInFrame = 0;
}
int CTerrain::GetSecMML(int x, int y)
{
assert(x/CTerrain::GetSectorSize()>=0);
assert(y/CTerrain::GetSectorSize()>=0);
assert(x/CTerrain::GetSectorSize()<CTerrain::GetSectorsTableSize());
assert(y/CTerrain::GetSectorSize()<CTerrain::GetSectorsTableSize());
CSectorInfo * info = m_arrSecInfoTable[x/CTerrain::GetSectorSize()][y/CTerrain::GetSectorSize()];
return info->m_cGeometryMML;
}
void CTerrain::AddVisSetcor(CSectorInfo * newsec)
{
m_lstVisSectors.Add(newsec);
}
void CTerrain::LinkVisSetcors()
{
for(int i=0; i<m_lstVisSectors.Count(); i++)
{
CSectorInfo * info = (CSectorInfo*)m_lstVisSectors[i];
int sx1 = info->m_nOriginX/CTerrain::GetSectorSize();
int sy1 = info->m_nOriginY/CTerrain::GetSectorSize();
if(sx1+1<CTerrain::GetSectorsTableSize())
m_arrSecInfoTable[sx1+1][sy1]->CheckGeomCompWithLOD(info->m_cGeometryMML);
if(sy1+1<CTerrain::GetSectorsTableSize())
m_arrSecInfoTable[sx1][sy1+1]->CheckGeomCompWithLOD(info->m_cGeometryMML);
if(sx1>0)
m_arrSecInfoTable[sx1-1][sy1]->CheckGeomCompWithLOD(info->m_cGeometryMML);
if(sy1>0)
m_arrSecInfoTable[sx1][sy1-1]->CheckGeomCompWithLOD(info->m_cGeometryMML);
}
}
void CTerrain::RenderTerrain( CObjManager * pObjManager, const int & DrawFlags )
{
FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE );
m_pObjManager = pObjManager;
// precache tarrain data if camera was teleported more than 32 meters
if(m_nRenderStackLevel==0)
{
if(GetDistance(m_vPrevCameraPos, GetViewCamera().GetPos()) > 32)
PreCacheArea(GetViewCamera().GetPos(), GetViewCamera().GetZMax()*1.5f);
m_vPrevCameraPos = GetViewCamera().GetPos();
}
if(m_nRenderStackLevel==0)
m_fDistanceToSectorWithWater=-1;
m_ucTerrainFrame++;
m_lstVisSectors.Clear();
if(!m_nRenderStackLevel)
m_lstReflectedTerrainIdxArray.Clear();
m_pObjManager->m_lstFarObjects[m_nRenderStackLevel].Clear();
m_vCameraPos = m_pViewCamera->GetPos();
RefineSector(0, CTerrain::GetTerrainSize(), 0, CTerrain::GetTerrainSize(), 0);
LinkVisSetcors();
if(m_nRenderStackLevel==0)
{
m_bOceanIsVisibe = m_fDistanceToSectorWithWater > -1 || !m_lstVisSectors.Count();
m_fDistanceToSectorWithWater-=CTerrain::GetSectorSize()*0.5f;
if(m_fDistanceToSectorWithWater<1.0f)
m_fDistanceToSectorWithWater=1.0f;
if(!m_lstVisSectors.Count())
m_fDistanceToSectorWithWater=0;
m_fDistanceToSectorWithWater = max(m_fDistanceToSectorWithWater, (m_pViewCamera->GetPos().z-m_fGlobalWaterLevel)*0.05f);
}
if(m_pDetailObjects)
if(DrawFlags & DLD_DETAIL_OBJECTS)
m_pDetailObjects->RenderDetailGrass(this);
}
void CSectorInfo :: CheckGeomCompWithLOD(int minMML)
{
if(m_cLastFrameUsed == m_pTerrain->m_ucTerrainFrame)
if(m_cGeometryMML < 100)
if(m_cGeometryMML>minMML+1)
{
m_cGeometryMML = minMML+1;
int sx1 = m_nOriginX/CTerrain::GetSectorSize();
int sy1 = m_nOriginY/CTerrain::GetSectorSize();
if(sx1+1<CTerrain::GetSectorsTableSize())
m_pTerrain->m_arrSecInfoTable[sx1+1][sy1]->CheckGeomCompWithLOD(m_cGeometryMML);
if(sy1+1<CTerrain::GetSectorsTableSize())
m_pTerrain->m_arrSecInfoTable[sx1][sy1+1]->CheckGeomCompWithLOD(m_cGeometryMML);
if(sx1>0)
m_pTerrain->m_arrSecInfoTable[sx1-1][sy1]->CheckGeomCompWithLOD(m_cGeometryMML);
if(sy1>0)
m_pTerrain->m_arrSecInfoTable[sx1][sy1-1]->CheckGeomCompWithLOD(m_cGeometryMML);
}
}
// todo: use real quadtree here
void CTerrain::RefineSector(int x1, int x2, int y1, int y2, bool bAllIN)
{
FUNCTION_PROFILER_FAST( GetSystem(),PROFILE_3DENGINE,m_bProfilerEnabled );
int xm = (x1+x2)>>1;
int ym = (y1+y2)>>1;
if((x2-x1) > CTerrain::GetSectorSize())
{
Vec3d bmin((float)x1-TERRAIN_SECTORS_MAX_OVERLAPPING, (float)y1-TERRAIN_SECTORS_MAX_OVERLAPPING,-256.f);
Vec3d bmax((float)x2+TERRAIN_SECTORS_MAX_OVERLAPPING, (float)y2+TERRAIN_SECTORS_MAX_OVERLAPPING, 512.f);
if( bAllIN || m_pViewCamera->IsAABBVisible_hierarchical(AABB(bmin,bmax),&bAllIN) )
{
if(m_vCameraPos.x < xm)
{
if(m_vCameraPos.y < ym)
{
RefineSector(x1, xm, y1, ym, bAllIN );
RefineSector(xm, x2, y1, ym, bAllIN );
RefineSector(x1, xm, ym, y2, bAllIN );
RefineSector(xm, x2, ym, y2, bAllIN );
}
else
{
RefineSector(x1, xm, ym, y2, bAllIN );
RefineSector(xm, x2, ym, y2, bAllIN );
RefineSector(x1, xm, y1, ym, bAllIN );
RefineSector(xm, x2, y1, ym, bAllIN );
}
}
else
{
if(m_vCameraPos.y < ym)
{
RefineSector(xm, x2, y1, ym, bAllIN );
RefineSector(xm, x2, ym, y2, bAllIN );
RefineSector(x1, xm, y1, ym, bAllIN );
RefineSector(x1, xm, ym, y2, bAllIN );
}
else
{
RefineSector(xm, x2, ym, y2, bAllIN );
RefineSector(xm, x2, y1, ym, bAllIN );
RefineSector(x1, xm, ym, y2, bAllIN );
RefineSector(x1, xm, y1, ym, bAllIN );
}
}
}
}
else
{
CSectorInfo * info = m_arrSecInfoTable[x1/CTerrain::GetSectorSize()][y1/CTerrain::GetSectorSize()];
// test higher bbox to include all flying dynamic stuff and reflected in water terrain
if(!m_pViewCamera->IsAABBVisible_hierarchical(
AABB(
Vec3d((float)x1-TERRAIN_SECTORS_MAX_OVERLAPPING,(float)y1-TERRAIN_SECTORS_MAX_OVERLAPPING,0),
Vec3d((float)x2+TERRAIN_SECTORS_MAX_OVERLAPPING,(float)y2+TERRAIN_SECTORS_MAX_OVERLAPPING,512.f)),
&info->m_bAllStaticsInFrustum))
return;
// debug: render this sector only
if(GetCVars()->e_terrain_draw_this_sector_only)
if(GetSecInfo(GetViewCamera().GetPos()) != info)
return;
// if(info->m_nOriginX != 1344 || info->m_nOriginY!=1344)
// return;
if(!m_nRenderStackLevel) // for reflections
info->MergeSectorIntoLowResTerrain(false);
// draw dynamic objects
info->RenderEntities(m_pObjManager, !info->m_bAllStaticsInFrustum, "", DYNAMIC_ENTITIES);
// test exact bbox of sector, it includes all static geometry
if(!m_pViewCamera->IsAABBVisible_hierarchical( AABB(info->m_vBoxMin,info->m_vBoxMax), &info->m_bAllStaticsInFrustum))
return;
// test ground visibility
if(info->m_bAllStaticsInFrustum)
info->m_bGroundVisible = true;
else
{
float fOrgX = float(info->m_nOriginX);
float fOrgY = float(info->m_nOriginY);
info->m_bGroundVisible = m_pViewCamera->IsAABBVisibleFast( AABB(Vec3d(fOrgX,fOrgY,info->m_fMinZ), Vec3d(fOrgX+CTerrain::GetSectorSize(),fOrgY+CTerrain::GetSectorSize(),max(info->m_fMaxZ,m_fGlobalWaterLevel))));
}
// calc distance
info->m_fDistance = GetDist2D( (float)xm, (float)ym, m_vCameraPos.x, m_vCameraPos.y ) - (CTerrain::GetSectorSize()>>1)*1.3333f;
if(info->m_fDistance > m_pViewCamera->GetZMax())
return;
if(info->m_fDistance<1)
info->m_fDistance=1;
/*
if( info->m_fDistance>128 && info->m_vBoxMax.z <= m_fGlobalWaterLevel &&
m_vCameraPos.z > m_fGlobalWaterLevel+1 && m_bCullUnderwaterTerrain && m_fGlobalWaterLevel)
return; */
// occlusion test (affects only static objects)
if(GetCVars()->e_terrain_occlusion_culling)
if(m_pObjManager->IsBoxOccluded(info->m_vBoxMin,info->m_vBoxMax,info->m_fDistance, &info->m_OcclusionTestClient))
return;
// test occl by antiportals
if(GetVisAreaManager() && GetVisAreaManager()->IsOccludedByOcclVolumes(info->m_vBoxMin,info->m_vBoxMax))
return;
if(m_nRenderStackLevel==0)
info->m_cLastFrameUsed = m_ucTerrainFrame;
if( info->m_bGroundVisible || info->m_fDistance<4 )
info->SetLOD();
// else
// info->m_cGeometryMML = MAX_MML_LEVEL;
// update distance to the ocean
if(m_nRenderStackLevel==0)
{
if(info->m_bGroundVisible)
if(info->m_fMinZ<m_fGlobalWaterLevel)
if(m_fDistanceToSectorWithWater == -1)
m_fDistanceToSectorWithWater = info->m_fDistance;
}
AddVisSetcor(info);
// render static objects
if(info)
info->RenderEntities(m_pObjManager, !info->m_bAllStaticsInFrustum, "", STATIC_ENTITIES);
}
}
void CTerrain::UnloadOldSectors(float fMaxViewDist)
{
FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE );
static int nStaticLoadedTexturesNum[2]={0,0};
int cCurTimeSec = fastftol_positive(GetCurTimeSec());
/////////////////////////////////////////////////////////////////////////////////////
// x/y cycle
/////////////////////////////////////////////////////////////////////////////////////
for(int t=0; t<16; t++)
{
m_nOldSectorsY++;
if(m_nOldSectorsY>=CTerrain::GetSectorsTableSize())
{
m_nOldSectorsY=0;
m_nOldSectorsX++;
if(m_nOldSectorsX>=CTerrain::GetSectorsTableSize())
{
m_nOldSectorsY=m_nOldSectorsX=0;
m_arrLoadedTexturesNum[0] = nStaticLoadedTexturesNum[0];
m_arrLoadedTexturesNum[1] = nStaticLoadedTexturesNum[1];
nStaticLoadedTexturesNum[0] = nStaticLoadedTexturesNum[1]=0;
}
}
/////////////////////////////////////////////////////////////////////////////////////
{
CSectorInfo * info = m_arrSecInfoTable[m_nOldSectorsX][m_nOldSectorsY];
if(info->m_bLockTexture)
return; // do not unload locked texture
if(info->m_nTextureID && info->m_nTextureID != info->m_nLowLodTextureID)
nStaticLoadedTexturesNum[0]++;
if(info->m_nLowLodTextureID)
nStaticLoadedTexturesNum[1]++;
float fDistanse = GetDist2D(
(float)info->m_nOriginX+(CTerrain::GetSectorSize()>>1),
(float)info->m_nOriginY+(CTerrain::GetSectorSize()>>1),
m_pViewCamera->GetPos().x, m_pViewCamera->GetPos().y ) - (CTerrain::GetSectorSize()>>1);
if((fDistanse > (1.5f*fMaxViewDist)) || (info->m_cLastTimeUsed < (cCurTimeSec - 4)))
{ // try to release vert buffer if not in use int time
info->ReleaseHeightMapVertBuffer();
// release static shadow vertex buffers
// info->ReleaseStaticShadowVertexBuffers();
// if(GetCVars()->e_terrain_log)
// GetLog()->Log("buffer unloaded %d", info->GetSecIndex());
}
if(GetCVars()->e_terrain_debug==3 || !GetCVars()->e_terrain_texture_pool)
{
if( fDistanse > (1.5f*fMaxViewDist) || (info->m_cLastTimeUsed < (cCurTimeSec - 8)))
{
info->UnloadHeighFieldTexture(fDistanse, fMaxViewDist);
}
}
}
}
}
int CTerrain::RenderEntitiesOutOfTheMap(CObjManager * pObjManager)
{
FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE );
if(!GetCVars()->e_objects || GetCVars()->e_terrain_draw_this_sector_only == 2)
return 0;
// this sector used also for entities outside of the map and for draw near objects
m_arrSecInfoTable[0][0]->RenderEntities(pObjManager, true, "", STATIC_ENTITIES);
m_arrSecInfoTable[0][0]->RenderEntities(pObjManager, true, "", DYNAMIC_ENTITIES);
return 0;
}
int CTerrain::RenderTerrainWater(bool bRenderShore)
{
FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE );
if(!GetCVars()->e_water_ocean)
return 0;
m_pWater->Render(m_nRenderStackLevel);
float fCamZ = GetViewCamera().GetPos().z;
if(fCamZ>m_fGlobalWaterLevel)
if(bRenderShore && m_pSHShore && !m_nRenderStackLevel && GetCVars()->e_beach)
{
float fZoomFactor = 0.1f+0.9f*(RAD2DEG(GetViewCamera().GetFov())/90.f);
for( int i=0; i<m_lstVisSectors.Count(); i++ )
m_lstVisSectors[i]->RenderBeach(m_pSHShore, fZoomFactor, fCamZ);
}
return 0;
}
CSectorInfo * CTerrain::GetSectorFromPoint(int _x, int _y)
{
int x = _x/CTerrain::GetSectorSize();
int y = _y/CTerrain::GetSectorSize();
if( x>=0 && y>=0 && x<CTerrain::GetSectorsTableSize() && y<CTerrain::GetSectorsTableSize() )
return (m_arrSecInfoTable)[x][y];
return 0;
}
void CTerrain::ResetDLightMaskInSectors()
{
CSectorInfo ** p = &m_arrSecInfoTable[0][0];
CSectorInfo ** pEnd = &m_arrSecInfoTable[CTerrain::GetSectorsTableSize()-1][CTerrain::GetSectorsTableSize()-1];
while(p <= pEnd)
{
register CSectorInfo *pSector = *p;
pSector->m_nDynLightMaskNoSun = 0;
pSector->m_nDynLightMask = 0;
++p;
}
}
void CTerrain::ApplyForceToEnvironment(Vec3d vPos, float fRadius, float fAmountOfForce)
{
if(fRadius<=0)
return;
if(!_finite(vPos.x) || !_finite(vPos.y) || !_finite(vPos.z))
{
GetLog()->Log("Error: 3DEngine::ApplyForceToEnvironment: Undefined position passed to the function");
return;
}
if (fRadius > 50.f)
fRadius = 50.f;
if(fAmountOfForce>1.f)
fAmountOfForce = 1.f;
if( (GetDistance(vPos,m_pViewCamera->GetPos()) > 50.f+fRadius*2.f ) || // too far
vPos.z < (GetZApr(vPos.x, vPos.y)-1.f)) // under ground
return;
/*
int min_x = (int)(((vPos.x-fRadius)/CTerrain::GetSectorSize()))-1;
int min_y = (int)(((vPos.y-fRadius)/CTerrain::GetSectorSize()))-1;
int max_x = (int)(((vPos.x+fRadius)/CTerrain::GetSectorSize()))+1;
int max_y = (int)(((vPos.y+fRadius)/CTerrain::GetSectorSize()))+1;
if(min_x<0)
min_x=0;
if(min_y<0)
min_y=0;
if(max_x>=CTerrain::GetSectorsTableSize())
max_x = CTerrain::GetSectorsTableSize()-1;
if(max_y>=CTerrain::GetSectorsTableSize())
max_y = CTerrain::GetSectorsTableSize()-1;
for(int x=min_x; x<=max_x; x++)
for(int y=min_y; y<=max_y; y++)
{
list2<IEntityRender*> * pList = &m_arrSecInfoTable[x][y]->m_lstEntities[STATIC_ENTITIES];
for(int s=0; s<pList->Count(); s++)
if(pList->GetAt(s)->GetEntityRenderType()==eERType_Vegetation)
{
CStatObjInst * pEnt = (CStatObjInst *)pList->GetAt(s);
float fDist = GetDist2D(pEnt->GetPos(true).x,pEnt->GetPos(true).y, vPos.x,vPos.y);
if(fDist<fRadius)
{
pEnt->m_fCurrentBending = (1.f - fDist/fRadius)*fAmountOfForce*0.25;
pEnt->m_fCurrentBending=pEnt->m_fCurrentBending;
}
}
}*/
// calc area
int x1=int(vPos.x-fRadius-CTerrain::GetHeightMapUnitSize());
int y1=int(vPos.y-fRadius-CTerrain::GetHeightMapUnitSize());
int x2=int(vPos.x+fRadius+CTerrain::GetHeightMapUnitSize());
int y2=int(vPos.y+fRadius+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;
// 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);
}
// affect 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++)
if(pSecInfo->m_lstEntities[STATIC_ENTITIES][i]->GetEntityRenderType() == eERType_Vegetation)
{
CStatObjInst * pStatObjInst = (CStatObjInst*)pSecInfo->m_lstEntities[STATIC_ENTITIES][i];
float fDist = GetDist2D(pStatObjInst->GetPos(true).x,pStatObjInst->GetPos(true).y, vPos.x,vPos.y);
if(fDist<fRadius)
{
float fNewBending = (1.f - fDist/fRadius)*fAmountOfForce;
if(fNewBending > pStatObjInst->m_fCurrentBending)
pStatObjInst->m_fCurrentBending = fNewBending;
}
}
}
}
Vec3d CTerrain::GetTerrainSurfaceNormal(Vec3d vPos)
{
Vec3d v1 = Vec3d(vPos.x-0.5f, vPos.y-0.5f, GetZApr(vPos.x-0.5f,vPos.y-0.5f));
Vec3d v2 = Vec3d(vPos.x+0.5f, vPos.y, GetZApr(vPos.x+0.5f,vPos.y ));
Vec3d v3 = Vec3d(vPos.x, vPos.y+0.5f, GetZApr(vPos.x, vPos.y+0.5f));
return (v2-v1).Cross(v3-v1);
}
bool CTerrain::UnRegisterInAllSectors(IEntityRender * pEntityRS)
{
assert(pEntityRS);
bool bRes = 0;
if(pEntityRS)
{
int nStatic = (pEntityRS->GetEntityRenderType() != eERType_Unknown);
for( int x=0; x<CTerrain::GetSectorsTableSize(); x++ )
for( int y=0; y<CTerrain::GetSectorsTableSize(); y++ )
if(m_arrSecInfoTable[x][y])
bRes |= m_arrSecInfoTable[x][y]->m_lstEntities[nStatic].Delete(pEntityRS);
pEntityRS->m_pSector = 0;
}
return bRes;
}
ushort * CTerrain::GetUnderWaterSmoothHMap(int & nDimensions)
{
nDimensions = m_arrusUnderWaterSmoothHMap.m_nSize;
return m_arrusUnderWaterSmoothHMap.m_pData;
}
void CTerrain::GetMemoryUsage( class ICrySizer*pSizer)
{
{
SIZER_COMPONENT_NAME(pSizer, "HMap");
GetHighMapMemoryUsage(pSizer);
}
{
SIZER_COMPONENT_NAME(pSizer, "SecInfoTable");
m_arrSecInfoTable.GetMemoryUsage(pSizer);
}
{
SIZER_COMPONENT_NAME(pSizer, "SectorsData");
for( int x=0; x<CTerrain::GetSectorsTableSize(); x++)
for( int y=0; y<CTerrain::GetSectorsTableSize(); y++)
m_arrSecInfoTable[x][y]->GetMemoryUsage(pSizer);
}
int nSize = 0;
m_arrusUnderWaterSmoothHMap.GetMemoryUsage(pSizer);
nSize += m_lstFogVolumes.GetMemoryUsage();
nSize += m_lstLowResTerrainIdxArray.GetMemoryUsage();
nSize += m_lstReflectedTerrainIdxArray.GetMemoryUsage();
nSize += m_lstSectorVertArray.GetMemoryUsage();
nSize += m_lstVisSectors.GetMemoryUsage();
// nSize += m_pBugsManager->GetMemoryUsage();
if(m_pCoverageBuffer)
nSize += sizeof(*m_pCoverageBuffer);
if(m_pDetailObjects)
nSize += sizeof(*m_pDetailObjects) + m_pDetailObjects->GetMemoryUsage();
if(m_pTexturePool)
m_pTexturePool->GetMemoryUsage(pSizer);
if(m_pWater)
nSize += sizeof(*m_pWater) + m_pWater->GetMemoryUsage();
nSize += m_nSectorTextureDataSizeBytes;
pSizer->AddObject(this, nSize + sizeof(*this));
}
void CTexturePool::TexInfo::GetSize (ICrySizer*pSizer)const
{
pSizer->Add (*this);
pSectorInfo->GetMemoryUsage (pSizer);
}
void CTexturePool::GetMemoryUsage(class ICrySizer*pSizer)
{
for (int i = 0; i < sizeof(m_TexturePool)/sizeof(m_TexturePool[0]); ++i)
{
list2<TexInfo>& arrTexInfo = m_TexturePool[i];
for (unsigned j = 0; j < arrTexInfo.size(); ++j)
arrTexInfo[j].GetSize (pSizer);
}
}
void CTerrain::UnregisterFogVolumeFromOutdoor(VolumeInfo * pFogVolume)
{
// reset fog volume pointer in all affected terrain sectors
for(int x=0; x<CTerrain::GetSectorsTableSize(); x++)
for(int y=0; y<CTerrain::GetSectorsTableSize(); y++)
{
CSectorInfo * pSecInfo = m_arrSecInfoTable[x][y];
if(pSecInfo && pSecInfo->m_pFogVolume == pFogVolume)
{
pSecInfo->m_pFogVolume = 0;
SetSectorFogVolume(pSecInfo);
}
}
}
void CTerrain::MoveAllEntitiesIntoList(list2<IEntityRender*> * plstVisAreasEntities,
const Vec3d & vBoxMin, const Vec3d & vBoxMax)
{
// gat 2d bounds
int min_x = (int)(((vBoxMin.x - 1.f)/CTerrain::GetSectorSize()));
int min_y = (int)(((vBoxMin.y - 1.f)/CTerrain::GetSectorSize()));
int max_x = (int)(((vBoxMax.x + 1.f)/CTerrain::GetSectorSize()));
int max_y = (int)(((vBoxMax.y + 1.f)/CTerrain::GetSectorSize()));
if( min_x<0 ) min_x = 0; else if( min_x>=CTerrain::GetSectorsTableSize() ) min_x = CTerrain::GetSectorsTableSize()-1;
if( min_y<0 ) min_y = 0; else if( min_y>=CTerrain::GetSectorsTableSize() ) min_y = CTerrain::GetSectorsTableSize()-1;
if( max_x<0 ) max_x = 0; else if( max_x>=CTerrain::GetSectorsTableSize() ) max_x = CTerrain::GetSectorsTableSize()-1;
if( max_y<0 ) max_y = 0; else if( max_y>=CTerrain::GetSectorsTableSize() ) max_y = CTerrain::GetSectorsTableSize()-1;
// make list of sectors
list2<CSectorInfo*> TerrainSectorsList;
for(int x=min_x; x<=max_x; x++)
for(int y=min_y; y<=max_y; y++)
TerrainSectorsList.Add(m_arrSecInfoTable[x][y]);
// this sector contains fps weapons and entities from outside of the map
TerrainSectorsList.Add(m_arrSecInfoTable[0][0]);
// add lists of entities where not added
for(int i=0; i<TerrainSectorsList.Count(); i++)
{
// note: lstEntitiesInArea will have duplicates but it's not a problem
plstVisAreasEntities->AddList(TerrainSectorsList.GetAt(i)->m_lstEntities[DYNAMIC_ENTITIES]);
plstVisAreasEntities->AddList(TerrainSectorsList.GetAt(i)->m_lstEntities[STATIC_ENTITIES]);
TerrainSectorsList.GetAt(i)->m_lstEntities[STATIC_ENTITIES].Clear();
TerrainSectorsList.GetAt(i)->m_lstEntities[DYNAMIC_ENTITIES].Clear();
}
// remove duplicates
for(int i=0; i<plstVisAreasEntities->Count(); i++)
{
IEntityRender * pEnt = plstVisAreasEntities->GetAt(0);
plstVisAreasEntities->Delete(pEnt);
plstVisAreasEntities->Add(pEnt);
}
}
bool CTerrain::PreloadResources()
{
FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE );
static int nCurTexPreloadX=0, nCurTexPreloadY=0;
nCurTexPreloadX++;
if(nCurTexPreloadX>=CTerrain::GetSectorsTableSize())
{
nCurTexPreloadX=0;
nCurTexPreloadY++;
}
if(nCurTexPreloadY>=CTerrain::GetSectorsTableSize())
{
nCurTexPreloadY = 0;
DrawDetailTextures(32, 64, false);
if(m_pDetailObjects)
m_pDetailObjects->PreloadResources();
}
assert(nCurTexPreloadX>=0 && nCurTexPreloadX<CTerrain::GetSectorsTableSize());
assert(nCurTexPreloadY>=0 && nCurTexPreloadY<CTerrain::GetSectorsTableSize());
CSectorInfo * pSecInfo = m_arrSecInfoTable[nCurTexPreloadX][nCurTexPreloadY];
if(pSecInfo)
{
pSecInfo->m_fDistance =
GetDist2D( float(pSecInfo->m_nOriginX+(CTerrain::GetSectorSize()>>1)),
float(pSecInfo->m_nOriginY+(CTerrain::GetSectorSize()>>1)),
m_vCameraPos.x, m_vCameraPos.y ) - (CTerrain::GetSectorSize()>>1);
pSecInfo->SetLOD();
if(pSecInfo->m_fDistance<GetViewCamera().GetZMax()*2)
{
pSecInfo->SetTextures();
//CCObject * pTerrainCCObject = GetRenderer()->EF_GetObject(true);
//pSecInfo->RenderSector(pTerrainCCObject);
pSecInfo->PreloadResources(GetViewCamera().GetPos(), 0);
pSecInfo->m_cLastTimeUsed = fastftol_positive( GetCurTimeSec() );
}
}
return !nCurTexPreloadX && !nCurTexPreloadY;
}
void CTerrain::GetObjects(list2<struct IEntityRender*> * pLstObjects)
{
// reset fog volume pointer in all affected terrain sectors
for(int x=0; x<CTerrain::GetSectorsTableSize(); x++)
for(int y=0; y<CTerrain::GetSectorsTableSize(); y++)
{
CBasicArea * pSecInfo = m_arrSecInfoTable[x][y];
for(int nStatic=0; nStatic<2; nStatic++)
{
if(pLstObjects)
pLstObjects->AddList(pSecInfo->m_lstEntities[nStatic]);
pSecInfo->m_lstEntities[nStatic].Reset();
}
}
}
const void * CTerrain::GetShoreGeometry(int & nPosStride, int & nVertCount, int nSectorX, int nSectorY)
{
CSectorInfo * pSecInfo = GetSecInfo(nSectorX, nSectorY);
if(!pSecInfo)
return 0;
return pSecInfo->GetShoreGeometry(nPosStride, nVertCount);
}

Some files were not shown because too many files have changed in this diff Show More