Program Listing for File animation.cpp

Return to documentation for file (src/animation/animation.cpp)

/*
 * Animation - Base class for rendering Animations on a Section.
 */

#include "animation.h"

namespace PixelMaestro {
    Animation::Animation(Section& section) : section_(section) {
        this->timer_ = new AnimationTimer(*this);
        rebuild_map();
        initialized_ = true;
    }

    Point& Animation::get_center() const {
        return const_cast<Point&>(center_);
    }

    uint8_t Animation::get_cycle_index() const {
        return cycle_index_;
    }

    bool Animation::get_fade() const {
        return fade_;
    }

    Animation::Orientation Animation::get_orientation() const {
        return orientation_;
    }

    Palette* Animation::get_palette() const {
        return palette_;
    }

    bool Animation::get_reverse() const {
        return reverse_;
    }

    Section& Animation::get_section() const {
        return section_;
    }

    AnimationTimer* Animation::get_timer() const {
        return timer_;
    }

    AnimationType Animation::get_type() const {
        return type_;
    }

    void Animation::rebuild_map() {
        // Regenerate the color-to-pixel mapping.
        for (uint16_t y = 0; y < dimensions_.y; y++) {
            delete [] map_[y];
        }
        delete [] map_;

        dimensions_ = section_.get_dimensions();

        map_ = new uint8_t*[dimensions_.y];
        for (uint16_t y = 0; y < dimensions_.y; y++) {
            map_[y] = new uint8_t[dimensions_.x] {0};
        }

        set_center(dimensions_.x / 2, dimensions_.y / 2);
    }

    void Animation::set_center(uint16_t x, uint16_t y) {
        center_.set(x, y);
        if (initialized_) map();
    }

    void Animation::set_cycle_index(uint8_t index) {
        if (palette_ != nullptr && index > palette_->get_num_colors()) {
            index %= palette_->get_num_colors();
        }

        cycle_index_ = index;
    }

    void Animation::set_fade(bool fade) {
        fade_ = fade;
        timer_->recalculate_step_count();
    }

    void Animation::set_map_color_index(uint16_t x, uint16_t y, uint8_t color_index) {
        if (orientation_ == Orientation::HorizontalFlipped || orientation_ == Orientation::VerticalFlipped) {
            map_[(dimensions_.y - 1) - y][(dimensions_.x - 1) - x] = color_index;
        }
        else {
            map_[y][x] = color_index;
        }
    }

    void Animation::set_orientation(Orientation orientation) {
        this->orientation_ = orientation;
        map();
    }

    void Animation::set_palette(Palette& palette) {
        this->palette_ = &palette;
    }

    void Animation::set_reverse(bool reverse) {
        this->reverse_ = reverse;
    }

    AnimationTimer& Animation::set_timer(uint16_t speed, uint16_t delay) {
        timer_->set_interval(speed, delay);
        timer_->recalculate_step_count();

        return *timer_;
    }

    bool Animation::update(const uint32_t &current_time) {
        // If the color palette is not set, exit.
        if (palette_ == nullptr || palette_->get_num_colors() == 0) return false;

        if (timer_->update(current_time)) {
            // Call the derived Animation's update routine
            update();
            section_.set_step_count(timer_->get_step_count());
            for (uint16_t x = 0; x < section_.get_dimensions().x; x++) {
                for (uint16_t y = 0; y < section_.get_dimensions().y; y++) {
                    // Color index 255 reserved for black
                    if (map_[y][x] == 255) {
                        section_.set_pixel_color(x, y, Colors::RGB(0, 0, 0));
                    }
                    else {
                        section_.set_pixel_color(x,
                            y,
                            palette_->get_color_at_index(map_[y][x] + cycle_index_)
                        );
                    }
                }
            }

            return true;
        }

        return false;
    }

    void Animation::update_cycle(uint8_t min, uint8_t max) {
        if (reverse_) {
            if (cycle_index_ == 0) {
                cycle_index_ = max - 1;
            }
            else {
                cycle_index_--;
            }
        }
        else {
            if (cycle_index_ >= max - 1) {
                cycle_index_ = min;
            }
            else {
                cycle_index_++;
            }
        }
    }

    Animation::~Animation() {
        delete timer_;

        // Destroy the map
        for (uint16_t y = 0; y < dimensions_.y; y++) {
            delete [] map_[y];
        }
        delete [] map_;
    }
}