Example for the LPC4088 QSB Base Board

Dependencies:   EALib mbed

CubeDemo.cpp

Committer:
embeddedartists
Date:
2014-04-09
Revision:
3:15f457b3bdbd
Parent:
0:a771927a62fd

File content as of revision 3:15f457b3bdbd:

/******************************************************************************
 * Includes
 *****************************************************************************/

#include "mbed.h"

#include "LcdController.h"
#include "EaLcdBoard.h"
#include "CubeDemo.h"

#include "Image.h"

//#include "wchar.h"
#include <math.h>


extern const unsigned char cube_image1[];
extern int cube_image1_sz;
extern const unsigned char cube_image2[];
extern int cube_image2_sz;


/******************************************************************************
 * Typedefs and defines
 *****************************************************************************/

/******************************************************************************
 * Local variables
 *****************************************************************************/


/******************************************************************************
 * External variables
 *****************************************************************************/
extern EaLcdBoard lcdBoard;
extern bool abortTest;

/******************************************************************************
 * Local functions
 *****************************************************************************/




/* (c) 2008 by Denis Markovic
   I give hereby permission to Anders Rosvall of Embedded Artists to use this function in his ARM7 board
   demo program, as long as I'm not hold responsible for bugs in the code and I take not responsibility
   for any damage used by that code :-) */

#define TRIANG_PROJ_SFT 16

static unsigned short DivTab[] =
{0xffff, 0x7fff, 0x5554, 0x3fff, 0x3332, 0x2aa9, 0x2491,
  0x1fff, 0x1c70, 0x1998, 0x1744, 0x1554, 0x13b0, 0x1248, 0x1110,
  0x0fff, 0x0f0e, 0x0e37, 0x0d78, 0x0ccb, 0x0c2f, 0x0ba1, 0x0b20,
  0x0aa9, 0x0a3c, 0x09d7, 0x097a, 0x0923, 0x08d2, 0x0887, 0x0841,
  0x07ff, 0x07c0, 0x0786, 0x074f, 0x071b, 0x06ea, 0x06bb, 0x068f,
  0x0665, 0x063d, 0x0617, 0x05f3, 0x05d0, 0x05af, 0x058f, 0x0571,
  0x0554, 0x0538, 0x051d, 0x0504, 0x04eb, 0x04d3, 0x04bc, 0x04a6,
  0x0491, 0x047c, 0x0468, 0x0455, 0x0443, 0x0431, 0x0420, 0x040f,
  0x03ff, 0x03ef, 0x03df, 0x03d1, 0x03c2, 0x03b4, 0x03a7, 0x039a,
  0x038d, 0x0380, 0x0374, 0x0368, 0x035d, 0x0352, 0x0347, 0x033c,
  0x0332, 0x0328, 0x031e, 0x0314, 0x030b, 0x0302, 0x02f9, 0x02f0,
  0x02e7, 0x02df, 0x02d7, 0x02cf, 0x02c7, 0x02bf, 0x02b8, 0x02b0,
  0x02a9, 0x02a2, 0x029b, 0x0294, 0x028e, 0x0287, 0x0281, 0x027b,
  0x0275, 0x026f, 0x0269, 0x0263, 0x025d, 0x0258, 0x0252, 0x024d,
  0x0248, 0x0242, 0x023d, 0x0238, 0x0233, 0x022f, 0x022a, 0x0225,
  0x0221, 0x021c, 0x0218, 0x0213, 0x020f, 0x020b, 0x0207, 0x0203,
  0x01ff, 0x01fb, 0x01f7, 0x01f3, 0x01ef, 0x01eb, 0x01e8, 0x01e4,
  0x01e0, 0x01dd, 0x01d9, 0x01d6, 0x01d3, 0x01cf, 0x01cc, 0x01c9,
  0x01c6, 0x01c2, 0x01bf, 0x01bc, 0x01b9, 0x01b6, 0x01b3, 0x01b1,
  0x01ae, 0x01ab, 0x01a8, 0x01a5, 0x01a3, 0x01a0, 0x019d, 0x019b,
  0x0198, 0x0196, 0x0193, 0x0191, 0x018e, 0x018c, 0x0189, 0x0187,
  0x0185, 0x0182, 0x0180, 0x017e, 0x017c, 0x0179, 0x0177, 0x0175,
  0x0173, 0x0171, 0x016f, 0x016d, 0x016b, 0x0169, 0x0167, 0x0165,
  0x0163, 0x0161, 0x015f, 0x015d, 0x015b, 0x0159, 0x0157, 0x0156,
  0x0154, 0x0152, 0x0150, 0x014f, 0x014d, 0x014b, 0x0149, 0x0148,
  0x0146, 0x0145, 0x0143, 0x0141, 0x0140, 0x013e, 0x013d, 0x013b,
  0x013a, 0x0138, 0x0137, 0x0135, 0x0134, 0x0132, 0x0131, 0x012f,
  0x012e, 0x012d, 0x012b, 0x012a, 0x0128, 0x0127, 0x0126, 0x0124,
  0x0123, 0x0122, 0x0120, 0x011f, 0x011e, 0x011d, 0x011b, 0x011a,
  0x0119, 0x0118, 0x0117, 0x0115, 0x0114, 0x0113, 0x0112, 0x0111,
  0x0110, 0x010e, 0x010d, 0x010c, 0x010b, 0x010a, 0x0109, 0x0108,
  0x0107, 0x0106, 0x0105, 0x0104, 0x0103, 0x0102, 0x0101, 0x0100,
  0x00ff, 0x00fe, 0x00fd, 0x00fc, 0x00fb, 0x00fa, 0x00f9, 0x00f8,
  0x00f7, 0x00f6, 0x00f5, 0x00f4, 0x00f3, 0x00f2, 0x00f1, 0x00f0,
  0x00ef, 0x00ef, 0x00ee, 0x00ed, 0x00ec, 0x00eb, 0x00ea, 0x00e9,
  0x00e9, 0x00e8, 0x00e7, 0x00e6, 0x00e5, 0x00e4, 0x00e4, 0x00e3,
  0x00e2, 0x00e1, 0x00e0, 0x00e0, 0x00df, 0x00de, 0x00dd, 0x00dd,
  0x00dc, 0x00db, 0x00da, 0x00da, 0x00d9, 0x00d8, 0x00d8, 0x00d7,
  0x00d6, 0x00d5, 0x00d5, 0x00d4, 0x00d3, 0x00d3, 0x00d2, 0x00d1,
  0x00d1, 0x00d0, 0x00cf, 0x00cf, 0x00ce, 0x00cd, 0x00cd, 0x00cc,
  0x00cb, 0x00cb, 0x00ca, 0x00c9, 0x00c9, 0x00c8, 0x00c8, 0x00c7,
  0x00c6, 0x00c6, 0x00c5, 0x00c4, 0x00c4, 0x00c3, 0x00c3, 0x00c2,
  0x00c2, 0x00c1, 0x00c0, 0x00c0, 0x00bf, 0x00bf, 0x00be, 0x00be,
  0x00bd, 0x00bc, 0x00bc, 0x00bb, 0x00bb, 0x00ba, 0x00ba, 0x00b9,
  0x00b9, 0x00b8, 0x00b8, 0x00b7, 0x00b7, 0x00b6, 0x00b6, 0x00b5,
  0x00b5, 0x00b4, 0x00b4, 0x00b3, 0x00b3, 0x00b2, 0x00b2, 0x00b1,
  0x00b1, 0x00b0, 0x00b0, 0x00af, 0x00af, 0x00ae, 0x00ae, 0x00ad,
  0x00ad, 0x00ac, 0x00ac, 0x00ab, 0x00ab, 0x00ab, 0x00aa, 0x00aa,
  0x00a9, 0x00a9, 0x00a8, 0x00a8, 0x00a7, 0x00a7, 0x00a7, 0x00a6,
  0x00a6, 0x00a5, 0x00a5, 0x00a4, 0x00a4, 0x00a4, 0x00a3, 0x00a3,
  0x00a2, 0x00a2, 0x00a2, 0x00a1, 0x00a1, 0x00a0, 0x00a0, 0x00a0,
  0x009f, 0x009f, 0x009e, 0x009e, 0x009e, 0x009d, 0x009d, 0x009c,
  0x009c, 0x009c, 0x009b, 0x009b, 0x009b, 0x009a, 0x009a, 0x0099,
  0x0099, 0x0099, 0x0098, 0x0098, 0x0098, 0x0097, 0x0097, 0x0097,
  0x0096, 0x0096, 0x0096, 0x0095, 0x0095, 0x0094, 0x0094, 0x0094,
  0x0093, 0x0093, 0x0093, 0x0092, 0x0092, 0x0092, 0x0091, 0x0091,
  0x0091, 0x0090, 0x0090, 0x0090, 0x008f, 0x008f, 0x008f, 0x008f,
  0x008e, 0x008e, 0x008e, 0x008d, 0x008d, 0x008d, 0x008c, 0x008c,
  0x008c, 0x008b, 0x008b, 0x008b, 0x008b, 0x008a, 0x008a, 0x008a,
  0x0089, 0x0089, 0x0089, 0x0088, 0x0088, 0x0088, 0x0088, 0x0087,
  0x0087, 0x0087, 0x0086, 0x0086, 0x0086, 0x0086, 0x0085, 0x0085,
  0x0085, 0x0085, 0x0084, 0x0084, 0x0084, 0x0083, 0x0083, 0x0083,
  0x0083, 0x0082, 0x0082, 0x0082, 0x0082, 0x0081, 0x0081, 0x0081,
  0x0081, 0x0080, 0x0080, 0x0080, 0x0080, 0x007f, 0x007f, 0x007f,
};

/* (c) 2008 by Denis Markovic
   I give hereby permission to Anders Rosvall of Embedded Artists to use this function in his ARM7 board
   demo program, as long as I'm not hold responsible for bugs in the code and I take not responsibility
   for any damage used by that code :-) */
void CubeDemo::CpPixel16Fast(int xSrc, int ySrc, int x, int y, Surface_t *SrcRP_p, Surface_t *DstRP_p)
{
  unsigned short *src_p, *dst_p;

  src_p = (unsigned short *) SrcRP_p->pixels;
  dst_p = (unsigned short *) DstRP_p->pixels;

  dst_p[y * DstRP_p->w + x] = src_p[ySrc * SrcRP_p->w + xSrc];

  return;
}

/* (c) 2008 by Denis Markovic
   I give hereby permission to Anders Rosvall of Embedded Artists to use this function in his ARM7 board
   demo program, as long as I'm not hold responsible for bugs in the code and I take not responsibility
   for any damage used by that code :-)

   Input: SrcRP_p: pointer to type holding width and height and ptr to source pixel data
          DstRP_p: pointer to type holding width and height and ptr to destination pixel data (i.e. gfx memory to draw to)
          SrcCoords_p: pointer to array holding 3 source coordinates into triangle source accessed through SrcRP_p
          DstCoords_p: pointer to array holding 3 destination triangle coordinates in draw buffer which is accessed through DstRP_p

   Description: take triangle from source rectangular picture (raw data, 16 bit) and project it into a triangle
                in the destination picture (also 16 bit)
 */
void CubeDemo::TriangleProjectFast(Surface_t *SrcRP_p, Surface_t *DstRP_p, Coord2D_t *SrcCoords_p,  Coord2D_t *DstCoords_p)
{
  int TopCoord = 0, MiddleCoord = 1, BottomCoord = 2;
  int /*SrcStartX, SrcStartY,*/ x, y, Direction, i, j;
  long dxDstBig, dxDstSmall, dxSrcBig, dxSrcSmall, dySrcBig, dySrcSmall, DeltaY;
  int DivMultVal;

  /* 1. step: sort dst triangle points */
  if(DstCoords_p[1].y <  DstCoords_p[TopCoord].y)
  {
    TopCoord = 1;
    MiddleCoord = 0;
  }

  if(DstCoords_p[2].y <  DstCoords_p[TopCoord].y)
  {
    TopCoord = 2;
    BottomCoord = 1;
    MiddleCoord = 0;
  }

  if(DstCoords_p[BottomCoord].y < DstCoords_p[MiddleCoord].y)
  {
    int tmp;
    tmp = MiddleCoord;
    MiddleCoord = BottomCoord;
    BottomCoord = tmp;
  }

  /* so now we have the 3 sorted dst triangle points in TopCoord, MiddleCoord and BottomCoord
     (can be done much more efficient with arithmetics instead of if or use pos/neg direction
     vectors later?) */

  /* 2. step: find start and end points for this line in src and dst triangle for each
     line; start pt always on a line that originates from middle point; later replace
     all div by mult with 1/DeltaY, i.e. only one division, maybe even save 1/... in
     Tab as there are not so many possible DeltaY */
  DeltaY = (long) DstCoords_p[BottomCoord].y - DstCoords_p[TopCoord].y + 1;

  DivMultVal = ((int) DivTab[DeltaY-1] + 1);

  dxDstBig   = ((long) DstCoords_p[BottomCoord].x - DstCoords_p[TopCoord].x + 1) * DivMultVal;
  dySrcBig   = ((long) SrcCoords_p[BottomCoord].y - SrcCoords_p[TopCoord].y + 1) * DivMultVal;
  dxSrcBig   = ((long) SrcCoords_p[BottomCoord].x - SrcCoords_p[TopCoord].x + 1) * DivMultVal;

  DeltaY = (long) DstCoords_p[MiddleCoord].y - DstCoords_p[TopCoord].y + 1;

  DivMultVal = ((int) DivTab[DeltaY-1] + 1);

  dxDstSmall = ((long) DstCoords_p[MiddleCoord].x - DstCoords_p[TopCoord].x + 1) * DivMultVal;
  dySrcSmall = ((long) SrcCoords_p[MiddleCoord].y - SrcCoords_p[TopCoord].y + 1) * DivMultVal;
  dxSrcSmall = ((long) SrcCoords_p[MiddleCoord].x - SrcCoords_p[TopCoord].x + 1) * DivMultVal;

  Direction = 1;
  if(dxDstSmall > dxDstBig)
    Direction = -1;

  for(y = DstCoords_p[TopCoord].y, i=0; y <= DstCoords_p[MiddleCoord].y; y++, i++)
  { /* for each row/line */
    long MoveSrcX, MoveSrcY, P1x, P2x, P1y, P2y, SrcDeltaSteps;

    //SrcStartX = SrcCoords_p[TopCoord].x;

    P1x = SrcCoords_p[TopCoord].x + ((i * dxSrcSmall)>>TRIANG_PROJ_SFT);
    P1y = SrcCoords_p[TopCoord].y + ((i * dySrcSmall)>>TRIANG_PROJ_SFT);
    P2x = SrcCoords_p[TopCoord].x + ((i * dxSrcBig)>>TRIANG_PROJ_SFT);
    P2y = SrcCoords_p[TopCoord].y + ((i * dySrcBig)>>TRIANG_PROJ_SFT);

    {
      int xx;

      x  = DstCoords_p[TopCoord].x + ((i * dxDstSmall)>>TRIANG_PROJ_SFT);
      xx = DstCoords_p[TopCoord].x + ((i * dxDstBig)  >>TRIANG_PROJ_SFT);

      SrcDeltaSteps = xx - x;
      if(SrcDeltaSteps < 0)
    SrcDeltaSteps = -SrcDeltaSteps;

      SrcDeltaSteps++;

      DivMultVal = ((int) DivTab[SrcDeltaSteps-1] + 1);

      MoveSrcX = (P2x - P1x) * DivMultVal;
      MoveSrcY = (P2y - P1y) * DivMultVal;

      x-= Direction;

      P1x <<= TRIANG_PROJ_SFT;
      P1y <<= TRIANG_PROJ_SFT;

      do
      {
    x+= Direction;

    CpPixel16Fast(P1x >>TRIANG_PROJ_SFT, P1y >>TRIANG_PROJ_SFT, x, y, SrcRP_p, DstRP_p);

    P1x += MoveSrcX;
    P1y += MoveSrcY;

      } while(x!=xx);
    }
  }

  /* second part of triangle from middle to bottom */
  DeltaY = (long) DstCoords_p[BottomCoord].y - DstCoords_p[MiddleCoord].y+1;

  DivMultVal = ((int) DivTab[DeltaY-1] + 1);

  dxDstSmall = ((long) DstCoords_p[BottomCoord].x - DstCoords_p[MiddleCoord].x + 1) * DivMultVal;
  dySrcSmall = ((long) SrcCoords_p[BottomCoord].y - SrcCoords_p[MiddleCoord].y + 1) * DivMultVal;
  dxSrcSmall = ((long) SrcCoords_p[BottomCoord].x - SrcCoords_p[MiddleCoord].x + 1) * DivMultVal;

  y--;
  i--;

  for(j=0; y <= DstCoords_p[BottomCoord].y; y++, i++, j++)
  { /* for each row/line */
    long MoveSrcX, MoveSrcY, P1x, P2x, P1y, P2y, SrcDeltaSteps;

    //SrcStartX = SrcCoords_p[MiddleCoord].x;

    P1x = SrcCoords_p[MiddleCoord].x + ((j * dxSrcSmall)>>TRIANG_PROJ_SFT);
    P1y = SrcCoords_p[MiddleCoord].y + ((j * dySrcSmall)>>TRIANG_PROJ_SFT);
    P2x = SrcCoords_p[TopCoord].x + ((i * dxSrcBig)>>TRIANG_PROJ_SFT);
    P2y = SrcCoords_p[TopCoord].y + ((i * dySrcBig)>>TRIANG_PROJ_SFT);

    {
      int xx;

      x  = DstCoords_p[MiddleCoord].x + ((j * dxDstSmall)>>TRIANG_PROJ_SFT);
      xx = DstCoords_p[TopCoord].x    + ((i * dxDstBig)  >>TRIANG_PROJ_SFT);

      SrcDeltaSteps = xx - x;

      /* todo, fixme: direction should not have to be set here but if we do not
         do it here, sometimes calc fails, investigate (problem case: dst coords
         250/299, 321/302, 472/308 and src coord 0/0, bike w-1, 0, bike w-1/bike h-1 */
      if(SrcDeltaSteps < 0)
      {
    SrcDeltaSteps = -SrcDeltaSteps;
    Direction = -1;
      }
      else
    Direction = 1;

      SrcDeltaSteps++;

      DivMultVal = ((int) DivTab[SrcDeltaSteps-1] + 1);

      MoveSrcX = (P2x - P1x) * DivMultVal;
      MoveSrcY = (P2y - P1y) * DivMultVal;

      x-= Direction;

      P1x <<= TRIANG_PROJ_SFT;
      P1y <<= TRIANG_PROJ_SFT;

      do
      {
    x+= Direction;

    CpPixel16Fast(P1x >>TRIANG_PROJ_SFT, P1y >>TRIANG_PROJ_SFT, x, y, SrcRP_p, DstRP_p);

    P1x += MoveSrcX;
    P1y += MoveSrcY;

      } while(x!=xx);
    }
  }

  return;
}


short CubeDemo::_sin(short y) const {
    static short s1 = 0x6487;
    static short s3 = 0x2951;
    static short s5 = 0x4f6;
    long z, prod, sum;

    z = ((long)y * y) >> 12;
    prod = (z * s5) >> 16;
    sum = s3 - prod;
    prod = (z * sum) >> 16;
    sum = s1 - prod;

    // for better accuracy, round here
    return (short)((y * sum) >> 13);
 }

short CubeDemo::_cos(short y) const {
    static short c0 = 0x7fff;
    static short c2 = 0x4eea;
    static short c4 = 0x0fc4;
    long z, prod, sum;
    z = ((long)y * y) >> 12;
    prod = (z * c4) >> 16;
    sum = c2 - prod;

    // for better accuracy, round here
    prod = (z * sum) >> 15;
    return (short)(c0 - prod);
}

short CubeDemo::isine(short x) const {
    unsigned short n = (((unsigned short)x + 0x2000) >> 14) & 0x3;
    x -= n * 0x4000;
    switch(n){
        case 0:
            return _sin(x);
        case 1:
            return _cos(x);
        case 2:
            return - _sin(x);
        case 3:
            return  - _cos(x);
    }
    return 0;
 }


short CubeDemo::icosine(short x) const {
    return isine(x + 0x4000);
 }

int32_t CubeDemo::sgn(int32_t val) const
{
  if (val > 0) return 1;
  else if (val < 0) return -1;
  else return 0;
}

void CubeDemo::createCubeModel(uint32_t radius)
{
  uint32_t i,j;
  uint32_t theta, dTheta;
  static uint8_t cubeConnect[24] = {
    0, 1, 2, 3,
    1, 5, 6, 2,
    5, 4, 7, 6,
    4, 0, 3, 7,
    4, 5, 1, 0,
    3, 2, 6, 7};

  theta  = 0x2000; //PI/4
  dTheta = 0x4000; //PI/2

  for(i=0; i<8; i++)
  {
    cubeModel[i].x = radius * sgn(icosine(theta));
    cubeModel[i].y = radius * sgn(isine(theta));
    cubeModel[i].z = radius - (2 * radius) * (i / 4);
    theta += dTheta;
  }

  j=0;
  for(i=0; i<6; i++)
  {
    cubePoly[j].p1 = cubeConnect[i*4 + 3];
    cubePoly[j].p2 = cubeConnect[i*4 + 1];
    cubePoly[j].p3 = cubeConnect[i*4 + 0];
    j++;
    cubePoly[j].p1 = cubeConnect[i*4 + 3];
    cubePoly[j].p2 = cubeConnect[i*4 + 2];
    cubePoly[j].p3 = cubeConnect[i*4 + 1];
    j++;
  }
}

void CubeDemo::rotateAndProject(uint16_t rotX, uint16_t rotY, uint16_t rotZ)
{
  uint32_t i;
  long crx,srx,cry,sry,crz,srz;
  long x,y,z,tx,ty,tz;
  long distance;

  crx = icosine(rotX);
  srx = isine(rotX);
  cry = icosine(rotY);
  sry = isine(rotY);
  crz = icosine(rotZ);
  srz = isine(rotZ);
  
  for (i=0;i<8;i++)
  {
        //--> rotate around y-axis              
//      var tempX = (this.x * Math.cos(rY)) - (this.z * Math.sin(rY));
//      var tempZ = (this.x * Math.sin(rY)) + (this.z * Math.cos(rY));

        //--> rotate around x-axis      
//      this.dz  =  (tempZ * Math.cos(rX)) - (this.y * Math.sin(rX));
//      var tempY =  (tempZ * Math.sin(rX)) + (this.y * Math.cos(rX));

        //--> rotate around z-axis
//      this.dx =  (tempX * Math.cos(rZ)) + (tempY * Math.sin(rZ));
//      this.dy =  (tempY * Math.cos(rZ)) - (tempX * Math.sin(rZ));
        

    x = cubeModel[i].x;
    y = cubeModel[i].y;
    z = cubeModel[i].z;
    
        //--> rotate around y-axis
    tx = (z*sry + x*cry) / 0x7fff;
    tz = (z*cry - x*sry) / 0x7fff;

        //--> rotate around x-axis
    cubeModel[i].zr = (y*srx + tz*crx) / 0x7fff;
    ty              = (y*crx - tz*srx) / 0x7fff;

        //--> rotate around z-axis
    cubeModel[i].xr = (tx*crz - ty*srz) / 0x7fff;
    cubeModel[i].yr = (tx*srz + ty*crz) / 0x7fff;

    cubeModel[i].xr -= camX;
    cubeModel[i].yr -= camY;
    cubeModel[i].zr -= camZ;

    distance = LENS - cubeModel[i].zr;
    if (distance > 0)
    {
      cubeModel[i].scrx = X_OFFSET + (LENS * cubeModel[i].xr) / distance;
      cubeModel[i].scry = Y_OFFSET + (LENS * cubeModel[i].yr) / distance;
    }
  }
}

void CubeDemo::drawCubeZ(Surface_t *pSourcePicture, uint8_t shades)
{
  uint32_t i;
  int32_t  x1,x2,x3,y1,y2,y3,/*u1,u2,u3,v1,v2,v3,*/znormal;
  
  activeFrame.w = this->windowX;
  activeFrame.h = this->windowY;
  activeFrame.pixels = (uint16_t*)this->pFrmBuf;

  for(i=0; i<12; i++)
  {
    x1 = cubeModel[cubePoly[i].p1].scrx;  //Get triangles from "projected"
    x2 = cubeModel[cubePoly[i].p2].scrx;  //X and Y coords since Znormal
    x3 = cubeModel[cubePoly[i].p3].scrx;  //Does not require a Z coord
    y1 = cubeModel[cubePoly[i].p1].scry;  //V1= Point1 connected to V2 then
    y2 = cubeModel[cubePoly[i].p2].scry;  //V2 to V3 and so on...
    y3 = cubeModel[cubePoly[i].p3].scry;

    znormal = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3);
    if (znormal > 0)
    {
      //no texture?
      if (pSourcePicture == NULL)
      {
        if (shades == 0)
        {
          if ((cubePoly[i].p1 == 0) && (cubePoly[i].p2 == 1))
            graphics.put_line( cubeModel[cubePoly[i].p1].scrx, cubeModel[cubePoly[i].p1].scry, cubeModel[cubePoly[i].p2].scrx, cubeModel[cubePoly[i].p2].scry, RED);
          else
            graphics.put_line( cubeModel[cubePoly[i].p1].scrx, cubeModel[cubePoly[i].p1].scry, cubeModel[cubePoly[i].p2].scrx, cubeModel[cubePoly[i].p2].scry, SMALL_CIRCLE_FRONT_COLOR);
          graphics.put_line( cubeModel[cubePoly[i].p2].scrx, cubeModel[cubePoly[i].p2].scry, cubeModel[cubePoly[i].p3].scrx, cubeModel[cubePoly[i].p3].scry, SMALL_CIRCLE_FRONT_COLOR);
          graphics.put_line( cubeModel[cubePoly[i].p3].scrx, cubeModel[cubePoly[i].p3].scry, cubeModel[cubePoly[i].p1].scrx, cubeModel[cubePoly[i].p1].scry, SMALL_CIRCLE_FRONT_COLOR);
        }
        else
        {
          Coord2D_t SrcCoords[3], DstCoords[3];
          Surface_t a;
          static uint16_t pix;

          a.w = this->windowX;
          a.h = this->windowY;
          a.pixels = &pix;
          if ((i&1) == 0)
          {
            if ((znormal / 400) > 31)
              pix = 0x1f << 11;
            else
              pix = (znormal / 400 & 0x1f) << 11;
          }
          SrcCoords[0].x = 0;
          SrcCoords[0].y = 0;
          SrcCoords[1].x = 0;
          SrcCoords[1].y = 0;
          SrcCoords[2].x = 0;
          SrcCoords[2].y = 0;
          DstCoords[0].x = cubeModel[cubePoly[i].p1].scrx;
          DstCoords[0].y = cubeModel[cubePoly[i].p1].scry;
          DstCoords[1].x = cubeModel[cubePoly[i].p2].scrx;
          DstCoords[1].y = cubeModel[cubePoly[i].p2].scry;
          DstCoords[2].x = cubeModel[cubePoly[i].p3].scrx;
          DstCoords[2].y = cubeModel[cubePoly[i].p3].scry;
          TriangleProjectFast(&a, &activeFrame, SrcCoords, DstCoords);
        }
      }
      
      //Render with texture
      else
      {
        Coord2D_t SrcCoords[3], DstCoords[3];
#if 1
        /*
         *       Image in the file
         *  0,0_______ _______ _______
         *    |       |       |      *|                   
         *    |       |       |       |                   Image as it is used
         *    |_______|_______|_______|                 _______ _______ _______ _______
         *    |       |       |       |        \       |*      |       |       |       |
         *    |       |       |       |         \      |       | top   |       |       |
         *    |_______|_______|_______|    ======      |_______|_______|_______|_______|
         *    |       |       |       |         /      |       |       |       |       |
         *    |       |       |       |        /       | side1 | side2 | side3 | side4 |
         *    |_______|_______|_______|                |_______|_______|_______|_______|
         *    |       |       |       |                |       |       |       |       |
         *    |       |       |       |                |       | bottom|       |       |
         *    |_______|_______|_______|                |_______|_______|_______|_______|
         *                           150,200
         *  All coordinates below are in the left image above and with coordinates 0,0 in the
         *  upper left corner and 150,200 in the lower right corner.
         *
         */
#define XYZ  {49,0},{0,0},{0,50},{50,50}
        static Coord2D_t a[24] = {{49,50}, {0,50},  {0,99},  {49,99},            //bottom  6
                                  {99,50}, {50,50}, {50,99}, {99,99},            //side2   2
                                  {149,50},{100,50},{100,99},{149,99},           //top     5
                                  {50,150},{99,150},{99,199},{50,199},           //side4   4
                                  {99,49}, {99,0},  {50,0},  {50,49},            //side1   1
                                  {99,100},{99,149},{50,149},{50,100}};          //side3   3
#elif 0
        static Coord2D_t a[24] = {{49,50}, {0,50},  {0,99},  {49,99},            //bottom  6
                                  {99,50}, {50,50}, {50,99}, {99,99},            //side2   2
                                  {149,50},{100,50},{100,99},{149,99},           //top     5
                                  {99,150},{50,150},{50,199},{99,199},           //side4   4
                                  {99,49}, {99,0},  {50,0},  {50,49},            //side1   1
                                  {99,149},{99,100},{50,100},{50,149}};          //side3   3
#else                                  
        static Coord2D_t a[24] = {{49,50}, {0,50},  {0,99},  {49,99},
                                  {99,50}, {50,50}, {50,99}, {99,99},
                                  {149,50},{100,50},{100,99},{149,99},
                                  {99,199},{50,199},{50,150},{99,150},
                                  {50,0},  {99,0},  {99,49}, {50,49},  //top
                                  {50,100},{99,100},{99,149},{50,149}};//bottom
#endif                                  

        if (i&1)
        {
          SrcCoords[0].x = a[(i/2)*4+2].x;
          SrcCoords[0].y = a[(i/2)*4+2].y;
          SrcCoords[1].x = a[(i/2)*4+3].x;
          SrcCoords[1].y = a[(i/2)*4+3].y;
          SrcCoords[2].x = a[(i/2)*4+0].x;
          SrcCoords[2].y = a[(i/2)*4+0].y;
          DstCoords[0].x = cubeModel[cubePoly[i].p1].scrx;
          DstCoords[0].y = cubeModel[cubePoly[i].p1].scry;
          DstCoords[1].x = cubeModel[cubePoly[i].p2].scrx;
          DstCoords[1].y = cubeModel[cubePoly[i].p2].scry;
          DstCoords[2].x = cubeModel[cubePoly[i].p3].scrx;
          DstCoords[2].y = cubeModel[cubePoly[i].p3].scry;
          TriangleProjectFast(pSourcePicture, &activeFrame, SrcCoords, DstCoords);
        }
        else
        {
          SrcCoords[0].x = a[(i/2)*4+0].x; //0
          SrcCoords[0].y = a[(i/2)*4+0].y; //0
          SrcCoords[1].x = a[(i/2)*4+1].x; //31;
          SrcCoords[1].y = a[(i/2)*4+1].y; //0;
          SrcCoords[2].x = a[(i/2)*4+2].x; //31;
          SrcCoords[2].y = a[(i/2)*4+2].y; //31;
          DstCoords[0].x = cubeModel[cubePoly[i].p2].scrx;
          DstCoords[0].y = cubeModel[cubePoly[i].p2].scry;
          DstCoords[1].x = cubeModel[cubePoly[i].p3].scrx;
          DstCoords[1].y = cubeModel[cubePoly[i].p3].scry;
          DstCoords[2].x = cubeModel[cubePoly[i].p1].scrx;
          DstCoords[2].y = cubeModel[cubePoly[i].p1].scry;
          TriangleProjectFast(pSourcePicture, &activeFrame, SrcCoords, DstCoords);
        }
      }
    }
  }
}

void CubeDemo::render(uint32_t idx)
{
 static uint8_t cnt=0;

  if (cnt == 0)
  {
    cnt = 1;
    pFrmBuf = pFrmBuf1;
  }
  else if (cnt == 1)
  {
    cnt = 2;
    pFrmBuf = pFrmBuf2;
  }
  else
  {
    cnt = 0;
    pFrmBuf = pFrmBuf3;
  }
  
  graphics.setFrameBuffer(pFrmBuf);

  // rendering here
  memset((void*)(pFrmBuf), BACKGROUND_COLOR, this->windowX * this->windowY * 2);

  rotateAndProject(rx, ry, 0);

  switch(mode)
  {
  case 0: //draw just points
    graphics.put_circle( cubeModel[0].scrx, cubeModel[0].scry, RED,                      2, 1);
    graphics.put_circle( cubeModel[1].scrx, cubeModel[1].scry, SMALL_CIRCLE_FRONT_COLOR, 2, 1);
    graphics.put_circle( cubeModel[2].scrx, cubeModel[2].scry, GREEN,                    2, 1);
    graphics.put_circle( cubeModel[3].scrx, cubeModel[3].scry, SMALL_CIRCLE_FRONT_COLOR, 2, 1);
    graphics.put_circle( cubeModel[4].scrx, cubeModel[4].scry, SMALL_CIRCLE_FRONT_COLOR, 2, 1);
    graphics.put_circle( cubeModel[5].scrx, cubeModel[5].scry, SMALL_CIRCLE_FRONT_COLOR, 2, 1);
    graphics.put_circle( cubeModel[6].scrx, cubeModel[6].scry, SMALL_CIRCLE_FRONT_COLOR, 2, 1);
    graphics.put_circle( cubeModel[7].scrx, cubeModel[7].scry, SMALL_CIRCLE_FRONT_COLOR, 2, 1);
    break;
  case 1: //draw lines points
    graphics.put_line( cubeModel[0].scrx, cubeModel[0].scry, cubeModel[1].scrx, cubeModel[1].scry, RED);
    graphics.put_line( cubeModel[1].scrx, cubeModel[1].scry, cubeModel[2].scrx, cubeModel[2].scry, SMALL_CIRCLE_FRONT_COLOR);
    graphics.put_line( cubeModel[2].scrx, cubeModel[2].scry, cubeModel[3].scrx, cubeModel[3].scry, GREEN);
    graphics.put_line( cubeModel[3].scrx, cubeModel[3].scry, cubeModel[0].scrx, cubeModel[0].scry, SMALL_CIRCLE_FRONT_COLOR);

    graphics.put_line( cubeModel[5].scrx, cubeModel[5].scry, cubeModel[4].scrx, cubeModel[4].scry, SMALL_CIRCLE_FRONT_COLOR);
    graphics.put_line( cubeModel[4].scrx, cubeModel[4].scry, cubeModel[7].scrx, cubeModel[7].scry, SMALL_CIRCLE_FRONT_COLOR);
    graphics.put_line( cubeModel[7].scrx, cubeModel[7].scry, cubeModel[6].scrx, cubeModel[6].scry, SMALL_CIRCLE_FRONT_COLOR);
    graphics.put_line( cubeModel[6].scrx, cubeModel[6].scry, cubeModel[5].scrx, cubeModel[5].scry, SMALL_CIRCLE_FRONT_COLOR);

    graphics.put_line( cubeModel[0].scrx, cubeModel[0].scry, cubeModel[4].scrx, cubeModel[4].scry, SMALL_CIRCLE_FRONT_COLOR);
    graphics.put_line( cubeModel[1].scrx, cubeModel[1].scry, cubeModel[5].scrx, cubeModel[5].scry, SMALL_CIRCLE_FRONT_COLOR);
    graphics.put_line( cubeModel[2].scrx, cubeModel[2].scry, cubeModel[6].scrx, cubeModel[6].scry, SMALL_CIRCLE_FRONT_COLOR);
    graphics.put_line( cubeModel[3].scrx, cubeModel[3].scry, cubeModel[7].scrx, cubeModel[7].scry, SMALL_CIRCLE_FRONT_COLOR);
    break;
  case 2: //draw cube with texture
    if (sourcePicture1.pixels == NULL)
    {
      drawCubeZ( NULL, false);
    }
    else
    {
      drawCubeZ( &sourcePicture1, false);
    }
    break;
  case 3: //draw cube with texture
    drawCubeZ( NULL, true);
    break;
  case 4: //draw cube with texture
    if (sourcePicture2.pixels == NULL)
    {
      drawCubeZ( NULL, false);
    }
    else
    {
      drawCubeZ( &sourcePicture2, false);
    }
    break;
  case 5: //draw sorted lines
    drawCubeZ( NULL, false);
    break;
  default:
    mode = 0;
    break;
  }
  ry += ry_;
  rx += rx_;
}

/***********************************************************************
 * Private functions
 **********************************************************************/

void CubeDemo::initialize()
{
    mode = 3;
    rx   = 0x9000;
    ry   = 0;
    ry_  = 350;
    rx_  = -25; //-3
    camX = 0;
    camY = 0;
    camZ = 128;

    createCubeModel(70);

    Image::ImageData_t d;
    if (Image::decode(cube_image1, cube_image1_sz, &d) == 0) {
        sourcePicture1.w = d.width;
        sourcePicture1.h = d.height;
        sourcePicture1.pixels = d.pixels;
    }
    if (Image::decode(cube_image2, cube_image2_sz, &d) == 0) {
        sourcePicture2.w = d.width;
        sourcePicture2.h = d.height;
        sourcePicture2.pixels = d.pixels;
    }
}


/******************************************************************************
 * Public functions
 *****************************************************************************/
CubeDemo::CubeDemo(uint8_t *pFrameBuf, uint16_t dispWidth, uint16_t dispHeight) 
    : graphics((uint16_t *)pFrameBuf, dispWidth, dispHeight) {

    this->windowX = dispWidth;
    this->windowY = dispHeight;
    this->pFrmBuf  = (uint16_t *)pFrameBuf;
    this->pFrmBuf1 = (uint16_t *)pFrameBuf;
    this->pFrmBuf2 = (uint16_t *)((uint32_t)pFrameBuf + dispWidth*dispHeight*2);
    this->pFrmBuf3 = (uint16_t *)((uint32_t)pFrameBuf + dispWidth*dispHeight*4);

    sourcePicture1.w = 0;
    sourcePicture1.h = 0;
    sourcePicture1.pixels = NULL;
    sourcePicture2.w = 0;
    sourcePicture2.h = 0;
    sourcePicture2.pixels = NULL;
        
    initialize();
}

CubeDemo::~CubeDemo()
{
  if (sourcePicture1.pixels != NULL) {
    free(sourcePicture1.pixels);
  }
  if (sourcePicture2.pixels != NULL) {
    free(sourcePicture2.pixels);
  }
}
void CubeDemo::run(uint32_t loops, uint32_t delayMs) {

  printf("CubeDemo, %d loops, %dms delay\n", loops, delayMs);
  
    for(int32_t n=0;n<loops;n++) {
    
        mode = ((n/128) % 5);
        //mode = 4;
    
        //render globe
        render(n);
    
        //update framebuffer
        lcdBoard.setFrameBuffer((uint32_t)this->pFrmBuf);

        if (abortTest) {
            break;
        }      
      
        if (mode == 3)
            wait_ms(delayMs-7);
        else
            wait_ms(delayMs);
    }
}