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 }