mirror of
https://github.com/isledecomp/isle-portable.git
synced 2026-01-10 18:21:14 +00:00
Implement DirectX 9 backend (#332)
This commit is contained in:
parent
a94187b233
commit
ea4b9ab1c9
18
CMake/cmake-toolchain-mingw64-x86_64.cmake
Normal file
18
CMake/cmake-toolchain-mingw64-x86_64.cmake
Normal file
@ -0,0 +1,18 @@
|
||||
set(CMAKE_SYSTEM_NAME Windows)
|
||||
set(CMAKE_SYSTEM_PROCESSOR x86_64)
|
||||
|
||||
find_program(CMAKE_C_COMPILER NAMES x86_64-w64-mingw32-gcc)
|
||||
find_program(CMAKE_CXX_COMPILER NAMES x86_64-w64-mingw32-g++)
|
||||
find_program(CMAKE_RC_COMPILER NAMES x86_64-w64-mingw32-windres windres)
|
||||
|
||||
if(NOT CMAKE_C_COMPILER)
|
||||
message(FATAL_ERROR "Failed to find CMAKE_C_COMPILER.")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_CXX_COMPILER)
|
||||
message(FATAL_ERROR "Failed to find CMAKE_CXX_COMPILER.")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_RC_COMPILER)
|
||||
message(FATAL_ERROR "Failed to find CMAKE_RC_COMPILER.")
|
||||
endif()
|
||||
@ -22,6 +22,7 @@ if (NOT MINGW)
|
||||
set(NOT_MINGW ON)
|
||||
else()
|
||||
set(NOT_MINGW OFF)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static -static-libgcc -static-libstdc++")
|
||||
endif()
|
||||
|
||||
find_program(SDL_SHADERCROSS_BIN NAMES "shadercross")
|
||||
|
||||
@ -48,6 +48,14 @@ else()
|
||||
message(STATUS "🧩 OpenGL ES 2.x support not enabled")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_sources(miniwin PRIVATE
|
||||
src/d3drm/backends/directx9/actual.cpp
|
||||
src/d3drm/backends/directx9/renderer.cpp
|
||||
)
|
||||
target_link_libraries(miniwin PRIVATE d3d9)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(miniwin PUBLIC MINIWIN)
|
||||
|
||||
target_include_directories(miniwin
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include "miniwin/windows.h"
|
||||
|
||||
// --- Typedefs ---
|
||||
typedef struct IDirectInputA* LPDIRECTINPUTA;
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL_events.h>
|
||||
|
||||
DEFINE_GUID(IID_IDirect3DRMMiniwinDevice, 0x6eb09673, 0x8d30, 0x4d8a, 0x8d, 0x81, 0x34, 0xea, 0x69, 0x30, 0x12, 0x01);
|
||||
|
||||
struct IDirect3DRMMiniwinDevice : virtual public IUnknown {
|
||||
|
||||
385
miniwin/src/d3drm/backends/directx9/actual.cpp
Normal file
385
miniwin/src/d3drm/backends/directx9/actual.cpp
Normal file
@ -0,0 +1,385 @@
|
||||
#include "actual.h"
|
||||
|
||||
#include "structs.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <d3d9.h>
|
||||
#include <vector>
|
||||
#include <windows.h>
|
||||
|
||||
// Global D3D9 state
|
||||
static LPDIRECT3D9 g_d3d;
|
||||
static LPDIRECT3DDEVICE9 g_device;
|
||||
static HWND g_hwnd;
|
||||
static LPDIRECT3DTEXTURE9 g_renderTargetTex;
|
||||
static LPDIRECT3DSURFACE9 g_renderTargetSurf;
|
||||
static LPDIRECT3DSURFACE9 g_oldRenderTarget;
|
||||
static int m_width;
|
||||
static int m_height;
|
||||
static std::vector<BridgeSceneLight> m_lights;
|
||||
static Matrix4x4 m_projection;
|
||||
|
||||
bool Actual_Initialize(void* hwnd, int width, int height)
|
||||
{
|
||||
g_hwnd = (HWND) hwnd;
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
g_d3d = Direct3DCreate9(D3D_SDK_VERSION);
|
||||
if (!g_d3d) {
|
||||
return false;
|
||||
}
|
||||
|
||||
D3DPRESENT_PARAMETERS pp = {};
|
||||
pp.Windowed = TRUE;
|
||||
pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
||||
pp.hDeviceWindow = g_hwnd;
|
||||
pp.BackBufferFormat = D3DFMT_A8R8G8B8;
|
||||
pp.BackBufferWidth = width;
|
||||
pp.BackBufferHeight = height;
|
||||
pp.EnableAutoDepthStencil = TRUE;
|
||||
pp.AutoDepthStencilFormat = D3DFMT_D24S8;
|
||||
|
||||
HRESULT hr = g_d3d->CreateDevice(
|
||||
D3DADAPTER_DEFAULT,
|
||||
D3DDEVTYPE_HAL,
|
||||
g_hwnd,
|
||||
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
|
||||
&pp,
|
||||
&g_device
|
||||
);
|
||||
if (FAILED(hr)) {
|
||||
g_d3d->Release();
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = g_device->CreateTexture(
|
||||
width,
|
||||
height,
|
||||
1,
|
||||
D3DUSAGE_RENDERTARGET,
|
||||
D3DFMT_A8R8G8B8,
|
||||
D3DPOOL_DEFAULT,
|
||||
&g_renderTargetTex,
|
||||
nullptr
|
||||
);
|
||||
if (FAILED(hr)) {
|
||||
g_device->Release();
|
||||
g_d3d->Release();
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = g_renderTargetTex->GetSurfaceLevel(0, &g_renderTargetSurf);
|
||||
if (FAILED(hr)) {
|
||||
g_renderTargetTex->Release();
|
||||
g_device->Release();
|
||||
g_d3d->Release();
|
||||
return false;
|
||||
}
|
||||
|
||||
g_device->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Actual_Shutdown()
|
||||
{
|
||||
if (g_renderTargetSurf) {
|
||||
g_renderTargetSurf->Release();
|
||||
g_renderTargetSurf = nullptr;
|
||||
}
|
||||
if (g_renderTargetTex) {
|
||||
g_renderTargetTex->Release();
|
||||
g_renderTargetTex = nullptr;
|
||||
}
|
||||
if (g_device) {
|
||||
g_device->Release();
|
||||
g_device = nullptr;
|
||||
}
|
||||
if (g_d3d) {
|
||||
g_d3d->Release();
|
||||
g_d3d = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Actual_PushLights(const BridgeSceneLight* lightsArray, size_t count)
|
||||
{
|
||||
m_lights.assign(lightsArray, lightsArray + count);
|
||||
}
|
||||
|
||||
void Actual_SetProjection(const Matrix4x4* projection, float front, float back)
|
||||
{
|
||||
memcpy(&m_projection, projection, sizeof(Matrix4x4));
|
||||
}
|
||||
|
||||
IDirect3DTexture9* UploadSurfaceToD3DTexture(SDL_Surface* surface)
|
||||
{
|
||||
IDirect3DTexture9* texture;
|
||||
|
||||
HRESULT hr =
|
||||
g_device->CreateTexture(surface->w, surface->h, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &texture, nullptr);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SDL_Surface* conv = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_ARGB8888);
|
||||
if (!conv) {
|
||||
texture->Release();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
D3DLOCKED_RECT lockedRect;
|
||||
texture->LockRect(0, &lockedRect, nullptr, 0);
|
||||
|
||||
for (int y = 0; y < conv->h; ++y) {
|
||||
memcpy(
|
||||
(uint8_t*) lockedRect.pBits + y * lockedRect.Pitch,
|
||||
(uint8_t*) conv->pixels + y * conv->pitch,
|
||||
conv->w * 4
|
||||
);
|
||||
}
|
||||
|
||||
texture->UnlockRect(0);
|
||||
SDL_DestroySurface(conv);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
void ReleaseD3DTexture(IDirect3DTexture9* texture)
|
||||
{
|
||||
texture->Release();
|
||||
}
|
||||
|
||||
void ReleaseD3DVertexBuffer(IDirect3DVertexBuffer9* buffer)
|
||||
{
|
||||
buffer->Release();
|
||||
}
|
||||
|
||||
void ReleaseD3DIndexBuffer(IDirect3DIndexBuffer9* buffer)
|
||||
{
|
||||
buffer->Release();
|
||||
}
|
||||
|
||||
void UploadMeshBuffers(
|
||||
const void* vertices,
|
||||
int vertexSize,
|
||||
const uint16_t* indices,
|
||||
int indexSize,
|
||||
D3D9MeshCacheEntry& cache
|
||||
)
|
||||
{
|
||||
g_device->CreateVertexBuffer(
|
||||
vertexSize,
|
||||
0,
|
||||
D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1,
|
||||
D3DPOOL_MANAGED,
|
||||
&cache.vbo,
|
||||
nullptr
|
||||
);
|
||||
void* vbData;
|
||||
cache.vbo->Lock(0, 0, &vbData, 0);
|
||||
memcpy(vbData, vertices, vertexSize);
|
||||
cache.vbo->Unlock();
|
||||
|
||||
g_device->CreateIndexBuffer(indexSize, 0, D3DFMT_INDEX16, D3DPOOL_MANAGED, &cache.ibo, nullptr);
|
||||
void* ibData;
|
||||
cache.ibo->Lock(0, 0, &ibData, 0);
|
||||
memcpy(ibData, indices, indexSize);
|
||||
cache.ibo->Unlock();
|
||||
}
|
||||
|
||||
constexpr float PI = 3.14159265358979323846f;
|
||||
|
||||
void SetupLights()
|
||||
{
|
||||
g_device->SetRenderState(D3DRS_LIGHTING, TRUE);
|
||||
|
||||
for (DWORD i = 0; i < 8; ++i) {
|
||||
g_device->LightEnable(i, FALSE);
|
||||
}
|
||||
|
||||
DWORD lightIdx = 0;
|
||||
for (const auto& l : m_lights) {
|
||||
if (lightIdx >= 8) {
|
||||
break;
|
||||
}
|
||||
|
||||
const FColor c = l.color;
|
||||
|
||||
if (l.directional != 1.0f && l.positional != 1.0f) {
|
||||
g_device->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_COLORVALUE(c.r, c.g, c.b, 1.0f));
|
||||
continue;
|
||||
}
|
||||
|
||||
D3DLIGHT9 light = {};
|
||||
light.Type = (l.directional == 1.0f) ? D3DLIGHT_DIRECTIONAL : D3DLIGHT_POINT;
|
||||
|
||||
light.Ambient = {0, 0, 0, 0};
|
||||
light.Diffuse = {c.r, c.g, c.b, c.a};
|
||||
|
||||
if (light.Type == D3DLIGHT_DIRECTIONAL) {
|
||||
light.Direction.x = -l.direction.x;
|
||||
light.Direction.y = -l.direction.y;
|
||||
light.Direction.z = -l.direction.z;
|
||||
light.Specular = {0, 0, 0, 0};
|
||||
}
|
||||
else if (light.Type == D3DLIGHT_POINT) {
|
||||
light.Specular = {1, 1, 1, 1};
|
||||
light.Position.x = l.position.x;
|
||||
light.Position.y = l.position.y;
|
||||
light.Position.z = l.position.z;
|
||||
light.Range = 1000.0f;
|
||||
light.Attenuation0 = 1.0f;
|
||||
light.Attenuation1 = 0.0f;
|
||||
light.Attenuation2 = 0.0f;
|
||||
}
|
||||
|
||||
light.Falloff = 1.0f;
|
||||
light.Phi = PI;
|
||||
light.Theta = PI / 2;
|
||||
|
||||
if (SUCCEEDED(g_device->SetLight(lightIdx, &light))) {
|
||||
g_device->LightEnable(lightIdx, TRUE);
|
||||
}
|
||||
++lightIdx;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Actual_BeginFrame()
|
||||
{
|
||||
g_device->GetRenderTarget(0, &g_oldRenderTarget);
|
||||
g_device->SetRenderTarget(0, g_renderTargetSurf);
|
||||
|
||||
g_device->Clear(0, nullptr, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 0, 0, 0), 1.0f, 0);
|
||||
|
||||
g_device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
|
||||
g_device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
|
||||
g_device->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
|
||||
|
||||
g_device->BeginScene();
|
||||
|
||||
SetupLights();
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
void Actual_EnableTransparency()
|
||||
{
|
||||
g_device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
||||
g_device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
|
||||
g_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
|
||||
g_device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
|
||||
}
|
||||
|
||||
D3DMATRIX ToD3DMATRIX(const Matrix4x4& in)
|
||||
{
|
||||
D3DMATRIX out;
|
||||
for (int row = 0; row < 4; ++row) {
|
||||
out.m[row][0] = static_cast<float>(in[row][0]);
|
||||
out.m[row][1] = static_cast<float>(in[row][1]);
|
||||
out.m[row][2] = static_cast<float>(in[row][2]);
|
||||
out.m[row][3] = static_cast<float>(in[row][3]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void Actual_SubmitDraw(
|
||||
const D3D9MeshCacheEntry* mesh,
|
||||
const Matrix4x4* modelViewMatrix,
|
||||
const Matrix3x3* normalMatrix,
|
||||
const Appearance* appearance,
|
||||
IDirect3DTexture9* texture
|
||||
)
|
||||
{
|
||||
D3DMATRIX worldView = ToD3DMATRIX(*modelViewMatrix);
|
||||
g_device->SetTransform(D3DTS_WORLD, &worldView);
|
||||
D3DMATRIX proj = ToD3DMATRIX(m_projection);
|
||||
g_device->SetTransform(D3DTS_PROJECTION, &proj);
|
||||
|
||||
D3DMATERIAL9 mat = {};
|
||||
mat.Diffuse.r = appearance->color.r / 255.0f;
|
||||
mat.Diffuse.g = appearance->color.g / 255.0f;
|
||||
mat.Diffuse.b = appearance->color.b / 255.0f;
|
||||
mat.Diffuse.a = appearance->color.a / 255.0f;
|
||||
mat.Ambient = mat.Diffuse;
|
||||
|
||||
if (appearance->shininess != 0) {
|
||||
g_device->SetRenderState(D3DRS_SPECULARENABLE, TRUE);
|
||||
mat.Specular.r = 1.0f;
|
||||
mat.Specular.g = 1.0f;
|
||||
mat.Specular.b = 1.0f;
|
||||
mat.Specular.a = 1.0f;
|
||||
mat.Power = appearance->shininess;
|
||||
}
|
||||
else {
|
||||
g_device->SetRenderState(D3DRS_SPECULARENABLE, FALSE);
|
||||
mat.Specular.r = 0.0f;
|
||||
mat.Specular.g = 0.0f;
|
||||
mat.Specular.b = 0.0f;
|
||||
mat.Specular.a = 0.0f;
|
||||
mat.Power = 0.0f;
|
||||
}
|
||||
|
||||
g_device->SetMaterial(&mat);
|
||||
|
||||
if (texture) {
|
||||
g_device->SetTexture(0, texture);
|
||||
g_device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
||||
g_device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||
g_device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
|
||||
g_device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
|
||||
g_device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
||||
g_device->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
|
||||
}
|
||||
else {
|
||||
g_device->SetTexture(0, nullptr);
|
||||
}
|
||||
|
||||
g_device->SetRenderState(D3DRS_SHADEMODE, mesh->flat ? D3DSHADE_FLAT : D3DSHADE_GOURAUD);
|
||||
|
||||
g_device->SetStreamSource(0, mesh->vbo, 0, sizeof(BridgeSceneVertex));
|
||||
g_device->SetIndices(mesh->ibo);
|
||||
g_device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, mesh->vertexCount, 0, mesh->indexCount / 3);
|
||||
}
|
||||
|
||||
uint32_t Actual_FinalizeFrame(void* pixels, int pitch)
|
||||
{
|
||||
g_device->EndScene();
|
||||
|
||||
g_device->SetRenderTarget(0, g_oldRenderTarget);
|
||||
g_oldRenderTarget->Release();
|
||||
|
||||
LPDIRECT3DSURFACE9 sysMemSurf;
|
||||
HRESULT hr =
|
||||
g_device
|
||||
->CreateOffscreenPlainSurface(m_width, m_height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &sysMemSurf, nullptr);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = g_device->GetRenderTargetData(g_renderTargetSurf, sysMemSurf);
|
||||
if (FAILED(hr)) {
|
||||
sysMemSurf->Release();
|
||||
return hr;
|
||||
}
|
||||
|
||||
D3DLOCKED_RECT lockedRect;
|
||||
hr = sysMemSurf->LockRect(&lockedRect, nullptr, D3DLOCK_READONLY);
|
||||
if (FAILED(hr)) {
|
||||
sysMemSurf->Release();
|
||||
return hr;
|
||||
}
|
||||
|
||||
BYTE* src = static_cast<BYTE*>(lockedRect.pBits);
|
||||
BYTE* dst = static_cast<BYTE*>(pixels);
|
||||
int copyWidth = m_width * 4;
|
||||
|
||||
for (int y = 0; y < m_height; y++) {
|
||||
memcpy(dst + y * pitch, src + y * lockedRect.Pitch, copyWidth);
|
||||
}
|
||||
|
||||
sysMemSurf->UnlockRect();
|
||||
sysMemSurf->Release();
|
||||
|
||||
return hr;
|
||||
}
|
||||
76
miniwin/src/d3drm/backends/directx9/actual.h
Normal file
76
miniwin/src/d3drm/backends/directx9/actual.h
Normal file
@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
|
||||
#include "structs.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
typedef float Matrix4x4[4][4];
|
||||
|
||||
struct BridgeVector {
|
||||
float x, y, z;
|
||||
};
|
||||
|
||||
struct BridgeSceneLight {
|
||||
FColor color;
|
||||
BridgeVector position;
|
||||
float positional;
|
||||
BridgeVector direction;
|
||||
float directional;
|
||||
};
|
||||
|
||||
struct BridgeSceneVertex {
|
||||
BridgeVector position;
|
||||
BridgeVector normal;
|
||||
float tu, tv;
|
||||
};
|
||||
|
||||
struct IDirect3DRMTexture;
|
||||
struct IDirect3DTexture9;
|
||||
struct IDirect3DVertexBuffer9;
|
||||
struct IDirect3DIndexBuffer9;
|
||||
struct MeshGroup;
|
||||
|
||||
struct D3D9TextureCacheEntry {
|
||||
IDirect3DRMTexture* texture;
|
||||
uint32_t version;
|
||||
IDirect3DTexture9* dxTexture;
|
||||
};
|
||||
|
||||
struct D3D9MeshCacheEntry {
|
||||
const MeshGroup* meshGroup;
|
||||
uint32_t version;
|
||||
bool flat;
|
||||
|
||||
IDirect3DVertexBuffer9* vbo;
|
||||
uint32_t vertexCount;
|
||||
IDirect3DIndexBuffer9* ibo;
|
||||
uint32_t indexCount;
|
||||
};
|
||||
|
||||
bool Actual_Initialize(void* hwnd, int width, int height);
|
||||
void Actual_Shutdown();
|
||||
void Actual_PushLights(const BridgeSceneLight* lightsArray, size_t count);
|
||||
void Actual_SetProjection(const Matrix4x4* projection, float front, float back);
|
||||
IDirect3DTexture9* UploadSurfaceToD3DTexture(SDL_Surface* surface);
|
||||
void ReleaseD3DTexture(IDirect3DTexture9* dxTexture);
|
||||
void ReleaseD3DVertexBuffer(IDirect3DVertexBuffer9* buffer);
|
||||
void ReleaseD3DIndexBuffer(IDirect3DIndexBuffer9* buffer);
|
||||
void UploadMeshBuffers(
|
||||
const void* vertices,
|
||||
int vertexSize,
|
||||
const uint16_t* indices,
|
||||
int indexSize,
|
||||
D3D9MeshCacheEntry& cache
|
||||
);
|
||||
uint32_t Actual_BeginFrame();
|
||||
void Actual_EnableTransparency();
|
||||
void Actual_SubmitDraw(
|
||||
const D3D9MeshCacheEntry* mesh,
|
||||
const Matrix4x4* modelViewMatrix,
|
||||
const Matrix3x3* normalMatrix,
|
||||
const Appearance* appearance,
|
||||
IDirect3DTexture9* texture
|
||||
);
|
||||
uint32_t Actual_FinalizeFrame(void* pixels, int pitch);
|
||||
277
miniwin/src/d3drm/backends/directx9/renderer.cpp
Normal file
277
miniwin/src/d3drm/backends/directx9/renderer.cpp
Normal file
@ -0,0 +1,277 @@
|
||||
#include "d3drmrenderer_directx9.h"
|
||||
#include "ddraw_impl.h"
|
||||
#include "ddsurface_impl.h"
|
||||
#include "mathutils.h"
|
||||
#include "meshutils.h"
|
||||
#include "structs.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
static_assert(sizeof(Matrix4x4) == sizeof(D3DRMMATRIX4D), "Matrix4x4 is wrong size");
|
||||
static_assert(sizeof(BridgeVector) == sizeof(D3DVECTOR), "BridgeVector is wrong size");
|
||||
static_assert(sizeof(BridgeSceneLight) == sizeof(SceneLight), "BridgeSceneLight is wrong size");
|
||||
static_assert(sizeof(BridgeSceneVertex) == sizeof(D3DRMVERTEX), "BridgeSceneVertex is wrong size");
|
||||
|
||||
Direct3DRMRenderer* DirectX9Renderer::Create(DWORD width, DWORD height)
|
||||
{
|
||||
return new DirectX9Renderer(width, height);
|
||||
}
|
||||
|
||||
DirectX9Renderer::DirectX9Renderer(DWORD width, DWORD height) : m_width(width), m_height(height)
|
||||
{
|
||||
Actual_Initialize(
|
||||
SDL_GetPointerProperty(SDL_GetWindowProperties(DDWindow), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL),
|
||||
width,
|
||||
height
|
||||
);
|
||||
m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_ARGB8888);
|
||||
}
|
||||
|
||||
DirectX9Renderer::~DirectX9Renderer()
|
||||
{
|
||||
Actual_Shutdown();
|
||||
}
|
||||
|
||||
void DirectX9Renderer::PushLights(const SceneLight* lightsArray, size_t count)
|
||||
{
|
||||
Actual_PushLights((BridgeSceneLight*) lightsArray, count);
|
||||
}
|
||||
|
||||
void DirectX9Renderer::SetFrustumPlanes(const Plane* frustumPlanes)
|
||||
{
|
||||
}
|
||||
|
||||
void DirectX9Renderer::SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back)
|
||||
{
|
||||
Actual_SetProjection(&projection, front, back);
|
||||
}
|
||||
|
||||
struct TextureDestroyContextDX9 {
|
||||
DirectX9Renderer* renderer;
|
||||
Uint32 textureId;
|
||||
};
|
||||
|
||||
void DirectX9Renderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture)
|
||||
{
|
||||
auto* ctx = new TextureDestroyContextDX9{this, id};
|
||||
texture->AddDestroyCallback(
|
||||
[](IDirect3DRMObject* obj, void* arg) {
|
||||
auto* ctx = static_cast<TextureDestroyContextDX9*>(arg);
|
||||
auto& cache = ctx->renderer->m_textures[ctx->textureId];
|
||||
if (cache.dxTexture) {
|
||||
ReleaseD3DTexture(cache.dxTexture);
|
||||
cache.dxTexture = nullptr;
|
||||
cache.texture = nullptr;
|
||||
}
|
||||
delete ctx;
|
||||
},
|
||||
ctx
|
||||
);
|
||||
}
|
||||
|
||||
Uint32 DirectX9Renderer::GetTextureId(IDirect3DRMTexture* iTexture)
|
||||
{
|
||||
auto texture = static_cast<Direct3DRMTextureImpl*>(iTexture);
|
||||
auto surface = static_cast<DirectDrawSurfaceImpl*>(texture->m_surface);
|
||||
|
||||
for (Uint32 i = 0; i < m_textures.size(); ++i) {
|
||||
auto& tex = m_textures[i];
|
||||
if (tex.texture == texture) {
|
||||
if (tex.version != texture->m_version) {
|
||||
if (tex.dxTexture) {
|
||||
ReleaseD3DTexture(tex.dxTexture);
|
||||
tex.dxTexture = nullptr;
|
||||
}
|
||||
tex.dxTexture = UploadSurfaceToD3DTexture(surface->m_surface);
|
||||
if (!tex.dxTexture) {
|
||||
return NO_TEXTURE_ID;
|
||||
}
|
||||
tex.version = texture->m_version;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
IDirect3DTexture9* newTex = UploadSurfaceToD3DTexture(surface->m_surface);
|
||||
if (!newTex) {
|
||||
return NO_TEXTURE_ID;
|
||||
}
|
||||
|
||||
for (Uint32 i = 0; i < m_textures.size(); ++i) {
|
||||
auto& tex = m_textures[i];
|
||||
if (!tex.texture) {
|
||||
tex.texture = texture;
|
||||
tex.version = texture->m_version;
|
||||
tex.dxTexture = newTex;
|
||||
AddTextureDestroyCallback(i, texture);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
m_textures.push_back({texture, texture->m_version, newTex});
|
||||
AddTextureDestroyCallback((Uint32) (m_textures.size() - 1), texture);
|
||||
return (Uint32) (m_textures.size() - 1);
|
||||
}
|
||||
|
||||
D3D9MeshCacheEntry UploadD3D9Mesh(const MeshGroup& meshGroup)
|
||||
{
|
||||
D3D9MeshCacheEntry cache;
|
||||
cache.meshGroup = &meshGroup;
|
||||
cache.version = meshGroup.version;
|
||||
cache.flat = meshGroup.quality == D3DRMRENDER_FLAT || meshGroup.quality == D3DRMRENDER_UNLITFLAT;
|
||||
|
||||
std::vector<D3DRMVERTEX> vertices;
|
||||
std::vector<uint16_t> indices;
|
||||
|
||||
if (cache.flat) {
|
||||
FlattenSurfaces(
|
||||
meshGroup.vertices.data(),
|
||||
meshGroup.vertices.size(),
|
||||
meshGroup.indices.data(),
|
||||
meshGroup.indices.size(),
|
||||
meshGroup.texture != nullptr,
|
||||
vertices,
|
||||
indices
|
||||
);
|
||||
}
|
||||
else {
|
||||
vertices = meshGroup.vertices;
|
||||
indices.resize(meshGroup.indices.size());
|
||||
std::transform(meshGroup.indices.begin(), meshGroup.indices.end(), indices.begin(), [](DWORD i) {
|
||||
return static_cast<uint16_t>(i);
|
||||
});
|
||||
}
|
||||
|
||||
cache.indexCount = indices.size();
|
||||
cache.vertexCount = vertices.size();
|
||||
|
||||
UploadMeshBuffers(
|
||||
vertices.data(),
|
||||
vertices.size() * sizeof(D3DRMVERTEX),
|
||||
indices.data(),
|
||||
indices.size() * sizeof(uint16_t),
|
||||
cache
|
||||
);
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
struct D3D9MeshDestroyContext {
|
||||
DirectX9Renderer* renderer;
|
||||
Uint32 id;
|
||||
};
|
||||
|
||||
void DirectX9Renderer::AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh)
|
||||
{
|
||||
auto* ctx = new D3D9MeshDestroyContext{this, id};
|
||||
mesh->AddDestroyCallback(
|
||||
[](IDirect3DRMObject*, void* arg) {
|
||||
auto* ctx = static_cast<D3D9MeshDestroyContext*>(arg);
|
||||
auto& cache = ctx->renderer->m_meshs[ctx->id];
|
||||
if (cache.vbo) {
|
||||
ReleaseD3DVertexBuffer(cache.vbo);
|
||||
cache.vbo = nullptr;
|
||||
}
|
||||
if (cache.ibo) {
|
||||
ReleaseD3DIndexBuffer(cache.ibo);
|
||||
cache.ibo = nullptr;
|
||||
}
|
||||
cache.meshGroup = nullptr;
|
||||
|
||||
delete ctx;
|
||||
},
|
||||
ctx
|
||||
);
|
||||
}
|
||||
|
||||
Uint32 DirectX9Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup)
|
||||
{
|
||||
for (Uint32 i = 0; i < m_meshs.size(); ++i) {
|
||||
auto& cache = m_meshs[i];
|
||||
if (cache.meshGroup == meshGroup) {
|
||||
if (cache.version != meshGroup->version) {
|
||||
cache = UploadD3D9Mesh(*meshGroup);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
auto newCache = UploadD3D9Mesh(*meshGroup);
|
||||
|
||||
for (Uint32 i = 0; i < m_meshs.size(); ++i) {
|
||||
if (!m_meshs[i].meshGroup) {
|
||||
m_meshs[i] = std::move(newCache);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
m_meshs.push_back(std::move(newCache));
|
||||
return static_cast<Uint32>(m_meshs.size() - 1);
|
||||
}
|
||||
|
||||
DWORD DirectX9Renderer::GetWidth()
|
||||
{
|
||||
return m_width;
|
||||
}
|
||||
|
||||
DWORD DirectX9Renderer::GetHeight()
|
||||
{
|
||||
return m_height;
|
||||
}
|
||||
|
||||
void DirectX9Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc)
|
||||
{
|
||||
halDesc->dcmColorModel = D3DCOLORMODEL::RGB;
|
||||
halDesc->dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH;
|
||||
halDesc->dwDeviceZBufferBitDepth = DDBD_24;
|
||||
helDesc->dwDeviceRenderBitDepth = DDBD_32;
|
||||
halDesc->dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE;
|
||||
halDesc->dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND;
|
||||
halDesc->dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR;
|
||||
|
||||
memset(helDesc, 0, sizeof(D3DDEVICEDESC));
|
||||
}
|
||||
|
||||
const char* DirectX9Renderer::GetName()
|
||||
{
|
||||
return "DirectX 9 HAL";
|
||||
}
|
||||
|
||||
HRESULT DirectX9Renderer::BeginFrame()
|
||||
{
|
||||
return Actual_BeginFrame();
|
||||
}
|
||||
|
||||
void DirectX9Renderer::EnableTransparency()
|
||||
{
|
||||
Actual_EnableTransparency();
|
||||
}
|
||||
|
||||
void DirectX9Renderer::SubmitDraw(
|
||||
DWORD meshId,
|
||||
const D3DRMMATRIX4D& modelViewMatrix,
|
||||
const Matrix3x3& normalMatrix,
|
||||
const Appearance& appearance
|
||||
)
|
||||
{
|
||||
IDirect3DTexture9* texture = nullptr;
|
||||
if (appearance.textureId != NO_TEXTURE_ID) {
|
||||
texture = m_textures[appearance.textureId].dxTexture;
|
||||
}
|
||||
Actual_SubmitDraw(&m_meshs[meshId], &modelViewMatrix, &normalMatrix, &appearance, texture);
|
||||
}
|
||||
|
||||
HRESULT DirectX9Renderer::FinalizeFrame()
|
||||
{
|
||||
HRESULT hr = Actual_FinalizeFrame(m_renderedImage->pixels, m_renderedImage->pitch);
|
||||
if (hr != DD_OK) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Composite onto SDL backbuffer
|
||||
SDL_BlitSurface(m_renderedImage, nullptr, DDBackBuffer, nullptr);
|
||||
return hr;
|
||||
}
|
||||
@ -13,6 +13,9 @@
|
||||
#ifdef USE_OPENGLES2
|
||||
#include "d3drmrenderer_opengles2.h"
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#include "d3drmrenderer_directx9.h"
|
||||
#endif
|
||||
#include "d3drmrenderer_sdl3gpu.h"
|
||||
#include "d3drmrenderer_software.h"
|
||||
#include "d3drmtexture_impl.h"
|
||||
@ -156,6 +159,11 @@ HRESULT Direct3DRMImpl::CreateDeviceFromSurface(
|
||||
else if (SDL_memcmp(&guid, &OpenGL1_GUID, sizeof(GUID)) == 0) {
|
||||
renderer = OpenGL1Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight);
|
||||
}
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
else if (SDL_memcmp(&guid, &DirectX9_GUID, sizeof(GUID)) == 0) {
|
||||
renderer = DirectX9Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Device GUID not recognized");
|
||||
|
||||
@ -4,6 +4,9 @@
|
||||
#ifdef USE_OPENGLES2
|
||||
#include "d3drmrenderer_opengles2.h"
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#include "d3drmrenderer_directx9.h"
|
||||
#endif
|
||||
#include "d3drmrenderer_sdl3gpu.h"
|
||||
#include "d3drmrenderer_software.h"
|
||||
#include "ddpalette_impl.h"
|
||||
@ -225,6 +228,9 @@ HRESULT DirectDrawImpl::EnumDevices(LPD3DENUMDEVICESCALLBACK cb, void* ctx)
|
||||
#endif
|
||||
#ifdef USE_OPENGL1
|
||||
OpenGL1Renderer_EnumDevice(cb, ctx);
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
DirectX9Renderer_EnumDevice(cb, ctx);
|
||||
#endif
|
||||
Direct3DRMSoftware_EnumDevice(cb, ctx);
|
||||
|
||||
@ -332,6 +338,11 @@ HRESULT DirectDrawImpl::CreateDevice(
|
||||
else if (SDL_memcmp(&guid, &OpenGL1_GUID, sizeof(GUID)) == 0) {
|
||||
renderer = OpenGL1Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight);
|
||||
}
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
else if (SDL_memcmp(&guid, &DirectX9_GUID, sizeof(GUID)) == 0) {
|
||||
renderer = DirectX9Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight);
|
||||
}
|
||||
#endif
|
||||
else if (SDL_memcmp(&guid, &SOFTWARE_GUID, sizeof(GUID)) == 0) {
|
||||
renderer = new Direct3DRMSoftwareRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight);
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include "mathutils.h"
|
||||
#include "miniwin/d3drm.h"
|
||||
#include "miniwin/miniwindevice.h"
|
||||
#include "structs.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
@ -11,17 +12,6 @@
|
||||
|
||||
static_assert(sizeof(D3DRMVERTEX) == 32);
|
||||
|
||||
struct Appearance {
|
||||
SDL_Color color;
|
||||
float shininess;
|
||||
Uint32 textureId;
|
||||
Uint32 flat;
|
||||
};
|
||||
|
||||
struct FColor {
|
||||
float r, g, b, a;
|
||||
};
|
||||
|
||||
struct SceneLight {
|
||||
FColor color;
|
||||
D3DVECTOR position;
|
||||
|
||||
55
miniwin/src/internal/d3drmrenderer_directx9.h
Normal file
55
miniwin/src/internal/d3drmrenderer_directx9.h
Normal file
@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include "../d3drm/backends/directx9/actual.h"
|
||||
#include "d3drmrenderer.h"
|
||||
#include "d3drmtexture_impl.h"
|
||||
#include "ddraw_impl.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
DEFINE_GUID(DirectX9_GUID, 0x682656F3, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05);
|
||||
|
||||
class DirectX9Renderer : public Direct3DRMRenderer {
|
||||
public:
|
||||
static Direct3DRMRenderer* Create(DWORD width, DWORD height);
|
||||
DirectX9Renderer(DWORD width, DWORD height);
|
||||
~DirectX9Renderer() override;
|
||||
|
||||
void PushLights(const SceneLight* lightsArray, size_t count) override;
|
||||
void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override;
|
||||
void SetFrustumPlanes(const Plane* frustumPlanes) override;
|
||||
Uint32 GetTextureId(IDirect3DRMTexture* texture) override;
|
||||
Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override;
|
||||
DWORD GetWidth() override;
|
||||
DWORD GetHeight() override;
|
||||
void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override;
|
||||
const char* GetName() override;
|
||||
HRESULT BeginFrame() override;
|
||||
void EnableTransparency() override;
|
||||
void SubmitDraw(
|
||||
DWORD meshId,
|
||||
const D3DRMMATRIX4D& modelViewMatrix,
|
||||
const Matrix3x3& normalMatrix,
|
||||
const Appearance& appearance
|
||||
) override;
|
||||
HRESULT FinalizeFrame() override;
|
||||
|
||||
private:
|
||||
void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture);
|
||||
void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh);
|
||||
|
||||
SDL_Surface* m_renderedImage;
|
||||
DWORD m_width, m_height;
|
||||
std::vector<SceneLight> m_lights;
|
||||
std::vector<D3D9MeshCacheEntry> m_meshs;
|
||||
std::vector<D3D9TextureCacheEntry> m_textures;
|
||||
};
|
||||
|
||||
inline static void DirectX9Renderer_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx)
|
||||
{
|
||||
Direct3DRMRenderer* device = DirectX9Renderer::Create(640, 480);
|
||||
if (device) {
|
||||
EnumDevice(cb, ctx, device, DirectX9_GUID);
|
||||
delete device;
|
||||
}
|
||||
}
|
||||
17
miniwin/src/internal/structs.h
Normal file
17
miniwin/src/internal/structs.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef float Matrix3x3[3][3];
|
||||
|
||||
struct FColor {
|
||||
float r, g, b, a;
|
||||
};
|
||||
|
||||
struct Appearance {
|
||||
SDL_Color color;
|
||||
float shininess;
|
||||
uint32_t textureId;
|
||||
uint32_t flat;
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user