Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 

417 Zeilen
15 KiB

  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(g_name_keyboard, "Escape");
  61. m_controller->GetKey(KEY_PUSH).Bind(g_name_keyboard, "p");
  62. m_controller->GetKey(KEY_POP).Bind(g_name_keyboard, "o");
  63. m_controller->GetKey(KEY_F1).Bind(g_name_keyboard, "F1");
  64. m_controller->GetKey(KEY_F2).Bind(g_name_keyboard, "F2");
  65. m_controller->GetKey(KEY_F3).Bind(g_name_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. }