main.C

00001 /*
00002  * This file is part of the "Archon" framework.
00003  * (http://files3d.sourceforge.net)
00004  *
00005  * Copyright © 2002 by Kristian Spangsege and Brian Kristiansen.
00006  *
00007  * Permission to use, copy, modify, and distribute this software and
00008  * its documentation under the terms of the GNU General Public License is
00009  * hereby granted. No representations are made about the suitability of
00010  * this software for any purpose. It is provided "as is" without express
00011  * or implied warranty. See the GNU General Public License
00012  * (http://www.gnu.org/copyleft/gpl.html) for more details.
00013  *
00014  * The characters in this file are ISO8859-1 encoded.
00015  *
00016  * The documentation in this file is in "Doxygen" style
00017  * (http://www.doxygen.org).
00018  */
00019 
00020 #include <unistd.h>
00021 
00022 
00023 #include <string>
00024 #include <typeinfo>
00025 #include <iostream>
00026 #include <vector>
00027 #include <map>
00028 
00029 #include <archon/util/term.H>
00030 #include <archon/util/text.H>
00031 #include <archon/util/options.H>
00032 #include <archon/util/uri.H>
00033 #include <archon/util/thread.H>
00034 #include <archon/util/logger.H>
00035 #include <archon/util/parse_values.H>
00036 #include <archon/util/text.H>
00037 #include <archon/x3d/exception.H>
00038 #include <archon/x3d/x3d.H>
00039 #include <archon/x3d/load.H>
00040 
00041 #include "exception.H"
00042 #include "options.H"
00043 #include "object.H"
00044 #include "world.H"
00045 #include "engine.H"
00046 #include "sceneloader.H"
00047 #include "scene_view.H"
00048 
00049 using namespace std;
00050 
00051 namespace Archon
00052 {
00053   using namespace Utilities;
00054 
00055   namespace Raytracer
00056   {
00057     struct Logger: public Utilities::Logger
00058     {
00059       Semaphore s;
00060 
00061       virtual ~Logger() {}
00062 
00063       void log(string message)
00064       {
00065         Logger::get()->log(message);
00066       }
00067     }
00068     logger;
00069 
00070     /*
00071     struct Producer: public Thread
00072     {
00073       Stream::Writer w;
00074       const char *s;
00075 
00076       Producer(Stream::Writer w, const char *s):w(w), s(s) {}
00077       ~Producer() { wait(); }
00078 
00079       virtual void main()
00080       {
00081         char buffer[64];
00082 
00083         for(int i=0;i<2;++i)
00084         {
00085           sprintf(buffer, "%s(%d)\n", s, i);
00086           w.writeAll(buffer, strlen(buffer));
00087         }
00088         w.close();
00089       }
00090     };
00091 
00092     struct Consumer: public Thread
00093     {
00094       Stream::Reader r;
00095 
00096       Consumer(Stream::Reader r):r(r) {}
00097       ~Consumer() { wait(); }
00098 
00099       virtual void main()
00100       {
00101         for(;;)
00102         {
00103           char b[1025];
00104           int n = r.read(b, 1025);
00105           if(n == 0) break;
00106           cerr << string(b, n);
00107         }
00108         r.close();
00109       }
00110     };
00111     */
00112 
00113     int main(int argc, const char *argv[])
00114     {
00115       /*
00116       //
00117       // Example 4.34 from the Dragon Book
00118       //
00119       {
00120       CFG g;
00121       const int plus = g.defineTerminal("+");
00122       const int star = g.defineTerminal("*");
00123       const int lpar = g.defineTerminal("(");
00124       const int rpar = g.defineTerminal(")");
00125       const int id   = g.defineTerminal("id");
00126 
00127       const int e  = g.defineNonterminal("E");
00128       const int t  = g.defineNonterminal("T");
00129       const int f  = g.defineNonterminal("F");
00130 
00131       g.addProduction(e, CFG::nonterm(e), CFG::term(plus), CFG::nonterm(t));
00132       g.addProduction(e, CFG::nonterm(t));
00133       g.addProduction(t, CFG::nonterm(t), CFG::term(star), CFG::nonterm(f));
00134       g.addProduction(t, CFG::nonterm(f));
00135       g.addProduction(f, CFG::term(lpar), CFG::nonterm(e), CFG::term(rpar));
00136       g.addProduction(f, CFG::term(id));
00137 
00138       cerr << g.print(System::Term::getWidth()) << "\n";
00139       ClrParser parser(g);      
00140       }
00141       */
00142 
00143       /*
00144       //
00145       // Example 4.39 from the Dragon Book
00146       //
00147       {
00148       CFG g;
00149       const int equal = g.defineTerminal("=");
00150       const int star  = g.defineTerminal("*");
00151       const int id    = g.defineTerminal("id");
00152 
00153       const int S  = g.defineNonterminal("S");
00154       const int L  = g.defineNonterminal("L");
00155       const int R  = g.defineNonterminal("R");
00156 
00157       g.addProduction(S, CFG::nonterm(L), CFG::term(equal), CFG::nonterm(R));
00158       g.addProduction(S, CFG::nonterm(R));
00159       g.addProduction(L, CFG::term(star), CFG::nonterm(R));
00160       g.addProduction(L, CFG::term(id));
00161       g.addProduction(R, CFG::nonterm(L));
00162 
00163       cerr << g.print(System::Term::getWidth()) << "\n";
00164       ClrParser parser(g);      
00165       }
00166       */
00167 
00168       /*
00169       //
00170       // Example 4.42 from the Dragon Book
00171       //
00172       {
00173       CFG g;
00174       const int d = g.defineTerminal("d");
00175       const int c = g.defineTerminal("c");
00176 
00177       const int S  = g.defineNonterminal("S");
00178       const int C  = g.defineNonterminal("C");
00179 
00180       g.addProduction(S, CFG::nonterm(C), CFG::nonterm(C));
00181       g.addProduction(C, CFG::term(c), CFG::nonterm(C));
00182       g.addProduction(C, CFG::term(d));
00183 
00184       cerr << g.print(System::Term::getWidth()) << "\n";
00185       ClrParser parser(g);      
00186       }
00187       */
00188 
00189       /*
00190         Stream::Reader r;
00191         Stream::Writer w;
00192         Stream::makePipe(r, w);
00193         Producer producer1(w, "Alpha");
00194         Producer producer2(w, "Beta");
00195         Producer producer3(w, "Gamma");
00196         Consumer consumer(r);
00197         r.close();
00198         w.close();
00199         producer1.start();
00200         producer2.start();
00201         producer3.start();
00202         consumer.start();
00203       */
00204 
00205       Options o;
00206 
00207       o.addVar("h", "help", opt_help, true,
00208                "Describe the parameters of the raytracer");
00209       o.addVar("d", "display", opt_displayRendering, true,
00210                "Display image during rendering");
00211       o.addVar("r", "resolution", opt_resolution, opt_resolution,
00212                "Set resolution of rendered image",
00213                Options::wantArg_always);
00214       o.addVar("o", "output-file", opt_outputFileName, opt_outputFileName,
00215                "Set filename of rendered image",
00216                Options::wantArg_always);
00217       o.addVar("e", "eyepoint", opt_eyepoint, opt_eyepoint,
00218                "Location of the eye in the default view",
00219                Options::wantArg_always);
00220       o.addVar("l", "lookat", opt_lookat, opt_lookat,
00221                "Point of interest in the default view",
00222                Options::wantArg_always);
00223       o.addVar("f", "field-of-view", opt_fieldOfView, opt_fieldOfView,
00224                "Smallest edge-to-edge angle of viewplane when seen from the eye",
00225                Options::wantArg_always);
00226       o.addVar("b", "background-color", opt_backgroundColor, opt_backgroundColor,
00227                "R,G,B or R,G,B,A color of background (range 0-1)",
00228                Options::wantArg_always);
00229       o.addVar("p", "photon-map", opt_generatePhotonMap, true,
00230                "Generate a photon map and use it to produce caustics");
00231       o.addVar("a", "photon-map-alone", opt_showOnlyPhotonMap, true,
00232                "Only visualize the photon-map during raytracing");
00233       o.addVar("c", "caustic-photons", opt_causticPhotons, opt_causticPhotons,
00234                "Total number of caustic photons to emit (each light source gets a share)",
00235                Options::wantArg_always);
00236       o.addVar("P", "photons_in_estimate", opt_photonsInEstimate, opt_photonsInEstimate,
00237                "Number of photons in radiance estimate",
00238                Options::wantArg_always);
00239       o.addVar("v", "preview", opt_preview, true,
00240                "Preview the scene to adjust viewpoint");
00241       o.addVar("V", "preview-only", opt_previewOnly, true,
00242                "Only view the scene in the previewer - don't raytrace (implies -v)");
00243       o.addVar("F", "full-screen", opt_fullScreen, true,
00244                "Preview in fullscreen mode");
00245       o.addVar("R", "preview-resolution", opt_previewResolution, opt_previewResolution,
00246                "Set resolution of preview window",
00247                Options::wantArg_always);
00248       o.addVar("L", "show-light-sources", opt_showLightSources, true,
00249                "Display light sources in the previewer as points in their color");
00250       o.addVar("H", "head-light", opt_headLight, true,
00251                "Enable head light for scenes with no defined light sources",
00252                Options::wantArg_optional);
00253       o.addVar("t", "max-loader-threads", opt_maxLoaderThreads, opt_maxLoaderThreads,
00254                "Maximum number of threads to spawn for loading scene components",
00255                Options::wantArg_always);
00256       o.addVar("i", "max-loader-thread-idle", opt_maxLoaderThreadIdle, opt_maxLoaderThreadIdle,
00257                "Maximum idle time in seconds for loader threads before disposal",
00258                Options::wantArg_always);
00259       o.addVar(0, "frame-rate", opt_frameRate, opt_frameRate,
00260                "Set the number of frames per second when previewing",
00261                Options::wantArg_always);
00262       o.addVar("s", "subdivision", opt_subdivision, opt_subdivision,
00263                "Set subdivision of curved geometry when previewing (affects sphers, tori, cylinders and cones)",
00264                Options::wantArg_always);
00265 
00266       if(o.execute(argc, argv))
00267       {
00268         cerr << "Try --help\n";
00269         return 1;
00270       }
00271 
00272       UriReference x3dUriReference;
00273       bool malformedUri = false;
00274       Uri::SyntaxException uriException;
00275       if(argc>1) try
00276       {
00277         x3dUriReference = UriReference(argv[1]);
00278 
00279         /*
00280          * Build output file name now so that it can by displayed in the
00281          * option table
00282          */
00283         if(opt_outputFileName == "")
00284         {
00285           // Use the name in the input url as a basis for the output file name
00286           opt_outputFileName = Uri::decode(x3dUriReference.getUri().getFile(), false);
00287 
00288           // Chop off suffix if it is 'x3d'
00289           if(opt_outputFileName.size() >= 4 &&
00290              Text::compareIgnoreCase(opt_outputFileName.substr(opt_outputFileName.size()-4), ".x3d")==0)
00291             opt_outputFileName = opt_outputFileName.substr(0, opt_outputFileName.size()-4);
00292 
00293           opt_outputFileName += ".png";
00294         }
00295       }
00296       catch(Uri::SyntaxException e)
00297       {
00298         uriException = e;
00299         malformedUri = true;
00300       }
00301 
00302       if(opt_help)
00303       {
00304         cout <<
00305           "Raytracer by Brian Kristiansen & Kristian Spangsege\n"
00306           "\n"
00307           "Synopsis: " << argv[0] << " URI\n"
00308           "\n"
00309           "The URI must refer to an X3D file and\n"
00310           "may be specified relative to the current working directory.\n"
00311           "If you specify a fragment identifier it will be interpreted\n"
00312           "as the name of the viewpoint to use. For example\n"
00313           "  " << argv[0] << " house.x3d#front\n"
00314           "will render the house from the viewpoint named 'front'.\n"
00315           "\n"
00316           "Available options:\n";
00317         cout << o.list();
00318         return 0;
00319       }
00320 
00321       // Treat 1st arg as URL of X3D file to load
00322       if(argc < 2)
00323       {
00324         logger.log("Too few arguments");
00325         cerr << "Try --help\n";
00326         return 1;
00327       }
00328 
00329       if(argc > 2)
00330       {
00331         logger.log("Too many aguments");
00332         cerr << "Try --help\n";
00333         return 1;
00334       }
00335 
00336       if(malformedUri)
00337       {
00338         cerr << Uri::explain(uriException);
00339         exit(1);
00340       }
00341 
00342       X3D::initialize();
00343 
00344       Ref<X3D::Server> server = X3D::Server::get(opt_consoleName, opt_frameRate, logger,
00345                                                  uriSpecified, x3dUriReference.getUri(), opt_progressiveLoad);
00346 
00347       Ref<X3D::Scene> scene = server.getRootScene();
00348       Ref<X3D::Material> defaultMaterial = X3D::Material::type->instantiate(scene);
00349 
00350       // Set up the default viewpoint
00351       CoordSystem3 eye = CoordSystem3::identity;
00352       eye.origin += opt_eyepoint;
00353       eye.lookAt(opt_lookat);
00354       View view(eye, opt_fieldOfView, "default", "default");
00355 
00356       if(opt_preview || opt_previewOnly)
00357       {
00358         viewScene(scene.get(), x3dUriReference.getFragmentIdentifier(),
00359                   &view, opt_backgroundColor,
00360                   opt_previewResolution.x, opt_previewResolution.y,
00361                   opt_fullScreen, opt_showLightSources, opt_headLight,
00362                   opt_subdivision.x, opt_subdivision.y, opt_frameRate,
00363                   &logger);
00364       }
00365       else
00366       {
00367         vector<View> views;
00368 
00369         get_scene(scene, defaultMaterial, 0, &views, 0, &logger);
00370 
00371         int viewIndex = -1;
00372 
00373         string viewName = x3dUriReference.getFragmentIdentifier();
00374         if(!viewName.empty())
00375         {
00376           for(unsigned i=0; i<views.size(); ++i)
00377             if(views[i].name == viewName)
00378             {
00379               viewIndex = i;
00380               break;
00381             }
00382           if(viewIndex == -1)
00383           {
00384             cerr << "No view point defined with the name '" << viewName << "'\n";
00385             exit(1);
00386           }
00387         }
00388         else if(!views.empty()) for(;;)
00389         {
00390           vector<double> columnWidthFractions;
00391           columnWidthFractions.push_back(0.1);
00392           columnWidthFractions.push_back(0.3);
00393           columnWidthFractions.push_back(0.6);
00394           Text::Table<string> table(views.size()+1, columnWidthFractions);
00395           table(0, 1) = "Name";
00396           table(0, 2) = "Description";
00397           for(unsigned i=0; i<views.size(); ++i)
00398           {
00399             table(i+1, 0) = Text::toString(i+1);
00400             table(i+1, 1) = views[i].name;
00401             table(i+1, 2) = views[i].description;
00402           }
00403 
00404           cout <<
00405             "\nThe following views are defined:\n\n" <<
00406             Text::format(table, Term::getWidth(), 2, true) <<
00407             "\nChoose one [1]: ";
00408           string input;
00409           getline(cin, input);
00410           input = Text::trim(input);
00411           if(input.empty())
00412           {
00413             viewIndex = 0;
00414             break;
00415           }
00416           else try
00417           {
00418             viewIndex = ParseValues::parseInteger(false, input.c_str()) - 1;
00419             if(viewIndex >= 0 && viewIndex < (int)views.size()) break;
00420           }
00421           catch(ParseValues::Exception) {}
00422           cout << "Illegal choise!\n";
00423         }
00424 
00425         if(viewIndex != -1) view = views[viewIndex];
00426       }
00427 
00428       if(!opt_previewOnly)
00429       {
00430         World world(opt_backgroundColor, 0.01, 10, true,
00431                     opt_photonsInEstimate,
00432                     opt_showOnlyPhotonMap && opt_generatePhotonMap);
00433 
00434         get_scene(scene, defaultMaterial, &world, 0, 0, &logger);
00435 
00436         Engine(&logger).render(&world, view);
00437       }
00438 
00439       return 0;
00440     }
00441 
00442     void handle_unexpected()
00443     {
00444       try { throw; }
00445       catch(exception &e)
00446       {
00447         cerr << typeid(e).name() << ": " << e.what() << "\n";
00448         abort();
00449       }
00450       catch(Utilities::Exception &e)
00451       {
00452         cerr << typeid(e).name() << ": " << e.getMessage() << "\n";
00453         abort();
00454       }
00455       catch(X3D::Exception &e)
00456       {
00457         cerr << typeid(e).name() << ": " << e.getMessage() << "\n";
00458         abort();
00459       }
00460       catch(Raytracer::Exception &e)
00461       {
00462         cerr << typeid(e).name() << ": " << e.getMessage() << "\n";
00463         abort();
00464       }
00465       catch(...)
00466       {
00467         cerr << "Caught unknown exception\n";
00468         abort();
00469       }
00470     }
00471   }
00472 }
00473 
00474 int main(int argc, const char *argv[]) throw()
00475 {
00476   set_unexpected(Archon::Raytracer::handle_unexpected);
00477 
00478   return Archon::Raytracer::main(argc, argv);
00479 }

Generated on Sun Jul 30 22:55:41 2006 for Archon by  doxygen 1.4.4