-#include <stdio.h>
-#include <unistd.h>
+#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <GL/glew.h>
#include <GL/gl.h>
#include <GLFW/glfw3.h>
+#include <stb/stb_image_write.h>
+#include <stdio.h>
+#include <unistd.h>
#include "client/camera.h"
#include "client/client.h"
-#include "client/client_map.h"
+#include "client/client_entity.h"
#include "client/client_node.h"
#include "client/client_player.h"
-#include "client/hud.h"
-#include "client/input.h"
+#include "client/client_terrain.h"
+#include "client/debug_menu.h"
#include "client/font.h"
+#include "client/frustum.h"
+#include "client/game.h"
+#include "client/gl_debug.h"
+#include "client/gui.h"
+#include "client/input.h"
+#include "client/sky.h"
#include "client/window.h"
-#include "signal_handlers.h"
+#include "day.h"
+#include "interrupt.h"
-static void game_loop(Client *client)
+int game_fps = 0;
+
+static void crosshair_init()
{
- HUDElement *fps_hud = hud_add((HUDElementDefinition) {
- .type = HUD_TEXT,
- .pos = {-1.0f, -1.0f, 0.0f},
- .offset = {2, 2 + 16 + 2},
- .type_def = {
- .text = {
- .text = "",
- .color = {1.0f, 1.0f, 1.0f},
- },
- },
+ gui_add(NULL, (GUIElementDefinition) {
+ .pos = {0.5f, 0.5f},
+ .z_index = 0.0f,
+ .offset = {0, 0},
+ .margin = {0, 0},
+ .align = {0.5f, 0.5f},
+ .scale = {1.0f, 1.0f},
+ .scale_type = SCALE_IMAGE,
+ .affect_parent_scale = false,
+ .text = NULL,
+ .image = texture_load(RESSOURCE_PATH "textures/crosshair.png", false),
+ .text_color = {0.0f, 0.0f, 0.0f, 0.0f},
+ .bg_color = {0.0f, 0.0f, 0.0f, 0.0f},
});
+}
+
+static void render(f64 dtime)
+{
+ glEnable(GL_DEPTH_TEST); GL_DEBUG
+ glEnable(GL_BLEND); GL_DEBUG
+ glEnable(GL_MULTISAMPLE); GL_DEBUG
+ glEnable(GL_CULL_FACE); GL_DEBUG
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_DEBUG
+ glCullFace(GL_BACK); GL_DEBUG
+ glFrontFace(GL_CCW); GL_DEBUG
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); GL_DEBUG
+
+ frustum_update();
+ terrain_gfx_update();
+ client_entity_gfx_update();
+
+ sky_render();
+ model_scene_render(dtime);
+ gui_render();
+}
+
+static void game_loop()
+{
f64 fps_update_timer = 1.0f;
- int frames = 0;
+ unsigned int frames = 0;
struct timespec ts, ts_old;
clock_gettime(CLOCK_REALTIME, &ts_old);
- while (! glfwWindowShouldClose(window.handle) && client->state != CS_DISCONNECTED && ! interrupted) {
+ while (!glfwWindowShouldClose(window.handle) && !interrupt.set) {
clock_gettime(CLOCK_REALTIME, &ts);
- f64 dtime = (f64) (ts.tv_sec - ts_old.tv_sec) + (f64) (ts.tv_nsec - ts_old.tv_nsec) / 1000000000.0;
+ f64 dtime = (f64) (ts.tv_sec - ts_old.tv_sec) + (f64) (ts.tv_nsec - ts_old.tv_nsec) / 1.0e9;
ts_old = ts;
if ((fps_update_timer -= dtime) <= 0.0) {
- char fps[((int) log10(frames) + 1) + 1 + 3 + 1];
- sprintf(fps, "%d FPS", frames);
- hud_change_text(fps_hud, fps);
+ debug_menu_changed(ENTRY_FPS);
+ game_fps = frames;
fps_update_timer += 1.0;
frames = 0;
}
frames++;
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_BLEND);
- glEnable(GL_MULTISAMPLE);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- glClearColor(0.52941176470588f, 0.8078431372549f, 0.92156862745098f, 1.0f);
-
- input_tick();
+ input_tick(dtime);
client_player_tick(dtime);
- scene_render();
- hud_render();
- // font_render();
+ debug_menu_changed(ENTRY_TIME);
+ debug_menu_changed(ENTRY_DAYLIGHT);
+ debug_menu_changed(ENTRY_SUN_ANGLE);
+ debug_menu_update();
+
+ render(dtime);
glfwSwapBuffers(window.handle);
glfwPollEvents();
}
}
-void game(Client *client)
+bool game(Flag *gfx_init)
{
- int width, height;
- width = 1250;
- height = 750;
+ if (!window_init())
+ return false;
- if (! window_init(width, height))
- return;
+ if (!font_init())
+ return false;
- if (! font_init())
- return;
+ model_init();
- if (! scene_init())
- return;
+ if (!sky_init())
+ return false;
- scene_on_resize(width, height);
+ if (!terrain_gfx_init())
+ return false;
- client_node_init();
- client_map_start_meshgen();
+ if (!client_entity_gfx_init())
+ return false;
- camera_set_position((v3f) {0.0f, 0.0f, 0.0f});
- camera_set_angle(0.0f, 0.0f);
+ client_player_gfx_init();
- hud_init();
- hud_on_resize(width, height);
+ client_node_init();
+ client_terrain_start();
- hud_add((HUDElementDefinition) {
- .type = HUD_IMAGE,
- .pos = {0.0f, 0.0f, 0.0f},
- .offset = {0, 0},
- .type_def = {
- .image = {
- .texture = texture_get(RESSOURCEPATH "textures/crosshair.png"),
- .scale = {1.0f, 1.0f},
- .scale_type = HUD_SCALE_TEXTURE,
- },
- },
- });
+ camera_set_position((v3f32) {0.0f, 0.0f, 0.0f});
+ camera_set_angle(0.0f, 0.0f);
- hud_add((HUDElementDefinition) {
- .type = HUD_TEXT,
- .pos = {-1.0f, -1.0f, 0.0f},
- .offset = {2, 2},
- .type_def = {
- .text = {
- .text = "Dragonblocks Alpha",
- .color = {1.0f, 1.0f, 1.0f},
- },
- },
- });
+ if (!gui_init())
+ return false;
+ debug_menu_init();
+ crosshair_init();
input_init();
- client_player_add_to_scene();
+ flag_set(gfx_init);
+ game_loop();
- game_loop(client);
+ client_terrain_stop();
font_deinit();
- hud_deinit();
- scene_deinit();
+ gui_deinit();
+ model_deinit();
+ sky_deinit();
+ terrain_gfx_deinit();
+ client_entity_gfx_deinit();
+ client_player_gfx_deinit();
+
+ return true;
+}
+
+char *game_take_screenshot()
+{
+ // renderbuffer for depth & stencil buffer
+ GLuint rbo;
+ glGenRenderbuffers(1, &rbo); GL_DEBUG
+ glBindRenderbuffer(GL_RENDERBUFFER, rbo); GL_DEBUG
+ glRenderbufferStorageMultisample(GL_RENDERBUFFER, 8, GL_DEPTH24_STENCIL8, window.width, window.height); GL_DEBUG
+
+ // 2 textures, one with AA, one without
+
+ GLuint txos[2];
+ glGenTextures(2, txos); GL_DEBUG
+
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, txos[0]); GL_DEBUG
+ glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 8, GL_RGB, window.width, window.height, GL_TRUE); GL_DEBUG
+
+ glBindTexture(GL_TEXTURE_2D, txos[1]); GL_DEBUG
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, window.width, window.height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); GL_DEBUG
+
+ // 2 framebuffers, one with AA, one without
+
+ GLuint fbos[2];
+ glGenFramebuffers(2, fbos); GL_DEBUG
+
+ glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]); GL_DEBUG
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, txos[0], 0); GL_DEBUG
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); GL_DEBUG
+
+ glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]); GL_DEBUG
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, txos[1], 0); GL_DEBUG
+
+ // render scene
+ glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]); GL_DEBUG
+ render(0.0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0); GL_DEBUG
+
+ // blit AA-buffer into no-AA buffer
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]); GL_DEBUG
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]); GL_DEBUG
+ glBlitFramebuffer(0, 0, window.width, window.height, 0, 0, window.width, window.height, GL_COLOR_BUFFER_BIT, GL_NEAREST); GL_DEBUG
+
+ // read data
+ GLubyte data[window.width * window.height * 3];
+ glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]); GL_DEBUG
+ glPixelStorei(GL_PACK_ALIGNMENT, 1); GL_DEBUG
+ glReadPixels(0, 0, window.width, window.height, GL_RGB, GL_UNSIGNED_BYTE, data); GL_DEBUG
+
+ // create filename
+ char filename[BUFSIZ];
+ time_t timep = time(0);
+ strftime(filename, BUFSIZ, "screenshot-%Y-%m-%d-%H:%M:%S.png", localtime(&timep));
+
+ // save screenshot
+ stbi_flip_vertically_on_write(true);
+ stbi_write_png(filename, window.width, window.height, 3, data, window.width * 3);
+
+ // delete buffers
+ glDeleteRenderbuffers(1, &rbo); GL_DEBUG
+ glDeleteTextures(2, txos); GL_DEBUG
+ glDeleteFramebuffers(2, fbos); GL_DEBUG
+
+ return strdup(filename);
}