Event+Asset+Keycodes: Add keybind for taking screenshots
This commit is contained in:
@@ -274,6 +274,11 @@ bool Application::onKeyPress(KeyPressEvent& e)
|
|||||||
m_window->setShouldClose(true);
|
m_window->setShouldClose(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (e.getKey() == keyCode("GLFW_KEY_F12")) {
|
||||||
|
ruc::info("Taking screenshot..");
|
||||||
|
Texture::saveScreenshotPNG("screenshot.png", m_window->getWidth(), m_window->getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,8 @@
|
|||||||
#include "ruc/meta/assert.h"
|
#include "ruc/meta/assert.h"
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#include "stb/stb_image.h"
|
#include "stb/stb_image.h"
|
||||||
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
|
#include "stb/stb_image_write.h"
|
||||||
|
|
||||||
#include "inferno/asset/texture.h"
|
#include "inferno/asset/texture.h"
|
||||||
|
|
||||||
@@ -23,6 +25,51 @@ Texture::~Texture()
|
|||||||
glDeleteTextures(1, &m_id);
|
glDeleteTextures(1, &m_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
|
||||||
|
void Texture::savePNG(std::string_view path, std::shared_ptr<Texture> texture)
|
||||||
|
{
|
||||||
|
texture->bind();
|
||||||
|
|
||||||
|
// Allocate memory
|
||||||
|
uint32_t dataFormat = texture->m_dataFormat == GL_RGBA ? 4 : 3;
|
||||||
|
size_t dataSize = texture->m_width * texture->m_height * dataFormat;
|
||||||
|
std::vector<unsigned char> data(dataSize);
|
||||||
|
|
||||||
|
// Read texture data from the GPU
|
||||||
|
glGetTexImage(GL_TEXTURE_2D, 0, texture->m_dataFormat, texture->m_dataType, data.data());
|
||||||
|
|
||||||
|
// Write image to a file
|
||||||
|
stbi_flip_vertically_on_write(1);
|
||||||
|
stbi_write_png(
|
||||||
|
path.data(),
|
||||||
|
texture->m_width,
|
||||||
|
texture->m_height,
|
||||||
|
dataFormat,
|
||||||
|
data.data(),
|
||||||
|
texture->m_width * dataFormat);
|
||||||
|
|
||||||
|
texture->unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texture::saveScreenshotPNG(std::string_view path, uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
// Allocate memory
|
||||||
|
size_t dataSize = width * height * 4;
|
||||||
|
std::vector<unsigned char> data(dataSize);
|
||||||
|
|
||||||
|
// Set the pack alignment to 1 (to avoid row alignment issues)
|
||||||
|
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||||
|
|
||||||
|
// Read the pixels from the default framebuffer
|
||||||
|
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data.data());
|
||||||
|
|
||||||
|
stbi_flip_vertically_on_write(1);
|
||||||
|
stbi_write_png(path.data(), width, height, 4, data.data(), width * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
|
||||||
void Texture::init(uint32_t width, uint32_t height, uint8_t channels)
|
void Texture::init(uint32_t width, uint32_t height, uint8_t channels)
|
||||||
{
|
{
|
||||||
init(width, height,
|
init(width, height,
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ class Texture : public Asset {
|
|||||||
public:
|
public:
|
||||||
virtual ~Texture();
|
virtual ~Texture();
|
||||||
|
|
||||||
|
static void savePNG(std::string_view path, std::shared_ptr<Texture> texture);
|
||||||
|
static void saveScreenshotPNG(std::string_view path, uint32_t width, uint32_t height);
|
||||||
|
|
||||||
void init(uint32_t width, uint32_t height, uint8_t channels);
|
void init(uint32_t width, uint32_t height, uint8_t channels);
|
||||||
void init(uint32_t width, uint32_t height, uint32_t internalFormat, uint32_t dataFormat, uint32_t dataType);
|
void init(uint32_t width, uint32_t height, uint32_t internalFormat, uint32_t dataFormat, uint32_t dataType);
|
||||||
|
|
||||||
|
|||||||
@@ -14,24 +14,27 @@ namespace Inferno {
|
|||||||
|
|
||||||
class KeyEvent : public Event {
|
class KeyEvent : public Event {
|
||||||
public:
|
public:
|
||||||
inline int getKey() const { return m_key; }
|
int getKey() const { return m_key; }
|
||||||
|
int getMods() const { return m_mods; }
|
||||||
|
|
||||||
EVENT_CLASS_CATEGORY(InputEventCategory | KeyEventCategory)
|
EVENT_CLASS_CATEGORY(InputEventCategory | KeyEventCategory)
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
KeyEvent(int key)
|
KeyEvent(int key, int mods)
|
||||||
: m_key(key)
|
: m_key(key)
|
||||||
|
, m_mods(mods)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_key;
|
int m_key { 0 };
|
||||||
|
int m_mods { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
class KeyPressEvent : public KeyEvent {
|
class KeyPressEvent final : public KeyEvent {
|
||||||
public:
|
public:
|
||||||
KeyPressEvent(int key)
|
KeyPressEvent(int key, int mods)
|
||||||
: KeyEvent(key)
|
: KeyEvent(key, mods)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,10 +48,10 @@ public:
|
|||||||
EVENT_CLASS_TYPE(KeyPress)
|
EVENT_CLASS_TYPE(KeyPress)
|
||||||
};
|
};
|
||||||
|
|
||||||
class KeyReleaseEvent : public KeyEvent {
|
class KeyReleaseEvent final : public KeyEvent {
|
||||||
public:
|
public:
|
||||||
KeyReleaseEvent(int key)
|
KeyReleaseEvent(int key, int mods)
|
||||||
: KeyEvent(key)
|
: KeyEvent(key, mods)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,13 +62,13 @@ public:
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
EVENT_CLASS_TYPE(KeyPress)
|
EVENT_CLASS_TYPE(KeyRelease)
|
||||||
};
|
};
|
||||||
|
|
||||||
class KeyRepeatEvent : public KeyEvent {
|
class KeyRepeatEvent final : public KeyEvent {
|
||||||
public:
|
public:
|
||||||
KeyRepeatEvent(int key)
|
KeyRepeatEvent(int key, int mods)
|
||||||
: KeyEvent(key)
|
: KeyEvent(key, mods)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +79,7 @@ public:
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
EVENT_CLASS_TYPE(KeyPress)
|
EVENT_CLASS_TYPE(KeyRepeat)
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Inferno
|
} // namespace Inferno
|
||||||
|
|||||||
@@ -139,14 +139,33 @@ static std::unordered_map<std::string_view, int> keys({
|
|||||||
{ MAP_KEY(GLFW_KEY_MENU) },
|
{ MAP_KEY(GLFW_KEY_MENU) },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
static std::unordered_map<std::string_view, int> modifiers({
|
||||||
|
{ MAP_KEY(GLFW_MOD_SHIFT) },
|
||||||
|
{ MAP_KEY(GLFW_MOD_CONTROL) },
|
||||||
|
{ MAP_KEY(GLFW_MOD_ALT) },
|
||||||
|
{ MAP_KEY(GLFW_MOD_SUPER) },
|
||||||
|
{ MAP_KEY(GLFW_MOD_CAPS_LOCK) }, // State, not really a modifier
|
||||||
|
{ MAP_KEY(GLFW_MOD_NUM_LOCK) }, // State, not really a modifier
|
||||||
|
});
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
|
// Example usage:
|
||||||
|
// event.getKey() == keyCode("GLFW_KEY_ESCAPE")
|
||||||
int keyCode(std::string_view name)
|
int keyCode(std::string_view name)
|
||||||
{
|
{
|
||||||
VERIFY(keys.find(name) != keys.end(), "could not find key code: {}", name);
|
VERIFY(keys.find(name) != keys.end(), "could not find key code: {}", name);
|
||||||
return keys.at(name);
|
return keys.at(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Example usage:
|
||||||
|
// event.getMods() & keyMod("GLFW_MOD_SHIFT")
|
||||||
|
int keyMod(std::string_view name)
|
||||||
|
{
|
||||||
|
VERIFY(modifiers.find(name) != modifiers.end(), "could not find key modifier: {}", name);
|
||||||
|
return modifiers.at(name);
|
||||||
|
}
|
||||||
|
|
||||||
std::string_view keyName(int key)
|
std::string_view keyName(int key)
|
||||||
{
|
{
|
||||||
auto it = std::find_if(keys.begin(), keys.end(), [key](const auto& keybind) {
|
auto it = std::find_if(keys.begin(), keys.end(), [key](const auto& keybind) {
|
||||||
|
|||||||
@@ -13,6 +13,8 @@
|
|||||||
namespace Inferno {
|
namespace Inferno {
|
||||||
|
|
||||||
int keyCode(std::string_view name);
|
int keyCode(std::string_view name);
|
||||||
std::string_view keyName(int);
|
int keyMod(std::string_view name);
|
||||||
|
|
||||||
|
std::string_view keyName(int key);
|
||||||
|
|
||||||
} // namespace Inferno
|
} // namespace Inferno
|
||||||
|
|||||||
@@ -122,17 +122,17 @@ void Window::initialize()
|
|||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case GLFW_PRESS: {
|
case GLFW_PRESS: {
|
||||||
KeyPressEvent event(key);
|
KeyPressEvent event(key, mods);
|
||||||
w.m_eventCallback(event);
|
w.m_eventCallback(event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GLFW_RELEASE: {
|
case GLFW_RELEASE: {
|
||||||
KeyReleaseEvent event(key);
|
KeyReleaseEvent event(key, mods);
|
||||||
w.m_eventCallback(event);
|
w.m_eventCallback(event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GLFW_REPEAT: {
|
case GLFW_REPEAT: {
|
||||||
KeyRepeatEvent event(key);
|
KeyRepeatEvent event(key, mods);
|
||||||
w.m_eventCallback(event);
|
w.m_eventCallback(event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user