diff --git a/src/Animation.cpp b/src/Animation.cpp index 41c69f4..32c2362 100644 --- a/src/Animation.cpp +++ b/src/Animation.cpp @@ -53,7 +53,7 @@ bool Animation::playing(bool include_delay) const return play_state && !paused && (include_delay || delay <= 0); } -void Animation::update(float timestamp) +bool Animation::update(float timestamp) { timer.update(timestamp); if (playing()) @@ -81,7 +81,7 @@ void Animation::update(float timestamp) { overflow = 0; } - } - } - } + return true; + } } } + return false; } diff --git a/src/Animation.hpp b/src/Animation.hpp index 430e61f..067d9c1 100644 --- a/src/Animation.hpp +++ b/src/Animation.hpp @@ -24,14 +24,19 @@ private: bool play_state = false, ending = false, paused = false; float delay = 0.0f, overflow = 0.0f, _frame_length = 0.0f, previous_step_time = 0.0f; - Callback step = nullptr; sb::Timer timer; + Callback step = [](){}; public: Animation(); /*! + * @deprecated It is preferable to use the default constructor, provide a frame length using Animation::frame_length(float), and + * omit the callback function. This is because storing the callback function in this object can create copying issues when + * std::bind is used to create the callback. Instead, check the return value of Animation::update(float) to determine whether or + * not to call the desired callback externally. + * * Create an Animation object by supplying a function and interval at which the function should run. Run Animation::update(float) * regularly with an updated timestamp from Game::update(float), and the function will be launched automatically at the given * interval. If the interval is omitted, the function will run every time Animation::update(float) is run. @@ -71,7 +76,17 @@ public: void unpause(); void reset(); bool playing(bool = true) const; - void update(float timestamp); + + /*! + * Update the timer and check the function's return value to determine whether a new frame of the animation should be produced. + * + * This will run the callback automatically if it is stored in this object, but the ability to store the callback in this object is deprecated and + * will be removed soon. + * + * @param timestamp Seconds since the program has started, which can be obtained from Game::update(float) + * @return True if the next frame of animation should be triggered, false otherwise + */ + bool update(float timestamp); }; diff --git a/src/Game.cpp b/src/Game.cpp index 1498224..73939b1 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -286,7 +286,7 @@ void Game::load_gl_context() { std::ostringstream message; message << "GLEW could not initialize " << glewGetErrorString(error); - sb::Log::log(message, sb::Log::ERROR); + sb::Log::log(message, sb::Log::ERR); } #endif @@ -383,7 +383,7 @@ GLuint Game::load_shader(const fs::path& path, GLenum type) const error_info.resize(max_length, 0); glGetShaderInfoLog(shader, error_info.size(), nullptr, error_info.data()); message << "failed to compile " << path << ": " << error_info; - sb::Log::log(message, sb::Log::Level::ERROR); + sb::Log::log(message, sb::Log::Level::ERR); return -1; } } @@ -409,7 +409,7 @@ bool Game::link_shader(GLuint program) const error_info.resize(max_length, 0); glGetProgramInfoLog(program, error_info.size(), nullptr, error_info.data()); message << "failed linking shader program " << program << ": " << error_info; - sb::Log::log(message, sb::Log::Level::ERROR); + sb::Log::log(message, sb::Log::Level::ERR); return false; } } @@ -562,7 +562,7 @@ std::shared_ptr sb::Game::font(const fs::path& path, int size) const { std::ostringstream message; message << "Could not load " << path; - sb::Log::log(message, sb::Log::ERROR); + sb::Log::log(message, sb::Log::ERR); if (path != configuration()("display", "default font path").get()) { return this->font(); diff --git a/src/Log.hpp b/src/Log.hpp index 4eb8179..fa7cbb9 100644 --- a/src/Log.hpp +++ b/src/Log.hpp @@ -47,7 +47,7 @@ namespace sb DEBUG, INFO, WARN, - ERROR, + ERR, CRITICAL, }; @@ -88,7 +88,7 @@ namespace sb * @param level message priority level * @return a string stream containing the full message */ - static std::ostringstream sdl_error(const std::string& message = "", const Level level = ERROR); + static std::ostringstream sdl_error(const std::string& message = "", const Level level = ERR); }; diff --git a/src/Model.cpp b/src/Model.cpp index 4c31d75..cdd217a 100644 --- a/src/Model.cpp +++ b/src/Model.cpp @@ -117,7 +117,7 @@ const sb::Texture& sb::Model::texture(int index) const } else { - return textures()[index]; + return textures()[glm::mod(index, static_cast(textures().size()))]; } } @@ -129,7 +129,7 @@ sb::Texture& sb::Model::texture(int index) } else { - return textures()[index]; + return textures()[glm::mod(index, static_cast(textures().size()))]; } } diff --git a/src/Model.hpp b/src/Model.hpp index edf0418..0b0c1c5 100644 --- a/src/Model.hpp +++ b/src/Model.hpp @@ -180,14 +180,17 @@ namespace sb std::vector& textures(); /*! - * Get a constant reference to the texture at the given index. If there are no textures, an exception will be thrown. + * Get a constant reference to the texture at the given index. If there are no textures, an exception will be thrown. If the index is greater + * than the number of textures or is a negative number, modulus will be be used to wrap the value of the index to the size of the texture + * list. * * @param index index of texture to get */ const sb::Texture& texture(int index) const; /*! - * Get the texture at the given index. If there are no textures, an exception will be thrown. + * Get the texture at the given index. If there are no textures, an exception will be thrown. If the index is greater than the number of textures + * or is a negative number, modulus will be be used to wrap the value of the index to the size of the texture list. * * @param index index of texture to get */ diff --git a/src/Pixels.cpp b/src/Pixels.cpp index f6235fb..a8a2d93 100644 --- a/src/Pixels.cpp +++ b/src/Pixels.cpp @@ -79,7 +79,7 @@ Pixels::Pixels(SDL_Renderer* renderer, SDL_Texture* texture, const Box& box) : } else { - sb::Log::log("unknown texture format for loading pixels", sb::Log::Level::ERROR); + sb::Log::log("unknown texture format for loading pixels", sb::Log::Level::ERR); } } diff --git a/src/Sprite.hpp b/src/Sprite.hpp index f71972f..ae774d5 100644 --- a/src/Sprite.hpp +++ b/src/Sprite.hpp @@ -15,6 +15,7 @@ #include "glm/glm.hpp" #include "filesystem.hpp" #include "Model.hpp" +#include "Animation.hpp" namespace sb { @@ -41,8 +42,18 @@ namespace sb /* A sprite by definition has only one texture per draw, so keep an index to the currently active texture. */ int _texture_index = 0; + void frame_by_frame() + { + if (static_cast(++_texture_index) >= plane.textures().size()) + { + _texture_index = 0; + } + } + public: + sb::Animation frames; + /*! * Construct an instance of Sprite using an existing plane object. The plane will be copied into the Sprite, so further edits must * be made using the Sprite class. @@ -295,6 +306,15 @@ namespace sb plane.transform(_translation * _scale * _rotation * transformation); } + void update(const sb::Timer& timer) + { + /* Update animation */ + if (frames.update(timer.stamp())) + { + frame_by_frame(); + } + } + /*! * Get the sprite's transformation from Sprite::transform(glm::mat4), which combines the translation, scale, rotation, and an * optional arbitrary transformation, apply the given view and projection transformations, and pass the transformation to the diff --git a/src/Texture.cpp b/src/Texture.cpp index da39532..a2e9be8 100644 --- a/src/Texture.cpp +++ b/src/Texture.cpp @@ -69,7 +69,7 @@ void Texture::load() { std::ostringstream message; message << "Error loading texture path: " << path; - sb::Log::log(message, sb::Log::ERROR); + sb::Log::log(message, sb::Log::ERR); } #endif } diff --git a/src/extension.cpp b/src/extension.cpp index 1e9ea48..eafe778 100644 --- a/src/extension.cpp +++ b/src/extension.cpp @@ -384,7 +384,7 @@ SDL_Texture* sb::get_remapped_texture( SDL_Texture* remapped = get_remapped_texture(renderer, base, map); if (remapped == nullptr) { - sb::Log::log("could not remap texture", sb::Log::ERROR); + sb::Log::log("could not remap texture", sb::Log::ERR); return nullptr; } SDL_DestroyTexture(base);