/* Copyright (c) 2001, Stanford University * All rights reserved * * See the file LICENSE.txt for information on redistributing this software. */ /* * This code contributed by Karl Rasche */ #include #include "cr_server.h" #include "cr_mem.h" #include "server.h" static void __find_intersection(double *s, double *e, double *clp, double *clp_next, double *intr) { double v1[2], v2[2]; double A, B, T; v1[0] = e[0] - s[0]; v1[1] = e[1] - s[1]; v2[0] = clp_next[0] - clp[0]; v2[1] = clp_next[1] - clp[1]; if ((v1[1]) && (v2[0])) { A = (clp[1]-s[1])/v1[1] + (v2[1]/v1[1])*(s[0]-clp[0])/v2[0]; B = 1.-(v2[1]/v1[1])*(v1[0]/v2[0]); if (B) T = A/B; else { T = 0; } intr[0] = s[0]+T*v1[0]; intr[1] = s[1]+T*v1[1]; } else if (v1[1]) { /* clp -> clp_next is vertical */ T = (clp[0]-s[0])/v1[0]; intr[0] = s[0]+T*v1[0]; intr[1] = s[1]+T*v1[1]; } else { /* s -> e is horizontal */ T = (s[1]-clp[1])/v2[1]; intr[0] = clp[0]+T*v2[0]; intr[1] = clp[1]+T*v2[1]; } } static void __clip_one_side(double *poly, int npnts, double *clp, double *clp_next, double *norm, double **new_poly_in, int *new_npnts_in, double **new_poly_out, int *new_npnts_out) { int a, sin, ein; double *s, *e, intr[2]; *new_poly_in = (double *)crAlloc(2*npnts*2*sizeof(double)); *new_npnts_in = 0; *new_poly_out = (double *)crAlloc(2*npnts*2*sizeof(double)); *new_npnts_out = 0; s = poly; for (a=0; a= 0) ein = 0; else ein = 1; if (((s[0]-clp[0])*norm[0]) + ((s[1]-clp[1])*norm[1]) >= 0) sin = 0; else sin = 1; if (sin && ein) { /* case 1: */ crMemcpy(*new_poly_in+2*(*new_npnts_in), e, 2*sizeof(double)); (*new_npnts_in)++; } else if (sin && (!ein)) { /* case 2: */ __find_intersection(s, e, clp, clp_next, intr); crMemcpy(*new_poly_in+2*(*new_npnts_in), intr, 2*sizeof(double)); (*new_npnts_in)++; crMemcpy(*new_poly_out+2*(*new_npnts_out), intr, 2*sizeof(double)); (*new_npnts_out)++; crMemcpy(*new_poly_out+2*(*new_npnts_out), e, 2*sizeof(double)); (*new_npnts_out)++; } else if ((!sin) && ein) { /* case 4: */ __find_intersection(s, e, clp, clp_next, intr); crMemcpy((*new_poly_in)+2*(*new_npnts_in), intr, 2*sizeof(double)); (*new_npnts_in)++; crMemcpy((*new_poly_in)+2*(*new_npnts_in), e, 2*sizeof(double)); (*new_npnts_in)++; crMemcpy(*new_poly_out+2*(*new_npnts_out), intr, 2*sizeof(double)); (*new_npnts_out)++; } else { crMemcpy(*new_poly_out+2*(*new_npnts_out), e, 2*sizeof(double)); (*new_npnts_out)++; } s = e; } } /* * Sutherland/Hodgman clipping for interior & exterior regions. * length_of((*new_vert_out)[a]) == nclip_to_vert */ static void __clip(double *poly, int nvert, double *clip_to_poly, int nclip_to_vert, double **new_vert_in, int *nnew_vert_in, double ***new_vert_out, int **nnew_vert_out) { int a, side, *nout; double *clip_normals, *s, *e, *n, *new_vert_src; double *norm, *clp, *clp_next; double **out; *new_vert_out = (double **)crAlloc(nclip_to_vert*sizeof(double *)); *nnew_vert_out = (int *)crAlloc(nclip_to_vert*sizeof(int)); /* * First, compute normals for the clip poly. This * breaks for multiple (3+) adjacent colinear verticies */ clip_normals = (double *)crAlloc(nclip_to_vert*2*sizeof(double)); for (a=0; a 0), the normals are backwards, * assuming the clip region is convex */ if (norm[0]*(n[0]-e[0]) + norm[1]*(n[1]-e[1]) > 0) { norm[0] *= -1; norm[1] *= -1; } } new_vert_src = (double *)crAlloc(nvert*nclip_to_vert*2*sizeof(double)); crMemcpy(new_vert_src, poly, 2*nvert*sizeof(double)); for (side=0; sidenext = NULL; got_intr = 0; /* first, intersect the first 2 polys marked */ for (a=0; apoints, base[a]->npoints, base[b]->points, base[b]->npoints, &in, &nin, &out, &nout); last = b; crFree (nout); for (a=0; anpoints; a++) if (out[a]) crFree(out[a]); crFree(out); if (nin) { intr->npoints = nin; intr->points = in; got_intr = 1; } while (1) { for (a=last+1; apoints, base[a]->npoints, intr->points, intr->npoints, &in, &nin, &out, &nout); crFree (nout); for (b=0; bnpoints; b++) if (out[b]) crFree(out[b]); crFree(out); if (nin) { intr->npoints = nin; intr->points = in; } else { got_intr = 0; break; } } else { __clip(base[a]->points, base[a]->npoints, base[last]->points, base[last]->npoints, &in, &nin, &out, &nout); crFree (nout); for (b=0; bnpoints; b++) { if (out[b]) crFree(out[b]); } crFree(out); if (nin) { intr->npoints = nin; intr->points = in; got_intr = 1; } } last = a; if (a == n) break; } /* can't subract something from nothing! */ if (got_intr) *head = intr; else return; /* find the first item to subtract */ for (a=0; apoints, intr->npoints, base[last]->points, base[last]->npoints, &in, &nin, &out, &nout); crFree(in); for (a=0; anpoints; a++) { if (!nout[a]) continue; p = (CRPoly *)crAlloc(sizeof(CRPoly)); p->npoints = nout[a]; p->points = out[a]; p->next = diff; diff = p; } *head = diff; while (1) { intr = diff; diff = NULL; for (a=last+1; apoints, intr->npoints, base[last]->points, base[last]->npoints, &in, &nin, &out, &nout); crFree(in); for (a=0; anpoints; a++) { if (!nout[a]) continue; p = (CRPoly *)crAlloc(sizeof(CRPoly)); p->npoints = nout[a]; p->points = out[a]; p->next = diff; diff = p; } intr = intr->next; } *head = diff; } } /* * Here we generate all valid bitmaps to represent union/difference * conbinations. Each bitmap is N elements long, where N is the * number of polys [quads] that we are testing for overlap */ static void __generate_masks(int n, int ***mask, int *nmasks) { int a, b, c, d, e; int i, idx, isec_size, add; *mask = (int **)crAlloc((unsigned int)pow(2, n)*sizeof(int)); for (a=0; anpoints = 4; p->points = (double *)crAlloc(8*sizeof(double)); for (b=0; b<8; b++) { p->points[b] = quads[8*a+b]; } p->next = NULL; base[a] = p; } *res = (CRPoly **)crAlloc(nquad*sizeof(CRPoly *)); for (a=0; anext; p->next = (*res)[isec_size]; (*res)[isec_size] = p; p = next; } } for (a=0; apoints); crFree(base[a]); } crFree(base); } /* * This is similar to ComputeOverlapGeom above, but for "knockout" * edge blending. * * my_quad_idx is an index of quads indicating which display tile * we are computing geometry for. From this, we either generate * geometry, or not, such that all geometry can be drawn in black * and only one tile will show through the blend as non-black. * * To add a combination to our set of geom, we must test that: * + mask[a][my_quad_idx] is set * + mask[a][my_quad_idx] is not the first element set in * mask[a]. * If these conditions hold, execute mask[a] and draw the resulting * geometry in black * * Unlike ComputeOverlapGeom, res is just a list of polys to draw in black */ void crComputeKnockoutGeom(double *quads, int nquad, int my_quad_idx, CRPoly **res) { int a, b, idx, first, **mask; CRPoly *p, *next, **base; base = (CRPoly **) crAlloc(nquad*sizeof(CRPoly *)); for (a=0; anpoints = 4; p->points = (double *) crAlloc(8*sizeof(double)); for (b=0; b<8; b++) { p->points[b] = quads[8*a+b]; } p->next = NULL; base[a] = p; } (*res) = NULL; __generate_masks(nquad, &mask, &idx); for (a=0; anext; p->next = *res; *res = p; p = next; } } for (a=0; apoints); crFree(base[a]); } crFree(base); }