Browse Source

welcome sketch for ESP8266

James Bowman 6 years ago
parent
commit
cec46af075
1 changed files with 494 additions and 0 deletions
  1. 494 0
      welcome.ino

+ 494 - 0
welcome.ino

@@ -0,0 +1,494 @@
+#include <EEPROM.h>
+#include <SPI.h>
+#include <GD2.h>
+
+#include "welcome_assets.h"
+
+#define FACE_BACK 0
+#define FACE_FRONT 1
+
+#define P 125
+#define N -P
+
+static const PROGMEM int8_t CUBE_vertices[] = {
+  P,P,P,
+  N,P,P,
+  P,N,P,
+  N,N,P,
+
+  P,P,N,
+  N,P,N,
+  P,N,N,
+  N,N,N,
+};
+
+// each line is a face: count, normal, 4 vertices
+
+static const PROGMEM int8_t CUBE_faces[] = {
+  4, 0,0,127,   0, 1, 3, 2,
+  4, 0,0,-127,  6, 7, 5, 4,
+
+  4, 0,127,0,   4, 5, 1, 0,
+  4, 0,-127,0,  2, 3, 7, 6,
+
+  4, 127,0,0,   0, 2, 6, 4,
+  4, -127,0,0,  3, 1, 5, 7,
+
+  -1
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//                                  3D Projection
+////////////////////////////////////////////////////////////////////////////////
+
+static float model_mat[9] = {
+  1.0, 0.0, 0.0,
+  0.0, 1.0, 0.0,
+  0.0, 0.0, 1.0 };
+static float normal_mat[9] = {
+  1.0, 0.0, 0.0,
+  0.0, 1.0, 0.0,
+  0.0, 0.0, 1.0 };
+
+#define M(nm,i,j)       ((nm)[3 * (i) + (j)])
+
+// 3x3 matrix multiplication: c = a * b
+void mult_matrices(float *a, float *b, float *c)
+{
+  int i, j, k;
+  float result[9];
+  for(i = 0; i < 3; i++) {
+    for(j = 0; j < 3; j++) {
+      M(result,i,j) = 0.0f;
+      for(k = 0; k < 3; k++) {
+        M(result,i,j) += M(a,i,k) * M(b,k,j);
+      }
+    }
+  }
+  memcpy(c, result, sizeof(result));
+}
+
+// Based on glRotate()
+// Returns 3x3 rotation matrix in 'm'
+// and its invese in 'mi'
+
+static void rotate(float *m, float *mi, float angle, float *axis)
+{
+  float x = axis[0];
+  float y = axis[1];
+  float z = axis[2];
+
+  float s = sin(angle);
+  float c = cos(angle);
+
+  float xx = x*x*(1-c);
+  float xy = x*y*(1-c);
+  float xz = x*z*(1-c);
+  float yy = y*y*(1-c);
+  float yz = y*z*(1-c);
+  float zz = z*z*(1-c);
+
+  float xs = x * s;
+  float ys = y * s;
+  float zs = z * s;
+
+  m[0] = xx + c;
+  m[1] = xy - zs;
+  m[2] = xz + ys;
+
+  m[3] = xy + zs;
+  m[4] = yy + c;
+  m[5] = yz - xs;
+
+  m[6] = xz - ys;
+  m[7] = yz + xs;
+  m[8] = zz + c;
+
+  mi[0] = m[0];
+  mi[1] = xy + zs;
+  mi[2] = xz - ys;
+
+  mi[3] = xy - zs;
+  mi[4] = m[4];
+  mi[5] = yz + xs;
+
+  mi[6] = xz + ys;
+  mi[7] = yz - xs;
+  mi[8] = m[8];
+}
+
+static void rotation(float angle, float *axis)
+{
+  float mat[9], mati[9];
+
+  rotate(mat, mati, angle, axis);
+  mult_matrices(model_mat, mat, model_mat);
+  mult_matrices(mati, normal_mat, normal_mat);
+}
+
+#define N_VERTICES  (sizeof(CUBE_vertices) / 3)
+
+typedef struct {
+  int x, y;
+} point2;
+
+static point2 projected[N_VERTICES];
+
+void project()
+{
+  byte vx;
+  const PROGMEM int8_t *pm = CUBE_vertices; 
+  const PROGMEM int8_t *pm_e = pm + sizeof(CUBE_vertices);
+  point2 *dst = projected;
+  int16_t x, y, z;
+  int scale = 64 * GD.h / 280;
+  while (pm < pm_e) {
+    x = (scale * (int8_t)pgm_read_byte_near(pm++)) >> 6;
+    y = (scale * (int8_t)pgm_read_byte_near(pm++)) >> 6;
+    z = (scale * (int8_t)pgm_read_byte_near(pm++)) >> 6;
+    float xx = x * model_mat[0] + y * model_mat[3] + z * model_mat[6];
+    float yy = x * model_mat[1] + y * model_mat[4] + z * model_mat[7];
+    dst->x = 16 * (GD.w / 2 + xx);
+    dst->y = 16 * (GD.h / 2 + yy);
+    dst++;
+  }
+}
+
+static void transform_normal(int8_t &nx, int8_t &ny, int8_t &nz)
+{
+  int8_t xx = nx * normal_mat[0] + ny * normal_mat[1] + nz * normal_mat[2];
+  int8_t yy = nx * normal_mat[3] + ny * normal_mat[4] + nz * normal_mat[5];
+  int8_t zz = nx * normal_mat[6] + ny * normal_mat[7] + nz * normal_mat[8];
+  nx = xx, ny = yy, nz = zz;
+}
+
+static void quad(int x1, int y1,
+                 int x2, int y2,
+                 int x3, int y3,
+                 int bx1, int by1,
+                 int bx3, int by3)
+{
+  // Compute the fourth vertex of the parallelogram, (x4,y4)
+  int x4 = x3 + (x1 - x2);
+  int y4 = y3 + (y1 - y2);
+
+  // Apply Scissor to the extents of the quad
+  int minx = max(0,    min(min(x1, x2), min(x3, x4)));
+  int maxx = min(GD.w, max(max(x1, x2), max(x3, x4)));
+  int miny = max(0,    min(min(y1, y2), min(y3, y4)));
+  int maxy = min(GD.h, max(max(y1, y2), max(y3, y4)));
+  GD.ScissorXY(minx, miny);
+  GD.ScissorSize(maxx - minx, maxy - miny);
+  // GD.ClearColorRGB(0, 255, 0); GD.Clear();
+
+  // Set the new bitmap transform
+  GD.cmd32(0xffffff21UL); // bitmap transform
+  GD.cmd32(x1); GD.cmd32(y1);
+  GD.cmd32(x2); GD.cmd32(y2);
+  GD.cmd32(x3); GD.cmd32(y3);
+
+  GD.cmd32(bx1); GD.cmd32(by1);
+  GD.cmd32(bx1); GD.cmd32(by3);
+  GD.cmd32(bx3); GD.cmd32(by3);
+  GD.cmd32(0);
+
+  // Draw the quad
+  GD.Vertex2f(0, 0);
+}
+
+void draw_faces(int dir)
+{
+  int R = 15;
+  const PROGMEM int8_t *p = CUBE_faces; 
+  byte n;
+
+  GD.BlendFunc(ONE, ONE_MINUS_SRC_ALPHA);
+  GD.Begin(BITMAPS);
+
+  byte i = 0;
+  while ((n = pgm_read_byte_near(p++)) != 0xff) {
+    int8_t nx = pgm_read_byte_near(p++);
+    int8_t ny = pgm_read_byte_near(p++);
+    int8_t nz = pgm_read_byte_near(p++);
+    byte v1 = pgm_read_byte_near(p);
+    byte v2 = pgm_read_byte_near(p + 1);
+    byte v3 = pgm_read_byte_near(p + 2);
+    p += n;
+
+    long x1 = projected[v1].x;
+    long y1 = projected[v1].y;
+    long x2 = projected[v2].x;
+    long y2 = projected[v2].y;
+    long x3 = projected[v3].x;
+    long y3 = projected[v3].y;
+    long area = (x1 - x3) * (y2 - y1) - (x1 - x2) * (y3 - y1);
+    byte face = (area < 0);
+    if (face == dir) {
+      uint16_t r = 80, g = 40, b = 0;  // Ambient
+
+      if (face) {
+        transform_normal(nx, ny, nz);
+        int d = max(0, -nz);                      // diffuse light from +ve Z
+        r += 2 * d;
+        g += 2 * d;
+        b += 2 * d;
+      }
+      r = constrain(r, 192, 255);
+      GD.ColorRGB(min(255, r), min(255, g), min(255, b));
+      GD.BitmapHandle(face);
+      GD.Cell(i);
+      i = (i + 1) & 3;
+
+      x1 >>= 4;
+      y1 >>= 4;
+      x2 >>= 4;
+      y2 >>= 4;
+      x3 >>= 4;
+      y3 >>= 4;
+      quad(x1, y1, x2, y2, x3, y3,
+           80 - 90, 64 - 90,
+           80 + 90, 64 + 90);
+    }
+  }
+}
+
+/*****************************************************************/
+
+/* simple trackball-like motion control */
+/* Based on projtex.c - by David Yu and David Blythe, SGI */
+
+float angle, axis[3] = {0,1,0};
+float lastPos[3];
+
+void
+ptov(int x, int y, int width, int height, float v[3])
+{
+  float d, a;
+
+  /* project x,y onto a hemi-sphere centered within width, height */
+  v[0] = (2.0 * x - width) / width;
+  v[1] = (2.0 * y - height) / height;
+  d = sqrt(v[0] * v[0] + v[1] * v[1]);
+  v[2] = cos((M_PI / 2.0) * ((d < 1.0) ? d : 1.0));
+  a = 1.0 / sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+  v[0] *= a;
+  v[1] *= a;
+  v[2] *= a;
+}
+
+void
+startMotion(int x, int y)
+{
+  angle = 0.0;
+  ptov(x, y, GD.w, GD.h, lastPos);
+}
+
+void
+trackMotion(int x, int y)
+{
+  float curPos[3], dx, dy, dz;
+
+  ptov(x, y, GD.w, GD.h, curPos);
+
+  dx = curPos[0] - lastPos[0];
+  dy = curPos[1] - lastPos[1];
+  dz = curPos[2] - lastPos[2];
+  angle = (M_PI / 2) * sqrt(dx * dx + dy * dy + dz * dz);
+
+  axis[0] = lastPos[1] * curPos[2] - lastPos[2] * curPos[1];
+  axis[1] = lastPos[2] * curPos[0] - lastPos[0] * curPos[2];
+  axis[2] = lastPos[0] * curPos[1] - lastPos[1] * curPos[0];
+
+  float mag = 1 / sqrt(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]);
+  axis[0] *= mag;
+  axis[1] *= mag;
+  axis[2] *= mag;
+
+  lastPos[0] = curPos[0];
+  lastPos[1] = curPos[1];
+  lastPos[2] = curPos[2];
+}
+
+/*****************************************************************/
+
+uint32_t f0;
+int qq;
+
+class MoviePlayer
+{
+  uint16_t wp;
+  Reader r;
+  void loadsector() {
+    byte buf[512];
+    GD.__end();
+    r.readsector(buf);
+    GD.resume();
+    GD.wr_n(0x0f0000UL + wp, buf, 512);
+    wp += 512;
+  }
+
+public:
+  int begin(const char *filename) {
+    GD.__end();
+    if (!r.openfile(filename)) {
+      Serial.println("Open failed");
+      return 0;
+    }
+    GD.resume();
+
+uint32_t t0 = millis();
+    wp = 0;
+    while (wp < 0xfe00U)
+      loadsector();
+    uint32_t took = (millis() - t0);
+Serial.println(took);
+Serial.print(1000L * wp / took);
+Serial.println(" bytes/s");
+
+    GD.cmd_mediafifo(0x0f0000UL, 0x10000UL);
+    GD.cmd_regwrite(REG_MEDIAFIFO_WRITE, wp);
+GD.finish();
+
+    if (0) {
+      GD.cmd_playvideo(OPT_MEDIAFIFO);
+    } else {
+      GD.cmd_videostart();
+    }
+
+f0 = millis();
+    return 1;
+  }
+  int play() {
+    if (r.eof()) {
+      return 0;
+    } else {
+      byte buf[512];
+
+      uint16_t fullness = wp - GD.rd16(REG_MEDIAFIFO_READ);
+      qq = 0;
+      while (fullness < 0xfe00U) {
+        loadsector();
+        fullness += 512;
+        qq += 512;
+      }
+      GD.wr16(REG_MEDIAFIFO_WRITE, wp);
+      return 1;
+    }
+  }
+};
+
+MoviePlayer mp;
+
+/*****************************************************************/
+
+#define BG 25
+
+Bitmap background;
+
+void cube_setup()
+{
+  GD.Clear();
+  GD.cmd_text(GD.w / 2, GD.h / 2, 31, OPT_CENTER, "Loading video");
+  GD.BitmapHandle(0);
+  GD.cmd_setbitmap(0, RGB565, 160, 128);
+  GD.BitmapHandle(1);
+  GD.cmd_setbitmap(0, RGB565, 160, 128);
+  GD.swap();
+
+  mp.begin("70s_tv18.avi");
+  GD.Clear();
+  GD.swap();
+
+  GD.BitmapHandle(FACE_FRONT);
+  GD.BitmapSize(BILINEAR, BORDER, BORDER, GD.w, GD.h);
+  GD.BitmapSource(GD.loadptr);
+  GD.BitmapHandle(FACE_BACK);
+  GD.BitmapSize(NEAREST, BORDER, BORDER, GD.w, GD.h);
+  GD.BitmapSource(GD.loadptr);
+  Serial.println(__LINE__);
+
+  startMotion(240, 136);
+  trackMotion(247, 138);
+}
+
+byte prev_touching;
+
+void cube_loop()
+{
+  unsigned long t0 = micros();
+  mp.play();
+  unsigned long took = micros() - t0;
+  GD.get_inputs();
+  GD.cmd_videoframe(GD.loadptr, 0xefffcUL);
+
+  GD.Clear();
+  GD.ColorRGB(48, 48, 90);
+  // background.wallpaper();
+
+  GD.ColorRGB(255, 255, 255);
+
+  if (!prev_touching && GD.inputs.touching)
+    startMotion(GD.inputs.x, GD.inputs.y);
+  else if (GD.inputs.touching)
+    trackMotion(GD.inputs.x, GD.inputs.y);
+  prev_touching = GD.inputs.touching;
+
+  if (angle != 0.0f)
+    rotation(angle, axis);
+
+  project();
+  draw_faces(FACE_BACK);
+  draw_faces(FACE_FRONT);
+
+  GD.swap();
+
+  // GD.dumpscreen();
+}
+
+void setup()
+{
+  GD.begin();
+  LOAD_ASSETS();
+}
+
+int cmap(int value, int fromLow, int fromHigh, int toLow, int toHigh)
+{
+  return map(constrain(value, fromLow, fromHigh), fromLow, fromHigh, toLow, toHigh);
+}
+
+int t;
+
+void loop()
+{
+  GD.ClearColorRGB(0xffffff);
+  GD.Clear();
+
+  GD.ColorRGB(0x000000);
+  GD.LineWidth(PIXELS(24));
+  GD.Begin(RECTS);
+  int r = 32;
+  GD.Vertex2ii(r, r);
+  GD.Vertex2ii(GD.w - r, GD.h - r);
+
+  int g = cmap(t, 60, 100, 0, 255);
+  GD.ColorRGB(g, g, g);
+  bitmaps.gd.draw(GD.w / 2, GD.h / 2 - 20);
+
+  g = cmap(t, 100, 130, 0, 255);
+  GD.ColorRGB(g, g, g);
+  GD.Begin(LINES);
+  GD.LineWidth(PIXELS(10));
+  int y = PIXELS(GD.h / 2 + 15);
+  for (int i = -1; i < 2; i++) {
+    int x = PIXELS(GD.w / 2 + 45 * i);
+    GD.Vertex2f(x, y);
+    GD.Vertex2f(x, cmap(t, 120, 210, y, PIXELS(GD.h)));
+  }
+  GD.swap();
+  t++;
+  if (t == 300) {
+    cube_setup();
+    for (;;)
+      cube_loop();
+  }
+} //' }A