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
Diff: main.cpp
- 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 (); }