home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume35 / wave / part01 / wave.c next >
Encoding:
C/C++ Source or Header  |  1993-03-04  |  12.9 KB  |  347 lines

  1. /* Single-Image-Random-Dot 3D-animation frame generator
  2.  * with
  3.  * - antialiasing
  4.  * - OUT.PPM 24-bit output
  5.  * with new previeously unknown:
  6.  *  - dithering pattern  (c) Esa Kuru (kuru@jyu.fi)
  7.  *    that enables 
  8.  *    a) changing of resolution of an already drawn picture afterwards 
  9.  *    b) colours and shades to be added to surfaces in the picture
  10.  *
  11.  * Copyright by Esa Kuru (the Author)
  12.  * Address: 
  13.  *   Aatoksenkatu 10 B 31
  14.  *   40720 Jyvaskyla
  15.  *   FINDLAND
  16.  *
  17.  * This code is freely distributable and released mainly on
  18.  * research purposes for 3-D vision enthusiasts.
  19.  * This comment must be kept within this program and within its
  20.  * modified versions unmodified. No part of this code may be
  21.  * sold in any format without my written and signed permission.
  22.  * This code may be modified on following conditions:
  23.  * - If you modify the code You must send the modified version
  24.  *   of this code directly to me, the author Esa Kuru 
  25.  *   (E-mail above is fine)
  26.  * - If You include any part of this or modified code to another program
  27.  *   (commercial, freely distributable, public-domain, share-ware
  28.  *   or whatever) then You must send all of the source files needed
  29.  *   to compile that program with an executable with all the gadgets
  30.  *   to run it (not the computer) and one free license for me to use 
  31.  *   that code. My contribution to Your product must be mentioned.
  32.  *
  33.  * This code is not quaranteed to do what it claims to do and the
  34.  * author is in no way responsible of any damage caused by
  35.  * running this program. WYSIWYG.
  36.  *
  37.  * Since I just have no time to include this to those Wonderful 
  38.  * public-domain or freely distributable and modifiable ray tracers
  39.  * I'm releasing this new feature for You programmers to do the
  40.  * job, thank You.
  41.  *
  42.  * My best wishes to Vesa Meskanen (the author of commercial ray-tracer 'REAL-3D')
  43.  * You ought to have answered my request for call back. Are You too proud or what? 
  44.  * Now I cannot wait for Your call forever, therefore I am releasing
  45.  * this code free for everyone. :-) Sorry. :--)
  46.  */
  47.  
  48. /* History:
  49.  *     5.1.1993 An initial version written in AREXX-language (Esa Kuru)
  50.  *    12.1.1993 First C-language version (Esa Kuru)
  51.  *           I have successfully compiled this on SUN-Sparc-station with 
  52.  *        gcc -O2 wave.c -o wave -lm
  53.  *          and with Amiga 3000/68040 with 18Mb RAM :
  54.  *        gcc -O2 wave.c -o wave -m68020 -m68881
  55.  *          all double types converted to floats and stack set to 300000.
  56.  *    15.1.1993 Animation frame generation added and
  57.  *          a random number seed initialization corrected.
  58.  *                This version is run by a script that alters framenumber
  59.  *          in command line. (Esa Kuru)
  60.  *    Note:      Currently this code doesn't handle perspective images
  61.  *           correctly although it gives 3D-sird-effect.
  62.  *          Nor does this handle right and left eye colors
  63.  *           in incr, incg and incb statements correctly, but works.
  64.  *          amp statement should be rewritten if included to another
  65.  *          program (Esa Kuru)
  66.  *
  67.  *    Have fun! And don't loose Your sence of reality. :-)
  68.  */
  69.  
  70. /* That's about it and now the fun starts, the rest of the comments may be 
  71.  * removed if You like. Try to keep the code as portable as possible.
  72.  */
  73.  
  74. /* maybe all of these includes are not necessary, figure out */
  75. #include <ctype.h>
  76. #include <stdio.h>
  77. #include <stdlib.h>
  78. #include <time.h>
  79. #include <math.h>
  80.  
  81. /* PLANE is 3d-magic number
  82.  * rest of #defines relate to maximum picture size
  83.  * ROUNDS is needed to fill the picture with dithering pattern
  84.  */
  85. #define PLANE 60
  86. #define XMIN 0
  87. #define YMIN 0
  88. #define YYMAX 2000
  89. #define XXMAX 2000
  90. #define ROUNDS 64
  91.  
  92. /* Antialias must be: AALIAS > 0, or division by zero error will occur.
  93.  * BUFLEN is the length of outputbuffer to a file.
  94.  */
  95. #define AALIAS 10
  96. #define BUFLEN 60000L
  97. /* header is a part of ppm P6 header
  98.  */
  99. static char header[]={0x32,0x35,0x35,0x0a,0x00};
  100.  
  101. /* rast[] contains the NEW dithering pattern that is based on 
  102.  * prime numbers in the sense that an integral over rast[]
  103.  * is always constant and rast[] is frequencymodulated by primes. 
  104.  * There may be different amplitudes, lengths or orders preferrably
  105.  * ascending or descending frequency modulation.
  106.  * I think there is no reason to hide or keep secret any of this information,
  107.  * one can always analyze a drawn picture by magnifying it enough.
  108.  */
  109.  
  110. static long rast[]={32,64,64,00,00,48,48,48,16,16,16,40,40,40,40,40,\
  111.         24,24,24,24,24,24,24,36,36,36,36,36,36,36,28,28,28,28,\
  112.         28,28,28,28,28,28,28,34,34,34,34,34,34,34,34,34,34,34,\
  113.         34,34,31,31,31,31,31,31,31,31,31,31,31};
  114. char out[BUFLEN];
  115.  
  116. /* make this a subroutine! */
  117. main(argc,argv)int argc;char *argv[];{
  118.  FILE *outf1;
  119.  long outptr=-1; /* buffer counter */
  120.  int t,xcenter,ycenter;
  121.  
  122. /* rr - right red
  123.  * rg - right green
  124.  * rb - right blue
  125.  * lr - left red
  126.  * lg - left green
  127.  * lb - left blue
  128.  * cr - the average of rr and lr
  129.  * cg - the average of rg and lg
  130.  * cb - the average of rb and lb
  131.  */
  132.  
  133.  int y,yy,x,rr,rg,rb,lr,lg,lb,cr,cg,cb,i,aa;
  134.  int rp,gp,bp,xp,yp;
  135.  int XMAX,YMAX;
  136.  
  137. /* Make these tables with calloc() or malloc() to keep this code
  138.  * portable with small Personal microcomputer systems. This version is a
  139.  * stack pig. (+3 in arrays is just to be sure...figure out!)
  140.  */ 
  141.  
  142.  float xposr[YYMAX+3],xposg[YYMAX+3],xposb[YYMAX+3];
  143.  float xx,amp,ftmp,incr,incg,incb,xr,xb,xg,pii;
  144.  float r[XXMAX+3],g[XXMAX+3],b[XXMAX+3];
  145.  
  146.  pii=(float)2.0*(float)acos(-1.00);
  147.  
  148. /* initialize starting positions in left column for each colour separately
  149.  * but first dump a ppm file header and do the init stuff.
  150.  */
  151.  
  152.  for(i=0;i<5;i++){outptr++;out[outptr]=header[i];}  /* dump header */
  153.  (void) srand(time(NULL));            /* init random seed */
  154.  for(y=YMIN;y<YYMAX;y++){        /* init position tables */
  155.   xposr[y]=(float)((rand()%111)-2*PLANE); /* constant 111 is not accurate */
  156.   xposg[y]=(float)((rand()%111)-2*PLANE); /* find a better one */
  157.   xposb[y]=(float)((rand()%111)-2*PLANE); /* find a better randomnumber generator */
  158.  }
  159.  
  160.  /* I'd like to see someone rewritten 'selectable' commandline parameters.
  161.   */
  162.  
  163.  if(argc<4){
  164.   (void) printf("Usage: %s <picture#> <xmax> <ymax>\n",argv[0]);
  165.     (void) printf("0 <= picture# <= 30, 320 <= xmax <= %d, 200 <= ymax <= %d.\n",\
  166.     XXMAX,YYMAX);
  167.     (void) printf("%s is a 24-bit random-dot 'wave'-animation frame generator.\n",argv[0]);
  168.     (void) printf("Outputfile is OUT.PPM\n");
  169.     (void) printf("Executable is freely distributable.\n");
  170.     (void) printf("Author: Esa Kuru (kuru@jyu.fi) 15.2.1993 \n");
  171.     exit(10);
  172.  }
  173.  t=atoi(argv[1]); /* t - the time i.e. the number of frame */
  174.  XMAX=atoi(argv[2]);
  175.  YMAX=atoi(argv[3]);
  176.  
  177. /* the next figures are tested to be all-right with current formulaes below.
  178.  */
  179.  
  180.  if((t<0)||(t>30)){
  181.   (void) printf("Invalid parameter: picture# must be between 0...30 \n");exit(5);
  182.  }
  183.  if(XMAX<320){
  184.   (void) printf("Invalid parameter: xmax too small.\n");exit(1);
  185.  }
  186.  if(XMAX>XXMAX){
  187.   (void) printf("Invalid parameter; xmax too large.\n");exit(2);
  188.  }
  189.  if(YMAX<200){
  190.   (void) printf("Invalid parameter: ymax too small.\n");exit(3);
  191.  }
  192.  if(YMAX>YYMAX){
  193.   (void) printf("Invalid parameter: ymax too large.\n");exit(4);
  194.  }
  195. /* make a filename selectable in one of commandline options 
  196.  */
  197.  if(NULL==(outf1=fopen("OUT.PPM","wb"))){
  198.     (void) printf("Cannot open outfile: OUT.PPM");
  199.     exit(20);
  200.  }
  201.  (void) fprintf(outf1,"P6\n%d %d\n",XMAX,YMAX);
  202.  fclose(outf1);                 /* These few lines are a dirty kludge and tells */
  203.  if(NULL==(outf1=fopen("OUT.PPM","awb"))){ /* about my ignorance of programming */
  204.     (void) printf("Cannot open outfile: OUT.PPM\n"); /* in C */
  205.   exit(30);
  206.  }
  207.  ycenter=(int)((YMAX-YMIN)/2.0);
  208.  xcenter=(int)((XMAX-XMIN)/2.0);
  209.  
  210.  for(y=-ycenter;y<ycenter;y++){        /* main loop: process all lines */ 
  211.   for(x=-xcenter;x<xcenter;x++){    /* init background colors */
  212.    xx=x+xcenter;            /* this loop could be well removed */
  213.    rr=128;rg=128;rb=128;
  214.    lr=128;                 /* define red for left eye */
  215.    lg=128;                 /* define green for left eye */
  216.    lb=128;                /* define blue for left eye */
  217.    cr=(int)(rr+lr)/2.0; cg=(int)(rg+lg)/2.0; cb=(int)(rb+lb)/2.0;
  218.    if(((int)xx>=XMIN)&&((int)xx<=XMAX)){ r[(int)xx]=(float)cr; 
  219.                     g[(int)xx]=(float)cg; 
  220.                                b[(int)xx]=(float)cb;
  221.                 }
  222.   }                    /* end init background colors */
  223.   for(i=1;(long)i<(long)ROUNDS;i++){         /* process all micropixels in a line */
  224.    yy=y+ycenter;
  225.    for(aa=0;aa<AALIAS;aa++){             /* process each pixel as antialiased */
  226.     incr=(float)(((xposr[yy]+i)*AALIAS+aa)/(float)(AALIAS+1)); /* red start position */
  227.     incg=(float)(((xposg[yy]+i)*AALIAS+aa)/(float)(AALIAS+1)); /* green start position */
  228.     incb=(float)(((xposb[yy]+i)*AALIAS+aa)/(float)(AALIAS+1)); /* blue start position */
  229.     ftmp= -xcenter-PLANE; xr=ftmp+incr; xg=ftmp+incg; xb=ftmp+incb;
  230.  
  231.     while ((long)(xr)<(long)xcenter){            /* do calc red line */
  232.      xx=xr+xcenter;
  233. /*
  234.  * The next three while loops could be merged together and one of them
  235.  * could handle all colours in single loop. However it is interesting to
  236.  * note that if You put different functions within different while loops
  237.  * You can easily create transparent 3D-surfaces that have different
  238.  * base colour (anything You like) and different depths (=distances from screen).
  239.  * Note that amp is not pefect for any depth functions and may have
  240.  * to be corrected. incr,incg,incb should be updated in each of those 
  241.  * while loops if You want to create transparent surfaces.
  242.  * If You want to include this into a ray-tracer then the incr,incg,incb functions
  243.  * should call a raytracer and return the distance to the nearest viewable object
  244.  * a ray crosses within point (x,y). Amp should be modified to use correct
  245.  * shades 'rast[]'-dithering included.
  246.  * sin() is here the depth function that can be modified if You just want to
  247.  * play around. 
  248.  * It would be nice to have to sliders for additive and multiplicative
  249.  * dithering coefficients in amp function and not just constants.
  250.  * This affects to the randomness of the picture and to the clarity of 3D-effect.
  251.  */
  252. /*   an alternative static pyramid-like function is commented here
  253.  */ 
  254. /*     incr=((float)PLANE-((float)180.0-((float)abs(xr)+(float)abs(y)))/(float)18.0); 
  255. */                        /* depth function (for red) */
  256.   /*   if (incr>(float)PLANE)incr=(float)PLANE;
  257.    */
  258.      incr=(float)PLANE+sin(sqrt(xr*xr+y*y)/20.0+(float)t*pii/30.0)*2.0;
  259.  
  260.      if (xx>0) {
  261.       amp=(float)((255+((float)rast[i])*8-8*32)/(255.0+(xr*xr+y*y)/150)+ \
  262.          ((float)rast[i])/64.0-32/64.0);
  263.       if (amp<(float)(0.0))amp=(float)0.0;
  264.       rr=128; lr=128; cr=(rr+lr)/2; x=(int)(xx);
  265.       if((x>=XMIN) && (x<=XMAX))r[x]=(float)((float)(r[x])+(float)(cr)*amp);
  266.      }
  267.      xr=xr+incr;
  268.     }                        /* end calc red line */
  269.  
  270.     while ((long)(xg)<(long)xcenter){            /* do calc green line */
  271.      xx=xg+xcenter;
  272.  
  273.  
  274. /*     incg=(float)PLANE+(((float)180.0-((float)abs(xg)+(float)abs(y)))/(float)18.0);
  275. */                        /* depth function (for green) */
  276.   /*   if (incg<(float)PLANE)incg=(float)PLANE;
  277.    */
  278.     incg=(float)PLANE+sin(sqrt(xg*xg+y*y)/20.0+(float)t*pii/30.0)*2.0;
  279.  
  280.      if (xx>0) {
  281.       amp=(float)((255+(rast[i])*8-8*32)/(255.0+(xg*xg+y*y)/150)+(rast[i])/64-32/64);
  282.       if (amp<0) amp=(float)0.0;
  283.       rg=128; lg=128; cg=(rg+lg)/2; x=(int)(xx);
  284.       if((x>=XMIN) && (x<XMAX))g[x]=(float)((float)(g[x])+(float)(cg)*amp);
  285.      }
  286.      xg=xg+incg;
  287.     }                        /* end calc green line */ 
  288.  
  289.     while ((long)(xb)<(long)xcenter){            /* do calc blue line */
  290.      xx=xb+xcenter;
  291.  
  292.  
  293.   /*   incb=(float)PLANE; */            /* depth function (for blue) */
  294.  
  295.      incb=(float)PLANE+sin(sqrt(xb*xb+y*y)/20.0+(float)t*pii/30.0)*2.0;
  296.  
  297.      if (xx>0) {
  298.       amp=(float)((255+(rast[i])*8-8*32)/(255.0+(xb*xb+y*y)/150)+(rast[i])/64-32/64);
  299.       if (amp<0) amp=(float)0.0;
  300.       rb=128; lb=128; cb=(rb+lb)/2; x=(int)(xx);
  301.       if((x>=XMIN) && (x<XMAX))b[x]=(float)((float)(b[x])+(float)(cb)*amp);
  302.      }
  303.      xb=xb+incb;
  304.     }                         /* end calc blue line */
  305.    }                         /* end anti aliasing */
  306.   }                        /* end process mikropixels */
  307.  
  308. /* The rest is an easy part of the program: 
  309.  * we just check that the pixel to be drawn into outputbuffer
  310.  * is within drawing boundaries and then we scale the colour to
  311.  * rp,gp,bp into allowable limits.
  312.  */
  313.   x=-xcenter;
  314.   while (x<xcenter){                /* draw line by line */
  315.    xx=(int)(x+xcenter);
  316.    yp=(int)(y+ycenter);xp=(int)(x+xcenter);
  317.    if ((yp>=YMIN)&&(yp<=YMAX-1)){
  318.     if ((xp>=XMIN)&&(xp<=XMAX-1)){
  319.      rp=(int)(r[(int)xx]/(AALIAS+1));    /* calc anti-aliased color in xp */
  320.      gp=(int)(g[(int)xx]/(AALIAS+1));
  321.      bp=(int)(b[(int)xx]/(AALIAS+1));
  322.      if (rp>255) {rp=255;}        /* color range must be 0..255 for r,g,b */
  323.     else if (rp<0) rp=0;
  324.      if (gp>255) {gp=255;}
  325.     else if (gp<0) gp=0;
  326.      if (bp>255) {bp=255;}
  327.     else if (bp<0) bp=0;
  328.      if ((long)outptr>(long)BUFLEN-6){
  329.       (void) fwrite((void *) out,1,outptr+1,outf1);
  330.       outptr=-1;
  331.      }
  332.      outptr++;
  333.      out[outptr]=(char)rp;
  334.      outptr++;
  335.      out[outptr]=(char)gp;
  336.      outptr++;
  337.      out[outptr]=(char)bp;
  338.     }                         /* end y-range ok */
  339.    }                        /* end x-range ok */
  340.    x=x+1;                    /* next horizontal pixel */
  341.   }                         /* end draw line */
  342.  }                        /* end main loop: process all lines */
  343.  (void) fwrite((void *) out,1,outptr+1,outf1);  /* dump partial buffer to a file */
  344.  fclose(outf1);
  345.  exit(0);
  346. }/* main */
  347.