// ############################################
// 
// 4x4x4 LED Cube project
// By Christian Moen 2008
// chr@syntaks.org
// Lisence: GPL
//
// Versión para microcontroladores PIC
// por Gerardo Cibeira 2008
// gcibeira@gmail.com
//
// ############################################
void setpixel(int x, int y, int z);
void clrpixel(int x, int y, int z);
unsigned char getpixel(int x, int y, int z);
unsigned char inrange(int x, int y, int z);
void negpixel(int x, int y, int z);
void alterpixel(int x, int y, int z, int state);
void setplane_z(int z);
void clrplane_z(int z);
void setplane_x(int x);
void clrplane_x(int x);
void setplane_y(int y);
void clrplane_y(int y);
void setplane(unsigned char plane, int i, int state);
void setline_z(int x, int y, int z1, int z2);
void setline_x(int z, int y, int x1, int x2);
void setline_y(int z, int x, int y1, int y2);
void clrline_z(int x, int y, int z1, int z2);
void clrline_x(int z, int y, int x1, int x2);
void clrline_y(int z, int x, int y1, int y2);
void drawline_plane(int x2, int y2, int x1, int y1,unsigned char anchor);
void fill (unsigned char pattern);
void rotcube(char axis, char direccion);
void tmp2cube(void);
void cube2tmp(void);


// activa un pixel
void setpixel(int x, int y, int z)
{ 
   if(inrange(x,y,z))
      cube[z][y] |= (0x01 << x);
}

// borra un pixel
void clrpixel(int x, int y, int z)
{
   if(inrange(x,y,z))
      cube[z][y] &= ~(0x01 << x);
}

// obtiene el estado de un pixel
unsigned char getpixel(int x, int y, int z)
{
   if(inrange(x,y,z))
      if(cube[z][y] & (1 << x))
         return 0x01;
      else
         return 0x00;
}

// para saber si estamos dibujando dentro del cubo
unsigned char inrange(int x, int y, int z)
{
   if (x >= 0 && x < 3 && y >= 0 && y < 3 && z >= 0 && z < 3)
      return 0x01;
   else
      // One of the coordinates was outside the cube.
      return 0x00;
}

// activa o desactiva un pixel, segun 'state'
void alterpixel(int x, int y, int z, int state)
{
   if(state)
      setpixel(x,y,z);
   else
      clrpixel(x,y,z);
}

// invierte el estado de un pixel
void negpixel(int x, int y, int z)
{
   if (inrange(x,y,z))
      cube[z][y] ^= (1 << x);
}

// dibuja un plano en el eje z
void setplane_z(int z)
{
   int i;
   // Loop the 4 rows on the given level and write 1 to the bits.
   for (i=0;i<3;i++)
      cube[z][i]=0x07;
}

// borra un plano en el eje z
void clrplane_z(int z)
{
   int i;
   for (i=0;i<3;i++)
      cube[z][i]=0x00;
}

// dibuja un plano en el eje x
void setplane_x(int x)
{
   int z,y;
   for (z=0;z<3;z++)
      for (y=0;y<3;y++)
         cube[z][y] |= (0x01 << x);
}

// borra un plano en el eje x
void clrplane_x(int x)
{
   int z,y;
   for(z=0;z<3;z++)
      for(y=0;y<3;y++)
         cube[z][y] &= ~(0x01 << x);
}

// dibuja un plano en el eje y
void setplane_y(int y)
{
   int i;
   for(i=0;i<3;i++)
      cube[i][y] = 0x07; 
}

// borra un plano en el eje y
void clrplane_y(int y)
{
   int i;
   for(i=0;i<3;i++)
      cube[i][y] = 0x00; 
}

// dibuja un plano usando las funciones de arriba
void setplane(unsigned char plane, int i, int state)
{
   if(plane == 'x')
      if(state > 0)
         setplane_x(i);
      else
         clrplane_x(i);
   
   if(plane == 'y')
      if (state > 0)
         setplane_y(i);
      else
         clrplane_y(i);
   
   if(plane == 'z')
      if (state > 0)
         setplane_z(i);
      else
         clrplane_z(i);
}


// dibuja o borra una linea a lo largo del eje z
void line_z(int x, int y, int state)
{
   int i;
   for (i=0;i<3;i++)
      alterpixel(x,y,i,state);
}

// dibuja o borra una linea a lo largo del eje x
void line_x(int z, int y, int state)
{
   int i;
   for (i=0;i<3;i++)
      alterpixel(i,y,z,state);
}

// dibuja o borra una linea a lo largo del eje y
void line_y(int z, int x, int state)
{
   int i;
   for (i=0;i<3;i++)
         alterpixel(x,i,z,state);
}

// copia el buffer temporal al cubo
void tmp2cube(void)
{
   int y, z;
   for (z=0;z<3;z++)
      for (y=0;y<3;y++)
         cube[z][y] = tmpcube[z][y];
}

// copia el cubo al buffer temporal
void cube2tmp(void)
{
   int y, z;
   for (z=0;z<3;z++)
      for (y=0;y<3;y++)
         tmpcube[z][y] = cube[z][y];
}

// llena el cubo con el patron dado
void fill(unsigned char pattern)
{
   int z,y;
   for (z=0;z<3;z++)
      for (y=0;y<3;y++)
         cube[z][y] = pattern;
}

// rota el cubo alrededor del eje y
// todavia le falta...
void rotcube_y(void)
{
   tmpcube[0][1]=cube[0][0];
   tmpcube[0][2]=cube[0][1];
   tmpcube[1][2]=cube[0][2];
   tmpcube[2][2]=cube[1][2];
   tmpcube[2][1]=cube[2][2];
   tmpcube[2][0]=cube[2][1];
   tmpcube[1][0]=cube[2][0];
   tmpcube[0][0]=cube[1][0];
   tmp2cube();
}
