Skip to content

Commit

Permalink
Canvas - Reverted get_pixel_color() removal and rendering changes.
Browse files Browse the repository at this point in the history
Section - Changed brightness to float to reduce repeating calculations.
Colors - Changed pointers to references.
Arduino - Updated examples.
  • Loading branch information
8bitbuddhist committed May 9, 2019
1 parent 68e61e5 commit d26aeac
Show file tree
Hide file tree
Showing 14 changed files with 135 additions and 89 deletions.
43 changes: 30 additions & 13 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,63 @@ All notable changes to PixelMaestro will be documented in this file.

The format is loosely based on [Keep a Changelog](http://keepachangelog.com/).

## [v2.0] - In Progress
IMPORTANT: This version changes the API for many objects. For example, adding an Animation has changed from this:
## [v2.0.0] - In Progress

### Important Changes

#### API Changes

This version introduces significant API changes and changes many pointers to references. For example, adding an Animation has changed from:

```c++
Section* section = maestro.get_section(0);
section->set_animation(AnimationType::Blink);
```
to this:
to:
```c++
Section& section = maestro.get_section(0);
section.set_animation(AnimationType::Blink);
```

The following Cues have been modified. Any Cuefiles containing these Cues will need to be regenerated:
- `AnimationCueHandler::set_wave_options`: removed mirror option
- `CanvasCueHandler::draw_frame`: converted grid size from uint8_t to uint16_t
#### Canvas-related Changes

Canvas drawing methods and Cues now require you to specify which frame to draw on. This means you can draw on a frame without having to switch to it first. For example, drawing a point has changed from this:

```c++
canvas.set_current_frame_index(5);
canvas.draw_point(x, y);
```

to this:

```c++
canvas.draw_point(5, x, y);
```

### Added
- Added ability to mirror Sections across the x and/or y axes.
- Added `Point::in_bounds(x, y)`, which checks whether the coordinates provided are within the boundaries of the Point.
- Added `Point::in_bounds(x, y)`, which checks whether the coordinates provided are within the boundaries of the Point (when used as a dimension).
- Added CueHandler helper functions for generating Cues.
- Added the `#define DISABLE_COLOR_BUFFER` preprocessor directive to disable the color fade buffer in Pixels.h. This enables devices with limited memory to support more Pixels at the cost of no color fading.

### Changed
- Changed many pointers to references. This will require you to change your sketches.
- Changed several internal pointers to references. This may require code changes, e.g. to Arduino sketches.
- Revised rendering logic to improve performance:
- Sections now draw Canvas output directly to Pixels, instead of layering them in `Section::get_pixel_color()`.
- The `MappedAnimation` class was merged into the base `Animation` class. All Animations now use maps to store color data.
- Pixels now use the new `Step` struct to determine how to change their color on each update.
- Merged the `MappedAnimation` into the base `Animation` class. All Animations now use maps to store color data per frame.
- Pixels now use a new `Step` struct to store color change amounts on each update. This can be disabled by uncommenting `#define DISABLE_COLOR_BUFFER` in Pixel.h.
- Rewrote CueHandlers to reduce program size.
- Fixed `CanvasCueHandler::draw_frame()` not supporting Canvases larger than 255x255.
- Fixed `CanvasCueHandler::draw_frame()` not supporting frames larger than 255x255.
- Added buffer overflow check to `CanvasCueHandler::draw_frame()`.
- Fixed Show crash when enabling relative time and looping after the Show has already ended.

### Removed
- Removed `Pixel::next_step_` to reduce memory usage.
- Wave animation mirror option.
- Removed `WaveAnimation` mirror option.
- Removed `Canvas::in_bounds()` (see `Point::in_bounds()` instead).
- Removed `Canvas::get_pixel_color()` (see `Section::get_pixel_color()` instead).
- Removed mirror option in `AnimationCueHandler::set_wave_options`.

## [v1.0.2] - 2018-12-03
### Added
Expand Down
8 changes: 4 additions & 4 deletions examples/arduino/NeoPixel/Blink/Blink.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ using namespace PixelMaestro;
Maestro maestro(8, 1);

// Initialize the NeoPixel strip on pin 10
Adafruit_NeoPixel strip = Adafruit_NeoPixel(maestro.get_section(0)->get_dimensions()->x, 10, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip = Adafruit_NeoPixel(maestro.get_section(0).get_dimensions().x, 10, NEO_GRB + NEO_KHZ800);

void setup () {
strip.begin();
Expand All @@ -23,8 +23,8 @@ void setup () {
maestro.set_brightness(25);

// Create a new blinking animation and set the color palette to the ColorWheel preset
Animation* animation = maestro.get_section(0)->set_animation(AnimationType::Blink);
animation->set_palette(&ColorPresets::Colorwheel_Palette);
Animation* animation = maestro.get_section(0).set_animation(AnimationType::Blink);
animation->set_palette(ColorPresets::Colorwheel_Palette);

// Set the amount of time between animation cycles to 500ms
animation->set_timer(500);
Expand All @@ -33,7 +33,7 @@ void setup () {
void loop() {
if (maestro.update(millis())) {
// Copy each Pixel's color to the NeoPixel strip
for (unsigned char x = 0; x < maestro.get_section(0)->get_dimensions()->x; x++) {
for (unsigned char x = 0; x < maestro.get_section(0).get_dimensions().x; x++) {
Colors::RGB color = maestro.get_pixel_color(0, x, 0);
strip.setPixelColor(x, color.r, color.g, color.b);
}
Expand Down
20 changes: 10 additions & 10 deletions examples/arduino/NeoPixel/USB/USB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ Maestro maestro(8, 1);

// Initialize the NeoPixel strip on pin 10
const uint8_t LED_PIN = 10;
Adafruit_NeoPixel strip = Adafruit_NeoPixel(maestro.get_section(0)->get_dimensions()->x, 10, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip = Adafruit_NeoPixel(maestro.get_section(0).get_dimensions().x, 10, NEO_GRB + NEO_KHZ800);

// Run the Cuefile stored in EEPROM
void run_eeprom_cue() {
for (uint16_t index = 0; index < EEPROM.length(); index++) {
maestro.get_cue_controller()->read(EEPROM[index]);
maestro.get_cue_controller().read(EEPROM[index]);
}
}

Expand All @@ -45,12 +45,12 @@ void setup () {
* Initialize the CueController and CueHandlers.
* To reduce the sketch size, disable any unused CueHandlers.
*/
CueController* controller = maestro.set_cue_controller();
controller->enable_animation_cue_handler();
controller->enable_canvas_cue_handler();
controller->enable_maestro_cue_handler();
controller->enable_section_cue_handler();
controller->enable_show_cue_handler();
CueController& controller = maestro.set_cue_controller();
controller.enable_animation_cue_handler();
controller.enable_canvas_cue_handler();
controller.enable_maestro_cue_handler();
controller.enable_section_cue_handler();
controller.enable_show_cue_handler();

// If we have Cue data stored in EEPROM, read it in.
if (EEPROM.read(0) == 'P' && EEPROM.read(1) == 'M' && EEPROM.read(2) == 'C') {
Expand All @@ -66,7 +66,7 @@ void loop() {
uint8_t in = Serial.read();

// Read in the current byte to the CueController
maestro.get_cue_controller()->read(in);
maestro.get_cue_controller().read(in);

// If the current byte might indicate an EEPROM start/stop command, reset the header read index
if (in == 'R') {
Expand Down Expand Up @@ -105,7 +105,7 @@ void loop() {
// Update the Maestro
if (maestro.update(millis())) {
// Copy each Pixel's color to the WS2812 strip
for (unsigned char x = 0; x < maestro.get_section(0)->get_dimensions()->x; x++) {
for (unsigned char x = 0; x < maestro.get_section(0).get_dimensions().x; x++) {
Colors::RGB color = maestro.get_pixel_color(0, x, 0);
strip.setPixelColor(x, color.r, color.g, color.b);
}
Expand Down
20 changes: 10 additions & 10 deletions examples/arduino/WS2812/USB/USB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ Maestro maestro(8, 1);

// Initialize WS2812 components
const uint8_t LED_PIN = 10;
WS2812 ws = WS2812(maestro.get_section(0)->get_dimensions()->x);
WS2812 ws = WS2812(maestro.get_section(0).get_dimensions().x);

// Run the Cuefile stored in EEPROM
void run_eeprom_cue() {
for (uint16_t index = 0; index < EEPROM.length(); index++) {
maestro.get_cue_controller()->read(EEPROM[index]);
maestro.get_cue_controller().read(EEPROM[index]);
}
}

Expand All @@ -55,12 +55,12 @@ void setup () {
* Initialize the CueController and CueHandlers.
* To reduce the sketch size, disable any unused CueHandlers.
*/
CueController* controller = maestro.set_cue_controller();
controller->enable_animation_cue_handler();
controller->enable_canvas_cue_handler();
controller->enable_maestro_cue_handler();
controller->enable_section_cue_handler();
controller->enable_show_cue_handler();
CueController& controller = maestro.set_cue_controller();
controller.enable_animation_cue_handler();
controller.enable_canvas_cue_handler();
controller.enable_maestro_cue_handler();
controller.enable_section_cue_handler();
controller.enable_show_cue_handler();

// If we have Cue data stored in EEPROM, read it in.
if (EEPROM.read(0) == 'P' && EEPROM.read(1) == 'M' && EEPROM.read(2) == 'C') {
Expand All @@ -76,7 +76,7 @@ void loop() {
uint8_t in = Serial.read();

// Read in the current byte to the CueController
maestro.get_cue_controller()->read(in);
maestro.get_cue_controller().read(in);

// If the current byte might indicate an EEPROM start/stop command, reset the header read index
if (in == 'R') {
Expand Down Expand Up @@ -115,7 +115,7 @@ void loop() {
// Update the Maestro
if (maestro.update(millis())) {
// Copy each Pixel's color to the WS2812 strip
for (unsigned char x = 0; x < maestro.get_section(0)->get_dimensions()->x; x++) {
for (unsigned char x = 0; x < maestro.get_section(0).get_dimensions().x; x++) {
ws.set_crgb_at(x, RGBtoCRGB(maestro.get_pixel_color(0, x, 0)));
}

Expand Down
16 changes: 10 additions & 6 deletions examples/arduino/WS2812/Wave/Wave.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Maestro maestro(8, 1);

// Initialize WS1812 components
const unsigned char LED_PIN = 10;
WS2812 ws = WS2812(maestro.get_section(0)->get_dimensions()->x);
WS2812 ws = WS2812(maestro.get_section(0).get_dimensions().x);

// Translate PixelMaestro RGB to LightWS2812 cRGB
cRGB RGBtoCRGB(Colors::RGB rgb) {
Expand All @@ -35,15 +35,19 @@ void setup () {
maestro.set_brightness(25);

// Create a new wave animation, change the palette to ColorWheel, then set the speed to 500ms.
Animation* animation = maestro.get_section(0)->set_animation(AnimationType::Wave);
animation->set_palette(&ColorPresets::Colorwheel_Palette);
animation->set_timer(500);
Animation& animation = maestro.get_section(0).set_animation(AnimationType::Wave);
animation.set_palette(ColorPresets::Colorwheel_Palette);
animation.set_timer(500);
}

void loop() {
if (maestro.update(millis())) {
for (unsigned char x = 0; x < maestro.get_section(0)->get_dimensions()->x; x++) {
ws.set_crgb_at(x, RGBtoCRGB(maestro.get_pixel_color(0, x, 0)));
uint8_t led = 0;
for (uint8_t y = 0; y < maestro.get_section(0).get_dimensions().y; y++) {
for (uint8_t x = 0; x < maestro.get_section(0).get_dimensions().x; x++) {
ws.set_crgb_at(led, RGBtoCRGB(maestro.get_pixel_color(0, x, y)));
led++;
}
}

ws.sync();
Expand Down
37 changes: 21 additions & 16 deletions src/canvas/canvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,9 @@ namespace PixelMaestro {
area = 0.5 *(-point_b_y*point_c_x + point_a_y*(-point_b_x + point_c_x) + point_a_x*(point_b_y - point_c_y) + point_b_x*point_c_y);

/*
* Instead of checking every single point in the frame, check only the area containing the triangle.
* We calculate a small rectangle based on the triangle's vertices and check each Pixel in that area.
*
* Is point a < point b?
* Yes: Is point a < point c?
* Yes: Return point a
Expand All @@ -279,7 +282,7 @@ namespace PixelMaestro {
uint16_t min_y = (point_a_y < point_b_y ? (point_c_y < point_a_y ? point_c_y : point_a_y) : (point_b_y < point_c_y ? point_b_y : point_c_y));
uint16_t max_y = (point_a_y > point_b_y ? (point_c_y > point_a_y ? point_c_y : point_a_y) : (point_b_y > point_c_y ? point_b_y : point_c_y));

// For each point in the "rectangle", determine whether it lies inside the triangle. If so, fill it in.
// For each Pixel in the rectangle, determine whether it lies inside the triangle. If so, fill it in.
for (cursor.x = min_x; cursor.x < max_x; cursor.x++) {
for (cursor.y = min_y; cursor.y < max_y; cursor.y++) {
s = 1 / (2 * area) * (point_a_y * point_c_x - point_a_x * point_c_y + (point_c_y - point_a_y) * cursor.x + (point_a_x - point_c_x) * cursor.y);
Expand Down Expand Up @@ -346,6 +349,23 @@ namespace PixelMaestro {
return palette_;
}

/**
* Returns the color at the specified Pixel.
*
* @param x Pixel X coordinate.
* @param y Pixel Y coordinate.
* @return Color if found. If the Pixel is transparent, return nullptr.
*/
Colors::RGB* Canvas::get_pixel_color(uint16_t x, uint16_t y) {
uint8_t index = frames_[current_frame_index_][section_.get_dimensions().get_inline_index(x, y)];
if (index != 255) {
return &palette_->get_color_at_index(index);
}
else {
return nullptr;
}
}

/**
* Returns the Canvas' parent Section.
* @return Parent Section.
Expand Down Expand Up @@ -453,21 +473,6 @@ namespace PixelMaestro {
* @param current_time The program's current runtime.
*/
void Canvas::update(const uint32_t& current_time) {
/*
* Set each Pixel's color according to the current frame.
* If no Palette is set, don't do anything at all.
*/
if (palette_ != nullptr) {
for (uint8_t y = 0; y < section_.get_dimensions().y; y++) {
for (uint8_t x = 0; x < section_.get_dimensions().x; x++) {
uint8_t index = frames_[current_frame_index_][section_.get_dimensions().get_inline_index(x, y)];
if (index != 255) {
section_.set_one(x, y, palette_->get_color_at_index(index), 1);
}
}
}
}

if (frame_timer_ && frame_timer_->update(current_time)) {
next_frame();
}
Expand Down
1 change: 1 addition & 0 deletions src/canvas/canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ namespace PixelMaestro {
uint8_t* get_frame(uint16_t frame) const;
uint16_t get_num_frames() const;
Palette* get_palette() const;
Colors::RGB* get_pixel_color(uint16_t x, uint16_t y);
Section& get_section() const;
void next_frame();
void previous_frame();
Expand Down
22 changes: 11 additions & 11 deletions src/core/colors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,38 +91,38 @@ namespace PixelMaestro {
@param alpha Color two alpha factor (0 - 255).
@return The mixed color.
*/
Colors::RGB Colors::mix_colors(RGB* color_one, RGB* color_two, MixMode mode, uint8_t alpha) {
Colors::RGB Colors::mix_colors(const RGB& color_one, const RGB& color_two, MixMode mode, uint8_t alpha) {
RGB mixed_color;

switch (mode) {
case MixMode::Alpha:
{
float alpha_pct = alpha / (float)255;
float alpha_pct_inv = 1 - alpha_pct;
mixed_color.r = (alpha_pct * color_two->r) + (alpha_pct_inv * color_one->r);
mixed_color.g = (alpha_pct * color_two->g) + (alpha_pct_inv * color_one->g);
mixed_color.b = (alpha_pct * color_two->b) + (alpha_pct_inv * color_one->b);
mixed_color.r = (alpha_pct * color_two.r) + (alpha_pct_inv * color_one.r);
mixed_color.g = (alpha_pct * color_two.g) + (alpha_pct_inv * color_one.g);
mixed_color.b = (alpha_pct * color_two.b) + (alpha_pct_inv * color_one.b);
break;
}
case MixMode::Multiply:
{
mixed_color.r = color_one->r * (float)(color_two->r / (float)255);
mixed_color.g = color_one->g * (float)(color_two->g / (float)255);
mixed_color.b = color_one->b * (float)(color_two->b / (float)255);
mixed_color.r = color_one.r * (float)(color_two.r / (float)255);
mixed_color.g = color_one.g * (float)(color_two.g / (float)255);
mixed_color.b = color_one.b * (float)(color_two.b / (float)255);
break;
}
case MixMode::Overlay:
{
if (*color_two != Colors::RGB {0, 0, 0}) {
mixed_color = *color_two;
if (color_two != Colors::RGB {0, 0, 0}) {
mixed_color = color_two;
}
else {
mixed_color = *color_one;
mixed_color = color_one;
}
break;
}
default: // Return color_one
mixed_color = *color_one;
mixed_color = color_one;
break;
};

Expand Down
2 changes: 1 addition & 1 deletion src/core/colors.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ namespace PixelMaestro {
static RGB generate_random_color();
static void generate_random_color_array(RGB* array, uint8_t num_colors);
static void generate_scaling_color_array(RGB* array, RGB& base_color, RGB& target_color, uint8_t num_colors, bool reverse = false);
static RGB mix_colors(RGB* color_one, RGB* color_two, MixMode mode, uint8_t alpha = 0);
static RGB mix_colors(const RGB& color_one, const RGB& color_two, MixMode mode, uint8_t alpha = 0);
};
}

Expand Down
2 changes: 1 addition & 1 deletion src/core/pixel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ namespace PixelMaestro {
*/
void Pixel::update() {
#ifndef DISABLE_COLOR_BUFFER
// WARNING: This may be imprecise, especially with small/more gradual color changes.
// WARNING: This can be imprecise, especially with small or gradual color changes.
if (step_.count > 0) {
current_color_.r += step_.r;
current_color_.g += step_.g;
Expand Down
1 change: 0 additions & 1 deletion src/core/pixel.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
Inspired by RGBMood (http://forum.arduino.cc/index.php?topic=90160.0)
*/

// FIXME: How to make this available in a sketch?
//#define DISABLE_COLOR_BUFFER // Disable per-Pixel fading and color buffering.

#ifndef PIXEL_H
Expand Down
Loading

0 comments on commit d26aeac

Please sign in to comment.