New input selection UI + Mouse support, updated TODO list
[tennix.git] / animation.c
blob7248c032790f9203e0aad0298b51bb9098431a6d
2 /**
4 * Tennix! SDL Port
5 * Copyright (C) 2003, 2007, 2008, 2009 Thomas Perl <thp@thpinfo.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20 * MA 02110-1301, USA.
22 **/
25 #include <stdlib.h>
26 #include <assert.h>
28 #include "tennix.h"
29 #include "graphics.h"
30 #include "animation.h"
32 Animation* animation_new()
34 Animation* animation = (Animation*)calloc(1, sizeof(Animation));
35 assert(animation != NULL);
36 return animation;
39 Animation* animation_append(Animation* animation, AnimationPart* part)
41 if (part->end > animation->duration) {
42 animation->duration = part->end;
45 if (animation->head == NULL) {
46 /* insert into empty list */
47 part->next = NULL;
48 part->prev = NULL;
49 animation->head = part;
50 animation->tail = part;
51 } else {
52 /* insert into non-empty list */
53 part->prev = animation->tail;
54 part->next = NULL;
55 animation->tail->next = part;
56 animation->tail = part;
59 return animation;
62 void animation_free(Animation* animation)
64 AnimationPart* part;
65 AnimationPart* next;
67 part = animation->head;
68 while (part != NULL) {
69 next = part->next;
70 animation_part_free(part);
71 part = next;
74 free(animation);
77 AnimationState* animation_state_new(Animation* animation)
79 AnimationState* state = (AnimationState*)calloc(1, sizeof(AnimationState));
80 assert(state != NULL);
82 state->animation = animation;
83 state->started = SDL_GetTicks();
84 state->ending = state->started + animation->duration;
86 return state;
89 void animation_state_run(AnimationState* state, int interruptible)
91 AnimationPart* p;
92 SDL_Event e;
94 clear_screen();
95 store_screen();
96 while (animation_state_update(state)) {
97 if (interruptible) {
98 while (SDL_PollEvent(&e)) {
99 if (e.type == SDL_KEYDOWN || e.type == SDL_MOUSEBUTTONDOWN || e.type == SDL_QUIT) {
100 return;
104 p = state->animation->head;
105 while (p != NULL) {
106 animation_part_display(p, state);
107 p = p->next;
109 updatescr();
113 int animation_state_update(AnimationState* state)
115 assert(state != NULL);
117 state->current = SDL_GetTicks();
119 return state->current < state->ending;
122 void animation_state_free(AnimationState* state)
124 free(state);
127 AnimationPart* animation_part_new_from_surface(Uint32 start, Uint32 end,
128 unsigned int effects, int x, int y, int zindex, unsigned int gravity,
129 SDL_Surface* surface, unsigned char free_surface, int pos, int count)
131 AnimationPart* part = (AnimationPart*)calloc(1, sizeof(AnimationPart));
132 assert(part != NULL);
134 part->start = start;
135 part->end = end;
136 part->effects = effects;
138 part->x = x;
139 part->y = y;
140 part->zindex = zindex;
142 part->gravity = gravity;
144 part->surface = surface;
145 part->free_surface = free_surface;
146 part->pos = pos;
147 part->count = count;
149 return part;
152 AnimationPart* animation_part_new_text(Uint32 start, Uint32 end,
153 unsigned int effects, int x, int y, int zindex, unsigned int gravity,
154 font_id id, const char* text, Uint8 r, Uint8 g, Uint8 b)
156 return animation_part_new_from_surface(
157 start,
158 end,
159 effects,
162 zindex,
163 gravity,
164 font_render_surface(id, text, r, g, b),
171 void animation_part_display(AnimationPart* part, AnimationState* state)
173 Uint32 start = state->started + part->start;
174 Uint32 end = state->started + part->end;
175 Uint32 x, y;
176 float p, pe;
177 SDL_Surface* surface;
179 if (state->current < start || state->current > end) {
180 /* this part has had it's time (or is yet to have it ;) */
181 return;
184 surface = part->surface;
185 p = (float)(state->current - start)/(float)(end - start);
187 if (part->effects & ANIMATION_ZOOM_2X) {
188 surface = rotozoom_surface(surface, 0.0, p+1);
191 switch (part->gravity) {
192 case GRAVITY_CENTER_UPPERHALF:
193 x = (WIDTH - surface->w)/2 + part->x;
194 y = HEIGHT/2 - surface->h + part->y;
195 break;
196 case GRAVITY_CENTER_BOTTOMHALF:
197 x = (WIDTH - surface->w)/2 + part->x;
198 y = HEIGHT/2 + part->y;
199 break;
200 case GRAVITY_CENTER_SCREEN:
201 x = (WIDTH - surface->w)/2 + part->x;
202 y = (HEIGHT - surface->h)/2 + part->y;
203 break;
204 case GRAVITY_TOPLEFT:
205 /* fall-through to default */
206 default:
207 x = part->x;
208 y = part->y;
209 break;
212 if (part->effects & ANIMATION_FROM_BOTTOM) {
213 y = y * p + (HEIGHT-part->surface->h) * (1-p);
216 if (part->effects & ANIMATION_SLIDE_LEFT) {
217 x = x * p;
220 if (part->effects & ANIMATION_SLIDE_RIGHT) {
221 x = (WIDTH-surface->w) * (1.-p) + x * pe;
224 blit_surface_simple(surface, x, y);
226 /* FIXME: fade in and out should be handled by blitting w/ alpha value */
227 if (part->effects & ANIMATION_FADE_IN) {
228 if (p < ANIMATION_FADE_PART) {
229 rectangle_alpha(x, y, surface->w, surface->h, 0, 0, 0,
230 255*(1-(1./ANIMATION_FADE_PART)*p));
234 if (part->effects & ANIMATION_FADE_OUT) {
235 if (p > (1-ANIMATION_FADE_PART)) {
236 rectangle_alpha(x, y, surface->w, surface->h, 0, 0, 0,
237 255*((1./ANIMATION_FADE_PART)*(p-(1-ANIMATION_FADE_PART))));
241 if (part->effects & ANIMATION_ZOOM_2X) {
242 SDL_FreeSurface(surface);
246 void animation_part_free(AnimationPart* part)
248 /* free surface if necessary */
249 if (part->free_surface) {
250 SDL_FreeSurface(part->surface);
253 free(part);
257 Animation* create_intro()
259 Animation* intro = animation_new();
261 /* Just some weird demo of how the animations work */
262 animation_append(intro, animation_part_new_text(100, 4000, ANIMATION_FADE_IN | ANIMATION_FADE_OUT | ANIMATION_SLIDE_LEFT, 0, 0, 0, GRAVITY_CENTER_UPPERHALF, FONT_MEDIUM, "Deine Eltern sind", 255, 255, 255));
263 animation_append(intro, animation_part_new_text(1000, 4500, ANIMATION_FADE_IN | ANIMATION_FADE_OUT | ANIMATION_SLIDE_RIGHT, 0, 0, 0, GRAVITY_CENTER_BOTTOMHALF, FONT_MEDIUM, "auf einem Tennixturnier", 255, 255, 255));
264 animation_append(intro, animation_part_new_from_surface(2000, 5500, ANIMATION_FADE_IN | ANIMATION_FADE_OUT | ANIMATION_FROM_BOTTOM | ANIMATION_ZOOM_2X, 0, 0, 0, GRAVITY_CENTER_SCREEN, get_surface(GR_TENNIXLOGO), 0, 0, 1));
266 return intro;