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

Revision 13376, 50.4 kB (checked in by robert, 89 minutes ago)

Added in source shaders

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