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 ¶ms) { 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 ¶ms) { 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
1.5.6