1 //-----------------------------------------------------------------------------
3 // kfountain - Partical Fountain Screen Saver for KDE 2
5 // Copyright (c) Ian Reinhart Geiser 2001
7 // KConfig code and KScreenSaver "Setup..." improvements by
8 // Nick Betcher <nbetcher@usinternet.com> 2001
13 #include <kapplication.h>
16 #include <kcolordialog.h>
17 #include <kbuttonbox.h>
18 #include <kcolorbutton.h>
21 #include "fountain.moc"
23 #include <OpenGL/gl.h>
24 #include <OpenGL/glu.h>
32 #include <qradiobutton.h>
34 #include <kstandarddirs.h>
36 #include <kmessagebox.h>
38 // libkscreensaver interface
39 class KFountainSaverInterface
: public KScreenSaverInterface
44 virtual KAboutData
* aboutData() {
45 return new KAboutData( "kfountain.kss", I18N_NOOP( "Particle Fountain Screen Saver" ), "2.2.0", I18N_NOOP( "Particle Fountain Screen Saver" ) );
49 virtual KScreenSaver
* create( WId id
)
51 return new KFountainSaver( id
);
54 virtual QDialog
* setup()
56 return new KFountainSetup();
60 int main( int argc
, char *argv
[] )
62 KFountainSaverInterface kss
;
63 return kScreenSaverMain( argc
, argv
, kss
);
66 //-----------------------------------------------------------------------------
67 // dialog to setup screen saver parameters
69 KFountainSetup::KFountainSetup( QWidget
*parent
)
77 //QPushButton *button;
79 //setCaption( i18n("Setup Particle Fountain") );
81 //QVBoxLayout *tl = new QVBoxLayout(this, 10);
82 //QHBoxLayout *tl1 = new QHBoxLayout;
85 //QVBoxLayout *tl11 = new QVBoxLayout(5);
86 //tl1->addLayout(tl11);
88 //label = new QLabel( i18n("No options here yet...:"), this );
89 ///tl11->addWidget(label);;
91 //preview = new QWidget( this );
92 preview
->setFixedSize( 220, 170 );
93 preview
->setBackgroundColor( Qt::black
);
94 preview
->show(); // otherwise saver does not get correct size
95 saver
= new KFountainSaver( preview
->winId() );
96 //tl1->addWidget(preview);
98 //KButtonBox *bbox = new KButtonBox(this);
99 //bbox->addStretch(1);
101 connect( PushButton1
, SIGNAL( clicked() ), SLOT( slotOkPressed() ) );
102 connect( PushButton2
, SIGNAL( clicked() ), SLOT( reject() ) );
103 connect( PushButton3
, SIGNAL( clicked() ), SLOT( aboutPressed() ) );
104 connect( SpinBox1
, SIGNAL( valueChanged(int)), saver
, SLOT( updateSize(int)));
105 connect( RadioButton1
, SIGNAL( toggled(bool)), saver
, SLOT( doStars(bool)));
109 // read settings from config file
110 void KFountainSetup::readSettings()
112 KConfig
config("kssfountainrc", false, false);
114 config
.setGroup( "Settings" );
115 QString boolval
= config
.readEntry( "Stars", "false" );
116 if (boolval
== "true") {
117 RadioButton1
->setDown(true);
118 RadioButton1_2
->setDown(false);
120 if (boolval
== "false")
122 RadioButton1
->setDown(false);
123 RadioButton1_2
->setDown(true);
127 QString starammount
= config
.readEntry("StarSize", "75");
128 SpinBox1
->setValue(starammount
.toInt());
132 // Ok pressed - save settings and exit
133 void KFountainSetup::slotOkPressed()
135 KConfig
config("kssfountainrc", false, false);
136 config
.setGroup( "Settings" );
138 if (RadioButton1
->isOn() == true)
140 config
.writeEntry( "Stars", "true" );
142 if (RadioButton1_2
->isOn() == true)
144 config
.writeEntry( "Stars", "false" );
147 config
.writeEntry( "StarSize", QString::number(SpinBox1
->value()) );
154 void KFountainSetup::aboutPressed()
156 KMessageBox::about(this,
157 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>"));
159 //-----------------------------------------------------------------------------
162 KFountainSaver::KFountainSaver( WId id
) : KScreenSaver( id
)
165 kDebug() << "Blank" << endl
;
167 timer
= new QTimer( this );
168 timer
->setSingleShot(true);
170 setBackgroundColor( Qt::black
);
172 fountain
= new Fountain();
175 connect( timer
, SIGNAL(timeout()), this, SLOT(blank()) );
178 KFountainSaver::~KFountainSaver()
183 // read configuration settings from config file
184 void KFountainSaver::readSettings()
190 void KFountainSaver::blank()
194 fountain
->updateGL();
195 timer
->setSingleShot(true);
199 Fountain::Fountain( QWidget
* parent
, const char * name
) : QGLWidget (parent
,name
)
206 obj
= gluNewQuadric();
208 // This has to be here because you can't update the fountain until 'fountain' is created!
209 KConfig
config("kssfountainrc", false, false);
210 config
.setGroup( "Settings" );
211 QString boolval
= config
.readEntry( "Stars", "false" );
212 if (boolval
== "true") {
215 if (boolval
== "false")
221 QString starammount
= config
.readEntry("StarSize", "75");
222 float passvalue
= (starammount
.toInt() / 100.0);
227 Fountain::~Fountain()
229 glDeleteTextures( 1, &texture
[0] );
230 gluDeleteQuadric(obj
);
233 /** load the particle file */
234 bool Fountain::loadParticle()
236 /* Status indicator */
240 kDebug() << "Loading: " << KStandardDirs::locate("data", "kscreensaver/particle.png") << endl
;
241 if (buf
.load( KStandardDirs::locate("data", "kscreensaver/particle.png") ) )
244 tex
= convertToGLFormat(buf
); // flipped 32bit RGBA
245 kDebug() << "Texture loaded: " << tex
.numBytes () << endl
;
249 QImage
dummy( 32, 32, 32 );
250 dummy
.fill( Qt::white
);
252 tex
= convertToGLFormat( buf
);
255 /* Set the status to true */
257 glGenTextures(1, &texture
[0]); /* create three textures */
258 glBindTexture(GL_TEXTURE_2D
, texture
[0]);
259 /* use linear filtering */
260 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
261 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
262 /* actually generate the texture */
263 glTexImage2D(GL_TEXTURE_2D
, 0, 4, tex
.width(), tex
.height(), 0,
264 GL_RGBA
, GL_UNSIGNED_BYTE
, tex
.bits());
270 /** setup the GL enviroment */
271 void Fountain::initializeGL ()
274 kDebug() << "InitGL" << endl
;
275 GLfloat colors
[12][3]=
276 {{1.0f
,0.5f
,0.5f
},{1.0f
,0.75f
,0.5f
},{1.0f
,1.0f
,0.5f
},{0.75f
,1.0f
,0.5f
},
277 {0.5f
,1.0f
,0.5f
},{0.5f
,1.0f
,0.75f
},{0.5f
,1.0f
,1.0f
},{0.5f
,0.75f
,1.0f
},
278 {0.5f
,0.5f
,1.0f
},{0.75f
,0.5f
,1.0f
},{1.0f
,0.5f
,1.0f
},{1.0f
,0.5f
,0.75f
}};
280 if (loadParticle()) // Jump To Texture Loading Routine
282 /* Enable smooth shading */
283 glShadeModel( GL_SMOOTH
);
285 /* Set the background black */
286 glClearColor( 0.0f
, 0.0f
, 0.0f
, 0.0f
);
288 /* Depth buffer setup */
289 glClearDepth( 1.0f
);
291 /* Enables Depth Testing */
292 glDisable( GL_DEPTH_TEST
);
294 /* Enable Blending */
295 glEnable( GL_BLEND
);
296 /* Type Of Blending To Perform */
297 glBlendFunc( GL_SRC_ALPHA
, GL_ONE
);
300 /* Really Nice Perspective Calculations */
301 glHint( GL_PERSPECTIVE_CORRECTION_HINT
, GL_NICEST
);
302 /* Really Nice Point Smoothing */
303 glHint( GL_POINT_SMOOTH_HINT
, GL_NICEST
);
305 /* Enable Texture Mapping */
306 glEnable( GL_TEXTURE_2D
);
307 /* Select Our Texture */
308 glBindTexture( GL_TEXTURE_2D
, texture
[0] );
310 for (loop
=0;loop
<MAX_PARTICLES
;loop
++) // Initials All The Textures
312 particle
[loop
].active
=true; // Make All The Particles Active
313 particle
[loop
].life
=1.0f
; // Give All The Particles Full Life
314 particle
[loop
].fade
=float(KRandom::random()%100)/1000.0f
+0.003f
; // Random Fade Speed
315 int color_index
= (loop
+1)/(MAX_PARTICLES
/12);
316 color_index
= qMin(11, color_index
);
317 particle
[loop
].r
=colors
[color_index
][0]; // Select Red Rainbow Color
318 particle
[loop
].g
=colors
[color_index
][1]; // Select Green Rainbow Color
319 particle
[loop
].b
=colors
[color_index
][2]; // Select Blue Rainbow Color
320 particle
[loop
].xi
=float((KRandom::random()%50)-26.0f
)*10.0f
; // Random Speed On X Axis
321 particle
[loop
].yi
=float((KRandom::random()%50)-25.0f
)*10.0f
; // Random Speed On Y Axis
322 particle
[loop
].zi
=float((KRandom::random()%50)-25.0f
)*10.0f
; // Random Speed On Z Axis
323 particle
[loop
].xg
=0.0f
; // Set Horizontal Pull To Zero
324 particle
[loop
].yg
=-0.8f
; // Set Vertical Pull Downward
325 particle
[loop
].zg
=0.0f
; // Set Pull On Z Axis To Zero
326 particle
[loop
].size
=size
; // Set particle size.
332 /** resize the gl view */
333 void Fountain::resizeGL ( int width
, int height
)
335 kDebug() << "ResizeGL " << width
<< "," <<height
<< endl
;
336 if (height
==0) // Prevent A Divide By Zero By
338 height
=1; // Making Height Equal One
341 glViewport(0,0,width
,height
); // Reset The Current Viewport
343 glMatrixMode(GL_PROJECTION
); // Select The Projection Matrix
344 glLoadIdentity(); // Reset The Projection Matrix
346 // Calculate The Aspect Ratio Of The Window
347 gluPerspective(45.0f
,(GLfloat
)width
/(GLfloat
)height
,0.1f
,200.0f
);
349 glMatrixMode(GL_MODELVIEW
); // Select The Modelview Matrix
352 /** paint the GL view */
353 void Fountain::paintGL ()
355 //kDebug() << "PaintGL" << endl;
357 GLfloat colors
[12][3]=
358 {{1.0f
,0.5f
,0.5f
},{1.0f
,0.75f
,0.5f
},{1.0f
,1.0f
,0.5f
},{0.75f
,1.0f
,0.5f
},
359 {0.5f
,1.0f
,0.5f
},{0.5f
,1.0f
,0.75f
},{0.5f
,1.0f
,1.0f
},{0.5f
,0.75f
,1.0f
},
360 {0.5f
,0.5f
,1.0f
},{0.75f
,0.5f
,1.0f
},{1.0f
,0.5f
,1.0f
},{1.0f
,0.5f
,0.75f
}};
361 col
= ( ++col
) % 12;
362 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
); // Clear Screen And Depth Buffer
365 // Reset The ModelView Matrix
367 glTranslatef( GLfloat(5.0*sin(4*3.14*transIndex
/360)), GLfloat(4.0*cos(2*3.14*transIndex
/360)), 0.0 );
368 xspeed
= GLfloat(100.0*cos(3*3.14*transIndex
/360)+100);
369 yspeed
= GLfloat(100.0*sin(3*3.14*transIndex
/360)+100);
370 //slowdown = GLfloat(4.0*sin(2*3.14*transIndex/360)+4.01);
372 for (loop
=0;loop
<MAX_PARTICLES
;loop
++) // Loop Through All The Particles
374 if (particle
[loop
].active
) // If The Particle Is Active
376 float x
=particle
[loop
].x
; // Grab Our Particle X Position
377 float y
=particle
[loop
].y
; // Grab Our Particle Y Position
378 float z
=particle
[loop
].z
+zoom
; // Particle Z Pos + Zoom
379 /* Select Our Texture */
381 /* Draw The Particle Using Our RGB Values,
382 * Fade The Particle Based On It's Life
385 glColor4f( particle
[loop
].r
,
388 particle
[loop
].life
);
390 /* Build Quad From A Triangle Strip */
392 glBegin( GL_TRIANGLE_STRIP
);
394 glBegin( GL_TRIANGLE_FAN
);
396 glTexCoord2d( 1, 1 );
397 glVertex3f( x
+ particle
[loop
].size
, y
+ particle
[loop
].size
, z
);
399 glTexCoord2d( 0, 1 );
400 glVertex3f( x
- particle
[loop
].size
, y
+ particle
[loop
].size
, z
);
402 glTexCoord2d( 1, 0 );
403 glVertex3f( x
+ particle
[loop
].size
, y
- particle
[loop
].size
, z
);
405 glTexCoord2d( 0, 0 );
406 glVertex3f( x
- particle
[loop
].size
, y
- particle
[loop
].size
, z
);
409 particle
[loop
].x
+=particle
[loop
].xi
/(slowdown
*1000);// Move On The X Axis By X Speed
410 particle
[loop
].y
+=particle
[loop
].yi
/(slowdown
*1000);// Move On The Y Axis By Y Speed
411 particle
[loop
].z
+=particle
[loop
].zi
/(slowdown
*1000);// Move On The Z Axis By Z Speed
413 particle
[loop
].xi
+=particle
[loop
].xg
; // Take Pull On X Axis Into Account
414 particle
[loop
].yi
+=particle
[loop
].yg
; // Take Pull On Y Axis Into Account
415 particle
[loop
].zi
+=particle
[loop
].zg
; // Take Pull On Z Axis Into Account
416 particle
[loop
].life
-=particle
[loop
].fade
; // Reduce Particles Life By 'Fade'
418 if (particle
[loop
].life
<0.0f
) // If Particle Is Burned Out
420 particle
[loop
].life
=2.0f
; // Give It New Life
421 particle
[loop
].fade
=float(KRandom::random()%100)/1000.0f
+0.003f
; // Random Fade Value
422 particle
[loop
].x
=0.0f
; // Center On X Axis
423 particle
[loop
].y
=0.0f
; // Center On Y Axis
424 particle
[loop
].z
=0.0f
; // Center On Z Axis
425 particle
[loop
].xi
=xspeed
+float((KRandom::random()%60)-32.0f
); // X Axis Speed And Direction
426 particle
[loop
].yi
=yspeed
+float((KRandom::random()%60)-30.0f
); // Y Axis Speed And Direction
427 particle
[loop
].zi
=float((KRandom::random()%60)-30.0f
); // Z Axis Speed And Direction
428 particle
[loop
].r
=colors
[col
][0]; // Select Red From Color Table
429 particle
[loop
].g
=colors
[col
][1]; // Select Green From Color Table
430 particle
[loop
].b
=colors
[col
][2]; // Select Blue From Color Table
431 particle
[loop
].size
=size
;
432 if ((1+(random()%20)) == 10)
435 particle
[loop
].active
=true; // Make All The Particles Active
436 particle
[loop
].life
=1.0f
; // Give All The Particles Full Life
437 particle
[loop
].fade
=float(KRandom::random()%100)/1000.0f
+0.003f
; // Random Fade Speed
438 int color_index
= (loop
+1)/(MAX_PARTICLES
/12);
439 color_index
= qMin(11, color_index
);
440 particle
[loop
].r
=colors
[color_index
][0]; // Select Red Rainbow Color
441 particle
[loop
].g
=colors
[color_index
][1]; // Select Green Rainbow Color
442 particle
[loop
].b
=colors
[color_index
][2]; // Select Blue Rainbow Color
443 particle
[loop
].xi
=float((KRandom::random()%50)-26.0f
)*10.0f
; // Random Speed On X Axis
444 particle
[loop
].yi
=float((KRandom::random()%50)-25.0f
)*10.0f
; // Random Speed On Y Axis
445 particle
[loop
].zi
=float((KRandom::random()%50)-25.0f
)*10.0f
; // Random Speed On Z Axis
446 particle
[loop
].xg
=0.0f
; // Set Horizontal Pull To Zero
447 particle
[loop
].yg
=-0.8f
; // Set Vertical Pull Downward
448 particle
[loop
].zg
=0.0f
; // Set Pull On Z Axis To Zero
449 particle
[loop
].size
=size
; // Set particle size.
452 // Lets stir some things up
454 particle
[loop
].yg
=2.0*sin(2*3.14*transIndex
/360);
455 particle
[loop
].xg
=2.0*cos(2*3.14*transIndex
/360);
456 particle
[loop
].zg
=4.0+(4.0*cos(2*3.14*transIndex
/360));
463 void Fountain::setSize( float newSize
)
467 void Fountain::setStars( bool doStars
)
472 void KFountainSaver::updateSize(int newSize
)
474 fountain
->setSize(newSize
/100);
476 void KFountainSaver::doStars(bool starState
)
478 fountain
->setStars(starState
);