Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

SkyDomeImage.cpp

Go to the documentation of this file.
00001 /*
00002  * SkyDomeImage.cpp
00003  *
00004  * Part of Fly! Legacy project
00005  *
00006  * Copyright 2003 Chris Wallace
00007  *
00008  * Fly! Legacy is free software; you can redistribute it and/or modify
00009  *   it under the terms of the GNU General Public License as published by
00010  *   the Free Software Foundation; either version 2 of the License, or
00011  *   (at your option) any later version.
00012  *
00013  * Fly! Legacy is distributed in the hope that it will be useful,
00014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *   GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  *   along with Fly! Legacy; if not, write to the Free Software
00020  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 
00029 #include "../Include/Globals.h"
00030 #include "../Include/Sky.h"
00031 #include "../Include/Utility.h"
00032 #include "../Include/Ui.h"
00033 #include <plib/ssg.h>
00034 
00035 using namespace std;
00036 
00037 //
00038 // SSG pre-draw callback disables z-buffering and fog
00039 //
00040 static int skydomeimage_predraw (ssgEntity *e)
00041 {
00042   ssgLeaf *f = (ssgLeaf*) e;
00043   if (f->hasState()) f->getState()->apply();
00044 
00045   if (globals->settings->skydomeWireframe) {
00046     glPushAttrib (GL_DEPTH_BUFFER_BIT | GL_FOG_BIT | GL_POLYGON_BIT);
00047     glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
00048   } else {
00049     glPushAttrib (GL_DEPTH_BUFFER_BIT | GL_FOG_BIT);
00050   }
00051   glDisable (GL_DEPTH_TEST);
00052   glDisable (GL_FOG);
00053 
00054     return true;
00055 }
00056 
00057 
00058 //
00059 // SSG post-draw callback restores original state of
00060 //   z-buffering and fog
00061 //
00062 static int skydomeimage_postdraw (ssgEntity *e)
00063 {
00064   glPopAttrib ();
00065 
00066   return true;
00067 }
00068 
00069 
00070 /*
00071  * Perez sky dome
00072  */
00073 
00074 //
00075 // Perez function
00076 //
00077 float PerezFunction (float theta, float gamma, const SPerezCoefficients &p)
00078 {
00079   // Check for indeterminate case of cos(theta)=0, where exp(p.B/cos(theta))=0,
00080   //   assuming p.B is negative
00081   float f1;
00082   double epsilon = 1.0e-10;
00083   if (cos(theta) < epsilon) {
00084     f1 = 1;
00085   } else {
00086     f1 = 1 + (p.A * exp (p.B / cos(theta)));
00087   }
00088   float cosgamma = cos(gamma);
00089   float cos2gamma = cosgamma * cosgamma;
00090   float f2 = 1 + (p.C * exp (p.D * gamma)) + (p.E * cos2gamma);
00091 
00092   return f1 * f2;
00093 }
00094 
00095            
00096 //
00097 // Calculate Perez distribution coefficients
00098 //
00099 // Inputs:
00100 //  T   Turbidity
00101 //  parm  Coefficient parameters
00102 //
00103 // Outputs:
00104 //  coeff Coefficients
00105 //
00106 void CalcPerezCoefficients (float T,
00107                 const SCoefficientParameters &parm,
00108                 SPerezCoefficients &coeff)
00109 {
00110   coeff.A = parm.A[1] * T + parm.A[0];
00111   coeff.B = parm.B[1] * T + parm.B[0];
00112   coeff.C = parm.C[1] * T + parm.C[0];
00113   coeff.D = parm.D[1] * T + parm.D[0];
00114   coeff.E = parm.E[1] * T + parm.E[0];
00115 }
00116 
00117           
00118 //
00119 // Calculate the Y (luminance component) for the zenith
00120 //
00121 // Input parameters:
00122 //  theta Solar zenith angle in radians
00123 //  T   Turbidity
00124 //
00125 // Return code:
00126 //  float Y (luminance)
00127 //typedef struct {
00128 //  float   A, B, C, D;
00129 //} SLuminanceZenith;
00130 //
00131 static float ZenithLuminance (float theta, float T, const SLuminanceZenith &p)
00132 {
00133   float chi = ((4.0 / 9.0) - (T / 120.0)) * (SG_PI - 2.0 * theta);
00134   float Yz = ((p.A * T) + p.B) * tan(chi) + (p.C * T) + p.D;
00135   Yz *= 1000.0f;
00136 
00137   return Yz;
00138 }
00139 
00140 
00141 //
00142 // Calculate chrominance (x or y) component for the zenith
00143 //
00144 // Input parameters:
00145 //  theta Solar zenith angle in radians
00146 //  T   Turbidity
00147 //  p   Zenith chrominance parameter matrix
00148 //
00149 // Return value:
00150 //  float Chrominance component
00151 //
00152 static float ZenithChrominance (float theta, float T, const SChromaZenith &p)
00153 {
00154   float rc = 0.0;
00155   float T2 = T * T;
00156   float theta2 = theta * theta;
00157   float theta3 = theta * theta * theta;
00158   rc = 
00159     (p.t2[3] * theta3 + p.t2[2] * theta2 + p.t2[1] * theta + p.t2[0]) * T2 +
00160     (p.t1[3] * theta3 + p.t1[2] * theta2 + p.t1[1] * theta + p.t1[0]) * T +
00161     (p.t0[3] * theta3 + p.t0[2] * theta2 + p.t0[1] * theta + p.t0[0]);
00162 
00163   return rc;
00164 }
00165 
00166 
00167 //
00168 // Convert CIE Yxy colour value to RGB.  This is done in two steps, first to
00169 //   CIE XYZ format, then from XYZ to RGB.  White point D65 is used.
00170 //
00171 // Input parameters:
00172 //  Y CIE Yxy luminance Y value   [0..100]
00173 //  x CIE Yxy chrominance x value   [0..1]
00174 //  y CIE Yxy chrominance y value   [0..1]
00175 //
00176 static void YxyToRGB (float Y, float x, float y, float* r, float* g, float* b)
00177 {
00178   // First convert to CIE XYZ format
00179   float X = (x / y) * Y;
00180   float Z = ((1 - x - y) / y) * Y;
00181 
00182   // Convert XYZ to RGB using D65 white point
00183   float factor = 1.0f - exp(-(1.0f / 15000.0f));
00184   float R = factor * ( 3.240479 * X + -1.537150 * Y + -0.498535 * Z);
00185   float G = factor * (-0.969256 * X +  1.875992 * Y +  0.041556 * Z);
00186   float B = factor * ( 0.055648 * X + -0.204043 * Y +  1.057311 * Z);
00187 
00188   if (R < 0.0f) R = 0.0f;
00189   if (R > 1.0f) R = 1.0f;
00190 
00191   if (G < 0.0f) G = 0.0f;
00192   if (G > 1.0f) G = 1.0f;
00193   
00194   if (B < 0.0f) B = 0.0f;
00195   if (B > 1.0f) B = 1.0f;
00196 
00197   // Gamma-adjust
00199   float gamma = 1.8;
00200   float invgamma = 1.0f / gamma;
00201   *r = pow (R, invgamma);
00202   *g = pow (G, invgamma);
00203   *b = pow (B, invgamma);
00204 }
00205 
00206 
00207 static void InitPerezParameters (SPerezParameters* p,
00208                  CIniFile *inisky,
00209                  const char* name)
00210 {
00211   // Initialize to defaults
00212   memset (p, 0, sizeof(SPerezParameters));
00213 
00214   // Initialize name
00215   strcpy (p->name, name);
00216 
00217   // Initialize zenith parameters
00218   inisky->Get (name, "zenith_Y_A", &(p->Y_zenith.A));
00219   inisky->Get (name, "zenith_Y_B", &(p->Y_zenith.B));
00220   inisky->Get (name, "zenith_Y_C", &(p->Y_zenith.C));
00221   inisky->Get (name, "zenith_Y_D", &(p->Y_zenith.D));
00222 
00223   inisky->Get (name, "zenith_x_theta3_T2", &(p->x_zenith.t2[3]));
00224   inisky->Get (name, "zenith_x_theta3_T1", &(p->x_zenith.t1[3]));
00225   inisky->Get (name, "zenith_x_theta3_T0", &(p->x_zenith.t0[3]));
00226   inisky->Get (name, "zenith_x_theta2_T2", &(p->x_zenith.t2[2]));
00227   inisky->Get (name, "zenith_x_theta2_T1", &(p->x_zenith.t1[2]));
00228   inisky->Get (name, "zenith_x_theta2_T0", &(p->x_zenith.t0[2]));
00229   inisky->Get (name, "zenith_x_theta1_T2", &(p->x_zenith.t2[1]));
00230   inisky->Get (name, "zenith_x_theta1_T1", &(p->x_zenith.t1[1]));
00231   inisky->Get (name, "zenith_x_theta1_T0", &(p->x_zenith.t0[1]));
00232   inisky->Get (name, "zenith_x_theta0_T2", &(p->x_zenith.t2[0]));
00233   inisky->Get (name, "zenith_x_theta0_T1", &(p->x_zenith.t1[0]));
00234   inisky->Get (name, "zenith_x_theta0_T0", &(p->x_zenith.t0[0]));
00235 
00236   inisky->Get (name, "zenith_y_theta3_T2", &(p->y_zenith.t2[3]));
00237   inisky->Get (name, "zenith_y_theta3_T1", &(p->y_zenith.t1[3]));
00238   inisky->Get (name, "zenith_y_theta3_T0", &(p->y_zenith.t0[3]));
00239   inisky->Get (name, "zenith_y_theta2_T2", &(p->y_zenith.t2[2]));
00240   inisky->Get (name, "zenith_y_theta2_T1", &(p->y_zenith.t1[2]));
00241   inisky->Get (name, "zenith_y_theta2_T0", &(p->y_zenith.t0[2]));
00242   inisky->Get (name, "zenith_y_theta1_T2", &(p->y_zenith.t2[1]));
00243   inisky->Get (name, "zenith_y_theta1_T1", &(p->y_zenith.t1[1]));
00244   inisky->Get (name, "zenith_y_theta1_T0", &(p->y_zenith.t0[1]));
00245   inisky->Get (name, "zenith_y_theta0_T2", &(p->y_zenith.t2[0]));
00246   inisky->Get (name, "zenith_y_theta0_T1", &(p->y_zenith.t1[0]));
00247   inisky->Get (name, "zenith_y_theta0_T0", &(p->y_zenith.t0[0]));
00248 
00249   // Initialize curve parameters
00250   inisky->Get (name, "perez_Y_A_T1", &(p->Y_curve.A[1]));
00251   inisky->Get (name, "perez_Y_A_T0", &(p->Y_curve.A[0]));
00252   inisky->Get (name, "perez_Y_B_T1", &(p->Y_curve.B[1]));
00253   inisky->Get (name, "perez_Y_B_T0", &(p->Y_curve.B[0]));
00254   inisky->Get (name, "perez_Y_C_T1", &(p->Y_curve.C[1]));
00255   inisky->Get (name, "perez_Y_C_T0", &(p->Y_curve.C[0]));
00256   inisky->Get (name, "perez_Y_D_T1", &(p->Y_curve.D[1]));
00257   inisky->Get (name, "perez_Y_D_T0", &(p->Y_curve.D[0]));
00258   inisky->Get (name, "perez_Y_E_T1", &(p->Y_curve.E[1]));
00259   inisky->Get (name, "perez_Y_E_T0", &(p->Y_curve.E[0]));
00260 
00261   inisky->Get (name, "perez_x_A_T1", &(p->x_curve.A[1]));
00262   inisky->Get (name, "perez_x_A_T0", &(p->x_curve.A[0]));
00263   inisky->Get (name, "perez_x_B_T1", &(p->x_curve.B[1]));
00264   inisky->Get (name, "perez_x_B_T0", &(p->x_curve.B[0]));
00265   inisky->Get (name, "perez_x_C_T1", &(p->x_curve.C[1]));
00266   inisky->Get (name, "perez_x_C_T0", &(p->x_curve.C[0]));
00267   inisky->Get (name, "perez_x_D_T1", &(p->x_curve.D[1]));
00268   inisky->Get (name, "perez_x_D_T0", &(p->x_curve.D[0]));
00269   inisky->Get (name, "perez_x_E_T1", &(p->x_curve.E[1]));
00270   inisky->Get (name, "perez_x_E_T0", &(p->x_curve.E[0]));
00271 
00272   inisky->Get (name, "perez_y_A_T1", &(p->y_curve.A[1]));
00273   inisky->Get (name, "perez_y_A_T0", &(p->y_curve.A[0]));
00274   inisky->Get (name, "perez_y_B_T1", &(p->y_curve.B[1]));
00275   inisky->Get (name, "perez_y_B_T0", &(p->y_curve.B[0]));
00276   inisky->Get (name, "perez_y_C_T1", &(p->y_curve.C[1]));
00277   inisky->Get (name, "perez_y_C_T0", &(p->y_curve.C[0]));
00278   inisky->Get (name, "perez_y_D_T1", &(p->y_curve.D[1]));
00279   inisky->Get (name, "perez_y_D_T0", &(p->y_curve.D[0]));
00280   inisky->Get (name, "perez_y_E_T1", &(p->y_curve.E[1]));
00281   inisky->Get (name, "perez_y_E_T0", &(p->y_curve.E[0]));
00282 }
00283 
00284 
00285 SPerezParameters DefaultPerezParameters =
00286 {
00287   "Default",
00288 
00289   // Y distribution
00290   {
00291     {-1.4630, +0.1787}, // A
00292     {+0.4275, -0.3554}, // B
00293     {+5.3251, -0.0227}, // C
00294     {-2.5771, +0.1206}, // D
00295     {+0.3703, -0.0670}, // E
00296   },
00297 
00298   // x distribution
00299   {
00300     {-0.2592, -0.0193}, // A
00301     {+0.0008, -0.0665}, // B
00302     {+0.2125, -0.0004}, // C
00303     {-0.8989, -0.0641}, // D
00304     {+0.0452, -0.0033}, // E
00305   },
00306 
00307   // y distribution
00308   {
00309     {-0.2608, -0.0167}, // A
00310     {+0.0092, -0.0950}, // B
00311     {+0.2102, -0.0079}, // C
00312     {-1.6537, -0.0441}, // D
00313     {+0.0529, -0.0109}, // E
00314   },
00315 
00316   // Y zenith
00317   {
00318     +4.0453,    // A
00319     -4.9710,    // B
00320     -0.2155,    // C
00321     +2.4192,    // D
00322   },
00323 
00324   // x zenith
00325   {
00326     //   1       theta    theta^2   theta^3
00327     {+0.00000, +0.00209, -0.00375, +0.00166}, // T^2
00328     {+0.00394, -0.03202, +0.06377, -0.02903}, // T
00329     {+0.25886, +0.06052, -0.21196, +0.11693}, // 1
00330   },
00331 
00332   // y zenith
00333   {
00334     //   1       theta    theta^2   theta^3
00335     {+0.00000, +0.00317, -0.00610, +0.00275}, // T^2
00336     {+0.00516, -0.04153, +0.08970, -0.04214}, // T
00337     {+0.26688, +0.06670, -0.26756, +0.15346}, // 1
00338   }
00339 };
00340 
00341 CSkyDomeImage::CSkyDomeImage (double distance)
00342 {
00343   int i, j;
00344   
00345   // Add default Perez parameters
00346   SPerezParameters *pDefault = new SPerezParameters;
00347   memcpy (pDefault, &DefaultPerezParameters, sizeof(SPerezParameters));
00348   perez[DefaultPerezParameters.name] = pDefault;
00349 
00350   //
00351   // Load Perez parameter sets from SKIES.INI
00352   //
00353   CIniFile *inisky = new CIniFile;
00354   if (inisky->Load ("System\\Skies.ini") != 0) {
00355     // SKIES.INI could be read; parse parameters from INI settings
00356     int nSkies = inisky->GetNumSections();
00357     for (i=0; i<nSkies; i++) {
00358       SPerezParameters *p = new SPerezParameters;
00359       memcpy (p, &DefaultPerezParameters, sizeof(SPerezParameters));
00360       char* skyname = inisky->GetSectionName (i);
00361       InitPerezParameters (p, inisky, skyname);
00362       perez[skyname] = p;
00363     }
00364   }
00365   delete inisky;
00366 
00367   // Get default sky name from INI settings
00368   perezCurrent = &DefaultPerezParameters;
00369   char skyname[64];
00370   strcpy (skyname, "");
00371   GetIniString ("Graphics", "skyDefaultName", skyname, 64);
00372   if (strlen (skyname) > 0) {
00373     // Parameter was specified, search available skies for the default
00374     map<string,SPerezParameters*>::iterator i = perez.find(skyname);
00375     if (i != perez.end()) {
00376       perezCurrent = i->second;
00377     }
00378   }
00379 
00380   //
00381   // Generate raw vertex data
00382   //
00383   // The sky dome vertex raw data is made up of a single zenith vertex, plus
00384   //   SKYDOME_STACKS "rings" of SKYDOME_SLICES vertices in each ring.  The top of
00385   //   the sky dome is constructed of a triangle fan between the zenith
00386   //   vertex and each of the vertices in the top ring.  The remainder of the
00387   //   dome is constructed of triangle strips spanning each successive vertex ring.
00388   //
00389 
00390   // Zenith vertex is easy
00391   sgSetVec3 (vtx_zenith, 0, 0, distance);
00392 
00393   // Iterate over all vertices of all rings
00394   double dPhi = (SGD_PI / 2) / SKYDOME_STACKS;
00395   double dTheta = (2.0 * SGD_PI) / SKYDOME_SLICES;
00396   for (i=0; i<SKYDOME_STACKS; i++) {
00397     // Calculate elevation angle phi for all vertices in this ring
00398     double phi = (SGD_PI / 2) - ((i+1) * dPhi);
00399     double ring_radius = distance * cos(phi);
00400     double ring_elevation = distance * sin(phi);
00401 
00402     for (j=0; j<SKYDOME_SLICES; j++) {
00403       // Calculate azimuth angle theta
00404       double theta = j * dTheta;
00405       sgSetVec3 (vtx_ring[i][j],
00406                  cos(theta) * ring_radius,
00407                  sin(theta) * ring_radius,
00408                  ring_elevation);
00409     }
00410   }
00411 
00412   //
00413   // Create top-level SSG object to be the parent of all leaf objects
00414   //
00415   top = new ssgTransform;
00416   top->setName ("SkyDomeImage");
00417 
00418   //  Define a dummy colour for construction of the skydome.
00419   //  The Repaint method will set the proper colours for each vertex
00420   sgVec4 c;
00421   sgSetVec4 (c, 0.39, 0.50, 0.75, 1.0);
00422 
00423   // Define a "special" colour that can be used to highlight particular
00424   //   areas of the skydome for testing
00425   sgVec4 special;
00426   sgSetVec4 (special, 1.0, 0.0, 0.0, 1.0);
00427 
00428   //
00429   // Create SSG leaf for zenith triangle fan
00430   //
00431   ssgVertexArray *va = new ssgVertexArray(SKYDOME_SLICES + 2);
00432   ssgColourArray *rgba = new ssgColourArray(SKYDOME_SLICES + 2);
00433 
00434   // Generate zenith disk
00435   va->add (vtx_zenith);
00436   rgba->add (c);
00437   for (i=0; i<SKYDOME_SLICES; i++) {
00438     va->add (vtx_ring[0][i]);
00439     rgba->add (c);
00440   }
00441   va->add (vtx_ring[0][0]);
00442   rgba->add (c);
00443 
00444   // Create SSG state data to be applied to zenith fan
00445   ssgSimpleState *state = new ssgSimpleState ();
00446   state->setShadeModel (GL_SMOOTH);
00447   state->disable (GL_LIGHTING);
00449   state->disable (GL_CULL_FACE);
00450   state->disable (GL_TEXTURE_2D);
00451   state->enable (GL_BLEND);
00452   state->disable (GL_ALPHA_TEST);
00453   state->enable (GL_COLOR_MATERIAL);
00454   state->setColourMaterial (GL_AMBIENT_AND_DIFFUSE);
00455   state->setMaterial (GL_EMISSION, 0, 0, 0, 1);
00456   state->setMaterial (GL_SPECULAR, 0, 0, 0, 1);
00457 
00458   // Create SSG leaf, assign name, state and callbacks
00459   ssgVtxTable *vtZenith = new ssgVtxTable (GL_TRIANGLE_FAN, va, NULL, NULL, rgba);
00460   vtZenith->setName ("Zenith");
00461   vtZenith->setState (state);
00462   vtZenith->setCallback (SSG_CALLBACK_PREDRAW,  skydomeimage_predraw);
00463   vtZenith->setCallback (SSG_CALLBACK_POSTDRAW, skydomeimage_postdraw);
00464 
00465   // Attach leaf to top-level transform
00466   top->addKid (vtZenith);
00467 
00468   //
00469   // Create SSG leaf objects for each stack
00470   //
00471   for (i=0; i<SKYDOME_STACKS-1; i++) {
00472     // Allocate vertex and colour arrays
00473     va = new ssgVertexArray((SKYDOME_SLICES * 2) + 2);
00474     rgba = new ssgColourArray((SKYDOME_SLICES * 2) + 2);
00475 
00476     // Generate arrays
00477     for (j=0; j<SKYDOME_SLICES; j++) {
00478       va->add (vtx_ring[i][j]);
00479       rgba->add (c);
00480       va->add (vtx_ring[i+1][j]);
00481       rgba->add (c);
00482     }
00483     va->add (vtx_ring[i][0]);
00484     rgba->add (c);
00485     va->add (vtx_ring[i+1][0]);
00486     rgba->add (c);
00487 
00488     // Create SSG state data to be applied to this slice
00489     ssgSimpleState *state = new ssgSimpleState ();
00490     state->setShadeModel (GL_SMOOTH);
00491     state->disable (GL_LIGHTING);
00493     state->disable (GL_CULL_FACE);
00494     state->disable (GL_TEXTURE_2D);
00495     state->enable (GL_BLEND);
00496     state->disable (GL_ALPHA_TEST);
00497     state->enable (GL_COLOR_MATERIAL);
00498     state->setColourMaterial (GL_AMBIENT_AND_DIFFUSE);
00499     state->setMaterial (GL_EMISSION, 0, 0, 0, 1);
00500     state->setMaterial (GL_SPECULAR, 0, 0, 0, 1);
00501 
00502     // Create SSG leaf, assign name, state and callbacks
00503     ssgVtxTable *vtab = new ssgVtxTable (GL_TRIANGLE_STRIP, va, NULL, NULL, rgba);
00504     char name[64];
00505     sprintf (name, "Stack %d", i);
00506     vtab->setName (name);
00507     vtab->setState (state);
00508     vtab->setCallback (SSG_CALLBACK_PREDRAW,  skydomeimage_predraw);
00509     vtab->setCallback (SSG_CALLBACK_POSTDRAW, skydomeimage_postdraw);
00510 
00511     // Attach leaf to top-level transform
00512     top->addKid (vtab);
00513   }
00514 
00515   // Initialize repaint solar zenith angle
00516   prevTheta = 0;
00517 }
00518 
00519 
00520 CSkyDomeImage::~CSkyDomeImage (void)
00521 {
00522   map<string,SPerezParameters*>::iterator i;
00523   for (i=perez.begin(); i!=perez.end(); i++) {
00524     SPerezParameters *p = i->second;
00525     delete p;
00526   }
00527 }
00528 
00529 
00530 //
00531 // Return the top-level SSG entity for the sky dome
00532 //
00533 ssgEntity*      CSkyDomeImage::GetSSGEntity (void)
00534 {
00535   return top;
00536 }
00537 
00538 
00539 //
00540 // Repaint the sky dome
00541 //
00542 // Input parameters:
00543 //  solTheta    Zenith angle of the sun, radians
00544 //  solPhi      Azimuth angle of the sun, in radians W of S
00545 //
00546 void CSkyDomeImage::Repaint (double solTheta, double solPhi)
00547 {
00548   int i, j;
00549   double thetaThreshold = DegToRad (0.01);
00550 
00551   if (fabs(solTheta - prevTheta) < thetaThreshold) {
00552     // Sun angle has not changed significantly; nothing to do
00553     return;
00554   }
00555   prevTheta = solTheta;
00556 
00557   //
00558   // Perez sky shading is intended for day/dusk only.  Set dome colour to
00559   //   all black, these values will be overwritten with Perez-derived
00560   //   colours if the sun is above astronomical night
00561   float nightTheta = DegToRad (108.0f);   // -18 deg solar elevation
00562 
00563   //
00564   // Step 1 : Calculate new sky dome colours
00565   //
00566 
00567   // TEMP Assume a reasonable value for turbidity, should be based on visibility
00568 
00569   if (solTheta > nightTheta) {
00570     // Sun is below level of astronomical night...set all vertices to black
00571     sgSetVec3 (rgb_zenith, 0, 0, 0);
00572     for (i=0; i<SKYDOME_STACKS; i++) {
00573       for (j=0; j<SKYDOME_SLICES; j++) {
00574         sgSetVec3 (rgb_dome[i][j], 0, 0, 0);
00575       }
00576     }
00577   } else {
00578     // Sun is above level of astronomical night...use Perez equations to compute
00579     //   zenith and dome vertex colours
00580     float turbidity = 4.0;
00581     float r = 0, g = 0, b = 0;
00582 
00583     // Calculate distribution coefficients
00584     SPerezCoefficients cY, cx, cy;
00585     CalcPerezCoefficients (turbidity, perezCurrent->Y_curve, cY);
00586     CalcPerezCoefficients (turbidity, perezCurrent->x_curve, cx);
00587     CalcPerezCoefficients (turbidity, perezCurrent->y_curve, cy);
00588 
00589     // Calculate zenith luminance and chrominance
00590     float Yz = ZenithLuminance (solTheta, turbidity, perezCurrent->Y_zenith);
00591     float xz = ZenithChrominance (solTheta, turbidity, perezCurrent->x_zenith);
00592     float yz = ZenithChrominance (solTheta, turbidity, perezCurrent->y_zenith);
00593 
00594     // Calculate Perez function zenith values for later use
00595     float Ypz = PerezFunction (0, solTheta, cY);
00596     float xpz = PerezFunction (0, solTheta, cx);
00597     float ypz = PerezFunction (0, solTheta, cy);
00598 
00599     // Convert to RGB
00600     YxyToRGB (Yz, xz, yz, &r, &g, &b);
00601 
00602     // Set zenith colour
00603     sgSetVec3 (rgb_zenith, r, g, b);
00604 
00605 // DEBUG
00606 //  char debug[80];
00607 //  sprintf (debug, "Yz = %7.3f xz = %7.3f yz = %7.3f   rz=%7.3f gz=%7.3f bz=%7.3f",
00608 //    Yz, xz, yz, rz, gz, bz);
00609 //  DrawNoticeToUser (debug, 1);
00610 
00611     // Pre-calculate theta and phi steps per dome stack/slice
00612     float dTheta = (SG_PI / 2.0f) / SKYDOME_STACKS;
00613     float dPhi = (SG_PI * 2.0f) / SKYDOME_SLICES;
00614 
00615     // Since sky dome 0th vertex is aligned with sun, the sun vector by
00616     //   definition is at phi=0, regardless of the actual phi angle
00617     //   cos(0) = 1, sin(0) = 0
00618     sgVec3 vSun;
00619     sgSetVec3 (vSun, sin(solTheta), 0, cos(solTheta));
00620 
00621     // Iterate over all dome vertices
00622     for (int i=0; i<SKYDOME_STACKS; i++) {
00623       float domeTheta = (i+1) * dTheta;
00624       for (int j=0; j<SKYDOME_SLICES; j++) {
00625         float domePhi = j * dPhi;
00626 
00627         // Calcualate gamma angle for this point on the dome
00628         sgVec3 vDome;
00629         sgSetVec3 (vDome,
00630                    cos(domePhi) * sin(domeTheta),
00631                    sin(domePhi) * sin(domeTheta),
00632                    cos(domeTheta));
00633         float gamma = DegToRad (sgAngleBetweenVec3 (vSun, vDome));
00634 
00635         // Calculate dome luminance and chrominance
00636         float Yd = Yz * PerezFunction (domeTheta, gamma, cY) / Ypz;
00637         float xd = xz * PerezFunction (domeTheta, gamma, cx) / xpz;
00638         float yd = yz * PerezFunction (domeTheta, gamma, cy) / ypz;
00639 
00640         // Convert to RGB
00641         YxyToRGB (Yd, xd, yd, &r, &g, &b);
00642 
00643         sgSetVec3 (rgb_dome[i][j], r, g, b);
00644       }
00645     }
00646   }
00647 
00648   //
00649   // Step 2 : Apply calculated colours to sky dome
00650   //
00651 
00652   // Apply colour to zenith vertex
00653   ssgVtxTable* vt = (ssgVtxTable*) top->getKid (0);
00654   float *c = vt->getColour (0);
00655   sgSetVec4 (c, rgb_zenith[0], rgb_zenith[1], rgb_zenith[2], 1.0);
00656 
00657   // Apply colours to bottom row of zenith
00658   for (j=0; j<SKYDOME_SLICES; j++) {
00659     c = vt->getColour (j+1);
00660     sgSetVec4 (c, rgb_dome[0][j][0], rgb_dome[0][j][1], rgb_dome[0][j][2], 1.0);
00661   }
00662   c = vt->getColour (SKYDOME_SLICES+1);
00663   sgSetVec4 (c, rgb_dome[0][0][0], rgb_dome[0][0][1], rgb_dome[0][0][2], 1.0);
00664 
00665   // Iterate over stacks
00666   for (i=0; i<SKYDOME_STACKS-1; i++) {
00667     ssgVtxTable *vt = (ssgVtxTable *) top->getKid (i+1);
00668 
00669     // Apply colours top vertices of this stack
00670     for (j=0; j<SKYDOME_SLICES; j++) {
00671       c = vt->getColour (j * 2);
00672       sgSetVec4 (c, rgb_dome[i][j][0], rgb_dome[i][j][1], rgb_dome[i][j][2], 1.0);
00673     }
00674     c = vt->getColour (SKYDOME_SLICES * 2);
00675     sgSetVec4 (c, rgb_dome[i][0][0], rgb_dome[i][0][1], rgb_dome[i][0][2], 1.0);
00676 
00677     // Apply colours to bottom vertices of this stack
00678     for (j=0; j<=SKYDOME_SLICES; j++) {
00679       c = vt->getColour ((j * 2) + 1);
00680       sgSetVec4 (c, rgb_dome[i+1][j][0], rgb_dome[i+1][j][1], rgb_dome[i+1][j][2], 1.0);
00681     }
00682     c = vt->getColour ((SKYDOME_SLICES * 2) + 1);
00683     sgSetVec4 (c, rgb_dome[i+1][0][0], rgb_dome[i+1][0][1], rgb_dome[i+1][0][2], 1.0);
00684   }
00685 
00686 /*
00687   // TEST code to colour sky dome vertices
00688   sgVec4 test;
00689   sgSetVec4 (test, 1.0, 0.0, 0.0, 1.0);
00690 
00691   int ring = 0;
00692   ssgVtxTable *zenith = NULL;
00693   ssgVtxTable *topStack = NULL;
00694   ssgVtxTable *botStack = NULL;
00695 
00696   if (ring == 0) {
00697     zenith = vtZenith;
00698   }
00699 
00700   if (ring < SKYDOME_STACKS-1) {
00701     topStack = vtStack[ring];
00702   }
00703 
00704   if (ring > 0) {
00705     botStack = vtStack[ring-1];
00706   }
00707 
00708   for (int j=0; j<SKYDOME_SLICES; j++) {
00709     // Apply to zenith fan vertices
00710     if (vtZenith != NULL) {
00711       c = vtZenith->getColour (j+1);
00712       sgCopyVec4 (c, test);
00713     }
00714 
00715     // Apply to top vertices of stack
00716     if (topStack != NULL) {
00717       c = topStack->getColour (j * 2);
00718       sgCopyVec4 (c, test);
00719 
00720       if (j==0) {
00721         c = topStack->getColour (SKYDOME_SLICES * 2);
00722         sgCopyVec4 (c, test);
00723       }
00724     }
00725   }
00726 */
00727 }
00728 
00729 
00730 //
00731 // Reposition the sky dome.  The only repositioning required is rotation of the
00732 //   dome so that the 0th vertex of each ring is aligned with the solar azimuth
00733 //
00734 // Input parameters:
00735 //  solAzimuth    Azimuth angle of the sun in radians W of S
00736 //
00737 void CSkyDomeImage::Reposition (double solAzimuth)
00738 {
00739   // Make rotation matrix for sun azimuth angle
00740   sgVec3 axis;
00741   sgSetVec3 (axis, 0, 0, -1);
00742   sgMat4 SPIN;
00743   sgMakeRotMat4 (SPIN, RadToDeg (solAzimuth) - 90, axis);
00744 
00745   // Make top-level transform
00746   sgMat4 T;
00747   sgCopyMat4 (T, SPIN);
00748   top->setTransform (T);
00749 
00750 /*
00751   *** Obsolete sky dome repositioning code to be deleted
00752 
00753   sgMat4 LON, LAT, SPIN;
00754   sgVec3 axis;
00755 
00756   // Rotate for eye position latitude and longitude
00757   sgSetVec3 (axis, 0, 0, 1);
00758   sgMakeRotMat4 (LON, lon, axis);
00759 
00760   sgSetVec3 (axis, 0, 1, 0);
00761   sgMakeRotMat4 (LAT, 90 - lat, axis);
00762 
00763   // Rotate for sun azimuth.  This ensures that the 0th vertex of each ring of the
00764   //   sky dome mesh is aligned with the current sun position, making it easier
00765   //   to apply complex sky dome shading algorithms in the future
00766   sgSetVec3 (axis, 0, 0, 1);
00767   sgMakeRotMat4 (SPIN, spin, axis);
00768 
00769   sgMat4 T;
00770   sgMakeIdentMat4 (T);
00771   sgPreMultMat4 (T, LON);
00772   sgPreMultMat4 (T, LAT);
00773   sgPreMultMat4 (T, SPIN);
00774 
00775   sgCoord skypos;
00776   sgSetCoord (&skypos, T);
00777 
00778   top->setTransform (&skypos);
00779 */
00780 }
00781 
00782 
00783 //
00784 // Dump sky dome attributes to a file for debugging
00785 //
00786 // This is called from the parent CSkyManager class
00787 //
00788 void CSkyDomeImage::Print (FILE *f)
00789 {
00791 
00792   // Display Perez parameter sets
00793   map<string,SPerezParameters*>::iterator i;
00794   for (i=perez.begin(); i!=perez.end(); i++) {
00795     SPerezParameters* p = i->second;
00796 
00797     fprintf (f, "Perez parameter set : %s\n", p->name);
00798     fprintf (f, "  Y (Luminance) curve parameters:\n");
00799     fprintf (f, "    A = %10.8f T + %10.8f\n", p->Y_curve.A[1], p->Y_curve.A[0]);
00800     fprintf (f, "    B = %10.8f T + %10.8f\n", p->Y_curve.B[1], p->Y_curve.B[0]);
00801     fprintf (f, "    C = %10.8f T + %10.8f\n", p->Y_curve.C[1], p->Y_curve.C[0]);
00802     fprintf (f, "    D = %10.8f T + %10.8f\n", p->Y_curve.D[1], p->Y_curve.D[0]);
00803     fprintf (f, "    E = %10.8f T + %10.8f\n", p->Y_curve.E[1], p->Y_curve.E[0]);
00804 
00805     fprintf (f, "  x (Chrominance) curve parameters:\n");
00806     fprintf (f, "    A = %10.8f T + %10.8f\n", p->x_curve.A[1], p->x_curve.A[0]);
00807     fprintf (f, "    B = %10.8f T + %10.8f\n", p->x_curve.B[1], p->x_curve.B[0]);
00808     fprintf (f, "    C = %10.8f T + %10.8f\n", p->x_curve.C[1], p->x_curve.C[0]);
00809     fprintf (f, "    D = %10.8f T + %10.8f\n", p->x_curve.D[1], p->x_curve.D[0]);
00810     fprintf (f, "    E = %10.8f T + %10.8f\n", p->x_curve.E[1], p->x_curve.E[0]);
00811 
00812     fprintf (f, "  y (Chrominance) curve parameters:\n");
00813     fprintf (f, "    A = %10.8f T + %10.8f\n", p->y_curve.A[1], p->y_curve.A[0]);
00814     fprintf (f, "    B = %10.8f T + %10.8f\n", p->y_curve.B[1], p->y_curve.B[0]);
00815     fprintf (f, "    C = %10.8f T + %10.8f\n", p->y_curve.C[1], p->y_curve.C[0]);
00816     fprintf (f, "    D = %10.8f T + %10.8f\n", p->y_curve.D[1], p->y_curve.D[0]);
00817     fprintf (f, "    E = %10.8f T + %10.8f\n", p->y_curve.E[1], p->y_curve.E[0]);
00818 
00819     fprintf (f, "  Y (Luminance) zenith parameters:\n");
00820     fprintf (f, "    A = %10.8f\n", p->Y_zenith.A);
00821     fprintf (f, "    B = %10.8f\n", p->Y_zenith.B);
00822     fprintf (f, "    C = %10.8f\n", p->Y_zenith.C);
00823     fprintf (f, "    D = %10.8f\n", p->Y_zenith.D);
00824 
00825     fprintf (f, "  x (Chrominance) zenith parameters:\n");
00826     fprintf (f, "      theta^3 (%10.8f T^2 + %10.8f T + %10.8f\n",
00827       p->x_zenith.t2[3], p->x_zenith.t1[3], p->x_zenith.t0[3]);
00828     fprintf (f, "    + theta^2 (%10.8f T^2 + %10.8f T + %10.8f\n",
00829       p->x_zenith.t2[2], p->x_zenith.t1[2], p->x_zenith.t0[2]);
00830     fprintf (f, "    + theta   (%10.8f T^2 + %10.8f T + %10.8f\n",
00831       p->x_zenith.t2[1], p->x_zenith.t1[1], p->x_zenith.t0[1]);
00832     fprintf (f, "    +         (%10.8f T^2 + %10.8f T + %10.8f\n",
00833       p->x_zenith.t2[0], p->x_zenith.t1[0], p->x_zenith.t0[0]);
00834 
00835     fprintf (f, "  y (Chrominance) zenith parameters:\n");
00836     fprintf (f, "      theta^3 (%10.8f T^2 + %10.8f T + %10.8f\n",
00837       p->y_zenith.t2[3], p->y_zenith.t1[3], p->y_zenith.t0[3]);
00838     fprintf (f, "    + theta^2 (%10.8f T^2 + %10.8f T + %10.8f\n",
00839       p->y_zenith.t2[2], p->y_zenith.t1[2], p->y_zenith.t0[2]);
00840     fprintf (f, "    + theta   (%10.8f T^2 + %10.8f T + %10.8f\n",
00841       p->y_zenith.t2[1], p->y_zenith.t1[1], p->y_zenith.t0[1]);
00842     fprintf (f, "    +         (%10.8f T^2 + %10.8f T + %10.8f\n",
00843       p->y_zenith.t2[0], p->y_zenith.t1[0], p->y_zenith.t0[0]);
00844 
00845     fprintf (f, "\n");
00846   }
00847 }
00848 
SourceForge.net Logo Documentation generated by doxygen