
int drw_aktx       = 0;
int drw_akty       = 0;

uint16_t drw_color = 0xffff;

// Koordinaten, um die die Ausgabe einer Turtlegrafik "verschoben" werden kann
int drw_xofs      = 0;
int drw_yofs      = 0;

/* -------------------------------------------------------------
     drw_putpixel

     zeichnet einen einzelnen Bildpunkt auf das Display

         x, y  : Koordinate, an der ein Bildpunkt gesetzt
                 wird
         col   : Farbe des Bildpunktes
   ------------------------------------------------------------- */

void drw_putpixel(int x, int y, uint16_t col)
{
  putpixel(x + drw_xofs, y + drw_yofs, col);
}

/* -------------------------------------------------------------
     drw_line

     Zeichnet eine Linie von den Koordinaten x0,y0 zu x1,y1
     mit der angegebenen Farbe

        x0,y0 : Koordinate linke obere Ecke
        x1,y1 : Koordinate rechte untere Ecke
        color : Farbwert, der gezeichnet wird
     Linienalgorithmus nach Bresenham (www.wikipedia.org)

   ------------------------------------------------------------- */
void drw_line(int x0, int y0, int x1, int y1, uint16_t color)
{

  //    Linienalgorithmus nach Bresenham (www.wikipedia.org)

  int dx =  abs(x1-x0), sx = x0<x1 ? 1 : -1;
  int dy = -abs(y1-y0), sy = y0<y1 ? 1 : -1;
  int err = dx+dy, e2;                                     /* error value e_xy */

  for(;;)
  {

    drw_putpixel(x0, y0, color);
    if (x0==x1 && y0==y1) break;
    e2 = 2*err;
    if (e2 > dy) { err += dy; x0 += sx; }                  /* e_xy+e_x > 0 */
    if (e2 < dx) { err += dx; y0 += sy; }                  /* e_xy+e_y < 0 */
  }
}

/* -------------------------------------------------------------
     drw_ellipse

     Zeichnet eine Ellipse mit Mittelpunt an der Koordinate
     xm,ym mit den Hoehen- Breitenverhaeltnis a:b
     mit der angegebenen Farbe

        xm,ym  : Koordinate des Mittelpunktes der Ellipse
        a,b    : Hoehen- Breitenverhaeltnis
        color  : Farbwert, der gezeichnet wird

     Ellipsenalgorithmus nach Bresenham (www.wikipedia.org)
   ------------------------------------------------------------- */
void drw_ellipse(int xm, int ym, int a, int b, uint16_t color )
{
  // Algorithmus nach Bresenham (www.wikipedia.org)

  int dx = 0, dy = b;                       // im I. Quadranten von links oben nach rechts unten

  long a2 = a*a, b2 = b*b;
  long err = b2-(2*b-1)*a2, e2;             // Fehler im 1. Schritt */

  do
  {

    drw_putpixel(xm+dx, ym+dy,color);                // I.   Quadrant
    drw_putpixel(xm-dx, ym+dy,color);                // II.  Quadrant
    drw_putpixel(xm-dx, ym-dy,color);                // III. Quadrant
    drw_putpixel(xm+dx, ym-dy,color);                // IV.  Quadrant

    e2 = 2*err;
    if (e2 <  (2*dx+1)*b2) { dx++; err += (2*dx+1)*b2; }
    if (e2 > -(2*dy-1)*a2) { dy--; err -= (2*dy-1)*a2; }
  } while (dy >= 0);

  while (dx++ < a)                        // fehlerhafter Abbruch bei flachen Ellipsen (b=1)
  {

    drw_putpixel(xm+dx, ym,color);
    drw_putpixel(xm-dx, ym,color);

  }
}

/* ----------------------------------------------------------
     drw_fastxline

     zeichnet eine Linie in X-Achse mit den X Punkten
     x1 und x2 auf der Y-Achse y1

        x1, x2 : Start-, Endpunkt der Linie
        y1     : Y-Koordinate der Linie
        color  : 16 - Bit RGB565 Farbwert der gezeichnet
                 werden soll
   ---------------------------------------------------------- */
void drw_fastxline(int x1, int y1, int x2, uint16_t color)
{
  int x;

  if (x2 < x1) { x = x1; x1 = x2; x2 = x; }

  for (x= x1; x< (x2+1); x++)
  {
    drw_putpixel(x,y1, color);
  }
}

/* -------------------------------------------------------------
     drw_rectangle

     Zeichnet ein Rechteck von den Koordinaten x0,y0 zu x1,y1
     mit der angegebenen Farbe

        x0,y0  : Koordinate linke obere Ecke
        x1,y1  : Koordinate rechte untere Ecke
        color  : Farbwert, der gezeichnet wird
   ------------------------------------------------------------- */
void drw_rectangle(int x1, int y1, int x2, int y2, uint16_t color)
{
  if (x2 < x1) { int t = x1; x1 = x2; x2 = t; }
  if (y2 < y1) { int t = y1; y1 = y2; y2 = t; }

  drw_line(x1,y1,x2,y1, color);
  drw_line(x2,y1,x2,y2, color);
  drw_line(x1,y2,x2,y2, color);
  drw_line(x1,y1,x1,y2, color);
}

/* -------------------------------------------------------------
     drw_fillrectangle

     Zeichnet ein gefuelltes Rechteck von den Koordinaten
     x0,y0 zu x1,y1 mit der angegebenen Farbe

        x0,y0  : Koordinate linke obere Ecke
        x1,y1  : Koordinate rechte untere Ecke
        color  : Farbwert, der gezeichnet wird
   ------------------------------------------------------------- */
void drw_fillrectangle(int x1, int y1, int x2, int y2, uint16_t color)
{
  if (x2 < x1) { int t = x1; x1 = x2; x2 = t; }
  if (y2 < y1) { int t = y1; y1 = y2; y2 = t; }

  int y;

  for (y = y1; y <= y2; y++)
  {
    drw_fastxline(x1, y, x2, color);
  }
}

/* -------------------------------------------------------------
     drw_circle

     Zeichnet einen Kreis mit Mittelpunt an der Koordinate xm,ym
     und dem Radius r mit der angegebenen Farbe

        x ,y   : Koordinate des Mittelpunktes der Ellipse
        r      : Radius des Kreises
        color  : Farbwert, der gezeichnet wird
   ------------------------------------------------------------- */
void drw_circle(int x, int y, int r, uint16_t color )
{
  drw_ellipse(x,y,r,r,color);
}

/* -------------------------------------------------------------
     drw_fillellipse

     Zeichnet eine ausgefuellte Ellipse mit Mittelpunt an der
     Koordinate xm,ym mit den Hoehen- Breitenverhaeltnis a:b
     mit der angegebenen Farbe

        xm,ym  : Koordinate des Mittelpunktes der Ellipse
        a,b    : Hoehen- Breitenverhaeltnis
        color  : Farbwert, der gezeichnet wird

   Ellipsenalgorithmus nach Bresenham (www.wikipedia.org)
   ------------------------------------------------------------- */
void drw_fillellipse(int xm, int ym, int a, int b, uint16_t color )
{
  int dx = 0, dy = b;
  long a2 = a*a, b2 = b*b;
  long err = b2-(2*b-1)*a2, e2;

  do
  {
    drw_fastxline(xm+dx, ym+dy,xm-dx, color);
    drw_fastxline(xm-dx, ym-dy,xm+dx, color);

    e2 = 2*err;
    if (e2 <  (2*dx+1)*b2) { dx++; err += (2*dx+1)*b2; }
    if (e2 > -(2*dy-1)*a2) { dy--; err -= (2*dy-1)*a2; }
  } while (dy >= 0);

  while (dx++ < a)
  {
    drw_putpixel(xm+dx, ym,color);
    drw_putpixel(xm-dx, ym,color);
  }
}

/* -------------------------------------------------------------
     drw_fillcircle

     Zeichnet einen ausgefuellten Kreis mit Mittelpunt an der
     Koordinate xm,ym und dem Radius r mit der angegebenen Farbe

        x,y    : Koordinate des Mittelpunktes der Ellipse
        r      : Radius des Kreises
        color  : Farbwert, der gezeichnet wird
   ------------------------------------------------------------- */
void drw_fillcircle(int x, int y, int r, uint16_t color )
{
  drw_fillellipse(x,y,r,r,color);
}

/* -------------------------------------------------------------
     cmd_getonearg

     liest einen Parameter als Integer ab der Stringposition 0
     und gibt als Funktionsargument einen Zeiger auf den dem
     Argument folgenden String zurueck.

        *str   : Zeiger auf String (PROGMEM)
        *value : Zeiger Speicherplatz, der den im String ent-
                 haltenen Wert als Integer aufnimmt

     Rueckgabe :
        Zeiger auf den String, der dem Parameter folgt

   ------------------------------------------------------------- */
const char *cmd_getonearg(const char *str, int *value)
{
  char ch, negativesign;
  char loop;
  int  v;

  loop = 1;
  v = 0;
  negativesign = 0;

  while ((ch = pgm_read_byte(str)) && loop)
  {
    if (ch == '-')
    {
      negativesign = 1;
      str++;
      ch = pgm_read_byte(str);
    }

    if ((ch >= '0') && (ch <= '9'))
    {
      v = v * 10;
      v += ch - '0';
      str++;
    }
    else
    {
      loop = 0;
    }
  }

  *value = negativesign ? -v : v;
  return str;
}

/* -------------------------------------------------------------
     cmd_parse

     Interpretiert einen String als Anweisungen fuer einen
     Zeichenstift

   ------------------------------------------------------------- */
void cmd_parse(const char *str)
{
  char ch;
  int  arg1, arg2, arg3;

  while ((ch = pgm_read_byte(str)))
  {
    str++;

    switch (ch)
    {
     case 'c' :
       {
         str = cmd_getonearg(str, &arg1);
         drw_color = rgbfromega(arg1);
         break;
       }

     case 'C' :
       {
         str = cmd_getonearg(str, &arg1);
         if (pgm_read_byte(str) == ',') str++;
         str = cmd_getonearg(str, &arg2);
         if (pgm_read_byte(str) == ',') str++;
         str = cmd_getonearg(str, &arg3);
         drw_color = rgbfromvalue(arg1, arg2, arg3);
         break;
       }

     case 'r' :
       {
         str = cmd_getonearg(str, &arg1);
         drw_line(drw_aktx, drw_akty, drw_aktx + arg1, drw_akty, drw_color);
         drw_aktx += arg1;
         break;
       }

     case 'l' :
       {
         str = cmd_getonearg(str, &arg1);
         drw_line(drw_aktx, drw_akty, drw_aktx - arg1, drw_akty, drw_color);
         drw_aktx -= arg1;
         break;
       }

     case 'u' :
       {
         str = cmd_getonearg(str, &arg1);
         drw_line(drw_aktx, drw_akty, drw_aktx, drw_akty - arg1, drw_color);
         drw_akty -= arg1;
         break;
       }

     case 'd' :
       {
         str = cmd_getonearg(str, &arg1);
         drw_line(drw_aktx, drw_akty, drw_aktx, drw_akty + arg1, drw_color);
         drw_akty += arg1;
         break;
       }

     case 'k' :
       {
         str = cmd_getonearg(str, &arg1);
         drw_circle(drw_aktx, drw_akty, arg1, drw_color);
         break;
       }

     case 'K' :
       {
         str = cmd_getonearg(str, &arg1);
         drw_fillcircle(drw_aktx, drw_akty, arg1, drw_color);
         break;
       }

     case 't' :
       {
         str = cmd_getonearg(str, &arg1);
         str++;
         str = cmd_getonearg(str, &arg2);
         drw_rectangle(drw_aktx, drw_akty, drw_aktx + arg1, drw_akty + arg2, drw_color);
         break;
       }

     case 'T' :
       {
         str = cmd_getonearg(str, &arg1);
         str++;
         str = cmd_getonearg(str, &arg2);
         drw_fillrectangle(drw_aktx, drw_akty, drw_aktx + arg1, drw_akty + arg2, drw_color);
         break;
       }

     case 'P' :
       {
         str = cmd_getonearg(str, &arg1);
         str++;
         str = cmd_getonearg(str, &arg2);
         drw_aktx = arg1;
         drw_akty = arg2;
         break;
       }

     case 'p' :
       {
         str = cmd_getonearg(str, &arg1);
         str++;
         str = cmd_getonearg(str, &arg2);
         drw_line(drw_aktx, drw_akty, arg1, arg2, drw_color);
         drw_aktx = arg1;
         drw_akty = arg2;
         break;
       }

     case 'M' :
       {
         str = cmd_getonearg(str, &arg1);
         str++;
         str = cmd_getonearg(str, &arg2);
         drw_aktx += arg1;
         drw_akty += arg2;
         break;
       }

     case 'm' :
       {
         str = cmd_getonearg(str, &arg1);
         str++;
         str = cmd_getonearg(str, &arg2);
         drw_line(drw_aktx, drw_akty, drw_aktx + arg1, drw_akty + arg2, drw_color);
         drw_aktx += arg1;
         drw_akty += arg2;
         break;
       }

     default : break;
    }
  }
}
