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 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 9 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 10 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 9 години
преди 11 години
преди 9 години
преди 11 години
преди 9 години
преди 9 години
преди 9 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 10 години
преди 11 години
преди 10 години
преди 11 години
преди 11 години
преди 11 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. //
  2. // Lol Engine - Framebuffer Object tutorial
  3. //
  4. // Copyright: (c) 2013-2013 Sam Hocevar <sam@hocevar.net>
  5. // (c) 2013-2013 Benjamin "Touky" Huet <huet.benjamin@gmail.com>
  6. // This program is free software; you can redistribute it and/or
  7. // modify it under the terms of the Do What The Fuck You Want To
  8. // Public License, Version 2, as published by Sam Hocevar. See
  9. // http://www.wtfpl.net/ for more details.
  10. //
  11. #if HAVE_CONFIG_H
  12. # include "config.h"
  13. #endif
  14. #include <lol/engine.h>
  15. #include "loldebug.h"
  16. using namespace lol;
  17. LOLFX_RESOURCE_DECLARE(12_voronoi);
  18. LOLFX_RESOURCE_DECLARE(12_voronoi_setup);
  19. LOLFX_RESOURCE_DECLARE(12_voronoi_distance);
  20. LOLFX_RESOURCE_DECLARE(12_distance);
  21. LOLFX_RESOURCE_DECLARE(12_texture_to_screen);
  22. enum
  23. {
  24. KEY_ESC,
  25. KEY_PUSH,
  26. KEY_POP,
  27. KEY_F1,
  28. KEY_F2,
  29. KEY_F3,
  30. KEY_MAX
  31. };
  32. enum FboType
  33. {
  34. SrcVoronoiFbo,
  35. VoronoiFbo,
  36. DistanceVoronoiFbo,
  37. DistanceFbo,
  38. MaxFboType
  39. };
  40. class Voronoi : public WorldEntity
  41. {
  42. public:
  43. Voronoi()
  44. {
  45. m_vertices << vec2( 1.0, 1.0);
  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_ready = false;
  52. m_cur_fbo = 0;
  53. m_time = .0f;
  54. m_timer = -1.0f;
  55. mode = 0;
  56. m_controller = new Controller("Default");
  57. m_controller->SetInputCount(KEY_MAX, 0);
  58. m_controller->GetKey(KEY_ESC).Bind("Keyboard", "Escape");
  59. m_controller->GetKey(KEY_PUSH).Bind("Keyboard", "p");
  60. m_controller->GetKey(KEY_POP).Bind("Keyboard", "o");
  61. m_controller->GetKey(KEY_F1).Bind("Keyboard", "F1");
  62. m_controller->GetKey(KEY_F2).Bind("Keyboard", "F2");
  63. m_controller->GetKey(KEY_F3).Bind("Keyboard", "F3");
  64. }
  65. virtual void TickGame(float seconds)
  66. {
  67. WorldEntity::TickGame(seconds);
  68. {
  69. //Shutdown logic
  70. if (m_controller->WasKeyReleasedThisFrame(KEY_ESC))
  71. Ticker::Shutdown();
  72. }
  73. m_time += seconds;
  74. m_hotspot = 0.4f * vec3((float)lol::sin(m_time * 4.0) + (float)lol::cos(m_time * 5.3),
  75. (float)lol::sin(m_time * 5.7) + (float)lol::cos(m_time * 4.4),
  76. (float)lol::sin(m_time * 5.0));
  77. m_color = 0.25f * vec3(1.1f + (float)lol::sin(m_time * 2.5 + 1.0),
  78. 1.1f + (float)lol::sin(m_time * 2.8 + 1.3),
  79. 1.1f + (float)lol::sin(m_time * 2.7));
  80. /* Saturate dot color */
  81. float x = std::max(m_color.x, std::max(m_color.y, m_color.z));
  82. m_color /= x;
  83. }
  84. virtual void TickDraw(float seconds, Scene &scene)
  85. {
  86. WorldEntity::TickDraw(seconds, scene);
  87. if (!m_ready)
  88. {
  89. m_vdecl = new VertexDeclaration(VertexStream<vec2>(VertexUsage::Position));
  90. m_vbo = new VertexBuffer(m_vertices.Bytes());
  91. void *vertices = m_vbo->Lock(0, 0);
  92. memcpy(vertices, &m_vertices[0], m_vertices.Bytes());
  93. m_vbo->Unlock();
  94. m_screen_shader = Shader::Create(LOLFX_RESOURCE_NAME(12_texture_to_screen));
  95. m_screen_coord = m_screen_shader->GetAttribLocation(VertexUsage::Position, 0);
  96. m_screen_texture = m_screen_shader->GetUniformLocation("in_texture");
  97. for (int i = 0; i < MaxFboType; ++i)
  98. {
  99. m_fbos.Push(new Framebuffer(Video::GetSize()), 0, array<ShaderUniform>(), array<ShaderAttrib>() );
  100. if (i == SrcVoronoiFbo)
  101. {
  102. m_fbos[i].m2 = Shader::Create(LOLFX_RESOURCE_NAME(12_voronoi_setup));
  103. m_fbos[i].m3 << m_fbos[i].m2->GetUniformLocation("in_texture");
  104. m_fbos[i].m3 << m_fbos[i].m2->GetUniformLocation("in_source_point");
  105. m_fbos[i].m3 << m_fbos[i].m2->GetUniformLocation("in_screen_res");
  106. m_fbos[i].m4 << m_fbos[i].m2->GetAttribLocation(VertexUsage::Position, 0);
  107. }
  108. else if (i == VoronoiFbo)
  109. {
  110. m_fbos[i].m2 = Shader::Create(LOLFX_RESOURCE_NAME(12_voronoi));
  111. m_fbos[i].m3 << m_fbos[i].m2->GetUniformLocation("in_texture");
  112. m_fbos[i].m3 << m_fbos[i].m2->GetUniformLocation("in_step");
  113. m_fbos[i].m3 << m_fbos[i].m2->GetUniformLocation("in_screen_res");
  114. m_fbos[i].m4 << m_fbos[i].m2->GetAttribLocation(VertexUsage::Position, 0);
  115. }
  116. else if (i == DistanceVoronoiFbo)
  117. {
  118. m_fbos[i].m2 = Shader::Create(LOLFX_RESOURCE_NAME(12_voronoi_distance));
  119. }
  120. else if (i == DistanceFbo)
  121. {
  122. m_fbos[i].m2 = Shader::Create(LOLFX_RESOURCE_NAME(12_distance));
  123. }
  124. m_fbos.Last().m1->Bind();
  125. {
  126. RenderContext rc;
  127. rc.SetClearColor(vec4(0.f, 0.f, 0.f, 1.f));
  128. rc.SetClearDepth(1.f);
  129. Renderer::Get()->Clear(ClearMask::Color | ClearMask::Depth);
  130. }
  131. m_fbos.Last().m1->Unbind();
  132. }
  133. temp_buffer = new Framebuffer(Video::GetSize());
  134. temp_buffer->Bind();
  135. {
  136. RenderContext rc;
  137. rc.SetClearColor(vec4(0.f, 0.f, 0.f, 1.f));
  138. rc.SetClearDepth(1.f);
  139. Renderer::Get()->Clear(ClearMask::Color | ClearMask::Depth);
  140. }
  141. temp_buffer->Unbind();
  142. m_ready = true;
  143. /* FIXME: this object never cleans up */
  144. //SRC SETUP
  145. m_cur_fbo = VoronoiFbo;
  146. }
  147. {
  148. //Shutdown logic
  149. if (m_controller->WasKeyReleasedThisFrame(KEY_POP))
  150. voronoi_points.Pop();
  151. else if (m_controller->WasKeyReleasedThisFrame(KEY_PUSH))
  152. voronoi_points.Push(vec3(rand<float>(512.f), rand<float>(512.f), .0f),
  153. vec2(64.f + rand<float>(64.f), 64.f + rand<float>(64.f)));
  154. else if (m_controller->WasKeyReleasedThisFrame(KEY_F1))
  155. m_cur_fbo = SrcVoronoiFbo;
  156. else if (m_controller->WasKeyReleasedThisFrame(KEY_F2))
  157. m_cur_fbo = VoronoiFbo;
  158. else if (m_controller->WasKeyReleasedThisFrame(KEY_F3))
  159. {
  160. voronoi_points.Empty();
  161. if (mode == 0)
  162. {
  163. int i = 4;
  164. while (i-- > 0)
  165. voronoi_points.Push(vec3(rand<float>(512.f), rand<float>(512.f), .0f),
  166. vec2(64.f + rand<float>(64.f), 64.f + rand<float>(64.f))
  167. //vec2::zero
  168. );
  169. mode = 1;
  170. }
  171. else
  172. {
  173. mode = 0;
  174. }
  175. }
  176. }
  177. if (mode == 0)
  178. {
  179. voronoi_points.Empty();
  180. int maxi = 6;
  181. for (int i = 0; i < maxi; ++i)
  182. {
  183. float mi = (float)maxi;
  184. float j = (float)i;
  185. float f_time = (float)m_time;
  186. 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));
  187. 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));
  188. 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));
  189. 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));
  190. }
  191. voronoi_points.Push(vec3(256.f), vec2(0.f));
  192. }
  193. temp_buffer->Bind();
  194. {
  195. RenderContext rc;
  196. rc.SetClearColor(vec4(0.f, 0.f, 0.f, 1.f));
  197. rc.SetClearDepth(1.f);
  198. Renderer::Get()->Clear(ClearMask::Color | ClearMask::Depth);
  199. }
  200. temp_buffer->Unbind();
  201. {
  202. vec2 limit(1.f, 511.f);
  203. //SRC SETUP
  204. for (int j = 0; j < voronoi_points.Count(); ++j)
  205. {
  206. voronoi_points[j].m1 = vec3(voronoi_points[j].m1.xy + voronoi_points[j].m2 * seconds, voronoi_points[j].m1.z);
  207. if (voronoi_points[j].m1.x >= limit.y || voronoi_points[j].m1.x <= limit.x)
  208. {
  209. voronoi_points[j].m2.x *= -1.f;
  210. voronoi_points[j].m1.x = clamp(voronoi_points[j].m1.x, limit.x, limit.y);
  211. }
  212. if (voronoi_points[j].m1.y >= limit.y || voronoi_points[j].m1.y <= limit.x)
  213. {
  214. voronoi_points[j].m2.y *= -1.f;
  215. voronoi_points[j].m1.y = clamp(voronoi_points[j].m1.y, limit.x, limit.y);
  216. }
  217. voronoi_points[j].m1.z = ((float)j + 1) / ((float)voronoi_points.Count());
  218. }
  219. int f = SrcVoronoiFbo;
  220. m_fbos[f].m1->Bind();
  221. {
  222. RenderContext rc;
  223. rc.SetClearColor(vec4(0.f, 0.f, 0.f, 1.f));
  224. rc.SetClearDepth(1.f);
  225. Renderer::Get()->Clear(ClearMask::Color | ClearMask::Depth);
  226. }
  227. m_fbos[f].m1->Unbind();
  228. int buf = voronoi_points.Count() % 2;
  229. for (int j = 0; j < voronoi_points.Count(); ++j)
  230. {
  231. Framebuffer *dst_buf;
  232. Framebuffer *src_buf;
  233. if (buf)
  234. {
  235. dst_buf = m_fbos[f].m1;
  236. src_buf = temp_buffer;
  237. }
  238. else
  239. {
  240. src_buf = m_fbos[f].m1;
  241. dst_buf = temp_buffer;
  242. }
  243. dst_buf->Bind();
  244. /* FIXME: we should just disable depth test in the shader */
  245. Renderer::Get()->Clear(ClearMask::Depth);
  246. m_fbos[f].m2->Bind();
  247. int i = 0;
  248. m_fbos[f].m2->SetUniform(m_fbos[f].m3[i++], src_buf->GetTextureUniform(), 0); //"in_texture"
  249. m_fbos[f].m2->SetUniform(m_fbos[f].m3[i++], voronoi_points[j].m1); //"in_source_point"
  250. m_fbos[f].m2->SetUniform(m_fbos[f].m3[i++], vec2(512.f, 512.f)); //"in_screen_res"
  251. m_vdecl->SetStream(m_vbo, m_fbos[f].m4.Last());
  252. m_vdecl->Bind();
  253. m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, 6);
  254. m_vdecl->Unbind();
  255. m_fbos[f].m2->Unbind();
  256. dst_buf->Unbind();
  257. buf = 1 - buf;
  258. }
  259. }
  260. Renderer::Get()->Clear(ClearMask::Color | ClearMask::Depth);
  261. //FRAME BUFFER DRAW
  262. m_timer -= seconds;
  263. if (m_timer < .0f && m_cur_fbo != SrcVoronoiFbo)
  264. {
  265. //m_timer = 1.0f;
  266. m_fbos[m_cur_fbo].m1->Bind();
  267. {
  268. RenderContext rc;
  269. rc.SetClearColor(vec4(0.f, 0.f, 0.f, 1.f));
  270. rc.SetClearDepth(1.f);
  271. Renderer::Get()->Clear(ClearMask::Color | ClearMask::Depth);
  272. }
  273. m_fbos[m_cur_fbo].m1->Unbind();
  274. ivec2 curres = ivec2(512, 512) / 2;
  275. int buf = 0;
  276. while (1)
  277. {
  278. Framebuffer *dst_buf;
  279. Framebuffer *src_buf;
  280. 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. Renderer::Get()->Clear(ClearMask::Depth);
  298. shader->Bind();
  299. //08_FBO ??
  300. #if _XBOX
  301. /* FIXME: the Xbox enforces full EDRAM clears on each frame, so
  302. * we cannot expect the render target contents to be preserved.
  303. * This code snippet should be moved inside the Framebuffer class. */
  304. //m_fbos[m_cur_fbo].m2->SetUniform(m_uni_flag, 1.f);
  305. //m_fbos[m_cur_fbo].m2->SetUniform(m_uni_texture, m_fbo->GetTextureUniform(), 0);
  306. //m_vdecl->SetStream(m_vbo, m_fbos[m_cur_fbo].m4.Last());
  307. //m_vdecl->Bind();
  308. //m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, 6);
  309. //m_vdecl->Unbind();
  310. #endif
  311. int i = 0;
  312. if (curres == ivec2::zero)
  313. m_screen_shader->SetUniform(m_screen_texture, src_buf->GetTextureUniform(), 0);
  314. else if (m_cur_fbo == VoronoiFbo)
  315. {
  316. shader->SetUniform(m_fbos[m_cur_fbo].m3[i++], src_buf->GetTextureUniform(), 0); //"in_texture"
  317. shader->SetUniform(m_fbos[m_cur_fbo].m3[i++], ((float)curres.x) / 512.f); //"in_step"
  318. shader->SetUniform(m_fbos[m_cur_fbo].m3[i++], vec2(512.f, 512.f)); //"in_screen_res"
  319. }
  320. m_vdecl->SetStream(m_vbo, m_fbos[m_cur_fbo].m4.Last());
  321. m_vdecl->Bind();
  322. m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, 6);
  323. m_vdecl->Unbind();
  324. m_fbos[m_cur_fbo].m2->Unbind();
  325. dst_buf->Unbind();
  326. if (curres == ivec2::zero)
  327. break;
  328. if (curres == ivec2(1))
  329. {
  330. if (buf == 1)
  331. curres = ivec2::zero;
  332. else
  333. break;
  334. }
  335. buf = 1 - buf;
  336. curres /= 2;
  337. }
  338. }
  339. //SCREEN DRAW
  340. m_screen_shader->Bind();
  341. m_screen_shader->SetUniform(m_screen_texture, m_fbos[m_cur_fbo].m1->GetTextureUniform(), 0);
  342. m_vdecl->SetStream(m_vbo, m_screen_coord);
  343. m_vdecl->Bind();
  344. m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, 6);
  345. m_vdecl->Unbind();
  346. m_screen_shader->Unbind();
  347. }
  348. private:
  349. Controller* m_controller;
  350. array<vec3, vec2> voronoi_points;
  351. array<vec2> m_vertices;
  352. Shader *m_screen_shader;
  353. ShaderAttrib m_screen_coord;
  354. ShaderUniform m_screen_texture;
  355. VertexDeclaration *m_vdecl;
  356. VertexBuffer *m_vbo;
  357. array<Framebuffer *, Shader *, array<ShaderUniform>, array<ShaderAttrib> > m_fbos;
  358. Framebuffer *temp_buffer;
  359. int mode;
  360. int m_cur_fbo;
  361. double m_time;
  362. vec3 m_hotspot, m_color;
  363. bool m_ready;
  364. float m_timer;
  365. };
  366. int main(int argc, char **argv)
  367. {
  368. System::Init(argc, argv);
  369. Application app("Tutorial 12: Jump Flooding Algorithm & Voronoi", ivec2(512, 512), 60.0f);
  370. new Voronoi();
  371. app.Run();
  372. return EXIT_SUCCESS;
  373. }