Install just if we compile with opengl
[kdeartwork.git] / kscreensaver / kdesavers / fountain.cpp
blobf9b4e9bee83da4c6df9f3f3259d09c0c2155af5c
1 //-----------------------------------------------------------------------------
2 //
3 // kfountain - Partical Fountain Screen Saver for KDE 2
4 //
5 // Copyright (c) Ian Reinhart Geiser 2001
6 //
7 // KConfig code and KScreenSaver "Setup..." improvements by
8 // Nick Betcher <nbetcher@usinternet.com> 2001
9 //
10 #include <stdlib.h>
11 #include <qlabel.h>
12 #include <qlayout.h>
13 #include <kapplication.h>
14 #include <klocale.h>
15 #include <kconfig.h>
16 #include <kcolordialog.h>
17 #include <kbuttonbox.h>
18 #include <kcolorbutton.h>
19 #include <kglobal.h>
20 #include "fountain.h"
21 #include "fountain.moc"
22 #ifdef Q_WS_MACX
23 #include <OpenGL/gl.h>
24 #include <OpenGL/glu.h>
25 #else
26 #include <GL/glu.h>
27 #include <GL/gl.h>
28 #endif
29 #include <qimage.h>
30 #include <kdebug.h>
31 #include <qpainter.h>
32 #include <qradiobutton.h>
33 #include <qspinbox.h>
34 #include <kstandarddirs.h>
35 #include <math.h>
36 #include <kmessagebox.h>
37 #include <krandom.h>
38 // libkscreensaver interface
39 class KFountainSaverInterface : public KScreenSaverInterface
43 public:
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, const char *name )
70 : SetupUi( parent, name, TRUE )
72 readSettings();
74 //QLabel *label;
75 //QPushButton *button;
77 //setCaption( i18n("Setup Particle Fountain") );
79 //QVBoxLayout *tl = new QVBoxLayout(this, 10);
80 //QHBoxLayout *tl1 = new QHBoxLayout;
81 //tl->addLayout(tl1);
83 //QVBoxLayout *tl11 = new QVBoxLayout(5);
84 //tl1->addLayout(tl11);
86 //label = new QLabel( i18n("No options here yet...:"), this );
87 ///tl11->addWidget(label);;
89 //preview = new QWidget( this );
90 preview->setFixedSize( 220, 170 );
91 preview->setBackgroundColor( Qt::black );
92 preview->show(); // otherwise saver does not get correct size
93 saver = new KFountainSaver( preview->winId() );
94 //tl1->addWidget(preview);
96 //KButtonBox *bbox = new KButtonBox(this);
97 //bbox->addStretch(1);
99 connect( PushButton1, SIGNAL( clicked() ), SLOT( slotOkPressed() ) );
100 connect( PushButton2, SIGNAL( clicked() ), SLOT( reject() ) );
101 connect( PushButton3, SIGNAL( clicked() ), SLOT( aboutPressed() ) );
102 connect( SpinBox1, SIGNAL( valueChanged(int)), saver, SLOT( updateSize(int)));
103 connect( RadioButton1, SIGNAL( toggled(bool)), saver, SLOT( doStars(bool)));
107 // read settings from config file
108 void KFountainSetup::readSettings()
110 KConfig config("kssfountainrc", false, false);
112 config.setGroup( "Settings" );
113 QString boolval = config.readEntry( "Stars", "false" );
114 if (boolval == "true") {
115 RadioButton1->setDown(true);
116 RadioButton1_2->setDown(false);
117 } else {
118 if (boolval == "false")
120 RadioButton1->setDown(false);
121 RadioButton1_2->setDown(true);
125 QString starammount = config.readEntry("StarSize", "75");
126 SpinBox1->setValue(starammount.toInt());
130 // Ok pressed - save settings and exit
131 void KFountainSetup::slotOkPressed()
133 KConfig config("kssfountainrc", false, false);
134 config.setGroup( "Settings" );
136 if (RadioButton1->isOn() == true)
138 config.writeEntry( "Stars", "true" );
139 } else {
140 if (RadioButton1_2->isOn() == true)
142 config.writeEntry( "Stars", "false" );
145 config.writeEntry( "StarSize", QString::number(SpinBox1->value()) );
147 config.sync();
149 accept();
152 void KFountainSetup::aboutPressed()
154 KMessageBox::about(this,
155 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>"));
157 //-----------------------------------------------------------------------------
160 KFountainSaver::KFountainSaver( WId id ) : KScreenSaver( id )
163 kDebug() << "Blank" << endl;
165 timer = new QTimer( this );
166 timer->start( 25, TRUE );
167 setBackgroundColor( Qt::black );
168 erase();
169 fountain = new Fountain();
170 embed(fountain);
171 fountain->show();
172 connect( timer, SIGNAL(timeout()), this, SLOT(blank()) );
175 KFountainSaver::~KFountainSaver()
180 // read configuration settings from config file
181 void KFountainSaver::readSettings()
183 // Please remove me
187 void KFountainSaver::blank()
189 // Play fountain
191 fountain->updateGL();
192 timer->start( 25, TRUE );
195 Fountain::Fountain( QWidget * parent, const char * name) : QGLWidget (parent,name)
197 rainbow=true;
198 slowdown=2.0f;
199 zoom=-40.0f;
200 index=0;
201 size = 0.75f;
202 obj = gluNewQuadric();
204 // This has to be here because you can't update the fountain until 'fountain' is created!
205 KConfig config("kssfountainrc", false, false);
206 config.setGroup( "Settings" );
207 QString boolval = config.readEntry( "Stars", "false" );
208 if (boolval == "true") {
209 setStars(true);
210 } else {
211 if (boolval == "false")
213 setStars(false);
217 QString starammount = config.readEntry("StarSize", "75");
218 float passvalue = (starammount.toInt() / 100.0);
219 setSize(passvalue);
223 Fountain::~Fountain()
225 glDeleteTextures( 1, &texture[0] );
226 gluDeleteQuadric(obj);
229 /** load the particle file */
230 bool Fountain::loadParticle()
232 /* Status indicator */
233 bool Status = TRUE;
234 QImage buf;
236 kDebug() << "Loading: " << KStandardDirs::locate("data", "kscreensaver/particle.png") << endl;
237 if (buf.load( KStandardDirs::locate("data", "kscreensaver/particle.png") ) )
240 tex = convertToGLFormat(buf); // flipped 32bit RGBA
241 kDebug() << "Texture loaded: " << tex.numBytes () << endl;
243 else
245 QImage dummy( 32, 32, 32 );
246 dummy.fill( Qt::white );
247 buf = dummy;
248 tex = convertToGLFormat( buf );
251 /* Set the status to true */
252 //Status = TRUE;
253 glGenTextures(1, &texture[0]); /* create three textures */
254 glBindTexture(GL_TEXTURE_2D, texture[0]);
255 /* use linear filtering */
256 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
257 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
258 /* actually generate the texture */
259 glTexImage2D(GL_TEXTURE_2D, 0, 4, tex.width(), tex.height(), 0,
260 GL_RGBA, GL_UNSIGNED_BYTE, tex.bits());
264 return Status;
266 /** setup the GL enviroment */
267 void Fountain::initializeGL ()
270 kDebug() << "InitGL" << endl;
271 GLfloat colors[12][3]=
272 {{1.0f,0.5f,0.5f},{1.0f,0.75f,0.5f},{1.0f,1.0f,0.5f},{0.75f,1.0f,0.5f},
273 {0.5f,1.0f,0.5f},{0.5f,1.0f,0.75f},{0.5f,1.0f,1.0f},{0.5f,0.75f,1.0f},
274 {0.5f,0.5f,1.0f},{0.75f,0.5f,1.0f},{1.0f,0.5f,1.0f},{1.0f,0.5f,0.75f}};
276 if (loadParticle()) // Jump To Texture Loading Routine
278 /* Enable smooth shading */
279 glShadeModel( GL_SMOOTH );
281 /* Set the background black */
282 glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
284 /* Depth buffer setup */
285 glClearDepth( 1.0f );
287 /* Enables Depth Testing */
288 glDisable( GL_DEPTH_TEST );
290 /* Enable Blending */
291 glEnable( GL_BLEND );
292 /* Type Of Blending To Perform */
293 glBlendFunc( GL_SRC_ALPHA, GL_ONE );
296 /* Really Nice Perspective Calculations */
297 glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
298 /* Really Nice Point Smoothing */
299 glHint( GL_POINT_SMOOTH_HINT, GL_NICEST );
301 /* Enable Texture Mapping */
302 glEnable( GL_TEXTURE_2D );
303 /* Select Our Texture */
304 glBindTexture( GL_TEXTURE_2D, texture[0] );
306 for (loop=0;loop<MAX_PARTICLES;loop++) // Initials All The Textures
308 particle[loop].active=true; // Make All The Particles Active
309 particle[loop].life=1.0f; // Give All The Particles Full Life
310 particle[loop].fade=float(KRandom::random()%100)/1000.0f+0.003f; // Random Fade Speed
311 particle[loop].r=colors[(loop+1)/(MAX_PARTICLES/12)][0]; // Select Red Rainbow Color
312 particle[loop].g=colors[(loop+1)/(MAX_PARTICLES/12)][1]; // Select Green Rainbow Color
313 particle[loop].b=colors[(loop+1)/(MAX_PARTICLES/12)][2]; // Select Blue Rainbow Color
314 particle[loop].xi=float((KRandom::random()%50)-26.0f)*10.0f; // Random Speed On X Axis
315 particle[loop].yi=float((KRandom::random()%50)-25.0f)*10.0f; // Random Speed On Y Axis
316 particle[loop].zi=float((KRandom::random()%50)-25.0f)*10.0f; // Random Speed On Z Axis
317 particle[loop].xg=0.0f; // Set Horizontal Pull To Zero
318 particle[loop].yg=-0.8f; // Set Vertical Pull Downward
319 particle[loop].zg=0.0f; // Set Pull On Z Axis To Zero
320 particle[loop].size=size; // Set particle size.
323 else
324 exit(0);
326 /** resize the gl view */
327 void Fountain::resizeGL ( int width, int height )
329 kDebug() << "ResizeGL " << width << "," <<height<< endl;
330 if (height==0) // Prevent A Divide By Zero By
332 height=1; // Making Height Equal One
335 glViewport(0,0,width,height); // Reset The Current Viewport
337 glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
338 glLoadIdentity(); // Reset The Projection Matrix
340 // Calculate The Aspect Ratio Of The Window
341 gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,200.0f);
343 glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
344 glLoadIdentity();
346 /** paint the GL view */
347 void Fountain::paintGL ()
349 //kDebug() << "PaintGL" << endl;
351 GLfloat colors[12][3]=
352 {{1.0f,0.5f,0.5f},{1.0f,0.75f,0.5f},{1.0f,1.0f,0.5f},{0.75f,1.0f,0.5f},
353 {0.5f,1.0f,0.5f},{0.5f,1.0f,0.75f},{0.5f,1.0f,1.0f},{0.5f,0.75f,1.0f},
354 {0.5f,0.5f,1.0f},{0.75f,0.5f,1.0f},{1.0f,0.5f,1.0f},{1.0f,0.5f,0.75f}};
355 col = ( ++col ) % 12;
356 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
358 glLoadIdentity();
359 // Reset The ModelView Matrix
360 transIndex++;
361 glTranslatef( GLfloat(5.0*sin(4*3.14*transIndex/360)), GLfloat(4.0*cos(2*3.14*transIndex/360)), 0.0 );
362 xspeed = GLfloat(100.0*cos(3*3.14*transIndex/360)+100);
363 yspeed = GLfloat(100.0*sin(3*3.14*transIndex/360)+100);
364 //slowdown = GLfloat(4.0*sin(2*3.14*transIndex/360)+4.01);
366 for (loop=0;loop<MAX_PARTICLES;loop++) // Loop Through All The Particles
368 if (particle[loop].active) // If The Particle Is Active
370 float x=particle[loop].x; // Grab Our Particle X Position
371 float y=particle[loop].y; // Grab Our Particle Y Position
372 float z=particle[loop].z+zoom; // Particle Z Pos + Zoom
373 /* Select Our Texture */
375 /* Draw The Particle Using Our RGB Values,
376 * Fade The Particle Based On It's Life
379 glColor4f( particle[loop].r,
380 particle[loop].g,
381 particle[loop].b,
382 particle[loop].life );
384 /* Build Quad From A Triangle Strip */
385 if( !stars )
386 glBegin( GL_TRIANGLE_STRIP );
387 else
388 glBegin( GL_TRIANGLE_FAN );
389 /* Top Right */
390 glTexCoord2d( 1, 1 );
391 glVertex3f( x + particle[loop].size, y + particle[loop].size, z );
392 /* Top Left */
393 glTexCoord2d( 0, 1 );
394 glVertex3f( x - particle[loop].size, y + particle[loop].size, z );
395 /* Bottom Right */
396 glTexCoord2d( 1, 0 );
397 glVertex3f( x + particle[loop].size, y - particle[loop].size, z );
398 /* Bottom Left */
399 glTexCoord2d( 0, 0 );
400 glVertex3f( x - particle[loop].size, y - particle[loop].size, z );
401 glEnd( );
403 particle[loop].x+=particle[loop].xi/(slowdown*1000);// Move On The X Axis By X Speed
404 particle[loop].y+=particle[loop].yi/(slowdown*1000);// Move On The Y Axis By Y Speed
405 particle[loop].z+=particle[loop].zi/(slowdown*1000);// Move On The Z Axis By Z Speed
407 particle[loop].xi+=particle[loop].xg; // Take Pull On X Axis Into Account
408 particle[loop].yi+=particle[loop].yg; // Take Pull On Y Axis Into Account
409 particle[loop].zi+=particle[loop].zg; // Take Pull On Z Axis Into Account
410 particle[loop].life-=particle[loop].fade; // Reduce Particles Life By 'Fade'
412 if (particle[loop].life<0.0f) // If Particle Is Burned Out
414 particle[loop].life=2.0f; // Give It New Life
415 particle[loop].fade=float(KRandom::random()%100)/1000.0f+0.003f; // Random Fade Value
416 particle[loop].x=0.0f; // Center On X Axis
417 particle[loop].y=0.0f; // Center On Y Axis
418 particle[loop].z=0.0f; // Center On Z Axis
419 particle[loop].xi=xspeed+float((KRandom::random()%60)-32.0f); // X Axis Speed And Direction
420 particle[loop].yi=yspeed+float((KRandom::random()%60)-30.0f); // Y Axis Speed And Direction
421 particle[loop].zi=float((KRandom::random()%60)-30.0f); // Z Axis Speed And Direction
422 particle[loop].r=colors[col][0]; // Select Red From Color Table
423 particle[loop].g=colors[col][1]; // Select Green From Color Table
424 particle[loop].b=colors[col][2]; // Select Blue From Color Table
425 particle[loop].size=size;
426 if ((1+(random()%20)) == 10)
428 // Explode
429 particle[loop].active=true; // Make All The Particles Active
430 particle[loop].life=1.0f; // Give All The Particles Full Life
431 particle[loop].fade=float(KRandom::random()%100)/1000.0f+0.003f; // Random Fade Speed
432 particle[loop].r=colors[(loop+1)/(MAX_PARTICLES/12)][0]; // Select Red Rainbow Color
433 particle[loop].g=colors[(loop+1)/(MAX_PARTICLES/12)][1]; // Select Green Rainbow Color
434 particle[loop].b=colors[(loop+1)/(MAX_PARTICLES/12)][2]; // Select Blue Rainbow Color
435 particle[loop].xi=float((KRandom::random()%50)-26.0f)*10.0f; // Random Speed On X Axis
436 particle[loop].yi=float((KRandom::random()%50)-25.0f)*10.0f; // Random Speed On Y Axis
437 particle[loop].zi=float((KRandom::random()%50)-25.0f)*10.0f; // Random Speed On Z Axis
438 particle[loop].xg=0.0f; // Set Horizontal Pull To Zero
439 particle[loop].yg=-0.8f; // Set Vertical Pull Downward
440 particle[loop].zg=0.0f; // Set Pull On Z Axis To Zero
441 particle[loop].size=size; // Set particle size.
444 // Lets stir some things up
445 index += 0.001;
446 particle[loop].yg =2.0*sin(2*3.14*transIndex/360);
447 particle[loop].xg =2.0*cos(2*3.14*transIndex/360);
448 particle[loop].zg =4.0+(4.0*cos(2*3.14*transIndex/360));
453 glFlush();
455 void Fountain::setSize( float newSize )
457 size = newSize;
459 void Fountain::setStars( bool doStars )
461 stars = doStars;
464 void KFountainSaver::updateSize(int newSize)
466 fountain->setSize(newSize/100);
468 void KFountainSaver::doStars(bool starState)
470 fountain->setStars(starState);