////////////////////////////////////////////////////////////
//
//  CT_SCAN.CPP - Cubic Tetrahedron Scan Conversion Class
//
//  Version:    1.03A
//
//  History:    94/08/23 - Version 1.00A release.
//              94/12/16 - Version 1.01A release.
//              95/02/05 - Version 1.02A release.
//              95/07/21 - Version 1.02B release.
//              96/02/14 - Version 1.02C release.
//              96/04/01 - Version 1.03A release.
//
//  Compilers:  Microsoft Visual C/C++ Professional V1.5
//              Borland C++ Version 4.5
//
//  Author:     Ian Ashdown, P.Eng.
//              byHeart Software Limited
//              620 Ballantree Road
//              West Vancouver, B.C.
//              Canada V7S 1W3
//              Tel. (604) 922-6148
//              Fax. (604) 987-7621
//
//  Copyright 1994-1996 byHeart Software Limited
//
//  The following source code has been derived from:
//
//    Ashdown, I. 1994. Radiosity: A Programmer's
//    Perspective. New York, NY: John Wiley & Sons.
//
//  It may be freely copied, redistributed, and/or modified
//  for personal use ONLY, as long as the copyright notice
//  is included with all source code files.
//
////////////////////////////////////////////////////////////

#include "ff_delta.h"
#include "ff_scan.h"
#include "ct_scan.h"

CubicScan::CubicScan()  // Class constructor
{
  int row;      // Loop index
  int width;    // Scan line width
  
  status = TRUE;        // Initialize object status

  // Allocate edge list
  if ((edge_list = new FormEdgeInfo[FF_ArrayRes]) != NULL)
  {
    // Allocate cell information buffer
    if ((cell_buffer =
        new (FormCellInfo (*[FF_ArrayRes]))) != NULL)
    {
      width = FF_ArrayRes;
      for (row = 0; row < FF_ArrayRes; row++)
      {
        if ((cell_buffer[row] = new FormCellInfo[width])
            == NULL)
        {
          // Release partially allocated buffer
          row--;
          for ( ; row >= 0; row--)
            delete [] cell_buffer[row];
          delete [] cell_buffer;

          // Release edge list memory 
          delete [] edge_list;

          status = FALSE;
          break;
        }
        width--;        // Decrement scan line width
      }
    }
  }
  else
  {
    delete [] edge_list;        // Release edge list memory
    status = FALSE;
  }
}

CubicScan::~CubicScan()         // Class destructor
{
  int row;      // Loop index
  
  delete [] edge_list;          // Release edge list memory

  // Delete cell information buffer
  for (row = 0; row < FF_ArrayRes; row++)
    delete [] cell_buffer[row];
  delete [] cell_buffer;
}

// Initialize cell information buffer
void CubicScan::InitBuffer()
{
  int row, col;     // Loop indices
  int width;        // Scan line width

  width = FF_ArrayRes;
  for (row = 0; row < FF_ArrayRes; row++)
  {
    for (col = 0; col < width; col++)
    {
      cell_buffer[row][col].depth = FF_Infinity;
      cell_buffer[row][col].id = FF_None;
    }
    width--;    // Decrement scan line width
  }
}

void CubicScan::DrawEdgeList()  // Draw edge list
{
  int x, y;             // Loop indices
  int sx, ex;           // Scan line x-axis co-ordinates
  double dz;            // Pseudodepth delta
  double iz;            // Element pseudodepth
  double x_dist;        // X-axis distance
  FormEdgeInfo *pedge;  // Edge info pointer
  FormScanInfo *pss;    // Scan line start info pointer
  FormScanInfo *pse;    // Scan line end info pointer
  FormScanInfo *psw;    // Swap scan line info pointer

  pedge = &(edge_list[ymin]);
  for (y = ymin; y < ymax; y++)
  {
    // Get scan line info pointers
    pss = &(pedge->isect[0]);
    pse = &(pedge->isect[1]);

    if (pss->x > pse->x)
    {
      // Swap scan line info pointers
      psw = pss; pss = pse; pse = psw;
    }

    // Get scan line x-axis co-ordinates
    sx = min((int) pss->x, FF_ArrayRes - y);
    ex = min((int) pse->x, FF_ArrayRes - y);

    if (sx < ex)        // Ignore zero-length segments
    {
      // Determine scan line start info
      iz = pss->z;

      // Determine inverse slopes
      x_dist = pse->x - pss->x;

      dz = (pse->z - iz) / x_dist;

      // Enter scan line
      for (x = sx; x < ex; x++)
      {
        // Check element visibility
        if (iz < (double) cell_buffer[y][x].depth)
        {
          // Update Z-buffer
          cell_buffer[y][x].depth = (float) iz;

          // Set polygon identifier
          cell_buffer[y][x].id = poly_id;
        }

        // Update element pseudodepth
        iz += dz;
      }
    }
    pedge++;    // Point to next edge list element
  }
}

// Sum delta form factors
void CubicScan::SumDeltas( float *ff_array )
{
  WORD poly_id;     // Polygon identifier
  int row, col;     // Face cell indices
  int width;        // Scan line width

  width = FF_ArrayRes;
  for (row = 0; row < FF_ArrayRes; row++)
  {
    for (col = 0; col < width; col++)
    {
      if ((poly_id = cell_buffer[row][col].id) !=
          FF_None)
        ff_array[poly_id - 1] += dff.GetFactor(row, col);
    }
    width--;    // Decrement scan line width
  }
}

