1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003 The GemRB Project
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program 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
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 #include "Interface.h"
30 Gem_Polygon::Gem_Polygon(Point
* points
, unsigned int cnt
, Region
*bbox
)
33 this->points
= ( Point
* ) malloc( cnt
* sizeof( Point
) );
34 memcpy( this->points
, points
, cnt
* sizeof( Point
) );
45 Gem_Polygon::~Gem_Polygon(void)
52 void Gem_Polygon::RecalcBBox()
55 BBox
.x
=BBox
.y
=BBox
.w
=BBox
.h
=0;
63 for(i
=1; i
<count
; i
++) {
64 if(points
[i
].x
<BBox
.x
) {
67 if(points
[i
].x
>BBox
.w
) {
70 if(points
[i
].y
<BBox
.y
) {
73 if(points
[i
].y
>BBox
.h
) {
81 bool Gem_Polygon::PointIn(const Point
&p
) const
83 if(!BBox
.PointInside(p
) ) return false;
84 return PointIn(p
.x
, p
.y
);
87 bool Gem_Polygon::PointIn(int tx
, int ty
) const
89 register int j
, yflag0
, yflag1
, xflag0
, index
;
90 bool inside_flag
= false;
98 vtx0
= &points
[count
- 1];
99 yflag0
= ( vtx0
->y
>= ty
);
100 vtx1
= &points
[index
];
102 for (j
= count
+ 1; --j
;) {
103 yflag1
= ( vtx1
->y
>= ty
);
104 if (yflag0
!= yflag1
) {
105 xflag0
= ( vtx0
->x
>= tx
);
106 if (xflag0
== ( vtx1
->x
>= tx
)) {
108 inside_flag
= !inside_flag
;
111 ( vtx1
->y
- ty
) * ( vtx0
->x
- vtx1
->x
) /
112 ( vtx0
->y
- vtx1
->y
) ) >= tx
) {
113 inside_flag
= !inside_flag
;
119 vtx1
= &points
[++index
];
124 // returns twice the area of triangle a, b, c.
125 // (can also be negative depending on orientation of a,b,c)
126 inline int area2(const Point
& a
, const Point
& b
, const Point
& c
)
128 return (b
.x
- a
.x
) * (c
.y
- a
.y
) - (c
.x
- a
.x
) * (b
.y
- a
.y
);
132 // return (c is to the left of a-b)
133 inline bool left(const Point
& a
, const Point
& b
, const Point
& c
)
135 return (area2(a
, b
, c
) > 0);
138 // { return (c is collinear with a-b)
139 inline bool collinear(const Point
& a
, const Point
& b
, const Point
& c
)
141 return (area2(a
, b
, c
) == 0);
144 // Find the intersection of two segments, if any.
145 // If the intersection is one of the endpoints, or the lines are
146 // parallel, false is returned.
147 // The point returned has the actual intersection coordinates rounded down
149 static bool intersectSegments(Point
& a
, Point
& b
, Point
& c
, Point
& d
, Point
& s
)
151 if (collinear(a
, b
, c
) || collinear(a
, b
, d
) ||
152 collinear(c
, d
, a
) || collinear(c
, d
, b
))
155 if (!((left(a
, b
, c
) != left(a
, b
, d
)) &&
156 (left(c
, d
, a
) != left(c
, d
, b
))))
159 __int64 A1
= area2(c
, d
, a
);
160 __int64 A2
= area2(d
, c
, b
);
162 s
.x
= (short) ((b
.x
*A1
+ a
.x
*A2
) / (A1
+ A2
));
163 s
.y
= (short) ((b
.y
*A1
+ a
.y
*A2
) / (A1
+ A2
));
168 // find the intersection of a segment with a horizontal scanline, if any
169 static bool intersectSegmentScanline(Point
& a
, Point
& b
, int y
, int& x
)
174 if (y1
* y2
> 0) return false;
175 if (y1
== 0 && y2
== 0) return false;
177 x
= a
.x
+ ((b
.x
- a
.x
)*y1
)/(y1
-y2
);
187 bool operator<(const ScanlineInt
& i2
) const
195 Point
& a
= p
->points
[pi
];
196 Point
& b
= p
->points
[(pi
+1)%(p
->count
)];
197 Point
& c
= p
->points
[i2
.pi
];
198 Point
& d
= p
->points
[(i2
.pi
+1)%(p
->count
)];
215 if (dx1
* dy2
> dx2
* dy1
) return true;
223 void Gem_Polygon::ComputeTrapezoids()
225 if (count
< 3) return;
226 //the loader never should load such a large polygon,
227 //because the polygon count is supposed to be a 16 bit value
229 printMessage("Polygon", "Invalid Polygon!\n", LIGHT_RED
);
237 // y coords of vertices
240 for (i
= 0; i
< count
; ++i
)
241 ys
.push_back(points
[i
].y
);
244 // y coords of self-intersections
245 for (unsigned int i1
= 0; i1
< count
; ++i1
) {
246 Point
& a
= points
[i1
];
247 Point
& b
= points
[(i1
+1)%count
];
249 // intersections with horizontal lines don't matter
250 if (a
.y
== b
.y
) continue;
252 for (unsigned int i2
= i1
+2; i2
< count
; ++i2
) {
253 Point
& c
= points
[i2
];
254 Point
& d
= points
[(i2
+1)%count
];
256 // intersections with horizontal lines don't matter
257 if (c
.y
== d
.y
) continue;
259 if (intersectSegments(a
, b
, c
, d
, p
)) {
265 std::sort(ys
.begin(), ys
.end());
267 std::vector
<ScanlineInt
> ints
;
273 std::list
<Trapezoid
>::iterator iter
;
278 // TODO: it's possible to keep a set of 'active' edges and only check
279 // scanline intersections of those edges.
282 while (yi
< ys
.size() - 1) {
283 while (yi
< ys
.size() && ys
[yi
] == cury
) ++yi
;
284 if (yi
== ys
.size()) break;
290 // Determine all scanline intersections at level nexty.
291 // This includes edges which have their lower vertex at nexty,
292 // but excludes edges with their upper vertex at nexty.
293 // (We're taking the intersections along the 'upper' edge of
294 // the nexty scanline.)
296 for (i
= 0; i
< count
; ++i
) {
297 Point
& a
= points
[i
];
298 Point
& b
= points
[(i
+1)%count
];
300 if (a
.y
== b
.y
) continue;
303 if (b
.y
- nexty
< 0) {
308 } else if (b
.y
== nexty
) {
309 if (a
.y
- nexty
< 0) {
316 if (intersectSegmentScanline(a
, b
, nexty
, x
)) {
324 std::sort(ints
.begin(), ints
.end());
325 unsigned int newtcount
= (unsigned int) (ints
.size() / 2);
327 for (i
= 0; i
< newtcount
; ++i
) {
328 t
.left_edge
= ints
[2*i
].pi
;
329 t
.right_edge
= ints
[2*i
+1].pi
;
334 // merge trapezoids with old one if it's just a continuation
335 for (iter
= trapezoids
.begin(); iter
!= trapezoids
.end(); ++iter
) {
336 Trapezoid
& oldt
= *iter
;
337 if (oldt
.y2
== cury
&&
338 oldt
.left_edge
== t
.left_edge
&&
339 oldt
.right_edge
== t
.right_edge
)
348 trapezoids
.push_back(t
);
351 // Done with this strip
358 void Wall_Polygon::SetBaseline(const Point
&a
, const Point
&b
)
360 if ((a
.x
<b
.x
) || ((a
.x
==b
.x
) && (a
.y
<b
.y
)) ) {
369 bool Wall_Polygon::PointCovered(const Point
&p
) const
371 if (wall_flag
&WF_DISABLED
)
373 if (wall_flag
&WF_BASELINE
) {
374 if (base0
.x
> base1
.x
)
375 return left(base0
, base1
, p
);
377 return left(base1
, base0
, p
);
382 bool Wall_Polygon::PointCovered(int tx
, int ty
) const
384 Point
p((short) tx
, (short) ty
);
385 return PointCovered(p
);