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

Revision 14244, 37.4 kB (checked in by robert, 11 days ago)

Added shaders to support experimental shader based displacement mapping technique osgTerrain::ShaderTerrain?.

  • 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/Notify>
27#include <osg/observer_ptr>
28#include <osg/Projection>
29#include <osg/Switch>
30#include <osg/Texture2D>
31
32#include <osgDB/ReadFile>
33#include <osgGA/GUIEventHandler>
34#include <osgUtil/Optimizer>
35
36#include <osgText/Text>
37
38#include <osgViewer/Renderer>
39#include <osgViewer/Viewer>
40#include <osgViewer/ViewerEventHandlers>
41
42#include <iostream>
43#include <sstream>
44
45/* Demonstration of floating point depth buffers. The most basic way to use
46 * a floating point depth buffer in OpenGL is to create a frame buffer
47 * object, attach a color and floating point depth texture, render,
48 * and then copy the color texture to the screen. When doing
49 * multisampling we can't use textures directly, so we have to create
50 * render buffers with the proper format. Then we let OSG handle the
51 * details of resolving the multisampling.
52 *
53 * When using a floating point depth buffer, it's advantageous to
54 * reverse the depth buffer range (and the depth test, of course) so
55 * that 0.0 corresponds to the far plane. See
56 * e.g. http://www.humus.name/index.php?ID=25 for details.
57 */
58using namespace osg;
59using namespace std;
60
61/* createFBO() and destroyFBO(), and the supporting classes and
62 * functions below, are only used to test possible valid frame buffer
63 * configurations at startup. They wouldn't be used in a normal OSG
64 * program unless we wanted to enumerate all the valid FBO
65 * combinations and let the user choose between them.
66 */
67
68// Properties of an FBO that we will try to create
69struct FboConfig
70{
71    FboConfig()
72        : colorFormat(0), depthFormat(0), redbits(0), depthBits(0),
73          depthSamples(0), coverageSamples(0)
74    {
75    }
76    FboConfig(const string& name_, GLenum colorFormat_, GLenum depthFormat_,
77              int redbits_, int depthBits_, int depthSamples_ = 0,
78              int coverageSamples_ = 0)
79        : name(name_), colorFormat(colorFormat_), depthFormat(depthFormat_),
80          redbits(redbits_), depthBits(depthBits_), depthSamples(depthSamples_),
81          coverageSamples(coverageSamples_)
82    {
83    }
84    string name;
85    GLenum colorFormat;
86    GLenum depthFormat;
87    int redbits;
88    int depthBits;
89    int depthSamples;
90    int coverageSamples;
91};
92
93// Properties of a buffer
94struct BufferConfig
95{
96    BufferConfig() {}
97    BufferConfig(const string& name_, GLenum format_, int bits_)
98        : name(name_), format(format_), bits(bits_)
99    {
100    }
101    string name;
102    GLenum format;
103    int bits;
104};
105
106typedef vector<BufferConfig> BufferConfigList;
107
108vector<FboConfig> validConfigs;
109// Ugly global variables for the viewport width and height
110int width, height;
111
112// This is only used when testing possible frame buffer configurations
113// to find valid ones.
114struct FboData
115{
116    ref_ptr<Texture2D> tex;             // color texture
117    ref_ptr<Texture2D> depthTex;        // depth texture
118    ref_ptr<FrameBufferObject> fb;      // render framebuffer
119    ref_ptr<FrameBufferObject> resolveFB; // multisample resolve target
120};
121
122Texture2D* makeDepthTexture(int width, int height, GLenum internalFormat);
123
124// Assemble lists of the valid buffer configurations, along with the
125// possibilities for multisample coverage antialiasing, if any.
126void getPossibleConfigs(GraphicsContext* gc, BufferConfigList& colorConfigs,
127                        BufferConfigList& depthConfigs,
128                        vector<int>& coverageConfigs)
129{
130    int maxSamples = 0;
131    int coverageSampleConfigs = 0;
132    unsigned contextID = gc->getState()->getContextID();
133    colorConfigs.push_back(BufferConfig("RGBA8", GL_RGBA8, 8));
134    depthConfigs.push_back(BufferConfig("D24", GL_DEPTH_COMPONENT24, 24));
135    FBOExtensions* fboe = FBOExtensions::instance(contextID, true);
136    if (!fboe->isSupported())
137        return;
138    if (fboe->isMultisampleSupported())
139        glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamples);
140    // isMultisampleCoverageSupported
141    if (isGLExtensionSupported(contextID,
142                               "GL_NV_framebuffer_multisample_coverage"))
143    {
144        glGetIntegerv(GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV,
145                      &coverageSampleConfigs);
146        coverageConfigs.resize(coverageSampleConfigs * 2 + 4);
147        glGetIntegerv(GL_MULTISAMPLE_COVERAGE_MODES_NV, &coverageConfigs[0]);
148    }
149    if (isGLExtensionSupported(contextID, "GL_ARB_depth_buffer_float"))
150        depthConfigs.push_back(BufferConfig("D32F", GL_DEPTH_COMPONENT32F, 32));
151    else if (isGLExtensionSupported(contextID, "GL_NV_depth_buffer_float"))
152        depthConfigs.push_back(BufferConfig("D32F", GL_DEPTH_COMPONENT32F_NV,
153                                            32));
154}
155
156bool checkFramebufferStatus(GraphicsContext* gc, bool silent = false)
157{
158    State& state = *gc->getState();
159    unsigned contextID = state.getContextID();
160    FBOExtensions* fboe = FBOExtensions::instance(contextID, true);
161    switch(fboe->glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT)) {
162        case GL_FRAMEBUFFER_COMPLETE_EXT:
163            break;
164        case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
165            if (!silent)
166                cout << "Unsupported framebuffer format\n";
167            return false;
168        case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
169            if (!silent)
170                cout << "Framebuffer incomplete, missing attachment\n";
171            return false;
172        case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
173            if (!silent)
174                cout << "Framebuffer incomplete, duplicate attachment\n";
175            return false;
176        case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
177            if (!silent)
178                cout << "Framebuffer incomplete, attached images must have same dimensions\n";
179            return false;
180        case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
181            if (!silent)
182                cout << "Framebuffer incomplete, attached images must have same format\n";
183            return false;
184        case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
185            if (!silent)
186                cout << "Framebuffer incomplete, missing draw buffer\n";
187            return false;
188        case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
189            if (!silent)
190                cout << "Framebuffer incomplete, missing read buffer\n";
191            return false;
192        default:
193            return false;
194    }
195    return true;
196}
197
198// Attempt to create an FBO with a certain configuration. If the FBO
199// is created with fewer bits in any of its parameters, the creation
200// is deemed to have failed. Even though the result is a valid FBO,
201// we're only interested in discrete, valid configurations.
202bool createFBO(GraphicsContext* gc, FboConfig &config, FboData &data)
203{
204    bool result = true;
205    bool multisample = config.depthSamples > 0;
206    bool csaa = config.coverageSamples > config.depthSamples;
207    data.fb = new FrameBufferObject;
208    int texWidth = 512, texHeight = 512;
209    data.tex = new Texture2D;
210    data.tex->setTextureSize(texWidth, texHeight);
211    data.tex->setInternalFormat(config.colorFormat);
212    data.tex->setSourceFormat(GL_RGBA);
213    data.tex->setSourceType(GL_FLOAT);
214    data.tex->setFilter(Texture::MIN_FILTER, Texture::LINEAR_MIPMAP_LINEAR);
215    data.tex->setFilter(Texture::MAG_FILTER, Texture::LINEAR);
216    data.tex->setWrap(Texture::WRAP_S, Texture::CLAMP_TO_EDGE);
217    data.tex->setWrap(Texture::WRAP_T, Texture::CLAMP_TO_EDGE);
218    RenderBuffer* colorRB = 0;
219    RenderBuffer* depthRB = 0;
220    if (multisample)
221    {
222        data.resolveFB = new FrameBufferObject;
223        data.resolveFB->setAttachment(Camera::COLOR_BUFFER,
224                                      FrameBufferAttachment(data.tex.get()));
225        colorRB = new RenderBuffer(texWidth, texHeight, config.colorFormat,
226                                   config.coverageSamples, config.depthSamples);
227        data.fb->setAttachment(Camera::COLOR_BUFFER,
228                               FrameBufferAttachment(colorRB));
229        depthRB = new RenderBuffer(texWidth, texHeight, config.depthFormat,
230                                   config.coverageSamples, config.depthSamples);
231        data.fb->setAttachment(Camera::DEPTH_BUFFER,
232                               FrameBufferAttachment(depthRB));
233    }
234    else
235    {
236        data.depthTex = makeDepthTexture(texWidth, texHeight,
237                                         config.depthFormat);
238        data.fb->setAttachment(Camera::COLOR_BUFFER,
239                               FrameBufferAttachment(data.tex.get()));
240        data.fb->setAttachment(Camera::DEPTH_BUFFER,
241                               FrameBufferAttachment(data.depthTex.get()));
242    }
243    State& state = *gc->getState();
244    unsigned int contextID = state.getContextID();
245    FBOExtensions* fboe = FBOExtensions::instance(contextID, true);
246
247    data.fb->apply(state);
248    result = checkFramebufferStatus(gc, true);
249    if (!result)
250    {
251        fboe->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
252        return false;
253    }
254    int query;
255    if (multisample)
256    {
257        GLuint colorRBID = colorRB->getObjectID(contextID, fboe);
258        fboe->glBindRenderbuffer(GL_RENDERBUFFER_EXT, colorRBID);
259        if (csaa)
260        {
261            fboe->glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT,
262                                               GL_RENDERBUFFER_COVERAGE_SAMPLES_NV,
263                                               &query);
264            if (query < config.coverageSamples)
265                result = false;
266            else
267                config.coverageSamples = query;
268            fboe->glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT,
269                                               GL_RENDERBUFFER_COLOR_SAMPLES_NV,
270                                               &query);
271
272            if ( query < config.depthSamples)
273               result = false;
274            else
275                config.depthSamples = query; // report back the actual number
276
277        }
278        else
279        {
280            fboe->glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT,
281                                               GL_RENDERBUFFER_SAMPLES_EXT,
282                                               &query);
283            if (query < config.depthSamples)
284                result = false;
285            else
286                config.depthSamples = query;
287        }
288    }
289    glGetIntegerv( GL_RED_BITS, &query);
290    if (query != config.redbits)
291        result = false;
292    glGetIntegerv(GL_DEPTH_BITS, &query);
293    if ( query != config.depthBits)
294        result = false;
295    if (result && multisample && data.resolveFB.valid())
296    {
297        data.resolveFB->apply(state);
298        result = checkFramebufferStatus(gc, true);
299        if (result)
300        {
301            glGetIntegerv( GL_RED_BITS, &query);
302            if (query != config.redbits)
303                result = false;
304        }
305    }
306    fboe->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
307    return result;
308}
309
310void destroyFBO(GraphicsContext* gc, FboData &data)
311{
312    data.tex = 0;
313    data.depthTex = 0;
314    data.fb = 0;
315    data.resolveFB = 0;
316    State& state = *gc->getState();
317    double availableTime = 100.0;
318    RenderBuffer::flushDeletedRenderBuffers(state.getContextID(), 0.0,
319                                            availableTime);
320    availableTime = 100.0;
321    FrameBufferObject::flushDeletedFrameBufferObjects(state.getContextID(),
322                                                      0.0, availableTime);
323}
324
325void setAttachmentsFromConfig(Camera* camera, const FboConfig& config);
326Switch* makeTexturesAndGeometry(int width, int height, Switch* sw = 0);
327
328// Application state accessed from event handlers and main function;
329// contains state that can be changed by the user and the OSG classes
330// used to display / indicate that state.
331//
332// camera - Camera with fbo, using either fp depth buffer or fixed
333// switch child 0 - texture containing rendering of scene
334// switch child 1 - fp depth buffer as texture
335// switch child 2 - integer depth buffer as texture
336// textNotAvailable- "not available" text if texture isn't valid.
337
338struct AppState : public Referenced
339{
340    AppState(osgViewer::Viewer* viewer_);
341    void setStateFromConfig(const FboConfig& config);
342    void advanceConfig(int increment);
343    void updateDisplayedTexture();
344    void updateNear();
345    virtual ~AppState() {}
346    ref_ptr<Switch> sw;         // switch between displayed texture
347    bool displayScene;
348    bool invertRange;
349    int currentConfig;
350    osgViewer::Viewer* viewer;
351    double zNear;
352    ref_ptr<Camera> camera;
353    // text displayed on the screen showing the user's choices
354    ref_ptr<Projection> textProjection;
355    ref_ptr<osgText::Text> configText;
356    ref_ptr<osgText::Text> zNearText;
357    ref_ptr<Geode> textNotAvailable;
358    ref_ptr<Geode> textInverted;
359};
360
361AppState::AppState(osgViewer::Viewer* viewer_)
362    : displayScene(true), invertRange(true), currentConfig(0),
363      viewer(viewer_), zNear(0.03125)
364{
365    sw = new Switch;
366    string fontName("fonts/arial.ttf");
367    // Text description of current config
368    configText = new osgText::Text;
369    configText->setDataVariance(Object::DYNAMIC);
370    configText->setFont(fontName);
371    configText->setPosition(Vec3(50.0f, 50.0f, 0.0f));
372    configText->setColor(Vec4(1.0, 1.0, 1.0, 1.0));
373    Geode* textGeode = new Geode;
374    textGeode->addDrawable(configText.get());
375    // Text for the near plane distance
376    zNearText = new osgText::Text;
377    zNearText->setDataVariance(Object::DYNAMIC);
378    zNearText->setFont(fontName);
379    zNearText->setPosition(Vec3(1230.0f, 50.0f, 0.0f));
380    zNearText->setColor(Vec4(1.0, 1.0, 1.0, 1.0));
381    zNearText->setAlignment(osgText::Text::RIGHT_BASE_LINE);
382    textGeode->addDrawable(zNearText.get());
383    // Projection that lets the text be placed in pixels.
384    textProjection = new Projection;
385    textProjection->setMatrix(Matrix::ortho2D(0,1280,0,1024));
386    textProjection->addChild(textGeode);
387    // "texture not available" text displayed when the user trys to
388    // display the depth texture while multisampling.
389    osgText::Text* noCanDo = new osgText::Text;
390    noCanDo->setFont(fontName);
391    noCanDo->setPosition(Vec3(512.0f, 384.0f, 0.0f));
392    noCanDo->setColor(Vec4(1.0, 0.0, 0.0, 1.0));
393    noCanDo->setText("not available");
394    textNotAvailable = new Geode;
395    textNotAvailable->addDrawable(noCanDo);
396    textProjection->addChild(textNotAvailable.get());
397    // Is the depth test inverted?
398    osgText::Text* inverted = new osgText::Text;
399    inverted->setFont(fontName);
400    inverted->setPosition(Vec3(512.0f, 50.0f, 0.0f));
401    inverted->setColor(Vec4(1.0, 1.0, 1.0, 1.0));
402    inverted->setText("inverted depth test");
403    textInverted = new Geode;
404    textInverted->addDrawable(inverted);
405    textInverted->setNodeMask(~0u);
406    textProjection->addChild(textInverted.get());
407    textProjection->getOrCreateStateSet()->setRenderBinDetails(11, "RenderBin");
408}
409
410void AppState::setStateFromConfig(const FboConfig& config)
411{
412    Camera* camera = viewer->getSlave(0)._camera.get();
413    setAttachmentsFromConfig(camera, config);
414    osgViewer::Renderer* renderer
415        = dynamic_cast<osgViewer::Renderer*>(camera->getRenderer());
416    if (renderer)
417        renderer->setCameraRequiresSetUp(true);
418    if (configText.valid())
419    {
420        configText->setText(validConfigs[currentConfig].name);
421        configText->update();
422    }
423    updateDisplayedTexture();
424}
425
426void AppState::advanceConfig(int increment)
427{
428    currentConfig = (currentConfig + increment) % validConfigs.size();
429    setStateFromConfig(validConfigs[currentConfig]);
430}
431
432void AppState::updateDisplayedTexture()
433{
434    if (displayScene)
435        sw->setSingleChildOn(0);
436    else if (validConfigs[currentConfig].depthSamples > 0
437             || validConfigs[currentConfig].coverageSamples > 0)
438        sw->setAllChildrenOff();
439    else if (validConfigs[currentConfig].depthFormat != GL_DEPTH_COMPONENT24)
440        sw->setSingleChildOn(2);
441    else
442        sw->setSingleChildOn(3);
443    if (displayScene
444        || (validConfigs[currentConfig].depthSamples == 0
445            && validConfigs[currentConfig].coverageSamples == 0))
446        textNotAvailable->setNodeMask(0u);
447    else
448        textNotAvailable->setNodeMask(~0u);
449}
450
451void AppState::updateNear()
452{
453    // Assume that the viewing frustum is symmetric.
454    double fovy, aspectRatio, cNear, cFar;
455    viewer->getCamera()->getProjectionMatrixAsPerspective(fovy, aspectRatio,
456                                                          cNear, cFar);
457    viewer->getCamera()->setProjectionMatrixAsPerspective(fovy, aspectRatio,
458                                                          zNear, cFar);
459    stringstream nearStream;
460    nearStream << "near: " << zNear;
461    zNearText->setText(nearStream.str());
462    zNearText->update();
463}
464
465class ConfigHandler : public osgGA::GUIEventHandler
466{
467public:
468
469    ConfigHandler(AppState* appState)
470        : _appState(appState)
471    {
472    }
473
474    virtual bool handle(const osgGA::GUIEventAdapter& ea,
475                        osgGA::GUIActionAdapter& aa,
476                        Object*, NodeVisitor* /*nv*/)
477    {
478        if (ea.getHandled()) return false;
479        osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
480        if (!viewer) return false;
481        switch(ea.getEventType())
482        {
483        case osgGA::GUIEventAdapter::KEYUP:
484        {
485            if (ea.getKey()=='d')
486            {
487                _appState->displayScene = !_appState->displayScene;
488                _appState->updateDisplayedTexture();
489                return true;
490            }
491            else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Right ||
492                     ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Right)
493            {
494                _appState->advanceConfig(1);
495                return true;
496            }
497            else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Left ||
498                     ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Left)
499            {
500                _appState->advanceConfig(-1);
501                return true;
502            }
503            break;
504        }
505        default:
506            break;
507        }
508        return false;
509    }
510
511    void getUsage(ApplicationUsage& usage) const
512    {
513        usage.addKeyboardMouseBinding("d", "display depth texture");
514        usage.addKeyboardMouseBinding("right arrow",
515                                      "next frame buffer configuration");
516        usage.addKeyboardMouseBinding("left arrow",
517                                      "previous frame buffer configuration");
518    }
519
520protected:
521    virtual ~ConfigHandler() {}
522    ref_ptr<AppState> _appState;
523};
524
525class DepthHandler : public osgGA::GUIEventHandler
526{
527public:
528
529    DepthHandler(AppState *appState, Depth* depth)
530        : _appState(appState), _depth(depth)
531    {
532        depth->setDataVariance(Object::DYNAMIC);
533    }
534
535    virtual bool handle(const osgGA::GUIEventAdapter& ea,
536                        osgGA::GUIActionAdapter& /*aa*/,
537                        Object*, NodeVisitor* /*nv*/)
538    {
539        if (ea.getHandled()) return false;
540
541        ref_ptr<Depth> depth;
542        if (!_depth.lock(depth)) return false;
543
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.