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 {
|
class Renderer {
|
||||||
public:
|
public:
|
||||||
constexpr static int NUM_VAO = 7;
|
constexpr static int NUM_VAO = 7;
|
||||||
|
constexpr static const char* SCREENSHOT_PATH = "./screenshot";
|
||||||
Renderer(TextureManager& texture_manager, Config& config);
|
Renderer(TextureManager& texture_manager, Config& config);
|
||||||
~Renderer();
|
~Renderer();
|
||||||
void reload_config();
|
void reload_config();
|
||||||
@@ -83,6 +83,8 @@ public:
|
|||||||
|
|
||||||
ModelRender& model_renderer();
|
ModelRender& model_renderer();
|
||||||
|
|
||||||
|
void save_screenshot();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TextureManager& m_texture_manager;
|
TextureManager& m_texture_manager;
|
||||||
bool m_init = false;
|
bool m_init = false;
|
||||||
@@ -98,6 +100,8 @@ private:
|
|||||||
float m_window_width = 0.0f;
|
float m_window_width = 0.0f;
|
||||||
float m_window_height = 0.0f;
|
float m_window_height = 0.0f;
|
||||||
|
|
||||||
|
bool m_save_screenshot = false;
|
||||||
|
|
||||||
glm::mat4 m_world_proj_matrix;
|
glm::mat4 m_world_proj_matrix;
|
||||||
|
|
||||||
std::unique_ptr<VertexBuffer> m_sky_vbo;
|
std::unique_ptr<VertexBuffer> m_sky_vbo;
|
||||||
@@ -129,6 +133,7 @@ private:
|
|||||||
void updata_framebuffer(int width, int height);
|
void updata_framebuffer(int width, int height);
|
||||||
void init_quad();
|
void init_quad();
|
||||||
void init_text();
|
void init_text();
|
||||||
|
void handle_screenshot();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -1,11 +1,23 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <SDL3/SDL_timer.h>
|
#include <SDL3/SDL_timer.h>
|
||||||
|
#include <chrono>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <format>
|
||||||
|
#include <string>
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
namespace Tools {
|
namespace Tools {
|
||||||
// return ms
|
// return ms
|
||||||
inline uint64_t get_time_ticks() { return SDL_GetTicks(); }
|
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 Tools
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -9,10 +9,13 @@
|
|||||||
#include "Cubed/tools/font.hpp"
|
#include "Cubed/tools/font.hpp"
|
||||||
#include "Cubed/tools/log.hpp"
|
#include "Cubed/tools/log.hpp"
|
||||||
#include "Cubed/tools/shader_tools.hpp"
|
#include "Cubed/tools/shader_tools.hpp"
|
||||||
|
#include "Cubed/tools/time_tools.hpp"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <glm/gtc/type_ptr.hpp>
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
|
#include <stb_image_write.h>
|
||||||
|
namespace fs = std::filesystem;
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
Renderer::Renderer(TextureManager& texture_manager, Config& config)
|
Renderer::Renderer(TextureManager& texture_manager, Config& config)
|
||||||
@@ -139,7 +142,7 @@ void Renderer::begin_frame() {
|
|||||||
glClearColor(0.0, 0.0, 0.0, 1.0);
|
glClearColor(0.0, 0.0, 0.0, 1.0);
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
void Renderer::end_frame() {}
|
void Renderer::end_frame() { handle_screenshot(); }
|
||||||
|
|
||||||
void Renderer::begin_render_ui() {
|
void Renderer::begin_render_ui() {
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
@@ -288,6 +291,34 @@ bool Renderer::handle_frame_buffer_resize_event(
|
|||||||
return false;
|
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() {
|
float& Renderer::ambient_strength() {
|
||||||
return m_world_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 glm::mat4& Renderer::p_mat() const { return m_world_proj_matrix; }
|
||||||
const std::vector<VertexArray>& Renderer::vao() const { return m_vao; }
|
const std::vector<VertexArray>& Renderer::vao() const { return m_vao; }
|
||||||
ModelRender& Renderer::model_renderer() { return m_model_renderer; }
|
ModelRender& Renderer::model_renderer() { return m_model_renderer; }
|
||||||
|
void Renderer::save_screenshot() { m_save_screenshot = true; }
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "Cubed/app.hpp"
|
#include "Cubed/app.hpp"
|
||||||
#include "Cubed/render/renderer.hpp"
|
#include "Cubed/render/renderer.hpp"
|
||||||
#include "Cubed/scene/scene_manager.hpp"
|
#include "Cubed/scene/scene_manager.hpp"
|
||||||
|
#include "Cubed/tools/time_tools.hpp"
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
WorldScene::WorldScene(SceneManager& scene_manager)
|
WorldScene::WorldScene(SceneManager& scene_manager)
|
||||||
: m_scene_manager(scene_manager), m_dev_panel(*this),
|
: 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) {
|
if (m_paused) {
|
||||||
switch (m_paused_ui) {
|
switch (m_paused_ui) {
|
||||||
case PauseUI::INVENTORY:
|
case PauseUI::INVENTORY:
|
||||||
|
|||||||
Reference in New Issue
Block a user