Browse Source

Add screenshot hotkey

master
C. J. Howard 4 years ago
parent
commit
61242281f5
3 changed files with 70 additions and 41 deletions
  1. +38
    -33
      src/application.cpp
  2. +16
    -3
      src/application.hpp
  3. +16
    -5
      src/game/bootloader.cpp

+ 38
- 33
src/application.cpp View File

@ -31,12 +31,13 @@
#include "input/mouse.hpp" #include "input/mouse.hpp"
#include "input/game-controller.hpp" #include "input/game-controller.hpp"
#include "rasterizer/rasterizer.hpp" #include "rasterizer/rasterizer.hpp"
#include "resources/image.hpp"
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <glad/glad.h> #include <glad/glad.h>
#include <stdexcept> #include <stdexcept>
#include <utility>
#include <thread>
#include <stb/stb_image_write.h> #include <stb/stb_image_write.h>
//#include "utility/timestamp.hpp"
//#include <thread>
application::application(): application::application():
closed(false), closed(false),
@ -299,6 +300,41 @@ void application::change_state(const state_type& next_state)
} }
} }
std::shared_ptr<image> application::capture_frame() const
{
int w = viewport_dimensions[0];
int h = viewport_dimensions[1];
std::shared_ptr<image> frame = std::make_shared<image>();
frame->format(3, false);
frame->resize(w, h);
// Read pixel data from framebuffer into image
unsigned char* pixels = new unsigned char[w * h * 3];
glReadBuffer(GL_BACK);
glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, frame->get_pixels());
return std::move(frame);
}
void application::save_frame(const std::string& path) const
{
logger->push_task("Saving screenshot to \"" + path + "\"");
auto frame = capture_frame();
std::thread
(
[frame, path]
{
stbi_flip_vertically_on_write(1);
stbi_write_png(path.c_str(), frame->get_width(), frame->get_height(), frame->get_channels(), frame->get_pixels(), frame->get_width() * frame->get_channels());
}
).detach();
logger->pop_task(EXIT_SUCCESS);
}
void application::set_update_callback(const update_callback_type& callback) void application::set_update_callback(const update_callback_type& callback)
{ {
update_callback = callback; update_callback = callback;
@ -598,34 +634,3 @@ void application::window_resized()
ui_system->set_viewport(viewport); ui_system->set_viewport(viewport);
*/ */
} }
/*
void application::take_screenshot()
{
std::string filename = screenshots_path + "antkeeper-" + timestamp() + ".png";
logger->push_task("Saving screenshot to \"" + filename + "\"");
int x = viewport[0];
int y = viewport[1];
int w = viewport[2];
int h = viewport[3];
// Read pixel data from framebuffer
unsigned char* pixels = new unsigned char[w * h * 3];
glReadBuffer(GL_BACK);
glReadPixels(x, y, w, h, GL_RGB, GL_UNSIGNED_BYTE, pixels);
std::thread screenshot_thread(application::save_image, filename, w, h, pixels);
screenshot_thread.detach();
logger->pop_task(EXIT_SUCCESS);
}
*/
void application::save_image(const std::string& filename, int w, int h, const unsigned char* pixels)
{
stbi_flip_vertically_on_write(1);
stbi_write_png(filename.c_str(), w, h, 3, pixels, w * 3);
delete[] pixels;
}

+ 16
- 3
src/application.hpp View File

@ -23,6 +23,7 @@
#include <array> #include <array>
#include <functional> #include <functional>
#include <list> #include <list>
#include <memory>
#include <unordered_map> #include <unordered_map>
// Forward declarations // Forward declarations
@ -36,6 +37,7 @@ class logger;
class mouse; class mouse;
class performance_sampler; class performance_sampler;
class rasterizer; class rasterizer;
class image;
/** /**
* *
@ -81,6 +83,20 @@ public:
*/ */
void change_state(const state_type& state); void change_state(const state_type& state);
/**
* Captures a screenshot of last rendered frame.
*
* @return Image containing the captured frame.
*/
std::shared_ptr<image> capture_frame() const;
/**
* Captures a screenshot of last rendered frame.
*
* @return Image containing the captured frame.
*/
void save_frame(const std::string& path) const;
/** /**
* Sets the update callback, which is executed at regular intervals until the application is closed. The update callback expects two parameters, the first being the total time in seconds since the application was executed (t), and the second being the time in seconds since the last update (dt). dt will always be a fixed value, and is determined by the user-specified update rate. * Sets the update callback, which is executed at regular intervals until the application is closed. The update callback expects two parameters, the first being the total time in seconds since the application was executed (t), and the second being the time in seconds since the last update (dt). dt will always be a fixed value, and is determined by the user-specified update rate.
* *
@ -143,8 +159,6 @@ public:
*/ */
void set_vsync(bool vsync); void set_vsync(bool vsync);
void take_screenshot();
/// Returns the dimensions of the current display. /// Returns the dimensions of the current display.
const std::array<int, 2>& get_display_dimensions() const; const std::array<int, 2>& get_display_dimensions() const;
@ -181,7 +195,6 @@ private:
void translate_sdl_events(); void translate_sdl_events();
void window_resized(); void window_resized();
static void save_image(const std::string& filename, int w, int h, const unsigned char* pixels);
bool closed; bool closed;
int exit_status; int exit_status;

+ 16
- 5
src/game/bootloader.cpp View File

@ -92,6 +92,7 @@
#include <functional> #include <functional>
#include <string> #include <string>
#include <vector> #include <vector>
#include "utility/timestamp.hpp"
static void parse_options(game_context* ctx, int argc, char** argv); static void parse_options(game_context* ctx, int argc, char** argv);
static void setup_resources(game_context* ctx); static void setup_resources(game_context* ctx);
@ -361,6 +362,15 @@ void load_strings(game_context* ctx)
build_string_table_map(&ctx->string_table_map, *ctx->string_table); build_string_table_map(&ctx->string_table_map, *ctx->string_table);
ctx->language_code = ctx->config->get<std::string>("language"); ctx->language_code = ctx->config->get<std::string>("language");
ctx->language_index = -1;
for (int i = 2; i < (*ctx->string_table)[0].size(); ++i)
{
if ((*ctx->string_table)[0][i] == ctx->language_code)
ctx->language_index = i;
}
logger->log("lang index: " + std::to_string(ctx->language_index));
ctx->strings = &ctx->string_table_map[ctx->language_code]; ctx->strings = &ctx->string_table_map[ctx->language_code];
logger->pop_task(EXIT_SUCCESS); logger->pop_task(EXIT_SUCCESS);
@ -864,17 +874,18 @@ void setup_controls(game_context* ctx)
} }
); );
// Create screenshot control // Create screenshot control
ctx->screenshot_control = new control(); ctx->screenshot_control = new control();
/*ctx->screenshot_control.set_activated_callback([this]()
{
ctx->screenshot_control->set_activated_callback
(
[ctx]() [ctx]()
{ {
ctx->app->take_screenshot();
std::string path = ctx->screenshots_path + "antkeeper-" + timestamp() + ".png";
ctx->app->save_frame(path);
} }
});*/
);
// Create menu back control // Create menu back control
ctx->menu_back_control = new control(); ctx->menu_back_control = new control();

Loading…
Cancel
Save