1 /*
2 * Copyright (C) 2002 Terence M. Welsh
3 * Ported to Linux by Tugrul Galatali <tugrul@galatali.com>
4 *
5 * Helios 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 * Helios 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 // Helios screensaver
20
21 #include <math.h>
22 #include <stdio.h>
23 #include <GL/gl.h>
24 #include <GL/glu.h>
25 #include <GL/glx.h>
26
27 #include "driver.h"
28 #include "Implicit/impCubeVolume.h"
29 #include "Implicit/impCrawlPoint.h"
30 #include "Implicit/impSphere.h"
31 #include "loadTexture.h"
32 #include "rgbhsl.h"
33 #include "rsDefines.h"
34 #include "rsRand.h"
35 #include "rsMath/rsMatrix.h"
36 #include "rsMath/rsQuat.h"
37 #include "rsMath/rsVec.h"
38
39 const char *hack_name = "helios";
40
41 #define TEXSIZE 256
42
43 extern unsigned char *spheremap;
44 extern unsigned int spheremap_size;
45 extern unsigned int spheremap_compressedsize;
46
47 #define LIGHTSIZE 64
48
49 class particle;
50 class emitter;
51 class attracter;
52 class ion;
53
54 // Global variables
55 int readyToDraw = 0;
56 unsigned char lightTexture[LIGHTSIZE][LIGHTSIZE];
57 float elapsedTime = 0.0f;
58 emitter *elist;
59 attracter *alist;
60 ion *ilist;
61 rsVec newRgb;
62 float billboardMat[16];
63 int pfd_swap_exchange;
64
65 // Parameters edited in the dialog box
66 int dIons;
67 int dSize;
68 int dEmitters;
69 int dAttracters;
70 int dSpeed;
71 int dCameraspeed;
72 int dSurface;
73 int dWireframe;
74 int dBlur;
75
76 impCubeVolume *volume;
77 impSurface *surface;
78 impSphere *spheres;
79
80 class particle {
81 public:
82 rsVec pos;
83 rsVec rgb;
84 float size;
85 };
86
87 class emitter:public particle {
88 public:
89 rsVec oldpos;
90 rsVec targetpos;
91
92 emitter ();
~emitter()93 ~emitter () {
94 };
settargetpos(rsVec target)95 void settargetpos (rsVec target) {
96 oldpos = pos;
97 targetpos = target;
98 };
interppos(float n)99 void interppos (float n) {
100 pos = oldpos * (1.0f - n) + targetpos * n;
101 };
update()102 void update () {
103 };
104 };
105
emitter()106 emitter::emitter ()
107 {
108 pos = rsVec (rsRandf (1000.0f) - 500.0f, rsRandf (1000.0f) - 500.0f, rsRandf (1000.0f) - 500.0f);
109 }
110
111 class attracter:public particle {
112 public:
113 rsVec oldpos;
114 rsVec targetpos;
115
116 attracter ();
~attracter()117 ~attracter () {
118 };
settargetpos(rsVec target)119 void settargetpos (rsVec target) {
120 oldpos = pos;
121 targetpos = target;
122 };
interppos(float n)123 void interppos (float n) {
124 pos = oldpos * (1.0f - n) + targetpos * n;
125 };
update()126 void update () {
127 };
128 };
129
attracter()130 attracter::attracter ()
131 {
132 pos = rsVec (rsRandf (1000.0f) - 500.0f, rsRandf (1000.0f) - 500.0f, rsRandf (1000.0f) - 500.0f);
133 }
134
135 class ion:public particle {
136 public:
137 float speed;
138
139 ion ();
~ion()140 ~ion () {
141 };
142 void start ();
143 void update ();
144 void draw ();
145 };
146
ion()147 ion::ion ()
148 {
149 float temp;
150
151 pos = rsVec (0.0f, 0.0f, 0.0f);
152 rgb = rsVec (0.0f, 0.0f, 0.0f);
153 temp = rsRandf (2.0f) + 0.4f;
154 size = float (dSize) * temp;
155 speed = float (dSpeed) * 12.0f / temp;
156 }
157
158 void
start()159 ion::start ()
160 {
161 int i = rsRandi (dEmitters);
162 float offset = elapsedTime * speed;
163
164 pos = elist[i].pos;
165
166 switch (rsRandi (14)) {
167 case 0:
168 pos[0] += offset;
169 break;
170 case 1:
171 pos[0] -= offset;
172 break;
173 case 2:
174 pos[1] += offset;
175 break;
176 case 3:
177 pos[1] -= offset;
178 break;
179 case 4:
180 pos[2] += offset;
181 break;
182 case 5:
183 pos[2] -= offset;
184 break;
185 case 6:
186 pos[0] += offset;
187 pos[1] += offset;
188 pos[2] += offset;
189 break;
190 case 7:
191 pos[0] -= offset;
192 pos[1] += offset;
193 pos[2] += offset;
194 break;
195 case 8:
196 pos[0] += offset;
197 pos[1] -= offset;
198 pos[2] += offset;
199 break;
200 case 9:
201 pos[0] -= offset;
202 pos[1] -= offset;
203 pos[2] += offset;
204 break;
205 case 10:
206 pos[0] += offset;
207 pos[1] += offset;
208 pos[2] -= offset;
209 break;
210 case 11:
211 pos[0] -= offset;
212 pos[1] += offset;
213 pos[2] -= offset;
214 break;
215 case 12:
216 pos[0] += offset;
217 pos[1] -= offset;
218 pos[2] -= offset;
219 break;
220 case 13:
221 pos[0] -= offset;
222 pos[1] -= offset;
223 pos[2] -= offset;
224 }
225
226 rgb = newRgb;
227 }
228
update()229 void ion::update ()
230 {
231 int i;
232 int startOver = 0;
233 static float startOverDistance;
234 static rsVec force, tempvec;
235 static float length, temp;
236
237 force = rsVec (0.0f, 0.0f, 0.0f);
238 for (i = 0; i < dEmitters; i++) {
239 tempvec = pos - elist[i].pos;
240 length = tempvec.normalize ();
241 if (length > 11000.0f)
242 startOver = 1;
243 if (length <= 1.0f)
244 temp = 1.0f;
245 else
246 temp = 1.0f / length;
247 tempvec *= temp;
248 force += tempvec;
249 }
250 startOverDistance = speed * elapsedTime;
251 for (i = 0; i < dAttracters; i++) {
252 tempvec = alist[i].pos - pos;
253 length = tempvec.normalize ();
254 if (length < startOverDistance)
255 startOver = 1;
256 if (length <= 1.0f)
257 temp = 1.0f;
258 else
259 temp = 1.0f / length;
260 tempvec *= temp;
261 force += tempvec;
262 }
263
264 // Start this ion at an emitter if it gets too close to an attracter
265 // or too far from an emitter
266 if (startOver)
267 start ();
268 else {
269 force.normalize ();
270 pos += (force * elapsedTime * speed);
271 }
272 }
273
draw()274 void ion::draw ()
275 {
276 glColor3f (rgb[0], rgb[1], rgb[2]);
277 glPushMatrix ();
278 glTranslatef (pos[0] * billboardMat[0] + pos[1] * billboardMat[4] + pos[2] * billboardMat[8],
279 pos[0] * billboardMat[1] + pos[1] * billboardMat[5] + pos[2] * billboardMat[9],
280 pos[0] * billboardMat[2] + pos[1] * billboardMat[6] + pos[2] * billboardMat[10]);
281 glScalef (size, size, size);
282 glCallList (1);
283 glPopMatrix ();
284 }
285
setTargets(int whichTarget)286 void setTargets (int whichTarget)
287 {
288 int i;
289
290 switch (whichTarget) {
291 case 0: // random
292 for (i = 0; i < dEmitters; i++)
293 elist[i].settargetpos (rsVec (rsVec (rsRandf (1000.0f) - 500.0f, rsRandf (1000.0f) - 500.0f, rsRandf (1000.0f) - 500.0f)));
294 for (i = 0; i < dAttracters; i++)
295 alist[i].settargetpos (rsVec (rsVec (rsRandf (1000.0f) - 500.0f, rsRandf (1000.0f) - 500.0f, rsRandf (1000.0f) - 500.0f)));
296 break;
297 case 1:
298 { // line (all emitters on one side, all attracters on the other)
299 float position = -500.0f, change = 1000.0f / float (dEmitters + dAttracters - 1);
300
301 for (i = 0; i < dEmitters; i++) {
302 elist[i].settargetpos (rsVec (rsVec (position, position * 0.5f, 0.0f)));
303 position += change;
304 }
305 for (i = 0; i < dAttracters; i++) {
306 alist[i].settargetpos (rsVec (rsVec (position, position * 0.5f, 0.0f)));
307 position += change;
308 }
309 break;
310 }
311 case 2:
312 { // line (emitters and attracters staggered)
313 float change;
314
315 if (dEmitters > dAttracters) {
316 change = 1000.0f / float (dEmitters * 2 - 1);
317 } else {
318 change = 1000.0f / float (dAttracters * 2 - 1);
319 }
320 float position = -500.0f;
321
322 for (i = 0; i < dEmitters; i++) {
323 elist[i].settargetpos (rsVec (rsVec (position, position * 0.5f, 0.0f)));
324 position += change * 2.0f;
325 }
326 position = -500.0f + change;
327 for (i = 0; i < dAttracters; i++) {
328 alist[i].settargetpos (rsVec (rsVec (position, position * 0.5f, 0.0f)));
329 position += change * 2.0f;
330 }
331 break;
332 }
333 case 3:
334 { // 2 lines (parallel)
335 float change = 1000.0f / float (dEmitters * 2 - 1);
336 float position = -500.0f;
337 float height = -525.0f + float (dEmitters * 25);
338
339 for (i = 0; i < dEmitters; i++) {
340 elist[i].settargetpos (rsVec (rsVec (position, height, -50.0f)));
341 position += change * 2.0f;
342 }
343 change = 1000.0f / float (dAttracters * 2 - 1);
344
345 position = -500.0f;
346 height = 525.0f - float (dAttracters * 25);
347
348 for (i = 0; i < dAttracters; i++) {
349 alist[i].settargetpos (rsVec (rsVec (position, height, 50.0f)));
350 position += change * 2.0f;
351 }
352 break;
353 }
354 case 4:
355 { // 2 lines (skewed)
356 float change = 1000.0f / float (dEmitters * 2 - 1);
357 float position = -500.0f;
358 float height = -525.0f + float (dEmitters * 25);
359
360 for (i = 0; i < dEmitters; i++) {
361 elist[i].settargetpos (rsVec (rsVec (position, height, 0.0f)));
362 position += change * 2.0f;
363 }
364 change = 1000.0f / float (dAttracters * 2 - 1);
365
366 position = -500.0f;
367 height = 525.0f - float (dAttracters * 25);
368
369 for (i = 0; i < dAttracters; i++) {
370 alist[i].settargetpos (rsVec (rsVec (10.0f, height, position)));
371 position += change * 2.0f;
372 }
373 break;
374 }
375 case 5: // random distribution across a plane
376 for (i = 0; i < dEmitters; i++)
377 elist[i].settargetpos (rsVec (rsVec (rsRandf (1000.0f) - 500.0f, 0.0f, rsRandf (1000.0f) - 500.0f)));
378 for (i = 0; i < dAttracters; i++)
379 alist[i].settargetpos (rsVec (rsVec (rsRandf (1000.0f) - 500.0f, 0.0f, rsRandf (1000.0f) - 500.0f)));
380 break;
381 case 6:
382 { // random distribution across 2 planes
383 float height = -525.0f + float (dEmitters * 25);
384
385 for (i = 0; i < dEmitters; i++)
386 elist[i].settargetpos (rsVec (rsVec (rsRandf (1000.0f) - 500.0f, height, rsRandf (1000.0f) - 500.0f)));
387
388 height = 525.0f - float (dAttracters * 25);
389
390 for (i = 0; i < dAttracters; i++)
391 alist[i].settargetpos (rsVec (rsVec (rsRandf (1000.0f) - 500.0f, height, rsRandf (1000.0f) - 500.0f)));
392
393 break;
394 }
395 case 7:
396 { // 2 rings (1 inside and 1 outside)
397 float angle = 0.5f, cosangle, sinangle;
398 float change = PIx2 / float (dEmitters);
399
400 for (i = 0; i < dEmitters; i++) {
401 angle += change;
402 cosangle = cos (angle) * 200.0f;
403 sinangle = sin (angle) * 200.0f;
404 elist[i].settargetpos (rsVec (rsVec (cosangle, sinangle, 0.0f)));
405 }
406 angle = 1.5f;
407 change = PIx2 / float (dAttracters);
408
409 for (i = 0; i < dAttracters; i++) {
410 angle += change;
411 cosangle = cos (angle) * 500.0f;
412 sinangle = sin (angle) * 500.0f;
413 alist[i].settargetpos (rsVec (rsVec (cosangle, sinangle, 0.0f)));
414 }
415 break;
416 }
417 case 8:
418 { // ring (all emitters on one side, all attracters on the other)
419 float angle = 0.5f, cosangle, sinangle;
420 float change = PIx2 / float (dEmitters + dAttracters);
421
422 for (i = 0; i < dEmitters; i++) {
423 angle += change;
424 cosangle = cos (angle) * 500.0f;
425 sinangle = sin (angle) * 500.0f;
426 elist[i].settargetpos (rsVec (rsVec (cosangle, sinangle, 0.0f)));
427 }
428 for (i = 0; i < dAttracters; i++) {
429 angle += change;
430 cosangle = cos (angle) * 500.0f;
431 sinangle = sin (angle) * 500.0f;
432 alist[i].settargetpos (rsVec (rsVec (cosangle, sinangle, 0.0f)));
433 }
434 break;
435 }
436 case 9:
437 { // ring (emitters and attracters staggered)
438 float change;
439
440 if (dEmitters > dAttracters) {
441 change = PIx2 / float (dEmitters * 2);
442 } else {
443 change = PIx2 / float (dAttracters * 2);
444 }
445 float angle = 0.5f, cosangle, sinangle;
446
447 for (i = 0; i < dEmitters; i++) {
448 cosangle = cos (angle) * 500.0f;
449 sinangle = sin (angle) * 500.0f;
450 elist[i].settargetpos (rsVec (rsVec (cosangle, sinangle, 0.0f)));
451 angle += change * 2.0f;
452 }
453 angle = 0.5f + change;
454 for (i = 0; i < dAttracters; i++) {
455 cosangle = cos (angle) * 500.0f;
456 sinangle = sin (angle) * 500.0f;
457 alist[i].settargetpos (rsVec (rsVec (cosangle, sinangle, 0.0f)));
458 angle += change * 2.0f;
459 }
460 break;
461 }
462 case 10: // 2 points
463 for (i = 0; i < dEmitters; i++)
464 elist[i].settargetpos (rsVec (rsVec (500.0f, 100.0f, 50.0f)));
465 for (i = 0; i < dAttracters; i++)
466 alist[i].settargetpos (rsVec (rsVec (-500.0f, -100.0f, -50.0f)));
467 break;
468 }
469 }
470
surfaceFunction(float * position)471 float surfaceFunction (float *position)
472 {
473 static int i;
474 static float value;
475 static int points = dEmitters + dAttracters;
476
477 value = 0.0f;
478 for (i = 0; i < points; i++)
479 value += spheres[i].value (position);
480
481 return (value);
482 }
483
hack_draw(xstuff_t * XStuff,double currentTime,float frameTime)484 void hack_draw (xstuff_t * XStuff, double currentTime, float frameTime)
485 {
486 int i;
487 static int ionsReleased = 0;
488 static float releaseTime = 0.0f;
489 Display *dpy = XStuff->display;
490 #ifdef BENCHMARK
491 static int a = 1;
492 #endif
493
494 Window window = XStuff->window;
495
496 elapsedTime = frameTime;
497
498 #ifdef BENCHMARK
499 if (a++ == 1000)
500 exit(0);
501 elapsedTime = 0.1f;
502 #endif
503
504 // Camera movements
505 // first do translation (distance from center)
506 static float oldCameraDistance;
507 static float cameraDistance;
508 static float targetCameraDistance = -1000.0f;
509 static float preCameraInterp = PI;
510 float cameraInterp;
511
512 preCameraInterp += float (dCameraspeed) * elapsedTime * 0.01f;
513
514 cameraInterp = 0.5f - (0.5f * cos (preCameraInterp));
515 cameraDistance = (1.0f - cameraInterp) * oldCameraDistance + cameraInterp * targetCameraDistance;
516
517 if (preCameraInterp >= PI) {
518 oldCameraDistance = targetCameraDistance;
519 targetCameraDistance = -rsRandf (1300.0f) - 200.0f;
520 preCameraInterp = 0.0f;
521 }
522
523 glMatrixMode (GL_MODELVIEW);
524 glLoadIdentity ();
525 glTranslatef (0.0, 0.0, cameraDistance);
526
527 // then do rotation
528 static rsVec radialVel = rsVec (0.0f, 0.0f, 0.0f);
529 static rsVec targetRadialVel = radialVel;
530 static rsQuat rotQuat = rsQuat (0.0f, 0.0f, 0.0f, 1.0f);
531
532 rsVec radialVelDiff = targetRadialVel - radialVel;
533 float changeRemaining = radialVelDiff.normalize ();
534 float change = float (dCameraspeed) * 0.0002f * elapsedTime;
535
536 if (changeRemaining > change) {
537 radialVelDiff *= change;
538 radialVel += radialVelDiff;
539 } else {
540 radialVel = targetRadialVel;
541 if (rsRandi (2)) {
542 targetRadialVel = rsVec (rsRandf (1.0f), rsRandf (1.0f), rsRandf (1.0f));
543 targetRadialVel.normalize ();
544 targetRadialVel *= float (dCameraspeed) * rsRandf (0.002f);
545 } else
546 targetRadialVel = rsVec (0.0f, 0.0f, 0.0f);
547 }
548
549 rsVec tempRadialVel = radialVel;
550 float angle = tempRadialVel.normalize ();
551
552 rsQuat radialQuat;
553
554 radialQuat.make (angle, tempRadialVel[0], tempRadialVel[1], tempRadialVel[2]);
555 rotQuat.preMult (radialQuat);
556 rsMatrix rotMat;
557
558 rotMat.fromQuat (rotQuat);
559
560 // make billboard matrix for rotating particles when they are drawn
561 rotMat.get (billboardMat);
562
563 // Calculate new color
564 static rsVec oldHsl, newHsl = rsVec (rsRandf (1.0f), 1.0f, 1.0f), targetHsl;
565 static float colorInterp = 1.0f, colorChange;
566
567 colorInterp += elapsedTime * colorChange;
568 if (colorInterp >= 1.0f) {
569 if (!rsRandi (3) && dIons >= 100) // change color suddenly
570 newHsl = rsVec (rsRandf (1.0f), 1.0f - (rsRandf (1.0f) * rsRandf (1.0f)), 1.0f);
571 oldHsl = newHsl;
572 targetHsl = rsVec (rsRandf (1.0f), 1.0f - (rsRandf (1.0f) * rsRandf (1.0f)), 1.0f);
573 colorInterp = 0.0f;
574 // amount by which to change colorInterp each second
575 colorChange = rsRandf (0.005f * float (dSpeed)) + (0.002f * float (dSpeed));
576 } else {
577 float diff = targetHsl[0] - oldHsl[0];
578
579 if (diff < -0.5f || (diff > 0.0f && diff < 0.5f))
580 newHsl[0] = oldHsl[0] + colorInterp * diff;
581 else
582 newHsl[0] = oldHsl[0] - colorInterp * diff;
583 diff = targetHsl[1] - oldHsl[1];
584 newHsl[1] = oldHsl[1] + colorInterp * diff;
585 if (newHsl[0] < 0.0f)
586 newHsl[0] += 1.0f;
587 if (newHsl[0] > 1.0f)
588 newHsl[0] -= 1.0f;
589 hsl2rgb (newHsl[0], newHsl[1], 1.0f, newRgb[0], newRgb[1], newRgb[2]);
590 }
591
592 // Release ions
593 if (ionsReleased < dIons) {
594 releaseTime -= elapsedTime;
595 while (ionsReleased < dIons && releaseTime <= 0.0f) {
596 ilist[ionsReleased].start ();
597 ionsReleased++;
598 // all ions released after 2 minutes
599 releaseTime += 120.0f / float (dIons);
600 }
601 }
602 // Set interpolation value for emitters and attracters
603 static float wait = 0.0f;
604 static float preinterp = PI, interp;
605 static float interpconst = 0.001f;
606
607 wait -= elapsedTime;
608 if (wait <= 0.0f) {
609 preinterp += elapsedTime * float (dSpeed) * interpconst;
610
611 interp = 0.5f - (0.5f * cos (preinterp));
612 }
613 if (preinterp >= PI) {
614 // select new taget points (not the same pattern twice in a row)
615 static int newTarget = 0, lastTarget;
616
617 lastTarget = newTarget;
618 newTarget = rsRandi (10);
619 if (newTarget == lastTarget)
620 newTarget++;
621 setTargets (newTarget);
622 preinterp = 0.0f;
623 interp = 0.0f;
624 wait = 10.0f; // pause after forming each new pattern
625 interpconst = 0.001f;
626 if (!rsRandi (4)) // interpolate really fast sometimes
627 interpconst = 0.1f;
628 }
629 // Update particles
630 for (i = 0; i < dEmitters; i++) {
631 elist[i].interppos (interp);
632 elist[i].update ();
633 }
634 for (i = 0; i < dAttracters; i++) {
635 alist[i].interppos (interp);
636 alist[i].update ();
637 }
638 for (i = 0; i < ionsReleased; i++)
639 ilist[i].update ();
640
641 // Calculate surface
642 if (dSurface) {
643 for (i = 0; i < dEmitters; i++)
644 spheres[i].setPosition (elist[i].pos[0], elist[i].pos[1], elist[i].pos[2]);
645 for (i = 0; i < dAttracters; i++)
646 spheres[dEmitters + i].setPosition (alist[i].pos[0], alist[i].pos[1], alist[i].pos[2]);
647
648 impCrawlPointVector cpv;
649 for(i=0; i<dEmitters+dAttracters; i++)
650 spheres[i].addCrawlPoint(cpv);
651
652 surface->reset ();
653
654 static float valuetrig = 0.0f;
655 valuetrig += elapsedTime;
656
657 volume->setSurfaceValue(0.45f + 0.05f * cosf(valuetrig));
658 volume->makeSurface(cpv);
659 }
660 // Draw
661 // clear the screen
662 if (dBlur) { // partially
663 glMatrixMode (GL_PROJECTION);
664 glPushMatrix ();
665 glLoadIdentity();
666 glOrtho(0.0, 1.0, 0.0, 1.0, 1.0, -1.0);
667 glMatrixMode(GL_MODELVIEW);
668 glPushMatrix();
669 glLoadIdentity();
670 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
671 glColor4f(0.0f, 0.0f, 0.0f, 0.5f - (float(sqrtf(sqrtf(float(dBlur)))) * 0.15495f));
672 glBegin(GL_TRIANGLE_STRIP);
673 glVertex3f(0.0f, 0.0f, 0.0f);
674 glVertex3f(1.0f, 0.0f, 0.0f);
675 glVertex3f(0.0f, 1.0f, 0.0f);
676 glVertex3f(1.0f, 1.0f, 0.0f);
677 glEnd();
678 glPopMatrix();
679 glMatrixMode(GL_PROJECTION);
680 glPopMatrix();
681 } else // completely
682 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
683
684 // Draw ions
685 glMatrixMode(GL_MODELVIEW);
686 glBlendFunc (GL_ONE, GL_ONE);
687 glBindTexture (GL_TEXTURE_2D, 1);
688 for (i = 0; i < ionsReleased; i++)
689 ilist[i].draw ();
690
691 // Draw surfaces
692 float brightFactor = 0;
693 float surfaceColor[3] = {
694 0.0f,
695 0.0f,
696 0.0f
697 };
698
699 if (dSurface) {
700 glBindTexture (GL_TEXTURE_2D, 2);
701 glEnable (GL_TEXTURE_GEN_S);
702 glEnable (GL_TEXTURE_GEN_T);
703 // find color for surfaces
704 if (dIons >= 100) {
705 if (dWireframe)
706 brightFactor = 2.0f / (float (dBlur + 30) * float (dBlur + 30));
707 else
708 brightFactor = 4.0f / (float (dBlur + 30) * float (dBlur + 30));
709 for (i = 0; i < 100; i++) {
710 surfaceColor[0] += ilist[i].rgb[0] * brightFactor;
711 surfaceColor[1] += ilist[i].rgb[1] * brightFactor;
712 surfaceColor[2] += ilist[i].rgb[2] * brightFactor;
713 }
714 glColor3fv (surfaceColor);
715 } else {
716 if (dWireframe)
717 brightFactor = 200.0f / (float (dBlur + 30) * float (dBlur + 30));
718 else
719 brightFactor = 400.0f / (float (dBlur + 30) * float (dBlur + 30));
720 glColor3f (newRgb[0] * brightFactor, newRgb[1] * brightFactor, newRgb[2] * brightFactor);
721 }
722 // draw the surface
723 glPushMatrix ();
724 glMultMatrixf (billboardMat);
725 if (dWireframe) {
726 glDisable (GL_TEXTURE_2D);
727 surface->draw_wireframe ();
728 glEnable (GL_TEXTURE_2D);
729 } else
730 surface->draw ();
731 glPopMatrix ();
732 glDisable (GL_TEXTURE_GEN_S);
733 glDisable (GL_TEXTURE_GEN_T);
734 }
735 // If graphics card does a true buffer swap instead of a copy swap
736 // then everything must get drawn on both buffers
737 if (dBlur & pfd_swap_exchange) {
738 glXSwapBuffers (dpy, window);
739 // wglSwapLayerBuffers(hdc, WGL_SWAP_MAIN_PLANE);
740 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
741 glColor4f (0.0f, 0.0f, 0.0f, 0.5f - (float (sqrt (sqrt (double (dBlur)))) * 0.15495f));
742
743 glPushMatrix ();
744 glLoadIdentity ();
745 glBegin (GL_TRIANGLE_STRIP);
746 glVertex3f (-5.0f, -4.0f, -3.0f);
747 glVertex3f (5.0f, -4.0f, -3.0f);
748 glVertex3f (-5.0f, 4.0f, -3.0f);
749 glVertex3f (5.0f, 4.0f, -3.0f);
750 glEnd ();
751 glPopMatrix ();
752
753 // Draw ions
754 glBlendFunc (GL_ONE, GL_ONE);
755 glBindTexture (GL_TEXTURE_2D, 1);
756 for (i = 0; i < ionsReleased; i++)
757 ilist[i].draw ();
758
759 // Draw surfaces
760 if (dSurface) {
761 glBindTexture (GL_TEXTURE_2D, 2);
762 glEnable (GL_TEXTURE_GEN_S);
763 glEnable (GL_TEXTURE_GEN_T);
764 if (dIons >= 100)
765 glColor3fv (surfaceColor);
766 else
767 glColor3f (newRgb[0] * brightFactor, newRgb[1] * brightFactor, newRgb[2] * brightFactor);
768 glPushMatrix ();
769 glMultMatrixf (billboardMat);
770 if (dWireframe) {
771 glDisable (GL_TEXTURE_2D);
772 surface->draw_wireframe ();
773 glEnable (GL_TEXTURE_2D);
774 } else
775 surface->draw ();
776 glPopMatrix ();
777 glDisable (GL_TEXTURE_GEN_S);
778 glDisable (GL_TEXTURE_GEN_T);
779 }
780 }
781 }
782
hack_reshape(xstuff_t * XStuff)783 void hack_reshape (xstuff_t * XStuff)
784 {
785 glViewport (0, 0, XStuff->windowWidth, XStuff->windowHeight);
786
787 glMatrixMode (GL_PROJECTION);
788 glLoadIdentity ();
789 gluPerspective (60.0, float (XStuff->windowWidth) / float (XStuff->windowHeight), 0.1, 10000.0f);
790 }
791
hack_init(xstuff_t * XStuff)792 void hack_init (xstuff_t * XStuff)
793 {
794 int i, j;
795 float x, y, temp;
796 unsigned char *tex;
797
798 // Window initialization
799 hack_reshape (XStuff);
800
801 glDisable (GL_DEPTH_TEST);
802 glEnable (GL_BLEND);
803 glLightModeli (GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
804
805 // Clear the buffers and test for type of buffer swapping
806 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
807 glXSwapBuffers (XStuff->display, XStuff->window); // wglSwapLayerBuffers(hdc, WGL_SWAP_MAIN_PLANE);
808 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
809 unsigned char pixel[1] = { 255 };
810
811 glRasterPos2i (0, 0);
812 glDrawPixels (1, 1, GL_RED, GL_UNSIGNED_BYTE, pixel);
813 glXSwapBuffers (XStuff->display, XStuff->window); // wglSwapLayerBuffers(hdc, WGL_SWAP_MAIN_PLANE);
814 glReadPixels (0, 0, 1, 1, GL_RED, GL_UNSIGNED_BYTE, pixel);
815
816 if (pixel[0] == 0) { // Color was swapped out of the back buffer
817 pfd_swap_exchange = 1;
818 } else { // Color remains in back buffer
819 pfd_swap_exchange = 0;
820 }
821
822 // Init light texture
823 for (i = 0; i < LIGHTSIZE; i++) {
824 for (j = 0; j < LIGHTSIZE; j++) {
825 x = float (i - LIGHTSIZE / 2) / float (LIGHTSIZE / 2);
826 y = float (j - LIGHTSIZE / 2) / float (LIGHTSIZE / 2);
827 temp = 1.0f - float (sqrt ((x * x) + (y * y)));
828
829 if (temp > 1.0f)
830 temp = 1.0f;
831 if (temp < 0.0f)
832 temp = 0.0f;
833 lightTexture[i][j] = char (255.0f * temp * temp);
834 }
835 }
836
837 glBindTexture (GL_TEXTURE_2D, 1);
838 glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
839 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
840 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
841 gluBuild2DMipmaps (GL_TEXTURE_2D, 1, LIGHTSIZE, LIGHTSIZE, GL_LUMINANCE, GL_UNSIGNED_BYTE, lightTexture);
842 glBindTexture (GL_TEXTURE_2D, 2);
843 glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
844 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
845 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
846
847 LOAD_TEXTURE (tex, spheremap, spheremap_compressedsize, spheremap_size)
848 gluBuild2DMipmaps (GL_TEXTURE_2D, 3, TEXSIZE, TEXSIZE, GL_RGB, GL_UNSIGNED_BYTE, tex);
849 FREE_TEXTURE (tex)
850
851 glTexGeni (GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
852 glTexGeni (GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
853 glEnable (GL_TEXTURE_2D);
854
855 // Initialize light display list
856 glNewList (1, GL_COMPILE);
857 glBindTexture (GL_TEXTURE_2D, 1);
858 glBegin (GL_TRIANGLES);
859 glTexCoord2f (0.0f, 0.0f);
860 glVertex3f (-0.5f, -0.5f, 0.0f);
861 glTexCoord2f (1.0f, 0.0f);
862 glVertex3f (0.5f, -0.5f, 0.0f);
863 glTexCoord2f (1.0f, 1.0f);
864 glVertex3f (0.5f, 0.5f, 0.0f);
865 glTexCoord2f (0.0f, 0.0f);
866 glVertex3f (-0.5f, -0.5f, 0.0f);
867 glTexCoord2f (1.0f, 1.0f);
868 glVertex3f (0.5f, 0.5f, 0.0f);
869 glTexCoord2f (0.0f, 1.0f);
870 glVertex3f (-0.5f, 0.5f, 0.0f);
871 glEnd ();
872 glEndList ();
873
874 // Initialize particles
875 elist = new emitter[dEmitters];
876 alist = new attracter[dAttracters];
877 ilist = new ion[dIons];
878
879 // Initialize surface
880 if (dSurface) {
881 volume = new impCubeVolume;
882 volume->init (50, 50, 50, 35.0f);
883 volume->function = surfaceFunction;
884 surface = volume->getSurface();
885
886 spheres = new impSphere[dEmitters + dAttracters];
887
888 float sphereScaleFactor = 1.0f / sqrtf (double (2 * dEmitters + dAttracters));
889 for (i = 0; i < dEmitters; i++)
890 spheres[i].setThickness (400.0f * sphereScaleFactor);
891 for (i = 0; i < dAttracters; i++)
892 spheres[i + dEmitters].setThickness (200.0f * sphereScaleFactor);
893 }
894 }
895
hack_cleanup(xstuff_t * XStuff)896 void hack_cleanup (xstuff_t * XStuff)
897 {
898 glDeleteLists (1, 1);
899 }
900
hack_handle_opts(int argc,char ** argv)901 void hack_handle_opts (int argc, char **argv)
902 {
903 dIons = 1500;
904 dSize = 10;
905 dEmitters = 3;
906 dAttracters = 3;
907 dSpeed = 10;
908 dCameraspeed = 10;
909 dSurface = 1;
910 dWireframe = 0;
911 dBlur = 10;
912
913 while (1) {
914 int c;
915
916 #ifdef HAVE_GETOPT_H
917 static struct option long_options[] = {
918 {"help", 0, 0, 'h'},
919 DRIVER_OPTIONS_LONG {"ions", 1, 0, 'i'},
920 {"size", 1, 0, 's'},
921 {"emitters", 1, 0, 'e'},
922 {"attracters", 1, 0, 'a'},
923 {"speed", 1, 0, 'S'},
924 {"cameraspeed", 1, 0, 'c'},
925 {"surface", 0, 0, 'u'},
926 {"no-surface", 0, 0, 'U'},
927 {"blur", 1, 0, 'b'},
928 {"wireframe", 0, 0, 'w'},
929 {"no-wireframe", 0, 0, 'W'},
930 {0, 0, 0, 0}
931 };
932
933 c = getopt_long (argc, argv, DRIVER_OPTIONS_SHORT "hi:s:e:a:S:c:uUb:wW", long_options, NULL);
934 #else
935 c = getopt (argc, argv, DRIVER_OPTIONS_SHORT "hi:s:e:a:S:c:uUb:wW");
936 #endif
937 if (c == -1)
938 break;
939
940 switch (c) {
941 DRIVER_OPTIONS_CASES case 'h':printf ("%s:"
942 #ifndef HAVE_GETOPT_H
943 " Not built with GNU getopt.h, long options *NOT* enabled."
944 #endif
945 "\n" DRIVER_OPTIONS_HELP "\t--ions/-i <arg>\n" "\t--size/-s <arg>\n" "\t--emitters/-e <arg>\n"
946 "\t--attracters/-a <arg>\n" "\t--speed/-S <arg>\n" "\t--cameraspeed/-c <arg>\n" "\t--surface/-u\n"
947 "\t--no-surface/-U\n" "\t--blur/-b <arg>\n" "\t--wireframe/-w\n" "\t--no-wireframe/-W\n", argv[0]);
948 exit (1);
949 case 'i':
950 dIons = strtol_minmaxdef (optarg, 10, 0, 30000, 1, 1500, "--ions: ");
951 break;
952 case 's':
953 dSize = strtol_minmaxdef (optarg, 10, 1, 100, 1, 10, "--size: ");
954 break;
955 case 'e':
956 dEmitters = strtol_minmaxdef (optarg, 10, 1, 10, 1, 3, "--emitters: ");
957 break;
958 case 'a':
959 dAttracters = strtol_minmaxdef (optarg, 10, 1, 10, 1, 3, "--attracters: ");
960 break;
961 case 'S':
962 dSpeed = strtol_minmaxdef (optarg, 10, 1, 100, 1, 10, "--speed: ");
963 break;
964 case 'c':
965 dCameraspeed = strtol_minmaxdef (optarg, 10, 0, 100, 1, 10, "--cameraspeed: ");
966 break;
967 case 'u':
968 dSurface = 1;
969 break;
970 case 'U':
971 dSurface = 0;
972 break;
973 case 'b':
974 dBlur = strtol_minmaxdef (optarg, 10, 0, 100, 1, 10, "--blur: ");
975 break;
976 case 'w':
977 dWireframe = 1;
978 break;
979 case 'W':
980 dWireframe = 0;
981 break;
982 }
983 }
984 }
985