2V2-e.1: 3D draw-command channel — recording D3D8 device, StateManager, GrpBase, camera

EterLib/StateManager.cpp and GrpBase.cpp ported verbatim. CGraphicDevice::Create builds a platform
IDirect3DDevice8 that keeps the device state and records every Draw* call as a Render3DDraw
(vertices decoded by FVF, strips/fans expanded, textures, world/view/proj, blend/depth/light state).
The 40250 camera (__UpdateCamera, SetCenterPosition, ...) and the Process order
(__UpdateCamera -> OnCameraUpdate -> OnUIUpdate -> Begin/SetInterfaceRenderState/OnUIRender/End)
are in place; CScreen Begin/End, CPythonGraphic render states and CCullingManager::Process matrix
updates are verbatim. port.login_flow asserts a textured, lit character draw under the RH
perspective with every vertex on screen; offline and live pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-09-23 20:15:54 +09:00
co-authored by Claude Opus 5.5
parent 668f48d6ec
commit 5bfa13c5cc
27 changed files with 3616 additions and 777 deletions
@@ -11,12 +11,30 @@ struct MtCpuVertexBuffer : IDirect3DVertexBuffer8
{
std::vector<uint8_t> bytes;
DWORD fvf = 0;
HRESULT Lock(UINT offset, UINT size, BYTE** data, DWORD) override
{
if (size_t(offset) + size > bytes.size())
return E_FAIL;
*data = bytes.data() + offset;
return S_OK;
}
HRESULT Unlock() override { return S_OK; }
};
struct MtCpuIndexBuffer : IDirect3DIndexBuffer8
{
std::vector<uint8_t> bytes;
D3DFORMAT format = D3DFMT_INDEX16;
HRESULT Lock(UINT offset, UINT size, BYTE** data, DWORD) override
{
if (size_t(offset) + size > bytes.size())
return E_FAIL;
*data = bytes.data() + offset;
return S_OK;
}
HRESULT Unlock() override { return S_OK; }
};
// D3DXGetFVFVertexSize.
@@ -40,9 +40,16 @@ auto CCullingManager::Update() -> void
MT_PLATFORM_STUB();
}
auto CCullingManager::Process() -> void
// 40250 CullingManager.cpp:105. RenderGame calls it after SetPerspective; it hands the camera's view and
// the projection to CStateManager for the scene.
// PORT: BuildViewFrustum and m_Factory->FrustumTest follow in 40250; the sphere-pack culling (SphereLib)
// is not ported, so every registered object stays visible.
void CCullingManager::Process()
{
MT_PLATFORM_STUB();
//DWORD time = ELTimer_GetMSec();
//Frustum f;
UpdateViewMatrix();
UpdateProjMatrix();
}
auto CCullingManager::FindRange(const Vector3d &, float) -> void
-378
View File
@@ -1,378 +0,0 @@
// Platform skeleton for EterLib/GrpBase.h (40250 EterLib/GrpBase.cpp), generated by platform_stub.py.
// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation.
#include "EterLib/StdAfx.h"
#include "EterLib/GrpBase.h"
#include "../PlatformStub.h"
#include <cstring>
#include "UIRenderCommands.h"
auto CGraphicBase::GetAvailableTextureMemory() -> DWORD
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<DWORD>();
}
auto CGraphicBase::GetViewMatrix() -> const D3DXMATRIX &
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<const D3DXMATRIX &>();
}
auto CGraphicBase::GetIdentityMatrix() -> const D3DXMATRIX &
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<const D3DXMATRIX &>();
}
CGraphicBase::CGraphicBase()
{
MT_PLATFORM_STUB();
}
CGraphicBase::~CGraphicBase()
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::SetSimpleCamera(float, float, float, float, float) -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::SetEyeCamera(float, float, float, float, float, float, float, float, float) -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::SetAroundCamera(float, float, float, float) -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::SetPositionCamera(float, float, float, float, float, float) -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::MoveCamera(float, float, float) -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::GetTargetPosition(float *, float *, float *) -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::GetCameraPosition(float *, float *, float *) -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::SetOrtho2D(float, float, float) -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::SetOrtho3D(float, float, float, float) -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::SetPerspective(float, float, float, float) -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::GetFOV() -> float
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<float>();
}
auto CGraphicBase::PushMatrix() -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::MultMatrix(const D3DXMATRIX *) -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::MultMatrixLocal(const D3DXMATRIX *) -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::Translate(float, float, float) -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::Rotate(float, float, float, float) -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::RotateLocal(float, float, float, float) -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::RotateYawPitchRollLocal(float, float, float) -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::Scale(float, float, float) -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::PopMatrix() -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::LoadMatrix(const D3DXMATRIX &) -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::GetMatrix(D3DXMATRIX *) const -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::GetMatrixPointer() const -> const D3DXMATRIX *
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<const D3DXMATRIX *>();
}
auto CGraphicBase::GetSphereMatrix(D3DXMATRIX *, float) -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::InitScreenEffect() -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::SetScreenEffectWaving(float, int) -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::SetScreenEffectFlashing(float, const D3DXCOLOR &) -> void
{
MT_PLATFORM_STUB();
}
// 40250 GrpBase.cpp:458: the bytes B, G, R, A of a little-endian D3DCOLOR.
auto CGraphicBase::GetColor(float r, float g, float b, float a) -> DWORD
{
BYTE argb[4] =
{
(BYTE) (255.0f * b),
(BYTE) (255.0f * g),
(BYTE) (255.0f * r),
(BYTE) (255.0f * a)
};
DWORD color;
std::memcpy(&color, argb, sizeof(color));
return color;
}
auto CGraphicBase::GetFaceCount() -> DWORD
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<DWORD>();
}
auto CGraphicBase::ResetFaceCount() -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::GetLastResult() -> HRESULT
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<HRESULT>();
}
auto CGraphicBase::UpdateProjMatrix() -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::UpdateViewMatrix() -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::SetViewport(DWORD, DWORD, DWORD, DWORD, float, float) -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::GetBackBufferSize(UINT *width, UINT *height) -> void
{
UIRenderGetSize(width, height);
}
auto CGraphicBase::IsTLVertexClipping() -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CGraphicBase::IsFastTNL() -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CGraphicBase::IsLowTextureMemory() -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CGraphicBase::IsHighTextureMemory() -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CGraphicBase::SetDefaultIndexBuffer(UINT) -> void
{
MT_PLATFORM_STUB();
}
auto CGraphicBase::SetPDTStream(SPDTVertexRaw *, UINT) -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CGraphicBase::SetPDTStream(SPDTVertex *, UINT) -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
decltype(CGraphicBase::ms_matIdentity) CGraphicBase::ms_matIdentity{};
decltype(CGraphicBase::ms_matView) CGraphicBase::ms_matView{};
decltype(CGraphicBase::ms_matProj) CGraphicBase::ms_matProj{};
decltype(CGraphicBase::ms_matInverseView) CGraphicBase::ms_matInverseView{};
decltype(CGraphicBase::ms_matInverseViewYAxis) CGraphicBase::ms_matInverseViewYAxis{};
decltype(CGraphicBase::ms_matWorld) CGraphicBase::ms_matWorld{};
decltype(CGraphicBase::ms_matWorldView) CGraphicBase::ms_matWorldView{};
auto CGraphicBase::UpdatePipeLineMatrix() -> void
{
MT_PLATFORM_STUB();
}
decltype(CGraphicBase::ms_lpSphereMesh) CGraphicBase::ms_lpSphereMesh{};
decltype(CGraphicBase::ms_lpCylinderMesh) CGraphicBase::ms_lpCylinderMesh{};
decltype(CGraphicBase::ms_hLastResult) CGraphicBase::ms_hLastResult{};
decltype(CGraphicBase::ms_iWidth) CGraphicBase::ms_iWidth{};
decltype(CGraphicBase::ms_iHeight) CGraphicBase::ms_iHeight{};
decltype(CGraphicBase::ms_iD3DAdapterInfo) CGraphicBase::ms_iD3DAdapterInfo{};
decltype(CGraphicBase::ms_iD3DDevInfo) CGraphicBase::ms_iD3DDevInfo{};
decltype(CGraphicBase::ms_iD3DModeInfo) CGraphicBase::ms_iD3DModeInfo{};
decltype(CGraphicBase::ms_kD3DDetector) CGraphicBase::ms_kD3DDetector{};
decltype(CGraphicBase::ms_hWnd) CGraphicBase::ms_hWnd{};
decltype(CGraphicBase::ms_hDC) CGraphicBase::ms_hDC{};
decltype(CGraphicBase::ms_lpd3d) CGraphicBase::ms_lpd3d{};
decltype(CGraphicBase::ms_lpd3dDevice) CGraphicBase::ms_lpd3dDevice{};
decltype(CGraphicBase::ms_lpd3dMatStack) CGraphicBase::ms_lpd3dMatStack{};
decltype(CGraphicBase::ms_Viewport) CGraphicBase::ms_Viewport{};
decltype(CGraphicBase::ms_faceCount) CGraphicBase::ms_faceCount{};
decltype(CGraphicBase::ms_d3dCaps) CGraphicBase::ms_d3dCaps{};
decltype(CGraphicBase::ms_d3dPresentParameter) CGraphicBase::ms_d3dPresentParameter{};
decltype(CGraphicBase::ms_dwD3DBehavior) CGraphicBase::ms_dwD3DBehavior{};
decltype(CGraphicBase::ms_ptVS) CGraphicBase::ms_ptVS{};
decltype(CGraphicBase::ms_pntVS) CGraphicBase::ms_pntVS{};
decltype(CGraphicBase::ms_pnt2VS) CGraphicBase::ms_pnt2VS{};
decltype(CGraphicBase::ms_matScreen0) CGraphicBase::ms_matScreen0{};
decltype(CGraphicBase::ms_matScreen1) CGraphicBase::ms_matScreen1{};
decltype(CGraphicBase::ms_matScreen2) CGraphicBase::ms_matScreen2{};
decltype(CGraphicBase::ms_vtPickRayOrig) CGraphicBase::ms_vtPickRayOrig{};
decltype(CGraphicBase::ms_vtPickRayDir) CGraphicBase::ms_vtPickRayDir{};
decltype(CGraphicBase::ms_fFieldOfView) CGraphicBase::ms_fFieldOfView{};
decltype(CGraphicBase::ms_fAspect) CGraphicBase::ms_fAspect{};
decltype(CGraphicBase::ms_fNearY) CGraphicBase::ms_fNearY{};
decltype(CGraphicBase::ms_fFarY) CGraphicBase::ms_fFarY{};
decltype(CGraphicBase::ms_dwWavingEndTime) CGraphicBase::ms_dwWavingEndTime{};
decltype(CGraphicBase::ms_iWavingPower) CGraphicBase::ms_iWavingPower{};
decltype(CGraphicBase::ms_dwFlashingEndTime) CGraphicBase::ms_dwFlashingEndTime{};
decltype(CGraphicBase::ms_FlashingColor) CGraphicBase::ms_FlashingColor{};
decltype(CGraphicBase::ms_Ray) CGraphicBase::ms_Ray{};
decltype(CGraphicBase::ms_bSupportDXT) CGraphicBase::ms_bSupportDXT{};
decltype(CGraphicBase::ms_isLowTextureMemory) CGraphicBase::ms_isLowTextureMemory{};
decltype(CGraphicBase::ms_isHighTextureMemory) CGraphicBase::ms_isHighTextureMemory{};
decltype(CGraphicBase::ms_alpd3dPDTVB) CGraphicBase::ms_alpd3dPDTVB{};
decltype(CGraphicBase::ms_alpd3dDefIB) CGraphicBase::ms_alpd3dDefIB{};
auto PixelPositionToD3DXVECTOR3(const D3DXVECTOR3 &, D3DXVECTOR3 *) -> void
{
MT_PLATFORM_STUB();
}
auto D3DXVECTOR3ToPixelPosition(const D3DXVECTOR3 &, D3DXVECTOR3 *) -> void
{
MT_PLATFORM_STUB();
}
+235 -39
View File
@@ -1,34 +1,143 @@
// Platform skeleton for EterLib/GrpDevice.h (40250 EterLib/GrpDevice.cpp), generated by platform_stub.py.
// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation.
// 40250 EterLib/GrpDevice.cpp over the platform's recording device (RecordingDevice.h): there is no
// Direct3D object, adapter detection or window; Create makes the device, CStateManager, the matrix
// stack and the default buffers as 40250 does. The remaining MT_PLATFORM_STUB() bodies (device reset,
// web-browser mode, driver warnings) have no platform counterpart yet.
#include "EterLib/StdAfx.h"
#include "EterLib/GrpDevice.h"
#include "EterLib/StateManager.h"
#include "EterBase/Stl.h"
#include "CpuBuffer.h"
#include "RecordingDevice.h"
#include <cstring>
#include "../PlatformStub.h"
bool GRAPHICS_CAPS_CAN_NOT_DRAW_LINE = false;
bool GRAPHICS_CAPS_CAN_NOT_DRAW_SHADOW = false;
bool GRAPHICS_CAPS_HALF_SIZE_IMAGE = false;
bool GRAPHICS_CAPS_CAN_NOT_TEXTURE_ADDRESS_BORDER = false;
bool GRAPHICS_CAPS_SOFTWARE_TILING = false;
CGraphicDevice::CGraphicDevice()
: m_uBackBufferCount(0)
{
MT_PLATFORM_STUB();
__Initialize();
}
CGraphicDevice::~CGraphicDevice()
{
MT_PLATFORM_STUB();
Destroy();
}
auto CGraphicDevice::InitBackBufferCount(UINT) -> void
void CGraphicDevice::InitBackBufferCount(UINT uBackBufferCount)
{
MT_PLATFORM_STUB();
m_uBackBufferCount=uBackBufferCount;
}
auto CGraphicDevice::Destroy() -> void
void CGraphicDevice::Destroy()
{
MT_PLATFORM_STUB();
__DestroyPDTVertexBufferList();
__DestroyDefaultIndexBufferList();
// PORT: no DC, vertex shader objects or D3DX meshes; the stream "shaders" are FVF codes.
ms_ptVS = 0;
ms_pntVS = 0;
ms_pnt2VS = 0;
safe_release(ms_lpd3dMatStack);
safe_release(ms_lpd3dDevice);
if (m_pStateManager)
{
delete m_pStateManager;
m_pStateManager = NULL;
}
__Initialize();
}
auto CGraphicDevice::Create(HWND, int, int, bool, int, int) -> int
int CGraphicDevice::Create(HWND hWnd, int iHres, int iVres, bool Windowed, int /*iBit*/, int iReflashRate)
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<int>();
int iRet = CREATE_OK;
Destroy();
ms_iWidth = iHres;
ms_iHeight = iVres;
// PORT: in place of Direct3DCreate8, the display-mode detection and CreateDevice: the recording
// device renders through Godot, which supports DXT and has no refresh-rate or T&L failures.
ms_hWnd = hWnd;
ms_lpd3dDevice = MtCreateRecordingDevice(iHres, iVres);
ms_dwD3DBehavior = D3DCREATE_HARDWARE_VERTEXPROCESSING;
ms_d3dPresentParameter.BackBufferWidth = iHres;
ms_d3dPresentParameter.BackBufferHeight = iVres;
ms_d3dPresentParameter.Windowed = Windowed;
if (FAILED((ms_hLastResult = ms_lpd3dDevice->GetDeviceCaps(&ms_d3dCaps))))
{
Tracenf("IDirect3DDevice.GetDeviceCaps - ERROR %d", ms_hLastResult);
return CREATE_GET_DEVICE_CAPS2;
}
ms_lpd3dDevice->GetViewport(&ms_Viewport);
m_pStateManager = new CStateManager(ms_lpd3dDevice);
D3DXCreateMatrixStack(0, &ms_lpd3dMatStack);
ms_lpd3dMatStack->LoadIdentity();
ms_ptVS = CreatePTStreamVertexShader();
ms_pntVS = CreatePNTStreamVertexShader();
ms_pnt2VS = CreatePNT2StreamVertexShader();
D3DXMatrixIdentity(&ms_matIdentity);
D3DXMatrixIdentity(&ms_matView);
D3DXMatrixIdentity(&ms_matProj);
D3DXMatrixIdentity(&ms_matInverseView);
D3DXMatrixIdentity(&ms_matInverseViewYAxis);
D3DXMatrixIdentity(&ms_matScreen0);
D3DXMatrixIdentity(&ms_matScreen1);
D3DXMatrixIdentity(&ms_matScreen2);
ms_matScreen0._11 = 1;
ms_matScreen0._22 = -1;
ms_matScreen1._41 = 1;
ms_matScreen1._42 = 1;
ms_matScreen2._11 = (float) iHres / 2;
ms_matScreen2._22 = (float) iVres / 2;
// PORT: no D3DXCreateSphere/D3DXCreateCylinder (debug collision rendering) and no Clear.
if (!__CreateDefaultIndexBufferList())
return false;
if (!__CreatePDTVertexBufferList())
return false;
DWORD dwTexMemSize = GetAvailableTextureMemory();
if (dwTexMemSize < 64 * 1024 * 1024)
ms_isLowTextureMemory = true;
else
ms_isLowTextureMemory = false;
if (dwTexMemSize > 100 * 1024 * 1024)
ms_isHighTextureMemory = true;
else
ms_isHighTextureMemory = false;
if (ms_d3dCaps.TextureAddressCaps & D3DPTADDRESSCAPS_BORDER)
GRAPHICS_CAPS_CAN_NOT_TEXTURE_ADDRESS_BORDER=false;
else
GRAPHICS_CAPS_CAN_NOT_TEXTURE_ADDRESS_BORDER=true;
// PORT: the SIS/3dfx driver checks have no adapter identifier to test.
return (iRet);
}
auto CGraphicDevice::GetDeviceState() -> EDeviceState
@@ -69,9 +178,23 @@ auto CGraphicDevice::RegisterWarningString(UINT, const char *) -> void
MT_PLATFORM_STUB();
}
auto CGraphicDevice::__Initialize() -> void
void CGraphicDevice::__Initialize()
{
MT_PLATFORM_STUB();
ms_iD3DAdapterInfo=D3DADAPTER_DEFAULT;
ms_iD3DDevInfo=D3DADAPTER_DEFAULT;
ms_iD3DModeInfo=D3DADAPTER_DEFAULT;
ms_lpd3d = NULL;
ms_lpd3dDevice = NULL;
ms_lpd3dMatStack = NULL;
ms_dwWavingEndTime = 0;
ms_dwFlashingEndTime = 0;
m_pStateManager = NULL;
__InitializeDefaultIndexBufferList();
__InitializePDTVertexBufferList();
}
auto CGraphicDevice::__IsInDriverBlackList(D3D_CAdapterInfo &) -> bool
@@ -85,60 +208,133 @@ auto CGraphicDevice::__WarningMessage(HWND, UINT) -> void
MT_PLATFORM_STUB();
}
auto CGraphicDevice::__InitializeDefaultIndexBufferList() -> void
void CGraphicDevice::__InitializeDefaultIndexBufferList()
{
MT_PLATFORM_STUB();
for (UINT i=0; i<DEFAULT_IB_NUM; ++i)
ms_alpd3dDefIB[i]=NULL;
}
auto CGraphicDevice::__DestroyDefaultIndexBufferList() -> void
void CGraphicDevice::__DestroyDefaultIndexBufferList()
{
MT_PLATFORM_STUB();
for (UINT i=0; i<DEFAULT_IB_NUM; ++i)
if (ms_alpd3dDefIB[i])
{
delete ms_alpd3dDefIB[i]; // PORT: CPU buffer, no Release
ms_alpd3dDefIB[i]=NULL;
}
}
auto CGraphicDevice::__CreateDefaultIndexBufferList() -> bool
bool CGraphicDevice::__CreateDefaultIndexBufferList()
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
static const WORD c_awLineIndices[2] = { 0, 1, };
static const WORD c_awLineTriIndices[6] = { 0, 1, 0, 2, 1, 2, };
static const WORD c_awLineRectIndices[8] = { 0, 1, 0, 2, 1, 3, 2, 3,};
static const WORD c_awLineCubeIndices[24] = {
0, 1, 0, 2, 1, 3, 2, 3,
0, 4, 1, 5, 2, 6, 3, 7,
4, 5, 4, 6, 5, 7, 6, 7,
};
static const WORD c_awFillTriIndices[3]= { 0, 1, 2, };
static const WORD c_awFillRectIndices[6] = { 0, 2, 1, 2, 3, 1, };
static const WORD c_awFillCubeIndices[36] = {
0, 1, 2, 1, 3, 2,
2, 0, 6, 0, 4, 6,
0, 1, 4, 1, 5, 4,
1, 3, 5, 3, 7, 5,
3, 2, 7, 2, 6, 7,
4, 5, 6, 5, 7, 6,
};
if (!__CreateDefaultIndexBuffer(DEFAULT_IB_LINE, 2, c_awLineIndices))
return false;
if (!__CreateDefaultIndexBuffer(DEFAULT_IB_LINE_TRI, 6, c_awLineTriIndices))
return false;
if (!__CreateDefaultIndexBuffer(DEFAULT_IB_LINE_RECT, 8, c_awLineRectIndices))
return false;
if (!__CreateDefaultIndexBuffer(DEFAULT_IB_LINE_CUBE, 24, c_awLineCubeIndices))
return false;
if (!__CreateDefaultIndexBuffer(DEFAULT_IB_FILL_TRI, 3, c_awFillTriIndices))
return false;
if (!__CreateDefaultIndexBuffer(DEFAULT_IB_FILL_RECT, 6, c_awFillRectIndices))
return false;
if (!__CreateDefaultIndexBuffer(DEFAULT_IB_FILL_CUBE, 36, c_awFillCubeIndices))
return false;
return true;
}
auto CGraphicDevice::__CreateDefaultIndexBuffer(UINT, UINT, const WORD *) -> bool
bool CGraphicDevice::__CreateDefaultIndexBuffer(UINT eDefIB, UINT uIdxCount, const WORD* c_awIndices)
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
assert(ms_alpd3dDefIB[eDefIB]==NULL);
// PORT: a CPU buffer in place of CreateIndexBuffer (CpuBuffer.h).
MtCpuIndexBuffer* pIB = new MtCpuIndexBuffer;
pIB->bytes.resize(sizeof(WORD)*uIdxCount);
pIB->format = D3DFMT_INDEX16;
ms_alpd3dDefIB[eDefIB] = pIB;
WORD* dstIndices;
if (FAILED(
ms_alpd3dDefIB[eDefIB]->Lock(0, 0, (BYTE**)&dstIndices, 0)
)) return false;
memcpy(dstIndices, c_awIndices, sizeof(WORD)*uIdxCount);
ms_alpd3dDefIB[eDefIB]->Unlock();
return true;
}
auto CGraphicDevice::__InitializePDTVertexBufferList() -> void
void CGraphicDevice::__InitializePDTVertexBufferList()
{
MT_PLATFORM_STUB();
for (UINT i=0; i<PDT_VERTEXBUFFER_NUM; ++i)
ms_alpd3dPDTVB[i]=NULL;
}
auto CGraphicDevice::__DestroyPDTVertexBufferList() -> void
void CGraphicDevice::__DestroyPDTVertexBufferList()
{
MT_PLATFORM_STUB();
for (UINT i=0; i<PDT_VERTEXBUFFER_NUM; ++i)
{
if (ms_alpd3dPDTVB[i])
{
delete ms_alpd3dPDTVB[i]; // PORT: CPU buffer, no Release
ms_alpd3dPDTVB[i]=NULL;
}
}
}
auto CGraphicDevice::__CreatePDTVertexBufferList() -> bool
bool CGraphicDevice::__CreatePDTVertexBufferList()
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
for (UINT i=0; i<PDT_VERTEXBUFFER_NUM; ++i)
{
// PORT: a CPU buffer in place of CreateVertexBuffer (CpuBuffer.h).
MtCpuVertexBuffer* pVB = new MtCpuVertexBuffer;
pVB->bytes.resize(sizeof(TPDTVertex)*PDT_VERTEX_NUM);
pVB->fvf = D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1;
ms_alpd3dPDTVB[i] = pVB;
}
return true;
}
auto CGraphicDevice::CreatePTStreamVertexShader() -> DWORD
// PORT: the stream vertex shaders are declarations for the fixed-function pipeline; the recording
// device decodes vertices by FVF, so each returns the FVF matching its declaration. PT keeps its
// texture coordinates in stream 1, which the device does not record: stream 0 is position only.
DWORD CGraphicDevice::CreatePTStreamVertexShader()
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<DWORD>();
assert(ms_lpd3dDevice != NULL);
return D3DFVF_XYZ;
}
auto CGraphicDevice::CreatePNTStreamVertexShader() -> DWORD
DWORD CGraphicDevice::CreatePNTStreamVertexShader()
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<DWORD>();
assert(ms_lpd3dDevice != NULL);
return D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1;
}
auto CGraphicDevice::CreatePNT2StreamVertexShader() -> DWORD
DWORD CGraphicDevice::CreatePNT2StreamVertexShader()
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<DWORD>();
assert(ms_lpd3dDevice != NULL);
return D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX2;
}
auto CGraphicDevice::CreateDoublePNTStreamVertexShader() -> DWORD
@@ -9,6 +9,7 @@
#include <cstring>
#include <map>
#include <mutex>
#include <set>
namespace {
unsigned little16(const unsigned char* data) { return data[0] | (unsigned(data[1]) << 8); }
@@ -100,6 +101,25 @@ MemoryTexture* live_memory_texture(const IDirect3DTexture8* texture)
if (entry.second == texture) return entry.second;
return nullptr;
}
// PORT: the IDirect3DTexture8 behind a file texture (CreateFromMemoryFile). The canvas and the 3D
// renderer decode the file themselves; the handle only carries the pack path so a texture bound
// through STATEMANAGER.SetTexture(stage, GetD3DTexture()) can be named.
struct FileTexture : IDirect3DTexture8
{
std::string name;
};
std::set<const FileTexture*> g_file_textures; // guarded by g_memory_mutex
IDirect3DTexture8* new_file_texture(const std::string& name)
{
auto* file = new FileTexture();
file->name = name;
std::lock_guard<std::mutex> lock(g_memory_mutex);
g_file_textures.insert(file);
return file;
}
}
void UIRenderReleaseMemoryTexture(IDirect3DTexture8* texture)
@@ -108,9 +128,22 @@ void UIRenderReleaseMemoryTexture(IDirect3DTexture8* texture)
if (MemoryTexture* memory = live_memory_texture(texture)) {
g_memory.erase(memory->id);
delete memory;
} else if (g_file_textures.erase(static_cast<const FileTexture*>(texture))) {
delete static_cast<FileTexture*>(texture);
}
}
std::string UIRenderTextureNameFromHandle(const IDirect3DBaseTexture8* handle)
{
if (!handle) return {};
const auto* texture = static_cast<const IDirect3DTexture8*>(handle);
std::lock_guard<std::mutex> lock(g_memory_mutex);
if (const MemoryTexture* memory = live_memory_texture(texture))
return "mem:" + std::to_string(memory->id) + "@" + std::to_string(memory->revision);
const auto* file = static_cast<const FileTexture*>(texture);
return g_file_textures.count(file) ? file->name : std::string();
}
bool UIRenderMemoryTexture(const std::string& name, UIMemoryTexture* out)
{
if (name.compare(0, 4, "mem:") != 0 || !out) return false;
@@ -195,6 +228,11 @@ auto CGraphicImageTexture::CreateFromTexturePointer(const CGraphicTexture *sourc
// 40250 shares the source's D3D texture; the canvas names textures by pack path instead.
if (const auto* image = dynamic_cast<const CGraphicImageTexture*>(source))
m_stFileName = image->m_stFileName;
// PORT: 40250 AddRefs the source's texture; this handle is not reference counted, so the copy gets
// its own named handle.
DestroyDeviceObjects();
if (!m_bEmpty && !m_stFileName.empty())
m_lpd3dTexture = new_file_texture(m_stFileName);
}
auto CGraphicImageTexture::CreateFromDiskFile(const char *, D3DFORMAT, DWORD) -> bool
@@ -223,6 +261,8 @@ auto CGraphicImageTexture::CreateFromMemoryFile(UINT size, const void *bytes, D3
if (!width || !height || width > 16384 || height > 16384) return false;
m_width = static_cast<int>(width); m_height = static_cast<int>(height);
m_bEmpty = false;
DestroyDeviceObjects();
m_lpd3dTexture = new_file_texture(m_stFileName);
return true;
}
+46 -13
View File
@@ -2,19 +2,19 @@
// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation.
#include "EterLib/StdAfx.h"
#include "EterLib/GrpScreen.h"
#include "EterLib/StateManager.h"
#include "../PlatformStub.h"
#include "UIRenderCommands.h"
#include <algorithm>
// 40250 GrpScreen.cpp:838
CScreen::CScreen()
{
MT_PLATFORM_STUB();
}
CScreen::~CScreen()
{
MT_PLATFORM_STUB();
}
auto CScreen::ClearDepthBuffer() -> void
@@ -27,15 +27,26 @@ auto CScreen::Clear() -> void
MT_PLATFORM_STUB();
}
auto CScreen::Begin() -> bool
// 40250 GrpScreen.cpp:691. CPythonApplication::Process brackets the frame's render with Begin/End; only
// inside the scene does CStateManager hand transforms to the recording device.
bool CScreen::Begin()
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
assert(ms_lpd3dDevice != NULL);
ResetFaceCount();
if (!STATEMANAGER.BeginScene())
{
Tracenf("BeginScene FAILED\n");
return false;
}
return true;
}
auto CScreen::End() -> void
// 40250 GrpScreen.cpp:705
void CScreen::End()
{
MT_PLATFORM_STUB();
STATEMANAGER.EndScene();
}
auto CScreen::Show(HWND) -> void
@@ -158,19 +169,41 @@ auto CScreen::RenderCylinder(const D3DXMATRIX *, float, float, float, float, flo
MT_PLATFORM_STUB();
}
auto CScreen::SetColorOperation() -> void
// 40250 GrpScreen.cpp
void CScreen::SetColorOperation()
{
MT_PLATFORM_STUB();
STATEMANAGER.SetTexture(0, NULL);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
}
auto CScreen::SetDiffuseOperation() -> void
// 40250 GrpScreen.cpp
void CScreen::SetDiffuseOperation()
{
MT_PLATFORM_STUB();
STATEMANAGER.SetTexture(0, NULL);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
}
auto CScreen::SetBlendOperation() -> void
// 40250 GrpScreen.cpp
void CScreen::SetBlendOperation()
{
MT_PLATFORM_STUB();
STATEMANAGER.SetTexture(0, NULL);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
}
auto CScreen::SetOneColorOperation(D3DXCOLOR &) -> void
@@ -31,7 +31,7 @@ auto CGraphicTexture::GetD3DTexture() const -> LPDIRECT3DTEXTURE8
return m_lpd3dTexture;
}
// PORT: safe_release(m_lpd3dTexture); the only textures this platform creates are memory textures.
// PORT: safe_release(m_lpd3dTexture); the platform textures are memory textures and file-texture handles.
auto CGraphicTexture::DestroyDeviceObjects() -> void
{
if (m_lpd3dTexture)
@@ -0,0 +1,385 @@
#include "RecordingDevice.h"
#include "RenderCommands3D.h"
#include "UIRenderCommands.h"
#include "CpuBuffer.h"
#include <cstring>
#include <mutex>
namespace {
std::mutex g_draws_mutex;
std::vector<Render3DDraw> g_draws;
struct VertexLayout {
unsigned stride = 0;
bool rhw = false;
int normal = -1, diffuse = -1, uv0 = -1, uv1 = -1;
};
// The element offsets of a fixed-function FVF (D3DXGetFVFVertexSize's order).
VertexLayout fvf_layout(DWORD fvf)
{
VertexLayout layout;
unsigned offset = 0;
switch (fvf & D3DFVF_POSITION_MASK)
{
case D3DFVF_XYZ: offset = 12; break;
case D3DFVF_XYZRHW: offset = 16; layout.rhw = true; break;
case D3DFVF_XYZB1: offset = 16; break;
case D3DFVF_XYZB2: offset = 20; break;
case D3DFVF_XYZB3: offset = 24; break;
case D3DFVF_XYZB4: offset = 28; break;
case D3DFVF_XYZB5: offset = 32; break;
}
if (fvf & D3DFVF_NORMAL) { layout.normal = offset; offset += 12; }
if (fvf & D3DFVF_PSIZE) offset += 4;
if (fvf & D3DFVF_DIFFUSE) { layout.diffuse = offset; offset += 4; }
if (fvf & D3DFVF_SPECULAR) offset += 4;
const unsigned texCount = (fvf & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
for (unsigned i = 0; i < texCount; ++i)
{
static const unsigned coordSize[4] = { 8, 12, 16, 4 };
if (i == 0) layout.uv0 = offset;
if (i == 1) layout.uv1 = offset;
offset += coordSize[(fvf >> (16 + i * 2)) & 3];
}
layout.stride = offset;
return layout;
}
void copy_color(float out[4], const D3DCOLORVALUE& c)
{
out[0] = c.r; out[1] = c.g; out[2] = c.b; out[3] = c.a;
}
class RecordingDevice final : public IDirect3DDevice8
{
public:
RecordingDevice(int width, int height) : m_width(width), m_height(height)
{
static const float identity[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
for (auto& matrix : m_transforms)
std::memcpy(matrix, identity, sizeof(identity));
std::memset(&m_material, 0, sizeof(m_material));
m_material.Diffuse = { 1, 1, 1, 1 };
std::memset(m_lights, 0, sizeof(m_lights));
}
ULONG AddRef() override { return ++m_refs; }
ULONG Release() override
{
const ULONG refs = --m_refs;
if (!refs)
delete this;
return refs;
}
// PORT: a D3D8 HAL on a T&L card (D3DDEVCAPS_HWTRANSFORMANDLIGHT), 8 lights, 4 texture stages.
HRESULT GetDeviceCaps(D3DCAPS8* caps) override
{
std::memset(caps, 0, sizeof(*caps));
caps->DevCaps = D3DDEVCAPS_HWTRANSFORMANDLIGHT;
caps->MaxActiveLights = 8;
caps->MaxTextureBlendStages = 4;
caps->MaxSimultaneousTextures = 4;
caps->MaxTextureWidth = caps->MaxTextureHeight = 4096;
caps->MaxAnisotropy = 16;
caps->MaxPrimitiveCount = 0xFFFFF;
caps->MaxVertexIndex = 0xFFFFF;
caps->MaxStreams = 8;
caps->MaxStreamStride = 255;
caps->TextureAddressCaps = D3DPTADDRESSCAPS_BORDER | D3DPTADDRESSCAPS_CLAMP | D3DPTADDRESSCAPS_WRAP | D3DPTADDRESSCAPS_MIRROR;
return S_OK;
}
HRESULT GetViewport(D3DVIEWPORT8* viewport) override
{
*viewport = { 0, 0, DWORD(m_width), DWORD(m_height), 0.0f, 1.0f };
return S_OK;
}
// PORT: CPU memory has no texture budget; report the 64MB of a mid-range 2004 card.
UINT GetAvailableTextureMem() override { return 64u << 20; }
HRESULT BeginScene() override { return S_OK; }
HRESULT EndScene() override { return S_OK; }
HRESULT SetTransform(D3DTRANSFORMSTATETYPE state, const D3DMATRIX* matrix) override
{
if (unsigned(state) < kTransforms && matrix)
std::memcpy(m_transforms[state], matrix, sizeof(float) * 16);
return S_OK;
}
HRESULT GetTransform(D3DTRANSFORMSTATETYPE state, D3DMATRIX* matrix) override
{
if (unsigned(state) < kTransforms)
std::memcpy(matrix, m_transforms[state], sizeof(float) * 16);
return S_OK;
}
HRESULT SetMaterial(const D3DMATERIAL8* material) override { m_material = *material; return S_OK; }
HRESULT SetLight(DWORD index, const D3DLIGHT8* light) override
{
if (index < 8)
m_lights[index] = *light;
return S_OK;
}
HRESULT SetRenderState(D3DRENDERSTATETYPE state, DWORD value) override
{
if (unsigned(state) < kRenderStates)
m_renderStates[state] = value;
return S_OK;
}
HRESULT SetTexture(DWORD stage, IDirect3DBaseTexture8* texture) override
{
if (stage < kStages)
m_textures[stage] = texture;
return S_OK;
}
HRESULT SetTextureStageState(DWORD stage, D3DTEXTURESTAGESTATETYPE type, DWORD value) override
{
if (stage < kStages && unsigned(type) < kStageStates)
m_stageStates[stage][type] = value;
return S_OK;
}
// PORT: fixed function only; CGraphicDevice's stream "shaders" are the FVFs they describe.
HRESULT SetVertexShader(DWORD handle) override { m_fvf = handle; return S_OK; }
HRESULT SetPixelShader(DWORD) override { return S_OK; }
HRESULT SetVertexShaderConstant(DWORD, const void*, DWORD) override { return S_OK; }
HRESULT SetPixelShaderConstant(DWORD, const void*, DWORD) override { return S_OK; }
HRESULT SetStreamSource(UINT stream, IDirect3DVertexBuffer8* buffer, UINT stride) override
{
if (stream == 0)
{
m_stream = static_cast<MtCpuVertexBuffer*>(buffer);
m_streamStride = stride;
}
return S_OK;
}
HRESULT SetIndices(IDirect3DIndexBuffer8* indices, UINT baseVertex) override
{
m_indices = static_cast<MtCpuIndexBuffer*>(indices);
m_baseVertex = baseVertex;
return S_OK;
}
HRESULT DrawPrimitive(D3DPRIMITIVETYPE type, UINT startVertex, UINT primitiveCount) override
{
if (!m_stream)
return E_FAIL;
const UINT count = index_count(type, primitiveCount);
std::vector<std::uint32_t> indices(count);
for (UINT i = 0; i < count; ++i)
indices[i] = startVertex + i;
record(type, primitiveCount, m_stream->bytes.data(), m_stream->bytes.size(), m_streamStride, indices);
return S_OK;
}
HRESULT DrawIndexedPrimitive(D3DPRIMITIVETYPE type, UINT, UINT, UINT startIndex, UINT primitiveCount) override
{
if (!m_stream || !m_indices)
return E_FAIL;
std::vector<std::uint32_t> indices;
if (!read_indices(m_indices->bytes.data(), m_indices->bytes.size(), m_indices->format, startIndex,
index_count(type, primitiveCount), m_baseVertex, &indices))
return E_FAIL;
record(type, primitiveCount, m_stream->bytes.data(), m_stream->bytes.size(), m_streamStride, indices);
return S_OK;
}
HRESULT DrawPrimitiveUP(D3DPRIMITIVETYPE type, UINT primitiveCount, const void* vertices, UINT stride) override
{
const UINT count = index_count(type, primitiveCount);
std::vector<std::uint32_t> indices(count);
for (UINT i = 0; i < count; ++i)
indices[i] = i;
record(type, primitiveCount, static_cast<const uint8_t*>(vertices), size_t(count) * stride, stride, indices);
return S_OK;
}
HRESULT DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE type, UINT minVertex, UINT numVertices, UINT primitiveCount,
const void* indexData, D3DFORMAT indexFormat, const void* vertices, UINT stride) override
{
const UINT count = index_count(type, primitiveCount);
const size_t indexSize = indexFormat == D3DFMT_INDEX32 ? 4 : 2;
std::vector<std::uint32_t> indices;
if (!read_indices(static_cast<const uint8_t*>(indexData), count * indexSize, indexFormat, 0, count, 0, &indices))
return E_FAIL;
record(type, primitiveCount, static_cast<const uint8_t*>(vertices), size_t(minVertex + numVertices) * stride, stride, indices);
return S_OK;
}
private:
static constexpr unsigned kTransforms = 512; // D3DTS_WORLDMATRIX(0..255) = 256..511
static constexpr unsigned kRenderStates = 256;
static constexpr unsigned kStages = 8;
static constexpr unsigned kStageStates = 32;
static UINT index_count(D3DPRIMITIVETYPE type, UINT primitives)
{
switch (type)
{
case D3DPT_POINTLIST: return primitives;
case D3DPT_LINELIST: return primitives * 2;
case D3DPT_LINESTRIP: return primitives + 1;
case D3DPT_TRIANGLELIST: return primitives * 3;
case D3DPT_TRIANGLESTRIP: case D3DPT_TRIANGLEFAN: return primitives + 2;
default: return 0;
}
}
static bool read_indices(const uint8_t* bytes, size_t size, D3DFORMAT format, UINT start, UINT count, UINT base,
std::vector<std::uint32_t>* out)
{
const size_t indexSize = format == D3DFMT_INDEX32 ? 4 : 2;
if ((size_t(start) + count) * indexSize > size)
return false;
out->resize(count);
for (UINT i = 0; i < count; ++i)
{
const uint8_t* p = bytes + (size_t(start) + i) * indexSize;
std::uint32_t index = indexSize == 4 ? (p[0] | (p[1] << 8) | (p[2] << 16) | (std::uint32_t(p[3]) << 24)) : (p[0] | (p[1] << 8));
(*out)[i] = index + base;
}
return true;
}
void record(D3DPRIMITIVETYPE type, UINT primitives, const uint8_t* vertices, size_t vertexBytes, UINT stride,
const std::vector<std::uint32_t>& indices)
{
if (type == D3DPT_POINTLIST || indices.empty() || !vertices)
return;
VertexLayout layout = fvf_layout(m_fvf);
if (!stride)
stride = layout.stride;
if (!stride || stride < (layout.rhw ? 16u : 12u))
return;
// Elements past the stream's stride live in another stream (CreatePTStreamVertexShader).
if (layout.normal + 12 > int(stride)) layout.normal = -1;
if (layout.diffuse + 4 > int(stride)) layout.diffuse = -1;
if (layout.uv0 + 8 > int(stride)) layout.uv0 = -1;
if (layout.uv1 + 8 > int(stride)) layout.uv1 = -1;
Render3DDraw draw;
std::memcpy(draw.world, m_transforms[256], sizeof(draw.world)); // D3DTS_WORLD
std::memcpy(draw.view, m_transforms[D3DTS_VIEW], sizeof(draw.view));
std::memcpy(draw.proj, m_transforms[D3DTS_PROJECTION], sizeof(draw.proj));
draw.texture0 = UIRenderTextureNameFromHandle(m_textures[0]);
draw.texture1 = UIRenderTextureNameFromHandle(m_textures[1]);
draw.pretransformed = layout.rhw;
draw.lines = type == D3DPT_LINELIST || type == D3DPT_LINESTRIP;
// Rebase: copy only the vertices the indices reference.
std::uint32_t lo = indices[0], hi = indices[0];
for (std::uint32_t index : indices)
{
lo = std::min(lo, index);
hi = std::max(hi, index);
}
if ((size_t(hi) + 1) * stride > vertexBytes)
return;
const size_t count = size_t(hi - lo) + 1;
draw.positions.resize(count * 3);
if (layout.rhw) draw.rhw.resize(count);
if (layout.normal >= 0) draw.normals.resize(count * 3);
if (layout.uv0 >= 0) draw.uv0.resize(count * 2);
if (layout.uv1 >= 0) draw.uv1.resize(count * 2);
if (layout.diffuse >= 0) draw.diffuse.resize(count);
for (size_t i = 0; i < count; ++i)
{
const uint8_t* v = vertices + (lo + i) * stride;
std::memcpy(&draw.positions[i * 3], v, 12);
if (layout.rhw) std::memcpy(&draw.rhw[i], v + 12, 4);
if (layout.normal >= 0) std::memcpy(&draw.normals[i * 3], v + layout.normal, 12);
if (layout.uv0 >= 0) std::memcpy(&draw.uv0[i * 2], v + layout.uv0, 8);
if (layout.uv1 >= 0) std::memcpy(&draw.uv1[i * 2], v + layout.uv1, 8);
if (layout.diffuse >= 0) std::memcpy(&draw.diffuse[i], v + layout.diffuse, 4);
}
// Strips and fans become lists; D3D flips the winding of every odd strip triangle.
switch (type)
{
case D3DPT_TRIANGLESTRIP:
for (UINT i = 0; i < primitives; ++i)
{
const std::uint32_t a = indices[i] - lo, b = indices[i + 1] - lo, c = indices[i + 2] - lo;
if (i & 1) draw.indices.insert(draw.indices.end(), { b, a, c });
else draw.indices.insert(draw.indices.end(), { a, b, c });
}
break;
case D3DPT_TRIANGLEFAN:
for (UINT i = 0; i < primitives; ++i)
draw.indices.insert(draw.indices.end(), { indices[0] - lo, indices[i + 1] - lo, indices[i + 2] - lo });
break;
case D3DPT_LINESTRIP:
for (UINT i = 0; i < primitives; ++i)
draw.indices.insert(draw.indices.end(), { indices[i] - lo, indices[i + 1] - lo });
break;
default:
for (std::uint32_t index : indices)
draw.indices.push_back(index - lo);
break;
}
draw.alpha_blend = m_renderStates[D3DRS_ALPHABLENDENABLE];
draw.src_blend = m_renderStates[D3DRS_SRCBLEND];
draw.dest_blend = m_renderStates[D3DRS_DESTBLEND];
draw.alpha_test = m_renderStates[D3DRS_ALPHATESTENABLE];
draw.alpha_ref = m_renderStates[D3DRS_ALPHAREF];
draw.alpha_func = m_renderStates[D3DRS_ALPHAFUNC];
draw.cull_mode = m_renderStates[D3DRS_CULLMODE];
draw.z_enable = m_renderStates[D3DRS_ZENABLE];
draw.z_write = m_renderStates[D3DRS_ZWRITEENABLE];
draw.z_func = m_renderStates[D3DRS_ZFUNC];
draw.lighting = m_renderStates[D3DRS_LIGHTING];
draw.texture_factor = m_renderStates[D3DRS_TEXTUREFACTOR];
draw.fog_enable = m_renderStates[D3DRS_FOGENABLE];
draw.ambient = m_renderStates[D3DRS_AMBIENT];
for (int stage = 0; stage < 2; ++stage)
{
draw.color_op[stage] = m_stageStates[stage][D3DTSS_COLOROP];
draw.color_arg1[stage] = m_stageStates[stage][D3DTSS_COLORARG1];
draw.color_arg2[stage] = m_stageStates[stage][D3DTSS_COLORARG2];
draw.alpha_op[stage] = m_stageStates[stage][D3DTSS_ALPHAOP];
draw.alpha_arg1[stage] = m_stageStates[stage][D3DTSS_ALPHAARG1];
draw.alpha_arg2[stage] = m_stageStates[stage][D3DTSS_ALPHAARG2];
}
copy_color(draw.material_diffuse, m_material.Diffuse);
copy_color(draw.material_ambient, m_material.Ambient);
copy_color(draw.material_emissive, m_material.Emissive);
if (m_lights[0].Type == D3DLIGHT_DIRECTIONAL)
{
draw.light0 = true;
draw.light0_direction[0] = m_lights[0].Direction.x;
draw.light0_direction[1] = m_lights[0].Direction.y;
draw.light0_direction[2] = m_lights[0].Direction.z;
copy_color(draw.light0_diffuse, m_lights[0].Diffuse);
copy_color(draw.light0_ambient, m_lights[0].Ambient);
}
Render3DAdd(std::move(draw));
}
ULONG m_refs = 1;
int m_width, m_height;
float m_transforms[kTransforms][16];
DWORD m_renderStates[kRenderStates] = {};
DWORD m_stageStates[kStages][kStageStates] = {};
IDirect3DBaseTexture8* m_textures[kStages] = {};
D3DMATERIAL8 m_material;
D3DLIGHT8 m_lights[8];
DWORD m_fvf = 0;
MtCpuVertexBuffer* m_stream = nullptr;
UINT m_streamStride = 0;
MtCpuIndexBuffer* m_indices = nullptr;
UINT m_baseVertex = 0;
};
}
IDirect3DDevice8* MtCreateRecordingDevice(int width, int height) { return new RecordingDevice(width, height); }
void Render3DBeginFrame()
{
std::lock_guard<std::mutex> lock(g_draws_mutex);
g_draws.clear();
}
void Render3DAdd(Render3DDraw draw)
{
std::lock_guard<std::mutex> lock(g_draws_mutex);
g_draws.push_back(std::move(draw));
}
const std::vector<Render3DDraw>& Render3DDraws() { return g_draws; }
@@ -0,0 +1,7 @@
#pragma once
// The platform's IDirect3DDevice8: CGraphicDevice::Create hands it to CStateManager, which keeps
// 40250's state caching; the device remembers the state it is given and turns every draw call into a
// Render3DDraw (RenderCommands3D.h) for the Godot renderer.
#include "EterLib/StdAfx.h"
IDirect3DDevice8* MtCreateRecordingDevice(int width, int height);
@@ -0,0 +1,55 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
// The 3D draw calls the ported game render (CPythonApplication::RenderGame) issues through
// CStateManager, recorded by the platform's IDirect3DDevice8 (RecordingDevice.cpp) and consumed by
// Godot. Like UIRenderCommands.h this header stays free of D3D and godot-cpp types.
//
// Matrices are D3D8's row-vector layout (translation in elements 12..14), exactly as 40250 set them.
struct Render3DDraw {
float world[16];
float view[16];
float proj[16];
// Stage 0/1 textures, named like UIRenderTextureName: the pack path of a file texture or
// "mem:<id>@<revision>"; empty when the stage has no texture.
std::string texture0;
std::string texture1;
// The referenced vertices, rebased so indices start at 0. normals/uv0/uv1/diffuse are empty when
// the vertex format has no such element. pretransformed: D3DFVF_XYZRHW (screen-space x, y, z, rhw
// in positions + rhw).
bool pretransformed = false;
std::vector<float> positions; // x, y, z
std::vector<float> rhw;
std::vector<float> normals; // x, y, z
std::vector<float> uv0; // u, v
std::vector<float> uv1; // u, v
std::vector<std::uint32_t> diffuse; // 0xAARRGGBB
std::vector<std::uint32_t> indices; // triangle list (strips and fans are expanded), or line list
bool lines = false;
// D3DRS_* / D3DTSS_* values in effect for the draw.
std::uint32_t alpha_blend = 0, src_blend = 0, dest_blend = 0;
std::uint32_t alpha_test = 0, alpha_ref = 0, alpha_func = 0;
std::uint32_t cull_mode = 0, z_enable = 0, z_write = 0, z_func = 0;
std::uint32_t lighting = 0, texture_factor = 0, fog_enable = 0;
std::uint32_t color_op[2] = {}, color_arg1[2] = {}, color_arg2[2] = {};
std::uint32_t alpha_op[2] = {}, alpha_arg1[2] = {}, alpha_arg2[2] = {};
// D3DMATERIAL8 diffuse/ambient/emissive (r, g, b, a) and light 0 when enabled.
float material_diffuse[4] = {1, 1, 1, 1};
float material_ambient[4] = {};
float material_emissive[4] = {};
bool light0 = false;
float light0_direction[3] = {};
float light0_diffuse[4] = {};
float light0_ambient[4] = {};
std::uint32_t ambient = 0; // D3DRS_AMBIENT
};
void Render3DBeginFrame();
void Render3DAdd(Render3DDraw draw);
const std::vector<Render3DDraw>& Render3DDraws();
@@ -1,292 +0,0 @@
// Platform skeleton for EterLib/StateManager.h (40250 EterLib/StateManager.cpp), generated by platform_stub.py.
// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation.
#include "EterLib/StdAfx.h"
#include "EterLib/StateManager.h"
#include "../PlatformStub.h"
CStateManager::CStateManager(LPDIRECT3DDEVICE8)
{
MT_PLATFORM_STUB();
}
CStateManager::~CStateManager()
{
MT_PLATFORM_STUB();
}
auto CStateManager::SetDefaultState() -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::Restore() -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::BeginScene() -> bool
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<bool>();
}
auto CStateManager::EndScene() -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SaveMaterial() -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SaveMaterial(const D3DMATERIAL8 *) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::RestoreMaterial() -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SetMaterial(const D3DMATERIAL8 *) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::GetMaterial(D3DMATERIAL8 *) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SetLight(DWORD, const D3DLIGHT8 *) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::GetLight(DWORD, D3DLIGHT8 *) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SaveRenderState(D3DRENDERSTATETYPE, DWORD) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::RestoreRenderState(D3DRENDERSTATETYPE) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SetRenderState(D3DRENDERSTATETYPE, DWORD) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::GetRenderState(D3DRENDERSTATETYPE, DWORD *) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SaveTexture(DWORD, LPDIRECT3DBASETEXTURE8) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::RestoreTexture(DWORD) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SetTexture(DWORD, LPDIRECT3DBASETEXTURE8) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::GetTexture(DWORD, LPDIRECT3DBASETEXTURE8 *) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SaveTextureStageState(DWORD, D3DTEXTURESTAGESTATETYPE, DWORD) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::RestoreTextureStageState(DWORD, D3DTEXTURESTAGESTATETYPE) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SetTextureStageState(DWORD, D3DTEXTURESTAGESTATETYPE, DWORD) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::GetTextureStageState(DWORD, D3DTEXTURESTAGESTATETYPE, DWORD *) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SetBestFiltering(DWORD) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SaveVertexShader(DWORD) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::RestoreVertexShader() -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SetVertexShader(DWORD) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::GetVertexShader(DWORD *) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SavePixelShader(DWORD) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::RestorePixelShader() -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SetPixelShader(DWORD) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::GetPixelShader(DWORD *) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SaveTransform(D3DTRANSFORMSTATETYPE, const D3DMATRIX *) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::RestoreTransform(D3DTRANSFORMSTATETYPE) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SetTransform(D3DTRANSFORMSTATETYPE, const D3DMATRIX *) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::GetTransform(D3DTRANSFORMSTATETYPE, D3DMATRIX *) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SaveVertexShaderConstant(DWORD, const void *, DWORD) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::RestoreVertexShaderConstant(DWORD, DWORD) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SetVertexShaderConstant(DWORD, const void *, DWORD) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SavePixelShaderConstant(DWORD, const void *, DWORD) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::RestorePixelShaderConstant(DWORD, DWORD) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SetPixelShaderConstant(DWORD, const void *, DWORD) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SaveStreamSource(UINT, LPDIRECT3DVERTEXBUFFER8, UINT) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::RestoreStreamSource(UINT) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SetStreamSource(UINT, LPDIRECT3DVERTEXBUFFER8, UINT) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SaveIndices(LPDIRECT3DINDEXBUFFER8, UINT) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::RestoreIndices() -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::SetIndices(LPDIRECT3DINDEXBUFFER8, UINT) -> void
{
MT_PLATFORM_STUB();
}
auto CStateManager::DrawPrimitive(D3DPRIMITIVETYPE, UINT, UINT) -> HRESULT
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<HRESULT>();
}
auto CStateManager::DrawPrimitiveUP(D3DPRIMITIVETYPE, UINT, const void *, UINT) -> HRESULT
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<HRESULT>();
}
auto CStateManager::DrawIndexedPrimitive(D3DPRIMITIVETYPE, UINT, UINT, UINT, UINT) -> HRESULT
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<HRESULT>();
}
auto CStateManager::DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE, UINT, UINT, UINT, const void *, D3DFORMAT, const void *, UINT) -> HRESULT
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<HRESULT>();
}
auto CStateManager::GetRenderState(D3DRENDERSTATETYPE) -> DWORD
{
MT_PLATFORM_STUB();
return mt_platform_stub_return<DWORD>();
}
auto CStateManager::SetDevice(LPDIRECT3DDEVICE8) -> void
{
MT_PLATFORM_STUB();
}
@@ -44,7 +44,11 @@ struct UIMemoryTexture {
};
bool UIRenderMemoryTexture(const std::string& name, UIMemoryTexture* out);
struct IDirect3DTexture8;
struct IDirect3DBaseTexture8;
// Frees the platform texture behind a CGraphicTexture: a memory texture or a file texture's handle.
void UIRenderReleaseMemoryTexture(IDirect3DTexture8* texture);
// The name (as UIRenderTextureName) of the texture a D3D handle belongs to; "" for null or unknown.
std::string UIRenderTextureNameFromHandle(const IDirect3DBaseTexture8* handle);
// A textured quad from 40250's TPDTVertex[4] (TL, TR, BL, BR) positions and texture coordinates.
// PORT: D3D8 puts pixel centres on integers, which is why 40250 subtracts 0.5 from every vertex; the