PageRenderTime 64ms CodeModel.GetById 11ms app.highlight 46ms RepoModel.GetById 1ms app.codeStats 0ms

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