mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-13 03:09:57 +01:00
FrameBuffer creation flags replace booleans
Instead of many creation options (with alpha, with multisampling, etc) use a single flag with boolean operators. Creation of the new mipmap flag for FrameBuffer, rendering the current FBO into multiple sub-resolutions.
This commit is contained in:
150
FrameBuffer.cpp
150
FrameBuffer.cpp
@@ -75,22 +75,24 @@ glm::ivec2 FrameBuffer::getParametersFromResolution(glm::vec3 res)
|
||||
return p;
|
||||
}
|
||||
|
||||
FrameBuffer::FrameBuffer(glm::vec3 resolution, bool useAlpha, bool multiSampling):
|
||||
textureid_(0), intermediate_textureid_(0), framebufferid_(0), intermediate_framebufferid_(0),
|
||||
use_alpha_(useAlpha), use_multi_sampling_(multiSampling)
|
||||
FrameBuffer::FrameBuffer(glm::vec3 resolution, FrameBufferFlags flags): flags_(flags),
|
||||
textureid_(0), multisampling_textureid_(0), framebufferid_(0), multisampling_framebufferid_(0)
|
||||
{
|
||||
attrib_.viewport = glm::ivec2(resolution);
|
||||
setProjectionArea(glm::vec2(1.f, 1.f));
|
||||
attrib_.clear_color = glm::vec4(0.f, 0.f, 0.f, 0.f);
|
||||
for(int i=0; i<MIPMAP_LEVEL; ++i)
|
||||
mipmap_framebufferid_[MIPMAP_LEVEL] = 0;
|
||||
}
|
||||
|
||||
FrameBuffer::FrameBuffer(uint width, uint height, bool useAlpha, bool multiSampling):
|
||||
textureid_(0), intermediate_textureid_(0), framebufferid_(0), intermediate_framebufferid_(0),
|
||||
use_alpha_(useAlpha), use_multi_sampling_(multiSampling)
|
||||
FrameBuffer::FrameBuffer(uint width, uint height, FrameBufferFlags flags): flags_(flags),
|
||||
textureid_(0), multisampling_textureid_(0), framebufferid_(0), multisampling_framebufferid_(0)
|
||||
{
|
||||
attrib_.viewport = glm::ivec2(width, height);
|
||||
setProjectionArea(glm::vec2(1.f, 1.f));
|
||||
attrib_.clear_color = glm::vec4(0.f, 0.f, 0.f, 0.f);
|
||||
for(int i=0; i<MIPMAP_LEVEL; ++i)
|
||||
mipmap_framebufferid_[MIPMAP_LEVEL] = 0;
|
||||
}
|
||||
|
||||
void FrameBuffer::init()
|
||||
@@ -98,27 +100,40 @@ void FrameBuffer::init()
|
||||
// generate texture
|
||||
glGenTextures(1, &textureid_);
|
||||
glBindTexture(GL_TEXTURE_2D, textureid_);
|
||||
glTexStorage2D(GL_TEXTURE_2D, 1, use_alpha_ ? GL_RGBA8 : GL_RGB8, attrib_.viewport.x, attrib_.viewport.y);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
||||
if (flags_ & FrameBuffer_mipmap) {
|
||||
glTexStorage2D(GL_TEXTURE_2D, MIPMAP_LEVEL + 1, (flags_ & FrameBuffer_alpha) ? GL_RGBA8 : GL_RGB8, attrib_.viewport.x, attrib_.viewport.y);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
}
|
||||
else {
|
||||
glTexStorage2D(GL_TEXTURE_2D, 1, (flags_ & FrameBuffer_alpha) ? GL_RGBA8 : GL_RGB8, attrib_.viewport.x, attrib_.viewport.y);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
}
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
// create a framebuffer object
|
||||
glGenFramebuffers(1, &framebufferid_);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebufferid_);
|
||||
|
||||
// take settings into account: no multisampling for level 0
|
||||
use_multi_sampling_ &= Settings::application.render.multisampling > 0;
|
||||
#ifdef FRAMEBUFFER_DEBUG
|
||||
g_printerr("New FBO %d (%d x %d)\n", framebufferid_, attrib_.viewport.x, attrib_.viewport.y);
|
||||
#endif
|
||||
|
||||
if (use_multi_sampling_){
|
||||
// take settings into account: no multisampling if application multisampling is level 0
|
||||
if ( Settings::application.render.multisampling < 1 )
|
||||
flags_ &= ~FrameBuffer_multisampling;
|
||||
|
||||
if (flags_ & FrameBuffer_multisampling){
|
||||
|
||||
// create a multisample texture
|
||||
glGenTextures(1, &intermediate_textureid_);
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, intermediate_textureid_);
|
||||
glGenTextures(1, &multisampling_textureid_);
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, multisampling_textureid_);
|
||||
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, Settings::application.render.multisampling,
|
||||
use_alpha_ ? GL_RGBA8 : GL_RGB8, attrib_.viewport.x, attrib_.viewport.y, GL_TRUE);
|
||||
(flags_ & FrameBuffer_alpha) ? GL_RGBA8 : GL_RGB8, attrib_.viewport.x, attrib_.viewport.y, GL_TRUE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
@@ -126,28 +141,34 @@ void FrameBuffer::init()
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
|
||||
|
||||
// attach the multisampled texture to FBO (framebufferid_ currently binded)
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, intermediate_textureid_, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, multisampling_textureid_, 0);
|
||||
|
||||
// create an intermediate FBO : this is the FBO to use for reading
|
||||
glGenFramebuffers(1, &intermediate_framebufferid_);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, intermediate_framebufferid_);
|
||||
|
||||
// attach the 2D texture to intermediate FBO (intermediate_framebufferid_)
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureid_, 0);
|
||||
glGenFramebuffers(1, &multisampling_framebufferid_);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, multisampling_framebufferid_);
|
||||
|
||||
#ifdef FRAMEBUFFER_DEBUG
|
||||
g_printerr("New FBO %d Multi Sampling\n", framebufferid_);
|
||||
g_printerr(" - with Multi Sampling (%d) \n", Settings::application.render.multisampling);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
|
||||
// direct attach the 2D texture to FBO
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureid_, 0);
|
||||
// attach the 2D texture to latest binded FBO
|
||||
// (i.e. the multisampling_framebufferid_ FBO if enabled, default framebufferid_ otherwise)
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureid_, 0);
|
||||
|
||||
if (flags_ & FrameBuffer_mipmap) {
|
||||
|
||||
glGenFramebuffers(MIPMAP_LEVEL, mipmap_framebufferid_);
|
||||
for(int i=0; i < MIPMAP_LEVEL; ++i) {
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mipmap_framebufferid_[i]);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureid_, i + 1);
|
||||
|
||||
}
|
||||
|
||||
#ifdef FRAMEBUFFER_DEBUG
|
||||
g_printerr("New FBO %d Single Sampling\n", framebufferid_);
|
||||
g_printerr(" - with Mipmap (%d)\n", MIPMAP_LEVEL);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
checkFramebufferStatus();
|
||||
@@ -159,15 +180,17 @@ FrameBuffer::~FrameBuffer()
|
||||
{
|
||||
if (framebufferid_)
|
||||
glDeleteFramebuffers(1, &framebufferid_);
|
||||
if (intermediate_framebufferid_)
|
||||
glDeleteFramebuffers(1, &intermediate_framebufferid_);
|
||||
if (multisampling_framebufferid_)
|
||||
glDeleteFramebuffers(1, &multisampling_framebufferid_);
|
||||
if (mipmap_framebufferid_[0])
|
||||
glDeleteFramebuffers(MIPMAP_LEVEL, mipmap_framebufferid_);
|
||||
if (textureid_)
|
||||
glDeleteTextures(1, &textureid_);
|
||||
if (intermediate_textureid_)
|
||||
glDeleteTextures(1, &intermediate_textureid_);
|
||||
if (multisampling_textureid_)
|
||||
glDeleteTextures(1, &multisampling_textureid_);
|
||||
|
||||
#ifdef FRAMEBUFFER_DEBUG
|
||||
GLint framebufferMemoryInKB = ( width() * height() * (use_alpha_?4:3) ) / 1024;
|
||||
GLint framebufferMemoryInKB = ( width() * height() * (flags_ & FrameBuffer_alpha?4:3) ) / 1024;
|
||||
g_printerr("Framebuffer deleted %d x %d, ~%d kB freed\n", width(), height(), framebufferMemoryInKB);
|
||||
#endif
|
||||
}
|
||||
@@ -213,15 +236,22 @@ void FrameBuffer::resize(int width, int height)
|
||||
glDeleteFramebuffers(1, &framebufferid_);
|
||||
framebufferid_ = 0;
|
||||
|
||||
if (intermediate_framebufferid_)
|
||||
glDeleteFramebuffers(1, &intermediate_framebufferid_);
|
||||
intermediate_framebufferid_ = 0;
|
||||
if (multisampling_framebufferid_)
|
||||
glDeleteFramebuffers(1, &multisampling_framebufferid_);
|
||||
multisampling_framebufferid_ = 0;
|
||||
|
||||
if (mipmap_framebufferid_[0])
|
||||
glDeleteFramebuffers(MIPMAP_LEVEL, mipmap_framebufferid_);
|
||||
for(int i=0; i<MIPMAP_LEVEL; ++i)
|
||||
mipmap_framebufferid_[MIPMAP_LEVEL] = 0;
|
||||
|
||||
if (textureid_)
|
||||
glDeleteTextures(1, &textureid_);
|
||||
textureid_ = 0;
|
||||
if (intermediate_textureid_)
|
||||
glDeleteTextures(1, &intermediate_textureid_);
|
||||
intermediate_textureid_ = 0;
|
||||
|
||||
if (multisampling_textureid_)
|
||||
glDeleteTextures(1, &multisampling_textureid_);
|
||||
multisampling_textureid_ = 0;
|
||||
|
||||
// change resolution
|
||||
attrib_.viewport = glm::ivec2(width, height);
|
||||
@@ -245,15 +275,35 @@ void FrameBuffer::begin(bool clear)
|
||||
void FrameBuffer::end()
|
||||
{
|
||||
// if multisampling frame buffer
|
||||
if (use_multi_sampling_) {
|
||||
if (flags_ & FrameBuffer_multisampling) {
|
||||
// blit the multisample FBO into unisample FBO to generate 2D texture
|
||||
// Doing this blit will automatically resolve the multisampled FBO.
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebufferid_);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediate_framebufferid_);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, multisampling_framebufferid_);
|
||||
glBlitFramebuffer(0, 0, attrib_.viewport.x, attrib_.viewport.y,
|
||||
0, 0, attrib_.viewport.x, attrib_.viewport.y, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
}
|
||||
|
||||
// if mipmapped texture, fill FBOs
|
||||
if (flags_ & FrameBuffer_mipmap) {
|
||||
// First read full-size framebuffer
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebufferid_);
|
||||
int width = attrib_.viewport.x;
|
||||
int height = attrib_.viewport.y;
|
||||
// iterate over all levels of mipmaps
|
||||
for(int i=0; i < MIPMAP_LEVEL; ++i) {
|
||||
// draw on Mipmap level i
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mipmap_framebufferid_[i]);
|
||||
// blit into half-sized mipmap i (with linear nearest color)
|
||||
glBlitFramebuffer(0, 0, width, height,
|
||||
0, 0, width / 2, height / 2, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
// next iteration (i+1), read half-size mipmap level i
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, mipmap_framebufferid_[i]);
|
||||
width = MAX(1, (width / 2));
|
||||
height = MAX(1, (height / 2));
|
||||
}
|
||||
}
|
||||
|
||||
FrameBuffer::release();
|
||||
|
||||
Rendering::manager().popAttrib();
|
||||
@@ -273,23 +323,23 @@ void FrameBuffer::readPixels(uint8_t *target_data)
|
||||
return;
|
||||
}
|
||||
|
||||
if (use_multi_sampling_)
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, intermediate_framebufferid_);
|
||||
if (flags_ & FrameBuffer_multisampling)
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, multisampling_framebufferid_);
|
||||
else
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebufferid_);
|
||||
|
||||
if (use_alpha())
|
||||
if (flags_ & FrameBuffer_alpha)
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 4);
|
||||
else
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
|
||||
glReadPixels(0, 0, attrib_.viewport.x, attrib_.viewport.y, (use_alpha_? GL_RGBA : GL_RGB), GL_UNSIGNED_BYTE, target_data);
|
||||
glReadPixels(0, 0, attrib_.viewport.x, attrib_.viewport.y, ((flags_ & FrameBuffer_alpha)? GL_RGBA : GL_RGB), GL_UNSIGNED_BYTE, target_data);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
bool FrameBuffer::blit(FrameBuffer *destination)
|
||||
{
|
||||
if (!framebufferid_ || !destination || (use_alpha_ != destination->use_alpha_) ){
|
||||
if (!framebufferid_ || !destination || (flags_ & FrameBuffer_alpha) != (destination->flags_ & FrameBuffer_alpha) ){
|
||||
#ifdef FRAMEBUFFER_DEBUG
|
||||
g_printerr("FrameBuffer blit failed\n");
|
||||
#endif
|
||||
@@ -299,8 +349,8 @@ bool FrameBuffer::blit(FrameBuffer *destination)
|
||||
if (!destination->framebufferid_)
|
||||
destination->init();
|
||||
|
||||
if (use_multi_sampling_)
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, intermediate_framebufferid_);
|
||||
if (flags_ & FrameBuffer_multisampling)
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, multisampling_framebufferid_);
|
||||
else
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebufferid_);
|
||||
|
||||
@@ -310,6 +360,8 @@ bool FrameBuffer::blit(FrameBuffer *destination)
|
||||
0, 0, destination->width(), destination->height(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
// TODO : verify blit onto FBO with mipmapping ?
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -353,7 +405,7 @@ void FrameBuffer::checkFramebufferStatus()
|
||||
{
|
||||
|
||||
// approximation of RAM needed for this FBO
|
||||
GLint framebufferMemoryInKB = ( width() * height() * (use_alpha_?4:3) * (use_multi_sampling_?2:1) ) / 1024;
|
||||
GLint framebufferMemoryInKB = ( width() * height() * (flags_ & FrameBuffer_alpha?4:3) * (flags_ & FrameBuffer_multisampling?2:1) ) / 1024;
|
||||
|
||||
// test available memory if created buffer is big (more than 8MB)
|
||||
if ( framebufferMemoryInKB > 8000 ) {
|
||||
@@ -463,7 +515,7 @@ FrameBufferImage *FrameBuffer::image(){
|
||||
return img;
|
||||
|
||||
// only compatible for RGB FrameBuffers
|
||||
if (use_alpha_ || use_multi_sampling_)
|
||||
if (flags_ & FrameBuffer_alpha || flags_ & FrameBuffer_multisampling)
|
||||
return img;
|
||||
|
||||
// allocate image
|
||||
@@ -482,7 +534,7 @@ bool FrameBuffer::fill(FrameBufferImage *image)
|
||||
init();
|
||||
|
||||
// only compatible for RGB FrameBuffers
|
||||
if (use_alpha_ || use_multi_sampling_)
|
||||
if (flags_ & FrameBuffer_alpha || flags_ & FrameBuffer_multisampling)
|
||||
return false;
|
||||
|
||||
// invalid image
|
||||
|
||||
Reference in New Issue
Block a user