Back to index

kdeartwork  4.3.2
firesaverwriter.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2004 by E.Ros                                           *
00003  *   rosenric@dei.unipd.it                                                 *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  *                                                                         *
00010  ***************************************************************************/
00011 
00012 #include <math.h>
00013 #include <stdlib.h>
00014 #include <qimage.h>
00015 #include <qgl.h>
00016 #include <qfile.h>
00017 #include <qstring.h>
00018 
00019 #include <kdebug.h>
00020 #include <kstandarddirs.h>
00021 #include <kdeversion.h>
00022 #include <klocale.h>
00023 #include "firesaverwriter.h"
00024 
00025 
00026 /* Word: SINGLE WORD */
00027 
00028 Word::Word( const char * _text, QMap<char, Symbol *> * sMap, float _scale )
00029     : width(0), scale(_scale), cX(0), cY(0), vScale(0), vX(0), vY(0),
00030     activateTime(0.0), lifeTime(2), currentTime(0)
00031 {
00032        for ( ; *_text != 0 && *_text != ' '; _text++ )
00033        {
00034               char c = *_text;
00035               if ( !sMap->contains(c) )   //search for a symbol in the map
00036                      continue;
00037               Symbol * symbol = (*sMap)[c];      //get the symbol*
00038               width += symbol->scale;            //increase word's half-width
00039               symbolList.append( symbol );       //insert it to the list
00040        }
00041        color[0] = 0;
00042        color[1] = 0.8 * drand48();
00043        color[2] = 0.2 + 0.8 * drand48();
00044        color[3] = 1;
00045 }
00046 
00047 inline void Word::renderWord( double dT )
00048 {
00049        if ( (currentTime += dT) < activateTime )
00050               return;
00051 
00052        //update coloring
00053        if ( activateTime >= 0 ) {
00054               if ( currentTime < activateTime + 0.4 )
00055                      color[3] = (currentTime - activateTime) / 0.4;
00056               else
00057                      color[3] = 1 - (currentTime - activateTime - 0.4) / (lifeTime - 0.4);
00058        } else
00059               color[3] = 1 - currentTime / lifeTime;
00060 
00061        //word's global transforms
00062        glPushMatrix();
00063        glTranslatef( cX - scale * width, cY, 0 );
00064        glScalef( scale, scale, 1 );
00065        glColor4fv( color );
00066 
00067        //for each symbol draw it!
00068        Symbol * symbol = symbolList.first();
00069        for( ; symbol; symbol = symbolList.next() )
00070               symbol->renderSymbol();
00071        glPopMatrix();
00072 
00073        //physical update to position and scale
00074        cX += vX * dT;
00075        cY += vY * dT;
00076        scale += scale * vScale * dT;
00077 }
00078 
00079 inline bool Word::isDead()
00080 {
00081        if ( activateTime > 0 )
00082               return (currentTime - activateTime) >= lifeTime;
00083        return currentTime >= lifeTime;
00084 }
00085 
00086 
00087 
00088 /* Writer: engine that spawns and manages words */
00089 
00090 Writer::Writer( QString descFileName )
00091     : numTextures(0)
00092 {
00093        wordList.setAutoDelete( true );
00094 
00095        if ( !loadMap( descFileName ) )
00096               return;
00097 
00098        QString welcomeString = i18n("Welcome to KDE %1.%2.%3",
00099             KDE_VERSION_MAJOR,
00100             KDE_VERSION_MINOR,
00101             KDE_VERSION_RELEASE);
00102        spawnWords(welcomeString, Fun1);
00103 }
00104 
00105 Writer::~ Writer()
00106 {
00107        glDeleteTextures( numTextures, texArray );
00108        wordList.clear();
00109        QMap<char, Symbol *>::Iterator it = symbolMap.begin();
00110        for ( ; it != symbolMap.end(); ++it )
00111               delete (Symbol *)it.data();
00112 }
00113 
00114 void Writer::spawnWords( QString phrase, effectType fX )
00115 {
00116        int wordCount = 0;
00117        float xCenter = 0,
00118              yCenter = drand48()*40 - 20,
00119              wordsWidth = 0;
00120        QList<Word *> localWords;
00121        while ( phrase.length() > 0 )
00122        {
00123               QString letters = phrase.section(' ',0,0);
00124               Word * word = new Word( letters.latin1(), &symbolMap );
00125               wordList.append( word );
00126               localWords.append( word );
00127               word->cX = xCenter;
00128               word->cY = yCenter;
00129               switch ( fX ) {
00130                   case Fun1:{
00131                      float  angle = 2*M_PI * drand48(),
00132                             module = 0.25 * (drand48() + drand48());
00133                      word->vX = module * cos( angle );
00134                      word->vY = module * sin( angle );
00135                      word->vScale = 0.6;
00136                      word->scale = 0.7 + 0.3*(drand48() + drand48());}
00137                      word->activateTime = 0.3 * wordCount;
00138                      //fall to the case below for word spacing
00139                   default:
00140                   case NoEffect:
00141                      wordsWidth += word->width;
00142                      word->cX += wordsWidth;
00143                      wordsWidth += word->width + 1;
00144                      break;
00145                   case Sequence:
00146                      word->lifeTime = 1.2;
00147                      word->activateTime = 0.6 + 0.9 * wordCount;
00148 //                   word->vY = -5;
00149                      break;
00150               }
00151               wordCount ++;
00152               phrase.remove(0, letters.length() + 1);
00153        }
00154        if ( localWords.count() < 1 )
00155               return;
00156        //some computations to 'center' the string
00157        float displace = -(wordsWidth - 1) / 2;
00158        Word * word = localWords.first();
00159        for( ; word; word = localWords.next() )
00160               word->cX += displace;
00161 }
00162 
00163 void Writer::render( double dT )
00164 {
00165     if ( !numTextures )
00166        return;
00167 
00168     glEnable( GL_TEXTURE_2D );
00169 
00170     glPushMatrix();
00171     glScalef( 0.6, 0.6, 1.0 );
00172     Word * word = wordList.first();
00173     while( word ) {
00174        word->renderWord( dT );
00175        if ( word->isDead() ) {
00176               wordList.remove();
00177               word = wordList.current();
00178        } else
00179               word = wordList.next();
00180     }
00181     glPopMatrix();
00182 }
00183 
00184 /* loadMap()
00185  *  parses the description file to create the internal symbols map.
00186  *  This map is then used when building words.
00187  **/
00188 bool Writer::loadMap( QString descFile )
00189 {
00190     QFile desc( locate("data","kfiresaver/"+descFile) );
00191     if ( !desc.open( QIODevice::ReadOnly ) )
00192        return false;
00193 
00194     unsigned int currentNumber;
00195     float xres = 0, yres = 0;
00196     bool generatedFirst = false;
00197 
00198     while ( !desc.atEnd() )
00199     {
00200        QString line;
00201        int count = desc.readLine( line, 100 );
00202        //skip comments / invalid lines
00203        if ( count < 6 || line.at(0) == '#')
00204            continue;
00205        //load texture maps
00206        if ( line.at(0) == '"' && numTextures < 15 )
00207        {
00208            //load and generate texture
00209            QString fileName = line.section("\"", 1,1 );
00210            QImage tmp;
00211            if ( !tmp.load( locate("data","kfiresaver/"+fileName) ) ) {
00212               kWarning() << "can't load filename:" << fileName ;
00213               generatedFirst = false;
00214               continue;
00215            }
00216            glGenTextures( 1, &currentNumber );
00217            texArray[ numTextures++ ] = currentNumber;
00218            glBindTexture(GL_TEXTURE_2D, currentNumber);
00219            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
00220            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
00221            QImage texture = QGLWidget::convertToGLFormat( tmp );
00222            xres = (float)texture.width();
00223            yres = (float)texture.height();
00224            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)xres, (int)yres, 0,
00225               GL_RGBA, GL_UNSIGNED_BYTE, texture.bits());
00226            generatedFirst = true;
00227            continue;
00228        }
00229        if  ( !generatedFirst )
00230            continue;
00231        if ( line.contains(' ') != 4 ) {
00232            kWarning() << "wrong line on symbols.desc (4 spaces expected):" ;
00233            kWarning() << " '" << line << "'" ;
00234            continue;
00235        }
00236        //parse the line describing a symbol and create it
00237        char p = *(line.latin1());
00238        if ( symbolMap.contains(p) )
00239            continue;
00240        float left = (float)(line.section(' ',1,1).toInt())/xres,
00241              top = (float)(line.section(' ',2,2).toInt())/yres,
00242              right = (float)(line.section(' ',3,3).toInt() + 1)/xres,
00243              bottom = (float)(line.section(' ',4,4).toInt() + 1)/yres;
00244        symbolMap[p] = new Symbol( currentNumber, left,top,right,bottom );
00245     }
00246 
00247     return symbolMap.size() > 0;
00248 }