- store video stashes in linked lists

- cube face textures demo
- only dispatch events to active nodes
- only update animation if containing object is active
This commit is contained in:
Frank DeMarco 2019-07-21 03:13:19 -04:00
parent d7f1877cbe
commit b2f5f56063
16 changed files with 316 additions and 211 deletions

View File

@ -1,9 +1,10 @@
/***
reset, pause, auto reset, analog d-pad, gamepad config, any key, confirm exit
game, screen wipes, screen offset, screen scale, networking
game, screen wipes, screen offset, screen scale, networking, post processing
:) SWEATY HANDS :) OILY SNACKS :) AND BAD HYGIENE :)
*surf wizard*
*Exxiit* eXIt
***/
@ -73,9 +74,9 @@ GLuint get_gl_texture_from_surface(SDL_Surface *surface, GLint mipmap_filter)
glBindTexture(GL_TEXTURE_2D, id);
GLenum format;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
format = GL_RGBA;
#else
format = GL_BGRA;
#else
format = GL_RGBA;
#endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surface->w, surface->h, 0, format,
GL_UNSIGNED_BYTE, surface->pixels);
@ -142,7 +143,8 @@ void Mushroom::update()
Demo::Demo()
{
Mix_Music *music = Mix_LoadMUS("resource/Field.mp3");
// Mix_Music *music = Mix_LoadMUS("resource/Field.mp3");
Mix_Music *music = Mix_LoadMUS("/home/frank/WATERMELON-clean.mp3");
Mix_PlayMusic(music, -1);
load_gl_context();
delegate.subscribe(&Demo::respond, this);
@ -219,10 +221,19 @@ void Demo::load_gl_context()
100.0f);
view = glm::lookAt(
glm::vec3(4, 3, 3), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
SDL_Surface *surface = rotateSurface90Degrees(IMG_Load("resource/tile.png"), 2);
SDL_Surface* surface = zoomSurface(
rotateSurface90Degrees(IMG_Load("resource/tile.png"), 2), 1, -1, SMOOTHING_OFF);
SDL_Log("tile.png bytes per pixel %i", surface->format->BytesPerPixel);
space_texture_id = get_gl_texture_from_surface(surface, GL_LINEAR);
SDL_FreeSurface(surface);
std::vector<fs::path> paths = sfw::glob("/home/frank/projects/public/games/rov/face03/[0-9]+\\-.+\\.png");
for (fs::path path : paths)
{
surface = zoomSurface(rotateSurface90Degrees(IMG_Load(path.c_str()), 2), -1, 1, SMOOTHING_OFF);
SDL_Log("loading %s", path.c_str());
face_ids.push_back(get_gl_texture_from_surface(surface, GL_LINEAR));
SDL_FreeSurface(surface);
}
std::array<glm::vec2, 6> framerate_indicator_uv = {
{
{0, 1}, {1, 1}, {0, 0},
@ -296,8 +307,8 @@ void Demo::load_gl_context()
link_shader(flat_program);
mvp_id = glGetUniformLocation(world_program, "MVP");
// GLuint sampler_uniform_id = glGetUniformLocation(world_program, "myTextureSampler");
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, space_texture_id);
// glActiveTexture(GL_TEXTURE0);
// glBindTexture(GL_TEXTURE_2D, space_texture_id);
// glUniform1i(sampler_uniform_id, 0);
glDepthFunc(GL_LESS);
frame_count_timestamp = SDL_GetTicks();
@ -399,7 +410,9 @@ void Demo::update()
{
// glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
// glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), diamond, GL_STATIC_DRAW);
glClearColor(.7, .7, .5, 1);
// glColorMask(false, false, false, true);
// glClearColor(.7, .7, .5, 1);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glUseProgram(flat_program);
@ -417,18 +430,27 @@ void Demo::update()
glDrawArrays(GL_TRIANGLES, 42, 6);
}
// printf("%s\n", glm::to_string(model).c_str());
model = glm::rotate(model, .0005f * frame_length, glm::vec3(0.0f, 1.0f, 0.0f));
float rotation = .0005f * frame_length;
model = glm::rotate(model, rotation, glm::vec3(0.0f, 1.0f, 0.0f));
mvp = projection * view * model;
glEnable(GL_DEPTH_TEST);
glUseProgram(world_program);
glUniformMatrix4fv(mvp_id, 1, GL_FALSE, &mvp[0][0]);
glBindTexture(GL_TEXTURE_2D, space_texture_id);
glEnableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glVertexAttrib3f(2, 1, 1, 1);
glDrawArrays(GL_TRIANGLES, 0, 36);
for (int ii = 0; ii < 6; ii++)
{
glBindTexture(GL_TEXTURE_2D, face_ids[ii]);
glDrawArrays(GL_TRIANGLES, ii * 6, 6);
}
//glFlush();
SDL_GL_SwapWindow(window);
// if (amount_rotated < 3.14f * 2)
// {
// recorder.capture_screen();
// }
amount_rotated += rotation;
}
else
{

View File

@ -63,6 +63,8 @@ struct Demo : Game
glm::mat4 projection, view, model = glm::mat4(1.0f), mvp;
Mushroom mushroom = Mushroom(this);
Sprite grass = Sprite(this, "resource/Field.png");
std::vector<GLuint> face_ids;
float amount_rotated;
Demo();
void load_sdl_context();

View File

@ -40,8 +40,8 @@ $(SFW_SRC_DIR)Sprite.o: $(addprefix $(SFW_SRC_DIR),Game.*pp Location.*pp Node.*p
$(SFW_SRC_DIR)Game.o: $(addprefix $(SFW_SRC_DIR),Sprite.*pp Configuration.*pp Delegate.*pp Display.*pp \
Recorder.*pp Node.*pp Input.*pp)
$(SFW_SRC_DIR)Node.o: $(addprefix $(SFW_SRC_DIR),Game.*pp Configuration.*pp Delegate.*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 Delegate.*pp Animation.*pp)
$(SFW_SRC_DIR)Animation.o: $(addprefix $(SFW_SRC_DIR),Node.*pp Timer.*pp)
$(SFW_SRC_DIR)Recorder.o: $(addprefix $(SFW_SRC_DIR),extension.*pp Node.*pp Delegate.*pp Animation.*pp Display.*pp)
$(SFW_SRC_DIR)Input.o: $(addprefix $(SFW_SRC_DIR),Delegate.*pp Node.*pp)
$(SFW_SRC_DIR)Configuration.o: $(addprefix $(SFW_SRC_DIR),Node.*pp)
$(SFW_SRC_DIR)Delegate.o: $(addprefix $(SFW_SRC_DIR),Node.*pp)

View File

@ -20,7 +20,9 @@
},
"recording":
{
"enabled": true,
"write-mp4": true,
"video-frame-length": 33.334
"video-frame-length": 16.667,
"max-video-memory": 2000
}
}

View File

@ -47,7 +47,7 @@ void Animation::reset()
void Animation::update()
{
timer.update();
if (playing and not paused)
if (playing and not paused and containing_object->is_active())
{
if (delay > 0)
{

View File

@ -5,6 +5,7 @@
#include <functional>
#include <algorithm>
#include "Node.hpp"
#include "Timer.hpp"
typedef std::function<void()> callback;
@ -16,6 +17,7 @@ struct Animation
int previous_step_time = 0, overflow = 0, count = 0;
float delay = 0, frame_length;
callback step;
Node* containing_object;
Timer timer = Timer();
template<typename T>
@ -23,6 +25,7 @@ struct Animation
{
step = std::bind(f, o);
timer.toggle(false);
containing_object = static_cast<Node*>(o);
}
void set_frame_length(float);

View File

@ -34,6 +34,7 @@ void Configuration::set_defaults()
{"fps", 60}
};
sys_config["recording"] = {
{"enabled", false},
{"screenshot-prefix", "screenshot-"},
{"screenshot-extension", ".png"},
{"screenshot-zfill", 5},

View File

@ -24,7 +24,10 @@ void Delegate::dispatch()
{
for (Subscriber s : iter->second)
{
s.f(event);
if (s.o->is_active())
{
s.f(event);
}
}
}
}

View File

@ -15,7 +15,7 @@
struct Subscriber
{
std::function<void(SDL_Event&)> f;
void* o;
Node* o;
};
struct Delegate : Node
@ -34,7 +34,7 @@ struct Delegate : Node
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), o}, type);
add_subscriber({std::bind(f, o, std::placeholders::_1), static_cast<Node*>(o)}, type);
}
template<typename T>

View File

@ -16,19 +16,25 @@ void Display::get_screen_pixels(unsigned char* pixels, int w, int h, int x, int
{
GLenum format;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
format = GL_RGBA;
#else
format = GL_BGRA;
#else
format = GL_RGBA;
#endif
glReadBuffer(GL_FRONT);
glReadPixels(x, y, w, h, format, GL_UNSIGNED_BYTE, pixels);
// SDL_Log("(%i, %i, %i) (%i, %i, %i, %i)",
// glCheckFramebufferStatus(GL_FRAMEBUFFER),
// glCheckFramebufferStatus(GL_READ_FRAMEBUFFER),
// glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER),
// pixels[0], pixels[1], pixels[2], pixels[3]);
}
else
{
Uint32 format;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
format = SDL_PIXELFORMAT_ABGR8888;
#else
format = SDL_PIXELFORMAT_ARGB8888;
#else
format = SDL_PIXELFORMAT_ABGR8888;
#endif
SDL_RenderReadPixels(
get_root()->renderer, NULL, format, pixels, bpp / 8 * w);
@ -51,16 +57,28 @@ SDL_Surface* Display::get_screen_surface_from_pixels(
{
glm::ivec2 size = get_window_size();
SDL_Surface* surface;
Uint32 rmask, gmask, bmask, amask;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
rmask = 0xff000000;
gmask = 0x00ff0000;
bmask = 0x0000ff00;
amask = 0x000000ff;
#else
rmask = 0x000000ff;
gmask = 0x0000ff00;
bmask = 0x00ff0000;
amask = 0xff000000;
#endif
if (flip)
{
SDL_Surface* pixel_surface = SDL_CreateRGBSurfaceFrom(
pixels, size.x, size.y, bpp, bpp / 8 * size.x, 0, 0, 0, 0);
pixels, size.x, size.y, bpp, bpp / 8 * size.x, rmask, gmask, bmask, amask);
surface = zoomSurface(pixel_surface, 1, -1, SMOOTHING_OFF);
SDL_FreeSurface(pixel_surface);
}
else
{
surface = SDL_CreateRGBSurface(0, size.x, size.y, bpp, 0, 0, 0, 0);
surface = SDL_CreateRGBSurface(0, size.x, size.y, bpp, rmask, gmask, bmask, amask);
std::memcpy(surface->pixels, pixels, bpp / 8 * size.x * size.y);
}
return surface;

View File

@ -13,7 +13,7 @@ Game::Game()
delegate.subscribe(&Game::handle_quit_event, this, SDL_QUIT);
SDL_Log("GLEW %s", glewGetString(GLEW_VERSION));
putenv("SDL_VIDEO_X11_LEGACY_FULLSCREEN=0");
putenv("SDL_VIDEO_CENTERED=0");
// putenv("SDL_VIDEO_CENTERED=0");
SDL_version version;
SDL_GetVersion(&version);
SDL_Log("SDL %d.%d.%d", version.major, version.minor, version.patch);
@ -31,9 +31,14 @@ Game::Game()
// SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
print_gl_attributes();
std::vector<int> window_size = get_configuration()["display"]["dimensions"];
window = SDL_CreateWindow("TARE control", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
window = SDL_CreateWindow("TARE control", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
window_size[0], window_size[1], SDL_WINDOW_OPENGL);
if (window == NULL)
{
@ -74,9 +79,9 @@ Game::Game()
SDL_GetAudioDeviceName(ii, SDL_TRUE));
}
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
SDL_Log("big endian, using GL_RGBA and SDL_PIXELFORMAT_ABGR8888");
SDL_Log("big endian");
#else
SDL_Log("little endian, using GL_BGRA and SDL_PIXELFORMAT_ARGB8888");
SDL_Log("little endian");
#endif
last_frame_timestamp = SDL_GetTicks();
}
@ -133,6 +138,7 @@ void Game::load_sdl_context()
info.max_texture_height);
}
is_gl_context = false;
log_display_mode();
}
void Game::load_gl_context()
@ -162,6 +168,7 @@ void Game::load_gl_context()
glGetString(GL_VERSION), glGetString(GL_RENDERER),
glGetString(GL_SHADING_LANGUAGE_VERSION));
is_gl_context = true;
log_display_mode();
}
GLuint Game::create_gl_texture()
@ -172,7 +179,7 @@ GLuint Game::create_gl_texture()
return id;
}
bool Game::log_gl_errors()
bool Game::log_gl_errors(std::string suffix)
{
GLenum error;
bool error_logged = false;
@ -184,186 +191,213 @@ bool Game::log_gl_errors()
SDL_LogError(
SDL_LOG_CATEGORY_APPLICATION,
"GL_INVALID_ENUM, an unacceptable value is specified for an "
"enumerated argument");
"enumerated argument %s", suffix.c_str());
}
else if (error == GL_INVALID_VALUE)
{
SDL_LogError(
SDL_LOG_CATEGORY_APPLICATION,
"GL_INVALID_VALUE, a numeric argument is out of range");
"GL_INVALID_VALUE, a numeric argument is out of range %s", suffix.c_str());
}
else if (error == GL_INVALID_OPERATION)
{
SDL_LogError(
SDL_LOG_CATEGORY_APPLICATION,
"GL_INVALID_OPERATION, the specified operation is not allowed "
"in the current state");
"in the current state %s", suffix.c_str());
}
else if (error == GL_INVALID_FRAMEBUFFER_OPERATION)
{
SDL_LogError(
SDL_LOG_CATEGORY_APPLICATION,
"GL_INVALID_FRAMEBUFFER_OPERATION, the framebuffer object is "
"not complete");
"not complete %s", suffix.c_str());
}
else if (error == GL_OUT_OF_MEMORY)
{
SDL_LogError(
SDL_LOG_CATEGORY_APPLICATION,
"GL_OUT_OF_MEMORY, there is not enough memory left to execute "
"the command");
"the command %s", suffix.c_str());
}
else if (error == GL_STACK_UNDERFLOW)
{
SDL_LogError(
SDL_LOG_CATEGORY_APPLICATION,
"GL_STACK_UNDERFLOW, an attempt has been made to perform an "
"operation that would cause an internal stack to underflow.");
"operation that would cause an internal stack to underflow. %s", suffix.c_str());
}
else if (error == GL_STACK_OVERFLOW)
{
SDL_LogError(
SDL_LOG_CATEGORY_APPLICATION,
"GL_STACK_OVERFLOW, an attempt has been made to perform an "
"operation that would cause an internal stack to overflow.");
"operation that would cause an internal stack to overflow. %s", suffix.c_str());
}
}
return error_logged;
}
// from SDL_GetCurrentDisplayMode.html
void Game::log_display_mode()
{
SDL_DisplayMode current;
for (int ii = 0; ii < SDL_GetNumVideoDisplays(); ii++)
{
int mode = SDL_GetCurrentDisplayMode(ii, &current);
if (mode != 0)
{
SDL_Log("Could not get display mode for video display #%d: %s", ii,
SDL_GetError());
}
else
{
SDL_Log("Display #%d: display mode is %dx%dpx @ %dhz %s", ii,
current.w, current.h, current.refresh_rate,
get_pixel_format_string(current.format).c_str());
}
}
}
void Game::log_surface_format(SDL_Surface* surface, std::string preface)
{
SDL_PixelFormat* format = surface->format;
std::string pixel_format;
if (format->format == SDL_PIXELFORMAT_UNKNOWN)
{
pixel_format = "SDL_PIXELFORMAT_UNKNOWN";
}
else if (format->format == SDL_PIXELFORMAT_INDEX1LSB)
{
pixel_format = "SDL_PIXELFORMAT_INDEX1LSB";
}
else if (format->format == SDL_PIXELFORMAT_INDEX1MSB)
{
pixel_format = "SDL_PIXELFORMAT_INDEX1MSB";
}
else if (format->format == SDL_PIXELFORMAT_INDEX4LSB)
{
pixel_format = "SDL_PIXELFORMAT_INDEX4LSB";
}
else if (format->format == SDL_PIXELFORMAT_INDEX4MSB)
{
pixel_format = "SDL_PIXELFORMAT_INDEX4MSB";
}
else if (format->format == SDL_PIXELFORMAT_INDEX8)
{
pixel_format = "SDL_PIXELFORMAT_INDEX8";
}
else if (format->format == SDL_PIXELFORMAT_RGB332)
{
pixel_format = "SDL_PIXELFORMAT_RGB332";
}
else if (format->format == SDL_PIXELFORMAT_RGB444)
{
pixel_format = "SDL_PIXELFORMAT_RGB444";
}
else if (format->format == SDL_PIXELFORMAT_RGB555)
{
pixel_format = "SDL_PIXELFORMAT_RGB555";
}
else if (format->format == SDL_PIXELFORMAT_BGR555)
{
pixel_format = "SDL_PIXELFORMAT_BGR555";
}
else if (format->format == SDL_PIXELFORMAT_ARGB4444)
{
pixel_format = "SDL_PIXELFORMAT_ARGB4444";
}
else if (format->format == SDL_PIXELFORMAT_RGBA4444)
{
pixel_format = "SDL_PIXELFORMAT_RGBA4444";
}
else if (format->format == SDL_PIXELFORMAT_ABGR4444)
{
pixel_format = "SDL_PIXELFORMAT_ABGR4444";
}
else if (format->format == SDL_PIXELFORMAT_BGRA4444)
{
pixel_format = "SDL_PIXELFORMAT_BGRA4444";
}
else if (format->format == SDL_PIXELFORMAT_ARGB1555)
{
pixel_format = "SDL_PIXELFORMAT_ARGB1555";
}
else if (format->format == SDL_PIXELFORMAT_RGBA5551)
{
pixel_format = "SDL_PIXELFORMAT_RGBA5551";
}
else if (format->format == SDL_PIXELFORMAT_ABGR1555)
{
pixel_format = "SDL_PIXELFORMAT_ABGR1555";
}
else if (format->format == SDL_PIXELFORMAT_BGRA5551)
{
pixel_format = "SDL_PIXELFORMAT_BGRA5551";
}
else if (format->format == SDL_PIXELFORMAT_RGB565)
{
pixel_format = "SDL_PIXELFORMAT_RGB565";
}
else if (format->format == SDL_PIXELFORMAT_BGR565)
{
pixel_format = "SDL_PIXELFORMAT_BGR565";
}
else if (format->format == SDL_PIXELFORMAT_RGB24)
{
pixel_format = "SDL_PIXELFORMAT_RGB24";
}
else if (format->format == SDL_PIXELFORMAT_BGR24)
{
pixel_format = "SDL_PIXELFORMAT_BGR24";
}
else if (format->format == SDL_PIXELFORMAT_RGB888)
{
pixel_format = "SDL_PIXELFORMAT_RGB888";
}
else if (format->format == SDL_PIXELFORMAT_RGBX8888)
{
pixel_format = "SDL_PIXELFORMAT_RGBX8888";
}
else if (format->format == SDL_PIXELFORMAT_BGR888)
{
pixel_format = "SDL_PIXELFORMAT_BGR888";
}
else if (format->format == SDL_PIXELFORMAT_BGRX8888)
{
pixel_format = "SDL_PIXELFORMAT_BGRX8888";
}
else if (format->format == SDL_PIXELFORMAT_ARGB8888)
{
pixel_format = "SDL_PIXELFORMAT_ARGB8888";
}
else if (format->format == SDL_PIXELFORMAT_RGBA8888)
{
pixel_format = "SDL_PIXELFORMAT_RGBA8888";
}
else if (format->format == SDL_PIXELFORMAT_ABGR8888)
{
pixel_format = "SDL_PIXELFORMAT_ABGR8888";
}
else if (format->format == SDL_PIXELFORMAT_BGRA8888)
{
pixel_format = "SDL_PIXELFORMAT_BGRA8888";
}
else if (format->format == SDL_PIXELFORMAT_ARGB2101010)
{
pixel_format = "SDL_PIXELFORMAT_ARGB2101010";
}
std::string pixel_format = get_pixel_format_string(format->format);
SDL_Log("%s bpp: %i mask: %i %i %i %i format: %s", preface.c_str(),
format->BytesPerPixel, format->Rmask, format->Gmask, format->Bmask,
format->Amask, pixel_format.c_str());
}
std::string Game::get_pixel_format_string(Uint32 format)
{
std::string pixel_format;
if (format == SDL_PIXELFORMAT_UNKNOWN)
{
pixel_format = "SDL_PIXELFORMAT_UNKNOWN";
}
else if (format == SDL_PIXELFORMAT_INDEX1LSB)
{
pixel_format = "SDL_PIXELFORMAT_INDEX1LSB";
}
else if (format == SDL_PIXELFORMAT_INDEX1MSB)
{
pixel_format = "SDL_PIXELFORMAT_INDEX1MSB";
}
else if (format == SDL_PIXELFORMAT_INDEX4LSB)
{
pixel_format = "SDL_PIXELFORMAT_INDEX4LSB";
}
else if (format == SDL_PIXELFORMAT_INDEX4MSB)
{
pixel_format = "SDL_PIXELFORMAT_INDEX4MSB";
}
else if (format == SDL_PIXELFORMAT_INDEX8)
{
pixel_format = "SDL_PIXELFORMAT_INDEX8";
}
else if (format == SDL_PIXELFORMAT_RGB332)
{
pixel_format = "SDL_PIXELFORMAT_RGB332";
}
else if (format == SDL_PIXELFORMAT_RGB444)
{
pixel_format = "SDL_PIXELFORMAT_RGB444";
}
else if (format == SDL_PIXELFORMAT_RGB555)
{
pixel_format = "SDL_PIXELFORMAT_RGB555";
}
else if (format == SDL_PIXELFORMAT_BGR555)
{
pixel_format = "SDL_PIXELFORMAT_BGR555";
}
else if (format == SDL_PIXELFORMAT_ARGB4444)
{
pixel_format = "SDL_PIXELFORMAT_ARGB4444";
}
else if (format == SDL_PIXELFORMAT_RGBA4444)
{
pixel_format = "SDL_PIXELFORMAT_RGBA4444";
}
else if (format == SDL_PIXELFORMAT_ABGR4444)
{
pixel_format = "SDL_PIXELFORMAT_ABGR4444";
}
else if (format == SDL_PIXELFORMAT_BGRA4444)
{
pixel_format = "SDL_PIXELFORMAT_BGRA4444";
}
else if (format == SDL_PIXELFORMAT_ARGB1555)
{
pixel_format = "SDL_PIXELFORMAT_ARGB1555";
}
else if (format == SDL_PIXELFORMAT_RGBA5551)
{
pixel_format = "SDL_PIXELFORMAT_RGBA5551";
}
else if (format == SDL_PIXELFORMAT_ABGR1555)
{
pixel_format = "SDL_PIXELFORMAT_ABGR1555";
}
else if (format == SDL_PIXELFORMAT_BGRA5551)
{
pixel_format = "SDL_PIXELFORMAT_BGRA5551";
}
else if (format == SDL_PIXELFORMAT_RGB565)
{
pixel_format = "SDL_PIXELFORMAT_RGB565";
}
else if (format == SDL_PIXELFORMAT_BGR565)
{
pixel_format = "SDL_PIXELFORMAT_BGR565";
}
else if (format == SDL_PIXELFORMAT_RGB24)
{
pixel_format = "SDL_PIXELFORMAT_RGB24";
}
else if (format == SDL_PIXELFORMAT_BGR24)
{
pixel_format = "SDL_PIXELFORMAT_BGR24";
}
else if (format == SDL_PIXELFORMAT_RGB888)
{
pixel_format = "SDL_PIXELFORMAT_RGB888";
}
else if (format == SDL_PIXELFORMAT_RGBX8888)
{
pixel_format = "SDL_PIXELFORMAT_RGBX8888";
}
else if (format == SDL_PIXELFORMAT_BGR888)
{
pixel_format = "SDL_PIXELFORMAT_BGR888";
}
else if (format == SDL_PIXELFORMAT_BGRX8888)
{
pixel_format = "SDL_PIXELFORMAT_BGRX8888";
}
else if (format == SDL_PIXELFORMAT_ARGB8888)
{
pixel_format = "SDL_PIXELFORMAT_ARGB8888";
}
else if (format == SDL_PIXELFORMAT_RGBA8888)
{
pixel_format = "SDL_PIXELFORMAT_RGBA8888";
}
else if (format == SDL_PIXELFORMAT_ABGR8888)
{
pixel_format = "SDL_PIXELFORMAT_ABGR8888";
}
else if (format == SDL_PIXELFORMAT_BGRA8888)
{
pixel_format = "SDL_PIXELFORMAT_BGRA8888";
}
else if (format == SDL_PIXELFORMAT_ARGB2101010)
{
pixel_format = "SDL_PIXELFORMAT_ARGB2101010";
}
return pixel_format;
}
void Game::run()
{
while (not done)

View File

@ -46,7 +46,7 @@ struct Game : Node
int frame_time_overflow = 0, framerate, ticks, last_frame_timestamp,
frame_count_timestamp, last_frame_length;
float frame_length;
bool done = false, show_framerate = false, is_gl_context = true;
bool done = false, show_framerate = true, is_gl_context = true;
Configuration configuration = Configuration(this);
Delegate delegate = Delegate(this);
Display display = Display(this);
@ -61,8 +61,10 @@ struct Game : Node
void load_sdl_context();
void load_gl_context();
GLuint create_gl_texture();
bool log_gl_errors();
bool log_gl_errors(std::string);
void log_display_mode();
void log_surface_format(SDL_Surface*, std::string = "surface");
std::string get_pixel_format_string(Uint32);
void run();
void flag_to_end();
virtual void update() {};

View File

@ -32,6 +32,11 @@ void Node::deactivate()
active = false;
}
bool Node::is_active()
{
return active;
}
nlohmann::json& Node::get_configuration()
{
return get_root()->configuration.config;

View File

@ -20,10 +20,11 @@ struct Node
bool active = false;
Node();
Node(Node*, bool = false);
Node(Node*, bool = true);
virtual ~Node();
void activate();
void deactivate();
bool is_active();
Game* get_root();
nlohmann::json& get_configuration();
Delegate& get_delegate();

View File

@ -7,7 +7,10 @@ Recorder::Recorder(Node* parent) : Node(parent)
get_delegate().subscribe(&Recorder::respond, this);
animation.play();
Mix_SetPostMix(&process_audio, this);
video_stashes.reserve(100);
if (not get_configuration()["recording"]["enabled"])
{
deactivate();
}
}
float Recorder::get_frame_length()
@ -87,9 +90,7 @@ void Recorder::grab_stash()
void Recorder::write_most_recent_frames()
{
make_directory();
write_stash_frames(&most_recent_stash.pixel_buffers,
&most_recent_stash.flipped,
most_recent_stash.frame_offset);
write_stash_frames(&most_recent_stash);
open_audio_file();
while (not most_recent_stash.audio_buffers.empty())
{
@ -136,7 +137,7 @@ void Recorder::open_audio_file()
void Recorder::add_frame()
{
glm::ivec2 size = get_display().get_window_size();
int bytes = 32 / 8 * size.x * size.y;
int bytes = Display::bpp / 8 * size.x * size.y;
unsigned char* pixels = new unsigned char[bytes];
get_display().get_screen_pixels(pixels, size.x, size.y);
int max_length = get_configuration()["recording"]["max-stash-length"];
@ -157,14 +158,29 @@ void Recorder::add_frame()
video_stashes.back().flipped.push_back(get_root()->is_gl_context);
if (video_stashes.back().pixel_buffers.size() * get_frame_length() > max_length)
{
std::function<void(std::vector<unsigned char*>*, std::vector<bool>*, int)> f =
std::bind(&Recorder::write_stash_frames, this,
std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3);
std::thread writing(f, &video_stashes.back().pixel_buffers,
&video_stashes.back().flipped,
video_stashes.back().frame_offset);
std::function<void(Stash*)> f =
std::bind(&Recorder::write_stash_frames, this, std::placeholders::_1);
std::thread writing(f, &video_stashes.back());
writing.detach();
// int frame_offset = video_stashes.back().frame_offset;
// std::vector<unsigned char*> pixel_buffers = video_stashes.back().pixel_buffers;
// std::vector<bool> flipped = video_stashes.back().flipped;
// for (int ii = frame_offset; ii < pixel_buffers.size() + frame_offset; ii++)
// {
// SDL_Surface* frame = get_display().get_screen_surface_from_pixels(
// pixel_buffers[ii - frame_offset], flipped[ii - frame_offset]);
// std::stringstream name;
// name << sfw::pad(ii, 5) << ".png";
// fs::path path = current_video_directory / name.str();
// SDL_Log("%s (%i, %i) (%i, %i, %i, %i)", path.c_str(), frame->w, frame->h,
// ((unsigned char*) frame->pixels)[0], ((unsigned char*) frame->pixels)[1],
// ((unsigned char*) frame->pixels)[2], ((unsigned char*) frame->pixels)[3]);
// IMG_SavePNG(frame, path.string().c_str());
// }
// end_recording();
// write_stash_frames(video_stashes.back().pixel_buffers,
// video_stashes.back().flipped,
// video_stashes.back().frame_offset);
video_stashes.push_back(
Stash(video_stashes.back().frame_offset +
video_stashes.back().pixel_buffers.size()));
@ -212,31 +228,27 @@ void Recorder::make_directory()
current_video_directory = directory;
}
void Recorder::write_stash_frames(
std::vector<unsigned char*>* pixel_buffers, std::vector<bool>* flipped,
int frame_offset)
void Recorder::write_stash_frames(Stash* stash)
{
SDL_Log("Writing stash offset %i to %s...", frame_offset, current_video_directory.c_str());
SDL_Log("Writing stash offset %i to %s...", stash->frame_offset, current_video_directory.c_str());
SDL_Surface* frame;
GifWriter gif_writer;
int gif_frame_length = get_configuration()["recording"]["gif-frame-length"];
fs::path gif_path = sfw::get_next_file_name(
current_video_directory, 3, "gif-", ".gif");
float elapsed = 0, last_gif_write = 0, gif_write_overflow = 0;
SDL_Log("Pixel buffers size %zu", pixel_buffers->size());
for (int ii = frame_offset; not pixel_buffers->empty(); ii++)
for (int ii = stash->frame_offset; not stash->pixel_buffers.empty(); ii++)
{
frame = get_display().get_screen_surface_from_pixels(
pixel_buffers->front(), flipped->front());
get_root()->log_surface_format(frame, "got");
stash->pixel_buffers.front(), stash->flipped.front());
std::stringstream name;
name << sfw::pad(ii, 5) << ".png";
fs::path path = current_video_directory / name.str();
IMG_SavePNG(frame, path.string().c_str());
if (ii == frame_offset or
if (ii == stash->frame_offset or
elapsed - last_gif_write + gif_write_overflow >= gif_frame_length)
{
if (ii == frame_offset)
if (ii == stash->frame_offset)
{
GifBegin(&gif_writer, gif_path.string().c_str(), frame->w,
frame->h, gif_frame_length / 10);
@ -252,9 +264,9 @@ void Recorder::write_stash_frames(
frame->w, frame->h, gif_frame_length / 10);
}
elapsed += get_frame_length();
delete[] pixel_buffers->front();
pixel_buffers->erase(pixel_buffers->begin());
flipped->erase(flipped->begin());
delete[] stash->pixel_buffers.front();
stash->pixel_buffers.erase(stash->pixel_buffers.begin());
stash->flipped.erase(stash->flipped.begin());
SDL_FreeSurface(frame);
}
GifEnd(&gif_writer);
@ -291,9 +303,7 @@ void Recorder::end_recording()
void Recorder::finish_writing_video()
{
write_stash_frames(
&video_stashes.back().pixel_buffers, &video_stashes.back().flipped,
video_stashes.back().frame_offset);
write_stash_frames(&video_stashes.back());
int count;
while (true)
{
@ -352,21 +362,24 @@ void Recorder::update()
void process_audio(void* user_data, Uint8* stream, int len)
{
Recorder* recorder = static_cast<Recorder*>(user_data);
int max_length = recorder->get_configuration()["recording"]["max-stash-length"];
float length = recorder->get_frame_length() * recorder->current_stash.pixel_buffers.size();
if (length > max_length)
if (recorder->is_active())
{
delete[] recorder->current_stash.audio_buffers.front();
recorder->current_stash.audio_buffers.erase(recorder->current_stash.audio_buffers.begin());
recorder->current_stash.audio_buffer_lengths.erase(
recorder->current_stash.audio_buffer_lengths.begin());
}
Uint8* stream_copy = new Uint8[len];
std::memcpy(stream_copy, stream, len);
recorder->current_stash.audio_buffers.push_back(stream_copy);
recorder->current_stash.audio_buffer_lengths.push_back(len);
if (recorder->is_recording)
{
recorder->write_audio(stream_copy, len);
int max_length = recorder->get_configuration()["recording"]["max-stash-length"];
float length = recorder->get_frame_length() * recorder->current_stash.pixel_buffers.size();
if (length > max_length)
{
delete[] recorder->current_stash.audio_buffers.front();
recorder->current_stash.audio_buffers.erase(recorder->current_stash.audio_buffers.begin());
recorder->current_stash.audio_buffer_lengths.erase(
recorder->current_stash.audio_buffer_lengths.begin());
}
Uint8* stream_copy = new Uint8[len];
std::memcpy(stream_copy, stream, len);
recorder->current_stash.audio_buffers.push_back(stream_copy);
recorder->current_stash.audio_buffer_lengths.push_back(len);
if (recorder->is_recording)
{
recorder->write_audio(stream_copy, len);
}
}
}

View File

@ -36,8 +36,8 @@ struct Recorder : Node
Stash current_stash = Stash();
Stash most_recent_stash;
std::vector<Stash> in_game_stashes;
std::vector<Stash> video_stashes;
std::list<Stash> in_game_stashes;
std::list<Stash> video_stashes;
fs::path current_video_directory, current_audio_path;
Animation animation = Animation(&Recorder::add_frame, this);
bool is_recording = false, writing_recording = false, writing_most_recent = false;
@ -54,8 +54,7 @@ struct Recorder : Node
void add_frame();
int get_memory_size();
void make_directory();
void write_stash_frames(
std::vector<unsigned char*>*, std::vector<bool>*, int);
void write_stash_frames(Stash*);
void keep_stash();
void end_recording();
void finish_writing_video();