/*
*     ___                       ___
*    / _ \___ _    _____ ____  / _ \_______ __    __
*   / ___/ _ \ |/|/ / -_) __/ / // / __/ _ `/ |/|/ /
*  /_/   \___/__,__/\__/_/   /____/_/  \_,_/|__,__/
*
*
*   Original Code by John Garrison
*   Written June 3-7, August 5,6,9 1999
*
*   To be released under the LGPL
*
*   Basic drawing of graphics primitives
*
*   See LICENSE.TXT for more LGPL info
*/

#include <math.h>

#include "SDL/SDL.h"
#include "powerdraw.h"
#include "primitives.h"

int (*_PutPixel)(PD_Surface *Surface, Sint32 X, Sint32 Y, PD_Color Color);

/////////////////////////////////////////
//          INTERNAL ROUTINES          //
/////////////////////////////////////////

//begin code added by Karl Bartel
int fast_putpixel1(PD_Surface *Surface, Sint32 X, Sint32 Y, PD_Color Color)
{
  if (X < 0 || X > Surface->w || Y < 0 || Y > Surface->h) 
    return -1;

  *((Uint8 *)Surface->pixels + Y * Surface->pitch + X) = Color;

  return 0;
}
int fast_putpixel2(PD_Surface *Surface, Sint32 X, Sint32 Y, PD_Color Color)
{
  if (X < 0 || X > Surface->w || Y < 0 || Y > Surface->h) 
    return -1;

 *((Uint16 *)Surface->pixels + Y * (Surface->pitch>>1) + X) = Color;

  return 0;
}
int fast_putpixel3(PD_Surface *Surface, Sint32 X, Sint32 Y, PD_Color Color)
{
  Uint8 *pix;
  int shift;

  if (X < 0 || X > Surface->w || Y < 0 || Y > Surface->h) 
    return -1;

  /* Gack - slow, but endian correct */
  pix = (Uint8 *)Surface->pixels + Y * Surface->pitch + X*3;
  shift = Surface->format->Rshift;
  *(pix+shift/8) = Color>>shift;
  shift = Surface->format->Gshift;
  *(pix+shift/8) = Color>>shift;
  shift = Surface->format->Bshift;
  *(pix+shift/8) = Color>>shift;

  return 0;
}
int fast_putpixel4(PD_Surface *Surface, Sint32 X, Sint32 Y, PD_Color Color)
{
  if (X < 0 || X > Surface->w || Y < 0 || Y > Surface->h) 
    return -1;

  *((Uint32 *)Surface->pixels + Y * Surface->pitch/4 + X) = Color;

  return 0;
}
//end code added by Karl Bartel



/* _HLine is the internal horizontal line drawer. Tried memset for speed
but that didn't work, it wouldn't draw in color in higher color depths */
int _HLine(PD_Surface *Surface, Sint32 X1, Sint32 X2, Sint32 Y, PD_Color Color)
{
   Sint32 temp;

   /* Make sure X1 is before X2 */
   if (X2 < X1){
      temp = X2;
      X2 = X1;
      X1 = temp;
   }

   /* Draw the line */
   for (temp = X1; temp <= X2; temp++)
      _PutPixel(Surface, temp, Y, Color);

   return 0;
}



/* _VLine is the internal vertical line drawer. */
int _VLine(PD_Surface *Surface, Sint32 Y1, Sint32 Y2, Sint32 X, PD_Color Color)
{
   Sint32 temp;

   /* Make sure X1 is before X2 */
   if (Y2 < Y1){
      temp = Y2;
      Y2 = Y1;
      Y1 = temp;
   }

   /* Draw the line */
   for (temp = Y1; temp <= Y2; temp++)
      _PutPixel(Surface, X, temp, Color);

   return 0;
}

/* This function is for the PD_Line Routine */
int _sgn(long a)
{
   if (a > 0) return +1;
   else if (a < 0) return -1;
   else return 0;
}



/* used so the user doesn't have to deal with radians */
float _DegToRad(float deg)
{
   float rad;

   rad = (deg * 3.1416) / 180;

   return rad;
}



/////////////////////////////////////////////
//          SINGLE PIXEL ROUTINES          //
/////////////////////////////////////////////

/*PD_PutPixel is the routine for the user to draw a pixel */
int PD_PutPixel (PD_Surface *Surface, Sint32 X, Sint32 Y, PD_Color Color)
{
   if (SDL_MUSTLOCK(Surface)) {
      if (SDL_LockSurface(Surface) < 0)
         return 0;
   }

   /* Draw the pixel */
   _PutPixel(Surface, X, Y, Color);

   /* unlock the display */
   if (SDL_MUSTLOCK(Surface)) {
      SDL_UnlockSurface(Surface);
   }

   return 0;
}



PD_Color PD_GetPixel (PD_Surface *Surface, Sint32 X, Sint32 Y)
{
   Uint8  *bits;
   Uint32 Bpp;

   Bpp = BPP/8;

   bits = ((Uint8 *)Surface->pixels)+Y*Surface->pitch+X*Bpp;

   /* Get the pixel */
   switch(Bpp) {
      case 1:
         return *((Uint32 *)(bits));
         break;
      case 2:
         return *((Uint32 *)(bits));
         break;
      case 3: { /* Format/endian independent */
         Uint8 r, g, b;
         r = *((bits)+Surface->format->Rshift/8);
         g = *((bits)+Surface->format->Gshift/8);
         b = *((bits)+Surface->format->Bshift/8);
         return SDL_MapRGB(Surface->format, r, g, b);
         }
         break;
      case 4:
         return *((Uint32 *)(bits));
         break;
   }

   return 0;
}



/////////////////////////////////////
//          LINE ROUTINES          //
/////////////////////////////////////

/* A quick fast way of drawing horizontal lines. Quick and fast development
time that is :) */
int PD_HLine (PD_Surface *Surface, Sint32 X1, Sint32 X2, Sint32 Y, PD_Color Color)
{
   Sint32 temp;

   /* Make sure X1 is before X2 */
   if (X2 < X1){
      temp = X2;
      X2 = X1;
      X1 = temp;
   }

   if (SDL_MUSTLOCK(Surface)) {
      if (SDL_LockSurface(Surface) < 0)
         return 0;
   }

   /* Draw the line */
   _HLine(Surface, X1, X2, Y, Color);

   /* unlock the display */
   if (SDL_MUSTLOCK(Surface)) {
      SDL_UnlockSurface(Surface);
   }

   return 0;
}


/* A quick and easy way of drawing vertical lines */
int PD_VLine (PD_Surface *Surface, Sint32 Y1, Sint32 Y2, Sint32 X, PD_Color Color)
{
   Sint32 temp;

   /* Make sure Y1 is before Y2 */
   if (Y2 < Y1){
      temp = Y2;
      Y2 = Y1;
      Y1 = temp;
   }

   if (SDL_MUSTLOCK(Surface)) {
      if (SDL_LockSurface(Surface) < 0)
         return 0;
   }

   /* Draw the line */
   _VLine(Surface, Y1, Y2, X, Color);

   /* unlock the display */
   if (SDL_MUSTLOCK(Surface)) {
      SDL_UnlockSurface(Surface);
   }

   return 0;
}



/* Performs Callback at each line point. This came straight from the
asphyxia vga trainers */
int PD_DoLine (PD_Surface *Surface, Sint32 X1, Sint32 Y1, Sint32 X2, Sint32 Y2, PD_Color Color, int Callback (PD_Surface *Surf, Sint32 X, Sint32 Y, PD_Color Color))
{ 
  Sint32 dx, dy, sdx, sdy, x, y, px, py; 
 
  dx = X2 - X1; 
  dy = Y2 - Y1; 
 
  sdx = (dx < 0) ? -1 : 1; 
  sdy = (dy < 0) ? -1 : 1; 
 
  dx = sdx * dx + 1; 
  dy = sdy * dy + 1; 
 
  x = y = 0; 
 
  px = X1; 
  py = Y1; 
 
  if (dx >= dy) 
    { 
      for (x = 0; x < dx; x++) 
	{ 
          Callback(Surface, px, py, Color);
	 
	  y += dy; 
	  if (y >= dx) 
	    { 
	      y -= dx; 
	      py += sdy; 
	    } 
	  px += sdx; 
	} 
    } 
  else 
    { 
      for (y = 0; y < dy; y++) 
	{ 
 
          Callback(Surface, px, py, Color);
 
	  x += dx; 
	  if (x >= dy) 
	    { 
	      x -= dy; 
	      px += sdx; 
	    } 
	  py += sdy; 
	} 
    } 
  
   return 0;
}



/* The user's line drawing function */
int PD_Line (PD_Surface *Surface, Sint32 X1, Sint32 Y1, Sint32 X2, Sint32 Y2, PD_Color Color)
{
   Sint32 temp;

   if (SDL_MUSTLOCK(Surface)) {
      if (SDL_LockSurface(Surface) < 0)
         return 0;
   }

   /* Draw the line */
   PD_DoLine(Surface, X1, Y1, X2, Y2, Color, _PutPixel);

   /* unlock the display */
   if (SDL_MUSTLOCK(Surface)) {
      SDL_UnlockSurface(Surface);
   }

   /* Make sure X1 is before X2 */
   if (X2 < X1){
      temp = X2;
      X2 = X1;
      X1 = temp;
   }
   /* Make sure Y1 is before Y2 */
   if (Y2 < Y1){
      temp = Y2;
      Y2 = Y1;
      Y1 = temp;
   }

   return 0;
}



//////////////////////////////////////////
//          RECTANGLE ROUTINES          //
//////////////////////////////////////////

/* Draws a simple unfilled rectangle */
int PD_Rect (PD_Surface *Surface, Sint32 X1, Sint32 Y1, Sint32 X2, Sint32 Y2, PD_Color Color)
{
   Sint32 temp;

   if (SDL_MUSTLOCK(Surface)) {
      if (SDL_LockSurface(Surface) < 0)
         return 0;
   }

   /* Draw rectangle */
   PD_DoRect(Surface, X1, Y1, X2, Y2, Color, _PutPixel);

   /* unlock the display */
   if (SDL_MUSTLOCK(Surface)) {
      SDL_UnlockSurface(Surface);
   }

  /* Make sure X1 is before X2 */
   if (X2 < X1){
      temp = X2;
      X2 = X1;
      X1 = temp;
   }
   /* Make sure Y1 is before Y2 */
   if (Y2 < Y1){
      temp = Y2;
      Y2 = Y1;
      Y1 = temp;
   }

   return 0;
}



int PD_DoRect (PD_Surface *Surface, Sint32 X1, Sint32 Y1, Sint32 X2, Sint32 Y2, PD_Color Color, int Callback (PD_Surface *Surf, Sint32 X, Sint32 Y, PD_Color Color))
{
   /* Draw the rectangle and perform callbacks */
   PD_DoLine(Surface, X1, Y1, X2, Y1, Color, Callback);
   PD_DoLine(Surface, X2, Y1, X2, Y2, Color, Callback);
   PD_DoLine(Surface, X1, Y2, X2, Y2, Color, Callback);
   PD_DoLine(Surface, X1, Y1, X1, Y2, Color, Callback);

   return 0;
}



/* Draws a filled rectangle onto Surface */
int PD_RectFilled (PD_Surface *Surface, Sint32 X1, Sint32 Y1, Sint32 X2, Sint32 Y2, PD_Color Color)
{
  SDL_Rect temp;

   temp.x = X1;
   temp.y = Y1;
   temp.w = X2-X1;
   temp.h = Y2-Y1;

   if (SDL_MUSTLOCK(Surface)) {
      if (SDL_LockSurface(Surface) < 0)
         return 0;
   }

   SDL_FillRect(Surface, &temp, Color);

   /* unlock the display */
   if (SDL_MUSTLOCK(Surface)) {
      SDL_UnlockSurface(Surface);
   }

   return 0;
}



///////////////////////////////////////
//          CIRCLE ROUTINES          //
///////////////////////////////////////

/* Draws a circle and Performs Callback on the points. Note that deg is actually
 radians. */
int PD_DoCircle (PD_Surface *Surface, Sint32 X, Sint32 Y, Sint32 Rad, float Aspect, PD_Color Color, int Callback (PD_Surface *Surf, Sint32 X, Sint32 Y, PD_Color Color))
{
   Sint32 x, y;
   float deg;

   deg = 0.0;

   /* Perform Callback for all the degrees in our circle */
   do {
      /* Find the postion from the origin of the pixel at deg */
      x = Rad * cos(deg);
      y = Rad * sin(deg);

      /* Move the origin and perform the Callback */
      Callback(Surface, X+x, Y+y, Color);
      deg += Aspect;
   }while (deg < 6.4);

   return 0;
}



/* Draw the circle onto Surface */
int PD_Circle (PD_Surface *Surface, Sint32 X, Sint32 Y, Sint32 Rad, float Aspect, PD_Color Color)
{
   /* Let's not even try to draw it if it never touches the Surface */
   if ((X-Rad) > (Surface->w-1))
      return 0;
   if ((Y-Rad) > (Surface->h-1))
      return 0;
   if (((X-Rad)+(Rad*2)) < 0)
      return 0;
   if (((Y-Rad)+(Rad*2)) < 0)
      return 0;

   if (SDL_MUSTLOCK(Surface)) {
      if (SDL_LockSurface(Surface) < 0)
         return 0;
   }

   /* Draw our circle */
   PD_DoCircle (Surface, X, Y, Rad, Aspect, Color, _PutPixel);

   /* unlock the display */
   if (SDL_MUSTLOCK(Surface)) {
      SDL_UnlockSurface(Surface);
   }

   return 0;
}

/* This is something I figured out how to do on my own, so don't expect it
to be too fast */
int PD_CircleFilled (PD_Surface *Surface, Sint32 X, Sint32 Y, Sint32 Rad, float Aspect, PD_Color Color)
{
   float deg;
   int x, y;

   /* Let's not even try to draw it if it never touches the Surface */
   if ((X-Rad) > (Surface->w-1))
      return 0;
   if ((Y-Rad) > (Surface->h-1))
      return 0;
   if (((X-Rad)+(Rad*2)) < 0)
      return 0;
   if (((Y-Rad)+(Rad*2)) < 0)
      return 0;

   deg = 0;

   if (SDL_MUSTLOCK(Surface)) {
      if (SDL_LockSurface(Surface) < 0)
         return 0;
   }

   /* Plot pixels for all the degrees in our circle */
   do {
      /* Find the postion from the origin of the pixel at deg */
      x = Rad * cos(deg);
      y = Rad * sin(deg);

      /* Move the origin and set the pixel */
      _HLine (Surface, X, X+x, Y+y, Color);
      deg += Aspect;
   }while (deg < 6.4);

   /* unlock the display */
   if (SDL_MUSTLOCK(Surface)) {
      SDL_UnlockSurface(Surface);
   }

   return 0;
}



////////////////////////////////////////
//          ELLIPSE ROUTINES          //
////////////////////////////////////////

/* This here is Bresenham's ellipse algorithm. Do me a favor and don't
ask me to explain it. */
int PD_DoEllipse (PD_Surface *Surface, Sint32 X, Sint32 Y, Sint32 XRad, Sint32 YRad, PD_Color Color, int Callback (PD_Surface *Surf, Sint32 X, Sint32 Y, PD_Color Color))
{
   int a2, b2;
   int x, y, dec;

   a2 = XRad*XRad;
   b2 = YRad*YRad;

   for (x = 0, y = YRad, dec = 2*b2+a2*(1-2*YRad); b2*x <= a2*y; x++)
   {
       Callback(Surface, X+x, Y+y, Color);
       Callback(Surface, X-x, Y+y, Color);
       Callback(Surface, X+x, Y-y, Color);
       Callback(Surface, X-x, Y-y, Color);

       if (dec >= 0)
           dec += 4*a2*(1-(y--));
       dec += b2*(4*x+6);
   }

   for (x = XRad, y = 0, dec = 2*a2+b2*(1-2*XRad); a2*y <= b2*x; y++)
   {
       Callback(Surface, X+x, Y+y, Color);
       Callback(Surface, X-x, Y+y, Color);
       Callback(Surface, X+x, Y-y, Color);
       Callback(Surface, X-x, Y-y, Color);

       if (dec >= 0)
           dec += 4*b2*(1-(x--));
       dec += a2*(4*y+6);
   }

   return 0;
}



/* Draws our ellipse to Surface */
int PD_Ellipse (PD_Surface *Surface, Sint32 X, Sint32 Y, Sint32 XRad, Sint32 YRad, PD_Color Color)
{
   /* Let's not even try to draw it if it never touches the Surface */
   if ((X-XRad) > (Surface->w-1))
      return 0;
   if ((Y-YRad) > (Surface->h-1))
      return 0;
   if (((X-XRad)+(XRad*2)) < 0)
      return 0;
   if (((Y-YRad)+(YRad*2)) < 0)
      return 0;

   if (SDL_MUSTLOCK(Surface)) {
      if (SDL_LockSurface(Surface) < 0 )
         return 0;
   }

   /* Put a pixel at every point */
   PD_DoEllipse (Surface, X, Y, XRad ,YRad, Color, _PutPixel);

    /* unlock the display */
   if (SDL_MUSTLOCK(Surface)) {
      SDL_UnlockSurface(Surface);
   }

   return 0;
}



/* Even though I don't fully understand the ellipse algorithm I made this up
like I did the circle fill. How much you wanna bet it doesn't even work :) */
int PD_EllipseFilled (PD_Surface *Surface, Sint32 X, Sint32 Y, Sint32 XRad, Sint32 YRad, PD_Color Color)
{
   int a2, b2;
   int x, y, dec;

  /* Let's not even try to draw it if it never touches the Surface */
   if ((X-XRad) > (Surface->w-1))
      return 0;
   if ((Y-YRad) > (Surface->h-1))
      return 0;
   if (((X-XRad)+(XRad*2)) < 0)
      return 0;
   if (((Y-YRad)+(YRad*2)) < 0)
      return 0;

   a2 = XRad*XRad;
   b2 = YRad*YRad;

   if (SDL_MUSTLOCK(Surface)) {
      if (SDL_LockSurface(Surface) < 0)
         return 0;
   }

   for (x = 0, y = YRad, dec = 2*b2+a2*(1-2*YRad); b2*x <= a2*y; x++)
   {
       _HLine(Surface, X+x, X-x, Y+y, Color);
       _HLine(Surface, X+x, X-x, Y-y, Color);

       if (dec >= 0)
           dec += 4*a2*(1-(y--));
       dec += b2*(4*x+6);
   }

   for (x = XRad, y = 0, dec = 2*a2+b2*(1-2*XRad); a2*y <= b2*x; y++)
   {
       _HLine(Surface, X+x, X-x, Y+y, Color);
       _HLine(Surface, X+x, X-x, Y-y, Color);

       if (dec >= 0)
           dec += 4*b2*(1-(x--));
       dec += a2*(4*y+6);
   }

   /* unlock the display */
   if ( SDL_MUSTLOCK(Surface) ) {
      SDL_UnlockSurface(Surface);
   }

   return 0;
}



/////////////////////////////////////////
//          TRIANGLE ROUTINES          //
/////////////////////////////////////////

/*  Performs Callback for each point on the triangle */
int PD_DoTriangle (PD_Surface *Surface, Sint32 X1, Sint32 Y1, Sint32 X2, Sint32 Y2, Sint32 X3, Sint32 Y3, PD_Color Color, int Callback (PD_Surface *Surf, Sint32 X, Sint32 Y, PD_Color Color))
{
   /* Draw the triangle and perform callbacks */
   PD_DoLine(Surface, X1, Y1, X2, Y2, Color, Callback);
   PD_DoLine(Surface, X2, Y2, X3, Y3, Color, Callback);
   PD_DoLine(Surface, X3, Y3, X1, Y1, Color, Callback);

   return 0;
}



/* Draws a triangle to Surface */
int PD_Triangle (PD_Surface *Surface, Sint32 X1, Sint32 Y1, Sint32 X2, Sint32 Y2, Sint32 X3, Sint32 Y3, PD_Color Color)
{
   /* Draw the triangle */
   PD_Line(Surface, X1, Y1, X2, Y2, Color);
   PD_Line(Surface, X2, Y2, X3, Y3, Color);
   PD_Line(Surface, X3, Y3, X1, Y1, Color);

   return 0;
}



/* Draws a filled triangle for the user */
int PD_TriangleFilled (PD_Surface *Surface, Sint32 X1, Sint32 Y1, Sint32 X2, Sint32 Y2, Sint32 X3, Sint32 Y3, PD_Color Color)
{
   Sint32 y;
   float topx, topy;
   float midx, midy;
   float botx, boty;
   float ebleft, ebright;
   float rpos, lpos;

   /* Make was complaining that these weren't always initialized
      I didn't want people to think something was wrong with the
      code because of Make's paranoia */
   midx = 0;
   midy = 0;

   /* We need to sort our points in Y-order */
   if (Y2 <= Y1) {
      topx = X2;
      topy = Y2;
      botx = X1;
      boty = Y1;
   }
   else if (Y2 > Y1) {
      topx = X1;
      topy = Y1;
      botx = X2;
      boty = Y2;
   }

   if (Y3 >= topy && Y3 <= boty) {
      midx = X3;
      midy = Y3;
   }
   else if (Y3 < topy) {
      midx = topx;
      midy = topy;
      topx = X3;
      topy = Y3;
   }
   else if (Y3 > boty) {
      midx = botx;
      midy = boty;
      botx = X3;
      boty = Y3;
   }

   /* Find the slope of our lines */
   ebleft = (midx - topx) / (midy - topy);
   ebright = (botx - topx) / (boty - topy);

   /* Set our variable's initial values */
   rpos = topx;
   lpos = topx;

   /* Draw the first half of the triangle */
   for (y = topy; y <= midy; y++) {
      PD_HLine(Surface, rpos, lpos, y, Color);
      rpos += ebright;
      lpos += ebleft;
   }

   /* Find the new slope for the next half */
   ebleft = (botx - midx) / (boty - midy);

   /* Reset our variable for the next half */
   lpos = midx;

   /* Draw the second half of the triangle */
   for (y = midy; y <= boty; y++) {
      PD_HLine(Surface, rpos, lpos, y, Color);
      rpos += ebright;
      lpos += ebleft;
   }

   return 0;
}



////////////////////////////////////////
//          POLYGON ROUTINES          //
////////////////////////////////////////

/* Does Callback for each point in a Polygon */
int PD_DoPolygon (PD_Surface *Surface, Sint32 Vertices, Sint32 *X, Sint32 *Y, PD_Color Color, int Callback (PD_Surface *Surf, Sint32 X, Sint32 Y, PD_Color Color))
{
   Sint32 v;

   /* Draw our poly. Doesn't work for concave polygons! */
   for (v=0; (v+1) < Vertices; v++) {
      PD_DoLine(Surface, X[v], Y[v], X[v+1], Y[v+1], Color, Callback);
   }
   PD_DoLine(Surface, X[0], Y[0], X[Vertices-1], Y[Vertices-1], Color, Callback);

   return 0;
}



/* Draw the poly to Surface */
int PD_Polygon (PD_Surface *Surface, Sint32 Vertices, Sint32 *X, Sint32 *Y, PD_Color Color)
{
   Sint32 v;

   /* Draw our poly. Doesn't work for concave polygons! */
   for (v=0; (v+1) < Vertices; v++) {
      PD_Line(Surface, X[v], Y[v], X[v+1], Y[v+1], Color);
   }
   PD_Line(Surface, X[0], Y[0], X[Vertices-1], Y[Vertices-1], Color);

   return 0;
}



int PD_PolygonFilled (PD_Surface *Surface, Sint32 Vertices, Sint32 *X, Sint32 *Y, PD_Color Color)
{
   Sint32 v;

   /* Draw our poly. Doesn't work for concave polygons! */
   for (v=0; (v+2) < Vertices; v++) {
      PD_TriangleFilled (Surface, X[0], Y[0], X[v+1], Y[v+1], X[v+2], Y[v+2], Color);
   }

   return 0;
}



////////////////////////////////////
//          ARC ROUTINES          //
////////////////////////////////////

int PD_DoArc (PD_Surface *Surface, Sint32 X, Sint32 Y, Sint32 Rad, float Aspect, float Deg1, float Deg2, PD_Color Color, int Callback (PD_Surface *Surf, Sint32 X, Sint32 Y, PD_Color Color))
{
   Sint32 x, y;
   float deg;

   Deg1 = _DegToRad(Deg1);
   Deg2 = _DegToRad(Deg2);

   /* Plot pixels between the degrees in the arc */
   for (deg = Deg1; deg <= Deg2; deg += Aspect)
   {
      /* Make sure not to go too far */
      if (deg > Deg2)
         deg = Deg2;

      /* Find the postion from the origin of the pixel at deg */
      x = Rad * cos(deg);
      y = Rad * sin(deg);

      /* Move the origin and perform the Callback */
      Callback(Surface, X+x, Y+y, Color);
   }

   return 0;
}



int PD_Arc (PD_Surface *Surface, Sint32 X, Sint32 Y, Sint32 Rad, float Aspect, float Deg1, float Deg2, PD_Color Color)
{
   Sint32 temp;

   /* Make sure Deg1 is before Deg2 */
   if (Deg2 < Deg1){
      temp = Deg2;
      Deg2 = Deg1;
      Deg1 = temp;
   }

    /* Let's not even try to draw it if it never touches the Surface */
   if ((X-Rad) > (Surface->w-1))
      return 0;
   if ((Y-Rad) > (Surface->h-1))
      return 0;
   if (((X-Rad)+(Rad*2)) < 0)
      return 0;
   if (((Y-Rad)+(Rad*2)) < 0)
      return 0;

   if (SDL_MUSTLOCK(Surface)) {
      if (SDL_LockSurface(Surface) < 0)
         return 0;
   }

   /* Draw our arc */
   PD_DoArc(Surface, X, Y, Rad, Aspect, Deg1, Deg2, Color, _PutPixel);

   /* unlock the display */
   if (SDL_MUSTLOCK(Surface)) {
      SDL_UnlockSurface(Surface);
   }

   return 0;
}
