diff options
Diffstat (limited to 'cube_gl/effect.cpp')
-rw-r--r-- | cube_gl/effect.cpp | 776 |
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; + } +} |