Files
Client/Library/dxx8/samples/Multimedia/Direct3D/SkinnedMesh/mdraw.cpp
LGram16 e067522598 Initial commit: ROW Client source code
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>
2025-11-29 16:24:34 +09:00

565 lines
19 KiB
C++

//-----------------------------------------------------------------------------
// File: mdraw.cpp
//
// Copyright (c) 1999-2001 Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#include <d3d8.h>
#include <d3dx8.h>
#include "D3DApp.h"
#include "D3DFont.h"
#include "D3DUtil.h"
#include "DXUtil.h"
#include "SkinnedMesh.h"
HRESULT CMyD3DApplication::DrawMeshContainer(SMeshContainer *pmcMesh)
{
UINT ipattr;
HRESULT hr = S_OK;
LPD3DXBONECOMBINATION pBoneComb;
DWORD AttribIdPrev;
if (pmcMesh->m_pSkinMesh)
{
if (m_method != pmcMesh->m_Method)
{
GenerateMesh(pmcMesh);
}
if (m_method == D3DNONINDEXED)
{
AttribIdPrev = UNUSED32;
pBoneComb = reinterpret_cast<LPD3DXBONECOMBINATION>(pmcMesh->m_pBoneCombinationBuf->GetBufferPointer());
// Draw using default vtx processing of the device (typically HW)
for (ipattr = 0; ipattr < pmcMesh->cpattr; ipattr++)
{
DWORD numBlend = 0;
for (DWORD i = 0; i < pmcMesh->m_maxFaceInfl; ++i)
{
if (pBoneComb[ipattr].BoneId[i] != UINT_MAX)
{
numBlend = i;
}
}
if (m_d3dCaps.MaxVertexBlendMatrices >= numBlend + 1)
{
for (DWORD i = 0; i < pmcMesh->m_maxFaceInfl; ++i)
{
DWORD matid = pBoneComb[ipattr].BoneId[i];
if (matid != UINT_MAX)
{
m_pd3dDevice->SetTransform(D3DTS_WORLDMATRIX(i), pmcMesh->m_pBoneMatrix[matid]);
m_pd3dDevice->MultiplyTransform(D3DTS_WORLDMATRIX(i), &pmcMesh->m_pBoneOffsetMat[matid]);
}
}
m_pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, numBlend);
if ((AttribIdPrev != pBoneComb[ipattr].AttribId) || (AttribIdPrev == UNUSED32))
{
m_pd3dDevice->SetMaterial(&(pmcMesh->rgMaterials[pBoneComb[ipattr].AttribId]));
m_pd3dDevice->SetTexture(0, pmcMesh->pTextures[pBoneComb[ipattr].AttribId]);
AttribIdPrev = pBoneComb[ipattr].AttribId;
}
hr = pmcMesh->pMesh->DrawSubset( ipattr );
if(FAILED(hr))
return hr;
}
}
// If necessary, draw parts that HW could not handle using SW
if (pmcMesh->iAttrSplit < pmcMesh->cpattr)
{
AttribIdPrev = UNUSED32;
m_pd3dDevice->SetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING, TRUE);
for (ipattr = pmcMesh->iAttrSplit; ipattr < pmcMesh->cpattr; ipattr++)
{
DWORD numBlend = 0;
for (DWORD i = 0; i < pmcMesh->m_maxFaceInfl; ++i)
{
if (pBoneComb[ipattr].BoneId[i] != UINT_MAX)
{
numBlend = i;
}
}
if (m_d3dCaps.MaxVertexBlendMatrices < numBlend + 1)
{
for (DWORD i = 0; i < pmcMesh->m_maxFaceInfl; ++i)
{
DWORD matid = pBoneComb[ipattr].BoneId[i];
if (matid != UINT_MAX)
{
m_pd3dDevice->SetTransform(D3DTS_WORLDMATRIX(i), pmcMesh->m_pBoneMatrix[matid]);
m_pd3dDevice->MultiplyTransform(D3DTS_WORLDMATRIX(i), &pmcMesh->m_pBoneOffsetMat[matid]);
}
}
m_pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, numBlend);
if ((AttribIdPrev != pBoneComb[ipattr].AttribId) || (AttribIdPrev == UNUSED32))
{
m_pd3dDevice->SetMaterial(&(pmcMesh->rgMaterials[pBoneComb[ipattr].AttribId]));
m_pd3dDevice->SetTexture(0, pmcMesh->pTextures[pBoneComb[ipattr].AttribId]);
AttribIdPrev = pBoneComb[ipattr].AttribId;
}
hr = pmcMesh->pMesh->DrawSubset( ipattr );
if(FAILED(hr))
return hr;
}
}
m_pd3dDevice->SetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING, FALSE);
}
m_pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, 0);
}
else if (m_method == D3DINDEXEDVS)
{
// Use COLOR instead of UBYTE4 since Geforce3 does not support it
// vConst.w should be 3, but due to about hack, mul by 255 and add epsilon
D3DXVECTOR4 vConst( 1.0f, 0.0f, 0.0f, 765.01f );
LPDIRECT3DVERTEXBUFFER8 pVB;
LPDIRECT3DINDEXBUFFER8 pIB;
if (pmcMesh->m_bUseSW)
{
m_pd3dDevice->SetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING, TRUE);
}
pmcMesh->pMesh->GetVertexBuffer(&pVB);
pmcMesh->pMesh->GetIndexBuffer(&pIB);
hr = m_pd3dDevice->SetStreamSource(0, pVB, D3DXGetFVFVertexSize(pmcMesh->pMesh->GetFVF()));
if(FAILED(hr))
return hr;
hr = m_pd3dDevice->SetIndices(pIB, 0);
if(FAILED(hr))
return hr;
pVB->Release();
pIB->Release();
hr = m_pd3dDevice->SetVertexShader(m_dwIndexedVertexShader[pmcMesh->m_maxFaceInfl - 1]);
if(FAILED(hr))
return hr;
pBoneComb = reinterpret_cast<LPD3DXBONECOMBINATION>(pmcMesh->m_pBoneCombinationBuf->GetBufferPointer());
for (ipattr = 0; ipattr < pmcMesh->cpattr; ipattr++)
{
for (DWORD i = 0; i < pmcMesh->m_paletteSize; ++i)
{
DWORD matid = pBoneComb[ipattr].BoneId[i];
if (matid != UINT_MAX)
{
D3DXMATRIXA16 mat;
D3DXMatrixMultiply(&mat, &pmcMesh->m_pBoneOffsetMat[matid], pmcMesh->m_pBoneMatrix[matid]);
D3DXMatrixMultiplyTranspose(&mat, &mat, &m_mView);
m_pd3dDevice->SetVertexShaderConstant(i*3 + 9, &mat, 3);
}
}
// Sum of all ambient and emissive contribution
D3DXCOLOR ambEmm;
D3DXColorModulate(&ambEmm, &D3DXCOLOR(pmcMesh->rgMaterials[pBoneComb[ipattr].AttribId].Ambient),&D3DXCOLOR(.25, .25, .25, 1.0));
ambEmm += D3DXCOLOR(pmcMesh->rgMaterials[pBoneComb[ipattr].AttribId].Emissive);
m_pd3dDevice->SetVertexShaderConstant(8, &(pmcMesh->rgMaterials[pBoneComb[ipattr].AttribId].Diffuse), 1);
m_pd3dDevice->SetVertexShaderConstant(7, &ambEmm, 1);
vConst.y = pmcMesh->rgMaterials[pBoneComb[ipattr].AttribId].Power;
m_pd3dDevice->SetVertexShaderConstant(0, &vConst, 1);
m_pd3dDevice->SetTexture(0, pmcMesh->pTextures[pBoneComb[ipattr].AttribId]);
hr = m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
pBoneComb[ipattr].VertexStart, pBoneComb[ipattr].VertexCount,
pBoneComb[ipattr].FaceStart * 3, pBoneComb[ipattr].FaceCount);
if(FAILED(hr))
return hr;
}
if (pmcMesh->m_bUseSW)
{
m_pd3dDevice->SetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING, FALSE);
}
}
else if (m_method == D3DINDEXED)
{
if (pmcMesh->m_bUseSW)
{
m_pd3dDevice->SetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING, TRUE);
}
if (pmcMesh->m_maxFaceInfl == 1)
m_pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_0WEIGHTS);
else
m_pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, pmcMesh->m_maxFaceInfl - 1);
if (pmcMesh->m_maxFaceInfl)
m_pd3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, TRUE);
pBoneComb = reinterpret_cast<LPD3DXBONECOMBINATION>(pmcMesh->m_pBoneCombinationBuf->GetBufferPointer());
for (ipattr = 0; ipattr < pmcMesh->cpattr; ipattr++)
{
for (DWORD i = 0; i < pmcMesh->m_paletteSize; ++i)
{
DWORD matid = pBoneComb[ipattr].BoneId[i];
if (matid != UINT_MAX)
{
m_pd3dDevice->SetTransform(D3DTS_WORLDMATRIX(i), pmcMesh->m_pBoneMatrix[matid]);
m_pd3dDevice->MultiplyTransform(D3DTS_WORLDMATRIX(i), &pmcMesh->m_pBoneOffsetMat[matid]);
}
}
m_pd3dDevice->SetMaterial(&(pmcMesh->rgMaterials[pBoneComb[ipattr].AttribId]));
m_pd3dDevice->SetTexture(0, pmcMesh->pTextures[pBoneComb[ipattr].AttribId]);
hr = pmcMesh->pMesh->DrawSubset( ipattr );
if(FAILED(hr))
return hr;
}
m_pd3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE);
m_pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, 0);
if (pmcMesh->m_bUseSW)
{
m_pd3dDevice->SetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING, FALSE);
}
}
else if (m_method == SOFTWARE)
{
D3DXMATRIX Identity;
DWORD cBones = pmcMesh->m_pSkinMesh->GetNumBones();
// set up bone transforms
for (DWORD iBone = 0; iBone < cBones; ++iBone)
{
D3DXMatrixMultiply
(
&m_pBoneMatrices[iBone], // output
&pmcMesh->m_pBoneOffsetMat[iBone],
pmcMesh->m_pBoneMatrix[iBone]
);
}
// set world transform
D3DXMatrixIdentity(&Identity);
hr = m_pd3dDevice->SetTransform(D3DTS_WORLD, &Identity);
if (FAILED(hr))
return hr;
// generate skinned mesh
hr = pmcMesh->m_pSkinMesh->UpdateSkinnedMesh(m_pBoneMatrices, NULL, pmcMesh->pMesh);
if (FAILED(hr))
return hr;
for (ipattr = 0; ipattr < pmcMesh->cpattr; ipattr++)
{
m_pd3dDevice->SetMaterial(&(pmcMesh->rgMaterials[pmcMesh->m_pAttrTable[ipattr].AttribId]));
m_pd3dDevice->SetTexture(0, pmcMesh->pTextures[pmcMesh->m_pAttrTable[ipattr].AttribId]);
hr = pmcMesh->pMesh->DrawSubset(pmcMesh->m_pAttrTable[ipattr].AttribId);
if (FAILED(hr))
return hr;
}
return hr;
}
}
else
{
for (ipattr = 0; ipattr < pmcMesh->cpattr; ipattr++)
{
m_pd3dDevice->SetMaterial(&(pmcMesh->rgMaterials[ipattr]));
m_pd3dDevice->SetTexture(0, pmcMesh->pTextures[ipattr]);
hr = pmcMesh->pMesh->DrawSubset( ipattr );
if(FAILED(hr))
return hr;
}
}
return S_OK;
}
HRESULT CMyD3DApplication::UpdateFrames(SFrame *pframeCur, D3DXMATRIX &matCur)
{
HRESULT hr = S_OK;
pframeCur->matCombined = matCur;
D3DXMatrixMultiply(&pframeCur->matCombined, &pframeCur->matRot, &matCur);
D3DXMatrixMultiply(&pframeCur->matCombined, &pframeCur->matCombined, &pframeCur->matTrans );
SFrame *pframeChild = pframeCur->pframeFirstChild;
while (pframeChild != NULL)
{
hr = UpdateFrames(pframeChild, pframeCur->matCombined);
if (FAILED(hr))
return hr;
pframeChild = pframeChild->pframeSibling;
}
return S_OK;
}
HRESULT CMyD3DApplication::DrawFrames(SFrame *pframeCur, UINT &cTriangles)
{
HRESULT hr = S_OK;
SMeshContainer *pmcMesh;
SFrame *pframeChild;
if (pframeCur->pmcMesh != NULL)
{
hr = m_pd3dDevice->SetTransform(D3DTS_WORLD, &pframeCur->matCombined);
if(FAILED(hr))
return hr;
}
pmcMesh = pframeCur->pmcMesh;
while (pmcMesh != NULL)
{
hr = DrawMeshContainer(pmcMesh);
if (FAILED(hr))
return hr;
cTriangles += pmcMesh->pMesh->GetNumFaces();
pmcMesh = pmcMesh->pmcNext;
}
pframeChild = pframeCur->pframeFirstChild;
while (pframeChild != NULL)
{
hr = DrawFrames(pframeChild, cTriangles);
if (FAILED(hr))
return hr;
pframeChild = pframeChild->pframeSibling;
}
return S_OK;
}
void SFrame::SetTime(float fGlobalTime)
{
UINT iKey;
UINT dwp2;
UINT dwp3;
D3DXMATRIXA16 matResult;
D3DXMATRIXA16 matTemp;
float fTime1;
float fTime2;
float fLerpValue;
D3DXVECTOR3 vScale;
D3DXVECTOR3 vPos;
D3DXQUATERNION quat;
BOOL bAnimate = false;
float fTime;
if (m_pMatrixKeys )
{
fTime = (float)fmod(fGlobalTime, m_pMatrixKeys[m_cMatrixKeys-1].dwTime);
for (iKey = 0 ;iKey < m_cMatrixKeys ; iKey++)
{
if ((float)m_pMatrixKeys[iKey].dwTime > fTime)
{
dwp3 = iKey;
if (iKey > 0)
{
dwp2= iKey - 1;
}
else // when iKey == 0, then dwp2 == 0
{
dwp2 = iKey;
}
break;
}
}
fTime1 = (float)m_pMatrixKeys[dwp2].dwTime;
fTime2 = (float)m_pMatrixKeys[dwp3].dwTime;
if ((fTime2 - fTime1) ==0)
fLerpValue = 0;
else
fLerpValue = (fTime - fTime1) / (fTime2 - fTime1);
if (fLerpValue > 0.5)
{
iKey = dwp3;
}
else
{
iKey = dwp2;
}
pframeToAnimate->matRot = m_pMatrixKeys[iKey].mat;
}
else
{
D3DXMatrixIdentity(&matResult);
if (m_pScaleKeys)
{
dwp2 = dwp3 = 0;
fTime = (float)fmod(fGlobalTime, m_pScaleKeys[m_cScaleKeys-1].dwTime);
for (iKey = 0 ;iKey < m_cScaleKeys ; iKey++)
{
if ((float)m_pScaleKeys[iKey].dwTime > fTime)
{
dwp3 = iKey;
if (iKey > 0)
{
dwp2= iKey - 1;
}
else // when iKey == 0, then dwp2 == 0
{
dwp2 = iKey;
}
break;
}
}
fTime1 = (float)m_pScaleKeys[dwp2].dwTime;
fTime2 = (float)m_pScaleKeys[dwp3].dwTime;
if ((fTime2 - fTime1) ==0)
fLerpValue = 0;
else
fLerpValue = (fTime - fTime1) / (fTime2 - fTime1);
D3DXVec3Lerp(&vScale,
&m_pScaleKeys[dwp2].vScale,
&m_pScaleKeys[dwp3].vScale,
fLerpValue);
D3DXMatrixScaling(&matTemp, vScale.x, vScale.y, vScale.z);
D3DXMatrixMultiply(&matResult, &matResult, &matTemp);
bAnimate = true;
}
//check rot keys
if (m_pRotateKeys )
{
int i1 = 0;
int i2 = 0;
fTime = (float)fmod(fGlobalTime, m_pRotateKeys[m_cRotateKeys-1].dwTime);
for (iKey = 0 ;iKey < m_cRotateKeys ; iKey++)
{
if ((float)m_pRotateKeys[iKey].dwTime > fTime)
{
i1 = (iKey > 0) ? iKey - 1 : 0;
i2 = iKey;
break;
}
}
fTime1 = (float)m_pRotateKeys[i1].dwTime;
fTime2 = (float)m_pRotateKeys[i2].dwTime;
if ((fTime2 - fTime1) ==0)
fLerpValue = 0;
else
fLerpValue = (fTime - fTime1) / (fTime2 - fTime1);
#define USE_SQUAD
#ifdef USE_SQUAD
int i0 = i1 - 1;
int i3 = i2 + 1;
if(i0 < 0)
i0 += m_cRotateKeys;
if(i3 >= (INT) m_cRotateKeys)
i3 -= m_cRotateKeys;
D3DXQUATERNION qA, qB, qC;
D3DXQuaternionSquadSetup(&qA, &qB, &qC,
&m_pRotateKeys[i0].quatRotate, &m_pRotateKeys[i1].quatRotate,
&m_pRotateKeys[i2].quatRotate, &m_pRotateKeys[i3].quatRotate);
D3DXQuaternionSquad(&quat, &m_pRotateKeys[i1].quatRotate, &qA, &qB, &qC, fLerpValue);
#else
D3DXQuaternionSlerp(&quat, &m_pRotateKeys[i1].quatRotate, &m_pRotateKeys[i2].quatRotate, fLerpValue);
#endif
quat.w = -quat.w;
D3DXMatrixRotationQuaternion(&matTemp, &quat);
D3DXMatrixMultiply(&matResult, &matResult, &matTemp);
bAnimate = true;
}
if (m_pPositionKeys)
{
dwp2=dwp3=0;
fTime = (float)fmod(fGlobalTime, m_pPositionKeys[m_cPositionKeys-1].dwTime);
for (iKey = 0 ;iKey < m_cPositionKeys ; iKey++)
{
if ((float)m_pPositionKeys[iKey].dwTime > fTime)
{
dwp3 = iKey;
if (iKey > 0)
{
dwp2= iKey - 1;
}
else // when iKey == 0, then dwp2 == 0
{
dwp2 = iKey;
}
break;
}
}
fTime1 = (float)m_pPositionKeys[dwp2].dwTime;
fTime2 = (float)m_pPositionKeys[dwp3].dwTime;
if ((fTime2 - fTime1) ==0)
fLerpValue = 0;
else
fLerpValue = (fTime - fTime1) / (fTime2 - fTime1);
D3DXVec3Lerp((D3DXVECTOR3*)&vPos,
&m_pPositionKeys[dwp2].vPos,
&m_pPositionKeys[dwp3].vPos,
fLerpValue);
D3DXMatrixTranslation(&matTemp, vPos.x, vPos.y, vPos.z);
D3DXMatrixMultiply(&matResult, &matResult, &matTemp);
bAnimate = true;
}
else
{
D3DXMatrixTranslation(&matTemp, pframeToAnimate->matRotOrig._41, pframeToAnimate->matRotOrig._42, pframeToAnimate->matRotOrig._43);
D3DXMatrixMultiply(&matResult, &matResult, &matTemp);
}
if (bAnimate)
{
pframeToAnimate->matRot = matResult;
}
}
}