1050 lines
24 KiB
C++
1050 lines
24 KiB
C++
#include "Game.hpp"
|
|
#include "Sprite.hpp"
|
|
|
|
Sprite::Sprite() : Sprite(nullptr) {}
|
|
|
|
Sprite::Sprite(Node* parent) :
|
|
Node(parent), current_frameset_name(configuration()["animation"]["all-frames-frameset-name"])
|
|
{
|
|
add_frameset(current_frameset_name);
|
|
frame_animation.play();
|
|
}
|
|
|
|
Sprite::Sprite(Node* parent, std::string path) : Sprite(parent)
|
|
{
|
|
associate(path);
|
|
}
|
|
|
|
void Sprite::reset()
|
|
{
|
|
Node::reset();
|
|
activate();
|
|
wipe_animation.reset();
|
|
unhide();
|
|
}
|
|
|
|
void Sprite::associate(std::string path)
|
|
{
|
|
if (fs::is_regular_file(path))
|
|
{
|
|
frame_paths.push_back(fs::path(path));
|
|
}
|
|
else if (fs::is_directory(path))
|
|
{
|
|
fs::directory_iterator directory(path);
|
|
std::vector<fs::path> paths;
|
|
std::copy(directory, fs::directory_iterator(), std::back_inserter(paths));
|
|
std::sort(paths.begin(), paths.end());
|
|
for (const fs::path& name : paths)
|
|
{
|
|
frame_paths.push_back(name);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::ostringstream message;
|
|
message << "invalid path " << path;
|
|
sb::Log::log(message, sb::Log::Level::ERROR);
|
|
}
|
|
}
|
|
|
|
void Sprite::load()
|
|
{
|
|
for (const fs::path &path : frame_paths)
|
|
{
|
|
load_file(path);
|
|
}
|
|
for (Child& child : children)
|
|
{
|
|
child.sprite.load();
|
|
}
|
|
}
|
|
|
|
void Sprite::load_file(fs::path path)
|
|
{
|
|
Game *game = get_root();
|
|
const char* previous_scale_quality = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
|
|
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, scale_quality.c_str());
|
|
SDL_Texture *base = IMG_LoadTexture(game->renderer, path.string().c_str()), *texture;
|
|
if (texture_access == SDL_TEXTUREACCESS_TARGET)
|
|
{
|
|
texture = sb::duplicate_texture(get_renderer(), base);
|
|
SDL_DestroyTexture(base);
|
|
}
|
|
else
|
|
{
|
|
texture = base;
|
|
}
|
|
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, previous_scale_quality);
|
|
if (not texture)
|
|
{
|
|
sb::Log::sdl_error("Could not load image");
|
|
}
|
|
else
|
|
{
|
|
add_frames(texture);
|
|
}
|
|
}
|
|
|
|
void Sprite::add_frames(SDL_Texture* frame)
|
|
{
|
|
bool preserve_center = frames.size() > 0;
|
|
frames.push_back(frame);
|
|
Frameset& all_frames_frameset = get_all_frames_frameset();
|
|
all_frames_frameset.clear();
|
|
for (std::size_t ii = 0; ii < frames.size(); ii++)
|
|
{
|
|
all_frames_frameset.add_frame_indicies(ii);
|
|
}
|
|
for (auto& [name, frameset] : framesets)
|
|
{
|
|
frameset.set_size();
|
|
}
|
|
update_size(preserve_center);
|
|
}
|
|
|
|
void Sprite::add_frames(const std::vector<SDL_Texture*>& frames)
|
|
{
|
|
for (SDL_Texture* frame : frames)
|
|
{
|
|
add_frames(frame);
|
|
}
|
|
}
|
|
|
|
const std::vector<SDL_Texture*>& Sprite::get_frames() const
|
|
{
|
|
return frames;
|
|
}
|
|
|
|
Sprite::Frameset& Sprite::get_all_frames_frameset()
|
|
{
|
|
return framesets[configuration()["animation"]["all-frames-frameset-name"]];
|
|
}
|
|
|
|
Sprite::Frameset& Sprite::add_frameset(std::string name)
|
|
{
|
|
if (framesets.find(name) == framesets.end())
|
|
{
|
|
framesets[name] = Frameset(this);
|
|
}
|
|
return framesets[name];
|
|
}
|
|
|
|
Sprite::Frameset& Sprite::set_frameset(std::string name)
|
|
{
|
|
current_frameset_name = name;
|
|
frame_animation.set_frame_length(get_current_frameset().get_frame_length());
|
|
if (is_loaded())
|
|
{
|
|
update_size(true);
|
|
}
|
|
return get_current_frameset();
|
|
}
|
|
|
|
Sprite::Frameset& Sprite::get_current_frameset()
|
|
{
|
|
return framesets.at(current_frameset_name);
|
|
}
|
|
|
|
const Sprite::Frameset& Sprite::get_current_frameset() const
|
|
{
|
|
return framesets.at(current_frameset_name);
|
|
}
|
|
|
|
void Sprite::set_frame_length(float length)
|
|
{
|
|
get_current_frameset().set_frame_length(length);
|
|
}
|
|
|
|
SDL_Texture* Sprite::get_current_frame() const
|
|
{
|
|
if (frames.size() == 0)
|
|
{
|
|
return nullptr;
|
|
}
|
|
else
|
|
{
|
|
return frames[get_current_frameset().get_current_frame_index()];
|
|
}
|
|
}
|
|
|
|
const Box& Sprite::get_box(int index) const
|
|
{
|
|
return get_boxes()[index];
|
|
}
|
|
|
|
const std::vector<Box>& Sprite::get_boxes() const
|
|
{
|
|
return boxes;
|
|
}
|
|
|
|
void Sprite::add_box(glm::vec2 position, bool absolute)
|
|
{
|
|
if (!absolute)
|
|
{
|
|
position += get_nw();
|
|
}
|
|
boxes.emplace_back(glm::vec2(position.x, position.y), glm::vec2(get_w(), get_h()));
|
|
}
|
|
|
|
void Sprite::update_size(bool preserve_center)
|
|
{
|
|
for (std::size_t ii = 0; ii < boxes.size(); ii++)
|
|
{
|
|
boxes[ii].size(get_current_frameset().get_size(), preserve_center);
|
|
if (scale != 1)
|
|
{
|
|
boxes[ii].scale(scale, preserve_center);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Sprite::set_scale(float s)
|
|
{
|
|
scale = s;
|
|
update_size(true);
|
|
}
|
|
|
|
void Sprite::set_scale_quality(const std::string& quality)
|
|
{
|
|
scale_quality = quality;
|
|
}
|
|
|
|
float Sprite::get_scale() const
|
|
{
|
|
return scale;
|
|
}
|
|
|
|
bool Sprite::is_loaded() const
|
|
{
|
|
return !frames.empty();
|
|
}
|
|
|
|
void Sprite::unload()
|
|
{
|
|
while (!frames.empty())
|
|
{
|
|
if (!leave_memory_allocated)
|
|
{
|
|
SDL_DestroyTexture(frames.back());
|
|
}
|
|
frames.pop_back();
|
|
}
|
|
boxes = {{{0, 0}, {0, 0}}};
|
|
}
|
|
|
|
void Sprite::advance_frame()
|
|
{
|
|
get_current_frameset().step();
|
|
}
|
|
|
|
void Sprite::hide()
|
|
{
|
|
hidden = true;
|
|
for (Child& child : children)
|
|
{
|
|
child.sprite.hide();
|
|
}
|
|
}
|
|
|
|
void Sprite::unhide()
|
|
{
|
|
hidden = false;
|
|
for (Child& child : children)
|
|
{
|
|
child.sprite.unhide();
|
|
}
|
|
}
|
|
|
|
void Sprite::toggle_hidden()
|
|
{
|
|
if (is_hidden())
|
|
{
|
|
unhide();
|
|
}
|
|
else
|
|
{
|
|
hide();
|
|
}
|
|
}
|
|
|
|
bool Sprite::is_hidden() const
|
|
{
|
|
return hidden;
|
|
}
|
|
|
|
void Sprite::set_step(glm::vec2 s)
|
|
{
|
|
step.x = s.x;
|
|
step.y = s.y;
|
|
}
|
|
|
|
void Sprite::set_alpha_mod(Uint8 mod)
|
|
{
|
|
alpha_mod = mod;
|
|
}
|
|
|
|
Uint8 Sprite::get_alpha_mod() const
|
|
{
|
|
return alpha_mod;
|
|
}
|
|
|
|
void Sprite::set_color_mod(const SDL_Color& color)
|
|
{
|
|
color_mod = color;
|
|
}
|
|
|
|
const SDL_Color& Sprite::get_color_mod() const
|
|
{
|
|
return color_mod;
|
|
}
|
|
|
|
float Sprite::get_w() const
|
|
{
|
|
return get_box().width();
|
|
}
|
|
|
|
float Sprite::get_h() const
|
|
{
|
|
return get_box().height();
|
|
}
|
|
|
|
glm::vec2 Sprite::get_size() const
|
|
{
|
|
return get_box().size();
|
|
}
|
|
|
|
float Sprite::get_top(int index) const
|
|
{
|
|
return get_box(index).top();
|
|
}
|
|
|
|
float Sprite::get_right(int index) const
|
|
{
|
|
return get_box(index).right();
|
|
}
|
|
|
|
float Sprite::get_bottom(int index) const
|
|
{
|
|
return get_box(index).bottom();
|
|
}
|
|
|
|
float Sprite::get_left(int index) const
|
|
{
|
|
return get_box(index).left();
|
|
}
|
|
|
|
float Sprite::get_center_x(int index) const
|
|
{
|
|
return get_box(index).cx();
|
|
}
|
|
|
|
float Sprite::get_center_y(int index) const
|
|
{
|
|
return get_box(index).cy();
|
|
}
|
|
|
|
glm::vec2 Sprite::get_nw(int index) const
|
|
{
|
|
return get_box(index).nw();
|
|
}
|
|
|
|
glm::vec2 Sprite::get_north(int index) const
|
|
{
|
|
return get_box(index).north();
|
|
}
|
|
|
|
glm::vec2 Sprite::get_ne(int index) const
|
|
{
|
|
return get_box(index).ne();
|
|
}
|
|
|
|
glm::vec2 Sprite::get_east(int index) const
|
|
{
|
|
return get_box(index).east();
|
|
}
|
|
|
|
glm::vec2 Sprite::get_se(int index) const
|
|
{
|
|
return get_box(index).se();
|
|
}
|
|
|
|
glm::vec2 Sprite::get_south(int index) const
|
|
{
|
|
return get_box(index).south();
|
|
}
|
|
|
|
glm::vec2 Sprite::get_sw(int index) const
|
|
{
|
|
return get_box(index).sw();
|
|
}
|
|
|
|
glm::vec2 Sprite::get_west(int index) const
|
|
{
|
|
return get_box(index).west();
|
|
}
|
|
|
|
glm::vec2 Sprite::get_center(int index) const
|
|
{
|
|
return get_box(index).center();
|
|
}
|
|
|
|
void Sprite::set_top(float top)
|
|
{
|
|
move({0, top - get_top()});
|
|
}
|
|
|
|
void Sprite::set_right(float right)
|
|
{
|
|
move({right - get_right(), 0});
|
|
}
|
|
|
|
void Sprite::set_bottom(float bottom)
|
|
{
|
|
move({0, bottom - get_bottom()});
|
|
}
|
|
|
|
void Sprite::set_left(float left)
|
|
{
|
|
move({left - get_left(), 0});
|
|
}
|
|
|
|
void Sprite::set_center_x(float x)
|
|
{
|
|
move({x - get_center_x(), 0});
|
|
}
|
|
|
|
void Sprite::set_center_y(float y)
|
|
{
|
|
move({0, y - get_center_y()});
|
|
}
|
|
|
|
void Sprite::set_nw(const glm::vec2& nw)
|
|
{
|
|
move(nw - get_nw());
|
|
}
|
|
|
|
void Sprite::set_north(const glm::vec2& north)
|
|
{
|
|
move(north - get_north());
|
|
}
|
|
|
|
void Sprite::set_ne(const glm::vec2& ne)
|
|
{
|
|
move(ne - get_ne());
|
|
}
|
|
|
|
void Sprite::set_se(const glm::vec2& se)
|
|
{
|
|
move(se - get_se());
|
|
}
|
|
|
|
void Sprite::set_south(const glm::vec2& south)
|
|
{
|
|
move(south - get_south());
|
|
}
|
|
|
|
void Sprite::set_sw(const glm::vec2& sw)
|
|
{
|
|
move(sw - get_sw());
|
|
}
|
|
|
|
void Sprite::set_west(const glm::vec2& west)
|
|
{
|
|
move(west - get_west());
|
|
}
|
|
|
|
void Sprite::set_center(const glm::vec2& center)
|
|
{
|
|
move(center - get_center());
|
|
}
|
|
|
|
void Sprite::add_wrap(bool x, bool y)
|
|
{
|
|
add_wrap(x, y, get_display().window_box());
|
|
}
|
|
|
|
void Sprite::add_wrap(bool x, bool y, Box frame)
|
|
{
|
|
wrap = {x, y};
|
|
int original_box_count = boxes.size();
|
|
for (int ii = 0; ii < original_box_count; ii++)
|
|
{
|
|
if (x)
|
|
{
|
|
add_box({frame.width(), 0});
|
|
}
|
|
if (y)
|
|
{
|
|
add_box({0, frame.height()});
|
|
}
|
|
if (x && y)
|
|
{
|
|
add_box({frame.width(), frame.height()});
|
|
}
|
|
}
|
|
wrap_frame = frame;
|
|
}
|
|
|
|
void Sprite::add_hue_shift_frames(int count)
|
|
{
|
|
float step = 360 / (count + 1);
|
|
SDL_Texture* base = get_current_frame();
|
|
for (float offset = step; offset <= 359.9; offset += step)
|
|
{
|
|
add_frames(sb::get_hue_shifted_texture(get_renderer(), base, offset));
|
|
}
|
|
}
|
|
|
|
glm::vec2 Sprite::move(const glm::vec2& delta)
|
|
{
|
|
for (Box& box : boxes)
|
|
{
|
|
box.move(delta);
|
|
}
|
|
if (wrap.x)
|
|
{
|
|
if (get_right() > wrap_frame.right())
|
|
{
|
|
move({-wrap_frame.width(), 0});
|
|
}
|
|
else if (get_right() < wrap_frame.left())
|
|
{
|
|
move({wrap_frame.width(), 0});
|
|
}
|
|
}
|
|
if (wrap.y)
|
|
{
|
|
if (get_bottom() > wrap_frame.bottom())
|
|
{
|
|
move({0, -wrap_frame.height()});
|
|
}
|
|
else if (get_bottom() < wrap_frame.top())
|
|
{
|
|
move({0, wrap_frame.height()});
|
|
}
|
|
}
|
|
return delta;
|
|
}
|
|
|
|
glm::vec2 Sprite::move_weighted(const glm::vec2& delta)
|
|
{
|
|
glm::vec2 delta_weighted = get_root()->weight(delta);
|
|
move(delta_weighted);
|
|
return delta_weighted;
|
|
}
|
|
|
|
bool Sprite::collide(const glm::vec2& point, bool all) const
|
|
{
|
|
if (!all)
|
|
{
|
|
return get_box().collide(point);
|
|
}
|
|
else
|
|
{
|
|
for (const Box& box : boxes)
|
|
{
|
|
if (box.collide(point))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Sprite::collide(const Segment& segment, glm::vec2* intersection, bool all) const
|
|
{
|
|
if (!all)
|
|
{
|
|
return get_box().collide(segment, intersection);
|
|
}
|
|
else
|
|
{
|
|
for (const Box& box : boxes)
|
|
{
|
|
if (box.collide(segment, intersection))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Sprite::collide(const Segment& segment, glm::vec2& intersection, bool all) const
|
|
{
|
|
return collide(segment, &intersection, all);
|
|
}
|
|
|
|
bool Sprite::collide(const Box& box, bool precise, Box* overlap, bool all, SDL_Texture* other_texture) const
|
|
{
|
|
Box o;
|
|
if (precise)
|
|
{
|
|
int texture_access;
|
|
SDL_QueryTexture(get_current_frame(), nullptr, &texture_access, nullptr, nullptr);
|
|
if (texture_access != SDL_TEXTUREACCESS_TARGET)
|
|
{
|
|
SDL_LogWarn(SDL_LOG_CATEGORY_ERROR,
|
|
"can't do precise collision detection on texture without target access");
|
|
precise = false;
|
|
}
|
|
else if (other_texture != nullptr)
|
|
{
|
|
SDL_QueryTexture(other_texture, nullptr, &texture_access, nullptr, nullptr);
|
|
if (texture_access != SDL_TEXTUREACCESS_TARGET)
|
|
{
|
|
SDL_LogWarn(SDL_LOG_CATEGORY_ERROR,
|
|
"can't use other texture in precise collision detection without target access");
|
|
other_texture = nullptr;
|
|
}
|
|
}
|
|
if (precise && overlap == nullptr)
|
|
{
|
|
overlap = &o;
|
|
}
|
|
}
|
|
for (auto ii = 0; ii < static_cast<int>(get_boxes().size()); ii++)
|
|
{
|
|
if (get_box(ii).collide(box, overlap))
|
|
{
|
|
if (precise)
|
|
{
|
|
bool collision_detected = false;
|
|
SDL_Texture* collision_check_frame;
|
|
if (get_scale() == 1)
|
|
{
|
|
collision_check_frame = get_current_frame();
|
|
}
|
|
else
|
|
{
|
|
collision_check_frame = sb::duplicate_texture(
|
|
const_cast<SDL_Renderer*>(get_renderer()), get_current_frame(), get_box(ii).size());
|
|
}
|
|
Pixels region_pixels = Pixels(
|
|
const_cast<SDL_Renderer*>(get_renderer()), collision_check_frame, overlap->stamp(-get_nw(ii)));
|
|
if (other_texture == nullptr)
|
|
{
|
|
for (int x = 0; x < region_pixels.rect.w; x++)
|
|
{
|
|
for (int y = 0; y < region_pixels.rect.h; y++)
|
|
{
|
|
if (region_pixels.get(x, y).a > 0)
|
|
{
|
|
collision_detected = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Pixels other_region_pixels = Pixels(
|
|
const_cast<SDL_Renderer*>(get_renderer()), other_texture, overlap->stamp(-box.nw()));
|
|
for (int x = 0; x < region_pixels.rect.w && x < other_region_pixels.rect.w; x++)
|
|
{
|
|
for (int y = 0; y < region_pixels.rect.h && y < other_region_pixels.rect.h; y++)
|
|
{
|
|
if (region_pixels.get(x, y).a > 0 && other_region_pixels.get(x, y).a > 0)
|
|
{
|
|
collision_detected = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (get_scale() != 1)
|
|
{
|
|
SDL_DestroyTexture(collision_check_frame);
|
|
}
|
|
if (collision_detected)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
if (!all)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Sprite::collide(const Box& box, Box& overlap, bool precise, bool all) const
|
|
{
|
|
return collide(box, precise, &overlap, all);
|
|
}
|
|
|
|
bool Sprite::collide(const Sprite& sprite, bool precise, Box* overlap, bool all, bool all_other) const
|
|
{
|
|
SDL_Texture* other_sprite_collision_check_texture = nullptr;
|
|
int limit;
|
|
bool collision = false;
|
|
if (all_other)
|
|
{
|
|
limit = sprite.get_boxes().size();
|
|
}
|
|
else
|
|
{
|
|
limit = 1;
|
|
}
|
|
for (int ii = 0; ii < limit; ii++)
|
|
{
|
|
if (precise)
|
|
{
|
|
if (sprite.get_scale() == 1)
|
|
{
|
|
other_sprite_collision_check_texture = sprite.get_current_frame();
|
|
}
|
|
else
|
|
{
|
|
other_sprite_collision_check_texture = sb::duplicate_texture(
|
|
const_cast<SDL_Renderer*>(get_renderer()), sprite.get_current_frame(), sprite.get_box(ii).size());
|
|
}
|
|
}
|
|
if (collide(sprite.get_box(ii), precise, overlap, all, other_sprite_collision_check_texture))
|
|
{
|
|
collision = true;
|
|
break;
|
|
}
|
|
}
|
|
if (sprite.get_scale() != 1)
|
|
{
|
|
SDL_DestroyTexture(other_sprite_collision_check_texture);
|
|
}
|
|
return collision;
|
|
}
|
|
|
|
bool Sprite::collide(const Sprite& sprite, Box& overlap, bool precise, bool all, bool all_other) const
|
|
{
|
|
return collide(sprite, precise, &overlap, all, all_other);
|
|
}
|
|
|
|
void Sprite::wipe(float delay)
|
|
{
|
|
wipe_blinds = sb::get_blinds_boxes(get_size());
|
|
if (wipe_increment < 0)
|
|
{
|
|
wipe_index = static_cast<int>(wipe_blinds.size() - 1);
|
|
}
|
|
else
|
|
{
|
|
wipe_index = 0;
|
|
}
|
|
wipe_animation.play(delay);
|
|
for (Child& child : children)
|
|
{
|
|
child.sprite.wipe(delay);
|
|
}
|
|
}
|
|
|
|
void Sprite::advance_wipe_frame()
|
|
{
|
|
wipe_index += wipe_increment;
|
|
if (wipe_index < 0 || wipe_index >= static_cast<int>(wipe_blinds.size()))
|
|
{
|
|
if (wipe_index < 0)
|
|
{
|
|
wipe_index = static_cast<int>(wipe_blinds.size() - 1);
|
|
hide();
|
|
}
|
|
else
|
|
{
|
|
wipe_index = 0;
|
|
}
|
|
wipe_animation.reset();
|
|
}
|
|
}
|
|
|
|
const std::vector<Box>& Sprite::get_current_wipe_blinds() const
|
|
{
|
|
return wipe_blinds[wipe_index];
|
|
}
|
|
|
|
void Sprite::reverse_wipe_direction()
|
|
{
|
|
wipe_increment *= -1;
|
|
}
|
|
|
|
Sprite& Sprite::insert_child(std::string name, std::list<Child>::iterator position)
|
|
{
|
|
children.emplace(position, name, this);
|
|
return get_child(name);
|
|
}
|
|
|
|
Sprite& Sprite::insert_child(std::string name, std::string before)
|
|
{
|
|
return insert_child(name, std::find(children.begin(), children.end(), before));
|
|
}
|
|
|
|
Sprite& Sprite::insert_child(std::string name, int index)
|
|
{
|
|
auto position = children.begin();
|
|
for (int ii = 0; position != children.end(); ii++, position++)
|
|
{
|
|
if (ii == index)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return insert_child(name, position);
|
|
}
|
|
|
|
Sprite& Sprite::insert_child(std::string name)
|
|
{
|
|
return insert_child(name, children.size());
|
|
}
|
|
|
|
Sprite& Sprite::get_child(std::string name)
|
|
{
|
|
auto position = std::find(children.begin(), children.end(), name);
|
|
if (position == children.end())
|
|
{
|
|
throw std::runtime_error("child not found");
|
|
}
|
|
return position->sprite;
|
|
}
|
|
|
|
bool Sprite::has_child(std::string name) const
|
|
{
|
|
return std::find(children.begin(), children.end(), name) != children.end();
|
|
}
|
|
|
|
void Sprite::remove_child(std::string name)
|
|
{
|
|
auto position = std::find(children.begin(), children.end(), name);
|
|
if (position != children.end())
|
|
{
|
|
children.erase(position);
|
|
}
|
|
}
|
|
|
|
void Sprite::set_draw_children_on_frame(bool on_frame)
|
|
{
|
|
draw_children_on_frame = on_frame;
|
|
}
|
|
|
|
void Sprite::update(const std::vector<Box>& subsections)
|
|
{
|
|
if (is_active())
|
|
{
|
|
if (step != glm::vec2(0, 0))
|
|
{
|
|
move_weighted(step);
|
|
}
|
|
frame_animation.update();
|
|
blink_animation.update();
|
|
wipe_animation.update();
|
|
toggle_hidden_animation.update();
|
|
SDL_Texture* texture = get_current_frame();
|
|
if (is_loaded() && !is_hidden() && get_current_frameset().get_frame_count())
|
|
{
|
|
SDL_Renderer* renderer = get_root()->renderer;
|
|
SDL_SetTextureAlphaMod(texture, alpha_mod);
|
|
SDL_SetTextureColorMod(texture, color_mod.r, color_mod.g, color_mod.b);
|
|
SDL_SetRenderTarget(renderer, get_canvas());
|
|
if (wrap.x || wrap.y)
|
|
{
|
|
SDL_Rect wrap_frame_rect = wrap_frame;
|
|
SDL_RenderSetClipRect(renderer, &wrap_frame_rect);
|
|
}
|
|
for (std::size_t box_ii = 0; box_ii < boxes.size(); box_ii++)
|
|
{
|
|
if (subsections.size() == 0 && !wipe_animation.playing(false))
|
|
{
|
|
SDL_RenderCopyF(renderer, texture, nullptr, &boxes[box_ii]);
|
|
}
|
|
else
|
|
{
|
|
if (wipe_animation.playing(false))
|
|
{
|
|
for (const Box& blind : get_current_wipe_blinds())
|
|
{
|
|
render_subsection(renderer, texture, blind, get_box(box_ii));
|
|
}
|
|
}
|
|
for (const Box& subsection : subsections)
|
|
{
|
|
render_subsection(renderer, texture, subsection, get_box(box_ii));
|
|
}
|
|
}
|
|
}
|
|
if (wrap.x || wrap.y)
|
|
{
|
|
SDL_RenderSetClipRect(renderer, nullptr);
|
|
}
|
|
}
|
|
for (Child& child : children)
|
|
{
|
|
if (draw_children_on_frame)
|
|
{
|
|
child.sprite.set_canvas(texture);
|
|
}
|
|
else
|
|
{
|
|
child.sprite.set_canvas(get_canvas());
|
|
child_relative_position = child.sprite.get_nw();
|
|
child.sprite.move(get_nw());
|
|
}
|
|
child.sprite.update();
|
|
if (!draw_children_on_frame)
|
|
{
|
|
child.sprite.set_nw(child_relative_position);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Sprite::update()
|
|
{
|
|
update({});
|
|
}
|
|
|
|
void Sprite::render_subsection(SDL_Renderer* renderer, SDL_Texture* texture, const Box& subsection, const Box& box)
|
|
{
|
|
bottom_save = std::round(subsection.bottom());
|
|
subsection_int_rect = SDL_Rect(subsection);
|
|
subsection_int_rect.y += bottom_save - (subsection_int_rect.y + subsection_int_rect.h);
|
|
subsection_destination = subsection_int_rect;
|
|
subsection_destination.x += box.left();
|
|
subsection_destination.y += box.top();
|
|
if (get_scale() != 1)
|
|
{
|
|
unscaled_subsection = subsection;
|
|
unscaled_subsection.nw(unscaled_subsection.nw() / get_scale());
|
|
unscaled_subsection.size(unscaled_subsection.size() / get_scale());
|
|
subsection_int_rect = unscaled_subsection;
|
|
}
|
|
SDL_RenderCopy(renderer, texture, &subsection_int_rect, &subsection_destination);
|
|
}
|
|
|
|
void Sprite::set_to_leave_memory_allocated()
|
|
{
|
|
leave_memory_allocated = true;
|
|
}
|
|
|
|
void Sprite::set_to_deallocate_memory()
|
|
{
|
|
leave_memory_allocated = false;
|
|
}
|
|
|
|
Sprite::Frameset::Frameset() : Frameset(NULL) {}
|
|
|
|
Sprite::Frameset::Frameset(Sprite* sprite) : sprite(sprite) {}
|
|
|
|
void Sprite::Frameset::add_frame_indicies(int index)
|
|
{
|
|
order.push_back(index);
|
|
set_size();
|
|
}
|
|
|
|
void Sprite::Frameset::set_frame_length(float length)
|
|
{
|
|
frame_length = length;
|
|
if (&sprite->get_current_frameset() == this)
|
|
{
|
|
sprite->frame_animation.set_frame_length(length);
|
|
}
|
|
}
|
|
|
|
float Sprite::Frameset::get_frame_length() const
|
|
{
|
|
return frame_length;
|
|
}
|
|
|
|
void Sprite::Frameset::reset()
|
|
{
|
|
set_order_index(0);
|
|
}
|
|
|
|
void Sprite::Frameset::clear()
|
|
{
|
|
order.clear();
|
|
reset();
|
|
}
|
|
|
|
int Sprite::Frameset::get_order_index() const
|
|
{
|
|
return order_index;
|
|
}
|
|
|
|
void Sprite::Frameset::set_order_index(int index)
|
|
{
|
|
order_index = index;
|
|
}
|
|
|
|
int Sprite::Frameset::get_current_frame_index() const
|
|
{
|
|
return order[get_order_index()];
|
|
}
|
|
|
|
glm::vec2 Sprite::Frameset::measure() const
|
|
{
|
|
glm::vec2 s(0, 0);
|
|
int w, h;
|
|
for (std::size_t index : order)
|
|
{
|
|
if (index < sprite->get_frames().size())
|
|
{
|
|
SDL_QueryTexture(sprite->get_frames()[index], nullptr, nullptr, &w, &h);
|
|
s.x = std::max(static_cast<float>(w * sprite->get_scale()), s.x);
|
|
s.y = std::max(static_cast<float>(h * sprite->get_scale()), s.y);
|
|
}
|
|
}
|
|
return s;
|
|
}
|
|
|
|
void Sprite::Frameset::set_size()
|
|
{
|
|
set_size(measure());
|
|
}
|
|
|
|
void Sprite::Frameset::set_size(const glm::vec2& s)
|
|
{
|
|
size = s;
|
|
}
|
|
|
|
const glm::vec2& Sprite::Frameset::get_size() const
|
|
{
|
|
return size;
|
|
}
|
|
|
|
void Sprite::Frameset::step()
|
|
{
|
|
if (order.size() > 0)
|
|
{
|
|
increment_index();
|
|
}
|
|
}
|
|
|
|
void Sprite::Frameset::increment_index()
|
|
{
|
|
increment_index(reversed ? -1 : 1);
|
|
}
|
|
|
|
void Sprite::Frameset::increment_index(int increment)
|
|
{
|
|
set_order_index((order_index + increment) % order.size());
|
|
}
|
|
|
|
int Sprite::Frameset::get_frame_count() const
|
|
{
|
|
return order.size();
|
|
}
|
|
|
|
void Sprite::Frameset::reverse()
|
|
{
|
|
reversed = !reversed;
|
|
}
|
|
|
|
Pixels::Pixels(Sprite& sprite) : Pixels(sprite.get_renderer(), sprite.get_current_frame()) {}
|
|
Pixels::Pixels(Sprite& sprite, const Box& box) : Pixels(sprite.get_renderer(), sprite.get_current_frame(), box) {}
|
|
|
|
Segment::Segment(const Sprite& start, const Sprite& end) : Segment(start.get_center(), end.get_center()) {}
|