From 6506e559570b851441b7e4711c4465008fd4b99d Mon Sep 17 00:00:00 2001 From: sumotoy Date: Wed, 10 Jun 2015 23:46:32 +0200 Subject: [PATCH] added solid3d example --- solid3D/solid3D.ino | 306 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 306 insertions(+) create mode 100644 solid3D/solid3D.ino diff --git a/solid3D/solid3D.ino b/solid3D/solid3D.ino new file mode 100644 index 0000000..883247e --- /dev/null +++ b/solid3D/solid3D.ino @@ -0,0 +1,306 @@ +/* +From ucg, modified for use with all my libraries. +IMPORTANT! You need my modified Adafruit_GFX library! +https://github.com/sumotoy/Adafruit_GFX/ +*/ + + + +#include +#include +#include + +#ifndef _ADAFRUIT_GFX_VARIANT +#error you need the modified Adafruit_GFX library! +#endif + +#define __CS 10 +#define __DC 6 + +TFT_ILI9163C tft = TFT_ILI9163C(__CS, __DC); + +struct pt3d +{ + int x, y, z; +}; + +struct surface +{ + uint8_t p[4]; + int16_t z; +}; + +struct pt2d +{ + int x, y; + unsigned is_visible; +}; + + +// define the point at which the observer looks, 3d box will be centered there +#define MX (tft.width()/2) +#define MY (tft.height()/2) + +// define a value that corresponds to "1" +#define U 100 + +// eye to screen distance (fixed) +#define ZS U + +// cube edge length is 2*U +struct pt3d cube[8] = +{ + { -U, -U, U}, + { U, -U, U}, + { U, -U, -U}, + { -U, -U, -U}, + { -U, U, U}, + { U, U, U}, + { U, U, -U}, + { -U, U, -U}, +}; + +// define the surfaces +struct surface cube_surface[6] = +{ + { {0, 1, 2, 3}, 0 }, // bottom + { {4, 5, 6, 7}, 0 }, // top + { {0, 1, 5, 4}, 0 }, // back + + { {3, 7, 6, 2}, 0 }, // front + { {1, 2, 6, 5}, 0 }, // right + { {0, 3, 7, 4}, 0 }, // left +}; + +// define some structures for the copy of the box, calculation will be done there +struct pt3d cube2[8]; +struct pt2d cube_pt[8]; + +// will contain a rectangle border of the box projection into 2d plane +int x_min, x_max; +int y_min, y_max; + +const int16_t sin_tbl[65] = { + 0, 1606, 3196, 4756, 6270, 7723, 9102, 10394, 11585, 12665, 13623, 14449, 15137, 15679, 16069, 16305, 16384, 16305, 16069, 15679, + 15137, 14449, 13623, 12665, 11585, 10394, 9102, 7723, 6270, 4756, 3196, 1606, 0, -1605, -3195, -4755, -6269, -7722, -9101, -10393, + -11584, -12664, -13622, -14448, -15136, -15678, -16068, -16304, -16383, -16304, -16068, -15678, -15136, -14448, -13622, -12664, -11584, -10393, -9101, -7722, + -6269, -4755, -3195, -1605, 0 +}; + +const int16_t cos_tbl[65] = { + 16384, 16305, 16069, 15679, 15137, 14449, 13623, 12665, 11585, 10394, 9102, 7723, 6270, 4756, 3196, 1606, 0, -1605, -3195, -4755, + -6269, -7722, -9101, -10393, -11584, -12664, -13622, -14448, -15136, -15678, -16068, -16304, -16383, -16304, -16068, -15678, -15136, -14448, -13622, -12664, + -11584, -10393, -9101, -7722, -6269, -4755, -3195, -1605, 0, 1606, 3196, 4756, 6270, 7723, 9102, 10394, 11585, 12665, 13623, 14449, + 15137, 15679, 16069, 16305, 16384 +}; + + +void copy_cube(void) +{ + uint8_t i; + for (i = 0; i < 8; i++) + { + cube2[i] = cube[i]; + } +} + +void rotate_cube_y(uint16_t w) +{ + uint8_t i; + int16_t x, z; + /* + x' = x * cos(w) + z * sin(w) + z' = - x * sin(w) + z * cos(w) + */ + for (i = 0; i < 8; i++) + { + x = ((int32_t)cube2[i].x * (int32_t)cos_tbl[w] + (int32_t)cube2[i].z * (int32_t)sin_tbl[w]) >> 14; + z = (-(int32_t)cube2[i].x * (int32_t)sin_tbl[w] + (int32_t)cube2[i].z * (int32_t)cos_tbl[w]) >> 14; + //printf("%d: %d %d --> %d %d\n", i, cube2[i].x, cube2[i].z, x, z); + cube2[i].x = x; + cube2[i].z = z; + } +} + +void rotate_cube_x(uint16_t w) +{ + uint8_t i; + int16_t y, z; + for (i = 0; i < 8; i++) + { + y = ((int32_t)cube2[i].y * (int32_t)cos_tbl[w] + (int32_t)cube2[i].z * (int32_t)sin_tbl[w]) >> 14; + z = (-(int32_t)cube2[i].y * (int32_t)sin_tbl[w] + (int32_t)cube2[i].z * (int32_t)cos_tbl[w]) >> 14; + cube2[i].y = y; + cube2[i].z = z; + } +} + +void trans_cube(uint16_t z) +{ + uint8_t i; + for (i = 0; i < 8; i++) + { + cube2[i].z += z; + } +} + +void reset_min_max(void) +{ + x_min = 0x07fff; + y_min = 0x07fff; + x_max = -0x07fff; + y_max = -0x07fff; +} + +// calculate xs and ys from a 3d value +void convert_3d_to_2d(struct pt3d *p3, struct pt2d *p2) +{ + int32_t t; + p2->is_visible = 1; + if (p3->z >= ZS) + { + t = ZS; + t *= p3->x; + t <<= 1; + t /= p3->z; + if (t >= -MX && t <= MX - 1) + { + t += MX; + p2->x = t; + + if (x_min > t) x_min = t; + if (x_max < t) x_max = t; + + t = ZS; + t *= p3->y; + t <<= 1; + t /= p3->z; + if (t >= -MY && t <= MY - 1) + { + t += MY; + p2->y = t; + if (y_min > t) y_min = t; + if (y_max < t) y_max = t; + } + else + { + p2->is_visible = 0; + } + } + else + { + p2->is_visible = 0; + } + } + else + { + p2->is_visible = 0; + } +} + +void convert_cube(void) +{ + uint8_t i; + reset_min_max(); + for (i = 0; i < 8; i++) + { + convert_3d_to_2d(cube2 + i, cube_pt + i); + } +} + +void calculate_z(void) +{ + uint8_t i, j; + uint16_t z; + for (i = 0; i < 6; i++) + { + z = 0; + for (j = 0; j < 4; j++) + { + z += cube2[cube_surface[i].p[j]].z; + } + z /= 4; + cube_surface[i].z = z; + //printf("%d: z=%d\n", i, z); + } +} + +void draw_cube(void) +{ + uint8_t i, ii; + uint8_t skip_cnt = 3; /* it is known, that the first 3 surfaces are invisible */ + int16_t z, z_upper; + uint16_t color; + + z_upper = 32767; + for (;;) + { + ii = 6; + z = -32767; + for (i = 0; i < 6; i++) + { + if (cube_surface[i].z <= z_upper) + { + if (z < cube_surface[i].z) + { + z = cube_surface[i].z; + ii = i; + } + } + } + + if (ii >= 6) break; + z_upper = cube_surface[ii].z; + cube_surface[ii].z++; + + if (skip_cnt > 0) + { + skip_cnt--; + } + else + { + color = tft.Color565(((ii + 1) & 1) * 255, (((ii + 1) >> 1) & 1) * 255, (((ii + 1) >> 2) & 1) * 255); + tft.fillQuad( + cube_pt[cube_surface[ii].p[0]].x, cube_pt[cube_surface[ii].p[0]].y, + cube_pt[cube_surface[ii].p[1]].x, cube_pt[cube_surface[ii].p[1]].y, + cube_pt[cube_surface[ii].p[2]].x, cube_pt[cube_surface[ii].p[2]].y, + cube_pt[cube_surface[ii].p[3]].x, cube_pt[cube_surface[ii].p[3]].y, color); + + } + } +} + + + +void calc_and_draw(uint16_t w, uint16_t v) +{ + + copy_cube(); + rotate_cube_y(w); + rotate_cube_x(v); + trans_cube(U * 8); + convert_cube(); + calculate_z(); + draw_cube(); +} + + +void setup(void) +{ + tft.begin(); +} + +uint16_t w = 0; +uint16_t v = 0; + +void loop(void) +{ + calc_and_draw(w, v >> 3); + v += 3; + v &= 511; + w++; + w &= 63; + delay(10); + tft.fillRect(x_min, y_min, x_max - x_min + 3, y_max - y_min + 3, 0x0000); +} +