Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!linus!security!genrad!decvax!decwrl!flairvax!turtleva!ken From: ken@turtleva.UUCP (Ken Turkowski) Newsgroups: net.sources Subject: Graphics source in C: hsalgs/ftb_zsort.c Message-ID: <280@turtleva.UUCP> Date: Thu, 15-Dec-83 22:10:35 EST Article-I.D.: turtleva.280 Posted: Thu Dec 15 22:10:35 1983 Date-Received: Sun, 18-Dec-83 23:32:15 EST Lines: 767 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 */ #include #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= 0) && (!bfacing[i] || backfaces[obj_no[i]]))/*rejected?*/ { min = ZRES; for (k=ivtx; k 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 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 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 0) /* clip */ polclp(0,&npts,poly,poly2,npars); if (npts > 2) { for (k=0; kptr;/* 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 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 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 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 HILIT_MIN) { if (*nlts != j) for (k=0; k=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; ixn = 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= 0.0) /* copy point if inside */ { for (l=0; l 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 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= 0.0) bfacing[i] = TRUE; /* backfacing */ else bfacing[i] = FALSE; if (!faceted[objnum]) for (j=ivtx; jx + 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!