1 /*
2 BStone: A Source port of
3 Blake Stone: Aliens of Gold and Blake Stone: Planet Strike
4 
5 Copyright (c) 1992-2013 Apogee Entertainment, LLC
6 Copyright (c) 2013-2015 Boris I. Bendovsky (bibendovsky@hotmail.com)
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the
20 Free Software Foundation, Inc.,
21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 */
23 
24 
25 #include "3d_def.h"
26 #include "an_codes.h"
27 
28 
29 bool IN_CheckAck();
30 void VH_UpdateScreen();
31 
32 void VL_LatchToScreen(
33     int source,
34     int width,
35     int height,
36     int x,
37     int y);
38 
39 
40 //
41 // Various types for various purposes...
42 //
43 
44 enum FADES {
45     FADE_NONE,
46     FADE_SET,
47     FADE_IN,
48     FADE_OUT,
49     FADE_IN_FRAME,
50     FADE_OUT_FRAME
51 }; // FADES
52 
53 
54 enum MOVIE_FLAGS {
55     MV_NONE,
56     MV_FILL,
57     MV_SKIP,
58     MV_READ
59 }; // MOVIE_FLAGS
60 
61 
62 // ===========================================================================
63 //
64 // VARIABLES
65 //
66 // ===========================================================================
67 
68 
69 // Movie File variables
70 bstone::FileStream Movie_FHandle;
71 
72 // Fade Variables
73 FADES fade_flags, fi_type, fo_type;
74 uint8_t fi_rate, fo_rate;
75 
76 // MOVIE_GetFrame & MOVIE_LoadBuffer variables
77 char* MovieBuffer; // Ptr to Allocated Memory for Buffer
78 uint32_t BufferLen; // Len of MovieBuffer (Ammount of RAM allocated)
79 uint32_t PageLen; // Len of data loaded into MovieBuffer
80 char* BufferPtr; // Ptr to next frame in MovieBuffer
81 char* NextPtr; // Ptr Ofs to next frame after BufferOfs
82 
83 bool MorePagesAvail; // More Pages avail on disk?
84 
85 MOVIE_FLAGS movie_flag;
86 bool ExitMovie;
87 bool EverFaded;
88 int32_t seek_pos;
89 int8_t movie_reps;
90 ControlInfo ci;
91 const void* movie_palette;
92 
93 
94 //
95 // MOVIE Definations for external movies
96 //
97 // NOTE: This list is ordered according to mv_???? enum list.
98 //
99 
100 Movies movies = {
101     { "IANIM.", 1, 3, 0, 0, 200, nullptr, }, // mv_intro
102     { "EANIM.", 1, 3, 0, 0, 200, nullptr, }, // mv_final
103     { "SANIM.", 1, 3, 0, 0, 200, nullptr, }, // mv_final2
104     { "GANIM.", 1, 3, 0, 0, 200, nullptr, }, // mv_final3
105 };
106 
107 
108 // ===========================================================================
109 //
110 // LOCAL PROTO TYPES
111 //
112 // ===========================================================================
113 
114 void JM_MemToScreen();
115 
116 void JM_ClearVGAScreen(
117     uint8_t fill);
118 
119 void FlipPages();
120 bool CheckFading();
121 bool CheckPostFade();
122 
123 
124 // ===========================================================================
125 //
126 // FUNCTIONS
127 //
128 // ===========================================================================
129 
130 
131 // Inits all the internal routines for the Movie Presenter
SetupMovie(MovieStuff_t * MovieStuff)132 void SetupMovie(
133     MovieStuff_t* MovieStuff)
134 {
135     movie_reps = MovieStuff->rep;
136     movie_flag = MV_FILL;
137     LastScan = ScanCode::sc_none;
138     PageLen = 0;
139     MorePagesAvail = true;
140     ExitMovie = false;
141     EverFaded = false;
142     IN_ClearKeysDown();
143 
144     movie_palette = MovieStuff->palette;
145 
146     ::JM_VGALinearFill(
147         0,
148         ::vga_ref_width * ::vga_ref_height,
149         0);
150 
151     VL_FillPalette(0, 0, 0);
152     LastScan = ScanCode::sc_none;
153 
154     // Find out how much memory we have to work with..
155 
156     BufferLen = 65535;
157     BufferLen -= 65535; // HACK: Save some room for sounds - This is cludgey
158 
159     if (BufferLen < 64256) {
160         BufferLen = 64256;
161     }
162 
163     MovieBuffer = new char[BufferLen];
164 }
165 
ShutdownMovie()166 void ShutdownMovie()
167 {
168     delete [] MovieBuffer;
169     MovieBuffer = nullptr;
170 
171     Movie_FHandle.close();
172 }
173 
174 // ---------------------------------------------------------------------------
175 // void JM_DrawBlock()
176 //
177 // dest_offset = Correct offset value for memory location for Paged/Latch mem
178 //
179 // byte_offset = Offset for the image to be drawn - This address is NOT
180 // a calculated Paged/Latch value but a byte offset in
181 // conventional memory.
182 //
183 // source = Source image of graphic to be blasted to latch memory.  This
184 //                                        pic is NOT 'munged'
185 //
186 // length = length of the source image in bytes
187 // ---------------------------------------------------------------------------
JM_DrawBlock(int dest_offset,int byte_offset,const char * source,int length)188 void JM_DrawBlock(
189     int dest_offset,
190     int byte_offset,
191     const char* source,
192     int length)
193 {
194     static_cast<void>(dest_offset);
195 
196     int x = byte_offset % ::vga_ref_width;
197     int y = byte_offset / ::vga_ref_width;
198 
199     for (int i = 0; i < length; ++i) {
200         VL_Plot(x, y, static_cast<uint8_t>(source[i]));
201 
202         ++x;
203 
204         if (x == ::vga_ref_width) {
205             x = 0;
206             ++y;
207         }
208     }
209 }
210 
211 // ---------------------------------------------------------------------------
212 // MOVIE_ShowFrame() - Shows an animation frame
213 //
214 // PARAMETERS: pointer to animpic
215 // ---------------------------------------------------------------------------
MOVIE_ShowFrame(char * inpic)216 void MOVIE_ShowFrame(
217     char* inpic)
218 {
219     anim_chunk* ah;
220 
221     if (!inpic) {
222         return;
223     }
224 
225     for ( ; ; ) {
226         ah = (anim_chunk*)inpic;
227 
228         if (ah->opt == 0) {
229             break;
230         }
231 
232         inpic += sizeof(anim_chunk);
233         JM_DrawBlock(bufferofs, ah->offset, (char*)inpic, ah->length);
234         inpic += ah->length;
235     }
236 }
237 
238 // ---------------------------------------------------------------------------
239 // MOVIE_LoadBuffer() - Loads the RAM Buffer full of graphics...
240 //
241 // RETURNS:  true - MORE Pages avail on disk..
242 //          false   - LAST Pages from disk..
243 //
244 // PageLen = Length of data loaded into buffer
245 //
246 // ---------------------------------------------------------------------------
MOVIE_LoadBuffer()247 bool MOVIE_LoadBuffer()
248 {
249     anim_frame blk;
250     long chunkstart;
251     char* frame;
252     uint32_t free_space;
253 
254     NextPtr = BufferPtr = frame = MovieBuffer;
255     free_space = BufferLen;
256 
257     while (free_space) {
258         chunkstart = static_cast<long>(Movie_FHandle.get_position());
259 
260         if (Movie_FHandle.read(
261                 &blk.code,
262                 sizeof(blk.code)) != sizeof(blk.code))
263         {
264             ::Quit("Animation file is corrupt or truncated.");
265         }
266 
267         if (Movie_FHandle.read(
268                 &blk.block_num,
269                 sizeof(blk.block_num)) != sizeof(blk.block_num))
270         {
271             ::Quit("Animation file is corrupt or truncated.");
272         }
273 
274         if (Movie_FHandle.read(
275                 &blk.recsize,
276                 sizeof(blk.recsize)) != sizeof(blk.recsize))
277         {
278             ::Quit("Animation file is corrupt or truncated.");
279         }
280 
281         if (blk.code == AN_END_OF_ANIM) {
282             return false;
283         }
284 
285         if (free_space >= (blk.recsize + sizeof(anim_frame))) {
286             memcpy(frame, &blk, sizeof(anim_frame));
287 
288             free_space -= sizeof(anim_frame);
289             frame += sizeof(anim_frame);
290             PageLen += sizeof(anim_frame);
291 
292             if (Movie_FHandle.read(frame, blk.recsize) != blk.recsize) {
293                 ::Quit("Animation file is corrupt or truncated.");
294             }
295 
296             free_space -= blk.recsize;
297             frame += blk.recsize;
298             PageLen += blk.recsize;
299         } else {
300             Movie_FHandle.set_position(chunkstart);
301             free_space = 0;
302         }
303     }
304 
305     return true;
306 }
307 
308 // ---------------------------------------------------------------------------
309 // MOVIE_GetFrame() - Returns pointer to next Block/Screen of animation
310 //
311 // PURPOSE: This function "Buffers" the movie presentation from allocated
312 //      ram.  It loads and buffers incomming frames of animation..
313 //
314 // RETURNS:  0 - Ok
315 //          1 - End Of File
316 // ---------------------------------------------------------------------------
MOVIE_GetFrame()317 int16_t MOVIE_GetFrame()
318 {
319     anim_frame blk;
320 
321     if (PageLen == 0) {
322         if (MorePagesAvail) {
323             MorePagesAvail = MOVIE_LoadBuffer();
324         } else {
325             return 1;
326         }
327     }
328 
329     BufferPtr = NextPtr;
330     memcpy(&blk, BufferPtr, sizeof(anim_frame));
331     PageLen -= sizeof(anim_frame);
332     PageLen -= blk.recsize;
333     NextPtr = BufferPtr + sizeof(anim_frame) + blk.recsize;
334     return 0;
335 }
336 
337 // ---------------------------------------------------------------------------
338 // MOVIE_HandlePage() - This handles the current page of data from the
339 //      ram buffer...
340 //
341 // PURPOSE: Process current Page of anim.
342 //
343 //
344 // RETURNS:
345 //
346 // ---------------------------------------------------------------------------
MOVIE_HandlePage(MovieStuff_t * MovieStuff)347 void MOVIE_HandlePage(
348     MovieStuff_t* MovieStuff)
349 {
350     anim_frame blk;
351     char* frame;
352 
353     memcpy(&blk, BufferPtr, sizeof(anim_frame));
354     BufferPtr += sizeof(anim_frame);
355     frame = BufferPtr;
356 
357     IN_ReadControl(0, &ci);
358 
359     switch (blk.code) {
360 
361     case AN_SOUND: // Sound Chunk
362     {
363         uint16_t sound_chunk;
364         sound_chunk = *(uint16_t*)frame;
365 
366         ::sd_play_player_sound(
367             sound_chunk,
368             bstone::AC_ITEM);
369 
370         BufferPtr += blk.recsize;
371     }
372     break;
373 
374     case AN_FADE_IN_FRAME: // Fade In Page
375         VL_FadeIn(0, 255, (const uint8_t*)movie_palette, 30);
376         fade_flags = FADE_NONE;
377         EverFaded = true;
378         screenfaded = false;
379         break;
380 
381     case AN_FADE_OUT_FRAME: // Fade Out Page
382         VW_FadeOut();
383         screenfaded = true;
384         fade_flags = FADE_NONE;
385         break;
386 
387     case AN_PAUSE: // Pause
388     {
389         uint16_t vbls;
390         vbls = *(uint16_t*)frame;
391         IN_UserInput(vbls);
392         BufferPtr += blk.recsize;
393 
394         // BBi
395         ::IN_ClearKeysDown();
396         ci = {};
397         // BBi
398     }
399     break;
400 
401 
402 
403     // -------------------------------------------
404     //
405     //
406     // -------------------------------------------
407 
408     case AN_PAGE: // Graphics Chunk
409         if (movie_flag == MV_FILL)
410         {
411             // First page comming in.. Fill screen with fill color...
412             //
413             movie_flag = MV_NONE; // Set READ flag to skip the first frame on an anim repeat
414 
415             ::JM_VGALinearFill(
416                 0,
417                 ::vga_ref_width * ::vga_ref_height,
418                 *frame);
419 
420             frame++;
421         }
422 // BBi No need without page flipping
423 #if 0
424         else
425         {
426             VL_LatchToScreen(
427                 PAGE1START + ylookup[MovieStuff->start_line],
428                 ::vga_ref_width / 4,
429                 MovieStuff->end_line - MovieStuff->start_line,
430                 0,
431                 MovieStuff->start_line);
432         }
433 #endif
434 
435         MOVIE_ShowFrame(frame);
436 
437         FlipPages();
438 
439         if (TimeCount < static_cast<uint32_t>(MovieStuff->ticdelay)) {
440             const auto min_wait_time = 0;
441             const auto max_wait_time = 2 * TickBase; // 2 seconds
442 
443             auto wait_time =
444                 MovieStuff->ticdelay - static_cast<int>(TimeCount);
445 
446             if (wait_time < min_wait_time) {
447                 wait_time = min_wait_time;
448             }
449 
450             if (wait_time > max_wait_time) {
451                 wait_time = max_wait_time;
452             }
453 
454             if (wait_time > 0) {
455                 wait_time *= 1000;
456                 wait_time /= TickBase;
457                 ::sys_sleep_for(wait_time);
458             }
459         } else {
460             ::sys_sleep_for(1000 / TickBase);
461         }
462 
463         TimeCount = 0;
464 
465         if ((!screenfaded) && (ci.button0 || ci.button1 || LastScan != ScanCode::sc_none)) {
466             ExitMovie = true;
467             if (EverFaded) { // This needs to be a passed flag...
468                 VW_FadeOut();
469                 screenfaded = true;
470             }
471         }
472         break;
473 
474     case AN_END_OF_ANIM:
475         ExitMovie = true;
476         break;
477 
478     default:
479         ::Quit("Unrecognized anim code.");
480         break;
481     }
482 }
483 
484 // ---------------------------------------------------------------------------
485 // MOVIE_Play() - Playes an Animation
486 //
487 // RETURNS: true  - Movie File was found and "played"
488 //      false - Movie file was NOT found!
489 // ---------------------------------------------------------------------------
MOVIE_Play(MovieStuff_t * MovieStuff)490 bool MOVIE_Play(
491     MovieStuff_t* MovieStuff)
492 {
493     // Init our Movie Stuff...
494     //
495 
496     SetupMovie(MovieStuff);
497 
498     // Start the anim process
499     //
500 
501     Movie_FHandle.open(::data_dir + MovieStuff->file_name);
502     if (!Movie_FHandle.is_open()) {
503         return false;
504     }
505 
506     while (movie_reps && (!ExitMovie)) {
507         for (; !ExitMovie; ) {
508             if (MOVIE_GetFrame()) {
509                 break;
510             }
511 
512             MOVIE_HandlePage(MovieStuff);
513         }
514 
515         movie_reps--;
516         movie_flag = MV_SKIP;
517     }
518 
519     ShutdownMovie();
520 
521     return true;
522 }
523 
FlipPages()524 void FlipPages()
525 {
526     ::VL_RefreshScreen();
527 }
528