source: swollen_viewer/swollen/main.cpp @ 2612

Last change on this file since 2612 was 1968, checked in by darran, 19 years ago
  • Setting SWOLLEN_BINDIR environmental variable allows swollen to locate needed texture maps
File size: 12.6 KB
Line 
1/*
2  SWWViewer
3
4  An OpenSceneGraph viewer for pyVolution SWW files.
5  copyright (C) 2004-2005 Geoscience Australia
6*/
7
8#include <iostream>
9#include <fstream>
10
11#include <osg/Group>
12#include <osg/Material>
13#include <osg/MatrixTransform>
14#include <osg/Notify>
15#include <osg/PositionAttitudeTransform>
16#include <osg/StateAttribute>
17#include <osgDB/FileNameUtils>
18#include <osgDB/FileUtils>
19
20#include <animation.h>
21#include <project.h>
22#include <SWWReader.h>
23#include <bedslope.h>
24#include <hud.h>
25#include <keyboardeventhandler.h>
26#include <directionallight.h>
27#include <state.h>
28#include <watersurface.h>
29#include <customviewer.h>
30#include <customargumentparser.h>
31
32// prototypes
33osg::Transform* createSky(float radius, const std::string filename);
34extern const char* version();
35
36
37int main( int argc, char **argv )
38{
39
40   // use an ArgumentParser object to manage the program arguments.
41   // this custom version detects if the last argument is a macro file
42   // and modifies the argument list accordingly so the following code works ...
43   CustomArgumentParser arguments( &argc, argv );
44
45
46   // set up the usage document
47   std::string appname = arguments.getApplicationName();
48   arguments.getApplicationUsage()->setDescription( appname );
49   arguments.getApplicationUsage()->setCommandLineUsage("swollen [options] swwfile ...");
50   arguments.getApplicationUsage()->addCommandLineOption("-help", "Display this information");
51   arguments.getApplicationUsage()->addCommandLineOption("-scale <float>", "Vertical scale factor");
52   arguments.getApplicationUsage()->addCommandLineOption("-tps <rate>", "Timesteps per second");
53   arguments.getApplicationUsage()->addCommandLineOption("-hmin <float>", "Height below which transparency is set to zero");
54   arguments.getApplicationUsage()->addCommandLineOption("-hmax <float>", "Height above which transparency is set to alphamax");
55   arguments.getApplicationUsage()->addCommandLineOption("-alphamin <float 0-1>", "Transparency value at hmin");
56   arguments.getApplicationUsage()->addCommandLineOption("-alphamax <float 0-1>", "Maximum transparency clamp value");
57   arguments.getApplicationUsage()->addCommandLineOption("-lightpos <float>,<float>,<float>", "x,y,z of bedslope directional light (z is up, default is overhead)");
58   arguments.getApplicationUsage()->addCommandLineOption("-movie <dirname>", "Save numbered images to named directory and quit");
59   arguments.getApplicationUsage()->addCommandLineOption("-loop", "Repeated (looped) playback of .swm files");
60   arguments.getApplicationUsage()->addCommandLineOption("-nosky", "Omit background sky");
61   arguments.getApplicationUsage()->addCommandLineOption("-cullangle <float angle 0-90>", "Cull triangles steeper than this value");
62   arguments.getApplicationUsage()->addCommandLineOption("-texture <file>", "Image to use for bedslope topography");
63   arguments.getApplicationUsage()->addCommandLineOption("-version", "Revision number and creation (not compile) date");
64
65
66   // construct the viewer.
67   CustomViewer viewer(arguments);
68
69
70   // set up with sensible default event handlers
71   viewer.setUpViewer( osgProducer::Viewer::STANDARD_SETTINGS );
72   viewer.setClearColor( osg::Vec4(DEF_BACKGROUND_COLOUR) );
73   //viewer.getCamera(0)->getRenderSurface()->setWindowRectangle(200,300,400,300);
74   viewer.getCullSettings().setComputeNearFarMode( osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES );
75
76
77   // animation
78   StateList statelist;
79   bool playbackmode;
80   bool recordingmode = false;
81   bool savemovie = false;
82   bool loop = false;
83   unsigned int playback_index = 0;
84   std::string moviedir;
85   Animation animation;
86
87   if( arguments.isSWM() )
88   {
89      playbackmode = true;
90      statelist.read( arguments.getFilename() );
91      if( arguments.read("-movie",moviedir) ) 
92      {
93         savemovie = true;  // flag to store frames and quit ...
94         animation.setDirectory( moviedir );
95         animation.setViewer( viewer );
96      }
97      if( arguments.read("-loop") ) 
98         loop = true;
99   }
100   else
101   {
102      playbackmode = false;
103      savemovie = false;
104      loop = true;  // playback in none macro mode should loop (otherwise you don't get a chance to save)
105   }
106
107
108   // get details on keyboard and mouse bindings used by the viewer
109   viewer.getUsage(*arguments.getApplicationUsage());
110
111   // if user requested help, write it out to cout
112   if( arguments.read("-help") || arguments.read("--help") || arguments.read("-h") )
113   {
114      arguments.getApplicationUsage()->write(std::cout);
115      return 1;
116   }
117
118
119   // same for version info
120   if( arguments.read("-version") )
121   {
122      std::cout << version() << std::endl;
123      return 1;
124   }
125
126
127   // last argument is either an sww file or an swm macro recording
128   int lastarg = arguments.argc()-1;
129   std::string swwfile = arguments.argv()[lastarg];
130   arguments.remove(lastarg);
131   if( osgDB::getLowerCaseFileExtension(swwfile) != std::string("sww") )
132   {
133      std::cout << "Require last argument be an .sww/.swm file ... quitting" << std::endl;
134      return 1; 
135   }
136   SWWReader *sww = new SWWReader(swwfile);
137   if (sww->isValid() == false)
138   {
139      std::cout << "Unable to load " << swwfile << " ... is this really an .sww file?" << std::endl;
140      return 1;
141   }
142
143
144   // need swollen binary directory which contains resource images
145   char *ptr;
146   if( (ptr = getenv( "SWOLLEN_BINDIR" )) )
147      sww->setSwollenDir( std::string(ptr) );
148   else if( osgDB::getFilePath(argv[0]) == "" )
149      sww->setSwollenDir( std::string(".") );
150   else
151      sww->setSwollenDir( osgDB::getFilePath(argv[0]) );
152   std::cout << sww->getSwollenDir() << std::endl;
153
154
155   // default arguments and command line parameters
156   float tmpfloat, tps, vscale;
157   if( !arguments.read("-tps", tps) || tps <= 0.0 ) tps = DEF_TPS;
158   if( !arguments.read("-scale", vscale) ) vscale = 1.0;
159   if( arguments.read("-hmin",tmpfloat) ) sww->setHeightMin( tmpfloat ); 
160   if( arguments.read("-hmax",tmpfloat) ) sww->setHeightMax( tmpfloat );     
161   if( arguments.read("-alphamin",tmpfloat) ) sww->setAlphaMin( tmpfloat );   
162   if( arguments.read("-alphamax",tmpfloat) ) sww->setAlphaMax( tmpfloat );
163   if( arguments.read("-cullangle",tmpfloat) ) sww->setCullAngle( tmpfloat );
164
165   std::string bedslopetexture;
166   if( arguments.read("-texture",bedslopetexture) ) sww->setBedslopeTexture( bedslopetexture );
167
168   // root node
169   osg::Group* rootnode = new osg::Group;
170
171   // transform
172   osg::PositionAttitudeTransform* model = new osg::PositionAttitudeTransform;
173   model->setName("position_attitude_transform");
174
175   // enscapsulates OpenGL state
176   osg::StateSet* rootStateSet = new osg::StateSet;
177
178   // Bedslope geometry
179   BedSlope* bedslope = new BedSlope(sww);
180
181   // Water geometry
182   WaterSurface* water = new WaterSurface(sww);
183
184   // Heads Up Display (text overlay)
185   HeadsUpDisplay* hud = new HeadsUpDisplay();
186   hud->setTitle("pyVolution SWW Viewer");
187   if( arguments.isSWM() )
188      hud->setMode("playback");
189
190
191   // Lighting
192   DirectionalLight* light = new DirectionalLight(rootStateSet);
193   light->setPosition( osg::Vec3(1,1,1) );  // z is up
194
195   std::string lightposstr;
196   while (arguments.read("-lightpos",lightposstr))
197   {
198      float x, y, z;
199      int count = sscanf( lightposstr.c_str(), "%f,%f,%f", &x, &y, &z );
200      if( count == 3 ) light->setPosition( osg::Vec3(x,y,z) );  // z is up
201      else osg::notify(osg::WARN) << "Invalid bedslope light position \"" << lightposstr << "\"" << std::endl;
202   }
203
204
205
206   // scenegraph hierarchy
207   rootnode->setStateSet(rootStateSet);
208   rootnode->addChild( hud->get() );
209   rootnode->addChild( light->get() );
210   rootnode->addChild(model);
211   model->addChild( bedslope->get() );
212   model->addChild( water->get() );
213
214
215   // allow vertical scaling from command line parameter
216   model->setScale( osg::Vec3(1.0, 1.0, vscale) );
217
218   // surrounding sky sphere
219   if( !arguments.read("-nosky") )
220      rootnode->addChild( createSky(10.0, sww->getSwollenDir() + std::string("/sky_small.jpg") ));
221
222
223   // add model to viewer.
224   viewer.setSceneData(rootnode);
225 
226   // any option left unread are converted into errors to write out later.
227   arguments.reportRemainingOptionsAsUnrecognized();
228 
229   // report any errors if they have occured when parsing the program aguments.
230   if (arguments.errors())
231   {
232      arguments.writeErrorMessages(std::cout);
233      return 1;
234   }
235
236
237   // register additional event handler
238   KeyboardEventHandler* event_handler = new KeyboardEventHandler(sww->getNumberOfTimesteps(), tps);
239   viewer.getEventHandlerList().push_front(event_handler);
240
241 
242   // create the windows and run the threads.
243   viewer.realize();
244
245
246   // initial camera position
247   CustomTerrainManipulator* terrainmanipulator = viewer.getTerrainManipulator();
248   terrainmanipulator->setNode( model );
249   terrainmanipulator->setAutoComputeHomePosition( false );
250   terrainmanipulator->setHomePosition(
251      osg::Vec3d(0,-3,3),    // camera location
252      osg::Vec3d(0,0,0),     // camera target
253      osg::Vec3d(0,1,1) );   // camera up vector
254   terrainmanipulator->moveToHome();
255   terrainmanipulator->enable();
256
257 
258   unsigned int timestep = 0;
259   bool done = false;
260   while( !done )
261   {
262   
263      // wait for all cull and draw threads to complete.
264      viewer.sync();
265
266      // user hits 'escape' to exit
267      if( viewer.done() )
268         done = true;
269
270
271      if( !playbackmode )
272      {
273
274         // current time
275         double time = viewer.getFrameStamp()->getReferenceTime();
276
277         event_handler->setTime( time );
278         timestep = event_handler->getTimestep();
279         water->setTimeStep(timestep);
280         hud->setTime( sww->getTime(timestep) );
281
282
283         // events
284         if( event_handler->toggleWireframe() )
285            water->toggleWireframe();
286         if( event_handler->toggleCulling() )
287            water->toggleCulling();
288
289         // '1' key starts/stops recording of view/position/setting info
290         if( event_handler->toggleRecording() )
291         {
292            switch( recordingmode )
293            {
294               case false : 
295                  recordingmode = true; 
296                  hud->setMode("recording");
297                  break;
298               case true : 
299                  recordingmode = false; 
300                  hud->setMode("");
301                  break;
302            }
303         }
304
305
306         // '2' key starts playback of recorded frames
307         if( event_handler->togglePlayback() && statelist.size() > 0 )
308         {
309            recordingmode = false;
310            playbackmode = true; 
311            hud->setMode("playback");
312            event_handler->setPaused( true );
313            playback_index = 0;
314         }
315
316         if( recordingmode )
317         {
318            State state = State();
319            state.setTimestep( event_handler->getTimestep() );
320            state.setCulling( sww->getCulling() );
321            state.setWireframe( water->getWireframe() );
322            state.setMatrix( viewer.getViewMatrix() );
323            statelist.push_back( state );
324         }
325      }
326
327      else
328
329      {
330         // might need to save image from previous pass ...
331         if( savemovie )
332            animation.saveImage( playback_index );
333
334         // in playback mode
335         State state = statelist.at( playback_index );
336         water->setTimeStep( state.getTimestep() );
337         water->setWireframe( state.getWireframe() );
338         water->setCulling( state.getCulling() );
339         hud->setTime( sww->getTime(state.getTimestep()) );
340
341         // loop playback
342         playback_index ++;
343         if( playback_index == statelist.size() )
344         {
345            if( loop )
346               playback_index = 0;
347            else
348               done = true;
349         }
350
351         // '2' key stops playback of recorded frames
352         if( event_handler->togglePlayback() )
353         {
354            playbackmode = false; 
355            hud->setMode("");
356            event_handler->setPaused( true );
357         }
358
359         viewer.setView( state.getMatrix() );
360      }
361
362
363      // '3' key causes compiled animation to be saved to disk
364      if( event_handler->toggleSave() )
365      {
366         std::fstream f;
367         f.open( "movie.swm", std::fstream::out );
368         if( f.is_open() )
369         {
370            f << "# SWM 1.0 START" << std::endl;
371            arguments.write( f );
372            statelist.write( f );
373            f << "# SWM END" << std::endl;
374            f.close();
375         }
376         std::cout << "Wrote macro file movie.swm" << std::endl;
377      }
378
379      // scene-graph updates
380      bedslope->update();
381      hud->update();
382      water->update();
383
384      // update the scene by traversing with the update visitor
385      viewer.update();
386
387      // fire off the cull and draw traversals of the scene.
388      viewer.frame();
389   }
390   
391   // wait for all cull and draw threads to complete before exit.
392   viewer.sync();
393
394   return 0;
395}
Note: See TracBrowser for help on using the repository browser.