mirror of
https://github.com/luanti-org/luanti.git
synced 2025-12-22 14:45:27 +01:00
Allow taking screenshots in main menu (#16749)
Co-authored-by: sfan5 <sfan5@live.de> Co-authored-by: siliconsniffer <siliconsniffer@users.noreply.github.com>
This commit is contained in:
@@ -36,6 +36,7 @@
|
|||||||
#include "translation.h"
|
#include "translation.h"
|
||||||
#include "util/auth.h"
|
#include "util/auth.h"
|
||||||
#include "util/pointedthing.h"
|
#include "util/pointedthing.h"
|
||||||
|
#include "util/screenshot.h"
|
||||||
#include "util/serialize.h"
|
#include "util/serialize.h"
|
||||||
#include "util/srp.h"
|
#include "util/srp.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
@@ -1915,69 +1916,12 @@ float Client::getCurRate()
|
|||||||
void Client::makeScreenshot()
|
void Client::makeScreenshot()
|
||||||
{
|
{
|
||||||
video::IVideoDriver *driver = m_rendering_engine->get_video_driver();
|
video::IVideoDriver *driver = m_rendering_engine->get_video_driver();
|
||||||
video::IImage* const raw_image = driver->createScreenShot();
|
|
||||||
|
|
||||||
if (!raw_image) {
|
|
||||||
errorstream << "Could not take screenshot" << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct tm tm = mt_localtime();
|
|
||||||
|
|
||||||
char timestamp_c[64];
|
|
||||||
strftime(timestamp_c, sizeof(timestamp_c), "%Y%m%d_%H%M%S", &tm);
|
|
||||||
|
|
||||||
std::string screenshot_dir = g_settings->get("screenshot_path");
|
|
||||||
if (!fs::IsPathAbsolute(screenshot_dir))
|
|
||||||
screenshot_dir = porting::path_user + DIR_DELIM + screenshot_dir;
|
|
||||||
|
|
||||||
std::string filename_base = screenshot_dir
|
|
||||||
+ DIR_DELIM
|
|
||||||
+ std::string("screenshot_")
|
|
||||||
+ timestamp_c;
|
|
||||||
std::string filename_ext = "." + g_settings->get("screenshot_format");
|
|
||||||
|
|
||||||
// Create the directory if it doesn't already exist.
|
|
||||||
// Otherwise, saving the screenshot would fail.
|
|
||||||
fs::CreateAllDirs(screenshot_dir);
|
|
||||||
|
|
||||||
u32 quality = (u32)g_settings->getS32("screenshot_quality");
|
|
||||||
quality = rangelim(quality, 0, 100) / 100.0f * 255;
|
|
||||||
|
|
||||||
// Try to find a unique filename
|
|
||||||
std::string filename;
|
std::string filename;
|
||||||
unsigned serial = 0;
|
if (takeScreenshot(driver, filename)) {
|
||||||
|
std::string msg = fmtgettext("Saved screenshot to \"%s\"", filename.c_str());
|
||||||
while (serial < SCREENSHOT_MAX_SERIAL_TRIES) {
|
|
||||||
filename = filename_base + (serial > 0 ? ("_" + itos(serial)) : "") + filename_ext;
|
|
||||||
if (!fs::PathExists(filename))
|
|
||||||
break; // File did not apparently exist, we'll go with it
|
|
||||||
serial++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (serial == SCREENSHOT_MAX_SERIAL_TRIES) {
|
|
||||||
errorstream << "Could not find suitable filename for screenshot" << std::endl;
|
|
||||||
} else {
|
|
||||||
video::IImage* const image =
|
|
||||||
driver->createImage(video::ECF_R8G8B8, raw_image->getDimension());
|
|
||||||
|
|
||||||
if (image) {
|
|
||||||
raw_image->copyTo(image);
|
|
||||||
|
|
||||||
std::string msg;
|
|
||||||
if (driver->writeImageToFile(image, filename.c_str(), quality)) {
|
|
||||||
msg = fmtgettext("Saved screenshot to \"%s\"", filename.c_str());
|
|
||||||
} else {
|
|
||||||
msg = fmtgettext("Failed to save screenshot to \"%s\"", filename.c_str());
|
|
||||||
}
|
|
||||||
pushToChatQueue(new ChatMessage(CHATMESSAGE_TYPE_SYSTEM,
|
pushToChatQueue(new ChatMessage(CHATMESSAGE_TYPE_SYSTEM,
|
||||||
utf8_to_wide(msg)));
|
utf8_to_wide(msg)));
|
||||||
infostream << msg << std::endl;
|
|
||||||
image->drop();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
raw_image->drop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::pushToEventQueue(ClientEvent *event)
|
void Client::pushToEventQueue(ClientEvent *event)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <ICameraSceneNode.h>
|
#include <ICameraSceneNode.h>
|
||||||
#include <IGUIStaticText.h>
|
#include <IGUIStaticText.h>
|
||||||
#include "client/imagefilters.h"
|
#include "client/imagefilters.h"
|
||||||
|
#include "util/screenshot.h"
|
||||||
#include "util/tracy_wrapper.h"
|
#include "util/tracy_wrapper.h"
|
||||||
#include "script/common/c_types.h" // LuaError
|
#include "script/common/c_types.h" // LuaError
|
||||||
|
|
||||||
@@ -39,6 +40,13 @@ void TextDestGuiEngine::gotText(const StringMap &fields)
|
|||||||
m_engine->getScriptIface()->handleMainMenuButtons(fields);
|
m_engine->getScriptIface()->handleMainMenuButtons(fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextDestGuiEngine::requestScreenshot()
|
||||||
|
{
|
||||||
|
if (m_engine) {
|
||||||
|
m_engine->requestScreenshot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
MenuTextureSource::~MenuTextureSource()
|
MenuTextureSource::~MenuTextureSource()
|
||||||
{
|
{
|
||||||
@@ -367,6 +375,14 @@ void GUIEngine::run()
|
|||||||
// the menu.
|
// the menu.
|
||||||
drawHeader(driver);
|
drawHeader(driver);
|
||||||
|
|
||||||
|
// Take screenshot if requested
|
||||||
|
// Must be before endScene() to capture the rendered frame
|
||||||
|
if (m_take_screenshot) {
|
||||||
|
m_take_screenshot = false;
|
||||||
|
std::string filename;
|
||||||
|
takeScreenshot(driver, filename);
|
||||||
|
}
|
||||||
|
|
||||||
driver->endScene();
|
driver->endScene();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
void gotText(const StringMap &fields);
|
void gotText(const StringMap &fields);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request a screenshot from the main menu
|
||||||
|
*/
|
||||||
|
void requestScreenshot();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** target to transmit data to */
|
/** target to transmit data to */
|
||||||
GUIEngine *m_engine = nullptr;
|
GUIEngine *m_engine = nullptr;
|
||||||
@@ -146,6 +151,14 @@ public:
|
|||||||
return m_scriptdir;
|
return m_scriptdir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request taking a screenshot on the next frame
|
||||||
|
*/
|
||||||
|
void requestScreenshot()
|
||||||
|
{
|
||||||
|
m_take_screenshot = true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get translations for content
|
* Get translations for content
|
||||||
*
|
*
|
||||||
@@ -199,6 +212,9 @@ private:
|
|||||||
/** variable used to abort menu and return back to main game handling */
|
/** variable used to abort menu and return back to main game handling */
|
||||||
bool m_startgame = false;
|
bool m_startgame = false;
|
||||||
|
|
||||||
|
/** flag to take a screenshot on next frame */
|
||||||
|
bool m_take_screenshot = false;
|
||||||
|
|
||||||
/** scripting interface */
|
/** scripting interface */
|
||||||
std::unique_ptr<MainMenuScripting> m_script;
|
std::unique_ptr<MainMenuScripting> m_script;
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#include "client/fontengine.h"
|
#include "client/fontengine.h"
|
||||||
#include "client/sound.h"
|
#include "client/sound.h"
|
||||||
#include "util/numeric.h"
|
#include "util/numeric.h"
|
||||||
|
#include "util/screenshot.h"
|
||||||
#include "util/string.h" // for parseColorString()
|
#include "util/string.h" // for parseColorString()
|
||||||
#include "irrlicht_changes/static_text.h"
|
#include "irrlicht_changes/static_text.h"
|
||||||
#include "client/guiscalingfilter.h"
|
#include "client/guiscalingfilter.h"
|
||||||
@@ -4082,9 +4083,13 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_client != NULL && event.KeyInput.PressedDown &&
|
if (event.KeyInput.PressedDown &&
|
||||||
(kp == getKeySetting("keymap_screenshot"))) {
|
(kp == getKeySetting("keymap_screenshot"))) {
|
||||||
|
if (m_client) {
|
||||||
m_client->makeScreenshot();
|
m_client->makeScreenshot();
|
||||||
|
} else if (m_text_dst) { // in main menu
|
||||||
|
m_text_dst->requestScreenshot();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.KeyInput.PressedDown && kp == getKeySetting("keymap_toggle_debug")) {
|
if (event.KeyInput.PressedDown && kp == getKeySetting("keymap_toggle_debug")) {
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ struct TextDest
|
|||||||
virtual ~TextDest() = default;
|
virtual ~TextDest() = default;
|
||||||
|
|
||||||
virtual void gotText(const StringMap &fields) = 0;
|
virtual void gotText(const StringMap &fields) = 0;
|
||||||
|
virtual void requestScreenshot() {}
|
||||||
|
|
||||||
std::string m_formname;
|
std::string m_formname;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ set(util_SRCS
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/pointabilities.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/pointabilities.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/quicktune.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/quicktune.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/serialize.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/serialize.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/screenshot.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/sha1.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/sha1.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/string.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/string.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/srp.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/srp.cpp
|
||||||
|
|||||||
96
src/util/screenshot.cpp
Normal file
96
src/util/screenshot.cpp
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
// Luanti
|
||||||
|
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
// Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
|
|
||||||
|
#include "screenshot.h"
|
||||||
|
#include "filesys.h"
|
||||||
|
#include "gettime.h"
|
||||||
|
#include "porting.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "util/string.h"
|
||||||
|
#include "util/numeric.h"
|
||||||
|
#include "gettext.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include <IVideoDriver.h>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
#define SCREENSHOT_MAX_SERIAL_TRIES 1000
|
||||||
|
|
||||||
|
bool takeScreenshot(video::IVideoDriver *driver, std::string &filename_out)
|
||||||
|
{
|
||||||
|
sanity_check(driver);
|
||||||
|
|
||||||
|
video::IImage* const raw_image = driver->createScreenShot();
|
||||||
|
|
||||||
|
if (!raw_image) {
|
||||||
|
errorstream << "Could not take screenshot" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct tm tm = mt_localtime();
|
||||||
|
|
||||||
|
char timestamp_c[64];
|
||||||
|
strftime(timestamp_c, sizeof(timestamp_c), "%Y%m%d_%H%M%S", &tm);
|
||||||
|
|
||||||
|
std::string screenshot_dir = g_settings->get("screenshot_path");
|
||||||
|
if (!fs::IsPathAbsolute(screenshot_dir))
|
||||||
|
screenshot_dir = porting::path_user + DIR_DELIM + screenshot_dir;
|
||||||
|
|
||||||
|
std::string filename_base = screenshot_dir
|
||||||
|
+ DIR_DELIM
|
||||||
|
+ std::string("screenshot_")
|
||||||
|
+ timestamp_c;
|
||||||
|
std::string filename_ext = "." + g_settings->get("screenshot_format");
|
||||||
|
|
||||||
|
// Create the directory if it doesn't already exist.
|
||||||
|
// Otherwise, saving the screenshot would fail.
|
||||||
|
fs::CreateAllDirs(screenshot_dir);
|
||||||
|
|
||||||
|
u32 quality = (u32)g_settings->getS32("screenshot_quality");
|
||||||
|
quality = rangelim(quality, 0, 100) / 100.0f * 255;
|
||||||
|
|
||||||
|
// Try to find a unique filename
|
||||||
|
std::string filename;
|
||||||
|
unsigned serial = 0;
|
||||||
|
|
||||||
|
while (serial < SCREENSHOT_MAX_SERIAL_TRIES) {
|
||||||
|
filename = filename_base + (serial > 0 ? ("_" + itos(serial)) : "").append(filename_ext);
|
||||||
|
if (!fs::PathExists(filename))
|
||||||
|
break; // File did not apparently exist, we'll go with it
|
||||||
|
serial++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serial == SCREENSHOT_MAX_SERIAL_TRIES) {
|
||||||
|
errorstream << "Could not find suitable filename for screenshot" << std::endl;
|
||||||
|
raw_image->drop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
video::IImage* const image =
|
||||||
|
driver->createImage(video::ECF_R8G8B8, raw_image->getDimension());
|
||||||
|
|
||||||
|
if (!image) {
|
||||||
|
errorstream << "Could not create image for screenshot" << std::endl;
|
||||||
|
raw_image->drop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_image->copyTo(image);
|
||||||
|
|
||||||
|
bool success = driver->writeImageToFile(image, filename.c_str(), quality);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
filename_out = filename;
|
||||||
|
std::string msg = fmtgettext("Saved screenshot to \"%s\"", filename.c_str());
|
||||||
|
infostream << msg << std::endl;
|
||||||
|
} else {
|
||||||
|
std::string msg = fmtgettext("Failed to save screenshot to \"%s\"", filename.c_str());
|
||||||
|
errorstream << msg << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
image->drop();
|
||||||
|
raw_image->drop();
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
20
src/util/screenshot.h
Normal file
20
src/util/screenshot.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// Luanti
|
||||||
|
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
// Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace video {
|
||||||
|
class IVideoDriver;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take a screenshot and save it to disk
|
||||||
|
* @param driver Video driver to use for the screenshot
|
||||||
|
* @param filename_out Output parameter that receives the path to the saved screenshot
|
||||||
|
* @return true if the screenshot was saved successfully, false otherwise
|
||||||
|
*/
|
||||||
|
bool takeScreenshot(video::IVideoDriver *driver, std::string &filename_out);
|
||||||
|
|
||||||
Reference in New Issue
Block a user