]> git.lizzy.rs Git - dragonblocks_alpha.git/blob - src/client/client_player.c
Redesign file structure and graphics pipeline; add font rendering
[dragonblocks_alpha.git] / src / client / client_player.c
1 #include "client/camera.h"
2 #include "client/client.h"
3 #include "client/client_player.h"
4 #include "client/cube.h"
5 #include "client/texture.h"
6
7 struct ClientPlayer client_player;
8
9 static void update_pos()
10 {
11         camera_set_position((v3f) {client_player.pos.x, client_player.pos.y + client_player.eye_height, client_player.pos.z});
12         client_send_position(client_player.pos);
13
14         client_player.obj->pos = client_player.pos;
15         object_transform(client_player.obj);
16 }
17
18 void client_player_init(Map *map)
19 {
20         client_player.map = map;
21         client_player.pos = (v3f) {0.0f, 200.0f, 0.0f};
22         client_player.velocity = (v3f) {0.0f, 0.0f, 0.0f};
23         client_player.box = (aabb3f) {{-0.3f, 0.0f, -0.3f}, {0.3f, 1.75f, 0.3f}};
24         client_player.yaw = client_player.pitch = 0.0f;
25         client_player.eye_height = 1.5f;
26 }
27
28 void client_player_add_to_scene()
29 {
30         client_player.obj = object_create();
31         client_player.obj->scale = (v3f) {0.6f, 1.75f, 0.6f};
32         client_player.obj->visible = false;
33
34         object_set_texture(client_player.obj, texture_get(RESSOURCEPATH "textures/player.png"));
35
36         for (int f = 0; f < 6; f++) {
37                 for (int v = 0; v < 6; v++) {
38                         Vertex3D vertex = cube_vertices[f][v];
39                         vertex.position.y += 0.5;
40                         object_add_vertex(client_player.obj, &vertex);
41                 }
42         }
43
44         update_pos();
45 }
46
47 static aabb3f get_box()
48 {
49         return (aabb3f) {
50                 {client_player.box.min.x + client_player.pos.x, client_player.box.min.y + client_player.pos.y, client_player.box.min.z + client_player.pos.z},
51                 {client_player.box.max.x + client_player.pos.x, client_player.box.max.y + client_player.pos.y, client_player.box.max.z + client_player.pos.z},
52         };
53 }
54
55 static aabb3s32 round_box(aabb3f box)
56 {
57         return (aabb3s32) {
58                 {floor(box.min.x + 0.5f), floor(box.min.y + 0.5f), floor(box.min.z + 0.5f)},
59                 {ceil(box.max.x - 0.5f), ceil(box.max.y - 0.5f), ceil(box.max.z - 0.5f)},
60         };
61 }
62
63 static bool is_solid(s32 x, s32 y, s32 z)
64 {
65         Node node = map_get_node(client_player.map, (v3s32) {x, y, z}).type;
66         return node == NODE_UNLOADED || node_definitions[node].solid;
67 }
68
69 static bool can_jump()
70 {
71         aabb3f fbox = get_box();
72         fbox.min.y -= 0.5f;
73
74         aabb3s32 box = round_box(fbox);
75
76         if (fbox.min.y - (f32) box.min.y > 0.01f)
77                 return false;
78
79         for (s32 x = box.min.x; x <= box.max.x; x++)
80                 for (s32 z = box.min.z; z <= box.max.z; z++)
81                         if (is_solid(x, box.min.y, z))
82                                 return true;
83
84         return false;
85 }
86
87 void client_player_jump()
88 {
89         if (can_jump())
90                 client_player.velocity.y += 10.0f;
91 }
92
93 void client_player_tick(f64 dtime)
94 {
95         v3f old_pos = client_player.pos;
96         v3f old_velocity = client_player.velocity;
97
98         client_player.velocity.y -= 32.0f * dtime;
99
100 #define GETS(vec, comp) *(s32 *) ((char *) &vec + offsetof(v3s32, comp))
101 #define GETF(vec, comp) *(f32 *) ((char *) &vec + offsetof(v3f32, comp))
102 #define PHYSICS(a, b, c) { \
103                 f32 v = (GETF(client_player.velocity, a) + GETF(old_velocity, a)) / 2.0f; \
104                 if (v == 0.0f) \
105                         goto a ## _physics_done; \
106                 aabb3s32 box = round_box(get_box()); \
107                 v3f old_pos = client_player.pos; \
108                 GETF(client_player.pos, a) += v * dtime; \
109                 s32 dir; \
110                 f32 offset; \
111                 if (v > 0.0f) { \
112                         dir = +1; \
113                         offset = GETF(client_player.box.max, a); \
114                         GETS(box.min, a) = ceil(GETF(old_pos, a) + offset + 0.5f); \
115                         GETS(box.max, a) = floor(GETF(client_player.pos, a) + offset + 0.5f); \
116                 } else { \
117                         dir = -1; \
118                         offset = GETF(client_player.box.min, a); \
119                         GETS(box.min, a) = floor(GETF(old_pos, a) + offset - 0.5f); \
120                         GETS(box.max, a) = ceil(GETF(client_player.pos, a) + offset - 0.5f); \
121                 } \
122                 GETS(box.max, a) += dir; \
123                 for (s32 a = GETS(box.min, a); a != GETS(box.max, a); a += dir) { \
124                         for (s32 b = GETS(box.min, b); b <= GETS(box.max, b); b++) { \
125                                 for (s32 c = GETS(box.min, c); c <= GETS(box.max, c); c++) { \
126                                         if (is_solid(x, y, z)) { \
127                                                 GETF(client_player.pos, a) = (f32) a - offset - 0.5f * (f32) dir; \
128                                                 GETF(client_player.velocity, a) = 0.0f; \
129                                                 goto a ## _physics_done; \
130                                         } \
131                                 } \
132                         } \
133                 } \
134                 a ## _physics_done: (void) 0;\
135         }
136
137         PHYSICS(x, y, z)
138         PHYSICS(y, x, z)
139         PHYSICS(z, x, y)
140
141 #undef GETS
142 #undef GETF
143 #undef PHYSICS
144
145         if (old_pos.x != client_player.pos.x || old_pos.y != client_player.pos.y || old_pos.z != client_player.pos.z)
146                 update_pos();
147 }