/***********************************************************/
/*                  The 3D-Object-Animator                 */
/*                 written by Wolf Dietrich                */
/*              especially for  KICKSTART  9/87            */
/***********************************************************/
#include <exec/types.h>
#include <graphics/gfxmacros.h>
#include <stdio.h>
#include <math.h>
#include <exec/devices.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <ctype.h>
#include <fcntl.h>
#include <functions.h>

#define CONTINUE      for(;;)
#define MAXPPF        20
#define MAXFL         40
#define MAXP          200
#define FAK           100000L
#define PI            3.1415926

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;

struct NewScreen graph_screen =
{
 0, 0, 320, 214,
 4, 0, 1, NULL, CUSTOMSCREEN,
 NULL, NULL, NULL, NULL,      
};

struct ViewPort   *vp_1, *vp_2;
struct Screen     *screen_1, *screen_2;
struct NewWindow  graph_window_1,graph_window_2, 
                  info_nwindow_1,info_nwindow_2;
struct Window  *window_1, *window_2, 
               *info_window_1, *info_window_2;
struct RastPort *rp_1, *rp_2, *rp_3, *rp_4;

struct TmpRas temp_ras;
struct AreaInfo area_info;

BYTE *area_plane;
char *filename, *zielchar, zielstring[10];
UWORD areabuf[100];
USHORT farbliste[] = {0x000,0x00f,0x0f0,0xf00,
                      0x0ff,0xf0f,0xff0,0xfff,
                      0xf6b,0x3a9,0x492,0x777,
                      0xbbb,0x07c,0xc40,0x90a  };
int sinus[360],cosin[360],zoom;
int pkt_zahl = 0,flaech_zahl = 0,pkt_p_flaech[MAXFL] ;
int obj_xturn,obj_yturn,obj_zturn,xdreher,ydreher,zdreher;
int sichtbar[MAXFL],plst[MAXFL][MAXPPF],filenumber;
long sp[MAXP],ze[MAXP],cx[MAXP],cz[MAXP],cy[MAXP],farbe[MAXFL];               
float fzoom;


main()
{ 
 init_trig();
 graph_screens();

 rp_1 = window_1->RPort;
 rp_2 = window_2->RPort;
 rp_3 = info_window_1->RPort;
 rp_4 = info_window_2->RPort;
 vp_1 = &screen_1->ViewPort;
 vp_2 = &screen_2->ViewPort;

 LoadRGB4(vp_1,farbliste,16L);
 LoadRGB4(vp_2,farbliste,16L);

 SetRast(rp_3,0L);
 SetRast(rp_4,0L);

 rp_1->Layer->ClipRect->bounds.MinX = (SHORT)0;
 rp_1->Layer->ClipRect->bounds.MinY = (SHORT)0;
 rp_1->Layer->ClipRect->bounds.MaxX = (SHORT)319;
 rp_1->Layer->ClipRect->bounds.MaxY = (SHORT)199;
 rp_2->Layer->ClipRect->bounds.MinX = (SHORT)0;
 rp_2->Layer->ClipRect->bounds.MinY = (SHORT)0;
 rp_2->Layer->ClipRect->bounds.MaxX = (SHORT)319;
 rp_2->Layer->ClipRect->bounds.MaxY = (SHORT)199;

 InitArea(&area_info,&areabuf[0],40L);

 rp_1->AreaInfo = &area_info;
 rp_2->AreaInfo = &area_info;
 rp_1->TmpRas   = &temp_ras;
 rp_2->TmpRas   = &temp_ras ;

 area_plane = AllocMem(8000L,MEMF_CHIP);

 rp_1->TmpRas->RasPtr = area_plane;
 rp_1->TmpRas->Size   = (long)RASSIZE(320,200);   
 rp_2->TmpRas->RasPtr = area_plane;
 rp_2->TmpRas->Size   = (long)RASSIZE(320,200);  

 object_drawer(); 
 ausstieg();  
}      

graph_screens()
{  
 IntuitionBase=(struct IntuitionBase *)
   OpenLibrary("intuition.library",0L);
 GfxBase=(struct GfxBase *)
   OpenLibrary("graphics.library",0L);

 screen_1=(struct Screen *)OpenScreen(&graph_screen); 
 screen_2=(struct Screen *)OpenScreen(&graph_screen);
 
 graph_window_1.LeftEdge = 0;
 graph_window_1.TopEdge  = 0;
 graph_window_1.Width    = 320;
 graph_window_1.Height   = 200;
 graph_window_1.DetailPen = 0;
 graph_window_1.BlockPen = 1; 
 graph_window_1.Title    = NULL;
 graph_window_1.Flags    = SIMPLE_REFRESH;
 graph_window_1.IDCMPFlags = NULL;
 graph_window_1.Type       = CUSTOMSCREEN;
 graph_window_1.FirstGadget= NULL;
 graph_window_1.CheckMark  = NULL;
 graph_window_1.Screen     = screen_1;
 graph_window_1.BitMap     = NULL;
 graph_window_1.MinWidth   = 320;
 graph_window_1.MinHeight  = 200;
 graph_window_1.MaxWidth   = 320;
 graph_window_1.MaxHeight  = 200;
 
 window_1=(struct Window *)OpenWindow(& graph_window_1); 

 graph_window_2.LeftEdge = 0;
 graph_window_2.TopEdge  = 0;
 graph_window_2.Width    = 320;
 graph_window_2.Height   = 200;
 graph_window_2.DetailPen = 0;
 graph_window_2.BlockPen = 1; 
 graph_window_2.Title    = NULL;
 graph_window_2.Flags    = SIMPLE_REFRESH;
 graph_window_2.IDCMPFlags = NULL;
 graph_window_2.Type       = CUSTOMSCREEN;
 graph_window_2.FirstGadget= NULL;
 graph_window_2.CheckMark  = NULL;
 graph_window_2.Screen     = screen_2;
 graph_window_2.BitMap     = NULL;
 graph_window_2.MinWidth   = 320;
 graph_window_2.MinHeight  = 200;
 graph_window_2.MaxWidth   = 320;
 graph_window_2.MaxHeight  = 200;

 window_2=(struct Window *)OpenWindow(&graph_window_2); 

 info_nwindow_1.LeftEdge = 0;
 info_nwindow_1.TopEdge  = 200;
 info_nwindow_1.Width    = 320;
 info_nwindow_1.Height   = 13;
 info_nwindow_1.DetailPen = 0;
 info_nwindow_1.BlockPen = 1; 
 info_nwindow_1.Title    = NULL;
 info_nwindow_1.Flags    = SIMPLE_REFRESH;
 info_nwindow_1.IDCMPFlags = NULL;
 info_nwindow_1.Type       = CUSTOMSCREEN;
 info_nwindow_1.FirstGadget= NULL;
 info_nwindow_1.CheckMark  = NULL;
 info_nwindow_1.Screen     = screen_1;
 info_nwindow_1.BitMap     = NULL;
 info_nwindow_1.MinWidth   = 320;
 info_nwindow_1.MinHeight  = 13;
 info_nwindow_1.MaxWidth   = 320;
 info_nwindow_1.MaxHeight  = 13;

 info_window_1=(struct Window *)OpenWindow(&info_nwindow_1);

 info_nwindow_2.LeftEdge = 0;
 info_nwindow_2.TopEdge  = 200;
 info_nwindow_2.Width    = 320;
 info_nwindow_2.Height   = 13;
 info_nwindow_2.DetailPen = 0;
 info_nwindow_2.BlockPen = 1; 
 info_nwindow_2.Title    = NULL;
 info_nwindow_2.Flags    = SIMPLE_REFRESH|ACTIVATE;
 info_nwindow_2.IDCMPFlags = VANILLAKEY;
 info_nwindow_2.Type       = CUSTOMSCREEN;
 info_nwindow_2.FirstGadget= NULL;
 info_nwindow_2.CheckMark  = NULL;
 info_nwindow_2.Screen     = screen_2;
 info_nwindow_2.BitMap     = NULL;
 info_nwindow_2.MinWidth   = 320;
 info_nwindow_2.MinHeight  = 13;
 info_nwindow_2.MaxWidth   = 320;
 info_nwindow_2.MaxHeight  = 13;

 info_window_2=(struct Window *)OpenWindow(&info_nwindow_2);
}

object_drawer()
{ 
 int loop,pind;
 int abbruch = FALSE;

 zoom = 10;
 fzoom = (float)zoom;
 fzoom = (float)(fzoom/10);

 SetOPen(rp_1,0L);
 SetOPen(rp_2 ,0L); 
 SetAPen(rp_3,3L);
 SetAPen(rp_4,3L); 

 info_text();

 CONTINUE
 {
  transform();
 
  BltClear(rp_1->BitMap->Planes[0],8000L,0L);
  BltClear(rp_1->BitMap->Planes[1],8000L,0L);
  BltClear(rp_1->BitMap->Planes[2],8000L,0L);
  BltClear(rp_1->BitMap->Planes[3],8000L,0L);

  for(loop=0;loop<flaech_zahl;loop++)
  { 
   if(sichtbar[loop])
   {   
    SetAPen(rp_1,farbe[loop]); 
    AreaMove(rp_1,sp[plst[loop][0]],ze[plst[loop][0]]);
    for(pind=1;pind<pkt_p_flaech[loop];pind++)
     AreaDraw(rp_1,sp[plst[loop][pind]],ze[plst[loop][pind]]);
    AreaEnd(rp_1  );
    sichtbar[loop] = FALSE;
   }
  } 
  ScreenToFront(screen_1);

  abbruch = lies_tastatur();
  if(abbruch) break;
 
  transform();

  BltClear(rp_2->BitMap->Planes[0],8000L,0L);
  BltClear(rp_2->BitMap->Planes[1],8000L,0L);
  BltClear(rp_2->BitMap->Planes[2],8000L,0L);
  BltClear(rp_2->BitMap->Planes[3],8000L,0L);

  for(loop=0;loop<flaech_zahl;loop++)
  { 
   if(sichtbar[loop])
   {   
    SetAPen(rp_2,farbe[loop]);
    AreaMove(rp_2,sp[plst[loop][0]],ze[plst[loop][0]]);
    for(pind=1;pind<pkt_p_flaech[loop];pind++)
     AreaDraw(rp_2 ,sp[plst[loop][pind]],ze[plst[loop][pind]]);
    AreaEnd(rp_2  );
    sichtbar[loop] = FALSE;
   }
  } 
  ScreenToFront(screen_2);
 }
}

init_trig()
{
 int loop;

 for(loop=0;loop<360;loop++)
 {
  sinus[loop] = ((int)(sin(loop*PI/180)*16384));
  cosin[loop] = ((int)(cos(loop*PI/180)*16384));
 } 
}
  
ausstieg()
{
 FreeMem(area_plane,8000L); 
 CloseWindow(window_1);
 CloseWindow(window_2);
 CloseWindow(info_window_1 );
 CloseWindow(info_window_2);
 CloseScreen(screen_1 );
 CloseScreen(screen_2);
 CloseLibrary(GfxBase);
 CloseLibrary(IntuitionBase);
 exit(TRUE);
}

transform()
 {
 int loop;
 long u,v,z,x,y,hz,hx,hy,vg_wert1,vg_wert2;
 long va_x,va_y,va_z,vb_x,vb_y,vb_z,normv_y;
 long trans_x[MAXP],trans_y[MAXP],trans_z[MAXP];
 
 obj_xturn+= xdreher;
 if(obj_xturn<0) obj_xturn+= 360;
 if(obj_xturn>359) obj_xturn-= 360; 
 obj_yturn+= ydreher;
 if(obj_yturn<0) obj_yturn+= 360;
 if(obj_yturn>359) obj_yturn-= 360; 
 obj_zturn+= zdreher;
 if(obj_zturn<0) obj_zturn+= 360;
 if(obj_zturn>359) obj_zturn-= 360; 

 for(loop=0;loop<pkt_zahl ;loop++)
 {
  hx = cx[loop];
  hy = cosin[obj_xturn]*cy[loop] - sinus[obj_xturn]*cz[loop];
  hz = sinus[obj_xturn]*cy[loop] + cosin[obj_xturn]*cz[loop];

  hy/= 16384;
  hz/= 16384;
  
  x = cosin[obj_yturn]*hx - sinus[obj_yturn]*hz;
  y = hy;
  z = sinus[obj_yturn]*hx + cosin[obj_yturn]*hz;

  x/=16384;
  z/=16384;

  hx = cosin[obj_zturn]*x - sinus[obj_zturn]*y;
  hy = sinus[obj_zturn]*x + cosin[obj_zturn]*y;
  hz = z;

  hx/= 16384;
  hy/= 16384;

  trans_x[loop] = hx;
  trans_y[loop] = hy;
  trans_z[loop] = hz;
   
  hy = (long)((hy-FAK)/2048 );

  u=(long)((-hx/hy)*fzoom);
  v=(long)((-hz/hy)*fzoom);

  sp[loop]=160+u;
  ze[loop]=100+v;
 }

 for(loop=0;loop<flaech_zahl ;loop++)
 {
  va_x = trans_x[plst[loop][0]] - trans_x[plst[loop][1]];
  va_y = trans_y[plst[loop][0]] - trans_y[plst[loop][1]];
  va_z = trans_z[plst[loop][0]] - trans_z[plst[loop][1]];

  vb_x = trans_x[plst[loop][2]] - trans_x[plst[loop][1]];
  vb_y = trans_y[plst[loop][2]] - trans_y[plst[loop][1]];
  vb_z = trans_z[plst[loop][2]] - trans_z[plst[loop][1]];

  normv_y = (va_x * vb_z) - (va_z * vb_x);

  vg_wert1 = normv_y+trans_y[plst[loop][1]];
  vg_wert2 = trans_y[plst[loop][1]];
  if(vg_wert1 > vg_wert2) sichtbar[loop] = TRUE;
 }
}

int lies_tastatur()
{
 int abbruch = FALSE;

 switch(info_window_2->MessageKey->Code)
 {
  case '8':xdreher+=1;
           write_int(xdreher,30L,9L,rp_3);
           write_int(xdreher,30L,9L,rp_4);
           break;  
  case '2':xdreher-=1;
           write_int(xdreher,30L,9L,rp_3);
           write_int(xdreher,30L,9L,rp_4);
           break;  
  case '9':zdreher+=1;
           write_int(zdreher,150L,9L,rp_3);
           write_int(zdreher,150L,9L,rp_4);
           break;  
  case '1':zdreher-=1;
           write_int(zdreher,150L,9L,rp_3);
           write_int(zdreher,150L,9L,rp_4);          
           break;  
  case '4':ydreher+=1;
           write_int(ydreher,90L,9L,rp_3);
           write_int(ydreher,90L,9L,rp_4);  
           break;  
  case '6':ydreher-=1;
           write_int(ydreher,90L,9L,rp_3);
           write_int(ydreher,90L,9L,rp_4);
           break;  
  case 'g':zoom+= 1;
           write_int(zoom,235L,9L,rp_3);
           write_int(zoom,235L,9L,rp_4);
           fzoom = (float)zoom;
           fzoom = fzoom/10;
           break;              
  case 'k':if(zoom>0) zoom-= 1;
           write_int(zoom,235L,9L,rp_3);
           write_int(zoom,235L,9L,rp_4);
           fzoom = (float)zoom;
           fzoom  =  fzoom/10;
           break;
  case 'n':info_window_2->MessageKey->Code = NULL;
           file_loader();
           break;              
  case 'q':abbruch = TRUE;
           break;
  default :break;
 }
 info_window_2->MessageKey->Code = NULL;
 return(abbruch);
}
 
file_loader()
{
 int count,loop,pos_zaehl,singlechar;
 char eingabe[19], *append = ".3d\0";
 
 pos_zaehl = 0;
 SetRast(rp_4,0L);
 Move(rp_4, 10L,9L);
 Text(rp_4,"Filename:",9L);
 ScreenToFront(screen_2);
 do
 {
  if(info_window_2->MessageKey->Code)
  {
   singlechar = info_window_2->MessageKey->Code;
   if(singlechar == 13) break;
   if(singlechar !=  8)
   {
    eingabe[pos_zaehl] = (char)singlechar;
    ++pos_zaehl;
    Move(rp_4,90L,9L); 
    Text(rp_4,&eingabe,(long)pos_zaehl);
    info_window_2->MessageKey->Code = NULL;
   }
   else
   {
    if(pos_zaehl>0)
    {
     --pos_zaehl;
     eingabe[pos_zaehl] = '\0';
     Move(rp_4,90L,9L); 
     Text(rp_4,"               ",15L);
     Move(rp_4,90L,9L); 
     Text(rp_4,&eingabe,(long)pos_zaehl);
     info_window_2->MessageKey->Code = NULL;
    }
   }
  }
 } 
 while((singlechar != 13) && (pos_zaehl<14));
 info_window_2 ->MessageKey->Code = NULL;
 for(count=pos_zaehl;count<(pos_zaehl+4);count++)
  eingabe[count] = append[count-pos_zaehl];
 filename = &eingabe[0];
 filenumber = open(filename,O_RDONLY);
 if(filenumber<0)
 {
  SetRast(rp_4,0L);
  Move(rp_4,20L,9L); 
  Text(rp_4,"File kann nicht geoeffnet werden!",33L);
  Delay(200L);
  SetRast(rp_4,0L);
  info_text();
  write_int(xdreher,30L,9L,rp_4);
  write_int(zdreher,150L,9L,rp_4);
  write_int(ydreher,90L,9L,rp_4);  
  write_int(zoom,235L,9L,rp_4);
  write_int(xdreher,30L,9L,rp_3);
  write_int(zdreher,150L,9L,rp_3);
  write_int(ydreher,90L,9L,rp_3);  
  write_int(zoom,235L,9L,rp_3);
  ScreenToFront(screen_1);
 }
 else
 {
  pkt_zahl = lies_int();
  flaech_zahl = lies_int();
  for(count=0;count<pkt_zahl;count++)
  {
   cx[count] = (long)lies_int();
   cy[count] = (long)lies_int();
   cz[count] = (long)lies_int();
  }
  for(count=0;count<flaech_zahl;count++)
   pkt_p_flaech[count] = lies_int(); 
  for(count=0;count<flaech_zahl;count++)
   for(loop=0;loop<pkt_p_flaech[count];loop++)
    plst [count][loop] = lies_int();
  for(count=0;count<flaech_zahl;count++)
   farbe[count] = (long)lies_int();
  close(filenumber);
  obj_xturn = 0;
  obj_yturn = 0;
  obj_zturn = 0;
  xdreher = 0;
  ydreher = 0;
  zdreher = 0;
  zoom = 10;
  fzoom = 1.0;
  SetRast(rp_3,0L);
  SetRast(rp_4,0L);
  info_text();
  ScreenToFront(screen_1);
 }
}
 
int lies_int()
{
 int wert,loop,pos_zaehl;
 pos_zaehl = 0;

 do
 {
  read(filenumber,zielchar,1);
  if(zielchar[0] == '-')
  {
   zielstring[pos_zaehl] = zielchar[0];
   ++pos_zaehl;
  }
  if(isdigit((int)zielchar[0]))
  { 
   zielstring[pos_zaehl] = zielchar[0];
   ++pos_zaehl;
  }
 } 
 while((zielchar[0] != ';') && (zielchar[0] != '\0'));
 wert = atoi(zielstring);
 for(loop=0;loop<10;loop++)
  zielstring[loop] = '\0';
 return(wert);
}

write_int(int_wert,output_xpos,output_ypos,ziel_port)
int int_wert;
long output_xpos,output_ypos;
struct RastPort *ziel_port;
{
 char output_string[8];
 int int_wert_buffer,zahl,s_factor,d_counter;
 int pos_zaehl; 
 int int_wert_stellen;

 pos_zaehl = 0;
 int_wert_stellen = 5;

 if(int_wert<0) 
 {
  output_string[pos_zaehl++] = '-';  
  int_wert_buffer = -int_wert;
 }
 else
  int_wert_buffer =  int_wert;
   
 for(d_counter=10000;d_counter>=1;d_counter/=10)
 {  
  if(int_wert_buffer/d_counter)break;
  int_wert_stellen -= 1;
 }

 switch(int_wert_stellen)
 {
  case 5:s_factor = int_wert_buffer / 10000;
         output_string[pos_zaehl++] = 48 + s_factor;
         int_wert_buffer -= s_factor * 10000;
  case 4:s_factor = int_wert_buffer / 1000;
         output_string[pos_zaehl++] = 48 + s_factor;
         int_wert_buffer -= s_factor * 1000;
  case 3:s_factor = int_wert_buffer / 100;
         output_string[pos_zaehl++] = 48 + s_factor;
         int_wert_buffer -= s_factor * 100;
  case 2:s_factor = int_wert_buffer / 10;
         output_string[pos_zaehl++] = 48 + s_factor;
         int_wert_buffer -= s_factor * 10;
  case 1:s_factor = int_wert_buffer / 1;
         output_string[pos_zaehl++] = 48 + s_factor;
         int_wert_buffer -= s_factor * 1;
         break;
  case 0:output_string[pos_zaehl++] = 48; 
 }  
 output_string[pos_zaehl] = '\0';
 Move(ziel_port,output_xpos,output_ypos);
 Text(ziel_port,"    ",4L); 
 Move(ziel_port,output_xpos,output_ypos);
 Text(ziel_port,&output_string,(long)pos_zaehl);
}   

info_text()
{ 
 SetRast(rp_3,0L);
 SetRast(rp_4,0L);
 Move(rp_3,10L,9L);
 Text(rp_3,"X:",2L);
 Move(rp_3,70L,9L);
 Text(rp_3,"Y:",2L);
 Move(rp_3,130L,9L);
 Text(rp_3,"Z:",2L);
 Move(rp_3,190L,9L);
 Text(rp_3,"Zoom:",5L);
 Move(rp_3,235L,9L);
 Text(rp_3 ,"10",2L); 
 Move(rp_4,10L,9L);
 Text(rp_4,"X:",2L);
 Move(rp_4,70L,9L);
 Text(rp_4,"Y:",2L);
 Move(rp_4,130L,9L);
 Text(rp_4,"Z:",2L);
 Move(rp_4,190L,9L);
 Text(rp_4,"Zoom:",5L);
 Move(rp_4,235L,9L);
 Text(rp_4,"10",2L); 
}

/****************   Ende des 3d-Object-Animators  **************/


   Nachfolgendend noch zwei Objektbeispiele ( bitte getrennt   
         eingeben, benennen und mit dem Animator laden         


/*********** Eine Art stilisiertes Raumschiff ******************/

9;          Anzahl Punkte   
9;          Anzahl Flaechen 

 x       y        z     Koordinaten von [Anzahl Punkte]

 0;     -1000;    500;
-1000;  -1000;    0;
 0;     -1000;   -500;
 1000;  -1000;    0;
 0;      0;       1000;
-2000;   0;       0;
 0;      0;      -1000;
 2000;   0;       0;
 0;      3500;    0;

 Anzahl der Punkte [Flaechen]

 4; 4; 4; 4; 4; 3; 3; 3; 3;

 Punktliste [Anzahl Flaechen] [Punktzahl pro Flaeche]

 0; 1; 2; 3;
 0; 4; 5; 1;
 1; 5; 6; 2;
 2; 6; 7; 3;
 0; 3; 7; 4; 
 4; 8; 5; 
 4; 7; 8; 
 7; 6; 8; 
 5; 8; 6; 

 Farbliste [Anzahl Flaechen]

 3; 9; 9; 9; 9;11;11;11;11;

/****************************************************************/

/*********** Ein Würfel mit Innenflächen  ***********************/

16;    14;
   
 2000;   2000;  2000;     -2000;   2000;  2000;  
-2000;  -2000;  2000;      2000;  -2000;  2000;
 2000;   2000; -2000;     -2000;   2000; -2000;
-2000;  -2000; -2000;      2000;  -2000; -2000;
 1500;   1500;  2000;     -1500;   1500;  2000;
-1500;  -1500;  2000;      1500;  -1500;  2000;
 1500;   1500; -1000;     -1500;   1500; -1000;
-1500;  -1500; -1000;      1500;  -1500; -1000;

 4;4;4;4;4;4;4;4;4;4;4;4;4;4;

 12;13;14;15;     8;12;15;11;     8; 9;13;12;
  9;10;14;13;    10;11;15;14;     3; 7; 4; 0;
  0; 4; 5; 1;     1; 5; 6; 2;     3; 2; 6; 7;
  5; 4; 7; 6;     1; 2;10; 9;     0; 1; 9; 8;
  0; 8;11; 3;     3;11;10; 2;

  8;11;3;4;5;6;7;9;10;11;12;13;14;15;
