1 // Copyright (c) 2015 Sergio Gonzalez. All rights reserved.
2 // License: https://github.com/serge-rgb/milton#license
3
4
5 #include "system_includes.h"
6
7 #include "common.h"
8 #include "DArray.h"
9 #include "memory.h"
10 #include "utils.h"
11
12
13 // total RAM in bytes
14 size_t
get_system_RAM()15 get_system_RAM()
16 {
17 return (size_t)SDL_GetSystemRAM() * 1024 * 1024;
18 }
19
20 v2l
v2f_to_v2l(v2f p)21 v2f_to_v2l(v2f p)
22 {
23 return v2l{(i64)p.x, (i64)p.y};
24 }
25
26 v2i
v2l_to_v2i(v2l p)27 v2l_to_v2i(v2l p)
28 {
29 return v2i{ (i32)p.x, (i32)p.y };
30 }
31
32
33 v2f
v2l_to_v2f(v2l p)34 v2l_to_v2f(v2l p)
35 {
36 #ifdef _WIN32
37 #pragma warning(push)
38 #pragma warning(disable: 4307)
39 #endif
40 mlt_assert(MLT_ABS(p.x) < (1L<<31) - 1L);
41 mlt_assert(MLT_ABS(p.y) < (1L<<31) - 1L);
42 #ifdef _WIN32
43 #pragma warning(pop)
44 #endif
45 return v2f{(f32)p.x, (f32)p.y};
46 }
47
48 v2l
v2i_to_v2l(v2i p)49 v2i_to_v2l(v2i p)
50 {
51 return v2l{p.x, p.y};
52 }
53
54 v2f
v2i_to_v2f(v2i p)55 v2i_to_v2f(v2i p)
56 {
57 return v2f{(f32)p.x, (f32)p.y};
58 }
59
60
61 // ---------------
62 // Math functions.
63 // ---------------
64
65 f32
magnitude(v2f a)66 magnitude(v2f a)
67 {
68 return sqrtf(DOT(a, a));
69 }
70
71 i64
magnitude(v2l a)72 magnitude(v2l a)
73 {
74 return sqrtf((float)DOT(a, a));
75 }
76
77 f32
distance(v2f a,v2f b)78 distance(v2f a, v2f b)
79 {
80 v2f diff = a - b;
81
82 f32 dist = sqrtf(DOT(diff, diff));
83
84 return dist;
85 }
86
87 i32
manhattan_distance(v2i a,v2i b)88 manhattan_distance(v2i a, v2i b)
89 {
90 i32 dist = MLT_ABS(a.x - b.x) + MLT_ABS(a.y - b.y);
91 return dist;
92 }
93
94 f32
deegrees_to_radians(int d)95 deegrees_to_radians(int d)
96 {
97 mlt_assert (0 <= d && d < 360);
98 return kPi * ((f32)(d) / 180.0f);
99 }
100
101 f32
radians_to_degrees(f32 r)102 radians_to_degrees(f32 r)
103 {
104 return (180 * r) / kPi;
105 }
106
107 f32
norm(v2f v)108 norm(v2f v)
109 {
110 f32 result = sqrtf(v.x * v.x + v.y * v.y);
111 return result;
112 }
113
114 v2f
normalized(v2f v)115 normalized (v2f v)
116 {
117 v2f result = v / norm(v);
118 return result;
119 }
120
121 f32
clamp(f32 value,f32 min,f32 max)122 clamp(f32 value, f32 min, f32 max)
123 {
124 return min(max(value, min), max);
125 }
126
127
128
129 // Could be called a signed area. `orientation(a, b, c) / 2` is the area of the
130 // triangle.
131 // If positive, c is to the left of ab. Negative: right of ab. 0 if
132 // colinear.
133 f32
orientation(v2f a,v2f b,v2f c)134 orientation(v2f a, v2f b, v2f c)
135 {
136 return (b.x - a.x)*(c.y - a.y) - (c.x - a.x)*(b.y - a.y);
137 }
138
139 b32
is_inside_triangle(v2f point,v2f a,v2f b,v2f c)140 is_inside_triangle(v2f point, v2f a, v2f b, v2f c)
141 {
142 b32 is_inside =
143 (orientation(a, b, point) <= 0) &&
144 (orientation(b, c, point) <= 0) &&
145 (orientation(c, a, point) <= 0);
146 return is_inside;
147 }
148
149 v2f
polar_to_cartesian(f32 angle,f32 radius)150 polar_to_cartesian(f32 angle, f32 radius)
151 {
152 v2f result = {
153 radius * cosf(angle),
154 radius * sinf(angle)
155 };
156 return result;
157 }
158
159 v2i
rotate_v2i(v2i p,f32 angle)160 rotate_v2i(v2i p, f32 angle)
161 {
162 v2i r = {
163 (i32)((p.x * cosf(angle)) - (p.y * sinf(angle))),
164 (i32)((p.x * sinf(angle)) + (p.y * cosf(angle))),
165 };
166 return r;
167 }
168
169 v2f
closest_point_in_segment_f(i32 ax,i32 ay,i32 bx,i32 by,v2f ab,f32 ab_magnitude_squared,v2i point,f32 * out_t)170 closest_point_in_segment_f(i32 ax, i32 ay,
171 i32 bx, i32 by,
172 v2f ab, f32 ab_magnitude_squared,
173 v2i point, f32* out_t)
174 {
175 v2f result;
176 f32 mag_ab = sqrtf(ab_magnitude_squared);
177 f32 d_x = ab.x / mag_ab;
178 f32 d_y = ab.y / mag_ab;
179 f32 ax_x = (f32)(point.x - ax);
180 f32 ax_y = (f32)(point.y - ay);
181 f32 disc = d_x * ax_x + d_y * ax_y;
182 if ( disc < 0 ) disc = 0;
183 if ( disc > mag_ab ) disc = mag_ab;
184 if ( out_t ) {
185 *out_t = disc / mag_ab;
186 }
187 result = v2f{(ax + disc * d_x), (ay + disc * d_y)};
188 return result;
189 }
190
191 v2i
closest_point_in_segment(v2i a,v2i b,v2f ab,f32 ab_magnitude_squared,v2i point,f32 * out_t)192 closest_point_in_segment(v2i a, v2i b,
193 v2f ab, f32 ab_magnitude_squared,
194 v2i point, f32* out_t)
195 {
196 v2i result;
197 f32 mag_ab = sqrtf(ab_magnitude_squared);
198 f32 d_x = ab.x / mag_ab;
199 f32 d_y = ab.y / mag_ab;
200 f32 ax_x = (f32)(point.x - a.x);
201 f32 ax_y = (f32)(point.y - a.y);
202 f32 disc = d_x * ax_x + d_y * ax_y;
203 if ( disc < 0 ) disc = 0;
204 if ( disc > mag_ab ) disc = mag_ab;
205 if ( out_t ) {
206 *out_t = disc / mag_ab;
207 }
208 result = v2i{(i32)(a.x + disc * d_x), (i32)(a.y + disc * d_y)};
209 return result;
210 }
211
212 b32
intersect_line_segments(v2i a,v2i b,v2i u,v2i v,v2f * out_intersection)213 intersect_line_segments(v2i a, v2i b,
214 v2i u, v2i v,
215 v2f* out_intersection)
216 {
217 b32 hit = false;
218 v2i perp = perpendicular(v - u);
219 i32 det = DOT(b - a, perp);
220 if ( det != 0 ) {
221 f32 t = (f32)DOT(u - a, perp) / (f32)det;
222 if (t > 1 && t < 1.001) t = 1;
223 if (t < 0 && t > -0.001) t = 1;
224
225 if ( t >= 0 && t <= 1 ) {
226 hit = true;
227 out_intersection->x = a.x + t * (b.x - a.x);
228 out_intersection->y = a.y + t * (b.y - a.y);
229 }
230 }
231 return hit;
232 }
233
234 i32
rect_split(Rect ** out_rects,Rect src_rect,i32 width,i32 height)235 rect_split(Rect** out_rects, Rect src_rect, i32 width, i32 height)
236 {
237 DArray<Rect> rects = {};
238 reserve(&rects, 32);
239
240 int n_width = (src_rect.right - src_rect.left) / width;
241 int n_height = (src_rect.bottom - src_rect.top) / height;
242
243 if ( !n_width || !n_height ) {
244 return 0;
245 }
246
247 i32 max_num_rects = (n_width + 1) * (n_height + 1);
248
249 for ( int h = src_rect.top; h < src_rect.bottom; h += height ) {
250 for ( int w = src_rect.left; w < src_rect.right; w += width ) {
251 Rect rect;
252 {
253 rect.left = w;
254 rect.right = min(src_rect.right, w + width);
255 rect.top = h;
256 rect.bottom = min(src_rect.bottom, h + height);
257 }
258 push(&rects, rect);
259 }
260 }
261
262 mlt_assert((i32)rects.count <= max_num_rects);
263 *out_rects = rects.data;
264 i32 num_rects = (i32)rects.count;
265 return num_rects;
266 }
267
268 Rect
rect_union(Rect a,Rect b)269 rect_union(Rect a, Rect b)
270 {
271 Rect result;
272 result.left = min(a.left, b.left);
273 result.right = max(a.right, b.right);
274
275 if ( result.left > result.right ) {
276 result.left = result.right;
277 }
278 result.top = min(a.top, b.top);
279 result.bottom = max(a.bottom, b.bottom);
280 if ( result.bottom < result.top ) {
281 result.bottom = result.top;
282 }
283 return result;
284 }
285
286 b32
rect_intersects_rect(Rect a,Rect b)287 rect_intersects_rect(Rect a, Rect b)
288 {
289 b32 intersects = true;
290 if ( a.left > b.right || b.left > a.right ||
291 a.top > b.bottom || b.top > a.bottom ) {
292 intersects = false;
293 }
294 return intersects;
295 }
296
297 Rect
rect_intersect(Rect a,Rect b)298 rect_intersect(Rect a, Rect b)
299 {
300 Rect result;
301 result.left = max(a.left, b.left);
302 result.right = min(a.right, b.right);
303
304 if ( result.left >= result.right ) {
305 result.left = result.right;
306 }
307 result.top = max(a.top, b.top);
308 result.bottom = min(a.bottom, b.bottom);
309 if ( result.bottom <= result.top ) {
310 result.bottom = result.top;
311 }
312 return result;
313 }
314 Rect
rect_stretch(Rect rect,i32 width)315 rect_stretch(Rect rect, i32 width)
316 {
317 Rect stretched = rect;
318 // Make the raster limits at least as wide as a block
319 if ( stretched.bottom - stretched.top < width ) {
320 stretched.top -= width / 2;
321 stretched.bottom += width / 2;
322 }
323 if ( stretched.right - stretched.left < width ) {
324 stretched.left -= width / 2;
325 stretched.right += width / 2;
326 }
327 return stretched;
328 }
329
330 Rect
rect_clip_to_screen(Rect limits,v2i screen_size)331 rect_clip_to_screen(Rect limits, v2i screen_size)
332 {
333 if (limits.left < 0) limits.left = 0;
334 if (limits.right > screen_size.w) limits.right = screen_size.w;
335 if (limits.top < 0) limits.top = 0;
336 if (limits.bottom > screen_size.h) limits.bottom = screen_size.h;
337 return limits;
338 }
339
340 const Rect
rect_enlarge(Rect src,i32 offset)341 rect_enlarge(Rect src, i32 offset)
342 {
343 Rect result;
344 result.left = src.left - offset;
345 result.top = src.top - offset;
346 result.right = src.right + offset;
347 result.bottom = src.bottom + offset;
348 return result;
349 }
350
351 Rect
bounding_rect_for_points(v2l points[],i32 num_points)352 bounding_rect_for_points(v2l points[], i32 num_points)
353 {
354 mlt_assert (num_points > 0);
355
356 v2l top_left = points[0];
357 v2l bot_right = points[0];
358
359 for ( i32 i = 1; i < num_points; ++i ) {
360 v2l point = points[i];
361 if (point.x < top_left.x) top_left.x = point.x;
362 if (point.x > bot_right.x) bot_right.x = point.x;
363
364 if (point.y < top_left.y) top_left.y = point.y;
365 if (point.y > bot_right.y) bot_right.y = point.y;
366 }
367 Rect rect = { top_left, bot_right };
368 return rect;
369 }
370
371 b32
is_inside_rect(Rect bounds,v2i point)372 is_inside_rect(Rect bounds, v2i point)
373 {
374 return
375 point.x >= bounds.left &&
376 point.x < bounds.right &&
377 point.y >= bounds.top &&
378 point.y < bounds.bottom;
379 }
380
381 b32
rect_is_valid(Rect rect)382 rect_is_valid(Rect rect)
383 {
384 b32 valid = rect.left <= rect.right && rect.top <= rect.bottom;
385 return valid;
386 }
387
388 Rect
bounding_rect_for_points_scalar(i32 points_x[],i32 points_y[],i32 num_points)389 bounding_rect_for_points_scalar(i32 points_x[], i32 points_y[], i32 num_points)
390 {
391 mlt_assert (num_points > 0);
392
393 i32 top_left_x = points_x[0];
394 i32 bot_right_x = points_x[0];
395
396 i32 top_left_y = points_y[0];
397 i32 bot_right_y = points_y[0];
398
399 for ( i32 i = 1; i < num_points; ++i ) {
400 if (points_x[i] < top_left_x) top_left_x = points_x[i];
401 if (points_x[i] > bot_right_x) bot_right_x = points_x[i];
402
403 if (points_y[i] < top_left_y) top_left_y = points_y[i];
404 if (points_y[i] > bot_right_y) bot_right_y = points_y[i];
405 }
406 Rect rect;
407 rect.left = top_left_x;
408 rect.right = bot_right_x;
409 rect.top = top_left_y;
410 rect.bottom = bot_right_y;
411 return rect;
412 }
413
414 Rect
rect_without_size()415 rect_without_size()
416 {
417 Rect rect;
418 rect.left = I64_MAX;
419 rect.right = I64_MIN;
420 rect.top = I64_MAX;
421 rect.bottom = I64_MIN;
422 return rect;
423 }
424
425 i32
rect_area(Rect rect)426 rect_area(Rect rect)
427 {
428 return (rect.right - rect.left) * (rect.bottom - rect.top);
429 }
430
431 b32
is_inside_rect_scalar(Rect bounds,i32 point_x,i32 point_y)432 is_inside_rect_scalar(Rect bounds, i32 point_x, i32 point_y)
433 {
434 return
435 point_x >= bounds.left &&
436 point_x < bounds.right &&
437 point_y >= bounds.top &&
438 point_y < bounds.bottom;
439 }
440
441 b32
is_rect_within_rect(Rect a,Rect b)442 is_rect_within_rect(Rect a, Rect b)
443 {
444 if ( (a.left < b.left)
445 || (a.right > b.right)
446 || (a.top < b.top)
447 || (a.bottom > b.bottom) ) {
448 return false;
449 }
450 return true;
451 }
452
453 Rect
rect_from_xywh(i32 x,i32 y,i32 w,i32 h)454 rect_from_xywh(i32 x, i32 y, i32 w, i32 h)
455 {
456 Rect rect;
457 rect.left = x;
458 rect.right = x + w;
459 rect.top = y;
460 rect.bottom = y + h;
461
462 return rect;
463 }
464
465 void
utf16_to_utf8_simple(char *,char *)466 utf16_to_utf8_simple(char* , char* )
467 {
468 // Nothing needs to be done
469 }
470
471 void
utf16_to_utf8_simple(wchar_t * utf16_name,char * utf8_name)472 utf16_to_utf8_simple(wchar_t* utf16_name, char* utf8_name)
473 {
474 for ( wchar_t* iter = utf16_name;
475 *iter!='\0';
476 ++iter ) {
477 if ( *iter <= 128 ) {
478 *utf8_name++ = (char)*iter;
479 }
480 }
481 *utf8_name='\0';
482 }
483
484 wchar_t*
str_trim_to_last_slash(wchar_t * str)485 str_trim_to_last_slash(wchar_t* str)
486 {
487 wchar_t* cool_char = str;
488 for ( wchar_t* iter = str;
489 *iter != '\0';
490 iter++ ) {
491 if ( (*iter == '/' || *iter == '\\') ) {
492 cool_char = (iter+1);
493 }
494 }
495 return cool_char;
496 }
497
498 char*
str_trim_to_last_slash(char * str)499 str_trim_to_last_slash(char* str)
500 {
501 char* cool_char = str;
502 for ( char* iter = str;
503 *iter != '\0';
504 iter++ ) {
505 if ( (*iter == '/' || *iter == '\\') ) {
506 cool_char = (iter+1);
507 }
508 }
509 return cool_char;
510 }
511
512 u64
hash(char * string,size_t len)513 hash(char* string, size_t len)
514 {
515 u64 h = 0;
516 for ( size_t i = 0; i < len; ++i ) {
517 h += string[i];
518 h ^= h<<10;
519 h += h>>5;
520 }
521 return h;
522 }
523
524 u64
difference_in_ms(WallTime start,WallTime end)525 difference_in_ms(WallTime start, WallTime end)
526 {
527 // Note: There is some risk of overflow here, but at the time of my
528 // writing this we are only using this for animations, where things won't
529 // explode.
530
531 u64 diff = end.ms - start.ms;
532 if (end.s > start.s) {
533 diff += 1000 * (end.s - start.s);
534 }
535 if (end.m > start.m) {
536 diff += 1000 * 60 * (end.m - start.s);
537 }
538 if (end.h > start.h) {
539 diff += 1000 * 60 * 60 * (end.h - start.h);
540 }
541 return diff;
542 }