home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
RISC DISC 3
/
RISC_DISC_3.iso
/
resources
/
etexts
/
gems
/
gemsv
/
ch7_6
/
zrendv3.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-04-04
|
18KB
|
661 lines
/* Accurate Rendering Algorithm Based on the Z-Buffer Algorithm
Developed by Raghu Karinthi
West Virginia University
Department of Computer Science
P.O.Box 6330
Morgantown WV 26506-6330
raghu@cs.wvu.edu
Version 3 01/20/95 */
#include "ZRendv3.h"
#define ZFABS(x) (((x) < 0.0) ? -(x) : (x))
#define sub_vec(res,V1,V2) \
{ \
(res)[0] = (V1)[0] - (V2)[0]; \
(res)[1] = (V1)[1] - (V2)[1]; \
(res)[2] = (V1)[2] - (V2)[2]; \
}
#define dot_product(V1,V2) \
((V1)[0] * (V2)[0] + (V1)[1] * (V2)[1] + (V1)[2] * (V2)[2])
#define mathpointmult(x,y,z,w,vec,mat) \
{ \
(x) = (vec)[0] * (mat)[0][0] + \
(vec)[1] * (mat)[0][1] + \
(vec)[2] * (mat)[0][2] + \
(mat)[0][3]; \
\
(y) = (vec)[0] * (mat)[1][0] + \
(vec)[1] * (mat)[1][1] + \
(vec)[2] * (mat)[1][2] + \
(mat)[1][3]; \
\
(z) = (vec)[0] * (mat)[2][0] + \
(vec)[1] * (mat)[2][1] + \
(vec)[2] * (mat)[2][2] + \
(mat)[2][3]; \
\
(w) = (vec)[0] * (mat)[3][0] + \
(vec)[1] * (mat)[3][1] + \
(vec)[2] * (mat)[3][2] + \
(mat)[3][3]; \
} /* mathpointmult */
#define TSWAP(_a_, _b_, _c_) \
{ \
(_c_) = (_a_); (_a_) = (_b_); (_b_) = (_c_); \
}
#define min(_a_, _b_) (((_a_) < (_b_)) ? (_a_) : (_b_))
#define max(_a_, _b_) (((_a_) > (_b_)) ? (_a_) : (_b_))
#define fp_int(x) \
(((x) < 0) ? \
(!((x) & LOMASK)) ? ((x) >> LOBITS) : (((x) >> LOBITS)+1) : \
((x) >> LOBITS) \
)
/*
* Works only if x +ve.
*/
#define fp_int_flr(x) ((x) >> LOBITS)
/*
* We use the following approximation.
*/
#define fp_div(x,y) \
(((x) < 0) ? ((x) / (y) - 1) << LOBITS : ((x) / (y)) << LOBITS)
/*
* Works only if xlo = 0.
*/
#define fp_mult1(x,y) \
(((x)<0) ? \
-(((-(x) & HIMASK)>> LOBITS)*(y)) : \
((x)>> LOBITS)*(y))
/*
* Works only if xhi = 0
*/
#define fp_mult2(x,y) \
(((y)<0)?(-((((-(y))&HIMASK)>>LOBITS)*(x)+((((-(y))&LOMASK)*x)>>LOBITS)))\
: (((y) >> LOBITS) * (x) + ((((y)&LOMASK)*x)>>LOBITS)))
/*
* Fractional Part if x +ve
*/
#define fp_fraction(x) ((x) & LOMASK)
/* Turn a double into a fixpoint number int two's complement.
Negative numbers become: ~a + 1
*/
fixpoint fp_fix(double x)
{
int negative = (x < 0);
double i; /* integer part */
/* not used: double fraction; /* fraction part, positive only */
fixpoint p; /* fixpoint version of abs(x) */
x = fabs(x);
i = floor(x);
/* not used: fraction = x - i; */
p = (((int) i) << LOBITS) | ((int) ((x-i)*(1<<LOBITS)));
if (negative) return (-p);
else return (p);
}
/*
* The following : edge data structure, and functions EdgeScan,
* EdgeSetup, and rasterize_sorted_triangle, are modified from the code
* obtained in Graphics Gems III subdirectory accurate_scan due to Kurt
* Fleischer. Also Refer Lathrop, Kirk, Voorhies, IEEE CG&A 10(5),
* 1990 for a discussion
*/
/*
* Array has the fields called E, Imin, Astep, Bstep, DEA and DEB
* in the paper by Lathrop, Kirk and Voorhies.
*/
typedef int edge[6];
#define EdgeScan(e) \
if ((e)[0] < 0 ) \
{ \
(e)[1] += (e)[2]; (e)[0] += (e)[4]; \
} \
else \
{ \
(e)[1] += (e)[3]; (e)[0] += (e)[5]; \
}
#define EdgeSetup(e,x0,y0,x1,y1) \
{ \
dx = (x1)-(x0); \
dy = (y1)-(y0); \
if (dy >= FIX1) \
{ \
si = fp_div(dx, dy); \
sf = dx - fp_mult1(si, dy); \
xi = (x0) + fp_mult2((FIX1 - fp_fraction((y0))),si) ; \
e[2] = fp_int(si); \
e[3] = e[2]+1; \
e[4]= sf; \
e[5] = sf - dy; \
e[0] = fp_mult2(fp_fraction(xi),dy) + e[5]; \
e[1] = fp_int(xi); \
} \
else e[1] = fp_int(x0); \
} /* EdgeSetup */
/*
* This function applies the view Transform to set of triangles.
*/
void viewTrans_DivByW_DevTrans (InDataSet localSet, register int count,
MAT3mat transform)
{
int i, j;
double x,y,z,w;
/* For every triangle do... */
for( i = 0; i < count; i++)
{
for( j = 0; j < 3; j++)
{
mathpointmult (x,y,z,w,localSet[i].vertices[j].vertex,transform)
x /= w;
y /= w;
z /= w;
localSet[i].vertices[j].vertex[X] = x * (double) WINDOW_WIDTH/2
+ (double) WINDOW_WIDTH/2;
localSet[i].vertices[j].vertex[Y] = y * (double) WINDOW_WIDTH/2
+ (double) WINDOW_HEIGHT/2;
localSet[i].vertices[j].vertex[Z] = z * (double) WINDOW_WIDTH
+ (double) WINDOW_WIDTH;
} /* for j */
} /* for i */
} /* viewTrans_DivByW_DevTrans */
/*
* This function does the actual rasterization.
* Like integer version, but uses EdgeSetup.
*/
void rasterize_sorted_triangle (int minv,
int midv,
int maxv,
InDataSet tp,
FrameBuffer localBuff)
{
edge left, right,
zleft, zright, zspan,
rleft, rright, rspan,
gleft, gright, gspan,
bleft, bright, bspan;
int x, yi,
xmin, xmax;
int temp;
int temp1;
int cw;
fixpoint sf, xi, si, dx, dy;
fixpoint fxmin, fxmax,
fzmin, fzmax, z,
frmin, frmax, r,
fgmin, fgmax, g,
fbmin, fbmax, b;
fixpoint x0, y0, z0, r0, g0, b0;
fixpoint x1, y1, z1, r1, g1, b1;
fixpoint x2, y2, z2, r2, g2, b2;
/*
* Convert the vertices of the triangle and their color value
* to 'fixpoint' representation.
*/
x0 = fp_fix ((tp->vertices[minv]).vertex[X]);
y0 = fp_fix ((tp->vertices[minv]).vertex[Y]);
z0 = fp_fix ((tp->vertices[minv]).vertex[Z]);
x1 = fp_fix ((tp->vertices[midv]).vertex[X]);
y1 = fp_fix ((tp->vertices[midv]).vertex[Y]);
z1 = fp_fix ((tp->vertices[midv]).vertex[Z]);
x2 = fp_fix ((tp->vertices[maxv]).vertex[X]);
y2 = fp_fix ((tp->vertices[maxv]).vertex[Y]);
z2 = fp_fix ((tp->vertices[maxv]).vertex[Z]);
r0 = (tp->vertices[minv]).red;
g0 = (tp->vertices[minv]).green;
b0 = (tp->vertices[minv]).blue;
r1 = (tp->vertices[midv]).red;
g1 = (tp->vertices[midv]).green;
b1 = (tp->vertices[midv]).blue;
r2 = (tp->vertices[maxv]).red;
g2 = (tp->vertices[maxv]).green;
b2 = (tp->vertices[maxv]).blue;
/*
* Find out whether the triangle edges are oriented in clockwise
* or anti-clockwise direction.
*
*/
cw = ( ((tp->vertices[midv]).vertex[1] -
(tp->vertices[minv]).vertex[1]) *
((tp->vertices[maxv]).vertex[0] -
(tp->vertices[minv]).vertex[0])
< ((tp->vertices[midv]).vertex[0] -
(tp->vertices[minv]).vertex[0]) *
((tp->vertices[maxv]).vertex[1] -
(tp->vertices[minv]).vertex[1])
);
/*
* Setup first pair of edges.
*/
if (cw)
{
EdgeSetup (left, x0, y0, x2, y2);
EdgeSetup (zleft, z0, y0, z2, y2);
EdgeSetup (rleft, r0, y0, r2, y2);
EdgeSetup (gleft, g0, y0, g2, y2);
EdgeSetup (bleft, b0, y0, b2, y2);
EdgeSetup (right, x0, y0, x1, y1);
EdgeSetup (zright, z0, y0, z1, y1);
EdgeSetup (rright, r0, y0, r1, y1);
EdgeSetup (gright, g0, y0, g1, y1);
EdgeSetup (bright, b0, y0, b1, y1);
} /* if cw orientation of edges */
else
{
EdgeSetup (left, x0, y0, x1, y1);
EdgeSetup (zleft, z0, y0, z1, y1);
EdgeSetup (rleft, r0, y0, r1, y1);
EdgeSetup (gleft, g0, y0, g1, y1);
EdgeSetup (bleft, b0, y0, b1, y1);
EdgeSetup (right, x0, y0, x2, y2);
EdgeSetup (zright, z0, y0, z2, y2);
EdgeSetup (rright, r0, y0, r2, y2);
EdgeSetup (gright, g0, y0, g2, y2);
EdgeSetup (bright, b0, y0, b2, y2);
} /* else anti-clockwise orientation of edges */
temp = min (fp_int_flr ((cw) ? y2 : y1), fp_int_flr ((cw) ? y1 : y2));
for (yi = fp_int_flr (y0) + 1; yi <= temp; yi ++)
{
fxmin = left[1]; EdgeScan (left)
fxmax = right[1]; EdgeScan (right)
fzmin = zleft[1]; EdgeScan (zleft)
fzmax = zright[1]; EdgeScan (zright)
frmin = rleft[1]; EdgeScan (rleft)
frmax = rright[1]; EdgeScan (rright)
fgmin = gleft[1]; EdgeScan (gleft)
fgmax = gright[1]; EdgeScan (gright)
fbmin = bleft[1]; EdgeScan (bleft)
fbmax = bright[1]; EdgeScan (bright)
xmin = fxmin;
xmax = fxmax;
fxmin = fxmin << LOBITS;
fxmax = fxmax << LOBITS;
fzmin = fzmin << LOBITS;
fzmax = fzmax << LOBITS;
frmin = frmin << LOBITS;
frmax = frmax << LOBITS;
fgmin = fgmin << LOBITS;
fgmax = fgmax << LOBITS;
fbmin = fbmin << LOBITS;
fbmax = fbmax << LOBITS;
EdgeSetup (zspan, fzmin, fxmin, fzmax, fxmax);
EdgeSetup (rspan, frmin, fxmin, frmax, fxmax);
EdgeSetup (gspan, fgmin, fxmin, fgmax, fxmax);
EdgeSetup (bspan, fbmin, fxmin, fbmax, fxmax);
for (x = xmin + 1; x <= xmax; x ++)
{
z = zspan[1]; EdgeScan (zspan)
r = rspan[1]; EdgeScan (rspan)
g = gspan[1]; EdgeScan (gspan)
b = bspan[1]; EdgeScan (bspan)
if (localBuff[yi][x].z < z)
{
localBuff[yi][x].z = z;
localBuff[yi][x].red = r;
localBuff[yi][x].green = g;
localBuff[yi][x].blue = b;
}
} /* for all pixels on the scan line between the edges */
} /* for every scan line upto the lower 'y' of the two edges */
/*
* Setup the third edge.
*/
if (!cw)
{
EdgeSetup (left, x1, y1, x2, y2);
EdgeSetup (zleft, z1, y1, z2, y2);
EdgeSetup (rleft, r1, y1, r2, y2);
EdgeSetup (gleft, g1, y1, g2, y2);
EdgeSetup (bleft, b1, y1, b2, y2);
}
else
{
EdgeSetup (right, x1, y1, x2, y2);
EdgeSetup (zright, z1, y1, z2, y2);
EdgeSetup (rright, r1, y1, r2, y2);
EdgeSetup (gright, g1, y1, g2, y2);
EdgeSetup (bright, b1, y1, b2, y2);
}
/*
* Now scan convert the rest of the triangle.
*/
temp = max (fp_int_flr ((cw) ? y0 : y1), fp_int_flr ((cw) ? y1 : y0)) + 1;
temp1 = fp_int_flr (y2);
for (yi = temp; yi <= temp1; yi ++)
{
fxmin = left[1]; EdgeScan (left)
fxmax = right[1]; EdgeScan (right)
fzmin = zleft[1]; EdgeScan (zleft)
fzmax = zright[1]; EdgeScan (zright)
frmin = rleft[1]; EdgeScan (rleft)
frmax = rright[1]; EdgeScan (rright)
fgmin = gleft[1]; EdgeScan (gleft)
fgmax = gright[1]; EdgeScan (gright)
fbmin = bleft[1]; EdgeScan (bleft)
fbmax = bright[1]; EdgeScan (bright)
xmin = fxmin;
xmax = fxmax;
fxmin = fxmin << LOBITS;
fxmax = fxmax << LOBITS;
fzmin = fzmin << LOBITS;
fzmax = fzmax << LOBITS;
frmin = frmin << LOBITS;
frmax = frmax << LOBITS;
fgmin = fgmin << LOBITS;
fgmax = fgmax << LOBITS;
fbmin = fbmin << LOBITS;
fbmax = fbmax << LOBITS;
EdgeSetup (zspan, fzmin, fxmin, fzmax, fxmax);
EdgeSetup (rspan, frmin, fxmin, frmax, fxmax);
EdgeSetup (gspan, fgmin, fxmin, fgmax, fxmax);
EdgeSetup (bspan, fbmin, fxmin, fbmax, fxmax);
for (x = xmin + 1; x <= xmax; x ++)
{
z = zspan[1]; EdgeScan (zspan)
r = rspan[1]; EdgeScan (rspan)
g = gspan[1]; EdgeScan (gspan)
b = bspan[1]; EdgeScan (bspan)
if (localBuff[yi][x].z < z)
{
localBuff[yi][x].z = z;
localBuff[yi][x].red = r;
localBuff[yi][x].green = g;
localBuff[yi][x].blue = b;
}
} /* for every pixel on scan line b/w the left and right edges */
} /* for every scan line till the uppermost vertex of the triangle */
} /* rasterize_sorted_triangle */
/*
* Rasterizes a triangle. It first orients the triangle edges so that
* vertex 0 is lower that vertex 1 which in turn is lower than vertex 2.
*/
void rasterizeTriangle (FrameBuffer localBuff, InDataSet tp)
{
int minv = 0, midv = 1, maxv = 2, tmp = 0;
if ((tp->vertices[minv]).vertex[Y] >
(tp->vertices[midv]).vertex[Y])
{
TSWAP (minv, midv, tmp);
}
if ((tp->vertices[minv]).vertex[Y] >
(tp->vertices[maxv]).vertex[Y])
{
TSWAP (minv, maxv, tmp);
}
if ((tp->vertices[midv]).vertex[Y] >
(tp->vertices[maxv]).vertex[Y])
{
TSWAP (midv, maxv, tmp);
}
rasterize_sorted_triangle (minv, midv, maxv, tp, localBuff);
} /* rasterizeTriangle */
/*
* The function rasterizes a set of triangles one at a time.
*/
void Rasterize (InDataSet localSet, int count, FrameBuffer localBuff)
{
int i;
for (i = 0; i < count; i ++)
{
rasterizeTriangle (localBuff, &localSet[i]);
}
} /* Rasterize */
/*
* Function to Shade the Triangle Vertices.
*/
void Lighting (InDataSet localSet,int *datasizep,
double Iar, double Iag, double Iab,
double Kar, double Kdr, double Kag,
double Kdg, double Kab, double Kdb,
double c1, double c2,
int num_lights, Lights lights)
{
int i = 0, j = 0, k = 0;
MAT3vec temp1;
double dist, r = 0.0, g = 0.0, b = 0.0;
double tmp2r, tmp2g, tmp2b ;
tmp2r = Iar * Kar * MAX_INTENSITY / (num_lights + 1);
tmp2g = Iag * Kag * MAX_INTENSITY / (num_lights + 1);
tmp2b = Iab * Kab * MAX_INTENSITY / (num_lights + 1);
for (k=0; k < num_lights; k++) {
lights[k].red *= Kdr * MAX_INTENSITY / (num_lights+1);
lights[k].green *= Kdg * MAX_INTENSITY / (num_lights+1);
lights[k].blue *= Kdb * MAX_INTENSITY / (num_lights+1);
}
for(i = 0; i < (*datasizep); i++)
{
for (j = 0; j < 3; j++)
{
r = tmp2r; g = tmp2g; b = tmp2b;
for (k = 0; k < num_lights; k++)
{
sub_vec (temp1, lights[k].location,
localSet[i].vertices[j].vertex)
dist = sqrt (temp1[X]*temp1[X] +
temp1[Y]*temp1[Y] +
temp1[Z]*temp1[Z]);
dist = 1 / dist * (1 + c1*dist + c2*dist*dist);
r += ZFABS (lights[k].red * dist *
dot_product (temp1, localSet[i].vertices[j].normal));
g += ZFABS (lights[k].green * dist *
dot_product (temp1, localSet[i].vertices[j].normal));
b += ZFABS (lights[k].blue * dist *
dot_product (temp1, localSet[i].vertices[j].normal));
} /* for k */
localSet[i].vertices[j].red = fp_fix(r);
localSet[i].vertices[j].green = fp_fix(g);
localSet[i].vertices[j].blue = fp_fix(b);
} /* for j */
} /* for i */
} /* Lighting */
void main(int argc, char **argv)
{
int i, j, datasize, num_lights;
InDataSet localSet;
Point vrp, prp;
MAT3vec vpn, vupv;
double fplane, bplane,
umin, umax, vmin, vmax;
MAT3mat vo_matrix, vm_matrix, transform;
MtlProp activeProp;
FrameBuffer localBuff;
Lights lights;
BackGroundColor backgndcolor;
clock_t tm1, tm2;
localSet = (InDataSet) calloc (1, NUM_TRIANGLES * sizeof (Triangle));
lights = (Lights) calloc (1, NUM_LIGHT_SOURCES * sizeof (LightPoint));
readNFFFile (argv[1], localSet,
vrp, vpn, vupv,
prp, &fplane, &bplane,
&umin, &umax, &vmin, &vmax,
lights, &backgndcolor,
&datasize, &activeProp, &num_lights);
#ifdef PRINTVIEWINGVALS
fprintf (stderr, "Number of triangles: %d\n", datasize);
fprintf (stderr, "Vrp : %lf %lf %lf\n",
vrp[0], vrp[1], vrp[2]);
fprintf (stderr, "Vpn : %lf %lf %lf\n",
vpn[0], vpn[1], vpn[2]);
fprintf (stderr, "Vupv : %lf %lf %lf\n",
vupv[0], vupv[1], vupv[2]);
fprintf (stderr, "prp : %lf %lf %lf\n",
prp[0], prp[1], prp[2]);
fprintf (stderr, "fplane : %lf\n", fplane);
fprintf (stderr, "bplane : %lf\n", bplane);
fprintf (stderr, "umin, umax : %lf %lf\n",
umin, umax);
fprintf (stderr, "vmin, vmax : %lf %lf\n",
vmin, vmax);
#endif /* PRINTVIEWINGVALS */
for (i=0; i < WINDOW_HEIGHT; i++)
{
for (j=0; j < WINDOW_WIDTH; j++)
{
localBuff[i][j].red = backgndcolor.red;
localBuff[i][j].green = backgndcolor.green;
localBuff[i][j].blue = backgndcolor.blue;
}
}
evaluateViewOrientationMatrix (vrp, vpn, vupv, vo_matrix);
evaluateViewMappingMatrix (umin, umax, vmin, vmax,
prp, fplane, bplane, vm_matrix);
MAT3mult (transform, vm_matrix, vo_matrix);
tm1 = clock ();
Lighting (localSet, &datasize,
activeProp.red, activeProp.green, activeProp.blue,
activeProp.ambientK, activeProp.diffuseK,
activeProp.ambientK, activeProp.diffuseK,
activeProp.ambientK, activeProp.diffuseK,
activeProp.c1, activeProp.c2, num_lights, lights);
tm2 = clock ();
printf ("Lighting took %f secs.\n",
(double) (tm2-tm1)/CLOCKS_PER_SEC);
tm1 = clock ();
viewTrans_DivByW_DevTrans (localSet, datasize, transform);
tm2 = clock ();
printf ("Transformation took %f secs.\n",
(double)(tm2-tm1)/CLOCKS_PER_SEC);
tm1 = clock ();
Rasterize (localSet, datasize, localBuff);
tm2 = clock ();
printf ("Rasterize took %f secs\n",(double) (tm2-tm1)/CLOCKS_PER_SEC);
write_tga_buffer (localBuff, (argc > 2) ? argv[2] : DEFAULTOUT);
free ((char *) localSet);
free ((char *) lights);
} /* main */