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