diff --git a/demo/Demo.cpp b/demo/Demo.cpp index 0e54658..d4d17f7 100644 --- a/demo/Demo.cpp +++ b/demo/Demo.cpp @@ -86,45 +86,51 @@ GLuint get_gl_texture_from_surface(SDL_Surface *surface, GLint mipmap_filter) SDL_Surface* get_framerate_indicator_surface(int frame_count) { - TTF_Font *font = TTF_OpenFont("resource/SourceCodePro-Regular.otf", 14); - SDL_Surface *shaded = TTF_RenderText_Shaded( - font, std::to_string(frame_count).c_str(), {0, 0, 0}, {255, 255, 255}); - SDL_Surface *converted = SDL_ConvertSurfaceFormat(shaded, SDL_PIXELFORMAT_ARGB8888, 0); - SDL_Surface *flipped = zoomSurface(converted, 1, -1, SMOOTHING_OFF); + TTF_Font* font = TTF_OpenFont("resource/SourceCodePro-Regular.otf", 14); + std::string padded = sfw::pad(frame_count, 2); + SDL_Surface* shaded = TTF_RenderText_Shaded( + font, padded.c_str(), {0, 0, 0}, {255, 255, 255}); + SDL_Surface* converted = SDL_ConvertSurfaceFormat( + shaded, SDL_PIXELFORMAT_ARGB8888, 0); + SDL_Surface* flipped = zoomSurface(converted, 1, -1, SMOOTHING_OFF); + SDL_FreeSurface(shaded); + SDL_FreeSurface(converted); if (not flipped) { fprintf(stderr, "Could not create text %s\n", SDL_GetError()); } + TTF_CloseFont(font); return flipped; } void set_framerate_indicator(int frame_count, GLuint id) { - printf("%i %i", frame_count, id); - SDL_Surface *message = get_framerate_indicator_surface(frame_count); + SDL_Surface* message = get_framerate_indicator_surface(frame_count); glBindTexture(GL_TEXTURE_2D, id); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, message->w, message->h, 0, GL_BGRA, GL_UNSIGNED_BYTE, - message->pixels); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, message->w, message->h, GL_BGRA, + GL_UNSIGNED_BYTE, message->pixels); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + SDL_FreeSurface(message); } Mushroom::Mushroom(Node *parent) : Sprite(parent, "resource/shrooms") { + set_frame_length(500); std::cout << "mushroom constructor " << this << std::endl; } void Mushroom::update() { - Game *game = get_root(); move(direction); int x = location.get_x(); - if (x > game->sw or x < 0) + glm::ivec2 resolution = get_display().get_window_size(); + if (x > resolution.x or x < 0) { direction = -direction; - if (x > game->sw) + if (x > resolution.x) { - move(game->sw - x); + move(resolution.x - x); } else { @@ -140,11 +146,6 @@ Demo::Demo() Mix_PlayMusic(music, -1); load_gl_context(); delegate.subscribe(&Demo::respond, this); - // audio_file.open("audio.raw", std::ios::binary); - // SDL_AudioSpec spec; - // audio_device_id = SDL_OpenAudioDevice(NULL, SDL_TRUE, &spec, &spec, 0); - // SDL_Log("opened audio device %i", audio_device_id); - // SDL_PauseAudioDevice(audio_device_id, SDL_FALSE); } void Demo::load_sdl_context() @@ -168,7 +169,7 @@ void Demo::load_gl_context() v6-v1-v0 v1-v6-v7 (left) v7-v2-v1 - v7-v4-v3 (bottom) + v7-v4-v3 (bottom) v3-v2-v7 v4-v7-v6 (back) v6-v5-v4 @@ -212,12 +213,14 @@ void Demo::load_gl_context() vertices.insert(vertices.end(), background_vertices.begin(), background_vertices.end()); vertices.insert(vertices.end(), framerate_indicator_vertices.begin(), framerate_indicator_vertices.end()); - projection = glm::perspective(glm::radians(45.0f), - (float) sw / (float) sh, 0.1f, 100.0f); + glm::ivec2 resolution = get_display().get_window_size(); + projection = glm::perspective( + glm::radians(45.0f), resolution.x / (float) resolution.y, 0.1f, + 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); - printf("tile.png bytes per pixel %i\n", surface->format->BytesPerPixel); + 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::array framerate_indicator_uv = { @@ -292,14 +295,15 @@ void Demo::load_gl_context() glBindAttribLocation(flat_program, 3, "pos"); link_shader(flat_program); mvp_id = glGetUniformLocation(world_program, "MVP"); - GLuint sampler_uniform_id = glGetUniformLocation(world_program, "myTextureSampler"); + // GLuint sampler_uniform_id = glGetUniformLocation(world_program, "myTextureSampler"); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, space_texture_id); - glUniform1i(sampler_uniform_id, 0); + // glUniform1i(sampler_uniform_id, 0); glDepthFunc(GL_LESS); frame_count_timestamp = SDL_GetTicks(); - framerate_texture_id = get_gl_texture_from_surface( - get_framerate_indicator_surface(frame_count), GL_LINEAR); + SDL_Surface* fps_surface = get_framerate_indicator_surface(frame_count); + framerate_texture_id = get_gl_texture_from_surface(fps_surface, GL_LINEAR); + SDL_FreeSurface(fps_surface); } void Demo::respond(SDL_Event& event) @@ -320,6 +324,17 @@ void Demo::respond(SDL_Event& event) Mix_Chunk* music = Mix_LoadWAV("resource/Ag.ogg"); Mix_PlayChannel(-1, music, 0); } + else if (delegate.compare(event, "fullscreen")) + { + if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) + { + SDL_SetWindowFullscreen(window, 0); + } + else + { + SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN); + } + } } void Demo::update() @@ -328,18 +343,7 @@ void Demo::update() // { // if (event.type == SDL_KEYDOWN) // { - // if (event.key.keysym.sym == SDLK_F11) - // { - // if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) - // { - // SDL_SetWindowFullscreen(window, 0); - // } - // else - // { - // SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN); - // } - // } - // else if (SDL_GetModState() & KMOD_CTRL) + // if (SDL_GetModState() & KMOD_CTRL) // { // if (event.key.keysym.sym == SDLK_f) // { diff --git a/demo/Demo.hpp b/demo/Demo.hpp index 8f6c646..704878a 100644 --- a/demo/Demo.hpp +++ b/demo/Demo.hpp @@ -37,6 +37,7 @@ #include "Sprite.hpp" #include "Input.hpp" #include "Delegate.hpp" +#include "extension.hpp" struct Mushroom : Sprite { @@ -60,11 +61,8 @@ struct Demo : Game GLuint vbo, space_texture_id, mvp_id, framerate_texture_id, flat_program, world_program, fake_texture_id; glm::mat4 projection, view, model = glm::mat4(1.0f), mvp; - int abc, def, ghi, jkl, mno, pqr, stu, vwx, yz; Mushroom mushroom = Mushroom(this); Sprite grass = Sprite(this, "resource/Field.png"); - // SDL_AudioDeviceID audio_device_id; - // std::ofstream audio_file; Demo(); void load_sdl_context(); diff --git a/demo/Makefile b/demo/Makefile index db2222f..f864ff1 100644 --- a/demo/Makefile +++ b/demo/Makefile @@ -36,13 +36,16 @@ $(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 Node.*pp) +$(SFW_SRC_DIR)Sprite.o: $(addprefix $(SFW_SRC_DIR),Game.*pp Location.*pp Node.*pp Animation.*pp) $(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) -$(SFW_SRC_DIR)Input.o: $(addprefix $(SFW_SRC_DIR),Delegate.*pp) +$(SFW_SRC_DIR)Recorder.o: $(addprefix $(SFW_SRC_DIR),extension.*pp Node.*pp Delegate.*pp Animation.*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) +$(SFW_SRC_DIR)Display.o: $(addprefix $(SFW_SRC_DIR),Node.*pp) $(SFW_SRC_DIR)%.o: $(addprefix $(SFW_SRC_DIR),%.cpp %.hpp) $(CPPC_LINUX) $(CPP_FLAGS) $(SDL_FLAGS) $< -o $@ diff --git a/demo/config.json b/demo/config.json index 4c3c9bb..031c4ad 100644 --- a/demo/config.json +++ b/demo/config.json @@ -1,7 +1,8 @@ { "display": { - "dimensions": [640, 480] + "dimensions": [864, 486], + "fps": 60 }, "path": { @@ -14,12 +15,12 @@ "keys": { "context": " ", - "print-video-memory": "?", - "play-sound": "s" + "print-video-memory-size": "v", + "play-sound": "" }, "recording": { "write-mp4": true, - "video-frame-length": 16.667 + "video-frame-length": 33.334 } } diff --git a/src/Configuration.cpp b/src/Configuration.cpp index 1daad5f..29b1624 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -22,14 +22,16 @@ void Configuration::set_defaults() {"down", "down"}, {"left", "left"}, {"pause", "enter"}, - {"fullscreen", {"ALT", "enter"}} + {"fullscreen", {"ALT", "enter"}}, + {"show-fps", {"CTRL", "f"}} }; sys_config["path"] = { {"screenshots", "."}, {"video", "."} }; sys_config["display"] = { - {"dimensions", {640, 480}} + {"dimensions", {640, 480}}, + {"fps", 60} }; sys_config["recording"] = { {"screenshot-prefix", "screenshot-"}, @@ -43,6 +45,12 @@ void Configuration::set_defaults() {"max-video-memory", 1000}, {"mp4-pixel-format", "yuv444p"} }; + sys_config["fps-indicator"] = { + {"width", .05}, + {"height", .04}, + {"background", {255, 255, 255}}, + {"foreground", {0, 0, 0}} + }; } void Configuration::load() diff --git a/src/Display.cpp b/src/Display.cpp index aadd5a1..b39c580 100644 --- a/src/Display.cpp +++ b/src/Display.cpp @@ -12,13 +12,27 @@ glm::ivec2 Display::get_window_size() void Display::get_screen_pixels(unsigned char* pixels, int w, int h, int x, int y) { - GLenum format; + if (get_root()->is_gl_context) + { + GLenum format; #if SDL_BYTEORDER == SDL_BIG_ENDIAN - format = GL_RGB; + format = GL_RGBA; #else - format = GL_BGR; + format = GL_BGRA; #endif - glReadPixels(x, y, w, h, format, GL_UNSIGNED_BYTE, pixels); + glReadPixels(x, y, w, h, format, GL_UNSIGNED_BYTE, pixels); + } + else + { + Uint32 format; +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + format = SDL_PIXELFORMAT_ABGR8888; +#else + format = SDL_PIXELFORMAT_ARGB8888; +#endif + SDL_RenderReadPixels( + get_root()->renderer, NULL, format, pixels, bpp / 8 * w); + } } SDL_Surface* Display::get_screen_surface() @@ -26,17 +40,28 @@ 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 = get_screen_surface_from_pixels(pixels); + SDL_Surface* surface = get_screen_surface_from_pixels( + pixels, get_root()->is_gl_context); delete[] pixels; return surface; } -SDL_Surface* Display::get_screen_surface_from_pixels(unsigned char* pixels) +SDL_Surface* Display::get_screen_surface_from_pixels( + unsigned char* pixels, bool flip) { glm::ivec2 size = get_window_size(); - 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); - return zoomed_surface; + SDL_Surface* surface; + if (flip) + { + SDL_Surface* pixel_surface = SDL_CreateRGBSurfaceFrom( + pixels, size.x, size.y, bpp, bpp / 8 * size.x, 0, 0, 0, 0); + 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); + std::memcpy(surface->pixels, pixels, bpp / 8 * size.x * size.y); + } + return surface; } diff --git a/src/Display.hpp b/src/Display.hpp index 8e523a0..4ed353b 100644 --- a/src/Display.hpp +++ b/src/Display.hpp @@ -19,13 +19,13 @@ struct Display : Node { - const static int bpp = 24; + const static int bpp = 32; Display(Node*); glm::ivec2 get_window_size(); void get_screen_pixels(unsigned char*, int, int, int = 0, int = 0); SDL_Surface* get_screen_surface(); - SDL_Surface* get_screen_surface_from_pixels(unsigned char*); + SDL_Surface* get_screen_surface_from_pixels(unsigned char*, bool); }; diff --git a/src/Game.cpp b/src/Game.cpp index 3cdae8b..f4388dc 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -1,14 +1,22 @@ #include "Game.hpp" +// FPSIndicator::FPSIndicator(Node* parent) : Node(parent) {} + +// FPSIndicator::update() +// { + +// } + Game::Game() { + set_framerate(get_configuration()["display"]["fps"]); delegate.subscribe(&Game::handle_quit_event, this, SDL_QUIT); - std::cout << "GLEW " << glewGetString(GLEW_VERSION) << std::endl; + SDL_Log("GLEW %s", glewGetString(GLEW_VERSION)); putenv("SDL_VIDEO_X11_LEGACY_FULLSCREEN=0"); - putenv("SDL_VIDEO_CENTERED=1"); + putenv("SDL_VIDEO_CENTERED=0"); SDL_version version; SDL_GetVersion(&version); - printf("SDL %d.%d.%d\n", version.major, version.minor, version.patch); + SDL_Log("SDL %d.%d.%d", version.major, version.minor, version.patch); fprintf(stderr, "stderr test message\n"); SDL_SetMainReady(); // SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); @@ -24,8 +32,9 @@ Game::Game() SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); print_gl_attributes(); + std::vector window_size = get_configuration()["display"]["dimensions"]; window = SDL_CreateWindow("TARE control", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - sw, sh, SDL_WINDOW_OPENGL); + window_size[0], window_size[1], SDL_WINDOW_OPENGL); if (window == NULL) { print_sdl_error("Could not create window"); @@ -39,8 +48,8 @@ Game::Game() } else { - printf("initialized SDL ttf %d.%d.%d\n", SDL_TTF_MAJOR_VERSION, - SDL_TTF_MINOR_VERSION, SDL_TTF_PATCHLEVEL); + SDL_Log("initialized SDL ttf %d.%d.%d", SDL_TTF_MAJOR_VERSION, + SDL_TTF_MINOR_VERSION, SDL_TTF_PATCHLEVEL); } if (Mix_Init(MIX_INIT_FLAC) == 0) { @@ -49,22 +58,26 @@ Game::Game() } else { - printf("initialized SDL mixer %d.%d.%d\n", SDL_MIXER_MAJOR_VERSION, - SDL_MIXER_MINOR_VERSION, SDL_MIXER_PATCHLEVEL); + SDL_Log("initialized SDL mixer %d.%d.%d", SDL_MIXER_MAJOR_VERSION, + SDL_MIXER_MINOR_VERSION, SDL_MIXER_PATCHLEVEL); } if (Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, 1024) < 0) { print_sdl_error("Could not set up audio"); } - std::cout << "Using audio driver: " << SDL_GetCurrentAudioDriver() << - std::endl; + SDL_Log("Using audio driver: %s", SDL_GetCurrentAudioDriver()); const int audio_device_count = SDL_GetNumAudioDevices(SDL_TRUE); for (int ii = 0; ii < audio_device_count; ii++) { - std::cout << "Found audio capture device " << ii << ": " << - SDL_GetAudioDeviceName(ii, SDL_TRUE) << std::endl; + SDL_Log("Found audio capture device %i: %s", ii, + SDL_GetAudioDeviceName(ii, SDL_TRUE)); } +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + SDL_Log("big endian, using GL_RGBA and SDL_PIXELFORMAT_ABGR8888"); +#else + SDL_Log("little endian, using GL_BGRA and SDL_PIXELFORMAT_ARGB8888"); +#endif last_frame_timestamp = SDL_GetTicks(); } @@ -88,7 +101,14 @@ void Game::print_gl_attributes() int major, minor; SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major); SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor); - std::cout << "GL CONTEXT: " << major << ", " << minor << std::endl; + SDL_Log("GL CONTEXT: %i, %i", major, minor); + int r, g, b, a, buf; + SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &r); + SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &g); + SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &b); + SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &a); + SDL_GL_GetAttribute(SDL_GL_BUFFER_SIZE, &buf); + SDL_Log("GL PIXELS: red: %i green: %i blue: %i alpha: %i", r, g, b, a); } void Game::load_sdl_context() @@ -103,6 +123,15 @@ void Game::load_sdl_context() print_sdl_error("Could not create renderer"); flag_to_end(); } + else + { + SDL_RendererInfo info; + SDL_GetRendererInfo(renderer, &info); + SDL_Log("renderer name: %s, flags: %i, texture formats: %i, " + "max texture w: %i, max texture h: %i", info.name, info.flags, + info.num_texture_formats, info.max_texture_width, + info.max_texture_height); + } is_gl_context = false; } @@ -129,11 +158,212 @@ void Game::load_gl_context() message << "GLEW could not initialize " << glewGetErrorString(error); print_error(message.str()); } - printf("OpenGL %s, renderer %s, shading language %s\n", glGetString(GL_VERSION), - glGetString(GL_RENDERER), glGetString(GL_SHADING_LANGUAGE_VERSION)); + SDL_Log("OpenGL %s, renderer %s, shading language %s", + glGetString(GL_VERSION), glGetString(GL_RENDERER), + glGetString(GL_SHADING_LANGUAGE_VERSION)); is_gl_context = true; } +GLuint Game::create_gl_texture() +{ + GLuint id; + glCreateTextures(GL_TEXTURE_2D, 1, &id); + glBindTexture(GL_TEXTURE_2D, id); + return id; +} + +bool Game::log_gl_errors() +{ + GLenum error; + bool error_logged = false; + while ((error = glGetError()) != GL_NO_ERROR) + { + error_logged = true; + if (error == GL_INVALID_ENUM) + { + SDL_LogError( + SDL_LOG_CATEGORY_APPLICATION, + "GL_INVALID_ENUM, an unacceptable value is specified for an " + "enumerated argument"); + } + else if (error == GL_INVALID_VALUE) + { + SDL_LogError( + SDL_LOG_CATEGORY_APPLICATION, + "GL_INVALID_VALUE, a numeric argument is out of range"); + } + 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"); + } + else if (error == GL_INVALID_FRAMEBUFFER_OPERATION) + { + SDL_LogError( + SDL_LOG_CATEGORY_APPLICATION, + "GL_INVALID_FRAMEBUFFER_OPERATION, the framebuffer object is " + "not complete"); + } + 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"); + } + 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."); + } + 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."); + } + } + return error_logged; +} + +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"; + } + 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()); +} + void Game::run() { while (not done) diff --git a/src/Game.hpp b/src/Game.hpp index a98314e..09e858b 100644 --- a/src/Game.hpp +++ b/src/Game.hpp @@ -21,6 +21,14 @@ #include "Display.hpp" #include "Recorder.hpp" #include "Input.hpp" +// #include "Sprite.hpp" + +// struct FPSIndicator : Sprite +// { + +// FPSIndicator(Node*); + +// }; struct Game : Node { @@ -33,10 +41,11 @@ struct Game : Node SDL_Window* window; SDL_Renderer* renderer = NULL; SDL_GLContext glcontext = NULL; - int sw = 640, sh = 480, framerate = 60, frame_time_overflow = 0, - last_frame_timestamp, frame_count_timestamp, ticks, - last_frame_length; - float frame_length = 1000.0 / framerate; + // 768, 432 + // 864, 486 + 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; Configuration configuration = Configuration(this); Delegate delegate = Delegate(this); @@ -51,6 +60,9 @@ struct Game : Node void print_gl_attributes(); void load_sdl_context(); void load_gl_context(); + GLuint create_gl_texture(); + bool log_gl_errors(); + void log_surface_format(SDL_Surface*, std::string = "surface"); void run(); void flag_to_end(); virtual void update() {}; @@ -67,4 +79,6 @@ struct Game : Node }; +#include "Sprite.hpp" + #endif diff --git a/src/Input.cpp b/src/Input.cpp index 7164b26..aa0ed6c 100644 --- a/src/Input.cpp +++ b/src/Input.cpp @@ -75,23 +75,20 @@ void Input::add_to_key_map( void Input::respond(SDL_Event &event) { - // if (event.type == SDL_KEYDOWN) - // { - SDL_Keymod mod = SDL_GetModState(); - for (KeyCombination& combination : key_map) + SDL_Keymod mod = SDL_GetModState(); + for (KeyCombination& combination : key_map) + { + if (event.key.keysym.sym == combination.key and + (not combination.ctrl || mod & KMOD_CTRL) and + (not combination.shift || mod & KMOD_SHIFT) and + (not combination.alt || mod & KMOD_ALT)) { - if (event.key.keysym.sym == combination.key and - (not combination.ctrl || mod & KMOD_CTRL) and - (not combination.shift || mod & KMOD_SHIFT) and - (not combination.alt || mod & KMOD_ALT)) - { - SDL_Event relay; - bool* cancel = new bool(event.type == SDL_KEYDOWN ? false : true); - relay.type = Delegate::command_event_type; - relay.user.data1 = &combination.command; - relay.user.data2 = cancel; - SDL_PushEvent(&relay); - } + SDL_Event relay; + bool* cancel = new bool(event.type == SDL_KEYDOWN ? false : true); + relay.type = Delegate::command_event_type; + relay.user.data1 = &combination.command; + relay.user.data2 = cancel; + SDL_PushEvent(&relay); } - // } + } } diff --git a/src/Node.cpp b/src/Node.cpp index 6b3cec9..9c67ccf 100644 --- a/src/Node.cpp +++ b/src/Node.cpp @@ -1,12 +1,16 @@ #include "Node.hpp" #include "Game.hpp" -#include "Display.hpp" -#include "Delegate.hpp" +// #include "Display.hpp" +// #include "Delegate.hpp" Node::Node() : Node(NULL) {} -Node::Node(Node *parent) : parent(parent) +Node::Node(Node *parent, bool active) : parent(parent) { + if (active) + { + activate(); + } std::cout << "Constructing "; print_branch(); } @@ -18,6 +22,16 @@ Node::~Node() get_delegate().unsubscribe(this); } +void Node::activate() +{ + active = true; +} + +void Node::deactivate() +{ + active = false; +} + nlohmann::json& Node::get_configuration() { return get_root()->configuration.config; diff --git a/src/Node.hpp b/src/Node.hpp index 1030c13..6fe7ce6 100644 --- a/src/Node.hpp +++ b/src/Node.hpp @@ -17,10 +17,13 @@ struct Node { Node *parent = NULL; + bool active = false; Node(); - Node(Node*); + Node(Node*, bool = false); virtual ~Node(); + void activate(); + void deactivate(); Game* get_root(); nlohmann::json& get_configuration(); Delegate& get_delegate(); diff --git a/src/Recorder.cpp b/src/Recorder.cpp index 02b10c9..d90011e 100644 --- a/src/Recorder.cpp +++ b/src/Recorder.cpp @@ -133,7 +133,7 @@ void Recorder::open_audio_file() void Recorder::add_frame() { glm::ivec2 size = get_display().get_window_size(); - int bytes = Display::bpp / 8 * size.x * size.y; + int bytes = 32 / 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"]; @@ -142,13 +142,16 @@ void Recorder::add_frame() { delete[] current_stash.pixel_buffers.front(); current_stash.pixel_buffers.erase(current_stash.pixel_buffers.begin()); + current_stash.flipped.erase(current_stash.flipped.begin()); } current_stash.pixel_buffers.push_back(pixels); + current_stash.flipped.push_back(get_root()->is_gl_context); if (is_recording) { unsigned char* vid_pixels = new unsigned char[bytes]; memcpy(vid_pixels, pixels, bytes); video_stashes.back().pixel_buffers.push_back(vid_pixels); + 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 f = @@ -166,20 +169,30 @@ void Recorder::add_frame() int Recorder::get_memory_size() { glm::ivec2 window = get_display().get_window_size(); - int bytes_per_buffer = Display::bpp / 8 * window.x * window.y; - int count = 0; + int bytes_per_frame = Display::bpp / 8 * window.x * window.y, + size_in_bytes = 0; for (Stash& stash : in_game_stashes) { - count += stash.pixel_buffers.size(); + size_in_bytes += stash.pixel_buffers.size() * bytes_per_frame; + for (int& length : stash.audio_buffer_lengths) + { + size_in_bytes += length; + } } for (Stash& stash : video_stashes) { - count += stash.pixel_buffers.size(); + size_in_bytes += stash.pixel_buffers.size() * bytes_per_frame; + } + size_in_bytes += current_stash.pixel_buffers.size() * bytes_per_frame; + for (int& length : current_stash.audio_buffer_lengths) + { + size_in_bytes += length; + } + size_in_bytes += most_recent_stash.pixel_buffers.size() * bytes_per_frame; + for (int& length : most_recent_stash.audio_buffer_lengths) + { + size_in_bytes += length; } - count += current_stash.pixel_buffers.size(); - count += most_recent_stash.pixel_buffers.size(); - int size_in_bytes = 0; - size_in_bytes = count * bytes_per_buffer; return size_in_bytes / 1000000; } @@ -196,8 +209,7 @@ void Recorder::make_directory() void Recorder::write_stash_frames(bool is_video, int index) { int frame_offset = is_video ? video_stashes[index].frame_offset : 0; - std::cout << "Writing stash index " << index << " to " << current_video_directory << "..." << - std::endl; + SDL_Log("Writing stash index %i to %s...", index, current_video_directory.c_str()); SDL_Surface* frame; GifWriter gif_writer; int gif_frame_length = get_configuration()["recording"]["gif-frame-length"]; @@ -211,12 +223,14 @@ void Recorder::write_stash_frames(bool is_video, int index) if (is_video) { frame = get_display().get_screen_surface_from_pixels( - video_stashes[index].pixel_buffers.front()); + video_stashes[index].pixel_buffers.front(), + video_stashes[index].flipped.front()); } else { frame = get_display().get_screen_surface_from_pixels( - most_recent_stash.pixel_buffers.front()); + most_recent_stash.pixel_buffers.front(), + most_recent_stash.flipped.front()); } std::stringstream name; name << sfw::pad(ii, 5) << ".png"; @@ -235,7 +249,9 @@ void Recorder::write_stash_frames(bool is_video, int index) gif_write_overflow += elapsed - (last_gif_write + gif_frame_length); last_gif_write = elapsed; } - GifWriteFrame(&gif_writer, (const uint8_t*) frame->pixels, + SDL_Surface* converted = SDL_ConvertSurfaceFormat( + frame, SDL_PIXELFORMAT_ABGR8888, 0); + GifWriteFrame(&gif_writer, (const uint8_t*) converted->pixels, frame->w, frame->h, gif_frame_length / 10); } elapsed += get_frame_length(); @@ -244,12 +260,16 @@ void Recorder::write_stash_frames(bool is_video, int index) delete[] video_stashes[index].pixel_buffers.front(); video_stashes[index].pixel_buffers.erase( video_stashes[index].pixel_buffers.begin()); + video_stashes[index].flipped.erase( + video_stashes[index].flipped.begin()); } else { delete[] most_recent_stash.pixel_buffers.front(); most_recent_stash.pixel_buffers.erase( most_recent_stash.pixel_buffers.begin()); + most_recent_stash.flipped.erase( + most_recent_stash.flipped.begin()); } SDL_FreeSurface(frame); } @@ -268,6 +288,7 @@ void Recorder::keep_stash() { delete[] stash.pixel_buffers.back(); stash.pixel_buffers.pop_back(); + stash.flipped.pop_back(); } in_game_stashes.erase(in_game_stashes.begin()); } diff --git a/src/Recorder.hpp b/src/Recorder.hpp index f2e23d8..582227d 100644 --- a/src/Recorder.hpp +++ b/src/Recorder.hpp @@ -23,6 +23,7 @@ struct Stash { std::vector pixel_buffers; + std::vector flipped; std::vector audio_buffers; std::vector audio_buffer_lengths; int frame_offset; diff --git a/src/Sprite.cpp b/src/Sprite.cpp index 0981372..2c6dbbd 100644 --- a/src/Sprite.cpp +++ b/src/Sprite.cpp @@ -1,11 +1,17 @@ #include "Sprite.hpp" #include "Game.hpp" -Sprite::Sprite(Node *parent) : Node(parent) {} +Sprite::Sprite(Node *parent) : Node(parent, true) {} -Sprite::Sprite(Node *parent, std::string path) : Node(parent) +Sprite::Sprite(Node *parent, std::string path) : Node(parent, true) { associate(path); + animation.play(); +} + +void Sprite::set_frame_length(float length) +{ + animation.set_frame_length(length); } void Sprite::associate(std::string path) @@ -70,15 +76,23 @@ void Sprite::unload() } } -void Sprite::update() +void Sprite::advance_frame() { - int w, h; - SDL_Texture *frame = frames[frame_ii++]; - SDL_QueryTexture(frame, NULL, NULL, &w, &h); - SDL_Rect frame_rect = {location.get_x(), location.get_y(), w, h}; - SDL_RenderCopy(get_root()->renderer, frame, NULL, &frame_rect); - if (frame_ii >= frames.size()) + if (++frame_ii >= frames.size()) { frame_ii = 0; } } + +void Sprite::update() +{ + if (active) + { + animation.update(); + int w, h; + SDL_Texture *frame = frames[frame_ii]; + SDL_QueryTexture(frame, NULL, NULL, &w, &h); + SDL_Rect frame_rect = {location.get_x(), location.get_y(), w, h}; + SDL_RenderCopy(get_root()->renderer, frame, NULL, &frame_rect); + } +} diff --git a/src/Sprite.hpp b/src/Sprite.hpp index 7daec65..70be14c 100644 --- a/src/Sprite.hpp +++ b/src/Sprite.hpp @@ -12,6 +12,7 @@ #include "Node.hpp" #include "Game.hpp" #include "Location.hpp" +#include "Animation.hpp" struct Sprite : Node { @@ -20,14 +21,17 @@ struct Sprite : Node std::vector frame_paths; int frame_ii = 0; Location location; + Animation animation = Animation(&Sprite::advance_frame, this); Sprite(Node*); Sprite(Node*, std::string); + void set_frame_length(float); void associate(std::string); void load(); void load_file(fs::path); void add_frame(SDL_Texture*); void unload(); + void advance_frame(); void update(); std::string get_class_name() { return "Sprite"; }