Graphics source in C: hsalgs/ftb_zsort.c
Ken Turkowski
ken at turtleva.UUCP
Fri Dec 16 13:10:35 AEST 1983
echo x - hsalgs/ftb_zsort.c
cat >hsalgs/ftb_zsort.c <<'!Funky!Stuff!'
/* --------------------------------------------------------------
Clip, sort and display objects in the standard binary format
- Sort is front-to-back based only on closest vertex.
Therefore, objects must be made of consistently-sized
surface elements which do not intersect.
input format is defined in "man hsalg_input"
---------------------------------------------------------------
*/
/* #include <ctype.h> */
#include <stdio.h>
#define TRUE 1
#define FALSE 0
#define NULLCHAR '\0'
#define DtoR 3.14159 / 180.
#define sqr(x) ((x)*(x))
#define DET_CODE 0x20746564
#define PCL_CODE 0x206C6370
#define VCL_CODE 0x206C6376
#define TXC_CODE 0x20637874
#define TXTR_CODE 0x72747874
#define IN 0
#define OUTLFT 1
#define OUTRGT 2
#define OUTTOP 4
#define OUTBOT 8
#define OUTHTR 16
#define SUBPIX .01 /* minimum detail size */
#define HRES 640
#define ZRES 1023.
#define SORTRES 1024
#define MAXPTS 2048 /* must be <= 32768 indexed by shorts */
#define MAXPOLYS 2048 /* " */
#define MAXFRNTFC 1024 /* must be <= 16384 (packed with 65535) */
#define MAXVTCES 8192 /* must be <= 65536 */
#define MAXLTS 16 /* maximum number of light sources */
#define MAXOBJ 2 /* maximum number of objects */
#define MAXPTS_POLY 64 /* maximum number of points defining a polygon */
#define HILIT_MIN .02 /* minimum noticeable highlight intensity */
#define TRANS_MIN .02 /* minimum noticeable transmittance */
#define LINE_LENGTH 160
#define X 0
#define Y 1
#define Z 2
#define R 3
#define G 4
#define B 5
#define T 6
#define XN 7
#define YN 8
#define ZN 9
#define TX_X 10
#define TX_Y 11
#define NORMS 12 /* array position where normals begin */
#define NORM_PARMS 6 /* number of parameters per normal */
/* maximum polygon array size */
#define POLYSIZE MAXPTS_POLY * (NORMS + NORM_PARMS*MAXLTS)
#define TX_RES 128 /* texture image resolution */
/* global variables for pixel output routine */
short num_lights,hilit_power,txtr,object;
struct { short r,g,b,t,s; } texture[MAXOBJ][TX_RES][TX_RES];
static double ambnt,ambntcomp; /* lighting specifications */
static double view_angle,cot_x,cot_y;
static short nbr_lights;
static struct {float x,y,z,r,g,b,range;} lights[MAXLTS];
static short objnum,clipping[MAXOBJ],faceted[MAXOBJ], /* object info */
backfaces[MAXOBJ],vertex_clrs[MAXOBJ],poly_clrs[MAXOBJ],
poly_txtr[MAXOBJ];
static double clrred[MAXOBJ],clrgrn[MAXOBJ],clrblu[MAXOBJ],
trnsmtnce[MAXOBJ],trns_pwr[MAXOBJ],hilit_exp[MAXOBJ];
static struct {float x,y,z;} pts[MAXPTS],norms[MAXPTS];
static struct {float r,g,b,t;} pclrs[MAXPTS],vclrs[MAXVTCES];
static struct {float x,y;} tx_coords[MAXVTCES]; /* texture coords at vertices */
static short npts,npolys,tpts,tpolys,nvtces,tvtces;
static double zmax,zmin;
static short cnt[MAXPTS],vtces[MAXVTCES];
static short bfacing[MAXPOLYS],clp[MAXPOLYS],obj_no[MAXPOLYS];
static double matrix[16]; /* current object transform matrix */
extern void ftb_pxls(),hiq_pxls(); /* pixel calculation routines */
/* +++++++++++++++++++++++++ MAIN +++++++++++++++++++++++++++++++++++++++++ */
main()
{
struct list_entry { short ply; long vtx; long ptr; };
static struct list_entry polsort[MAXFRNTFC],*buckets[SORTRES];
char instrg[LINE_LENGTH],keywd[LINE_LENGTH],remainder[LINE_LENGTH],dvc[3];
short first_obj,ltop,i,bits,divisions,frmnum;
long ivtx;
double zscale,atof(),sqrt(),fabs();
nocore(); /* prevent core dumps on errors */
objnum = 0; first_obj = TRUE;
tpts = 0; tpolys = 0; tvtces = 0; /* init pts and poly cnts */
zmax = 0.0; zmin = ZRES; /* initialize for depth range */
ambnt = .3; ambntcomp = .7; nbr_lights = 0;/* lighting initialization */
/* scan input for keywords */
while ( gets(instrg) != NULL )
{ if (strlen(instrg) > LINE_LENGTH) error("input line too long");
get_term(instrg,keywd,remainder); /* get keyword from input */
if (strcmp(keywd,"device") == 0) /* get display device */
{ sscanf(remainder,"%s %hd %hd %hd",dvc,&bits,&divisions,&frmnum);
if ((strcmp(dvc,"bb") == 0) && (bits >= 24))
u_tilinit(divisions,frmnum);
else error("(ftb_zsort) only 32-bit pixels allowed");
}
else if ( strcmp(keywd,"light") == 0 ) /* get light source info */
{ sscanf(remainder,"%f%f%f%f%f%f%f",
&lights[nbr_lights].x,&lights[nbr_lights].y,&lights[nbr_lights].z,
&lights[nbr_lights].r,&lights[nbr_lights].g,&lights[nbr_lights].b,
&lights[nbr_lights].range);
if ((lights[nbr_lights].r + lights[nbr_lights].g +
lights[nbr_lights].b) <= 0.)
lights[nbr_lights].r = lights[nbr_lights].g =
lights[nbr_lights].b = 1.;
/* NOTE! all other shading factors 0.-1. (used to scale up) */
lights[nbr_lights].r *= 255.; lights[nbr_lights].g *= 255.;
lights[nbr_lights].b *= 255.;
nbr_lights++;
}
else if ( strcmp(keywd,"ambient_light") == 0 ) /* get ambient light */
{ sscanf(remainder,"%f",&ambnt);
ambntcomp = 1.0 - ambnt;
}
else if ( strcmp(keywd,"object") == 0 ) /* get an object file */
{ if (!first_obj) /* transform, etc. last object */
{ prepare_obj(objnum); objnum++; }
npts = 0; npolys = 0; nvtces = 0; first_obj = FALSE;
clrred[objnum] = clrgrn[objnum] = clrblu[objnum] = 1.;/* defaults */
getobject(remainder,&npts,&pts[tpts],&npolys,&nvtces,&vtces[tvtces]);
clipping[objnum] = TRUE;
}
else if ( strcmp(keywd,"view_angle") == 0 ) /* get view angle */
{ double cos(),sin();
sscanf(remainder,"%f",&view_angle);
cot_x = cos(DtoR * view_angle/2.) / sin(DtoR * view_angle/2.);
cot_y = cot_x / .75;
if ((strcmp(dvc,"fb") == 0) || (strcmp(dvc,"aed") == 0))
cot_y *= 640./512.; /* adjust for pixel distortion on 512x484 */
}
else if (strcmp(keywd,"color") == 0 ) /* get object color */
{ sscanf(remainder,"%F%F%F%F",&clrred[objnum],
&clrgrn[objnum],&clrblu[objnum]);
}
else if ( strcmp(keywd,"transform") == 0 ) /* get eyespace transform */
for (i=0; i<16; i+=4) sscanf(gets(instrg),"%F%F%F%F",&matrix[i],
&matrix[i+1],&matrix[i+2],&matrix[i+3]);
else if ( strcmp(keywd,"no_clipping") == 0 ) /* need clipping? */
clipping[objnum] = FALSE;
else fprintf(stderr,"bad keyword to ftb_zsort - %s\n",instrg);
}
prepare_obj(objnum); /* transform, etc. last object */
/* ------------ get transform for z-coordinates --------------------- */
if (zmin < 0.0) zmin = 0.0;
zscale = (zmax - zmin > 0)? ZRES / (zmax - zmin) : ZRES;
/* ------ run through polygons, if not rejected, find closest vertex
and put pointer in appropriate bucket list ------------------ */
ivtx = 0; ltop = 0; for (i=0; i<SORTRES; i++) buckets[i]=0;
for (i=0; i<tpolys; i++)
{ short j,jmin,size; long k; float min,depth;
size = vtces[ivtx++];
if ((clp[i] >= 0) && (!bfacing[i] || backfaces[obj_no[i]]))/*rejected?*/
{ min = ZRES;
for (k=ivtx; k<ivtx+size; k++) /* find closest vertex */
{ j = vtces[k];
depth = (pts[j].z - zmin) * zscale;
if (depth < min) min = depth;
}
jmin = (min < 0.0)? 0.0 : min;
polsort[ltop].ply = i; /* enter in sort bucket */
polsort[ltop].vtx = ivtx-1;
polsort[ltop].ptr = (long)buckets[jmin];
buckets[jmin] = &polsort[ltop++];
if (ltop > MAXFRNTFC)
{ fprintf(stderr,"(ftb_zsort) excess displayable polys!! %d > MAXFRNTFC\n",
ltop);
ltop--;
}
}
ivtx += size;
}
/* -------- pick up polys in depth order, send to tiler ------------ */
for (i=0; i<SORTRES; i++)
{ if (buckets[i] > 0)
{ double poly[POLYSIZE],poly2[POLYSIZE];
struct list_entry *pntr;
short k,l,m,obj,polptr,sign,npts,npars; long j;
double hilite,trnsp;
pntr = (struct list_entry *)buckets[i];
while (pntr > 0)
{ polptr = pntr->ply;
obj = obj_no[polptr];
j = pntr->vtx;
npts = vtces[j++];
sign = bfacing[polptr]? -1 : 1; /* reverse nrmls if bckfcng */
k = 0;
for (l=0; l<npts; l++) /* copy polygon */
{ m = vtces[j];
poly[k+X] = pts[m].x;
poly[k+Y] = pts[m].y;
poly[k+Z] = pts[m].z;
poly[k+R] = clrred[obj]; /* object color */
poly[k+G] = clrgrn[obj];
poly[k+B] = clrblu[obj];
poly[k+T] = trnsmtnce[obj];
if (vertex_clrs[obj]) /* color per vertex */
{ poly[k+R] *= vclrs[m].r * clrred[obj];
poly[k+G] *= vclrs[m].g * clrgrn[obj];
poly[k+B] *= vclrs[m].b * clrblu[obj];
poly[k+T] *= vclrs[m].t * trnsmtnce[obj]; }
if (poly_clrs[obj]) /* color per polygon */
{ poly[k+R] *= pclrs[polptr].r * clrred[obj];
poly[k+G] *= pclrs[polptr].g * clrgrn[obj];
poly[k+B] *= pclrs[polptr].b * clrblu[obj];
poly[k+T] *= pclrs[polptr].t * trnsmtnce[obj]; }
if (poly_txtr[obj]) /* load texture parameters */
{ poly[k+TX_X] = tx_coords[j].x;
poly[k+TX_Y] = tx_coords[j].y;
}
if (!faceted[obj]) /* smooth shading */
{ poly[k+XN] = sign * norms[m].x;
poly[k+YN] = sign * norms[m].y;
poly[k+ZN] = sign * norms[m].z;
}
k += NORMS; j++; /* increment vertex pointer */
}
if (faceted[obj])/* get normal vector for polygon, if faceted */
{ struct { float x,y,z; } vec;
X_prod(&vec,pts[vtces[j-3]],pts[vtces[j-2]],pts[vtces[j-1]]);
for (k=0; k<npts*NORMS; k+=NORMS)
{ poly[k+XN] = sign * vec.x; /* faceted shading */
poly[k+YN] = sign * vec.y;
poly[k+ZN] = sign * vec.z; }
}
hilite = hilit_exp[obj]; trnsp = trns_pwr[obj];
get_shades(npts,poly,&hilite,&trnsp,&num_lights); /* shading */
hilit_power = hilite; /* > 0 if highlight in poly */
npars = NORMS + NORM_PARMS*num_lights; /*parameters per vertex*/
if (poly_txtr[obj]) { txtr = TRUE; object = obj; }
else txtr = FALSE;
for (k=0; k<npts*npars; k+=npars) /* predistort for clipping */
{ poly[k+X] *= cot_x; poly[k+Y] *= cot_y; }
if (clp[polptr] > 0) /* clip */
polclp(0,&npts,poly,poly2,npars);
if (npts > 2)
{ for (k=0; k<npts*npars; k+=npars) /* take to screen space */
{ poly[k+X] /= poly[k+Z]; poly[k+Y] /= poly[k+Z]; }
/* scan convert */
if (hilite) hiq_tiler(npts,poly,npars,hiq_pxls);
else u_tiler(npts,poly,npars,ftb_pxls);
}
pntr = (struct list_entry *)pntr->ptr;/* get next list elmnt */
} /* done with one linked list */
}
} /* done with outputting sorted list */
} /* done with main program */
/* ++++++++++++++++++++++++ GETCOLORS ++++++++++++++++++++++++++++++++++++ */
getcolors(instrg,objpts,pts) /* read in color file */
char *instrg; short objpts;
struct { float r,g,b,t; } pts[];
{ short i,npts; long code; FILE *input; char fname[LINE_LENGTH];
get_term(instrg,fname,instrg); /* strip leading and trailing blanks */
input = fopen(fname,"r");
if (input == NULL)
{ fprintf(stderr,"(getcolors) unable to open %s for input\n",fname);
return;
}
fread(&code,4,1,input);
if ((code != VCL_CODE) && (code != PCL_CODE))
{ fprintf(stderr,"warning!! %s not tagged as color file\n",fname);
close(input); input = fopen(fname,"r");/* replace with return */
}
fread(&npts,2,1,input);
if (npts > MAXPTS)
{ fprintf(stderr," (getcolors) object too big!! %d > %d\n",npts,MAXPTS); return; }
fread(pts,4,npts*4,input);
fclose(input);
if (npts < objpts) for (i=npts; i<objpts; i++)
pts[i].r = pts[i].g = pts[i].b = pts[i].t = 1.;
}
/* +++++++++++++++++++++++ GET_TEXTURE ++++++++++++++++++++++++++++++++++ */
get_texture(instrg,texture,tx_coords) /* read texture image */
char *instrg; struct { short r,g,b,t,s; } texture[TX_RES][TX_RES];
struct { float x,y; } tx_coords[];
{ FILE *input; short i,j,npolys,size; long code; char fname[LINE_LENGTH];
get_term(instrg,fname,instrg); /* texture coordinate filename */
input = fopen(fname,"r");
if (input == NULL) error("(get_texture) unable to open %s for input",fname);
j = 0;
fread(&code,4,1,input);
if (code != TXC_CODE)
{ fprintf(stderr," %s not tagged as texture coordinate file\n",fname);
close(input); return;
}
fread(&npolys,2,1,input); /* get number of polys */
for (i=0; i<npolys; i++)
{ short num;
fread(&num,2,1,input);
tx_coords[j++].x = num;
if ((fread(&tx_coords[j],4,num*2,input) < num) || (num < 3))
{ fprintf(stderr,"(ftb_zsort) bad polygon # %d in %s\n",fname);
j--; continue; }
j += num;
}
fclose(input);
get_term(instrg,fname,instrg); /* texture image filename */
input = fopen(fname,"r");
if (input == NULL) error("(get_texture) unable to open %s for input",fname);
fread(&code,4,1,input);
if (code != TXTR_CODE)
{ fprintf(stderr,"warning!! %s not tagged as texture file\n",fname);
close(input); return;
}
/* fread(&size,2,1,input); /* texture image resolution */
fread(texture,2,TX_RES*TX_RES*5,input); /* dump file into array */
fclose(input);
}
/* ++++++++++++++++++++++++ GETOBJECT ++++++++++++++++++++++++++++++++++++ */
getobject(instrg,npts,pts,npolys,nvtces,vtces)/* read in object file */
char *instrg; short *npts,*npolys,*nvtces,vtces[];
struct { float x,y,z; } pts[];
{ FILE *input; short i; long j,code;
char fname[LINE_LENGTH],line[LINE_LENGTH],detail_file[LINE_LENGTH];
get_term(instrg,fname,instrg); /* strip leading and trailing blanks */
input = fopen(fname,"r");
if (input == NULL)
{ fprintf(stderr,"(ftb_zsort) unable to open %s for input\n",fname);
return; }
detail_file[0] = NULLCHAR; /* nullify detail filename */
while (fgets(line,LINE_LENGTH,input) != NULL)
{ char term[LINE_LENGTH];
get_term(line,term,line); /* get keyword */
if (strcmp(term,"detail") == 0)
get_term(line,detail_file,line);
else if (strcmp(term,"poly_colors") == 0)
{ if (!vertex_clrs[objnum])
{ poly_clrs[objnum] = TRUE;
getcolors(line,npolys,&pclrs[tpolys]);
}
}
else if (strcmp(term,"vertex_colors") == 0)
{ if (!poly_clrs[objnum])
{ vertex_clrs[objnum] = TRUE;
getcolors(line,npolys,&vclrs[tpts]);
}
}
else if ( strcmp(term,"texture") == 0 ) /* texture coords & image */
{ get_texture(line,texture[objnum],&tx_coords[tpolys]);
poly_txtr[objnum] = TRUE;
}
else if (strcmp(term,"type") == 0)
{ get_term(line,term,line);
if (strcmp(term,"polygon") == 0)
while(strlen(line) > 4)
{ get_term(line,term,line);
if (strcmp(term,"open") == 0)
backfaces[objnum] = TRUE;
else if (strcmp(term,"faceted") == 0)
faceted[objnum] = TRUE;
}
}
else if (strcmp(term,"color") == 0)
sscanf(line,"%F%F%F",&clrred[objnum],&clrgrn[objnum],
&clrblu[objnum]);
else if (strcmp(term,"transmittance") == 0)
{ sscanf(line,"%F%F",&trnsmtnce[objnum],&trns_pwr[objnum]);
if (trns_pwr[objnum] <= 0.) trns_pwr[objnum] = 1.;
}
else if (strcmp(term,"shininess") == 0)
sscanf(line,"%F",&hilit_exp[objnum]);
}
fclose(input); /* close ".obj" file and open detail file */
input = fopen(detail_file,"r");
if (input == NULL)
error("poly_zsort: can't open detail file %s\n",detail_file);
fread(&code,4,1,input); /* read file type header */
if (code != DET_CODE)
{ fprintf(stderr,"poly_zsort: %s not tagged detail file\n",detail_file);
close(input); return; /* not detail file, give up */
}
fread(npts,2,1,input); fread(npolys,2,1,input);
if ((*npts > MAXPTS) || (*npolys > MAXPOLYS))
{ fprintf(stderr,
" (poly_zsort) object too big!! %d > MAXPTS or %d > MAXPOLYS\n",
*npts,*npolys);
*npts = 0; *npolys = 0; return;
}
fread(pts,4,(*npts)*3,input);
j = 0;
for (i=0; i<*npolys; i++)
{ short num; long k;
fread(&num,2,1,input);
vtces[j++] = num;
if ((fread(&vtces[j],2,num,input) < num) || (num < 3))
{ fprintf(stderr," (poly_zsort) - bad polygon # %d in %s\n",i,fname);
j--; continue;
}
/* offset pointers to point at vertices for right object */
for (k=j; k<j+num; k++) vtces[k] += tpts - 1; /*-1 so ptrs strt at 0*/
j += num;
}
*nvtces = j;
fclose(input);
}
/* ++++++++++++++++++++++ GET_SHADES +++++++++++++++++++++++++++++++++++++++ */
get_shades(npts,poly,hilit,trnsp,nlts)/* get shades, chck on hilit */
short npts,*nlts; double *hilit,*trnsp;
double poly[];
{ short i,j;
double sqrt(),pow(),fabs(),
trans_max,xmax[MAXLTS],ymax[MAXLTS],xmin[MAXLTS],ymin[MAXLTS];
struct { double xn,yn,zn,r,g,b; } hl_nms[MAXPTS_POLY][MAXLTS];
trans_max = 0; /* maximum transparency for polygon */
for (i=0; i<npts; i++)
{ short k; double norm_mag,dot_prod,red,grn,blu;
k = i * NORMS;
norm_mag = sqrt(sqr(poly[k+XN]) + sqr(poly[k+YN]) + sqr(poly[k+ZN]));
if (norm_mag <= 0)
{ fprintf(stderr,"(get_shades) null normal vector"); norm_mag = 1; }
if (*trnsp > 0.) /* get transmittance at vertex */
{ double eye_mag,cosang;
eye_mag = sqrt(sqr(poly[k+X]) + sqr(poly[k+Y]) + sqr(poly[k+Z]));
cosang = (-poly[k+X] * poly[k+XN] - poly[k+Y] * poly[k+YN]
- poly[k+Z] * poly[k+ZN]) / (eye_mag * norm_mag);
poly[k+T] *= pow(cosang,*trnsp);
if (poly[k+T] > trans_max) trans_max = poly[k+T];
}
red = grn = blu = 0;
for (j=0; j<nbr_lights; j++) /* do for each light source */
{ double lx,ly,lz,lit_dst,atten;
lx = lights[j].x - poly[k+X];
ly = lights[j].y - poly[k+Y];
lz = lights[j].z - poly[k+Z];
lit_dst = sqrt(sqr(lx) + sqr(ly) + sqr(lz)); /* dist. from lite */
atten = 1.0 - lit_dst/lights[j].range;
atten = (atten > 0.)? sqr(atten) : 0.; /* distance attenuation */
dot_prod = (poly[k+XN]*lx + poly[k+YN]*ly + poly[k+ZN]*lz) /
(norm_mag * lit_dst);
if (dot_prod < 0.0) dot_prod = 0.0;
dot_prod = dot_prod*ambntcomp + ambnt; /* ambient light */
red += poly[k+R] * dot_prod * lights[j].r * atten;
grn += poly[k+G] * dot_prod * lights[j].g * atten;
blu += poly[k+B] * dot_prod * lights[j].b * atten;
if (*hilit > 0.) /* get reflection vector if hilite possible */
{ get_vec(lx,ly,lz,lit_dst,&poly[k],&hl_nms[i][j]);
if (i == 0) /* first vertex, set up for min-max tests */
{ xmax[j] = xmin[j] = hl_nms[i][j].xn;
ymax[j] = ymin[j] = hl_nms[i][j].yn; }
else /* min-max tests for bounding box on highlight */
{ if (hl_nms[i][j].xn > xmax[j]) xmax[j] = hl_nms[i][j].xn;
else if (hl_nms[i][j].xn < xmin[j]) xmin[j] = hl_nms[i][j].xn;
if (hl_nms[i][j].yn > ymax[j]) ymax[j] = hl_nms[i][j].yn;
else if (hl_nms[i][j].yn < ymin[j]) ymin[j] = hl_nms[i][j].yn;
}
}
}
{ double fac;
fac = 255.; /* attenuate overflowing colors */
if (red > fac) fac = red;
if (grn > fac) fac = grn;
if (blu > fac) fac = blu;
fac = 255./fac;
poly[k+R] = red*fac; poly[k+G] = grn*fac; poly[k+B] = blu*fac;
}
}
*nlts = 0; /* count number of lights which cause highlights in this poly */
if (*hilit > 0.) for (j=0; j<nbr_lights; j++)
{ short k;
xmin[j] = (xmax[j]*xmin[j] < 0.)? 0. :
((fabs(xmin[j]) < fabs(xmax[j]))? xmin[j] : xmax[j]);
ymin[j] = (ymax[j]*ymin[j] < 0.)? 0. :
((fabs(ymin[j]) < fabs(ymax[j]))? ymin[j] : ymax[j]);
if (pow(1. - sqr(xmin[j]) - sqr(ymin[j]),*hilit) > HILIT_MIN)
{ if (*nlts != j) for (k=0; k<npts; k++)/* highlight!, store normal */
{ hl_nms[k][*nlts].xn = hl_nms[k][j].xn;
hl_nms[k][*nlts].yn = hl_nms[k][j].yn;
hl_nms[k][*nlts].zn = hl_nms[k][j].zn;
}
hl_nms[0][*nlts].r = lights[j].r; /* store light source color */
hl_nms[0][*nlts].g = lights[j].g;
hl_nms[0][*nlts].b = lights[j].b;
(*nlts)++;
}
}
if ((*nlts) == 0) *hilit = 0.; /* zero highlight power if no highlights */
if (trans_max < TRANS_MIN) *trnsp = 0.; /* is max. trnsmttnce noticeable? */
if (*hilit) for (i=npts-1; i>=0; i--) /* copy highlight info into poly */
{ short j,k,l;
k = i * (NORMS + NORM_PARMS*(*nlts)); /* new vertex ptr in poly array */
l = i * NORMS; /* old vertex pointer */
for (j=NORMS-1; j>=0; j--) poly[k+j] = poly[l+j];
for (j=0; j<(*nlts); j++)
{ l = k + NORMS + NORM_PARMS*j;
poly[l+X] = hl_nms[i][j].xn;
poly[l+Y] = hl_nms[i][j].yn;
poly[l+Z] = hl_nms[i][j].zn;
poly[l+R] = hl_nms[0][j].r;
poly[l+G] = hl_nms[0][j].g;
poly[l+B] = hl_nms[0][j].b;
}
}
}
/* +++++++++++++++++++++ GET_TERM +++++++++++++++++++++++++++++++++ */
get_term(instrg,term,remainder) /* remove first term from string */
char *instrg,*term,*remainder; /* blanks, tabs, nulls, commas are separators */
{ short i,index1,index2;
index1 = 0; /* find first non-separator */
while ((instrg[index1] == ' ') || (instrg[index1] == '\t') ||
(instrg[index1] == NULLCHAR) || (instrg[index1] == ',' )) index1++;
index2 = index1; /* find next separator */
while ((instrg[index2] != ' ') && (instrg[index2] != '\t') &&
(instrg[index2] != NULLCHAR) && (instrg[index2] != ',' ) &&
(instrg[index2] != '\n')) index2++;
for (i=index1; i<index2; i++) term[i-index1] = instrg[i];
term[i-index1] = NULLCHAR;
while ((instrg[i] != NULLCHAR) && (instrg[i] != '\n'))
{ remainder[i-index2] = instrg[i]; i++; }
remainder[i-index2] = NULLCHAR;
}
/* ++++++++++++++++++++++++++++ GET_VEC ++++++++++++++++++++++++++++++++++ */
get_vec(lx,ly,lz,lit_dst,vtx,nrml) /* get vector in ideal reflection space */
double lx,ly,lz,lit_dst,vtx[];
struct { double xn,yn,zn,r,g,b; } *nrml;
{ double eye_mag,rflx,rfly,rflz,cosa,sina,hypota,cosb,sinb,hypotb,
tx,ty,tz,tm,sqrt();
eye_mag = sqrt(sqr(vtx[X]) + sqr(vtx[Y]) + sqr(vtx[Z]));
rflx = (lx/lit_dst - vtx[X]/eye_mag) / 2; /* get half-angle vector */
rfly = (ly/lit_dst - vtx[Y]/eye_mag) / 2; /* represents normal at */
rflz = (lz/lit_dst - vtx[Z]/eye_mag) / 2; /* middle of highlight */
/* rotate normal into space in which half-angle vector is on z-axis */
hypota = sqrt(sqr(rflx) + sqr(rflz));
cosa = rflz / hypota; sina = rflx / hypota;
hypotb = sqrt(sqr(rfly) + sqr(hypota));
cosb = hypota / hypotb; sinb = rfly / hypotb;
tx = cosa * vtx[XN] - sina * vtx[ZN]; /* rotate about y */
ty = vtx[YN];
tz = sina * vtx[XN] + cosa * vtx[ZN];
nrml->xn = tx; /* rotate about x */
nrml->yn = cosb * ty - sinb * tz;
nrml->zn = sinb * ty + cosb * tz;
tm = sqrt(sqr(vtx[XN]) + sqr(vtx[YN]) + sqr(vtx[ZN]));
nrml->xn /= tm; nrml->yn /= tm; nrml->zn /= tm; /* normalize */
}
/* +++++++++++++++++++++++++++++ POLCLP +++++++++++++++++++++++++++++++++++++ */
polclp(pass,npts,pts,pt2,npars) /* polygon clipper (eyespace) */
short *npts,pass,npars; double pts[],pt2[];
{ short i,lk,m; float dist,last_dist;
if ((pass == 4) || (*npts < 3)) return; /* completion conditions */
last_dist = 0.0; m = 0; lk = 0;
for (i=0; i<=*npts; i++)
{ short k,l;
k = (i == *npts) ? 0 : i*npars;
switch (pass)
{ case 0: { dist = pts[k+Z]+pts[k+X]; break; } /* left side */
case 1: { dist = pts[k+Z]-pts[k+X]; break; } /* right side */
case 2: { dist = pts[k+Z]+pts[k+X]; break; } /* bottom */
case 3: { dist = pts[k+Z]-pts[k+X]; break; } /* top */
}
if (i == 0) { last_dist = dist; lk = k; continue; } /* 1st pnt? */
if (last_dist * dist < 0.0) /* put out point if clip plane crossed */
{ float t,t1;
t = dist / (dist - last_dist); t1 = 1.0 - t;
for (l=0; l<npars; l++) pt2[m+l] = pts[k+l] * t1 + pts[lk+l] * t;
m += npars;
}
if (dist >= 0.0) /* copy point if inside */
{ for (l=0; l<npars; l++) pt2[m+l] = pts[k+l];
m += npars;
}
lk = k; last_dist = dist;
} /* recurse for next plane */
*npts = m/npars; polclp(++pass,npts,pt2,pts,npars);
}
/* ++++++++++++++++++++++ PREPARE_OBJ ++++++++++++++++++++++++++++++++++ */
prepare_obj(objnum) /* transform vertices, compute normals, etc. */
short objnum;
{ short i;
/* ----- run through points, transform, find max and min in z ----- */
for (i=tpts; i<tpts+npts; i++)
{ transform(&pts[i],matrix,&pts[i]);
if (pts[i].z > zmax) zmax = pts[i].z;
else if (pts[i].z < zmin) zmin = pts[i].z;
cnt[i] = IN; /* set clip code */
norms[i].x = 0; norms[i].y = 0; norms[i].z = 0; /* init. normals */
}
if (clipping[objnum]) for (i=tpts; i<tpts+npts; i++) /* tag if clipping */
{ if ( pts[i].z < 0.0) cnt[i] |= OUTHTR;
if ((pts[i].x)*cot_x < -pts[i].z) cnt[i] |= OUTLFT;
if ((pts[i].x)*cot_x > pts[i].z) cnt[i] |= OUTRGT;
if ((pts[i].y)*cot_y < -pts[i].z) cnt[i] |= OUTBOT;
if ((pts[i].y)*cot_y > pts[i].z) cnt[i] |= OUTTOP;
}
/* ------------- run through polygons, check backfacing,
sum normals at vertices of frontfacing polys,
and do trivial reject/accept clip --------------- */
{ short in,out; long ivtx;
ivtx = tvtces; in = out = 0;
for (i=tpolys; i<tpolys+npolys; i++)
{ struct { float x,y,z; } vec; short size; long j;
size = vtces[ivtx++];
if (clipping[objnum]) /* trivial clip test if clipping */
{ out = 0; in = 0;
for (j=ivtx; j<ivtx+size; j++)
{ out &= cnt[vtces[j]]; in |= cnt[vtces[j]]; }
}
if (out) clp[i] = -out; /* trivial rejection, skip this one */
else
{ clp[i] = in; /* store code for trivial acceptance */
obj_no[i] = objnum; /* tag with object ID for shading */
j = ivtx; /* get normal vector, do backface test */
X_prod(&vec,pts[vtces[j]],pts[vtces[j+1]],pts[vtces[j+2]]);
j = vtces[ivtx];
if ((vec.x*pts[j].x + vec.y*pts[j].y + vec.z*pts[j].z) >= 0.0)
bfacing[i] = TRUE; /* backfacing */
else bfacing[i] = FALSE;
if (!faceted[objnum])
for (j=ivtx; j<ivtx+size; j++) /* sum vertex normals */
{ short k; /* if smooth shading */
k = vtces[j];
norms[k].x += vec.x;
norms[k].y += vec.y;
norms[k].z += vec.z;
}
}
ivtx += size; /* increment to next poly */
}
}
tpts += npts; tpolys += npolys; tvtces += nvtces;
}
/* +++++++++++++++++++++++++ TRANSFORM ++++++++++++++++++++++++++++++++++++ */
transform(orgpt,mtx,pt) /* apply transform to point */
struct { float x,y,z; } *orgpt,*pt; double mtx[16];
{ float tx,ty,tz;
tx = mtx[0]*orgpt->x + mtx[4]*orgpt->y + mtx[8]*orgpt->z + mtx[12];
ty = mtx[1]*orgpt->x + mtx[5]*orgpt->y + mtx[9]*orgpt->z + mtx[13];
tz = mtx[2]*orgpt->x + mtx[6]*orgpt->y + mtx[10]*orgpt->z + mtx[14];
pt->x = tx; pt->y = ty; pt->z = tz;
}
/* ++++++++++++++++++++++++++ X_PROD +++++++++++++++++++++++++++++++++++ */
X_prod(vec,pt1,pt2,pt3) /* vector cross-product */
struct { float x,y,z; } *vec,pt1,pt2,pt3;
{ pt1.x = pt2.x - pt1.x;
pt1.y = pt2.y - pt1.y;
pt1.z = pt2.z - pt1.z;
pt2.x = pt3.x - pt2.x;
pt2.y = pt3.y - pt2.y;
pt2.z = pt3.z - pt2.z;
vec->x = pt1.y*pt2.z - pt1.z*pt2.y;
vec->y = pt1.z*pt2.x - pt1.x*pt2.z;
vec->z = pt1.x*pt2.y - pt1.y*pt2.x;
}
!Funky!Stuff!
More information about the Comp.sources.unix
mailing list