rnd-20020330-4-src
[rocksndiamonds.git] / src / libgame / toons.c
1 /***********************************************************
2 * Artsoft Retro-Game Library                               *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * toons.c                                                  *
12 ***********************************************************/
13
14 #include "toons.h"
15 #include "misc.h"
16
17
18 /* values for toon animation */
19 #define ANIM_START      0
20 #define ANIM_CONTINUE   1
21 #define ANIM_STOP       2
22
23
24 static struct ToonScreenInfo screen_info;
25
26 void InitToonScreen(Bitmap **toon_bitmap_array,
27                     Bitmap *save_buffer,
28                     void (*update_function)(void),
29                     void (*prepare_backbuffer_function)(void),
30                     boolean (*redraw_needed_function)(void),
31                     struct ToonInfo *toons, int num_toons,
32                     int startx, int starty,
33                     int width, int height)
34 {
35   screen_info.toon_bitmap_array = toon_bitmap_array;
36   screen_info.save_buffer = save_buffer;
37   screen_info.update_function = update_function;
38   screen_info.prepare_backbuffer_function = prepare_backbuffer_function;
39   screen_info.redraw_needed_function = redraw_needed_function;
40   screen_info.toons = toons;
41   screen_info.num_toons = num_toons;
42   screen_info.startx = startx;
43   screen_info.starty = starty;
44   screen_info.width = width;
45   screen_info.height = height;
46 }
47
48 void DrawAnim(Bitmap *toon_bitmap, GC toon_clip_gc,
49               int src_x, int src_y, int width, int height,
50               int dest_x, int dest_y, int pad_x, int pad_y)
51 {
52   int buf_x = DOOR_GFX_PAGEX3, buf_y = DOOR_GFX_PAGEY1;
53
54 #if 1
55   /* special method to avoid flickering interference with BackToFront() */
56   BlitBitmap(backbuffer, screen_info.save_buffer, dest_x-pad_x, dest_y-pad_y,
57              width+2*pad_x, height+2*pad_y, buf_x, buf_y);
58   SetClipOrigin(toon_bitmap, toon_clip_gc, dest_x-src_x, dest_y-src_y);
59   BlitBitmapMasked(toon_bitmap, backbuffer,
60                    src_x, src_y, width, height, dest_x, dest_y);
61   BlitBitmap(backbuffer, window, dest_x-pad_x, dest_y-pad_y,
62              width+2*pad_x, height+2*pad_y, dest_x-pad_x, dest_y-pad_y);
63
64   screen_info.update_function();
65
66   BlitBitmap(screen_info.save_buffer, backbuffer, buf_x, buf_y,
67             width+2*pad_x, height+2*pad_y, dest_x-pad_x, dest_y-pad_y);
68 #else
69   /* normal method, causing flickering interference with BackToFront() */
70   BlitBitmap(backbuffer, screen_info.save_buffer, dest_x-pad_x, dest_y-pad_y,
71              width+2*pad_x, height+2*pad_y, buf_x, buf_y);
72   SetClipOrigin(toon_bitmap,toon_clip_gc, buf_x-src_x+pad_x,buf_y-src_y+pad_y);
73   BlitBitmapMasked(toon_bitmap, screen_info.save_buffer,
74                    src_x, src_y, width, height, buf_x+pad_x, buf_y+pad_y);
75   BlitBitmap(screen_info.save_buffer, window, buf_x, buf_y,
76              width+2*pad_x, height+2*pad_y, dest_x-pad_x, dest_y-pad_y);
77 #endif
78
79   FlushDisplay();
80 }
81
82 boolean AnimateToon(int toon_nr, boolean restart)
83 {
84   static int pos_x = 0, pos_y = 0;
85   static int delta_x = 0, delta_y = 0;
86   static int frame = 0, frame_step = 1;
87   static boolean horiz_move, vert_move;
88   static unsigned long anim_delay = 0;
89   static unsigned long anim_delay_value = 0;
90   static int width,height;
91   static int pad_x,pad_y;
92   static int cut_x,cut_y;
93   static int src_x, src_y;
94   static int dest_x, dest_y;
95
96   struct ToonInfo *anim = &screen_info.toons[toon_nr];
97   int bitmap_nr = screen_info.toons[toon_nr].bitmap_nr;
98   Bitmap *anim_bitmap = screen_info.toon_bitmap_array[bitmap_nr];
99   GC anim_clip_gc = anim_bitmap->stored_clip_gc;
100
101   if (restart)
102   {
103     horiz_move = (anim->direction & (ANIMDIR_LEFT | ANIMDIR_RIGHT));
104     vert_move = (anim->direction & (ANIMDIR_UP | ANIMDIR_DOWN));
105     anim_delay_value = 1000/anim->frames_per_second;
106     frame = 0;
107
108     if (horiz_move)
109     {
110       if (anim->position == ANIMPOS_UP)
111         pos_y = 0;
112       else if (anim->position == ANIMPOS_DOWN)
113         pos_y = screen_info.height - anim->height;
114       else if (anim->position == ANIMPOS_UPPER)
115         pos_y = SimpleRND((screen_info.height - anim->height) / 2);
116       else
117         pos_y = SimpleRND(screen_info.height - anim->height);
118
119       if (anim->direction == ANIMDIR_RIGHT)
120       {
121         delta_x = anim->stepsize;
122         pos_x = -anim->width + delta_x;
123       }
124       else
125       {
126         delta_x = -anim->stepsize;
127         pos_x = screen_info.width + delta_x;
128       }
129       delta_y = 0;
130     }
131     else
132     {
133       if (anim->position == ANIMPOS_LEFT)
134         pos_x = 0;
135       else if (anim->position == ANIMPOS_RIGHT)
136         pos_x = screen_info.width - anim->width;
137       else
138         pos_x = SimpleRND(screen_info.width - anim->width);
139
140       if (anim->direction == ANIMDIR_DOWN)
141       {
142         delta_y = anim->stepsize;
143         pos_y = -anim->height + delta_y;
144       }
145       else
146       {
147         delta_y = -anim->stepsize;
148         pos_y = screen_info.width + delta_y;
149       }
150       delta_x = 0;
151     }
152   }
153
154   if (pos_x <= -anim->width        - anim->stepsize ||
155       pos_x >=  screen_info.width  + anim->stepsize ||
156       pos_y <= -anim->height       - anim->stepsize ||
157       pos_y >=  screen_info.height + anim->stepsize)
158     return TRUE;
159
160   if (!DelayReached(&anim_delay, anim_delay_value))
161   {
162     if (screen_info.redraw_needed_function() && !restart)
163       DrawAnim(anim_bitmap, anim_clip_gc,
164                src_x + cut_x, src_y + cut_y,
165                width, height,
166                screen_info.startx + dest_x,
167                screen_info.starty + dest_y,
168                pad_x, pad_y);
169
170     return FALSE;
171   }
172
173   if (pos_x < -anim->width)
174     pos_x = -anim->width;
175   else if (pos_x > screen_info.width)
176     pos_x = screen_info.width;
177   if (pos_y < -anim->height)
178     pos_y = -anim->height;
179   else if (pos_y > screen_info.height)
180     pos_y = screen_info.height;
181
182   pad_x = (horiz_move ? anim->stepsize : 0);
183   pad_y = (vert_move  ? anim->stepsize : 0);
184   src_x = anim->src_x + frame * anim->width;
185   src_y = anim->src_y;
186   dest_x = pos_x;
187   dest_y = pos_y;
188   cut_x = cut_y = 0;
189   width  = anim->width;
190   height = anim->height;
191
192   if (pos_x<0)
193   {
194     dest_x = 0;
195     width += pos_x;
196     cut_x = -pos_x;
197   }
198   else if (pos_x > screen_info.width - anim->width)
199     width -= (pos_x - (screen_info.width - anim->width));
200
201   if (pos_y<0)
202   {
203     dest_y = 0;
204     height += pos_y;
205     cut_y = -pos_y;
206   }
207   else if (pos_y > screen_info.height - anim->height)
208     height -= (pos_y - (screen_info.height - anim->height));
209
210   DrawAnim(anim_bitmap, anim_clip_gc,
211            src_x + cut_x, src_y + cut_y,
212            width, height,
213            screen_info.startx + dest_x,
214            screen_info.starty + dest_y,
215            pad_x, pad_y);
216
217   pos_x += delta_x;
218   pos_y += delta_y;
219   frame += frame_step;
220
221   if (frame<0 || frame>=anim->frames)
222   {
223     if (anim->pingpong)
224     {
225       frame_step *= -1;
226       frame = (frame<0 ? 1 : anim->frames-2);
227     }
228     else
229       frame = (frame<0 ? anim->frames-1 : 0);
230   }
231
232   return FALSE;
233 }
234
235 void HandleAnimation(int mode)
236 {
237   static unsigned long animstart_delay = -1;
238   static unsigned long animstart_delay_value = 0;
239   static boolean anim_restart = TRUE;
240   static boolean reset_delay = TRUE;
241   static int toon_nr = 0;
242   int draw_mode;
243
244   if (!setup.toons)
245     return;
246
247   switch(mode)
248   {
249     case ANIM_START:
250       screen_info.prepare_backbuffer_function();
251       anim_restart = TRUE;
252       reset_delay = TRUE;
253
254       return;
255
256     case ANIM_CONTINUE:
257       break;
258
259     case ANIM_STOP:
260       redraw_mask |= (REDRAW_FIELD | REDRAW_FROM_BACKBUFFER);
261
262       /* Redraw background even when in direct drawing mode */
263       draw_mode = setup.direct_draw;
264       setup.direct_draw = FALSE;
265       screen_info.update_function();
266       setup.direct_draw = draw_mode;
267
268       return;
269
270     default:
271       break;
272   }
273
274   if (reset_delay)
275   {
276     animstart_delay = Counter();
277     animstart_delay_value = SimpleRND(3000);
278     reset_delay = FALSE;
279   }
280
281   if (anim_restart)
282   {
283     if (!DelayReached(&animstart_delay, animstart_delay_value))
284       return;
285
286     toon_nr = SimpleRND(screen_info.num_toons);
287   }
288
289   anim_restart = reset_delay = AnimateToon(toon_nr,anim_restart);
290 }
291
292 void InitAnimation()
293 {
294   HandleAnimation(ANIM_START);
295 }
296
297 void StopAnimation()
298 {
299   HandleAnimation(ANIM_STOP);
300 }
301
302 void DoAnimation()
303 {
304   HandleAnimation(ANIM_CONTINUE);
305 }