You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdeartwork/tdescreensaver/kdesavers/firesaverwriter.cpp

248 lines
6.9 KiB

/***************************************************************************
* Copyright (C) 2004 by E.Ros *
* rosenric@dei.unipd.it *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include <math.h>
#include <stdlib.h>
#include <tqimage.h>
#include <tqgl.h>
#include <tqfile.h>
#include <tqstring.h>
#include <kdebug.h>
#include <kstandarddirs.h>
#include <tdeversion.h>
#include <tdelocale.h>
#include "firesaverwriter.h"
/* Word: SINGLE WORD */
Word::Word( const char * _text, TQMap<char, Symbol *> * sMap, float _scale )
: width(0), scale(_scale), cX(0), cY(0), vScale(0), vX(0), vY(0),
activateTime(0.0), lifeTime(2), currentTime(0)
{
for ( ; *_text != 0 && *_text != ' '; _text++ )
{
char c = *_text;
if ( !sMap->contains(c) ) //search for a symbol in the map
continue;
Symbol * symbol = (*sMap)[c]; //get the symbol*
width += symbol->scale; //increase word's half-width
symbolList.append( symbol ); //insert it to the list
}
color[0] = 0;
color[1] = 0.8 * drand48();
color[2] = 0.2 + 0.8 * drand48();
color[3] = 1;
}
inline void Word::renderWord( double dT )
{
if ( (currentTime += dT) < activateTime )
return;
//update coloring
if ( activateTime >= 0 ) {
if ( currentTime < activateTime + 0.4 )
color[3] = (currentTime - activateTime) / 0.4;
else
color[3] = 1 - (currentTime - activateTime - 0.4) / (lifeTime - 0.4);
} else
color[3] = 1 - currentTime / lifeTime;
//word's global transforms
glPushMatrix();
glTranslatef( cX - scale * width, cY, 0 );
glScalef( scale, scale, 1 );
glColor4fv( color );
//for each symbol draw it!
Symbol * symbol = symbolList.first();
for( ; symbol; symbol = symbolList.next() )
symbol->renderSymbol();
glPopMatrix();
//physical update to position and scale
cX += vX * dT;
cY += vY * dT;
scale += scale * vScale * dT;
}
inline bool Word::isDead()
{
if ( activateTime > 0 )
return (currentTime - activateTime) >= lifeTime;
return currentTime >= lifeTime;
}
/* Writer: engine that spawns and manages words */
Writer::Writer( TQString descFileName )
: numTextures(0)
{
wordList.setAutoDelete( true );
if ( !loadMap( descFileName ) )
return;
TQString welcomeString = i18n("Welcome to KDE %1.%2.%3")
.arg(TDE_VERSION_MAJOR)
.arg(TDE_VERSION_MINOR)
.arg(TDE_VERSION_RELEASE);
spawnWords(welcomeString, Fun1);
}
Writer::~ Writer()
{
glDeleteTextures( numTextures, texArray );
wordList.clear();
TQMap<char, Symbol *>::Iterator it = symbolMap.begin();
for ( ; it != symbolMap.end(); ++it )
delete (Symbol *)it.data();
}
void Writer::spawnWords( TQString phrase, effectType fX )
{
int wordCount = 0;
float xCenter = 0,
yCenter = drand48()*40 - 20,
wordsWidth = 0;
TQPtrList<Word> localWords;
while ( phrase.length() > 0 )
{
TQString letters = phrase.section(" ",0,0);
Word * word = new Word( letters.latin1(), &symbolMap );
wordList.append( word );
localWords.append( word );
word->cX = xCenter;
word->cY = yCenter;
switch ( fX ) {
case Fun1:{
float angle = 2*M_PI * drand48(),
module = 0.25 * (drand48() + drand48());
word->vX = module * cos( angle );
word->vY = module * sin( angle );
word->vScale = 0.6;
word->scale = 0.7 + 0.3*(drand48() + drand48());}
word->activateTime = 0.3 * wordCount;
//fall to the case below for word spacing
default:
case NoEffect:
wordsWidth += word->width;
word->cX += wordsWidth;
wordsWidth += word->width + 1;
break;
case Sequence:
word->lifeTime = 1.2;
word->activateTime = 0.6 + 0.9 * wordCount;
// word->vY = -5;
break;
}
wordCount ++;
phrase.remove(0, letters.length() + 1);
}
if ( localWords.count() < 1 )
return;
//some computations to 'center' the string
float displace = -(wordsWidth - 1) / 2;
Word * word = localWords.first();
for( ; word; word = localWords.next() )
word->cX += displace;
}
void Writer::render( double dT )
{
if ( !numTextures )
return;
glEnable( GL_TEXTURE_2D );
glPushMatrix();
glScalef( 0.6, 0.6, 1.0 );
Word * word = wordList.first();
while( word ) {
word->renderWord( dT );
if ( word->isDead() ) {
wordList.remove();
word = wordList.current();
} else
word = wordList.next();
}
glPopMatrix();
}
/* loadMap()
* parses the description file to create the internal symbols map.
* This map is then used when building words.
**/
bool Writer::loadMap( TQString descFile )
{
TQFile desc( locate("data","kfiresaver/"+descFile) );
if ( !desc.open( IO_ReadOnly ) )
return false;
unsigned int currentNumber;
float xres = 0, yres = 0;
bool generatedFirst = false;
while ( !desc.atEnd() )
{
TQString line;
int count = desc.readLine( line, 100 );
//skip comments / invalid lines
if ( count < 6 || line.at(0) == '#')
continue;
//load texture maps
if ( line.at(0) == '"' && numTextures < 15 )
{
//load and generate texture
TQString fileName = line.section("\"", 1,1 );
TQImage tmp;
if ( !tmp.load( locate("data","kfiresaver/"+fileName) ) ) {
kdWarning() << "can't load filename:" << fileName << endl;
generatedFirst = false;
continue;
}
glGenTextures( 1, &currentNumber );
texArray[ numTextures++ ] = currentNumber;
glBindTexture(GL_TEXTURE_2D, currentNumber);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
TQImage texture = TQGLWidget::convertToGLFormat( tmp );
xres = (float)texture.width();
yres = (float)texture.height();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)xres, (int)yres, 0,
GL_RGBA, GL_UNSIGNED_BYTE, texture.bits());
generatedFirst = true;
continue;
}
if ( !generatedFirst )
continue;
if ( line.contains(' ') != 4 ) {
kdWarning() << "wrong line on symbols.desc (4 spaces expected):" << endl;
kdWarning() << " '" << line << "'" << endl;
continue;
}
//parse the line describing a symbol and create it
char p = *(line.latin1());
if ( symbolMap.contains(p) )
continue;
float left = (float)(line.section(" ",1,1).toInt())/xres,
top = (float)(line.section(" ",2,2).toInt())/yres,
right = (float)(line.section(" ",3,3).toInt() + 1)/xres,
bottom = (float)(line.section(" ",4,4).toInt() + 1)/yres;
symbolMap[p] = new Symbol( currentNumber, left,top,right,bottom );
}
return symbolMap.size() > 0;
}