|
1 /* |
|
2 * Copyright (c) 2002 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Graphics Math Utility functions |
|
15 * |
|
16 */ |
|
17 |
|
18 #include "Gfxmath.h" |
|
19 |
|
20 |
|
21 /*-------------------------------------------------------------------*//*! |
|
22 * \brief Counts number of leading zeroes in an integer |
|
23 * \param value Integer value |
|
24 * \return Number of leading zeroes [0,32] |
|
25 * \note Example outputs: clz(0)=32, clz(1)=31, clz(-1)=0 |
|
26 * \todo We want to generate clz instruction for ARM if supported by the CPU |
|
27 *//*-------------------------------------------------------------------*/ |
|
28 |
|
29 static int svgClz32(unsigned int value) |
|
30 { |
|
31 int c = 0; |
|
32 |
|
33 if (value<(1u<<( 16 ))) |
|
34 c+=( 16 ); |
|
35 else |
|
36 value >>= ( 16 );; |
|
37 if (value<(1u<<( 8 ))) |
|
38 c+=( 8 ); |
|
39 else |
|
40 value >>= ( 8 );; |
|
41 if (value<(1u<<( 4 ))) |
|
42 c+=( 4 ); |
|
43 else |
|
44 value >>= ( 4 );; |
|
45 if (value<(1u<<( 2 ))) |
|
46 c+=( 2 ); |
|
47 else |
|
48 value >>= ( 2 );; |
|
49 c += 2 >> value; |
|
50 |
|
51 return c; |
|
52 |
|
53 } |
|
54 |
|
55 /*-------------------------------------------------------------------*//*! |
|
56 * \brief Returns absolute value of an integer |
|
57 * \param a 32-bit input value |
|
58 * \return abs(a) |
|
59 * \todo On many platforms it might be best to use native abs() ? |
|
60 *//*-------------------------------------------------------------------*/ |
|
61 static int svgAbs32 (int a) |
|
62 { |
|
63 return (a >= 0) ? a : -a; |
|
64 } |
|
65 |
|
66 static int svgGTEFloat(int lhs, int rhs) |
|
67 { |
|
68 int cmp; |
|
69 if ((lhs & rhs) >> 31) |
|
70 { |
|
71 cmp = (int)lhs <= (int)rhs; |
|
72 } |
|
73 else |
|
74 { |
|
75 cmp = (int)lhs >= (int)rhs; |
|
76 } |
|
77 return cmp; |
|
78 } |
|
79 |
|
80 static int svgLTEFloat(int lhs, int rhs) |
|
81 { |
|
82 /* Compare signed, if both are negative, we need to invert the result */ |
|
83 int cmp; |
|
84 if ((lhs & rhs) >> 31) |
|
85 { |
|
86 cmp = (int)lhs >= (int)rhs; |
|
87 } |
|
88 else |
|
89 { |
|
90 cmp = (int)lhs <= (int)rhs; |
|
91 } |
|
92 return cmp; |
|
93 } |
|
94 |
|
95 /** |
|
96 * \brief Clamping version of the fixed -> float conversion routine. That is, will not |
|
97 * create incorrect results on values > ~32768.0 or < -32768.0 |
|
98 * |
|
99 * \param f Input floating-point |
|
100 * \return Fixed-point number within 16.16 fixed-point range. |
|
101 */ |
|
102 int svgScalarFromFloat(float f) |
|
103 { |
|
104 int a; |
|
105 int sign; |
|
106 int exponent; |
|
107 |
|
108 int r; |
|
109 |
|
110 if (svgGTEFloat((*(int*)&f ), 0x47000000) ) |
|
111 { |
|
112 return 0x7fffffff; |
|
113 } |
|
114 else |
|
115 if (svgLTEFloat((*(int*)&f ), 0xc7000000) ) |
|
116 { |
|
117 return 0x80000000; |
|
118 } |
|
119 else |
|
120 { |
|
121 a = (*(int*)&f ); |
|
122 sign = a >> 31; |
|
123 exponent = (127 + 15) - ((a >> 23) & 0xff); |
|
124 |
|
125 r = (int)((((int)(a) << 8) | (1U << 31)) >> exponent); |
|
126 r &= ((exponent - 32) >> 31); |
|
127 |
|
128 r = (r ^ sign) - sign; |
|
129 |
|
130 return r; |
|
131 } |
|
132 } |
|
133 |
|
134 /*********************************************************************//*! |
|
135 * \internal |
|
136 * |
|
137 * \brief Converts a 16.16 fixed point value into a floating point |
|
138 * value |
|
139 * \param x Fixed point value |
|
140 * \returns Corresponding floating point value |
|
141 * \note This is essentially exactly the same routine as nglIntToFloat, |
|
142 * except that the exponent bias value is 16 smaller (thus |
|
143 * dividing the float by 65536). If we run out of space and |
|
144 * want to squeeze out a few extra bytes, we could write a |
|
145 * common routine where the scale factor is passed in as |
|
146 * a parameter. |
|
147 * |
|
148 ************************************************************************/ |
|
149 |
|
150 float svgFixedToFloat(int x) |
|
151 { |
|
152 unsigned int d = (unsigned int)(x) & 0x80000000u; /* get copy of sign */ |
|
153 int exponent; |
|
154 |
|
155 if (!x) /* special case handling for 0 */ |
|
156 return (float)(0); |
|
157 |
|
158 x = svgAbs32(x); /* get rid of sign (the code works only for unsigned values -> we add the sign later back) */ |
|
159 |
|
160 /*exponent = nglGetHighestSetBit((unsigned int)(x))-23;*//* get exponent and divide value */ |
|
161 exponent = 31 - svgClz32((unsigned int)(x)) - 23; |
|
162 |
|
163 if (exponent >= 0) /* "signed shift right" (we shift the mantissa to the proper place) */ |
|
164 x>>=exponent; |
|
165 else |
|
166 x<<=(-exponent); /*lint !e504 *//* yes, it is an unusual shift.. */ |
|
167 |
|
168 exponent += 127+23-16; /* convert exponent into biased form (divide by 65536 simultaneously!) */ |
|
169 exponent <<=23; /* shift exponent to proper place */ |
|
170 d |= (unsigned int)(exponent); /* combine sign with exponent */ |
|
171 x &= ((1<<23)-1); /* mask the mantissa */ |
|
172 d |= (unsigned int)(x); /* combine sign and exponent with mantissa */ |
|
173 |
|
174 return *(float*)&d; /* done */ |
|
175 } |
|
176 |
|
177 /*-------------------------------------------------------------------*//*! |
|
178 * \brief 32x32->64-bit signed multiplication |
|
179 * \param a 32-bit signed integer |
|
180 * \param b 32-bit signed integer |
|
181 * \return 64-bit signed result of the multiplication |
|
182 *//*-------------------------------------------------------------------*/ |
|
183 |
|
184 static svgInt64 svgMul64(int a, int b) |
|
185 { |
|
186 return (svgInt64)(a) * (int)(b); |
|
187 } |
|
188 /*=======================================================================*/ |
|
189 /*=======================================================================*/ |
|
190 |
|
191 int svgScalarMul(int r1, int r2) |
|
192 { |
|
193 |
|
194 svgInt64 a = svgMul64(r1, r2); |
|
195 int l = (int)(a); |
|
196 int h = (int)((svgUint64)(a)>>32); |
|
197 int r = (h << 16) | (((unsigned int)l) >> 16); /* r = 32 middle bits of the 64 bit result */ |
|
198 int hs = h >> 31; /* hs is either 0 or 0xffffffff */ |
|
199 /* test if there is data in the upper 17 bits of h */ |
|
200 if ( (h >> 15) != hs) |
|
201 r = (~hs) ^ 0x80000000; /* saturate (~hs to avoid a big constant on ARM) */ |
|
202 |
|
203 return r; |
|
204 } |
|
205 |
|
206 /*=======================================================================*/ |
|
207 /*=======================================================================*/ |
|
208 |
|
209 int svgScalarDiv(int x, int y) |
|
210 { |
|
211 unsigned int ax = x < 0 ? -x : x; |
|
212 unsigned int ay = y < 0 ? -y : y; |
|
213 unsigned int axh = ax >> 14; |
|
214 unsigned int axl = ax << 18; |
|
215 int q = 0, i; |
|
216 |
|
217 if ((axh >> 1) >= ay) |
|
218 { /* saturate when overflows */ |
|
219 if ( (x < 0) ^ (y < 0)) |
|
220 q = 0x80000000; |
|
221 else |
|
222 q = 0x7fffffff; |
|
223 } |
|
224 else |
|
225 { |
|
226 for (i = 30; i>=0; i--) |
|
227 { |
|
228 if (axh >= ay) |
|
229 { |
|
230 axh -= ay; |
|
231 q += 1<<i; |
|
232 } |
|
233 /* lsl64 #1 */ |
|
234 axh <<= 1; |
|
235 axh |= axl >> 31; /* add carry */ |
|
236 axl <<= 1; |
|
237 } |
|
238 if ( (x < 0) ^ (y < 0)) |
|
239 q = -q; |
|
240 } |
|
241 |
|
242 return q; |
|
243 } |