Rev 1892 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1892 | serge | 1 | /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ |
2 | /* Cairo - a vector graphics library with display and print output |
||
3 | * |
||
4 | * Copyright © 2007 Mozilla Corporation |
||
5 | * |
||
6 | * This library is free software; you can redistribute it and/or |
||
7 | * modify it either under the terms of the GNU Lesser General Public |
||
8 | * License version 2.1 as published by the Free Software Foundation |
||
9 | * (the "LGPL") or, at your option, under the terms of the Mozilla |
||
10 | * Public License Version 1.1 (the "MPL"). If you do not alter this |
||
11 | * notice, a recipient may use your version of this file under either |
||
12 | * the MPL or the LGPL. |
||
13 | * |
||
14 | * You should have received a copy of the LGPL along with this library |
||
15 | * in the file COPYING-LGPL-2.1; if not, write to the Free Software |
||
16 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA |
||
17 | * You should have received a copy of the MPL along with this library |
||
18 | * in the file COPYING-MPL-1.1 |
||
19 | * |
||
20 | * The contents of this file are subject to the Mozilla Public License |
||
21 | * Version 1.1 (the "License"); you may not use this file except in |
||
22 | * compliance with the License. You may obtain a copy of the License at |
||
23 | * http://www.mozilla.org/MPL/ |
||
24 | * |
||
25 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY |
||
26 | * OF ANY KIND, either express or implied. See the LGPL or the MPL for |
||
27 | * the specific language governing rights and limitations. |
||
28 | * |
||
29 | * The Original Code is the cairo graphics library. |
||
30 | * |
||
31 | * The Initial Developer of the Original Code is Mozilla Foundation |
||
32 | * |
||
33 | * Contributor(s): |
||
34 | * Vladimir Vukicevic |
||
35 | */ |
||
36 | |||
37 | #ifndef CAIRO_FIXED_PRIVATE_H |
||
38 | #define CAIRO_FIXED_PRIVATE_H |
||
39 | |||
40 | #include "cairo-fixed-type-private.h" |
||
41 | |||
42 | #include "cairo-wideint-private.h" |
||
3959 | Serge | 43 | #include "cairoint.h" |
1892 | serge | 44 | |
45 | /* Implementation */ |
||
46 | |||
47 | #if (CAIRO_FIXED_BITS != 32) |
||
48 | # error CAIRO_FIXED_BITS must be 32, and the type must be a 32-bit type. |
||
49 | # error To remove this limitation, you will have to fix the tesselator. |
||
50 | #endif |
||
51 | |||
52 | #define CAIRO_FIXED_ONE ((cairo_fixed_t)(1 << CAIRO_FIXED_FRAC_BITS)) |
||
53 | #define CAIRO_FIXED_ONE_DOUBLE ((double)(1 << CAIRO_FIXED_FRAC_BITS)) |
||
54 | #define CAIRO_FIXED_EPSILON ((cairo_fixed_t)(1)) |
||
55 | |||
3959 | Serge | 56 | #define CAIRO_FIXED_ERROR_DOUBLE (1. / (2 * CAIRO_FIXED_ONE_DOUBLE)) |
57 | |||
1892 | serge | 58 | #define CAIRO_FIXED_FRAC_MASK ((cairo_fixed_t)(((cairo_fixed_unsigned_t)(-1)) >> (CAIRO_FIXED_BITS - CAIRO_FIXED_FRAC_BITS))) |
59 | #define CAIRO_FIXED_WHOLE_MASK (~CAIRO_FIXED_FRAC_MASK) |
||
60 | |||
61 | static inline cairo_fixed_t |
||
62 | _cairo_fixed_from_int (int i) |
||
63 | { |
||
64 | return i << CAIRO_FIXED_FRAC_BITS; |
||
65 | } |
||
66 | |||
67 | /* This is the "magic number" approach to converting a double into fixed |
||
68 | * point as described here: |
||
69 | * |
||
70 | * http://www.stereopsis.com/sree/fpu2006.html (an overview) |
||
71 | * http://www.d6.com/users/checker/pdfs/gdmfp.pdf (in detail) |
||
72 | * |
||
73 | * The basic idea is to add a large enough number to the double that the |
||
74 | * literal floating point is moved up to the extent that it forces the |
||
75 | * double's value to be shifted down to the bottom of the mantissa (to make |
||
76 | * room for the large number being added in). Since the mantissa is, at a |
||
77 | * given moment in time, a fixed point integer itself, one can convert a |
||
78 | * float to various fixed point representations by moving around the point |
||
79 | * of a floating point number through arithmetic operations. This behavior |
||
80 | * is reliable on most modern platforms as it is mandated by the IEEE-754 |
||
81 | * standard for floating point arithmetic. |
||
82 | * |
||
83 | * For our purposes, a "magic number" must be carefully selected that is |
||
84 | * both large enough to produce the desired point-shifting effect, and also |
||
85 | * has no lower bits in its representation that would interfere with our |
||
86 | * value at the bottom of the mantissa. The magic number is calculated as |
||
87 | * follows: |
||
88 | * |
||
89 | * (2 ^ (MANTISSA_SIZE - FRACTIONAL_SIZE)) * 1.5 |
||
90 | * |
||
91 | * where in our case: |
||
92 | * - MANTISSA_SIZE for 64-bit doubles is 52 |
||
93 | * - FRACTIONAL_SIZE for 16.16 fixed point is 16 |
||
94 | * |
||
95 | * Although this approach provides a very large speedup of this function |
||
96 | * on a wide-array of systems, it does come with two caveats: |
||
97 | * |
||
98 | * 1) It uses banker's rounding as opposed to arithmetic rounding. |
||
99 | * 2) It doesn't function properly if the FPU is in single-precision |
||
100 | * mode. |
||
101 | */ |
||
102 | |||
103 | /* The 16.16 number must always be available */ |
||
104 | #define CAIRO_MAGIC_NUMBER_FIXED_16_16 (103079215104.0) |
||
105 | |||
106 | #if CAIRO_FIXED_BITS <= 32 |
||
107 | #define CAIRO_MAGIC_NUMBER_FIXED ((1LL << (52 - CAIRO_FIXED_FRAC_BITS)) * 1.5) |
||
108 | |||
109 | /* For 32-bit fixed point numbers */ |
||
110 | static inline cairo_fixed_t |
||
111 | _cairo_fixed_from_double (double d) |
||
112 | { |
||
113 | union { |
||
114 | double d; |
||
115 | int32_t i[2]; |
||
116 | } u; |
||
117 | |||
118 | u.d = d + CAIRO_MAGIC_NUMBER_FIXED; |
||
119 | #ifdef FLOAT_WORDS_BIGENDIAN |
||
120 | return u.i[1]; |
||
121 | #else |
||
122 | return u.i[0]; |
||
123 | #endif |
||
124 | } |
||
125 | |||
126 | #else |
||
127 | # error Please define a magic number for your fixed point type! |
||
128 | # error See cairo-fixed-private.h for details. |
||
129 | #endif |
||
130 | |||
131 | static inline cairo_fixed_t |
||
132 | _cairo_fixed_from_26_6 (uint32_t i) |
||
133 | { |
||
134 | #if CAIRO_FIXED_FRAC_BITS > 6 |
||
135 | return i << (CAIRO_FIXED_FRAC_BITS - 6); |
||
136 | #else |
||
137 | return i >> (6 - CAIRO_FIXED_FRAC_BITS); |
||
138 | #endif |
||
139 | } |
||
140 | |||
141 | static inline cairo_fixed_t |
||
142 | _cairo_fixed_from_16_16 (uint32_t i) |
||
143 | { |
||
144 | #if CAIRO_FIXED_FRAC_BITS > 16 |
||
145 | return i << (CAIRO_FIXED_FRAC_BITS - 16); |
||
146 | #else |
||
147 | return i >> (16 - CAIRO_FIXED_FRAC_BITS); |
||
148 | #endif |
||
149 | } |
||
150 | |||
151 | static inline double |
||
152 | _cairo_fixed_to_double (cairo_fixed_t f) |
||
153 | { |
||
154 | return ((double) f) / CAIRO_FIXED_ONE_DOUBLE; |
||
155 | } |
||
156 | |||
157 | static inline int |
||
158 | _cairo_fixed_is_integer (cairo_fixed_t f) |
||
159 | { |
||
160 | return (f & CAIRO_FIXED_FRAC_MASK) == 0; |
||
161 | } |
||
162 | |||
163 | static inline cairo_fixed_t |
||
164 | _cairo_fixed_floor (cairo_fixed_t f) |
||
165 | { |
||
166 | return f & ~CAIRO_FIXED_FRAC_MASK; |
||
167 | } |
||
168 | |||
169 | static inline cairo_fixed_t |
||
3959 | Serge | 170 | _cairo_fixed_ceil (cairo_fixed_t f) |
171 | { |
||
172 | return _cairo_fixed_floor (f + CAIRO_FIXED_FRAC_MASK); |
||
173 | } |
||
174 | |||
175 | static inline cairo_fixed_t |
||
1892 | serge | 176 | _cairo_fixed_round (cairo_fixed_t f) |
177 | { |
||
178 | return _cairo_fixed_floor (f + (CAIRO_FIXED_FRAC_MASK+1)/2); |
||
179 | } |
||
180 | |||
181 | static inline cairo_fixed_t |
||
182 | _cairo_fixed_round_down (cairo_fixed_t f) |
||
183 | { |
||
184 | return _cairo_fixed_floor (f + CAIRO_FIXED_FRAC_MASK/2); |
||
185 | } |
||
186 | |||
187 | static inline int |
||
188 | _cairo_fixed_integer_part (cairo_fixed_t f) |
||
189 | { |
||
190 | return f >> CAIRO_FIXED_FRAC_BITS; |
||
191 | } |
||
192 | |||
193 | static inline int |
||
194 | _cairo_fixed_integer_round (cairo_fixed_t f) |
||
195 | { |
||
196 | return _cairo_fixed_integer_part (f + (CAIRO_FIXED_FRAC_MASK+1)/2); |
||
197 | } |
||
198 | |||
199 | static inline int |
||
200 | _cairo_fixed_integer_round_down (cairo_fixed_t f) |
||
201 | { |
||
202 | return _cairo_fixed_integer_part (f + CAIRO_FIXED_FRAC_MASK/2); |
||
203 | } |
||
204 | |||
205 | static inline int |
||
206 | _cairo_fixed_fractional_part (cairo_fixed_t f) |
||
207 | { |
||
208 | return f & CAIRO_FIXED_FRAC_MASK; |
||
209 | } |
||
210 | |||
211 | static inline int |
||
212 | _cairo_fixed_integer_floor (cairo_fixed_t f) |
||
213 | { |
||
214 | if (f >= 0) |
||
215 | return f >> CAIRO_FIXED_FRAC_BITS; |
||
216 | else |
||
217 | return -((-f - 1) >> CAIRO_FIXED_FRAC_BITS) - 1; |
||
218 | } |
||
219 | |||
220 | static inline int |
||
221 | _cairo_fixed_integer_ceil (cairo_fixed_t f) |
||
222 | { |
||
223 | if (f > 0) |
||
224 | return ((f - 1)>>CAIRO_FIXED_FRAC_BITS) + 1; |
||
225 | else |
||
226 | return - (-f >> CAIRO_FIXED_FRAC_BITS); |
||
227 | } |
||
228 | |||
229 | /* A bunch of explicit 16.16 operators; we need these |
||
230 | * to interface with pixman and other backends that require |
||
231 | * 16.16 fixed point types. |
||
232 | */ |
||
233 | static inline cairo_fixed_16_16_t |
||
234 | _cairo_fixed_to_16_16 (cairo_fixed_t f) |
||
235 | { |
||
236 | #if (CAIRO_FIXED_FRAC_BITS == 16) && (CAIRO_FIXED_BITS == 32) |
||
237 | return f; |
||
238 | #elif CAIRO_FIXED_FRAC_BITS > 16 |
||
239 | /* We're just dropping the low bits, so we won't ever got over/underflow here */ |
||
240 | return f >> (CAIRO_FIXED_FRAC_BITS - 16); |
||
241 | #else |
||
242 | cairo_fixed_16_16_t x; |
||
243 | |||
244 | /* Handle overflow/underflow by clamping to the lowest/highest |
||
245 | * value representable as 16.16 |
||
246 | */ |
||
247 | if ((f >> CAIRO_FIXED_FRAC_BITS) < INT16_MIN) { |
||
248 | x = INT32_MIN; |
||
249 | } else if ((f >> CAIRO_FIXED_FRAC_BITS) > INT16_MAX) { |
||
250 | x = INT32_MAX; |
||
251 | } else { |
||
252 | x = f << (16 - CAIRO_FIXED_FRAC_BITS); |
||
253 | } |
||
254 | |||
255 | return x; |
||
256 | #endif |
||
257 | } |
||
258 | |||
259 | static inline cairo_fixed_16_16_t |
||
260 | _cairo_fixed_16_16_from_double (double d) |
||
261 | { |
||
262 | union { |
||
263 | double d; |
||
264 | int32_t i[2]; |
||
265 | } u; |
||
266 | |||
267 | u.d = d + CAIRO_MAGIC_NUMBER_FIXED_16_16; |
||
268 | #ifdef FLOAT_WORDS_BIGENDIAN |
||
269 | return u.i[1]; |
||
270 | #else |
||
271 | return u.i[0]; |
||
272 | #endif |
||
273 | } |
||
274 | |||
275 | static inline int |
||
276 | _cairo_fixed_16_16_floor (cairo_fixed_16_16_t f) |
||
277 | { |
||
278 | if (f >= 0) |
||
279 | return f >> 16; |
||
280 | else |
||
281 | return -((-f - 1) >> 16) - 1; |
||
282 | } |
||
283 | |||
284 | static inline double |
||
285 | _cairo_fixed_16_16_to_double (cairo_fixed_16_16_t f) |
||
286 | { |
||
287 | return ((double) f) / (double) (1 << 16); |
||
288 | } |
||
289 | |||
290 | #if CAIRO_FIXED_BITS == 32 |
||
291 | |||
292 | static inline cairo_fixed_t |
||
293 | _cairo_fixed_mul (cairo_fixed_t a, cairo_fixed_t b) |
||
294 | { |
||
295 | cairo_int64_t temp = _cairo_int32x32_64_mul (a, b); |
||
296 | return _cairo_int64_to_int32(_cairo_int64_rsl (temp, CAIRO_FIXED_FRAC_BITS)); |
||
297 | } |
||
298 | |||
299 | /* computes round (a * b / c) */ |
||
300 | static inline cairo_fixed_t |
||
301 | _cairo_fixed_mul_div (cairo_fixed_t a, cairo_fixed_t b, cairo_fixed_t c) |
||
302 | { |
||
303 | cairo_int64_t ab = _cairo_int32x32_64_mul (a, b); |
||
304 | cairo_int64_t c64 = _cairo_int32_to_int64 (c); |
||
305 | return _cairo_int64_to_int32 (_cairo_int64_divrem (ab, c64).quo); |
||
306 | } |
||
307 | |||
308 | /* computes floor (a * b / c) */ |
||
309 | static inline cairo_fixed_t |
||
310 | _cairo_fixed_mul_div_floor (cairo_fixed_t a, cairo_fixed_t b, cairo_fixed_t c) |
||
311 | { |
||
312 | return _cairo_int64_32_div (_cairo_int32x32_64_mul (a, b), c); |
||
313 | } |
||
314 | |||
315 | |||
316 | static inline cairo_fixed_t |
||
317 | _cairo_edge_compute_intersection_y_for_x (const cairo_point_t *p1, |
||
318 | const cairo_point_t *p2, |
||
319 | cairo_fixed_t x) |
||
320 | { |
||
321 | cairo_fixed_t y, dx; |
||
322 | |||
323 | if (x == p1->x) |
||
324 | return p1->y; |
||
325 | if (x == p2->x) |
||
326 | return p2->y; |
||
327 | |||
328 | y = p1->y; |
||
329 | dx = p2->x - p1->x; |
||
330 | if (dx != 0) |
||
331 | y += _cairo_fixed_mul_div_floor (x - p1->x, p2->y - p1->y, dx); |
||
332 | |||
333 | return y; |
||
334 | } |
||
335 | |||
336 | static inline cairo_fixed_t |
||
337 | _cairo_edge_compute_intersection_x_for_y (const cairo_point_t *p1, |
||
338 | const cairo_point_t *p2, |
||
339 | cairo_fixed_t y) |
||
340 | { |
||
341 | cairo_fixed_t x, dy; |
||
342 | |||
343 | if (y == p1->y) |
||
344 | return p1->x; |
||
345 | if (y == p2->y) |
||
346 | return p2->x; |
||
347 | |||
348 | x = p1->x; |
||
349 | dy = p2->y - p1->y; |
||
350 | if (dy != 0) |
||
351 | x += _cairo_fixed_mul_div_floor (y - p1->y, p2->x - p1->x, dy); |
||
352 | |||
353 | return x; |
||
354 | } |
||
355 | |||
3959 | Serge | 356 | /* Intersect two segments based on the algorithm described at |
357 | * http://paulbourke.net/geometry/pointlineplane/. This implementation |
||
358 | * uses floating point math. */ |
||
359 | static inline cairo_bool_t |
||
360 | _slow_segment_intersection (const cairo_point_t *seg1_p1, |
||
361 | const cairo_point_t *seg1_p2, |
||
362 | const cairo_point_t *seg2_p1, |
||
363 | const cairo_point_t *seg2_p2, |
||
364 | cairo_point_t *intersection) |
||
365 | { |
||
366 | double denominator, u_a, u_b; |
||
367 | double seg1_dx, seg1_dy, seg2_dx, seg2_dy, seg_start_dx, seg_start_dy; |
||
368 | |||
369 | seg1_dx = _cairo_fixed_to_double (seg1_p2->x - seg1_p1->x); |
||
370 | seg1_dy = _cairo_fixed_to_double (seg1_p2->y - seg1_p1->y); |
||
371 | seg2_dx = _cairo_fixed_to_double (seg2_p2->x - seg2_p1->x); |
||
372 | seg2_dy = _cairo_fixed_to_double (seg2_p2->y - seg2_p1->y); |
||
373 | denominator = (seg2_dy * seg1_dx) - (seg2_dx * seg1_dy); |
||
374 | if (denominator == 0) |
||
375 | return FALSE; |
||
376 | |||
377 | seg_start_dx = _cairo_fixed_to_double (seg1_p1->x - seg2_p1->x); |
||
378 | seg_start_dy = _cairo_fixed_to_double (seg1_p1->y - seg2_p1->y); |
||
379 | u_a = ((seg2_dx * seg_start_dy) - (seg2_dy * seg_start_dx)) / denominator; |
||
380 | u_b = ((seg1_dx * seg_start_dy) - (seg1_dy * seg_start_dx)) / denominator; |
||
381 | |||
382 | if (u_a <= 0 || u_a >= 1 || u_b <= 0 || u_b >= 1) |
||
383 | return FALSE; |
||
384 | |||
385 | intersection->x = seg1_p1->x + _cairo_fixed_from_double ((u_a * seg1_dx)); |
||
386 | intersection->y = seg1_p1->y + _cairo_fixed_from_double ((u_a * seg1_dy)); |
||
387 | return TRUE; |
||
388 | } |
||
389 | |||
1892 | serge | 390 | #else |
391 | # error Please define multiplication and other operands for your fixed-point type size |
||
392 | #endif |
||
393 | |||
394 | #endif /* CAIRO_FIXED_PRIVATE_H */=>=>><>><>>><>><>><>=>><>><>><> |