|
|
- //========================================================================
- // Heightmap example program using OpenGL 3 core profile
- // Copyright (c) 2010 Olivier Delannoy
- //
- // This software is provided 'as-is', without any express or implied
- // warranty. In no event will the authors be held liable for any damages
- // arising from the use of this software.
- //
- // Permission is granted to anyone to use this software for any purpose,
- // including commercial applications, and to alter it and redistribute it
- // freely, subject to the following restrictions:
- //
- // 1. The origin of this software must not be misrepresented; you must not
- // claim that you wrote the original software. If you use this software
- // in a product, an acknowledgment in the product documentation would
- // be appreciated but is not required.
- //
- // 2. Altered source versions must be plainly marked as such, and must not
- // be misrepresented as being the original software.
- //
- // 3. This notice may not be removed or altered from any source
- // distribution.
- //
- //========================================================================
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <math.h>
- #include <assert.h>
- #include <stddef.h>
-
- #include <glad/glad.h>
- #include <GLFW/glfw3.h>
-
- /* Map height updates */
- #define MAX_CIRCLE_SIZE (5.0f)
- #define MAX_DISPLACEMENT (1.0f)
- #define DISPLACEMENT_SIGN_LIMIT (0.3f)
- #define MAX_ITER (200)
- #define NUM_ITER_AT_A_TIME (1)
-
- /* Map general information */
- #define MAP_SIZE (10.0f)
- #define MAP_NUM_VERTICES (80)
- #define MAP_NUM_TOTAL_VERTICES (MAP_NUM_VERTICES*MAP_NUM_VERTICES)
- #define MAP_NUM_LINES (3* (MAP_NUM_VERTICES - 1) * (MAP_NUM_VERTICES - 1) + \
- 2 * (MAP_NUM_VERTICES - 1))
-
-
- /**********************************************************************
- * Default shader programs
- *********************************************************************/
-
- static const char* vertex_shader_text =
- "#version 150\n"
- "uniform mat4 project;\n"
- "uniform mat4 modelview;\n"
- "in float x;\n"
- "in float y;\n"
- "in float z;\n"
- "\n"
- "void main()\n"
- "{\n"
- " gl_Position = project * modelview * vec4(x, y, z, 1.0);\n"
- "}\n";
-
- static const char* fragment_shader_text =
- "#version 150\n"
- "out vec4 color;\n"
- "void main()\n"
- "{\n"
- " color = vec4(0.2, 1.0, 0.2, 1.0); \n"
- "}\n";
-
- /**********************************************************************
- * Values for shader uniforms
- *********************************************************************/
-
- /* Frustum configuration */
- static GLfloat view_angle = 45.0f;
- static GLfloat aspect_ratio = 4.0f/3.0f;
- static GLfloat z_near = 1.0f;
- static GLfloat z_far = 100.f;
-
- /* Projection matrix */
- static GLfloat projection_matrix[16] = {
- 1.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 1.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 1.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 1.0f
- };
-
- /* Model view matrix */
- static GLfloat modelview_matrix[16] = {
- 1.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 1.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 1.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 1.0f
- };
-
- /**********************************************************************
- * Heightmap vertex and index data
- *********************************************************************/
-
- static GLfloat map_vertices[3][MAP_NUM_TOTAL_VERTICES];
- static GLuint map_line_indices[2*MAP_NUM_LINES];
-
- /* Store uniform location for the shaders
- * Those values are setup as part of the process of creating
- * the shader program. They should not be used before creating
- * the program.
- */
- static GLuint mesh;
- static GLuint mesh_vbo[4];
-
- /**********************************************************************
- * OpenGL helper functions
- *********************************************************************/
-
- /* Creates a shader object of the specified type using the specified text
- */
- static GLuint make_shader(GLenum type, const char* text)
- {
- GLuint shader;
- GLint shader_ok;
- GLsizei log_length;
- char info_log[8192];
-
- shader = glCreateShader(type);
- if (shader != 0)
- {
- glShaderSource(shader, 1, (const GLchar**)&text, NULL);
- glCompileShader(shader);
- glGetShaderiv(shader, GL_COMPILE_STATUS, &shader_ok);
- if (shader_ok != GL_TRUE)
- {
- fprintf(stderr, "ERROR: Failed to compile %s shader\n", (type == GL_FRAGMENT_SHADER) ? "fragment" : "vertex" );
- glGetShaderInfoLog(shader, 8192, &log_length,info_log);
- fprintf(stderr, "ERROR: \n%s\n\n", info_log);
- glDeleteShader(shader);
- shader = 0;
- }
- }
- return shader;
- }
-
- /* Creates a program object using the specified vertex and fragment text
- */
- static GLuint make_shader_program(const char* vs_text, const char* fs_text)
- {
- GLuint program = 0u;
- GLint program_ok;
- GLuint vertex_shader = 0u;
- GLuint fragment_shader = 0u;
- GLsizei log_length;
- char info_log[8192];
-
- vertex_shader = make_shader(GL_VERTEX_SHADER, vs_text);
- if (vertex_shader != 0u)
- {
- fragment_shader = make_shader(GL_FRAGMENT_SHADER, fs_text);
- if (fragment_shader != 0u)
- {
- /* make the program that connect the two shader and link it */
- program = glCreateProgram();
- if (program != 0u)
- {
- /* attach both shader and link */
- glAttachShader(program, vertex_shader);
- glAttachShader(program, fragment_shader);
- glLinkProgram(program);
- glGetProgramiv(program, GL_LINK_STATUS, &program_ok);
-
- if (program_ok != GL_TRUE)
- {
- fprintf(stderr, "ERROR, failed to link shader program\n");
- glGetProgramInfoLog(program, 8192, &log_length, info_log);
- fprintf(stderr, "ERROR: \n%s\n\n", info_log);
- glDeleteProgram(program);
- glDeleteShader(fragment_shader);
- glDeleteShader(vertex_shader);
- program = 0u;
- }
- }
- }
- else
- {
- fprintf(stderr, "ERROR: Unable to load fragment shader\n");
- glDeleteShader(vertex_shader);
- }
- }
- else
- {
- fprintf(stderr, "ERROR: Unable to load vertex shader\n");
- }
- return program;
- }
-
- /**********************************************************************
- * Geometry creation functions
- *********************************************************************/
-
- /* Generate vertices and indices for the heightmap
- */
- static void init_map(void)
- {
- int i;
- int j;
- int k;
- GLfloat step = MAP_SIZE / (MAP_NUM_VERTICES - 1);
- GLfloat x = 0.0f;
- GLfloat z = 0.0f;
- /* Create a flat grid */
- k = 0;
- for (i = 0 ; i < MAP_NUM_VERTICES ; ++i)
- {
- for (j = 0 ; j < MAP_NUM_VERTICES ; ++j)
- {
- map_vertices[0][k] = x;
- map_vertices[1][k] = 0.0f;
- map_vertices[2][k] = z;
- z += step;
- ++k;
- }
- x += step;
- z = 0.0f;
- }
- #if DEBUG_ENABLED
- for (i = 0 ; i < MAP_NUM_TOTAL_VERTICES ; ++i)
- {
- printf ("Vertice %d (%f, %f, %f)\n",
- i, map_vertices[0][i], map_vertices[1][i], map_vertices[2][i]);
-
- }
- #endif
- /* create indices */
- /* line fan based on i
- * i+1
- * | / i + n + 1
- * | /
- * |/
- * i --- i + n
- */
-
- /* close the top of the square */
- k = 0;
- for (i = 0 ; i < MAP_NUM_VERTICES -1 ; ++i)
- {
- map_line_indices[k++] = (i + 1) * MAP_NUM_VERTICES -1;
- map_line_indices[k++] = (i + 2) * MAP_NUM_VERTICES -1;
- }
- /* close the right of the square */
- for (i = 0 ; i < MAP_NUM_VERTICES -1 ; ++i)
- {
- map_line_indices[k++] = (MAP_NUM_VERTICES - 1) * MAP_NUM_VERTICES + i;
- map_line_indices[k++] = (MAP_NUM_VERTICES - 1) * MAP_NUM_VERTICES + i + 1;
- }
-
- for (i = 0 ; i < (MAP_NUM_VERTICES - 1) ; ++i)
- {
- for (j = 0 ; j < (MAP_NUM_VERTICES - 1) ; ++j)
- {
- int ref = i * (MAP_NUM_VERTICES) + j;
- map_line_indices[k++] = ref;
- map_line_indices[k++] = ref + 1;
-
- map_line_indices[k++] = ref;
- map_line_indices[k++] = ref + MAP_NUM_VERTICES;
-
- map_line_indices[k++] = ref;
- map_line_indices[k++] = ref + MAP_NUM_VERTICES + 1;
- }
- }
-
- #ifdef DEBUG_ENABLED
- for (k = 0 ; k < 2 * MAP_NUM_LINES ; k += 2)
- {
- int beg, end;
- beg = map_line_indices[k];
- end = map_line_indices[k+1];
- printf ("Line %d: %d -> %d (%f, %f, %f) -> (%f, %f, %f)\n",
- k / 2, beg, end,
- map_vertices[0][beg], map_vertices[1][beg], map_vertices[2][beg],
- map_vertices[0][end], map_vertices[1][end], map_vertices[2][end]);
- }
- #endif
- }
-
- static void generate_heightmap__circle(float* center_x, float* center_y,
- float* size, float* displacement)
- {
- float sign;
- /* random value for element in between [0-1.0] */
- *center_x = (MAP_SIZE * rand()) / (1.0f * RAND_MAX);
- *center_y = (MAP_SIZE * rand()) / (1.0f * RAND_MAX);
- *size = (MAX_CIRCLE_SIZE * rand()) / (1.0f * RAND_MAX);
- sign = (1.0f * rand()) / (1.0f * RAND_MAX);
- sign = (sign < DISPLACEMENT_SIGN_LIMIT) ? -1.0f : 1.0f;
- *displacement = (sign * (MAX_DISPLACEMENT * rand())) / (1.0f * RAND_MAX);
- }
-
- /* Run the specified number of iterations of the generation process for the
- * heightmap
- */
- static void update_map(int num_iter)
- {
- assert(num_iter > 0);
- while(num_iter)
- {
- /* center of the circle */
- float center_x;
- float center_z;
- float circle_size;
- float disp;
- size_t ii;
- generate_heightmap__circle(¢er_x, ¢er_z, &circle_size, &disp);
- disp = disp / 2.0f;
- for (ii = 0u ; ii < MAP_NUM_TOTAL_VERTICES ; ++ii)
- {
- GLfloat dx = center_x - map_vertices[0][ii];
- GLfloat dz = center_z - map_vertices[2][ii];
- GLfloat pd = (2.0f * (float) sqrt((dx * dx) + (dz * dz))) / circle_size;
- if (fabs(pd) <= 1.0f)
- {
- /* tx,tz is within the circle */
- GLfloat new_height = disp + (float) (cos(pd*3.14f)*disp);
- map_vertices[1][ii] += new_height;
- }
- }
- --num_iter;
- }
- }
-
- /**********************************************************************
- * OpenGL helper functions
- *********************************************************************/
-
- /* Create VBO, IBO and VAO objects for the heightmap geometry and bind them to
- * the specified program object
- */
- static void make_mesh(GLuint program)
- {
- GLuint attrloc;
-
- glGenVertexArrays(1, &mesh);
- glGenBuffers(4, mesh_vbo);
- glBindVertexArray(mesh);
- /* Prepare the data for drawing through a buffer inidices */
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh_vbo[3]);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)* MAP_NUM_LINES * 2, map_line_indices, GL_STATIC_DRAW);
-
- /* Prepare the attributes for rendering */
- attrloc = glGetAttribLocation(program, "x");
- glBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[0]);
- glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[0][0], GL_STATIC_DRAW);
- glEnableVertexAttribArray(attrloc);
- glVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0);
-
- attrloc = glGetAttribLocation(program, "z");
- glBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[2]);
- glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[2][0], GL_STATIC_DRAW);
- glEnableVertexAttribArray(attrloc);
- glVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0);
-
- attrloc = glGetAttribLocation(program, "y");
- glBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[1]);
- glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[1][0], GL_DYNAMIC_DRAW);
- glEnableVertexAttribArray(attrloc);
- glVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0);
- }
-
- /* Update VBO vertices from source data
- */
- static void update_mesh(void)
- {
- glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[1][0]);
- }
-
- /**********************************************************************
- * GLFW callback functions
- *********************************************************************/
-
- static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
- {
- switch(key)
- {
- case GLFW_KEY_ESCAPE:
- /* Exit program on Escape */
- glfwSetWindowShouldClose(window, GLFW_TRUE);
- break;
- }
- }
-
- static void error_callback(int error, const char* description)
- {
- fprintf(stderr, "Error: %s\n", description);
- }
-
- int main(int argc, char** argv)
- {
- GLFWwindow* window;
- int iter;
- double dt;
- double last_update_time;
- int frame;
- float f;
- GLint uloc_modelview;
- GLint uloc_project;
- int width, height;
-
- GLuint shader_program;
-
- glfwSetErrorCallback(error_callback);
-
- if (!glfwInit())
- exit(EXIT_FAILURE);
-
- glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
- glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
- glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
- glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
- glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
-
- window = glfwCreateWindow(800, 600, "GLFW OpenGL3 Heightmap demo", NULL, NULL);
- if (! window )
- {
- glfwTerminate();
- exit(EXIT_FAILURE);
- }
-
- /* Register events callback */
- glfwSetKeyCallback(window, key_callback);
-
- glfwMakeContextCurrent(window);
- gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);
-
- /* Prepare opengl resources for rendering */
- shader_program = make_shader_program(vertex_shader_text, fragment_shader_text);
-
- if (shader_program == 0u)
- {
- glfwTerminate();
- exit(EXIT_FAILURE);
- }
-
- glUseProgram(shader_program);
- uloc_project = glGetUniformLocation(shader_program, "project");
- uloc_modelview = glGetUniformLocation(shader_program, "modelview");
-
- /* Compute the projection matrix */
- f = 1.0f / tanf(view_angle / 2.0f);
- projection_matrix[0] = f / aspect_ratio;
- projection_matrix[5] = f;
- projection_matrix[10] = (z_far + z_near)/ (z_near - z_far);
- projection_matrix[11] = -1.0f;
- projection_matrix[14] = 2.0f * (z_far * z_near) / (z_near - z_far);
- glUniformMatrix4fv(uloc_project, 1, GL_FALSE, projection_matrix);
-
- /* Set the camera position */
- modelview_matrix[12] = -5.0f;
- modelview_matrix[13] = -5.0f;
- modelview_matrix[14] = -20.0f;
- glUniformMatrix4fv(uloc_modelview, 1, GL_FALSE, modelview_matrix);
-
- /* Create mesh data */
- init_map();
- make_mesh(shader_program);
-
- /* Create vao + vbo to store the mesh */
- /* Create the vbo to store all the information for the grid and the height */
-
- /* setup the scene ready for rendering */
- glfwGetFramebufferSize(window, &width, &height);
- glViewport(0, 0, width, height);
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-
- /* main loop */
- frame = 0;
- iter = 0;
- last_update_time = glfwGetTime();
-
- while (!glfwWindowShouldClose(window))
- {
- ++frame;
- /* render the next frame */
- glClear(GL_COLOR_BUFFER_BIT);
- glDrawElements(GL_LINES, 2* MAP_NUM_LINES , GL_UNSIGNED_INT, 0);
-
- /* display and process events through callbacks */
- glfwSwapBuffers(window);
- glfwPollEvents();
- /* Check the frame rate and update the heightmap if needed */
- dt = glfwGetTime();
- if ((dt - last_update_time) > 0.2)
- {
- /* generate the next iteration of the heightmap */
- if (iter < MAX_ITER)
- {
- update_map(NUM_ITER_AT_A_TIME);
- update_mesh();
- iter += NUM_ITER_AT_A_TIME;
- }
- last_update_time = dt;
- frame = 0;
- }
- }
-
- glfwTerminate();
- exit(EXIT_SUCCESS);
- }
-
|