home *** CD-ROM | disk | FTP | other *** search
- /* Single-Image-Random-Dot 3D-animation frame generator
- * with
- * - antialiasing
- * - OUT.PPM 24-bit output
- * with new previeously unknown:
- * - dithering pattern (c) Esa Kuru (kuru@jyu.fi)
- * that enables
- * a) changing of resolution of an already drawn picture afterwards
- * b) colours and shades to be added to surfaces in the picture
- *
- * Copyright by Esa Kuru (the Author)
- * Address:
- * Aatoksenkatu 10 B 31
- * 40720 Jyvaskyla
- * FINDLAND
- *
- * This code is freely distributable and released mainly on
- * research purposes for 3-D vision enthusiasts.
- * This comment must be kept within this program and within its
- * modified versions unmodified. No part of this code may be
- * sold in any format without my written and signed permission.
- * This code may be modified on following conditions:
- * - If you modify the code You must send the modified version
- * of this code directly to me, the author Esa Kuru
- * (E-mail above is fine)
- * - If You include any part of this or modified code to another program
- * (commercial, freely distributable, public-domain, share-ware
- * or whatever) then You must send all of the source files needed
- * to compile that program with an executable with all the gadgets
- * to run it (not the computer) and one free license for me to use
- * that code. My contribution to Your product must be mentioned.
- *
- * This code is not quaranteed to do what it claims to do and the
- * author is in no way responsible of any damage caused by
- * running this program. WYSIWYG.
- *
- * Since I just have no time to include this to those Wonderful
- * public-domain or freely distributable and modifiable ray tracers
- * I'm releasing this new feature for You programmers to do the
- * job, thank You.
- *
- * My best wishes to Vesa Meskanen (the author of commercial ray-tracer 'REAL-3D')
- * You ought to have answered my request for call back. Are You too proud or what?
- * Now I cannot wait for Your call forever, therefore I am releasing
- * this code free for everyone. :-) Sorry. :--)
- */
-
- /* History:
- * 5.1.1993 An initial version written in AREXX-language (Esa Kuru)
- * 12.1.1993 First C-language version (Esa Kuru)
- * I have successfully compiled this on SUN-Sparc-station with
- * gcc -O2 wave.c -o wave -lm
- * and with Amiga 3000/68040 with 18Mb RAM :
- * gcc -O2 wave.c -o wave -m68020 -m68881
- * all double types converted to floats and stack set to 300000.
- * 15.1.1993 Animation frame generation added and
- * a random number seed initialization corrected.
- * This version is run by a script that alters framenumber
- * in command line. (Esa Kuru)
- * Note: Currently this code doesn't handle perspective images
- * correctly although it gives 3D-sird-effect.
- * Nor does this handle right and left eye colors
- * in incr, incg and incb statements correctly, but works.
- * amp statement should be rewritten if included to another
- * program (Esa Kuru)
- *
- * Have fun! And don't loose Your sence of reality. :-)
- */
-
- /* That's about it and now the fun starts, the rest of the comments may be
- * removed if You like. Try to keep the code as portable as possible.
- */
-
- /* maybe all of these includes are not necessary, figure out */
- #include <ctype.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <time.h>
- #include <math.h>
-
- /* PLANE is 3d-magic number
- * rest of #defines relate to maximum picture size
- * ROUNDS is needed to fill the picture with dithering pattern
- */
- #define PLANE 60
- #define XMIN 0
- #define YMIN 0
- #define YYMAX 2000
- #define XXMAX 2000
- #define ROUNDS 64
-
- /* Antialias must be: AALIAS > 0, or division by zero error will occur.
- * BUFLEN is the length of outputbuffer to a file.
- */
- #define AALIAS 10
- #define BUFLEN 60000L
- /* header is a part of ppm P6 header
- */
- static char header[]={0x32,0x35,0x35,0x0a,0x00};
-
- /* rast[] contains the NEW dithering pattern that is based on
- * prime numbers in the sense that an integral over rast[]
- * is always constant and rast[] is frequencymodulated by primes.
- * There may be different amplitudes, lengths or orders preferrably
- * ascending or descending frequency modulation.
- * I think there is no reason to hide or keep secret any of this information,
- * one can always analyze a drawn picture by magnifying it enough.
- */
-
- static long rast[]={32,64,64,00,00,48,48,48,16,16,16,40,40,40,40,40,\
- 24,24,24,24,24,24,24,36,36,36,36,36,36,36,28,28,28,28,\
- 28,28,28,28,28,28,28,34,34,34,34,34,34,34,34,34,34,34,\
- 34,34,31,31,31,31,31,31,31,31,31,31,31};
- char out[BUFLEN];
-
- /* make this a subroutine! */
- main(argc,argv)int argc;char *argv[];{
- FILE *outf1;
- long outptr=-1; /* buffer counter */
- int t,xcenter,ycenter;
-
- /* rr - right red
- * rg - right green
- * rb - right blue
- * lr - left red
- * lg - left green
- * lb - left blue
- * cr - the average of rr and lr
- * cg - the average of rg and lg
- * cb - the average of rb and lb
- */
-
- int y,yy,x,rr,rg,rb,lr,lg,lb,cr,cg,cb,i,aa;
- int rp,gp,bp,xp,yp;
- int XMAX,YMAX;
-
- /* Make these tables with calloc() or malloc() to keep this code
- * portable with small Personal microcomputer systems. This version is a
- * stack pig. (+3 in arrays is just to be sure...figure out!)
- */
-
- float xposr[YYMAX+3],xposg[YYMAX+3],xposb[YYMAX+3];
- float xx,amp,ftmp,incr,incg,incb,xr,xb,xg,pii;
- float r[XXMAX+3],g[XXMAX+3],b[XXMAX+3];
-
- pii=(float)2.0*(float)acos(-1.00);
-
- /* initialize starting positions in left column for each colour separately
- * but first dump a ppm file header and do the init stuff.
- */
-
- for(i=0;i<5;i++){outptr++;out[outptr]=header[i];} /* dump header */
- (void) srand(time(NULL)); /* init random seed */
- for(y=YMIN;y<YYMAX;y++){ /* init position tables */
- xposr[y]=(float)((rand()%111)-2*PLANE); /* constant 111 is not accurate */
- xposg[y]=(float)((rand()%111)-2*PLANE); /* find a better one */
- xposb[y]=(float)((rand()%111)-2*PLANE); /* find a better randomnumber generator */
- }
-
- /* I'd like to see someone rewritten 'selectable' commandline parameters.
- */
-
- if(argc<4){
- (void) printf("Usage: %s <picture#> <xmax> <ymax>\n",argv[0]);
- (void) printf("0 <= picture# <= 30, 320 <= xmax <= %d, 200 <= ymax <= %d.\n",\
- XXMAX,YYMAX);
- (void) printf("%s is a 24-bit random-dot 'wave'-animation frame generator.\n",argv[0]);
- (void) printf("Outputfile is OUT.PPM\n");
- (void) printf("Executable is freely distributable.\n");
- (void) printf("Author: Esa Kuru (kuru@jyu.fi) 15.2.1993 \n");
- exit(10);
- }
- t=atoi(argv[1]); /* t - the time i.e. the number of frame */
- XMAX=atoi(argv[2]);
- YMAX=atoi(argv[3]);
-
- /* the next figures are tested to be all-right with current formulaes below.
- */
-
- if((t<0)||(t>30)){
- (void) printf("Invalid parameter: picture# must be between 0...30 \n");exit(5);
- }
- if(XMAX<320){
- (void) printf("Invalid parameter: xmax too small.\n");exit(1);
- }
- if(XMAX>XXMAX){
- (void) printf("Invalid parameter; xmax too large.\n");exit(2);
- }
- if(YMAX<200){
- (void) printf("Invalid parameter: ymax too small.\n");exit(3);
- }
- if(YMAX>YYMAX){
- (void) printf("Invalid parameter: ymax too large.\n");exit(4);
- }
- /* make a filename selectable in one of commandline options
- */
- if(NULL==(outf1=fopen("OUT.PPM","wb"))){
- (void) printf("Cannot open outfile: OUT.PPM");
- exit(20);
- }
- (void) fprintf(outf1,"P6\n%d %d\n",XMAX,YMAX);
- fclose(outf1); /* These few lines are a dirty kludge and tells */
- if(NULL==(outf1=fopen("OUT.PPM","awb"))){ /* about my ignorance of programming */
- (void) printf("Cannot open outfile: OUT.PPM\n"); /* in C */
- exit(30);
- }
- ycenter=(int)((YMAX-YMIN)/2.0);
- xcenter=(int)((XMAX-XMIN)/2.0);
-
- for(y=-ycenter;y<ycenter;y++){ /* main loop: process all lines */
- for(x=-xcenter;x<xcenter;x++){ /* init background colors */
- xx=x+xcenter; /* this loop could be well removed */
- rr=128;rg=128;rb=128;
- lr=128; /* define red for left eye */
- lg=128; /* define green for left eye */
- lb=128; /* define blue for left eye */
- cr=(int)(rr+lr)/2.0; cg=(int)(rg+lg)/2.0; cb=(int)(rb+lb)/2.0;
- if(((int)xx>=XMIN)&&((int)xx<=XMAX)){ r[(int)xx]=(float)cr;
- g[(int)xx]=(float)cg;
- b[(int)xx]=(float)cb;
- }
- } /* end init background colors */
- for(i=1;(long)i<(long)ROUNDS;i++){ /* process all micropixels in a line */
- yy=y+ycenter;
- for(aa=0;aa<AALIAS;aa++){ /* process each pixel as antialiased */
- incr=(float)(((xposr[yy]+i)*AALIAS+aa)/(float)(AALIAS+1)); /* red start position */
- incg=(float)(((xposg[yy]+i)*AALIAS+aa)/(float)(AALIAS+1)); /* green start position */
- incb=(float)(((xposb[yy]+i)*AALIAS+aa)/(float)(AALIAS+1)); /* blue start position */
- ftmp= -xcenter-PLANE; xr=ftmp+incr; xg=ftmp+incg; xb=ftmp+incb;
-
- while ((long)(xr)<(long)xcenter){ /* do calc red line */
- xx=xr+xcenter;
- /*
- * The next three while loops could be merged together and one of them
- * could handle all colours in single loop. However it is interesting to
- * note that if You put different functions within different while loops
- * You can easily create transparent 3D-surfaces that have different
- * base colour (anything You like) and different depths (=distances from screen).
- * Note that amp is not pefect for any depth functions and may have
- * to be corrected. incr,incg,incb should be updated in each of those
- * while loops if You want to create transparent surfaces.
- * If You want to include this into a ray-tracer then the incr,incg,incb functions
- * should call a raytracer and return the distance to the nearest viewable object
- * a ray crosses within point (x,y). Amp should be modified to use correct
- * shades 'rast[]'-dithering included.
- * sin() is here the depth function that can be modified if You just want to
- * play around.
- * It would be nice to have to sliders for additive and multiplicative
- * dithering coefficients in amp function and not just constants.
- * This affects to the randomness of the picture and to the clarity of 3D-effect.
- */
- /* an alternative static pyramid-like function is commented here
- */
- /* incr=((float)PLANE-((float)180.0-((float)abs(xr)+(float)abs(y)))/(float)18.0);
- */ /* depth function (for red) */
- /* if (incr>(float)PLANE)incr=(float)PLANE;
- */
- incr=(float)PLANE+sin(sqrt(xr*xr+y*y)/20.0+(float)t*pii/30.0)*2.0;
-
- if (xx>0) {
- amp=(float)((255+((float)rast[i])*8-8*32)/(255.0+(xr*xr+y*y)/150)+ \
- ((float)rast[i])/64.0-32/64.0);
- if (amp<(float)(0.0))amp=(float)0.0;
- rr=128; lr=128; cr=(rr+lr)/2; x=(int)(xx);
- if((x>=XMIN) && (x<=XMAX))r[x]=(float)((float)(r[x])+(float)(cr)*amp);
- }
- xr=xr+incr;
- } /* end calc red line */
-
- while ((long)(xg)<(long)xcenter){ /* do calc green line */
- xx=xg+xcenter;
-
-
- /* incg=(float)PLANE+(((float)180.0-((float)abs(xg)+(float)abs(y)))/(float)18.0);
- */ /* depth function (for green) */
- /* if (incg<(float)PLANE)incg=(float)PLANE;
- */
- incg=(float)PLANE+sin(sqrt(xg*xg+y*y)/20.0+(float)t*pii/30.0)*2.0;
-
- if (xx>0) {
- amp=(float)((255+(rast[i])*8-8*32)/(255.0+(xg*xg+y*y)/150)+(rast[i])/64-32/64);
- if (amp<0) amp=(float)0.0;
- rg=128; lg=128; cg=(rg+lg)/2; x=(int)(xx);
- if((x>=XMIN) && (x<XMAX))g[x]=(float)((float)(g[x])+(float)(cg)*amp);
- }
- xg=xg+incg;
- } /* end calc green line */
-
- while ((long)(xb)<(long)xcenter){ /* do calc blue line */
- xx=xb+xcenter;
-
-
- /* incb=(float)PLANE; */ /* depth function (for blue) */
-
- incb=(float)PLANE+sin(sqrt(xb*xb+y*y)/20.0+(float)t*pii/30.0)*2.0;
-
- if (xx>0) {
- amp=(float)((255+(rast[i])*8-8*32)/(255.0+(xb*xb+y*y)/150)+(rast[i])/64-32/64);
- if (amp<0) amp=(float)0.0;
- rb=128; lb=128; cb=(rb+lb)/2; x=(int)(xx);
- if((x>=XMIN) && (x<XMAX))b[x]=(float)((float)(b[x])+(float)(cb)*amp);
- }
- xb=xb+incb;
- } /* end calc blue line */
- } /* end anti aliasing */
- } /* end process mikropixels */
-
- /* The rest is an easy part of the program:
- * we just check that the pixel to be drawn into outputbuffer
- * is within drawing boundaries and then we scale the colour to
- * rp,gp,bp into allowable limits.
- */
- x=-xcenter;
- while (x<xcenter){ /* draw line by line */
- xx=(int)(x+xcenter);
- yp=(int)(y+ycenter);xp=(int)(x+xcenter);
- if ((yp>=YMIN)&&(yp<=YMAX-1)){
- if ((xp>=XMIN)&&(xp<=XMAX-1)){
- rp=(int)(r[(int)xx]/(AALIAS+1)); /* calc anti-aliased color in xp */
- gp=(int)(g[(int)xx]/(AALIAS+1));
- bp=(int)(b[(int)xx]/(AALIAS+1));
- if (rp>255) {rp=255;} /* color range must be 0..255 for r,g,b */
- else if (rp<0) rp=0;
- if (gp>255) {gp=255;}
- else if (gp<0) gp=0;
- if (bp>255) {bp=255;}
- else if (bp<0) bp=0;
- if ((long)outptr>(long)BUFLEN-6){
- (void) fwrite((void *) out,1,outptr+1,outf1);
- outptr=-1;
- }
- outptr++;
- out[outptr]=(char)rp;
- outptr++;
- out[outptr]=(char)gp;
- outptr++;
- out[outptr]=(char)bp;
- } /* end y-range ok */
- } /* end x-range ok */
- x=x+1; /* next horizontal pixel */
- } /* end draw line */
- } /* end main loop: process all lines */
- (void) fwrite((void *) out,1,outptr+1,outf1); /* dump partial buffer to a file */
- fclose(outf1);
- exit(0);
- }/* main */
-