/**********************************************************************
This file is part of Crack dot Com's free source code release of Golgotha.
for information about compiling & licensing issues visit this URL
 If that doesn't help, contact Jonathan Clark at 
  golgotha_source@usa.net (Subject should have "GOLG" in it) 
***********************************************************************/

#include "frustrum_clip.hh"
#include "poly/poly.hh"
#include "math/num_type.hh"
#include "clip.hh"

#define F_NEXT(i,j) ( ((i+1)==(j))?(0):(i+1) )
#define F_PREV(i,j) ( ((i)==(0))?(j-1):(i-1) )

#include "arch.hh"
#include "math/num_type.hh"
#include "frustrum_clip.hh"
#include "poly/poly.hh"

i4_polygon_class *g1_full_clip(i4_polygon_class *src, 
                               i4_polygon_class *dest,
                               w32 center_x, w32 center_y)
{
  w32 ORCODE  = 0;
  w32 ANDCODE = 0xffffffff;
  w32 i,j,c0,c1;
  w32 bitmask;
  i4_float ooz,dx,dy,dz,ds,dt,dr,dg,db,da,t;
  i4_polygon_class *temp;
  i4_vertex_class *v,clippoint;    
  
  dest->t_verts=0;
  
  for (i=0; it_verts; i++)
  {    
    v = &src->vert[i];
    v->outcode = g1_calc_clip_code(v->v, 0.01f, 0, i4_F);

    ORCODE  |= v->outcode;
    ANDCODE &= v->outcode;      
    if (!v->outcode)
    {
      ooz = r1_ooz(v->v.z);
      v->w  = ooz;
      v->px = ((v->v.x * ooz) * center_x) + center_x;
      v->py = ((v->v.y * ooz) * center_y) + center_y;        
    }
  }
  
  //all verts are outside one of the view planes
  //return a poly with 0 vertices
  if (ANDCODE)
  {
    dest->t_verts=0;
    return dest;
  }
  
  if (!ORCODE)
  {
    return src;
  }
  
  for (bitmask=16;bitmask;bitmask=bitmask>>1)
  {
    if ((bitmask&ORCODE)==0) continue;
    
    for (i=0;it_verts;i++)
    {			
      
      j  = F_NEXT(i,src->t_verts);
      
      c0 = bitmask & src->vert[i].outcode;
      c1 = bitmask & src->vert[j].outcode;
      
      //if c0 is not outside of this plane,
      //add it
      if (c0==0) {
        dest->add_vert(&src->vert[i]);
      }
      
      //if they are on the same
      //side, move to the next vert
      if (c0==c1) continue;
      
      //otherwise, generate a clipped
      //point
      
      dx = src->vert[j].v.x - src->vert[i].v.x;
      dy = src->vert[j].v.y - src->vert[i].v.y;
      dz = src->vert[j].v.z - src->vert[i].v.z;
      ds = src->vert[j].s - src->vert[i].s;
      dt = src->vert[j].t - src->vert[i].t;
      dr = src->vert[j].r - src->vert[i].r;
      dg = src->vert[j].g - src->vert[i].g;
      db = src->vert[j].b - src->vert[i].b;
      da = src->vert[j].a - src->vert[i].a;
      
      

      switch (bitmask) {
        case 1:  t = (-src->vert[i].v.x + src->vert[i].v.z) / ( dx - dz);                  
                 clippoint.v.y = src->vert[i].v.y + (t * dy);
                 clippoint.v.z = src->vert[i].v.z + (t * dz);
                 
                 clippoint.v.x = clippoint.v.z;
                 break;

        case 2:  t = ( src->vert[i].v.x + src->vert[i].v.z) / (-dx - dz);                  
                 clippoint.v.y = src->vert[i].v.y + (t * dy);
                 clippoint.v.z = src->vert[i].v.z + (t * dz);
                 
                 clippoint.v.x = -clippoint.v.z;
                 break;
        
        case 4:  t = (-src->vert[i].v.y + src->vert[i].v.z) / ( dy - dz);
                 clippoint.v.x = src->vert[i].v.x + (t * dx);                 
                 clippoint.v.z = src->vert[i].v.z + (t * dz);
                 
                 clippoint.v.y = clippoint.v.z;
                 break;
        
        case 8:  t = ( src->vert[i].v.y + src->vert[i].v.z) / (-dy - dz);
                 clippoint.v.x = src->vert[i].v.x + (t * dx);                 
                 clippoint.v.z = src->vert[i].v.z + (t * dz);
                 
                 clippoint.v.y = -clippoint.v.z; 
                 break;

        case 16: t = (0.01 - src->vert[i].v.z) / (dz);		                
                 clippoint.v.x = src->vert[i].v.x + (t * dx);
                 clippoint.v.y = src->vert[i].v.y + (t * dy);
                 
                 clippoint.v.z = 0.01;
                 break;
      }
      
      clippoint.s = src->vert[i].s + (t * ds);
      clippoint.t = src->vert[i].t + (t * dt);
      clippoint.r = src->vert[i].r + (t * dr);
      clippoint.g = src->vert[i].g + (t * dg);
      clippoint.b = src->vert[i].b + (t * db);
      clippoint.a = src->vert[i].a + (t * da);
      
      // no far clip
      clippoint.outcode = g1_calc_clip_code(clippoint.v, 0.01f, 0, i4_F);

      if (!clippoint.outcode)
      {
        ooz = r1_ooz(clippoint.v.z);        
        clippoint.px = ((clippoint.v.x * ooz) * center_x) + center_x;
        clippoint.py = ((clippoint.v.y * ooz) * center_y) + center_y;          
        clippoint.w  = ooz;
      }  
      ORCODE |= clippoint.outcode;
      
      dest->add_vert(&clippoint);      
    }
    
    temp = src;
    src = dest;
    dest = temp;
    dest->t_verts = 0;
  }
  return src;
}

i4_polygon_class *g1_fast_full_clip(i4_polygon_class *src, 
                                    i4_polygon_class *dest,
                                    w32 center_x, w32 center_y)
{
  w32 ORCODE  = 0;    
  w32 i,j,c0,c1;
  w32 bitmask;
  i4_float ooz,dx,dy,dz,ds,dt,dr,da,t;
  i4_polygon_class *temp;
  i4_vertex_class *v,clippoint;    
  
  dest->t_verts=0;
  
  for (i=0; it_verts; i++)
  {      
    v = &src->vert[i];
    v->outcode = g1_calc_clip_code(v->v, 0.01f, 0, i4_F);

    ORCODE |= v->outcode;    
  }
  
  for (bitmask=16;bitmask;bitmask=bitmask>>1)
  {
    if ((bitmask&ORCODE)==0) continue;
    
    for (i=0;it_verts;i++)
    {			
      
      j  = F_NEXT(i,src->t_verts);
      
      c0 = bitmask & src->vert[i].outcode;
      c1 = bitmask & src->vert[j].outcode;
      
      //if c0 is not outside of this plane,
      //add it
      if (c0==0) {
        dest->add_vert(&src->vert[i]);
      }
      
      //if they are on the same
      //side, move to the next vert
      if (c0==c1) continue;
      
      //otherwise, generate a clipped
      //point
      
      dx = src->vert[j].v.x - src->vert[i].v.x;
      dy = src->vert[j].v.y - src->vert[i].v.y;
      dz = src->vert[j].v.z - src->vert[i].v.z;
      ds = src->vert[j].s - src->vert[i].s;
      dt = src->vert[j].t - src->vert[i].t;
      dr = src->vert[j].r - src->vert[i].r;
      da = src->vert[j].a - src->vert[i].a;

      switch (bitmask) {
        case 1:  t = (-src->vert[i].v.x + src->vert[i].v.z) / ( dx - dz);                  
                 clippoint.v.y = src->vert[i].v.y + (t * dy);
                 clippoint.v.z = src->vert[i].v.z + (t * dz);
                 
                 clippoint.v.x = clippoint.v.z;
                 break;

        case 2:  t = ( src->vert[i].v.x + src->vert[i].v.z) / (-dx - dz);                  
                 clippoint.v.y = src->vert[i].v.y + (t * dy);
                 clippoint.v.z = src->vert[i].v.z + (t * dz);
                 
                 clippoint.v.x = -clippoint.v.z;
                 break;
        
        case 4:  t = (-src->vert[i].v.y + src->vert[i].v.z) / ( dy - dz);
                 clippoint.v.x = src->vert[i].v.x + (t * dx);                 
                 clippoint.v.z = src->vert[i].v.z + (t * dz);
                 
                 clippoint.v.y = clippoint.v.z;
                 break;
        
        case 8:  t = ( src->vert[i].v.y + src->vert[i].v.z) / (-dy - dz);
                 clippoint.v.x = src->vert[i].v.x + (t * dx);
                 clippoint.v.y = src->vert[i].v.y + (t * dy);
                 clippoint.v.z = src->vert[i].v.z + (t * dz);
                 
                 clippoint.v.y = -clippoint.v.z; 
                 break;

        case 16: t = (0.01 - src->vert[i].v.z) / (dz);		                
                 clippoint.v.x = src->vert[i].v.x + (t * dx);
                 clippoint.v.y = src->vert[i].v.y + (t * dy);
                 
                 clippoint.v.z = 0.01;
                 break;
      }
      
      clippoint.s = src->vert[i].s + (t * ds);
      clippoint.t = src->vert[i].t + (t * dt);
      clippoint.r = src->vert[i].r + (t * dr);
      
      clippoint.outcode =  g1_calc_clip_code(clippoint.v, 0.01f, 0, i4_F);

      if (!clippoint.outcode)
      {
        ooz = r1_ooz(clippoint.v.z);
        clippoint.px = ((clippoint.v.x * ooz) * center_x) + center_x;
        clippoint.py = ((clippoint.v.y * ooz) * center_y) + center_y;              
        clippoint.w  = ooz;
      }
      
      ORCODE |= clippoint.outcode;
      
      dest->add_vert(&clippoint);      
    }
    
    temp = src;
    src = dest;
    dest = temp;
    dest->t_verts = 0;
  }
  return src;
}

//only clips x,y,z
i4_polygon_class *g1_geometric_clip(i4_polygon_class *src, 
                                    i4_polygon_class *dest,
                                    w32 center_x, w32 center_y)
{
  w32 ORCODE  = 0;
  w32 ANDCODE = 0xffffffff;
  w32 i,j,c0,c1;
  w32 bitmask;
  i4_float ooz,dx,dy,dz,t;
  i4_polygon_class *temp;
  i4_vertex_class *v,clippoint;    
  
  dest->t_verts=0;
  
  for (i=0; it_verts; i++)
  {    
    v = &src->vert[i];
    v->outcode = g1_calc_clip_code(v->v, 0.01f, 0, i4_F);

    ORCODE  |= v->outcode;
    ANDCODE &= v->outcode;      
    if (!v->outcode)
    {
      ooz = r1_ooz(v->v.z);
      v->px = ((v->v.x * ooz) * center_x) + center_x;
      v->py = ((v->v.y * ooz) * center_y) + center_y;
      v->w  = ooz;
    }
  }
  
  //all verts are outside one of the view planes
  //return a poly with 0 vertices
  if (ANDCODE)
  {
    dest->t_verts=0;
    return dest;
  }
  
  if (!ORCODE)
  {
    return src;
  }
  
  for (bitmask=16;bitmask;bitmask=bitmask>>1)
  {
    if ((bitmask&ORCODE)==0) continue;
    
    for (i=0;it_verts;i++)
    {			
      
      j  = F_NEXT(i,src->t_verts);
      
      c0 = bitmask & src->vert[i].outcode;
      c1 = bitmask & src->vert[j].outcode;
      
      //if c0 is not outside of this plane,
      //add it
      if (c0==0) {
        dest->add_vert(&src->vert[i]);
      }
      
      //if they are on the same
      //side, move to the next vert
      if (c0==c1) continue;
      
      //otherwise, generate a clipped
      //point
      
      dx = src->vert[j].v.x - src->vert[i].v.x;
      dy = src->vert[j].v.y - src->vert[i].v.y;
      dz = src->vert[j].v.z - src->vert[i].v.z;
      
      switch (bitmask) {
        case 1:  t = (-src->vert[i].v.x + src->vert[i].v.z) / ( dx - dz);                  
                 clippoint.v.y = src->vert[i].v.y + (t * dy);
                 clippoint.v.z = src->vert[i].v.z + (t * dz);
                 
                 clippoint.v.x = clippoint.v.z;
                 break;

        case 2:  t = ( src->vert[i].v.x + src->vert[i].v.z) / (-dx - dz);                  
                 clippoint.v.y = src->vert[i].v.y + (t * dy);
                 clippoint.v.z = src->vert[i].v.z + (t * dz);
                 
                 clippoint.v.x = -clippoint.v.z;
                 break;
        
        case 4:  t = (-src->vert[i].v.y + src->vert[i].v.z) / ( dy - dz);
                 clippoint.v.x = src->vert[i].v.x + (t * dx);                 
                 clippoint.v.z = src->vert[i].v.z + (t * dz);
                 
                 clippoint.v.y = clippoint.v.z;
                 break;
        
        case 8:  t = ( src->vert[i].v.y + src->vert[i].v.z) / (-dy - dz);
                 clippoint.v.x = src->vert[i].v.x + (t * dx);
                 clippoint.v.y = src->vert[i].v.y + (t * dy);
                 clippoint.v.z = src->vert[i].v.z + (t * dz);
                 
                 clippoint.v.y = -clippoint.v.z; 
                 break;

        case 16: t = (0.01 - src->vert[i].v.z) / (dz);		                
                 clippoint.v.x = src->vert[i].v.x + (t * dx);
                 clippoint.v.y = src->vert[i].v.y + (t * dy);
                 
                 clippoint.v.z = 0.01;
                 break;
      }
            
      clippoint.outcode = g1_calc_clip_code(v->v, 0.01f, 0, i4_F);

      if (!clippoint.outcode)
      {
        ooz = r1_ooz(clippoint.v.z);
        clippoint.px = ((clippoint.v.x * ooz) * center_x) + center_x;
        clippoint.py = ((clippoint.v.y * ooz) * center_y) + center_y;              
        clippoint.w  = ooz;
      }
      
      ORCODE |= clippoint.outcode;
      
      dest->add_vert(&clippoint);      
    }
    
    temp = src;
    src = dest;
    dest = temp;
    dest->t_verts = 0;
  }
  return src;
}