You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

пре 12 година
пре 10 година
пре 8 година
пре 8 година
пре 8 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 8 година
пре 8 година
пре 12 година
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. //
  2. // Lol Engine — Voronoi diagram tutorial
  3. //
  4. // Copyright © 2015—2019 Sam Hocevar <sam@hocevar.net>
  5. // © 2011—2015 Benjamin “Touky” Huet <huet.benjamin@gmail.com>
  6. //
  7. // Lol Engine is free software. It comes without any warranty, to
  8. // the extent permitted by applicable law. You can redistribute it
  9. // and/or modify it under the terms of the Do What the Fuck You Want
  10. // to Public License, Version 2, as published by the WTFPL Task Force.
  11. // See http://www.wtfpl.net/ for more details.
  12. //
  13. #if HAVE_CONFIG_H
  14. # include "config.h"
  15. #endif
  16. #include <memory>
  17. #include <lol/engine.h>
  18. #include "loldebug.h"
  19. using namespace lol;
  20. LOLFX_RESOURCE_DECLARE(12_voronoi);
  21. LOLFX_RESOURCE_DECLARE(12_voronoi_setup);
  22. LOLFX_RESOURCE_DECLARE(12_voronoi_distance);
  23. LOLFX_RESOURCE_DECLARE(12_distance);
  24. LOLFX_RESOURCE_DECLARE(12_texture_to_screen);
  25. enum
  26. {
  27. KEY_ESC,
  28. KEY_PUSH,
  29. KEY_POP,
  30. KEY_F1,
  31. KEY_F2,
  32. KEY_F3,
  33. KEY_MAX
  34. };
  35. enum FboType
  36. {
  37. SrcVoronoiFbo,
  38. VoronoiFbo,
  39. DistanceVoronoiFbo,
  40. DistanceFbo,
  41. MaxFboType
  42. };
  43. class Voronoi : public WorldEntity
  44. {
  45. public:
  46. Voronoi()
  47. {
  48. m_vertices << vec2( 1.0, 1.0);
  49. m_vertices << vec2(-1.0, -1.0);
  50. m_vertices << vec2( 1.0, -1.0);
  51. m_vertices << vec2(-1.0, -1.0);
  52. m_vertices << vec2( 1.0, 1.0);
  53. m_vertices << vec2(-1.0, 1.0);
  54. m_ready = false;
  55. m_cur_fbo = 0;
  56. m_time = .0f;
  57. m_timer = -1.0f;
  58. mode = 0;
  59. m_controller = new Controller("Default");
  60. m_controller->GetKey(KEY_ESC).Bind("Keyboard", "Escape");
  61. m_controller->GetKey(KEY_PUSH).Bind("Keyboard", "p");
  62. m_controller->GetKey(KEY_POP).Bind("Keyboard", "o");
  63. m_controller->GetKey(KEY_F1).Bind("Keyboard", "F1");
  64. m_controller->GetKey(KEY_F2).Bind("Keyboard", "F2");
  65. m_controller->GetKey(KEY_F3).Bind("Keyboard", "F3");
  66. }
  67. virtual void tick_game(float seconds)
  68. {
  69. WorldEntity::tick_game(seconds);
  70. {
  71. //Shutdown logic
  72. if (m_controller->WasKeyReleasedThisFrame(KEY_ESC))
  73. Ticker::Shutdown();
  74. }
  75. m_time += seconds;
  76. m_hotspot = 0.4f * vec3((float)lol::sin(m_time * 4.0) + (float)lol::cos(m_time * 5.3),
  77. (float)lol::sin(m_time * 5.7) + (float)lol::cos(m_time * 4.4),
  78. (float)lol::sin(m_time * 5.0));
  79. m_color = 0.25f * vec3(1.1f + (float)lol::sin(m_time * 2.5 + 1.0),
  80. 1.1f + (float)lol::sin(m_time * 2.8 + 1.3),
  81. 1.1f + (float)lol::sin(m_time * 2.7));
  82. /* Saturate dot color */
  83. float x = std::max(m_color.x, std::max(m_color.y, m_color.z));
  84. m_color /= x;
  85. }
  86. virtual void tick_draw(float seconds, Scene &scene)
  87. {
  88. WorldEntity::tick_draw(seconds, scene);
  89. if (!m_ready)
  90. {
  91. m_vdecl = std::make_shared<VertexDeclaration>(VertexStream<vec2>(VertexUsage::Position));
  92. m_vbo = std::make_shared<VertexBuffer>(m_vertices.bytes());
  93. void *vertices = m_vbo->Lock(0, 0);
  94. memcpy(vertices, &m_vertices[0], m_vertices.bytes());
  95. m_vbo->Unlock();
  96. m_screen_shader = Shader::Create(LOLFX_RESOURCE_NAME(12_texture_to_screen));
  97. m_screen_coord = m_screen_shader->GetAttribLocation(VertexUsage::Position, 0);
  98. m_screen_texture = m_screen_shader->GetUniformLocation("u_texture");
  99. for (int i = 0; i < MaxFboType; ++i)
  100. {
  101. m_fbos.push(std::make_shared<Framebuffer>(Video::GetSize()), 0, array<ShaderUniform>(), array<ShaderAttrib>() );
  102. if (i == SrcVoronoiFbo)
  103. {
  104. m_fbos[i].m2 = Shader::Create(LOLFX_RESOURCE_NAME(12_voronoi_setup));
  105. m_fbos[i].m3 << m_fbos[i].m2->GetUniformLocation("u_texture");
  106. m_fbos[i].m3 << m_fbos[i].m2->GetUniformLocation("u_source_point");
  107. m_fbos[i].m3 << m_fbos[i].m2->GetUniformLocation("u_screen_res");
  108. m_fbos[i].m4 << m_fbos[i].m2->GetAttribLocation(VertexUsage::Position, 0);
  109. }
  110. else if (i == VoronoiFbo)
  111. {
  112. m_fbos[i].m2 = Shader::Create(LOLFX_RESOURCE_NAME(12_voronoi));
  113. m_fbos[i].m3 << m_fbos[i].m2->GetUniformLocation("u_texture");
  114. m_fbos[i].m3 << m_fbos[i].m2->GetUniformLocation("u_step");
  115. m_fbos[i].m3 << m_fbos[i].m2->GetUniformLocation("u_screen_res");
  116. m_fbos[i].m4 << m_fbos[i].m2->GetAttribLocation(VertexUsage::Position, 0);
  117. }
  118. else if (i == DistanceVoronoiFbo)
  119. {
  120. m_fbos[i].m2 = Shader::Create(LOLFX_RESOURCE_NAME(12_voronoi_distance));
  121. }
  122. else if (i == DistanceFbo)
  123. {
  124. m_fbos[i].m2 = Shader::Create(LOLFX_RESOURCE_NAME(12_distance));
  125. }
  126. m_fbos.last().m1->Bind();
  127. {
  128. render_context rc(scene.get_renderer());
  129. rc.clear_color(vec4(0.f, 0.f, 0.f, 1.f));
  130. rc.clear_depth(1.f);
  131. scene.get_renderer()->Clear(ClearMask::Color | ClearMask::Depth);
  132. }
  133. m_fbos.last().m1->Unbind();
  134. }
  135. temp_buffer = std::make_shared<Framebuffer>(Video::GetSize());
  136. temp_buffer->Bind();
  137. {
  138. render_context rc(scene.get_renderer());
  139. rc.clear_color(vec4(0.f, 0.f, 0.f, 1.f));
  140. rc.clear_depth(1.f);
  141. scene.get_renderer()->Clear(ClearMask::Color | ClearMask::Depth);
  142. }
  143. temp_buffer->Unbind();
  144. m_ready = true;
  145. /* FIXME: this object never cleans up */
  146. //SRC SETUP
  147. m_cur_fbo = VoronoiFbo;
  148. }
  149. {
  150. //Shutdown logic
  151. if (m_controller->WasKeyReleasedThisFrame(KEY_POP))
  152. voronoi_points.pop();
  153. else if (m_controller->WasKeyReleasedThisFrame(KEY_PUSH))
  154. voronoi_points.push(vec3(rand<float>(512.f), rand<float>(512.f), .0f),
  155. vec2(64.f + rand<float>(64.f), 64.f + rand<float>(64.f)));
  156. else if (m_controller->WasKeyReleasedThisFrame(KEY_F1))
  157. m_cur_fbo = SrcVoronoiFbo;
  158. else if (m_controller->WasKeyReleasedThisFrame(KEY_F2))
  159. m_cur_fbo = VoronoiFbo;
  160. else if (m_controller->WasKeyReleasedThisFrame(KEY_F3))
  161. {
  162. voronoi_points.clear();
  163. if (mode == 0)
  164. {
  165. int i = 4;
  166. while (i-- > 0)
  167. voronoi_points.push(vec3(rand<float>(512.f), rand<float>(512.f), .0f),
  168. vec2(64.f + rand<float>(64.f), 64.f + rand<float>(64.f))
  169. //vec2::zero
  170. );
  171. mode = 1;
  172. }
  173. else
  174. {
  175. mode = 0;
  176. }
  177. }
  178. }
  179. if (mode == 0)
  180. {
  181. voronoi_points.clear();
  182. int maxi = 6;
  183. for (int i = 0; i < maxi; ++i)
  184. {
  185. float mi = (float)maxi;
  186. float j = (float)i;
  187. float f_time = (float)m_time;
  188. voronoi_points.push(vec3(256.f) + 196.f * vec3(lol::cos( f_time + j * 2.f * F_PI / mi), lol::sin( f_time + j * 2.f * F_PI / mi), .0f), vec2(.0f));
  189. voronoi_points.push(vec3(256.f) + 128.f * vec3(lol::cos(-f_time + j * 2.f * F_PI / mi), lol::sin(-f_time + j * 2.f * F_PI / mi), .0f), vec2(.0f));
  190. voronoi_points.push(vec3(256.f) + 64.f * vec3(lol::cos( f_time + j * 2.f * F_PI / mi), lol::sin( f_time + j * 2.f * F_PI / mi), .0f), vec2(.0f));
  191. voronoi_points.push(vec3(256.f) + 32.f * vec3(lol::cos(-f_time + j * 2.f * F_PI / mi), lol::sin(-f_time + j * 2.f * F_PI / mi), .0f), vec2(.0f));
  192. }
  193. voronoi_points.push(vec3(256.f), vec2(0.f));
  194. }
  195. temp_buffer->Bind();
  196. {
  197. render_context rc(scene.get_renderer());
  198. rc.clear_color(vec4(0.f, 0.f, 0.f, 1.f));
  199. rc.clear_depth(1.f);
  200. scene.get_renderer()->Clear(ClearMask::Color | ClearMask::Depth);
  201. }
  202. temp_buffer->Unbind();
  203. {
  204. vec2 limit(1.f, 511.f);
  205. //SRC SETUP
  206. for (int j = 0; j < voronoi_points.count(); ++j)
  207. {
  208. voronoi_points[j].m1 = vec3(voronoi_points[j].m1.xy + voronoi_points[j].m2 * seconds, voronoi_points[j].m1.z);
  209. if (voronoi_points[j].m1.x >= limit.y || voronoi_points[j].m1.x <= limit.x)
  210. {
  211. voronoi_points[j].m2.x *= -1.f;
  212. voronoi_points[j].m1.x = clamp(voronoi_points[j].m1.x, limit.x, limit.y);
  213. }
  214. if (voronoi_points[j].m1.y >= limit.y || voronoi_points[j].m1.y <= limit.x)
  215. {
  216. voronoi_points[j].m2.y *= -1.f;
  217. voronoi_points[j].m1.y = clamp(voronoi_points[j].m1.y, limit.x, limit.y);
  218. }
  219. voronoi_points[j].m1.z = ((float)j + 1) / ((float)voronoi_points.count());
  220. }
  221. int f = SrcVoronoiFbo;
  222. m_fbos[f].m1->Bind();
  223. {
  224. render_context rc(scene.get_renderer());
  225. rc.clear_color(vec4(0.f, 0.f, 0.f, 1.f));
  226. rc.clear_depth(1.f);
  227. scene.get_renderer()->Clear(ClearMask::Color | ClearMask::Depth);
  228. }
  229. m_fbos[f].m1->Unbind();
  230. int buf = voronoi_points.count() % 2;
  231. for (int j = 0; j < voronoi_points.count(); ++j)
  232. {
  233. std::shared_ptr<Framebuffer> dst_buf, src_buf;
  234. if (buf)
  235. {
  236. dst_buf = m_fbos[f].m1;
  237. src_buf = temp_buffer;
  238. }
  239. else
  240. {
  241. src_buf = m_fbos[f].m1;
  242. dst_buf = temp_buffer;
  243. }
  244. dst_buf->Bind();
  245. /* FIXME: we should just disable depth test in the shader */
  246. scene.get_renderer()->Clear(ClearMask::Depth);
  247. m_fbos[f].m2->Bind();
  248. int i = 0;
  249. m_fbos[f].m2->SetUniform(m_fbos[f].m3[i++], src_buf->GetTextureUniform(), 0); //"u_texture"
  250. m_fbos[f].m2->SetUniform(m_fbos[f].m3[i++], voronoi_points[j].m1); //"u_source_point"
  251. m_fbos[f].m2->SetUniform(m_fbos[f].m3[i++], vec2(512.f, 512.f)); //"u_screen_res"
  252. m_vdecl->SetStream(m_vbo, m_fbos[f].m4.last());
  253. m_vdecl->Bind();
  254. m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, 6);
  255. m_vdecl->Unbind();
  256. m_fbos[f].m2->Unbind();
  257. dst_buf->Unbind();
  258. buf = 1 - buf;
  259. }
  260. }
  261. scene.get_renderer()->Clear(ClearMask::Color | ClearMask::Depth);
  262. //FRAME BUFFER DRAW
  263. m_timer -= seconds;
  264. if (m_timer < .0f && m_cur_fbo != SrcVoronoiFbo)
  265. {
  266. //m_timer = 1.0f;
  267. m_fbos[m_cur_fbo].m1->Bind();
  268. {
  269. render_context rc(scene.get_renderer());
  270. rc.clear_color(vec4(0.f, 0.f, 0.f, 1.f));
  271. rc.clear_depth(1.f);
  272. scene.get_renderer()->Clear(ClearMask::Color | ClearMask::Depth);
  273. }
  274. m_fbos[m_cur_fbo].m1->Unbind();
  275. ivec2 curres = ivec2(512, 512) / 2;
  276. int buf = 0;
  277. while (1)
  278. {
  279. std::shared_ptr<Framebuffer> dst_buf, src_buf;
  280. std::shared_ptr<Shader> shader;
  281. if (curres == ivec2::zero)
  282. shader = m_screen_shader;
  283. else
  284. shader = m_fbos[m_cur_fbo].m2;
  285. if (curres.x == 256)
  286. src_buf = m_fbos[SrcVoronoiFbo].m1;
  287. else if (buf)
  288. src_buf = m_fbos[m_cur_fbo].m1;
  289. else
  290. src_buf = temp_buffer;
  291. if (buf)
  292. dst_buf = temp_buffer;
  293. else
  294. dst_buf = m_fbos[m_cur_fbo].m1;
  295. dst_buf->Bind();
  296. /* FIXME: we should just disable depth test in the shader */
  297. scene.get_renderer()->Clear(ClearMask::Depth);
  298. shader->Bind();
  299. int i = 0;
  300. if (curres == ivec2::zero)
  301. m_screen_shader->SetUniform(m_screen_texture, src_buf->GetTextureUniform(), 0);
  302. else if (m_cur_fbo == VoronoiFbo)
  303. {
  304. shader->SetUniform(m_fbos[m_cur_fbo].m3[i++], src_buf->GetTextureUniform(), 0); //"u_texture"
  305. shader->SetUniform(m_fbos[m_cur_fbo].m3[i++], ((float)curres.x) / 512.f); //"u_step"
  306. shader->SetUniform(m_fbos[m_cur_fbo].m3[i++], vec2(512.f, 512.f)); //"u_screen_res"
  307. }
  308. m_vdecl->SetStream(m_vbo, m_fbos[m_cur_fbo].m4.last());
  309. m_vdecl->Bind();
  310. m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, 6);
  311. m_vdecl->Unbind();
  312. m_fbos[m_cur_fbo].m2->Unbind();
  313. dst_buf->Unbind();
  314. if (curres == ivec2::zero)
  315. break;
  316. if (curres == ivec2(1))
  317. {
  318. if (buf == 1)
  319. curres = ivec2::zero;
  320. else
  321. break;
  322. }
  323. buf = 1 - buf;
  324. curres /= 2;
  325. }
  326. }
  327. //SCREEN DRAW
  328. m_screen_shader->Bind();
  329. m_screen_shader->SetUniform(m_screen_texture, m_fbos[m_cur_fbo].m1->GetTextureUniform(), 0);
  330. m_vdecl->SetStream(m_vbo, m_screen_coord);
  331. m_vdecl->Bind();
  332. m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, 6);
  333. m_vdecl->Unbind();
  334. m_screen_shader->Unbind();
  335. }
  336. private:
  337. Controller* m_controller;
  338. array<vec3, vec2> voronoi_points;
  339. array<vec2> m_vertices;
  340. std::shared_ptr<Shader> m_screen_shader;
  341. ShaderAttrib m_screen_coord;
  342. ShaderUniform m_screen_texture;
  343. std::shared_ptr<VertexDeclaration> m_vdecl;
  344. std::shared_ptr<VertexBuffer> m_vbo;
  345. array<std::shared_ptr<Framebuffer>, std::shared_ptr<Shader>, array<ShaderUniform>, array<ShaderAttrib> > m_fbos;
  346. std::shared_ptr<Framebuffer> temp_buffer;
  347. int mode;
  348. int m_cur_fbo;
  349. double m_time;
  350. vec3 m_hotspot, m_color;
  351. bool m_ready;
  352. float m_timer;
  353. };
  354. int main(int argc, char **argv)
  355. {
  356. sys::init(argc, argv);
  357. Application app("Tutorial 12: Jump Flooding Algorithm & Voronoi", ivec2(512, 512), 60.0f);
  358. new Voronoi();
  359. app.Run();
  360. return EXIT_SUCCESS;
  361. }