1 // SONIC ROBO BLAST 2
2 //-----------------------------------------------------------------------------
3 // Copyright (C) 1993-1996 by id Software, Inc.
4 // Copyright (C) 1998-2000 by DooM Legacy Team.
5 // Copyright (C) 1999-2020 by Sonic Team Junior.
6 //
7 // This program is free software distributed under the
8 // terms of the GNU General Public License, version 2.
9 // See the 'LICENSE' file for more details.
10 //-----------------------------------------------------------------------------
11 /// \file  m_fixed.h
12 /// \brief Fixed point arithmetics implementation
13 ///        Fixed point, 32bit as 16.16.
14 
15 #ifndef __M_FIXED__
16 #define __M_FIXED__
17 
18 #include "doomtype.h"
19 #ifdef __GNUC__
20 #include <stdlib.h>
21 #endif
22 
23 /*!
24   \brief bits of the fraction
25 */
26 #define FRACBITS 16
27 /*!
28   \brief units of the fraction
29 */
30 #define FRACUNIT (1<<FRACBITS)
31 #define FRACMASK (FRACUNIT -1)
32 /**	\brief	Redefinition of INT32 as fixed_t
33 	unit used as fixed_t
34 */
35 
36 typedef INT32 fixed_t;
37 
38 /*!
39   \brief convert fixed_t into floating number
40 */
41 
FixedToFloat(fixed_t x)42 FUNCMATH FUNCINLINE static ATTRINLINE float FixedToFloat(fixed_t x)
43 {
44 	return x / (float)FRACUNIT;
45 }
46 
FloatToFixed(float f)47 FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FloatToFixed(float f)
48 {
49 	return (fixed_t)(f * FRACUNIT);
50 }
51 
52 // for backwards compat
53 #define FIXED_TO_FLOAT(x) FixedToFloat(x) // (((float)(x)) / ((float)FRACUNIT))
54 #define FLOAT_TO_FIXED(f) FloatToFixed(f) // (fixed_t)((f) * ((float)FRACUNIT))
55 
56 
57 #if defined (__WATCOMC__) && FRACBITS == 16
58 	#pragma aux FixedMul =  \
59 		"imul ebx",         \
60 		"shrd eax,edx,16"   \
61 		parm    [eax] [ebx] \
62 		value   [eax]       \
63 		modify exact [eax edx]
64 
65 	#pragma aux FixedDiv2 = \
66 		"cdq",              \
67 		"shld edx,eax,16",  \
68 		"sal eax,16",       \
69 		"idiv ebx"          \
70 		parm    [eax] [ebx] \
71 		value   [eax]       \
72 		modify exact [eax edx]
73 #elif defined (__GNUC__) && defined (__i386__) && !defined (NOASM)
74 	// DJGPP, i386 linux, cygwin or mingw
FixedMul(fixed_t a,fixed_t b)75 	FUNCMATH FUNCINLINE static inline fixed_t FixedMul(fixed_t a, fixed_t b) // asm
76 	{
77 		fixed_t ret;
78 		asm
79 		(
80 			 "imull %2;"           // a*b
81 			 "shrdl %3,%%edx,%0;"  // shift logical right FRACBITS bits
82 			:"=a" (ret)            // eax is always the result and the first operand (%0,%1)
83 			:"0" (a), "r" (b)      // and %2 is what we use imull on with what in %1
84 			, "I" (FRACBITS)       // %3 holds FRACBITS (normally 16)
85 			:"cc", "%edx"         // edx and condition codes clobbered
86 		);
87 		return ret;
88 	}
89 
FixedDiv2(fixed_t a,fixed_t b)90 	FUNCMATH FUNCINLINE static inline fixed_t FixedDiv2(fixed_t a, fixed_t b)
91 	{
92 		fixed_t ret;
93 		asm
94 		(
95 			  "movl  %1,%%edx;"    // these two instructions allow the next two to pair, on the Pentium processor.
96 			  "sarl  $31,%%edx;"   // shift arithmetic right 31 on EDX
97 			  "shldl %3,%1,%%edx;" // DP shift logical left FRACBITS on EDX
98 			  "sall  %3,%0;"       // shift arithmetic left FRACBITS on EAX
99 			  "idivl %2;"          // EDX/b = EAX
100 			: "=a" (ret)
101 			: "0" (a), "r" (b)
102 			, "I" (FRACBITS)
103 			: "%edx"
104 		);
105 		return ret;
106 	}
107 #elif defined (__GNUC__) && defined (__arm__) && !defined(__thumb__) && !defined(NOASM) //ARMv4 ASM
FixedMul(fixed_t a,fixed_t b)108 	FUNCMATH FUNCINLINE static inline fixed_t FixedMul(fixed_t a, fixed_t b) // let abuse smull
109 	{
110 		fixed_t ret;
111 		asm
112 		(
113 			  "smull %[lo], r1, %[a], %[b];"
114 			  "mov %[lo], %[lo], lsr %3;"
115 			  "orr %[lo], %[lo], r1, lsl %3;"
116 			: [lo] "=&r" (ret) // rhi, rlo and rm must be distinct registers
117 			: [a] "r" (a), [b] "r" (b)
118 			, "i" (FRACBITS)
119 			: "r1"
120 		);
121 		return ret;
122 	}
123 
124 	#define __USE_C_FIXEDDIV__ // no double or asm div in ARM land
125 #elif defined (__GNUC__) && defined (__ppc__) && !defined(NOASM) && 0 // WII: PPC CPU
FixedMul(fixed_t a,fixed_t b)126 	FUNCMATH FUNCINLINE static inline fixed_t FixedMul(fixed_t a, fixed_t b) // asm
127 	{
128 		fixed_t ret, hi, lo;
129 		asm
130 		(
131 			  "mullw %0, %2, %3;"
132 			  "mulhw %1, %2, %3"
133 			: "=r" (hi), "=r" (lo)
134 			: "r" (a), "r" (b)
135 			, "I" (FRACBITS)
136 		);
137 		ret = (INT64)((hi>>FRACBITS)+lo)<<FRACBITS;
138 		return ret;
139 	}
140 
141 	#define __USE_C_FIXEDDIV__// Alam: I am lazy
142 #elif defined (__GNUC__) && defined (__mips__) && !defined(NOASM) && 0 // PSP: MIPS CPU
FixedMul(fixed_t a,fixed_t b)143 	FUNCMATH FUNCINLINE static inline fixed_t FixedMul(fixed_t a, fixed_t b) // asm
144 	{
145 		fixed_t ret;
146 		asm
147 		(
148 			  "mult %3, %4;"    // a*b=h<32+l
149 			: "=r" (ret), "=l" (a), "=h" (b) //todo: abuse shr opcode
150 			: "0" (a), "r" (b)
151 			, "I" (FRACBITS)
152 			//: "+l", "+h"
153 		);
154 		ret = (INT64)((a>>FRACBITS)+b)<<FRACBITS;
155 		return ret;
156 	}
157 
158 	#define __USE_C_FIXEDDIV__ // no 64b asm div in MIPS land
159 #elif defined (__GNUC__) && defined (__sh__) && 0 // DC: SH4 CPU
160 #elif defined (__GNUC__) && defined (__m68k__) && 0 // DEAD: Motorola 6800 CPU
161 #elif defined (_MSC_VER) && defined(USEASM) && FRACBITS == 16
162 	// Microsoft Visual C++ (no asm inline)
163 	fixed_t __cdecl FixedMul(fixed_t a, fixed_t b);
164 	fixed_t __cdecl FixedDiv2(fixed_t a, fixed_t b);
165 #else
166 	#define __USE_C_FIXEDMUL__
167 	#define __USE_C_FIXEDDIV__
168 #endif
169 
170 #ifdef __USE_C_FIXEDMUL__
171 FUNCMATH fixed_t FixedMul(fixed_t a, fixed_t b);
172 #endif
173 
174 #ifdef __USE_C_FIXEDDIV__
175 FUNCMATH fixed_t FixedDiv2(fixed_t a, fixed_t b);
176 #endif
177 
178 /**	\brief	The FixedInt function
179 
180 	\param	a	fixed_t number
181 
182 	\return	 a/FRACUNIT
183 */
184 
FixedInt(fixed_t a)185 FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedInt(fixed_t a)
186 {
187 	return FixedMul(a, 1);
188 }
189 
190 /**	\brief	The FixedDiv function
191 
192 	\param	a	fixed_t number
193 	\param	b	fixed_t number
194 
195 	\return	a/b
196 
197 
198 */
FixedDiv(fixed_t a,fixed_t b)199 FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedDiv(fixed_t a, fixed_t b)
200 {
201 	if ((abs(a) >> (FRACBITS-2)) >= abs(b))
202 		return (a^b) < 0 ? INT32_MIN : INT32_MAX;
203 
204 	return FixedDiv2(a, b);
205 }
206 
207 /**	\brief	The FixedSqrt function
208 
209 	\param	x	fixed_t number
210 
211 	\return	sqrt(x)
212 
213 
214 */
215 FUNCMATH fixed_t FixedSqrt(fixed_t x);
216 
217 /**	\brief	The FixedHypot function
218 
219 	\param	x	fixed_t number
220 	\param	y	fixed_t number
221 
222 	\return	sqrt(x*x+y*y)
223 
224 
225 */
226 FUNCMATH fixed_t FixedHypot(fixed_t x, fixed_t y);
227 
228 /**	\brief	The FixedFloor function
229 
230 	\param	x	fixed_t number
231 
232 	\return	floor(x)
233 
234 
235 */
FixedFloor(fixed_t x)236 FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedFloor(fixed_t x)
237 {
238 	const fixed_t a = abs(x); //absolute of x
239 	const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
240 	const fixed_t f = a-i; // cut out the integral part
241 	if (f == 0)
242 		return x;
243 	if (x != INT32_MIN)
244 	{ // return rounded down to nearest whole number
245 		if (x > 0)
246 			return x-f;
247 		else
248 			return x-(FRACUNIT-f);
249 	}
250 	return INT32_MIN;
251 }
252 
253 /**	\brief	The FixedTrunc function
254 
255 	\param	x	fixed_t number
256 
257 	\return trunc(x)
258 
259 
260 */
FixedTrunc(fixed_t x)261 FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedTrunc(fixed_t x)
262 {
263 	const fixed_t a = abs(x); //absolute of x
264 	const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
265 	const fixed_t f = a-i; // cut out the integral part
266 	if (x != INT32_MIN)
267 	{ // return rounded to nearest whole number, towards zero
268 		if (x > 0)
269 			return x-f;
270 		else
271 			return x+f;
272 	}
273 	return INT32_MIN;
274 }
275 
276 /**	\brief	The FixedCeil function
277 
278 	\param	x	fixed_t number
279 
280 	\return	ceil(x)
281 
282 
283 */
FixedCeil(fixed_t x)284 FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedCeil(fixed_t x)
285 {
286 	const fixed_t a = abs(x); //absolute of x
287 	const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
288 	const fixed_t f = a-i; // cut out the integral part
289 	if (f == 0)
290 		return x;
291 	if (x == INT32_MIN)
292 		return INT32_MIN;
293 	else if (x < FixedFloor(INT32_MAX))
294 	{ // return rounded up to nearest whole number
295 		if (x > 0)
296 			return x+(FRACUNIT-f);
297 		else
298 			return x+f;
299 	}
300 	return INT32_MAX;
301 }
302 
303 /**	\brief	The FixedRound function
304 
305 	\param	x	fixed_t number
306 
307 	\return	round(x)
308 
309 
310 */
FixedRound(fixed_t x)311 FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedRound(fixed_t x)
312 {
313 	const fixed_t a = abs(x); //absolute of x
314 	const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
315 	const fixed_t f = a-i; // cut out the integral part
316 	if (f == 0)
317 		return x;
318 	if (x == INT32_MIN)
319 		return INT32_MIN;
320 	else if (x < FixedFloor(INT32_MAX))
321 	{ // return rounded to nearest whole number, away from zero
322 		if (x > 0)
323 			return x+(FRACUNIT-f);
324 		else
325 			return x-(FRACUNIT-f);
326 	}
327 	return INT32_MAX;
328 }
329 
330 typedef struct
331 {
332 	fixed_t x;
333 	fixed_t y;
334 } vector2_t;
335 
336 vector2_t *FV2_Load(vector2_t *vec, fixed_t x, fixed_t y);
337 vector2_t *FV2_UnLoad(vector2_t *vec, fixed_t *x, fixed_t *y);
338 vector2_t *FV2_Copy(vector2_t *a_o, const vector2_t *a_i);
339 vector2_t *FV2_AddEx(const vector2_t *a_i, const vector2_t *a_c, vector2_t *a_o);
340 vector2_t *FV2_Add(vector2_t *a_i, const vector2_t *a_c);
341 vector2_t *FV2_SubEx(const vector2_t *a_i, const vector2_t *a_c, vector2_t *a_o);
342 vector2_t *FV2_Sub(vector2_t *a_i, const vector2_t *a_c);
343 vector2_t *FV2_MulEx(const vector2_t *a_i, fixed_t a_c, vector2_t *a_o);
344 vector2_t *FV2_Mul(vector2_t *a_i, fixed_t a_c);
345 vector2_t *FV2_DivideEx(const vector2_t *a_i, fixed_t a_c, vector2_t *a_o);
346 vector2_t *FV2_Divide(vector2_t *a_i, fixed_t a_c);
347 vector2_t *FV2_Midpoint(const vector2_t *a_1, const vector2_t *a_2, vector2_t *a_o);
348 fixed_t FV2_Distance(const vector2_t *p1, const vector2_t *p2);
349 fixed_t FV2_Magnitude(const vector2_t *a_normal);
350 fixed_t FV2_NormalizeEx(const vector2_t *a_normal, vector2_t *a_o);
351 fixed_t FV2_Normalize(vector2_t *a_normal);
352 vector2_t *FV2_NegateEx(const vector2_t *a_1, vector2_t *a_o);
353 vector2_t *FV2_Negate(vector2_t *a_1);
354 boolean FV2_Equal(const vector2_t *a_1, const vector2_t *a_2);
355 fixed_t FV2_Dot(const vector2_t *a_1, const vector2_t *a_2);
356 vector2_t *FV2_Point2Vec (const vector2_t *point1, const vector2_t *point2, vector2_t *a_o);
357 
358 typedef struct
359 {
360 	fixed_t x, y, z;
361 } vector3_t;
362 
363 vector3_t *FV3_Load(vector3_t *vec, fixed_t x, fixed_t y, fixed_t z);
364 vector3_t *FV3_UnLoad(vector3_t *vec, fixed_t *x, fixed_t *y, fixed_t *z);
365 vector3_t *FV3_Copy(vector3_t *a_o, const vector3_t *a_i);
366 vector3_t *FV3_AddEx(const vector3_t *a_i, const vector3_t *a_c, vector3_t *a_o);
367 vector3_t *FV3_Add(vector3_t *a_i, const vector3_t *a_c);
368 vector3_t *FV3_SubEx(const vector3_t *a_i, const vector3_t *a_c, vector3_t *a_o);
369 vector3_t *FV3_Sub(vector3_t *a_i, const vector3_t *a_c);
370 vector3_t *FV3_MulEx(const vector3_t *a_i, fixed_t a_c, vector3_t *a_o);
371 vector3_t *FV3_Mul(vector3_t *a_i, fixed_t a_c);
372 vector3_t *FV3_DivideEx(const vector3_t *a_i, fixed_t a_c, vector3_t *a_o);
373 vector3_t *FV3_Divide(vector3_t *a_i, fixed_t a_c);
374 vector3_t *FV3_Midpoint(const vector3_t *a_1, const vector3_t *a_2, vector3_t *a_o);
375 fixed_t FV3_Distance(const vector3_t *p1, const vector3_t *p2);
376 fixed_t FV3_Magnitude(const vector3_t *a_normal);
377 fixed_t FV3_NormalizeEx(const vector3_t *a_normal, vector3_t *a_o);
378 fixed_t FV3_Normalize(vector3_t *a_normal);
379 vector3_t *FV3_NegateEx(const vector3_t *a_1, vector3_t *a_o);
380 vector3_t *FV3_Negate(vector3_t *a_1);
381 boolean FV3_Equal(const vector3_t *a_1, const vector3_t *a_2);
382 fixed_t FV3_Dot(const vector3_t *a_1, const vector3_t *a_2);
383 vector3_t *FV3_Cross(const vector3_t *a_1, const vector3_t *a_2, vector3_t *a_o);
384 vector3_t *FV3_ClosestPointOnLine(const vector3_t *Line, const vector3_t *p, vector3_t *out);
385 void FV3_ClosestPointOnVector(const vector3_t *dir, const vector3_t *p, vector3_t *out);
386 void FV3_ClosestPointOnTriangle(const vector3_t *tri, const vector3_t *point, vector3_t *result);
387 vector3_t *FV3_Point2Vec(const vector3_t *point1, const vector3_t *point2, vector3_t *a_o);
388 fixed_t FV3_Normal(const vector3_t *a_triangle, vector3_t *a_normal);
389 fixed_t FV3_Strength(const vector3_t *a_1, const vector3_t *dir);
390 fixed_t FV3_PlaneDistance(const vector3_t *a_normal, const vector3_t *a_point);
391 boolean FV3_IntersectedPlane(const vector3_t *a_triangle, const vector3_t *a_line, vector3_t *a_normal, fixed_t *originDistance);
392 fixed_t FV3_PlaneIntersection(const vector3_t *pOrigin, const vector3_t *pNormal, const vector3_t *rOrigin, const vector3_t *rVector);
393 fixed_t FV3_IntersectRaySphere(const vector3_t *rO, const vector3_t *rV, const vector3_t *sO, fixed_t sR);
394 vector3_t *FV3_IntersectionPoint(const vector3_t *vNormal, const vector3_t *vLine, fixed_t distance, vector3_t *ReturnVec);
395 UINT8 FV3_PointOnLineSide(const vector3_t *point, const vector3_t *line);
396 boolean FV3_PointInsideBox(const vector3_t *point, const vector3_t *box);
397 
398 typedef struct
399 {
400 	fixed_t m[16];
401 } matrix_t;
402 
403 void FM_LoadIdentity(matrix_t* matrix);
404 void FM_CreateObjectMatrix(matrix_t *matrix, fixed_t x, fixed_t y, fixed_t z, fixed_t anglex, fixed_t angley, fixed_t anglez, fixed_t upx, fixed_t upy, fixed_t upz, fixed_t radius);
405 void FM_MultMatrixVec3(const matrix_t *matrix, const vector3_t *vec, vector3_t *out);
406 void FM_MultMatrix(matrix_t *dest, const matrix_t *multme);
407 void FM_Translate(matrix_t *dest, fixed_t x, fixed_t y, fixed_t z);
408 void FM_Scale(matrix_t *dest, fixed_t x, fixed_t y, fixed_t z);
409 
410 #endif //m_fixed.h
411