/* triangle.c */


/*
 * New triangle rasterizer.  This isn't used yet but may be in the future...
 */


#include <assert.h>
#include <stdio.h>
#include "context.h"
#include "dd.h"
#include "interp.h"
#include "span.h"
#include "vb.h"



#define SWAP( A, B, TMP )  { TMP = A;  A = B;  B = TMP; }


#define LINTERP( T, A, B )  ( (A) + (T) * ((B) - (A)) )




static void trap_z_monocolor( GLint y0, GLint y1,
			   GLfloat lx, GLfloat dlx,   GLfloat rx, GLfloat drx,
			   GLfloat lz, GLfloat dlz,   GLfloat rz, GLfloat drz,
			   GLfloat color[4] )
{
   GLint y;

   printf("trap slopes: %f %f\n", dlx, drx );

   for (y=y0;y<y1;y++) {
      /* span at y from lx to rx */
      GLint x0 = (GLint) (lx+0.5);
      GLint x1 = (GLint) (rx-0.5);
      GLint len = x1-x0+1;
      if (len>0) {
	 GLint red[MAX_WIDTH], green[MAX_WIDTH], blue[MAX_WIDTH];
	 GLint alpha[MAX_WIDTH], zspan[MAX_WIDTH];
	 GLfloat dzdx = (rz-lz) / (rx-lx);
	 GLfloat lfudge = (x0 + 0.5 - lx) * dzdx;
	 GLfloat rfudge = (x1 + 0.5 - rx) * dzdx;
	 GLint z0 = (GLint) ((lz+lfudge) * DEPTH_SCALE);
	 GLint z1 = (GLint) ((rz+rfudge) * DEPTH_SCALE);
	 GL_INTERPOLATE_I( len, z0, z1, zspan );
	 gl_write_monocolor_span( len, x0, y, zspan, color, GL_POLYGON );
      }
      lx += dlx;   rx += drx;
      lz += dlz;   rz += drz;
   }
}





/*
 * Newest as of Jun 13, 1995
 */
void gl_triangle4( GLuint v0, GLuint v1, GLuint v2, GLuint pv )
{
   GLuint min, mid, max;
   GLint ymin, ymid, ymax;
   GLfloat dy_mid_min, dy_max_min, dy_max_mid;
   GLfloat X[1000], Y[1000], Z[1000];

#ifdef TRUNC
   X[v0] = (GLfloat) (VB.WinX[v0] >> SUB_PIX_SHIFT);
   Y[v0] = (GLfloat) (VB.WinY[v0] >> SUB_PIX_SHIFT);
   Z[v0] = (GLfloat) VB.WinZ[v0];

   X[v1] = (GLfloat) (VB.WinX[v1] >> SUB_PIX_SHIFT);
   Y[v1] = (GLfloat) (VB.WinY[v1] >> SUB_PIX_SHIFT);
   Z[v1] = (GLfloat) VB.WinZ[v1];

   X[v2] = (GLfloat) (VB.WinX[v2] >> SUB_PIX_SHIFT);
   Y[v2] = (GLfloat) (VB.WinY[v2] >> SUB_PIX_SHIFT);
   Z[v2] = (GLfloat) VB.WinZ[v2];
#endif
#ifdef TRUNC2
   X[v0] = (GLfloat) (VB.WinX[v0] >> 6) / 4.0;
   Y[v0] = (GLfloat) (VB.WinY[v0] >> 6) / 4.0;
   Z[v0] = (GLfloat) VB.WinZ[v0];

   X[v1] = (GLfloat) (VB.WinX[v1] >> 6) / 4.0;
   Y[v1] = (GLfloat) (VB.WinY[v1] >> 6) / 4.0;
   Z[v1] = (GLfloat) VB.WinZ[v1];

   X[v2] = (GLfloat) (VB.WinX[v2] >> 6) / 4.0;
   Y[v2] = (GLfloat) (VB.WinY[v2] >> 6) / 4.0;
   Z[v2] = (GLfloat) VB.WinZ[v2];
#endif
#define NORM
#ifdef NORM
   X[v0] = VB.WinX[v0] / SUB_PIX_SCALE;
   Y[v0] = VB.WinY[v0] / SUB_PIX_SCALE;
   Z[v0] = (GLfloat) VB.WinZ[v0];

   X[v1] = VB.WinX[v1] / SUB_PIX_SCALE;
   Y[v1] = VB.WinY[v1] / SUB_PIX_SCALE;
   Z[v1] = (GLfloat) VB.WinZ[v1];

   X[v2] = VB.WinX[v2] / SUB_PIX_SCALE;
   Y[v2] = VB.WinY[v2] / SUB_PIX_SCALE;
   Z[v2] = (GLfloat) VB.WinZ[v2];
#endif


/*
#define WinX(i)  X[i]
#define WinY(i)  Y[i]
#define WinZ(i)  Z[i]
*/
#define WinX(i)  VB.Win[i][0]
#define WinY(i)  VB.Win[i][1]
#define WinZ(i)  VB.Win[i][2]


   /* find the order of the 3 vertices along the Y axis */
   {
      register GLfloat y0, y1, y2;

      y0 = WinY(v0);
      y1 = WinY(v1);
      y2 = WinY(v2);

      if (y0<=y1) {
	 if (y1<=y2) {	 /* y0<=y1<=y2 */
	    min = v0;   mid = v1;   max = v2;
	 }
	 else if (y2<=y0) {
	    /* y2<=y0<=y1 */
	    min = v2;   mid = v0;   max = v1;
	 }
	 else {
	    /* y0<=y2<=y1 */
	    min = v0;   mid = v2;   max = v1;
	 }
      }
      else {
	 /* y1<y0... */
	 if (y0<=y2) {
	    /* y1<=y0<=y2 */
	    min = v1;   mid = v0;   max = v2;
	 }
	 else if (y2<=y1) {
	    /* y2<=y1<=y0 */
	    min = v2;   mid = v1;   max = v0;
	 }
	 else {
	    /* y1<=y2<=y0 */
	    min = v1;   mid = v2;   max = v0;
	 }
      }

      assert( WinY(min) <= WinY(min) );
      assert( WinY(mid) <= WinY(max) );
   }

   ymin = (GLint) (WinY(min)+0.5);      /* add .5??? */
   ymid = (GLint) (WinY(mid) + 0.5);
   ymax = (GLint) (WinY(max)+0.5);      /* add .5??? */

   dy_mid_min = WinY(mid) - WinY(min);
   dy_max_min = WinY(max) - WinY(min);
   dy_max_mid = WinY(max) - WinY(mid);

/* Assume we have a triangle with vertices like:

   Y
   |        *max
   |
   | mid*
   |
   |          *min
   +----------------X
*/
   /*
    * Draw bottom half (from ymin up to ymid)
    */
   if (dy_mid_min>0.0) {
      GLfloat lx, rx, dlx, drx;
      GLfloat lz, rz, dlz, drz;
      GLfloat fudge;

      printf("drawing bottom\n");

      /* compute left and right edges' dx/dy */
      /* assume mid is left of max */
      dlx = (WinX(mid)-WinX(min)) / dy_mid_min;
      dlz = (WinZ(mid)-WinZ(min)) / dy_mid_min;
      drx = (WinX(max)-WinX(min)) / dy_max_min;
      drz = (WinZ(max)-WinZ(min)) / dy_max_min;

      if (dlx>drx) {
	 /* wrong assumption */
	 GLfloat tmp;
	 SWAP( dlx, drx, tmp );
	 SWAP( dlz, drz, tmp );
      }

      assert( dlx<=drx );   /* edges should diverge */

      fudge = ymin + 0.5 - WinY(min);  /* adjust to pixel centers */
      lx = WinX(min) + dlx * fudge;
      lz = WinZ(min) + dlz * fudge;
      rx = WinX(min) + drx * fudge;
      rz = WinZ(min) + drz * fudge;

      trap_z_monocolor( ymin, ymid, lx, dlx, rx, drx, lz, dlz, rz, drz,
		        VB.Color[pv] );
   }


   /*
    * Draw top half (from ymid up to ymax)
    */
   if (dy_max_mid>0.0) {
      GLfloat lx, rx, dlx, drx;
      GLfloat lz, rz, dlz, drz;
      GLfloat fudge;

      GLfloat t = (dy_mid_min) / (dy_max_min);
      GLfloat newx = LINTERP( t, WinX(min), WinX(max) );
      GLfloat newz = LINTERP( t, WinZ(min), WinZ(max) );

      printf("drawing top\n");

      /* this adjusts values to pixel centers */
      fudge = ymid + 0.5 - WinY(mid);
      printf("fudge %f\n", fudge);
      if (fudge<0.0) {
	 fudge = 0.0;
      }

      if (WinX(mid) < newx) {
	 /* mid is left side of triangle */
	 dlx = (WinX(max)-WinX(mid)) / dy_max_mid;
	 lx = WinX(mid) + dlx * fudge;
	 dlz = (WinZ(max)-WinZ(mid)) / dy_max_mid;
	 lz = WinZ(mid) + dlz * fudge;
/*	 drx = (WinX(max)-newx) / dy_max_mid;*/
	 drx = (WinX(max)-WinX(min)) / dy_max_min;
	 rx = newx + drx * fudge;
	 drz = (WinZ(max)-newz) / dy_max_mid;
	 rz = newz + drz * fudge;
      }
      else {
	 /* mid is on right side of triangle */
/*	 dlx = (WinX(max)-newx) / dy_max_mid;*/
	 dlx = (WinX(max)-WinX(min)) / dy_max_min;
	 lx = newx + dlx * fudge;
	 dlz = (WinZ(max)-newz) / dy_max_mid;
	 lz = newz + drz * fudge;
	 drx = (WinX(max)-WinX(mid)) / dy_max_mid;
	 rx = WinX(mid) + drx * fudge;
	 drz = (WinZ(max)-WinZ(mid)) / dy_max_mid;
	 rz = WinZ(mid) + dlz * fudge;
      }

      assert( dlx >= drx );   /* slopes should converge */

      trap_z_monocolor( ymid, ymax, lx, dlx, rx, drx, lz, dlz, rz, drz,
		        VB.Color[pv] );
   }

}

