/** Animations are structured in AnimationData as follows: .colors contains .color_count*3 uint8_t values for R, G and B. .offsets contains the frame start offsets within .data + the length of the data. (So you can always do something like `for (int i=anim.offsets[i]; idata = d; this->endFrame = d->frame_count-1; this->colors = new CRGB[this->data->color_count]; uint8_t *color_data = new uint8_t[this->data->color_count * 3]; memcpy_P(color_data, this->data->colors, this->data->color_count * 3); for (int i = 0; idata->color_count; i++) colors[i] = CRGB(color_data[i * 3], color_data[i * 3 + 1], color_data[i * 3 + 2]); delete color_data; int length = this->data->offsets[this->data->frame_count]; this->animation_data = new uint8_t[length]; memcpy_P(this->animation_data, this->data->data, length); } void Animation::setFgColor(CRGB* fg_color) { this->fgColor = fg_color; } void Animation::setBgColor(CRGB* bg_color) { this->bgColor = bg_color; } bool Animation::invert() { if (this->fgColor == NULL) return false; CRGB* temp = this->fgColor; this->fgColor = this->bgColor; this->bgColor = temp; return true; } void Animation::setOffsets(int8_t x, int8_t y) { this->xOffset = x; this->yOffset = y; } void Animation::setStartFrame(uint8_t sf) { if (sf <= this->endFrame && sf < this->data->frame_count ) this->startFrame = sf; } void Animation::setEndFrame(uint8_t ef) { if (ef >= this->startFrame && ef < this->data->frame_count) this->endFrame = ef; } void Animation::setFrameRange(uint8_t sf, uint8_t ef) { if (sf<=ef && ef < this->data->frame_count) { this->startFrame = sf; this->endFrame = ef; } } void Animation::setSingleFrame(uint8_t frame) { if (frame < this->data->frame_count) { this->startFrame = frame; this->endFrame = frame; } } Animation::~Animation() { delete this->colors; delete this->animation_data; } void Animation::draw(Window* win) { for (uint16_t i=0; icurrentFrame; i++) this->drawFrame(win, i); } void Animation::drawFrame(Window* win) { this->drawFrame(win, currentFrame); } void Animation::drawFrame(Window* win, uint8_t frame_index) { uint16_t led_index = 0; for (uint16_t i=this->data->offsets[frame_index]; idata->offsets[frame_index + 1]; i++) { uint8_t color_index; uint8_t count = 1; if (this->animation_data[i]==255) { // Run-length encoded data color_index = this->animation_data[i + 2]; count = this->animation_data[i + 1]; i += 2; } else { color_index = this->animation_data[i]; } if (color_index == 0) { // color #0 = skip this pixels led_index += count; } else { CRGB* color = this->getColor(color_index); for (int j=0; jdrawPixel(win, led_index++, color); } } } bool Animation::advance() { if (this->currentFrameSince == 0) { this->currentFrameSince = millis(); } else if (this->currentFrameSince + this->getFrameDelay(currentFrame) < millis() || this->currentFrameSince > millis()) { currentFrame++; if (currentFrame > endFrame) currentFrame = startFrame; this->currentFrameSince = millis(); return true; } return false; } void Animation::drawPixel(Window* win, int index, CRGB* color) { uint8_t x = this->xOffset + (index % this->data->w); uint8_t y = this->yOffset + (index / this->data->h); win->setPixel(x, y, color); } uint16_t Animation::getFrameDelay(int frame) { if (this->data->individual_delays) return this->data->delays[frame]; return this->data->delays[0]; } CRGB* Animation::getColor(uint8_t index) { if (index==1) return this->bgColor; else if (this->fgColor != NULL) return this->fgColor; else return &(this->colors[index - 2]); }