1 /* OpenSceneGraph example, osgstereoimage.
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 <osgViewer/Viewer>
20 #include <osgDB/fstream>
21 #include <osgDB/ReadFile>
22 #include <osgDB/WriteFile>
23 #include <osgUtil/Optimizer>
24
25 #include <osg/ImageStream>
26 #include <osg/Geode>
27 #include <osg/Notify>
28 #include <osg/MatrixTransform>
29 #include <osg/Switch>
30 #include <osg/TexMat>
31 #include <osg/Texture2D>
32
33 #include <iostream>
34
35 typedef std::vector<std::string> FileList;
36
37 #include <osg/Program>
38 #include <osg/Shader>
39
createColorToGreyscaleStateSet()40 osg::StateSet* createColorToGreyscaleStateSet()
41 {
42 osg::StateSet* stateset = new osg::StateSet;
43
44 osg::Program* program = new osg::Program;
45 stateset->setAttribute(program);
46
47 const char* fragSource =
48 {
49 "uniform sampler2D baseTexture;\n"
50 "uniform mat4 colorMatrix;\n"
51 "void main(void)\n"
52 "{\n"
53 " vec4 color = texture2D( baseTexture, gl_TexCoord[0].st );\n"
54 " gl_FragColor = colorMatrix * color;\n"
55 "}\n"
56 };
57 program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragSource));
58
59 stateset->addUniform(new osg::Uniform("baseTexture",0));
60
61 osg::Matrixf colorMatrix(
62 0.3f, 0.3f, 0.3f, 0.0f,
63 0.59f, 0.59f, 0.59f, 0.0f,
64 0.11f, 0.11f, 0.11f, 0.0f,
65 0.0f, 0.0f, 0.0f, 1.0f
66 );
67
68 stateset->addUniform(new osg::Uniform("colorMatrix",colorMatrix));
69
70 return stateset;
71 }
72
73
createSectorForImage(osg::Image * image,osg::TexMat * texmat,float s,float t,float radius,float height,float length)74 osg::Geode* createSectorForImage(osg::Image* image, osg::TexMat* texmat, float s,float t, float radius, float height, float length)
75 {
76 bool flip = image->getOrigin()==osg::Image::TOP_LEFT;
77
78 int numSegments = 20;
79 float Theta = length/radius;
80 float dTheta = Theta/(float)(numSegments-1);
81
82 float ThetaZero = height*s/(t*radius);
83
84 // set up the texture.
85 osg::Texture2D* texture = new osg::Texture2D;
86 texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
87 texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
88 texture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER);
89 texture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER);
90 texture->setResizeNonPowerOfTwoHint(false);
91 texture->setImage(image);
92
93 // set up the drawstate.
94 osg::StateSet* dstate = new osg::StateSet;
95 dstate->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);
96 dstate->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
97 dstate->setTextureAttributeAndModes(0, texture,osg::StateAttribute::ON);
98 dstate->setTextureAttribute(0, texmat);
99
100 // set up the geoset.
101 osg::Geometry* geom = new osg::Geometry;
102 geom->setStateSet(dstate);
103
104 osg::Vec3Array* coords = new osg::Vec3Array();
105 osg::Vec2Array* tcoords = new osg::Vec2Array();
106
107 int i;
108 float angle = -Theta/2.0f;
109 for(i=0;
110 i<numSegments;
111 ++i, angle+=dTheta)
112 {
113 coords->push_back(osg::Vec3(sinf(angle)*radius,cosf(angle)*radius,height*0.5f)); // top
114 coords->push_back(osg::Vec3(sinf(angle)*radius,cosf(angle)*radius,-height*0.5f)); // bottom.
115
116 tcoords->push_back(osg::Vec2(angle/ThetaZero+0.5f, flip ? 0.0f : 1.0f)); // top
117 tcoords->push_back(osg::Vec2(angle/ThetaZero+0.5f, flip ? 1.0f : 0.0f)); // bottom.
118
119 }
120
121 osg::Vec4Array* colors = new osg::Vec4Array();
122 colors->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
123
124 osg::DrawArrays* elements = new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP,0,coords->size());
125
126
127
128 geom->setVertexArray(coords);
129 geom->setTexCoordArray(0,tcoords);
130 geom->setColorArray(colors, osg::Array::BIND_OVERALL);
131
132 geom->addPrimitiveSet(elements);
133
134 // set up the geode.
135 osg::Geode* geode = new osg::Geode;
136 geode->addDrawable(geom);
137
138 return geode;
139
140 }
141
loadImages(std::string image1,std::string image2,osg::TexMat * texmatLeft,osg::TexMat * texmatRight,float radius,float height,float length)142 osg::Group * loadImages(std::string image1, std::string image2, osg::TexMat* texmatLeft, osg::TexMat* texmatRight, float radius, float height, float length)
143 {
144 osg::ref_ptr<osg::Image> imageLeft = osgDB::readRefImageFile(image1);
145 osg::ref_ptr<osg::Image> imageRight = osgDB::readRefImageFile(image2);
146 if (imageLeft.valid() && imageRight.valid())
147 {
148 osg::ImageStream* streamLeft = dynamic_cast<osg::ImageStream*>(imageLeft.get());
149 if (streamLeft) streamLeft->play();
150
151 osg::ImageStream* streamRight = dynamic_cast<osg::ImageStream*>(imageRight.get());
152 if (streamRight) streamRight->play();
153
154
155 float average_s = (imageLeft->s()+imageRight->s())*0.5f;
156 float average_t = (imageLeft->t()+imageRight->t())*0.5f;
157 osg::Geode* geodeLeft = createSectorForImage(imageLeft.get(),texmatLeft,average_s,average_t, radius, height, length);
158 geodeLeft->setNodeMask(0x01);
159
160 osg::Geode* geodeRight = createSectorForImage(imageRight.get(),texmatRight,average_s,average_t, radius, height, length);
161 geodeRight->setNodeMask(0x02);
162
163 osg::Group * imageGroup = new osg::Group;
164
165 imageGroup->addChild(geodeLeft);
166 imageGroup->addChild(geodeRight);
167 return imageGroup;
168 }
169 else
170 {
171 std::cout << "Warning: Unable to load both image files, '"<<image1<<"' & '"<<image2<<"', required for stereo imaging."<<std::endl;
172 return 0;
173 }
174 }
175
176 // create a switch containing a set of child each containing a
177 // stereo image pair.
createScene(FileList fileList,osg::TexMat * texmatLeft,osg::TexMat * texmatRight,float radius,float height,float length)178 osg::Switch* createScene(FileList fileList, osg::TexMat* texmatLeft, osg::TexMat* texmatRight, float radius, float height, float length)
179 {
180 osg::Switch* sw = new osg::Switch;
181
182 // load the images.
183 for(unsigned int i=0;i+1<fileList.size();i+=2)
184 {
185 osg::Group * imageGroup = loadImages(fileList[i],fileList[i+1],texmatLeft,texmatRight, radius, height, length);
186 if (imageGroup) sw->addChild(imageGroup);
187 }
188
189
190 if (sw->getNumChildren()>0)
191 {
192 // select first child.
193 sw->setSingleChildOn(0);
194 }
195
196 return sw;
197 }
198
199 class SlideEventHandler : public osgGA::GUIEventHandler
200 {
201 public:
202
203 SlideEventHandler();
204
205 META_Object(osgStereImageApp,SlideEventHandler);
206
207
208 void set(osg::Switch* sw, float offsetX, float offsetY, osg::TexMat* texmatLeft, osg::TexMat* texmatRight, float timePerSlide, bool autoSteppingActive);
209
210 void set(FileList fileList, osg::Switch* sw, float offsetX, float offsetY, osg::TexMat* texmatLeft, osg::TexMat* texmatRight, float radius, float height, float length, float timePerSlide, bool autoSteppingActive);
211
212
213 virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&);
214
215 virtual void getUsage(osg::ApplicationUsage& usage) const;
216
217 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
218
219 void nextSlide();
220
221 void previousSlide();
222
223 void scaleImage(float s);
224
225 void offsetImage(float ds,float dt);
226
227 void rotateImage(float rx,float ry);
228
229 void initTexMatrices();
230
231 protected:
232
~SlideEventHandler()233 ~SlideEventHandler() {}
SlideEventHandler(const SlideEventHandler &,const osg::CopyOp &)234 SlideEventHandler(const SlideEventHandler&,const osg::CopyOp&) {}
235
236 osg::ref_ptr<osg::Switch> _switch;
237 osg::ref_ptr<osg::TexMat> _texmatLeft;
238 osg::ref_ptr<osg::TexMat> _texmatRight;
239 float _radius;
240 float _height;
241 float _length;
242 bool _firstTraversal;
243 unsigned int _activeSlide;
244 double _previousTime;
245 double _timePerSlide;
246 bool _autoSteppingActive;
247 float _initSeperationX;
248 float _currentSeperationX;
249 float _initSeperationY;
250 float _currentSeperationY;
251 FileList _fileList;
252
253 };
254
SlideEventHandler()255 SlideEventHandler::SlideEventHandler():
256 _switch(0),
257 _texmatLeft(0),
258 _texmatRight(0),
259 _firstTraversal(true),
260 _activeSlide(0),
261 _previousTime(-1.0f),
262 _timePerSlide(5.0),
263 _autoSteppingActive(false)
264 {
265 }
266
set(osg::Switch * sw,float offsetX,float offsetY,osg::TexMat * texmatLeft,osg::TexMat * texmatRight,float timePerSlide,bool autoSteppingActive)267 void SlideEventHandler::set(osg::Switch* sw, float offsetX, float offsetY, osg::TexMat* texmatLeft, osg::TexMat* texmatRight, float timePerSlide, bool autoSteppingActive)
268 {
269 _switch = sw;
270 _switch->setUpdateCallback(this);
271
272 _texmatLeft = texmatLeft;
273 _texmatRight = texmatRight;
274
275 _timePerSlide = timePerSlide;
276 _autoSteppingActive = autoSteppingActive;
277
278 _initSeperationX = offsetX;
279 _currentSeperationX = _initSeperationX;
280
281 _initSeperationY = offsetY;
282 _currentSeperationY = _initSeperationY;
283
284 initTexMatrices();
285
286 }
287
set(FileList fileList,osg::Switch * sw,float offsetX,float offsetY,osg::TexMat * texmatLeft,osg::TexMat * texmatRight,float radius,float height,float length,float timePerSlide,bool autoSteppingActive)288 void SlideEventHandler::set(FileList fileList, osg::Switch* sw, float offsetX, float offsetY, osg::TexMat* texmatLeft, osg::TexMat* texmatRight, float radius, float height, float length, float timePerSlide, bool autoSteppingActive)
289 {
290 _switch = sw;
291 _switch->setUpdateCallback(this);
292 _fileList=FileList(fileList);
293
294 osg::ref_ptr<osg::Group> imageGroup = loadImages(fileList[0],fileList[1],texmatLeft,texmatRight, radius, height, length);
295 if (imageGroup.get())_switch->addChild(imageGroup.get());
296
297 _texmatLeft = texmatLeft;
298 _texmatRight = texmatRight;
299
300 _radius=radius;
301 _height=height;
302 _length=length;
303
304 _timePerSlide = timePerSlide;
305 _autoSteppingActive = autoSteppingActive;
306
307 _initSeperationX = offsetX;
308 _currentSeperationX = _initSeperationX;
309
310 _initSeperationY = offsetY;
311 _currentSeperationY = _initSeperationY;
312
313 initTexMatrices();
314 }
315
316
handle(const osgGA::GUIEventAdapter & ea,osgGA::GUIActionAdapter &)317 bool SlideEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&)
318 {
319 switch(ea.getEventType())
320 {
321 case(osgGA::GUIEventAdapter::KEYDOWN):
322 {
323 if (ea.getKey()=='a')
324 {
325 _autoSteppingActive = !_autoSteppingActive;
326 _previousTime = ea.getTime();
327 return true;
328 }
329 else if ((ea.getKey()=='n') || (ea.getKey()==osgGA::GUIEventAdapter::KEY_Right))
330 {
331 nextSlide();
332 return true;
333 }
334 else if ((ea.getKey()=='p') || (ea.getKey()==osgGA::GUIEventAdapter::KEY_Left))
335 {
336 previousSlide();
337 return true;
338 }
339 else if ((ea.getKey()=='w') || (ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Add))
340 {
341 scaleImage(0.99f);
342 return true;
343 }
344 else if ((ea.getKey()=='s') || (ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Subtract))
345 {
346 scaleImage(1.01f);
347 return true;
348 }
349 else if (ea.getKey()=='j')
350 {
351 offsetImage(-0.001f,0.0f);
352 return true;
353 }
354 else if (ea.getKey()=='k')
355 {
356 offsetImage(0.001f,0.0f);
357 return true;
358 }
359 else if (ea.getKey()=='i')
360 {
361 offsetImage(0.0f,-0.001f);
362 return true;
363 }
364 else if (ea.getKey()=='m')
365 {
366 offsetImage(0.0f,0.001f);
367 return true;
368 }
369 else if (ea.getKey()==' ')
370 {
371 initTexMatrices();
372 return true;
373 }
374 return false;
375 }
376 case(osgGA::GUIEventAdapter::DRAG):
377 case(osgGA::GUIEventAdapter::MOVE):
378 {
379 static float px = ea.getXnormalized();
380 static float py = ea.getYnormalized();
381
382 float dx = ea.getXnormalized()-px;
383 float dy = ea.getYnormalized()-py;
384
385 px = ea.getXnormalized();
386 py = ea.getYnormalized();
387
388 rotateImage(dx,dy);
389
390 return true;
391 }
392
393 default:
394 return false;
395 }
396 }
397
getUsage(osg::ApplicationUsage & usage) const398 void SlideEventHandler::getUsage(osg::ApplicationUsage& usage) const
399 {
400 usage.addKeyboardMouseBinding("Space","Reset the image position to center");
401 usage.addKeyboardMouseBinding("a","Toggle on/off the automatic advancement for image to image");
402 usage.addKeyboardMouseBinding("n","Advance to next image");
403 usage.addKeyboardMouseBinding("p","Move to previous image");
404 usage.addKeyboardMouseBinding("q","Zoom into the image");
405 usage.addKeyboardMouseBinding("a","Zoom out of the image");
406 usage.addKeyboardMouseBinding("j","Reduce horizontal offset");
407 usage.addKeyboardMouseBinding("k","Increase horizontal offset");
408 usage.addKeyboardMouseBinding("m","Reduce vertical offset");
409 usage.addKeyboardMouseBinding("i","Increase vertical offset");
410 }
411
operator ()(osg::Node * node,osg::NodeVisitor * nv)412 void SlideEventHandler::operator()(osg::Node* node, osg::NodeVisitor* nv)
413 {
414 if (_autoSteppingActive && nv->getFrameStamp())
415 {
416 double time = nv->getFrameStamp()->getSimulationTime();
417
418 if (_firstTraversal)
419 {
420 _firstTraversal = false;
421 _previousTime = time;
422 }
423 else if (time-_previousTime>_timePerSlide)
424 {
425 _previousTime = time;
426
427 nextSlide();
428 }
429
430 }
431
432 traverse(node,nv);
433 }
434
nextSlide()435 void SlideEventHandler::nextSlide()
436 {
437
438 if (_switch->getNumChildren()==0) return;
439
440 ++_activeSlide;
441
442 if (_fileList.size()>0) {
443 if (_activeSlide>= _fileList.size()/2 ) _activeSlide = 0;
444 osg::ref_ptr<osg::Group> images = loadImages(_fileList[2*_activeSlide],_fileList[2*_activeSlide+1],_texmatLeft.get(),_texmatRight.get(),_radius,_height,_length);
445 if (images.valid()) _switch->replaceChild(_switch->getChild(0),images.get());
446
447 } else {
448 if (_activeSlide>=_switch->getNumChildren()) _activeSlide = 0;
449
450 _switch->setSingleChildOn(_activeSlide);
451 }
452 }
453
previousSlide()454 void SlideEventHandler::previousSlide()
455 {
456 if (_switch->getNumChildren()==0) return;
457
458 if (_fileList.size()>0) {
459 if (_activeSlide==0) _activeSlide = _fileList.size()/2-1;
460 else --_activeSlide;
461 osg::ref_ptr<osg::Group> images = loadImages(_fileList[2*_activeSlide],_fileList[2*_activeSlide+1],_texmatLeft.get(),_texmatRight.get(),_radius,_height,_length);
462 if (images.valid()) _switch->replaceChild(_switch->getChild(0),images.get());
463 } else {
464 if (_activeSlide==0) _activeSlide = _switch->getNumChildren()-1;
465 else --_activeSlide;
466
467 _switch->setSingleChildOn(_activeSlide);
468 }
469 }
470
scaleImage(float s)471 void SlideEventHandler::scaleImage(float s)
472 {
473 _texmatLeft->setMatrix(_texmatLeft->getMatrix()*osg::Matrix::translate(-0.5f,-0.5f,0.0f)*osg::Matrix::scale(s,s,1.0f)*osg::Matrix::translate(0.5f,0.5f,0.0f));
474 _texmatRight->setMatrix(_texmatRight->getMatrix()*osg::Matrix::translate(-0.5f,-0.5f,0.0f)*osg::Matrix::scale(s,s,1.0f)*osg::Matrix::translate(0.5f,0.5f,0.0f));
475 }
476
offsetImage(float ds,float dt)477 void SlideEventHandler::offsetImage(float ds,float dt)
478 {
479 _currentSeperationX+=ds;
480 _currentSeperationY+=dt;
481 osg::notify(osg::NOTICE)<<"image offset x = "<<_currentSeperationX<<" y ="<<_currentSeperationY<<std::endl;
482 _texmatLeft->setMatrix(_texmatLeft->getMatrix()*osg::Matrix::translate(ds,dt,0.0f));
483 _texmatRight->setMatrix(_texmatRight->getMatrix()*osg::Matrix::translate(-ds,-dt,0.0f));
484 }
485
rotateImage(float rx,float ry)486 void SlideEventHandler::rotateImage(float rx,float ry)
487 {
488 const float scale = 0.5f;
489 _texmatLeft->setMatrix(_texmatLeft->getMatrix()*osg::Matrix::translate(-rx*scale,-ry*scale,0.0f));
490 _texmatRight->setMatrix(_texmatRight->getMatrix()*osg::Matrix::translate(-rx*scale,-ry*scale,0.0f));
491 }
492
initTexMatrices()493 void SlideEventHandler::initTexMatrices()
494 {
495 _texmatLeft->setMatrix(osg::Matrix::translate(_initSeperationX,_initSeperationY,0.0f));
496 _texmatRight->setMatrix(osg::Matrix::translate(-_initSeperationX,-_initSeperationY,0.0f));
497 }
498
499
500
main(int argc,char ** argv)501 int main( int argc, char **argv )
502 {
503 // use an ArgumentParser object to manage the program arguments.
504 osg::ArgumentParser arguments(&argc,argv);
505
506 // set up the usage document, in case we need to print out how to use this program.
507 arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates use node masks to create stereo images.");
508 arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] image_file_left_eye image_file_right_eye");
509 arguments.getApplicationUsage()->addCommandLineOption("-d <float>","Time delay in seconds between the display of successive image pairs when in auto advance mode.");
510 arguments.getApplicationUsage()->addCommandLineOption("-a","Enter auto advance of image pairs on start up.");
511 arguments.getApplicationUsage()->addCommandLineOption("-x <float>","Horizontal offset of left and right images.");
512 arguments.getApplicationUsage()->addCommandLineOption("-y <float>","Vertical offset of left and right images.");
513 arguments.getApplicationUsage()->addCommandLineOption("--disk","Keep images on disk");
514 arguments.getApplicationUsage()->addCommandLineOption("-files <filename>","Load filenames from a file");
515 arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
516 arguments.getApplicationUsage()->addCommandLineOption("--SingleThreaded","Select SingleThreaded threading model for viewer.");
517 arguments.getApplicationUsage()->addCommandLineOption("--CullDrawThreadPerContext","Select CullDrawThreadPerContext threading model for viewer.");
518 arguments.getApplicationUsage()->addCommandLineOption("--DrawThreadPerContext","Select DrawThreadPerContext threading model for viewer.");
519 arguments.getApplicationUsage()->addCommandLineOption("--CullThreadPerCameraDrawThreadPerContext","Select CullThreadPerCameraDrawThreadPerContext threading model for viewer.");
520
521
522 // construct the viewer.
523 osgViewer::Viewer viewer(arguments);
524
525 // register the handler to add keyboard and mouse handling.
526 SlideEventHandler* seh = new SlideEventHandler();
527 viewer.addEventHandler(seh);
528
529 // read any time delay argument.
530 float timeDelayBetweenSlides = 5.0f;
531 while (arguments.read("-d",timeDelayBetweenSlides)) {}
532
533 bool autoSteppingActive = false;
534 while (arguments.read("-a")) autoSteppingActive = true;
535
536 float offsetX=0.0f;
537 while (arguments.read("-x",offsetX)) {}
538
539 float offsetY=0.0f;
540 while (arguments.read("-y",offsetY)) {}
541
542 bool onDisk=false;
543 while (arguments.read("--disk")) { onDisk=true;}
544
545 std::string filename="";
546 FileList fileList;
547 // extract the filenames from the a file, one filename per line.
548 while (arguments.read("-files",filename)) {
549 osgDB::ifstream is(filename.c_str());
550 if (is) {
551 std::string line;
552 while (std::getline(is,line,'\n')) fileList.push_back(line);
553 is.close();
554 }
555
556 }
557
558 // if user request help write it out to cout.
559 if (arguments.read("-h") || arguments.read("--help"))
560 {
561 arguments.getApplicationUsage()->write(std::cout);
562 return 1;
563 }
564
565 osgViewer::Viewer::ThreadingModel threading = osgViewer::Viewer::SingleThreaded;
566 while (arguments.read("--SingleThreaded")) threading = osgViewer::Viewer::SingleThreaded;
567 while (arguments.read("--CullDrawThreadPerContext")) threading = osgViewer::Viewer::CullDrawThreadPerContext;
568 while (arguments.read("--DrawThreadPerContext")) threading = osgViewer::Viewer::DrawThreadPerContext;
569 while (arguments.read("--CullThreadPerCameraDrawThreadPerContext")) threading = osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext;
570
571 viewer.setThreadingModel(threading);
572
573 // any option left unread are converted into errors to write out later.
574 arguments.reportRemainingOptionsAsUnrecognized();
575
576 // report any errors if they have occurred when parsing the program arguments.
577 if (arguments.errors())
578 {
579 arguments.writeErrorMessages(std::cout);
580 return 1;
581 }
582
583 // extract the filenames from the arguments list.
584 for(int pos=1;pos<arguments.argc();++pos)
585 {
586 if (arguments.isString(pos)) fileList.push_back(arguments[pos]);
587 }
588
589 if (fileList.empty())
590 {
591 fileList.push_back("Images/dog_left_eye.jpg");
592 fileList.push_back("Images/dog_right_eye.jpg");
593 }
594 else if (fileList.size()<2)
595 {
596 arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
597 return 1;
598 }
599
600 // now the windows have been realized we switch off the cursor to prevent it
601 // distracting the people seeing the stereo images.
602 double fovy, aspectRatio, zNear, zFar;
603 viewer.getCamera()->getProjectionMatrixAsPerspective(fovy, aspectRatio, zNear, zFar);
604
605 float radius = 1.0f;
606 float height = 2*radius*tan(osg::DegreesToRadians(fovy)*0.5f);
607 float length = osg::PI*radius; // half a cylinder.
608
609 // use a texture matrix to control the placement of the image.
610 osg::TexMat* texmatLeft = new osg::TexMat;
611 osg::TexMat* texmatRight = new osg::TexMat;
612
613 // creat the scene from the file list.
614 osg::ref_ptr<osg::Switch> rootNode;
615 if (!onDisk) rootNode = createScene(fileList,texmatLeft,texmatRight,radius,height,length);
616 else rootNode=new osg::Switch();
617
618 //osgDB::writeNodeFile(*rootNode,"test.osgt");
619
620
621
622 viewer.getCamera()->setCullMask(0xffffffff);
623 viewer.getCamera()->setCullMaskLeft(0x00000001);
624 viewer.getCamera()->setCullMaskRight(0x00000002);
625
626 // set up the use of stereo by default.
627 osg::DisplaySettings::instance()->setStereo(true);
628
629 if (osg::DisplaySettings::instance()->getStereoMode()==osg::DisplaySettings::ANAGLYPHIC)
630 {
631 rootNode->setStateSet(createColorToGreyscaleStateSet());
632 }
633
634
635 // set the scene to render
636 viewer.setSceneData(rootNode.get());
637
638
639 // create the windows and run the threads.
640 viewer.realize();
641
642
643 // switch off the cursor
644 osgViewer::Viewer::Windows windows;
645 viewer.getWindows(windows);
646 for(osgViewer::Viewer::Windows::iterator itr = windows.begin();
647 itr != windows.end();
648 ++itr)
649 {
650 (*itr)->useCursor(false);
651 }
652
653 viewer.setFusionDistance(osgUtil::SceneView::USE_FUSION_DISTANCE_VALUE,radius);
654
655 // set up the SlideEventHandler.
656 if (onDisk) seh->set(fileList,rootNode.get(),offsetX,offsetY,texmatLeft,texmatRight,radius,height,length,timeDelayBetweenSlides,autoSteppingActive);
657 else seh->set(rootNode.get(),offsetX,offsetY,texmatLeft,texmatRight,timeDelayBetweenSlides,autoSteppingActive);
658
659 osg::Matrix homePosition;
660 homePosition.makeLookAt(osg::Vec3(0.0f,0.0f,0.0f),osg::Vec3(0.0f,1.0f,0.0f),osg::Vec3(0.0f,0.0f,1.0f));
661
662 while( !viewer.done() )
663 {
664 viewer.getCamera()->setViewMatrix(homePosition);
665
666 // fire off the cull and draw traversals of the scene.
667 viewer.frame();
668
669 }
670
671 return 0;
672 }
673
674