Upgrade OpenGL ES renderer to 3.0, add option for MSAA (#636)

This commit is contained in:
Christian Semmler 2025-07-23 11:00:48 -07:00 committed by GitHub
parent 8f6bfe078b
commit a5a3c4ec83
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 324 additions and 213 deletions

View File

@ -14,7 +14,7 @@ endif()
if (EMSCRIPTEN)
add_compile_options(-pthread)
add_link_options(-sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=2gb -sUSE_PTHREADS=1 -sPROXY_TO_PTHREAD=1 -sOFFSCREENCANVAS_SUPPORT=1 -sPTHREAD_POOL_SIZE_STRICT=0 -sFORCE_FILESYSTEM=1 -sWASMFS=1 -sEXIT_RUNTIME=1)
add_link_options(-sUSE_WEBGL2=1 -sMIN_WEBGL_VERSION=2 -sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=2gb -sUSE_PTHREADS=1 -sPROXY_TO_PTHREAD=1 -sOFFSCREENCANVAS_SUPPORT=1 -sPTHREAD_POOL_SIZE_STRICT=0 -sFORCE_FILESYSTEM=1 -sWASMFS=1 -sEXIT_RUNTIME=1)
set(SDL_PTHREADS ON CACHE BOOL "Enable SDL pthreads" FORCE)
endif()
@ -181,6 +181,8 @@ target_include_directories(lego1 PUBLIC "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/L
target_link_libraries(lego1 PRIVATE SDL3::SDL3)
target_link_libraries(lego1 PUBLIC SDL3::Headers)
target_link_libraries(lego1 PRIVATE $<$<BOOL:${ISLE_USE_DX5}>:DirectX5::DirectX5>)
# Allow unconditional include of miniwin/miniwind3d.h
target_link_libraries(lego1 PRIVATE miniwin-headers)
if(WIN32)
set_property(TARGET lego1 PROPERTY PREFIX "")
endif()

View File

@ -182,6 +182,7 @@ IsleApp::IsleApp()
m_exclusiveFrameRate = 60.00f;
m_frameRate = 100.0f;
m_exclusiveFullScreen = FALSE;
m_msaaSamples = 0;
}
// FUNCTION: ISLE 0x4011a0
@ -914,6 +915,7 @@ MxResult IsleApp::SetupWindow()
#endif
window = SDL_CreateWindowWithProperties(props);
SDL_SetPointerProperty(SDL_GetWindowProperties(window), ISLE_PROP_WINDOW_CREATE_VIDEO_PARAM, &m_videoParam);
if (m_exclusiveFullScreen && m_fullScreen) {
SDL_DisplayMode closestMode;
@ -1188,6 +1190,7 @@ bool IsleApp::LoadConfig()
}
m_frameRate = (1000.0f / iniparser_getdouble(dict, "isle:Frame Delta", m_frameDelta));
m_frameDelta = static_cast<int>(std::round(iniparser_getdouble(dict, "isle:Frame Delta", m_frameDelta)));
m_videoParam.SetMSAASamples(iniparser_getint(dict, "isle:MSAA", m_msaaSamples));
const char* deviceId = iniparser_getstring(dict, "isle:3D Device ID", NULL);
if (deviceId != NULL) {

View File

@ -114,6 +114,7 @@ private:
MxFloat m_exclusiveFrameRate;
MxFloat m_frameRate;
MxBool m_exclusiveFullScreen;
MxU32 m_msaaSamples;
};
extern IsleApp* g_isle;

View File

@ -1,7 +1,12 @@
#ifndef MINIWIN
#include <initguid.h>
#endif
#include "mxdirect3d.h"
#include <SDL3/SDL.h> // for SDL_Log
#include <assert.h>
#include <miniwin/miniwind3d.h>
DECOMP_SIZE_ASSERT(MxDirect3D, 0x894)
@ -44,6 +49,7 @@ BOOL MxDirect3D::Create(
)
{
BOOL success = FALSE;
IDirect3DMiniwin* miniwind3d = nullptr;
assert(m_currentDeviceInfo);
if (!MxDirectDraw::Create(
@ -64,6 +70,20 @@ BOOL MxDirect3D::Create(
goto done;
}
if (m_pDirect3d->QueryInterface(IID_IDirect3DMiniwin, (void**) &miniwind3d) == DD_OK) {
MxVideoParam* videoParam = (MxVideoParam*) SDL_GetPointerProperty(
SDL_GetWindowProperties(reinterpret_cast<SDL_Window*>(hWnd)),
ISLE_PROP_WINDOW_CREATE_VIDEO_PARAM,
nullptr
);
#ifndef MXDIRECTX_FOR_CONFIG
assert(videoParam);
#endif
if (videoParam) {
miniwind3d->RequestMSAA(videoParam->GetMSAASamples());
}
}
if (!D3DSetMode()) {
goto done;
}

View File

@ -1,7 +1,10 @@
#include "mxdirectxinfo.h"
#include "omni/include/mxvideoparam.h"
#include <SDL3/SDL_log.h>
#include <assert.h>
#include <miniwin/miniwind3d.h>
#include <stdio.h> // for vsprintf
DECOMP_SIZE_ASSERT(MxAssignedDevice, 0xe4)
@ -216,12 +219,28 @@ BOOL MxDeviceEnumerate::EnumDirectDrawCallback(LPGUID p_guid, LPSTR p_driverDesc
LPDIRECTDRAW lpDD = NULL;
MxDriver& newDevice = m_ddInfo.back();
HRESULT result = DirectDrawCreate(newDevice.m_guid, &lpDD, NULL);
IDirect3DMiniwin* miniwind3d = nullptr;
if (result != DD_OK) {
BuildErrorString("DirectDraw Create failed: %s\n", EnumerateErrorToString(result));
goto done;
}
result = lpDD->QueryInterface(IID_IDirect3DMiniwin, (void**) &miniwind3d);
if (result == DD_OK) {
MxVideoParam* videoParam = (MxVideoParam*) SDL_GetPointerProperty(
SDL_GetWindowProperties(reinterpret_cast<SDL_Window*>(m_hWnd)),
ISLE_PROP_WINDOW_CREATE_VIDEO_PARAM,
nullptr
);
#ifndef MXDIRECTX_FOR_CONFIG
assert(videoParam);
#endif
if (videoParam) {
miniwind3d->RequestMSAA(videoParam->GetMSAASamples());
}
}
result = lpDD->SetCooperativeLevel(m_hWnd, DDSCL_NORMAL);
if (result != DD_OK) {
BuildErrorString("SetCooperativeLevel failed: %s\n", EnumerateErrorToString(result));

View File

@ -15,6 +15,8 @@
class MxPalette;
#define ISLE_PROP_WINDOW_CREATE_VIDEO_PARAM "ISLE.window.create.videoParam"
// SIZE 0x24
class MxVideoParam {
public:
@ -51,6 +53,9 @@ public:
// FUNCTION: BETA10 0x10141fe0
void SetBackBuffers(MxU32 p_backBuffers) { m_backBuffers = p_backBuffers; }
void SetMSAASamples(MxU32 p_msaaSamples) { m_msaaSamples = p_msaaSamples; }
MxU32 GetMSAASamples() { return m_msaaSamples; }
private:
MxRect32 m_rect; // 0x00
MxPalette* m_palette; // 0x10
@ -58,6 +63,7 @@ private:
MxVideoParamFlags m_flags; // 0x18
int m_unk0x1c; // 0x1c
char* m_deviceId; // 0x20
MxU32 m_msaaSamples;
};
#endif // MXVIDEOPARAM_H

View File

@ -28,6 +28,7 @@ MxVideoParam::MxVideoParam(MxRect32& p_rect, MxPalette* p_palette, MxULong p_bac
m_flags = p_flags;
m_unk0x1c = 0;
m_deviceId = NULL;
m_msaaSamples = 0;
}
// FUNCTION: LEGO1 0x100becf0
@ -41,6 +42,7 @@ MxVideoParam::MxVideoParam(MxVideoParam& p_videoParam)
m_unk0x1c = p_videoParam.m_unk0x1c;
m_deviceId = NULL;
SetDeviceName(p_videoParam.m_deviceId);
m_msaaSamples = p_videoParam.m_msaaSamples;
}
// FUNCTION: LEGO1 0x100bed50
@ -82,6 +84,7 @@ MxVideoParam& MxVideoParam::operator=(const MxVideoParam& p_videoParam)
m_flags = p_videoParam.m_flags;
m_unk0x1c = p_videoParam.m_unk0x1c;
SetDeviceName(p_videoParam.m_deviceId);
m_msaaSamples = p_videoParam.m_msaaSamples;
return *this;
}

View File

@ -44,16 +44,16 @@ if(NOT WINDOWS_STORE)
message(STATUS "🧩 OpenGL 1.x support not enabled — needs OpenGL")
endif()
find_library(OPENGL_ES2_LIBRARY NAMES GLESv2)
if(EMSCRIPTEN OR OPENGL_ES2_LIBRARY)
message(STATUS "Found OpenGL: enabling OpenGL ES 2.x renderer")
target_sources(miniwin PRIVATE src/d3drm/backends/opengles2/renderer.cpp)
list(APPEND GRAPHICS_BACKENDS USE_OPENGLES2)
if(OPENGL_ES2_LIBRARY)
target_link_libraries(miniwin PRIVATE ${OPENGL_ES2_LIBRARY})
find_library(OPENGL_ES3_LIBRARY NAMES GLESv2)
if(EMSCRIPTEN OR OPENGL_ES3_LIBRARY)
message(STATUS "Found OpenGL: enabling OpenGL ES 3.x renderer")
target_sources(miniwin PRIVATE src/d3drm/backends/opengles3/renderer.cpp)
list(APPEND GRAPHICS_BACKENDS USE_OPENGLES3)
if(OPENGL_ES3_LIBRARY)
target_link_libraries(miniwin PRIVATE ${OPENGL_ES3_LIBRARY})
endif()
else()
message(STATUS "🧩 OpenGL ES 2.x support not enabled")
message(STATUS "🧩 OpenGL ES 3.x support not enabled")
endif()
endif()

View File

@ -0,0 +1,8 @@
#pragma once
DEFINE_GUID(IID_IDirect3DMiniwin, 0xf8a97f2d, 0x9b3a, 0x4f1c, 0x9e, 0x8d, 0x6a, 0x5b, 0x4c, 0x3d, 0x2e, 0x1f);
struct IDirect3DMiniwin : virtual public IUnknown {
virtual HRESULT RequestMSAA(DWORD msaaSamples) = 0;
virtual DWORD GetMSAASamples() const = 0;
};

View File

@ -1,8 +1,8 @@
#include "d3drmrenderer_opengles2.h"
#include "d3drmrenderer_opengles3.h"
#include "meshutils.h"
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <GLES3/gl3.h>
#include <SDL3/SDL.h>
#include <algorithm>
#include <string>
@ -15,20 +15,29 @@ static GLuint CompileShader(GLenum type, const char* source)
GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
glDeleteShader(shader);
GLint logLength = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
std::vector<char> log(logLength);
glGetShaderInfoLog(shader, logLength, nullptr, log.data());
SDL_Log("Shader compile error: %s", log.data());
}
else {
SDL_Log("CompileShader (%s)", SDL_GetError());
}
glDeleteShader(shader);
return 0;
}
return shader;
}
struct SceneLightGLES2 {
struct SceneLightGLES3 {
float color[4];
float position[4];
float direction[4];
};
Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height)
Direct3DRMRenderer* OpenGLES3Renderer::Create(DWORD width, DWORD height, DWORD msaaSamples)
{
// We have to reset the attributes here after having enumerated the
// OpenGL ES 2.0 renderer, or else SDL gets very confused by SDL_GL_DEPTH_SIZE
@ -37,7 +46,7 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height)
// But ResetAttributes resets it to 16.
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
if (!DDWindow) {
@ -61,18 +70,20 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height)
glCullFace(GL_BACK);
glFrontFace(GL_CW);
const char* vertexShaderSource = R"(
attribute vec3 a_position;
attribute vec3 a_normal;
attribute vec2 a_texCoord;
const char* vertexShaderSource = R"(#version 300 es
precision mediump float;
in vec3 a_position;
in vec3 a_normal;
in vec2 a_texCoord;
uniform mat4 u_modelViewMatrix;
uniform mat3 u_normalMatrix;
uniform mat4 u_projectionMatrix;
varying vec3 v_viewPos;
varying vec3 v_normal;
varying vec2 v_texCoord;
out vec3 v_viewPos;
out vec3 v_normal;
out vec2 v_texCoord;
void main() {
vec4 viewPos = u_modelViewMatrix * vec4(a_position, 1.0);
@ -83,7 +94,7 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height)
}
)";
const char* fragmentShaderSource = R"(
const char* fragmentShaderSource = R"(#version 300 es
precision mediump float;
struct SceneLight {
@ -95,22 +106,22 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height)
uniform SceneLight u_lights[3];
uniform int u_lightCount;
varying vec3 v_viewPos;
varying vec3 v_normal;
varying vec2 v_texCoord;
in vec3 v_viewPos;
in vec3 v_normal;
in vec2 v_texCoord;
uniform float u_shininess;
uniform vec4 u_color;
uniform int u_useTexture;
uniform bool u_useTexture;
uniform sampler2D u_texture;
out vec4 fragColor;
void main() {
vec3 diffuse = vec3(0.0);
vec3 specular = vec3(0.0);
for (int i = 0; i < 3; ++i) {
if (i >= u_lightCount) break;
for (int i = 0; i < u_lightCount; ++i) {
vec3 lightColor = u_lights[i].color.rgb;
if (u_lights[i].position.w == 0.0 && u_lights[i].direction.w == 0.0) {
@ -134,7 +145,7 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height)
// Specular
if (u_shininess > 0.0 && u_lights[i].direction.w == 1.0) {
vec3 viewVec = normalize(-v_viewPos); // Assuming camera at origin
vec3 viewVec = normalize(-v_viewPos);
vec3 H = normalize(lightVec + viewVec);
float dotNH = max(dot(v_normal, H), 0.0);
float spec = pow(dotNH, u_shininess);
@ -145,13 +156,13 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height)
vec4 finalColor = u_color;
finalColor.rgb = clamp(diffuse * u_color.rgb + specular, 0.0, 1.0);
if (u_useTexture != 0) {
vec4 texel = texture2D(u_texture, v_texCoord);
if (u_useTexture) {
vec4 texel = texture(u_texture, v_texCoord);
finalColor.rgb = clamp(texel.rgb * finalColor.rgb, 0.0, 1.0);
finalColor.a = texel.a;
}
gl_FragColor = finalColor;
fragColor = finalColor;
}
)";
@ -168,12 +179,12 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height)
glDeleteShader(vs);
glDeleteShader(fs);
return new OpenGLES2Renderer(width, height, context, shaderProgram);
return new OpenGLES3Renderer(width, height, msaaSamples, context, shaderProgram);
}
GLES2MeshCacheEntry GLES2UploadMesh(const MeshGroup& meshGroup, bool forceUV = false)
GLES3MeshCacheEntry OpenGLES3Renderer::GLES3UploadMesh(const MeshGroup& meshGroup, bool forceUV)
{
GLES2MeshCacheEntry cache{&meshGroup, meshGroup.version};
GLES3MeshCacheEntry cache{&meshGroup, meshGroup.version};
cache.flat = meshGroup.quality == D3DRMRENDER_FLAT || meshGroup.quality == D3DRMRENDER_UNLITFLAT;
@ -211,18 +222,27 @@ GLES2MeshCacheEntry GLES2UploadMesh(const MeshGroup& meshGroup, bool forceUV = f
std::vector<D3DVECTOR> normals(vertices.size());
std::transform(vertices.begin(), vertices.end(), normals.begin(), [](const D3DRMVERTEX& v) { return v.normal; });
glGenVertexArrays(1, &cache.vao);
glBindVertexArray(cache.vao);
glGenBuffers(1, &cache.vboPositions);
glBindBuffer(GL_ARRAY_BUFFER, cache.vboPositions);
glBufferData(GL_ARRAY_BUFFER, positions.size() * sizeof(D3DVECTOR), positions.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(m_posLoc);
glVertexAttribPointer(m_posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glGenBuffers(1, &cache.vboNormals);
glBindBuffer(GL_ARRAY_BUFFER, cache.vboNormals);
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(D3DVECTOR), normals.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(m_normLoc);
glVertexAttribPointer(m_normLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
if (meshGroup.texture || forceUV) {
glGenBuffers(1, &cache.vboTexcoords);
glBindBuffer(GL_ARRAY_BUFFER, cache.vboTexcoords);
glBufferData(GL_ARRAY_BUFFER, texcoords.size() * sizeof(TexCoord), texcoords.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(m_texLoc);
glVertexAttribPointer(m_texLoc, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
}
glGenBuffers(1, &cache.ibo);
@ -234,6 +254,8 @@ GLES2MeshCacheEntry GLES2UploadMesh(const MeshGroup& meshGroup, bool forceUV = f
GL_STATIC_DRAW
);
glBindVertexArray(0);
return cache;
}
@ -262,7 +284,7 @@ bool UploadTexture(SDL_Surface* source, GLuint& outTexId, bool isUI)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (strstr((const char*) glGetString(GL_EXTENSIONS), "GL_EXT_texture_filter_anisotropic")) {
if (SDL_GL_ExtensionSupported("GL_EXT_texture_filter_anisotropic")) {
GLfloat maxAniso = 0.0f;
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAniso);
GLfloat desiredAniso = fminf(8.0f, maxAniso);
@ -278,12 +300,35 @@ bool UploadTexture(SDL_Surface* source, GLuint& outTexId, bool isUI)
return true;
}
OpenGLES2Renderer::OpenGLES2Renderer(DWORD width, DWORD height, SDL_GLContext context, GLuint shaderProgram)
: m_context(context), m_shaderProgram(shaderProgram)
OpenGLES3Renderer::OpenGLES3Renderer(
DWORD width,
DWORD height,
DWORD msaaSamples,
SDL_GLContext context,
GLuint shaderProgram
)
: m_context(context), m_shaderProgram(shaderProgram), m_msaa(msaaSamples)
{
glGenFramebuffers(1, &m_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
GLint maxSamples;
glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
if (m_msaa > maxSamples) {
m_msaa = maxSamples;
}
SDL_Log(
"MSAA is %s. Requested samples: %d, active samples: %d, max samples: %d",
m_msaa > 1 ? "on" : "off",
msaaSamples,
m_msaa,
maxSamples
);
if (m_msaa > 1) {
glGenFramebuffers(1, &m_resolveFBO);
}
m_virtualWidth = width;
m_virtualHeight = height;
ViewportTransform viewportTransform = {1.0f, 0.0f, 0.0f};
@ -310,14 +355,6 @@ OpenGLES2Renderer::OpenGLES2Renderer(DWORD width, DWORD height, SDL_GLContext co
}
SDL_DestroySurface(dummySurface);
m_uiMesh.vertices = {
{{0.0f, 0.0f, 0.0f}, {0, 0, -1}, {0.0f, 0.0f}},
{{1.0f, 0.0f, 0.0f}, {0, 0, -1}, {1.0f, 0.0f}},
{{1.0f, 1.0f, 0.0f}, {0, 0, -1}, {1.0f, 1.0f}},
{{0.0f, 1.0f, 0.0f}, {0, 0, -1}, {0.0f, 1.0f}}
};
m_uiMesh.indices = {0, 1, 2, 0, 2, 3};
m_uiMeshCache = GLES2UploadMesh(m_uiMesh, true);
m_posLoc = glGetAttribLocation(m_shaderProgram, "a_position");
m_normLoc = glGetAttribLocation(m_shaderProgram, "a_normal");
m_texLoc = glGetAttribLocation(m_shaderProgram, "a_texCoord");
@ -336,17 +373,35 @@ OpenGLES2Renderer::OpenGLES2Renderer(DWORD width, DWORD height, SDL_GLContext co
m_normalMatrixLoc = glGetUniformLocation(m_shaderProgram, "u_normalMatrix");
m_projectionMatrixLoc = glGetUniformLocation(m_shaderProgram, "u_projectionMatrix");
m_uiMesh.vertices = {
{{0.0f, 0.0f, 0.0f}, {0, 0, -1}, {0.0f, 0.0f}},
{{1.0f, 0.0f, 0.0f}, {0, 0, -1}, {1.0f, 0.0f}},
{{1.0f, 1.0f, 0.0f}, {0, 0, -1}, {1.0f, 1.0f}},
{{0.0f, 1.0f, 0.0f}, {0, 0, -1}, {0.0f, 1.0f}}
};
m_uiMesh.indices = {0, 1, 2, 0, 2, 3};
m_uiMeshCache = GLES3UploadMesh(m_uiMesh, true);
glUseProgram(m_shaderProgram);
}
OpenGLES2Renderer::~OpenGLES2Renderer()
OpenGLES3Renderer::~OpenGLES3Renderer()
{
SDL_DestroySurface(m_renderedImage);
glDeleteTextures(1, &m_dummyTexture);
glDeleteProgram(m_shaderProgram);
glDeleteRenderbuffers(1, &m_colorTarget);
glDeleteRenderbuffers(1, &m_depthTarget);
glDeleteFramebuffers(1, &m_fbo);
if (m_msaa > 1) {
glDeleteRenderbuffers(1, &m_resolveColor);
glDeleteFramebuffers(1, &m_resolveFBO);
}
SDL_GL_DestroyContext(m_context);
}
void OpenGLES2Renderer::PushLights(const SceneLight* lightsArray, size_t count)
void OpenGLES3Renderer::PushLights(const SceneLight* lightsArray, size_t count)
{
if (count > 3) {
SDL_Log("Unsupported number of lights (%d)", static_cast<int>(count));
@ -356,21 +411,21 @@ void OpenGLES2Renderer::PushLights(const SceneLight* lightsArray, size_t count)
m_lights.assign(lightsArray, lightsArray + count);
}
void OpenGLES2Renderer::SetFrustumPlanes(const Plane* frustumPlanes)
void OpenGLES3Renderer::SetFrustumPlanes(const Plane* frustumPlanes)
{
}
void OpenGLES2Renderer::SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back)
void OpenGLES3Renderer::SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back)
{
memcpy(&m_projection, projection, sizeof(D3DRMMATRIX4D));
}
struct TextureDestroyContextGLS2 {
OpenGLES2Renderer* renderer;
OpenGLES3Renderer* renderer;
Uint32 textureId;
};
void OpenGLES2Renderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture)
void OpenGLES3Renderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture)
{
auto* ctx = new TextureDestroyContextGLS2{this, id};
texture->AddDestroyCallback(
@ -388,7 +443,7 @@ void OpenGLES2Renderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture*
);
}
Uint32 OpenGLES2Renderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUI, float scaleX, float scaleY)
Uint32 OpenGLES3Renderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUI, float scaleX, float scaleY)
{
SDL_GL_MakeCurrent(DDWindow, m_context);
auto texture = static_cast<Direct3DRMTextureImpl*>(iTexture);
@ -432,42 +487,43 @@ Uint32 OpenGLES2Renderer::GetTextureId(IDirect3DRMTexture* iTexture, bool isUI,
return (Uint32) (m_textures.size() - 1);
}
struct GLES2MeshDestroyContext {
OpenGLES2Renderer* renderer;
struct GLES3MeshDestroyContext {
OpenGLES3Renderer* renderer;
Uint32 id;
};
void OpenGLES2Renderer::AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh)
void OpenGLES3Renderer::AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh)
{
auto* ctx = new GLES2MeshDestroyContext{this, id};
auto* ctx = new GLES3MeshDestroyContext{this, id};
mesh->AddDestroyCallback(
[](IDirect3DRMObject*, void* arg) {
auto* ctx = static_cast<GLES2MeshDestroyContext*>(arg);
auto* ctx = static_cast<GLES3MeshDestroyContext*>(arg);
auto& cache = ctx->renderer->m_meshs[ctx->id];
cache.meshGroup = nullptr;
glDeleteBuffers(1, &cache.vboPositions);
glDeleteBuffers(1, &cache.vboNormals);
glDeleteBuffers(1, &cache.vboTexcoords);
glDeleteBuffers(1, &cache.ibo);
glDeleteVertexArrays(1, &cache.vao);
delete ctx;
},
ctx
);
}
Uint32 OpenGLES2Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup)
Uint32 OpenGLES3Renderer::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 = std::move(GLES2UploadMesh(*meshGroup));
cache = std::move(GLES3UploadMesh(*meshGroup));
}
return i;
}
}
auto newCache = GLES2UploadMesh(*meshGroup);
auto newCache = GLES3UploadMesh(*meshGroup);
for (Uint32 i = 0; i < m_meshs.size(); ++i) {
auto& cache = m_meshs[i];
@ -483,7 +539,7 @@ Uint32 OpenGLES2Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* mesh
return (Uint32) (m_meshs.size() - 1);
}
HRESULT OpenGLES2Renderer::BeginFrame()
HRESULT OpenGLES3Renderer::BeginFrame()
{
SDL_GL_MakeCurrent(DDWindow, m_context);
m_dirty = true;
@ -495,7 +551,7 @@ HRESULT OpenGLES2Renderer::BeginFrame()
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
SceneLightGLES2 lightData[3];
SceneLightGLES3 lightData[3];
int lightCount = std::min(static_cast<int>(m_lights.size()), 3);
for (int i = 0; i < lightCount; ++i) {
@ -525,14 +581,14 @@ HRESULT OpenGLES2Renderer::BeginFrame()
return DD_OK;
}
void OpenGLES2Renderer::EnableTransparency()
void OpenGLES3Renderer::EnableTransparency()
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask(GL_FALSE);
}
void OpenGLES2Renderer::SubmitDraw(
void OpenGLES3Renderer::SubmitDraw(
DWORD meshId,
const D3DRMMATRIX4D& modelViewMatrix,
const D3DRMMATRIX4D& worldMatrix,
@ -570,28 +626,12 @@ void OpenGLES2Renderer::SubmitDraw(
glUniform1i(m_textureLoc, 0);
}
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboPositions);
glEnableVertexAttribArray(m_posLoc);
glVertexAttribPointer(m_posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboNormals);
glEnableVertexAttribArray(m_normLoc);
glVertexAttribPointer(m_normLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
if (appearance.textureId != NO_TEXTURE_ID) {
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboTexcoords);
glEnableVertexAttribArray(m_texLoc);
glVertexAttribPointer(m_texLoc, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.ibo);
glBindVertexArray(mesh.vao);
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(mesh.indices.size()), GL_UNSIGNED_SHORT, nullptr);
glDisableVertexAttribArray(m_normLoc);
glDisableVertexAttribArray(m_texLoc);
glBindVertexArray(0);
}
HRESULT OpenGLES2Renderer::FinalizeFrame()
HRESULT OpenGLES3Renderer::FinalizeFrame()
{
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
@ -599,7 +639,7 @@ HRESULT OpenGLES2Renderer::FinalizeFrame()
return DD_OK;
}
void OpenGLES2Renderer::Resize(int width, int height, const ViewportTransform& viewportTransform)
void OpenGLES3Renderer::Resize(int width, int height, const ViewportTransform& viewportTransform)
{
SDL_GL_MakeCurrent(DDWindow, m_context);
m_width = width;
@ -610,37 +650,65 @@ void OpenGLES2Renderer::Resize(int width, int height, const ViewportTransform& v
}
m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32);
if (m_colorTarget) {
glDeleteRenderbuffers(1, &m_colorTarget);
m_colorTarget = 0;
}
if (m_resolveColor) {
glDeleteRenderbuffers(1, &m_resolveColor);
m_resolveColor = 0;
}
if (m_depthTarget) {
glDeleteRenderbuffers(1, &m_depthTarget);
m_depthTarget = 0;
}
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
// Create color texture
glGenTextures(1, &m_colorTarget);
glBindTexture(GL_TEXTURE_2D, m_colorTarget);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorTarget, 0);
glGenRenderbuffers(1, &m_colorTarget);
glBindRenderbuffer(GL_RENDERBUFFER, m_colorTarget);
if (m_msaa > 1) {
glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_msaa, GL_RGBA8, width, height);
}
else {
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
}
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_colorTarget);
// Create depth renderbuffer
glGenRenderbuffers(1, &m_depthTarget);
glBindRenderbuffer(GL_RENDERBUFFER, m_depthTarget);
if (SDL_GL_ExtensionSupported("GL_OES_depth24")) {
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES, width, height);
}
else if (SDL_GL_ExtensionSupported("GL_OES_depth32")) {
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32_OES, width, height);
if (m_msaa > 1) {
glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_msaa, GL_DEPTH_COMPONENT24, width, height);
}
else {
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
}
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthTarget);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
SDL_Log("FBO incomplete: 0x%X", status);
}
if (m_msaa > 1) {
glBindFramebuffer(GL_FRAMEBUFFER, m_resolveFBO);
glGenRenderbuffers(1, &m_resolveColor);
glBindRenderbuffer(GL_RENDERBUFFER, m_resolveColor);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_resolveColor);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
SDL_Log("Resolve FBO incomplete: 0x%X", status);
}
}
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
glViewport(0, 0, m_width, m_height);
}
void OpenGLES2Renderer::Clear(float r, float g, float b)
void OpenGLES3Renderer::Clear(float r, float g, float b)
{
SDL_GL_MakeCurrent(DDWindow, m_context);
m_dirty = true;
@ -653,71 +721,22 @@ void OpenGLES2Renderer::Clear(float r, float g, float b)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void OpenGLES2Renderer::Flip()
void OpenGLES3Renderer::Flip()
{
SDL_GL_MakeCurrent(DDWindow, m_context);
if (!m_dirty) {
return;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDisable(GL_DEPTH_TEST);
glFrontFace(GL_CCW);
glDepthMask(GL_FALSE);
glUniform4f(m_colorLoc, 1.0f, 1.0f, 1.0f, 1.0f);
glUniform1f(m_shinLoc, 0.0f);
float ambient[] = {1.0f, 1.0f, 1.0f, 1.0f};
float blank[] = {0.0f, 0.0f, 0.0f, 0.0f};
glUniform4fv(u_lightLocs[0][0], 1, ambient);
glUniform4fv(u_lightLocs[0][1], 1, blank);
glUniform4fv(u_lightLocs[0][2], 1, blank);
glUniform1i(m_lightCountLoc, 1);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_colorTarget);
glUniform1i(m_textureLoc, 0);
glUniform1i(m_useTextureLoc, 1);
D3DRMMATRIX4D projection;
D3DRMMATRIX4D modelViewMatrix = {
{(float) m_width, 0.0f, 0.0f, 0.0f},
{0.0f, (float) -m_height, 0.0f, 0.0f},
{0.0f, 0.0f, 1.0f, 0.0f},
{0.0f, (float) m_height, 0.0f, 1.0f}
};
glUniformMatrix4fv(m_modelViewMatrixLoc, 1, GL_FALSE, &modelViewMatrix[0][0]);
Matrix3x3 identity = {{1.f, 0.f, 0.f}, {0.f, 1.f, 0.f}, {0.f, 0.f, 1.f}};
glUniformMatrix3fv(m_normalMatrixLoc, 1, GL_FALSE, &identity[0][0]);
CreateOrthographicProjection((float) m_width, (float) m_height, projection);
glUniformMatrix4fv(m_projectionMatrixLoc, 1, GL_FALSE, &projection[0][0]);
glDisable(GL_SCISSOR_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindBuffer(GL_ARRAY_BUFFER, m_uiMeshCache.vboPositions);
glEnableVertexAttribArray(m_posLoc);
glVertexAttribPointer(m_posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glBindBuffer(GL_ARRAY_BUFFER, m_uiMeshCache.vboTexcoords);
glEnableVertexAttribArray(m_texLoc);
glVertexAttribPointer(m_texLoc, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_uiMeshCache.ibo);
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m_uiMeshCache.indices.size()), GL_UNSIGNED_SHORT, nullptr);
glDisableVertexAttribArray(m_texLoc);
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, m_width, m_height, 0, 0, m_width, m_height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
SDL_GL_SwapWindow(DDWindow);
glFrontFace(GL_CW);
m_dirty = false;
}
void OpenGLES2Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color)
void OpenGLES3Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color)
{
SDL_GL_MakeCurrent(DDWindow, m_context);
m_dirty = true;
@ -739,7 +758,7 @@ void OpenGLES2Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, c
SDL_Rect expandedDstRect;
if (textureId != NO_TEXTURE_ID) {
const GLES2TextureCacheEntry& texture = m_textures[textureId];
const GLES3TextureCacheEntry& texture = m_textures[textureId];
float scaleX = static_cast<float>(dstRect.w) / srcRect.w;
float scaleY = static_cast<float>(dstRect.h) / srcRect.h;
expandedDstRect = {
@ -790,26 +809,27 @@ void OpenGLES2Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, c
static_cast<int>(std::round(dstRect.h * m_viewportTransform.scale))
);
glBindBuffer(GL_ARRAY_BUFFER, m_uiMeshCache.vboPositions);
glEnableVertexAttribArray(m_posLoc);
glVertexAttribPointer(m_posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glBindBuffer(GL_ARRAY_BUFFER, m_uiMeshCache.vboTexcoords);
glEnableVertexAttribArray(m_texLoc);
glVertexAttribPointer(m_texLoc, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_uiMeshCache.ibo);
glBindVertexArray(m_uiMeshCache.vao);
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m_uiMeshCache.indices.size()), GL_UNSIGNED_SHORT, nullptr);
glBindVertexArray(0);
glDisableVertexAttribArray(m_texLoc);
glDisable(GL_SCISSOR_TEST);
}
void OpenGLES2Renderer::Download(SDL_Surface* target)
void OpenGLES3Renderer::Download(SDL_Surface* target)
{
glFinish();
if (m_msaa > 1) {
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolveFBO);
glBlitFramebuffer(0, 0, m_width, m_height, 0, 0, m_width, m_height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_FRAMEBUFFER, m_resolveFBO);
}
else {
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
}
glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, m_renderedImage->pixels);
SDL_Rect srcRect = {
@ -839,7 +859,7 @@ void OpenGLES2Renderer::Download(SDL_Surface* target)
SDL_DestroySurface(bufferClone);
}
void OpenGLES2Renderer::SetDither(bool dither)
void OpenGLES3Renderer::SetDither(bool dither)
{
if (dither) {
glEnable(GL_DITHER);

View File

@ -132,7 +132,11 @@ HRESULT Direct3DRMImpl::CreateDeviceFromSurface(
DDSDesc.dwSize = sizeof(DDSURFACEDESC);
surface->GetSurfaceDesc(&DDSDesc);
DDRenderer = CreateDirect3DRMRenderer(DDSDesc, guid);
IDirect3DMiniwin* miniwind3d = nullptr;
dd->QueryInterface(IID_IDirect3DMiniwin, (void**) &miniwind3d);
SDL_assert(miniwind3d);
DDRenderer = CreateDirect3DRMRenderer(miniwind3d, DDSDesc, guid);
if (!DDRenderer) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Device GUID not recognized");
return E_NOINTERFACE;

View File

@ -2,8 +2,8 @@
#ifdef USE_OPENGL1
#include "d3drmrenderer_opengl1.h"
#endif
#ifdef USE_OPENGLES2
#include "d3drmrenderer_opengles2.h"
#ifdef USE_OPENGLES3
#include "d3drmrenderer_opengles3.h"
#endif
#ifdef USE_CITRO3D
#include "d3drmrenderer_citro3d.h"
@ -18,7 +18,11 @@
#include "d3drmrenderer_software.h"
#endif
Direct3DRMRenderer* CreateDirect3DRMRenderer(const DDSURFACEDESC& DDSDesc, const GUID* guid)
Direct3DRMRenderer* CreateDirect3DRMRenderer(
const IDirect3DMiniwin* d3d,
const DDSURFACEDESC& DDSDesc,
const GUID* guid
)
{
#ifdef USE_SDL_GPU
if (SDL_memcmp(guid, &SDL3_GPU_GUID, sizeof(GUID)) == 0) {
@ -30,9 +34,9 @@ Direct3DRMRenderer* CreateDirect3DRMRenderer(const DDSURFACEDESC& DDSDesc, const
return new Direct3DRMSoftwareRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight);
}
#endif
#ifdef USE_OPENGLES2
if (SDL_memcmp(guid, &OpenGLES2_GUID, sizeof(GUID)) == 0) {
return OpenGLES2Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight);
#ifdef USE_OPENGLES3
if (SDL_memcmp(guid, &OpenGLES3_GUID, sizeof(GUID)) == 0) {
return OpenGLES3Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight, d3d->GetMSAASamples());
}
#endif
#ifdef USE_OPENGL1
@ -53,13 +57,13 @@ Direct3DRMRenderer* CreateDirect3DRMRenderer(const DDSURFACEDESC& DDSDesc, const
return nullptr;
}
void Direct3DRMRenderer_EnumDevices(LPD3DENUMDEVICESCALLBACK cb, void* ctx)
void Direct3DRMRenderer_EnumDevices(const IDirect3DMiniwin* d3d, LPD3DENUMDEVICESCALLBACK cb, void* ctx)
{
#ifdef USE_SDL_GPU
Direct3DRMSDL3GPU_EnumDevice(cb, ctx);
#endif
#ifdef USE_OPENGLES2
OpenGLES2Renderer_EnumDevice(cb, ctx);
#ifdef USE_OPENGLES3
OpenGLES3Renderer_EnumDevice(d3d, cb, ctx);
#endif
#ifdef USE_OPENGL1
OpenGL1Renderer_EnumDevice(cb, ctx);

View File

@ -29,6 +29,11 @@ HRESULT DirectDrawImpl::QueryInterface(const GUID& riid, void** ppvObject)
*ppvObject = static_cast<IDirect3D2*>(this);
return S_OK;
}
if (SDL_memcmp(&riid, &IID_IDirect3DMiniwin, sizeof(GUID)) == 0) {
this->IUnknown::AddRef();
*ppvObject = static_cast<IDirect3DMiniwin*>(this);
return S_OK;
}
MINIWIN_NOT_IMPLEMENTED();
return E_NOINTERFACE;
}
@ -220,7 +225,7 @@ void EnumDevice(
HRESULT DirectDrawImpl::EnumDevices(LPD3DENUMDEVICESCALLBACK cb, void* ctx)
{
Direct3DRMRenderer_EnumDevices(cb, ctx);
Direct3DRMRenderer_EnumDevices(this, cb, ctx);
return S_OK;
}
@ -317,7 +322,7 @@ HRESULT DirectDrawImpl::CreateDevice(
DDSDesc.dwSize = sizeof(DDSURFACEDESC);
pBackBuffer->GetSurfaceDesc(&DDSDesc);
DDRenderer = CreateDirect3DRMRenderer(DDSDesc, &guid);
DDRenderer = CreateDirect3DRMRenderer(this, DDSDesc, &guid);
if (!DDRenderer) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Device GUID not recognized");
return E_NOINTERFACE;
@ -326,6 +331,17 @@ HRESULT DirectDrawImpl::CreateDevice(
return DD_OK;
}
HRESULT DirectDrawImpl::RequestMSAA(DWORD msaaSamples)
{
m_msaaSamples = msaaSamples;
return DD_OK;
}
DWORD DirectDrawImpl::GetMSAASamples() const
{
return m_msaaSamples;
}
HRESULT DirectDrawEnumerate(LPDDENUMCALLBACKA cb, void* context)
{
const char* driverName = SDL_GetCurrentVideoDriver();

View File

@ -3,6 +3,7 @@
#include "d3drmmesh_impl.h"
#include "mathutils.h"
#include "miniwin/d3drm.h"
#include "miniwin/miniwind3d.h"
#include "miniwin/miniwindevice.h"
#include "structs.h"
@ -61,5 +62,9 @@ protected:
ViewportTransform m_viewportTransform;
};
Direct3DRMRenderer* CreateDirect3DRMRenderer(const DDSURFACEDESC& DDSDesc, const GUID* guid);
void Direct3DRMRenderer_EnumDevices(LPD3DENUMDEVICESCALLBACK cb, void* ctx);
Direct3DRMRenderer* CreateDirect3DRMRenderer(
const IDirect3DMiniwin* d3d,
const DDSURFACEDESC& DDSDesc,
const GUID* guid
);
void Direct3DRMRenderer_EnumDevices(const IDirect3DMiniwin* d3d, LPD3DENUMDEVICESCALLBACK cb, void* ctx);

View File

@ -4,13 +4,13 @@
#include "d3drmtexture_impl.h"
#include "ddraw_impl.h"
#include <GLES2/gl2.h>
#include <GLES3/gl3.h>
#include <SDL3/SDL.h>
#include <vector>
DEFINE_GUID(OpenGLES2_GUID, 0x682656F3, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04);
DEFINE_GUID(OpenGLES3_GUID, 0x682656F3, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04);
struct GLES2TextureCacheEntry {
struct GLES3TextureCacheEntry {
IDirect3DRMTexture* texture;
Uint32 version;
GLuint glTextureId;
@ -18,7 +18,7 @@ struct GLES2TextureCacheEntry {
uint16_t height;
};
struct GLES2MeshCacheEntry {
struct GLES3MeshCacheEntry {
const MeshGroup* meshGroup;
int version;
bool flat;
@ -28,13 +28,14 @@ struct GLES2MeshCacheEntry {
GLuint vboNormals;
GLuint vboTexcoords;
GLuint ibo;
GLuint vao;
};
class OpenGLES2Renderer : public Direct3DRMRenderer {
class OpenGLES3Renderer : public Direct3DRMRenderer {
public:
static Direct3DRMRenderer* Create(DWORD width, DWORD height);
OpenGLES2Renderer(DWORD width, DWORD height, SDL_GLContext context, GLuint shaderProgram);
~OpenGLES2Renderer() override;
static Direct3DRMRenderer* Create(DWORD width, DWORD height, DWORD msaaSamples);
OpenGLES3Renderer(DWORD width, DWORD height, DWORD msaaSamples, SDL_GLContext context, GLuint shaderProgram);
~OpenGLES3Renderer() override;
void PushLights(const SceneLight* lightsArray, size_t count) override;
void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override;
@ -62,18 +63,22 @@ public:
private:
void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture);
void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh);
GLES3MeshCacheEntry GLES3UploadMesh(const MeshGroup& meshGroup, bool forceUV = false);
MeshGroup m_uiMesh;
GLES2MeshCacheEntry m_uiMeshCache;
std::vector<GLES2TextureCacheEntry> m_textures;
std::vector<GLES2MeshCacheEntry> m_meshs;
GLES3MeshCacheEntry m_uiMeshCache;
std::vector<GLES3TextureCacheEntry> m_textures;
std::vector<GLES3MeshCacheEntry> m_meshs;
D3DRMMATRIX4D m_projection;
SDL_Surface* m_renderedImage = nullptr;
bool m_dirty = false;
std::vector<SceneLight> m_lights;
SDL_GLContext m_context;
uint32_t m_msaa;
GLuint m_fbo;
GLuint m_resolveFBO;
GLuint m_colorTarget;
GLuint m_resolveColor = 0;
GLuint m_depthTarget;
GLuint m_shaderProgram;
GLuint m_dummyTexture;
@ -92,35 +97,25 @@ private:
ViewportTransform m_viewportTransform;
};
inline static void OpenGLES2Renderer_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx)
inline static void OpenGLES3Renderer_EnumDevice(const IDirect3DMiniwin* d3d, LPD3DENUMDEVICESCALLBACK cb, void* ctx)
{
Direct3DRMRenderer* device = OpenGLES2Renderer::Create(640, 480);
Direct3DRMRenderer* device = OpenGLES3Renderer::Create(640, 480, d3d->GetMSAASamples());
if (!device) {
return;
}
delete device;
D3DDEVICEDESC halDesc = {};
halDesc.dcmColorModel = D3DCOLOR_RGB;
halDesc.dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH;
halDesc.dwDeviceZBufferBitDepth = DDBD_16;
halDesc.dwDeviceZBufferBitDepth = DDBD_24;
halDesc.dwDeviceRenderBitDepth = DDBD_32;
halDesc.dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE;
halDesc.dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND;
halDesc.dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR;
const char* extensions = (const char*) glGetString(GL_EXTENSIONS);
if (extensions) {
if (strstr(extensions, "GL_OES_depth24")) {
halDesc.dwDeviceZBufferBitDepth |= DDBD_24;
}
if (strstr(extensions, "GL_OES_depth32")) {
halDesc.dwDeviceZBufferBitDepth |= DDBD_32;
}
}
delete device;
D3DDEVICEDESC helDesc = {};
EnumDevice(cb, ctx, "OpenGL ES 2.0 HAL", &halDesc, &helDesc, OpenGLES2_GUID);
EnumDevice(cb, ctx, "OpenGL ES 3.0 HAL", &halDesc, &helDesc, OpenGLES3_GUID);
}

View File

@ -4,6 +4,7 @@
#include "framebuffer_impl.h"
#include "miniwin/d3d.h"
#include "miniwin/ddraw.h"
#include "miniwin/miniwind3d.h"
#include <SDL3/SDL.h>
@ -15,7 +16,7 @@ inline static SDL_Rect ConvertRect(const RECT* r)
return {r->left, r->top, r->right - r->left, r->bottom - r->top};
}
struct DirectDrawImpl : public IDirectDraw2, public IDirect3D2 {
struct DirectDrawImpl : public IDirectDraw2, public IDirect3D2, public IDirect3DMiniwin {
// IUnknown interface
HRESULT QueryInterface(const GUID& riid, void** ppvObject) override;
// IDirectDraw interface
@ -45,11 +46,15 @@ struct DirectDrawImpl : public IDirectDraw2, public IDirect3D2 {
HRESULT CreateDevice(const GUID& guid, IDirectDrawSurface* pBackBuffer, IDirect3DDevice2** ppDirect3DDevice)
override;
HRESULT EnumDevices(LPD3DENUMDEVICESCALLBACK cb, void* ctx) override;
// IDirect3DMiniwin interface
HRESULT RequestMSAA(DWORD msaaSamples) override;
DWORD GetMSAASamples() const override;
private:
FrameBufferImpl* m_frameBuffer;
int m_virtualWidth = 0;
int m_virtualHeight = 0;
DWORD m_msaaSamples = 0;
};
HRESULT DirectDrawEnumerate(LPDDENUMCALLBACKA cb, void* context);