Graphics source in C: hsalgs/hiq_tiler.c
Ken Turkowski
ken at turtleva.UUCP
Fri Dec 16 13:40:53 AEST 1983
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!
More information about the Comp.sources.unix
mailing list