/* Modul 7 : Vektorgrafikbefehle zu AmigaLisp */

#include <exec/types.h>
#include <intuition/intuitionbase.h>

extern BYTE genug_parameter();
extern void fehler(),delete(),dispose(),nprint();
extern WORD *neu(),*evaluate(),*wahr;
extern float sin(),cos();
extern float getfloat();

struct RastPort *RP;
struct paar { int knotentyp;
              WORD *CAR,*CDR;
            };
struct atom { int knotentyp;
              char zeichenkette[2];     /*alte Knotentypen*/
            };
struct bruch { int knotentyp;
               char kennung[2];
               int zaehler,nenner;
             };

struct operationen { char typ[2];
                     float wert1,wert2,wert3;
                   };

/* operationen nimmt alle Matrizenverknüpfungen auf*/
/* Definition der Operationen : */
/* 0 : Rotation in x-y-Ebene    */
/* 1 : Rotation in x-z-Ebene    */
/* 2 : Rotation in y-z-Ebene    */
/* 3 : Translation              */
/* 4 : Streckung/Stauchung      */

struct objekt { int knotentyp;
                struct object *next; /*nächstes Objekt*/
                struct atom *name;   /*Objektname*/
                int farbe;    /*Farbregister des Objekts*/
                int polygone; /*Anzahl der Polygone des "*/
                float x,y,z;  /*Weltkoordinaten des "*/
                /*bis hier 32 Bytes*/
                int ramzahl; /*Anzahl der Operationen*/
                struct operationen ram[20];/*Stack für Matrizen-*/
                /*operationen zu diesem Objekt*/
                float koordinaten[2];/*wird erweitert...*/
                /*alle Koordinaten aller Polygone mit Anzahlangaben*/
              };

struct objekt *objektliste=0L; /*Kopfzeiger der Objektliste*/

BYTE einobjekt =0; /*für spätere Erweiterungen : */
                   /*wird das Flag auf 1 gesetzt, so ist ein Hidden-Line-*/
                   /*Algorithmus aktiv*/

extern WORD *leeres_atom;

/* defobj generiert aus einer Liste ein Objekt*/

struct atom *defobj(parameter)
struct paar *parameter;
{  if(genug_parameter(parameter,2,2))
   {  /* zunächst Unterlisten Zählen*/
      struct paar *hilf;
      struct atom *merke;
      hilf=parameter->CDR;
      merke=parameter->CAR;
      dispose(parameter);
      parameter=hilf;
      if((!merke)||(merke==-1L)||(merke->knotentyp!=2)||
         (merke->zeichenkette[0]=='#')||
         (merke->zeichenkette[0]=='æ')||
         (merke->zeichenkette[0]=='"'))
      {  /*erster Parameter ist kein Name */
         if(merke!=-1L)
         {  fehler(2,merke);
            delete(merke);
         }
         delete(parameter);
         return(-1L);
      }
      /*merke zeigt nun auf das Namen-Atom*/
      parameter=evaluate(parameter->CAR);
      dispose(hilf);
      if((parameter!=-1L)&&parameter)
      {  struct paar *lauf1,*lauf2,*lauf3;
         struct objekt *objekt,*hilfobj;
         BYTE flag=1,killobj();
         int i=0,j=0,k;
         float mitte[3]; /*Mittelpunkt eines Polygonzugs*/
         lauf1=parameter;
         while(lauf1&&flag)
         {  i++; /*noch ein Polygonzug*/
            lauf2=lauf1->CAR;
            while(lauf2&&flag)
            {  if((lauf2->knotentyp!=1)||(lauf1->knotentyp!=1))
                 flag=0;
               else
               {  lauf2=lauf2->CDR;
                  j++;
               }
            }
            lauf1=lauf1->CDR;
         } /*i = Anzahl Polygonzüge, j*3 = Anzahl Koordinaten*/
         if(!flag)
         {  fehler(2,parameter);
            delete(parameter);
            dispose(merke);
            return(-1L);
         }
         /* ev. ältere Datenstruktur gleichen Namens löschen*/

         flag=killobj(merke); /*flag ist dummy*/
         flag=1;

         /* Nun Platz für die anzulegende Datenstruktur schaffen*/

         objekt=neu(36+sizeof(struct operationen)*20+(i*4+j*3)*4);
         if(objektliste)
         {  /* neues Objekt anketten*/
            hilfobj=objektliste;
            while(hilfobj->next)
               hilfobj=hilfobj->next;
            hilfobj->next=objekt;
         }
         else
            objektliste=objekt;
         objekt->knotentyp=5;
         objekt->next=0L;
         objekt->name=merke;
         objekt->farbe=1;    /*kann mit anderen Befehlen eingest. werden*/
         objekt->polygone=i;
         objekt->x=0.0;      /*ebenfalls noch festzulegen*/
         objekt->y=0.0;
         objekt->z=0.0;
         objekt->ramzahl=0; /*Liste abschießen*/
         /* Nun die einzelnen Koordinaten eintragen :*/
         lauf1=parameter; i=4;
         while(lauf1&&flag)  /*Liste der Polygone*/
         {  lauf2=lauf1->CAR;
            lauf1=lauf1->CDR;
            j=0;
            mitte[0]=mitte[1]=mitte[2]=0.0;
            while(lauf2&&flag) /*für jedes Polygon*/
            {  lauf3=lauf2->CAR;
               lauf2=lauf2->CDR;
               for(k=0;(k<3)&&flag;k++) /*Koordinatentripel lesen*/
               {  if(lauf3&&(lauf3->knotentyp==1)&&
                     (lauf3->CAR)&&(*((int*)(lauf3->CAR))==2)&&
                     (((struct atom*)(lauf3->CAR))->zeichenkette[0]=='æ'))
                     mitte[k]+=(objekt->koordinaten[i+j*3+k]=getfloat(lauf3->CAR));
                  else
                  {  if(lauf3&&(lauf3->knotentyp==1))
                        fehler(2,lauf3->CAR); /*keine Zahl*/
                     else
                        fehler(2,lauf3);
                     flag=0;
                  }
                  lauf3=lauf3->CDR;
               }
               if(flag&&lauf3) /*kein Tripel*/
               {  fehler(2,lauf3);
                  flag=0;
               }
               j++;
            }
            /* Anzahl der Koordinatentripel pro Polygon festhalten*/
            objekt->koordinaten[i-4]=(float)(j);
            /*Mittelpunkt der beschriebenen Fläche*/
            objekt->koordinaten[i-3]=mitte[0]/(float)(j);
            objekt->koordinaten[i-2]=mitte[1]/(float)(j);
            objekt->koordinaten[i-1]=mitte[2]/(float)(j);
            i+=j*3+4;
         }
         delete(parameter); /*Liste jetzt im Feld gespeichert*/
         if(flag)
            return(leeres_atom);
         else
         {  if(objektliste==objekt)
               objektliste=0L;
            else
               hilfobj->next=0L;
            dispose(objekt);
            dispose(merke);
            return(-1L);
         }
      }
      else
      {  dispose(merke);
         if(!parameter)
            fehler(2,0L);
         return(-1L);
      }
   }
   else
   {  delete(parameter);
      return(-1L);
   }
}

extern BYTE compare();

/* suchobjekt identifiziert ein Grafikobjekt durch seinen Namen*/

struct objekt *suchobjekt(parameter)
struct atom *parameter;
{  if((!parameter)||(parameter==-1L)||(parameter->knotentyp!=2))
   {  fehler(2,parameter);
      delete(parameter);
      return(-1L);
   }
   else
   {  char *z1,*z2;
      struct objekt *lauf;
      BYTE flag=1;
      lauf=objektliste;
      while(lauf&&flag)
      {  z2=lauf->name->zeichenkette;
         z1=parameter->zeichenkette;
         while((*z1==*z2)&&(*z1)) {z1++;z2++;}
         if(*z1==*z2)
            flag=0;
         else
            lauf=lauf->next;
      }
      dispose(parameter);
      if(flag)
      {  nprint("\nFehler : Objekt existiert nicht.\n");
         return(-1L);
      }
      else
         return(lauf);
   }
}

BYTE killobj(name)
struct atom *name;
{  struct objekt *hilfobj,*mobj;
   BYTE flag=1;
   char *z1,*z2;

   hilfobj=objektliste;
   while(hilfobj&&flag)
   {  z1=hilfobj->name->zeichenkette;
      z2=name->zeichenkette;
      while((*z1==*z2)&&(*z1)) {z1++;z2++;}
      if(*z1==*z2) /*gefunden*/
      {  if(hilfobj==objektliste)
            objektliste=hilfobj->next;
         else
            mobj->next=hilfobj->next;
         dispose(hilfobj->name);
         dispose(hilfobj);
         flag=0;  /*höchstens 1 Objekt dieses Namens*/
      }
      mobj=hilfobj;
      hilfobj=hilfobj->next;
   }
   return(!flag);
}

/* killobjekt ermöglicht dem Programmierer, ein bereits definiertes*/
/* Grafikobjekt wieder zu entfernen. */

struct atom *killobjekt(parameter)
struct paar *parameter;
{  if(genug_parameter(parameter,1,1))
   {  struct atom *hilf;
      hilf=parameter->CAR;
      dispose(parameter);
      if((hilf==0L)||(hilf->knotentyp==1))
      {  fehler(2,hilf);
         delete(hilf);
         return(-1L);
      }
      else
         if(killobj(hilf))
         {  dispose(hilf);
            return(wahr);
         }
         else
         {  dispose(hilf);
            return(0L);
         }
   }
   else
   {  delete(parameter);
      return(-1L);
   }
}

/* objlist zeigt die Namen aller verfügbarer Grafikobjekte an */

struct atom *objlist(parameter)
struct paar *parameter;
{  struct objekt *lauf;
   int cr=0; /*return bei der Ausgabe*/
   lauf=objektliste;
   nprint("\nDie Liste aller Grafikobjekte : ");
   if(lauf==0L) nprint("ist leer !");
   while(lauf!=0L)
   {  nprint(lauf->name->zeichenkette);nprint(" ");
      cr=(cr+1)%6;if(!cr) nprint("\n");
      lauf=lauf->next;
   }
   nprint("\n");
   return(leeres_atom);
}

/* weltpos legt die Weltkoordinaten für ein Objekt fest */
/* außerdem Translation und Streckung !*/


struct atom *weltpos(parameter,typ)
struct paar *parameter;
BYTE typ; /* 0:Weltkoordinaten 1:Translation, 2:Streckung*/
{  if(genug_parameter(parameter,2,2))
   {  struct paar *hilf;
      struct atom *merke;
      struct objekt *objekt;
      BYTE flag=1;
      float w[3];
      int i=0;
      merke=parameter->CAR;
      hilf=parameter;
      parameter=parameter->CDR;
      dispose(hilf);
      objekt=suchobjekt(merke);
      if(objekt==-1L)
      {  delete(parameter);
         return(-1L);
      }
      hilf=parameter;
      parameter=evaluate(parameter->CAR); /*wertet zu Liste aus*/
      dispose(hilf);
      if((parameter==-1L)||(!parameter)||(parameter->knotentyp!=1))
      {  if(parameter!=-1L)
         {  fehler(2,parameter);
            delete(parameter);
         }
         return(-1L);
      }
      hilf=parameter;
      while((i<3)&&hilf&&(hilf->knotentyp==1)&&flag)
      {  if((hilf->CAR)&&(*((int*)(hilf->CAR))==2)&&
            (((struct atom*)(hilf->CAR))->zeichenkette[0]=='æ'))
           w[i++]=getfloat(hilf->CAR);
         else
         {  flag=0;
            fehler(2,hilf->CAR);
         }
         hilf=hilf->CDR;
      }
      if(flag&&hilf)      /*Zuviele Koordinaten*/
      {  fehler(2,hilf);
         flag=0;
      }
      delete(parameter);
      if(flag)
      {  if(!typ)  /*neue Weltkoordinaten setzen*/
         {  objekt->x=w[0];
            objekt->y=w[1];
            objekt->z=w[2];
            return(leeres_atom);
         }
         else      /*Translation oder Streckung*/
         {  if(objekt->ramzahl<20)
            {  objekt->ram[objekt->ramzahl].typ[0]=typ+2;
               objekt->ram[objekt->ramzahl].wert1=w[0];
               objekt->ram[objekt->ramzahl].wert2=w[1];
               objekt->ram[objekt->ramzahl++].wert3=w[2];
               return(leeres_atom);
            }
            else
            {  nprint("\nFehler : Zuviele Matrizenoperationen.\n");
               return(-1L);
            }
         }
      }
      else
         return(-1L);
   }
   else
   {  delete(parameter);
      return(-1L);
   }
}

/* mit farbe wird die Zeichenfarbe für ein Objekt bestimmt.*/
/* diese Funktion setzt außerdem Rotationsbefehle*/

struct atom *farbe_rotat(parameter,typ)
struct paar *parameter;
BYTE typ; /*typ = 0:Farbe, 1:Rotation xy, 2:xz, 3:yz*/
{  if(genug_parameter(parameter,2,2))
   {  struct atom *merke;
      struct paar *hilf;
      struct objekt *objekt;
      merke=parameter->CAR;
      hilf=parameter;
      parameter=parameter->CDR;
      dispose(hilf);
      objekt=suchobjekt(merke);
      if(objekt==-1L)
      {  delete(parameter);
         return(-1L);
      }
      hilf=parameter;
      parameter=evaluate(parameter->CAR); /*wertet zu Registernr. aus*/
      dispose(hilf);
      if((!parameter)||(parameter==-1L)||(parameter->knotentyp!=2)||
         (((struct atom*)parameter)->zeichenkette[0]!='æ'))
      {  if(parameter!=-1L)
         {  fehler(2,parameter);
            delete(parameter);
         }
         return(-1L);
      }
      else
      {  float zahl;
         zahl = getfloat(parameter);
         dispose(parameter);
         if(!typ)
         {   objekt->farbe=(int)zahl;
             return(leeres_atom);
         }
         else
         {  if(objekt->ramzahl<20)
            {  objekt->ram[objekt->ramzahl].typ[0]=typ-1;
               objekt->ram[objekt->ramzahl++].wert1=zahl*3.1416/180.0;
               /*Winkel werden in Grad gemessen...*/
               return(leeres_atom);
            }
            else
            {  nprint("\nFehler : Zuviele Matrizenoperationen.\n");
               return(-1L);
            }
         }
      }
   }
   else
   {  delete(parameter);
      return(-1L);
   }
}

/* Matrizenrechnen */

struct matrix { float matrix[4][4]; }matrix1,matrix2,matrix3;
struct matrix *m1,*m2,*m3;

/* initmatrix erstellt eine gewünschte Matrix */

void initmatrix(zeig,typ,wert1,wert2,wert3)
struct matrix *zeig;
BYTE typ;
float wert1,wert2,wert3;
{  register int i,j;
   register struct matrix *zeiger;
   zeiger=zeig; /*zur Beschleunigung*/
   for(i=0;i<4;i++)
      for(j=0;j<4;j++)
         if(i==j)                        /*Aufbau der Einheitsmatrix*/
            zeiger->matrix[i][j]=1.0;
         else
            zeiger->matrix[i][j]=0.0;
   switch(typ)
   {  case 0 : zeiger->matrix[0][0]=cos(wert1);
               zeiger->matrix[0][1]=-sin(wert1); /*um z-Achse*/
               zeiger->matrix[1][0]=sin(wert1);
               zeiger->matrix[1][1]=cos(wert1);
               break;
      case 1 : zeiger->matrix[0][0]=cos(wert1);
               zeiger->matrix[0][2]=-sin(wert1); /*um y-Achse*/
               zeiger->matrix[2][0]=sin(wert1);
               zeiger->matrix[2][2]=cos(wert1);
               break;
      case 2 : zeiger->matrix[1][1]=cos(wert1);
               zeiger->matrix[1][2]=-sin(wert1); /*um x-Achse*/
               zeiger->matrix[2][1]=sin(wert1);
               zeiger->matrix[2][2]=cos(wert1);
               break;
      case 3 : zeiger->matrix[0][3]=wert1;
               zeiger->matrix[1][3]=wert2; /*Translation*/
               zeiger->matrix[2][3]=wert3;
               break;
      case 4 : zeiger->matrix[0][0]=wert1;
               zeiger->matrix[1][1]=wert2; /*Streckung*/
               zeiger->matrix[2][2]=wert3;
               break;
      case 5 : break; /*Einheitsmatrix*/
   }
}

/* mamult multipliziert die 4-4 Matrizen z1 und z2.*/
/* Das Ergebnis findet sich in z3*/

void mamult(z1,z2,z3)
struct matrix *z1,*z2,*z3;
{  register int i,j,k;
   for(i=0;i<4;i++)
      for(j=0;j<4;j++)
      {  z3->matrix[i][j]=0.0;
         for(k=0;k<4;k++)
            z3->matrix[i][j]+=(z1->matrix[i][k])*(z2->matrix[k][j]);
      }
}

/* ma_aus gibt eine Matrix zu Wartungszwecken aus.*/

void ma_aus(z)
struct matrix *z;
{  int i,j;
   printf("\n");
   for(i=0;i<4;i++)
   {  for(j=0;j<4;j++)
         printf("%f ",z->matrix[i][j]);
      printf("\n");
   }
}

/* zusammenfassen führt alle in Objekt gespeicherten Operationen aus*/
/* das Ergebnis befindet sich in m1, Achtung: m2 und m3 werden benutzt*/

void zusammenfassen(objekt)
struct objekt *objekt;
{  int pos;
   struct matrix *tausch;
   pos=objekt->ramzahl;
   m1=&matrix1;m2=&matrix2;m3=&matrix3;
   initmatrix(m1,3,objekt->x,objekt->y,objekt->z);/*Weltkoordinaten*/
   while(pos)
   {  pos--;
      initmatrix(m2,objekt->ram[pos].typ[0],objekt->ram[pos].wert1,
                    objekt->ram[pos].wert2, objekt->ram[pos].wert3);
      mamult(m1,m2,m3);
      tausch=m1;m1=m3;m3=tausch; /*Ergebnis nach m1 !*/
   }
   objekt->ramzahl=0; /*Liste zurücksetzen*/
}

int x2,y2; /*Punktkoordinaten eines Transformietern Punktes*/
#define zoom 400.0 /*Enfernung Beobachter zum Bildschirm*/

/* vemult multipliziert die Matrix m mit dem angegebenen Punkt*/
/* und führt anschließend die Transformation 3D->2D durch.*/

float xh,yh,zh;

BYTE ruecken=0; /*ev. später ein Vorderseitenclipping einbauen*/

void vemult(m,x3,y3,z3)
struct matrix *m;
float x3,y3,z3;
{  xh=x3*(m->matrix[0][0])+y3*(m->matrix[0][1])+z3*(m->matrix[0][2])+m->matrix[0][3];
   yh=x3*(m->matrix[1][0])+y3*(m->matrix[1][1])+z3*(m->matrix[1][2])+m->matrix[1][3];
   zh=x3*(m->matrix[2][0])+y3*(m->matrix[2][1])+z3*(m->matrix[2][2])+m->matrix[2][3];
   if(zh>=0)
   { x2=(int)(zoom*xh/(zoom+zh));   /*zugleich Umrechnung der*/
     y2=(int)(zoom*yh/(zoom+zh))/2; /*Bildschirmverzerrung*/
     ruecken=0;
   }
   else
      ruecken=1;
}

/* wird in dieser Programmversion nicht benutzt : */
/* (Hidden-Line Algorithmus */
BYTE nsichtbar(m,x2,y2,z2,x3,y3,z3)
struct matrix *m;
float x2,y2,z2,x3,y3,z3;
{  float ax,ay,bx,by,az,bz,x,y,z;
   float h;
   h=x2*(m->matrix[0][0])+y2*(m->matrix[0][1])+z2*(m->matrix[0][2])+m->matrix[0][3];
   ax=h-xh;
   bx=x3*(m->matrix[0][0])+y3*(m->matrix[0][1])+z3*(m->matrix[0][2])+m->matrix[0][3]
     -h;
   h=x2*(m->matrix[1][0])+y2*(m->matrix[1][1])+z2*(m->matrix[1][2])+m->matrix[1][3];
   ay=h-yh;
   by=x3*(m->matrix[1][0])+y3*(m->matrix[1][1])+z3*(m->matrix[1][2])+m->matrix[1][3]
     -h;
   h=x2*(m->matrix[2][0])+y2*(m->matrix[2][1])+z2*(m->matrix[2][2])+m->matrix[0][3];
   az=h-zh;
   bz=x3*(m->matrix[2][0])+y3*(m->matrix[2][1])+z3*(m->matrix[2][2])+m->matrix[0][3]
     -h;
   /*Vektorprodukt berechnen :*/
   x=ay*bz-az*by;
   y=az*bx-ax*bz;
   z=ax*by-ay*bx;
   if(-x*x3-y*y3-z*(z3+zoom/2.0)>0.0) return(0);  /*Winkel als Cos-Wert*/
   return(1);
}

void polymult(m,x3,y3,z3)
struct matrix *m;
float x3,y3,z3;
{  float x,y,z,xm,ym;
   int x22,y22;
   void linie();
   x=x3*(m->matrix[0][0])+y3*(m->matrix[0][1])+z3*(m->matrix[0][2])+m->matrix[0][3];
   y=x3*(m->matrix[1][0])+y3*(m->matrix[1][1])+z3*(m->matrix[1][2])+m->matrix[1][3];
   z=x3*(m->matrix[2][0])+y3*(m->matrix[2][1])+z3*(m->matrix[2][2])+m->matrix[2][3];
   if((zh>=0)&&(z>=0))
   {  x22 =(int)(zoom*x/(zoom+z));
      y22 =(int)(zoom*y/(zoom+z))/2;
      linie(x2,y2,x22,y22);
      x2=x22;y2=y22;
      xh=x;yh=y;zh=z;
      return();
   }
   if((zh<0)&&(z<0))      /*Linie nicht sichtbar*/
   {  xh=x;yh=y;zh=z;
      return();
   }
   if(zh>=0)   /*aktueller Punkt nicht sichtbar*/
   {  x22=(int)((x-xh)*zh/(zh-z)+xh);
      y22=(int)((y-yh)*zh/(zh-z)+yh)/2; /*liegt auf Bildschirmebene,*/
      linie(x2,y2,x22,y22);             /*daher keine Fallunterscheidung*/
      xh=x;yh=y;zh=z;
      return();
   }
   else   /*letzter Punkt nicht sichtbar*/
   {  x22=(int)((xh-x)*z/(z-zh)+x);
      y22=(int)((yh-y)*z/(z-zh)+y)/2;
      x2 =(int)(zoom*x/(zoom+z));
      y2 =(int)(zoom*y/(zoom+z))/2;
      linie(x2,y2,x22,y22);
      xh=x;yh=y;zh=z;
      return();
   }
}

extern struct Window *GWindow1;
extern struct Screen *GScreen;
/*auf Turtle-Modul Bezug nehmen*/
extern struct IntuitionBase *IntuitionBase;

/* linie zeichnet eine Linie*/
/* und verwendet den Cohen-Sutherland-Clipping-Algorithmus*/

void linie(a1,b1,a2,b2)
int a1,a2,b1,b2;
{  BYTE code1=0,code2=0,code3=0,hilf,flag=0;
   int x1,x2,y1,y2;
   int i,j;
   register int Mx,My;

   if(a1<=-218)
     code1|=1;
   else
      if(a1>=218)
         code1|=2;
   if(b1<=-100)
      code1|=4;
   else
      if(b1>=100)
         code1|=8;

   if(a2<=-218)
     code2|=1;
   else
      if(a2>=218)
         code2|=2;
   if(b2<=-100)
      code2|=4;
   else
      if(b2>=100)
         code2|=8;
   hilf=code1;
   if(code1&code2)
      /*Linie nicht sichtbar !*/
      return();
   if((!code1)&&(!code2))
   {  /*Linie im Bildschirm*/
      Move(RP,220+a1,102-b1);
      Draw(RP,220+a2,102-b2);
      return();
   }
   x1=a1;x2=a2;y1=b1;y2=b2;
   for(i=0;i<2;i++)
   {  if(code2)
      { do
        {flag=0;
         Mx=(x1+x2)>>1;
         My=(y1+y2)>>1;
         code3=0;
         if(Mx<=-218)
            code3|=1;
         else
            if(Mx>=218)
               code3|=2;
         if(My<=-100)
            code3|=4;
         else
            if(My>100)
               code3|=8;
         if((code1&code3)&&(code2&code3))
            return(); /*Linie außerhalb*/
         if(((Mx!=x1)||(My!=y1))&&
             ((Mx!=x2)||(My!=y2)))
         {  if(code3&code2) /*rechten Linienendpunkt verschieben*/
            {  x2=Mx;
               y2=My;
               code2=code3;
            }
            else
            {  x1=Mx;
               y1=My;
               code1=code3;
            }
            flag=1;
         }
        }while(flag);
        if(i)
        {  a1=x1; /*Schnittpunkt setzen*/
           b1=y1;
        }
        else
        {  a2=x1;
           b2=y1;
        }
      }
      if(!i)   /*linker Punkt*/
      {  code2=hilf;
         code1=0;
         x1=a2;
         x2=a1;
         y1=b2;
         y2=b1;
      }
   }
   Move(RP,220+a1,102-b1);
   Draw(RP,220+a2,102-b2);
}

void plotten(objekt)
struct objekt *objekt;
{
   float *lauf;
   int i,j,k;

   SetAPen(RP,objekt->farbe);
   zusammenfassen(objekt); /*Matrizen erstellen und multiplizieren*/

   /* Testen, ob sich Objekt im Sichtfenster befindet*/
   vemult(m1,objekt->x,objekt->y,objekt->z);
   if((zh<0.0)||(zh>3000.0)||(x2>=420)||(x2<-420)||(y2<-300)||(y2>=300))
   return(); /*über 200 Pkt außerhalb des Sichtfensters*/

   lauf=&(objekt->koordinaten[0]);
   for(i=0;i<(objekt->polygone);i++) /*Alle Polygone zeichnen*/
   {  j=(int)(*lauf); /*j=Anzahl Koordinatentripel im Polygon*/
      lauf+=4;
      if(j==1)
      {  vemult(m1,*lauf,*(lauf+1),*(lauf+2));
         lauf+=3;
         if((!ruecken)&&(x2>-218)&&(x2<218)&&(y2>-100)&&(y2<100))
            WritePixel(RP,220+x2,102-y2);
      }
      else
      {  float *merke;
         vemult(m1,*lauf,*(lauf+1),*(lauf+2));
         if(einobjekt&&(j>2)&&nsichtbar(m1,
            *(lauf+3),*(lauf+4),*(lauf+5),*(lauf-3),*(lauf-2),
            *(lauf-1))) /*letzte Koordinate ist Mittelpunkt*/
           lauf+=j*3;     /* Fläche nicht sichtbar */
         else
         { merke=lauf;
           lauf+=3;
           for(k=0;k<j-1;k++)
           {  polymult(m1,*lauf,*(lauf+1),*(lauf+2));
              lauf+=3;
           }
           if(j>2) /*geschlossener Polygonzug*/
              polymult(m1,*merke,*(merke+1),*(merke+2));
         }
      }
   }
}

/* drawobj zeichnet ein Grafikobjekt */

struct atom *drawobj(parameter)
struct paar *parameter;
{  if(GWindow1)
   if(genug_parameter(parameter,1,1))
   {  struct atom *merke;
      struct objekt *objekt;

      RP=GWindow1->RPort;
      merke=parameter->CAR;
      dispose(parameter);
      objekt=suchobjekt(merke);
      if(objekt==-1L)
      {  delete(parameter);
         return(-1L);
      }
      plotten(objekt);
      return(leeres_atom);
   }
   else
   {  delete(parameter);
      return(-1L);
   }
   else
   {  fehler(23,0L);
      delete(parameter);
      return(-1L);
   }
}

struct atom *world(parameter)
{  struct objekt *lauf;
   ULONG zeile[40];
   if(GWindow1)
   { if(parameter)
     {  fehler(2,parameter);
        delete(parameter);
        return(-1L);
     }
     lauf=objektliste;
     if(GScreen) RP=&GScreen->RastPort;
     else RP=GWindow1->RPort;
     SetAPen(RP,0);
     RectFill(RP,2,2,437,202);
     SetAPen(RP,1);
     while(lauf)
     {  plotten(lauf);
        lauf=lauf->next;
     }
     if(GScreen)
        BltBitMap(&GScreen->BitMap,2,2,&IntuitionBase->ActiveScreen->BitMap
                  ,202,2,436,200,0xc0,3,zeile);
     /* zweiten Bildschirm verstecken */
     return(leeres_atom);
   }
   else
   {  fehler(23,0L);
      delete(parameter);
      return(-1L);
   }
}

