1 /*****************************************************************************
2 * This file is part of gfxprim library. *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
19 * Copyright (C) 2009-2011 Jiri "BlueBear" Dluhos *
20 * <jiri.bluebear.dluhos@gmail.com> *
22 * Copyright (C) 2009-2012 Cyril Hrubis <metan@ucw.cz> *
24 *****************************************************************************/
26 #include "gfx/GP_Polygon.h"
27 #include "gfx/GP_HLine.h"
32 struct GP_PolygonEdge
{
33 GP_Coord startx
, starty
;
39 struct GP_PolygonEdge
*edges
;
44 #define GP_POLYGON_INITIALIZER { \
51 static void GP_InitEdge(struct GP_PolygonEdge
*edge
,
52 GP_Coord x1
, GP_Coord y1
, GP_Coord x2
, GP_Coord y2
)
54 if (y1
< y2
) { /* coords are top-down, correct */
59 } else { /* coords are bottom-up, flip them */
66 edge
->dx
= edge
->endx
- edge
->startx
;
67 edge
->dy
= edge
->endy
- edge
->starty
;
70 static void GP_AddEdge(struct GP_Polygon
*poly
, GP_Coord x1
, GP_Coord y1
,
71 GP_Coord x2
, GP_Coord y2
)
73 struct GP_PolygonEdge
*edge
= poly
->edges
+ poly
->edge_count
;
77 GP_InitEdge(edge
, x1
, y1
, x2
, y2
);
79 poly
->ymin
= GP_MIN(poly
->ymin
, edge
->starty
);
80 poly
->ymax
= GP_MAX(poly
->ymax
, edge
->endy
);
83 static int GP_CompareEdges(const void *edge1
, const void *edge2
)
85 struct GP_PolygonEdge
*e1
= (struct GP_PolygonEdge
*) edge1
;
86 struct GP_PolygonEdge
*e2
= (struct GP_PolygonEdge
*) edge2
;
88 if (e1
->starty
> e2
->starty
)
90 if (e1
->starty
> e2
->starty
)
93 if (e1
->startx
> e2
->startx
)
95 if (e1
->startx
< e2
->startx
)
101 static void GP_LoadPolygon(struct GP_Polygon
*poly
, GP_Coord vertex_count
,
104 poly
->edge_count
= 0;
105 poly
->edges
= calloc(sizeof(struct GP_PolygonEdge
),
109 GP_Coord coord_count
= 2*vertex_count
- 2;
110 for (i
= 0; i
< coord_count
; i
+=2) {
112 /* add the edge, unless it is horizontal */
113 if (xy
[i
+1] != xy
[i
+3]) {
114 GP_AddEdge(poly
, xy
[i
], xy
[i
+1], xy
[i
+2], xy
[i
+3]);
118 /* add the closing edge, unless it is horizontal */
119 if (xy
[1] != xy
[i
+1]) {
120 GP_AddEdge(poly
, xy
[i
], xy
[i
+1], xy
[0], xy
[1]);
124 qsort(poly
->edges
, poly
->edge_count
, sizeof(struct GP_PolygonEdge
),
128 static void GP_ResetPolygon(struct GP_Polygon
*poly
)
132 poly
->edge_count
= 0;
133 poly
->ymin
= INT_MAX
;
138 * Finds an X coordinate of an GP_Coordersection of the edge
139 * with the given Y line.
141 static inline GP_Coord
GP_FindIntersection(GP_Coord y
, const struct GP_PolygonEdge
*edge
)
143 GP_Coord edge_y
= y
- edge
->starty
; /* Y relative to the edge */
144 GP_Coord x
= edge
->startx
;
147 while (edge
->startx
*edge
->dy
+ edge_y
*edge
->dx
> x
*edge
->dy
)
150 while (edge
->startx
*edge
->dy
+ edge_y
*edge
->dx
< x
*edge
->dy
)
157 void GP_FillPolygon_Raw(GP_Context
*context
, GP_Coord vertex_count
,
158 const GP_Coord
*xy
, GP_Pixel pixel
)
160 struct GP_Polygon poly
= GP_POLYGON_INITIALIZER
;
162 GP_LoadPolygon(&poly
, vertex_count
, xy
);
164 GP_Coord y
, startx
, endx
;
166 for (y
= poly
.ymin
; y
<= poly
.ymax
; y
++) {
171 for (i
= 0; i
< poly
.edge_count
; i
++) {
172 struct GP_PolygonEdge
*edge
= poly
.edges
+ i
;
174 if (y
< edge
->starty
|| y
> edge
->endy
)
177 GP_Coord GP_Coorder
= GP_FindIntersection(y
, edge
);
179 startx
= GP_MIN(startx
, GP_Coorder
);
180 endx
= GP_MAX(endx
, GP_Coorder
);
182 if (y
!= edge
->endy
) {
183 GP_Coorder
= GP_FindIntersection(y
+ 1, edge
);
184 startx
= GP_MIN(startx
, GP_Coorder
);
185 endx
= GP_MAX(endx
, GP_Coorder
);
189 GP_HLine_Raw(context
, startx
, endx
, y
, pixel
);
192 GP_ResetPolygon(&poly
);