engine.C

00001 /*
00002  * This file is part of the "Archon" framework.
00003  * (http://files3d.sourceforge.net)
00004  *
00005  * Copyright © 2002 by Kristian Spangsege and Brian Kristiansen.
00006  *
00007  * Permission to use, copy, modify, and distribute this software and
00008  * its documentation under the terms of the GNU General Public License is
00009  * hereby granted. No representations are made about the suitability of
00010  * this software for any purpose. It is provided "as is" without express
00011  * or implied warranty. See the GNU General Public License
00012  * (http://www.gnu.org/copyleft/gpl.html) for more details.
00013  *
00014  * The characters in this file are ISO8859-1 encoded.
00015  *
00016  * The documentation in this file is in "Doxygen" style
00017  * (http://www.doxygen.org).
00018  */
00019 
00020 #include <archon/util/window.H>
00021 #include <archon/util/time.H>
00022 #include <archon/util/thread.H>
00023 #include <archon/util/kdtree.H>
00024 #include <archon/util/adaptive_skip.H>
00025 #include <archon/util/color.H>
00026 #include <archon/util/image.H>
00027 #include <archon/util/progress_meter.H>
00028 
00029 #include "options.H"
00030 #include "world.H"
00031 #include "engine.H"
00032 
00033 #if ! defined M_PI
00034 #define M_E           2.7182818284590452353602874713526625  /* e */
00035 #define M_LOG2E       1.4426950408889634073599246810018922  /* log_2 e */
00036 #define M_LOG10E      0.4342944819032518276511289189166051  /* log_10 e */
00037 #define M_LN2         0.6931471805599453094172321214581766  /* log_e 2 */
00038 #define M_LN10        2.3025850929940456840179914546843642  /* log_e 10 */
00039 #define M_PI          3.1415926535897932384626433832795029  /* pi */
00040 #define M_PI_2        1.5707963267948966192313216916397514  /* pi/2 */
00041 #define M_PI_4        0.7853981633974483096156608458198757  /* pi/4 */
00042 #define M_1_PI        0.3183098861837906715377675267450287  /* 1/pi */
00043 #define M_2_PI        0.6366197723675813430755350534900574  /* 2/pi */
00044 #define M_2_SQRTPI    1.1283791670955125738961589031215452  /* 2/sqrt(pi) */
00045 #define M_SQRT2       1.4142135623730950488016887242096981  /* sqrt(2) */
00046 #define M_SQRT1_2     0.7071067811865475244008443621048490  /* 1/sqrt(2) */
00047 #endif
00048 
00049 using namespace std;
00050 
00051 namespace Archon
00052 {
00053   using namespace Utilities;
00054   using namespace Math;
00055 
00056   namespace Raytracer
00057   {
00058     void flush(Window *window, vector<Vector4> &pixels,
00059                unsigned &frameX, unsigned &frameY)
00060     {
00061       Window::Update update(window);
00062       for(unsigned i=0; i<pixels.size(); ++i)
00063       {
00064         unsigned red   = unsigned(pixels[i][0] * 256); if(red   >= 256) red   = 255;
00065         unsigned green = unsigned(pixels[i][1] * 256); if(green >= 256) green = 255;
00066         unsigned blue  = unsigned(pixels[i][2] * 256); if(blue  >= 256) blue  = 255;
00067         update.drawPoint(frameX, frameY, Window::set, red, green, blue);
00068         ++frameX;
00069         if(frameX == window->getWidth())
00070         {
00071           frameX = 0;
00072           --frameY;
00073         }
00074       }
00075 
00076       pixels.clear();
00077     }
00078 
00079     class WindowQuitHandler: public Window::WindowHandler
00080     {
00081       bool &quitFlag;
00082 
00083     public:
00084       WindowQuitHandler(bool &quitFlag): quitFlag(quitFlag) {}
00085 
00086       void quit()
00087       {
00088         quitFlag = true;
00089         cout << "\n";
00090       }
00091     };
00092 
00093     void Engine::render(World *world, View view)
00094     {
00095       if(opt_generatePhotonMap)
00096         world->photonTrace(opt_causticPhotons);
00097 
00098       const double aspect = double(opt_resolution.y) / opt_resolution.x;
00099 
00100       Vector2 viewPlane;
00101 
00102       if(aspect < 1)
00103       {
00104         viewPlane[1] = 2*tan(view.fieldOfView/2);
00105         viewPlane[0] = viewPlane[1] / aspect;
00106       }
00107       else
00108       {
00109         viewPlane[0] = 2*tan(view.fieldOfView/2);
00110         viewPlane[1] = viewPlane[0] * aspect;
00111       }
00112 
00113       Vector3 viewPlaneLowerLeft = view.coordSystem.origin;
00114       viewPlaneLowerLeft -= view.coordSystem.basis.x * viewPlane[0] / 2;
00115       viewPlaneLowerLeft -= view.coordSystem.basis.y * viewPlane[1] / 2;
00116       viewPlaneLowerLeft -= view.coordSystem.basis.z;
00117 
00118       Vector3 viewPlaneHorizontalSpan = view.coordSystem.basis.x;
00119       viewPlaneHorizontalSpan *= viewPlane[0];
00120 
00121       Vector3 viewPlaneVerticalSpan = view.coordSystem.basis.y;
00122       viewPlaneVerticalSpan *= viewPlane[1];
00123 
00124       Window *window = 0;
00125       AdaptiveSkip skip(100);
00126       vector<Vector4> pixels;
00127       unsigned frameX = 0;
00128       unsigned frameY = opt_resolution.y - 1;
00129 
00130       bool quit = false;
00131 
00132       WindowQuitHandler windowQuitHandler(quit);
00133 
00134       if(opt_displayRendering)
00135         window = new Window(opt_resolution.x, opt_resolution.y,
00136                                     32, false, false, 0, 0, &windowQuitHandler);
00137 
00138       Image image(opt_resolution.x, opt_resolution.y);
00139 
00140       ProgressStatus progress(opt_resolution.x * opt_resolution.y);
00141 
00142       unsigned extraSkip = 0;
00143 
00144       for(int y = 0; y<opt_resolution.y; ++y)
00145       {
00146         Vector3 vy(viewPlaneVerticalSpan);
00147         vy *= double(y) / opt_resolution.y;
00148 
00149         for(int x = 0; x<opt_resolution.x; ++x)
00150         {
00151           Vector3 v(viewPlaneHorizontalSpan);
00152           v *= double(x) / opt_resolution.x;
00153           v += vy;
00154           v += viewPlaneLowerLeft;
00155           v -= view.coordSystem.origin;
00156           v.normalize();
00157 
00158           Vector4 c = world->trace(Line3(view.coordSystem.origin, v));
00159           image.setPixel(x, y, c[0], c[1], c[2], c[3]);
00160 
00161           if(c[0] >= 1) c[0] = 1;
00162           if(c[1] >= 1) c[1] = 1;
00163           if(c[2] >= 1) c[2] = 1;
00164           if(c[3] >= 1) c[3] = 1;
00165 
00166           // Blend with background of gray tiles ala The Gimp
00167           double tile = ((x/16+y/16)%2 ? 0.5 : 0.7) * (1-c[3]);
00168           c[0] = c[3] * c[0] + tile;
00169           c[1] = c[3] * c[1] + tile;
00170           c[2] = c[3] * c[2] + tile;
00171           c[3] = 1;
00172 
00173           pixels.push_back(c);
00174 
00175           progress.tick();
00176 
00177           if(opt_displayRendering && skip.tick())
00178           {
00179             window->executeEventQueue(Time::now().getMilliSeconds());
00180             if(++extraSkip == 10)
00181             {
00182               flush(window, pixels, frameX, frameY);
00183               extraSkip = 0;
00184             }
00185           }
00186 
00187           if(quit) break;
00188         }
00189         if(quit) break;
00190       }
00191 
00192       if(opt_displayRendering) flush(window, pixels, frameX, frameY);
00193 
00194       image.save(opt_outputFileName, "", 0, logger);
00195 
00196       if(opt_displayRendering) while(!quit)
00197       {
00198         window->executeEventQueue(Time::now().getMilliSeconds());
00199         Thread::sleep(Time(0, 100000000));
00200       }
00201     }
00202   }
00203 }

Generated on Sun Jul 30 22:55:51 2006 for Archon by  doxygen 1.4.4