1 module re.math.bounds;
2 
3 import std.algorithm.comparison;
4 static import raymath;
5 import re.math;
6 
7 static class Bounds {
8     /** based on
9     calculate bounds for an object in 2d space taking into account its transform
10     https://github.com/prime31/Nez/blob/0e97e68bd9df191fb3b893eb69e54238c30fcc80/Nez.Portable/Utils/Extensions/Bounds.cs#L184
11     */
12     public static Rectangle calculate(ref Transform transform, Vector2 origin,
13             float width, float height) {
14         auto rotation = transform.rotation_z;
15         auto position = transform.position2;
16         auto scale = transform.scale2;
17         if (rotation == 0) {
18             return Rectangle(cast(int)(position.x - (origin.x * scale.x)),
19                     cast(int)(position.y - (origin.y * scale.y)),
20                     cast(int)(width * scale.x), cast(int)(height * scale.y));
21         } else {
22             auto tmp1 = Matrix4.init;
23 
24             // set the reference point to world reference taking origin into account
25             auto transform_mat = raymath.MatrixTranslate(-position.x - origin.x,
26                     -position.y - origin.y, 0);
27             tmp1 = raymath.MatrixScale(scale.x, scale.y, 1); // scale ->
28             transform_mat = raymath.MatrixMultiply(transform_mat, tmp1);
29             tmp1 = raymath.MatrixRotateZ(rotation); // rotate ->
30             transform_mat = raymath.MatrixMultiply(transform_mat, tmp1);
31             tmp1 = raymath.MatrixTranslate(position.x, position.y, 0); // translate back
32             transform_mat = raymath.MatrixMultiply(transform_mat, tmp1);
33 
34             // get all four corners in world space
35             auto top_left_w = Vector3(position.x, position.y, 0);
36             auto top_right_w = Vector3(position.x + width, position.y, 0);
37             auto btm_left_w = Vector3(position.x, position.y + height, 0);
38             auto btm_right_w = Vector3(position.x + width, position.y + height, 0);
39 
40             // transform the corners into our work space
41             auto top_left = raymath.Vector3Transform(top_left_w, transform_mat);
42             auto top_right = raymath.Vector3Transform(top_right_w, transform_mat);
43             auto btm_left = raymath.Vector3Transform(btm_left_w, transform_mat);
44             auto btm_right = raymath.Vector3Transform(btm_right_w, transform_mat);
45 
46             // find the min and max values so we can concoct our bounding box
47             auto min_x = cast(int) min(top_left.x, btm_right.x, top_right.x, btm_left.x);
48             auto max_x = cast(int) max(top_left.x, btm_right.x, top_right.x, btm_left.x);
49             auto min_y = cast(int) min(top_left.y, btm_right.y, top_right.y, btm_left.y);
50             auto max_y = cast(int) max(top_left.y, btm_right.y, top_right.y, btm_left.y);
51 
52             return Rectangle(min_x, min_y, max_x - min_x, max_y - min_y);
53         }
54     }
55 
56     /// calculate the new bounding box by applying the transform to the raw bounding box
57     public static BoundingBox calculate(BoundingBox bounds, ref Transform transform) {
58         auto t_min = raymath.Vector3Transform(bounds.min, transform.local_to_world_transform);
59         auto t_max = raymath.Vector3Transform(bounds.max, transform.local_to_world_transform);
60         return BoundingBox(t_min, t_max);
61 
62         // this is a crappy workaround, using dlib
63         // import re.util.dlib;
64 
65         // auto rot_quat = transform.orientation;
66         // auto dl_rot_quat = convert_quat(rot_quat);
67         // auto dl_rot_mat = dl_rot_quat.toMatrix4x4();
68         // auto t_min = convert_vec3(bounds.min) * dl_rot_mat;
69         // auto t_max = convert_vec3(bounds.max) * dl_rot_mat;
70         // auto dl_tf = convert_mat(transform.local_to_world_transform);
71         // auto t_min = convert_vec3(bounds.min) * dl_tf;
72         // auto t_max = convert_vec3(bounds.max) * dl_tf;
73 
74         // return BoundingBox(convert_vec3(t_min), convert_vec3(t_max));
75         // return BoundingBox(bounds.min * 1.1f, bounds.max * 1.1f);
76     }
77 }