/*
* Software to control a 4x4x4 LED cube with Arduino
*
*
* I used lots of code from Christian Moen ([email protected])
* and Ståle Kristoffersen ([email protected])
*
* However, I connected the LEDs differently (shift regs, SPI etc)
* so at least the IRQ routine and most of the stuff in main.cpp
* was done by me.
*
* License: http://creativecommons.org/licenses/by-nc-sa/3.0/
*
*
* 2011, Matthias Wientapper
*
*/
//#include <Arduino.h>
#include <SPI.h>
//#include <TimerOne.h>
//#include "string.h"
//#include "cube.h"
//#include "draw.h"
//#include "effect.h"
#include <avr/pgmspace.h>
// SPI interface on Arduino:
// 10 (SS), 11 (MOSI), 12 (MISO), and 13 (SCK).
#define latch_pin 10 // can use any pin you want to latch the shift registers
#define blank_pin 4 // same, can use any pin you want for this, just make sure you pull up via a 1k to 5V
#define data_pin 11 // used by SPI, must be pin 11
#define clock_pin 13 // used by SPI, must be 13
int latchPinPORTB = latch_pin - 8; // direct port communication correction
//***variables***variables***variables***variables***variables***variables***variables***variables
// Some of the functions are created to be portable
// These functions will work on cubes of different sizes by
// changing this constant
#define CUBE_SIZE 4
#define CUBE_BYTES (CUBE_SIZE*CUBE_SIZE)
#define CUBE_LEDS (CUBE_SIZE*CUBE_SIZE)*CUBE_SIZE
#define NUM_IC595 (CUBE_BYTES/8)
// Cube buffer
// Data from this array is loaded onto the cube for each duty cycle
byte Cube[CUBE_SIZE*NUM_IC595];
byte TempCube[CUBE_SIZE*NUM_IC595];
const char Font[95][8] = {
{ 3, 0x00, 0x00, 0x00, 0, 0, 0, 0}, //
{ 4, 0X06, 0Xdf, 0Xdf, 0X06, 0, 0, 0}, // !
{ 5, 0X06, 0x0e, 0x00, 0x0e, 0X06, 0, 0}, // "
{ 7, 0x28, 0xfe, 0xfe, 0x28, 0xfe, 0xfe, 0x28}, // #
{ 5, 0x48, 0x54, 0xfe, 0x54, 0x24, 0, 0}, // $
{ 6, 0x46, 0x66, 0x30, 0x18, 0xcc, 0xc4, 0}, // %
{ 7, 0x64, 0xfe, 0x8a, 0x9a, 0xee, 0xc4, 0}, // &
{ 3, 0x10, 0x1e, 0x0e, 0, 0, 0, 0}, // '
{ 4, 0x3c, 0x7e, 0xc3, 0x81, 0, 0, 0}, // (
{ 4, 0x81, 0xc3, 0x7e, 0x3c, 0, 0, 0}, // )
{ 7, 0x10, 0x54, 0x7c, 0x38, 0x7c, 0x54, 0x10}, // *
{ 6, 0x18, 0x18, 0x7e, 0x7e, 0x18, 0x18, 0}, // +
{ 3, 0x80, 0xf0, 0x70, 0, 0, 0, 0}, // ,
{ 4, 0x18, 0x18, 0x18, 0x18, 0, 0, 0}, // -
{ 2, 0xc0, 0xc0, 0, 0, 0, 0, 0}, // .
{ 7, 0x40, 0x60, 0x30, 0x18, 0x0c, 0X06, 0x02}, // /
{ 6, 0x7e, 0xff, 0x91, 0x89, 0xff, 0x7e, 0}, // 0
{ 6, 0x80, 0x84, 0xff, 0xff, 0x80, 0x80, 0}, // 1
{ 6, 0xc2, 0xe3, 0xb1, 0x99, 0x8f, 0x86, 0}, // 2
{ 6, 0x42, 0xc3, 0x99, 0x99, 0xff, 0x66, 0}, // 3
{ 6, 0x18, 0x14, 0x12, 0xff, 0xff, 0x10, 0}, // 4
{ 6, 0x4f, 0xcf, 0x89, 0x89, 0xf9, 0x71, 0}, // 5
{ 6, 0x7e, 0xff, 0x89, 0x89, 0xfb, 0x72, 0}, // 6
{ 6, 0x03, 0x03, 0xf1, 0xfd, 0x0f, 0x03, 0}, // 7
{ 6, 0x76, 0xff, 0x89, 0x89, 0xff, 0x76, 0}, // 8
{ 6, 0x4e, 0Xdf, 0x91, 0x91, 0xff, 0x3e, 0}, // 9
{ 2, 0x6c, 0x6c, 0, 0, 0, 0, 0}, // :
{ 3, 0x80, 0xec, 0x6c, 0, 0, 0, 0}, // ;
{ 5, 0x10, 0x38, 0x6c, 0xc6, 0x82, 0, 0}, // <
{ 4, 0x28, 0x28, 0x28, 0x28, 0, 0, 0}, // =
{ 5, 0x82, 0xc6, 0x6c, 0x38, 0x10, 0, 0}, // >
{ 6, 0x04, 0X06, 0xb2, 0xb2, 0x1e, 0x0c, 0}, // ?
{ 6, 0x3c, 0x42, 0x5a, 0x5a, 0x4c, 0x20, 0}, // @
{ 6, 0xfe, 0xff, 0x11, 0x11, 0xff, 0xfe, 0}, // A
{ 6, 0xff, 0xff, 0x89, 0x89, 0xff, 0x76, 0}, // B
{ 6, 0x7e, 0xff, 0x81, 0x81, 0xc3, 0x42, 0}, // C
{ 6, 0xff, 0xff, 0x81, 0x81, 0xff, 0x7e, 0}, // D
{ 6, 0xff, 0xff, 0x89, 0x89, 0x89, 0x81, 0}, // E
{ 6, 0xff, 0xff, 0x09, 0x09, 0x09, 0x01, 0}, // F
{ 6, 0x7e, 0xff, 0x81, 0xa1, 0xe3, 0x62, 0}, // G
{ 6, 0xff, 0xff, 0x10, 0x10, 0xff, 0xff, 0}, // H
{ 4, 0x81, 0xff, 0xff, 0x81, 0, 0, 0}, // I
{ 6, 0x60, 0xe0, 0x81, 0xff, 0x7f, 0x01, 0}, // J
{ 6, 0xff, 0xff, 0x3c, 0x66, 0xe3, 0x81, 0}, // K
{ 6, 0xff, 0xff, 0x80, 0x80, 0x80, 0x80, 0}, // L
{ 7, 0xff, 0xff, 0X06, 0x0c, 0X06, 0xff, 0xff}, // M
{ 7, 0xff, 0xff, 0x0c, 0x18, 0x30, 0xff, 0xff}, // N
{ 6, 0x7e, 0xff, 0x81, 0x81, 0xff, 0x7e, 0}, // O
{ 6, 0xff, 0xff, 0x11, 0x11, 0x1f, 0x0e, 0}, // P
{ 6, 0x3e, 0x7f, 0x41, 0x61, 0xff, 0xbe, 0}, // Q
{ 6, 0xff, 0xff, 0x19, 0x39, 0xef, 0xc6, 0}, // R
{ 6, 0x4e, 0Xdf, 0x99, 0x99, 0xfb, 0x72, 0}, // S
{ 6, 0x03, 0x01, 0xff, 0xff, 0x01, 0x03, 0}, // T
{ 6, 0x7f, 0xff, 0x80, 0x80, 0xff, 0xff, 0}, // U
{ 6, 0x3f, 0x7f, 0xc0, 0xc0, 0x7f, 0x3f, 0}, // V
{ 7, 0xff, 0xff, 0x60, 0x30, 0x60, 0xff, 0xff}, // W
{ 7, 0xc3, 0xe7, 0x3c, 0x18, 0x3c, 0xe7, 0xc3}, // X
{ 6, 0x0f, 0x1f, 0xf0, 0xf0, 0x1f, 0x0f, 0}, // Y
{ 6, 0xc3, 0xe3, 0xfb, 0Xdf, 0xc7, 0xc3, 0}, // Z
{ 4, 0xff, 0xff, 0x81, 0x81, 0, 0, 0}, // [
{ 7, 0x02, 0X06, 0x0c, 0x18, 0x30, 0x60, 0x40}, // \
{ 4, 0x81, 0x81, 0xff, 0xff, 0, 0, 0}, // ]
{ 7, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10}, // ^
{ 4, 0x80, 0x80, 0x80, 0x80, 0, 0, 0}, // _
{ 3, 0X06, 0x0e, 0x08, 0, 0, 0, 0}, // `
{ 6, 0x40, 0xe8, 0xa8, 0xa8, 0xf8, 0xf0, 0}, // a
{ 6, 0xfe, 0xfe, 0x90, 0x90, 0xf0, 0x60, 0}, // b
{ 6, 0x70, 0xf8, 0x88, 0x88, 0xd8, 0x50, 0}, // c
{ 6, 0x60, 0xf0, 0x90, 0x90, 0xfe, 0xfe, 0}, // d
{ 6, 0x70, 0xf8, 0xa8, 0xa8, 0xb8, 0x30, 0}, // e
{ 6, 0x20, 0xfc, 0xfe, 0x22, 0x26, 0x04, 0}, // f
{ 6, 0x18, 0xbc, 0xa4, 0xa4, 0xfc, 0x7c, 0}, // g
{ 6, 0xfe, 0xfe, 0x10, 0x10, 0xf0, 0xe0, 0}, // h
{ 4, 0x80, 0xf4, 0xf4, 0x80, 0, 0, 0}, // i
{ 5, 0x60, 0xe0, 0x80, 0xfa, 0x7a, 0, 0}, // j
{ 6, 0xfe, 0xfe, 0x20, 0x70, 0xd8, 0x88, 0}, // k
{ 2, 0xfe, 0xfe, 0, 0, 0, 0, 0}, // l
{ 7, 0xf8, 0xf8, 0x30, 0xe0, 0x30, 0xf8, 0xf8}, // m
{ 6, 0xf8, 0xf8, 0x18, 0x18, 0xf8, 0xf0, 0}, // n
{ 6, 0x70, 0xf8, 0x88, 0x88, 0xf8, 0x70, 0}, // o
{ 6, 0xfc, 0xfc, 0x24, 0x24, 0x3c, 0x18, 0}, // p
{ 7, 0x18, 0x3c, 0x24, 0xfc, 0xfc, 0x80, 0xc0}, // q
{ 6, 0xf8, 0xf8, 0x08, 0x08, 0x38, 0x30, 0}, // r
{ 6, 0x90, 0xa8, 0xa8, 0xa8, 0xa8, 0x48, 0}, // s
{ 6, 0x10, 0x10, 0xfc, 0xfc, 0x10, 0x10, 0}, // t
{ 6, 0x78, 0xf8, 0x80, 0x80, 0xf8, 0xf8, 0}, // u
{ 6, 0x30, 0x70, 0xc0, 0xc0, 0x70, 0x30, 0}, // v
{ 7, 0x78, 0xf8, 0x80, 0xf0, 0x80, 0xf8, 0x78}, // w
{ 6, 0x88, 0xd8, 0x70, 0x70, 0xd8, 0x88, 0}, // x
{ 6, 0x18, 0xb8, 0xa0, 0xa0, 0xf8, 0x78, 0}, // y
{ 4, 0xc8, 0xe8, 0xb8, 0x98, 0, 0, 0}, // z
{ 5, 0x10, 0x7c, 0xee, 0x82, 0x82, 0, 0}, // {
{ 1, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, // |
{ 5, 0x82, 0x82, 0xee, 0x7c, 0x10, 0, 0}, // }
{ 6, 0x10, 0x18, 0x08, 0x18, 0x10, 0x08, 0} // ~
};
// Some effects can render on different axis
// for example send pixels along an axis
// for better readability, we use the following predefined constants
#define AXIS_X 0x78
#define AXIS_Y 0x79
#define AXIS_Z 0x7a
#define LEFT 0x1a
#define RIGHT 0x1b
#define FRONT 0x1c
#define BACK 0x1d
#define UP 0x1e
#define DOWN 0x1f
// Total number of effects
// Used in the main loop to loop through all the effects one by bone.
// Set this number one higher than the highest number inside switch()
// in launch_effect() in launch_effect.c
#define EFFECTS_TOTAL 29
int shift_out;
byte anode[CUBE_SIZE];//byte to write to the anode shift register, 8 of them, shifting the ON z in each byte in the array
int current_layer;
int layers = (CUBE_SIZE*NUM_IC595)-1;
int ledOnTime;
int skipDelay=1;
byte linepath[CUBE_SIZE+(CUBE_SIZE-2)][NUM_IC595];
//****setup****setup****setup****setup****setup****setup****setup****setup****setup****setup****setup****setup****setup
void setup() {
// This variable specifies which layer is currently being drawn by the
// cube interrupt routine. We assign a value to it to make sure it's not >7.
current_layer = 0;
SPI.setBitOrder(MSBFIRST);//Most Significant Bit First
SPI.setDataMode(SPI_MODE0);// Mode 0 Rising edge of data, keep clock low
SPI.setClockDivider(SPI_CLOCK_DIV2);//Run the data in at 16MHz/2 - 8MHz
Serial.begin(9600);// if you need it?
noInterrupts();// kill interrupts until everybody is set up
//We use Timer 1 to refresh the cube
TCCR1A = B00000000;//Register A all 0's since we're not toggling any pins
TCCR1B = B00001011;//bit 3 set to place in CTC mode, will call an interrupt on a counter match
//bits 0 and 1 are set to divide the clock by 64, so 16MHz/64=250kHz
TIMSK1 = B00000010;//bit 1 set to call the interrupt on an OCR1A match
// OCR1A = 30; // you can play with this, but I set it to 30, which means:
OCR1A = 30; // you can play with this, but I set it to 30, which means:
//our clock runs at 250kHz, which is 1/250kHz = 4us
//with OCR1A set to 30, this means the interrupt will be called every (30+1)x4us=124us,
//which gives a multiplex frequency of about 8kHz
// here I just set up the anode array, this is what's written to the anode shift register, to enable each z
for(char aa=0 ; aa<CUBE_SIZE ; aa++) anode[aa] = (1 << aa);
buildlinepath();
//finally set up the Outputs
pinMode(latch_pin, OUTPUT);//Latch
pinMode(data_pin, OUTPUT);//MOSI DATA
pinMode(clock_pin, OUTPUT);//SPI Clock
//pinMode(blank_pin, OUTPUT);//Output Enable important to do this last, so LEDs do not flash on boot up
SPI.begin();//start up the SPI library
interrupts();//let the show begin, this lets the multiplexing start
}
ISR(TIMER1_COMPA_vect)
{ //***WRITE TO CUBE***WRITE TO CUBE***WRITE TO CUBE***WRITE TO CUBE***WRITE TO CUBE***WRITE TO CUBE***WRITE TO CUBE
//This routine is called in the background automatically at frequency set by OCR1A
//In this code, I set OCR1A to 30, so this is called every 124us, giving each z in the cube 124us of ON time
//There are 8 zs, so we have a maximum brightness of 1/8, since the z must turn off before the next z is turned on
//The frequency of the multiplexing is then 124us*8=992us, or 1/992us= about 1kHz
PORTD |= 1 << blank_pin; //The first thing we do is turn all of the LEDs OFF, by writing a 1 to the blank pin
//Note, in my bread-boarded version, I was able to move this way down in the cube, meaning that the OFF time was minimized
//do to signal integrity and parasitic capcitance, my rise/fall times, required all of the LEDs to first turn off, before updating
//otherwise you get a ghosting effect on the previous z
// Activate the current layer
SPI.transfer(anode[current_layer]);
// Loop through all 8 bytes of data in the current layer
// and latch it onto the cube.
for (shift_out = layers; shift_out > layers - NUM_IC595; shift_out--) SPI.transfer(Cube[shift_out]);
PORTB |= 1 << latchPinPORTB; //Latch pin HIGH
PORTB &= ~(1 << latchPinPORTB); //Latch pin LOW
PORTD &= ~(1 << blank_pin); //Blank pin LOW to turn on the LEDs with the new data
// Increment the curren_layer counter so that the next layer is
// drawn the next time this function runs.
current_layer++;
layers -= NUM_IC595;
// We want to count from 0-7, so set it to 0 when it reaches 8.
if (current_layer == CUBE_SIZE)
current_layer = 0;
if (layers < 0)
layers = (CUBE_SIZE*NUM_IC595)-1;
pinMode(blank_pin, OUTPUT);//moved down here so outputs are all off until the first call of this function
}//***WRITE TO CUBE END***WRITE TO CUBE END***WRITE TO CUBE END***WRITE TO CUBE END***WRITE TO CUBE END***WRITE TO CUBE END***WRITE TO CUBE END
void loop() { //***start loop***start loop***start loop***start loop***start loop***start loop***start loop***start loop***start loop
int i;
while (1)
{
// Show the effects in a predefined order
for (i = 0; i < EFFECTS_TOTAL; i++)
{
clearCube();
if(skipDelay==0) delay(1000);
else skipDelay=0;
launch_effect(i);
// Show the effects in a random order.
// Comment the two lines above and uncomment this
// if you want the effects in a random order.
// launch_effect(random(EFFECTS_TOTAL));
}
}
}//***end loop***end loop***end loop***end loop***end loop***end loop***end loop***end loop***end loop***end loop***end loop***end loop
void launch_effect(int effect) {
// the show
switch (effect) {
case 0:
// Test function to see if all leds are connected correctly; first led = left low back; last led = right high front
// effect_LED_Test();
// usage: effect_rain(number of iterations)
// effect_rain(100);
break;
case 1:
// usage: effect_sendvoxels_rand_z(number of iterations, delay between leds moving up/down, delay for next led to go)
// effect_sendvoxels_rand_z(20, 220, 2000);
break;
case 2:
// usage: effect_random_filler (delay between leds coming/going, state: 1=fill up; 0=clear)
/* for(int ii=0 ; ii<10 ; ii++)
{
if(ii%2) effect_random_filler(150,0);
else effect_random_filler(150,1);
}
*/ break;
case 3:
// usage: effect_z_updown (number of iterations, delay between movement)
// effect_z_updown(50,750);
break;
case 4:
// usage: effect_wormsqueeze(width of the worm, worm move along which axis, direction where to start, number of iterations, delay between movements)
// effect_wormsqueeze(1, AXIS_Z, -1, 100, 1000);
break;
case 5:
// no usage !! blinking pattern for all leds
// effect_blinky2();
break;
case 6:
// usage: effect_box_shrink_grow (number of (repeated) iterations, mirror between X/Y-Axis , Mirror Z-Axis, delay between movements)
/* for (int ii = 0; ii < 20; ii++)
{
effect_box_shrink_grow (1, ii%4, ii & 0x04, 450);
}
*/ break;
case 7:
// usage: effect_box_woopwoop (delay between movements, 0=grow; 1=shrink)
/* for (int ii=0 ; ii < 10 ; ii++)
{
if(ii%2) effect_box_woopwoop(800,0);
else effect_box_woopwoop(800,1);
}
*/ break;
case 8:
// usage: effect_planboing (plane X/Y/Z, movement speed)
/* for(int ii=0 ; ii < 5 ; ii++)
{
effect_planboing (AXIS_Z, 1500);
effect_planboing (AXIS_X, 1500);
effect_planboing (AXIS_Y, 1500);
}
*/ break;
case 9:
// usage: effect_telcstairs (0=down->up; 1=up->down, delay, 0=clear; 1=fill)
/* for(int ii=0 ; ii<5 ; ii++)
{
effect_telcstairs(0,800,1);
effect_telcstairs(0,800,0);
effect_telcstairs(1,800,1);
effect_telcstairs(1,800,0);
}
*/ break;
case 10:
// usage: effect_axis_updown_randsuspend(axis, delay between led movement, sleep midway, invert)
/* effect_axis_updown_randsuspend(AXIS_Z, 550,5000,0);
effect_axis_updown_randsuspend(AXIS_Z, 550,5000,1);
effect_axis_updown_randsuspend(AXIS_Z, 550,5000,0);
effect_axis_updown_randsuspend(AXIS_Z, 550,5000,1);
effect_axis_updown_randsuspend(AXIS_X, 550,5000,0);
effect_axis_updown_randsuspend(AXIS_X, 550,5000,1);
effect_axis_updown_randsuspend(AXIS_X, 550,5000,0);
effect_axis_updown_randsuspend(AXIS_X, 550,5000,1);
effect_axis_updown_randsuspend(AXIS_Y, 550,5000,0);
effect_axis_updown_randsuspend(AXIS_Y, 550,5000,1);
effect_axis_updown_randsuspend(AXIS_Y, 550,5000,0);
effect_axis_updown_randsuspend(AXIS_Y, 550,5000,1);
*/ break;
case 11:
// if(CUBE_SIZE>=8) effect_stringfly2("INSTRUCTABLES");
// else
skipDelay=1;
break;
case 12:
// usage: effect_boxside_randsend_parallel (axis, startpoint(0) or inversion(1), delay, mode)
/* effect_boxside_randsend_parallel (AXIS_Z, 0 , 200,1);
delay(250);
effect_boxside_randsend_parallel (AXIS_Z, 1 , 200,1);
delay(250);
effect_boxside_randsend_parallel (AXIS_Z, 0 , 200,2);
delay(250);
effect_boxside_randsend_parallel (AXIS_Z, 1 , 200,2);
delay(250);
effect_boxside_randsend_parallel (AXIS_Y, 0 , 200,1);
delay(250);
effect_boxside_randsend_parallel (AXIS_Y, 1 , 200,1);
delay(250);
effect_boxside_randsend_parallel (AXIS_Y, 0 , 200,2);
delay(250);
effect_boxside_randsend_parallel (AXIS_Y, 1 , 200,2);
delay(250);
effect_boxside_randsend_parallel (AXIS_X, 0 , 200,1);
delay(250);
effect_boxside_randsend_parallel (AXIS_X, 1 , 200,1);
delay(250);
effect_boxside_randsend_parallel (AXIS_X, 0 , 200,2);
delay(250);
effect_boxside_randsend_parallel (AXIS_X, 1 , 200,2);
delay(250);
*/ break;
case 13:
// if(CUBE_SIZE>=8) effect_smileyspin(2,750,1);
// else
skipDelay=1;
break;
case 14:
// usage: effect_pathspiral(number of iterations, delay between iterations)
// effect_pathspiral(100,150);
break;
case 15:
// if(CUBE_SIZE>=8) effect_path_bitmap(700,3,3);
// else
skipDelay=1;
break;
case 16:
// if(CUBE_SIZE>=8) effect_path_text(1000,"LED-Cube");
// else
skipDelay=1;
break;
case 17:
// usage: effect_rand_patharound(number of iterations, delay between iterations)
// effect_rand_patharound(200,100);
break;
case 18:
// if(CUBE_SIZE>=8) effect_smileyspin(2,1000,2);
// else
skipDelay=1;
break;
case 19:
// no usage !!
// effect_random_sparkle();
break;
case 20:
// no usage !!
// effect_folder();
break;
case 21:
// No usage !!
// effect_count_up(); //AZ
break;
case 22:
// if(CUBE_SIZE>=8) effect_fireworks (20, 6, 100);
// else
skipDelay=1;
break;
case 23:
// usage: effect_moveopensquare(number of repeats, delay between moves, delay between alternates)
// effect_moveopensquare(5,100,200);
break;
case 24:
// usage: effect_sendplane_rand_z(startpoint:0 or CUBE_SIZE-1, delay between moves up/down, delay for next voxel to start)
// for(int ii=0; ii<5 ; ii++)
// {
// effect_sendplane_rand_z(0, 20, 80);
// effect_sendplane_rand_z(CUBE_SIZE-1, 20, 80);
// }
break;
case 25:
// usage: effect_running_up_down(delay between moves)
effect_running_up_down(50);
break;
case 26:
// usage: effect_rotatewall(number of iterations, delay between moves)
// effect_rotatewall(5, 150);
break;
case 27:
// usage: effect_spinning_plane(number of iterations, delay between spin moves)
// effect_spinning_plane(75, 100);
break;
case 28:
// usage: effect_spiral(number of iterations, delay between spin moves)
// effect_spiral(75, 100);
break;
}
}
//*** start effect functions *** start effect functions *** start effect functions *** start effect functions *** start effect functions ***
void effect_LED_Test()
{
int x, y, z;
for(z = 0; z < CUBE_SIZE; z++)
{
for(y = 0; y < CUBE_SIZE; y++)
{
for(x = 0; x < CUBE_SIZE; x++)
{
setvoxel(x, y, z);
delay(100);
}
}
}
}// effect_LED_Test
void effect_rain(int iterations)
{
int i, ii;
int rnd_x;
int rnd_y;
int rnd_num;
for (ii = 0; ii < iterations; ii++)
{
rnd_num = rand() % CUBE_SIZE;
for (i = 0; i < rnd_num; i++)
{
rnd_x = rand() % CUBE_SIZE;
rnd_y = rand() % CUBE_SIZE;
setvoxel(rnd_x, rnd_y, CUBE_SIZE-1);
}
delay(100);
shift(AXIS_Z, -1);
}
}
// For each coordinate along X and Y, a voxel is set either at z 0 or at z 7
// for n iterations, a random voxel is sent to the opposite side of where it was.
void effect_sendvoxels_rand_z(int iterations, int del, int wait)
{
unsigned char x, y, last_x = 0, last_y = 0, i;
clearCube();
// Loop through all the X and Y coordinates
for (x = 0; x < CUBE_SIZE; x++)
{
for (y = 0; y < CUBE_SIZE; y++)
{
// Then set a voxel either at the top or at the bottom
// rand()%2 returns either 0 or 1. multiplying by 7 gives either 0 or 7.
setvoxel(x, y, ((rand() % 2)*(CUBE_SIZE-1)));
}
}
for (i = 0; i < iterations; i++)
{
// Pick a random x,y position
x = rand() % CUBE_SIZE;
y = rand() % CUBE_SIZE;
// but not the sameone twice in a row
if (y != last_y && x != last_x)
{
// If the voxel at this x,y is at the bottom
if (getvoxel(x, y, 0))
{
// send it to the top
sendvoxel_z(x, y, 0, del);
}
else
{
// if its at the top, send it to the bottom
sendvoxel_z(x, y, CUBE_SIZE-1, del);
}
delay_ms(wait);
// Remember the last move
last_y = y;
last_x = x;
}
}
}
// Set or clear exactly 512 voxels in a random order.
void effect_random_filler (int delay, int state)
{
int x, y, z;
int effectloop = 0;
if (state == 1) clearCube();
else fillCube();
while (effectloop < (CUBE_LEDS-1))
{
x = rand() % CUBE_SIZE;
y = rand() % CUBE_SIZE;
z = rand() % CUBE_SIZE;
if ((state == 0 && getvoxel(x,y,z) == 0x01) || (state == 1 && getvoxel(x,y,z) == 0x00))
{
altervoxel(x, y, z, state);
delay_ms(delay);
effectloop++;
}
}
}//effect_random_filler
void effect_z_updown (int iterations, int delay)
{
unsigned char positions[CUBE_BYTES];
unsigned char destinations[CUBE_BYTES];
int i, y, move;
for (i = 0; i < CUBE_BYTES; i++)
{
positions[i] = CUBE_SIZE/2;
destinations[i] = rand() % CUBE_SIZE;
}
for (i = 0; i < CUBE_SIZE; i++)
{
effect_z_updown_move(positions, destinations, AXIS_Z);
delay_ms(delay);
}
for (i = 0; i < iterations; i++)
{
for (move = 0; move < CUBE_SIZE; move++)
{
effect_z_updown_move(positions, destinations, AXIS_Z);
delay_ms(delay);
}
delay_ms(delay*4);
for (y = 0; y < (CUBE_BYTES/2); y++)
{
destinations[rand() % CUBE_BYTES] = rand() % CUBE_SIZE;
}
}
}//effect_z_updown
void effect_z_updown_move (unsigned char positions[CUBE_BYTES], unsigned char destinations[CUBE_BYTES], char axis)
{
int px;
for (px=0; px<CUBE_BYTES; px++)
{
if (positions[px] < destinations[px]) positions[px]++;
if (positions[px] > destinations[px]) positions[px]--;
}
draw_positions_axis (AXIS_Z, positions,0);
}//effect_z_updown_move
void effect_wormsqueeze(int size, int axis, int direction, int iterations, int del)
{
int x, y, i, j, k, dx, dy;
int cube_size;
int origin = 1;
if (direction == -1) origin = CUBE_SIZE-1;
cube_size = CUBE_SIZE - (size - 1);
x = rand() % cube_size;
y = rand() % cube_size;
for (i = 0; i < iterations; i++)
{
dx = ((rand() % CUBE_SIZE-1) - 1);
dy = ((rand() % CUBE_SIZE-1) - 1);
if ((x + dx) > 0 && (x + dx) < cube_size) x += dx;
if ((y + dy) > 0 && (y + dy) < cube_size) y += dy;
shift(axis, direction);
for (j = 0; j < size; j++)
{
for (k = 0; k < size; k++)
{
if (axis == AXIS_Z) setvoxel(x + j, y + k, origin);
if (axis == AXIS_Y) setvoxel(x + j, origin, y + k);
if (axis == AXIS_X) setvoxel(origin, y + j, x + k);
}
}
delay_ms(del);
}
}
void effect_blinky2()
{
int i, r;
for (r = 0; r < 2; r++)
{
i = 750;
while (i > 0)
{
clearCube();
delay(i);
fillCube();
delay(75);
i = i - (15 + (1000 / (i / 5)));
}
delay(1000);
i =750;
while (i > 0)
{
clearCube();
delay(751 - i);
fillCube();
delay(75);
i = i - (15 + (1000 / (i / 5)));
}
}
}//effect_blinky2
void effect_box_shrink_grow (int iterations, int rot, int flip, uint16_t delay)
{
int x, i, xyz;
for (x = 0; x < iterations; x++)
{
for (i = 0; i< (CUBE_SIZE*2); i++)
{
xyz = (CUBE_SIZE-1) - i; // This reverses counter i between 0 and 7.
if (i > (CUBE_SIZE-1)) xyz = i - CUBE_SIZE; // at i > 7, i 8-15 becomes xyz 0-7.
clearCube();
delay_ms(1000);
noInterrupts(); // disable interrupts while the cube is being rotated
box_wireframe(0, 0, 0, xyz, xyz, xyz);
if (flip > 0) // upside-down
mirror_z();
if (rot == 1 || rot == 3) mirror_y();
if (rot == 2 || rot == 3) mirror_x();
interrupts(); // enable interrupts
delay_ms(delay);
clearCube();
}
}
}//effect_box_shrink_grow
// Creates a wireframe box that shrinks or grows out from the center of the cube.
void effect_box_woopwoop (int delay, int grow)
{
int i, ii;
for (i = 0; i < (CUBE_SIZE/2); i++)
{
ii = i;
if (grow > 0) ii = ((CUBE_SIZE/2) - 1) - i;
box_wireframe((CUBE_SIZE/2) + ii, (CUBE_SIZE/2) + ii, (CUBE_SIZE/2) + ii, ((CUBE_SIZE/2) - 1) - ii, ((CUBE_SIZE/2) - 1) - ii, ((CUBE_SIZE/2) - 1) - ii);
delay_ms(delay*3);
clearCube();
}
}// effect_box_woopwoop
// Draw a plane on one axis and send it back and forth once.
void effect_planboing (int plane, int speed)
{
int i;
for (i = 0; i < CUBE_SIZE; i++)
{
clearCube();
setplane(plane, i);
delay_ms(speed);
}
for (i = (CUBE_SIZE-1); i >= 0; i--)
{
clearCube();
setplane(plane, i);
delay_ms(speed);
}
}//effect_planboing
void effect_telcstairs (int invert, int del, int val)
{
int z;
if(invert)
{
for(z = CUBE_SIZE*2; z >= 0; z--)
{
z = effect_telcstairs_do(z, val, del);
}
}
else
{
for(z = 0; z < CUBE_SIZE*2; z++)
{
z = effect_telcstairs_do(z, val, del);
}
}
}//effect_telcstairs
int effect_telcstairs_do(int z, int val, int del)
{
int x, y;
for(y = 0, x = z; y <= x; y++, z--)
{
if(z < CUBE_SIZE && y < CUBE_SIZE)
{
for(int xx = 0; xx < CUBE_SIZE; xx++)
{
if(val == 0) clrvoxel(xx, y, z);
else setvoxel(xx, y, z);
}
}
}
delay_ms(del);
return x;
}//effect_telcstairs_do
void effect_axis_updown_randsuspend(char axis, int del, int sleep, int invert)
{
unsigned char positions[CUBE_BYTES];
unsigned char destinations[CUBE_BYTES];
int i, px;
// Set 64 random positions
for (i = 0; i < CUBE_BYTES; i++)
{
positions[i] = 0; // Set all starting positions to 0
destinations[i] = rand() % CUBE_SIZE;
}
// Loop 8 times to allow destination 7 to reach all the way
for (i = 0; i < CUBE_SIZE; i++)
{
// For every iteration, move all position one step closer to their destination
for (px = 0; px < CUBE_BYTES; px++)
{
if (positions[px] < destinations[px]) positions[px]++;
}
// Draw the positions and take a nap
draw_positions_axis(axis, positions, invert);
delay_ms(del);
}
// Set all destinations to 7 (opposite from the side they started out)
for (i = 0; i < CUBE_BYTES; i++)
{
destinations[i] = CUBE_SIZE-1;
}
// Suspend the positions in mid-air for a while
delay_ms(sleep);
// Then do the same thing one more time
for (i = 0; i < CUBE_SIZE; i++)
{
for (px = 0; px < CUBE_BYTES; px++)
{
if (positions[px] < destinations[px]) positions[px]++;
if (positions[px] > destinations[px]) positions[px]--;
}
draw_positions_axis(axis, positions, invert);
delay_ms(del);
}
delay_ms(sleep);
}
void effect_boxside_randsend_parallel (char axis, int origin, int delay, int mode)
{
int i;
int done;
unsigned char cubepos[CUBE_BYTES];
unsigned char pos[CUBE_BYTES];
int notdone = 1;
int notdone2 = 1;
int sent = 0;
int lastPos;
for (i = 0; i < CUBE_BYTES; i++)
{
pos[i] = 0;
}
while (notdone)
{
if (mode == 1)
{
notdone2 = 1;
while (notdone2 && (sent < CUBE_BYTES))
{
i = rand() % CUBE_BYTES;
if (pos[i] == 0)
{
sent++;
pos[i] += 1;
notdone2 = 0;
lastPos = i;
}
}
} else if (mode == 2)
{
if (sent < CUBE_BYTES)
{
pos[sent] += 1;
lastPos = sent;
sent++;
}
}
if(sent == CUBE_BYTES) lastPos = 10000;
done = 0;
for (i = 0; i < CUBE_BYTES; i++)
{
if (pos[i] > 0 && pos[i] < (CUBE_SIZE-1))
{
if(i != lastPos) pos[i] += 1;
}
if (pos[i] == (CUBE_SIZE-1)) done++;
}
if (done == CUBE_BYTES) notdone = 0;
for (i = 0; i < CUBE_BYTES; i++)
{
if (origin == 0) cubepos[i] = pos[i];
else cubepos[i] = ((CUBE_SIZE-1)-pos[i]);
}
delay_ms(delay);
draw_positions_axis(axis, cubepos, 0);
}
}//effect_boxside_randsend_parallel
void effect_pathspiral (int iterations, int del)
{
int i;
for (i = 0; i < iterations; i++)
{
setvoxel(0, 0, i % CUBE_SIZE);
delay(del);
walkaround();
}
}//effect_pathspiral
void effect_rand_patharound (int iterations, int del)
{
int z, dz, i;
z = CUBE_SIZE/2;
for (i = 0; i < iterations; i++)
{
dz = ((random(3)) - 1);
z += dz;
if (z > CUBE_SIZE-1) z = CUBE_SIZE-1;
if (z < 0) z = 0;
walkaround();
setvoxel(0, 0, z);
delay(del);
}
}//effect_rand_patharound
// blink 1 random voxel, blink 2 random voxels..... blink 20 random voxels
// and back to 1 again.
void effect_random_sparkle(void)
{
int i;
for (i = 1; i < (CUBE_BYTES*3); i++)
{
effect_random_sparkle_flash(5, i, 40);
}
for (i = (CUBE_BYTES*3); i >= 1; i--)
{
effect_random_sparkle_flash(5, i, 40);
}
}
// Set n number of voxels at random positions
void effect_random_sparkle_flash(int iterations, int voxels, int del)
{
int i;
int v;
for (i = 0; i < iterations; i++)
{
for (v = 0; v <= voxels; v++) setvoxel(rand() % CUBE_SIZE, rand() % CUBE_SIZE, rand() % CUBE_SIZE);
delay(del);
clearCube();
}
}
void effect_folder()
{
int a, b, xx, yy, zz, pullback[CUBE_SIZE*2];
int folderaddr[CUBE_SIZE*2], LED_Old[CUBE_SIZE*2], oldpullback[CUBE_SIZE*2];
int bot = 0, top = 1, right = 0, left = 0, back = 0, front = 0, side = 0, side_select;
unsigned long start;
for(a = 0, b = -(CUBE_SIZE-1); a < CUBE_SIZE; a++, b++) folderaddr[a] = b;
for(xx = 0; xx < CUBE_SIZE; xx++)
{
oldpullback[xx] = 0;
pullback[xx] = 0;
}
start = millis();
while(millis() - (start < 10000))
{
if(top == 1)
{
if(side == 0)
{
//top to left-side
for(yy = 0; yy < CUBE_SIZE; yy++)
{
for(xx = 0; xx < CUBE_SIZE; xx++)
{
clrvoxel(xx, yy - oldpullback[yy], (CUBE_SIZE-1) - LED_Old[yy]);
setadjvoxel(xx, yy - pullback[yy], (CUBE_SIZE-1) - folderaddr[yy]);
}
}
}
if(side == 1)
{
//top-side to right
for(yy = 0; yy < CUBE_SIZE; yy++)
{
for(xx = 0; xx < CUBE_SIZE; xx++)
{
clrvoxel(xx, yy + oldpullback[yy], (CUBE_SIZE-1) - LED_Old[(CUBE_SIZE-1) - yy]);
setadjvoxel(xx, yy + pullback[yy], (CUBE_SIZE-1) - folderaddr[(CUBE_SIZE-1) - yy]);
}
}
}
if(side == 2)
{
//top to back-side
for(yy = 0; yy < CUBE_SIZE; yy++)
{
for(xx = 0; xx < CUBE_SIZE; xx++)
{
clrvoxel(yy - oldpullback[yy], xx, (CUBE_SIZE-1) - LED_Old[yy]);
setadjvoxel(yy - pullback[yy], xx, (CUBE_SIZE-1) - folderaddr[yy]);
}
}
}
if(side==3)
{
//top-side to front-side
for(yy = 0; yy < CUBE_SIZE; yy++)
{
for(xx = 0; xx < CUBE_SIZE; xx++)
{
clrvoxel(yy + oldpullback[yy], xx, (CUBE_SIZE-1) - LED_Old[(CUBE_SIZE-1) - yy]);
setadjvoxel(yy + pullback[yy], xx, (CUBE_SIZE-1) - folderaddr[(CUBE_SIZE-1) - yy]);
}
}
}
}//top
if(right == 1)
{
if(side == 2)
{
//right-side to back-side
for(yy = 0; yy < CUBE_SIZE; yy++)
{
for(xx = 0; xx < CUBE_SIZE; xx++)
{
clrvoxel(yy - oldpullback[yy], (CUBE_SIZE-1) - LED_Old[yy], xx);
setadjvoxel(yy - pullback[yy], (CUBE_SIZE-1) - folderaddr[yy], xx);
}
}
}
if(side == 3)
{
for(yy = 0; yy < CUBE_SIZE; yy++)
{
for(xx = 0; xx < CUBE_SIZE; xx++)
{
clrvoxel(yy + oldpullback[yy], (CUBE_SIZE-1) - LED_Old[(CUBE_SIZE-1) - yy], xx);
setadjvoxel(yy + pullback[yy], (CUBE_SIZE-1) - folderaddr[(CUBE_SIZE-1) - yy], zz);
}
}
}
if(side == 4)
{
//right-side to top
for(yy = 0; yy < CUBE_SIZE; yy++)
{
for(xx = 0; xx < CUBE_SIZE; xx++)
{
clrvoxel(xx, (CUBE_SIZE-1) - LED_Old[(CUBE_SIZE-1) - yy], yy + oldpullback[(CUBE_SIZE-1) - yy]);
setadjvoxel(xx, (CUBE_SIZE-1) - folderaddr[(CUBE_SIZE-1) - yy], yy + pullback[(CUBE_SIZE-1) - yy]);
}
}
}
if(side == 5)
{
//right-side to bottom
for(yy = 0; yy < CUBE_SIZE; yy++)
{
for(xx = 0; xx < CUBE_SIZE; xx++)
{
clrvoxel(xx, (CUBE_SIZE-1) - LED_Old[yy], yy - oldpullback[yy]);
setadjvoxel(xx, (CUBE_SIZE-1) - folderaddr[yy], yy - pullback[yy]);
}
}
}
}//right
if(left == 1)
{
if(side == 2)
{
//left-side to back-side
for(yy = 0; yy < CUBE_SIZE; yy++)
{
for(xx = 0; xx < CUBE_SIZE; xx++)
{
clrvoxel(yy - oldpullback[yy], LED_Old[yy], xx);
setadjvoxel(yy - pullback[yy], folderaddr[yy], xx);
}
}
}
if(side == 3)
{
//left-side to front-side
for(yy = 0; yy < CUBE_SIZE; yy++)
{
for(xx = 0; xx < CUBE_SIZE; xx++)
{
clrvoxel(yy + oldpullback[yy], LED_Old[(CUBE_SIZE-1) - yy], xx);
setadjvoxel(yy + pullback[yy], folderaddr[(CUBE_SIZE-1) - yy], xx);
}
}
}
if(side == 4)
{
//left-side to top
for(yy = 0; yy < CUBE_SIZE; yy++)
{
for(xx = 0; xx < CUBE_SIZE; xx++)
{
clrvoxel(xx, LED_Old[(CUBE_SIZE-1) - yy], yy+oldpullback[yy]);
setadjvoxel(xx, folderaddr[(CUBE_SIZE-1) - yy], yy+pullback[yy]);
}
}
}
if(side == 5)
{
//left-side to bottom
for(yy = 0; yy < CUBE_SIZE; yy++)
{
for(xx = 0; xx < CUBE_SIZE; xx++)
{
clrvoxel(xx, LED_Old[yy], yy - oldpullback[yy]);
setadjvoxel(xx, folderaddr[yy], yy - pullback[yy]);
}
}
}
}//left
if(back == 1)
{
if(side == 0)
{
//back-side to left-side
for(yy = 0; yy < CUBE_SIZE; yy++)
{
for(xx = 0; xx < CUBE_SIZE; xx++)
{
clrvoxel(LED_Old[yy], yy - oldpullback[yy], xx);
setadjvoxel(folderaddr[yy], yy - pullback[yy], xx);
}
}
}
if(side == 1)
{
//back-side to right-side
for(yy = 0; yy < CUBE_SIZE; yy++)
{
for(xx = 0; xx < CUBE_SIZE; xx++)
{
clrvoxel(LED_Old[(CUBE_SIZE-1) - yy], yy+oldpullback[yy], xx);
setadjvoxel(folderaddr[(CUBE_SIZE-1) - yy], yy+pullback[yy], xx);
}
}
}
if(side == 4)
{
// back-side to top-side
for(yy = 0; yy < CUBE_SIZE; yy++)
{
for(xx = 0; xx < CUBE_SIZE; xx++)
{
clrvoxel(LED_Old[(CUBE_SIZE-1) - yy], xx, yy+oldpullback[yy]);
setadjvoxel(folderaddr[(CUBE_SIZE-1) - yy], xx, yy+pullback[yy]);
}
}
}
if(side ==5)
{
// back-side to bottom
for(yy = 0; yy < CUBE_SIZE; yy++)
{
for(xx = 0; xx < CUBE_SIZE; xx++)
{
clrvoxel(LED_Old[yy], xx, yy - oldpullback[yy]);
setadjvoxel(folderaddr[yy], xx, yy - pullback[yy]);
}
}
}
}//back
if(bot == 1)
{
if(side == 0)
{
//bottom to left-side
for(yy = 0; yy < CUBE_SIZE; yy++)
{
for(xx = 0; xx < CUBE_SIZE; xx++)
{
clrvoxel(xx, yy - oldpullback[yy], LED_Old[yy]);
setadjvoxel(xx, yy - pullback[yy], folderaddr[yy]);
}
}
}
if(side == 1)
{
// bottom-side to right-side
for(yy = 0; yy < CUBE_SIZE; yy++)
{
for(xx = 0; xx < CUBE_SIZE; xx++)
{
clrvoxel(xx, yy + oldpullback[yy], LED_Old[(CUBE_SIZE-1) - yy]);
setadjvoxel(xx, yy + pullback[yy], folderaddr[(CUBE_SIZE-1) - yy]);
}
}
}
if(side == 2)
{
//bottom to back-side
for(yy = 0; yy < CUBE_SIZE; yy++)
{
for(xx = 0; xx < CUBE_SIZE; xx++)
{
clrvoxel(yy - oldpullback[yy], xx, LED_Old[yy]);
setadjvoxel(yy - pullback[yy], xx, folderaddr[yy]);
}
}
}
if(side == 3)
{
//bottom to front-side
for(yy = 0; yy < CUBE_SIZE; yy++)
{
for(xx = 0; xx < CUBE_SIZE; xx++)
{
clrvoxel(yy + oldpullback[yy], xx, LED_Old[(CUBE_SIZE-1) - yy]);
setadjvoxel(yy + pullback[yy], xx, folderaddr[(CUBE_SIZE-1) - yy]);
}
}
}
}//bot
if(front == 1)
{
if(side == 0)
{
//front-side to left-side
for(yy = 0; yy < CUBE_SIZE; yy++)
{
for(xx = 0; xx < CUBE_SIZE; xx++)
{
clrvoxel((CUBE_SIZE-1) - LED_Old[yy], yy - oldpullback[yy], xx);
setadjvoxel((CUBE_SIZE-1) - folderaddr[yy], yy - pullback[yy], xx);
}
}
}
if(side == 1)
{
//front-side to right-side
for(yy = 0; yy < CUBE_SIZE; yy++)
{
for(xx = 0; xx < CUBE_SIZE; xx++)
{
clrvoxel((CUBE_SIZE-1) - LED_Old[(CUBE_SIZE-1) - yy], yy + oldpullback[yy], xx);
setadjvoxel((CUBE_SIZE-1) - folderaddr[(CUBE_SIZE-1) - yy], yy + pullback[yy], xx);
}
}
}
if(side == 4)
{
// front-side to top-side
for(yy = 0; yy < CUBE_SIZE; yy++)
{
for(xx = 0; xx < CUBE_SIZE; xx++)
{
clrvoxel((CUBE_SIZE-1) - LED_Old[(CUBE_SIZE-1) - yy], xx, yy+oldpullback[yy]);
setadjvoxel((CUBE_SIZE-1) - folderaddr[(CUBE_SIZE-1) - yy], xx , yy+pullback[yy]);
}
}
}
if(side == 5)
{
// front-side to bottom
for(yy = 0; yy < CUBE_SIZE; yy++)
{
for(xx = 0; xx < CUBE_SIZE; xx++)
{
clrvoxel((CUBE_SIZE-1) - LED_Old[yy], xx, yy - oldpullback[yy]);
setadjvoxel((CUBE_SIZE-1) - folderaddr[yy], xx, yy - pullback[yy]);
}
}
}
}//front
// delay(5);// DELAY DELAY DELAY ORG
delay(50);// DELAY DELAY DELAY
for(xx = 0; xx < CUBE_SIZE; xx++)
{
LED_Old[xx] = folderaddr[xx];
oldpullback[xx] = pullback[xx];
}
if(folderaddr[(CUBE_SIZE-1)] == (CUBE_SIZE-1))
{
// pullback=8;
for(zz = 0; zz < CUBE_SIZE; zz++) pullback[zz] = pullback[zz]+1;
if(pullback[(CUBE_SIZE-1)] == CUBE_SIZE)
{
//finished with fold
// delay(10); // ORG
delay(100);
side_select = rand() % 3;
if(top == 1)
{// TOP
top = 0;
if(side == 0)
{//top to left
left = 1;
if(side_select == 0) side = 2;
if(side_select == 1) side = 3;
if(side_select == 2) side = 5;
} else
if(side == 1)
{//top to right
right = 1;
if(side_select == 0) side = 5;
if(side_select == 1) side = 2;
if(side_select == 2) side = 3;
} else
if(side == 2)
{//top to back
back = 1;
if(side_select == 0) side = 0;
if(side_select == 1) side = 1;
if(side_select == 2) side = 5;
} else
if(side == 3)
{//top to front
front = 1;
if(side_select == 0) side = 0;
if(side_select == 1) side = 1;
if(side_select == 2) side = 5;
}
} else//top
if(bot == 1)
{// BOTTOM
bot = 0;
if(side == 0)
{//bot to left
left = 1;
if(side_select == 0) side = 2;
if(side_select == 1) side = 3;
if(side_select == 2) side = 4;
} else
if(side == 1)
{//bot to right
right = 1;
if(side_select == 0) side = 2;
if(side_select == 1) side = 3;
if(side_select == 2) side = 4;
} else
if(side == 2)
{//bot to back
back = 1;
if(side_select == 0) side = 0;
if(side_select == 1) side = 1;
if(side_select == 2) side = 4;
} else
if(side == 3)
{//bot to front
front = 1;
if(side_select == 0) side = 0;
if(side_select == 1) side = 1;
if(side_select == 2) side = 4;
}
} else//bot
if(right == 1)
{// RIGHT
right = 0;
if(side == 4)
{//right to top
top = 1;
if(side_select == 0) side = 2;
if(side_select == 1) side = 3;
if(side_select == 2) side = 0;
} else
if(side == 5)
{//right to bot
bot = 1;
if(side_select == 0) side = 0;
if(side_select == 1) side = 2;
if(side_select == 2) side = 3;
} else
if(side == 2)
{//right to back
back = 1;
if(side_select == 0) side = 0;
if(side_select == 1) side = 5;
if(side_select == 2) side = 4;
} else
if(side == 3)
{//right to front
front = 1;
if(side_select == 0) side = 0;
if(side_select == 1) side = 5;
if(side_select == 2) side = 4;
}
} else//bot
if(left == 1)
{// LEFT
left = 0;
if(side == 4)
{//left to top
top = 1;
if(side_select == 0) side = 3;
if(side_select == 1) side = 2;
if(side_select == 2) side = 1;
} else
if(side == 5)
{//left to bot
bot = 1;
if(side_select == 0) side = 2;
if(side_select == 1) side = 3;
if(side_select == 2) side = 1;
} else
if(side == 2)
{//left to back
back = 1;
if(side_select == 0) side = 1;
if(side_select == 1) side = 5;
if(side_select == 2) side = 4;
} else
if(side == 3)
{//left to front
front = 1;
if(side_select == 0) side = 1;
if(side_select == 1) side = 5;
if(side_select == 2) side = 4;
}
} else//bot
if(front == 1)
{// front
front = 0;
if(side == 4)
{//front to top
top = 1;
if(side_select == 0) side = 2;
if(side_select == 1) side = 0;
if(side_select == 2) side = 1;
} else
if(side == 5)
{//front to bot
bot = 1;
if(side_select == 0) side = 0;
if(side_select == 1) side = 2;
if(side_select == 2) side = 1;
} else
if(side == 0)
{//front to left
left = 1;
if(side_select == 0) side = 2;
if(side_select == 1) side = 5;
if(side_select == 2) side = 4;
} else
if(side == 1)
{//front to right
right = 1;
if(side_select == 0) side = 2;
if(side_select == 1) side = 5;
if(side_select == 2) side = 4;
}
} else//bot
if(back == 1)
{// back
back = 0;
if(side == 4)
{//back to top
top = 1;
if(side_select == 0) side = 3;
if(side_select == 1) side = 0;
if(side_select == 2) side = 1;
} else
if(side == 5)
{//back to bot
bot = 1;
if(side_select == 0) side = 0;
if(side_select == 1) side = 3;
if(side_select == 2) side = 1;
} else
if(side == 0)
{//back to left
left = 1;
if(side_select == 0) side = 3;
if(side_select == 1) side = 5;
if(side_select == 2) side = 4;
} else
if(side == 1)
{//back to right
right = 1;
if(side_select == 0) side = 3;
if(side_select == 1) side = 5;
if(side_select == 2) side = 4;
}
} //bot
for(xx = 0; xx < CUBE_SIZE; xx++)
{
oldpullback[xx] = 0;
pullback[xx] = 0;
}
for(a = 0,b = -CUBE_SIZE; a < CUBE_SIZE; a++, b++) folderaddr[a] = b;
/* folderaddr[0]=-8;
folderaddr[1]=-7;
folderaddr[2]=-6;
folderaddr[3]=-5;
folderaddr[4]=-4;
folderaddr[5]=-3;
folderaddr[6]=-2;
folderaddr[7]=-1;
*/ }
}
if(folderaddr[(CUBE_SIZE-1)] != (CUBE_SIZE-1))
{
for(zz = 0; zz < CUBE_SIZE; zz++)
{
folderaddr[zz] = folderaddr[zz]+1;
}
}
}//while
}//folder
// effect_count_up (AZ).
void effect_count_up ()
{
int i, ii, iii;
int x;
int y;
int z;
for (y = 0; y < CUBE_SIZE; y++)
{
for (x = 0; x < CUBE_SIZE; x++)
{
for (z = 0; z < CUBE_SIZE; z++)
{
setvoxel(x, y, z);
delay_ms(100);
}
setvoxel(x, y, z);
delay_ms(100);
}
setvoxel(x, y, z);
delay_ms(100);
}
}//effect_count_up
void effect_moveopensquare(int iterations, int delshort, int dellong)
{
box_wireframe(0, 0, 0, (CUBE_SIZE-1), (CUBE_SIZE-1), 0);
delay(delshort);
for(int repeat = 0; repeat < iterations; repeat++)
{
// bottom->top
for(int z = 1; z < CUBE_SIZE; z++)
{
box_wireframe(0, 0, 0, (CUBE_SIZE-1), (CUBE_SIZE-1), z);
delay(delshort);
}
for(int i = 0; i < CUBE_SIZE-1; i++)
{
clrplane_z(i);
delay(delshort);
}
delay(dellong);
// top->back
for(int y = CUBE_SIZE-1; y > 0; y--)
{
shiftrow(0, DOWN);
shiftlevel(CUBE_SIZE-1, BACK);
delay(delshort);
}
delay(dellong);
// back -> front
for(int y = 1 ; y < CUBE_SIZE; y++)
{
box_wireframe(0, y, 0, (CUBE_SIZE-1), y, (CUBE_SIZE-1));
delay(delshort);
}
for(int i = 0; i <CUBE_SIZE-1; i++)
{
clrplane_y(i);
delay(delshort);
}
delay(dellong);
// front -> left
for(int y = CUBE_SIZE-1; y > 0; y--)
{
shiftcolumn(0, BACK);
shiftrow(CUBE_SIZE-1, LEFT);
delay(delshort);
}
delay(dellong);
// left -> right
for(int x = 1 ; x < CUBE_SIZE; x++)
{
box_wireframe(x, 0, 0, x,(CUBE_SIZE-1), (CUBE_SIZE-1));
delay(delshort);
}
for(int i = 0; i < CUBE_SIZE-1; i++)
{
clrplane_x(i);
delay(delshort);
}
delay(dellong);
// left -> front
for(int y = CUBE_SIZE-1; y > 0; y--)
{
shiftrow(CUBE_SIZE-1, LEFT);
shiftcolumn(CUBE_SIZE-1, FRONT);
delay(delshort);
}
delay(dellong);
// front -> back
for(int y = CUBE_SIZE-2 ; y >= 0; y--)
{
box_wireframe(0, y, 0, (CUBE_SIZE-1), y, (CUBE_SIZE-1));
delay(delshort);
}
for(int i = CUBE_SIZE-1; i > 0; i--)
{
clrplane_y(i);
delay(delshort);
}
delay(dellong);
for(int z = CUBE_SIZE-1; z > 0; z--)
{
shiftlevel(0, FRONT);
shiftrow(0, DOWN);
delay(delshort);
}
delay(dellong);
}
}
// Send all the voxels from one side of the cube to the other
// Start at z and send to the opposite side.
// Sends in random order.
void effect_sendplane_rand_z(unsigned char z, int del, int wait)
{
unsigned char loop = 16;
unsigned char x, y;
clearCube();
setplane_z(z);
// Send voxels at random until all 16 have crossed the cube.
while (loop) {
x = rand() % 4;
y = rand() % 4;
if (getvoxel(x, y, z)) {
// Send the voxel flying
sendvoxel_z(x, y, z, del);
delay(wait);
loop--; // one down, loop-- to go. when this hits 0, the loop exits.
}
}
}
void effect_running_up_down(int del)
{
for (int z = 0; z < CUBE_SIZE; z++) {
effect_running_light_z(z, del);
}
for (int z = 1; z < CUBE_SIZE; z++) {
effect_running_light_z(3 - z, del);
}
}
void effect_running_light_z(int z, int del)
{
for (int i = 0; i < CUBE_SIZE; i++) {
clearCube();
setvoxel(i, 0, z);
delay(del);
}
for (int i = 1; i < CUBE_SIZE; i++) {
clearCube();
setvoxel(CUBE_SIZE-1, i, z);
delay(del);
}
for (int i = 1; i < CUBE_SIZE; i++) {
clearCube();
setvoxel(CUBE_SIZE-1 - i, CUBE_SIZE-1, z);
delay(del);
}
for (int i = 1; i < CUBE_SIZE-1; i++) {
clearCube();
setvoxel(0, CUBE_SIZE-1 - i, z);
delay(del);
}
}
void effect_rotatewall(int iterations, int del)
{
for (int i = 0; i < iterations; i++) {
fillPlane(0, 1);
delay(del);
fillPlane(CUBE_SIZE-1, 2);
delay(del);
fillPlane(CUBE_SIZE-1, 1);
delay(del);
fillPlane(0, 2);
delay(del);
}
}
// Shows an animation of a spinning plane.
void effect_spinning_plane(int iterations, int del)
{
int i, z;
int SentByte;
for(i = 0; i < iterations; i++)
{
for(z = 0; z < CUBE_SIZE; z++)
for(SentByte = 0; SentByte < NUM_IC595; SentByte++)
Cube[(z * NUM_IC595) + SentByte] = linepath[(i) % (CUBE_SIZE + (CUBE_SIZE-2))][SentByte];
delay(del);
}
}
// Shows an animation of a spinning spiral
void effect_spiral(int iterations, int del)
{
int i,z;
int SentByte;
for (i = 0; i < iterations; i++)
{
for (z = 0; z < CUBE_SIZE; z++)
for(SentByte = 0; SentByte < NUM_IC595; SentByte++)
Cube[(z * NUM_IC595) + SentByte] = linepath[(i + z) % (CUBE_SIZE + (CUBE_SIZE-2))][SentByte];
delay(del);
}
}
//*** end effect functions *** end effect functions *** end effect functions *** end effect functions *** end effect functions ***
//*** start draw functions *** start draw functions *** start draw functions *** start draw functions *** start draw functions ***
// This function validates that we are drawing inside the cube.
unsigned char inrange(int x, int y, int z)
{
if (x >= 0 && x < CUBE_SIZE && y >= 0 && y < CUBE_SIZE && z >= 0 && z < CUBE_SIZE)
{
return 1;
} else
{
// One of the coordinates was outside the cube.
return 0;
}
}
// setvoxel(coord x, coord y, coord
void setvoxel(int x, int y, int z)
{
if(inrange(x, y, z))
{
int whichbyte = ((z * CUBE_BYTES) + (y * CUBE_SIZE) + x) / 8;
int wholebyte = (z * CUBE_BYTES) + (y * CUBE_SIZE) + x;
bitWrite(Cube[whichbyte], wholebyte - (8 * whichbyte), 1);
}
}
void settmpvoxel(int x, int y, int z)
{
if(inrange(x, y, z))
{
int whichbyte = ((z * CUBE_BYTES) + (y * CUBE_SIZE) + x) / 8;
int wholebyte = (z * CUBE_BYTES) + (y * CUBE_SIZE) + x;
bitWrite(TempCube[whichbyte], wholebyte - (8 * whichbyte), 1);
}
}
void clrvoxel(int x, int y, int z)
{
if(inrange(x, y, z))
{
int whichbyte = ((z * CUBE_BYTES) + (y * CUBE_SIZE) + x) / 8;
int wholebyte = (z * CUBE_BYTES) + (y * CUBE_SIZE) + x;
bitWrite(Cube[whichbyte], wholebyte - (8 * whichbyte), 0);
}
}
void clrtmpvoxel(int x, int y, int z)
{
if(inrange(x, y, z))
{
int whichbyte = ((z * CUBE_BYTES) + (y * CUBE_SIZE) + x) / 8;
int wholebyte = (z * CUBE_BYTES) + (y * CUBE_SIZE) + x;
bitWrite(TempCube[whichbyte], wholebyte - (8 * whichbyte), 0);
}
}
unsigned char getvoxel(int x, int y, int z)
{
if (inrange(x, y, z))
{
int whichbyte = ((z * CUBE_BYTES) + (y * CUBE_SIZE) + x) / 8;
int wholebyte = (z * CUBE_BYTES) + (y * CUBE_SIZE) + x;
if (bitRead(Cube[whichbyte], wholebyte - (8 * whichbyte)))
{
return 1;
} else
{
return 0;
}
} else
{
return 0;
}
}
// Flip the state of a voxel.
// If the voxel is 1, its turned into a 0, and vice versa.
void flpvoxel(int x, int y, int z)
{
if (inrange(x, y, z))
{
int whichbyte = ((z * CUBE_BYTES) + (y * CUBE_SIZE) + x) / 8;
int wholebyte = (z * CUBE_BYTES) + (y * CUBE_SIZE) + x;
if (bitRead(Cube[whichbyte], wholebyte - (8 * whichbyte)))
{
bitWrite(Cube[whichbyte], wholebyte - (8 * whichbyte), 0);
} else
{
bitWrite(Cube[whichbyte], wholebyte - (8 * whichbyte), 1);
}
}
}
// In some effect we want to just take bool and write it to a voxel
// this function calls the apropriate voxel manipulation function.
void altervoxel(int x, int y, int z, int state)
{
if (state == 1)
{
setvoxel(x, y, z);
} else
{
clrvoxel(x, y, z);
}
}
void setadjvoxel(int x, int y, int z)
{
if(x < 0) x = 0;
if(x >= CUBE_SIZE) x = CUBE_SIZE-1;
if(y < 0) y = 0;
if(y >= CUBE_SIZE) y = CUBE_SIZE-1;
if(z < 0) z = 0;
if(z >= CUBE_SIZE) z = CUBE_SIZE-1;
setvoxel(x, y, z);
}
// Send a voxel flying from one side of the cube to the other
// If its at the bottom, send it to the top..
void sendvoxel_z(unsigned char x, unsigned char y, unsigned char z, int del)
{
int i, ii;
for (i = 1; i < CUBE_SIZE; i++)
{
if (z == CUBE_SIZE-1)
{
ii = (CUBE_SIZE-1) - i;
clrvoxel(x, y, ii + 1);
} else
{
ii = i;
clrvoxel(x, y, ii - 1);
}
setvoxel(x, y, ii);
delay(del);
}
}
// Fill a value into all 64 byts of the cube buffer
// Mostly used for clearing. fill(0x00)
// or setting all on. fill(0xff)
void clearCube()
{
int x, y, z;
for (x = 0; x < CUBE_SIZE; x++)
for (y = 0; y < CUBE_SIZE; y++)
for (z = 0 ; z < CUBE_SIZE; z++)
clrvoxel(x, y, z);
}
void clearTempCube()
{
int x, y, z;
for (x = 0; x < CUBE_SIZE; x++)
for (y = 0; y < CUBE_SIZE; y++)
for (z = 0 ; z < CUBE_SIZE; z++)
clrtmpvoxel(x, y, z);
}
void fillCube(void)
{
for (int x = 0; x < CUBE_SIZE; x++)
for (int y = 0; y < CUBE_SIZE; y++)
for (int z = 0; z < CUBE_SIZE; z++)
setvoxel(x, y, z);
}
// Shift the entire contents of the cube along an axis
// This is great for effects where you want to draw something
// on one side of the cube and have it flow towards the other
// side. Like rain flowing down the Z axiz.
void shift (char axis, int direction)
{
int i, x, y;
int ii, iii;
int state;
for (i = 0; i < CUBE_SIZE; i++)
{
if (direction == -1)
{
ii = i;
} else
{
ii = ((CUBE_SIZE-1) - i);
}
for (x = 0; x < CUBE_SIZE; x++)
{
for (y = 0; y < CUBE_SIZE; y++)
{
if (direction == -1)
{
iii = ii + 1;
} else
{
iii = ii - 1;
}
if (axis == AXIS_Z)
{
state = getvoxel(x, y, iii);
altervoxel(x, y, ii, state);
}
if (axis == AXIS_Y)
{
state = getvoxel(x, iii, y);
altervoxel(x, ii, y, state);
}
if (axis == AXIS_X)
{
state = getvoxel(iii, y, x);
altervoxel(ii, y, x, state);
}
}
}
}
if (direction == -1)
{
i = (CUBE_SIZE-1);
} else
{
i = 0;
}
for (x = 0; x < CUBE_SIZE; x++)
{
for (y = 0; y < CUBE_SIZE; y++)
{
if (axis == AXIS_Z) clrvoxel(x, y, i);
if (axis == AXIS_Y) clrvoxel(x, i, y);
if (axis == AXIS_X) clrvoxel(i, y, x);
}
}
}
void shiftrow(int y, char moveto)
{
int x, z;
int state;
if(moveto == UP)
{
for(z = CUBE_SIZE-1; z >= 0; z--)
{
for(x = 0; x <CUBE_SIZE; x++)
{
state = getvoxel(x, y, z);
altervoxel(x, y, z + 1, state);
clrvoxel(x, y, z);
}
}
}
if(moveto == DOWN)
{
for(z = 0; z < CUBE_SIZE; z++)
{
for(x = 0; x < CUBE_SIZE; x++)
{
state = getvoxel(x, y, z);
altervoxel(x, y, z - 1, state);
clrvoxel(x, y, z);
}
}
}
if(moveto == BACK)
{
for(z = 0; z < CUBE_SIZE; z++)
{
for(x = 0; x < CUBE_SIZE; x++)
{
state = getvoxel(x, y, z);
altervoxel(x, y - 1, z, state);
clrvoxel(x, y, z);
}
}
}
if(moveto == FRONT)
{
for(z = 0; z < CUBE_SIZE; z++)
{
for(x = 0; x < CUBE_SIZE; x++)
{
state = getvoxel(x, y, z);
altervoxel(x, y + 1, z, state);
clrvoxel(x, y, z);
}
}
}
if(moveto == LEFT)
{
for(z = 0; z < CUBE_SIZE; z++)
{
for(x = 0; x < CUBE_SIZE; x++)
{
state = getvoxel(x, y, z);
altervoxel(x - 1, y, z, state);
clrvoxel(x, y, z);
}
}
}
if(moveto == RIGHT)
{
for(z = 0; z < CUBE_SIZE; z++)
{
for(x = CUBE_SIZE-1; x >= 0; x--)
{
state = getvoxel(x, y, z);
altervoxel(x + 1, y, z, state);
clrvoxel(x, y, z);
}
}
}
}
void shiftcolumn(int x, char moveto)
{
int y, z;
int state;
if(moveto == UP)
{
for(z = CUBE_SIZE-1; z >= 0; z--)
{
for(y = 0; y < CUBE_SIZE; y++)
{
state = getvoxel(x, y, z);
altervoxel(x, y, z + 1, state);
clrvoxel(x, y, z);
}
}
}
if(moveto == DOWN)
{
for(z = 0; z < CUBE_SIZE; z++)
{
for(y = 0; y < CUBE_SIZE; y++)
{
state = getvoxel(x, y, z);
altervoxel(x, y, z - 1, state);
clrvoxel(x, y, z);
}
}
}
if(moveto == BACK)
{
for(z = 0; z < CUBE_SIZE; z++)
{
for(y = 0; y < CUBE_SIZE; y++)
{
state = getvoxel(x, y, z);
altervoxel(x, y - 1, z, state);
clrvoxel(x, y, z);
}
}
}
if(moveto == FRONT)
{
for(y = CUBE_SIZE-1; y >= 0; y--)
{
for(z = 0; z < CUBE_SIZE; z++)
{
state = getvoxel(x, y, z);
altervoxel(x, y + 1, z, state);
clrvoxel(x, y, z);
}
}
}
if(moveto == LEFT)
{
for(z = 0; z < CUBE_SIZE; z++)
{
for(y = 0; y < CUBE_SIZE; y++)
{
state = getvoxel(x, y, z);
altervoxel(x - 1, y, z, state);
clrvoxel(x, y, z);
}
}
}
if(moveto == RIGHT)
{
for(z = 0; z < CUBE_SIZE; z++)
{
for(y = CUBE_SIZE-1; y >= 0; y--)
{
state = getvoxel(x, y, z);
altervoxel(x + 1, y, z, state);
clrvoxel(x, y, z);
}
}
}
}
void shiftlevel(int z, char moveto)
{
int x, y;
int state;
if(moveto == UP)
{
for(y = 0; y < CUBE_SIZE; y++)
{
for(x = 0; x < CUBE_SIZE; x++)
{
state = getvoxel(x, y, z);
altervoxel(x, y, z + 1, state);
clrvoxel(x, y, z);
}
}
}
if(moveto == DOWN)
{
for(y = 0; y < CUBE_SIZE; y++)
{
for(x = 0; x < CUBE_SIZE; x++)
{
state = getvoxel(x, y, z);
altervoxel(x, y, z - 1, state);
clrvoxel(x, y, z);
}
}
}
if(moveto == BACK)
{
for(y = 0; y < CUBE_SIZE; y++)
{
for(x = 0; x < CUBE_SIZE; x++)
{
state = getvoxel(x, y, z);
altervoxel(x, y - 1, z, state);
clrvoxel(x, y, z);
}
}
}
if(moveto == FRONT)
{
for(y = CUBE_SIZE-1; y >= 0; y--)
{
for(x = 0; x < CUBE_SIZE; x++)
{
state = getvoxel(x, y, z);
altervoxel(x, y + 1, z, state);
clrvoxel(x, y, z);
}
}
}
if(moveto == LEFT)
{
for(x = 0; x < CUBE_SIZE; x++)
{
for(y = 0; y < CUBE_SIZE; y++)
{
state = getvoxel(x, y, z);
altervoxel(x - 1, y, z, state);
clrvoxel(x, y, z);
}
}
}
if(moveto == RIGHT)
{
for(x = CUBE_SIZE-1; x >= 0; x--)
{
for(y = 0; y < CUBE_SIZE; y++)
{
state = getvoxel(x, y, z);
altervoxel(x + 1, y, z, state);
clrvoxel(x, y, z);
}
}
}
}
void setplane (char axis, unsigned char i)
{
switch (axis)
{
case AXIS_X:
setplane_x(i);
break;
case AXIS_Y:
setplane_y(i);
break;
case AXIS_Z:
setplane_z(i);
break;
}
}
void clrplane (char axis, unsigned char i)
{
switch (axis)
{
case AXIS_X:
clrplane_x(i);
break;
case AXIS_Y:
clrplane_y(i);
break;
case AXIS_Z:
clrplane_z(i);
break;
}
}
void setplane_x (int x)
{
int z;
int y;
if (x >= 0 && x < CUBE_SIZE)
{
for (z = 0; z < CUBE_SIZE; z++)
{
for (y = 0; y < CUBE_SIZE; y++)
{
setvoxel(x, y, z);
}
}
}
}
void clrplane_x (int x)
{
int y, z;
if (x >= 0 && x < CUBE_SIZE)
{
for (z = 0; z < CUBE_SIZE; z++)
{
for (y = 0; y < CUBE_SIZE; y++)
{
clrvoxel(x, y, z);
}
}
}
}
void setplane_y (int y)
{
int x, z;
if (y >= 0 && y < CUBE_SIZE)
{
for (z = 0; z < CUBE_SIZE; z++)
{
for(x = 0; x < CUBE_SIZE; x++)
{
setvoxel(x, y, z);
}
}
}
}
void clrplane_y (int y)
{
int x, z;
if (y >= 0 && y < CUBE_SIZE)
{
for (z = 0; z < CUBE_SIZE; z++)
{
for(x = 0; x < CUBE_SIZE; x++)
{
clrvoxel(x, y, z);
}
}
}
}
// Sets all voxels along a X/Y plane at a given point
// on axis Z
void setplane_z (int z)
{
int x, y;
if (z >= 0 && z < CUBE_SIZE)
{
for(x = 0; x < CUBE_SIZE; x++)
{
for(y = 0; y < CUBE_SIZE; y++)
{
setvoxel(x, y, z);
}
}
}
}
void clrplane_z (int z)
{
int x, y;
if (z >= 0 && z < CUBE_SIZE)
{
for(x = 0; x < CUBE_SIZE; x++)
{
for(y = 0; y < CUBE_SIZE; y++)
{
clrvoxel(x, y, z);
}
}
}
}
void fillPlane(byte plane, byte mode)
{
clearCube();
switch (mode)
{ // x, y, z
case 0:
for (int x = 0; x < CUBE_SIZE; x++)
{
for (int y = 0; y < CUBE_SIZE; y++)
{
setvoxel(x, y, plane);
}
}
break;
case 1:
for (int y = 0; y < CUBE_SIZE; y++)
{
for (int z = 0; z < CUBE_SIZE; z++)
{
setvoxel(plane, y, z);
}
}
break;
case 2:
for (int x = 0; x < CUBE_SIZE; x++)
{
for (int z = 0; z < CUBE_SIZE; z++)
{
setvoxel(x, plane, z);
}
}
break;
default:
break;
}
}
// Draw a wireframe box. This only draws the corners and edges,
// no walls.
void box_wireframe(int x1, int y1, int z1, int x2, int y2, int z2)
{
int ix, iy, iz;
argorder(x1, x2, &x1, &x2);
argorder(y1, y2, &y1, &y2);
argorder(z1, z2, &z1, &z2);
for (ix = x1; ix < x2; ix++)
{
setvoxel(ix, y1, z1);
setvoxel(ix, y2, z1);
setvoxel(ix, y1, z2);
setvoxel(ix, y2, z2);
}
// Lines along Y axis
for (iy = y1; iy <= y2; iy++)
{
setvoxel(x1, iy, z1);
setvoxel(x1, iy, z2);
setvoxel(x2, iy, z1);
setvoxel(x2, iy, z2);
}
// Lines along Z axis
for (iz = z1; iz <= z2; iz++)
{
setvoxel(x1, y1, iz);
setvoxel(x1, y2, iz);
setvoxel(x2, y1, iz);
setvoxel(x2, y2, iz);
}
}
// Makes sure x1 is alwas smaller than x2
// This is usefull for functions that uses for loops,
// to avoid infinite loops
void argorder(int ix1, int ix2, int *ox1, int *ox2)
{
if (ix1 > ix2)
{
int tmp;
tmp = ix1;
ix1= ix2;
ix2 = tmp;
}
*ox1 = ix1;
*ox2 = ix2;
}
// Flip the cube 180 degrees along the y axis.
void mirror_y ()
{
unsigned char buffer[CUBE_BYTES];
unsigned char x, y, z;
memcpy(buffer, Cube, CUBE_BYTES); // copy the current cube into a buffer.
clearCube();
for (z = 0; z < CUBE_SIZE; z++)
{
for (y = 0; y < CUBE_SIZE; y++)
{
for (x = 0; x < CUBE_SIZE; x++)
{
int whichbyte = ((z * CUBE_BYTES) + (y * CUBE_SIZE) + x) / 8;
int wholebyte = (z * CUBE_BYTES) + (y * CUBE_SIZE) + x;
if (bitRead(buffer[whichbyte], wholebyte - (8 * whichbyte))) setvoxel(x, (CUBE_SIZE-1) - y, z);
}
}
}
}
// Flip the cube 180 degrees along the x axis
void mirror_x ()
{
unsigned char buffer[CUBE_BYTES];
unsigned char x, y, z;
memcpy(buffer, Cube, CUBE_BYTES); // copy the current cube into a buffer.
clearCube();
for (z = 0; z < CUBE_SIZE; z++)
{
for (y = 0; y < CUBE_SIZE; y++)
{
for (x = 0; x < CUBE_SIZE; x++)
{
int whichbyte = ((z * CUBE_BYTES) + (y * CUBE_SIZE) + x) / 8;
int wholebyte = (z * CUBE_BYTES) + (y * CUBE_SIZE) + x;
if (bitRead(buffer[whichbyte], wholebyte - (8 * whichbyte))) setvoxel((CUBE_SIZE-1) - x, y, z);
}
}
}
}
// flip the cube 180 degrees along the z axis
void mirror_z ()
{
unsigned char buffer[CUBE_BYTES];
unsigned char x, y, z;
memcpy(buffer, Cube, CUBE_BYTES); // copy the current cube into a buffer.
clearCube();
for (z = 0; z < CUBE_SIZE; z++)
{
for (y = 0; y < CUBE_SIZE; y++)
{
for (x = 0; x < CUBE_SIZE; x++)
{
int whichbyte = ((z * CUBE_BYTES) + (y * CUBE_SIZE) + x) / 8;
int wholebyte = (z * CUBE_BYTES) + (y * CUBE_SIZE) + x;
if (bitRead(buffer[whichbyte], wholebyte - (8 * whichbyte))) setvoxel(x, y, (CUBE_SIZE-1) - z);
}
}
}
}
void draw_positions_axis(char axis, unsigned char positions[CUBE_BYTES], int invert)
{
int x, y, p;
clearCube();
for (x = 0; x < CUBE_SIZE; x++)
{
for (y = 0; y < CUBE_SIZE; y++)
{
if (invert) p = ((CUBE_SIZE-1) - positions[(x * CUBE_SIZE) + y]);
else p = positions[(x * CUBE_SIZE) + y];
if (axis == AXIS_Z) setvoxel(x, y, p);
if (axis == AXIS_Y) setvoxel(x, p, y);
if (axis == AXIS_X) setvoxel(p, y, x);
}
}
}
// Draw a line between any coordinates in 3d space.
// Uses integer values for input, so dont expect smooth animations.
void line(int x0, int y0, int x1, int y1, int z,int buffer)
{
int16_t steep = abs(y1 - y0) > abs(x1 - x0);
if (steep) {
int tmp;
tmp = x0; x0 = y0; y0 = tmp;
tmp = x1; x1 = y1, y1 = tmp;
}
if (x0 > x1) {
int tmp;
tmp = x0; x0 = x1, x1 = tmp;
tmp = y0; y0 = y1; y1 = tmp;
}
int16_t dx, dy;
dx = x1 - x0;
dy = abs(y1 - y0);
int16_t err = dx / 2;
int16_t ystep;
if (y0 < y1) ystep = 1;
else ystep = -1;
for (; x0 <= x1; x0++) {
if (steep)
{
if (!buffer) setvoxel(y0, x0, z);
else settmpvoxel(y0,x0,z);
}
else
{
if (!buffer) setvoxel(x0, y0, z);
else settmpvoxel(x0,y0,z);
}
err -= dy;
if (err < 0)
{
y0 += ystep;
err += dx;
}
}
}
void walkaround()
{
int x, y, z;
for(int side = 3; side >= 0; side--)
{
for(z = 0; z < CUBE_SIZE; z++)
{
if(side == 3) for(y = 1; y < CUBE_SIZE-1; y++) walkupdate(0, y, z, 0, 1);
if(side == 2) for(x = 0; x < CUBE_SIZE-1; x++) walkupdate(x, CUBE_SIZE-1, z, 1, 0);
if(side == 1) for(y = CUBE_SIZE-1; y > 0; y--) walkupdate(CUBE_SIZE-1, y, z, 0, -1);
if(side == 0) for(x = CUBE_SIZE-1; x > 0; x--) walkupdate(x, 0, z, -1, 0);
}
}
for(z = 0; z < CUBE_SIZE; z++) clrvoxel(0, 0, z);
}
void walkupdate(int x, int y, int z,int xdir, int ydir)
{
int state = getvoxel(x + xdir, y + ydir, z);
altervoxel(x, y, z, state);
}
//*** end draw functions *** end draw functions *** end draw functions *** end draw functions *** end draw functions ***
//*** start helper functions *** start helper functions *** start helper functions *** start helper functions *** start helper functions
// Delay loop.
void delay_ms(uint16_t x)
{
uint8_t y, z;
for(; x > 0; x--)
{
for(y = 0; y < 90; y++)
{
for(z = 0; z < 6; z++)
{
asm volatile ("nop");
}
}
}
}
// Print a BYTE to the serial Console
void printBin(byte aByte)
{
for (int8_t aBit = 7; aBit >= 0; aBit--) Serial.write(bitRead(aByte, aBit) ? '1' : '0');
}
// display Cube[] content to the serial Console
void displayCube(int tmp)
{
for(int a = 0; a < CUBE_SIZE * NUM_IC595; a++)
{
if(!tmp) printBin(Cube[a]);
else printBin(TempCube[a]);
if(a < (CUBE_SIZE * NUM_IC595) - 1) Serial.print(",");
}
Serial.println();
}
void buildlinepath()
{
int x, y;
int a = 0;
for(y = 0; y < CUBE_SIZE; y++)
{
line(0, y, CUBE_SIZE-1, (CUBE_SIZE-1) - y, 0, 1);
for(int b = 0; b < NUM_IC595; b++) linepath[a][b] = TempCube[b];
a++;
clearTempCube();
}
for(x = 1; x < CUBE_SIZE-1; x++)
{
line(x, CUBE_SIZE-1, (CUBE_SIZE-1) - x, 0, 0, 1);
for(int b = 0; b < NUM_IC595; b++) linepath[a][b] = TempCube[b];
a++;
clearTempCube();
}
}
//*** end helper functions *** end helper functions *** end helper functions *** end helper functions *** end helper functions