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 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  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. Video::SetClearColor(vec4(0.f, 0.f, 0.f, 1.f));
  109. Video::SetClearDepth(1.f);
  110. Video::Clear(ClearMask::Color | ClearMask::Depth);
  111. m_fbos.Last().m1->Unbind();
  112. }
  113. temp_buffer = new Framebuffer(Video::GetSize());
  114. temp_buffer->Bind();
  115. Video::SetClearColor(vec4(0.f, 0.f, 0.f, 1.f));
  116. Video::SetClearDepth(1.f);
  117. Video::Clear(ClearMask::Color | ClearMask::Depth);
  118. temp_buffer->Unbind();
  119. m_ready = true;
  120. /* FIXME: this object never cleans up */
  121. //SRC SETUP
  122. m_cur_fbo = VoronoiFbo;
  123. }
  124. {
  125. //Shutdown logic
  126. if (Input::WasReleased(Key::O))
  127. voronoi_points.Pop();
  128. else if (Input::WasReleased(Key::P))
  129. voronoi_points.Push(vec3(rand<float>(512.f), rand<float>(512.f), .0f),
  130. vec2(64.f + rand<float>(64.f), 64.f + rand<float>(64.f)));
  131. else if (Input::WasReleased(Key::F1))
  132. m_cur_fbo = SrcVoronoiFbo;
  133. else if (Input::WasReleased(Key::F2))
  134. m_cur_fbo = VoronoiFbo;
  135. else if (Input::WasReleased(Key::F3))
  136. {
  137. voronoi_points.Empty();
  138. if (mode == 0)
  139. {
  140. int i = 4;
  141. while (i-- > 0)
  142. voronoi_points.Push(vec3(rand<float>(512.f), rand<float>(512.f), .0f),
  143. vec2(64.f + rand<float>(64.f), 64.f + rand<float>(64.f))
  144. //vec2(0.f)
  145. );
  146. mode = 1;
  147. }
  148. else
  149. {
  150. mode = 0;
  151. }
  152. }
  153. }
  154. if (mode == 0)
  155. {
  156. voronoi_points.Empty();
  157. int maxi = 6;
  158. for (int i = 0; i < maxi; ++i)
  159. {
  160. 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));
  161. 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));
  162. 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));
  163. 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));
  164. }
  165. voronoi_points.Push(vec3(256.f), vec2(.0f));
  166. }
  167. temp_buffer->Bind();
  168. Video::SetClearColor(vec4(0.f, 0.f, 0.f, 1.f));
  169. Video::SetClearDepth(1.f);
  170. Video::Clear(ClearMask::Color | ClearMask::Depth);
  171. temp_buffer->Unbind();
  172. {
  173. vec2 limit(1.f, 511.f);
  174. //SRC SETUP
  175. for (int j = 0; j < voronoi_points.Count(); ++j)
  176. {
  177. voronoi_points[j].m1 = vec3(voronoi_points[j].m1.xy + voronoi_points[j].m2 * seconds, voronoi_points[j].m1.z);
  178. if (voronoi_points[j].m1.x >= limit.y || voronoi_points[j].m1.x <= limit.x)
  179. {
  180. voronoi_points[j].m2.x *= -1.f;
  181. voronoi_points[j].m1.x = clamp(voronoi_points[j].m1.x, limit.x, limit.y);
  182. }
  183. if (voronoi_points[j].m1.y >= limit.y || voronoi_points[j].m1.y <= limit.x)
  184. {
  185. voronoi_points[j].m2.y *= -1.f;
  186. voronoi_points[j].m1.y = clamp(voronoi_points[j].m1.y, limit.x, limit.y);
  187. }
  188. voronoi_points[j].m1.z = ((float)j + 1) / ((float)voronoi_points.Count());
  189. }
  190. int f = SrcVoronoiFbo;
  191. m_fbos[f].m1->Bind();
  192. Video::SetClearColor(vec4(0.f, 0.f, 0.f, 1.f));
  193. Video::SetClearDepth(1.f);
  194. Video::Clear(ClearMask::Color | ClearMask::Depth);
  195. m_fbos[f].m1->Unbind();
  196. int buf = voronoi_points.Count() % 2;
  197. for (int j = 0; j < voronoi_points.Count(); ++j)
  198. {
  199. Framebuffer *dst_buf;
  200. Framebuffer *src_buf;
  201. if (buf)
  202. {
  203. dst_buf = m_fbos[f].m1;
  204. src_buf = temp_buffer;
  205. }
  206. else
  207. {
  208. src_buf = m_fbos[f].m1;
  209. dst_buf = temp_buffer;
  210. }
  211. dst_buf->Bind();
  212. /* FIXME: we should just disable depth test in the shader */
  213. Video::Clear(ClearMask::Depth);
  214. m_fbos[f].m2->Bind();
  215. int i = 0;
  216. m_fbos[f].m2->SetUniform(m_fbos[f].m3[i++], src_buf->GetTexture(), 0); //"in_texture"
  217. m_fbos[f].m2->SetUniform(m_fbos[f].m3[i++], voronoi_points[j].m1); //"in_source_point"
  218. m_fbos[f].m2->SetUniform(m_fbos[f].m3[i++], vec2(512.f, 512.f)); //"in_screen_res"
  219. m_vdecl->SetStream(m_vbo, m_fbos[f].m4.Last());
  220. m_vdecl->Bind();
  221. m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, 6);
  222. m_vdecl->Unbind();
  223. m_fbos[f].m2->Unbind();
  224. dst_buf->Unbind();
  225. buf = 1 - buf;
  226. }
  227. }
  228. Video::Clear(ClearMask::Color | ClearMask::Depth);
  229. //FRAME BUFFER DRAW
  230. m_timer -= seconds;
  231. if (m_timer < .0f && m_cur_fbo != SrcVoronoiFbo)
  232. {
  233. //m_timer = 1.0f;
  234. m_fbos[m_cur_fbo].m1->Bind();
  235. Video::SetClearColor(vec4(0.f, 0.f, 0.f, 1.f));
  236. Video::SetClearDepth(1.f);
  237. Video::Clear(ClearMask::Color | ClearMask::Depth);
  238. m_fbos[m_cur_fbo].m1->Unbind();
  239. ivec2 curres = ivec2(512, 512) / 2;
  240. int buf = 0;
  241. while (1)
  242. {
  243. Framebuffer *dst_buf;
  244. Framebuffer *src_buf;
  245. Shader *shader;
  246. if (curres == ivec2(0))
  247. shader = m_screen_shader;
  248. else
  249. shader = m_fbos[m_cur_fbo].m2;
  250. if (curres.x == 256)
  251. src_buf = m_fbos[SrcVoronoiFbo].m1;
  252. else if (buf)
  253. src_buf = m_fbos[m_cur_fbo].m1;
  254. else
  255. src_buf = temp_buffer;
  256. if (buf)
  257. dst_buf = temp_buffer;
  258. else
  259. dst_buf = m_fbos[m_cur_fbo].m1;
  260. dst_buf->Bind();
  261. /* FIXME: we should just disable depth test in the shader */
  262. Video::Clear(ClearMask::Depth);
  263. shader->Bind();
  264. //08_FBO ??
  265. #if _XBOX
  266. /* FIXME: the Xbox enforces full EDRAM clears on each frame, so
  267. * we cannot expect the render target contents to be preserved.
  268. * This code snippet should be moved inside the Framebuffer class. */
  269. //m_fbos[m_cur_fbo].m2->SetUniform(m_uni_flag, 1.f);
  270. //m_fbos[m_cur_fbo].m2->SetUniform(m_uni_texture, m_fbo->GetTexture(), 0);
  271. //m_vdecl->SetStream(m_vbo, m_fbos[m_cur_fbo].m4.Last());
  272. //m_vdecl->Bind();
  273. //m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, 6);
  274. //m_vdecl->Unbind();
  275. #endif
  276. int i = 0;
  277. if (curres == ivec2(0))
  278. m_screen_shader->SetUniform(m_screen_texture, src_buf->GetTexture(), 0);
  279. else if (m_cur_fbo == VoronoiFbo)
  280. {
  281. shader->SetUniform(m_fbos[m_cur_fbo].m3[i++], src_buf->GetTexture(), 0); //"in_texture"
  282. shader->SetUniform(m_fbos[m_cur_fbo].m3[i++], ((float)curres.x) / 512.f); //"in_step"
  283. shader->SetUniform(m_fbos[m_cur_fbo].m3[i++], vec2(512.f, 512.f)); //"in_screen_res"
  284. }
  285. m_vdecl->SetStream(m_vbo, m_fbos[m_cur_fbo].m4.Last());
  286. m_vdecl->Bind();
  287. m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, 6);
  288. m_vdecl->Unbind();
  289. m_fbos[m_cur_fbo].m2->Unbind();
  290. dst_buf->Unbind();
  291. if (curres == ivec2(0))
  292. break;
  293. if (curres == ivec2(1))
  294. {
  295. if (buf == 1)
  296. curres = ivec2(0);
  297. else
  298. break;
  299. }
  300. buf = 1 - buf;
  301. curres /= 2;
  302. }
  303. }
  304. //SCREEN DRAW
  305. m_screen_shader->Bind();
  306. m_screen_shader->SetUniform(m_screen_texture, m_fbos[m_cur_fbo].m1->GetTexture(), 0);
  307. m_vdecl->SetStream(m_vbo, m_screen_coord);
  308. m_vdecl->Bind();
  309. m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, 6);
  310. m_vdecl->Unbind();
  311. m_screen_shader->Unbind();
  312. }
  313. private:
  314. Array<vec3, vec2> voronoi_points;
  315. Array<vec2> m_vertices;
  316. Shader *m_screen_shader;
  317. ShaderAttrib m_screen_coord;
  318. ShaderUniform m_screen_texture;
  319. VertexDeclaration *m_vdecl;
  320. VertexBuffer *m_vbo;
  321. Array<Framebuffer *, Shader *, Array<ShaderUniform>, Array<ShaderAttrib> > m_fbos;
  322. Framebuffer *temp_buffer;
  323. int mode;
  324. int m_cur_fbo;
  325. double m_time;
  326. vec3 m_hotspot, m_color;
  327. bool m_ready;
  328. float m_timer;
  329. };
  330. int main(int argc, char **argv)
  331. {
  332. System::Init(argc, argv);
  333. Application app("Tutorial 12: Jump Flooding Algorithm & Voronoi", ivec2(512, 512), 60.0f);
  334. new Voronoi();
  335. app.Run();
  336. return EXIT_SUCCESS;
  337. }