1 // This file is part of KFireSaver3D.
3 // KFireSaver3D is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation; either version 2 of the License, or
6 // (at your option) any later version.
8 // KFireSaver3D is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with KFireSaver3D; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 // Author: Enrico Ros, based on the great work of David Sansome (kfiresaver)
19 // Email: asy@libero.it
25 #include <kstandarddirs.h>
28 #include <kiconloader.h>
29 #include <kmessagebox.h>
30 #include <arts/kmedia2.h>
31 #include <arts/kplayobject.h>
32 #include <arts/kplayobjectfactory.h>
34 #include "firesaversetup.h"
35 #include "firesaverparticle.h"
36 #include "firesaverwriter.h"
37 #include "firesaver.h"
40 /* Factory code for KScreensaver begins *here* *\
43 #include <kscreensaver.h>
46 #include <QTimerEvent>
48 class KFireSaverKSS
: public KScreenSaver
51 KFireSaverKSS( WId id
)
54 setBackgroundColor( black
);
56 saver
= new KFireSaver
;
70 class KFireSaverSetupKDB
: public KDialog
73 KFireSaverSetupKDB( QWidget
* parent
= 0, const char* name
= 0 )
74 : KDialog( parent
, name
, true, i18n("Setup Screen Saver"),
75 Ok
| Cancel
| Help
, Ok
, true )
77 setup
= new KFireSaverSetup( this );
78 setMainWidget( setup
);
79 setButtonText( KDialog::Help
, i18n( "A&bout" ) );
85 KMessageBox::about(this, i18n("<h3>KFireSaver 3D 1.0</h3>\n<p>TEST Koral - Enrico Ros::2004</p>") );
94 KFireSaverSetup
* setup
;
97 class KFireSaverInterface
: public KScreenSaverInterface
102 virtual KAboutData
* aboutData() {
103 return new KAboutData( "kfiresaver.kss", I18N_NOOP( "Fireworks 3D (GL)" ), "0.7", I18N_NOOP( "Fireworks 3D (GL)" ) );
107 virtual KScreenSaver
* create( WId id
)
109 return new KFireSaverKSS( id
);
112 virtual QDialog
* setup()
114 return new KFireSaverSetupKDB
;
118 int main( int argc
, char *argv
[] )
120 KFireSaverInterface kss
;
121 return kScreenSaverMain( argc
, argv
, kss
);
125 \* Factory code for KScreensaver ends *here* */
128 KFireSaver :: KFireSaver( QWidget
*parent
, const char *name
)
129 : QGLWidget( parent
, name
)
131 // set random seed to initialize drand48() calls
133 gettimeofday(&tv
,NULL
);
134 srand48( (long)tv
.tv_usec
);
138 particleList
.setAutoDelete(true);
139 starList
.setAutoDelete(true);
140 imageList
.setAutoDelete(true);
141 playObjectList
.setAutoDelete(true);
143 //initialize openGL context before managing GL calls
145 loadTexture( KStandardDirs::locate("data","kfiresaver/kfs_particle.png"), particleTexture
);
146 loadTexture( KStandardDirs::locate("data","kfiresaver/kfs_particle_flare.png"), flareTexture
);
147 loadTexture( KStandardDirs::locate("data","kfiresaver/kfs_particle_diastar.png"), diastarTexture
);
148 starTexture
= particleTexture
;
151 if (parameters
.enableStars
) {
152 int number
= parameters
.starsNumber
+ 1;
153 number
*= 10 * number
;
154 for (int i
=0 ; i
<number
; i
++)
156 Particle
* star
= new Particle( Particle::StarParticle
);
157 star
->initializeValues();
158 star
->texture
= starTexture
;
159 if (parameters
.enableStarGradient
)
161 GLfloat red
= star
->colour
[0],
162 green
= star
->colour
[1],
163 blue
= star
->colour
[2],
164 tint
= 0.5 + star
->ypos
/ FIELDWIDTH
,
165 merge
= 0.3 + DRAND
*0.7,
167 star
->colour
[0] = red
* merge
+ (1.0-tint
) * mergen
;
168 star
->colour
[1] = green
* merge
+ tint
* mergen
;
169 star
->colour
[2] = blue
* merge
+ tint
* mergen
;
171 starList
.append( star
);
175 //generate bottom fire
176 if (parameters
.enableBottomFire
) {
177 float cRed
= (float)parameters
.bottomFireColor
.red() / 255.0,
178 cGreen
= (float)parameters
.bottomFireColor
.green() / 255.0,
179 cBlue
= (float)parameters
.bottomFireColor
.blue() / 255.0;
180 for (int i
=0 ; i
<NUMBER_OF_FIREPARTICLES
; i
++)
182 Particle
* particle
= new Particle( Particle::FireParticle
);
183 particle
->initializeValues();
184 particle
->texture
= particleTexture
;
185 particle
->zspeed
*= 4.0;
186 particle
->colour
[0] = cRed
* (0.6 + 0.4*DRAND
);
187 particle
->colour
[1] = cGreen
* (0.6 + 0.4*DRAND
);
188 particle
->colour
[2] = cBlue
* (0.6 + 0.4*DRAND
);
189 particleList
.append(particle
);
194 if (parameters
.enableSound
) {
195 sound_explosion
= locate("data","kfiresaver/kfs_explode.ogg");
196 sound_debris
= locate("data","kfiresaver/kfs_debris.ogg");
199 //create the writer class that manages flying writings.
200 if ( parameters
.enableWritings
)
201 writer
= new Writer("kfs_letters.desc");
203 showp
.forceBicolour
=
206 showp
.forceType
= false;
207 showp
.timeStamp
= 0.0;
208 startTimer(MSECPERIOD
);
210 //force initialization of "show" variables for the first time
215 KFireSaver :: ~KFireSaver()
217 freeTexture( particleTexture
);
218 freeTexture( starTexture
);
219 particleList
.clear();
222 playObjectList
.clear();
223 if ( parameters
.enableWritings
)
228 void KFireSaver :: initializeGL()
230 glDisable(GL_DEPTH_TEST
);
232 glBlendFunc(GL_SRC_ALPHA
,GL_ONE
);
233 glShadeModel( GL_SMOOTH
);
235 resizeGL( 640, 480 );
239 void KFireSaver :: resizeGL( int width
, int height
)
241 glViewport( 0, 0, width
, height
);
243 glMatrixMode(GL_PROJECTION
);
245 glOrtho( -FIELDW_2
, FIELDW_2
, -FIELDW_2
, FIELDW_2
, 5.0, 60.0 );
247 glMatrixMode(GL_MODELVIEW
);
250 float ratio
= (float)width
/ (float)height
,
251 numH
= 750 - 90 * parameters
.particleSize
,
252 numW
= 1000 - 120 * parameters
.particleSize
;
253 if ( ratio
>= (4.0/3.0) ) {
254 unitX
= FIELDWIDTH
/ (numH
* ratio
);
255 unitY
= FIELDWIDTH
/ numH
;
257 unitX
= FIELDWIDTH
/ numW
;
258 unitY
= FIELDWIDTH
/ (numW
/ ratio
);
262 gettimeofday(&tv
,NULL
);
263 timeStampFrame
= (double)tv
.tv_sec
+ (double)tv
.tv_usec
/1000000.0;
269 void KFireSaver :: paintGL ()
270 /* Main procedure. It does the following:
271 - calculate time diff between current and previous frame
272 - clear the color buffer
273 - simple render of stars
274 - advanced render of particles
276 - update physics based on time difference
277 - check die/change conditions
278 - call to explode_firework if a leader dies
279 - if random -> start a new firework
280 - if random -> explode a penquin or kde logo
283 /* calculate TIME ELAPSED between current and previous frame */
286 gettimeofday(&tv
,NULL
);
287 double timeCurrent
= (double)tv
.tv_sec
+ (double)tv
.tv_usec
/1000000.0;
288 double timeDiff
= (MSECPERIOD
/ 1000.0);
289 if (parameters
.enableRealtime
)
291 timeDiff
= timeCurrent
- timeStampFrame
;
292 timeStampFrame
= timeCurrent
;
293 timeDiff
= (timeDiff
> 0.5) ? 0.5 : (timeDiff
< 0.005) ? 0.005 : timeDiff
;
296 /* CLEAR SCREEN: to do it there are 2 ways */
299 glTranslatef( 0, 0, -50.0 );
300 glDisable( GL_TEXTURE_2D
);
302 if ( !parameters
.enableFade
|| firstGLFrame
)
303 { // quick - clear the OpenGL color buffer
304 glClearColor( 0.0, 0.0, 0.0, 1.0 );
305 glClear( GL_COLOR_BUFFER_BIT
);
306 firstGLFrame
= false;
310 /* superpose a semi-transparent black rectangle so we
311 can see a sort of 'tail' for each particle drawn. */
312 const GLfloat conv_tab
[10] = {
313 0.50, 0.33, 0.22, 0.15, 0.10,
314 0.07, 0.05, 0.03, 0.02, 0.01 };
315 glBlendFunc(GL_SRC_ALPHA
,GL_ONE_MINUS_SRC_ALPHA
);
316 glColor4f(0.0,0.0,0.0, conv_tab
[parameters
.fadeAmount
]);
317 glBegin( GL_TRIANGLE_STRIP
);
318 glVertex2f( FIELDW_2
, FIELDW_2
);
319 glVertex2f( -FIELDW_2
, FIELDW_2
);
320 glVertex2f( FIELDW_2
, -FIELDW_2
);
321 glVertex2f( -FIELDW_2
, -FIELDW_2
);
323 glBlendFunc(GL_SRC_ALPHA
,GL_ONE
);
328 if (parameters
.enableStars
) {
330 glEnable( GL_TEXTURE_2D
);
331 glBindTexture( GL_TEXTURE_2D
, currentTexture
= starTexture
);
333 glDisable( GL_TEXTURE_2D
);
336 bool flickers
= parameters
.enableStarFlickering
;
337 float alpha
= flickers
? 0.5 : 1.0;
338 Particle
* star
= starList
.first();
339 for (; star
; star
= starList
.next())
341 if (flickers
&& DRAND
<0.6)
344 GLfloat sizeX
= star
->pixelSize
* unitX
,
345 sizeY
= star
->pixelSize
* unitY
,
346 pLeft
= star
->xpos
- sizeX
,
347 pRight
= star
->xpos
+ sizeX
,
348 pTop
= star
->ypos
+ sizeY
,
349 pBottom
= star
->ypos
- sizeY
;
350 glColor4f(star
->colour
[0], star
->colour
[1], star
->colour
[2], alpha
);
351 glTexCoord2f( 0, 0 ); // Bottom Left
352 glVertex2f( pLeft
, pBottom
);
353 glTexCoord2f( 0, 1 ); // Top Left
354 glVertex2f( pLeft
, pTop
);
355 glTexCoord2f( 1, 1 ); // Top Right
356 glVertex2f( pRight
, pTop
);
357 glTexCoord2f( 1, 0 ); // Bottom Right
358 glVertex2f( pRight
, pBottom
);
363 /* render FIREWORKS */
366 bool playedExplodeSound
= false;
367 bool flashedScreen
= false;
368 Particle
* particle
= particleList
.first();
369 for (; particle
; particle
= particleList
.next())
371 //bind the texture for current particle (if not already bound)
372 if ( !particle
->texture
) {
374 glDisable( GL_TEXTURE_2D
);
377 } else if ( particle
->texture
!= currentTexture
) {
379 glEnable( GL_TEXTURE_2D
);
380 glBindTexture( GL_TEXTURE_2D
, currentTexture
= particle
->texture
);
384 //perspective projection (done by hand to make it funnier than opengl's :-)
385 float mfactor
= PERSP_MAG_FACTOR
* particle
->ypos
;
386 if ( mfactor
< -246.0 ) {
387 particleList
.remove();
391 float sfactor
= 256.0 / (256.0 + mfactor
),
392 posx
= sfactor
* particle
->xpos
,
393 posy
= sfactor
* particle
->zpos
- 4.0;
394 //size computation (magnify if enableMegaFlares is set)
395 if ( parameters
.enableMegaFlares
) {
396 mfactor
= parameters
.megaFlares
*particle
->ypos
;
397 if ( mfactor
< -255.0 || mfactor
> 512.0 ) {
398 particleList
.remove();
402 sfactor
= 256.0 / (256.0 + mfactor
);
404 sfactor
= 76.8 - sfactor
/ 5.0;
406 float size
= sfactor
* particle
->pixelSize
,
407 sizeX
= size
* unitX
,
408 sizeY
= size
* unitY
;
410 //determine brightness (alpha component) for the particle
411 if ( particle
->useLife
) {
412 float life
= particle
->life
,
413 startLife
= particle
->startLife
;
414 //bright changes with the following curve: "2*k - k^2" (or "k(2-k)")
415 if ( life
> startLife
)
416 particle
->colour
[3] = startLife
+ 1 - life
;
418 particle
->colour
[3] = life
/ startLife
;
419 //apply flickering if enabled
420 if (particle
->flicker
< 0) {
421 particle
->colour
[3] = 0.2;
422 if (++particle
->flicker
>= 0)
423 particle
->flicker
= FLICKER_FRAMES_DELAY
;
424 } else if (particle
->flicker
> 0) {
425 if ( life
<= startLife
)
426 particle
->colour
[3] = 1.0;
427 if (--particle
->flicker
<= 0)
428 particle
->flicker
= -FLICKER_FRAMES_DELAY
;
430 glColor4fv( particle
->colour
);
432 glColor3fv( particle
->colour
);
435 float pLeft
= posx
- sizeX
,
437 pRight
= posx
+ sizeX
,
438 pBottom
= posy
- sizeY
;
439 glTexCoord2f( 0, 0 ); // Bottom Left
440 glVertex2f( pLeft
, pBottom
);
441 glTexCoord2f( 0, 1 ); // Top Left
442 glVertex2f( pLeft
, pTop
);
443 glTexCoord2f( 1, 1 ); // Top Right
444 glVertex2f( pRight
, pTop
);
445 glTexCoord2f( 1, 0 ); // Bottom Right
446 glVertex2f( pRight
, pBottom
);
448 //phisically update parameters of the particle
449 particle
->updateParameters( timeDiff
);
451 //check for particle death / explosion
452 switch (particle
->particleType
)
454 //a Fireparticle is restarted when in right conditions
455 case Particle::FireParticle
:
456 if ( posx
< -FIELDW_2
|| posx
> FIELDW_2
||
457 (particle
->zpos
< -10.0 && posy
< -FIELDW_2
) )
459 particle
->initializeValues();
460 if ( DRAND
> 0.9995 )
461 particle
->zspeed
*= 4;
465 //a leader explodes when his z speed drops to zero
466 //or, if it uses life, at death
467 case Particle::FireWorkLeaderParticle
:
468 if ((particle
->zspeed
<= 0.0f
&& !particle
->useLife
) ||
469 (particle
->useLife
&& particle
->life
<= 0.0) )
471 // play sound if enabled (and once per frame)
472 if (parameters
.enableSound
&& !playedExplodeSound
)
474 playSound(sound_explosion
);
475 playedExplodeSound
= true;
477 // flash screen if enabled
478 if (parameters
.enableFlash
&& !flashedScreen
) {
480 glDisable( GL_TEXTURE_2D
);
481 glColor4f( 1,1,1, parameters
.flashOpacity
/ 10.0 );
482 glBegin( GL_TRIANGLE_STRIP
);
483 glVertex2f( FIELDW_2
, FIELDW_2
);
484 glVertex2f( -FIELDW_2
, FIELDW_2
);
485 glVertex2f( FIELDW_2
, -FIELDW_2
);
486 glVertex2f( -FIELDW_2
, -FIELDW_2
);
488 if ( particleTexture
)
489 glEnable( GL_TEXTURE_2D
);
491 flashedScreen
= true;
493 // generating children and removing parent
494 int elementIndex
= particleList
.at();
495 explodeFirework(particle
);
496 particleList
.remove(elementIndex
);
498 } else if ( parameters
.enableTrails
&& DRAND
< 0.4 ) {
499 // leave trail behind the particle (it'a small and slow red debris)
500 Particle
* p
= new Particle( Particle::FireWorkDebrisParticle
);
501 p
->initializeValues( 0, particle
, 1, 1 );
502 p
->texture
= particleTexture
;
509 int elementIndex
= particleList
.at();
510 particleList
.append( p
);
511 particleList
.at( elementIndex
);
515 //remove if dead or outside field
517 if (particle
->life
<= 0.0 || posx
<-FIELDW_2
|| posx
>FIELDW_2
|| posy
<-FIELDW_2
) {
518 particleList
.remove();
526 /* render WRITINGS */
528 if ( parameters
.enableWritings
)
530 int chance
= (int) (1000.0 * DRAND
);
532 static const QString someStrings
[] = {
534 i18n("Conquer your desktop!"),
535 i18n("KFIRESAVER 3D"),
536 i18n("Thank you for using KDE"),
538 int n
= (int)(4.0 * DRAND
);
539 writer
->spawnWords( someStrings
[n
], Writer::Fun1
);
541 writer
->render( timeDiff
);
544 /* generate a new FIREWORK_LEADER */
546 int random
= (int) ((float)parameters
.fireworksFrequency
* DRAND
);
547 if (showp
.ShowType
== Show
)
549 //double the chances ('frequency') to raise a new leaderParticle
550 //but envelop it under a sine function
551 float step
= (showp
.timeStamp
- timeCurrent
) / showp
.timeGap
;
552 if (DRAND
> sin(M_PI
*step
))
554 if (showp
.type
== AngelHairs
&& DRAND
< 0.5)
559 Particle
* particle
= new Particle( Particle::FireWorkLeaderParticle
);
560 particle
->initializeValues();
561 particle
->texture
= flareTexture
;
562 particleList
.append( particle
);
567 int logoImages
= imageList
.count();
568 if ( logoImages
> 0 ) {
569 random
= (int) (parameters
.logoFrequency
* logoImages
* 200.0 * DRAND
);
570 if ( random
< logoImages
)
572 if (parameters
.enableFlash
&& !flashedScreen
) {
573 glDisable( GL_TEXTURE_2D
);
574 glColor4f( 1,1,1, parameters
.flashOpacity
/ 10.0 );
575 glBegin( GL_TRIANGLE_STRIP
);
576 glVertex2f( FIELDW_2
, FIELDW_2
);
577 glVertex2f( -FIELDW_2
, FIELDW_2
);
578 glVertex2f( FIELDW_2
, -FIELDW_2
);
579 glVertex2f( -FIELDW_2
, -FIELDW_2
);
582 burnLogo( imageList
.at(random
) );
588 int KFireSaver :: pickColour()
590 int color
= (int) (DRAND
* parameters
.colorsCount
);
591 return parameters
.colorsT
[ color
];
595 KFireSaver :: enumFireworkType
KFireSaver :: pickType()
597 int type
= (int) (DRAND
* parameters
.typesCount
);
598 return parameters
.typesT
[ type
];
602 void KFireSaver :: explodeFirework(Particle
* leaderParticle
)
604 GLfloat displace
[3] = {0.0,0.0,0.0};
605 float tmp1
= 0.0, tmp2
= 0.0, tmp3
= 0.0, tmp4
= 0.0, tmp5
= 0.0;
607 // color of exploded particles
608 bool bicolor
= parameters
.enableCombos
&& (showp
.forceBicolour
|| DRAND
> 0.95),
610 int cscheme
= showp
.forceColour
? showp
.colour
: pickColour(),
611 cscheme2
= showp
.forceColour
? showp
.colourSec
: pickColour();
613 // randomize type of exploding firework
614 enumFireworkType fwType
=
615 showp
.forceType
? (enumFireworkType
) showp
.type
: pickType();
617 // other options for generated particles
618 int number
= (int) ((DRAND
+ DRAND
) * 150.0);
619 float power
= showp
.forcePower
?
620 showp
.powerEnvelop
* (0.8 + 0.3*DRAND
) :
622 powermin
= DRAND
* power
;
624 // now some rules ...
625 //a splitter can't split up more than 2 times
626 if (fwType
== Splitter
&& leaderParticle
->explosionsDepth
> 1) {
627 if (parameters
.typesCount
== 1)
630 fwType
= showp
.typeSec
;
631 if (fwType
== Splitter
)
632 while ( (fwType
= pickType()) == Splitter
);
635 // PRE-ADJUST parameters for the firework we're creating
638 //no need to handle this. it's the default configuration.
642 //explosion whithout emitting particles, only a flash
645 power
= powermin
= 0;
648 //splits up into 'number' orange pieces. tmp1 holds base_life
650 cscheme
= showp
.forceColour
? showp
.colour
: 1;
652 number
= 3 + (int) (DRAND
* 4);
654 powermin
= power
/ 2.0;
655 tmp1
= 0.4 + DRAND
* 1.5;
658 //randomize a couple of angles (phi - theta) for exploding circle
662 power
= DRAND
* 5.0 + 4.0;
665 tmp4
= cos(tmp2
); //c2
666 tmp3
= sin(tmp2
); //s2
667 tmp2
= cos(tmp1
); //c1
668 tmp1
= sin(tmp1
); //s1
671 //cascade of flickering orange particles
673 cscheme
= showp
.forceColour
? showp
.colour
: 1;
676 power
= 0.8 + DRAND
* 1.9;
677 powermin
= DRAND
*0.5;
678 number
= 100 + (int)(DRAND
* 150);
679 displace
[0] = -leaderParticle
->xspeed
/2;
680 displace
[1] = -leaderParticle
->yspeed
/2;
684 //behave as a standard spherical firework
688 //not yet implemented, suppressing particles
695 //limit number of particles as we are getting to the capacity saturation
696 float currentParticles
= (float) particleList
.count();
697 const float particleCapacity
= 15000;
698 const float particleGap
= 8000;
699 if ( number
> 10 && currentParticles
> (particleCapacity
- particleGap
) )
701 //NoFW, Splitter and NoRender aren't limited.
702 number
= (int)( (float)number
* (particleCapacity
- currentParticles
) / particleGap
);
707 int newExplosionsDepth
= leaderParticle
->explosionsDepth
+ 1;
708 for (int i
=0 ; i
<number
; i
++)
711 if ( fwType
== Spirals
)
712 particle
= new TurningParticle( Particle::FireWorkDebrisParticle
);
714 particle
= new Particle( Particle::FireWorkDebrisParticle
);
716 particle
->initializeValues (
717 bicolor
&& (i
>number
/2) ? cscheme2
: cscheme
,
718 leaderParticle
, powermin
, power
,
719 flickers
, displace
);
720 particle
->texture
= particleTexture
;
721 particle
->explosionsDepth
= newExplosionsDepth
;
723 // POST-ADJUST particle coefficients adapting to current FireworkType
726 //create a big, white particle, simulating explosion
728 if (parameters
.enableFade
)
729 particle
->startLife
= particle
->life
= 0.030;
731 particle
->startLife
= particle
->life
= 0.075;
732 particle
->texture
= flareTexture
;
735 particle
->colour
[2]=1.0;
736 particle
->pixelSize
= 50.0 + 75.0 * DRAND
;
740 //default. no need to change parameters, only create the
741 //'sphere light' as the first big particle if set.
743 if (i
==0 && parameters
.enableSphereLight
&& number
> 40) {
744 particle
->texture
= flareTexture
;
745 particle
->xspeed
= leaderParticle
->xspeed
;
746 particle
->yspeed
= leaderParticle
->yspeed
;
747 particle
->zspeed
= 0.0;
748 particle
->colour
[0] /= 2.0;
749 particle
->colour
[1] /= 2.0;
750 particle
->colour
[2] /= 2.0;
751 float impression
= power
* (float)number
/5.0;
752 particle
->pixelSize
= 25.0 * DRAND
+ impression
;
753 if (parameters
.enableFade
) {
754 particle
->startLife
= particle
->life
= 0.040;
756 particle
->startLife
= 1.3;
757 particle
->life
= 1.8;
764 particle
->particleType
= Particle::FireWorkLeaderParticle
;
765 particle
->pixelSize
*= 3.0;
766 particle
->startLife
= particle
->life
= tmp1
* (0.75 + DRAND
/3.0);
767 if (particle
->zspeed
< 0)
768 particle
->zspeed
= -particle
->zspeed
;
773 tmp5
= 2 * M_PI
* DRAND
;
774 //MMX can be useful.. if you know how to use it :-)
775 if ( fwType
== BiCircle
&& i
> number
/2 ) {
776 GLfloat ey
= cos(tmp5
),
778 particle
->xspeed
= power
* ( tmp3
*ez
);
779 particle
->yspeed
= power
* ( tmp2
*ey
- tmp1
*tmp4
*ez
);
780 particle
->zspeed
= power
* ( tmp1
*ey
+ tmp2
*tmp4
*ez
);
782 GLfloat ex
= sin(tmp5
),
784 particle
->xspeed
= power
* ( tmp4
*ex
);
785 particle
->yspeed
= power
* ( tmp1
*tmp3
*ex
+ tmp2
*ey
);
786 particle
->zspeed
= power
* ( -tmp2
*tmp3
*ex
+ tmp1
*ey
);
791 particle
->zacc
= -9.807 * (0.05 + DRAND
*0.20);
792 particle
->life
= 2.0 + DRAND
*2.5;
793 particle
->startLife
= particle
->life
- 1;
794 if (particle
->zspeed
< 0)
795 particle
->zspeed
*= -1;
796 //particle->pixelSize = 5.0;
800 particle
->texture
= diastarTexture
;
808 particleList
.append(particle
);
812 void KFireSaver :: timerEvent(QTimerEvent
*)
815 gettimeofday(&tv
,NULL
);
816 double currentTime
= (double)tv
.tv_sec
+ (double)tv
.tv_usec
/1000000.0;
818 bool chooseType
= false,
820 chooseOthers
= false,
821 updateTimings
= false;
822 bool firstTime
= showp
.timeStamp
== 0.0;
823 bool endOfScene
= currentTime
>= showp
.timeStamp
;
826 switch (showp
.ShowType
)
829 /* first time choose the type, color and attributes will
830 be choosed randomly for every firework which explodes*/
831 showp
.forceType
= true;
836 /* first time choose the color, type and attributes will
837 be choosed randomly for every firework which explodes*/
838 showp
.forceColour
= true;
846 if (endOfScene
|| firstTime
)
847 switch (showp
.ShowType
)
850 /* if a scene ended, randomize global parameters for the
852 showp
.forceType
= true;
853 showp
.forceColour
= true;
854 showp
.forcePower
= true;
858 updateTimings
= true;
866 showp
.type
= pickType();
867 if (parameters
.typesCount
< 2)
868 showp
.typeSec
= NoRender
;
870 while ((showp
.typeSec
= pickType()) == showp
.type
);
873 showp
.colour
= pickColour();
874 showp
.colourSec
= pickColour();
878 showp
.powerEnvelop
= DRAND
* 8.0 + 3.0;
881 showp
.forceBicolour
= true;
882 showp
.colourSec
= pickColour();
884 showp
.forceBicolour
= false;
886 if ( firstTime
|| updateTimings
)
889 showp
.timeGap
= 1.0 + DRAND
* 2.0;
891 showp
.timeGap
= 3.0 + DRAND
* 10.0;
892 showp
.timeStamp
= currentTime
+ showp
.timeGap
;
893 showp
.timeGap
/= 1.5; //hack to introduce delay in sine func
899 void KFireSaver :: burnLogo(QImage
* image
)
901 if (!image
|| image
->isNull())
903 int step
= parameters
.enableReduceLogo
? 2 : 1,
904 imageW
= image
->width(),
905 imageH
= image
->height(),
906 offsetX
= imageW
/ 2,
907 offsetY
= imageH
/ 2;
908 float speed
= FIELDW_4
/ (imageW
> imageH
? imageW
: imageH
),
909 speedXOffs
= 5 * (DRAND
- DRAND
),
910 speedYOffs
= DRAND
+ DRAND
+ 1;
911 //if image is too big, lower sample points
912 while ((imageW
/step
)>96 || (imageH
/step
)>96)
914 for (int y
=0 ; y
<imageH
; y
+=step
)
916 for (int x
=0 ; x
<imageW
; x
+=step
)
918 QRgb pixel
= image
->pixel(x
,y
);
919 if ( qAlpha(pixel
) < 250 )
924 Particle
* particle
= new Particle( Particle::LogoParticle
);
925 particle
->initializeValues();
926 particle
->texture
= particleTexture
;
928 float xI
= (x
- offsetX
) ,
930 particle
->xpos
= xI
* speed
* 0.5;
931 particle
->zpos
= yI
* speed
* 0.5 + 5;
932 particle
->xspeed
= xI
* speed
+ speedXOffs
;
933 particle
->zspeed
= yI
* speed
+ speedYOffs
;
935 particle
->colour
[0] = qRed(pixel
) / 255.0f
;
936 particle
->colour
[1] = qGreen(pixel
) / 255.0f
;
937 particle
->colour
[2] = qBlue(pixel
) / 255.0f
;
939 particleList
.append(particle
);
942 if (parameters
.enableSound
)
943 playSound(sound_debris
);
946 void KFireSaver :: playSound(QString file
)
948 //flush inactive players
949 KPlayObject
* playObject
= playObjectList
.first();
952 if ( playObject
->state() != Arts::posPlaying
)
954 playObjectList
.remove();
955 playObject
= playObjectList
.current();
957 playObject
= playObjectList
.next();
960 //discart this sound if the player queue is already full (4 channels playing)
961 if ( playObjectList
.count() >= 6 )
964 // not needed when all of the files are in the distribution
965 //if (!QFile::exists(file))
968 KPlayObjectFactory
factory(artsServer
.server());
969 playObject
= factory
.createPlayObject(KUrl(file
), true);
971 if (playObject
&& !playObject
->isNull())
974 playObjectList
.append(playObject
);
978 bool KFireSaver :: loadTexture( QString fileName
, unsigned int & textureID
)
980 //reset texture ID to the default EMPTY value
985 if ( !tmp
.load( fileName
) )
988 //convert it to suitable format (flipped RGBA)
989 QImage texture
= QGLWidget::convertToGLFormat( tmp
);
990 if ( texture
.isNull() )
993 //get texture number and bind loaded image to that texture
994 glGenTextures( 1, &textureID
);
995 glBindTexture( GL_TEXTURE_2D
, textureID
);
996 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
997 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
998 glTexImage2D( GL_TEXTURE_2D
, 0, 4 /* 3 ??? */, texture
.width(), texture
.height(),
999 0, GL_RGBA
, GL_UNSIGNED_BYTE
, texture
.bits() );
1003 void KFireSaver :: freeTexture( unsigned int & textureID
)
1005 if ( textureID
> 0 )
1006 glDeleteTextures( 1, &textureID
);
1010 void KFireSaver :: readConfig ()
1012 KConfig
config("kfiresaverrc",true,false);
1015 config
.setGroup( "Show" );
1016 showp
.ShowType
= (enum enumShowType
)config
.readEntry( "ShowType", 1 );
1017 parameters
.fireworksFrequency
= 11 - config
.readEntry( "FireworksFrequency", 7 );
1018 if ( parameters
.fireworksFrequency
< 1 )
1019 parameters
.fireworksFrequency
= 1;
1020 if ( parameters
.fireworksFrequency
> 11 )
1021 parameters
.fireworksFrequency
= 11;
1022 parameters
.fireworksFrequency
*= (parameters
.fireworksFrequency
+ 1); //*karl gauss's sum*
1023 parameters
.particleSize
= config
.readEntry( "ParticlesSize", 0 );
1024 if ( parameters
.particleSize
< -5 )
1025 parameters
.particleSize
= -5;
1026 if ( parameters
.particleSize
> 5 )
1027 parameters
.particleSize
= 5;
1028 if ( parameters
.enableBottomFire
= config
.readEntry( "enable-BottomFire", true ) )
1030 QColor blue
= Qt::darkBlue
;
1031 parameters
.bottomFireColor
= config
.readEntry( "BottomFireColor", blue
);
1033 parameters
.enableSound
= config
.readEntry( "enable-Sounds", false );
1034 parameters
.enableNoOverhead
= config
.readEntry( "enable-NoOverhead", true );
1035 parameters
.enableRealtime
= config
.readEntry( "enable-FrameSkip", true );
1038 config
.setGroup( "Fireworks" );
1039 parameters
.typesCount
= 0;
1040 if ( config
.readEntry( "use-Classic", true ) )
1041 parameters
.typesT
[parameters
.typesCount
++] = Sphere
;
1042 if ( config
.readEntry( "use-Explosion", false ) )
1043 parameters
.typesT
[parameters
.typesCount
++] = NoFW
;
1044 if ( config
.readEntry( "use-FlameRing", false ) )
1045 parameters
.typesT
[parameters
.typesCount
++] = Circle
;
1046 if ( config
.readEntry( "use-FlameWorld", false ) )
1047 parameters
.typesT
[parameters
.typesCount
++] = BiCircle
;
1048 if ( config
.readEntry( "use-Fall", false ) )
1049 parameters
.typesT
[parameters
.typesCount
++] = AngelHairs
;
1050 if ( config
.readEntry( "use-Splitter", false ) )
1051 parameters
.typesT
[parameters
.typesCount
++] = Splitter
;
1052 if ( config
.readEntry( "use-Spirals", false ) )
1053 parameters
.typesT
[parameters
.typesCount
++] = Spirals
;
1054 if ( config
.readEntry( "use-SuperNova", false ) )
1055 parameters
.typesT
[parameters
.typesCount
++] = SuperNova
;
1056 if ( !parameters
.typesCount
) {
1057 kWarning() << "KFireSaver3D: Warning, no fireworks enabled in config file" << endl
;
1058 kWarning() << " enabling 'Classic Spherical'" << endl
;
1059 parameters
.typesCount
= 1;
1060 parameters
.typesT
[0] = Sphere
;
1062 parameters
.typesT
[ parameters
.typesCount
] =
1063 parameters
.typesT
[ parameters
.typesCount
-1 ];
1064 parameters
.colorsCount
= 0;
1065 if ( config
.readEntry( "use-Red", false ) )
1066 parameters
.colorsT
[parameters
.colorsCount
++] = 0;
1067 if ( config
.readEntry( "use-Orange", true ) )
1068 parameters
.colorsT
[parameters
.colorsCount
++] = 1;
1069 if ( config
.readEntry( "use-Green", false ) )
1070 parameters
.colorsT
[parameters
.colorsCount
++] = 2;
1071 if ( config
.readEntry( "use-Blue", false ) )
1072 parameters
.colorsT
[parameters
.colorsCount
++] = 3;
1073 if ( config
.readEntry( "use-White", true ) )
1074 parameters
.colorsT
[parameters
.colorsCount
++] = 4;
1075 if ( config
.readEntry( "use-Purple", false ) )
1076 parameters
.colorsT
[parameters
.colorsCount
++] = 5;
1077 if ( config
.readEntry( "use-DeepGreen", true ) )
1078 parameters
.colorsT
[parameters
.colorsCount
++] = 6;
1079 if ( !parameters
.colorsCount
)
1081 kWarning() << "KFireSaver3D: Warning enable at least one color" << endl
;
1082 kWarning() << " enabling 'Blinding White'" << endl
;
1083 parameters
.colorsCount
= 1;
1084 parameters
.colorsT
[0] = 4;
1086 parameters
.colorsT
[ parameters
.colorsCount
] =
1087 parameters
.colorsT
[ parameters
.colorsCount
-1 ];
1088 parameters
.enableCombos
= config
.readEntry( "use-Multicolor", true );
1091 config
.setGroup( "Specials" );
1092 if ( parameters
.enableLogos
= config
.readEntry( "enable-Logos", true ) )
1095 tempImage
.setAlphaBuffer( true );
1096 if ( config
.readEntry( "LogosTux", true ) )
1097 if ( tempImage
.load(locate("data","kfiresaver/kfs_tux.png")) )
1098 imageList
.append( new QImage(tempImage
) );
1099 if ( config
.readEntry( "LogosKonqui", true ) )
1100 if ( tempImage
.load(locate("data","kfiresaver/kfs_kde.png")) )
1101 imageList
.append( new QImage(tempImage
) );
1102 if ( config
.readEntry( "LogosKDEIcons", true ) ) {
1103 const QString icons
[] = {
1104 "3floppy_unmount", "cdrom_unmount", "hdd_mount", "kmix",
1105 "network", "my-computer", "folder_home", "konqueror",
1106 "kmail", "penguin", "personal" };
1107 for ( int i
= 0; i
< 11; i
++ )
1108 imageList
.append( new QImage(DesktopIcon(icons
[i
],64).convertToImage()) );
1110 parameters
.enableReduceLogo
= config
.readEntry( "LogosReduceDetail", true );
1111 parameters
.logoFrequency
= 11 - config
.readEntry( "LogosFrequency", 4 );
1112 if ( parameters
.logoFrequency
< 1 )
1113 parameters
.logoFrequency
= 1;
1114 if ( parameters
.logoFrequency
> 11 )
1115 parameters
.logoFrequency
= 11;
1117 if ( parameters
.enableStars
= config
.readEntry( "enable-Stars", true ) )
1119 parameters
.enableStarFlickering
= config
.readEntry( "StarsFlicker", false );
1120 parameters
.enableStarGradient
= config
.readEntry( "StarsGradient", true );
1121 parameters
.starsNumber
= config
.readEntry( "StarsNumber", 4 );
1122 if ( parameters
.starsNumber
< 0 )
1123 parameters
.starsNumber
= 0;
1124 if ( parameters
.starsNumber
> 10 )
1125 parameters
.starsNumber
= 10;
1127 parameters
.enableWritings
= config
.readEntry( "enable-Writings", true );
1130 config
.setGroup( "Effects" );
1131 parameters
.enableSphereLight
= config
.readEntry( "enable-SphericalLight", true );
1132 if ( parameters
.enableFlash
= config
.readEntry( "enable-Flash", false ) )
1134 parameters
.flashOpacity
= config
.readEntry( "FlashOpacity", 5 );
1135 if ( parameters
.flashOpacity
< 0 )
1136 parameters
.flashOpacity
= 0;
1137 if ( parameters
.flashOpacity
> 10 )
1138 parameters
.flashOpacity
= 10;
1140 if ( parameters
.enableFade
= config
.readEntry( "enable-Fade", false ) )
1142 parameters
.fadeAmount
= config
.readEntry( "FadeIntensity", 3 );
1143 if ( parameters
.fadeAmount
< 0 )
1144 parameters
.fadeAmount
= 0;
1145 if ( parameters
.fadeAmount
> 9 )
1146 parameters
.fadeAmount
= 9;
1148 if ( parameters
.enableMegaFlares
= config
.readEntry( "enable-Flares", true ) )
1150 parameters
.megaFlares
= config
.readEntry( "FlaresDimension", 5 );
1151 if ( parameters
.megaFlares
< 0 )
1152 parameters
.megaFlares
= 0;
1153 if ( parameters
.megaFlares
> 10 )
1154 parameters
.megaFlares
= 10;
1155 parameters
.megaFlares
+= 4;
1156 parameters
.megaFlares
*= 2;
1158 parameters
.enableTrails
= config
.readEntry( "enable-Trail", false );