2
0

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