blob: 3e141b9480be59910e7152194330c0de145a1ec7 [file] [log] [blame]
Olivier Delannoy70647ea2010-09-24 21:47:25 +01001//========================================================================
2// Heightmap example program using OpenGL 3 core profile
3// Copyright (c) 2010 Olivier Delannoy
4//
5// This software is provided 'as-is', without any express or implied
6// warranty. In no event will the authors be held liable for any damages
7// arising from the use of this software.
8//
9// Permission is granted to anyone to use this software for any purpose,
10// including commercial applications, and to alter it and redistribute it
11// freely, subject to the following restrictions:
12//
13// 1. The origin of this software must not be misrepresented; you must not
14// claim that you wrote the original software. If you use this software
15// in a product, an acknowledgment in the product documentation would
16// be appreciated but is not required.
17//
18// 2. Altered source versions must be plainly marked as such, and must not
19// be misrepresented as being the original software.
20//
21// 3. This notice may not be removed or altered from any source
22// distribution.
23//
24//========================================================================
25
26#include <stdlib.h>
27#include <stdio.h>
28#include <math.h>
29#include <assert.h>
30#include <stddef.h>
31#include "getopt.h"
32
Olivier Delannoy70647ea2010-09-24 21:47:25 +010033#include <GL/glfw3.h>
Camilla Berglunda1ae18f2010-10-03 19:01:06 +020034#include <GL/glext.h>
Olivier Delannoy70647ea2010-09-24 21:47:25 +010035
Camilla Berglundba3ecfb2010-10-03 18:57:12 +020036/* OpenGL function pointers */
Camilla Berglunda1ae18f2010-10-03 19:01:06 +020037static PFNGLGENBUFFERSPROC pglGenBuffers = NULL;
38static PFNGLGENVERTEXARRAYSPROC pglGenVertexArrays = NULL;
39static PFNGLDELETEVERTEXARRAYSPROC pglDeleteVertexArrays = NULL;
40static PFNGLCREATESHADERPROC pglCreateShader = NULL;
41static PFNGLSHADERSOURCEPROC pglShaderSource = NULL;
42static PFNGLCOMPILESHADERPROC pglCompileShader = NULL;
43static PFNGLGETSHADERIVPROC pglGetShaderiv = NULL;
44static PFNGLGETSHADERINFOLOGPROC pglGetShaderInfoLog = NULL;
45static PFNGLDELETESHADERPROC pglDeleteShader = NULL;
46static PFNGLCREATEPROGRAMPROC pglCreateProgram = NULL;
47static PFNGLATTACHSHADERPROC pglAttachShader = NULL;
48static PFNGLLINKPROGRAMPROC pglLinkProgram = NULL;
49static PFNGLUSEPROGRAMPROC pglUseProgram = NULL;
50static PFNGLGETPROGRAMIVPROC pglGetProgramiv = NULL;
51static PFNGLGETPROGRAMINFOLOGPROC pglGetProgramInfoLog = NULL;
52static PFNGLDELETEPROGRAMPROC pglDeleteProgram = NULL;
53static PFNGLGETUNIFORMLOCATIONPROC pglGetUniformLocation = NULL;
54static PFNGLUNIFORMMATRIX4FVPROC pglUniformMatrix4fv = NULL;
55static PFNGLGETATTRIBLOCATIONPROC pglGetAttribLocation = NULL;
56static PFNGLBINDVERTEXARRAYPROC pglBindVertexArray = NULL;
57static PFNGLBUFFERDATAPROC pglBufferData = NULL;
58static PFNGLBINDBUFFERPROC pglBindBuffer = NULL;
59static PFNGLBUFFERSUBDATAPROC pglBufferSubData = NULL;
60static PFNGLENABLEVERTEXATTRIBARRAYPROC pglEnableVertexAttribArray = NULL;
61static PFNGLVERTEXATTRIBPOINTERPROC pglVertexAttribPointer = NULL;
Olivier Delannoy70647ea2010-09-24 21:47:25 +010062
63/* Map height updates */
64#define MAX_CIRCLE_SIZE (5.0f)
65#define MAX_DISPLACEMENT (1.0f)
66#define DISPLACEMENT_SIGN_LIMIT (0.3f)
67#define MAX_ITER (200)
68#define NUM_ITER_AT_A_TIME (1)
69
70/* Map general information */
71#define MAP_SIZE (10.0f)
72#define MAP_NUM_VERTICES (80)
73#define MAP_NUM_TOTAL_VERTICES (MAP_NUM_VERTICES*MAP_NUM_VERTICES)
74#define MAP_NUM_LINES (3* (MAP_NUM_VERTICES - 1) * (MAP_NUM_VERTICES - 1) + \
75 2 * (MAP_NUM_VERTICES - 1))
76
77
78/* OpenGL function pointers */
79
Olivier Delannoy70647ea2010-09-24 21:47:25 +010080#define RESOLVE_GL_FCN(type, var, name) \
81 if (status == GL_TRUE) \
82 {\
Camilla Berglund0c49e9e2012-06-11 14:13:05 +020083 var = (type) glfwGetProcAddress((name));\
Olivier Delannoy70647ea2010-09-24 21:47:25 +010084 if ((var) == NULL)\
85 {\
86 status = GL_FALSE;\
87 }\
88 }
89
90
91static GLboolean init_opengl(void)
92{
93 GLboolean status = GL_TRUE;
Camilla Berglund0c49e9e2012-06-11 14:13:05 +020094 RESOLVE_GL_FCN(PFNGLCREATESHADERPROC, pglCreateShader, "glCreateShader");
95 RESOLVE_GL_FCN(PFNGLSHADERSOURCEPROC, pglShaderSource, "glShaderSource");
96 RESOLVE_GL_FCN(PFNGLCOMPILESHADERPROC, pglCompileShader, "glCompileShader");
97 RESOLVE_GL_FCN(PFNGLGETSHADERIVPROC, pglGetShaderiv, "glGetShaderiv");
98 RESOLVE_GL_FCN(PFNGLGETSHADERINFOLOGPROC, pglGetShaderInfoLog, "glGetShaderInfoLog");
99 RESOLVE_GL_FCN(PFNGLDELETESHADERPROC, pglDeleteShader, "glDeleteShader");
100 RESOLVE_GL_FCN(PFNGLCREATEPROGRAMPROC, pglCreateProgram, "glCreateProgram");
101 RESOLVE_GL_FCN(PFNGLATTACHSHADERPROC, pglAttachShader, "glAttachShader");
102 RESOLVE_GL_FCN(PFNGLLINKPROGRAMPROC, pglLinkProgram, "glLinkProgram");
103 RESOLVE_GL_FCN(PFNGLUSEPROGRAMPROC, pglUseProgram, "glUseProgram");
104 RESOLVE_GL_FCN(PFNGLGETPROGRAMIVPROC, pglGetProgramiv, "glGetProgramiv");
105 RESOLVE_GL_FCN(PFNGLGETPROGRAMINFOLOGPROC, pglGetProgramInfoLog, "glGetProgramInfoLog");
106 RESOLVE_GL_FCN(PFNGLDELETEPROGRAMPROC, pglDeleteProgram, "glDeleteProgram");
107 RESOLVE_GL_FCN(PFNGLGETUNIFORMLOCATIONPROC, pglGetUniformLocation, "glGetUniformLocation");
108 RESOLVE_GL_FCN(PFNGLUNIFORMMATRIX4FVPROC, pglUniformMatrix4fv, "glUniformMatrix4fv");
109 RESOLVE_GL_FCN(PFNGLGETATTRIBLOCATIONPROC, pglGetAttribLocation, "glGetAttribLocation");
110 RESOLVE_GL_FCN(PFNGLGENVERTEXARRAYSPROC, pglGenVertexArrays, "glGenVertexArrays");
111 RESOLVE_GL_FCN(PFNGLDELETEVERTEXARRAYSPROC, pglDeleteVertexArrays, "glDeleteVertexArrays");
112 RESOLVE_GL_FCN(PFNGLBINDVERTEXARRAYPROC, pglBindVertexArray, "glBindVertexArray");
113 RESOLVE_GL_FCN(PFNGLGENBUFFERSPROC, pglGenBuffers, "glGenBuffers");
114 RESOLVE_GL_FCN(PFNGLBINDBUFFERPROC, pglBindBuffer, "glBindBuffer");
115 RESOLVE_GL_FCN(PFNGLBUFFERDATAPROC, pglBufferData, "glBufferData");
116 RESOLVE_GL_FCN(PFNGLBUFFERSUBDATAPROC, pglBufferSubData, "glBufferSubData");
117 RESOLVE_GL_FCN(PFNGLENABLEVERTEXATTRIBARRAYPROC, pglEnableVertexAttribArray, "glEnableVertexAttribArray");
118 RESOLVE_GL_FCN(PFNGLVERTEXATTRIBPOINTERPROC, pglVertexAttribPointer, "glVertexAttribPointer");
Olivier Delannoy70647ea2010-09-24 21:47:25 +0100119 return status;
120}
121/**********************************************************************
122 * Default shader programs
123 *********************************************************************/
124
125static const char* default_vertex_shader =
126"#version 150\n"
127"uniform mat4 project;\n"
128"uniform mat4 modelview;\n"
129"in float x;\n"
130"in float y;\n"
131"in float z;\n"
132"\n"
133"void main()\n"
134"{\n"
135" gl_Position = project * modelview * vec4(x, y, z, 1.0);\n"
136"}\n";
137
138static const char* default_fragment_shader =
139"#version 150\n"
140"out vec4 gl_FragColor;\n"
141"void main()\n"
142"{\n"
143" gl_FragColor = vec4(0.2, 1.0, 0.2, 1.0); \n"
144"}\n";
145
146/**********************************************************************
147 * Values for shader uniforms
148 *********************************************************************/
149
150/* Frustum configuration */
151static GLfloat view_angle = 45.0f;
152static GLfloat aspect_ratio = 4.0f/3.0f;
153static GLfloat z_near = 1.0f;
154static GLfloat z_far = 100.f;
155
156/* Projection matrix */
157static GLfloat projection_matrix[16] = {
158 1.0f, 0.0f, 0.0f, 0.0f,
159 0.0f, 1.0f, 0.0f, 0.0f,
160 0.0f, 0.0f, 1.0f, 0.0f,
161 0.0f, 0.0f, 0.0f, 1.0f
162};
163
164/* Model view matrix */
165static GLfloat modelview_matrix[16] = {
166 1.0f, 0.0f, 0.0f, 0.0f,
167 0.0f, 1.0f, 0.0f, 0.0f,
168 0.0f, 0.0f, 1.0f, 0.0f,
169 0.0f, 0.0f, 0.0f, 1.0f
170};
171
172/**********************************************************************
173 * Heightmap vertex and index data
174 *********************************************************************/
175
176static GLfloat map_vertices[3][MAP_NUM_TOTAL_VERTICES];
177static GLuint map_line_indices[2*MAP_NUM_LINES];
178
179/* Store uniform location for the shaders
180 * Those values are setup as part of the process of creating
181 * the shader program. They should not be used before creating
182 * the program.
183 */
184static GLuint mesh;
185static GLuint mesh_vbo[4];
186
187/**********************************************************************
188 * OpenGL helper functions
189 *********************************************************************/
190
191/* Load a (text) file into memory and return its contents
192 */
193static char* read_file_content(const char* filename)
194{
195 FILE* fd;
196 size_t size = 0;
197 char* result = NULL;
198
199 fd = fopen(filename, "r");
200 if (fd != NULL)
201 {
202 size = fseek(fd, 0, SEEK_END);
203 (void) fseek(fd, 0, SEEK_SET);
204
205 result = malloc(size + 1);
206 result[size] = '\0';
207 if (fread(result, size, 1, fd) != 1)
208 {
209 free(result);
210 result = NULL;
211 }
212 (void) fclose(fd);
213 }
214 return result;
215}
216
217/* Creates a shader object of the specified type using the specified text
218 */
219static GLuint make_shader(GLenum type, const char* shader_src)
220{
221 GLuint shader;
222 GLint shader_ok;
223 GLsizei log_length;
224 char info_log[8192];
225
226 shader = pglCreateShader(type);
227 if (shader != 0)
228 {
229 pglShaderSource(shader, 1, (const GLchar**)&shader_src, NULL);
230 pglCompileShader(shader);
231 pglGetShaderiv(shader, GL_COMPILE_STATUS, &shader_ok);
232 if (shader_ok != GL_TRUE)
233 {
234 fprintf(stderr, "ERROR: Failed to compile %s shader\n", (type == GL_FRAGMENT_SHADER) ? "fragment" : "vertex" );
235 pglGetShaderInfoLog(shader, 8192, &log_length,info_log);
236 fprintf(stderr, "ERROR: \n%s\n\n", info_log);
237 pglDeleteShader(shader);
238 shader = 0;
239 }
240 }
241 return shader;
242}
243
244/* Creates a program object using the specified vertex and fragment text
245 */
246static GLuint make_shader_program(const char* vertex_shader_src, const char* fragment_shader_src)
247{
248 GLuint program = 0u;
249 GLint program_ok;
250 GLuint vertex_shader = 0u;
251 GLuint fragment_shader = 0u;
252 GLsizei log_length;
253 char info_log[8192];
254
255 vertex_shader = make_shader(GL_VERTEX_SHADER, (vertex_shader_src == NULL) ? default_vertex_shader : vertex_shader_src);
256 if (vertex_shader != 0u)
257 {
258 fragment_shader = make_shader(GL_FRAGMENT_SHADER, (fragment_shader_src == NULL) ? default_fragment_shader : fragment_shader_src);
259 if (fragment_shader != 0u)
260 {
261 /* make the program that connect the two shader and link it */
262 program = pglCreateProgram();
263 if (program != 0u)
264 {
265 /* attach both shader and link */
266 pglAttachShader(program, vertex_shader);
267 pglAttachShader(program, fragment_shader);
268 pglLinkProgram(program);
269 pglGetProgramiv(program, GL_LINK_STATUS, &program_ok);
270
271 if (program_ok != GL_TRUE)
272 {
273 fprintf(stderr, "ERROR, failed to link shader program\n");
274 pglGetProgramInfoLog(program, 8192, &log_length, info_log);
275 fprintf(stderr, "ERROR: \n%s\n\n", info_log);
276 pglDeleteProgram(program);
277 pglDeleteShader(fragment_shader);
278 pglDeleteShader(vertex_shader);
279 program = 0u;
280 }
281 }
282 }
283 else
284 {
285 fprintf(stderr, "ERROR: Unable to load fragment shader\n");
286 pglDeleteShader(vertex_shader);
287 }
288 }
289 else
290 {
291 fprintf(stderr, "ERROR: Unable to load vertex shader\n");
292 }
293 return program;
294}
295
296/**********************************************************************
297 * Geometry creation functions
298 *********************************************************************/
299
300/* Generate vertices and indices for the heightmap
301 */
302static void init_map(void)
303{
304 int i;
305 int j;
306 int k;
307 GLfloat step = MAP_SIZE / (MAP_NUM_VERTICES - 1);
308 GLfloat x = 0.0f;
309 GLfloat z = 0.0f;
310 /* Create a flat grid */
311 k = 0;
312 for (i = 0 ; i < MAP_NUM_VERTICES ; ++i)
313 {
314 for (j = 0 ; j < MAP_NUM_VERTICES ; ++j)
315 {
316 map_vertices[0][k] = x;
317 map_vertices[1][k] = 0.0f;
318 map_vertices[2][k] = z;
319 z += step;
320 ++k;
321 }
322 x += step;
323 z = 0.0f;
324 }
325#if DEBUG_ENABLED
326 for (i = 0 ; i < MAP_NUM_TOTAL_VERTICES ; ++i)
327 {
328 printf ("Vertice %d (%f, %f, %f)\n",
329 i, map_vertices[0][i], map_vertices[1][i], map_vertices[2][i]);
330
331 }
332#endif
333 /* create indices */
334 /* line fan based on i
335 * i+1
336 * | / i + n + 1
337 * | /
338 * |/
339 * i --- i + n
340 */
341
342 /* close the top of the square */
343 k = 0;
344 for (i = 0 ; i < MAP_NUM_VERTICES -1 ; ++i)
345 {
346 map_line_indices[k++] = (i + 1) * MAP_NUM_VERTICES -1;
347 map_line_indices[k++] = (i + 2) * MAP_NUM_VERTICES -1;
348 }
349 /* close the right of the square */
350 for (i = 0 ; i < MAP_NUM_VERTICES -1 ; ++i)
351 {
352 map_line_indices[k++] = (MAP_NUM_VERTICES - 1) * MAP_NUM_VERTICES + i;
353 map_line_indices[k++] = (MAP_NUM_VERTICES - 1) * MAP_NUM_VERTICES + i + 1;
354 }
355
356 for (i = 0 ; i < (MAP_NUM_VERTICES - 1) ; ++i)
357 {
358 for (j = 0 ; j < (MAP_NUM_VERTICES - 1) ; ++j)
359 {
360 int ref = i * (MAP_NUM_VERTICES) + j;
361 map_line_indices[k++] = ref;
362 map_line_indices[k++] = ref + 1;
363
364 map_line_indices[k++] = ref;
365 map_line_indices[k++] = ref + MAP_NUM_VERTICES;
366
367 map_line_indices[k++] = ref;
368 map_line_indices[k++] = ref + MAP_NUM_VERTICES + 1;
369 }
370 }
371
372#ifdef DEBUG_ENABLED
373 for (k = 0 ; k < 2 * MAP_NUM_LINES ; k += 2)
374 {
375 int beg, end;
376 beg = map_line_indices[k];
377 end = map_line_indices[k+1];
378 printf ("Line %d: %d -> %d (%f, %f, %f) -> (%f, %f, %f)\n",
379 k / 2, beg, end,
380 map_vertices[0][beg], map_vertices[1][beg], map_vertices[2][beg],
381 map_vertices[0][end], map_vertices[1][end], map_vertices[2][end]);
382 }
383#endif
384}
385
386static void generate_heightmap__circle(float* center_x, float* center_y,
387 float* size, float* displacement)
388{
389 float sign;
390 /* random value for element in between [0-1.0] */
391 *center_x = (MAP_SIZE * rand()) / (1.0f * RAND_MAX);
392 *center_y = (MAP_SIZE * rand()) / (1.0f * RAND_MAX);
393 *size = (MAX_CIRCLE_SIZE * rand()) / (1.0f * RAND_MAX);
394 sign = (1.0f * rand()) / (1.0f * RAND_MAX);
395 sign = (sign < DISPLACEMENT_SIGN_LIMIT) ? -1.0f : 1.0f;
396 *displacement = (sign * (MAX_DISPLACEMENT * rand())) / (1.0f * RAND_MAX);
397}
398
399/* Run the specified number of iterations of the generation process for the
400 * heightmap
401 */
402static void update_map(int num_iter)
403{
404 assert(num_iter > 0);
405 while(num_iter)
406 {
407 /* center of the circle */
408 float center_x;
409 float center_z;
410 float circle_size;
411 float disp;
412 size_t ii;
413 generate_heightmap__circle(&center_x, &center_z, &circle_size, &disp);
414 disp = disp / 2.0f;
415 for (ii = 0u ; ii < MAP_NUM_TOTAL_VERTICES ; ++ii)
416 {
417 GLfloat dx = center_x - map_vertices[0][ii];
418 GLfloat dz = center_z - map_vertices[2][ii];
419 GLfloat pd = (2.0f * sqrtf((dx * dx) + (dz * dz))) / circle_size;
420 if (fabs(pd) <= 1.0f)
421 {
422 /* tx,tz is within the circle */
Camilla Berglund4afc67c2011-07-27 17:09:17 +0200423 GLfloat new_height = disp + (float) (cos(pd*3.14f)*disp);
Olivier Delannoy70647ea2010-09-24 21:47:25 +0100424 map_vertices[1][ii] += new_height;
425 }
426 }
427 --num_iter;
428 }
429}
430
431/**********************************************************************
432 * OpenGL helper functions
433 *********************************************************************/
434
435/* Create VBO, IBO and VAO objects for the heightmap geometry and bind them to
436 * the specified program object
437 */
438static void make_mesh(GLuint program)
439{
440 GLuint attrloc;
441
442 pglGenVertexArrays(1, &mesh);
443 pglGenBuffers(4, mesh_vbo);
444 pglBindVertexArray(mesh);
445 /* Prepare the data for drawing through a buffer inidices */
446 pglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh_vbo[3]);
447 pglBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)* MAP_NUM_LINES * 2, map_line_indices, GL_STATIC_DRAW);
448
449 /* Prepare the attributes for rendering */
450 attrloc = pglGetAttribLocation(program, "x");
451 pglBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[0]);
452 pglBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[0][0], GL_STATIC_DRAW);
453 pglEnableVertexAttribArray(attrloc);
454 pglVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0);
455
456 attrloc = pglGetAttribLocation(program, "z");
457 pglBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[2]);
458 pglBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[2][0], GL_STATIC_DRAW);
459 pglEnableVertexAttribArray(attrloc);
460 pglVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0);
461
462 attrloc = pglGetAttribLocation(program, "y");
463 pglBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[1]);
464 pglBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[1][0], GL_DYNAMIC_DRAW);
465 pglEnableVertexAttribArray(attrloc);
466 pglVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0);
467}
468
469/* Update VBO vertices from source data
470 */
471static void update_mesh(void)
472{
473 pglBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[1][0]);
474}
475
476/**********************************************************************
477 * GLFW callback functions
478 *********************************************************************/
479
Camilla Berglund9af960e2013-01-05 21:13:28 +0100480static void key_callback(GLFWwindow* window, int key, int action)
Olivier Delannoy70647ea2010-09-24 21:47:25 +0100481{
482 switch(key)
483 {
Marcuse3cb5632011-01-03 22:22:14 +0100484 case GLFW_KEY_ESCAPE:
Olivier Delannoy70647ea2010-09-24 21:47:25 +0100485 /* Exit program on Escape */
Camilla Berglund6fadf372013-03-01 13:45:12 +0100486 glfwSetWindowShouldClose(window, GL_TRUE);
Olivier Delannoy70647ea2010-09-24 21:47:25 +0100487 break;
488 }
489}
490
491/* Print usage information */
492static void usage(void)
493{
494 printf("Usage: heightmap [-v <vertex_shader_path>] [-f <fragment_shader_path>]\n");
495 printf(" heightmap [-h]\n");
496}
497
498int main(int argc, char** argv)
499{
Camilla Berglund9af960e2013-01-05 21:13:28 +0100500 GLFWwindow* window;
Olivier Delannoy70647ea2010-09-24 21:47:25 +0100501 int ch, iter;
502 double dt;
503 double last_update_time;
504 int frame;
505 float f;
506 GLint uloc_modelview;
507 GLint uloc_project;
508
509 char* vertex_shader_path = NULL;
510 char* fragment_shader_path = NULL;
511 char* vertex_shader_src = NULL;
512 char* fragment_shader_src = NULL;
513 GLuint shader_program;
514
515 while ((ch = getopt(argc, argv, "f:v:h")) != -1)
516 {
517 switch (ch)
518 {
519 case 'f':
520 fragment_shader_path = optarg;
521 break;
522 case 'v':
523 vertex_shader_path = optarg;
524 break;
525 case 'h':
526 usage();
527 exit(EXIT_SUCCESS);
528 default:
529 usage();
530 exit(EXIT_FAILURE);
531 }
532 }
533
534 if (fragment_shader_path)
535 {
536 vertex_shader_src = read_file_content(fragment_shader_path);
537 if (!fragment_shader_src)
538 {
539 fprintf(stderr,
540 "ERROR: unable to load fragment shader from '%s'\n",
541 fragment_shader_path);
542 exit(EXIT_FAILURE);
543 }
544 }
545
546 if (vertex_shader_path)
547 {
548 vertex_shader_src = read_file_content(vertex_shader_path);
549 if (!vertex_shader_src)
550 {
551 fprintf(stderr,
552 "ERROR: unable to load vertex shader from '%s'\n",
553 fragment_shader_path);
554 exit(EXIT_FAILURE);
555 }
556 }
557
Camilla Berglund0c3b1b52012-02-07 14:58:58 +0100558 if (!glfwInit())
Olivier Delannoy70647ea2010-09-24 21:47:25 +0100559 {
560 fprintf(stderr, "ERROR: Unable to initialize GLFW\n");
561 usage();
562
563 free(vertex_shader_src);
564 free(fragment_shader_src);
565 exit(EXIT_FAILURE);
566 }
567
Camilla Berglunda2ca0952012-08-21 20:28:36 +0200568 glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
Camilla Berglund3f5843f2012-12-13 02:22:39 +0100569 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
570 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
Camilla Berglundaff30d02012-08-06 17:56:41 +0200571 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
572 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_FALSE);
Olivier Delannoy70647ea2010-09-24 21:47:25 +0100573
Camilla Berglund1be16362012-09-27 21:37:36 +0200574 window = glfwCreateWindow(800, 600, "GLFW OpenGL3 Heightmap demo", NULL, NULL);
Olivier Delannoy70647ea2010-09-24 21:47:25 +0100575 if (! window )
576 {
577 fprintf(stderr, "ERROR: Unable to create the OpenGL context and associated window\n");
578 usage();
579
580 free(vertex_shader_src);
581 free(fragment_shader_src);
Camilla Berglundd68acb72012-10-22 03:20:16 +0200582
583 glfwTerminate();
Olivier Delannoy70647ea2010-09-24 21:47:25 +0100584 exit(EXIT_FAILURE);
585 }
Camilla Berglund2f095cc2012-08-10 15:29:45 +0200586
587 /* Register events callback */
Camilla Berglund18d71c22012-10-28 13:45:11 +0100588 glfwSetKeyCallback(window, key_callback);
Olivier Delannoy70647ea2010-09-24 21:47:25 +0100589
Camilla Berglund2f095cc2012-08-10 15:29:45 +0200590 glfwMakeContextCurrent(window);
Olivier Delannoy70647ea2010-09-24 21:47:25 +0100591 if (GL_TRUE != init_opengl())
592 {
593 fprintf(stderr, "ERROR: unable to resolve OpenGL function pointers\n");
594 free(vertex_shader_src);
595 free(fragment_shader_src);
Camilla Berglundd68acb72012-10-22 03:20:16 +0200596
597 glfwTerminate();
Olivier Delannoy70647ea2010-09-24 21:47:25 +0100598 exit(EXIT_FAILURE);
599 }
600 /* Prepare opengl resources for rendering */
601 shader_program = make_shader_program(vertex_shader_src , fragment_shader_src);
602 free(vertex_shader_src);
603 free(fragment_shader_src);
604
605 if (shader_program == 0u)
606 {
607 fprintf(stderr, "ERROR: during creation of the shader program\n");
608 usage();
Camilla Berglundd68acb72012-10-22 03:20:16 +0200609
610 glfwTerminate();
Olivier Delannoy70647ea2010-09-24 21:47:25 +0100611 exit(EXIT_FAILURE);
612 }
613
614 pglUseProgram(shader_program);
615 uloc_project = pglGetUniformLocation(shader_program, "project");
616 uloc_modelview = pglGetUniformLocation(shader_program, "modelview");
617
618 /* Compute the projection matrix */
619 f = 1.0f / tanf(view_angle / 2.0f);
620 projection_matrix[0] = f / aspect_ratio;
621 projection_matrix[5] = f;
622 projection_matrix[10] = (z_far + z_near)/ (z_near - z_far);
623 projection_matrix[11] = -1.0f;
624 projection_matrix[14] = 2.0f * (z_far * z_near) / (z_near - z_far);
625 pglUniformMatrix4fv(uloc_project, 1, GL_FALSE, projection_matrix);
626
627 /* Set the camera position */
628 modelview_matrix[12] = -5.0f;
629 modelview_matrix[13] = -5.0f;
630 modelview_matrix[14] = -20.0f;
631 pglUniformMatrix4fv(uloc_modelview, 1, GL_FALSE, modelview_matrix);
632
633 /* Create mesh data */
634 init_map();
635 make_mesh(shader_program);
636
637 /* Create vao + vbo to store the mesh */
638 /* Create the vbo to store all the information for the grid and the height */
639
640 /* setup the scene ready for rendering */
641 glViewport(0, 0, 800, 600);
642 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
643
644 /* main loop */
645 frame = 0;
646 iter = 0;
647 dt = last_update_time = glfwGetTime();
648
Camilla Berglund6fadf372013-03-01 13:45:12 +0100649 while (!glfwWindowShouldClose(window))
Olivier Delannoy70647ea2010-09-24 21:47:25 +0100650 {
651 ++frame;
652 /* render the next frame */
653 glClear(GL_COLOR_BUFFER_BIT);
654 glDrawElements(GL_LINES, 2* MAP_NUM_LINES , GL_UNSIGNED_INT, 0);
655
656 /* display and process events through callbacks */
Camilla Berglund585a8402012-08-06 18:13:37 +0200657 glfwSwapBuffers(window);
Olivier Delannoy70647ea2010-09-24 21:47:25 +0100658 glfwPollEvents();
659 /* Check the frame rate and update the heightmap if needed */
660 dt = glfwGetTime();
661 if ((dt - last_update_time) > 0.2)
662 {
663 /* generate the next iteration of the heightmap */
664 if (iter < MAX_ITER)
665 {
666 update_map(NUM_ITER_AT_A_TIME);
667 update_mesh();
668 iter += NUM_ITER_AT_A_TIME;
669 }
670 last_update_time = dt;
671 frame = 0;
672 }
673 }
674
Camilla Berglundd68acb72012-10-22 03:20:16 +0200675 glfwTerminate();
Olivier Delannoy70647ea2010-09-24 21:47:25 +0100676 exit(EXIT_SUCCESS);
677}
678