/*************************************************************************** Twin4 - Four in a Row for TDE ------------------- begin : March 2000 copyright : (C) 1995-2001 by Martin Heni email : martin@heni-online.de ***************************************************************************/ /*************************************************************************** * * * 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 "kspritecache.h" #include #include #include #include #include #include // KSprite #include KSpriteCache::KSpriteCache(TQString grafixdir, TQObject* parent,const char * name) : TQObject(parent,name) { kdDebug(11002) << "KSpriteCache:: grafixdir=" << grafixdir << endl; mConfig=0; mCanvas=0; setRcFile(TQString("grafix.rc")); setGrafixDir(grafixdir); kdDebug(11002) << "Grafixdir=" << grafixDir() << " rcfile=" << rcFile() << endl; reset(); } KSpriteCache::~KSpriteCache() { kdDebug(11002) << "KSpriteCache: ItemDict=" << mItemDict.count() << endl; kdDebug(11002) << "KSpriteCache: CloneDict=" << mCloneDict.count() << endl; reset(); delete mConfig; } void KSpriteCache::setRcFile(TQString name) { mRcFile=name; } bool KSpriteCache::setGrafixDir(TQString name) { delete mConfig; TQDir dir(name); TQString d; d=dir.absPath()+TQString("/"); TQString file=d+rcFile(); // TODO check for filename kdDebug(11002) << "Opening config " << file << endl; mConfig=new TDEConfig(file,false,false); mGrafixDir=d; return true; } void KSpriteCache::reset() { mItemDict.setAutoDelete(false); mCloneDict.setAutoDelete(false); mItemDict.clear(); mCloneDict.clear(); } void KSpriteCache::deleteAllItems() { TQDictIterator it( mItemDict ); //kdDebug(11002) << "KSpriteCache::deleteAllItems items in cache=" << mItemDict.size() << endl; while ( it.current() ) { TQCanvasItem *item=it.current(); mItemDict.remove(it.currentKey()); delete item; } } void KSpriteCache::deleteItem(TQString s,int no) { TQCanvasItem *item; TQString name=s+TQString("_%1").arg(no); //kdDebug(11002) << "KSpriteCache::deleteItem name=" << name << endl; item=mItemDict[name]; if (item) { mItemDict.remove(name); // kdDebug(11002) << "deleteitem "< getItem("<"<hasGroup(name)) { kdError() << "Item "<setGroup(name); item=loadItem(mConfig,name); // kdDebug(11002) << "Inserting sprite="<load(dir+file); } if (result1 && !mask.isNull()) { TQBitmap bitmask; if (mask==TQString("auto")) // self mask..slow but quick to create { newP->setMask( newP->createHeuristicMask() ); result2=true; } else { result2=bitmask.load(dir+mask); if (result2) newP->setMask(bitmask); } } //kdDebug(11002) << "KSpriteCache::loadPixmap: file="<readListEntry("pixmaps"); // Append default entry (empty string) if (operationList.count()==0) { operationList.append(TQString()); } // Prepare for the reading of the pixmaps TQPixmap *pixmap=0; TQPtrList pixlist; pixlist.setAutoDelete(true); TQPtrList hotlist; hotlist.setAutoDelete(true); // work through the operations list and create pixmaps for ( TQStringList::Iterator it = operationList.begin(); it !=operationList.end(); ++it ) { TQString name=*it; // Try to find out what we want to do, e.g. load, scale, ... TQString type=config->readEntry(name+"method"); if (type.isNull()) type=TQString("load"); // default load //kdDebug(11002) << " Processing operation " << (name.isNull()?"default":name) << "type="<readNumEntry(name+"number",1); //kdDebug(11002) << " Reading " << number << " frames " << endl; TQString pixfile=config->readPathEntry(name+"file"); TQString mastdefile=config->readPathEntry(name+"mask"); // Load a given set of images or replace a %d by a sequence if there are // less image names than number given if (type==TQString("load")) { // Read images for (unsigned int i=0;ireadNumEntry(name+"axis",0); double finalscale=config->readDoubleNumEntry(name+"final",0.0); double step; if (number>1) step=(100.0-finalscale)/100.0/(double)(number-1); else step=1.0; //kdDebug(11002) << " Scaling " << number << " pics axis="< transformList; transformList=config->readIntListEntry(name+"transformfilter"); // apply transformation filter if (transformList.count()>0) { if (transformList[0]==1 && transformList.count()==2) // rotate { TQWMatrix rotate; rotate.rotate(transformList[1]); *pixmap=pixmap->xForm(rotate); } else if (transformList[0]==2 && transformList.count()==3) // scale { TQWMatrix scale; scale.scale((double)transformList[1]/100.0,(double)transformList[2]/100.0); *pixmap=pixmap->xForm(scale); } } // apply colorfilter if (filterList.count()>0) { // Only filter 1 HSV and 2: grey are implemented if (filterList[0]==1 && filterList.count()==4) changeHSV(pixmap,filterList[1],filterList[2],filterList[3]); else if (filterList[0]==2 && filterList.count()==2) changeGrey(pixmap,filterList[1]); else if (filterList[0]==2 && filterList.count()==1) changeGrey(pixmap); else kdWarning(11002) << "WARNING: Colorfilter parameter incorrect "<< endl; } } void KSpriteCache::changeHSV(TQPixmap *pixmap,int dh,int ds,int dv) { if (!pixmap || (dh==0 && ds==0 && dv==0)) return ; if (pixmap->isNull()) return ; if (pixmap->width()==0 && pixmap->height()==0) return ; int h,s,v; TQColor black=TQColor(0,0,0); TQImage img=pixmap->convertToImage(); // slow for (int y=0;yconvertFromImage(img); // slow } void KSpriteCache::changeGrey(TQPixmap *pixmap,int lighter) { if (!pixmap) return ; if (pixmap->isNull()) return ; if (pixmap->width()==0 && pixmap->height()==0) return ; TQImage img=pixmap->convertToImage(); // slow for (int y=0;y0) col=col.light(lighter); if (lighter<0) col=col.dark(-lighter); img.setPixel(x,y,tqRgba(col.red(),col.green(),col.blue(),tqAlpha(pix))); } } pixmap->convertFromImage(img); // slow } TQCanvasItem *KSpriteCache::loadItem(TDEConfig *config,TQString name) { if (!config) return 0; int rtti=config->readNumEntry("rtti",0); TQCanvasItem *item=0; switch(rtti) { case TQCanvasItem::Rtti_Text: { TQCanvasText *sprite=new TQCanvasText(canvas()); //kdDebug(11002) << "new CanvasText =" << sprite << endl; TQString text=config->readEntry("text"); sprite->setText(text); TQColor color=config->readColorEntry("color"); sprite->setColor(color); TQFont font=config->readFontEntry("font"); sprite->setFont(font); item=(TQCanvasItem *)sprite; configureCanvasItem(config,item); } break; case 32: { TQCanvasPixmapArray *pixmaps=createPixmapArray(config,name); KSprite *sprite=new KSprite(pixmaps,canvas()); //kdDebug(11002) << "new sprite =" << sprite << endl; double speed=config->readDoubleNumEntry("speed",0.0); sprite->setSpeed(speed); //kdDebug(11002) << "speed=" << sprite->speed() << endl; createAnimations(config,sprite); item=(TQCanvasItem *)sprite; configureCanvasItem(config,item); } break; default: { kdError() << "KSpriteCache::loadItem: Should create unkwown rtti " << rtti << "...overwrite this function" << endl; } break; } return item; } TQCanvasItem *KSpriteCache::cloneItem(TQCanvasItem *original) { if (!original) return 0; int rtti=original->rtti(); TQCanvasItem *item=0; switch(rtti) { case TQCanvasItem::Rtti_Text: { TQCanvasText *sprite=(TQCanvasText *)original; TQCanvasText *copy=new TQCanvasText(canvas()); configureCanvasItem(original,(TQCanvasItem *)copy); copy->setText(sprite->text()); copy->setColor(sprite->color()); copy->setFont(sprite->font()); item=(TQCanvasItem *)copy; } break; case 32: { KSprite *sprite=(KSprite *)original; KSprite *copy=new KSprite(sprite->images(),canvas()); configureCanvasItem(original,(TQCanvasItem *)copy); copy->setSpeed(sprite->speed()); createAnimations(sprite,copy); item=(TQCanvasItem *)copy; } break; default: { kdError() << "KSpriteCache::cloneItem: Should create unkwown rtti " << rtti << "...overwrite this function" << endl; } break; } return item; } void KSpriteCache::configureCanvasItem(TDEConfig *config, TQCanvasItem *sprite) { double x=config->readDoubleNumEntry("x",0.0); double y=config->readDoubleNumEntry("y",0.0); double z=config->readDoubleNumEntry("z",0.0); sprite->setX(x); sprite->setY(y); sprite->setZ(z); //kdDebug(11002) << "x=" << sprite->x() << endl; //kdDebug(11002) << "y=" << sprite->y() << endl; //kdDebug(11002) << "z=" << sprite->z() << endl; } void KSpriteCache::configureCanvasItem(TQCanvasItem *original, TQCanvasItem *copy) { copy->setX(original->x()); copy->setY(original->y()); copy->setZ(original->z()); } void KSpriteCache::createAnimations(KSprite *original,KSprite *sprite) { unsigned int no=original->animationCount(); for (unsigned int i=0;igetAnimation(i,start,end,mode,delay); sprite->createAnimation(i,start,end,mode,delay); } } void KSpriteCache::createAnimations(TDEConfig *config,KSprite *sprite) { if (!sprite) return ; for (int i=0;i<1000;i++) { TQString anim=TQString("anim%1").arg(i); if (config->hasKey(anim)) { //kdDebug(11002) << "Found animation key " << anim << endl; TQValueList animList=config->readIntListEntry(anim); if (animList.count()!=4) { kdWarning(11002) << "KSpriteCache::createAnimations:: warning animation parameter " << anim << " needs four arguments" << endl; } else { sprite->createAnimation(i,animList[0],animList[1],animList[2],animList[3]); } } else { break; } } } // ----------------------- KSPRITE -------------------------------- KSprite::KSprite(TQCanvasPixmapArray* array, TQCanvas* canvas) :TQCanvasSprite(array,canvas) { mImages=array; mSpeed=0.0; mNotify=0; mAnimationNumber=-1; mAnimSpeedCnt=0; mMoveObj=0; } void KSprite::moveTo(double tx,double ty,double speed) { if (speed>0.0) { mSpeed=speed; } //kdDebug(11002) <<"KSprite::moveTo x=" << tx << " y="<b // -1: single shot b->a // 2: cycle a->b->a // -2: cycle b->a->b // 3: cycle a->b // -3: cycle b->a mAnimSpeedCnt++; if (mAnimationNumber<0 || mAnimDelay[mAnimationNumber]==0) { // nothing to do? isAnimated=false; mAnimSpeedCnt=0; } if (mAnimationNumber>=0 && mAnimSpeedCnt>=mAnimDelay[mAnimationNumber]) { switch(mAnimDirection[mAnimationNumber]) { case 1: if (frame()+1 <= mAnimTo[mAnimationNumber]) setFrame(frame()+1); else emitsignal=2; break; case -1: if (frame()-1 >= mAnimFrom[mAnimationNumber]) setFrame(frame()-1); else emitsignal=2; break; case 2: if (mAnimDirection[mAnimationNumber]==mCurrentAnimDir) { if (frame()+1 <= mAnimTo[mAnimationNumber]) setFrame(frame()+1); else { mCurrentAnimDir=-mCurrentAnimDir; if (frame()>0) setFrame(frame()-1); } } else { if (frame()-1 >= mAnimFrom[mAnimationNumber]) setFrame(frame()-1); else { mCurrentAnimDir=-mCurrentAnimDir; if (frame()+1= mAnimFrom[mAnimationNumber]) setFrame(frame()-1); else { mCurrentAnimDir=-mCurrentAnimDir; if (frame()+10) setFrame(frame()-1); } } break; case 3: if (frame()+1 <= mAnimTo[mAnimationNumber]) setFrame(frame()+1); else setFrame(mAnimFrom[mAnimationNumber]); break; case -3: if (frame()-1 >= mAnimFrom[mAnimationNumber]) setFrame(frame()-1); else setFrame(mAnimTo[mAnimationNumber]); break; default: //0 isAnimated=false; setFrame(0); } if (emitsignal) isAnimated=false; mAnimSpeedCnt=0; } // Movement to target if (!moveObject() && (fabs(mTargetX-x())+fabs(mTargetY-y())) >0.0 && mSpeed>0.0) { isMoving=spriteMove(mTargetX,mTargetY); if (!isMoving) emitsignal=1; } else if (moveObject()) { isMoving=moveObject()->spriteMove(mTargetX,mTargetY,this); if (!isMoving) emitsignal=1; } // Final checks if (!isAnimated && !isMoving) { //kdDebug(11002) << "Animation over" << endl; setAnimated(false); } if (mNotify && emitsignal) { //kdDebug(11002) << " ADVANCE emits signal " << emitsignal << " for item "<< this << endl; mNotify->emitSignal((TQCanvasItem *)this,emitsignal); } } // Generates linear movement to tx,ty bool KSprite::spriteMove(double tx,double ty) { bool isMoving=false; double dx,dy; double vx,vy; dx=tx-x(); dy=ty-y(); vx=0.0; vy=0.0; // first pure x,y movements if (fabs(dy)<=0.0001) { if (dx>0.0) vx=mSpeed; else if (dx<0.0) vx=-mSpeed; else vx=0.0; } else if (fabs(dx)<=0.0001) { if (dy>0.0) vy=mSpeed; else if (dy<0.0) vy=-mSpeed; else vy=0.0; } else // diagonal { double alpha=atan2(dy,dx); vx=cos(alpha)*mSpeed; vy=sin(alpha)*mSpeed; } if (fabs(dx)<=fabs(vx) && fabs(dy)<=fabs(vy)) { move(tx,ty); isMoving=false; } else if (fabs(dx)<=fabs(vx)) { moveBy(dx,vy); isMoving=true; } else if (fabs(dy)<=fabs(vy)) { moveBy(vx,dy); isMoving=true; } else { moveBy(vx,vy); isMoving=true; } return isMoving; } void KSprite::emitNotify(int mode) { if (!mNotify) return ; //kdDebug(11002) << " ADVANCE emits DIRECT signal " << mode << " for item "<< this << endl; mNotify->emitSignal((TQCanvasItem *)this,mode); } TQObject *KSprite::createNotify() { if (!mNotify) mNotify=new KSpriteNotify; mNotify->incRefCnt(); return (TQObject *)mNotify; } void KSprite::deleteNotify() { if (!mNotify) return ; mNotify->decRefCnt(); if (mNotify->refCnt()<=0) { //kdDebug(11002) << "REALLY deleting notify" << endl; delete mNotify; mNotify=0; } } KSprite::~KSprite() { delete mNotify; mNotify=0; } void KSprite::setAnimation(int no) { if ((int)mAnimFrom.count()<=no) { kdError(11002) << "KSprite::setAnimation:: Animation " << no << " not defined " << endl; return ; } mAnimationNumber=no; if (no<0) return ; mAnimSpeedCnt=0; mCurrentAnimDir=mAnimDirection[no]; // Start frame if (mCurrentAnimDir>0) setFrame(mAnimFrom[no]); else if (mCurrentAnimDir<0) setFrame(mAnimTo[no]); // animated if (mCurrentAnimDir!=0 && mAnimTo[no]>=mAnimFrom[no]) setAnimated(true); else setAnimated(false); //kdDebug(11002) << this << " setAnimation("<"<