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.

преди 13 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 13 години
преди 13 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. //
  2. // Lol Engine - Fractal tutorial
  3. //
  4. // Copyright: (c) 2011-2012 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 lol;
  18. #if defined _WIN32
  19. # include <direct.h>
  20. # if defined USE_D3D9
  21. # define FAR
  22. # define NEAR
  23. # include <d3d9.h>
  24. # endif
  25. #endif
  26. extern char const *lolfx_11_fractal;
  27. #if defined USE_D3D9
  28. extern IDirect3DDevice9 *g_d3ddevice;
  29. #elif defined _XBOX
  30. extern D3DDevice *g_d3ddevice;
  31. #elif __CELLOS_LV2__
  32. static GLint const INTERNAL_FORMAT = GL_ARGB_SCE;
  33. static GLenum const TEXTURE_FORMAT = GL_BGRA;
  34. static GLenum const TEXTURE_TYPE = GL_UNSIGNED_INT_8_8_8_8_REV;
  35. #elif defined __native_client__ || defined HAVE_GLES_2X
  36. static GLint const INTERNAL_FORMAT = GL_RGBA;
  37. static GLenum const TEXTURE_FORMAT = GL_RGBA;
  38. static GLenum const TEXTURE_TYPE = GL_UNSIGNED_BYTE;
  39. #else
  40. /* Seems efficient for little endian textures */
  41. static GLint const INTERNAL_FORMAT = GL_RGBA;
  42. static GLenum const TEXTURE_FORMAT = GL_BGRA;
  43. static GLenum const TEXTURE_TYPE = GL_UNSIGNED_INT_8_8_8_8_REV;
  44. #endif
  45. class Fractal : public WorldEntity
  46. {
  47. public:
  48. Fractal(ivec2 const &size)
  49. {
  50. /* Ensure texture size is a multiple of 16 for better aligned
  51. * data access. Store the dimensions of a texel for our shader,
  52. * as well as the half-size of the screen. */
  53. m_size = size;
  54. m_size.x = (m_size.x + 15) & ~15;
  55. m_size.y = (m_size.y + 15) & ~15;
  56. m_texel_settings = vec4(1.0, 1.0, 2.0, 2.0) / m_size.xyxy;
  57. m_screen_settings = vec4(1.0, 1.0, 0.5, 0.5) * m_size.xyxy;
  58. /* Window size decides the world aspect ratio. For instance, 640×480
  59. * will be mapped to (-0.66,-0.5) - (0.66,0.5). */
  60. #if !defined __native_client__
  61. m_window_size = Video::GetSize();
  62. #else
  63. /* FIXME: it's illegal to call this on the game thread! */
  64. m_window_size = ivec2(640, 480);
  65. #endif
  66. if (m_window_size.y < m_window_size.x)
  67. m_window2world = 0.5 / m_window_size.y;
  68. else
  69. m_window2world = 0.5 / m_window_size.x;
  70. m_texel2world = (vec2)m_window_size / m_size * m_window2world;
  71. m_oldmouse = ivec2(0, 0);
  72. m_pixels = new u8vec4[m_size.x * m_size.y];
  73. m_tmppixels = new u8vec4[m_size.x / 2 * m_size.y / 2];
  74. m_frame = -1;
  75. m_slices = 4;
  76. for (int i = 0; i < 4; i++)
  77. {
  78. m_deltashift[i] = real("0");
  79. m_deltascale[i] = real("1");
  80. m_dirty[i] = 2;
  81. }
  82. #if defined __CELLOS_LV2__ || defined _XBOX
  83. //m_center = rcmplx(-.22815528839841, -1.11514249704382);
  84. //m_center = rcmplx(0.001643721971153, 0.822467633298876);
  85. m_center = rcmplx("-0.65823419062254", "0.50221777363480");
  86. m_zoom_speed = -0.025;
  87. #else
  88. m_center = rcmplx(-0.75, 0.0);
  89. m_zoom_speed = 0.0;
  90. #endif
  91. m_translate = rcmplx(0.0, 0.0);
  92. m_radius = 5.0;
  93. m_ready = false;
  94. m_drag = false;
  95. m_palette = new u8vec4[(MAX_ITERATIONS + 1) * PALETTE_STEP];
  96. for (int i = 0; i < (MAX_ITERATIONS + 1) * PALETTE_STEP; i++)
  97. {
  98. double f = (double)i / PALETTE_STEP;
  99. double r = 0.5 * lol::sin(f * 0.27 + 2.0) + 0.5;
  100. double g = 0.5 * lol::sin(f * 0.17 - 1.8) + 0.5;
  101. double b = 0.5 * lol::sin(f * 0.21 - 2.6) + 0.5;
  102. if (f < 7.0)
  103. {
  104. f = f < 1.0 ? 0.0 : (f - 1.0) / 6.0;
  105. r *= f;
  106. g *= f;
  107. b *= f;
  108. }
  109. uint8_t red = r * 255.99f;
  110. uint8_t green = g * 255.99f;
  111. uint8_t blue = b * 255.99f;
  112. #if defined __CELLOS_LV2__ || defined _XBOX
  113. m_palette[i] = u8vec4(255, red, green, blue);
  114. #elif defined __native_client__
  115. m_palette[i] = u8vec4(red, green, blue, 255);
  116. #else
  117. m_palette[i] = u8vec4(blue, green, red, 255);
  118. #endif
  119. }
  120. #if !defined __native_client__
  121. m_centertext = new Text(NULL, "src/data/font/ascii.png");
  122. m_centertext->SetPos(ivec3(5, m_window_size.y - 15, 1));
  123. Ticker::Ref(m_centertext);
  124. m_mousetext = new Text(NULL, "src/data/font/ascii.png");
  125. m_mousetext->SetPos(ivec3(5, m_window_size.y - 29, 1));
  126. Ticker::Ref(m_mousetext);
  127. m_zoomtext = new Text(NULL, "src/data/font/ascii.png");
  128. m_zoomtext->SetPos(ivec3(5, m_window_size.y - 43, 1));
  129. Ticker::Ref(m_zoomtext);
  130. #endif
  131. m_position = ivec3(0, 0, 0);
  132. m_bbox[0] = m_position;
  133. m_bbox[1] = ivec3(m_window_size, 0);
  134. Input::TrackMouse(this);
  135. /* Spawn worker threads and wait for their readiness. */
  136. for (int i = 0; i < MAX_THREADS; i++)
  137. m_threads[i] = new Thread(DoWorkHelper, this);
  138. for (int i = 0; i < MAX_THREADS; i++)
  139. m_spawnqueue.Pop();
  140. }
  141. ~Fractal()
  142. {
  143. /* Signal worker threads for completion and wait for
  144. * them to quit. */
  145. for (int i = 0; i < MAX_THREADS; i++)
  146. m_jobqueue.Push(-1);
  147. for (int i = 0; i < MAX_THREADS; i++)
  148. m_donequeue.Pop();
  149. Input::UntrackMouse(this);
  150. #if !defined __native_client__
  151. Ticker::Unref(m_centertext);
  152. Ticker::Unref(m_mousetext);
  153. Ticker::Unref(m_zoomtext);
  154. #endif
  155. delete m_pixels;
  156. delete m_tmppixels;
  157. delete m_palette;
  158. }
  159. inline dcmplx TexelToWorldOffset(vec2 texel)
  160. {
  161. double dx = (0.5 + texel.x - m_size.x / 2) * m_texel2world.x;
  162. double dy = (0.5 + m_size.y / 2 - texel.y) * m_texel2world.y;
  163. return m_radius * dcmplx(dx, dy);
  164. }
  165. inline dcmplx ScreenToWorldOffset(vec2 pixel)
  166. {
  167. /* No 0.5 offset here, because we want to be able to position the
  168. * mouse at (0,0) exactly. */
  169. double dx = pixel.x - m_window_size.x / 2;
  170. double dy = m_window_size.y / 2 - pixel.y;
  171. return m_radius * m_window2world * dcmplx(dx, dy);
  172. }
  173. virtual void TickGame(float seconds)
  174. {
  175. WorldEntity::TickGame(seconds);
  176. int prev_frame = (m_frame + 4) % 4;
  177. m_frame = (m_frame + 1) % 4;
  178. rcmplx worldmouse = m_center + rcmplx(ScreenToWorldOffset(m_mousepos));
  179. ivec3 buttons = Input::GetMouseButtons();
  180. #if !defined __CELLOS_LV2__ && !defined _XBOX
  181. if (buttons[1])
  182. {
  183. if (!m_drag)
  184. {
  185. m_oldmouse = m_mousepos;
  186. m_drag = true;
  187. }
  188. m_translate = ScreenToWorldOffset(m_oldmouse)
  189. - ScreenToWorldOffset(m_mousepos);
  190. /* XXX: the purpose of this hack is to avoid translating by
  191. * an exact number of pixels. If this were to happen, the step()
  192. * optimisation for i915 cards in our shader would behave
  193. * incorrectly because a quarter of the pixels in the image
  194. * would have tie rankings in the distance calculation. */
  195. m_translate *= real(1023.0 / 1024.0);
  196. m_oldmouse = m_mousepos;
  197. }
  198. else
  199. {
  200. m_drag = false;
  201. if (m_translate != rcmplx(0.0, 0.0))
  202. {
  203. m_translate *= real(std::pow(2.0, -seconds * 5.0));
  204. if ((double)m_translate.norm() < m_radius * 1e-4)
  205. m_translate = rcmplx(0.0, 0.0);
  206. }
  207. }
  208. if ((buttons[0] || buttons[2]) && m_mousepos.x != -1)
  209. {
  210. double zoom = buttons[0] ? -0.5 : 0.5;
  211. m_zoom_speed += zoom * seconds;
  212. if (m_zoom_speed / zoom > 5e-3f)
  213. m_zoom_speed = zoom * 5e-3f;
  214. }
  215. else if (m_zoom_speed)
  216. {
  217. m_zoom_speed *= std::pow(2.0, -seconds * 5.0);
  218. if (abs(m_zoom_speed) < 1e-5 || m_drag)
  219. m_zoom_speed = 0.0;
  220. }
  221. #endif
  222. if (m_zoom_speed || m_translate != rcmplx(0.0, 0.0))
  223. {
  224. rcmplx oldcenter = m_center;
  225. double oldradius = m_radius;
  226. double zoom = std::pow(2.0, seconds * 1e3f * m_zoom_speed);
  227. if (m_radius * zoom > 8.0)
  228. {
  229. m_zoom_speed *= -1.0;
  230. zoom = 8.0 / m_radius;
  231. }
  232. else if (m_radius * zoom < 1e-14)
  233. {
  234. m_zoom_speed *= -1.0;
  235. zoom = 1e-14 / m_radius;
  236. }
  237. m_radius *= zoom;
  238. #if !defined __CELLOS_LV2__ && !defined _XBOX
  239. m_center += m_translate;
  240. m_center = (m_center - worldmouse) * real(zoom) + worldmouse;
  241. worldmouse = m_center + rcmplx(ScreenToWorldOffset(m_mousepos));
  242. #endif
  243. /* Store the transformation properties to go from m_frame - 1
  244. * to m_frame. */
  245. m_deltashift[prev_frame] = (m_center - oldcenter) / real(oldradius);
  246. m_deltashift[prev_frame].x /= m_size.x * m_texel2world.x;
  247. m_deltashift[prev_frame].y /= m_size.y * m_texel2world.y;
  248. m_deltascale[prev_frame] = m_radius / oldradius;
  249. m_dirty[0] = m_dirty[1] = m_dirty[2] = m_dirty[3] = 2;
  250. }
  251. else
  252. {
  253. /* If settings didn't change, set transformation from previous
  254. * frame to identity. */
  255. m_deltashift[prev_frame] = real::R_0;
  256. m_deltascale[prev_frame] = real::R_1;
  257. }
  258. /* Transformation from current frame to current frame is always
  259. * identity. */
  260. m_zoom_settings[m_frame][0] = 0.0f;
  261. m_zoom_settings[m_frame][1] = 0.0f;
  262. m_zoom_settings[m_frame][2] = 1.0f;
  263. /* Compute transformation from other frames to current frame */
  264. for (int i = 0; i < 3; i++)
  265. {
  266. int prev_index = (m_frame + 4 - i) % 4;
  267. int cur_index = (m_frame + 3 - i) % 4;
  268. m_zoom_settings[cur_index][0] = (real)m_zoom_settings[prev_index][0] * m_deltascale[cur_index] + m_deltashift[cur_index].x;
  269. m_zoom_settings[cur_index][1] = (real)m_zoom_settings[prev_index][1] * m_deltascale[cur_index] + m_deltashift[cur_index].y;
  270. m_zoom_settings[cur_index][2] = (real)m_zoom_settings[prev_index][2] * m_deltascale[cur_index];
  271. }
  272. /* Precompute texture offset change instead of doing it in GLSL */
  273. for (int i = 0; i < 4; i++)
  274. {
  275. m_zoom_settings[i][0] += 0.5 * (1.0 - m_zoom_settings[i][2]);
  276. m_zoom_settings[i][1] -= 0.5 * (1.0 - m_zoom_settings[i][2]);
  277. }
  278. #if !defined __native_client__
  279. char buf[256];
  280. sprintf(buf, "center: ");
  281. m_center.x.sprintf(buf + strlen(buf), 30);
  282. sprintf(buf + strlen(buf), " ");
  283. m_center.y.sprintf(buf + strlen(buf), 30);
  284. m_centertext->SetText(buf);
  285. sprintf(buf, " mouse: ");
  286. worldmouse.x.sprintf(buf + strlen(buf), 30);
  287. sprintf(buf + strlen(buf), " ");
  288. worldmouse.y.sprintf(buf + strlen(buf), 30);
  289. m_mousetext->SetText(buf);
  290. sprintf(buf, " zoom: %g", 1.0 / m_radius);
  291. m_zoomtext->SetText(buf);
  292. #endif
  293. if (m_dirty[m_frame])
  294. {
  295. m_dirty[m_frame]--;
  296. for (int i = 0; i < m_size.y; i += MAX_LINES * 2)
  297. m_jobqueue.Push(i);
  298. }
  299. }
  300. static void *DoWorkHelper(void *data)
  301. {
  302. Fractal *that = (Fractal *)data;
  303. that->m_spawnqueue.Push(0);
  304. for ( ; ; )
  305. {
  306. int line = that->m_jobqueue.Pop();
  307. if (line == -1)
  308. break;
  309. that->DoWork(line);
  310. that->m_donequeue.Push(0);
  311. }
  312. that->m_donequeue.Push(0);
  313. return NULL;
  314. };
  315. void DoWork(int line)
  316. {
  317. double const maxsqlen = 1024;
  318. double const k1 = 1.0 / (1 << 10) / (std::log(maxsqlen) / std::log(2.0));
  319. int jmin = ((m_frame + 1) % 4) / 2 + line;
  320. int jmax = jmin + MAX_LINES * 2;
  321. if (jmax > m_size.y)
  322. jmax = m_size.y;
  323. u8vec4 *m_pixelstart = m_pixels
  324. + m_size.x * (m_size.y / 4 * m_frame + line / 4);
  325. dcmplx c = (dcmplx)m_center;
  326. for (int j = jmin; j < jmax; j += 2)
  327. for (int i = m_frame % 2; i < m_size.x; i += 2)
  328. {
  329. dcmplx z0 = c + TexelToWorldOffset(ivec2(i, j));
  330. dcmplx z1, z2, z3, r0 = z0;
  331. //dcmplx r0(0.28693186889504513, 0.014286693904085048);
  332. //dcmplx r0(0.001643721971153, 0.822467633298876);
  333. //dcmplx r0(-1.207205434596, 0.315432814901);
  334. //dcmplx r0(-0.79192956889854, -0.14632423080102);
  335. //dcmplx r0(0.3245046418497685, 0.04855101129280834);
  336. int iter = MAX_ITERATIONS - 4;
  337. for (;;)
  338. {
  339. /* Unroll the loop: tests are more expensive to do at each
  340. * iteration than the few extra multiplications. */
  341. z1 = z0 * z0 + r0;
  342. z2 = z1 * z1 + r0;
  343. z3 = z2 * z2 + r0;
  344. z0 = z3 * z3 + r0;
  345. if (sqlength(z0) >= maxsqlen)
  346. break;
  347. iter -= 4;
  348. if (iter < 4)
  349. break;
  350. }
  351. if (iter)
  352. {
  353. double n = sqlength(z0);
  354. if (sqlength(z1) >= maxsqlen) { iter += 3; n = sqlength(z1); }
  355. else if (sqlength(z2) >= maxsqlen) { iter += 2; n = sqlength(z2); }
  356. else if (sqlength(z3) >= maxsqlen) { iter += 1; n = sqlength(z3); }
  357. if (n > maxsqlen * maxsqlen)
  358. n = maxsqlen * maxsqlen;
  359. /* Approximate log(sqrt(n))/log(sqrt(maxsqlen)) */
  360. double f = iter;
  361. union { double n; uint64_t x; } u = { n };
  362. double k = (u.x >> 42) - (((1 << 10) - 1) << 10);
  363. k *= k1;
  364. /* Approximate log2(k) in [1,2]. */
  365. f += (- 0.344847817623168308695977510213252644185 * k
  366. + 2.024664188044341212602376988171727038739) * k
  367. - 1.674876738008591047163498125918330313237;
  368. *m_pixelstart++ = m_palette[(int)(f * PALETTE_STEP)];
  369. }
  370. else
  371. {
  372. #if defined __CELLOS_LV2__ || defined _XBOX
  373. *m_pixelstart++ = u8vec4(255, 0, 0, 0);
  374. #else
  375. *m_pixelstart++ = u8vec4(0, 0, 0, 255);
  376. #endif
  377. }
  378. }
  379. }
  380. virtual void TickDraw(float seconds)
  381. {
  382. WorldEntity::TickDraw(seconds);
  383. static float const vertices[] =
  384. {
  385. 1.0f, 1.0f,
  386. -1.0f, 1.0f,
  387. -1.0f, -1.0f,
  388. -1.0f, -1.0f,
  389. 1.0f, -1.0f,
  390. 1.0f, 1.0f,
  391. };
  392. static float const texcoords[] =
  393. {
  394. 1.0f, 1.0f,
  395. 0.0f, 1.0f,
  396. 0.0f, 0.0f,
  397. 0.0f, 0.0f,
  398. 1.0f, 0.0f,
  399. 1.0f, 1.0f,
  400. };
  401. if (!m_ready)
  402. {
  403. #if !defined _XBOX && !defined USE_D3D9
  404. /* Create a texture of half the width and twice the height
  405. * so that we can upload four different subimages each frame. */
  406. glGenTextures(1, &m_texid);
  407. glBindTexture(GL_TEXTURE_2D, m_texid);
  408. glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT,
  409. m_size.x / 2, m_size.y * 2, 0,
  410. TEXTURE_FORMAT, TEXTURE_TYPE, m_pixels);
  411. # if defined __CELLOS_LV2__
  412. /* We need this hint because by default the storage type is
  413. * GL_TEXTURE_SWIZZLED_GPU_SCE. */
  414. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_ALLOCATION_HINT_SCE,
  415. GL_TEXTURE_TILED_GPU_SCE);
  416. # endif
  417. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  418. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  419. #elif defined _XBOX
  420. /* By default the X360 will swizzle the texture. Ask for linear. */
  421. g_d3ddevice->CreateTexture(m_size.x / 2, m_size.y * 2, 1,
  422. D3DUSAGE_WRITEONLY, D3DFMT_LIN_A8R8G8B8,
  423. D3DPOOL_DEFAULT, &m_tex, NULL);
  424. #else
  425. g_d3ddevice->CreateTexture(m_size.x / 2, m_size.y * 2, 1,
  426. D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8,
  427. D3DPOOL_SYSTEMMEM, &m_tex, NULL);
  428. #endif
  429. m_shader = Shader::Create(lolfx_11_fractal);
  430. m_vertexattrib = m_shader->GetAttribLocation("a_Vertex", VertexUsage::Position, 0);
  431. m_texattrib = m_shader->GetAttribLocation("a_TexCoord", VertexUsage::TexCoord, 0);
  432. m_texeluni = m_shader->GetUniformLocation("u_TexelSize");
  433. m_screenuni = m_shader->GetUniformLocation("u_ScreenSize");
  434. m_zoomuni = m_shader->GetUniformLocation("u_ZoomSettings");
  435. m_vdecl =
  436. new VertexDeclaration(VertexStream<vec2>(VertexUsage::Position),
  437. VertexStream<vec2>(VertexUsage::TexCoord));
  438. m_vbo = new VertexBuffer(sizeof(vertices));
  439. m_tbo = new VertexBuffer(sizeof(texcoords));
  440. void *tmp = m_vbo->Lock(0, 0);
  441. memcpy(tmp, vertices, sizeof(vertices));
  442. m_vbo->Unlock();
  443. tmp = m_tbo->Lock(0, 0);
  444. memcpy(tmp, texcoords, sizeof(texcoords));
  445. m_tbo->Unlock();
  446. /* FIXME: this object never cleans up */
  447. m_ready = true;
  448. }
  449. #if defined _XBOX || defined USE_D3D9
  450. #else
  451. # if !defined HAVE_GLES_2X
  452. glEnable(GL_TEXTURE_2D);
  453. # endif
  454. glBindTexture(GL_TEXTURE_2D, m_texid);
  455. #endif
  456. if (m_dirty[m_frame])
  457. {
  458. for (int i = 0; i < m_size.y; i += MAX_LINES * 2)
  459. m_donequeue.Pop();
  460. m_dirty[m_frame]--;
  461. #if defined _XBOX || defined USE_D3D9
  462. D3DLOCKED_RECT rect;
  463. # if defined _XBOX
  464. m_tex->LockRect(0, &rect, NULL, D3DLOCK_NOOVERWRITE);
  465. # else
  466. m_tex->LockRect(0, &rect, NULL,
  467. D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE);
  468. # endif
  469. for (int j = 0; j < m_size.y * 2; j++)
  470. {
  471. u8vec4 *line = (u8vec4 *)rect.pBits + j * rect.Pitch / 4;
  472. for (int i = 0; i < m_size.x / 2; i++)
  473. line[i] = m_pixels[m_size.x / 2 * j + i];
  474. }
  475. m_tex->UnlockRect(0);
  476. #elif defined __CELLOS_LV2__
  477. /* glTexSubImage2D is extremely slow on the PS3, to the point
  478. * that uploading the whole texture is 40 times faster. */
  479. glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT,
  480. m_size.x / 2, m_size.y * 2, 0,
  481. TEXTURE_FORMAT, TEXTURE_TYPE, m_pixels);
  482. #else
  483. glTexSubImage2D(GL_TEXTURE_2D, 0, 0, m_frame * m_size.y / 2,
  484. m_size.x / 2, m_size.y / 2,
  485. TEXTURE_FORMAT, TEXTURE_TYPE,
  486. m_pixels + m_size.x * m_size.y / 4 * m_frame);
  487. #endif
  488. }
  489. m_shader->Bind();
  490. m_shader->SetUniform(m_texeluni, m_texel_settings);
  491. m_shader->SetUniform(m_screenuni, m_screen_settings);
  492. m_shader->SetUniform(m_zoomuni, m_zoom_settings);
  493. m_vdecl->Bind();
  494. m_vdecl->SetStream(m_vbo, m_vertexattrib);
  495. m_vdecl->SetStream(m_tbo, m_texattrib);
  496. #if defined _XBOX || defined USE_D3D9
  497. g_d3ddevice->SetTexture(0, m_tex);
  498. g_d3ddevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
  499. #elif !defined __CELLOS_LV2__ && !defined __ANDROID__
  500. #else
  501. #endif
  502. m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, 2);
  503. m_vdecl->Unbind();
  504. }
  505. private:
  506. static int const MAX_ITERATIONS = 340;
  507. static int const PALETTE_STEP = 32;
  508. static int const MAX_THREADS = 8;
  509. static int const MAX_LINES = 8;
  510. ivec2 m_size, m_window_size, m_oldmouse;
  511. double m_window2world;
  512. dvec2 m_texel2world;
  513. u8vec4 *m_pixels, *m_tmppixels, *m_palette;
  514. Shader *m_shader;
  515. ShaderAttrib m_vertexattrib, m_texattrib;
  516. ShaderUniform m_texeluni, m_screenuni, m_zoomuni;
  517. VertexDeclaration *m_vdecl;
  518. VertexBuffer *m_vbo, *m_tbo;
  519. #if defined USE_D3D9
  520. IDirect3DTexture9 *m_tex;
  521. #elif defined _XBOX
  522. D3DTexture *m_tex;
  523. #else
  524. GLuint m_texid;
  525. #endif
  526. int m_frame, m_slices, m_dirty[4];
  527. bool m_ready, m_drag;
  528. rcmplx m_deltashift[4], m_center, m_translate;
  529. real m_deltascale[4];
  530. double m_zoom_speed, m_radius;
  531. vec4 m_texel_settings, m_screen_settings;
  532. mat4 m_zoom_settings;
  533. /* Worker threads */
  534. Thread *m_threads[MAX_THREADS];
  535. Queue<int> m_spawnqueue, m_jobqueue, m_donequeue;
  536. /* Debug information */
  537. #if !defined __native_client__
  538. Text *m_centertext, *m_mousetext, *m_zoomtext;
  539. #endif
  540. };
  541. int main(int argc, char **argv)
  542. {
  543. Application app("Tutorial 3: Fractal", ivec2(640, 480), 60.0f);
  544. #if defined _MSC_VER && !defined _XBOX
  545. _chdir("..");
  546. #elif defined _WIN32 && !defined _XBOX
  547. _chdir("../..");
  548. #endif
  549. new DebugFps(5, 5);
  550. new Fractal(ivec2(640, 480));
  551. //new DebugRecord("fractalol.ogm", 60.0f);
  552. app.Run();
  553. return EXIT_SUCCESS;
  554. }