root/OpenSceneGraph/trunk/examples/osgkeystone/osgkeystone.cpp @ 13374

Revision 13374, 44.8 kB (checked in by robert, 14 hours ago)

Added debug setting of VolumeSettings? that is commented out

Line 
1/* OpenSceneGraph example, osganimate.
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
19#include <osg/Notify>
20#include <osg/io_utils>
21#include <osg/TextureRectangle>
22#include <osg/TexMat>
23#include <osg/Stencil>
24#include <osg/PolygonStipple>
25
26#include <osgDB/ReadFile>
27#include <osgGA/StateSetManipulator>
28#include <osgGA/TrackballManipulator>
29#include <osgViewer/Viewer>
30#include <osgViewer/ViewerEventHandlers>
31
32
33class Keystone : public osg::Referenced
34{
35public:
36    Keystone():
37        keystoneEditingEnabled(false),
38        bottom_left(-1.0,-1.0),
39        bottom_right(1.0,-1.0),
40        top_left(-1.0,1.0),
41        top_right(1.0,1.0) {}
42
43    void reset()
44    {
45        bottom_left.set(-1.0,-1.0);
46        bottom_right.set(1.0,-1.0);
47        top_left.set(-1.0,1.0);
48        top_right.set(1.0,1.0);
49    }
50
51    Keystone& operator = (const Keystone& rhs)
52    {
53        if (&rhs==this) return *this;
54        keystoneEditingEnabled = rhs.keystoneEditingEnabled;
55        bottom_left = rhs.bottom_left;
56        bottom_right = rhs.bottom_right;
57        top_left = rhs.top_left;
58        top_right = rhs.top_right;
59        return *this;
60    }
61
62    bool        keystoneEditingEnabled;
63
64    osg::Vec2d  bottom_left;
65    osg::Vec2d  bottom_right;
66    osg::Vec2d  top_left;
67    osg::Vec2d  top_right;
68
69    void compute3DPositions(osg::DisplaySettings* ds, osg::Vec3& tl, osg::Vec3& tr, osg::Vec3& br, osg::Vec3& bl) const
70    {
71        double tr_x = ((top_right-bottom_right).length()) / ((top_left-bottom_left).length());
72        double r_left = sqrt(tr_x);
73        double r_right = r_left/tr_x;
74
75        double tr_y = ((top_right-top_left).length()) / ((bottom_right-bottom_left).length());
76        double r_bottom = sqrt(tr_y);
77        double r_top = r_bottom/tr_y;
78
79        double screenDistance = ds->getScreenDistance();
80        double screenWidth = ds->getScreenWidth();
81        double screenHeight = ds->getScreenHeight();
82
83        tl = osg::Vec3(screenWidth*0.5*top_left.x(), screenHeight*0.5*top_left.y(), -screenDistance)*r_left*r_top;
84        tr = osg::Vec3(screenWidth*0.5*top_right.x(), screenHeight*0.5*top_right.y(), -screenDistance)*r_right*r_top;
85        br = osg::Vec3(screenWidth*0.5*bottom_right.x(), screenHeight*0.5*bottom_right.y(), -screenDistance)*r_right*r_bottom;
86        bl = osg::Vec3(screenWidth*0.5*bottom_left.x(), screenHeight*0.5*bottom_left.y(), -screenDistance)*r_left*r_bottom;
87    }
88};
89
90
91
92class KeystoneHandler : public osgGA::GUIEventHandler
93{
94public:
95
96    KeystoneHandler(Keystone* keystone);
97
98    ~KeystoneHandler() {}
99
100    bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa);
101
102    void setKeystoneEditingEnabled(bool enabled) { if (_currentControlPoints.valid()) _currentControlPoints->keystoneEditingEnabled = enabled; }
103    bool getKeystoneEditingEnabled() const { return _currentControlPoints.valid() ? _currentControlPoints->keystoneEditingEnabled : false; }
104
105    enum Region
106    {
107        NONE_SELECTED,
108        TOP_LEFT,
109        TOP,
110        TOP_RIGHT,
111        RIGHT,
112        BOTTOM_RIGHT,
113        BOTTOM,
114        BOTTOM_LEFT,
115        LEFT,
116        CENTER
117    };
118
119    osg::Vec2d incrementScale(const osgGA::GUIEventAdapter& ea) const;
120    Region computeRegion(const osgGA::GUIEventAdapter& ea) const;
121    void move(Region region, const osg::Vec2d& delta);
122   
123protected:
124
125
126    osg::ref_ptr<Keystone>      _keystone;
127
128    osg::Vec2d                  _defaultIncrement;
129    osg::Vec2d                  _ctrlIncrement;
130    osg::Vec2d                  _shiftIncrement;
131    osg::Vec2d                  _keyIncrement;
132
133    osg::Vec2d                  _startPosition;
134    osg::ref_ptr<Keystone>      _startControlPoints;
135   
136    Region                      _selectedRegion;
137    osg::ref_ptr<Keystone>      _currentControlPoints;
138
139};
140
141KeystoneHandler::KeystoneHandler(Keystone* keystone):
142    _keystone(keystone),
143    _defaultIncrement(0.0,0.0),
144    _ctrlIncrement(1.0,1.0),
145    _shiftIncrement(0.1,0.1),
146    _keyIncrement(0.005, 0.005),
147    _selectedRegion(NONE_SELECTED)
148{
149    _startControlPoints = new Keystone;
150    _currentControlPoints = keystone; //new Keystone;
151}
152
153KeystoneHandler::Region KeystoneHandler::computeRegion(const osgGA::GUIEventAdapter& ea) const
154{
155    float x = ea.getXnormalized();
156    float y = ea.getYnormalized();
157    if (x<-0.33)
158    {
159        // left side
160        if (y<-0.33) return BOTTOM_LEFT;
161        else if (y<0.33) return LEFT;
162        else return TOP_LEFT;
163    }
164    else if (x<0.33)
165    {
166        // center side
167        if (y<-0.33) return BOTTOM;
168        else if (y<0.33) return CENTER;
169        else return TOP;
170    }
171    else
172    {
173        // right side
174        if (y<-0.33) return BOTTOM_RIGHT;
175        else if (y<0.33) return RIGHT;
176        else return TOP_RIGHT;
177    }
178    return NONE_SELECTED;
179}
180
181void KeystoneHandler::move(Region region, const osg::Vec2d& delta)
182{
183    switch(region)
184    {
185        case(TOP_LEFT):
186            _currentControlPoints->top_left += delta;
187            break;
188        case(TOP):
189            _currentControlPoints->top_left += delta;
190            _currentControlPoints->top_right += delta;
191            break;
192        case(TOP_RIGHT):
193            _currentControlPoints->top_right += delta;
194            break;
195        case(RIGHT):
196            _currentControlPoints->top_right += delta;
197            _currentControlPoints->bottom_right += delta;
198            break;
199        case(BOTTOM_RIGHT):
200            _currentControlPoints->bottom_right += delta;
201            break;
202        case(BOTTOM):
203            _currentControlPoints->bottom_right += delta;
204            _currentControlPoints->bottom_left += delta;
205            break;
206        case(BOTTOM_LEFT):
207            _currentControlPoints->bottom_left += delta;
208            break;
209        case(LEFT):
210            _currentControlPoints->bottom_left += delta;
211            _currentControlPoints->top_left += delta;
212            break;
213        case(CENTER):
214            _currentControlPoints->bottom_left += delta;
215            _currentControlPoints->top_left += delta;
216            _currentControlPoints->bottom_right += delta;
217            _currentControlPoints->top_right += delta;
218            break;
219        case(NONE_SELECTED):
220            break;
221    }
222}
223
224osg::Vec2d KeystoneHandler::incrementScale(const osgGA::GUIEventAdapter& ea) const
225{
226    if (_ctrlIncrement!=osg::Vec2d(0.0,0.0) && (ea.getModKeyMask()==osgGA::GUIEventAdapter::MODKEY_LEFT_CTRL || ea.getModKeyMask()==osgGA::GUIEventAdapter::MODKEY_RIGHT_CTRL )) return _ctrlIncrement;
227    if (_shiftIncrement!=osg::Vec2d(0.0,0.0) && (ea.getModKeyMask()==osgGA::GUIEventAdapter::MODKEY_LEFT_SHIFT || ea.getModKeyMask()==osgGA::GUIEventAdapter::MODKEY_RIGHT_SHIFT )) return _shiftIncrement;
228    return _defaultIncrement;
229}
230
231bool KeystoneHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
232{
233    switch(ea.getEventType())
234    {
235        case(osgGA::GUIEventAdapter::PUSH):
236        {
237            if (getKeystoneEditingEnabled())
238            {
239                osg::Vec2d scale = incrementScale(ea);
240                if (scale.length2()!=0.0)
241                {
242                    _selectedRegion = computeRegion(ea);
243                    (*_startControlPoints) = (*_currentControlPoints);
244                    _startPosition.set(ea.getXnormalized(),ea.getYnormalized());
245                }
246                else
247                {
248                    _selectedRegion = NONE_SELECTED;
249                }
250            }
251            return false;
252        }
253        case(osgGA::GUIEventAdapter::DRAG):
254        {
255            if (getKeystoneEditingEnabled())
256            {
257                if (_selectedRegion!=NONE_SELECTED)
258                {
259                    (*_currentControlPoints) = (*_startControlPoints);
260                    osg::Vec2d currentPosition(ea.getXnormalized(), ea.getYnormalized());
261                    osg::Vec2d delta(currentPosition-_startPosition);
262                    osg::Vec2d scale = incrementScale(ea);
263                    move(_selectedRegion, osg::Vec2d(delta.x()*scale.x(), delta.y()*scale.y()) );
264                    return true;
265                }
266            }
267            return false;
268        }
269        case(osgGA::GUIEventAdapter::RELEASE):
270        {
271            if (getKeystoneEditingEnabled())
272            {
273                _selectedRegion = NONE_SELECTED;
274            }
275            return false;
276        }
277        case(osgGA::GUIEventAdapter::KEYDOWN):
278        {
279            if (getKeystoneEditingEnabled())
280            {
281                if (ea.getUnmodifiedKey()=='g' && (ea.getModKeyMask()==osgGA::GUIEventAdapter::MODKEY_LEFT_CTRL || ea.getModKeyMask()==osgGA::GUIEventAdapter::MODKEY_RIGHT_CTRL))
282                {
283                    setKeystoneEditingEnabled(false);
284                }
285                else if (ea.getKey()=='r')
286                {
287                    _selectedRegion = NONE_SELECTED;
288                    _startControlPoints->reset();
289                    _currentControlPoints->reset();
290                }
291                else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Up)
292                {
293                    move(computeRegion(ea), osg::Vec2d(0.0, _keyIncrement.y()*incrementScale(ea).y()) );
294                }
295                else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Down)
296                {
297                    move(computeRegion(ea), osg::Vec2d(0.0, -_keyIncrement.y()*incrementScale(ea).y()) );
298                }
299                else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Left)
300                {
301                    move(computeRegion(ea), osg::Vec2d(-_keyIncrement.x()*incrementScale(ea).x(), 0.0) );
302                }
303                else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Right)
304                {
305                    move(computeRegion(ea), osg::Vec2d(_keyIncrement.x()*incrementScale(ea).x(), 0.0) );
306                }
307                else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_7 || ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Home)
308                {
309                    _currentControlPoints->top_left.set(ea.getXnormalized(), ea.getYnormalized());
310                }
311                else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_9 || ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Page_Up)
312                {
313                    _currentControlPoints->top_right.set(ea.getXnormalized(), ea.getYnormalized());
314                }
315                else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_3 || ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Page_Down)
316                {
317                    _currentControlPoints->bottom_right.set(ea.getXnormalized(), ea.getYnormalized());
318                }
319                else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_1 || ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_End)
320                {
321                    _currentControlPoints->bottom_left.set(ea.getXnormalized(), ea.getYnormalized());
322                }
323            }
324            else if (ea.getUnmodifiedKey()=='g' && (ea.getModKeyMask()==osgGA::GUIEventAdapter::MODKEY_LEFT_CTRL || ea.getModKeyMask()==osgGA::GUIEventAdapter::MODKEY_RIGHT_CTRL))
325            {
326                setKeystoneEditingEnabled(true);
327            }
328            return false;
329        }
330        default:
331            return false;
332    }
333}
334struct KeystoneCullCallback : public osg::Drawable::CullCallback
335{
336    KeystoneCullCallback(Keystone* keystone=0):_keystone(keystone) {}
337    KeystoneCullCallback(const KeystoneCullCallback&, const osg::CopyOp&) {}
338
339    META_Object(osg,KeystoneCullCallback);
340
341    /** do customized cull code, return true if drawable should be culled.*/
342    virtual bool cull(osg::NodeVisitor* nv, osg::Drawable* drawable, osg::RenderInfo* renderInfo) const
343    {
344        return _keystone.valid() ? !_keystone->keystoneEditingEnabled : true;
345    }
346
347    osg::ref_ptr<Keystone> _keystone;
348};
349
350
351struct KeystoneUpdateCallback : public osg::Drawable::UpdateCallback
352{
353    KeystoneUpdateCallback(Keystone* keystone=0):_keystone(keystone) {}
354    KeystoneUpdateCallback(const KeystoneUpdateCallback&, const osg::CopyOp&) {}
355
356    META_Object(osg,KeystoneUpdateCallback);
357
358    /** do customized update code.*/
359    virtual void update(osg::NodeVisitor*, osg::Drawable* drawable)
360    {
361        update(dynamic_cast<osg::Geometry*>(drawable));
362    }
363
364    void update(osg::Geometry* geometry)
365    {
366        if (!geometry) return;
367
368        osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
369        if (!vertices) return;
370
371        osg::Vec2Array* texcoords = dynamic_cast<osg::Vec2Array*>(geometry->getTexCoordArray(0));
372        if (!texcoords) return;
373
374        osg::Vec3 tl, tr, br, bl;
375
376        _keystone->compute3DPositions(osg::DisplaySettings::instance().get(), tl, tr, br, bl);
377
378        for(unsigned int i=0; i<vertices->size(); ++i)
379        {
380            osg::Vec3& v = (*vertices)[i];
381            osg::Vec2& t = (*texcoords)[i];
382            v = bl * ((1.0f-t.x())*(1.0f-t.y())) +
383                br * ((t.x())*(1.0f-t.y())) +
384                tl * ((1.0f-t.x())*(t.y())) +
385                tr * ((t.x())*(t.y()));
386        }
387        geometry->dirtyBound();
388    }
389   
390    osg::ref_ptr<Keystone> _keystone;
391};
392
393
394osg::Geode* createKeystoneDistortionMesh(Keystone* keystone)
395{
396    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
397
398    osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
399    geode->addDrawable(geometry.get());
400
401    geometry->setUseDisplayList(false);
402
403    osg::ref_ptr<KeystoneUpdateCallback> kuc = new KeystoneUpdateCallback(keystone);
404    geometry->setUpdateCallback(kuc.get());
405
406    osg::ref_ptr<osg::Vec4Array> colours = new osg::Vec4Array;
407    colours->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
408    geometry->setColorArray(colours.get());
409    geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
410
411    osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
412    geometry->setVertexArray(vertices.get());
413
414    osg::ref_ptr<osg::Vec2Array> texcoords = new osg::Vec2Array;
415    geometry->setTexCoordArray(0, texcoords.get());
416
417    unsigned int numRows = 7;
418    unsigned int numColumns = 7;
419    unsigned int numVertices = numRows*numColumns;
420
421    vertices->resize(numVertices);
422    texcoords->resize(numVertices);
423
424    for(unsigned j=0; j<numRows; j++)
425    {
426        for(unsigned i=0; i<numColumns; i++)
427        {
428            osg::Vec2& t = (*texcoords)[j*numColumns+i];
429            t.set(static_cast<float>(i)/static_cast<float>(numColumns-1), static_cast<float>(j)/static_cast<float>(numRows-1));
430        }
431    }
432
433    osg::ref_ptr<osg::DrawElementsUShort> elements = new osg::DrawElementsUShort(GL_TRIANGLES);
434    geometry->addPrimitiveSet(elements.get());
435    for(unsigned j=0; j<numRows-1; j++)
436    {
437        for(unsigned i=0; i<numColumns-1; i++)
438        {
439            unsigned int vi = j*numColumns+i;
440           
441            elements->push_back(vi+numColumns);
442            elements->push_back(vi);
443            elements->push_back(vi+1);
444
445            elements->push_back(vi+numColumns);
446            elements->push_back(vi+1);
447            elements->push_back(vi+1+numColumns);
448        }
449    }
450   
451    geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
452    geometry->getOrCreateStateSet()->setRenderBinDetails(0, "RenderBin");
453
454    kuc->update(geometry.get());
455
456    return geode.release();
457}
458
459osg::Node* createGrid(Keystone* keystone, const osg::Vec4& colour)
460{
461    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
462
463    osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
464    geode->addDrawable(geometry.get());
465
466    geometry->setUseDisplayList(false);
467
468    osg::ref_ptr<KeystoneUpdateCallback> kuc = new KeystoneUpdateCallback(keystone);
469    geometry->setUpdateCallback(kuc.get());
470
471    geometry->setCullCallback(new KeystoneCullCallback(keystone));
472
473    osg::ref_ptr<osg::Vec4Array> colours = new osg::Vec4Array;
474    colours->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
475    geometry->setColorArray(colours.get());
476    geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
477
478    osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
479    geometry->setVertexArray(vertices.get());
480
481    osg::ref_ptr<osg::Vec2Array> texcoords = new osg::Vec2Array;
482    geometry->setTexCoordArray(0, texcoords.get());
483
484    osg::Vec2 origin(0.0f, 0.0f);
485    osg::Vec2 widthVector(1.0f, 0.0f);
486    osg::Vec2 heightVector(0.0f, 1.0f);
487
488    unsigned int numIntervals = 7;
489   
490    // border line
491    {
492        unsigned int vi = texcoords->size();
493        texcoords->push_back(origin);
494        texcoords->push_back(origin+widthVector);
495        texcoords->push_back(origin+widthVector+heightVector);
496        texcoords->push_back(origin+heightVector);
497        geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINE_LOOP, vi, 4));
498    }
499
500    // cross lines
501    {
502        unsigned int vi = texcoords->size();
503        osg::Vec2 v = origin;
504        osg::Vec2 dv = (widthVector+heightVector)/static_cast<float>(numIntervals-1);
505        for(unsigned int i=0; i<numIntervals; ++i)
506        {
507            texcoords->push_back(v);
508            v += dv;
509        }
510        geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINE_STRIP, vi, numIntervals));
511
512        vi = texcoords->size();
513        v = origin+heightVector;
514        dv = (widthVector-heightVector)/static_cast<float>(numIntervals-1);
515        for(unsigned int i=0; i<numIntervals; ++i)
516        {
517            texcoords->push_back(v);
518            v += dv;
519        }
520        geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINE_STRIP, vi, numIntervals));
521    }
522
523    // vertices lines
524    {
525        unsigned int vi = texcoords->size();
526        osg::Vec2 dv = widthVector/6.0;
527        osg::Vec2 bv = origin+dv;
528        osg::Vec2 tv = bv+heightVector;
529        for(unsigned int i=0; i<5; ++i)
530        {
531            texcoords->push_back(bv);
532            texcoords->push_back(tv);
533            bv += dv;
534            tv += dv;
535        }
536        geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINES, vi, 10));
537    }
538
539    // horizontal lines
540    {
541        unsigned int vi = texcoords->size();
542        osg::Vec2 dv = heightVector/6.0;
543        osg::Vec2 bv = origin+dv;
544        osg::Vec2 tv = bv+widthVector;
545        for(unsigned int i=0; i<5; ++i)
546        {
547            texcoords->push_back(bv);
548            texcoords->push_back(tv);
549            bv += dv;
550            tv += dv;
551        }
552        geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINES, vi, 10));
553    }
554
555    vertices->resize(texcoords->size());
556
557    geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
558    geometry->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
559    geometry->getOrCreateStateSet()->setRenderBinDetails(1, "RenderBin");
560
561    kuc->update(geometry.get());
562
563    return geode.release();
564}
565
566osg::Texture* createKestoneDistortionTexture(int width, int height)
567{
568    osg::ref_ptr<osg::TextureRectangle> texture = new osg::TextureRectangle;
569
570    texture->setTextureSize(width, height);
571    texture->setInternalFormat(GL_RGB);
572    texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR);
573    texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR);
574    texture->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP_TO_EDGE);
575    texture->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP_TO_EDGE);
576
577    return texture.release();
578}
579
580osg::Camera* assignKeystoneRenderToTextureCamera(osgViewer::View* view, osg::GraphicsContext* gc, int width, int height, osg::Texture* texture)
581{
582    osg::Camera::RenderTargetImplementation renderTargetImplementation = osg::Camera::FRAME_BUFFER_OBJECT;
583    GLenum buffer = GL_FRONT;
584
585    osg::ref_ptr<osg::Camera> camera = new osg::Camera;
586    camera->setName("Render to texture camera");
587    camera->setGraphicsContext(gc);
588    camera->setViewport(new osg::Viewport(0,0,width, height));
589    camera->setDrawBuffer(buffer);
590    camera->setReadBuffer(buffer);
591    camera->setAllowEventFocus(false);
592    // tell the camera to use OpenGL frame buffer object where supported.
593    camera->setRenderTargetImplementation(renderTargetImplementation);
594
595    // attach the texture and use it as the color buffer.
596    camera->attach(osg::Camera::COLOR_BUFFER, texture);
597
598    view->addSlave(camera.get(), osg::Matrixd(), osg::Matrixd());
599
600    return camera.release();
601}
602
603osg::Camera* assignKeystoneDistortionCamera(osgViewer::View* view, osg::DisplaySettings* ds, osg::GraphicsContext* gc, int x, int y, int width, int height, GLenum buffer, osg::Texture* texture, Keystone* keystone)
604{
605    double screenDistance = ds->getScreenDistance();
606    double screenWidth = ds->getScreenWidth();
607    double screenHeight = ds->getScreenHeight();
608    double fovy = osg::RadiansToDegrees(2.0*atan2(screenHeight/2.0,screenDistance));
609    double aspectRatio = screenWidth/screenHeight;
610
611    osg::Geode* geode = createKeystoneDistortionMesh(keystone);
612
613    // new we need to add the texture to the mesh, we do so by creating a
614    // StateSet to contain the Texture StateAttribute.
615    osg::StateSet* stateset = geode->getOrCreateStateSet();
616    stateset->setTextureAttributeAndModes(0, texture,osg::StateAttribute::ON);
617    stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
618
619    osg::TexMat* texmat = new osg::TexMat;
620    texmat->setScaleByTextureRectangleSize(true);
621    stateset->setTextureAttributeAndModes(0, texmat, osg::StateAttribute::ON);
622
623    osg::ref_ptr<osg::Camera> camera = new osg::Camera;
624    camera->setGraphicsContext(gc);
625    camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT );
626    camera->setClearColor( osg::Vec4(0.0,0.0,0.0,1.0) );
627    camera->setViewport(new osg::Viewport(x, y, width, height));
628    camera->setDrawBuffer(buffer);
629    camera->setReadBuffer(buffer);
630    camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
631    camera->setAllowEventFocus(false);
632    camera->setInheritanceMask(camera->getInheritanceMask() & ~osg::CullSettings::CLEAR_COLOR & ~osg::CullSettings::COMPUTE_NEAR_FAR_MODE);
633    //camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
634
635    camera->setViewMatrix(osg::Matrix::identity());
636    camera->setProjectionMatrixAsPerspective(fovy, aspectRatio, 0.1, 1000.0);
637
638    // add subgraph to render
639    camera->addChild(geode);
640
641    camera->addChild(createGrid(keystone, osg::Vec4(1.0,1.0,1.0,1.0)));
642
643    camera->setName("DistortionCorrectionCamera");
644
645    // camera->addEventCallback(new KeystoneHandler(keystone));
646
647    view->addSlave(camera.get(), osg::Matrixd(), osg::Matrixd(), false);
648
649    return camera.release();
650}
651
652
653
654struct StereoSlaveCallback : public osg::View::Slave::UpdateSlaveCallback
655{
656    StereoSlaveCallback(osg::DisplaySettings* ds, double eyeScale):_ds(ds), _eyeScale(eyeScale) {}
657
658    virtual void updateSlave(osg::View& view, osg::View::Slave& slave)
659    {
660        osg::Camera* camera = slave._camera.get();
661        osgViewer::View* viewer_view = dynamic_cast<osgViewer::View*>(&view);
662
663        if (_ds.valid() && camera && viewer_view)
664        {
665
666            // set projection matrix
667            if (_eyeScale<0.0)
668            {
669                camera->setProjectionMatrix(_ds->computeLeftEyeProjectionImplementation(view.getCamera()->getProjectionMatrix()));
670            }
671            else
672            {
673                camera->setProjectionMatrix(_ds->computeRightEyeProjectionImplementation(view.getCamera()->getProjectionMatrix()));
674            }
675
676            double sd = _ds->getScreenDistance();
677            double fusionDistance = sd;
678            switch(viewer_view->getFusionDistanceMode())
679            {
680                case(osgUtil::SceneView::USE_FUSION_DISTANCE_VALUE):
681                    fusionDistance = viewer_view->getFusionDistanceValue();
682                    break;
683                case(osgUtil::SceneView::PROPORTIONAL_TO_SCREEN_DISTANCE):
684                    fusionDistance *= viewer_view->getFusionDistanceValue();
685                    break;
686            }
687            double eyeScale = osg::absolute(_eyeScale) * (fusionDistance/sd);
688
689            if (_eyeScale<0.0)
690            {
691                camera->setViewMatrix(_ds->computeLeftEyeViewImplementation(view.getCamera()->getViewMatrix(), eyeScale));
692            }
693            else
694            {
695                camera->setViewMatrix(_ds->computeRightEyeViewImplementation(view.getCamera()->getViewMatrix(), eyeScale));
696            }
697        }
698        else
699        {
700            slave.updateSlaveImplementation(view);
701        }
702    }
703
704    osg::ref_ptr<osg::DisplaySettings> _ds;
705    double _eyeScale;
706};
707
708osg::Camera* assignStereoCamera(osgViewer::View* view, osg::DisplaySettings* ds, osg::GraphicsContext* gc, int x, int y, int width, int height, GLenum buffer, double eyeScale)
709{
710    osg::ref_ptr<osg::Camera> camera = new osg::Camera;
711
712    camera->setGraphicsContext(gc);
713    camera->setViewport(new osg::Viewport(x,y, width, height));
714    camera->setDrawBuffer(buffer);
715    camera->setReadBuffer(buffer);
716
717    // add this slave camera to the viewer, with a shift left of the projection matrix
718    view->addSlave(camera.get(), osg::Matrixd::identity(), osg::Matrixd::identity());
719
720    // assign update callback to maintain the correct view and projection matrices
721    osg::View::Slave& slave = view->getSlave(view->getNumSlaves()-1);
722    slave._updateSlaveCallback =  new StereoSlaveCallback(ds, eyeScale);
723
724    return camera.release();
725}
726
727static const GLubyte patternVertEven[] = {
728    0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
729    0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
730    0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
731    0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
732    0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
733    0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
734    0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
735    0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
736    0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
737    0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
738    0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
739    0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
740    0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
741    0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
742    0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
743    0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
744
745static const GLubyte patternVertOdd[] = {
746    0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
747    0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
748    0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
749    0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
750    0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
751    0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
752    0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
753    0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
754    0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
755    0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
756    0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
757    0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
758    0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
759    0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
760    0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
761    0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
762
763static const GLubyte patternHorzEven[] = {
764    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
765    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
766    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
767    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
768    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
769    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
770    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
771    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
772    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
773    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
774    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
775    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
776    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
777    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
778    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
779    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00};
780
781// 32 x 32 bit array every row is a horizontal line of pixels
782//  and the (bitwise) columns a vertical line
783//  The following is a checkerboard pattern
784static const GLubyte patternCheckerboard[] = {
785    0x55, 0x55, 0x55, 0x55,
786    0xAA, 0xAA, 0xAA, 0xAA,
787    0x55, 0x55, 0x55, 0x55,
788    0xAA, 0xAA, 0xAA, 0xAA,
789    0x55, 0x55, 0x55, 0x55,
790    0xAA, 0xAA, 0xAA, 0xAA,
791    0x55, 0x55, 0x55, 0x55,
792    0xAA, 0xAA, 0xAA, 0xAA,
793    0x55, 0x55, 0x55, 0x55,
794    0xAA, 0xAA, 0xAA, 0xAA,
795    0x55, 0x55, 0x55, 0x55,
796    0xAA, 0xAA, 0xAA, 0xAA,
797    0x55, 0x55, 0x55, 0x55,
798    0xAA, 0xAA, 0xAA, 0xAA,
799    0x55, 0x55, 0x55, 0x55,
800    0xAA, 0xAA, 0xAA, 0xAA,
801    0x55, 0x55, 0x55, 0x55,
802    0xAA, 0xAA, 0xAA, 0xAA,
803    0x55, 0x55, 0x55, 0x55,
804    0xAA, 0xAA, 0xAA, 0xAA,
805    0x55, 0x55, 0x55, 0x55,
806    0xAA, 0xAA, 0xAA, 0xAA,
807    0x55, 0x55, 0x55, 0x55,
808    0xAA, 0xAA, 0xAA, 0xAA,
809    0x55, 0x55, 0x55, 0x55,
810    0xAA, 0xAA, 0xAA, 0xAA,
811    0x55, 0x55, 0x55, 0x55,
812    0xAA, 0xAA, 0xAA, 0xAA,
813    0x55, 0x55, 0x55, 0x55,
814    0xAA, 0xAA, 0xAA, 0xAA,
815    0x55, 0x55, 0x55, 0x55,
816    0xAA, 0xAA, 0xAA, 0xAA};
817
818
819void setUpViewForStereo(osgViewer::View* view, osg::DisplaySettings* ds)
820{
821    if (!ds->getStereo()) return;
822
823    ds->setUseSceneViewForStereoHint(false);
824
825   
826    // set up view's main camera
827    {
828        double height = osg::DisplaySettings::instance()->getScreenHeight();
829        double width = osg::DisplaySettings::instance()->getScreenWidth();
830        double distance = osg::DisplaySettings::instance()->getScreenDistance();
831        double vfov = osg::RadiansToDegrees(atan2(height/2.0f,distance)*2.0);
832
833        view->getCamera()->setProjectionMatrixAsPerspective( vfov, width/height, 1.0f,10000.0f);
834    }
835   
836
837    int screenNum = 0;
838
839    osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface();
840    if (!wsi)
841    {
842        OSG_NOTICE<<"Error, no WindowSystemInterface available, cannot create windows."<<std::endl;
843        return;
844    }
845
846    // unsigned int numScreens = wsi->getNumScreens(si);
847   
848    osg::GraphicsContext::ScreenIdentifier si;
849    si.readDISPLAY();
850
851    // displayNum has not been set so reset it to 0.
852    if (si.displayNum<0) si.displayNum = 0;
853
854    si.screenNum = screenNum;
855
856    unsigned int width, height;
857    wsi->getScreenResolution(si, width, height);
858
859//    width/=2; height/=2;
860
861    osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits(ds);
862    traits->hostName = si.hostName;
863    traits->displayNum = si.displayNum;
864    traits->screenNum = si.screenNum;
865    traits->x = 0;
866    traits->y = 0;
867    traits->width = width;
868    traits->height = height;
869    traits->windowDecoration = false;
870    traits->doubleBuffer = true;
871    traits->sharedContext = 0;
872
873    OSG_NOTICE<<"traits->stencil="<<traits->stencil<<std::endl;
874
875
876    osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());
877    if (!gc)
878    {
879        OSG_NOTICE<<"GraphicsWindow has not been created successfully."<<std::endl;
880        return;
881    }
882
883    switch(ds->getStereoMode())
884    {
885        case(osg::DisplaySettings::QUAD_BUFFER):
886        {
887            // left Camera left buffer
888            {
889                osg::ref_ptr<osg::Camera> camera = assignStereoCamera(view, ds, gc, 0, 0, traits->width, traits->height, traits->doubleBuffer ? GL_BACK_LEFT : GL_FRONT_LEFT, -1.0);
890                camera->setClearMask(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
891                camera->setRenderOrder(osg::Camera::NESTED_RENDER, 0);
892            }
893
894            // right Camera right buffer
895            {
896                osg::ref_ptr<osg::Camera> camera = assignStereoCamera(view, ds, gc, 0, 0, traits->width, traits->height, traits->doubleBuffer ? GL_BACK_RIGHT : GL_FRONT_RIGHT, 1.0);
897                camera->setClearMask(GL_DEPTH_BUFFER_BIT);
898                camera->setRenderOrder(osg::Camera::NESTED_RENDER, 1);
899            }
900
901            // for keystone:
902            // left camera to render to left texture
903            // right camera to render to right texture
904            // left keystone camera to render to left buffer
905            // left keystone camera to render to right buffer
906            // one keystone and editing for the one window
907           
908            break;
909        }
910        case(osg::DisplaySettings::ANAGLYPHIC):
911        {
912            // left Camera red
913            {
914                osg::ref_ptr<osg::Camera> camera = assignStereoCamera(view, ds, gc, 0, 0, traits->width, traits->height, traits->doubleBuffer ? GL_BACK : GL_FRONT, -1.0);
915                camera->setClearMask(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
916                camera->getOrCreateStateSet()->setAttribute(new osg::ColorMask(true, false, false, true));
917                camera->setRenderOrder(osg::Camera::NESTED_RENDER, 0);
918            }
919
920            // right Camera cyan
921            {
922                osg::ref_ptr<osg::Camera> camera = assignStereoCamera(view, ds, gc, 0, 0, traits->width, traits->height, traits->doubleBuffer ? GL_BACK : GL_FRONT, 1.0);
923                camera->setClearMask(GL_DEPTH_BUFFER_BIT);
924                camera->getOrCreateStateSet()->setAttribute(new osg::ColorMask(false, true, true, true));
925                camera->setRenderOrder(osg::Camera::NESTED_RENDER, 1);
926            }
927
928            // for keystone:
929            // left camera to render to texture using red colour mask
930            // right camera to render to same texture using cyan colour mask
931            // keystone camera to render to whole screen without colour masks
932            // one keystone and editing for the one window
933
934            break;
935        }
936        case(osg::DisplaySettings::HORIZONTAL_SPLIT):
937        {
938            // left viewport Camera
939            assignStereoCamera(view, ds, gc,
940                               0, 0, traits->width/2, traits->height, traits->doubleBuffer ? GL_BACK : GL_FRONT,
941                               (ds->getSplitStereoHorizontalEyeMapping()==osg::DisplaySettings::LEFT_EYE_LEFT_VIEWPORT) ? -1.0 : 1.0);
942
943            // right viewport Camera
944            assignStereoCamera(view, ds, gc,
945                               traits->width/2,0, traits->width/2, traits->height, traits->doubleBuffer ? GL_BACK : GL_FRONT,
946                               (ds->getSplitStereoHorizontalEyeMapping()==osg::DisplaySettings::LEFT_EYE_RIGHT_VIEWPORT) ? -1.0 : 1.0);
947
948            // for keystone:
949            // left camera to render to left texture using whole viewport of left texture
950            // right camera to render to right texture using whole viewport of right texture
951            // left keystone camera to render to left viewport/window
952            // right keystone camera to render to right viewport/window
953            // two keystone, one for each of the left and right viewports/windows
954
955            break;
956        }
957        case(osg::DisplaySettings::VERTICAL_SPLIT):
958        {
959            // bottom viewport Camera
960            assignStereoCamera(view, ds, gc,
961                               0, 0, traits->width, traits->height/2, traits->doubleBuffer ? GL_BACK : GL_FRONT,
962                               (ds->getSplitStereoVerticalEyeMapping()==osg::DisplaySettings::LEFT_EYE_BOTTOM_VIEWPORT) ? -1.0 : 1.0);
963
964            // top vieport camera
965            assignStereoCamera(view, ds, gc,
966                               0,traits->height/2, traits->width, traits->height/2, traits->doubleBuffer ? GL_BACK : GL_FRONT,
967                               (ds->getSplitStereoVerticalEyeMapping()==osg::DisplaySettings::LEFT_EYE_TOP_VIEWPORT) ? -1.0 : 1.0);
968
969            // for keystone:
970            // left camera to render to left texture using whole viewport of left texture
971            // right camera to render to right texture using whole viewport of right texture
972            // left keystone camera to render to left viewport/window
973            // right keystone camera to render to right viewport/window
974            // two keystone, one for each of the left and right viewports/windows
975
976            break;
977        }
978        case(osg::DisplaySettings::LEFT_EYE):
979        {
980            // single window, whole window, just left eye offsets
981            osg::ref_ptr<osg::Camera> camera = assignStereoCamera(view, ds, gc, 0, 0, traits->width, traits->height, traits->doubleBuffer ? GL_BACK : GL_FRONT, -1.0);
982
983            // for keystone:
984            // treat as standard keystone correction.
985            // left eye camera to render to texture
986            // keystone camera then render to window
987            // one keystone and editing for window
988
989            break;
990        }
991        case(osg::DisplaySettings::RIGHT_EYE):
992        {
993            // single window, whole window, just right eye offsets
994            osg::ref_ptr<osg::Camera> camera = assignStereoCamera(view, ds, gc, 0, 0, traits->width, traits->height, traits->doubleBuffer ? GL_BACK : GL_FRONT, 1.0);
995
996            // for keystone:
997            // treat as standard keystone correction.
998            // left eye camera to render to texture
999            // keystone camera then render to window
1000            // one keystone and editing for window
1001
1002            break;
1003        }
1004        case(osg::DisplaySettings::HORIZONTAL_INTERLACE):
1005        case(osg::DisplaySettings::VERTICAL_INTERLACE):
1006        case(osg::DisplaySettings::CHECKERBOARD):
1007        {
1008            // set up the stencil buffer
1009            {
1010                osg::ref_ptr<osg::Camera> camera = new osg::Camera;
1011                camera->setGraphicsContext(gc.get());
1012                camera->setViewport(0, 0, traits->width, traits->height);
1013                camera->setDrawBuffer(traits->doubleBuffer ? GL_BACK : GL_FRONT);
1014                camera->setReadBuffer(camera->getDrawBuffer());
1015                camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
1016                camera->setClearMask(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
1017                camera->setClearStencil(0);
1018                camera->setRenderOrder(osg::Camera::NESTED_RENDER, 0);
1019                view->addSlave(camera.get(), false);
1020
1021                osg::ref_ptr<osg::Geometry> geometry = osg::createTexturedQuadGeometry(osg::Vec3(-1.0f,-1.0f,0.0f), osg::Vec3(2.0f,0.0f,0.0f), osg::Vec3(0.0f,2.0f,0.0f), 0.0f, 0.0f, 1.0f, 1.0f);
1022                osg::ref_ptr<osg::Geode> geode = new osg::Geode;
1023                geode->addDrawable(geometry.get());
1024                camera->addChild(geode.get());
1025
1026                geode->setCullingActive(false);
1027               
1028                osg::ref_ptr<osg::StateSet> stateset = geode->getOrCreateStateSet();
1029
1030                // set up stencil
1031                osg::ref_ptr<osg::Stencil> stencil = new osg::Stencil;
1032                stencil->setFunction(osg::Stencil::ALWAYS, 1, ~0u);
1033                stencil->setOperation(osg::Stencil::REPLACE, osg::Stencil::REPLACE, osg::Stencil::REPLACE);
1034                stencil->setWriteMask(~0u);
1035                stateset->setAttributeAndModes(stencil.get(), osg::StateAttribute::ON);
1036
1037                // set up polygon stipple
1038                if(ds->getStereoMode() == osg::DisplaySettings::VERTICAL_INTERLACE)
1039                {
1040                    stateset->setAttributeAndModes(new osg::PolygonStipple(patternVertEven), osg::StateAttribute::ON);
1041                }
1042                else if(ds->getStereoMode() == osg::DisplaySettings::HORIZONTAL_INTERLACE)
1043                {
1044                    stateset->setAttributeAndModes(new osg::PolygonStipple(patternHorzEven), osg::StateAttribute::ON);
1045                }
1046                else
1047                {
1048                    stateset->setAttributeAndModes(new osg::PolygonStipple(patternCheckerboard), osg::StateAttribute::ON);
1049                }
1050
1051                stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
1052                stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
1053
1054            }
1055
1056            OSG_NOTICE<<"view->getNumSlaves()="<<view->getNumSlaves()<<std::endl;
1057            // left Camera
1058            {
1059                osg::ref_ptr<osg::Camera> camera = assignStereoCamera(view, ds, gc, 0, 0, traits->width, traits->height, traits->doubleBuffer ? GL_BACK : GL_FRONT, -1.0);
1060                camera->setClearMask(0);
1061                camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
1062                camera->setRenderOrder(osg::Camera::NESTED_RENDER, 1);
1063
1064                osg::ref_ptr<osg::Stencil> stencil = new osg::Stencil;
1065                stencil->setFunction(osg::Stencil::EQUAL, 0, ~0u);
1066                stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP);
1067                camera->getOrCreateStateSet()->setAttributeAndModes(stencil.get(), osg::StateAttribute::ON);
1068            }
1069
1070            // right Camera cyan
1071            {
1072                osg::ref_ptr<osg::Camera> camera = assignStereoCamera(view, ds, gc, 0, 0, traits->width, traits->height, traits->doubleBuffer ? GL_BACK : GL_FRONT, 1.0);
1073                camera->setClearMask(GL_DEPTH_BUFFER_BIT);
1074                camera->setRenderOrder(osg::Camera::NESTED_RENDER, 2);
1075
1076                osg::ref_ptr<osg::Stencil> stencil = new osg::Stencil;
1077                stencil->setFunction(osg::Stencil::NOTEQUAL, 0, ~0u);
1078                stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP);
1079                camera->getOrCreateStateSet()->setAttributeAndModes(stencil.get(), osg::StateAttribute::ON);
1080            }
1081            break;
1082        }
1083    }
1084}
1085
1086
1087void setUpViewForKeystone(osgViewer::View* view, Keystone* keystone)
1088{
1089    int screenNum = 0;
1090   
1091    osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface();
1092    if (!wsi)
1093    {
1094        OSG_NOTICE<<"Error, no WindowSystemInterface available, cannot create windows."<<std::endl;
1095        return;
1096    }
1097
1098    osg::GraphicsContext::ScreenIdentifier si;
1099    si.readDISPLAY();
1100
1101    // displayNum has not been set so reset it to 0.
1102    if (si.displayNum<0) si.displayNum = 0;
1103
1104    si.screenNum = screenNum;
1105
1106    unsigned int width, height;
1107    wsi->getScreenResolution(si, width, height);
1108
1109//    width/=2; height/=2;
1110
1111    osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
1112    traits->hostName = si.hostName;
1113    traits->displayNum = si.displayNum;
1114    traits->screenNum = si.screenNum;
1115    traits->x = 0;
1116    traits->y = 0;
1117    traits->width = width;
1118    traits->height = height;
1119    traits->windowDecoration = false;
1120    traits->doubleBuffer = true;
1121    traits->sharedContext = 0;
1122
1123
1124    osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());
1125    if (!gc)
1126    {
1127        OSG_NOTICE<<"GraphicsWindow has not been created successfully."<<std::endl;
1128        return;
1129    }
1130
1131    osg::DisplaySettings* ds = osg::DisplaySettings::instance();
1132
1133
1134    // create distortion texture
1135    osg::ref_ptr<osg::Texture> texture = createKestoneDistortionTexture(width, height);
1136
1137    // create RTT Camera
1138    assignKeystoneRenderToTextureCamera(view, gc.get(), width, height, texture);
1139
1140    // create Keystone distortion camera
1141    osg::ref_ptr<osg::Camera> camera = assignKeystoneDistortionCamera(view, ds, gc.get(),
1142                                                                      0, 0, width, height,
1143                                                                      traits->doubleBuffer ? GL_BACK : GL_FRONT,
1144                                                                      texture, keystone);
1145    // attach Keystone editing event handler.
1146    camera->addEventCallback(new KeystoneHandler(keystone));
1147   
1148}
1149
1150int main( int argc, char **argv )
1151{
1152    osg::ArgumentParser arguments(&argc,argv);
1153   
1154    // initialize the viewer.
1155    osgViewer::Viewer viewer(arguments);
1156
1157    osg::DisplaySettings* ds = viewer.getDisplaySettings() ? viewer.getDisplaySettings() : osg::DisplaySettings::instance().get();
1158    ds->readCommandLine(arguments);
1159
1160    osg::ref_ptr<osg::Node> model = osgDB::readNodeFiles(arguments);
1161
1162    if (!model)
1163    {
1164        OSG_NOTICE<<"No models loaded, please specify a model file on the command line"<<std::endl;
1165        return 1;
1166    }
1167
1168
1169    OSG_NOTICE<<"Stereo "<<ds->getStereo()<<std::endl;
1170    OSG_NOTICE<<"StereoMode "<<ds->getStereoMode()<<std::endl;
1171
1172    viewer.setSceneData(model.get());
1173   
1174    // add the state manipulator
1175    viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
1176
1177    // add the stats handler
1178    viewer.addEventHandler(new osgViewer::StatsHandler);
1179
1180    // add camera manipulator
1181    viewer.setCameraManipulator(new osgGA::TrackballManipulator());
1182
1183    if (ds->getStereo())
1184    {
1185        setUpViewForStereo(&viewer, ds);
1186    }
1187    else
1188    {
1189        setUpViewForKeystone(&viewer, new Keystone);
1190    }
1191   
1192    viewer.realize();
1193
1194    while(!viewer.done())
1195    {
1196        viewer.advance();
1197        viewer.eventTraversal();
1198        viewer.updateTraversal();
1199        viewer.renderingTraversals();
1200    }
1201    return 0;
1202}
Note: See TracBrowser for help on using the browser.