123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- #include <SPI.h>
- #include <GD.h>
- ////////////////////////////////////////////////////////////////////////////////
- // Plotter
- ////////////////////////////////////////////////////////////////////////////////
- #include "wireframe.h"
- #include "eraser.h"
- // replicate a 2-bit color across the whole byte.
- byte replicate(byte color)
- {
- return (color << 6) | (color << 4) | (color << 2) | color;
- }
- #define BLACK RGB(0,0,0)
- #define WHITE RGB(255,255,255)
- class PlotterClass
- {
- public:
- void begin();
- void line(byte x0, byte y0, byte x1, byte y1);
- void show();
- private:
- byte flip;
- byte plotting;
- void erase();
- void waitready();
- };
- PlotterClass Plotter;
- void PlotterClass::waitready()
- {
- while (GD.rd(COMM+7))
- ;
- }
- void PlotterClass::erase()
- {
- byte color = flip ? 1 : 2;
- plotting = 0;
- GD.wr(J1_RESET, 1);
- GD.wr(COMM+7, 1);
- GD.wr(COMM+8, replicate(color ^ 3));
- GD.microcode(eraser_code, sizeof(eraser_code));
- }
- void PlotterClass::begin()
- {
- // Draw 256 sprites left to right, top to bottom, all in 4-color
- // palette mode. By doing them in column-wise order, the address
- // calculation in setpixel is made simpler.
- // First 64 use bits 0-1, next 64 use bits 2-4, etc.
- // This gives a 256 x 256 4-color bitmap.
- unsigned int i;
- for (i = 0; i < 256; i++) {
- int x = 72 + 16 * ((i >> 4) & 15);
- int y = 22 + 16 * (i & 15);
- int image = i & 63; /* image 0-63 */
- int pal = 3 - (i >> 6); /* palettes bits in columns 3,2,1,0 */
- GD.sprite(i, x, y, image, 0x8 | (pal << 1), 0);
- }
- flip = 0;
- plotting = 0;
- erase();
- show();
- }
- void PlotterClass::show()
- {
- waitready();
- if (flip == 1) {
- GD.wr16(PALETTE4A, BLACK);
- GD.wr16(PALETTE4A + 2, WHITE);
- GD.wr16(PALETTE4A + 4, BLACK);
- GD.wr16(PALETTE4A + 6, WHITE);
- } else {
- GD.wr16(PALETTE4A, BLACK);
- GD.wr16(PALETTE4A + 2, BLACK);
- GD.wr16(PALETTE4A + 4, WHITE);
- GD.wr16(PALETTE4A + 6, WHITE);
- }
- flip ^= 1;
- erase();
- }
- void PlotterClass::line(byte x0, byte y0, byte x1, byte y1)
- {
- byte swap;
- #define SWAP(a, b) (swap = (a), (a) = (b), (b) = swap)
- byte steep = abs(y1 - y0) > abs(x1 - x0);
- if (steep) {
- SWAP(x0, y0);
- SWAP(x1, y1);
- }
- if (x0 > x1) {
- SWAP(x0, x1);
- SWAP(y0, y1);
- }
- int deltax = x1 - x0;
- int deltay = abs(y1 - y0);
- int error = deltax / 2;
- char ystep;
- if (y0 < y1)
- ystep = 1;
- else
- ystep = -1;
- byte x;
- byte y = y0;
- waitready();
- if (!plotting) {
- GD.microcode(wireframe_code, sizeof(wireframe_code));
- plotting = 1;
- byte color = flip ? 1 : 2;
- GD.wr(COMM+8, color << 6);
- }
- GD.__wstart(COMM+0);
- SPI.transfer(x0);
- SPI.transfer(y0);
- SPI.transfer(x1);
- SPI.transfer(y1);
- SPI.transfer(steep);
- SPI.transfer(deltax);
- SPI.transfer(deltay);
- SPI.transfer(ystep);
- GD.__end();
- }
- ////////////////////////////////////////////////////////////////////////////////
- // 3D Projection
- ////////////////////////////////////////////////////////////////////////////////
- #include "eliteships.h"
- #define NSHIPS (sizeof(eliteships) / sizeof(eliteships[0]))
- 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;
- }
- static byte projected[40 * 2];
- void project(struct ship *s, float distance)
- {
- byte vx;
- flash_int8_t *pm = s->vertices;
- flash_int8_t *pm_e = pm + (s->nvertices * 3);
- byte *dst = projected;
- 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;
- float q = 140 / (140 + zz);
- *dst++ = byte(128 + xx * q);
- *dst++ = byte(128 + yy * q);
- }
- }
- void draw(struct ship *s, float distance)
- {
- project(s, distance);
- flash_uint8_t *pe = s->edges;
- flash_uint8_t *pe_e = pe + (s->nedges * 2);
- while (pe < pe_e) {
- byte *v0 = &projected[pgm_read_byte_near(pe++) << 1];
- byte *v1 = &projected[pgm_read_byte_near(pe++) << 1];
- Plotter.line(v0[0], v0[1], v1[0], v1[1]);
- }
- }
- void setup()
- {
- GD.begin();
- GD.ascii();
- GD.putstr(0, 0, "Accelerated wireframe");
- Plotter.begin();
- Serial.begin(1000000); // JCB
- }
- static byte sn; // Ship number, 0-NSHIPS
- static float phi; // Current rotation angle
- // Draw one frame of ship
- void cycle(float distance)
- {
- rotation(phi);
- phi += 0.02;
- draw(&eliteships[sn], distance);
- // GD.waitvblank(); // uncomment this to sync to 72Hz frame rate
- Plotter.show();
- 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);
- //screenshot(); // JCB
- tprev = t;
- tprev = micros(); // JCB
- }
- }
- void loop()
- {
- const char *name = eliteships[sn].name;
- GD.putstr(0, 36, " ");
- GD.putstr(25 - strlen(name) / 2, 36, name);
- int d;
- for (d = 0; d < 100; d++)
- cycle(1000 - 10 * d);
- for (d = 0; d < 72*6; d++)
- cycle(0.0);
- for (d = 0; d < 100; d++)
- cycle(10 * d);
- sn = (sn + 1) % NSHIPS;
- }
|