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.

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