hyperrogue/renderbuffer.cpp

271 lines
7.3 KiB
C++
Raw Normal View History

// Hyperbolic Rogue -- drawing screens to buffers
// Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
/** \file renderbuffer.cpp
* \brief drawing screens to buffers
*
* This file implements the 'renderbuffer', which is an object
* that can be used to draw a HyperRogue screen into,
* and then either used as a OpenGL texture (e.g. in the Hypersian Rug mode), or saved.
*/
#include "hyper.h"
namespace hr {
#if CAP_GL
2018-02-01 12:43:48 +00:00
#if !CAP_GLEW
#if ISLINUX
extern "C" {
GLAPI void APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers);
GLAPI void APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer);
GLAPI void APIENTRY glFramebufferTexture (GLenum target, GLenum attachment, GLuint texture, GLint level);
GLAPI GLenum APIENTRY glCheckFramebufferStatus (GLenum target);
GLAPI void APIENTRY glDrawBuffers (GLsizei n, const GLenum *bufs);
GLAPI void APIENTRY glGenRenderbuffers (GLsizei n, GLuint *renderbuffers);
GLAPI void APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer);
GLAPI void APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
GLAPI void APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
GLAPI void APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers);
GLAPI void APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers);
}
#endif
#if ISMAC
#define glFramebufferTexture glFramebufferTextureEXT
#endif
#endif
#endif
2018-02-01 12:43:48 +00:00
2019-08-09 20:07:03 +00:00
#if HDR
struct renderbuffer {
bool valid;
int x, y;
#if CAP_GL
int tx, ty;
GLuint FramebufferName;
GLuint renderedTexture;
GLuint depth_stencil_rb;
Uint32 *expanded_data;
void use_as_texture();
#endif
#if CAP_SDL
SDL_Surface *srf;
void make_surface();
SDL_Surface *render();
#endif
renderbuffer(int x, int y, bool gl);
~renderbuffer();
void enable();
void clear(color_t col);
};
struct resetbuffer {
GLint drawFboId, readFboId;
2020-04-06 06:37:22 +00:00
#if CAP_SDL
2019-08-09 20:07:03 +00:00
SDL_Surface *sreset;
2020-04-06 06:37:22 +00:00
#endif
2019-08-09 20:07:03 +00:00
resetbuffer();
void reset();
};
#endif
2018-02-01 12:43:48 +00:00
renderbuffer::renderbuffer(int x, int y, bool gl) : x(x), y(y) {
valid = false;
#if CAP_GL
FramebufferName = renderedTexture = depth_stencil_rb = 0; expanded_data = NULL;
#endif
#if CAP_SDL
srf = NULL;
#endif
2018-02-01 12:43:48 +00:00
2022-04-25 22:36:27 +00:00
tx = next_p2(x);
ty = next_p2(y);
# if CAP_GL
2018-02-01 12:43:48 +00:00
if(gl) {
2020-10-15 14:39:05 +00:00
GLERR("renderbuffer init");
2018-02-11 01:19:49 +00:00
resetbuffer rb;
2020-10-15 14:39:05 +00:00
GLERR("after resetbuffer");
2018-02-01 12:43:48 +00:00
FramebufferName = renderedTexture = depth_stencil_rb = 0;
2018-02-11 01:19:49 +00:00
GLERR("even before");
glGenFramebuffers(1, &FramebufferName); //
2018-02-11 01:19:49 +00:00
GLERR("GenFramebuffer");
2018-02-01 12:43:48 +00:00
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
2018-02-11 01:19:49 +00:00
GLERR("BindFramebuffer");
2018-02-01 12:43:48 +00:00
glGenTextures(1, &renderedTexture);
glBindTexture(GL_TEXTURE_2D, renderedTexture);
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, tx, ty, 0,GL_RGB, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2018-02-11 01:19:49 +00:00
GLERR("GenTextures");
2018-02-01 12:43:48 +00:00
#ifdef TEX
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexture, 0);
#else
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderedTexture, 0);
#endif
2018-02-11 01:19:49 +00:00
GLERR("FramebufferTexture");
// GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
// glDrawBuffers(1, DrawBuffers);
2018-02-01 12:43:48 +00:00
glGenRenderbuffers(1, &depth_stencil_rb);
2018-02-11 01:19:49 +00:00
GLERR("GenRenderbuffer");
2018-02-01 12:43:48 +00:00
glBindRenderbuffer(GL_RENDERBUFFER, depth_stencil_rb);
2018-02-11 01:19:49 +00:00
GLERR("BindRenderbuffer");
2018-02-01 12:43:48 +00:00
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, tx, ty);
2018-02-11 18:08:17 +00:00
bool has_depth = true;
if(glGetError() != GL_NO_ERROR) {
2020-10-15 14:39:05 +00:00
println(hlog, "Could not create: GL_DEPTH24_STENCIL8");
2018-02-11 18:08:17 +00:00
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, tx, ty);
has_depth = false;
}
2018-02-11 01:19:49 +00:00
GLERR("RbS");
2018-02-11 18:08:17 +00:00
if(has_depth)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_stencil_rb);
2018-02-01 12:43:48 +00:00
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depth_stencil_rb);
2018-02-11 01:19:49 +00:00
GLERR("FrRb");
2018-02-01 12:43:48 +00:00
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
FramebufferName = renderedTexture = 0;
else
valid = true;
2018-02-11 01:19:49 +00:00
2019-05-12 23:57:40 +00:00
DEBB(DF_GRAPH, ("Framebuffer remains = ", int(FramebufferName), " (", int(valid), ")"));
2018-02-04 00:04:29 +00:00
GLERR("initialization");
2018-02-11 01:19:49 +00:00
rb.reset();
2018-02-01 12:43:48 +00:00
}
#endif
#if CAP_SDL
if(!valid)
2018-02-01 12:43:48 +00:00
make_surface();
#endif
2018-02-01 12:43:48 +00:00
}
#if CAP_SDL
2018-02-01 12:43:48 +00:00
void renderbuffer::make_surface() {
if(!srf)
srf = SDL_CreateRGBSurface(SDL_SWSURFACE, x, y, 32,0xff0000,0xff00,0xff,0xff000000);
}
SDL_Surface *renderbuffer::render() {
make_surface() ;
if(FramebufferName) {
2018-02-27 18:21:31 +00:00
glReadPixels(0, 0, x, y, GL_BGRA, GL_UNSIGNED_BYTE, srf->pixels);
2018-02-11 01:19:49 +00:00
GLERR("readPixels");
2018-02-27 18:21:31 +00:00
for(int iy=0; iy<y/2; iy++)
for(int ix=0; ix<x; ix++)
swap(qpixel(srf,ix,iy), qpixel(srf,ix,y-1-iy));
}
return srf;
}
#endif
2019-08-09 19:00:52 +00:00
EX int current_rbuffer = -1;
2019-04-23 13:03:17 +00:00
2018-02-01 12:43:48 +00:00
void renderbuffer::enable() {
#if CAP_GL
2018-02-01 12:43:48 +00:00
if(FramebufferName) {
2018-02-11 01:19:49 +00:00
GLERR("prebind");
2018-02-01 12:43:48 +00:00
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
2019-04-23 13:03:17 +00:00
current_rbuffer = FramebufferName;
2018-02-11 01:19:49 +00:00
GLERR("bind");
2018-02-01 12:43:48 +00:00
vid.usingGL = true;
return;
2018-02-01 12:43:48 +00:00
}
#endif
#if CAP_SDL
make_surface();
s = srf;
vid.usingGL = false;
#endif
2018-02-01 12:43:48 +00:00
}
#if CAP_GL
2018-02-01 12:43:48 +00:00
void renderbuffer::use_as_texture() {
if(!renderedTexture) {
glGenTextures( 1, &renderedTexture);
glBindTexture( GL_TEXTURE_2D, renderedTexture);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
}
if(FramebufferName) {
glBindTexture( GL_TEXTURE_2D, renderedTexture);
}
#if CAP_SDL
2018-02-01 12:43:48 +00:00
else {
if(!expanded_data)
expanded_data = new Uint32[tx * ty];
for(int y=0; y<ty; y++) for(int x=0; x<tx; x++)
expanded_data[y*tx + x] = qpixel(srf, x, ty-1-y) | 0xFF000000;
glBindTexture( GL_TEXTURE_2D, renderedTexture);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, tx, ty, 0, GL_BGRA, GL_UNSIGNED_BYTE, expanded_data );
}
#endif
2018-02-01 12:43:48 +00:00
}
#endif
2018-02-01 12:43:48 +00:00
renderbuffer::~renderbuffer() {
#if CAP_GL
2018-02-01 12:43:48 +00:00
if(renderedTexture)
glDeleteTextures(1, &renderedTexture);
if(FramebufferName) {
glDeleteRenderbuffers(1, &depth_stencil_rb);
glDeleteFramebuffers(1, &FramebufferName);
}
if(expanded_data)
delete[] expanded_data;
#endif
#if CAP_SDL
if(srf)
SDL_FreeSurface(srf);
#endif
2018-02-01 12:43:48 +00:00
}
void renderbuffer::clear(color_t col) {
#if CAP_GL
if(FramebufferName) {
setGLProjection(col);
return;
}
#endif
#if CAP_SDL
SDL_FillRect(srf, NULL, col);
#endif
2018-02-01 12:43:48 +00:00
}
2018-02-11 01:19:49 +00:00
resetbuffer::resetbuffer() {
#if CAP_GL
drawFboId = 0, readFboId = 0;
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &drawFboId);
2020-10-15 14:39:05 +00:00
GLERR("getInteger a");
2020-12-24 21:58:55 +00:00
#ifndef GLES_ONLY
2018-02-11 01:19:49 +00:00
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &readFboId);
2020-10-15 14:39:05 +00:00
GLERR("getInteger b");
2018-02-11 01:19:49 +00:00
#endif
2020-12-24 21:58:55 +00:00
#endif
2018-02-11 01:19:49 +00:00
#if CAP_SDL
sreset = s;
#endif
}
void resetbuffer::reset() {
#if CAP_GL
glBindFramebuffer(GL_FRAMEBUFFER, drawFboId);
2019-04-23 13:03:17 +00:00
current_rbuffer = drawFboId;
2018-02-11 01:19:49 +00:00
#endif
#if CAP_SDL
s = sreset;
#endif
}
}