|
- /***************************************************
- ** DemoSauce! **
- State-of-the-art graphics for your beautiful TFT display.
-
- Greetz to the Portland Dorkbot Crew!!!!
-
- Programmed by Zach Archer (@zkarcher) :: http://controlzinc.com/
- Using hardware by Thomas Hudson (@hydronics) :: http://thomashudson.org/
-
- Usage:
- * Connect a microphone to MIC_PIN.
- * Connect TFT backlight to BACKLIGHT_PIN.
-
- MIT license, all text above must be included in any redistribution
- ****************************************************/
-
- // https://github.com/zkarcher/demosauce
-
- #include "SPI.h"
- #include "ILI9488_t3.h"
- #include "ILI9488_t3_font_Arial.h"
-
- #include "FrameParams.h"
-
- // Animations
- #include "Checkerboard.h"
- #include "Cube3D.h"
- #include "Leaves.h"
- #include "MagentaSquares.h"
- //#include "MicCheck.h"
- #include "PlasmaCloud.h"
- #include "PlasmaYellow.h"
- #include "Sphere3D.h"
- #include "TriangleWeb.h"
- #include "TwistyText.h"
- #include "Waveform.h"
-
- // Transitions
- #include "TransitionDither.h"
- #include "TransitionHalftone.h"
- #include "TransitionScroll.h"
- #include "TransitionSquares.h"
-
- const boolean DO_BENCHMARKS = true;
- const uint32_t SERIAL_BAUD_RATE = 9600;
-
- const boolean DEBUG_ANIM = false; // dev: for hacking on one animation.
- const uint_fast8_t DEBUG_ANIM_INDEX = 0;
-
- const boolean DEBUG_TRANSITION = false; // dev: set to true for short animation durations
- const int_fast8_t DEBUG_TRANSITION_INDEX = -1; // Supports -1: chooses a transition at random
-
- const int_fast16_t DEFAULT_ANIM_TIME = 10.0f * 1000.0f; // ms
-
- // TFT pins
- const uint8_t TFT_DC = 9;
- const uint8_t TFT_CS = 10;
-
- // Use hardware SPI (#13, #12, #11) and the above for CS/DC
- ILI9488_t3 tft = ILI9488_t3(&SPI, TFT_CS, TFT_DC,23);
- FrameParams frameParams;
- long previousMillis = 0;
-
- Checkerboard * _checkerboard = new Checkerboard();
- Cube3D * _cube3D = new Cube3D();
- Leaves * _leaves = new Leaves();
- MagentaSquares * _magentaSquares = new MagentaSquares();
- PlasmaCloud * _plasmaCloud = new PlasmaCloud();
- PlasmaYellow * _plasmaYellow = new PlasmaYellow();
- Sphere3D * _sphere3D = new Sphere3D();
- TriangleWeb * _triangleWeb = new TriangleWeb();
- TwistyText * _twistyText = new TwistyText();
- Waveform * _waveform = new Waveform();
-
- TransitionDither * _transDither = new TransitionDither();
- TransitionHalftone * _transHalftone = new TransitionHalftone();
- TransitionScroll * _transScroll = new TransitionScroll();
- TransitionSquares * _transSquares = new TransitionSquares();
-
- BaseAnimation **anims; // Array of pointers to BaseAnimation's. Initialized in setup() below.
- int_fast8_t animCount;
-
- BaseAnimation *activeAnim = 0;
- int_fast16_t animTimeLeft = 0;
- BaseAnimation *nextAnim;
-
- BaseTransition **transitions;
- int_fast8_t transCount;
- boolean isTransition = true;
- BaseTransition *activeTransition = 0;
-
- // Benchmarks
- uint32_t frameCount;
-
- // Search the anims[] aray for the activeAnim pointer. If found, return the array index.
- int_fast8_t getActiveAnimIndex() {
- for( int_fast8_t i=0; i<animCount; i++ ) {
- if( anims[i] == activeAnim ) return i;
- }
- return -1; // not found
- }
-
- void setup() {
-
-
- tft.begin();
- tft.setRotation( 3 );
- tft.fillScreen(ILI9488_BLACK);
-
- // Serial
- if( DO_BENCHMARKS ) {
- Serial.begin( SERIAL_BAUD_RATE );
- tft.setTextColor(ILI9488_YELLOW);
- tft.setFont(Arial_18);
- tft.setCursor(98, 42);
- tft.print("waiting for");
- tft.setFont(Arial_24);
- tft.setCursor(100, 80);
- tft.print("Arduino");
- tft.setCursor(60, 120);
- tft.print("Serial Monitor");
- tft.setTextColor(ILI9488_GREEN);
- tft.setFont(Arial_18);
- while (!Serial && millis() < 8000) { // wait for Arduino Serial Monitor
- tft.fillRect(118, 182, 42, 18, ILI9488_BLACK);
- tft.setCursor(118, 182);
- tft.print((8000.0 - (float)millis()) / 1000.0, 1);
- tft.print(" sec");
- delay(100);
- }
- }
- previousMillis = millis();
-
- // Clear
- uint16_t w = tft.width();
- uint16_t h = tft.height();
- tft.fillRect( 0, 0, w, h, 0x0 );
-
- tft.setRotation( 3 ); // ribbon cable on left
- tft.setScroll( 0 );
-
- // Populate anims in the order you want them to display.
- BaseAnimation* ANIMS_TEMP[] = {
- _twistyText,
- _plasmaCloud,
- _waveform,
- _magentaSquares,
- _sphere3D,
- _checkerboard,
- _leaves,
- _cube3D,
- _plasmaYellow,
- _triangleWeb
- };
- animCount = sizeof( ANIMS_TEMP ) / sizeof( BaseAnimation* );
-
- // Retain ANIMS_TEMP objects permanently
- anims = (BaseAnimation**)malloc( animCount * sizeof(BaseAnimation*) );
- for( int_fast8_t i=0; i<animCount; i++ ) {
- anims[i] = ANIMS_TEMP[i];
- anims[i]->init( tft ); // Initalize all animations
- }
-
- BaseTransition* TRANS_TEMP[] = {
- _transDither,
- _transHalftone,
- _transScroll,
- _transSquares
- };
- transCount = sizeof( TRANS_TEMP ) / sizeof( BaseTransition* );
-
- // Retain TRANS_TEMP objects permanently
- transitions = (BaseTransition**)malloc( transCount * sizeof(BaseTransition*) );
- for( int_fast8_t i=0; i<transCount; i++ ) {
- transitions[i] = TRANS_TEMP[i];
- transitions[i]->init( tft );
- }
-
- // Start!
- if( !activeAnim ) {
- if( DEBUG_ANIM ) {
- startAnimation( anims[DEBUG_ANIM_INDEX] );
- } else {
- startAnimation( anims[0] );
- }
- }
- }
-
- void startAnimation( BaseAnimation *newAnim ) {
- isTransition = false;
-
- activeAnim = newAnim;
- tft.fillScreen( activeAnim->bgColor() );
- tft.setScroll( 0 );
- activeAnim->reset( tft );
-
- animTimeLeft = DEFAULT_ANIM_TIME;
-
- if( DEBUG_TRANSITION ) animTimeLeft = 2000;
-
- if( DO_BENCHMARKS ) {
- Serial.println("---");
- Serial.print( activeAnim->title() );
-
- if( activeAnim->willForceTransition() ) {
- // TwistyText does not obey DEFAULT_ANIM_TIME
- Serial.println("");
-
- } else {
- Serial.print(" [");
- Serial.print( (uint8_t)(animTimeLeft / 1000.0f) );
- Serial.println(" secs]");
- }
-
- frameCount = 0;
- }
- }
-
- void loop() {
- // Frame multiplier
- long newMillis = millis();
- uint_fast8_t elapsed = newMillis - previousMillis;
- previousMillis = newMillis;
- frameParams.timeMult = elapsed * (60.0f / 1000); // 1.0==exactly 60fps. 4.0==15fps, 4x slower
-
- // Get some audio input
- const uint_fast8_t SAMPLES_PER_FRAME = 1;
- frameParams.audioPeak = 0;
- uint_fast16_t sum = 0;
-
- for( uint_fast8_t s=0; s<SAMPLES_PER_FRAME; s++ ) {
- uint_fast16_t sample = abs( random(0,1023) - 511 );
- frameParams.audioPeak = max( frameParams.audioPeak, sample );
- sum += sample;
- }
- frameParams.audioMean = sum * (1.0 / (512*SAMPLES_PER_FRAME)); // Range: 0..1
-
- frameParams.audioPeak = min( (uint_fast16_t)frameParams.audioPeak, (uint_fast16_t)511 );
-
- if( !isTransition ) {
- activeAnim->perFrame( tft, frameParams );
- animTimeLeft -= elapsed;
-
- if( DO_BENCHMARKS ) frameCount++;
- }
-
- // Has this animation expired?
- boolean willForceTransition = activeAnim->willForceTransition();
- boolean forceTransitionNow = activeAnim->forceTransitionNow();
-
- // Debugging transitions: Ignore animations hogging the screen
- if( DEBUG_TRANSITION ) willForceTransition = false;
-
- if( !DEBUG_ANIM ) {
- if( (!willForceTransition && (animTimeLeft <= 0)) || forceTransitionNow ) {
-
- // If the transition has not started yet, then start it.
- if( !isTransition ) {
- isTransition = true;
-
- nextAnim = anims[ (getActiveAnimIndex() + 1) % animCount ];
-
- /*
- // Print some debug stuff
- if( DO_BENCHMARKS ) {
- Serial.println("---------- Testing sinf() vs sin() performance");
- unsigned long then = micros();
- float z = 0;
- for( uint32_t i=0; i<50000; i++ ) {
- z += sinf( (float)i );
- }
- unsigned long now = micros();
- Serial.print("sinf:");
- Serial.println( now - then );
- Serial.print(" z:");
- Serial.println( z );
-
- then = micros();
- z = 0;
- for( uint32_t i=0; i<50000; i++ ) {
- z += sin( (float)i );
- }
- now = micros();
- Serial.print(" sin:");
- Serial.println( now - then );
- Serial.print(" z:");
- Serial.println( z );
- }
- */
-
- // When we loop back to the first animation, shuffle the other ones for variety.
- if( nextAnim == anims[0] ) {
- for( int_fast8_t i=1; i<animCount-1; i++ ) {
- uint_fast8_t shuffleIdx = random( i, animCount );
-
- BaseAnimation* temp = anims[i];
- anims[i] = anims[shuffleIdx];
- anims[shuffleIdx] = temp;
- }
- }
-
- // Choose a random transition
- activeTransition = transitions[ random(transCount) ];
- if( DEBUG_TRANSITION && (DEBUG_TRANSITION_INDEX >= 0) ) {
- activeTransition = transitions[ DEBUG_TRANSITION_INDEX ];
- }
-
- activeTransition->restart( tft, nextAnim->bgColor() );
-
- // Benchmark: show how many frames the animation completed while alive.
- if( DO_BENCHMARKS ) {
- Serial.print("Frame count (more is better): ");
- Serial.print( frameCount );
-
- if( !activeAnim->willForceTransition() ) {
- Serial.print( " (" );
- Serial.print( (float)frameCount / (DEFAULT_ANIM_TIME / 1000.0f) );
- Serial.println(" FPS)");
- } else {
- Serial.println("");
- }
- }
- }
-
- // After the transition ends, advance to the next animation
- activeTransition->perFrame( tft, frameParams );
- if( activeTransition->isComplete() ) {
- startAnimation( nextAnim );
- }
-
- }
- }
-
- }
|