The general rule I'm aiming for is to <> include system wide / installed paths / generally everything that's outside the git managed source tree (this means mruby paths too!), and "" include everything else, ie. local mkxp headers. The only current exception are the mri headers, which all have './' at their front as to not clash with system wide ruby headers. I'm leaving them be for now until I can come up with a better general solution.
419 lines
7.7 KiB
C++
419 lines
7.7 KiB
C++
/*
|
|
** gl-util.h
|
|
**
|
|
** This file is part of mkxp.
|
|
**
|
|
** Copyright (C) 2013 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/>.
|
|
*/
|
|
|
|
#ifndef GLUTIL_H
|
|
#define GLUTIL_H
|
|
|
|
#include <glew.h>
|
|
|
|
#include "etc-internal.h"
|
|
|
|
/* Struct wrapping GLuint for some light type safety */
|
|
#define DEF_GL_ID \
|
|
struct ID \
|
|
{ \
|
|
GLuint gl; \
|
|
explicit ID(GLuint gl = 0) \
|
|
: gl(gl) \
|
|
{} \
|
|
ID &operator=(const ID &o) \
|
|
{ \
|
|
gl = o.gl; \
|
|
return *this; \
|
|
} \
|
|
bool operator==(const ID &o) const \
|
|
{ \
|
|
return gl == o.gl; \
|
|
} \
|
|
};
|
|
|
|
/* 2D Texture */
|
|
namespace TEX
|
|
{
|
|
DEF_GL_ID
|
|
|
|
inline ID gen()
|
|
{
|
|
ID id;
|
|
glGenTextures(1, &id.gl);
|
|
|
|
return id;
|
|
}
|
|
|
|
inline void del(ID id)
|
|
{
|
|
glDeleteTextures(1, &id.gl);
|
|
}
|
|
|
|
inline void bind(ID id)
|
|
{
|
|
glBindTexture(GL_TEXTURE_2D, id.gl);
|
|
}
|
|
|
|
inline void unbind()
|
|
{
|
|
bind(ID(0));
|
|
}
|
|
|
|
inline void uploadImage(GLsizei width, GLsizei height, const void *data, GLenum format)
|
|
{
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, format, GL_UNSIGNED_BYTE, data);
|
|
}
|
|
|
|
inline void uploadSubImage(GLint x, GLint y, GLsizei width, GLsizei height, const void *data, GLenum format)
|
|
{
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, format, GL_UNSIGNED_BYTE, data);
|
|
}
|
|
|
|
inline void allocEmpty(GLsizei width, GLsizei height)
|
|
{
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
|
}
|
|
|
|
inline void setRepeat(bool mode)
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mode ? GL_REPEAT : GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mode ? GL_REPEAT : GL_CLAMP_TO_EDGE);
|
|
}
|
|
|
|
inline void setSmooth(bool mode)
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mode ? GL_LINEAR : GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mode ? GL_LINEAR : GL_NEAREST);
|
|
}
|
|
}
|
|
|
|
/* Renderbuffer Object */
|
|
namespace RBO
|
|
{
|
|
DEF_GL_ID
|
|
|
|
inline ID gen()
|
|
{
|
|
ID id;
|
|
glGenRenderbuffersEXT(1, &id.gl);
|
|
|
|
return id;
|
|
}
|
|
|
|
inline void del(ID id)
|
|
{
|
|
glDeleteRenderbuffersEXT(1, &id.gl);
|
|
}
|
|
|
|
inline void bind(ID id)
|
|
{
|
|
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, id.gl);
|
|
}
|
|
|
|
inline void unbind()
|
|
{
|
|
bind(ID(0));
|
|
}
|
|
|
|
inline void allocEmpty(GLsizei width, GLsizei height)
|
|
{
|
|
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, width, height);
|
|
}
|
|
}
|
|
|
|
/* Framebuffer Object */
|
|
namespace FBO
|
|
{
|
|
DEF_GL_ID
|
|
|
|
enum Mode
|
|
{
|
|
Draw = 0,
|
|
Read = 1
|
|
};
|
|
|
|
enum BlitMode
|
|
{
|
|
Nearest = 0,
|
|
Linear = 1
|
|
};
|
|
|
|
inline ID gen()
|
|
{
|
|
ID id;
|
|
glGenFramebuffersEXT(1, &id.gl);
|
|
|
|
return id;
|
|
}
|
|
|
|
inline void del(ID id)
|
|
{
|
|
glDeleteFramebuffersEXT(1, &id.gl);
|
|
}
|
|
|
|
inline void bind(ID id, Mode mode)
|
|
{
|
|
static const GLenum modes[] =
|
|
{
|
|
GL_DRAW_FRAMEBUFFER_EXT,
|
|
GL_READ_FRAMEBUFFER_EXT
|
|
};
|
|
|
|
glBindFramebufferEXT(modes[mode], id.gl);
|
|
}
|
|
|
|
inline void unbind(Mode mode)
|
|
{
|
|
bind(ID(0), mode);
|
|
}
|
|
|
|
inline void setTarget(TEX::ID target, unsigned colorAttach = 0)
|
|
{
|
|
glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + colorAttach, GL_TEXTURE_2D, target.gl, 0);
|
|
}
|
|
|
|
inline void setTarget(RBO::ID target, unsigned colorAttach = 0)
|
|
{
|
|
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + colorAttach, GL_RENDERBUFFER, target.gl);
|
|
}
|
|
|
|
inline void blit(int srcX, int srcY,
|
|
int srcW, int srcH,
|
|
int dstX, int dstY,
|
|
int dstW, int dstH,
|
|
BlitMode mode = Nearest)
|
|
{
|
|
static const GLenum modes[] =
|
|
{
|
|
GL_NEAREST,
|
|
GL_LINEAR
|
|
};
|
|
|
|
glBlitFramebufferEXT(srcX, srcY, srcX+srcW, srcY+srcH,
|
|
dstX, dstY, dstX+dstW, dstY+dstH,
|
|
GL_COLOR_BUFFER_BIT, modes[mode]);
|
|
}
|
|
|
|
inline void blit(int srcX, int srcY,
|
|
int dstX, int dstY,
|
|
int srcW, int srcH,
|
|
BlitMode mode = Nearest)
|
|
{
|
|
blit(srcX, srcY, srcW, srcH, dstX, dstY, srcW, srcH, mode);
|
|
}
|
|
|
|
inline Vec4 getPixel(int x, int y)
|
|
{
|
|
Vec4 pixel;
|
|
|
|
glReadPixels(x, y, 1, 1, GL_RGBA, GL_FLOAT, &pixel.x);
|
|
|
|
return pixel;
|
|
}
|
|
|
|
inline void clear()
|
|
{
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
}
|
|
}
|
|
|
|
/* Vertex Array Object */
|
|
namespace VAO
|
|
{
|
|
DEF_GL_ID
|
|
|
|
inline ID gen()
|
|
{
|
|
ID id;
|
|
glGenVertexArrays(1, &id.gl);
|
|
|
|
return id;
|
|
}
|
|
|
|
inline void del(ID id)
|
|
{
|
|
glDeleteVertexArrays(1, &id.gl);
|
|
}
|
|
|
|
inline void bind(ID id)
|
|
{
|
|
glBindVertexArray(id.gl);
|
|
}
|
|
|
|
inline void unbind()
|
|
{
|
|
bind(ID(0));
|
|
}
|
|
}
|
|
|
|
template<GLenum target>
|
|
struct GenericBO
|
|
{
|
|
DEF_GL_ID
|
|
|
|
inline static ID gen()
|
|
{
|
|
ID id;
|
|
glGenBuffers(1, &id.gl);
|
|
|
|
return id;
|
|
}
|
|
|
|
inline static void del(ID id)
|
|
{
|
|
glDeleteBuffers(1, &id.gl);
|
|
}
|
|
|
|
inline static void bind(ID id)
|
|
{
|
|
glBindBuffer(target, id.gl);
|
|
}
|
|
|
|
inline static void unbind()
|
|
{
|
|
bind(ID(0));
|
|
}
|
|
|
|
inline static void uploadData(GLsizeiptr size, const GLvoid *data, GLenum usage = GL_STATIC_DRAW)
|
|
{
|
|
glBufferData(target, size, data, usage);
|
|
}
|
|
|
|
inline static void uploadSubData(GLintptr offset, GLsizeiptr size, const GLvoid *data)
|
|
{
|
|
glBufferSubData(target, offset, size, data);
|
|
}
|
|
|
|
inline static void allocEmpty(GLsizeiptr size, GLenum usage = GL_STATIC_DRAW)
|
|
{
|
|
uploadData(size, 0, usage);
|
|
}
|
|
};
|
|
|
|
/* Vertex Buffer Object */
|
|
typedef struct GenericBO<GL_ARRAY_BUFFER> VBO;
|
|
|
|
/* Index Buffer Object */
|
|
typedef struct GenericBO<GL_ELEMENT_ARRAY_BUFFER> IBO;
|
|
|
|
#undef DEF_GL_ID
|
|
|
|
namespace PixelStore
|
|
{
|
|
/* Setup a 'glSubTexImage2D()' call where the uploaded image
|
|
* itself is part of a bigger image in client memory */
|
|
inline void setupSubImage(GLint imgWidth, GLint subX, GLint subY)
|
|
{
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, imgWidth);
|
|
glPixelStorei(GL_UNPACK_SKIP_PIXELS, subX);
|
|
glPixelStorei(GL_UNPACK_SKIP_ROWS, subY);
|
|
}
|
|
|
|
/* Reset all states set with 'setupSubImage()' */
|
|
inline void reset()
|
|
{
|
|
setupSubImage(0, 0, 0);
|
|
}
|
|
}
|
|
|
|
/* Convenience struct wrapping a framebuffer
|
|
* and a 2D texture as its target */
|
|
struct TEXFBO
|
|
{
|
|
TEX::ID tex;
|
|
FBO::ID fbo;
|
|
int width, height;
|
|
|
|
TEXFBO()
|
|
: tex(0), fbo(0), width(0), height(0)
|
|
{}
|
|
|
|
bool operator==(const TEXFBO &other) const
|
|
{
|
|
return (tex == other.tex) && (fbo == other.fbo);
|
|
}
|
|
|
|
static inline void init(TEXFBO &obj)
|
|
{
|
|
obj.tex = TEX::gen();
|
|
obj.fbo = FBO::gen();
|
|
TEX::bind(obj.tex);
|
|
TEX::setRepeat(false);
|
|
TEX::setSmooth(false);
|
|
}
|
|
|
|
static inline void allocEmpty(TEXFBO &obj, int width, int height)
|
|
{
|
|
TEX::bind(obj.tex);
|
|
TEX::allocEmpty(width, height);
|
|
obj.width = width;
|
|
obj.height = height;
|
|
}
|
|
|
|
static inline void linkFBO(TEXFBO &obj)
|
|
{
|
|
FBO::bind(obj.fbo, FBO::Draw);
|
|
FBO::setTarget(obj.tex);
|
|
}
|
|
|
|
static inline void fini(TEXFBO &obj)
|
|
{
|
|
FBO::del(obj.fbo);
|
|
TEX::del(obj.tex);
|
|
}
|
|
};
|
|
|
|
/* Convenience struct wrapping a framebuffer
|
|
* and a renderbuffer as its target */
|
|
struct RBOFBO
|
|
{
|
|
RBO::ID rbo;
|
|
FBO::ID fbo;
|
|
int width, height;
|
|
|
|
RBOFBO()
|
|
: rbo(0), fbo(0), width(0), height(0)
|
|
{}
|
|
|
|
static inline void init(RBOFBO &obj)
|
|
{
|
|
obj.rbo = RBO::gen();
|
|
obj.fbo = FBO::gen();
|
|
}
|
|
|
|
static inline void allocEmpty(RBOFBO &obj, int width, int height)
|
|
{
|
|
RBO::bind(obj.rbo);
|
|
RBO::allocEmpty(width, height);
|
|
obj.width = width;
|
|
obj.height = height;
|
|
}
|
|
|
|
static inline void linkFBO(RBOFBO &obj)
|
|
{
|
|
FBO::bind(obj.fbo, FBO::Draw);
|
|
FBO::setTarget(obj.rbo);
|
|
}
|
|
|
|
static inline void fini(RBOFBO &obj)
|
|
{
|
|
FBO::del(obj.fbo);
|
|
RBO::del(obj.rbo);
|
|
}
|
|
};
|
|
|
|
#endif // GLUTIL_H
|