/* $Revision Header *** Header built automatically - do not edit! ***********
 *
 *	(C) Copyright 1991 by Metalworx
 *
 *	Name .....: cdm2dkb.c
 *	Created ..: Sat 14-Dec-91 17:38
 *	Revision .: 0
 *
 *	Date		Author		Comment
 *	=========	========	====================
 *	14-Dec-91	Mtwx		Created this file!
 *
 * $Revision Header ********************************************************/
 #define REVISION 0

/***************************************************************************
* cdm2dkb.c:  konvertiert Chemesthetics-Datei in DKBTrace-Datei, diese	   *
*	      dann mit DKBTrace V2.12 berechnet werden			   *
***************************************************************************/

/* ------------------------------- includes ----------------------------- */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <exec/types.h>

#include "/chem_defs.h"
#include "cdm2dkb.h"

/* ------------------------------- defines ------------------------------ */

#define round(x)  ((int) ((x) + 0.5))

/* ------------------------------- type definitions --------------------- */

/* ------------------------------- global references -------------------- */

static int anzahl,anzahlinfo,drehx,drehy,drehz,ref;
static double vergr,lichtx,lichty,lichtz;
static struct Atom *AtomInfo[104];
ATOMTYP *Atom[MAXATOM];

/* ------------------------------- external references ------------------ */

extern int Revision;
extern char ProgId[],Version[],Date[];

/* ------------------------------- prototypes --------------------------- */

void usage(void), readinfo(void), readchemfile(char *),
     writedkbfile(char *), twistatoms(char, double), centeratoms(void),
     cleanup(void);

/* ------------------------------- routines ----------------------------- */

void main(int argc, char *argv[])
{
  printf("%s %s/%d - %s (C) 1991 Metalworx *** FREEWARE!\n",ProgId,Version,
	 Revision,Date);
#ifdef USE_BUILTIN
  printf("  This version uses builtin data.\n");
#else
  printf("  This version uses external data from 'chems_e.dat'.\n");
#endif
  if(argc!=3)
  {
    usage();
    exit(1);
  }
  readinfo();
  readchemfile(argv[1]);
  printf("calculating...\n");
  twistatoms('x',(double)drehx);
  twistatoms('y',(double)drehy);
  twistatoms('z',(double)drehz);
  centeratoms();
  writedkbfile(argv[2]);
  cleanup();
  exit(0);
}

void usage(void)
{
  puts("Usage: cdm2dkb <infile> <outfile>");
}

void readinfo(void)
{
  register int i;
#ifndef USE_BUILTIN
  char line[81];
  FILE *edatei;

  if(!(edatei=fopen("chems_e.dat","r")))
  {
    puts(Error[0]);
    perror("chems_e.dat");
    exit(1);
  }
  printf("reading infofile...\n");
  fgets(line,80,edatei);
  anzahlinfo=atoi(line);
  for(i=0;i<anzahlinfo;i++)
  {
    AtomInfo[i]=calloc(sizeof(struct Atom),1);
    if(AtomInfo[i]==NULL)
    {
      puts(Error[1]);
      exit(1);
    }
    fgets(line,80,edatei);
    line[strlen(line)-1]='\0';
    strcpy(AtomInfo[i]->Kurzz,line);
    fgets(line,80,edatei);
    line[strlen(line)-1]='\0';
    strcpy(AtomInfo[i]->Name,line);
    fgets(line,80,edatei);
    AtomInfo[i]->Farbe=atoi(line);
  }
  fclose(edatei);
#else
  /* use builtin infos */
  anzahlinfo=104;
  for(i=0;i<anzahlinfo;i++)
    AtomInfo[i]=&BIAtomInfo[i];
#endif
}

void readchemfile(char *filename)
{
  register int i;
  char line[81];
  FILE *edatei;

  if(!(edatei=fopen(filename,"r")))
  {
    printf("%s\n",Error[2]);
    perror(filename);
    exit(1);
  }
  printf("reading inputfile...\n");
  fgets(line,80,edatei);
  anzahl=atoi(line);
  for(i=0;i<anzahl;i++)
  {
    Atom[i]=calloc(sizeof(ATOMTYP),1);
    if(Atom[i]==NULL)
    {
      puts(Error[1]);
      exit(1);
    }
    fgets(line,80,edatei);
    line[strlen(line)-1]='\0';  /* delete trailing \n */
    strcpy(Atom[i]->name,line);
    fgets(line,80,edatei);
    Atom[i]->x=atoi(line);
    fgets(line,80,edatei);
    Atom[i]->y=atoi(line);
    fgets(line,80,edatei);
    Atom[i]->z=atoi(line);
    fgets(line,80,edatei);
    Atom[i]->r=atoi(line);
  }
  fgets(line,80,edatei);
  vergr=atof(line);
  fgets(line,80,edatei);
  drehx=atoi(line);
  fgets(line,80,edatei);
  drehy=atoi(line);
  fgets(line,80,edatei);
  drehz=atoi(line);
  fgets(line,80,edatei);
  lichtx=atof(line);
  fgets(line,80,edatei);
  lichty=atof(line);
  fgets(line,80,edatei);
  lichtz=atof(line);
  fgets(line,80,edatei);
  ref=atoi(line);
  fclose(edatei);
}

void writedkbfile(char *filename)
{
  register int i,j;
  int col,height_of_plane;
  int minx,miny,minz,maxx,maxy,maxz;
  BOOL found;
  long t;
  FILE *adatei;
  struct tm *zeit;
  char Month[12][4]={ "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep",
		      "Oct","Nov","Dec" };
  char WDay [7][4]={ "Sun","Mon","Tue","Wed","Thu","Fri","Sat" };
  char Color[16][20]={ "Gray","Black","White","CornflowerBlue","Magenta",
		       "Cyan","VioletRed","Blue","Red","Green","Gold",
		       "SeaGreen","Yellow","Coral","DarkTurquoise",
		       "GreenYellow" };
#define DEFAULT_COLOR 2

  if(!(adatei=fopen(filename,"w")))
  {
    printf("%s\n",Error[3]);
    perror(filename);
    exit(1);
  }
  printf("writing outputfile...\n");
  time(&t);
  zeit=localtime(&t);
  fprintf(adatei,"{ %s - An input file for the DKB raytracer by David Buck\n\n",
	  filename);
  fprintf(adatei,"  This file was created using cdm2dkb by Joerg Fenin / Metalworx\n");
  fprintf(adatei,"  cdm2dkb converts molecule files of Chemesthetics into DKBTrace files\n\n");
  fprintf(adatei,"  This file is public domain, it may be altered or distributed freely\n\n");
  fprintf(adatei,"  Created: %s %02d-%s-%2d by CDM2DKB (C) 1991 Metalworx\n",
	  WDay[zeit->tm_wday], zeit->tm_mday,Month[zeit->tm_mon],
	  zeit->tm_year);
  fprintf(adatei,"}\n\n");
  fprintf(adatei,"{ Include colors, textures and shapes }\n");
  fprintf(adatei,"INCLUDE \"shapes.dat\"\n");
  fprintf(adatei,"INCLUDE \"colors.dat\"\n");
  fprintf(adatei,"INCLUDE \"textures.dat\"\n\n");
  fprintf(adatei,"VIEW_POINT\n");

  minx=maxx=Atom[0]->x-Atom[0]->r;
  miny=maxy=Atom[0]->y-Atom[0]->r;
  minz=maxz=Atom[0]->z-Atom[0]->r;
  height_of_plane=minz-Atom[0]->r-2;

/* Minimums und Maximums bestimmen */
  for(i=0;i<anzahl;i++)
  {
    if((Atom[i]->x-Atom[i]->r)<minx)
      minx=Atom[i]->x-Atom[i]->r;
    if((Atom[i]->y-Atom[i]->r)<miny)
      miny=Atom[i]->y-Atom[i]->r;
    if((Atom[i]->z-Atom[i]->r)<minz)
    {
      minz=Atom[i]->z-Atom[i]->r;
      height_of_plane=minz-2;
    }
    if((Atom[i]->x+Atom[i]->r)>maxx)
      maxx=Atom[i]->x+Atom[i]->r;
    if((Atom[i]->y+Atom[i]->r)>maxy)
      maxy=Atom[i]->y+Atom[i]->r;
    if((Atom[i]->z+Atom[i]->r)>maxz)
      maxz=Atom[i]->z+Atom[i]->r;
  }
  fprintf(adatei,"  LOCATION  <0 0 %d>\n",(maxy-miny)/2*-1-300);
  fprintf(adatei,"  DIRECTION <0 0 1>\n");
  fprintf(adatei,"  UP        <0 1 0>\n");
  fprintf(adatei,"  RIGHT     <1.5 0 0> { Change the RIGHT value appropriate to your screen }\n");
  fprintf(adatei,"END_VIEW_POINT\n\n");
  fprintf(adatei,"{ build all atoms into one object }\n");
  fprintf(adatei,"COMPOSITE { consits of %d atoms and one plane underneath }\n",anzahl);

/* jetzt die einzelnen Atome einsetzen */
  for(i=0;i<anzahl;i++)
  {
    found=FALSE;
    for(j=0;j<anzahlinfo;j++)
    {
      if(strcmp(strupr(Atom[i]->name),strupr(AtomInfo[j]->Kurzz))==NULL)
      {
	fprintf(adatei,"  OBJECT { %s }\n",AtomInfo[j]->Name);
	col=AtomInfo[j]->Farbe;
	found=TRUE;
	break;
      }
    }
    if(found==FALSE)
    {
      fprintf(adatei,"  OBJECT { ???????? }\n");
      col=DEFAULT_COLOR;
      puts(Warning[0]);
    }
    fprintf(adatei,"    SPHERE <%d %d %d> %d END_SPHERE\n",Atom[i]->x,
	    Atom[i]->z,Atom[i]->y,Atom[i]->r);
	    /* y und z vertauschen, weil Chemesthetics die beiden Koordinaten
	       vertauscht hat */
    fprintf(adatei,"    TEXTURE\n");
    fprintf(adatei,"      COLOUR %s\n",Color[col]);
    if(!found)
      fprintf(adatei,"        { color %s assumed, real color unknown! }\n",
	      Color[DEFAULT_COLOR]);
    if(ref>1)
    {
      fprintf(adatei,"      PHONG 1.0\n");
      fprintf(adatei,"      PHONGSIZE 90\n");
    }
    fprintf(adatei,"    END_TEXTURE\n");
    fprintf(adatei,"  END_OBJECT\n\n");
  }

/* Fläche unter dem Molekül */
  fprintf(adatei,"  OBJECT { plane beneath the molecule }\n");
  fprintf(adatei,"    PLANE <0 1 0> %d END_PLANE\n",height_of_plane);
  fprintf(adatei,"    TEXTURE\n      Pine_Wood COLOUR OldGold\n");
  fprintf(adatei,"    END_TEXTURE\n    COLOUR OldGold\n");
  fprintf(adatei,"  END_OBJECT\n\n");

/* jetzt die Befehle, die das Gesamtmolekül betreffen */
  fprintf(adatei,"{ manipulation of composite object }\n");
  fprintf(adatei,"  SCALE <%4.1f %4.1f %4.1f>\n",vergr,vergr,vergr);
  fprintf(adatei,"END_COMPOSITE\n\n");

/* Himmelszelt */
  fprintf(adatei,"{ \"The sky was the color of her eyes\" }\n");
  fprintf(adatei,"{             ... and just as cloudy! }\n");
  fprintf(adatei,"OBJECT\n");
  fprintf(adatei,"  SPHERE <0.0 0.0 0.0> 150000.0 END_SPHERE\n");
  fprintf(adatei,"  TEXTURE\n");
  fprintf(adatei,"    0.05\n    Cloud_Sky\n");
  fprintf(adatei,"    SCALE <30000.0 4000.0 20000.0>\n    AMBIENT 0.7\n");
  fprintf(adatei,"    DIFFUSE 0.0\n  END_TEXTURE\n");
  fprintf(adatei,"  COLOUR RED 0.5 GREEN 0.5 BLUE 1.0\nEND_OBJECT\n\n");

/* Lichtquelle */
  fprintf(adatei,"OBJECT { light source }\n");
  fprintf(adatei,"  SPHERE <0 0 0> 10000 END_SPHERE\n");
  fprintf(adatei,"  TEXTURE\n    COLOUR White\n  END_TEXTURE\n");
  fprintf(adatei,"  TRANSLATE <%d %d %d> { move light behind viewer's location }\n",
	  (int)lichtx,(int)lichtz,(int)lichty);
  if(lichty<-160000.0)
  {
    puts(Warning[1]);
    fprintf(adatei,"  { ATTENTION: light source is located behind the `heaven's sphere`!\n");
    fprintf(adatei,"               the light may not fall upon the molecule!\n");
    fprintf(adatei,"               you should translate the light source manually to a\n");
    fprintf(adatei,"               value > -150000! }\n");
  }
  fprintf(adatei,"  LIGHT_SOURCE\n  COLOUR White\n");
  fprintf(adatei,"END_OBJECT\n\n");

  fprintf(adatei,"{ end of file }\n");
  fclose(adatei);
}

/* dreht alle Atome um den Winkel dx um die Koordinatenachse "Achse"    */
void	  twistatoms(char achse, double dx)
{
  int	    xalt, yalt, zalt, i;
  double    sx, cx;

  dx = dx / 180.0 * PI; 	       /*Umrechnung in rad*/
  sx = sin(dx);
  cx = cos(dx);
  for (i = 0; i < anzahl; i++)
  {
    xalt = Atom[i]->x;
    yalt = Atom[i]->y;
    zalt = Atom[i]->z;
    switch (achse)
    {
      case 'x':
	Atom[i]->y = round(yalt * cx + zalt * sx);
	Atom[i]->z = round(-yalt * sx + zalt * cx);
	break;
      case 'y':
	Atom[i]->x = round(xalt * cx - zalt * sx);
	Atom[i]->z = round(xalt * sx + zalt * cx);
	break;
      case 'z':
	Atom[i]->x = round(xalt * cx + yalt * sx);
	Atom[i]->y = round(-xalt * sx + yalt * cx);
	break;
    }
  }
}

void	  centeratoms(void) /* zentriert die Atome im Koordinatensystem */
{
  int	    i, dx, dy, dz, minx, maxx, miny, maxy, minz, maxz;

  maxx = -30000;
  maxy = maxx;
  maxz = maxx;
  minx = 30000;
  miny = minx;
  minz = minx;
  for (i = 0; i < anzahl; i++)
  {
    if (Atom[i]->x < minx)
      minx = Atom[i]->x;
    if (Atom[i]->x > maxx)
      maxx = Atom[i]->x;
    if (Atom[i]->y < miny)
      miny = Atom[i]->y;
    if (Atom[i]->y > maxy)
      maxy = Atom[i]->y;
    if (Atom[i]->z < minz)
      minz = Atom[i]->z;
    if (Atom[i]->z > maxz)
      maxz = Atom[i]->z;
  }
  dx = round(((double) maxx + minx) / 2.0);
  dy = round(((double) maxy + miny) / 2.0);
  dz = round(((double) maxz + minz) / 2.0);
  for (i = 0; i < anzahl; i++)
  {
    Atom[i]->x-=dx;
    Atom[i]->y-=dy;
    Atom[i]->z-=dz;
  }
}

void cleanup(void)
{
  register int i;

  printf("cleaning up...\n");
#ifndef USE_BUILTIN
  for(i=0;i<anzahlinfo;i++)
    free(AtomInfo[i]);
#endif
  for(i=0;i<anzahl;i++)
    free(Atom[i]);
}
