Descent3/renderer/dyna_gl.h
2024-09-24 23:00:53 +03:00

207 lines
5.6 KiB
C++

/*
* 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/>.
*/
#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"
#include "module.h"
#if defined(WIN32)
#define GLFUNCCALL __stdcall
#elif defined(POSIX)
#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));
}
#endif
}
template <typename T> struct FnPtr;
template <typename Ret, typename... Args>
struct FnPtr<Ret(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;
}
}
operator bool() const { return fn_; }
private:
Ret (GLFUNCCALL *fn_)(Args...);
};
#if defined(DECLARE_OPENGL)
extern char loadedLibrary[_MAX_PATH];
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();
}
template<typename Ret, typename... Args>
FnPtr<Ret(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);
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);
return NULL;
}
strcpy(loadedLibrary, dllname);
LOG_INFO << "OpenGL dll loading successful.";
return &OpenGLDLLInst;
}
#define DYNAEXTERN_OPT(Name, Opt) FnPtr<decltype(Name)> const d##Name{#Name, Opt}
#define DYNAEXTERN(Name) DYNAEXTERN_OPT(Name, false)
#else
#define DYNAEXTERN(Name) extern FnPtr<decltype(Name)> const d##Name
#endif
DYNAEXTERN(glAttachShader);
DYNAEXTERN(glBindAttribLocation);
DYNAEXTERN(glBindBuffer);
DYNAEXTERN(glBindTexture);
DYNAEXTERN(glBindVertexArray);
DYNAEXTERN(glBlendFunc);
DYNAEXTERN(glBufferData);
DYNAEXTERN(glBufferSubData);
DYNAEXTERN(glClear);
DYNAEXTERN(glClearColor);
DYNAEXTERN(glCompileShader);
DYNAEXTERN(glCreateProgram);
DYNAEXTERN(glCreateShader);
DYNAEXTERN(glDeleteBuffers);
DYNAEXTERN(glDeleteProgram);
DYNAEXTERN(glDeleteShader);
DYNAEXTERN(glDeleteTextures);
DYNAEXTERN(glDeleteVertexArrays);
DYNAEXTERN(glDepthFunc);
DYNAEXTERN(glDepthMask);
DYNAEXTERN(glDisable);
DYNAEXTERN(glDrawArrays);
DYNAEXTERN(glEnable);
DYNAEXTERN(glEnableVertexAttribArray);
DYNAEXTERN(glFlush);
DYNAEXTERN(glGenBuffers);
DYNAEXTERN(glGenTextures);
DYNAEXTERN(glGenVertexArrays);
DYNAEXTERN(glGetError);
DYNAEXTERN(glGetIntegerv);
DYNAEXTERN(glGetProgramInfoLog);
DYNAEXTERN(glGetProgramiv);
DYNAEXTERN(glGetShaderInfoLog);
DYNAEXTERN(glGetShaderiv);
DYNAEXTERN(glGetString);
DYNAEXTERN(glGetStringi);
DYNAEXTERN(glGetUniformLocation);
DYNAEXTERN(glLinkProgram);
DYNAEXTERN(glMapBufferRange);
DYNAEXTERN(glPixelStorei);
DYNAEXTERN(glPolygonOffset);
DYNAEXTERN(glReadPixels);
DYNAEXTERN(glScissor);
DYNAEXTERN(glShaderSource);
DYNAEXTERN(glTexImage2D);
DYNAEXTERN(glTexParameteri);
DYNAEXTERN(glTexSubImage2D);
DYNAEXTERN(glUniform1f);
DYNAEXTERN(glUniform1i);
DYNAEXTERN(glUniform4f);
DYNAEXTERN(glUniformMatrix4fv);
DYNAEXTERN(glUnmapBuffer);
DYNAEXTERN(glUseProgram);
DYNAEXTERN(glVertexAttribPointer);
DYNAEXTERN(glViewport);
// FBO entry points for render-to-texture ...
DYNAEXTERN(glBindFramebuffer);
DYNAEXTERN(glBindRenderbuffer);
DYNAEXTERN(glBlitFramebuffer);
DYNAEXTERN(glCheckFramebufferStatus);
DYNAEXTERN(glDeleteFramebuffers);
DYNAEXTERN(glDeleteRenderbuffers);
DYNAEXTERN(glFramebufferRenderbuffer);
DYNAEXTERN(glGenFramebuffers);
DYNAEXTERN(glGenRenderbuffers);
DYNAEXTERN(glRenderbufferStorage);
DYNAEXTERN(glActiveTexture);
DYNAEXTERN(glMultiTexCoord4f);
#if defined(WIN32)
DYNAEXTERN(wglCreateContext);
DYNAEXTERN(wglDeleteContext);
DYNAEXTERN(wglGetProcAddress);
DYNAEXTERN(wglMakeCurrent);
#endif