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