Branch data Line data Source code
1 : : /* ______ ___ ___
2 : : * /\ _ \ /\_ \ /\_ \
3 : : * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 : : * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 : : * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 : : * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 : : * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 : : * /\____/
9 : : * \_/__/
10 : : *
11 : : * Common utilities.
12 : : *
13 : : *
14 : : * By Michał Cichoń.
15 : : *
16 : : * See readme.txt for copyright information.
17 : : */
18 : :
19 : : #include "allegro5/allegro.h"
20 : : #include "allegro5/allegro_primitives.h"
21 : : #include "allegro5/internal/aintern_list.h"
22 : : #include "allegro5/internal/aintern_prim.h"
23 : : #include <float.h>
24 : : #include <math.h>
25 : :
26 : : #ifdef ALLEGRO_MSVC
27 : : #define hypotf(x, y) _hypotf((x), (y))
28 : : #endif
29 : :
30 : : # define AL_EPSILON 0.001f
31 : :
32 : :
33 : : /*
34 : : * Make an estimate of the scale of the current transformation.
35 : : */
36 : 0 : float _al_prim_get_scale(void)
37 : : {
38 : 0 : const ALLEGRO_TRANSFORM* t = al_get_current_transform();
39 : 0 : return (hypotf(t->m[0][0], t->m[0][1]) + hypotf(t->m[1][0], t->m[1][1])) / 2;
40 : : }
41 : :
42 : :
43 : : /*
44 : : * Normalizes vector.
45 : : */
46 : 792 : float _al_prim_normalize(float* vector)
47 : : {
48 : : float length;
49 : : float inv_length;
50 : :
51 : 792 : length = hypotf(vector[0], vector[1]);
52 [ + - ]: 792 : inv_length = length > 0.0f ? 1.0f / length : 1.0f;
53 : :
54 : 792 : vector[0] *= inv_length;
55 : 792 : vector[1] *= inv_length;
56 : :
57 : 792 : return length;
58 : : }
59 : :
60 : :
61 : : /*
62 : : * Wraps angle to the range [0, 2 pi).
63 : : */
64 : 162 : float _al_prim_wrap_two_pi(float angle)
65 : : {
66 : 162 : angle = fmodf(angle, 2.0f * ALLEGRO_PI);
67 [ + + ]: 162 : if (angle < 0)
68 : 40 : angle += 2.0f * ALLEGRO_PI;
69 : 162 : return angle;
70 : : }
71 : :
72 : :
73 : : /*
74 : : * Wraps angle to the range [-pi, pi).
75 : : */
76 : 0 : float _al_prim_wrap_pi_to_pi(float angle)
77 : : {
78 : 0 : angle = _al_prim_wrap_two_pi(angle);
79 [ # # ]: 0 : if (angle >= ALLEGRO_PI)
80 : 0 : angle = -2.0f * ALLEGRO_PI + angle;
81 : 0 : return angle;
82 : : }
83 : :
84 : :
85 : : /*
86 : : * Returns angle between two edges.
87 : : *
88 : : * Angle is in range [-2 pi, 2 pi], so it is good idea to
89 : : * use _al_prim_wrap_two_pi() for normalization.
90 : : */
91 : 162 : float _al_prim_get_angle(const float* p0, const float* origin, const float* p1)
92 : : {
93 : 162 : float angle1 = atan2f(origin[1] - p0[1], origin[0] - p0[0]);
94 : 162 : float angle2 = atan2f(origin[1] - p1[1], origin[0] - p1[0]);
95 : :
96 : 162 : return angle2 - angle1;
97 : : }
98 : :
99 : :
100 : : /*
101 : : * Tests on which side of the line point is placed.
102 : : * Positive value will be returned if point is on half plane
103 : : * determined by normal vector. Negative value will be returned
104 : : * if point is on negative half plane determined by normal vector.
105 : : * Zero will be returned if point lie on the line.
106 : : */
107 : 3162 : int _al_prim_test_line_side(const float* origin, const float* normal, const float* point)
108 : : {
109 : 3162 : float c = -(origin[0] * normal[0] + origin[1] * normal[1]);
110 : 3162 : float d = point[0] * normal[0] + point[1] * normal[1] + c;
111 [ + + ]: 3162 : if (d < 0.0f)/*-AL_EPSILON)*/
112 : : return -1;
113 [ - + ]: 1424 : else if (d > 0.0f)/*AL_EPSILON)*/
114 : : return 1;
115 : : else
116 : 3162 : return 0;
117 : : }
118 : :
119 : :
120 : : /*
121 : : * Tests if point is inside of the triangle defined by vertices v0, v1 and v2.
122 : : *
123 : : * Order of vertices does not have matter.
124 : : */
125 : 1054 : bool _al_prim_is_point_in_triangle(const float* point, const float* v0, const float* v1, const float* v2)
126 : : {
127 : 1054 : float edge_normal_0[2] = { -(v1[1] - v0[1]), v1[0] - v0[0] };
128 : 1054 : float edge_normal_1[2] = { -(v2[1] - v1[1]), v2[0] - v1[0] };
129 : 1054 : float edge_normal_2[2] = { -(v0[1] - v2[1]), v0[0] - v2[0] };
130 : :
131 : 1054 : int edge_side_0 = _al_prim_test_line_side(v0, edge_normal_0, point);
132 : 1054 : int edge_side_1 = _al_prim_test_line_side(v1, edge_normal_1, point);
133 : 1054 : int edge_side_2 = _al_prim_test_line_side(v2, edge_normal_2, point);
134 : :
135 [ + - ][ + - ]: 1054 : if (edge_side_0 && edge_side_1 && edge_side_2)
136 : 1054 : return (edge_side_0 == edge_side_1) && (edge_side_0 == edge_side_2);
137 [ # # ]: 0 : else if (0 == edge_side_0)
138 : 0 : return (edge_side_1 == edge_side_2);
139 [ # # ]: 0 : else if (0 == edge_side_1)
140 : 0 : return (edge_side_0 == edge_side_2);
141 : : else /*if (0 == edge_side_2)*/
142 : 1054 : return (edge_side_0 == edge_side_1);
143 : : }
144 : :
145 : :
146 : : /*
147 : : * Tests for intersection of lines defined by points { v0, v1 }
148 : : * and { p0, p1 }.
149 : : *
150 : : * Returns true if intersection point was determined. If pointers
151 : : * are provided time and exact point of intersection will be returned.
152 : : * If test fails false will be returned. Intersection point and time
153 : : * variables will not be altered in this case.
154 : : *
155 : : * Intersection time is in { v0, v1 } line space.
156 : : */
157 : 0 : bool _al_prim_intersect_segment(const float* v0, const float* v1, const float* p0, const float* p1, float* point/* = NULL*/, float* t0/* = NULL*/, float* t1/* = NULL*/)
158 : : {
159 : : float num, denom, time;
160 : :
161 : 0 : denom = (p1[1] - p0[1]) * (v1[0] - v0[0]) - (p1[0] - p0[0]) * (v1[1] - v0[1]);
162 : :
163 [ # # ]: 0 : if (fabsf(denom) == 0.0f)
164 : : return false;
165 : :
166 : 0 : num = (p1[0] - p0[0]) * (v0[1] - p0[1]) - (p1[1] - p0[1]) * (v0[0] - p0[0]);
167 : :
168 : 0 : time = (num / denom);
169 [ # # ]: 0 : if (t0)
170 : 0 : *t0 = time;
171 : :
172 [ # # ]: 0 : if (t1) {
173 : :
174 : 0 : const float num2 = (v1[0] - v0[0]) * (v0[1] - p0[1]) - (v1[1] - v0[1]) * (v0[0] - p0[0]);
175 : :
176 : 0 : *t1 = (num2 / denom);
177 : : }
178 : :
179 [ # # ]: 0 : if (point) {
180 : :
181 : 0 : point[0] = v0[0] + time * (v1[0] - v0[0]);
182 : 0 : point[1] = v0[1] + time * (v1[1] - v0[1]);
183 : : }
184 : :
185 : : return true;
186 : : }
187 : :
188 : :
189 : : /*
190 : : * Compares two points for equality.
191 : : *
192 : : * This is not exact comparison but it is sufficient
193 : : * for our needs.
194 : : */
195 : 0 : bool _al_prim_are_points_equal(const float* point_a, const float* point_b)
196 : : {
197 : 0 : return (fabsf(point_a[0] - point_b[0]) < AL_EPSILON)
198 [ # # ][ # # ]: 0 : && (fabsf(point_a[1] - point_b[1]) < AL_EPSILON);
199 : : }
200 : :
201 : :
202 : : /*
203 : : *
204 : : */
205 : 24 : void _al_prim_cache_init(ALLEGRO_PRIM_VERTEX_CACHE* cache, int prim_type, ALLEGRO_COLOR color)
206 : : {
207 : 24 : _al_prim_cache_init_ex(cache, prim_type, color, NULL);
208 : 24 : }
209 : :
210 : 26 : void _al_prim_cache_init_ex(ALLEGRO_PRIM_VERTEX_CACHE* cache, int prim_type, ALLEGRO_COLOR color, void* user_data)
211 : : {
212 : 26 : cache->size = 0;
213 : 26 : cache->current = cache->buffer;
214 : 26 : cache->color = color;
215 : 26 : cache->prim_type = prim_type;
216 : 26 : cache->user_data = user_data;
217 : 26 : }
218 : :
219 : 24 : void _al_prim_cache_term(ALLEGRO_PRIM_VERTEX_CACHE* cache)
220 : : {
221 : 24 : _al_prim_cache_flush(cache);
222 : 24 : }
223 : :
224 : 46 : void _al_prim_cache_flush(ALLEGRO_PRIM_VERTEX_CACHE* cache)
225 : : {
226 [ + - ]: 46 : if (cache->size == 0)
227 : 46 : return;
228 : :
229 [ + + ]: 46 : if (cache->prim_type == ALLEGRO_PRIM_VERTEX_CACHE_TRIANGLE)
230 : 44 : al_draw_prim(cache->buffer, NULL, NULL, 0, cache->size, ALLEGRO_PRIM_TRIANGLE_LIST);
231 [ + - ]: 2 : else if (cache->prim_type == ALLEGRO_PRIM_VERTEX_CACHE_LINE_STRIP)
232 : 2 : al_draw_prim(cache->buffer, NULL, NULL, 0, cache->size, ALLEGRO_PRIM_LINE_STRIP);
233 : :
234 [ + + ]: 46 : if (cache->prim_type == ALLEGRO_PRIM_VERTEX_CACHE_LINE_STRIP)
235 : : {
236 : 2 : cache->buffer[0] = *(cache->current - 1);
237 : 2 : cache->current = cache->buffer + 1;
238 : 2 : cache->size = 1;
239 : : }
240 : : else
241 : : {
242 : 44 : cache->current = cache->buffer;
243 : 44 : cache->size = 0;
244 : : }
245 : : }
246 : :
247 : 2788 : void _al_prim_cache_push_triangle(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* v0, const float* v1, const float* v2)
248 : : {
249 [ + + ]: 2788 : if (cache->size >= (ALLEGRO_VERTEX_CACHE_SIZE - 3))
250 : 20 : _al_prim_cache_flush(cache);
251 : :
252 : 2788 : cache->current->x = v0[0];
253 : 2788 : cache->current->y = v0[1];
254 : 2788 : cache->current->z = 0.0f;
255 : 2788 : cache->current->color = cache->color;
256 : :
257 : 2788 : ++cache->current;
258 : :
259 : 2788 : cache->current->x = v1[0];
260 : 2788 : cache->current->y = v1[1];
261 : 2788 : cache->current->z = 0.0f;
262 : 2788 : cache->current->color = cache->color;
263 : :
264 : 2788 : ++cache->current;
265 : :
266 : 2788 : cache->current->x = v2[0];
267 : 2788 : cache->current->y = v2[1];
268 : 2788 : cache->current->z = 0.0f;
269 : 2788 : cache->current->color = cache->color;
270 : :
271 : 2788 : ++cache->current;
272 : :
273 : 2788 : cache->size += 3;
274 : :
275 : : //al_draw_triangle(v0[0], v0[1], v1[0], v1[1], v2[0], v2[1], cache->color, 1.0f);
276 : 2788 : }
277 : :
278 : 24 : void _al_prim_cache_push_point(ALLEGRO_PRIM_VERTEX_CACHE* cache, const float* v)
279 : : {
280 [ - + ]: 24 : if (cache->size >= (ALLEGRO_VERTEX_CACHE_SIZE - 1))
281 : 0 : _al_prim_cache_flush(cache);
282 : :
283 : 24 : cache->current->x = v[0];
284 : 24 : cache->current->y = v[1];
285 : 24 : cache->current->z = 0.0f;
286 : 24 : cache->current->color = cache->color;
287 : :
288 : 24 : ++cache->current;
289 : 24 : ++cache->size;
290 : 24 : }
|