[net.sources] Graphics source in C: hsalgs/hiq_pxls.c

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!