// Copyright (c) 2021. Pascal Syma <pascal@syma.dev> and Antonio Martinez Casadesus <acasadesus@stud.hs-bremen.de>. // All rights reserved. #include "oglwidget.h" #include <math.h> #include <iostream> #include <iomanip> #include <fstream> #include <string> #include <vector> #define PI 3.14159265358979323846 using namespace std; static double alpha = 45.0; // rotation angle class Vertex{ public: float _x, _y, _z; bool isNext; Vertex(); // empty constructor Vertex(float x, float y, float z); // constructor with initialization }; void subdivChaikin(int count, int amount); void subdivCubic(int count, int amount); Vertex::Vertex(){}; // empty constructor Vertex::Vertex(float x, float y, float z){ // constructor with initialization _x = x; _y = y; _z = z; isNext = false; } vector <Vertex> points; void loadData() { string fname = R"(C:\CLionProjects\cg\hw03\mesh1.obj)"; ifstream file( fname); if (!file){ cout << "error opening file" << endl; return; } string key; while( file){ //getline( file, line); file >> key; if (key == "v") { float x, y, z; file >> x >> y >> z; Vertex pVertex = *new Vertex(x, y, 0); points.push_back(pVertex); } } file.close(); int amount = points.size(); subdivChaikin(3, amount); subdivCubic(3, amount); } void subdivChaikin(int count, int amount) { // calculate needed matrix size int totalcount = amount - 1; for (int i = 0; i < count; ++i) { totalcount += totalcount-2; } float P[totalcount][2]; int i = 0; // copy verts to matrix for (auto vert : points) { P[i][0] = vert._x; P[i][1] = vert._y; i++; } int n = amount - 1; // iterate for detailed subdiv level for (int k = 0; k < count; ++k) { // init Mask float M[2*n-2][n]; // M = zeros(2*n-1, n) for (int x = 0; x < 2 * n - 2; ++x) { for (int y = 0; y < n; ++y) { M[x][y] = 0; } } // set fixed values at beginning and end of Mask M[0][0] = 1; M[1][0] = .5; M[1][1] = .5; M[2*n-3][ n-1] = 1; M[2*n-4][ n-1] = .5; M[2*n-4][ n-2] = .5; for (int j = 2; j < n-1; ++j) { M[2*j-2][j-1] = .75; M[2*j-2][j] = .25; M[2*j-1][j-1] = .25; M[2*j-1][j] = .75; } // matrix multiplication // l = 2*n-2 // m = n // n = 2 // A = M // B = P // init C for temp result of matmult float C[2*n-2][2]; for (int j = 0; j < 2 * n - 2; ++j) { C[j][0] = 0; C[j][1] = 0; } // actual matmult // C = M*P for (int i = 0; i < 2 * n - 2; ++i) { for (int k = 0; k < 2; ++k) { for (int j = 0; j < n; ++j) { C[i][k] += M[i][j] * P[j][k]; } } } // P = C for (int x = 0; x < 2*n-2; ++x) { for (int y = 0; y < 2; ++y) { P[x][y] = C[x][y]; } } n = 2*n-2; // store new subdiv verts in vert vector for (i = 0; i < n; ++i) { Vertex pVertex = *new Vertex(P[i][0], P[i][1], ((float) k) + 2); // isNext means start a new strip if (i == 0) pVertex.isNext = true; points.push_back(pVertex); } } } void subdivCubic(int count, int amount) { // calculate needed matrix size int totalcount = amount - 1; for (int i = 0; i < count; ++i) { totalcount += totalcount-1; } float P[totalcount][2]; int i = 0; // copy verts to matrix for (auto vert : points) { P[i][0] = vert._x; P[i][1] = vert._y; i++; if (i > amount) break; } int n = amount - 1; // iterate for detailed subdiv level for (int k = 0; k < count; ++k) { // init Mask float M[2*n-1][n]; // M = zeros(2*n-1, n) for (int x = 0; x < 2 * n - 1; ++x) { for (int y = 0; y < n; ++y) { M[x][y] = 0; } } // set fixed values at beginning and end of Mask M[0][0] = 1; M[1][0] = 3.0f/8.0f; M[1][1] = 3.0f/4.0f; M[1][2] = -1.0f/8.0f; M[2*n-4][ n-2] = 1; M[2*n-3][ n-1] = 3.0f/8.0f; M[2*n-3][n-2] = 3.0f/4.0f; M[2*n-3][n-3] = -1.0f/8.0f; M[2*n-2][ n-1] = 1; for (int j = 2; j < n - 1; ++j) { M[2*j-2][j-1] = 1; M[2*j-1][j-2] = -1.0f/16.0f; M[2*j-1][j-1] = 9.0f/16.0f; M[2*j-1][j] = 9.0f/16.0f; M[2*j-1][j+1] = -1.0f/16.0f; } // matrix multiplication // l = 2*n-2 // m = n // n = 2 // A = M // B = P // init C for temp result of matmult float C[2*n-1][2]; for (int j = 0; j < 2 * n - 1; ++j) { C[j][0] = 0; C[j][1] = 0; } // actual matmult // C = M*P for (int i = 0; i < 2 * n - 1; ++i) { for (int k = 0; k < 2; ++k) { for (int j = 0; j < n; ++j) { C[i][k] += M[i][j] * P[j][k]; } } } // P = C for (int x = 0; x < 2*n-1; ++x) { for (int y = 0; y < 2; ++y) { P[x][y] = C[x][y]; } } n = 2*n-1; // store new subdiv verts in vert vector for (i = 0; i < n; ++i) { Vertex pVertex = *new Vertex(P[i][0], P[i][1] - 1.0f, -((float)k) - 2.0f); // isNext means start a new strip if (i == 0) pVertex.isNext = true; points.push_back(pVertex); } } } void DrawTriag() { glLineWidth(1.0f); glBegin( GL_LINE_STRIP); for (auto vert : points) { if (vert.isNext) { glEnd(); glLineWidth(2*abs(vert._z)); glColor3f(1.0f, 0.0f, 0.0f); glBegin( GL_LINE_STRIP); } glVertex3f(vert._x, vert._y, vert._z); } glEnd(); } // initialize Open GL lighting and projection matrix void InitLightingAndProjection() // to be executed once before drawing { // light positions and colors GLfloat LightPosition1[4] = { 10, 5, 10, 0}; GLfloat LightPosition2[4] = { -5, 5, -10, 0}; GLfloat ColorRedish[4] = { 1.0, .8, .8, 1}; // white with a little bit of red GLfloat ColorBlueish[4] = { .8, .8, 1.0, 1};// white with a little bit of blue glEnable( GL_DEPTH_TEST); // switch on z-buffer glDepthFunc( GL_LESS); glShadeModel( GL_SMOOTH); // Gouraud shading //glShadeModel( GL_FLAT); glDisable( GL_LIGHTING); // use lighting glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, 1); // draw both sides // define and switch on light 0 glLightfv( GL_LIGHT0, GL_POSITION, LightPosition1); glLightfv( GL_LIGHT0, GL_DIFFUSE, ColorRedish); glLightfv( GL_LIGHT0, GL_SPECULAR, ColorRedish); glEnable( GL_LIGHT0); // define and switch on light 1 glLightfv( GL_LIGHT1, GL_POSITION, LightPosition2); glLightfv( GL_LIGHT1, GL_DIFFUSE, ColorBlueish); glLightfv( GL_LIGHT1, GL_SPECULAR, ColorBlueish); glEnable( GL_LIGHT1); glMatrixMode( GL_PROJECTION); // define camera projection glLoadIdentity(); // reset matrix to identity (otherwise existing matrix will be multiplied with) glOrtho( -15, 15, -10, 10, -50, 50); // orthogonal projection (xmin xmax ymin ymax zmin zmax) //glFrustum( -10, 10, -8, 8, 2, 20); // perspective projektion } // define material color properties for front and back side void SetMaterialColor( int side, float r, float g, float b){ float amb[4], dif[4], spe[4]; int i, mat; dif[0] = r; // diffuse color as defined by r,g, and b dif[1] = g; dif[2] = b; for( i=0; i<3; i++){ amb[i] = .1 * dif[i]; // ambient color is 10 percent of diffuse spe[i] = .5; // specular color is just white / gray } amb[3] = dif[3] = spe[3] = 1.0; // alpha component is always 1 switch( side){ case 1: mat = GL_FRONT; break; case 2: mat = GL_BACK; break; default: mat = GL_FRONT_AND_BACK; break; } glMaterialfv( mat, GL_AMBIENT, amb); // define ambient, diffuse and specular components glMaterialfv( mat, GL_DIFFUSE, dif); glMaterialfv( mat, GL_SPECULAR, spe); glMaterialf( mat, GL_SHININESS, 50.0); // Phong constant for the size of highlights } OGLWidget::OGLWidget(QWidget *parent) // constructor : QOpenGLWidget(parent) { // Setup the animation timer to fire every x msec animtimer = new QTimer(this); animtimer->start( 50 ); // Everytime the timer fires, the animation is going one step forward connect(animtimer, SIGNAL(timeout()), this, SLOT(stepAnimation())); animstep = 0; } OGLWidget::~OGLWidget() // destructor { } void OGLWidget::stepAnimation() { animstep++; // Increase animation steps update(); // Trigger redraw of scene with paintGL } void OGLWidget::initializeGL() // initializations to be called once { initializeOpenGLFunctions(); InitLightingAndProjection(); // define light sources and projection loadData(); } void OGLWidget::paintGL() // draw everything, to be called repeatedly { glEnable(GL_NORMALIZE); // this is necessary when using glScale (keep normals to unit length) // set background color glClearColor(0.8, 0.8, 1.0, 1.0); // bright blue glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // draw the scene glMatrixMode( GL_MODELVIEW); glLoadIdentity(); // Reset The Current Modelview Matrix glTranslated( 0 ,0 ,-10.0); // Move 10 units backwards in z, since camera is at origin glScaled( 2.0, 2.0, 2.0); // scale objects glRotated( alpha, 0, 3, 1); // continuous rotation alpha += 2; // define color: 1=front, 2=back, 3=both, followed by r, g, and b SetMaterialColor( 1, 0, .2, .2); // front color is red SetMaterialColor( 2, 0.2, 0.2, 1.0); // back color is blue // draw a cylinder with default resolution DrawTriag(); // make it appear (before this, it's hidden in the rear buffer) glFlush(); } void OGLWidget::resizeGL(int w, int h) // called when window size is changed { // adjust viewport transform glViewport(0,0,w,h); }