Atlas - heightmap.c

Home / ext / glfw / examples Lines: 31 | Size: 16086 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1//======================================================================== 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 32#define GLAD_GL_IMPLEMENTATION 33#include <glad/gl.h> 34#define GLFW_INCLUDE_NONE 35#include <GLFW/glfw3.h> 36 37/* Map height updates */ 38#define MAX_CIRCLE_SIZE (5.0f) 39#define MAX_DISPLACEMENT (1.0f) 40#define DISPLACEMENT_SIGN_LIMIT (0.3f) 41#define MAX_ITER (200) 42#define NUM_ITER_AT_A_TIME (1) 43 44/* Map general information */ 45#define MAP_SIZE (10.0f) 46#define MAP_NUM_VERTICES (80) 47#define MAP_NUM_TOTAL_VERTICES (MAP_NUM_VERTICES*MAP_NUM_VERTICES) 48#define MAP_NUM_LINES (3* (MAP_NUM_VERTICES - 1) * (MAP_NUM_VERTICES - 1) + \ 49 2 * (MAP_NUM_VERTICES - 1)) 50 51 52/********************************************************************** 53 * Default shader programs 54 *********************************************************************/ 55 56static const char* vertex_shader_text = 57"#version 150\n" 58"uniform mat4 project;\n" 59"uniform mat4 modelview;\n" 60"in float x;\n" 61"in float y;\n" 62"in float z;\n" 63"\n" 64"void main()\n" 65"{\n" 66" gl_Position = project * modelview * vec4(x, y, z, 1.0);\n" 67"}\n"; 68 69static const char* fragment_shader_text = 70"#version 150\n" 71"out vec4 color;\n" 72"void main()\n" 73"{\n" 74" color = vec4(0.2, 1.0, 0.2, 1.0); \n" 75"}\n"; 76 77/********************************************************************** 78 * Values for shader uniforms 79 *********************************************************************/ 80 81/* Frustum configuration */ 82static GLfloat view_angle = 45.0f; 83static GLfloat aspect_ratio = 4.0f/3.0f; 84static GLfloat z_near = 1.0f; 85static GLfloat z_far = 100.f; 86 87/* Projection matrix */ 88static GLfloat projection_matrix[16] = { 89 1.0f, 0.0f, 0.0f, 0.0f, 90 0.0f, 1.0f, 0.0f, 0.0f, 91 0.0f, 0.0f, 1.0f, 0.0f, 92 0.0f, 0.0f, 0.0f, 1.0f 93}; 94 95/* Model view matrix */ 96static GLfloat modelview_matrix[16] = { 97 1.0f, 0.0f, 0.0f, 0.0f, 98 0.0f, 1.0f, 0.0f, 0.0f, 99 0.0f, 0.0f, 1.0f, 0.0f, 100 0.0f, 0.0f, 0.0f, 1.0f 101}; 102 103/********************************************************************** 104 * Heightmap vertex and index data 105 *********************************************************************/ 106 107static GLfloat map_vertices[3][MAP_NUM_TOTAL_VERTICES]; 108static GLuint map_line_indices[2*MAP_NUM_LINES]; 109 110/* Store uniform location for the shaders 111 * Those values are setup as part of the process of creating 112 * the shader program. They should not be used before creating 113 * the program. 114 */ 115static GLuint mesh; 116static GLuint mesh_vbo[4]; 117 118/********************************************************************** 119 * OpenGL helper functions 120 *********************************************************************/ 121 122/* Creates a shader object of the specified type using the specified text 123 */ 124static GLuint make_shader(GLenum type, const char* text) 125{ 126 GLuint shader; 127 GLint shader_ok; 128 GLsizei log_length; 129 char info_log[8192]; 130 131 shader = glCreateShader(type); 132 if (shader != 0) 133 { 134 glShaderSource(shader, 1, (const GLchar**)&text, NULL); 135 glCompileShader(shader); 136 glGetShaderiv(shader, GL_COMPILE_STATUS, &shader_ok); 137 if (shader_ok != GL_TRUE) 138 { 139 fprintf(stderr, "ERROR: Failed to compile %s shader\n", (type == GL_FRAGMENT_SHADER) ? "fragment" : "vertex" ); 140 glGetShaderInfoLog(shader, 8192, &log_length,info_log); 141 fprintf(stderr, "ERROR: \n%s\n\n", info_log); 142 glDeleteShader(shader); 143 shader = 0; 144 } 145 } 146 return shader; 147} 148 149/* Creates a program object using the specified vertex and fragment text 150 */ 151static GLuint make_shader_program(const char* vs_text, const char* fs_text) 152{ 153 GLuint program = 0u; 154 GLint program_ok; 155 GLuint vertex_shader = 0u; 156 GLuint fragment_shader = 0u; 157 GLsizei log_length; 158 char info_log[8192]; 159 160 vertex_shader = make_shader(GL_VERTEX_SHADER, vs_text); 161 if (vertex_shader != 0u) 162 { 163 fragment_shader = make_shader(GL_FRAGMENT_SHADER, fs_text); 164 if (fragment_shader != 0u) 165 { 166 /* make the program that connect the two shader and link it */ 167 program = glCreateProgram(); 168 if (program != 0u) 169 { 170 /* attach both shader and link */ 171 glAttachShader(program, vertex_shader); 172 glAttachShader(program, fragment_shader); 173 glLinkProgram(program); 174 glGetProgramiv(program, GL_LINK_STATUS, &program_ok); 175 176 if (program_ok != GL_TRUE) 177 { 178 fprintf(stderr, "ERROR, failed to link shader program\n"); 179 glGetProgramInfoLog(program, 8192, &log_length, info_log); 180 fprintf(stderr, "ERROR: \n%s\n\n", info_log); 181 glDeleteProgram(program); 182 glDeleteShader(fragment_shader); 183 glDeleteShader(vertex_shader); 184 program = 0u; 185 } 186 } 187 } 188 else 189 { 190 fprintf(stderr, "ERROR: Unable to load fragment shader\n"); 191 glDeleteShader(vertex_shader); 192 } 193 } 194 else 195 { 196 fprintf(stderr, "ERROR: Unable to load vertex shader\n"); 197 } 198 return program; 199} 200 201/********************************************************************** 202 * Geometry creation functions 203 *********************************************************************/ 204 205/* Generate vertices and indices for the heightmap 206 */ 207static void init_map(void) 208{ 209 int i; 210 int j; 211 int k; 212 GLfloat step = MAP_SIZE / (MAP_NUM_VERTICES - 1); 213 GLfloat x = 0.0f; 214 GLfloat z = 0.0f; 215 /* Create a flat grid */ 216 k = 0; 217 for (i = 0 ; i < MAP_NUM_VERTICES ; ++i) 218 { 219 for (j = 0 ; j < MAP_NUM_VERTICES ; ++j) 220 { 221 map_vertices[0][k] = x; 222 map_vertices[1][k] = 0.0f; 223 map_vertices[2][k] = z; 224 z += step; 225 ++k; 226 } 227 x += step; 228 z = 0.0f; 229 } 230#if DEBUG_ENABLED 231 for (i = 0 ; i < MAP_NUM_TOTAL_VERTICES ; ++i) 232 { 233 printf ("Vertice %d (%f, %f, %f)\n", 234 i, map_vertices[0][i], map_vertices[1][i], map_vertices[2][i]); 235 236 } 237#endif 238 /* create indices */ 239 /* line fan based on i 240 * i+1 241 * | / i + n + 1 242 * | / 243 * |/ 244 * i --- i + n 245 */ 246 247 /* close the top of the square */ 248 k = 0; 249 for (i = 0 ; i < MAP_NUM_VERTICES -1 ; ++i) 250 { 251 map_line_indices[k++] = (i + 1) * MAP_NUM_VERTICES -1; 252 map_line_indices[k++] = (i + 2) * MAP_NUM_VERTICES -1; 253 } 254 /* close the right of the square */ 255 for (i = 0 ; i < MAP_NUM_VERTICES -1 ; ++i) 256 { 257 map_line_indices[k++] = (MAP_NUM_VERTICES - 1) * MAP_NUM_VERTICES + i; 258 map_line_indices[k++] = (MAP_NUM_VERTICES - 1) * MAP_NUM_VERTICES + i + 1; 259 } 260 261 for (i = 0 ; i < (MAP_NUM_VERTICES - 1) ; ++i) 262 { 263 for (j = 0 ; j < (MAP_NUM_VERTICES - 1) ; ++j) 264 { 265 int ref = i * (MAP_NUM_VERTICES) + j; 266 map_line_indices[k++] = ref; 267 map_line_indices[k++] = ref + 1; 268 269 map_line_indices[k++] = ref; 270 map_line_indices[k++] = ref + MAP_NUM_VERTICES; 271 272 map_line_indices[k++] = ref; 273 map_line_indices[k++] = ref + MAP_NUM_VERTICES + 1; 274 } 275 } 276 277#ifdef DEBUG_ENABLED 278 for (k = 0 ; k < 2 * MAP_NUM_LINES ; k += 2) 279 { 280 int beg, end; 281 beg = map_line_indices[k]; 282 end = map_line_indices[k+1]; 283 printf ("Line %d: %d -> %d (%f, %f, %f) -> (%f, %f, %f)\n", 284 k / 2, beg, end, 285 map_vertices[0][beg], map_vertices[1][beg], map_vertices[2][beg], 286 map_vertices[0][end], map_vertices[1][end], map_vertices[2][end]); 287 } 288#endif 289} 290 291static void generate_heightmap__circle(float* center_x, float* center_y, 292 float* size, float* displacement) 293{ 294 float sign; 295 /* random value for element in between [0-1.0] */ 296 *center_x = (MAP_SIZE * rand()) / (float) RAND_MAX; 297 *center_y = (MAP_SIZE * rand()) / (float) RAND_MAX; 298 *size = (MAX_CIRCLE_SIZE * rand()) / (float) RAND_MAX; 299 sign = (1.0f * rand()) / (float) RAND_MAX; 300 sign = (sign < DISPLACEMENT_SIGN_LIMIT) ? -1.0f : 1.0f; 301 *displacement = (sign * (MAX_DISPLACEMENT * rand())) / (float) RAND_MAX; 302} 303 304/* Run the specified number of iterations of the generation process for the 305 * heightmap 306 */ 307static void update_map(int num_iter) 308{ 309 assert(num_iter > 0); 310 while(num_iter) 311 { 312 /* center of the circle */ 313 float center_x; 314 float center_z; 315 float circle_size; 316 float disp; 317 size_t ii; 318 generate_heightmap__circle(&center_x, &center_z, &circle_size, &disp); 319 disp = disp / 2.0f; 320 for (ii = 0u ; ii < MAP_NUM_TOTAL_VERTICES ; ++ii) 321 { 322 GLfloat dx = center_x - map_vertices[0][ii]; 323 GLfloat dz = center_z - map_vertices[2][ii]; 324 GLfloat pd = (2.0f * (float) sqrt((dx * dx) + (dz * dz))) / circle_size; 325 if (fabs(pd) <= 1.0f) 326 { 327 /* tx,tz is within the circle */ 328 GLfloat new_height = disp + (float) (cos(pd*3.14f)*disp); 329 map_vertices[1][ii] += new_height; 330 } 331 } 332 --num_iter; 333 } 334} 335 336/********************************************************************** 337 * OpenGL helper functions 338 *********************************************************************/ 339 340/* Create VBO, IBO and VAO objects for the heightmap geometry and bind them to 341 * the specified program object 342 */ 343static void make_mesh(GLuint program) 344{ 345 GLuint attrloc; 346 347 glGenVertexArrays(1, &mesh); 348 glGenBuffers(4, mesh_vbo); 349 glBindVertexArray(mesh); 350 /* Prepare the data for drawing through a buffer inidices */ 351 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh_vbo[3]); 352 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)* MAP_NUM_LINES * 2, map_line_indices, GL_STATIC_DRAW); 353 354 /* Prepare the attributes for rendering */ 355 attrloc = glGetAttribLocation(program, "x"); 356 glBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[0]); 357 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[0][0], GL_STATIC_DRAW); 358 glEnableVertexAttribArray(attrloc); 359 glVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0); 360 361 attrloc = glGetAttribLocation(program, "z"); 362 glBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[2]); 363 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[2][0], GL_STATIC_DRAW); 364 glEnableVertexAttribArray(attrloc); 365 glVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0); 366 367 attrloc = glGetAttribLocation(program, "y"); 368 glBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[1]); 369 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[1][0], GL_DYNAMIC_DRAW); 370 glEnableVertexAttribArray(attrloc); 371 glVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0); 372} 373 374/* Update VBO vertices from source data 375 */ 376static void update_mesh(void) 377{ 378 glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[1][0]); 379} 380 381/********************************************************************** 382 * GLFW callback functions 383 *********************************************************************/ 384 385static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) 386{ 387 switch(key) 388 { 389 case GLFW_KEY_ESCAPE: 390 /* Exit program on Escape */ 391 glfwSetWindowShouldClose(window, GLFW_TRUE); 392 break; 393 } 394} 395 396static void error_callback(int error, const char* description) 397{ 398 fprintf(stderr, "Error: %s\n", description); 399} 400 401int main(int argc, char** argv) 402{ 403 GLFWwindow* window; 404 int iter; 405 double dt; 406 double last_update_time; 407 int frame; 408 float f; 409 GLint uloc_modelview; 410 GLint uloc_project; 411 int width, height; 412 413 GLuint shader_program; 414 415 glfwSetErrorCallback(error_callback); 416 417 if (!glfwInit()) 418 exit(EXIT_FAILURE); 419 420 glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); 421 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 422 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); 423 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 424 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); 425 426 window = glfwCreateWindow(800, 600, "GLFW OpenGL3 Heightmap demo", NULL, NULL); 427 if (! window ) 428 { 429 glfwTerminate(); 430 exit(EXIT_FAILURE); 431 } 432 433 /* Register events callback */ 434 glfwSetKeyCallback(window, key_callback); 435 436 glfwMakeContextCurrent(window); 437 gladLoadGL(glfwGetProcAddress); 438 439 /* Prepare opengl resources for rendering */ 440 shader_program = make_shader_program(vertex_shader_text, fragment_shader_text); 441 442 if (shader_program == 0u) 443 { 444 glfwTerminate(); 445 exit(EXIT_FAILURE); 446 } 447 448 glUseProgram(shader_program); 449 uloc_project = glGetUniformLocation(shader_program, "project"); 450 uloc_modelview = glGetUniformLocation(shader_program, "modelview"); 451 452 /* Compute the projection matrix */ 453 f = 1.0f / tanf(view_angle / 2.0f); 454 projection_matrix[0] = f / aspect_ratio; 455 projection_matrix[5] = f; 456 projection_matrix[10] = (z_far + z_near)/ (z_near - z_far); 457 projection_matrix[11] = -1.0f; 458 projection_matrix[14] = 2.0f * (z_far * z_near) / (z_near - z_far); 459 glUniformMatrix4fv(uloc_project, 1, GL_FALSE, projection_matrix); 460 461 /* Set the camera position */ 462 modelview_matrix[12] = -5.0f; 463 modelview_matrix[13] = -5.0f; 464 modelview_matrix[14] = -20.0f; 465 glUniformMatrix4fv(uloc_modelview, 1, GL_FALSE, modelview_matrix); 466 467 /* Create mesh data */ 468 init_map(); 469 make_mesh(shader_program); 470 471 /* Create vao + vbo to store the mesh */ 472 /* Create the vbo to store all the information for the grid and the height */ 473 474 /* setup the scene ready for rendering */ 475 glfwGetFramebufferSize(window, &width, &height); 476 glViewport(0, 0, width, height); 477 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 478 479 /* main loop */ 480 frame = 0; 481 iter = 0; 482 last_update_time = glfwGetTime(); 483 484 while (!glfwWindowShouldClose(window)) 485 { 486 ++frame; 487 /* render the next frame */ 488 glClear(GL_COLOR_BUFFER_BIT); 489 glDrawElements(GL_LINES, 2* MAP_NUM_LINES , GL_UNSIGNED_INT, 0); 490 491 /* display and process events through callbacks */ 492 glfwSwapBuffers(window); 493 glfwPollEvents(); 494 /* Check the frame rate and update the heightmap if needed */ 495 dt = glfwGetTime(); 496 if ((dt - last_update_time) > 0.2) 497 { 498 /* generate the next iteration of the heightmap */ 499 if (iter < MAX_ITER) 500 { 501 update_map(NUM_ITER_AT_A_TIME); 502 update_mesh(); 503 iter += NUM_ITER_AT_A_TIME; 504 } 505 last_update_time = dt; 506 frame = 0; 507 } 508 } 509 510 glfwTerminate(); 511 exit(EXIT_SUCCESS); 512} 513 514
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.