mirror of
https://github.com/isledecomp/isle-portable.git
synced 2026-01-11 10:31:16 +00:00
Fix the OpenGL backends on non-glx Linux platforms (and remove GLEW dependency) (#446)
* Work around issues with depth-buffer size on EGL-based platforms The OpenGL 1.1 and OpenGL ES 2.0 backends can break on EGL-based platforms, such as Wayland, or X11 with SDL_VIDEO_FORCE_EGL=1. One of the reasons for this (the other being glew on the GL1.1 backend) is that SDL/egl get very confused by the way we set OpenGL attributes, particularly SDL_GL_DEPTH_SIZE, resulting in SDL_GL_CreateContext() failing with EGL_BAD_MATCH. The exact cause of this is unknown, but it seems to be a combination of: - SDL_GL_SetAttribute() is supposed to be called _before_ the window is created, and we're calling it afterward. - Creating several test windows during the enumeration process, mixing and matching between OpenGL and OpenGL ES profiles. The "most correct" solution is probably to delay creating the game window until the backend creation process, rather than before the enumeration occurs. But that's a real refactor, which could cause other issues. Instead, set the 24-bit bit depth (which we've hardcoded anyway) before creating the window, and use SDL_GL_ResetAttributes() when creating backends. This seems to work here in all of the cases I was able to try (modulo the GLEW dependency, which is removed in the next patch). * miniwin: Remove GLEW dependency for OpenGL 1.1 GLEW normally backs directly onto glXGetProcAddress on Linux, which is broken on non-GLX setups, such as Wayland (but also X11 with EGL, and presumably KMSDRM). Replace it with manual calls to SDL_GL_GetProcAddress() for the VBO path. Note, however, that SDL_opengl.h includes "windows.h", so conflicts with the miniwin implementation, which breaks builds on windows. In order to work around this, we do what the Direct3D9 implementation does and push all of the OpenGL calls to a separate file, actual.cpp. Going forward, it may make sense to load _all_ OpenGL entry points via SDL, which would allow us to avoid linking directly with libGL/libOpenGL, and therefore eliminate the separate build dependency altogether, as well as allowing more runtime configurability as to the OpenGL library to load. (But that's definitely a bit uglier, and also useful very rarely.)
This commit is contained in:
parent
020969c483
commit
e87184b502
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -66,7 +66,7 @@ jobs:
|
|||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y \
|
sudo apt-get install -y \
|
||||||
libx11-dev libxext-dev libxrandr-dev libxrender-dev libxfixes-dev libxi-dev libxinerama-dev \
|
libx11-dev libxext-dev libxrandr-dev libxrender-dev libxfixes-dev libxi-dev libxinerama-dev \
|
||||||
libxcursor-dev libwayland-dev libxkbcommon-dev wayland-protocols libgl1-mesa-dev libglew-dev qt6-base-dev \
|
libxcursor-dev libwayland-dev libxkbcommon-dev wayland-protocols libgl1-mesa-dev qt6-base-dev \
|
||||||
libasound2-dev
|
libasound2-dev
|
||||||
|
|
||||||
- name: Install macOS dependencies (brew)
|
- name: Install macOS dependencies (brew)
|
||||||
|
|||||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@ -45,7 +45,7 @@ jobs:
|
|||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y \
|
sudo apt-get install -y \
|
||||||
libx11-dev libxext-dev libxrandr-dev libxrender-dev libxfixes-dev libxi-dev libxinerama-dev \
|
libx11-dev libxext-dev libxrandr-dev libxrender-dev libxfixes-dev libxi-dev libxinerama-dev \
|
||||||
libxcursor-dev libwayland-dev libxkbcommon-dev wayland-protocols libgl1-mesa-dev libglew-dev qt6-base-dev \
|
libxcursor-dev libwayland-dev libxkbcommon-dev wayland-protocols libgl1-mesa-dev qt6-base-dev \
|
||||||
libasound2-dev
|
libasound2-dev
|
||||||
|
|
||||||
- name: Install macOS dependencies (brew)
|
- name: Install macOS dependencies (brew)
|
||||||
|
|||||||
@ -657,6 +657,7 @@ MxResult IsleApp::SetupWindow()
|
|||||||
#ifdef MINIWIN
|
#ifdef MINIWIN
|
||||||
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true);
|
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true);
|
||||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
window = SDL_CreateWindowWithProperties(props);
|
window = SDL_CreateWindowWithProperties(props);
|
||||||
|
|||||||
@ -32,14 +32,16 @@ target_compile_definitions(miniwin PRIVATE
|
|||||||
)
|
)
|
||||||
|
|
||||||
find_package(OpenGL)
|
find_package(OpenGL)
|
||||||
find_package(GLEW)
|
if(OpenGL_FOUND)
|
||||||
if(OpenGL_FOUND AND GLEW_FOUND)
|
message(STATUS "Found OpenGL: enabling OpenGL 1.x renderer")
|
||||||
message(STATUS "Found OpenGL and GLEW: enabling OpenGL 1.x renderer")
|
target_sources(miniwin PRIVATE
|
||||||
target_sources(miniwin PRIVATE src/d3drm/backends/opengl1/renderer.cpp)
|
src/d3drm/backends/opengl1/actual.cpp
|
||||||
|
src/d3drm/backends/opengl1/renderer.cpp
|
||||||
|
)
|
||||||
target_compile_definitions(miniwin PRIVATE USE_OPENGL1)
|
target_compile_definitions(miniwin PRIVATE USE_OPENGL1)
|
||||||
target_link_libraries(miniwin PRIVATE OpenGL::GL GLEW::GLEW)
|
target_link_libraries(miniwin PRIVATE OpenGL::GL)
|
||||||
else()
|
else()
|
||||||
message(STATUS "🧩 OpenGL 1.x support not enabled — needs OpenGL and GLEW")
|
message(STATUS "🧩 OpenGL 1.x support not enabled — needs OpenGL")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_library(OPENGL_ES2_LIBRARY NAMES GLESv2)
|
find_library(OPENGL_ES2_LIBRARY NAMES GLESv2)
|
||||||
|
|||||||
354
miniwin/src/d3drm/backends/opengl1/actual.cpp
Normal file
354
miniwin/src/d3drm/backends/opengl1/actual.cpp
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
// This file cannot include any minwin headers.
|
||||||
|
|
||||||
|
#include "actual.h"
|
||||||
|
|
||||||
|
#include "structs.h"
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#include <SDL3/SDL_opengl.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// GL extension API functions.
|
||||||
|
bool g_useVBOs;
|
||||||
|
PFNGLGENBUFFERSPROC mwglGenBuffers;
|
||||||
|
PFNGLBINDBUFFERPROC mwglBindBuffer;
|
||||||
|
PFNGLBUFFERDATAPROC mwglBufferData;
|
||||||
|
PFNGLDELETEBUFFERSPROC mwglDeleteBuffers;
|
||||||
|
|
||||||
|
void GL11_InitState()
|
||||||
|
{
|
||||||
|
glEnable(GL_CULL_FACE);
|
||||||
|
glCullFace(GL_BACK);
|
||||||
|
glFrontFace(GL_CW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GL11_LoadExtensions()
|
||||||
|
{
|
||||||
|
g_useVBOs = SDL_GL_ExtensionSupported("GL_ARB_vertex_buffer_object");
|
||||||
|
|
||||||
|
if (g_useVBOs) {
|
||||||
|
// Load the required GL function pointers.
|
||||||
|
mwglGenBuffers = (PFNGLGENBUFFERSPROC) SDL_GL_GetProcAddress("glGenBuffersARB");
|
||||||
|
mwglBindBuffer = (PFNGLBINDBUFFERPROC) SDL_GL_GetProcAddress("glBindBufferARB");
|
||||||
|
mwglBufferData = (PFNGLBUFFERDATAPROC) SDL_GL_GetProcAddress("glBufferDataARB");
|
||||||
|
mwglDeleteBuffers = (PFNGLDELETEBUFFERSPROC) SDL_GL_GetProcAddress("glDeleteBuffersARB");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GL11_DestroyTexture(GLuint texId)
|
||||||
|
{
|
||||||
|
glDeleteTextures(1, &texId);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint GL11_UploadTextureData(void* pixels, int width, int height)
|
||||||
|
{
|
||||||
|
GLuint texId;
|
||||||
|
glGenTextures(1, &texId);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texId);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||||
|
return texId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GL11_UploadMesh(GLMeshCacheEntry& cache, bool hasTexture)
|
||||||
|
{
|
||||||
|
if (g_useVBOs) {
|
||||||
|
mwglGenBuffers(1, &cache.vboPositions);
|
||||||
|
mwglBindBuffer(GL_ARRAY_BUFFER_ARB, cache.vboPositions);
|
||||||
|
mwglBufferData(
|
||||||
|
GL_ARRAY_BUFFER_ARB,
|
||||||
|
cache.positions.size() * sizeof(GL11_BridgeVector),
|
||||||
|
cache.positions.data(),
|
||||||
|
GL_STATIC_DRAW_ARB
|
||||||
|
);
|
||||||
|
|
||||||
|
mwglGenBuffers(1, &cache.vboNormals);
|
||||||
|
mwglBindBuffer(GL_ARRAY_BUFFER_ARB, cache.vboNormals);
|
||||||
|
mwglBufferData(
|
||||||
|
GL_ARRAY_BUFFER_ARB,
|
||||||
|
cache.normals.size() * sizeof(GL11_BridgeVector),
|
||||||
|
cache.normals.data(),
|
||||||
|
GL_STATIC_DRAW_ARB
|
||||||
|
);
|
||||||
|
|
||||||
|
if (hasTexture) {
|
||||||
|
mwglGenBuffers(1, &cache.vboTexcoords);
|
||||||
|
mwglBindBuffer(GL_ARRAY_BUFFER_ARB, cache.vboTexcoords);
|
||||||
|
mwglBufferData(
|
||||||
|
GL_ARRAY_BUFFER_ARB,
|
||||||
|
cache.texcoords.size() * sizeof(GL11_BridgeTexCoord),
|
||||||
|
cache.texcoords.data(),
|
||||||
|
GL_STATIC_DRAW_ARB
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
mwglGenBuffers(1, &cache.ibo);
|
||||||
|
mwglBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, cache.ibo);
|
||||||
|
mwglBufferData(
|
||||||
|
GL_ELEMENT_ARRAY_BUFFER_ARB,
|
||||||
|
cache.indices.size() * sizeof(cache.indices[0]),
|
||||||
|
cache.indices.data(),
|
||||||
|
GL_STATIC_DRAW_ARB
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GL11_DestroyMesh(GLMeshCacheEntry& cache)
|
||||||
|
{
|
||||||
|
if (g_useVBOs) {
|
||||||
|
mwglDeleteBuffers(1, &cache.vboPositions);
|
||||||
|
mwglDeleteBuffers(1, &cache.vboNormals);
|
||||||
|
mwglDeleteBuffers(1, &cache.vboTexcoords);
|
||||||
|
mwglDeleteBuffers(1, &cache.ibo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GL11_BeginFrame(const Matrix4x4* projection)
|
||||||
|
{
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
|
glEnable(GL_LIGHTING);
|
||||||
|
glEnable(GL_COLOR_MATERIAL);
|
||||||
|
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
|
||||||
|
|
||||||
|
// Disable all lights and reset global ambient
|
||||||
|
for (int i = 0; i < 8; ++i) {
|
||||||
|
glDisable(GL_LIGHT0 + i);
|
||||||
|
}
|
||||||
|
const GLfloat zeroAmbient[4] = {0.f, 0.f, 0.f, 1.f};
|
||||||
|
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, zeroAmbient);
|
||||||
|
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
|
||||||
|
|
||||||
|
// Projection and view
|
||||||
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
glLoadMatrixf((const GLfloat*) projection);
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glLoadIdentity();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GL11_UploadLight(int lightIdx, GL11_BridgeSceneLight* l)
|
||||||
|
{
|
||||||
|
// Setup light
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glPushMatrix();
|
||||||
|
glLoadIdentity();
|
||||||
|
GLenum lightId = GL_LIGHT0 + lightIdx++;
|
||||||
|
const FColor& c = l->color;
|
||||||
|
GLfloat col[4] = {c.r, c.g, c.b, c.a};
|
||||||
|
const GLfloat zeroAmbient[4] = {0.f, 0.f, 0.f, 1.f};
|
||||||
|
|
||||||
|
if (l->positional == 0.f && l->directional == 0.f) {
|
||||||
|
// Ambient light only
|
||||||
|
glLightfv(lightId, GL_AMBIENT, col);
|
||||||
|
const GLfloat black[4] = {0.f, 0.f, 0.f, 1.f};
|
||||||
|
glLightfv(lightId, GL_DIFFUSE, black);
|
||||||
|
glLightfv(lightId, GL_SPECULAR, black);
|
||||||
|
const GLfloat dummyPos[4] = {0.f, 0.f, 1.f, 0.f};
|
||||||
|
glLightfv(lightId, GL_POSITION, dummyPos);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
glLightfv(lightId, GL_AMBIENT, zeroAmbient);
|
||||||
|
glLightfv(lightId, GL_DIFFUSE, col);
|
||||||
|
if (l->directional == 1.0f) {
|
||||||
|
glLightfv(lightId, GL_SPECULAR, col);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const GLfloat black[4] = {0.f, 0.f, 0.f, 1.f};
|
||||||
|
glLightfv(lightId, GL_SPECULAR, black);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLfloat pos[4];
|
||||||
|
if (l->directional == 1.f) {
|
||||||
|
pos[0] = -l->direction.x;
|
||||||
|
pos[1] = -l->direction.y;
|
||||||
|
pos[2] = -l->direction.z;
|
||||||
|
pos[3] = 0.f;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pos[0] = l->position.x;
|
||||||
|
pos[1] = l->position.y;
|
||||||
|
pos[2] = l->position.z;
|
||||||
|
pos[3] = 1.f;
|
||||||
|
}
|
||||||
|
glLightfv(lightId, GL_POSITION, pos);
|
||||||
|
}
|
||||||
|
glEnable(lightId);
|
||||||
|
|
||||||
|
glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GL11_EnableTransparency()
|
||||||
|
{
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glDepthMask(GL_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NO_TEXTURE_ID 0xffffffff
|
||||||
|
|
||||||
|
void GL11_SubmitDraw(
|
||||||
|
GLMeshCacheEntry& mesh,
|
||||||
|
const Matrix4x4& modelViewMatrix,
|
||||||
|
const Appearance& appearance,
|
||||||
|
GLuint texId
|
||||||
|
)
|
||||||
|
{
|
||||||
|
glLoadMatrixf(&modelViewMatrix[0][0]);
|
||||||
|
glEnable(GL_NORMALIZE);
|
||||||
|
|
||||||
|
glColor4ub(appearance.color.r, appearance.color.g, appearance.color.b, appearance.color.a);
|
||||||
|
|
||||||
|
if (appearance.shininess != 0.0f) {
|
||||||
|
GLfloat whiteSpec[] = {1.f, 1.f, 1.f, 1.f};
|
||||||
|
glMaterialfv(GL_FRONT, GL_SPECULAR, whiteSpec);
|
||||||
|
glMaterialf(GL_FRONT, GL_SHININESS, appearance.shininess);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
GLfloat noSpec[] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||||
|
glMaterialfv(GL_FRONT, GL_SPECULAR, noSpec);
|
||||||
|
glMaterialf(GL_FRONT, GL_SHININESS, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mesh.flat) {
|
||||||
|
glShadeModel(GL_FLAT);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
glShadeModel(GL_SMOOTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind texture if present
|
||||||
|
if (appearance.textureId != NO_TEXTURE_ID) {
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texId);
|
||||||
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glEnableClientState(GL_NORMAL_ARRAY);
|
||||||
|
|
||||||
|
if (g_useVBOs) {
|
||||||
|
mwglBindBuffer(GL_ARRAY_BUFFER_ARB, mesh.vboPositions);
|
||||||
|
glVertexPointer(3, GL_FLOAT, 0, nullptr);
|
||||||
|
|
||||||
|
mwglBindBuffer(GL_ARRAY_BUFFER_ARB, mesh.vboNormals);
|
||||||
|
glNormalPointer(GL_FLOAT, 0, nullptr);
|
||||||
|
|
||||||
|
if (appearance.textureId != NO_TEXTURE_ID) {
|
||||||
|
mwglBindBuffer(GL_ARRAY_BUFFER_ARB, mesh.vboTexcoords);
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, 0, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
mwglBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, mesh.ibo);
|
||||||
|
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(mesh.indices.size()), GL_UNSIGNED_SHORT, nullptr);
|
||||||
|
|
||||||
|
mwglBindBuffer(GL_ARRAY_BUFFER_ARB, 0);
|
||||||
|
mwglBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
glVertexPointer(3, GL_FLOAT, 0, mesh.positions.data());
|
||||||
|
glNormalPointer(GL_FLOAT, 0, mesh.normals.data());
|
||||||
|
if (appearance.textureId != NO_TEXTURE_ID) {
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, 0, mesh.texcoords.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(mesh.indices.size()), GL_UNSIGNED_SHORT, mesh.indices.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GL11_Resize(int width, int height)
|
||||||
|
{
|
||||||
|
glViewport(0, 0, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GL11_Clear(float r, float g, float b)
|
||||||
|
{
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
|
glClearColor(r, g, b, 1.0f);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GL11_Draw2DImage(
|
||||||
|
GLuint texId,
|
||||||
|
const SDL_Rect& srcRect,
|
||||||
|
const SDL_Rect& dstRect,
|
||||||
|
float left,
|
||||||
|
float right,
|
||||||
|
float bottom,
|
||||||
|
float top
|
||||||
|
)
|
||||||
|
{
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glDepthMask(GL_FALSE);
|
||||||
|
|
||||||
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
glPushMatrix();
|
||||||
|
glLoadIdentity();
|
||||||
|
|
||||||
|
glOrtho(left, right, bottom, top, -1, 1);
|
||||||
|
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glPushMatrix();
|
||||||
|
glLoadIdentity();
|
||||||
|
|
||||||
|
glDisable(GL_LIGHTING);
|
||||||
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texId);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
|
||||||
|
GLint boundTexture = 0;
|
||||||
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTexture);
|
||||||
|
|
||||||
|
GLfloat texW, texH;
|
||||||
|
glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &texW);
|
||||||
|
glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &texH);
|
||||||
|
|
||||||
|
float u1 = srcRect.x / texW;
|
||||||
|
float v1 = srcRect.y / texH;
|
||||||
|
float u2 = (srcRect.x + srcRect.w) / texW;
|
||||||
|
float v2 = (srcRect.y + srcRect.h) / texH;
|
||||||
|
|
||||||
|
float x1 = (float) dstRect.x;
|
||||||
|
float y1 = (float) dstRect.y;
|
||||||
|
float x2 = x1 + dstRect.w;
|
||||||
|
float y2 = y1 + dstRect.h;
|
||||||
|
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
glTexCoord2f(u1, v1);
|
||||||
|
glVertex2f(x1, y1);
|
||||||
|
glTexCoord2f(u2, v1);
|
||||||
|
glVertex2f(x2, y1);
|
||||||
|
glTexCoord2f(u2, v2);
|
||||||
|
glVertex2f(x2, y2);
|
||||||
|
glTexCoord2f(u1, v2);
|
||||||
|
glVertex2f(x1, y2);
|
||||||
|
glEnd();
|
||||||
|
|
||||||
|
// Restore state
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glPopMatrix();
|
||||||
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GL11_Download(SDL_Surface* target)
|
||||||
|
{
|
||||||
|
glFinish();
|
||||||
|
glReadPixels(0, 0, target->w, target->h, GL_RGBA, GL_UNSIGNED_BYTE, target->pixels);
|
||||||
|
}
|
||||||
88
miniwin/src/d3drm/backends/opengl1/actual.h
Normal file
88
miniwin/src/d3drm/backends/opengl1/actual.h
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "structs.h"
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// We don't want to transitively include windows.h, but we need GLuint
|
||||||
|
typedef unsigned int GLuint;
|
||||||
|
struct IDirect3DRMTexture;
|
||||||
|
struct MeshGroup;
|
||||||
|
|
||||||
|
typedef float Matrix4x4[4][4];
|
||||||
|
|
||||||
|
struct GL11_BridgeVector {
|
||||||
|
float x, y, z;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GL11_BridgeTexCoord {
|
||||||
|
float u, v;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GL11_BridgeSceneLight {
|
||||||
|
FColor color;
|
||||||
|
GL11_BridgeVector position;
|
||||||
|
float positional;
|
||||||
|
GL11_BridgeVector direction;
|
||||||
|
float directional;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GL11_BridgeSceneVertex {
|
||||||
|
GL11_BridgeVector position;
|
||||||
|
GL11_BridgeVector normal;
|
||||||
|
float tu, tv;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GLTextureCacheEntry {
|
||||||
|
IDirect3DRMTexture* texture;
|
||||||
|
Uint32 version;
|
||||||
|
GLuint glTextureId;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GLMeshCacheEntry {
|
||||||
|
const MeshGroup* meshGroup;
|
||||||
|
int version;
|
||||||
|
bool flat;
|
||||||
|
|
||||||
|
// non-VBO cache
|
||||||
|
std::vector<GL11_BridgeVector> positions;
|
||||||
|
std::vector<GL11_BridgeVector> normals;
|
||||||
|
std::vector<GL11_BridgeTexCoord> texcoords;
|
||||||
|
std::vector<uint16_t> indices;
|
||||||
|
|
||||||
|
// VBO cache
|
||||||
|
GLuint vboPositions;
|
||||||
|
GLuint vboNormals;
|
||||||
|
GLuint vboTexcoords;
|
||||||
|
GLuint ibo;
|
||||||
|
};
|
||||||
|
|
||||||
|
void GL11_InitState();
|
||||||
|
void GL11_LoadExtensions();
|
||||||
|
void GL11_DestroyTexture(GLuint texId);
|
||||||
|
GLuint GL11_UploadTextureData(void* pixels, int width, int height);
|
||||||
|
void GL11_UploadMesh(GLMeshCacheEntry& cache, bool hasTexture);
|
||||||
|
void GL11_DestroyMesh(GLMeshCacheEntry& cache);
|
||||||
|
void GL11_BeginFrame(const Matrix4x4* projection);
|
||||||
|
void GL11_UploadLight(int lightIdx, GL11_BridgeSceneLight* l);
|
||||||
|
void GL11_EnableTransparency();
|
||||||
|
void GL11_SubmitDraw(
|
||||||
|
GLMeshCacheEntry& mesh,
|
||||||
|
const Matrix4x4& modelViewMatrix,
|
||||||
|
const Appearance& appearance,
|
||||||
|
GLuint texId
|
||||||
|
);
|
||||||
|
void GL11_Resize(int width, int height);
|
||||||
|
void GL11_Clear(float r, float g, float b);
|
||||||
|
void GL11_Draw2DImage(
|
||||||
|
GLuint texId,
|
||||||
|
const SDL_Rect& srcRect,
|
||||||
|
const SDL_Rect& dstRect,
|
||||||
|
float left,
|
||||||
|
float right,
|
||||||
|
float bottom,
|
||||||
|
float top
|
||||||
|
);
|
||||||
|
void GL11_Download(SDL_Surface* target);
|
||||||
@ -1,5 +1,4 @@
|
|||||||
#include <GL/glew.h>
|
#include "actual.h"
|
||||||
// must come after GLEW
|
|
||||||
#include "d3drmrenderer_opengl1.h"
|
#include "d3drmrenderer_opengl1.h"
|
||||||
#include "ddraw_impl.h"
|
#include "ddraw_impl.h"
|
||||||
#include "ddsurface_impl.h"
|
#include "ddsurface_impl.h"
|
||||||
@ -11,8 +10,20 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
static_assert(sizeof(Matrix4x4) == sizeof(D3DRMMATRIX4D), "Matrix4x4 is wrong size");
|
||||||
|
static_assert(sizeof(GL11_BridgeVector) == sizeof(D3DVECTOR), "GL11_BridgeVector is wrong size");
|
||||||
|
static_assert(sizeof(GL11_BridgeTexCoord) == sizeof(TexCoord), "GL11_BridgeTexCoord is wrong size");
|
||||||
|
static_assert(sizeof(GL11_BridgeSceneLight) == sizeof(SceneLight), "GL11_BridgeSceneLight is wrong size");
|
||||||
|
static_assert(sizeof(GL11_BridgeSceneVertex) == sizeof(D3DRMVERTEX), "GL11_BridgeSceneVertex is wrong size");
|
||||||
|
|
||||||
Direct3DRMRenderer* OpenGL1Renderer::Create(DWORD width, DWORD height)
|
Direct3DRMRenderer* OpenGL1Renderer::Create(DWORD width, DWORD height)
|
||||||
{
|
{
|
||||||
|
// 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
|
||||||
|
// call below when on an EGL-based backend, and crashes with EGL_BAD_MATCH.
|
||||||
|
SDL_GL_ResetAttributes();
|
||||||
|
// 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_COMPATIBILITY);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
|
||||||
@ -28,8 +39,6 @@ Direct3DRMRenderer* OpenGL1Renderer::Create(DWORD width, DWORD height)
|
|||||||
testWindow = true;
|
testWindow = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
|
||||||
|
|
||||||
SDL_GLContext context = SDL_GL_CreateContext(window);
|
SDL_GLContext context = SDL_GL_CreateContext(window);
|
||||||
if (!context) {
|
if (!context) {
|
||||||
SDL_Log("SDL_GL_CreateContext: %s", SDL_GetError());
|
SDL_Log("SDL_GL_CreateContext: %s", SDL_GetError());
|
||||||
@ -47,18 +56,7 @@ Direct3DRMRenderer* OpenGL1Renderer::Create(DWORD width, DWORD height)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLenum err = glewInit();
|
GL11_InitState();
|
||||||
if (err != GLEW_OK) {
|
|
||||||
SDL_Log("glewInit: %s", glewGetErrorString(err));
|
|
||||||
if (testWindow) {
|
|
||||||
SDL_DestroyWindow(window);
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
glEnable(GL_CULL_FACE);
|
|
||||||
glCullFace(GL_BACK);
|
|
||||||
glFrontFace(GL_CW);
|
|
||||||
|
|
||||||
if (testWindow) {
|
if (testWindow) {
|
||||||
SDL_DestroyWindow(window);
|
SDL_DestroyWindow(window);
|
||||||
@ -74,7 +72,7 @@ OpenGL1Renderer::OpenGL1Renderer(DWORD width, DWORD height, SDL_GLContext contex
|
|||||||
m_virtualWidth = width;
|
m_virtualWidth = width;
|
||||||
m_virtualHeight = height;
|
m_virtualHeight = height;
|
||||||
m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32);
|
m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32);
|
||||||
m_useVBOs = GLEW_ARB_vertex_buffer_object;
|
GL11_LoadExtensions();
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGL1Renderer::~OpenGL1Renderer()
|
OpenGL1Renderer::~OpenGL1Renderer()
|
||||||
@ -114,7 +112,7 @@ void OpenGL1Renderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* t
|
|||||||
auto* ctx = static_cast<TextureDestroyContextGL*>(arg);
|
auto* ctx = static_cast<TextureDestroyContextGL*>(arg);
|
||||||
auto& cache = ctx->renderer->m_textures[ctx->textureId];
|
auto& cache = ctx->renderer->m_textures[ctx->textureId];
|
||||||
if (cache.glTextureId != 0) {
|
if (cache.glTextureId != 0) {
|
||||||
glDeleteTextures(1, &cache.glTextureId);
|
GL11_DestroyTexture(cache.glTextureId);
|
||||||
cache.glTextureId = 0;
|
cache.glTextureId = 0;
|
||||||
cache.texture = nullptr;
|
cache.texture = nullptr;
|
||||||
}
|
}
|
||||||
@ -133,15 +131,13 @@ Uint32 OpenGL1Renderer::GetTextureId(IDirect3DRMTexture* iTexture)
|
|||||||
auto& tex = m_textures[i];
|
auto& tex = m_textures[i];
|
||||||
if (tex.texture == texture) {
|
if (tex.texture == texture) {
|
||||||
if (tex.version != texture->m_version) {
|
if (tex.version != texture->m_version) {
|
||||||
glDeleteTextures(1, &tex.glTextureId);
|
GL11_DestroyTexture(tex.glTextureId);
|
||||||
glGenTextures(1, &tex.glTextureId);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, tex.glTextureId);
|
|
||||||
|
|
||||||
SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_RGBA32);
|
SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_RGBA32);
|
||||||
if (!surf) {
|
if (!surf) {
|
||||||
return NO_TEXTURE_ID;
|
return NO_TEXTURE_ID;
|
||||||
}
|
}
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels);
|
tex.glTextureId = GL11_UploadTextureData(surf->pixels, surf->w, surf->h);
|
||||||
SDL_DestroySurface(surf);
|
SDL_DestroySurface(surf);
|
||||||
|
|
||||||
tex.version = texture->m_version;
|
tex.version = texture->m_version;
|
||||||
@ -151,14 +147,12 @@ Uint32 OpenGL1Renderer::GetTextureId(IDirect3DRMTexture* iTexture)
|
|||||||
}
|
}
|
||||||
|
|
||||||
GLuint texId;
|
GLuint texId;
|
||||||
glGenTextures(1, &texId);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texId);
|
|
||||||
|
|
||||||
SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_RGBA32);
|
SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_RGBA32);
|
||||||
if (!surf) {
|
if (!surf) {
|
||||||
return NO_TEXTURE_ID;
|
return NO_TEXTURE_ID;
|
||||||
}
|
}
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels);
|
texId = GL11_UploadTextureData(surf->pixels, surf->w, surf->h);
|
||||||
SDL_DestroySurface(surf);
|
SDL_DestroySurface(surf);
|
||||||
|
|
||||||
for (Uint32 i = 0; i < m_textures.size(); ++i) {
|
for (Uint32 i = 0; i < m_textures.size(); ++i) {
|
||||||
@ -206,52 +200,19 @@ GLMeshCacheEntry GLUploadMesh(const MeshGroup& meshGroup, bool useVBOs)
|
|||||||
if (meshGroup.texture) {
|
if (meshGroup.texture) {
|
||||||
cache.texcoords.resize(vertices.size());
|
cache.texcoords.resize(vertices.size());
|
||||||
std::transform(vertices.begin(), vertices.end(), cache.texcoords.begin(), [](const D3DRMVERTEX& v) {
|
std::transform(vertices.begin(), vertices.end(), cache.texcoords.begin(), [](const D3DRMVERTEX& v) {
|
||||||
return v.texCoord;
|
return GL11_BridgeTexCoord{v.texCoord.u, v.texCoord.v};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
cache.positions.resize(vertices.size());
|
cache.positions.resize(vertices.size());
|
||||||
std::transform(vertices.begin(), vertices.end(), cache.positions.begin(), [](const D3DRMVERTEX& v) {
|
std::transform(vertices.begin(), vertices.end(), cache.positions.begin(), [](const D3DRMVERTEX& v) {
|
||||||
return v.position;
|
return GL11_BridgeVector{v.position.x, v.position.y, v.position.z};
|
||||||
});
|
});
|
||||||
cache.normals.resize(vertices.size());
|
cache.normals.resize(vertices.size());
|
||||||
std::transform(vertices.begin(), vertices.end(), cache.normals.begin(), [](const D3DRMVERTEX& v) {
|
std::transform(vertices.begin(), vertices.end(), cache.normals.begin(), [](const D3DRMVERTEX& v) {
|
||||||
return v.normal;
|
return GL11_BridgeVector{v.normal.x, v.normal.y, v.normal.z};
|
||||||
});
|
});
|
||||||
|
|
||||||
if (useVBOs) {
|
GL11_UploadMesh(cache, meshGroup.texture != nullptr);
|
||||||
glGenBuffers(1, &cache.vboPositions);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, cache.vboPositions);
|
|
||||||
glBufferData(
|
|
||||||
GL_ARRAY_BUFFER,
|
|
||||||
cache.positions.size() * sizeof(D3DVECTOR),
|
|
||||||
cache.positions.data(),
|
|
||||||
GL_STATIC_DRAW
|
|
||||||
);
|
|
||||||
|
|
||||||
glGenBuffers(1, &cache.vboNormals);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, cache.vboNormals);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, cache.normals.size() * sizeof(D3DVECTOR), cache.normals.data(), GL_STATIC_DRAW);
|
|
||||||
|
|
||||||
if (meshGroup.texture) {
|
|
||||||
glGenBuffers(1, &cache.vboTexcoords);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, cache.vboTexcoords);
|
|
||||||
glBufferData(
|
|
||||||
GL_ARRAY_BUFFER,
|
|
||||||
cache.texcoords.size() * sizeof(TexCoord),
|
|
||||||
cache.texcoords.data(),
|
|
||||||
GL_STATIC_DRAW
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
glGenBuffers(1, &cache.ibo);
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache.ibo);
|
|
||||||
glBufferData(
|
|
||||||
GL_ELEMENT_ARRAY_BUFFER,
|
|
||||||
cache.indices.size() * sizeof(cache.indices[0]),
|
|
||||||
cache.indices.data(),
|
|
||||||
GL_STATIC_DRAW
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
@ -269,12 +230,7 @@ void OpenGL1Renderer::AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh)
|
|||||||
auto* ctx = static_cast<GLMeshDestroyContext*>(arg);
|
auto* ctx = static_cast<GLMeshDestroyContext*>(arg);
|
||||||
auto& cache = ctx->renderer->m_meshs[ctx->id];
|
auto& cache = ctx->renderer->m_meshs[ctx->id];
|
||||||
cache.meshGroup = nullptr;
|
cache.meshGroup = nullptr;
|
||||||
if (ctx->renderer->m_useVBOs) {
|
GL11_DestroyMesh(cache);
|
||||||
glDeleteBuffers(1, &cache.vboPositions);
|
|
||||||
glDeleteBuffers(1, &cache.vboNormals);
|
|
||||||
glDeleteBuffers(1, &cache.vboTexcoords);
|
|
||||||
glDeleteBuffers(1, &cache.ibo);
|
|
||||||
}
|
|
||||||
delete ctx;
|
delete ctx;
|
||||||
},
|
},
|
||||||
ctx
|
ctx
|
||||||
@ -329,90 +285,23 @@ const char* OpenGL1Renderer::GetName()
|
|||||||
|
|
||||||
HRESULT OpenGL1Renderer::BeginFrame()
|
HRESULT OpenGL1Renderer::BeginFrame()
|
||||||
{
|
{
|
||||||
m_dirty = true;
|
GL11_BeginFrame((Matrix4x4*) &m_projection[0][0]);
|
||||||
|
|
||||||
glDisable(GL_BLEND);
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
|
||||||
glDepthMask(GL_TRUE);
|
|
||||||
glEnable(GL_LIGHTING);
|
|
||||||
glEnable(GL_COLOR_MATERIAL);
|
|
||||||
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
|
|
||||||
|
|
||||||
// Disable all lights and reset global ambient
|
|
||||||
for (int i = 0; i < 8; ++i) {
|
|
||||||
glDisable(GL_LIGHT0 + i);
|
|
||||||
}
|
|
||||||
const GLfloat zeroAmbient[4] = {0.f, 0.f, 0.f, 1.f};
|
|
||||||
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, zeroAmbient);
|
|
||||||
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
|
|
||||||
|
|
||||||
// Setup lights
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
|
||||||
glPushMatrix();
|
|
||||||
glLoadIdentity();
|
|
||||||
|
|
||||||
int lightIdx = 0;
|
int lightIdx = 0;
|
||||||
for (const auto& l : m_lights) {
|
for (const auto& l : m_lights) {
|
||||||
if (lightIdx > 7) {
|
if (lightIdx > 7) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
GLenum lightId = GL_LIGHT0 + lightIdx++;
|
GL11_UploadLight(lightIdx, (GL11_BridgeSceneLight*) &l);
|
||||||
const FColor& c = l.color;
|
|
||||||
GLfloat col[4] = {c.r, c.g, c.b, c.a};
|
|
||||||
|
|
||||||
if (l.positional == 0.f && l.directional == 0.f) {
|
lightIdx++;
|
||||||
// Ambient light only
|
|
||||||
glLightfv(lightId, GL_AMBIENT, col);
|
|
||||||
const GLfloat black[4] = {0.f, 0.f, 0.f, 1.f};
|
|
||||||
glLightfv(lightId, GL_DIFFUSE, black);
|
|
||||||
glLightfv(lightId, GL_SPECULAR, black);
|
|
||||||
const GLfloat dummyPos[4] = {0.f, 0.f, 1.f, 0.f};
|
|
||||||
glLightfv(lightId, GL_POSITION, dummyPos);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
glLightfv(lightId, GL_AMBIENT, zeroAmbient);
|
|
||||||
glLightfv(lightId, GL_DIFFUSE, col);
|
|
||||||
if (l.directional == 1.0f) {
|
|
||||||
glLightfv(lightId, GL_SPECULAR, col);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const GLfloat black[4] = {0.f, 0.f, 0.f, 1.f};
|
|
||||||
glLightfv(lightId, GL_SPECULAR, black);
|
|
||||||
}
|
|
||||||
|
|
||||||
GLfloat pos[4];
|
|
||||||
if (l.directional == 1.f) {
|
|
||||||
pos[0] = -l.direction.x;
|
|
||||||
pos[1] = -l.direction.y;
|
|
||||||
pos[2] = -l.direction.z;
|
|
||||||
pos[3] = 0.f;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
pos[0] = l.position.x;
|
|
||||||
pos[1] = l.position.y;
|
|
||||||
pos[2] = l.position.z;
|
|
||||||
pos[3] = 1.f;
|
|
||||||
}
|
|
||||||
glLightfv(lightId, GL_POSITION, pos);
|
|
||||||
}
|
|
||||||
glEnable(lightId);
|
|
||||||
}
|
}
|
||||||
glPopMatrix();
|
|
||||||
|
|
||||||
// Projection and view
|
|
||||||
glMatrixMode(GL_PROJECTION);
|
|
||||||
glLoadMatrixf(&m_projection[0][0]);
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
|
||||||
glLoadIdentity();
|
|
||||||
|
|
||||||
return DD_OK;
|
return DD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGL1Renderer::EnableTransparency()
|
void OpenGL1Renderer::EnableTransparency()
|
||||||
{
|
{
|
||||||
glEnable(GL_BLEND);
|
GL11_EnableTransparency();
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
glDepthMask(GL_FALSE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGL1Renderer::SubmitDraw(
|
void OpenGL1Renderer::SubmitDraw(
|
||||||
@ -426,75 +315,14 @@ void OpenGL1Renderer::SubmitDraw(
|
|||||||
{
|
{
|
||||||
auto& mesh = m_meshs[meshId];
|
auto& mesh = m_meshs[meshId];
|
||||||
|
|
||||||
glLoadMatrixf(&modelViewMatrix[0][0]);
|
|
||||||
glEnable(GL_NORMALIZE);
|
|
||||||
|
|
||||||
glColor4ub(appearance.color.r, appearance.color.g, appearance.color.b, appearance.color.a);
|
|
||||||
|
|
||||||
if (appearance.shininess != 0.0f) {
|
|
||||||
GLfloat whiteSpec[] = {1.f, 1.f, 1.f, 1.f};
|
|
||||||
glMaterialfv(GL_FRONT, GL_SPECULAR, whiteSpec);
|
|
||||||
glMaterialf(GL_FRONT, GL_SHININESS, appearance.shininess);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
GLfloat noSpec[] = {0.0f, 0.0f, 0.0f, 0.0f};
|
|
||||||
glMaterialfv(GL_FRONT, GL_SPECULAR, noSpec);
|
|
||||||
glMaterialf(GL_FRONT, GL_SHININESS, 0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mesh.flat) {
|
|
||||||
glShadeModel(GL_FLAT);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
glShadeModel(GL_SMOOTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bind texture if present
|
// Bind texture if present
|
||||||
if (appearance.textureId != NO_TEXTURE_ID) {
|
if (appearance.textureId != NO_TEXTURE_ID) {
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
auto& tex = m_textures[appearance.textureId];
|
auto& tex = m_textures[appearance.textureId];
|
||||||
glEnable(GL_TEXTURE_2D);
|
GL11_SubmitDraw(mesh, modelViewMatrix, appearance, tex.glTextureId);
|
||||||
glBindTexture(GL_TEXTURE_2D, tex.glTextureId);
|
|
||||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
glDisable(GL_TEXTURE_2D);
|
GL11_SubmitDraw(mesh, modelViewMatrix, appearance, 0);
|
||||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
|
||||||
glEnableClientState(GL_NORMAL_ARRAY);
|
|
||||||
|
|
||||||
if (m_useVBOs) {
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboPositions);
|
|
||||||
glVertexPointer(3, GL_FLOAT, 0, nullptr);
|
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboNormals);
|
|
||||||
glNormalPointer(GL_FLOAT, 0, nullptr);
|
|
||||||
|
|
||||||
if (appearance.textureId != NO_TEXTURE_ID) {
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboTexcoords);
|
|
||||||
glTexCoordPointer(2, GL_FLOAT, 0, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.ibo);
|
|
||||||
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(mesh.indices.size()), GL_UNSIGNED_SHORT, nullptr);
|
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
glVertexPointer(3, GL_FLOAT, 0, mesh.positions.data());
|
|
||||||
glNormalPointer(GL_FLOAT, 0, mesh.normals.data());
|
|
||||||
if (appearance.textureId != NO_TEXTURE_ID) {
|
|
||||||
glTexCoordPointer(2, GL_FLOAT, 0, mesh.texcoords.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(mesh.indices.size()), GL_UNSIGNED_SHORT, mesh.indices.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
glPopMatrix();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT OpenGL1Renderer::FinalizeFrame()
|
HRESULT OpenGL1Renderer::FinalizeFrame()
|
||||||
@ -509,16 +337,13 @@ void OpenGL1Renderer::Resize(int width, int height, const ViewportTransform& vie
|
|||||||
m_viewportTransform = viewportTransform;
|
m_viewportTransform = viewportTransform;
|
||||||
SDL_DestroySurface(m_renderedImage);
|
SDL_DestroySurface(m_renderedImage);
|
||||||
m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32);
|
m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32);
|
||||||
glViewport(0, 0, m_width, m_height);
|
GL11_Resize(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGL1Renderer::Clear(float r, float g, float b)
|
void OpenGL1Renderer::Clear(float r, float g, float b)
|
||||||
{
|
{
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
glEnable(GL_DEPTH_TEST);
|
GL11_Clear(r, g, b);
|
||||||
glDepthMask(GL_TRUE);
|
|
||||||
glClearColor(r, g, b, 1.0f);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGL1Renderer::Flip()
|
void OpenGL1Renderer::Flip()
|
||||||
@ -532,73 +357,18 @@ void OpenGL1Renderer::Flip()
|
|||||||
void OpenGL1Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect)
|
void OpenGL1Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect)
|
||||||
{
|
{
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
glDisable(GL_DEPTH_TEST);
|
|
||||||
glDepthMask(GL_FALSE);
|
|
||||||
|
|
||||||
glMatrixMode(GL_PROJECTION);
|
|
||||||
glPushMatrix();
|
|
||||||
glLoadIdentity();
|
|
||||||
|
|
||||||
float left = -m_viewportTransform.offsetX / m_viewportTransform.scale;
|
float left = -m_viewportTransform.offsetX / m_viewportTransform.scale;
|
||||||
float right = (m_width - m_viewportTransform.offsetX) / m_viewportTransform.scale;
|
float right = (m_width - m_viewportTransform.offsetX) / m_viewportTransform.scale;
|
||||||
float top = -m_viewportTransform.offsetY / m_viewportTransform.scale;
|
float top = -m_viewportTransform.offsetY / m_viewportTransform.scale;
|
||||||
float bottom = (m_height - m_viewportTransform.offsetY) / m_viewportTransform.scale;
|
float bottom = (m_height - m_viewportTransform.offsetY) / m_viewportTransform.scale;
|
||||||
glOrtho(left, right, bottom, top, -1, 1);
|
|
||||||
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
GL11_Draw2DImage(m_textures[textureId].glTextureId, srcRect, dstRect, left, right, bottom, top);
|
||||||
glPushMatrix();
|
|
||||||
glLoadIdentity();
|
|
||||||
|
|
||||||
glDisable(GL_LIGHTING);
|
|
||||||
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
|
||||||
|
|
||||||
glEnable(GL_TEXTURE_2D);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, m_textures[textureId].glTextureId);
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
||||||
|
|
||||||
GLint boundTexture = 0;
|
|
||||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTexture);
|
|
||||||
|
|
||||||
GLfloat texW, texH;
|
|
||||||
glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &texW);
|
|
||||||
glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &texH);
|
|
||||||
|
|
||||||
float u1 = srcRect.x / texW;
|
|
||||||
float v1 = srcRect.y / texH;
|
|
||||||
float u2 = (srcRect.x + srcRect.w) / texW;
|
|
||||||
float v2 = (srcRect.y + srcRect.h) / texH;
|
|
||||||
|
|
||||||
float x1 = (float) dstRect.x;
|
|
||||||
float y1 = (float) dstRect.y;
|
|
||||||
float x2 = x1 + dstRect.w;
|
|
||||||
float y2 = y1 + dstRect.h;
|
|
||||||
|
|
||||||
glBegin(GL_QUADS);
|
|
||||||
glTexCoord2f(u1, v1);
|
|
||||||
glVertex2f(x1, y1);
|
|
||||||
glTexCoord2f(u2, v1);
|
|
||||||
glVertex2f(x2, y1);
|
|
||||||
glTexCoord2f(u2, v2);
|
|
||||||
glVertex2f(x2, y2);
|
|
||||||
glTexCoord2f(u1, v2);
|
|
||||||
glVertex2f(x1, y2);
|
|
||||||
glEnd();
|
|
||||||
|
|
||||||
// Restore state
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
|
||||||
glPopMatrix();
|
|
||||||
glMatrixMode(GL_PROJECTION);
|
|
||||||
glPopMatrix();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGL1Renderer::Download(SDL_Surface* target)
|
void OpenGL1Renderer::Download(SDL_Surface* target)
|
||||||
{
|
{
|
||||||
glFinish();
|
GL11_Download(m_renderedImage);
|
||||||
glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, m_renderedImage->pixels);
|
|
||||||
|
|
||||||
SDL_Rect srcRect = {
|
SDL_Rect srcRect = {
|
||||||
static_cast<int>(m_viewportTransform.offsetX),
|
static_cast<int>(m_viewportTransform.offsetX),
|
||||||
|
|||||||
@ -30,6 +30,12 @@ struct SceneLightGLES2 {
|
|||||||
|
|
||||||
Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height)
|
Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height)
|
||||||
{
|
{
|
||||||
|
// 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
|
||||||
|
// call below when on an EGL-based backend, and crashes with EGL_BAD_MATCH.
|
||||||
|
SDL_GL_ResetAttributes();
|
||||||
|
// 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_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||||
@ -41,8 +47,6 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height)
|
|||||||
testWindow = true;
|
testWindow = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
|
||||||
|
|
||||||
SDL_GLContext context = SDL_GL_CreateContext(window);
|
SDL_GLContext context = SDL_GL_CreateContext(window);
|
||||||
if (!context) {
|
if (!context) {
|
||||||
if (testWindow) {
|
if (testWindow) {
|
||||||
|
|||||||
@ -1,44 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "../d3drm/backends/opengl1/actual.h"
|
||||||
#include "d3drmrenderer.h"
|
#include "d3drmrenderer.h"
|
||||||
#include "d3drmtexture_impl.h"
|
#include "d3drmtexture_impl.h"
|
||||||
#include "ddraw_impl.h"
|
#include "ddraw_impl.h"
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
#include <OpenGL/gl.h>
|
|
||||||
#else
|
|
||||||
#include <GL/gl.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
DEFINE_GUID(OpenGL1_GUID, 0x682656F3, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03);
|
DEFINE_GUID(OpenGL1_GUID, 0x682656F3, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03);
|
||||||
|
|
||||||
struct GLTextureCacheEntry {
|
|
||||||
IDirect3DRMTexture* texture;
|
|
||||||
Uint32 version;
|
|
||||||
GLuint glTextureId;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GLMeshCacheEntry {
|
|
||||||
const MeshGroup* meshGroup;
|
|
||||||
int version;
|
|
||||||
bool flat;
|
|
||||||
|
|
||||||
// non-VBO cache
|
|
||||||
std::vector<D3DVECTOR> positions;
|
|
||||||
std::vector<D3DVECTOR> normals;
|
|
||||||
std::vector<TexCoord> texcoords;
|
|
||||||
std::vector<uint16_t> indices;
|
|
||||||
|
|
||||||
// VBO cache
|
|
||||||
GLuint vboPositions;
|
|
||||||
GLuint vboNormals;
|
|
||||||
GLuint vboTexcoords;
|
|
||||||
GLuint ibo;
|
|
||||||
};
|
|
||||||
|
|
||||||
class OpenGL1Renderer : public Direct3DRMRenderer {
|
class OpenGL1Renderer : public Direct3DRMRenderer {
|
||||||
public:
|
public:
|
||||||
static Direct3DRMRenderer* Create(DWORD width, DWORD height);
|
static Direct3DRMRenderer* Create(DWORD width, DWORD height);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user