client/EterGrnLib/LODController.cpp

696 lines
17 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "StdAfx.h"
#include "LODController.h"
static float LODHEIGHT_ACTOR = 500.0f;
static float LODDISTANCE_ACTOR = 5000.0f;
static float LODDISTANCE_BUILDING = 25000.0f;
static const float c_fNearLodScale = 3.0f;
static const float c_fFarLodScale = 25.0f;
static const float LOD_APPLY_MAX = 2000.0f;
static const float LOD_APPLY_MIN = 500.0f;
bool ms_isMinLODModeEnable=false;
enum
{
SHARED_VB_500 = 0,
SHARED_VB_1000 = 1,
SHARED_VB_1500 = 2,
SHARED_VB_2000 = 3,
SHARED_VB_2500 = 4,
SHARED_VB_3000 = 5,
SHARED_VB_3500 = 6,
SHARED_VB_4000 = 7,
SHARED_VB_NUM = 9,
};
static std::vector<CGraphicVertexBuffer*> gs_vbs[SHARED_VB_NUM];
static CGraphicVertexBuffer gs_emptyVB;
#include <time.h>
static CGraphicVertexBuffer* __AllocDeformVertexBuffer(unsigned deformableVertexCount)
{
if (deformableVertexCount == 0)
return &gs_emptyVB;
unsigned capacity = (((deformableVertexCount-1) / 500) + 1) * 500;
unsigned index = (deformableVertexCount-1) / 500;
if (index < SHARED_VB_NUM)
{
std::vector<CGraphicVertexBuffer*>& vbs = gs_vbs[index];
if (!vbs.empty())
{
//TraceError("REUSE %d(%d)", capacity, deformableVertexCount);
CGraphicVertexBuffer* pkRetVB = vbs.back();
vbs.pop_back();
return pkRetVB;
}
}
static time_t base = time(NULL);
//TraceError("NEW %8d: %d(%d)", time(NULL) - base, capacity, deformableVertexCount);
CGraphicVertexBuffer* pkNewVB = new CGraphicVertexBuffer;
if (!pkNewVB->Create(
capacity,
D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1,
D3DUSAGE_WRITEONLY,
D3DPOOL_MANAGED))
{
TraceError("NEW_ERROR %8d: %d(%d)", time(NULL) - base, capacity, deformableVertexCount);
}
return pkNewVB;
}
void __FreeDeformVertexBuffer(CGraphicVertexBuffer* pkDelVB)
{
if (pkDelVB)
{
if (pkDelVB == &gs_emptyVB)
return;
unsigned index = (pkDelVB->GetVertexCount() - 1) / 500;
if (index < SHARED_VB_NUM)
{
gs_vbs[index].push_back(pkDelVB);
}
else
{
pkDelVB->Destroy();
delete pkDelVB;
}
}
}
void __ReserveSharedVertexBuffers(unsigned index, unsigned count)
{
NANOBEGIN
if (index >= SHARED_VB_NUM)
return;
unsigned capacity = (index + 1) * 500;
for (unsigned i = 0; i != count; ++i)
{
CGraphicVertexBuffer* pkNewVB = new CGraphicVertexBuffer;
pkNewVB->Create(
capacity,
D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1,
D3DUSAGE_WRITEONLY,
D3DPOOL_MANAGED);
gs_vbs[index].push_back(pkNewVB);
}
NANOEND
}
void GrannyCreateSharedDeformBuffer()
{
__ReserveSharedVertexBuffers(SHARED_VB_500, 40);
__ReserveSharedVertexBuffers(SHARED_VB_1000, 20);
__ReserveSharedVertexBuffers(SHARED_VB_1500, 20);
__ReserveSharedVertexBuffers(SHARED_VB_2000, 40);
__ReserveSharedVertexBuffers(SHARED_VB_3000, 20);
}
void GrannyDestroySharedDeformBuffer()
{
#ifdef _DEBUG
TraceError("granny_shared_vbs:");
#endif
for (int i = 0; i != SHARED_VB_NUM; ++i)
{
std::vector<CGraphicVertexBuffer*>& vbs = gs_vbs[i];
#ifdef _DEBUG
TraceError("\t%d: %d", i, vbs.size());
#endif
std::vector<CGraphicVertexBuffer*>::iterator v;
for (v = vbs.begin(); v != vbs.end(); ++v)
{
CGraphicVertexBuffer* pkEachVB = (*v);
pkEachVB->Destroy();
delete pkEachVB;
}
vbs.clear();
}
}
void CGrannyLODController::SetMinLODMode(bool isEnable)
{
ms_isMinLODModeEnable=isEnable;
}
void CGrannyLODController::SetMaterialImagePointer(const char* c_szImageName, CGraphicImage* pImage)
{
std::deque<CGrannyModelInstance *>::iterator i;
for (i=m_que_pkModelInst.begin(); i!=m_que_pkModelInst.end(); ++i)
{
CGrannyModelInstance* pkModelInst=(*i);
pkModelInst->SetMaterialImagePointer(c_szImageName, pImage);
}
}
void CGrannyLODController::SetMaterialData(const char* c_szImageName, const SMaterialData& c_rkMaterialData)
{
std::deque<CGrannyModelInstance *>::iterator i;
for (i=m_que_pkModelInst.begin(); i!=m_que_pkModelInst.end(); ++i)
{
CGrannyModelInstance* pkModelInst=(*i);
pkModelInst->SetMaterialData(c_szImageName, c_rkMaterialData);
}
}
void CGrannyLODController::SetSpecularInfo(const char* c_szMtrlName, BOOL bEnable, float fPower)
{
std::deque<CGrannyModelInstance *>::iterator i;
for (i=m_que_pkModelInst.begin(); i!=m_que_pkModelInst.end(); ++i)
{
CGrannyModelInstance* pkModelInst=(*i);
pkModelInst->SetSpecularInfo(c_szMtrlName, bEnable, fPower);
}
}
CGrannyLODController::CGrannyLODController() :
m_pCurrentModelInstance(NULL),
m_bLODLevel(0),
m_pAttachedParentModel(NULL),
m_fLODDistance(0.0f),
m_dwLODAniFPS(CGrannyModelInstance::ANIFPS_MAX),
m_pkSharedDeformableVertexBuffer(NULL)
/////////////////////////////////////////////////////
{
}
CGrannyLODController::~CGrannyLODController()
{
__FreeDeformVertexBuffer(m_pkSharedDeformableVertexBuffer);
Clear();
}
void CGrannyLODController::Clear()
{
if (m_pAttachedParentModel)
{
m_pAttachedParentModel->DetachModelInstance(this);
}
m_pCurrentModelInstance = NULL;
m_pAttachedParentModel = NULL;
std::for_each(m_que_pkModelInst.begin(), m_que_pkModelInst.end(), CGrannyModelInstance::Delete);
m_que_pkModelInst.clear();
std::vector<TAttachingModelData>::iterator itor = m_AttachedModelDataVector.begin();
for (; m_AttachedModelDataVector.end() != itor; ++itor)
{
TAttachingModelData & rData = *itor;
rData.pkLODController->m_pAttachedParentModel = NULL;
}
m_AttachedModelDataVector.clear();
}
void CGrannyLODController::AddModel(CGraphicThing * pThing, int iSrcModel, CGrannyLODController * pSkelLODController)
{
if (!pThing)
return;
if (pSkelLODController && pSkelLODController->m_que_pkModelInst.empty())
{
assert(!"EMPTY SKELETON(CANNON LINK)");
return;
}
assert(pThing->GetReferenceCount()>=1);
pThing->AddReference();
if (pThing->GetModelCount() <= iSrcModel)
{
pThing->Release();
return;
}
CGrannyModel * pModel = pThing->GetModelPointer(iSrcModel);
if (!pModel)
{
pThing->Release();
return;
}
CGrannyModelInstance * pModelInstance = CGrannyModelInstance::New();
__ReserveSharedDeformableVertexBuffer(pModel->GetDeformVertexCount());
if (pSkelLODController)
{
pModelInstance->SetLinkedModelPointer(pModel, m_pkSharedDeformableVertexBuffer, &pSkelLODController->m_pCurrentModelInstance);
}
else
{
pModelInstance->SetLinkedModelPointer(pModel, m_pkSharedDeformableVertexBuffer, NULL);
}
// END_OF_WORK
if (!m_pCurrentModelInstance)
{
m_pCurrentModelInstance = pModelInstance;
pModelInstance->DeformNoSkin(&ms_matIdentity);
D3DXVECTOR3 vtMin, vtMax;
pModelInstance->GetBoundBox(&vtMin, &vtMax);
float fSize = 0.0f;
fSize = fMAX(fSize, fabs(vtMin.x - vtMax.x));
fSize = fMAX(fSize, fabs(vtMin.y - vtMax.y));
fSize = fMAX(fSize, fabs(vtMin.z - vtMax.z));
if (fSize<LODHEIGHT_ACTOR)
SetLODLimits(0.0f, LODDISTANCE_ACTOR);
else
//
SetLODLimits(0.0f, LODDISTANCE_BUILDING);
}
else
{
// FIXME : CModelInstance::m_pgrnWorldPose<73><65> Update<74><65><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ϴµ<CFB4>,
// Deform<72><6D> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> NULL <20>Դϴ<D4B4>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>ٲ<EFBFBD><D9B2><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.. - [levites]
pModelInstance->DeformNoSkin(&ms_matIdentity);
}
pThing->Release();
m_que_pkModelInst.push_front(pModelInstance);
}
void CGrannyLODController::__ReserveSharedDeformableVertexBuffer(DWORD deformableVertexCount)
{
if (m_pkSharedDeformableVertexBuffer &&
m_pkSharedDeformableVertexBuffer->GetVertexCount() >= deformableVertexCount)
return;
__FreeDeformVertexBuffer(m_pkSharedDeformableVertexBuffer);
m_pkSharedDeformableVertexBuffer = __AllocDeformVertexBuffer(deformableVertexCount);
}
void CGrannyLODController::AttachModelInstance(CGrannyLODController * pSrcLODController, const char * c_szBoneName)
{
CGrannyModelInstance * pSrcInstance = pSrcLODController->GetModelInstance();
if (!pSrcInstance)
return;
CGrannyModelInstance * pDestInstance = GetModelInstance();
if (pDestInstance)
{
pSrcInstance->SetParentModelInstance(pDestInstance, c_szBoneName);
}
if (!pSrcLODController->GetModelInstance())
return;
// Link Parent Data
pSrcLODController->m_pAttachedParentModel = this;
// Link Child Data
std::vector<TAttachingModelData>::iterator itor = m_AttachedModelDataVector.begin();
for (; m_AttachedModelDataVector.end() != itor;)
{
TAttachingModelData & rData = *itor;
if (pSrcLODController == rData.pkLODController)
{
itor = m_AttachedModelDataVector.erase(itor);
}
else
{
++itor;
}
}
TAttachingModelData AttachingModelData;
AttachingModelData.pkLODController = pSrcLODController;
AttachingModelData.strBoneName = c_szBoneName;
m_AttachedModelDataVector.push_back(AttachingModelData);
}
void CGrannyLODController::DetachModelInstance(CGrannyLODController * pSrcLODController)
{
CGrannyModelInstance * pSrcInstance = pSrcLODController->GetModelInstance();
if (!pSrcInstance)
return;
CGrannyModelInstance * pDestInstance = GetModelInstance();
if (pDestInstance)
{
pSrcInstance->SetParentModelInstance(NULL, 0);
}
// if (!pSrcLODController->GetModelInstance())
// return;
// Unlink Child Data
std::vector<TAttachingModelData>::iterator itor = m_AttachedModelDataVector.begin();
for (; m_AttachedModelDataVector.end() != itor;)
{
TAttachingModelData & rData = *itor;
if (pSrcLODController == rData.pkLODController)
{
itor = m_AttachedModelDataVector.erase(itor);
}
else
{
++itor;
}
}
// Unlink Parent Data
pSrcLODController->m_pAttachedParentModel = NULL;
}
void CGrannyLODController::SetLODLimits(float /*fNearLOD*/, float fFarLOD)
{
m_fLODDistance = fFarLOD;
}
void CGrannyLODController::SetLODLevel(BYTE bLodLevel)
{
assert(m_que_pkModelInst.size() > 0);
if (m_que_pkModelInst.size() > 0)
m_bLODLevel = (BYTE) MIN(m_que_pkModelInst.size() - 1, bLodLevel);
}
void CGrannyLODController::CreateDeviceObjects()
{
std::for_each(m_que_pkModelInst.begin(),
m_que_pkModelInst.end(),
CGrannyModelInstance::FCreateDeviceObjects());
}
void CGrannyLODController::DestroyDeviceObjects()
{
std::for_each(m_que_pkModelInst.begin(),
m_que_pkModelInst.end(),
CGrannyModelInstance::FDestroyDeviceObjects());
}
void CGrannyLODController::RenderWithOneTexture()
{
assert(m_pCurrentModelInstance != NULL);
//#define CHECK_LOD
#ifdef CHECK_LOD
if (m_que_pkModelInst.size() > 0 && m_pCurrentModelInstance == m_que_pkModelInst[0])
m_pCurrentModelInstance->RenderWithoutTexture();
if (m_que_pkModelInst.size() > 1 && m_pCurrentModelInstance == m_que_pkModelInst[1])
m_pCurrentModelInstance->RenderWithOneTexture();
if (m_que_pkModelInst.size() > 2 && m_pCurrentModelInstance == m_que_pkModelInst[2])
m_pCurrentModelInstance->RenderWithOneTexture();
if (m_que_pkModelInst.size() > 3 && m_pCurrentModelInstance == m_que_pkModelInst[3])
m_pCurrentModelInstance->RenderWithOneTexture();
#else
m_pCurrentModelInstance->RenderWithOneTexture();
#endif
}
void CGrannyLODController::BlendRenderWithOneTexture()
{
assert(m_pCurrentModelInstance != NULL);
m_pCurrentModelInstance->BlendRenderWithOneTexture();
}
void CGrannyLODController::RenderWithTwoTexture()
{
assert(m_pCurrentModelInstance != NULL);
m_pCurrentModelInstance->RenderWithTwoTexture();
}
void CGrannyLODController::BlendRenderWithTwoTexture()
{
assert(m_pCurrentModelInstance != NULL);
m_pCurrentModelInstance->BlendRenderWithTwoTexture();
}
void CGrannyLODController::Update(float fElapsedTime, float fDistanceFromCenter, float fDistanceFromCamera)
{
UpdateLODLevel(fDistanceFromCenter, fDistanceFromCamera);
UpdateTime(fElapsedTime);
}
void CGrannyLODController::UpdateLODLevel(float fDistanceFromCenter, float fDistanceFromCamera)
{
if (m_que_pkModelInst.size()<=1)
return;
assert(m_pCurrentModelInstance != NULL);
if (fDistanceFromCenter > LOD_APPLY_MIN) // <20>߽<EFBFBD> LOD <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
{
// ī<>޶<EFBFBD><DEB6><EFBFBD><EFBFBD><EFBFBD> <20>־<EFBFBD><D6BE><EFBFBD> <20><><EFBFBD><EFBFBD> fLODRate<74><65> <20>۾<EFBFBD><DBBE><EFBFBD><EFBFBD><EFBFBD>
// 3<><33> LOD<4F><44> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.. <20><><EFBFBD><EFBFBD> <20>հ<EFBFBD> 0, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD>ڰ<EFBFBD> Ŀ<><C4BF><EFBFBD><EFBFBD>
// 100fps 50fps 33fps 25fps 20fps
// 10ms 20ms 30ms 40ms 50ms
float fLODFactor = fMINMAX(0.0f, (m_fLODDistance-fDistanceFromCamera), m_fLODDistance);
if (m_fLODDistance>0.0f)
m_dwLODAniFPS = (DWORD) ((CGrannyModelInstance::ANIFPS_MAX - CGrannyModelInstance::ANIFPS_MIN) * fLODFactor / m_fLODDistance + CGrannyModelInstance::ANIFPS_MIN);
else
m_dwLODAniFPS = CGrannyModelInstance::ANIFPS_MIN;
assert(m_dwLODAniFPS > 0);
m_dwLODAniFPS /= 10;
m_dwLODAniFPS *= 10;
float fLODStep = m_fLODDistance / m_que_pkModelInst.size();
BYTE bLODLevel = BYTE(fLODFactor / fLODStep);
if (m_fLODDistance <= 5000.0f)
{
if (fDistanceFromCamera < 500.0f)
{
bLODLevel = 0;
}
else if (fDistanceFromCamera < 1500.0f)
{
bLODLevel = 1;
}
else if (fDistanceFromCamera < 2500.0f)
{
bLODLevel = 2;
}
else
{
bLODLevel = 3;
}
bLODLevel = (BYTE) (m_que_pkModelInst.size() - min(bLODLevel, m_que_pkModelInst.size()) - 1);
}
if (ms_isMinLODModeEnable)
bLODLevel=0;
SetLODLevel(bLODLevel);
if (m_pCurrentModelInstance != m_que_pkModelInst[m_bLODLevel])
{
SetCurrentModelInstance(m_que_pkModelInst[m_bLODLevel]);
}
}
else
{
m_dwLODAniFPS=CGrannyModelInstance::ANIFPS_MAX;
if (!m_que_pkModelInst.empty())
{
if (m_pCurrentModelInstance != m_que_pkModelInst.back())
{
SetCurrentModelInstance(m_que_pkModelInst.back());
}
}
}
}
void CGrannyLODController::UpdateTime(float fElapsedTime)
{
assert(m_pCurrentModelInstance != NULL);
m_pCurrentModelInstance->Update(m_dwLODAniFPS);
//DWORD t3=timeGetTime();
m_pCurrentModelInstance->UpdateLocalTime(fElapsedTime);
//DWORD t4=timeGetTime();
#ifdef __PERFORMANCE_CHECKER__
{
static FILE* fp=fopen("perf_lod_update.txt", "w");
if (t4-t1>3)
{
fprintf(fp, "LOD.Total %d (Time %f)\n", t4-t1, timeGetTime()/1000.0f);
fprintf(fp, "LOD.SMI %d\n", t2-t1);
fprintf(fp, "LOD.UP %d\n", t3-t2);
fprintf(fp, "LOD.UL %d\n", t4-t3);
fprintf(fp, "-------------------------------- \n");
fflush(fp);
}
fflush(fp);
}
#endif
}
void CGrannyLODController::SetCurrentModelInstance(CGrannyModelInstance * pgrnModelInstance)
{
// Copy Motion
pgrnModelInstance->CopyMotion(m_pCurrentModelInstance, true);
m_pCurrentModelInstance = pgrnModelInstance;
// Change children attaching link
RefreshAttachedModelInstance();
// Change parent attaching link
if (m_pAttachedParentModel)
{
m_pAttachedParentModel->RefreshAttachedModelInstance();
}
}
void CGrannyLODController::RefreshAttachedModelInstance()
{
if (!m_pCurrentModelInstance)
return;
for (DWORD i = 0; i < m_AttachedModelDataVector.size(); ++i)
{
TAttachingModelData & rModelData = m_AttachedModelDataVector[i];
CGrannyModelInstance * pSrcInstance = rModelData.pkLODController->GetModelInstance();
if (!pSrcInstance)
{
Tracenf("CGrannyLODController::RefreshAttachedModelInstance : m_AttachedModelDataVector[%d]->pkLODController->GetModelIntance()==NULL", i);
continue;
}
pSrcInstance->SetParentModelInstance(m_pCurrentModelInstance, rModelData.strBoneName.c_str());
}
}
void CGrannyLODController::UpdateSkeleton(const D3DXMATRIX * c_pWorldMatrix, float fElapsedTime)
{
if (m_pCurrentModelInstance)
m_pCurrentModelInstance->UpdateSkeleton(c_pWorldMatrix, fElapsedTime);
}
void CGrannyLODController::DeformAll(const D3DXMATRIX * c_pWorldMatrix)
{
std::deque<CGrannyModelInstance *>::iterator i;
for (i=m_que_pkModelInst.begin(); i!=m_que_pkModelInst.end(); ++i)
{
CGrannyModelInstance* pkModelInst=(*i);
pkModelInst->Deform(c_pWorldMatrix);
}
}
void CGrannyLODController::DeformNoSkin(const D3DXMATRIX * c_pWorldMatrix)
{
if (m_pCurrentModelInstance)
m_pCurrentModelInstance->DeformNoSkin(c_pWorldMatrix);
}
void CGrannyLODController::Deform(const D3DXMATRIX * c_pWorldMatrix)
{
if (m_pCurrentModelInstance)
m_pCurrentModelInstance->Deform(c_pWorldMatrix);
}
void CGrannyLODController::RenderToShadowMap()
{
if (m_pCurrentModelInstance)
m_pCurrentModelInstance->RenderWithoutTexture();
}
void CGrannyLODController::RenderShadow()
{
if (m_pCurrentModelInstance)
m_pCurrentModelInstance->RenderWithOneTexture();
}
void CGrannyLODController::ReloadTexture()
{
if (m_pCurrentModelInstance)
m_pCurrentModelInstance->ReloadTexture();
}
void CGrannyLODController::GetBoundBox(D3DXVECTOR3 * vtMin, D3DXVECTOR3 * vtMax)
{
if (m_pCurrentModelInstance)
m_pCurrentModelInstance->GetBoundBox(vtMin, vtMax);
}
bool CGrannyLODController::Intersect(const D3DXMATRIX * c_pMatrix, float * u, float * v, float * t)
{
if (!m_pCurrentModelInstance)
return false;
return m_pCurrentModelInstance->Intersect(c_pMatrix, u, v, t);
}
void CGrannyLODController::SetLocalTime(float fLocalTime)
{
if (m_pCurrentModelInstance)
m_pCurrentModelInstance->SetLocalTime(fLocalTime);
}
void CGrannyLODController::ResetLocalTime()
{
assert(m_pCurrentModelInstance != NULL);
m_pCurrentModelInstance->ResetLocalTime();
}
void CGrannyLODController::SetMotionPointer(const CGrannyMotion * c_pMotion, float fBlendTime, int iLoopCount, float speedRatio)
{
assert(m_pCurrentModelInstance != NULL);
m_pCurrentModelInstance->SetMotionPointer(c_pMotion, fBlendTime, iLoopCount, speedRatio);
}
void CGrannyLODController::ChangeMotionPointer(const CGrannyMotion * c_pMotion, int iLoopCount, float speedRatio)
{
assert(m_pCurrentModelInstance != NULL);
m_pCurrentModelInstance->ChangeMotionPointer(c_pMotion, iLoopCount, speedRatio);
}
void CGrannyLODController::SetMotionAtEnd()
{
if (m_pCurrentModelInstance)
m_pCurrentModelInstance->SetMotionAtEnd();
}
BOOL CGrannyLODController::isModelInstance()
{
if (!m_pCurrentModelInstance)
return FALSE;
return TRUE;
}
CGrannyModelInstance * CGrannyLODController::GetModelInstance()
{
return m_pCurrentModelInstance;
}