vcglib/wrap/gl/fbo.h

949 lines
18 KiB
C++

/****************************************************************************
* MeshLab o o *
* An extendible mesh processor o o *
* _ O _ *
* Copyright(C) 2005, 2009 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program 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. *
* *
* This program 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 (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
#ifndef __FBO_H__
#define __FBO_H__
#pragma warning(disable : 4250)
#include <map>
#include <vector>
#include <GL/glew.h>
#include <GL/glut.h>
#include "gl_object.h"
class FrameBufferSemantic
{
public:
typedef enum
{
COLOR,
DEPTH,
STENCIL
} FBSType;
virtual FBSType Semantic(void) const = 0;
virtual bool ValidateFormat(GLenum format) const = 0;
static bool ValidateFormat(FBSType type, GLenum format)
{
switch (type)
{
case COLOR : return FrameBufferSemantic::ValidateColor(format);
case DEPTH : return FrameBufferSemantic::ValidateDepth(format);
case STENCIL : return FrameBufferSemantic::ValidateStencil(format);
default : return false;
}
}
static bool ValidateColor(GLenum type)
{
return true;
}
static bool ValidateDepth(GLenum type)
{
return true;
}
static bool ValidateStencil(GLenum type)
{
return true;
}
};
class Texture : public GLObject, public Bindable, public FrameBufferSemantic
{
public:
Texture(void) : GLObject(), Bindable(), FrameBufferSemantic()
{
this->format = GL_NONE;
}
void Gen(void)
{
this->Del();
glGenTextures(1, &(this->objectID));
}
void Del(void)
{
if (this->objectID == 0) return;
glDeleteTextures(1, &(this->objectID));
this->objectID = 0;
}
GLenum Format(void) const
{
return this->format;
}
virtual GLint Dimensions(void) const = 0;
virtual GLsizei Size(const unsigned int i) const = 0;
virtual GLenum Target(void) const = 0;
protected:
GLenum format;
void DoBind(void)
{
glBindTexture(this->Target(), this->objectID);
}
void DoUnbind(void)
{
glBindTexture(this->Target(), 0);
}
};
class ColorTexture : public virtual Texture
{
public:
ColorTexture(void) : Texture()
{
}
FrameBufferSemantic::FBSType Semantic(void) const
{
return FrameBufferSemantic::COLOR;
}
bool ValidateFormat(GLenum format) const
{
return FrameBufferSemantic::ValidateColor(format);
}
};
class DepthTexture : public virtual Texture
{
public:
DepthTexture(void) : Texture()
{
}
FrameBufferSemantic::FBSType Semantic(void) const
{
return FrameBufferSemantic::DEPTH;
}
bool ValidateFormat(GLenum format) const
{
return FrameBufferSemantic::ValidateDepth(format);
}
};
class StencilTexture : public virtual Texture
{
public:
StencilTexture(void) : Texture()
{
}
FrameBufferSemantic::FBSType Semantic(void) const
{
return FrameBufferSemantic::STENCIL;
}
bool ValidateFormat(GLenum format) const
{
return FrameBufferSemantic::ValidateStencil(format);
}
};
class Texture1D : public virtual Texture
{
public:
Texture1D(void) : Texture()
{
this->dims[0] = 0;
this->wraps[0] = GL_CLAMP_TO_EDGE;
}
GLsizei Width(void) const
{
return this->dims[0];
}
GLint Dimensions(void) const
{
return 1;
}
GLsizei Size(const unsigned int i) const
{
if (i > 0) return 0;
return this->dims[0];
}
GLenum Target(void) const
{
return GL_TEXTURE_1D;
}
bool Set(GLint level, GLint internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid * pixels)
{
if (!this->ValidateFormat(internalFormat)) return false;
this->Bind();
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage1D(GL_TEXTURE_1D, level, internalFormat, width, border, format, type, pixels);
this->Unbind();
this->format = internalFormat;
this->dims[0] = width;
return true;
}
protected:
GLsizei dims[1];
GLenum wraps[1];
};
class Texture2D : public virtual Texture
{
public:
Texture2D(void) : Texture()
{
this->dims[0] = 0;
this->dims[1] = 0;
}
GLsizei Width(void) const
{
return this->dims[0];
}
GLsizei Height(void) const
{
return this->dims[1];
}
GLint Dimensions(void) const
{
return 2;
}
GLsizei Size(const unsigned int i) const
{
if (i > 1) return 0;
return this->dims[i];
}
GLenum Target(void) const
{
return GL_TEXTURE_2D;
}
bool Set(GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid * pixels)
{
if (!this->ValidateFormat(internalFormat)) return false;
this->Bind();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, border, format, type, pixels);
this->Unbind();
this->format = internalFormat;
this->dims[0] = width;
this->dims[1] = height;
return true;
}
protected:
GLsizei dims[2];
void DoBind(void)
{
glBindTexture(GL_TEXTURE_2D, this->objectID);
}
void DoUnbind(void)
{
glBindTexture(GL_TEXTURE_2D, 0);
}
};
class Texture3D : public virtual Texture
{
public:
Texture3D(void) : Texture()
{
this->dims[0] = 0;
this->dims[1] = 0;
this->dims[2] = 0;
}
GLsizei Width(void) const
{
return this->dims[0];
}
GLsizei Height(void) const
{
return this->dims[1];
}
GLsizei Depth(void) const
{
return this->dims[2];
}
GLint Dimensions(void) const
{
return 3;
}
GLsizei Size(const unsigned int i) const
{
if (i > 2) return 0;
return this->dims[i];
}
GLenum Target(void) const
{
return GL_TEXTURE_3D;
}
bool Set(GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid * pixels)
{
if (!this->ValidateFormat(internalFormat)) return false;
this->Bind();
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage3D(GL_TEXTURE_3D, 0, internalFormat, width, height, depth, border, format, type, pixels);
this->Unbind();
this->format = internalFormat;
this->dims[0] = width;
this->dims[1] = height;
this->dims[2] = depth;
return true;
}
protected:
GLsizei dims[3];
void DoBind(void)
{
glBindTexture(GL_TEXTURE_3D, this->objectID);
}
void DoUnbind(void)
{
glBindTexture(GL_TEXTURE_3D, 0);
}
};
class ColorTexture1D : public virtual ColorTexture, public virtual Texture1D
{
public:
ColorTexture1D(void) : ColorTexture(), Texture1D()
{
}
};
class ColorTexture2D : public virtual ColorTexture, public virtual Texture2D
{
public:
ColorTexture2D(void) : ColorTexture(), Texture2D()
{
}
};
class ColorTexture3D : public virtual ColorTexture, public virtual Texture3D
{
public:
ColorTexture3D(void) : ColorTexture(), Texture3D()
{
}
};
class DepthTexture2D : public virtual DepthTexture, public virtual Texture2D
{
public:
DepthTexture2D(void) : DepthTexture(), Texture2D()
{
}
};
class StencilTexture2D : public virtual StencilTexture, public virtual Texture2D
{
public:
StencilTexture2D(void) : StencilTexture(), Texture2D()
{
}
};
class FrameBuffer;
class RenderTarget : public GLObject, public Bindable, public FrameBufferSemantic
{
friend class FrameBuffer;
public:
typedef enum
{
BUFFER,
TEXTURE
} RTStorageType;
RenderTarget(void) : GLObject(), Bindable(), FrameBufferSemantic()
{
this->frameBuffer = 0;
}
bool Attach(FrameBuffer * fb);
bool Detach(void);
FrameBuffer * GetFrameBuffer(void)
{
return this->frameBuffer;
}
const FrameBuffer * GetFrameBuffer(void) const
{
return this->frameBuffer;
}
virtual GLsizei Width(void) const = 0;
virtual GLsizei Height(void) const = 0;
virtual GLenum Format(void) const = 0;
virtual GLenum Attachment(void) const = 0;
virtual bool ValidateAttachment(GLenum attachment) const = 0;
virtual RTStorageType StorageType(void) const = 0;
protected:
FrameBuffer * frameBuffer;
virtual bool BindToFB(void) = 0;
};
class BufferRenderTarget : public virtual RenderTarget
{
public:
BufferRenderTarget(void) : RenderTarget()
{
this->width = 0;
this->height = 0;
this->format = GL_NONE;
}
void Gen(void)
{
this->Del();
glGenRenderbuffersEXT(1, &(this->objectID));
}
void Del(void)
{
if (this->objectID == 0) return;
glDeleteRenderbuffersEXT(1, &(this->objectID));
this->objectID = 0;
}
GLsizei Width(void) const
{
return this->width;
}
GLsizei Height(void) const
{
return this->height;
}
GLenum Format(void) const
{
return this->format;
}
RTStorageType StorageType(void) const
{
return RenderTarget::BUFFER;
}
bool Set(GLenum format, GLsizei width, GLsizei height)
{
if (!this->ValidateFormat(format)) return false;
this->Bind();
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, format, width, height);
this->Unbind();
this->format = format;
this->width = width;
this->height = height;
return true;
}
bool BindToFB(void)
{
if (this->frameBuffer == 0) return false;
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, this->Attachment(), GL_RENDERBUFFER_EXT, this->objectID);
return true;
}
protected:
GLenum format;
GLsizei width;
GLsizei height;
void DoBind(void)
{
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, this->objectID);
}
void DoUnbind(void)
{
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
}
};
class TextureRenderTarget : public virtual RenderTarget
{
public:
TextureRenderTarget(void) : RenderTarget()
{
this->tex = 0;
this->level = 0;
}
void Gen(void)
{
}
void Del(void)
{
}
GLsizei Width(void) const
{
if (this->tex == 0) return 0;
return this->tex->Width();
}
GLsizei Height(void) const
{
if (this->tex == 0) return 0;
return this->tex->Height();
}
GLenum Format(void) const
{
if (this->tex == 0) return GL_NONE;
return this->tex->Format();
}
RTStorageType StorageType(void) const
{
return RenderTarget::TEXTURE;
}
void SetLevel(GLint level)
{
if (level < 0) level = 0;
this->level = level;
}
bool Set(Texture2D * tex)
{
this->Unset();
if (tex == 0) return true;
if (this->Semantic() != tex->Semantic()) return false;
this->tex = tex;
return true;
}
bool Unset(void)
{
this->tex = 0;
return true;
}
Texture2D * GetTexture(void)
{
return (this->tex);
}
bool BindToFB(void)
{
if (this->frameBuffer == 0) return false;
if (this->tex == 0) return false;
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, this->Attachment(), GL_TEXTURE_2D, this->tex->ObjectID(), this->level);
return true;
}
protected:
Texture2D * tex;
GLint level;
void DoBind(void)
{
}
void DoUnbind(void)
{
}
};
class ColorRenderTarget : public virtual RenderTarget
{
public:
ColorRenderTarget(void) : RenderTarget()
{
this->attachment = GL_COLOR_ATTACHMENT0_EXT;
}
FrameBufferSemantic::FBSType Semantic(void) const
{
return FrameBufferSemantic::COLOR;
}
bool ValidateFormat(GLenum format) const
{
return FrameBufferSemantic::ValidateColor(format);
}
bool ValidateAttachment(GLenum attachment) const
{
return (((GL_COLOR_ATTACHMENT0_EXT) <= attachment) && (attachment <= (GL_COLOR_ATTACHMENT0_EXT + 3)));
}
void SetAttachment(GLenum attachment)
{
if (!this->ValidateAttachment(attachment)) return;
this->attachment = attachment;
}
GLenum Attachment(void) const
{
return this->attachment;
}
protected:
GLenum attachment;
};
class DepthRenderTarget : public virtual RenderTarget
{
public:
DepthRenderTarget(void) : RenderTarget()
{
}
FrameBufferSemantic::FBSType Semantic(void) const
{
return FrameBufferSemantic::DEPTH;
}
bool ValidateFormat(GLenum format) const
{
return FrameBufferSemantic::ValidateDepth(format);
}
bool ValidateAttachment(GLenum attachment) const
{
return (attachment == GL_DEPTH_ATTACHMENT_EXT);
}
GLenum Attachment(void) const
{
return GL_DEPTH_ATTACHMENT_EXT;
}
};
class StencilRenderTarget : public virtual RenderTarget
{
public:
StencilRenderTarget(void) : RenderTarget()
{
}
FrameBufferSemantic::FBSType Semantic(void) const
{
return FrameBufferSemantic::STENCIL;
}
bool ValidateFormat(GLenum format) const
{
return FrameBufferSemantic::ValidateStencil(format);
}
bool ValidateAttachment(GLenum attachment) const
{
return (attachment == GL_STENCIL_ATTACHMENT_EXT);
}
GLenum Attachment(void) const
{
return GL_STENCIL_ATTACHMENT_EXT;
}
};
class ColorRenderBuffer : public virtual ColorRenderTarget, public virtual BufferRenderTarget
{
public:
ColorRenderBuffer(void) : ColorRenderTarget(), BufferRenderTarget()
{
}
};
class ColorRenderTexture : public virtual ColorRenderTarget, public virtual TextureRenderTarget
{
public:
ColorRenderTexture(void) : ColorRenderTarget(), TextureRenderTarget()
{
}
ColorRenderTexture(Texture2D * tex) : ColorRenderTarget(), TextureRenderTarget()
{
this->Set(tex);
}
};
class DepthRenderBuffer : public virtual DepthRenderTarget, public virtual BufferRenderTarget
{
public:
DepthRenderBuffer(void) : DepthRenderTarget(), BufferRenderTarget()
{
}
};
class DepthRenderTexture : public virtual DepthRenderTarget, public virtual TextureRenderTarget
{
public:
DepthRenderTexture(void) : DepthRenderTarget(), TextureRenderTarget()
{
}
DepthRenderTexture(Texture2D * tex) : DepthRenderTarget(), TextureRenderTarget()
{
this->Set(tex);
}
};
class StencilRenderBuffer : public virtual StencilRenderTarget, public virtual BufferRenderTarget
{
public:
StencilRenderBuffer(void) : StencilRenderTarget(), BufferRenderTarget()
{
}
};
class StencilRenderTexture : public virtual StencilRenderTarget, public virtual TextureRenderTarget
{
public:
StencilRenderTexture(void) : StencilRenderTarget(), TextureRenderTarget()
{
}
StencilRenderTexture(Texture2D * tex) : StencilRenderTarget(), TextureRenderTarget()
{
this->Set(tex);
}
};
class FrameBuffer : public GLObject, public Bindable
{
friend class RenderTarget;
public:
FrameBuffer(void) : GLObject(), Bindable()
{
}
void Gen(void)
{
this->Del();
glGenFramebuffersEXT(1, &(this->objectID));
}
void Del(void)
{
if (this->objectID == 0) return;
glDeleteFramebuffersEXT(1, &(this->objectID));
this->objectID = 0;
}
bool DetachAll(void)
{
return false;
}
bool IsValid(void) const
{
const GLenum s = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
//return (s == GL_FRAMEBUFFER_COMPLETE_EXT);
switch (s)
{
case GL_FRAMEBUFFER_COMPLETE_EXT:
printf("ok\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
printf("i a\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
printf("i m a\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT:
printf("i d a\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
printf("i d\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
printf("i f\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
printf("i d b\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
printf("i r b\n");
break;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
printf("u\n");
break;
default:
printf("def\n");
break;
}
return (s == GL_FRAMEBUFFER_COMPLETE_EXT);
}
protected:
typedef std::map<GLenum, RenderTarget *> RTMap;
typedef RTMap::iterator RTMap_i;
typedef RTMap::const_iterator RTMap_ci;
RTMap renderTargets;
void DoBind(void)
{
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, this->objectID);
std::vector<GLenum> colorDrawBuffers;
colorDrawBuffers.reserve(this->renderTargets.size());
for (RTMap_i rt=this->renderTargets.begin(); rt!=this->renderTargets.end(); ++rt)
{
RenderTarget * prt = (*rt).second;
if (prt->Semantic() == FrameBufferSemantic::COLOR)
{
colorDrawBuffers.push_back(prt->Attachment());
}
prt->BindToFB();
}
const GLsizei sz = (GLsizei)(colorDrawBuffers.size());
if (sz > 0)
{
glDrawBuffers(sz, &(colorDrawBuffers[0]));
}
}
void DoUnbind(void)
{
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}
bool AddRT(RenderTarget * rt)
{
if (rt == 0) return false;
RTMap_i it = this->renderTargets.find(rt->Attachment());
if (it == this->renderTargets.end())
{
this->renderTargets.insert(std::make_pair(rt->Attachment(), rt));
return true;
}
return false;
}
bool RemoveRT(RenderTarget * rt)
{
if (rt == 0) return false;
RTMap_i it = this->renderTargets.find(rt->Attachment());
if ((*it).second == rt)
{
this->renderTargets.erase(it);
return true;
}
return false;
}
};
bool RenderTarget::Attach(FrameBuffer * fb)
{
this->Detach();
if (fb == 0) return true;
if (fb->AddRT(this))
{
this->frameBuffer = fb;
return true;
}
return false;
}
bool RenderTarget::Detach(void)
{
if (this->frameBuffer == 0) return false;
this->frameBuffer->RemoveRT(this);
this->frameBuffer = 0;
return true;
}
#endif // __FBO_H__