1 /************************************************************************
2  *                                                                      *
3  *  FreeSynd - a remake of the classic Bullfrog game "Syndicate".       *
4  *                                                                      *
5  *   Copyright (C) 2005  Stuart Binge  <skbinge@gmail.com>              *
6  *   Copyright (C) 2005  Joost Peters  <joostp@users.sourceforge.net>   *
7  *   Copyright (C) 2006  Trent Waddington <qg@biodome.org>              *
8  *                                                                      *
9  *    This program is free software;  you can redistribute it and / or  *
10  *  modify it  under the  terms of the  GNU General  Public License as  *
11  *  published by the Free Software Foundation; either version 2 of the  *
12  *  License, or (at your option) any later version.                     *
13  *                                                                      *
14  *    This program is  distributed in the hope that it will be useful,  *
15  *  but WITHOUT  ANY WARRANTY;  without even  the implied  warranty of  *
16  *  MERCHANTABILITY  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  *
17  *  General Public License for more details.                            *
18  *                                                                      *
19  *    You can view the GNU  General Public License, online, at the GNU  *
20  *  project's  web  site;  see <http://www.gnu.org/licenses/gpl.html>.  *
21  *  The full text of the license is also included in the file COPYING.  *
22  *                                                                      *
23  ************************************************************************/
24 
25 #include <cstdio>
26 
27 #include "fliplayer.h"
28 #include "screen.h"
29 #include "utils/log.h"
30 #include "menus/menumanager.h"
31 
32 #if 0 // TMN: Data for playing samples during intro video. Hardcoded from intro.exe.
33 
34 //#include <pshpack1.h>
35 struct sample_timings {
36     int16 m0;
37     uint8 m1, m2, m3, m4, m5, m6;
38 };
39 //#include <poppack.h>
40 
41 const sample_timings g_rg_sample_offsets_and_timings[] = {
42     {   0, 0x4C, 0x12, 0x00, 0x00, 0x00 }, // read data from FLC (0x12     (18)     bytes)
43     {   1, 0x4C, 0xB2, 0xF2, 0x08, 0x00 }, // read data from FLC (0x08f2b2 (586418) bytes)
44     {   1, 0x45, 0x00, 0x00, 0x00, 0x00 }, // load "data/isnds-0.dat"
45     {   1, 0x41, 0x01, 0x00, 0x00, 0x00 }, // wait 1/100 seconds (1 = 10ms)
46     {   1, 0x53, 0x12, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x12
47     {  15, 0x54, 0x01, 0x00, 0x00, 0x00 }, // draw subtitle string, index
48     {  19, 0x41, 0x06, 0x00, 0x00, 0x00 }, // wait 1/100 seconds (6 = 60ms)
49     {  19, 0x4D, 0x00, 0x00, 0x00, 0x00 }, // start new sequence (sequence # 0)
50     {  34, 0x53, 0x01, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x01
51     {  39, 0x54, 0x00, 0x00, 0x00, 0x00 }, // clear subtitle string area
52     {  44, 0x54, 0x02, 0x00, 0x00, 0x00 }, // draw subtitle string, index
53     {  60, 0x53, 0x02, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x02
54     {  62, 0x54, 0x00, 0x00, 0x00, 0x00 }, // clear subtitle string area
55     {  67, 0x54, 0x03, 0x00, 0x00, 0x00 }, // draw subtitle string, index
56     {  85, 0x54, 0x00, 0x00, 0x00, 0x00 }, // clear subtitle string area
57     {  90, 0x54, 0x04, 0x00, 0x00, 0x00 }, // draw subtitle string, index
58     {  91, 0x41, 0x06, 0x00, 0x00, 0x00 }, // wait 1/100 seconds (6 = 60ms)
59     { 117, 0x54, 0x00, 0x00, 0x00, 0x00 }, // clear subtitle string area
60     { 119, 0x4C, 0xFA, 0xD6, 0x04, 0x00 }, // read data from FLC (0x04d6fa (317178) bytes)
61     { 119, 0x41, 0x06, 0x00, 0x00, 0x00 }, // wait 1/100 seconds (6 = 60ms)
62     { 121, 0x54, 0x05, 0x00, 0x00, 0x00 }, // draw subtitle string, index
63     { 135, 0x54, 0x00, 0x00, 0x00, 0x00 }, // clear subtitle string area
64     { 138, 0x54, 0x06, 0x00, 0x00, 0x00 }, // draw subtitle string, index
65     { 153, 0x54, 0x07, 0x00, 0x00, 0x00 }, // draw subtitle string, index
66     { 165, 0x54, 0x08, 0x00, 0x00, 0x00 }, // draw subtitle string, index
67     { 169, 0x53, 0x0B, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x0B
68     { 178, 0x54, 0x00, 0x00, 0x00, 0x00 }, // clear subtitle string area
69     { 180, 0x54, 0x09, 0x00, 0x00, 0x00 }, // draw subtitle string, index
70     { 190, 0x53, 0x0A, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x0A
71     { 200, 0x54, 0x00, 0x00, 0x00, 0x00 }, // clear subtitle string area
72     { 217, 0x4C, 0x16, 0x6E, 0x02, 0x00 }, // read data from FLC (0x026e16 (159254) bytes)
73     { 217, 0x41, 0x06, 0x00, 0x00, 0x00 }, // wait 1/100 seconds (6 = 60ms)
74     { 218, 0x53, 0x03, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x03
75     { 231, 0x54, 0x0A, 0x00, 0x00, 0x00 }, // draw subtitle string, index
76     { 267, 0x4C, 0xC0, 0x52, 0x04, 0x00 }, // read data from FLC (0x0452c0 (283328) bytes)
77     { 267, 0x41, 0x0C, 0x00, 0x00, 0x00 }, // wait 1/100 seconds (12 = 120ms)
78     { 268, 0x53, 0x0C, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x0C
79     { 271, 0x54, 0x00, 0x00, 0x00, 0x00 }, // clear subtitle string area
80     { 291, 0x54, 0x0B, 0x00, 0x00, 0x00 }, // draw subtitle string, index
81     { 305, 0x41, 0x06, 0x00, 0x00, 0x00 }, // wait 1/100 seconds (6 = 60ms)
82     { 316, 0x4C, 0x84, 0x7C, 0x0A, 0x00 }, // read data from FLC (0x0a7c84 (687236) bytes)
83     { 317, 0x41, 0x0C, 0x00, 0x00, 0x00 }, // wait 1/100 seconds (12 = 120ms)
84     { 318, 0x53, 0x0D, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x0D
85     { 333, 0x54, 0x00, 0x00, 0x00, 0x00 }, // clear subtitle string area
86     { 333, 0x53, 0x0D, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x0D
87     { 343, 0x53, 0x0D, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x0D
88     { 354, 0x53, 0x0D, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x0D
89     { 359, 0x54, 0x0C, 0x00, 0x00, 0x00 }, // draw subtitle string, index
90     { 367, 0x41, 0x07, 0x00, 0x00, 0x00 }, // wait 1/100 seconds (7 = 70ms)
91     { 406, 0x54, 0x00, 0x00, 0x00, 0x00 }, // clear subtitle string area
92     { 414, 0x4C, 0x78, 0x2D, 0x02, 0x00 }, // read data from FLC (0x22d78 (142712) bytes)
93     { 415, 0x41, 0x06, 0x00, 0x00, 0x00 }, // wait 1/100 seconds (6 = 60ms)
94     { 427, 0x53, 0x05, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x05
95     { 439, 0x4C, 0x0A, 0x29, 0x01, 0x00 }, // read data from FLC (0x01290a (76042) bytes)
96     { 439, 0x41, 0x78, 0x00, 0x00, 0x00 }, // wait 1/100 seconds (120 = 1200ms)
97     { 440, 0x41, 0x0C, 0x00, 0x00, 0x00 }, // wait 1/100 seconds (12 = 120ms)
98     { 442, 0x54, 0x0D, 0x00, 0x00, 0x00 }, // draw subtitle string, index
99     { 449, 0x53, 0x11, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x11
100     { 454, 0x53, 0x11, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x11
101     { 459, 0x53, 0x0F, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x0F
102     { 467, 0x54, 0x00, 0x00, 0x00, 0x00 }, // clear subtitle string area
103     { 470, 0x53, 0x10, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x10
104     { 472, 0x4C, 0x42, 0xE2, 0x07, 0x00 }, // read data from FLC (0x07e242 (516674) bytes)
105     { 473, 0x54, 0x0E, 0x00, 0x00, 0x00 }, // draw subtitle string, index
106     { 473, 0x41, 0x0A, 0x00, 0x00, 0x00 }, // wait 1/100 seconds
107     { 489, 0x53, 0x07, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x07
108     { 502, 0x54, 0x00, 0x00, 0x00, 0x00 }, // clear subtitle string area
109     { 504, 0x41, 0x08, 0x00, 0x00, 0x00 }, // wait 1/100 seconds
110     { 520, 0x53, 0x08, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x08
111     { 528, 0x41, 0x0C, 0x00, 0x00, 0x00 }, // wait 1/100 seconds (12 = 120ms)
112     { 532, 0x53, 0x09, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x09
113     { 541, 0x41, 0x08, 0x00, 0x00, 0x00 }, // wait 1/100 seconds
114     { 542, 0x53, 0x08, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x08
115     { 548, 0x54, 0x0F, 0x00, 0x00, 0x00 }, // draw subtitle string, index
116     { 548, 0x53, 0x07, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x07
117     { 562, 0x54, 0x00, 0x00, 0x00, 0x00 }, // clear subtitle string area
118     { 565, 0x41, 0x0C, 0x00, 0x00, 0x00 }, // wait 1/100 seconds (12 = 120ms)
119     { 568, 0x53, 0x06, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x06
120     { 569, 0x54, 0x10, 0x00, 0x00, 0x00 }, // draw subtitle string, index
121     { 577, 0x53, 0x07, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x07
122     { 580, 0x53, 0x04, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x04
123     { 583, 0x53, 0x07, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x07
124     { 589, 0x53, 0x04, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x04
125     { 592, 0x53, 0x07, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x07
126     { 602, 0x53, 0x04, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x04
127     { 606, 0x53, 0x07, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x07
128     { 610, 0x54, 0x00, 0x00, 0x00, 0x00 }, // clear subtitle string area
129     { 617, 0x53, 0x04, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x04
130     { 620, 0x53, 0x07, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x07
131     { 627, 0x4C, 0xAC, 0x5D, 0x00, 0x00 }, // read data from FLC (0x5dac (23980) bytes)
132     { 628, 0x41, 0x28, 0x00, 0x00, 0x00 }, // wait 1/100 seconds
133     { 629, 0x53, 0x0E, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x0E
134     { 635, 0x4C, 0x5C, 0x31, 0x01, 0x00 }, // read data from FLC (0x01315c (78172) bytes)
135     { 635, 0x41, 0x01, 0x00, 0x00, 0x00 }, // wait 1/100 seconds (1 = 10ms)
136     { 636, 0x53, 0x00, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x00
137     { 637, 0x45, 0x01, 0x00, 0x00, 0x00 }, // load "data/isnds-1.dat"
138     { 638, 0x41, 0x06, 0x00, 0x00, 0x00 }, // wait 1/100 seconds (6 = 60ms)
139     { 639, 0x54, 0x11, 0x00, 0x00, 0x00 }, // draw subtitle string, index
140     { 641, 0x53, 0x0B, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x0B
141     { 646, 0x53, 0x07, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x07
142     { 654, 0x53, 0x05, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x05
143     { 662, 0x53, 0x06, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x06
144     { 673, 0x54, 0x00, 0x00, 0x00, 0x00 }, // clear subtitle string area
145     { 674, 0x53, 0x04, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x04
146     { 679, 0x53, 0x08, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x08
147     { 691, 0x53, 0x09, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x09
148     { 704, 0x53, 0x0A, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x0A
149     { 709, 0x53, 0x0C, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x0C
150     { 719, 0x53, 0x0A, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x0A
151     { 725, 0x53, 0x0A, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x0A
152     { 727, 0x53, 0x0C, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x0C
153     { 733, 0x53, 0x0A, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x0A
154     { 738, 0x53, 0x0A, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x0A
155     { 741, 0x53, 0x0C, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x0C
156     { 744, 0x53, 0x0A, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x0A
157     { 749, 0x53, 0x0A, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x0A
158     { 755, 0x53, 0x0C, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x0C
159     { 761, 0x53, 0x0D, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x0D
160     { 786, 0x4C, 0xCE, 0x90, 0x04, 0x00 }, // read data from FLC (0x0490ce (299214) bytes)
161     { 787, 0x41, 0x06, 0x00, 0x00, 0x00 }, // wait 1/100 seconds (6 = 60ms)
162     { 788, 0x53, 0x01, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x01
163     { 807, 0x53, 0x02, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x02
164     { 837, 0x4C, 0xF8, 0x03, 0x01, 0x00 }, // read data from FLC (0x0103f8 (66552) bytes)
165     { 848, 0x54, 0x12, 0x00, 0x00, 0x00 }, // draw subtitle string, index
166     { 869, 0x4C, 0x78, 0x92, 0x00, 0x00 }, // read data from FLC (0x9278 (37496) bytes)
167     { 870, 0x41, 0x0C, 0x00, 0x00, 0x00 }, // wait 1/100 seconds (12 = 120ms)
168     { 871, 0x53, 0x03, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x03
169     { 892, 0x54, 0x00, 0x00, 0x00, 0x00 }, // clear subtitle string area
170     { 902, 0x4C, 0x10, 0x17, 0x05, 0x00 }, // read data from FLC, 0x051710 (333584) bytes
171     { 903, 0x41, 0x0A, 0x00, 0x00, 0x00 }, // wait 1/100 seconds (10 = 100ms)
172     { 903, 0x53, 0x0E, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x0E
173     { 904, 0x54, 0x13, 0x00, 0x00, 0x00 }, // draw subtitle string, index
174     { 917, 0x53, 0x07, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x07
175     { 920, 0x41, 0x0B, 0x00, 0x00, 0x00 }, // wait 1/100 seconds (11 = 110ms)
176     { 929, 0x58, 0x00, 0x00, 0x00, 0x00 }, // stop current sequence
177     { 931, 0x53, 0x0F, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x0F
178     { 935, 0x53, 0x10, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x10
179     { 938, 0x53, 0x10, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x10
180     { 941, 0x53, 0x10, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x10
181     { 944, 0x53, 0x10, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x10
182     { 947, 0x53, 0x10, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x10
183     { 950, 0x53, 0x10, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x10
184     { 953, 0x53, 0x10, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x10
185     { 956, 0x53, 0x10, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x10
186     { 959, 0x53, 0x10, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x10
187     { 960, 0x54, 0x00, 0x00, 0x00, 0x00 }, // clear subtitle string area
188     { 963, 0x53, 0x11, 0x00, 0x00, 0x00 }, // maybe play VOC index 0x11
189     { 997, 0x41, 0x78, 0x00, 0x00, 0x00 }, // wait 1/100 seconds (120 = 1200ms)
190     { 998, 0x41, 0x78, 0x00, 0x00, 0x00 }, // wait 1/100 seconds (120 = 1200ms)
191     {  -1, 0x00, 0x00, 0x00, 0x00, 0x00 }
192 };
193 
194 #endif
195 
~FliPlayer()196 FliPlayer::~FliPlayer() {
197     if (offscreen_) {
198         delete[] offscreen_;
199         offscreen_ = NULL;
200     }
201 }
202 
loadFliData(uint8 * data)203 void FliPlayer::loadFliData(uint8 *data) {
204     fli_data_ = data;
205 
206     fli_info_.size = READ_LE_UINT32(fli_data_);
207     fli_data_ += 4;
208     fli_info_.type = READ_LE_UINT16(fli_data_);
209     fli_data_ += 2;
210     fli_info_.numFrames = READ_LE_UINT16(fli_data_);
211     fli_data_ += 2;
212     fli_info_.width = READ_LE_UINT16(fli_data_);
213     fli_data_ += 2;
214     fli_info_.height = READ_LE_UINT16(fli_data_);
215     fli_data_ += 2;
216 
217     if (fli_info_.type != 0xAF12) {     //simple check to verify it is indeed a (Bullfrog) FLI
218         FSERR(Log::k_FLG_GFX, "FliPlayer", "loadFliData()", ("Attempted to load non-FLI data (type = 0x%04X)\n", fli_info_.type));
219         fli_info_.width = fli_info_.height = 100;
220         fli_info_.numFrames = 0;
221         return;
222     }
223 
224     assert(fli_info_.width == 320 && fli_info_.height == 200);
225     if (offscreen_)
226         delete[] offscreen_;
227     offscreen_ = new uint8[fli_info_.width * fli_info_.height];
228 
229     memset(palette_, 0, sizeof(palette_));
230 }
231 
isValidChunk(uint16 type)232 bool FliPlayer::isValidChunk(uint16 type) {
233     //Even though it may be a valid chunk type, only return true if we know how to deal with it
234     switch (type) {
235     case 4:                    //COLOR_256
236     case 7:                    //DELTA_FLC (FLI_SS2)
237     case 15:                   //BYTE_RUN
238     case 0xF1FA:               //FRAME_TYPE
239         return true;
240 
241     default:
242         FSERR(Log::k_FLG_GFX, "FliPlayer", "isValidChunk()", ("ERROR: isValidChunk(0x%04X) is NOT a valid chunk\n", type));
243         return false;
244     }
245 }
246 
readChunkHeader(uint8 * mem)247 ChunkHeader FliPlayer::readChunkHeader(uint8 * mem) {
248     ChunkHeader head;
249     head.size = READ_LE_UINT32(mem + 0);
250     head.type = READ_LE_UINT16(mem + 4);
251     return head;
252 }
253 
readFrameTypeChunkHeader(ChunkHeader chunkHead,uint8 * & mem)254 FrameTypeChunkHeader FliPlayer::readFrameTypeChunkHeader(ChunkHeader chunkHead,
255         uint8 *&mem) {
256     FrameTypeChunkHeader head;
257 
258     head.header = chunkHead;
259     mem += 6;
260     head.numChunks = READ_LE_UINT16(mem);
261     mem += 2;
262     head.delay = READ_LE_UINT16(mem);
263     mem += 2;
264     head.reserved = READ_LE_UINT16(mem);
265     mem += 2;
266     head.widthOverride = READ_LE_UINT16(mem);
267     mem += 2;
268     head.heightOverride = READ_LE_UINT16(mem);
269     mem += 2;
270 
271     return head;
272 }
273 
decodeByteRun(uint8 * data)274 void FliPlayer::decodeByteRun(uint8 *data) {
275     uint8 *ptr = (uint8 *) offscreen_;
276     while ((ptr - offscreen_) < (fli_info_.width * fli_info_.height)) {
277         uint8 chunks = *data++;
278         while (chunks--) {
279             int8 count = *data++;
280             if (count > 0) {
281                 while (count--) {
282                     *ptr++ = *data;
283                 }
284                 data++;
285             } else {
286                 uint8 copyBytes = -count;
287                 memcpy(ptr, data, copyBytes);
288                 ptr += copyBytes;
289                 data += copyBytes;
290             }
291         }
292     }
293 }
294 
295 #define OP_PACKETCOUNT      0
296 #define OP_UNDEFINED        1
297 #define OP_LASTPIXEL        2
298 #define OP_LINESKIPCOUNT    3
299 
decodeDeltaFLC(uint8 * data)300 void FliPlayer::decodeDeltaFLC(uint8 *data) {
301     uint16 linesInChunk = READ_LE_UINT16(data);
302     data += 2;
303     uint16 currentLine = 0;
304     uint16 packetCount = 0;
305 
306     while (linesInChunk--) {
307         uint16 opcode;
308 
309         // First process all the opcodes.
310         do {
311             opcode = READ_LE_UINT16(data);
312             data += 2;
313 
314             switch ((opcode >> 14) & 3) {
315             case OP_PACKETCOUNT:
316                 packetCount = opcode;
317                 break;
318             case OP_UNDEFINED:
319                 break;
320             case OP_LASTPIXEL:
321                 *(uint8 *) (offscreen_ + (currentLine * fli_info_.width) +
322                             (fli_info_.width - 1)) = (opcode & 0xFF);
323                 break;
324             case OP_LINESKIPCOUNT:
325                 currentLine += -(int16) opcode;
326                 break;
327             }
328         } while (((opcode >> 14) & 3) != OP_PACKETCOUNT);
329 
330         uint16 column = 0;
331 
332         //Now interpret the RLE data
333         while (packetCount--) {
334             column += *data++;
335             int8 rleCount = (int8) * data++;
336 
337             if (rleCount > 0) {
338                 memcpy((void *) (offscreen_ +
339                                  (currentLine * fli_info_.width) + column),
340                        data, rleCount * 2);
341                 data += rleCount * 2;
342                 column += rleCount * 2;
343             }
344             else if (rleCount < 0) {
345                 uint16 dataWord = *(uint16 *) data;
346                 data += 2;
347                 for (int i = 0; i < -(int16) rleCount; ++i) {
348                     *(uint16 *) (offscreen_ +
349                                  (currentLine * fli_info_.width) + column +
350                                  (i * 2)) = dataWord;
351                 }
352 
353                 column += (-(int16) rleCount) * 2;
354             }
355             else {            // End of cutscene ?
356                 return;
357             }
358         }
359 
360         currentLine++;
361     }
362 }
363 
364 
365 #define FRAME_TYPE  0xF1FA
366 
decodeFrame()367 bool FliPlayer::decodeFrame() {
368     FrameTypeChunkHeader frameHeader;
369     ChunkHeader cHeader = readChunkHeader(fli_data_);
370     do {
371         switch (cHeader.type) {
372         case 4:
373             setPalette(fli_data_ + 6);
374             g_System.setPalette8b3(palette_);
375             break;
376         case 7:
377             decodeDeltaFLC(fli_data_ + 6);
378             break;
379         case 15:
380             decodeByteRun(fli_data_ + 6);
381             break;
382         case FRAME_TYPE:
383             frameHeader = readFrameTypeChunkHeader(cHeader, fli_data_);
384             fli_info_.numFrames--;
385             //printf("Frames Remaining: %d\n", fli_info_.numFrames);
386             break;
387         default:
388             break;
389         }
390 
391         if (cHeader.type != FRAME_TYPE)
392             fli_data_ += cHeader.size;
393 
394         cHeader = readChunkHeader(fli_data_);
395 
396     } while (isValidChunk(cHeader.type) && cHeader.type != FRAME_TYPE);
397 
398     return isValidChunk(cHeader.type);
399 
400 }
401 
setPalette(uint8 * mem)402 void FliPlayer::setPalette(uint8 *mem) {
403     uint16 numPackets = READ_LE_UINT16(mem);
404     mem += 2;
405 
406     if (0 == READ_LE_UINT16(mem)) {     //special case
407         mem += 2;
408         for (int i = 0; i < 256; ++i)
409             for (int j = 0; j < 3; ++j)
410                 palette_[i * 3 + j] =
411                     (mem[i * 3 + j] << 2) | (mem[i * 3 + j] & 3);
412     }
413     else {
414         uint8 palPos = 0;
415 
416         while (numPackets--) {
417             palPos += *mem++;
418             uint8 change = *mem++;
419 
420             for (int i = 0; i < change; ++i)
421                 for (int j = 0; j < 3; ++j)
422                     palette_[(palPos + i) * 3 + j] =
423                         (mem[i * 3 + j] << 2) | (mem[i * 3 + j] & 3);
424 
425             palPos += change;
426             mem += (change * 3);
427         }
428     }
429 }
430 
copyCurrentFrameToScreen()431 void FliPlayer::copyCurrentFrameToScreen() {
432     g_Screen.scale2x(0, 0, fli_info_.width, fli_info_.height, offscreen(),
433                      0, false);
434 }
435 
play(bool intro,Font * pIntroFont)436 bool FliPlayer::play(bool intro, Font *pIntroFont) {
437     if (!fli_data_)
438         return false;
439 
440     g_Screen.clear(0);
441     int cur_frame = 0;
442     while (hasFrames()) {
443         // Consumes events now so they won't be piled up after the animation
444         pManager_->handleEvents();
445 
446         if (!decodeFrame())
447             break;
448         copyCurrentFrameToScreen();
449 
450         cur_frame++;
451 
452         g_System.updateScreen();
453         g_System.delay(1000 / (intro ? 10 : 15));      //fps
454     }
455 
456     //clear the backscreen
457     //bzero(Screen::pixels(), GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT);
458 
459     return true;
460 }
461