root/OpenSceneGraph/trunk/examples/osgfpdepth/osgfpdepth.cpp @ 11339

Revision 11339, 37.0 kB (checked in by robert, 4 years ago)

From Tim Moore, "This contains a couple of fixes to support changing FrameBufferObject? configurations on the fly; the user changes the camera attachments and calls Renderer::setCameraRequiresSetUp(). The major part of this submission is a comprehensive example of setting up floating point depth buffers. The user can change the near plane value and cycle through the available combinations of depth format and multisample buffer formats."

Line 
1/* OpenSceneGraph example, osgfpdepth.
2*
3*  Permission is hereby granted, free of charge, to any person obtaining a copy
4*  of this software and associated documentation files (the "Software"), to deal
5*  in the Software without restriction, including without limitation the rights
6*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7*  copies of the Software, and to permit persons to whom the Software is
8*  furnished to do so, subject to the following conditions:
9*
10*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16*  THE SOFTWARE.
17*/
18#include <osg/ColorMask>
19#include <osg/CullFace>
20#include <osg/Depth>
21#include <osg/FrameBufferObject>
22#include <osg/Geode>
23#include <osg/Geometry>
24#include <osg/GLExtensions>
25#include <osg/Node>
26#include <osg/NodeCallback>
27#include <osg/Notify>
28#include <osg/observer_ptr>
29#include <osg/Projection>
30#include <osg/Switch>
31#include <osg/Texture2D>
32
33#include <osgDB/ReadFile>
34#include <osgGA/GUIEventHandler>
35#include <osgUtil/Optimizer>
36
37#include <osgText/Text>
38
39#include <osgViewer/Renderer>
40#include <osgViewer/Viewer>
41#include <osgViewer/ViewerEventHandlers>
42
43#include <iostream>
44#include <sstream>
45
46/* Demonstration of floating point depth buffers. The most basic way to use
47 * a floating point depth buffer in OpenGL is to create a frame buffer
48 * object, attach a color and floating point depth texture, render,
49 * and then copy the color texture to the screen. When doing
50 * multisampling we can't use textures directly, so we have to create
51 * render buffers with the proper format. Then we let OSG handle the
52 * details of resolving the multisampling.
53 *
54 * When using a floating point depth buffer, it's advantageous to
55 * reverse the depth buffer range (and the depth test, of course) so
56 * that 0.0 corresponds to the far plane. See
57 * e.g. http://www.humus.name/index.php?ID=25 for details.
58 */
59using namespace osg;
60using namespace std;
61
62/* createFBO() and destroyFBO(), and the supporting classes and
63 * functions below, are only used to test possible valid frame buffer
64 * configurations at startup. They wouldn't be used in a normal OSG
65 * program unless we wanted to enumerate all the valid FBO
66 * combinations and let the user choose between them.
67 */
68
69// Properties of an FBO that we will try to create
70struct FboConfig
71{
72    FboConfig()
73        : colorFormat(0), depthFormat(0), redbits(0), depthBits(0),
74          depthSamples(0), coverageSamples(0)
75    {
76    }
77    FboConfig(const string& name_, GLenum colorFormat_, GLenum depthFormat_,
78              int redbits_, int depthBits_, int depthSamples_ = 0,
79              int coverageSamples_ = 0)
80        : name(name_), colorFormat(colorFormat_), depthFormat(depthFormat_),
81          redbits(redbits_), depthBits(depthBits_), depthSamples(depthSamples_),
82          coverageSamples(coverageSamples_)
83    {
84    }
85    string name;
86    GLenum colorFormat;
87    GLenum depthFormat;
88    int redbits;
89    int depthBits;
90    int depthSamples;
91    int coverageSamples;
92};
93
94// Properties of a buffer
95struct BufferConfig
96{
97    BufferConfig() {}
98    BufferConfig(const string& name_, GLenum format_, int bits_)
99        : name(name_), format(format_), bits(bits_)
100    {
101    }
102    string name;
103    GLenum format;
104    int bits;
105};
106
107typedef vector<BufferConfig> BufferConfigList;
108
109vector<FboConfig> validConfigs;
110// Ugly global variables for the viewport width and height
111int width, height;
112
113// This is only used when testing possible frame buffer configurations
114// to find valid ones.
115struct FboData
116{
117    ref_ptr<Texture2D> tex;             // color texture
118    ref_ptr<Texture2D> depthTex;        // depth texture
119    ref_ptr<FrameBufferObject> fb;      // render framebuffer
120    ref_ptr<FrameBufferObject> resolveFB; // multisample resolve target
121};
122
123Texture2D* makeDepthTexture(int width, int height, GLenum internalFormat);
124
125// Assemble lists of the valid buffer configurations, along with the
126// possibilities for multisample coverage antialiasing, if any.
127void getPossibleConfigs(GraphicsContext* gc, BufferConfigList& colorConfigs,
128                        BufferConfigList& depthConfigs,
129                        vector<int>& coverageConfigs)
130{
131    int maxSamples = 0;
132    int coverageSampleConfigs = 0;
133    unsigned contextID = gc->getState()->getContextID();
134    colorConfigs.push_back(BufferConfig("RGBA8", GL_RGBA8, 8));
135    depthConfigs.push_back(BufferConfig("D24", GL_DEPTH_COMPONENT24, 24));
136    FBOExtensions* fboe = FBOExtensions::instance(contextID, true);
137    if (!fboe->isSupported())
138        return;
139    if (fboe->isMultisampleSupported())
140        glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamples);
141    // isMultisampleCoverageSupported
142    if (isGLExtensionSupported(contextID,
143                               "GL_NV_framebuffer_multisample_coverage"))
144    {
145        glGetIntegerv(GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV,
146                      &coverageSampleConfigs);
147        coverageConfigs.resize(coverageSampleConfigs * 2 + 4);
148        glGetIntegerv(GL_MULTISAMPLE_COVERAGE_MODES_NV, &coverageConfigs[0]);
149    }
150    if (isGLExtensionSupported(contextID, "GL_ARB_depth_buffer_float"))
151        depthConfigs.push_back(BufferConfig("D32F", GL_DEPTH_COMPONENT32F, 32));
152    else if (isGLExtensionSupported(contextID, "GL_NV_depth_buffer_float"))
153        depthConfigs.push_back(BufferConfig("D32F", GL_DEPTH_COMPONENT32F_NV,
154                                            32));
155}
156
157bool checkFramebufferStatus(GraphicsContext* gc, bool silent = false)
158{
159    State& state = *gc->getState();
160    unsigned contextID = state.getContextID();
161    FBOExtensions* fboe = FBOExtensions::instance(contextID, true);
162    switch(fboe->glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT)) {
163        case GL_FRAMEBUFFER_COMPLETE_EXT:
164            break;
165        case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
166            if (!silent)
167                cout << "Unsupported framebuffer format\n";
168            return false;
169        case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
170            if (!silent)
171                cout << "Framebuffer incomplete, missing attachment\n";
172            return false;
173        case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
174            if (!silent)
175                cout << "Framebuffer incomplete, duplicate attachment\n";
176            return false;
177        case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
178            if (!silent)
179                cout << "Framebuffer incomplete, attached images must have same dimensions\n";
180            return false;
181        case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
182            if (!silent)
183                cout << "Framebuffer incomplete, attached images must have same format\n";
184            return false;
185        case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
186            if (!silent)
187                cout << "Framebuffer incomplete, missing draw buffer\n";
188            return false;
189        case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
190            if (!silent)
191                cout << "Framebuffer incomplete, missing read buffer\n";
192            return false;
193        default:
194            return false;
195    }
196    return true;
197}
198
199// Attempt to create an FBO with a certain configuration. If the FBO
200// is created with fewer bits in any of its parameters, the creation
201// is deemed to have failed. Even though the result is a valid FBO,
202// we're only interested in discrete, valid configurations.
203bool createFBO(GraphicsContext* gc, FboConfig &config, FboData &data)
204{
205    bool result = true;
206    bool multisample = config.depthSamples > 0;
207    bool csaa = config.coverageSamples > config.depthSamples;
208    data.fb = new FrameBufferObject;
209    int texWidth = 512, texHeight = 512;
210    data.tex = new Texture2D;
211    data.tex->setTextureSize(texWidth, texHeight);
212    data.tex->setInternalFormat(config.colorFormat);
213    data.tex->setSourceFormat(GL_RGBA);
214    data.tex->setSourceType(GL_FLOAT);
215    data.tex->setFilter(Texture::MIN_FILTER, Texture::LINEAR_MIPMAP_LINEAR);
216    data.tex->setFilter(Texture::MAG_FILTER, Texture::LINEAR);
217    data.tex->setWrap(Texture::WRAP_S, Texture::CLAMP_TO_EDGE);
218    data.tex->setWrap(Texture::WRAP_T, Texture::CLAMP_TO_EDGE);
219    RenderBuffer* colorRB = 0;
220    RenderBuffer* depthRB = 0;
221    if (multisample)
222    {
223        data.resolveFB = new FrameBufferObject;
224        data.resolveFB->setAttachment(Camera::COLOR_BUFFER,
225                                      FrameBufferAttachment(data.tex.get()));
226        colorRB = new RenderBuffer(texWidth, texHeight, config.colorFormat,
227                                   config.coverageSamples, config.depthSamples);
228        data.fb->setAttachment(Camera::COLOR_BUFFER,
229                               FrameBufferAttachment(colorRB));
230        depthRB = new RenderBuffer(texWidth, texHeight, config.depthFormat,
231                                   config.coverageSamples, config.depthSamples);
232        data.fb->setAttachment(Camera::DEPTH_BUFFER,
233                               FrameBufferAttachment(depthRB));
234    }
235    else
236    {
237        data.depthTex = makeDepthTexture(texWidth, texHeight,
238                                         config.depthFormat);
239        data.fb->setAttachment(Camera::COLOR_BUFFER,
240                               FrameBufferAttachment(data.tex.get()));
241        data.fb->setAttachment(Camera::DEPTH_BUFFER,
242                               FrameBufferAttachment(data.depthTex.get()));
243    }
244    State& state = *gc->getState();
245    unsigned int contextID = state.getContextID();
246    FBOExtensions* fboe = FBOExtensions::instance(contextID, true);
247
248    data.fb->apply(state);
249    result = checkFramebufferStatus(gc, true);
250    if (!result)
251    {
252        fboe->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
253        return false;
254    }
255    int query;
256    if (multisample)
257    {
258        GLuint colorRBID = colorRB->getObjectID(contextID, fboe);
259        fboe->glBindRenderbuffer(GL_RENDERBUFFER_EXT, colorRBID);
260        if (csaa)
261        {
262            fboe->glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT,
263                                               GL_RENDERBUFFER_COVERAGE_SAMPLES_NV,
264                                               &query);
265            if (query < config.coverageSamples)
266                result = false;
267            else
268                config.coverageSamples = query;
269            fboe->glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT,
270                                               GL_RENDERBUFFER_COLOR_SAMPLES_NV,
271                                               &query);
272
273            if ( query < config.depthSamples)
274               result = false;
275            else
276                config.depthSamples = query; // report back the actual number
277
278        }
279        else
280        {
281            fboe->glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT,
282                                               GL_RENDERBUFFER_SAMPLES_EXT,
283                                               &query);
284            if (query < config.depthSamples)
285                result = false;
286            else
287                config.depthSamples = query;
288        }
289    }
290    glGetIntegerv( GL_RED_BITS, &query);
291    if (query != config.redbits)
292        result = false;
293    glGetIntegerv(GL_DEPTH_BITS, &query);
294    if ( query != config.depthBits)
295        result = false;
296    if (result && multisample && data.resolveFB.valid())
297    {
298        data.resolveFB->apply(state);
299        result = checkFramebufferStatus(gc, true);
300        if (result)
301        {
302            glGetIntegerv( GL_RED_BITS, &query);
303            if (query != config.redbits)
304                result = false;
305        }
306    }
307    fboe->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
308    return result;
309}
310
311void destroyFBO(GraphicsContext* gc, FboData &data)
312{
313    data.tex = 0;
314    data.depthTex = 0;
315    data.fb = 0;
316    data.resolveFB = 0;
317    State& state = *gc->getState();
318    double availableTime = 100.0;
319    RenderBuffer::flushDeletedRenderBuffers(state.getContextID(), 0.0,
320                                            availableTime);
321    availableTime = 100.0;
322    FrameBufferObject::flushDeletedFrameBufferObjects(state.getContextID(),
323                                                      0.0, availableTime);
324}
325
326void setAttachmentsFromConfig(Camera* camera, const FboConfig& config);
327Switch* makeTexturesAndGeometry(int width, int height, Switch* sw = 0);
328
329// Application state accessed from event handlers and main function;
330// contains state that can be changed by the user and the OSG classes
331// used to display / indicate that state.
332//
333// camera - Camera with fbo, using either fp depth buffer or fixed
334// switch child 0 - texture containing rendering of scene
335// switch child 1 - fp depth buffer as texture
336// switch child 2 - integer depth buffer as texture
337// textNotAvailable- "not available" text if texture isn't valid.
338
339struct AppState : public Referenced
340{
341    AppState(osgViewer::Viewer* viewer_);
342    void setStateFromConfig(const FboConfig& config);
343    void advanceConfig(int increment);
344    void updateDisplayedTexture();
345    void updateNear();
346    virtual ~AppState() {}
347    ref_ptr<Switch> sw;         // switch between displayed texture
348    bool displayScene;
349    bool invertRange;
350    int currentConfig;
351    osgViewer::Viewer* viewer;
352    double zNear;
353    ref_ptr<Camera> camera;
354    // text displayed on the screen showing the user's choices
355    ref_ptr<Projection> textProjection;
356    ref_ptr<osgText::Text> configText;
357    ref_ptr<osgText::Text> zNearText;
358    ref_ptr<Geode> textNotAvailable;
359    ref_ptr<Geode> textInverted;
360};
361
362AppState::AppState(osgViewer::Viewer* viewer_)
363    : displayScene(true), invertRange(true), currentConfig(0),
364      viewer(viewer_), zNear(0.03125)
365{
366    sw = new Switch;
367    string fontName("fonts/arial.ttf");
368    // Text description of current config
369    configText = new osgText::Text;
370    configText->setDataVariance(Object::DYNAMIC);
371    configText->setFont(fontName);
372    configText->setPosition(Vec3(50.0f, 50.0f, 0.0f));
373    configText->setColor(Vec4(1.0, 1.0, 1.0, 1.0));
374    Geode* textGeode = new Geode;
375    textGeode->addDrawable(configText.get());
376    // Text for the near plane distance
377    zNearText = new osgText::Text;
378    zNearText->setDataVariance(Object::DYNAMIC);
379    zNearText->setFont(fontName);
380    zNearText->setPosition(Vec3(1230.0f, 50.0f, 0.0f));
381    zNearText->setColor(Vec4(1.0, 1.0, 1.0, 1.0));
382    zNearText->setAlignment(osgText::Text::RIGHT_BASE_LINE);
383    textGeode->addDrawable(zNearText.get());
384    // Projection that lets the text be placed in pixels.
385    textProjection = new Projection;
386    textProjection->setMatrix(Matrix::ortho2D(0,1280,0,1024));
387    textProjection->addChild(textGeode);
388    // "texture not available" text displayed when the user trys to
389    // display the depth texture while multisampling.
390    osgText::Text* noCanDo = new osgText::Text;
391    noCanDo->setFont(fontName);
392    noCanDo->setPosition(Vec3(512.0f, 384.0f, 0.0f));
393    noCanDo->setColor(Vec4(1.0, 0.0, 0.0, 1.0));
394    noCanDo->setText("not available");
395    textNotAvailable = new Geode;
396    textNotAvailable->addDrawable(noCanDo);
397    textProjection->addChild(textNotAvailable.get());
398    // Is the depth test inverted?
399    osgText::Text* inverted = new osgText::Text;
400    inverted->setFont(fontName);
401    inverted->setPosition(Vec3(512.0f, 50.0f, 0.0f));
402    inverted->setColor(Vec4(1.0, 1.0, 1.0, 1.0));
403    inverted->setText("inverted depth test");
404    textInverted = new Geode;
405    textInverted->addDrawable(inverted);
406    textInverted->setNodeMask(~0);
407    textProjection->addChild(textInverted);
408    textProjection->getOrCreateStateSet()->setRenderBinDetails(11, "RenderBin");
409}
410
411void AppState::setStateFromConfig(const FboConfig& config)
412{
413    Camera* camera = viewer->getSlave(0)._camera.get();
414    setAttachmentsFromConfig(camera, config);
415    osgViewer::Renderer* renderer
416        = dynamic_cast<osgViewer::Renderer*>(camera->getRenderer());
417    if (renderer)
418        renderer->setCameraRequiresSetUp(true);
419    if (configText.valid())
420    {
421        configText->setText(validConfigs[currentConfig].name);
422        configText->update();
423    }
424    updateDisplayedTexture();
425}
426
427void AppState::advanceConfig(int increment)
428{
429    currentConfig = (currentConfig + increment) % validConfigs.size();
430    setStateFromConfig(validConfigs[currentConfig]);
431}
432
433void AppState::updateDisplayedTexture()
434{
435    if (displayScene)
436        sw->setSingleChildOn(0);
437    else if (validConfigs[currentConfig].depthSamples > 0
438             || validConfigs[currentConfig].coverageSamples > 0)
439        sw->setAllChildrenOff();
440    else if (validConfigs[currentConfig].depthFormat != GL_DEPTH_COMPONENT24)
441        sw->setSingleChildOn(2);
442    else
443        sw->setSingleChildOn(3);
444    if (displayScene
445        || (validConfigs[currentConfig].depthSamples == 0
446            && validConfigs[currentConfig].coverageSamples == 0))
447        textNotAvailable->setNodeMask(0);
448    else
449        textNotAvailable->setNodeMask(~0);
450}
451
452void AppState::updateNear()
453{
454    // Assume that the viewing frustum is symmetric.
455    double fovy, aspectRatio, cNear, cFar;
456    viewer->getCamera()->getProjectionMatrixAsPerspective(fovy, aspectRatio,
457                                                          cNear, cFar);
458    viewer->getCamera()->setProjectionMatrixAsPerspective(fovy, aspectRatio,
459                                                          zNear, cFar);
460    stringstream nearStream;
461    nearStream << "near: " << zNear;
462    zNearText->setText(nearStream.str());
463    zNearText->update();
464}
465
466class ConfigHandler : public osgGA::GUIEventHandler
467{
468public:
469
470    ConfigHandler(AppState* appState)
471        : _appState(appState)
472    {
473    }
474
475    virtual bool handle(const osgGA::GUIEventAdapter& ea,
476                        osgGA::GUIActionAdapter& aa,
477                        Object*, NodeVisitor* /*nv*/)
478    {
479        if (ea.getHandled()) return false;
480        osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
481        if (!viewer) return false;
482        switch(ea.getEventType())
483        {
484        case osgGA::GUIEventAdapter::KEYUP:
485        {
486            if (ea.getKey()=='d')
487            {
488                _appState->displayScene = !_appState->displayScene;
489                _appState->updateDisplayedTexture();
490                return true;
491            }
492            else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Right ||
493                     ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Right)
494            {
495                _appState->advanceConfig(1);
496                return true;
497            }
498            else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Left ||
499                     ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Left)
500            {
501                _appState->advanceConfig(-1);
502                return true;
503            }
504            break;
505        }
506        default:
507            break;
508        }
509        return false;
510    }
511
512    void getUsage(ApplicationUsage& usage) const
513    {
514        usage.addKeyboardMouseBinding("d", "display depth texture");
515        usage.addKeyboardMouseBinding("right arrow",
516                                      "next frame buffer configuration");
517        usage.addKeyboardMouseBinding("left arrow",
518                                      "previous frame buffer configuration");
519    }
520
521protected:
522    virtual ~ConfigHandler() {}
523    ref_ptr<AppState> _appState;
524};
525
526class DepthHandler : public osgGA::GUIEventHandler
527{
528public:
529
530    DepthHandler(AppState *appState, Depth* depth)
531        : _appState(appState), _depth(depth)
532    {
533        depth->setDataVariance(Object::DYNAMIC);
534    }
535
536    virtual bool handle(const osgGA::GUIEventAdapter& ea,
537                        osgGA::GUIActionAdapter& /*aa*/,
538                        Object*, NodeVisitor* /*nv*/)
539    {
540        if (ea.getHandled()) return false;
541        ref_ptr<Depth> depth = _depth.lock();
542        if (!depth.valid())
543            return false;
544        switch(ea.getEventType())
545        {
546        case(osgGA::GUIEventAdapter::KEYUP):
547        {
548            if (ea.getKey() == 'i')
549            {
550                _appState->invertRange = !_appState->invertRange;
551                if (!_appState->invertRange)
552                {
553                    _appState->camera->setClearDepth(1.0f);
554                    depth->setFunction(Depth::LESS);
555                    depth->setRange(0.0f, 1.0f);
556                    _appState->textInverted->setNodeMask(0);
557                }
558                else
559                {
560                    _appState->camera->setClearDepth(0.0f);
561                    depth->setFunction(Depth::GEQUAL);
562                    depth->setRange(1.0f, 0.0f);
563                    _appState->textInverted->setNodeMask(~0);
564                }
565                return true;
566            }
567            else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Up ||
568                     ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Up)
569            {
570                _appState->zNear *= 2.0;
571                _appState->updateNear();
572                return true;
573            }
574            else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Down ||
575                     ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Down)
576            {
577                _appState->zNear *= .5;
578                _appState->updateNear();
579                return true;
580            }
581            break;
582        }
583        default:
584            break;
585        }
586        return false;
587    }
588
589    void getUsage(ApplicationUsage& usage) const
590    {
591        usage.addKeyboardMouseBinding("i", "invert depth buffer range");
592        usage.addKeyboardMouseBinding("up arrow",
593                                      "double near plane distance");
594        usage.addKeyboardMouseBinding("down arrow",
595                                      "half near plane distance");
596    }
597protected:
598    virtual ~DepthHandler() {}
599    ref_ptr<AppState> _appState;
600    observer_ptr<Depth> _depth;
601};
602
603Geode* createTextureQuad(Texture2D *texture)
604{
605    Vec3Array *vertices = new Vec3Array;
606    vertices->push_back(Vec3(-1.0, -1.0, 0.0));
607    vertices->push_back(Vec3(1.0, -1.0, 0.0));
608    vertices->push_back(Vec3(1.0, 1.0, 0.0));
609    vertices->push_back(Vec3(-1.0, 1.0, 0.0));
610
611    Vec2Array *texcoord = new Vec2Array;
612    texcoord->push_back(Vec2(0.0, 0.0));
613    texcoord->push_back(Vec2(1.0, 0.0));
614    texcoord->push_back(Vec2(1.0, 1.0));
615    texcoord->push_back(Vec2(0.0, 1.0));
616
617    Geometry *geom = new Geometry;
618    geom->setVertexArray(vertices);
619    geom->setTexCoordArray(0, texcoord);
620    geom->addPrimitiveSet(new DrawArrays(GL_QUADS, 0, 4));
621
622    Geode *geode = new Geode;
623    geode->addDrawable(geom);
624    geode->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture, StateAttribute::ON);
625
626    return geode;
627}
628
629struct ResizedCallback : public osg::GraphicsContext::ResizedCallback
630{
631    ResizedCallback(AppState* appState)
632        : _appState(appState)
633    {
634    }
635    void resizedImplementation(GraphicsContext* gc, int x, int y, int width,
636                               int height);
637    ref_ptr<AppState> _appState;
638};
639
640void ResizedCallback::resizedImplementation(GraphicsContext* gc, int x, int y,
641                                            int width, int height)
642{
643    gc->resizedImplementation(x, y, width, height);
644    makeTexturesAndGeometry(width, height, _appState->sw);
645    _appState->setStateFromConfig(validConfigs[_appState
646                                               ->currentConfig]);
647    osgViewer::Viewer* viewer = _appState->viewer;
648    Viewport* vp = viewer->getSlave(0)._camera->getViewport();
649    if (vp)
650    {
651        double oldWidth = vp->width(), oldHeight = vp->height();
652        double aspectRatioChange
653            = (width / oldWidth) / (height / oldHeight);
654        vp->setViewport(0, 0, width, height);
655        if (aspectRatioChange != 1.0)
656        {
657            Camera* master = viewer->getCamera();
658            switch (master->getProjectionResizePolicy())
659            {
660            case Camera::HORIZONTAL:
661                master->getProjectionMatrix()
662                    *= Matrix::scale(1.0/aspectRatioChange,1.0,1.0);
663                break;
664            case Camera::VERTICAL:
665                master->getProjectionMatrix()
666                    *= Matrix::scale(1.0, aspectRatioChange,1.0);
667                break;
668            default:
669                break;
670            }
671        }
672    }
673}
674
675// Prefer GL_DEPTH_COMPONENT32F, otherwise use
676// GL_DEPTH_COMPONENT32F_NV if available
677GLenum depthTextureEnum = 0;
678
679// Standard OSG code for initializing osgViewer::Viewer with explicit
680// creation of own graphics context. This is also a good time to test
681// for valid frame buffer configurations; we have a valid graphics
682// context, but multithreading hasn't started, etc.
683GraphicsContext* setupGC(osgViewer::Viewer& viewer, ArgumentParser& arguments)
684{
685    int x = -1, y = -1, width = -1, height = -1;
686    while (arguments.read("--window",x,y,width,height)) {}
687
688    GraphicsContext::WindowingSystemInterface* wsi =
689        GraphicsContext::getWindowingSystemInterface();
690    if (!wsi)
691    {
692        OSG_NOTIFY(NOTICE)<<"View::setUpViewOnSingleScreen() : Error, no WindowSystemInterface available, cannot create windows."<<std::endl;
693        return 0;
694    }
695
696    DisplaySettings* ds = viewer.getDisplaySettings();
697    if (!ds)
698        ds = DisplaySettings::instance();
699    GraphicsContext::ScreenIdentifier si;
700    si.readDISPLAY();
701
702    // displayNum has not been set so reset it to 0.
703    if (si.displayNum<0) si.displayNum = 0;
704
705    bool decoration = true;
706    if (x < 0)
707    {
708        unsigned int w, h;
709        wsi->getScreenResolution(si, w, h);
710        x = 0;
711        y = 0;
712        width = w;
713        height = h;
714        decoration = false;
715    }
716
717    ref_ptr<GraphicsContext::Traits> traits
718        = new GraphicsContext::Traits(ds);
719    traits->hostName = si.hostName;
720    traits->displayNum = si.displayNum;
721    traits->screenNum = si.screenNum;
722    traits->x = x;
723    traits->y = y;
724    traits->width = width;
725    traits->height = height;
726    traits->windowDecoration = decoration;
727    traits->doubleBuffer = true;
728    traits->sharedContext = 0;
729    ref_ptr<GraphicsContext> gc
730        = GraphicsContext::createGraphicsContext(traits.get());
731    osgViewer::GraphicsWindow* gw
732        = dynamic_cast<osgViewer::GraphicsWindow*>(gc.get());
733    if (gw)
734    {
735        OSG_NOTIFY(INFO)<<"View::setUpViewOnSingleScreen - GraphicsWindow has been created successfully."<<std::endl;
736        gw->getEventQueue()->getCurrentEventState()
737            ->setWindowRectangle(0, 0, width, height);
738    }
739    else
740    {
741        OSG_NOTIFY(NOTICE)<<"  GraphicsWindow has not been created successfully."<<std::endl;
742    }
743    double fovy, aspectRatio, zNear, zFar;
744    viewer.getCamera()->getProjectionMatrixAsPerspective(fovy, aspectRatio,
745                                                         zNear, zFar);
746    double newAspectRatio = double(traits->width) / double(traits->height);
747    double aspectRatioChange = newAspectRatio / aspectRatio;
748    if (aspectRatioChange != 1.0)
749    {
750        viewer.getCamera()->getProjectionMatrix()
751            *= Matrix::scale(1.0/aspectRatioChange,1.0,1.0);
752    }
753    // Context has to be current to test for extensions
754    gc->realize();
755    gc->makeCurrent();
756    unsigned int contextID = gc->getState()->getContextID();
757    FBOExtensions* fboe = FBOExtensions::instance(contextID, true);
758    if (!fboe->isSupported())
759    {
760        OSG_NOTIFY(NOTICE) << "Frame buffer objects are not supported\n";
761        gc->releaseContext();
762        gc->close(true);
763        return 0;
764    }
765    if (isGLExtensionSupported(contextID, "GL_ARB_depth_buffer_float"))
766        depthTextureEnum = GL_DEPTH_COMPONENT32F;
767    else if (isGLExtensionSupported(contextID, "GL_NV_depth_buffer_float"))
768        depthTextureEnum = GL_DEPTH_COMPONENT32F_NV;
769    BufferConfigList colorConfigs;
770    BufferConfigList depthConfigs;
771    vector<int> coverageConfigs;
772    getPossibleConfigs(gc, colorConfigs, depthConfigs, coverageConfigs);
773    int coverageSampleConfigs = (coverageConfigs.size() - 4) / 2;
774    cout << "color configs\nname\tbits\n";
775    for (BufferConfigList::const_iterator colorItr = colorConfigs.begin(),
776             colorEnd = colorConfigs.end();
777         colorItr != colorEnd;
778         ++colorItr)
779    {
780        for (BufferConfigList::const_iterator depthItr = depthConfigs.begin(),
781             depthEnd = depthConfigs.end();
782             depthItr != depthEnd;
783             ++depthItr)
784        {
785            string root = colorItr->name + " " + depthItr->name;
786            FboConfig config(root, colorItr->format, depthItr->format,
787                             colorItr->bits, depthItr->bits);
788            FboData data;
789            if (createFBO(gc, config, data))
790                validConfigs.push_back(config);
791            destroyFBO(gc, data);
792            if (coverageConfigs.size() > 0)
793            {
794                //CSAA provides a list of all supported AA modes for
795                //quick enumeration
796                for (int kk = 0; kk < coverageSampleConfigs; kk++)
797                {
798                    stringstream msText;
799                    msText << root;
800                    config.depthSamples = coverageConfigs[kk*2+1];
801                    config.coverageSamples = coverageConfigs[kk*2];
802
803                    if ( config.coverageSamples == config.depthSamples )
804                    {
805                        // Normal antialiasing
806                        msText << " - " << config.depthSamples << " MSAA";
807                    }
808                    else
809                    {
810                        // coverage antialiasing
811                        msText << " - " << config.coverageSamples << "/"
812                               << config.depthSamples << " CSAA";
813                    }
814                    config.name = msText.str();
815
816                    if (createFBO(gc, config, data)) {
817                        validConfigs.push_back( config);
818                    }
819                    destroyFBO(gc, data);
820                }
821            }
822        }
823    }
824    cout << "valid frame buffer configurations:\n";
825    for (vector<FboConfig>::iterator itr = validConfigs.begin(),
826             end = validConfigs.end();
827         itr != end;
828         ++itr)
829        cout << itr->name << "\n";
830    gc->releaseContext();
831
832    return gc.release();
833}
834
835ref_ptr<Texture2D> colorTexture;
836ref_ptr<Texture2D> depthTexture;
837ref_ptr<Texture2D> depthTexture24;
838
839Texture2D* makeDepthTexture(int width, int height, GLenum internalFormat)
840{
841    Texture2D *depthTex = new Texture2D;
842    depthTex->setTextureSize(width, height);
843    depthTex->setSourceFormat(GL_DEPTH_COMPONENT);
844    depthTex->setSourceType(GL_FLOAT);
845    depthTex->setInternalFormat(internalFormat);
846    depthTex->setFilter(Texture2D::MIN_FILTER, Texture2D::NEAREST);
847    depthTex->setFilter(Texture2D::MAG_FILTER, Texture2D::NEAREST);
848    depthTex->setWrap(Texture::WRAP_S, Texture::CLAMP_TO_EDGE);
849    depthTex->setWrap(Texture::WRAP_T, Texture::CLAMP_TO_EDGE);
850    return depthTex;
851}
852
853Camera* makeRttCamera(GraphicsContext* gc, int width, int height)
854{
855    Camera* rttCamera = new Camera;
856    rttCamera->setGraphicsContext(gc);
857    rttCamera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
858    rttCamera->setClearColor(Vec4(0.0, 0.4, 0.5, 0.0));
859    // normally the depth test is inverted, although the user can
860    // change that.
861    rttCamera->setClearDepth(0.0);
862    rttCamera->setViewport(0, 0, width, height);
863    rttCamera->setDrawBuffer(GL_FRONT);
864    rttCamera->setReadBuffer(GL_FRONT);
865    rttCamera->setRenderTargetImplementation(Camera::FRAME_BUFFER_OBJECT);
866    rttCamera->setComputeNearFarMode(CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
867    return rttCamera;
868}
869
870void setAttachmentsFromConfig(Camera* camera, const FboConfig& config)
871{
872    // XXX Detaching the old buffers may not be necessary.
873    if (!camera->getBufferAttachmentMap().empty())
874    {
875        camera->detach(Camera::COLOR_BUFFER);
876        camera->detach(Camera::DEPTH_BUFFER);
877    }
878    camera->attach(Camera::COLOR_BUFFER, colorTexture.get(), 0, 0, false,
879                   config.coverageSamples, config.depthSamples);
880    if (config.coverageSamples != 0 || config.depthSamples != 0)
881        camera->attach(Camera::DEPTH_BUFFER, config.depthFormat);
882    else if (config.depthFormat == GL_DEPTH_COMPONENT24)
883        camera->attach(Camera::DEPTH_BUFFER, depthTexture24);
884    else
885        camera->attach(Camera::DEPTH_BUFFER, depthTexture);
886}
887
888// Create the parts of the local scene graph used to display the final
889// results.
890Switch* makeTexturesAndGeometry(int width, int height, Switch* sw)
891{
892    if (!sw)
893        sw = new Switch;
894    colorTexture = new Texture2D;
895    colorTexture->setTextureSize(width, height);
896    colorTexture->setInternalFormat(GL_RGBA);
897    colorTexture->setFilter(Texture2D::MIN_FILTER, Texture2D::LINEAR);
898    colorTexture->setFilter(Texture2D::MAG_FILTER, Texture2D::LINEAR);
899    colorTexture->setWrap(Texture::WRAP_S, Texture::CLAMP_TO_EDGE);
900    colorTexture->setWrap(Texture::WRAP_T, Texture::CLAMP_TO_EDGE);
901    colorTexture->setBorderColor(Vec4(0, 0, 0, 0));
902
903    depthTexture24 = makeDepthTexture(width, height, GL_DEPTH_COMPONENT24);
904    if (depthTextureEnum)
905        depthTexture = makeDepthTexture(width, height, depthTextureEnum);
906    else
907        depthTexture = depthTexture24;
908    sw->removeChildren(0, sw->getNumChildren());
909    sw->addChild(createTextureQuad(colorTexture));
910    sw->addChild(createTextureQuad(depthTexture));
911    sw->addChild(createTextureQuad(depthTexture24));
912    sw->setSingleChildOn(0);
913    return sw;
914}
915
916int main(int argc, char **argv)
917{
918    // use an ArgumentParser object to manage the program arguments.
919    ArgumentParser arguments(&argc,argv);
920    arguments.getApplicationUsage()
921        ->setDescription(arguments.getApplicationName()
922                         + " demonstrates using a floating point depth buffer.\nThe user can invert the depth buffer range and choose among available multi-sample configurations.");
923    arguments.getApplicationUsage()
924        ->addCommandLineOption("--far <number>", "Set far plane value");
925    // if user request help write it out to cout.
926    if (arguments.read("-h") || arguments.read("--help"))
927    {
928        arguments.getApplicationUsage()->write(std::cout);
929        return 1;
930    }
931    float zFar = 500.0f;
932    while (arguments.read("--far", zFar))
933        ;
934    // construct the viewer.
935    osgViewer::Viewer viewer;
936    ref_ptr<AppState> appState = new AppState(&viewer);
937    viewer.addEventHandler(new osgViewer::StatsHandler);
938    viewer.addEventHandler(new osgViewer::WindowSizeHandler);
939    viewer.addEventHandler(new osgViewer::ScreenCaptureHandler);
940    // The aspect ratio is set to the correct ratio for the window in
941    // setupGC().
942    viewer.getCamera()
943        ->setProjectionMatrixAsPerspective(40.0, 1.0, appState->zNear, zFar);
944    GraphicsContext* gc = setupGC(viewer, arguments);
945    if (!gc)
946        return 1;
947    gc->setResizedCallback(new ResizedCallback(appState.get()));
948    const GraphicsContext::Traits* traits = gc->getTraits();
949    width = traits->width;
950    height = traits->height;
951    ref_ptr<Node> loadedModel = osgDB::readNodeFiles(arguments);
952    if (!loadedModel) {
953        cerr << "couldn't load " << argv[1] << "\n";
954        return 1;
955    }
956    osgUtil::Optimizer optimizer;
957    optimizer.optimize(loadedModel.get());
958    // creates texture to be rendered
959    Switch* sw = makeTexturesAndGeometry(width, height, appState->sw);
960    ref_ptr<Camera> rttCamera = makeRttCamera(gc, width, height);
961    rttCamera->setRenderOrder(Camera::PRE_RENDER);
962    viewer.addSlave(rttCamera);
963    appState->camera = rttCamera;
964    // geometry and slave camera to display the result
965    Group* displayRoot = new Group;
966    displayRoot->addChild(sw);
967    displayRoot->addChild(appState->textProjection);
968    StateSet* displaySS = displayRoot->getOrCreateStateSet();
969    displaySS->setMode(GL_LIGHTING, StateAttribute::OFF);
970    displaySS->setMode(GL_DEPTH_TEST, StateAttribute::OFF);
971    Camera* texCamera = new Camera;
972    texCamera->setGraphicsContext(gc);
973    texCamera->setClearMask(GL_COLOR_BUFFER_BIT);
974    texCamera->setClearColor(Vec4(0.0, 0.0, 0.0, 0.0));
975    texCamera->setReferenceFrame(Camera::ABSOLUTE_RF);
976    texCamera->setViewport(0, 0, width, height);
977    texCamera->setDrawBuffer(GL_BACK);
978    texCamera->setReadBuffer(GL_BACK);
979    texCamera->addChild(displayRoot);
980    texCamera->setAllowEventFocus(false);
981    texCamera->setCullingMode(CullSettings::NO_CULLING);
982    texCamera->setProjectionResizePolicy(Camera::FIXED);
983    viewer.addSlave(texCamera, Matrixd(), Matrixd(), false);
984    viewer.addEventHandler(new ConfigHandler(appState));
985
986    // add model to the viewer.
987    Group* sceneRoot = new Group;
988    StateSet* sceneSS = sceneRoot->getOrCreateStateSet();
989    Depth* depth = new Depth(Depth::GEQUAL, 1.0, 0.0);
990    sceneSS->setAttributeAndModes(depth,(StateAttribute::ON
991                                         | StateAttribute::OVERRIDE));
992#if 0
993    // Hack to work around Blender osg export bug
994    sceneSS->setAttributeAndModes(new CullFace(CullFace::BACK));
995#endif
996    sceneRoot->addChild(loadedModel.get());
997    appState->setStateFromConfig(validConfigs[0]);
998    appState->updateNear();
999    viewer.addEventHandler(new DepthHandler(appState.get(), depth));
1000    // add the help handler
1001    viewer.addEventHandler(new osgViewer
1002                           ::HelpHandler(arguments.getApplicationUsage()));
1003
1004    viewer.setSceneData(sceneRoot);
1005
1006    return viewer.run();
1007}
Note: See TracBrowser for help on using the browser.