ken@turtleva.UUCP (Ken Turkowski) (12/16/83)
echo x - hsalgs/hiq_pxls.c cat >hsalgs/hiq_pxls.c <<'!Funky!Stuff!' /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hiq_pxls.c - writes pixels for front-to-back algorithms using coverage bits. Uses four corner points of pixel to properly average over texture and small highlights. Entries: - hiq_pxls(X_pos,coverage,tp_lft_pxl,bt_lft_pxl,tp_rgt_pxl,bt_rgt_pxl) NOTE! - must be loaded with ftb_pxls.c to pick up getseg and putseg ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ #define X 0 #define Y 1 #define Z 2 #define R 0 #define G 1 #define B 2 #define T 3 #define XN 4 #define YN 5 #define ZN 6 #define TX_X 7 #define TX_Y 8 #define NORMS 9 #define NORM_PARMS 6 #define LT_R 3 #define LT_G 4 #define LT_B 5 #define TX_RES 128 /* texture image resolution */ #define HRES 640 #define TRANS_MIN .02 /* minimum effective transmittance */ #define HILIT_MIN .02 /* minimum effective highlight factor */ #define MAXOBJ 2 #define TRUE 1 #define FALSE 0 #define sqr(x) ((x)*(x)) extern short cvr[HRES+2]; extern double red[HRES+2],grn[HRES+2],blu[HRES+2]; /* scanline buffer */ /* global variables for pixel output routine */ extern short num_lights,hilit_power,txtr,object; extern struct { short r,g,b,t,s; } texture[MAXOBJ][TX_RES][TX_RES]; /* +++++++++++++++++++++++++++ HIQ_PXLS +++++++++++++++++++++++++++++++++++ */ void hiq_pxls(X_pos,covrge,tp_lft_pxl,bt_lft_pxl,tp_rgt_pxl,bt_rgt_pxl) /* blend pixels using coverage bits */ short X_pos; double covrge,tp_lft_pxl[],bt_lft_pxl[], tp_rgt_pxl[],bt_rgt_pxl[]; { double oldcvr,newred,newgrn,newblu,px_trans; short i; struct { short r,g,b,t,s; } txtr_val; newred = tp_lft_pxl[R]; newgrn = tp_lft_pxl[G]; newblu = tp_lft_pxl[B]; if (txtr) /* color from texture */ { av_texture(&txtr_val,tp_lft_pxl,bt_lft_pxl,tp_rgt_pxl,bt_rgt_pxl); newred *= txtr_val.r / 255.; newgrn *= txtr_val.g / 255.; newblu *= txtr_val.b / 255.; } /* transmittance from texture */ px_trans = txtr? tp_lft_pxl[T] * txtr_val.t / 255. : tp_lft_pxl[T]; if (hilit_power > 0.) for (i=0; i<num_lights; i++) /* hilight */ { short k,x_cross,y_cross; double hilit_value,av_hilit(),pow(),sqrt(); double maj_xc,min_xc,maj_yc,min_yc,vtl,vbl,vtr,vbr,avrg,mgntud; k = NORMS + i*NORM_PARMS; /* offset for highlight normals */ maj_xc = tp_lft_pxl[k+X] * bt_rgt_pxl[k+X]; /* get zero crossings */ min_xc = bt_lft_pxl[k+X] * tp_rgt_pxl[k+X]; /* x zero crossings */ if ((maj_xc <= 0.) || (min_xc <=0.)) x_cross = TRUE; else x_cross = FALSE; maj_yc = tp_lft_pxl[k+Y] * bt_rgt_pxl[k+Y]; /* Y zero crossings */ min_yc = bt_lft_pxl[k+Y] * tp_rgt_pxl[k+Y]; if ((maj_yc <= 0.) || (min_yc <=0.)) y_cross = TRUE; else y_cross = FALSE; mgntud = sqr(tp_lft_pxl[k+X])+sqr(tp_lft_pxl[k+Y])+sqr(tp_lft_pxl[k+Z]); vtl = pow(sqr(tp_lft_pxl[k+Z]) / mgntud ,(double)hilit_power); mgntud = sqr(bt_lft_pxl[k+X])+sqr(bt_lft_pxl[k+Y])+sqr(bt_lft_pxl[k+Z]); vbl = pow(sqr(bt_lft_pxl[k+Z]) / mgntud ,(double)hilit_power); mgntud = sqr(tp_rgt_pxl[k+X])+sqr(tp_rgt_pxl[k+Y])+sqr(tp_rgt_pxl[k+Z]); vtr = pow(sqr(tp_rgt_pxl[k+Z]) / mgntud ,(double)hilit_power); mgntud = sqr(bt_rgt_pxl[k+X])+sqr(bt_rgt_pxl[k+Y])+sqr(bt_rgt_pxl[k+Z]); vbr = pow(sqr(bt_rgt_pxl[k+Z]) / mgntud ,(double)hilit_power); avrg = (vtl + vbl + vtr + vbr) / 4.; /* average of 4 corner values */ if ((avrg <= HILIT_MIN) && (!(x_cross || y_cross))) continue; else hilit_value = avrg; /* skip out if no highlight */ /* ----- sub-sample highlight if zero crossing or high variance ----- */ if ((sqrt(sqr(vtl-avrg) + sqr(vbl-avrg) + sqr(vtr-avrg) + sqr(vbr-avrg)) > HILIT_MIN * 2.) || x_cross || y_cross) { if (maj_xc < min_xc) if ((maj_yc < min_yc) || (maj_xc < min_yc)) /* major diag. */ hilit_value = av_hilit(k,bt_lft_pxl,tp_rgt_pxl); else /* minor diag. */ hilit_value = av_hilit(k,bt_rgt_pxl,tp_lft_pxl); else if ((min_yc < maj_yc) || (min_xc < maj_yc)) /* minor diag. */ hilit_value = av_hilit(k,bt_rgt_pxl,tp_lft_pxl); else /* major diag. */ hilit_value = av_hilit(k,bt_lft_pxl,tp_rgt_pxl); } if (txtr) hilit_value *= txtr_val.s / 255.; /* sum highlights */ newred = newred + (tp_lft_pxl[k+LT_R] - newred) * hilit_value; newgrn = newgrn + (tp_lft_pxl[k+LT_G] - newgrn) * hilit_value; newblu = newblu + (tp_lft_pxl[k+LT_B] - newblu) * hilit_value; if (px_trans > (1.0 - hilit_value)) px_trans = 1.0 - hilit_value; } if (px_trans > TRANS_MIN) covrge *= 1.0 - px_trans; /* transmittance */ oldcvr = cvr[X_pos]; /* get previous pixel coverage */ if (oldcvr == 0.) { cvr[X_pos] = covrge * 255. + .5; /* no previous coverage */ if (cvr[X_pos] > 0) { red[X_pos] = newred; grn[X_pos] = newgrn; blu[X_pos] = newblu; } } else if (oldcvr < 255.) /* partial previous coverage */ { oldcvr /= 255.; /* convert to 0. <= oldcvr <= 1. */ if ((oldcvr + covrge) >= 1.) /* pixel fully covered */ { covrge = 1. - oldcvr; cvr[X_pos] = 255; } else /* pixel partially covered */ { double adj; adj = oldcvr + covrge; cvr[X_pos] = adj * 255. + .5; oldcvr /= adj; covrge /= adj; } red[X_pos] = red[X_pos] * oldcvr + newred * covrge; grn[X_pos] = grn[X_pos] * oldcvr + newgrn * covrge; blu[X_pos] = blu[X_pos] * oldcvr + newblu * covrge; } } /* ++++++++++++++++++++++++++++ AV_HILIT ++++++++++++++++++++++++++++++ */ double av_hilit(k,pxl1,pxl2) /* subsample highlight between 2 pixel positions */ short k; double pxl1[],pxl2[]; { double tx,ty,tz,val1,val2,val3,val4,val5,mag_norm,pow(); mag_norm = sqr(pxl1[k+X]) + sqr(pxl1[k+Y]) + sqr(pxl1[k+Z]); val1 = pow(sqr(pxl1[k+Z])/mag_norm , (double)hilit_power); /*hilit at pxl1*/ tx = (pxl1[k+X] + pxl2[k+X])/2; ty = (pxl1[k+Y] + pxl2[k+Y])/2; tz = (pxl1[k+Z] + pxl2[k+Z])/2; mag_norm = sqr(tx) + sqr(ty) + sqr(tz); val3 = pow(sqr(tz)/mag_norm , (double)hilit_power); /*hilit midway between*/ mag_norm = sqr((pxl1[k+X] + tx)/2) + sqr((pxl1[k+Y] + ty)/2) + sqr((pxl1[k+Z] + tz)/2); val2 = pow(sqr((pxl1[k+Z] + tz)/2)/mag_norm,(double)hilit_power);/*1/4 pt.*/ mag_norm = sqr((pxl2[k+X] + tx)/2) + sqr((pxl2[k+Y] + ty)/2) + sqr((pxl2[k+Z] + tz)/2); val4 = pow(sqr((pxl2[k+Z] + tz)/2)/mag_norm,(double)hilit_power);/*3/4 pt.*/ mag_norm = sqr(pxl2[k+X]) + sqr(pxl2[k+Y]) + sqr(pxl2[k+Z]); val5 = pow(sqr(pxl2[k+Z])/mag_norm , (double)hilit_power); /*hilit at pxl2*/ return (val1 + val2 + val3 + val4 + val5) / 5.; } /* ++++++++++++++++++++++ AV_TEXTURE ++++++++++++++++++++++++++++++++ */ av_texture(txtr_val,tp_lft_pxl,bt_lft_pxl,tp_rgt_pxl,bt_rgt_pxl) /* average texture values for anti-aliasing */ double tp_lft_pxl[],bt_lft_pxl[],tp_rgt_pxl[],bt_rgt_pxl[]; struct { short r,g,b,t,s; } *txtr_val; { short tx_tl,tx_bl,tx_tr,tx_br,ty_tl,ty_bl,ty_tr,ty_br; struct { short r,g,b,t,s; } maj_avrge,min_avrge; /* texture coordinates at 4 corners */ tx_tl = (short)(TX_RES * tp_lft_pxl[TX_X]); ty_tl = (short)(TX_RES * tp_lft_pxl[TX_Y]); tx_bl = (short)(TX_RES * bt_lft_pxl[TX_X]); ty_bl = (short)(TX_RES * bt_lft_pxl[TX_Y]); tx_tr = (short)(TX_RES * tp_rgt_pxl[TX_X]); ty_tr = (short)(TX_RES * tp_rgt_pxl[TX_Y]); tx_br = (short)(TX_RES * bt_rgt_pxl[TX_X]); ty_br = (short)(TX_RES * bt_rgt_pxl[TX_Y]); crawl_to(&maj_avrge,tx_tl,ty_tl,tx_br,ty_br); crawl_to(&min_avrge,tx_bl,ty_bl,tx_tr,ty_tr); txtr_val->r = (maj_avrge.r + min_avrge.r) / 2; txtr_val->g = (maj_avrge.g + min_avrge.g) / 2; txtr_val->b = (maj_avrge.b + min_avrge.b) / 2; txtr_val->t = (maj_avrge.t + min_avrge.t) / 2; txtr_val->s = (maj_avrge.s + min_avrge.s) / 2; } /* +++++++++++++++++++++++++++ CRAWL_TO ++++++++++++++++++++++++++++++++ */ crawl_to(value,x1,y1,x2,y2) /* iterate from p1 to p2 averaging en route */ struct {short r,g,b,t,s; } *value; short x1,y1,x2,y2; { short i,sign,temp; struct {short r,g,b,t,s; } *txtr_ptr; if (y2 < y1) /* ensure y goes positively */ { temp = y2; y2 = y1; y1 = temp; temp = x2; x2 = x1; x1 = temp; } if (x2 < x1) sign = -1; else sign = 1; txtr_ptr = &texture[object][x1%TX_RES][y1%TX_RES]; /* store initial pt. */ value->r = txtr_ptr->r; value->g = txtr_ptr->g; value->b = txtr_ptr->b; value->t = txtr_ptr->t; value->s = txtr_ptr->s; i = 1; while ((x1 != x2) && (y1 != y2)) { if ((y2 - y1)/2 >= abs(x2 - x1)) y1++; else if (abs((x2 - x1)/2) >= (y2 - y1)) x1 += sign; else { x1 += sign; y1++; } txtr_ptr = &texture[object][x1%TX_RES][y1%TX_RES]; /* add new values */ value->r += txtr_ptr->r; value->g += txtr_ptr->g; value->b += txtr_ptr->b; value->t += txtr_ptr->t; value->s += txtr_ptr->s; i++; } value->r /= i; value->g /= i; value->b /= i; value->t /= i; value->s /= i; } !Funky!Stuff!