PageRenderTime 88ms CodeModel.GetById 8ms app.highlight 72ms RepoModel.GetById 1ms app.codeStats 0ms

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