Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. //
  2. // Lol Engine - Fractal tutorial
  3. //
  4. // Copyright: (c) 2011 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://sam.zoy.org/projects/COPYING.WTFPL for more details.
  9. //
  10. #if defined HAVE_CONFIG_H
  11. # include "config.h"
  12. #endif
  13. #include <cstring>
  14. #include "core.h"
  15. #include "lolgl.h"
  16. #include "loldebug.h"
  17. using namespace std;
  18. using namespace lol;
  19. #if USE_SDL && defined __APPLE__
  20. # include <SDL_main.h>
  21. #endif
  22. #if defined _WIN32
  23. # undef main /* FIXME: still needed? */
  24. # include <direct.h>
  25. #endif
  26. class Fractal : public WorldEntity
  27. {
  28. public:
  29. Fractal(ivec2 const &size)
  30. {
  31. m_size = size;
  32. m_pixels = new u8vec4[size.x * size.y];
  33. m_tmppixels = new u8vec4[size.x / 2 * size.y / 2];
  34. m_frame = -1;
  35. for (int i = 0; i < 4; i++)
  36. {
  37. m_deltashift[i] = 0.0;
  38. m_deltascale[i] = 1.0;
  39. m_dirty[i] = 2;
  40. }
  41. m_center = -0.75;
  42. m_radius = 1.5;
  43. m_screenradius = 0.5 * (m_size.x < m_size.y ? m_size.x : m_size.y);
  44. m_ready = false;
  45. m_centertext = new Text(NULL, "gfx/font/ascii.png");
  46. m_centertext->SetPos(ivec3(5, m_size.y - 15, 1));
  47. Ticker::Ref(m_centertext);
  48. m_mousetext = new Text(NULL, "gfx/font/ascii.png");
  49. m_mousetext->SetPos(ivec3(5, m_size.y - 29, 1));
  50. Ticker::Ref(m_mousetext);
  51. m_zoomtext = new Text(NULL, "gfx/font/ascii.png");
  52. m_zoomtext->SetPos(ivec3(5, m_size.y - 43, 1));
  53. Ticker::Ref(m_zoomtext);
  54. position = ivec3(0, 0, 0);
  55. bbox[0] = position;
  56. bbox[1] = ivec3(size, 0);
  57. Input::TrackMouse(this);
  58. }
  59. ~Fractal()
  60. {
  61. Input::UntrackMouse(this);
  62. Ticker::Unref(m_centertext);
  63. Ticker::Unref(m_mousetext);
  64. Ticker::Unref(m_zoomtext);
  65. delete m_pixels;
  66. delete m_tmppixels;
  67. }
  68. inline f64cmplx ScreenToWorldOffset(ivec2 pixel)
  69. {
  70. f64cmplx tmp = f64cmplx(0.5 + pixel.x - m_size.x / 2,
  71. 0.5 + m_size.y / 2 - pixel.y);
  72. return tmp * (m_radius / m_screenradius);
  73. }
  74. virtual void TickGame(float deltams)
  75. {
  76. WorldEntity::TickGame(deltams);
  77. m_frame = (m_frame + 1) % 4;
  78. f64cmplx worldmouse = m_center + ScreenToWorldOffset(mousepos);
  79. ivec3 buttons = Input::GetMouseButtons();
  80. if ((buttons[0] || buttons[2]) && mousepos.x != -1)
  81. {
  82. f64cmplx oldcenter = m_center;
  83. double oldradius = m_radius;
  84. double zoom = pow(2.0, (buttons[0] ? -deltams : deltams) * 0.0015);
  85. if (m_radius * zoom > 8.0)
  86. zoom = 8.0 / m_radius;
  87. else if (m_radius * zoom < 1e-14)
  88. zoom = 1e-14 / m_radius;
  89. m_radius *= zoom;
  90. m_center = (m_center - worldmouse) * zoom + worldmouse;
  91. worldmouse = m_center + ScreenToWorldOffset(mousepos);
  92. /* Store the transformation properties to go from m_frame-1
  93. * to m_frame. */
  94. m_deltashift[m_frame] = (oldcenter - m_center) / m_radius;
  95. m_deltascale[m_frame] = oldradius / m_radius;
  96. m_dirty[0] = m_dirty[1] = m_dirty[2] = m_dirty[3] = 2;
  97. }
  98. else
  99. {
  100. /* If settings didn't change, set transformation from previous
  101. * frame to identity. */
  102. m_deltashift[m_frame] = 0.0;
  103. m_deltascale[m_frame] = 1.0;
  104. }
  105. if (buttons[1])
  106. m_dirty[0] = m_dirty[1] = m_dirty[2] = m_dirty[3] = 2;
  107. char buf[128];
  108. sprintf(buf, "center: %+13.11f%+13.11fi", m_center.x, m_center.y);
  109. m_centertext->SetText(buf);
  110. sprintf(buf, " mouse: %+13.11f%+13.11fi", worldmouse.x, worldmouse.y);
  111. m_mousetext->SetText(buf);
  112. sprintf(buf, " zoom: %g", 1.0 / m_radius);
  113. m_zoomtext->SetText(buf);
  114. u8vec4 *m_pixelstart = m_pixels + m_size.x * m_size.y / 4 * m_frame;
  115. if (m_dirty[m_frame])
  116. {
  117. m_dirty[m_frame]--;
  118. for (int j = ((m_frame + 1) % 4) / 2; j < m_size.y; j += 2)
  119. for (int i = m_frame % 2; i < m_size.x; i += 2)
  120. {
  121. double const maxlen = 32;
  122. int const maxiter = 170;
  123. f64cmplx z0 = m_center + ScreenToWorldOffset(ivec2(i, j));
  124. f64cmplx r0 = z0;
  125. //f64cmplx r0(0.28693186889504513, 0.014286693904085048);
  126. //f64cmplx r0(0.001643721971153, 0.822467633298876);
  127. //f64cmplx r0(-1.207205434596, 0.315432814901);
  128. //f64cmplx r0(-0.79192956889854, -0.14632423080102);
  129. //f64cmplx r0(0.3245046418497685, 0.04855101129280834);
  130. f64cmplx z;
  131. int iter = maxiter;
  132. for (z = z0; iter && z.sqlen() < maxlen * maxlen; z = z * z + r0)
  133. --iter;
  134. double f = iter;
  135. double n = z.sqlen();
  136. double k = log(n) * 0.5f / log(maxlen);
  137. /* Approximate log2(k) in [1,2]. */
  138. f += (- 0.344847817623168308695977510213252644185 * k
  139. + 2.024664188044341212602376988171727038739) * k
  140. - 1.674876738008591047163498125918330313237;
  141. if (iter)
  142. {
  143. double r = 0.5 * sin(f * 0.27 - 1.5) + 0.5;
  144. double g = 0.5 * sin(f * 0.13 + 1.3) + 0.5;
  145. double b = 0.5 * sin(f * 0.21 + 0.4) + 0.5;
  146. uint8_t red = r * 255.0f;
  147. uint8_t green = g * 255.0f;
  148. uint8_t blue = b * 255.0f;
  149. *m_pixelstart++ = u8vec4(red, green, blue, 0);
  150. }
  151. else
  152. {
  153. *m_pixelstart++ = u8vec4(0, 0, 0, 0);
  154. }
  155. }
  156. }
  157. }
  158. virtual void TickDraw(float deltams)
  159. {
  160. WorldEntity::TickDraw(deltams);
  161. static float const vertices[] =
  162. {
  163. 1.0f, 1.0f,
  164. -1.0f, 1.0f,
  165. -1.0f, -1.0f,
  166. -1.0f, -1.0f,
  167. 1.0f, -1.0f,
  168. 1.0f, 1.0f,
  169. };
  170. static float const texcoords[] =
  171. {
  172. 1.0f, 1.0f,
  173. 0.0f, 1.0f,
  174. 0.0f, 0.0f,
  175. 0.0f, 0.0f,
  176. 1.0f, 0.0f,
  177. 1.0f, 1.0f,
  178. };
  179. if (!m_ready)
  180. {
  181. /* Create a texture of half the width and twice the height
  182. * so that we can upload four different subimages each frame. */
  183. glGenTextures(1, &m_texid);
  184. glBindTexture(GL_TEXTURE_2D, m_texid);
  185. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_size.x / 2, m_size.y * 2,
  186. 0, GL_RGBA, GL_UNSIGNED_BYTE, m_pixels);
  187. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  188. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  189. m_shader = Shader::Create(
  190. #if !defined __CELLOS_LV2__
  191. "#version 120\n"
  192. "attribute vec2 in_TexCoord;\n"
  193. "attribute vec2 in_Vertex;"
  194. "void main(void) {"
  195. " gl_Position = vec4(in_Vertex, 0.0, 1.0);"
  196. " gl_TexCoord[0] = vec4(in_TexCoord, 0.0, 0.0);\n"
  197. "}",
  198. "#version 120\n"
  199. "uniform sampler2D in_Texture;\n"
  200. "void main(void) {"
  201. " vec2 coord = gl_TexCoord[0].xy;"
  202. /* gl_FragCoord is centered inside the pixel, so we remove
  203. * 0.5 from gl_FragCoord.x. Also, (0,0) is at the bottom
  204. * left whereas our images have (0,0) at the top left, so we
  205. * _add_ 0.5 to gl_FragCoord.y. (XXX: this is no longer true
  206. * but will be again when mouse coordinates are back to
  207. * being top-left again). */
  208. " float i = mod(gl_FragCoord.x - 0.5, 2.0);"
  209. " float j = mod(gl_FragCoord.y - 0.5 + i, 2.0);"
  210. " coord.y += i + j * 2;"
  211. " coord.y *= 0.25;"
  212. " vec4 p = texture2D(in_Texture, coord);"
  213. " gl_FragColor = p;"
  214. "}"
  215. #else
  216. "void main(float4 in_Position : POSITION,"
  217. " float2 in_TexCoord : TEXCOORD0,"
  218. " out float4 out_Position : POSITION,"
  219. " out float2 out_TexCoord : TEXCOORD0)"
  220. "{"
  221. " out_TexCoord = in_TexCoord;"
  222. " out_Position = in_Position;"
  223. "}",
  224. "void main(float2 in_TexCoord : TEXCOORD0,"
  225. " uniform sampler2D tex,"
  226. " out float4 out_FragColor : COLOR)"
  227. "{"
  228. " out_FragColor = tex2D(tex, in_TexCoord);"
  229. "}"
  230. #endif
  231. );
  232. m_vertexattrib = m_shader->GetAttribLocation("in_Vertex");
  233. m_texattrib = m_shader->GetAttribLocation("in_TexCoord");
  234. m_ready = true;
  235. #if !defined __CELLOS_LV2__ && !defined __ANDROID__ && !defined __APPLE__
  236. /* Method 1: store vertex buffer on the GPU memory */
  237. glGenBuffers(1, &m_vbo);
  238. glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
  239. glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices,
  240. GL_STATIC_DRAW);
  241. glGenBuffers(1, &m_tbo);
  242. glBindBuffer(GL_ARRAY_BUFFER, m_tbo);
  243. glBufferData(GL_ARRAY_BUFFER, sizeof(texcoords), texcoords,
  244. GL_STATIC_DRAW);
  245. #elif !defined __CELLOS_LV2__ && !defined __ANDROID__ && !defined __APPLE__
  246. /* Method 2: upload vertex information at each frame */
  247. #else
  248. #endif
  249. /* FIXME: this object never cleans up */
  250. }
  251. glEnable(GL_TEXTURE_2D);
  252. glBindTexture(GL_TEXTURE_2D, m_texid);
  253. if (m_dirty[m_frame])
  254. {
  255. m_dirty[m_frame]--;
  256. glTexSubImage2D(GL_TEXTURE_2D, 0, 0, m_frame * m_size.y / 2,
  257. m_size.x / 2, m_size.y / 2,
  258. #if !defined __CELLOS_LV2__
  259. GL_RGBA, GL_UNSIGNED_BYTE,
  260. #else
  261. /* The PS3 is big-endian */
  262. GL_RGBA, GL_UNSIGNED_INT_8_8_8_8,
  263. #endif
  264. m_pixels + m_size.x * m_size.y / 4 * m_frame);
  265. }
  266. /* If other frames are dirty, upload fake data for now */
  267. for (int i = 0; i < 4; i++)
  268. {
  269. if (m_dirty[i])
  270. {
  271. glTexSubImage2D(GL_TEXTURE_2D, 0, 0, i * m_size.y / 2,
  272. m_size.x / 2, m_size.y / 2,
  273. #if !defined __CELLOS_LV2__
  274. GL_RGBA, GL_UNSIGNED_BYTE,
  275. #else
  276. /* The PS3 is big-endian */
  277. GL_RGBA, GL_UNSIGNED_INT_8_8_8_8,
  278. #endif
  279. m_pixels + m_size.x * m_size.y / 4 * m_frame);
  280. }
  281. }
  282. m_shader->Bind();
  283. #if !defined __CELLOS_LV2__ && !defined __ANDROID__ && !defined __APPLE__
  284. glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
  285. glEnableVertexAttribArray(m_vertexattrib);
  286. glVertexAttribPointer(m_vertexattrib, 2, GL_FLOAT, GL_FALSE, 0, 0);
  287. glBindBuffer(GL_ARRAY_BUFFER, m_tbo);
  288. glEnableVertexAttribArray(m_texattrib);
  289. glVertexAttribPointer(m_texattrib, 2, GL_FLOAT, GL_FALSE, 0, 0);
  290. #elif !defined __CELLOS_LV2__ && !defined __ANDROID__ && !defined __APPLE__
  291. /* Never used for now */
  292. //glEnableVertexAttribArray(m_vertexattrib);
  293. //glVertexAttribPointer(m_vertexattrib, 2, GL_FLOAT, GL_FALSE, 0, vertices);
  294. #else
  295. glEnableClientState(GL_VERTEX_ARRAY);
  296. glVertexPointer(2, GL_FLOAT, 0, vertices);
  297. glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  298. glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
  299. #endif
  300. glDrawArrays(GL_TRIANGLES, 0, 6);
  301. #if !defined __CELLOS_LV2__ && !defined __ANDROID__ && !defined __APPLE__
  302. glDisableVertexAttribArray(m_vertexattrib);
  303. glDisableVertexAttribArray(m_texattrib);
  304. glBindBuffer(GL_ARRAY_BUFFER, 0);
  305. #elif !defined __CELLOS_LV2__ && !defined __ANDROID__ && !defined __APPLE__
  306. /* Never used for now */
  307. //glDisableVertexAttribArray(m_vertexattrib);
  308. //glDisableVertexAttribArray(m_texattrib);
  309. #else
  310. glDisableClientState(GL_VERTEX_ARRAY);
  311. glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  312. #endif
  313. }
  314. private:
  315. ivec2 m_size;
  316. u8vec4 *m_pixels, *m_tmppixels;
  317. Shader *m_shader;
  318. GLuint m_texid;
  319. #if !defined __CELLOS_LV2__ && !defined __ANDROID__ && !defined __APPLE__
  320. GLuint m_vbo, m_tbo;
  321. GLuint m_tco;
  322. #endif
  323. int m_vertexattrib, m_texattrib;
  324. int m_frame, m_dirty[4];
  325. bool m_ready;
  326. f64cmplx m_center;
  327. double m_radius, m_screenradius;
  328. f64cmplx m_deltashift[4];
  329. double m_deltascale[4];
  330. /* Debug information */
  331. Text *m_centertext, *m_mousetext, *m_zoomtext;
  332. };
  333. int main()
  334. {
  335. #if defined _WIN32
  336. _chdir("../..");
  337. #endif
  338. Application app("Tutorial 3: Fractal", ivec2(640, 480), 60.0f);
  339. new DebugFps(5, 5);
  340. new Fractal(ivec2(640, 480));
  341. //new DebugRecord("fractalol.ogm", 60.0f);
  342. app.Run();
  343. return EXIT_SUCCESS;
  344. }