Chris Dick
/
Gameduino_Spinning_DNA_demo
Spinning dna graphics demo for the Gameduino
Diff: main.cpp
- Revision:
- 0:87bd6fb28ffb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Fri Dec 21 14:08:13 2012 +0000 @@ -0,0 +1,217 @@ +#include "mbed.h" +#include "GD.h" +#include "shield.h" +#include "arduino.h" + +GDClass GD(ARD_MOSI, ARD_MISO, ARD_SCK, ARD_D9, USBTX, USBRX) ; +SPI spimain(ARD_MOSI, ARD_MISO, ARD_SCK); // mosi, miso, sclk +//#include <stdlib.h> +//#include <spimainmain.h> +//#include <GD.h> +Serial pcmain(USBTX, USBRX); +static uint16_t SWAP_RB(uint16_t color) { // Swap red and blue channel + byte r = (color >> 10) & 31; + byte g = (color >> 5) & 31; + byte b = color & 31; + return (color & 0x8000) | (b << 10) | (g << 5) | (r); +} + +static uint16_t SWAP_RG(uint16_t color) { // Swap red and blue channel + byte r = (color >> 10) & 31; + byte g = (color >> 5) & 31; + byte b = color & 31; + return (color & 0x8000) | (g << 10) | (r << 5) | (b); +} + +#include "dna.h" + +//////////////////////////////////////////////////////////////////////////////// +// 3D Projection +//////////////////////////////////////////////////////////////////////////////// + +static float mats[2][9]; + +static float mat[9]; + +// Taken from glRotate() +static void rotation(float phi) { + float x = 0.57735026918962573; + float y = 0.57735026918962573; + float z = 0.57735026918962573; + + float s = sin(phi); + float c = cos(phi); + + mat[0] = x*x*(1-c)+c; + mat[1] = x*y*(1-c)-z*s; + mat[2] = x*z*(1-c)+y*s; + + mat[3] = y*x*(1-c)+z*s; + mat[4] = y*y*(1-c)+c; + mat[5] = y*z*(1-c)-x*s; + + mat[6] = x*z*(1-c)-y*s; + mat[7] = y*z*(1-c)+x*s; + mat[8] = z*z*(1-c)+c; +} + +#ifdef MAPLE_IDE +#define NVERTICES 250 +#else +#define NVERTICES 220 // Arduino does not have enough RAM for all 250 +#endif + +struct screenpt { + short x, y, z; +}; +static struct screenpt projected[NVERTICES]; + +void project(float distance) { + byte vx; + const prog_char *pm = cloud; + const prog_char *pm_e = cloud + (NVERTICES*3); + struct screenpt *dst = projected; + signed char x, y, z; + + while (pm < pm_e) { + x = pgm_read_byte_near(pm++); + y = pgm_read_byte_near(pm++); + z = pgm_read_byte_near(pm++); + float xx = x * mat[0] + y * mat[3] + z * mat[6]; + float yy = x * mat[1] + y * mat[4] + z * mat[7]; + float zz = x * mat[2] + y * mat[5] + z * mat[8] + distance; + int scale = 200; + float q = scale / (250 + zz); + dst->x = (511 & (int)(200 + xx * q)) | (((x^y^z) & 3) << 14); + dst->y = (int)(150 + yy * q); + dst->z = (int)(zz * 100); + dst++; + } +} + +// point depth comparison, for depth sort +int ptcmp(const void *va, const void *vb) { + struct screenpt *a = (struct screenpt *)va; + struct screenpt *b = (struct screenpt *)vb; + + if (a->z < b->z) + return 1; + else if (a->z > b->z) + return -1; + else + return 0; +} + +// load a sprite at (x,y). z is distance 0-63, color is 0-3 +static void render_sphere(int x, int y, byte z, byte color) { + static byte pals[4][2] = { + { 4,6 }, + { 5,7 }, + { 0,1 }, + { 2,3 } + }; + + int ox = x - 8; + int oy = y - 8; + byte palette = pals[color][z & 1]; + byte image = (z >> 1); + + spimain.write(lowByte(ox)); + spimain.write((palette << 4) | (highByte(ox) & 1)); + spimain.write(lowByte(oy)); + spimain.write((image << 1) | (highByte(oy) & 1)); +} + +void draw(float distance) { + project(distance); + qsort(projected, NVERTICES, sizeof(struct screenpt), ptcmp); + + static byte flip; + GD.__wstartspr(flip ? 256 : 0); + for (int i = 0; i < NVERTICES; i++) { + byte color = (projected[i].x >> 14) & 3; + short x = projected[i].x & 511; + short y = projected[i].y; + int z = max(0, min(63, int(32 + projected[i].z / 500))); + render_sphere(x, y, z, color); + } + GD.__end(); + GD.wr(SPR_PAGE, flip); + flip = !flip; +} + +static float phi; // Current rotation angle + +// Draw one frame of ship +void cycle(float distance) { + rotation(phi); + phi += 0.02; + draw(distance); + + // report frame rate in top-right + static byte every; + if (++every == 4) { + static long tprev; + long t = micros(); + every = 0; + + char msg[30]; + int fps10 = int(4 * 10000000UL / (t - tprev)); + sprintf(msg, "%3d.%d fps ", fps10 / 10, fps10 % 10); + GD.putstr(41, 0, msg); + tprev = t; + } + +} + +// this function has been changed to handle the gameduino being in little endian +static uint16_t rdpal(int i) { + uint16_t swapped = (sphere_pal[(i << 1)+1] << 8) | ((sphere_pal[(i << 1)])); + return swapped; +} + +void setup() { + GD.begin(); + GD.ascii(); + + for (byte y = 0; y < 38; y++) { + prog_uchar *src = ramp_pic + y * 4; + for (byte x = 0; x < 50; x++) + GD.wr(RAM_PIC + y * 64 + x, pgm_read_byte(src + random(4))); + } + GD.copy(RAM_CHR + 128 * 16, ramp_chr, sizeof(ramp_chr)); + GD.copy(RAM_PAL + 128 * 8, ramp_pal, sizeof(ramp_pal)); + + GD.copy(PALETTE16A, sphere_pal, sizeof(sphere_pal)); + for (byte i = 0; i < 16; i++) { + GD.wr16(PALETTE16B + 2 * i, SWAP_RB(rdpal(i))); + } + + for (int i = 0; i < 256; i++) { + // palette 0 decodes low nibble, hence (i & 15) + GD.wr16(RAM_SPRPAL + (i << 1), SWAP_RG(rdpal(i & 15))); + // palette 1 decodes nigh nibble, hence (i >> 4) + GD.wr16(RAM_SPRPAL + 512 + (i << 1), SWAP_RG(rdpal(i >> 4))); + + // palette 0 decodes low nibble, hence (i & 15) + GD.wr16(RAM_SPRPAL + 1024 + (i << 1), SWAP_RB(SWAP_RG(rdpal(i & 15)))); + // palette 1 decodes nigh nibble, hence (i >> 4) + GD.wr16(RAM_SPRPAL + 1024 + 512 + (i << 1), SWAP_RB(SWAP_RG(rdpal(i >> 4)))); + } + + GD.copy(RAM_SPRIMG, sphere_img, sizeof(sphere_img)); + GD.putstr(0, 0, "DNA demo: Gameduino with Mbed"); + +} + +void loop() { + cycle(0.0); +} + +int main() { + timer_start(); + setup(); + while (1) { + loop(); + } +} \ No newline at end of file