Path: linus!linus!agate!ames!tulane!wupost!darwin.sura.net!mojo.eng.umd.edu!mimsy!phantom
From: phantom@cs.umd.edu (Scott Perry)
Newsgroups: alt.fractals
Subject: Program to convert Fractint 3D to 3dv25
Keywords: fractint 3dv
Message-ID: <45177@mimsy.umd.edu>
Date: 19 Dec 91 03:45:10 GMT
Sender: news@mimsy.umd.edu
Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742
Lines: 329


The following program converts the RAW brief raytracer output of
Fractint v16 to the format used by 3dv25. 3dv25 is much like acrospin,
it allows you to rotate 3D objects on the screen.  A zip containing an
executable as well as source has been uploaded to wuarchive.wustl.edu
in /pub/MSDOS_UPLOADS/rayconv.zip. Both fractint and 3dv25 are also
available from wuarchive in /mirrors/msdos/graphics.

To use, first use fractint to make the 3D output, selecting
RAW raytracer output, and make sure you set brief to yes (I doubt you
will get anything usable if you forget this part). Then run this
program on the resulting FRACTXXX.RAY file. It will create a
FRACTXXX.3D file while can be loaded into 3dv25.

This program isn't really finished, but it works enough
that I'm not sure I will work on it again any time soon. Most
significantly lacking is color (brief=no output). Also there is a bug
in GRID mode that leaves some lines out on the top and bottom of the
image, but it's very tolerable. This code was compiled with Turbo C++
1.0, but will probably compile under most C compilers without much
work.

Comments are welcome. And one final note, I believe 3dv25
requires a mouse.

Scottphantom@cs.umd.edu      uunet!mimsy!phantom
--------------------------

#include <stdio.h>
#include <string.h>

void usage();
void convert();
int findnumtri(FILE*);

/* Rayconvert
   Purpose: To convert Fractint V16.1 RAW 3D output to a format
      compatible with 3DV25
 */

#define Ver "1.3c"
/* History:
   1.0 Original
   1.1 Point support (now the default)
   1.2 Cache/history
   1.3 Command line parsing, box
*/   
/* Cache 4 last points - There are some points duplicated which w/o
   caching would create multiple entries in output file. Caching attempts
   to eliminate these redundancies. This is really just a history since
   it doesn't attempt to optimize what it keeps around. */
#define CACHE 4 /* This seems to be optimal. >5 gains nothing. */

/* these probably should be passed */
int grid=0,default_color=44,box=2;

void main(int argc,char **argv)
{
char fn[12],fn2[12];
FILE *in,*out,*tmp;
char i,found=0;

   printf("Rayconvert v%s by Scott Perry (phantom@cs.umd.edu)\n\n",Ver);

   /* Parse command line arguments */
   argc++; /* gets rid of annoying unused warning, no other purpose */
   while (*++argv)
   {
      if (argv[0][0]=='-' || argv[0][0]=='/')
      {
 if (argv[0][1]=='g')
    grid=1;
 else if (argv[0][1]=='p')
    grid=0;
 else if (argv[0][1]=='b')
    box=0;
 else if (argv[0][1]=='f')
    box=1;
 else if (argv[0][1]=='c')
    default_color=atoi(*++argv);
      }
      else
      {
 if (found)
    usage();
 found=1;
 strcpy(fn2,*argv);
      }
   }
   if (!found)
      usage();
 
   in=fopen(fn2,"r");
   if (!in)
   {
      fprintf(stderr,"Couldn't open input file %s.\n",fn2);
      exit(2);
   }

   /* Get base file name, append .3d and put it in fn */
   i = strcspn(fn2, ".");
   if (i)
fn2[i] = 0;
   sprintf(fn, "%s.3d", fn2);

   out=fopen(fn,"w");
   if (!out)
   {
      fprintf(stderr,"Couldn't open output file %s.\n",fn);
      exit(3);
   }
   tmp=fopen("rayconv.tmp","w");
   if (!tmp)
   {
      fprintf(stderr,"Couldn't open temporary file rayconv.tmp.\n");
      exit(4);
   }

   convert(in,out,tmp);
   printf("\nDone.\n");
} /* End of Main */

/* Given an open (for reading) file, search for Fractint's comment that
gives the number of triangles in the file. Then rewind back to the beginning
of the file */
int findnumtri(FILE *in)
{
   char c;
   int n=0;
   
   c=fgetc(in);
   /* Scan for =, then input the next number. Could be more fool-proof. */
   while (!feof(in))
   {
      if (c=='=')
      {
fscanf(in,"%d",&n);
break;
      }
      c=fgetc(in);
   }
   rewind(in);
   
   return n;
}
      
void usage()
{
   printf("Usage: rayconv [flags] <input file name>\n");
   printf("flags:\n\t-g\tGrid mode\n\t-p\tPoint mode (default)\n");
   printf("\t-c #\tSet color to # (default=%d)\n",default_color);
   printf("\t-b\tTurn off bounding box\n\t-f\tFast bounding box\n");
   exit(1);
}

/* Main conversion routine */
void convert(FILE *in,FILE *out,FILE *tmp)
{
float x,y,z,minx,miny,minz,maxx,maxy,maxz;
float cx[CACHE],cy[CACHE],cz[CACHE]; /* x,y,z coordinates */
int   cnum[CACHE];                   /* point number */
int numtri,count=0,color;
int hits=0,cp=0,c,new=0;
char i,line[80];

   printf("Rayconvert creating %s format output.\n\n",(grid?"GRID":"POINT"));
   printf("Rayconvert scanning for # of triangles...");
   numtri=findnumtri(in);
   printf("Found %d triangles.\n",numtri);
   /* From here on, numtri really is numpoints */
   numtri*=3;
   /* Create a space to store the number of data points later */
   fprintf(out,"       ");

   if (box==2)
      minx=miny=minz=maxx=maxy=maxz=0.0;
   if (box==1)
   {
      minx=miny=minz=-1.0;
      maxx=maxy=maxz=1.0;
   }
   
   /* Zero cache and cache pointer */
   for (c=0;c<CACHE;c++)
      cx[c]=cy[c]=cz[c]=2.0; /* Fractint outputs between [-1.0,1.0] */
   cp=0;
   /* Main conversion loop */
   printf("Rayconvert now converting data.\n");
   while (!feof(in))
   {
      fgets(line,80,in);
      if (line[0]!='\n') /* not_blank_line */
      {
 /* Check for comment line */
 if (line[0]=='{')
    printf("%s",line);
 else
 {  /* this_must_be_a_point */
    sscanf(line,"%f %f %f",&x,&y,&z);
    count++;

    if (box>1)
    {
       if (x>maxx) maxx=x;
       if (y>maxy) maxy=y;
       if (z>maxz) maxz=z;
       if (x<minx) minx=x;
       if (y<miny) miny=y;
       if (z<minz) minz=z;
    }
    
    /* Calculate move code for grid output */
    if (grid)
    {
       if (count % 4==1)
  color=0;
       else
  color=default_color;
    }

    /* Search for point in cache */
    for (c=0;c<CACHE;c++)
       if (cx[c]==x && cy[c]==y && cz[c]==z)
       {
  hits++;
/* 0 2 3 2 3 0 1 0 1 2 3 2 3 0 1 0 1 2 3 2 3 0 1 0 1
this pattern is the value of c at this point on 3 sample files

5 6 7 8  11 12 13 14  pattern of count value
*/
  if (grid)
     fprintf(tmp,"%d %d\n",cnum[c],color);
  break; /* break from for */
       }
    
    if (c==CACHE) /* if_not_cache_hit */
    {
       /* Add point to cache here */
       cx[cp]=x; cy[cp]=y; cz[cp]=z;
       new++;
       cnum[cp]=new;
       /* Update cache pointer */
       cp++;
       if (cp==CACHE)
  cp=0;
  
       /* Copy it to out (point list) */
       fprintf(out,"%.4f %.4f %.4f\n",x,y,z);

       /* Output to moves list */
       if (grid)
       {
  /* Write color code to "moves list" */
  fprintf(tmp,"%d %d\n",new,color);
       }
       else /* point_mode */
       {
  fprintf(tmp,"%d 0\n",new);
  fprintf(tmp,"%d %d\n",new,default_color);
       } /* End point_mode */
    } /* End of if_not_cache_hit */
 } /* end of this_must_be_a_point else */
      } /* End of if not_blank_line */
   }  /* End of while(!eof) */

   if (box)
   {
      fprintf(out,"%.4f %.4f %.4f\n",minx,maxy,maxz);
      fprintf(out,"%.4f %.4f %.4f\n",maxx,maxy,maxz);
      fprintf(out,"%.4f %.4f %.4f\n",minx,miny,maxz);
      fprintf(out,"%.4f %.4f %.4f\n",maxx,miny,maxz);
      fprintf(out,"%.4f %.4f %.4f\n",minx,maxy,minz);
      fprintf(out,"%.4f %.4f %.4f\n",maxx,maxy,minz);
      fprintf(out,"%.4f %.4f %.4f\n",minx,miny,minz);
      fprintf(out,"%.4f %.4f %.4f\n",maxx,miny,minz);
      fprintf(tmp,"%d 0\n",new+1);
      fprintf(tmp,"%d 1\n",new+2);      
      fprintf(tmp,"%d 1\n",new+4);      
      fprintf(tmp,"%d 1\n",new+3);      
      fprintf(tmp,"%d 1\n",new+1);      
      fprintf(tmp,"%d 1\n",new+5);      
      fprintf(tmp,"%d 1\n",new+6);      
      fprintf(tmp,"%d 1\n",new+8);      
      fprintf(tmp,"%d 1\n",new+7);      
      fprintf(tmp,"%d 1\n",new+5);      
      fprintf(tmp,"%d 1\n",new+7);      
      fprintf(tmp,"%d 1\n",new+3);
      fprintf(tmp,"%d 1\n",new+4);      
      fprintf(tmp,"%d 1\n",new+8);      
      fprintf(tmp,"%d 1\n",new+6);      
      fprintf(tmp,"%d 1\n",new+2);
   }
   
   if (count!=numtri)
      fprintf(stderr,"Warning:%d!=%d--> Data may be damaged.\n",count,numtri);
   printf("Cache hits %d of %d (%.1f%%)\n",hits,count,100.0*hits/count);
   count=count-hits;
   
   /* output number of moves, if grid then hits count as moves, if not
      we have one move without draw for each move with draw */
   fprintf(out,"%d\n",(grid?count+hits:count*2)+(box?16:0));

   if (box)
      count+=8;
      
   /* Now copy tmp (move codes) to the end of out */
   fclose(tmp);
   tmp=fopen("rayconv.tmp","r");
   if (!tmp)
   {
      fprintf(stderr,"Oops. Can't re-open temporary file for reading!\n");
      exit(5);
   }
   while(!feof(tmp))
   {
      i=fgetc(tmp);
      fputc(i,out);
   }

   /* Update number of points */
   rewind(out);
   fprintf(out,"%d\n",count);
   printf("%d Data points found.\n",count);
   
   fclose(out);
   fclose(in);
   fclose(tmp);
   remove("rayconv.tmp");
}
