2
* Copyright (C) 2005 Terence M. Welsh
3
* Ported to Linux by Tugrul Galatali <tugrul@galatali.com>
5
* This file is part of Hyperspace.
7
* Hyperspace is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License version 2 as
9
* published by the Free Software Foundation.
11
* Hyperspace is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28
#include "causticTextures.h"
29
#include "rsMath/rsMath.h"
32
causticTextures::causticTextures(xstuff_t *XStuff, int keys, int frames, int res, int size, float depth, float wa, float rm)
35
int xminus, xplus, zminus, zplus;
37
unsigned char* bitmap = new unsigned char[size * size * 3];
39
// initialize dimensions
44
if(numFrames < numKeys * 2)
45
numFrames = numKeys * 2;
55
caustictex = new GLuint[numFrames];
56
glGenTextures(numFrames, caustictex);
59
x = new float[geoRes + 1];
60
z = new float[geoRes + 1];
61
y = new float**[numFrames];
62
for(k=0; k<numFrames; k++){
63
y[k] = new float*[geoRes];
64
for(i=0; i<geoRes; i++)
65
y[k][i] = new float[geoRes];
67
xz = new float**[geoRes + 1];
68
for(i=0; i<=geoRes; i++){
69
xz[i] = new float*[geoRes + 1];
70
for(j=0; j<=geoRes; j++)
71
xz[i][j] = new float[2];
73
intensity = new float*[geoRes + 1];
74
for(i=0; i<=geoRes; i++)
75
intensity[i] = new float[geoRes + 1];
77
// set x and z geometry positions
78
for(i=0; i<=geoRes; i++){
79
x[i] = float(i) / float(geoRes);
80
z[i] = float(i) / float(geoRes);
83
// set y geometry positions (altitudes)
84
// fractal altitudes is sort of ugly, so I don't use it
85
//makeFractalAltitudes();
88
// prepare to draw textures
89
glGetIntegerv(GL_VIEWPORT, viewport);
90
glViewport(0, 0, texSize, texSize);
91
glMatrixMode(GL_PROJECTION);
94
glOrtho(0.0f, 1.0f, 0.0f, 1.0f, -0.5f, 0.5f);
95
glMatrixMode(GL_MODELVIEW);
97
glRotatef(-90.0f, 1, 0, 0);
98
glReadBuffer(GL_BACK);
99
//glPixelStorei(GL_UNPACK_ROW_LENGTH, texSize);
100
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
101
glDisable(GL_TEXTURE_2D);
102
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
105
// project vertices and create textures
106
float recvert = float(geoRes) * 0.5f; // reciprocal of vertical component of light ray
107
for(k=0; k<numFrames; k++){
108
// compute projected offsets
109
// (this uses surface normals, not actual refractions, but it's faster this way)
110
for(i=0; i<geoRes; i++){
111
for(j=0; j<geoRes; j++){
112
makeIndices(i, &xminus, &xplus);
113
xz[i][j][0] = (y[k][xplus][j] - y[k][xminus][j]) * recvert * (depth + y[k][i][j]);
114
makeIndices(j, &zminus, &zplus);
115
xz[i][j][1] = (y[k][i][zplus] - y[k][i][zminus]) * recvert * (depth + y[k][i][j]);
119
// copy offsets to edges of xz array
120
for(i=0; i<geoRes; i++){
121
xz[i][geoRes][0] = xz[i][0][0];
122
xz[i][geoRes][1] = xz[i][0][1];
124
for(j=0; j<=geoRes; j++){
125
xz[geoRes][j][0] = xz[0][j][0];
126
xz[geoRes][j][1] = xz[0][j][1];
129
// compute light intensities
130
float space = 1.0f / float(geoRes);
131
for(i=0; i<geoRes; i++){
132
for(j=0; j<geoRes; j++){
133
makeIndices(i, &xminus, &xplus);
134
makeIndices(j, &zminus, &zplus);
135
// this assumes nominal light intensity is 0.25
136
intensity[i][j] = (1.0f / (float(geoRes) * float(geoRes)))
137
/ ((fabs(xz[xplus][j][0] - xz[i][j][0] + space)
138
+ fabs(xz[i][j][0] - xz[xminus][j][0] + space))
139
* (fabs(xz[i][zplus][1] - xz[i][j][1] + space)
140
+ fabs(xz[i][j][1] - xz[i][zminus][1] + space)))
142
if(intensity[i][j] > 1.0f)
143
intensity[i][j] = 1.0f;
147
// copy intensities to edges of intensity array
148
for(i=0; i<geoRes; i++)
149
intensity[i][geoRes] = intensity[i][0];
150
for(j=0; j<=geoRes; j++)
151
intensity[geoRes][j] = intensity[0][j];
154
glClear(GL_COLOR_BUFFER_BIT);
155
// draw most of texture
156
draw(0, geoRes, 0, geoRes);
157
// draw edges of texture that wrap around from opposite sides
158
int numRows = geoRes / 10;
160
glTranslatef(-1.0f, 0.0f, 0.0f);
161
draw(geoRes - numRows, geoRes, 0, geoRes);
164
glTranslatef(1.0f, 0.0f, 0.0f);
165
draw(0, numRows, 0, geoRes);
168
glTranslatef(0.0f, 0.0f, -1.0f);
169
draw(0, geoRes, geoRes - numRows, geoRes);
172
glTranslatef(0.0f, 0.0f, 1.0f);
173
draw(0, geoRes, 0, numRows);
177
glTranslatef(-1.0f, 0.0f, -1.0f);
178
draw(geoRes - numRows, geoRes, geoRes - numRows, geoRes);
181
glTranslatef(1.0f, 0.0f, -1.0f);
182
draw(0, numRows, geoRes - numRows, geoRes);
185
glTranslatef(-1.0f, 0.0f, 1.0f);
186
draw(geoRes - numRows, geoRes, 0, numRows);
189
glTranslatef(1.0f, 0.0f, 1.0f);
190
draw(0, numRows, 0, numRows);
194
glReadPixels(0, 0, texSize, texSize, GL_RGB, GL_UNSIGNED_BYTE, bitmap);
196
// create texture object
197
glBindTexture(GL_TEXTURE_2D, caustictex[k]);
198
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
199
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
200
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, texSize, texSize, GL_RGB,
201
GL_UNSIGNED_BYTE, bitmap);
203
glXSwapBuffers (XStuff->display, XStuff->window);
206
// restore matrix stack
208
glMatrixMode(GL_PROJECTION);
210
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
221
void causticTextures::makeFractalAltitudes(){
223
float keySeparation = float(numFrames) / float(numKeys);
224
int* keyFrame = new int[numKeys+1];
226
// generate keyframes
228
for(k=0; k<numKeys; k++){
229
keyFrame[k] = int(float(k) * keySeparation);
230
// set all keyframe altitudes to 0.0
231
for(i=0; i<geoRes; i++){
232
for(j=0; j<geoRes; j++)
233
y[keyFrame[k]][i][j] = 0.0f;
235
// generate altitudes in first positions
236
phase = float(k) * RS_PIx2 / float(numKeys);
237
y[keyFrame[k]][0][0] = waveAmp * rsCosf(1.5707f + phase);
238
y[keyFrame[k]][geoRes/2][0] = waveAmp * rsCosf(1.5707f + phase);
239
y[keyFrame[k]][geoRes/2][geoRes/2] = waveAmp * rsCosf(3.1416f + phase);
240
y[keyFrame[k]][0][geoRes/2] = waveAmp * rsCosf(4.7124f + phase);
241
// recurse to find remaining altitudes
242
altitudeSquare(0, geoRes/2, 0, geoRes/2, y[keyFrame[k]]);
243
altitudeSquare(geoRes/2, geoRes, 0, geoRes/2, y[keyFrame[k]]);
244
altitudeSquare(0, geoRes/2, geoRes/2, geoRes, y[keyFrame[k]]);
245
altitudeSquare(geoRes/2, geoRes, geoRes/2, geoRes, y[keyFrame[k]]);
248
// interpolate to find remaining frames
250
int kf0, kf1, kf2, kf3; // keyframe indices
252
keyFrame[numKeys] = numFrames;
253
for(k=0; k<numKeys; k++){
268
for(a=kf1+1; a<kf1+diff; a++){
269
where = float(a-kf1) / float(diff);
270
for(i=0; i<geoRes; i++)
271
for(j=0; j<geoRes; j++)
272
y[a][i][j] = interpolate(y[kf0][i][j], y[kf1][i][j],
273
y[kf2][i][j], y[kf3][i][j], where);
282
void causticTextures::altitudeSquare(int left, int right, int bottom, int top, float** alt){
283
// find wrapped indices
291
// for determining if there is a gap to be filled
292
int hor = right - left;
293
int vert = top - bottom;
295
int centerHor = (left + right) / 2;
296
int centerVert = (bottom + top) / 2;
298
if(hor > 1){ // find bottom and top altitudes
299
offset = fabs(waveAmp * float(x[right] - x[left]));
300
if(alt[centerHor][bottom] == 0.0f)
301
alt[centerHor][bottom] = (alt[left][bottom] + alt[rr][bottom]) * 0.5f
302
+ rsRandf(offset+offset) - offset;
303
if(alt[centerHor][tt] == 0.0f)
304
alt[centerHor][tt] = (alt[left][tt] + alt[rr][tt]) * 0.5f
305
+ rsRandf(offset+offset) - offset;
307
if(vert > 1){ // find left and right altitudes
308
offset = fabs(waveAmp * float(z[top] - z[bottom]));
309
if(alt[left][centerVert] == 0.0f)
310
alt[left][centerVert] = (alt[left][bottom] + alt[left][tt]) * 0.5f
311
+ rsRandf(offset+offset) - offset;
312
if(alt[rr][centerVert] == 0.0f)
313
alt[rr][centerVert] = (alt[rr][bottom] + alt[rr][tt]) * 0.5f
314
+ rsRandf(offset+offset) - offset;
316
if(hor > 1 && vert > 1){ // find center altitude
317
offset = waveAmp * 0.5f *
318
(fabs(float(x[right] - x[left]))
319
+ fabs(float(z[top] - z[bottom])));
320
alt[centerHor][centerVert] = (alt[left][bottom] + alt[rr][bottom] + alt[left][tt]
321
+ alt[rr][tt]) * 0.25f + rsRandf(offset+offset) - offset;
324
// keep recursing if necessary
325
int quadrant[4] = {0, 0, 0, 0};
326
if(centerHor - left > 1){
330
if(right - centerHor > 1){
334
if(centerVert - bottom > 1){
338
if(top - centerVert > 1){
343
altitudeSquare(left, centerHor, bottom, centerVert, alt);
345
altitudeSquare(centerHor, right, bottom, centerVert, alt);
347
altitudeSquare(left, centerHor, centerVert, top, alt);
349
altitudeSquare(centerHor, right, centerVert, top, alt);
355
void causticTextures::makeTrigAltitudes(){
357
float xx, zz, offset;
359
for(k=0; k<numFrames; k++){
360
offset = RS_PIx2 * float(k) / float(numFrames);
361
for(i=0; i<geoRes; i++){
362
xx = RS_PIx2 * float(i) / float(geoRes);
363
for(j=0; j<geoRes; j++){
364
zz = RS_PIx2 * float(j) / float(geoRes);
365
/*y[k][i][j] = waveAmp
366
* (0.12f * rsCosf(xx + 2.0f * offset)
367
+ 0.08f * rsCosf(-1.0f * xx + 2.0f * zz + offset)
368
+ 0.04f * rsCosf(-2.0f * xx - 4.0f * zz + offset)
369
+ 0.014f * rsCosf(xx - 7.0f * zz - 2.0f * offset)
370
+ 0.014f * rsCosf(3.0f * xx + 5.0f * zz + offset)
371
+ 0.014f * rsCosf(9.0f * xx + zz - offset)
372
+ 0.007f * rsCosf(11.0f * xx + 7.0f * zz - offset)
373
+ 0.007f * rsCosf(4.0f * xx - 13.0f * zz + offset)
374
+ 0.007f * rsCosf(19.0f * xx - 9.0f * zz - offset));*/
376
* (0.08f * rsCosf(xx * 2.0f + offset)
377
+ 0.06f * rsCosf(-1.0f * xx + 2.0f * zz + offset)
378
+ 0.04f * rsCosf(-2.0f * xx - 3.0f * zz + offset)
379
+ 0.01f * rsCosf(xx - 7.0f * zz - 2.0f * offset)
380
+ 0.01f * rsCosf(3.0f * xx + 5.0f * zz + offset)
381
+ 0.01f * rsCosf(9.0f * xx + zz - offset)
382
+ 0.005f * rsCosf(11.0f * xx + 7.0f * zz - offset)
383
+ 0.005f * rsCosf(4.0f * xx - 13.0f * zz + offset)
384
+ 0.003f * rsCosf(19.0f * xx - 9.0f * zz - offset));
391
void causticTextures::draw(int xlo, int xhi, int zlo, int zhi){
395
for(j=zlo; j<zhi; j++){
397
mult = 1.0f - refractionMult / float(geoRes);
398
glBegin(GL_TRIANGLE_STRIP);
399
for(i=xlo; i<=xhi; i++){
400
glColor3f(intensity[i][j+1], 0.0f, 0.0f);
401
glVertex3f(x[i] + xz[i][j+1][0] * mult, 0.0f, z[j+1] + xz[i][j+1][1] * mult);
402
glColor3f(intensity[i][j], 0.0f, 0.0f);
403
glVertex3f(x[i] + xz[i][j][0] * mult, 0.0f, z[j] + xz[i][j][1] * mult);
407
glBegin(GL_TRIANGLE_STRIP);
408
for(i=xlo; i<=xhi; i++){
409
glColor3f(0.0f, intensity[i][j+1], 0.0f);
410
glVertex3f(x[i] + xz[i][j+1][0], 0.0f, z[j+1] + xz[i][j+1][1]);
411
glColor3f(0.0f, intensity[i][j], 0.0f);
412
glVertex3f(x[i] + xz[i][j][0], 0.0f, z[j] + xz[i][j][1]);
416
mult = 1.0f + refractionMult / float(geoRes);
417
glBegin(GL_TRIANGLE_STRIP);
418
for(i=xlo; i<=xhi; i++){
419
glColor3f(0.0f, 0.0f, intensity[i][j+1]);
420
glVertex3f(x[i] + xz[i][j+1][0] * mult, 0.0f, z[j+1] + xz[i][j+1][1] * mult);
421
glColor3f(0.0f, 0.0f, intensity[i][j]);
422
glVertex3f(x[i] + xz[i][j][0] * mult, 0.0f, z[j] + xz[i][j][1] * mult);
429
void causticTextures::makeIndices(int index, int* minus, int* plus){
439
// Here's a little calculus that takes 4 points along a single
440
// dimension and interpolates smoothly between the second and third
441
// depending on the value of where which can be 0.0 to 1.0.
442
// The slope at b is estimated using a and c. The slope at c
443
// is estimated using b and d.
444
float causticTextures::interpolate(float a, float b, float c, float d, float where){
447
q = (((3.0f * b) + d - a - (3.0f * c)) * (where * where * where)) * 0.5f;
448
r = (((2.0f * a) - (5.0f * b) + (4.0f * c) - d) * (where * where)) * 0.5f;
449
s = ((c - a) * where) * 0.5f;
451
return(q + r + s + t);