// 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 //#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(&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(&pVertexBuffer), nVtxSize); #else m_spBranchVertexBuffer->Lock(reinterpret_cast(&pVertexBuffer), nVtxSize, D3DLOCK_NOSYSLOCK | D3DLOCK_DISCARD); #endif assert(pVertexBuffer && "m_spBranchVertexBuffer->Lock(reinterpret_cast(&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(&pIndexBuffer), nIdxSize); assert(pIndexBuffer && "m_spBranchIndexBuffer->Lock( reinterpret_cast(&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(&pVertexBuffer), nVtxSize); #else m_spFrondVertexBuffer->Lock(reinterpret_cast(&pVertexBuffer), nVtxSize, D3DLOCK_NOSYSLOCK | D3DLOCK_DISCARD); #endif assert(pVertexBuffer && "m_spFrondVertexBuffer->Lock(reinterpret_cast(&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(&pIndexBuffer), nIdxSize); assert(pIndexBuffer && "m_spFrondIndexBufferArray[i]->Lock(reinterpret_cast(&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(&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(&pVertexBuffer), nVtxSize ); #else m_spLeafVertexBufferArray[unLod]->Lock( reinterpret_cast(&pVertexBuffer), nVtxSize, D3DLOCK_NOSYSLOCK | D3DLOCK_DISCARD ); #endif assert(pVertexBuffer && "m_spLeafVertexBufferArray[unLod]->Lock( reinterpret_cast(&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; }