diff --git a/desmume/src/windows/agg/agg-2.5.vcproj b/desmume/src/windows/agg/agg-2.5.vcproj index 4d4e94bfe..19ce703de 100644 --- a/desmume/src/windows/agg/agg-2.5.vcproj +++ b/desmume/src/windows/agg/agg-2.5.vcproj @@ -872,10 +872,6 @@ RelativePath=".\src\platform\win32\agg_win32_bmp.cpp" > - - diff --git a/desmume/src/windows/agg/gpc/VERSIONS.TXT b/desmume/src/windows/agg/gpc/VERSIONS.TXT deleted file mode 100644 index 0b877b628..000000000 --- a/desmume/src/windows/agg/gpc/VERSIONS.TXT +++ /dev/null @@ -1,123 +0,0 @@ - -Generic Polygon Clipper (gpc) Revision History -============================================== - - -v2.32 17th Dec 2004 ---------------------- - Fixed occasional memory leak occurring when processing some - degenerate polygon arrangements. - Added explicit type casting to memory allocator in support of - increased code portability. - -v2.31 4th Jun 1999 ---------------------- - Separated edge merging measure based on a user-defined GPC_EPSILON - value from general numeric equality testing and ordering, which now - uses direct arithmetic comparison rather an EPSILON based proximity - test. - Fixed problem with numerical equality test during construction of - local minima and scanbeam tables, leading to occasional crash. - Fixed hole array memory leak in gpc_add_contour. - Fixed uninitialised hole field bug in gpc_polygon_clip result. - -v2.30 11th Apr 1999 ---------------------- - Major re-write. - Minor API change: additional 'hole' array field added to gpc_polygon - datatype to indicate which constituent contours are internal holes, - and which form external boundaries. - Minor API change: additional 'hole' argument to gpc_add_contour - to indicate whether the new contour is a hole or external contour. - Minor API change: additional parameter to gpc_read_polygon and - gpc_write_polygon to indicate whether or not to read or write - contour hole flags. - Fixed NULL pointer bug in add/merge left/right operations. - Fixed numerical problem in intersection table generation. - Fixed zero byte malloc problem. - Fixed problem producing occasional 2 vertex contours. - Added bounding box test optimisations. - Simplified edge bundle creation, detection of scanbeam internal - edge intersections and tristrip scanbeam boundary code. - Renamed 'class' variable to be C++ friendly. - -v2.22 17th Oct 1998 ---------------------- - Re-implemented edge interpolation and intersection calculations - to improve numerical robustness. - Simplified setting of GPC_EPSILON. - -v2.21 19th Aug 1998 ---------------------- - Fixed problem causing occasional incorrect output when processing - self-intersecting polygons (bow-ties etc). - Removed bug which may lead to non-generation of uppermost triangle - in tristrip output. - -v2.20 26th May 1998 ---------------------- - Major re-write. - Added exclusive-or polygon set operation. - Replaced table-based processing of edge intersections with - rule-based system. - Replaced two-pass approach to scanbeam interior processing with - single pass method. - -v2.10a 14th May 1998 ---------------------- - Minor bug-fixes to counter some v2.10 reliability problems. - -v2.10 11th May 1998 ---------------------- - Major re-write. - Incorporated edge bundle processing of AET to overcome coincident - edge problems present in previous releases. - Replaced Vatti's method for processing scanbeam interior regions - with an adapted version of the scanbeam boundary processing - algorithm. - -v2.02 16th Apr 1998 (unreleased) ----------------------------------- - Fixed internal minimum vertex duplication in gpc_polygon_clip - result. - Improved line intersection code discourage superfluous - intersections near line ends. - Removed limited precision number formatting in gpc_write_polygon. - Modification to allow subject or clip polygon to be reused as the - result in gpc_polygon_clip without memory leakage. - -v2.01 23rd Feb 1998 ---------------------- - Removed bug causing duplicated vertices in output polygon. - Fixed scanbeam table index overrun problem. - -v2.00 25th Nov 1997 ---------------------- - Major re-write. - Replaced temporary horizontal edge work-around (using tilting) - with true horizontal edge handling. - Trapezoidal output replaced by tristrips. - gpc_op constants now feature a `GPC_' prefix. - Data structures now passed by reference to gpc functions. - Replaced AET search by proxy addressing in polygon table. - Eliminated most (all?) coincident vertex / edge crashes. - -v1.02 18th Oct 1997 (unreleased) ----------------------------------- - Significantly reduced number of mallocs in build_lmt. - Scanbeam table now built using heapsort rather than insertion - sort. - -v1.01 12th Oct 1997 ---------------------- - Fixed memory leak during output polygon build in - gpc_clip_polygon. - Removed superfluous logfile debug code. - Commented out malloc counts. - Added missing horizontal edge tilt-correction code in - gpc_clip_polygon. - -v1.00 8th Oct 1997 --------------------- - First release. - diff --git a/desmume/src/windows/agg/gpc/copying.txt b/desmume/src/windows/agg/gpc/copying.txt deleted file mode 100644 index 5f1e6bc46..000000000 --- a/desmume/src/windows/agg/gpc/copying.txt +++ /dev/null @@ -1,22 +0,0 @@ - - http://www.cs.man.ac.uk/aig/staff/alan/software/ - -Author: Alan Murta (email: gpc@cs.man.ac.uk) -Version: 2.31 -Date: 4th June 1999 - -Copyright: (C) 1997-1999, Advanced Interfaces Group, - University of Manchester. - - This software is free for non-commercial use. It may be copied, - modified, and redistributed provided that this copyright notice - is preserved on all copies. The intellectual property rights of - the algorithms used reside with the University of Manchester - Advanced Interfaces Group. - - You may not use this software, in whole or in part, in support - of any commercial product without the express consent of the - author. - - There is no warranty or other guarantee of fitness of this - software for any purpose. It is provided solely "as is". diff --git a/desmume/src/windows/agg/gpc/gpc.c b/desmume/src/windows/agg/gpc/gpc.c deleted file mode 100644 index b25800bcf..000000000 --- a/desmume/src/windows/agg/gpc/gpc.c +++ /dev/null @@ -1,2472 +0,0 @@ -/* -=========================================================================== - -Project: Generic Polygon Clipper - - A new algorithm for calculating the difference, intersection, - exclusive-or or union of arbitrary polygon sets. - -File: gpc.c -Author: Alan Murta (email: gpc@cs.man.ac.uk) -Version: 2.32 -Date: 17th December 2004 - -Copyright: (C) 1997-2004, Advanced Interfaces Group, - University of Manchester. - - This software is free for non-commercial use. It may be copied, - modified, and redistributed provided that this copyright notice - is preserved on all copies. The intellectual property rights of - the algorithms used reside with the University of Manchester - Advanced Interfaces Group. - - You may not use this software, in whole or in part, in support - of any commercial product without the express consent of the - author. - - There is no warranty or other guarantee of fitness of this - software for any purpose. It is provided solely "as is". - -=========================================================================== -*/ - - -/* -=========================================================================== - Includes -=========================================================================== -*/ - -#include "gpc.h" -#include -#include -#include - - -/* -=========================================================================== - Constants -=========================================================================== -*/ - -#ifndef TRUE -#define FALSE 0 -#define TRUE 1 -#endif - -#define LEFT 0 -#define RIGHT 1 - -#define ABOVE 0 -#define BELOW 1 - -#define CLIP 0 -#define SUBJ 1 - -#define INVERT_TRISTRIPS FALSE - - -/* -=========================================================================== - Macros -=========================================================================== -*/ - -#define EQ(a, b) (fabs((a) - (b)) <= GPC_EPSILON) - -#define PREV_INDEX(i, n) ((i - 1 + n) % n) -#define NEXT_INDEX(i, n) ((i + 1 ) % n) - -#define OPTIMAL(v, i, n) ((v[PREV_INDEX(i, n)].y != v[i].y) || \ - (v[NEXT_INDEX(i, n)].y != v[i].y)) - -#define FWD_MIN(v, i, n) ((v[PREV_INDEX(i, n)].vertex.y >= v[i].vertex.y) \ - && (v[NEXT_INDEX(i, n)].vertex.y > v[i].vertex.y)) - -#define NOT_FMAX(v, i, n) (v[NEXT_INDEX(i, n)].vertex.y > v[i].vertex.y) - -#define REV_MIN(v, i, n) ((v[PREV_INDEX(i, n)].vertex.y > v[i].vertex.y) \ - && (v[NEXT_INDEX(i, n)].vertex.y >= v[i].vertex.y)) - -#define NOT_RMAX(v, i, n) (v[PREV_INDEX(i, n)].vertex.y > v[i].vertex.y) - -#define VERTEX(e,p,s,x,y) {add_vertex(&((e)->outp[(p)]->v[(s)]), x, y); \ - (e)->outp[(p)]->active++;} - -#define P_EDGE(d,e,p,i,j) {(d)= (e); \ - do {(d)= (d)->prev;} while (!(d)->outp[(p)]); \ - (i)= (d)->bot.x + (d)->dx * ((j)-(d)->bot.y);} - -#define N_EDGE(d,e,p,i,j) {(d)= (e); \ - do {(d)= (d)->next;} while (!(d)->outp[(p)]); \ - (i)= (d)->bot.x + (d)->dx * ((j)-(d)->bot.y);} - -#define MALLOC(p, b, s, t) {if ((b) > 0) { \ - p= (t*)malloc(b); if (!(p)) { \ - fprintf(stderr, "gpc malloc failure: %s\n", s); \ - exit(0);}} else p= NULL;} - -#define FREE(p) {if (p) {free(p); (p)= NULL;}} - - -/* -=========================================================================== - Private Data Types -=========================================================================== -*/ - -typedef enum /* Edge intersection classes */ -{ - NUL, /* Empty non-intersection */ - EMX, /* External maximum */ - ELI, /* External left intermediate */ - TED, /* Top edge */ - ERI, /* External right intermediate */ - RED, /* Right edge */ - IMM, /* Internal maximum and minimum */ - IMN, /* Internal minimum */ - EMN, /* External minimum */ - EMM, /* External maximum and minimum */ - LED, /* Left edge */ - ILI, /* Internal left intermediate */ - BED, /* Bottom edge */ - IRI, /* Internal right intermediate */ - IMX, /* Internal maximum */ - FUL /* Full non-intersection */ -} vertex_type; - -typedef enum /* Horizontal edge states */ -{ - NH, /* No horizontal edge */ - BH, /* Bottom horizontal edge */ - TH /* Top horizontal edge */ -} h_state; - -typedef enum /* Edge bundle state */ -{ - UNBUNDLED, /* Isolated edge not within a bundle */ - BUNDLE_HEAD, /* Bundle head node */ - BUNDLE_TAIL /* Passive bundle tail node */ -} bundle_state; - -typedef struct v_shape /* Internal vertex list datatype */ -{ - double x; /* X coordinate component */ - double y; /* Y coordinate component */ - struct v_shape *next; /* Pointer to next vertex in list */ -} vertex_node; - -typedef struct p_shape /* Internal contour / tristrip type */ -{ - int active; /* Active flag / vertex count */ - int hole; /* Hole / external contour flag */ - vertex_node *v[2]; /* Left and right vertex list ptrs */ - struct p_shape *next; /* Pointer to next polygon contour */ - struct p_shape *proxy; /* Pointer to actual structure used */ -} polygon_node; - -typedef struct edge_shape -{ - gpc_vertex vertex; /* Piggy-backed contour vertex data */ - gpc_vertex bot; /* Edge lower (x, y) coordinate */ - gpc_vertex top; /* Edge upper (x, y) coordinate */ - double xb; /* Scanbeam bottom x coordinate */ - double xt; /* Scanbeam top x coordinate */ - double dx; /* Change in x for a unit y increase */ - int type; /* Clip / subject edge flag */ - int bundle[2][2]; /* Bundle edge flags */ - int bside[2]; /* Bundle left / right indicators */ - bundle_state bstate[2]; /* Edge bundle state */ - polygon_node *outp[2]; /* Output polygon / tristrip pointer */ - struct edge_shape *prev; /* Previous edge in the AET */ - struct edge_shape *next; /* Next edge in the AET */ - struct edge_shape *pred; /* Edge connected at the lower end */ - struct edge_shape *succ; /* Edge connected at the upper end */ - struct edge_shape *next_bound; /* Pointer to next bound in LMT */ -} edge_node; - -typedef struct lmt_shape /* Local minima table */ -{ - double y; /* Y coordinate at local minimum */ - edge_node *first_bound; /* Pointer to bound list */ - struct lmt_shape *next; /* Pointer to next local minimum */ -} lmt_node; - -typedef struct sbt_t_shape /* Scanbeam tree */ -{ - double y; /* Scanbeam node y value */ - struct sbt_t_shape *less; /* Pointer to nodes with lower y */ - struct sbt_t_shape *more; /* Pointer to nodes with higher y */ -} sb_tree; - -typedef struct it_shape /* Intersection table */ -{ - edge_node *ie[2]; /* Intersecting edge (bundle) pair */ - gpc_vertex point; /* Point of intersection */ - struct it_shape *next; /* The next intersection table node */ -} it_node; - -typedef struct st_shape /* Sorted edge table */ -{ - edge_node *edge; /* Pointer to AET edge */ - double xb; /* Scanbeam bottom x coordinate */ - double xt; /* Scanbeam top x coordinate */ - double dx; /* Change in x for a unit y increase */ - struct st_shape *prev; /* Previous edge in sorted list */ -} st_node; - -typedef struct bbox_shape /* Contour axis-aligned bounding box */ -{ - double xmin; /* Minimum x coordinate */ - double ymin; /* Minimum y coordinate */ - double xmax; /* Maximum x coordinate */ - double ymax; /* Maximum y coordinate */ -} bbox; - - -/* -=========================================================================== - Global Data -=========================================================================== -*/ - -/* Horizontal edge state transitions within scanbeam boundary */ -const h_state next_h_state[3][6]= -{ - /* ABOVE BELOW CROSS */ - /* L R L R L R */ - /* NH */ {BH, TH, TH, BH, NH, NH}, - /* BH */ {NH, NH, NH, NH, TH, TH}, - /* TH */ {NH, NH, NH, NH, BH, BH} -}; - - -/* -=========================================================================== - Private Functions -=========================================================================== -*/ - -static void reset_it(it_node **it) -{ - it_node *itn; - - while (*it) - { - itn= (*it)->next; - FREE(*it); - *it= itn; - } -} - - -static void reset_lmt(lmt_node **lmt) -{ - lmt_node *lmtn; - - while (*lmt) - { - lmtn= (*lmt)->next; - FREE(*lmt); - *lmt= lmtn; - } -} - - -static void insert_bound(edge_node **b, edge_node *e) -{ - edge_node *existing_bound; - - if (!*b) - { - /* Link node e to the tail of the list */ - *b= e; - } - else - { - /* Do primary sort on the x field */ - if (e[0].bot.x < (*b)[0].bot.x) - { - /* Insert a new node mid-list */ - existing_bound= *b; - *b= e; - (*b)->next_bound= existing_bound; - } - else - { - if (e[0].bot.x == (*b)[0].bot.x) - { - /* Do secondary sort on the dx field */ - if (e[0].dx < (*b)[0].dx) - { - /* Insert a new node mid-list */ - existing_bound= *b; - *b= e; - (*b)->next_bound= existing_bound; - } - else - { - /* Head further down the list */ - insert_bound(&((*b)->next_bound), e); - } - } - else - { - /* Head further down the list */ - insert_bound(&((*b)->next_bound), e); - } - } - } -} - - -static edge_node **bound_list(lmt_node **lmt, double y) -{ - lmt_node *existing_node; - - if (!*lmt) - { - /* Add node onto the tail end of the LMT */ - MALLOC(*lmt, sizeof(lmt_node), "LMT insertion", lmt_node); - (*lmt)->y= y; - (*lmt)->first_bound= NULL; - (*lmt)->next= NULL; - return &((*lmt)->first_bound); - } - else - if (y < (*lmt)->y) - { - /* Insert a new LMT node before the current node */ - existing_node= *lmt; - MALLOC(*lmt, sizeof(lmt_node), "LMT insertion", lmt_node); - (*lmt)->y= y; - (*lmt)->first_bound= NULL; - (*lmt)->next= existing_node; - return &((*lmt)->first_bound); - } - else - if (y > (*lmt)->y) - /* Head further up the LMT */ - return bound_list(&((*lmt)->next), y); - else - /* Use this existing LMT node */ - return &((*lmt)->first_bound); -} - - -static void add_to_sbtree(int *entries, sb_tree **sbtree, double y) -{ - if (!*sbtree) - { - /* Add a new tree node here */ - MALLOC(*sbtree, sizeof(sb_tree), "scanbeam tree insertion", sb_tree); - (*sbtree)->y= y; - (*sbtree)->less= NULL; - (*sbtree)->more= NULL; - (*entries)++; - } - else - { - if ((*sbtree)->y > y) - { - /* Head into the 'less' sub-tree */ - add_to_sbtree(entries, &((*sbtree)->less), y); - } - else - { - if ((*sbtree)->y < y) - { - /* Head into the 'more' sub-tree */ - add_to_sbtree(entries, &((*sbtree)->more), y); - } - } - } -} - - -static void build_sbt(int *entries, double *sbt, sb_tree *sbtree) -{ - if (sbtree->less) - build_sbt(entries, sbt, sbtree->less); - sbt[*entries]= sbtree->y; - (*entries)++; - if (sbtree->more) - build_sbt(entries, sbt, sbtree->more); -} - - -static void free_sbtree(sb_tree **sbtree) -{ - if (*sbtree) - { - free_sbtree(&((*sbtree)->less)); - free_sbtree(&((*sbtree)->more)); - FREE(*sbtree); - } -} - - -static int count_optimal_vertices(gpc_vertex_list c) -{ - int result= 0, i; - - /* Ignore non-contributing contours */ - if (c.num_vertices > 0) - { - for (i= 0; i < c.num_vertices; i++) - /* Ignore superfluous vertices embedded in horizontal edges */ - if (OPTIMAL(c.vertex, i, c.num_vertices)) - result++; - } - return result; -} - - -static edge_node *build_lmt(lmt_node **lmt, sb_tree **sbtree, - int *sbt_entries, gpc_polygon *p, int type, - gpc_op op) -{ - int c, i, min, max, num_edges, v, num_vertices; - int total_vertices= 0, e_index=0; - edge_node *e, *edge_table; - - for (c= 0; c < p->num_contours; c++) - total_vertices+= count_optimal_vertices(p->contour[c]); - - /* Create the entire input polygon edge table in one go */ - MALLOC(edge_table, total_vertices * sizeof(edge_node), - "edge table creation", edge_node); - - for (c= 0; c < p->num_contours; c++) - { - if (p->contour[c].num_vertices < 0) - { - /* Ignore the non-contributing contour and repair the vertex count */ - p->contour[c].num_vertices= -p->contour[c].num_vertices; - } - else - { - /* Perform contour optimisation */ - num_vertices= 0; - for (i= 0; i < p->contour[c].num_vertices; i++) - if (OPTIMAL(p->contour[c].vertex, i, p->contour[c].num_vertices)) - { - edge_table[num_vertices].vertex.x= p->contour[c].vertex[i].x; - edge_table[num_vertices].vertex.y= p->contour[c].vertex[i].y; - - /* Record vertex in the scanbeam table */ - add_to_sbtree(sbt_entries, sbtree, - edge_table[num_vertices].vertex.y); - - num_vertices++; - } - - /* Do the contour forward pass */ - for (min= 0; min < num_vertices; min++) - { - /* If a forward local minimum... */ - if (FWD_MIN(edge_table, min, num_vertices)) - { - /* Search for the next local maximum... */ - num_edges= 1; - max= NEXT_INDEX(min, num_vertices); - while (NOT_FMAX(edge_table, max, num_vertices)) - { - num_edges++; - max= NEXT_INDEX(max, num_vertices); - } - - /* Build the next edge list */ - e= &edge_table[e_index]; - e_index+= num_edges; - v= min; - e[0].bstate[BELOW]= UNBUNDLED; - e[0].bundle[BELOW][CLIP]= FALSE; - e[0].bundle[BELOW][SUBJ]= FALSE; - for (i= 0; i < num_edges; i++) - { - e[i].xb= edge_table[v].vertex.x; - e[i].bot.x= edge_table[v].vertex.x; - e[i].bot.y= edge_table[v].vertex.y; - - v= NEXT_INDEX(v, num_vertices); - - e[i].top.x= edge_table[v].vertex.x; - e[i].top.y= edge_table[v].vertex.y; - e[i].dx= (edge_table[v].vertex.x - e[i].bot.x) / - (e[i].top.y - e[i].bot.y); - e[i].type= type; - e[i].outp[ABOVE]= NULL; - e[i].outp[BELOW]= NULL; - e[i].next= NULL; - e[i].prev= NULL; - e[i].succ= ((num_edges > 1) && (i < (num_edges - 1))) ? - &(e[i + 1]) : NULL; - e[i].pred= ((num_edges > 1) && (i > 0)) ? &(e[i - 1]) : NULL; - e[i].next_bound= NULL; - e[i].bside[CLIP]= (op == GPC_DIFF) ? RIGHT : LEFT; - e[i].bside[SUBJ]= LEFT; - } - insert_bound(bound_list(lmt, edge_table[min].vertex.y), e); - } - } - - /* Do the contour reverse pass */ - for (min= 0; min < num_vertices; min++) - { - /* If a reverse local minimum... */ - if (REV_MIN(edge_table, min, num_vertices)) - { - /* Search for the previous local maximum... */ - num_edges= 1; - max= PREV_INDEX(min, num_vertices); - while (NOT_RMAX(edge_table, max, num_vertices)) - { - num_edges++; - max= PREV_INDEX(max, num_vertices); - } - - /* Build the previous edge list */ - e= &edge_table[e_index]; - e_index+= num_edges; - v= min; - e[0].bstate[BELOW]= UNBUNDLED; - e[0].bundle[BELOW][CLIP]= FALSE; - e[0].bundle[BELOW][SUBJ]= FALSE; - for (i= 0; i < num_edges; i++) - { - e[i].xb= edge_table[v].vertex.x; - e[i].bot.x= edge_table[v].vertex.x; - e[i].bot.y= edge_table[v].vertex.y; - - v= PREV_INDEX(v, num_vertices); - - e[i].top.x= edge_table[v].vertex.x; - e[i].top.y= edge_table[v].vertex.y; - e[i].dx= (edge_table[v].vertex.x - e[i].bot.x) / - (e[i].top.y - e[i].bot.y); - e[i].type= type; - e[i].outp[ABOVE]= NULL; - e[i].outp[BELOW]= NULL; - e[i].next= NULL; - e[i].prev= NULL; - e[i].succ= ((num_edges > 1) && (i < (num_edges - 1))) ? - &(e[i + 1]) : NULL; - e[i].pred= ((num_edges > 1) && (i > 0)) ? &(e[i - 1]) : NULL; - e[i].next_bound= NULL; - e[i].bside[CLIP]= (op == GPC_DIFF) ? RIGHT : LEFT; - e[i].bside[SUBJ]= LEFT; - } - insert_bound(bound_list(lmt, edge_table[min].vertex.y), e); - } - } - } - } - return edge_table; -} - - -static void add_edge_to_aet(edge_node **aet, edge_node *edge, edge_node *prev) -{ - if (!*aet) - { - /* Append edge onto the tail end of the AET */ - *aet= edge; - edge->prev= prev; - edge->next= NULL; - } - else - { - /* Do primary sort on the xb field */ - if (edge->xb < (*aet)->xb) - { - /* Insert edge here (before the AET edge) */ - edge->prev= prev; - edge->next= *aet; - (*aet)->prev= edge; - *aet= edge; - } - else - { - if (edge->xb == (*aet)->xb) - { - /* Do secondary sort on the dx field */ - if (edge->dx < (*aet)->dx) - { - /* Insert edge here (before the AET edge) */ - edge->prev= prev; - edge->next= *aet; - (*aet)->prev= edge; - *aet= edge; - } - else - { - /* Head further into the AET */ - add_edge_to_aet(&((*aet)->next), edge, *aet); - } - } - else - { - /* Head further into the AET */ - add_edge_to_aet(&((*aet)->next), edge, *aet); - } - } - } -} - - -static void add_intersection(it_node **it, edge_node *edge0, edge_node *edge1, - double x, double y) -{ - it_node *existing_node; - - if (!*it) - { - /* Append a new node to the tail of the list */ - MALLOC(*it, sizeof(it_node), "IT insertion", it_node); - (*it)->ie[0]= edge0; - (*it)->ie[1]= edge1; - (*it)->point.x= x; - (*it)->point.y= y; - (*it)->next= NULL; - } - else - { - if ((*it)->point.y > y) - { - /* Insert a new node mid-list */ - existing_node= *it; - MALLOC(*it, sizeof(it_node), "IT insertion", it_node); - (*it)->ie[0]= edge0; - (*it)->ie[1]= edge1; - (*it)->point.x= x; - (*it)->point.y= y; - (*it)->next= existing_node; - } - else - /* Head further down the list */ - add_intersection(&((*it)->next), edge0, edge1, x, y); - } -} - - -static void add_st_edge(st_node **st, it_node **it, edge_node *edge, - double dy) -{ - st_node *existing_node; - double den, r, x, y; - - if (!*st) - { - /* Append edge onto the tail end of the ST */ - MALLOC(*st, sizeof(st_node), "ST insertion", st_node); - (*st)->edge= edge; - (*st)->xb= edge->xb; - (*st)->xt= edge->xt; - (*st)->dx= edge->dx; - (*st)->prev= NULL; - } - else - { - den= ((*st)->xt - (*st)->xb) - (edge->xt - edge->xb); - - /* If new edge and ST edge don't cross */ - if ((edge->xt >= (*st)->xt) || (edge->dx == (*st)->dx) || - (fabs(den) <= DBL_EPSILON)) - { - /* No intersection - insert edge here (before the ST edge) */ - existing_node= *st; - MALLOC(*st, sizeof(st_node), "ST insertion", st_node); - (*st)->edge= edge; - (*st)->xb= edge->xb; - (*st)->xt= edge->xt; - (*st)->dx= edge->dx; - (*st)->prev= existing_node; - } - else - { - /* Compute intersection between new edge and ST edge */ - r= (edge->xb - (*st)->xb) / den; - x= (*st)->xb + r * ((*st)->xt - (*st)->xb); - y= r * dy; - - /* Insert the edge pointers and the intersection point in the IT */ - add_intersection(it, (*st)->edge, edge, x, y); - - /* Head further into the ST */ - add_st_edge(&((*st)->prev), it, edge, dy); - } - } -} - - -static void build_intersection_table(it_node **it, edge_node *aet, double dy) -{ - st_node *st, *stp; - edge_node *edge; - - /* Build intersection table for the current scanbeam */ - reset_it(it); - st= NULL; - - /* Process each AET edge */ - for (edge= aet; edge; edge= edge->next) - { - if ((edge->bstate[ABOVE] == BUNDLE_HEAD) || - edge->bundle[ABOVE][CLIP] || edge->bundle[ABOVE][SUBJ]) - add_st_edge(&st, it, edge, dy); - } - - /* Free the sorted edge table */ - while (st) - { - stp= st->prev; - FREE(st); - st= stp; - } -} - -static int count_contours(polygon_node *polygon) -{ - int nc, nv; - vertex_node *v, *nextv; - - for (nc= 0; polygon; polygon= polygon->next) - if (polygon->active) - { - /* Count the vertices in the current contour */ - nv= 0; - for (v= polygon->proxy->v[LEFT]; v; v= v->next) - nv++; - - /* Record valid vertex counts in the active field */ - if (nv > 2) - { - polygon->active= nv; - nc++; - } - else - { - /* Invalid contour: just free the heap */ - for (v= polygon->proxy->v[LEFT]; v; v= nextv) - { - nextv= v->next; - FREE(v); - } - polygon->active= 0; - } - } - return nc; -} - - -static void add_left(polygon_node *p, double x, double y) -{ - vertex_node *nv; - - /* Create a new vertex node and set its fields */ - MALLOC(nv, sizeof(vertex_node), "vertex node creation", vertex_node); - nv->x= x; - nv->y= y; - - /* Add vertex nv to the left end of the polygon's vertex list */ - nv->next= p->proxy->v[LEFT]; - - /* Update proxy->[LEFT] to point to nv */ - p->proxy->v[LEFT]= nv; -} - - -static void merge_left(polygon_node *p, polygon_node *q, polygon_node *list) -{ - polygon_node *target; - - /* Label contour as a hole */ - q->proxy->hole= TRUE; - - if (p->proxy != q->proxy) - { - /* Assign p's vertex list to the left end of q's list */ - p->proxy->v[RIGHT]->next= q->proxy->v[LEFT]; - q->proxy->v[LEFT]= p->proxy->v[LEFT]; - - /* Redirect any p->proxy references to q->proxy */ - - for (target= p->proxy; list; list= list->next) - { - if (list->proxy == target) - { - list->active= FALSE; - list->proxy= q->proxy; - } - } - } -} - - -static void add_right(polygon_node *p, double x, double y) -{ - vertex_node *nv; - - /* Create a new vertex node and set its fields */ - MALLOC(nv, sizeof(vertex_node), "vertex node creation", vertex_node); - nv->x= x; - nv->y= y; - nv->next= NULL; - - /* Add vertex nv to the right end of the polygon's vertex list */ - p->proxy->v[RIGHT]->next= nv; - - /* Update proxy->v[RIGHT] to point to nv */ - p->proxy->v[RIGHT]= nv; -} - - -static void merge_right(polygon_node *p, polygon_node *q, polygon_node *list) -{ - polygon_node *target; - - /* Label contour as external */ - q->proxy->hole= FALSE; - - if (p->proxy != q->proxy) - { - /* Assign p's vertex list to the right end of q's list */ - q->proxy->v[RIGHT]->next= p->proxy->v[LEFT]; - q->proxy->v[RIGHT]= p->proxy->v[RIGHT]; - - /* Redirect any p->proxy references to q->proxy */ - for (target= p->proxy; list; list= list->next) - { - if (list->proxy == target) - { - list->active= FALSE; - list->proxy= q->proxy; - } - } - } -} - - -static void add_local_min(polygon_node **p, edge_node *edge, - double x, double y) -{ - polygon_node *existing_min; - vertex_node *nv; - - existing_min= *p; - - MALLOC(*p, sizeof(polygon_node), "polygon node creation", polygon_node); - - /* Create a new vertex node and set its fields */ - MALLOC(nv, sizeof(vertex_node), "vertex node creation", vertex_node); - nv->x= x; - nv->y= y; - nv->next= NULL; - - /* Initialise proxy to point to p itself */ - (*p)->proxy= (*p); - (*p)->active= TRUE; - (*p)->next= existing_min; - - /* Make v[LEFT] and v[RIGHT] point to new vertex nv */ - (*p)->v[LEFT]= nv; - (*p)->v[RIGHT]= nv; - - /* Assign polygon p to the edge */ - edge->outp[ABOVE]= *p; -} - - -static int count_tristrips(polygon_node *tn) -{ - int total; - - for (total= 0; tn; tn= tn->next) - if (tn->active > 2) - total++; - return total; -} - - -static void add_vertex(vertex_node **t, double x, double y) -{ - if (!(*t)) - { - MALLOC(*t, sizeof(vertex_node), "tristrip vertex creation", vertex_node); - (*t)->x= x; - (*t)->y= y; - (*t)->next= NULL; - } - else - /* Head further down the list */ - add_vertex(&((*t)->next), x, y); -} - - -static void new_tristrip(polygon_node **tn, edge_node *edge, - double x, double y) -{ - if (!(*tn)) - { - MALLOC(*tn, sizeof(polygon_node), "tristrip node creation", polygon_node); - (*tn)->next= NULL; - (*tn)->v[LEFT]= NULL; - (*tn)->v[RIGHT]= NULL; - (*tn)->active= 1; - add_vertex(&((*tn)->v[LEFT]), x, y); - edge->outp[ABOVE]= *tn; - } - else - /* Head further down the list */ - new_tristrip(&((*tn)->next), edge, x, y); -} - - -static bbox *create_contour_bboxes(gpc_polygon *p) -{ - bbox *box; - int c, v; - - MALLOC(box, p->num_contours * sizeof(bbox), "Bounding box creation", bbox); - - /* Construct contour bounding boxes */ - for (c= 0; c < p->num_contours; c++) - { - /* Initialise bounding box extent */ - box[c].xmin= DBL_MAX; - box[c].ymin= DBL_MAX; - box[c].xmax= -DBL_MAX; - box[c].ymax= -DBL_MAX; - - for (v= 0; v < p->contour[c].num_vertices; v++) - { - /* Adjust bounding box */ - if (p->contour[c].vertex[v].x < box[c].xmin) - box[c].xmin= p->contour[c].vertex[v].x; - if (p->contour[c].vertex[v].y < box[c].ymin) - box[c].ymin= p->contour[c].vertex[v].y; - if (p->contour[c].vertex[v].x > box[c].xmax) - box[c].xmax= p->contour[c].vertex[v].x; - if (p->contour[c].vertex[v].y > box[c].ymax) - box[c].ymax= p->contour[c].vertex[v].y; - } - } - return box; -} - - -static void minimax_test(gpc_polygon *subj, gpc_polygon *clip, gpc_op op) -{ - bbox *s_bbox, *c_bbox; - int s, c, *o_table, overlap; - - s_bbox= create_contour_bboxes(subj); - c_bbox= create_contour_bboxes(clip); - - MALLOC(o_table, subj->num_contours * clip->num_contours * sizeof(int), - "overlap table creation", int); - - /* Check all subject contour bounding boxes against clip boxes */ - for (s= 0; s < subj->num_contours; s++) - for (c= 0; c < clip->num_contours; c++) - o_table[c * subj->num_contours + s]= - (!((s_bbox[s].xmax < c_bbox[c].xmin) || - (s_bbox[s].xmin > c_bbox[c].xmax))) && - (!((s_bbox[s].ymax < c_bbox[c].ymin) || - (s_bbox[s].ymin > c_bbox[c].ymax))); - - /* For each clip contour, search for any subject contour overlaps */ - for (c= 0; c < clip->num_contours; c++) - { - overlap= 0; - for (s= 0; (!overlap) && (s < subj->num_contours); s++) - overlap= o_table[c * subj->num_contours + s]; - - if (!overlap) - /* Flag non contributing status by negating vertex count */ - clip->contour[c].num_vertices = -clip->contour[c].num_vertices; - } - - if (op == GPC_INT) - { - /* For each subject contour, search for any clip contour overlaps */ - for (s= 0; s < subj->num_contours; s++) - { - overlap= 0; - for (c= 0; (!overlap) && (c < clip->num_contours); c++) - overlap= o_table[c * subj->num_contours + s]; - - if (!overlap) - /* Flag non contributing status by negating vertex count */ - subj->contour[s].num_vertices = -subj->contour[s].num_vertices; - } - } - - FREE(s_bbox); - FREE(c_bbox); - FREE(o_table); -} - - -/* -=========================================================================== - Public Functions -=========================================================================== -*/ - -void gpc_free_polygon(gpc_polygon *p) -{ - int c; - - for (c= 0; c < p->num_contours; c++) - FREE(p->contour[c].vertex); - FREE(p->hole); - FREE(p->contour); - p->num_contours= 0; -} - - -void gpc_read_polygon(FILE *fp, int read_hole_flags, gpc_polygon *p) -{ - int c, v; - - fscanf(fp, "%d", &(p->num_contours)); - MALLOC(p->hole, p->num_contours * sizeof(int), - "hole flag array creation", int); - MALLOC(p->contour, p->num_contours - * sizeof(gpc_vertex_list), "contour creation", gpc_vertex_list); - for (c= 0; c < p->num_contours; c++) - { - fscanf(fp, "%d", &(p->contour[c].num_vertices)); - - if (read_hole_flags) - fscanf(fp, "%d", &(p->hole[c])); - else - p->hole[c]= FALSE; /* Assume all contours to be external */ - - MALLOC(p->contour[c].vertex, p->contour[c].num_vertices - * sizeof(gpc_vertex), "vertex creation", gpc_vertex); - for (v= 0; v < p->contour[c].num_vertices; v++) - fscanf(fp, "%lf %lf", &(p->contour[c].vertex[v].x), - &(p->contour[c].vertex[v].y)); - } -} - - -void gpc_write_polygon(FILE *fp, int write_hole_flags, gpc_polygon *p) -{ - int c, v; - - fprintf(fp, "%d\n", p->num_contours); - for (c= 0; c < p->num_contours; c++) - { - fprintf(fp, "%d\n", p->contour[c].num_vertices); - - if (write_hole_flags) - fprintf(fp, "%d\n", p->hole[c]); - - for (v= 0; v < p->contour[c].num_vertices; v++) - fprintf(fp, "% .*lf % .*lf\n", - DBL_DIG, p->contour[c].vertex[v].x, - DBL_DIG, p->contour[c].vertex[v].y); - } -} - - -void gpc_add_contour(gpc_polygon *p, gpc_vertex_list *new_contour, int hole) -{ - int *extended_hole, c, v; - gpc_vertex_list *extended_contour; - - /* Create an extended hole array */ - MALLOC(extended_hole, (p->num_contours + 1) - * sizeof(int), "contour hole addition", int); - - /* Create an extended contour array */ - MALLOC(extended_contour, (p->num_contours + 1) - * sizeof(gpc_vertex_list), "contour addition", gpc_vertex_list); - - /* Copy the old contour and hole data into the extended arrays */ - for (c= 0; c < p->num_contours; c++) - { - extended_hole[c]= p->hole[c]; - extended_contour[c]= p->contour[c]; - } - - /* Copy the new contour and hole onto the end of the extended arrays */ - c= p->num_contours; - extended_hole[c]= hole; - extended_contour[c].num_vertices= new_contour->num_vertices; - MALLOC(extended_contour[c].vertex, new_contour->num_vertices - * sizeof(gpc_vertex), "contour addition", gpc_vertex); - for (v= 0; v < new_contour->num_vertices; v++) - extended_contour[c].vertex[v]= new_contour->vertex[v]; - - /* Dispose of the old contour */ - FREE(p->contour); - FREE(p->hole); - - /* Update the polygon information */ - p->num_contours++; - p->hole= extended_hole; - p->contour= extended_contour; -} - - -void gpc_polygon_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, - gpc_polygon *result) -{ - sb_tree *sbtree= NULL; - it_node *it= NULL, *intersect; - edge_node *edge, *prev_edge, *next_edge, *succ_edge, *e0, *e1; - edge_node *aet= NULL, *c_heap= NULL, *s_heap= NULL; - lmt_node *lmt= NULL, *local_min; - polygon_node *out_poly= NULL, *p, *q, *poly, *npoly, *cf= NULL; - vertex_node *vtx, *nv; - h_state horiz[2]; - int in[2], exists[2], parity[2]= {LEFT, LEFT}; - int c, v, contributing, search, scanbeam= 0, sbt_entries= 0; - int vclass, bl, br, tl, tr; - double *sbt= NULL, xb, px, yb, yt, dy, ix, iy; - - /* Test for trivial NULL result cases */ - if (((subj->num_contours == 0) && (clip->num_contours == 0)) - || ((subj->num_contours == 0) && ((op == GPC_INT) || (op == GPC_DIFF))) - || ((clip->num_contours == 0) && (op == GPC_INT))) - { - result->num_contours= 0; - result->hole= NULL; - result->contour= NULL; - return; - } - - /* Identify potentialy contributing contours */ - if (((op == GPC_INT) || (op == GPC_DIFF)) - && (subj->num_contours > 0) && (clip->num_contours > 0)) - minimax_test(subj, clip, op); - - /* Build LMT */ - if (subj->num_contours > 0) - s_heap= build_lmt(&lmt, &sbtree, &sbt_entries, subj, SUBJ, op); - if (clip->num_contours > 0) - c_heap= build_lmt(&lmt, &sbtree, &sbt_entries, clip, CLIP, op); - - /* Return a NULL result if no contours contribute */ - if (lmt == NULL) - { - result->num_contours= 0; - result->hole= NULL; - result->contour= NULL; - reset_lmt(&lmt); - FREE(s_heap); - FREE(c_heap); - return; - } - - /* Build scanbeam table from scanbeam tree */ - MALLOC(sbt, sbt_entries * sizeof(double), "sbt creation", double); - build_sbt(&scanbeam, sbt, sbtree); - scanbeam= 0; - free_sbtree(&sbtree); - - /* Allow pointer re-use without causing memory leak */ - if (subj == result) - gpc_free_polygon(subj); - if (clip == result) - gpc_free_polygon(clip); - - /* Invert clip polygon for difference operation */ - if (op == GPC_DIFF) - parity[CLIP]= RIGHT; - - local_min= lmt; - - /* Process each scanbeam */ - while (scanbeam < sbt_entries) - { - /* Set yb and yt to the bottom and top of the scanbeam */ - yb= sbt[scanbeam++]; - if (scanbeam < sbt_entries) - { - yt= sbt[scanbeam]; - dy= yt - yb; - } - - /* === SCANBEAM BOUNDARY PROCESSING ================================ */ - - /* If LMT node corresponding to yb exists */ - if (local_min) - { - if (local_min->y == yb) - { - /* Add edges starting at this local minimum to the AET */ - for (edge= local_min->first_bound; edge; edge= edge->next_bound) - add_edge_to_aet(&aet, edge, NULL); - - local_min= local_min->next; - } - } - - /* Set dummy previous x value */ - px= -DBL_MAX; - - /* Create bundles within AET */ - e0= aet; - e1= aet; - - /* Set up bundle fields of first edge */ - aet->bundle[ABOVE][ aet->type]= (aet->top.y != yb); - aet->bundle[ABOVE][!aet->type]= FALSE; - aet->bstate[ABOVE]= UNBUNDLED; - - for (next_edge= aet->next; next_edge; next_edge= next_edge->next) - { - /* Set up bundle fields of next edge */ - next_edge->bundle[ABOVE][ next_edge->type]= (next_edge->top.y != yb); - next_edge->bundle[ABOVE][!next_edge->type]= FALSE; - next_edge->bstate[ABOVE]= UNBUNDLED; - - /* Bundle edges above the scanbeam boundary if they coincide */ - if (next_edge->bundle[ABOVE][next_edge->type]) - { - if (EQ(e0->xb, next_edge->xb) && EQ(e0->dx, next_edge->dx) - && (e0->top.y != yb)) - { - next_edge->bundle[ABOVE][ next_edge->type]^= - e0->bundle[ABOVE][ next_edge->type]; - next_edge->bundle[ABOVE][!next_edge->type]= - e0->bundle[ABOVE][!next_edge->type]; - next_edge->bstate[ABOVE]= BUNDLE_HEAD; - e0->bundle[ABOVE][CLIP]= FALSE; - e0->bundle[ABOVE][SUBJ]= FALSE; - e0->bstate[ABOVE]= BUNDLE_TAIL; - } - e0= next_edge; - } - } - - horiz[CLIP]= NH; - horiz[SUBJ]= NH; - - /* Process each edge at this scanbeam boundary */ - for (edge= aet; edge; edge= edge->next) - { - exists[CLIP]= edge->bundle[ABOVE][CLIP] + - (edge->bundle[BELOW][CLIP] << 1); - exists[SUBJ]= edge->bundle[ABOVE][SUBJ] + - (edge->bundle[BELOW][SUBJ] << 1); - - if (exists[CLIP] || exists[SUBJ]) - { - /* Set bundle side */ - edge->bside[CLIP]= parity[CLIP]; - edge->bside[SUBJ]= parity[SUBJ]; - - /* Determine contributing status and quadrant occupancies */ - switch (op) - { - case GPC_DIFF: - case GPC_INT: - contributing= (exists[CLIP] && (parity[SUBJ] || horiz[SUBJ])) - || (exists[SUBJ] && (parity[CLIP] || horiz[CLIP])) - || (exists[CLIP] && exists[SUBJ] - && (parity[CLIP] == parity[SUBJ])); - br= (parity[CLIP]) - && (parity[SUBJ]); - bl= (parity[CLIP] ^ edge->bundle[ABOVE][CLIP]) - && (parity[SUBJ] ^ edge->bundle[ABOVE][SUBJ]); - tr= (parity[CLIP] ^ (horiz[CLIP]!=NH)) - && (parity[SUBJ] ^ (horiz[SUBJ]!=NH)); - tl= (parity[CLIP] ^ (horiz[CLIP]!=NH) ^ edge->bundle[BELOW][CLIP]) - && (parity[SUBJ] ^ (horiz[SUBJ]!=NH) ^ edge->bundle[BELOW][SUBJ]); - break; - case GPC_XOR: - contributing= exists[CLIP] || exists[SUBJ]; - br= (parity[CLIP]) - ^ (parity[SUBJ]); - bl= (parity[CLIP] ^ edge->bundle[ABOVE][CLIP]) - ^ (parity[SUBJ] ^ edge->bundle[ABOVE][SUBJ]); - tr= (parity[CLIP] ^ (horiz[CLIP]!=NH)) - ^ (parity[SUBJ] ^ (horiz[SUBJ]!=NH)); - tl= (parity[CLIP] ^ (horiz[CLIP]!=NH) ^ edge->bundle[BELOW][CLIP]) - ^ (parity[SUBJ] ^ (horiz[SUBJ]!=NH) ^ edge->bundle[BELOW][SUBJ]); - break; - case GPC_UNION: - contributing= (exists[CLIP] && (!parity[SUBJ] || horiz[SUBJ])) - || (exists[SUBJ] && (!parity[CLIP] || horiz[CLIP])) - || (exists[CLIP] && exists[SUBJ] - && (parity[CLIP] == parity[SUBJ])); - br= (parity[CLIP]) - || (parity[SUBJ]); - bl= (parity[CLIP] ^ edge->bundle[ABOVE][CLIP]) - || (parity[SUBJ] ^ edge->bundle[ABOVE][SUBJ]); - tr= (parity[CLIP] ^ (horiz[CLIP]!=NH)) - || (parity[SUBJ] ^ (horiz[SUBJ]!=NH)); - tl= (parity[CLIP] ^ (horiz[CLIP]!=NH) ^ edge->bundle[BELOW][CLIP]) - || (parity[SUBJ] ^ (horiz[SUBJ]!=NH) ^ edge->bundle[BELOW][SUBJ]); - break; - } - - /* Update parity */ - parity[CLIP]^= edge->bundle[ABOVE][CLIP]; - parity[SUBJ]^= edge->bundle[ABOVE][SUBJ]; - - /* Update horizontal state */ - if (exists[CLIP]) - horiz[CLIP]= - next_h_state[horiz[CLIP]] - [((exists[CLIP] - 1) << 1) + parity[CLIP]]; - if (exists[SUBJ]) - horiz[SUBJ]= - next_h_state[horiz[SUBJ]] - [((exists[SUBJ] - 1) << 1) + parity[SUBJ]]; - - vclass= tr + (tl << 1) + (br << 2) + (bl << 3); - - if (contributing) - { - xb= edge->xb; - - switch (vclass) - { - case EMN: - case IMN: - add_local_min(&out_poly, edge, xb, yb); - px= xb; - cf= edge->outp[ABOVE]; - break; - case ERI: - if (xb != px) - { - add_right(cf, xb, yb); - px= xb; - } - edge->outp[ABOVE]= cf; - cf= NULL; - break; - case ELI: - add_left(edge->outp[BELOW], xb, yb); - px= xb; - cf= edge->outp[BELOW]; - break; - case EMX: - if (xb != px) - { - add_left(cf, xb, yb); - px= xb; - } - merge_right(cf, edge->outp[BELOW], out_poly); - cf= NULL; - break; - case ILI: - if (xb != px) - { - add_left(cf, xb, yb); - px= xb; - } - edge->outp[ABOVE]= cf; - cf= NULL; - break; - case IRI: - add_right(edge->outp[BELOW], xb, yb); - px= xb; - cf= edge->outp[BELOW]; - edge->outp[BELOW]= NULL; - break; - case IMX: - if (xb != px) - { - add_right(cf, xb, yb); - px= xb; - } - merge_left(cf, edge->outp[BELOW], out_poly); - cf= NULL; - edge->outp[BELOW]= NULL; - break; - case IMM: - if (xb != px) - { - add_right(cf, xb, yb); - px= xb; - } - merge_left(cf, edge->outp[BELOW], out_poly); - edge->outp[BELOW]= NULL; - add_local_min(&out_poly, edge, xb, yb); - cf= edge->outp[ABOVE]; - break; - case EMM: - if (xb != px) - { - add_left(cf, xb, yb); - px= xb; - } - merge_right(cf, edge->outp[BELOW], out_poly); - edge->outp[BELOW]= NULL; - add_local_min(&out_poly, edge, xb, yb); - cf= edge->outp[ABOVE]; - break; - case LED: - if (edge->bot.y == yb) - add_left(edge->outp[BELOW], xb, yb); - edge->outp[ABOVE]= edge->outp[BELOW]; - px= xb; - break; - case RED: - if (edge->bot.y == yb) - add_right(edge->outp[BELOW], xb, yb); - edge->outp[ABOVE]= edge->outp[BELOW]; - px= xb; - break; - default: - break; - } /* End of switch */ - } /* End of contributing conditional */ - } /* End of edge exists conditional */ - } /* End of AET loop */ - - /* Delete terminating edges from the AET, otherwise compute xt */ - for (edge= aet; edge; edge= edge->next) - { - if (edge->top.y == yb) - { - prev_edge= edge->prev; - next_edge= edge->next; - if (prev_edge) - prev_edge->next= next_edge; - else - aet= next_edge; - if (next_edge) - next_edge->prev= prev_edge; - - /* Copy bundle head state to the adjacent tail edge if required */ - if ((edge->bstate[BELOW] == BUNDLE_HEAD) && prev_edge) - { - if (prev_edge->bstate[BELOW] == BUNDLE_TAIL) - { - prev_edge->outp[BELOW]= edge->outp[BELOW]; - prev_edge->bstate[BELOW]= UNBUNDLED; - if (prev_edge->prev) - if (prev_edge->prev->bstate[BELOW] == BUNDLE_TAIL) - prev_edge->bstate[BELOW]= BUNDLE_HEAD; - } - } - } - else - { - if (edge->top.y == yt) - edge->xt= edge->top.x; - else - edge->xt= edge->bot.x + edge->dx * (yt - edge->bot.y); - } - } - - if (scanbeam < sbt_entries) - { - /* === SCANBEAM INTERIOR PROCESSING ============================== */ - - build_intersection_table(&it, aet, dy); - - /* Process each node in the intersection table */ - for (intersect= it; intersect; intersect= intersect->next) - { - e0= intersect->ie[0]; - e1= intersect->ie[1]; - - /* Only generate output for contributing intersections */ - if ((e0->bundle[ABOVE][CLIP] || e0->bundle[ABOVE][SUBJ]) - && (e1->bundle[ABOVE][CLIP] || e1->bundle[ABOVE][SUBJ])) - { - p= e0->outp[ABOVE]; - q= e1->outp[ABOVE]; - ix= intersect->point.x; - iy= intersect->point.y + yb; - - in[CLIP]= ( e0->bundle[ABOVE][CLIP] && !e0->bside[CLIP]) - || ( e1->bundle[ABOVE][CLIP] && e1->bside[CLIP]) - || (!e0->bundle[ABOVE][CLIP] && !e1->bundle[ABOVE][CLIP] - && e0->bside[CLIP] && e1->bside[CLIP]); - in[SUBJ]= ( e0->bundle[ABOVE][SUBJ] && !e0->bside[SUBJ]) - || ( e1->bundle[ABOVE][SUBJ] && e1->bside[SUBJ]) - || (!e0->bundle[ABOVE][SUBJ] && !e1->bundle[ABOVE][SUBJ] - && e0->bside[SUBJ] && e1->bside[SUBJ]); - - /* Determine quadrant occupancies */ - switch (op) - { - case GPC_DIFF: - case GPC_INT: - tr= (in[CLIP]) - && (in[SUBJ]); - tl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP]) - && (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ]); - br= (in[CLIP] ^ e0->bundle[ABOVE][CLIP]) - && (in[SUBJ] ^ e0->bundle[ABOVE][SUBJ]); - bl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP] ^ e0->bundle[ABOVE][CLIP]) - && (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ] ^ e0->bundle[ABOVE][SUBJ]); - break; - case GPC_XOR: - tr= (in[CLIP]) - ^ (in[SUBJ]); - tl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP]) - ^ (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ]); - br= (in[CLIP] ^ e0->bundle[ABOVE][CLIP]) - ^ (in[SUBJ] ^ e0->bundle[ABOVE][SUBJ]); - bl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP] ^ e0->bundle[ABOVE][CLIP]) - ^ (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ] ^ e0->bundle[ABOVE][SUBJ]); - break; - case GPC_UNION: - tr= (in[CLIP]) - || (in[SUBJ]); - tl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP]) - || (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ]); - br= (in[CLIP] ^ e0->bundle[ABOVE][CLIP]) - || (in[SUBJ] ^ e0->bundle[ABOVE][SUBJ]); - bl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP] ^ e0->bundle[ABOVE][CLIP]) - || (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ] ^ e0->bundle[ABOVE][SUBJ]); - break; - } - - vclass= tr + (tl << 1) + (br << 2) + (bl << 3); - - switch (vclass) - { - case EMN: - add_local_min(&out_poly, e0, ix, iy); - e1->outp[ABOVE]= e0->outp[ABOVE]; - break; - case ERI: - if (p) - { - add_right(p, ix, iy); - e1->outp[ABOVE]= p; - e0->outp[ABOVE]= NULL; - } - break; - case ELI: - if (q) - { - add_left(q, ix, iy); - e0->outp[ABOVE]= q; - e1->outp[ABOVE]= NULL; - } - break; - case EMX: - if (p && q) - { - add_left(p, ix, iy); - merge_right(p, q, out_poly); - e0->outp[ABOVE]= NULL; - e1->outp[ABOVE]= NULL; - } - break; - case IMN: - add_local_min(&out_poly, e0, ix, iy); - e1->outp[ABOVE]= e0->outp[ABOVE]; - break; - case ILI: - if (p) - { - add_left(p, ix, iy); - e1->outp[ABOVE]= p; - e0->outp[ABOVE]= NULL; - } - break; - case IRI: - if (q) - { - add_right(q, ix, iy); - e0->outp[ABOVE]= q; - e1->outp[ABOVE]= NULL; - } - break; - case IMX: - if (p && q) - { - add_right(p, ix, iy); - merge_left(p, q, out_poly); - e0->outp[ABOVE]= NULL; - e1->outp[ABOVE]= NULL; - } - break; - case IMM: - if (p && q) - { - add_right(p, ix, iy); - merge_left(p, q, out_poly); - add_local_min(&out_poly, e0, ix, iy); - e1->outp[ABOVE]= e0->outp[ABOVE]; - } - break; - case EMM: - if (p && q) - { - add_left(p, ix, iy); - merge_right(p, q, out_poly); - add_local_min(&out_poly, e0, ix, iy); - e1->outp[ABOVE]= e0->outp[ABOVE]; - } - break; - default: - break; - } /* End of switch */ - } /* End of contributing intersection conditional */ - - /* Swap bundle sides in response to edge crossing */ - if (e0->bundle[ABOVE][CLIP]) - e1->bside[CLIP]= !e1->bside[CLIP]; - if (e1->bundle[ABOVE][CLIP]) - e0->bside[CLIP]= !e0->bside[CLIP]; - if (e0->bundle[ABOVE][SUBJ]) - e1->bside[SUBJ]= !e1->bside[SUBJ]; - if (e1->bundle[ABOVE][SUBJ]) - e0->bside[SUBJ]= !e0->bside[SUBJ]; - - /* Swap e0 and e1 bundles in the AET */ - prev_edge= e0->prev; - next_edge= e1->next; - if (next_edge) - next_edge->prev= e0; - - if (e0->bstate[ABOVE] == BUNDLE_HEAD) - { - search= TRUE; - while (search) - { - prev_edge= prev_edge->prev; - if (prev_edge) - { - if (prev_edge->bstate[ABOVE] != BUNDLE_TAIL) - search= FALSE; - } - else - search= FALSE; - } - } - if (!prev_edge) - { - aet->prev= e1; - e1->next= aet; - aet= e0->next; - } - else - { - prev_edge->next->prev= e1; - e1->next= prev_edge->next; - prev_edge->next= e0->next; - } - e0->next->prev= prev_edge; - e1->next->prev= e1; - e0->next= next_edge; - } /* End of IT loop*/ - - /* Prepare for next scanbeam */ - for (edge= aet; edge; edge= next_edge) - { - next_edge= edge->next; - succ_edge= edge->succ; - - if ((edge->top.y == yt) && succ_edge) - { - /* Replace AET edge by its successor */ - succ_edge->outp[BELOW]= edge->outp[ABOVE]; - succ_edge->bstate[BELOW]= edge->bstate[ABOVE]; - succ_edge->bundle[BELOW][CLIP]= edge->bundle[ABOVE][CLIP]; - succ_edge->bundle[BELOW][SUBJ]= edge->bundle[ABOVE][SUBJ]; - prev_edge= edge->prev; - if (prev_edge) - prev_edge->next= succ_edge; - else - aet= succ_edge; - if (next_edge) - next_edge->prev= succ_edge; - succ_edge->prev= prev_edge; - succ_edge->next= next_edge; - } - else - { - /* Update this edge */ - edge->outp[BELOW]= edge->outp[ABOVE]; - edge->bstate[BELOW]= edge->bstate[ABOVE]; - edge->bundle[BELOW][CLIP]= edge->bundle[ABOVE][CLIP]; - edge->bundle[BELOW][SUBJ]= edge->bundle[ABOVE][SUBJ]; - edge->xb= edge->xt; - } - edge->outp[ABOVE]= NULL; - } - } - } /* === END OF SCANBEAM PROCESSING ================================== */ - - /* Generate result polygon from out_poly */ - result->contour= NULL; - result->hole= NULL; - result->num_contours= count_contours(out_poly); - if (result->num_contours > 0) - { - MALLOC(result->hole, result->num_contours - * sizeof(int), "hole flag table creation", int); - MALLOC(result->contour, result->num_contours - * sizeof(gpc_vertex_list), "contour creation", gpc_vertex_list); - - c= 0; - for (poly= out_poly; poly; poly= npoly) - { - npoly= poly->next; - if (poly->active) - { - result->hole[c]= poly->proxy->hole; - result->contour[c].num_vertices= poly->active; - MALLOC(result->contour[c].vertex, - result->contour[c].num_vertices * sizeof(gpc_vertex), - "vertex creation", gpc_vertex); - - v= result->contour[c].num_vertices - 1; - for (vtx= poly->proxy->v[LEFT]; vtx; vtx= nv) - { - nv= vtx->next; - result->contour[c].vertex[v].x= vtx->x; - result->contour[c].vertex[v].y= vtx->y; - FREE(vtx); - v--; - } - c++; - } - FREE(poly); - } - } - else - { - for (poly= out_poly; poly; poly= npoly) - { - npoly= poly->next; - FREE(poly); - } - } - - /* Tidy up */ - reset_it(&it); - reset_lmt(&lmt); - FREE(c_heap); - FREE(s_heap); - FREE(sbt); -} - - -void gpc_free_tristrip(gpc_tristrip *t) -{ - int s; - - for (s= 0; s < t->num_strips; s++) - FREE(t->strip[s].vertex); - FREE(t->strip); - t->num_strips= 0; -} - - -void gpc_polygon_to_tristrip(gpc_polygon *s, gpc_tristrip *t) -{ - gpc_polygon c; - - c.num_contours= 0; - c.hole= NULL; - c.contour= NULL; - gpc_tristrip_clip(GPC_DIFF, s, &c, t); -} - - -void gpc_tristrip_clip(gpc_op op, gpc_polygon *subj, gpc_polygon *clip, - gpc_tristrip *result) -{ - sb_tree *sbtree= NULL; - it_node *it= NULL, *intersect; - edge_node *edge, *prev_edge, *next_edge, *succ_edge, *e0, *e1; - edge_node *aet= NULL, *c_heap= NULL, *s_heap= NULL, *cf; - lmt_node *lmt= NULL, *local_min; - polygon_node *tlist= NULL, *tn, *tnn, *p, *q; - vertex_node *lt, *ltn, *rt, *rtn; - h_state horiz[2]; - vertex_type cft; - int in[2], exists[2], parity[2]= {LEFT, LEFT}; - int s, v, contributing, search, scanbeam= 0, sbt_entries= 0; - int vclass, bl, br, tl, tr; - double *sbt= NULL, xb, px, nx, yb, yt, dy, ix, iy; - - /* Test for trivial NULL result cases */ - if (((subj->num_contours == 0) && (clip->num_contours == 0)) - || ((subj->num_contours == 0) && ((op == GPC_INT) || (op == GPC_DIFF))) - || ((clip->num_contours == 0) && (op == GPC_INT))) - { - result->num_strips= 0; - result->strip= NULL; - return; - } - - /* Identify potentialy contributing contours */ - if (((op == GPC_INT) || (op == GPC_DIFF)) - && (subj->num_contours > 0) && (clip->num_contours > 0)) - minimax_test(subj, clip, op); - - /* Build LMT */ - if (subj->num_contours > 0) - s_heap= build_lmt(&lmt, &sbtree, &sbt_entries, subj, SUBJ, op); - if (clip->num_contours > 0) - c_heap= build_lmt(&lmt, &sbtree, &sbt_entries, clip, CLIP, op); - - /* Return a NULL result if no contours contribute */ - if (lmt == NULL) - { - result->num_strips= 0; - result->strip= NULL; - reset_lmt(&lmt); - FREE(s_heap); - FREE(c_heap); - return; - } - - /* Build scanbeam table from scanbeam tree */ - MALLOC(sbt, sbt_entries * sizeof(double), "sbt creation", double); - build_sbt(&scanbeam, sbt, sbtree); - scanbeam= 0; - free_sbtree(&sbtree); - - /* Invert clip polygon for difference operation */ - if (op == GPC_DIFF) - parity[CLIP]= RIGHT; - - local_min= lmt; - - /* Process each scanbeam */ - while (scanbeam < sbt_entries) - { - /* Set yb and yt to the bottom and top of the scanbeam */ - yb= sbt[scanbeam++]; - if (scanbeam < sbt_entries) - { - yt= sbt[scanbeam]; - dy= yt - yb; - } - - /* === SCANBEAM BOUNDARY PROCESSING ================================ */ - - /* If LMT node corresponding to yb exists */ - if (local_min) - { - if (local_min->y == yb) - { - /* Add edges starting at this local minimum to the AET */ - for (edge= local_min->first_bound; edge; edge= edge->next_bound) - add_edge_to_aet(&aet, edge, NULL); - - local_min= local_min->next; - } - } - - /* Set dummy previous x value */ - px= -DBL_MAX; - - /* Create bundles within AET */ - e0= aet; - e1= aet; - - /* Set up bundle fields of first edge */ - aet->bundle[ABOVE][ aet->type]= (aet->top.y != yb); - aet->bundle[ABOVE][!aet->type]= FALSE; - aet->bstate[ABOVE]= UNBUNDLED; - - for (next_edge= aet->next; next_edge; next_edge= next_edge->next) - { - /* Set up bundle fields of next edge */ - next_edge->bundle[ABOVE][ next_edge->type]= (next_edge->top.y != yb); - next_edge->bundle[ABOVE][!next_edge->type]= FALSE; - next_edge->bstate[ABOVE]= UNBUNDLED; - - /* Bundle edges above the scanbeam boundary if they coincide */ - if (next_edge->bundle[ABOVE][next_edge->type]) - { - if (EQ(e0->xb, next_edge->xb) && EQ(e0->dx, next_edge->dx) - && (e0->top.y != yb)) - { - next_edge->bundle[ABOVE][ next_edge->type]^= - e0->bundle[ABOVE][ next_edge->type]; - next_edge->bundle[ABOVE][!next_edge->type]= - e0->bundle[ABOVE][!next_edge->type]; - next_edge->bstate[ABOVE]= BUNDLE_HEAD; - e0->bundle[ABOVE][CLIP]= FALSE; - e0->bundle[ABOVE][SUBJ]= FALSE; - e0->bstate[ABOVE]= BUNDLE_TAIL; - } - e0= next_edge; - } - } - - horiz[CLIP]= NH; - horiz[SUBJ]= NH; - - /* Process each edge at this scanbeam boundary */ - for (edge= aet; edge; edge= edge->next) - { - exists[CLIP]= edge->bundle[ABOVE][CLIP] + - (edge->bundle[BELOW][CLIP] << 1); - exists[SUBJ]= edge->bundle[ABOVE][SUBJ] + - (edge->bundle[BELOW][SUBJ] << 1); - - if (exists[CLIP] || exists[SUBJ]) - { - /* Set bundle side */ - edge->bside[CLIP]= parity[CLIP]; - edge->bside[SUBJ]= parity[SUBJ]; - - /* Determine contributing status and quadrant occupancies */ - switch (op) - { - case GPC_DIFF: - case GPC_INT: - contributing= (exists[CLIP] && (parity[SUBJ] || horiz[SUBJ])) - || (exists[SUBJ] && (parity[CLIP] || horiz[CLIP])) - || (exists[CLIP] && exists[SUBJ] - && (parity[CLIP] == parity[SUBJ])); - br= (parity[CLIP]) - && (parity[SUBJ]); - bl= (parity[CLIP] ^ edge->bundle[ABOVE][CLIP]) - && (parity[SUBJ] ^ edge->bundle[ABOVE][SUBJ]); - tr= (parity[CLIP] ^ (horiz[CLIP]!=NH)) - && (parity[SUBJ] ^ (horiz[SUBJ]!=NH)); - tl= (parity[CLIP] ^ (horiz[CLIP]!=NH) ^ edge->bundle[BELOW][CLIP]) - && (parity[SUBJ] ^ (horiz[SUBJ]!=NH) ^ edge->bundle[BELOW][SUBJ]); - break; - case GPC_XOR: - contributing= exists[CLIP] || exists[SUBJ]; - br= (parity[CLIP]) - ^ (parity[SUBJ]); - bl= (parity[CLIP] ^ edge->bundle[ABOVE][CLIP]) - ^ (parity[SUBJ] ^ edge->bundle[ABOVE][SUBJ]); - tr= (parity[CLIP] ^ (horiz[CLIP]!=NH)) - ^ (parity[SUBJ] ^ (horiz[SUBJ]!=NH)); - tl= (parity[CLIP] ^ (horiz[CLIP]!=NH) ^ edge->bundle[BELOW][CLIP]) - ^ (parity[SUBJ] ^ (horiz[SUBJ]!=NH) ^ edge->bundle[BELOW][SUBJ]); - break; - case GPC_UNION: - contributing= (exists[CLIP] && (!parity[SUBJ] || horiz[SUBJ])) - || (exists[SUBJ] && (!parity[CLIP] || horiz[CLIP])) - || (exists[CLIP] && exists[SUBJ] - && (parity[CLIP] == parity[SUBJ])); - br= (parity[CLIP]) - || (parity[SUBJ]); - bl= (parity[CLIP] ^ edge->bundle[ABOVE][CLIP]) - || (parity[SUBJ] ^ edge->bundle[ABOVE][SUBJ]); - tr= (parity[CLIP] ^ (horiz[CLIP]!=NH)) - || (parity[SUBJ] ^ (horiz[SUBJ]!=NH)); - tl= (parity[CLIP] ^ (horiz[CLIP]!=NH) ^ edge->bundle[BELOW][CLIP]) - || (parity[SUBJ] ^ (horiz[SUBJ]!=NH) ^ edge->bundle[BELOW][SUBJ]); - break; - } - - /* Update parity */ - parity[CLIP]^= edge->bundle[ABOVE][CLIP]; - parity[SUBJ]^= edge->bundle[ABOVE][SUBJ]; - - /* Update horizontal state */ - if (exists[CLIP]) - horiz[CLIP]= - next_h_state[horiz[CLIP]] - [((exists[CLIP] - 1) << 1) + parity[CLIP]]; - if (exists[SUBJ]) - horiz[SUBJ]= - next_h_state[horiz[SUBJ]] - [((exists[SUBJ] - 1) << 1) + parity[SUBJ]]; - - vclass= tr + (tl << 1) + (br << 2) + (bl << 3); - - if (contributing) - { - xb= edge->xb; - - switch (vclass) - { - case EMN: - new_tristrip(&tlist, edge, xb, yb); - cf= edge; - break; - case ERI: - edge->outp[ABOVE]= cf->outp[ABOVE]; - if (xb != cf->xb) - VERTEX(edge, ABOVE, RIGHT, xb, yb); - cf= NULL; - break; - case ELI: - VERTEX(edge, BELOW, LEFT, xb, yb); - edge->outp[ABOVE]= NULL; - cf= edge; - break; - case EMX: - if (xb != cf->xb) - VERTEX(edge, BELOW, RIGHT, xb, yb); - edge->outp[ABOVE]= NULL; - cf= NULL; - break; - case IMN: - if (cft == LED) - { - if (cf->bot.y != yb) - VERTEX(cf, BELOW, LEFT, cf->xb, yb); - new_tristrip(&tlist, cf, cf->xb, yb); - } - edge->outp[ABOVE]= cf->outp[ABOVE]; - VERTEX(edge, ABOVE, RIGHT, xb, yb); - break; - case ILI: - new_tristrip(&tlist, edge, xb, yb); - cf= edge; - cft= ILI; - break; - case IRI: - if (cft == LED) - { - if (cf->bot.y != yb) - VERTEX(cf, BELOW, LEFT, cf->xb, yb); - new_tristrip(&tlist, cf, cf->xb, yb); - } - VERTEX(edge, BELOW, RIGHT, xb, yb); - edge->outp[ABOVE]= NULL; - break; - case IMX: - VERTEX(edge, BELOW, LEFT, xb, yb); - edge->outp[ABOVE]= NULL; - cft= IMX; - break; - case IMM: - VERTEX(edge, BELOW, LEFT, xb, yb); - edge->outp[ABOVE]= cf->outp[ABOVE]; - if (xb != cf->xb) - VERTEX(cf, ABOVE, RIGHT, xb, yb); - cf= edge; - break; - case EMM: - VERTEX(edge, BELOW, RIGHT, xb, yb); - edge->outp[ABOVE]= NULL; - new_tristrip(&tlist, edge, xb, yb); - cf= edge; - break; - case LED: - if (edge->bot.y == yb) - VERTEX(edge, BELOW, LEFT, xb, yb); - edge->outp[ABOVE]= edge->outp[BELOW]; - cf= edge; - cft= LED; - break; - case RED: - edge->outp[ABOVE]= cf->outp[ABOVE]; - if (cft == LED) - { - if (cf->bot.y == yb) - { - VERTEX(edge, BELOW, RIGHT, xb, yb); - } - else - { - if (edge->bot.y == yb) - { - VERTEX(cf, BELOW, LEFT, cf->xb, yb); - VERTEX(edge, BELOW, RIGHT, xb, yb); - } - } - } - else - { - VERTEX(edge, BELOW, RIGHT, xb, yb); - VERTEX(edge, ABOVE, RIGHT, xb, yb); - } - cf= NULL; - break; - default: - break; - } /* End of switch */ - } /* End of contributing conditional */ - } /* End of edge exists conditional */ - } /* End of AET loop */ - - /* Delete terminating edges from the AET, otherwise compute xt */ - for (edge= aet; edge; edge= edge->next) - { - if (edge->top.y == yb) - { - prev_edge= edge->prev; - next_edge= edge->next; - if (prev_edge) - prev_edge->next= next_edge; - else - aet= next_edge; - if (next_edge) - next_edge->prev= prev_edge; - - /* Copy bundle head state to the adjacent tail edge if required */ - if ((edge->bstate[BELOW] == BUNDLE_HEAD) && prev_edge) - { - if (prev_edge->bstate[BELOW] == BUNDLE_TAIL) - { - prev_edge->outp[BELOW]= edge->outp[BELOW]; - prev_edge->bstate[BELOW]= UNBUNDLED; - if (prev_edge->prev) - if (prev_edge->prev->bstate[BELOW] == BUNDLE_TAIL) - prev_edge->bstate[BELOW]= BUNDLE_HEAD; - } - } - } - else - { - if (edge->top.y == yt) - edge->xt= edge->top.x; - else - edge->xt= edge->bot.x + edge->dx * (yt - edge->bot.y); - } - } - - if (scanbeam < sbt_entries) - { - /* === SCANBEAM INTERIOR PROCESSING ============================== */ - - build_intersection_table(&it, aet, dy); - - /* Process each node in the intersection table */ - for (intersect= it; intersect; intersect= intersect->next) - { - e0= intersect->ie[0]; - e1= intersect->ie[1]; - - /* Only generate output for contributing intersections */ - if ((e0->bundle[ABOVE][CLIP] || e0->bundle[ABOVE][SUBJ]) - && (e1->bundle[ABOVE][CLIP] || e1->bundle[ABOVE][SUBJ])) - { - p= e0->outp[ABOVE]; - q= e1->outp[ABOVE]; - ix= intersect->point.x; - iy= intersect->point.y + yb; - - in[CLIP]= ( e0->bundle[ABOVE][CLIP] && !e0->bside[CLIP]) - || ( e1->bundle[ABOVE][CLIP] && e1->bside[CLIP]) - || (!e0->bundle[ABOVE][CLIP] && !e1->bundle[ABOVE][CLIP] - && e0->bside[CLIP] && e1->bside[CLIP]); - in[SUBJ]= ( e0->bundle[ABOVE][SUBJ] && !e0->bside[SUBJ]) - || ( e1->bundle[ABOVE][SUBJ] && e1->bside[SUBJ]) - || (!e0->bundle[ABOVE][SUBJ] && !e1->bundle[ABOVE][SUBJ] - && e0->bside[SUBJ] && e1->bside[SUBJ]); - - /* Determine quadrant occupancies */ - switch (op) - { - case GPC_DIFF: - case GPC_INT: - tr= (in[CLIP]) - && (in[SUBJ]); - tl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP]) - && (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ]); - br= (in[CLIP] ^ e0->bundle[ABOVE][CLIP]) - && (in[SUBJ] ^ e0->bundle[ABOVE][SUBJ]); - bl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP] ^ e0->bundle[ABOVE][CLIP]) - && (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ] ^ e0->bundle[ABOVE][SUBJ]); - break; - case GPC_XOR: - tr= (in[CLIP]) - ^ (in[SUBJ]); - tl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP]) - ^ (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ]); - br= (in[CLIP] ^ e0->bundle[ABOVE][CLIP]) - ^ (in[SUBJ] ^ e0->bundle[ABOVE][SUBJ]); - bl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP] ^ e0->bundle[ABOVE][CLIP]) - ^ (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ] ^ e0->bundle[ABOVE][SUBJ]); - break; - case GPC_UNION: - tr= (in[CLIP]) - || (in[SUBJ]); - tl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP]) - || (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ]); - br= (in[CLIP] ^ e0->bundle[ABOVE][CLIP]) - || (in[SUBJ] ^ e0->bundle[ABOVE][SUBJ]); - bl= (in[CLIP] ^ e1->bundle[ABOVE][CLIP] ^ e0->bundle[ABOVE][CLIP]) - || (in[SUBJ] ^ e1->bundle[ABOVE][SUBJ] ^ e0->bundle[ABOVE][SUBJ]); - break; - } - - vclass= tr + (tl << 1) + (br << 2) + (bl << 3); - - switch (vclass) - { - case EMN: - new_tristrip(&tlist, e1, ix, iy); - e0->outp[ABOVE]= e1->outp[ABOVE]; - break; - case ERI: - if (p) - { - P_EDGE(prev_edge, e0, ABOVE, px, iy); - VERTEX(prev_edge, ABOVE, LEFT, px, iy); - VERTEX(e0, ABOVE, RIGHT, ix, iy); - e1->outp[ABOVE]= e0->outp[ABOVE]; - e0->outp[ABOVE]= NULL; - } - break; - case ELI: - if (q) - { - N_EDGE(next_edge, e1, ABOVE, nx, iy); - VERTEX(e1, ABOVE, LEFT, ix, iy); - VERTEX(next_edge, ABOVE, RIGHT, nx, iy); - e0->outp[ABOVE]= e1->outp[ABOVE]; - e1->outp[ABOVE]= NULL; - } - break; - case EMX: - if (p && q) - { - VERTEX(e0, ABOVE, LEFT, ix, iy); - e0->outp[ABOVE]= NULL; - e1->outp[ABOVE]= NULL; - } - break; - case IMN: - P_EDGE(prev_edge, e0, ABOVE, px, iy); - VERTEX(prev_edge, ABOVE, LEFT, px, iy); - N_EDGE(next_edge, e1, ABOVE, nx, iy); - VERTEX(next_edge, ABOVE, RIGHT, nx, iy); - new_tristrip(&tlist, prev_edge, px, iy); - e1->outp[ABOVE]= prev_edge->outp[ABOVE]; - VERTEX(e1, ABOVE, RIGHT, ix, iy); - new_tristrip(&tlist, e0, ix, iy); - next_edge->outp[ABOVE]= e0->outp[ABOVE]; - VERTEX(next_edge, ABOVE, RIGHT, nx, iy); - break; - case ILI: - if (p) - { - VERTEX(e0, ABOVE, LEFT, ix, iy); - N_EDGE(next_edge, e1, ABOVE, nx, iy); - VERTEX(next_edge, ABOVE, RIGHT, nx, iy); - e1->outp[ABOVE]= e0->outp[ABOVE]; - e0->outp[ABOVE]= NULL; - } - break; - case IRI: - if (q) - { - VERTEX(e1, ABOVE, RIGHT, ix, iy); - P_EDGE(prev_edge, e0, ABOVE, px, iy); - VERTEX(prev_edge, ABOVE, LEFT, px, iy); - e0->outp[ABOVE]= e1->outp[ABOVE]; - e1->outp[ABOVE]= NULL; - } - break; - case IMX: - if (p && q) - { - VERTEX(e0, ABOVE, RIGHT, ix, iy); - VERTEX(e1, ABOVE, LEFT, ix, iy); - e0->outp[ABOVE]= NULL; - e1->outp[ABOVE]= NULL; - P_EDGE(prev_edge, e0, ABOVE, px, iy); - VERTEX(prev_edge, ABOVE, LEFT, px, iy); - new_tristrip(&tlist, prev_edge, px, iy); - N_EDGE(next_edge, e1, ABOVE, nx, iy); - VERTEX(next_edge, ABOVE, RIGHT, nx, iy); - next_edge->outp[ABOVE]= prev_edge->outp[ABOVE]; - VERTEX(next_edge, ABOVE, RIGHT, nx, iy); - } - break; - case IMM: - if (p && q) - { - VERTEX(e0, ABOVE, RIGHT, ix, iy); - VERTEX(e1, ABOVE, LEFT, ix, iy); - P_EDGE(prev_edge, e0, ABOVE, px, iy); - VERTEX(prev_edge, ABOVE, LEFT, px, iy); - new_tristrip(&tlist, prev_edge, px, iy); - N_EDGE(next_edge, e1, ABOVE, nx, iy); - VERTEX(next_edge, ABOVE, RIGHT, nx, iy); - e1->outp[ABOVE]= prev_edge->outp[ABOVE]; - VERTEX(e1, ABOVE, RIGHT, ix, iy); - new_tristrip(&tlist, e0, ix, iy); - next_edge->outp[ABOVE]= e0->outp[ABOVE]; - VERTEX(next_edge, ABOVE, RIGHT, nx, iy); - } - break; - case EMM: - if (p && q) - { - VERTEX(e0, ABOVE, LEFT, ix, iy); - new_tristrip(&tlist, e1, ix, iy); - e0->outp[ABOVE]= e1->outp[ABOVE]; - } - break; - default: - break; - } /* End of switch */ - } /* End of contributing intersection conditional */ - - /* Swap bundle sides in response to edge crossing */ - if (e0->bundle[ABOVE][CLIP]) - e1->bside[CLIP]= !e1->bside[CLIP]; - if (e1->bundle[ABOVE][CLIP]) - e0->bside[CLIP]= !e0->bside[CLIP]; - if (e0->bundle[ABOVE][SUBJ]) - e1->bside[SUBJ]= !e1->bside[SUBJ]; - if (e1->bundle[ABOVE][SUBJ]) - e0->bside[SUBJ]= !e0->bside[SUBJ]; - - /* Swap e0 and e1 bundles in the AET */ - prev_edge= e0->prev; - next_edge= e1->next; - if (e1->next) - e1->next->prev= e0; - - if (e0->bstate[ABOVE] == BUNDLE_HEAD) - { - search= TRUE; - while (search) - { - prev_edge= prev_edge->prev; - if (prev_edge) - { - if (prev_edge->bundle[ABOVE][CLIP] - || prev_edge->bundle[ABOVE][SUBJ] - || (prev_edge->bstate[ABOVE] == BUNDLE_HEAD)) - search= FALSE; - } - else - search= FALSE; - } - } - if (!prev_edge) - { - e1->next= aet; - aet= e0->next; - } - else - { - e1->next= prev_edge->next; - prev_edge->next= e0->next; - } - e0->next->prev= prev_edge; - e1->next->prev= e1; - e0->next= next_edge; - } /* End of IT loop*/ - - /* Prepare for next scanbeam */ - for (edge= aet; edge; edge= next_edge) - { - next_edge= edge->next; - succ_edge= edge->succ; - - if ((edge->top.y == yt) && succ_edge) - { - /* Replace AET edge by its successor */ - succ_edge->outp[BELOW]= edge->outp[ABOVE]; - succ_edge->bstate[BELOW]= edge->bstate[ABOVE]; - succ_edge->bundle[BELOW][CLIP]= edge->bundle[ABOVE][CLIP]; - succ_edge->bundle[BELOW][SUBJ]= edge->bundle[ABOVE][SUBJ]; - prev_edge= edge->prev; - if (prev_edge) - prev_edge->next= succ_edge; - else - aet= succ_edge; - if (next_edge) - next_edge->prev= succ_edge; - succ_edge->prev= prev_edge; - succ_edge->next= next_edge; - } - else - { - /* Update this edge */ - edge->outp[BELOW]= edge->outp[ABOVE]; - edge->bstate[BELOW]= edge->bstate[ABOVE]; - edge->bundle[BELOW][CLIP]= edge->bundle[ABOVE][CLIP]; - edge->bundle[BELOW][SUBJ]= edge->bundle[ABOVE][SUBJ]; - edge->xb= edge->xt; - } - edge->outp[ABOVE]= NULL; - } - } - } /* === END OF SCANBEAM PROCESSING ================================== */ - - /* Generate result tristrip from tlist */ - result->strip= NULL; - result->num_strips= count_tristrips(tlist); - if (result->num_strips > 0) - { - MALLOC(result->strip, result->num_strips * sizeof(gpc_vertex_list), - "tristrip list creation", gpc_vertex_list); - - s= 0; - for (tn= tlist; tn; tn= tnn) - { - tnn= tn->next; - - if (tn->active > 2) - { - /* Valid tristrip: copy the vertices and free the heap */ - result->strip[s].num_vertices= tn->active; - MALLOC(result->strip[s].vertex, tn->active * sizeof(gpc_vertex), - "tristrip creation", gpc_vertex); - v= 0; - if (INVERT_TRISTRIPS) - { - lt= tn->v[RIGHT]; - rt= tn->v[LEFT]; - } - else - { - lt= tn->v[LEFT]; - rt= tn->v[RIGHT]; - } - while (lt || rt) - { - if (lt) - { - ltn= lt->next; - result->strip[s].vertex[v].x= lt->x; - result->strip[s].vertex[v].y= lt->y; - v++; - FREE(lt); - lt= ltn; - } - if (rt) - { - rtn= rt->next; - result->strip[s].vertex[v].x= rt->x; - result->strip[s].vertex[v].y= rt->y; - v++; - FREE(rt); - rt= rtn; - } - } - s++; - } - else - { - /* Invalid tristrip: just free the heap */ - for (lt= tn->v[LEFT]; lt; lt= ltn) - { - ltn= lt->next; - FREE(lt); - } - for (rt= tn->v[RIGHT]; rt; rt=rtn) - { - rtn= rt->next; - FREE(rt); - } - } - FREE(tn); - } - } - - /* Tidy up */ - reset_it(&it); - reset_lmt(&lmt); - FREE(c_heap); - FREE(s_heap); - FREE(sbt); -} - -/* -=========================================================================== - End of file: gpc.c -=========================================================================== -*/ diff --git a/desmume/src/windows/agg/gpc/gpc.h b/desmume/src/windows/agg/gpc/gpc.h deleted file mode 100644 index 593539839..000000000 --- a/desmume/src/windows/agg/gpc/gpc.h +++ /dev/null @@ -1,133 +0,0 @@ -/* -=========================================================================== - -Project: Generic Polygon Clipper - - A new algorithm for calculating the difference, intersection, - exclusive-or or union of arbitrary polygon sets. - -File: gpc.h -Author: Alan Murta (email: gpc@cs.man.ac.uk) -Version: 2.32 -Date: 17th December 2004 - -Copyright: (C) 1997-2004, Advanced Interfaces Group, - University of Manchester. - - This software is free for non-commercial use. It may be copied, - modified, and redistributed provided that this copyright notice - is preserved on all copies. The intellectual property rights of - the algorithms used reside with the University of Manchester - Advanced Interfaces Group. - - You may not use this software, in whole or in part, in support - of any commercial product without the express consent of the - author. - - There is no warranty or other guarantee of fitness of this - software for any purpose. It is provided solely "as is". - -=========================================================================== -*/ - -#ifndef __gpc_h -#define __gpc_h - -#include - - -/* -=========================================================================== - Constants -=========================================================================== -*/ - -/* Increase GPC_EPSILON to encourage merging of near coincident edges */ - -#define GPC_EPSILON (DBL_EPSILON) - -#define GPC_VERSION "2.32" - - -/* -=========================================================================== - Public Data Types -=========================================================================== -*/ - -typedef enum /* Set operation type */ -{ - GPC_DIFF, /* Difference */ - GPC_INT, /* Intersection */ - GPC_XOR, /* Exclusive or */ - GPC_UNION /* Union */ -} gpc_op; - -typedef struct /* Polygon vertex structure */ -{ - double x; /* Vertex x component */ - double y; /* vertex y component */ -} gpc_vertex; - -typedef struct /* Vertex list structure */ -{ - int num_vertices; /* Number of vertices in list */ - gpc_vertex *vertex; /* Vertex array pointer */ -} gpc_vertex_list; - -typedef struct /* Polygon set structure */ -{ - int num_contours; /* Number of contours in polygon */ - int *hole; /* Hole / external contour flags */ - gpc_vertex_list *contour; /* Contour array pointer */ -} gpc_polygon; - -typedef struct /* Tristrip set structure */ -{ - int num_strips; /* Number of tristrips */ - gpc_vertex_list *strip; /* Tristrip array pointer */ -} gpc_tristrip; - - -/* -=========================================================================== - Public Function Prototypes -=========================================================================== -*/ - -void gpc_read_polygon (FILE *infile_ptr, - int read_hole_flags, - gpc_polygon *polygon); - -void gpc_write_polygon (FILE *outfile_ptr, - int write_hole_flags, - gpc_polygon *polygon); - -void gpc_add_contour (gpc_polygon *polygon, - gpc_vertex_list *contour, - int hole); - -void gpc_polygon_clip (gpc_op set_operation, - gpc_polygon *subject_polygon, - gpc_polygon *clip_polygon, - gpc_polygon *result_polygon); - -void gpc_tristrip_clip (gpc_op set_operation, - gpc_polygon *subject_polygon, - gpc_polygon *clip_polygon, - gpc_tristrip *result_tristrip); - -void gpc_polygon_to_tristrip (gpc_polygon *polygon, - gpc_tristrip *tristrip); - -void gpc_free_polygon (gpc_polygon *polygon); - -void gpc_free_tristrip (gpc_tristrip *tristrip); - -#endif - -/* -=========================================================================== - End of file: gpc.h -=========================================================================== -*/