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 * Copyright 2020 Google 22 * 23 */ 24 25 #ifndef HADESCH_VIDEOROOM_H 26 #define HADESCH_VIDEOROOM_H 27 28 #include "common/scummsys.h" 29 #include "common/array.h" 30 #include "audio/audiostream.h" 31 #include "audio/mixer.h" 32 #include "common/rect.h" 33 #include "common/ptr.h" 34 #include "hadesch/pod_file.h" 35 #include "hadesch/pod_image.h" 36 #include "common/hashmap.h" 37 #include "common/str.h" 38 #include "hadesch/enums.h" 39 #include "hadesch/event.h" 40 #include "hadesch/hotzone.h" 41 #include "hadesch/table.h" 42 #include "common/queue.h" 43 44 namespace Video { 45 class SmackerDecoder; 46 } 47 48 namespace Hadesch { 49 50 class PodImage; 51 class HadeschEngine; 52 class TagFile; 53 54 static const int kDefaultSpeed = 100; 55 56 class Renderable { 57 public: 58 Renderable(Common::Array<PodImage> images); 59 const PodImage &getFrame(int time); 60 void startAnimation(int startms, int msperframe, 61 bool loop, int first, int last); 62 bool isAnimationFinished(int time); 63 void selectFrame(int frame); 64 int getAnimationFrameNum(int time); getNumFrames()65 int getNumFrames() { 66 return _images.size(); 67 } 68 69 private: 70 int getLen(); 71 Common::Array<PodImage> _images; 72 int _msperframe; 73 int _startms; 74 int _first; 75 int _last; 76 bool _loop; 77 }; 78 79 class LayerId { 80 public: LayerId(const Common::String & name)81 LayerId(const Common::String &name) { 82 _name = name; 83 _idx = -1; 84 } 85 LayerId()86 LayerId() { 87 _idx = -1; 88 } 89 LayerId(const char * name)90 LayerId(const char *name) { 91 _name = name; 92 _idx = -1; 93 } 94 LayerId(const Common::String & name,int idx,const Common::String & qualifier)95 LayerId(const Common::String &name, int idx, const Common::String &qualifier) { 96 _qualifier = qualifier; 97 _name = name; 98 _idx = idx; 99 } 100 getFilename()101 Common::String getFilename() const { 102 return _name; 103 } 104 105 Common::String getDebug() const; 106 107 bool operator== (const LayerId &b) const; 108 109 private: 110 Common::String _name; 111 int _idx; 112 Common::String _qualifier; 113 }; 114 115 struct Animation { 116 Audio::SoundHandle _soundHandle; 117 LayerId _animName; 118 EventHandlerWrapper _callbackEvent; 119 bool _finished; 120 bool _keepLastFrame; 121 bool _skippable; 122 int _subtitleID; 123 }; 124 125 class PlayAnimParams { 126 public: 127 static PlayAnimParams loop(); 128 static PlayAnimParams keepLastFrame(); 129 static PlayAnimParams disappear(); 130 bool getKeepLastFrame(); 131 bool isLoop(); 132 int getSpeed(); 133 int getFirstFrame(); 134 int getLastFrame(); 135 PlayAnimParams partial(int first, int last) const; 136 PlayAnimParams speed(int msperframe) const; 137 PlayAnimParams backwards() const; 138 private: 139 PlayAnimParams(bool loop, bool keepLastFrame); 140 bool _loop; 141 bool _keepLastFrame; 142 int _firstFrame; 143 int _lastFrame; 144 int _msperframe; 145 }; 146 147 struct TranscribedSound { 148 const char *soundName; 149 const char *transcript; 150 makeTranscribedSound151 static TranscribedSound make(const char *s, const char *t) { 152 TranscribedSound res; 153 res.soundName = s; 154 res.transcript = t; 155 return res; 156 } 157 }; 158 159 class VideoRoom { 160 public: 161 VideoRoom(const Common::String &dir, const Common::String &pod, 162 const Common::String &assetMapFile); 163 ~VideoRoom(); 164 165 void nextFrame(Common::SharedPtr<GfxContext> context, int time, bool stopVideo); 166 uint getWidth(); 167 uint getHeight(); 168 int getCursor(); 169 170 // Hotzones and mouse 171 void setHotzoneEnabled(const Common::String &name, bool enabled); 172 void enableHotzone(const Common::String &name); 173 void disableHotzone(const Common::String &name); 174 void pushHotZones(const Common::String &hotzoneFile, bool enable = true, 175 Common::Point offset = Common::Point(0, 0)); 176 void popHotZones(); 177 void loadHotZones(const Common::String &hotzoneFile, bool enable = true, 178 Common::Point offset = Common::Point(0, 0)); 179 void computeHotZone(int time, Common::Point mousePos); 180 Common::String getHotZone(); 181 void setHotZoneOffset(const Common::String &name, Common::Point offset); 182 Common::String mapClick(Common::Point mousePos); enableMouse()183 void enableMouse() { 184 _mouseEnabled = true; 185 } disableMouse()186 void disableMouse() { 187 _mouseEnabled = false; 188 } isMouseEnabled()189 bool isMouseEnabled() { 190 return _mouseEnabled; 191 } 192 int getCursorAnimationFrame(int time); 193 194 // Animations and layers 195 void setLayerEnabled(const LayerId &name, bool enabled); 196 void setLayerParallax(const LayerId &name, int val); 197 void setColorScale(const LayerId &name, int val); 198 void setScale(const LayerId &name, int val); 199 int getNumFrames(const LayerId &animName); 200 201 // Main animation API 202 void playAnimWithSpeech(const LayerId &animName, 203 const TranscribedSound &sound, 204 int zValue, 205 PlayAnimParams params, 206 EventHandlerWrapper callbackEvent = EventHandlerWrapper(), 207 Common::Point offset = Common::Point(0, 0)); 208 void playAnimWithSFX(const LayerId &animName, 209 const Common::String &soundName, 210 int zValue, 211 PlayAnimParams params, 212 EventHandlerWrapper callbackEvent = EventHandlerWrapper(), 213 Common::Point offset = Common::Point(0, 0)); 214 void playAnimWithMusic(const LayerId &animName, 215 const Common::String &soundName, 216 int zValue, 217 PlayAnimParams params, 218 EventHandlerWrapper callbackEvent = EventHandlerWrapper(), 219 Common::Point offset = Common::Point(0, 0)); 220 void playAnim(const LayerId &animName, int zValue, 221 PlayAnimParams params, 222 EventHandlerWrapper callbackEvent = EventHandlerWrapper(), 223 Common::Point offset = Common::Point(0, 0)); 224 225 void stopAnim(const LayerId &animName); 226 // Like stopAnim but also remove layer altogether 227 void purgeAnim(const LayerId &animName); 228 bool isAnimationFinished(const LayerId &name, int time); 229 void addStaticLayer(const LayerId &name, int zValue, Common::Point offset = Common::Point(0, 0)); 230 void selectFrame(const LayerId &name, int zValue, int val, Common::Point offset = Common::Point(0, 0)); 231 bool doesLayerExist(const LayerId &name); 232 PodImage getLayerFrame(const LayerId &name); 233 int getAnimFrameNum(const LayerId &name); 234 void dumpLayers(); 235 236 // Convenience wrappers 237 void playAnimLoop(const LayerId &animName, int zValue, Common::Point offset = Common::Point(0, 0)); 238 void playAnimKeepLastFrame(const LayerId &animName, int zValue, EventHandlerWrapper callbackEvent = EventHandlerWrapper(), 239 Common::Point offset = Common::Point(0, 0)); 240 241 // Videos 242 void playVideo(const Common::String &name, int zValue, 243 EventHandlerWrapper callbackEvent = EventHandlerWrapper(), 244 Common::Point offset = Common::Point(0, 0)); 245 void cancelVideo(); 246 bool isVideoPlaying(); 247 248 // Panning 249 void panLeftAnim(EventHandlerWrapper callbackEvent = EventHandlerWrapper()); 250 void panRightAnim(EventHandlerWrapper callbackEvent = EventHandlerWrapper()); 251 void panRightInstant(); 252 void setPannable(bool pannable); 253 void setUserPanCallback(EventHandlerWrapper leftStart, 254 EventHandlerWrapper leftEnd, 255 EventHandlerWrapper rightStart, 256 EventHandlerWrapper rightEnd); isPanLeft()257 bool isPanLeft() { 258 return _pan == 0; 259 } 260 isPanRight()261 bool isPanRight() { 262 return _pan == 640; 263 } 264 265 // Hero belt enableHeroBelt()266 void enableHeroBelt() { 267 _heroBeltEnabled = true; 268 } disableHeroBelt()269 void disableHeroBelt() { 270 _heroBeltEnabled = false; 271 } isHeroBeltEnabled()272 bool isHeroBeltEnabled() { 273 return _heroBeltEnabled; 274 } 275 276 // Font 277 void renderString(const Common::String &font, const Common::U32String &str, 278 Common::Point startPos, int zVal, int fontDelta = 0, const Common::String &extraId = "letter"); 279 void renderStringCentered(const Common::String &font, const Common::U32String &str, 280 Common::Point centerPos, int zVal, int fontDelta = 0, const Common::String &extraId = "letter"); 281 void hideString(const Common::String &font, size_t maxLen, const Common::String &extraId = "letter"); 282 int computeStringWidth(const Common::String &font, const Common::U32String &str, int fontDelta = 0); 283 284 // Misc 285 void playSFX(const Common::String &soundName, 286 EventHandlerWrapper callbackEvent = EventHandlerWrapper()); 287 void playMusic(const Common::String &soundName, 288 EventHandlerWrapper callbackEvent = EventHandlerWrapper()); 289 void playSFXLoop(const Common::String &soundName); 290 void playMusicLoop(const Common::String &soundName); 291 void playSpeech(const TranscribedSound &sound, 292 EventHandlerWrapper callbackEvent = EventHandlerWrapper()); 293 void playStatueSMK(StatueId id, const LayerId &animName, int zValue, 294 const Common::Array<Common::String> &smkNames, 295 int startOfLoop, int startOfEnd, 296 Common::Point offset = Common::Point(0, 0)); 297 Common::SeekableReadStream *openFile(const Common::String &name); 298 void fadeOut(int ms, const EventHandlerWrapper &callback); 299 void resetFade(); 300 void resetLayers(); 301 void drag(const Common::String &name, int frame, Common::Point hotspot); 302 PodImage *getDragged(); 303 void clearDrag(); 304 void pause(); 305 void unpause(); 306 void finish(); 307 void cancelAllSubtitles(); setViewportOffset(Common::Point vp)308 void setViewportOffset(Common::Point vp) { 309 _viewportOffset = vp; 310 } 311 312 private: 313 struct Layer { 314 Common::SharedPtr<Renderable> renderable; 315 LayerId name; 316 Common::Point offset; 317 bool isEnabled; 318 int genCounter; 319 int zValue; 320 int parallax; 321 int colorScale; // From 0 to 0x100 322 int scale; // From 0 to 100 323 }; 324 325 struct SubtitleLine { 326 Common::U32String line; 327 int32 maxTime; 328 int ID; 329 }; 330 331 void playAnimWithSoundInternal(const LayerId &animName, 332 const Common::String &soundName, 333 Audio::Mixer::SoundType soundType, 334 int zValue, 335 PlayAnimParams params, 336 EventHandlerWrapper callbackEvent, 337 Common::Point offset, 338 int subID = -1); 339 void playSubtitles(const char *text, int subID); 340 void addLayer(Renderable *renderable, const LayerId &name, 341 int zValue, 342 bool isEnabled = true, Common::Point offset = Common::Point(0, 0)); 343 void startAnimationInternal(const LayerId &name, int zValue, int msperframe, bool loop, 344 bool fixedFrame, int first, int last, Common::Point offset); 345 Audio::RewindableAudioStream *getAudioStream(const Common::String &soundName); 346 Common::String mapAsset(const Common::String &name); 347 Common::String mapAsset(const LayerId &name); 348 void addAnimLayerInternal(const LayerId &name, int zValue, Common::Point offset = Common::Point(0, 0)); 349 void playSoundInternal(const Common::String &soundName, EventHandlerWrapper callbackEvent, bool loop, 350 bool skippable, Audio::Mixer::SoundType soundType, int subtitleID = -1); 351 static int layerComparator (const Layer &a, const Layer &b); 352 void loadFontWidth(const Common::String &font); 353 354 uint _videoW, _videoH; 355 Common::Point _videoOffset, _videoSurfOffset; 356 Common::SharedPtr<byte> _videoPixels; 357 byte _videoPalette[256 * 3]; 358 359 HotZoneArray _hotZones; 360 Common::Array<HotZoneArray> _hotZoneStack; 361 Common::SortedArray<Layer, const Layer&> _layers; 362 int _layerGenCounter; 363 364 int _startHotTime; 365 int _hotZone; 366 int _cursor; 367 // We need to keep cursor pointer valid for at 368 // least one more frame. Hence use circular buffer 369 PodImage _draggedImage[5]; 370 int _draggingPtr; 371 bool _isDragging; 372 int _pan, _panSpeed; 373 EventHandlerWrapper _panCallback; 374 EventHandlerWrapper _userPanStartLeftCallback; 375 EventHandlerWrapper _userPanStartRightCallback; 376 EventHandlerWrapper _userPanEndLeftCallback; 377 EventHandlerWrapper _userPanEndRightCallback; 378 379 bool _pannable; 380 bool _leftEdge; 381 bool _rightEdge; 382 bool _heroBeltEnabled; 383 int _edgeStartTime; 384 Common::String _smkPath; 385 Common::String _podPath; 386 387 Common::SharedPtr<Video::SmackerDecoder> _videoDecoder; 388 Common::Point _viewportOffset; 389 Common::Array<Animation> _anims; 390 EventHandlerWrapper _videoDecoderEndEvent; 391 int _videoZ; 392 Common::SharedPtr<PodFile> _podFile; 393 Common::HashMap<Common::String, Common::Array<int> > _fontWidths; 394 Common::Queue<SubtitleLine> _subtitles; 395 Common::HashMap<int, int> _countQueuedSubtitles; 396 TextTable _assetMap; 397 bool _mouseEnabled; 398 399 int _finalFade, _finalFadeSpeed; 400 EventHandlerWrapper _finalFadeCallback; 401 }; 402 403 static const int kVideoWidth = 640; 404 static const int kVideoHeight = 480; 405 #define kOffsetRightRoom (Common::Point(kVideoWidth, 0)) 406 #define kZeroPoint (Common::Point(10, 50)) 407 408 struct PrePoint { 409 int x, y; 410 getPrePoint411 Common::Point get() const { 412 return Common::Point(x, y); 413 } 414 }; 415 416 } 417 #endif 418