[comp.sys.ibm.pc] Phong shading demo for Atari ST

wheels@mks.UUCP (Gerry Wheeler) (03/13/88)

/*
 * The following software is modeled very closely after the program that
 * appeared in the math coprocessor section of the March '88 Byte magazine. 
 * To compile this with Mark Williams C, use the command:
 * 
 * 	cc -f -o ball.tos ball.c -lm
 * 
 * The -f option supplies the floating point version of printf(), and the
 * -lm option includes the math library. 
 * 
 * A Turbo C version of this program was posted recently.  I started with
 * that source (saved me some typing -- thanks Bill), and changed it as
 * necessary for the ST's graphics. 
 * 
 * Here are some brief test results from the Turbo C version and from the
 * ST:
 * 
 * Machine		Without coprocessor		With coprocessor
 * 			mm:ss				mm:ss
 * ---------       -------------------             -----------------
 * ATT 6300,
 * V30, 8bit EGA	59:37				 3:08
 * 
 * Epson Equity III
 * 8 MHz		37:36				 N/A
 * 
 * IBM PS/2 mod 80
 * EGA emulation	16:25				 1:02
 * VGA, but same # of pixels				 0:48
 * 
 * Atari ST
 * low res mode		13:54				 N/A
 *
 * Atari ST
 * low res (bug fixed)	14:11				 N/A
 * 
 * 
 * The first three of the above machines were running the 80186/80286 code
 * generated by TC, ver 1.5.  Note that the different mapping of the bit
 * planes of VGA permitted a more efficient driver to be written, apparently
 * because of not needing to keep tinkering with the bit plane select
 * register as in EGA. 
 * 
 * The Atari ST version was compiled using the Mark Williams C compiler. 
 * This is a bit of an apples and oranges comparison, because the ST has
 * fewer pixels on the screen in low res mode than the others tested.  (The
 * ST's screen is 320 by 200 by 4 bits.) The putpixel routine is part of
 * MWC's line A support. Things might be quicker if a custom routine were
 * written instead of using the line A interrupts in the ST.
 *
 * By the way, if anyone knows, can they tell me how to read the current
 * contents of the ST's colour palette? If I could do that, I could restore
 * it at the end of the program.
 *
 * Also by the way, there is a bug in the original listing and in the
 * Turbo C version that went around. When finding the nearest vertex to
 * the point being drawn, in order to decide what colour to use, the loop
 * should read "for (i=0, p=0; i<12; ++i)". The original had "i<11". This
 * affects the timing results, since there is now one more calculation to
 * do for each pixel, so I have included the ST's times with and without
 * the bug. (The bug didn't affect the original display, because the vertex
 * being omitted was the one away from the viewer. I noticed it when I
 * changed the code to rotate the ball to a different view.)
 */

#include <math.h>
#include <stdio.h>
#include <time.h>
#include <osbind.h>
#include <xbios.h>
#include <linea.h>
 
clock_t start, stop;
float	pi;
int	colors[] = { 3, 6, 10, 13, 6, 3, 10, 13, 6, 3, 13, 10 },
	d[] = { 320, 200 },
	palette[] = { 0x000, 0x003, 0x005, 0x007, 0x030, 0x050, 0x070,
			0x000, 0x300, 0x500, 0x700, 0x330, 0x550, 0x770,
			0x000, 0x777 },
	i, k, x, y, x_min, x_max, y_min, y_max;
unsigned short random;


 
main() {
    float  a, b, c, l0, l1, l2, ln, ln1, n0, n1, n2, p, q, r=99,
           s, t, v[12][3];
    int old_rez;

    /*
     * Initialise palette and resolution, and line A routines.
     */

    old_rez = Getrez();
    /* get old palette? */
    Setscreen((char *)-1, (char *)-1, 0);
    Setpallete(palette);
    linea0();

    /* Start timing. */
    start = clock();
    
    /* Pixel aspect ratio */
    a= 1.2;	/* (d[0] / 4) / (d[1] / 3) */
 
    /* Screen center coordinates */
    b=0.5*(d[0]-1);
    c=0.5*(d[1]-1);
 
    /* Unit length light source vector */
    l0=-1/sqrt(3.);
    l1=l0;
    l2=-l0;
 
    /* Ratio of circumference to diameter of circle */
    pi=4*atan(1.);
 
    /* A dozen vertices evenly spread over a unit sphere. */
    v[0][0]=0;
    v[0][1]=0;
    v[0][2]=1;
    s=sqrt(5.);
    for (i=1; i<11; i++) {
       p = pi * i / 5;
       v[i][0]=2*cos(p)/s;
       v[i][1]=2*sin(p)/s;
       v[i][2]=(1.-i%2*2)/s;
    }
    v[11][0]=0;
    v[11][1]=0;
    v[11][2]=-1;
 
    /* Loop to Phong shade every pixel */
    y_max=c+r;
    y_min=2*c-y_max;
    for (y=y_min;y<y_max;y++) {
	s=y-c;
	n1=s/r;
	ln1=l1*n1;
	s=r*r-s*s;
	x_max=b+a*sqrt(s);
	x_min=2*b-x_max;
	for (x=x_min;x<x_max;x++) {
	    t=(x-b)/a;
	    n0=t/r;
	    t=sqrt(s-t*t);
	    n2=t/r;
	    /* compute dot product & clamp to positive value */
	    ln=l0*n0+ln1+l2*n2;
	    if (ln<0)
	        ln=0;
	    /* cos(e.r)**27 */
	    t=ln*n2;
	    t+=t-l2;
	    t*=t*t;
	    t*=t*t;
	    t*=t*t;
	    /* nearest vertex to normal yields max dot prod.  get that color */
	    for (i=0,p=0;i<12;i++)
		if (p<(q=n0*v[i][0]+n1*v[i][1]+n2*v[i][2])) {
		    p=q;
		    k=colors[i];
		}
	    /* Aggregate ambient, diffuse & specular int. & do dither. */
	    i=k-2.5+2.5*ln+t+(random=37*random+1)/65536.;
	    /* clamp values outside range of 3 color levels to blk or wht */
	    if (i<k-2)
	        i=0;
	    else if (i>k)
	        i=15;
	    putpixel(x,y,i);
	}
    }
    /* Finish timing. */
    stop = clock();

    /* restore old screen parameters */
    Setscreen((char *)-1, (char *)-1, old_rez);
    
    /* Print timing results. */
    printf("Time = %3.2f seconds\n", ((double)(stop-start))/CLK_TCK);
}
-- 
     Gerry Wheeler                           Phone: (519)884-2251
Mortice Kern Systems Inc.               UUCP: uunet!watmath!mks!wheels
   35 King St. North                             BIX: join mks
Waterloo, Ontario  N2J 2W9                  CompuServe: 73260,1043