diff --git a/examples/osgpbuffer/RenderToTextureStage.cpp b/examples/osgpbuffer/RenderToTextureStage.cpp new file mode 100644 index 000000000..e63c6bd41 --- /dev/null +++ b/examples/osgpbuffer/RenderToTextureStage.cpp @@ -0,0 +1,80 @@ +#include +//#include + +#include "RenderToTextureStage.h" + +//using namespace osg; +//using namespace osgUtil; + +// register a RenderToTextureStage prototype with the RenderBin prototype list. +//RegisterRenderBinProxy s_registerRenderToTextureStageProxy; + +MyRenderToTextureStage::MyRenderToTextureStage() +{ + _pbuffer = 0L; +} + +MyRenderToTextureStage::~MyRenderToTextureStage() +{ +} + +void MyRenderToTextureStage::reset() +{ + RenderStage::reset(); +} + +void MyRenderToTextureStage::draw(osg::State& state, osgUtil::RenderLeaf*& previous) +{ + if (_pbuffer && _texture.valid()) + { + // Create pbuffer texture + const unsigned int contextID = state.getContextID(); + GLuint& handle = _texture->getTextureObject(contextID); + if (handle == 0) + { + // Create dynamic texture, subload callback required. + _texture->apply(state); + } + + HDC hdc = ::wglGetCurrentDC(); + HGLRC hglrc = ::wglGetCurrentContext(); + + // Release pbuffer from "render to texture". + _pbuffer->releaseTexImage(); + + // Make the p-buffer's context current. + _pbuffer->makeCurrent(); + + // Render in p-buffer. + RenderStage::draw(state,previous); + + // restore window's context as current. + if (!::wglMakeCurrent(hdc, hglrc)) + { + assert(0); + } + + if (true /*_isRenderTextureSupported*/) + { + // transfer contents of p-buffer to texture + _pbuffer->bindTexImage(handle); + } + else + { +// TODO: +// _pbuffer->copyTexImage(state); + } + + } + else + { + RenderStage::draw(state,previous); + + // now copy the rendered image to attached texture. + if (_texture.valid()) + _texture->copyTexImage2D(state,_viewport->x(),_viewport->y(),_viewport->width(),_viewport->height()); + + if (_image.valid()) + _image->readPixels(_viewport->x(),_viewport->y(),_viewport->width(),_viewport->height(),GL_RGBA,GL_UNSIGNED_BYTE); + } +} diff --git a/examples/osgpbuffer/RenderToTextureStage.h b/examples/osgpbuffer/RenderToTextureStage.h new file mode 100644 index 000000000..8816eb663 --- /dev/null +++ b/examples/osgpbuffer/RenderToTextureStage.h @@ -0,0 +1,60 @@ +//C++ header - Open Scene Graph - Copyright (C) 1998-2002 Robert Osfield +//Distributed under the terms of the GNU Library General Public License (LGPL) +//as published by the Free Software Foundation. + +#ifndef RENDERTOTEXTURESTAGE +#define RENDERTOTEXTURESTAGE 1 + +#include + +#include + +#include "pbuffer.h" + +// namespace osgUtil { + +/** + * RenderStage which copies the final image to an attached texture or image. + * Generally used as a pre-rendering stage. + */ +class /*OSGUTIL_EXPORT*/ MyRenderToTextureStage : public osgUtil::RenderStage +{ + public: + + + MyRenderToTextureStage(); + + virtual osg::Object* cloneType() const { return new MyRenderToTextureStage(); } + virtual osg::Object* clone(const osg::CopyOp&) const { return new MyRenderToTextureStage(); } // note only implements a clone of type. + virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast(obj)!=0L; } + virtual const char* libraryName() const { return ""; } + virtual const char* className() const { return "MyRenderToTextureStage"; } + + inline void setPBuffer(PBuffer* pbuffer) { _pbuffer = pbuffer; } + + virtual void reset(); + + void setTexture(osg::Texture2D* texture) { _texture = texture; } + osg::Texture2D* getTexture() { return _texture.get(); } + + void setImage(osg::Image* image) { _image = image; } + osg::Image* getImage() { return _image.get(); } + + virtual void draw(osg::State& state,osgUtil::RenderLeaf*& previous); + + public: + + + protected: + + virtual ~MyRenderToTextureStage(); + + osg::ref_ptr _texture; + osg::ref_ptr _image; + PBuffer* _pbuffer; +}; + +// } + +#endif + diff --git a/examples/osgpbuffer/osgpbuffer.cpp b/examples/osgpbuffer/osgpbuffer.cpp new file mode 100644 index 000000000..f278a4178 --- /dev/null +++ b/examples/osgpbuffer/osgpbuffer.cpp @@ -0,0 +1,670 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include "RenderToTextureStage.h" +#include "pbuffer.h" + +PBuffer* g_pPixelBuffer; + +class MyUpdateCallback : public osg::NodeCallback +{ + public: + + MyUpdateCallback(osg::Node* subgraph): + _subgraph(subgraph) {} + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + // traverse the subgraph to update any nodes. + if (_subgraph.valid()) _subgraph->accept(*nv); + + // must traverse the Node's subgraph + traverse(node,nv); + } + + osg::ref_ptr _subgraph; +}; + +class MyCullCallback : public osg::NodeCallback +{ + public: + + MyCullCallback(osg::Node* subgraph,osg::Texture2D* texture): + _subgraph(subgraph), + _texture(texture) + { + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + + osgUtil::CullVisitor* cullVisitor = dynamic_cast(nv); + if (cullVisitor && _texture.valid() && _subgraph.valid()) + doPreRender(*node,*cullVisitor); + + // must traverse the subgraph + traverse(node,nv); + } + + void doPreRender(osg::Node& node, osgUtil::CullVisitor& cv); + + osg::ref_ptr _subgraph; + osg::ref_ptr _texture; + osg::ref_ptr _localState; + +}; + + +void MyCullCallback::doPreRender(osg::Node&, osgUtil::CullVisitor& cv) +{ + const osg::BoundingSphere& bs = _subgraph->getBound(); + if (!bs.valid()) + { + osg::notify(osg::WARN) << "bb invalid"<<_subgraph.get()< rtts = new MyRenderToTextureStage; + rtts->setPBuffer(g_pPixelBuffer); + + // set up lighting. + // currently ignore lights in the scene graph itself.. + // will do later. + osgUtil::RenderStage* previous_stage = cv.getCurrentRenderBin()->_stage; + + // set up the background color and clear mask. + rtts->setClearColor(osg::Vec4(0.1f,0.9f,0.3f,1.0f)); + rtts->setClearMask(previous_stage->getClearMask()); + + // set up to charge the same RenderStageLighting is the parent previous stage. + rtts->setRenderStageLighting(previous_stage->getRenderStageLighting()); + + + // record the render bin, to be restored after creation + // of the render to text + osgUtil::RenderBin* previousRenderBin = cv.getCurrentRenderBin(); + + // set the current renderbin to be the newly created stage. + cv.setCurrentRenderBin(rtts.get()); + + float znear = 1.0f*bs.radius(); + float zfar = 3.0f*bs.radius(); + + // 2:1 aspect ratio as per flag geomtry below. + float top = 0.25f*znear; + float right = 0.5f*znear; + + znear *= 0.9f; + zfar *= 1.1f; + + // set up projection. + osg::RefMatrix* projection = new osg::RefMatrix; + projection->makeFrustum(-right,right,-top,top,znear,zfar); + + cv.pushProjectionMatrix(projection); + + osg::RefMatrix* matrix = new osg::RefMatrix; + matrix->makeLookAt(bs.center()+osg::Vec3(0.0f,2.0f,0.0f)*bs.radius(),bs.center(),osg::Vec3(0.0f,0.0f,1.0f)); + + cv.pushModelViewMatrix(matrix); + + if (!_localState) _localState = new osg::StateSet; + + cv.pushStateSet(_localState.get()); + + { + // traverse the subgraph + _subgraph->accept(cv); + } + + cv.popStateSet(); + + // restore the previous model view matrix. + cv.popModelViewMatrix(); + + // restore the previous model view matrix. + cv.popProjectionMatrix(); + + // restore the previous renderbin. + cv.setCurrentRenderBin(previousRenderBin); + + if (rtts->_renderGraphList.size()==0 && rtts->_bins.size()==0) + { + // getting to this point means that all the subgraph has been + // culled by small feature culling or is beyond LOD ranges. + return; + } + + + + int height = 512; + int width = 512; + + + const osg::Viewport& viewport = *cv.getViewport(); + + // offset the impostor viewport from the center of the main window + // viewport as often the edges of the viewport might be obscured by + // other windows, which can cause image/reading writing problems. + int center_x = viewport.x()+viewport.width()/2; + int center_y = viewport.y()+viewport.height()/2; + + osg::Viewport* new_viewport = new osg::Viewport; +// new_viewport->setViewport(center_x-width/2,center_y-height/2,width,height); + new_viewport->setViewport(0,0,width,height); + rtts->setViewport(new_viewport); + + _localState->setAttribute(new_viewport); + + // and the render to texture stage to the current stages + // dependancy list. + cv.getCurrentRenderBin()->_stage->addToDependencyList(rtts.get()); + + // if one exist attach texture to the RenderToTextureStage. + if (_texture.valid()) rtts->setTexture(_texture.get()); + + // if one exist attach image to the RenderToTextureStage. +// if (_image.valid()) rtts->setImage(_image.get()); + +} + + +// call back which cretes a deformation field to oscilate the model. +class MyGeometryCallback : + public osg::Drawable::UpdateCallback, + public osg::Drawable::AttributeFunctor +{ + public: + + MyGeometryCallback(const osg::Vec3& o, + const osg::Vec3& x,const osg::Vec3& y,const osg::Vec3& z, + double period,double xphase,double amplitude): + _firstCall(true), + _startTime(0.0), + _time(0.0), + _period(period), + _xphase(xphase), + _amplitude(amplitude), + _origin(o), + _xAxis(x), + _yAxis(y), + _zAxis(z) {} + + virtual void update(osg::NodeVisitor* nv,osg::Drawable* drawable) + { + const osg::FrameStamp* fs = nv->getFrameStamp(); + double referenceTime = fs->getReferenceTime(); + if (_firstCall) + { + _firstCall = false; + _startTime = referenceTime; + } + + _time = referenceTime-_startTime; + + drawable->accept(*this); + drawable->dirtyBound(); + + osg::Geometry* geometry = dynamic_cast(drawable); + if (geometry) + { + osgUtil::SmoothingVisitor::smooth(*geometry); + } + + } + + virtual void apply(osg::Drawable::AttributeType type,unsigned int count,osg::Vec3* begin) + { + if (type == osg::Drawable::VERTICES) + { + const float TwoPI=2.0f*osg::PI; + const float phase = -_time/_period; + + osg::Vec3* end = begin+count; + for (osg::Vec3* itr=begin;itr0)?_subloadImageWidth:texture.getImage()->s(); + GLsizei height = (_subloadImageHeight>0)?_subloadImageHeight:texture.getImage()->t(); + + + bool sizeChanged = false; + if (_textureWidth==0) + { + // need to calculate texture dimension + sizeChanged = true; + _textureWidth = 1; + for (; _textureWidth < (static_cast(_subloadTextureOffsetX) + width); _textureWidth <<= 1) {} + } + + if (_textureHeight==0) + { + // need to calculate texture dimension + sizeChanged = true; + _textureHeight = 1; + for (; _textureHeight < (static_cast(_subloadTextureOffsetY) + height); _textureHeight <<= 1) {} + } + + if (sizeChanged) + { + texture.setTextureSize(_textureWidth, _textureHeight); + } +*/ +#if 0 + // reserve appropriate texture memory + glTexImage2D(GL_TEXTURE_2D, 0, texture.getInternalFormat(), + _textureWidth, _textureHeight, 0, + (GLenum) texture.getImage()->getPixelFormat(), (GLenum) texture.getImage()->getDataType(), + NULL); + + + glPixelStorei(GL_UNPACK_ROW_LENGTH,texture.getImage()->s()); + + + glTexSubImage2D(GL_TEXTURE_2D, 0, + _subloadTextureOffsetX, _subloadTextureOffsetY, + width, height, + (GLenum) texture.getImage()->getPixelFormat(), (GLenum) texture.getImage()->getDataType(), + texture.getImage()->data(_subloadImageOffsetX,_subloadImageOffsetY)); + + glPixelStorei(GL_UNPACK_ROW_LENGTH,0); +#else + glTexImage2D( GL_TEXTURE_2D, 0, texture.getInternalFormat(), _textureWidth, _textureHeight, 0, GL_RGB, GL_FLOAT, 0 ); +#endif + } + + virtual void subload(const osg::Texture2D& texture,osg::State&) const + { + osg::notify(osg::INFO)<<"doing subload"<s()); + + glTexSubImage2D(GL_TEXTURE_2D, 0, + _subloadTextureOffsetX, _subloadTextureOffsetY, + (_subloadImageWidth>0)?_subloadImageWidth:texture.getImage()->s(), (_subloadImageHeight>0)?_subloadImageHeight:texture.getImage()->t(), + (GLenum) texture.getImage()->getPixelFormat(), (GLenum) texture.getImage()->getDataType(), + texture.getImage()->data(_subloadImageOffsetX,_subloadImageOffsetY)); + + glPixelStorei(GL_UNPACK_ROW_LENGTH,0); +#else +#endif + } + + + SubloadMode _subloadMode; + mutable GLsizei _textureWidth, _textureHeight; + GLint _subloadTextureOffsetX, _subloadTextureOffsetY; + GLint _subloadImageOffsetX, _subloadImageOffsetY; + GLsizei _subloadImageWidth, _subloadImageHeight; +}; + + + +osg::Node* createPreRenderSubGraph(osg::Node* subgraph) +{ + if (!subgraph) return 0; + + // create the quad to visualize. + osg::Geometry* polyGeom = new osg::Geometry(); + + polyGeom->setSupportsDisplayList(false); + + osg::Vec3 origin(0.0f,0.0f,0.0f); + osg::Vec3 xAxis(1.0f,0.0f,0.0f); + osg::Vec3 yAxis(0.0f,0.0f,1.0f); + osg::Vec3 zAxis(0.0f,-1.0f,0.0f); + float height = 100.0f; + float width = 200.0f; + int noSteps = 20; + + osg::Vec3Array* vertices = new osg::Vec3Array; + osg::Vec3 bottom = origin; + osg::Vec3 top = origin; top.z()+= height; + osg::Vec3 dv = xAxis*(width/((float)(noSteps-1))); + + osg::Vec2Array* texcoords = new osg::Vec2Array; + osg::Vec2 bottom_texcoord(0.0f,0.0f); + osg::Vec2 top_texcoord(0.0f,1.0f); + osg::Vec2 dv_texcoord(1.0f/(float)(noSteps-1),0.0f); + + for(int i=0;ipush_back(top); + vertices->push_back(bottom); + top+=dv; + bottom+=dv; + + texcoords->push_back(top_texcoord); + texcoords->push_back(bottom_texcoord); + top_texcoord+=dv_texcoord; + bottom_texcoord+=dv_texcoord; + } + + + // pass the created vertex array to the points geometry object. + polyGeom->setVertexArray(vertices); + + polyGeom->setTexCoordArray(0,texcoords); + + osg::Vec4Array* colors = new osg::Vec4Array; + colors->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); + polyGeom->setColorArray(colors); + polyGeom->setColorBinding(osg::Geometry::BIND_OVERALL); + + polyGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP,0,vertices->size())); + + // new we need to add the texture to the Drawable, we do so by creating a + // StateSet to contain the Texture StateAttribute. + osg::StateSet* stateset = new osg::StateSet; + + // set up the texture. +// osg::Image* image = new osg::Image; +// image->setInternalTextureFormat(GL_RGBA); + + // Dynamic texture filled with data from pbuffer. + osg::Texture2D* texture = new osg::Texture2D; + //texture->setSubloadMode(osg::Texture::IF_DIRTY); + texture->setInternalFormat(GL_RGB); + texture->setTextureSize(512,512); + texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); + texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); +texture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP); +texture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP); + texture->setSubloadCallback(new MyTextureSubloadCallback()); + stateset->setTextureAttributeAndModes(0, texture,osg::StateAttribute::ON); + + polyGeom->setStateSet(stateset); + + polyGeom->setUpdateCallback(new MyGeometryCallback(origin,xAxis,yAxis,zAxis,1.0,1.0/width,0.2f)); + + osg::Geode* geode = new osg::Geode(); + geode->addDrawable(polyGeom); + + osg::Group* parent = new osg::Group; + + parent->setUpdateCallback(new MyUpdateCallback(subgraph)); + + parent->setCullCallback(new MyCullCallback(subgraph,texture)); + + parent->addChild(geode); + + return parent; +} + +void write_usage(std::ostream& out,const std::string& name) +{ + out << std::endl; + out <<"usage:"<< std::endl; + out <<" "<setCommandLineUsage(arguments.getProgramName()+" [options] filename ..."); + arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information"); + + + // construct the viewer. + osgProducer::Viewer viewer(arguments); + + // set up the value with sensible default event handlers. + viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS); + + // get details on keyboard and mouse bindings used by the viewer. + viewer.getUsage(*arguments.getApplicationUsage()); + + // if user request help write it out to cout. + if (arguments.read("-h") || arguments.read("--help")) + { + arguments.getApplicationUsage()->write(std::cout); + return 1; + } + + // any option left unread are converted into errors to write out later. + arguments.reportRemainingOptionsAsUnrecognized(); + + // report any errors if they have occured when parsing the program aguments. + if (arguments.errors()) + { + arguments.writeErrorMessages(std::cout); + return 1; + } + + // load the nodes from the commandline arguments. + osg::Node* loadedModel = osgDB::readNodeFiles(arguments); + + + if (!loadedModel) + { +// write_usage(osg::notify(osg::NOTICE),argv[0]); + return 1; + } + + // create a transform to spin the model. + osg::MatrixTransform* loadedModelTransform = new osg::MatrixTransform; + loadedModelTransform->addChild(loadedModel); + + osg::NodeCallback* nc = new osgUtil::TransformCallback(loadedModelTransform->getBound().center(),osg::Vec3(0.0f,0.0f,1.0f),osg::inDegrees(45.0f)); + loadedModelTransform->setUpdateCallback(nc); + + osg::Group* rootNode = new osg::Group(); +// rootNode->addChild(loadedModelTransform); + rootNode->addChild(createPreRenderSubGraph(loadedModelTransform)); + + + // set the scene to render + viewer.setSceneData(rootNode); + + // create the windows and run the threads. + viewer.realize(Producer::CameraGroup::ThreadPerCamera); + + g_pPixelBuffer = new PBuffer(512,512); + g_pPixelBuffer->initialize(); + + while( !viewer.done() ) + { + // wait for all cull and draw threads to complete. + viewer.sync(); + + // update the scene by traversing it with the the update visitor which will + // call all node update callbacks and animations. + viewer.update(); + + // fire off the cull and draw traversals of the scene. + viewer.frame(); + + } + + delete g_pPixelBuffer; + + return 0; +} diff --git a/examples/osgpbuffer/pbuffer.cpp b/examples/osgpbuffer/pbuffer.cpp new file mode 100644 index 000000000..fc2a5ddee --- /dev/null +++ b/examples/osgpbuffer/pbuffer.cpp @@ -0,0 +1,446 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include "pbuffer.h" + +namespace osg { + bool isWGLExtensionSupported(const char *extension); +} + + +// WGL_ARB_pbuffer +static WGLCreatePBufferProc wglCreatePBuffer; +static WGLGetPBufferDCProc wglGetPBufferDC; +static WGLReleasePBufferDCProc wglReleasePBufferDC; +static WGLDestroyPBufferProc wglDestroyPBuffer; +static WGLQueryPBufferProc wglQueryPBuffer; + +// WGL_ARB_pixel_format +static WGLGetPixelFormatAttribivProc wglGetPixelFormatAttribiv; +static WGLGetPixelFormatAttribfvProc wglGetPixelFormatAttribfv; +static WGLChoosePixelFormatProc wglChoosePixelFormat; + +// WGL_ARB_render_texture +static WGLBindTexImageProc wglBindTexImage; +static WGLReleaseTexImageProc wglReleaseTexImage; +static WGLSetPbufferAttribProc wglSetPbufferAttrib; + + +#ifdef _WIN32 + +#ifndef WGL_ARB_extensions_string +#define WGL_ARB_extensions_string 1 +typedef const char * (WINAPI * WGLGetExtensionsStringProc) (HDC hDC); +#endif + +#endif + +#ifdef _WIN32 +bool osg::isWGLExtensionSupported(const char *extension) +{ + + typedef std::set ExtensionSet; + static ExtensionSet s_extensionSet; + static const char* s_extensions = NULL; + static WGLGetExtensionsStringProc wglGetExtensionsString = (WGLGetExtensionsStringProc)osg::getGLExtensionFuncPtr("wglGetExtensionsStringARB"); + if (wglGetExtensionsString == NULL) return false; + if (s_extensions==NULL) + { + // get the extension list from OpenGL. + s_extensions = (const char*)wglGetExtensionsString(::wglGetCurrentDC()); + if (s_extensions==NULL) return false; + + // insert the ' ' delimiated extensions words into the extensionSet. + const char *startOfWord = s_extensions; + const char *endOfWord; + while ((endOfWord = strchr(startOfWord,' '))!=NULL) + { + s_extensionSet.insert(std::string(startOfWord,endOfWord)); + startOfWord = endOfWord+1; + } + if (*startOfWord!=0) s_extensionSet.insert(std::string(startOfWord)); + + osg::notify(osg::INFO)<<"OpenGL extensions supported by installed OpenGL drivers are:"<~PBuffer(); + initialize(); + } +} + + +// This function actually does the creation of the p-buffer. +// It can only be called once a window has already been created. +void PBuffer::initialize() +{ + setupGLExtenions(); + + HDC hdc = wglGetCurrentDC(); + HGLRC hglrc = wglGetCurrentContext(); + + // Query for a suitable pixel format based on the specified mode. + std::vector iattributes; + std::vector fattributes; + + // P-buffer will be used with OpenGL + iattributes.push_back(WGL_SUPPORT_OPENGL_ARB); + iattributes.push_back(true); + + // Since we are trying to create a pbuffer, the pixel format we + // request (and subsequently use) must be "p-buffer capable". + iattributes.push_back(WGL_DRAW_TO_PBUFFER_ARB); + iattributes.push_back(true); + + // Bind to texture + iattributes.push_back(WGL_BIND_TO_TEXTURE_RGBA_ARB); + iattributes.push_back(true); + +//iattributes.push_back(WGL_ACCELERATION_ARB); +//iattributes.push_back(WGL_FULL_ACCELERATION_ARB); + + if (_RGB) + { + iattributes.push_back(WGL_PIXEL_TYPE_ARB); + iattributes.push_back(WGL_TYPE_RGBA_ARB); + + // We require a minimum of 8-bits for each R, G, B, and A. + iattributes.push_back(WGL_RED_BITS_ARB); + iattributes.push_back(8); + iattributes.push_back(WGL_GREEN_BITS_ARB); + iattributes.push_back(8); + iattributes.push_back(WGL_BLUE_BITS_ARB); + iattributes.push_back(8); + if (_minimumNumberAlphaBits > 0) + { + iattributes.push_back(WGL_ALPHA_BITS_ARB); + iattributes.push_back(_minimumNumberAlphaBits); + } + } + else + { + iattributes.push_back(WGL_PIXEL_TYPE_ARB); + iattributes.push_back(WGL_TYPE_COLORINDEX_ARB); + } + + iattributes.push_back(WGL_DOUBLE_BUFFER_ARB); + iattributes.push_back(_doubleBuffer); + + if (_minimumNumberDepthBits > 0) + { + iattributes.push_back(WGL_DEPTH_BITS_ARB); + iattributes.push_back(_minimumNumberDepthBits); + } + + if (_minimumNumberStencilBits > 0) + { + iattributes.push_back(WGL_STENCIL_BITS_ARB); + iattributes.push_back(_minimumNumberStencilBits); + } + + if (_minimumNumberAccumulationBits > 0) + { + iattributes.push_back(WGL_ACCUM_BITS_ARB); + iattributes.push_back(_minimumNumberAccumulationBits); + } + + // Terminate array + iattributes.push_back(0); + + + // Now obtain a list of pixel formats that meet these minimum requirements. + int format; + int pformat[MAX_PFORMATS]; + unsigned int nformats=0; + if ( !wglChoosePixelFormat( hdc, &iattributes.front(), &fattributes.front(), MAX_PFORMATS, pformat, &nformats ) ) + { + osg::notify(osg::FATAL)<< "pbuffer creation error: Couldn't find a suitable pixel format." < pbattr; + + // Texture format + pbattr.push_back(WGL_TEXTURE_FORMAT_ARB); + pbattr.push_back(WGL_TEXTURE_RGBA_ARB); +#if 1 + // Texture target + pbattr.push_back(WGL_TEXTURE_TARGET_ARB); + pbattr.push_back(WGL_TEXTURE_2D_ARB); +#else + // Cubemap + pbattr.push_back(WGL_TEXTURE_TARGET_ARB); + pbattr.push_back(WGL_TEXTURE_CUBE_MAP_ARB); + + // Cubemap face + pbattr.push_back(WGL_CUBE_MAP_FACE_ARB); + pbattr.push_back(WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB); +#endif + // Terminate array + pbattr.push_back(0); + + iattributes[0] = 0; + _hPBuffer = wglCreatePBuffer( hdc, format, _width, _height, &pbattr.front() ); + if ( !_hPBuffer ) + { + DWORD err = GetLastError(); + osg::notify(osg::FATAL)<< "pbuffer creation error: wglCreatePBufferARB() failed\n" < +#include "GL/gl.h" +#include +#include "GL/wglext.h" +#include +*/ + +#include + +#if defined(WIN32) + #define WIN32_LEAN_AND_MEAN + #include +#endif + + +#ifndef WGL_ARB_pbuffer +#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_DRAW_TO_BITMAP_ARB 0x2002 +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_NEED_PALETTE_ARB 0x2004 +#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005 +#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 +#define WGL_SWAP_METHOD_ARB 0x2007 +#define WGL_NUMBER_OVERLAYS_ARB 0x2008 +#define WGL_NUMBER_UNDERLAYS_ARB 0x2009 +#define WGL_TRANSPARENT_ARB 0x200A +#define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037 +#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038 +#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039 +#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A +#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B +#define WGL_SHARE_DEPTH_ARB 0x200C +#define WGL_SHARE_STENCIL_ARB 0x200D +#define WGL_SHARE_ACCUM_ARB 0x200E +#define WGL_SUPPORT_GDI_ARB 0x200F +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_STEREO_ARB 0x2012 +#define WGL_PIXEL_TYPE_ARB 0x2013 +#define WGL_COLOR_BITS_ARB 0x2014 +#define WGL_RED_BITS_ARB 0x2015 +#define WGL_RED_SHIFT_ARB 0x2016 +#define WGL_GREEN_BITS_ARB 0x2017 +#define WGL_GREEN_SHIFT_ARB 0x2018 +#define WGL_BLUE_BITS_ARB 0x2019 +#define WGL_BLUE_SHIFT_ARB 0x201A +#define WGL_ALPHA_BITS_ARB 0x201B +#define WGL_ALPHA_SHIFT_ARB 0x201C +#define WGL_ACCUM_BITS_ARB 0x201D +#define WGL_ACCUM_RED_BITS_ARB 0x201E +#define WGL_ACCUM_GREEN_BITS_ARB 0x201F +#define WGL_ACCUM_BLUE_BITS_ARB 0x2020 +#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_AUX_BUFFERS_ARB 0x2024 +#define WGL_NO_ACCELERATION_ARB 0x2025 +#define WGL_GENERIC_ACCELERATION_ARB 0x2026 +#define WGL_FULL_ACCELERATION_ARB 0x2027 +#define WGL_SWAP_EXCHANGE_ARB 0x2028 +#define WGL_SWAP_COPY_ARB 0x2029 +#define WGL_SWAP_UNDEFINED_ARB 0x202A +#define WGL_TYPE_RGBA_ARB 0x202B +#define WGL_TYPE_COLORINDEX_ARB 0x202C +#define WGL_DRAW_TO_PBUFFER_ARB 0x202D +#define WGL_MAX_PBUFFER_PIXELS_ARB 0x202E +#define WGL_MAX_PBUFFER_WIDTH_ARB 0x202F +#define WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030 +#define WGL_PBUFFER_LARGEST_ARB 0x2033 +#define WGL_PBUFFER_WIDTH_ARB 0x2034 +#define WGL_PBUFFER_HEIGHT_ARB 0x2035 +#define WGL_PBUFFER_LOST_ARB 0x2036 +#endif + + +#ifndef WGL_ARB_pbuffer +#define WGL_ARB_pbuffer 1 + +DECLARE_HANDLE(HPBUFFERARB); + +typedef HPBUFFERARB (WINAPI * WGLCreatePBufferProc) ( + HDC hDC, + int iPixelFormat, + int iWidth, + int iHeight, + const int *piAttribList); +typedef HDC (WINAPI * WGLGetPBufferDCProc) (HPBUFFERARB hPbuffer); +typedef int (WINAPI * WGLReleasePBufferDCProc) ( + HPBUFFERARB hPbuffer, + HDC hDC); +typedef BOOL (WINAPI * WGLDestroyPBufferProc) (HPBUFFERARB hPbuffer); +typedef BOOL (WINAPI * WGLQueryPBufferProc) ( + HPBUFFERARB hPbuffer, + int iAttribute, + int *piValue); +#endif + + +#ifndef WGL_ARB_pixel_format +#define WGL_ARB_pixel_format 1 +typedef BOOL (WINAPI * WGLGetPixelFormatAttribivProc) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); +typedef BOOL (WINAPI * WGLGetPixelFormatAttribfvProc) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues); +typedef BOOL (WINAPI * WGLChoosePixelFormatProc) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); +#endif + + + +#ifndef WGL_ARB_render_texture +#define WGL_BIND_TO_TEXTURE_RGB_ARB 0x2070 +#define WGL_BIND_TO_TEXTURE_RGBA_ARB 0x2071 +#define WGL_TEXTURE_FORMAT_ARB 0x2072 +#define WGL_TEXTURE_TARGET_ARB 0x2073 +#define WGL_MIPMAP_TEXTURE_ARB 0x2074 +#define WGL_TEXTURE_RGB_ARB 0x2075 +#define WGL_TEXTURE_RGBA_ARB 0x2076 +#define WGL_NO_TEXTURE_ARB 0x2077 +#define WGL_TEXTURE_CUBE_MAP_ARB 0x2078 +#define WGL_TEXTURE_1D_ARB 0x2079 +#define WGL_TEXTURE_2D_ARB 0x207A +#define WGL_NO_TEXTURE_ARB 0x2077 +#define WGL_MIPMAP_LEVEL_ARB 0x207B +#define WGL_CUBE_MAP_FACE_ARB 0x207C +#define WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x207D +#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x207E +#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x207F +#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x2080 +#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x2081 +#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x2082 +#define WGL_FRONT_LEFT_ARB 0x2083 +#define WGL_FRONT_RIGHT_ARB 0x2084 +#define WGL_BACK_LEFT_ARB 0x2085 +#define WGL_BACK_RIGHT_ARB 0x2086 +#define WGL_AUX0_ARB 0x2087 +#define WGL_AUX1_ARB 0x2088 +#define WGL_AUX2_ARB 0x2089 +#define WGL_AUX3_ARB 0x208A +#define WGL_AUX4_ARB 0x208B +#define WGL_AUX5_ARB 0x208C +#define WGL_AUX6_ARB 0x208D +#define WGL_AUX7_ARB 0x208E +#define WGL_AUX8_ARB 0x208F +#define WGL_AUX9_ARB 0x2090 +#endif + +#ifndef WGL_ARB_render_texture +#define WGL_ARB_render_texture 1 +typedef BOOL (WINAPI * WGLBindTexImageProc) (HPBUFFERARB hPbuffer, int iBuffer); +typedef BOOL (WINAPI * WGLReleaseTexImageProc) (HPBUFFERARB hPbuffer, int iBuffer); +typedef BOOL (WINAPI * WGLSetPbufferAttribProc) (HPBUFFERARB hPbuffer, const int * piAttribList); +#endif + + +#define MAX_PFORMATS 256 +#define MAX_ATTRIBS 32 + + + +class PBuffer +{ + private: + + HDC _hDC; // Handle to a device context. + HGLRC _hGLcontext; // Handle to a GL context. + HPBUFFERARB _hPBuffer; // Handle to a pbuffer. + int _width; + int _height; + + bool _doubleBuffer; + bool _RGB; + bool _shareLists; + unsigned int _minimumNumberDepthBits; + unsigned int _minimumNumberAlphaBits; + unsigned int _minimumNumberStencilBits; + unsigned int _minimumNumberAccumulationBits; + + bool _isPBufferSupported; + bool _isPixelFormatSupported; + bool _isRenderTextureSupported; + + public: + + PBuffer(const int width, const int height ); + ~PBuffer(); + void handleModeSwitch(); + void makeCurrent(); + void initialize(); + void bindTexImage(GLuint textureID); + void releaseTexImage(); + + + protected: + + void setupGLExtenions(); + +}; + +#endif \ No newline at end of file