ken@turtleva.UUCP (Ken Turkowski) (12/16/83)
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!