/xbmc/screensavers/rsxs-0.9/src/lattice/lattice.cc

http://github.com/xbmc/xbmc · C++ · 868 lines · 760 code · 64 blank · 44 comment · 77 complexity · 00f0ac88923ee0aa318e4860399ca151 MD5 · raw file

  1. /*
  2. * Really Slick XScreenSavers
  3. * Copyright (C) 2002-2006 Michael Chapman
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. *
  18. *****************************************************************************
  19. *
  20. * This is a Linux port of the Really Slick Screensavers,
  21. * Copyright (C) 2002 Terence M. Welsh, available from www.reallyslick.com
  22. */
  23. #include <common.hh>
  24. #include <camera.hh>
  25. #include <common.hh>
  26. #include <hack.hh>
  27. #include <lattice.hh>
  28. #include <resources.hh>
  29. #include <vector.hh>
  30. // Important: See XXX below
  31. #define LATSIZE 10u
  32. namespace Hack {
  33. unsigned int longitude = 16;
  34. unsigned int latitude = 8;
  35. float thickness = 50.0f;
  36. unsigned int density = 50;
  37. unsigned int depth = 4;
  38. float fov = 90.0;
  39. unsigned int pathRand = 7;
  40. float speed = 10.0f;
  41. LinkType linkType = UNKNOWN_LINKS;
  42. std::vector<Texture> textures;
  43. bool smooth = false;
  44. bool fog = true;
  45. bool widescreen = false;
  46. };
  47. namespace Hack {
  48. enum Arguments {
  49. ARG_LATITUDE = 1,
  50. ARG_LONGITUDE,
  51. ARG_THICKNESS,
  52. ARG_DENSITY,
  53. ARG_DEPTH,
  54. ARG_FOV,
  55. ARG_RANDOMNESS,
  56. ARG_SPEED,
  57. ARG_SHININESS,
  58. ARG_PLAIN,
  59. ARG_TEXTURE,
  60. ARG_SMOOTH = 0x100, ARG_NO_SMOOTH,
  61. ARG_FOG = 0x200, ARG_NO_FOG,
  62. ARG_WIDESCREEN = 0x300, ARG_NO_WIDESCREEN,
  63. ARG_INDUSTRIAL_TEXTURE = 0x400, ARG_CRYSTAL_TEXTURE,
  64. ARG_CHROME_TEXTURE, ARG_BRASS_TEXTURE,
  65. ARG_SHINY_TEXTURE, ARG_GHOSTLY_TEXTURE,
  66. ARG_CIRCUITS_TEXTURE, ARG_DOUGHNUTS_TEXTURE,
  67. ARG_RANDOM_TEXTURE,
  68. ARG_SOLID_LINKS = 0x500, ARG_TRANSLUCENT_LINKS, ARG_HOLLOW_LINKS,
  69. ARG_SPHEREMAP = 0x600, ARG_NO_SPHEREMAP,
  70. ARG_COLORED = 0x700, ARG_NO_COLORED,
  71. ARG_MODULATE = 0x800, ARG_NO_MODULATE
  72. };
  73. GLuint _lattice[LATSIZE][LATSIZE][LATSIZE];
  74. // Border points and direction vectors where camera can cross
  75. // from cube to cube
  76. const float _bPnt[][6] = {
  77. { 0.5f , -0.25f, 0.25f, 1.0f , 0.0f , 0.0f },
  78. { 0.5f , 0.25f, -0.25f, 1.0f , 0.0f , 0.0f },
  79. { -0.25f, 0.5f , 0.25f, 0.0f , 1.0f , 0.0f },
  80. { 0.25f, 0.5f , -0.25f, 0.0f , 1.0f , 0.0f },
  81. { -0.25f, -0.25f, 0.5f , 0.0f , 0.0f , 1.0f },
  82. { 0.25f, 0.25f, 0.5f , 0.0f , 0.0f , 1.0f },
  83. { 0.5f , -0.5f , -0.5f , 1.0f , -1.0f , -1.0f },
  84. { 0.5f , 0.5f , -0.5f , 1.0f , 1.0f , -1.0f },
  85. { 0.5f , -0.5f , 0.5f , 1.0f , -1.0f , 1.0f },
  86. { 0.5f , 0.5f , 0.5f , 1.0f , 1.0f , 1.0f }
  87. };
  88. float _path[7][6];
  89. const unsigned int _transitions[][6] = {
  90. { 1, 2, 12, 4, 14, 8 },
  91. { 0, 3, 15, 7, 7, 7 },
  92. { 3, 4, 14, 0, 7, 16 },
  93. { 2, 1, 15, 7, 7, 7 },
  94. { 5, 10, 12, 17, 17, 17 },
  95. { 4, 3, 13, 11, 9, 17 },
  96. { 12, 4, 10, 17, 17, 17 },
  97. { 2, 0, 14, 8, 16, 19 },
  98. { 1, 3, 15, 7, 7, 7 },
  99. { 4, 10, 12, 17, 17, 17 },
  100. { 11, 4, 12, 17, 17, 17 },
  101. { 10, 5, 15, 13, 17, 18 },
  102. { 13, 10, 4, 17, 17, 17 },
  103. { 12, 1, 11, 5, 6, 17 },
  104. { 15, 2, 12, 0, 7, 19 },
  105. { 14, 3, 1, 7, 7, 7 },
  106. { 3, 1, 15, 7, 7, 7 },
  107. { 5, 11, 13, 6, 9, 18 },
  108. { 10, 4, 12, 17, 17, 17 },
  109. { 15, 1, 3, 7, 7, 7 }
  110. };
  111. int _globalXYZ[3];
  112. unsigned int _lastBorder;
  113. unsigned int _segments;
  114. unsigned int latticeMod(int);
  115. float interpolate(float, float, float, float, float);
  116. void reconfigure();
  117. void setLinkType(LinkType);
  118. error_t parse(int, char*, struct argp_state*);
  119. };
  120. // Modulus function for picking the correct element of lattice array
  121. unsigned int Hack::latticeMod(int x) {
  122. if (x < 0)
  123. return (LATSIZE - (-x % LATSIZE)) % LATSIZE;
  124. else
  125. return x % LATSIZE;
  126. }
  127. // start point, start slope, end point, end slope, position (0.0 - 1.0)
  128. // returns point somewhere along a smooth curve between the start point
  129. // and end point
  130. float Hack::interpolate(float a, float b, float c, float d, float where) {
  131. float q = 2.0f * (a - c) + b + d;
  132. float r = 3.0f * (c - a) - 2.0f * b - d;
  133. return (where * where * where * q) + (where * where * r) + (where * b) + a;
  134. }
  135. void Hack::reconfigure() {
  136. // End of old path = start of new path
  137. for (unsigned int i = 0; i < 6; ++i)
  138. _path[0][i] = _path[_segments][i];
  139. // determine if direction of motion is positive or negative
  140. // update global position
  141. bool positive;
  142. if (_lastBorder < 6) {
  143. if ((_path[0][3] + _path[0][4] + _path[0][5]) > 0.0f) {
  144. positive = true;
  145. ++_globalXYZ[_lastBorder / 2];
  146. } else {
  147. positive = false;
  148. --_globalXYZ[_lastBorder / 2];
  149. }
  150. } else {
  151. if (_path[0][3] > 0.0f) {
  152. positive = true;
  153. ++_globalXYZ[0];
  154. } else {
  155. positive = false;
  156. --_globalXYZ[0];
  157. }
  158. if (_path[0][4] > 0.0f)
  159. ++_globalXYZ[1];
  160. else
  161. --_globalXYZ[1];
  162. if (_path[0][5] > 0.0f)
  163. ++_globalXYZ[2];
  164. else
  165. --_globalXYZ[2];
  166. }
  167. if (!Common::randomInt(11 - pathRand)) { // Change directions
  168. if (!positive)
  169. _lastBorder += 10;
  170. unsigned int newBorder = _transitions[_lastBorder][Common::randomInt(6)];
  171. positive = false;
  172. if (newBorder < 10)
  173. positive = true;
  174. else
  175. newBorder -= 10;
  176. for (unsigned int i = 0; i < 6; ++i) // set the new border point
  177. _path[1][i] = _bPnt[newBorder][i];
  178. if (!positive) { // flip everything if direction is negative
  179. if (newBorder < 6)
  180. _path[1][newBorder / 2] *= -1.0f;
  181. else
  182. for (unsigned int i = 0; i < 3; ++i)
  183. _path[1][i] *= -1.0f;
  184. for (unsigned int i = 3; i < 6; ++i)
  185. _path[1][i] *= -1.0f;
  186. }
  187. for (unsigned int i = 0; i < 3; ++i) // reposition the new border
  188. _path[1][i] += _globalXYZ[i];
  189. _lastBorder = newBorder;
  190. _segments = 1;
  191. } else { // Just keep going straight
  192. unsigned int newBorder = _lastBorder;
  193. for (unsigned int i = 0; i < 6; ++i)
  194. _path[1][i] = _bPnt[newBorder][i];
  195. unsigned int i = newBorder / 2;
  196. if (!positive) {
  197. if (newBorder < 6)
  198. _path[1][i] *= -1.0f;
  199. else {
  200. _path[1][0] *= -1.0f;
  201. _path[1][1] *= -1.0f;
  202. _path[1][2] *= -1.0f;
  203. }
  204. _path[1][3] *= -1.0f;
  205. _path[1][4] *= -1.0f;
  206. _path[1][5] *= -1.0f;
  207. }
  208. for (unsigned int j = 0; j < 3; ++j) {
  209. _path[1][j] += _globalXYZ[j];
  210. if ((newBorder < 6) && (j != 1))
  211. _path[1][j] += Common::randomFloat(0.15f) - 0.075f;
  212. }
  213. if (newBorder >= 6)
  214. _path[1][0] += Common::randomFloat(0.1f) - 0.05f;
  215. _segments = 1;
  216. }
  217. }
  218. void Hack::setLinkType(LinkType lt) {
  219. if (linkType == lt)
  220. return;
  221. if (linkType != UNKNOWN_LINKS) {
  222. static char* linkTypeOption[3] = { "--solid", "--translucent", "--hollow" };
  223. WARN("Overriding " << linkTypeOption[linkType] << " with " <<
  224. linkTypeOption[lt]);
  225. }
  226. linkType = lt;
  227. }
  228. error_t Hack::parse(int key, char* arg, struct argp_state* state) {
  229. static float shininess = 50.0f;
  230. static bool sphereMap = false;
  231. static bool colored = true;
  232. static bool modulate = true;
  233. retry:
  234. switch (key) {
  235. case ARG_LATITUDE:
  236. if (Common::parseArg(arg, latitude, 2u, 100u))
  237. argp_failure(state, EXIT_FAILURE, 0,
  238. "latitudinal divisions must be between 2 and 100");
  239. return 0;
  240. case ARG_LONGITUDE:
  241. if (Common::parseArg(arg, longitude, 4u, 100u))
  242. argp_failure(state, EXIT_FAILURE, 0,
  243. "longitudinal divisions must be between 4 and 100");
  244. return 0;
  245. case ARG_THICKNESS:
  246. if (Common::parseArg(arg, thickness, 1.0f, 100.0f))
  247. argp_failure(state, EXIT_FAILURE, 0,
  248. "torus thickness must be between 1 and 100");
  249. return 0;
  250. case ARG_DENSITY:
  251. if (Common::parseArg(arg, density, 1u, 100u))
  252. argp_failure(state, EXIT_FAILURE, 0,
  253. "lattice density must be between 1 and 100");
  254. return 0;
  255. case ARG_DEPTH:
  256. if (Common::parseArg(arg, depth, 1u, LATSIZE - 2))
  257. argp_failure(state, EXIT_FAILURE, 0,
  258. "lattice depth must be between 1 and %d", LATSIZE - 2);
  259. return 0;
  260. case ARG_FOV:
  261. if (Common::parseArg(arg, fov, 10.0f, 150.0f))
  262. argp_failure(state, EXIT_FAILURE, 0,
  263. "field of view must be between 10 and 150");
  264. return 0;
  265. case ARG_RANDOMNESS:
  266. if (Common::parseArg(arg, pathRand, 1u, 10u))
  267. argp_failure(state, EXIT_FAILURE, 0,
  268. "path randomness must be between 1 and 10");
  269. return 0;
  270. case ARG_SPEED:
  271. speed = std::strtod(arg, NULL);
  272. if (speed < 1.0f || speed > 100.0f)
  273. argp_failure(state, EXIT_FAILURE, 0,
  274. "camera speed must be between 1 and 100");
  275. return 0;
  276. case ARG_SHININESS:
  277. if (Common::parseArg(arg, shininess, 0.0f, 128.0f, -1.0f))
  278. argp_failure(state, EXIT_FAILURE, 0,
  279. "shininess must be -1 (to disable lighting), or between 0 and 128");
  280. return 0;
  281. case ARG_PLAIN:
  282. {
  283. Texture texture = { "", shininess, sphereMap, colored, modulate };
  284. textures.push_back(texture);
  285. }
  286. return 0;
  287. case ARG_TEXTURE:
  288. {
  289. Texture texture = { arg, shininess, sphereMap, colored, modulate };
  290. textures.push_back(texture);
  291. }
  292. return 0;
  293. case ARG_SMOOTH:
  294. smooth = true;
  295. return 0;
  296. case ARG_NO_SMOOTH:
  297. smooth = false;
  298. return 0;
  299. case ARG_FOG:
  300. fog = true;
  301. return 0;
  302. case ARG_NO_FOG:
  303. fog = false;
  304. return 0;
  305. case ARG_WIDESCREEN:
  306. widescreen = true;
  307. return 0;
  308. case ARG_NO_WIDESCREEN:
  309. widescreen = false;
  310. return 0;
  311. case ARG_INDUSTRIAL_TEXTURE:
  312. setLinkType(SOLID_LINKS);
  313. shininess = 0.0f;
  314. sphereMap = false;
  315. colored = false;
  316. modulate = true;
  317. {
  318. Texture texture = { "industrial1.png",
  319. shininess, sphereMap, colored, modulate };
  320. textures.push_back(texture);
  321. }
  322. {
  323. Texture texture = { "industrial2.png",
  324. shininess, sphereMap, colored, modulate };
  325. textures.push_back(texture);
  326. }
  327. return 0;
  328. case ARG_CRYSTAL_TEXTURE:
  329. setLinkType(TRANSLUCENT_LINKS);
  330. shininess = 10.0f;
  331. sphereMap = true;
  332. colored = false;
  333. modulate = true;
  334. {
  335. Texture texture = { "crystal.png",
  336. shininess, sphereMap, colored, modulate };
  337. textures.push_back(texture);
  338. }
  339. return 0;
  340. case ARG_CHROME_TEXTURE:
  341. setLinkType(SOLID_LINKS);
  342. shininess = -1.0f;
  343. sphereMap = true;
  344. colored = false;
  345. modulate = true;
  346. {
  347. Texture texture = { "chrome.png",
  348. shininess, sphereMap, colored, modulate };
  349. textures.push_back(texture);
  350. }
  351. return 0;
  352. case ARG_BRASS_TEXTURE:
  353. setLinkType(SOLID_LINKS);
  354. shininess = -1.0f;
  355. sphereMap = true;
  356. colored = false;
  357. modulate = true;
  358. {
  359. Texture texture = { "brass.png",
  360. shininess, sphereMap, colored, modulate };
  361. textures.push_back(texture);
  362. }
  363. return 0;
  364. case ARG_SHINY_TEXTURE:
  365. setLinkType(SOLID_LINKS);
  366. shininess = 50.0f;
  367. sphereMap = true;
  368. colored = true;
  369. modulate = false;
  370. {
  371. Texture texture = { "shiny.png",
  372. shininess, sphereMap, colored, modulate };
  373. textures.push_back(texture);
  374. }
  375. return 0;
  376. case ARG_GHOSTLY_TEXTURE:
  377. setLinkType(TRANSLUCENT_LINKS);
  378. shininess = -1.0f;
  379. sphereMap = true;
  380. colored = true;
  381. modulate = true;
  382. {
  383. Texture texture = { "ghostly.png",
  384. shininess, sphereMap, colored, modulate };
  385. textures.push_back(texture);
  386. }
  387. return 0;
  388. case ARG_CIRCUITS_TEXTURE:
  389. setLinkType(HOLLOW_LINKS);
  390. shininess = 50.0f;
  391. sphereMap = false;
  392. colored = true;
  393. modulate = true;
  394. {
  395. Texture texture = { "circuits.png",
  396. shininess, sphereMap, colored, modulate };
  397. textures.push_back(texture);
  398. }
  399. return 0;
  400. case ARG_DOUGHNUTS_TEXTURE:
  401. setLinkType(SOLID_LINKS);
  402. shininess = 50.0f;
  403. sphereMap = false;
  404. colored = true;
  405. modulate = false;
  406. {
  407. Texture texture = { "doughnuts.png",
  408. shininess, sphereMap, colored, modulate };
  409. textures.push_back(texture);
  410. }
  411. return 0;
  412. case ARG_RANDOM_TEXTURE:
  413. key = Common::randomInt(8) + ARG_INDUSTRIAL_TEXTURE;
  414. goto retry;
  415. case ARG_SOLID_LINKS:
  416. setLinkType(SOLID_LINKS);
  417. return 0;
  418. case ARG_TRANSLUCENT_LINKS:
  419. setLinkType(TRANSLUCENT_LINKS);
  420. return 0;
  421. case ARG_HOLLOW_LINKS:
  422. setLinkType(HOLLOW_LINKS);
  423. return 0;
  424. case ARG_SPHEREMAP:
  425. sphereMap = true;
  426. return 0;
  427. case ARG_NO_SPHEREMAP:
  428. sphereMap = false;
  429. return 0;
  430. case ARG_COLORED:
  431. colored = true;
  432. return 0;
  433. case ARG_NO_COLORED:
  434. colored = false;
  435. return 0;
  436. case ARG_MODULATE:
  437. modulate = true;
  438. return 0;
  439. case ARG_NO_MODULATE:
  440. modulate = false;
  441. return 0;
  442. case ARGP_KEY_FINI:
  443. if (linkType == UNKNOWN_LINKS)
  444. linkType = SOLID_LINKS;
  445. if (textures.empty()) {
  446. Texture texture = { "", shininess, sphereMap, colored, modulate };
  447. textures.push_back(texture);
  448. }
  449. default:
  450. return ARGP_ERR_UNKNOWN;
  451. }
  452. }
  453. const struct argp* Hack::getParser() {
  454. static struct argp_option options[] = {
  455. { NULL, 0, NULL, 0, "Lattice options:" },
  456. { "density", ARG_DENSITY, "NUM", 0, "Lattice density (1-100, default = 50)" },
  457. // XXX 8 = LATSIZE - 2
  458. { "depth", ARG_DEPTH, "NUM", 0, "Lattice depth (1-8, default = 4)" },
  459. { "fog", ARG_FOG, NULL, OPTION_HIDDEN, "Disable depth fogging" },
  460. { "no-fog", ARG_NO_FOG, NULL, OPTION_ALIAS },
  461. { NULL, 0, NULL, 0, "Torus options:" },
  462. { "latitude", ARG_LATITUDE, "NUM", 0,
  463. "Latitudinal divisions on each torus (2-100, default = 8)" },
  464. { "longitude", ARG_LONGITUDE, "NUM", 0,
  465. "Longitudinal divisions on each torus (4-100, default = 16)" },
  466. { "thickness", ARG_THICKNESS, "NUM", 0,
  467. "Thickness of each torus (1-100, default = 50)" },
  468. { "smooth", ARG_SMOOTH, NULL, 0, "Enable smooth shading" },
  469. { "no-smooth", ARG_NO_SMOOTH, NULL, OPTION_ALIAS | OPTION_HIDDEN },
  470. { NULL, 0, NULL, 0, "Rendering options:" },
  471. { "solid", ARG_SOLID_LINKS, NULL, 0,
  472. "Surface rendering mode (default = solid)" },
  473. { "translucent", ARG_TRANSLUCENT_LINKS, NULL, OPTION_ALIAS },
  474. { "hollow", ARG_HOLLOW_LINKS, NULL, OPTION_ALIAS },
  475. { "These options define the global rendering scheme for the surfaces of the"
  476. " toruses. If more than one of these options are specified, the last"
  477. " will take precedence.", 0, NULL, OPTION_DOC | OPTION_NO_USAGE },
  478. { NULL, 0, NULL, 0, "Surface options:" },
  479. { "shininess", ARG_SHININESS, "NUM", 0,
  480. "Degree of specular reflection (0-128, -1 to disable lighting, default"
  481. " = 50)" },
  482. { "spheremap", ARG_SPHEREMAP, NULL, 0,
  483. "Enable environment mapping of surface texture" },
  484. { "no-spheremap", ARG_NO_SPHEREMAP, NULL, OPTION_ALIAS | OPTION_HIDDEN },
  485. { "colored", ARG_COLORED, NULL, 0,
  486. "Colorize (or whiten) the surfaces (default = colored)" },
  487. { "white", ARG_NO_COLORED, NULL, OPTION_ALIAS },
  488. { "no-colored", ARG_NO_COLORED, NULL, OPTION_ALIAS | OPTION_HIDDEN },
  489. { "no-white", ARG_COLORED, NULL, OPTION_ALIAS | OPTION_HIDDEN },
  490. { "modulate", ARG_MODULATE, NULL, 0,
  491. "Modulate the surface color with the texture, or paste the texture over"
  492. " the color as a decal (default = modulate)" },
  493. { "decal", ARG_NO_MODULATE, NULL, OPTION_ALIAS },
  494. { "no-modulate", ARG_NO_MODULATE, NULL, OPTION_ALIAS | OPTION_HIDDEN },
  495. { "no-decal", ARG_MODULATE, NULL, OPTION_ALIAS | OPTION_HIDDEN },
  496. { NULL, 0, NULL, 0, "" },
  497. { "plain", ARG_PLAIN, NULL, 0, "Plain surface" },
  498. { "texture", ARG_TEXTURE, "FILE", 0, "PNG image surface" },
  499. { "Any of these options may be specified multiple times. Each --plain and"
  500. " --texture option defines a group of toruses that are rendered in the"
  501. " same manner. Any --shininess, --solid, --translucent, --hollow and"
  502. " --spheremap options must precede the --plain or --texture they are"
  503. " to affect.", 0, NULL, OPTION_DOC | OPTION_NO_USAGE },
  504. { NULL, 0, NULL, 0, "Predefined surfaces:" },
  505. { "random", ARG_RANDOM_TEXTURE, NULL, 0,
  506. "Randomly choose a predefined surface" },
  507. { NULL, 0, NULL, 0, "" },
  508. { "industrial", ARG_INDUSTRIAL_TEXTURE, NULL, 0 },
  509. { "crystal", ARG_CRYSTAL_TEXTURE, NULL, 0 },
  510. { "chrome", ARG_CHROME_TEXTURE, NULL, 0 },
  511. { "brass", ARG_BRASS_TEXTURE, NULL, 0 },
  512. { "shiny", ARG_SHINY_TEXTURE, NULL, 0 },
  513. { "ghostly", ARG_GHOSTLY_TEXTURE, NULL, 0 },
  514. { "circuits", ARG_CIRCUITS_TEXTURE, NULL, 0 },
  515. { "donuts", ARG_DOUGHNUTS_TEXTURE, NULL, 0 },
  516. { "doughnuts", ARG_DOUGHNUTS_TEXTURE, NULL, OPTION_ALIAS | OPTION_HIDDEN },
  517. { "Each of these selects one of the rendering options (--solid,"
  518. " --translucent, and --hollow) and defines one or more torus groups.",
  519. 0, NULL, OPTION_DOC | OPTION_NO_USAGE },
  520. { NULL, 0, NULL, 0, "View options:" },
  521. { "fov", ARG_FOV, "NUM", 0, "Field of view (10-150, default = 90)" },
  522. { "randomness", ARG_RANDOMNESS, "NUM", 0,
  523. "Path randomness (1-10, default = 7)" },
  524. { "speed", ARG_SPEED, "NUM", 0, "Camera speed (1-100, default = 10)" },
  525. { "widescreen", ARG_WIDESCREEN, NULL, 0, "Enable widescreen view" },
  526. { "no-widescreen", ARG_NO_WIDESCREEN, NULL, OPTION_ALIAS | OPTION_HIDDEN },
  527. {}
  528. };
  529. static struct argp parser = {
  530. options, parse, NULL,
  531. "Fly through an infinite lattice of interlocking rings."
  532. };
  533. return &parser;
  534. }
  535. std::string Hack::getShortName() { return "lattice"; }
  536. std::string Hack::getName() { return "Lattice"; }
  537. void Hack::start() {
  538. if (widescreen)
  539. glViewport(
  540. 0, Common::height / 2 - Common::width / 4,
  541. Common::width, Common::width / 2
  542. );
  543. else
  544. glViewport(0, 0, Common::width, Common::height);
  545. Resources::init();
  546. glFrontFace(GL_CCW);
  547. glEnable(GL_CULL_FACE);
  548. glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  549. glMatrixMode(GL_PROJECTION);
  550. glLoadIdentity();
  551. float mat[16] = {
  552. std::cos(fov * 0.5f * D2R) / std::sin(fov * 0.5f * D2R), 0.0f, 0.0f, 0.0f,
  553. 0.0f, 0.0, 0.0f, 0.0f,
  554. 0.0f, 0.0f, -1.0f - 0.02f / float(depth), -1.0f,
  555. 0.0f, 0.0f, -(0.02f + 0.0002f / float(depth)), 0.0f
  556. };
  557. if (widescreen)
  558. mat[5] = mat[0] * 2.0f;
  559. else
  560. mat[5] = mat[0] * Common::aspectRatio;
  561. glLoadMatrixf(mat);
  562. Camera::set(mat, float(depth));
  563. glMatrixMode(GL_MODELVIEW);
  564. glLoadIdentity();
  565. if (fog) {
  566. glEnable(GL_FOG);
  567. float fog_color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
  568. glFogfv(GL_FOG_COLOR, fog_color);
  569. glFogf(GL_FOG_MODE, GL_LINEAR);
  570. glFogf(GL_FOG_START, float(depth) * 0.3f);
  571. glFogf(GL_FOG_END, float(depth) - 0.1f);
  572. }
  573. // Initialize lattice objects and their positions in the lattice array
  574. for (unsigned int i = 0; i < LATSIZE; ++i)
  575. for (unsigned int j = 0; j < LATSIZE; ++j)
  576. for (unsigned int k = 0; k < LATSIZE; ++k)
  577. _lattice[i][j][k] = Resources::lists + Common::randomInt(NUMOBJECTS);
  578. _globalXYZ[0] = 0;
  579. _globalXYZ[1] = 0;
  580. _globalXYZ[2] = 0;
  581. // Set up first path section
  582. _path[0][0] = 0.0f;
  583. _path[0][1] = 0.0f;
  584. _path[0][2] = 0.0f;
  585. _path[0][3] = 0.0f;
  586. _path[0][4] = 0.0f;
  587. _path[0][5] = 0.0f;
  588. unsigned int j = Common::randomInt(12);
  589. unsigned int k = j % 6;
  590. for (unsigned int i = 0; i < 6; ++i)
  591. _path[1][i] = _bPnt[k][i];
  592. if (j > 5) { // If we want to head in a negative direction
  593. unsigned int i = k / 2; // then we need to flip along the appropriate axis
  594. _path[1][i] *= -1.0f;
  595. _path[1][i + 3] *= -1.0f;
  596. }
  597. _lastBorder = k;
  598. _segments = 1;
  599. }
  600. void Hack::tick() {
  601. static float where = 0.0f; // Position on path
  602. static unsigned int seg = 0; // Section of path
  603. where += speed * 0.05f * Common::elapsedSecs;
  604. if (where >= 1.0f) {
  605. where -= 1.0f;
  606. seg++;
  607. }
  608. if (seg >= _segments) {
  609. seg = 0;
  610. reconfigure();
  611. }
  612. static Vector oldXYZ(0.0f, 0.0f, 0.0f);
  613. static UnitVector oldDir(Vector(0.0f, 0.0f, -1.0f));
  614. static Vector oldAngVel(0.0f, 0.0f, 0.0f);
  615. // Calculate position
  616. Vector XYZ(
  617. interpolate(_path[seg][0], _path[seg][3],
  618. _path[seg + 1][0], _path[seg + 1][3], where),
  619. interpolate(_path[seg][1], _path[seg][4],
  620. _path[seg + 1][1], _path[seg + 1][4], where),
  621. interpolate(_path[seg][2], _path[seg][5],
  622. _path[seg + 1][2], _path[seg + 1][5], where)
  623. );
  624. static float maxSpin = 0.0025f * speed;
  625. static float rotationInertia = 0.007f * speed;
  626. // Do rotation stuff
  627. UnitVector dir(XYZ - oldXYZ); // Direction of motion
  628. Vector angVel(Vector::cross(dir, oldDir)); // Desired axis of rotation
  629. float temp = Vector::dot(oldDir, dir);
  630. if (temp < -1.0f) temp = -1.0f;
  631. if (temp > +1.0f) temp = +1.0f;
  632. float angle = Common::clamp(
  633. float(std::acos(temp)), // Desired turn angle
  634. -maxSpin, maxSpin
  635. );
  636. angVel *= angle; // Desired angular velocity
  637. Vector tempVec(angVel - oldAngVel); // Change in angular velocity
  638. // Don't let angular velocity change too much
  639. float distance = tempVec.length();
  640. if (distance > rotationInertia * Common::elapsedSecs) {
  641. tempVec *= (rotationInertia * Common::elapsedSecs) / distance;
  642. angVel = oldAngVel + tempVec;
  643. }
  644. static float flymodeChange = 20.0f;
  645. static int flymode = 1;
  646. flymodeChange -= Common::elapsedSecs;
  647. if (flymodeChange <= 1.0f) // prepare to transition
  648. angVel *= flymodeChange;
  649. if (flymodeChange <= 0.0f) { // transition from one fly mode to the other?
  650. flymode = Common::randomInt(4);
  651. flymodeChange = Common::randomFloat(float(150 - speed)) + 5.0f;
  652. }
  653. tempVec = angVel; // Recompute desired rotation
  654. angle = tempVec.normalize();
  655. static UnitQuat quat;
  656. if (flymode) // fly normal (straight)
  657. quat.multiplyBy(UnitQuat(angle, tempVec));
  658. else // don't fly normal (go backwards and stuff)
  659. quat.preMultiplyBy(UnitQuat(angle, tempVec));
  660. // Roll
  661. static float rollChange = Common::randomFloat(10.0f) + 2.0f;
  662. static float rollAcc = 0.0f;
  663. static float rollVel = 0.0f;
  664. rollChange -= Common::elapsedSecs;
  665. if (rollChange <= 0.0f) {
  666. rollAcc = Common::randomFloat(0.02f * speed) - (0.01f * speed);
  667. rollChange = Common::randomFloat(10.0f) + 2.0f;
  668. }
  669. rollVel += rollAcc * Common::elapsedSecs;
  670. if (rollVel > (0.04f * speed) && rollAcc > 0.0f)
  671. rollAcc = 0.0f;
  672. if (rollVel < (-0.04f * speed) && rollAcc < 0.0f)
  673. rollAcc = 0.0f;
  674. quat.multiplyBy(UnitQuat(rollVel * Common::elapsedSecs, oldDir));
  675. RotationMatrix rotMat(quat);
  676. // Save old stuff
  677. oldXYZ = XYZ;
  678. oldDir = Vector(
  679. -rotMat.get()[2],
  680. -rotMat.get()[6],
  681. -rotMat.get()[10]
  682. );
  683. oldAngVel = angVel;
  684. // Apply transformations
  685. glLoadMatrixf(rotMat.get());
  686. glTranslatef(-XYZ.x(), -XYZ.y(), -XYZ.z());
  687. // Render everything
  688. static int drawDepth = depth + 2;
  689. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  690. for (int i = _globalXYZ[0] - drawDepth;
  691. i <= _globalXYZ[0] + drawDepth; ++i) {
  692. for (int j = _globalXYZ[1] - drawDepth;
  693. j <= _globalXYZ[1] + drawDepth; ++j) {
  694. for (int k = _globalXYZ[2] - drawDepth;
  695. k <= _globalXYZ[2] + drawDepth; ++k) {
  696. Vector tempVec(Vector(i, j, k) - XYZ);
  697. // transformed position
  698. Vector tPos(rotMat.transform(tempVec));
  699. if (Camera::isVisible(tPos, 0.9f)) {
  700. unsigned int indexX = latticeMod(i);
  701. unsigned int indexY = latticeMod(j);
  702. unsigned int indexZ = latticeMod(k);
  703. // draw it
  704. glPushMatrix();
  705. glTranslatef(float(i), float(j), float(k));
  706. glCallList(_lattice[indexX][indexY][indexZ]);
  707. glPopMatrix();
  708. }
  709. }
  710. }
  711. }
  712. Common::flush();
  713. }
  714. void Hack::reshape() {
  715. if (widescreen)
  716. glViewport(0, Common::height / 2 - Common::width / 4,
  717. Common::width, Common::width / 2);
  718. else
  719. glViewport(0, 0, Common::width, Common::height);
  720. glMatrixMode(GL_PROJECTION);
  721. glLoadIdentity();
  722. float mat[16] = {
  723. std::cos(fov * 0.5f * D2R) / std::sin(fov * 0.5f * D2R), 0.0f, 0.0f, 0.0f,
  724. 0.0f, 0.0, 0.0f, 0.0f,
  725. 0.0f, 0.0f, -1.0f - 0.02f / float(depth), -1.0f,
  726. 0.0f, 0.0f, -(0.02f + 0.0002f / float(depth)), 0.0f
  727. };
  728. if (widescreen)
  729. mat[5] = mat[0] * 2.0f;
  730. else
  731. mat[5] = mat[0] * Common::aspectRatio;
  732. glLoadMatrixf(mat);
  733. Camera::set(mat, float(depth));
  734. glMatrixMode(GL_MODELVIEW);
  735. }
  736. void Hack::stop() {}
  737. void Hack::keyPress(char c, const KeySym&) {
  738. switch (c) {
  739. case 3: case 27:
  740. case 'q': case 'Q':
  741. Common::running = false;
  742. break;
  743. }
  744. }
  745. void Hack::keyRelease(char, const KeySym&) {}
  746. void Hack::pointerMotion(int, int) {}
  747. void Hack::buttonPress(unsigned int) {}
  748. void Hack::buttonRelease(unsigned int) {}
  749. void Hack::pointerEnter() {}
  750. void Hack::pointerLeave() {}
  751. #define _LINUX
  752. #include "../../../addons/include/xbmc_scr_dll.h"
  753. extern "C" {
  754. ADDON_STATUS Create(void* hdl, void* props)
  755. {
  756. if (!props)
  757. return STATUS_UNKNOWN;
  758. SCR_PROPS* scrprops = (SCR_PROPS*)props;
  759. Common::width = scrprops->width;
  760. Common::height = scrprops->height;
  761. Common::aspectRatio = float(Common::width) / float(Common::height);
  762. return STATUS_OK;
  763. }
  764. void Start()
  765. {
  766. Hack::start();
  767. }
  768. void Render()
  769. {
  770. Hack::tick();
  771. }
  772. void Stop()
  773. {
  774. Hack::stop();
  775. }
  776. void Destroy()
  777. {
  778. }
  779. ADDON_STATUS GetStatus()
  780. {
  781. return STATUS_OK;
  782. }
  783. bool HasSettings()
  784. {
  785. return false;
  786. }
  787. unsigned int GetSettings(StructSetting ***sSet)
  788. {
  789. return 0;
  790. }
  791. ADDON_STATUS SetSetting(const char *settingName, const void *settingValue)
  792. {
  793. return STATUS_OK;
  794. }
  795. void FreeSettings()
  796. {
  797. }
  798. void GetInfo(SCR_INFO *info)
  799. {
  800. }
  801. void Remove()
  802. {
  803. }
  804. }