2013-09-01 14:27:21 +00:00
|
|
|
/*
|
|
|
|
** 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
|
|
|
|
|
2013-10-14 00:22:34 +00:00
|
|
|
#include "glew.h"
|
2013-09-01 14:27:21 +00:00
|
|
|
|
|
|
|
#include "etc-internal.h"
|
|
|
|
#include <QDebug>
|
|
|
|
|
|
|
|
/* 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; \
|
|
|
|
} \
|
|
|
|
};
|
|
|
|
|
2013-09-06 10:33:33 +00:00
|
|
|
/* 2D Texture */
|
2013-09-06 10:26:41 +00:00
|
|
|
namespace TEX
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-06 10:33:33 +00:00
|
|
|
/* Renderbuffer Object */
|
2013-09-06 10:16:24 +00:00
|
|
|
namespace RBO
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
|
|
|
DEF_GL_ID
|
|
|
|
|
|
|
|
inline ID gen()
|
|
|
|
{
|
|
|
|
ID id;
|
2013-09-07 00:41:37 +00:00
|
|
|
glGenRenderbuffersEXT(1, &id.gl);
|
2013-09-01 14:27:21 +00:00
|
|
|
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void del(ID id)
|
|
|
|
{
|
2013-09-07 00:41:37 +00:00
|
|
|
glDeleteRenderbuffersEXT(1, &id.gl);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void bind(ID id)
|
|
|
|
{
|
2013-09-07 00:41:37 +00:00
|
|
|
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, id.gl);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void unbind()
|
|
|
|
{
|
|
|
|
bind(ID(0));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void allocEmpty(GLsizei width, GLsizei height)
|
|
|
|
{
|
2013-09-07 00:41:37 +00:00
|
|
|
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, width, height);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-06 10:33:33 +00:00
|
|
|
/* Framebuffer Object */
|
2013-09-01 14:27:21 +00:00
|
|
|
namespace FBO
|
|
|
|
{
|
|
|
|
DEF_GL_ID
|
|
|
|
|
|
|
|
enum Mode
|
|
|
|
{
|
|
|
|
Draw = 0,
|
2013-09-06 12:56:30 +00:00
|
|
|
Read = 1
|
2013-09-01 14:27:21 +00:00
|
|
|
};
|
|
|
|
|
2013-09-23 09:00:50 +00:00
|
|
|
enum BlitMode
|
|
|
|
{
|
|
|
|
Nearest = 0,
|
|
|
|
Linear = 1
|
|
|
|
};
|
|
|
|
|
2013-09-01 14:27:21 +00:00
|
|
|
inline ID gen()
|
|
|
|
{
|
|
|
|
ID id;
|
2013-09-06 12:37:28 +00:00
|
|
|
glGenFramebuffersEXT(1, &id.gl);
|
2013-09-01 14:27:21 +00:00
|
|
|
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void del(ID id)
|
|
|
|
{
|
2013-09-06 12:37:28 +00:00
|
|
|
glDeleteFramebuffersEXT(1, &id.gl);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
2013-09-06 12:56:30 +00:00
|
|
|
inline void bind(ID id, Mode mode)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
|
|
|
static const GLenum modes[] =
|
|
|
|
{
|
2013-09-06 12:37:28 +00:00
|
|
|
GL_DRAW_FRAMEBUFFER_EXT,
|
2013-09-06 12:56:30 +00:00
|
|
|
GL_READ_FRAMEBUFFER_EXT
|
2013-09-01 14:27:21 +00:00
|
|
|
};
|
|
|
|
|
2013-09-06 12:37:28 +00:00
|
|
|
glBindFramebufferEXT(modes[mode], id.gl);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
2013-09-06 12:56:30 +00:00
|
|
|
inline void unbind(Mode mode)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
|
|
|
bind(ID(0), mode);
|
|
|
|
}
|
|
|
|
|
2013-09-06 10:26:41 +00:00
|
|
|
inline void setTarget(TEX::ID target, unsigned colorAttach = 0)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
2013-09-06 12:37:28 +00:00
|
|
|
glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + colorAttach, GL_TEXTURE_2D, target.gl, 0);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
2013-09-06 10:22:55 +00:00
|
|
|
inline void setTarget(RBO::ID target, unsigned colorAttach = 0)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
2013-09-06 12:37:28 +00:00
|
|
|
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + colorAttach, GL_RENDERBUFFER, target.gl);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void blit(int srcX, int srcY,
|
|
|
|
int srcW, int srcH,
|
|
|
|
int dstX, int dstY,
|
2013-09-23 09:00:50 +00:00
|
|
|
int dstW, int dstH,
|
|
|
|
BlitMode mode = Nearest)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
2013-09-23 09:00:50 +00:00
|
|
|
static const GLenum modes[] =
|
|
|
|
{
|
|
|
|
GL_NEAREST,
|
|
|
|
GL_LINEAR
|
|
|
|
};
|
|
|
|
|
2013-09-06 12:37:28 +00:00
|
|
|
glBlitFramebufferEXT(srcX, srcY, srcX+srcW, srcY+srcH,
|
|
|
|
dstX, dstY, dstX+dstW, dstY+dstH,
|
2013-09-23 09:00:50 +00:00
|
|
|
GL_COLOR_BUFFER_BIT, modes[mode]);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void blit(int srcX, int srcY,
|
|
|
|
int dstX, int dstY,
|
2013-09-23 09:00:50 +00:00
|
|
|
int srcW, int srcH,
|
|
|
|
BlitMode mode = Nearest)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
2013-09-23 09:00:50 +00:00
|
|
|
blit(srcX, srcY, srcW, srcH, dstX, dstY, srcW, srcH, mode);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
2013-09-23 05:15:01 +00:00
|
|
|
inline Vec4 getPixel(int x, int y)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
|
|
|
Vec4 pixel;
|
|
|
|
|
|
|
|
glReadPixels(x, y, 1, 1, GL_RGBA, GL_FLOAT, &pixel.x);
|
|
|
|
|
|
|
|
return pixel;
|
|
|
|
}
|
2013-10-01 11:10:14 +00:00
|
|
|
|
|
|
|
inline void clear()
|
|
|
|
{
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
}
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
2013-09-06 10:33:33 +00:00
|
|
|
/* Vertex Array Object */
|
2013-09-01 14:27:21 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-09-06 10:33:33 +00:00
|
|
|
/* Vertex Buffer Object */
|
2013-09-01 14:27:21 +00:00
|
|
|
typedef struct GenericBO<GL_ARRAY_BUFFER> VBO;
|
2013-09-06 10:33:33 +00:00
|
|
|
|
|
|
|
/* Index Buffer Object */
|
2013-09-01 14:27:21 +00:00
|
|
|
typedef struct GenericBO<GL_ELEMENT_ARRAY_BUFFER> IBO;
|
|
|
|
|
2013-09-06 11:14:34 +00:00
|
|
|
#undef DEF_GL_ID
|
|
|
|
|
2013-10-16 17:20:36 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-06 10:33:33 +00:00
|
|
|
/* Convenience struct wrapping a framebuffer
|
|
|
|
* and a 2D texture as its target */
|
2013-09-06 10:26:41 +00:00
|
|
|
struct TEXFBO
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
2013-09-06 10:26:41 +00:00
|
|
|
TEX::ID tex;
|
2013-09-01 14:27:21 +00:00
|
|
|
FBO::ID fbo;
|
|
|
|
int width, height;
|
|
|
|
|
2013-09-06 10:26:41 +00:00
|
|
|
TEXFBO()
|
2013-09-01 14:27:21 +00:00
|
|
|
: tex(0), fbo(0), width(0), height(0)
|
|
|
|
{}
|
|
|
|
|
2013-09-06 10:26:41 +00:00
|
|
|
bool operator==(const TEXFBO &other) const
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
|
|
|
return (tex == other.tex) && (fbo == other.fbo);
|
|
|
|
}
|
|
|
|
|
2013-09-06 10:26:41 +00:00
|
|
|
static inline void init(TEXFBO &obj)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
2013-09-06 10:26:41 +00:00
|
|
|
obj.tex = TEX::gen();
|
2013-09-01 14:27:21 +00:00
|
|
|
obj.fbo = FBO::gen();
|
2013-09-06 10:26:41 +00:00
|
|
|
TEX::bind(obj.tex);
|
|
|
|
TEX::setRepeat(false);
|
|
|
|
TEX::setSmooth(false);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
2013-09-06 10:26:41 +00:00
|
|
|
static inline void allocEmpty(TEXFBO &obj, int width, int height)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
2013-09-06 10:26:41 +00:00
|
|
|
TEX::bind(obj.tex);
|
|
|
|
TEX::allocEmpty(width, height);
|
2013-09-01 14:27:21 +00:00
|
|
|
obj.width = width;
|
|
|
|
obj.height = height;
|
|
|
|
}
|
|
|
|
|
2013-09-06 10:26:41 +00:00
|
|
|
static inline void linkFBO(TEXFBO &obj)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
2013-09-06 12:56:30 +00:00
|
|
|
FBO::bind(obj.fbo, FBO::Draw);
|
2013-09-06 10:22:55 +00:00
|
|
|
FBO::setTarget(obj.tex);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
2013-09-06 10:26:41 +00:00
|
|
|
static inline void fini(TEXFBO &obj)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
|
|
|
FBO::del(obj.fbo);
|
2013-09-06 10:26:41 +00:00
|
|
|
TEX::del(obj.tex);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-09-06 10:33:33 +00:00
|
|
|
/* Convenience struct wrapping a framebuffer
|
|
|
|
* and a renderbuffer as its target */
|
2013-09-06 10:16:24 +00:00
|
|
|
struct RBOFBO
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
2013-09-06 10:16:24 +00:00
|
|
|
RBO::ID rbo;
|
2013-09-01 14:27:21 +00:00
|
|
|
FBO::ID fbo;
|
|
|
|
int width, height;
|
|
|
|
|
2013-09-06 10:16:24 +00:00
|
|
|
RBOFBO()
|
|
|
|
: rbo(0), fbo(0), width(0), height(0)
|
2013-09-01 14:27:21 +00:00
|
|
|
{}
|
|
|
|
|
2013-09-06 10:16:24 +00:00
|
|
|
static inline void init(RBOFBO &obj)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
2013-09-06 10:16:24 +00:00
|
|
|
obj.rbo = RBO::gen();
|
2013-09-01 14:27:21 +00:00
|
|
|
obj.fbo = FBO::gen();
|
|
|
|
}
|
|
|
|
|
2013-09-06 10:16:24 +00:00
|
|
|
static inline void allocEmpty(RBOFBO &obj, int width, int height)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
2013-09-06 10:16:24 +00:00
|
|
|
RBO::bind(obj.rbo);
|
|
|
|
RBO::allocEmpty(width, height);
|
2013-09-01 14:27:21 +00:00
|
|
|
obj.width = width;
|
|
|
|
obj.height = height;
|
|
|
|
}
|
|
|
|
|
2013-09-06 10:16:24 +00:00
|
|
|
static inline void linkFBO(RBOFBO &obj)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
2013-09-06 12:56:30 +00:00
|
|
|
FBO::bind(obj.fbo, FBO::Draw);
|
2013-09-06 10:22:55 +00:00
|
|
|
FBO::setTarget(obj.rbo);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
|
2013-09-06 10:16:24 +00:00
|
|
|
static inline void fini(RBOFBO &obj)
|
2013-09-01 14:27:21 +00:00
|
|
|
{
|
|
|
|
FBO::del(obj.fbo);
|
2013-09-06 10:16:24 +00:00
|
|
|
RBO::del(obj.rbo);
|
2013-09-01 14:27:21 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif // GLUTIL_H
|