/* Goom Project
 * Copyright (C) <2003> iOS-Software
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */
#include "drawmethods.h"

#define DRAWMETHOD_PLUS(_out,_backbuf,_col) \
{\
      int tra=0,i=0;\
      unsigned char *bra = (unsigned char*)&(_backbuf);\
      unsigned char *dra = (unsigned char*)&(_out);\
      unsigned char *cra = (unsigned char*)&(_col);\
      for (;i<4;i++) {\
				tra = *cra;\
				tra += *bra;\
				if (tra>255) tra=255;\
				*dra = tra;\
				++dra;++cra;++bra;\
			}\
}

#define DRAWMETHOD DRAWMETHOD_PLUS(*p,*p,col)

void
draw_line (Pixel * data, int x1, int y1, int x2, int y2, int col, int screenx,
    int screeny)
{
  int x, y, dx, dy, yy, xx;
  Pixel *p;

  if ((y1 < 0) || (y2 < 0) || (x1 < 0) || (x2 < 0) || (y1 >= screeny)
      || (y2 >= screeny) || (x1 >= screenx) || (x2 >= screenx))
    return;

  /* clip to top edge 
     if ((y1 < 0) && (y2 < 0))
     return;

     if (y1 < 0) {
     x1 += (y1 * (x1 - x2)) / (y2 - y1);
     y1 = 0;
     }
     if (y2 < 0) {
     x2 += (y2 * (x1 - x2)) / (y2 - y1);
     y2 = 0;
     }

     clip to bottom edge 
     if ((y1 >= screeny) && (y2 >= screeny))
     return;
     if (y1 >= screeny) {
     x1 -= ((screeny - y1) * (x1 - x2)) / (y2 - y1);
     y1 = screeny - 1;
     }
     if (y2 >= screeny) {
     x2 -= ((screeny - y2) * (x1 - x2)) / (y2 - y1);
     y2 = screeny - 1;
     }
     clip to left edge 
     if ((x1 < 0) && (x2 < 0))
     return;
     if (x1 < 0) {
     y1 += (x1 * (y1 - y2)) / (x2 - x1);
     x1 = 0;
     }
     if (x2 < 0) {
     y2 += (x2 * (y1 - y2)) / (x2 - x1);
     x2 = 0;
     }
     clip to right edge 
     if ((x1 >= screenx) && (x2 >= screenx))
     return;
     if (x1 >= screenx) {
     y1 -= ((screenx - x1) * (y1 - y2)) / (x2 - x1);
     x1 = screenx - 1;
     }
     if (x2 >= screenx) {
     y2 -= ((screenx - x2) * (y1 - y2)) / (x2 - x1);
     x2 = screenx - 1;
     }
   */

  dx = x2 - x1;
  dy = y2 - y1;
  if (x1 > x2) {
    int tmp;

    tmp = x1;
    x1 = x2;
    x2 = tmp;
    tmp = y1;
    y1 = y2;
    y2 = tmp;
    dx = x2 - x1;
    dy = y2 - y1;
  }

  /* vertical line */
  if (dx == 0) {
    if (y1 < y2) {
      p = &(data[(screenx * y1) + x1]);
      for (y = y1; y <= y2; y++) {
        DRAWMETHOD;
        p += screenx;
      }
    } else {
      p = &(data[(screenx * y2) + x1]);
      for (y = y2; y <= y1; y++) {
        DRAWMETHOD;
        p += screenx;
      }
    }
    return;
  }
  /* horizontal line */
  if (dy == 0) {
    if (x1 < x2) {
      p = &(data[(screenx * y1) + x1]);
      for (x = x1; x <= x2; x++) {
        DRAWMETHOD;
        p++;
      }
      return;
    } else {
      p = &(data[(screenx * y1) + x2]);
      for (x = x2; x <= x1; x++) {
        DRAWMETHOD;
        p++;
      }
      return;
    }
  }
  /* 1    */
  /* \   */
  /* \  */
  /* 2 */
  if (y2 > y1) {
    /* steep */
    if (dy > dx) {
      dx = ((dx << 16) / dy);
      x = x1 << 16;
      for (y = y1; y <= y2; y++) {
        xx = x >> 16;
        p = &(data[(screenx * y) + xx]);
        DRAWMETHOD;
        if (xx < (screenx - 1)) {
          p++;
          /* DRAWMETHOD; */
        }
        x += dx;
      }
      return;
    }
    /* shallow */
    else {
      dy = ((dy << 16) / dx);
      y = y1 << 16;
      for (x = x1; x <= x2; x++) {
        yy = y >> 16;
        p = &(data[(screenx * yy) + x]);
        DRAWMETHOD;
        if (yy < (screeny - 1)) {
          p += screeny;
          /* DRAWMETHOD; */
        }
        y += dy;
      }
    }
  }
  /* 2 */
  /* /  */
  /* /   */
  /* 1    */
  else {
    /* steep */
    if (-dy > dx) {
      dx = ((dx << 16) / -dy);
      x = (x1 + 1) << 16;
      for (y = y1; y >= y2; y--) {
        xx = x >> 16;
        p = &(data[(screenx * y) + xx]);
        DRAWMETHOD;
        if (xx < (screenx - 1)) {
          p--;
          /* DRAWMETHOD; */
        }
        x += dx;
      }
      return;
    }
    /* shallow */
    else {
      dy = ((dy << 16) / dx);
      y = y1 << 16;
      for (x = x1; x <= x2; x++) {
        yy = y >> 16;
        p = &(data[(screenx * yy) + x]);
        DRAWMETHOD;
        if (yy < (screeny - 1)) {
          p += screeny;
          /* DRAWMETHOD; */
        }
        y += dy;
      }
      return;
    }
  }
}