/*
*/
#include <Arduino.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#define BTN_PIN 5
#define TFT_DC 2
#define TFT_CS 15
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
#include "img_lib.h"
#include "d3.h"
#include "qsort.h"
#include "object.h"
#ifndef NDEBUG
#define DBG(fmt, ...) Serial.printf("[%9lu %s:%d] " fmt "\n", millis(), __func__, __LINE__, ##__VA_ARGS__)
#define TRACE() Serial.printf("[%9lu %s:%d]\n", millis(), __func__, __LINE__)
#else
#define DBG(fmt, ...)
#define TRACE()
#endif
#define WARN(fmt, ...) Serial.printf("\033[1;33m[%9lu %s:%d] " fmt "\e[0m\n", millis(), __func__, __LINE__, ##__VA_ARGS__)
#define ERR(fmt, ...) Serial.printf("\033[1;31m[%9lu %s:%d] " fmt "\e[0m\n", millis(), __func__, __LINE__, ##__VA_ARGS__)
void setup() {
pinMode(BTN_PIN, INPUT_PULLUP);
tft.begin();
tft.setRotation(1);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(1);
tft.print("Start");
Serial.begin(115200);
Serial.printf("Start !\n");
Serial.printf("Application " __FILE__ " compiled " __DATE__ " at " __TIME__ "\n");
DBG("This is a debug statement.");
WARN("This is a warning.");
ERR("This is an error.");
DBG("max alloc %u B.\n", ESP.getMaxAllocHeap());
DBG("Object has %u points, %u lines, %u triangles.", NPOINTS, NLINES, NTRIANGLES);
}
void loop() {
const int height = 200; // tft.height();
const int width = height; //tft.width()/2;
STATIC_IMG(img, width, height, IMG_TYPE_RGB565);
if (!img) {
while (true) {
ERR("alloc failed.");
delay(10);
}
}
uint32_t t0 = millis();
// Draw a 3D object
draw_obj(img);
uint32_t t1 = millis();
tft.drawRGBBitmap(0, 0, (uint16_t *)img->data, width, height);
uint32_t t2 = millis();
DBG("Draw in %u ms, blit in %u ms, max alloc %u B.\n", t1 - t0, t2 - t1, ESP.getMaxAllocHeap());
delay(10);
}
void draw_obj(img_t *img) {
DBG("draw_obj");
/* Draw a 3D object */
STATIC_MAT4X4(homogeneous_transform);
STATIC_MAT4X4(projection);
STATIC_MAT4X4(transf_proj);
STATIC_VEC4(translation);
translation->z = -5.0;
float alpha, beta, gamma;
int now_ms = millis();
beta = radians(now_ms / 6.);
gamma = beta / 10;
alpha = gamma / 30;
/* Define a homogeneous transform, from 3 rotations and a 3-axes translation */
//homogeneous_transform = ht_transform(homogeneous_transform, alpha, beta, gamma, translation);
homogeneous_transform = ht_transform_axis_angle(homogeneous_transform,
(vec4_t *) & ((const float []) {
0.0, 1.0, 0.0, 0.0
}),
radians(now_ms / 150.),
translation);
/* Define the projection matrix */
projection = ht_projection(projection, radians(45), img->w * 1.0 / img->h, 0.1, 1000.);
/* The projected transform matrix is composed of both */
transf_proj = mat4x4_prod(transf_proj, projection, homogeneous_transform);
static int points2d[NPOINTS][3];
static float points3d_transformed[NPOINTS][4];
STATIC_VEC4(v_proj);
DBG("transform vertices");
/* Transform and project points */
for (int i = 0; i < NPOINTS; i++) {
mat4x4_vec4_prod(v_proj, transf_proj, (vec4_t *)&points3d[i]);
if (abs(v_proj->w) < 1.0e-8) {
ERR("Point %d projection error.", i);
v_proj->w = 1.0;
}
points2d[i][0] = img->w * (0.5 + 1.0 * v_proj->x / v_proj -> w);
points2d[i][1] = img->h * (0.5 + 1.0 * v_proj->y / v_proj -> w);
points2d[i][2] = img->w * (0.5 + 1.0 * v_proj->z / v_proj -> w); // for triangles z-sort
// DBG("Point #%u: (%d,%d,%d)", i, points2d[i][0], points2d[i][1], points2d[i][2]);
// store points 3D coordinates (hacky...)
points3d_transformed[i][0] = v_proj->x;
points3d_transformed[i][1] = v_proj->y;
points3d_transformed[i][2] = v_proj->z;
}
/* Sort triangles by Z coordinate */
static int triangle_z[NTRIANGLES];
static int z_sort[NTRIANGLES];
static float lighting[NTRIANGLES];
/* Set light direction */
STATIC_VEC4(light_direction);
light_direction->x = cos(radians(now_ms / 6.));
light_direction->y = sin(radians(now_ms / 6.));
light_direction->z = 1.0;
vec4_normalize(light_direction);
DBG("compute triangle Z and normal");
/* Compute triangle Z, and normal-based lighting */
STATIC_VEC4(normal);
for (int i = 0; i < NTRIANGLES; i++) {
int p = triangles[i][0];
int q = triangles[i][1];
int r = triangles[i][2];
/* Compute triangle Z coordinate */
triangle_z[i] = -(points2d[p][2] + points2d[q][2] + points2d[r][2]) / 3;
/* Compute face orientation */
triangle_normal((float *)normal, (float *)points3d_transformed[p], (float *)points3d_transformed[q], (float *)points3d_transformed[r]);
lighting[i] = vec4_dot_prod(light_direction, normal);
}
/* sort triangles by average Z depth */
quicksort(triangle_z, z_sort, NTRIANGLES);
DBG("draw");
/* Clear picture */
img_fill(img, RGB565(0, 0, 0));
/* Draw triangles */
for (int i = 0; i < NTRIANGLES; i++) {
int t = z_sort[i];
int p = triangles[t][0];
int q = triangles[t][1];
int r = triangles[t][2];
int px = points2d[p][0], py = points2d[p][1];
int qx = points2d[q][0], qy = points2d[q][1];
int rx = points2d[r][0], ry = points2d[r][1];
// Each triangle a color
//uint16_t color = HSV2RGB565(256 * t / NTRIANGLES, 196, 128);
// Yellow, with Lambert lighting
uint16_t color = HSV2RGB565(32, 196, (uint8_t)(32 + 128 + 96 * lighting[t]));
img_fill_triangle(img, px, py, qx, qy, rx, ry, color);
}
/* Draw lines */
for (int i = 0; i < NLINES; i++) {
int p = lines[i][0];
int q = lines[i][1];
int px = points2d[p][0], py = points2d[p][1];
int qx = points2d[q][0], qy = points2d[q][1];
//img_draw_line(img, px, py, qx, qy, HSV2RGB565(256 * i / NLINES, 255, 255));
}
/* Draw points */
for (int i = 0; i < NPOINTS; i++) {
//img_draw_circle(img, points2d[i][0], points2d[i][1], 4, HSV2RGB565(256 * i / NPOINTS, 255, 255));
//img_putpixel(img, points2d[i][0], points2d[i][1], HSV2RGB565(256 * i / NPOINTS, 255, 255));
}
}
Loading
esp32-devkit-c-v4
esp32-devkit-c-v4