1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
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.
11  *
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.
16  *
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, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "bladerunner/overlays.h"
24 
25 #include "bladerunner/bladerunner.h"
26 #include "bladerunner/game_constants.h"
27 
28 #include "bladerunner/archive.h"
29 #include "bladerunner/savefile.h"
30 #include "bladerunner/vqa_player.h"
31 
32 #include "graphics/surface.h"
33 
34 namespace BladeRunner {
35 
Overlays(BladeRunnerEngine * vm)36 Overlays::Overlays(BladeRunnerEngine *vm) {
37 	_vm = vm;
38 }
39 
init()40 bool Overlays::init() {
41 	reset();
42 	_videos.resize(kOverlayVideos);
43 
44 	for (int i = 0; i < kOverlayVideos; ++i) {
45 		_videos[i].vqaPlayer = nullptr;
46 		resetSingle(i);
47 	}
48 
49 	return true;
50 }
51 
~Overlays()52 Overlays::~Overlays() {
53 	for (int i = 0; i < kOverlayVideos; ++i) {
54 		resetSingle(i);
55 	}
56 	_videos.clear();
57 	reset();
58 }
59 
play(const Common::String & name,int loopId,bool loopForever,bool startNow,int a6)60 int Overlays::play(const Common::String &name, int loopId, bool loopForever, bool startNow, int a6) {
61 	assert(name.size() <= 12);
62 	if (loopId < 0) {
63 		warning("Overlays::play - loop id can't be a negative number!");
64 		return -1;
65 	}
66 
67 	int32 hash = MIXArchive::getHash(name);
68 	int index = findByHash(hash);
69 	if (index < 0) {
70 		index = findEmpty();
71 		if (index < 0) {
72 			return index;
73 		}
74 		_videos[index].loaded = true;
75 		_videos[index].name = name;
76 		_videos[index].hash = hash;
77 		_videos[index].loopId = loopId;
78 		_videos[index].enqueuedLoopId = -1;
79 		_videos[index].loopForever = loopForever;
80 		_videos[index].vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceFront, Common::String::format("%s.VQA", name.c_str()));
81 
82 		if (!_videos[index].vqaPlayer) {
83 			resetSingle(index);
84 			return -1;
85 		}
86 		// TODO? Removed as redundant
87 		// repeat forever
88 		//_videos[index].vqaPlayer->setBeginAndEndFrame(0, 0, -1, kLoopSetModeJustStart, nullptr, nullptr);
89 	}
90 
91 	bool skipNewVQAPlayerOpen = false;
92 	if (_videos[index].vqaPlayer
93 	    && !startNow
94 	    && _videos[index].vqaPlayer->getFrameCount() > 0
95 	) {
96 		skipNewVQAPlayerOpen = true;
97 		_videos[index].enqueuedLoopId = loopId;
98 	}
99 
100 	if (skipNewVQAPlayerOpen || _videos[index].vqaPlayer->open()) {
101 		_videos[index].vqaPlayer->setLoop(
102 			loopId,
103 			loopForever ? -1 : 0,
104 			startNow ? kLoopSetModeImmediate : kLoopSetModeEnqueue,
105 			nullptr, nullptr);
106 	} else {
107 		resetSingle(index);
108 		return -1;
109 	}
110 	return index;
111 }
112 
resume(bool isLoadingGame)113 void Overlays::resume(bool isLoadingGame) {
114 
115 	for (int i = 0; i < kOverlayVideos; ++i) {
116 		if (_videos[i].loaded && isLoadingGame) {
117 			_videos[i].vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceFront, Common::String::format("%s.VQA", _videos[i].name.c_str()));
118 			if (!_videos[i].vqaPlayer) {
119 				resetSingle(i);
120 				continue;
121 			}
122 
123 			_videos[i].vqaPlayer->open();
124 			_videos[i].vqaPlayer->setLoop(
125 				_videos[i].loopId,
126 				_videos[i].loopForever ? -1 : 0,
127 				kLoopSetModeImmediate,
128 				nullptr, nullptr);
129 
130 			_videos[i].vqaPlayer->seekToFrame(_videos[i].frame);
131 			_videos[i].vqaPlayer->update(true);
132 		}
133 	}
134 }
135 
remove(const Common::String & name)136 void Overlays::remove(const Common::String &name) {
137 	int index = findByHash(MIXArchive::getHash(name));
138 	if (index >= 0) {
139 		resetSingle(index);
140 	}
141 }
142 
removeAll()143 void Overlays::removeAll() {
144 	for (int i = 0; i < kOverlayVideos; ++i) {
145 		if (_videos[i].loaded) {
146 			resetSingle(i);
147 		}
148 	}
149 }
150 
tick()151 void Overlays::tick() {
152 	for (int i = 0; i < kOverlayVideos; ++i) {
153 		if (_videos[i].loaded) {
154 			_videos[i].frame = _videos[i].vqaPlayer->update(true);
155 			if (_videos[i].frame < 0) {
156 				resetSingle(i);
157 			}
158 		}
159 	}
160 }
161 
findByHash(int32 hash) const162 int Overlays::findByHash(int32 hash) const {
163 	for (int i = 0; i < kOverlayVideos; ++i) {
164 		if (_videos[i].loaded && _videos[i].hash == hash) {
165 			return i;
166 		}
167 	}
168 	return -1;
169 }
170 
findEmpty() const171 int Overlays::findEmpty() const {
172 	for (int i = 0; i < kOverlayVideos; ++i) {
173 		if (!_videos[i].loaded) {
174 			return i;
175 		}
176 	}
177 	return -1;
178 }
179 
resetSingle(int i)180 void Overlays::resetSingle(int i) {
181 	assert(i >= 0 && i < (int)_videos.size());
182 	if (_videos[i].vqaPlayer) {
183 		delete _videos[i].vqaPlayer;
184 		_videos[i].vqaPlayer = nullptr;
185 	}
186 	_videos[i].loaded = false;
187 	_videos[i].hash = 0;
188 	_videos[i].frame = -1;
189 	_videos[i].name.clear();
190 }
191 
reset()192 void Overlays::reset() {
193 	_videos.clear();
194 }
195 
save(SaveFileWriteStream & f)196 void Overlays::save(SaveFileWriteStream &f) {
197 	for (int i = 0; i < kOverlayVideos; ++i) {
198 		// 37 bytes per overlay
199 		Video &ov = _videos[i];
200 
201 		f.writeBool(ov.loaded);
202 		f.writeInt(0); // vqaPlayer pointer
203 		f.writeStringSz(ov.name, 13);
204 		f.writeSint32LE(ov.hash);
205 		if (ov.enqueuedLoopId != -1) {
206 		// When there is an enqueued video, save that loop Id instead
207 			f.writeInt(ov.enqueuedLoopId);
208 		} else {
209 			f.writeInt(ov.loopId);
210 		}
211 		f.writeBool(ov.loopForever);
212 		f.writeInt(ov.frame);
213 	}
214 }
215 
load(SaveFileReadStream & f)216 void Overlays::load(SaveFileReadStream &f) {
217 	for (int i = 0; i < kOverlayVideos; ++i) {
218 		// 37 bytes per overlay
219 		Video &ov = _videos[i];
220 
221 		ov.loaded = f.readBool();
222 		f.skip(4); // vqaPlayer pointer
223 		ov.vqaPlayer = nullptr;
224 		ov.name = f.readStringSz(13);
225 		ov.hash = f.readSint32LE();
226 		ov.loopId = f.readInt();
227 		ov.loopForever = f.readBool();
228 		ov.frame = f.readInt();
229 	}
230 }
231 
232 } // End of namespace BladeRunner
233