]> git.lizzy.rs Git - dragonblocks_alpha.git/blob - src/client.c
Add textures
[dragonblocks_alpha.git] / src / client.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <math.h>
5 #include <arpa/inet.h>
6 #include <unistd.h>
7 #include <errno.h>
8 #include <netdb.h>
9 #include <GL/glew.h>
10 #include <GL/gl.h>
11 #include <GLFW/glfw3.h>
12 #include "client.h"
13 #include "clientmap.h"
14 #include "clientnode.h"
15 #include "signal.h"
16 #include "shaders.h"
17 #include "util.h"
18
19 Client client;
20
21 void client_disconnect(bool send, const char *detail)
22 {
23         pthread_mutex_lock(&client.mtx);
24         if (client.state != CS_DISCONNECTED) {
25                 if (send)
26                         write_u32(client.fd, SC_DISCONNECT);
27
28                 client.state = CS_DISCONNECTED;
29                 printf("Disconnected %s%s%s\n", INBRACES(detail));
30                 close(client.fd);
31         }
32         pthread_mutex_unlock(&client.mtx);
33 }
34
35 #include "network.c"
36
37 static void *reciever_thread(__attribute__((unused)) void *unused)
38 {
39         handle_packets(&client);
40
41         if (errno != EINTR)
42                 client_disconnect(false, "network error");
43
44         return NULL;
45 }
46
47 static void update_view_matrix(ShaderProgram *prog, mat4x4 view)
48 {
49         mat4x4_translate(view, -client.pos.x, -client.pos.y, -client.pos.z);
50         glUniformMatrix4fv(prog->loc_view, 1, GL_FALSE, view[0]);
51 }
52
53 static void client_loop()
54 {
55         if(! glfwInit()) {
56                 printf("Failed to initialize GLFW\n");
57                 return;
58         }
59
60         glfwWindowHint(GLFW_SAMPLES, 8);
61         glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
62         glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
63         glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
64
65         int width, height;
66         width = 1250;
67         height = 750;
68
69         GLFWwindow *window = glfwCreateWindow(width, height, "Dragonblocks", NULL, NULL);
70
71         if (! window) {
72                 fprintf(stderr, "Failed to create window\n");
73                 glfwTerminate();
74                 return;
75         }
76
77         glfwMakeContextCurrent(window);
78         if (glewInit() != GLEW_OK) {
79                 fprintf(stderr, "Failed to initialize GLEW\n");
80                 return;
81         }
82
83         glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
84
85         ShaderProgram *prog = create_shader_program(RESSOURCEPATH "shaders");
86         if (! prog) {
87                 fprintf(stderr, "Failed to create shader program\n");
88                 return;
89         }
90
91         init_client_node_definitions();
92         clientmap_start_meshgen();
93
94         mat4x4 view, projection;
95
96         update_view_matrix(prog, view);
97         mat4x4_perspective(projection, 86.1f / 180.0f * M_PI, (float) width / (float) height, 0.01f, 1000.0f);
98
99         glUseProgram(prog->id);
100         glUniformMatrix4fv(prog->loc_view, 1, GL_FALSE, view[0]);
101         glUniformMatrix4fv(prog->loc_projection, 1, GL_FALSE, projection[0]);
102
103         while (! glfwWindowShouldClose(window) && client.state != CS_DISCONNECTED && ! interrupted) {
104                 glEnable(GL_DEPTH_TEST);
105                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
106                 glClearColor(0.52941176470588f, 0.8078431372549f, 0.92156862745098f, 1.0f);
107
108                 bool pos_changed = false;
109
110                 if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {
111                         pos_changed = true;
112                         client.pos.z -= 1.0f;
113                 } else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) {
114                         pos_changed = true;
115                         client.pos.z += 1.0f;
116                 } if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) {
117                         pos_changed = true;
118                         client.pos.x -= 1.0f;
119                 } else if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) {
120                         pos_changed = true;
121                         client.pos.x += 1.0f;
122                 } if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) {
123                         pos_changed = true;
124                         client.pos.y -= 1.0f;
125                 } else if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) {
126                         pos_changed = true;
127                         client.pos.y += 1.0f;
128                 }
129
130                 if (pos_changed) {
131                         update_view_matrix(prog, view);
132                         pthread_mutex_lock(&client.mtx);
133                         (void) (write_u32(client.fd, SC_POS) && write_v3f32(client.fd, client.pos));
134                         pthread_mutex_unlock(&client.mtx);
135                 }
136
137                 scene_render(client.scene, prog);
138
139                 glfwSwapBuffers(window);
140                 glfwPollEvents();
141         }
142
143         delete_shader_program(prog);
144 }
145
146 static bool client_name_prompt()
147 {
148         printf("Enter name: ");
149         fflush(stdout);
150         char name[NAME_MAX];
151         if (scanf("%s", name) == EOF)
152                 return false;
153         client.name = strdup(name);
154         pthread_mutex_lock(&client.mtx);
155         if (write_u32(client.fd, SC_AUTH) && write(client.fd, client.name, strlen(client.name) + 1)) {
156                 client.state = CS_AUTH;
157                 printf("Authenticating...\n");
158         }
159         pthread_mutex_unlock(&client.mtx);
160         return true;
161 }
162
163 static bool client_authenticate()
164 {
165         for ever {
166                 switch (client.state) {
167                         case CS_CREATED:
168                                 if (client_name_prompt())
169                                         break;
170                                 else
171                                         return false;
172                         case CS_AUTH:
173                                 if (interrupted)
174                                         return false;
175                                 else
176                                         sched_yield();
177                                 break;
178                         case CS_ACTIVE:
179                                 return true;
180                         case CS_DISCONNECTED:
181                                 return false;
182                 }
183         }
184         return false;
185 }
186
187 static void client_start(int fd)
188 {
189         client.fd = fd;
190         pthread_mutex_init(&client.mtx, NULL);
191         client.state = CS_CREATED;
192         client.name = NULL;
193         client.map = map_create();
194         client.scene = scene_create();
195         client.pos = (v3f) {0.0f, 0.0f, 0.0f};
196
197         clientmap_init(&client);
198
199         pthread_t recv_thread;
200         pthread_create(&recv_thread, NULL, &reciever_thread, NULL);
201
202         if (client_authenticate())
203                 client_loop();
204
205         if (client.state != CS_DISCONNECTED)
206                 client_disconnect(true, NULL);
207
208         if (client.name)
209                 free(client.name);
210
211         clientmap_deinit();
212
213         map_delete(client.map, NULL);
214         scene_delete(client.scene);
215
216         pthread_mutex_destroy(&client.mtx);
217 }
218
219 int main(int argc, char **argv)
220 {
221         program_name = argv[0];
222
223         if (argc < 3)
224                 internal_error("missing address or port");
225
226         struct addrinfo hints = {
227                 .ai_family = AF_UNSPEC,
228                 .ai_socktype = SOCK_STREAM,
229                 .ai_protocol = 0,
230                 .ai_flags = AI_NUMERICSERV,
231         };
232
233         struct addrinfo *info = NULL;
234
235         int gai_state = getaddrinfo(argv[1], argv[2], &hints, &info);
236
237         if (gai_state != 0)
238                 internal_error(gai_strerror(gai_state));
239
240         int fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
241
242         if (fd == -1)
243                 syscall_error("socket");
244
245         if (connect(fd, info->ai_addr, info->ai_addrlen) == -1)
246                 syscall_error("connect");
247
248         char *addrstr = address_string((struct sockaddr_in6 *) info->ai_addr);
249         printf("Connected to %s\n", addrstr);
250         free(addrstr);
251
252         freeaddrinfo(info);
253
254         init_signal_handlers();
255         client_start(fd);
256
257         return EXIT_SUCCESS;
258 }