Back to index

kdeartwork  4.3.2
Euphoria.cpp
Go to the documentation of this file.
00001 /*
00002  *  Terence Welsh Screensaver - Euphoria
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 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <math.h>
00025 #include <time.h>
00026 #include <qtimer.h>
00027 
00028 #include "Euphoria.h"
00029 #include "Euphoria.moc"
00030 #include "EuphoriaTexture.h"
00031 #include <GL/glu.h>
00032 
00033 
00034 #define NUMCONSTS 9
00035 #define PIx2 6.28318530718f
00036 
00037 
00038 //----------------------------------------------------------------------------
00039 
00040 
00041 #include <sys/time.h>
00042 #include <unistd.h>
00043 
00044 
00045 // Returns the system time, in seconds.
00046 double timeGetTime()
00047 {
00048     struct timeval tp;
00049     gettimeofday( &tp, 0 );
00050     return (double)tp.tv_sec + (double)tp.tv_usec / 1000000;
00051 }
00052 
00053 
00054 //----------------------------------------------------------------------------
00055 
00056 
00057 class rsVec
00058 {
00059 public:
00060 
00061     float v[3];
00062 
00063     rsVec() {}
00064     rsVec(float xx, float yy, float zz);
00065 
00066     void set(float xx, float yy, float zz);
00067     float normalize();
00068     float dot(rsVec);
00069     void cross(rsVec, rsVec);
00070 
00071     float & operator [] (int i) {return v[i];}
00072     const float & operator [] (int i) const {return v[i];}
00073     rsVec & operator = (const rsVec &vec)
00074         {v[0]=vec[0];v[1]=vec[1];v[2]=vec[2];return *this;}
00075     rsVec operator + (const rsVec &vec)
00076         {return(rsVec(v[0]+vec[0], v[1]+vec[1], v[2]+vec[2]));}
00077     rsVec operator - (const rsVec &vec)
00078         {return(rsVec(v[0]-vec[0], v[1]-vec[1], v[2]-vec[2]));}
00079     rsVec operator * (const float &mul)
00080         {return(rsVec(v[0]*mul, v[1]*mul, v[2]*mul));}
00081     rsVec operator / (const float &div)
00082         {float rec = 1.0f/div; return(rsVec(v[0]*rec, v[1]*rec, v[2]*rec));}
00083     rsVec & operator += (const rsVec &vec)
00084         {v[0]+=vec[0];v[1]+=vec[1];v[2]+=vec[2];return *this;}
00085     rsVec & operator -= (const rsVec &vec)
00086         {v[0]-=vec[0];v[1]-=vec[1];v[2]-=vec[2];return *this;}
00087     rsVec & operator *= (const rsVec &vec)
00088         {v[0]*=vec[0];v[1]*=vec[1];v[2]*=vec[2];return *this;}
00089     rsVec & operator *= (const float &mul)
00090         {v[0]*=mul;v[1]*=mul;v[2]*=mul;return *this;}
00091 };
00092 
00093 
00094 rsVec::rsVec(float xx, float yy, float zz){
00095     v[0] = xx;
00096     v[1] = yy;
00097     v[2] = zz;
00098 }
00099 
00100 
00101 void rsVec::set(float xx, float yy, float zz){
00102     v[0] = xx;
00103     v[1] = yy;
00104     v[2] = zz;
00105 }
00106 
00107 
00108 float rsVec::normalize(){
00109     float length = float(sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]));
00110     if(length == 0.0f){
00111         v[1] = 1.0f;
00112         return(0.0f);
00113     }
00114     float reciprocal = 1.0f / length;
00115     v[0] *= reciprocal;
00116     v[1] *= reciprocal;
00117     v[2] *= reciprocal;
00118     // Really freakin' stupid compiler bug fix for VC++ 5.0
00119     /*v[0] /= length;
00120     v[1] /= length;
00121     v[2] /= length;*/
00122     return(length);
00123 }
00124 
00125 
00126 float rsVec::dot(rsVec vec1){
00127     return(v[0] * vec1[0] + v[1] * vec1[1] + v[2] * vec1[2]);
00128 }
00129 
00130 
00131 void rsVec::cross(rsVec vec1, rsVec vec2){
00132     v[0] = vec1[1] * vec2[2] - vec2[1] * vec1[2];
00133     v[1] = vec1[2] * vec2[0] - vec2[2] * vec1[0];
00134     v[2] = vec1[0] * vec2[1] - vec2[0] * vec1[1];
00135 }
00136 
00137 
00138 //----------------------------------------------------------------------------
00139 
00140 
00141 void hsl2rgb(float h, float s, float l, float &r, float &g, float &b)
00142 {
00143     // hue influence
00144     if(h < 0.166667){  // full red, some green
00145         r = 1.0;
00146         g = h * 6.0f;
00147         b = 0.0;
00148     }
00149     else {
00150         if(h < 0.5){  // full green
00151             g = 1.0;
00152             if(h < 0.333333){  // some red
00153                 r = 1.0f - ((h - 0.166667f) * 6.0f);
00154                 b = 0.0;
00155             }
00156             else{  // some blue
00157                 b = (h - 0.333333f) * 6.0f;
00158                 r = 0.0;
00159             }
00160         }
00161         else{
00162             if(h < 0.833333){  // full blue
00163                 b = 1.0;
00164                 if(h < 0.666667){  // some green
00165                     g = 1.0f - ((h - 0.5f) * 6.0f);
00166                     r = 0.0;
00167                 }
00168                 else{  // some red
00169                     r = (h - 0.666667f) * 6.0f;
00170                     g = 0.0;
00171                 }
00172             }
00173             else{  // full red, some blue
00174                 r = 1.0;
00175                 b = 1.0f - ((h - 0.833333f) * 6.0f);
00176                 g = 0.0;
00177             }
00178         }
00179     }
00180 
00181     // saturation influence
00182     r = 1.0f - (s * (1.0f - r));
00183     g = 1.0f - (s * (1.0f - g));
00184     b = 1.0f - (s * (1.0f - b));
00185 
00186     // luminosity influence
00187     r *= l;
00188     g *= l;
00189     b *= l;
00190 }
00191 
00192 
00193 // Useful random number macros
00194 // Don't forget to initialize with srand()
00195 inline int myRandi(int x){
00196     return((rand() * x) / RAND_MAX);
00197 }
00198 inline float myRandf(float x){
00199     return(float(rand() * x) / float(RAND_MAX));
00200 }
00201 
00202 
00203 //----------------------------------------------------------------------------
00204 
00205 
00206 // Context pointer to allow many instances.
00207 static EuphoriaWidget* _ec = 0;
00208 
00209 
00210 class wisp
00211 {
00212 public:
00213 
00214        wisp();
00215        ~wisp();
00216        void update();
00217        void draw();
00218        void drawAsBackground();
00219 
00220 
00221     int density;
00222        float*** vertices;
00223        float c[NUMCONSTS];     // constants
00224        float cr[NUMCONSTS];    // constants' radial position
00225        float cv[NUMCONSTS];    // constants' change velocities
00226        float hsl[3];
00227        float rgb[3];
00228        float hueSpeed;
00229        float saturationSpeed;
00230 };
00231 
00232 
00233 wisp::wisp()
00234 {
00235        int i, j;
00236        float recHalfDens = 1.0f / (float(_ec->dDensity) * 0.5f);
00237 
00238     density = _ec->dDensity;
00239        vertices = new float**[density+1];
00240        for(i=0; i<=density; i++)
00241     {
00242               vertices[i] = new float*[density+1];
00243               for(j=0; j<=density; j++)
00244         {
00245                      vertices[i][j] = new float[7];
00246                      vertices[i][j][3] = float(i) * recHalfDens - 1.0f;  // x position on grid
00247                      vertices[i][j][4] = float(j) * recHalfDens - 1.0f;  // y position on grid
00248                      // distance squared from the center
00249                      vertices[i][j][5] = vertices[i][j][3] * vertices[i][j][3]
00250                             + vertices[i][j][4] * vertices[i][j][4];
00251                      vertices[i][j][6] = 0.0f;  // intensity
00252               }
00253        }
00254 
00255        // initialize constants
00256        for(i=0; i<NUMCONSTS; i++)
00257     {
00258               c[i] = myRandf(2.0f) - 1.0f;
00259               cr[i] = myRandf(PIx2);
00260               cv[i] = myRandf(_ec->dSpeed * 0.03f) + (_ec->dSpeed * 0.001f);
00261        }
00262 
00263        // pick color
00264        hsl[0] = myRandf(1.0f);
00265        hsl[1] = 0.1f + myRandf(0.9f);
00266        hsl[2] = 1.0f;
00267        hueSpeed = myRandf(0.1f) - 0.05f;
00268        saturationSpeed = myRandf(0.04f) + 0.001f;
00269 }
00270 
00271 
00272 wisp::~wisp()
00273 {
00274        int i, j;
00275 
00276        for(i=0; i<=density; i++)
00277     {
00278               for(j=0; j<=density; j++)
00279         {
00280                      delete[] vertices[i][j];
00281               }
00282               delete[] vertices[i];
00283        }
00284        delete[] vertices;
00285 }
00286 
00287 
00288 void wisp::update()
00289 {
00290        int i, j;
00291        rsVec up, right, crossvec;
00292        // visibility constants
00293        static float viscon1 = float(_ec->dVisibility) * 0.01f;
00294        static float viscon2 = 1.0f / viscon1;
00295 
00296        // update constants
00297        for(i=0; i<NUMCONSTS; i++){
00298               cr[i] += cv[i] * _ec->elapsedTime;
00299               if(cr[i] > PIx2)
00300                      cr[i] -= PIx2;
00301               c[i] = cos(cr[i]);
00302        }
00303 
00304        // update vertex positions
00305        for(i=0; i<=density; i++){
00306               for(j=0; j<=density; j++){
00307                      vertices[i][j][0] = vertices[i][j][3] * vertices[i][j][3] * vertices[i][j][4] * c[0]
00308                             + vertices[i][j][5] * c[1] + 0.5f * c[2];
00309                      vertices[i][j][1] = vertices[i][j][4] * vertices[i][j][4] * vertices[i][j][5] * c[3]
00310                             + vertices[i][j][3] * c[4] + 0.5f * c[5];
00311                      vertices[i][j][2] = vertices[i][j][5] * vertices[i][j][5] * vertices[i][j][3] * c[6]
00312                             + vertices[i][j][4] * c[7] + c[8];
00313               }
00314        }
00315 
00316        // update vertex normals for most of mesh
00317        for(i=1; i<density; i++){
00318               for(j=1; j<density; j++){
00319                      up.set(vertices[i][j+1][0] - vertices[i][j-1][0],
00320                             vertices[i][j+1][1] - vertices[i][j-1][1],
00321                             vertices[i][j+1][2] - vertices[i][j-1][2]);
00322                      right.set(vertices[i+1][j][0] - vertices[i-1][j][0],
00323                             vertices[i+1][j][1] - vertices[i-1][j][1],
00324                             vertices[i+1][j][2] - vertices[i-1][j][2]);
00325                      up.normalize();
00326                      right.normalize();
00327                      crossvec.cross(right, up);
00328                      // Use depth component of normal to compute intensity
00329                      // This way only edges of wisp are bright
00330                      if(crossvec[2] < 0.0f)
00331                             crossvec[2] *= -1.0f;
00332                      vertices[i][j][6] = viscon2 * (viscon1 - crossvec[2]);
00333                      if(vertices[i][j][6] > 1.0f)
00334                             vertices[i][j][6] = 1.0f;
00335                      if(vertices[i][j][6] < 0.0f)
00336                             vertices[i][j][6] = 0.0f;
00337               }
00338        }
00339 
00340        // update color
00341        hsl[0] += hueSpeed * _ec->elapsedTime;
00342        if(hsl[0] < 0.0f)
00343               hsl[0] += 1.0f;
00344        if(hsl[0] > 1.0f)
00345               hsl[0] -= 1.0f;
00346        hsl[1] += saturationSpeed * _ec->elapsedTime;
00347        if(hsl[1] <= 0.1f){
00348               hsl[1] = 0.1f;
00349               saturationSpeed = -saturationSpeed;
00350        }
00351        if(hsl[1] >= 1.0f){
00352               hsl[1] = 1.0f;
00353               saturationSpeed = -saturationSpeed;
00354        }
00355        hsl2rgb(hsl[0], hsl[1], hsl[2], rgb[0], rgb[1], rgb[2]);
00356 }
00357 
00358 
00359 void wisp::draw()
00360 {
00361        int i, j;
00362 
00363        glPushMatrix();
00364 
00365        if(_ec->dWireframe)
00366     {
00367               for(i=1; i<density; i++){
00368                      glBegin(GL_LINE_STRIP);
00369                      for(j=0; j<=density; j++){
00370                             glColor3f(rgb[0] + vertices[i][j][6] - 1.0f, rgb[1] + vertices[i][j][6] - 1.0f, rgb[2] + vertices[i][j][6] - 1.0f);
00371                             glTexCoord2d(vertices[i][j][3] - vertices[i][j][0], vertices[i][j][4] - vertices[i][j][1]);
00372                             glVertex3fv(vertices[i][j]);
00373                      }
00374                      glEnd();
00375               }
00376               for(j=1; j<density; j++){
00377                      glBegin(GL_LINE_STRIP);
00378                      for(i=0; i<=density; i++){
00379                             glColor3f(rgb[0] + vertices[i][j][6] - 1.0f, rgb[1] + vertices[i][j][6] - 1.0f, rgb[2] + vertices[i][j][6] - 1.0f);
00380                             glTexCoord2d(vertices[i][j][3] - vertices[i][j][0], vertices[i][j][4] - vertices[i][j][1]);
00381                             glVertex3fv(vertices[i][j]);
00382                      }
00383                      glEnd();
00384               }
00385        }
00386        else
00387     {
00388               for(i=0; i<density; i++){
00389                      glBegin(GL_TRIANGLE_STRIP);
00390                             for(j=0; j<=density; j++){
00391                                    glColor3f(rgb[0] + vertices[i+1][j][6] - 1.0f, rgb[1] + vertices[i+1][j][6] - 1.0f, rgb[2] + vertices[i+1][j][6] - 1.0f);
00392                                    glTexCoord2d(vertices[i+1][j][3] - vertices[i+1][j][0], vertices[i+1][j][4] - vertices[i+1][j][1]);
00393                                    glVertex3fv(vertices[i+1][j]);
00394                                    glColor3f(rgb[0] + vertices[i][j][6] - 1.0f, rgb[1] + vertices[i][j][6] - 1.0f, rgb[2] + vertices[i][j][6] - 1.0f);
00395                                    glTexCoord2d(vertices[i][j][3] - vertices[i][j][0], vertices[i][j][4] - vertices[i][j][1]);
00396                                    glVertex3fv(vertices[i][j]);
00397                             }
00398                      glEnd();
00399               }
00400        }
00401 
00402        glPopMatrix();
00403 }
00404 
00405 
00406 void wisp::drawAsBackground()
00407 {
00408        int i, j;
00409 
00410        glPushMatrix();
00411        glTranslatef(c[0] * 0.2f, c[1] * 0.2f, 1.6f);
00412 
00413        if(_ec->dWireframe)
00414     {
00415               for(i=1; i<density; i++){
00416                      glBegin(GL_LINE_STRIP);
00417                      for(j=0; j<=density; j++){
00418                             glColor3f(rgb[0] + vertices[i][j][6] - 1.0f, rgb[1] + vertices[i][j][6] - 1.0f, rgb[2] + vertices[i][j][6] - 1.0f);
00419                             glTexCoord2d(vertices[i][j][3] - vertices[i][j][0], vertices[i][j][4] - vertices[i][j][1]);
00420                             glVertex3f(vertices[i][j][3], vertices[i][j][4], vertices[i][j][6]);
00421                      }
00422                      glEnd();
00423               }
00424               for(j=1; j<density; j++){
00425                      glBegin(GL_LINE_STRIP);
00426                      for(i=0; i<=density; i++){
00427                             glColor3f(rgb[0] + vertices[i][j][6] - 1.0f, rgb[1] + vertices[i][j][6] - 1.0f, rgb[2] + vertices[i][j][6] - 1.0f);
00428                             glTexCoord2d(vertices[i][j][3] - vertices[i][j][0], vertices[i][j][4] - vertices[i][j][1]);
00429                             glVertex3f(vertices[i][j][3], vertices[i][j][4], vertices[i][j][6]);
00430                      }
00431                      glEnd();
00432               }
00433        }
00434        else
00435     {
00436               for(i=0; i<density; i++){
00437                      glBegin(GL_TRIANGLE_STRIP);
00438                             for(j=0; j<=density; j++){
00439                                    glColor3f(rgb[0] + vertices[i+1][j][6] - 1.0f, rgb[1] + vertices[i+1][j][6] - 1.0f, rgb[2] + vertices[i+1][j][6] - 1.0f);
00440                                    glTexCoord2d(vertices[i+1][j][3] - vertices[i+1][j][0], vertices[i+1][j][4] - vertices[i+1][j][1]);
00441                                    glVertex3f(vertices[i+1][j][3], vertices[i+1][j][4], vertices[i+1][j][6]);
00442                                    glColor3f(rgb[0] + vertices[i][j][6] - 1.0f, rgb[1] + vertices[i][j][6] - 1.0f, rgb[2] + vertices[i][j][6] - 1.0f);
00443                                    glTexCoord2d(vertices[i][j][3] - vertices[i][j][0], vertices[i][j][4] - vertices[i][j][1]);
00444                                    glVertex3f(vertices[i][j][3], vertices[i][j][4], vertices[i][j][6]);
00445                             }
00446                      glEnd();
00447               }
00448        }
00449 
00450        glPopMatrix();
00451 }
00452 
00453 
00454 //----------------------------------------------------------------------------
00455 
00456 
00457 EuphoriaWidget::EuphoriaWidget( QWidget* parent )
00458               : QGLWidget(parent), texName(0), _wisps(0), _backwisps(0),
00459              feedbackmap(0), feedbacktex(0)
00460 {
00461     setDefaults( Regular );
00462 
00463     _frameTime = 1000 / 60;
00464     _timer = new QTimer( this );
00465     _timer->setSingleShot( true );
00466     connect( _timer, SIGNAL(timeout()), this, SLOT(nextFrame()) );
00467 }
00468 
00469 
00470 EuphoriaWidget::~EuphoriaWidget()
00471 {
00472        // Free memory
00473        if ( texName )
00474               glDeleteTextures( 1, &texName );
00475        if ( feedbacktex )
00476               glDeleteTextures( 1, &feedbacktex );
00477        delete[] _wisps;
00478        delete[] _backwisps;
00479 }
00480 
00481 
00482 void EuphoriaWidget::paintGL()
00483 {
00484        int i;
00485        static double lastTime = timeGetTime();
00486 
00487        // update time
00488        elapsedTime = timeGetTime() - lastTime;
00489        lastTime += elapsedTime;
00490 
00491     _ec = this;
00492 
00493        // Update wisps
00494        for(i=0; i<dWisps; i++)
00495               _wisps[i].update();
00496        for(i=0; i<dBackground; i++)
00497               _backwisps[i].update();
00498 
00499 
00500        if(dFeedback)
00501     {
00502               float feedbackIntensity = float(dFeedback) / 101.0f;
00503 
00504               // update feedback variables
00505               for(i=0; i<4; i++)
00506         {
00507                      fr[i] += elapsedTime * fv[i];
00508                      if(fr[i] > PIx2)
00509                             fr[i] -= PIx2;
00510               }
00511               f[0] = 30.0f * cos(fr[0]);
00512               f[1] = 0.2f * cos(fr[1]);
00513               f[2] = 0.2f * cos(fr[2]);
00514               f[3] = 0.8f * cos(fr[3]);
00515               for(i=0; i<3; i++)
00516         {
00517                      lr[i] += elapsedTime * lv[i];
00518                      if(lr[i] > PIx2)
00519                             lr[i] -= PIx2;
00520                      l[i] = cos(lr[i]);
00521                      l[i] = l[i] * l[i];
00522               }
00523 
00524               // Create drawing area for feedback texture
00525               glViewport(0, 0, feedbacktexsize, feedbacktexsize);
00526               glMatrixMode(GL_PROJECTION);
00527               glLoadIdentity();
00528               gluPerspective(30.0, aspectRatio, 0.01f, 20.0f);
00529               glMatrixMode(GL_MODELVIEW);
00530 
00531               // Draw
00532               glClear(GL_COLOR_BUFFER_BIT);
00533               glColor3f(feedbackIntensity, feedbackIntensity, feedbackIntensity);
00534               glBindTexture(GL_TEXTURE_2D, feedbacktex);
00535               glPushMatrix();
00536               glTranslatef(f[1] * l[1], f[2] * l[1], f[3] * l[2]);
00537               glRotatef(f[0] * l[0], 0, 0, 1);
00538               glBegin(GL_TRIANGLE_STRIP);
00539                      glTexCoord2f(-0.5f, -0.5f);
00540                      glVertex3f(-aspectRatio*2.0f, -2.0f, 1.25f);
00541                      glTexCoord2f(1.5f, -0.5f);
00542                      glVertex3f(aspectRatio*2.0f, -2.0f, 1.25f);
00543                      glTexCoord2f(-0.5f, 1.5f);
00544                      glVertex3f(-aspectRatio*2.0f, 2.0f, 1.25f);
00545                      glTexCoord2f(1.5f, 1.5f);
00546                      glVertex3f(aspectRatio*2.0f, 2.0f, 1.25f);
00547               glEnd();
00548               glPopMatrix();
00549               glBindTexture(GL_TEXTURE_2D, texName);
00550               for(i=0; i<dBackground; i++)
00551                      _backwisps[i].drawAsBackground();
00552               for(i=0; i<dWisps; i++)
00553                      _wisps[i].draw();
00554 
00555               // readback feedback texture
00556               glReadBuffer(GL_BACK);
00557               glPixelStorei(GL_UNPACK_ROW_LENGTH, feedbacktexsize);
00558               glBindTexture(GL_TEXTURE_2D, feedbacktex);
00559               glReadPixels(0, 0, feedbacktexsize, feedbacktexsize, GL_RGB, GL_UNSIGNED_BYTE, feedbackmap);
00560               glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, feedbacktexsize, feedbacktexsize, GL_RGB, GL_UNSIGNED_BYTE, feedbackmap);
00561 
00562               // create regular drawing area
00563               glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
00564               glMatrixMode(GL_PROJECTION);
00565               glLoadIdentity();
00566               gluPerspective(20.0, aspectRatio, 0.01f, 20.0f);
00567               glMatrixMode(GL_MODELVIEW);
00568 
00569               // Draw again
00570               glClear(GL_COLOR_BUFFER_BIT);
00571               glColor3f(feedbackIntensity, feedbackIntensity, feedbackIntensity);
00572               glPushMatrix();
00573               glTranslatef(f[1] * l[1], f[2] * l[1], f[3] * l[2]);
00574               glRotatef(f[0] * l[0], 0, 0, 1);
00575               glBegin(GL_TRIANGLE_STRIP);
00576                      glTexCoord2f(-0.5f, -0.5f);
00577                      glVertex3f(-aspectRatio*2.0f, -2.0f, 1.25f);
00578                      glTexCoord2f(1.5f, -0.5f);
00579                      glVertex3f(aspectRatio*2.0f, -2.0f, 1.25f);
00580                      glTexCoord2f(-0.5f, 1.5f);
00581                      glVertex3f(-aspectRatio*2.0f, 2.0f, 1.25f);
00582                      glTexCoord2f(1.5f, 1.5f);
00583                      glVertex3f(aspectRatio*2.0f, 2.0f, 1.25f);
00584               glEnd();
00585               glPopMatrix();
00586 
00587               glBindTexture(GL_TEXTURE_2D, texName);
00588        }
00589        else
00590               glClear(GL_COLOR_BUFFER_BIT);
00591 
00592        //
00593        for(i=0; i<dBackground; i++)
00594               _backwisps[i].drawAsBackground();
00595        for(i=0; i<dWisps; i++)
00596               _wisps[i].draw();
00597 
00598        glFlush();
00599 }
00600 
00601 
00602 void EuphoriaWidget::resizeGL( int w, int h )
00603 {
00604     glViewport(0, 0, w, h );
00605 
00606        viewport[0] = 0;
00607        viewport[1] = 0;
00608        viewport[2] = w;
00609        viewport[3] = h;
00610 
00611        aspectRatio = (float) w / (float) h;
00612 
00613        // setup regular drawing area just in case feedback isn't used
00614        glMatrixMode(GL_PROJECTION);
00615        glLoadIdentity();
00616     gluPerspective(20.0, aspectRatio, 0.01, 20);
00617        glMatrixMode(GL_MODELVIEW);
00618        glLoadIdentity();
00619        glTranslatef(0.0, 0.0, -5.0);
00620 }
00621 
00622 
00623 // Window initialization
00624 void EuphoriaWidget::initializeGL()
00625 {
00626     // Need to call this to setup viewport[] parameters used in
00627     // the next updateParameters() call
00628     resizeGL( width(), height() );
00629 
00630     updateParameters();
00631 
00632     _timer->start( _frameTime );
00633 }
00634 
00635 
00636 #ifdef UNIT_TEST
00637 void EuphoriaWidget::keyPressEvent( QKeyEvent* e )
00638 {
00639     if( e->key() == Qt::Key_0 ) { setDefaults( 0 ); updateParameters(); }
00640     if( e->key() == Qt::Key_1 ) { setDefaults( 1 ); updateParameters(); }
00641     if( e->key() == Qt::Key_2 ) { setDefaults( 2 ); updateParameters(); }
00642     if( e->key() == Qt::Key_3 ) { setDefaults( 3 ); updateParameters(); }
00643     if( e->key() == Qt::Key_4 ) { setDefaults( 4 ); updateParameters(); }
00644     if( e->key() == Qt::Key_5 ) { setDefaults( 5 ); updateParameters(); }
00645     if( e->key() == Qt::Key_6 ) { setDefaults( 6 ); updateParameters(); }
00646     if( e->key() == Qt::Key_7 ) { setDefaults( 7 ); updateParameters(); }
00647     if( e->key() == Qt::Key_8 ) { setDefaults( 8 ); updateParameters(); }
00648 }
00649 #endif
00650 
00651 
00652 void EuphoriaWidget::nextFrame()
00653 {
00654     updateGL();
00655     _timer->start( _frameTime );
00656 }
00657 
00658 
00659 void EuphoriaWidget::updateParameters()
00660 {
00661        srand((unsigned)time(NULL));
00662        rand(); rand(); rand(); rand(); rand();
00663 
00664     elapsedTime = 0.0f;
00665 
00666     fr[0] = 0.0f;
00667     fr[1] = 0.0f;
00668     fr[2] = 0.0f;
00669     fr[3] = 0.0f;
00670 
00671     lr[0] = 0.0f;
00672     lr[1] = 0.0f;
00673     lr[2] = 0.0f;
00674 
00675        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
00676        glClear(GL_COLOR_BUFFER_BIT);
00677        glEnable(GL_BLEND);
00678        glBlendFunc(GL_ONE, GL_ONE);
00679        glLineWidth(2.0f);
00680 
00681        // Commented out because smooth lines and textures don't mix on my TNT.
00682        // It's like it rendering in software mode
00683        glEnable(GL_LINE_SMOOTH);
00684        //glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
00685 
00686        if(dTexture)
00687     {
00688               int whichtex = dTexture;
00689               if(whichtex == 4)  // random texture
00690                      whichtex = myRandi(3) + 1;
00691               glEnable(GL_TEXTURE_2D);
00692               glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00693               // Initialize texture
00694               glGenTextures(1, &texName);
00695               glBindTexture(GL_TEXTURE_2D, texName);
00696               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00697               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
00698               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
00699               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
00700               switch(whichtex){
00701               case 1:
00702                      gluBuild2DMipmaps(GL_TEXTURE_2D, 1, TEXSIZE, TEXSIZE, GL_LUMINANCE, GL_UNSIGNED_BYTE, plasmamap);
00703                      break;
00704               case 2:
00705                      gluBuild2DMipmaps(GL_TEXTURE_2D, 1, TEXSIZE, TEXSIZE, GL_LUMINANCE, GL_UNSIGNED_BYTE, stringymap);
00706                      break;
00707               case 3:
00708                      gluBuild2DMipmaps(GL_TEXTURE_2D, 1, TEXSIZE, TEXSIZE, GL_LUMINANCE, GL_UNSIGNED_BYTE, linesmap);
00709               }
00710        } else if ( texName ) {
00711               glDeleteTextures( 1, &texName );
00712               texName = 0;
00713        }
00714 
00715        if(dFeedback)
00716     {
00717               feedbacktexsize = int(pow(2.0, dFeedbacksize));
00718               while(feedbacktexsize > viewport[2] || feedbacktexsize > viewport[3]){
00719                      dFeedbacksize -= 1;
00720                      feedbacktexsize = int(pow(2.0, dFeedbacksize));
00721               }
00722 
00723               // feedback texture setup
00724               glEnable(GL_TEXTURE_2D);
00725               delete [] feedbackmap;
00726               feedbackmap = new unsigned char[feedbacktexsize*feedbacktexsize*3];
00727               glGenTextures(1, &feedbacktex);
00728               glBindTexture(GL_TEXTURE_2D, feedbacktex);
00729               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00730               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00731               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
00732               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
00733               glTexImage2D(GL_TEXTURE_2D, 0, 3, feedbacktexsize, feedbacktexsize, 0, GL_RGB, GL_UNSIGNED_BYTE, feedbackmap);
00734 
00735               // feedback velocity variable setup
00736               fv[0] = float(dFeedbackspeed) * (myRandf(0.025f) + 0.025f);
00737               fv[1] = float(dFeedbackspeed) * (myRandf(0.05f) + 0.05f);
00738               fv[2] = float(dFeedbackspeed) * (myRandf(0.05f) + 0.05f);
00739               fv[3] = float(dFeedbackspeed) * (myRandf(0.1f) + 0.1f);
00740               lv[0] = float(dFeedbackspeed) * (myRandf(0.0025f) + 0.0025f);
00741               lv[1] = float(dFeedbackspeed) * (myRandf(0.0025f) + 0.0025f);
00742               lv[2] = float(dFeedbackspeed) * (myRandf(0.0025f) + 0.0025f);
00743        } else if ( feedbacktex ) {
00744               glDeleteTextures( 1, &feedbacktex );
00745               feedbacktex = 0;
00746        }
00747 
00748        // Initialize wisps
00749     _ec = this;
00750     delete[] _wisps;
00751     delete[] _backwisps;
00752        _wisps     = new wisp[dWisps];
00753        _backwisps = new wisp[dBackground];
00754 }
00755 
00756 
00760 void EuphoriaWidget::setDefaults(int which)
00761 {
00762        switch(which)
00763     {
00764        case Grid:
00765               dWisps = 4;
00766               dBackground = 1;
00767               dDensity = 25;
00768               dVisibility = 70;
00769               dSpeed = 15;
00770               dFeedback = 0;
00771               dFeedbackspeed = 1;
00772               dFeedbacksize = 8;
00773               dWireframe = 1;
00774               dTexture = 0;
00775               break;
00776 
00777     case Cubism:
00778               dWisps = 15;
00779               dBackground = 0;
00780               dDensity = 4;
00781               dVisibility = 15;
00782               dSpeed = 10;
00783               dFeedback = 0;
00784               dFeedbackspeed = 1;
00785               dFeedbacksize = 8;
00786               dWireframe = 0;
00787               dTexture = 0;
00788               break;
00789 
00790     case BadMath:
00791               dWisps = 2;
00792               dBackground = 2;
00793               dDensity = 20;
00794               dVisibility = 40;
00795               dSpeed = 30;
00796               dFeedback = 40;
00797               dFeedbackspeed = 5;
00798               dFeedbacksize = 8;
00799               dWireframe = 1;
00800               dTexture = 2;
00801               break;
00802 
00803     case MTheory:
00804               dWisps = 3;
00805               dBackground = 0;
00806               dDensity = 25;
00807               dVisibility = 15;
00808               dSpeed = 20;
00809               dFeedback = 40;
00810               dFeedbackspeed = 20;
00811               dFeedbacksize = 8;
00812               dWireframe = 0;
00813               dTexture = 0;
00814               break;
00815 
00816        case UHFTEM:
00817               dWisps = 0;
00818               dBackground = 3;
00819               dDensity = 35;
00820               dVisibility = 5;
00821               dSpeed = 50;
00822               dFeedback = 0;
00823               dFeedbackspeed = 1;
00824               dFeedbacksize = 8;
00825               dWireframe = 0;
00826               dTexture = 0;
00827               break;
00828 
00829     case Nowhere:
00830               dWisps = 0;
00831               dBackground = 3;
00832               dDensity = 30;
00833               dVisibility = 40;
00834               dSpeed = 20;
00835               dFeedback = 80;
00836               dFeedbackspeed = 10;
00837               dFeedbacksize = 8;
00838               dWireframe = 1;
00839               dTexture = 3;
00840               break;
00841 
00842     case Echo:
00843               dWisps = 3;
00844               dBackground = 0;
00845               dDensity = 25;
00846               dVisibility = 30;
00847               dSpeed = 20;
00848               dFeedback = 85;
00849               dFeedbackspeed = 30;
00850               dFeedbacksize = 8;
00851               dWireframe = 0;
00852               dTexture = 1;
00853               break;
00854 
00855     case Kaleidoscope:
00856               dWisps = 3;
00857               dBackground = 0;
00858               dDensity = 25;
00859               dVisibility = 40;
00860               dSpeed = 15;
00861               dFeedback = 90;
00862               dFeedbackspeed = 3;
00863               dFeedbacksize = 8;
00864               dWireframe = 0;
00865               dTexture = 0;
00866               break;
00867 
00868     case Regular:
00869     default:
00870               dWisps = 5;
00871               dBackground = 0;
00872               dDensity = 25;
00873               dVisibility = 35;
00874               dSpeed = 15;
00875               dFeedback = 0;
00876               dFeedbackspeed = 1;
00877               dFeedbacksize = 8;
00878               dWireframe = 0;
00879               dTexture = 2;
00880               break;
00881        }
00882 }
00883 
00884 
00885 //----------------------------------------------------------------------------
00886 
00887 
00888 #ifndef UNIT_TEST
00889 #include <klocale.h>
00890 #include <kglobal.h>
00891 #include <kconfig.h>
00892 
00893 
00894 // libkscreensaver interface
00895 class KEuphoriaSaverInterface : public KScreenSaverInterface
00896 {
00897 
00898 
00899 public:
00900     virtual KAboutData* aboutData() {
00901         return new KAboutData( "keuphoria.kss", "klock", ki18n( "Euphoria" ), "1.0", ki18n( "Euphoria" ) );
00902     }
00903 
00904 
00905     virtual KScreenSaver* create( WId id )
00906     {
00907         return new KEuphoriaScreenSaver( id );
00908     }
00909 
00910     virtual QDialog* setup()
00911     {
00912         return new KEuphoriaSetup;
00913     }
00914 };
00915 
00916 int main( int argc, char *argv[] )
00917 {
00918     KEuphoriaSaverInterface kss;
00919     return kScreenSaverMain( argc, argv, kss );
00920 }
00921 
00922 
00923 //----------------------------------------------------------------------------
00924 
00925 
00926 KEuphoriaScreenSaver::KEuphoriaScreenSaver( WId id ) : KScreenSaver( id )
00927 {
00928     _effect = new EuphoriaWidget;
00929 
00930     readSettings();
00931 
00932     embed( _effect );
00933     _effect->show();
00934 }
00935 
00936 
00937 KEuphoriaScreenSaver::~KEuphoriaScreenSaver()
00938 {
00939 }
00940 
00941 
00942 static int filterRandom( int n )
00943 {
00944     if( (n < 0) || (n >= EuphoriaWidget::DefaultModes) )
00945     {
00946         srand((unsigned)time(NULL));
00947         n = rand() % EuphoriaWidget::DefaultModes;
00948     }
00949     return n;
00950 }
00951 
00952 
00953 void KEuphoriaScreenSaver::readSettings()
00954 {
00955     KConfigGroup config(KGlobal::config(), "Settings");
00956 
00957     _mode = config.readEntry( "Mode", (int)EuphoriaWidget::Regular );
00958     _effect->setDefaults( filterRandom(_mode) );
00959 }
00960 
00961 
00965 void KEuphoriaScreenSaver::setMode( int id )
00966 {
00967     _mode = id;
00968     _effect->setDefaults( filterRandom(id) );
00969     _effect->updateParameters();
00970 }
00971 
00972 
00973 //----------------------------------------------------------------------------
00974 
00975 
00976 #include <qlayout.h>
00977 #include <qlabel.h>
00978 #include <qcombobox.h>
00979 #include <kmessagebox.h>
00980 
00981 
00982 static const char* defaultText[] =
00983 {
00984     I18N_NOOP( "Regular" ),
00985     I18N_NOOP( "Grid" ),
00986     I18N_NOOP( "Cubism" ),
00987     I18N_NOOP( "Bad Math" ),
00988     I18N_NOOP( "M-Theory" ),
00989     I18N_NOOP( "UHFTEM" ), //"ultra high frequency tunneling electron microscope",
00990     I18N_NOOP( "Nowhere" ),
00991     I18N_NOOP( "Echo" ),
00992     I18N_NOOP( "Kaleidoscope" ),
00993     I18N_NOOP( "(Random)" ),
00994     0
00995 };
00996 
00997 
00998 KEuphoriaSetup::KEuphoriaSetup( QWidget* parent )
00999         : KDialog( parent)
01000 {
01001     setCaption(i18n("Setup Euphoria Screen Saver"));
01002        setButtons(Ok|Cancel|Help);
01003        setDefaultButton(Ok);
01004        setModal(true);
01005        showButtonSeparator(true);
01006     setButtonText( Help, i18n( "A&bout" ) );
01007 
01008     QWidget *main = new QWidget(this);
01009        setMainWidget(main);
01010 
01011     QHBoxLayout* top = new QHBoxLayout( main );
01012     top->setSpacing( spacingHint() );
01013     QVBoxLayout* leftCol = new QVBoxLayout;
01014     top->addLayout( leftCol );
01015 
01016     QLabel* label = new QLabel( i18n("Mode:"), main );
01017     leftCol->addWidget( label );
01018 
01019     modeW = new QComboBox( main );
01020     int i = 0;
01021     while (defaultText[i])
01022         modeW->addItem( i18n(defaultText[i++]) );
01023     leftCol->addWidget( modeW );
01024 
01025     leftCol->addStretch();
01026 
01027     // Preview
01028     QWidget* preview;
01029     preview = new QWidget( main );
01030     preview->setFixedSize( 220, 170 );
01031     {
01032         QPalette palette;
01033         palette.setColor( preview->backgroundRole(), Qt::black );
01034         preview->setPalette( palette );
01035        preview->setAutoFillBackground(true);
01036     }
01037     preview->show();    // otherwise saver does not get correct size
01038     _saver = new KEuphoriaScreenSaver( preview->winId() );
01039     top->addWidget(preview);
01040 
01041     // Now that we have _saver...
01042     modeW->setCurrentIndex( _saver->mode() );    // set before we connect
01043     connect( modeW, SIGNAL(activated(int)), _saver, SLOT(setMode(int)) );
01044        connect(this,SIGNAL(okClicked()),SLOT(slotOk()));
01045        connect(this,SIGNAL(helpClicked()),SLOT(slotHelp()));
01046 
01047     setMinimumSize( sizeHint() );
01048 }
01049 
01050 
01051 KEuphoriaSetup::~KEuphoriaSetup()
01052 {
01053     delete _saver;
01054 }
01055 
01056 
01057 void KEuphoriaSetup::slotHelp()
01058 {
01059     KMessageBox::about(this,
01060         i18n("<h3>Euphoria 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>"),
01061         QString(), KMessageBox::AllowLink);
01062 }
01063 
01064 
01068 void KEuphoriaSetup::slotOk()
01069 {
01070     KConfigGroup config( KGlobal::config(), "Settings");
01071 
01072     config.writeEntry("Mode", QString::number( modeW->currentIndex() ) );
01073 
01074     config.sync();
01075     accept();
01076 }
01077 #endif
01078 //----------------------------------------------------------------------------
01079 
01080 
01081 #ifdef UNIT_TEST
01082 // moc Euphoria.h -o Euphoria.moc
01083 // g++ -g -DUNIT_TEST Euphoria.cpp -I/usr/lib/qt3/include -lqt -L/usr/lib/qt3/lib -lGLU -lGL
01084 
01085 #include <qapplication.h>
01086 
01087 int main( int argc, char** argv )
01088 {
01089     QApplication app( argc, argv );
01090 
01091     EuphoriaWidget w;
01092     w.setDefaults( EuphoriaWidget::UHFTEM );
01093     app.setMainWidget( &w );
01094     w.show();
01095 
01096     return app.exec();
01097 }
01098 #endif
01099 
01100 
01101 //EOF