]> git.lizzy.rs Git - dragonblocks_alpha.git/blob - src/client/frustum.c
ec96a4b0cd4089349bcbe21029cd978cd70cc811
[dragonblocks_alpha.git] / src / client / frustum.c
1 #include "frustum.h"
2
3 typedef enum
4 {
5         PLANE_LEFT,
6         PLANE_RIGHT,
7         PLANE_BOTTOM,
8         PLANE_TOP,
9         PLANE_NEAR,
10         PLANE_FAR,
11         PLANE_COUNT,
12 } Plane;
13
14 static struct
15 {
16         vec3 points[8];
17         vec4 planes[PLANE_COUNT];
18         int cross_indices[PLANE_COUNT][PLANE_COUNT];
19 } frustum;
20
21 __attribute__((constructor)) static void init_frustum()
22 {
23         for (Plane a = 0; a < PLANE_COUNT; a++)
24                 for (Plane b = 0; b < PLANE_COUNT; b++)
25                         frustum.cross_indices[a][b] = a * (9 - a) / 2 + b - 1;
26 }
27
28 void frustum_update(mat4x4 view_proj)
29 {
30         mat4x4 m;
31
32 #pragma GCC diagnostic push
33 #pragma GCC diagnostic ignored "-Wpedantic"
34         mat4x4_transpose(m, view_proj);
35 #pragma GCC diagnostic pop
36
37         vec4_add(frustum.planes[PLANE_LEFT], m[3], m[0]);
38         vec4_sub(frustum.planes[PLANE_RIGHT], m[3], m[0]);
39         vec4_add(frustum.planes[PLANE_BOTTOM], m[3], m[1]);
40         vec4_sub(frustum.planes[PLANE_TOP], m[3], m[1]);
41         vec4_add(frustum.planes[PLANE_NEAR], m[3], m[2]);
42         vec4_sub(frustum.planes[PLANE_FAR], m[3], m[2]);
43
44         int i = 0;
45         vec3 crosses[PLANE_COUNT * (PLANE_COUNT - 1) / 2];
46         for (Plane a = 0; a < PLANE_COUNT; a++)
47                 for (Plane b = a + 1; b < PLANE_COUNT; b++)
48                         vec3_mul_cross(crosses[i++], frustum.planes[a], frustum.planes[b]);
49
50         int j = 0;
51         for (Plane c = PLANE_NEAR; c <= PLANE_FAR; c++) {
52                 for (Plane a = PLANE_LEFT; a <= PLANE_RIGHT; a++) {
53                         for (Plane b = PLANE_BOTTOM; b <= PLANE_TOP; b++) {
54                                 float d = -1.0f / vec3_mul_inner(frustum.planes[a], crosses[frustum.cross_indices[b][c]]);
55                                 vec3 w = {frustum.planes[a][4], frustum.planes[b][4], frustum.planes[c][4]};
56                                 float *res = frustum.points[j++];
57
58                                 vec3 res_1_cross = {-crosses[frustum.cross_indices[a][c]][0], -crosses[frustum.cross_indices[a][c]][1], -crosses[frustum.cross_indices[a][c]][2]};
59
60                                 res[0] = vec3_mul_inner(crosses[frustum.cross_indices[b][c]], w) * d;
61                                 res[1] = vec3_mul_inner(res_1_cross, w) * d;
62                                 res[2] = vec3_mul_inner(crosses[frustum.cross_indices[a][b]], w) * d;
63                         }
64                 }
65         }
66 }
67
68 static bool outside_plane(Plane i, aabb3f32 box)
69 {
70         for (int x = 0; x <= 1; x++) {
71                 for (int y = 0; y <= 1; y++) {
72                         for (int z = 0; z <= 1; z++) {
73                                 vec4 plane = {
74                                         x ? box.max.x : box.min.x,
75                                         y ? box.max.y : box.min.y,
76                                         z ? box.max.z : box.min.z,
77                                         1.0f,
78                                 };
79
80                                 if (vec4_mul_inner(frustum.planes[i], plane) > 0.0)
81                                         return false;
82                         }
83                 }
84         }
85
86         return true;
87 }
88
89 // http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm
90 bool frustum_is_visible(aabb3f32 box)
91 {
92         for (Plane i = 0; i < PLANE_COUNT; i++) {
93                 if (outside_plane(i, box))
94                         return false;
95         }
96
97         int box_outside[6] = {0};
98
99         for (Plane i = 0; i < PLANE_COUNT; i++) {
100                 int outside[6] = {
101                         frustum.points[i][0] > box.max.x,
102                         frustum.points[i][0] < box.min.x,
103                         frustum.points[i][1] > box.max.y,
104                         frustum.points[i][1] < box.min.y,
105                         frustum.points[i][2] > box.max.z,
106                         frustum.points[i][2] < box.min.z,
107                 };
108
109                 for (int i = 0; i < 6; i++)
110                         box_outside[i] += outside[i];
111         }
112
113         for (int i = 0; i < 6; i++) {
114                 if (box_outside[i] == 8)
115                         return false;
116         }
117
118         return true;
119 }