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

ken@turtleva.UUCP (Ken Turkowski) (12/16/83)

echo x - hsalgs/hiq_tiler.c
cat >hsalgs/hiq_tiler.c <<'!Funky!Stuff!'


/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
    hiq_tiler.c - "Universal" anti-aliasing tiler for convex polygons with
    an arbitrary number of parameters/vertex.
       Entries: 
     - hiq_tiler(npts,pts,npars,pix_proc)
        short npts,npars;  void (*pix_proc)(); 
        double pts[];
NOTE!!!  needs to be loaded with BB file providing pix_proc(),
	 getseg() and putseg() and numerous tiler support routines. 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */  

#define MAX_HRES        640     /* maximum horizontal resolution */
#define MAX_VRES        484     /* maximum vertical resolution */
#define SUBPIX          .01     /* minimum allowable width or height */
#define MAX_OPAQUE      .02     /* maximum transmittance considered opaque */
#define MAXLTS          16      /* max number of light sources */ 
#define MAXLONG  0x7FFFFFFF 
#define MAXFLOAT 0xFFFF7FFF   /* yes, that's right (look in the VAX manual) */
#define TRUE   1
#define FALSE  0
#define X      0
#define Y      1
#define PAR1             3    /* array index of first non-specific parameter */ 
#define NORMS  		12
#define NORM_PARMS	 6
#define MAX_PARS   NORMS + NORM_PARMS*MAXLTS   /* max allowed number of parms */
#define sqr(x) ((x)*(x))

static void (*pix_proc)();		/* pointer to pixel write procedure */

/* parameters for image placement in big buffer memory */
extern short Xofset,Yofset;
extern short hres,vres,Y_pos,xleft,xrght;

/* polygon edge data structure */
typedef struct  {  short        lnth;
	           double       x,ht,par[MAX_PARS - PAR1];
                }  edge_position;


 
/* +++++++++++++++++++++++++ HIQ_TILER +++++++++++++++++++++++++++++++++++ */ 

hiq_tiler(npts,pts,npars,pxl_proc)    /* tile a convex poly, taken clockwise */ 
    short npts,npars;   double pts[];    void (*pxl_proc)();
{ 
    edge_position l_edge,r_edge,l_incr,r_incr,l_old,r_old; 
    short i,lpt,rpt,ptcnt,top_pt,next_line,top_line;
    double top,bot,lft,rgt,ceil(),floor(),fabs();

    if (npts < 3) {  printf(" degenerate polygon\n");    return;   } 

    pix_proc = pxl_proc;	/* set pointer to pixel write procedure */

    top = 0.0;    bot = MAX_VRES;    lft = MAX_HRES;    rgt = 0.; 
    for(i=0; i<npts; i++)        /* scale to screen and find topmost vertex */
    {   short j;
        j = i * npars;          /* offset for vertex */
        pts[j+X] = hres * (pts[j+X] + 1.) + SUBPIX + Xofset; 
        pts[j+Y] = vres * (pts[j+Y] + 1.) + SUBPIX + Yofset;   
        if (pts[j+Y] > top)  {   top = pts[j+Y];    top_pt = i;   } 
        if (pts[j+Y] < bot)  bot = pts[j+Y];  /* get bounding box */
        if (pts[j+X] < lft)  lft = pts[j+X];  /* for size check */
        if (pts[j+X] > rgt)  rgt = pts[j+X];
    } 
    if ((top - bot < SUBPIX) || (rgt - lft < SUBPIX))  /* ignore tiny polys */ 
    {   printf(" rejected eensy polygon\n");    return;   } 

    l_edge.lnth = r_edge.lnth = 0;                         /* scanlines left */
    lpt = top_pt;  rpt = top_pt;                        /* vertex pointers */
    Y_pos =  floor(top);                             /* set to top scanline */
    next_line = FALSE;    top_line = TRUE;
    xleft = MAX_HRES;    xrght = 0;            /* initialize segment extremes */
    ptcnt = 0;     /* zero processed point count */ 

    r_edge.x  = l_edge.x  = pts[top_pt*npars+X];       /* load top position */
    r_edge.ht = l_edge.ht = pts[top_pt*npars+Y] - floor(pts[top_pt*npars+Y]);
    for (i=PAR1; i<npars; i++) 
        r_edge.par[i-PAR1] = l_edge.par[i-PAR1] = pts[top_pt*npars+i];

    /* ----------------------- scan loop --------------------------------- */ 
    while(ptcnt <= npts) 
    {  
        /* get left side bottom positions */ 
        copy(&l_edge,&l_old,npars-PAR1,next_line);/* copy to top posns */ 
        if ((l_edge.lnth > 0) && next_line)
            increment(&l_edge,&l_incr,&pts[lpt*npars],npars-PAR1);
        else if (l_edge.lnth <= 0)             /* get new edge block if nec. */
        {   mkedge(&lpt,pts,npars,&l_edge,&l_incr,npts-1,npts);   ptcnt++;   } 

        /* get right side bottom positions */ 
        copy(&r_edge,&r_old,npars-PAR1,next_line);/* copy to top posns */ 
        if ((r_edge.lnth > 0) && next_line) 
            increment(&r_edge,&r_incr,&pts[rpt*npars],npars-PAR1);
        else if (r_edge.lnth <= 0)            /* get new edge block if nec. */ 
        {   mkedge(&rpt,pts,npars,&r_edge,&r_incr,npts+1,npts);   ptcnt++;   }

        hiq_scanseg(&l_edge,&l_old,&r_old,&r_edge,npars-PAR1,next_line | top_line);
    
        if ((l_edge.ht == 0.) && (r_edge.ht == 0.)) /* outpt seg if lin done */
        {   next_line = TRUE;   putseg(Y_pos,xleft,xrght);   Y_pos--;   }
        else            next_line = FALSE; 

 top_line = FALSE;

 if ((Y_pos <= bot)     && (ptcnt >= npts) &&
     (l_edge.lnth == 0) && (r_edge.lnth == 0))  break; /* quit if done */ 
    } 
    putseg(Y_pos,xleft,xrght);        /* store away bottom segment */
}




/* +++++++++++++++++++++++++++++ HIQ_SCANSEG +++++++++++++++++++++++++++++ */ 

hiq_scanseg(lbot,ltop,rtop,rbot,npars,newln) /*trapezoidal section of scan seg*/
    edge_position  *lbot,*ltop,*rtop,*rbot;    short npars,newln;
{   short i,left_top,rght_top,new_left,new_rght,same_slope;
    double left_ht,rght_ht,get_ht();
    edge_position *lb,*lt,*rt,*rb,*v1,*v2,*v3,*v4,*v5,*v6,midlft,midrgt;

    /* allow for twisted or counterclockwise polygons */
    if (ltop->x > rtop->x)  { lt=rtop;  rt=ltop; }  else { lt=ltop;  rt=rtop; }
    if (lbot->x > rbot->x)  { lb=rbot;  rb=lbot; }  else { lb=lbot;  rb=rbot; }
    
    /* find leftmost and rightmost pixels */
    left_top = (lt->x < lb->x)?  TRUE : FALSE; 
    rght_top = (rt->x > rb->x)?  TRUE : FALSE;
    
    /* get section of scanline if new line or smaller left or bigger right */ 
    new_left = left_top?  lt->x : lb->x;   new_rght = rght_top?  rt->x : rb->x;
    if (newln)
    {   xleft = new_left;   xrght = new_rght;   getseg(Y_pos,xleft,xrght);   } 
    else {  if (new_rght > xrght)  {   getseg(Y_pos,xrght+1,new_rght);
                                       xrght = new_rght;            } 
            if (new_left < xleft)  {   getseg(Y_pos,new_left,xleft-1);
                                       xleft = new_left;            }
         }
    
    /* order left-to-right and calculate thickness at inner vertices */ 
    if (left_top) 
    {  v1 = lt; 
       if (rght_top) if (lb->x < rb->x) { v2=lb; v3=rb; 
                                                        same_slope = FALSE; }
                                   else               { v2=rb; v3=lb; 
                                                        same_slope = FALSE; }
                     else          if (lb->x < rt->x) { v2=lb; v3=rt; 
                                                        same_slope = TRUE; } 
                                   else               { v2=rt; v3=lb; 
                                                        same_slope = TRUE; }
    }
    else          
    {  v1 = lb; 
       if (rght_top) if (lt->x < rb->x) { v2=lt; v3=rb; 
                                                        same_slope = TRUE; }
                                   else               { v2=rb; v3=lt; 
                                                        same_slope = TRUE; }
                     else          if (lt->x < rt->x) { v2=lt; v3=rt; 
                                                        same_slope = FALSE; } 
                                   else               { v2=rt; v3=lt;
                                                        same_slope = FALSE; }
    }
    v4 = rght_top?  rt : rb;
    if (same_slope) {   left_ht = get_ht(v1,v2,v3); 
                        rght_ht = get_ht(v2,v3,v4);   }
    else            {   left_ht = get_ht(v1,v2,v4); 
                        rght_ht = get_ht(v1,v3,v4);   }
   
    /* get interpolated cross-trapezoid position at inner vertices */
    if (same_slope) 		   /* get intermediate pts on opposite sides */
    {   double fraction,denom,fabs();
	v6 = v4;    v5 = v3;    v3 = &midlft;    v4 = &midrgt;
	denom = v5->x - v1->x;
	if(fabs(denom) < SUBPIX) fraction = 1.;
	else			 fraction = (v2->x - v1->x) / denom;
	v3->x = v2->x;
	for (i=0; i<npars; i++) 
	    v3->par[i] = v1->par[i] + fraction * (v5->par[i] - v1->par[i]);
	denom = v6->x - v2->x;
	if(fabs(denom) < SUBPIX) fraction = 1.;
	else			 fraction = (v5->x - v2->x) / denom;
	v4->x = v5->x;
	for (i=0; i<npars; i++) 
	    v4->par[i] = v2->par[i] + fraction * (v6->par[i] - v2->par[i]);
    }
    else				/* get intermediate pts on wider side */
    {   double fraction,denom,fabs();	
	v6 = v4;    v4 = v3;    v3 = &midlft;    v5 = &midrgt;
	denom = v6->x - v1->x;
	if(fabs(denom) < SUBPIX) fraction = 1.;
	else			 fraction = (v2->x - v1->x) / denom;
	v3->x = v2->x;
	for (i=0; i<npars; i++) 
	    v3->par[i] = v1->par[i] + fraction * (v6->par[i] - v1->par[i]);
	if(fabs(denom) < SUBPIX) fraction = 1.;
	else			 fraction = (v4->x - v1->x) / denom;
	v5->x = v4->x;
	for (i=0; i<npars; i++) 
	    v5->par[i] = v1->par[i] + fraction * (v6->par[i] - v1->par[i]);
    }
 
 
    /* call shader  for nonzero length segments */ 
    if ((v2->x - v1->x) > SUBPIX) hiq_shader(v1,v1,     0.,v2,v3,left_ht,npars);
    if ((v4->x - v3->x) > SUBPIX) hiq_shader(v2,v3,left_ht,v4,v5,rght_ht,npars);
    if ((v6->x - v5->x) > SUBPIX) hiq_shader(v4,v5,rght_ht,v6,v6,     0.,npars);
}




/* +++++++++++++++++++++++ HIQ_SHADER +++++++++++++++++++++++++++++++++++++++ */
hiq_shader(toplft,botlft,lht,toprgt,botrgt,rht,npars)
				  /* shade segment - trapezoid with sloping 
                                     top, aligned with scanline at bottom and
                                     with vertical sides assumed     */
edge_position *toplft,*botlft,*toprgt,*botrgt;   double lht,rht;   short npars;
{   short xleft,xrght;

    xleft = toplft->x;    xrght = toprgt->x;

    /* --------------------------
    |   single pixel spanned    | 
    -------------------------- */
    if (xleft == xrght)
    {   double cvr; 
        cvr = (toprgt->x - toplft->x) * (lht + rht) / 2;
        (*pix_proc)(xleft,cvr,toplft->par,botlft->par,toprgt->par,botrgt->par);
    }

    /* ------------------------
    |   two pixels spanned    |
    ------------------------ */
    else if (xleft - xrght == 1)
    {   double lcvr,rcvr,midhght;
        lcvr = xleft + 1 - toplft->x;    rcvr = toprgt->x - xrght;
        midhght = lht + (rht - lht) * lcvr / (lcvr + rcvr);
        lcvr = lcvr * (lht + midhght) / 2.;
        rcvr = rcvr * (rht + midhght) / 2.;
        (*pix_proc)(xleft,lcvr,toplft->par,botlft->par,toprgt->par,botrgt->par);
        (*pix_proc)(xrght,rcvr,toplft->par,botlft->par,toprgt->par,botrgt->par);
    }

    /* ---------------------
    |   Multiple pixels    |
    --------------------- */ 
    else
    {   double  tp_px1[MAX_PARS] ,tp_px2[MAX_PARS],
		bt_px1[MAX_PARS] ,bt_px2[MAX_PARS],
		top_inc[MAX_PARS],bot_inc[MAX_PARS],
		*ltop,*lbot,*rtop,*rbot,*temp;
        short i,ix;    double adj,xlnth,ht,hxinc,cvr;
        
        xlnth = (toprgt->x - toplft->x);         /* ----  do left pixel ----- */
        hxinc = (rht - lht) / xlnth;            /* height increment / pixel */
        adj = xleft + 1 - toplft->x;
        ht = lht + hxinc * adj; 
        
        for (i=0; i<npars; i++)                 /* increments */ 
        {   top_inc[i] = (toprgt->par[i] - toplft->par[i]) / xlnth; 
            bot_inc[i] = (botrgt->par[i] - botlft->par[i]) / xlnth; 
            tp_px2[i]  = toplft->par[i] + adj * top_inc[i];
            bt_px2[i]  = toplft->par[i] + adj * top_inc[i];
        } 
        cvr = (xleft + 1 - toplft->x) * (lht + ht) / 2; /* part pixel covrge */
        (*pix_proc)(xleft,cvr,toplft->par,botlft->par,tp_px2,bt_px2);

	rtop = tp_px2;    rbot = bt_px2;    ltop = tp_px1;    lbot = bt_px1;
        for (ix=xleft+1; ix<=xrght; ix++)      /* loop through rest of pixels */
        {   temp = ltop;    ltop = rtop;    rtop = temp;   /* switch pointers */
	    temp = lbot;    lbot = rbot;    rbot = temp;
	    if (ix != xrght)				      /* middle pixel */
	    {   cvr = ht + hxinc/2.;
                for (i=0; i<npars; i++)   rtop[i] = ltop[i] + top_inc[i]; 
                for (i=0; i<npars; i++)   rbot[i] = lbot[i] + bot_inc[i]; 
                ht      += hxinc;
	    }
            else					   /* rightmost pixel */
	    {   cvr = (toprgt->x - ix) * (ht + rht)/2.; 
		rtop = toprgt->par;    rbot = botrgt->par;
            }
	    (*pix_proc)(ix,cvr,ltop,lbot,rtop,rbot);
        } 
    }
}



!Funky!Stuff!