First cut of multi-player support
[tennix.git] / animation.c
blobf78780e03aa43ca09b8edd6b042ad3f893f0414a
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 #include "credits.h"
34 Animation* animation_new()
36 Animation* animation = (Animation*)calloc(1, sizeof(Animation));
37 assert(animation != NULL);
38 return animation;
41 Animation* animation_append(Animation* animation, AnimationPart* part)
43 if (part->end > animation->duration) {
44 animation->duration = part->end;
47 if (animation->head == NULL) {
48 /* insert into empty list */
49 part->next = NULL;
50 part->prev = NULL;
51 animation->head = part;
52 animation->tail = part;
53 } else {
54 /* insert into non-empty list */
55 part->prev = animation->tail;
56 part->next = NULL;
57 animation->tail->next = part;
58 animation->tail = part;
61 return animation;
64 void animation_free(Animation* animation)
66 AnimationPart* part;
67 AnimationPart* next;
69 part = animation->head;
70 while (part != NULL) {
71 next = part->next;
72 animation_part_free(part);
73 part = next;
76 free(animation);
79 AnimationState* animation_state_new(Animation* animation)
81 AnimationState* state = (AnimationState*)calloc(1, sizeof(AnimationState));
82 assert(state != NULL);
84 state->animation = animation;
85 state->started = SDL_GetTicks();
86 state->ending = state->started + animation->duration;
88 return state;
91 void animation_state_run(AnimationState* state, int interruptible)
93 AnimationPart* p;
94 SDL_Event e;
96 clear_screen();
97 store_screen();
98 while (animation_state_update(state)) {
99 if (interruptible) {
100 while (SDL_PollEvent(&e)) {
101 if (e.type == SDL_KEYDOWN || e.type == SDL_QUIT) {
102 return;
106 p = state->animation->head;
107 while (p != NULL) {
108 animation_part_display(p, state);
109 p = p->next;
111 updatescr();
115 int animation_state_update(AnimationState* state)
117 assert(state != NULL);
119 state->current = SDL_GetTicks();
121 return state->current < state->ending;
124 void animation_state_free(AnimationState* state)
126 free(state);
129 AnimationPart* animation_part_new_from_surface(Uint32 start, Uint32 end,
130 unsigned int effects, int x, int y, int zindex, unsigned int gravity,
131 SDL_Surface* surface, unsigned char free_surface, int pos, int count)
133 AnimationPart* part = (AnimationPart*)calloc(1, sizeof(AnimationPart));
134 assert(part != NULL);
136 part->start = start;
137 part->end = end;
138 part->effects = effects;
140 part->x = x;
141 part->y = y;
142 part->zindex = zindex;
144 part->gravity = gravity;
146 part->surface = surface;
147 part->free_surface = free_surface;
148 part->pos = pos;
149 part->count = count;
151 return part;
154 AnimationPart* animation_part_new_text(Uint32 start, Uint32 end,
155 unsigned int effects, int x, int y, int zindex, unsigned int gravity,
156 font_id id, const char* text, Uint8 r, Uint8 g, Uint8 b)
158 return animation_part_new_from_surface(
159 start,
160 end,
161 effects,
164 zindex,
165 gravity,
166 font_render_surface(id, text, r, g, b),
173 void animation_part_display(AnimationPart* part, AnimationState* state)
175 Uint32 start = state->started + part->start;
176 Uint32 end = state->started + part->end;
177 Uint32 x, y;
178 float p;
179 SDL_Surface* surface;
181 if (state->current < start || state->current > end) {
182 /* this part has had it's time (or is yet to have it ;) */
183 return;
186 surface = part->surface;
187 p = (float)(state->current - start)/(float)(end - start);
189 if (part->effects & ANIMATION_ZOOM_2X) {
190 surface = rotozoom_surface(surface, 0.0, p+1);
193 switch (part->gravity) {
194 case GRAVITY_CENTER_UPPERHALF:
195 x = (WIDTH - surface->w)/2 + part->x;
196 y = HEIGHT/2 - surface->h + part->y;
197 break;
198 case GRAVITY_CENTER_BOTTOMHALF:
199 x = (WIDTH - surface->w)/2 + part->x;
200 y = HEIGHT/2 + part->y;
201 break;
202 case GRAVITY_CENTER_SCREEN:
203 x = (WIDTH - surface->w)/2 + part->x;
204 y = (HEIGHT - surface->h)/2 + part->y;
205 break;
206 case GRAVITY_TOP:
207 x = (WIDTH - surface->w)/2 + part->x;
208 y = part->y;
209 break;
210 case GRAVITY_TOPLEFT:
211 /* fall-through to default */
212 default:
213 x = part->x;
214 y = part->y;
215 break;
218 if (part->effects & ANIMATION_FROM_BOTTOM) {
219 y = y * p + (HEIGHT-part->surface->h) * (1-p);
222 if (part->effects & ANIMATION_SLIDE_LEFT) {
223 x = x * p;
226 if (part->effects & ANIMATION_SLIDE_RIGHT) {
227 x = (WIDTH-surface->w) * (1.-p) + x * p;
230 blit_surface_simple(surface, x, y);
232 /* FIXME: fade in and out should be handled by blitting w/ alpha value */
233 if (part->effects & ANIMATION_FADE_IN) {
234 if (p < ANIMATION_FADE_PART) {
235 rectangle_alpha(x, y, surface->w, surface->h, 0, 0, 0,
236 255*(1-(1./ANIMATION_FADE_PART)*p));
240 if (part->effects & ANIMATION_FADE_OUT) {
241 if (p > (1-ANIMATION_FADE_PART)) {
242 rectangle_alpha(x, y, surface->w, surface->h, 0, 0, 0,
243 255*((1./ANIMATION_FADE_PART)*(p-(1-ANIMATION_FADE_PART))));
247 if (part->effects & ANIMATION_ZOOM_2X) {
248 SDL_FreeSurface(surface);
252 void animation_part_free(AnimationPart* part)
254 /* free surface if necessary */
255 if (part->free_surface) {
256 SDL_FreeSurface(part->surface);
259 free(part);
263 Animation* create_intro()
265 Animation* intro = animation_new();
267 /* Just some weird demo of how the animations work */
268 animation_append(intro, animation_part_new_text(100, 4000, ANIMATION_FADE_IN | ANIMATION_FADE_OUT, 0, 0, 0, GRAVITY_CENTER_SCREEN, FONT_MEDIUM, "thpinfo.com presents", 255, 255, 255));
269 animation_append(intro, animation_part_new_from_surface(4000, 8000, ANIMATION_FADE_IN | ANIMATION_FADE_OUT | ANIMATION_ZOOM_2X, 0, 0, 0, GRAVITY_CENTER_SCREEN, get_surface(GR_TENNIXLOGO), 0, 0, 1));
271 return intro;
274 Animation* create_credits()
276 int pos = 0;
277 Animation* credits = animation_new();
278 while (credits_text[pos] != NULL) {
279 animation_append(credits,
280 animation_part_new_text(100+pos*CREDITS_OFFSET,
281 100+pos*CREDITS_OFFSET + CREDITS_DURATION,
282 ANIMATION_FADE_IN | ANIMATION_FADE_OUT | ANIMATION_FROM_BOTTOM,
283 0, 0, 0,
284 GRAVITY_TOP,
285 FONT_MEDIUM,
286 credits_text[pos],
287 255, 255, 255));
288 pos++;
290 return credits;