deprecate passing callback to Animation; add an update function to Sprite for running frame by frame animation; rename log's ERROR to ERR to avoid conflict with windows.h

This commit is contained in:
ohsqueezy 2023-11-14 00:19:32 -05:00
parent 333a7b73ac
commit 110b876648
10 changed files with 57 additions and 19 deletions

View File

@ -53,7 +53,7 @@ bool Animation::playing(bool include_delay) const
return play_state && !paused && (include_delay || delay <= 0); return play_state && !paused && (include_delay || delay <= 0);
} }
void Animation::update(float timestamp) bool Animation::update(float timestamp)
{ {
timer.update(timestamp); timer.update(timestamp);
if (playing()) if (playing())
@ -81,7 +81,7 @@ void Animation::update(float timestamp)
{ {
overflow = 0; overflow = 0;
} }
} return true;
} } } }
} return false;
} }

View File

@ -24,14 +24,19 @@ private:
bool play_state = false, ending = false, paused = false; bool play_state = false, ending = false, paused = false;
float delay = 0.0f, overflow = 0.0f, _frame_length = 0.0f, previous_step_time = 0.0f; float delay = 0.0f, overflow = 0.0f, _frame_length = 0.0f, previous_step_time = 0.0f;
Callback step = nullptr;
sb::Timer timer; sb::Timer timer;
Callback step = [](){};
public: public:
Animation(); 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) * 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 * 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. * 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 unpause();
void reset(); void reset();
bool playing(bool = true) const; 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);
}; };

View File

@ -286,7 +286,7 @@ void Game::load_gl_context()
{ {
std::ostringstream message; std::ostringstream message;
message << "GLEW could not initialize " << glewGetErrorString(error); message << "GLEW could not initialize " << glewGetErrorString(error);
sb::Log::log(message, sb::Log::ERROR); sb::Log::log(message, sb::Log::ERR);
} }
#endif #endif
@ -383,7 +383,7 @@ GLuint Game::load_shader(const fs::path& path, GLenum type) const
error_info.resize(max_length, 0); error_info.resize(max_length, 0);
glGetShaderInfoLog(shader, error_info.size(), nullptr, error_info.data()); glGetShaderInfoLog(shader, error_info.size(), nullptr, error_info.data());
message << "failed to compile " << path << ": " << error_info; 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; return -1;
} }
} }
@ -409,7 +409,7 @@ bool Game::link_shader(GLuint program) const
error_info.resize(max_length, 0); error_info.resize(max_length, 0);
glGetProgramInfoLog(program, error_info.size(), nullptr, error_info.data()); glGetProgramInfoLog(program, error_info.size(), nullptr, error_info.data());
message << "failed linking shader program " << program << ": " << error_info; 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; return false;
} }
} }
@ -562,7 +562,7 @@ std::shared_ptr<TTF_Font> sb::Game::font(const fs::path& path, int size) const
{ {
std::ostringstream message; std::ostringstream message;
message << "Could not load " << path; 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<std::string>()) if (path != configuration()("display", "default font path").get<std::string>())
{ {
return this->font(); return this->font();

View File

@ -47,7 +47,7 @@ namespace sb
DEBUG, DEBUG,
INFO, INFO,
WARN, WARN,
ERROR, ERR,
CRITICAL, CRITICAL,
}; };
@ -88,7 +88,7 @@ namespace sb
* @param level message priority level * @param level message priority level
* @return a string stream containing the full message * @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);
}; };

View File

@ -117,7 +117,7 @@ const sb::Texture& sb::Model::texture(int index) const
} }
else else
{ {
return textures()[index]; return textures()[glm::mod(index, static_cast<int>(textures().size()))];
} }
} }
@ -129,7 +129,7 @@ sb::Texture& sb::Model::texture(int index)
} }
else else
{ {
return textures()[index]; return textures()[glm::mod(index, static_cast<int>(textures().size()))];
} }
} }

View File

@ -180,14 +180,17 @@ namespace sb
std::vector<sb::Texture>& textures(); std::vector<sb::Texture>& 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 * @param index index of texture to get
*/ */
const sb::Texture& texture(int index) const; 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 * @param index index of texture to get
*/ */

View File

@ -79,7 +79,7 @@ Pixels::Pixels(SDL_Renderer* renderer, SDL_Texture* texture, const Box& box) :
} }
else 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);
} }
} }

View File

@ -15,6 +15,7 @@
#include "glm/glm.hpp" #include "glm/glm.hpp"
#include "filesystem.hpp" #include "filesystem.hpp"
#include "Model.hpp" #include "Model.hpp"
#include "Animation.hpp"
namespace sb 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. */ /* A sprite by definition has only one texture per draw, so keep an index to the currently active texture. */
int _texture_index = 0; int _texture_index = 0;
void frame_by_frame()
{
if (static_cast<std::size_t>(++_texture_index) >= plane.textures().size())
{
_texture_index = 0;
}
}
public: 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 * 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. * be made using the Sprite class.
@ -295,6 +306,15 @@ namespace sb
plane.transform(_translation * _scale * _rotation * transformation); 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 * 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 * optional arbitrary transformation, apply the given view and projection transformations, and pass the transformation to the

View File

@ -69,7 +69,7 @@ void Texture::load()
{ {
std::ostringstream message; std::ostringstream message;
message << "Error loading texture path: " << path; message << "Error loading texture path: " << path;
sb::Log::log(message, sb::Log::ERROR); sb::Log::log(message, sb::Log::ERR);
} }
#endif #endif
} }

View File

@ -384,7 +384,7 @@ SDL_Texture* sb::get_remapped_texture(
SDL_Texture* remapped = get_remapped_texture(renderer, base, map); SDL_Texture* remapped = get_remapped_texture(renderer, base, map);
if (remapped == nullptr) 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; return nullptr;
} }
SDL_DestroyTexture(base); SDL_DestroyTexture(base);