/*  Verschiedene Vektor-Grafikroutinen (Solid-Fill,Gouraud-Shading von Polygonen)
    (c) DL 30.1.97-
   Es mssen vom einbindenden Programm folgende Variablen gestellt werden:
     BaseAddr - Dorthin sollen die Polygone gezeichnet werden
  ACHTUNG: ab 6.4. ist BaseAddr ein Zeiger auf die Zielbitmap,
   da nun die Allegro-Library statt LIBGRX verwendet wird
     ScrWidth/ScrHeight

   Prozeduren:
    * SetLine_Interpol usw.: lineare Interpolationsmethoden
    * DL_Line(x1,y1,x2,y2,farbe): Zeichnet eine Linie
    * DL_LineGouraud(x1,y1,x2,y2,c1,c2): Schattiert eine Linie mit allen Farben zwischen c1 und c2
    * DL_FillPoly(nPoint,int points[][2],farbe): Zeichnet ein einf„rbig geflltes Polygon
    * DL_FillPolyGouraud(nPoint,int points[][2],int colors[]): Zeichnet ein
        Polygon mit Gouraud-Schattierung 
  Variablen:
   char drawback;          Wenn 1, dann wird das Polygon auch gezeichnet, wenn
                           es entgegen dem Uhrzeigersinn gespeichert ist (sinnvoll
                           fr verdeckte Fl„chen konvexer K”rper in 3D-Transformationen 
*/
#ifdef __cplusplus
 
extern "C" {
#endif
 
#include <dos.h>
 
#ifdef test_dlline
 
 #include <std.h>
 #include <grx.h>
 #include <math.h>
 unsigned int RetracePort;
 #define NoSprites
 #include "_dlspr.c"
  #define RedStart 32
  #define LongTime(h,m,sec,sec100) (long)(sec100+sec*100+m*6000+h*360000)
#endif
 

#define xchg(x,y) x^=y^=x^=y
 

typedef struct {        /* Struktur fr lineare Interpolation */
 int a,dx;               /* a = Z„hler, dx = Nenner */
 int IncrF,IncrIP;
 int Dec_a;             /* Um diesen Wert wird a bei jedem Durchlauf verringert */
 int fcoord,ipcoord;    /* fcoord ... Wird bei jedem Durchlauf fix um 1 erh”ht/verringert (-> Incr)
                           ipcoord .. Diese Koordinate wird linear interpoliert */
 int flim;
 int swp;              /* Wenn 1, dann fcoord = y und ipcoord = x, ansonsten umgekehrt */
 int swapcolors;       /* Wenn 1, dann mssen beim Gouraud-Shading die beiden
                           Eckfarben umgedreht werden */
} TInterpol;

/* ---------- F u n k t i o n s p r o t o t y p e n --------------- */

inline void SetLine_Interpol(int x1,int y1,int x2,int y2,TInterpol *ipol);
inline int Do_Interpol(TInterpol *ipol);
inline int LineReady(TInterpol *ipol);
inline void SetColor_Interpol(int c1,int c2,int length,TInterpol *ipol);
void DL_Line(int x1,int y1,int x2,int y2,int farbe);
void DL_LineGouraud(int x1,int y1,int x2,int y2,int c1,int c2);
void DL_FillPoly(char nPoint,int points[][2],unsigned char color);
int DL_FillPolyGouraud(char nPoint,int points[][2],int colors[]);
void DL_Clear32(BITMAP *b);

/* -------------------------------------------------------------- */

unsigned char colortable[2000]; /* Fr die Funktion DL_HLineGouraud256 */
char drawback=1;

/* -------------------------------------------------------------- */

/* Die Prozedure SetLine_Interpol und Do_Interpol bilden im wesentlichen eine
  Routine zum Linienzeichnen mittels linearer Interpolation, k”nnen aber z.B.
  auch zum Fllen von Polygonen verwendet werden
  (Hinweis: es wird immer von oben nach unten, d.h. vom Punkt mit der kleineren
  y-Koordinate zum Punkt mit der grӇeren y-Koordinate gerechnet */

inline void SetLine_Interpol(int x1,int y1,int x2,int y2,TInterpol *ipol) {
        /* Setzt die Interpolationsvariablen fr eine Linie */
int dx,dy;
 ipol->IncrF = ipol->IncrIP = 1;
 ipol->swapcolors = 0;
 if ((dx = x2-x1) < 0) dx = -dx;
 if ((dy = y2-y1) < 0) dy = -dy;
 if (dx > dy) {         /* Steigung < 1? */
  if (x1 > x2) {
   xchg(x1,x2);
   xchg(y1,y2);
   ipol->swapcolors = 1;
  }
  if (y1 > y2) {
   ipol->IncrF = -1;
   ipol->Dec_a = (y1-y2) << 1;
   ipol->fcoord = x2;
   ipol->ipcoord = y2;
   ipol->flim = x1;
   ipol->swapcolors = !ipol->swapcolors;
  }
  else {
   ipol->Dec_a = (y2-y1) << 1;
   ipol->fcoord = x1;
   ipol->ipcoord = y1;
   ipol->flim = x2;
  }
  ipol->a = x2-x1;
  ipol->swp = 0;
  ipol->dx = ipol->a << 1;
 }
 else {                               /* Steigung > 1 */
  if (y1 > y2) {
   xchg(x1,x2);
   xchg(y1,y2);
   ipol->swapcolors = 1;
  }
  if (x1 > x2) {
   ipol->IncrIP = -1;
   ipol->Dec_a = (x1-x2) << 1;
   ipol->fcoord = y1;
   ipol->ipcoord = x1;
   ipol->flim = y2;
  } else {
   ipol->Dec_a = (x2-x1) << 1;
   ipol->fcoord = y1;
   ipol->ipcoord = x1;
   ipol->flim = y2;
  }
  ipol->a = y2-y1;
  ipol->swp = 1;
  ipol->dx = ipol->a << 1;
 }
}

inline int Do_Interpol(TInterpol *ipol) /* Fhrt die Interpolation aus (1 Schritt),
        Rckgabe 1, wenn ipcoord erh”ht wurde */
{ 
 /* ipol-Offsets: a             0
                  dx            4
                  IncrF         8
                  IncrIP        12
                  Dec_a         16
                  fcoord        20
                  ipcoord       24
                  flim          28
                  swp           32
                  swapcolors    36 */
/*  asm volatile (
  "
   movl %1,%%edi
   movl $0,(%%edi)
   movl %0,%%edi
   movl 8(%%edi),%%eax 
   addl %%eax,20(%%edi)

   movl 16(%%edi),%%eax
   subl %%eax,(%%edi)
   jns Do_InterpolEnde

    movl 4(%%edi),%%eax
    addl %%eax,(%%edi)
    movl 12(%%edi),%%eax
    addl %%eax,24(%%edi)
    movl %1,%%edi
    movl $1,(%%edi)

  Do_InterpolEnde:
  "
  :
  : "g" (ipol), "g" (&result)
  : "edi","eax");*/

  ipol->fcoord += ipol->IncrF;
  if ((ipol->a -= ipol->Dec_a) > 0) return(0);
  else
   {
    ipol->a += ipol->dx;
    ipol->ipcoord += ipol->IncrIP;
    return(1);
   }

}

inline int LineReady(TInterpol *ipol)
{
 if (ipol->IncrF > 0)
  if (ipol->fcoord < ipol->flim) return(0);
  else return(1);
 else if (ipol->fcoord > ipol->flim) return(0);
  else return(1);
}

inline void SetColor_Interpol(int c1,int c2,int length,TInterpol *ipol)
{
 ipol->ipcoord = c1;
 ipol->a = c1 << 10;
 if (length != 0)
  ipol->Dec_a = ((c2-c1) << 10)/length;
 else ipol->Dec_a = 0;
}

#define Do_ColorInterpol(ipol) { \
 
 ipol.a += ipol.Dec_a;           \
 ipol.ipcoord = ipol.a >> 10;    \
} 

/* ----------------------------------------------------------- */
/* Algorithmus siehe "Algorithmen zur Spieleprogrammierung", S. 187ff */

void DL_Line(int x1,int y1,int x2,int y2,int farbe) {
int x,y;
TInterpol ipol;

 SetLine_Interpol(x1,y1,x2,y2,&ipol);
 do {
  if (ipol.swp)
   putpixel(BaseAddr,ipol.ipcoord,ipol.fcoord,farbe);
  else putpixel(BaseAddr,ipol.fcoord,ipol.ipcoord,farbe);
  Do_Interpol(&ipol);
 } while (!LineReady(&ipol));
}

/* Zeichnet eine Linie mittels Gouraudshading mit linearer Interpolation der
   Farbe */
void DL_LineGouraud(int x1,int y1,int x2,int y2,int c1,int c2)
{
int x,y;
TInterpol ipol,ipol_color;

 SetLine_Interpol(x1,y1,x2,y2,&ipol);
 SetColor_Interpol(c1,c2,ipol.a,&ipol_color);
/* if (ipol.swapcolors) {
  xchg(ipol_color.ipcoord,ipol_color.flim);
  ipol_color.IncrIP = -ipol_color.IncrIP;
 }*/
 do {
  if (ipol.swp)
   putpixel(BaseAddr,ipol.ipcoord,ipol.fcoord,ipol_color.ipcoord);
  else putpixel(BaseAddr,ipol.fcoord,ipol.ipcoord,ipol_color.ipcoord);
  Do_Interpol(&ipol);
  Do_ColorInterpol(ipol_color);
 } while (!LineReady(&ipol));
}

#if 0
 
/* Diese Routine zeichnet NUR horizontale Gouraud-Linien NUR im 256-Farb-Modus */
void DL_HLineGouraud256(int x1,int x2,int y,char c1,char c2)
{
int x,w,ctablestart;
unsigned char *scrp;
int aktcolor,inccolor;

 if ((y < 0) || (y >= ScrHeight) || (x2 < x1) ||
     ((x1 < 0) && (x2 < 0)) || ((x1 > ScrWidth) && (x2 > ScrWidth))) return;

 w = x2-x1;
 if (w == 1) {
  scrp = (unsigned char *) BaseAddr+y*ScrWidth+x1;
  *scrp = (c1+c2) >> 1;
  return;
 }
 if (w < 2) return;

 aktcolor = c1 << 10;
 inccolor = ((c2-c1) << 10) / w;

/* for (x = 0; x < w; x++) {
  colortable[x] = aktcolor >> 10;
  aktcolor += inccolor;
 }*/
 /* Pixeltabelle aufbauen, die dann nur noch 1:1 in den Bildspeicher bertragen werden muá */
 asm volatile (
 "
  movl %0,%%edi
  movl %1,%%eax
  movl %2,%%ebx
  movl %3,%%ecx
 ColorTableLoop:
  movl %%eax,%%edx
  shr $10,%%edx
  movb %%dl,(%%edi)
  inc %%edi
  addl %%ebx,%%eax
  dec %%ecx
  jnz ColorTableLoop
 "
 :
 : "g" (&colortable), "g" (aktcolor), "g" (inccolor), "g" (w)
 : "edi","eax","ebx","ecx","edx");
 if (x1 < 0) {
  ctablestart = -x1;
  scrp = (unsigned char *) BaseAddr+y*ScrWidth;
  w += x1;
 } else {
  scrp = (unsigned char *) BaseAddr+y*ScrWidth+x1;
  ctablestart = 0;
 }
 if (x2 >= ScrWidth)
  w -= x2-ScrWidth;
 asm volatile(
 "
  movl %0,%%edi
  movl %1,%%esi
  movl %2,%%ecx
  cmp $4,%%ecx
  jb IsShortLine

  pushl %%ecx
  shr $2,%%ecx
  pushl %%ecx
  rep
  movsl
  popl %%eax
  popl %%ecx
  shl $2,%%eax
  subl %%eax,%%ecx
 IsShortLine:
  rep
  movsb
 "
 :
 : "g" (scrp), "g" (&colortable[ctablestart]), "g" (w)
 : "esi","edi"
 );
}
#endif
 


/* Diese Routine zeichnet NUR horizontale Gouraud-Linien NUR im 256-Farb-Modus */
void DL_HLineGouraud256(int x1,int x2,int y,char c1,char c2)
{
int x,w;
unsigned char *scrp;
int aktcolor,inccolor;

 if ((y < 0) || (y >= ScrHeight) || (x2 <= x1) ||
     ((x1 <= 0) && (x2 <= 0)) || ((x1 >= ScrWidth) && (x2 >= ScrWidth))) return;

 w = x2-x1;
 if (w == 1) {
  scrp = BaseAddr->line[y]+x1;
  _farpokeb(BaseAddr->seg,scrp,((c1+c2) >> 1));
  return;
 }
// if (w < 2) return;

 aktcolor = c1 << 10;
 inccolor = ((c2-c1) << 10) / w;
 if (x1 < 0) {
  scrp = BaseAddr->line[y];
  w += x1;
 } else scrp = BaseAddr->line[y]+x1;
 if (x2 >= ScrWidth)
  w -= x2-ScrWidth+1;

 if ((int) scrp & 1) {
  _farpokeb(BaseAddr->seg,scrp,aktcolor >> 10);
  aktcolor += inccolor;
  scrp++;
  if (--w == 1) {
    _farpokeb(BaseAddr->seg,scrp,aktcolor >> 10);
    return;
   }
 }
  /* Es werden immer 2 Pixel auf einmal berechnet und dann als Word zur
    Grafikkarte geschickt, bei HLineGouraud256_LP wird der letzte Punkt
    gezeichnet, falls die Linienl„nge keine gerade Zahl war
    Da diese Routine auf direkt auf den Bildschirm zeichnen k”nnen
    soll, muá das Segment explizit per Segment-Override angegeben
    werden (Segment in FS)
    */

 asm volatile(
 "
  push %%fs
  mov %4,%%fs
  movl %0,%%edi
  movl %1,%%ecx
  sub $1,%%ecx
  js HLineGouraud256Ende
  inc %%ecx

  movl %2,%%ebx
  push %%ecx
  shr $1,%%ecx
  movl %3,%%esi
  push %%ecx
  jz HLineGouraud256_LP

 HLineGouraud256XLoop:
   mov %%ebx,%%eax
   add %%esi,%%ebx
   shr $10,%%eax

   mov %%ebx,%%edx
   add %%esi,%%ebx
   shr $10,%%edx

   mov %%dl,%%ah
   movw %%ax,%%fs:(%%edi)
   add $2,%%edi

   dec %%ecx
   jnz HLineGouraud256XLoop


   pop %%ecx
   pop %%edx
   shl $1,%%ecx
   sub %%ecx,%%edx
   jz HLineGouraud256Ende
 HLineGouraud256_LP:
   shr $10,%%ebx
   mov %%bl,%%al
   movb %%bl,%%fs:(%%edi)

 HLineGouraud256Ende:
   pop %%fs
 "
 :
 : "g" (scrp), "g" (w), "g" (aktcolor), "g" (inccolor), "g" (BaseAddr->seg)
 : "edi","esi","eax","ebx","ecx","edx"
 );
}

/* -------------------------- DL_FillPolyGouraud ----------------------- */
/* Fllt ein Polygon mittels Gouraud-Shading. Die Farben der Eckpunkte sind im
   Array colors gespeichert. */

int DL_FillPolyGouraud(char nPoint,int points[][2],int colors[]) {
int x,y;
int i,top_point,bottom_point,top_point2;   /* Der h”chste und der niedrigste Punkt des Polygons */
int point_left,point_right,opoint;       /* Nummer des akt. rechten/linken Eckpunktes des Polygons */
int leftswap,rightswap;
int top_y,bottom_y;
TInterpol ipol_left,ipol_right;     /* Interpolationsvariablen fr beide Seiten */
int aktcolor_left,inccolor_left,aktcolor_right,inccolor_right;
int left_x,right_x;          /* x-Koordinate des interpolierten linken/rechten Punkts */
int leftpointx,leftpointy;
int rightpointx,rightpointy;
int rightpointcol,leftpointcol;

 top_y = 0xFFFF;       /* Vorsicht: "top" bedeutet NIEDRIGE y-Koordinate */
 bottom_y = -0xFFFF;

 for (i = 0; i < nPoint; i++) {       /* H”chsten und niedrigsten Punkt des Polygons finden */
  x = points[i][0];
  y = points[i][1];
  if (y <= top_y) {
   if (y == top_y) top_point2 = i;
   else {
     top_y = y;
     top_point = top_point2 = i;
   }
  }
  if (y > bottom_y) {
   bottom_y = y;
   bottom_point = i;
  }
 }

 if ((bottom_y-top_y < 1) || ((top_y <= 0) && (bottom_y <= 0)) ||
     ((top_y >= ScrHeight) && (bottom_y >= ScrHeight))) return(0);
 if ((top_point != top_point2) && (top_point == 0) && (top_point2 == nPoint-1) &&
     (points[top_point][0] < points[top_point2][0])) return(0);

/* if (top_y < 0) top_y = 0;
 if (bottom_y >= ScrHeight) bottom_y = ScrHeight-1;*/
 /* Annahme: Polygon ist im Uhrzeigersinn gespeichert */
 point_left = top_point-1; if (point_left < 0) point_left = nPoint-1;
 if (point_left == top_point2) point_left--;
 point_right = top_point2+1; if (point_right > nPoint-1) point_right = 0;
 if (point_right == top_point) point_right++;

 if (points[top_point][0] > points[top_point2][0])
   if ((top_point == 0) && (top_point2 == nPoint-1)) xchg(top_point,top_point2);
   else
    if (!drawback) return(0); 
   else xchg(top_point,top_point2);

 leftpointx = points[point_left][0]; leftpointy = points[point_left][1];
 rightpointx = points[point_right][0]; rightpointy = points[point_right][1];
 SetLine_Interpol(points[top_point][0],points[top_point][1],
                  leftpointx,leftpointy,&ipol_left);
 aktcolor_left = colors[top_point] << 10;
 if (ipol_left.a) inccolor_left = ((colors[point_left]-colors[top_point]) << 10) / ipol_left.a;
 else inccolor_left = 0;

 SetLine_Interpol(points[top_point2][0],points[top_point2][1],
                  rightpointx,rightpointy,&ipol_right);
 aktcolor_right = colors[top_point2] << 10;
 if (ipol_right.a) inccolor_right = ((colors[point_right]-colors[top_point2]) << 10) / ipol_right.a;
 else inccolor_right = 0;

 leftswap = ipol_left.swp;
 rightswap = ipol_right.swp;
 /* --------- Die Hauptschleife ---------------- */
 for (y = top_y; y <= bottom_y; y++) {

  leftpointcol = aktcolor_left >> 10;
  rightpointcol = aktcolor_right >> 10;
  if (leftswap) {
   left_x = ipol_left.ipcoord;
   Do_Interpol(&ipol_left);
   aktcolor_left += inccolor_left;
  }
  else {
   left_x = ipol_left.fcoord;
   if (ipol_left.Dec_a)
    do { aktcolor_left += inccolor_left; } while (!Do_Interpol(&ipol_left));
 /* ipol-Offsets: a             0
                  dx            4
                  IncrF         8
                  IncrIP        12
                  Dec_a         16
                  fcoord        20
                  ipcoord       24
                  flim          28
                  swp           32
                  swapcolors    36 */

// Assembler-Interpolation vorl„ufig ausgeklammert, da sie sich nicht
// mit den Compiler-Optimierungen vertr„gt
/*         if (ipol_left.Dec_a)
          asm volatile (
          "
           movl %1,%%edi
           push %%edi
           movl (%%edi),%%ecx
           movl %0,%%edi
           movl %2,%%ebx
           movl 8(%%edi),%%edx
           movl 16(%%edi),%%eax
           movl 20(%%edi),%%esi
           push %%ebp
           movl (%%edi),%%ebp
          Do_LeftInterpol:
            addl %%ebx,%%ecx
            addl %%edx,%%esi
            subl %%eax,%%ebp
           jns Do_LeftInterpol

           movl %%esi,20(%%edi)
           movl 4(%%edi),%%eax
           addl %%eax,%%ebp
           movl 12(%%edi),%%eax
           addl %%eax,24(%%edi)
           movl %%ebp,(%%edi)

           pop %%ebp
           pop %%edi
           movl %%ecx,(%%edi)
          "
          :
          : "g" (&ipol_left), "g" (&aktcolor_left), "g" (inccolor_left)
          : "edi","eax","ebx","ecx","edx","esi");*/
      }
    
  if (rightswap) {
   right_x = ipol_right.ipcoord;
   Do_Interpol(&ipol_right);
   aktcolor_right += inccolor_right;
  }
  else {
   right_x = ipol_right.fcoord;
   if (ipol_right.Dec_a)
    do { aktcolor_right += inccolor_right; } while (!Do_Interpol(&ipol_right));
// siehe left-interpol
/*      if (ipol_right.Dec_a)
          asm volatile (
          "
           movl %1,%%edi
           push %%edi
           movl (%%edi),%%ecx
           movl %0,%%edi
           movl %2,%%ebx
           movl 8(%%edi),%%edx
           movl 16(%%edi),%%eax
           movl 20(%%edi),%%esi
           push %%ebp
           movl (%%edi),%%ebp
          Do_RightInterpol:
            addl %%ebx,%%ecx
            addl %%edx,%%esi
            subl %%eax,%%ebp
           jns Do_RightInterpol
        
           movl %%esi,20(%%edi)
           movl 4(%%edi),%%eax
           addl %%eax,%%ebp
           movl 12(%%edi),%%eax
           addl %%eax,24(%%edi)
           movl %%ebp,(%%edi)

           pop %%ebp
           pop %%edi
           movl %%ecx,(%%edi)
          "
          :
          : "g" (&ipol_right), "g" (&aktcolor_right), "g" (inccolor_right)
          : "edi","eax","ebx","ecx","edx","esi");*/
    }
  
  if (!drawback)
   if (left_x > right_x) return(0);
   else ;
  else if (left_x > right_x) { xchg(left_x,right_x); xchg(leftpointcol,rightpointcol); }

  DL_HLineGouraud256(left_x,right_x,y,leftpointcol,rightpointcol);

  /* --- Eventuell neue Eckpunkte setzen ---- */
   if (y == leftpointy) {       /* Wenn eine linke Kante fertiggezeichnet ist, neuen Punkt berechnen */
    opoint = point_left;
    point_left--;
    if (point_left < 0) point_left += nPoint;
    else if (point_left > nPoint-1) point_left -= nPoint;
    leftpointx = points[point_left][0]; leftpointy = points[point_left][1];

    SetLine_Interpol(points[opoint][0],points[opoint][1],
                   leftpointx,leftpointy,&ipol_left);
    leftswap = ipol_left.swp;
     aktcolor_left = colors[opoint] << 10;
     if (ipol_left.a) inccolor_left = ((colors[point_left]-colors[opoint]) << 10) / ipol_left.a;
     else inccolor_left = 0;
   }
   if (y == rightpointy) {      /* Fr die rechte Kante ebenso.... */
    opoint = point_right;
    point_right++;
    if (point_right < 0) point_right += nPoint;
    else if (point_right > nPoint-1) point_right -= nPoint;
    rightpointx = points[point_right][0]; rightpointy = points[point_right][1];

     SetLine_Interpol(points[opoint][0],points[opoint][1],
                   rightpointx,rightpointy,&ipol_right);
     rightswap = ipol_right.swp;
     aktcolor_right = colors[opoint] << 10;
     if (ipol_right.a) inccolor_right = ((colors[point_right]-colors[opoint]) << 10) / ipol_right.a;
     else inccolor_right = 0;
   }
  }
 return(1);
}

#if 0
 
void DL_FillPoly(char nPoint,int points[][2],unsigned char color) {
short int x,y;
char i,top_point,bottom_point,top_point2;   /* Der h”chste und der niedrigste Punkt des Polygons */
char point_left,point_right,opoint;       /* Nummer des akt. rechten/linken Eckpunktes des Polygons */
short int top_y,bottom_y;
TInterpol ipol_left,ipol_right;     /* Interpolationsvariablen fr beide Seiten */
char richtung;                  /* 1 .. Polygon ist im Uhrzeigersinn gespeichert
                                  -1 .. Polygon ist entgegen dem Uhrzeigersinn gespeichert
                                  Durch Addition dieses Wertes kann man den jeweils rechten
                                  Eckpunkt errechnen */
int left_x,right_x;          /* x-Koordinate des interpolierten linken/rechten Punkts */

 top_y = ScrHeight;       /* Vorsicht: "hoch" bedeutet NIEDRIGE y-Koordinate */
 bottom_y = 0;
 for (i = 0; i < nPoint; i++) {       /* H”chsten und niedrigsten Punkt des Polygons finden */
  if (points[i][1] <= top_y) {
   if (points[i][1] == top_y) top_point2 = i;
   else {
     top_y = points[i][1];
     top_point = top_point2 = i;
   }
  }
  if (points[i][1] > bottom_y) {
   bottom_y = points[i][1];
   bottom_point = i;
  }
 }
 /* Annahme: Polygon ist im Uhrzeigersinn gespeichert */
 point_left = top_point-1; if (point_left < 0) point_left += nPoint;
 point_right = top_point+1; if (point_right > nPoint-1) point_right -= nPoint;

 if (points[point_left][0] > points[point_right][0]) {  /* Polygon ist andersrum gespeichert */
  if (!drawback) return;
  xchg(point_left,point_right);
  xchg(top_point,top_point2);
  richtung = -1;
 } else richtung = 1;

 SetLine_Interpol(points[top_point][0],points[top_point][1],
                  points[point_left][0],points[point_left][1],&ipol_left);
 SetLine_Interpol(points[top_point2][0],points[top_point2][1],
                  points[point_right][0],points[point_right][1],&ipol_right);

 for (y = top_y; y < bottom_y; y++) {

  if (ipol_left.swp) left_x = ipol_left.ipcoord;
  else left_x = ipol_left.fcoord;
  if (ipol_right.swp) right_x = ipol_right.ipcoord;
  else right_x = ipol_right.fcoord;

  GrHLine(left_x,right_x,y,color);

  if (ipol_left.swp) Do_Interpol(&ipol_left);
  else while (!Do_Interpol(&ipol_left)) ;
  if (ipol_right.swp) Do_Interpol(&ipol_right) ;
  else while (!Do_Interpol(&ipol_right)) ;

   if (LineReady(&ipol_left)) {       /* Wenn eine linke Kante fertiggezeichnet ist, neuen Punkt berechnen */
    opoint = point_left;
    point_left -= richtung;
    if (point_left < 0) point_left += nPoint;
    else if (point_left > nPoint-1) point_left -= nPoint;
    SetLine_Interpol(points[opoint][0],points[opoint][1],
                   points[point_left][0],points[point_left][1],&ipol_left);
   }
   if (LineReady(&ipol_right)) {      /* Fr die rechte Kante ebenso.... */
    opoint = point_right;
    point_right += richtung;
    if (point_right < 0) point_right += nPoint;
    else if (point_right > nPoint-1) point_right -= nPoint;

     SetLine_Interpol(points[opoint][0],points[opoint][1],
                   points[point_right][0],points[point_right][1],&ipol_right);
   }
  }
}
#endif
 

void DL_Clear32(BITMAP *b)
{
 int y,x;
 unsigned char *scrp;

 for (y = 0; y < b->h; y++) {
  scrp = b->line[y];
  asm volatile (
  "
   push %%es
   mov %2,%%edi
   mov %1,%%es
   mov %0,%%ecx
   shr $2,%%ecx
   xor %%eax,%%eax
   rep
   stosl
   pop %%es
  "
  :
  :"g" (b->w), "g" (b->seg), "g" (scrp)
  :"eax","ecx","edi");
 }
}


#ifdef __cplusplus
 
}
#endif
 

#ifdef test_dlline
 

void main() {
int x,y;
double angle;
int poly[10][2],poly_rot[10][2],i;
int pointcolors[10];
struct time timestart,timeend;
unsigned int tstart,tend;
unsigned char *offscreen;


 RetracePort = _farpeekw(_go32_conventional_mem_selector(),0x40*16+0x63);
 GrSetMode(GR_width_height_color_graphics,320,200,256);
 DLSprInit();
 offscreen = (unsigned char *)malloc(ScrWidth*ScrHeight);
 for (i = 0; i < 64; i++) GrSetColor(i+RedStart,i*4,0,0);

/* poly[0][0] = 100-160; poly[0][1] = 50-100;
 poly[1][0] = 220-160; poly[1][1] = 50-100;
 poly[2][0] = 220-160; poly[2][1] = 150-100;
 poly[3][0] = 100-160; poly[3][1] = 150-100;

 poly[0][0] = -160; poly[0][1] = -150;
 poly[1][0] = 320-160; poly[1][1] = -150;
 poly[2][0] = 320-160; poly[2][1] = 250-100;
 poly[3][0] = -160; poly[3][1] = 250-100;
  */
 poly[0][0] = 50; poly[0][1] = -50;
 poly[1][0] = 100; poly[1][1] = -50;
 poly[2][0] = 100; poly[2][1] = 50;
 poly[3][0] = 50; poly[3][1] = -10;

 pointcolors[0] = RedStart+60;
 pointcolors[1] = RedStart+10;
 pointcolors[2] = RedStart+10;
 pointcolors[3] = RedStart+62;

 drawback = 1;
 DL_FillPolyGouraud(4,poly,pointcolors);
 getchar();
 return;
  
 angle = M_PI/4;
 for (i = 0; i < 4; i++) {
  poly_rot[i][0] = (int)160+(poly[i][0]*cos(angle)-poly[i][1]*sin(angle));
  poly_rot[i][1] = (int)100+(poly[i][0]*sin(angle)+poly[i][1]*cos(angle));
 }
 gettime(×tart);
 tstart = LongTime(timestart.ti_hour,timestart.ti_min,timestart.ti_sec,timestart.ti_hund);
 drawback = 0;
 for (x = 0; x < 500; x++) {
  angle += 0.01;
  for (i = 0; i < 4; i++) {
   poly_rot[i][0] = (int)160+(poly[i][0]*cos(angle)-poly[i][1]*sin(angle));
   poly_rot[i][1] = (int)100+(poly[i][0]*sin(angle)+poly[i][1]*cos(angle));
  }
  BaseAddr = (unsigned int)offscreen;
  DL_ClearScreen();     /* L”scht den Zwischenpuffer */
  DL_FillPolyGouraud(4,poly_rot,pointcolors);
  BaseAddr = 0xD0000000;
  DL_BlitScreen320(offscreen);

/*  angle += 0.01;
  x = (int)(100*sin(angle));
  y = (int)(70*cos(angle));
  DL_LineGouraud(160-x,100-y,160+x,100+y,63,32);
  WaitRetrace();
  DL_Line(160-x,100-y,160+x,100+y,0);*/
 }
 gettime(&timeend);
 tend = LongTime(timeend.ti_hour,timeend.ti_min,timeend.ti_sec,timeend.ti_hund);
 GrSetMode(GR_80_25_text,80,25);
 printf("\n\nZeit pro Bild: %g/100 sec",((float)(tend-tstart)/500));
 printf("\nfps:         : %g",((float)100/((float)(tend-tstart)/500))); 
 getchar();
}
#endif