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

http://github.com/xbmc/xbmc · C++ · 486 lines · 403 code · 42 blank · 41 comment · 95 complexity · 0e7e9b3a4e7fa5b33555e358ba4fe2b5 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 <implicit.hh>
  25. #include <vector.hh>
  26. unsigned int Implicit::_width, Implicit::_height, Implicit::_length;
  27. unsigned int Implicit::_width1, Implicit::_height1, Implicit::_length1;
  28. Vector Implicit::_lbf;
  29. float Implicit::_cw;
  30. unsigned int Implicit::_cubeTable[256][17];
  31. bool Implicit::_crawlTable[256][6];
  32. #define WHL(X, Y, Z) (((X) * _height1 + (Y)) * _length1 + (Z))
  33. void Implicit::init(
  34. unsigned int width, unsigned int height, unsigned int length, float cw
  35. ) {
  36. _width = width;
  37. _height = height;
  38. _length = length;
  39. _width1 = width + 1;
  40. _height1 = height + 1;
  41. _length1 = length + 1;
  42. _lbf = Vector(width, height, length) * cw * -0.5;
  43. _cw = cw;
  44. static unsigned int ec[12][2] = {
  45. { 0, 1 }, { 0, 2 }, { 1, 3 }, { 2, 3 }, { 0, 4 }, { 1, 5 },
  46. { 2, 6 }, { 3, 7 }, { 4, 5 }, { 4, 6 }, { 5, 7 }, { 6, 7 }
  47. };
  48. static unsigned int next[8][12] = {
  49. {
  50. 1, 4, UINT_MAX, UINT_MAX,
  51. 0, UINT_MAX, UINT_MAX, UINT_MAX,
  52. UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX
  53. },
  54. {
  55. 5, UINT_MAX, 0, UINT_MAX,
  56. UINT_MAX, 2, UINT_MAX, UINT_MAX,
  57. UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX
  58. },
  59. {
  60. UINT_MAX, 3, UINT_MAX, 6,
  61. UINT_MAX, UINT_MAX, 1, UINT_MAX,
  62. UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX
  63. },
  64. {
  65. UINT_MAX, UINT_MAX, 7, 2,
  66. UINT_MAX, UINT_MAX, UINT_MAX, 3,
  67. UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX
  68. },
  69. {
  70. UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX,
  71. 9, UINT_MAX, UINT_MAX, UINT_MAX,
  72. 4, 8, UINT_MAX, UINT_MAX
  73. },
  74. {
  75. UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX,
  76. UINT_MAX, 8, UINT_MAX, UINT_MAX,
  77. 10, UINT_MAX, 5, UINT_MAX
  78. },
  79. {
  80. UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX,
  81. UINT_MAX, UINT_MAX, 11, UINT_MAX,
  82. UINT_MAX, 6, UINT_MAX, 9
  83. },
  84. {
  85. UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX,
  86. UINT_MAX, UINT_MAX, UINT_MAX, 10,
  87. UINT_MAX, UINT_MAX, 11, 7
  88. }
  89. };
  90. for (unsigned int i = 0; i < 256; ++i) {
  91. // impCubeTables::makeTriStripPatterns
  92. bool vertices[8]; // true if on low side of gradient (outside of surface)
  93. for (unsigned int j = 0; j < 8; ++j)
  94. vertices[j] = i & (1 << j);
  95. bool edges[12];
  96. bool edgesDone[12];
  97. for (unsigned int j = 0; j < 12; ++j) {
  98. edges[j] = vertices[ec[j][0]] ^ vertices[ec[j][1]];
  99. edgesDone[j] = false;
  100. }
  101. unsigned int totalCount = 0;
  102. // Construct lists of edges that form triangle strips
  103. // try starting from each edge (no need to try last 2 edges)
  104. for (unsigned int j = 0; j < 10; ++j) {
  105. unsigned int edgeList[7];
  106. unsigned int edgeCount = 0;
  107. for (
  108. unsigned int currentEdge = j;
  109. edges[currentEdge] && !edgesDone[currentEdge];
  110. ) {
  111. edgeList[edgeCount++] = currentEdge;
  112. edgesDone[currentEdge] = true;
  113. unsigned int currentVertex = vertices[ec[currentEdge][0]] ?
  114. ec[currentEdge][0] : ec[currentEdge][1];
  115. currentEdge = next[currentVertex][currentEdge];
  116. while (!edges[currentEdge]) {
  117. currentVertex = (currentVertex != ec[currentEdge][0]) ?
  118. ec[currentEdge][0] : ec[currentEdge][1];
  119. currentEdge = next[currentVertex][currentEdge];
  120. }
  121. }
  122. if (edgeCount) {
  123. _cubeTable[i][totalCount++] = edgeCount;
  124. switch (edgeCount) {
  125. case 3:
  126. _cubeTable[i][totalCount++] = edgeList[0];
  127. _cubeTable[i][totalCount++] = edgeList[1];
  128. _cubeTable[i][totalCount++] = edgeList[2];
  129. break;
  130. case 4:
  131. _cubeTable[i][totalCount++] = edgeList[0];
  132. _cubeTable[i][totalCount++] = edgeList[1];
  133. _cubeTable[i][totalCount++] = edgeList[3];
  134. _cubeTable[i][totalCount++] = edgeList[2];
  135. break;
  136. case 5:
  137. _cubeTable[i][totalCount++] = edgeList[0];
  138. _cubeTable[i][totalCount++] = edgeList[1];
  139. _cubeTable[i][totalCount++] = edgeList[4];
  140. _cubeTable[i][totalCount++] = edgeList[2];
  141. _cubeTable[i][totalCount++] = edgeList[3];
  142. break;
  143. case 6:
  144. _cubeTable[i][totalCount++] = edgeList[0];
  145. _cubeTable[i][totalCount++] = edgeList[1];
  146. _cubeTable[i][totalCount++] = edgeList[5];
  147. _cubeTable[i][totalCount++] = edgeList[2];
  148. _cubeTable[i][totalCount++] = edgeList[4];
  149. _cubeTable[i][totalCount++] = edgeList[3];
  150. break;
  151. case 7:
  152. _cubeTable[i][totalCount++] = edgeList[0];
  153. _cubeTable[i][totalCount++] = edgeList[1];
  154. _cubeTable[i][totalCount++] = edgeList[6];
  155. _cubeTable[i][totalCount++] = edgeList[2];
  156. _cubeTable[i][totalCount++] = edgeList[5];
  157. _cubeTable[i][totalCount++] = edgeList[3];
  158. _cubeTable[i][totalCount++] = edgeList[4];
  159. break;
  160. }
  161. _cubeTable[i][totalCount] = 0;
  162. }
  163. }
  164. // impCubeTables::makeCrawlDirections
  165. _crawlTable[i][0] = edges[0] || edges[1] || edges[2] || edges[3];
  166. _crawlTable[i][1] = edges[8] || edges[9] || edges[10] || edges[11];
  167. _crawlTable[i][2] = edges[0] || edges[4] || edges[5] || edges[8];
  168. _crawlTable[i][3] = edges[3] || edges[6] || edges[7] || edges[11];
  169. _crawlTable[i][4] = edges[1] || edges[4] || edges[6] || edges[9];
  170. _crawlTable[i][5] = edges[2] || edges[5] || edges[7] || edges[10];
  171. }
  172. }
  173. Implicit::Implicit(ImplicitField field) : _serial(0), _field(field) {
  174. stdx::construct_n(_info, _width1 * _height1 * _length1);
  175. for (unsigned int i = 0; i < _width1; ++i) {
  176. for (unsigned int j = 0; j < _height1; ++j) {
  177. for (unsigned int k = 0; k < _length1; ++k) {
  178. unsigned int xyz = WHL(i, j, k);
  179. _info[xyz].cube.serial = 0;
  180. _info[xyz].corner.serial = 0;
  181. _info[xyz].corner.XYZ = _lbf + Vector(i, j, k) * _cw;
  182. _info[xyz].edge[X_AXIS].serial = 0;
  183. _info[xyz].edge[Y_AXIS].serial = 0;
  184. _info[xyz].edge[Z_AXIS].serial = 0;
  185. }
  186. }
  187. }
  188. }
  189. void Implicit::update(float threshold, const CrawlPointVector& crawlPoints) {
  190. _threshold = threshold;
  191. ++_serial;
  192. _vertices.reset();
  193. _indices.reset();
  194. _lengths.reset();
  195. // crawl from every crawl point to create the surface
  196. CrawlPointVector::const_iterator e = crawlPoints.end();
  197. for (
  198. CrawlPointVector::const_iterator it = crawlPoints.begin();
  199. it != e;
  200. ++it
  201. ) {
  202. // find cube corresponding to crawl point
  203. Vector cube((*it - _lbf) / _cw);
  204. unsigned int x = Common::clamp((unsigned int)cube.x(), 0u, _width - 1);
  205. unsigned int y = Common::clamp((unsigned int)cube.y(), 0u, _height - 1);
  206. unsigned int z = Common::clamp((unsigned int)cube.z(), 0u, _length - 1);
  207. while (true) {
  208. unsigned int xyz = WHL(x, y, z);
  209. if (_info[xyz].cube.serial == _serial)
  210. break; // escape if a finished cube
  211. // find mask for this cube
  212. unsigned char mask = calculateCube(xyz);
  213. if (mask == 255)
  214. break; // escape if outside surface
  215. if (mask == 0) {
  216. // this cube is inside volume
  217. _info[xyz].cube.serial = _serial;
  218. if (--x < 0)
  219. break;
  220. } else {
  221. crawl(x, y, z);
  222. break;
  223. }
  224. }
  225. }
  226. }
  227. void Implicit::update(float threshold) {
  228. _threshold = threshold;
  229. ++_serial;
  230. _vertices.reset();
  231. _indices.reset();
  232. _lengths.reset();
  233. // find gradient value at every corner
  234. unsigned int xyz = 0;
  235. for (unsigned int i = 0; i < _width; ++i) {
  236. for (unsigned int j = 0; j < _height; ++j) {
  237. for (unsigned int k = 0; k < _length; ++k) {
  238. calculateCube(xyz);
  239. polygonize(xyz);
  240. ++xyz;
  241. }
  242. ++xyz;
  243. }
  244. xyz += _length1;
  245. }
  246. }
  247. #define LBF 0x01
  248. #define LBN 0x02
  249. #define LTF 0x04
  250. #define LTN 0x08
  251. #define RBF 0x10
  252. #define RBN 0x20
  253. #define RTF 0x40
  254. #define RTN 0x80
  255. unsigned char Implicit::calculateCube(unsigned int xyz) {
  256. unsigned char mask = 0;
  257. if (_info[xyz + WHL(0, 0, 0)].corner.serial != _serial) {
  258. _info[xyz + WHL(0, 0, 0)].corner.value = _field(_info[xyz + WHL(0, 0, 0)].corner.XYZ);
  259. _info[xyz + WHL(0, 0, 0)].corner.serial = _serial;
  260. }
  261. if (_info[xyz + WHL(0, 0, 0)].corner.value < _threshold)
  262. mask |= LBF;
  263. if (_info[xyz + WHL(0, 0, 1)].corner.serial != _serial) {
  264. _info[xyz + WHL(0, 0, 1)].corner.value = _field(_info[xyz + WHL(0, 0, 1)].corner.XYZ);
  265. _info[xyz + WHL(0, 0, 1)].corner.serial = _serial;
  266. }
  267. if (_info[xyz + WHL(0, 0, 1)].corner.value < _threshold)
  268. mask |= LBN;
  269. if (_info[xyz + WHL(0, 1, 0)].corner.serial != _serial) {
  270. _info[xyz + WHL(0, 1, 0)].corner.value = _field(_info[xyz + WHL(0, 1, 0)].corner.XYZ);
  271. _info[xyz + WHL(0, 1, 0)].corner.serial = _serial;
  272. }
  273. if (_info[xyz + WHL(0, 1, 0)].corner.value < _threshold)
  274. mask |= LTF;
  275. if (_info[xyz + WHL(0, 1, 1)].corner.serial != _serial) {
  276. _info[xyz + WHL(0, 1, 1)].corner.value = _field(_info[xyz + WHL(0, 1, 1)].corner.XYZ);
  277. _info[xyz + WHL(0, 1, 1)].corner.serial = _serial;
  278. }
  279. if (_info[xyz + WHL(0, 1, 1)].corner.value < _threshold)
  280. mask |= LTN;
  281. if (_info[xyz + WHL(1, 0, 0)].corner.serial != _serial) {
  282. _info[xyz + WHL(1, 0, 0)].corner.value = _field(_info[xyz + WHL(1, 0, 0)].corner.XYZ);
  283. _info[xyz + WHL(1, 0, 0)].corner.serial = _serial;
  284. }
  285. if (_info[xyz + WHL(1, 0, 0)].corner.value < _threshold)
  286. mask |= RBF;
  287. if (_info[xyz + WHL(1, 0, 1)].corner.serial != _serial) {
  288. _info[xyz + WHL(1, 0, 1)].corner.value = _field(_info[xyz + WHL(1, 0, 1)].corner.XYZ);
  289. _info[xyz + WHL(1, 0, 1)].corner.serial = _serial;
  290. }
  291. if (_info[xyz + WHL(1, 0, 1)].corner.value < _threshold)
  292. mask |= RBN;
  293. if (_info[xyz + WHL(1, 1, 0)].corner.serial != _serial) {
  294. _info[xyz + WHL(1, 1, 0)].corner.value = _field(_info[xyz + WHL(1, 1, 0)].corner.XYZ);
  295. _info[xyz + WHL(1, 1, 0)].corner.serial = _serial;
  296. }
  297. if (_info[xyz + WHL(1, 1, 0)].corner.value < _threshold)
  298. mask |= RTF;
  299. if (_info[xyz + WHL(1, 1, 1)].corner.serial != _serial) {
  300. _info[xyz + WHL(1, 1, 1)].corner.value = _field(_info[xyz + WHL(1, 1, 1)].corner.XYZ);
  301. _info[xyz + WHL(1, 1, 1)].corner.serial = _serial;
  302. }
  303. if (_info[xyz + WHL(1, 1, 1)].corner.value < _threshold)
  304. mask |= RTN;
  305. _info[xyz].cube.mask = mask;
  306. return mask;
  307. }
  308. void Implicit::crawl(unsigned int x, unsigned int y, unsigned int z) {
  309. unsigned int xyz = WHL(x, y, z);
  310. if (_info[xyz].cube.serial == _serial)
  311. return;
  312. unsigned char mask = calculateCube(xyz);
  313. if (mask == 0 || mask == 255)
  314. return;
  315. // polygonize this cube if it intersects surface
  316. polygonize(xyz);
  317. // mark this cube as completed
  318. _info[xyz].cube.serial = _serial;
  319. // polygonize adjacent cubes
  320. if (_crawlTable[mask][0] && x > 0)
  321. crawl(x - 1, y, z);
  322. if (_crawlTable[mask][1] && x < _width - 1)
  323. crawl(x + 1, y, z);
  324. if (_crawlTable[mask][2] && y > 0)
  325. crawl(x, y - 1, z);
  326. if (_crawlTable[mask][3] && y < _height - 1)
  327. crawl(x, y + 1, z);
  328. if (_crawlTable[mask][4] && z > 0)
  329. crawl(x, y, z - 1);
  330. if (_crawlTable[mask][5] && z < _length - 1)
  331. crawl(x, y, z + 1);
  332. }
  333. // polygonize an individual cube
  334. void Implicit::polygonize(unsigned int xyz) {
  335. unsigned char mask = _info[xyz].cube.mask;
  336. unsigned int counter = 0;
  337. unsigned int numEdges = _cubeTable[mask][counter];
  338. while (numEdges != 0) {
  339. _lengths.push_back(numEdges);
  340. for (unsigned int i = 0; i < numEdges; ++i) {
  341. // generate vertex position and normal data
  342. switch (_cubeTable[mask][i + counter + 1]) {
  343. case 0:
  344. addVertex(Z_AXIS, xyz + WHL(0, 0, 0));
  345. break;
  346. case 1:
  347. addVertex(Y_AXIS, xyz + WHL(0, 0, 0));
  348. break;
  349. case 2:
  350. addVertex(Y_AXIS, xyz + WHL(0, 0, 1));
  351. break;
  352. case 3:
  353. addVertex(Z_AXIS, xyz + WHL(0, 1, 0));
  354. break;
  355. case 4:
  356. addVertex(X_AXIS, xyz + WHL(0, 0, 0));
  357. break;
  358. case 5:
  359. addVertex(X_AXIS, xyz + WHL(0, 0, 1));
  360. break;
  361. case 6:
  362. addVertex(X_AXIS, xyz + WHL(0, 1, 0));
  363. break;
  364. case 7:
  365. addVertex(X_AXIS, xyz + WHL(0, 1, 1));
  366. break;
  367. case 8:
  368. addVertex(Z_AXIS, xyz + WHL(1, 0, 0));
  369. break;
  370. case 9:
  371. addVertex(Y_AXIS, xyz + WHL(1, 0, 0));
  372. break;
  373. case 10:
  374. addVertex(Y_AXIS, xyz + WHL(1, 0, 1));
  375. break;
  376. case 11:
  377. addVertex(Z_AXIS, xyz + WHL(1, 1, 0));
  378. break;
  379. }
  380. }
  381. counter += numEdges + 1;
  382. numEdges = _cubeTable[mask][counter];
  383. }
  384. }
  385. void Implicit::addVertex(Axis axis, unsigned int xyz) {
  386. const Info::Corner& corner = _info[xyz].corner;
  387. Info::Edge& edge = _info[xyz].edge[axis];
  388. if (edge.serial == _serial) {
  389. _indices.push_back(edge.index);
  390. return;
  391. }
  392. // find position of vertex along this edge
  393. edge.serial = _serial;
  394. _indices.push_back(edge.index = _vertices.size());
  395. struct VertexData data;
  396. switch (axis) {
  397. case X_AXIS:
  398. data.x = corner.XYZ.x() +
  399. _cw * ((_threshold - corner.value)
  400. / (_info[xyz + WHL(1, 0, 0)].corner.value - corner.value)),
  401. data.y = corner.XYZ.y();
  402. data.z = corner.XYZ.z();
  403. break;
  404. case 1: // y-axis
  405. data.x = corner.XYZ.x();
  406. data.y = corner.XYZ.y() +
  407. _cw * ((_threshold - corner.value)
  408. / (_info[xyz + WHL(0, 1, 0)].corner.value - corner.value));
  409. data.z = corner.XYZ.z();
  410. break;
  411. case 2: // z-axis
  412. data.x = corner.XYZ.x();
  413. data.y = corner.XYZ.y();
  414. data.z = corner.XYZ.z() +
  415. _cw * ((_threshold - corner.value)
  416. / (_info[xyz + WHL(0, 0, 1)].corner.value - corner.value));
  417. break;
  418. default:
  419. abort();
  420. }
  421. // find normal vector at vertex along this edge
  422. // first find normal vector origin value
  423. Vector pos(data.x, data.y, data.z);
  424. float no = _field(pos);
  425. // then find values at slight displacements and subtract
  426. data.nx = _field(pos - Vector(0.01f, 0.0f, 0.0f)) - no;
  427. data.ny = _field(pos - Vector(0.0f, 0.01f, 0.0f)) - no;
  428. data.nz = _field(pos - Vector(0.0f, 0.0f, 0.01f)) - no;
  429. float normalizer = 1.0f / std::sqrt(data.nx * data.nx + data.ny * data.ny + data.nz * data.nz);
  430. data.nx *= normalizer;
  431. data.ny *= normalizer;
  432. data.nz *= normalizer;
  433. // Add this vertex to surface
  434. _vertices.push_back(data);
  435. }
  436. void Implicit::draw(GLenum mode) const {
  437. glInterleavedArrays(GL_N3F_V3F, 0, _vertices.begin());
  438. LazyVector<unsigned int>::const_iterator index = _indices.begin();
  439. LazyVector<unsigned int>::const_iterator e = _lengths.end();
  440. for (LazyVector<unsigned int>::const_iterator it = _lengths.begin(); it < e; ++it) {
  441. glDrawElements(mode, *it, GL_UNSIGNED_INT, index);
  442. index += *it;
  443. }
  444. }