Back to index

kdeartwork  4.3.2
fountain.cpp
Go to the documentation of this file.
00001 //-----------------------------------------------------------------------------
00002 //
00003 // kfountain - Partical Fountain Screen Saver for KDE
00004 //
00005 // Copyright (c)  Ian Reinhart Geiser 2001
00006 //
00007 // KConfig code and KScreenSaver "Setup..." improvements by
00008 // Nick Betcher <nbetcher@usinternet.com> 2001
00009 //
00010 #include <stdlib.h>
00011 #include <qlabel.h>
00012 #include <qlayout.h>
00013 #include <kapplication.h>
00014 #include <klocale.h>
00015 #include <kconfig.h>
00016 #include <kcolordialog.h>
00017 #include <kcolorbutton.h>
00018 #include <kglobal.h>
00019 #include "fountain.h"
00020 #include "fountain.moc"
00021 #ifdef Q_WS_MACX
00022 #include <OpenGL/gl.h>
00023 #include <OpenGL/glu.h>
00024 #else
00025 #include <GL/glu.h>
00026 #include <GL/gl.h>
00027 #endif
00028 #include <qimage.h>
00029 #include <kdebug.h>
00030 #include <qpainter.h>
00031 #include <qradiobutton.h>
00032 #include <qspinbox.h>
00033 #include <kstandarddirs.h>
00034 #include <math.h>
00035 #include <kmessagebox.h>
00036 #include <krandom.h>
00037 // libkscreensaver interface
00038 class KFountainSaverInterface : public KScreenSaverInterface
00039 {
00040 
00041 
00042 public:
00043     virtual KAboutData* aboutData() {
00044         return new KAboutData( "kfountain.kss", "klock", ki18n( "Particle Fountain Screen Saver" ), "2.2.0", ki18n( "Particle Fountain Screen Saver" ) );
00045     }
00046 
00047 
00048        virtual KScreenSaver* create( WId id )
00049        {
00050               return new KFountainSaver( id );
00051        }
00052 
00053        virtual QDialog* setup()
00054        {
00055               return new KFountainSetup();
00056        }
00057 };
00058 
00059 int main( int argc, char *argv[] )
00060 {
00061     KFountainSaverInterface kss;
00062     return kScreenSaverMain( argc, argv, kss );
00063 }
00064 
00065 //-----------------------------------------------------------------------------
00066 // dialog to setup screen saver parameters
00067 //
00068 KFountainSetup::KFountainSetup( QWidget *parent )
00069        : QDialog( parent)
00070 {
00071        setupUi(this);
00072        setModal(true);
00073        readSettings();
00074 
00075        //QLabel *label;
00076        //QPushButton *button;
00077 
00078        //setCaption( i18n("Setup Particle Fountain") );
00079 
00080        //QVBoxLayout *tl = new QVBoxLayout(this, 10);
00081        //QHBoxLayout *tl1 = new QHBoxLayout;
00082        //tl->addLayout(tl1);
00083 
00084        //QVBoxLayout *tl11 = new QVBoxLayout(5);
00085        //tl1->addLayout(tl11);
00086 
00087        //label = new QLabel( i18n("No options here yet...:"), this );
00089 
00090        //preview = new QWidget( this );
00091        preview->setFixedSize( 220, 170 );
00092         {
00093             QPalette palette;
00094             palette.setColor( preview->backgroundRole(), Qt::black );
00095             preview->setPalette( palette );
00096            preview->setAutoFillBackground(true);
00097         }
00098        preview->show();    // otherwise saver does not get correct size
00099        saver = new KFountainSaver( preview->winId() );
00100        //tl1->addWidget(preview);
00101 
00102        //KButtonBox *bbox = new KButtonBox(this);
00103        //bbox->addStretch(1);
00104 ;
00105        connect( PushButton1, SIGNAL( clicked() ), SLOT( slotOkPressed() ) );
00106        connect( PushButton2, SIGNAL( clicked() ), SLOT( reject() ) );
00107        connect( PushButton3, SIGNAL( clicked() ), SLOT( aboutPressed() ) );
00108        connect(  SpinBox1, SIGNAL( valueChanged(int)), saver, SLOT( updateSize(int)));
00109        connect( RadioButton1, SIGNAL( toggled(bool)), saver, SLOT( doStars(bool)));
00110 
00111 }
00112 
00113 // read settings from config file
00114 void KFountainSetup::readSettings()
00115 {
00116        KConfig config("kssfountainrc", KConfig::NoGlobals);
00117        KConfigGroup grp = config.group("Settings");
00118 
00119        bool boolval = grp.readEntry( "Stars", false );
00120        if (boolval) {
00121               RadioButton1->setChecked(true);
00122        } else {
00123                      RadioButton1_2->setChecked(true);
00124        }
00125 
00126        int starammount = grp.readEntry("StarSize", 75);
00127        SpinBox1->setValue(starammount);
00128 
00129 }
00130 
00131 // Ok pressed - save settings and exit
00132 void KFountainSetup::slotOkPressed()
00133 {
00134        KConfig _config("kssfountainrc", KConfig::NoGlobals);
00135        KConfigGroup config(&_config, "Settings" );
00136 
00137        if (RadioButton1->isChecked() == true)
00138        {
00139               config.writeEntry( "Stars", true );
00140        } else {
00141               if (RadioButton1_2->isChecked() == true)
00142               {
00143                      config.writeEntry( "Stars", false );
00144               }
00145        }
00146        config.writeEntry( "StarSize", SpinBox1->value() );
00147 
00148        config.sync();
00149 
00150        accept();
00151 }
00152 
00153 void KFountainSetup::aboutPressed()
00154 {
00155     KMessageBox::about(this,
00156         i18n("<h3>Particle Fountain</h3>\n<p>Particle Fountain Screen Saver for KDE</p>\nCopyright (c)  Ian Reinhart Geiser 2001<br>\n\n<p>KConfig code and KScreenSaver \"Setup...\" improvements by Nick Betcher <nbetcher@usinternet.com> 2001</p>"));
00157 }
00158 //-----------------------------------------------------------------------------
00159 
00160 
00161 KFountainSaver::KFountainSaver( WId id ) : KScreenSaver( id )
00162 {
00163 
00164        kDebug() << "Blank";
00165 
00166        timer = new QTimer( this );
00167         timer->setSingleShot( true );
00168         timer->start( 25 );
00169         {
00170             QPalette palette;
00171             palette.setColor( backgroundRole(), Qt::black );
00172             setPalette( palette );
00173         }
00174         update();
00175        fountain = new Fountain();
00176        embed(fountain);
00177        fountain->show();
00178        connect( timer, SIGNAL(timeout()), this, SLOT(blank()) );
00179        show();
00180 }
00181 
00182 KFountainSaver::~KFountainSaver()
00183 {
00184 
00185 }
00186 
00187 // read configuration settings from config file
00188 void KFountainSaver::readSettings()
00189 {
00190 // Please remove me
00191 
00192 }
00193 
00194 void KFountainSaver::blank()
00195 {
00196        // Play fountain
00197 
00198        fountain->updateGL();
00199     timer->setSingleShot(true);
00200        timer->start( 25);
00201 
00202 }
00203 Fountain::Fountain( QWidget * parent ) : QGLWidget (parent)
00204 {
00205        rainbow=true;
00206        slowdown=2.0f;
00207        zoom=-40.0f;
00208        index=0;
00209        size = 0.75f;
00210        obj = gluNewQuadric();
00211 
00212 // This has to be here because you can't update the fountain until 'fountain' is created!
00213        KConfig _config("kssfountainrc", KConfig::NoGlobals);
00214        KConfigGroup config(&_config, "Settings" );
00215        bool boolval = config.readEntry( "Stars", false );
00216         setStars(boolval);
00217 
00218        int starammount = config.readEntry("StarSize", 75);
00219        float passvalue = (starammount / 100.0);
00220        setSize(passvalue);
00221 
00222 }
00223 
00224 Fountain::~Fountain()
00225 {
00226        glDeleteTextures( 1, &texture[0] );
00227        gluDeleteQuadric(obj);
00228 }
00229 
00231 bool Fountain::loadParticle()
00232 {
00233     /* Status indicator */
00234     bool Status = true;
00235     QImage buf;
00236 
00237     kDebug() << "Loading: " << KStandardDirs::locate("data", "kscreensaver/particle.png");
00238 
00239     if (buf.load( KStandardDirs::locate("data", "kscreensaver/particle.png") ) )
00240     {
00241         tex = convertToGLFormat(buf);  // flipped 32bit RGBA
00242         kDebug() << "Texture loaded: " << tex.numBytes ();
00243     }
00244     else
00245     {
00246         QImage dummy( 32, 32, QImage::Format_RGB32 );
00247         dummy.fill( Qt::white );
00248         buf = dummy;
00249         tex = convertToGLFormat( buf );
00250     }
00251 
00252     /* Set the status to true */
00253     //Status = true;
00254     glGenTextures(1, &texture[0]);   /* create three textures */
00255     glBindTexture(GL_TEXTURE_2D, texture[0]);
00256     /* use linear filtering */
00257     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00258     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00259     /* actually generate the texture */
00260     glTexImage2D(GL_TEXTURE_2D, 0, 4, tex.width(), tex.height(), 0,
00261     GL_RGBA, GL_UNSIGNED_BYTE, tex.bits());
00262 
00263 
00264 
00265     return Status;
00266 }
00268 void Fountain::initializeGL ()
00269 {
00270 
00271        kDebug() << "InitGL";
00272        GLfloat colors[12][3]=
00273        {{1.0f,0.5f,0.5f},{1.0f,0.75f,0.5f},{1.0f,1.0f,0.5f},{0.75f,1.0f,0.5f},
00274        {0.5f,1.0f,0.5f},{0.5f,1.0f,0.75f},{0.5f,1.0f,1.0f},{0.5f,0.75f,1.0f},
00275        {0.5f,0.5f,1.0f},{0.75f,0.5f,1.0f},{1.0f,0.5f,1.0f},{1.0f,0.5f,0.75f}};
00276 
00277        if (loadParticle())                                     // Jump To Texture Loading Routine
00278        {
00279     /* Enable smooth shading */
00280     glShadeModel( GL_SMOOTH );
00281 
00282     /* Set the background black */
00283     glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
00284 
00285     /* Depth buffer setup */
00286     glClearDepth( 1.0f );
00287 
00288     /* Enables Depth Testing */
00289     glDisable( GL_DEPTH_TEST );
00290 
00291     /* Enable Blending */
00292     glEnable( GL_BLEND );
00293     /* Type Of Blending To Perform */
00294     glBlendFunc( GL_SRC_ALPHA, GL_ONE );
00295 
00296 
00297     /* Really Nice Perspective Calculations */
00298     glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
00299     /* Really Nice Point Smoothing */
00300     glHint( GL_POINT_SMOOTH_HINT, GL_NICEST );
00301 
00302     /* Enable Texture Mapping */
00303     glEnable( GL_TEXTURE_2D );
00304     /* Select Our Texture */
00305     glBindTexture( GL_TEXTURE_2D, texture[0] );
00306 
00307               for (loop=0;loop<MAX_PARTICLES;loop++)                         // Initials All The Textures
00308               {
00309                      particle[loop].active=true;                      // Make All The Particles Active
00310                      particle[loop].life=1.0f;                        // Give All The Particles Full Life
00311                      particle[loop].fade=float(KRandom::random()%100)/1000.0f+0.003f;      // Random Fade Speed
00312                      int color_index = (loop+1)/(MAX_PARTICLES/12);
00313                      color_index = qMin(11, color_index);
00314                      particle[loop].r=colors[color_index][0];  // Select Red Rainbow Color
00315                      particle[loop].g=colors[color_index][1];  // Select Green Rainbow Color
00316                      particle[loop].b=colors[color_index][2];  // Select Blue Rainbow Color
00317                      particle[loop].xi=float((KRandom::random()%50)-26.0f)*10.0f;   // Random Speed On X Axis
00318                      particle[loop].yi=float((KRandom::random()%50)-25.0f)*10.0f;   // Random Speed On Y Axis
00319                      particle[loop].zi=float((KRandom::random()%50)-25.0f)*10.0f;   // Random Speed On Z Axis
00320                      particle[loop].xg=0.0f;                                 // Set Horizontal Pull To Zero
00321                      particle[loop].yg=-0.8f;                         // Set Vertical Pull Downward
00322                      particle[loop].zg=0.0f;                                 // Set Pull On Z Axis To Zero
00323                      particle[loop].size=size;                        // Set particle size.
00324               }
00325        }
00326        else
00327               exit(0);
00328 }
00330 void Fountain::resizeGL ( int width, int height )
00331 {
00332        kDebug() << "ResizeGL " << width << "," <<height;
00333        if (height==0)                                                 // Prevent A Divide By Zero By
00334        {
00335               height=1;                                        // Making Height Equal One
00336        }
00337 
00338        glViewport(0,0,width,height);                                  // Reset The Current Viewport
00339 
00340        glMatrixMode(GL_PROJECTION);                                   // Select The Projection Matrix
00341        glLoadIdentity();                                       // Reset The Projection Matrix
00342 
00343        // Calculate The Aspect Ratio Of The Window
00344        gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,200.0f);
00345 
00346        glMatrixMode(GL_MODELVIEW);                             // Select The Modelview Matrix
00347        glLoadIdentity();
00348 }
00350 void Fountain::paintGL ()
00351 {
00352        //kDebug() << "PaintGL";
00353 
00354        GLfloat colors[12][3]=
00355        {{1.0f,0.5f,0.5f},{1.0f,0.75f,0.5f},{1.0f,1.0f,0.5f},{0.75f,1.0f,0.5f},
00356        {0.5f,1.0f,0.5f},{0.5f,1.0f,0.75f},{0.5f,1.0f,1.0f},{0.5f,0.75f,1.0f},
00357        {0.5f,0.5f,1.0f},{0.75f,0.5f,1.0f},{1.0f,0.5f,1.0f},{1.0f,0.5f,0.75f}};
00358        col = ( ++col ) % 12;
00359        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);            // Clear Screen And Depth Buffer
00360 
00361        glLoadIdentity();
00362                                           // Reset The ModelView Matrix
00363        transIndex++;
00364        glTranslatef( GLfloat(5.0*sin(4*3.14*transIndex/360)), GLfloat(4.0*cos(2*3.14*transIndex/360)), 0.0 );
00365        xspeed = GLfloat(100.0*cos(3*3.14*transIndex/360)+100);
00366        yspeed = GLfloat(100.0*sin(3*3.14*transIndex/360)+100);
00367        //slowdown = GLfloat(4.0*sin(2*3.14*transIndex/360)+4.01);
00368 
00369        for (loop=0;loop<MAX_PARTICLES;loop++)                         // Loop Through All The Particles
00370        {
00371               if (particle[loop].active)                       // If The Particle Is Active
00372               {
00373                      float x=particle[loop].x;                 // Grab Our Particle X Position
00374                      float y=particle[loop].y;                 // Grab Our Particle Y Position
00375                      float z=particle[loop].z+zoom;                   // Particle Z Pos + Zoom
00376     /* Select Our Texture */
00377 
00378                     /* Draw The Particle Using Our RGB Values,
00379                      * Fade The Particle Based On It's Life
00380                      */
00381 
00382                     glColor4f( particle[loop].r,
00383                                particle[loop].g,
00384                                particle[loop].b,
00385                                particle[loop].life );
00386 
00387                     /* Build Quad From A Triangle Strip */
00388                 if( !stars )
00389                   glBegin( GL_TRIANGLE_STRIP );
00390                 else
00391                   glBegin( GL_TRIANGLE_FAN );
00392                       /* Top Right */
00393                       glTexCoord2d( 1, 1 );
00394                       glVertex3f( x + particle[loop].size, y + particle[loop].size, z );
00395                       /* Top Left */
00396                       glTexCoord2d( 0, 1 );
00397                       glVertex3f( x - particle[loop].size, y + particle[loop].size, z );
00398                       /* Bottom Right */
00399                       glTexCoord2d( 1, 0 );
00400                       glVertex3f( x + particle[loop].size, y - particle[loop].size, z );
00401                       /* Bottom Left */
00402                       glTexCoord2d( 0, 0 );
00403                       glVertex3f( x - particle[loop].size, y - particle[loop].size, z );
00404                     glEnd( );
00405 
00406                      particle[loop].x+=particle[loop].xi/(slowdown*1000);// Move On The X Axis By X Speed
00407                      particle[loop].y+=particle[loop].yi/(slowdown*1000);// Move On The Y Axis By Y Speed
00408                      particle[loop].z+=particle[loop].zi/(slowdown*1000);// Move On The Z Axis By Z Speed
00409 
00410                      particle[loop].xi+=particle[loop].xg;                   // Take Pull On X Axis Into Account
00411                      particle[loop].yi+=particle[loop].yg;                   // Take Pull On Y Axis Into Account
00412                      particle[loop].zi+=particle[loop].zg;                   // Take Pull On Z Axis Into Account
00413                      particle[loop].life-=particle[loop].fade;        // Reduce Particles Life By 'Fade'
00414 
00415                      if (particle[loop].life<0.0f)                                  // If Particle Is Burned Out
00416                      {
00417                             particle[loop].life=2.0f;                        // Give It New Life
00418                             particle[loop].fade=float(KRandom::random()%100)/1000.0f+0.003f;      // Random Fade Value
00419                             particle[loop].x=0.0f;                                  // Center On X Axis
00420                             particle[loop].y=0.0f;                                  // Center On Y Axis
00421                             particle[loop].z=0.0f;                                  // Center On Z Axis
00422                             particle[loop].xi=xspeed+float((KRandom::random()%60)-32.0f);  // X Axis Speed And Direction
00423                             particle[loop].yi=yspeed+float((KRandom::random()%60)-30.0f);  // Y Axis Speed And Direction
00424                             particle[loop].zi=float((KRandom::random()%60)-30.0f);         // Z Axis Speed And Direction
00425                             particle[loop].r=colors[col][0];                 // Select Red From Color Table
00426                             particle[loop].g=colors[col][1];                 // Select Green From Color Table
00427                             particle[loop].b=colors[col][2];                 // Select Blue From Color Table
00428                             particle[loop].size=size;
00429                             if ((1+(random()%20)) == 10)
00430                             {
00431                             // Explode
00432                                    particle[loop].active=true;                      // Make All The Particles Active
00433                                    particle[loop].life=1.0f;                        // Give All The Particles Full Life
00434                                    particle[loop].fade=float(KRandom::random()%100)/1000.0f+0.003f;      // Random Fade Speed
00435                                    int color_index = (loop+1)/(MAX_PARTICLES/12);
00436                                    color_index = qMin(11, color_index);
00437                                    particle[loop].r=colors[color_index][0];        // Select Red Rainbow Color
00438                                    particle[loop].g=colors[color_index][1];        // Select Green Rainbow Color
00439                                    particle[loop].b=colors[color_index][2];  // Select Blue Rainbow Color
00440                                    particle[loop].xi=float((KRandom::random()%50)-26.0f)*10.0f;   // Random Speed On X Axis
00441                                    particle[loop].yi=float((KRandom::random()%50)-25.0f)*10.0f;   // Random Speed On Y Axis
00442                                    particle[loop].zi=float((KRandom::random()%50)-25.0f)*10.0f;   // Random Speed On Z Axis
00443                                    particle[loop].xg=0.0f;                                 // Set Horizontal Pull To Zero
00444                                    particle[loop].yg=-0.8f;                         // Set Vertical Pull Downward
00445                                    particle[loop].zg=0.0f;                                 // Set Pull On Z Axis To Zero
00446                                    particle[loop].size=size;                        // Set particle size.
00447                             }
00448                      }
00449                      // Lets stir some things up
00450                      index += 0.001;
00451                      particle[loop].yg =2.0*sin(2*3.14*transIndex/360);
00452                      particle[loop].xg =2.0*cos(2*3.14*transIndex/360);
00453                      particle[loop].zg =4.0+(4.0*cos(2*3.14*transIndex/360));
00454 
00455               }
00456        }
00457 
00458        glFlush();
00459 }
00460 void Fountain::setSize( float newSize )
00461 {
00462        size = newSize;
00463 }
00464 void Fountain::setStars( bool doStars )
00465 {
00466        stars = doStars;
00467 }
00468 
00469 void KFountainSaver::updateSize(int newSize)
00470 {
00471        fountain->setSize(newSize/100);
00472 }
00473 void KFountainSaver::doStars(bool starState)
00474 {
00475        fountain->setStars(starState);
00476 }
00477