PageRenderTime 83ms CodeModel.GetById 11ms app.highlight 68ms RepoModel.GetById 1ms app.codeStats 0ms

/xbmc/screensavers/rsxs-0.9/src/hyperspace/caustic.cc

http://github.com/xbmc/xbmc
C++ | 311 lines | 236 code | 33 blank | 42 comment | 29 complexity | e001bfff2b59a4ae24cf7ed2b94dc69b 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 FoundAT2on.
  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 * FoundAT2on, 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) 2005 Terence M. Welsh, available from www.reallyslick.com
 22 */
 23#include <common.hh>
 24
 25#include <caustic.hh>
 26#include <hyperspace.hh>
 27
 28#define CAUSTIC_RESOLUTION 100
 29#define CAUSTIC_SIZE       256
 30#define CAUSTIC_DEPTH      1.0f
 31#define CAUSTIC_AMPLITUDE  0.01f
 32#define CAUSTIC_REFRACTION 20.0f
 33
 34namespace CausticTextures {
 35	std::vector<GLuint> _textures;
 36
 37	void draw(
 38		const stdx::dim2<float, CAUSTIC_RESOLUTION + 1>&,
 39		const float*, const float*,
 40		const stdx::dim2<std::pair<float, float>, CAUSTIC_RESOLUTION + 1>&,
 41		unsigned int, unsigned int, unsigned int, unsigned int
 42	);
 43};
 44
 45void CausticTextures::init() {
 46	unsigned int size = CAUSTIC_SIZE;
 47	if (Common::width < size)  size = Common::width;
 48	if (Common::height < size) size = Common::height;
 49
 50	float x[CAUSTIC_RESOLUTION + 1];
 51	float z[CAUSTIC_RESOLUTION + 1];
 52
 53	stdx::dim2<float, CAUSTIC_RESOLUTION> y[Hack::frames];
 54	for (unsigned int i = 0; i < Hack::frames; ++i)
 55		y[i].resize(CAUSTIC_RESOLUTION);
 56	stdx::dim2<std::pair<float, float>, CAUSTIC_RESOLUTION + 1> xz(CAUSTIC_RESOLUTION + 1);
 57	stdx::dim2<float, CAUSTIC_RESOLUTION + 1> intensity(CAUSTIC_RESOLUTION + 1);
 58
 59	// set x and z geometry positions
 60	for (unsigned int i = 0; i <= CAUSTIC_RESOLUTION; ++i) {
 61		x[i] = z[i] = float(i) / float(CAUSTIC_RESOLUTION);
 62	}
 63
 64	// set y geometry positions (altitudes)
 65	for (unsigned int k = 0; k < Hack::frames; ++k) {
 66		float offset = M_PI * 2.0f * float(k) / float(Hack::frames);
 67		for (unsigned int i = 0; i < CAUSTIC_RESOLUTION; ++i) {
 68			float xx = M_PI * 2.0f * float(i) / float(CAUSTIC_RESOLUTION);
 69			for (unsigned int j = 0; j < CAUSTIC_RESOLUTION; ++j) {
 70				float zz = M_PI * 2.0f * float(j) / float(CAUSTIC_RESOLUTION);
 71				y[k](i, j) = CAUSTIC_AMPLITUDE * (
 72					0.08f * std::cos(xx * 2.0f + offset)
 73					+ 0.06f * std::cos(-1.0f * xx + 2.0f * zz + offset)
 74					+ 0.04f * std::cos(-2.0f * xx - 3.0f * zz + offset)
 75					+ 0.01f * std::cos(xx - 7.0f * zz - 2.0f * offset)
 76					+ 0.01f * std::cos(3.0f * xx + 5.0f * zz + offset)
 77					+ 0.01f * std::cos(9.0f * xx + zz - offset)
 78					+ 0.005f * std::cos(11.0f * xx + 7.0f * zz - offset)
 79					+ 0.005f * std::cos(4.0f * xx - 13.0f * zz + offset)
 80					+ 0.003f * std::cos(19.0f * xx - 9.0f * zz - offset)
 81				);
 82			}
 83		}
 84	}
 85
 86	// prepare to draw textures
 87	Common::flush();
 88	glXWaitX();
 89	glPushAttrib(GL_ALL_ATTRIB_BITS);
 90
 91	glDisable(GL_FOG);
 92
 93	glMatrixMode(GL_MODELVIEW);
 94	glPushMatrix();
 95	glLoadIdentity();
 96	glRotatef(-90.0f, 1, 0, 0);
 97
 98	glMatrixMode(GL_PROJECTION);
 99	glPushMatrix();
100
101	glReadBuffer(GL_BACK);
102	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
103
104	glDisable(GL_TEXTURE_2D);
105	glEnable(GL_BLEND);
106
107	std::vector<unsigned char> bitmap(size * size * 3);
108
109	// project vertices and create textures
110
111	// reciprocal of vertical component of light ray
112	float recvert = float(CAUSTIC_RESOLUTION) * 0.5f;
113	for (unsigned int k = 0; k < Hack::frames; ++k) {
114		// compute projected offsets
115		// (this uses surface normals, not actual refractions, but it's faster this way)
116		for (unsigned int i = 0; i < CAUSTIC_RESOLUTION; ++i) {
117			for (unsigned int j = 0; j < CAUSTIC_RESOLUTION; ++j) {
118				unsigned int minus, plus;
119
120				minus = (i == 0 ? CAUSTIC_RESOLUTION - 1 : i - 1);
121				plus  = (i == CAUSTIC_RESOLUTION - 1 ? 0 : i + 1);
122				xz(i, j).first = (y[k](plus, j) - y[k](minus, j)) * recvert * (CAUSTIC_DEPTH + y[k](i, j));
123
124				minus = (j == 0 ? CAUSTIC_RESOLUTION - 1 : j - 1);
125				plus  = (j == CAUSTIC_RESOLUTION - 1 ? 0 : j + 1);
126				xz(i, j).second = (y[k](i, plus) - y[k](i, minus)) * recvert * (CAUSTIC_DEPTH + y[k](i, j));
127			}
128		}
129
130		// copy offsets to edges of xz array
131		for (unsigned int i = 0; i < CAUSTIC_RESOLUTION; ++i)
132			xz(i, CAUSTIC_RESOLUTION) = xz(i, 0);
133		for (unsigned int j = 0; j <= CAUSTIC_RESOLUTION; ++j)
134			xz(CAUSTIC_RESOLUTION, j) = xz(0, j);
135
136		// compute light intensities
137		float space = 1.0f / float(CAUSTIC_RESOLUTION);
138		for (unsigned int i = 0; i < CAUSTIC_RESOLUTION; ++i) {
139			for (unsigned int j = 0; j < CAUSTIC_RESOLUTION; ++j) {
140				unsigned int xminus = (i == 0 ? CAUSTIC_RESOLUTION - 1 : i - 1);
141				unsigned int xplus  = (i == CAUSTIC_RESOLUTION - 1 ? 0 : i + 1);
142				unsigned int zminus = (j == 0 ? CAUSTIC_RESOLUTION - 1 : j - 1);
143				unsigned int zplus  = (j == CAUSTIC_RESOLUTION - 1 ? 0 : j + 1);
144				// this assumes nominal light intensity is 0.25
145				intensity(i, j) = (1.0f / (float(CAUSTIC_RESOLUTION) * float(CAUSTIC_RESOLUTION)))
146					/ ((std::abs(xz(xplus, j).first - xz(i, j).first + space)
147					+ std::abs(xz(i, j).first - xz(xminus, j).first + space))
148					* (std::abs(xz(i, zplus).second - xz(i, j).second + space)
149					+ std::abs(xz(i, j).second - xz(i, zminus).second + space)))
150					- 0.125f;
151				if (intensity(i, j) > 1.0f)
152					intensity(i, j) = 1.0f;
153			}
154		}
155
156		// copy intensities to edges of intensity array
157		for (unsigned int i = 0; i < CAUSTIC_RESOLUTION; ++i)
158			intensity(i, CAUSTIC_RESOLUTION) = intensity(i, 0);
159		for (unsigned int j = 0; j <= CAUSTIC_RESOLUTION; ++j)
160			intensity(CAUSTIC_RESOLUTION, j) = intensity(0, j);
161
162		glMatrixMode(GL_PROJECTION);
163		glLoadIdentity();
164		glOrtho(0.0f, 1.0f, 0.0f, 1.0f, -0.5f, 0.5f);
165		glViewport(
166			(Common::width - size) >> 1,
167			(Common::height - size) >> 1,
168			size, size
169		);
170		glBlendFunc(GL_SRC_ALPHA, GL_ONE);
171
172		// draw texture
173		glClear(GL_COLOR_BUFFER_BIT);
174		// draw most of texture
175		draw(intensity, x, z, xz, 0, CAUSTIC_RESOLUTION, 0, CAUSTIC_RESOLUTION);
176		// draw edges of texture that wrap around from opposite sides
177		glMatrixMode(GL_MODELVIEW);
178		glPushMatrix();
179			glTranslatef(-1.0f, 0.0f, 0.0f);
180			draw(intensity, x, z, xz, CAUSTIC_RESOLUTION * 9 / 10, CAUSTIC_RESOLUTION, 0, CAUSTIC_RESOLUTION);
181		glPopMatrix();
182		glPushMatrix();
183			glTranslatef(1.0f, 0.0f, 0.0f);
184			draw(intensity, x, z, xz, 0, CAUSTIC_RESOLUTION / 10, 0, CAUSTIC_RESOLUTION);
185		glPopMatrix();
186		glPushMatrix();
187			glTranslatef(0.0f, 0.0f, -1.0f);
188			draw(intensity, x, z, xz, 0, CAUSTIC_RESOLUTION, CAUSTIC_RESOLUTION * 9 / 10, CAUSTIC_RESOLUTION);
189		glPopMatrix();
190		glPushMatrix();
191			glTranslatef(0.0f, 0.0f, 1.0f);
192			draw(intensity, x, z, xz, 0, CAUSTIC_RESOLUTION, 0, CAUSTIC_RESOLUTION / 10);
193		glPopMatrix();
194		// draw corners too
195		glPushMatrix();
196			glTranslatef(-1.0f, 0.0f, -1.0f);
197			draw(intensity, x, z, xz, CAUSTIC_RESOLUTION * 9 / 10, CAUSTIC_RESOLUTION, CAUSTIC_RESOLUTION * 9 / 10, CAUSTIC_RESOLUTION);
198		glPopMatrix();
199		glPushMatrix();
200			glTranslatef(1.0f, 0.0f, -1.0f);
201			draw(intensity, x, z, xz, 0, CAUSTIC_RESOLUTION / 10, CAUSTIC_RESOLUTION * 9 / 10, CAUSTIC_RESOLUTION);
202		glPopMatrix();
203		glPushMatrix();
204			glTranslatef(-1.0f, 0.0f, 1.0f);
205			draw(intensity, x, z, xz, CAUSTIC_RESOLUTION * 9 / 10, CAUSTIC_RESOLUTION, 0, CAUSTIC_RESOLUTION / 10);
206		glPopMatrix();
207		glPushMatrix();
208			glTranslatef(1.0f, 0.0f, 1.0f);
209			draw(intensity, x, z, xz, 0, CAUSTIC_RESOLUTION / 10, 0, CAUSTIC_RESOLUTION / 10);
210		glPopMatrix();
211
212		// read back texture
213		glReadPixels(
214			(Common::width - size) >> 1,
215			(Common::height - size) >> 1,
216			size, size,
217			GL_RGB, GL_UNSIGNED_BYTE, &bitmap.front()
218		);
219
220		glMatrixMode(GL_PROJECTION);
221		glLoadIdentity();
222		glOrtho(0.0f, Common::width, 0.0f, Common::height, -0.5f, 0.5f);
223		glViewport(0, 0, Common::width, Common::height);
224
225		unsigned int left   = ((Common::width - size) >> 1) - 5;
226		unsigned int right  = left + size + 10;
227		unsigned int bottom = ((Common::height - size) >> 1) - 5;
228		unsigned int top    = bottom + size + 10;
229		unsigned int barBottom = bottom - 10;
230		unsigned int barTop    = barBottom - 20;
231
232		glBlendFunc(GL_ONE, GL_ZERO);
233		glLineWidth(2.0f);
234		glBegin(GL_LINE_STRIP);
235			glColor3f(0.0f, 0.4f, 0.0f);
236			glVertex3f(left, 0.0f, bottom);
237			glVertex3f(right, 0.0f, bottom);
238			glVertex3f(right, 0.0f, top);
239			glVertex3f(left, 0.0f, top);
240			glVertex3f(left, 0.0f, bottom);
241		glEnd();
242		glBegin(GL_QUADS);
243			glColor3f(0.0f, 0.2f, 0.0f);
244			glVertex3f(left, 0.0f, barBottom);
245			glVertex3f(left + (k + 1) * float(right - left) / float(Hack::frames), 0.0f, barBottom);
246			glVertex3f(left + (k + 1) * float(right - left) / float(Hack::frames), 0.0f, barTop);
247			glVertex3f(left, 0.0f, barTop);
248		glEnd();
249		glBegin(GL_LINE_STRIP);
250			glColor3f(0.0f, 0.4f, 0.0f);
251			glVertex3f(left, 0.0f, barBottom);
252			glVertex3f(right, 0.0f, barBottom);
253			glVertex3f(right, 0.0f, barTop);
254			glVertex3f(left, 0.0f, barTop);
255			glVertex3f(left, 0.0f, barBottom);
256		glEnd();
257
258		Common::flush();
259
260		// create texture object
261		_textures.push_back(Common::resources->genTexture(
262			GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT,
263			3, size, size, GL_RGB, GL_UNSIGNED_BYTE, &bitmap.front()
264		));
265	}
266
267	glMatrixMode(GL_PROJECTION);
268	glPopMatrix();
269	glMatrixMode(GL_MODELVIEW);
270	glPopMatrix();
271	glPopAttrib();
272}
273
274void CausticTextures::draw(
275	const stdx::dim2<float, CAUSTIC_RESOLUTION + 1>& intensity,
276	const float* x, const float* z,
277	const stdx::dim2<std::pair<float, float>, CAUSTIC_RESOLUTION + 1>& xz,
278	unsigned int xLo, unsigned int xHi, unsigned int zLo, unsigned int zHi
279) {
280	for (unsigned int j = zLo; j < zHi; ++j) {
281		// red
282		float mult = 1.0f - CAUSTIC_REFRACTION / float(CAUSTIC_RESOLUTION);
283		glBegin(GL_TRIANGLE_STRIP);
284		for (unsigned int i = xLo; i <= xHi; ++i) {
285			glColor3f(intensity(i, j + 1), 0.0f, 0.0f);
286			glVertex3f(x[i] + xz(i, j + 1).first * mult, 0.0f, z[j + 1] + xz(i, j + 1).second * mult);
287			glColor3f(intensity(i, j), 0.0f, 0.0f);
288			glVertex3f(x[i] + xz(i, j).first * mult, 0.0f, z[j] + xz(i, j).second * mult);
289		}
290		glEnd();
291		// green
292		glBegin(GL_TRIANGLE_STRIP);
293		for(unsigned int i = xLo; i <= xHi; ++i) {
294			glColor3f(0.0f, intensity(i, j + 1), 0.0f);
295			glVertex3f(x[i] + xz(i, j + 1).first, 0.0f, z[j + 1] + xz(i, j + 1).second);
296			glColor3f(0.0f, intensity(i, j), 0.0f);
297			glVertex3f(x[i] + xz(i, j).first, 0.0f, z[j] + xz(i, j).second);
298		}
299		glEnd();
300		// blue
301		mult = 1.0f + CAUSTIC_REFRACTION / float(CAUSTIC_RESOLUTION);
302		glBegin(GL_TRIANGLE_STRIP);
303		for(unsigned int i = xLo; i <= xHi; ++i) {
304			glColor3f(0.0f, 0.0f, intensity(i, j + 1));
305			glVertex3f(x[i] + xz(i, j + 1).first * mult, 0.0f, z[j + 1] + xz(i, j + 1).second * mult);
306			glColor3f(0.0f, 0.0f, intensity(i, j));
307			glVertex3f(x[i] + xz(i, j).first * mult, 0.0f, z[j] + xz(i, j).second * mult);
308		}
309		glEnd();
310	}
311}