Spinning dna graphics demo for the Gameduino

Dependencies:   Gameduino mbed

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?

UserRevisionLine numberNew 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 }