SHOW:
|
|
- or go back to the newest paste.
1 | // g++ -std=c++11 main.cpp -lglut -lGLEW | |
2 | ||
3 | #include <GL/glew.h> | |
4 | #include <GL/glut.h> | |
5 | ||
6 | /* Using the standard output for fprintf */ | |
7 | #include <iostream> | |
8 | #include <functional> | |
9 | #include <memory> | |
10 | #include <vector> | |
11 | #include <stdexcept> | |
12 | ||
13 | #include <map> | |
14 | #include <vector> | |
15 | #include <cmath> | |
16 | #include <algorithm> | |
17 | #include <iterator> | |
18 | #include <time.h> | |
19 | ||
20 | using namespace std; | |
21 | ||
22 | GLint attribute_coord3d, attribute_v_color; | |
23 | GLuint vbo_triangle, vbo_triangle_colors; | |
24 | GLuint program; | |
25 | const int NUM_ITERATIONS = 5; | |
26 | const int NUM_TRIANGLES = pow( 4.0, NUM_ITERATIONS ); | |
27 | int modelDrawn = 0; | |
28 | ||
29 | ||
30 | struct vec3 | |
31 | { | |
32 | float x; | |
33 | float y; | |
34 | float z; | |
35 | ||
36 | vec3( float x1, float y1, float z1 ) : x( x1 ), y( y1 ), z( z1 ) | |
37 | { | |
38 | } | |
39 | ||
40 | vec3( ) : x( 0 ), y( 0 ), z( 0 ) | |
41 | { | |
42 | } | |
43 | ||
44 | vec3& operator+=(const vec3 & other ) | |
45 | { | |
46 | x += other.x; | |
47 | y += other.y; | |
48 | z += other.z; | |
49 | } | |
50 | ||
51 | vec3 operator/=(const float) | |
52 | { | |
53 | ||
54 | } | |
55 | ||
56 | vec3 operator+(const vec3 & other ) const | |
57 | { | |
58 | return vec3( x + other.x, y + other.y, z + other.z ); | |
59 | } | |
60 | ||
61 | vec3 operator/(const float &denom ) const | |
62 | { | |
63 | return vec3( x / denom, y / denom, z / denom ); | |
64 | } | |
65 | ||
66 | vec3 operator*(const float mult) | |
67 | { | |
68 | return vec3( x*mult, y*mult, z * mult ); | |
69 | } | |
70 | ||
71 | bool operator<(const vec3 & n ) const | |
72 | { | |
73 | if( x != n.x ) | |
74 | return x < n.x; | |
75 | else if( y != n.y ) | |
76 | return y < n.y; | |
77 | else if( z != n.z ) | |
78 | return z < n.z; | |
79 | return length( ) < n.length( ); | |
80 | } | |
81 | ||
82 | bool operator==(const vec3 & n ) const | |
83 | { | |
84 | return x == n.x && y == n.y && z == n.z; | |
85 | } | |
86 | ||
87 | float length( ) const | |
88 | { | |
89 | return sqrt( pow( x, 2 ) + pow( y, 2 ) + pow( z, 2 ) ); | |
90 | } | |
91 | ||
92 | void Print( ) const | |
93 | { | |
94 | std::cout << "(" << x << "," << y << "," << z << ")" << std::endl; | |
95 | } | |
96 | }; | |
97 | ||
98 | //container for gasket verts | |
99 | std::vector<vec3> triangle_vertices; | |
100 | std::vector<vec3> triangle_colors_vec; | |
101 | ||
102 | float getRandom( float max, float min ) | |
103 | { | |
104 | return ((float(rand( ) ) / float(RAND_MAX ) ) * ( max - ( min ) ) ) + ( min ); | |
105 | } | |
106 | ||
107 | float getVectorDistance( vec3 a, vec3 b ) | |
108 | { | |
109 | return sqrt( pow( ( a.x - b.x ), 2 ) + pow( ( a.y - b.y ), 2 ) + pow( ( a.z - b.z ), 2 ) ); | |
110 | } | |
111 | ||
112 | vec3 randVector( ); | |
113 | ||
114 | ||
115 | struct Triangle | |
116 | { | |
117 | vec3 a; | |
118 | vec3 b; | |
119 | vec3 c; | |
120 | ||
121 | Triangle( vec3 a1, vec3 b1, vec3 c1 ) : a( a1 ), b( b1 ), c( c1 ) | |
122 | { | |
123 | } | |
124 | }; | |
125 | ||
126 | vec3 getMidpoint( const vec3& a, const vec3& b ) | |
127 | { | |
128 | const float SCALE = 0.1; | |
129 | ||
130 | static std::map<std::pair<vec3, vec3>, vec3> memo; | |
131 | ||
132 | ||
133 | auto foundResult = memo.find( std::make_pair( a, b ) ); | |
134 | if( foundResult != memo.end( ) ) | |
135 | { | |
136 | return foundResult->second; | |
137 | } | |
138 | ||
139 | auto result = ( a + b ) / 2; | |
140 | auto variance = 0.1 * getVectorDistance( a, b ); | |
141 | auto randX = getRandom( result.x + variance, result.x - variance ); | |
142 | auto randY = getRandom( result.y + variance, result.y - variance ); | |
143 | auto randZ = getRandom( result.z + variance, result.z - variance ); | |
144 | ||
145 | result = vec3( randX, randY, randZ ); | |
146 | memo.insert( std::make_pair( std::make_pair( a, b ), result ) ); | |
147 | memo.insert( std::make_pair( std::make_pair( b, a ), result ) ); | |
148 | return result; | |
149 | ||
150 | } | |
151 | ||
152 | void makeGasket( Triangle t, int count ) | |
153 | { | |
154 | if( count > 0 ) | |
155 | { | |
156 | auto d = getMidpoint( t.a, t.b ); | |
157 | auto e = getMidpoint( t.b, t.c ); | |
158 | auto f = getMidpoint( t.a, t.c ); | |
159 | ||
160 | ||
161 | makeGasket( Triangle( t.a, d, f ), count - 1 ); | |
162 | makeGasket( Triangle( d, t.b, e ), count - 1 ); | |
163 | makeGasket( Triangle( f, d, e ), count - 1 ); | |
164 | makeGasket( Triangle( f, e, t.c ), count - 1 ); | |
165 | } | |
166 | else | |
167 | { | |
168 | triangle_vertices.push_back( t.a ); | |
169 | triangle_vertices.push_back( t.b ); | |
170 | triangle_vertices.push_back( t.c ); | |
171 | ||
172 | } | |
173 | ||
174 | } | |
175 | ||
176 | void createColors( ) | |
177 | { | |
178 | for( int i = 0; i < triangle_vertices.size( ); i++ ) | |
179 | { | |
180 | float random = getRandom( 0.5, 1.0 ); | |
181 | static std::map<vec3, float> randColor; | |
182 | auto foundResult = randColor.find( triangle_vertices[i] ); | |
183 | if( foundResult != randColor.end( ) ) | |
184 | { | |
185 | random = foundResult->second; | |
186 | } | |
187 | else | |
188 | randColor.insert( std::make_pair( triangle_vertices[i], random ) ); | |
189 | ||
190 | triangle_colors_vec.push_back( vec3( random, random, random ) ); | |
191 | } | |
192 | ||
193 | } | |
194 | ||
195 | vec3 triangle_verts[15000]; | |
196 | vec3 triangle_colors[15000]; | |
197 | ||
198 | void onDisplay( ) | |
199 | { | |
200 | srand( time( NULL ) ); | |
201 | /* Clear the background as white */ | |
202 | glClearColor( 0.0, 0.0, 0.0, 0.0 ); | |
203 | glEnable( GL_DEPTH_TEST ); | |
204 | glDepthFunc( GL_LESS ); | |
205 | glCullFace( GL_FRONT ); | |
206 | glEnable( GL_CULL_FACE ); | |
207 | glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); | |
208 | /* Tell OpenGL which program to use*/ | |
209 | glUseProgram( program ); | |
210 | ||
211 | if( modelDrawn == 0 ) | |
212 | { | |
213 | modelDrawn = 1; | |
214 | vec3 verts[] ={ | |
215 | vec3( 0.0, 1.0, 0.0 ), | |
216 | vec3( 0.943, -0.333, 0.0 ), | |
217 | vec3( -0.471, -0.333, 0.816 ), | |
218 | vec3( -0.471, -0.333, -0.816 ) | |
219 | }; | |
220 | ||
221 | Triangle initialTri = Triangle( | |
222 | verts[0], | |
223 | verts[2], | |
224 | verts[1] | |
225 | ); | |
226 | Triangle initialTri2 = Triangle( | |
227 | verts[0], | |
228 | verts[1], | |
229 | verts[3] | |
230 | ); | |
231 | Triangle initialTri3 = Triangle( | |
232 | verts[0], | |
233 | verts[3], | |
234 | verts[2] | |
235 | ); | |
236 | Triangle initialTri4 = Triangle( | |
237 | verts[1], | |
238 | verts[2], | |
239 | verts[3] | |
240 | ); | |
241 | ||
242 | makeGasket( initialTri, NUM_ITERATIONS ); | |
243 | makeGasket( initialTri2, NUM_ITERATIONS ); | |
244 | makeGasket( initialTri3, NUM_ITERATIONS ); | |
245 | makeGasket( initialTri4, NUM_ITERATIONS ); | |
246 | ||
247 | std::copy( triangle_vertices.begin( ), triangle_vertices.end( ), triangle_verts ); | |
248 | ||
249 | createColors( ); | |
250 | ||
251 | std::copy( triangle_colors_vec.begin( ), triangle_colors_vec.end( ), triangle_colors ); | |
252 | } | |
253 | ||
254 | /* Setup vertex data */ | |
255 | glBindBuffer( GL_ARRAY_BUFFER, vbo_triangle ); | |
256 | glBufferData( GL_ARRAY_BUFFER, sizeof (triangle_verts ), triangle_verts, GL_STATIC_DRAW ); | |
257 | ||
258 | auto attribute_coord3d = glGetAttribLocation( program, "coord3d" ); | |
259 | glEnableVertexAttribArray( attribute_coord3d ); | |
260 | ||
261 | /* Describe our vertices array to OpenGL (it can't guess its format automatically) */ | |
262 | glVertexAttribPointer( | |
263 | attribute_coord3d, // attribute | |
264 | 3, // number of elements per vertex, here (x,y,z) | |
265 | GL_FLOAT, // the type of each element | |
266 | GL_FALSE, // take our values as-is | |
267 | 0, // no extra data between each position | |
268 | 0 // vec3er to the C array | |
269 | ); | |
270 | ||
271 | /* Push each element in buffer_vertices to the vertex shader */ | |
272 | glBindBuffer( GL_ARRAY_BUFFER, vbo_triangle_colors ); | |
273 | glBufferData( GL_ARRAY_BUFFER, sizeof (triangle_colors ), triangle_colors, GL_STATIC_DRAW ); | |
274 | ||
275 | auto attribute_v_color = glGetAttribLocation( program, "v_color" ); | |
276 | glEnableVertexAttribArray( attribute_v_color ); | |
277 | ||
278 | glVertexAttribPointer( | |
279 | attribute_v_color, // attribute | |
280 | 3, // number of elements per vertex, here (r,g,b) | |
281 | GL_FLOAT, // the type of each element | |
282 | GL_FALSE, // take our values as-is | |
283 | 0, // no extra data between each position | |
284 | 0 // offset of first element | |
285 | ); | |
286 | ||
287 | glDrawArrays( GL_TRIANGLES, 0, NUM_TRIANGLES * 3 * 4 ); | |
288 | glDisableVertexAttribArray( attribute_coord3d ); | |
289 | glDisableVertexAttribArray( attribute_v_color ); | |
290 | ||
291 | /* Display the result */ | |
292 | glutSwapBuffers( ); | |
293 | } | |
294 | ||
295 | void rotate( int value ) | |
296 | { | |
297 | float angle = 0.0175; // 1 degree | |
298 | //float angle = glutGet(GLUT_ELAPSED_TIME) / 1000.0 * 0.001; | |
299 | ||
300 | float rotation_matrix[] ={ | |
301 | cosf( angle ), 0, sinf( angle ), | |
302 | 0, 1, 0, | |
303 | -1.0 * sinf( angle ), 0, cosf( angle ), | |
304 | ||
305 | }; | |
306 | float rotation_matrix_x[] ={ | |
307 | 1, 0, 0, | |
308 | 0, cosf( angle ), -1.0 * sinf( angle ), | |
309 | 0, sinf( angle ), cosf( angle ), | |
310 | ||
311 | }; | |
312 | float rotation_matrix_z[] ={ | |
313 | cosf( angle ), -1.0 * sin( angle ), 0, | |
314 | sinf( angle ), cosf( angle ), 0, | |
315 | 0, 0, 1, | |
316 | }; | |
317 | ||
318 | vec3 tempVec; | |
319 | for( int i = 0; i < triangle_vertices.size( ); i++ ) | |
320 | { | |
321 | tempVec.x = rotation_matrix[0] * triangle_verts[i].x + rotation_matrix[1] * triangle_verts[i].y + rotation_matrix[2] * triangle_verts[i].z; | |
322 | tempVec.y = rotation_matrix[3] * triangle_verts[i].x + rotation_matrix[4] * triangle_verts[i].y + rotation_matrix[5] * triangle_verts[i].z; | |
323 | tempVec.z = rotation_matrix[6] * triangle_verts[i].x + rotation_matrix[7] * triangle_verts[i].y + rotation_matrix[8] * triangle_verts[i].z; | |
324 | triangle_verts[i] = tempVec; | |
325 | } | |
326 | glutTimerFunc( 10, rotate, 1 ); | |
327 | glutPostRedisplay( ); | |
328 | } | |
329 | ||
330 | void CheckStatus( GLuint obj ) | |
331 | { | |
332 | GLint status = 0; | |
333 | if( glIsShader( obj ) ) glGetShaderiv( obj, GL_COMPILE_STATUS, &status ); | |
334 | if( glIsProgram( obj ) ) glGetProgramiv( obj, GL_LINK_STATUS, &status ); | |
335 | if( status == GL_TRUE ) return; | |
336 | ||
337 | GLint len = 0; | |
338 | if( glIsShader( obj ) ) glGetShaderiv( obj, GL_INFO_LOG_LENGTH, &len ); | |
339 | if( glIsProgram( obj ) ) glGetProgramiv( obj, GL_INFO_LOG_LENGTH, &len ); | |
340 | ||
341 | vector< char > log( len ); | |
342 | if( glIsShader( obj ) ) glGetShaderInfoLog( obj, len, NULL, &log[0] ); | |
343 | if( glIsProgram( obj ) ) glGetProgramInfoLog( obj, len, NULL, &log[0] ); | |
344 | if( glIsShader( obj ) ) glDeleteShader( obj ); | |
345 | if( glIsProgram( obj ) ) glDeleteProgram( obj ); | |
346 | throw runtime_error( string( log.begin( ), log.end( ) ) ); | |
347 | } | |
348 | ||
349 | GLuint LoadShader( GLenum type, const string& aShaderSrc ) | |
350 | { | |
351 | GLuint shader = glCreateShader( type ); | |
352 | const char* srcPtr = aShaderSrc.c_str( ); | |
353 | glShaderSource( shader, 1, &srcPtr, NULL ); | |
354 | glCompileShader( shader ); | |
355 | CheckStatus( shader ); | |
356 | return shader; | |
357 | } | |
358 | ||
359 | GLuint LoadProgram( const string& aVertSrc, const string& aFragSrc ) | |
360 | { | |
361 | GLuint vert = LoadShader( GL_VERTEX_SHADER, aVertSrc ); | |
362 | GLuint frag = LoadShader( GL_FRAGMENT_SHADER, aFragSrc ); | |
363 | GLuint program = glCreateProgram( ); | |
364 | glAttachShader( program, vert ); | |
365 | glAttachShader( program, frag ); | |
366 | glLinkProgram( program ); | |
367 | CheckStatus( program ); | |
368 | - | // delete shaders here? |
368 | + | |
369 | } | |
370 | ||
371 | #define GLSL(version, shader) "#version " #version "\n" #shader | |
372 | ||
373 | const GLchar* vert = GLSL | |
374 | ( | |
375 | 120, | |
376 | attribute vec3 coord3d; | |
377 | attribute vec3 v_color; | |
378 | varying vec3 f_color; | |
379 | void main( void ) | |
380 | { | |
381 | gl_Position = vec4( coord3d, 1.0 ); | |
382 | f_color = v_color; | |
383 | - | gl_Position = vec4( coord3d, 1.0 ); |
383 | + | |
384 | ); | |
385 | ||
386 | const GLchar* frag = GLSL | |
387 | ( | |
388 | 120, | |
389 | varying vec3 f_color; | |
390 | void main( void ) | |
391 | { | |
392 | gl_FragColor = vec4( f_color.x, f_color.y, f_color.z, 1.0 ); | |
393 | } | |
394 | - | gl_FragColor = vec4( f_color.x, f_color.y, f_color.z, 1.0 ); |
394 | + | |
395 | ||
396 | int main( int argc, char* argv[] ) | |
397 | { | |
398 | /* Glut-related initialising functions */ | |
399 | glutInit( &argc, argv ); | |
400 | glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH ); | |
401 | glutInitWindowSize( 640, 480 ); | |
402 | glutCreateWindow( "Hello Triangle!" ); | |
403 | ||
404 | /* Extension wrangler initialising */ | |
405 | GLenum glew_status = glewInit( ); | |
406 | if( glew_status != GLEW_OK ) | |
407 | { | |
408 | fprintf( stderr, "Error: %s\n", glewGetErrorString( glew_status ) ); | |
409 | return EXIT_FAILURE; | |
410 | } | |
411 | ||
412 | /* When all init functions runs without errors, | |
413 | the program can initialise the resources */ | |
414 | try | |
415 | { | |
416 | program = LoadProgram( vert, frag ); | |
417 | ||
418 | glGenBuffers( 1, &vbo_triangle ); | |
419 | glGenBuffers( 1, &vbo_triangle_colors ); | |
420 | ||
421 | glutDisplayFunc( onDisplay ); | |
422 | //glutIdleFunc( idle ); | |
423 | ||
424 | glutTimerFunc( 10, rotate, 1 ); | |
425 | glutMainLoop( ); | |
426 | } | |
427 | catch( std::exception& e ) | |
428 | { | |
429 | std::cerr << e.what( ); | |
430 | } | |
431 | return EXIT_SUCCESS; | |
432 | } |