mitsuba/src/libhw/gltexture.cpp

661 lines
20 KiB
C++

/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2011 by Wenzel Jakob and others.
Mitsuba is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Mitsuba 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mitsuba/mitsuba.h>
#if defined(__OSX__)
#include <OpenGL/glew.h>
#else
#include <GL/glew.h>
#endif
#include <mitsuba/hw/gltexture.h>
#ifndef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT
#define GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT 0x8CD8
#endif
MTS_NAMESPACE_BEGIN
GLTexture::GLTexture(const std::string &name, Bitmap *bitmap)
: GPUTexture(name, bitmap), m_id(0), m_needsUpdate(true) {
}
void GLTexture::init() {
if (m_fbType == ENone)
Log(ETrace, "Uploading a texture : %s", toString().c_str());
else
Log(ETrace, "Creating a framebuffer : %s", toString().c_str());
lookupGLConstants();
/* Generate an identifier */
glGenTextures(1, &m_id);
/* Bind to the texture */
glBindTexture(m_glType, m_id);
/* Set the texture filtering / wrapping modes
(don't do this for multisample textures)*/
if (!((m_fbType & EColorBuffer) && m_samples > 1))
configureTexture(); /* Multisample textures don't have parameters */
if (m_samples > 1) {
int samples;
glGetIntegerv(GL_MAX_SAMPLES_EXT, &samples);
if (m_samples > samples) {
Log(EWarn, "Attempted to create a multisample framebuffer "
"with an unsupported # of samples (requested=%i, supported=%i)",
m_samples, samples);
m_samples = samples;
}
}
if (m_fbType == ENone) {
Assert(m_samples == 1);
refresh();
} else {
/* Create the FBO and bind it */
glGenFramebuffersEXT(1, &m_fboId);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboId);
AssertEx(glIsFramebufferEXT(m_fboId), "Creating an FBO failed");
bool depthAsTexture = m_fbType & EDepthBuffer;
switch (m_fbType) {
case EColorAndDepthBuffer:
case EColorBuffer: {
if (m_type == ETexture2D) {
if (!depthAsTexture) {
glGenRenderbuffersEXT(1, &m_depthId);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthId);
if (m_samples == 1)
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
GL_DEPTH_COMPONENT, m_size.x, m_size.y);
else
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT,
m_samples, GL_DEPTH_COMPONENT, m_size.x, m_size.y);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthId);
} else {
glGenTextures(1, &m_depthId);
glBindTexture(m_glType, m_depthId);
configureTexture();
glTexParameteri(m_glType, GL_TEXTURE_COMPARE_MODE, GL_NONE);
glTexParameteri(m_glType, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
if (m_samples == 1)
glTexImage2D(m_glType, 0, GL_DEPTH_COMPONENT24, m_size.x, m_size.y,
0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
else
glTexImage2DMultisample(m_glType,
m_samples, GL_DEPTH_COMPONENT24, m_size.x, m_size.y, GL_FALSE);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
GL_DEPTH_ATTACHMENT, m_glType, m_depthId, 0);
glBindTexture(m_glType, m_id);
}
if (m_samples == 1)
glTexImage2D(m_glType, 0, m_internalFormat, m_size.x, m_size.y,
0, m_format, m_dataFormat, NULL);
else
glTexImage2DMultisample(m_glType,
m_samples, m_internalFormat, m_size.x, m_size.y, GL_FALSE);
if (isMipMapped())
glGenerateMipmapEXT(m_glType);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
GL_COLOR_ATTACHMENT0_EXT, m_glType, m_id, 0);
} else if (m_type == ETextureCubeMap) {
Assert(m_size.x == m_size.y && isPow2(m_size.x));
Assert(m_fbType == EColorBuffer);
Assert(m_samples == 1);
for (int i=0; i<6; i++)
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, m_internalFormat,
m_size.x, m_size.y, 0, m_format, m_dataFormat, NULL);
if (isMipMapped())
glGenerateMipmapEXT(m_glType);
/* Generate an identifier */
glGenTextures(1, &m_depthId);
glBindTexture(m_glType, m_depthId);
glTexParameteri(m_glType, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(m_glType, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
for (int i=0; i<6; i++)
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT24,
m_size.x, m_size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
if (glewIsSupported("GL_EXT_geometry_shader4"))
activateSide(-1);
else
activateSide(0);
} else {
Log(EError, "Unsupported texture type!");
}
}
break;
case EDepthBuffer:
Assert(m_samples == 1);
if (m_depthMode == ECompare) {
glTexParameteri(m_glType, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(m_glType, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
}
if (m_type == ETexture2D) {
/* Allocate the texture memory */
glTexImage2D(m_glType, 0, m_internalFormat,
m_size.x, m_size.y, 0, GL_DEPTH_COMPONENT,
GL_UNSIGNED_BYTE, NULL);
/* Attach the texture as a depth target */
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
GL_DEPTH_ATTACHMENT_EXT, m_glType, m_id, 0);
} else if (m_type == ETextureCubeMap) {
Assert(m_size.x == m_size.y && isPow2(m_size.x));
for (int i=0; i<6; i++)
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, m_internalFormat,
m_size.x, m_size.y, 0, m_format, m_dataFormat, NULL);
if (glewIsSupported("GL_EXT_geometry_shader4"))
activateSide(-1);
else
activateSide(0);
} else {
Log(EError, "Unsupported texture type!");
}
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
break;
default:
Log(EError, "Invalid render buffer type!");
}
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
switch (status) {
case GL_FRAMEBUFFER_COMPLETE_EXT:
break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
Log(EError, "FBO Error: Incomplete attachment!");
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
Log(EError, "FBO Error: Unsupported framebuffer format!");
case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT:
Log(EError, "FBO Error: Incomplete framebuffer - duplicate attachment!");
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
Log(EError, "FBO Error: Incomplete framebuffer - missing attachment!");
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
Log(EError, "FBO Error: Incomplete framebuffer - invalid dimensions!");
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
Log(EError, "FBO Error: Incomplete framebuffer - no draw buffer!");
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
Log(EError, "FBO Error: Incomplete framebuffer - invalid formats!");
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
Log(EError, "FBO Error: Incomplete framebuffer - no readbuffer!");
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT:
Log(EError, "FBO Error: Incomplete multisample framebuffer!");
case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS:
Log(EError, "FBO Error: Incomplete layer targets!");
default:
Log(EError, "FBO Error: Unknown error status (0x%x)!", status);
}
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, GL_NONE);
}
}
void GLTexture::refresh() {
Bitmap *bitmap = getBitmap();
/* Bind to the texture */
glBindTexture(m_glType, m_id);
if (m_type == ETexture1D) {
Assert((isPow2(m_size.x) && m_size.y == 1)
|| (isPow2(m_size.y) && m_size.x == 1));
if (isMipMapped()) {
/* Let GLU generate mipmaps for us */
gluBuild1DMipmaps(m_glType, m_internalFormat, m_size.x == 1 ? m_size.y : m_size.x,
m_format, m_dataFormat, bitmap->getData());
} else {
glTexImage1D(m_glType, 0, m_internalFormat, m_size.x == 1 ? m_size.y : m_size.x,
0, m_format, m_dataFormat, bitmap->getData());
}
} else if (m_type == ETexture2D) {
//Assert(m_size.x == m_size.y);
/* Anisotropic texture filtering */
float anisotropy = (float) getMaxAnisotropy();
if (anisotropy > 1.0f) {
if (isMipMapped() && m_filterType == EMipMapLinear) {
/* Only use anisotropy when it makes sense - otherwise some
GL implementations will enforce mipmapping */
glTexParameterf(m_glType, GL_TEXTURE_MAX_ANISOTROPY_EXT,
anisotropy);
}
}
glTexImage2D(m_glType, 0, m_internalFormat, m_size.x, m_size.y,
0, m_format, m_dataFormat, bitmap->getData());
if (isMipMapped())
glGenerateMipmapEXT(m_glType);
} else if (m_type == ETextureCubeMap) {
Assert(bitmap != NULL);
Assert(bitmap->getWidth() == bitmap->getHeight());
Assert(isPow2(bitmap->getWidth()));
if (isMipMapped())
glTexParameteri(m_glType, GL_GENERATE_MIPMAP, GL_TRUE);
for (int i=0; i<6; i++) {
Bitmap *bitmap = getBitmap(i);
GLuint pos;
switch (i) {
case ECubeMapPositiveX: pos = GL_TEXTURE_CUBE_MAP_POSITIVE_X; break;
case ECubeMapNegativeX: pos = GL_TEXTURE_CUBE_MAP_NEGATIVE_X; break;
case ECubeMapPositiveY: pos = GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT; break;
case ECubeMapNegativeY: pos = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT; break;
case ECubeMapPositiveZ: pos = GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT; break;
case ECubeMapNegativeZ: pos = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT; break;
default: Log(EError, "Unknown cube map index"); return;
};
glTexImage2D(pos, 0, m_internalFormat, bitmap->getWidth(), bitmap->getHeight(),
0, m_format, m_dataFormat, bitmap->getData());
}
} else {
Log(EError, "Unknown texture type!");
}
}
void GLTexture::lookupGLConstants() {
m_dataFormat = GL_UNSIGNED_BYTE;
/* Convert the texture type */
switch (m_type) {
case ETexture1D: m_glType = GL_TEXTURE_1D; break;
case ETexture2D:
if (m_samples == 1)
m_glType = GL_TEXTURE_2D;
else
m_glType = GL_TEXTURE_2D_MULTISAMPLE;
break;
case ETexture3D: m_glType = GL_TEXTURE_3D; break;
case ETextureCubeMap: m_glType = GL_TEXTURE_CUBE_MAP_EXT; break;
default: Log(EError, "Invalid texture type specified"); return;
}
/* Convert the texture format */
switch (getFormat()) {
case ER8G8B8:
m_format = GL_RGB;
m_internalFormat = GL_RGB;
break;
case ER8G8B8A8:
m_format = GL_RGBA;
m_internalFormat = GL_RGBA;
break;
case EL8:
m_format = GL_LUMINANCE;
m_internalFormat = GL_LUMINANCE8;
break;
case EL8A8:
m_format = GL_LUMINANCE_ALPHA;
m_internalFormat = GL_LUMINANCE8_ALPHA8;
break;
case EDepth:
m_format = GL_DEPTH_COMPONENT;
m_internalFormat = GL_DEPTH_COMPONENT32;
break;
case EFloat16L:
m_format = GL_LUMINANCE;
m_internalFormat = GL_RGBA16F_ARB;
m_dataFormat = GL_FLOAT;
break;
case EFloat16RGB:
m_format = GL_RGB;
m_internalFormat = GL_RGBA16F_ARB;
m_dataFormat = GL_FLOAT;
break;
case EFloat16RGBA:
m_format = GL_RGBA;
m_internalFormat = GL_RGBA16F_ARB;
m_dataFormat = GL_FLOAT;
break;
case EFloat32L:
m_format = GL_LUMINANCE;
m_internalFormat = GL_RGBA32F_ARB;
m_dataFormat = GL_FLOAT;
break;
case EFloat32RGB:
m_format = GL_RGB;
m_internalFormat = GL_RGBA32F_ARB;
m_dataFormat = GL_FLOAT;
break;
case EFloat32RGBA:
m_format = GL_RGBA;
m_internalFormat = GL_RGBA32F_ARB;
m_dataFormat = GL_FLOAT;
break;
default: Log(EError, "Invalid texture format specified"); return;
}
}
void GLTexture::configureTexture() {
int wrap, mag_filter, min_filter;
/* Convert the texture coordinate wrapping type */
switch (getWrapType()) {
case EClamp: wrap = GL_CLAMP; break;
case EClampToEdge: wrap = GL_CLAMP_TO_EDGE; break;
case EClampToBorder: wrap = GL_CLAMP_TO_BORDER; break;
case ERepeat: wrap = GL_REPEAT; break;
case EMirroredRepeat: wrap = GL_MIRRORED_REPEAT_ARB; break;
default: Log(EError, "Invalid texture wrap type specified"); return;
}
/* Convert the texture filter type */
switch (m_filterType) {
case ENearest:
mag_filter = GL_NEAREST;
min_filter = isMipMapped() ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST;
break;
case ELinear:
mag_filter = GL_LINEAR;
min_filter = isMipMapped() ? GL_NEAREST_MIPMAP_LINEAR : GL_LINEAR;
break;
case EMipMapNearest:
if (!isMipMapped()) {
mag_filter = GL_LINEAR;
min_filter = GL_LINEAR;
break;
}
mag_filter = GL_LINEAR;
min_filter = GL_LINEAR_MIPMAP_NEAREST;
break;
case EMipMapLinear:
if (!isMipMapped()) {
mag_filter = GL_LINEAR;
min_filter = GL_LINEAR;
break;
}
mag_filter = GL_LINEAR;
min_filter = GL_LINEAR_MIPMAP_LINEAR;
break;
default:
Log(EError, "Invalid filter type specified");
return;
}
/* Set the filter type */
glTexParameteri(m_glType, GL_TEXTURE_MAG_FILTER, mag_filter);
glTexParameteri(m_glType, GL_TEXTURE_MIN_FILTER, min_filter);
/* Set the texcoord wrapping type */
if (m_type == ETexture1D) {
glTexParameteri(m_glType, GL_TEXTURE_WRAP_S, wrap);
} else if (m_type == ETexture2D) {
glTexParameteri(m_glType, GL_TEXTURE_WRAP_S, wrap);
glTexParameteri(m_glType, GL_TEXTURE_WRAP_T, wrap);
} else if (m_type == ETextureCubeMap) {
glTexParameteri(m_glType, GL_TEXTURE_WRAP_S, wrap);
glTexParameteri(m_glType, GL_TEXTURE_WRAP_T, wrap);
glTexParameteri(m_glType, GL_TEXTURE_WRAP_R, wrap);
}
}
void GLTexture::download(Bitmap *bitmap) {
Assert(m_type == ETexture2D); // Only type supported so far
if (bitmap == NULL)
bitmap = getBitmap();
Assert(bitmap != NULL);
unsigned char *temp, *pixels = bitmap->getData();
activateTarget();
GLenum format = 0, dataFormat = GL_UNSIGNED_BYTE;
switch (bitmap->getBitsPerPixel()) {
case 8:
if (m_fbType == EDepthBuffer)
format = GL_DEPTH_COMPONENT;
else
format = GL_LUMINANCE;
break;
case 24: format = GL_RGB; break;
case 32: format = GL_RGBA; break;
case 96: format = GL_RGB; dataFormat = GL_FLOAT; break;
case 128: format = GL_RGBA; dataFormat = GL_FLOAT; break;
}
glReadPixels(0, 0, bitmap->getWidth(), bitmap->getHeight(), format,
dataFormat, pixels);
releaseTarget();
/* OpenGL has associates (0, 0) with the lower left position
and the resulting bitmap is thus vertically flipped. */
int rowSize = bitmap->getWidth() * bitmap->getBitsPerPixel() / 8,
halfHeight= bitmap->getHeight()/2;
temp = new unsigned char[rowSize];
for (int i=0, j=bitmap->getHeight()-1; i<halfHeight; ++i) {
memcpy(temp, pixels + i * rowSize, rowSize);
memcpy(pixels + i * rowSize, pixels + j * rowSize, rowSize);
memcpy(pixels + j * rowSize, temp, rowSize);
j--;
}
delete[] temp;
}
Spectrum GLTexture::getPixel(int x, int y) const {
Assert(m_fbType == EColorBuffer);
float pixels[3];
Spectrum result;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboId);
glPushAttrib(GL_VIEWPORT_BIT);
glViewport(0, 0, m_size.x, m_size.y);
glReadPixels(x, y, 1, 1, GL_RGB, GL_FLOAT, &pixels);
glPopAttrib();
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, GL_NONE);
result.fromLinearRGB(pixels[0], pixels[1], pixels[2]);
return result;
}
void GLTexture::activateTarget() {
Assert(m_fbType != ENone);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboId);
glPushAttrib(GL_VIEWPORT_BIT);
glViewport(0, 0, m_size.x, m_size.y);
}
void GLTexture::activateSide(int side) {
if (side == -1) {
if (m_fbType == EColorBuffer) {
glFramebufferTextureEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, m_id, 0);
glFramebufferTextureEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, m_depthId, 0);
} else if (m_fbType == EDepthBuffer) {
glFramebufferTextureEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, m_id, 0);
} else {
Log(EError, "Unsupported framebuffer type!");
}
} else {
if (m_fbType == EColorBuffer) {
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_CUBE_MAP_POSITIVE_X + side, m_id, 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
GL_TEXTURE_CUBE_MAP_POSITIVE_X + side, m_depthId, 0);
} else if (m_fbType == EDepthBuffer) {
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
GL_TEXTURE_CUBE_MAP_POSITIVE_X + side, m_id, 0);
} else {
Log(EError, "Unsupported framebuffer type!");
}
}
}
void GLTexture::setTargetRegion(const Point2i &offset, const Vector2i &size) {
glViewport(offset.x, offset.y, size.x, size.y);
}
void GLTexture::releaseTarget() {
Assert(m_fbType != ENone);
glPopAttrib();
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, GL_NONE);
if (isMipMapped())
m_needsUpdate = true;
}
void GLTexture::bind(int textureUnit, int textureIndex) const {
/* Bind to the texture */
if (GLEW_VERSION_1_3) {
m_textureUnits.get().insert(textureUnit);
glActiveTexture(GL_TEXTURE0 + textureUnit);
} else {
if (textureUnit != 0)
Log(EError, "Multitexturing is not supported");
}
glEnable(m_glType);
if (textureIndex == 1 && m_fbType == EColorAndDepthBuffer) {
glBindTexture(m_glType, m_depthId);
} else {
glBindTexture(m_glType, m_id);
}
if (isMipMapped() && m_needsUpdate) {
glGenerateMipmapEXT(m_glType);
m_needsUpdate = false;
}
}
void GLTexture::unbind() const {
if (GLEW_VERSION_1_3) {
std::set<int> &textureUnits = m_textureUnits.get();
for (std::set<int>::iterator it = textureUnits.begin();
it != textureUnits.end(); ++it) {
glActiveTexture(GL_TEXTURE0 + *it);
glDisable(m_glType);
}
textureUnits.clear();
} else {
glDisable(m_glType);
}
}
void GLTexture::cleanup() {
if (m_id == 0)
return;
if (m_fbType != ENone) {
Log(ETrace, "Freeing framebuffer \"%s\"", m_name.c_str());
if (m_fbType == EColorAndDepthBuffer || (m_fbType == EColorBuffer && m_type == ETextureCubeMap)) {
glDeleteTextures(1, &m_depthId);
} else if (m_fbType == EColorBuffer) {
glDeleteRenderbuffersEXT(1, &m_depthId);
}
glDeleteFramebuffersEXT(1, &m_fboId);
} else {
Log(ETrace, "Freeing texture \"%s\"", m_name.c_str());
}
glDeleteTextures(1, &m_id);
m_id = 0;
}
void GLTexture::blit(GPUTexture *target, int what) const {
GLTexture *dest = static_cast<GLTexture *>(target);
Assert(m_fbType != ENone && (dest == NULL || dest->m_fbType != ENone));
if (!GLEW_EXT_framebuffer_blit)
Log(EError, "Your OpenGL driver does not support fast "
"framebuffer blitting!");
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_fboId);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT,
(dest == NULL) ? GL_NONE : dest->m_fboId);
int flags = 0;
if (what & EDepthBuffer)
flags |= GL_DEPTH_BUFFER_BIT;
if (what & EColorBuffer)
flags |= GL_COLOR_BUFFER_BIT;
if (!dest) {
glBlitFramebufferEXT(0, 0, m_size.x, m_size.y, 0, 0,
m_size.x, m_size.y, flags, GL_NEAREST);
} else {
glBlitFramebufferEXT(0, 0, m_size.x, m_size.y, 0, 0,
dest->m_size.x, dest->m_size.y, flags,
(m_size == dest->m_size) ? GL_NEAREST : GL_LINEAR);
}
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_NONE);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_NONE);
}
void GLTexture::blit(GPUTexture *target, int what,
const Point2i &sourceOffset, const Vector2i &sourceSize,
const Point2i &destOffset, const Vector2i &destSize) const {
GLTexture *dest = static_cast<GLTexture *>(target);
Assert(m_fbType != ENone && (dest == NULL || dest->m_fbType != ENone));
if (!GLEW_EXT_framebuffer_blit)
Log(EError, "Your OpenGL driver does not support fast "
"framebuffer blitting!");
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_fboId);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT,
(dest == NULL) ? GL_NONE : dest->m_fboId);
int flags = 0;
if (what & EDepthBuffer)
flags |= GL_DEPTH_BUFFER_BIT;
if (what & EColorBuffer)
flags |= GL_COLOR_BUFFER_BIT;
glBlitFramebufferEXT(sourceOffset.x, sourceOffset.y,
sourceOffset.x + sourceSize.x, sourceOffset.x + sourceSize.y,
destOffset.x, destOffset.y, destOffset.x + destSize.x,
destOffset.y + destSize.y, flags,
(sourceSize == destSize) ? GL_NEAREST : GL_LINEAR);
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_NONE);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_NONE);
}
void GLTexture::clear() {
Assert(m_fbType != ENone);
glClear(GL_DEPTH_BUFFER_BIT
| ((m_fbType & EColorBuffer) ? GL_COLOR_BUFFER_BIT : 0));
}
GLTexture::~GLTexture() {
cleanup();
}
MTS_IMPLEMENT_CLASS(GLTexture, false, Texture)
MTS_NAMESPACE_END