File: video.h

package info (click to toggle)
scummvm 2.9.1%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 450,580 kB
  • sloc: cpp: 4,299,825; asm: 28,322; python: 12,901; sh: 11,302; java: 9,289; xml: 7,895; perl: 2,639; ansic: 2,465; yacc: 1,670; javascript: 1,020; makefile: 933; lex: 578; awk: 275; objc: 82; sed: 11; php: 1
file content (416 lines) | stat: -rw-r--r-- 12,624 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Copyright 2020 Google
 *
 */

#ifndef HADESCH_VIDEOROOM_H
#define HADESCH_VIDEOROOM_H

#include "common/scummsys.h"
#include "common/array.h"
#include "audio/audiostream.h"
#include "audio/mixer.h"
#include "common/rect.h"
#include "common/ptr.h"
#include "hadesch/pod_file.h"
#include "hadesch/pod_image.h"
#include "common/hashmap.h"
#include "common/str.h"
#include "hadesch/enums.h"
#include "hadesch/event.h"
#include "hadesch/hotzone.h"
#include "hadesch/table.h"
#include "common/queue.h"

namespace Video {
class SmackerDecoder;
}

namespace Hadesch {

class PodImage;
class HadeschEngine;
class TagFile;

static const int kDefaultSpeed = 100;

class Renderable {
public:
		Renderable(Common::Array<PodImage> images);
	const PodImage &getFrame(int time);
	void startAnimation(int startms, int msperframe,
			    bool loop, int first, int last);
	bool isAnimationFinished(int time);
	void selectFrame(int frame);
	int getAnimationFrameNum(int time);
	int getNumFrames() {
		return _images.size();
	}

private:
	int getLen();
	Common::Array<PodImage> _images;
	int _msperframe;
	int _startms;
	int _first;
	int _last;
	bool _loop;
};

class LayerId {
public:
	LayerId(const Common::String &name) {
		_name = name;
		_idx = -1;
	}

	LayerId() {
		_idx = -1;
	}

	LayerId(const char *name) {
		_name = name;
		_idx = -1;
	}

	LayerId(const Common::String &name, int idx, const Common::String &qualifier) {
		_qualifier = qualifier;
		_name = name;
		_idx = idx;
	}

	Common::String getFilename() const {
		return _name;
	}

	Common::String getDebug() const;

	bool operator== (const LayerId &b) const;

private:
	Common::String _name;
	int _idx;
	Common::String _qualifier;
};

struct Animation {
	Audio::SoundHandle _soundHandle;
	LayerId _animName;
	EventHandlerWrapper _callbackEvent;
	bool _finished;
	bool _keepLastFrame;
	bool _skippable;
	int _subtitleID;
};

class PlayAnimParams {
public:
	static PlayAnimParams loop();
	static PlayAnimParams keepLastFrame();
	static PlayAnimParams disappear();
	bool getKeepLastFrame();
	bool isLoop();
	int getSpeed();
	int getFirstFrame();
	int getLastFrame();
	PlayAnimParams partial(int first, int last) const;
	PlayAnimParams speed(int msperframe) const;
	PlayAnimParams backwards() const;
private:
	PlayAnimParams(bool loop, bool keepLastFrame);
	bool _loop;
	bool _keepLastFrame;
	int _firstFrame;
	int _lastFrame;
	int _msperframe;
};

struct TranscribedSound {
	const char *soundName;
	const char *transcript;

	static TranscribedSound make(const char *s, const char *t) {
		TranscribedSound res;
		res.soundName = s;
		res.transcript = t;
		return res;
	}
};

class VideoRoom {
public:
	VideoRoom(const Common::String &dir, const Common::String &pod,
		  const Common::String &assetMapFile);
	~VideoRoom();

	void nextFrame(Common::SharedPtr<GfxContext> context, int time, bool stopVideo);
	uint getWidth();
	uint getHeight();
	int getCursor();

	// Hotzones and mouse
	void setHotzoneEnabled(const Common::String &name, bool enabled);
	void enableHotzone(const Common::String &name);
	void disableHotzone(const Common::String &name);
	void pushHotZones(const Common::String &hotzoneFile, bool enable = true,
			  Common::Point offset = Common::Point(0, 0));
	void popHotZones();
	void loadHotZones(const Common::String &hotzoneFile, bool enable = true,
			  Common::Point offset = Common::Point(0, 0));
	void computeHotZone(int time, Common::Point mousePos);
	Common::String getHotZone();
	void setHotZoneOffset(const Common::String &name, Common::Point offset);
	Common::String mapClick(Common::Point mousePos);
	void enableMouse() {
		_mouseEnabled = true;
	}
	void disableMouse() {
		_mouseEnabled = false;
	}
	bool isMouseEnabled() {
		return _mouseEnabled;
	}
	int getCursorAnimationFrame(int time);

	// Animations and layers
	void setLayerEnabled(const LayerId &name, bool enabled);
	void setLayerParallax(const LayerId &name, int val);
	void setColorScale(const LayerId &name, int val);
	void setScale(const LayerId &name, int val);
	int getNumFrames(const LayerId &animName);

	// Main animation API
	void playAnimWithSpeech(const LayerId &animName,
				const TranscribedSound &sound,
				int zValue,
				PlayAnimParams params,
				EventHandlerWrapper callbackEvent = EventHandlerWrapper(),
				Common::Point offset = Common::Point(0, 0));
	void playAnimWithSFX(const LayerId &animName,
			     const Common::String &soundName,
			     int zValue,
			     PlayAnimParams params,
			     EventHandlerWrapper callbackEvent = EventHandlerWrapper(),
			     Common::Point offset = Common::Point(0, 0));
		void playAnimWithMusic(const LayerId &animName,
			       const Common::String &soundName,
			       int zValue,
			       PlayAnimParams params,
			       EventHandlerWrapper callbackEvent = EventHandlerWrapper(),
			       Common::Point offset = Common::Point(0, 0));
	void playAnim(const LayerId &animName, int zValue,
		      PlayAnimParams params,
		      EventHandlerWrapper callbackEvent = EventHandlerWrapper(),
		      Common::Point offset = Common::Point(0, 0));

	void stopAnim(const LayerId &animName);
	// Like stopAnim but also remove layer altogether
	void purgeAnim(const LayerId &animName);
  	bool isAnimationFinished(const LayerId &name, int time);
	void addStaticLayer(const LayerId &name, int zValue, Common::Point offset = Common::Point(0, 0));
	void selectFrame(const LayerId &name, int zValue, int val, Common::Point offset = Common::Point(0, 0));
	bool doesLayerExist(const LayerId &name);
	PodImage getLayerFrame(const LayerId &name);
  	int getAnimFrameNum(const LayerId &name);
	void dumpLayers();

	// Convenience wrappers
	void playAnimLoop(const LayerId &animName, int zValue, Common::Point offset = Common::Point(0, 0));
	void playAnimKeepLastFrame(const LayerId &animName, int zValue, EventHandlerWrapper callbackEvent = EventHandlerWrapper(),
				   Common::Point offset = Common::Point(0, 0));

	// Videos
	void playVideo(const Common::String &name, int zValue,
		       EventHandlerWrapper callbackEvent = EventHandlerWrapper(),
		       Common::Point offset = Common::Point(0, 0));
	void cancelVideo();
	bool isVideoPlaying();

	// Panning
	void panLeftAnim(EventHandlerWrapper callbackEvent = EventHandlerWrapper());
	void panRightAnim(EventHandlerWrapper callbackEvent = EventHandlerWrapper());
	void panRightInstant();
	void setPannable(bool pannable);
	void setUserPanCallback(EventHandlerWrapper leftStart,
				EventHandlerWrapper leftEnd,
				EventHandlerWrapper rightStart,
				EventHandlerWrapper rightEnd);
	bool isPanLeft() {
		return _pan == 0;
	}

	bool isPanRight() {
		return _pan == 640;
	}

	// Hero belt
	void enableHeroBelt() {
		_heroBeltEnabled = true;
	}
	void disableHeroBelt() {
		_heroBeltEnabled = false;
	}
	bool isHeroBeltEnabled() {
		return _heroBeltEnabled;
	}

	// Font
	void renderString(const Common::String &font, const Common::U32String &str,
			  Common::Point startPos, int zVal, int fontDelta = 0, const Common::String &extraId = "letter");
	void renderStringCentered(const Common::String &font, const Common::U32String &str,
				  Common::Point centerPos, int zVal, int fontDelta = 0, const Common::String &extraId = "letter");
	void hideString(const Common::String &font, size_t maxLen, const Common::String &extraId = "letter");
	int computeStringWidth(const Common::String &font, const Common::U32String &str, int fontDelta = 0);

	// Misc
	void playSFX(const Common::String &soundName,
		     EventHandlerWrapper callbackEvent = EventHandlerWrapper());
	void playMusic(const Common::String &soundName,
		       EventHandlerWrapper callbackEvent = EventHandlerWrapper());
	void playSFXLoop(const Common::String &soundName);
	void playMusicLoop(const Common::String &soundName);
	void playSpeech(const TranscribedSound &sound,
				 EventHandlerWrapper callbackEvent = EventHandlerWrapper());
	void playStatueSMK(StatueId id, const LayerId &animName, int zValue,
			   const Common::Array<Common::String> &smkNames,
			   int startOfLoop, int startOfEnd,
			   Common::Point offset = Common::Point(0, 0));
	Common::SeekableReadStream *openFile(const Common::String &name);
	void fadeOut(int ms, const EventHandlerWrapper &callback);
	void resetFade();
	void resetLayers();
	void drag(const Common::String &name, int frame, Common::Point hotspot);
	PodImage *getDragged();
	void clearDrag();
	void pause();
	void unpause();
	void finish();
	void cancelAllSubtitles();
	void setViewportOffset(Common::Point vp) {
		_viewportOffset = vp;
	}

private:
	struct Layer {
		Common::SharedPtr<Renderable> renderable;
		LayerId name;
		Common::Point offset;
		bool isEnabled;
		int genCounter;
		int zValue;
		int parallax;
		int colorScale; // From 0 to 0x100
		int scale; // From 0 to 100
	};

	struct SubtitleLine {
		Common::U32String line;
		int32 maxTime;
		int ID;
	};

	void playAnimWithSoundInternal(const LayerId &animName,
				       const Common::String &soundName,
				       Audio::Mixer::SoundType soundType,
				       int zValue,
				       PlayAnimParams params,
				       EventHandlerWrapper callbackEvent,
				       Common::Point offset,
				       int subID = -1);
	void playSubtitles(const char *text, int subID);
	void addLayer(Renderable *renderable, const LayerId &name,
		      int zValue,
		      bool isEnabled = true, Common::Point offset = Common::Point(0, 0));
	void startAnimationInternal(const LayerId &name, int zValue, int msperframe, bool loop,
				    bool fixedFrame, int first, int last, Common::Point offset);
	Audio::RewindableAudioStream *getAudioStream(const Common::String &soundName);
	Common::String mapAsset(const Common::String &name);
	Common::String mapAsset(const LayerId &name);
	void addAnimLayerInternal(const LayerId &name, int zValue, Common::Point offset = Common::Point(0, 0));
	void playSoundInternal(const Common::String &soundName, EventHandlerWrapper callbackEvent, bool loop,
			       bool skippable, Audio::Mixer::SoundType soundType, int subtitleID = -1);
	static int layerComparator (const Layer &a, const Layer &b);
	void loadFontWidth(const Common::String &font);

	uint _videoW, _videoH;
	Common::Point _videoOffset, _videoSurfOffset;
	Common::SharedPtr<byte> _videoPixels;
	byte _videoPalette[256 * 3];

	HotZoneArray _hotZones;
	Common::Array<HotZoneArray> _hotZoneStack;
	Common::SortedArray<Layer, const Layer&> _layers;
	int _layerGenCounter;

	int _startHotTime;
	int _hotZone;
	int _cursor;
	// We need to keep cursor pointer valid for at
	// least one more frame. Hence use circular buffer
	PodImage _draggedImage[5];
	int _draggingPtr;
	bool _isDragging;
	int _pan, _panSpeed;
	EventHandlerWrapper _panCallback;
	EventHandlerWrapper _userPanStartLeftCallback;
	EventHandlerWrapper _userPanStartRightCallback;
	EventHandlerWrapper _userPanEndLeftCallback;
	EventHandlerWrapper _userPanEndRightCallback;

	bool _pannable;
	bool _leftEdge;
	bool _rightEdge;
	bool _heroBeltEnabled;
	int _edgeStartTime;
	Common::String _smkPath;
	Common::String _podPath;

	Common::SharedPtr<Video::SmackerDecoder> _videoDecoder;
	Common::Point _viewportOffset;
	Common::Array<Animation> _anims;
	EventHandlerWrapper _videoDecoderEndEvent;
	int _videoZ;
	Common::SharedPtr<PodFile> _podFile;
	Common::HashMap<Common::String, Common::Array<int> > _fontWidths;
	Common::Queue<SubtitleLine> _subtitles;
	Common::HashMap<int, int> _countQueuedSubtitles;
	TextTable _assetMap;
	bool _mouseEnabled;

	int _finalFade, _finalFadeSpeed;
	EventHandlerWrapper _finalFadeCallback;
};

static const int kVideoWidth = 640;
static const int kVideoHeight = 480;
#define kOffsetRightRoom (Common::Point(kVideoWidth, 0))
#define kZeroPoint (Common::Point(10, 50))

struct PrePoint {
	int x, y;

	Common::Point get() const {
		return Common::Point(x, y);
	}
};

}
#endif