1+ #include "obj_picking.h"
2+
3+ #include "world.h"
4+ #include "game/camera.h"
5+ #include "game/model.h"
6+ #include "render/model_renderer.h"
7+ #include "shape/frustum_shape.h"
8+
9+ void * obj_picking_find_obj_under_cursor (vec2 cursor_pos_rel , te_camera * camera , te_world * world ) {
10+ te_frustum_shape * frustum = camera_get_frustum (camera );
11+ vec3 camera_world_pos ;
12+ camera_get_position (camera , camera_world_pos );
13+
14+ // Convert mouse pos to NDC [-1; 1] space.
15+ vec2 ndc ;
16+ glm_vec2_mul (cursor_pos_rel , (vec2 ){2.0f , 2.0f }, ndc );
17+ ndc [1 ] = 2.0f - ndc [1 ]; // flip Y
18+ glm_vec2_sub (ndc , (vec2 ){1.0f , 1.0f }, ndc );
19+
20+ // Construct a point in clip space.
21+ vec4 camera_ray ;
22+ camera_ray [0 ] = ndc [0 ];
23+ camera_ray [1 ] = ndc [1 ];
24+ camera_ray [2 ] = -1.0f ; // forward axis in clip space
25+ camera_ray [3 ] = 1.0f ;
26+
27+ // Apply inverse view/proj matrix.
28+ mat4 * view_proj_mat = camera_get_view_proj_mat (camera );
29+ mat4 inv_view_proj_mat ;
30+ glm_mat4_inv (* view_proj_mat , inv_view_proj_mat );
31+ glm_mat4_mulv (inv_view_proj_mat , camera_ray , camera_ray );
32+ glm_vec3_divs (camera_ray , camera_ray [3 ], camera_ray );
33+
34+ // Get direction from camera pos.
35+ glm_vec3_sub (camera_ray , camera_world_pos , camera_ray );
36+ glm_vec3_normalize (camera_ray );
37+
38+ unsigned int count ;
39+ te_model * * models = world_get_models (world , & count );
40+
41+ struct closest_model_info {
42+ te_model * model ;
43+ te_aabb_shape aabb_world ;
44+ float bb_size ;
45+ float distance ;
46+ };
47+ struct closest_model_info info ;
48+ info .model = NULL ;
49+
50+ unsigned int handle = 0xFFFFFFFF ;
51+ for (unsigned int i = 0 ; i < count ; i ++ ) {
52+ handle = prv_model_get_render_data_handle (models [i ]);
53+ if (handle == 0xFFFFFFFF ) {
54+ continue ;
55+ }
56+
57+ te_model_renderer * renderer = prv_model_get_model_renderer (models [i ]);
58+ if (renderer == NULL ) {
59+ continue ;
60+ }
61+
62+ te_model_render_data * data = model_renderer_get_render_data_tmp (renderer , handle );
63+ if (!frustum_shape_is_aabb_inside (frustum , & data -> aabb_world )) {
64+ continue ;
65+ }
66+
67+ float distance ;
68+ if (!aabb_shape_intersect_ray (
69+ & data -> aabb_world , camera_world_pos , camera_ray , & distance )) {
70+ continue ;
71+ }
72+
73+ // TODO: for now just do a bunch of simple tests (no ray-triangle intersection
74+ // because we don't store the geometry on the CPU).
75+ const float bb_size = data -> aabb_world .extents [0 ] * 2.0f * data -> aabb_world .extents [1 ]
76+ * 2.0f * data -> aabb_world .extents [2 ] * 2.0f ;
77+ if (info .model != NULL ) {
78+ if (!aabb_shape_intersect (& data -> aabb_world , & info .aabb_world )) {
79+ if (distance >= info .distance ) {
80+ continue ;
81+ }
82+ } else {
83+ if (bb_size >= info .bb_size ) {
84+ continue ;
85+ }
86+ }
87+ }
88+
89+ info .model = models [i ];
90+ info .aabb_world = data -> aabb_world ;
91+ info .bb_size = bb_size ;
92+ info .distance = distance ;
93+ }
94+
95+ free (models );
96+
97+ return info .model ;
98+ }
0 commit comments