aboutsummaryrefslogtreecommitdiffstats
path: root/cube_gl/effect.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cube_gl/effect.cpp')
-rw-r--r--cube_gl/effect.cpp776
1 files changed, 776 insertions, 0 deletions
diff --git a/cube_gl/effect.cpp b/cube_gl/effect.cpp
new file mode 100644
index 0000000..4288fa0
--- /dev/null
+++ b/cube_gl/effect.cpp
@@ -0,0 +1,776 @@
+
+#include "effect.h"
+#include "font.h"
+#include <SDL.h>
+#include <cassert>
+#include <cmath>
+
+#define CUBE_SIZE 8
+#define CUBE_BYTES CUBE_SIZE*CUBE_SIZE
+#define AXIS_Z 2
+#define AXIS_Y 1
+#define AXIS_X 0
+
+unsigned char leds[8][8];
+volatile bool led_change = false;
+
+//unsigned char pow2[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
+//const unsigned char pow2[8] = {128, 64, 32, 16, 8, 4, 2, 1};
+
+/*****************************************************************************
+ * ACCESSORS
+ *****************************************************************************/
+
+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;
+ }
+}
+
+bool get_led(unsigned char x, unsigned char y, unsigned char z)
+{
+ /*
+ assert(x >= 0 && x <= 7);
+ assert(y >= 0 && y <= 7);
+ assert(z >= 0 && z <= 7);
+ */
+
+ if (inrange(x, y, z)) {
+ return leds[y][z] & (1 << x);
+ }
+
+ return false;
+}
+
+void set_led(unsigned char x, unsigned char y, unsigned char z, bool on)
+{
+
+ if (!inrange(x, y, z)) {
+ return;
+ }
+
+ /*
+ assert(x >= 0 && x <= 7);
+ assert(y >= 0 && y <= 7);
+ assert(z >= 0 && z <= 7);
+ */
+
+ if (on) {
+ leds[y][z] |= ((unsigned char)1) << x;
+ }
+ else {
+ leds[y][z] &= ~(((unsigned char)1) << x);
+ }
+}
+
+void clear_led()
+{
+ memset(leds, 0, sizeof(leds));
+}
+
+void set_voxel(int x, int y, int z)
+{
+ set_led(x, y, z, true);
+}
+
+void clr_voxel(int x, int y, int z)
+{
+ set_led(x, y, z, false);
+}
+
+void fill(char val)
+{
+ memset(leds, val, sizeof(leds));
+}
+
+void delay(unsigned t)
+{
+ led_change = true;
+ SDL_Delay(t);
+}
+
+/*****************************************************************************
+ * EFFECTS
+ *****************************************************************************/
+
+void test_effect()
+{
+ static int active_layer = 0;
+
+ for (int k = 0; k < 8; ++k) {
+ //std::cout << "boo" << std::endl;
+ for (int j = 0; j < 8; ++j) {
+ //std::cout << "boo2" << std::endl;
+ if (k == active_layer) {
+ //std::cerr << "active" << std::endl;
+ leds[j][k] = 0xFF;
+ }
+ else leds[j][k] = 0;
+ }
+ }
+ ++active_layer;
+ if (active_layer >= 8) {
+ active_layer = 0;
+ }
+}
+
+
+void sendvoxels_z(int x, int y, int z, int delay)
+{
+ assert(z == 0 || z == 7);
+
+ if (z == 7) {
+ for (int i = 0; i < 7; ++i) {
+ set_led(x, y, i, false);
+ set_led(x, y, i+1, true);
+ led_change = true;
+ SDL_Delay(delay);
+ }
+ }
+ else {
+ for(int i = 6; i >= 0; --i) {
+ set_led(x, y, i + 1, false);
+ set_led(x, y, i, true);
+ led_change = true;
+ SDL_Delay(delay);
+ }
+ }
+}
+
+
+void sendvoxels_random_z_effect(int maxiters,
+ int delay, /* speed of movement */
+ int wait) /* delay between 2 movement */
+{
+ clear_led(); // clear the cube
+ for (int j = 0; j < 8; ++j) {
+ for (int i = 0; i < 8; ++i) {
+ if (rand()%2) {
+ set_led(i, j, 0, true);
+ }
+ else {
+ set_led(i, j, 7, true);
+ }
+ }
+ }
+
+ int previous_x = 0, previous_y = 0;
+ for (int n = 0; n < maxiters ; ++n ) {
+ int x = rand()%8, y = rand()%8;
+
+ if (previous_x == x && previous_y == y) {
+ --n;
+ continue;
+ }
+
+ if (get_led(x, y, 0)) {
+ sendvoxels_z(x, y, 7, delay);
+ }
+ else if (get_led(x, y, 7)) {
+ sendvoxels_z(x, y, 0, delay);
+ }
+ SDL_Delay(wait);
+ }
+
+}
+
+void rain_effect(int iterations)
+{
+
+ for (int i = 0; i < iterations ; ++i) {
+
+ // clear layer 7
+ for (int j = 0 ; j < 8; ++j) {
+ leds[j][7] = 0;
+ }
+
+ // place pixels at random x and y coord at layer 7
+ int n = rand()%4;
+ for (int i2 = 0; i2 < n; ++i2) {
+ set_led(rand()%8, rand()%8, 7, 1);
+ }
+
+ led_change = true;
+ SDL_Delay(90);
+
+ // shift down
+ for (int k = 0; k < 7; ++k) {
+ for (int j = 0 ; j < 8; ++j) {
+ leds[j][k] = leds[j][k+1];
+ }
+ }
+ }
+}
+
+void set_plane(int axis, unsigned char index, bool on = true)
+{
+ switch(axis) {
+ case 0: // X
+ for (int k = 0; k < 8; ++k) {
+ for (int j = 0; j < 8; ++j) {
+ set_led(index, j, k, on);
+ }
+ }
+ break;
+ case 1: // Y
+ for (int k = 0; k < 8; ++k) {
+ for (int i = 0; i < 8; ++i) {
+ set_led(i, index, k, on);
+ }
+ }
+ break;
+ case 2: // Z
+ for (int j = 0; j < 8; ++j) {
+ for (int i = 0; i < 8; ++i) {
+ set_led(i, j, index, on);
+ }
+ }
+ break;
+ default:
+ assert(false);
+ }
+}
+
+void planboing(int plane, int speed)
+{
+ for (int i = 0; i < 8; ++i) {
+ clear_led(); // clear cube
+ set_plane(plane, i);
+ led_change = true;
+ SDL_Delay(speed);
+ }
+ for (int i = 7; i >= 0; --i) {
+ clear_led(); // clear cube
+ set_plane(plane, i);
+ led_change = true;
+ SDL_Delay(speed);
+ }
+}
+
+// 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 = (7-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 == 2)
+ {
+ set_led(x, y, ii, get_led(x, y, iii));
+ //state = get_led(x,y,iii);
+ //set_led(x,y,ii,state?false:true);
+ }
+
+ if (axis == 1)
+ {
+ set_led(x, ii, y, get_led(x, iii, y));
+ //state = get_led(x,iii,y);
+ //altervoxel(x,ii,y,state);
+ //set_led(x,ii,y,state?false:true);
+ }
+
+ if (axis == 0)
+ {
+ set_led(ii, y, x, get_led(iii, y, x));
+ //state = get_led(iii,y,x);
+ //set_led(ii,y,x,state?false:true);
+ }
+ }
+ }
+ }
+
+ if (direction == -1) {
+ i = 7;
+ }
+ else {
+ i = 0;
+ }
+
+ /*
+ for (x = 0; x < CUBE_SIZE; x++) {
+ for (y = 0; y < CUBE_SIZE; y++) {
+ if (axis == AXIS_Z) set_led(x,y,i, false);
+ if (axis == AXIS_Y) set_led(x,i,y, false);
+ if (axis == AXIS_X) set_led(i,y,x, false);
+ }
+ }
+
+ */
+ set_plane(axis, i, false);
+}
+
+
+// Flips a byte 180 degrees.
+// MSB becomes LSB, LSB becomes MSB.
+char flipbyte (char byte)
+{
+ char flop = 0x00;
+
+ flop = (flop & 0b11111110) | (0b00000001 & (byte >> 7));
+ flop = (flop & 0b11111101) | (0b00000010 & (byte >> 5));
+ flop = (flop & 0b11111011) | (0b00000100 & (byte >> 3));
+ flop = (flop & 0b11110111) | (0b00001000 & (byte >> 1));
+ flop = (flop & 0b11101111) | (0b00010000 & (byte << 1));
+ flop = (flop & 0b11011111) | (0b00100000 & (byte << 3));
+ flop = (flop & 0b10111111) | (0b01000000 & (byte << 5));
+ flop = (flop & 0b01111111) | (0b10000000 & (byte << 7));
+ return flop;
+}
+
+// Flip the cube 180 degrees along the y axis.
+void mirror_y (void)
+{
+ unsigned char buffer[CUBE_SIZE][CUBE_SIZE];
+ unsigned char x,y,z;
+
+ memcpy(buffer, leds, CUBE_BYTES); // copy the current cube into a buffer.
+
+ //fill(0x00);
+ clear_led();
+ for (z=0; z<CUBE_SIZE; z++)
+ {
+ for (y=0; y<CUBE_SIZE; y++)
+ {
+ for (x=0; x<CUBE_SIZE; x++)
+ {
+ if (buffer[y][z] & (0x01 << x))
+ set_led(x,CUBE_SIZE-1-y,z,true);
+ }
+ }
+ }
+
+}
+
+// Flip the cube 180 degrees along the x axis
+void mirror_x (void)
+{
+ unsigned char buffer[CUBE_SIZE][CUBE_SIZE];
+ unsigned char y,z;
+
+ memcpy(buffer, leds, CUBE_BYTES); // copy the current cube into a buffer.
+
+ //fill(0x00);
+ clear_led();
+
+ for (z=0; z<CUBE_SIZE; z++)
+ {
+ for (y=0; y<CUBE_SIZE; y++)
+ {
+ // This will break with different buffer sizes..
+ leds[y][z] = flipbyte(buffer[y][z]);
+ }
+ }
+}
+
+// flip the cube 180 degrees along the z axis
+void mirror_z (void)
+{
+ unsigned char buffer[CUBE_SIZE][CUBE_SIZE];
+ unsigned char z, y;
+
+ memcpy(buffer, leds, CUBE_BYTES); // copy the current cube into a buffer.
+
+ for (y=0; y<CUBE_SIZE; y++)
+ {
+ for (z=0; z<CUBE_SIZE; z++)
+ {
+ leds[y][CUBE_SIZE-1-z] = buffer[y][z];
+ }
+ }
+}
+
+
+// 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;
+}
+
+// Returns a byte with a row of 1's drawn in it.
+// byteline(2,5) gives 0b00111100
+char byteline (int start, int end)
+{
+ return ((0xff<<start) & ~(0xff<<(end+1)));
+}
+
+
+// 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 iy;
+ int iz;
+
+ argorder(x1, x2, &x1, &x2);
+ argorder(y1, y2, &y1, &y2);
+ argorder(z1, z2, &z1, &z2);
+
+ // Lines along X axis
+ leds[y1][z1] = byteline(x1,x2);
+ leds[y2][z1] = byteline(x1,x2);
+ leds[y1][z2] = byteline(x1,x2);
+ leds[y2][z2] = byteline(x1,x2);
+
+ // Lines along Y axis
+ for (iy=y1;iy<=y2;iy++)
+ {
+ set_led(x1,iy,z1, true);
+ set_led(x1,iy,z2, true);
+ set_led(x2,iy,z1, true);
+ set_led(x2,iy,z2, true);
+ }
+
+ // Lines along Z axis
+ for (iz=z1;iz<=z2;iz++)
+ {
+ set_led(x1,y1,iz, true);
+ set_led(x1,y2,iz, true);
+ set_led(x2,y1,iz, true);
+ set_led(x2,y2,iz, true);
+ }
+}
+
+void box_shrink_grow_effect(int iterations, int rot, int flip, int delay)
+{
+ for (int it = 0; it < iterations ; ++it) {
+ for (int it2 = 0; it2 < 16; ++it2) {
+ int xyz = it2 > 7 ? it2 - 8: 7 - it2;
+
+ clear_led();
+
+ box_wireframe(0, 0, 0, xyz, xyz, xyz);
+
+ if (flip > 0) mirror_z();
+ if (rot == 1 || rot == 3) mirror_y();
+ if (rot == 2 || rot == 3) mirror_x();
+
+ led_change = true;
+ SDL_Delay(delay);
+ }
+ }
+}
+
+void effect_box_woopwoop (int delay, int grow)
+{
+ int i,ii;
+
+ //fill(0x00);
+ clear_led();
+ for (i=0;i<4;i++)
+ {
+ ii = i;
+ if (grow > 0)
+ ii = 3-i;
+
+ box_wireframe(4+ii,4+ii,4+ii,3-ii,3-ii,3-ii);
+ led_change = true;
+ SDL_Delay(delay);
+ clear_led();
+ //delay_ms(delay);
+ //fill(0x00);
+ }
+}
+
+void draw_positions_axis (char axis, unsigned char positions[64], int invert)
+{
+ int x, y, p;
+
+ //fill(0x00);
+ clear_led();
+
+ for (x=0; x<8; x++)
+ {
+ for (y=0; y<8; y++)
+ {
+ if (invert)
+ {
+ p = (7-positions[(x*8)+y]);
+ } else
+ {
+ p = positions[(x*8)+y];
+ }
+
+ //if (axis == AXIS_Z)
+ if (axis == 2)
+ set_led(x,y,p, true);
+
+ if (axis == 1)
+ set_led(x,p,y, true);
+
+ if (axis == 0)
+ set_led(p,y,x, true);
+ }
+ }
+
+}
+
+
+
+void effect_axis_updown_randsuspend(char axis,
+ int delay, int sleep, int invert)
+{
+ unsigned char positions[64];
+ unsigned char destinations[64];
+
+ int i,px;
+
+ // Set 64 random positions
+ for (i=0; i<64; i++)
+ {
+ positions[i] = 0; // Set all starting positions to 0
+ destinations[i] = rand()%8;
+ }
+
+ // Loop 8 times to allow destination 7 to reach all the way
+ for (i=0; i<8; i++)
+ {
+ // For every iteration, move all position one step closer to their destination
+ for (px=0; px<64; px++)
+ {
+ if (positions[px]<destinations[px])
+ {
+ positions[px]++;
+ }
+ }
+ // Draw the positions and take a nap
+ draw_positions_axis (axis, positions,invert);
+ led_change = true;
+ SDL_Delay(delay);
+ //delay_ms(delay);
+ }
+
+ // Set all destinations to 7 (opposite from the side they started out)
+ for (i=0; i<64; i++)
+ {
+ destinations[i] = 7;
+ }
+
+ // Suspend the positions in mid-air for a while
+ //delay_ms(sleep);
+ SDL_Delay(sleep);
+
+ // Then do the same thing one more time
+ for (i=0; i<8; i++)
+ {
+ for (px=0; px<64; px++)
+ {
+ if (positions[px]<destinations[px])
+ {
+ positions[px]++;
+ }
+ if (positions[px]>destinations[px])
+ {
+ positions[px]--;
+ }
+ }
+ draw_positions_axis (axis, positions,invert);
+ led_change = true;
+ SDL_Delay(delay);
+ //delay_ms(delay);
+ }
+}
+
+void effect_stringfly2(const char* str)
+{
+ //int x,y,i;
+ unsigned char x,y,i;
+ unsigned char chr[5];
+ int delay = 80;
+
+ clear_led();
+
+ while (*str)
+ {
+ font_getchar(*str++, chr);
+
+ // Put a character on the back of the cube
+ for (x = 0; x < 5; x++)
+ {
+ for (y = 0; y < 8; y++)
+ {
+ if ((chr[x] & (0x80>>y)))
+ {
+ //setvoxel(7,x+2,y);
+ //set_led(7,x+2,y);
+ set_led(x+2, 7, y);
+ }
+ }
+ }
+
+ //led_change = true;
+ //SDL_Delay(1000);
+ //clear_led();
+ //continue;
+
+ // Shift the entire contents of the cube forward by 6 steps
+ // before placing the next character
+ for (i = 0; i<6; i++)
+ {
+ led_change = true;
+ //delay_ms(1000);
+ //SDL_Delay(1000);
+ SDL_Delay(delay);
+ //shift(AXIS_X,-1);
+ shift(1,-1);
+ //set_plane(1, 7, false);
+ }
+ }
+
+ //return;
+ // Shift the last character out of the cube.
+ for (i = 0; i<8; i++)
+ {
+ led_change = true;
+ SDL_Delay(delay);
+ //delay_ms(1000);
+ //shift(AXIS_X,-1);
+ shift(1,-1);
+ }
+}
+
+float distance2d (float x1, float y1, float x2, float y2)
+{
+ float dist;
+ dist = sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
+
+ return dist;
+}
+
+float distance3d (float x1, float y1, float z1, float x2, float y2, float z2)
+{
+ float dist;
+ dist = sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) + (z1-z2)*(z1-z2));
+
+ return dist;
+}
+
+
+
+
+// Display a sine wave running out from the center of the cube.
+void ripples (int iterations, int delay)
+{
+ float distance, height, ripple_interval;
+ int x,y,i;
+
+ clear_led();
+ //fill(0x00);
+
+ for (i=0;i<iterations;i++)
+ {
+ for (x=0;x<8;x++)
+ {
+ for (y=0;y<8;y++)
+ {
+ distance = distance2d(3.5,3.5,x,y)/9.899495*8;
+ //distance = distance2d(3.5,3.5,x,y);
+ ripple_interval =1.3;
+ height = 4+sin(distance/ripple_interval+(float) i/50)*4;
+
+ //setvoxel(x,y,(int) height);
+ set_led(x,y,(int) height);
+ }
+ }
+ //delay_ms(delay);
+ led_change = true;
+ SDL_Delay(delay);
+ //fill(0x00);
+ clear_led();
+ }
+}
+
+
+
+/*****************************************************************************
+ * EFFECT LAUNCHER
+ *****************************************************************************/
+
+void launch_effect(int effect)
+{
+ switch(effect) {
+ case 0: rain_effect(100); break;
+ case 1: sendvoxels_random_z_effect(20, 50, 100); break;
+ case 2:
+ break;
+ case 3:
+ break;
+ case 4:
+ break;
+ case 5: ripples(1000, 50); break;
+ case 6:
+ for (int i = 0; i < 8; ++i) {
+ box_shrink_grow_effect(1, i%4, i & 0x4, 50);
+ }
+ effect_box_woopwoop(80, 0);
+ effect_box_woopwoop(80, 1);
+ effect_box_woopwoop(80, 0);
+ effect_box_woopwoop(80, 1);
+ break;
+ case 7:
+ for (int i = 0; i < 6; ++i) {
+ planboing(i%3, 50);
+ }
+ break;
+ case 9:
+ effect_axis_updown_randsuspend(2, 55, 100, 0);
+ effect_axis_updown_randsuspend(2, 55, 100, 1);
+ effect_axis_updown_randsuspend(2, 55, 100, 0);
+ effect_axis_updown_randsuspend(2, 55, 100, 1);
+ effect_axis_updown_randsuspend(0, 55, 100, 0);
+ effect_axis_updown_randsuspend(0, 55, 100, 1);
+ effect_axis_updown_randsuspend(1, 55, 100, 0);
+ effect_axis_updown_randsuspend(1, 55, 100, 1);
+ break;
+ case 12:
+ //clear_led();
+ //set_led(0, 0, 7);
+ //SDL_Delay(1000);
+ effect_stringfly2("Vive Lyly");
+ break;
+ default:
+ break;
+ }
+}