#define	LIBQDISPLAY_CORE
#include "../include/libqdisplay.h"

/*
 *   Render a Quake polygon:
 *      read it from the db
 *      transform it into 3d
 *      clip it in 3d
 *      compute the 2d texture gradients
 *      scan convert
 *      pass off the spans
 */

/* drawing */
displaypointer texture;
int textureRow;
int textureMask1, textureMask2;
short int textureShift1, textureShift2;
short int textureMip;
short int textureType;
unsigned char textureColor;

#ifndef __OPTIMIZE__
#include "draw-orig.c"
#else
#include "draw-opti.c"
#endif

static inline void draw_poly(int n, point_3d ** vl)
{
  int i, j, y, ey;
  fix ymin, ymax;

  /* find max and min y height */
  ymin = ymax = vl[0]->sy;
  for (i = 1; i < n; ++i) {
    if (vl[i]->sy < ymin)
      ymin = vl[i]->sy;
    else if (vl[i]->sy > ymax)
      ymax = vl[i]->sy;
  }

  /* scan out each edge */
  j = n - 1;
  for (i = 0; i < n; ++i) {
    scan_convert(vl[i], vl[j]);
    j = i;
  }

  y = FIX_INT(ymin);
  ey = FIX_INT(ymax);

#ifndef __OPTIMIZE__
  for (; y < ey; y++) {
    int sx = FIX_INT(scan[y][0]);
    int ex = FIX_INT(scan[y][1]);

    if (ex - sx) {
      /* iterate over all spans and draw */
#ifdef DRIVER_8BIT
      if (localDim.frameDepth <= 8) {
	if (displayType == DISPLAY_TEXTURED)
	  draw_spans8(y, sx, ex);
	else if (displayType == DISPLAY_FLAT)
	  draw_spans8flat(y, sx, ex);
	else if (displayType == DISPLAY_WIRE)
	  draw_spans8wire(y, sx, ex);
      }
      else
#endif
#ifdef DRIVER_16BIT
      if (localDim.frameDepth <= 16)
	draw_spans16(y, sx, ex);
      else
#endif
#ifdef DRIVER_24BIT
      if (localDim.frameDepth <= 24)
	draw_spans24(y, sx, ex);
      else
#endif
#ifdef DRIVER_32BIT
#endif
	;
    }
  }
#else
  /* iterate over all spans and draw */
#ifdef DRIVER_8BIT
  if (localDim.frameDepth <= 8)
    if (displayType == DISPLAY_TEXTURED)
      draw_spans8(y, ey);
    else if (displayType == DISPLAY_FLAT)
      draw_spans8flat(y, ey);
    else if (displayType == DISPLAY_WIRE)
      draw_spans8wire(y, ey);
  else
#endif
#ifdef DRIVER_16BIT
  if (localDim.frameDepth <= 16)
    draw_spans16(y, ey);
  else
#endif
#ifdef DRIVER_24BIT
  if (localDim.frameDepth <= 24)
    draw_spans24(y, ey);
  else
#endif
#ifdef DRIVER_32BIT
#endif
    ;
#endif
}

void draw_face(__memBase, int face)
{
  int n = bspMem->shared.quake1.dfaces[face].numedges;
  int se = bspMem->shared.quake1.dfaces[face].firstedge;
  int i, edge, codes_or = 0, codes_and = 0xff;
  point_3d **vlist;

  for (i = 0; i < n; ++i) {
    edge = bspMem->shared.quake1.dsurfedges[se + i];

    if (edge < 0)
      transform_point(&defaultPoints[i], (vec_t *) & bspMem->shared.quake1.dvertexes[bspMem->shared.quake1.dedges[-edge].v[1]].point);
    else
      transform_point(&defaultPoints[i], (vec_t *) & bspMem->shared.quake1.dvertexes[bspMem->shared.quake1.dedges[edge].v[0]].point);

    codes_or |= defaultPoints[i].ccodes;
    codes_and &= defaultPoints[i].ccodes;
  }

  if (codes_and)
    return;
  if (codes_or)							/* poly crosses frustrum, so clip it */
    n = clip_poly(n, defaultVList, codes_or, &vlist);
  else
    vlist = defaultVList;

  /*
   * with this texChange-technique it is possible for example
   * to let light render the bsp-tree, then light marks the
   * last processed face as changed and render the tree again
   * and voila, everything is unchanged but the new lightface
   */
  if (n) {
    struct texture *Text;

    Text = GetCache(bspMem, face);

    if ((textureMip = compute_mip_level(bspMem, face)) != Text->lastMip)	/* if the mipmap changes, the tex and it lights changes too */
      Text->texChanged = TRUE;

    GetTMap(bspMem, Text, textureMip);				/* GetTMap must have the capability to set texChange */
    compute_texture_gradients(bspMem, Text, textureMip);
    draw_poly(n, vlist);

    Text->lastMip = textureMip;					/* set last mip here, perhaps GetTMap should use the old value */

    /*
     * should we free the whole face if it is an ANIM_MIPMAP?
     * perhaps the sizes etc. changes ...
     */
  }
}
