main.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. /*================================================================
  2. * Copyright: 2020 John Jackson
  3. * terrain
  4. Dynamic heightmap terrain demo.
  5. Press `esc` to exit the application.
  6. ================================================================*/
  7. #include <gs.h>
  8. #include "sdnoise1234.h"
  9. // Heightmap Terrain Demo
  10. // Ripped from Sebastian Lague's demo, converted/modified to C
  11. // Struct Defines
  12. typedef struct model_t
  13. {
  14. gs_vertex_buffer_t vbo;
  15. u32 vertex_count;
  16. } model_t;
  17. typedef struct color_t
  18. {
  19. u8 r;
  20. u8 g;
  21. u8 b;
  22. u8 a;
  23. } color_t;
  24. typedef struct terrain_type
  25. {
  26. f32 height;
  27. color_t color;
  28. } terrain_type;
  29. typedef struct terrain_vert_data_t
  30. {
  31. gs_vec3 position;
  32. gs_vec3 normal;
  33. gs_vec2 tex_coord;
  34. } terrain_vert_data_t;
  35. typedef struct terrain_mesh_data_packet_t
  36. {
  37. f32* data;
  38. usize sz;
  39. u32 count;
  40. } terrain_mesh_data_packet_t;
  41. // Constants
  42. gs_global f32 scale = 100.f;
  43. gs_global u32 octaves = 4;
  44. gs_global f32 persistence = 0.5f;
  45. gs_global f32 lacunarity = 2.f;
  46. gs_global const u32 map_width = 200;
  47. gs_global const u32 map_height = 200;
  48. // Globals
  49. gs_global gs_shader_t shader = {0};
  50. gs_global gs_texture_t noise_tex = {0};
  51. gs_global gs_uniform_t u_noise_tex = {0};
  52. gs_global gs_uniform_t u_proj = {0};
  53. gs_global gs_uniform_t u_view = {0};
  54. gs_global gs_uniform_t u_model = {0};
  55. gs_global gs_uniform_t u_view_pos = {0};
  56. gs_global model_t terrain_model = {0};
  57. gs_global gs_command_buffer_t g_cb = {0};
  58. // Function Forward Decls.
  59. gs_result app_init(); // Use to init your application
  60. gs_result app_update(); // Use to update your application
  61. gs_result app_shutdown(); // Use to shutdown your appliaction
  62. void render_scene();
  63. void generate_terrain_mesh(f32* noise_data, u32 width, u32 height);
  64. int main(int argc, char** argv)
  65. {
  66. gs_application_desc_t app = {0};
  67. app.window_title = "Terrain Demo";
  68. app.window_width = 800;
  69. app.window_height = 600;
  70. app.init = &app_init;
  71. app.update = &app_update;
  72. app.shutdown = &app_shutdown;
  73. // Construct internal instance of our engine
  74. gs_engine_t* engine = gs_engine_construct(app);
  75. // Run the internal engine loop until completion
  76. gs_result res = engine->run();
  77. // Check result of engine after exiting loop
  78. if (res != gs_result_success)
  79. {
  80. gs_println("Error: Engine did not successfully finish running.");
  81. return -1;
  82. }
  83. gs_println("Gunslinger exited successfully.");
  84. return 0;
  85. }
  86. f32* generate_noise_map(u32 width, u32 height, f32 scale, u32 octaves, f32 persistence, f32 lacunarity, f32 x_offset, f32 y_offset)
  87. {
  88. f32* noise_map = gs_malloc(width * height * sizeof(f32));
  89. gs_assert(noise_map);
  90. f32 max_noise_height = f32_min;
  91. f32 min_noise_height = f32_max;
  92. for (s32 y = 0; y < height; y++)
  93. {
  94. for (s32 x = 0; x < width; x++)
  95. {
  96. f32 amplitude = 1.f;
  97. f32 frequency = 1.f;
  98. f32 noise_height = 0.f;
  99. for (u32 i = 0; i < octaves; ++i)
  100. {
  101. f32 sample_x = ((x + x_offset) / scale) * frequency;
  102. f32 sample_y = ((y + y_offset) / scale) * frequency;
  103. f32 p_val = sdnoise2(sample_x, sample_y, NULL, NULL);
  104. noise_height += p_val * amplitude;
  105. amplitude *= persistence;
  106. frequency *= lacunarity;
  107. }
  108. noise_map[ y * width + x ] = noise_height;
  109. if (noise_height > max_noise_height)
  110. max_noise_height = noise_height;
  111. else if (noise_height < min_noise_height)
  112. min_noise_height = noise_height;
  113. }
  114. }
  115. // Renormalize ranges between [0.0, 1.0]
  116. for (s32 y = 0; y < height; ++y)
  117. {
  118. for (s32 x = 0; x < width; ++x)
  119. {
  120. noise_map[ y * width + x ] = gs_map_range(min_noise_height, max_noise_height,
  121. 0.0f, 1.f, noise_map[ y * width + x ]);
  122. }
  123. }
  124. return noise_map;
  125. }
  126. color_t* generate_color_map(f32* noise_map, u32 width, u32 height)
  127. {
  128. gs_assert(noise_map);
  129. color_t* color_map= gs_malloc(width * height * sizeof(color_t));
  130. gs_assert(color_map);
  131. terrain_type regions[] = {
  132. {0.3f, {10, 20, 150, 255}}, // Deep Water
  133. {0.5f, {10, 50, 250, 255}}, // Shallow Water
  134. {0.53f, {255, 255, 153, 255}}, // Sand/Beach
  135. {0.6f, {100, 170, 40, 255}}, // Grass
  136. {0.65f, {100, 140, 30, 255}}, // Grass2
  137. {0.8f, {153, 102, 10, 255}}, // Rock
  138. {0.85f, {51, 26, 0, 255}}, // Rock2
  139. {1.0f, {200, 190, 210, 255}} // Snow
  140. };
  141. u32 num_regions = sizeof(regions) / sizeof(terrain_type);
  142. // We'll then create a color map from these noise values
  143. for (s32 y = 0; y < height; y++)
  144. {
  145. for (s32 x = 0; x < width; x++)
  146. {
  147. u32 idx = y * width + x;
  148. f32 p = noise_map[ idx ];
  149. for (u32 i = 0; i < num_regions; ++i) {
  150. if (p <= regions[ i ].height) {
  151. color_map[ idx ] = regions[ i ].color;
  152. break;
  153. }
  154. }
  155. }
  156. }
  157. return color_map;
  158. }
  159. terrain_mesh_data_packet_t generate_terrain_mesh_data(f32* noise_data, u32 width, u32 height)
  160. {
  161. gs_graphics_i* gfx = gs_engine_instance()->ctx.graphics;
  162. gs_dyn_array(gs_vec3) positions = gs_dyn_array_new(gs_vec3);
  163. gs_dyn_array(gs_vec2) uvs = gs_dyn_array_new(gs_vec2);
  164. gs_dyn_array(u32) tris = gs_dyn_array_new(u32);
  165. // Generate triangles, calculate normals, calculate uvs
  166. f32 top_left_x = (f32)(width - 1) / -2.f;
  167. f32 top_left_z = (f32)(height - 1) / 2.f;
  168. // Generate mesh data
  169. for (u32 y = 0; y < height; ++y)
  170. {
  171. for (u32 x = 0; x < width; ++x)
  172. {
  173. u32 idx = y * width + x;
  174. // Want to define some way of being able to pass in a curve to evaluate data for this
  175. f32 nd = noise_data[ idx ];
  176. f32 mult = 1.f;
  177. f32 water_height = 0.3f;
  178. f32 sand_height = 0.5f;
  179. if (nd <= water_height) {
  180. mult = gs_map_range(0.f, water_height, 0.f, 0.9f, nd);
  181. } else {
  182. mult = gs_map_range(water_height + 0.1f, 1.f, 10.f, 30.f, nd);
  183. }
  184. gs_dyn_array_push(positions, ((gs_vec3){top_left_x + x, nd * mult, top_left_z - y }));
  185. gs_dyn_array_push(uvs, ((gs_vec2){ x / (f32)width, y / (f32)height }));
  186. if (x < (width - 1) && y < (height - 1)) {
  187. // Add triangle
  188. gs_dyn_array_push(tris, idx);
  189. gs_dyn_array_push(tris, idx + width);
  190. gs_dyn_array_push(tris, idx + width + 1);
  191. // Add triangle
  192. gs_dyn_array_push(tris, idx + width + 1);
  193. gs_dyn_array_push(tris, idx + 1);
  194. gs_dyn_array_push(tris, idx);
  195. }
  196. }
  197. }
  198. gs_vec3* vertex_normals = gs_malloc(sizeof(gs_vec3) * gs_dyn_array_size(positions));
  199. memset(vertex_normals, 0, sizeof(gs_vec3) * gs_dyn_array_size(positions));
  200. // Now that we have positions, uvs, and triangles, need to calculate normals for each triangle
  201. // For now, just put normal as UP, cause normals are going to take more time to do
  202. // Go through each triangle, calculate normal
  203. for (u32 i = 0; i < gs_dyn_array_size(tris); i += 3)
  204. {
  205. u32 idx_0 = tris[ i ];
  206. u32 idx_1 = tris[ i + 1 ];
  207. u32 idx_2 = tris[ i + 2 ];
  208. gs_vec3 pos_0 = positions[ idx_0 ];
  209. gs_vec3 pos_1 = positions[ idx_1 ];
  210. gs_vec3 pos_2 = positions[ idx_2 ];
  211. // Calculate vector a = normalize(pos_1 - pos_0)
  212. gs_vec3 a = gs_vec3_norm(gs_vec3_sub(pos_1, pos_0));
  213. // Calculate vector b = normalize(pos_2 - pos_0)
  214. gs_vec3 b = gs_vec3_norm(gs_vec3_sub(pos_2, pos_0));
  215. // Calculate normal
  216. gs_vec3 n = gs_vec3_norm(gs_vec3_cross(b, a));
  217. // Add normal to every position idx found up above
  218. vertex_normals[ idx_0 ] = gs_vec3_add(vertex_normals[ idx_0 ], n);
  219. vertex_normals[ idx_1 ] = gs_vec3_add(vertex_normals[ idx_1 ], n);
  220. vertex_normals[ idx_2 ] = gs_vec3_add(vertex_normals[ idx_2 ], n);
  221. }
  222. // Loop through all vertex normals and normalize
  223. gs_for_range_i(gs_dyn_array_size(positions))
  224. {
  225. vertex_normals[ i ] = gs_vec3_norm(vertex_normals[ i ]);
  226. }
  227. // Batch vertex data together
  228. usize vert_data_size = gs_dyn_array_size(tris) * sizeof(terrain_vert_data_t);
  229. f32* vertex_data = gs_malloc(vert_data_size);
  230. // Have to interleave data
  231. u32 n_idx = 0;
  232. gs_for_range_i(gs_dyn_array_size(tris))
  233. {
  234. u32 base_idx = i * 8;
  235. u32 idx = tris[ i ];
  236. gs_vec3 pos = positions[ idx ];
  237. gs_vec3 norm = vertex_normals[ idx ];
  238. gs_vec2 uv = uvs[ idx ];
  239. vertex_data[ base_idx + 0 ] = pos.x;
  240. vertex_data[ base_idx + 1 ] = pos.y;
  241. vertex_data[ base_idx + 2 ] = pos.z;
  242. vertex_data[ base_idx + 3 ] = norm.x;
  243. vertex_data[ base_idx + 4 ] = norm.y;
  244. vertex_data[ base_idx + 5 ] = norm.z;
  245. vertex_data[ base_idx + 6 ] = uv.x;
  246. vertex_data[ base_idx + 7 ] = uv.y;
  247. if (i % 3 == 0)
  248. n_idx++;
  249. }
  250. terrain_mesh_data_packet_t packet;
  251. packet.data = vertex_data;
  252. packet.sz = vert_data_size;
  253. packet.count = gs_dyn_array_size(tris);
  254. // Free used memory
  255. gs_dyn_array_free(positions);
  256. gs_dyn_array_free(uvs);
  257. gs_free(vertex_normals);
  258. gs_dyn_array_free(tris);
  259. return packet;
  260. }
  261. gs_result app_init()
  262. {
  263. // Graphics api instance
  264. gs_graphics_i* gfx = gs_engine_instance()->ctx.graphics;
  265. // Platform api instance
  266. gs_platform_i* platform = gs_engine_instance()->ctx.platform;
  267. // Create noise map
  268. f32* noise_map = generate_noise_map(map_width, map_height, scale, octaves, persistence, lacunarity, 0.f, 0.f);
  269. // Create color map from noise
  270. color_t* color_map = generate_color_map(noise_map, map_width, map_height);
  271. // Generate terrain mesh data from noise
  272. terrain_mesh_data_packet_t mesh = generate_terrain_mesh_data(noise_map, map_width, map_height);
  273. gs_vertex_attribute_type layout[] = {
  274. gs_vertex_attribute_float3,
  275. gs_vertex_attribute_float3,
  276. gs_vertex_attribute_float2
  277. };
  278. // Create mesh
  279. terrain_model.vbo = gfx->construct_vertex_buffer(layout, sizeof(layout), mesh.data, mesh.sz);
  280. terrain_model.vertex_count = mesh.count;
  281. // Make our noise texture for gpu
  282. gs_texture_parameter_desc t_desc = gs_texture_parameter_desc_default();
  283. t_desc.width = map_width;
  284. t_desc.height = map_height;
  285. t_desc.mag_filter = gs_nearest;
  286. t_desc.min_filter = gs_nearest;
  287. t_desc.mipmap_filter = gs_nearest;
  288. t_desc.data = color_map;
  289. // Construct texture
  290. noise_tex = gfx->construct_texture(t_desc);
  291. char* v_src = NULL;
  292. char* f_src = NULL;
  293. // Construct shader
  294. if (platform->file_exists("../assets/shaders/terrain.v.glsl")) {
  295. v_src = platform->read_file_contents("../assets/shaders/terrain.v.glsl", "r", NULL);
  296. f_src = platform->read_file_contents("../assets/shaders/terrain.f.glsl", "r", NULL);
  297. shader = gfx->construct_shader(v_src, f_src);
  298. }
  299. else if (platform->file_exists("./assets/shaders/terrain.v.glsl")) {
  300. v_src = platform->read_file_contents("./assets/shaders/terrain.v.glsl", "r", NULL);
  301. f_src = platform->read_file_contents("./assets/shaders/terrain.f.glsl", "r", NULL);
  302. shader = gfx->construct_shader(v_src, f_src);
  303. }
  304. else {
  305. gs_println("Can't find shaders!");
  306. gs_assert(false);
  307. }
  308. // Construct uniforms
  309. u_noise_tex = gfx->construct_uniform(shader, "u_noise_tex", gs_uniform_type_sampler2d);
  310. u_proj = gfx->construct_uniform(shader, "u_proj", gs_uniform_type_mat4);
  311. u_view = gfx->construct_uniform(shader, "u_view", gs_uniform_type_mat4);
  312. u_model = gfx->construct_uniform(shader, "u_model", gs_uniform_type_mat4);
  313. u_view_pos = gfx->construct_uniform(shader, "u_view_pos", gs_uniform_type_vec3);
  314. // Construct command buffer for rendering
  315. g_cb = gs_command_buffer_new();
  316. // Free data
  317. gs_free(noise_map);
  318. gs_free(color_map);
  319. gs_free(mesh.data);
  320. gs_free(v_src);
  321. gs_free(f_src);
  322. return gs_result_success;
  323. }
  324. void update_terrain()
  325. {
  326. static f32 t = 0.f;
  327. const f32 speed = 10.f;
  328. t += gs_engine_instance()->ctx.platform->time.delta;
  329. // f32 _scale = (sin(t) * 0.5f + 0.5f + 50.f) * 2.f;
  330. f32 _scale = 100.f;
  331. // f32 _persistence = (sin(t * 0.6f) * 0.5f + 0.5f);
  332. // f32 _lacunarity = (sin(t * 0.2f) * 0.5f + 0.5f + 1.f);
  333. f32 _persistence = (0.5f);
  334. f32 _lacunarity = (2.5f);
  335. // Create noise map
  336. f32* noise_map = generate_noise_map(map_width, map_height, _scale, octaves, _persistence, _lacunarity, t * speed, t);
  337. // Create color map from noise
  338. color_t* color_map = generate_color_map(noise_map, map_width, map_height);
  339. // Make our noise texture for gpu
  340. gs_texture_parameter_desc t_desc = gs_texture_parameter_desc_default();
  341. t_desc.width = map_width;
  342. t_desc.height = map_height;
  343. t_desc.mag_filter = gs_nearest;
  344. t_desc.min_filter = gs_nearest;
  345. t_desc.mipmap_filter = gs_nearest;
  346. t_desc.data = color_map;
  347. gs_graphics_i* gfx = gs_engine_instance()->ctx.graphics;
  348. // Update texture (let's just glTexImage2d for now)...
  349. gfx->update_texture_data(&noise_tex, t_desc);
  350. // Generate terrain mesh data from noise
  351. terrain_mesh_data_packet_t mesh = generate_terrain_mesh_data(noise_map, map_width, map_height);
  352. // Create mesh
  353. gfx->update_vertex_buffer_data(terrain_model.vbo, mesh.data, mesh.sz);
  354. // Free data
  355. gs_free(noise_map);
  356. gs_free(color_map);
  357. gs_free(mesh.data);
  358. }
  359. gs_result app_update()
  360. {
  361. // Grab global instance of engine
  362. gs_engine_t* engine = gs_engine_instance();
  363. gs_timed_action(20,
  364. {
  365. gs_println("Frame: %.2f", engine->ctx.platform->time.frame);
  366. });
  367. // If we press the escape key, exit the application
  368. if (engine->ctx.platform->key_pressed(gs_keycode_esc))
  369. {
  370. return gs_result_success;
  371. }
  372. // Want to update the data for the terrain over time (to give the effect of it scrolling)
  373. update_terrain();
  374. // Render terrain
  375. render_scene();
  376. // Otherwise, continue
  377. return gs_result_in_progress;
  378. }
  379. gs_result app_shutdown()
  380. {
  381. return gs_result_success;
  382. }
  383. void render_scene()
  384. {
  385. // Grab graphics api instance
  386. gs_graphics_i* gfx = gs_engine_instance()->ctx.graphics;
  387. gs_platform_i* platform = gs_engine_instance()->ctx.platform;
  388. gs_command_buffer_t* cb = &g_cb;
  389. const gs_vec2 ws = platform->window_size(platform->main_window());
  390. const gs_vec2 fbs = platform->frame_buffer_size(platform->main_window());
  391. // Clear screen
  392. f32 clear_color[4] = { 0.3f, 0.3f, 0.3f, 1.f };
  393. gfx->set_view_clear(cb, clear_color);
  394. gfx->set_face_culling(cb, gs_face_culling_front);
  395. gfx->set_viewport(cb, 0.f, 0.f, fbs.x, fbs.y);
  396. // Set depth flags
  397. gfx->set_depth_enabled(cb, true);
  398. // Bind shader
  399. gfx->bind_shader(cb, shader);
  400. // Bind texture
  401. gfx->bind_texture(cb, u_noise_tex, noise_tex, 0);
  402. static f32 t = 0.f;
  403. t += 0.1f * gs_engine_instance()->ctx.platform->time.delta;
  404. gs_mat4 model = gs_mat4_identity();
  405. gs_vqs xform = gs_vqs_default();
  406. gs_quat rot = gs_quat_angle_axis(gs_deg_to_rad(30.f), (gs_vec3){1.f, 0.f, 0.f});
  407. rot = gs_quat_mul_quat(rot, gs_quat_angle_axis(t, (gs_vec3){0.f, 1.f, 0.f}));
  408. xform.rotation = rot;
  409. model = gs_vqs_to_mat4(&xform);
  410. gs_mat4 view = gs_mat4_identity();
  411. gs_mat4 proj = gs_mat4_identity();
  412. // view = gs_mat4_translate((gs_vec3){0.f, -10.f, -200.f});
  413. // proj = gs_mat4_perspective(45.f, 800.f/600.f, 0.01f, 1000.f);
  414. const f32 scl = 0.5f;
  415. gs_mat4 view_mtx = gs_mat4_translate((gs_vec3){0.f, -10.f, -200.f});
  416. gs_mat4 proj_mtx = gs_mat4_perspective(60.f, ws.x / ws.y, 0.01f, 1000.f);
  417. // gs_mat4 proj_mtx = gs_mat4_ortho(-ws.x / 2.f * scl, ws.x / 2.f * scl, ws.y / 2.f * scl, -ws.y / 2.f * scl, 0.01f, 1000.f);
  418. f32 t_s = t * 10.f;
  419. gs_vec3 vp = (gs_vec3){0.f, -10.f, -250.f};
  420. gfx->bind_uniform(cb, u_view_pos, &vp);
  421. gfx->bind_uniform(cb, u_view, &view_mtx);
  422. gfx->bind_uniform(cb, u_proj, &proj_mtx);
  423. gfx->bind_uniform(cb, u_model, &model);
  424. // Bind vertex buffer of terrain
  425. gfx->bind_vertex_buffer(cb, terrain_model.vbo);
  426. // Draw
  427. gfx->draw(cb, 0, terrain_model.vertex_count);
  428. // Submit command buffer to graphics api for final render
  429. gfx->submit_command_buffer(cb);
  430. }