From Marco Jez, added example that uses FBO extension to do prerendering.

This commit is contained in:
Robert Osfield
2005-06-09 11:08:37 +00:00
parent 96eb0b71c6
commit 5c86ecebe4
12 changed files with 894 additions and 0 deletions

View File

@@ -187,6 +187,7 @@ EXAMPLE_DIRS = \
osgcubemap\
osgdepthshadow\
osgdistortion\
osgfbo\
osgforest\
osgfxbrowser\
osggeodemo\

View File

@@ -0,0 +1,38 @@
#include "FBOExtensions.h"
#include <osg/GLExtensions>
using namespace osg;
#define LOAD_FBO_EXT(name) name = (T##name *)getGLExtensionFuncPtr(#name);
FBOExtensions::FBOExtensions(unsigned int contextID)
: _supported(false)
{
if (!isGLExtensionSupported(contextID, "GL_EXT_framebuffer_object"))
return;
LOAD_FBO_EXT(glBindRenderbufferEXT);
LOAD_FBO_EXT(glGenRenderbuffersEXT);
LOAD_FBO_EXT(glRenderbufferStorageEXT);
LOAD_FBO_EXT(glBindFramebufferEXT);
LOAD_FBO_EXT(glGenFramebuffersEXT);
LOAD_FBO_EXT(glCheckFramebufferStatusEXT);
LOAD_FBO_EXT(glFramebufferTexture1DEXT);
LOAD_FBO_EXT(glFramebufferTexture2DEXT);
LOAD_FBO_EXT(glFramebufferTexture3DEXT);
LOAD_FBO_EXT(glFramebufferRenderbufferEXT);
LOAD_FBO_EXT(glGenerateMipmapEXT);
_supported =
glBindRenderbufferEXT != 0 &&
glGenRenderbuffersEXT != 0 &&
glRenderbufferStorageEXT != 0 &&
glBindFramebufferEXT != 0 &&
glGenFramebuffersEXT != 0 &&
glCheckFramebufferStatusEXT != 0 &&
glFramebufferTexture1DEXT != 0 &&
glFramebufferTexture2DEXT != 0 &&
glFramebufferTexture3DEXT != 0 &&
glFramebufferRenderbufferEXT != 0 &&
glGenerateMipmapEXT != 0;
}

View File

@@ -0,0 +1,118 @@
#ifndef OSG_FBOEXTENSIONS
#define OSG_FBOEXTENSIONS 1
#include <osg/GL>
#include <osg/buffered_value>
#ifndef GL_EXT_framebuffer_object
#define GL_EXT_framebuffer_object 1
#define GL_FRAMEBUFFER_EXT 0x8D40
#define GL_RENDERBUFFER_EXT 0x8D41
#define GL_STENCIL_INDEX_EXT 0x8D45
#define GL_STENCIL_INDEX1_EXT 0x8D46
#define GL_STENCIL_INDEX4_EXT 0x8D47
#define GL_STENCIL_INDEX8_EXT 0x8D48
#define GL_STENCIL_INDEX16_EXT 0x8D49
#define GL_RENDERBUFFER_WIDTH_EXT 0x8D42
#define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43
#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44
#define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50
#define GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51
#define GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52
#define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53
#define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54
#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55
#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0
#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4
#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0
#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1
#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2
#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3
#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4
#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5
#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6
#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7
#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8
#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9
#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA
#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB
#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC
#define GL_COLOR_ATTACHMENT13_EXT 0x8CED
#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE
#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF
#define GL_DEPTH_ATTACHMENT_EXT 0x8D00
#define GL_STENCIL_ATTACHMENT_EXT 0x8D20
#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5
#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6
#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7
#define GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT 0x8CD8
#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9
#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA
#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB
#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC
#define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD
#define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6
#define GL_RENDERBUFFER_BINDING_EXT 0x8CA7
#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF
#define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8
#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506
#endif
namespace osg
{
class FBOExtensions
{
public:
typedef void APIENTRY TglBindRenderbufferEXT(GLenum, GLuint);
typedef void APIENTRY TglGenRenderbuffersEXT(GLsizei, GLuint *);
typedef void APIENTRY TglRenderbufferStorageEXT(GLenum, GLenum, GLsizei, GLsizei);
typedef void APIENTRY TglBindFramebufferEXT(GLenum, GLuint);
typedef void APIENTRY TglGenFramebuffersEXT(GLsizei, GLuint *);
typedef GLenum APIENTRY TglCheckFramebufferStatusEXT(GLenum);
typedef void APIENTRY TglFramebufferTexture1DEXT(GLenum, GLenum, GLenum, GLuint, GLint);
typedef void APIENTRY TglFramebufferTexture2DEXT(GLenum, GLenum, GLenum, GLuint, GLint);
typedef void APIENTRY TglFramebufferTexture3DEXT(GLenum, GLenum, GLenum, GLuint, GLint, GLint);
typedef void APIENTRY TglFramebufferRenderbufferEXT(GLenum, GLenum, GLenum, GLuint);
typedef void APIENTRY TglGenerateMipmapEXT(GLenum);
TglBindRenderbufferEXT *glBindRenderbufferEXT;
TglGenRenderbuffersEXT *glGenRenderbuffersEXT;
TglRenderbufferStorageEXT *glRenderbufferStorageEXT;
TglBindFramebufferEXT *glBindFramebufferEXT;
TglGenFramebuffersEXT *glGenFramebuffersEXT;
TglCheckFramebufferStatusEXT *glCheckFramebufferStatusEXT;
TglFramebufferTexture1DEXT *glFramebufferTexture1DEXT;
TglFramebufferTexture2DEXT *glFramebufferTexture2DEXT;
TglFramebufferTexture3DEXT *glFramebufferTexture3DEXT;
TglFramebufferRenderbufferEXT *glFramebufferRenderbufferEXT;
TglGenerateMipmapEXT *glGenerateMipmapEXT;
static FBOExtensions *instance(unsigned contextID)
{
static buffered_object<FBOExtensions *> _instances;
FBOExtensions *ext = _instances[contextID];
if (!ext)
{
ext = new FBOExtensions(contextID);
_instances[contextID] = ext;
}
return ext;
}
bool isSupported() const { return _supported; }
protected:
FBOExtensions(unsigned int contextID);
private:
bool _supported;
};
}
#endif

View File

@@ -0,0 +1,173 @@
#include "FramebufferAttachment.h"
#include "Renderbuffer.h"
#include "FBOExtensions.h"
#include <osg/Texture1D>
#include <osg/Texture2D>
#include <osg/Texture3D>
#include <osg/TextureCubeMap>
#include <osg/TextureRectangle>
#include <osg/State>
using namespace osg;
#ifndef GL_TEXTURE_CUBE_MAP_POSITIVE_X
#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
#endif
struct FramebufferAttachment::Pimpl
{
enum TargetType
{
RENDERBUFFER,
TEXTURE1D,
TEXTURE2D,
TEXTURE3D,
TEXTURECUBE,
TEXTURERECT
};
TargetType targetType;
ref_ptr<Renderbuffer> renderbufferTarget;
ref_ptr<Texture> textureTarget;
int cubeMapFace;
int level;
int zoffset;
explicit Pimpl(TargetType ttype = RENDERBUFFER, int lev = 0)
: targetType(ttype),
cubeMapFace(0),
level(lev),
zoffset(0)
{
}
Pimpl(const Pimpl &copy)
: targetType(copy.targetType),
renderbufferTarget(copy.renderbufferTarget),
textureTarget(copy.textureTarget),
cubeMapFace(copy.cubeMapFace),
level(copy.level),
zoffset(copy.zoffset)
{
}
};
FramebufferAttachment::FramebufferAttachment()
{
_ximpl = new Pimpl;
}
FramebufferAttachment::FramebufferAttachment(const FramebufferAttachment &copy)
{
_ximpl = new Pimpl(*copy._ximpl);
}
FramebufferAttachment::FramebufferAttachment(Renderbuffer* target)
{
_ximpl = new Pimpl(Pimpl::RENDERBUFFER);
_ximpl->renderbufferTarget = target;
}
FramebufferAttachment::FramebufferAttachment(Texture1D* target, int level)
{
_ximpl = new Pimpl(Pimpl::TEXTURE1D, level);
_ximpl->textureTarget = target;
}
FramebufferAttachment::FramebufferAttachment(Texture2D* target, int level)
{
_ximpl = new Pimpl(Pimpl::TEXTURE2D, level);
_ximpl->textureTarget = target;
}
FramebufferAttachment::FramebufferAttachment(Texture3D* target, int level, int zoffset)
{
_ximpl = new Pimpl(Pimpl::TEXTURE3D, level);
_ximpl->textureTarget = target;
_ximpl->zoffset = zoffset;
}
FramebufferAttachment::FramebufferAttachment(TextureCubeMap* target, int face, int level)
{
_ximpl = new Pimpl(Pimpl::TEXTURECUBE, level);
_ximpl->textureTarget = target;
_ximpl->cubeMapFace = face;
}
FramebufferAttachment::FramebufferAttachment(TextureRectangle* target)
{
_ximpl = new Pimpl(Pimpl::TEXTURERECT);
_ximpl->textureTarget = target;
}
FramebufferAttachment::~FramebufferAttachment()
{
delete _ximpl;
}
FramebufferAttachment &FramebufferAttachment::operator = (const FramebufferAttachment &copy)
{
delete _ximpl;
_ximpl = new Pimpl(*copy._ximpl);
return *this;
}
void FramebufferAttachment::attach(State &state, GLenum attachment_point, const FBOExtensions* ext) const
{
unsigned int contextID = state.getContextID();
// force compile texture if necessary
Texture::TextureObject *tobj = 0;
if (_ximpl->textureTarget.valid())
{
tobj = _ximpl->textureTarget->getTextureObject(contextID);
if (!tobj || tobj->_id == 0)
{
_ximpl->textureTarget->compileGLObjects(state);
tobj = _ximpl->textureTarget->getTextureObject(contextID);
}
if (!tobj || tobj->_id == 0)
return;
}
switch (_ximpl->targetType)
{
default:
case Pimpl::RENDERBUFFER:
ext->glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attachment_point, GL_RENDERBUFFER_EXT, _ximpl->renderbufferTarget->getObjectID(contextID, ext));
break;
case Pimpl::TEXTURE1D:
ext->glFramebufferTexture1DEXT(GL_FRAMEBUFFER_EXT, attachment_point, GL_TEXTURE_1D, tobj->_id, _ximpl->level);
break;
case Pimpl::TEXTURE2D:
ext->glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment_point, GL_TEXTURE_2D, tobj->_id, _ximpl->level);
break;
case Pimpl::TEXTURE3D:
ext->glFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, attachment_point, GL_TEXTURE_3D, tobj->_id, _ximpl->level, _ximpl->zoffset);
break;
case Pimpl::TEXTURERECT:
ext->glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment_point, GL_TEXTURE_RECTANGLE, tobj->_id, 0);
break;
case Pimpl::TEXTURECUBE:
ext->glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment_point, GL_TEXTURE_CUBE_MAP_POSITIVE_X + _ximpl->cubeMapFace, tobj->_id, _ximpl->level);
break;
}
}
int FramebufferAttachment::compare(const FramebufferAttachment &fa) const
{
if (&fa == this) return 0;
if (_ximpl->targetType < fa._ximpl->targetType) return -1;
if (_ximpl->targetType > fa._ximpl->targetType) return 1;
if (_ximpl->renderbufferTarget.get() < fa._ximpl->renderbufferTarget.get()) return -1;
if (_ximpl->renderbufferTarget.get() > fa._ximpl->renderbufferTarget.get()) return 1;
if (_ximpl->textureTarget.get() < fa._ximpl->textureTarget.get()) return -1;
if (_ximpl->textureTarget.get() > fa._ximpl->textureTarget.get()) return 1;
if (_ximpl->cubeMapFace < fa._ximpl->cubeMapFace) return -1;
if (_ximpl->cubeMapFace > fa._ximpl->cubeMapFace) return 1;
if (_ximpl->level < fa._ximpl->level) return -1;
if (_ximpl->level > fa._ximpl->level) return 1;
if (_ximpl->zoffset < fa._ximpl->zoffset) return -1;
if (_ximpl->zoffset > fa._ximpl->zoffset) return 1;
return 0;
}

View File

@@ -0,0 +1,48 @@
#ifndef OSG_FRAMEBUFFERATTACHMENT
#define OSG_FRAMEBUFFERATTACHMENT 1
#include <osg/Object>
#include <osg/GL>
namespace osg
{
class FBOExtensions;
class Renderbuffer;
class Texture1D;
class Texture2D;
class Texture3D;
class TextureCubeMap;
class TextureRectangle;
class FramebufferAttachment
{
public:
FramebufferAttachment();
FramebufferAttachment(const FramebufferAttachment &copy);
explicit FramebufferAttachment(Renderbuffer* target);
explicit FramebufferAttachment(Texture1D* target, int level = 0);
explicit FramebufferAttachment(Texture2D* target, int level = 0);
explicit FramebufferAttachment(Texture3D* target, int zoffset, int level = 0);
explicit FramebufferAttachment(TextureCubeMap* target, int face, int level = 0);
explicit FramebufferAttachment(TextureRectangle* target);
~FramebufferAttachment();
FramebufferAttachment &operator = (const FramebufferAttachment &copy);
void attach(State &state, GLenum attachment_point, const FBOExtensions* ext) const;
int compare(const FramebufferAttachment &fa) const;
private:
// use the Pimpl idiom to avoid dependency from
// all Texture* headers
struct Pimpl;
Pimpl* _ximpl;
};
}
#endif

View File

@@ -0,0 +1,79 @@
#include "FramebufferObject.h"
#include "FBOExtensions.h"
#include <osg/State>
#include <osg/Notify>
using namespace osg;
FramebufferObject::FramebufferObject()
: StateAttribute()
{
}
FramebufferObject::FramebufferObject(const FramebufferObject &copy, const CopyOp &copyop)
: StateAttribute(copy, copyop),
_attachments(copy._attachments)
{
}
void FramebufferObject::apply(State &state) const
{
unsigned int contextID = state.getContextID();
if (_unsupported[contextID])
return;
FBOExtensions* ext = FBOExtensions::instance(contextID);
if (!ext->isSupported())
{
_unsupported[contextID] = 1;
notify(WARN) << "Warning: EXT_framebuffer_object is not supported" << std::endl;
return;
}
if (_attachments.empty())
{
ext->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
return;
}
int &dirtyAttachmentList = _dirtyAttachmentList[contextID];
GLuint &fboID = _fboID[contextID];
if (fboID == 0)
{
ext->glGenFramebuffersEXT(1, &fboID);
if (fboID == 0)
{
notify(WARN) << "Warning: FramebufferObject: could not create the FBO" << std::endl;
return;
}
dirtyAttachmentList = 1;
}
ext->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboID);
if (dirtyAttachmentList)
{
for (AttachmentMap::const_iterator i=_attachments.begin(); i!=_attachments.end(); ++i)
{
const FramebufferAttachment &fa = i->second;
fa.attach(state, i->first, ext);
}
dirtyAttachmentList = 0;
}
}
int FramebufferObject::compare(const StateAttribute &sa) const
{
COMPARE_StateAttribute_Types(FramebufferObject, sa);
COMPARE_StateAttribute_Parameter(_attachments.size());
AttachmentMap::const_iterator i = _attachments.begin();
AttachmentMap::const_iterator j = rhs._attachments.begin();
for (; i!=_attachments.end(); ++i, ++j)
{
int cmp = i->second.compare(j->second);
if (cmp != 0) return cmp;
}
return 0;
}

View File

@@ -0,0 +1,73 @@
#ifndef OSG_FRAMEBUFFEROBJECT
#define OSG_FRAMEBUFFEROBJECT 1
#include <osg/Texture>
#include <osg/buffered_value>
#include "FramebufferAttachment.h"
namespace osg
{
class FramebufferObject: public StateAttribute
{
public:
typedef std::map<GLenum, FramebufferAttachment> AttachmentMap;
FramebufferObject();
FramebufferObject(const FramebufferObject &copy, const CopyOp &copyop = CopyOp::SHALLOW_COPY);
META_StateAttribute(osg, FramebufferObject, (StateAttribute::Type)0x101010/*FRAMEBUFFEROBJECT*/);
inline const AttachmentMap &getAttachmentMap() const;
inline bool hasAttachment(GLenum attachment_point) const;
inline const FramebufferAttachment& getAttachment(GLenum attachment_point) const;
inline void setAttachment(GLenum attachment_point, const FramebufferAttachment &attachment);
int compare(const StateAttribute &sa) const;
void apply(State &state) const;
protected:
virtual ~FramebufferObject() {}
FramebufferObject &operator=(const FramebufferObject &) { return *this; }
inline void dirtyAll();
private:
AttachmentMap _attachments;
mutable buffered_value<int> _dirtyAttachmentList;
mutable buffered_value<int> _unsupported;
mutable buffered_value<GLuint> _fboID;
};
// INLINE METHODS
inline const FramebufferObject::AttachmentMap &FramebufferObject::getAttachmentMap() const
{
return _attachments;
}
inline bool FramebufferObject::hasAttachment(GLenum attachment_point) const
{
return _attachments.find(attachment_point) != _attachments.end();
}
inline const FramebufferAttachment &FramebufferObject::getAttachment(GLenum attachment_point) const
{
return _attachments.find(attachment_point)->second;
}
inline void FramebufferObject::setAttachment(GLenum attachment_point, const FramebufferAttachment &attachment)
{
_attachments[attachment_point] = attachment;
dirtyAll();
}
inline void FramebufferObject::dirtyAll()
{
_dirtyAttachmentList.setAllElementsTo(1);
}
}
#endif

View File

@@ -0,0 +1,22 @@
TOPDIR = ../..
include $(TOPDIR)/Make/makedefs
CXXFILES =\
FBOExtensions.cpp\
FramebufferObject.cpp\
Renderbuffer.cpp\
FramebufferAttachment.cpp\
fbo.cpp\
LIBS += -losgProducer -lProducer -losgText -losgGA -losgDB -losgUtil -losg $(GL_LIBS) $(X_LIBS) $(OTHER_LIBS)
INSTFILES = \
$(CXXFILES)\
GNUmakefile.inst=GNUmakefile
EXEC = osgfbo
INC += $(X_INC)
include $(TOPDIR)/Make/makerules

View File

@@ -0,0 +1,17 @@
TOPDIR = ../..
include $(TOPDIR)/Make/makedefs
CXXFILES =\
FBOExtensions.cpp\
FramebufferObject.cpp\
Renderbuffer.cpp\
FramebufferAttachment.cpp\
fbo.cpp\
LIBS += -losgProducer -lProducer -losgDB -losgText -losgUtil -losg $(GL_LIBS) $(X_LIBS) $(OTHER_LIBS)
EXEC = osgfbo
INC += $(X_INC)
include $(TOPDIR)/Make/makerules

View File

@@ -0,0 +1,53 @@
#include "Renderbuffer.h"
#include "FBOExtensions.h"
using namespace osg;
Renderbuffer::Renderbuffer()
: Object(),
_width(512),
_height(512),
_internalFormat(GL_DEPTH_COMPONENT24)
{
}
Renderbuffer::Renderbuffer(int width, int height, GLenum internalFormat)
: Object(),
_width(width),
_height(height),
_internalFormat(internalFormat)
{
}
Renderbuffer::Renderbuffer(const Renderbuffer &copy, const CopyOp &copyop)
: Object(copy, copyop),
_width(copy._width),
_height(copy._height),
_internalFormat(copy._internalFormat)
{
}
GLuint Renderbuffer::getObjectID(unsigned int contextID, const FBOExtensions *ext) const
{
GLuint &objectID = _objectID[contextID];
int &dirty = _dirty[contextID];
if (objectID == 0)
{
ext->glGenRenderbuffersEXT(1, &objectID);
if (objectID == 0)
return 0;
dirty = 1;
}
if (dirty)
{
// bind and configure
ext->glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, objectID);
ext->glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, _internalFormat, _width, _height);
dirty = 0;
}
return objectID;
}

View File

@@ -0,0 +1,114 @@
#ifndef OSG_RENDERBUFFER
#define OSG_RENDERBUFFER 1
#include <osg/Object>
#include <osg/buffered_value>
#include <osg/GL>
#ifndef GL_VERSION_1_4
#define GL_DEPTH_COMPONENT16 0x81A5
#define GL_DEPTH_COMPONENT24 0x81A6
#define GL_DEPTH_COMPONENT32 0x81A7
#endif
namespace osg
{
class FBOExtensions;
class Renderbuffer: public Object
{
public:
Renderbuffer();
Renderbuffer(int width, int height, GLenum internalFormat);
Renderbuffer(const Renderbuffer &copy, const CopyOp &copyop = CopyOp::SHALLOW_COPY);
META_Object(osg, Renderbuffer);
inline int getWidth() const;
inline int getHeight() const;
inline void setWidth(int w);
inline void setHeight(int h);
inline void setSize(int w, int h);
inline GLenum getInternalFormat() const;
inline void setInternalFormat(GLenum format);
GLuint getObjectID(unsigned int contextID, const FBOExtensions *ext) const;
inline int compare(const Renderbuffer &rb) const;
protected:
virtual ~Renderbuffer() {}
Renderbuffer &operator=(const Renderbuffer &) { return *this; }
inline void dirtyAll() const;
private:
mutable buffered_value<GLuint> _objectID;
mutable buffered_value<int> _dirty;
GLenum _internalFormat;
int _width;
int _height;
};
// INLINE METHODS
inline int Renderbuffer::getWidth() const
{
return _width;
}
inline int Renderbuffer::getHeight() const
{
return _height;
}
inline void Renderbuffer::setWidth(int w)
{
_width = w;
dirtyAll();
}
inline void Renderbuffer::setHeight(int h)
{
_height = h;
dirtyAll();
}
inline void Renderbuffer::setSize(int w, int h)
{
_width = w;
_height = h;
dirtyAll();
}
inline GLenum Renderbuffer::getInternalFormat() const
{
return _internalFormat;
}
inline void Renderbuffer::setInternalFormat(GLenum format)
{
_internalFormat = format;
dirtyAll();
}
inline void Renderbuffer::dirtyAll() const
{
_dirty.setAllElementsTo(1);
}
inline int Renderbuffer::compare(const Renderbuffer &rb) const
{
if (&rb == this) return 0;
if (_internalFormat < rb._internalFormat) return -1;
if (_internalFormat > rb._internalFormat) return 1;
if (_width < rb._width) return -1;
if (_width > rb._width) return 1;
if (_height < rb._height) return -1;
if (_height > rb._height) return 1;
return 0;
}
}
#endif

158
examples/osgfbo/osgfbo.cpp Normal file
View File

@@ -0,0 +1,158 @@
#include <osg/GL>
#include <osg/Group>
#include <osg/Geometry>
#include <osg/Geode>
#include <osg/Viewport>
#include <osg/Texture2D>
#include <osg/MatrixTransform>
#include <osgProducer/Viewer>
#include <osgDB/ReadFile>
#include "FramebufferObject.h"
#include "FramebufferAttachment.h"
#include "Renderbuffer.h"
#include "FBOExtensions.h"
// This drawable class provides the means for clearing
// the color and depth buffer and it is used in this
// example to clear the offscreen buffers. Of course
// this is just a trick, but I couldn't think of any
// cleaner way to do that (ClearNode always affects
// the main buffers).
class ClearBuffer: public osg::Drawable
{
public:
ClearBuffer() {}
ClearBuffer(const ClearBuffer &copy, const osg::CopyOp &copyop = osg::CopyOp::SHALLOW_COPY): osg::Drawable(copy, copyop) {}
META_Object(example, ClearBuffer);
void drawImplementation(osg::State &state) const
{
glPushAttrib(GL_COLOR_BUFFER_BIT);
glClearColor(0.5f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPopAttrib();
}
};
// This function builds a textured quad
osg::Node *build_quad(osg::Texture2D *tex)
{
osg::Geometry *geo = new osg::Geometry;
osg::Vec3Array *vx = new osg::Vec3Array;
vx->push_back(osg::Vec3(-10, 0, -10));
vx->push_back(osg::Vec3(10, 0, -10));
vx->push_back(osg::Vec3(10, 0, 10));
vx->push_back(osg::Vec3(-10, 0, 10));
geo->setVertexArray(vx);
osg::Vec3Array *nx = new osg::Vec3Array;
nx->push_back(osg::Vec3(0, -1, 0));
geo->setNormalArray(nx);
geo->setNormalBinding(osg::Geometry::BIND_OVERALL);
osg::Vec2Array *tx = new osg::Vec2Array;
tx->push_back(osg::Vec2(0, 0));
tx->push_back(osg::Vec2(1, 0));
tx->push_back(osg::Vec2(1, 1));
tx->push_back(osg::Vec2(0, 1));
geo->setTexCoordArray(0, tx);
geo->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4));
geo->getOrCreateStateSet()->setTextureAttributeAndModes(0, tex);
osg::Geode *geode = new osg::Geode;
geode->addDrawable(geo);
return geode;
}
// This class is provided because osg::Texture classes
// don't apply texture parameters when the image pointer
// is null. When performing render-to-texture, texture
// data must be applied as usual but a null pointer must
// be specified as pixel data.
// This is another trick: it would be better to allow
// null image pointers in osg::Texture classes.
struct MySubload: public osg::Texture2D::SubloadCallback
{
void load(const osg::Texture2D &texture, osg::State &state) const
{
glTexImage2D(GL_TEXTURE_2D, 0, texture.getInternalFormat(), texture.getTextureWidth(), texture.getTextureHeight(), texture.getBorderWidth(), GL_RGBA, GL_UNSIGNED_BYTE, 0);
}
void subload(const osg::Texture2D &texture, osg::State &state) const
{
}
};
void build_world(osg::Group *root)
{
int width = 512;
int height = 512;
// create and configure the texture that we're going
// to use as target for render-to-texture
osg::ref_ptr<osg::Texture2D> tex = new osg::Texture2D;
tex->setTextureSize(width, height);
tex->setInternalFormat(GL_RGBA);
tex->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
tex->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
tex->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
tex->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
tex->setSubloadCallback(new MySubload);
// create and configure a framebuffer object.
// We attach the texture to the first color buffer,
// and we attach a simple offscreen image (Renderbuffer)
// to the depth buffer in order to allow depth operations
osg::ref_ptr<osg::FramebufferObject> fbo = new osg::FramebufferObject();
fbo->setAttachment(GL_COLOR_ATTACHMENT0_EXT, osg::FramebufferAttachment(tex.get()));
fbo->setAttachment(GL_DEPTH_ATTACHMENT_EXT, osg::FramebufferAttachment(new osg::Renderbuffer(width, height, GL_DEPTH_COMPONENT24)));
// create a subgraph that will be rendered to texture.
// We apply the previously created FBO and a Viewport
// attribute to this subgraph.
osg::ref_ptr<osg::MatrixTransform> offscreen = new osg::MatrixTransform;
root->addChild(offscreen.get());
offscreen->getOrCreateStateSet()->setRenderBinDetails(-1, "RenderBin");
offscreen->getOrCreateStateSet()->setAttribute(fbo.get());
offscreen->getOrCreateStateSet()->setAttribute(new osg::Viewport(0, 0, width, height));
offscreen->setMatrix(osg::Matrix::lookAt(osg::Vec3(0, -20, 0), osg::Vec3(0, 0, 0), osg::Vec3(0, 0, 1)));
offscreen->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
// add a ClearBuffer drawable to the offscreen subgraph
// in order to clear the color and depth buffers
osg::ref_ptr<osg::Geode> cbuf = new osg::Geode;
cbuf->addDrawable(new ClearBuffer);
cbuf->getOrCreateStateSet()->setRenderBinDetails(-2, "RenderBin");
offscreen->addChild(cbuf.get());
// add our beloved cow the offscreen subgraph
offscreen->addChild(osgDB::readNodeFile("cow.osg"));
// now create a simple quad that will be rendered
// in the main framebuffers. The quad's texture
// will be the content of the FBO's color buffer
root->addChild(build_quad(tex.get()));
}
int main()
{
osg::ref_ptr<osg::Group> root = new osg::Group;
build_world(root.get());
osgProducer::Viewer viewer;
viewer.setUpViewer();
viewer.setSceneData(root.get());
viewer.realize();
while (!viewer.done())
{
viewer.sync();
viewer.update();
viewer.frame();
}
viewer.sync();
viewer.cleanup_frame();
viewer.sync();
return 0;
}