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-2011 Cyril Hrubis <metan@ucw.cz> *
24 *****************************************************************************/
31 struct GP_PolygonEdge
{
32 GP_Coord startx
, starty
;
38 struct GP_PolygonEdge
*edges
;
43 #define GP_POLYGON_INITIALIZER { \
50 static void GP_InitEdge(struct GP_PolygonEdge
*edge
,
51 GP_Coord x1
, GP_Coord y1
, GP_Coord x2
, GP_Coord y2
)
53 if (y1
< y2
) { /* coords are top-down, correct */
58 } else { /* coords are bottom-up, flip them */
65 edge
->dx
= edge
->endx
- edge
->startx
;
66 edge
->dy
= edge
->endy
- edge
->starty
;
69 static void GP_AddEdge(struct GP_Polygon
*poly
, GP_Coord x1
, GP_Coord y1
,
70 GP_Coord x2
, GP_Coord y2
)
72 struct GP_PolygonEdge
*edge
= poly
->edges
+ poly
->edge_count
;
76 GP_InitEdge(edge
, x1
, y1
, x2
, y2
);
78 poly
->ymin
= GP_MIN(poly
->ymin
, edge
->starty
);
79 poly
->ymax
= GP_MAX(poly
->ymax
, edge
->endy
);
82 static int GP_CompareEdges(const void *edge1
, const void *edge2
)
84 struct GP_PolygonEdge
*e1
= (struct GP_PolygonEdge
*) edge1
;
85 struct GP_PolygonEdge
*e2
= (struct GP_PolygonEdge
*) edge2
;
87 if (e1
->starty
> e2
->starty
)
89 if (e1
->starty
> e2
->starty
)
92 if (e1
->startx
> e2
->startx
)
94 if (e1
->startx
< e2
->startx
)
100 static void GP_LoadPolygon(struct GP_Polygon
*poly
, GP_Coord vertex_count
,
103 poly
->edge_count
= 0;
104 poly
->edges
= calloc(sizeof(struct GP_PolygonEdge
),
108 GP_Coord coord_count
= 2*vertex_count
- 2;
109 for (i
= 0; i
< coord_count
; i
+=2) {
111 /* add the edge, unless it is horizontal */
112 if (xy
[i
+1] != xy
[i
+3]) {
113 GP_AddEdge(poly
, xy
[i
], xy
[i
+1], xy
[i
+2], xy
[i
+3]);
117 /* add the closing edge, unless it is horizontal */
118 if (xy
[1] != xy
[i
+1]) {
119 GP_AddEdge(poly
, xy
[i
], xy
[i
+1], xy
[0], xy
[1]);
123 qsort(poly
->edges
, poly
->edge_count
, sizeof(struct GP_PolygonEdge
),
127 static void GP_ResetPolygon(struct GP_Polygon
*poly
)
131 poly
->edge_count
= 0;
132 poly
->ymin
= INT_MAX
;
137 * Finds an X coordinate of an GP_Coordersection of the edge
138 * with the given Y line.
140 static inline GP_Coord
GP_FindIntersection(GP_Coord y
, const struct GP_PolygonEdge
*edge
)
142 GP_Coord edge_y
= y
- edge
->starty
; /* Y relative to the edge */
143 GP_Coord x
= edge
->startx
;
146 while (edge
->startx
*edge
->dy
+ edge_y
*edge
->dx
> x
*edge
->dy
)
149 while (edge
->startx
*edge
->dy
+ edge_y
*edge
->dx
< x
*edge
->dy
)
156 void GP_FillPolygon_Raw(GP_Context
*context
, GP_Coord vertex_count
,
157 const GP_Coord
*xy
, GP_Pixel pixel
)
159 struct GP_Polygon poly
= GP_POLYGON_INITIALIZER
;
161 GP_LoadPolygon(&poly
, vertex_count
, xy
);
163 GP_Coord y
, startx
, endx
;
164 GP_Coord startx_prev
= -INT_MAX
;
165 GP_Coord endx_prev
= INT_MAX
;
167 for (y
= poly
.ymin
; y
<= poly
.ymax
; y
++) {
172 for (i
= 0; i
< poly
.edge_count
; i
++) {
173 struct GP_PolygonEdge
*edge
= poly
.edges
+ i
;
175 if (y
< edge
->starty
|| y
> edge
->endy
)
178 GP_Coord GP_Coorder
= GP_FindIntersection(y
, edge
);
180 startx
= GP_MIN(startx
, GP_Coorder
);
181 endx
= GP_MAX(endx
, GP_Coorder
);
183 if (y
!= edge
->endy
) {
184 GP_Coorder
= GP_FindIntersection(y
+ 1, edge
);
185 startx
= GP_MIN(startx
, GP_Coorder
);
186 endx
= GP_MAX(endx
, GP_Coorder
);
190 GP_HLine_Raw(context
, startx
, endx
, y
, pixel
);
192 startx_prev
= startx
;
196 GP_ResetPolygon(&poly
);