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.

пре 11 година
пре 11 година
пре 11 година
пре 11 година
пре 11 година
пре 11 година
пре 11 година
пре 11 година
пре 11 година
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. //
  2. // Lol Engine — Voronoi diagram tutorial
  3. //
  4. // Copyright © 2011—2015 Benjamin “Touky” Huet <huet.benjamin@gmail.com>
  5. //
  6. // Lol Engine is free software. It comes without any warranty, to
  7. // the extent permitted by applicable law. You can redistribute it
  8. // and/or modify it under the terms of the Do What the Fuck You Want
  9. // to Public License, Version 2, as published by the WTFPL Task Force.
  10. // See http://www.wtfpl.net/ for more details.
  11. //
  12. #if HAVE_CONFIG_H
  13. # include "config.h"
  14. #endif
  15. #include <lol/engine.h>
  16. #include "loldebug.h"
  17. using namespace lol;
  18. LOLFX_RESOURCE_DECLARE(12_voronoi);
  19. LOLFX_RESOURCE_DECLARE(12_voronoi_setup);
  20. LOLFX_RESOURCE_DECLARE(12_voronoi_distance);
  21. LOLFX_RESOURCE_DECLARE(12_distance);
  22. LOLFX_RESOURCE_DECLARE(12_texture_to_screen);
  23. enum
  24. {
  25. KEY_ESC,
  26. KEY_PUSH,
  27. KEY_POP,
  28. KEY_F1,
  29. KEY_F2,
  30. KEY_F3,
  31. KEY_MAX
  32. };
  33. enum FboType
  34. {
  35. SrcVoronoiFbo,
  36. VoronoiFbo,
  37. DistanceVoronoiFbo,
  38. DistanceFbo,
  39. MaxFboType
  40. };
  41. class Voronoi : public WorldEntity
  42. {
  43. public:
  44. Voronoi()
  45. {
  46. m_vertices << vec2( 1.0, 1.0);
  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_ready = false;
  53. m_cur_fbo = 0;
  54. m_time = .0f;
  55. m_timer = -1.0f;
  56. mode = 0;
  57. m_controller = new Controller("Default");
  58. m_controller->SetInputCount(KEY_MAX, 0);
  59. m_controller->GetKey(KEY_ESC).Bind("Keyboard", "Escape");
  60. m_controller->GetKey(KEY_PUSH).Bind("Keyboard", "p");
  61. m_controller->GetKey(KEY_POP).Bind("Keyboard", "o");
  62. m_controller->GetKey(KEY_F1).Bind("Keyboard", "F1");
  63. m_controller->GetKey(KEY_F2).Bind("Keyboard", "F2");
  64. m_controller->GetKey(KEY_F3).Bind("Keyboard", "F3");
  65. }
  66. virtual void TickGame(float seconds)
  67. {
  68. WorldEntity::TickGame(seconds);
  69. {
  70. //Shutdown logic
  71. if (m_controller->WasKeyReleasedThisFrame(KEY_ESC))
  72. Ticker::Shutdown();
  73. }
  74. m_time += seconds;
  75. m_hotspot = 0.4f * vec3((float)lol::sin(m_time * 4.0) + (float)lol::cos(m_time * 5.3),
  76. (float)lol::sin(m_time * 5.7) + (float)lol::cos(m_time * 4.4),
  77. (float)lol::sin(m_time * 5.0));
  78. m_color = 0.25f * vec3(1.1f + (float)lol::sin(m_time * 2.5 + 1.0),
  79. 1.1f + (float)lol::sin(m_time * 2.8 + 1.3),
  80. 1.1f + (float)lol::sin(m_time * 2.7));
  81. /* Saturate dot color */
  82. float x = std::max(m_color.x, std::max(m_color.y, m_color.z));
  83. m_color /= x;
  84. }
  85. virtual void TickDraw(float seconds, Scene &scene)
  86. {
  87. WorldEntity::TickDraw(seconds, scene);
  88. if (!m_ready)
  89. {
  90. m_vdecl = new VertexDeclaration(VertexStream<vec2>(VertexUsage::Position));
  91. m_vbo = new VertexBuffer(m_vertices.bytes());
  92. void *vertices = m_vbo->Lock(0, 0);
  93. memcpy(vertices, &m_vertices[0], m_vertices.bytes());
  94. m_vbo->Unlock();
  95. m_screen_shader = Shader::Create(LOLFX_RESOURCE_NAME(12_texture_to_screen));
  96. m_screen_coord = m_screen_shader->GetAttribLocation(VertexUsage::Position, 0);
  97. m_screen_texture = m_screen_shader->GetUniformLocation("in_texture");
  98. for (int i = 0; i < MaxFboType; ++i)
  99. {
  100. m_fbos.push(new Framebuffer(Video::GetSize()), 0, array<ShaderUniform>(), array<ShaderAttrib>() );
  101. if (i == SrcVoronoiFbo)
  102. {
  103. m_fbos[i].m2 = Shader::Create(LOLFX_RESOURCE_NAME(12_voronoi_setup));
  104. m_fbos[i].m3 << m_fbos[i].m2->GetUniformLocation("in_texture");
  105. m_fbos[i].m3 << m_fbos[i].m2->GetUniformLocation("in_source_point");
  106. m_fbos[i].m3 << m_fbos[i].m2->GetUniformLocation("in_screen_res");
  107. m_fbos[i].m4 << m_fbos[i].m2->GetAttribLocation(VertexUsage::Position, 0);
  108. }
  109. else if (i == VoronoiFbo)
  110. {
  111. m_fbos[i].m2 = Shader::Create(LOLFX_RESOURCE_NAME(12_voronoi));
  112. m_fbos[i].m3 << m_fbos[i].m2->GetUniformLocation("in_texture");
  113. m_fbos[i].m3 << m_fbos[i].m2->GetUniformLocation("in_step");
  114. m_fbos[i].m3 << m_fbos[i].m2->GetUniformLocation("in_screen_res");
  115. m_fbos[i].m4 << m_fbos[i].m2->GetAttribLocation(VertexUsage::Position, 0);
  116. }
  117. else if (i == DistanceVoronoiFbo)
  118. {
  119. m_fbos[i].m2 = Shader::Create(LOLFX_RESOURCE_NAME(12_voronoi_distance));
  120. }
  121. else if (i == DistanceFbo)
  122. {
  123. m_fbos[i].m2 = Shader::Create(LOLFX_RESOURCE_NAME(12_distance));
  124. }
  125. m_fbos.last().m1->Bind();
  126. {
  127. RenderContext rc;
  128. rc.SetClearColor(vec4(0.f, 0.f, 0.f, 1.f));
  129. rc.SetClearDepth(1.f);
  130. Renderer::Get()->Clear(ClearMask::Color | ClearMask::Depth);
  131. }
  132. m_fbos.last().m1->Unbind();
  133. }
  134. temp_buffer = new Framebuffer(Video::GetSize());
  135. temp_buffer->Bind();
  136. {
  137. RenderContext rc;
  138. rc.SetClearColor(vec4(0.f, 0.f, 0.f, 1.f));
  139. rc.SetClearDepth(1.f);
  140. Renderer::Get()->Clear(ClearMask::Color | ClearMask::Depth);
  141. }
  142. temp_buffer->Unbind();
  143. m_ready = true;
  144. /* FIXME: this object never cleans up */
  145. //SRC SETUP
  146. m_cur_fbo = VoronoiFbo;
  147. }
  148. {
  149. //Shutdown logic
  150. if (m_controller->WasKeyReleasedThisFrame(KEY_POP))
  151. voronoi_points.pop();
  152. else if (m_controller->WasKeyReleasedThisFrame(KEY_PUSH))
  153. voronoi_points.push(vec3(rand<float>(512.f), rand<float>(512.f), .0f),
  154. vec2(64.f + rand<float>(64.f), 64.f + rand<float>(64.f)));
  155. else if (m_controller->WasKeyReleasedThisFrame(KEY_F1))
  156. m_cur_fbo = SrcVoronoiFbo;
  157. else if (m_controller->WasKeyReleasedThisFrame(KEY_F2))
  158. m_cur_fbo = VoronoiFbo;
  159. else if (m_controller->WasKeyReleasedThisFrame(KEY_F3))
  160. {
  161. voronoi_points.empty();
  162. if (mode == 0)
  163. {
  164. int i = 4;
  165. while (i-- > 0)
  166. voronoi_points.push(vec3(rand<float>(512.f), rand<float>(512.f), .0f),
  167. vec2(64.f + rand<float>(64.f), 64.f + rand<float>(64.f))
  168. //vec2::zero
  169. );
  170. mode = 1;
  171. }
  172. else
  173. {
  174. mode = 0;
  175. }
  176. }
  177. }
  178. if (mode == 0)
  179. {
  180. voronoi_points.empty();
  181. int maxi = 6;
  182. for (int i = 0; i < maxi; ++i)
  183. {
  184. float mi = (float)maxi;
  185. float j = (float)i;
  186. float f_time = (float)m_time;
  187. 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));
  188. 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));
  189. 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));
  190. 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));
  191. }
  192. voronoi_points.push(vec3(256.f), vec2(0.f));
  193. }
  194. temp_buffer->Bind();
  195. {
  196. RenderContext rc;
  197. rc.SetClearColor(vec4(0.f, 0.f, 0.f, 1.f));
  198. rc.SetClearDepth(1.f);
  199. Renderer::Get()->Clear(ClearMask::Color | ClearMask::Depth);
  200. }
  201. temp_buffer->Unbind();
  202. {
  203. vec2 limit(1.f, 511.f);
  204. //SRC SETUP
  205. for (int j = 0; j < voronoi_points.count(); ++j)
  206. {
  207. voronoi_points[j].m1 = vec3(voronoi_points[j].m1.xy + voronoi_points[j].m2 * seconds, voronoi_points[j].m1.z);
  208. if (voronoi_points[j].m1.x >= limit.y || voronoi_points[j].m1.x <= limit.x)
  209. {
  210. voronoi_points[j].m2.x *= -1.f;
  211. voronoi_points[j].m1.x = clamp(voronoi_points[j].m1.x, limit.x, limit.y);
  212. }
  213. if (voronoi_points[j].m1.y >= limit.y || voronoi_points[j].m1.y <= limit.x)
  214. {
  215. voronoi_points[j].m2.y *= -1.f;
  216. voronoi_points[j].m1.y = clamp(voronoi_points[j].m1.y, limit.x, limit.y);
  217. }
  218. voronoi_points[j].m1.z = ((float)j + 1) / ((float)voronoi_points.count());
  219. }
  220. int f = SrcVoronoiFbo;
  221. m_fbos[f].m1->Bind();
  222. {
  223. RenderContext rc;
  224. rc.SetClearColor(vec4(0.f, 0.f, 0.f, 1.f));
  225. rc.SetClearDepth(1.f);
  226. Renderer::Get()->Clear(ClearMask::Color | ClearMask::Depth);
  227. }
  228. m_fbos[f].m1->Unbind();
  229. int buf = voronoi_points.count() % 2;
  230. for (int j = 0; j < voronoi_points.count(); ++j)
  231. {
  232. Framebuffer *dst_buf;
  233. Framebuffer *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. Renderer::Get()->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); //"in_texture"
  250. m_fbos[f].m2->SetUniform(m_fbos[f].m3[i++], voronoi_points[j].m1); //"in_source_point"
  251. m_fbos[f].m2->SetUniform(m_fbos[f].m3[i++], vec2(512.f, 512.f)); //"in_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. Renderer::Get()->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. RenderContext rc;
  270. rc.SetClearColor(vec4(0.f, 0.f, 0.f, 1.f));
  271. rc.SetClearDepth(1.f);
  272. Renderer::Get()->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. Framebuffer *dst_buf;
  280. Framebuffer *src_buf;
  281. 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. Renderer::Get()->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); //"in_texture"
  306. shader->SetUniform(m_fbos[m_cur_fbo].m3[i++], ((float)curres.x) / 512.f); //"in_step"
  307. shader->SetUniform(m_fbos[m_cur_fbo].m3[i++], vec2(512.f, 512.f)); //"in_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. Shader *m_screen_shader;
  342. ShaderAttrib m_screen_coord;
  343. ShaderUniform m_screen_texture;
  344. VertexDeclaration *m_vdecl;
  345. VertexBuffer *m_vbo;
  346. array<Framebuffer *, Shader *, array<ShaderUniform>, array<ShaderAttrib> > m_fbos;
  347. 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. System::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. }