Chris Dick
/
Gameduino_Spinning_DNA_demo
Spinning dna graphics demo for the Gameduino
main.cpp@0:87bd6fb28ffb, 2012-12-21 (annotated)
- Committer:
- TheChrisyd
- Date:
- Fri Dec 21 14:08:13 2012 +0000
- Revision:
- 0:87bd6fb28ffb
Working version - a few glitches on the bottom of the screen
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
TheChrisyd | 0:87bd6fb28ffb | 1 | #include "mbed.h" |
TheChrisyd | 0:87bd6fb28ffb | 2 | #include "GD.h" |
TheChrisyd | 0:87bd6fb28ffb | 3 | #include "shield.h" |
TheChrisyd | 0:87bd6fb28ffb | 4 | #include "arduino.h" |
TheChrisyd | 0:87bd6fb28ffb | 5 | |
TheChrisyd | 0:87bd6fb28ffb | 6 | GDClass GD(ARD_MOSI, ARD_MISO, ARD_SCK, ARD_D9, USBTX, USBRX) ; |
TheChrisyd | 0:87bd6fb28ffb | 7 | SPI spimain(ARD_MOSI, ARD_MISO, ARD_SCK); // mosi, miso, sclk |
TheChrisyd | 0:87bd6fb28ffb | 8 | //#include <stdlib.h> |
TheChrisyd | 0:87bd6fb28ffb | 9 | //#include <spimainmain.h> |
TheChrisyd | 0:87bd6fb28ffb | 10 | //#include <GD.h> |
TheChrisyd | 0:87bd6fb28ffb | 11 | Serial pcmain(USBTX, USBRX); |
TheChrisyd | 0:87bd6fb28ffb | 12 | static uint16_t SWAP_RB(uint16_t color) { // Swap red and blue channel |
TheChrisyd | 0:87bd6fb28ffb | 13 | byte r = (color >> 10) & 31; |
TheChrisyd | 0:87bd6fb28ffb | 14 | byte g = (color >> 5) & 31; |
TheChrisyd | 0:87bd6fb28ffb | 15 | byte b = color & 31; |
TheChrisyd | 0:87bd6fb28ffb | 16 | return (color & 0x8000) | (b << 10) | (g << 5) | (r); |
TheChrisyd | 0:87bd6fb28ffb | 17 | } |
TheChrisyd | 0:87bd6fb28ffb | 18 | |
TheChrisyd | 0:87bd6fb28ffb | 19 | static uint16_t SWAP_RG(uint16_t color) { // Swap red and blue channel |
TheChrisyd | 0:87bd6fb28ffb | 20 | byte r = (color >> 10) & 31; |
TheChrisyd | 0:87bd6fb28ffb | 21 | byte g = (color >> 5) & 31; |
TheChrisyd | 0:87bd6fb28ffb | 22 | byte b = color & 31; |
TheChrisyd | 0:87bd6fb28ffb | 23 | return (color & 0x8000) | (g << 10) | (r << 5) | (b); |
TheChrisyd | 0:87bd6fb28ffb | 24 | } |
TheChrisyd | 0:87bd6fb28ffb | 25 | |
TheChrisyd | 0:87bd6fb28ffb | 26 | #include "dna.h" |
TheChrisyd | 0:87bd6fb28ffb | 27 | |
TheChrisyd | 0:87bd6fb28ffb | 28 | //////////////////////////////////////////////////////////////////////////////// |
TheChrisyd | 0:87bd6fb28ffb | 29 | // 3D Projection |
TheChrisyd | 0:87bd6fb28ffb | 30 | //////////////////////////////////////////////////////////////////////////////// |
TheChrisyd | 0:87bd6fb28ffb | 31 | |
TheChrisyd | 0:87bd6fb28ffb | 32 | static float mats[2][9]; |
TheChrisyd | 0:87bd6fb28ffb | 33 | |
TheChrisyd | 0:87bd6fb28ffb | 34 | static float mat[9]; |
TheChrisyd | 0:87bd6fb28ffb | 35 | |
TheChrisyd | 0:87bd6fb28ffb | 36 | // Taken from glRotate() |
TheChrisyd | 0:87bd6fb28ffb | 37 | static void rotation(float phi) { |
TheChrisyd | 0:87bd6fb28ffb | 38 | float x = 0.57735026918962573; |
TheChrisyd | 0:87bd6fb28ffb | 39 | float y = 0.57735026918962573; |
TheChrisyd | 0:87bd6fb28ffb | 40 | float z = 0.57735026918962573; |
TheChrisyd | 0:87bd6fb28ffb | 41 | |
TheChrisyd | 0:87bd6fb28ffb | 42 | float s = sin(phi); |
TheChrisyd | 0:87bd6fb28ffb | 43 | float c = cos(phi); |
TheChrisyd | 0:87bd6fb28ffb | 44 | |
TheChrisyd | 0:87bd6fb28ffb | 45 | mat[0] = x*x*(1-c)+c; |
TheChrisyd | 0:87bd6fb28ffb | 46 | mat[1] = x*y*(1-c)-z*s; |
TheChrisyd | 0:87bd6fb28ffb | 47 | mat[2] = x*z*(1-c)+y*s; |
TheChrisyd | 0:87bd6fb28ffb | 48 | |
TheChrisyd | 0:87bd6fb28ffb | 49 | mat[3] = y*x*(1-c)+z*s; |
TheChrisyd | 0:87bd6fb28ffb | 50 | mat[4] = y*y*(1-c)+c; |
TheChrisyd | 0:87bd6fb28ffb | 51 | mat[5] = y*z*(1-c)-x*s; |
TheChrisyd | 0:87bd6fb28ffb | 52 | |
TheChrisyd | 0:87bd6fb28ffb | 53 | mat[6] = x*z*(1-c)-y*s; |
TheChrisyd | 0:87bd6fb28ffb | 54 | mat[7] = y*z*(1-c)+x*s; |
TheChrisyd | 0:87bd6fb28ffb | 55 | mat[8] = z*z*(1-c)+c; |
TheChrisyd | 0:87bd6fb28ffb | 56 | } |
TheChrisyd | 0:87bd6fb28ffb | 57 | |
TheChrisyd | 0:87bd6fb28ffb | 58 | #ifdef MAPLE_IDE |
TheChrisyd | 0:87bd6fb28ffb | 59 | #define NVERTICES 250 |
TheChrisyd | 0:87bd6fb28ffb | 60 | #else |
TheChrisyd | 0:87bd6fb28ffb | 61 | #define NVERTICES 220 // Arduino does not have enough RAM for all 250 |
TheChrisyd | 0:87bd6fb28ffb | 62 | #endif |
TheChrisyd | 0:87bd6fb28ffb | 63 | |
TheChrisyd | 0:87bd6fb28ffb | 64 | struct screenpt { |
TheChrisyd | 0:87bd6fb28ffb | 65 | short x, y, z; |
TheChrisyd | 0:87bd6fb28ffb | 66 | }; |
TheChrisyd | 0:87bd6fb28ffb | 67 | static struct screenpt projected[NVERTICES]; |
TheChrisyd | 0:87bd6fb28ffb | 68 | |
TheChrisyd | 0:87bd6fb28ffb | 69 | void project(float distance) { |
TheChrisyd | 0:87bd6fb28ffb | 70 | byte vx; |
TheChrisyd | 0:87bd6fb28ffb | 71 | const prog_char *pm = cloud; |
TheChrisyd | 0:87bd6fb28ffb | 72 | const prog_char *pm_e = cloud + (NVERTICES*3); |
TheChrisyd | 0:87bd6fb28ffb | 73 | struct screenpt *dst = projected; |
TheChrisyd | 0:87bd6fb28ffb | 74 | signed char x, y, z; |
TheChrisyd | 0:87bd6fb28ffb | 75 | |
TheChrisyd | 0:87bd6fb28ffb | 76 | while (pm < pm_e) { |
TheChrisyd | 0:87bd6fb28ffb | 77 | x = pgm_read_byte_near(pm++); |
TheChrisyd | 0:87bd6fb28ffb | 78 | y = pgm_read_byte_near(pm++); |
TheChrisyd | 0:87bd6fb28ffb | 79 | z = pgm_read_byte_near(pm++); |
TheChrisyd | 0:87bd6fb28ffb | 80 | float xx = x * mat[0] + y * mat[3] + z * mat[6]; |
TheChrisyd | 0:87bd6fb28ffb | 81 | float yy = x * mat[1] + y * mat[4] + z * mat[7]; |
TheChrisyd | 0:87bd6fb28ffb | 82 | float zz = x * mat[2] + y * mat[5] + z * mat[8] + distance; |
TheChrisyd | 0:87bd6fb28ffb | 83 | int scale = 200; |
TheChrisyd | 0:87bd6fb28ffb | 84 | float q = scale / (250 + zz); |
TheChrisyd | 0:87bd6fb28ffb | 85 | dst->x = (511 & (int)(200 + xx * q)) | (((x^y^z) & 3) << 14); |
TheChrisyd | 0:87bd6fb28ffb | 86 | dst->y = (int)(150 + yy * q); |
TheChrisyd | 0:87bd6fb28ffb | 87 | dst->z = (int)(zz * 100); |
TheChrisyd | 0:87bd6fb28ffb | 88 | dst++; |
TheChrisyd | 0:87bd6fb28ffb | 89 | } |
TheChrisyd | 0:87bd6fb28ffb | 90 | } |
TheChrisyd | 0:87bd6fb28ffb | 91 | |
TheChrisyd | 0:87bd6fb28ffb | 92 | // point depth comparison, for depth sort |
TheChrisyd | 0:87bd6fb28ffb | 93 | int ptcmp(const void *va, const void *vb) { |
TheChrisyd | 0:87bd6fb28ffb | 94 | struct screenpt *a = (struct screenpt *)va; |
TheChrisyd | 0:87bd6fb28ffb | 95 | struct screenpt *b = (struct screenpt *)vb; |
TheChrisyd | 0:87bd6fb28ffb | 96 | |
TheChrisyd | 0:87bd6fb28ffb | 97 | if (a->z < b->z) |
TheChrisyd | 0:87bd6fb28ffb | 98 | return 1; |
TheChrisyd | 0:87bd6fb28ffb | 99 | else if (a->z > b->z) |
TheChrisyd | 0:87bd6fb28ffb | 100 | return -1; |
TheChrisyd | 0:87bd6fb28ffb | 101 | else |
TheChrisyd | 0:87bd6fb28ffb | 102 | return 0; |
TheChrisyd | 0:87bd6fb28ffb | 103 | } |
TheChrisyd | 0:87bd6fb28ffb | 104 | |
TheChrisyd | 0:87bd6fb28ffb | 105 | // load a sprite at (x,y). z is distance 0-63, color is 0-3 |
TheChrisyd | 0:87bd6fb28ffb | 106 | static void render_sphere(int x, int y, byte z, byte color) { |
TheChrisyd | 0:87bd6fb28ffb | 107 | static byte pals[4][2] = { |
TheChrisyd | 0:87bd6fb28ffb | 108 | { 4,6 }, |
TheChrisyd | 0:87bd6fb28ffb | 109 | { 5,7 }, |
TheChrisyd | 0:87bd6fb28ffb | 110 | { 0,1 }, |
TheChrisyd | 0:87bd6fb28ffb | 111 | { 2,3 } |
TheChrisyd | 0:87bd6fb28ffb | 112 | }; |
TheChrisyd | 0:87bd6fb28ffb | 113 | |
TheChrisyd | 0:87bd6fb28ffb | 114 | int ox = x - 8; |
TheChrisyd | 0:87bd6fb28ffb | 115 | int oy = y - 8; |
TheChrisyd | 0:87bd6fb28ffb | 116 | byte palette = pals[color][z & 1]; |
TheChrisyd | 0:87bd6fb28ffb | 117 | byte image = (z >> 1); |
TheChrisyd | 0:87bd6fb28ffb | 118 | |
TheChrisyd | 0:87bd6fb28ffb | 119 | spimain.write(lowByte(ox)); |
TheChrisyd | 0:87bd6fb28ffb | 120 | spimain.write((palette << 4) | (highByte(ox) & 1)); |
TheChrisyd | 0:87bd6fb28ffb | 121 | spimain.write(lowByte(oy)); |
TheChrisyd | 0:87bd6fb28ffb | 122 | spimain.write((image << 1) | (highByte(oy) & 1)); |
TheChrisyd | 0:87bd6fb28ffb | 123 | } |
TheChrisyd | 0:87bd6fb28ffb | 124 | |
TheChrisyd | 0:87bd6fb28ffb | 125 | void draw(float distance) { |
TheChrisyd | 0:87bd6fb28ffb | 126 | project(distance); |
TheChrisyd | 0:87bd6fb28ffb | 127 | qsort(projected, NVERTICES, sizeof(struct screenpt), ptcmp); |
TheChrisyd | 0:87bd6fb28ffb | 128 | |
TheChrisyd | 0:87bd6fb28ffb | 129 | static byte flip; |
TheChrisyd | 0:87bd6fb28ffb | 130 | GD.__wstartspr(flip ? 256 : 0); |
TheChrisyd | 0:87bd6fb28ffb | 131 | for (int i = 0; i < NVERTICES; i++) { |
TheChrisyd | 0:87bd6fb28ffb | 132 | byte color = (projected[i].x >> 14) & 3; |
TheChrisyd | 0:87bd6fb28ffb | 133 | short x = projected[i].x & 511; |
TheChrisyd | 0:87bd6fb28ffb | 134 | short y = projected[i].y; |
TheChrisyd | 0:87bd6fb28ffb | 135 | int z = max(0, min(63, int(32 + projected[i].z / 500))); |
TheChrisyd | 0:87bd6fb28ffb | 136 | render_sphere(x, y, z, color); |
TheChrisyd | 0:87bd6fb28ffb | 137 | } |
TheChrisyd | 0:87bd6fb28ffb | 138 | GD.__end(); |
TheChrisyd | 0:87bd6fb28ffb | 139 | GD.wr(SPR_PAGE, flip); |
TheChrisyd | 0:87bd6fb28ffb | 140 | flip = !flip; |
TheChrisyd | 0:87bd6fb28ffb | 141 | } |
TheChrisyd | 0:87bd6fb28ffb | 142 | |
TheChrisyd | 0:87bd6fb28ffb | 143 | static float phi; // Current rotation angle |
TheChrisyd | 0:87bd6fb28ffb | 144 | |
TheChrisyd | 0:87bd6fb28ffb | 145 | // Draw one frame of ship |
TheChrisyd | 0:87bd6fb28ffb | 146 | void cycle(float distance) { |
TheChrisyd | 0:87bd6fb28ffb | 147 | rotation(phi); |
TheChrisyd | 0:87bd6fb28ffb | 148 | phi += 0.02; |
TheChrisyd | 0:87bd6fb28ffb | 149 | draw(distance); |
TheChrisyd | 0:87bd6fb28ffb | 150 | |
TheChrisyd | 0:87bd6fb28ffb | 151 | // report frame rate in top-right |
TheChrisyd | 0:87bd6fb28ffb | 152 | static byte every; |
TheChrisyd | 0:87bd6fb28ffb | 153 | if (++every == 4) { |
TheChrisyd | 0:87bd6fb28ffb | 154 | static long tprev; |
TheChrisyd | 0:87bd6fb28ffb | 155 | long t = micros(); |
TheChrisyd | 0:87bd6fb28ffb | 156 | every = 0; |
TheChrisyd | 0:87bd6fb28ffb | 157 | |
TheChrisyd | 0:87bd6fb28ffb | 158 | char msg[30]; |
TheChrisyd | 0:87bd6fb28ffb | 159 | int fps10 = int(4 * 10000000UL / (t - tprev)); |
TheChrisyd | 0:87bd6fb28ffb | 160 | sprintf(msg, "%3d.%d fps ", fps10 / 10, fps10 % 10); |
TheChrisyd | 0:87bd6fb28ffb | 161 | GD.putstr(41, 0, msg); |
TheChrisyd | 0:87bd6fb28ffb | 162 | tprev = t; |
TheChrisyd | 0:87bd6fb28ffb | 163 | } |
TheChrisyd | 0:87bd6fb28ffb | 164 | |
TheChrisyd | 0:87bd6fb28ffb | 165 | } |
TheChrisyd | 0:87bd6fb28ffb | 166 | |
TheChrisyd | 0:87bd6fb28ffb | 167 | // this function has been changed to handle the gameduino being in little endian |
TheChrisyd | 0:87bd6fb28ffb | 168 | static uint16_t rdpal(int i) { |
TheChrisyd | 0:87bd6fb28ffb | 169 | uint16_t swapped = (sphere_pal[(i << 1)+1] << 8) | ((sphere_pal[(i << 1)])); |
TheChrisyd | 0:87bd6fb28ffb | 170 | return swapped; |
TheChrisyd | 0:87bd6fb28ffb | 171 | } |
TheChrisyd | 0:87bd6fb28ffb | 172 | |
TheChrisyd | 0:87bd6fb28ffb | 173 | void setup() { |
TheChrisyd | 0:87bd6fb28ffb | 174 | GD.begin(); |
TheChrisyd | 0:87bd6fb28ffb | 175 | GD.ascii(); |
TheChrisyd | 0:87bd6fb28ffb | 176 | |
TheChrisyd | 0:87bd6fb28ffb | 177 | for (byte y = 0; y < 38; y++) { |
TheChrisyd | 0:87bd6fb28ffb | 178 | prog_uchar *src = ramp_pic + y * 4; |
TheChrisyd | 0:87bd6fb28ffb | 179 | for (byte x = 0; x < 50; x++) |
TheChrisyd | 0:87bd6fb28ffb | 180 | GD.wr(RAM_PIC + y * 64 + x, pgm_read_byte(src + random(4))); |
TheChrisyd | 0:87bd6fb28ffb | 181 | } |
TheChrisyd | 0:87bd6fb28ffb | 182 | GD.copy(RAM_CHR + 128 * 16, ramp_chr, sizeof(ramp_chr)); |
TheChrisyd | 0:87bd6fb28ffb | 183 | GD.copy(RAM_PAL + 128 * 8, ramp_pal, sizeof(ramp_pal)); |
TheChrisyd | 0:87bd6fb28ffb | 184 | |
TheChrisyd | 0:87bd6fb28ffb | 185 | GD.copy(PALETTE16A, sphere_pal, sizeof(sphere_pal)); |
TheChrisyd | 0:87bd6fb28ffb | 186 | for (byte i = 0; i < 16; i++) { |
TheChrisyd | 0:87bd6fb28ffb | 187 | GD.wr16(PALETTE16B + 2 * i, SWAP_RB(rdpal(i))); |
TheChrisyd | 0:87bd6fb28ffb | 188 | } |
TheChrisyd | 0:87bd6fb28ffb | 189 | |
TheChrisyd | 0:87bd6fb28ffb | 190 | for (int i = 0; i < 256; i++) { |
TheChrisyd | 0:87bd6fb28ffb | 191 | // palette 0 decodes low nibble, hence (i & 15) |
TheChrisyd | 0:87bd6fb28ffb | 192 | GD.wr16(RAM_SPRPAL + (i << 1), SWAP_RG(rdpal(i & 15))); |
TheChrisyd | 0:87bd6fb28ffb | 193 | // palette 1 decodes nigh nibble, hence (i >> 4) |
TheChrisyd | 0:87bd6fb28ffb | 194 | GD.wr16(RAM_SPRPAL + 512 + (i << 1), SWAP_RG(rdpal(i >> 4))); |
TheChrisyd | 0:87bd6fb28ffb | 195 | |
TheChrisyd | 0:87bd6fb28ffb | 196 | // palette 0 decodes low nibble, hence (i & 15) |
TheChrisyd | 0:87bd6fb28ffb | 197 | GD.wr16(RAM_SPRPAL + 1024 + (i << 1), SWAP_RB(SWAP_RG(rdpal(i & 15)))); |
TheChrisyd | 0:87bd6fb28ffb | 198 | // palette 1 decodes nigh nibble, hence (i >> 4) |
TheChrisyd | 0:87bd6fb28ffb | 199 | GD.wr16(RAM_SPRPAL + 1024 + 512 + (i << 1), SWAP_RB(SWAP_RG(rdpal(i >> 4)))); |
TheChrisyd | 0:87bd6fb28ffb | 200 | } |
TheChrisyd | 0:87bd6fb28ffb | 201 | |
TheChrisyd | 0:87bd6fb28ffb | 202 | GD.copy(RAM_SPRIMG, sphere_img, sizeof(sphere_img)); |
TheChrisyd | 0:87bd6fb28ffb | 203 | GD.putstr(0, 0, "DNA demo: Gameduino with Mbed"); |
TheChrisyd | 0:87bd6fb28ffb | 204 | |
TheChrisyd | 0:87bd6fb28ffb | 205 | } |
TheChrisyd | 0:87bd6fb28ffb | 206 | |
TheChrisyd | 0:87bd6fb28ffb | 207 | void loop() { |
TheChrisyd | 0:87bd6fb28ffb | 208 | cycle(0.0); |
TheChrisyd | 0:87bd6fb28ffb | 209 | } |
TheChrisyd | 0:87bd6fb28ffb | 210 | |
TheChrisyd | 0:87bd6fb28ffb | 211 | int main() { |
TheChrisyd | 0:87bd6fb28ffb | 212 | timer_start(); |
TheChrisyd | 0:87bd6fb28ffb | 213 | setup(); |
TheChrisyd | 0:87bd6fb28ffb | 214 | while (1) { |
TheChrisyd | 0:87bd6fb28ffb | 215 | loop(); |
TheChrisyd | 0:87bd6fb28ffb | 216 | } |
TheChrisyd | 0:87bd6fb28ffb | 217 | } |