/* Ball animation classes */ #include "Ball.h" #include #include #include #include #include #include Ball* Ball::first = 0; //TQImage Ball::back; int Ball::sizeX, Ball::sizeY; double Ball::lightX, Ball::lightY, Ball::lightZ; TQColor Ball::lightColor; double Ball::rippleCount, Ball::rippleDepth; /* set global Ball parameter */ void Ball::setSize(int x, int y) { sizeX = x; sizeY = y; tqinvalidate(); } void Ball::tqinvalidate() { Ball *b; /* tqinvalidate all Balls... */ for(b=first;b!=0;b=b->next) b->pm.resize(0,0); } void Ball::setLight(int x, int y, int z, const TQColor& c) { double len = sqrt(double(x*x + y*y + z*z)); lightX = x/len; lightY = y/len; lightZ = z/len; lightColor = c; tqinvalidate(); } void Ball::setTexture(double c, double d) { rippleCount = c; rippleDepth = d; tqinvalidate(); } Ball::Ball(const TQColor& c, double a, int t) { if (first ==0) { sizeX = sizeY = -1; setLight(); setTexture(7,.3); } bColor = c; an = a; sina = sin(a), cosa = cos(a); zoom= 1.05, flip = 2.0, limit = 0; tex = t; next = first; first = this; } Ball::~Ball() { Ball* b; if (first == this) first = next; else { for(b = first; b!=0; b=b->next) if (b->next == this) break; if (b!=0) b->next = next; } } TQPixmap* Ball::pixmap() { if (pm.isNull() && sizeX>0 && sizeY>0) render(); return ± } void Ball::render() { int x,y; double xx,yy,zz, ll,lll, red,green,blue; if (sizeX==0 || sizeY==0) return; TQImage image(sizeX,sizeY,32); image.fill(0); double vv=2./(sizeX+sizeY); /* Go through all pixels, mapping x/y to (-1..1,-1..1) */ for(y=0;yflip) zz=2*flip-zz; else { zz -= limit; } if (zz>-vv) { zz = (zz<0) ? 0 : sqrt(zz); /* ll: light intensity at this point */ ll = xx*lightX + yy*lightY + zz*lightZ; /* some face modification */ double mapx = xx*(2-zz); double mapy = yy*(2-zz); double rmapx = cosa*mapx + sina*mapy; /* rotate */ double rmapy = -sina*mapx + cosa*mapy; if (tex>0) ll += rippleDepth* cos(rippleCount*rmapx)*cos(rippleCount*rmapy); ll = (ll<0.01) ? 0.0 : (ll>.99) ? 1.0 : ll; lll = ll*ll; // printf("x %f, y %f, z %f : ll %f lll %f\n", xx,yy,zz,ll,lll); /* mix ball+light */ red = lll * lightColor.red() + (1-lll) * bColor.red(); green = lll * lightColor.green() + (1-lll) * bColor.green(); blue = lll * lightColor.blue() + (1-lll) * bColor.blue(); /* lightness */ red = .2 * bColor.red() + .8 * ll * red; green = .2 * bColor.green() + .8 * ll * green; blue = .2 * bColor.blue() + .8 * ll * blue; image.setPixel(x,y, tqRgb( (int)red, (int)green, (int)blue )); } } } const TQImage iMask = image.createHeuristicMask(); TQBitmap bMask; bMask.convertFromImage(iMask); pm.convertFromImage( image, 0 ); pm.setMask(bMask); } /* Class BallAnimation */ BallAnimation::BallAnimation(int s, Ball* ball1, Ball* ball2) { TQColor c1 = ball1->ballColor(); double a1 = ball1->angle(); int r1 = c1.red(), g1 = c1.green(), b1 = c1.blue(); TQColor c2 = ball2->ballColor(); double a2 = ball2->angle(); int r2 = c2.red(), g2 = c2.green(), b2 = c2.blue(); TQColor c; double a; int i; steps = s; s--; balls.append( new Ball( c1,a1 ) ); for(i=1; i< s; i++) { c.setRgb( r1+(r2-r1)*i/s, g1+(g2-g1)*i/s, b1+(b2-b1)*i/s ); a = a1+(a2-a1)*i/s; balls.append( new Ball( c,a ) ); } balls.append( new Ball( c2,a2 ) ); } /* Class BallPosition */ BallPosition::BallPosition(int xp,int yp, Ball* d) { x=xp; y=yp; def=d; actStep = -1; actType = ANIMATION_STOPPED; actAnimation=0; } /* Class BallWidget */ BallWidget::BallWidget( int _freq, int bFr, TQWidget *tqparent, const char *name ) : TQWidget(tqparent,name), positions(MAX_POSITION), animations(MAX_ANIMATION) { int i; for(i=0;i= MAX_ANIMATION) return; if (animations[no] !=0) delete animations[no]; animations[no] = new BallAnimation(s,b1,b2); } /* X, Y are coordinates in a virtual 1000x1000 area */ void BallWidget::createBallPosition(int no, int x, int y, Ball* def) { if (no<0 || no>= MAX_POSITION) return; if (positions[no] !=0) delete positions[no]; positions[no] = new BallPosition(x,y, def); } void BallWidget::startAnimation(int pos, int anim, int type) { BallPosition *p; if (pos<0 || pos>=MAX_POSITION || positions[pos]==0) return; if (anim<0 || anim>=MAX_ANIMATION || animations[anim]==0) return; p = positions.at(pos); p->actAnimation = animations.at(anim); /* One step *BEFORE* start */ p->actStep = -1; p->actDir = 1; p->actType = type; if (!isRunning) { isRunning = true; timer->start( 0, true ); } } /* If LOOP: Set to ONESHOT, otherwise set to last frame */ void BallWidget::stopAnimation(int pos) { BallPosition *p; if (pos<0 || pos>=MAX_POSITION || positions[pos]==0) return; p = positions.at(pos); if (p->actType == ANIMATION_STOPPED || p->actAnimation == 0) return; if (p->actType == ANIMATION_LOOP || p->actType == ANIMATION_CYCLE) { p->actType = ANIMATION_FORWARD; // return; } /* Set last step: animate() does the rest */ p->actDir = 1; p->actStep = p->actAnimation->steps; } void BallWidget::resizeEvent(TQResizeEvent *) { int w = width() *10/12, h = height(); realSize = (w>h) ? h:w; Ball::setSize( realSize/ballFraction, realSize/ballFraction ); tqrepaint(); } void BallWidget::paintEvent(TQPaintEvent *) { paint(TQT_TQPAINTDEVICE(this)); } void BallWidget::paint(TQPaintDevice *pd) { int i; BallPosition *p; int xReal, yReal; int w = width(), h = height(); if (realSize<0) return; for(i=0;ix * realSize / 500 - Ball::w() )/2; yReal = (h + p->y * realSize / 500 - Ball::h() )/2; if (p->actAnimation==0 || p->actStep==-1) { if (p->def !=0 ) bitBlt( pd, xReal, yReal, p->def->pixmap() ); } else { int s = p->actStep; if (s>= p->actAnimation->steps) s = p->actAnimation->steps-1; Ball* b = p->actAnimation->balls.at(s); bitBlt( pd, xReal, yReal, b->pixmap() ); } } } void BallWidget::animate() { bool doAnimation = false; int i; BallPosition *p; int xReal, yReal; int w = width(), h = height(); for(i=0;iactType == ANIMATION_STOPPED || p->actAnimation ==0) continue; p->actStep += p->actDir; if (p->actStep <= -1) { p->actDir = 1; p->actStep = 1; doAnimation = true; } else if (p->actStep >= p->actAnimation->steps) { if (p->actType == ANIMATION_CYCLE) { p->actDir = -1; p->actStep = p->actAnimation->steps -2; doAnimation = true; } else if (p->actType == ANIMATION_LOOP) { p->actStep = 1; /*skip first frame for smooth animation */ doAnimation = true; } else { p->actType = ANIMATION_STOPPED; p->actAnimation = 0; emit animationFinished(i); } } else { doAnimation = true; } /* Update Pixmap */ xReal = (w + p->x * realSize / 500 - Ball::w() )/2; yReal = (h + p->y * realSize / 500 - Ball::h() )/2; if (p->actAnimation==0 || p->actStep==-1) { if (p->def !=0 ) bitBlt( this, xReal, yReal, p->def->pixmap() ); } else { int s = p->actStep; if (s>= p->actAnimation->steps) s = p->actAnimation->steps-1; Ball* b = p->actAnimation->balls.at(s); bitBlt( this, xReal, yReal, b->pixmap() ); } } if (!doAnimation) { isRunning = false; emit animationsFinished(); } else { timer->start(1000/freq,true); } // tqrepaint( false ); } /* Ball Test */ BallTest::BallTest( TQWidget *tqparent, const char *name ) : BallWidget(10,2,tqparent,name) { int w,h; w = h = 150; resize(w,h); // Ball::setSize( w/2, h/2, this ); Ball *b1 = new Ball( green ); Ball *b2 = new Ball( yellow ); Ball *b3 = new Ball( red ); Ball *b4 = new Ball( red, 3.14/2 ); createBlending(0,5,b1,b2); createBallPosition( 0,250, 250, b1); createBlending(1,10,b1,b3); createBallPosition(1, 250, 750, b1); createBlending(2,15,b3,b2); createBallPosition( 2, 750, 250, b3); createBlending(3,20,b3,b4); createBallPosition(3, 750, 750, b3); } /* void BallTest::paintEvent( TQPaintEvent * ) { bitBlt(this,0,0, b.pixmap()); } */ void BallTest::mousePressEvent( TQMouseEvent * ) { startAnimation(0,0, ANIMATION_CYCLE); startAnimation(1,1); startAnimation(2,2); startAnimation(3,3, ANIMATION_LOOP); } void BallTest::mouseReleaseEvent( TQMouseEvent * ) { stopAnimation(0); stopAnimation(1); stopAnimation(3); } /* Test... #include int main(int argc, char *argv[]) { zoom=.52; flip=.85; limit=.75; KApplication app(argc, argv, "BallTest"); BallTest top; app.setMainWidget( &top ); top.show(); return app.exec(); } */ #include "Ball.moc"