Graphical demo for the LPC4088 Experiment Base Board with one of the Display Expansion Kits. This demo shows a rotating 3D cube with and without textures.

Dependencies:   EALib mbed

Revision:
0:c828045bbe69
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CubeDemo.cpp	Fri Oct 03 12:48:37 2014 +0000
@@ -0,0 +1,797 @@
+/******************************************************************************
+ * 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
+ *****************************************************************************/
+
+
+/******************************************************************************
+ * 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(EaLcdBoardGPIO& lcdBoard, 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 (mode == 3)
+            wait_ms(delayMs-7);
+        else
+            wait_ms(delayMs);
+    }
+}
+