Game client codebase including: - CharacterActionControl: Character and creature management - GlobalScript: Network, items, skills, quests, utilities - RYLClient: Main client application with GUI and event handlers - Engine: 3D rendering engine (RYLGL) - MemoryManager: Custom memory allocation - Library: Third-party dependencies (DirectX, boost, etc.) - Tools: Development utilities 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1222 lines
29 KiB
C++
1222 lines
29 KiB
C++
// Z3DMultipartSkin.cpp: implementation of the CZ3DMultipartSkin class.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
//#include "FunctionPerformanceCheck.h"
|
|
|
|
|
|
#include "Z3DMultipartSkin.h"
|
|
#include "Vertex.h"
|
|
//#include "BaseDataDefine.h"
|
|
#include "RenderOption.h"
|
|
#include "GMMemory.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// LOD 레벨당 몇 프레임에 한번씩 blending 계산을 할 것인지 결정할때 쓰이는 테이블
|
|
long CZ3DMultipartSkin::ms_alAniLODFrameTable[Z3D_LOD_LEVEL] = { 1, 3, 5, 10 };
|
|
|
|
|
|
bool CZ3DMultipartSkin::SetMesh( const char* szMeshName )
|
|
{
|
|
if( this != m_rpThis )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
int id;
|
|
int nPartId;
|
|
|
|
//H3DMeshTag tagMesh;
|
|
//g_ContLODMesh.GetObject( tagMesh, szMeshName );
|
|
//nPartId = tagMesh.GetObject()->GetId();
|
|
|
|
Z3DLODMesh* pMesh;
|
|
pMesh = g_ContLODMesh.GetObject( szMeshName );
|
|
nPartId = pMesh->GetId();
|
|
|
|
id = GetPortionIndex( nPartId );
|
|
if( -1 == id ) // 잘못된 id
|
|
{
|
|
// 현재 CBaseCacheMgr 은 release 관련 메소드가 없다
|
|
//tagMesh.Release();
|
|
return false;
|
|
}
|
|
if( m_apPortion[id]->SetMesh( nPartId, pMesh ) )
|
|
//if( m_apPortion[id]->SetMesh( nPartId, tagMesh ) )
|
|
{
|
|
if( !m_bIsBatchMode )
|
|
{
|
|
m_lAniLODCounter = 0; // 메쉬가 바뀌었을 경우 blending 재계산이 필요하므로
|
|
m_apPortion[id]->BuildMesh( GetDevice() );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
bool CZ3DMultipartSkin::SetTex( const char* szTexName, const char* szTex2Name )
|
|
{
|
|
if( this != m_rpThis )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
int id;
|
|
int nPartId;
|
|
|
|
H3DTexPieceTag tagTexPiece;
|
|
g_ContTexturePiece.GetObject( tagTexPiece, szTexName );
|
|
nPartId = tagTexPiece.GetObject()->GetId();
|
|
id = GetPortionIndex( nPartId );
|
|
if( -1 == id ) // 잘못된 id
|
|
{
|
|
tagTexPiece.Release();
|
|
return false;
|
|
}
|
|
|
|
if( !m_bIsBatchMode )
|
|
{
|
|
// 텍스처가 비어 있을때 null 텍스처 생성
|
|
if( true == m_apPortion[id]->m_pTexture->IsEmpty() )
|
|
{
|
|
if( 0 == id )
|
|
{
|
|
// if( false == m_apPortion[id]->m_pTexture->Load( "NULL_512x512.dds" ) )
|
|
// {
|
|
// _ASSERT(false); // error reading default texture!
|
|
// return false;
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// if( false == m_apPortion[id]->m_pTexture->Load( "NULL_256x512.dds" ) )
|
|
// {
|
|
// _ASSERT(false); // error reading default texture!
|
|
// return false;
|
|
// }
|
|
}
|
|
}
|
|
}
|
|
|
|
if( m_apPortion[id]->SetTexPiece( nPartId, tagTexPiece ) )
|
|
{
|
|
if( !m_bIsBatchMode )
|
|
{
|
|
tagTexPiece.GetObject()->Blt2Texture( m_apPortion[id]->m_pTexture->GetD3dTexture() );
|
|
}
|
|
}
|
|
|
|
// secondary texture 처리
|
|
if( NULL == szTex2Name )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
g_ContTexturePiece.GetObject( tagTexPiece, szTex2Name );
|
|
nPartId = tagTexPiece.GetObject()->GetId();
|
|
id = GetPortionIndex( nPartId );
|
|
if( -1 == id ) // 잘못된 id
|
|
{
|
|
tagTexPiece.Release();
|
|
return false;
|
|
}
|
|
|
|
if( !m_bIsBatchMode )
|
|
{
|
|
// 텍스처가 비어 있을때 null 텍스처 생성
|
|
if( true == m_apPortion[id]->m_pTexture2->IsEmpty() )
|
|
{
|
|
if( 0 == id )
|
|
{
|
|
// if( false == m_apPortion[id]->m_pTexture2->Load( "BUMP_512x512.dds" ) )
|
|
// {
|
|
// _ASSERT(false); // error reading default texture!
|
|
// return false;
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// if( false == m_apPortion[id]->m_pTexture2->Load( "BUMP_256x512.dds" ) )
|
|
// {
|
|
// _ASSERT(false); // error reading default texture!
|
|
// return false;
|
|
// }
|
|
}
|
|
}
|
|
}
|
|
|
|
if( m_apPortion[id]->SetTexPiece2( nPartId, tagTexPiece ) )
|
|
{
|
|
if( !m_bIsBatchMode )
|
|
{
|
|
tagTexPiece.GetObject()->Blt2Texture( m_apPortion[id]->m_pTexture2->GetD3dTexture() );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int CZ3DMultipartSkin::GetIdFromMeshName( char* szMeshName )
|
|
{
|
|
char* pNumberBegin = strrchr( szMeshName, '_' );
|
|
|
|
if( NULL == pNumberBegin )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
++pNumberBegin; // 숫자는 '_' 바로 다음 문자부터 시작이므로
|
|
|
|
char* pNumberEnd = strrchr( szMeshName, '.' );
|
|
|
|
if( NULL == pNumberEnd )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int nNumLen = pNumberEnd - pNumberBegin;
|
|
if( nNumLen < 0 )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
char szTmp[10];
|
|
|
|
strncpy( szTmp, pNumberBegin, nNumLen );
|
|
szTmp[nNumLen] = '\0';
|
|
|
|
return atoi( szTmp );
|
|
}
|
|
|
|
|
|
bool CZ3DMultipartSkin::SetMeshTexture( const char* szMeshName, const char* szTextureName, const char* szTexture2Name, long lGradeEffectIndex, long lGlowIndex )
|
|
{
|
|
if( this != m_rpThis )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
//DeclareBlockTimingCheck("mesh GetObject", aa);
|
|
//DeclareBlockTimingCheck("tex1 GetObject", bb);
|
|
//DeclareBlockTimingCheck("tex2 GetObject", cc);
|
|
|
|
int id;
|
|
int nPartId;
|
|
|
|
Z3DLODMesh* pMesh;
|
|
|
|
// H3DMeshTag tagMesh;
|
|
//BlockTimingCheckStart(aa);
|
|
//g_ContLODMesh.GetObject( tagMesh, szMeshName );
|
|
pMesh = g_ContLODMesh.GetObject( szMeshName );
|
|
|
|
//BlockTimingCheckStop(aa);
|
|
//nPartId = tagMesh.GetObject()->GetId();
|
|
nPartId = GetIdFromMeshName(const_cast<char*>(szMeshName));
|
|
|
|
id = GetPortionIndex( nPartId );
|
|
if( -1 == id ) // 잘못된 id
|
|
{
|
|
// 릴리즈
|
|
//tagMesh.Release();
|
|
return false;
|
|
}
|
|
|
|
m_apPortion[id]->SetGradeEffectIndex( nPartId, lGradeEffectIndex );
|
|
m_apPortion[id]->SetGlowIndex( nPartId, lGlowIndex );
|
|
|
|
if( m_apPortion[id]->SetMesh( nPartId, pMesh ) )
|
|
//if( m_apPortion[id]->SetMesh( nPartId, tagMesh ) )
|
|
{
|
|
if( !m_bIsBatchMode )
|
|
{
|
|
m_lAniLODCounter = 0; // 메쉬가 바뀌었을 경우 blending 재계산이 필요하므로
|
|
|
|
m_apPortion[id]->BuildMesh( GetDevice() );
|
|
|
|
}
|
|
}
|
|
|
|
Z3DTexture* pTexture;
|
|
// H3DTextureTag tagTexture;
|
|
if( NULL == szTextureName )
|
|
{
|
|
m_apPortion[id]->DeleteTexture( nPartId );
|
|
}
|
|
else
|
|
{
|
|
//BlockTimingCheckStart(bb);
|
|
pTexture = g_ContTexture.GetObject( szTextureName );
|
|
//g_ContTexture.GetObject( tagTexture, szTextureName );
|
|
//BlockTimingCheckStop(bb);
|
|
m_apPortion[id]->SetTexture( nPartId, pTexture );
|
|
/* if( NULL == tagTexture.GetObject() )
|
|
{
|
|
WRONG_WAY( "Texture file not found!" );
|
|
}
|
|
m_apPortion[id]->SetTexture( nPartId, tagTexture );*/
|
|
|
|
}
|
|
|
|
if( NULL == szTexture2Name )
|
|
{
|
|
m_apPortion[id]->DeleteTexture2( nPartId );
|
|
return true;
|
|
}
|
|
|
|
//BlockTimingCheckStart(cc);
|
|
pTexture = g_ContTexture.GetObject( szTexture2Name );
|
|
//BlockTimingCheckStop(cc);
|
|
|
|
return m_apPortion[id]->SetTexture2( nPartId, pTexture );
|
|
/*
|
|
//BlockTimingCheckStart(cc);
|
|
g_ContTexture.GetObject( tagTexture, szTexture2Name );
|
|
//BlockTimingCheckStop(cc);
|
|
if( NULL == tagTexture.GetObject() )
|
|
{
|
|
WRONG_WAY( "Texture file not found!" );
|
|
}
|
|
|
|
return m_apPortion[id]->SetTexture2( nPartId, tagTexture );*/
|
|
}
|
|
|
|
|
|
bool CZ3DMultipartSkin::DeleteMesh( int nPartId )
|
|
{
|
|
if( this != m_rpThis )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
int id = GetPortionIndex( nPartId );
|
|
if( -1 == id )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if( m_apPortion[id]->DeleteMesh( nPartId ) )
|
|
{
|
|
if( !m_bIsBatchMode )
|
|
{
|
|
m_apPortion[id]->BuildMesh( GetDevice() );
|
|
m_lAniLODCounter = 0; // 메쉬가 바뀌었을 경우 blending 재계산이 필요하므로
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CZ3DMultipartSkin::DeleteTex( int nPartId )
|
|
{
|
|
if( this != m_rpThis )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
int id = GetPortionIndex( nPartId );
|
|
if( -1 == id )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if( m_apPortion[id]->DeleteTexPiece( nPartId ) )
|
|
{
|
|
if( !m_bIsBatchMode )
|
|
{
|
|
if( m_apPortion[id]->m_map_IdTexPieceTag.empty() )
|
|
{
|
|
m_apPortion[id]->m_pTexture->Flush();
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
bool CZ3DMultipartSkin::BatchOpen()
|
|
{
|
|
if( this != m_rpThis )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
//_ASSERTE( !m_bIsBatchMode );
|
|
if( m_bIsBatchMode )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// batchopen으로 값 리셋하는 부분은 build mesh에 모두 포함되므로, 따로 호출하지 않는다.
|
|
/*for( int i = 0; i < Z3D_MULTIPART_PORTION_COUNT; i++ )
|
|
{
|
|
m_apPortion[i]->BatchOpen();
|
|
}*/
|
|
|
|
m_bIsBatchMode = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool CZ3DMultipartSkin::BatchClose()
|
|
{
|
|
if( this != m_rpThis )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
//_ASSERTE( m_bIsBatchMode );
|
|
if( false == m_bIsBatchMode )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
for( int i = 0; i < Z3D_MULTIPART_PORTION_COUNT; i++ )
|
|
{
|
|
if( Z3D_MPT_TEXPIECE == m_MPT )
|
|
{
|
|
if( m_apPortion[i]->m_map_IdTexPieceTag.empty() )
|
|
{
|
|
m_apPortion[i]->m_pTexture->Flush();
|
|
}
|
|
else if( m_apPortion[i]->m_pTexture->IsEmpty() )
|
|
{
|
|
// if( 0 == i )
|
|
// {
|
|
// if( false == m_apPortion[i]->m_pTexture->Load( "NULL_512x512.dds" ) )
|
|
// {
|
|
// return false;
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// if( false == m_apPortion[i]->m_pTexture->Load( "NULL_256x512.dds" ) )
|
|
// {
|
|
// return false;
|
|
// }
|
|
// }
|
|
}
|
|
|
|
if( m_apPortion[i]->m_map_IdTexPieceTag2.empty() )
|
|
{
|
|
m_apPortion[i]->m_pTexture2->Flush();
|
|
}
|
|
else if( m_apPortion[i]->m_pTexture2->IsEmpty() )
|
|
{
|
|
// if( 0 == i )
|
|
// {
|
|
// if( false == m_apPortion[i]->m_pTexture2->Load( "BUMP_512x512.dds" ) )
|
|
// {
|
|
// return false;
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// if( false == m_apPortion[i]->m_pTexture2->Load( "BUMP_256x512.dds" ) )
|
|
// {
|
|
// return false;
|
|
// }
|
|
// }
|
|
}
|
|
}
|
|
|
|
m_apPortion[i]->BatchClose( GetDevice() );
|
|
}
|
|
|
|
m_lAniLODCounter = 0; // 메쉬가 바뀌어 blending 재계산이 필요하므로
|
|
|
|
m_bIsBatchMode = false;
|
|
|
|
return true;
|
|
}
|
|
|
|
vector3 ComputeTangentVector(BumpVertex pVtxA, BumpVertex pVtxB,BumpVertex pVtxC )
|
|
{
|
|
vector3 vAB=pVtxB.v-pVtxA.v;
|
|
vector3 vAC=pVtxC.v-pVtxA.v;
|
|
|
|
vector3 n=pVtxA.n;
|
|
|
|
vector3 vProjAB=vAB-( (n*vAB)*n );
|
|
vector3 vProjAC=vAC-( (n*vAC)*n );
|
|
|
|
float duAB=pVtxB.tu-pVtxA.tu;
|
|
float duAC=pVtxC.tu-pVtxA.tu;
|
|
|
|
float dvAB=pVtxB.tv-pVtxA.tv;
|
|
float dvAC=pVtxC.tv-pVtxA.tv;
|
|
|
|
if( duAC*dvAB > duAB*dvAC )
|
|
{
|
|
duAC=-duAC;
|
|
duAB=-duAB;
|
|
}
|
|
|
|
vector3 vTangent=duAC*vProjAB-duAB*vProjAC;
|
|
|
|
vTangent.Normalize();
|
|
return vTangent;
|
|
|
|
}
|
|
|
|
|
|
void CalcTagentSpaceVector(BumpVertex *pVertices,WORD *pIndices,int cVertex,int cIndices,vector3 *pU)
|
|
{
|
|
memset(pU,0,sizeof(vector3)*cVertex);
|
|
|
|
for(int i=0;i<cIndices*3;i+=3)
|
|
{
|
|
WORD a=pIndices[i+0];
|
|
WORD b=pIndices[i+1];
|
|
WORD c=pIndices[i+2];
|
|
|
|
pU[a]+=ComputeTangentVector(pVertices[a],pVertices[b],pVertices[c]);
|
|
pU[b]+=ComputeTangentVector(pVertices[b],pVertices[a],pVertices[c]);
|
|
pU[c]+=ComputeTangentVector(pVertices[c],pVertices[a],pVertices[b]);
|
|
}
|
|
|
|
for(int i=0;i<cVertex;i++)
|
|
{
|
|
pU[i].Normalize();
|
|
|
|
}
|
|
}
|
|
|
|
|
|
void CZ3DMultipartSkin::ApplyAnimation()
|
|
{
|
|
|
|
if( this != m_rpThis )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( m_bIsBatchMode )
|
|
{
|
|
return;
|
|
}
|
|
for( int i = 0; i < Z3D_MULTIPART_PORTION_COUNT; i++ )
|
|
{
|
|
m_apPortion[i]->CheckLoadedStatus( GetDevice() );
|
|
}
|
|
|
|
|
|
// allocation safety check
|
|
for(int i = 0; i < Z3D_MULTIPART_PORTION_COUNT; ++i )
|
|
{
|
|
if( NULL == m_apPortion[i]->m_pVertexBuffer )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
// bounding box 최소값은 가장 큰 값으로, 최대값은 가장 작은 값으로 초기화
|
|
m_vBoundingBoxMin = vector3( 4.2e9f, 4.2e9f, 4.2e9f );
|
|
m_vBoundingBoxMax = vector3( -4.2e9f, -4.2e9f, -4.2e9f );
|
|
|
|
if( CRenderOption::m_CharacterPerPixelLighting )
|
|
{
|
|
//static bFirstRender=true;
|
|
//static vector3 vecU[2000];
|
|
|
|
|
|
BumpVertex* pVertices; // shortcut to render vertex pool of portion
|
|
Z3DBlend2Vertex* pBlVertex;
|
|
matrix* pMat1,* pMat2; // fixed as 2 for now
|
|
float factor1, factor2;
|
|
int i, j, k, l;
|
|
Z3DLODMesh* pMesh;
|
|
|
|
float f1, f2, f3, f4;
|
|
|
|
// LOD level 구함 : 뼈다구의 root위치를 기준으로 - 차후에 다른 방법으로 바꿀지도?
|
|
// 외부에서 LOD 레벨 설정해주는것으로 바뀜.
|
|
//pMat1 = m_rpSkeleton[0].GetTM();
|
|
int nLODLevel = GetLODLevel();
|
|
|
|
if( 1 )//CheckRecalcByAniLOD() )
|
|
{
|
|
// 원TM의 역행렬을 구해진 ani TM에 곱해준다.
|
|
for( i = 0; i < m_lSkelCount; i++ )
|
|
{
|
|
if( m_bTestMode )
|
|
{
|
|
m_pMatrixPalette[i].MakeIdent();
|
|
}
|
|
else
|
|
{
|
|
m_rpSkeleton[i].GetLocalizedTM( m_pMatrixPalette[i], m_rpSkeletonLocalizer[i] );
|
|
}
|
|
}
|
|
|
|
for( i = 0; i < Z3D_MULTIPART_PORTION_COUNT; i++ )
|
|
{
|
|
if( 0 == m_apPortion[i]->m_vec_pMesh.size() )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
j = 0;
|
|
//pVertices = m_apPortion[i]->m_pVertices;
|
|
// m_apPortion[i]->m_pVertexBuffer->Lock( 0, 0, (BYTE**)(&pVertices), D3DLOCK_DISCARD );
|
|
m_apPortion[i]->m_pVertexBuffer->Lock( 0, 0, (BYTE**)(&pVertices), 0 );
|
|
|
|
for( l = 0; l < (int)m_apPortion[i]->m_vec_pMesh.size(); l++ )
|
|
{
|
|
pMesh = m_apPortion[i]->m_vec_pMesh[l];
|
|
|
|
for( k = 0; k < pMesh->lVertexCount; k++ )
|
|
{
|
|
if( pMesh->pVertices[k].lodLevel >= nLODLevel )
|
|
{
|
|
pBlVertex = &(pMesh->pVertices[k]);
|
|
/*
|
|
// edith 2008.06.19 스켈레탈 처리
|
|
if(m_lSkelCount <= pBlVertex->mtrx_id[0])
|
|
continue;
|
|
else if(m_lSkelCount <= pBlVertex->mtrx_id[1])
|
|
continue;
|
|
*/
|
|
pMat1 = &(m_pMatrixPalette[pBlVertex->mtrx_id[0]]);
|
|
pMat2 = &(m_pMatrixPalette[pBlVertex->mtrx_id[1]]);
|
|
|
|
factor1 = pBlVertex->bfactor;
|
|
factor2 = 1.0f - factor1;
|
|
|
|
f1 = (factor1*pMat1->_11) + (factor2*pMat2->_11);
|
|
f2 = (factor1*pMat1->_21) + (factor2*pMat2->_21);
|
|
f3 = (factor1*pMat1->_31) + (factor2*pMat2->_31);
|
|
f4 = (factor1*pMat1->_41) + (factor2*pMat2->_41);
|
|
pVertices[j].v.x = (pBlVertex->pos.x*f1 + pBlVertex->pos.y*f2 + pBlVertex->pos.z*f3 + f4) * m_fScaleFactor;
|
|
pVertices[j].u.x = (pBlVertex->u.x*f1 + pBlVertex->u.y*f2 + pBlVertex->u.z*f3);
|
|
pVertices[j].n.x = pBlVertex->normal.x*f1 + pBlVertex->normal.y*f2 + pBlVertex->normal.z*f3;
|
|
|
|
f1 = (factor1*pMat1->_12) + (factor2*pMat2->_12);
|
|
f2 = (factor1*pMat1->_22) + (factor2*pMat2->_22);
|
|
f3 = (factor1*pMat1->_32) + (factor2*pMat2->_32);
|
|
f4 = (factor1*pMat1->_42) + (factor2*pMat2->_42);
|
|
pVertices[j].v.y = (pBlVertex->pos.x*f1 + pBlVertex->pos.y*f2 + pBlVertex->pos.z*f3 + f4) * m_fScaleFactor;
|
|
pVertices[j].u.y = (pBlVertex->u.x*f1 + pBlVertex->u.y*f2 + pBlVertex->u.z*f3);
|
|
pVertices[j].n.y = pBlVertex->normal.x*f1 + pBlVertex->normal.y*f2 + pBlVertex->normal.z*f3;
|
|
|
|
f1 = (factor1*pMat1->_13) + (factor2*pMat2->_13);
|
|
f2 = (factor1*pMat1->_23) + (factor2*pMat2->_23);
|
|
f3 = (factor1*pMat1->_33) + (factor2*pMat2->_33);
|
|
f4 = (factor1*pMat1->_43) + (factor2*pMat2->_43);
|
|
pVertices[j].v.z = (pBlVertex->pos.x*f1 + pBlVertex->pos.y*f2 + pBlVertex->pos.z*f3 + f4) * m_fScaleFactor;
|
|
pVertices[j].u.z = (pBlVertex->u.x*f1 + pBlVertex->u.y*f2 + pBlVertex->u.z*f3);
|
|
pVertices[j].n.z = pBlVertex->normal.x*f1 + pBlVertex->normal.y*f2 + pBlVertex->normal.z*f3;
|
|
|
|
pVertices[j].tu = pBlVertex->tu;
|
|
pVertices[j].tv = pBlVertex->tv;
|
|
|
|
// bounding box min/max 값 구함
|
|
m_vBoundingBoxMin.x = min( pVertices[j].v.x, m_vBoundingBoxMin.x );
|
|
m_vBoundingBoxMin.y = min( pVertices[j].v.y, m_vBoundingBoxMin.y );
|
|
m_vBoundingBoxMin.z = min( pVertices[j].v.z, m_vBoundingBoxMin.z );
|
|
|
|
m_vBoundingBoxMax.x = max( pVertices[j].v.x, m_vBoundingBoxMax.x );
|
|
m_vBoundingBoxMax.y = max( pVertices[j].v.y, m_vBoundingBoxMax.y );
|
|
m_vBoundingBoxMax.z = max( pVertices[j].v.z, m_vBoundingBoxMax.z );
|
|
}
|
|
j++;
|
|
}
|
|
}
|
|
|
|
m_apPortion[i]->m_pVertexBuffer->Unlock();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// blending 계산 및 텍스처 세팅, 렌더링
|
|
D3DVERTEX* pVertices; // shortcut to render vertex pool of portion
|
|
Z3DBlend2Vertex* pBlVertex;
|
|
matrix* pMat1,* pMat2; // fixed as 2 for now
|
|
float factor1, factor2;
|
|
int i, j, k, l;
|
|
Z3DLODMesh* pMesh;
|
|
matrix m;
|
|
float f1, f2, f3, f4;
|
|
|
|
// LOD level 구함 : 뼈다구의 root위치를 기준으로 - 차후에 다른 방법으로 바꿀지도?
|
|
// 외부에서 LOD 레벨 설정해주는것으로 바뀜.
|
|
//pMat1 = m_rpSkeleton[0].GetTM();
|
|
int nLODLevel = GetLODLevel();
|
|
|
|
if( 1 )//CheckRecalcByAniLOD() )
|
|
{
|
|
// 원TM의 역행렬을 구해진 ani TM에 곱해준다.
|
|
for( i = 0; i < m_lSkelCount; i++ )
|
|
{
|
|
if( m_bTestMode )
|
|
{
|
|
m_pMatrixPalette[i].MakeIdent();
|
|
}
|
|
else
|
|
{
|
|
m_rpSkeleton[i].GetLocalizedTM( m_pMatrixPalette[i], m_rpSkeletonLocalizer[i] );
|
|
}
|
|
}
|
|
|
|
for( i = 0; i < Z3D_MULTIPART_PORTION_COUNT; i++ )
|
|
{
|
|
if( 0 == m_apPortion[i]->m_vec_pMesh.size() )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
j = 0;
|
|
// m_apPortion[i]->m_pVertexBuffer->Lock( 0, 0, (BYTE**)(&pVertices), D3DLOCK_DISCARD );
|
|
m_apPortion[i]->m_pVertexBuffer->Lock( 0, 0, (BYTE**)(&pVertices), 0 );
|
|
|
|
for( l = 0; l < (int)m_apPortion[i]->m_vec_pMesh.size(); l++ )
|
|
{
|
|
pMesh = m_apPortion[i]->m_vec_pMesh[l];
|
|
|
|
for( k = 0; k < pMesh->lVertexCount; k++ )
|
|
{
|
|
if( pMesh->pVertices[k].lodLevel >= nLODLevel )
|
|
{
|
|
pBlVertex = &(pMesh->pVertices[k]);
|
|
/*
|
|
// edith 스킨
|
|
// edith 2008.06.19 스켈레탈 처리
|
|
if(m_lSkelCount <= pBlVertex->mtrx_id[0])
|
|
continue;
|
|
else if(m_lSkelCount <= pBlVertex->mtrx_id[1])
|
|
continue;
|
|
*/
|
|
pMat1 = &(m_pMatrixPalette[pBlVertex->mtrx_id[0]]);
|
|
pMat2 = &(m_pMatrixPalette[pBlVertex->mtrx_id[1]]);
|
|
|
|
factor1 = pBlVertex->bfactor;
|
|
factor2 = 1.0f - factor1;
|
|
|
|
f1 = (factor1*pMat1->_11) + (factor2*pMat2->_11);
|
|
f2 = (factor1*pMat1->_21) + (factor2*pMat2->_21);
|
|
f3 = (factor1*pMat1->_31) + (factor2*pMat2->_31);
|
|
f4 = (factor1*pMat1->_41) + (factor2*pMat2->_41);
|
|
pVertices[j].x = (pBlVertex->pos.x*f1 + pBlVertex->pos.y*f2 + pBlVertex->pos.z*f3 + f4) * m_fScaleFactor;
|
|
pVertices[j].nx = pBlVertex->normal.x*f1 + pBlVertex->normal.y*f2 + pBlVertex->normal.z*f3;
|
|
|
|
f1 = (factor1*pMat1->_12) + (factor2*pMat2->_12);
|
|
f2 = (factor1*pMat1->_22) + (factor2*pMat2->_22);
|
|
f3 = (factor1*pMat1->_32) + (factor2*pMat2->_32);
|
|
f4 = (factor1*pMat1->_42) + (factor2*pMat2->_42);
|
|
pVertices[j].y = (pBlVertex->pos.x*f1 + pBlVertex->pos.y*f2 + pBlVertex->pos.z*f3 + f4) * m_fScaleFactor;
|
|
pVertices[j].ny = pBlVertex->normal.x*f1 + pBlVertex->normal.y*f2 + pBlVertex->normal.z*f3;
|
|
|
|
f1 = (factor1*pMat1->_13) + (factor2*pMat2->_13);
|
|
f2 = (factor1*pMat1->_23) + (factor2*pMat2->_23);
|
|
f3 = (factor1*pMat1->_33) + (factor2*pMat2->_33);
|
|
f4 = (factor1*pMat1->_43) + (factor2*pMat2->_43);
|
|
pVertices[j].z = (pBlVertex->pos.x*f1 + pBlVertex->pos.y*f2 + pBlVertex->pos.z*f3 + f4) * m_fScaleFactor;
|
|
pVertices[j].nz = pBlVertex->normal.x*f1 + pBlVertex->normal.y*f2 + pBlVertex->normal.z*f3;
|
|
|
|
pVertices[j].tu = pBlVertex->tu;
|
|
pVertices[j].tv = pBlVertex->tv;
|
|
|
|
// bounding box min/max 값 구함
|
|
m_vBoundingBoxMin.x = min( pVertices[j].x, m_vBoundingBoxMin.x );
|
|
m_vBoundingBoxMin.y = min( pVertices[j].y, m_vBoundingBoxMin.y );
|
|
m_vBoundingBoxMin.z = min( pVertices[j].z, m_vBoundingBoxMin.z );
|
|
|
|
m_vBoundingBoxMax.x = max( pVertices[j].x, m_vBoundingBoxMax.x );
|
|
m_vBoundingBoxMax.y = max( pVertices[j].y, m_vBoundingBoxMax.y );
|
|
m_vBoundingBoxMax.z = max( pVertices[j].z, m_vBoundingBoxMax.z );
|
|
}
|
|
j++;
|
|
}
|
|
}
|
|
|
|
m_apPortion[i]->m_pVertexBuffer->Unlock();
|
|
}
|
|
}
|
|
}
|
|
|
|
m_vBoundingBoxMin += m_vPivotPos;
|
|
m_vBoundingBoxMax += m_vPivotPos;
|
|
}
|
|
|
|
|
|
void CZ3DMultipartSkin::Render()
|
|
{
|
|
if( this != m_rpThis )
|
|
{
|
|
return;
|
|
}
|
|
|
|
int i, j;
|
|
int nLODLevel = GetLODLevel();
|
|
|
|
for( i = 0; i < Z3D_MULTIPART_PORTION_COUNT; ++i )
|
|
{
|
|
if( NULL == m_apPortion[i]->m_pVertexBuffer )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( NULL == m_apPortion[i]->m_apIndexBuffer[nLODLevel] )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
if( m_bIsBatchMode )
|
|
{
|
|
return;
|
|
}
|
|
|
|
long lVertexOffset, lIndexOffset;
|
|
Z3DLODMesh* pMesh = NULL;
|
|
|
|
if(CRenderOption::m_CharacterPerPixelLighting)
|
|
{
|
|
//GetDevice()->SetVertexShader( BUMPVERTEXFVF );
|
|
}
|
|
else
|
|
{
|
|
GetDevice()->SetVertexShader( D3DFVF_VERTEX );
|
|
}
|
|
|
|
matrix m;
|
|
m.MakeIdent();
|
|
m._41 = m_vPivotPos.x;
|
|
m._42 = m_vPivotPos.y;
|
|
m._43 = m_vPivotPos.z;
|
|
GetDevice()->SetTransform( D3DTS_WORLD, m );
|
|
|
|
for( i = 0; i < Z3D_MULTIPART_PORTION_COUNT; i++ )
|
|
{
|
|
if( m_apPortion[i]->m_alIndexCount[nLODLevel] )
|
|
{
|
|
if( Z3D_MPT_TEXPIECE == m_apPortion[i]->m_MPT )
|
|
{
|
|
GetDevice()->SetTexture( 0, m_apPortion[i]->m_pTexture->GetD3dTexture() );
|
|
GetDevice()->SetTexture( 1, m_apPortion[i]->m_pTexture2->GetD3dTexture() );
|
|
}
|
|
|
|
if(CRenderOption::m_CharacterPerPixelLighting)
|
|
{
|
|
GetDevice()->SetStreamSource( 0, m_apPortion[i]->m_pVertexBuffer, sizeof(BumpVertex) );
|
|
}
|
|
else
|
|
{
|
|
GetDevice()->SetStreamSource( 0, m_apPortion[i]->m_pVertexBuffer, sizeof(D3DVERTEX) );
|
|
}
|
|
GetDevice()->SetIndices( m_apPortion[i]->m_apIndexBuffer[nLODLevel], 0 );
|
|
|
|
lVertexOffset = 0;
|
|
lIndexOffset = 0;
|
|
for( j = 0; j < (int)m_apPortion[i]->m_vec_pMesh.size(); ++j )
|
|
{
|
|
pMesh = m_apPortion[i]->m_vec_pMesh[j];
|
|
if( pMesh->aIndex[nLODLevel].lIndexCount )
|
|
{
|
|
|
|
if( Z3D_MPT_TEXTURE == m_apPortion[i]->m_MPT )
|
|
{
|
|
if( m_apPortion[i]->m_vec_pTexture[j] )
|
|
{
|
|
GetDevice()->SetTexture( 0, m_apPortion[i]->m_vec_pTexture[j]->GetD3dTexture() );
|
|
}
|
|
else
|
|
{
|
|
GetDevice()->SetTexture( 0, NULL );
|
|
}
|
|
// if( m_apPortion[i]->m_vec_pTexture2[j] )
|
|
// {
|
|
// GetDevice()->SetTexture( 1, *(m_apPortion[i]->m_vec_pTexture2[j]) );
|
|
// }
|
|
// else
|
|
// {
|
|
// GetDevice()->SetTexture( 1, NULL );
|
|
// }
|
|
}
|
|
|
|
|
|
//static int nTexTransformCounter = 0;
|
|
//int cTemp = (nTexTransformCounter < 1200) ? 384*sinf(3.1415926535f*nTexTransformCounter/1200.0f) : 0;
|
|
//if( cTemp > 255 ) cTemp = 255;
|
|
//GetDevice()->SetRenderState( D3DRS_TEXTUREFACTOR, D3DCOLOR_ARGB( cTemp, 0, cTemp, 0 ) );
|
|
////GetDevice()->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
|
|
////GetDevice()->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
|
|
//if( ++nTexTransformCounter == 2000 )
|
|
//{
|
|
// nTexTransformCounter = 0;
|
|
//}
|
|
|
|
m_apPortion[i]->m_vec_pGradeEffectHandler[j]->ApplySetting( GetDevice() );
|
|
|
|
HRESULT hr = GetDevice()->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, lVertexOffset,
|
|
pMesh->lVertexCount, lIndexOffset,
|
|
(pMesh->aIndex[nLODLevel].lIndexCount)/3 );
|
|
|
|
}
|
|
lVertexOffset += pMesh->lVertexCount;
|
|
lIndexOffset += pMesh->aIndex[nLODLevel].lIndexCount;
|
|
}
|
|
}
|
|
}
|
|
IncreaseAniLODCounter();
|
|
}
|
|
|
|
|
|
void CZ3DMultipartSkin::RenderShadow( IDirect3DDevice8* pDevice, DWORD vertexShader, int nLevel )
|
|
{
|
|
if( this != m_rpThis )
|
|
{
|
|
return;
|
|
}
|
|
|
|
int i, j;
|
|
// int nLODLevel = ( -1 == nLevel ) ? ( (m_lLODLevel+Z3D_LOD_LEVEL-1)/2 ) : min( Z3D_LOD_LEVEL, nLevel );
|
|
int nLODLevel = ( -1 == nLevel ) ? m_lLODLevel : min( Z3D_LOD_LEVEL, nLevel );
|
|
|
|
|
|
for( i = 0; i < Z3D_MULTIPART_PORTION_COUNT; ++i )
|
|
{
|
|
if( NULL == m_apPortion[i]->m_pVertexBuffer )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( NULL == m_apPortion[i]->m_apIndexBuffer[nLODLevel] )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
//_ASSERTE( !m_bIsBatchMode );
|
|
|
|
if( NULL != vertexShader )
|
|
{
|
|
if( 0xFFFFFFFF == vertexShader )
|
|
{
|
|
if(CRenderOption::m_CharacterPerPixelLighting)
|
|
{
|
|
GetDevice()->SetVertexShader( BUMPVERTEXFVF );
|
|
}
|
|
else
|
|
{
|
|
GetDevice()->SetVertexShader( D3DFVF_VERTEX );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GetDevice()->SetVertexShader( vertexShader );
|
|
}
|
|
}
|
|
|
|
matrix m;
|
|
m.MakeIdent();
|
|
m._41 = m_vPivotPos.x;
|
|
m._42 = m_vPivotPos.y;
|
|
m._43 = m_vPivotPos.z;
|
|
GetDevice()->SetTransform( D3DTS_WORLD, m );
|
|
|
|
Z3DLODMesh* pMesh;
|
|
|
|
|
|
long lVertexOffset, lIndexOffset;
|
|
for( i = 0; i < Z3D_MULTIPART_PORTION_COUNT; i++ )
|
|
{
|
|
if( m_apPortion[i]->m_alIndexCount[nLODLevel] )
|
|
{
|
|
if(CRenderOption::m_CharacterPerPixelLighting)
|
|
{
|
|
GetDevice()->SetStreamSource( 0, m_apPortion[i]->m_pVertexBuffer, sizeof(BumpVertex) );
|
|
}
|
|
else
|
|
{
|
|
GetDevice()->SetStreamSource( 0, m_apPortion[i]->m_pVertexBuffer, sizeof(D3DVERTEX) );
|
|
}
|
|
|
|
lVertexOffset = 0;
|
|
lIndexOffset = 0;
|
|
for( j = 0; j < (int)m_apPortion[i]->m_vec_pMesh.size(); ++j )
|
|
{
|
|
pMesh = m_apPortion[i]->m_vec_pMesh[j];
|
|
if( pMesh->aIndex[nLODLevel].lIndexCount )
|
|
{
|
|
GetDevice()->SetIndices( m_apPortion[i]->m_apIndexBuffer[nLODLevel], 0 );
|
|
|
|
GetDevice()->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, lVertexOffset,
|
|
pMesh->lVertexCount, lIndexOffset,
|
|
(pMesh->aIndex[nLODLevel].lIndexCount)/3 );
|
|
}
|
|
lVertexOffset += pMesh->lVertexCount;
|
|
lIndexOffset += pMesh->aIndex[nLODLevel].lIndexCount;
|
|
}
|
|
|
|
GetDevice()->SetStreamSource( 0, NULL, 0 );
|
|
GetDevice()->SetIndices( NULL, 0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CZ3DMultipartSkin::RenderGlowShape( IDirect3DDevice8* pDevice )
|
|
{
|
|
if( this != m_rpThis )
|
|
{
|
|
return;
|
|
}
|
|
|
|
int i, j;
|
|
|
|
for( i = 0; i < Z3D_MULTIPART_PORTION_COUNT; ++i )
|
|
{
|
|
if( NULL == m_apPortion[i]->m_pVertexBuffer )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( NULL == m_apPortion[i]->m_apIndexBuffer[m_lLODLevel] )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
//_ASSERTE( !m_bIsBatchMode );
|
|
|
|
GetDevice()->SetVertexShader( D3DFVF_VERTEX );
|
|
|
|
matrix m;
|
|
m.MakeIdent();
|
|
m._41 = m_vPivotPos.x;
|
|
m._42 = m_vPivotPos.y;
|
|
m._43 = m_vPivotPos.z;
|
|
GetDevice()->SetTransform( D3DTS_WORLD, m );
|
|
|
|
Z3DLODMesh* pMesh;
|
|
|
|
|
|
long lVertexOffset, lIndexOffset;
|
|
for( i = 0; i < Z3D_MULTIPART_PORTION_COUNT; i++ )
|
|
{
|
|
if( m_apPortion[i]->m_alIndexCount[m_lLODLevel] )
|
|
{
|
|
GetDevice()->SetStreamSource( 0, m_apPortion[i]->m_pVertexBuffer, sizeof(D3DVERTEX) );
|
|
|
|
lVertexOffset = 0;
|
|
lIndexOffset = 0;
|
|
for( j = 0; j < (int)m_apPortion[i]->m_vec_pMesh.size(); ++j )
|
|
{
|
|
pMesh = m_apPortion[i]->m_vec_pMesh[j];
|
|
m_apPortion[i]->m_vec_pGlowHandler[j]->ApplySetting( GetDevice() );
|
|
if( pMesh->aIndex[m_lLODLevel].lIndexCount )
|
|
{
|
|
GetDevice()->SetIndices( m_apPortion[i]->m_apIndexBuffer[m_lLODLevel], 0 );
|
|
|
|
GetDevice()->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, lVertexOffset,
|
|
pMesh->lVertexCount, lIndexOffset,
|
|
(pMesh->aIndex[m_lLODLevel].lIndexCount)/3 );
|
|
}
|
|
lVertexOffset += pMesh->lVertexCount;
|
|
lIndexOffset += pMesh->aIndex[m_lLODLevel].lIndexCount;
|
|
}
|
|
|
|
GetDevice()->SetStreamSource( 0, NULL, 0 );
|
|
GetDevice()->SetIndices( NULL, 0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CZ3DMultipartSkin::GetBoundingBox( vector3& r_vmin, vector3& r_vmax )
|
|
{
|
|
if( this != m_rpThis )
|
|
{
|
|
return;
|
|
}
|
|
|
|
int i, j;
|
|
r_vmin = vector3( 0, 0, 0 );
|
|
r_vmax = vector3( 0, 0, 0 );
|
|
|
|
D3DVERTEXBUFFER_DESC vd;
|
|
|
|
if(CRenderOption::m_CharacterPerPixelLighting)
|
|
{
|
|
BumpVertex* pVertices;
|
|
|
|
for( i = 0; i < Z3D_MULTIPART_PORTION_COUNT; i++ )
|
|
{
|
|
if( 0 == m_apPortion[i]->m_vec_pMesh.size() )
|
|
{
|
|
continue;
|
|
}
|
|
// allocation safety check
|
|
if( NULL == m_apPortion[i]->m_pVertexBuffer )
|
|
{
|
|
continue;
|
|
}
|
|
m_apPortion[i]->m_pVertexBuffer->GetDesc( &vd );
|
|
// m_apPortion[i]->m_pVertexBuffer->Lock( 0, 0, (BYTE**)(&pVertices), D3DLOCK_DISCARD );
|
|
m_apPortion[i]->m_pVertexBuffer->Lock( 0, 0, (BYTE**)(&pVertices), 0 );
|
|
|
|
for( j = 0; j < (int)(vd.Size/sizeof(BumpVertex)); ++j )
|
|
{
|
|
if( pVertices[j].v.x < r_vmin.x )
|
|
{
|
|
r_vmin.x = pVertices[j].v.x;
|
|
}
|
|
if( pVertices[j].v.y < r_vmin.y )
|
|
{
|
|
r_vmin.y = pVertices[j].v.y;
|
|
}
|
|
if( pVertices[j].v.z < r_vmin.z )
|
|
{
|
|
r_vmin.z = pVertices[j].v.z;
|
|
}
|
|
|
|
if( pVertices[j].v.x > r_vmax.x )
|
|
{
|
|
r_vmax.x = pVertices[j].v.x;
|
|
}
|
|
if( pVertices[j].v.y > r_vmax.y )
|
|
{
|
|
r_vmax.y = pVertices[j].v.y;
|
|
}
|
|
if( pVertices[j].v.z > r_vmax.z )
|
|
{
|
|
r_vmax.z = pVertices[j].v.z;
|
|
}
|
|
}
|
|
|
|
m_apPortion[i]->m_pVertexBuffer->Unlock();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
D3DVERTEX* pVertices;
|
|
|
|
for( i = 0; i < Z3D_MULTIPART_PORTION_COUNT; i++ )
|
|
{
|
|
if( 0 == m_apPortion[i]->m_vec_pMesh.size() )
|
|
{
|
|
continue;
|
|
}
|
|
// allocation safety check
|
|
if( NULL == m_apPortion[i]->m_pVertexBuffer )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
m_apPortion[i]->m_pVertexBuffer->GetDesc( &vd );
|
|
// m_apPortion[i]->m_pVertexBuffer->Lock( 0, 0, (BYTE**)(&pVertices), D3DLOCK_DISCARD );
|
|
m_apPortion[i]->m_pVertexBuffer->Lock( 0, 0, (BYTE**)(&pVertices), 0 );
|
|
|
|
for( j = 0; j < (int)(vd.Size/sizeof(D3DVERTEX)); ++j )
|
|
{
|
|
if( pVertices[j].x < r_vmin.x )
|
|
{
|
|
r_vmin.x = pVertices[j].x;
|
|
}
|
|
if( pVertices[j].y < r_vmin.y )
|
|
{
|
|
r_vmin.y = pVertices[j].y;
|
|
}
|
|
if( pVertices[j].z < r_vmin.z )
|
|
{
|
|
r_vmin.z = pVertices[j].z;
|
|
}
|
|
|
|
if( pVertices[j].x > r_vmax.x )
|
|
{
|
|
r_vmax.x = pVertices[j].x;
|
|
}
|
|
if( pVertices[j].y > r_vmax.y )
|
|
{
|
|
r_vmax.y = pVertices[j].y;
|
|
}
|
|
if( pVertices[j].z > r_vmax.z )
|
|
{
|
|
r_vmax.z = pVertices[j].z;
|
|
}
|
|
}
|
|
|
|
m_apPortion[i]->m_pVertexBuffer->Unlock();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CZ3DMultipartSkin::GetProcessedVertex( Z3DBlend2Vertex& v_in, vector3& v_out ) const
|
|
{
|
|
if( this != m_rpThis )
|
|
{
|
|
return;
|
|
}
|
|
|
|
matrix m2[2];
|
|
|
|
m_rpSkeleton[v_in.mtrx_id[0]].GetLocalizedTM( m2[0], m_rpSkeletonLocalizer[v_in.mtrx_id[0]] );
|
|
m_rpSkeleton[v_in.mtrx_id[1]].GetLocalizedTM( m2[1], m_rpSkeletonLocalizer[v_in.mtrx_id[1]] );
|
|
|
|
float factor1 = v_in.bfactor;
|
|
float factor2 = 1.0f - factor1;
|
|
|
|
float f1 = (factor1*m2[0]._11) + (factor2*m2[1]._11);
|
|
float f2 = (factor1*m2[0]._21) + (factor2*m2[1]._21);
|
|
float f3 = (factor1*m2[0]._31) + (factor2*m2[1]._31);
|
|
float f4 = (factor1*m2[0]._41) + (factor2*m2[1]._41);
|
|
v_out.x = (v_in.pos.x*f1 + v_in.pos.y*f2 + v_in.pos.z*f3 + f4);
|
|
|
|
f1 = (factor1*m2[0]._12) + (factor2*m2[1]._12);
|
|
f2 = (factor1*m2[0]._22) + (factor2*m2[1]._22);
|
|
f3 = (factor1*m2[0]._32) + (factor2*m2[1]._32);
|
|
f4 = (factor1*m2[0]._42) + (factor2*m2[1]._42);
|
|
v_out.y = (v_in.pos.x*f1 + v_in.pos.y*f2 + v_in.pos.z*f3 + f4);
|
|
|
|
f1 = (factor1*m2[0]._13) + (factor2*m2[1]._13);
|
|
f2 = (factor1*m2[0]._23) + (factor2*m2[1]._23);
|
|
f3 = (factor1*m2[0]._33) + (factor2*m2[1]._33);
|
|
f4 = (factor1*m2[0]._43) + (factor2*m2[1]._43);
|
|
v_out.z = (v_in.pos.x*f1 + v_in.pos.y*f2 + v_in.pos.z*f3 + f4);
|
|
}
|
|
|
|
|
|
long CZ3DMultipartSkin::GetPolyCount( int nLODLevel ) const
|
|
{
|
|
if( this != m_rpThis )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if( -1 == nLODLevel )
|
|
{
|
|
nLODLevel = m_lLODLevel;
|
|
}
|
|
|
|
if( nLODLevel >= Z3D_LOD_LEVEL )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
long lSum = 0;
|
|
|
|
for( int i = 0; i < Z3D_MULTIPART_PORTION_COUNT; ++i )
|
|
{
|
|
lSum += m_apPortion[i]->m_alIndexCount[nLODLevel];
|
|
}
|
|
|
|
lSum /= 3;
|
|
|
|
return lSum;
|
|
}
|