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 #ifndef SCI_GRAPHICS_VIDEO32_H 24 #define SCI_GRAPHICS_VIDEO32_H 25 26 #ifdef USE_RGB_COLOR 27 #include "common/config-manager.h" // for ConfMan 28 #endif 29 #include "common/ptr.h" 30 #include "common/rect.h" // for Rect 31 #include "common/scummsys.h" // for int16, uint8, uint16, int32 32 #include "common/str.h" // for String 33 #include "sci/engine/vm_types.h" // for reg_t 34 #include "sci/video/robot_decoder.h" // for RobotDecoder 35 #include "sci/sound/audio32.h" // for Audio32::kMaxVolume 36 #include "video/avi_decoder.h" // for AVIDecoder::setVolume 37 38 namespace Video { 39 class AdvancedVMDDecoder; 40 } 41 namespace Sci { 42 class EventManager; 43 class Plane; 44 class ScreenItem; 45 class SegManager; 46 class SEQDecoder; 47 struct Palette; 48 49 /** 50 * An abstract class implementing common video playback functionality for SCI 51 * engine. 52 */ 53 class VideoPlayer { 54 public: 55 enum EventFlags { 56 kEventFlagNone = 0, 57 kEventFlagEnd = 1, 58 kEventFlagEscapeKey = 2, 59 kEventFlagMouseDown = 4, 60 kEventFlagHotRectangle = 8, 61 kEventFlagToFrame = 0x10, 62 kEventFlagYieldToVM = 0x20, 63 kEventFlagReverse = 0x80 64 }; 65 66 friend EventFlags operator|(const EventFlags a, const EventFlags b) { 67 return static_cast<EventFlags>((int)a | (int)b); 68 } 69 70 VideoPlayer(EventManager *eventMan, Video::VideoDecoder *decoder = nullptr) : _eventMan(eventMan)71 _eventMan(eventMan), 72 _decoder(decoder), 73 _needsUpdate(false), 74 _currentFrame(nullptr) 75 #ifdef USE_RGB_COLOR 76 , 77 _hqVideoMode(false) 78 #endif 79 {} 80 ~VideoPlayer()81 virtual ~VideoPlayer() {} 82 83 protected: 84 EventManager *_eventMan; 85 86 /** 87 * The video decoder to use for video playback by this player. 88 */ 89 Common::ScopedPtr<Video::VideoDecoder> _decoder; 90 91 /** 92 * Attempts to open a video by filename and performs basic validation to 93 * ensure that the current system is actually capable of playing back the 94 * video. 95 */ 96 bool open(const Common::String &fileName); 97 98 /** 99 * Reinitializes the system hardware surface for playback of high-quality 100 * scaled video if the current video meets the necessary criteria for this 101 * playback mode. 102 * 103 * @returns whether or not the system surface was reinitialized for 104 * high-quality scaled video. 105 */ 106 bool startHQVideo(); 107 108 /** 109 * Determines whether or not the currently loaded video meets the criteria 110 * for high-quality scaled output. 111 */ shouldStartHQVideo()112 virtual bool shouldStartHQVideo() const { 113 #ifdef USE_RGB_COLOR 114 if (!ConfMan.getBool("enable_hq_video")) { 115 return false; 116 } 117 118 if (_decoder->getWidth() == _drawRect.width() && 119 _decoder->getHeight() == _drawRect.height()) { 120 return false; 121 } 122 123 return true; 124 #else 125 return false; 126 #endif 127 } 128 129 /** 130 * Restores the hardware surface back to CLUT8 after video playback. 131 */ 132 bool endHQVideo(); 133 134 /** 135 * Plays a video until an event in the given `flags` is encountered, or 136 * until the end of the video is reached. 137 * 138 * @param maxSleepMs An optional parameter defining the maximum number of 139 * milliseconds that the video player should sleep between video frames. 140 */ 141 virtual EventFlags playUntilEvent(const EventFlags flags, const uint32 maxSleepMs = 0xFFFFFFFF); 142 143 /** 144 * Checks to see if an event has occurred that should cause the video player 145 * to yield back to the VM. 146 */ 147 virtual EventFlags checkForEvent(const EventFlags flags); 148 149 /** 150 * Submits a palette from the video to the system. 151 */ 152 virtual void submitPalette(const uint8 palette[256 * 3]) const; 153 154 /** 155 * Renders a video frame to the system. 156 */ 157 virtual void renderFrame(const Graphics::Surface &nextFrame) const; 158 159 /** 160 * Renders a video frame to an intermediate surface using low-quality 161 * scaling, black-lining, or direct copy, depending upon the passed flags. 162 */ 163 template <typename PixelType> 164 void renderLQToSurface(Graphics::Surface &out, const Graphics::Surface &nextFrame, const bool doublePixels, const bool blackLines) const; 165 166 /** 167 * Sets the draw rect, clipping it to the screen's dimensions if necessary. 168 */ 169 void setDrawRect(const int16 x, const int16 y, const int16 width, const int16 height); 170 171 /** 172 * The rectangle where the video will be drawn, in screen coordinates. 173 */ 174 Common::Rect _drawRect; 175 176 /** 177 * If true, playUntilEvent() will immediately render a frame. 178 * Used by VMDPlayer when censorship blobs are added or removed in Phant1 179 * in order to immediately update the screen upon resuming playback. 180 */ 181 bool _needsUpdate; 182 183 /** 184 * Current frame rendered by playUntilEvent() 185 */ 186 const Graphics::Surface* _currentFrame; 187 188 #ifdef USE_RGB_COLOR 189 /** 190 * Whether or not the player is currently in high-quality video rendering 191 * mode. 192 */ 193 bool _hqVideoMode; 194 #endif 195 }; 196 197 #pragma mark SEQPlayer 198 199 /** 200 * SEQPlayer is used to play SEQ animations. 201 * Used by DOS versions of GK1 and QFG4CD. 202 */ 203 class SEQPlayer : public VideoPlayer { 204 public: 205 SEQPlayer(EventManager *eventMan); 206 207 /** 208 * Plays a SEQ animation with the given file name, with each frame being 209 * displayed for `numTicks` ticks. 210 */ 211 void play(const Common::String &fileName, const int16 numTicks, const int16 x, const int16 y); 212 }; 213 214 #pragma mark - 215 #pragma mark AVIPlayer 216 217 /** 218 * AVIPlayer is used to play AVI videos. 219 * Used by Windows versions of GK1CD, KQ7, and QFG4CD. 220 */ 221 class AVIPlayer : public VideoPlayer { 222 public: 223 enum IOStatus { 224 kIOSuccess = 0, 225 kIOFileNotFound = 2, 226 kIOSeekFailed = 12 227 }; 228 229 enum AVIStatus { 230 kAVINotOpen = 0, 231 kAVIOpen = 1, 232 kAVIPlaying = 2, 233 kAVIPaused = 3 234 }; 235 236 AVIPlayer(EventManager *eventMan); 237 238 /** 239 * Opens a stream to an AVI resource. 240 */ 241 IOStatus open(const Common::String &fileName); 242 243 /** 244 * Initializes the AVI rendering parameters for the current AVI. This must 245 * be called after `open`. 246 */ 247 IOStatus init(const bool doublePixels); 248 249 /** 250 * Begins playback of the current AVI. 251 */ 252 IOStatus play(const int16 from, const int16 to, const int16 showStyle, const bool cue); 253 254 EventFlags playUntilEvent(const EventFlags flags, const uint32 maxSleepMs = 0xFFFFFFFF) override; 255 256 /** 257 * Stops playback and closes the currently open AVI stream. 258 */ 259 IOStatus close(); 260 261 /** 262 * Seeks the currently open AVI stream to the given frame. 263 */ 264 IOStatus cue(const uint16 frameNo); 265 266 /** 267 * Returns the duration of the current video. 268 */ 269 uint16 getDuration() const; 270 271 private: 272 /** 273 * Playback status of the player. 274 */ 275 AVIStatus _status; 276 }; 277 278 #pragma mark - 279 #pragma mark QuickTimePlayer 280 281 /** 282 * QuickTimePlayer is used to play QuickTime animations. 283 * Used by Mac version of KQ7. 284 */ 285 class QuickTimePlayer : public VideoPlayer { 286 public: 287 QuickTimePlayer(EventManager *eventMan); 288 289 /** 290 * Plays a QuickTime animation with the given file name 291 */ 292 void play(const Common::String& fileName); 293 }; 294 295 #pragma mark - 296 #pragma mark VMDPlayer 297 298 /** 299 * VMDPlayer is used to play VMD videos. 300 * Used by LSL7, Phant1, GK2, PQ:SWAT, Shivers, SQ6, Rama, Torin, and 301 * Lighthouse. 302 */ 303 class VMDPlayer : public VideoPlayer { 304 public: 305 enum OpenFlags { 306 kOpenFlagNone = 0, 307 kOpenFlagMute = 1 308 }; 309 310 enum IOStatus { 311 kIOSuccess = 0, 312 kIOError = 0xFFFF 313 }; 314 315 enum PlayFlags { 316 kPlayFlagNone = 0, 317 kPlayFlagDoublePixels = 1, 318 kPlayFlagBlackLines = 4, 319 kPlayFlagBoost = 0x10, 320 kPlayFlagLeaveScreenBlack = 0x20, 321 kPlayFlagLeaveLastFrame = 0x40, 322 kPlayFlagBlackPalette = 0x80, 323 kPlayFlagStretchVertical = 0x100 324 }; 325 326 enum VMDStatus { 327 kVMDNotOpen = 0, 328 kVMDOpen = 1, 329 kVMDPlaying = 2, 330 kVMDPaused = 3, 331 kVMDStopped = 4, 332 kVMDFinished = 5 333 }; 334 335 VMDPlayer(EventManager *eventMan, SegManager *segMan); 336 ~VMDPlayer() override; 337 338 private: 339 SegManager *_segMan; 340 341 #pragma mark - 342 #pragma mark VMDPlayer - Playback 343 public: 344 /** 345 * Opens a stream to a VMD resource. 346 */ 347 IOStatus open(const Common::String &fileName, const OpenFlags flags); 348 349 /** 350 * Initializes the VMD rendering parameters for the current VMD. This must 351 * be called after `open`. 352 */ 353 void init(int16 x, int16 y, const PlayFlags flags, const int16 boostPercent, const int16 boostStartColor, const int16 boostEndColor); 354 355 /** 356 * Stops playback and closes the currently open VMD stream. 357 */ 358 IOStatus close(); 359 360 /** 361 * Gets the playback status of the VMD player. 362 */ 363 VMDStatus getStatus() const; 364 365 // Was WaitForEvent in SSCI 366 EventFlags kernelPlayUntilEvent(const EventFlags flags, const int16 lastFrameNo, const int16 yieldInterval); 367 368 private: 369 /** 370 * Whether or not a VMD stream has been opened with `open`. 371 */ 372 bool _isOpen; 373 374 /** 375 * Whether or not a VMD player has been initialized with `init`. 376 */ 377 bool _isInitialized; 378 379 /** 380 * The Resource object for VMDs that are read out of a resource bundle 381 * instead of being streamed from the filesystem. The resource is owned by 382 * ResourceManager. 383 */ 384 Resource *_bundledVmd; 385 386 /** 387 * For VMDs played with the `kEventFlagToFrame` flag, the target frame for 388 * yielding back to the SCI VM. 389 */ 390 int32 _yieldFrame; 391 392 /** 393 * For VMDs played with the `kEventFlagYieldToVM` flag, the number of frames 394 * that should be rendered until yielding back to the SCI VM. 395 */ 396 int32 _yieldInterval; 397 398 /** 399 * For VMDs played with the `kEventFlagYieldToVM` flag, the last frame when 400 * control of the main thread was yielded back to the SCI VM. 401 */ 402 int _lastYieldedFrameNo; 403 404 EventFlags playUntilEvent(const EventFlags flags, const uint32 = 0xFFFFFFFF) override; 405 EventFlags checkForEvent(const EventFlags flags) override; 406 407 #pragma mark - 408 #pragma mark VMDPlayer - Rendering 409 public: 410 /** 411 * Causes the VMD player to ignore all palettes in the currently playing 412 * video. 413 */ ignorePalettes()414 void ignorePalettes() { _ignorePalettes = true; } 415 416 /** 417 * Sets the plane and plane priority used to render video. 418 */ 419 void setPlane(const int16 priority, const reg_t planeId); 420 421 protected: 422 /** 423 * Renders a frame of video to the output bitmap. 424 */ 425 void renderFrame(const Graphics::Surface &nextFrame) const override; 426 427 /** 428 * Updates the system with palette data from the video. 429 */ 430 void submitPalette(const uint8 palette[256 * 3]) const override; 431 432 private: 433 /** 434 * The plane where the VMD will be drawn. The plane is owned by GfxFrameout. 435 */ 436 Plane *_plane; 437 438 /** 439 * The screen item representing the VMD surface. The screen item is owned by 440 * GfxFrameout. 441 */ 442 ScreenItem *_screenItem; 443 444 /** 445 * The bitmap used to render the VMD. 446 */ 447 reg_t _bitmapId; 448 449 /** 450 * If true, the plane for this VMD was set externally and is not owned by 451 * this VMDPlayer. 452 */ 453 bool _planeIsOwned; 454 455 /** 456 * The screen priority of the video. 457 * @see ScreenItem::_priority 458 */ 459 int _priority; 460 461 /** 462 * Whether or not the video should be pixel doubled. 463 */ 464 bool _doublePixels; 465 466 /** 467 * Whether or not the video should be pixel doubled vertically only. 468 */ 469 bool _stretchVertical; 470 471 /** 472 * Whether or not black lines should be rendered across the video. 473 */ 474 bool _blackLines; 475 476 /** 477 * Whether or not the playback area of the VMD should be left black at the 478 * end of playback. 479 */ 480 bool _leaveScreenBlack; 481 482 /** 483 * Whether or not the area of the VMD should be left displaying the final 484 * frame of the video. 485 */ 486 bool _leaveLastFrame; 487 488 /** 489 * Whether or not palettes from the VMD should be ignored. 490 */ 491 bool _ignorePalettes; 492 493 /** 494 * Whether or not rendering mode is composited. 495 */ 496 bool _isComposited; 497 498 /** 499 * Fills the given palette with RGB values from the VMD palette, applying 500 * brightness boost if it is enabled. 501 */ 502 void fillPalette(const uint8 rawPalette[256 * 3], Palette &outPalette) const; 503 504 #ifdef USE_RGB_COLOR 505 /** 506 * Redraws areas of the screen outside of the video to the system buffer. 507 * This is used whenever palette changes occur and the video is rendering in 508 * high color mode. 509 */ 510 void redrawGameScreen() const; 511 512 /** 513 * Determines whether or not the VMD player should upgrade the renderer to 514 * high color depth when rendering the video. 515 * 516 * @TODO It should be possible in the future to allow high color composited 517 * video, but this will require additional work in GfxFrameout and 518 * GfxCursor32 since the internal buffer and cursor code are 8bpp only. 519 */ shouldStartHQVideo()520 bool shouldStartHQVideo() const override { 521 if (!VideoPlayer::shouldStartHQVideo()) { 522 return false; 523 } 524 525 if (_priority != 0 || _leaveLastFrame || _showCursor || _blackLines) { 526 return false; 527 } 528 529 return true; 530 } 531 #endif 532 533 /** 534 * Determines whether or not the video should use the compositing renderer 535 * instead of the overlay renderer. 536 */ shouldUseCompositing()537 bool shouldUseCompositing() const { 538 #ifdef USE_RGB_COLOR 539 return isNormallyComposited() && !shouldStartHQVideo(); 540 #else 541 return isNormallyComposited(); 542 #endif 543 } 544 isNormallyComposited()545 bool isNormallyComposited() const { 546 return (getSciVersion() == SCI_VERSION_3) || 547 (g_sci->getPlatform() == Common::kPlatformMacintosh && 548 getSciVersion() >= SCI_VERSION_2_1_LATE); 549 } 550 551 void initOverlay(); 552 void renderOverlay(const Graphics::Surface &nextFrame) const; 553 void closeOverlay(); 554 555 void initComposited(); 556 void renderComposited() const; 557 void closeComposited(); 558 559 #pragma mark - 560 #pragma mark VMDPlayer - Blackout 561 public: 562 /** 563 * Sets the area of the screen that should be blacked out during VMD 564 * playback. 565 */ setBlackoutArea(const Common::Rect & rect)566 void setBlackoutArea(const Common::Rect &rect) { _blackoutRect = rect; } 567 568 private: 569 /** 570 * The dimensions of the blackout plane. 571 */ 572 Common::Rect _blackoutRect; 573 574 /** 575 * An optional plane that will be used to black out areas of the screen 576 * outside of the VMD surface. The plane is owned by GfxFrameout. 577 */ 578 Plane *_blackoutPlane; 579 580 #pragma mark - 581 #pragma mark VMDPlayer - Palette 582 public: 583 /** 584 * Restricts use of the system palette by VMD playback to the given range of 585 * palette indexes. 586 */ 587 void restrictPalette(const uint8 startColor, const int16 endColor); 588 589 private: 590 /** 591 * The first color in the system palette that the VMD can write to. 592 */ 593 uint8 _startColor; 594 595 /** 596 * The last color in the system palette that the VMD can write to. 597 */ 598 uint8 _endColor; 599 600 /** 601 * If true, video frames are rendered after a blank palette is submitted to 602 * the palette manager, which is then restored after the video pixels have 603 * already been rendered. 604 * 605 * This functionality is currently disabled because it seems like it was 606 * designed for a different graphics architecture where pixel data could be 607 * rendered before the video card's palette had been updated. This is not 608 * possible in ScummVM because the palette & pixel data are rendered 609 * simultaneously when OSystem::updateScreen is called, rather than 610 * immediately after they are sent to the backend. 611 */ 612 #ifdef SCI_VMD_BLACK_PALETTE 613 bool _blackPalette; 614 #endif 615 616 #pragma mark - 617 #pragma mark VMDPlayer - Brightness boost 618 private: 619 /** 620 * The amount of brightness boost for the video. Values above 100 increase 621 * brightness; values below 100 reduce it. 622 */ 623 int16 _boostPercent; 624 625 /** 626 * The first color in the palette that should be brightness boosted. 627 */ 628 uint8 _boostStartColor; 629 630 /** 631 * The last color in the palette that should be brightness boosted. 632 */ 633 uint8 _boostEndColor; 634 635 #pragma mark - 636 #pragma mark VMDPlayer - Mouse cursor 637 public: 638 /** 639 * Sets whether or not the mouse cursor should be drawn. This does not have 640 * any effect during playback, but can be used to prevent the mouse cursor 641 * from being shown again after the video has finished. 642 */ setShowCursor(const bool shouldShow)643 void setShowCursor(const bool shouldShow) { _showCursor = shouldShow; } 644 645 private: 646 /** 647 * Whether or not the mouse cursor should be shown during playback. 648 */ 649 bool _showCursor; 650 651 #pragma mark - 652 #pragma mark VMDPlayer - Censorship blobs 653 public: 654 /** 655 * Censorship blobs are pixelated rectangles which are added and removed by 656 * game scripts. Phant1 is the only game known to use this and always sets a 657 * blockSize of 10. Each block's color comes from the pixel in the upper left 658 * corner of the block's location. 659 */ 660 int16 addBlob(int16 blockSize, int16 top, int16 left, int16 bottom, int16 right); 661 void deleteBlobs(); 662 void deleteBlob(int16 blobNumber); 663 664 private: 665 enum { 666 kMaxBlobs = 10 667 }; 668 669 struct Blob { 670 int16 blobNumber; 671 int16 blockSize; 672 int16 top; 673 int16 left; 674 int16 bottom; 675 int16 right; 676 }; 677 678 Common::List<Blob> _blobs; 679 680 void drawBlobs(Graphics::Surface& frame) const; 681 }; 682 683 #pragma mark - 684 #pragma mark DuckPlayer 685 686 /** 687 * DuckPlayer is used to play Duck TrueMotion videos. 688 * Used by Phantasmagoria 2. 689 */ 690 class DuckPlayer : public VideoPlayer { 691 public: 692 enum DuckStatus { 693 kDuckClosed = 0, 694 kDuckOpen = 1, 695 kDuckPlaying = 2, 696 kDuckPaused = 3 697 }; 698 699 DuckPlayer(EventManager *eventMan, SegManager *segMan); 700 701 /** 702 * Opens a stream to a Duck resource. 703 */ 704 void open(const GuiResourceId resourceId, const int displayMode, const int16 x, const int16 y); 705 706 /** 707 * Stops playback and closes the currently open Duck stream. 708 */ 709 void close(); 710 711 /** 712 * Begins playback of the current Duck video. 713 */ 714 void play(const int lastFrameNo); 715 716 /** 717 * Sets a flag indicating that an opaque plane should be added to the 718 * graphics manager underneath the video surface during playback. 719 */ setDoFrameOut(const bool value)720 void setDoFrameOut(const bool value) { _doFrameOut = value; } 721 722 /** 723 * Sets the volume of the decoder. 724 */ setVolume(const uint8 value)725 void setVolume(const uint8 value) { 726 _volume = value * Audio::Mixer::kMaxChannelVolume / Audio32::kMaxVolume; 727 _decoder->setVolume(_volume); 728 } 729 730 protected: shouldStartHQVideo()731 bool shouldStartHQVideo() const override { 732 if (!VideoPlayer::shouldStartHQVideo() || _blackLines) { 733 return false; 734 } 735 736 return true; 737 } 738 739 void renderFrame(const Graphics::Surface &nextFrame) const override; 740 741 private: 742 /** 743 * An empty plane drawn behind the video when the doFrameOut flag is true. 744 * The plane is owned by GfxFrameout. 745 */ 746 Plane *_plane; 747 748 /** 749 * The player status. 750 */ 751 DuckStatus _status; 752 753 /** 754 * The playback volume for the player. 755 */ 756 uint8 _volume; 757 758 /** 759 * If true, frameOut will be called during Duck video playback to update 760 * other parts of the screen. 761 */ 762 bool _doFrameOut; 763 764 /** 765 * Whether or not the video should be pixel doubled. 766 */ 767 bool _doublePixels; 768 769 /** 770 * Whether or not black lines should be rendered across the video. 771 */ 772 bool _blackLines; 773 }; 774 775 #pragma mark - 776 #pragma mark Video32 777 778 /** 779 * Video32 provides facilities for playing back video in SCI engine. 780 */ 781 class Video32 : public Common::Serializable { 782 public: Video32(SegManager * segMan,EventManager * eventMan)783 Video32(SegManager *segMan, EventManager *eventMan) : 784 _SEQPlayer(eventMan), 785 _AVIPlayer(eventMan), 786 _QuickTimePlayer(eventMan), 787 _VMDPlayer(eventMan, segMan), 788 _robotPlayer(segMan), 789 _duckPlayer(eventMan, segMan) {} 790 791 void beforeSaveLoadWithSerializer(Common::Serializer &ser); 792 void saveLoadWithSerializer(Common::Serializer &ser) override; 793 getSEQPlayer()794 SEQPlayer &getSEQPlayer() { return _SEQPlayer; } getAVIPlayer()795 AVIPlayer &getAVIPlayer() { return _AVIPlayer; } getQuickTimePlayer()796 QuickTimePlayer &getQuickTimePlayer() { return _QuickTimePlayer; } getVMDPlayer()797 VMDPlayer &getVMDPlayer() { return _VMDPlayer; } getRobotPlayer()798 RobotDecoder &getRobotPlayer() { return _robotPlayer; } getDuckPlayer()799 DuckPlayer &getDuckPlayer() { return _duckPlayer; } 800 801 private: 802 SEQPlayer _SEQPlayer; 803 AVIPlayer _AVIPlayer; 804 QuickTimePlayer _QuickTimePlayer; 805 VMDPlayer _VMDPlayer; 806 RobotDecoder _robotPlayer; 807 DuckPlayer _duckPlayer; 808 }; 809 } // End of namespace Sci 810 811 #endif 812