00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #define NDEBUG 1
00024
00025 #include <iomanip>
00026 #include <fstream>
00027 #include <string>
00028 #include <sstream>
00029 #include <exception>
00030 #include <iostream>
00031
00032 #include <boost/program_options.hpp>
00033 #include <boost/thread.hpp>
00034 #include <boost/thread/xtime.hpp>
00035 #include <boost/date_time/posix_time/posix_time.hpp>
00036 #include <boost/filesystem/path.hpp>
00037 #include <boost/filesystem/operations.hpp>
00038
00039 #include "lux.h"
00040 #include "api.h"
00041 #include "context.h"
00042 #include "error.h"
00043 #include "renderserver.h"
00044 #include "osfunc.h"
00045
00046 #if defined(WIN32) && !defined(__CYGWIN__)
00047 #include <io.h>
00048 #include <fcntl.h>
00049 #endif
00050
00051 #if defined(WIN32) && !defined(__CYGWIN__)
00052 #include "direct.h"
00053 #define chdir _chdir
00054 #endif
00055
00056 using namespace lux;
00057 namespace po = boost::program_options;
00058
00059 std::string sceneFileName;
00060 int threads;
00061 bool parseError;
00062
00063 void engineThread() {
00064
00065 srand(time(NULL));
00066
00067 ParseFile(sceneFileName.c_str());
00068 if (luxStatistics("sceneIsReady") == 0.)
00069 parseError = true;
00070 }
00071
00072 void infoThread() {
00073 while (!boost::this_thread::interruption_requested()) {
00074 try {
00075 boost::xtime xt;
00076 boost::xtime_get(&xt, boost::TIME_UTC);
00077 xt.sec += 5;
00078 boost::thread::sleep(xt);
00079
00080 boost::posix_time::time_duration td(0, 0,
00081 (int) luxStatistics("secElapsed"), 0);
00082
00083 int sampleSec = (int)luxStatistics("samplesSec");
00084
00085 if (sampleSec > 0) {
00086 std::stringstream ss;
00087 ss << '[' << threads << " threads] " << td << " "
00088 << sampleSec << " samples/sec " << " "
00089 << (int) luxStatistics("samplesTotSec") << " samples/totsec " << " "
00090 << (float) luxStatistics("samplesPx") << " samples/pix";
00091 luxError(LUX_NOERROR, LUX_INFO, ss.str().c_str());
00092 }
00093 } catch(boost::thread_interrupted ex) {
00094 break;
00095 }
00096 }
00097 }
00098
00099 int main(int ac, char *av[]) {
00100
00101 srand(time(NULL));
00102
00103 luxInit();
00104
00105 try {
00106 std::stringstream ss;
00107
00108
00109
00110 po::options_description generic("Generic options");
00111 generic.add_options()
00112 ("version,v", "Print version string")
00113 ("help,h", "Produce help message")
00114 ("server,s", "Launch in server mode")
00115 ("bindump,b", "Dump binary RGB framebuffer to stdout when finished")
00116 ("debug,d", "Enable debug mode")
00117 ("fixedseed,f", "Disable random seed mode")
00118 ("minepsilon,e", po::value< float >(), "Set minimum epsilon")
00119 ("maxepsilon,E", po::value< float >(), "Set maximum epsilon")
00120 ("verbosity,V", po::value< int >(), "Log output verbosity")
00121 ;
00122
00123
00124
00125
00126 po::options_description config("Configuration");
00127 config.add_options()
00128 ("threads,t", po::value < int >(), "Specify the number of threads that Lux will run in parallel.")
00129 ("useserver,u", po::value< std::vector<std::string> >()->composing(), "Specify the adress of a rendering server to use.")
00130 ("serverinterval,i", po::value < int >(), "Specify the number of seconds between requests to rendering servers.")
00131 ("serverport,p", po::value < int >(), "Specify the tcp port used in server mode.")
00132 ;
00133
00134
00135
00136 po::options_description hidden("Hidden options");
00137 hidden.add_options()
00138 ("input-file", po::value< vector<string> >(), "input file")
00139 ("test", "debug test mode")
00140 ;
00141
00142 po::options_description cmdline_options;
00143 cmdline_options.add(generic).add(config).add(hidden);
00144
00145 po::options_description config_file_options;
00146 config_file_options.add(config).add(hidden);
00147
00148 po::options_description visible("Allowed options");
00149 visible.add(generic).add(config);
00150
00151 po::positional_options_description p;
00152
00153 p.add("input-file", -1);
00154
00155 po::variables_map vm;
00156 store(po::command_line_parser(ac, av).
00157 options(cmdline_options).positional(p).run(), vm);
00158
00159 std::ifstream
00160 ifs("luxconsole.cfg");
00161 store(parse_config_file(ifs, config_file_options), vm);
00162 notify(vm);
00163
00164 if (vm.count("help")) {
00165 ss.str("");
00166 ss << "Usage: luxconsole [options] file...\n" << visible;
00167 luxError(LUX_SYSTEM, LUX_ERROR, ss.str().c_str());
00168 return 0;
00169 }
00170
00171 if (vm.count("verbosity"))
00172 luxLogFilter = vm["verbosity"].as<int>();
00173
00174 ss.str("");
00175 ss << "Lux version " << LUX_VERSION << " of " << __DATE__ << " at " << __TIME__;
00176 luxError(LUX_NOERROR, LUX_INFO, ss.str().c_str());
00177 if (vm.count("version"))
00178 return 0;
00179
00180 if (vm.count("threads"))
00181 threads = vm["threads"].as<int>();
00182 else {
00183
00184 threads = osHardwareConcurrency();
00185 if (threads == 0)
00186 threads = 1;
00187 }
00188
00189 ss.str("");
00190 ss << "Threads: " << threads;
00191 luxError(LUX_NOERROR, LUX_INFO, ss.str().c_str());
00192
00193 if (vm.count("debug")) {
00194 luxError(LUX_NOERROR, LUX_INFO, "Debug mode enabled");
00195 luxEnableDebugMode();
00196 }
00197
00198 if (vm.count("fixedseed")) {
00199 if (!vm.count("server"))
00200 luxDisableRandomMode();
00201 else
00202 luxError(LUX_CONSISTENCY, LUX_WARNING, "Using random seed for server");
00203 }
00204
00205 int serverInterval;
00206 if (vm.count("serverinterval")) {
00207 serverInterval = vm["serverinterval"].as<int>();
00208 luxSetNetworkServerUpdateInterval(serverInterval);
00209 } else
00210 serverInterval = luxGetNetworkServerUpdateInterval();
00211
00212 if (vm.count("useserver")) {
00213 std::vector<std::string> names = vm["useserver"].as<std::vector<std::string> >();
00214
00215 for (std::vector<std::string>::iterator i = names.begin(); i < names.end(); i++)
00216 luxAddServer((*i).c_str());
00217
00218 ss.str("");
00219 ss << "Server requests interval: " << serverInterval << " secs";
00220 luxError(LUX_NOERROR, LUX_INFO, ss.str().c_str());
00221 }
00222
00223 int serverPort = RenderServer::DEFAULT_TCP_PORT;
00224 if (vm.count("serverport"))
00225 serverPort = vm["serverport"].as<int>();
00226
00227
00228 if (vm.count("minepsilon")) {
00229 const float mine = vm["minepsilon"].as<float>();
00230 if (vm.count("maxepsilon")) {
00231 const float maxe = vm["maxepsilon"].as<float>();
00232 luxSetEpsilon(mine, maxe);
00233 } else
00234 luxSetEpsilon(mine, DEFAULT_EPSILON_MAX);
00235 } else {
00236 if (vm.count("maxepsilon")) {
00237 const float maxe = vm["maxepsilon"].as<float>();
00238 luxSetEpsilon(DEFAULT_EPSILON_MIN, maxe);
00239 } else
00240 luxSetEpsilon(DEFAULT_EPSILON_MIN, DEFAULT_EPSILON_MAX);
00241 }
00242
00243 if (vm.count("input-file")) {
00244 const std::vector<std::string> &v = vm["input-file"].as < vector<string> > ();
00245 for (unsigned int i = 0; i < v.size(); i++) {
00246
00247 boost::filesystem::path fullPath(boost::filesystem::initial_path());
00248 fullPath = boost::filesystem::system_complete(boost::filesystem::path(v[i], boost::filesystem::native));
00249
00250 if (!boost::filesystem::exists(fullPath) && v[i] != "-") {
00251 ss.str("");
00252 ss << "Unable to open scenefile '" << fullPath.string() << "'";
00253 luxError(LUX_NOFILE, LUX_SEVERE, ss.str().c_str());
00254 continue;
00255 }
00256
00257 sceneFileName = fullPath.leaf();
00258 if (chdir(fullPath.branch_path().string().c_str())) {
00259 ss.str("");
00260 ss << "Unable to go into directory '" << fullPath.branch_path().string() << "'";
00261 luxError(LUX_NOFILE, LUX_SEVERE, ss.str().c_str());
00262 }
00263
00264 parseError = false;
00265 boost::thread engine(&engineThread);
00266
00267
00268 while (!luxStatistics("sceneIsReady") && !parseError) {
00269 boost::xtime xt;
00270 boost::xtime_get(&xt, boost::TIME_UTC);
00271 xt.sec += 1;
00272 boost::thread::sleep(xt);
00273 }
00274
00275 if (parseError) {
00276 std::stringstream ss;
00277 ss << "Skipping invalid scenefile '" << fullPath.string() << "'";
00278 luxError(LUX_BADFILE, LUX_SEVERE, ss.str().c_str());
00279 continue;
00280 }
00281
00282
00283 int threadsToAdd = threads;
00284 while (--threadsToAdd)
00285 Context::luxAddThread();
00286
00287
00288 boost::thread info(&infoThread);
00289
00290
00291 luxWait();
00292
00293
00294 info.interrupt();
00295 info.join();
00296
00297 luxExit();
00298
00299
00300 boost::posix_time::time_duration td(0, 0,
00301 (int) luxStatistics("secElapsed"), 0);
00302
00303 ss.str("");
00304 ss << "100% rendering done [" << threads << " threads] " << td;
00305 luxError(LUX_NOERROR, LUX_INFO, ss.str().c_str());
00306
00307 if (vm.count("bindump")) {
00308
00309 unsigned char* fb = luxFramebuffer();
00310
00311 int w = luxStatistics("filmXres"), h = luxStatistics("filmYres");
00312 luxUpdateFramebuffer();
00313
00314 #if defined(WIN32) && !defined(__CYGWIN__)
00315 _setmode(_fileno(stdout), _O_BINARY);
00316 #endif
00317
00318
00319 for (int i = 0; i < w * h * 3; i++)
00320 std::cout << fb[i];
00321 }
00322
00323 luxCleanup();
00324 }
00325 } else if (vm.count("server")) {
00326 RenderServer *renderServer = new RenderServer(threads, serverPort);
00327 renderServer->start();
00328 renderServer->join();
00329 delete renderServer;
00330 } else {
00331 ss.str("");
00332 ss << "luxconsole: no input file";
00333 luxError(LUX_SYSTEM, LUX_ERROR, ss.str().c_str());
00334 }
00335
00336 } catch (std::exception & e) {
00337 std::stringstream ss;
00338 ss << "Command line argument parsing failed with error '" << e.what() << "', please use the --help option to view the allowed syntax.";
00339 luxError(LUX_SYNTAX, LUX_SEVERE, ss.str().c_str());
00340 return 1;
00341 }
00342 return 0;
00343 }