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