Back to index

kdeartwork  4.3.2
Flux.cpp
Go to the documentation of this file.
00001 /*
00002  *  Terence Welsh Screensaver - Flux
00003  *  http://www.reallyslick.com/
00004  *
00005  *  Ported to KDE by Karl Robillard
00006  *  Copyright (C) 2002  Terence M. Welsh
00007  *
00008  *  This program is free software; you can redistribute it and/or
00009  *  modify it under the terms of the GNU General Public License as
00010  *  published by the Free Software Foundation; either version 2 of 
00011  *  the License, or (at your option) any later version.
00012  *   
00013  *  This program is distributed in the hope that it will be useful,
00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *  GNU General Public License for more details.
00017  *   
00018  *  You should have received a copy of the GNU General Public License
00019  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00020  */
00021 
00022 /*
00023   TODO
00024 
00025   [ ] Regular and others are messed up after Sparkler.
00026       Insane seems to reset them.
00027 */
00028 
00029 
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include <math.h>
00033 #include <time.h>
00034 #include <qtimer.h>
00035 
00036 #include "Flux.h"
00037 #include "Flux.moc"
00038 
00039 
00040 #define NUMCONSTS   8
00041 #define PIx2        6.28318530718f
00042 #define DEG2RAD     0.0174532925f
00043 
00044 
00045 void hsl2rgb(float h, float s, float l, float &r, float &g, float &b)
00046 {
00047     // hue influence
00048     if(h < 0.166667){  // full red, some green
00049         r = 1.0;
00050         g = h * 6.0f;
00051         b = 0.0;
00052     }
00053     else {
00054         if(h < 0.5){  // full green
00055             g = 1.0;
00056             if(h < 0.333333){  // some red
00057                 r = 1.0f - ((h - 0.166667f) * 6.0f);
00058                 b = 0.0;
00059             }
00060             else{  // some blue
00061                 b = (h - 0.333333f) * 6.0f;
00062                 r = 0.0;
00063             }
00064         }
00065         else{
00066             if(h < 0.833333){  // full blue
00067                 b = 1.0;
00068                 if(h < 0.666667){  // some green
00069                     g = 1.0f - ((h - 0.5f) * 6.0f);
00070                     r = 0.0;
00071                 }
00072                 else{  // some red
00073                     r = (h - 0.666667f) * 6.0f;
00074                     g = 0.0;
00075                 }
00076             }
00077             else{  // full red, some blue
00078                 r = 1.0;
00079                 b = 1.0f - ((h - 0.833333f) * 6.0f);
00080                 g = 0.0;
00081             }
00082         }
00083     }
00084 
00085     // saturation influence
00086     r = 1.0f - (s * (1.0f - r));
00087     g = 1.0f - (s * (1.0f - g));
00088     b = 1.0f - (s * (1.0f - b));
00089 
00090     // luminosity influence
00091     r *= l;
00092     g *= l;
00093     b *= l;
00094 }
00095 
00096 
00097 // Useful random number macros
00098 // Don't forget to initialize with srand()
00099 inline int myRandi(int x){
00100     return((rand() * x) / RAND_MAX);
00101 }
00102 inline float myRandf(float x){
00103     return(float(rand() * x) / float(RAND_MAX));
00104 }
00105 
00106 
00107 //----------------------------------------------------------------------------
00108 
00109 
00110 // Flux context to allow many instances.
00111 static FluxWidget* _fc = 0;
00112 
00113 static int whichparticle;
00114 
00115 
00116 // This class is poorly named.  It's actually a whole trail of particles.
00117 class particle
00118 {
00119 public:
00120 
00121     particle();
00122     ~particle();
00123     float update(float *c);
00124 
00125 private:
00126 
00127     float** vertices;
00128     short trails;
00129     short counter;
00130     float offset[3];
00131 };
00132 
00133 
00134 particle::particle()
00135 {
00136     // Offsets are somewhat like default positions for the head of each
00137     // particle trail.  Offsets spread out the particle trails and keep
00138     // them from all overlapping.
00139     offset[0] = cos(PIx2 * float(whichparticle) / float(_fc->dParticles));
00140     offset[1] = float(whichparticle) / float(_fc->dParticles) - 0.5f;
00141     offset[2] = sin(PIx2 * float(whichparticle) / float(_fc->dParticles));
00142     whichparticle++;
00143 
00144     // Initialize memory and set initial positions out of view of the camera
00145     trails = _fc->dTrail;
00146     vertices = new float*[ trails ];
00147 
00148     int i;
00149     for(i=0; i<trails; i++)
00150     {
00151         vertices[i] = new float[5];  // 0,1,2 = position, 3 = hue, 4 = saturation
00152         vertices[i][0] = 0.0f;
00153         vertices[i][1] = 3.0f;
00154         vertices[i][2] = 0.0f;
00155         vertices[i][3] = 0.0f;
00156         vertices[i][4] = 0.0f;
00157     }
00158 
00159     counter = 0;
00160 }
00161 
00162 
00163 particle::~particle()
00164 {
00165     for(int i=0; i<trails; i++)
00166         delete[] vertices[i];
00167     delete[] vertices;
00168 }
00169 
00170 
00171 float particle::update(float *c)
00172 {
00173     int i, p, growth;
00174     float rgb[3];
00175     float cx, cy, cz;  // Containment variables
00176     float luminosity;
00177     static float expander = 1.0f + 0.0005f * float(_fc->dExpansion);
00178     static float blower = 0.001f * float(_fc->dWind);
00179     //static float otherxyz[3];
00180     float depth = 0;
00181 
00182     // Record old position
00183     int oldc = counter;
00184     float oldpos[3];
00185     oldpos[0] = vertices[oldc][0];
00186     oldpos[1] = vertices[oldc][1];
00187     oldpos[2] = vertices[oldc][2];
00188 
00189     counter ++;
00190     if(counter >= _fc->dTrail)
00191         counter = 0;
00192 
00193     // Here's the iterative math for calculating new vertex positions
00194     // first calculate limiting terms which keep vertices from constantly
00195     // flying off to infinity
00196     cx = vertices[oldc][0] * (1.0f - 1.0f / (vertices[oldc][0] * vertices[oldc][0] + 1.0f));
00197     cy = vertices[oldc][1] * (1.0f - 1.0f / (vertices[oldc][1] * vertices[oldc][1] + 1.0f));
00198     cz = vertices[oldc][2] * (1.0f - 1.0f / (vertices[oldc][2] * vertices[oldc][2] + 1.0f));
00199     // then calculate new positions
00200     vertices[counter][0] = vertices[oldc][0] + c[6] * offset[0] - cx
00201         + c[2] * vertices[oldc][1]
00202         + c[5] * vertices[oldc][2];
00203     vertices[counter][1] = vertices[oldc][1] + c[6] * offset[1] - cy
00204         + c[1] * vertices[oldc][2]
00205         + c[4] * vertices[oldc][0];
00206     vertices[counter][2] = vertices[oldc][2] + c[6] * offset[2] - cz
00207         + c[0] * vertices[oldc][0]
00208         + c[3] * vertices[oldc][1];
00209 
00210     // Pick a hue
00211     vertices[counter][3] = cx * cx + cy * cy + cz * cz;
00212     if(vertices[counter][3] > 1.0f)
00213         vertices[counter][3] = 1.0f;
00214     vertices[counter][3] += c[7];
00215     // Limit the hue (0 - 1)
00216     if(vertices[counter][3] > 1.0f)
00217         vertices[counter][3] -= 1.0f;
00218     if(vertices[counter][3] < 0.0f)
00219         vertices[counter][3] += 1.0f;
00220     // Pick a saturation
00221     vertices[counter][4] = c[0] + vertices[counter][3];
00222     // Limit the saturation (0 - 1)
00223     if(vertices[counter][4] < 0.0f)
00224         vertices[counter][4] = -vertices[counter][4];
00225     vertices[counter][4] -= float(int(vertices[counter][4]));
00226     vertices[counter][4] = 1.0f - (vertices[counter][4] * vertices[counter][4]);
00227 
00228     // Bring particles back if they escape
00229     if(!counter){
00230         if((vertices[0][0] > 1000000000.0f) || (vertices[0][0] < -1000000000.0f)
00231             || (vertices[0][1] > 1000000000.0f) || (vertices[0][1] < -1000000000.0f)
00232             || (vertices[2][2] > 1000000000.0f) || (vertices[0][2] < -1000000000.0f)){
00233             vertices[0][0] = myRandf(2.0f) - 1.0f;
00234             vertices[0][1] = myRandf(2.0f) - 1.0f;
00235             vertices[0][2] = myRandf(2.0f) - 1.0f;
00236         }
00237     }
00238 
00239     // Draw every vertex in particle trail
00240     p = counter;
00241     growth = 0;
00242     luminosity = _fc->lumdiff;
00243     for(i=0; i<_fc->dTrail; i++){
00244         p ++;
00245         if(p >= _fc->dTrail)
00246             p = 0;
00247         growth++;
00248 
00249         // assign color to particle
00250         hsl2rgb(vertices[p][3], vertices[p][4], luminosity, rgb[0], rgb[1], rgb[2]);
00251         glColor3fv(rgb);
00252 
00253         glPushMatrix();
00254         if(_fc->dGeometry == 1)  // Spheres
00255             glTranslatef(vertices[p][0], vertices[p][1], vertices[p][2]);
00256         else{  // Points or lights
00257             depth = _fc->cosCameraAngle * vertices[p][2] - _fc->sinCameraAngle * vertices[p][0];
00258             glTranslatef(_fc->cosCameraAngle * vertices[p][0] + _fc->sinCameraAngle
00259                 * vertices[p][2], vertices[p][1], depth);
00260         }
00261         if(_fc->dGeometry){  // Spheres or lights
00262             switch(_fc->dTrail - growth){
00263             case 0:
00264                 glScalef(0.259f, 0.259f, 0.259f);
00265                 break;
00266             case 1:
00267                 glScalef(0.5f, 0.5f, 0.5f);
00268                 break;
00269             case 2:
00270                 glScalef(0.707f, 0.707f, 0.707f);
00271                 break;
00272             case 3:
00273                 glScalef(0.866f, 0.866f, 0.866f);
00274                 break;
00275             case 4:
00276                 glScalef(0.966f, 0.966f, 0.966f);
00277             }
00278         }
00279         switch(_fc->dGeometry){
00280         case 0:  // Points
00281             switch(_fc->dTrail - growth){
00282             case 0:
00283                 glPointSize(float(_fc->dSize * (depth + 200.0f) * 0.001036f));
00284                 break;
00285             case 1:
00286                 glPointSize(float(_fc->dSize * (depth + 200.0f) * 0.002f));
00287                 break;
00288             case 2:
00289                 glPointSize(float(_fc->dSize * (depth + 200.0f) * 0.002828f));
00290                 break;
00291             case 3:
00292                 glPointSize(float(_fc->dSize * (depth + 200.0f) * 0.003464f));
00293                 break;
00294             case 4:
00295                 glPointSize(float(_fc->dSize * (depth + 200.0f) * 0.003864f));
00296                 break;
00297             default:
00298                 glPointSize(float(_fc->dSize * (depth + 200.0f) * 0.004f));
00299             }
00300             glBegin(GL_POINTS);
00301                 glVertex3f(0.0f,0.0f,0.0f);
00302             glEnd();
00303             break;
00304         case 1:  // Spheres
00305         case 2:  // Lights
00306             glCallList(1);
00307         }
00308         glPopMatrix();
00309         vertices[p][0] *= expander;
00310         vertices[p][1] *= expander;
00311         vertices[p][2] *= expander;
00312         vertices[p][2] += blower;
00313         luminosity += _fc->lumdiff;
00314     }
00315 
00316     // Find distance between new position and old position and return it
00317     oldpos[0] -= vertices[counter][0];
00318     oldpos[1] -= vertices[counter][1];
00319     oldpos[2] -= vertices[counter][2];
00320     return(float(sqrt(oldpos[0] * oldpos[0] + oldpos[1] * oldpos[1] + oldpos[2] * oldpos[2])));
00321 }
00322 
00323 
00324 // This class is a set of particle trails and constants that enter
00325 // into their equations of motion.
00326 class flux
00327 {
00328 public:
00329 
00330     flux();
00331     ~flux();
00332     void update();
00333 
00334     particle *particles;
00335     int randomize;
00336     float c[NUMCONSTS];     // constants
00337     float cv[NUMCONSTS];    // constants' change velocities
00338     int currentSmartConstant;
00339     float oldDistance;
00340 };
00341 
00342 
00343 flux::flux()
00344 {
00345     whichparticle = 0;
00346 
00347     particles = new particle[_fc->dParticles];
00348     randomize = 1;
00349 
00350     float instability = _fc->dInstability;
00351     int i;
00352     for(i=0; i<NUMCONSTS; i++)
00353     {
00354         c[i] = myRandf(2.0f) - 1.0f;
00355         cv[i] = myRandf(0.000005f * instability * instability)
00356                 + 0.000001f * instability * instability;
00357     }
00358 
00359     currentSmartConstant = 0;
00360     oldDistance = 0.0f;
00361 }
00362 
00363 
00364 flux::~flux()
00365 {
00366     delete[] particles;
00367 }
00368 
00369 
00370 void flux::update()
00371 {
00372     int i;
00373 
00374     // randomize constants
00375     if(_fc->dRandomize){
00376         randomize --;
00377         if(randomize <= 0){
00378             for(i=0; i<NUMCONSTS; i++)
00379                 c[i] = myRandf(2.0f) - 1.0f;
00380             int temp = 101 - _fc->dRandomize;
00381             temp = temp * temp;
00382             randomize = temp + myRandi(temp);
00383         }
00384     }
00385 
00386     // update constants
00387     for(i=0; i<NUMCONSTS; i++){
00388         c[i] += cv[i];
00389         if(c[i] >= 1.0f){
00390             c[i] = 1.0f;
00391             cv[i] = -cv[i];
00392         }
00393         if(c[i] <= -1.0f){
00394             c[i] = -1.0f;
00395             cv[i] = -cv[i];
00396         }
00397     }
00398 
00399     // update all particles in this flux field
00400     float dist;
00401     for(i=0; i<_fc->dParticles; i++)
00402         dist = particles[i].update(c);
00403 
00404     // use dist from last particle to activate smart constants
00405     _fc->dSmart = 0;
00406     if(_fc->dSmart){
00407         const float upper = 0.4f;
00408         const float lower = 0.2f;
00409         int beSmart = 0;
00410         if(dist > upper && dist > oldDistance)
00411             beSmart = 1;
00412         if(dist < lower && dist < oldDistance)
00413             beSmart = 1;
00414         if(beSmart){
00415             cv[currentSmartConstant] = -cv[currentSmartConstant];
00416             currentSmartConstant ++;
00417             if(currentSmartConstant >= _fc->dSmart)
00418                 currentSmartConstant = 0;
00419         }
00420         oldDistance = dist;
00421     }
00422 }
00423 
00424 
00425 //----------------------------------------------------------------------------
00426 
00427 
00428 FluxWidget::FluxWidget( QWidget* parent )
00429                       : QGLWidget(parent), _fluxes(0)
00430 {
00431     setDefaults( Regular );
00432 
00433     _frameTime = 1000 / 60;
00434     _timer = new QTimer( this );
00435     connect( _timer, SIGNAL(timeout()), this, SLOT(nextFrame()) );
00436 }
00437 
00438 
00439 FluxWidget::~FluxWidget()
00440 {
00441     // Free memory
00442     delete[] _fluxes;
00443 }
00444 
00445 
00446 void FluxWidget::paintGL()
00447 {
00448     // clear the screen
00449     glLoadIdentity();
00450 
00451     if(dBlur)   // partially
00452     {
00453         int viewport[4];
00454         glGetIntegerv(GL_VIEWPORT, viewport);
00455         float viewRatio = float(viewport[2]) / float(viewport[3]);
00456 
00457         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00458         glEnable(GL_BLEND);
00459         glDisable(GL_DEPTH_TEST);
00460         glColor4f(0.0f, 0.0f, 0.0f, 0.5f - (float(sqrt(sqrt(double(dBlur)))) * 0.15495f));
00461         glBegin(GL_TRIANGLE_STRIP);
00462             glVertex3f(-3.0f * viewRatio, -3.0f, 0.0f);
00463             glVertex3f(3.0f * viewRatio, -3.0f, 0.0f);
00464             glVertex3f(-3.0f * viewRatio, 3.0f, 0.0f);
00465             glVertex3f(3.0f * viewRatio, 3.0f, 0.0f);
00466         glEnd();
00467     }
00468     else  // completely
00469     {
00470         glClear(GL_COLOR_BUFFER_BIT);
00471     }
00472 
00473     cameraAngle += 0.01f * float(dRotation);
00474     if(cameraAngle >= 360.0f)
00475         cameraAngle -= 360.0f;
00476     if(dGeometry == 1)  // Only rotate for spheres
00477         glRotatef(cameraAngle, 0.0f, 1.0f, 0.0f);
00478     else
00479     {
00480         cosCameraAngle = cos(cameraAngle * DEG2RAD);
00481         sinCameraAngle = sin(cameraAngle * DEG2RAD);
00482     }
00483 
00484     // set up blend modes for rendering particles
00485     switch(dGeometry)
00486     {
00487     case 0:  // Blending for points
00488         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
00489         glEnable(GL_BLEND);
00490         glEnable(GL_POINT_SMOOTH);
00491         glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
00492         break;
00493 
00494     case 1:  // No blending for spheres, but we need z-buffering
00495         glDisable(GL_BLEND);
00496         glEnable(GL_DEPTH_TEST);
00497         glClear(GL_DEPTH_BUFFER_BIT);
00498         break;
00499 
00500     case 2:  // Blending for lights
00501         glBlendFunc(GL_ONE, GL_ONE);
00502         glEnable(GL_BLEND);
00503     }
00504 
00505     // Update particles
00506     if( _fluxes )
00507     {
00508         _fc = this;
00509         int i;
00510         for(i=0; i<dFluxes; i++)
00511             _fluxes[i].update();
00512     }
00513 
00514     glFlush();
00515 }
00516 
00517 
00518 void FluxWidget::resizeGL( int w, int h )
00519 {
00520     glViewport(0, 0, w, h );
00521 
00522     glMatrixMode(GL_PROJECTION);
00523     glLoadIdentity();
00524     gluPerspective(100.0, (float) w / (float) h, 0.01, 200);
00525     glTranslatef(0.0, 0.0, -2.5);
00526     glMatrixMode(GL_MODELVIEW);
00527     glLoadIdentity();
00528 }
00529 
00530 
00531 // Window initialization
00532 void FluxWidget::initializeGL()
00533 {
00534     //resizeGL( width(), height() );
00535 
00536     updateParameters();
00537     _timer->setSingleShot(true);
00538     _timer->start( _frameTime );
00539 }
00540 
00541 
00542 #ifdef UNIT_TEST
00543 void FluxWidget::keyPressEvent( QKeyEvent* e )
00544 {
00545     if( e->key() == Qt::Key_0 ) { setDefaults( 0 ); updateParameters(); }
00546     if( e->key() == Qt::Key_1 ) { setDefaults( 1 ); updateParameters(); }
00547     if( e->key() == Qt::Key_2 ) { setDefaults( 2 ); updateParameters(); }
00548     if( e->key() == Qt::Key_3 ) { setDefaults( 3 ); updateParameters(); }
00549     if( e->key() == Qt::Key_4 ) { setDefaults( 4 ); updateParameters(); }
00550     if( e->key() == Qt::Key_5 ) { setDefaults( 5 ); updateParameters(); }
00551 }
00552 #endif
00553 
00554 
00555 void FluxWidget::nextFrame()
00556 {
00557     updateGL();
00558     _timer->setSingleShot(true);
00559     _timer->start( _frameTime );
00560 }
00561 
00562 
00566 void FluxWidget::setDefaults( int which )
00567 {
00568     switch(which)
00569     {
00570     case Hypnotic:
00571         dFluxes = 2;
00572         dParticles = 10;
00573         dTrail = 40;
00574         dGeometry = 2;
00575         dSize = 15;
00576         dRandomize = 80;
00577         dExpansion = 20;
00578         dRotation = 0;
00579         dWind = 40;
00580         dInstability = 10;
00581         dBlur = 30;
00582         break;
00583 
00584     case Insane:
00585         dFluxes = 4;
00586         dParticles = 30;
00587         dTrail = 8;
00588         dGeometry = 2;
00589         dSize = 25;
00590         dRandomize = 0;
00591         dExpansion = 80;
00592         dRotation = 60;
00593         dWind = 40;
00594         dInstability = 100;
00595         dBlur = 10;
00596         break;
00597 
00598     case Sparklers:
00599         dFluxes = 3;
00600         dParticles = 20;
00601         dTrail = 6;
00602         dGeometry = 1;
00603         dSize = 20;
00604         dComplexity = 3;
00605         dRandomize = 85;
00606         dExpansion = 60;
00607         dRotation = 30;
00608         dWind = 20;
00609         dInstability = 30;
00610         dBlur = 0;
00611         break;
00612 
00613     case Paradigm:
00614         dFluxes = 1;
00615         dParticles = 40;
00616         dTrail = 40;
00617         dGeometry = 2;
00618         dSize = 5;
00619         dRandomize = 90;
00620         dExpansion = 30;
00621         dRotation = 20;
00622         dWind = 10;
00623         dInstability = 5;
00624         dBlur = 10;
00625         break;
00626 
00627     case Galactic:
00628         dFluxes = 1;
00629         dParticles = 2;
00630         dTrail = 1500;
00631         dGeometry = 2;
00632         dSize = 10;
00633         dRandomize = 0;
00634         dExpansion = 5;
00635         dRotation = 25;
00636         dWind = 0;
00637         dInstability = 5;
00638         dBlur = 0;
00639         break;
00640 
00641     case Regular:
00642     default:
00643         dFluxes = 1;
00644         dParticles = 20;
00645         dTrail = 40;
00646         dGeometry = 2;
00647         dSize = 15;
00648         dRandomize = 0;
00649         dExpansion = 40;
00650         dRotation = 30;
00651         dWind = 20;
00652         dInstability = 20;
00653         dBlur = 0;
00654         break;
00655     }
00656 }
00657 
00658 
00663 void FluxWidget::updateParameters()
00664 {
00665     int i, j;
00666     float x, y, temp;
00667 
00668     srand((unsigned)time(NULL));
00669     rand(); rand(); rand(); rand(); rand();
00670 
00671     cameraAngle = 0.0f;
00672 
00673     glFrontFace(GL_CCW);
00674     glEnable(GL_CULL_FACE);
00675     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
00676     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00677 
00678     if(dGeometry == 0)
00679     {
00680         glDisable(GL_LIGHTING);
00681         glDisable(GL_COLOR_MATERIAL);
00682         glDisable(GL_TEXTURE_2D);
00683 
00684         glEnable(GL_POINT_SMOOTH);
00685         //glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
00686     }
00687     else if(dGeometry == 1)      // Spheres and their lighting
00688     {
00689         glNewList(1, GL_COMPILE);
00690         GLUquadricObj* qobj = gluNewQuadric();
00691         gluSphere(qobj, 0.005f * dSize, dComplexity + 2, dComplexity + 1);
00692         gluDeleteQuadric(qobj);
00693         glEndList();
00694 
00695         glDisable(GL_TEXTURE_2D);
00696         glEnable(GL_LIGHTING);
00697         glEnable(GL_LIGHT0);
00698 
00699         float ambient[4] = {0.0f, 0.0f, 0.0f, 0.0f};
00700         float diffuse[4] = {1.0f, 1.0f, 1.0f, 0.0f};
00701         float specular[4] = {1.0f, 1.0f, 1.0f, 0.0f};
00702         float position[4] = {500.0f, 500.0f, 500.0f, 0.0f};
00703 
00704         glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
00705         glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
00706         glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
00707         glLightfv(GL_LIGHT0, GL_POSITION, position);
00708         glEnable(GL_COLOR_MATERIAL);
00709         glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
00710     }
00711     else if(dGeometry == 2)      // Init lights
00712     {
00713         for(i=0; i<LIGHTSIZE; i++)
00714         {
00715             for(j=0; j<LIGHTSIZE; j++)
00716             {
00717                 x = float(i - LIGHTSIZE / 2) / float(LIGHTSIZE / 2);
00718                 y = float(j - LIGHTSIZE / 2) / float(LIGHTSIZE / 2);
00719                 temp = 1.0f - float(sqrt((x * x) + (y * y)));
00720                 if(temp > 1.0f)
00721                     temp = 1.0f;
00722                 if(temp < 0.0f)
00723                     temp = 0.0f;
00724                 lightTexture[i][j] = (unsigned char) (255.0f * temp * temp);
00725             }
00726         }
00727 
00728         glDisable(GL_LIGHTING);
00729         glDisable(GL_COLOR_MATERIAL);
00730 
00731         glEnable(GL_TEXTURE_2D);
00732         glBindTexture(GL_TEXTURE_2D, 1);
00733         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00734         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00735         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00736         glTexImage2D(GL_TEXTURE_2D, 0, 1, LIGHTSIZE, LIGHTSIZE, 0,
00737                      GL_LUMINANCE, GL_UNSIGNED_BYTE, lightTexture);
00738 
00739         temp = float(dSize) * 0.005f;
00740         glNewList(1, GL_COMPILE);
00741             glBindTexture(GL_TEXTURE_2D, 1);
00742             glBegin(GL_TRIANGLES);
00743                 glTexCoord2f(0.0f, 0.0f);
00744                 glVertex3f(-temp, -temp, 0.0f);
00745                 glTexCoord2f(1.0f, 0.0f);
00746                 glVertex3f(temp, -temp, 0.0f);
00747                 glTexCoord2f(1.0f, 1.0f);
00748                 glVertex3f(temp, temp, 0.0f);
00749                 glTexCoord2f(0.0f, 0.0f);
00750                 glVertex3f(-temp, -temp, 0.0f);
00751                 glTexCoord2f(1.0f, 1.0f);
00752                 glVertex3f(temp, temp, 0.0f);
00753                 glTexCoord2f(0.0f, 1.0f);
00754                 glVertex3f(-temp, temp, 0.0f);
00755             glEnd();
00756         glEndList();
00757     }
00758 
00759     // Initialize luminosity difference
00760     lumdiff = 1.0f / float(dTrail);
00761 
00762     _fc = this;
00763     delete[] _fluxes;
00764     _fluxes = new flux[dFluxes];
00765 }
00766 
00767 
00768 //----------------------------------------------------------------------------
00769 
00770 
00771 #ifndef UNIT_TEST
00772 #include <klocale.h>
00773 #include <kglobal.h>
00774 #include <kconfig.h>
00775 
00776 
00777 // libkscreensaver interface
00778 class KFluxSaverInterface : public KScreenSaverInterface
00779 {
00780 
00781 
00782 public:
00783     virtual KAboutData* aboutData() {
00784         return new KAboutData( "kflux.kss", "klock", ki18n( "Flux" ), "1.0", ki18n( "Flux" ) );
00785     }
00786 
00787 
00788     virtual KScreenSaver* create( WId id )
00789     {
00790         return new KFluxScreenSaver( id );
00791     }
00792 
00793     virtual QDialog* setup()
00794     {
00795         return new KFluxSetup;
00796     }
00797 };
00798 
00799 int main( int argc, char *argv[] )
00800 {
00801     KFluxSaverInterface kss;
00802     return kScreenSaverMain( argc, argv, kss );
00803 }
00804 
00805 
00806 //----------------------------------------------------------------------------
00807 
00808 
00809 KFluxScreenSaver::KFluxScreenSaver( WId id ) : KScreenSaver( id )
00810 {
00811     _flux = new FluxWidget;
00812 
00813     readSettings();
00814 
00815     embed( _flux );
00816     _flux->show();
00817     show();
00818 }
00819 
00820 
00821 KFluxScreenSaver::~KFluxScreenSaver()
00822 {
00823 }
00824 
00825 
00826 static int filterRandom( int n )
00827 {
00828     if( (n < 0) || (n >= FluxWidget::DefaultModes) )
00829     {
00830         srand((unsigned)time(NULL));
00831         n = rand() % FluxWidget::DefaultModes;
00832     }
00833     return n;
00834 }
00835 
00836 
00837 void KFluxScreenSaver::readSettings()
00838 {
00839     KConfigGroup config(KGlobal::config(), "Settings");
00840 
00841     _mode = config.readEntry( "Mode", (int)FluxWidget::Regular );
00842     _flux->setDefaults( filterRandom(_mode) );
00843 }
00844 
00845 
00849 void KFluxScreenSaver::setMode( int id )
00850 {
00851     _mode = id;
00852     _flux->setDefaults( filterRandom(id) );
00853     _flux->updateParameters();
00854 }
00855 
00856 
00857 //----------------------------------------------------------------------------
00858 
00859 
00860 #include <qlayout.h>
00861 #include <qpushbutton.h>
00862 #include <qlabel.h>
00863 #include <qcombobox.h>
00864 #include <kmessagebox.h>
00865 
00866 
00867 static const char* defaultText[] =
00868 {
00869     I18N_NOOP( "Regular" ),
00870     I18N_NOOP( "Hypnotic" ),
00871     I18N_NOOP( "Insane" ),
00872     I18N_NOOP( "Sparklers" ),
00873     I18N_NOOP( "Paradigm" ),
00874     I18N_NOOP( "Galactic" ),
00875     I18N_NOOP( "(Random)" ),
00876     0
00877 };
00878 
00879 
00880 KFluxSetup::KFluxSetup( QWidget* parent )
00881     : KDialog( parent)
00882 {
00883     setButtonText( Help, i18n( "A&bout" ) );
00884        setButtons(Ok|Cancel|Help);
00885        setDefaultButton(Ok);
00886        setModal(true);
00887        showButtonSeparator(true);
00888     QWidget *main = new QWidget(this);
00889        setMainWidget(main);
00890 
00891     QHBoxLayout* top = new QHBoxLayout( main );
00892     top->setSpacing( spacingHint() );
00893     QVBoxLayout* leftCol = new QVBoxLayout;
00894     top->addLayout( leftCol );
00895 
00896     // Parameters
00897     QLabel* label = new QLabel( i18n("Mode:"), main );
00898     leftCol->addWidget( label );
00899 
00900     modeW = new QComboBox( main );
00901     int i = 0;
00902     while (defaultText[i])
00903         modeW->addItem( i18n(defaultText[i++]) );
00904     leftCol->addWidget( modeW );
00905 
00906     leftCol->addStretch();
00907 
00908     // Preview
00909     QWidget* preview;
00910     preview = new QWidget( main );
00911     preview->setFixedSize( 220, 165 );
00912     {
00913         QPalette palette;
00914         palette.setColor( preview->backgroundRole(), Qt::black );
00915         preview->setPalette( palette );
00916        preview->setAutoFillBackground(true);
00917     }
00918     preview->show();    // otherwise saver does not get correct size
00919     _saver = new KFluxScreenSaver( preview->winId() );
00920     top->addWidget(preview);
00921 
00922     // Now that we have _saver...
00923     modeW->setCurrentIndex( _saver->mode() );    // set before we connect
00924    connect( modeW, SIGNAL(activated(int)), _saver, SLOT(setMode(int)) );
00925    connect( this, SIGNAL(okClicked()), SLOT(slotOk()));
00926    connect(this, SIGNAL(helpClicked()),SLOT(slotHelp()));
00927 }
00928 
00929 
00930 KFluxSetup::~KFluxSetup()
00931 {
00932     delete _saver;
00933 }
00934 
00935 
00936 void KFluxSetup::slotHelp()
00937 {
00938     KMessageBox::about(this,
00939         i18n("<h3>Flux 1.0</h3>\n<p>Copyright (c) 2002 Terence M. Welsh<br>\n<a href=\"http://www.reallyslick.com/\">http://www.reallyslick.com/</a></p>\n\n<p>Ported to KDE by Karl Robillard</p>"),
00940         QString(), KMessageBox::AllowLink);
00941 }
00942 
00943 
00947 void KFluxSetup::slotOk()
00948 {
00949     KConfigGroup config(KGlobal::config(), "Settings");
00950 
00951     QString val;
00952     val.setNum( modeW->currentIndex() );
00953     config.writeEntry("Mode", val );
00954 
00955     config.sync();
00956     accept();
00957 }
00958 #endif
00959 
00960 
00961 //----------------------------------------------------------------------------
00962 
00963 
00964 #ifdef UNIT_TEST
00965 // moc Flux.h -o Flux.moc
00966 // g++ -g -DUNIT_TEST Flux.cpp -I/usr/lib/qt3/include -lqt -L/usr/lib/qt3/lib -lGLU -lGL
00967 
00968 #include <qapplication.h>
00969 
00970 int main( int argc, char** argv )
00971 {
00972     QApplication app( argc, argv );
00973 
00974     FluxWidget w;
00975     w.setDefaults( FluxWidget::Sparklers );
00976     app.setMainWidget( &w );
00977     w.show();
00978 
00979     return app.exec();
00980 }
00981 #endif
00982 
00983 
00984 //EOF