2
* Copyright (C) 2002, 2009 S�ren Sonnenburg <sonne@debian.org>
4
* FX done Breakpoint 2002, code recovered, converted and polished into
5
* xscreensaver hack on Apr 12 at Breakpoint 2009.
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
10
* (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
* Lorenz attractor screensaver
26
char *hack_name = (char *)"lorenz";
36
#include <rsMath/rsVec.h>
37
#include <rsMath/rsQuat.h>
40
#define num_satellites_default 25
41
#define num_points_default 100000
42
#define line_width_attractor_default 2
43
#define line_width_satellites_default 16
44
#define camera_speed_default 0.3
45
#define linear_cutoff_default 0.2
46
#define camera_angle_default 45
48
static float elapsedTime;
50
static int line_width_satellites=line_width_satellites_default;
51
static int line_width_attractor=line_width_attractor_default;
52
static float camera_speed=camera_speed_default;
53
static float linear_cutoff=linear_cutoff_default;
55
static int num_points_max=-1;
56
static int num_precomputed_points=num_points_default;
57
static int num_points;
58
static int num_satellites=num_satellites_default;
59
static float lorenz_a=11;
60
static float lorenz_b=15;
61
static float lorenz_c=3;
62
static float lorenz_dt=0.02;
64
static float camera_angle=camera_angle_default;
65
static float camera_angle_anim[2] = {5, 179};
66
static float camera_angle_anim_speed=0.1;
67
static float mean[3] = { 0, 0, 0 };
69
static float lastn0 = 0;
70
static float flipn0 = 1;
71
static float deltaflipn0 = 0;
74
static int height=600;
76
static GLfloat col_ambient[] = { 0.0, 0.1, 0.4, 0 };
78
static GLfloat l0_diffuse[] = { 1.0, 1.0, 0.0, 1.0 };
79
static GLfloat l0_specular[] = { 0.1, 0.1, 0.05, 0.0 };
80
static GLfloat l0_att[] = { 0.5 };
81
static GLfloat l0_qatt[] = { 5.01 };
82
static GLfloat l0_cutoff[] = { 100 };
84
static float* lorenz_coords;
85
static float* lorenz_path;
86
static float* satellite_times;
87
static float* satellite_speeds;
89
static inline float distance(float P0x, float P0y, float P0z,
90
float P1x, float P1y, float P1z)
95
return sqrt(x*x+y*y+z*z);
98
static inline void norm_one(float* x, float* y, float* z)
100
float n=sqrt(((*x)*(*x))+((*y)*(*y))+((*z)*(*z)));
106
inline void calc_normal(float P0x, float P0y, float P0z,
107
float P1x, float P1y, float P1z,
108
float P2x, float P2y, float P2z,
109
float* Nx, float* Ny, float* Nz)
111
(*Nx)= (P1y - P0y) * (P2z - P0z) - (P1z - P0z) * (P2y - P0y);
112
(*Ny)= (P1z - P0z) * (P2x - P0x) - (P1x - P0x) * (P2z - P0z);
113
(*Nz)= (P1x - P0x) * (P2y - P0y) - (P1y - P0y) * (P2x - P0x);
116
inline float angle(float P0x, float P0y, float P0z,
117
float P1x, float P1y, float P1z,
118
float P2x, float P2y, float P2z)
120
return atan2(distance(P0x,P0y,P0z, P1x, P1y, P1z), distance(P0x,P0y,P0z, P2x, P2y, P2z));
124
inline void coords_at_time(float* from, float t, float* x, float* y, float* z)
129
*x=(1-s)*from[3*u]+s*from[3*(u+1)];
130
*y=(1-s)*from[3*u+1]+s*from[3*(u+1)+1];
131
*z=(1-s)*from[3*u+2]+s*from[3*(u+1)+2];
134
inline void normal_at_time(float* from, float t, float* x, float* y, float* z)
139
coords_at_time(from, t, &p1[0], &p1[1], &p1[2]);
140
coords_at_time(from, t-1, &p2[0], &p2[1], &p2[2]);
141
coords_at_time(from, t+1, &p3[0], &p3[1], &p3[2]);
142
calc_normal(p1[0], p1[1], p1[2],
148
inline float distance_to_line(float P0x, float P0y, float P0z,
149
float P1x, float P1y, float P1z,
150
float P2x, float P2y, float P2z)
153
return distance(P0x,P0y,P0z, P1x,P1y,P1z)*sin(angle(P0x,P0y,P0z, P1x,P1y,P1z, P2x,P2y,P2z));
156
void reduce_points(int cutoff)
164
num_points=num_precomputed_points;
166
while (current_offs<num_points-1 && start<num_points-1 && end<num_points-1)
169
for (end=start; end<num_points && dist<linear_cutoff; end++)
171
for (j=start; j<=end && dist<linear_cutoff; j++)
173
dist=distance_to_line(lorenz_coords[3*start],
174
lorenz_coords[3*start+1],lorenz_coords[3*start+2],
175
lorenz_coords[3*j],lorenz_coords[3*j+1],lorenz_coords[3*j+2],
176
lorenz_coords[3*end],lorenz_coords[3*end+1],lorenz_coords[3*end+2]);
182
lorenz_path[3*current_offs]=lorenz_coords[3*end];
183
lorenz_path[3*current_offs+1]=lorenz_coords[3*end+1];
184
lorenz_path[3*current_offs+2]=lorenz_coords[3*end+2];
188
printf("reduced from %d to %d\n", num_points, current_offs);
190
num_points=current_offs;
192
if (num_points_max>0 && num_points>num_points_max)
193
num_points=num_points_max;
196
void init_line_strip(void)
201
glClearColor(0.0, 0.0, 0.0, 0.0);
202
glShadeModel(GL_FLAT);
203
glEnable(GL_LIGHTING);
204
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
208
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col_ambient);
209
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
211
glNewList(1, GL_COMPILE);
212
glLineWidth(line_width_attractor);
213
glBegin(GL_LINE_STRIP);
214
for (i=100; i<num_points-20; i++)
216
glVertex3fv(&lorenz_path[i*3]);
218
calc_normal(lorenz_path[3*i], lorenz_path[3*i+1], lorenz_path[3*i+2],
219
lorenz_path[3*(i+3)], lorenz_path[3*(i+3)+1], lorenz_path[3*(i+3)+2],
220
lorenz_path[3*(i+5)], lorenz_path[3*(i+5)+2], lorenz_path[3*(i+5)+2],
223
norm_one(&n[0], &n[1], &n[2]);
242
glMatrixMode (GL_MODELVIEW);
245
coords_at_time(lorenz_coords, time, &p1[0], &p1[1], &p1[2]);
246
coords_at_time(lorenz_coords, time+10,&p2[0], &p2[1], &p2[2]);
247
coords_at_time(lorenz_coords, time+15,&p3[0], &p3[1], &p3[2]);
249
calc_normal(p1[0], p1[1], p1[2],
252
&n[0], &n[1], &n[2]);
254
norm_one(&n[0], &n[1], &n[2]);
256
// n[0]'s sign changes when transitioning between the lobes...
257
if ((lastn0 >= 0) != (n[0] >= 0)) {
258
// if we've completed a transition, one in four chance whether to transition again.
259
if ((deltaflipn0 >= 1.0) && (rand() < RAND_MAX / 4)) {
260
flipn0 = flipn0 * -1;
267
deltaflipn0 += elapsedTime;
269
// during transition, slerp between flipped states
270
if (deltaflipn0 < 1.0) {
273
la[0] = p2[0] - p1[0];
274
la[1] = p2[1] - p1[1];
275
la[2] = p2[2] - p1[2];
277
norm_one(&la[0], &la[1], &la[2]);
279
rsQuat normal, flipped;
280
normal.make(0.0, la[0], la[1], la[2]);
281
flipped.make(M_PI, la[0], la[1], la[2]);
285
f.slerp(normal, flipped, deltaflipn0);
287
f.slerp(flipped, normal, deltaflipn0);
289
rsVec rn = f.apply(rsVec(n[0], n[1], n[2]));
294
n[0] = n[0] * flipn0;
295
n[1] = n[1] * flipn0;
296
n[2] = n[2] * flipn0;
300
gluLookAt(p1[0]+0.9*n[0], p1[1]+0.9*n[1], p1[2]+0.9*n[2],
304
coords_at_time(lorenz_coords, time+10,&p2[0], &p2[1], &p2[2]);
305
coords_at_time(lorenz_coords, time+2, &p3[0], &p3[1], &p3[2]);
308
GLfloat light_position0[] = { p2[0]+n[0], p2[1]+n[1], p2[2]+n[2], 1.0 };
309
GLfloat light_dir0[] = { n[0], n[1], n[2], 1.0 };
313
glLightfv(GL_LIGHT0, GL_DIFFUSE, l0_diffuse);
314
glLightfv(GL_LIGHT0, GL_SPECULAR, l0_specular);
315
glLightfv(GL_LIGHT0, GL_POSITION, light_position0);
316
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light_dir0);
317
glLightfv(GL_LIGHT0, GL_CONSTANT_ATTENUATION, l0_att);
318
glLightfv(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, l0_qatt);
319
glLightfv(GL_LIGHT0, GL_SPOT_CUTOFF, l0_cutoff);
322
glClear (GL_COLOR_BUFFER_BIT);
325
glDisable(GL_LIGHTING);
326
for (satellites=0; satellites<num_satellites; satellites++)
330
coords_at_time(lorenz_coords, satellite_times[satellites], &x,&y,&z);
332
glLineWidth(line_width_satellites);
333
glBegin(GL_LINE_STRIP);
334
float s=37*elapsedTime*satellite_speeds[satellites]*num_points/num_precomputed_points;
336
float maxl= ( 10*(fabs(s)) < 3 ) ? 3 : 10*(fabs(s));
337
float stepl=(fabs(s)/maxl);
338
for (l=0; l<maxl; l+=stepl)
340
coords_at_time(lorenz_coords, satellite_times[satellites]+l, &x,&y,&z);
342
glNormal3d(light_dir0[0], light_dir0[1], light_dir0[2]);
344
glColor4f(0.4,0.3,1.0/(l+1),0.9/(l+1));
346
glColor4f(0.4,0.3,1.0/(maxl-l+1),0.9/(maxl-l+1));
352
satellite_times[satellites]+=s;
353
if (satellite_times[satellites]>num_points-20)
354
satellite_times[satellites]-=num_points-20;
355
if (satellite_times[satellites]<0)
356
satellite_times[satellites]+=num_points-20;
359
glEnable(GL_LIGHTING);
366
glMatrixMode(GL_PROJECTION);
368
gluPerspective(camera_angle, ((GLfloat) width)/height,0.0,1000);
371
void reshape (int w, int h)
376
printf("width=%d, height=%d\n", width, height);
380
glMatrixMode (GL_MODELVIEW);
381
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
384
void init_satellites()
388
if (num_satellites>0)
390
satellite_times = (float *)malloc(sizeof(float)*num_satellites);
391
satellite_speeds = (float *)malloc(sizeof(float)*num_satellites);
393
for (i=0; i<num_satellites; i++)
395
satellite_times[i]=((float) rand())*num_points/RAND_MAX;
396
satellite_speeds[i]=10*camera_speed*(((float) rand())/RAND_MAX - 0.5);
401
void precompute_lorenz_array()
404
float max[3] = { 1,1,1 };
406
lorenz_coords=(float*) malloc(3*num_precomputed_points*sizeof(float));
407
lorenz_path=(float*) malloc(3*num_precomputed_points*sizeof(float));
413
for (i=0; i<num_precomputed_points-1; i++)
415
lorenz_coords[(i+1)*3] = lorenz_coords[i*3] + lorenz_a *
416
( lorenz_coords[i*3+1] - lorenz_coords[i*3] ) * lorenz_dt;
418
lorenz_coords[(i+1)*3+1] = lorenz_coords[i*3+1] +
419
( lorenz_b * lorenz_coords[i*3] - lorenz_coords[i*3+1] -
420
lorenz_coords[i*3] * lorenz_coords[i*3+2] ) * lorenz_dt;
422
lorenz_coords[(i+1)*3+2] = lorenz_coords[i*3+2] +
423
( lorenz_coords[i*3] * lorenz_coords[i*3+1] -
424
lorenz_c * lorenz_coords[i*3+2] ) * lorenz_dt;
427
for (i=0; i<num_precomputed_points; i++)
429
mean[0]+=lorenz_coords[i*3];
430
mean[1]+=lorenz_coords[i*3+1];
431
mean[2]+=lorenz_coords[i*3+2];
434
mean[0]/=num_precomputed_points;
435
mean[1]/=num_precomputed_points;
436
mean[2]/=num_precomputed_points;
438
for (i=0; i<num_precomputed_points; i++)
440
lorenz_coords[i*3]-=mean[0];
441
lorenz_coords[i*3+1]-=mean[1];
442
lorenz_coords[i*3+2]-=mean[2];
445
for (i=0; i<num_precomputed_points; i++)
447
if (lorenz_coords[i*3]>max[0])
448
max[0]=lorenz_coords[i*3];
449
if (lorenz_coords[i*3+1]>max[1])
450
max[1]=lorenz_coords[i*3+1];
451
if (lorenz_coords[i*3+2]>max[2])
452
max[2]=lorenz_coords[i*3+2];
462
for (i=0; i<num_precomputed_points; i++)
464
lorenz_coords[i*3]/=m;
465
lorenz_coords[i*3+1]/=m;
466
lorenz_coords[i*3+2]/=m;
470
void cleanup_arrays()
478
free(satellite_times);
479
if (satellite_speeds)
480
free(satellite_speeds);
488
time+=37*elapsedTime*camera_speed*num_points/num_precomputed_points;
490
camera_angle+=37*elapsedTime*camera_angle_anim_speed;
491
if (camera_angle<camera_angle_anim[0] || camera_angle>camera_angle_anim[1])
493
camera_angle_anim_speed*=-1;
494
camera_angle+=camera_angle_anim_speed;
498
void hack_draw (xstuff_t * XStuff, double currentTime, float frameTime)
500
static float times[10] = { 0.03f, 0.03f, 0.03f, 0.03f, 0.03f,
501
0.03f, 0.03f, 0.03f, 0.03f, 0.03f
503
static int timeindex = 0;
509
times[timeindex] = frameTime;
511
times[timeindex] = elapsedTime;
516
elapsedTime = 0.1f * (times[0] + times[1] + times[2] + times[3] + times[4] + times[5] + times[6] + times[7] + times[8] + times[9]);
531
void hack_reshape (xstuff_t * XStuff)
534
printf("hack_reshape\n");
536
int w=XStuff->windowWidth;
537
int h=XStuff->windowHeight;
541
void hack_init (xstuff_t * XStuff)
544
printf("hack_init\n");
547
precompute_lorenz_array();
548
reduce_points(num_points_max);
551
hack_reshape (XStuff);
554
void hack_cleanup (xstuff_t * XStuff)
557
printf("hack_cleanup\n");
562
void hack_handle_opts (int argc, char **argv)
565
printf("handle_hack_opts\n");
571
static struct option long_options[] = {
574
{"num-points", 1, 0, 'n'},
575
{"num-satellites", 1, 0, 's'},
576
{"camera-speed", 1, 0, 'c'},
577
{"camera-angle", 1, 0, 'a'},
578
{"line-width", 1, 0, 'l'},
579
{"line-width-sat", 1, 0, 'w'},
580
{"line-cutoff", 1, 0, 'o'},
583
c = getopt_long (argc, argv, DRIVER_OPTIONS_SHORT "hn:s:c:a:l:w:o:", long_options, NULL);
585
c = getopt (argc, argv, DRIVER_OPTIONS_SHORT "hn:s:c:a:l:w:o:");
591
DRIVER_OPTIONS_CASES case 'h':
593
#ifndef HAVE_GETOPT_H
594
" Not built with GNU getopt.h, long options *NOT* enabled."
596
"\n" DRIVER_OPTIONS_HELP
597
"\t--num-points/-n <arg>\n"
598
"\t--num-satellites/-s\n"
599
"\t--camera-speed/-c\n"
600
"\t--camera-angle/-a\n"
602
"\t--line-width-sat/w\n"
603
"\t--line-cutoff/o\n", argv[0]);
606
num_precomputed_points = strtol_minmaxdef (optarg, 10, 100, 1000000, 1, num_points_default, "--num-points: ");
609
num_satellites = strtol_minmaxdef (optarg, 10, 0, 50, 1, num_satellites_default, "--num-satellites: ");
612
camera_speed = 0.01 * strtol_minmaxdef (optarg, 10, 0, 100, 1, camera_speed_default/0.01, "--camera-speed: ");
615
camera_angle = strtol_minmaxdef (optarg, 10, 5, 179, 1, camera_angle_default, "--camera-angle: ");
616
camera_angle_anim_speed=0;
619
line_width_attractor = strtol_minmaxdef (optarg, 10, 1, 100, 1, line_width_attractor_default, "--line-width: ");
622
line_width_satellites = strtol_minmaxdef (optarg, 10, 1, 100, 1, line_width_satellites_default, "--line-width-sat: ");
625
linear_cutoff = 0.01 * strtol_minmaxdef (optarg, 10, 0, 10000, 1, linear_cutoff_default/0.01, "--line-cutoff: ");