#include <GL/glew.h>
#include <GL/gl.h>
#include <GLFW/glfw3.h>
+#define STB_IMAGE_WRITE_IMPLEMENTATION
+#include <stb/stb_image_write.h>
#include "client/camera.h"
#include "client/client.h"
#include "client/client_map.h"
#include "day.h"
#include "signal_handlers.h"
+int window_width, window_height;
+
static void crosshair_init()
{
gui_add(&gui_root, (GUIElementDefinition) {
});
}
+static void render()
+{
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_ALPHA_TEST);
+ glEnable(GL_BLEND);
+ glEnable(GL_MULTISAMPLE);
+ glEnable(GL_CULL_FACE);
+
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glAlphaFunc(GL_GREATER, 0.0f);
+ glCullFace(GL_BACK);
+ glFrontFace(GL_CCW);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ scene_render();
+
+ glDisable(GL_CULL_FACE);
+ sky_render();
+
+ glDisable(GL_DEPTH_TEST);
+ gui_render();
+}
+
static void game_loop(Client *client)
{
f64 fps_update_timer = 1.0f;
frames++;
- debug_menu_update_time();
- debug_menu_update_daylight();
- debug_menu_update_sun_angle();
-
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_ALPHA_TEST);
- glEnable(GL_BLEND);
- glEnable(GL_MULTISAMPLE);
- glEnable(GL_CULL_FACE);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glAlphaFunc(GL_GREATER, 0.0f);
- glCullFace(GL_BACK);
- glFrontFace(GL_CCW);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
input_tick();
client_player_tick(dtime);
- scene_render();
-
- glDisable(GL_CULL_FACE);
- sky_render();
+ debug_menu_update_time();
+ debug_menu_update_daylight();
+ debug_menu_update_sun_angle();
- glDisable(GL_DEPTH_TEST);
- gui_render();
+ render();
glfwSwapBuffers(window.handle);
glfwPollEvents();
bool game(Client *client)
{
- int width, height;
- width = 1250;
- height = 750;
+ window_width = 1250;
+ window_height = 750;
- if (! window_init(width, height))
+ if (! window_init(window_width, window_height))
return false;
if (! font_init())
if (! scene_init())
return false;
- scene_on_resize(width, height);
+ scene_on_resize(window_width, window_height);
if (! sky_init())
return false;
if (! gui_init())
return false;
- gui_on_resize(width, height);
+ gui_on_resize(window_width, window_height);
debug_menu_init();
debug_menu_toggle();
return true;
}
+
+void take_screenshot()
+{
+ // renderbuffer for depth & stencil buffer
+ GLuint RBO;
+ glGenRenderbuffers(1, &RBO);
+ glBindRenderbuffer(GL_RENDERBUFFER, RBO);
+ glRenderbufferStorageMultisample(GL_RENDERBUFFER, 8, GL_DEPTH24_STENCIL8, window_width, window_height);
+
+ // 2 textures, one with AA, one without
+
+ GLuint textures[2];
+ glGenTextures(2, textures);
+
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, textures[0]);
+ glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 8, GL_RGB, window_width, window_height, GL_TRUE);
+
+ glBindTexture(GL_TEXTURE_2D, textures[1]);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, window_width, window_height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
+
+ // 2 framebuffers, one with AA, one without
+
+ GLuint FBOs[2];
+ glGenFramebuffers(2, FBOs);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, FBOs[0]);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, textures[0], 0);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, RBO);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, FBOs[1]);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[1], 0);
+
+ // render scene
+ glBindFramebuffer(GL_FRAMEBUFFER, FBOs[0]);
+ render();
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ // blit AA-buffer into no-AA buffer
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, FBOs[0]);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FBOs[1]);
+ glBlitFramebuffer(0, 0, window_width, window_height, 0, 0, window_width, window_height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+ // read data
+ GLubyte data[window_width * window_height * 3];
+ glBindFramebuffer(GL_FRAMEBUFFER, FBOs[1]);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ glReadPixels(0, 0, window_width, window_height, GL_RGB, GL_UNSIGNED_BYTE, data);
+
+ // 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);
+ glDeleteTextures(2, textures);
+ glDeleteFramebuffers(2, FBOs);
+}
+
+void game_on_resize(int width, int height)
+{
+ window_width = width;
+ window_height = height;
+}
#include "client/client.h"
#include "client/client_player.h"
#include "client/debug_menu.h"
+#include "client/game.h"
#include "client/gui.h"
#include "client/input.h"
#include "client/window.h"
KeyListener collision_listener;
KeyListener timelapse_listener;
KeyListener debug_menu_listener;
+ KeyListener screenshot_listener;
} input;
void input_on_cursor_pos(double current_x, double current_y)
do_key_listener(&input.collision_listener);
do_key_listener(&input.timelapse_listener);
do_key_listener(&input.debug_menu_listener);
+ do_key_listener(&input.screenshot_listener);
if (input.fly_listener.fired) {
client_player.fly = ! client_player.fly;
if (input.debug_menu_listener.fired)
debug_menu_toggle();
+
+ if (input.screenshot_listener.fired)
+ take_screenshot();
}
client_player.velocity.x = 0.0f;
input.collision_listener = create_key_listener(GLFW_KEY_C);
input.timelapse_listener = create_key_listener(GLFW_KEY_T);
input.debug_menu_listener = create_key_listener(GLFW_KEY_F3);
+ input.screenshot_listener = create_key_listener(GLFW_KEY_F2);
input.pause_menu = gui_add(&gui_root, (GUIElementDefinition) {
.pos = {0.0f, 0.0f},