save indexed screenshot to directory
This commit is contained in:
parent
ebd8f34266
commit
1dbb2a2e1d
|
@ -1,6 +1,10 @@
|
||||||
// reset, pause, auto reset, analog d-pad, gamepad config, any key, confirm exit game
|
/***
|
||||||
|
|
||||||
// sweaty gamer hands oily snacks and bad hygiene
|
reset, pause, auto reset, analog d-pad, gamepad config, any key, confirm exit
|
||||||
|
game, screen wipes
|
||||||
|
:) SWEATY HANDS :) OILY SNACKS :) AND BAD HYGIENE :)
|
||||||
|
|
||||||
|
***/
|
||||||
|
|
||||||
#include "Demo.hpp"
|
#include "Demo.hpp"
|
||||||
|
|
||||||
|
@ -65,7 +69,7 @@ SDL_Surface* get_screen_surface(SDL_Window *window)
|
||||||
{
|
{
|
||||||
int w, h;
|
int w, h;
|
||||||
SDL_GetWindowSize(window, &w, &h);
|
SDL_GetWindowSize(window, &w, &h);
|
||||||
unsigned char *pixels = (unsigned char *) malloc(24 * w * h);
|
unsigned char* pixels = new unsigned char[24 * w * h];
|
||||||
GLenum format;
|
GLenum format;
|
||||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||||
format = GL_RGB;
|
format = GL_RGB;
|
||||||
|
@ -76,7 +80,7 @@ SDL_Surface* get_screen_surface(SDL_Window *window)
|
||||||
SDL_Surface *surface = zoomSurface(
|
SDL_Surface *surface = zoomSurface(
|
||||||
SDL_CreateRGBSurfaceFrom(pixels, w, h, 24, 3 * w,
|
SDL_CreateRGBSurfaceFrom(pixels, w, h, 24, 3 * w,
|
||||||
0, 0, 0, 0), 1, -1, SMOOTHING_OFF);
|
0, 0, 0, 0), 1, -1, SMOOTHING_OFF);
|
||||||
free(pixels);
|
delete[] pixels;
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,6 +180,7 @@ struct Demo : Game
|
||||||
Mix_Music *music = Mix_LoadMUS("resource/Field.mp3");
|
Mix_Music *music = Mix_LoadMUS("resource/Field.mp3");
|
||||||
Mix_PlayMusic(music, -1);
|
Mix_PlayMusic(music, -1);
|
||||||
load_gl_context();
|
load_gl_context();
|
||||||
|
delegate->subscribe(&Demo::respond, this);
|
||||||
Input *input = new Input(this);
|
Input *input = new Input(this);
|
||||||
input->print_branch();
|
input->print_branch();
|
||||||
mushroom->print_branch();
|
mushroom->print_branch();
|
||||||
|
@ -343,23 +348,26 @@ struct Demo : Game
|
||||||
|
|
||||||
void respond(SDL_Event& event)
|
void respond(SDL_Event& event)
|
||||||
{
|
{
|
||||||
|
if (delegate->compare(event, "context"))
|
||||||
|
{
|
||||||
|
if (is_gl_context)
|
||||||
|
{
|
||||||
|
load_sdl_context();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
load_gl_context();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void update()
|
void update()
|
||||||
{
|
{
|
||||||
// while (SDL_PollEvent(&event))
|
// while (SDL_PollEvent(&event))
|
||||||
// {
|
// {
|
||||||
// if (event.type == SDL_QUIT)
|
// if (event.type == SDL_KEYDOWN)
|
||||||
// {
|
// {
|
||||||
// flag_to_end();
|
// if (event.key.keysym.sym == SDLK_F10)
|
||||||
// }
|
|
||||||
// else if (event.type == SDL_KEYDOWN)
|
|
||||||
// {
|
|
||||||
// if (event.key.keysym.sym == SDLK_F9)
|
|
||||||
// {
|
|
||||||
// capture_screen(window);
|
|
||||||
// }
|
|
||||||
// else if (event.key.keysym.sym == SDLK_F10)
|
|
||||||
// {
|
// {
|
||||||
// if (not is_recording)
|
// if (not is_recording)
|
||||||
// {
|
// {
|
||||||
|
@ -412,17 +420,6 @@ struct Demo : Game
|
||||||
// {
|
// {
|
||||||
// left_active = true;
|
// left_active = true;
|
||||||
// }
|
// }
|
||||||
// else if (event.key.keysym.sym == SDLK_SPACE)
|
|
||||||
// {
|
|
||||||
// if (is_gl_context)
|
|
||||||
// {
|
|
||||||
// load_sdl_context();
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// load_gl_context();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
// }
|
||||||
// else if (event.type == SDL_KEYUP)
|
// else if (event.type == SDL_KEYUP)
|
||||||
// {
|
// {
|
||||||
|
|
|
@ -37,15 +37,17 @@ $(GLEW_DIR)%.o: $(GLEW_DIR)%.c $(GLEW_DIR)%.h
|
||||||
$(CC_LINUX) $(CFLAGS) $< -o $@
|
$(CC_LINUX) $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
$(SFW_SRC_DIR)Sprite.o: $(addprefix $(SFW_SRC_DIR),Game.*pp Location.*pp)
|
$(SFW_SRC_DIR)Sprite.o: $(addprefix $(SFW_SRC_DIR),Game.*pp Location.*pp)
|
||||||
$(SFW_SRC_DIR)Game.o: $(addprefix $(SFW_SRC_DIR),Sprite.*pp Configuration.*pp Delegate.*pp)
|
$(SFW_SRC_DIR)Game.o: $(addprefix $(SFW_SRC_DIR),Sprite.*pp Configuration.*pp Delegate.*pp Display.*pp Recorder.*pp)
|
||||||
$(SFW_SRC_DIR)Node.o: $(addprefix $(SFW_SRC_DIR),Game.*pp Configuration.*pp)
|
$(SFW_SRC_DIR)Node.o: $(addprefix $(SFW_SRC_DIR),Game.*pp Configuration.*pp)
|
||||||
|
$(SFW_SRC_DIR)Recorder.o: $(addprefix $(SFW_SRC_DIR),extension.*pp)
|
||||||
$(SFW_SRC_DIR)%.o: $(addprefix $(SFW_SRC_DIR),%.cpp %.hpp Node.*pp)
|
$(SFW_SRC_DIR)%.o: $(addprefix $(SFW_SRC_DIR),%.cpp %.hpp Node.*pp)
|
||||||
$(CPPC_LINUX) $(CPP_FLAGS) $(SDL_FLAGS) $< -o $@
|
$(CPPC_LINUX) $(CPP_FLAGS) $(SDL_FLAGS) $< -o $@
|
||||||
|
|
||||||
Demo.o: Demo.cpp Demo.hpp $(addprefix $(SFW_SRC_DIR),Sprite.*pp Node.*pp Game.*pp Location.*pp Input.*pp)
|
Demo.o: Demo.cpp Demo.hpp $(addprefix $(SFW_SRC_DIR),Sprite.*pp Node.*pp Game.*pp Location.*pp Input.*pp Recorder.*pp)
|
||||||
$(CPPC_LINUX) $(CPP_FLAGS) $(SDL_FLAGS) $< -o $@
|
$(CPPC_LINUX) $(CPP_FLAGS) $(SDL_FLAGS) $< -o $@
|
||||||
|
|
||||||
linux: Demo.o $(addprefix $(SFW_SRC_DIR),Sprite.o Node.o Game.o Location.o Configuration.o Input.o Delegate.o) \
|
linux: Demo.o $(addprefix $(SFW_SRC_DIR),Sprite.o Node.o Game.o Location.o Configuration.o Input.o Delegate.o \
|
||||||
|
Display.o Recorder.o extension.o) \
|
||||||
$(GLEW_DIR)glew.o $(addprefix $(SDLGFX2_DIR),SDL2_rotozoom.o SDL2_gfxPrimitives.o)
|
$(GLEW_DIR)glew.o $(addprefix $(SDLGFX2_DIR),SDL2_rotozoom.o SDL2_gfxPrimitives.o)
|
||||||
$(CPPC_LINUX) $(LFLAGS) -D__LINUX__ $^ -lGL -lSDL2_image -lSDL2_ttf -lSDL2_mixer -lstdc++fs -o demo
|
$(CPPC_LINUX) $(LFLAGS) -D__LINUX__ $^ -lGL -lSDL2_image -lSDL2_ttf -lSDL2_mixer -lstdc++fs -o demo
|
||||||
|
|
||||||
|
|
|
@ -3,13 +3,15 @@
|
||||||
{
|
{
|
||||||
"dimensions": [640, 480]
|
"dimensions": [640, 480]
|
||||||
},
|
},
|
||||||
|
"path":
|
||||||
|
{
|
||||||
|
"screenshots": "local/screenshots"
|
||||||
|
},
|
||||||
"gamepad":
|
"gamepad":
|
||||||
{
|
{
|
||||||
},
|
},
|
||||||
|
|
||||||
"keys":
|
"keys":
|
||||||
{
|
{
|
||||||
"screenshot": ["CTRL", "s"]
|
"context": " "
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,15 @@ void Configuration::set_defaults()
|
||||||
{"down", "down"},
|
{"down", "down"},
|
||||||
{"left", "left"}
|
{"left", "left"}
|
||||||
};
|
};
|
||||||
|
sys_config["path"] = {
|
||||||
|
{"screenshots", "."}
|
||||||
|
};
|
||||||
|
sys_config["display"] = {
|
||||||
|
{"dimensions", {640, 480}},
|
||||||
|
{"screenshot-prefix", "screenshot-"},
|
||||||
|
{"screenshot-extension", ".png"},
|
||||||
|
{"screenshot-zfill", 5}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Configuration::load()
|
void Configuration::load()
|
||||||
|
@ -42,7 +51,13 @@ void Configuration::merge()
|
||||||
config = sys_config;
|
config = sys_config;
|
||||||
if (not game_config.empty())
|
if (not game_config.empty())
|
||||||
{
|
{
|
||||||
config["keys"].update(game_config["keys"]);
|
for (auto& section: config.items())
|
||||||
|
{
|
||||||
|
if (game_config.contains(section.key()))
|
||||||
|
{
|
||||||
|
config[section.key()].update(game_config[section.key()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
std::cout << std::setw(4) << config << std::endl;
|
std::cout << std::setw(4) << config << std::endl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
int Delegate::command_event_type = SDL_RegisterEvents(1);
|
int Delegate::command_event_type = SDL_RegisterEvents(1);
|
||||||
|
|
||||||
Delegate::Delegate(Node *parent) : Node(parent) {}
|
Delegate::Delegate(Node* parent) : Node(parent) {}
|
||||||
|
|
||||||
void Delegate::add_subscriber(subscriber s, int type)
|
void Delegate::add_subscriber(subscriber s, int type)
|
||||||
{
|
{
|
||||||
|
@ -30,3 +30,9 @@ void Delegate::dispatch()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Delegate::compare(SDL_Event& event, std::string command)
|
||||||
|
{
|
||||||
|
return event.type == command_event_type and
|
||||||
|
*static_cast<std::string*>(event.user.data1) == command;
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef Delegate_h_
|
#ifndef Delegate_h_
|
||||||
#define Delegate_h_
|
#define Delegate_h_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
@ -14,12 +15,19 @@ typedef std::function<void(SDL_Event&)> subscriber;
|
||||||
struct Delegate : Node
|
struct Delegate : Node
|
||||||
{
|
{
|
||||||
|
|
||||||
std::map<int, std::list<subscriber>> subscribers;
|
std::map<int, std::vector<subscriber>> subscribers;
|
||||||
static int command_event_type;
|
static int command_event_type;
|
||||||
|
|
||||||
Delegate(Node*);
|
Delegate(Node*);
|
||||||
void add_subscriber(subscriber, int);
|
void add_subscriber(subscriber, int);
|
||||||
void dispatch();
|
void dispatch();
|
||||||
|
bool compare(SDL_Event&, std::string);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void subscribe(void(T::*f)(SDL_Event&), T* o, int type = command_event_type)
|
||||||
|
{
|
||||||
|
add_subscriber(std::bind(f, o, std::placeholders::_1), type);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
#include "Display.hpp"
|
||||||
|
#include "Game.hpp"
|
||||||
|
|
||||||
|
Display::Display(Node* parent) : Node(parent) {}
|
||||||
|
|
||||||
|
glm::ivec2 Display::get_window_size()
|
||||||
|
{
|
||||||
|
glm::ivec2 size;
|
||||||
|
SDL_GetWindowSize(get_root()->window, &size.x, &size.y);
|
||||||
|
return size;
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef Display_h_
|
||||||
|
#define Display_h_
|
||||||
|
|
||||||
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
|
#include "glm/vec2.hpp"
|
||||||
|
|
||||||
|
#include "SDL.h"
|
||||||
|
|
||||||
|
#include "Node.hpp"
|
||||||
|
|
||||||
|
struct Display : Node
|
||||||
|
{
|
||||||
|
|
||||||
|
Display(Node*);
|
||||||
|
glm::ivec2 get_window_size();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
Game::Game()
|
Game::Game()
|
||||||
{
|
{
|
||||||
delegate->add_subscriber(std::bind(&Game::handle_quit_event, this, std::placeholders::_1), SDL_QUIT);
|
delegate->subscribe(&Game::handle_quit_event, this, SDL_QUIT);
|
||||||
std::cout << "GLEW " << glewGetString(GLEW_VERSION) << std::endl;
|
std::cout << "GLEW " << glewGetString(GLEW_VERSION) << std::endl;
|
||||||
putenv("SDL_VIDEO_X11_LEGACY_FULLSCREEN=0");
|
putenv("SDL_VIDEO_X11_LEGACY_FULLSCREEN=0");
|
||||||
putenv("SDL_VIDEO_CENTERED=1");
|
putenv("SDL_VIDEO_CENTERED=1");
|
||||||
|
|
12
src/Game.hpp
12
src/Game.hpp
|
@ -18,6 +18,8 @@
|
||||||
#include "Node.hpp"
|
#include "Node.hpp"
|
||||||
#include "Configuration.hpp"
|
#include "Configuration.hpp"
|
||||||
#include "Delegate.hpp"
|
#include "Delegate.hpp"
|
||||||
|
#include "Display.hpp"
|
||||||
|
#include "Recorder.hpp"
|
||||||
|
|
||||||
struct Game : Node
|
struct Game : Node
|
||||||
{
|
{
|
||||||
|
@ -27,16 +29,18 @@ struct Game : Node
|
||||||
Game(Game&&) = delete;
|
Game(Game&&) = delete;
|
||||||
Game& operator=(Game&&) = delete;
|
Game& operator=(Game&&) = delete;
|
||||||
|
|
||||||
SDL_Window *window;
|
SDL_Window* window;
|
||||||
SDL_Renderer *renderer = NULL;
|
SDL_Renderer* renderer = NULL;
|
||||||
SDL_GLContext glcontext = NULL;
|
SDL_GLContext glcontext = NULL;
|
||||||
int sw = 640, sh = 480, framerate = 60, frame_time_overflow = 0,
|
int sw = 640, sh = 480, framerate = 60, frame_time_overflow = 0,
|
||||||
last_frame_timestamp, frame_count_timestamp, ticks,
|
last_frame_timestamp, frame_count_timestamp, ticks,
|
||||||
last_frame_length;
|
last_frame_length;
|
||||||
float frame_length = 1000.0 / framerate;
|
float frame_length = 1000.0 / framerate;
|
||||||
bool done = false, show_framerate = false, is_gl_context = true;
|
bool done = false, show_framerate = false, is_gl_context = true;
|
||||||
Configuration *configuration = new Configuration(this);
|
Configuration* configuration = new Configuration(this);
|
||||||
Delegate *delegate = new Delegate(this);
|
Delegate* delegate = new Delegate(this);
|
||||||
|
Display* display = new Display(this);
|
||||||
|
Recorder* recorder = new Recorder(this);
|
||||||
|
|
||||||
Game();
|
Game();
|
||||||
void print_error(std::string);
|
void print_error(std::string);
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
Input::Input(Node *parent) : Node(parent)
|
Input::Input(Node *parent) : Node(parent)
|
||||||
{
|
{
|
||||||
load_key_map();
|
load_key_map();
|
||||||
get_delegate()->add_subscriber(std::bind(&Input::respond, this, std::placeholders::_1), SDL_KEYDOWN);
|
get_delegate()->subscribe(&Input::respond, this, SDL_KEYDOWN);
|
||||||
get_delegate()->add_subscriber(std::bind(&Input::respond, this, std::placeholders::_1), Delegate::command_event_type);
|
get_delegate()->subscribe(&Input::respond, this);
|
||||||
for (KeyCombination& combination : key_map)
|
for (KeyCombination& combination : key_map)
|
||||||
{
|
{
|
||||||
print_key_combination(combination);
|
print_key_combination(combination);
|
||||||
|
@ -29,19 +29,10 @@ void Input::load_key_map()
|
||||||
{
|
{
|
||||||
for (std::string part : entry.value())
|
for (std::string part : entry.value())
|
||||||
{
|
{
|
||||||
if (part == "CTRL")
|
ctrl = part == "CTRL";
|
||||||
{
|
shift = part == "SHIFT";
|
||||||
ctrl = true;
|
alt = part == "ALT";
|
||||||
}
|
if (not ctrl and not shift and not alt)
|
||||||
else if (part == "SHIFT")
|
|
||||||
{
|
|
||||||
shift = true;
|
|
||||||
}
|
|
||||||
else if (part == "ALT")
|
|
||||||
{
|
|
||||||
alt = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
key = get_key_code(part);
|
key = get_key_code(part);
|
||||||
}
|
}
|
||||||
|
@ -77,7 +68,6 @@ void Input::respond(SDL_Event &event)
|
||||||
{
|
{
|
||||||
if (event.type == SDL_KEYDOWN)
|
if (event.type == SDL_KEYDOWN)
|
||||||
{
|
{
|
||||||
std::cout << event.key.keysym.sym << std::endl;
|
|
||||||
SDL_Keymod mod = SDL_GetModState();
|
SDL_Keymod mod = SDL_GetModState();
|
||||||
for (KeyCombination &combination : key_map)
|
for (KeyCombination &combination : key_map)
|
||||||
{
|
{
|
||||||
|
@ -93,8 +83,4 @@ void Input::respond(SDL_Event &event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (event.type == Delegate::command_event_type)
|
|
||||||
{
|
|
||||||
std::cout << event.type << " " << *((std::string*) event.user.data1) << std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
#ifndef Input_h_
|
#ifndef Input_h_
|
||||||
#define Input_h_
|
#define Input_h_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <list>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
#include "SDL.h"
|
#include "SDL.h"
|
||||||
|
@ -40,7 +42,7 @@ struct Input : Node
|
||||||
{"f11", SDLK_F11},
|
{"f11", SDLK_F11},
|
||||||
{"f12", SDLK_F11}
|
{"f12", SDLK_F11}
|
||||||
};
|
};
|
||||||
std::list<KeyCombination> key_map;
|
std::vector<KeyCombination> key_map;
|
||||||
|
|
||||||
Input(Node*);
|
Input(Node*);
|
||||||
void respond(SDL_Event&);
|
void respond(SDL_Event&);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "Node.hpp"
|
#include "Node.hpp"
|
||||||
#include "Game.hpp"
|
#include "Game.hpp"
|
||||||
|
#include "Display.hpp"
|
||||||
|
|
||||||
Node::Node() : Node(NULL) {}
|
Node::Node() : Node(NULL) {}
|
||||||
|
|
||||||
|
@ -19,6 +20,11 @@ Delegate* Node::get_delegate()
|
||||||
return get_root()->delegate;
|
return get_root()->delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Display* Node::get_display()
|
||||||
|
{
|
||||||
|
return get_root()->display;
|
||||||
|
}
|
||||||
|
|
||||||
Game* Node::get_root()
|
Game* Node::get_root()
|
||||||
{
|
{
|
||||||
Node *current = this;
|
Node *current = this;
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
struct Game;
|
struct Game;
|
||||||
struct Delegate;
|
struct Delegate;
|
||||||
|
struct Display;
|
||||||
|
|
||||||
struct Node
|
struct Node
|
||||||
{
|
{
|
||||||
|
@ -21,6 +22,7 @@ struct Node
|
||||||
Game* get_root();
|
Game* get_root();
|
||||||
nlohmann::json& get_configuration();
|
nlohmann::json& get_configuration();
|
||||||
Delegate* get_delegate();
|
Delegate* get_delegate();
|
||||||
|
Display* get_display();
|
||||||
void print_branch();
|
void print_branch();
|
||||||
virtual std::string get_class_name() { return "Node"; };
|
virtual std::string get_class_name() { return "Node"; };
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
#include "Recorder.hpp"
|
||||||
|
|
||||||
|
Recorder::Recorder(Node* parent) : Node(parent)
|
||||||
|
{
|
||||||
|
get_delegate()->subscribe(&Recorder::respond, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Recorder::respond(SDL_Event& event)
|
||||||
|
{
|
||||||
|
if (get_delegate()->compare(event, "screenshot"))
|
||||||
|
{
|
||||||
|
capture_screen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Recorder::capture_screen()
|
||||||
|
{
|
||||||
|
nlohmann::json config = get_configuration();
|
||||||
|
SDL_Surface* surface = get_screen_surface();
|
||||||
|
fs::path directory = config["path"]["screenshots"];
|
||||||
|
fs::create_directories(directory);
|
||||||
|
std::string prefix = config["display"]["screenshot-prefix"].
|
||||||
|
get<std::string>();
|
||||||
|
std::string extension = config["display"]["screenshot-extension"].
|
||||||
|
get<std::string>();
|
||||||
|
std::stringstream file_pattern;
|
||||||
|
file_pattern << prefix << "(.*)" << extension;
|
||||||
|
fs::path query = directory / file_pattern.str();
|
||||||
|
std::vector<fs::path> files = sfw::glob(query);
|
||||||
|
int zfill = config["display"]["screenshot-zfill"].get<int>();
|
||||||
|
int index = 1;
|
||||||
|
if (files.size())
|
||||||
|
{
|
||||||
|
const std::string last = files.back().string();
|
||||||
|
std::smatch matches;
|
||||||
|
std::regex_match(last, matches, std::regex(query.string()));
|
||||||
|
index = std::stoi(matches[1]) + 1;
|
||||||
|
}
|
||||||
|
std::stringstream filename;
|
||||||
|
fs::path path;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
filename << prefix << sfw::pad(index++, zfill) << extension;
|
||||||
|
path = directory / filename.str();
|
||||||
|
filename.str("");
|
||||||
|
filename.clear();
|
||||||
|
}
|
||||||
|
while (fs::exists(path));
|
||||||
|
IMG_SavePNG(surface, path.c_str());
|
||||||
|
std::cout << "screenshot saved to " << path.string() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Surface* Recorder::get_screen_surface()
|
||||||
|
{
|
||||||
|
glm::ivec2 size = get_display()->get_window_size();
|
||||||
|
unsigned char* pixels = new unsigned char[24 * size.x * size.y];
|
||||||
|
get_screen_pixels(pixels, size.x, size.y);
|
||||||
|
SDL_Surface* surface = zoomSurface(
|
||||||
|
SDL_CreateRGBSurfaceFrom(
|
||||||
|
pixels, size.x, size.y, 24, 3 * size.x, 0, 0, 0, 0),
|
||||||
|
1, -1, SMOOTHING_OFF);
|
||||||
|
delete[] pixels;
|
||||||
|
return surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Recorder::get_screen_pixels(unsigned char* pixels, int w, int h, int x, int y)
|
||||||
|
{
|
||||||
|
GLenum format;
|
||||||
|
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||||
|
format = GL_RGB;
|
||||||
|
#else
|
||||||
|
format = GL_BGR;
|
||||||
|
#endif
|
||||||
|
glReadPixels(x, y, w, h, format, GL_UNSIGNED_BYTE, pixels);
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef Recorder_h_
|
||||||
|
#define Recorder_h_
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "SDL.h"
|
||||||
|
|
||||||
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
|
#include "glm/ext.hpp"
|
||||||
|
|
||||||
|
#define GL_GLEXT_PROTOTYPES
|
||||||
|
#define GLEW_STATIC
|
||||||
|
#include "glew/glew.h"
|
||||||
|
|
||||||
|
#include <SDL_image.h>
|
||||||
|
#include "sdl2-gfx/SDL2_gfxPrimitives.h"
|
||||||
|
#include "sdl2-gfx/SDL2_rotozoom.h"
|
||||||
|
|
||||||
|
#include "json/json.hpp"
|
||||||
|
|
||||||
|
#include "filesystem.hpp"
|
||||||
|
#include "Node.hpp"
|
||||||
|
#include "Delegate.hpp"
|
||||||
|
#include "Display.hpp"
|
||||||
|
#include "extension.hpp"
|
||||||
|
|
||||||
|
struct Recorder : Node
|
||||||
|
{
|
||||||
|
|
||||||
|
Recorder(Node*);
|
||||||
|
void respond(SDL_Event&);
|
||||||
|
void capture_screen();
|
||||||
|
SDL_Surface* get_screen_surface();
|
||||||
|
void get_screen_pixels(unsigned char*, int, int, int = 0, int = 0);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,22 @@
|
||||||
|
#include "extension.hpp"
|
||||||
|
|
||||||
|
std::vector<fs::path> sfw::glob(fs::path query)
|
||||||
|
{
|
||||||
|
fs::path basename = query.parent_path();
|
||||||
|
if (basename == "")
|
||||||
|
{
|
||||||
|
basename = ".";
|
||||||
|
}
|
||||||
|
std::regex expression(query.string());
|
||||||
|
std::vector<fs::path> files;
|
||||||
|
std::cout << basename << " " << query << std::endl;
|
||||||
|
for (auto& entry: fs::directory_iterator(basename))
|
||||||
|
{
|
||||||
|
if (std::regex_match(entry.path().string(), expression))
|
||||||
|
{
|
||||||
|
files.push_back(entry.path());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::sort(files.begin(), files.end());
|
||||||
|
return files;
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef extension_h_
|
||||||
|
#define extension_h_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
#include <regex>
|
||||||
|
#include <sstream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
#include "filesystem.hpp"
|
||||||
|
|
||||||
|
namespace sfw
|
||||||
|
{
|
||||||
|
std::vector<fs::path> glob(fs::path);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::string pad(T end, int width, char fill = '0')
|
||||||
|
{
|
||||||
|
std::stringstream padded;
|
||||||
|
padded.fill(fill);
|
||||||
|
padded.width(width);
|
||||||
|
padded << end;
|
||||||
|
return padded.str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue