Demo code for basic 3D graphics on the MBED application shield's LCD (K64F). Left pot changes Z depth, joystick rotates one of the cubes.

Dependencies:   C12832 FXOS8700CQ gfx3d mbed

Revision:
2:297b43e931d0
Parent:
1:3810f9d9c775
Child:
3:23a93f2f8cac
--- a/main.cpp	Sun Nov 01 23:10:01 2015 +0000
+++ b/main.cpp	Sat Nov 28 01:42:18 2015 +0000
@@ -8,8 +8,9 @@
 #include "FXOS8700CQ.h"
 
 #include "gfx3d.h"
+#include "g3d_textures.h"
 
-#define BENCHMARK
+// #define BENCHMARK
 
 /* some global objects */
 Serial host (USBTX, USBRX);
@@ -18,72 +19,79 @@
 
 FXOS8700CQ fxos (PTE25, PTE24, FXOS8700CQ_SLAVE_ADDR1);     /* On-board accelerometer: SDA, SCL, (addr << 1) */
 
-InterruptIn fxos_int1 (PTC6);                               /* unused, common with SW2 on FRDM-K64F */
+InterruptIn sw2_int (PTC6);                                 /* SW2 (also unused interrupt for FXOS8700CQ) */
 InterruptIn fxos_int2 (PTC13);                              /* should just be the Data-Ready interrupt */
 InterruptIn sw3_int (PTA4);                                 /* switch SW3 */
 
-SRAWDATA fxos_acc;                                          /* collected accelerometer data */
-SRAWDATA fxos_mag;                                          /* collected magnetometer data */
+InterruptIn joy_up (PTB10);
+InterruptIn joy_down (PTB11);
+InterruptIn joy_left (PTC11);
+InterruptIn joy_right (PTC10);
+InterruptIn joy_fire (PTB23);
 
+#define FRAME_RATE_FPS      (40)                            /* how fast we want it to go */
+#define FRAME_RATE_US       (1000000 / FRAME_RATE_FPS)
 Ticker frametimer;                                          /* timer that will be used to update frames and whatnot */
 
+AnalogIn shld_pot1 (A0);
+AnalogIn shld_pot2 (A1);
+
+
 #ifdef BENCHMARK
 Timer perftimer;
 #endif
 
 #define PFLAG_TIMER         (0x01)                          /* next frame please */
 #define PFLAG_FXOS          (0x02)                          /* accel/magno data ready */
+#define PFLAG_JOY           (0x04)                          /* joystick activity */
+
+#define JOY_NONE            (0x00)
+#define JOY_UP              (0x01)
+#define JOY_DOWN            (0x02)
+#define JOY_LEFT            (0x04)
+#define JOY_RIGHT           (0x08)
+#define JOY_FIRE            (0x10)
+
+#define JOY_ANGLE_ADVANCE   (2)                             /* how many 8-bit-degrees */
 
 static volatile uint8_t pflags = 0x00;                      /* program flags */
-
-
+static volatile uint8_t joybits = 0x00;                     /* joystick bits */
 
-/*
- *  unused (?) -- also SW2 on the board
- */
-void trigger_fxos_int1 (void)
-{
-    return;
-}
+#define TXBUF_WIDTH         (256)
+static uint8_t ltxbuf[TXBUF_WIDTH * 4];                     /* a 256x32 buffer that holds 8 32x32 textures, organised as 4-byte strips L-to-R */
 
 
 /*
- *  read-ready interrupt for FXOS8700CQ
- */
-void trigger_fxos_int2 (void)
-{
-    pflags |= PFLAG_FXOS;
-    return;
-}
-
-
-/*
- *  interrupt handler for SW3 on the board
+ *  assorted interrupt handlers, mostly just setting/clearing bits.
+ *  FXOS read-ready interrupt, button triggers (pulled high but not SW2 on my board).
+ *  Interrupt handler for frame-timeout (bang out frame, compute next).
+ *  Interrupt handlers for joystick up/down/etc. (pulled to ground).
+ *  Crushed up because MBED's editor doesn't fold yet.
  */
-void trigger_sw3_int (void)
-{
-    return;
-}
-
+static void trigger_fxos_int2 (void)        { pflags |= PFLAG_FXOS; }
+static void trigger_sw2_int (void)          { return; }
+static void trigger_sw3_int (void)          { return; }
+static void trigger_frametimer (void)       { pflags |= PFLAG_TIMER; }
+static void trigger_joy_up_rise (void)      { joybits |= JOY_UP;    pflags |= PFLAG_JOY; }
+static void trigger_joy_up_fall (void)      { joybits &= ~JOY_UP;   pflags |= PFLAG_JOY; }
+static void trigger_joy_down_rise (void)    { joybits |= JOY_DOWN;  pflags |= PFLAG_JOY; }
+static void trigger_joy_down_fall (void)    { joybits &= ~JOY_DOWN; pflags |= PFLAG_JOY; }
+static void trigger_joy_left_rise (void)    { joybits |= JOY_LEFT;  pflags |= PFLAG_JOY; }
+static void trigger_joy_left_fall (void)    { joybits &= ~JOY_LEFT; pflags |= PFLAG_JOY; }
+static void trigger_joy_right_rise (void)   { joybits |= JOY_RIGHT; pflags |= PFLAG_JOY; }
+static void trigger_joy_right_fall (void)   { joybits &= ~JOY_RIGHT;pflags |= PFLAG_JOY; }
+static void trigger_joy_fire_rise (void)    { joybits |= JOY_FIRE;  pflags |= PFLAG_JOY; }
+static void trigger_joy_fire_fall (void)    { joybits &= ~JOY_FIRE; pflags |= PFLAG_JOY; }
 
-/*
- *  interrupt handler for the frametimer Ticker object
- */
-void trigger_frametimer (void)
-{
-    pflags |= PFLAG_TIMER;
-    return;
-}
 
 
 /*
  *  dumps the global accelerometer/magnetomer reading to the serial-port "host"
  */
-void print_reading (void)
+void print_reading (FXOSData_t *p)
 {
     host.printf ("A X:%5d Y:%5d Z:%5d   M X:%5d Y:%5d Z:%5d\r\n",
-            fxos_acc.x, fxos_acc.y, fxos_acc.z,
-            fxos_mag.x, fxos_mag.y, fxos_mag.z);
+            p->s.acc_x, p->s.acc_y, p->s.acc_z, p->s.mag_x, p->s.mag_y, p->s.mag_z);
 }
 
 
@@ -95,8 +103,15 @@
 {
     angle_t a;
 #ifdef BENCHMARK
-    int bt_start, bt_now, bt_trans = 0, bt_render = 0;
+    int bt_start, bt_now, bt_update = 0, bt_trans = 0, bt_render = 0;
 #endif
+    angle_t x_rot = 0;
+    angle_t y_rot = 0;
+    FXOSData_t fxos_data;
+    uint8_t ljoybits = 0x00;            /* local joystick bits (JOY_...) */
+    static const uint8_t *std_cube_txmap[6] = {g3d_texture_face, g3d_texture_hlife, g3d_texture_ccube, g3d_texture_face, g3d_texture_hlife, g3d_texture_ccube};
+    
+    uint16_t pot1val, pot2val;
     
     /* initialise */
     host.baud (38400);
@@ -108,16 +123,38 @@
     fxos_int2.fall (trigger_fxos_int2);    /* level triggered interrupt */
     fxos.enable();                          /* enable device */
 
-    /* Interrupt for SW3 button-down state */
-    sw3_int.mode (PullUp);                  /* Since the FRDM-K64F doesn't have its SW2/SW3 pull-ups populated */
+    /* Interrupt for SW2/SW3 button-down state */
+    sw2_int.mode (PullUp);
+    sw2_int.fall (trigger_sw2_int);
+    
     sw3_int.fall (trigger_sw3_int);
 
+    /* sort out joystick interrupts */
+    joy_up.rise (trigger_joy_up_rise);
+    joy_up.fall (trigger_joy_up_fall);
+    joy_down.rise (trigger_joy_down_rise);
+    joy_down.fall (trigger_joy_down_fall);
+    joy_left.rise (trigger_joy_left_rise);
+    joy_left.fall (trigger_joy_left_fall);
+    joy_right.rise (trigger_joy_right_rise);
+    joy_right.fall (trigger_joy_right_fall);
+    joy_fire.rise (trigger_joy_fire_rise);
+    joy_fire.fall (trigger_joy_fire_fall);
+
+    /* read the two potentiometers */
+    pot1val = shld_pot1.read_u16 ();
+    pot2val = shld_pot2.read_u16 ();
+
+    float pot1f = G3D_Z_DEPTH_MIN + (((G3D_Z_DEPTH_MAX - G3D_Z_DEPTH_MIN) * (float)pot1val) / 65535.0f);
+
+    gfx3d_set_z_depth (pot1f);
+
     /* setup frame timer */
-    frametimer.attach_us (trigger_frametimer, 40000);
+    frametimer.attach_us (trigger_frametimer, FRAME_RATE_US);
 
     /* Example data printing */
-    fxos.get_data (&fxos_acc, &fxos_mag);
-    print_reading ();
+    fxos.get_data (&fxos_data);
+    print_reading (&fxos_data);
 
 #ifdef BENCHMARK
     perftimer.reset ();
@@ -126,42 +163,79 @@
 
     a = 0;
     for (;;) {
-        uint8_t cflags = 0x00;
+        uint8_t cflags;
         
-        if (pflags & PFLAG_TIMER) {
+        __disable_irq ();
+        cflags = pflags;
+        pflags = 0x00;
+        __enable_irq ();
+        
+        if (cflags & PFLAG_TIMER) {
             g3d_p3_t pts1[8];                   /* points for rotates/translated cubes */
             g3d_2p3_t pts2[8];                  /* points for projected cube */
+            g3d_poly_t poly[12];                /* polygons for cube */
+            g3d_edgebuf_t pedge[12];            /* edge-buffers for polygons */
+            int npolys = 0;                     /* number of polygons that are meaningful */
             int i;
+            uint16_t n_pot1, n_pot2;
             
+#ifdef BENCHMARK
+            bt_start = perftimer.read_us ();
+            bt_update = 0;
+            bt_trans = 0;
+            bt_render = 0;
+#endif
+
             /* push last frame first */
             shld_lcd.copy_to_lcd ();
             shld_lcd.cls ();
 
 #ifdef BENCHMARK
-            bt_start = perftimer.read_us ();
-            bt_trans = 0;
-            bt_render = 0;
+            bt_now = perftimer.read_us ();
+            bt_update += (bt_now - bt_start);
+            bt_start = bt_now;
 #endif
-            for (i=0; i<4; i++) {
-                g3d_p3_t trans = {3.0f * gfx3d_sin (a + (i * 64)), 0.0f, 3.0f * gfx3d_cos (a + (i * 64))};
-            
-                /* rotate, translate and render! */
-                if (i == 0) {
-                    gfx3d_translate (g3d_cubepnts, pts1, 8, trans);
-                } else {
-                    gfx3d_rotate_demo (g3d_cubepnts, pts1, 8, (a * i) & 0xff);
-                    gfx3d_translate (pts1, pts1, 8, trans);
+
+            /* read potentiometers */
+            n_pot1 = shld_pot1.read_u16 ();
+            n_pot2 = shld_pot2.read_u16 ();
+            if (pot1val != n_pot1) {
+                /* FIXME: ... */
+                pot1val = n_pot1;
+                pot1f = G3D_Z_DEPTH_MIN + (((G3D_Z_DEPTH_MAX - G3D_Z_DEPTH_MIN) * (float)pot1val) / 65535.0f);
+
+                gfx3d_set_z_depth (pot1f);
+            }
+            if (pot2val != n_pot2) {
+                /* FIXME: ... */
+                pot2val = n_pot2;
+            }
+            gfx3d_clear_zb ();
+
+#if 0
+            /* DEBUG: for texture mapping, simple rotating square (2 polys) */
+            {
+                int j;
+                g3d_p3_t scale = {2.0, 2.0, 1.0};
+                g3d_p3_t trans = {0.0, 0.0, -10.0 + ((20.0f * (float)a) / 256.0f)};
+                
+                gfx3d_scale (g3d_xyfacepnts, pts1, 4, scale);
+                gfx3d_rotate_x (pts1, pts1, 4, a);
+                gfx3d_translate (pts1, pts1, 4, trans);
+                gfx3d_rotate_z (pts1, pts1, 4, a * 2);
+                gfx3d_project (pts1, pts2, 4);
+                gfx3d_squarify_points (pts2, poly, &npolys, 0);     /* hide backfaces */
+                for (j=0; j<npolys; j++) {
+                    gfx3d_sort_poly (&poly[j]);
                 }
-
-                gfx3d_project (pts1, pts2, 8);
-
 #ifdef BENCHMARK
                 bt_now = perftimer.read_us ();
                 bt_trans += (bt_now - bt_start);
                 bt_start = bt_now;
 #endif
-
-                gfx3d_wirecube (pts2, shld_lcd);
+                for (j=0; j<npolys; j++) {
+                    gfx3d_polytxmap (&poly[j], g3d_texture_face, shld_lcd);
+                }
                 
 #ifdef BENCHMARK
                 bt_now = perftimer.read_us ();
@@ -170,23 +244,95 @@
 #endif
 
             }
+#else            
+            for (i=0; i<4; i++) {
+                g3d_p3_t trans = {3.0f * gfx3d_sin (a + (i * 64)), 0.0f, 5.0f * gfx3d_cos (a + (i * 64))};
+                int j;
+            
+                /* rotate, translate and render! */
+                if (i == 0) {
+                    gfx3d_rotate_y (g3d_cubepnts, pts1, 8, x_rot);
+                    gfx3d_rotate_x (pts1, pts1, 8, y_rot);
+                    gfx3d_translate (pts1, pts1, 8, trans);
+                } else {
+                    gfx3d_rotate_demo (g3d_cubepnts, pts1, 8, (a * i) & 0xff);
+                    gfx3d_translate (pts1, pts1, 8, trans);
+                }
+
+                gfx3d_project (pts1, pts2, 8);
+                gfx3d_cubify_points (pts2, poly, &npolys, 0, std_cube_txmap);       /* hide backfaces */
+                for (j=0; j<npolys; j++) {
+                    gfx3d_sort_poly (&poly[j]);
+                    if (i < 3) {
+                        /* nothing here for this one */
+                    } else {
+                        gfx3d_edgebuf_z (&poly[j], &pedge[j]);
+                    }
+                }
+
+#if 0
+if (i == 2) {
+if ((a & 0x0f) == 0) {
+    host.printf ("poly[0].tx_pts[0]=%4.4x, [1]=%4.4x, [2]=%4.4x, norm=%8.8x\r\n", poly[0].tx_pts[0], poly[0].tx_pts[1], poly[0].tx_pts[2], poly[0].norm);
+}
+}
+#endif
+
+#ifdef BENCHMARK
+                bt_now = perftimer.read_us ();
+                bt_trans += (bt_now - bt_start);
+                bt_start = bt_now;
+#endif
+
+                // gfx3d_wirecube (pts2, shld_lcd);
+                for (j=0; j<npolys; j++) {
+                    // gfx3d_wirepoly (&poly[j], shld_lcd);
+                    if (i < 2) {
+                        gfx3d_polytxmap (&poly[j], shld_lcd);
+                    } else if (i == 2) {
+                        gfx3d_polynormmap (&poly[j], shld_lcd);
+                    } else {
+                        gfx3d_wireedge (&pedge[j], shld_lcd);
+                    }
+                }
+                
+#ifdef BENCHMARK
+                bt_now = perftimer.read_us ();
+                bt_render += (bt_now - bt_start);
+                bt_start = bt_now;
+#endif
+
+            }
+#endif  /* (debugging what polygons to use) */
             
             a++;
+            if (ljoybits & JOY_UP) {
+                y_rot += JOY_ANGLE_ADVANCE;
+            } else if (ljoybits & JOY_DOWN) {
+                y_rot -= JOY_ANGLE_ADVANCE;
+            }
+            if (ljoybits & JOY_LEFT) {
+                x_rot += JOY_ANGLE_ADVANCE;
+            } else if (ljoybits & JOY_RIGHT) {
+                x_rot -= JOY_ANGLE_ADVANCE;
+            }
 
 #ifdef BENCHMARK
             /* write bt_trans and bt_render into the display */
             shld_lcd.locate (0, 24);
-            shld_lcd.printf ("T: %d, R: %d", bt_trans, bt_render);
+            shld_lcd.printf ("U:%d T:%d R:%d", bt_update, bt_trans, bt_render);
 #endif
-            cflags |= PFLAG_TIMER;
+        }
+        if (cflags & PFLAG_FXOS) {
+            fxos.get_data (&fxos_data);
         }
-        if (pflags & PFLAG_FXOS) {
-            fxos.get_data (&fxos_acc, &fxos_mag);
-            cflags |= PFLAG_FXOS;
+        if (cflags & PFLAG_JOY) {
+            /* just update our local version of the variable (might not see changes in A-B-A situations) */
+            ljoybits = joybits;
         }
+
         
         __disable_irq ();
-        pflags &= ~cflags;
         if (!pflags) {
             sleep ();
         }