mirror of
https://github.com/isledecomp/isle-portable.git
synced 2025-09-22 03:22:35 -04:00
Upgrade OpenGL ES renderer to 3.0, add option for MSAA (#636)
This commit is contained in:
parent
8f6bfe078b
commit
a5a3c4ec83
@ -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()
|
||||
|
@ -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) {
|
||||
|
@ -114,6 +114,7 @@ private:
|
||||
MxFloat m_exclusiveFrameRate;
|
||||
MxFloat m_frameRate;
|
||||
MxBool m_exclusiveFullScreen;
|
||||
MxU32 m_msaaSamples;
|
||||
};
|
||||
|
||||
extern IsleApp* g_isle;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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()
|
||||
|
||||
|
8
miniwin/include/miniwin/miniwind3d.h
Normal file
8
miniwin/include/miniwin/miniwind3d.h
Normal 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;
|
||||
};
|
@ -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) {
|
||||
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);
|
||||
SDL_Log("CompileShader (%s)", SDL_GetError());
|
||||
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();
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
|
||||
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);
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user