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