
/*
******************************************************************
        C-Programm zum Schreiben von CONSTRUCT-Szenen-Dateien
******************************************************************

   Erläuterungen:

         CONSTRUCT-Szenen bestehen aus Dreiecken und Kugeln.
         Diese sind in einem int-array obj[] gespeichert.
         Sie enthalten die nummern von Punkten, die wiederum in einem
         float-array pts[] liegen.

         Das Format für objekte ist folgendes:

         obj[i]    = art   art des objektes:
                           0=ebenes Dreieck
                           7=Dreieck mit Phong-interpolation der
                             Normalenvektoren (patch)
                             (rund)
                           8=Kugel

         obj[i+1]  = atr   Attributnr.  (Materialnr)
                           Hier sollten Sie 1 einsetzen. Materialnummern
                           können Sie in CONSTRUCT besser manipulieren.
         obj[i+2]  = p
         obj[i+3]  = q
         obj[i+4]  = r     Bei einem Dreieck (art=0 oder 7) sind p,q,r
                           die Nummern der Eckpunkte des Dreiecks
                           Bei einer Kugel ist p die Nummer des
                           Mittelpunktes, q und r (je 16-bit integer) werden
                           zusammengefaßt und als eine 32-bit-float zahl
                           interpretiert.

         Jedes Objekt belegt damit 5 zellen des obj-arrays.
         Objekt nr j findet sich damit bei obj[j*5]
         Objekt 1 beginnt bei obj[5];
         Objekt 0 gibt es nicht. (die ersten 5 zellen des obj-arrays werden
         nicht beachtet)

         Format der Punkte:

            pts[i]   = x
            pts[i+1] = y
            pts[i+2] = z

         Jeder Punkt belegt 3 zellen des pts-arrays.
         Die Daten für punkt j beginnen bei pts[j*3];
         Die Nummerierung beginnt bei punkt 1
         Punkt 0 wird nicht beachtet.

         Orientierung der Koordinatenachsen:
         -----------------------------------



         ^
      Z  |       / X
         |      /
         |     /
         |    /
         |   /
         |  /
         | /
         |/
         +------------------->
                          Y



**********************************************************************
Erzeugen Sie Ihre Objekte, indem Sie zuerst die Koordinaten der Punkte
errechnen und im pts-array abspeichern und danach die Punkte den objekten
zuteilen.(im obj-array)
Abschließend rufen Sie writeszene("Dateiname") auf.
Die dabei erzeugte Datei können Sie mit CONSTRUCT lesen


************************************************************************
         Wichtig  !!!!!

         Alle float-zahlen sind im Motorola Fast-Floating-Point Format (FFP)
         Berücksichtigen Sie das bei der kompilierung und beim linken.
         Beim Aztec-System:

         kompilieren:   cc -s +D writeszene.c +FF
         linken:        ln  writeszene.o -lml -lcl


Wenn Sie die erzeugte Testszene dann mit CONSTRUCT einlesen, wird sich
CONSTRUCT beschweren, daß zu der Szene keine Materialdatei existiert,
aber das brauchen Sie nicht zu beachten.

Materialien müssen Sie dann in CONSTRUCT vergeben.

***********************************************************************

Achten Sie darauf, daß die Eckpunkte zusammenhängender Dreiecke
gleich orientiert sind, also alle im Uhrzeigersinn oder dagegen.



*********************************************************************
Beispiel:
a) Erzeugen eines Dreiecks
         1) erzeugen der drei Eckpunkte 1,2 und 3

         pts[3]=0.0;        Punkt 1
         pts[4]=0.0;
         pts[5]=0.0;        erster Punkt beginnt bei pts[1*3]=pts[3];

         pts[6]=10.0;       punkt 2
         pts[7]=0.0;
         pts[8]=0.0;

         pts[9]=10.0;       Punkt 3
         pts[10]=10.0;
         pts[11]=0.0;

          jetzt das Dreieck nr 1 (beginnt bei obj[5])

         obj[5]=0;          art 0 ebenes Dreieck
         obj[6]=1;          Material 1
         obj[7]=1;          punkt 1
         obj[8]=2;          punkt 2
         obj[9]=3;          punkt 3

b) erzeugen einer Kugel mit Mittelpunkt 5,5,5 und Radius 3

        float radius,*r;

         pts[12]=5.0;        Punkt Nr 4
         pts[13]=5.0;
         pts[14]=5.0;

         radius=3.0;

         obj[10]=8;         objekt nr 2, art 8=Kugel
         obj[11]=1;         Material 1
         obj[12]=4;         Punkt nr 4 als Mittelpunkt
         r=(float *)&obj[13];  bei obj[13],obj[14] wird der Radius
                                 abgespeichert
         *r=radius;



Im Hauptprogram main ist ein kleines Beispiel um eine Szene mit
ca 1800 Dreiecken die eine Sinus-Fläche bilden mit einer Kugel darüber.


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

#include <stdio.h>
#include <functions.h>
#include <fcntl.h>

#define maxobj 5000            /* hier können Sie definieren, wieviele
                                  Objekte und Punkte sie maximal erlauben
                               */
#define maxobj5 25000
#define maxpts 5000
#define maxpts3 15000


short obj[maxobj5];
float pts[maxpts3];
short nobj,npts;

unsigned long pt_checksum,obj_checksum;
short buffer_index;
short i_buffer[256];
short filedes;


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

short init_schreiben(name)
/* initialisiert das file *name zum schreiben */
char *name;
{
   short ok=1;

   filedes=open(name,O_WRONLY+O_CREAT);

   if (filedes==-1)
         ok=0;
   buffer_index=0;

}

/****************************************************/
intwrite(i)
/* schreibt integer i auf geoeffnete file */
short i;
{
   short np;
   if (buffer_index>255)
   {
      np=write(filedes,&i_buffer[0],512);
      buffer_index=0;
   }
   i_buffer[buffer_index++]=i;
}
/*******************************************************/
realwrite(r)
float r;
{
   float *r1;
   short ii[2];
   r1=&ii[0];
   *r1=r;
   intwrite(ii[0]);
   intwrite(ii[1]);
}
/************************************************************/
longwrite(r)
long r;
{
   long *r1;

   short ii[2];
   r1=&ii[0];
   *r1=r;
   intwrite(ii[0]);
   intwrite(ii[1]);
}
/******************************************************/

close_schreiben()
{
   if (buffer_index>0)
     write(filedes,&i_buffer[0],512);
   close(filedes);
}
/******************************************************/

writeszene(name)
/* schreibt die szene, die sich im speicher befindet, unter dem
   namen <name> auf diskette.
*/

char *name;
{
   short i,i2,j1,art,p,q,r,attr;
   long j,i1;
   short no,np,nk,nlen,a,e,chh;
   char ch,strings[80];
   short kname[20],flag=0,nkp;
   short allnummer;
   unsigned long *rr;
   short *ae;

 if (init_schreiben(name)!=0)
 {
   intwrite(67);
   intwrite(79);
   intwrite(78);

   rr=&pts[3];  pt_checksum=0;
   for (i=1;i<=npts;i++)
   {
      pt_checksum+=(*rr++);
      pt_checksum+=(*rr++);
      pt_checksum+=(*rr++);
   }

   obj_checksum=0;
   j=7;
   for (i=1;i<=nobj;i++)
   {
      obj_checksum+=obj[j++];
      obj_checksum+=obj[j++];
      obj_checksum+=obj[j++];
      j+=2;
   }

   longwrite(pt_checksum);
   longwrite(obj_checksum);

   intwrite(nobj);
   intwrite(npts);
   intwrite(0);
   intwrite(0);
   i1=5;

   for (i=1;i<=nobj;i++)
   {
      intwrite(obj[i1++]);

      attr=obj[i1++];
      intwrite(attr);
      intwrite(obj[i1++]);
      intwrite(obj[i1++]);
      intwrite(obj[i1++]);
   }

   i1=3;

   for (i=1;i<=npts;i++)
   {
      for (j=1;j<=3;j++)
            realwrite(pts[i1++]);
   }

   intwrite(1);

   close_schreiben();
  }
}
/************************************************************/

extern float sin();

main()
{
   /* beispiel zum erzeugen einer testszene */
   int i,j;
   long np,no,p_nr,i1;
   float x,y,x1,dx,dy,z;
   float radius,*r;
   int n_zeilen,n_spalten;

   n_zeilen=n_spalten=31;    /* 31 Punkte pro zeile und 31 zeilen*/
   /* zuerst ein Punktgitter erzeugen das sich von (0,0) bis (10,10)
      erstreckt */
   /* an jeder Seite sind jeweils 31 Punkte, also zusammen 961 Punkte
   */


   printf("Punkte erzeugen\n");

   dx=10.0/(n_zeilen-1);
   dy=10.0/(n_spalten-1);
   npts=0;
   np=3;       /* erster Punkt beginnt bei pts[3] */
   for (x=0.0,j=1;j<=n_zeilen;j++,x+=dx)
   {
      printf("Zeile %d\n",j);
      for (y=0.0,i=1;i<=n_spalten;i++,y+=dy)
      {
         z=0.3*sin(x+y)+0.2*sin(3.0*x)+0.1*sin(5.0*y);
         pts[np++]=x;
         pts[np++]=y;
         pts[np++]=z;
         npts++;
      } /* for y,i */
   } /* for x,j */

   /* jetzt die Gitterpunkte zu Dreiecken verbinden */
   /* Punkte sind (von oben gesehen so angeordnet:

      930  931  932  933 ...                     961
        .
        .
        .

       63   64   65   66  ...                     93

       32   33   34   35  ...                     62

        1    2    3    4  ...                     31


      31 Eckpunkte entlang jeder seite ergibt 30*30 Vierecke
      und damit 30*30*2 Dreiecke =1800 Dreiecke

    Die Dreiecke werden jetzt zeilenweise erzeugt mit den Eckpunkten:
      1)  1,32,33
      2)  1,33,2
      3)  2,33,34
      4)  2,34,3,
      .
      .
      .

    */

   printf("Dreiecke erzeugen\n");

   nobj=0;
   no=5;       /* erstes Dreieck beginnt bei obj[5] */

   p_nr=1;
   for (j=1;j<=n_zeilen-1;j++)
   {
      i1=p_nr;
      printf("Zeile %d\n",j);
      for (i=1;i<=n_spalten-1;i++)
      {
         obj[no++]=7;      /*art:  rundes Dreieck */
         obj[no++]=1;      /* Material nr 1 */
         obj[no++]=i1;
         obj[no++]=i1+n_spalten;
         obj[no++]=i1+n_spalten+1;

         obj[no++]=7;      /*art:  rundes Dreieck */
         obj[no++]=1;      /* Material nr 1 */
         obj[no++]=i1;
         obj[no++]=i1+n_spalten+1;
         obj[no++]=i1+1;

         nobj+=2;
         i1+=1;
      } /* for i */
      p_nr+=n_spalten;
   }/* for j */

   /* schließlich noch eine Kugel erzeugen bei (5,5,3) mit radius 1*/

   radius=1.0;
   /* neuer punkt */
   npts+=1;
   np=npts;
   np*=3;

   pts[np++]=5.0;
   pts[np++]=5.0;
   pts[np]=3.0;

   nobj+=1;
   no=nobj;
   no*=5;

   obj[no++]=8;      /* art : Kugel */
   obj[no++]=1;      /* material 1 */
   obj[no++]=npts;   /* mittelpkt */
   r=(float *)&obj[no];
   *r=radius;

   writeszene("ram:testszene");

   printf("fertig\n");


}
