1 /**************************************************************************
3 * Copyright 2009 VMware, Inc. All Rights Reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 **************************************************************************/
30 #include "VG/openvg.h"
32 #include "pipe/p_compiler.h"
33 #include "util/u_math.h"
38 #define floatsEqual(x, y) (fabs(x - y) <= 0.00001f * MIN2(fabs(x), fabs(y)))
39 #define floatIsZero(x) (floatsEqual((x) + 1, 1))
40 #define ABS(x) (fabsf(x))
42 #define DEGREES_TO_RADIANS(d) (0.0174532925199 * (d))
43 #define FLT_TO_INT(flt) float_to_int_floor(((VGuint*)&(flt))[0])
45 static INLINE VGint
float_to_int_floor(VGuint bits
)
47 int sign
= (bits
>> 31) ? -1 : 1;
48 int exp
= ((bits
>> 23) & 255) - 127;
49 int mant
= bits
& 0x007fffff;
52 /* abs(value) >= 2^31 -> clamp. */
55 return (VGint
)((sign
< 0) ? 0x80000000u
: 0x7fffffffu
);
57 /* abs(value) < 1 -> return -1 or 0. */
60 return (sign
< 0 && (exp
> -127 || mant
!= 0)) ? -1 : 0;
62 /* abs(value) >= 2^23 -> shift left. */
66 return sign
* (mant
<< -sh
);
68 /* Negative -> add a rounding term. */
71 mant
+= (1 << sh
) - 1;
73 /* Shift right to obtain the result. */
75 return sign
* (mant
>> sh
);
83 static INLINE
void matrix_init(struct matrix
*mat
,
86 memcpy(mat
->m
, val
, sizeof(VGfloat
) * 9);
89 static INLINE
void matrix_inits(struct matrix
*mat
,
90 VGfloat m11
, VGfloat m12
, VGfloat m13
,
91 VGfloat m21
, VGfloat m22
, VGfloat m23
,
92 VGfloat m31
, VGfloat m32
, VGfloat m33
)
94 mat
->m
[0] = m11
; mat
->m
[1] = m12
; mat
->m
[2] = m13
;
95 mat
->m
[3] = m21
; mat
->m
[4] = m22
; mat
->m
[5] = m23
;
96 mat
->m
[6] = m31
; mat
->m
[7] = m32
; mat
->m
[8] = m33
;
99 static INLINE
void matrix_load_identity(struct matrix
*matrix
)
101 static const VGfloat identity
[9] = {1.f
, 0.f
, 0.f
,
104 memcpy(matrix
->m
, identity
, sizeof(identity
));
107 static INLINE VGboolean
matrix_is_identity(struct matrix
*matrix
)
109 return floatsEqual(matrix
->m
[0], 1) && floatIsZero(matrix
->m
[1]) &&
110 floatIsZero(matrix
->m
[2]) &&
111 floatIsZero(matrix
->m
[3]) && floatsEqual(matrix
->m
[4], 1) &&
112 floatIsZero(matrix
->m
[5]) &&
113 floatIsZero(matrix
->m
[6]) && floatIsZero(matrix
->m
[7]) &&
114 floatIsZero(matrix
->m
[8]);
117 static INLINE VGboolean
matrix_is_affine(struct matrix
*matrix
)
119 return floatIsZero(matrix
->m
[2]) && floatIsZero(matrix
->m
[5])
120 && floatsEqual(matrix
->m
[8], 1);
124 static INLINE
void matrix_make_affine(struct matrix
*matrix
)
131 static INLINE
void matrix_mult(struct matrix
*dst
,
134 VGfloat m11
= dst
->m
[0]*src
->m
[0] + dst
->m
[3]*src
->m
[1] + dst
->m
[6]*src
->m
[2];
135 VGfloat m12
= dst
->m
[0]*src
->m
[3] + dst
->m
[3]*src
->m
[4] + dst
->m
[6]*src
->m
[5];
136 VGfloat m13
= dst
->m
[0]*src
->m
[6] + dst
->m
[3]*src
->m
[7] + dst
->m
[6]*src
->m
[8];
138 VGfloat m21
= dst
->m
[1]*src
->m
[0] + dst
->m
[4]*src
->m
[1] + dst
->m
[7]*src
->m
[2];
139 VGfloat m22
= dst
->m
[1]*src
->m
[3] + dst
->m
[4]*src
->m
[4] + dst
->m
[7]*src
->m
[5];
140 VGfloat m23
= dst
->m
[1]*src
->m
[6] + dst
->m
[4]*src
->m
[7] + dst
->m
[7]*src
->m
[8];
142 VGfloat m31
= dst
->m
[2]*src
->m
[0] + dst
->m
[5]*src
->m
[1] + dst
->m
[8]*src
->m
[2];
143 VGfloat m32
= dst
->m
[2]*src
->m
[3] + dst
->m
[5]*src
->m
[4] + dst
->m
[8]*src
->m
[5];
144 VGfloat m33
= dst
->m
[2]*src
->m
[6] + dst
->m
[5]*src
->m
[7] + dst
->m
[8]*src
->m
[8];
146 dst
->m
[0] = m11
; dst
->m
[1] = m21
; dst
->m
[2] = m31
;
147 dst
->m
[3] = m12
; dst
->m
[4] = m22
; dst
->m
[5] = m32
;
148 dst
->m
[6] = m13
; dst
->m
[7] = m23
; dst
->m
[8] = m33
;
152 static INLINE
void matrix_map_point(struct matrix
*mat
,
153 VGfloat x
, VGfloat y
,
154 VGfloat
*out_x
, VGfloat
*out_y
)
156 /* to be able to do matrix_map_point(m, x, y, &x, &y) use
158 VGfloat tmp_x
= x
, tmp_y
= y
;
160 *out_x
= mat
->m
[0]*tmp_x
+ mat
->m
[3]*tmp_y
+ mat
->m
[6];
161 *out_y
= mat
->m
[1]*tmp_x
+ mat
->m
[4]*tmp_y
+ mat
->m
[7];
162 if (!matrix_is_affine(mat
)) {
163 VGfloat w
= 1/(mat
->m
[2]*tmp_x
+ mat
->m
[5]*tmp_y
+ mat
->m
[8]);
169 static INLINE
void matrix_translate(struct matrix
*dst
,
170 VGfloat tx
, VGfloat ty
)
172 if (!matrix_is_affine(dst
)) {
173 struct matrix trans_matrix
;
174 matrix_load_identity(&trans_matrix
);
175 trans_matrix
.m
[6] = tx
;
176 trans_matrix
.m
[7] = ty
;
177 matrix_mult(dst
, &trans_matrix
);
179 dst
->m
[6] += tx
*dst
->m
[0] + ty
*dst
->m
[3];
180 dst
->m
[7] += ty
*dst
->m
[4] + tx
*dst
->m
[1];
184 static INLINE
void matrix_scale(struct matrix
*dst
,
185 VGfloat sx
, VGfloat sy
)
187 if (!matrix_is_affine(dst
)) {
188 struct matrix scale_matrix
;
189 matrix_load_identity(&scale_matrix
);
190 scale_matrix
.m
[0] = sx
;
191 scale_matrix
.m
[4] = sy
;
192 matrix_mult(dst
, &scale_matrix
);
194 dst
->m
[0] *= sx
; dst
->m
[1] *= sx
;
195 dst
->m
[3] *= sy
; dst
->m
[4] *= sy
;
199 static INLINE
void matrix_shear(struct matrix
*dst
,
200 VGfloat shx
, VGfloat shy
)
202 struct matrix shear_matrix
;
203 matrix_load_identity(&shear_matrix
);
204 shear_matrix
.m
[1] = shy
;
205 shear_matrix
.m
[3] = shx
;
206 matrix_mult(dst
, &shear_matrix
);
209 static INLINE
void matrix_rotate(struct matrix
*dst
,
217 if (floatsEqual(angle
, 90) || floatsEqual(angle
, -270))
219 else if (floatsEqual(angle
, 270) || floatsEqual(angle
, -90))
221 else if (floatsEqual(angle
, 180))
224 float radians
= DEGREES_TO_RADIANS(angle
);
225 sin_val
= sin(radians
);
226 cos_val
= cos(radians
);
229 if (!matrix_is_affine(dst
)) {
230 matrix_load_identity(&mat
);
231 mat
.m
[0] = cos_val
; mat
.m
[1] = sin_val
;
232 mat
.m
[3] = -sin_val
; mat
.m
[4] = cos_val
;
234 matrix_mult(dst
, &mat
);
236 VGfloat m11
= cos_val
*dst
->m
[0] + sin_val
*dst
->m
[3];
237 VGfloat m12
= cos_val
*dst
->m
[1] + sin_val
*dst
->m
[4];
238 VGfloat m21
= -sin_val
*dst
->m
[0] + cos_val
*dst
->m
[3];
239 VGfloat m22
= -sin_val
*dst
->m
[1] + cos_val
*dst
->m
[4];
240 dst
->m
[0] = m11
; dst
->m
[1] = m12
;
241 dst
->m
[3] = m21
; dst
->m
[4] = m22
;
246 static INLINE VGfloat
matrix_determinant(struct matrix
*mat
)
248 return mat
->m
[0]*(mat
->m
[8]*mat
->m
[4]-mat
->m
[7]*mat
->m
[5]) -
249 mat
->m
[3]*(mat
->m
[8]*mat
->m
[1]-mat
->m
[7]*mat
->m
[2])+
250 mat
->m
[6]*(mat
->m
[5]*mat
->m
[1]-mat
->m
[4]*mat
->m
[2]);
254 static INLINE
void matrix_adjoint(struct matrix
*mat
)
257 h
[0] = mat
->m
[4]*mat
->m
[8] - mat
->m
[5]*mat
->m
[7];
258 h
[3] = mat
->m
[5]*mat
->m
[6] - mat
->m
[3]*mat
->m
[8];
259 h
[6] = mat
->m
[3]*mat
->m
[7] - mat
->m
[4]*mat
->m
[6];
260 h
[1] = mat
->m
[2]*mat
->m
[7] - mat
->m
[1]*mat
->m
[8];
261 h
[4] = mat
->m
[0]*mat
->m
[8] - mat
->m
[2]*mat
->m
[6];
262 h
[7] = mat
->m
[1]*mat
->m
[6] - mat
->m
[0]*mat
->m
[7];
263 h
[2] = mat
->m
[1]*mat
->m
[5] - mat
->m
[2]*mat
->m
[4];
264 h
[5] = mat
->m
[2]*mat
->m
[3] - mat
->m
[0]*mat
->m
[5];
265 h
[8] = mat
->m
[0]*mat
->m
[4] - mat
->m
[1]*mat
->m
[3];
268 memcpy(mat
->m
, h
, sizeof(VGfloat
) * 9);
271 static INLINE
void matrix_divs(struct matrix
*mat
,
285 static INLINE VGboolean
matrix_invert(struct matrix
*mat
)
287 VGfloat det
= matrix_determinant(mat
);
289 if (floatIsZero(det
))
293 matrix_divs(mat
, det
);
297 static INLINE VGboolean
matrix_is_invertible(struct matrix
*mat
)
299 return !floatIsZero(matrix_determinant(mat
));
303 static INLINE VGboolean
matrix_square_to_quad(VGfloat dx0
, VGfloat dy0
,
304 VGfloat dx1
, VGfloat dy1
,
305 VGfloat dx3
, VGfloat dy3
,
306 VGfloat dx2
, VGfloat dy2
,
309 VGfloat ax
= dx0
- dx1
+ dx2
- dx3
;
310 VGfloat ay
= dy0
- dy1
+ dy2
- dy3
;
312 if (floatIsZero(ax
) && floatIsZero(ay
)) {
315 dx1
- dx0
, dy1
- dy0
, 0,
316 dx2
- dx1
, dy2
- dy1
, 0,
319 VGfloat a
, b
, c
, d
, e
, f
, g
, h
;
320 VGfloat ax1
= dx1
- dx2
;
321 VGfloat ax2
= dx3
- dx2
;
322 VGfloat ay1
= dy1
- dy2
;
323 VGfloat ay2
= dy3
- dy2
;
326 VGfloat gtop
= ax
* ay2
- ax2
* ay
;
327 VGfloat htop
= ax1
* ay
- ax
* ay1
;
328 VGfloat bottom
= ax1
* ay2
- ax2
* ay1
;
336 a
= dx1
- dx0
+ g
* dx1
;
337 b
= dx3
- dx0
+ h
* dx3
;
339 d
= dy1
- dy0
+ g
* dy1
;
340 e
= dy3
- dy0
+ h
* dy3
;
352 static INLINE VGboolean
matrix_quad_to_square(VGfloat sx0
, VGfloat sy0
,
353 VGfloat sx1
, VGfloat sy1
,
354 VGfloat sx2
, VGfloat sy2
,
355 VGfloat sx3
, VGfloat sy3
,
358 if (!matrix_square_to_quad(sx0
, sy0
, sx1
, sy1
,
363 return matrix_invert(mat
);
367 static INLINE VGboolean
matrix_quad_to_quad(VGfloat dx0
, VGfloat dy0
,
368 VGfloat dx1
, VGfloat dy1
,
369 VGfloat dx2
, VGfloat dy2
,
370 VGfloat dx3
, VGfloat dy3
,
371 VGfloat sx0
, VGfloat sy0
,
372 VGfloat sx1
, VGfloat sy1
,
373 VGfloat sx2
, VGfloat sy2
,
374 VGfloat sx3
, VGfloat sy3
,
377 struct matrix sqr_to_qd
;
379 if (!matrix_square_to_quad(dx0
, dy0
, dx1
, dy1
,
384 if (!matrix_quad_to_square(sx0
, sy0
, sx1
, sy1
,
389 matrix_mult(mat
, &sqr_to_qd
);
395 static INLINE VGboolean
null_line(const VGfloat
*l
)
397 return floatsEqual(l
[0], l
[2]) && floatsEqual(l
[1], l
[3]);
400 static INLINE
void line_normal(float *l
, float *norm
)
405 norm
[2] = l
[0] + (l
[3] - l
[1]);
406 norm
[3] = l
[1] - (l
[2] - l
[0]);
409 static INLINE
void line_normalize(float *l
)
411 float x
= l
[2] - l
[0];
412 float y
= l
[3] - l
[1];
413 float len
= sqrt(x
*x
+ y
*y
);
418 static INLINE VGfloat
line_length(VGfloat x1
, VGfloat y1
,
419 VGfloat x2
, VGfloat y2
)
423 return sqrt(x
*x
+ y
*y
);
426 static INLINE VGfloat
line_lengthv(const VGfloat
*l
)
428 VGfloat x
= l
[2] - l
[0];
429 VGfloat y
= l
[3] - l
[1];
430 return sqrt(x
*x
+ y
*y
);
434 static INLINE
void line_point_at(float *l
, float t
, float *pt
)
436 float dx
= l
[2] - l
[0];
437 float dy
= l
[3] - l
[1];
439 pt
[0] = l
[0] + dx
* t
;
440 pt
[1] = l
[1] + dy
* t
;
443 static INLINE
void vector_unit(float *vec
)
445 float len
= sqrt(vec
[0] * vec
[0] + vec
[1] * vec
[1]);
450 static INLINE
void line_normal_vector(float *line
, float *vec
)
454 line_normal(line
, normal
);
456 vec
[0] = normal
[2] - normal
[0];
457 vec
[1] = normal
[3] - normal
[1];