Advertisement
Garey

OpenGL Glass

Nov 27th, 2019
650
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.68 KB | None | 0 0
  1. #include <GL/freeglut.h>
  2.  
  3. #include <cmath>
  4. #include <cstring>
  5. #include <iostream>
  6. #include <fstream>
  7. #include <regex>
  8.  
  9.  
  10. const struct OBJ_COLOR {
  11.     GLfloat red, green, blue, alpha;
  12.     OBJ_COLOR() : red(0.20f), green(0.59f), blue(0.86f), alpha(1.0f) {}
  13. } OBJ_COLOR;
  14.  
  15. typedef struct vertex {
  16.     double x, y, z;
  17. } vertex;
  18. typedef struct face_triangle {
  19.     unsigned long v1, v2, v3;
  20. } face_triangle;
  21. typedef struct face_quad {
  22.     unsigned long v1, v2, v3, v4;
  23. } face_quad;
  24.  
  25. std::vector<vertex> vertices;
  26. std::vector<face_quad> faces_quads;
  27. std::vector<face_triangle> faces_triangles;
  28.  
  29. bool is_quad;
  30. bool render_mode; // true = solid body, false = wireframe
  31.  
  32. const float RESCALE = 0.00125f;
  33. const float ZOOM_SPEED = 1.0f;
  34. const float ROTATE_SPEED = 0.1f;
  35. float       DISTANCE = 4.0f;
  36.  
  37. struct camera {
  38.     GLfloat x, y, z, phi, theta;
  39.     camera() : x(-4.0f), y(2.0f), z(0.0f), phi(0), theta(0) {}
  40. } camera;
  41.  
  42. void init() {
  43.     glShadeModel(GL_SMOOTH);
  44.     glClearColor(0.f, 0.3f, 0.3f, 1.0f);
  45.     glClearDepth(0.9f);
  46.     glEnable(GL_DEPTH_TEST);
  47.     glDepthFunc(GL_LEQUAL);
  48.     glEnable(GL_COLOR);
  49.     glEnable(GL_COLOR_MATERIAL);
  50.     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
  51.  
  52.     glEnable(GL_LIGHTING);
  53.     glEnable(GL_NORMALIZE);
  54.     glEnable(GL_LIGHT1);
  55.     GLfloat lightAmbient1[4] = { 0.2f, 0.2f, 0.2f, 1.0f };
  56.     GLfloat lightPos1[4] = { 0.5, 0.5, 0.5, 1.0 };
  57.     GLfloat lightDiffuse1[4] = { 0.8f, 0.8f, 0.8f, 1.0f };
  58.     GLfloat lightSpec1[4] = { 1.0, 1.0, 1.0, 1.0 };
  59.     GLfloat lightLinAtten = 0.0f;
  60.     GLfloat lightQuadAtten = 1.0f;
  61.     glLightfv(GL_LIGHT1, GL_POSITION, (GLfloat *)&lightPos1);
  62.     glLightfv(GL_LIGHT1, GL_AMBIENT, (GLfloat *)&lightAmbient1);
  63.     glLightfv(GL_LIGHT1, GL_DIFFUSE, (GLfloat *)&lightDiffuse1);
  64.     glLightfv(GL_LIGHT1, GL_SPECULAR, (GLfloat *)&lightSpec1);
  65.     glLightfv(GL_LIGHT1, GL_LINEAR_ATTENUATION, &lightLinAtten);
  66.     glLightfv(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, &lightQuadAtten);
  67.     glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
  68.  
  69. }
  70.  
  71. auto calculate_normal(face_triangle f, GLdouble *normal) -> void {
  72.     // x
  73.     normal[0] = (vertices[f.v2 - 1].y - vertices[f.v1 - 1].y) * (vertices[f.v3 - 1].z - vertices[f.v1 - 1].z)
  74.         - (vertices[f.v3 - 1].y - vertices[f.v1 - 1].y) * (vertices[f.v2 - 1].z - vertices[f.v1 - 1].z);
  75.     // y
  76.     normal[1] = (vertices[f.v2 - 1].z - vertices[f.v1 - 1].z) * (vertices[f.v3 - 1].x - vertices[f.v1 - 1].x)
  77.         - (vertices[f.v2 - 1].x - vertices[f.v1 - 1].x) * (vertices[f.v3 - 1].z - vertices[f.v1 - 1].z);
  78.     // z
  79.     normal[2] = (vertices[f.v2 - 1].x - vertices[f.v1 - 1].x) * (vertices[f.v3 - 1].y - vertices[f.v1 - 1].y)
  80.         - (vertices[f.v3 - 1].x - vertices[f.v1 - 1].x) * (vertices[f.v2 - 1].y - vertices[f.v1 - 1].y);
  81. }
  82.  
  83. auto draw_obj() -> void {
  84.     if (render_mode) {
  85.         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  86.     }
  87.     else {
  88.         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  89.     }
  90.     if (is_quad) {
  91.         for (face_quad f : faces_quads) {
  92.             // Calculate normal by calculating two tri normals & averaging
  93.             face_triangle f_tri1 = { f.v1, f.v2, f.v3 };
  94.             face_triangle f_tri2 = { f.v2, f.v3, f.v4 };
  95.             GLdouble normal_tri1[3];
  96.             GLdouble normal_tri2[3];
  97.             calculate_normal(f_tri1, normal_tri1);
  98.             calculate_normal(f_tri2, normal_tri2);
  99.             GLdouble normal[3] = {
  100.                     (normal_tri1[0] + normal_tri2[0]) / 2,
  101.                     (normal_tri1[1] + normal_tri2[1]) / 2,
  102.                     (normal_tri1[2] + normal_tri2[2]) / 2
  103.             };
  104.  
  105.             glBegin(GL_QUADS);
  106.             glColor3f(OBJ_COLOR.red, OBJ_COLOR.green, OBJ_COLOR.blue);
  107.             glNormal3dv(normal);
  108.             if (vertices.size() < 5000) {
  109.                 glVertex3d(vertices[f.v1 - 1].x, vertices[f.v1 - 1].y, vertices[f.v1 - 1].z);
  110.                 glVertex3d(vertices[f.v2 - 1].x, vertices[f.v2 - 1].y, vertices[f.v2 - 1].z);
  111.                 glVertex3d(vertices[f.v3 - 1].x, vertices[f.v3 - 1].y, vertices[f.v3 - 1].z);
  112.                 glVertex3d(vertices[f.v4 - 1].x, vertices[f.v4 - 1].y, vertices[f.v4 - 1].z);
  113.             }
  114.             else {
  115.                 glVertex3d(vertices[f.v1 - 1].x * RESCALE, vertices[f.v1 - 1].y * RESCALE, vertices[f.v1 - 1].z * RESCALE);
  116.                 glVertex3d(vertices[f.v2 - 1].x * RESCALE, vertices[f.v2 - 1].y * RESCALE, vertices[f.v2 - 1].z * RESCALE);
  117.                 glVertex3d(vertices[f.v3 - 1].x * RESCALE, vertices[f.v3 - 1].y * RESCALE, vertices[f.v3 - 1].z * RESCALE);
  118.                 glVertex3d(vertices[f.v4 - 1].x * RESCALE, vertices[f.v4 - 1].y * RESCALE, vertices[f.v4 - 1].z * RESCALE);
  119.             }
  120.            
  121.             glEnd();
  122.         }
  123.     }
  124.     else {
  125.         for (face_triangle f : faces_triangles) {
  126.             GLdouble normal[3];
  127.             calculate_normal(f, normal);
  128.             glBegin(GL_TRIANGLES);
  129.             glColor3f(OBJ_COLOR.red, OBJ_COLOR.green, OBJ_COLOR.blue);
  130.             glNormal3dv(normal);
  131.             glVertex3d(vertices[f.v1 - 1].x, vertices[f.v1 - 1].y, vertices[f.v1 - 1].z);
  132.             glVertex3d(vertices[f.v2 - 1].x, vertices[f.v2 - 1].y, vertices[f.v2 - 1].z);
  133.             glVertex3d(vertices[f.v3 - 1].x, vertices[f.v3 - 1].y, vertices[f.v3 - 1].z);
  134.             glEnd();
  135.         }
  136.     }
  137.     glFlush();
  138. }
  139.  
  140. auto reshape(int w, int h) -> void {
  141.     glViewport(0, 0, w, h);
  142.     glMatrixMode(GL_PROJECTION);
  143.     glLoadIdentity();
  144.     if (h == 0) {
  145.         gluPerspective(80, (float)w, 1.0, 5000.0);
  146.     }
  147.     else {
  148.         gluPerspective(80, (float)w / (float)h, 1.0, 5000.0);
  149.     }
  150.     glMatrixMode(GL_MODELVIEW);
  151.     glLoadIdentity();
  152. }
  153.  
  154. auto arrow_keys(int key, int x, int y) -> void {
  155.     switch (key) {
  156.         case GLUT_KEY_LEFT:
  157.             camera.theta -= ROTATE_SPEED;
  158.             break;
  159.  
  160.         case GLUT_KEY_RIGHT:
  161.             camera.theta += ROTATE_SPEED;
  162.             break;
  163.  
  164.         default:
  165.             break;
  166.     }
  167. }
  168.  
  169. auto keyboard(unsigned char key, int x, int y) -> void {
  170.     switch (key) {
  171.     case 27:
  172.         exit(0);
  173.     case 's':
  174.         render_mode = true;
  175.         break;
  176.     case 'w':
  177.         render_mode = false;
  178.         break;
  179.     default:
  180.         break;
  181.     }
  182. }
  183.  
  184. auto mouseWheel(int button, int dir, int x, int y) -> void {
  185.     if (dir > 0)
  186.         DISTANCE -= ZOOM_SPEED;
  187.     else
  188.         DISTANCE += ZOOM_SPEED;
  189. }
  190.  
  191. auto display() -> void {
  192.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  193.     glLoadIdentity();
  194.  
  195.     camera.x = DISTANCE * cos(camera.phi)*sin(camera.theta);
  196.     camera.y = 2.0f + DISTANCE * sin(camera.phi)*sin(camera.theta);
  197.     camera.z = DISTANCE * cos(camera.theta);
  198.  
  199.     gluLookAt(camera.x, camera.y, camera.z, 0, 2.0f, 0, 0.0f, 1.0f, 0.0f);
  200.     draw_obj();
  201.     glutSwapBuffers();
  202.     glutPostRedisplay();
  203. }
  204.  
  205. auto obj_parse(char *file_line) -> void {
  206.  
  207.     if (file_line[0] == '\0') {
  208.         // End of file
  209.         return;
  210.     }
  211.  
  212.     char *tokenized;
  213.     tokenized = strtok(file_line, " ");
  214.     char first_char = tokenized[0];
  215.  
  216.     if (first_char == '#') {
  217.         // Comment line, ignore
  218.         return;
  219.     }
  220.     else if (first_char == 'v') {
  221.         // Vertex
  222.  
  223.         double x = strtod(strtok(NULL, " "), NULL);
  224.         double y = strtod(strtok(NULL, " "), NULL);
  225.         double z = strtod(strtok(NULL, " "), NULL);
  226.  
  227.         vertex v = { x * 20, y * 20, z * 20 };
  228.         vertices.push_back(v);
  229.     }
  230.     else if (first_char == 'f') {
  231.         // Face
  232.  
  233.         unsigned long v1 = strtoul(strtok(NULL, " "), NULL, 0);
  234.         unsigned long v2 = strtoul(strtok(NULL, " "), NULL, 0);
  235.         unsigned long v3 = strtoul(strtok(NULL, " "), NULL, 0);
  236.  
  237.         unsigned long v4;
  238.         char *v4_str = strtok(NULL, " ");
  239.         if (v4_str != NULL) {
  240.             // Face is a quad
  241.             v4 = strtoul(v4_str, NULL, 0);
  242.  
  243.             face_quad f = { v1, v2, v3, v4 };
  244.             faces_quads.push_back(f);
  245.         }
  246.         else {
  247.             // Face is a triangle
  248.             face_triangle f = { v1, v2, v3 };
  249.             faces_triangles.push_back(f);
  250.         }
  251.     }
  252. }
  253.  
  254. void open_obj(int argc, char *argv[]) {
  255.  
  256.     //// Argument parsing ////
  257.  
  258.     if (argc < 2) {
  259.         // No object name passed in, show help & quit
  260.         std::cout << "Usage:" << std::endl;
  261.         std::cout << argv[0] << " <.obj filename>" << std::endl;
  262.         exit(1);
  263.     }
  264.  
  265.     std::string filename = argv[1];
  266.  
  267.     std::regex obj_regex(".+(\\.obj)$");
  268.     if (!std::regex_match(filename, obj_regex)) {
  269.         // Filename is invalid
  270.         std::cout << "This application only accepts *.obj files, exiting..." << std::endl;
  271.         exit(1);
  272.     }
  273.  
  274.     //// Filename accepted, attempting to open ////
  275.  
  276.     std::cout << "Opening file: " << filename << std::endl;
  277.  
  278.     std::ifstream file_stream;
  279.     file_stream.open(filename, std::ifstream::in);
  280.  
  281.     if ((file_stream.rdstate() & std::ifstream::failbit) != 0) {
  282.         std::cerr << "Error opening " << filename << std::endl;
  283.         exit(1);
  284.     }
  285.  
  286.     while (file_stream.good()) {
  287.         char file_line[100];
  288.         file_stream.getline(file_line, 100);
  289.         obj_parse(file_line);
  290.     }
  291.  
  292.     file_stream.close();
  293.  
  294.     is_quad = (faces_quads.size() > faces_triangles.size());
  295. }
  296.  
  297. int main(int argc, char *argv[]) {
  298.     open_obj(argc, argv);
  299.     // initialize rendering with solid body
  300.     render_mode = false;
  301.  
  302.     int window;
  303.     glutInit(&argc, argv);
  304.     glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);
  305.     glutInitWindowSize(960, 720);
  306.     glutInitWindowPosition(0, 0);
  307.     window = glutCreateWindow("ConsoleApplication27");
  308.     init();
  309.     glutDisplayFunc(display);
  310.     glutReshapeFunc(reshape);
  311.     glutSpecialFunc(arrow_keys);
  312.     glutKeyboardFunc(keyboard);
  313.     glutMouseWheelFunc(mouseWheel);
  314.     glutMainLoop();
  315. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement