00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifdef _WIN32
00025 #ifndef _DEBUG
00026 #define GUESS_HOME_PATH
00027 #endif // !_DEBUG
00028 #endif // _WIN32
00029
00030 #include "clparser.h"
00031 #include "common/math/mt19937rng.h"
00032 #include "common/math/real.h"
00033 #ifdef GUESS_HOME_PATH
00034 #include "common/misc/apppath.h"
00035 #endif // GUESS_HOME_PATH
00036 #include "common/misc/consoleprogressmonitor.h"
00037 #include "common/misc/minmax.h"
00038 #include "common/misc/stringutils.h"
00039 #include "renderer/causticsphotontracer.h"
00040 #include "renderer/context.h"
00041 #include "renderer/framebuffer.h"
00042 #include "renderer/globalphotontracer.h"
00043 #include "renderer/globals.h"
00044 #include "renderer/icamera.h"
00045 #ifdef _DEBUG
00046 #include "renderer/photon.h"
00047 #endif // _DEBUG
00048 #include "renderer/photonmap.h"
00049 #include "renderer/renderer.h"
00050 #include "renderer/scene.h"
00051 #include "renderer/settings.h"
00052 #include "renderer/statistics.h"
00053 #include "renderer/utilities.h"
00054 #include "driversettings.h"
00055 #include "driversettingswrapper.h"
00056 #include "error.h"
00057 #include "helpers.h"
00058 #include "scenebuilder.h"
00059 #include "scenesettingswrapper.h"
00060 #include "version.h"
00061
00062 #ifdef ENABLE_MULTITHREADING
00063 #pragma warning(disable : 4275)
00064 #pragma warning(disable : 4251)
00065
00066 #include <boost/thread/mutex.hpp>
00067 #include <boost/thread/thread.hpp>
00068 #endif // ENABLE_MULTITHREADING
00069
00070 #include <IL/il.h>
00071 #include <IL/ilu.h>
00072
00073 #include <cassert>
00074 #include <cstdio>
00075 #include <cstdlib>
00076 #include <iostream>
00077 #include <sstream>
00078 #include <string>
00079
00080 using namespace sheep;
00081 using namespace std;
00082 using namespace toxic;
00083
00084 namespace {
00085 void print_disclaimer() {
00086 cout << "toxic - A Global Illumination Renderer" << endl;
00087 cout << "Copyright (C) 2003-2004 Francois Beaune" << endl << endl;
00088 cout << "Visit http://toxicengine.sourceforge.net/ for more information." << endl;
00089 cout << endl;
00090 }
00091
00092 string get_home_path() {
00093 #ifdef GUESS_HOME_PATH
00094 string path = StringUtils::GetPath(GetApplicationPath());
00095
00096
00097 const string bin_path = "bin\\";
00098
00099
00100 if(StringUtils::CompareNoCase(path.substr(path.size() - bin_path.size()), "bin\\")) {
00101 cerr << Error << "toxic is not installed correctly. Please reinstall it." << endl;
00102 exit(EXIT_FAILURE);
00103 }
00104
00105
00106 path = path.substr(0, path.size() - bin_path.size());
00107
00108 return path;
00109 #else
00110 const char *home_env = getenv("TOXICHOME");
00111
00112 if(!home_env) {
00113 cerr << Warning << "'TOXICHOME' environment variable not set." << endl;
00114 return "./";
00115 }
00116
00117 return StringUtils::NormalizePath(home_env);
00118 #endif // GUESS_HOME_PATH
00119 }
00120
00121 void load_settings(DriverSettingsWrapper *driver_settings,
00122 SceneSettingsWrapper *scene_settings,
00123 const string &home_path)
00124 {
00125 assert(driver_settings);
00126 assert(scene_settings);
00127
00128 string driver_settings_file =
00129 driver_settings->m_settings_files.m_driver_settings_file;
00130
00131 if(driver_settings_file.size() == 0) {
00132 driver_settings_file = home_path + "settings/toxicsettings.xml";
00133 }
00134
00135
00136 driver_settings->Load(driver_settings_file, home_path);
00137
00138
00139 scene_settings->Load(
00140 driver_settings->m_settings_files.m_scene_settings_file,
00141 home_path
00142 );
00143 }
00144
00145 void print_statistics(const Statistics &statistics) {
00146 Indenter indenter;
00147
00148 cout << indenter() << "Rendering Statistics:" << endl;
00149 indenter.Indent();
00150
00151
00152
00153 cout << indenter() << "Pixels" << endl;
00154 indenter.Indent();
00155
00156 cout << indenter() << "Rendered Pixels: "
00157 << ConvertNumberToString(statistics.m_total_pixels)
00158 << endl;
00159
00160 indenter.Unindent();
00161
00162
00163
00164 cout << indenter() << "Photons" << endl;
00165 indenter.Indent();
00166
00167 cout << indenter() << "Photons in Global Photon Map: "
00168 << ConvertNumberToString(statistics.m_gpm_photons)
00169 << endl;
00170 cout << indenter() << "Photons in Caustics Photon Map: "
00171 << ConvertNumberToString(statistics.m_cpm_photons)
00172 << endl;
00173
00174 indenter.Unindent();
00175
00176
00177
00178 cout << indenter() << "Rays" << endl;
00179 indenter.Indent();
00180
00181 const int64 total_rays_cast = statistics.ComputeTotalRays();
00182
00183 cout << indenter() << "Total Rays Cast: "
00184 << ConvertNumberToString(total_rays_cast)
00185 << endl;
00186 indenter.Indent();
00187 cout << indenter() << "Primary Rays: "
00188 << ConvertNumberToString(statistics.m_primary_rays)
00189 << " ("
00190 << Percentage(statistics.m_primary_rays, total_rays_cast)
00191 << ')' << endl;
00192 cout << indenter() << "Secondary Rays: "
00193 << ConvertNumberToString(statistics.m_secondary_rays)
00194 << " ("
00195 << Percentage(statistics.m_secondary_rays, total_rays_cast)
00196 << ')' << endl;
00197 cout << indenter() << "Shadow Rays: "
00198 << ConvertNumberToString(statistics.m_shadow_rays)
00199 << " ("
00200 << Percentage(statistics.m_shadow_rays, total_rays_cast)
00201 << ')' << endl;
00202 cout << indenter() << "Primary Final Gathering Rays: "
00203 << ConvertNumberToString(statistics.m_primary_final_gathering_rays)
00204 << " ("
00205 << Percentage(statistics.m_primary_final_gathering_rays, total_rays_cast)
00206 << ')' << endl;
00207 cout << indenter() << "Secondary Final Gathering Rays: "
00208 << ConvertNumberToString(statistics.m_secondary_final_gathering_rays)
00209 << " ("
00210 << Percentage(statistics.m_secondary_final_gathering_rays, total_rays_cast)
00211 << ')' << endl;
00212 indenter.Unindent();
00213
00214 cout << indenter() << "Average Rays per Pixel: "
00215 << Ratio(total_rays_cast, statistics.m_total_pixels)
00216 << endl;
00217 indenter.Indent();
00218 cout << indenter() << "Primary Rays: "
00219 << Ratio(statistics.m_primary_rays, statistics.m_total_pixels)
00220 << endl;
00221 cout << indenter() << "Secondary Rays: "
00222 << Ratio(statistics.m_secondary_rays, statistics.m_total_pixels)
00223 << endl;
00224 cout << indenter() << "Shadow Rays: "
00225 << Ratio(statistics.m_shadow_rays, statistics.m_total_pixels)
00226 << endl;
00227 cout << indenter() << "Primary Final Gathering Rays: "
00228 << Ratio(statistics.m_primary_final_gathering_rays, statistics.m_total_pixels)
00229 << endl;
00230 cout << indenter() << "Secondary Final Gathering Rays: "
00231 << Ratio(statistics.m_secondary_final_gathering_rays, statistics.m_total_pixels)
00232 << endl;
00233 indenter.Unindent();
00234
00235 indenter.Unindent();
00236
00237
00238
00239 cout << indenter() << "Intersections" << endl;
00240 indenter.Indent();
00241
00242 cout << indenter() << "Intersections Tested: "
00243 << ConvertNumberToString(statistics.m_tested_intersections)
00244 << endl;
00245 cout << indenter() << "Intersections Found: "
00246 << ConvertNumberToString(statistics.m_intersections_found)
00247 << endl;
00248 cout << indenter() << "Found/Tested Intersections Ratio: "
00249 << Percentage(statistics.m_intersections_found, statistics.m_tested_intersections)
00250 << endl;
00251
00252 indenter.Unindent();
00253 }
00254 }
00255
00256 #ifdef ENABLE_MULTITHREADING
00257
00258 boost::mutex io_mutex;
00259
00260 void foo() {
00261 for(int i = 0; i < 100; ++i) {
00262 boost::mutex::scoped_lock lock(io_mutex);
00263 cerr << '*';
00264 }
00265 }
00266
00267 class RenderingThread {
00268 public:
00269 RenderingThread(Renderer *renderer, const Context &context) :
00270 m_renderer(renderer),
00271 m_context(context)
00272 {
00273 assert(renderer);
00274 assert(progmon);
00275 }
00276
00277 void operator()() const {
00278 while(!m_renderer->IsRenderComplete()) {
00279 m_renderer->RenderNextPixel(m_context);
00280 }
00281 }
00282
00283 private:
00284 Renderer *m_renderer;
00285 const Context &m_context;
00286 };
00287
00288 class ProgressMonitoringThread {
00289 public:
00290 void operator()() const {
00291 while(true) {
00292 }
00293 }
00294
00295 private:
00296
00297 bool is_render_complete() const {
00298 for(int i = 0; i < nthreads; ++i) {
00299 if(IsRenderComplete
00300 }
00301 }
00302 };
00303
00304 #endif // ENABLE_MULTITHREADING
00305
00306 int main(int argc, char *argv[]) {
00307
00308 ilInit();
00309 iluInit();
00310
00311 print_disclaimer();
00312
00313
00314 cout << "Running toxic version " << VERSION << ", build " << BUILD_NUMBER << endl << endl;
00315
00316 #ifdef _DEBUG
00317 cout << "DEBUG: Size of the Photon structure: "
00318 << sizeof(Photon)
00319 << " bytes"
00320 << endl << endl;
00321 #endif // _DEBUG
00322
00323 const string home_path = get_home_path();
00324
00325 #ifdef _DEBUG
00326 cout << "DEBUG: Home path: " << home_path << endl << endl;
00327 #endif // _DEBUG
00328
00329 DriverSettingsWrapper driver_settings;
00330 SceneSettingsWrapper scene_settings;
00331
00332
00333 CLParser(&driver_settings).Parse(argc, argv);
00334
00335
00336 load_settings(&driver_settings, &scene_settings, home_path);
00337
00338
00339 driver_settings.CheckConsistency();
00340 scene_settings.CheckConsistency();
00341
00342
00343 driver_settings.Print(cout);
00344 cout << endl;
00345 scene_settings.Print(cout);
00346 cout << endl;
00347
00348 ConsoleProgressMonitor progmon;
00349 stringstream ss;
00350
00351
00352 int task_count = 0;
00353 ++task_count;
00354 ++task_count;
00355 if(scene_settings.m_rendering.m_components.m_indirect_lighting.m_enabled)
00356 ++task_count;
00357 if(scene_settings.m_rendering.m_components.m_caustics.m_enabled)
00358 ++task_count;
00359 if(driver_settings.m_primary_output.m_enabled)
00360 ++task_count;
00361
00362 int current_task = 0;
00363
00364
00365 MT19937RNG rng;
00366 Statistics statistics;
00367 Context context(&rng, &scene_settings, &statistics);
00368
00369
00370 Renderer renderer;
00371
00372 cout << ++current_task << '/' << task_count << ". Initializing framebuffer" << endl;
00373
00374
00375 cout << " * Memory allocation" << flush;
00376 Framebuffer *framebuffer = new Framebuffer(
00377 driver_settings.m_primary_output.m_width,
00378 driver_settings.m_primary_output.m_height,
00379 Framebuffer::RGB_FLOAT_32
00380 );
00381 cout << " [" << ConvertSizeToString(framebuffer->GetSizeInMemory(), true)
00382 << " allocated]." << endl;
00383
00384
00385 cout << " * Memory initialization" << flush;
00386 framebuffer->Clear();
00387 cout << '.' << endl;
00388
00389
00390 renderer.SetFramebuffer(framebuffer);
00391
00392
00393 if(scene_settings.m_output.m_render_area.m_enabled) {
00394 renderer.SetRenderArea(
00395 scene_settings.m_output.m_render_area.m_x0,
00396 scene_settings.m_output.m_render_area.m_y0,
00397 scene_settings.m_output.m_render_area.m_x1,
00398 scene_settings.m_output.m_render_area.m_y1
00399 );
00400 }
00401
00402
00403
00404 cout << ++current_task << '/' << task_count << ". Initializing scene" << endl;
00405
00406 SceneBuilder *scene_builder;
00407 const Scene *scene;
00408 const ICamera *camera;
00409
00410 bool successful = false;
00411
00412 try {
00413 scene_builder = new SceneBuilder(
00414 context,
00415 framebuffer,
00416 driver_settings.m_input_files.m_scene_file,
00417 home_path,
00418 &progmon
00419 );
00420
00421 scene = scene_builder->GetScene().release();
00422 camera = scene_builder->GetCamera().release();
00423
00424 successful = true;
00425 }
00426 catch(const SceneBuilder::ParseErrorException &e) {
00427 cerr << Error << e.m_message << endl;
00428 }
00429 catch(const SceneBuilder::LoadErrorException &e) {
00430 cerr << Error << e.m_message << endl;
00431 }
00432 catch(...) {
00433 cerr << Error << "Unknown exception." << endl;
00434 }
00435
00436 if(!successful) {
00437 cerr << Error << "Could not load the scene file '"
00438 << driver_settings.m_input_files.m_scene_file
00439 << "'." << endl;
00440 return EXIT_FAILURE;
00441 }
00442
00443 renderer.SetScene(scene);
00444 renderer.SetCamera(camera);
00445
00446 cout << " * Scene composition" << endl;
00447 cout << " Objects: " << scene->GetRootObject()->GetObjectCount() << endl;
00448 cout << " Light sources: " << scene->GetLightCount() << endl;
00449
00450 PhotonMap *global_pm = 0;
00451
00452 if(scene_settings.m_rendering.m_components.m_indirect_lighting.m_enabled) {
00453 if(driver_settings.m_global_photon_map.m_op == DriverSettings::LOAD_PM) {
00454
00455
00456 ss.str("");
00457 ss << ++current_task << '/' << task_count << ". Reading GPM from file "
00458 << driver_settings.m_global_photon_map.m_file;
00459 progmon.Reset(ss.str());
00460
00461 global_pm = PhotonMap::CreateFromFile(
00462 driver_settings.m_global_photon_map.m_file,
00463 &progmon
00464 );
00465
00466 if(!global_pm) {
00467 cerr << Error << "Failed to read from file '"
00468 << driver_settings.m_global_photon_map.m_file << "'." << endl;
00469 return EXIT_FAILURE;
00470 }
00471
00472 statistics.m_gpm_photons = global_pm->GetPhotonCount();
00473
00474 } else {
00475
00476
00477 cout << ++current_task << '/' << task_count << ". Building global photon map (GPM)" << endl;
00478
00479
00480 global_pm = new PhotonMap();
00481
00482
00483 progmon.Reset(" * Photon tracing");
00484 GlobalPhotonTracer().BuildPhotonMap(
00485 context,
00486 global_pm,
00487 scene,
00488 scene_settings.m_rendering.m_components.m_indirect_lighting.m_photon_tracing.m_photons,
00489 &progmon
00490 );
00491
00492
00493 cout << " * Photon map balancing" << flush;
00494 global_pm->Balance();
00495 cout << '.' << endl;
00496
00497
00498 if(scene_settings.m_rendering.m_components.m_indirect_lighting.m_radiance_precomp.m_enabled) {
00499 #ifdef ENABLE_RADIANCES_PRECOMPUTATION
00500 progmon.Reset(" * Radiances precomputation");
00501 global_pm->PrecomputeRadiances(
00502 scene_settings.m_rendering.m_components.m_indirect_lighting.m_radiance_precomp.m_spacing,
00503 scene_settings.m_rendering.m_components.m_indirect_lighting.m_radiance_est.m_max_distance,
00504 scene_settings.m_rendering.m_components.m_indirect_lighting.m_radiance_est.m_max_photons,
00505 &progmon
00506 );
00507 #else
00508 cout << " * Radiances precomputation not available. Using standard radiance estimate." << endl;
00509 #endif // ENABLE_RADIANCES_PRECOMPUTATION
00510 }
00511 }
00512
00513
00514 cout << " * Early statistics" << endl;
00515 cout << " Allocated memory: "
00516 << ConvertSizeToString(global_pm->GetSizeInMemory(), true)
00517 << endl;
00518 if(driver_settings.m_global_photon_map.m_op != DriverSettings::LOAD_PM) {
00519 cout << " Emitted photons: "
00520 << ConvertNumberToString(scene_settings.m_rendering.m_components.m_indirect_lighting.m_photon_tracing.m_photons)
00521 << endl;
00522 }
00523 cout << " Stored photons: "
00524 << ConvertNumberToString(statistics.m_gpm_photons);
00525 if(driver_settings.m_global_photon_map.m_op != DriverSettings::LOAD_PM) {
00526 cout << " ("
00527 << Percentage(statistics.m_gpm_photons, scene_settings.m_rendering.m_components.m_indirect_lighting.m_photon_tracing.m_photons)
00528 << ')';
00529 }
00530 cout << endl;
00531
00532 if(driver_settings.m_global_photon_map.m_op == DriverSettings::BUILD_AND_SAVE_PM) {
00533
00534
00535 ss.str("");
00536 ss << " * Writing GPM to file "
00537 << driver_settings.m_global_photon_map.m_file;
00538 progmon.Reset(ss.str());
00539
00540 if(!global_pm->WriteToFile(
00541 driver_settings.m_global_photon_map.m_file,
00542 &progmon))
00543 {
00544 cerr << Error << "Failed to write to file '"
00545 << driver_settings.m_global_photon_map.m_file << "'." << endl;
00546
00547 }
00548 }
00549
00550
00551 renderer.SetGlobalPhotonMap(global_pm);
00552 }
00553
00554 PhotonMap *caustics_pm = 0;
00555
00556 if(scene_settings.m_rendering.m_components.m_caustics.m_enabled) {
00557 if(driver_settings.m_caustics_photon_map.m_op == DriverSettings::LOAD_PM) {
00558
00559
00560 ss.str("");
00561 ss << ++current_task << '/' << task_count << ". Reading CPM from file "
00562 << driver_settings.m_caustics_photon_map.m_file;
00563 progmon.Reset(ss.str());
00564
00565 caustics_pm = PhotonMap::CreateFromFile(
00566 driver_settings.m_caustics_photon_map.m_file,
00567 &progmon
00568 );
00569
00570 if(!caustics_pm) {
00571 cerr << Error << "Failed to read from file '"
00572 << driver_settings.m_caustics_photon_map.m_file << "'." << endl;
00573 return EXIT_FAILURE;
00574 }
00575
00576 statistics.m_cpm_photons = caustics_pm->GetPhotonCount();
00577
00578 } else {
00579
00580
00581 cout << ++current_task << '/' << task_count << ". Building caustics photon map (CPM)" << endl;
00582
00583
00584 caustics_pm = new PhotonMap();
00585
00586
00587 progmon.Reset(" * Photon tracing");
00588 CausticsPhotonTracer().BuildPhotonMap(
00589 context,
00590 caustics_pm,
00591 scene,
00592 scene_settings.m_rendering.m_components.m_caustics.m_photon_tracing.m_photons,
00593 &progmon
00594 );
00595
00596 cout << " * Allocated memory: "
00597 << ConvertSizeToString(caustics_pm->GetSizeInMemory(), true)
00598 << "." << endl;
00599
00600
00601 cout << " * Photon map balancing" << flush;
00602 caustics_pm->Balance();
00603 cout << '.' << endl;
00604 }
00605
00606
00607 cout << " * Early statistics" << endl;
00608 cout << " Allocated memory: "
00609 << ConvertSizeToString(caustics_pm->GetSizeInMemory(), true)
00610 << endl;
00611 if(driver_settings.m_caustics_photon_map.m_op != DriverSettings::LOAD_PM) {
00612 cout << " Emitted photons: "
00613 << ConvertNumberToString(scene_settings.m_rendering.m_components.m_caustics.m_photon_tracing.m_photons)
00614 << endl;
00615 }
00616 cout << " Stored photons: "
00617 << ConvertNumberToString(statistics.m_cpm_photons);
00618 if(driver_settings.m_caustics_photon_map.m_op != DriverSettings::LOAD_PM) {
00619 cout << " ("
00620 << Percentage(statistics.m_cpm_photons, scene_settings.m_rendering.m_components.m_caustics.m_photon_tracing.m_photons)
00621 << ')';
00622 }
00623 cout << endl;
00624
00625 if(driver_settings.m_caustics_photon_map.m_op == DriverSettings::BUILD_AND_SAVE_PM) {
00626
00627
00628 ss.str("");
00629 ss << " * Writing CPM to file "
00630 << driver_settings.m_caustics_photon_map.m_file;
00631 progmon.Reset(ss.str());
00632
00633 if(!caustics_pm->WriteToFile(
00634 driver_settings.m_caustics_photon_map.m_file,
00635 &progmon))
00636 {
00637 cerr << Error << "Failed to write to file '"
00638 << driver_settings.m_caustics_photon_map.m_file << "'." << endl;
00639
00640 }
00641 }
00642
00643
00644 renderer.SetCausticsPhotonMap(caustics_pm);
00645 }
00646
00647 if(driver_settings.m_primary_output.m_enabled) {
00648 cout << ++current_task << '/' << task_count << ". Generating primary output" << endl;
00649
00650 ss.str("");
00651 ss << " * Rendering";
00652 progmon.Reset(ss.str());
00653 progmon.StartJob(0.0, 1.0);
00654
00655
00656 renderer.Restart(context);
00657
00658 #ifdef ENABLE_MULTITHREADING
00659 boost::thread_group threads;
00660
00661
00662 threads.create_thread(ProgressMonitoringThread());
00663 #endif // ENABLE_MULTITHREADING
00664
00665
00666 while(!renderer.IsRenderComplete()) {
00667 renderer.RenderNextPixel(context);
00668
00669 #ifdef ENABLE_MULTITHREADING
00670 boost::mutex::scoped_lock lock(io_mutex);
00671 #endif // ENABLE_MULTITHREADING
00672
00673 progmon.SetJobProgress(renderer.GetProgress());
00674 }
00675
00676 #ifdef ENABLE_MULTITHREADING
00677 threads.join_all();
00678 #endif // ENABLE_MULTITHREADING
00679
00680 progmon.Done();
00681
00682
00683
00684
00685
00686
00687 if(scene_settings.m_output.m_gamma_correction.m_enabled) {
00688 cout << " * Applying gamma correction" << flush;
00689 framebuffer->CorrectGamma(
00690 scene_settings.m_output.m_gamma_correction.m_target_gamma
00691 );
00692 cout << '.' << endl;
00693 }
00694
00695
00696 cout << " * Writing rendered image to file "
00697 << driver_settings.m_primary_output.m_file << flush;
00698 if(!framebuffer->WriteToDisk(driver_settings.m_primary_output.m_file)) {
00699 cerr << Error << "Failed to write to file '"
00700 << driver_settings.m_primary_output.m_file << "'." << endl;
00701
00702 return EXIT_FAILURE;
00703 }
00704 cout << '.' << endl;
00705 }
00706
00707 cout << endl;
00708
00709
00710 print_statistics(statistics);
00711
00712 delete caustics_pm;
00713 delete global_pm;
00714 delete camera;
00715 delete scene;
00716 delete scene_builder;
00717 delete framebuffer;
00718
00719 return EXIT_SUCCESS;
00720 }