#include <GL/glew.h>
#include <GL/glut.h>
/* Using the standard output for fprintf */
#include <iostream>
#include <functional>
#include <memory>
#include "Shader.hpp"
#include "Program.hpp"
#include <map>
#include <vector>
#include <cmath>
#include <algorithm>
#include <iterator>
#include <time.h>
GLint attribute_coord3d, attribute_v_color;
GLuint vbo_triangle, vbo_triangle_colors;
std::shared_ptr<cs5400::Program> 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<<"("<<x<<","<<y<<","<<z<<")"<<std::endl;
}
};
//container for gasket verts
std::vector<vec3> triangle_vertices;
std::vector<vec3> 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<std::pair<vec3,vec3>,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<triangle_vertices.size();i++)
{
float random = getRandom(0.5,1.0);
static std::map<vec3,float> 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;
}