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 година
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 <lol/engine.h>
  17. #include "loldebug.h"
  18. using namespace lol;
  19. LOLFX_RESOURCE_DECLARE(12_voronoi);
  20. LOLFX_RESOURCE_DECLARE(12_voronoi_setup);
  21. LOLFX_RESOURCE_DECLARE(12_voronoi_distance);
  22. LOLFX_RESOURCE_DECLARE(12_distance);
  23. LOLFX_RESOURCE_DECLARE(12_texture_to_screen);
  24. enum
  25. {
  26. KEY_ESC,
  27. KEY_PUSH,
  28. KEY_POP,
  29. KEY_F1,
  30. KEY_F2,
  31. KEY_F3,
  32. KEY_MAX
  33. };
  34. enum FboType
  35. {
  36. SrcVoronoiFbo,
  37. VoronoiFbo,
  38. DistanceVoronoiFbo,
  39. DistanceFbo,
  40. MaxFboType
  41. };
  42. class Voronoi : public WorldEntity
  43. {
  44. public:
  45. Voronoi()
  46. {
  47. m_vertices << vec2( 1.0, 1.0);
  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_ready = false;
  54. m_cur_fbo = 0;
  55. m_time = .0f;
  56. m_timer = -1.0f;
  57. mode = 0;
  58. m_controller = new Controller("Default");
  59. m_controller->SetInputCount(KEY_MAX, 0);
  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 = new VertexDeclaration(VertexStream<vec2>(VertexUsage::Position));
  92. m_vbo = new 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(new 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. RenderContext rc(scene.get_renderer());
  129. rc.SetClearColor(vec4(0.f, 0.f, 0.f, 1.f));
  130. rc.SetClearDepth(1.f);
  131. scene.get_renderer()->Clear(ClearMask::Color | ClearMask::Depth);
  132. }
  133. m_fbos.last().m1->Unbind();
  134. }
  135. temp_buffer = new Framebuffer(Video::GetSize());
  136. temp_buffer->Bind();
  137. {
  138. RenderContext rc(scene.get_renderer());
  139. rc.SetClearColor(vec4(0.f, 0.f, 0.f, 1.f));
  140. rc.SetClearDepth(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. RenderContext rc(scene.get_renderer());
  198. rc.SetClearColor(vec4(0.f, 0.f, 0.f, 1.f));
  199. rc.SetClearDepth(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. RenderContext rc(scene.get_renderer());
  225. rc.SetClearColor(vec4(0.f, 0.f, 0.f, 1.f));
  226. rc.SetClearDepth(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. Framebuffer *dst_buf;
  234. Framebuffer *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. RenderContext rc(scene.get_renderer());
  271. rc.SetClearColor(vec4(0.f, 0.f, 0.f, 1.f));
  272. rc.SetClearDepth(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. Framebuffer *dst_buf;
  281. Framebuffer *src_buf;
  282. Shader *shader;
  283. if (curres == ivec2::zero)
  284. shader = m_screen_shader;
  285. else
  286. shader = m_fbos[m_cur_fbo].m2;
  287. if (curres.x == 256)
  288. src_buf = m_fbos[SrcVoronoiFbo].m1;
  289. else if (buf)
  290. src_buf = m_fbos[m_cur_fbo].m1;
  291. else
  292. src_buf = temp_buffer;
  293. if (buf)
  294. dst_buf = temp_buffer;
  295. else
  296. dst_buf = m_fbos[m_cur_fbo].m1;
  297. dst_buf->Bind();
  298. /* FIXME: we should just disable depth test in the shader */
  299. scene.get_renderer()->Clear(ClearMask::Depth);
  300. shader->Bind();
  301. int i = 0;
  302. if (curres == ivec2::zero)
  303. m_screen_shader->SetUniform(m_screen_texture, src_buf->GetTextureUniform(), 0);
  304. else if (m_cur_fbo == VoronoiFbo)
  305. {
  306. shader->SetUniform(m_fbos[m_cur_fbo].m3[i++], src_buf->GetTextureUniform(), 0); //"u_texture"
  307. shader->SetUniform(m_fbos[m_cur_fbo].m3[i++], ((float)curres.x) / 512.f); //"u_step"
  308. shader->SetUniform(m_fbos[m_cur_fbo].m3[i++], vec2(512.f, 512.f)); //"u_screen_res"
  309. }
  310. m_vdecl->SetStream(m_vbo, m_fbos[m_cur_fbo].m4.last());
  311. m_vdecl->Bind();
  312. m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, 6);
  313. m_vdecl->Unbind();
  314. m_fbos[m_cur_fbo].m2->Unbind();
  315. dst_buf->Unbind();
  316. if (curres == ivec2::zero)
  317. break;
  318. if (curres == ivec2(1))
  319. {
  320. if (buf == 1)
  321. curres = ivec2::zero;
  322. else
  323. break;
  324. }
  325. buf = 1 - buf;
  326. curres /= 2;
  327. }
  328. }
  329. //SCREEN DRAW
  330. m_screen_shader->Bind();
  331. m_screen_shader->SetUniform(m_screen_texture, m_fbos[m_cur_fbo].m1->GetTextureUniform(), 0);
  332. m_vdecl->SetStream(m_vbo, m_screen_coord);
  333. m_vdecl->Bind();
  334. m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, 6);
  335. m_vdecl->Unbind();
  336. m_screen_shader->Unbind();
  337. }
  338. private:
  339. Controller* m_controller;
  340. array<vec3, vec2> voronoi_points;
  341. array<vec2> m_vertices;
  342. Shader *m_screen_shader;
  343. ShaderAttrib m_screen_coord;
  344. ShaderUniform m_screen_texture;
  345. VertexDeclaration *m_vdecl;
  346. VertexBuffer *m_vbo;
  347. array<Framebuffer *, Shader *, array<ShaderUniform>, array<ShaderAttrib> > m_fbos;
  348. Framebuffer *temp_buffer;
  349. int mode;
  350. int m_cur_fbo;
  351. double m_time;
  352. vec3 m_hotspot, m_color;
  353. bool m_ready;
  354. float m_timer;
  355. };
  356. int main(int argc, char **argv)
  357. {
  358. sys::init(argc, argv);
  359. Application app("Tutorial 12: Jump Flooding Algorithm & Voronoi", ivec2(512, 512), 60.0f);
  360. new Voronoi();
  361. app.Run();
  362. return EXIT_SUCCESS;
  363. }