#ifdef DEBUG
#include <TinyDebug.h>
#endif

#define DS 2
#define STCP 3
#define SHCP 4
int zOff = 150;
int xOff = 0;
int yOff = 0;
int cSize = 50;
int view_plane = 12;//64;
float angle = PI/60;
#define vres 16
#define hres 16
const int ledAmount = 16 * 16;

float cube3d[8][3] = {
  {xOff - cSize,yOff + cSize,zOff - cSize},
  {xOff + cSize,yOff + cSize,zOff - cSize},
  {xOff - cSize,yOff - cSize,zOff - cSize},
  {xOff + cSize,yOff - cSize,zOff - cSize},
  {xOff - cSize,yOff + cSize,zOff + cSize},
  {xOff + cSize,yOff + cSize,zOff + cSize},
  {xOff - cSize,yOff - cSize,zOff + cSize},
  {xOff + cSize,yOff - cSize,zOff + cSize}
};
unsigned char cube2d[8][2];
bool buf[vres][hres];

void line(int x0, int y0, int x1, int y1) {
  bool steep = false; 
  if (x0<0){x0=0;}
  if (x1<0){x1=0;}
  if (y0<0){y0=0;}
  if (y1<0){y1=0;}


  if (x0>(hres-1)){x0=(hres-1);}
  if (x1>(hres-1)){x1=(hres-1);}
  if (y0>(hres-1)){y0=(hres-1);}
  if (y1>(hres-1)){y1=(hres-1);}


  if (x0>(vres-1)){x0=(vres-1);}
  if (x1>(vres-1)){x1=(vres-1);}
  if (y0>(vres-1)){y0=(vres-1);}
  if (y1>(vres-1)){y1=(vres-1);}
#ifdef DEBUG
  Debug.print(x0);
  Debug.print(F(" "));
  Debug.print(y0);
  Debug.print(F(" "));
  Debug.print(x1);
  Debug.print(F(" "));
  Debug.println(y1);
  #endif

    if (abs(x0-x1)<abs(y0-y1)) { 
        int t = x0;
        x0=y0;
        y0=t;
        t = x1;
        x1=y1;
        y1=t;
        
        steep = true; 
    } 
    if (x0>x1) { 
        int t = x0;
        x0=x1;
        x1=t;
        t=y0;
        y0=y1;
        y1=t;
         
    } 
    int dx = x1-x0; 
    int dy = y1-y0; 
    float derror = abs(dy/float(dx)); 
    float error = 0; 
    int y = y0; 
    for (int x=x0; x<=x1; x++) { 
        if (steep) { 
            buf[y][x]=1;
            
        } else { 
            buf[x][y]=1;
        } 
        error += derror; 
        if (error>.5) { 
            y += (y1>y0?1:-1); 
            error -= 1.; 
        } 
    } 

}

void setup() {
  // put your setup code here, to run once:
  #ifdef DEBUG
  Debug.begin();
  #endif
  pinMode(DS, OUTPUT);
  pinMode(STCP, OUTPUT);
  pinMode(SHCP, OUTPUT);

}

void loop() {
  // put your main code here, to run repeatedly:
  //for (int i = 0; i < 70; i++) {
  //        yrotate(angle);
  //}
  //      printcube();
  //      while(10)delay(10);
  //      return;
  int rsteps = random(10,60);
  switch(random(6)) {
    case 0:
      for (int i = 0; i < rsteps; i++) {
        zrotate(angle);
        printcube();
      }
      break;
    case 1:
      for (int i = 0; i < rsteps; i++) {
        zrotate(2*PI - angle);
        printcube();
      }
      break;
    case 2:
      for (int i = 0; i < rsteps; i++) {
        xrotate(angle);
        printcube();
      }
      break;
    case 3:
      for (int i = 0; i < rsteps; i++) {
        xrotate(2*PI - angle);
        printcube();
      }
      break;
    case 4:
      for (int i = 0; i < rsteps; i++) {
        yrotate(angle);
        printcube();
      }
      break;
    case 5:
      for (int i = 0; i < rsteps; i++) {
        yrotate(2*PI - angle);
        printcube();
      }
      break;
  }
}


void printcube() {
  //calculate 2d points
  for(byte i = 0; i < 8; i++) {
    cube2d[i][0] = (unsigned char)((cube3d[i][0] * view_plane / cube3d[i][2]) + (hres/2));
    cube2d[i][1] = (unsigned char)((cube3d[i][1] * view_plane / cube3d[i][2]) + (vres/2));
  }
  draw_cube();
}

void zrotate(float q) {
  float tx,ty,temp;
  for(byte i = 0; i < 8; i++) {
    tx = cube3d[i][0] - xOff;
    ty = cube3d[i][1] - yOff;
    temp = tx * cos(q) - ty * sin(q);
    ty = tx * sin(q) + ty * cos(q);
    tx = temp;
    cube3d[i][0] = tx + xOff;
    cube3d[i][1] = ty + yOff;
  }
}

void yrotate(float q) {
  float tx,tz,temp;
  for(byte i = 0; i < 8; i++) {
    tx = cube3d[i][0] - xOff;
    tz = cube3d[i][2] - zOff;
    temp = tz * cos(q) - tx * sin(q);
    tx = tz * sin(q) + tx * cos(q);
    tz = temp;
    cube3d[i][0] = tx + xOff;
    cube3d[i][2] = tz + zOff;
  }
}

void xrotate(float q) {
  float ty,tz,temp;
  for(byte i = 0; i < 8; i++) {
    ty = cube3d[i][1] - yOff;
    tz = cube3d[i][2] - zOff;
    temp = ty * cos(q) - tz * sin(q);
    tz = ty * sin(q) + tz * cos(q);
    ty = temp;
    cube3d[i][1] = ty + yOff;
    cube3d[i][2] = tz + zOff;
  }
}
void showLeds() {
  digitalWrite(STCP, LOW);
  for (int x = 0;x<ledAmount;x++) {
    digitalWrite(SHCP, LOW);
    digitalWrite(DS, buf[(vres - 1)- (x/vres)][(vres - 1)- (x%hres)] ? HIGH : LOW);
    digitalWrite(SHCP, HIGH);
  }
  digitalWrite(STCP, HIGH);
}

void draw_cube() {
  memset(buf, 0, sizeof buf);
  line(cube2d[0][0],cube2d[0][1],cube2d[1][0],cube2d[1][1]);
  line(cube2d[0][0],cube2d[0][1],cube2d[2][0],cube2d[2][1]);
  line(cube2d[0][0],cube2d[0][1],cube2d[4][0],cube2d[4][1]);
  line(cube2d[1][0],cube2d[1][1],cube2d[5][0],cube2d[5][1]);
  line(cube2d[1][0],cube2d[1][1],cube2d[3][0],cube2d[3][1]);
  line(cube2d[2][0],cube2d[2][1],cube2d[6][0],cube2d[6][1]);
  line(cube2d[2][0],cube2d[2][1],cube2d[3][0],cube2d[3][1]);
  line(cube2d[4][0],cube2d[4][1],cube2d[6][0],cube2d[6][1]);
  line(cube2d[4][0],cube2d[4][1],cube2d[5][0],cube2d[5][1]);
  line(cube2d[7][0],cube2d[7][1],cube2d[6][0],cube2d[6][1]);
  line(cube2d[7][0],cube2d[7][1],cube2d[3][0],cube2d[3][1]);
  line(cube2d[7][0],cube2d[7][1],cube2d[5][0],cube2d[5][1]);
  showLeds();
}
led0:A
led0:C
led1:A
led1:C
led2:A
led2:C
led3:A
led3:C
led4:A
led4:C
led5:A
led5:C
led6:A
led6:C
led7:A
led7:C
led8:A
led8:C
led9:A
led9:C
led10:A
led10:C
led11:A
led11:C
led12:A
led12:C
led13:A
led13:C
led14:A
led14:C
led15:A
led15:C
led16:A
led16:C
led17:A
led17:C
led18:A
led18:C
led19:A
led19:C
led20:A
led20:C
led21:A
led21:C
led22:A
led22:C
led23:A
led23:C
led24:A
led24:C
led25:A
led25:C
led26:A
led26:C
led27:A
led27:C
led28:A
led28:C
led29:A
led29:C
led30:A
led30:C
led31:A
led31:C
led32:A
led32:C
led33:A
led33:C
led34:A
led34:C
led35:A
led35:C
led36:A
led36:C
led37:A
led37:C
led38:A
led38:C
led39:A
led39:C
led40:A
led40:C
led41:A
led41:C
led42:A
led42:C
led43:A
led43:C
led44:A
led44:C
led45:A
led45:C
led46:A
led46:C
led47:A
led47:C
led48:A
led48:C
led49:A
led49:C
led50:A
led50:C
led51:A
led51:C
led52:A
led52:C
led53:A
led53:C
led54:A
led54:C
led55:A
led55:C
led56:A
led56:C
led57:A
led57:C
led58:A
led58:C
led59:A
led59:C
led60:A
led60:C
led61:A
led61:C
led62:A
led62:C
led63:A
led63:C
led64:A
led64:C
led65:A
led65:C
led66:A
led66:C
led67:A
led67:C
led68:A
led68:C
led69:A
led69:C
led70:A
led70:C
led71:A
led71:C
led72:A
led72:C
led73:A
led73:C
led74:A
led74:C
led75:A
led75:C
led76:A
led76:C
led77:A
led77:C
led78:A
led78:C
led79:A
led79:C
led80:A
led80:C
led81:A
led81:C
led82:A
led82:C
led83:A
led83:C
led84:A
led84:C
led85:A
led85:C
led86:A
led86:C
led87:A
led87:C
led88:A
led88:C
led89:A
led89:C
led90:A
led90:C
led91:A
led91:C
led92:A
led92:C
led93:A
led93:C
led94:A
led94:C
led95:A
led95:C
led96:A
led96:C
led97:A
led97:C
led98:A
led98:C
led99:A
led99:C
led100:A
led100:C
led101:A
led101:C
led102:A
led102:C
led103:A
led103:C
led104:A
led104:C
led105:A
led105:C
led106:A
led106:C
led107:A
led107:C
led108:A
led108:C
led109:A
led109:C
led110:A
led110:C
led111:A
led111:C
led112:A
led112:C
led113:A
led113:C
led114:A
led114:C
led115:A
led115:C
led116:A
led116:C
led117:A
led117:C
led118:A
led118:C
led119:A
led119:C
led120:A
led120:C
led121:A
led121:C
led122:A
led122:C
led123:A
led123:C
led124:A
led124:C
led125:A
led125:C
led126:A
led126:C
led127:A
led127:C
led128:A
led128:C
led129:A
led129:C
led130:A
led130:C
led131:A
led131:C
led132:A
led132:C
led133:A
led133:C
led134:A
led134:C
led135:A
led135:C
led136:A
led136:C
led137:A
led137:C
led138:A
led138:C
led139:A
led139:C
led140:A
led140:C
led141:A
led141:C
led142:A
led142:C
led143:A
led143:C
led144:A
led144:C
led145:A
led145:C
led146:A
led146:C
led147:A
led147:C
led148:A
led148:C
led149:A
led149:C
led150:A
led150:C
led151:A
led151:C
led152:A
led152:C
led153:A
led153:C
led154:A
led154:C
led155:A
led155:C
led156:A
led156:C
led157:A
led157:C
led158:A
led158:C
led159:A
led159:C
led160:A
led160:C
led161:A
led161:C
led162:A
led162:C
led163:A
led163:C
led164:A
led164:C
led165:A
led165:C
led166:A
led166:C
led167:A
led167:C
led168:A
led168:C
led169:A
led169:C
led170:A
led170:C
led171:A
led171:C
led172:A
led172:C
led173:A
led173:C
led174:A
led174:C
led175:A
led175:C
led176:A
led176:C
led177:A
led177:C
led178:A
led178:C
led179:A
led179:C
led180:A
led180:C
led181:A
led181:C
led182:A
led182:C
led183:A
led183:C
led184:A
led184:C
led185:A
led185:C
led186:A
led186:C
led187:A
led187:C
led188:A
led188:C
led189:A
led189:C
led190:A
led190:C
led191:A
led191:C
led192:A
led192:C
led193:A
led193:C
led194:A
led194:C
led195:A
led195:C
led196:A
led196:C
led197:A
led197:C
led198:A
led198:C
led199:A
led199:C
led200:A
led200:C
led201:A
led201:C
led202:A
led202:C
led203:A
led203:C
led204:A
led204:C
led205:A
led205:C
led206:A
led206:C
led207:A
led207:C
led208:A
led208:C
led209:A
led209:C
led210:A
led210:C
led211:A
led211:C
led212:A
led212:C
led213:A
led213:C
led214:A
led214:C
led215:A
led215:C
led216:A
led216:C
led217:A
led217:C
led218:A
led218:C
led219:A
led219:C
led220:A
led220:C
led221:A
led221:C
led222:A
led222:C
led223:A
led223:C
led224:A
led224:C
led225:A
led225:C
led226:A
led226:C
led227:A
led227:C
led228:A
led228:C
led229:A
led229:C
led230:A
led230:C
led231:A
led231:C
led232:A
led232:C
led233:A
led233:C
led234:A
led234:C
led235:A
led235:C
led236:A
led236:C
led237:A
led237:C
led238:A
led238:C
led239:A
led239:C
led240:A
led240:C
led241:A
led241:C
led242:A
led242:C
led243:A
led243:C
led244:A
led244:C
led245:A
led245:C
led246:A
led246:C
led247:A
led247:C
led248:A
led248:C
led249:A
led249:C
led250:A
led250:C
led251:A
led251:C
led252:A
led252:C
led253:A
led253:C
led254:A
led254:C
led255:A
led255:C