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

Revision 11420, 37.5 kB (checked in by robert, 4 years ago)

Fixes for building OSG with OSG_USE_REF_PTR_IMPLICIT_OUTPUT_CONVERSION set to OFF.

Fixed copy and paste error in Camera::getImplicitBufferAttachmentResolveMask().

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(~0u);
407    textProjection->addChild(textInverted.get());
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(0u);
448    else
449        textNotAvailable->setNodeMask(~0u);
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(0u);
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(~0u);
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.get());
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() ? viewer.getDisplaySettings() : DisplaySettings::instance().get();
697    GraphicsContext::ScreenIdentifier si;
698    si.readDISPLAY();
699
700    // displayNum has not been set so reset it to 0.
701    if (si.displayNum<0) si.displayNum = 0;
702
703    bool decoration = true;
704    if (x < 0)
705    {
706        unsigned int w, h;
707        wsi->getScreenResolution(si, w, h);
708        x = 0;
709        y = 0;
710        width = w;
711        height = h;
712        decoration = false;
713    }
714
715    ref_ptr<GraphicsContext::Traits> traits
716        = new GraphicsContext::Traits(ds);
717    traits->hostName = si.hostName;
718    traits->displayNum = si.displayNum;
719    traits->screenNum = si.screenNum;
720    traits->x = x;
721    traits->y = y;
722    traits->width = width;
723    traits->height = height;
724    traits->windowDecoration = decoration;
725    traits->doubleBuffer = true;
726    traits->sharedContext = 0;
727    ref_ptr<GraphicsContext> gc
728        = GraphicsContext::createGraphicsContext(traits.get());
729    osgViewer::GraphicsWindow* gw
730        = dynamic_cast<osgViewer::GraphicsWindow*>(gc.get());
731    if (gw)
732    {
733        OSG_NOTIFY(INFO)<<"View::setUpViewOnSingleScreen - GraphicsWindow has been created successfully."<<std::endl;
734        gw->getEventQueue()->getCurrentEventState()
735            ->setWindowRectangle(0, 0, width, height);
736    }
737    else
738    {
739        OSG_NOTIFY(NOTICE)<<"  GraphicsWindow has not been created successfully."<<std::endl;
740    }
741    double fovy, aspectRatio, zNear, zFar;
742    viewer.getCamera()->getProjectionMatrixAsPerspective(fovy, aspectRatio,
743                                                         zNear, zFar);
744    double newAspectRatio = double(traits->width) / double(traits->height);
745    double aspectRatioChange = newAspectRatio / aspectRatio;
746    if (aspectRatioChange != 1.0)
747    {
748        viewer.getCamera()->getProjectionMatrix()
749            *= Matrix::scale(1.0/aspectRatioChange,1.0,1.0);
750    }
751    // Context has to be current to test for extensions
752    gc->realize();
753    gc->makeCurrent();
754    unsigned int contextID = gc->getState()->getContextID();
755    FBOExtensions* fboe = FBOExtensions::instance(contextID, true);
756    if (!fboe->isSupported())
757    {
758        OSG_NOTIFY(NOTICE) << "Frame buffer objects are not supported\n";
759        gc->releaseContext();
760        gc->close(true);
761        return 0;
762    }
763    if (isGLExtensionSupported(contextID, "GL_ARB_depth_buffer_float"))
764        depthTextureEnum = GL_DEPTH_COMPONENT32F;
765    else if (isGLExtensionSupported(contextID, "GL_NV_depth_buffer_float"))
766        depthTextureEnum = GL_DEPTH_COMPONENT32F_NV;
767    BufferConfigList colorConfigs;
768    BufferConfigList depthConfigs;
769    vector<int> coverageConfigs;
770    getPossibleConfigs(gc.get(), colorConfigs, depthConfigs, coverageConfigs);
771    int coverageSampleConfigs = (coverageConfigs.size() - 4) / 2;
772    cout << "color configs\nname\tbits\n";
773    for (BufferConfigList::const_iterator colorItr = colorConfigs.begin(),
774             colorEnd = colorConfigs.end();
775         colorItr != colorEnd;
776         ++colorItr)
777    {
778        for (BufferConfigList::const_iterator depthItr = depthConfigs.begin(),
779             depthEnd = depthConfigs.end();
780             depthItr != depthEnd;
781             ++depthItr)
782        {
783            string root = colorItr->name + " " + depthItr->name;
784            FboConfig config(root, colorItr->format, depthItr->format,
785                             colorItr->bits, depthItr->bits);
786            FboData data;
787            if (createFBO(gc.get(), config, data))
788                validConfigs.push_back(config);
789            destroyFBO(gc.get(), data);
790            if (coverageConfigs.size() > 0)
791            {
792                //CSAA provides a list of all supported AA modes for
793                //quick enumeration
794                for (int kk = 0; kk < coverageSampleConfigs; kk++)
795                {
796                    stringstream msText;
797                    msText << root;
798                    config.depthSamples = coverageConfigs[kk*2+1];
799                    config.coverageSamples = coverageConfigs[kk*2];
800
801                    if ( config.coverageSamples == config.depthSamples )
802                    {
803                        // Normal antialiasing
804                        msText << " - " << config.depthSamples << " MSAA";
805                    }
806                    else
807                    {
808                        // coverage antialiasing
809                        msText << " - " << config.coverageSamples << "/"
810                               << config.depthSamples << " CSAA";
811                    }
812                    config.name = msText.str();
813
814                    if (createFBO(gc.get(), config, data)) {
815                        validConfigs.push_back( config);
816                    }
817                    destroyFBO(gc.get(), data);
818                }
819            }
820        }
821    }
822    if (validConfigs.empty())
823    {
824        cout << "no valid frame buffer configurations!\n";
825        return 0;
826    }
827    cout << "valid frame buffer configurations:\n";
828    for (vector<FboConfig>::iterator itr = validConfigs.begin(),
829             end = validConfigs.end();
830         itr != end;
831         ++itr)
832        cout << itr->name << "\n";
833    gc->releaseContext();
834
835    return gc.release();
836}
837
838ref_ptr<Texture2D> colorTexture;
839ref_ptr<Texture2D> depthTexture;
840ref_ptr<Texture2D> depthTexture24;
841
842Texture2D* makeDepthTexture(int width, int height, GLenum internalFormat)
843{
844    Texture2D *depthTex = new Texture2D;
845    depthTex->setTextureSize(width, height);
846    depthTex->setSourceFormat(GL_DEPTH_COMPONENT);
847    depthTex->setSourceType(GL_FLOAT);
848    depthTex->setInternalFormat(internalFormat);
849    depthTex->setFilter(Texture2D::MIN_FILTER, Texture2D::NEAREST);
850    depthTex->setFilter(Texture2D::MAG_FILTER, Texture2D::NEAREST);
851    depthTex->setWrap(Texture::WRAP_S, Texture::CLAMP_TO_EDGE);
852    depthTex->setWrap(Texture::WRAP_T, Texture::CLAMP_TO_EDGE);
853    return depthTex;
854}
855
856Camera* makeRttCamera(GraphicsContext* gc, int width, int height)
857{
858    Camera* rttCamera = new Camera;
859    rttCamera->setGraphicsContext(gc);
860    rttCamera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
861    rttCamera->setClearColor(Vec4(0.0, 0.4, 0.5, 0.0));
862    // normally the depth test is inverted, although the user can
863    // change that.
864    rttCamera->setClearDepth(0.0);
865    rttCamera->setViewport(0, 0, width, height);
866    rttCamera->setDrawBuffer(GL_FRONT);
867    rttCamera->setReadBuffer(GL_FRONT);
868    rttCamera->setRenderTargetImplementation(Camera::FRAME_BUFFER_OBJECT);
869    rttCamera->setComputeNearFarMode(CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
870    return rttCamera;
871}
872
873void setAttachmentsFromConfig(Camera* camera, const FboConfig& config)
874{
875    // XXX Detaching the old buffers may not be necessary.
876    if (!camera->getBufferAttachmentMap().empty())
877    {
878        camera->detach(Camera::COLOR_BUFFER);
879        camera->detach(Camera::DEPTH_BUFFER);
880    }
881    camera->attach(Camera::COLOR_BUFFER, colorTexture.get(), 0, 0, false,
882                   config.coverageSamples, config.depthSamples);
883    if (config.coverageSamples != 0 || config.depthSamples != 0)
884        camera->attach(Camera::DEPTH_BUFFER, config.depthFormat);
885    else if (config.depthFormat == GL_DEPTH_COMPONENT24)
886        camera->attach(Camera::DEPTH_BUFFER, depthTexture24.get());
887    else
888        camera->attach(Camera::DEPTH_BUFFER, depthTexture.get());
889}
890
891// Create the parts of the local scene graph used to display the final
892// results.
893Switch* makeTexturesAndGeometry(int width, int height, Switch* sw)
894{
895    if (!sw)
896        sw = new Switch;
897    colorTexture = new Texture2D;
898    colorTexture->setTextureSize(width, height);
899    colorTexture->setInternalFormat(GL_RGBA);
900    colorTexture->setFilter(Texture2D::MIN_FILTER, Texture2D::LINEAR);
901    colorTexture->setFilter(Texture2D::MAG_FILTER, Texture2D::LINEAR);
902    colorTexture->setWrap(Texture::WRAP_S, Texture::CLAMP_TO_EDGE);
903    colorTexture->setWrap(Texture::WRAP_T, Texture::CLAMP_TO_EDGE);
904    colorTexture->setBorderColor(Vec4(0, 0, 0, 0));
905
906    depthTexture24 = makeDepthTexture(width, height, GL_DEPTH_COMPONENT24);
907    if (depthTextureEnum)
908        depthTexture = makeDepthTexture(width, height, depthTextureEnum);
909    else
910        depthTexture = depthTexture24;
911    sw->removeChildren(0, sw->getNumChildren());
912    sw->addChild(createTextureQuad(colorTexture.get()));
913    sw->addChild(createTextureQuad(depthTexture.get()));
914    sw->addChild(createTextureQuad(depthTexture24.get()));
915    sw->setSingleChildOn(0);
916    return sw;
917}
918
919int main(int argc, char **argv)
920{
921    // use an ArgumentParser object to manage the program arguments.
922    ArgumentParser arguments(&argc,argv);
923    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()
924                         + " demonstrates using a floating point depth buffer.\nThe user can invert the depth buffer range and choose among available multi-sample configurations.");
925    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
926    arguments.getApplicationUsage()->addCommandLineOption("--far <number>", "Set far plane value");
927    // if user request help write it out to cout.
928    if (arguments.read("-h") || arguments.read("--help"))
929    {
930        arguments.getApplicationUsage()->write(std::cout);
931        return 1;
932    }
933    float zFar = 500.0f;
934    while (arguments.read("--far", zFar))
935        ;
936    // construct the viewer.
937    osgViewer::Viewer viewer;
938    ref_ptr<AppState> appState = new AppState(&viewer);
939    viewer.addEventHandler(new osgViewer::StatsHandler);
940    viewer.addEventHandler(new osgViewer::WindowSizeHandler);
941    viewer.addEventHandler(new osgViewer::ScreenCaptureHandler);
942    // The aspect ratio is set to the correct ratio for the window in
943    // setupGC().
944    viewer.getCamera()
945        ->setProjectionMatrixAsPerspective(40.0, 1.0, appState->zNear, zFar);
946    GraphicsContext* gc = setupGC(viewer, arguments);
947    if (!gc)
948        return 1;
949    gc->setResizedCallback(new ResizedCallback(appState.get()));
950    const GraphicsContext::Traits* traits = gc->getTraits();
951    width = traits->width;
952    height = traits->height;
953    if (arguments.argc()<=1)
954    {
955        arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
956        return 1;
957    }
958    ref_ptr<Node> loadedModel = osgDB::readNodeFiles(arguments);
959    if (!loadedModel) {
960        cerr << "couldn't load " << argv[1] << "\n";
961        return 1;
962    }
963    osgUtil::Optimizer optimizer;
964    optimizer.optimize(loadedModel.get());
965    // creates texture to be rendered
966    Switch* sw = makeTexturesAndGeometry(width, height, appState->sw.get());
967    ref_ptr<Camera> rttCamera = makeRttCamera(gc, width, height);
968    rttCamera->setRenderOrder(Camera::PRE_RENDER);
969    viewer.addSlave(rttCamera.get());
970    appState->camera = rttCamera;
971    // geometry and slave camera to display the result
972    Group* displayRoot = new Group;
973    displayRoot->addChild(sw);
974    displayRoot->addChild(appState->textProjection.get());
975    StateSet* displaySS = displayRoot->getOrCreateStateSet();
976    displaySS->setMode(GL_LIGHTING, StateAttribute::OFF);
977    displaySS->setMode(GL_DEPTH_TEST, StateAttribute::OFF);
978    Camera* texCamera = new Camera;
979    texCamera->setGraphicsContext(gc);
980    texCamera->setClearMask(GL_COLOR_BUFFER_BIT);
981    texCamera->setClearColor(Vec4(0.0, 0.0, 0.0, 0.0));
982    texCamera->setReferenceFrame(Camera::ABSOLUTE_RF);
983    texCamera->setViewport(0, 0, width, height);
984    texCamera->setDrawBuffer(GL_BACK);
985    texCamera->setReadBuffer(GL_BACK);
986    texCamera->addChild(displayRoot);
987    texCamera->setAllowEventFocus(false);
988    texCamera->setCullingMode(CullSettings::NO_CULLING);
989    texCamera->setProjectionResizePolicy(Camera::FIXED);
990    viewer.addSlave(texCamera, Matrixd(), Matrixd(), false);
991    viewer.addEventHandler(new ConfigHandler(appState.get()));
992
993    // add model to the viewer.
994    Group* sceneRoot = new Group;
995    StateSet* sceneSS = sceneRoot->getOrCreateStateSet();
996    Depth* depth = new Depth(Depth::GEQUAL, 1.0, 0.0);
997    sceneSS->setAttributeAndModes(depth,(StateAttribute::ON
998                                         | StateAttribute::OVERRIDE));
999#if 0
1000    // Hack to work around Blender osg export bug
1001    sceneSS->setAttributeAndModes(new CullFace(CullFace::BACK));
1002#endif
1003    sceneRoot->addChild(loadedModel.get());
1004    appState->setStateFromConfig(validConfigs[0]);
1005    appState->updateNear();
1006    viewer.addEventHandler(new DepthHandler(appState.get(), depth));
1007    // add the help handler
1008    viewer.addEventHandler(new osgViewer
1009                           ::HelpHandler(arguments.getApplicationUsage()));
1010
1011    viewer.setSceneData(sceneRoot);
1012
1013    return viewer.run();
1014}
Note: See TracBrowser for help on using the browser.