1 | /* |
2 | Simple DirectMedia Layer |
3 | Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org> |
4 | |
5 | This software is provided 'as-is', without any express or implied |
6 | warranty. In no event will the authors be held liable for any damages |
7 | arising from the use of this software. |
8 | |
9 | Permission is granted to anyone to use this software for any purpose, |
10 | including commercial applications, and to alter it and redistribute it |
11 | freely, subject to the following restrictions: |
12 | |
13 | 1. The origin of this software must not be misrepresented; you must not |
14 | claim that you wrote the original software. If you use this software |
15 | in a product, an acknowledgment in the product documentation would be |
16 | appreciated but is not required. |
17 | 2. Altered source versions must be plainly marked as such, and must not be |
18 | misrepresented as being the original software. |
19 | 3. This notice may not be removed or altered from any source distribution. |
20 | */ |
21 | #include "SDL_internal.h" |
22 | |
23 | // This file contains portable stdlib functions for SDL |
24 | |
25 | #include "../libm/math_libm.h" |
26 | |
27 | double SDL_atan(double x) |
28 | { |
29 | #ifdef HAVE_ATAN |
30 | return atan(x); |
31 | #else |
32 | return SDL_uclibc_atan(x); |
33 | #endif |
34 | } |
35 | |
36 | float SDL_atanf(float x) |
37 | { |
38 | #ifdef HAVE_ATANF |
39 | return atanf(x); |
40 | #else |
41 | return (float)SDL_atan((double)x); |
42 | #endif |
43 | } |
44 | |
45 | double SDL_atan2(double y, double x) |
46 | { |
47 | #ifdef HAVE_ATAN2 |
48 | return atan2(y, x); |
49 | #else |
50 | return SDL_uclibc_atan2(y, x); |
51 | #endif |
52 | } |
53 | |
54 | float SDL_atan2f(float y, float x) |
55 | { |
56 | #ifdef HAVE_ATAN2F |
57 | return atan2f(y, x); |
58 | #else |
59 | return (float)SDL_atan2((double)y, (double)x); |
60 | #endif |
61 | } |
62 | |
63 | double SDL_acos(double val) |
64 | { |
65 | #ifdef HAVE_ACOS |
66 | return acos(val); |
67 | #else |
68 | double result; |
69 | if (val == -1.0) { |
70 | result = SDL_PI_D; |
71 | } else { |
72 | result = SDL_atan(SDL_sqrt(1.0 - val * val) / val); |
73 | if (result < 0.0) { |
74 | result += SDL_PI_D; |
75 | } |
76 | } |
77 | return result; |
78 | #endif |
79 | } |
80 | |
81 | float SDL_acosf(float val) |
82 | { |
83 | #ifdef HAVE_ACOSF |
84 | return acosf(val); |
85 | #else |
86 | return (float)SDL_acos((double)val); |
87 | #endif |
88 | } |
89 | |
90 | double SDL_asin(double val) |
91 | { |
92 | #ifdef HAVE_ASIN |
93 | return asin(val); |
94 | #else |
95 | double result; |
96 | if (val == -1.0) { |
97 | result = -(SDL_PI_D / 2.0); |
98 | } else { |
99 | result = (SDL_PI_D / 2.0) - SDL_acos(val); |
100 | } |
101 | return result; |
102 | #endif |
103 | } |
104 | |
105 | float SDL_asinf(float val) |
106 | { |
107 | #ifdef HAVE_ASINF |
108 | return asinf(val); |
109 | #else |
110 | return (float)SDL_asin((double)val); |
111 | #endif |
112 | } |
113 | |
114 | double SDL_ceil(double x) |
115 | { |
116 | #ifdef HAVE_CEIL |
117 | return ceil(x); |
118 | #else |
119 | double integer = SDL_floor(x); |
120 | double fraction = x - integer; |
121 | if (fraction > 0.0) { |
122 | integer += 1.0; |
123 | } |
124 | return integer; |
125 | #endif // HAVE_CEIL |
126 | } |
127 | |
128 | float SDL_ceilf(float x) |
129 | { |
130 | #ifdef HAVE_CEILF |
131 | return ceilf(x); |
132 | #else |
133 | return (float)SDL_ceil((double)x); |
134 | #endif |
135 | } |
136 | |
137 | double SDL_copysign(double x, double y) |
138 | { |
139 | #ifdef HAVE_COPYSIGN |
140 | return copysign(x, y); |
141 | #elif defined(HAVE__COPYSIGN) |
142 | return _copysign(x, y); |
143 | #elif defined(__WATCOMC__) && defined(__386__) |
144 | // this is nasty as hell, but it works.. |
145 | unsigned int *xi = (unsigned int *)&x, |
146 | *yi = (unsigned int *)&y; |
147 | xi[1] = (yi[1] & 0x80000000) | (xi[1] & 0x7fffffff); |
148 | return x; |
149 | #else |
150 | return SDL_uclibc_copysign(x, y); |
151 | #endif // HAVE_COPYSIGN |
152 | } |
153 | |
154 | float SDL_copysignf(float x, float y) |
155 | { |
156 | #ifdef HAVE_COPYSIGNF |
157 | return copysignf(x, y); |
158 | #else |
159 | return (float)SDL_copysign((double)x, (double)y); |
160 | #endif |
161 | } |
162 | |
163 | double SDL_cos(double x) |
164 | { |
165 | #ifdef HAVE_COS |
166 | return cos(x); |
167 | #else |
168 | return SDL_uclibc_cos(x); |
169 | #endif |
170 | } |
171 | |
172 | float SDL_cosf(float x) |
173 | { |
174 | #ifdef HAVE_COSF |
175 | return cosf(x); |
176 | #else |
177 | return (float)SDL_cos((double)x); |
178 | #endif |
179 | } |
180 | |
181 | double SDL_exp(double x) |
182 | { |
183 | #ifdef HAVE_EXP |
184 | return exp(x); |
185 | #else |
186 | return SDL_uclibc_exp(x); |
187 | #endif |
188 | } |
189 | |
190 | float SDL_expf(float x) |
191 | { |
192 | #ifdef HAVE_EXPF |
193 | return expf(x); |
194 | #else |
195 | return (float)SDL_exp((double)x); |
196 | #endif |
197 | } |
198 | |
199 | double SDL_fabs(double x) |
200 | { |
201 | #ifdef HAVE_FABS |
202 | return fabs(x); |
203 | #else |
204 | return SDL_uclibc_fabs(x); |
205 | #endif |
206 | } |
207 | |
208 | float SDL_fabsf(float x) |
209 | { |
210 | #ifdef HAVE_FABSF |
211 | return fabsf(x); |
212 | #else |
213 | return (float)SDL_fabs((double)x); |
214 | #endif |
215 | } |
216 | |
217 | double SDL_floor(double x) |
218 | { |
219 | #ifdef HAVE_FLOOR |
220 | return floor(x); |
221 | #else |
222 | return SDL_uclibc_floor(x); |
223 | #endif |
224 | } |
225 | |
226 | float SDL_floorf(float x) |
227 | { |
228 | #ifdef HAVE_FLOORF |
229 | return floorf(x); |
230 | #else |
231 | return (float)SDL_floor((double)x); |
232 | #endif |
233 | } |
234 | |
235 | double SDL_trunc(double x) |
236 | { |
237 | #ifdef HAVE_TRUNC |
238 | return trunc(x); |
239 | #else |
240 | if (x >= 0.0f) { |
241 | return SDL_floor(x); |
242 | } else { |
243 | return SDL_ceil(x); |
244 | } |
245 | #endif |
246 | } |
247 | |
248 | float SDL_truncf(float x) |
249 | { |
250 | #ifdef HAVE_TRUNCF |
251 | return truncf(x); |
252 | #else |
253 | return (float)SDL_trunc((double)x); |
254 | #endif |
255 | } |
256 | |
257 | double SDL_fmod(double x, double y) |
258 | { |
259 | #ifdef HAVE_FMOD |
260 | return fmod(x, y); |
261 | #else |
262 | return SDL_uclibc_fmod(x, y); |
263 | #endif |
264 | } |
265 | |
266 | float SDL_fmodf(float x, float y) |
267 | { |
268 | #ifdef HAVE_FMODF |
269 | return fmodf(x, y); |
270 | #else |
271 | return (float)SDL_fmod((double)x, (double)y); |
272 | #endif |
273 | } |
274 | |
275 | int SDL_isinf(double x) |
276 | { |
277 | #ifdef HAVE_ISINF |
278 | return isinf(x); |
279 | #else |
280 | return SDL_uclibc_isinf(x); |
281 | #endif |
282 | } |
283 | |
284 | int SDL_isinff(float x) |
285 | { |
286 | #ifdef HAVE_ISINF_FLOAT_MACRO |
287 | return isinf(x); |
288 | #elif defined(HAVE_ISINFF) |
289 | return isinff(x); |
290 | #else |
291 | return SDL_uclibc_isinff(x); |
292 | #endif |
293 | } |
294 | |
295 | int SDL_isnan(double x) |
296 | { |
297 | #ifdef HAVE_ISNAN |
298 | return isnan(x); |
299 | #else |
300 | return SDL_uclibc_isnan(x); |
301 | #endif |
302 | } |
303 | |
304 | int SDL_isnanf(float x) |
305 | { |
306 | #ifdef HAVE_ISNAN_FLOAT_MACRO |
307 | return isnan(x); |
308 | #elif defined(HAVE_ISNANF) |
309 | return isnanf(x); |
310 | #else |
311 | return SDL_uclibc_isnanf(x); |
312 | #endif |
313 | } |
314 | |
315 | double SDL_log(double x) |
316 | { |
317 | #ifdef HAVE_LOG |
318 | return log(x); |
319 | #else |
320 | return SDL_uclibc_log(x); |
321 | #endif |
322 | } |
323 | |
324 | float SDL_logf(float x) |
325 | { |
326 | #ifdef HAVE_LOGF |
327 | return logf(x); |
328 | #else |
329 | return (float)SDL_log((double)x); |
330 | #endif |
331 | } |
332 | |
333 | double SDL_log10(double x) |
334 | { |
335 | #ifdef HAVE_LOG10 |
336 | return log10(x); |
337 | #else |
338 | return SDL_uclibc_log10(x); |
339 | #endif |
340 | } |
341 | |
342 | float SDL_log10f(float x) |
343 | { |
344 | #ifdef HAVE_LOG10F |
345 | return log10f(x); |
346 | #else |
347 | return (float)SDL_log10((double)x); |
348 | #endif |
349 | } |
350 | |
351 | double SDL_modf(double x, double *y) |
352 | { |
353 | #ifdef HAVE_MODF |
354 | return modf(x, y); |
355 | #else |
356 | return SDL_uclibc_modf(x, y); |
357 | #endif |
358 | } |
359 | |
360 | float SDL_modff(float x, float *y) |
361 | { |
362 | #ifdef HAVE_MODFF |
363 | return modff(x, y); |
364 | #else |
365 | double double_result, double_y; |
366 | double_result = SDL_modf((double)x, &double_y); |
367 | *y = (float)double_y; |
368 | return (float)double_result; |
369 | #endif |
370 | } |
371 | |
372 | double SDL_pow(double x, double y) |
373 | { |
374 | #ifdef HAVE_POW |
375 | return pow(x, y); |
376 | #else |
377 | return SDL_uclibc_pow(x, y); |
378 | #endif |
379 | } |
380 | |
381 | float SDL_powf(float x, float y) |
382 | { |
383 | #ifdef HAVE_POWF |
384 | return powf(x, y); |
385 | #else |
386 | return (float)SDL_pow((double)x, (double)y); |
387 | #endif |
388 | } |
389 | |
390 | double SDL_round(double arg) |
391 | { |
392 | #if defined HAVE_ROUND |
393 | return round(arg); |
394 | #else |
395 | if (arg >= 0.0) { |
396 | return SDL_floor(arg + 0.5); |
397 | } else { |
398 | return SDL_ceil(arg - 0.5); |
399 | } |
400 | #endif |
401 | } |
402 | |
403 | float SDL_roundf(float arg) |
404 | { |
405 | #if defined HAVE_ROUNDF |
406 | return roundf(arg); |
407 | #else |
408 | return (float)SDL_round((double)arg); |
409 | #endif |
410 | } |
411 | |
412 | long SDL_lround(double arg) |
413 | { |
414 | #if defined HAVE_LROUND |
415 | return lround(arg); |
416 | #else |
417 | return (long)SDL_round(arg); |
418 | #endif |
419 | } |
420 | |
421 | long SDL_lroundf(float arg) |
422 | { |
423 | #if defined HAVE_LROUNDF |
424 | return lroundf(arg); |
425 | #else |
426 | return (long)SDL_round((double)arg); |
427 | #endif |
428 | } |
429 | |
430 | double SDL_scalbn(double x, int n) |
431 | { |
432 | #ifdef HAVE_SCALBN |
433 | return scalbn(x, n); |
434 | #elif defined(HAVE__SCALB) |
435 | return _scalb(x, n); |
436 | #elif defined(HAVE_LIBC) && defined(HAVE_FLOAT_H) && (FLT_RADIX == 2) |
437 | /* from scalbn(3): If FLT_RADIX equals 2 (which is |
438 | * usual), then scalbn() is equivalent to ldexp(3). */ |
439 | return ldexp(x, n); |
440 | #else |
441 | return SDL_uclibc_scalbn(x, n); |
442 | #endif |
443 | } |
444 | |
445 | float SDL_scalbnf(float x, int n) |
446 | { |
447 | #ifdef HAVE_SCALBNF |
448 | return scalbnf(x, n); |
449 | #else |
450 | return (float)SDL_scalbn((double)x, n); |
451 | #endif |
452 | } |
453 | |
454 | double SDL_sin(double x) |
455 | { |
456 | #ifdef HAVE_SIN |
457 | return sin(x); |
458 | #else |
459 | return SDL_uclibc_sin(x); |
460 | #endif |
461 | } |
462 | |
463 | float SDL_sinf(float x) |
464 | { |
465 | #ifdef HAVE_SINF |
466 | return sinf(x); |
467 | #else |
468 | return (float)SDL_sin((double)x); |
469 | #endif |
470 | } |
471 | |
472 | double SDL_sqrt(double x) |
473 | { |
474 | #ifdef HAVE_SQRT |
475 | return sqrt(x); |
476 | #else |
477 | return SDL_uclibc_sqrt(x); |
478 | #endif |
479 | } |
480 | |
481 | float SDL_sqrtf(float x) |
482 | { |
483 | #ifdef HAVE_SQRTF |
484 | return sqrtf(x); |
485 | #else |
486 | return (float)SDL_sqrt((double)x); |
487 | #endif |
488 | } |
489 | |
490 | double SDL_tan(double x) |
491 | { |
492 | #ifdef HAVE_TAN |
493 | return tan(x); |
494 | #else |
495 | return SDL_uclibc_tan(x); |
496 | #endif |
497 | } |
498 | |
499 | float SDL_tanf(float x) |
500 | { |
501 | #ifdef HAVE_TANF |
502 | return tanf(x); |
503 | #else |
504 | return (float)SDL_tan((double)x); |
505 | #endif |
506 | } |
507 | |
508 | int SDL_abs(int x) |
509 | { |
510 | #ifdef HAVE_ABS |
511 | return abs(x); |
512 | #else |
513 | return (x < 0) ? -x : x; |
514 | #endif |
515 | } |
516 | |
517 | int SDL_isalpha(int x) { return (SDL_isupper(x)) || (SDL_islower(x)); } |
518 | int SDL_isalnum(int x) { return (SDL_isalpha(x)) || (SDL_isdigit(x)); } |
519 | int SDL_isdigit(int x) { return ((x) >= '0') && ((x) <= '9'); } |
520 | int SDL_isxdigit(int x) { return (((x) >= 'A') && ((x) <= 'F')) || (((x) >= 'a') && ((x) <= 'f')) || (SDL_isdigit(x)); } |
521 | int SDL_ispunct(int x) { return (SDL_isgraph(x)) && (!SDL_isalnum(x)); } |
522 | int SDL_isspace(int x) { return ((x) == ' ') || ((x) == '\t') || ((x) == '\r') || ((x) == '\n') || ((x) == '\f') || ((x) == '\v'); } |
523 | int SDL_isupper(int x) { return ((x) >= 'A') && ((x) <= 'Z'); } |
524 | int SDL_islower(int x) { return ((x) >= 'a') && ((x) <= 'z'); } |
525 | int SDL_isprint(int x) { return ((x) >= ' ') && ((x) < '\x7f'); } |
526 | int SDL_isgraph(int x) { return (SDL_isprint(x)) && ((x) != ' '); } |
527 | int SDL_iscntrl(int x) { return (((x) >= '\0') && ((x) <= '\x1f')) || ((x) == '\x7f'); } |
528 | int SDL_toupper(int x) { return ((x) >= 'a') && ((x) <= 'z') ? ('A' + ((x) - 'a')) : (x); } |
529 | int SDL_tolower(int x) { return ((x) >= 'A') && ((x) <= 'Z') ? ('a' + ((x) - 'A')) : (x); } |
530 | int SDL_isblank(int x) { return ((x) == ' ') || ((x) == '\t'); } |
531 | |
532 | void *SDL_aligned_alloc(size_t alignment, size_t size) |
533 | { |
534 | size_t padding; |
535 | Uint8 *result = NULL; |
536 | size_t requested_size = size; |
537 | |
538 | if (alignment < sizeof(void*)) { |
539 | alignment = sizeof(void*); |
540 | } |
541 | padding = (alignment - (size % alignment)); |
542 | |
543 | if (SDL_size_add_check_overflow(size, alignment, &size) && |
544 | SDL_size_add_check_overflow(size, sizeof(void *), &size) && |
545 | SDL_size_add_check_overflow(size, padding, &size)) { |
546 | void *original = SDL_malloc(size); |
547 | if (original) { |
548 | // Make sure we have enough space to store the original pointer |
549 | result = (Uint8 *)original + sizeof(original); |
550 | |
551 | // Align the pointer we're going to return |
552 | result += alignment - (((size_t)result) % alignment); |
553 | |
554 | // Store the original pointer right before the returned value |
555 | SDL_memcpy(result - sizeof(original), &original, sizeof(original)); |
556 | |
557 | // Initialize the padding to zero |
558 | if (padding > 0) { |
559 | SDL_memset(result + requested_size, 0, padding); |
560 | } |
561 | } |
562 | } |
563 | return result; |
564 | } |
565 | |
566 | void SDL_aligned_free(void *mem) |
567 | { |
568 | if (mem) { |
569 | void *original; |
570 | SDL_memcpy(&original, ((Uint8 *)mem - sizeof(original)), sizeof(original)); |
571 | SDL_free(original); |
572 | } |
573 | } |
574 | |