Descent3/renderer/dyna_gl.h

207 lines
5.6 KiB
C
Raw Permalink Normal View History

/*
* Descent 3
* Copyright (C) 2024 Parallax Software
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
2024-04-16 03:43:29 +00:00
#pragma once
#include <filesystem>
#include <stdexcept>
#include <string>
#include <tuple>
#include <vector>
#define GL_GLEXT_PROTOTYPES
#include <SDL_opengl.h>
#include "descent.h"
#include "log.h"
2024-04-16 03:43:29 +00:00
#include "module.h"
#if defined(WIN32)
2024-04-16 18:56:40 +00:00
#define GLFUNCCALL __stdcall
#elif defined(POSIX)
2024-04-16 03:43:29 +00:00
#include <unistd.h>
#define GLFUNCCALL
#endif
inline void CheckError() {
#if defined(FATAL_GL_ERRORS)
static auto _dglGetError = reinterpret_cast<GLenum (*)()>(SDL_GL_GetProcAddress("glGetError"));
auto err = _dglGetError();
switch (err) {
case GL_NO_ERROR:
return;
case GL_INVALID_ENUM:
throw std::runtime_error("invalid enum");
case GL_INVALID_VALUE:
throw std::runtime_error("invalid value");
case GL_INVALID_OPERATION:
throw std::runtime_error("invalid operation");
case GL_INVALID_FRAMEBUFFER_OPERATION:
throw std::runtime_error("invalid framebuffer operation");
case GL_INVALID_INDEX:
throw std::runtime_error("invalid index");
default:
throw std::runtime_error("unknown error: " + std::to_string(err));
}
2024-04-16 03:43:29 +00:00
#endif
}
2024-04-16 03:43:29 +00:00
template <typename T> struct FnPtr;
template <typename Ret, typename... Args>
struct FnPtr<Ret GLFUNCCALL(Args...)> {
explicit FnPtr(std::string_view name, bool optional = false);
Ret operator()(Args... args) const {
if constexpr (std::is_same_v<Ret, void>) {
fn_(args...);
CheckError();
} else {
auto ret = fn_(args...);
CheckError();
return ret;
}
}
2024-04-16 03:43:29 +00:00
operator bool() const { return fn_; }
2024-04-16 03:43:29 +00:00
private:
Ret (GLFUNCCALL *fn_)(Args...);
};
opengl: use SDL_WINDOW_FULLSCREEN_DESKTOP and an FBO. This now renders to an OpenGL Framebuffer Object at the game's resolution, and blits it to the window at whatever resolution it is currently using, scaling and letterboxing if necessary. Which is to say: display resolutions are now imaginary, and we never change the physical display mode now. A smaller resolution is simply drawing less pixels and scaling them up with the GPU for display. This solves a few problems: no more resizing background windows or desktop icons shuffling around, no more being stuck in a weird resolution when debugging or if the game crashes, no more waiting on monitors to click over to a new mode, and no more weird rendering when the display didn't exactly support the requested mode. This also means the game doesn't have to drop down to 640x480 for the config menu screen when it was otherwise using some other resolution. Some caveats: - This _requires_ OpenGL Framebuffer Object support; there is currently no fallback if it's missing and the game will refuse to start. But any desktop hardware of the last ~20 years should support it. For weird embedded things or whatnot, it will be possible to add a fallback. - This currently requires SDL. The OpenGL pieces should work on Windows, but someone would need to adjust the existing win32 code to create a fullscreen window and not change the physical display mode. It should still compile on windows and work as before (untested by me, though). - This is only OpenGL; it does not touch the Direct3D renderer, which should continue to work as before (again, untested by me).
2024-06-14 07:35:54 +00:00
#if defined(DECLARE_OPENGL)
extern char loadedLibrary[_MAX_PATH];
2024-04-16 03:43:29 +00:00
static module OpenGLDLLInst;
static std::vector<std::tuple<void **, std::string_view, bool>> inits_;
static void LoadGLFnPtrs() {
for (auto &[ptr, name, optional] : inits_) {
*ptr = SDL_GL_GetProcAddress(name.data());
if (!*ptr && !optional) {
throw std::runtime_error(std::string{"failed to find "} + name.data());
}
}
inits_.clear();
}
2024-04-16 03:43:29 +00:00
template<typename Ret, typename... Args>
FnPtr<Ret GLFUNCCALL(Args...)>::FnPtr(std::string_view name, bool optional) : fn_{} {
inits_.push_back(std::make_tuple(reinterpret_cast<void**>(&fn_), name, optional));
}
static module *LoadOpenGLDLL(const char *dllname) {
LOG_INFO << "Loading OpenGL dll...";
int rc = SDL_GL_LoadLibrary(dllname[0] ? dllname : nullptr);
2024-04-16 18:56:40 +00:00
if (rc < 0) {
const char *sdlErr = SDL_GetError();
LOG_ERROR.printf("OpenGL: Couldn't open library [%s]: SDL error [%s].",
dllname[0] ? dllname : "system default", sdlErr);
2024-04-16 18:56:40 +00:00
return NULL;
}
strcpy(loadedLibrary, dllname);
2024-04-16 03:43:29 +00:00
LOG_INFO << "OpenGL dll loading successful.";
2024-04-16 03:43:29 +00:00
return &OpenGLDLLInst;
}
2024-04-16 03:43:29 +00:00
#define DYNAEXTERN_OPT(Name, Opt) FnPtr<decltype(Name)> const d##Name{#Name, Opt}
#define DYNAEXTERN(Name) DYNAEXTERN_OPT(Name, false)
2024-04-16 03:43:29 +00:00
#else
#define DYNAEXTERN(Name) extern FnPtr<decltype(Name)> const d##Name
2024-04-16 03:43:29 +00:00
#endif
2024-07-20 21:19:31 +00:00
DYNAEXTERN(glAttachShader);
DYNAEXTERN(glBindAttribLocation);
DYNAEXTERN(glBindBuffer);
DYNAEXTERN(glBindTexture);
2024-07-20 21:19:31 +00:00
DYNAEXTERN(glBindVertexArray);
DYNAEXTERN(glBlendFunc);
2024-07-20 21:19:31 +00:00
DYNAEXTERN(glBufferData);
DYNAEXTERN(glBufferSubData);
DYNAEXTERN(glClear);
DYNAEXTERN(glClearColor);
2024-07-20 21:19:31 +00:00
DYNAEXTERN(glCompileShader);
DYNAEXTERN(glCreateProgram);
DYNAEXTERN(glCreateShader);
DYNAEXTERN(glDeleteBuffers);
DYNAEXTERN(glDeleteProgram);
DYNAEXTERN(glDeleteShader);
DYNAEXTERN(glDeleteTextures);
2024-07-20 21:19:31 +00:00
DYNAEXTERN(glDeleteVertexArrays);
DYNAEXTERN(glDepthFunc);
DYNAEXTERN(glDepthMask);
DYNAEXTERN(glDisable);
DYNAEXTERN(glDrawArrays);
DYNAEXTERN(glEnable);
2024-07-20 21:19:31 +00:00
DYNAEXTERN(glEnableVertexAttribArray);
DYNAEXTERN(glFlush);
2024-07-20 21:19:31 +00:00
DYNAEXTERN(glGenBuffers);
DYNAEXTERN(glGenTextures);
2024-07-20 21:19:31 +00:00
DYNAEXTERN(glGenVertexArrays);
DYNAEXTERN(glGetError);
DYNAEXTERN(glGetIntegerv);
2024-07-20 21:19:31 +00:00
DYNAEXTERN(glGetProgramInfoLog);
DYNAEXTERN(glGetProgramiv);
DYNAEXTERN(glGetShaderInfoLog);
DYNAEXTERN(glGetShaderiv);
DYNAEXTERN(glGetString);
2024-07-24 07:07:34 +00:00
DYNAEXTERN(glGetStringi);
DYNAEXTERN(glGetUniformLocation);
2024-07-20 21:19:31 +00:00
DYNAEXTERN(glLinkProgram);
DYNAEXTERN(glMapBufferRange);
DYNAEXTERN(glPixelStorei);
DYNAEXTERN(glPolygonOffset);
DYNAEXTERN(glReadPixels);
DYNAEXTERN(glScissor);
2024-07-20 21:19:31 +00:00
DYNAEXTERN(glShaderSource);
DYNAEXTERN(glTexImage2D);
DYNAEXTERN(glTexParameteri);
DYNAEXTERN(glTexSubImage2D);
2024-08-06 23:16:15 +00:00
DYNAEXTERN(glUniform1f);
DYNAEXTERN(glUniform1i);
2024-08-06 23:16:15 +00:00
DYNAEXTERN(glUniform4f);
DYNAEXTERN(glUniformMatrix4fv);
DYNAEXTERN(glUnmapBuffer);
2024-07-20 21:19:31 +00:00
DYNAEXTERN(glUseProgram);
DYNAEXTERN(glVertexAttribPointer);
DYNAEXTERN(glViewport);
2024-04-16 03:43:29 +00:00
// FBO entry points for render-to-texture ...
2024-08-07 05:58:49 +00:00
DYNAEXTERN(glBindFramebuffer);
DYNAEXTERN(glBindRenderbuffer);
DYNAEXTERN(glBlitFramebuffer);
DYNAEXTERN(glCheckFramebufferStatus);
DYNAEXTERN(glDeleteFramebuffers);
DYNAEXTERN(glDeleteRenderbuffers);
DYNAEXTERN(glFramebufferRenderbuffer);
DYNAEXTERN(glGenFramebuffers);
DYNAEXTERN(glGenRenderbuffers);
DYNAEXTERN(glRenderbufferStorage);
DYNAEXTERN(glActiveTexture);
2024-08-05 04:01:02 +00:00
DYNAEXTERN(glMultiTexCoord4f);
#if defined(WIN32)
DYNAEXTERN(wglCreateContext);
DYNAEXTERN(wglDeleteContext);
DYNAEXTERN(wglGetProcAddress);
DYNAEXTERN(wglMakeCurrent);
2024-04-16 03:43:29 +00:00
#endif