#include #include /* Using the standard output for fprintf */ #include #include #include #include "Shader.hpp" #include "Program.hpp" #include #include #include #include #include #include GLint attribute_coord3d, attribute_v_color; GLuint vbo_triangle, vbo_triangle_colors; std::shared_ptr program; const int NUM_ITERATIONS = 5; const int NUM_TRIANGLES = pow(4.0,NUM_ITERATIONS); int modelDrawn=0; struct vec3 { float x; float y; float z; vec3(float x1, float y1, float z1): x(x1), y(y1), z(z1) {} vec3():x(0),y(0),z(0) {} vec3& operator+=(const vec3& other) { x+=other.x; y+=other.y; z+=other.z; } vec3 operator/=(const float) { } vec3 operator+(const vec3& other) const { return vec3(x+other.x, y+other.y, z+other.z); } vec3 operator/(const float &denom) const { return vec3(x/denom, y/denom, z/denom); } vec3 operator*(const float mult) { return vec3(x*mult, y*mult, z*mult); } bool operator<( const vec3 & n ) const { if(x != n.x) return x < n.x; else if(y != n.y) return y < n.y; else if(z != n.z) return z < n.z; return length() < n.length(); } bool operator==( const vec3 & n ) const { return x==n.x&&y==n.y&&z==n.z; } float length() const { return sqrt(pow(x,2)+pow(y,2)+pow(z,2)); } void Print() const { std::cout<<"("< triangle_vertices; std::vector triangle_colors_vec; float getRandom(float max, float min) { return((float(rand()) / float(RAND_MAX)) * (max - (min))) + (min); } float getVectorDistance(vec3 a, vec3 b) { return sqrt(pow((a.x-b.x),2) + pow((a.y-b.y),2) + pow((a.z-b.z),2)); } vec3 randVector(); struct Triangle { vec3 a; vec3 b; vec3 c; Triangle(vec3 a1, vec3 b1, vec3 c1):a(a1),b(b1),c(c1) {} }; vec3 getMidpoint(const vec3& a, const vec3& b) { const float SCALE = 0.1; static std::map,vec3> memo; auto foundResult = memo.find(std::make_pair(a,b)); if (foundResult!=memo.end()) { return foundResult->second; } auto result = (a+b)/2; auto variance = 0.1 * getVectorDistance(a,b); auto randX = getRandom(result.x + variance, result.x - variance); auto randY = getRandom(result.y + variance, result.y - variance); auto randZ = getRandom(result.z + variance, result.z - variance); result = vec3(randX,randY,randZ); memo.insert(std::make_pair(std::make_pair(a,b),result)); memo.insert(std::make_pair(std::make_pair(b,a),result)); return result; } void makeGasket(Triangle t, int count) { if(count > 0) { auto d = getMidpoint(t.a,t.b); auto e = getMidpoint(t.b,t.c); auto f = getMidpoint(t.a,t.c); makeGasket(Triangle(t.a,d,f), count - 1); makeGasket(Triangle(d,t.b,e), count - 1); makeGasket(Triangle(f,d,e), count - 1); makeGasket(Triangle(f,e,t.c), count - 1); } else { triangle_vertices.push_back(t.a); triangle_vertices.push_back(t.b); triangle_vertices.push_back(t.c); } } void createColors() { for(int i=0;i randColor; auto foundResult = randColor.find(triangle_vertices[i]); if (foundResult!=randColor.end()) { random = foundResult->second; } else randColor.insert(std::make_pair(triangle_vertices[i],random)); triangle_colors_vec.push_back(vec3(random,random,random)); } } vec3 triangle_verts[15000]; vec3 triangle_colors[15000]; void onDisplay() { srand(time(NULL)); /* Clear the background as white */ glClearColor(0.0, 0.0, 0.0, 0.0); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glCullFace(GL_FRONT); glEnable(GL_CULL_FACE); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); /* Tell OpenGL which program to use*/ glUseProgram(program->getHandle()); if(modelDrawn == 0) { modelDrawn = 1; vec3 verts[]= { vec3(0.0, 1.0, 0.0), vec3(0.943, -0.333, 0.0), vec3(-0.471, -0.333, 0.816), vec3(-0.471, -0.333, -0.816) }; Triangle initialTri = Triangle( verts[0], verts[2], verts[1] ); Triangle initialTri2 = Triangle( verts[0], verts[1], verts[3] ); Triangle initialTri3 = Triangle( verts[0], verts[3], verts[2] ); Triangle initialTri4 = Triangle( verts[1], verts[2], verts[3] ); makeGasket(initialTri, NUM_ITERATIONS); makeGasket(initialTri2, NUM_ITERATIONS); makeGasket(initialTri3, NUM_ITERATIONS); makeGasket(initialTri4, NUM_ITERATIONS); std::copy(triangle_vertices.begin(),triangle_vertices.end(), triangle_verts); createColors(); std::copy(triangle_colors_vec.begin(),triangle_colors_vec.end(), triangle_colors); } /* Setup vertex data */ glGenBuffers(1, &vbo_triangle); glBindBuffer(GL_ARRAY_BUFFER, vbo_triangle); glBufferData(GL_ARRAY_BUFFER, sizeof(triangle_verts), triangle_verts, GL_STATIC_DRAW); glEnableVertexAttribArray(attribute_coord3d); /* Describe our vertices array to OpenGL (it can't guess its format automatically) */ glVertexAttribPointer( attribute_coord3d, // attribute 3, // number of elements per vertex, here (x,y,z) GL_FLOAT, // the type of each element GL_FALSE, // take our values as-is 0, // no extra data between each position 0 // vec3er to the C array ); /* Push each element in buffer_vertices to the vertex shader */ glGenBuffers(1, &vbo_triangle_colors); glBindBuffer(GL_ARRAY_BUFFER, vbo_triangle_colors); glBufferData(GL_ARRAY_BUFFER, sizeof(triangle_colors), triangle_colors, GL_STATIC_DRAW); char* attribute_name = "v_color"; auto attribute_v_color = glGetAttribLocation(program->getHandle(), attribute_name); if (attribute_v_color == -1) fprintf(stderr, "Could not bind attribute %s\n", attribute_name); glEnableVertexAttribArray(attribute_v_color); glBindBuffer(GL_ARRAY_BUFFER, vbo_triangle_colors); glVertexAttribPointer( attribute_v_color, // attribute 3, // number of elements per vertex, here (r,g,b) GL_FLOAT, // the type of each element GL_FALSE, // take our values as-is 0, // no extra data between each position 0 // offset of first element ); glDrawArrays(GL_TRIANGLES, 0, NUM_TRIANGLES*3*4); glDisableVertexAttribArray(attribute_v_color); glDisableVertexAttribArray(attribute_coord3d); /* Display the result */ glutSwapBuffers(); } void rotate( int value ) { // float angle = 0.0175; // 1 degree //float angle = glutGet(GLUT_ELAPSED_TIME) / 1000.0 * 0.001; float rotation_matrix[] = { cosf(angle),0,sinf(angle), 0,1,0, -1.0*sinf(angle),0,cosf(angle), }; float rotation_matrix_x[] = { 1,0,0, 0,cosf(angle),-1.0*sinf(angle), 0,sinf(angle),cosf(angle), }; float rotation_matrix_z[] = { cosf(angle),-1.0*sin(angle),0, sinf(angle),cosf(angle),0, 0,0,1, }; vec3 tempVec; for(int i=0;i< triangle_vertices.size();i++) { tempVec.x = rotation_matrix[0] * triangle_verts[i].x + rotation_matrix[1] * triangle_verts[i].y + rotation_matrix[2] * triangle_verts[i].z; tempVec.y = rotation_matrix[3] * triangle_verts[i].x + rotation_matrix[4] * triangle_verts[i].y + rotation_matrix[5] * triangle_verts[i].z; tempVec.z = rotation_matrix[6] * triangle_verts[i].x + rotation_matrix[7] * triangle_verts[i].y + rotation_matrix[8] * triangle_verts[i].z; triangle_verts[i] = tempVec; } glutTimerFunc(10, rotate,1); glutPostRedisplay(); } int main(int argc, char* argv[]) { /* Glut-related initialising functions */ glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH); glutInitWindowSize(640, 480); glutCreateWindow("Hello Triangle!"); /* Extension wrangler initialising */ GLenum glew_status = glewInit(); if (glew_status != GLEW_OK) { fprintf(stderr, "Error: %s\n", glewGetErrorString(glew_status)); return EXIT_FAILURE; } /* When all init functions runs without errors, the program can initialise the resources */ try { program = cs5400::make_program ( cs5400::make_vertexShader("vertex.glsl") ,cs5400::make_fragmentShader("fragment.glsl") ); glutDisplayFunc(onDisplay); //glutIdleFunc( idle ); glutTimerFunc(10, rotate,1); glutMainLoop(); } catch(std::exception& e) { std::cerr << e.what(); } return EXIT_SUCCESS; }