recorder writes video frames to folder
This commit is contained in:
parent
1dbb2a2e1d
commit
321d9df1be
|
@ -1,8 +1,9 @@
|
|||
/***
|
||||
|
||||
reset, pause, auto reset, analog d-pad, gamepad config, any key, confirm exit
|
||||
game, screen wipes
|
||||
game, screen wipes, screen offset, screen scale
|
||||
:) SWEATY HANDS :) OILY SNACKS :) AND BAD HYGIENE :)
|
||||
*surf's up broccoli* <it's surfing time but it's treacherous>
|
||||
|
||||
***/
|
||||
|
||||
|
@ -65,56 +66,6 @@ int link_shader(GLuint program)
|
|||
return 0;
|
||||
}
|
||||
|
||||
SDL_Surface* get_screen_surface(SDL_Window *window)
|
||||
{
|
||||
int w, h;
|
||||
SDL_GetWindowSize(window, &w, &h);
|
||||
unsigned char* pixels = new unsigned char[24 * w * h];
|
||||
GLenum format;
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
format = GL_RGB;
|
||||
#else
|
||||
format = GL_BGR;
|
||||
#endif
|
||||
glReadPixels(0, 0, w, h, format, GL_UNSIGNED_BYTE, pixels);
|
||||
SDL_Surface *surface = zoomSurface(
|
||||
SDL_CreateRGBSurfaceFrom(pixels, w, h, 24, 3 * w,
|
||||
0, 0, 0, 0), 1, -1, SMOOTHING_OFF);
|
||||
delete[] pixels;
|
||||
return surface;
|
||||
}
|
||||
|
||||
void capture_screen(SDL_Window *window)
|
||||
{
|
||||
SDL_Surface *surface = get_screen_surface(window);
|
||||
IMG_SavePNG(surface, "screen.png");
|
||||
printf("saved png to screen.png\n");
|
||||
SDL_FreeSurface(surface);
|
||||
}
|
||||
|
||||
void start_recording(bool *is_recording)
|
||||
{
|
||||
*is_recording = true;
|
||||
printf("start recording\n");
|
||||
}
|
||||
|
||||
void end_recording(std::list<SDL_Surface*> frames, bool *is_recording)
|
||||
{
|
||||
*is_recording = false;
|
||||
printf("end recording\n");
|
||||
SDL_Surface *frame;
|
||||
int ii = 0;
|
||||
while (not frames.empty())
|
||||
{
|
||||
frame = frames.front();
|
||||
char path[22];
|
||||
sprintf(path, "frames/%03i.png", ii++);
|
||||
IMG_SavePNG(frame, path);
|
||||
frames.pop_front();
|
||||
SDL_FreeSurface(frame);
|
||||
}
|
||||
}
|
||||
|
||||
GLuint get_gl_texture_from_surface(SDL_Surface *surface, GLint mipmap_filter)
|
||||
{
|
||||
GLuint id;
|
||||
|
@ -162,12 +113,9 @@ struct Demo : Game
|
|||
{
|
||||
|
||||
SDL_Texture *grass_texture;
|
||||
int recording_capture_framerate = 100, frame_time_overflow = 0,
|
||||
capture_time_overflow = 0, frame_count = 0, frame_count_timestamp,
|
||||
last_capture_timestamp;
|
||||
std::list<SDL_Surface*> frames;
|
||||
bool is_recording = false, right_active = false, down_active = false,
|
||||
left_active = false, up_active = false;
|
||||
int frame_count = 0, frame_count_timestamp;
|
||||
bool right_active = false, down_active = false, left_active = false,
|
||||
up_active = false;
|
||||
SDL_Event event;
|
||||
GLuint vbo, space_texture_id, mvp_id, framerate_texture_id, flat_program,
|
||||
world_program, fake_texture_id;
|
||||
|
@ -341,7 +289,7 @@ struct Demo : Game
|
|||
glBindTexture(GL_TEXTURE_2D, space_texture_id);
|
||||
glUniform1i(sampler_uniform_id, 0);
|
||||
glDepthFunc(GL_LESS);
|
||||
frame_count_timestamp = last_capture_timestamp = SDL_GetTicks();
|
||||
frame_count_timestamp = SDL_GetTicks();
|
||||
framerate_texture_id = get_gl_texture_from_surface(
|
||||
get_framerate_indicator_surface(frame_count), GL_LINEAR);
|
||||
}
|
||||
|
@ -367,18 +315,7 @@ struct Demo : Game
|
|||
// {
|
||||
// if (event.type == SDL_KEYDOWN)
|
||||
// {
|
||||
// if (event.key.keysym.sym == SDLK_F10)
|
||||
// {
|
||||
// if (not is_recording)
|
||||
// {
|
||||
// start_recording(&is_recording);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// end_recording(frames, &is_recording);
|
||||
// }
|
||||
// }
|
||||
// else if (event.key.keysym.sym == SDLK_F11)
|
||||
// if (event.key.keysym.sym == SDLK_F11)
|
||||
// {
|
||||
// if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN)
|
||||
// {
|
||||
|
@ -441,20 +378,6 @@ struct Demo : Game
|
|||
// }
|
||||
// }
|
||||
// }
|
||||
if (is_recording and ticks - last_capture_timestamp + capture_time_overflow >
|
||||
recording_capture_framerate)
|
||||
{
|
||||
frames.push_back(get_screen_surface(window));
|
||||
printf("added frame at %i\n", ticks);
|
||||
capture_time_overflow = ticks - last_capture_timestamp + capture_time_overflow -
|
||||
recording_capture_framerate;
|
||||
last_capture_timestamp = ticks;
|
||||
for (int ii = 1; capture_time_overflow > recording_capture_framerate;
|
||||
ii++, capture_time_overflow -= recording_capture_framerate)
|
||||
{
|
||||
fprintf(stderr, "lost %i frame(s) during capture\n", ii);
|
||||
}
|
||||
}
|
||||
if (is_gl_context)
|
||||
{
|
||||
// glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
|
||||
|
|
|
@ -36,18 +36,21 @@ $(SDLGFX2_DIR)%.o: $(SDLGFX2_DIR)%.c $(SDLGFX2_DIR)%.h
|
|||
$(GLEW_DIR)%.o: $(GLEW_DIR)%.c $(GLEW_DIR)%.h
|
||||
$(CC_LINUX) $(CFLAGS) $< -o $@
|
||||
|
||||
$(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 Display.*pp Recorder.*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)Sprite.o: $(addprefix $(SFW_SRC_DIR),Game.*pp Location.*pp Node.*pp)
|
||||
$(SFW_SRC_DIR)Game.o: $(addprefix $(SFW_SRC_DIR),Sprite.*pp Configuration.*pp Delegate.*pp Display.*pp \
|
||||
Recorder.*pp Node.*pp)
|
||||
$(SFW_SRC_DIR)Node.o: $(addprefix $(SFW_SRC_DIR),Game.*pp Configuration.*pp Node.*pp)
|
||||
$(SFW_SRC_DIR)Animation.o: $(addprefix $(SFW_SRC_DIR),Timer.*pp)
|
||||
$(SFW_SRC_DIR)Recorder.o: $(addprefix $(SFW_SRC_DIR),extension.*pp Node.*pp)
|
||||
$(SFW_SRC_DIR)%.o: $(addprefix $(SFW_SRC_DIR),%.cpp %.hpp)
|
||||
$(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 Recorder.*pp)
|
||||
Demo.o: Demo.cpp Demo.hpp $(addprefix $(SFW_SRC_DIR),Sprite.*pp Node.*pp Game.*pp Location.*pp Input.*pp \
|
||||
Recorder.*pp Timer.*pp Animation.*pp extension.*pp)
|
||||
$(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 \
|
||||
Display.o Recorder.o extension.o) \
|
||||
Display.o Recorder.o Timer.o Animation.o extension.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
|
||||
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
},
|
||||
"path":
|
||||
{
|
||||
"screenshots": "local/screenshots"
|
||||
"screenshots": "local/screenshots",
|
||||
"video": "local/video"
|
||||
},
|
||||
"gamepad":
|
||||
{
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
#include "Animation.hpp"
|
||||
|
||||
void Animation::play(int delay, bool play_once)
|
||||
{
|
||||
this->delay = delay;
|
||||
playing = true;
|
||||
paused = false;
|
||||
previous_step_time = timer.elapsed;
|
||||
overflow = 0;
|
||||
count = 0;
|
||||
ending = play_once;
|
||||
if (delay <= 0)
|
||||
{
|
||||
timer.toggle(true);
|
||||
}
|
||||
}
|
||||
|
||||
void Animation::play_once(int delay)
|
||||
{
|
||||
play(delay, true);
|
||||
}
|
||||
|
||||
void Animation::pause()
|
||||
{
|
||||
timer.toggle(false);
|
||||
paused = true;
|
||||
}
|
||||
|
||||
void Animation::unpause()
|
||||
{
|
||||
timer.toggle(true);
|
||||
paused = false;
|
||||
}
|
||||
|
||||
void Animation::reset()
|
||||
{
|
||||
timer.toggle(false);
|
||||
playing = false;
|
||||
timer.reset();
|
||||
}
|
||||
|
||||
void Animation::update()
|
||||
{
|
||||
timer.update();
|
||||
if (playing and not paused)
|
||||
{
|
||||
if (delay > 0)
|
||||
{
|
||||
delay -= timer.frame_duration;
|
||||
if (delay <= 0)
|
||||
{
|
||||
timer.toggle(true);
|
||||
}
|
||||
}
|
||||
if (delay <= 0)
|
||||
{
|
||||
if (timer.elapsed - previous_step_time + overflow > framerate)
|
||||
{
|
||||
overflow = timer.elapsed - previous_step_time + overflow - framerate;
|
||||
previous_step_time = timer.elapsed;
|
||||
step();
|
||||
count++;
|
||||
if (ending)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef Animation_h_
|
||||
#define Animation_h_
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
|
||||
#include "Timer.hpp"
|
||||
|
||||
typedef std::function<void()> callback;
|
||||
|
||||
struct Animation
|
||||
{
|
||||
|
||||
bool playing = false, ending = false, paused = false;
|
||||
int previous_step_time = 0, delay = 0, overflow = 0, count = 0, framerate;
|
||||
callback step;
|
||||
Timer timer = Timer();
|
||||
|
||||
template<typename T>
|
||||
Animation(void(T::*f)(), T* o, int framerate = 0) : framerate(framerate)
|
||||
{
|
||||
step = std::bind(f, o);
|
||||
timer.toggle(false);
|
||||
}
|
||||
|
||||
void play(int = 0, bool = false);
|
||||
void play_once(int = 0);
|
||||
void pause();
|
||||
void unpause();
|
||||
void reset();
|
||||
void update();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -15,20 +15,24 @@ void Configuration::set_defaults()
|
|||
sys_config["keys"] = {
|
||||
{"record", {"CTRL", "SHIFT", "f10"}},
|
||||
{"screenshot", "f9"},
|
||||
{"action", " "},
|
||||
{"action", "space"},
|
||||
{"up", "up"},
|
||||
{"right", "right"},
|
||||
{"down", "down"},
|
||||
{"left", "left"}
|
||||
{"left", "left"},
|
||||
{"pause", "enter"},
|
||||
{"fullscreen", {"ALT", "enter"}}
|
||||
};
|
||||
sys_config["path"] = {
|
||||
{"screenshots", "."}
|
||||
{"screenshots", "."},
|
||||
{"video", "."}
|
||||
};
|
||||
sys_config["display"] = {
|
||||
{"dimensions", {640, 480}},
|
||||
{"screenshot-prefix", "screenshot-"},
|
||||
{"screenshot-extension", ".png"},
|
||||
{"screenshot-zfill", 5}
|
||||
{"screenshot-zfill", 5},
|
||||
{"recording-framerate", 100}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -9,3 +9,27 @@ glm::ivec2 Display::get_window_size()
|
|||
SDL_GetWindowSize(get_root()->window, &size.x, &size.y);
|
||||
return size;
|
||||
}
|
||||
|
||||
void Display::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);
|
||||
}
|
||||
|
||||
SDL_Surface* Display::get_screen_surface()
|
||||
{
|
||||
glm::ivec2 size = get_window_size();
|
||||
unsigned char* pixels = new unsigned char[bpp / 8 * size.x * size.y];
|
||||
get_screen_pixels(pixels, size.x, size.y);
|
||||
SDL_Surface* surface = SDL_CreateRGBSurfaceFrom(
|
||||
pixels, size.x, size.y, bpp, bpp / 8 * size.x, 0, 0, 0, 0);
|
||||
SDL_Surface* zoomed_surface = zoomSurface(surface, 1, -1, SMOOTHING_OFF);
|
||||
SDL_FreeSurface(surface);
|
||||
delete[] pixels;
|
||||
return zoomed_surface;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,14 @@
|
|||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include "glm/vec2.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 "SDL.h"
|
||||
|
||||
#include "Node.hpp"
|
||||
|
@ -11,8 +19,12 @@
|
|||
struct Display : Node
|
||||
{
|
||||
|
||||
const static int bpp = 24;
|
||||
|
||||
Display(Node*);
|
||||
glm::ivec2 get_window_size();
|
||||
SDL_Surface* get_screen_surface();
|
||||
void get_screen_pixels(unsigned char*, int, int, int = 0, int = 0);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -130,6 +130,7 @@ void Game::run()
|
|||
last_frame_length = ticks - last_frame_timestamp;
|
||||
frame_time_overflow = last_frame_length + frame_time_overflow - frame_length;
|
||||
last_frame_timestamp = ticks;
|
||||
recorder->update();
|
||||
delegate->dispatch();
|
||||
update();
|
||||
}
|
||||
|
|
|
@ -40,7 +40,9 @@ struct Input : Node
|
|||
{"f9", SDLK_F9},
|
||||
{"f10", SDLK_F10},
|
||||
{"f11", SDLK_F11},
|
||||
{"f12", SDLK_F11}
|
||||
{"f12", SDLK_F11},
|
||||
{"enter", SDLK_RETURN},
|
||||
{"space", SDLK_SPACE}
|
||||
};
|
||||
std::vector<KeyCombination> key_map;
|
||||
|
||||
|
|
20
src/Node.cpp
20
src/Node.cpp
|
@ -15,16 +15,6 @@ nlohmann::json& Node::get_configuration()
|
|||
return get_root()->configuration->config;
|
||||
}
|
||||
|
||||
Delegate* Node::get_delegate()
|
||||
{
|
||||
return get_root()->delegate;
|
||||
}
|
||||
|
||||
Display* Node::get_display()
|
||||
{
|
||||
return get_root()->display;
|
||||
}
|
||||
|
||||
Game* Node::get_root()
|
||||
{
|
||||
Node *current = this;
|
||||
|
@ -35,6 +25,16 @@ Game* Node::get_root()
|
|||
return static_cast<Game*>(current);
|
||||
}
|
||||
|
||||
Delegate* Node::get_delegate()
|
||||
{
|
||||
return get_root()->delegate;
|
||||
}
|
||||
|
||||
Display* Node::get_display()
|
||||
{
|
||||
return get_root()->display;
|
||||
}
|
||||
|
||||
void Node::print_branch()
|
||||
{
|
||||
Node *current = this;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
struct Game;
|
||||
struct Delegate;
|
||||
struct Display;
|
||||
struct TimeFilter;
|
||||
|
||||
struct Node
|
||||
{
|
||||
|
|
|
@ -11,65 +11,71 @@ void Recorder::respond(SDL_Event& event)
|
|||
{
|
||||
capture_screen();
|
||||
}
|
||||
else if (get_delegate()->compare(event, "record"))
|
||||
{
|
||||
if (animation.playing)
|
||||
{
|
||||
end_recording();
|
||||
}
|
||||
else
|
||||
{
|
||||
start_recording();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Recorder::capture_screen()
|
||||
{
|
||||
nlohmann::json config = get_configuration();
|
||||
SDL_Surface* surface = get_screen_surface();
|
||||
SDL_Surface* surface = get_display()->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));
|
||||
fs::path path = sfw::get_next_file_name(directory, zfill, prefix, extension);
|
||||
IMG_SavePNG(surface, path.c_str());
|
||||
std::cout << "screenshot saved to " << path.string() << std::endl;
|
||||
SDL_FreeSurface(surface);
|
||||
std::cout << "Saved screenshot to " << path.string() << std::endl;
|
||||
}
|
||||
|
||||
SDL_Surface* Recorder::get_screen_surface()
|
||||
void Recorder::start_recording()
|
||||
{
|
||||
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;
|
||||
std::cout << "Starting recording..." << std::endl;
|
||||
animation.play();
|
||||
}
|
||||
|
||||
void Recorder::get_screen_pixels(unsigned char* pixels, int w, int h, int x, int y)
|
||||
void Recorder::add_frame_to_video()
|
||||
{
|
||||
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);
|
||||
frames.push_back(get_display()->get_screen_surface());
|
||||
}
|
||||
|
||||
void Recorder::end_recording()
|
||||
{
|
||||
std::cout << "Ending recording..." << std::endl;
|
||||
animation.reset();
|
||||
SDL_Surface* frame;
|
||||
nlohmann::json config = get_configuration();
|
||||
fs::path root = config["path"]["video"];
|
||||
fs::create_directories(root);
|
||||
fs::path directory = sfw::get_next_file_name(root, 5, "video-");
|
||||
fs::create_directories(directory);
|
||||
std::cout << "Writing recording to " << directory << "..." << std::endl;
|
||||
for (int ii = 0; not frames.empty(); ii++)
|
||||
{
|
||||
frame = frames.front();
|
||||
std::stringstream name;
|
||||
name << sfw::pad(ii, 5) << ".png";
|
||||
fs::path path = directory / name.str();
|
||||
IMG_SavePNG(frame, path.string().c_str());
|
||||
frames.erase(frames.begin());
|
||||
SDL_FreeSurface(frame);
|
||||
}
|
||||
}
|
||||
|
||||
void Recorder::update()
|
||||
{
|
||||
animation.update();
|
||||
}
|
||||
|
|
|
@ -9,18 +9,10 @@
|
|||
#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 "Animation.hpp"
|
||||
#include "Delegate.hpp"
|
||||
#include "Display.hpp"
|
||||
#include "extension.hpp"
|
||||
|
@ -28,11 +20,17 @@
|
|||
struct Recorder : Node
|
||||
{
|
||||
|
||||
std::vector<SDL_Surface*> frames;
|
||||
Animation animation = Animation(&Recorder::add_frame_to_video, this, 100);
|
||||
|
||||
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);
|
||||
void start_recording();
|
||||
void add_frame_to_video();
|
||||
void end_recording();
|
||||
void update();
|
||||
std::string get_class_name() { return "Recorder"; }
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
#include "Timer.hpp"
|
||||
|
||||
Timer::Timer()
|
||||
{
|
||||
ticks = SDL_GetTicks();
|
||||
ticks_previous = ticks;
|
||||
}
|
||||
|
||||
void Timer::toggle()
|
||||
{
|
||||
is_timing = not is_timing;
|
||||
}
|
||||
|
||||
void Timer::toggle(bool state)
|
||||
{
|
||||
is_timing = state;
|
||||
}
|
||||
|
||||
void Timer::reset()
|
||||
{
|
||||
elapsed = 0;
|
||||
}
|
||||
|
||||
void Timer::update()
|
||||
{
|
||||
ticks = SDL_GetTicks();
|
||||
frame_duration = ticks - ticks_previous;
|
||||
if (is_timing)
|
||||
{
|
||||
elapsed += frame_duration;
|
||||
}
|
||||
ticks_previous = ticks;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef Timer_h_
|
||||
#define Timer_h_
|
||||
|
||||
#include "SDL.h"
|
||||
|
||||
struct Timer
|
||||
{
|
||||
|
||||
int ticks, ticks_previous, frame_duration = 0, elapsed = 0;
|
||||
bool is_timing = true;
|
||||
|
||||
Timer();
|
||||
|
||||
void toggle();
|
||||
void toggle(bool);
|
||||
void reset();
|
||||
void update();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -9,7 +9,6 @@ std::vector<fs::path> sfw::glob(fs::path query)
|
|||
}
|
||||
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))
|
||||
|
@ -20,3 +19,31 @@ std::vector<fs::path> sfw::glob(fs::path query)
|
|||
std::sort(files.begin(), files.end());
|
||||
return files;
|
||||
}
|
||||
|
||||
fs::path sfw::get_next_file_name(
|
||||
fs::path directory, int zfill, std::string prefix, std::string extension)
|
||||
{
|
||||
std::stringstream file_pattern;
|
||||
file_pattern << prefix << "([0-9]+)" << extension;
|
||||
fs::path query = directory / file_pattern.str();
|
||||
std::vector<fs::path> files = sfw::glob(query);
|
||||
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));
|
||||
return path;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
namespace sfw
|
||||
{
|
||||
std::vector<fs::path> glob(fs::path);
|
||||
fs::path get_next_file_name(
|
||||
fs::path, int = 0, std::string = "", std::string = "");
|
||||
|
||||
template<typename T>
|
||||
std::string pad(T end, int width, char fill = '0')
|
||||
|
|
Loading…
Reference in New Issue