heightmap.c 16 KB

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