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 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 11 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 11 години
преди 12 години
преди 12 години
преди 12 години
преди 10 години
преди 12 години
преди 11 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 8 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 8 години
преди 12 години
преди 12 години
преди 8 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 10 години
преди 10 години
преди 12 години
преди 10 години
преди 10 години
преди 10 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 11 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 8 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 8 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 11 години
преди 10 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 8 години
преди 12 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  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->SetInputCount(KEY_MAX, 0);
  61. m_controller->GetKey(KEY_ESC).Bind("Keyboard", "Escape");
  62. m_controller->GetKey(KEY_PUSH).Bind("Keyboard", "p");
  63. m_controller->GetKey(KEY_POP).Bind("Keyboard", "o");
  64. m_controller->GetKey(KEY_F1).Bind("Keyboard", "F1");
  65. m_controller->GetKey(KEY_F2).Bind("Keyboard", "F2");
  66. m_controller->GetKey(KEY_F3).Bind("Keyboard", "F3");
  67. }
  68. virtual void tick_game(float seconds)
  69. {
  70. WorldEntity::tick_game(seconds);
  71. {
  72. //Shutdown logic
  73. if (m_controller->WasKeyReleasedThisFrame(KEY_ESC))
  74. Ticker::Shutdown();
  75. }
  76. m_time += seconds;
  77. m_hotspot = 0.4f * vec3((float)lol::sin(m_time * 4.0) + (float)lol::cos(m_time * 5.3),
  78. (float)lol::sin(m_time * 5.7) + (float)lol::cos(m_time * 4.4),
  79. (float)lol::sin(m_time * 5.0));
  80. m_color = 0.25f * vec3(1.1f + (float)lol::sin(m_time * 2.5 + 1.0),
  81. 1.1f + (float)lol::sin(m_time * 2.8 + 1.3),
  82. 1.1f + (float)lol::sin(m_time * 2.7));
  83. /* Saturate dot color */
  84. float x = std::max(m_color.x, std::max(m_color.y, m_color.z));
  85. m_color /= x;
  86. }
  87. virtual void tick_draw(float seconds, Scene &scene)
  88. {
  89. WorldEntity::tick_draw(seconds, scene);
  90. if (!m_ready)
  91. {
  92. m_vdecl = std::make_shared<VertexDeclaration>(VertexStream<vec2>(VertexUsage::Position));
  93. m_vbo = std::make_shared<VertexBuffer>(m_vertices.bytes());
  94. void *vertices = m_vbo->Lock(0, 0);
  95. memcpy(vertices, &m_vertices[0], m_vertices.bytes());
  96. m_vbo->Unlock();
  97. m_screen_shader = Shader::Create(LOLFX_RESOURCE_NAME(12_texture_to_screen));
  98. m_screen_coord = m_screen_shader->GetAttribLocation(VertexUsage::Position, 0);
  99. m_screen_texture = m_screen_shader->GetUniformLocation("u_texture");
  100. for (int i = 0; i < MaxFboType; ++i)
  101. {
  102. m_fbos.push(std::make_shared<Framebuffer>(Video::GetSize()), 0, array<ShaderUniform>(), array<ShaderAttrib>() );
  103. if (i == SrcVoronoiFbo)
  104. {
  105. m_fbos[i].m2 = Shader::Create(LOLFX_RESOURCE_NAME(12_voronoi_setup));
  106. m_fbos[i].m3 << m_fbos[i].m2->GetUniformLocation("u_texture");
  107. m_fbos[i].m3 << m_fbos[i].m2->GetUniformLocation("u_source_point");
  108. m_fbos[i].m3 << m_fbos[i].m2->GetUniformLocation("u_screen_res");
  109. m_fbos[i].m4 << m_fbos[i].m2->GetAttribLocation(VertexUsage::Position, 0);
  110. }
  111. else if (i == VoronoiFbo)
  112. {
  113. m_fbos[i].m2 = Shader::Create(LOLFX_RESOURCE_NAME(12_voronoi));
  114. m_fbos[i].m3 << m_fbos[i].m2->GetUniformLocation("u_texture");
  115. m_fbos[i].m3 << m_fbos[i].m2->GetUniformLocation("u_step");
  116. m_fbos[i].m3 << m_fbos[i].m2->GetUniformLocation("u_screen_res");
  117. m_fbos[i].m4 << m_fbos[i].m2->GetAttribLocation(VertexUsage::Position, 0);
  118. }
  119. else if (i == DistanceVoronoiFbo)
  120. {
  121. m_fbos[i].m2 = Shader::Create(LOLFX_RESOURCE_NAME(12_voronoi_distance));
  122. }
  123. else if (i == DistanceFbo)
  124. {
  125. m_fbos[i].m2 = Shader::Create(LOLFX_RESOURCE_NAME(12_distance));
  126. }
  127. m_fbos.last().m1->Bind();
  128. {
  129. render_context rc(scene.get_renderer());
  130. rc.clear_color(vec4(0.f, 0.f, 0.f, 1.f));
  131. rc.clear_depth(1.f);
  132. scene.get_renderer()->Clear(ClearMask::Color | ClearMask::Depth);
  133. }
  134. m_fbos.last().m1->Unbind();
  135. }
  136. temp_buffer = std::make_shared<Framebuffer>(Video::GetSize());
  137. temp_buffer->Bind();
  138. {
  139. render_context rc(scene.get_renderer());
  140. rc.clear_color(vec4(0.f, 0.f, 0.f, 1.f));
  141. rc.clear_depth(1.f);
  142. scene.get_renderer()->Clear(ClearMask::Color | ClearMask::Depth);
  143. }
  144. temp_buffer->Unbind();
  145. m_ready = true;
  146. /* FIXME: this object never cleans up */
  147. //SRC SETUP
  148. m_cur_fbo = VoronoiFbo;
  149. }
  150. {
  151. //Shutdown logic
  152. if (m_controller->WasKeyReleasedThisFrame(KEY_POP))
  153. voronoi_points.pop();
  154. else if (m_controller->WasKeyReleasedThisFrame(KEY_PUSH))
  155. voronoi_points.push(vec3(rand<float>(512.f), rand<float>(512.f), .0f),
  156. vec2(64.f + rand<float>(64.f), 64.f + rand<float>(64.f)));
  157. else if (m_controller->WasKeyReleasedThisFrame(KEY_F1))
  158. m_cur_fbo = SrcVoronoiFbo;
  159. else if (m_controller->WasKeyReleasedThisFrame(KEY_F2))
  160. m_cur_fbo = VoronoiFbo;
  161. else if (m_controller->WasKeyReleasedThisFrame(KEY_F3))
  162. {
  163. voronoi_points.clear();
  164. if (mode == 0)
  165. {
  166. int i = 4;
  167. while (i-- > 0)
  168. voronoi_points.push(vec3(rand<float>(512.f), rand<float>(512.f), .0f),
  169. vec2(64.f + rand<float>(64.f), 64.f + rand<float>(64.f))
  170. //vec2::zero
  171. );
  172. mode = 1;
  173. }
  174. else
  175. {
  176. mode = 0;
  177. }
  178. }
  179. }
  180. if (mode == 0)
  181. {
  182. voronoi_points.clear();
  183. int maxi = 6;
  184. for (int i = 0; i < maxi; ++i)
  185. {
  186. float mi = (float)maxi;
  187. float j = (float)i;
  188. float f_time = (float)m_time;
  189. 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));
  190. 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));
  191. 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));
  192. 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));
  193. }
  194. voronoi_points.push(vec3(256.f), vec2(0.f));
  195. }
  196. temp_buffer->Bind();
  197. {
  198. render_context rc(scene.get_renderer());
  199. rc.clear_color(vec4(0.f, 0.f, 0.f, 1.f));
  200. rc.clear_depth(1.f);
  201. scene.get_renderer()->Clear(ClearMask::Color | ClearMask::Depth);
  202. }
  203. temp_buffer->Unbind();
  204. {
  205. vec2 limit(1.f, 511.f);
  206. //SRC SETUP
  207. for (int j = 0; j < voronoi_points.count(); ++j)
  208. {
  209. voronoi_points[j].m1 = vec3(voronoi_points[j].m1.xy + voronoi_points[j].m2 * seconds, voronoi_points[j].m1.z);
  210. if (voronoi_points[j].m1.x >= limit.y || voronoi_points[j].m1.x <= limit.x)
  211. {
  212. voronoi_points[j].m2.x *= -1.f;
  213. voronoi_points[j].m1.x = clamp(voronoi_points[j].m1.x, limit.x, limit.y);
  214. }
  215. if (voronoi_points[j].m1.y >= limit.y || voronoi_points[j].m1.y <= limit.x)
  216. {
  217. voronoi_points[j].m2.y *= -1.f;
  218. voronoi_points[j].m1.y = clamp(voronoi_points[j].m1.y, limit.x, limit.y);
  219. }
  220. voronoi_points[j].m1.z = ((float)j + 1) / ((float)voronoi_points.count());
  221. }
  222. int f = SrcVoronoiFbo;
  223. m_fbos[f].m1->Bind();
  224. {
  225. render_context rc(scene.get_renderer());
  226. rc.clear_color(vec4(0.f, 0.f, 0.f, 1.f));
  227. rc.clear_depth(1.f);
  228. scene.get_renderer()->Clear(ClearMask::Color | ClearMask::Depth);
  229. }
  230. m_fbos[f].m1->Unbind();
  231. int buf = voronoi_points.count() % 2;
  232. for (int j = 0; j < voronoi_points.count(); ++j)
  233. {
  234. std::shared_ptr<Framebuffer> dst_buf, src_buf;
  235. if (buf)
  236. {
  237. dst_buf = m_fbos[f].m1;
  238. src_buf = temp_buffer;
  239. }
  240. else
  241. {
  242. src_buf = m_fbos[f].m1;
  243. dst_buf = temp_buffer;
  244. }
  245. dst_buf->Bind();
  246. /* FIXME: we should just disable depth test in the shader */
  247. scene.get_renderer()->Clear(ClearMask::Depth);
  248. m_fbos[f].m2->Bind();
  249. int i = 0;
  250. m_fbos[f].m2->SetUniform(m_fbos[f].m3[i++], src_buf->GetTextureUniform(), 0); //"u_texture"
  251. m_fbos[f].m2->SetUniform(m_fbos[f].m3[i++], voronoi_points[j].m1); //"u_source_point"
  252. m_fbos[f].m2->SetUniform(m_fbos[f].m3[i++], vec2(512.f, 512.f)); //"u_screen_res"
  253. m_vdecl->SetStream(m_vbo, m_fbos[f].m4.last());
  254. m_vdecl->Bind();
  255. m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, 6);
  256. m_vdecl->Unbind();
  257. m_fbos[f].m2->Unbind();
  258. dst_buf->Unbind();
  259. buf = 1 - buf;
  260. }
  261. }
  262. scene.get_renderer()->Clear(ClearMask::Color | ClearMask::Depth);
  263. //FRAME BUFFER DRAW
  264. m_timer -= seconds;
  265. if (m_timer < .0f && m_cur_fbo != SrcVoronoiFbo)
  266. {
  267. //m_timer = 1.0f;
  268. m_fbos[m_cur_fbo].m1->Bind();
  269. {
  270. render_context rc(scene.get_renderer());
  271. rc.clear_color(vec4(0.f, 0.f, 0.f, 1.f));
  272. rc.clear_depth(1.f);
  273. scene.get_renderer()->Clear(ClearMask::Color | ClearMask::Depth);
  274. }
  275. m_fbos[m_cur_fbo].m1->Unbind();
  276. ivec2 curres = ivec2(512, 512) / 2;
  277. int buf = 0;
  278. while (1)
  279. {
  280. std::shared_ptr<Framebuffer> dst_buf, src_buf;
  281. std::shared_ptr<Shader> shader;
  282. if (curres == ivec2::zero)
  283. shader = m_screen_shader;
  284. else
  285. shader = m_fbos[m_cur_fbo].m2;
  286. if (curres.x == 256)
  287. src_buf = m_fbos[SrcVoronoiFbo].m1;
  288. else if (buf)
  289. src_buf = m_fbos[m_cur_fbo].m1;
  290. else
  291. src_buf = temp_buffer;
  292. if (buf)
  293. dst_buf = temp_buffer;
  294. else
  295. dst_buf = m_fbos[m_cur_fbo].m1;
  296. dst_buf->Bind();
  297. /* FIXME: we should just disable depth test in the shader */
  298. scene.get_renderer()->Clear(ClearMask::Depth);
  299. shader->Bind();
  300. int i = 0;
  301. if (curres == ivec2::zero)
  302. m_screen_shader->SetUniform(m_screen_texture, src_buf->GetTextureUniform(), 0);
  303. else if (m_cur_fbo == VoronoiFbo)
  304. {
  305. shader->SetUniform(m_fbos[m_cur_fbo].m3[i++], src_buf->GetTextureUniform(), 0); //"u_texture"
  306. shader->SetUniform(m_fbos[m_cur_fbo].m3[i++], ((float)curres.x) / 512.f); //"u_step"
  307. shader->SetUniform(m_fbos[m_cur_fbo].m3[i++], vec2(512.f, 512.f)); //"u_screen_res"
  308. }
  309. m_vdecl->SetStream(m_vbo, m_fbos[m_cur_fbo].m4.last());
  310. m_vdecl->Bind();
  311. m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, 6);
  312. m_vdecl->Unbind();
  313. m_fbos[m_cur_fbo].m2->Unbind();
  314. dst_buf->Unbind();
  315. if (curres == ivec2::zero)
  316. break;
  317. if (curres == ivec2(1))
  318. {
  319. if (buf == 1)
  320. curres = ivec2::zero;
  321. else
  322. break;
  323. }
  324. buf = 1 - buf;
  325. curres /= 2;
  326. }
  327. }
  328. //SCREEN DRAW
  329. m_screen_shader->Bind();
  330. m_screen_shader->SetUniform(m_screen_texture, m_fbos[m_cur_fbo].m1->GetTextureUniform(), 0);
  331. m_vdecl->SetStream(m_vbo, m_screen_coord);
  332. m_vdecl->Bind();
  333. m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, 6);
  334. m_vdecl->Unbind();
  335. m_screen_shader->Unbind();
  336. }
  337. private:
  338. Controller* m_controller;
  339. array<vec3, vec2> voronoi_points;
  340. array<vec2> m_vertices;
  341. std::shared_ptr<Shader> m_screen_shader;
  342. ShaderAttrib m_screen_coord;
  343. ShaderUniform m_screen_texture;
  344. std::shared_ptr<VertexDeclaration> m_vdecl;
  345. std::shared_ptr<VertexBuffer> m_vbo;
  346. array<std::shared_ptr<Framebuffer>, std::shared_ptr<Shader>, array<ShaderUniform>, array<ShaderAttrib> > m_fbos;
  347. std::shared_ptr<Framebuffer> temp_buffer;
  348. int mode;
  349. int m_cur_fbo;
  350. double m_time;
  351. vec3 m_hotspot, m_color;
  352. bool m_ready;
  353. float m_timer;
  354. };
  355. int main(int argc, char **argv)
  356. {
  357. sys::init(argc, argv);
  358. Application app("Tutorial 12: Jump Flooding Algorithm & Voronoi", ivec2(512, 512), 60.0f);
  359. new Voronoi();
  360. app.Run();
  361. return EXIT_SUCCESS;
  362. }