Logo Search packages:      
Sourcecode: vdrift version File versions

utility.cpp

/* vim: set noexpandtab shiftwidth=8 cino= fo+=awc:
 ***************************************************************************
 *            utility.cc
 *
 *  Sat Mar 26 08:52:54 2005
 *  Copyright  2005  Joe Venzon
 *  joe@venzon.net
 ****************************************************************************/

/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#define GL_GLEXT_PROTOTYPES

#include "utility.h"
#include "textures.h"
#include <fstream>

#ifdef _WIN32
//#define GL_GLEXT_PROTOTYPES
#include <GL/glext.h>
#include <GL/glut.h>
//#include <GL/wglext.h>
//#include <GL/glprocs.h>
#include <windows.h>
#endif

#ifdef _WIN32
PFNGLMULTITEXCOORD2FARBPROC     pglMultiTexCoord2f     = NULL;
PFNGLMULTITEXCOORD4FARBPROC     pglMultiTexCoord4f     = NULL;
PFNGLCLIENTACTIVETEXTUREARBPROC     pglActiveTexture       = NULL;
PFNGLACTIVETEXTUREARBPROC       pglClientActiveTexture = NULL;
#endif

//includes needed to get folder contents
#ifndef _WIN32
#include <sys/types.h>
#include <dirent.h>
#endif

const float DEG2RAD = 3.14159 / 180.0;

void UTILITY::SelectTU(int TU)
{
      if (!initdone)
      {
          initerror();
          return;
      }

      GLenum tuenum;
      
      if (TU == 0)
            tuenum = GL_TEXTURE0_ARB;
      else if (TU == 1)
            tuenum = GL_TEXTURE1_ARB;
      else if (TU == 2)
            tuenum = GL_TEXTURE2_ARB;
      else if (TU == 3)
            tuenum = GL_TEXTURE3_ARB;
      else
            tuenum = GL_TEXTURE0_ARB;
      
      #ifdef _WIN32
      pglActiveTexture(tuenum);
      #else
      glActiveTextureARB(tuenum);
      #endif
}

void UTILITY::TexCoord2d2f(int TU, float u, float v)
{
      if (!initdone)
      {
          initerror();
          return;
      }

      GLenum tuenum;
      
      if (TU+1 > nb_multitexture)
            return;
      
      if (TU == 0)
            tuenum = GL_TEXTURE0_ARB;
      else if (TU == 1)
            tuenum = GL_TEXTURE1_ARB;
      else if (TU == 2)
            tuenum = GL_TEXTURE2_ARB;
      else if (TU == 3)
            tuenum = GL_TEXTURE3_ARB;
      else
            tuenum = GL_TEXTURE0_ARB;
      
      #ifdef _WIN32
      pglMultiTexCoord2f(tuenum, u, v);
      #else
      glMultiTexCoord2fARB(tuenum, u, v);
      #endif
}

GLuint UTILITY::TexLoad(string filename, int format, bool mipmap, int &w, int &h, const bool supressederror, bool &err)
{
      return TexLoad(filename, format, mipmap, w, h, supressederror, err, 0);
}

GLuint UTILITY::TexLoad(string filename, int format, bool mipmap, int &w, int &h, const bool supressederror, bool &err, int attempt)
{
      string filepath;
      string texture_size;
      char buffer[1024];
      //filepath = DATA_DIR + "/tex/" + filename;
      settings.Get( "display.texture_size", texture_size );

      switch (attempt)
      {
            case 0:
                  filepath = filename;
                  break;
            
            case 1:
                  filepath = settings.GetFullDataPath(filename);
                  break;
            
            case 2:
                  filepath = settings.GetFullDataPath("textures/" + texture_size + "/" + filename);
                  break;
            
            default:
                  filepath = filename;
                  break;
      }

      //cout << "Trying to load texture " << filepath << endl;
      
      strcpy(buffer, filepath.c_str());
      
      GLuint new_handle = 0;
      
      //*** Load Texture ***
      SDL_Surface *TextureImage[1];                         // Create Storage Space For The Texture

      // Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
      if ((TextureImage[0]=IMG_Load(buffer)))
      {
            //SDL_SetAlpha(TextureImage[0], 0, 0);
            
            w = TextureImage[0]->w;
            h = TextureImage[0]->h;
            
            switch (TextureImage[0]->format->BytesPerPixel)
            {
                  case 1:
                        format = GL_LUMINANCE;
                        break;
                  case 2:
                        format = GL_LUMINANCE_ALPHA;
                        break;
                  case 3:
                        format = GL_RGB;
                        break;
                  case 4:
                        format = GL_RGBA;
                        break;
                  default:
                        break;
            }
            
            glGenTextures(1, &new_handle);                              // Create Texture
            
            // Create MipMapped Texture
            glBindTexture(GL_TEXTURE_2D, new_handle);
            glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
            glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
            glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
            
            if (mipmap)
            {
                  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
                  gluBuild2DMipmaps( GL_TEXTURE_2D, format, TextureImage[0]->w, TextureImage[0]->h, format, GL_UNSIGNED_BYTE, TextureImage[0]->pixels );
            }
            else
            {
                  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
                  glTexImage2D( GL_TEXTURE_2D, 0, format, TextureImage[0]->w, TextureImage[0]->h, 0, format, GL_UNSIGNED_BYTE, TextureImage[0]->pixels );
            }
            
            //check for anisotropy
            if (gfxcard.GetCapability(CARDINFOTYPE::ANISOTROPY))
            {
                  //enable maximum anisotropy
                  int maxaniso = gfxcard.GetCapability(CARDINFOTYPE::MAXANISOTROPY);
                  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float) maxaniso);
            }
            
            err = false;
      }
      else
      {
            /*err = true;
            
          //try once more
            //cout << "initially failed: " << buffer << endl;
            int try2 = -1;
            if (filepath.find(settings.GetDataDir() + "/textures") > filepath.length())
            {
                  try2 = TexLoad(settings.GetFullDataPath("textures/" + settings.GetTexSize() + "/" + filepath), format, mipmap, w, h, supressederror, err);
            }
            //quit, bitmap not found
            if (err)
            {
                  if (!supressederror) error_log << "Could not find texture: " << buffer << "\n";
                  return 0;
            }
            else
            {
                  err = false;
                  return try2;
            }*/
            
            attempt++;
            
            if (attempt > 2)
            {
                  err = true;
                  if (!supressederror) error_log << "Could not find texture: " << filename << "\n";
                  return 0;
            }
            else
            {
                  return TexLoad(filename, format, mipmap, w, h, supressederror, err, attempt);
            }
      }

      if (TextureImage[0]) // If Texture Exists
      {
            // Free up any memory we may have used
            SDL_FreeSurface( TextureImage[0] );
      }
      
      return new_handle;
}

GLuint UTILITY::TexLoad(string texfile, bool mipmap)
{
      return TexLoad(texfile, GL_RGBA, mipmap);
}

GLuint UTILITY::TexLoad(string filename, int format, bool mipmap)
{
      int dw, dh, new_handle;
      bool err = false;
      
      new_handle = TexLoad(filename, format, mipmap, dw, dh, false, err);
      
      return new_handle;
}

UTILITY::UTILITY()
{
      error_log.open((settings.GetSettingsDir() + "/logs/utility.log").c_str());
      initdone = false;
}

extern bool verbose_output;
UTILITY::~UTILITY()
{
      if (verbose_output)
            cout << "utility deinit" << endl;
      
      error_log.close();
}

void UTILITY::Init()
{
      //cout << "utility init test" << endl;

#ifdef _WIN32
      pglMultiTexCoord4f = (PFNGLMULTITEXCOORD4FARBPROC) wglGetProcAddress("glMultiTexCoord4fARB");
      pglMultiTexCoord2f = (PFNGLMULTITEXCOORD2FARBPROC) wglGetProcAddress("glMultiTexCoord2fARB");
      pglActiveTexture = (PFNGLCLIENTACTIVETEXTUREARBPROC) wglGetProcAddress("glActiveTextureARB");
      pglClientActiveTexture = (PFNGLACTIVETEXTUREARBPROC) wglGetProcAddress("glClientActiveTextureARB");
      
      if (pglMultiTexCoord4f == NULL)
            error_log << "main, WIN32: wglGetProcAddress(\"glMultiTexCoord4fARB\") failed." << endl;
      if (pglMultiTexCoord2f == NULL)
            error_log << "main, WIN32: wglGetProcAddress(\"glMultiTexCoord2fARB\") failed." << endl;
      if (pglActiveTexture == NULL)
            error_log << "main, WIN32: wglGetProcAddress(\"glActiveTextureARB\") failed." << endl;
      if (pglClientActiveTexture == NULL)
            error_log << "main, WIN32: wglGetProcAddress(\"glClientActiveTextureARB\") failed." << endl;
            
            //cout << "utility init test" << endl;
#endif


      glGetIntegerv( GL_MAX_TEXTURE_UNITS_ARB,&nb_multitexture );
      
      //nb_multitexture = 2;
      
      cout << "Multitexture units (4 are required for all effects): " << nb_multitexture << endl;
      if (nb_multitexture < 2)
            cout << "You have less than the recommended number of texture units." << endl << "Some effects will not be rendered." << endl << "Upgrade your graphics card!" << endl;
      else if (nb_multitexture <= 3)
            cout << "You have less than the recommended number of texture units." << endl << "Some textures will lack detail." << endl << "Upgrade your graphics card!" << endl;
      else
            cout << "Your GPU meets the texture unit requirements." << endl;
      
      cout << endl << "Note to user:  All error messages will be put in " + settings.GetSettingsDir() + "/logs/." << endl;

      initdone = true;
}

string UTILITY::sGetLine(ifstream &ffrom)
{
      string trashstr;
      char trashchar[1024];

      //ffrom >> trashstr;
      ffrom.getline(trashchar,1024,'\n');

      while ((trashchar[0] == '#' || strlen(trashchar) <= 1 ) && !ffrom.eof())
      {
            ffrom.getline(trashchar, 1024, '\n');
            //ffrom >> trashstr;
            //ffrom.getline(trashchar,1024,'\n');
      }
      trashstr = trashchar;

      if (ffrom.eof() && trashstr.length() == 0)
            return ENDOFFILESTRING;
      else
            return trashstr;
}

string UTILITY::sGetParam(ifstream &ffrom)
{
      string trashstr;
      char trashchar[1024];

      ffrom >> trashstr;

      while (trashstr.c_str()[0] == '#' && !ffrom.eof() && trashstr != "")
      {
            ffrom.getline(trashchar, 1024, '\n');
            ffrom >> trashstr;
      }
      
      if (ffrom.eof() && trashstr.c_str()[0] == '#')
            return ENDOFFILESTRING;
      else
            return trashstr;
}

int UTILITY::iGetParam(ifstream &ffrom)
{
      string trashstr;
      char trashchar[1024];

      ffrom >> trashstr;

      while (trashstr.c_str()[0] == '#' && !ffrom.eof())
      {
            ffrom.getline(trashchar, 1024, '\n');
            ffrom >> trashstr;
      }

      return atoi(trashstr.c_str());
}

float UTILITY::fGetParam(ifstream &ffrom)
{
      string trashstr;
      char trashchar[1024];

      ffrom >> trashstr;

      while (trashstr.c_str()[0] == '#' && !ffrom.eof())
      {
            ffrom.getline(trashchar, 1024, '\n');
            ffrom >> trashstr;
      }

      return atof(trashstr.c_str());
}

void UTILITY::initerror()
{
      //error_log << "Utility library not yet initialized" << endl;
}

void UTILITY::Tex2D(int TU, bool enable)
{
      if (!initdone)
      {
          initerror();
          return;
      }

      SelectTU(TU);
      if (enable)
            glEnable(GL_TEXTURE_2D);
      else
            glDisable(GL_TEXTURE_2D);
}

bool UTILITY::bGetParam(ifstream &ffrom)
{
      string trashstr;
      char trashchar[1024];

      ffrom >> trashstr;

      while (trashstr.c_str()[0] == '#' && !ffrom.eof())
      {
            ffrom.getline(trashchar, 1024, '\n');
            ffrom >> trashstr;
      }
      
      if (trashstr == "true" || trashstr == "1" || trashstr == "on")
            return true;
      else
            return false;
}

int UTILITY::numTUs()
{
      if (!initdone)
      {
          initerror();
          return 0;
      }
      
      return nb_multitexture;
}

void UTILITY::Draw2D(float x1, float y1, float x2, float y2, TEXTURE_HANDLE * texid)
{
      Draw2D(x1, y1, x2, y2, texid, 0.0);
}

void UTILITY::Draw2D(float x1, float y1, float x2, float y2, TEXTURE_HANDLE * texid, float rotation)
{
      Draw2D(x1, y1, x2, y2, texid, rotation, 0);
}

void UTILITY::Draw2D(float x1, float y1, float x2, float y2, TEXTURE_HANDLE * texid, float rotation, int texsize)
{
      Draw2D(x1, y1, x2, y2, texid, rotation, texsize, 1.0);
}

void UTILITY::Draw2D(float x1, float y1, float x2, float y2, TEXTURE_HANDLE * texid, float rotation, int texsize, float opacity)
{
      int sx, sy;
      
      QUATERNION rot;
      rot.Rotate(rotation, 0,0,1);
      
      glPushAttrib(GL_ALL_ATTRIB_BITS);
      Tex2D(0, true);
      
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

      sx = 1600;
      sy = 1200;
      
      int x = (int) (x1*(float)sx);
      int y = (int) ((1.0-y1)*(float)sy);
      
      int w = (int) ((x2-x1)*(float)sx);
      int h = (int) ((y2-y1)*(float)sy);

      // Select our texture
      //glBindTexture( GL_TEXTURE_2D, texid );
      texid->Activate();

      // Disable depth testing 
      glDisable( GL_DEPTH_TEST );
      //and lighting...
      glDisable( GL_LIGHTING);
      glBlendFunc( GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR);
      glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
      glEnable( GL_BLEND );

      // Select The Projection Matrix
      glMatrixMode( GL_PROJECTION );
      // Store The Projection Matrix
      glPushMatrix( );

      // Reset The Projection Matrix 
      glLoadIdentity( );
      // Set Up An Ortho Screen 
      glOrtho( 0, sx, 0, sy, -1, 1 );

      // Select The Modelview Matrix
      glMatrixMode( GL_MODELVIEW );
      // Stor the Modelview Matrix
      glPushMatrix( );
      // Reset The Modelview Matrix
      glLoadIdentity( );

      // Position The Text (0,0 - Bottom Left)
      glTranslated( x, y, 0 );

      /*// Choose The Font Set (0 or 1)
      glListBase( base - 32 + ( 128 * set ) );

      // Write The Text To The Screen
      glCallLists( strlen( string ), GL_BYTE, string );*/
      
      //glColor3f(1,1,1);
      glColor4f(1,1,1,opacity);
      
      /*for (unsigned int i = 0; i < strlen(string); i++)
      {
            if (string[i] == 32)
                  glTranslated( 10, 0, 0 );
            else if (string[i] == '\n')
            {
                  num_crs++;
                  glLoadIdentity( );
                  glTranslated(x,y-20*num_crs,0);
            }
            else
            {
                  int pos = base - 32 + (128*set) + string[i];
                  if (pos < 0)
                        pos = 0;
                  glCallList(pos);
            }
      }*/
      
      VERTEX v[4];
      v[0].Set(0,0,0);
      v[1].Set(w,0,0);
      v[2].Set(w,-h,0);
      v[3].Set(0,-h,0);
      
      int i;
      
      for (i = 0; i < 4; i++)
      {
            v[i].x -= w/2.0;
            v[i].y += h/2.0;
      }
      
      for (i = 0; i < 4; i++)
            v[i] = rot.RotateVec(v[i]);
      
      for (i = 0; i < 4; i++)
      {
            v[i].x += w/2.0;
            v[i].y -= h/2.0;
      }

      float tmin, tmax;
      tmin = 0;
      tmax = 1;
      if (texsize > 0)
      {
            tmin = 1.0/(float)texsize;
            tmax = ((float)texsize-1.0)/(float)texsize;
      }

      //draw box
      glBegin( GL_QUADS );
              /* Texture Coord (Bottom Left) */
              glTexCoord2f( tmin, tmin);
            /* Vertex Coord (Bottom Left) */
            glVertex2f( v[0].x, v[0].y );

            /* Texture Coord (Bottom Right) */
            glTexCoord2f( tmax, tmin);
            /* Vertex Coord (Bottom Right) */
            glVertex2f( v[1].x, v[1].y );

            /* Texture Coord (Top Right) */
            glTexCoord2f( tmax, tmax);
            /* Vertex Coord (Top Right) */
            glVertex2f( v[2].x, v[2].y );

            /* Texture Coord (Top Left) */
            glTexCoord2f( tmin, tmax);
            /* Vertex Coord (Top Left) */
            glVertex2f( v[3].x, v[3].y );
      glEnd( );

      // Select The Projection Matrix
      glMatrixMode( GL_PROJECTION );
      // Restore The Old Projection Matrix
      glPopMatrix( );
      
      // Select the Modelview Matrix
      glMatrixMode( GL_MODELVIEW );
      // Restore the Old Projection Matrix
      glPopMatrix( );

      // Re-enable Depth Testing
      glEnable( GL_DEPTH_TEST );
      //and lighting...
      glEnable( GL_LIGHTING);
      glDisable(GL_BLEND);
      
      glPopAttrib();
}

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 )
{
      int sx = 1600;
      int sy = 1200;
      int x = (int)( center_x * (float)sx );
        int y = (int)( ( 1.0 - center_y ) * (float)sy );

      glLoadIdentity();
      glTranslated( x, y, 0 );
      glColor4f( color_r, color_g, color_b, opacity );

      glBegin( GL_LINE_LOOP );

      for( int i = 0; i < 360; i++ )
      {
            //convert degrees into radians
            float rad = i * DEG2RAD;
            glVertex2f( cos( rad ) * radius_x, sin( rad ) * radius_y );
      }

      glEnd();
}

float UTILITY::GetValue(SDL_Surface * surf, int channel, float x, float y, bool interpolate)
{
      return GetValue(surf, channel, x, y, interpolate, false);
}

float UTILITY::GetValue(SDL_Surface * surf, int channel, float x, float y, bool interpolate, bool wrap)
{
      //check for NANs
      if (!(x < 0 || x >= 0) || !(y < 0 || y >= 0))
            return 0;
      
      if (channel >= surf->format->BytesPerPixel || channel < 0)
      {
            error_log << "Asked for channel " << channel << ", image only has " << surf->format->BytesPerPixel << endl;
            channel = surf->format->BytesPerPixel - 1;
      }
      
      {
            if (x < 0)
                  x = 0;
            if (x > 1)
                  x = 1;
            if (y < 0)
                  y = 0;
            if (y > 1)
                  y = 1;
            int ix, iy;
            ix = (int)(x * surf->w);
            iy = (int)(y * surf->h);
            float dx, dy;
            dx = x - ix;
            dy = y - iy;
            
            unsigned char * pix;
            pix = (unsigned char *) surf->pixels;
            
            if (ix >= surf->w)
            {
                  if (wrap)
                        ix = ix % surf->w;
                  else
                        ix = surf->w - 1;
            }
            if (iy >= surf->h)
            {
                  if (wrap)
                        iy = iy % surf->h;
                  else
                        iy = surf->h - 1;
            }
            
            if (!interpolate)
            {
                  return pix[(ix+surf->pitch*iy)*surf->format->BytesPerPixel+channel] / 255.0f;
            }
            else
            {
                  float ul, ur, ll, lr;
                  
                  int rx, ry;
                  
                  rx = ix + 1;
                  if (rx >= surf->w)
                  {
                        if (wrap)
                              rx = rx % surf->w;
                        else
                              rx = ix;
                  }
                  
                  ry = iy + 1;
                  if (ry >= surf->h)
                  {
                        if (wrap)
                              ry = ry % surf->h;
                        else
                              ry = iy;
                  }
                  
                  rx = ix;
                  ry = iy;
                  
                  ul = pix[(ix+surf->pitch*iy)*surf->format->BytesPerPixel+channel] / 255.0f;
                  ur = pix[(rx+surf->pitch*iy)*surf->format->BytesPerPixel+channel] / 255.0f;
                  ll = pix[(ix+surf->pitch*ry)*surf->format->BytesPerPixel+channel] / 255.0f;
                  lr = pix[(rx+surf->pitch*ry)*surf->format->BytesPerPixel+channel] / 255.0f;
                  
                  float u, l;
                  
                  u = ul*(1.0-dx)+ur*dx;
                  l = ll*(1.0-dx)+lr*dx;
                  
                  return u*(1.0-dy)+l*dy;
            }
      }
}

bool UTILITY::FileExists(string filename)
{
      ifstream test;
      test.open(filename.c_str());
      if (test)
      {
            test.close();
            return true;
      }
      else
            return false;
}

int UTILITY::IntersectTriangleD(double orig[3], double dir[3],
                   double vert0[3], double vert1[3], double vert2[3],
                   double *t, double *u, double *v)
{
   double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
   double det,inv_det;

   /* find vectors for two edges sharing vert0 */
   SUB(edge1, vert1, vert0);
   SUB(edge2, vert2, vert0);

   /* begin calculating determinant - also used to calculate U parameter */
   CROSS(pvec, dir, edge2);

   /* if determinant is near zero, ray lies in plane of triangle */
   det = DOT(edge1, pvec);

#ifdef TEST_CULL           /* define TEST_CULL if culling is desired */
   if (det < EPSILON)
      return 0;

   /* calculate distance from vert0 to ray origin */
   SUB(tvec, orig, vert0);

   /* calculate U parameter and test bounds */
   *u = DOT(tvec, pvec);
   if (*u < 0.0 || *u > det)
      return 0;

   /* prepare to test V parameter */
   CROSS(qvec, tvec, edge1);

    /* calculate V parameter and test bounds */
   *v = DOT(dir, qvec);
   if (*v < 0.0 || *u + *v > det)
      return 0;

   /* calculate t, scale parameters, ray intersects triangle */
   *t = DOT(edge2, qvec);
   inv_det = 1.0 / det;
   *t *= inv_det;
   *u *= inv_det;
   *v *= inv_det;
#else                    /* the non-culling branch */
   if (det > -EPSILON && det < EPSILON)
     return 0;
   inv_det = 1.0 / det;

   /* calculate distance from vert0 to ray origin */
   SUB(tvec, orig, vert0);

   /* calculate U parameter and test bounds */
   *u = DOT(tvec, pvec) * inv_det;
   if (*u < 0.0 || *u > 1.0)
     return 0;

   /* prepare to test V parameter */
   CROSS(qvec, tvec, edge1);

   /* calculate V parameter and test bounds */
   *v = DOT(dir, qvec) * inv_det;
   if (*v < 0.0 || *u + *v > 1.0)
     return 0;

   /* calculate t, ray intersects triangle */
   *t = DOT(edge2, qvec) * inv_det;
#endif
   return 1;
}

int UTILITY::IntersectTriangleF(float orig[3], float dir[3],
                   float vert0[3], float vert1[3], float vert2[3],
                   float *t, float *u, float *v)
{
   float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
   float det,inv_det;

   /* find vectors for two edges sharing vert0 */
   SUB(edge1, vert1, vert0);
   SUB(edge2, vert2, vert0);

   /* begin calculating determinant - also used to calculate U parameter */
   CROSS(pvec, dir, edge2);

   /* if determinant is near zero, ray lies in plane of triangle */
   det = DOT(edge1, pvec);

#ifdef TEST_CULL           /* define TEST_CULL if culling is desired */
   if (det < EPSILON)
      return 0;

   /* calculate distance from vert0 to ray origin */
   SUB(tvec, orig, vert0);
   
   /* calculate U parameter and test bounds */
   *u = DOT(tvec, pvec);
   if (*u < 0.0 || *u > det)
      return 0;

   /* prepare to test V parameter */
   CROSS(qvec, tvec, edge1);

    /* calculate V parameter and test bounds */
   *v = DOT(dir, qvec);
   if (*v < 0.0 || *u + *v > det)
      return 0;

   /* calculate t, scale parameters, ray intersects triangle */
   *t = DOT(edge2, qvec);
   inv_det = 1.0 / det;
   *t *= inv_det;
   *u *= inv_det;
   *v *= inv_det;
#else                    /* the non-culling branch */
   if (det > -EPSILON && det < EPSILON)
     return 0;
   inv_det = 1.0 / det;

   /* calculate distance from vert0 to ray origin */
   SUB(tvec, orig, vert0);

   /* calculate U parameter and test bounds */
   *u = DOT(tvec, pvec) * inv_det;
   if (*u < 0.0 || *u > 1.0)
     return 0;

   /* prepare to test V parameter */
   CROSS(qvec, tvec, edge1);

   /* calculate V parameter and test bounds */
   *v = DOT(dir, qvec) * inv_det;
   if (*v < 0.0 || *u + *v > 1.0)
     return 0;

   /* calculate t, ray intersects triangle */
   *t = DOT(edge2, qvec) * inv_det;
#endif
   if (isNaN(*u) || isNaN(*v) || isNaN(*t))
         return 0;
   return 1;
}

void UTILITY::DrawButton(float x1, float y1, float x2, float y2, float sidewidth, TEXTURE_HANDLE * texid, float opacity)
{
      int sx, sy;
      
      /*QUATERNION rot;
      rot.Rotate(rotation, 0,0,1);*/
      
      glPushAttrib(GL_ALL_ATTRIB_BITS);
      
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
      
      sx = 1600;
      sy = 1200;
      
      int x = (int) (x1*(float)sx);
      int y = (int) ((1.0-y1)*(float)sy);
      
      int w = (int) ((x2-x1)*(float)sx);
      int h = (int) ((y2-y1)*(float)sy);
      
      int sw = (int) (sidewidth * (float) sx);

      // Select our texture
      //glBindTexture( GL_TEXTURE_2D, texid );
      texid->Activate();

      // Disable depth testing 
      glDisable( GL_DEPTH_TEST );
      //and lighting...
      glDisable( GL_LIGHTING);
      glBlendFunc( GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR);
      glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
      glEnable( GL_BLEND );

      // Select The Projection Matrix
      glMatrixMode( GL_PROJECTION );
      // Store The Projection Matrix
      glPushMatrix( );

      // Reset The Projection Matrix 
      glLoadIdentity( );
      // Set Up An Ortho Screen 
      glOrtho( 0, sx, 0, sy, -1, 1 );

      // Select The Modelview Matrix
      glMatrixMode( GL_MODELVIEW );
      glPushMatrix( );
      glLoadIdentity( );
      glTranslated( x, y, 0 );
      glColor4f(1,1,1,opacity);
      
      VERTEX v[4];
      v[0].Set(0,0,0);
      v[1].Set(sw,0,0);
      v[2].Set(sw,-h,0);
      v[3].Set(0,-h,0);
      
      glTranslated(-sw, 0, 0);
      
      //draw left side
      glBegin( GL_QUADS );
              /* Texture Coord (Bottom Left) */
              glTexCoord2f( 0, 0);
                  /* Vertex Coord (Bottom Left) */
                  glVertex2f( v[0].x, v[0].y );
      
                  /* Texture Coord (Bottom Right) */
                  glTexCoord2f( 0.5, 0);
                  /* Vertex Coord (Bottom Right) */
                  glVertex2f( v[1].x, v[1].y );
      
                  /* Texture Coord (Top Right) */
                  glTexCoord2f( 0.5, 1);
                  /* Vertex Coord (Top Right) */
                  glVertex2f( v[2].x, v[2].y );
      
                  /* Texture Coord (Top Left) */
                  glTexCoord2f( 0, 1);
                  /* Vertex Coord (Top Left) */
                  glVertex2f( v[3].x, v[3].y );
            glEnd( );

      glTranslated(sw, 0, 0);
      
      v[0].Set(0,0,0);
      v[1].Set(w,0,0);
      v[2].Set(w,-h,0);
      v[3].Set(0,-h,0);
      
      //draw middle
      glBegin( GL_QUADS );
              /* Texture Coord (Bottom Left) */
              glTexCoord2f( 0.5, 0);
                  /* Vertex Coord (Bottom Left) */
                  glVertex2f( v[0].x, v[0].y );
      
                  /* Texture Coord (Bottom Right) */
                  glTexCoord2f( 0.5, 0);
                  /* Vertex Coord (Bottom Right) */
                  glVertex2f( v[1].x, v[1].y );
      
                  /* Texture Coord (Top Right) */
                  glTexCoord2f( 0.5, 1);
                  /* Vertex Coord (Top Right) */
                  glVertex2f( v[2].x, v[2].y );
      
                  /* Texture Coord (Top Left) */
                  glTexCoord2f( 0.5, 1);
                  /* Vertex Coord (Top Left) */
                  glVertex2f( v[3].x, v[3].y );
            glEnd( );
      
      
      v[0].Set(0,0,0);
      v[1].Set(sw,0,0);
      v[2].Set(sw,-h,0);
      v[3].Set(0,-h,0);
      
      glTranslated(w, 0, 0);
      
      //draw right side
      glBegin( GL_QUADS );
              /* Texture Coord (Bottom Left) */
              glTexCoord2f( 0.5, 0);
                  /* Vertex Coord (Bottom Left) */
                  glVertex2f( v[0].x, v[0].y );
      
                  /* Texture Coord (Bottom Right) */
                  glTexCoord2f( 1, 0);
                  /* Vertex Coord (Bottom Right) */
                  glVertex2f( v[1].x, v[1].y );
      
                  /* Texture Coord (Top Right) */
                  glTexCoord2f( 1, 1);
                  /* Vertex Coord (Top Right) */
                  glVertex2f( v[2].x, v[2].y );
      
                  /* Texture Coord (Top Left) */
                  glTexCoord2f( 0.5, 1);
                  /* Vertex Coord (Top Left) */
                  glVertex2f( v[3].x, v[3].y );
            glEnd( );

      // Select the Modelview Matrix
      glMatrixMode( GL_MODELVIEW );
      // Restore the Old Projection Matrix
      glPopMatrix( );

      // Select The Projection Matrix
      glMatrixMode( GL_PROJECTION );
      // Restore The Old Projection Matrix
      glPopMatrix( );

      // Re-enable Depth Testing
      glEnable( GL_DEPTH_TEST );
      //and lighting...
      glEnable( GL_LIGHTING);
      glDisable(GL_BLEND);
      
      glPopAttrib();
}

bool UTILITY::IntersectQuadrilateralF(VERTEX orig, VERTEX dir,
                              VERTEX v_00, VERTEX v_10, VERTEX v_11, VERTEX v_01,
                              float &t, float &u, float &v)
{     
      // Reject rays that are parallel to Q, and rays that intersect the plane
      // of Q either on the left of the line V00V01 or below the line V00V10.
      VERTEX E_01 = v_10 - v_00;
      VERTEX E_03 = v_01 - v_00;
      VERTEX P = dir.cross(E_03);
      float det = E_01.dot(P);
      
      if (std::abs(det) < EPSILON) return false;
      
      VERTEX T = orig - v_00;
      float alpha = T.dot(P) / det;
      
      if (alpha < 0.0) return false;
      
      VERTEX Q = T.cross(E_01);
      float beta = dir.dot(Q) / det;
      
      if (beta < 0.0) return false;
      
      if (alpha + beta > 1.0)
      {
            // Reject rays that that intersect the plane of Q either on
            // the right of the line V11V10 or above the line V11V00.
            VERTEX E_23 = v_01 - v_11;
            VERTEX E_21 = v_10 - v_11;
            VERTEX P_prime = dir.cross(E_21);
            float det_prime = E_23.dot(P_prime);
            
            if (std::abs(det_prime) < EPSILON) return false;
                  
            VERTEX T_prime = orig - v_11;
            float alpha_prime = T_prime.dot(P_prime) / det_prime;
            
            if (alpha_prime < 0.0) return false;
                  
            VERTEX Q_prime = T_prime.cross(E_23);
            float beta_prime = dir.dot(Q_prime) / det_prime;
            
            if (beta_prime < 0.0) return false;
      }
      
      // Compute the ray parameter of the intersection point, and
      // reject the ray if it does not hit Q.
      t = E_03.dot(Q) / det;
      
      if (t < 0.0) return false;
      
      // Compute the barycentric coordinates of the fourth vertex.
      // These do not depend on the ray, and can be precomputed
      // and stored with the quadrilateral.
      float alpha_11, beta_11;
      VERTEX E_02 = v_11 - v_00;
      VERTEX n = E_01.cross(E_03);
      
      if ((std::abs(n.x) >= std::abs(n.y))
            && (std::abs(n.x) >= std::abs(n.z)))
      {
            alpha_11 = ((E_02.y * E_03.z) - (E_02.z * E_03.y)) / n.x;
            beta_11 = ((E_01.y * E_02.z) - (E_01.z  * E_02.y)) / n.x;
      }
      else if ((std::abs(n.y) >= std::abs(n.x))
            && (std::abs(n.y) >= std::abs(n.z)))
      {
            alpha_11 = ((E_02.z * E_03.x) - (E_02.x * E_03.z)) / n.y;
            beta_11 = ((E_01.z * E_02.x) - (E_01.x  * E_02.z)) / n.y;
      }
      else
      {
            alpha_11 = ((E_02.x * E_03.y) - (E_02.y * E_03.x)) / n.z;
            beta_11 = ((E_01.x * E_02.y) - (E_01.y  * E_02.x)) / n.z;
      }
      
      // Compute the bilinear coordinates of the intersection point.
      if (std::abs(alpha_11 - (1.0)) < EPSILON)
      {
            // Q is a trapezium.
            u = alpha;
            if (std::abs(beta_11 - (1.0)) < EPSILON) v = beta; // Q is a parallelogram.
            else v = beta / ((u * (beta_11 - (1.0))) + (1.0)); // Q is a trapezium.
      }
      else if (std::abs(beta_11 - (1.0)) < EPSILON)
      {
            // Q is a trapezium.
            v = beta;
            u = alpha / ((v * (alpha_11 - (1.0))) + (1.0));
      }
      else
      {
            float A = (1.0) - beta_11;
            float B = (alpha * (beta_11 - (1.0)))
              - (beta * (alpha_11 - (1.0))) - (1.0);
            float C = alpha;
            float D = (B * B) - ((4.0) * A * C);
            if (D < 0) return false;
            float Q = (-0.5) * (B + ((B < (0.0) ? (-1.0) : (1.0))
              * std::sqrt(D)));
            u = Q / A;
            if ((u < (0.0)) || (u > (1.0))) u = C / Q;
            v = beta / ((u * (beta_11 - (1.0))) + (1.0));
      }
      
      return true;
}

bool UTILITY::IntersectQuadrilateralD(VERTEXD orig, VERTEXD dir,
                              VERTEXD v_00, VERTEXD v_10, VERTEXD v_11, VERTEXD v_01,
                              double &t, double &u, double &v)
{     
      // Reject rays that are parallel to Q, and rays that intersect the plane
      // of Q either on the left of the line V00V01 or below the line V00V10.
      VERTEXD E_01 = v_10 - v_00;
      VERTEXD E_03 = v_01 - v_00;
      VERTEXD P = dir.cross(E_03);
      double det = E_01.dot(P);
      
      if (std::abs(det) < EPSILON) return false;
      
      VERTEXD T = orig - v_00;
      double alpha = T.dot(P) / det;
      
      if (alpha < 0.0) return false;
      
      VERTEXD Q = T.cross(E_01);
      double beta = dir.dot(Q) / det;
      
      if (beta < 0.0) return false;
      
      if (alpha + beta > 1.0)
      {
            // Reject rays that that intersect the plane of Q either on
            // the right of the line V11V10 or above the line V11V00.
            VERTEXD E_23 = v_01 - v_11;
            VERTEXD E_21 = v_10 - v_11;
            VERTEXD P_prime = dir.cross(E_21);
            double det_prime = E_23.dot(P_prime);
            
            if (std::abs(det_prime) < EPSILON) return false;
                  
            VERTEXD T_prime = orig - v_11;
            double alpha_prime = T_prime.dot(P_prime) / det_prime;
            
            if (alpha_prime < 0.0) return false;
                  
            VERTEXD Q_prime = T_prime.cross(E_23);
            double beta_prime = dir.dot(Q_prime) / det_prime;
            
            if (beta_prime < 0.0) return false;
      }
      
      // Compute the ray parameter of the intersection point, and
      // reject the ray if it does not hit Q.
      t = E_03.dot(Q) / det;
      
      if (t < 0.0) return false;
      
      // Compute the barycentric coordinates of the fourth vertex.
      // These do not depend on the ray, and can be precomputed
      // and stored with the quadrilateral.
      double alpha_11, beta_11;
      VERTEXD E_02 = v_11 - v_00;
      VERTEXD n = E_01.cross(E_03);
      
      if ((std::abs(n.x) >= std::abs(n.y))
            && (std::abs(n.x) >= std::abs(n.z)))
      {
            alpha_11 = ((E_02.y * E_03.z) - (E_02.z * E_03.y)) / n.x;
            beta_11 = ((E_01.y * E_02.z) - (E_01.z  * E_02.y)) / n.x;
      }
      else if ((std::abs(n.y) >= std::abs(n.x))
            && (std::abs(n.y) >= std::abs(n.z)))
      {
            alpha_11 = ((E_02.z * E_03.x) - (E_02.x * E_03.z)) / n.y;
            beta_11 = ((E_01.z * E_02.x) - (E_01.x  * E_02.z)) / n.y;
      }
      else
      {
            alpha_11 = ((E_02.x * E_03.y) - (E_02.y * E_03.x)) / n.z;
            beta_11 = ((E_01.x * E_02.y) - (E_01.y  * E_02.x)) / n.z;
      }
      
      // Compute the bilinear coordinates of the intersection point.
      if (std::abs(alpha_11 - (1.0)) < EPSILON)
      {
            // Q is a trapezium.
            u = alpha;
            if (std::abs(beta_11 - (1.0)) < EPSILON) v = beta; // Q is a parallelogram.
            else v = beta / ((u * (beta_11 - (1.0))) + (1.0)); // Q is a trapezium.
      }
      else if (std::abs(beta_11 - (1.0)) < EPSILON)
      {
            // Q is a trapezium.
            v = beta;
            u = alpha / ((v * (alpha_11 - (1.0))) + (1.0));
      }
      else
      {
            double A = (1.0) - beta_11;
            double B = (alpha * (beta_11 - (1.0)))
              - (beta * (alpha_11 - (1.0))) - (1.0);
            double C = alpha;
            double D = (B * B) - ((4.0) * A * C);
            if (D < 0) return false;
            double Q = (-0.5) * (B + ((B < (0.0) ? (-1.0) : (1.0))
              * std::sqrt(D)));
            u = Q / A;
            if ((u < (0.0)) || (u > (1.0))) u = C / Q;
            v = beta / ((u * (beta_11 - (1.0))) + (1.0));
      }
      
      return true;
}

/* some macros */
#define CROSS(dest,v1,v2)                      \
              dest[0]=v1[1]*v2[2]-v1[2]*v2[1]; \
              dest[1]=v1[2]*v2[0]-v1[0]*v2[2]; \
              dest[2]=v1[0]*v2[1]-v1[1]*v2[0];

#define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2])

#define SUB(dest,v1,v2) dest[0]=v1[0]-v2[0]; dest[1]=v1[1]-v2[1]; dest[2]=v1[2]-v2[2]; 

#define ADD(dest,v1,v2) dest[0]=v1[0]+v2[0]; dest[1]=v1[1]+v2[1]; dest[2]=v1[2]+v2[2]; 

#define MULT(dest,v,factor) dest[0]=factor*v[0]; dest[1]=factor*v[1]; dest[2]=factor*v[2];

#define SET(dest,src) dest[0]=src[0]; dest[1]=src[1]; dest[2]=src[2]; 

/* sort so that a<=b */
#define SORT(a,b)       \
             if(a>b)    \
             {          \
               float c; \
               c=a;     \
               a=b;     \
               b=c;     \
             }

/* sort so that a<=b */
#define SORT2(a,b,smallest)       \
             if(a>b)       \
             {             \
               float c;    \
               c=a;        \
               a=b;        \
               b=c;        \
               smallest=1; \
             }             \
             else smallest=0;
                   
#define ISECT(VV0,VV1,VV2,D0,D1,D2,isect0,isect1) \
              isect0=VV0+(VV1-VV0)*D0/(D0-D1);    \
              isect1=VV0+(VV2-VV0)*D0/(D0-D2);


#define COMPUTE_INTERVALS(VV0,VV1,VV2,D0,D1,D2,D0D1,D0D2,isect0,isect1) \
  if(D0D1>0.0f)                                         \
  {                                                     \
    /* here we know that D0D2<=0.0 */                   \
    /* that is D0, D1 are on the same side, D2 on the other or on the plane */ \
    ISECT(VV2,VV0,VV1,D2,D0,D1,isect0,isect1);          \
  }                                                     \
  else if(D0D2>0.0f)                                    \
  {                                                     \
    /* here we know that d0d1<=0.0 */                   \
    ISECT(VV1,VV0,VV2,D1,D0,D2,isect0,isect1);          \
  }                                                     \
  else if(D1*D2>0.0f || D0!=0.0f)                       \
  {                                                     \
    /* here we know that d0d1<=0.0 or that D0!=0.0 */   \
    ISECT(VV0,VV1,VV2,D0,D1,D2,isect0,isect1);          \
  }                                                     \
  else if(D1!=0.0f)                                     \
  {                                                     \
    ISECT(VV1,VV0,VV2,D1,D0,D2,isect0,isect1);          \
  }                                                     \
  else if(D2!=0.0f)                                     \
  {                                                     \
    ISECT(VV2,VV0,VV1,D2,D0,D1,isect0,isect1);          \
  }                                                     \
  else                                                  \
  {                                                     \
    /* triangles are coplanar */                        \
    return coplanar_tri_tri(N1,V0,V1,V2,U0,U1,U2);      \
  }

/* this edge to edge test is based on Franlin Antonio's gem:
   "Faster Line Segment Intersection", in Graphics Gems III,
   pp. 199-202 */ 
#define EDGE_EDGE_TEST(V0,U0,U1)                      \
  Bx=U0[i0]-U1[i0];                                   \
  By=U0[i1]-U1[i1];                                   \
  Cx=V0[i0]-U0[i0];                                   \
  Cy=V0[i1]-U0[i1];                                   \
  f=Ay*Bx-Ax*By;                                      \
  d=By*Cx-Bx*Cy;                                      \
  if((f>0 && d>=0 && d<=f) || (f<0 && d<=0 && d>=f))  \
  {                                                   \
    e=Ax*Cy-Ay*Cx;                                    \
    if(f>0)                                           \
    {                                                 \
      if(e>=0 && e<=f) return 1;                      \
    }                                                 \
    else                                              \
    {                                                 \
      if(e<=0 && e>=f) return 1;                      \
    }                                                 \
  }                                

#define EDGE_AGAINST_TRI_EDGES(V0,V1,U0,U1,U2) \
{                                              \
  float Ax,Ay,Bx,By,Cx,Cy,e,d,f;               \
  Ax=V1[i0]-V0[i0];                            \
  Ay=V1[i1]-V0[i1];                            \
  /* test edge U0,U1 against V0,V1 */          \
  EDGE_EDGE_TEST(V0,U0,U1);                    \
  /* test edge U1,U2 against V0,V1 */          \
  EDGE_EDGE_TEST(V0,U1,U2);                    \
  /* test edge U2,U1 against V0,V1 */          \
  EDGE_EDGE_TEST(V0,U2,U0);                    \
}

#define POINT_IN_TRI(V0,U0,U1,U2)           \
{                                           \
  float a,b,c,d0,d1,d2;                     \
  /* is T1 completly inside T2? */          \
  /* check if V0 is inside tri(U0,U1,U2) */ \
  a=U1[i1]-U0[i1];                          \
  b=-(U1[i0]-U0[i0]);                       \
  c=-a*U0[i0]-b*U0[i1];                     \
  d0=a*V0[i0]+b*V0[i1]+c;                   \
                                            \
  a=U2[i1]-U1[i1];                          \
  b=-(U2[i0]-U1[i0]);                       \
  c=-a*U1[i0]-b*U1[i1];                     \
  d1=a*V0[i0]+b*V0[i1]+c;                   \
                                            \
  a=U0[i1]-U2[i1];                          \
  b=-(U0[i0]-U2[i0]);                       \
  c=-a*U2[i0]-b*U2[i1];                     \
  d2=a*V0[i0]+b*V0[i1]+c;                   \
  if(d0*d1>0.0)                             \
  {                                         \
    if(d0*d2>0.0) return 1;                 \
  }                                         \
}
  
inline void isect2(float VTX0[3],float VTX1[3],float VTX2[3],float VV0,float VV1,float VV2,
            float D0,float D1,float D2,float *isect0,float *isect1,float isectpoint0[3],float isectpoint1[3]) 
{
  float tmp=D0/(D0-D1);          
  float diff[3];
  *isect0=VV0+(VV1-VV0)*tmp;         
  SUB(diff,VTX1,VTX0);              
  MULT(diff,diff,tmp);               
  ADD(isectpoint0,diff,VTX0);        
  tmp=D0/(D0-D2);                    
  *isect1=VV0+(VV2-VV0)*tmp;          
  SUB(diff,VTX2,VTX0);                   
  MULT(diff,diff,tmp);                 
  ADD(isectpoint1,VTX0,diff);          
}

int coplanar_tri_tri(float N[3],float V0[3],float V1[3],float V2[3],
                     float U0[3],float U1[3],float U2[3])
{
   float A[3];
   short i0,i1;
   /* first project onto an axis-aligned plane, that maximizes the area */
   /* of the triangles, compute indices: i0,i1. */
   A[0]=fabs(N[0]);
   A[1]=fabs(N[1]);
   A[2]=fabs(N[2]);
   if(A[0]>A[1])
   {
      if(A[0]>A[2])  
      {
          i0=1;      /* A[0] is greatest */
          i1=2;
      }
      else
      {
          i0=0;      /* A[2] is greatest */
          i1=1;
      }
   }
   else   /* A[0]<=A[1] */
   {
      if(A[2]>A[1])
      {
          i0=0;      /* A[2] is greatest */
          i1=1;                                           
      }
      else
      {
          i0=0;      /* A[1] is greatest */
          i1=2;
      }
    }               
                
    /* test all edges of triangle 1 against the edges of triangle 2 */
    EDGE_AGAINST_TRI_EDGES(V0,V1,U0,U1,U2);
    EDGE_AGAINST_TRI_EDGES(V1,V2,U0,U1,U2);
    EDGE_AGAINST_TRI_EDGES(V2,V0,U0,U1,U2);
                
    /* finally, test if tri1 is totally contained in tri2 or vice versa */
    POINT_IN_TRI(V0,U0,U1,U2);
    POINT_IN_TRI(U0,V0,V1,V2);

    return 0;
}

inline int compute_intervals_isectline(float VERT0[3],float VERT1[3],float VERT2[3],
                                       float VV0,float VV1,float VV2,float D0,float D1,float D2,
                                       float D0D1,float D0D2,float *isect0,float *isect1,
                                       float isectpoint0[3],float isectpoint1[3])
{
  if(D0D1>0.0f)                                        
  {                                                    
    /* here we know that D0D2<=0.0 */                  
    /* that is D0, D1 are on the same side, D2 on the other or on the plane */
    isect2(VERT2,VERT0,VERT1,VV2,VV0,VV1,D2,D0,D1,isect0,isect1,isectpoint0,isectpoint1);
  } 
  else if(D0D2>0.0f)                                   
    {                                                   
    /* here we know that d0d1<=0.0 */             
    isect2(VERT1,VERT0,VERT2,VV1,VV0,VV2,D1,D0,D2,isect0,isect1,isectpoint0,isectpoint1);
  }                                                  
  else if(D1*D2>0.0f || D0!=0.0f)   
  {                                   
    /* here we know that d0d1<=0.0 or that D0!=0.0 */
    isect2(VERT0,VERT1,VERT2,VV0,VV1,VV2,D0,D1,D2,isect0,isect1,isectpoint0,isectpoint1);   
  }                                                  
  else if(D1!=0.0f)                                  
  {                                               
    isect2(VERT1,VERT0,VERT2,VV1,VV0,VV2,D1,D0,D2,isect0,isect1,isectpoint0,isectpoint1); 
  }                                         
  else if(D2!=0.0f)                                  
  {                                                   
    isect2(VERT2,VERT0,VERT1,VV2,VV0,VV1,D2,D0,D1,isect0,isect1,isectpoint0,isectpoint1);     
  }                                                 
  else                                               
  {                                                   
    /* triangles are coplanar */    
    return 1;
  }
  return 0;
}

int UTILITY::MollerTriTriIsectWithLine(float * V0, float * V1, float * V2,
                              float * U0, float * U1, float * U2, int * coplanar,
                              float * isectpt1, float * isectpt2)
{
  float E1[3],E2[3];
  float N1[3],N2[3],d1,d2;
  float du0,du1,du2,dv0,dv1,dv2;
  float D[3];
  float isect1[2], isect2[2];
  float isectpointA1[3],isectpointA2[3];
  float isectpointB1[3],isectpointB2[3];
  float du0du1,du0du2,dv0dv1,dv0dv2;
  short index;
  float vp0,vp1,vp2;
  float up0,up1,up2;
  float b,c,max;
//  float tmp,diff[3];
  int smallest1,smallest2;
  
  /* compute plane equation of triangle(V0,V1,V2) */
  SUB(E1,V1,V0);
  SUB(E2,V2,V0);
  CROSS(N1,E1,E2);
  d1=-DOT(N1,V0);
  /* plane equation 1: N1.X+d1=0 */

  /* put U0,U1,U2 into plane equation 1 to compute signed distances to the plane*/
  du0=DOT(N1,U0)+d1;
  du1=DOT(N1,U1)+d1;
  du2=DOT(N1,U2)+d1;

  /* coplanarity robustness check */
#if USE_EPSILON_TEST==TRUE
  if(fabs(du0)<EPSILON) du0=0.0;
  if(fabs(du1)<EPSILON) du1=0.0;
  if(fabs(du2)<EPSILON) du2=0.0;
#endif
  du0du1=du0*du1;
  du0du2=du0*du2;

  if(du0du1>0.0f && du0du2>0.0f) /* same sign on all of them + not equal 0 ? */
    return 0;                    /* no intersection occurs */

  /* compute plane of triangle (U0,U1,U2) */
  SUB(E1,U1,U0);
  SUB(E2,U2,U0);
  CROSS(N2,E1,E2);
  d2=-DOT(N2,U0);
  /* plane equation 2: N2.X+d2=0 */

  /* put V0,V1,V2 into plane equation 2 */
  dv0=DOT(N2,V0)+d2;
  dv1=DOT(N2,V1)+d2;
  dv2=DOT(N2,V2)+d2;

#if USE_EPSILON_TEST==TRUE
  if(fabs(dv0)<EPSILON) dv0=0.0;
  if(fabs(dv1)<EPSILON) dv1=0.0;
  if(fabs(dv2)<EPSILON) dv2=0.0;
#endif

  dv0dv1=dv0*dv1;
  dv0dv2=dv0*dv2;
        
  if(dv0dv1>0.0f && dv0dv2>0.0f) /* same sign on all of them + not equal 0 ? */
    return 0;                    /* no intersection occurs */

  /* compute direction of intersection line */
  CROSS(D,N1,N2);

  /* compute and index to the largest component of D */
  max=fabs(D[0]);
  index=0;
  b=fabs(D[1]);
  c=fabs(D[2]);
  if(b>max) max=b,index=1;
  if(c>max) max=c,index=2;

  /* this is the simplified projection onto L*/
  vp0=V0[index];
  vp1=V1[index];
  vp2=V2[index];
  
  up0=U0[index];
  up1=U1[index];
  up2=U2[index];

  /* compute interval for triangle 1 */
  *coplanar=compute_intervals_isectline(V0,V1,V2,vp0,vp1,vp2,dv0,dv1,dv2,
                                       dv0dv1,dv0dv2,&isect1[0],&isect1[1],isectpointA1,isectpointA2);
  if(*coplanar) return coplanar_tri_tri(N1,V0,V1,V2,U0,U1,U2);     


  /* compute interval for triangle 2 */
  compute_intervals_isectline(U0,U1,U2,up0,up1,up2,du0,du1,du2,
                              du0du1,du0du2,&isect2[0],&isect2[1],isectpointB1,isectpointB2);

  SORT2(isect1[0],isect1[1],smallest1);
  SORT2(isect2[0],isect2[1],smallest2);

  if(isect1[1]<isect2[0] || isect2[1]<isect1[0]) return 0;

  /* at this point, we know that the triangles intersect */

  if(isect2[0]<isect1[0])
  {
    if(smallest1==0) { SET(isectpt1,isectpointA1); }
    else { SET(isectpt1,isectpointA2); }

    if(isect2[1]<isect1[1])
    {
      if(smallest2==0) { SET(isectpt2,isectpointB2); }
      else { SET(isectpt2,isectpointB1); }
    }
    else
    {
      if(smallest1==0) { SET(isectpt2,isectpointA2); }
      else { SET(isectpt2,isectpointA1); }
    }
  }
  else
  {
    if(smallest2==0) { SET(isectpt1,isectpointB1); }
    else { SET(isectpt1,isectpointB2); }

    if(isect2[1]>isect1[1])
    {
      if(smallest1==0) { SET(isectpt2,isectpointA2); }
      else { SET(isectpt2,isectpointA1); }      
    }
    else
    {
      if(smallest2==0) { SET(isectpt2,isectpointB2); }
      else { SET(isectpt2,isectpointB1); } 
    }
  }
  return 1;
}

#define NEWCOMPUTE_INTERVALS(VV0,VV1,VV2,D0,D1,D2,D0D1,D0D2,A,B,C,X0,X1) \
{ \
        if(D0D1>0.0f) \
        { \
                /* here we know that D0D2<=0.0 */ \
            /* that is D0, D1 are on the same side, D2 on the other or on the plane */ \
                A=VV2; B=(VV0-VV2)*D2; C=(VV1-VV2)*D2; X0=D2-D0; X1=D2-D1; \
        } \
        else if(D0D2>0.0f)\
        { \
                /* here we know that d0d1<=0.0 */ \
            A=VV1; B=(VV0-VV1)*D1; C=(VV2-VV1)*D1; X0=D1-D0; X1=D1-D2; \
        } \
        else if(D1*D2>0.0f || D0!=0.0f) \
        { \
                /* here we know that d0d1<=0.0 or that D0!=0.0 */ \
                A=VV0; B=(VV1-VV0)*D0; C=(VV2-VV0)*D0; X0=D0-D1; X1=D0-D2; \
        } \
        else if(D1!=0.0f) \
        { \
                A=VV1; B=(VV0-VV1)*D1; C=(VV2-VV1)*D1; X0=D1-D0; X1=D1-D2; \
        } \
        else if(D2!=0.0f) \
        { \
                A=VV2; B=(VV0-VV2)*D2; C=(VV1-VV2)*D2; X0=D2-D0; X1=D2-D1; \
        } \
        else \
        { \
                /* triangles are coplanar */ \
                return coplanar_tri_tri(N1,V0,V1,V2,U0,U1,U2); \
        } \
}

#define FABS(x) ((float)fabs(x))

int NoDivTriTriIsect(float V0[3],float V1[3],float V2[3],
                     float U0[3],float U1[3],float U2[3])
{
  float E1[3],E2[3];
  float N1[3],N2[3],d1,d2;
  float du0,du1,du2,dv0,dv1,dv2;
  float D[3];
  float isect1[2], isect2[2];
  float du0du1,du0du2,dv0dv1,dv0dv2;
  short index;
  float vp0,vp1,vp2;
  float up0,up1,up2;
  float bb,cc,max;
  float a,b,c,x0,x1;
  float d,e,f,y0,y1;
  float xx,yy,xxyy,tmp;

  /* compute plane equation of triangle(V0,V1,V2) */
  SUB(E1,V1,V0);
  SUB(E2,V2,V0);
  CROSS(N1,E1,E2);
  d1=-DOT(N1,V0);
  /* plane equation 1: N1.X+d1=0 */

  /* put U0,U1,U2 into plane equation 1 to compute signed distances to the plane*/
  du0=DOT(N1,U0)+d1;
  du1=DOT(N1,U1)+d1;
  du2=DOT(N1,U2)+d1;

  /* coplanarity robustness check */
#if USE_EPSILON_TEST==TRUE
  if(FABS(du0)<EPSILON) du0=0.0;
  if(FABS(du1)<EPSILON) du1=0.0;
  if(FABS(du2)<EPSILON) du2=0.0;
#endif
  du0du1=du0*du1;
  du0du2=du0*du2;

  if(du0du1>0.0f && du0du2>0.0f) /* same sign on all of them + not equal 0 ? */
    return 0;                    /* no intersection occurs */

  /* compute plane of triangle (U0,U1,U2) */
  SUB(E1,U1,U0);
  SUB(E2,U2,U0);
  CROSS(N2,E1,E2);
  d2=-DOT(N2,U0);
  /* plane equation 2: N2.X+d2=0 */

  /* put V0,V1,V2 into plane equation 2 */
  dv0=DOT(N2,V0)+d2;
  dv1=DOT(N2,V1)+d2;
  dv2=DOT(N2,V2)+d2;

#if USE_EPSILON_TEST==TRUE
  if(FABS(dv0)<EPSILON) dv0=0.0;
  if(FABS(dv1)<EPSILON) dv1=0.0;
  if(FABS(dv2)<EPSILON) dv2=0.0;
#endif

  dv0dv1=dv0*dv1;
  dv0dv2=dv0*dv2;

  if(dv0dv1>0.0f && dv0dv2>0.0f) /* same sign on all of them + not equal 0 ? */
    return 0;                    /* no intersection occurs */

  /* compute direction of intersection line */
  CROSS(D,N1,N2);

  /* compute and index to the largest component of D */
  max=(float)FABS(D[0]);
  index=0;
  bb=(float)FABS(D[1]);
  cc=(float)FABS(D[2]);
  if(bb>max) max=bb,index=1;
  if(cc>max) max=cc,index=2;

  /* this is the simplified projection onto L*/
  vp0=V0[index];
  vp1=V1[index];
  vp2=V2[index];

  up0=U0[index];
  up1=U1[index];
  up2=U2[index];

  /* compute interval for triangle 1 */
  NEWCOMPUTE_INTERVALS(vp0,vp1,vp2,dv0,dv1,dv2,dv0dv1,dv0dv2,a,b,c,x0,x1);

  /* compute interval for triangle 2 */
  NEWCOMPUTE_INTERVALS(up0,up1,up2,du0,du1,du2,du0du1,du0du2,d,e,f,y0,y1);

  xx=x0*x1;
  yy=y0*y1;
  xxyy=xx*yy;

  tmp=a*xxyy;
  isect1[0]=tmp+b*x1*yy;
  isect1[1]=tmp+c*x0*yy;

  tmp=d*xxyy;
  isect2[0]=tmp+e*xx*y1;
  isect2[1]=tmp+f*xx*y0;

  SORT(isect1[0],isect1[1]);
  SORT(isect2[0],isect2[1]);

  if(isect1[1]<isect2[0] || isect2[1]<isect1[0]) return 0;
  return 1;
}

int UTILITY::BruteForceTriangleIntersectionF(VERTEX * tri1, VERTEX * tri2, 
                              VERTEX & colpt, VERTEX & coldest, VERTEX & colorig, int & whichtri)
{
      //could do a simple test here to speed things up a bit:
      // find the distance from tri2 to tri1's plane, return false if all
      // distances are positive or negative, do the same for tri1 on tri2's plane
      
      int col = NoDivTriTriIsect(tri1[0].v3(), tri1[1].v3(), tri1[2].v3(), 
            tri2[0].v3(), tri2[1].v3(), tri2[2].v3());
      
      if (!col)
            return col;
      
      col = 0;
      
      //collide all tri1 edges to tri2 and vice versa
      VERTEX * edgetri = tri1;
      VERTEX * coltri = tri2;
      int i = 0;
      VERTEX segment;
      VERTEX dir;
      int i0;
      float t, u, v;
      for (i = 0; i < 6; i++)
      {
            if (i == 3)
            {
                  edgetri = tri2;
                  coltri = tri1;
            }
            
            i0 = i % 3;
            
            segment = edgetri[(i0+1)%3]-edgetri[i0];
            dir = segment.normalize();
      
            col = IntersectTriangleF(edgetri[i0].v3(), dir.v3(),
                   coltri[0].v3(), coltri[1].v3(), coltri[2].v3(),
                   &t, &u, &v);
            
            if (t > segment.len() || t < 0)
                  col = 0;
            
            if (col)
            {
                  whichtri = 1 - i / 3;
                  colorig = edgetri[i0];
                  colpt = edgetri[i0] + dir.ScaleR(t);
                  //colseg = edgetri[(i0+1)%3] - colpt;
                  coldest = edgetri[(i0+1)%3];
                  return col;
            }
      }
      
      return col;
}

VERTEX NormalFromTri(VERTEX * tri)
{
      VERTEX norm;
      norm = (tri[2] - tri[0]).cross(tri[1] - tri[0]);
      norm = norm.normalize();
      return norm;
}

//float PointToTriDistance(VERTEX * tri, VERTEX norm, float d, VERTEX point)
float PointToTriDistance(VERTEX norm, float d, VERTEX point)
{
      //float d = -norm.x*tri[0].x-norm.y*tri[0].y-norm.z*tri[0].z;
      
      //point = point - tri[0];
      
      float num, denom;
      num = norm.x*point.x+norm.y*point.y+norm.z*point.z+d;
      //denom = sqrt(norm.x*norm.x+norm.y*norm.y+norm.z*norm.z);
      denom = 1.0f;
      
      return num / denom;
}

int UTILITY::BruteForceTriangleIntersectionF2(VERTEX * tri1, VERTEX * tri2, 
                              VERTEX & colpt, VERTEX & coldest, VERTEX & colorig, int & whichtri,
                              float & destdepth, float & origdepth)
{
      //could do a simple test here to speed things up a bit:
      // find the distance from tri2 to tri1's plane, return false if all
      // distances are positive or negative, do the same for tri1 on tri2's plane
      
      int col = NoDivTriTriIsect(tri1[0].v3(), tri1[1].v3(), tri1[2].v3(), 
            tri2[0].v3(), tri2[1].v3(), tri2[2].v3());
      
      if (!col)
            return col;
      
      VERTEX norm1 = NormalFromTri(tri1);
      VERTEX norm2 = NormalFromTri(tri2);
      
      //load up all point to triangle distances
      
      float d1 = -norm1.x*tri1[0].x-norm1.y*tri1[0].y-norm1.z*tri1[0].z;
      float d2 = -norm2.x*tri2[0].x-norm2.y*tri2[0].y-norm2.z*tri2[0].z;
      
      /*float tri1to2[3];
      float tri2to1[3];
      
      for (int i = 0; i < 3; i++)
            tri1to2[3] = PointToTriDistance(tri2, norm2, d2, tri1[i]);
      
      for (int i = 0; i < 3; i++)
            tri2to1[3] = PointToTriDistance(tri1, norm1, d1, tri2[i]);
      
      whichtri = 1;
      
      //find which group of depths crosses zero
      if ((tri1to2[0] < 0 && tri1to2[1] < 0 && tri1to2[2] < 0) ||
            (tri1to2[0] > 0 && tri1to2[1] > 0 && tri1to2[2] > 0))
      {
            if ((tri2to1[0] < 0 && tri2to1[1] < 0 && tri2to1[2] < 0) ||
                  (tri2to1[0] > 0 && tri2to1[1] > 0 && tri2to1[2] > 0))
                        return col;
            else
            {
                  whichtri = 0;
            }
      }
      else
      {
            whichtri = 1;
      }
      
      //use whatever depths cross zero
      VERTEX * depths = tri1to2;
      if (whichtri == 0)
            depths = tri2to1;
      
      //find the extreme values that cross zero
      int idxmin = 0;
      int idxmax = 0;
      float min = 0;
      float max = 0;
      for (int i = 0; i < 3; i++)
      {
            if (depths[i] < min)
            {
                  min = depths[i];
                  idxmin = i;
            }
            if (depths[i] > max)
            {
                  max = depths[i];
                  idxmax = i;
            }
      }
      
      if (whichtri == 0)
      {
            //colpt = 
      }
      if (whichtri == 1)
      {
            //colpt = tri1[idxmin]
            //colorig.Set(-d2/norm2.x,-d2/norm2.y,-d2/norm2.z);
            colorig = tri1[idxmin];
            coldest = tri1[idxmax];
      }
      
      return col;*/
      
      col = 0;
      
      //collide all tri1 edges to tri2 and vice versa
      VERTEX * edgetri = tri1;
      VERTEX * coltri = tri2;
      int i = 0;
      VERTEX segment;
      VERTEX dir;
      int i0;
      float t, u, v;
      for (i = 0; i < 6; i++)
      {
            if (i == 3)
            {
                  edgetri = tri2;
                  coltri = tri1;
            }
            
            i0 = i % 3;
            
            segment = edgetri[(i0+1)%3]-edgetri[i0];
            dir = segment.normalize();
      
            col = IntersectTriangleF(edgetri[i0].v3(), dir.v3(),
                   coltri[0].v3(), coltri[1].v3(), coltri[2].v3(),
                   &t, &u, &v);
            
            if (t > segment.len() || t < 0)
                  col = 0;
            
            if (col)
            {
                  whichtri = 1 - i / 3;
                  float d = d2;
                  VERTEX n = norm2;
                  if (whichtri == 0)
                  {
                        d = d1;
                        n = norm1;
                  }
                  colorig = edgetri[i0];
                  colpt = edgetri[i0] + dir.ScaleR(t);
                  //colseg = edgetri[(i0+1)%3] - colpt;
                  coldest = edgetri[(i0+1)%3];
                  
                  destdepth = PointToTriDistance(n, d, coldest);
                  origdepth = PointToTriDistance(n, d, colorig);
                  
                  if (destdepth < 0)
                        destdepth = -destdepth;
                  if (origdepth < 0)
                        origdepth = -origdepth;
                  
                  return col;
            }
      }
      
      return col;
}

bool UTILITY::FileCopy( const string & srcfile, const string & dstfile ) const
{
      ifstream src(srcfile.c_str(), ios_base::binary);
      ofstream dst(dstfile.c_str(), ios_base::binary);
      
      if (!src || !dst)
            return false;
      
      char c;
      while (src.get(c))
            dst.put(c);
      
      return true;
}

string UTILITY::GetPathFromFilename(string filename)
{
      unsigned int pos = filename.find_last_of("/\\");
      if (pos < filename.length())
            return filename.substr(0,pos);
      else
            return "";
}

bool UTILITY::isNaN(float val)
{
      return (!(val <= 0 || val > 0));
}

bool UTILITY::GetFolderIndex(string folderpath, list <string> & outputfolderlist)
{
      //------Folder listing code for POSIX
      #ifndef _WIN32
      DIR *dp;
      struct dirent *ep;
      dp = opendir (folderpath.c_str());
      if (dp != NULL)
      {
            while ( ( ep = readdir( dp ) ) )
            {
                  //puts (ep->d_name);
                  string newname = ep->d_name;
                  if (newname != "." && newname != "..")
                  {
                        outputfolderlist.push_back(newname);
                  }
            }
            (void) closedir (dp);
      }
      else
            return false;
      #else       //------End POSIX-specific folder listing code ---- Start WIN32 Specific code
      HANDLE          hList;
      TCHAR           szDir[MAX_PATH+1];
      WIN32_FIND_DATA FileData;

      // Get the proper directory path
      sprintf(szDir, "%s\\*", folderpath.c_str ());

      // Get the first file
      hList = FindFirstFile(szDir, &FileData);
      if (hList == INVALID_HANDLE_VALUE)
      { 
            printf("No files found\n\n");
      }
      else
      {
            // Traverse through the directory structure
            while (FindNextFile(hList, &FileData))
            {
                  // Check the object is a directory or not
                  if (FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                  {
                        if (FileData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
                        } else {             
                              if ((strcmp(FileData.cFileName, ".") != 0) &&
                                 (strcmp(FileData.cFileName, "..") != 0))
                              {
                                    outputfolderlist.push_back (FileData.cFileName);
                              }
                        }
                  }
            }
      }

      FindClose(hList);
      #endif //------End WIN32 specific folder listing code
      
      return true;
}

Generated by  Doxygen 1.6.0   Back to index