mkxp-freebird/src/gl-fun.cpp

194 lines
3.8 KiB
C++

/*
** gl-fun.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2014 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp 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 2 of the License, or
** (at your option) any later version.
**
** mkxp 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 mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "gl-fun.h"
#include "boost-hash.h"
#include "exception.h"
#include <SDL_video.h>
#include <string>
GLFunctions gl;
typedef const GLubyte* (APIENTRYP _PFNGLGETSTRINGIPROC) (GLenum, GLuint);
static void parseExtensionsCore(_PFNGLGETINTEGERVPROC GetIntegerv, BoostSet<std::string> &out)
{
_PFNGLGETSTRINGIPROC GetStringi =
(_PFNGLGETSTRINGIPROC) SDL_GL_GetProcAddress("glGetStringi");
GLint extCount = 0;
GetIntegerv(GL_NUM_EXTENSIONS, &extCount);
for (GLint i = 0; i < extCount; ++i)
out.insert((const char*) GetStringi(GL_EXTENSIONS, i));
}
static void parseExtensionsCompat(_PFNGLGETSTRINGPROC GetString, BoostSet<std::string> &out)
{
const char *ext = (const char*) GetString(GL_EXTENSIONS);
if (!ext)
return;
char buffer[0x100];
size_t bufferI;
while (*ext)
{
bufferI = 0;
while (*ext && *ext != ' ')
buffer[bufferI++] = *ext++;
buffer[bufferI] = '\0';
out.insert(buffer);
if (*ext == ' ')
++ext;
}
}
#define GL_FUN(name, type) \
gl.name = (type) SDL_GL_GetProcAddress("gl" #name EXT_SUFFIX);
#define EXC(msg) \
Exception(Exception::MKXPError, "%s", msg)
void initGLFunctions()
{
#define EXT_SUFFIX ""
GL_20_FUN;
/* Determine GL version */
const char *ver = (const char*) gl.GetString(GL_VERSION);
const char glesPrefix[] = "OpenGL ES ";
const size_t glesPrefixN = sizeof(glesPrefix)-1;
bool gles = false;
if (!strncmp(ver, glesPrefix, glesPrefixN))
{
gles = true;
gl.glsles = true;
ver += glesPrefixN;
}
/* Assume single digit */
int glMajor = *ver - '0';
if (glMajor < 2)
throw EXC("At least OpenGL (ES) 2.0 is required");
if (gles)
{
GL_ES_FUN;
}
BoostSet<std::string> ext;
if (glMajor >= 3)
parseExtensionsCore(gl.GetIntegerv, ext);
else
parseExtensionsCompat(gl.GetString, ext);
#define HAVE_EXT(_ext) ext.contains("GL_" #_ext)
/* FBO entrypoints */
if (glMajor >= 3 || HAVE_EXT(ARB_framebuffer_object))
{
#undef EXT_SUFFIX
#define EXT_SUFFIX ""
GL_FBO_FUN;
GL_FBO_BLIT_FUN;
}
else if (gles && glMajor == 2)
{
GL_FBO_FUN;
}
else if (HAVE_EXT(EXT_framebuffer_object))
{
#undef EXT_SUFFIX
#define EXT_SUFFIX "EXT"
GL_FBO_FUN;
if (HAVE_EXT(EXT_framebuffer_blit))
{
GL_FBO_BLIT_FUN;
}
}
else
{
throw EXC("No FBO support available");
}
/* VAO entrypoints */
if (HAVE_EXT(ARB_vertex_array_object) || glMajor >= 3)
{
#undef EXT_SUFFIX
#define EXT_SUFFIX ""
GL_VAO_FUN;
}
else if (HAVE_EXT(APPLE_vertex_array_object))
{
#undef EXT_SUFFIX
#define EXT_SUFFIX "APPLE"
GL_VAO_FUN;
}
else if (HAVE_EXT(OES_vertex_array_object))
{
#undef EXT_SUFFIX
#define EXT_SUFFIX "OES"
GL_VAO_FUN;
}
/* Debug callback entrypoints */
if (HAVE_EXT(KHR_debug))
{
#undef EXT_SUFFIX
#define EXT_SUFFIX ""
GL_DEBUG_KHR_FUN;
}
else if (HAVE_EXT(ARB_debug_output))
{
#undef EXT_SUFFIX
#define EXT_SUFFIX "ARB"
GL_DEBUG_KHR_FUN;
}
if (HAVE_EXT(GREMEDY_string_marker))
{
#undef EXT_SUFFIX
#define EXT_SUFFIX "GREMEDY"
GL_GREMEMDY_FUN;
}
/* Misc caps */
if (!gles || glMajor >= 3 || HAVE_EXT(EXT_unpack_subimage))
gl.unpack_subimage = true;
if (!gles || glMajor >= 3 || HAVE_EXT(OES_texture_npot))
gl.npot_repeat = true;
}