Pixie Chroma
Documentation for the easiest 5x7 LED displays for Arduino!
pixie_chroma_internal.cpp
Go to the documentation of this file.
1 
10 #include "Pixie_Chroma.h"
11 #include "utility/pixie_utility.h"
12 
13 // ---------------------------------------------------------------------------------------------------------|
14 // -- PUBLIC CLASS FUNCTIONS -------------------------------------------------------------------------------|
15 // ---------------------------------------------------------------------------------------------------------|
16 
17 //............................................................................
34 
35 //............................................................................
78 void PixieChroma::begin( const uint8_t data_pin, uint8_t pixies_x, uint8_t pixies_y ){
79  pixie_pin = data_pin;
80 
81  chars_x = pixies_x * 2; // Pixies have two chars each
82  chars_y = pixies_y;
83 
84  matrix_width = display_width * chars_x;
85  matrix_height = display_height * chars_y;
86 
88 
89  color_map = new CRGB[ NUM_PIXELS + 1 ]; // Hidden extra LED to write to if we call an out-of-bounds XY coordinate for color or mask
90  mask = new uint8_t[ NUM_PIXELS + 1 ];
91  xy_table = new int16_t[ NUM_PIXELS ];
92 
93  calc_xy(); // NUM_LEDS is calculated here
94 
95  color_map_out = new CRGB[ NUM_LEDS ];
96  mask_out = new uint8_t[ NUM_LEDS ];
97 
98  for( uint16_t i = 0; i < NUM_LEDS; i++ ){
99  color_map[i] = CRGB( 0, 255, 0 );
100  }
101 
102  current_palette.loadDynamicGradientPalette( GREEN_SOLID );
103 
104  build_controller( pixie_pin ); // ----- Initialize FastLED
105  //set_animation( ANIMATION_NULL ); // --- Set animation function to an empty one
106  clear(); // --------------------------- Clear anything in mask (should be empty anyways), reset cursor
107  set_max_power( 5.0, 500 ); // --------- Set default power budget in volts and milliamps (5.0V, 500mA)
108 }
109 //............................................................................
196 void PixieChroma::begin_quad( uint8_t pixies_per_pin, uint8_t pixies_x, uint8_t pixies_y ){
197  chars_x = pixies_x * 2; // Pixies have two chars each
198  chars_y = pixies_y;
199 
200  matrix_width = display_width * chars_x;
201  matrix_height = display_height * chars_y;
202 
204 
205  color_map = new CRGB[ NUM_PIXELS + 1 ]; // Hidden extra LED to write to if we call an out-of-bounds XY coordinate for color or mask
206  mask = new uint8_t[ NUM_PIXELS + 1 ];
207  xy_table = new int16_t[ NUM_PIXELS ];
208 
209  calc_xy();
210 
211  color_map_out = new CRGB[ NUM_LEDS ];
212  mask_out = new uint8_t[ NUM_LEDS ];
213 
214  for( uint16_t i = 0; i < NUM_LEDS; i++ ){
215  color_map[i] = CRGB( 0,255,0 );
216  }
217 
218  current_palette.loadDynamicGradientPalette( GREEN_SOLID );
219 
220  #if defined( ARDUINO_ARCH_ESP8266 )
221  // WS2811_PORTA on ESP8266 takes up GPIO 12, GPIO 13, GPIO 14 and GPIO 15 for Quad Mode
222  FastLED.addLeds<WS2811_PORTA,4>( color_map_out, pixies_per_pin * leds_per_pixie ).setCorrection( TypicalLEDStrip ); // Initialize FastLED
223  #endif
224 
225  #if defined( ARDUINO_ARCH_ESP32 )
226 
227  // Quad Mode on ESP32 takes up GPIO 12, GPIO 13, GPIO 14 and GPIO 27
228  FastLED.addLeds<NEOPIXEL, 13>( // Initialize FastLED Data Out 1
229  color_map_out,
230  0,
231  ( pixies_per_pin*leds_per_pixie )
232  ).setCorrection( TypicalLEDStrip );
233 
234  FastLED.addLeds<NEOPIXEL, 12>( // Initialize FastLED Data Out 2
235  color_map_out,
236  ( pixies_per_pin*leds_per_pixie ),
237  ( pixies_per_pin*leds_per_pixie )
238  ).setCorrection( TypicalLEDStrip );
239 
240  FastLED.addLeds<NEOPIXEL, 14>( // Initialize FastLED Data Out 3
241  color_map_out,
242  ( pixies_per_pin*leds_per_pixie ) * 2,
243  ( pixies_per_pin*leds_per_pixie )
244  ).setCorrection( TypicalLEDStrip );
245 
246  FastLED.addLeds<NEOPIXEL, 27>( // Initialize FastLED Data Out 4
247  color_map_out,
248  ( pixies_per_pin*leds_per_pixie ) * 4,
249  ( pixies_per_pin*leds_per_pixie )
250  ).setCorrection( TypicalLEDStrip );
251 
252  #endif
253 
254  //set_animation( ANIMATION_NULL ); // --- Set animation function to an empty one
255  clear(); // --------------------------- Clear anything in mask ( should be empty anyways ), reset cursor
256  set_max_power( 5, 500 ); // ----------- Set default power budget in volts and milliamps
257 }
258 
259 //............................................................................
267 void PixieChroma::set_brightness( uint8_t level ){
268  brightness_level = level;
269 }
270 
271 //............................................................................
291 void PixieChroma::set_palette( const uint8_t* pal ){
292  current_palette.loadDynamicGradientPalette( pal ); // GRADIENT PALETTE
293 }
294 
295 //............................................................................
303 void PixieChroma::set_palette( CRGBPalette16 pal ){ // STANDARD PALETTE
304  current_palette = pal;
305 }
306 
307 //............................................................................
317 void PixieChroma::set_animation( void ( *action )(PixieChroma*, float) ) {
318  anim_func = action;
319 }
320 
321 //............................................................................
330  animation_speed = speed;
331 }
332 
333 //............................................................................
342  correct_gamma = enabled;
343 }
344 
345 //............................................................................
391 void PixieChroma::set_cursor( uint8_t x_position, uint8_t y_position ){
392  cursor_x = display_padding_x + ( display_width * x_position );
393  cursor_y = display_padding_y + ( display_height * y_position );
394 }
395 
396 //............................................................................
411 void PixieChroma::set_max_power( float volts, uint16_t milliamps ){
412  max_V = volts;
413  max_mA = milliamps;
414 }
415 
416 //............................................................................
434 void PixieChroma::set_frame_rate_target( uint16_t target ){
435  fps_target = target;
436 }
437 
438 //............................................................................
449 void PixieChroma::set_line_wrap( bool enabled ){
450  line_wrap = enabled;
451 }
452 
453 //............................................................................
476 void PixieChroma::set_update_mode( t_update_mode mode, uint16_t FPS ){
477  if( mode == AUTOMATIC && ticker_running == false ){
478  set_frame_rate_target( FPS );
479  animate.attach_ms( round(1000 / float(FPS)), [this](){ this->show(); });
480  // This. ^ This is the magic sauce
481  // right here. This is apparently how
482  // you add a non-static class member to
483  // Ticker from within a class and I
484  // hate it. Readability sucks, oh well.
485 
486  ticker_running = true;
487  }
488  else if( mode == MANUAL && ticker_running == true ){
489  animate.detach();
490  ticker_running = false;
491  }
492 }
493 
494 //............................................................................
503 void PixieChroma::write( const uint8_t* icon, uint8_t x_pos, uint8_t y_pos ){
504  write_pix(
505  icon,
506  display_padding_x + ( display_width * x_pos ),
507  display_padding_y + ( display_height * y_pos )
508  );
509 }
510 
511 //............................................................................
546 void PixieChroma::write( uint8_t icon_col_1, uint8_t icon_col_2, uint8_t icon_col_3, uint8_t icon_col_4, uint8_t icon_col_5, uint8_t x_pos, uint8_t y_pos ){
547  uint8_t icon[5] = {
548  icon_col_1,
549  icon_col_2,
550  icon_col_3,
551  icon_col_4,
552  icon_col_5
553  };
554  write( icon, x_pos, y_pos );
555 }
556 
557 //............................................................................
566 void PixieChroma::write( char* message, uint8_t x_pos, uint8_t y_pos ){
567  write_pix(
568  message,
569  display_padding_x + ( display_width * x_pos ),
570  display_padding_y + ( display_height * y_pos )
571  );
572 }
573 
574 //............................................................................
583 void PixieChroma::write( int16_t input, uint8_t x_pos, uint8_t y_pos ){
584  char char_buf[32];
585  itoa( input, char_buf, 10 );
586 
587  write_pix(
588  char_buf,
589  display_padding_x + ( display_width * x_pos ),
590  display_padding_y + ( display_height * y_pos )
591  );
592 }
593 
594 //............................................................................
603 void PixieChroma::write( uint16_t input, uint8_t x_pos, uint8_t y_pos ){
604  char char_buf[32];
605  utoa( input, char_buf, 10 );
606 
607  write_pix(
608  char_buf,
609  display_padding_x + ( display_width * x_pos ),
610  display_padding_y + ( display_height * y_pos )
611  );
612 }
613 
614 //............................................................................
623 void PixieChroma::write( int32_t input, uint8_t x_pos, uint8_t y_pos ){
624  char char_buf[32];
625  ltoa( input, char_buf, 10 );
626 
627  write_pix(
628  char_buf,
629  display_padding_x + ( display_width * x_pos ),
630  display_padding_y + ( display_height * y_pos )
631  );
632 }
633 
634 //............................................................................
643 void PixieChroma::write( uint32_t input, uint8_t x_pos, uint8_t y_pos ){
644  char char_buf[32];
645  ultoa( input, char_buf, 10 );
646 
647  write_pix(
648  char_buf,
649  display_padding_x + ( display_width * x_pos ),
650  display_padding_y + ( display_height * y_pos )
651  );
652 }
653 
654 //............................................................................
664 void PixieChroma::write( long unsigned int input, uint8_t x_pos, uint8_t y_pos ){
665  char char_buf[32];
666  ultoa( input, char_buf, 10 );
667 
668  write_pix(
669  char_buf,
670  display_padding_x + ( display_width * x_pos ),
671  display_padding_y + ( display_height * y_pos )
672  );
673 }
674 
675 //............................................................................
686 void PixieChroma::write( double input, uint8_t places, uint8_t x_pos, uint8_t y_pos ){
687  char char_buf[32];
688  dtoa( input, char_buf, places );
689 
690  write_pix(
691  char_buf,
692  display_padding_x + ( display_width * x_pos ),
693  display_padding_y + ( display_height * y_pos )
694  );
695 }
696 
697 //............................................................................
708 void PixieChroma::write( float input, uint8_t places, uint8_t x_pos, uint8_t y_pos ){
709  write(
710  double( input ),
711  places,
712  x_pos,
713  y_pos
714  );
715 }
716 
717 //............................................................................
730 void PixieChroma::write_pix( const uint8_t* icon, int16_t x_dest, int16_t y_dest ){
731  add_char(
732  icon,
733  x_dest,
734  y_dest
735  );
736 }
737 
738 //............................................................................
753 void PixieChroma::write_pix( char* message, int16_t x_dest, int16_t y_dest ){
754  int16_t offset_x = 0;
755  int16_t offset_y = 0;
756 
757  uint8_t len = strlen( message );
758  for( uint8_t i = 0; i < len; i++ ){
759  if( message[i] == '\n' ){ // Newline, force line break
760  x_dest = display_padding_x;
761  offset_x = 0;
762  offset_y = display_height;
763  }
764  else if( line_wrap == true && x_dest+offset_x >= ( display_width * chars_x ) ){ // End of line reached, wrap to new line if line_wrap enabled
765  x_dest = display_padding_x;
766  offset_x = 0;
767  offset_y = display_height;
768 
769  add_char(
770  message[i],
771  x_dest + offset_x,
772  y_dest + offset_y
773  );
774  offset_x += display_width;
775  }
776  else if( message[i] == 0 || message[i] == '\0' ){ // end of string
777  return;
778  }
779  else{ // Normal char
780  add_char(
781  message[i],
782  x_dest + offset_x,
783  y_dest + offset_y
784  );
785  offset_x += display_width;
786  }
787  }
788 
789  cursor_x_temp = x_dest+offset_x;
790  cursor_y_temp = y_dest+offset_y;
791 }
792 
793 //............................................................................
806 void PixieChroma::add_char( char chr, int16_t x_dest, int16_t y_dest ){
807  if ( chr >= printable_ascii_offset ) {
808  chr -= printable_ascii_offset;
809  }
810 
811  for( uint8_t x = 0; x < font_col_width; x++ ){
812  uint8_t column = pgm_read_byte( font + ( chr * font_col_width + x ) );
813 
814  uint16_t row1_index = xy( x_dest+x, y_dest+0 );
815  uint16_t row2_index = xy( x_dest+x, y_dest+1 );
816  uint16_t row3_index = xy( x_dest+x, y_dest+2 );
817  uint16_t row4_index = xy( x_dest+x, y_dest+3 );
818  uint16_t row5_index = xy( x_dest+x, y_dest+4 );
819  uint16_t row6_index = xy( x_dest+x, y_dest+5 );
820  uint16_t row7_index = xy( x_dest+x, y_dest+6 );
821 
822  // "Subtract" from mask transparency with saturating function
823  mask[row1_index] = qadd8( mask[row1_index], bit_table[bitRead( column, 0 )] );
824  mask[row2_index] = qadd8( mask[row2_index], bit_table[bitRead( column, 1 )] );
825  mask[row3_index] = qadd8( mask[row3_index], bit_table[bitRead( column, 2 )] );
826  mask[row4_index] = qadd8( mask[row4_index], bit_table[bitRead( column, 3 )] );
827  mask[row5_index] = qadd8( mask[row5_index], bit_table[bitRead( column, 4 )] );
828  mask[row6_index] = qadd8( mask[row6_index], bit_table[bitRead( column, 5 )] );
829  mask[row7_index] = qadd8( mask[row7_index], bit_table[bitRead( column, 6 )] );
830  }
831 }
832 
833 //............................................................................
842 void PixieChroma::add_char( const uint8_t* icon, int16_t x_dest, int16_t y_dest ){
843  for( uint8_t x = 0; x < font_col_width; x++ ){
844  uint8_t column = pgm_read_byte_far( icon+x );
845 
846  uint16_t row1_index = xy( x_dest+x, y_dest+0 );
847  uint16_t row2_index = xy( x_dest+x, y_dest+1 );
848  uint16_t row3_index = xy( x_dest+x, y_dest+2 );
849  uint16_t row4_index = xy( x_dest+x, y_dest+3 );
850  uint16_t row5_index = xy( x_dest+x, y_dest+4 );
851  uint16_t row6_index = xy( x_dest+x, y_dest+5 );
852  uint16_t row7_index = xy( x_dest+x, y_dest+6 );
853 
854  // "Subtract" from mask transparency with saturating function
855  mask[row1_index] = qadd8( mask[row1_index], bit_table[bitRead( column,0 )] );
856  mask[row2_index] = qadd8( mask[row2_index], bit_table[bitRead( column,1 )] );
857  mask[row3_index] = qadd8( mask[row3_index], bit_table[bitRead( column,2 )] );
858  mask[row4_index] = qadd8( mask[row4_index], bit_table[bitRead( column,3 )] );
859  mask[row5_index] = qadd8( mask[row5_index], bit_table[bitRead( column,4 )] );
860  mask[row6_index] = qadd8( mask[row6_index], bit_table[bitRead( column,5 )] );
861  mask[row7_index] = qadd8( mask[row7_index], bit_table[bitRead( column,6 )] );
862  }
863 }
864 
865 //............................................................................
872 void PixieChroma::print( const uint8_t* icon ){
873  write_pix( icon, cursor_x, cursor_y );
874 
875  // Store cursor changes
876  cursor_x = cursor_x_temp;
877  cursor_y = cursor_y_temp;
878 }
879 
880 //............................................................................
913 void PixieChroma::print( uint8_t icon_col_1, uint8_t icon_col_2, uint8_t icon_col_3, uint8_t icon_col_4, uint8_t icon_col_5 ){
914  cursor_x_temp = cursor_x;
915  cursor_y_temp = cursor_y;
916  const uint8_t icon[5] = {
917  icon_col_1,
918  icon_col_2,
919  icon_col_3,
920  icon_col_4,
921  icon_col_5,
922  };
923  write_pix( icon, cursor_x, cursor_y );
924 
925  // Store cursor changes
926  cursor_x = cursor_x_temp;
927  cursor_y = cursor_y_temp;
928 }
929 
930 //............................................................................
937 void PixieChroma::print( char* message ){
938  write_pix( message, cursor_x, cursor_y );
939 
940  // Store cursor changes
941  cursor_x = cursor_x_temp;
942  cursor_y = cursor_y_temp;
943 
944  // Store cursor changes
945  cursor_x = cursor_x_temp;
946  cursor_y = cursor_y_temp;
947 }
948 
949 //............................................................................
957 void PixieChroma::print( int16_t input ){
958  char char_buf[32];
959  itoa( input, char_buf, 10 );
960  write_pix( char_buf, cursor_x, cursor_y );
961 
962  // Store cursor changes
963  cursor_x = cursor_x_temp;
964  cursor_y = cursor_y_temp;
965 }
966 
967 //............................................................................
975 void PixieChroma::print( uint16_t input ){
976  char char_buf[32];
977  utoa( input, char_buf, 10 );
978  write_pix( char_buf, cursor_x, cursor_y );
979 
980  // Store cursor changes
981  cursor_x = cursor_x_temp;
982  cursor_y = cursor_y_temp;
983 }
984 
985 //............................................................................
993 void PixieChroma::print( int32_t input ){
994  char char_buf[32];
995  ltoa( input, char_buf, 10 );
996  write_pix( char_buf, cursor_x, cursor_y );
997 
998  // Store cursor changes
999  cursor_x = cursor_x_temp;
1000  cursor_y = cursor_y_temp;
1001 }
1002 
1003 //............................................................................
1011 void PixieChroma::print( uint32_t input ){
1012  char char_buf[32];
1013  ultoa( input, char_buf, 10 );
1014  write_pix( char_buf, cursor_x, cursor_y );
1015 
1016  // Store cursor changes
1017  cursor_x = cursor_x_temp;
1018  cursor_y = cursor_y_temp;
1019 }
1020 
1021 //............................................................................
1029 void PixieChroma::print( long unsigned int input ){
1030  char char_buf[32];
1031  ultoa( input, char_buf, 10 );
1032  write_pix( char_buf, cursor_x, cursor_y );
1033 
1034  // Store cursor changes
1035  cursor_x = cursor_x_temp;
1036  cursor_y = cursor_y_temp;
1037 }
1038 
1039 //............................................................................
1048 void PixieChroma::print( double input, uint8_t places ){
1049  char char_buf[32];
1050  dtoa( input, char_buf, places );
1051  write_pix( char_buf, cursor_x, cursor_y );
1052 
1053  // Store cursor changes
1054  cursor_x = cursor_x_temp;
1055  cursor_y = cursor_y_temp;
1056 }
1057 
1058 //............................................................................
1067 void PixieChroma::print( float input, uint8_t places ){
1068  print( double( input ), places );
1069 
1070  // Store cursor changes
1071  cursor_x = cursor_x_temp;
1072  cursor_y = cursor_y_temp;
1073 }
1074 
1075 //............................................................................
1083 void PixieChroma::println( const uint8_t* icon ){
1084  write_pix( icon, cursor_x, cursor_y ); // ........ Output
1085 
1086  // Store cursor changes
1087  cursor_x = cursor_x_temp;
1088  cursor_y = cursor_y_temp;
1089 
1090  cursor_x = display_padding_x;
1091  cursor_y += display_height;
1092 }
1093 
1094 //............................................................................
1107 void PixieChroma::println( uint8_t icon_col_1, uint8_t icon_col_2, uint8_t icon_col_3, uint8_t icon_col_4, uint8_t icon_col_5 ){
1108  const uint8_t icon[5] = {
1109  icon_col_1,
1110  icon_col_2,
1111  icon_col_3,
1112  icon_col_4,
1113  icon_col_5
1114  };
1115  write_pix( icon, cursor_x, cursor_y );
1116 
1117  // Store cursor changes
1118  cursor_x = cursor_x_temp;
1119  cursor_y = cursor_y_temp;
1120 
1121  cursor_x = display_padding_x;
1122  cursor_y += display_height;
1123 }
1124 
1125 //............................................................................
1134 void PixieChroma::println( char* message ){
1135  write_pix( message, cursor_x, cursor_y ); // ........ Output
1136 
1137  // Store cursor changes
1138  cursor_x = display_padding_x;
1139  cursor_y = cursor_y_temp;
1140  cursor_y += display_height;
1141 }
1142 
1143 //............................................................................
1152 void PixieChroma::println( int16_t input ){
1153  char char_buf[32];
1154  itoa( input, char_buf, 10 );
1155  println( char_buf );
1156 }
1157 
1158 //............................................................................
1167 void PixieChroma::println( uint16_t input ){
1168  char char_buf[32];
1169  utoa( input, char_buf, 10 );
1170  println( char_buf );
1171 }
1172 
1173 //............................................................................
1182 void PixieChroma::println( int32_t input ){
1183  char char_buf[32];
1184  ltoa( input, char_buf, 10 );
1185  println( char_buf );
1186 }
1187 
1188 //............................................................................
1197 void PixieChroma::println( uint32_t input ){
1198  char char_buf[32];
1199  ultoa( input, char_buf, 10 );
1200  println( char_buf );
1201 }
1202 
1203 //............................................................................
1212 void PixieChroma::println( long unsigned int input ){
1213  char char_buf[32];
1214  ultoa( input, char_buf, 10 );
1215  println( char_buf );
1216 }
1217 
1218 //............................................................................
1229 void PixieChroma::println( double input, uint8_t places ){
1230  char char_buf[32];
1231  dtoa( input, char_buf, places );
1232  println( char_buf );
1233 }
1234 
1235 //............................................................................
1246 void PixieChroma::println( float input, uint8_t places ){
1247  println( double(input), places );
1248 }
1249 
1250 //............................................................................
1257 void PixieChroma::blur( fract8 blur_amount ){
1258  blur_x( blur_amount );
1259  blur_y( blur_amount );
1260 }
1261 
1262 //............................................................................
1269 void PixieChroma::blur_x( fract8 blur_amount ){
1270  uint8_t keep = 255 - blur_amount;
1271  uint8_t seep = blur_amount >> 1;
1272  for( uint8_t row = 0; row < matrix_height; row++ ) {
1273  uint8_t carryover = 0;
1274  for( uint8_t i = 0; i < matrix_width; i++ ) {
1275  uint8_t cur = mask[xy( i,row )];
1276  uint8_t part = cur;
1277  part = scale8( part, seep );
1278  cur = scale8( cur, keep );
1279  cur = qadd8( cur,carryover );
1280  if( i ){
1281  mask[xy( i-1,row )] = qadd8( mask[xy( i-1,row )],part );
1282  }
1283  mask[xy( i,row )] = cur;
1284  carryover = part;
1285  }
1286  }
1287 }
1288 
1289 //............................................................................
1296 void PixieChroma::blur_y( fract8 blur_amount ){
1297  // blur columns
1298  uint8_t keep = 255 - blur_amount;
1299  uint8_t seep = blur_amount >> 1;
1300  for( uint8_t col = 0; col < matrix_width; ++col ) {
1301  uint8_t carryover = 0;
1302  for( uint8_t i = 0; i < matrix_height; ++i ) {
1303  uint8_t cur = mask[xy( col,i )];
1304  uint8_t part = cur;
1305  part = scale8( part, seep );
1306  cur = scale8( cur, keep );
1307  cur = qadd8( cur,carryover );
1308  if( i ){
1309  mask[xy( col,i-1 )] = qadd8( mask[xy( col,i-1 )],part );
1310  }
1311  mask[xy( col,i )] = cur;
1312  carryover = part;
1313  }
1314  }
1315 }
1316 
1317 //............................................................................
1326 void PixieChroma::dim( uint8_t amount, bool reset_cursor ){
1327  if( reset_cursor ){
1328  set_cursor( 0,0 );
1329  }
1330 
1331  for( uint16_t i = 0; i < NUM_PIXELS; i+=11 ){
1332  mask[i+0] = scale8( mask[i+0], 255-amount );
1333  mask[i+1] = scale8( mask[i+1], 255-amount );
1334  mask[i+2] = scale8( mask[i+2], 255-amount );
1335  mask[i+3] = scale8( mask[i+3], 255-amount );
1336  mask[i+4] = scale8( mask[i+4], 255-amount );
1337  mask[i+5] = scale8( mask[i+5], 255-amount );
1338  mask[i+6] = scale8( mask[i+6], 255-amount );
1339  mask[i+7] = scale8( mask[i+7], 255-amount );
1340  mask[i+8] = scale8( mask[i+8], 255-amount );
1341  mask[i+9] = scale8( mask[i+9], 255-amount );
1342  mask[i+10] = scale8( mask[i+10], 255-amount );
1343  }
1344 }
1345 
1346 //............................................................................
1353 void PixieChroma::color_blur( fract8 blur_amount ){
1354  color_blur_x( blur_amount );
1355  color_blur_y( blur_amount );
1356 }
1357 
1358 //............................................................................
1365 void PixieChroma::color_blur_x( fract8 blur_amount ){
1366  uint8_t keep = 255 - blur_amount;
1367  uint8_t seep = blur_amount >> 1;
1368  for( uint8_t row = 0; row < matrix_height; row++ ) {
1369  uint8_t carryover = 0;
1370  for( uint8_t i = 0; i < matrix_width; i++ ) {
1371  CRGB cur = color_map[xy( i,row )];
1372  CRGB part = cur;
1373  part.nscale8( seep );
1374  cur.nscale8( keep );
1375  cur += carryover;
1376  if( i ) color_map[xy( i-1,row )] += part;
1377  color_map[xy( i,row )] = cur;
1378  carryover = part;
1379  }
1380  }
1381 }
1382 
1383 //............................................................................
1390 void PixieChroma::color_blur_y( fract8 blur_amount ){
1391  // blur rows same as columns, for irregular matrix
1392  uint8_t keep = 255 - blur_amount;
1393  uint8_t seep = blur_amount >> 1;
1394  for( uint8_t row = 0; row < matrix_width; row++ ) {
1395  CRGB carryover = CRGB::Black;
1396  for( uint8_t i = 0; i < matrix_height; i++ ) {
1397  CRGB cur = color_map[xy( i,row )];
1398  CRGB part = cur;
1399  part.nscale8( seep );
1400  cur.nscale8( keep );
1401  cur += carryover;
1402  if( i ) color_map[xy( i-1,row )] += part;
1403  color_map[xy( i,row )] = cur;
1404  carryover = part;
1405  }
1406  }
1407 }
1408 
1409 //............................................................................
1416 void PixieChroma::color_dim( uint8_t amount ){
1417  CRGBSet leds_temp( color_map, NUM_PIXELS );
1418  leds_temp.fadeToBlackBy( amount );
1419 }
1420 
1421 //............................................................................
1429  return cursor_x / chars_x;
1430 }
1431 
1432 //............................................................................
1440  return cursor_y / chars_y;
1441 }
1442 
1443 //............................................................................
1451  return cursor_x;
1452 }
1453 
1454 //............................................................................
1462  return cursor_y;
1463 }
1464 
1465 //............................................................................
1471  memset( mask, 0, NUM_PIXELS );
1472  set_cursor( 0, 0 );
1473 }
1474 
1475 //............................................................................
1530 uint16_t PixieChroma::xy( int32_t x, int32_t y, bool wrap ) {
1531  if( wrap ){
1532  while( x < 0 ){
1533  x += matrix_width;
1534  }
1535  while( x >= matrix_width ){
1536  x -= matrix_width;
1537  }
1538  while( y < 0 ){
1539  y += matrix_height;
1540  }
1541  while( y >= matrix_height ){
1542  y -= matrix_height;
1543  }
1544  }
1545  else{
1546  if( x < 0 ){
1547  return NUM_PIXELS; // If offscreen without wrap return last led in matrix
1548  }
1549  else if( x >= matrix_width ){
1550  return NUM_PIXELS; // If offscreen without wrap return last led in matrix
1551  }
1552  if( y < 0 ){
1553  return NUM_PIXELS; // If offscreen without wrap return last led in matrix
1554  }
1555  else if( y >= matrix_height ){
1556  return NUM_PIXELS; // If offscreen without wrap return last led in matrix
1557  }
1558  }
1559 
1560  // done wrapping / culling, time for transformation
1561  return xy_table[ ( y * matrix_width ) + x ];
1562 }
1563 
1564 //............................................................................
1586 uint16_t PixieChroma::uv( float x, float y, bool wrap ) {
1587  if( wrap ){
1588  while( x < 0.0 ){
1589  x += 1.0;
1590  }
1591  while( x > 1.0 ){
1592  x -= 1.0;
1593  }
1594  while( y < 0.0 ){
1595  y += 1.0;
1596  }
1597  while( y > 1.0 ){
1598  y -= 1.0;
1599  }
1600  }
1601 
1602  y = 1.0-y; // Invert Y axis for OpenGL coordinate style
1603 
1604  return xy(
1605  uint16_t( matrix_width * x ),
1606  uint16_t( matrix_height * y )
1607  );
1608 }
1609 
1610 //............................................................................
1618 float PixieChroma::get_uv_x( int32_t x_pixel ){
1619  return x_pixel / float( matrix_width );
1620 }
1621 
1622 //............................................................................
1630 float PixieChroma::get_uv_y( int32_t y_pixel ){
1631  y_pixel = matrix_height - y_pixel;
1632  return y_pixel / float( matrix_height );
1633 }
1634 
1635 //............................................................................
1649 void PixieChroma::color( CRGB col ){
1650  fill_solid( color_map, NUM_PIXELS, col );
1651 }
1652 
1653 //............................................................................
1670 void PixieChroma::color( CRGB col, uint8_t x, uint8_t y ){
1671  int16_t x_pos = x * display_width + display_padding_x;
1672  int16_t y_pos = y * display_height + display_padding_y;
1673 
1674  for( uint8_t xi = 0; xi < font_col_width; xi++ ){
1675  color_map[xy( x_pos+xi, y_pos+0 )] = col;
1676  color_map[xy( x_pos+xi, y_pos+1 )] = col;
1677  color_map[xy( x_pos+xi, y_pos+2 )] = col;
1678  color_map[xy( x_pos+xi, y_pos+3 )] = col;
1679  color_map[xy( x_pos+xi, y_pos+4 )] = col;
1680  color_map[xy( x_pos+xi, y_pos+5 )] = col;
1681  color_map[xy( x_pos+xi, y_pos+6 )] = col;
1682  }
1683 }
1684 
1685 //............................................................................
1704 void PixieChroma::color( CRGB col, uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2 ){
1705  if( x2 < x1 || y2 < y1 ){
1706  return;
1707  }
1708 
1709  // Make rectangle selection inclusive
1710  x2 += 1;
1711  y2 += 1;
1712 
1713  int16_t x1_pos = x1 * display_width + display_padding_x;
1714  int16_t y1_pos = y1 * display_height + display_padding_y;
1715 
1716  int16_t x2_pos = x2 * display_width + display_padding_x;
1717  int16_t y2_pos = y2 * display_height + display_padding_y;
1718 
1719  uint16_t x_delta = x2_pos - x1_pos;
1720  uint16_t y_delta = y2_pos - y1_pos;
1721 
1722  for( uint16_t y = 0; y < y_delta; y++ ){
1723  for( uint16_t x = 0; x < x_delta; x++ ){
1724  int16_t x2_pos = x1_pos + x;
1725  int16_t y2_pos = y1_pos + y;
1726  color_map[xy( x2_pos, y2_pos )] = col;
1727  }
1728  }
1729 }
1730 
1731 //............................................................................
1741 void PixieChroma::draw_line( int16_t x1, int16_t y1, int16_t x2, int16_t y2 ){
1742  //Bresenham's line algorithm
1743  uint16_t index;
1744 
1745  int16_t x,y,dx,dy,dx1,dy1,px,py,xe,ye,i;
1746  dx=x2-x1;
1747  dy=y2-y1;
1748  dx1=fabs( dx );
1749  dy1=fabs( dy );
1750  px=2*dy1-dx1;
1751  py=2*dx1-dy1;
1752  if( dy1<=dx1 ){
1753  if( dx>=0 ){
1754  x=x1;
1755  y=y1;
1756  xe=x2;
1757  }
1758  else{
1759  x=x2;
1760  y=y2;
1761  xe=x1;
1762  }
1763  index = xy( x,y );
1764  mask[index] = qadd8( 255, mask[index] );
1765  for( i=0;x<xe;i++ ){
1766  x=x+1;
1767  if( px<0 ){
1768  px=px+2*dy1;
1769  }
1770  else{
1771  if( ( dx<0 && dy<0 ) || ( dx>0 && dy>0 ) ){
1772  y=y+1;
1773  }
1774  else{
1775  y=y-1;
1776  }
1777  px=px+2*( dy1-dx1 );
1778  }
1779  delay( 0 );
1780  index = xy( x,y );
1781  mask[index] = qadd8( 255, mask[index] );
1782  }
1783  }
1784  else{
1785  if( dy>=0 ){
1786  x=x1;
1787  y=y1;
1788  ye=y2;
1789  }
1790  else{
1791  x=x2;
1792  y=y2;
1793  ye=y1;
1794  }
1795  index = xy( x,y );
1796  mask[index] = qadd8( 255, mask[index] );
1797  for( i=0;y<ye;i++ ){
1798  y=y+1;
1799  if( py<=0 ){
1800  py=py+2*dx1;
1801  }
1802  else{
1803  if( ( dx<0 && dy<0 ) || ( dx>0 && dy>0 ) ){
1804  x=x+1;
1805  }
1806  else{
1807  x=x-1;
1808  }
1809  py=py+2*( dx1-dy1 );
1810  }
1811  index = xy( x,y );
1812  mask[index] = qadd8( 255, mask[index] );
1813  }
1814  }
1815 }
1816 
1817 //............................................................................
1839 CRGB PixieChroma::kelvin_to_rgb( uint16_t temperature ){
1840  // Tanner Helland formula
1841  float _temperature;
1842  float _red;
1843  float _green;
1844  float _blue;
1845 
1846  _temperature = constrain( temperature, 0, 65500 );
1847 
1848  _red = _green = _blue = 0;
1849  float t = _temperature * 0.01;
1850 
1851  if ( t <= 66 ){
1852  _red = 255;
1853  _green = ( 99.4708025861 * log( t ) ) - 161.1195681661;
1854  if ( t > 19 ){
1855  _blue = ( 138.5177312231 * log( t - 10 ) ) - 305.0447927307;
1856  }
1857  else{
1858  _blue = 0;
1859  }
1860  }
1861  else{
1862  _red = 329.698727466 * pow( t - 60, -0.1332047592 );
1863  _green = 288.1221695283 * pow( t - 60, -0.0755148492 );
1864  _blue = 255;
1865  }
1866 
1867  float f = 0.01 * 100;
1868 
1869  _red = constrain( f * _red, 0, 255 );
1870  _green = constrain( f * _green, 0, 255 );
1871  _blue = constrain( f * _blue, 0, 255 );
1872 
1873  return CRGB( _red, _green, _blue );
1874 }
1875 
1876 //............................................................................
1885  freeze = true;
1886 }
1887 
1888 //............................................................................
1895  freeze = false;
1896 }
1897 
1898 //............................................................................
1908  uint32_t t_now = micros();
1909  float frame_delta_us = t_now-t_last;
1910  frame_rate = 1000000.0 / frame_delta_us;
1911  delta = fps_target / frame_rate;
1912  t_last = t_now;
1913 
1914  anim_func( this, delta ); // Call custom animation function
1915 
1916  noInterrupts(); //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1917 
1918  if( !freeze ){ // If we're not holding out for a pix.free() call, show with the current mask
1919  memcpy( mask_out, mask, NUM_LEDS );
1920  }
1921  memcpy( color_map_out, color_map, sizeof( CRGB )*NUM_LEDS );
1922 
1923  for( uint16_t i = 0; i < NUM_LEDS; i++ ){
1924  // MASKING
1925  color_map_out[i].fadeLightBy( 255-mask_out[i] ); // Apply mask "over" LED color layer
1926 
1927  // GAMMA CORRECTION
1928  if( correct_gamma ){
1929  color_map_out[i].r = gamma8[ color_map_out[i].r ]; // Apply gamma correction LUT
1930  color_map_out[i].g = gamma8[ color_map_out[i].g ];
1931  color_map_out[i].b = gamma8[ color_map_out[i].b ];
1932  }
1933  }
1934 
1935  // Regulate brightness to keep power within budget set with pix.set_max_power( V, mA );
1936  FastLED.setBrightness( calculate_max_brightness_for_power_vmA( color_map_out, NUM_LEDS, brightness_level, max_V, max_mA ) );
1937  FastLED.show();
1938 
1939  interrupts(); //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%$$%
1940 }
1941 //............................................................................
1983  for( uint8_t y = 0; y < matrix_height; y++ ){
1984  for( uint8_t x = 0; x < matrix_width; x++ ){
1985  uint16_t index = ( matrix_width*y )+x;
1986  Serial.print( xy_table[index] );
1987  Serial.print( '\t' );
1988  }
1989  Serial.println();
1990  }
1991 }
1992 
1993 // ---------------------------------------------------------------------------------------------------------|
1994 // -- PRIVATE CLASS FUNCTIONS ------------------------------------------------------------------------------|
1995 // ---------------------------------------------------------------------------------------------------------|
1996 
1997 void PixieChroma::build_controller( const uint8_t pin ){
1998  // FastLED control pin has to be defined as a constant, ( not just declared const, it's weirdly different ) so
1999  // this is a hacky workaround. Since we have to hardwire the damn pin number variable, we also have
2000  // to be careful of the current architecture we're compiling to, since FastLED doesn't let you
2001  // define non-existent pins either.
2002 
2003  #ifdef ESP8266
2004  if ( pin == 0 ){FastLED.addLeds<WS2812B, 0, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2005  if ( pin == 1 ){FastLED.addLeds<WS2812B, 1, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2006  if ( pin == 2 ){FastLED.addLeds<WS2812B, 2, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2007  if ( pin == 3 ){FastLED.addLeds<WS2812B, 3, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2008  if ( pin == 4 ){FastLED.addLeds<WS2812B, 4, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2009  if ( pin == 5 ){FastLED.addLeds<WS2812B, 5, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2010  // annnnd a bunch of missing pins that are tied to external flash...
2011  if ( pin == 12 ){FastLED.addLeds<WS2812B, 12, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2012  if ( pin == 13 ){FastLED.addLeds<WS2812B, 13, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2013  if ( pin == 14 ){FastLED.addLeds<WS2812B, 14, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2014  if ( pin == 15 ){FastLED.addLeds<WS2812B, 15, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2015  if ( pin == 16 ){FastLED.addLeds<WS2812B, 16, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2016  #endif
2017 
2018  #ifdef ESP32
2019  if ( pin == 0 ){FastLED.addLeds<WS2812B, 0, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2020  if ( pin == 1 ){FastLED.addLeds<WS2812B, 1, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2021  if ( pin == 2 ){FastLED.addLeds<WS2812B, 2, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2022  if ( pin == 3 ){FastLED.addLeds<WS2812B, 3, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2023  if ( pin == 4 ){FastLED.addLeds<WS2812B, 4, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2024  if ( pin == 5 ){FastLED.addLeds<WS2812B, 5, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2025  if ( pin == 12 ){FastLED.addLeds<WS2812B, 12, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2026  if ( pin == 13 ){FastLED.addLeds<WS2812B, 13, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2027  if ( pin == 14 ){FastLED.addLeds<WS2812B, 14, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2028  if ( pin == 15 ){FastLED.addLeds<WS2812B, 15, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2029  if ( pin == 16 ){FastLED.addLeds<WS2812B, 16, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2030  if ( pin == 17 ){FastLED.addLeds<WS2812B, 17, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2031  if ( pin == 18 ){FastLED.addLeds<WS2812B, 18, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2032  if ( pin == 19 ){FastLED.addLeds<WS2812B, 19, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2033  if ( pin == 21 ){FastLED.addLeds<WS2812B, 21, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2034  if ( pin == 22 ){FastLED.addLeds<WS2812B, 22, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2035  if ( pin == 23 ){FastLED.addLeds<WS2812B, 23, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2036  if ( pin == 25 ){FastLED.addLeds<WS2812B, 25, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2037  if ( pin == 26 ){FastLED.addLeds<WS2812B, 26, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2038  if ( pin == 27 ){FastLED.addLeds<WS2812B, 27, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2039  if ( pin == 32 ){FastLED.addLeds<WS2812B, 32, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2040  if ( pin == 33 ){FastLED.addLeds<WS2812B, 33, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2041  #endif
2042 
2043  #ifdef SAMD_SERIES
2044  if ( pin == 0 ){FastLED.addLeds<WS2812B, 0, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2045  if ( pin == 1 ){FastLED.addLeds<WS2812B, 1, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2046  if ( pin == 2 ){FastLED.addLeds<WS2812B, 2, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2047  if ( pin == 3 ){FastLED.addLeds<WS2812B, 3, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2048  if ( pin == 4 ){FastLED.addLeds<WS2812B, 4, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2049  if ( pin == 5 ){FastLED.addLeds<WS2812B, 5, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2050  if ( pin == 6 ){FastLED.addLeds<WS2812B, 6, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2051  if ( pin == 7 ){FastLED.addLeds<WS2812B, 7, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2052  if ( pin == 8 ){FastLED.addLeds<WS2812B, 8, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2053  if ( pin == 9 ){FastLED.addLeds<WS2812B, 9, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2054  if ( pin == 10 ){FastLED.addLeds<WS2812B, 10, GRB>( color_map_out, NUM_LEDS ).setCorrection( TypicalLEDStrip );}
2055  #endif
2056 }
2057 
2058 
2059 void PixieChroma::calc_xy(){
2060  // Initialize XY table
2061  for( uint16_t yi = 0; yi < chars_y; yi++ ){
2062  for( uint16_t y = 0; y < 11; y++ ){
2063  for( uint16_t xi = 0; xi < chars_x; xi++ ){
2064  for( uint16_t x = 0; x < 7; x++ ){
2065  int16_t x_pos = ( xi*display_width )+x;
2066  int16_t y_pos = ( yi*display_height )+y;
2067 
2068  int16_t x_pos_mod = x_pos % display_width;
2069  int16_t y_pos_mod = y_pos % display_height;
2070 
2071  uint16_t i_table = ( y_pos * matrix_width ) + x_pos;
2072  uint16_t i_template = ( y_pos_mod * display_width ) + x_pos_mod;
2073 
2074  xy_table[i_table] = int8_t( pgm_read_byte( xy_template + i_template ) );
2075  }
2076  }
2077  }
2078  }
2079 
2080  //Serial.println( "SOLVING VISIBLE" );
2081 
2082  // Initialize first row of displays
2083  uint8_t visible_rows = 0;
2084  for( uint16_t row = 0; row < display_height; row++ ){
2085  uint16_t index = ( 5*visible_rows );
2086  bool found_visible = false;
2087  int16_t last_data = 0;
2088  for( uint16_t col = 0; col < matrix_width; col++ ){
2089  uint16_t i = ( row*matrix_width )+col;
2090  int16_t map_data = xy_table[i];
2091 
2092  if( map_data == -1 ){
2093  xy_table[i] = index;
2094  index++;
2095  found_visible = true;
2096  }
2097 
2098  else if( map_data == -2 ){
2099  if( last_data == -1 ){
2100  index+=30;
2101  }
2102  }
2103 
2104  last_data = map_data;
2105  }
2106 
2107  if( found_visible ){
2108  visible_rows++;
2109  }
2110  }
2111 
2112  NUM_LEDS = 35*chars_x; // account for first row
2113 
2114  // Solve additional rows
2115  if( chars_y > 1 ){
2116  uint8_t rows_left = chars_y-1;
2117  uint16_t row_length = ( display_width*display_height )*chars_x;
2118  for( uint8_t ii = 0; ii < rows_left; ii++ ){
2119  for( uint16_t r = 0; r < row_length; r++ ){
2120  uint16_t final_src_index = ( ii*row_length )+r;
2121  int16_t src_data = xy_table[final_src_index];
2122  if( src_data >= 0 ){
2123  src_data += ( 35*chars_x );
2124 
2125  if( src_data > NUM_LEDS ){
2126  NUM_LEDS = src_data+1;
2127  }
2128  xy_table[final_src_index+row_length] = src_data;
2129  }
2130  }
2131  }
2132  }
2133 
2134  uint16_t index = NUM_LEDS;
2135 
2136  //Serial.println( "SOLVING INVISIBLE" );
2137  for( uint16_t y = 0; y < matrix_height; y++ ){
2138  for( uint16_t x = 0; x < matrix_width; x++ ){
2139  uint16_t i = ( y * matrix_width ) + x;
2140  uint16_t j = xy_table[i];
2141 
2142  if( xy_table[i] == -2 ){
2143  xy_table[i] = index;
2144  index++;
2145  }
2146  }
2147  }
2148  //Serial.println( "DONE" );
2149 }
This is the software documentation for using Pixie Chroma functions on Arduino! For full example usag...
uint16_t NUM_PIXELS
Stores the total number of pixels, including invisible pixels.
void color_blur(fract8 blur_amount)
Blurs the color buffer in both axes by blur_amount.
void draw_line(int16_t x1, int16_t y1, int16_t x2, int16_t y2)
Draws a line in the mask buffer using Bresenham's line algorithm.
void color(CRGB col)
Sets the entire color buffer to a CRGB value.
void println(const uint8_t *icon)
Prints an Icon to the displays at the current cursor position, then jumps to the next row in the Pixi...
float animation_speed
Used by animation functions to scale the apparent speed of animation.
void write_pix(char *message, int16_t x_offset=0, int16_t y_offset=0)
Internal function for rendering char* strings to the mask buffer.
void set_brightness(uint8_t level)
Takes an 8-bit brightness value and passes it to FastLED internally, to provide global brightness con...
PixieChroma()
Construct a Pixie Chroma class object.
float delta
Used by animation functions as a way of self-regulating speed if performance drops,...
float get_uv_y(int32_t y_pixel)
Returns the Y-axis UV coordinate for a given Y-axis pixel position.
CRGB * color_map
Contains the entire color map, including "invisible" areas.
void set_line_wrap(bool enabled)
Sets the line wrapping behavior.
void add_char(char c, int16_t x_pos, int16_t y_pos)
Internal function for rendering a single char to the mask buffer.
void print_xy_table()
Prints the index table for the calculated XY map. Requires Serial.begin() first to function.
uint8_t * mask
Contains the entire mask, including "invisible" areas.
void begin(const uint8_t data_pin, uint8_t pixies_x, uint8_t pixies_y)
Initializes the display buffer, populates the XY coordinate table, defaults the display colors to gre...
void print(const uint8_t *icon)
Prints an Icon to the displays, at the current cursor position.
void free()
Unfreezes the current mask buffer in memory to allow showing updated text the next time show() is cal...
void blur(fract8 blur_amount)
Blurs the mask buffer in both axes by blur_amount.
void set_animation(void(*action)(PixieChroma *, float))
Accepts a preset or custom function to use for the animation ISR.
void clear()
Clears (blackens) the current mask buffer and resets the cursor to 0,0.
uint16_t NUM_LEDS
Stores the total number of physical LEDs, not including invisible pixels. This is calculated for you ...
uint16_t matrix_width
Stores the final width of the matrix, including invisible pixels.
CRGBPalette16 current_palette
The current FastLED CRGBPalette16 used for animations.
void show()
Processes 1D image data into truncated versions, sending them to the Pixie Chroma displays.
uint16_t uv(float x, float y, bool wrap=false)
This wrapper function returns the 1D color_map / mask index of a given OpenGL-style UV coordinate in ...
uint8_t get_cursor_y()
Returns the cursor's Y position.
void blur_x(fract8 blur_amount)
Blurs the mask buffer in the X axis by blur_amount.
void write(const uint8_t *icon, uint8_t x_pos=0, uint8_t y_pos=0)
Writes an icon* to a specified X and Y cursor position.
int16_t get_cursor_x_exact()
Returns the cursor's X position in exact pixel coordinates.
uint16_t xy(int32_t x, int32_t y, bool wrap=false)
This function returns the 1D color_map / mask index of a given 2D coordinate in the display matrix.
float get_uv_x(int32_t x_pixel)
Returns the X-axis UV coordinate for a given X-axis pixel position.
void color_blur_y(fract8 blur_amount)
Blurs the color buffer in the Y axis by blur_amount.
void color_blur_x(fract8 blur_amount)
Blurs the color buffer in the X axis by blur_amount.
void set_animation_speed(float speed)
Used to scale the animation speed of animation ISRs that can use pix.animation_speed() to scale their...
void color_dim(uint8_t amount)
Darkens the color buffer by an 8-bit amount.
void set_max_power(float volts, uint16_t milliamps)
Sets the maximum power budget in volts and milliamps.
uint16_t matrix_height
Stores the final height of the matrix, including invisible pixels.
int16_t get_cursor_y_exact()
Returns the cursor's Y position in exact pixel coordinates.
float frame_rate
Allows the user to access a live frame rate calculation (1 frame latency)
void set_frame_rate_target(uint16_t target)
Sets the target frame rate for animation. This target frame rate is only used to calculate delta in c...
void set_palette(const uint8_t *pal)
Accepts a const uint8_t (8-bit) array to generate a FastLED Gradient Palette at runtime:
void dim(uint8_t amount, bool reset_cursor=false)
Darkens the mask buffer by an 8-bit amount. Optionally resets the cursor position.
void set_update_mode(t_update_mode mode, uint16_t FPS=60)
Allows for automatic show() calls at a specified frames per second if AUTOMATIC is used....
void set_cursor(uint8_t x_position, uint8_t y_position=0)
Sets the cursor position in a 2D context, in whole displays.
void set_gamma_correction(bool enabled)
Allows you to enable built-in automatic gamma correction, using a fast LUT in pixie_utility....
CRGB kelvin_to_rgb(uint16_t temperature)
Approximates the conversion of a blackbody radiation temperature (i.e. 3500K) to a CRGB color object.
void begin_quad(uint8_t pixies_per_pin, uint8_t pixies_x, uint8_t pixies_y)
Initializes the display buffer, populates the XY coordinate table, defaults the display colors to gre...
uint8_t get_cursor_x()
Returns the cursor's X position.
void blur_y(fract8 blur_amount)
Blurs the mask buffer in the Y axis by blur_amount.
void hold()
Freezes the current mask buffer in memory to prevent showing unfinished text if show() automaticall f...
const uint8_t printable_ascii_offset
Constant defining the offset into the ASCII table that printable characters begin.
Definition: pixie_font.h:16
const uint8_t font_col_width
Constant defining the width of a character.
Definition: pixie_font.h:13
char * dtoa(double input, char *buffer, int precision)
Homebrew C function to convert double precision floats to char*. (Arduino Forum link)
Definition: pixie_utility.h:60
const uint8_t gamma8[]
Used as a fast lookup table for gamma correction.
Definition: pixie_utility.h:33
void(* anim_func)(PixieChroma *_p, float delta)
Used to store the pointer to any preset/custom animation functions the library needs to call during s...
Definition: pixie_utility.h:15