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