/raidem-0.3.1-src/src/seborrhea/container-animation.m
Objective C | 362 lines | 268 code | 63 blank | 31 comment | 35 complexity | 990042294561cf85e1f9291eb6dc3457 MD5 | raw file
- /* container-animation.m,
- *
- * Animations are files that contain multiple images, which make up an
- * animation. All of the frames must have the same dimensions.
- */
- #include <stdio.h>
- #include <assert.h>
- #include "seborrhea/container-animation.h"
- #include "seborrhea/seborrhea-common.h"
- #ifndef ABS
- # define ABS(x) (((x) < 0) ? (-x) : (x))
- #endif
- @implementation SebAnimation
- - setFrameDelay:(unsigned int)t LoopMethod:(enum SEB_ANIMATION_LOOP_METHOD)method
- {
- delay = t;
- loop_method = method;
- return self;
- }
- - (unsigned int) frameDelay { return delay; }
- - (enum SEB_ANIMATION_LOOP_METHOD) loopMethod { return loop_method; }
- - (BOOL) addToList:(Sebum<SebImage> *)frame
- {
- assert(frame);
- if (not [frame conformsToProtocol:@protocol(SebImage)]) {
- fprintf(stderr, "[%s:%s] Attempted to add non-image %s (%s)!\n",
- [[[self class] className] cString], [self name],
- [frame name], [[[frame class] className] cString]);
- return NO;
- }
- if (nelements == 0) {
- w = [frame width];
- h = [frame height];
- }
- else if ([frame width] != w || [frame height] != h) {
- fprintf(stderr, "[%s:%s] Attempted to add %s, but has differing dimensions!\n",
- [[[self class] className] cString], [self name], [frame name]);
- return NO;
- }
- return [super addToList:frame];
- }
- - (unsigned int) numFrames { return nelements; }
- - (Sebum<SebImage> *) getFrame:(int)nth
- {
- /* Use negative numbers to denote from back of list. */
- if (nelements == 0)
- return nil;
- if (nth < 0)
- nth += nelements;
- assert((nth >= 0) && ((unsigned)nth < nelements));
- return element[nth];
- }
- - (unsigned int) nextFrame:(unsigned int)curr
- {
- if (curr+1 >= nelements) /* Loop. */
- return 0;
- else
- return curr+1;
- }
- - (void) setPivotX:(int)x Y:(int)y
- {
- unsigned int i;
- for (i = 0; i < nelements; i++)
- [(<SebImage>)element[i] setPivotX:x Y:y];
- }
- /* Dimensions. */
- - (unsigned int) width { return w; }
- - (unsigned int) height { return h; }
- /* Draw, with transparency. */
- - (void) drawTo:(void *)dest X:(int)x Y:(int)y
- {
- assert(nelements > 0);
- [(<SebImage>)element[0] drawTo:dest X:x Y:y];
- }
- - (void) drawTo:(void *)dest X:(int)x Y:(int)y Angle:(double)theta
- {
- assert(nelements > 0);
- [(<SebImage>)element[0] drawTo:dest X:x Y:y Angle:theta];
- }
- - (void) drawTo:(void *)dest X:(int)x Y:(int)y Angle:(double)theta Scale:(double)scale
- {
- assert(nelements > 0);
- [(<SebImage>)element[0] drawTo:dest X:x Y:y Angle:theta Scale:scale];
- }
- /* Draw, with transparency and translucency. */
- - (void) drawTo:(void *)dest X:(int)x Y:(int)y Alpha:(int)alpha
- {
- assert(nelements > 0);
- [(<SebImage>)element[0] drawTo:dest X:x Y:y Alpha:alpha];
- }
- - (void) drawTo:(void *)dest X:(int)x Y:(int)y Alpha:(int)alpha Angle:(double)theta
- {
- assert(nelements > 0);
- [(<SebImage>)element[0] drawTo:dest X:x Y:y Alpha:alpha Angle:theta];
- }
- /* Draw, with transparency and tinting. */
- - (void) drawTo:(void *)dest X:(int)x Y:(int)y Tint:(int)r :(int)g :(int)b :(int)alpha
- {
- assert(nelements > 0);
- [(<SebImage>)element[0] drawTo:dest X:x Y:y Tint:r:g:b:alpha];
- }
- - (void) drawTo:(void *)dest X:(int)x Y:(int)y Tint:(int)r :(int)g :(int)b :(int)alpha Angle:(double)theta
- {
- assert(nelements > 0);
- [(<SebImage>)element[0] drawTo:dest X:x Y:y Tint:r:g:b:alpha Angle:theta];
- }
- /* Draw, without transparency. */
- - (void) drawTo:(void *)dest X:(int)x Y:(int)y W:(int)w_ H:(int)h_
- {
- assert(nelements > 0);
- [(<SebImage>)element[0] drawTo:dest X:x Y:y W:w_ H:h_];
- }
- - (void) drawFromX:(int)sx Y:(int)sy To:(void *)dest X:(int)x Y:(int)y W:(int)w_ H:(int)h_
- {
- assert(nelements > 0);
- [(<SebImage>)element[0] drawFromX:sx Y:sy To:dest X:x Y:y W:w_ H:h_];
- }
- @end
- /*--------------------------------------------------------------*/
- /* SebAnimatorManualPoll. */
- /*--------------------------------------------------------------*/
- @implementation SebAnimatorManual
- - (const char *) name { return [anim name]; }
- - (SebAnimation *)getAnimation { return anim; }
- - resetAnimation
- {
- frame = 0;
- return self;
- }
- - setAnimation:(SebAnimation *)anime
- {
- anim = anime;
- frame = 0;
- loop_method = [anim loopMethod];
- return self;
- }
- - setFrame:(int)frame_
- {
- frame = frame_;
- return self;
- }
- - setLoopMethod:(enum SEB_ANIMATION_LOOP_METHOD)method
- {
- loop_method = method;
- return self;
- }
- - (int) currentFrameNumber { return frame; }
- - (Sebum<SebImage> *) currentFrame
- {
- assert(anim && "[SebAnimator] no animation set!\n");
- /* ABS corrects the frame for when ping-pong-ing. */
- return [anim getFrame:ABS(frame)];
- }
- - (BOOL) nextFrame
- {
- if (loop_method == LOOP_NONE) {
- int next_frame = [anim nextFrame:frame];
- if (next_frame == 0)
- return NO;
- frame = next_frame;
- }
- else if (loop_method == LOOP_FORWARD) {
- frame = [anim nextFrame:frame];
- }
- else if (loop_method == LOOP_PING_PONG) {
- int num_frames = [anim numFrames];
- if (frame+1 >= num_frames)
- frame = -num_frames+1;
- else
- frame++;
- }
- return YES;
- }
- - (void) updateFrame
- {
- /* This is called after each draw routine. It is mainly for use
- by SebAnimator. */
- }
- - (BOOL) animationEnded
- {
- if (loop_method == LOOP_NONE &&
- frame+1 == (int)[anim numFrames])
- return YES;
- else
- return NO;
- }
- - (void) setPivotX:(int)x Y:(int)y
- {
- assert(anim);
- [anim setPivotX:x Y:y];
- }
- /* Dimensions. */
- - (unsigned int) width { return [anim width]; }
- - (unsigned int) height { return [anim height]; }
- /* Draw, with transparency. */
- - (void) drawTo:(void *)dest X:(int)x Y:(int)y
- {
- [[self currentFrame] drawTo:dest X:x Y:y];
- [self updateFrame];
- }
- - (void) drawTo:(void *)dest X:(int)x Y:(int)y Angle:(double)theta
- {
- [[self currentFrame] drawTo:dest X:x Y:y Angle:theta];
- [self updateFrame];
- }
- - (void) drawTo:(void *)dest X:(int)x Y:(int)y Angle:(double)theta Scale:(double)scale
- {
- [[self currentFrame] drawTo:dest X:x Y:y Angle:theta Scale:scale];
- [self updateFrame];
- }
- /* Draw, with transparency and translucency. */
- - (void) drawTo:(void *)dest X:(int)x Y:(int)y Alpha:(int)alpha
- {
- [[self currentFrame] drawTo:dest X:x Y:y Alpha:alpha];
- [self updateFrame];
- }
- - (void) drawTo:(void *)dest X:(int)x Y:(int)y Alpha:(int)alpha Angle:(double)theta
- {
- [[self currentFrame] drawTo:dest X:x Y:y Alpha:alpha Angle:theta];
- [self updateFrame];
- }
- /* Draw, with transparency and tinting. */
- - (void) drawTo:(void *)dest X:(int)x Y:(int)y Tint:(int)r :(int)g :(int)b :(int)alpha;
- {
- [[self currentFrame] drawTo:dest X:x Y:y Tint:r:g:b:alpha];
- [self updateFrame];
- }
- - (void) drawTo:(void *)dest X:(int)x Y:(int)y Tint:(int)r :(int)g :(int)b :(int)alpha Angle:(double)theta
- {
- [[self currentFrame] drawTo:dest X:x Y:y Tint:r:g:b:alpha Angle:theta];
- [self updateFrame];
- }
- /* Draw, without transparency. */
- - (void) drawTo:(void *)dest X:(int)x Y:(int)y W:(int)w H:(int)h
- {
- [[self currentFrame] drawTo:dest X:x Y:y W:w H:h];
- [self updateFrame];
- }
- - (void) drawFromX:(int)sx Y:(int)sy To:(void *)dest X:(int)x Y:(int)y W:(int)w H:(int)h
- {
- [[self currentFrame] drawFromX:sx Y:sy To:dest X:x Y:y W:w H:h];
- [self updateFrame];
- }
- @end
- /*--------------------------------------------------------------*/
- /* SebAnimatorManualWithDelay is like SebAnimatorManual, but it
- * respects the frame delay set by the animation. */
- @implementation SebAnimatorManualWithDelay
- - resetAnimation
- {
- [super resetAnimation];
- frame_tics = [anim frameDelay];
- return self;
- }
- - setAnimation:(SebAnimation *)anime
- {
- [super setAnimation:anime];
- frame_tics = [anim frameDelay];
- return self;
- }
- - setFrame:(int)frame_
- {
- [super setFrame:frame_];
- frame_tics = [anim frameDelay];
- return self;
- }
- - (BOOL) nextFrame
- {
- frame_tics--;
- if (frame_tics <= 0) {
- if ([super nextFrame]) {
- frame_tics = [anim frameDelay];
- return YES;
- }
- }
- return NO;
- }
- - (BOOL) animationEnded
- {
- if (loop_method == LOOP_NONE &&
- frame+1 == (int)[anim numFrames] &&
- frame_tics == 0)
- return YES;
- else
- return NO;
- }
- @end
- /*--------------------------------------------------------------*/
- /* SebAnimator is like a SebAnimatorManualWithDelay, but there is not
- * need to manually update the frame. Each time the sprite is drawn,
- * frame tics is decreased. When frame tics reaches zero, it will
- * move on to the next frame. Looping method is determined by the
- * animation. */
- @implementation SebAnimator
- - (void) updateFrame
- {
- [self nextFrame];
- }
- @end