MiltonApp.cpp

Go to the documentation of this file.
00001 /**<!-------------------------------------------------------------------->
00002    @file   MiltonApp.cpp
00003    @author Travis Fischer (fisch0920@gmail.com)
00004    @author Matthew Jacobs (jacobs.mh@gmail.com)
00005    @date   Fall 2008
00006    
00007    @brief
00008       Main entrypoint for Qt-based frontend which comes bundled with Milton 
00009    (including a non-graphical 'nox' mode for remote / batch rendering).
00010     
00011    @note 
00012       MiltonApp constructs an underlying QApplication, which must be 
00013    initialized before any other Qt user-interface objects are created.
00014    For this reason, initializing MiltonApp should generally be at the 
00015    very beginning of your program's mainline.
00016    
00017    @note
00018       MiltonApp is a singleton class and is only meant to be instantiated 
00019    once per program (generally the first line of main)
00020    <!-------------------------------------------------------------------->**/
00021 
00022 #include "MiltonApp.h"
00023 #include "RenderThread.h"
00024 #include <milton.h>
00025 
00026 #include <QApplication>
00027 #include <GL/glut.h>
00028 #include <typeinfo>
00029 
00030 #define DEFAULT_SCENEFILE   "default.js"
00031 
00032 bool MiltonApp::s_instance = false;
00033 
00034 MiltonApp::MiltonApp(int argc, char **argv, const std::string &title, 
00035                      bool enableGui)
00036    : m_title(title), m_qApplication(NULL), m_gui(NULL)
00037 {
00038    if (s_instance) {
00039       ASSERT(0 && "error: only one MiltonApp instance allowed per application");
00040       abort();
00041    }
00042    
00043    s_instance         = true;
00044    m_params.enableGui = enableGui;
00045    
00046    // initialize commandline parameters
00047    if (!_initializeParams(argc, argv, m_params))
00048       printUsage(argc, argv, "error parsing commandline input");
00049    
00050    // initialize Qt
00051    m_qApplication = new QApplication(argc, argv, m_params.enableGui);
00052    if (m_params.enableGui)
00053       glutInit(&argc, argv);
00054    
00055    _init();
00056 }
00057 
00058 MiltonApp::~MiltonApp() {
00059    safeDelete(m_gui);
00060    safeDelete(m_qApplication);
00061    
00062    FOREACH(RendererListIter, m_renderers, iter) {
00063       Renderer *renderer = *iter;
00064       
00065       safeDelete(renderer);
00066    }
00067 }
00068 
00069 void MiltonApp::_init() {
00070    // initialize the stats package
00071    Random::init();
00072    
00073    m_gui = (m_params.enableGui ? new Gui(m_title) : NULL);
00074 }
00075 
00076 bool MiltonApp::loadCommandlineParams() {
00077    ResourceManager::insert<bool>("enableGui",    m_params.enableGui);
00078    ResourceManager::insert<bool>("forcePreview", m_params.forcePreview);
00079    
00080    // load each scenefile specified
00081    FOREACH(StringListIter, m_params.scenefiles, iter) {
00082       const std::string &sceneFile = *iter;
00083       MiltonJSONSceneLoader loader;
00084       ParseData data(true);
00085       
00086       if (!loader.parse(sceneFile, data)) {
00087          cerr << "parse error: " << data.error << endl << endl;
00088          printUsage();
00089          return false;
00090       }
00091       
00092       ASSERT(data.renderer);
00093       ASSERT(data.camera);
00094       Canvas *canvas = NULL;
00095       
00096       if (NULL == data.output) {
00097          if (!m_params.enableGui) {
00098             // no output specified and gui is disabled, so use default output
00099             ResourceManager::log.info << 
00100                "no output specified; defaulting to file '" << 
00101                m_params.output << "'" << endl;
00102             
00103             data.output = _getOutput(m_params);
00104             if (NULL == data.output) {
00105                cerr << "error loading output" << endl;
00106                return false;
00107             }
00108             
00109             FileRenderOutput *output = 
00110                dynamic_cast<FileRenderOutput*>(data.output);
00111             output->setImage(new RgbaImage(data.outputProperties.getValue<unsigned>("width"),  
00112                                            data.outputProperties.getValue<unsigned>("height")));
00113          } else {
00114             // no output specified, so default to gui
00115             
00116             if (data.renderer->supportsOpenGL()) {
00117                canvas = new OpenGLCanvas(m_gui, 
00118                                          data.outputProperties.getValue<unsigned>("width"),  
00119                                          data.outputProperties.getValue<unsigned>("height"));
00120             } else {
00121                canvas = new ImageCanvas(m_gui, 
00122                                         data.outputProperties.getValue<unsigned>("width"),  
00123                                         data.outputProperties.getValue<unsigned>("height"));
00124                
00125                data.output = static_cast<ImageCanvas*>(canvas);
00126                data.output->inherit(data.outputProperties);
00127                data.output->init();
00128             }
00129             
00130             canvas->setRenderer(data.renderer);
00131          }
00132          
00133          if (data.output) {
00134             PointSampleRenderer *renderer = NULL;
00135             
00136             try {
00137                renderer = dynamic_cast<PointSampleRenderer*>(data.renderer);
00138             } catch(std::bad_cast&) { }
00139             
00140             if (renderer)
00141                renderer->setOutput(data.output);
00142          }
00143       }
00144       
00145       if (canvas)
00146          addCanvas(canvas, data.source);
00147       else 
00148          addRenderer(data.renderer);
00149    }
00150    
00151    return true;
00152 }
00153 
00154 void MiltonApp::addCanvas(Canvas *canvas, const std::string &name) {
00155    ASSERT(canvas);
00156    
00157    if (NULL == m_gui) {
00158       cerr << "GUI mode must be enabled to add a canvas to MiltonApp!" << endl;
00159       ASSERT(0);
00160       
00161       return;
00162    }
00163    
00164    canvas->init();
00165    m_gui->addCanvas(canvas, name.c_str());
00166    
00167    m_canvases.push_back(canvas);
00168 }
00169 
00170 void MiltonApp::addRenderer(Renderer *renderer) {
00171    ASSERT(renderer);
00172    
00173    renderer->init();
00174    m_renderers.push_back(renderer);
00175 }
00176 
00177 bool MiltonApp::exec() {
00178    std::vector<RenderThread*> renderThreads;
00179    bool success = true;
00180    
00181    FOREACH(RendererListIter, m_renderers, iter) {
00182       Renderer *renderer = *iter;
00183       
00184       if (renderer) {
00185          RenderThread *thread = new RenderThread(renderer);
00186          thread->start();
00187          
00188          renderThreads.push_back(thread);
00189       }
00190    }
00191    
00192    if (m_gui) {
00193       if (m_params.startRender) {
00194          QTimer::singleShot(50, m_gui, SLOT(renderPressed()));
00195       } else {
00196          ResourceManager::log.info << endl;
00197          ResourceManager::log.info << "paused -- select Options->Render to "
00198             "begin rendering (because of '-pause' commandline flag)" << endl;
00199       }
00200       
00201       success = m_qApplication->exec();
00202    }
00203    
00204    for(unsigned i = 0; i < renderThreads.size(); ++i) {
00205       RenderThread *thread = renderThreads[i];
00206       
00207       while(!thread->wait());
00208       safeDelete(thread);
00209    }
00210    
00211    return success;
00212 }
00213 
00214 void MiltonApp::printUsage(int argc, char **argv, const char *errorMsg) {
00215    const std::string &tab  = " \t";
00216    const std::string &tab1 = "   ";
00217    
00218    if (errorMsg)
00219       cerr << errorMsg << endl << endl;
00220    
00221    cerr << "Usage: " << (argv ? argv[0] : "miltonapp") << " <options> <scenefile>*" << endl 
00222         << tab1 << "Note: if no scenefile is specified, the default scenefile '" DEFAULT_SCENEFILE "' will be used" << endl << endl
00223         << "Options: (convenience, shortcut flags)" << endl
00224         << tab1 << "            " << tab << " (options later in commandline will override those " << endl
00225         << tab1 << "            " << tab << "  listed earlier)" << endl
00226         << tab1 << "--help      " << tab << ": prints out this usage information" << endl
00227         << tab1 << "-nox        " << tab << ": disables the Qt gui frontend for environments without" << endl
00228         << tab1 << "            " << tab << "  X support)" << endl
00229         << tab1 << "-gui        " << tab << ": enables the Qt gui frontend" << endl
00230         << tab1 << "-verbose -v " << tab << ": enables extra debugging printouts" << endl
00231         << tab1 << "-nopreview  " << tab << ": disables forcing of OpenGL preview of loaded scenes" << endl
00232         << tab1 << "-preview    " << tab << ": overrides renderer specified in scenefiles to default" << endl 
00233         << tab1 << "            " << tab << "  to an OpenGL preview" << endl
00234         << tab1 << "-pause      " << tab << ": disable rendering right away upon initialization when" << endl
00235         << tab1 << "            " << tab << "  Qt gui is enabled" << endl
00236         << tab1 << "-output=%s  " << tab << ": quickly specifies an output file to store rendered" << endl
00237         << tab1 << "            " << tab << "  results to. if the suffix for the filename given is" << endl
00238         << tab1 << "            " << tab << "  a valid image format, the results of rendering will" << endl
00239         << tab1 << "            " << tab << "  be saved as an image in the specified format, " << endl
00240         << tab1 << "            " << tab << "  otherwise, raw output of film plane positions -> " << endl
00241         << tab1 << "            " << tab << "  spectral radiance values will be recorded in a simple," << endl
00242         << tab1 << "            " << tab << "  unordered ASCII format:" << endl
00243         << tab1 << "            " << tab << "  x y L0 L1 ... LN" << endl
00244         << tab1 << "            " << tab << "  x y L0 L1 ... LN" << endl;
00245         /*<< tab1 << "            " << tab << "  ..." << endl << endl
00246         << "The following options use standard Milton JSON syntax to override possible "
00247            "equivalent definitions which may be listed in the scenefile(s) given" << endl
00248         << tab1 << "Example: " << endl
00249         << tab1 << tab << "-output={\"type\":\"naive\",\"width\":640,\"height\":480}" << endl
00250         << tab1 << "-output=%s  " << endl
00251         << tab1 << "-renderer=%s" << endl
00252         << tab1 << "-camera=%s  " << endl;*/
00253 }
00254 
00255 bool MiltonApp::_initializeParams(int argc, char **argv, MiltonParams &params) {
00256    int index = 0;
00257    
00258    /* Parse optional arguments */
00259    while(++index < argc) {
00260       const char firstChar = argv[index][0];
00261       
00262       if (firstChar == '\0') {
00263          return false;
00264       }
00265       if (firstChar != '-') {
00266          params.scenefiles.push_back(std::string(argv[index]));
00267       } else {
00268          const char *str = argv[index] + 1;
00269          
00270          if (!strcmp(str, "nox")) {
00271             params.enableGui = false;
00272          } else if (!strcmp(str, "gui")) {
00273             params.enableGui = true;
00274          } else if (!strcmp(str, "v") || !strcmp(str, "verbose")) {
00275             params.verbose   = true;
00276          } else if (!strcmp(str, "nopreview")) {
00277             params.forcePreview = false;
00278          } else if (!strcmp(str, "preview")) {
00279             params.forcePreview = true;
00280          } else if (!strcmp(str, "pause")) {
00281             params.startRender = false;
00282          } else if (!strncmp(str, "output=", strlen("output="))) {
00283             params.output      = (str + strlen("output="));
00284          } else if (!strcmp(str, "-help") || !strcmp(str, "help")) {
00285             printUsage(argc, argv);
00286             exit(0);
00287          } else {
00288             ResourceManager::log.error << "invalid option '" << 
00289                argv[index] << endl;
00290             
00291             return false;
00292          }
00293       }
00294    }
00295    
00296    ResourceManager::log.setDebug(params.verbose);
00297    
00298 #ifdef Q_WS_X11
00299    if (NULL == getenv("DISPLAY")) {
00300       if (params.enableGui) {
00301          ResourceManager::log.error << 
00302             "error: environment doesn't support Qt gui \"DISPLAY\"" << endl;
00303          
00304          params.enableGui = false;
00305       }
00306    }
00307 #endif
00308    
00309    if (!params.enableGui) {
00310       if (!params.startRender) {
00311          ResourceManager::log.info << 
00312             "rendering will start immediately in 'nox' mode" << endl;
00313          
00314          params.startRender = true;
00315       }
00316    }
00317    
00318    if (0 == params.scenefiles.size()) {
00319       ResourceManager::log.info << 
00320          "no scenefile specified; loading default '" << 
00321          DEFAULT_SCENEFILE << "'" << endl;
00322       
00323       params.scenefiles.push_back(DEFAULT_SCENEFILE);
00324    }
00325    
00326    ResourceManager::insert<bool>("enableGui",    params.enableGui);
00327    ResourceManager::insert<bool>("forcePreview", params.forcePreview);
00328    
00329    return true;
00330 }
00331 
00332 RenderOutput *MiltonApp::_getOutput(MiltonParams &params) {
00333    const std::string &output = params.output;
00334    const std::string &suffix = output.substr(output.rfind('.') + 1);
00335    
00336    if (suffix == "png"  || suffix == "jpg" || suffix == "gif" || 
00337        suffix == "jpeg" || suffix == "tiff")
00338    {
00339       return new FileRenderOutput(NULL, output);
00340    } else {
00341       ResourceManager::log.error << 
00342          "error: unrecognized outputfile suffix '" << suffix << "'" <<
00343          "for output file '" << output << "'" << endl;
00344       
00345       return NULL;
00346    }
00347 }
00348 

Generated on 28 Feb 2009 for Milton by doxygen 1.5.6