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

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

Ran svn propset -R svn:eol-style native . on the OpenSceneGraph

  • Property svn:eol-style set to native
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
542        ref_ptr<Depth> depth;
543        if (!_depth.lock(depth)) return false;
544
545        switch(ea.getEventType())
546        {
547        case(osgGA::GUIEventAdapter::KEYUP):
548        {
549            if (ea.getKey() == 'i')
550            {
551                _appState->invertRange = !_appState->invertRange;
552                if (!_appState->invertRange)
553                {
554                    _appState->camera->setClearDepth(1.0f);
555                    depth->setFunction(Depth::LESS);
556                    depth->setRange(0.0f, 1.0f);
557                    _appState->textInverted->setNodeMask(0u);
558                }
559                else
560                {
561                    _appState->camera->setClearDepth(0.0f);
562                    depth->setFunction(Depth::GEQUAL);
563                    depth->setRange(1.0f, 0.0f);
564                    _appState->textInverted->setNodeMask(~0u);
565                }
566                return true;
567            }
568            else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Up ||
569                     ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Up)
570            {
571                _appState->zNear *= 2.0;
572                _appState->updateNear();
573                return true;
574            }
575            else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Down ||
576                     ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Down)
577            {
578                _appState->zNear *= .5;
579                _appState->updateNear();
580                return true;
581            }
582            break;
583        }
584        default:
585            break;
586        }
587        return false;
588    }
589
590    void getUsage(ApplicationUsage& usage) const
591    {
592        usage.addKeyboardMouseBinding("i", "invert depth buffer range");
593        usage.addKeyboardMouseBinding("up arrow",
594                                      "double near plane distance");
595        usage.addKeyboardMouseBinding("down arrow",
596                                      "half near plane distance");
597    }
598protected:
599    virtual ~DepthHandler() {}
600    ref_ptr<AppState> _appState;
601    observer_ptr<Depth> _depth;
602};
603
604Geode* createTextureQuad(Texture2D *texture)
605{
606    Vec3Array *vertices = new Vec3Array;
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    vertices->push_back(Vec3(-1.0, 1.0, 0.0));
611
612    Vec2Array *texcoord = new Vec2Array;
613    texcoord->push_back(Vec2(0.0, 0.0));
614    texcoord->push_back(Vec2(1.0, 0.0));
615    texcoord->push_back(Vec2(1.0, 1.0));
616    texcoord->push_back(Vec2(0.0, 1.0));
617
618    Geometry *geom = new Geometry;
619    geom->setVertexArray(vertices);
620    geom->setTexCoordArray(0, texcoord);
621    geom->addPrimitiveSet(new DrawArrays(GL_QUADS, 0, 4));
622
623    Geode *geode = new Geode;
624    geode->addDrawable(geom);
625    geode->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture, StateAttribute::ON);
626
627    return geode;
628}
629
630struct ResizedCallback : public osg::GraphicsContext::ResizedCallback
631{
632    ResizedCallback(AppState* appState)
633        : _appState(appState)
634    {
635    }
636    void resizedImplementation(GraphicsContext* gc, int x, int y, int width,
637                               int height);
638    ref_ptr<AppState> _appState;
639};
640
641void ResizedCallback::resizedImplementation(GraphicsContext* gc, int x, int y,
642                                            int width, int height)
643{
644    gc->resizedImplementation(x, y, width, height);
645    makeTexturesAndGeometry(width, height, _appState->sw.get());
646    _appState->setStateFromConfig(validConfigs[_appState
647                                               ->currentConfig]);
648    osgViewer::Viewer* viewer = _appState->viewer;
649    Viewport* vp = viewer->getSlave(0)._camera->getViewport();
650    if (vp)
651    {
652        double oldWidth = vp->width(), oldHeight = vp->height();
653        double aspectRatioChange
654            = (width / oldWidth) / (height / oldHeight);
655        vp->setViewport(0, 0, width, height);
656        if (aspectRatioChange != 1.0)
657        {
658            Camera* master = viewer->getCamera();
659            switch (master->getProjectionResizePolicy())
660            {
661            case Camera::HORIZONTAL:
662                master->getProjectionMatrix()
663                    *= Matrix::scale(1.0/aspectRatioChange,1.0,1.0);
664                break;
665            case Camera::VERTICAL:
666                master->getProjectionMatrix()
667                    *= Matrix::scale(1.0, aspectRatioChange,1.0);
668                break;
669            default:
670                break;
671            }
672        }
673    }
674}
675
676// Prefer GL_DEPTH_COMPONENT32F, otherwise use
677// GL_DEPTH_COMPONENT32F_NV if available
678GLenum depthTextureEnum = 0;
679
680// Standard OSG code for initializing osgViewer::Viewer with explicit
681// creation of own graphics context. This is also a good time to test
682// for valid frame buffer configurations; we have a valid graphics
683// context, but multithreading hasn't started, etc.
684GraphicsContext* setupGC(osgViewer::Viewer& viewer, ArgumentParser& arguments)
685{
686    int x = -1, y = -1, width = -1, height = -1;
687    while (arguments.read("--window",x,y,width,height)) {}
688
689    GraphicsContext::WindowingSystemInterface* wsi =
690        GraphicsContext::getWindowingSystemInterface();
691    if (!wsi)
692    {
693        OSG_NOTIFY(NOTICE)<<"View::setUpViewOnSingleScreen() : Error, no WindowSystemInterface available, cannot create windows."<<std::endl;
694        return 0;
695    }
696
697    DisplaySettings* ds = viewer.getDisplaySettings() ? viewer.getDisplaySettings() : DisplaySettings::instance().get();
698    GraphicsContext::ScreenIdentifier si;
699    si.readDISPLAY();
700
701    // displayNum has not been set so reset it to 0.
702    if (si.displayNum<0) si.displayNum = 0;
703
704    bool decoration = true;
705    if (x < 0)
706    {
707        unsigned int w, h;
708        wsi->getScreenResolution(si, w, h);
709        x = 0;
710        y = 0;
711        width = w;
712        height = h;
713        decoration = false;
714    }
715
716    ref_ptr<GraphicsContext::Traits> traits
717        = new GraphicsContext::Traits(ds);
718    traits->hostName = si.hostName;
719    traits->displayNum = si.displayNum;
720    traits->screenNum = si.screenNum;
721    traits->x = x;
722    traits->y = y;
723    traits->width = width;
724    traits->height = height;
725    traits->windowDecoration = decoration;
726    traits->doubleBuffer = true;
727    traits->sharedContext = 0;
728    ref_ptr<GraphicsContext> gc
729        = GraphicsContext::createGraphicsContext(traits.get());
730    osgViewer::GraphicsWindow* gw
731        = dynamic_cast<osgViewer::GraphicsWindow*>(gc.get());
732    if (gw)
733    {
734        OSG_NOTIFY(INFO)<<"View::setUpViewOnSingleScreen - GraphicsWindow has been created successfully."<<std::endl;
735        gw->getEventQueue()->getCurrentEventState()
736            ->setWindowRectangle(0, 0, width, height);
737    }
738    else
739    {
740        OSG_NOTIFY(NOTICE)<<"  GraphicsWindow has not been created successfully."<<std::endl;
741    }
742    double fovy, aspectRatio, zNear, zFar;
743    viewer.getCamera()->getProjectionMatrixAsPerspective(fovy, aspectRatio,
744                                                         zNear, zFar);
745    double newAspectRatio = double(traits->width) / double(traits->height);
746    double aspectRatioChange = newAspectRatio / aspectRatio;
747    if (aspectRatioChange != 1.0)
748    {
749        viewer.getCamera()->getProjectionMatrix()
750            *= Matrix::scale(1.0/aspectRatioChange,1.0,1.0);
751    }
752    // Context has to be current to test for extensions
753    gc->realize();
754    gc->makeCurrent();
755    unsigned int contextID = gc->getState()->getContextID();
756    FBOExtensions* fboe = FBOExtensions::instance(contextID, true);
757    if (!fboe->isSupported())
758    {
759        OSG_NOTIFY(NOTICE) << "Frame buffer objects are not supported\n";
760        gc->releaseContext();
761        gc->close(true);
762        return 0;
763    }
764    if (isGLExtensionSupported(contextID, "GL_ARB_depth_buffer_float"))
765        depthTextureEnum = GL_DEPTH_COMPONENT32F;
766    else if (isGLExtensionSupported(contextID, "GL_NV_depth_buffer_float"))
767        depthTextureEnum = GL_DEPTH_COMPONENT32F_NV;
768    BufferConfigList colorConfigs;
769    BufferConfigList depthConfigs;
770    vector<int> coverageConfigs;
771    getPossibleConfigs(gc.get(), colorConfigs, depthConfigs, coverageConfigs);
772    int coverageSampleConfigs = (coverageConfigs.size() - 4) / 2;
773    cout << "color configs\nname\tbits\n";
774    for (BufferConfigList::const_iterator colorItr = colorConfigs.begin(),
775             colorEnd = colorConfigs.end();
776         colorItr != colorEnd;
777         ++colorItr)
778    {
779        for (BufferConfigList::const_iterator depthItr = depthConfigs.begin(),
780             depthEnd = depthConfigs.end();
781             depthItr != depthEnd;
782             ++depthItr)
783        {
784            string root = colorItr->name + " " + depthItr->name;
785            FboConfig config(root, colorItr->format, depthItr->format,
786                             colorItr->bits, depthItr->bits);
787            FboData data;
788            if (createFBO(gc.get(), config, data))
789                validConfigs.push_back(config);
790            destroyFBO(gc.get(), data);
791            if (coverageConfigs.size() > 0)
792            {
793                //CSAA provides a list of all supported AA modes for
794                //quick enumeration
795                for (int kk = 0; kk < coverageSampleConfigs; kk++)
796                {
797                    stringstream msText;
798                    msText << root;
799                    config.depthSamples = coverageConfigs[kk*2+1];
800                    config.coverageSamples = coverageConfigs[kk*2];
801
802                    if ( config.coverageSamples == config.depthSamples )
803                    {
804                        // Normal antialiasing
805                        msText << " - " << config.depthSamples << " MSAA";
806                    }
807                    else
808                    {
809                        // coverage antialiasing
810                        msText << " - " << config.coverageSamples << "/"
811                               << config.depthSamples << " CSAA";
812                    }
813                    config.name = msText.str();
814
815                    if (createFBO(gc.get(), config, data)) {
816                        validConfigs.push_back( config);
817                    }
818                    destroyFBO(gc.get(), data);
819                }
820            }
821        }
822    }
823    if (validConfigs.empty())
824    {
825        cout << "no valid frame buffer configurations!\n";
826        return 0;
827    }
828    cout << "valid frame buffer configurations:\n";
829    for (vector<FboConfig>::iterator itr = validConfigs.begin(),
830             end = validConfigs.end();
831         itr != end;
832         ++itr)
833        cout << itr->name << "\n";
834    gc->releaseContext();
835
836    return gc.release();
837}
838
839ref_ptr<Texture2D> colorTexture;
840ref_ptr<Texture2D> depthTexture;
841ref_ptr<Texture2D> depthTexture24;
842
843Texture2D* makeDepthTexture(int width, int height, GLenum internalFormat)
844{
845    Texture2D *depthTex = new Texture2D;
846    depthTex->setTextureSize(width, height);
847    depthTex->setSourceFormat(GL_DEPTH_COMPONENT);
848    depthTex->setSourceType(GL_FLOAT);
849    depthTex->setInternalFormat(internalFormat);
850    depthTex->setFilter(Texture2D::MIN_FILTER, Texture2D::NEAREST);
851    depthTex->setFilter(Texture2D::MAG_FILTER, Texture2D::NEAREST);
852    depthTex->setWrap(Texture::WRAP_S, Texture::CLAMP_TO_EDGE);
853    depthTex->setWrap(Texture::WRAP_T, Texture::CLAMP_TO_EDGE);
854    return depthTex;
855}
856
857Camera* makeRttCamera(GraphicsContext* gc, int width, int height)
858{
859    Camera* rttCamera = new Camera;
860    rttCamera->setGraphicsContext(gc);
861    rttCamera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
862    rttCamera->setClearColor(Vec4(0.0, 0.4, 0.5, 0.0));
863    // normally the depth test is inverted, although the user can
864    // change that.
865    rttCamera->setClearDepth(0.0);
866    rttCamera->setViewport(0, 0, width, height);
867    rttCamera->setDrawBuffer(GL_FRONT);
868    rttCamera->setReadBuffer(GL_FRONT);
869    rttCamera->setRenderTargetImplementation(Camera::FRAME_BUFFER_OBJECT);
870    rttCamera->setComputeNearFarMode(CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
871    return rttCamera;
872}
873
874void setAttachmentsFromConfig(Camera* camera, const FboConfig& config)
875{
876    // XXX Detaching the old buffers may not be necessary.
877    if (!camera->getBufferAttachmentMap().empty())
878    {
879        camera->detach(Camera::COLOR_BUFFER);
880        camera->detach(Camera::DEPTH_BUFFER);
881    }
882    camera->attach(Camera::COLOR_BUFFER, colorTexture.get(), 0, 0, false,
883                   config.coverageSamples, config.depthSamples);
884    if (config.coverageSamples != 0 || config.depthSamples != 0)
885        camera->attach(Camera::DEPTH_BUFFER, config.depthFormat);
886    else if (config.depthFormat == GL_DEPTH_COMPONENT24)
887        camera->attach(Camera::DEPTH_BUFFER, depthTexture24.get());
888    else
889        camera->attach(Camera::DEPTH_BUFFER, depthTexture.get());
890}
891
892// Create the parts of the local scene graph used to display the final
893// results.
894Switch* makeTexturesAndGeometry(int width, int height, Switch* sw)
895{
896    if (!sw)
897        sw = new Switch;
898    colorTexture = new Texture2D;
899    colorTexture->setTextureSize(width, height);
900    colorTexture->setInternalFormat(GL_RGBA);
901    colorTexture->setFilter(Texture2D::MIN_FILTER, Texture2D::LINEAR);
902    colorTexture->setFilter(Texture2D::MAG_FILTER, Texture2D::LINEAR);
903    colorTexture->setWrap(Texture::WRAP_S, Texture::CLAMP_TO_EDGE);
904    colorTexture->setWrap(Texture::WRAP_T, Texture::CLAMP_TO_EDGE);
905    colorTexture->setBorderColor(Vec4(0, 0, 0, 0));
906
907    depthTexture24 = makeDepthTexture(width, height, GL_DEPTH_COMPONENT24);
908    if (depthTextureEnum)
909        depthTexture = makeDepthTexture(width, height, depthTextureEnum);
910    else
911        depthTexture = depthTexture24;
912    sw->removeChildren(0, sw->getNumChildren());
913    sw->addChild(createTextureQuad(colorTexture.get()));
914    sw->addChild(createTextureQuad(depthTexture.get()));
915    sw->addChild(createTextureQuad(depthTexture24.get()));
916    sw->setSingleChildOn(0);
917    return sw;
918}
919
920int main(int argc, char **argv)
921{
922    // use an ArgumentParser object to manage the program arguments.
923    ArgumentParser arguments(&argc,argv);
924    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()
925                         + " demonstrates using a floating point depth buffer.\nThe user can invert the depth buffer range and choose among available multi-sample configurations.");
926    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
927    arguments.getApplicationUsage()->addCommandLineOption("--far <number>", "Set far plane value");
928    // if user request help write it out to cout.
929    if (arguments.read("-h") || arguments.read("--help"))
930    {
931        arguments.getApplicationUsage()->write(std::cout);
932        return 1;
933    }
934    float zFar = 500.0f;
935    while (arguments.read("--far", zFar))
936        ;
937    // construct the viewer.
938    osgViewer::Viewer viewer;
939    ref_ptr<AppState> appState = new AppState(&viewer);
940    viewer.addEventHandler(new osgViewer::StatsHandler);
941    viewer.addEventHandler(new osgViewer::WindowSizeHandler);
942    viewer.addEventHandler(new osgViewer::ScreenCaptureHandler);
943    // The aspect ratio is set to the correct ratio for the window in
944    // setupGC().
945    viewer.getCamera()
946        ->setProjectionMatrixAsPerspective(40.0, 1.0, appState->zNear, zFar);
947    GraphicsContext* gc = setupGC(viewer, arguments);
948    if (!gc)
949        return 1;
950    gc->setResizedCallback(new ResizedCallback(appState.get()));
951    const GraphicsContext::Traits* traits = gc->getTraits();
952    width = traits->width;
953    height = traits->height;
954    if (arguments.argc()<=1)
955    {
956        arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
957        return 1;
958    }
959    ref_ptr<Node> loadedModel = osgDB::readNodeFiles(arguments);
960    if (!loadedModel) {
961        cerr << "couldn't load " << argv[1] << "\n";
962        return 1;
963    }
964    osgUtil::Optimizer optimizer;
965    optimizer.optimize(loadedModel.get());
966    // creates texture to be rendered
967    Switch* sw = makeTexturesAndGeometry(width, height, appState->sw.get());
968    ref_ptr<Camera> rttCamera = makeRttCamera(gc, width, height);
969    rttCamera->setRenderOrder(Camera::PRE_RENDER);
970    viewer.addSlave(rttCamera.get());
971    appState->camera = rttCamera;
972    // geometry and slave camera to display the result
973    Group* displayRoot = new Group;
974    displayRoot->addChild(sw);
975    displayRoot->addChild(appState->textProjection.get());
976    StateSet* displaySS = displayRoot->getOrCreateStateSet();
977    displaySS->setMode(GL_LIGHTING, StateAttribute::OFF);
978    displaySS->setMode(GL_DEPTH_TEST, StateAttribute::OFF);
979    Camera* texCamera = new Camera;
980    texCamera->setGraphicsContext(gc);
981    texCamera->setClearMask(GL_COLOR_BUFFER_BIT);
982    texCamera->setClearColor(Vec4(0.0, 0.0, 0.0, 0.0));
983    texCamera->setReferenceFrame(Camera::ABSOLUTE_RF);
984    texCamera->setViewport(0, 0, width, height);
985    texCamera->setDrawBuffer(GL_BACK);
986    texCamera->setReadBuffer(GL_BACK);
987    texCamera->addChild(displayRoot);
988    texCamera->setAllowEventFocus(false);
989    texCamera->setCullingMode(CullSettings::NO_CULLING);
990    texCamera->setProjectionResizePolicy(Camera::FIXED);
991    viewer.addSlave(texCamera, Matrixd(), Matrixd(), false);
992    viewer.addEventHandler(new ConfigHandler(appState.get()));
993
994    // add model to the viewer.
995    Group* sceneRoot = new Group;
996    StateSet* sceneSS = sceneRoot->getOrCreateStateSet();
997    Depth* depth = new Depth(Depth::GEQUAL, 1.0, 0.0);
998    sceneSS->setAttributeAndModes(depth,(StateAttribute::ON
999                                         | StateAttribute::OVERRIDE));
1000#if 0
1001    // Hack to work around Blender osg export bug
1002    sceneSS->setAttributeAndModes(new CullFace(CullFace::BACK));
1003#endif
1004    sceneRoot->addChild(loadedModel.get());
1005    appState->setStateFromConfig(validConfigs[0]);
1006    appState->updateNear();
1007    viewer.addEventHandler(new DepthHandler(appState.get(), depth));
1008    // add the help handler
1009    viewer.addEventHandler(new osgViewer
1010                           ::HelpHandler(arguments.getApplicationUsage()));
1011
1012    viewer.setSceneData(sceneRoot);
1013
1014    return viewer.run();
1015}
Note: See TracBrowser for help on using the browser.