// -*- Mode: c++ -*-
// $Id: utils.C,v 1.1 1998/02/10 17:45:06 neel Exp $
// $Source: /u2/graphics/projects/6.838/gvis/gprims/utils.C,v $

static char
__rcs_ref_util_c( void )
{
  static char rcs_id_c[] = "$Header: /u2/graphics/projects/6.838/gvis/gprims/utils.C,v 1.1 1998/02/10 17:45:06 neel Exp $";
  return rcs_id_c[0];
}
// do not edit anything above this line
static char avoid_stupid_compiler_warnings = __rcs_ref_util_c();

#include <iostream.h>
#include <stdlib.h>
#include <math.h>
#include "utils.H"
#include "constants.H"

// using a fixed epsilon for point/plane 
// classification, regardless of the distance
// from the origin of the plane and point in
// question, is a bad idea.  here we just bump
// up the epsilon to make the plane IN slab
// that much thicker, and reduce false negatives
// in which a point IN or ABOVE the plane is
// classified as BELOW, and vice versa.
// what is needed is an epsilon that depends on d.
// since m_eps_f is 6 x 10-8, 100eps = 600 x 10-8 = 6 x 10-6
float __negeps_f = -100 * m_eps_f;
float __poseps_f =  100 * m_eps_f;

int
nan( const float &x, const int verbose )
{
#if __sgi
  if( x == x ) return 0;
#else
  assert( 0 );
#endif // __sgi
  
  if( verbose ) cerr << "found NaN at " << ( int )&x << "!" << endl;
  
  return 1;
}

// should be called only for positive powers of two
int 
logbasetwo( int x )
{
  int ret = 0;
  
  // must be positive
  assert( x > 0 );
  while( !(x & 1) ){
    x >>= 1;
    ret++;
  }
  
  // must have been a power of two
  assert( x == 1 );
  return ret;
}

// true if x >=0 and x is a power of two
int 
ispoweroftwo( int x )
{
  if( !x ) return 1;
  assert( x > 0 );
  while( !(x & 1) )
    x >>= 1;
  return x == 1;
}

// given x, returns 2^ceil(log_2 x)
int 
nextpoweroftwo( int x )
{
  if( !x ) return 0;
  assert( x > 0 );
  
  int ret = 1;
  while( ret < x )
    ret <<= 1;
  return ret;
}

// align to given block size
int
align( const int nbytes, const int wordsize )
{
  int nmodw = nbytes % wordsize;
  
  return !nmodw ? nbytes : nbytes + ( wordsize - nmodw );
}

float
det22 (
       float a, float b,
       float c, float d)
{
  float rval;
  
  rval = (a * d - b * c);
  return (rval);
}

float
det33 (
       float a, float b, float c, 
       float d, float e, float f, 
       float g, float h, float i)
{
  float rval;
  
  rval = (a * (e * i - h * f) - b * (d * i - g * f) + c * (d * h - g * e));
  
  return (rval);
}

float
det44 (
       float a, float b, float c, float d, 
       float e, float f, float g, float h, 
       float i, float j, float k, float l, 
       float m, float n, float o, float p)
{
  float rval = 0.0;
  
  rval += a * det33(f,g,h,j,k,l,n,o,p);
  rval -= b * det33(e,g,h,i,k,l,m,o,p);
  rval += c * det33(e,f,h,i,j,l,m,n,p);
  rval -= d * det33(e,f,g,i,j,k,m,n,o);
  
  return (rval);
}



/* generate a random, non-primary color */
void 
randomColor ( float *rgbcol )
{
  short rr, rg, rb;
  short d_rg, d_gb, d_br, d_min, c_sum;
  
  do {
    rb = 64 + rand() % 192;
    rg = 64 + rand() % 192;
    rr = 64 + rand() % 192;
    
    d_rg = (rg > rr) ? (rg - rr) : (rr - rg);
    d_gb = (rg > rb) ? (rg - rb) : (rb - rg);
    d_br = (rb > rr) ? (rb - rr) : (rr - rb);
    
    d_min = minf (d_rg, minf (d_gb, d_br));
    c_sum = rr + rg + rb;
  } while ((d_min <= 16) || (c_sum < 240));
  
  rgbcol[0] = rb / 255.0; // blue
  rgbcol[1] = rg / 255.0; // green
  rgbcol[2] = rr / 255.0; // red
}
