src/utility.cpp

Go to the documentation of this file.
00001 /* vim: set noexpandtab shiftwidth=8 cino= fo+=awc:
00002  ***************************************************************************
00003  *            utility.cc
00004  *
00005  *  Sat Mar 26 08:52:54 2005
00006  *  Copyright  2005  Joe Venzon
00007  *  joe@venzon.net
00008  ****************************************************************************/
00009 
00010 /*
00011  *  This program is free software; you can redistribute it and/or modify
00012  *  it under the terms of the GNU General Public License as published by
00013  *  the Free Software Foundation; either version 2 of the License, or
00014  *  (at your option) any later version.
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  You should have received a copy of the GNU General Public License
00022  *  along with this program; if not, write to the Free Software
00023  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00024  */
00025 
00026 #define GL_GLEXT_PROTOTYPES
00027 
00028 #include "utility.h"
00029 #include "textures.h"
00030 #include <fstream>
00031 
00032 #ifdef _WIN32
00033 //#define GL_GLEXT_PROTOTYPES
00034 #include <GL/glext.h>
00035 #include <GL/glut.h>
00036 //#include <GL/wglext.h>
00037 //#include <GL/glprocs.h>
00038 #include <windows.h>
00039 #endif
00040 
00041 #ifdef _WIN32
00042 PFNGLMULTITEXCOORD2FARBPROC     pglMultiTexCoord2f     = NULL;
00043 PFNGLMULTITEXCOORD4FARBPROC     pglMultiTexCoord4f     = NULL;
00044 PFNGLCLIENTACTIVETEXTUREARBPROC pglActiveTexture       = NULL;
00045 PFNGLACTIVETEXTUREARBPROC       pglClientActiveTexture = NULL;
00046 #endif
00047 
00048 //includes needed to get folder contents
00049 #ifndef _WIN32
00050 #include <sys/types.h>
00051 #include <dirent.h>
00052 #endif
00053 
00054 const float DEG2RAD = 3.14159 / 180.0;
00055 
00056 void UTILITY::SelectTU(int TU)
00057 {
00058         if (!initdone)
00059         {
00060             initerror();
00061             return;
00062         }
00063 
00064         GLenum tuenum;
00065         
00066         if (TU == 0)
00067                 tuenum = GL_TEXTURE0_ARB;
00068         else if (TU == 1)
00069                 tuenum = GL_TEXTURE1_ARB;
00070         else if (TU == 2)
00071                 tuenum = GL_TEXTURE2_ARB;
00072         else if (TU == 3)
00073                 tuenum = GL_TEXTURE3_ARB;
00074         else
00075                 tuenum = GL_TEXTURE0_ARB;
00076         
00077         #ifdef _WIN32
00078         pglActiveTexture(tuenum);
00079         #else
00080         glActiveTextureARB(tuenum);
00081         #endif
00082 }
00083 
00084 void UTILITY::TexCoord2d2f(int TU, float u, float v)
00085 {
00086         if (!initdone)
00087         {
00088             initerror();
00089             return;
00090         }
00091 
00092         GLenum tuenum;
00093         
00094         if (TU+1 > nb_multitexture)
00095                 return;
00096         
00097         if (TU == 0)
00098                 tuenum = GL_TEXTURE0_ARB;
00099         else if (TU == 1)
00100                 tuenum = GL_TEXTURE1_ARB;
00101         else if (TU == 2)
00102                 tuenum = GL_TEXTURE2_ARB;
00103         else if (TU == 3)
00104                 tuenum = GL_TEXTURE3_ARB;
00105         else
00106                 tuenum = GL_TEXTURE0_ARB;
00107         
00108         #ifdef _WIN32
00109         pglMultiTexCoord2f(tuenum, u, v);
00110         #else
00111         glMultiTexCoord2fARB(tuenum, u, v);
00112         #endif
00113 }
00114 
00115 GLuint UTILITY::TexLoad(string filename, int format, bool mipmap, int &w, int &h, const bool supressederror, bool &err)
00116 {
00117         return TexLoad(filename, format, mipmap, w, h, supressederror, err, 0);
00118 }
00119 
00120 GLuint UTILITY::TexLoad(string filename, int format, bool mipmap, int &w, int &h, const bool supressederror, bool &err, int attempt)
00121 {
00122         string filepath;
00123         string texture_size;
00124         char buffer[1024];
00125         //filepath = DATA_DIR + "/tex/" + filename;
00126         settings.Get( "display.texture_size", texture_size );
00127 
00128         switch (attempt)
00129         {
00130                 case 0:
00131                         filepath = filename;
00132                         break;
00133                 
00134                 case 1:
00135                         filepath = settings.GetFullDataPath(filename);
00136                         break;
00137                 
00138                 case 2:
00139                         filepath = settings.GetFullDataPath("textures/" + texture_size + "/" + filename);
00140                         break;
00141                 
00142                 default:
00143                         filepath = filename;
00144                         break;
00145         }
00146 
00147         //cout << "Trying to load texture " << filepath << endl;
00148         
00149         strcpy(buffer, filepath.c_str());
00150         
00151         GLuint new_handle = 0;
00152         
00153         //*** Load Texture ***
00154         SDL_Surface *TextureImage[1];                                   // Create Storage Space For The Texture
00155 
00156         // Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
00157         if ((TextureImage[0]=IMG_Load(buffer)))
00158         {
00159                 //SDL_SetAlpha(TextureImage[0], 0, 0);
00160                 
00161                 w = TextureImage[0]->w;
00162                 h = TextureImage[0]->h;
00163                 
00164                 switch (TextureImage[0]->format->BytesPerPixel)
00165                 {
00166                         case 1:
00167                                 format = GL_LUMINANCE;
00168                                 break;
00169                         case 2:
00170                                 format = GL_LUMINANCE_ALPHA;
00171                                 break;
00172                         case 3:
00173                                 format = GL_RGB;
00174                                 break;
00175                         case 4:
00176                                 format = GL_RGBA;
00177                                 break;
00178                         default:
00179                                 break;
00180                 }
00181                 
00182                 glGenTextures(1, &new_handle);                                  // Create Texture
00183                 
00184                 // Create MipMapped Texture
00185                 glBindTexture(GL_TEXTURE_2D, new_handle);
00186                 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
00187                 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
00188                 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
00189                 
00190                 if (mipmap)
00191                 {
00192                         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
00193                         gluBuild2DMipmaps( GL_TEXTURE_2D, format, TextureImage[0]->w, TextureImage[0]->h, format, GL_UNSIGNED_BYTE, TextureImage[0]->pixels );
00194                 }
00195                 else
00196                 {
00197                         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
00198                         glTexImage2D( GL_TEXTURE_2D, 0, format, TextureImage[0]->w, TextureImage[0]->h, 0, format, GL_UNSIGNED_BYTE, TextureImage[0]->pixels );
00199                 }
00200                 
00201                 //check for anisotropy
00202                 int anisotropy = 0;
00203                 settings.Get( "display.anisotropic", anisotropy );
00204                 if (gfxcard.GetCapability(CARDINFOTYPE::ANISOTROPY) && anisotropy > 0)
00205                 {
00206                         //enable maximum anisotropy
00207                         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)anisotropy);
00208                 }
00209                 
00210                 err = false;
00211         }
00212         else
00213         {
00214                 /*err = true;
00215                 
00216             //try once more
00217                 //cout << "initially failed: " << buffer << endl;
00218                 int try2 = -1;
00219                 if (filepath.find(settings.GetDataDir() + "/textures") > filepath.length())
00220                 {
00221                         try2 = TexLoad(settings.GetFullDataPath("textures/" + settings.GetTexSize() + "/" + filepath), format, mipmap, w, h, supressederror, err);
00222                 }
00223                 //quit, bitmap not found
00224                 if (err)
00225                 {
00226                         if (!supressederror) error_log << "Could not find texture: " << buffer << "\n";
00227                         return 0;
00228                 }
00229                 else
00230                 {
00231                         err = false;
00232                         return try2;
00233                 }*/
00234                 
00235                 attempt++;
00236                 
00237                 if (attempt > 2)
00238                 {
00239                         err = true;
00240                         if (!supressederror) error_log << "Could not find texture: " << filename << "\n";
00241                         return 0;
00242                 }
00243                 else
00244                 {
00245                         return TexLoad(filename, format, mipmap, w, h, supressederror, err, attempt);
00246                 }
00247         }
00248 
00249         if (TextureImage[0]) // If Texture Exists
00250         {
00251                 // Free up any memory we may have used
00252                 SDL_FreeSurface( TextureImage[0] );
00253         }
00254         
00255         return new_handle;
00256 }
00257 
00258 GLuint UTILITY::TexLoad(string texfile, bool mipmap)
00259 {
00260         return TexLoad(texfile, GL_RGBA, mipmap);
00261 }
00262 
00263 GLuint UTILITY::TexLoad(string filename, int format, bool mipmap)
00264 {
00265         int dw, dh, new_handle;
00266         bool err = false;
00267         
00268         new_handle = TexLoad(filename, format, mipmap, dw, dh, false, err);
00269         
00270         return new_handle;
00271 }
00272 
00273 UTILITY::UTILITY()
00274 {
00275         error_log.open((settings.GetSettingsDir() + "/logs/utility.log").c_str());
00276         initdone = false;
00277 }
00278 
00279 extern bool verbose_output;
00280 UTILITY::~UTILITY()
00281 {
00282         if (verbose_output)
00283                 cout << "utility deinit" << endl;
00284         
00285         error_log.close();
00286 }
00287 
00288 void UTILITY::Init()
00289 {
00290         //cout << "utility init test" << endl;
00291 
00292 #ifdef _WIN32
00293         pglMultiTexCoord4f = (PFNGLMULTITEXCOORD4FARBPROC) wglGetProcAddress("glMultiTexCoord4fARB");
00294         pglMultiTexCoord2f = (PFNGLMULTITEXCOORD2FARBPROC) wglGetProcAddress("glMultiTexCoord2fARB");
00295         pglActiveTexture = (PFNGLCLIENTACTIVETEXTUREARBPROC) wglGetProcAddress("glActiveTextureARB");
00296         pglClientActiveTexture = (PFNGLACTIVETEXTUREARBPROC) wglGetProcAddress("glClientActiveTextureARB");
00297         
00298         if (pglMultiTexCoord4f == NULL)
00299                 error_log << "main, WIN32: wglGetProcAddress(\"glMultiTexCoord4fARB\") failed." << endl;
00300         if (pglMultiTexCoord2f == NULL)
00301                 error_log << "main, WIN32: wglGetProcAddress(\"glMultiTexCoord2fARB\") failed." << endl;
00302         if (pglActiveTexture == NULL)
00303                 error_log << "main, WIN32: wglGetProcAddress(\"glActiveTextureARB\") failed." << endl;
00304         if (pglClientActiveTexture == NULL)
00305                 error_log << "main, WIN32: wglGetProcAddress(\"glClientActiveTextureARB\") failed." << endl;
00306                 
00307                 //cout << "utility init test" << endl;
00308 #endif
00309 
00310 
00311         glGetIntegerv( GL_MAX_TEXTURE_UNITS_ARB,&nb_multitexture );
00312         
00313         //nb_multitexture = 2;
00314         
00315         cout << "Multitexture units (4 are required for all effects): " << nb_multitexture << endl;
00316         if (nb_multitexture < 2)
00317                 cout << "You have less than the recommended number of texture units." << endl << "Some effects will not be rendered." << endl << "Upgrade your graphics card!" << endl;
00318         else if (nb_multitexture <= 3)
00319                 cout << "You have less than the recommended number of texture units." << endl << "Some textures will lack detail." << endl << "Upgrade your graphics card!" << endl;
00320         else
00321                 cout << "Your GPU meets the texture unit requirements." << endl;
00322         
00323         cout << endl << "Note to user:  All error messages will be put in " + settings.GetSettingsDir() + "/logs/." << endl;
00324 
00325         initdone = true;
00326 }
00327 
00328 string UTILITY::sGetLine(ifstream &ffrom)
00329 {
00330         string trashstr;
00331         char trashchar[1024];
00332 
00333         //ffrom >> trashstr;
00334         ffrom.getline(trashchar,1024,'\n');
00335 
00336         while ((trashchar[0] == '#' || strlen(trashchar) <= 1 ) && !ffrom.eof())
00337         {
00338                 ffrom.getline(trashchar, 1024, '\n');
00339                 //ffrom >> trashstr;
00340                 //ffrom.getline(trashchar,1024,'\n');
00341         }
00342         trashstr = trashchar;
00343 
00344         if (ffrom.eof() && trashstr.length() == 0)
00345                 return ENDOFFILESTRING;
00346         else
00347                 return trashstr;
00348 }
00349 
00350 string UTILITY::sGetParam(ifstream &ffrom)
00351 {
00352         string trashstr;
00353         char trashchar[1024];
00354 
00355         ffrom >> trashstr;
00356 
00357         while (trashstr.c_str()[0] == '#' && !ffrom.eof() && trashstr != "")
00358         {
00359                 ffrom.getline(trashchar, 1024, '\n');
00360                 ffrom >> trashstr;
00361         }
00362         
00363         if (ffrom.eof() && trashstr.c_str()[0] == '#')
00364                 return ENDOFFILESTRING;
00365         else
00366                 return trashstr;
00367 }
00368 
00369 int UTILITY::iGetParam(ifstream &ffrom)
00370 {
00371         string trashstr;
00372         char trashchar[1024];
00373 
00374         ffrom >> trashstr;
00375 
00376         while (trashstr.c_str()[0] == '#' && !ffrom.eof())
00377         {
00378                 ffrom.getline(trashchar, 1024, '\n');
00379                 ffrom >> trashstr;
00380         }
00381 
00382         return atoi(trashstr.c_str());
00383 }
00384 
00385 float UTILITY::fGetParam(ifstream &ffrom)
00386 {
00387         string trashstr;
00388         char trashchar[1024];
00389 
00390         ffrom >> trashstr;
00391 
00392         while (trashstr.c_str()[0] == '#' && !ffrom.eof())
00393         {
00394                 ffrom.getline(trashchar, 1024, '\n');
00395                 ffrom >> trashstr;
00396         }
00397 
00398         return atof(trashstr.c_str());
00399 }
00400 
00401 void UTILITY::initerror()
00402 {
00403         //error_log << "Utility library not yet initialized" << endl;
00404 }
00405 
00406 void UTILITY::Tex2D(int TU, bool enable)
00407 {
00408         if (!initdone)
00409         {
00410             initerror();
00411             return;
00412         }
00413 
00414         SelectTU(TU);
00415         if (enable)
00416                 glEnable(GL_TEXTURE_2D);
00417         else
00418                 glDisable(GL_TEXTURE_2D);
00419 }
00420 
00421 bool UTILITY::bGetParam(ifstream &ffrom)
00422 {
00423         string trashstr;
00424         char trashchar[1024];
00425 
00426         ffrom >> trashstr;
00427 
00428         while (trashstr.c_str()[0] == '#' && !ffrom.eof())
00429         {
00430                 ffrom.getline(trashchar, 1024, '\n');
00431                 ffrom >> trashstr;
00432         }
00433         
00434         if (trashstr == "true" || trashstr == "1" || trashstr == "on")
00435                 return true;
00436         else
00437                 return false;
00438 }
00439 
00440 int UTILITY::numTUs()
00441 {
00442         if (!initdone)
00443         {
00444             initerror();
00445             return 0;
00446         }
00447         
00448         return nb_multitexture;
00449 }
00450 
00451 void UTILITY::Draw2D(float x1, float y1, float x2, float y2, TEXTURE_HANDLE * texid)
00452 {
00453         Draw2D(x1, y1, x2, y2, texid, 0.0);
00454 }
00455 
00456 void UTILITY::Draw2D(float x1, float y1, float x2, float y2, TEXTURE_HANDLE * texid, float rotation)
00457 {
00458         Draw2D(x1, y1, x2, y2, texid, rotation, 0);
00459 }
00460 
00461 void UTILITY::Draw2D(float x1, float y1, float x2, float y2, TEXTURE_HANDLE * texid, float rotation, int texsize)
00462 {
00463         Draw2D(x1, y1, x2, y2, texid, rotation, texsize, 1.0);
00464 }
00465 
00466 void UTILITY::Draw2D(float x1, float y1, float x2, float y2, TEXTURE_HANDLE * texid, float rotation, int texsize, float opacity)
00467 {
00468         int sx, sy;
00469         
00470         QUATERNION rot;
00471         rot.Rotate(rotation, 0,0,1);
00472         
00473         glPushAttrib(GL_ALL_ATTRIB_BITS);
00474         Tex2D(0, true);
00475         
00476         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
00477         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
00478 
00479         sx = 1600;
00480         sy = 1200;
00481         
00482         int x = (int) (x1*(float)sx);
00483         int y = (int) ((1.0-y1)*(float)sy);
00484         
00485         int w = (int) ((x2-x1)*(float)sx);
00486         int h = (int) ((y2-y1)*(float)sy);
00487 
00488         // Select our texture
00489         //glBindTexture( GL_TEXTURE_2D, texid );
00490         texid->Activate();
00491 
00492         // Disable depth testing 
00493         glDisable( GL_DEPTH_TEST );
00494         //and lighting...
00495         glDisable( GL_LIGHTING);
00496         glBlendFunc( GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR);
00497         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00498         glEnable( GL_BLEND );
00499 
00500         // Select The Projection Matrix
00501         glMatrixMode( GL_PROJECTION );
00502         // Store The Projection Matrix
00503         glPushMatrix( );
00504 
00505         // Reset The Projection Matrix 
00506         glLoadIdentity( );
00507         // Set Up An Ortho Screen 
00508         glOrtho( 0, sx, 0, sy, -1, 1 );
00509 
00510         // Select The Modelview Matrix
00511         glMatrixMode( GL_MODELVIEW );
00512         // Stor the Modelview Matrix
00513         glPushMatrix( );
00514         // Reset The Modelview Matrix
00515         glLoadIdentity( );
00516 
00517         // Position The Text (0,0 - Bottom Left)
00518         glTranslated( x, y, 0 );
00519 
00520         /*// Choose The Font Set (0 or 1)
00521         glListBase( base - 32 + ( 128 * set ) );
00522 
00523         // Write The Text To The Screen
00524         glCallLists( strlen( string ), GL_BYTE, string );*/
00525         
00526         //glColor3f(1,1,1);
00527         glColor4f(1,1,1,opacity);
00528         
00529         /*for (unsigned int i = 0; i < strlen(string); i++)
00530         {
00531                 if (string[i] == 32)
00532                         glTranslated( 10, 0, 0 );
00533                 else if (string[i] == '\n')
00534                 {
00535                         num_crs++;
00536                         glLoadIdentity( );
00537                         glTranslated(x,y-20*num_crs,0);
00538                 }
00539                 else
00540                 {
00541                         int pos = base - 32 + (128*set) + string[i];
00542                         if (pos < 0)
00543                                 pos = 0;
00544                         glCallList(pos);
00545                 }
00546         }*/
00547         
00548         VERTEX v[4];
00549         v[0].Set(0,0,0);
00550         v[1].Set(w,0,0);
00551         v[2].Set(w,-h,0);
00552         v[3].Set(0,-h,0);
00553         
00554         int i;
00555         
00556         for (i = 0; i < 4; i++)
00557         {
00558                 v[i].x -= w/2.0;
00559                 v[i].y += h/2.0;
00560         }
00561         
00562         for (i = 0; i < 4; i++)
00563                 v[i] = rot.RotateVec(v[i]);
00564         
00565         for (i = 0; i < 4; i++)
00566         {
00567                 v[i].x += w/2.0;
00568                 v[i].y -= h/2.0;
00569         }
00570 
00571         float tmin, tmax;
00572         tmin = 0;
00573         tmax = 1;
00574         if (texsize > 0)
00575         {
00576                 tmin = 1.0/(float)texsize;
00577                 tmax = ((float)texsize-1.0)/(float)texsize;
00578         }
00579 
00580         //draw box
00581         glBegin( GL_QUADS );
00582                 /* Texture Coord (Bottom Left) */
00583                 glTexCoord2f( tmin, tmin);
00584                 /* Vertex Coord (Bottom Left) */
00585                 glVertex2f( v[0].x, v[0].y );
00586 
00587                 /* Texture Coord (Bottom Right) */
00588                 glTexCoord2f( tmax, tmin);
00589                 /* Vertex Coord (Bottom Right) */
00590                 glVertex2f( v[1].x, v[1].y );
00591 
00592                 /* Texture Coord (Top Right) */
00593                 glTexCoord2f( tmax, tmax);
00594                 /* Vertex Coord (Top Right) */
00595                 glVertex2f( v[2].x, v[2].y );
00596 
00597                 /* Texture Coord (Top Left) */
00598                 glTexCoord2f( tmin, tmax);
00599                 /* Vertex Coord (Top Left) */
00600                 glVertex2f( v[3].x, v[3].y );
00601         glEnd( );
00602 
00603         // Select The Projection Matrix
00604         glMatrixMode( GL_PROJECTION );
00605         // Restore The Old Projection Matrix
00606         glPopMatrix( );
00607         
00608         // Select the Modelview Matrix
00609         glMatrixMode( GL_MODELVIEW );
00610         // Restore the Old Projection Matrix
00611         glPopMatrix( );
00612 
00613         // Re-enable Depth Testing
00614         glEnable( GL_DEPTH_TEST );
00615         //and lighting...
00616         glEnable( GL_LIGHTING);
00617         glDisable(GL_BLEND);
00618         
00619         glPopAttrib();
00620 }
00621 
00622 void UTILITY::DrawEllipse( float center_x, float center_y, float radius_x, float radius_y, float color_r, float color_g, float color_b, float opacity )
00623 {
00624         int sx = 1600;
00625         int sy = 1200;
00626         int x = (int)( center_x * (float)sx );
00627         int y = (int)( ( 1.0 - center_y ) * (float)sy );
00628 
00629         glLoadIdentity();
00630         glTranslated( x, y, 0 );
00631         glColor4f( color_r, color_g, color_b, opacity );
00632 
00633         glBegin( GL_LINE_LOOP );
00634 
00635         for( int i = 0; i < 360; i++ )
00636         {
00637                 //convert degrees into radians
00638                 float rad = i * DEG2RAD;
00639                 glVertex2f( cos( rad ) * radius_x, sin( rad ) * radius_y );
00640         }
00641 
00642         glEnd();
00643 }
00644 
00645 float UTILITY::GetValue(SDL_Surface * surf, int channel, float x, float y, bool interpolate)
00646 {
00647         return GetValue(surf, channel, x, y, interpolate, false);
00648 }
00649 
00650 float UTILITY::GetValue(SDL_Surface * surf, int channel, float x, float y, bool interpolate, bool wrap)
00651 {
00652         //check for NANs
00653         if (!(x < 0 || x >= 0) || !(y < 0 || y >= 0))
00654                 return 0;
00655         
00656         if (channel >= surf->format->BytesPerPixel || channel < 0)
00657         {
00658                 error_log << "Asked for channel " << channel << ", image only has " << surf->format->BytesPerPixel << endl;
00659                 channel = surf->format->BytesPerPixel - 1;
00660         }
00661         
00662         {
00663                 if (x < 0)
00664                         x = 0;
00665                 if (x > 1)
00666                         x = 1;
00667                 if (y < 0)
00668                         y = 0;
00669                 if (y > 1)
00670                         y = 1;
00671                 int ix, iy;
00672                 ix = (int)(x * surf->w);
00673                 iy = (int)(y * surf->h);
00674                 float dx, dy;
00675                 dx = x - ix;
00676                 dy = y - iy;
00677                 
00678                 unsigned char * pix;
00679                 pix = (unsigned char *) surf->pixels;
00680                 
00681                 if (ix >= surf->w)
00682                 {
00683                         if (wrap)
00684                                 ix = ix % surf->w;
00685                         else
00686                                 ix = surf->w - 1;
00687                 }
00688                 if (iy >= surf->h)
00689                 {
00690                         if (wrap)
00691                                 iy = iy % surf->h;
00692                         else
00693                                 iy = surf->h - 1;
00694                 }
00695                 
00696                 if (!interpolate)
00697                 {
00698                         return pix[(ix+surf->pitch*iy)*surf->format->BytesPerPixel+channel] / 255.0f;
00699                 }
00700                 else
00701                 {
00702                         float ul, ur, ll, lr;
00703                         
00704                         int rx, ry;
00705                         
00706                         rx = ix + 1;
00707                         if (rx >= surf->w)
00708                         {
00709                                 if (wrap)
00710                                         rx = rx % surf->w;
00711                                 else
00712                                         rx = ix;
00713                         }
00714                         
00715                         ry = iy + 1;
00716                         if (ry >= surf->h)
00717                         {
00718                                 if (wrap)
00719                                         ry = ry % surf->h;
00720                                 else
00721                                         ry = iy;
00722                         }
00723                         
00724                         rx = ix;
00725                         ry = iy;
00726                         
00727                         ul = pix[(ix+surf->pitch*iy)*surf->format->BytesPerPixel+channel] / 255.0f;
00728                         ur = pix[(rx+surf->pitch*iy)*surf->format->BytesPerPixel+channel] / 255.0f;
00729                         ll = pix[(ix+surf->pitch*ry)*surf->format->BytesPerPixel+channel] / 255.0f;
00730                         lr = pix[(rx+surf->pitch*ry)*surf->format->BytesPerPixel+channel] / 255.0f;
00731                         
00732                         float u, l;
00733                         
00734                         u = ul*(1.0-dx)+ur*dx;
00735                         l = ll*(1.0-dx)+lr*dx;
00736                         
00737                         return u*(1.0-dy)+l*dy;
00738                 }
00739         }
00740 }
00741 
00742 bool UTILITY::FileExists(string filename)
00743 {
00744         ifstream test;
00745         test.open(filename.c_str());
00746         if (test)
00747         {
00748                 test.close();
00749                 return true;
00750         }
00751         else
00752                 return false;
00753 }
00754 
00755 int UTILITY::IntersectTriangleD(double orig[3], double dir[3],
00756                    double vert0[3], double vert1[3], double vert2[3],
00757                    double *t, double *u, double *v)
00758 {
00759    double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
00760    double det,inv_det;
00761 
00762    /* find vectors for two edges sharing vert0 */
00763    SUB(edge1, vert1, vert0);
00764    SUB(edge2, vert2, vert0);
00765 
00766    /* begin calculating determinant - also used to calculate U parameter */
00767    CROSS(pvec, dir, edge2);
00768 
00769    /* if determinant is near zero, ray lies in plane of triangle */
00770    det = DOT(edge1, pvec);
00771 
00772 #ifdef TEST_CULL           /* define TEST_CULL if culling is desired */
00773    if (det < EPSILON)
00774       return 0;
00775 
00776    /* calculate distance from vert0 to ray origin */
00777    SUB(tvec, orig, vert0);
00778 
00779    /* calculate U parameter and test bounds */
00780    *u = DOT(tvec, pvec);
00781    if (*u < 0.0 || *u > det)
00782       return 0;
00783 
00784    /* prepare to test V parameter */
00785    CROSS(qvec, tvec, edge1);
00786 
00787     /* calculate V parameter and test bounds */
00788    *v = DOT(dir, qvec);
00789    if (*v < 0.0 || *u + *v > det)
00790       return 0;
00791 
00792    /* calculate t, scale parameters, ray intersects triangle */
00793    *t = DOT(edge2, qvec);
00794    inv_det = 1.0 / det;
00795    *t *= inv_det;
00796    *u *= inv_det;
00797    *v *= inv_det;
00798 #else                    /* the non-culling branch */
00799    if (det > -EPSILON && det < EPSILON)
00800      return 0;
00801    inv_det = 1.0 / det;
00802 
00803    /* calculate distance from vert0 to ray origin */
00804    SUB(tvec, orig, vert0);
00805 
00806    /* calculate U parameter and test bounds */
00807    *u = DOT(tvec, pvec) * inv_det;
00808    if (*u < 0.0 || *u > 1.0)
00809      return 0;
00810 
00811    /* prepare to test V parameter */
00812    CROSS(qvec, tvec, edge1);
00813 
00814    /* calculate V parameter and test bounds */
00815    *v = DOT(dir, qvec) * inv_det;
00816    if (*v < 0.0 || *u + *v > 1.0)
00817      return 0;
00818 
00819    /* calculate t, ray intersects triangle */
00820    *t = DOT(edge2, qvec) * inv_det;
00821 #endif
00822    return 1;
00823 }
00824 
00825 int UTILITY::IntersectTriangleF(float orig[3], float dir[3],
00826                    float vert0[3], float vert1[3], float vert2[3],
00827                    float *t, float *u, float *v)
00828 {
00829    float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
00830    float det,inv_det;
00831 
00832    /* find vectors for two edges sharing vert0 */
00833    SUB(edge1, vert1, vert0);
00834    SUB(edge2, vert2, vert0);
00835 
00836    /* begin calculating determinant - also used to calculate U parameter */
00837    CROSS(pvec, dir, edge2);
00838 
00839    /* if determinant is near zero, ray lies in plane of triangle */
00840    det = DOT(edge1, pvec);
00841 
00842 #ifdef TEST_CULL           /* define TEST_CULL if culling is desired */
00843    if (det < EPSILON)
00844       return 0;
00845 
00846    /* calculate distance from vert0 to ray origin */
00847    SUB(tvec, orig, vert0);
00848    
00849    /* calculate U parameter and test bounds */
00850    *u = DOT(tvec, pvec);
00851    if (*u < 0.0 || *u > det)
00852       return 0;
00853 
00854    /* prepare to test V parameter */
00855    CROSS(qvec, tvec, edge1);
00856 
00857     /* calculate V parameter and test bounds */
00858    *v = DOT(dir, qvec);
00859    if (*v < 0.0 || *u + *v > det)
00860       return 0;
00861 
00862    /* calculate t, scale parameters, ray intersects triangle */
00863    *t = DOT(edge2, qvec);
00864    inv_det = 1.0 / det;
00865    *t *= inv_det;
00866    *u *= inv_det;
00867    *v *= inv_det;
00868 #else                    /* the non-culling branch */
00869    if (det > -EPSILON && det < EPSILON)
00870      return 0;
00871    inv_det = 1.0 / det;
00872 
00873    /* calculate distance from vert0 to ray origin */
00874    SUB(tvec, orig, vert0);
00875 
00876    /* calculate U parameter and test bounds */
00877    *u = DOT(tvec, pvec) * inv_det;
00878    if (*u < 0.0 || *u > 1.0)
00879      return 0;
00880 
00881    /* prepare to test V parameter */
00882    CROSS(qvec, tvec, edge1);
00883 
00884    /* calculate V parameter and test bounds */
00885    *v = DOT(dir, qvec) * inv_det;
00886    if (*v < 0.0 || *u + *v > 1.0)
00887      return 0;
00888 
00889    /* calculate t, ray intersects triangle */
00890    *t = DOT(edge2, qvec) * inv_det;
00891 #endif
00892    if (isNaN(*u) || isNaN(*v) || isNaN(*t))
00893            return 0;
00894    return 1;
00895 }
00896 
00897 void UTILITY::DrawButton(float x1, float y1, float x2, float y2, float sidewidth, TEXTURE_HANDLE * texid, float opacity)
00898 {
00899         int sx, sy;
00900         
00901         /*QUATERNION rot;
00902         rot.Rotate(rotation, 0,0,1);*/
00903         
00904         glPushAttrib(GL_ALL_ATTRIB_BITS);
00905         
00906         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
00907         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
00908         
00909         sx = 1600;
00910         sy = 1200;
00911         
00912         int x = (int) (x1*(float)sx);
00913         int y = (int) ((1.0-y1)*(float)sy);
00914         
00915         int w = (int) ((x2-x1)*(float)sx);
00916         int h = (int) ((y2-y1)*(float)sy);
00917         
00918         int sw = (int) (sidewidth * (float) sx);
00919 
00920         // Select our texture
00921         //glBindTexture( GL_TEXTURE_2D, texid );
00922         texid->Activate();
00923 
00924         // Disable depth testing 
00925         glDisable( GL_DEPTH_TEST );
00926         //and lighting...
00927         glDisable( GL_LIGHTING);
00928         glBlendFunc( GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR);
00929         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00930         glEnable( GL_BLEND );
00931 
00932         // Select The Projection Matrix
00933         glMatrixMode( GL_PROJECTION );
00934         // Store The Projection Matrix
00935         glPushMatrix( );
00936 
00937         // Reset The Projection Matrix 
00938         glLoadIdentity( );
00939         // Set Up An Ortho Screen 
00940         glOrtho( 0, sx, 0, sy, -1, 1 );
00941 
00942         // Select The Modelview Matrix
00943         glMatrixMode( GL_MODELVIEW );
00944         glPushMatrix( );
00945         glLoadIdentity( );
00946         glTranslated( x, y, 0 );
00947         glColor4f(1,1,1,opacity);
00948         
00949         VERTEX v[4];
00950         v[0].Set(0,0,0);
00951         v[1].Set(sw,0,0);
00952         v[2].Set(sw,-h,0);
00953         v[3].Set(0,-h,0);
00954         
00955         glTranslated(-sw, 0, 0);
00956         
00957         //draw left side
00958         glBegin( GL_QUADS );
00959                 /* Texture Coord (Bottom Left) */
00960                 glTexCoord2f( 0, 0);
00961                         /* Vertex Coord (Bottom Left) */
00962                         glVertex2f( v[0].x, v[0].y );
00963         
00964                         /* Texture Coord (Bottom Right) */
00965                         glTexCoord2f( 0.5, 0);
00966                         /* Vertex Coord (Bottom Right) */
00967                         glVertex2f( v[1].x, v[1].y );
00968         
00969                         /* Texture Coord (Top Right) */
00970                         glTexCoord2f( 0.5, 1);
00971                         /* Vertex Coord (Top Right) */
00972                         glVertex2f( v[2].x, v[2].y );
00973         
00974                         /* Texture Coord (Top Left) */
00975                         glTexCoord2f( 0, 1);
00976                         /* Vertex Coord (Top Left) */
00977                         glVertex2f( v[3].x, v[3].y );
00978               glEnd( );
00979 
00980         glTranslated(sw, 0, 0);
00981         
00982         v[0].Set(0,0,0);
00983         v[1].Set(w,0,0);
00984         v[2].Set(w,-h,0);
00985         v[3].Set(0,-h,0);
00986         
00987         //draw middle
00988         glBegin( GL_QUADS );
00989                 /* Texture Coord (Bottom Left) */
00990                 glTexCoord2f( 0.5, 0);
00991                         /* Vertex Coord (Bottom Left) */
00992                         glVertex2f( v[0].x, v[0].y );
00993         
00994                         /* Texture Coord (Bottom Right) */
00995                         glTexCoord2f( 0.5, 0);
00996                         /* Vertex Coord (Bottom Right) */
00997                         glVertex2f( v[1].x, v[1].y );
00998         
00999                         /* Texture Coord (Top Right) */
01000                         glTexCoord2f( 0.5, 1);
01001                         /* Vertex Coord (Top Right) */
01002                         glVertex2f( v[2].x, v[2].y );
01003         
01004                         /* Texture Coord (Top Left) */
01005                         glTexCoord2f( 0.5, 1);
01006                         /* Vertex Coord (Top Left) */
01007                         glVertex2f( v[3].x, v[3].y );
01008               glEnd( );
01009         
01010         
01011         v[0].Set(0,0,0);
01012         v[1].Set(sw,0,0);
01013         v[2].Set(sw,-h,0);
01014         v[3].Set(0,-h,0);
01015         
01016         glTranslated(w, 0, 0);
01017         
01018         //draw right side
01019         glBegin( GL_QUADS );
01020                 /* Texture Coord (Bottom Left) */
01021                 glTexCoord2f( 0.5, 0);
01022                         /* Vertex Coord (Bottom Left) */
01023                         glVertex2f( v[0].x, v[0].y );
01024         
01025                         /* Texture Coord (Bottom Right) */
01026                         glTexCoord2f( 1, 0);
01027                         /* Vertex Coord (Bottom Right) */
01028                         glVertex2f( v[1].x, v[1].y );
01029         
01030                         /* Texture Coord (Top Right) */
01031                         glTexCoord2f( 1, 1);
01032                         /* Vertex Coord (Top Right) */
01033                         glVertex2f( v[2].x, v[2].y );
01034         
01035                         /* Texture Coord (Top Left) */
01036                         glTexCoord2f( 0.5, 1);
01037                         /* Vertex Coord (Top Left) */
01038                         glVertex2f( v[3].x, v[3].y );
01039               glEnd( );
01040 
01041         // Select the Modelview Matrix
01042         glMatrixMode( GL_MODELVIEW );
01043         // Restore the Old Projection Matrix
01044         glPopMatrix( );
01045 
01046         // Select The Projection Matrix
01047         glMatrixMode( GL_PROJECTION );
01048         // Restore The Old Projection Matrix
01049         glPopMatrix( );
01050 
01051         // Re-enable Depth Testing
01052         glEnable( GL_DEPTH_TEST );
01053         //and lighting...
01054         glEnable( GL_LIGHTING);
01055         glDisable(GL_BLEND);
01056         
01057         glPopAttrib();
01058 }
01059 
01060 bool UTILITY::IntersectQuadrilateralF(VERTEX orig, VERTEX dir,
01061                                         VERTEX v_00, VERTEX v_10, VERTEX v_11, VERTEX v_01,
01062                                         float &t, float &u, float &v)
01063 {       
01064         // Reject rays that are parallel to Q, and rays that intersect the plane
01065         // of Q either on the left of the line V00V01 or below the line V00V10.
01066         VERTEX E_01 = v_10 - v_00;
01067         VERTEX E_03 = v_01 - v_00;
01068         VERTEX P = dir.cross(E_03);
01069         float det = E_01.dot(P);
01070         
01071         if (std::abs(det) < EPSILON) return false;
01072         
01073         VERTEX T = orig - v_00;
01074         float alpha = T.dot(P) / det;
01075         
01076         if (alpha < 0.0) return false;
01077         
01078         VERTEX Q = T.cross(E_01);
01079         float beta = dir.dot(Q) / det;
01080         
01081         if (beta < 0.0) return false;
01082         
01083         if (alpha + beta > 1.0)
01084         {
01085                 // Reject rays that that intersect the plane of Q either on
01086                 // the right of the line V11V10 or above the line V11V00.
01087                 VERTEX E_23 = v_01 - v_11;
01088                 VERTEX E_21 = v_10 - v_11;
01089                 VERTEX P_prime = dir.cross(E_21);
01090                 float det_prime = E_23.dot(P_prime);
01091                 
01092                 if (std::abs(det_prime) < EPSILON) return false;
01093                         
01094                 VERTEX T_prime = orig - v_11;
01095                 float alpha_prime = T_prime.dot(P_prime) / det_prime;
01096                 
01097                 if (alpha_prime < 0.0) return false;
01098                         
01099                 VERTEX Q_prime = T_prime.cross(E_23);
01100                 float beta_prime = dir.dot(Q_prime) / det_prime;
01101                 
01102                 if (beta_prime < 0.0) return false;
01103         }
01104         
01105         // Compute the ray parameter of the intersection point, and
01106         // reject the ray if it does not hit Q.
01107         t = E_03.dot(Q) / det;
01108         
01109         if (t < 0.0) return false;
01110         
01111         // Compute the barycentric coordinates of the fourth vertex.
01112         // These do not depend on the ray, and can be precomputed
01113         // and stored with the quadrilateral.
01114         float alpha_11, beta_11;
01115         VERTEX E_02 = v_11 - v_00;
01116         VERTEX n = E_01.cross(E_03);
01117         
01118         if ((std::abs(n.x) >= std::abs(n.y))
01119                 && (std::abs(n.x) >= std::abs(n.z)))
01120         {
01121                 alpha_11 = ((E_02.y * E_03.z) - (E_02.z * E_03.y)) / n.x;
01122                 beta_11 = ((E_01.y * E_02.z) - (E_01.z  * E_02.y)) / n.x;
01123         }
01124         else if ((std::abs(n.y) >= std::abs(n.x))
01125                 && (std::abs(n.y) >= std::abs(n.z)))
01126         {
01127                 alpha_11 = ((E_02.z * E_03.x) - (E_02.x * E_03.z)) / n.y;
01128                 beta_11 = ((E_01.z * E_02.x) - (E_01.x  * E_02.z)) / n.y;
01129         }
01130         else
01131         {
01132                 alpha_11 = ((E_02.x * E_03.y) - (E_02.y * E_03.x)) / n.z;
01133                 beta_11 = ((E_01.x * E_02.y) - (E_01.y  * E_02.x)) / n.z;
01134         }
01135         
01136         // Compute the bilinear coordinates of the intersection point.
01137         if (std::abs(alpha_11 - (1.0)) < EPSILON)
01138         {
01139                 // Q is a trapezium.
01140                 u = alpha;
01141                 if (std::abs(beta_11 - (1.0)) < EPSILON) v = beta; // Q is a parallelogram.
01142                 else v = beta / ((u * (beta_11 - (1.0))) + (1.0)); // Q is a trapezium.
01143         }
01144         else if (std::abs(beta_11 - (1.0)) < EPSILON)
01145         {
01146                 // Q is a trapezium.
01147                 v = beta;
01148                 u = alpha / ((v * (alpha_11 - (1.0))) + (1.0));
01149         }
01150         else
01151         {
01152                 float A = (1.0) - beta_11;
01153                 float B = (alpha * (beta_11 - (1.0)))
01154                   - (beta * (alpha_11 - (1.0))) - (1.0);
01155                 float C = alpha;
01156                 float D = (B * B) - ((4.0) * A * C);
01157                 if (D < 0) return false;
01158                 float Q = (-0.5) * (B + ((B < (0.0) ? (-1.0) : (1.0))
01159                   * std::sqrt(D)));
01160                 u = Q / A;
01161                 if ((u < (0.0)) || (u > (1.0))) u = C / Q;
01162                 v = beta / ((u * (beta_11 - (1.0))) + (1.0));
01163         }
01164         
01165         return true;
01166 }
01167 
01168 bool UTILITY::IntersectQuadrilateralD(VERTEXD orig, VERTEXD dir,
01169                                         VERTEXD v_00, VERTEXD v_10, VERTEXD v_11, VERTEXD v_01,
01170                                         double &t, double &u, double &v)
01171 {       
01172         // Reject rays that are parallel to Q, and rays that intersect the plane
01173         // of Q either on the left of the line V00V01 or below the line V00V10.
01174         VERTEXD E_01 = v_10 - v_00;
01175         VERTEXD E_03 = v_01 - v_00;
01176         VERTEXD P = dir.cross(E_03);
01177         double det = E_01.dot(P);
01178         
01179         if (std::abs(det) < EPSILON) return false;
01180         
01181         VERTEXD T = orig - v_00;
01182         double alpha = T.dot(P) / det;
01183         
01184         if (alpha < 0.0) return false;
01185         
01186         VERTEXD Q = T.cross(E_01);
01187         double beta = dir.dot(Q) / det;
01188         
01189         if (beta < 0.0) return false;
01190         
01191         if (alpha + beta > 1.0)
01192         {
01193                 // Reject rays that that intersect the plane of Q either on
01194                 // the right of the line V11V10 or above the line V11V00.
01195                 VERTEXD E_23 = v_01 - v_11;
01196                 VERTEXD E_21 = v_10 - v_11;
01197                 VERTEXD P_prime = dir.cross(E_21);
01198                 double det_prime = E_23.dot(P_prime);
01199                 
01200                 if (std::abs(det_prime) < EPSILON) return false;
01201                         
01202                 VERTEXD T_prime = orig - v_11;
01203                 double alpha_prime = T_prime.dot(P_prime) / det_prime;
01204                 
01205                 if (alpha_prime < 0.0) return false;
01206                         
01207                 VERTEXD Q_prime = T_prime.cross(E_23);
01208                 double beta_prime = dir.dot(Q_prime) / det_prime;
01209                 
01210                 if (beta_prime < 0.0) return false;
01211         }
01212         
01213         // Compute the ray parameter of the intersection point, and
01214         // reject the ray if it does not hit Q.
01215         t = E_03.dot(Q) / det;
01216         
01217         if (t < 0.0) return false;
01218         
01219         // Compute the barycentric coordinates of the fourth vertex.
01220         // These do not depend on the ray, and can be precomputed
01221         // and stored with the quadrilateral.
01222         double alpha_11, beta_11;
01223         VERTEXD E_02 = v_11 - v_00;
01224         VERTEXD n = E_01.cross(E_03);
01225         
01226         if ((std::abs(n.x) >= std::abs(n.y))
01227                 && (std::abs(n.x) >= std::abs(n.z)))
01228         {
01229                 alpha_11 = ((E_02.y * E_03.z) - (E_02.z * E_03.y)) / n.x;
01230                 beta_11 = ((E_01.y * E_02.z) - (E_01.z  * E_02.y)) / n.x;
01231         }
01232         else if ((std::abs(n.y) >= std::abs(n.x))
01233                 && (std::abs(n.y) >= std::abs(n.z)))
01234         {
01235                 alpha_11 = ((E_02.z * E_03.x) - (E_02.x * E_03.z)) / n.y;
01236                 beta_11 = ((E_01.z * E_02.x) - (E_01.x  * E_02.z)) / n.y;
01237         }
01238         else
01239         {
01240                 alpha_11 = ((E_02.x * E_03.y) - (E_02.y * E_03.x)) / n.z;
01241                 beta_11 = ((E_01.x * E_02.y) - (E_01.y  * E_02.x)) / n.z;
01242         }
01243         
01244         // Compute the bilinear coordinates of the intersection point.
01245         if (std::abs(alpha_11 - (1.0)) < EPSILON)
01246         {
01247                 // Q is a trapezium.
01248                 u = alpha;
01249                 if (std::abs(beta_11 - (1.0)) < EPSILON) v = beta; // Q is a parallelogram.
01250                 else v = beta / ((u * (beta_11 - (1.0))) + (1.0)); // Q is a trapezium.
01251         }
01252         else if (std::abs(beta_11 - (1.0)) < EPSILON)
01253         {
01254                 // Q is a trapezium.
01255                 v = beta;
01256                 u = alpha / ((v * (alpha_11 - (1.0))) + (1.0));
01257         }
01258         else
01259         {
01260                 double A = (1.0) - beta_11;
01261                 double B = (alpha * (beta_11 - (1.0)))
01262                   - (beta * (alpha_11 - (1.0))) - (1.0);
01263                 double C = alpha;
01264                 double D = (B * B) - ((4.0) * A * C);
01265                 if (D < 0) return false;
01266                 double Q = (-0.5) * (B + ((B < (0.0) ? (-1.0) : (1.0))
01267                   * std::sqrt(D)));
01268                 u = Q / A;
01269                 if ((u < (0.0)) || (u > (1.0))) u = C / Q;
01270                 v = beta / ((u * (beta_11 - (1.0))) + (1.0));
01271         }
01272         
01273         return true;
01274 }
01275 
01276 /* some macros */
01277 #define CROSS(dest,v1,v2)                      \
01278               dest[0]=v1[1]*v2[2]-v1[2]*v2[1]; \
01279               dest[1]=v1[2]*v2[0]-v1[0]*v2[2]; \
01280               dest[2]=v1[0]*v2[1]-v1[1]*v2[0];
01281 
01282 #define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2])
01283 
01284 #define SUB(dest,v1,v2) dest[0]=v1[0]-v2[0]; dest[1]=v1[1]-v2[1]; dest[2]=v1[2]-v2[2]; 
01285 
01286 #define ADD(dest,v1,v2) dest[0]=v1[0]+v2[0]; dest[1]=v1[1]+v2[1]; dest[2]=v1[2]+v2[2]; 
01287 
01288 #define MULT(dest,v,factor) dest[0]=factor*v[0]; dest[1]=factor*v[1]; dest[2]=factor*v[2];
01289 
01290 #define SET(dest,src) dest[0]=src[0]; dest[1]=src[1]; dest[2]=src[2]; 
01291 
01292 /* sort so that a<=b */
01293 #define SORT(a,b)       \
01294              if(a>b)    \
01295              {          \
01296                float c; \
01297                c=a;     \
01298                a=b;     \
01299                b=c;     \
01300              }
01301 
01302 /* sort so that a<=b */
01303 #define SORT2(a,b,smallest)       \
01304              if(a>b)       \
01305              {             \
01306                float c;    \
01307                c=a;        \
01308                a=b;        \
01309                b=c;        \
01310                smallest=1; \
01311              }             \
01312              else smallest=0;
01313                          
01314 #define ISECT(VV0,VV1,VV2,D0,D1,D2,isect0,isect1) \
01315               isect0=VV0+(VV1-VV0)*D0/(D0-D1);    \
01316               isect1=VV0+(VV2-VV0)*D0/(D0-D2);
01317 
01318 
01319 #define COMPUTE_INTERVALS(VV0,VV1,VV2,D0,D1,D2,D0D1,D0D2,isect0,isect1) \
01320   if(D0D1>0.0f)                                         \
01321