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