[Scummvm-git-logs] scummvm master -> fb6df4560ddb78bb5e3e2c7c9a314a4768be78c2
sev-
noreply at scummvm.org
Sun Jan 26 23:20:59 UTC 2025
This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
0a6d381b17 COMMON: Initialize Navigation struct in QTVR
fb6df4560d VIDEO: Split out QTVR code into a separate file
Commit: 0a6d381b1777555ec3d9be98da9cbb92e1b8d65c
https://github.com/scummvm/scummvm/commit/0a6d381b1777555ec3d9be98da9cbb92e1b8d65c
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2025-01-27T00:20:34+01:00
Commit Message:
COMMON: Initialize Navigation struct in QTVR
Changed paths:
common/formats/quicktime.h
diff --git a/common/formats/quicktime.h b/common/formats/quicktime.h
index 4abce63dd2b..328d5ce680d 100644
--- a/common/formats/quicktime.h
+++ b/common/formats/quicktime.h
@@ -327,23 +327,23 @@ protected:
};
struct Navigation {
- uint16 columns;
- uint16 rows;
- uint16 loop_size; // Number of frames shot at each position
- uint16 frame_duration;
+ uint16 columns = 1;
+ uint16 rows = 1;
+ uint16 loop_size = 0; // Number of frames shot at each position
+ uint16 frame_duration = 1;
- MovieType movie_type;
+ MovieType movie_type = MovieType::kStandardObject;
- uint16 loop_ticks; // Number of ticks before next frame of loop is displayed
+ uint16 loop_ticks = 0; // Number of ticks before next frame of loop is displayed
- float field_of_view;
+ float field_of_view = 1.0f;
- float startHPan;
- float startVPan;
- float endHPan;
- float endVPan;
- float initialHPan;
- float initialVPan;
+ float startHPan = 1.0f;
+ float startVPan = 1.0f;
+ float endHPan = 1.0f;
+ float endVPan = 1.0f;
+ float initialHPan = 1.0f;
+ float initialVPan = 1.0f;
};
virtual SampleDesc *readSampleDesc(Track *track, uint32 format, uint32 descSize) = 0;
Commit: fb6df4560ddb78bb5e3e2c7c9a314a4768be78c2
https://github.com/scummvm/scummvm/commit/fb6df4560ddb78bb5e3e2c7c9a314a4768be78c2
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2025-01-27T00:20:34+01:00
Commit Message:
VIDEO: Split out QTVR code into a separate file
Initial code on implementing Panorama tracks
Changed paths:
A video/qtvr_decoder.cpp
video/module.mk
video/qt_decoder.cpp
video/qt_decoder.h
diff --git a/video/module.mk b/video/module.mk
index 8bee4bdfa1a..356bc94d951 100644
--- a/video/module.mk
+++ b/video/module.mk
@@ -11,6 +11,7 @@ MODULE_OBJS := \
paco_decoder.o \
psx_decoder.o \
qt_decoder.o \
+ qtvr_decoder.o \
smk_decoder.o \
subtitles.o \
video_decoder.o
diff --git a/video/qt_decoder.cpp b/video/qt_decoder.cpp
index 453a77a55db..60f526d5c1a 100644
--- a/video/qt_decoder.cpp
+++ b/video/qt_decoder.cpp
@@ -49,8 +49,6 @@
namespace Video {
-static const char * const MACGUI_DATA_BUNDLE = "macgui.dat";
-
////////////////////////////////////////////
// QuickTimeDecoder
////////////////////////////////////////////
@@ -94,20 +92,14 @@ void QuickTimeDecoder::close() {
_scaledSurface = 0;
}
- delete _dataBundle;
- _dataBundle = nullptr;
- cleanupCursors();
+ closeQTVR();
}
const Graphics::Surface *QuickTimeDecoder::decodeNextFrame() {
const Graphics::Surface *frame = VideoDecoder::decodeNextFrame();
- if (isVR()) {
- _panAngle = (float)getCurrentColumn() / (float)_nav.columns * 360.0;
- _tiltAngle = ((_nav.rows - 1) / 2.0 - (float)getCurrentRow()) / (float)(_nav.rows - 1) * 180.0;
-
- debugC(1, kDebugLevelMacGUI, "QTVR: row: %d col: %d (%d x %d) pan: %f tilt: %f", getCurrentRow(), getCurrentColumn(), _nav.rows, _nav.columns, getPanAngle(), getTiltAngle());
- }
+ if (isVR())
+ updateAngles();
// Update audio buffers too
// (needs to be done after we find the next track)
@@ -226,6 +218,8 @@ Common::QuickTimeParser::SampleDesc *QuickTimeDecoder::readSampleDesc(Common::Qu
}
return entry;
+ } else if (track->codecType == CODEC_TYPE_PANO) {
+ //return readPanoSampleDesc(track, format, descSize);
}
// Pass it on up
@@ -326,6 +320,7 @@ QuickTimeDecoder::VideoTrackHandler::VideoTrackHandler(QuickTimeDecoder *decoder
_curFrame = -1;
_delayedFrameToBufferTo = -1;
enterNewEditListEntry(true, true); // might set _curFrame
+
if (decoder->_qtvrType == QTVRType::OBJECT)
_curFrame = getFrameCount() / 2;
@@ -337,13 +332,6 @@ QuickTimeDecoder::VideoTrackHandler::VideoTrackHandler(QuickTimeDecoder *decoder
_forcedDitherPalette = 0;
_ditherTable = 0;
_ditherFrame = 0;
- _isPanoConstructed = false;
-
- _constructedPano = nullptr;
- _projectedPano = nullptr;
-
- if (decoder->_qtvrType == QTVRType::PANORAMA)
- constructPanorama();
}
// FIXME: This check breaks valid QuickTime movies, such as the KQ6 Mac opening.
@@ -396,16 +384,6 @@ QuickTimeDecoder::VideoTrackHandler::~VideoTrackHandler() {
_ditherFrame->free();
delete _ditherFrame;
}
-
- if (_isPanoConstructed) {
- _constructedPano->free();
- delete _constructedPano;
- }
-
- if (_projectedPano) {
- _projectedPano->free();
- delete _projectedPano;
- }
}
bool QuickTimeDecoder::VideoTrackHandler::endOfTrack() const {
@@ -542,19 +520,6 @@ uint32 QuickTimeDecoder::VideoTrackHandler::getNextFrameStartTime() const {
}
const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::decodeNextFrame() {
- if (_decoder->_qtvrType == QTVRType::PANORAMA) {
- if (!_isPanoConstructed)
- return nullptr;
-
- if (_projectedPano) {
- _projectedPano->free();
- delete _projectedPano;
- }
-
- projectPanorama();
- return _projectedPano;
- }
-
if (endOfTrack())
return 0;
@@ -637,149 +602,6 @@ Common::String QuickTimeDecoder::getAliasPath() {
return Common::String();
}
-void QuickTimeDecoder::handleMouseMove(int16 x, int16 y) {
- if (_qtvrType != QTVRType::OBJECT)
- return;
-
- updateQTVRCursor(x, y);
-
- if (!_isMouseButtonDown)
- return;
-
- VideoTrackHandler *track = (VideoTrackHandler *)_nextVideoTrack;
-
- // HACK: FIXME: Hard coded for now
- const int sensitivity = 10;
- const float speedFactor = 0.1f;
-
- int16 mouseDeltaX = x - _prevMouseX;
- int16 mouseDeltaY = y - _prevMouseY;
-
- float speedX = (float)mouseDeltaX * speedFactor;
- float speedY = (float)mouseDeltaY * speedFactor;
-
- bool changed = false;
-
- if (ABS(mouseDeltaY) >= sensitivity) {
- int newFrame = track->getCurFrame() - round(speedY) * _nav.columns;
-
- if (newFrame >= 0 && newFrame < track->getFrameCount()) {
- track->setCurFrame(newFrame);
- changed = true;
- }
- }
-
- if (ABS(mouseDeltaX) >= sensitivity) {
- int currentRow = track->getCurFrame() / _nav.columns;
- int currentRowStart = currentRow * _nav.columns;
-
- int newFrame = (track->getCurFrame() - (int)roundf(speedX) - currentRowStart) % _nav.columns + currentRowStart;
-
- if (newFrame >= 0 && newFrame < track->getFrameCount()) {
- track->setCurFrame(newFrame);
- changed = true;
- }
- }
-
- if (changed) {
- _prevMouseX = x;
- _prevMouseY = y;
- }
-}
-
-void QuickTimeDecoder::handleMouseButton(bool isDown, int16 x, int16 y) {
- if (isDown) {
- if (y < _curBbox.top) {
- setCurrentRow(getCurrentRow() + 1);
- } else if (y > _curBbox.bottom) {
- setCurrentRow(getCurrentRow() - 1);
- } else if (x < _curBbox.left) {
- setCurrentColumn((getCurrentColumn() + 1) % _nav.columns);
- } else if (x > _curBbox.right) {
- setCurrentColumn((getCurrentColumn() - 1 + _nav.columns) % _nav.columns);
- } else {
- _prevMouseX = x;
- _prevMouseY = y;
- _isMouseButtonDown = isDown;
- }
- } else {
- _isMouseButtonDown = isDown;
- }
-
- updateQTVRCursor(x, y);
-}
-
-void QuickTimeDecoder::setCurrentRow(int row) {
- VideoTrackHandler *track = (VideoTrackHandler *)_nextVideoTrack;
-
- int currentColumn = track->getCurFrame() % _nav.columns;
- int newFrame = row * _nav.columns + currentColumn;
-
- if (newFrame >= 0 && newFrame < track->getFrameCount()) {
- track->setCurFrame(newFrame);
- }
-}
-
-void QuickTimeDecoder::setCurrentColumn(int column) {
- VideoTrackHandler *track = (VideoTrackHandler *)_nextVideoTrack;
-
- int currentRow = track->getCurFrame() / _nav.columns;
- int newFrame = currentRow * _nav.columns + column;
-
- if (newFrame >= 0 && newFrame < track->getFrameCount()) {
- track->setCurFrame(newFrame);
- }
-}
-
-void QuickTimeDecoder::nudge(const Common::String &direction) {
- VideoTrackHandler *track = (VideoTrackHandler *)_nextVideoTrack;
-
- int curFrame = track->getCurFrame();
- int currentRow = curFrame / _nav.columns;
- int currentRowStart = currentRow * _nav.columns;
- int newFrame = curFrame;
-
- if (direction.equalsIgnoreCase("left")) {
- newFrame = (curFrame - 1 - currentRowStart) % _nav.columns + currentRowStart;
- } else if (direction.equalsIgnoreCase("right")) {
- newFrame = (curFrame + 1 - currentRowStart) % _nav.columns + currentRowStart;
- } else if (direction.equalsIgnoreCase("top")) {
- newFrame = curFrame - _nav.columns;
- if (newFrame < 0)
- return;
- } else if (direction.equalsIgnoreCase("bottom")) {
- newFrame = curFrame + _nav.columns;
- if (newFrame >= track->getFrameCount())
- return;
- } else {
- error("QuickTimeDecoder::nudge(): Invald direction: ('%s')!", direction.c_str());
- }
-
- track->setCurFrame(newFrame);
-}
-
-QuickTimeDecoder::NodeData QuickTimeDecoder::getNodeData(uint32 nodeID) {
- for (const auto &sample : _panoTrack->panoSamples) {
- if (sample.hdr.nodeID == nodeID) {
- return {
- nodeID,
- sample.hdr.defHPan,
- sample.hdr.defVPan,
- sample.hdr.defZoom,
- sample.hdr.minHPan,
- sample.hdr.minVPan,
- sample.hdr.maxHPan,
- sample.hdr.maxVPan,
- sample.hdr.minZoom,
- sample.strTable.getString(sample.hdr.nameStrOffset)};
- }
- }
-
- error("QuickTimeDecoder::getNodeData(): Node with nodeID %d not found!", nodeID);
-
- return {};
-}
-
Audio::Timestamp QuickTimeDecoder::VideoTrackHandler::getFrameTime(uint frame) const {
// TODO: This probably doesn't work right with edit lists
int cumulativeDuration = 0;
@@ -1181,65 +1003,6 @@ void ditherFrame(const Graphics::Surface &src, Graphics::Surface &dst, const byt
} // End of anonymous namespace
-void QuickTimeDecoder::VideoTrackHandler::constructPanorama() {
- int16 totalWidth = getHeight() * _parent->frameCount;
- int16 totalHeight = getWidth();
-
- if (totalWidth <= 0 || totalHeight <= 0)
- return;
-
- _constructedPano = new Graphics::Surface();
- _constructedPano->create(totalWidth, totalHeight, getPixelFormat());
-
- for (uint32 frameIndex = 0; frameIndex < _parent->frameCount; frameIndex++) {
- const Graphics::Surface *frame = bufferNextFrame();
-
- for (int16 y = 0; y < frame->h; y++) {
- for (int16 x = 0; x < frame->w; x++) {
-
- int setX = (totalWidth - 1) - (frameIndex * _parent->height + y);
- int setY = x;
-
- if (setX >= 0 && setX < _constructedPano->w && setY >= 0 && setY < _constructedPano->h) {
- uint32 pixel = frame->getPixel(x, y);
- _constructedPano->setPixel(setX, setY, pixel);
- }
- }
- }
- }
-
- _isPanoConstructed = true;
-}
-
-void QuickTimeDecoder::VideoTrackHandler::projectPanorama() {
- if (!_isPanoConstructed)
- return;
-
- _projectedPano = new Graphics::Surface();
- _projectedPano->create(_constructedPano->w, _constructedPano->h, _constructedPano->format);
-
- const float c = _projectedPano->w;
- const float r = c / (2 * M_PI);
-
- // HACK: FIXME: Hard coded for now
- const float d = 500.0f;
-
- for (int16 y = 0; y < _projectedPano->h; y++) {
- for (int16 x = 0; x < _projectedPano->w; x++) {
- double u = atan(x / d) / (2.0 * M_PI);
- double v = y * r * cos(u) / d;
-
- int setX = round(u * _constructedPano->w);
- int setY = round(v);
-
- if (setX >= 0 && setX < _constructedPano->w && setY >= 0 && setY < _constructedPano->h) {
- uint32 pixel = _constructedPano->getPixel(setX, setY);
- _projectedPano->setPixel(x, y, pixel);
- }
- }
- }
-}
-
const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::forceDither(const Graphics::Surface &frame) {
if (frame.format.bytesPerPixel == 1) {
// This should always be true, but this is for sanity
@@ -1267,100 +1030,4 @@ const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::forceDither(const
return _ditherFrame;
}
-enum {
- kCurHand = 129,
- kCurGrab = 130,
- kCurObjUp = 131,
- kCurObjDown = 132,
- kCurObjLeft90 = 133,
- kCurObjRight90 = 134,
- kCurObjLeftM90 = 149,
- kCurObjRightM90 = 150,
- kCurObjUpLimit = 151,
- kCurObjDownLimit = 152,
- kCurLastCursor
-};
-
-void QuickTimeDecoder::updateQTVRCursor(int16 x, int16 y) {
- if (_qtvrType == QTVRType::OBJECT) {
- int tiltIdx = int((-_tiltAngle + 90.0) / 21) * 2;
-
- if (y < _curBbox.top)
- setCursor(tiltIdx == 16 ? kCurObjUpLimit : kCurObjUp);
- else if (y > _curBbox.bottom)
- setCursor(tiltIdx == 0 ? kCurObjDownLimit : kCurObjDown);
- else if (x < _curBbox.left)
- setCursor(kCurObjLeft90 + tiltIdx);
- else if (x > _curBbox.right)
- setCursor(kCurObjRight90 + tiltIdx);
- else
- setCursor(_isMouseButtonDown ? kCurGrab : kCurHand);
- }
-}
-
-void QuickTimeDecoder::cleanupCursors() {
- if (!_cursorCache)
- return;
-
- for (int i = 0; i < kCurLastCursor; i++)
- delete _cursorCache[i];
-
- free(_cursorCache);
- _cursorCache = nullptr;
-}
-
-void QuickTimeDecoder::setCursor(int curId) {
- if (_currentQTVRCursor == curId)
- return;
-
- _currentQTVRCursor = curId;
-
- if (!_dataBundle) {
- _dataBundle = Common::makeZipArchive(MACGUI_DATA_BUNDLE);
-
- if (!_dataBundle) {
- warning("QTVR: Couldn't load data bundle '%s'.", MACGUI_DATA_BUNDLE);
- }
- }
-
- if (!_cursorCache) {
- _cursorCache = (Graphics::Cursor **)calloc(kCurLastCursor, sizeof(Graphics::Cursor *));
-
- computeInteractivityZones();
- }
-
- if (curId >= kCurLastCursor)
- error("QTVR: Incorrect cursor ID: %d > %d", curId, kCurLastCursor);
-
- if (!_cursorCache[curId]) {
- Common::Path path(Common::String::format("qtvr/CURSOR%d_1.cur", curId));
-
- Common::SeekableReadStream *stream = _dataBundle->createReadStreamForMember(path);
-
- if (!stream) {
- warning("QTVR: Cannot load cursor ID %d, file '%s' does not exist", curId, path.toString().c_str());
- return;
- }
-
- Image::IcoCurDecoder decoder;
- if (!decoder.open(*stream, DisposeAfterUse::YES)) {
- warning("QTVR: Cannot load cursor ID %d, file '%s' bad format", curId, path.toString().c_str());
- return;
- }
-
- _cursorCache[curId] = decoder.loadItemAsCursor(0);
- }
-
- CursorMan.replaceCursor(_cursorCache[curId]);
- CursorMan.showMouse(true);
-}
-
-void QuickTimeDecoder::computeInteractivityZones() {
- _curBbox.left = MIN(20, getWidth() / 10);
- _curBbox.right = getWidth() - _curBbox.left;
-
- _curBbox.top = MIN(20, getHeight() / 10);
- _curBbox.bottom = getHeight() - _curBbox.top;
-}
-
} // End of namespace Video
diff --git a/video/qt_decoder.h b/video/qt_decoder.h
index aef82ff3cdf..fa8e7f239d3 100644
--- a/video/qt_decoder.h
+++ b/video/qt_decoder.h
@@ -124,6 +124,8 @@ private:
void updateAudioBuffer();
+ void closeQTVR();
+ void updateAngles();
void updateQTVRCursor(int16 x, int16 y);
void setCursor(int curId);
void cleanupCursors();
@@ -230,14 +232,6 @@ private:
mutable bool _dirtyPalette;
bool _reversed;
- void constructPanorama();
- void projectPanorama();
-
- Graphics::Surface *_constructedPano;
- Graphics::Surface *_projectedPano;
-
- bool _isPanoConstructed;
-
// Forced dithering of frames
byte *_forcedDitherPalette;
byte *_ditherTable;
@@ -257,6 +251,41 @@ private:
bool endOfCurEdit() const;
void checkEditListBounds();
};
+
+ class PanoTrackHandler {
+ public:
+ PanoTrackHandler(QuickTimeDecoder *decoder, Common::QuickTimeParser::Track *parent);
+ ~PanoTrackHandler();
+
+ uint16 getWidth() const;
+ uint16 getHeight() const;
+ Graphics::PixelFormat getPixelFormat() const;
+ bool setOutputPixelFormat(const Graphics::PixelFormat &format);
+ const Graphics::Surface *decodeNextFrame();
+ const byte *getPalette() const;
+ bool hasDirtyPalette() const { return _curPalette; }
+ bool canDither() const;
+ void setDither(const byte *palette);
+
+ Common::Rational getScaledWidth() const;
+ Common::Rational getScaledHeight() const;
+
+ private:
+ QuickTimeDecoder *_decoder;
+ Common::QuickTimeParser::Track *_parent;
+
+ const byte *_curPalette;
+
+ void constructPanorama();
+ void projectPanorama();
+
+ const Graphics::Surface *bufferNextFrame();
+
+ Graphics::Surface *_constructedPano;
+ Graphics::Surface *_projectedPano;
+
+ bool _isPanoConstructed;
+ };
};
} // End of namespace Video
diff --git a/video/qtvr_decoder.cpp b/video/qtvr_decoder.cpp
new file mode 100644
index 00000000000..e483aad016e
--- /dev/null
+++ b/video/qtvr_decoder.cpp
@@ -0,0 +1,432 @@
+/* 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/>.
+ *
+ */
+
+//
+// Partially based on ffmpeg code.
+//
+// Copyright (c) 2001 Fabrice Bellard.
+// First version by Francois Revol revol at free.fr
+// Seek function by Gael Chardon gael.dev at 4now.net
+//
+
+#include "video/qt_decoder.h"
+#include "video/qt_data.h"
+
+#include "audio/audiostream.h"
+
+#include "common/archive.h"
+#include "common/debug.h"
+#include "common/memstream.h"
+#include "common/system.h"
+#include "common/textconsole.h"
+#include "common/util.h"
+
+#include "common/compression/unzip.h"
+
+#include "graphics/cursorman.h"
+#include "image/icocur.h"
+
+// Video codecs
+#include "image/codecs/codec.h"
+
+namespace Video {
+
+static const char * const MACGUI_DATA_BUNDLE = "macgui.dat";
+
+////////////////////////////////////////////
+// QuickTimeDecoder
+////////////////////////////////////////////
+
+void QuickTimeDecoder::closeQTVR() {
+ delete _dataBundle;
+ _dataBundle = nullptr;
+ cleanupCursors();
+}
+
+void QuickTimeDecoder::updateAngles() {
+ _panAngle = (float)getCurrentColumn() / (float)_nav.columns * 360.0;
+ _tiltAngle = ((_nav.rows - 1) / 2.0 - (float)getCurrentRow()) / (float)(_nav.rows - 1) * 180.0;
+
+ debugC(1, kDebugLevelMacGUI, "QTVR: row: %d col: %d (%d x %d) pan: %f tilt: %f", getCurrentRow(), getCurrentColumn(), _nav.rows, _nav.columns, getPanAngle(), getTiltAngle());
+}
+
+void QuickTimeDecoder::handleMouseMove(int16 x, int16 y) {
+ if (_qtvrType != QTVRType::OBJECT)
+ return;
+
+ updateQTVRCursor(x, y);
+
+ if (!_isMouseButtonDown)
+ return;
+
+ VideoTrackHandler *track = (VideoTrackHandler *)_nextVideoTrack;
+
+ // HACK: FIXME: Hard coded for now
+ const int sensitivity = 10;
+ const float speedFactor = 0.1f;
+
+ int16 mouseDeltaX = x - _prevMouseX;
+ int16 mouseDeltaY = y - _prevMouseY;
+
+ float speedX = (float)mouseDeltaX * speedFactor;
+ float speedY = (float)mouseDeltaY * speedFactor;
+
+ bool changed = false;
+
+ if (ABS(mouseDeltaY) >= sensitivity) {
+ int newFrame = track->getCurFrame() - round(speedY) * _nav.columns;
+
+ if (newFrame >= 0 && newFrame < track->getFrameCount()) {
+ track->setCurFrame(newFrame);
+ changed = true;
+ }
+ }
+
+ if (ABS(mouseDeltaX) >= sensitivity) {
+ int currentRow = track->getCurFrame() / _nav.columns;
+ int currentRowStart = currentRow * _nav.columns;
+
+ int newFrame = (track->getCurFrame() - (int)roundf(speedX) - currentRowStart) % _nav.columns + currentRowStart;
+
+ if (newFrame >= 0 && newFrame < track->getFrameCount()) {
+ track->setCurFrame(newFrame);
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ _prevMouseX = x;
+ _prevMouseY = y;
+ }
+}
+
+void QuickTimeDecoder::handleMouseButton(bool isDown, int16 x, int16 y) {
+ if (isDown) {
+ if (y < _curBbox.top) {
+ setCurrentRow(getCurrentRow() + 1);
+ } else if (y > _curBbox.bottom) {
+ setCurrentRow(getCurrentRow() - 1);
+ } else if (x < _curBbox.left) {
+ setCurrentColumn((getCurrentColumn() + 1) % _nav.columns);
+ } else if (x > _curBbox.right) {
+ setCurrentColumn((getCurrentColumn() - 1 + _nav.columns) % _nav.columns);
+ } else {
+ _prevMouseX = x;
+ _prevMouseY = y;
+ _isMouseButtonDown = isDown;
+ }
+ } else {
+ _isMouseButtonDown = isDown;
+ }
+
+ updateQTVRCursor(x, y);
+}
+
+void QuickTimeDecoder::setCurrentRow(int row) {
+ VideoTrackHandler *track = (VideoTrackHandler *)_nextVideoTrack;
+
+ int currentColumn = track->getCurFrame() % _nav.columns;
+ int newFrame = row * _nav.columns + currentColumn;
+
+ if (newFrame >= 0 && newFrame < track->getFrameCount()) {
+ track->setCurFrame(newFrame);
+ }
+}
+
+void QuickTimeDecoder::setCurrentColumn(int column) {
+ VideoTrackHandler *track = (VideoTrackHandler *)_nextVideoTrack;
+
+ int currentRow = track->getCurFrame() / _nav.columns;
+ int newFrame = currentRow * _nav.columns + column;
+
+ if (newFrame >= 0 && newFrame < track->getFrameCount()) {
+ track->setCurFrame(newFrame);
+ }
+}
+
+void QuickTimeDecoder::nudge(const Common::String &direction) {
+ VideoTrackHandler *track = (VideoTrackHandler *)_nextVideoTrack;
+
+ int curFrame = track->getCurFrame();
+ int currentRow = curFrame / _nav.columns;
+ int currentRowStart = currentRow * _nav.columns;
+ int newFrame = curFrame;
+
+ if (direction.equalsIgnoreCase("left")) {
+ newFrame = (curFrame - 1 - currentRowStart) % _nav.columns + currentRowStart;
+ } else if (direction.equalsIgnoreCase("right")) {
+ newFrame = (curFrame + 1 - currentRowStart) % _nav.columns + currentRowStart;
+ } else if (direction.equalsIgnoreCase("top")) {
+ newFrame = curFrame - _nav.columns;
+ if (newFrame < 0)
+ return;
+ } else if (direction.equalsIgnoreCase("bottom")) {
+ newFrame = curFrame + _nav.columns;
+ if (newFrame >= track->getFrameCount())
+ return;
+ } else {
+ error("QuickTimeDecoder::nudge(): Invald direction: ('%s')!", direction.c_str());
+ }
+
+ track->setCurFrame(newFrame);
+}
+
+QuickTimeDecoder::NodeData QuickTimeDecoder::getNodeData(uint32 nodeID) {
+ for (const auto &sample : _panoTrack->panoSamples) {
+ if (sample.hdr.nodeID == nodeID) {
+ return {
+ nodeID,
+ sample.hdr.defHPan,
+ sample.hdr.defVPan,
+ sample.hdr.defZoom,
+ sample.hdr.minHPan,
+ sample.hdr.minVPan,
+ sample.hdr.maxHPan,
+ sample.hdr.maxVPan,
+ sample.hdr.minZoom,
+ sample.strTable.getString(sample.hdr.nameStrOffset)};
+ }
+ }
+
+ error("QuickTimeDecoder::getNodeData(): Node with nodeID %d not found!", nodeID);
+
+ return {};
+}
+
+QuickTimeDecoder::PanoTrackHandler::PanoTrackHandler(QuickTimeDecoder *decoder, Common::QuickTimeParser::Track *parent) : _decoder(decoder), _parent(parent) {
+ if (decoder->_qtvrType != QTVRType::PANORAMA)
+ error("QuickTimeDecoder::PanoTrackHandler: Incorrect track passed");
+
+ _isPanoConstructed = false;
+
+ _constructedPano = nullptr;
+ _projectedPano = nullptr;
+
+ constructPanorama();
+}
+
+QuickTimeDecoder::PanoTrackHandler::~PanoTrackHandler() {
+ if (_isPanoConstructed) {
+ _constructedPano->free();
+ delete _constructedPano;
+ }
+
+ if (_projectedPano) {
+ _projectedPano->free();
+ delete _projectedPano;
+ }
+}
+
+uint16 QuickTimeDecoder::PanoTrackHandler::getWidth() const {
+ return getScaledWidth().toInt();
+}
+
+uint16 QuickTimeDecoder::PanoTrackHandler::getHeight() const {
+ return getScaledHeight().toInt();
+}
+
+Graphics::PixelFormat QuickTimeDecoder::PanoTrackHandler::getPixelFormat() const {
+ return ((VideoSampleDesc *)_parent->sampleDescs[0])->_videoCodec->getPixelFormat();
+}
+
+Common::Rational QuickTimeDecoder::PanoTrackHandler::getScaledWidth() const {
+ return Common::Rational(_parent->width) / _parent->scaleFactorX;
+}
+
+Common::Rational QuickTimeDecoder::PanoTrackHandler::getScaledHeight() const {
+ return Common::Rational(_parent->height) / _parent->scaleFactorY;
+}
+
+const Graphics::Surface *QuickTimeDecoder::PanoTrackHandler::decodeNextFrame() {
+ if (!_isPanoConstructed)
+ return nullptr;
+
+ if (_projectedPano) {
+ _projectedPano->free();
+ delete _projectedPano;
+ }
+
+ projectPanorama();
+ return _projectedPano;
+}
+
+const Graphics::Surface *QuickTimeDecoder::PanoTrackHandler::bufferNextFrame() {
+ return nullptr;
+}
+
+void QuickTimeDecoder::PanoTrackHandler::constructPanorama() {
+ int16 totalWidth = getHeight() * _parent->frameCount;
+ int16 totalHeight = getWidth();
+
+ warning("construct, w: %d, h: %d", totalWidth, totalHeight);
+
+ if (totalWidth <= 0 || totalHeight <= 0)
+ return;
+
+ _constructedPano = new Graphics::Surface();
+ _constructedPano->create(totalWidth, totalHeight, getPixelFormat());
+
+ for (uint32 frameIndex = 0; frameIndex < _parent->frameCount; frameIndex++) {
+ const Graphics::Surface *frame = bufferNextFrame();
+
+ for (int16 y = 0; y < frame->h; y++) {
+ for (int16 x = 0; x < frame->w; x++) {
+
+ int setX = (totalWidth - 1) - (frameIndex * _parent->height + y);
+ int setY = x;
+
+ if (setX >= 0 && setX < _constructedPano->w && setY >= 0 && setY < _constructedPano->h) {
+ uint32 pixel = frame->getPixel(x, y);
+ _constructedPano->setPixel(setX, setY, pixel);
+ }
+ }
+ }
+ }
+
+ _isPanoConstructed = true;
+}
+
+void QuickTimeDecoder::PanoTrackHandler::projectPanorama() {
+ if (!_isPanoConstructed)
+ return;
+
+ _projectedPano = new Graphics::Surface();
+ _projectedPano->create(_constructedPano->w, _constructedPano->h, _constructedPano->format);
+
+ const float c = _projectedPano->w;
+ const float r = c / (2 * M_PI);
+
+ // HACK: FIXME: Hard coded for now
+ const float d = 500.0f;
+
+ for (int16 y = 0; y < _projectedPano->h; y++) {
+ for (int16 x = 0; x < _projectedPano->w; x++) {
+ double u = atan(x / d) / (2.0 * M_PI);
+ double v = y * r * cos(u) / d;
+
+ int setX = round(u * _constructedPano->w);
+ int setY = round(v);
+
+ if (setX >= 0 && setX < _constructedPano->w && setY >= 0 && setY < _constructedPano->h) {
+ uint32 pixel = _constructedPano->getPixel(setX, setY);
+ _projectedPano->setPixel(x, y, pixel);
+ }
+ }
+ }
+}
+
+enum {
+ kCurHand = 129,
+ kCurGrab = 130,
+ kCurObjUp = 131,
+ kCurObjDown = 132,
+ kCurObjLeft90 = 133,
+ kCurObjRight90 = 134,
+ kCurObjLeftM90 = 149,
+ kCurObjRightM90 = 150,
+ kCurObjUpLimit = 151,
+ kCurObjDownLimit = 152,
+ kCurLastCursor
+};
+
+void QuickTimeDecoder::updateQTVRCursor(int16 x, int16 y) {
+ if (_qtvrType == QTVRType::OBJECT) {
+ int tiltIdx = int((-_tiltAngle + 90.0) / 21) * 2;
+
+ if (y < _curBbox.top)
+ setCursor(tiltIdx == 16 ? kCurObjUpLimit : kCurObjUp);
+ else if (y > _curBbox.bottom)
+ setCursor(tiltIdx == 0 ? kCurObjDownLimit : kCurObjDown);
+ else if (x < _curBbox.left)
+ setCursor(kCurObjLeft90 + tiltIdx);
+ else if (x > _curBbox.right)
+ setCursor(kCurObjRight90 + tiltIdx);
+ else
+ setCursor(_isMouseButtonDown ? kCurGrab : kCurHand);
+ }
+}
+
+void QuickTimeDecoder::cleanupCursors() {
+ if (!_cursorCache)
+ return;
+
+ for (int i = 0; i < kCurLastCursor; i++)
+ delete _cursorCache[i];
+
+ free(_cursorCache);
+ _cursorCache = nullptr;
+}
+
+void QuickTimeDecoder::setCursor(int curId) {
+ if (_currentQTVRCursor == curId)
+ return;
+
+ _currentQTVRCursor = curId;
+
+ if (!_dataBundle) {
+ _dataBundle = Common::makeZipArchive(MACGUI_DATA_BUNDLE);
+
+ if (!_dataBundle) {
+ warning("QTVR: Couldn't load data bundle '%s'.", MACGUI_DATA_BUNDLE);
+ }
+ }
+
+ if (!_cursorCache) {
+ _cursorCache = (Graphics::Cursor **)calloc(kCurLastCursor, sizeof(Graphics::Cursor *));
+
+ computeInteractivityZones();
+ }
+
+ if (curId >= kCurLastCursor)
+ error("QTVR: Incorrect cursor ID: %d > %d", curId, kCurLastCursor);
+
+ if (!_cursorCache[curId]) {
+ Common::Path path(Common::String::format("qtvr/CURSOR%d_1.cur", curId));
+
+ Common::SeekableReadStream *stream = _dataBundle->createReadStreamForMember(path);
+
+ if (!stream) {
+ warning("QTVR: Cannot load cursor ID %d, file '%s' does not exist", curId, path.toString().c_str());
+ return;
+ }
+
+ Image::IcoCurDecoder decoder;
+ if (!decoder.open(*stream, DisposeAfterUse::YES)) {
+ warning("QTVR: Cannot load cursor ID %d, file '%s' bad format", curId, path.toString().c_str());
+ return;
+ }
+
+ _cursorCache[curId] = decoder.loadItemAsCursor(0);
+ }
+
+ CursorMan.replaceCursor(_cursorCache[curId]);
+ CursorMan.showMouse(true);
+}
+
+void QuickTimeDecoder::computeInteractivityZones() {
+ _curBbox.left = MIN(20, getWidth() / 10);
+ _curBbox.right = getWidth() - _curBbox.left;
+
+ _curBbox.top = MIN(20, getHeight() / 10);
+ _curBbox.bottom = getHeight() - _curBbox.top;
+}
+
+} // End of namespace Video
More information about the Scummvm-git-logs
mailing list