Advertisement
theblackshibe

Untitled

May 20th, 2021
1,039
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.78 KB | None | 0 0
  1. extern TFT_eSPI tft;
  2. extern WiFiUDP udp;
  3.  
  4. const float display_width = 320;
  5. const float display_height = 480;
  6. const int frame_budget_ms = 32; // target 30 fps
  7. const int pi = 3.14159;
  8.  
  9. struct vector3 {
  10.     float x, y, z;
  11. };
  12.  
  13. struct triangle {
  14.     vector3 points[3];
  15. };
  16.  
  17. struct mesh {
  18.     vector<triangle> tris = {};
  19. };
  20.  
  21. struct matrix4x4 {
  22.     float m[4][4] = { { 0 } };
  23. };
  24.  
  25. class renderer {
  26.    
  27.     private:
  28.         mesh mesh_cube;
  29.         matrix4x4 matrix_projection;
  30.         String current_mesh_name = "Default";
  31.         vector<triangle> last_drawn_tris = {};
  32.         vector3 camera;
  33.  
  34.         unsigned long next_signal_send = millis() + 1000;
  35.         float f_near = 0.1;
  36.         float f_far = 1000;
  37.         float fov = 90;
  38.         float aspect_ratio = display_height / display_width;
  39.         float f_fov_rad = 1 / tanf(fov * 0.5 / 180 * pi);
  40.         float f_theta = 0;
  41.  
  42.         void multiply_matrix_vector(vector3 &i, vector3 &o, matrix4x4 &m) {
  43.             o.x = i.x * m.m[0][0] + i.y * m.m[1][0] + i.z * m.m[2][0] + m.m[3][0];
  44.             o.y = i.x * m.m[0][1] + i.y * m.m[1][1] + i.z * m.m[2][1] + m.m[3][1];
  45.             o.z = i.x * m.m[0][2] + i.y * m.m[1][2] + i.z * m.m[2][2] + m.m[3][2];
  46.             float w = i.x * m.m[0][3] + i.y * m.m[1][3] + i.z * m.m[2][3] + m.m[3][3];
  47.  
  48.             if (w != 0.0f)
  49.             {
  50.                 o.x /= w;
  51.                 o.y /= w;
  52.                 o.z /= w;
  53.             }
  54.         }
  55.  
  56.         String split_string(String data, char separator, int index)
  57.         {
  58.             int found = 0;
  59.             int strIndex[] = {0, -1};
  60.             int maxIndex = data.length()-1;
  61.  
  62.             for(int i=0; i<=maxIndex && found<=index; i++){
  63.                 if(data.charAt(i)==separator || i==maxIndex){
  64.                     found++;
  65.                     strIndex[0] = strIndex[1]+1;
  66.                     strIndex[1] = (i == maxIndex) ? i+1 : i;
  67.                 }
  68.             }
  69.  
  70.             return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
  71.         }
  72.  
  73.     public:
  74.         void setup() {
  75.  
  76.             mesh_cube.tris = {
  77.  
  78.                 // SOUTH
  79.                 { 0, 0, 0,    0, 1, 0,    1, 1, 0 },
  80.                 { 0, 0, 0,    1, 1, 0,    1, 0, 0 },
  81.  
  82.                 // EAST                                                      
  83.                 { 1, 0, 0,    1, 1, 0,    1, 1, 1 },
  84.                 { 1, 0, 0,    1, 1, 1,    1, 0, 1 },
  85.  
  86.                 // NORTH                                                    
  87.                 { 1, 0, 1,    1, 1, 1,    0, 1, 1 },
  88.                 { 1, 0, 1,    0, 1, 1,    0, 0, 1 },
  89.  
  90.                 // WEST                                                      
  91.                 { 0, 0, 1,    0, 1, 1,    0, 1, 0 },
  92.                 { 0, 0, 1,    0, 1, 0,    0, 0, 0 },
  93.  
  94.                 // TOP                                                      
  95.                 { 0, 1, 0,    0, 1, 1,    1, 1, 1 },
  96.                 { 0, 1, 0,    1, 1, 1,    1, 1, 0 },
  97.  
  98.                 // BOTTOM                                                    
  99.                 { 1, 0, 1,    0, 0, 1,    0, 0, 0 },
  100.                 { 1, 0, 1,    0, 0, 0,    1, 0, 0 },
  101.  
  102.             };
  103.  
  104.             matrix_projection.m[0][0] = aspect_ratio * f_fov_rad;
  105.             matrix_projection.m[1][1] = f_fov_rad;
  106.             matrix_projection.m[2][2] = f_far / (f_far - f_near);
  107.             matrix_projection.m[3][2] = (-f_far * f_near) / (f_far - f_near);
  108.             matrix_projection.m[2][3] = 1;
  109.             matrix_projection.m[3][3] = 0;
  110.  
  111.             tft.fillScreen(TFT_BLACK);
  112.         }
  113.  
  114.         void upload(String filename) {
  115.  
  116.             // o = filename
  117.             // p = eof
  118.             // f, v = vertex data
  119.  
  120.             tft.fillScreen(TFT_BLACK);
  121.             tft.setTextSize(2);
  122.             tft.setCursor(40, 40);
  123.             tft.print("uploading file");
  124.  
  125.             tft.setCursor(40, 60);
  126.             tft.setTextSize(1);
  127.             tft.print(filename);
  128.  
  129.             // fresh data
  130.             current_mesh_name = filename;
  131.             vector<vector3> vertices = {};
  132.             mesh_cube.tris = {};
  133.  
  134.             bool finished = false;
  135.             String last_uploaded;
  136.             while (!finished) {
  137.  
  138.                 // read data
  139.                 String data = Serial.readStringUntil('\n');
  140.                 String command = split_string(data, ' ', 0);
  141.                 String arg1 = split_string(data, ' ', 1);
  142.                 String arg2 = split_string(data, ' ', 2);
  143.                 String arg3 = split_string(data, ' ', 3);
  144.  
  145.                 // print data
  146.                 if (last_uploaded != command) {
  147.                     tft.setCursor(40, tft.cursor_y);
  148.                     tft.println("uploading data with sign " + command);
  149.                     last_uploaded = command;
  150.                 }
  151.  
  152.                 // reset display if it overflows
  153.                 if (tft.cursor_y > display_height-40) {
  154.                     tft.fillRect(40, 60, display_width, display_height-40, TFT_BLACK);
  155.                     tft.setCursor(40, 60);
  156.                 }
  157.  
  158.                 if (command == "v") {
  159.                     vector3 new_vector;
  160.                     new_vector.x = arg1.toFloat();
  161.                     new_vector.y = arg2.toFloat();
  162.                     new_vector.z = arg3.toFloat();
  163.                     vertices.push_back(new_vector);
  164.                 }
  165.  
  166.                 if (command == "f") {
  167.                     int f[3];
  168.                     f[0] = arg1.toInt();
  169.                     f[1] = arg2.toInt();
  170.                     f[2] = arg3.toInt();
  171.                     mesh_cube.tris.push_back({ vertices[f[0] - 1], vertices[f[1] - 1], vertices[f[2] - 1] });
  172.                 }
  173.  
  174.                 // finish sign
  175.                 if (command == "p") {
  176.                     tft.setCursor(40, tft.cursor_y);
  177.                     tft.println("finished");
  178.                     finished = true;
  179.                     delay(1000);
  180.                 }
  181.  
  182.                 // write some data to tell the python program something is happening
  183.                 Serial.write("2");
  184.             }
  185.  
  186.             vertices.clear();
  187.         }
  188.  
  189.         void loop() {
  190.  
  191.             // start time
  192.             unsigned long frame_start_time = millis();
  193.             f_theta += 0.01;
  194.  
  195.             // assume incoming mesh information
  196.             // .obj is encoded with regular text
  197.             // also a periodic signal to tell the python program that no upload is taking place
  198.             if (Serial.available()) {
  199.                 String data = Serial.readStringUntil('\n');
  200.                 if (data[0] == 'o') {
  201.                     upload(data.substring(2, -1));
  202.                     return;
  203.                 }
  204.             } else if (millis() > next_signal_send) {
  205.                 Serial.write("1");
  206.                 next_signal_send = millis() + 1000;
  207.             }
  208.  
  209.             // clearing the screen
  210.             delay(10); // wait for 25ms longer to make the displayed image last longer
  211.             for (auto tri : last_drawn_tris) {
  212.                  tft.drawTriangle(
  213.                     tri.points[0].x, tri.points[0].y,
  214.                     tri.points[1].x, tri.points[1].y,
  215.                     tri.points[2].x, tri.points[2].y,
  216.                     TFT_BLACK
  217.                  );
  218.             }
  219.  
  220.             last_drawn_tris.clear();
  221.             matrix4x4 matrix_rotationZ;
  222.             matrix4x4 matrix_rotationX;
  223.  
  224.             // Rotation Z
  225.             matrix_rotationZ.m[0][0] = cosf(f_theta);
  226.             matrix_rotationZ.m[0][1] = sinf(f_theta);
  227.             matrix_rotationZ.m[1][0] = -sinf(f_theta);
  228.             matrix_rotationZ.m[1][1] = cosf(f_theta);
  229.             matrix_rotationZ.m[2][2] = 1;
  230.             matrix_rotationZ.m[3][3] = 1;
  231.  
  232.             // Rotation X
  233.             matrix_rotationX.m[0][0] = 1;
  234.             matrix_rotationX.m[1][1] = cosf(f_theta * 0.5f);
  235.             matrix_rotationX.m[1][2] = sinf(f_theta * 0.5f);
  236.             matrix_rotationX.m[2][1] = -sinf(f_theta * 0.5f);
  237.             matrix_rotationX.m[2][2] = cosf(f_theta * 0.5f);
  238.             matrix_rotationX.m[3][3] = 1;
  239.  
  240.  
  241.             for (auto tri : mesh_cube.tris) {
  242.  
  243.                 triangle projected, translated, rotated_z, rotated_zx;
  244.  
  245.                 // Rotate in Z-Axis
  246.                 multiply_matrix_vector(tri.points[0], rotated_z.points[0], matrix_rotationZ);
  247.                 multiply_matrix_vector(tri.points[1], rotated_z.points[1], matrix_rotationZ);
  248.                 multiply_matrix_vector(tri.points[2], rotated_z.points[2], matrix_rotationZ);
  249.  
  250.                 // Rotate in X-Axis
  251.                 multiply_matrix_vector(rotated_z.points[0], rotated_zx.points[0], matrix_rotationX);
  252.                 multiply_matrix_vector(rotated_z.points[1], rotated_zx.points[1], matrix_rotationX);
  253.                 multiply_matrix_vector(rotated_z.points[2], rotated_zx.points[2], matrix_rotationX);
  254.  
  255.                 // Offset into the screen
  256.                 translated = rotated_zx;
  257.                 translated.points[0].z = rotated_zx.points[0].z + 6;
  258.                 translated.points[1].z = rotated_zx.points[1].z + 6;
  259.                 translated.points[2].z = rotated_zx.points[2].z + 6;
  260.  
  261.  
  262.  
  263.                 vector3 normal, line1, line2;
  264.                 line1.x = translated.points[1].x - translated.points[0].x;
  265.                 line1.y = translated.points[1].y - translated.points[0].x;
  266.                 line1.z = translated.points[1].z - translated.points[0].x;
  267.  
  268.                 line2.x = translated.points[2].x - translated.points[0].x;
  269.                 line2.y = translated.points[2].y - translated.points[0].x;
  270.                 line2.z = translated.points[2].z - translated.points[0].x;
  271.  
  272.                 normal.x = line1.y * line2.z - line1.z * line2.y;
  273.                 normal.y = line1.z * line2.x - line1.x * line2.z;
  274.                 normal.z = line1.x * line2.y - line1.y * line2.x;
  275.  
  276.                 float l = sqrtf(normal.x*normal.x + normal.y*normal.y + normal.z*normal.z);
  277.                 normal.x /= l; normal.y /= l; normal.z /= l;
  278.  
  279.                 if (normal.x * (translated.points[0].x - camera.x) + normal.y * (translated.points[0].y - camera.y) + normal.z * (translated.points[0].z - camera.z) < 0) {
  280.  
  281.                     multiply_matrix_vector(translated.points[0], projected.points[0], matrix_projection);
  282.                     multiply_matrix_vector(translated.points[1], projected.points[1], matrix_projection);
  283.                     multiply_matrix_vector(translated.points[2], projected.points[2], matrix_projection);
  284.    
  285.                     projected.points[0].x += 1; projected.points[0].y += 1;
  286.                     projected.points[1].x += 1; projected.points[1].y += 1;
  287.                     projected.points[2].x += 1; projected.points[2].y += 1;
  288.  
  289.                     projected.points[0].x *= 0.5 * display_width;
  290.                     projected.points[0].y *= 0.5 * display_height;
  291.                     projected.points[1].x *= 0.5 * display_width;
  292.                     projected.points[1].y *= 0.5 * display_height;
  293.                     projected.points[2].x *= 0.5 * display_width;
  294.                     projected.points[2].y *= 0.5 * display_height;
  295.  
  296.                     last_drawn_tris.push_back(projected);
  297.                     tft.drawTriangle(
  298.                         projected.points[0].x, projected.points[0].y,
  299.                         projected.points[1].x, projected.points[1].y,
  300.                         projected.points[2].x, projected.points[2].y,
  301.                         TFT_ORANGE
  302.                     );
  303.  
  304.                     /*
  305.                         tft.setCursor(projected.points[0].x, projected.points[0].y);
  306.                         tft.print((normal.x * (translated.points[0].x - camera.x) +
  307.                                    normal.y * (translated.points[0].y - camera.y) +
  308.                                     normal.z * (translated.points[0].z - camera.z)));
  309.                     */
  310.  
  311.                 }
  312.             };
  313.  
  314.             // profiling
  315.             unsigned long frame_end_time = millis();
  316.             int wait_time = frame_end_time - frame_start_time;
  317.  
  318.             tft.setCursor(0, 0);
  319.             tft.println("object: " + current_mesh_name + "");
  320.            
  321.             tft.print(int(wait_time));
  322.             tft.println("ms");
  323.  
  324.             tft.print(int(float(1000/wait_time)));
  325.             tft.println("fps");
  326.  
  327.             // if the frame budget is high enough, we can wait
  328.             delay(max(frame_budget_ms-wait_time, 0));
  329.         };
  330. };
  331.  
  332.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement