/*************************************************** ** 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 "ILI9341_t3.h" #include "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 = 20.0f * 1000.0f; // ms // TFT pins const uint8_t TFT_DC = 9; const uint8_t TFT_CS = 10; const uint8_t MIC_PIN = 14; const uint8_t BACKLIGHT_PIN = 23; // Use hardware SPI (#13, #12, #11) and the above for CS/DC ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC); 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; iinit( 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; iinit( 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; sperFrame( 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= 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 ); } } } }