/* * 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 . */ #pragma once #include #include #include #include #include #define GL_GLEXT_PROTOTYPES #include #include "descent.h" #include "log.h" #include "module.h" #if defined(WIN32) #define GLFUNCCALL __stdcall #elif defined(POSIX) #include #define GLFUNCCALL #endif inline void CheckError() { #if defined(FATAL_GL_ERRORS) static auto _dglGetError = reinterpret_cast(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 struct FnPtr; template struct FnPtr { explicit FnPtr(std::string_view name, bool optional = false); Ret operator()(Args... args) const { if constexpr (std::is_same_v) { 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> 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 FnPtr::FnPtr(std::string_view name, bool optional) : fn_{} { inits_.push_back(std::make_tuple(reinterpret_cast(&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 const d##Name{#Name, Opt} #define DYNAEXTERN(Name) DYNAEXTERN_OPT(Name, false) #else #define DYNAEXTERN(Name) extern FnPtr 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