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
00031 #include <boost/program_options.hpp>
00032 #include <boost/thread.hpp>
00033 #include <boost/thread/xtime.hpp>
00034 #include <boost/date_time/posix_time/posix_time.hpp>
00035 #include <boost/filesystem/path.hpp>
00036 #include <boost/filesystem/operations.hpp>
00037
00038 #include "lux.h"
00039 #include "api.h"
00040 #include "context.h"
00041 #include "error.h"
00042 #include "renderserver.h"
00043
00044 #if defined(WIN32) && !defined(__CYGWIN__)
00045 #include "direct.h"
00046 #define chdir _chdir
00047 #endif
00048
00049 using namespace lux;
00050 namespace po = boost::program_options;
00051
00052 std::string sceneFileName;
00053 int threads;
00054 bool parseError;
00055
00056 void engineThread() {
00057 ParseFile(sceneFileName.c_str());
00058 if (luxStatistics("sceneIsReady") == false)
00059 parseError = true;
00060 }
00061
00062 void infoThread() {
00063 while (true) {
00064 boost::xtime xt;
00065 boost::xtime_get(&xt, boost::TIME_UTC);
00066 xt.sec += 5;
00067 boost::thread::sleep(xt);
00068
00069 boost::posix_time::time_duration td(0, 0,
00070 (int) luxStatistics("secElapsed"), 0);
00071
00072 int sampleSec = (int)luxStatistics("samplesSec");
00073
00074 if (sampleSec > 0) {
00075 std::stringstream ss;
00076 ss << '[' << threads << " threads] " << td << " "
00077 << sampleSec << " samples/sec " << " "
00078 << (int) luxStatistics("samplesTotSec") << " samples/totsec " << " "
00079 << (float) luxStatistics("samplesPx") << " samples/pix";
00080 luxError(LUX_NOERROR, LUX_INFO, ss.str().c_str());
00081 }
00082 }
00083 }
00084
00085 int main(int ac, char *av[]) {
00086 bool useServer = false;
00087 luxInit();
00088
00089 try {
00090 std::stringstream ss;
00091
00092
00093
00094 po::options_description generic("Generic options");
00095 generic.add_options()
00096 ("version,v", "Print version string") ("help", "Produce help message")
00097 ("server,s", "Launch in server mode")
00098 ("debug,d", "Enable debug mode")
00099 ;
00100
00101
00102
00103
00104 po::options_description config("Configuration");
00105 config.add_options()
00106 ("threads,t", po::value < int >(), "Specify the number of threads that Lux will run in parallel.")
00107 ("useserver,u", po::value< std::vector<std::string> >()->composing(), "Specify the adress of a rendering server to use.")
00108 ("serverinterval,i", po::value < int >(), "Specify the number of seconds between requests to rendering servers.")
00109 ("samplepix,p", po::value < int >(), "Specify to stop after the number of samples per pixel has been reached.")
00110 ;
00111
00112
00113
00114 po::options_description hidden("Hidden options");
00115 hidden.add_options()
00116 ("input-file", po::value< vector<string> >(), "input file")
00117 ("test", "debug test mode")
00118 ;
00119
00120 po::options_description cmdline_options;
00121 cmdline_options.add(generic).add(config).add(hidden);
00122
00123 po::options_description config_file_options;
00124 config_file_options.add(config).add(hidden);
00125
00126 po::options_description visible("Allowed options");
00127 visible.add(generic).add(config);
00128
00129 po::positional_options_description p;
00130
00131 p.add("input-file", -1);
00132
00133 po::variables_map vm;
00134 store(po::command_line_parser(ac, av).
00135 options(cmdline_options).positional(p).run(), vm);
00136
00137 std::ifstream
00138 ifs("luxconsole.cfg");
00139 store(parse_config_file(ifs, config_file_options), vm);
00140 notify(vm);
00141
00142 if (vm.count("help")) {
00143 ss.str("");
00144 ss << "Usage: luxconsole [options] file...\n" << visible;
00145 luxError(LUX_SYSTEM, LUX_ERROR, ss.str().c_str());
00146 return 0;
00147 }
00148
00149 ss.str("");
00150 ss << "Lux version " << LUX_VERSION << " of " << __DATE__ << " at " << __TIME__;
00151 luxError(LUX_NOERROR, LUX_INFO, ss.str().c_str());
00152 if (vm.count("version"))
00153 return 0;
00154
00155 if (vm.count("threads"))
00156 threads = vm["threads"].as<int>();
00157 else
00158 threads = 1;
00159 ss.str("");
00160 ss << "Threads: " << threads;
00161 luxError(LUX_NOERROR, LUX_INFO, ss.str().c_str());
00162
00163 if (vm.count("debug")) {
00164 luxError(LUX_NOERROR, LUX_INFO, "Debug mode enabled");
00165 luxEnableDebugMode();
00166 }
00167
00168 int serverInterval;
00169 if (vm.count("serverinterval")) {
00170 serverInterval = vm["serverinterval"].as<int>();
00171 luxSetNetworkServerUpdateInterval(serverInterval);
00172 } else
00173 serverInterval = luxGetNetworkServerUpdateInterval();
00174
00175 int maxSamplePerPixel;
00176 if (vm.count("samplepix")) {
00177 maxSamplePerPixel = vm["samplepix"].as<int>();
00178 ss.str("");
00179 ss << "Maximum number of samples per pixel: " << maxSamplePerPixel;
00180 luxError(LUX_NOERROR, LUX_INFO, ss.str().c_str());
00181 } else
00182 maxSamplePerPixel = -1;
00183
00184 if (vm.count("useserver")) {
00185 std::vector<std::string> names = vm["useserver"].as<std::vector<std::string> >();
00186
00187 for (std::vector<std::string>::iterator i = names.begin(); i < names.end(); i++)
00188 luxAddServer((*i).c_str());
00189
00190 useServer = true;
00191
00192 ss.str("");
00193 ss << "Server requests interval: " << serverInterval << " secs";
00194 luxError(LUX_NOERROR, LUX_INFO, ss.str().c_str());
00195 }
00196
00197 if (vm.count("input-file")) {
00198 const std::vector<std::string> &v = vm["input-file"].as < vector<string> > ();
00199 for (unsigned int i = 0; i < v.size(); i++) {
00200
00201 boost::filesystem::path fullPath(boost::filesystem::initial_path());
00202 fullPath = boost::filesystem::system_complete(boost::filesystem::path(v[i], boost::filesystem::native));
00203
00204 if (!boost::filesystem::exists(fullPath) && v[i] != "-") {
00205 ss.str("");
00206 ss << "Unable to open scenefile '" << fullPath.string() << "'";
00207 luxError(LUX_NOFILE, LUX_SEVERE, ss.str().c_str());
00208 continue;
00209 }
00210
00211 sceneFileName = fullPath.leaf();
00212 chdir(fullPath.branch_path().string().c_str());
00213
00214 parseError = false;
00215 boost::thread engine(&engineThread);
00216
00217
00218 while (!luxStatistics("sceneIsReady") && !parseError) {
00219 boost::xtime xt;
00220 boost::xtime_get(&xt, boost::TIME_UTC);
00221 xt.sec += 1;
00222 boost::thread::sleep(xt);
00223 }
00224
00225 if (parseError) {
00226 std::stringstream ss;
00227 ss << "Skipping invalid scenefile '" << fullPath.string() << "'";
00228 luxError(LUX_BADFILE, LUX_SEVERE, ss.str().c_str());
00229 continue;
00230 }
00231
00232
00233 int threadsToAdd = threads;
00234 while (--threadsToAdd)
00235 Context::luxAddThread();
00236
00237
00238 boost::thread info(&infoThread);
00239
00240 if (maxSamplePerPixel > 0) {
00241
00242
00243
00244 for(;;) {
00245 boost::xtime xt;
00246 boost::xtime_get(&xt, boost::TIME_UTC);
00247 xt.sec += 1;
00248 boost::thread::sleep(xt);
00249
00250 if(luxStatistics("samplesPx") >= maxSamplePerPixel) {
00251
00252 luxExit();
00253 break;
00254 }
00255 }
00256 }
00257
00258
00259 luxWait();
00260 luxExit();
00261
00262
00263 boost::posix_time::time_duration td(0, 0,
00264 (int) luxStatistics("secElapsed"), 0);
00265
00266 ss.str("");
00267 ss << "100% rendering done [" << threads << " threads] " << td;
00268 luxError(LUX_NOERROR, LUX_INFO, ss.str().c_str());
00269
00270 luxCleanup();
00271 }
00272 } else if (vm.count("server")) {
00273 RenderServer *renderServer = new RenderServer(threads);
00274 renderServer->start();
00275 renderServer->join();
00276 delete renderServer;
00277 } else {
00278 ss.str("");
00279 ss << "luxconsole: no input file";
00280 luxError(LUX_SYSTEM, LUX_ERROR, ss.str().c_str());
00281 }
00282
00283 } catch (std::exception & e) {
00284 std::stringstream ss;
00285 ss << "Command line argument parsing failed with error '" << e.what() << "', please use the --help option to view the allowed syntax.";
00286 luxError(LUX_SYNTAX, LUX_SEVERE, ss.str().c_str());
00287 return 1;
00288 }
00289 return 0;
00290 }