|
|
|
/***************************************************************************
|
|
|
|
* 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, ¤tNumber );
|
|
|
|
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;
|
|
|
|
}
|