Files
2026-06-01 12:46:52 +02:00

1447 lines
48 KiB
C++

// KSeqSpeedTree.cpp: implementation of the KSeqSpeedTree class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "KViewport.h"
#include "KResource.h"
#include "KSeqSpeedTree.h"
#include "KResourceManager.h"
#include "KRenderObjectMesh.h"
#include "SSpeedTreeVertexShaders.h"
#include <toolkit/XStringUtil.h>
//#include "K3DFrustum.h"
#include "gamedefine.h"
#include "k3dpccp.h"
#include "KRenderDeviceDX.h"
const int DEFAULT_LOD_UNIT_SIZE = 12; // 1미터가 좌표상으로 얼마인지를 정의 <- 게임 룰에서 가져온 것이므로, 변경되면 함께 변경 요망.
const float TREE_TRANSPARENT_MAX = 0.6f; // 투명화되는 순간의 최대 투명값
bool KSeqSpeedTree::s_bTransparentMode = true;
bool KSeqSpeedTree::S_bSpeedTreeRender = true;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#define AGBR2ARGB(dwColor) (dwColor & 0xff00ff00) + ((dwColor & 0x00ff0000) >> 16) + ((dwColor & 0x000000ff) << 16)
unsigned int KSeqSpeedTree::m_unNumWrappersActive = 0;
K3DRenderDevice * KSeqSpeedTree::m_pDevice = NULL;
K3DVector KSeqSpeedTree::m_afCameraPos(0.); // Camera position
K3DVector KSeqSpeedTree::m_afCameraDirection(0.); // Camera direction
K3DVector KSeqSpeedTree::m_afCameraTargetPos(0.); // Camera target position
KSeqSpeedTree::KSeqSpeedTree( bool bInstance ) :
m_bIsInstance(false),
m_pInstanceOf(NULL),
m_pGeometryCache(NULL),
m_usNumLeafLods(0),
m_unNumFrondLods(0),
m_pBranchIndexCounts(NULL),
m_pFrondIndexCounts(NULL),
m_spFrondIndexBufferArray(NULL),
m_spLeafVertexBufferArray(NULL),
m_pLeavesUpdatedByCpu(NULL)
{
m_afPos = K3DVector( 0.0f, 0.0f, 0.0f );
m_bLoad = FALSE;
m_bIsClip = false; //외부 Prop 에서 함.
// wind states
m_fWindStrength = 1.f;
m_fNearLod = 5.f;
m_fFarLod = 6000;
m_fCurrLodLevel = 1.f;
m_pSpeedTree = NULL;
if( bInstance == false )
{
m_pSpeedTree = new CSpeedTreeRT;
m_pSpeedTree->SetWindStrength(m_fWindStrength);
m_pSpeedTree->SetLocalMatrices(0, 4);
}
m_prBranch.SetSpeedTree( m_pSpeedTree );
m_prFrond.SetSpeedTree( m_pSpeedTree );
m_prLeaf.SetSpeedTree( m_pSpeedTree );
#ifdef WRAPPER_BILLBOARD_MODE
m_prBillboard.SetSpeedTree( m_pSpeedTree );
#endif
m_pTextureInfo = NULL;
m_unNumWrappersActive++;
m_bIsProcessed = false;
K3DMatrixIdentity( m_matWorld );
}
KSeqSpeedTree::~KSeqSpeedTree()
{
if (!m_bIsInstance)
{
SAFE_DELETE_ARRAY(m_pBranchIndexCounts);
SAFE_DELETE_ARRAY(m_spFrondIndexBufferArray);
SAFE_DELETE_ARRAY(m_pFrondIndexCounts);
SAFE_DELETE_ARRAY(m_spLeafVertexBufferArray);
SAFE_DELETE_ARRAY(m_pLeavesUpdatedByCpu);
SAFE_DELETE(m_pTextureInfo);
_oprint( "Delete original Tree\n" );
SAFE_DELETE(m_pGeometryCache);
}
// always delete the SpeedTree
SAFE_DELETE(m_pSpeedTree);
--m_unNumWrappersActive;
}
void KSeqSpeedTree::GetBranchTextureName(std::string& name)
{
if( !m_pTextureInfo ) return;
name = m_pTextureInfo->m_pBranchTextureFilename;
}
/*
void KSeqSpeedTree::GetFrondTextureName(std::string& name)
{
name = m_pTextureInfo->m_pFrondTextureFilenames;
}
void KSeqSpeedTree::GetLeafTextureName(std::string& name)
{
name = m_pTextureInfo->m_pLeafTextureFilename;
}
*/
void KSeqSpeedTree::GetCompositeTextureName(std::string& name)
{
if( !m_pTextureInfo ) return;
name = m_pTextureInfo->m_pCompositeFilename;
}
int KSeqSpeedTree::GetBranchPolyCount(float fLod)
{
if( !m_pSpeedTree ) return 0;
return m_pSpeedTree->GetBranchTriangleCount(fLod);
}
int KSeqSpeedTree::GetFrondPolyCount(float fLod)
{
if( !m_pSpeedTree ) return 0;
return m_pSpeedTree->GetFrondTriangleCount(fLod);
}
int KSeqSpeedTree::GetLeafPolyCount(float fLod)
{
if( !m_pSpeedTree ) return 0;
return m_pSpeedTree->GetLeafTriangleCount(fLod);
}
void *KSeqSpeedTree::Perform( KID id, KArg& msg )
{
_CID( REQ_BOUNDBOX );
if( id == id_REQ_BOUNDBOX )
{
KMsgREQ_BOUNDBOX *boundReq = static_cast<KMsgREQ_BOUNDBOX*>(&msg);
boundReq->AddBound( GetBoundCube() );
}
return (void*)1;
}
int KSeqSpeedTree::Process( DWORD dwTime )
{
int process_state = (m_bIsPlaying) ? (SEQINFO_PLAYING) : (SEQINFO_STOPPED);
if( !m_bLoad ) return SEQINFO_STOPPED;
{
//나무 퀄리티 올려주기
//2009-12-23 : hunee
//Advance(false, 1.0f);
Advance(true, m_fCurrLodLevel);
}
{
SetupBranchForTreeType();
SetupFrondForTreeType();
SetupLeafForTreeType();
EndLeafForTreeType();
}
if( !m_bIsProcessed )
m_bIsProcessed = true;
return process_state;
}
void KSeqSpeedTree::ClipTest( const K3DVector* pFrustum )
{
// m_bIsClip = ( pFrustum->ISContainCube(m_BoundCube) == K3DFrustum::FRUSTUM_OUT );
m_bIsClip = KPCCP::nonuniformcube_collide_nonuniformcube(pFrustum, m_BoundCube.GetVertices()) == false;
}
void KSeqSpeedTree::Render( KViewportObject *viewport, DWORD flag, const K3DMatrix * pAttachMat )
{
if( !m_bLoad ) return;
if( m_bIsClip ) return;
if( !S_bSpeedTreeRender ) return;
if( !m_bIsProcessed ) return;
bool bTransparent = m_fMasterVisibility >= 1.0 ? false : true;
// sonador #2.1.7.1 스피드 트리 퍼포먼스 증가
//bTransparent = false;
{
PositionTree( );
}
{
#ifndef _RAC //TOOL
bool bTransparent = m_fMasterVisibility >= 1.0 ? false : true;
bTransparent = false;
m_prBranch.SetVisibility( m_fMasterVisibility );
m_prFrond.SetVisibility( m_fMasterVisibility );
m_prLeaf.SetVisibility( m_fMasterVisibility );
m_prBillboard.SetVisibility( m_fMasterVisibility );
m_prBranch.SetTransparent( bTransparent );
m_prFrond.SetTransparent( bTransparent );
m_prLeaf.SetTransparent( bTransparent );
m_prBillboard.SetTransparent( bTransparent );
#else
//
// 카메라 위치로부터 투명도 계산
//
float playerDist, treeDist;
float opacity;
//bool isTransparent;
K3DMatrix *transform=m_prBranch.GetTransform();
K3DVector v;
v.x=transform->m30;
v.y=transform->m31;
v.z=transform->m32;
playerDist=(m_afCameraTargetPos-m_afCameraPos).Magnitude(); // 플레이어-카메라 거리
treeDist=(v-m_afCameraPos).Magnitude(); // 나무-카메라 거리
if (treeDist>playerDist) { // Tree is farther than player distance : Full opaque
//isTransparent=false; // 불투명
opacity=TREE_TRANSPARENT_MAX * m_fMasterVisibility; // 불투명도 max
} else { // Near-camera trees : make transparent
//isTransparent=true; // 투명
bTransparent=true; // 투명
opacity=1.0f * ( treeDist / playerDist ) * m_fMasterVisibility; // 불투명도 = 나무거리 / 플레이어거리 <- 나중에 적당히 숫자 곱하거나 n승해서 조절할 것
}
m_prBranch.SetVisibility( opacity );
m_prFrond.SetVisibility( opacity );
m_prLeaf.SetVisibility( opacity );
#ifdef WRAPPER_BILLBOARD_MODE
m_prBillboard.SetVisibility( opacity );
#endif
m_prBranch.SetTransparent( IsTranparentMode() && bTransparent );
m_prFrond.SetTransparent( IsTranparentMode() && bTransparent );
m_prLeaf.SetTransparent( IsTranparentMode() && bTransparent );
#ifdef WRAPPER_BILLBOARD_MODE
m_prBillboard.SetTransparent( IsTranparentMode() && bTransparent );
#endif
#endif
// RenderBillboards();
//if (m_pGeometryCache->m_sBillboard0.m_bIsActive)
//{
// int a = 1;
// a = 2;
//}
if( m_prBranch.IsValid() )
viewport->Register( &m_prBranch, KRenderObject::RENDEREFX_SPEEDTREE_BRANCH | (SHADOW_ST_CAST<<16) );
if( m_prFrond.IsValid() )
viewport->Register( &m_prFrond , KRenderObject::RENDEREFX_SPEEDTREE_FROND );
if( m_prLeaf.IsValid() )
viewport->Register( &m_prLeaf , KRenderObject::RENDEREFX_SPEEDTREE_LEAF | (SHADOW_ST_CAST<<16) );
#ifdef WRAPPER_BILLBOARD_MODE
if( m_prBillboard.IsValid() )
viewport->Register( &m_prBillboard, KRenderObject::RENDEREFX_SPEEDTREE_BILLBOARD );
#endif
//viewport->Register( &m_prBillboard, KRenderObject::RENDEREFX_SPEEDTREE_BILLBOARD | (SHADOW_ST_CAST<<16) );
}
// m_BoundCube.Render( viewport );
}
void KSeqSpeedTree::SetTransform( const K3DMatrix &mat )
{
// m_matTransform = mat;
SetPos( mat._41, mat._42, mat._43 );
// m_BoundCube.SetTransform( m_matTransform );
// if( m_pSpeedTree->Compute(NULL,1) )
// {
// float fSize, fVariance;
// m_pSpeedTree->GetTreeSize( fSize, fVariance );
// m_pSpeedTree->SetTreeSize( fSize*m_matTransform._11, fVariance );
// }
}
K3DBoundRotCube* KSeqSpeedTree::GetBoundCube( const char * pName )
{
realizeTime();
m_BoundCube.SetTransform(m_matResult);
m_BoundCube.GetVertices(); //미리 한번 계산 되게~
return &m_BoundCube;
}
bool KSeqSpeedTree::_load( unsigned int nSeed, float fSize, float fSizeVariance, const float * pTransform )
{
bool bSuccess = false;
// override the lighting method stored in the spt file
#ifdef WRAPPER_USE_DYNAMIC_LIGHTING
m_pSpeedTree->SetBranchLightingMethod(CSpeedTreeRT::LIGHT_DYNAMIC);
m_pSpeedTree->SetLeafLightingMethod(CSpeedTreeRT::LIGHT_DYNAMIC);
m_pSpeedTree->SetFrondLightingMethod(CSpeedTreeRT::LIGHT_DYNAMIC);
#else
m_pSpeedTree->SetBranchLightingMethod(CSpeedTreeRT::LIGHT_STATIC);
m_pSpeedTree->SetLeafLightingMethod(CSpeedTreeRT::LIGHT_STATIC);
m_pSpeedTree->SetFrondLightingMethod(CSpeedTreeRT::LIGHT_STATIC);
#endif
// set the wind method
#ifdef WRAPPER_USE_GPU_WIND
m_pSpeedTree->SetBranchWindMethod(CSpeedTreeRT::WIND_GPU);
m_pSpeedTree->SetLeafWindMethod(CSpeedTreeRT::WIND_GPU);
m_pSpeedTree->SetFrondWindMethod(CSpeedTreeRT::WIND_GPU);
#endif
#ifdef WRAPPER_USE_CPU_WIND
m_pSpeedTree->SetBranchWindMethod(CSpeedTreeRT::WIND_CPU);
m_pSpeedTree->SetLeafWindMethod(CSpeedTreeRT::WIND_CPU);
m_pSpeedTree->SetFrondWindMethod(CSpeedTreeRT::WIND_CPU);
#endif
#ifdef WRAPPER_USE_NO_WIND
m_pSpeedTree->SetBranchWindMethod(CSpeedTreeRT::WIND_NONE);
m_pSpeedTree->SetLeafWindMethod(CSpeedTreeRT::WIND_NONE);
m_pSpeedTree->SetFrondWindMethod(CSpeedTreeRT::WIND_NONE);
#endif
m_pSpeedTree->SetNumLeafRockingGroups(1);
// override the size, if necessary
if (fSize >= 0.0f && fSizeVariance >= 0.0f)
m_pSpeedTree->SetTreeSize(fSize, fSizeVariance);
//{
// float oriSize, oriSizeVariance;
// m_pSpeedTree->GetTreeSize( oriSize, oriSizeVariance );
// m_pSpeedTree->SetTreeSize(fSize*oriSize, fSizeVariance);
//}
/*float afLeafMaterial[ ] =
{
1.0f, 1.0f, 1.0f, // diffuse
0.2f, 0.2f, 0.2f, // ambient
0.0f, 0.0f, 0.0f, // specular
0.0f, 0.0f, 0.0f, // emissive
0.0f // shininess
};
m_pSpeedTree->SetLeafMaterial(afLeafMaterial);*/
// generate tree geometry
if (m_pSpeedTree->Compute(pTransform, nSeed))
{
//const char * pError = m_pSpeedTree->GetCurrentError();
// get the dimensions
m_pSpeedTree->GetBoundingBox(m_afBoundingBox);
m_BoundCube = K3DBoundRotCube( m_afBoundingBox[0], m_afBoundingBox[3], m_afBoundingBox[1], m_afBoundingBox[4], m_afBoundingBox[2], m_afBoundingBox[5] );
// make the leaves rock in the wind
m_pSpeedTree->SetLeafRockingState(true);
// billboard setup
#ifdef WRAPPER_BILLBOARD_MODE
CSpeedTreeRT::SetDropToBillboard(true);
#else
CSpeedTreeRT::SetDropToBillboard(false);
#endif
// query & set materials
m_cBranchMaterial.Set(m_pSpeedTree->GetBranchMaterial( ));
m_cFrondMaterial.Set(m_pSpeedTree->GetFrondMaterial( ));
m_cLeafMaterial.Set(m_pSpeedTree->GetLeafMaterial( ));
// adjust lod distances
float fHeight = m_afBoundingBox[5] - m_afBoundingBox[2];
m_pSpeedTree->SetLodLimits( fHeight * m_fNearLod, fHeight * m_fFarLod);
// query textures
m_pTextureInfo = new CSpeedTreeRT::STextures;
m_pSpeedTree->GetTextures(*m_pTextureInfo);
// load branch textures
m_spTexBranchTexture = LoadTexture( m_pTextureInfo->m_pBranchTextureFilename ); //DDS 포멧 사용
if( m_spTexBranchTexture == NULL )
{
_oprint( "->>Branch Texture Not DDS : %s\n", "_load()" );
m_spTexBranchTexture = LoadTexture( m_pTextureInfo->m_pBranchTextureFilename ); //tga 포멧 사용
}
#ifdef WRAPPER_RENDER_SELF_SHADOWS
if (m_pTextureInfo->m_pSelfShadowFilename != NULL && m_spTexShadow == NULL)
{
if( m_pTextureInfo->m_pSelfShadowFilename && m_pTextureInfo->m_pSelfShadowFilename[0] )
{
//DDS 처리
size_t nPos = 0;
std::string strFileName = m_pTextureInfo->m_pSelfShadowFilename;
nPos = strFileName.rfind( ".");
if(nPos != std::string::npos)
{
strFileName.erase(strFileName.begin() + nPos, strFileName.end());
}
strFileName += ".dds";
m_spTexShadow = LoadTexture( strFileName.c_str() );
if(m_spTexShadow == NULL)
{
//TGA 처리
XStringUtil::Replace( strFileName, ".dds", ".tga" );
m_spTexShadow = LoadTexture( strFileName.c_str() );
}
}
}
#endif
//통합 화일이 있으면,
if( strlen(m_pTextureInfo->m_pCompositeFilename) )
{
//DDS 처리
size_t nPos = 0;
std::string strFileName = m_pTextureInfo->m_pCompositeFilename;
nPos = strFileName.rfind( ".");
if(nPos != std::string::npos)
{
strFileName.erase(strFileName.begin() + nPos, strFileName.end());
}
strFileName += ".dds";
m_spTexFrondTexture = LoadTexture( strFileName.c_str() );
if(m_spTexFrondTexture == NULL)
{
//TGA 처리
XStringUtil::Replace( strFileName, ".dds", ".tga" );
m_spTexFrondTexture = LoadTexture( strFileName.c_str() );
}
m_spTexLeafTexture = m_spTexFrondTexture;
#ifdef WRAPPER_BILLBOARD_MODE
m_spTexBillboardTexture = m_spTexFrondTexture;
#endif
}
//else
//{ //개별 Load
// for( unsigned int i(0); m_pTextureInfo->m_uiFrondTextureCount>i; i++ )
// {
// const char * pFrondName = m_pTextureInfo->m_pFrondTextureFilenames[i];
// if( m_spTexFrondTexture == NULL )
// {
// m_spTexFrondTexture = LoadTexture( pFrondName );
// }
// }
// for( unsigned int i(0); m_pTextureInfo->m_uiLeafTextureCount>i; i++ )
// {
// const char * pLeafName = m_pTextureInfo->m_pLeafTextureFilenames[i];
// if( m_spTexLeafTexture == NULL )
// {
// m_spTexLeafTexture = LoadTexture( pLeafName );
// }
// }
//}
// setup the vertex and index buffers
SetupBuffers( );
m_prBranch.SetSubMeshCount( 1 );
m_prBranch.SetVertexBuffer( 0, m_spBranchVertexBuffer, SSpeedTreePrimitive::TREE_BRANCH,m_unBranchVertexCount, m_pBranchIndexCounts );
if( m_spBranchVertexBuffer )
m_prBranch.SetValid( m_spBranchVertexBuffer->IsValidVtx() );
else
m_prBranch.SetValid( false );
m_prBranch.SetIndexBuffer( 0, m_spBranchIndexBuffer );
//m_prBranch.SetTextureCount( 1 );
m_prBranch.SetTextureCount( 2 );
m_prBranch.SetTexture( 0, m_spTexBranchTexture );
m_prFrond.SetGeometry( m_pGeometryCache );
m_prFrond.SetSpeedTree( m_pSpeedTree );
m_prFrond.SetSubMeshCount( m_unNumFrondLods );
if( m_spFrondVertexBuffer != NULL)
m_prFrond.SetVertexBuffer( 0, m_spFrondVertexBuffer, SSpeedTreePrimitive::TREE_FROND, m_unFrondVertexCount, m_pFrondIndexCounts );
for(unsigned int i = 0; i < m_unNumFrondLods; i++)
{
m_prFrond.SetIndexBuffer(i, m_spFrondIndexBufferArray[i]);
if( m_spFrondVertexBuffer )
m_prFrond.SetValid( m_spFrondVertexBuffer->IsValidVtx() );
else
m_prFrond.SetValid( false );
}
//m_prFrond.SetTextureCount( 1 );
m_prFrond.SetTextureCount( 2 );
m_prFrond.SetTexture( 0, m_spTexFrondTexture );
m_prLeaf.SetGeometry( m_pGeometryCache );
m_prLeaf.SetSpeedTree( m_pSpeedTree );
m_prLeaf.SetSubMeshCount( m_usNumLeafLods );
for( int i(0); m_usNumLeafLods>i; i++ )
{
m_prLeaf.SetVertexBuffer( i,m_spLeafVertexBufferArray[i], SSpeedTreePrimitive::TREE_LEAF, 0, NULL );
if( m_spLeafVertexBufferArray[i] && m_spLeafVertexBufferArray[i]->IsValidVtx() == false )
m_prLeaf.SetValid( m_spLeafVertexBufferArray[i]->IsValidVtx() );
}
m_prLeaf.SetTextureCount( 1 );
//m_prLeaf.SetTextureCount( 2 );
m_prLeaf.SetTexture( 0, m_spTexLeafTexture );
#ifdef WRAPPER_BILLBOARD_MODE
m_prBillboard.SetGeometry(m_pGeometryCache);
m_prBillboard.SetSpeedTree(m_pSpeedTree);
m_prBillboard.SetSubMeshCount(1);
m_prBillboard.SetVertexBuffer(0, NULL, SSpeedTreePrimitive::TREE_BILLBOARD, 0, 0);
m_prBillboard.SetIndexBuffer(0, NULL);
m_prBillboard.SetTextureCount(1);
//m_prBillboard.SetTextureCount(2);
//m_prBillboard.SetTexture(0, m_spTexCompositeMap );
m_prBillboard.SetTexture(0, m_spTexBillboardTexture );
#endif
// everything appeared to go well023
bSuccess = true;
m_bLoad = TRUE;
}
else // tree failed to compute
_oprint( "\nFatal Error, cannot compute tree [%s]\n\n", CSpeedTreeRT::GetCurrentError( ));
return bSuccess;
}
bool KSeqSpeedTree::LoadTree(KStream* pszSptStream, unsigned int nSeed, float fSize, float fSizeVariance, const float * pTransform)
{
bool bSuccess = false;
// directx, so allow for flipping of the texture coordinate
#ifdef WRAPPER_FLIP_T_TEXCOORD
m_pSpeedTree->SetTextureFlip(true);
#endif
// load the tree file
if (m_pSpeedTree->LoadTree(pszSptStream))
{
bSuccess = _load( nSeed, fSize, fSizeVariance, pTransform );
}
else // tree failed to load
_oprint( "SpeedTreeRT Error: %s\n", CSpeedTreeRT::GetCurrentError( ));
return bSuccess;
}
bool KSeqSpeedTree::LoadTree(const char* pszSptFile, unsigned int nSeed, float fSize, float fSizeVariance, const float * pTransform )
{
bool bSuccess = false;
// _oprint( "Speed Tree : %s\n", pszSptFile );
// directx, so allow for flipping of the texture coordinate
#ifdef WRAPPER_FLIP_T_TEXCOORD
m_pSpeedTree->SetTextureFlip(true);
#endif
// load the tree file
if (m_pSpeedTree->LoadTree(pszSptFile))
{
bSuccess = _load( nSeed, fSize, fSizeVariance, pTransform );
}
else // tree failed to load
_oprint( "SpeedTreeRT Error: %s\n", CSpeedTreeRT::GetCurrentError( ));
return bSuccess;
}
void KSeqSpeedTree::SetupBuffers(void)
{
// read all the geometry for highest LOD into the geometry cache
m_pSpeedTree->SetLodLevel(1.f);
if (m_pGeometryCache == NULL)
{
static int nCnt = 0;
m_pGeometryCache = new CSpeedTreeRT::SGeometry;
// _oprint( "SetupBuffers : new m_pGeometryCache - %d\n", nCnt++ );
}
m_pSpeedTree->GetGeometry(*m_pGeometryCache);
m_prBranch.SetGeometry( m_pGeometryCache );
m_prFrond.SetGeometry( m_pGeometryCache );
m_prLeaf.SetGeometry( m_pGeometryCache );
#ifdef WRAPPER_BILLBOARD_MODE
m_prBillboard.SetGeometry(m_pGeometryCache);
#endif
////BillBoard
// m_pSpeedTree->GetGeometry(*m_pGeometryCache, SpeedTree_BillboardGeometry);
// m_pGeometryCache->m_sBillboard0.m_pTexCoords;
// setup the buffers for each tree part
SetupBranchBuffers( );
SetupFrondBuffers( );
SetupLeafBuffers( );
//SetupBillboardBuffers();
}
void KSeqSpeedTree::SetupBranchBuffers(void)
{
// reference to the branch structure
CSpeedTreeRT::SGeometry::SIndexed* pBranches = &(m_pGeometryCache->m_sBranches);
m_unBranchVertexCount = pBranches->m_usVertexCount; // we asked for a contiguous strip
// check if this tree has branches
if (m_unBranchVertexCount > 1)
{
// create the vertex buffer for storing branch vertices
#ifdef WRAPPER_USE_GPU_WIND
m_spBranchVertexBuffer = m_pDevice->CreateVertexBufferSpeedTree( sizeof(SFVFBranchVertex), D3DUSAGE_WRITEONLY, D3DFVF_SPEEDTREE_BRANCH_VERTEX, m_unBranchVertexCount );
#else
m_spBranchVertexBuffer = m_pDevice->CreateVertexBufferSpeedTree( sizeof(SFVFBranchVertex), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_SPEEDTREE_BRANCH_VERTEX, m_unBranchVertexCount );
#endif
if( m_spBranchVertexBuffer == NULL || !m_spBranchVertexBuffer->IsValidVtx() ) return;
// fill the vertex buffer by interleaving SpeedTree data
int nVtxSize = 0;
SFVFBranchVertex* pVertexBuffer = NULL;
#ifdef WRAPPER_USE_GPU_WIND
m_spBranchVertexBuffer->Lock(reinterpret_cast<void**>(&pVertexBuffer), nVtxSize);
#else
m_spBranchVertexBuffer->Lock(reinterpret_cast<void**>(&pVertexBuffer), nVtxSize, D3DLOCK_NOSYSLOCK | D3DLOCK_DISCARD);
#endif
assert(pVertexBuffer && "m_spBranchVertexBuffer->Lock(reinterpret_cast<void**>(&pVertexBuffer), nVtxSize);");
unsigned int i;
if( pVertexBuffer )
{
for (i = 0; i < m_unBranchVertexCount; ++i)
{
// position
memcpy(&pVertexBuffer->m_vPosition, &(pBranches->m_pCoords[i * 3]), sizeof(pVertexBuffer->m_vPosition));
// normal or color
#ifdef WRAPPER_USE_DYNAMIC_LIGHTING
memcpy(&pVertexBuffer->m_vNormal, &(pBranches->m_pNormals[i * 3]), sizeof(pVertexBuffer->m_vNormal));
#else
pVertexBuffer->m_dwDiffuseColor = AGBR2ARGB(pBranches->m_pColors[i]);
#endif
// texcoords for layer 0
pVertexBuffer->m_fTexCoords[0] = pBranches->m_pTexCoords0[i * 2];
pVertexBuffer->m_fTexCoords[1] = pBranches->m_pTexCoords0[i * 2 + 1];
// texcoords for layer 1 (if enabled)
#ifdef WRAPPER_RENDER_SELF_SHADOWS
pVertexBuffer->m_fShadowCoords[0] = pBranches->m_pTexCoords1[i * 2];
pVertexBuffer->m_fShadowCoords[1] = pBranches->m_pTexCoords1[i * 2 + 1];
#endif
// gpu wind data
#ifdef WRAPPER_USE_GPU_WIND
pVertexBuffer->m_fWindIndex = 4.0f * pBranches->m_pWindMatrixIndices[i];
pVertexBuffer->m_fWindWeight = (float)pBranches->m_pWindWeights[i];
#endif
++pVertexBuffer;
}
m_spBranchVertexBuffer->Unlock( );
m_spBranchVertexBuffer->Backup();
}
// create and fill the index counts for each LOD
unsigned int unNumLodLevels = m_pSpeedTree->GetNumBranchLodLevels( );
m_pBranchIndexCounts = new unsigned short[unNumLodLevels];
for (i = 0; i < unNumLodLevels; ++i)
{
// force geometry update for this LOD
m_pSpeedTree->GetGeometry(*m_pGeometryCache, SpeedTree_BranchGeometry, (short)i);
// check if this LOD has branches
if (pBranches->m_usNumStrips > 0)
m_pBranchIndexCounts[i] = pBranches->m_pStripLengths[0];
else
m_pBranchIndexCounts[i] = 0;
}
// force update of geometry to highest LOD
m_pSpeedTree->GetGeometry(*m_pGeometryCache, SpeedTree_BranchGeometry, 0);
// the first LOD level contains the most indices of all the levels, so
// we use its size to allocate the index buffer
m_spBranchIndexBuffer = m_pDevice->CreateIndexBuffer( m_pBranchIndexCounts[0] );
// fill the index buffer
unsigned short* pIndexBuffer = NULL;
int nIdxSize = 0;
m_spBranchIndexBuffer->Lock( reinterpret_cast<void**>(&pIndexBuffer), nIdxSize);
assert(pIndexBuffer && "m_spBranchIndexBuffer->Lock( reinterpret_cast<void**>(&pIndexBuffer), nIdxSize);");
if( pIndexBuffer )
{
memcpy(pIndexBuffer, pBranches->m_pStrips[0], pBranches->m_pStripLengths[0] * sizeof(unsigned short));
m_spBranchIndexBuffer->Unlock( );
}
}
}
///////////////////////////////////////////////////////////////////////
// CSpeedTreeWrapper::SetupFrondBuffers
void KSeqSpeedTree::SetupFrondBuffers(void)
{
// reference to frond structure
CSpeedTreeRT::SGeometry::SIndexed* pFronds = &(m_pGeometryCache->m_sFronds);
m_unFrondVertexCount = pFronds->m_usVertexCount; // we asked for a contiguous strip
// check if this tree has fronds
if (m_unFrondVertexCount > 1)
{
// create the vertex buffer for storing frond vertices
#ifdef WRAPPER_USE_GPU_WIND
m_spFrondVertexBuffer = m_pDevice->CreateVertexBufferSpeedTree( sizeof(SFVFBranchVertex), D3DUSAGE_WRITEONLY, D3DFVF_SPEEDTREE_BRANCH_VERTEX, m_unFrondVertexCount );
#else
m_spFrondVertexBuffer = m_pDevice->CreateVertexBufferSpeedTree( sizeof(SFVFBranchVertex), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_SPEEDTREE_BRANCH_VERTEX, m_unFrondVertexCount);
#endif
if( m_spFrondVertexBuffer == NULL || !m_spFrondVertexBuffer->IsValidVtx() ) return;
// fill the vertex buffer by interleaving SpeedTree data
SFVFBranchVertex* pVertexBuffer = NULL;
int nVtxSize = 0;
#ifdef WRAPPER_USE_GPU_WIND
m_spFrondVertexBuffer->Lock(reinterpret_cast<void**>(&pVertexBuffer), nVtxSize);
#else
m_spFrondVertexBuffer->Lock(reinterpret_cast<void**>(&pVertexBuffer), nVtxSize, D3DLOCK_NOSYSLOCK | D3DLOCK_DISCARD);
#endif
assert(pVertexBuffer && "m_spFrondVertexBuffer->Lock(reinterpret_cast<void**>(&pVertexBuffer), nVtxSize);");
for (unsigned short i = 0; i < m_unFrondVertexCount; ++i)
{
// position
memcpy(&pVertexBuffer->m_vPosition, &(pFronds->m_pCoords[i * 3]), sizeof(pVertexBuffer->m_vPosition));
// normal or color
#ifdef WRAPPER_USE_DYNAMIC_LIGHTING
memcpy(&pVertexBuffer->m_vNormal, &(pFronds->m_pNormals[i * 3]), sizeof(pVertexBuffer->m_vNormal));
#else
pVertexBuffer->m_dwDiffuseColor = AGBR2ARGB(pFronds->m_pColors[i]);
#endif
// texcoords for layer 0
pVertexBuffer->m_fTexCoords[0] = pFronds->m_pTexCoords0[i * 2];
pVertexBuffer->m_fTexCoords[1] = pFronds->m_pTexCoords0[i * 2 + 1];
// texcoords for layer 1 (if enabled)
#ifdef WRAPPER_RENDER_SELF_SHADOWS
pVertexBuffer->m_fShadowCoords[0] = pFronds->m_pTexCoords1[i * 2];
pVertexBuffer->m_fShadowCoords[1] = pFronds->m_pTexCoords1[i * 2 + 1];
#endif
// gpu wind data
#ifdef WRAPPER_USE_GPU_WIND
pVertexBuffer->m_fWindIndex = 4.0f * pFronds->m_pWindMatrixIndices[i];
pVertexBuffer->m_fWindWeight = pFronds->m_pWindWeights[i];
#endif
++pVertexBuffer;
}
m_spFrondVertexBuffer->Unlock( );
m_spFrondVertexBuffer->Backup();
// create and fill the index counts for each LOD
//unsigned int unNumLodLevels = m_pSpeedTree->GetNumFrondLodLevels( );
//m_pFrondIndexCounts = new unsigned short[unNumLodLevels];
m_unNumFrondLods = m_pSpeedTree->GetNumFrondLodLevels();
m_pFrondIndexCounts = new unsigned short[m_unNumFrondLods];
// 이런 위험한 짓을 -_-
m_spFrondIndexBufferArray = new K3DIndexBufferSPtr[m_unNumFrondLods];
//for (i = 0; i < unNumLodLevels; ++i)
for (unsigned int i = 0; i < m_unNumFrondLods; ++i)
{
// force update of geometry for this LOD
m_pSpeedTree->GetGeometry(*m_pGeometryCache, SpeedTree_FrondGeometry, -1, i);
// check if this LOD has fronds
if (pFronds->m_usNumStrips > 0)
m_pFrondIndexCounts[i] = pFronds->m_pStripLengths[0];
else
m_pFrondIndexCounts[i] = 0;
if (m_pFrondIndexCounts[i] > 0)
{
m_spFrondIndexBufferArray[i] = m_pDevice->CreateIndexBuffer(m_pFrondIndexCounts[i]);
// fill the index buffer
unsigned short* pIndexBuffer = NULL;
int nIdxSize = 0;
m_spFrondIndexBufferArray[i]->Lock(reinterpret_cast<void**>(&pIndexBuffer), nIdxSize);
assert(pIndexBuffer && "m_spFrondIndexBufferArray[i]->Lock(reinterpret_cast<void**>(&pIndexBuffer), nIdxSize);");
memcpy(pIndexBuffer, pFronds->m_pStrips[0], m_pFrondIndexCounts[i] * sizeof(unsigned short));
m_spFrondIndexBufferArray[i]->Unlock( );
}
}
// force update of geometry to highest LOD
m_pSpeedTree->GetGeometry(*m_pGeometryCache, SpeedTree_FrondGeometry, -1, 0);
// the first LOD level contains the most indices of all the levels, so
// we use its size to allocate the index buffer
//m_spFrondIndexBufferArray = m_pDevice->CreateIndexBuffer(m_pFrondIndexCounts[0]);
// fill the index buffer
//unsigned short* pIndexBuffer = NULL;
//int nIdxSize = 0;
//m_spFrondIndexBufferArray->Lock(reinterpret_cast<void**>(&pIndexBuffer), nIdxSize);
//memcpy(pIndexBuffer, pFronds->m_pStrips[0], pFronds->m_pStripLengths[0] * sizeof(unsigned short));
//m_spFrondIndexBufferArray->Unlock( );
}
}
///////////////////////////////////////////////////////////////////////
// CSpeedTreeWrapper::SetupLeafBuffers
void KSeqSpeedTree::SetupLeafBuffers(void)
{
// set up constants
const short anVertexIndices[6] = { 0, 1, 2, 0, 2, 3 };
// set up the leaf counts for each LOD
m_usNumLeafLods = m_pSpeedTree->GetNumLeafLodLevels( );
// create arrays for the number of LOD levels
//별로 안 좋다.
m_spLeafVertexBufferArray = new K3DVertexBufferSPtr[m_usNumLeafLods];
m_pLeavesUpdatedByCpu = new bool[m_usNumLeafLods];
for (unsigned int unLod = 0; unLod < m_usNumLeafLods; ++unLod)
{
m_pSpeedTree->GetGeometry(*m_pGeometryCache, SpeedTree_LeafGeometry, -1, -1, unLod);
m_pLeavesUpdatedByCpu[unLod] = false;
// if this level has no leaves, then skip it
unsigned short usLeafCount = m_pGeometryCache->m_sLeaves0.m_usLeafCount;
if (usLeafCount < 1)
continue;
// create the vertex buffer for storing leaf vertices
#if defined(WRAPPER_USE_GPU_WIND) && defined(WRAPPER_USE_GPU_LEAF_PLACEMENT)
m_spLeafVertexBufferArray[unLod] = m_pDevice->CreateVertexBufferSpeedTree( sizeof(SFVFLeafVertex), D3DUSAGE_WRITEONLY, D3DFVF_SPEEDTREE_LEAF_VERTEX, usLeafCount * 6 );
#else
m_spLeafVertexBufferArray[unLod] = m_pDevice->CreateVertexBufferSpeedTree( sizeof(SFVFLeafVertex), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_SPEEDTREE_LEAF_VERTEX, usLeafCount * 6 );
#endif
if( m_spLeafVertexBufferArray[unLod] == NULL || !m_spLeafVertexBufferArray[unLod]->IsValidVtx() ) continue;
// fill the vertex buffer by interleaving SpeedTree data
SFVFLeafVertex* pVertexBuffer = NULL;
int nVtxSize = 0;
#if defined(WRAPPER_USE_GPU_WIND) && defined(WRAPPER_USE_GPU_LEAF_PLACEMENT)
m_spLeafVertexBufferArray[unLod]->Lock( reinterpret_cast<void**>(&pVertexBuffer), nVtxSize );
#else
m_spLeafVertexBufferArray[unLod]->Lock( reinterpret_cast<void**>(&pVertexBuffer), nVtxSize, D3DLOCK_NOSYSLOCK | D3DLOCK_DISCARD );
#endif
assert(pVertexBuffer && "m_spLeafVertexBufferArray[unLod]->Lock( reinterpret_cast<void**>(&pVertexBuffer), nVtxSize );");
if( pVertexBuffer )
{
SFVFLeafVertex* pVertex = pVertexBuffer;
for (unsigned int unLeaf = 0; unLeaf < usLeafCount; ++unLeaf)
{
const CSpeedTreeRT::SGeometry::SLeaf* pLeaf = &(m_pGeometryCache->m_sLeaves0);
for (unsigned int unVert = 0; unVert < 6; ++unVert) // 6 verts == 2 triangles
{
// position
memcpy(pVertex->m_vPosition, &(pLeaf->m_pCenterCoords[unLeaf * 3]), sizeof(pVertex->m_vPosition));
#ifdef WRAPPER_USE_DYNAMIC_LIGHTING
// normal
memcpy(&pVertex->m_vNormal, &(pLeaf->m_pNormals[unLeaf * 3]), sizeof(pVertex->m_vNormal));
#else
// color
pVertex->m_dwDiffuseColor = AGBR2ARGB(pLeaf->m_pColors[unLeaf]);
#endif
// tex coord
memcpy(pVertex->m_fTexCoords, &(pLeaf->m_pLeafMapTexCoords[unLeaf][anVertexIndices[unVert] * 2]), sizeof(pVertex->m_fTexCoords));
// wind weights
#ifdef WRAPPER_USE_GPU_WIND
pVertex->m_fWindIndex = 4.0f * pLeaf->m_pWindMatrixIndices[unLeaf];
pVertex->m_fWindWeight = pLeaf->m_pWindWeights[unLeaf];
#endif
// gpu leaf placement data
#ifdef WRAPPER_USE_GPU_LEAF_PLACEMENT
pVertex->m_fLeafPlacementIndex = c_nVertexShader_LeafTables + pLeaf->m_pLeafClusterIndices[unLeaf] * 4.0f + anVertexIndices[unVert];
pVertex->m_fLeafScalarValue = m_pSpeedTree->GetLeafLodSizeAdjustments( )[unLod];
#endif
++pVertex;
}
}
m_spLeafVertexBufferArray[unLod]->Unlock( );
m_spLeafVertexBufferArray[unLod]->Backup();
}
}
}
///////////////////////////////////////////////////////////////////////
// CSpeedTreeWrapper::Advance
void KSeqSpeedTree::Advance(bool bControlLod, float fLodLevel)
{
if( !m_bLoad ) return;
// DWORD Stime = GetSafeTickCount();
if(bControlLod)
{
m_pSpeedTree->SetLodLevel(fLodLevel);
}
else
{
// compute LOD level (based on distance from camera)
m_pSpeedTree->ComputeLodLevel( );
}
// compute wind
#ifdef WRAPPER_USE_CPU_WIND
m_pSpeedTree->ComputeWindEffects(true, true, true);
#endif
// _oprint( "Advance Time : %d\n", GetSafeTickCount()-Stime );
}
///////////////////////////////////////////////////////////////////////
// CSpeedTreeWrapper::MakeInstance
XCriticalSection xCS;
bool KSeqSpeedTree::CopyFrom( KThreadResource* pResource )
{
THREAD_SYNCRONIZE( &xCS );
CopyFromTree( static_cast< KSeqSpeedTree* >( pResource ) );
return true;
}
void KSeqSpeedTree::CopyFromTree(KSeqSpeedTree* pSource)
{
// create a new object
KSeqSpeedTree* pInstance = this;
// make an instance of this object's SpeedTree
pInstance->m_bIsInstance = true;
pInstance->m_pSpeedTree = pSource->m_pSpeedTree->MakeInstance( );
pInstance->m_bLoad = pSource->m_bLoad;
if (pInstance->m_pSpeedTree)
{
//pInstance->m_pSpeedTree->ComputeLodLevel();
//pInstance->m_pSpeedTree->Compute(NULL, 0);
pInstance->m_fWindStrength = pSource->m_fWindStrength;
pInstance->m_fNearLod = pSource->m_fNearLod;
pInstance->m_fFarLod = pSource->m_fFarLod;
// use the same materials
pInstance->m_cBranchMaterial = pSource->m_cBranchMaterial;
pInstance->m_cLeafMaterial = pSource->m_cLeafMaterial;
pInstance->m_cFrondMaterial = pSource->m_cFrondMaterial;
pInstance->m_spTexBranchTexture = pSource->m_spTexBranchTexture;
pInstance->m_spTexShadow = pSource->m_spTexShadow;
pInstance->m_pTextureInfo = pSource->m_pTextureInfo;
// use the same geometry cache
pInstance->m_pGeometryCache = pSource->m_pGeometryCache;
// use the same buffers
pInstance->m_spBranchIndexBuffer = pSource->m_spBranchIndexBuffer;
pInstance->m_pBranchIndexCounts = pSource->m_pBranchIndexCounts;
pInstance->m_spBranchVertexBuffer = pSource->m_spBranchVertexBuffer;
pInstance->m_unBranchVertexCount = pSource->m_unBranchVertexCount;
pInstance->m_spFrondIndexBufferArray = pSource->m_spFrondIndexBufferArray;
pInstance->m_unNumFrondLods = m_unNumFrondLods;
pInstance->m_pFrondIndexCounts = pSource->m_pFrondIndexCounts;
pInstance->m_spFrondVertexBuffer = pSource->m_spFrondVertexBuffer;
pInstance->m_unFrondVertexCount = pSource->m_unFrondVertexCount;
pInstance->m_spLeafVertexBufferArray = pSource->m_spLeafVertexBufferArray;
pInstance->m_usNumLeafLods = pSource->m_usNumLeafLods;
pInstance->m_pLeavesUpdatedByCpu = pSource->m_pLeavesUpdatedByCpu;
// new stuff
memcpy(pInstance->m_afPos, pSource->m_afPos, sizeof(pInstance->m_afPos));
memcpy(pInstance->m_afBoundingBox, pSource->m_afBoundingBox, sizeof(pInstance->m_afBoundingBox));
pInstance->GetBoundCube()->SetCube( (K3DVertex *)pSource->m_BoundCube.GetVertices() );
pInstance->m_pInstanceOf = pSource;
pInstance->m_prBranch.SetGeometry( pInstance->m_pGeometryCache );
pInstance->m_prBranch.SetSpeedTree( pInstance->m_pSpeedTree );
pInstance->m_prBranch.SetSubMeshCount( 1 );
pInstance->m_prBranch.SetVertexBuffer( 0, pSource->m_spBranchVertexBuffer, SSpeedTreePrimitive::TREE_BRANCH,pSource-> m_unBranchVertexCount, pSource->m_pBranchIndexCounts );
if( pSource->m_spBranchVertexBuffer )
pInstance->m_prBranch.SetValid( pSource->m_spBranchVertexBuffer->IsValidVtx() );
pInstance->m_prBranch.SetIndexBuffer( 0, pSource->m_spBranchIndexBuffer );
//pInstance->m_prBranch.SetTextureCount( 1 );
pInstance->m_prBranch.SetTextureCount( 2 );
pInstance->m_prBranch.SetTexture( 0, pSource->m_spTexBranchTexture );
pInstance->m_prFrond.SetGeometry( pInstance->m_pGeometryCache );
pInstance->m_prFrond.SetSpeedTree( pInstance->m_pSpeedTree );
pInstance->m_prFrond.SetSubMeshCount( pSource->m_unNumFrondLods );
pInstance->m_prFrond.SetVertexBuffer( 0, pSource->m_spFrondVertexBuffer, SSpeedTreePrimitive::TREE_FROND, pSource->m_unFrondVertexCount, pSource->m_pFrondIndexCounts );
if( pSource->m_spFrondVertexBuffer )
pInstance->m_prFrond.SetValid( pSource->m_spFrondVertexBuffer->IsValidVtx() );
for(unsigned int i = 0; i < pSource->m_unNumFrondLods; i++)
{
pInstance->m_prFrond.SetIndexBuffer(i, pSource->m_spFrondIndexBufferArray[i]);
}
//pInstance->m_prFrond.SetTextureCount( 1 );
pInstance->m_prFrond.SetTextureCount( 2 );
pInstance->m_prFrond.SetTexture( 0, pSource->m_spTexFrondTexture );
pInstance->m_prLeaf.SetGeometry( pInstance->m_pGeometryCache );
pInstance->m_prLeaf.SetSpeedTree( pInstance->m_pSpeedTree );
pInstance->m_prLeaf.SetSubMeshCount( pSource->m_usNumLeafLods );
for( int i(0); pSource->m_usNumLeafLods>i; i++ )
{
pInstance->m_prLeaf.SetVertexBuffer( i,pSource-> m_spLeafVertexBufferArray[i], SSpeedTreePrimitive::TREE_LEAF, 0, NULL );
if( pSource->m_spLeafVertexBufferArray[i] && pSource->m_spLeafVertexBufferArray[i]->IsValidVtx() == false )
pInstance->m_prLeaf.SetValid( pSource->m_spLeafVertexBufferArray[i]->IsValidVtx() );
}
pInstance->m_prLeaf.SetTextureCount( 1 );
pInstance->m_prLeaf.SetTexture( 0, pSource->m_spTexLeafTexture );
#ifdef WRAPPER_BILLBOARD_MODE
pInstance->m_prBillboard.SetGeometry( pInstance->m_pGeometryCache );
pInstance->m_prBillboard.SetSpeedTree( pInstance->m_pSpeedTree );
pInstance->m_prBillboard.SetSubMeshCount( 1 );
pInstance->m_prBillboard.SetVertexBuffer( 0, NULL, SSpeedTreePrimitive::TREE_BILLBOARD, 0, 0 );
pInstance->m_prBillboard.SetIndexBuffer( 0, NULL );
pInstance->m_prBillboard.SetTextureCount( 1 );
//pInstance->m_prBillboard.SetTexture( 0, pSource->m_spTexCompositeMap );
pInstance->m_prBillboard.SetTexture( 0, pSource->m_spTexBillboardTexture );
#endif
pSource->m_vInstances.push_back(pInstance);
}
else
{
fprintf(stderr, "SpeedTreeRT Error: %s\n", m_pSpeedTree->GetCurrentError( ));
}
}
//KSeqSpeedTree** KSeqSpeedTree::GetInstances(unsigned int& nCount)
//{
// nCount = (int)m_vInstances.size( );
// return &(m_vInstances[0]);
//}
void KSeqSpeedTree::SetupBranchForTreeType(void)
{
#ifdef WRAPPER_USE_DYNAMIC_LIGHTING
// set lighting material
//Primitive를 만들어서, Render로 따로 만들자~
/* K3DMaterial mat;
mat=*m_cBranchMaterial.GetMaterial();
mat.SetTransparency(1.0f); // Set transparency for branch
m_prBranch.SetMaterial( 0, &mat );
*/ m_prBranch.SetMaterial( 0, m_cBranchMaterial.GetMaterial() );
SetShaderConstants(m_pSpeedTree->GetBranchMaterial( ));
#endif
// set texture map
if (m_spTexBranchTexture)
m_prBranch.SetTexture( 0, m_spTexBranchTexture );
// bind shadow texture (if enabled)
#ifdef WRAPPER_RENDER_SELF_SHADOWS
if (m_spTexShadow)
m_prBranch.SetTexture(1, m_spTexShadow);
#endif
// if tree has branches, bind the buffers
if (m_pGeometryCache->m_sBranches.m_usVertexCount > 0)
{
//Primitive를 만들어서, Render로 따로 만들자~
// activate the branch vertex buffer
m_prBranch.SetVertexBuffer( 0, m_spBranchVertexBuffer, SSpeedTreePrimitive::TREE_BRANCH, m_unBranchVertexCount, m_pBranchIndexCounts );
// set the index buffer
m_prBranch.SetIndexBuffer( 0, m_spBranchIndexBuffer );
}
}
void KSeqSpeedTree::SetLodLevel( float fValue /*0.f~1.f*/ )
{
m_fCurrLodLevel = fValue;
}
///////////////////////////////////////////////////////////////////////
// CSpeedTreeWrapper::SetupFrondForTreeType
void KSeqSpeedTree::SetupFrondForTreeType(void)
{
#ifdef WRAPPER_USE_DYNAMIC_LIGHTING
// set lighting material
m_prFrond.SetMaterial( 0, m_cFrondMaterial.GetMaterial() );
SetShaderConstants(m_pSpeedTree->GetFrondMaterial( ));
#endif
// bind shadow texture (if enabled)
#ifdef WRAPPER_RENDER_SELF_SHADOWS
if (m_spTexShadow)
m_prFrond.SetTexture( 1, m_spTexShadow );
#endif
// if tree has fronds, bind the buffers
if (m_pGeometryCache->m_sFronds.m_usVertexCount > 0)
{
// activate the frond vertex buffer
m_prFrond.SetVertexBuffer( 0, m_spFrondVertexBuffer, SSpeedTreePrimitive::TREE_FROND, m_unFrondVertexCount, m_pFrondIndexCounts );
//// set the index buffer
for(unsigned int i = 0; i < m_unNumFrondLods; i++)
{
m_prFrond.SetIndexBuffer(i, m_spFrondIndexBufferArray[i]);
}
}
}
///////////////////////////////////////////////////////////////////////
// CSpeedTreeWrapper::SetupLeafForTreeType
void KSeqSpeedTree::SetupLeafForTreeType(void)
{
#ifdef WRAPPER_USE_DYNAMIC_LIGHTING
// set lighting material
m_prLeaf.SetMaterial( 0, m_cLeafMaterial.GetMaterial() );
SetShaderConstants(m_pSpeedTree->GetLeafMaterial( ));
#endif
// send leaf tables to the gpu
#ifdef WRAPPER_USE_GPU_LEAF_PLACEMENT
UploadLeafTables(c_nVertexShader_LeafTables);
#endif
// bind shadow texture (if enabled)
#ifdef WRAPPER_RENDER_SELF_SHADOWS
if (m_spTexShadow)
m_prLeaf.SetTexture( 1, NULL );
#endif
for( int i(0); m_usNumLeafLods>i; i++ )
{
m_prLeaf.SetVertexBuffer( i, m_spLeafVertexBufferArray[i], SSpeedTreePrimitive::TREE_LEAF, 0, NULL );
}
}
///////////////////////////////////////////////////////////////////////
// CSpeedTreeWrapper::UploadLeafTables
#ifdef WRAPPER_USE_GPU_LEAF_PLACEMENT
void KSeqSpeedTree::UploadLeafTables(unsigned int uiLocation)
{
// query leaf cluster table from RT
unsigned int uiEntryCount = 0;
const float* pTable = m_pSpeedTree->GetLeafBillboardTable(uiEntryCount);
// upload for vertex shader use
m_prLeaf.SetShaderTable( uiLocation, pTable, uiEntryCount / 4 );
}
#endif
///////////////////////////////////////////////////////////////////////
// CSpeedTreeWrapper::EndLeafForTreeType
void KSeqSpeedTree::EndLeafForTreeType(void)
{
// reset flags for CPU data copying
for (unsigned int i = 0; i < m_usNumLeafLods; ++i)
m_pLeavesUpdatedByCpu[i] = false;
}
///////////////////////////////////////////////////////////////////////
// CSpeedTreeWrapper::RenderBillboards
void KSeqSpeedTree::RenderBillboards(void)
{
// // draw billboards in immediate mode (as close as directx gets to immediate mode)
//#ifdef WRAPPER_BILLBOARD_MODE
// PositionTree( );
//
// struct SBillboardVertex
// {
// float fX, fY, fZ;
// DWORD dColor;
// float fU, fV;
// };
//
// m_pSpeedTree->GetGeometry(*m_pGeometryCache, SpeedTree_BillboardGeometry);
// if (m_pGeometryCache->m_sBillboard0.m_bIsActive)
// {
// const float* pCoords = m_pGeometryCache->m_sBillboard0.m_pCoords;
// const float* pTexCoords = m_pGeometryCache->m_sBillboard0.m_pTexCoords;
// SBillboardVertex sVertex[4] =
// {
// { pCoords[0], pCoords[1], pCoords[2], 0xffffff, pTexCoords[0], pTexCoords[1] },
// { pCoords[3], pCoords[4], pCoords[5], 0xffffff, pTexCoords[2], pTexCoords[3] },
// { pCoords[6], pCoords[7], pCoords[8], 0xffffff, pTexCoords[4], pTexCoords[5] },
// { pCoords[9], pCoords[10], pCoords[11], 0xffffff, pTexCoords[6], pTexCoords[7] },
// };
// //m_pDevice->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
// //m_pDevice->SetRenderState(D3DRS_ALPHAREF, DWORD(m_pGeometryCache->m_sBillboard0.m_fAlphaTestValue));
// //m_pDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, sVertex, sizeof(SBillboardVertex));
// }
//
// // if there is a 360 degree billboard, then we need to draw the second one
// if (m_pGeometryCache->m_sBillboard1.m_bIsActive)
// {
// const float* pCoords = m_pGeometryCache->m_sBillboard1.m_pCoords;
// const float* pTexCoords = m_pGeometryCache->m_sBillboard1.m_pTexCoords;
// SBillboardVertex sVertex[4] =
// {
// { pCoords[0], pCoords[1], pCoords[2], 0xffffff, pTexCoords[0], pTexCoords[1] },
// { pCoords[3], pCoords[4], pCoords[5], 0xffffff, pTexCoords[2], pTexCoords[3] },
// { pCoords[6], pCoords[7], pCoords[8], 0xffffff, pTexCoords[4], pTexCoords[5] },
// { pCoords[9], pCoords[10], pCoords[11], 0xffffff, pTexCoords[6], pTexCoords[7] },
// };
// //m_pDevice->SetRenderState(D3DRS_ALPHAREF, DWORD(m_pGeometryCache->m_sBillboard1.m_fAlphaTestValue));
// //m_pDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, sVertex, sizeof(SBillboardVertex));
// }
//
// // if we have a horizontal bilboard and it is enabled, draw it too
//#ifdef WRAPPER_RENDER_HORIZONTAL_BILLBOARD
// if (m_pGeometryCache->m_sHorizontalBillboard.m_bIsActive)
// {
// const float* pCoords = m_pGeometryCache->m_sHorizontalBillboard.m_pCoords;
// const float* pTexCoords = m_pGeometryCache->m_sHorizontalBillboard.m_pTexCoords;
// SBillboardVertex sVertex[4] =
// {
// { pCoords[0], pCoords[1], pCoords[2], pTexCoords[0], pTexCoords[1] },
// { pCoords[3], pCoords[4], pCoords[5], pTexCoords[2], pTexCoords[3] },
// { pCoords[6], pCoords[7], pCoords[8], pTexCoords[4], pTexCoords[5] },
// { pCoords[9], pCoords[10], pCoords[11], pTexCoords[6], pTexCoords[7] },
// };
// //m_pDevice->SetRenderState(D3DRS_ALPHAREF, DWORD(m_pGeometryCache->m_sHorizontalBillboard.m_fAlphaTestValue));
// //m_pDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, sVertex, sizeof(SBillboardVertex));
// }
//
//#endif
//#endif
}
///////////////////////////////////////////////////////////////////////
// CSpeedTreeWrapper::CleanUpMemory
void KSeqSpeedTree::CleanUpMemory(void)
{
if (!m_bIsInstance)
m_pSpeedTree->DeleteTransientData( );
}
///////////////////////////////////////////////////////////////////////
// CSpeedTreeWrapper::SetPos
void KSeqSpeedTree::SetPos(float x, float y,float z)
{
m_afPos.x = x;
m_afPos.y = y;
m_afPos.z = z;
K3DMatrixTranslation( m_matTransform, m_afPos.x, m_afPos.y, m_afPos.z );
if( m_bLoad ) m_pSpeedTree->SetTreePosition(m_afPos.x, m_afPos.y, m_afPos.z);
}
void KSeqSpeedTree::SetPos(const float* pPos)
{
m_afPos.x = pPos[0];
m_afPos.y = pPos[1];
m_afPos.z = pPos[2];
K3DMatrixTranslation( m_matTransform, m_afPos.x, m_afPos.y, m_afPos.z );
if( m_bLoad ) m_pSpeedTree->SetTreePosition(pPos[0], pPos[1], pPos[2]);
}
///////////////////////////////////////////////////////////////////////
// CSpeedTreeWrapper::PositionTree
void KSeqSpeedTree::PositionTree(void)
{
realizeTime();
// D3DXVECTOR3 vecPosition = m_pSpeedTree->GetTreePosition( );
//K3DMatrixIdentity(m_matResult);
//K3DMatrixTranslation( &m_matResult, m_matTransform._41, m_matTransform._42, m_matTransform._43 );
m_prBranch.SetTransform( &m_matResult, &m_matWorld );
m_prFrond.SetTransform( &m_matResult, &m_matWorld );
m_prLeaf.SetTransform( &m_matResult, &m_matWorld );
#ifdef WRAPPER_BILLBOARD_MODE
m_prBillboard.SetTransform(&m_matResult, &m_matWorld);
#endif
//// store translation for use in vertex shader
//m_vecConstant = D3DXVECTOR4(m_matResult._41, m_matResult._42, m_matResult._43, 0.0f);
//m_prBranch.SetShaderVecConstant( c_nVertexShader_TreePos, (float*)&m_vecConstant, 1 );
//m_prFrond.SetShaderVecConstant ( c_nVertexShader_TreePos, (float*)&m_vecConstant, 1 );
//m_prLeaf.SetShaderVecConstant ( c_nVertexShader_TreePos, (float*)&m_vecConstant, 1 );
//m_prBillboard.SetShaderVecConstant ( c_nVertexShader_TreePos, (float*) &m_vecConstant, 1);
////Sort 용으로 사용.
//m_prLeaf.SetCenterPosition( K3DVector( m_matResult._41, m_matResult._42, m_matResult._43 ) );
}
///////////////////////////////////////////////////////////////////////
// CSpeedTreeWrapper::LoadTexture
K3DTexture* KSeqSpeedTree::LoadTexture(const char* pFilename)
{
//TODO : 리소스 옵션 로딩 추가 작업 중.
NX3LoadPack loadpack;
loadpack.Init();
if( KTextureManager::GetManager()->IsExistTexture( pFilename, &loadpack ) )
{
// sonador 4.3.1 텍스쳐 로딩시 널 참조 수정
K3DTexture* pTexture = KTextureManager::GetManager()->GetTexture( pFilename, &loadpack, true, KTextureManager::GetManager()->GetMipMapBiasLevel()-1 );
if( pTexture )
{
pTexture->Flags() |= TEXFLAG_SPEEDTREE;
return pTexture;
}
}
_oprint( "Resource Error: Speed Tree Texture Not Found - %s\n", pFilename );
return NULL;
}
///////////////////////////////////////////////////////////////////////
// CSpeedTreeWrapper::SetShaderConstants
void KSeqSpeedTree::SetShaderConstants(const float* pMaterial)
{
m_afUsefulConstants[0] = m_pSpeedTree->GetLeafLightingAdjustment();
m_afUsefulConstants[1] = 0.0f;
m_afUsefulConstants[2] = 0.0f;
m_afUsefulConstants[3] = 0.0f;
m_prBranch.SetShaderUsefulConstant( c_nVertexShader_LeafLightingAdjustment, m_afUsefulConstants, 1 );
m_prFrond.SetShaderUsefulConstant ( c_nVertexShader_LeafLightingAdjustment, m_afUsefulConstants, 1 );
m_prLeaf.SetShaderUsefulConstant ( c_nVertexShader_LeafLightingAdjustment, m_afUsefulConstants, 1 );
#ifdef WRAPPER_BILLBOARD_MODE
m_prBillboard.SetShaderUsefulConstant ( c_nVertexShader_LeafLightingAdjustment, m_afUsefulConstants, 1);
#endif
m_afMaterial[0] = pMaterial[0];
m_afMaterial[1] = pMaterial[1];
m_afMaterial[2] = pMaterial[2];
m_afMaterial[3] = 1.f; //m_afMaterial[3] = 1.f;
m_afMaterial[4] = pMaterial[3];
m_afMaterial[5] = pMaterial[4];
m_afMaterial[6] = pMaterial[5];
m_afMaterial[7] = 1.f; //m_afMaterial[7] = 1.0f;
m_prBranch.SetShaderMaterial( c_nVertexShader_Material, m_afMaterial, 2 );
m_prFrond.SetShaderMaterial ( c_nVertexShader_Material, m_afMaterial, 2 );
m_prLeaf.SetShaderMaterial ( c_nVertexShader_Material, m_afMaterial, 2 );
#ifdef WRAPPER_BILLBOARD_MODE
m_prBillboard.SetShaderMaterial(c_nVertexShader_Material, m_afMaterial, 2);
#endif
}
////////////////////////////////////////
// Utility
void KSeqSpeedTree::SetCamera(const K3DVector cameraPos, const K3DVector cameraDirection) // CSpeedTree::SetCamera()를 실행한다
{
// 좌표 저장
m_afCameraPos=cameraPos;
m_afCameraDirection=cameraDirection;
// CSpeedTreeRT모듈에 카메라 위치 보내기
float afDirection[3], campos[3];
afDirection[0] = cameraDirection.x;
afDirection[1] = cameraDirection.y;
afDirection[2] = cameraDirection.z;
campos[0] = cameraPos.x;
campos[1] = cameraPos.y;
campos[2] = cameraPos.z;
CSpeedTreeRT::SetCamera(campos, afDirection);
}
void KSeqSpeedTree::SetCameraTargetPosition(const K3DVector targetPos) // 내부적으로 camera target위치를 저장한다 (카메라 가리는 나무 반투명 처리용)
{
m_afCameraTargetPos=targetPos;
}