]> git.lizzy.rs Git - dragonblocks_alpha.git/blob - src/client/game.c
99da5785bf41cf6d6d6ab87dfe3af74479315e02
[dragonblocks_alpha.git] / src / client / game.c
1 #define STB_IMAGE_WRITE_IMPLEMENTATION
2 #include <GL/glew.h>
3 #include <GL/gl.h>
4 #include <GLFW/glfw3.h>
5 #include <stb/stb_image_write.h>
6 #include <stdio.h>
7 #include <unistd.h>
8 #include "client/camera.h"
9 #include "client/client.h"
10 #include "client/client_node.h"
11 #include "client/client_player.h"
12 #include "client/client_terrain.h"
13 #include "client/debug_menu.h"
14 #include "client/font.h"
15 #include "client/frustum.h"
16 #include "client/gui.h"
17 #include "client/input.h"
18 #include "client/sky.h"
19 #include "client/window.h"
20 #include "day.h"
21 #include "interrupt.h"
22
23 int game_fps = 0;
24
25 static void crosshair_init()
26 {
27         gui_add(NULL, (GUIElementDefinition) {
28                 .pos = {0.5f, 0.5f},
29                 .z_index = 0.0f,
30                 .offset = {0, 0},
31                 .margin = {0, 0},
32                 .align = {0.5f, 0.5f},
33                 .scale = {1.0f, 1.0f},
34                 .scale_type = SCALE_IMAGE,
35                 .affect_parent_scale = false,
36                 .text = NULL,
37                 .image = texture_load(RESSOURCE_PATH "textures/crosshair.png", false),
38                 .text_color = {0.0f, 0.0f, 0.0f, 0.0f},
39                 .bg_color = {0.0f, 0.0f, 0.0f, 0.0f},
40         });
41 }
42
43 static void render(f64 dtime)
44 {
45         glEnable(GL_DEPTH_TEST);
46         glEnable(GL_ALPHA_TEST);
47         glEnable(GL_BLEND);
48         glEnable(GL_MULTISAMPLE);
49         glEnable(GL_CULL_FACE);
50
51         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
52         glAlphaFunc(GL_GREATER, 0.1f);
53         glCullFace(GL_BACK);
54         glFrontFace(GL_CCW);
55
56         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
57
58         frustum_update();
59         terrain_gfx_update();
60
61         sky_render();
62         model_scene_render(dtime);
63         gui_render();
64 }
65
66 static void game_loop()
67 {
68         f64 fps_update_timer = 1.0f;
69         unsigned int frames = 0;
70
71         struct timespec ts, ts_old;
72         clock_gettime(CLOCK_REALTIME, &ts_old);
73
74         while (!glfwWindowShouldClose(window.handle) && !interrupt.set) {
75                 clock_gettime(CLOCK_REALTIME, &ts);
76                 f64 dtime = (f64) (ts.tv_sec - ts_old.tv_sec) + (f64) (ts.tv_nsec - ts_old.tv_nsec) / 1.0e9;
77                 ts_old = ts;
78
79                 if ((fps_update_timer -= dtime) <= 0.0) {
80                         debug_menu_changed(ENTRY_FPS);
81                         game_fps = frames;
82                         fps_update_timer += 1.0;
83                         frames = 0;
84                 }
85
86                 frames++;
87
88                 input_tick(dtime);
89                 client_player_tick(dtime);
90
91                 debug_menu_changed(ENTRY_TIME);
92                 debug_menu_changed(ENTRY_DAYLIGHT);
93                 debug_menu_changed(ENTRY_SUN_ANGLE);
94                 debug_menu_update();
95
96                 render(dtime);
97
98                 glfwSwapBuffers(window.handle);
99                 glfwPollEvents();
100         }
101 }
102
103 bool game(Flag *gfx_init)
104 {
105         if (!window_init())
106                 return false;
107
108         if (!font_init())
109                 return false;
110
111         model_init();
112
113         if (!sky_init())
114                 return false;
115
116         if (!terrain_gfx_init())
117                 return false;
118
119         client_node_init();
120         client_terrain_start();
121
122         camera_set_position((v3f32) {0.0f, 0.0f, 0.0f});
123         camera_set_angle(0.0f, 0.0f);
124
125         if (!gui_init())
126                 return false;
127
128         debug_menu_init();
129         crosshair_init();
130         input_init();
131
132         flag_set(gfx_init);
133         game_loop();
134
135         client_terrain_stop();
136
137         font_deinit();
138         gui_deinit();
139         model_deinit();
140         sky_deinit();
141         terrain_gfx_deinit();
142
143         return true;
144 }
145
146 char *game_take_screenshot()
147 {
148         // renderbuffer for depth & stencil buffer
149         GLuint rbo;
150         glGenRenderbuffers(1, &rbo);
151         glBindRenderbuffer(GL_RENDERBUFFER, rbo);
152         glRenderbufferStorageMultisample(GL_RENDERBUFFER, 8, GL_DEPTH24_STENCIL8, window.width, window.height);
153
154         // 2 textures, one with AA, one without
155
156         GLuint txos[2];
157         glGenTextures(2, txos);
158
159         glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, txos[0]);
160         glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 8, GL_RGB, window.width, window.height, GL_TRUE);
161
162         glBindTexture(GL_TEXTURE_2D, txos[1]);
163         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, window.width, window.height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
164
165         // 2 framebuffers, one with AA, one without
166
167         GLuint fbos[2];
168         glGenFramebuffers(2, fbos);
169
170         glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]);
171         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, txos[0], 0);
172         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
173
174         glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]);
175         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, txos[1], 0);
176
177         // render scene
178         glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]);
179         render(0.0);
180         glBindFramebuffer(GL_FRAMEBUFFER, 0);
181
182         // blit AA-buffer into no-AA buffer
183         glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
184         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);
185         glBlitFramebuffer(0, 0, window.width, window.height, 0, 0, window.width, window.height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
186
187         // read data
188         GLubyte data[window.width * window.height * 3];
189         glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]);
190         glPixelStorei(GL_PACK_ALIGNMENT, 1);
191         glReadPixels(0, 0, window.width, window.height, GL_RGB, GL_UNSIGNED_BYTE, data);
192
193         // create filename
194         char filename[BUFSIZ];
195         time_t timep = time(0);
196         strftime(filename, BUFSIZ, "screenshot-%Y-%m-%d-%H:%M:%S.png", localtime(&timep));
197
198         // save screenshot
199         stbi_flip_vertically_on_write(true);
200         stbi_write_png(filename, window.width, window.height, 3, data, window.width * 3);
201
202         // delete buffers
203         glDeleteRenderbuffers(1, &rbo);
204         glDeleteTextures(2, txos);
205         glDeleteFramebuffers(2, fbos);
206
207         return strdup(filename);
208 }