[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