Go Down

Topic: Big RGB Table Finally Needs Code (Read 5589 times) previous topic - next topic

Paranemertes

ok, i think for ease of programming, since im so new and all, i will go with the first configuration. I tried modifieing some of your example code, since i have a 12x24 matrix (12 RGBs) so really 36x24

Code: [Select]
// code for an 36 x 24 array (12 RGB LEDs, 24 columns) as an example
// not all code parts shown, just the highlights
// set up an array for the cathode drives
byte cathodeslower[ ] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20,  0x40, 0x80, 0,0,0,0,0,0,0,0};  // walking 1 for lower 8 NPNs
byte cathodesmid[ ] = {0,0,0,0, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,  0x40, 0x80, 0,0,0,0}; //walking for mid 8 NPNs ????????
byte cathodeshigher[ ] = {0,0,0,0,0,0,0,0,0x01, 0x02, 0x04, 0x08, 0x10, 0x20,  0x40, 0x80};  // walking 1 for upper 8 NPNs
byte anodes1 [12]; // array to hold 1st 3rd of RGB info, like red?
byte anodes2 [12]; // array to hold 2nd 3rd of RGB info, like blue?
byte anodes3 [12]; // array to hold 3rd 3rd of RGB info, like green?
byte columncount;
byte oe = 12;
unsigned long updateTime = 0;

void setup(){
pinMode (oe/, OUTPUT);
digitalWrite (oe/, HIGH);
SPI.begin;
}

void loop(){
// set up for blink without delay operation
if (millis() >=updateTime){
// yes, set up for next update
updateTime = updateTime +2; // update a column every 2 milliseconds, 16 columns at ~24 Hz rate
digitalWrite (oe, HIGH);  // turn off display
SPI.transfer (anodes1[columncount]); // update anodes
SPI.transfer (anodes2[columncount]); // update anodes
SPI.transfer (anodes3[columncount]); // update anodes
SPI.transfer (cathodeslower[columncount]); // turn on a cathode
SPI.transfer (cathodesupper[columncount]); // turn on a cathode
digitalWrite (oe, LOW); / turn display back on
columncount = columncount + 1; // update for next column
if (columncount == 24){columncount = 0;} // reset if reach the end
} //end display refresh

// now the fun part, for you!
// read buttons, or whatever processing you plan to do for patterns, etc.,
// and update anodes1, anodes2, anode3 as needed
} // end void loop


I really dont know about that cathodemid section, mostly guessing when i wrote that. But i did manage to do my research on hex, so at least that is understandable now. Still a little fuzzy on arrays.
"It's Dr. Evil. I didn't spend six years in Evil Medical School to be called 'mister,' thank you very much."

CrossRoads

Looking like a good start.
Maybe populate the anodes arrays as test starting condition and see if this works. Then start the array changing code.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

Paranemertes

Sounds good, too bad I won't be home until Sunday....
"It's Dr. Evil. I didn't spend six years in Evil Medical School to be called 'mister,' thank you very much."

Paranemertes

Do you think you could show me an example of how I could get it to slowly cycle through all the columns? Like turn on red for column 1 then wait a second then move on to column 2 repeat. When it gets to the end, that is, it's gone through all 24 columns, then repeat with blue, then green, then the other combinations?? Not sue where to start for that... Thank you!!
"It's Dr. Evil. I didn't spend six years in Evil Medical School to be called 'mister,' thank you very much."

Nick Gammon

#19
Apr 28, 2012, 11:52 pm Last Edit: Apr 28, 2012, 11:54 pm by Nick Gammon Reason: 1
Do what you had and thrown in a delay afterwards?

Well you seem to have timing in it. The code looks like it might potentially work. The devil is in the detail in your case ... are you bit patterns right? Only you can say that.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

CrossRoads

Can give it a shot a little later.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

Paranemertes

Thanks CrossRoads, id really appreciate it.
"It's Dr. Evil. I didn't spend six years in Evil Medical School to be called 'mister,' thank you very much."

CrossRoads

Ok, maybe something like this
Code: [Select]

#include <SPI.h>

// code for an 36 x 24 array (12 RGB LEDs, 24 columns) as an example
// not all code parts shown, just the highlights
// set up an array for the cathode drives
byte cathodeslower[ ] = {
  0x01, 0x02, 0x04, 0x08, 0x10, 0x20,  0x40, 0x80, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};  // walking 1 for lower 8 NPNs
byte cathodesmid[ ] = {
  0,0,0,0,0,0,0,0, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0,0,0,0,0,0,0,0}; //walking for mid 8 NPNs ????????
byte cathodeshigher[ ] = {
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x01, 0x02, 0x04, 0x08, 0x10, 0x20,  0x40, 0x80};  // walking 1 for upper 8 NPNs
 
byte anodes1 [12]; // array to hold 1st 3rd of RGB info, like red?
byte anodes2 [12]; // array to hold 2nd 3rd of RGB info, like blue?
byte anodes3 [12]; // array to hold 3rd 3rd of RGB info, like green?
byte columncount;
byte oe = 12;
unsigned long updateTime = 0;
unsigned long exampleTime = 0;
byte  Red = 0; // arrays go from 0 to 11
byte  Green = 12;
byte  Blue = 12;

void setup(){
  pinMode (oe, OUTPUT);
  digitalWrite (oe, HIGH);
  SPI.begin;

}

void loop(){
  // set up for blink without delay operation
  if (millis() >=updateTime){
    // yes, set up for next update
    updateTime = updateTime +2; // update a column every 2 milliseconds, 16 columns at ~24 Hz rate
    digitalWrite (oe, HIGH);  // turn off display
    SPI.transfer (anodes1[columncount]); // update anodes
    SPI.transfer (anodes2[columncount]); // update anodes
    SPI.transfer (anodes3[columncount]); // update anodes
    SPI.transfer (cathodeslower[columncount]); // turn on a cathode
    SPI.transfer (cathodesmid[columncount]); // turn on a cathode
    SPI.transfer (cathodeshigher[columncount]); // turn on a cathode
    digitalWrite (oe, LOW);  //turn display back on
      columncount = columncount + 1; // update for next column
    if (columncount == 24){
      columncount = 0;
    } // reset if reach the end
  } //end display refresh

  // now the fun part, for you!
  // read buttons, or whatever processing you plan to do for patterns, etc.,
  // and update anodes1, anodes2, anode3 as needed
  if (millis() >= exampleTime){
    exampleTime = exampleTime + 500; // 1/2 second changes
    if (Red < 12){
      anodes1[Red] = 0; // turn off prior LED
      Red = Red + 1; // set up for next LED
      if (Red == 12){  // if at last LED, set up next color
        Blue = 0;
      }
      else {
        anodes1[Red] = 1; // turn on next LED
      }
    }
    if (Blue<12){
      anodes2[Blue] = 0;
      Blue = Blue + 1;
      if (Blue == 12){
        Green = 0;
      }
      else{
        anodes2[Blue] = 1;
      }
    }
    if (Green <12){
      anodes3[Green] = 0;
      Green = Green + 1;
      if (Green == 12){
        Red = 0;
      }
      else{
        anodes3[Green] = 1;
      }
    }
  }

} // end void loop
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

Paranemertes

Thanks, I'll give it a try tomarrow.
"It's Dr. Evil. I didn't spend six years in Evil Medical School to be called 'mister,' thank you very much."

Paranemertes

PHEW. ok sorry about the delay, lots of stuff to do and all that. I FINALLY got some lights on! (just spend 2 1/2 hours doing some trial and error and working my way up on code) Minus 2 leds that need replacing and what i think to be a MOSFET that might be troubled, it works perfectly! you can see in the pics the column that needs replacing, and the 2 leds that are out, one has a blue out, the other has a red. Unfortunately your code didnt work... I tried some manipulations but i really dont know what i am doing, its like trying to build the Eiffel Tower out of legos while wearing boxing gloves. But hey, who doesnt love to learn? I worked my way up to this code:

Code: [Select]
#include <SPI.h>

const int oe = 10;

byte chip1 = 0xFF;
byte chip2 = 0xFF;
byte chip3 = 0xFF;
byte chip4 = 0xFF;
byte chip5 = 0xFF;

unsigned int time = 500;

void setup(){
  SPI.begin();
  pinMode(oe, OUTPUT);
  digitalWrite(oe, LOW);
}

void loop(){
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(0x80);
  SPI.transfer(chip5);
  SPI.transfer(chip4);
  SPI.transfer(chip3);
  SPI.transfer(chip2);
  SPI.transfer(chip1);
  delayMicroseconds(time);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(0x40);
  SPI.transfer(chip5);
  SPI.transfer(chip4);
  SPI.transfer(chip3);
  SPI.transfer(chip2);
  SPI.transfer(chip1);
  delayMicroseconds(time);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(0x20);
  SPI.transfer(chip5);
  SPI.transfer(chip4);
  SPI.transfer(chip3);
  SPI.transfer(chip2);
  SPI.transfer(chip1);
  delayMicroseconds(time);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(0x10);
  SPI.transfer(chip5);
  SPI.transfer(chip4);
  SPI.transfer(chip3);
  SPI.transfer(chip2);
  SPI.transfer(chip1);
  delayMicroseconds(time);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(0x08);
  SPI.transfer(chip5);
  SPI.transfer(chip4);
  SPI.transfer(chip3);
  SPI.transfer(chip2);
  SPI.transfer(chip1);
  delayMicroseconds(time);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(0x04);
  SPI.transfer(chip5);
  SPI.transfer(chip4);
  SPI.transfer(chip3);
  SPI.transfer(chip2);
  SPI.transfer(chip1);
  delayMicroseconds(time);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(0x02);
  SPI.transfer(chip5);
  SPI.transfer(chip4);
  SPI.transfer(chip3);
  SPI.transfer(chip2);
  SPI.transfer(chip1);
  delayMicroseconds(time);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(0x01);
  SPI.transfer(chip5);
  SPI.transfer(chip4);
  SPI.transfer(chip3);
  SPI.transfer(chip2);
  SPI.transfer(chip1);
  delayMicroseconds(time);
 
  SPI.transfer(0);
  SPI.transfer(0x80);
  SPI.transfer(0);
  SPI.transfer(chip5);
  SPI.transfer(chip4);
  SPI.transfer(chip3);
  SPI.transfer(chip2);
  SPI.transfer(chip1);
  delayMicroseconds(time);
  SPI.transfer(0);
  SPI.transfer(0x40);
  SPI.transfer(0);
  SPI.transfer(chip5);
  SPI.transfer(chip4);
  SPI.transfer(chip3);
  SPI.transfer(chip2);
  SPI.transfer(chip1);
  delayMicroseconds(time);
  SPI.transfer(0);
  SPI.transfer(0x20);
  SPI.transfer(0);
  SPI.transfer(chip5);
  SPI.transfer(chip4);
  SPI.transfer(chip3);
  SPI.transfer(chip2);
  SPI.transfer(chip1);
  delayMicroseconds(time);
  SPI.transfer(0);
  SPI.transfer(0x10);
  SPI.transfer(0);
  SPI.transfer(chip5);
  SPI.transfer(chip4);
  SPI.transfer(chip3);
  SPI.transfer(chip2);
  SPI.transfer(chip1);
  delayMicroseconds(time);
  SPI.transfer(0);
  SPI.transfer(0x08);
  SPI.transfer(0);
  SPI.transfer(chip5);
  SPI.transfer(chip4);
  SPI.transfer(chip3);
  SPI.transfer(chip2);
  SPI.transfer(chip1);
  delayMicroseconds(time);
  SPI.transfer(0);
  SPI.transfer(0x04);
  SPI.transfer(0);
  SPI.transfer(chip5);
  SPI.transfer(chip4);
  SPI.transfer(chip3);
  SPI.transfer(chip2);
  SPI.transfer(chip1);
  delayMicroseconds(time);
  SPI.transfer(0);
  SPI.transfer(0x02);
  SPI.transfer(0);
  SPI.transfer(chip5);
  SPI.transfer(chip4);
  SPI.transfer(chip3);
  SPI.transfer(chip2);
  SPI.transfer(chip1);
  delayMicroseconds(time);
  SPI.transfer(0);
  SPI.transfer(0x01);
  SPI.transfer(0);
  SPI.transfer(chip5);
  SPI.transfer(chip4);
  SPI.transfer(chip3);
  SPI.transfer(chip2);
  SPI.transfer(chip1);
  delayMicroseconds(time);
 
  SPI.transfer(0x80);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(chip5);
  SPI.transfer(chip4);
  SPI.transfer(chip3);
  SPI.transfer(chip2);
  SPI.transfer(chip1);
  delayMicroseconds(time);
  SPI.transfer(0x40);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(chip5);
  SPI.transfer(chip4);
  SPI.transfer(chip3);
  SPI.transfer(chip2);
  SPI.transfer(chip1);
  delayMicroseconds(time);
  SPI.transfer(0x20);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(chip5);
  SPI.transfer(chip4);
  SPI.transfer(chip3);
  SPI.transfer(chip2);
  SPI.transfer(chip1);
  delayMicroseconds(time);
  SPI.transfer(0x10);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(chip5);
  SPI.transfer(chip4);
  SPI.transfer(chip3);
  SPI.transfer(chip2);
  SPI.transfer(chip1);
  delayMicroseconds(time);
  SPI.transfer(0x08);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(chip5);
  SPI.transfer(chip4);
  SPI.transfer(chip3);
  SPI.transfer(chip2);
  SPI.transfer(chip1);
  delayMicroseconds(time);
  SPI.transfer(0x04);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(chip5);
  SPI.transfer(chip4);
  SPI.transfer(chip3);
  SPI.transfer(chip2);
  SPI.transfer(chip1);
  delayMicroseconds(time);
  SPI.transfer(0x02);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(chip5);
  SPI.transfer(chip4);
  SPI.transfer(chip3);
  SPI.transfer(chip2);
  SPI.transfer(chip1);
  delayMicroseconds(time);
  SPI.transfer(0x01);
  SPI.transfer(0);
  SPI.transfer(0);
  SPI.transfer(chip5);
  SPI.transfer(chip4);
  SPI.transfer(chip3);
  SPI.transfer(chip2);
  SPI.transfer(chip1);
  delayMicroseconds(time);
}


Ewwwww, isnt that gross?? Do you know a basic way to shorten it? Fortunately the SPI is working, i started
with shiftOut(), but there was a ton of flickering, i tried messing with the output enabler, but no good.

now then; what suggestions do you have for learning how to make more complicated animations? Your code seems like it would work, and i have a BASIC understanding of it. Maybe you could revise it? I'll keep trying to expand my knowledge and fix those minor hardware issues. Thank you so much for all your help so far! and thanks for directing me towards the SPI,
Quote
none of that shiftOut nonsense

great advice.
"It's Dr. Evil. I didn't spend six years in Evil Medical School to be called 'mister,' thank you very much."

Nick Gammon

Quote
Do you know a basic way to shorten it?


Use a loop. Use an array of what your patterns are.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Nick Gammon

Funnily enough I'm helping someone else out with SPI and shift registers:

http://arduino.cc/forum/index.php/topic,103839

I haven't tried patterns (I don't have dozens of LEDs wired up) but it would be simple enough to do, depending on the effect you are after.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Paranemertes

Thanks Nick, the thread didnt really help but Mikes webpage on arrays was nice. Im looking for something like what CrossRoads is doing, set up something like a blinkwithoutdelay program at the beginning (or end?) of the loop that cycles the gnd MOSFETS so it really only displays one column at a time, but thanks to persistance of vision we see a whole image. I have it doing that now with 500 microsecond delays between SPI transfers, that seems to be fast enough. So if my math is correct (and i dont think it is) that would be a refresh time of about ~83 Hz? doesnt really matter, but i also want to be able to punch that in at the top of the whole thing, like right now. Anyway kinda ranting, the main thing i am having trouble with is understyanding how to set up that first main part that cycles through the columns. Thanks!
"It's Dr. Evil. I didn't spend six years in Evil Medical School to be called 'mister,' thank you very much."

CrossRoads

Paranemertes,
I think you have the right idea - your code is like the long  hand version of the array lookups I had in a loop.
So if you had a for:next loop that went from 0 to 23,
Code: [Select]

for (x = 0; x<24; x=x+1){

and each of these was an array of 24 bytes
Code: [Select]

  SPI.transfer(0);          >> SPI.transfer(lower_cathode[x]);
  SPI.transfer(0x10);    >> SPI.transfer(middle_cathode[x]);
  SPI.transfer(0);          >> SPI.transfer(upper_cathode[x]);
  SPI.transfer(chip5);   >> SPI.transfer(chip5_anode[x]);
  SPI.transfer(chip4);   >> SPI.transfer(chip4_anode[x]);
  SPI.transfer(chip3);   >> SPI.transfer(chip3_anode[x]);
  SPI.transfer(chip2);   >> SPI.transfer(chip2_anode[x]);
  SPI.transfer(chip1);   >> SPI.transfer(chip1_anode[x]);


then every time thru the for:next loop it would cycle thru all the data in the arrays.
Code: [Select]

for (x = 0; x<24; x=x+1){
  SPI.transfer(lower_cathode[x]);
  SPI.transfer(middle_cathode[x]);
  SPI.transfer(upper_cathode[x]);
  SPI.transfer(chip5_anode[x]);
  SPI.transfer(chip4_anode[x]);
  SPI.transfer(chip3_anode[x]);
  SPI.transfer(chip2_anode[x]);
SPI.transfer(chip1_anode[x]);
}

and during the 500uS ontime you could do whatever logic you wanted, reading buttons, updating chip5/4/3/2/1 array values, etc.
Code: [Select]

void loop(){
for (x = 0; x<24; x=x+1){
  SPI.transfer(lower_cathode[x]);
  SPI.transfer(middle_cathode[x]);
  SPI.transfer(upper_cathode[x]);
  SPI.transfer(chip5_anode[x]);
  SPI.transfer(chip4_anode[x]);
  SPI.transfer(chip3_anode[x]);
  SPI.transfer(chip2_anode[x]);
SPI.transfer(chip1_anode[x]);

unsigned long startTime  = micros();
   while (micros() - startTime <=500){
   // read buttons, update array, etc
    } // end while
// 'while' finally expires, the display refresh runs the next x
   } // end for:next, 0:23
} // end loop
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

Paranemertes

#29
May 03, 2012, 07:59 am Last Edit: May 03, 2012, 08:01 am by Paranemertes Reason: 1
Ok great,i think we are off to a good start, still cant get anything to light up with the shorter code though. got those bad leds fixed and the faulty mosfet out of there so the hardware is 100% now. I gave a shot at trying to turn on all the colors at once with some of your new stuff and some guessing on my part (its really like boxing gloves and legos) unfortunately it didnt do anything.

Code: [Select]
#include <SPI.h>

// set up an array for the cathode drives
byte lower_cathode[ ] = {
 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,  0x40, 0x80, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};  // walking 1 for lower 8 NPNs
byte middle_cathode[ ] = {
 0,0,0,0,0,0,0,0, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0,0,0,0,0,0,0,0}; //walking for mid 8 NPNs
byte upper_cathode[ ] = {
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x01, 0x02, 0x04, 0x08, 0x10, 0x20,  0x40, 0x80};  // walking 1 for upper 8 NPNs

//are these arrays neccesary?
byte chip5 [8]; //holds green 9-12
byte chip4 [8]; //holds green 1-8
byte chip3 [8]; //holds blue 5-12
byte chip2 [8]; //holds red 9-12 and blue 1-4
byte chip1 [8]; //holds red 1-8

byte chip5_value = 0xFF; //chip values
byte chip4_value = 0xFF;
byte chip3_value = 0xFF;
byte chip2_value = 0xFF;
byte chip1_value = 0xFF;

byte anodes1 [12]; // array to hold 1st 3rd of RGB info, like red?
byte anodes2 [12]; // array to hold 2nd 3rd of RGB info, like blue?
byte anodes3 [12]; // array to hold 3rd 3rd of RGB info, like green?

byte columncount;

byte oe = 10;

unsigned long updateTime = 0;
unsigned long exampleTime = 0;

byte  Red = 0; // arrays go from 0 to 11
byte  Green = 12;
byte  Blue = 12;

int x = 0;
int i = 0;

void setup(){
 pinMode(oe, OUTPUT);
 digitalWrite (oe, LOW);
 SPI.begin();
}

void loop(){
 
for (x = 0; x < 24; x++){
 SPI.transfer(lower_cathode[x]);
 SPI.transfer(middle_cathode[x]);
 SPI.transfer(upper_cathode[x]);
 SPI.transfer(chip5[x]);
 SPI.transfer(chip4[x]);
 SPI.transfer(chip3[x]);
 SPI.transfer(chip2[x]);
SPI.transfer(chip1[x]);

unsigned long startTime = micros();
  while (micros() - startTime <= 500){
  // read buttons, update array, etc
 
  for(i = 0; i < 12; i++){
    SPI.transfer(chip5[chip5_value]);
    SPI.transfer(chip4[chip4_value]);
    SPI.transfer(chip3[chip3_value]);
    SPI.transfer(chip2[chip2_value]);
    SPI.transfer(chip1[chip1_value]);
  } // end while
 
// 'while' finally expires, the display refresh runs the next x

  } // end for:next, 0:23
} //end first for
} // end loop


Quote
and each of these was an array of 24 bytes
Code: [Select]
SPI.transfer(0);          >> SPI.transfer(lower_cathode[x]);
  SPI.transfer(0x10);    >> SPI.transfer(middle_cathode[x]);
  SPI.transfer(0);          >> SPI.transfer(upper_cathode[x]);
  SPI.transfer(chip5);   >> SPI.transfer(chip5_anode[x]);
  SPI.transfer(chip4);   >> SPI.transfer(chip4_anode[x]);
  SPI.transfer(chip3);   >> SPI.transfer(chip3_anode[x]);
  SPI.transfer(chip2);   >> SPI.transfer(chip2_anode[x]);
  SPI.transfer(chip1);   >> SPI.transfer(chip1_anode[x]);



this confuses me just a bit, could you possibly show me those 24 byte arrays? What im after is all leds on throughout the table, no fancy animations, no bling, just all on. thanks! really happy with how this is coming along.
"It's Dr. Evil. I didn't spend six years in Evil Medical School to be called 'mister,' thank you very much."

Go Up