mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-08 17:57:02 +08:00
feat(renderer): add screenshot capture with F2
This commit is contained in:
@@ -25,7 +25,7 @@ class DevPanel;
|
||||
class Renderer {
|
||||
public:
|
||||
constexpr static int NUM_VAO = 7;
|
||||
|
||||
constexpr static const char* SCREENSHOT_PATH = "./screenshot";
|
||||
Renderer(TextureManager& texture_manager, Config& config);
|
||||
~Renderer();
|
||||
void reload_config();
|
||||
@@ -83,6 +83,8 @@ public:
|
||||
|
||||
ModelRender& model_renderer();
|
||||
|
||||
void save_screenshot();
|
||||
|
||||
private:
|
||||
TextureManager& m_texture_manager;
|
||||
bool m_init = false;
|
||||
@@ -98,6 +100,8 @@ private:
|
||||
float m_window_width = 0.0f;
|
||||
float m_window_height = 0.0f;
|
||||
|
||||
bool m_save_screenshot = false;
|
||||
|
||||
glm::mat4 m_world_proj_matrix;
|
||||
|
||||
std::unique_ptr<VertexBuffer> m_sky_vbo;
|
||||
@@ -129,6 +133,7 @@ private:
|
||||
void updata_framebuffer(int width, int height);
|
||||
void init_quad();
|
||||
void init_text();
|
||||
void handle_screenshot();
|
||||
};
|
||||
|
||||
} // namespace Cubed
|
||||
@@ -1,11 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL_timer.h>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <format>
|
||||
#include <string>
|
||||
namespace Cubed {
|
||||
namespace Tools {
|
||||
// return ms
|
||||
inline uint64_t get_time_ticks() { return SDL_GetTicks(); }
|
||||
|
||||
inline std::string get_time_date_str() {
|
||||
static auto* zone = std::chrono::current_zone();
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto local =
|
||||
std::chrono::time_point_cast<std::chrono::seconds>(zone->to_local(now));
|
||||
return std::format("{:%F %T}", local);
|
||||
}
|
||||
|
||||
} // namespace Tools
|
||||
|
||||
} // namespace Cubed
|
||||
@@ -9,10 +9,13 @@
|
||||
#include "Cubed/tools/font.hpp"
|
||||
#include "Cubed/tools/log.hpp"
|
||||
#include "Cubed/tools/shader_tools.hpp"
|
||||
#include "Cubed/tools/time_tools.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <format>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include <stb_image_write.h>
|
||||
namespace fs = std::filesystem;
|
||||
namespace Cubed {
|
||||
|
||||
Renderer::Renderer(TextureManager& texture_manager, Config& config)
|
||||
@@ -139,7 +142,7 @@ void Renderer::begin_frame() {
|
||||
glClearColor(0.0, 0.0, 0.0, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
void Renderer::end_frame() {}
|
||||
void Renderer::end_frame() { handle_screenshot(); }
|
||||
|
||||
void Renderer::begin_render_ui() {
|
||||
glEnable(GL_BLEND);
|
||||
@@ -288,6 +291,34 @@ bool Renderer::handle_frame_buffer_resize_event(
|
||||
return false;
|
||||
}
|
||||
|
||||
void Renderer::handle_screenshot() {
|
||||
if (!m_save_screenshot) {
|
||||
return;
|
||||
}
|
||||
m_save_screenshot = false;
|
||||
std::array<int, 4> screen_stats;
|
||||
glGetIntegerv(GL_VIEWPORT, screen_stats.data());
|
||||
int width = screen_stats[2];
|
||||
int height = screen_stats[3];
|
||||
std::vector<unsigned char> pixels(width * height * 4);
|
||||
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
|
||||
std::vector<unsigned char> flipped_pixels(width * height * 4);
|
||||
for (int y = 0; y < height; ++y) {
|
||||
std::memcpy(&flipped_pixels[y * width * 4],
|
||||
&pixels[(height - 1 - y) * width * 4], width * 4);
|
||||
}
|
||||
fs::path path = SCREENSHOT_PATH;
|
||||
fs::create_directories(path);
|
||||
fs::path image =
|
||||
path / std::format("screenshot {}.png", Tools::get_time_date_str());
|
||||
if (!stbi_write_png(image.c_str(), width, height, 4, flipped_pixels.data(),
|
||||
width * 4)) {
|
||||
Logger::error("Failed to write {} image", image.c_str());
|
||||
} else {
|
||||
Logger::info("save {} success!", image.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
float& Renderer::ambient_strength() {
|
||||
return m_world_renderer.ambient_strength();
|
||||
}
|
||||
@@ -341,4 +372,5 @@ float Renderer::frame_width() const { return m_frame_width; }
|
||||
const glm::mat4& Renderer::p_mat() const { return m_world_proj_matrix; }
|
||||
const std::vector<VertexArray>& Renderer::vao() const { return m_vao; }
|
||||
ModelRender& Renderer::model_renderer() { return m_model_renderer; }
|
||||
void Renderer::save_screenshot() { m_save_screenshot = true; }
|
||||
} // namespace Cubed
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "Cubed/app.hpp"
|
||||
#include "Cubed/render/renderer.hpp"
|
||||
#include "Cubed/scene/scene_manager.hpp"
|
||||
#include "Cubed/tools/time_tools.hpp"
|
||||
namespace Cubed {
|
||||
WorldScene::WorldScene(SceneManager& scene_manager)
|
||||
: m_scene_manager(scene_manager), m_dev_panel(*this),
|
||||
@@ -380,7 +381,16 @@ bool WorldScene::handle_key_event(const KeyEvent& e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (e.key == Key::F2 && e.action == KeyAction::PRESS) {
|
||||
m_scene_manager.app().renderer().save_screenshot();
|
||||
ChatMessage msg;
|
||||
msg.system_msg = true;
|
||||
msg.color = Color::WHITE;
|
||||
msg.text = "Saved Screenshot!";
|
||||
msg.time = Tools::get_time_ticks();
|
||||
m_hud_ui.add_chat_message(msg);
|
||||
return true;
|
||||
}
|
||||
if (m_paused) {
|
||||
switch (m_paused_ui) {
|
||||
case PauseUI::INVENTORY:
|
||||
|
||||
Reference in New Issue
Block a user