[Scummvm-git-logs] scummvm master -> e0091f244440bef46498393609c150888c04937a
neuromancer
noreply at scummvm.org
Thu Mar 26 17:17:11 UTC 2026
This automated email contains information about 7 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
7ecf4d98cc FREESCAPE: enable sound for eclipse cpc
5d663b7ae4 FREESCAPE: fix water indicator in eclipse cpc
f3eb3b27b6 FREESCAPE: implemented heartbeat in eclipse cpc
2d9643afca FREESCAPE: implemented heartbeat in eclipse zx
8b48455b1f FREESCAPE: completed shake off effect for shaders and tinygl
f5b782fee5 FREESCAPE: draw the UI correctly when riddles are displayed
e0091f2444 FREESCAPE: pause game while text is displayed
Commit: 7ecf4d98cc050e8efc232e3c16cc5f159b0ef1bc
https://github.com/scummvm/scummvm/commit/7ecf4d98cc050e8efc232e3c16cc5f159b0ef1bc
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-03-26T18:16:56+01:00
Commit Message:
FREESCAPE: enable sound for eclipse cpc
Changed paths:
engines/freescape/games/eclipse/cpc.cpp
diff --git a/engines/freescape/games/eclipse/cpc.cpp b/engines/freescape/games/eclipse/cpc.cpp
index 96460fe0a55..2c1af76c80e 100644
--- a/engines/freescape/games/eclipse/cpc.cpp
+++ b/engines/freescape/games/eclipse/cpc.cpp
@@ -107,7 +107,7 @@ void EclipseEngine::loadAssetsCPCFullGame() {
loadFonts(&file, 0x6076);
loadMessagesFixedSize(&file, 0x326, 16, 30);
load8bitBinary(&file, 0x626e, 16);
- // TODO: loadSoundsCPC for full game - need to determine table offsets from TECODE.BIN
+ loadSoundsCPC(&file, 0x07C9, 104, 0x0831, 165, 0x0736, 147);
}
loadColorPalette();
Commit: 5d663b7ae440255f37887c677d9d5f75d4684bc4
https://github.com/scummvm/scummvm/commit/5d663b7ae440255f37887c677d9d5f75d4684bc4
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-03-26T18:16:56+01:00
Commit Message:
FREESCAPE: fix water indicator in eclipse cpc
Changed paths:
engines/freescape/games/eclipse/cpc.cpp
diff --git a/engines/freescape/games/eclipse/cpc.cpp b/engines/freescape/games/eclipse/cpc.cpp
index 2c1af76c80e..2ae3e63fb01 100644
--- a/engines/freescape/games/eclipse/cpc.cpp
+++ b/engines/freescape/games/eclipse/cpc.cpp
@@ -212,11 +212,18 @@ void EclipseEngine::drawCPCUI(Graphics::Surface *surface) {
drawIndicator(surface, 45, 4, 12);
drawEclipseIndicator(surface, 228, 0, front, other);
+ int energy = _gameStateVars[k8bitVariableEnergy];
+ if (energy < 0)
+ energy = 0;
+
+ _gfx->readFromPalette(19, r, g, b);
+ uint32 blue = _gfx->_texturePixelFormat.ARGBToColor(0xFF, r, g, b);
+
Common::Rect jarBackground(124, 165, 148, 192);
surface->fillRect(jarBackground, back);
- Common::Rect jarWater(124, 192 - _gameStateVars[k8bitVariableEnergy], 148, 192);
- surface->fillRect(jarWater, color);
+ Common::Rect jarWater(124, 192 - energy, 148, 192);
+ surface->fillRect(jarWater, blue);
surface->fillRect(Common::Rect(225, 168, 235, 187), front);
drawCompass(surface, 229, 177, _yaw, 10, back);
Commit: f3eb3b27b612df74a902e6ec11549156a5892512
https://github.com/scummvm/scummvm/commit/f3eb3b27b612df74a902e6ec11549156a5892512
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-03-26T18:16:56+01:00
Commit Message:
FREESCAPE: implemented heartbeat in eclipse cpc
Changed paths:
engines/freescape/games/eclipse/cpc.cpp
engines/freescape/games/eclipse/eclipse.h
diff --git a/engines/freescape/games/eclipse/cpc.cpp b/engines/freescape/games/eclipse/cpc.cpp
index 2ae3e63fb01..7f03f6d37b5 100644
--- a/engines/freescape/games/eclipse/cpc.cpp
+++ b/engines/freescape/games/eclipse/cpc.cpp
@@ -63,6 +63,69 @@ byte kCPCPaletteEclipseBorderData[4][3] = {
+void EclipseEngine::loadHeartFramesCPC(Common::SeekableReadStream *file, int restOffset, int beatOffset) {
+ // Decode into _eclipseSprites[0] (beat) and _eclipseSprites[1] (rest),
+ // matching the Atari ST convention for future unification.
+ // Same CLUT8âARGB approach as Castle's loadFrameWithHeaderCPCIndexed + convertCPCSprite.
+ int offsets[2] = { beatOffset, restOffset };
+
+ byte palette[4 * 3];
+ for (int c = 0; c < 4; c++) {
+ uint8 r, g, b;
+ _gfx->selectColorFromFourColorPalette(c, r, g, b);
+ palette[c * 3 + 0] = r;
+ palette[c * 3 + 1] = g;
+ palette[c * 3 + 2] = b;
+ }
+
+ for (int f = 0; f < 2; f++) {
+ file->seek(offsets[f]);
+ int height = file->readByte();
+ int widthBytes = file->readByte();
+
+ // Decode CPC mode 1 bytes into CLUT8 indexed surface (values 0-3)
+ Graphics::ManagedSurface clut8;
+ clut8.create(widthBytes * 4, height, Graphics::PixelFormat::createFormatCLUT8());
+ for (int y = 0; y < height; y++)
+ for (int col = 0; col < widthBytes; col++) {
+ byte cpc_byte = file->readByte();
+ for (int i = 0; i < 4; i++)
+ clut8.setPixel(col * 4 + i, y, getCPCPixelMode1(cpc_byte, i));
+ }
+
+ clut8.setPalette(palette, 0, 4);
+
+ // Convert CLUT8 to target pixel format
+ Graphics::Surface *converted = _gfx->convertImageFormatIfNecessary(&clut8);
+ auto *surf = new Graphics::ManagedSurface();
+ surf->copyFrom(*converted);
+ converted->free();
+ delete converted;
+
+ _eclipseSprites.push_back(surf);
+ }
+}
+
+void EclipseEngine::drawHeartIndicator(Graphics::Surface *surface, int x, int y) {
+ // CPC original: timer counts down from shield at 50Hz (_ticks rate).
+ // Beat frame shown for last 5 ticks of each cycle, rest frame for the remainder.
+ // Lower shield = faster heartbeat. At shield <= 5, heart beats constantly.
+ if (_eclipseSprites.size() < 2)
+ return;
+
+ int shield = _gameStateVars[k8bitVariableShield];
+ int beatCycle = MAX(shield, 1);
+ int phase = _ticks % beatCycle;
+ int beatStart = MAX(beatCycle - 5, 0);
+ int frame = (phase >= beatStart) ? 0 : 1;
+
+ if (phase == beatStart)
+ playSound(1, false, _soundFxHandle);
+
+ surface->copyRectToSurface(*_eclipseSprites[frame], x, y,
+ Common::Rect(_eclipseSprites[frame]->w, _eclipseSprites[frame]->h));
+}
+
void EclipseEngine::loadAssetsCPCFullGame() {
Common::File file;
@@ -113,6 +176,9 @@ void EclipseEngine::loadAssetsCPCFullGame() {
loadColorPalette();
swapPalette(1);
+ if (!isEclipse2())
+ loadHeartFramesCPC(&file, 0x0CDB, 0x0D0D);
+
_indicators.push_back(loadBundledImage("eclipse_ankh_indicator"));
for (auto &it : _indicators)
@@ -142,6 +208,7 @@ void EclipseEngine::loadAssetsCPCDemo() {
loadSoundsCPC(&file, 0x0805, 104, 0x086D, 165, 0x0772, 147);
loadColorPalette();
swapPalette(1);
+ loadHeartFramesCPC(&file, 0x0D17, 0x0D49);
// This patch forces a solid color to the bottom of the chest in the area 5
// It was transparent in the original game
@@ -225,6 +292,8 @@ void EclipseEngine::drawCPCUI(Graphics::Surface *surface) {
Common::Rect jarWater(124, 192 - energy, 148, 192);
surface->fillRect(jarWater, blue);
+ drawHeartIndicator(surface, 176, 168);
+
surface->fillRect(Common::Rect(225, 168, 235, 187), front);
drawCompass(surface, 229, 177, _yaw, 10, back);
diff --git a/engines/freescape/games/eclipse/eclipse.h b/engines/freescape/games/eclipse/eclipse.h
index c8398c6828d..298b8d8cf68 100644
--- a/engines/freescape/games/eclipse/eclipse.h
+++ b/engines/freescape/games/eclipse/eclipse.h
@@ -97,6 +97,8 @@ public:
void drawScoreString(int score, int x, int y, uint32 front, uint32 back, Graphics::Surface *surface);
soundFx *load1bPCM(Common::SeekableReadStream *file, int offset);
+ void loadHeartFramesCPC(Common::SeekableReadStream *file, int restOffset, int beatOffset);
+ void drawHeartIndicator(Graphics::Surface *surface, int x, int y);
Common::Array<byte> _musicData; // TEMUSIC.ST TEXT segment (Atari ST)
Commit: 2d9643afcaa6120b739d413cd03759c2f65b0ef5
https://github.com/scummvm/scummvm/commit/2d9643afcaa6120b739d413cd03759c2f65b0ef5
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-03-26T18:16:57+01:00
Commit Message:
FREESCAPE: implemented heartbeat in eclipse zx
Changed paths:
engines/freescape/freescape.cpp
engines/freescape/freescape.h
engines/freescape/games/castle/castle.cpp
engines/freescape/games/castle/castle.h
engines/freescape/games/eclipse/cpc.cpp
engines/freescape/games/eclipse/eclipse.cpp
engines/freescape/games/eclipse/eclipse.h
engines/freescape/games/eclipse/zx.cpp
diff --git a/engines/freescape/freescape.cpp b/engines/freescape/freescape.cpp
index d97a10aa3de..49e9dafeea0 100644
--- a/engines/freescape/freescape.cpp
+++ b/engines/freescape/freescape.cpp
@@ -1290,6 +1290,29 @@ Graphics::ManagedSurface *FreescapeEngine::loadAndConvertScrImage(Common::Seekab
return surface;
}
+Graphics::ManagedSurface *FreescapeEngine::loadFrame(Common::SeekableReadStream *file, Graphics::ManagedSurface *surface, int width, int height, uint32 front) {
+ for (int i = 0; i < width * height; i++) {
+ byte color = file->readByte();
+ for (int n = 0; n < 8; n++) {
+ int y = i / width;
+ int x = (i % width) * 8 + (7 - n);
+ if ((color & (1 << n)))
+ surface->setPixel(x, y, front);
+ }
+ }
+ return surface;
+}
+
+Graphics::ManagedSurface *FreescapeEngine::loadFrameCPCIndexed(Common::SeekableReadStream *file, Graphics::ManagedSurface *surface, int widthBytes, int height) {
+ for (int y = 0; y < height; y++)
+ for (int col = 0; col < widthBytes; col++) {
+ byte cpc_byte = file->readByte();
+ for (int i = 0; i < 4; i++)
+ surface->setPixel(col * 4 + i, y, getCPCPixel(cpc_byte, i, true));
+ }
+ return surface;
+}
+
void FreescapeEngine::getTimeFromCountdown(int &seconds, int &minutes, int &hours) {
int countdown = _countdown;
int h = countdown <= 0 ? 0 : countdown / 3600;
diff --git a/engines/freescape/freescape.h b/engines/freescape/freescape.h
index 61ad126f2a4..3e23d43c2e1 100644
--- a/engines/freescape/freescape.h
+++ b/engines/freescape/freescape.h
@@ -281,6 +281,8 @@ public:
byte *getPaletteFromNeoImage(Common::SeekableReadStream *stream, int offset);
Graphics::ManagedSurface *loadAndConvertNeoImage(Common::SeekableReadStream *stream, int offset, byte *palette = nullptr);
Graphics::ManagedSurface *loadAndConvertScrImage(Common::SeekableReadStream *stream);
+ Graphics::ManagedSurface *loadFrame(Common::SeekableReadStream *file, Graphics::ManagedSurface *surface, int width, int height, uint32 front);
+ Graphics::ManagedSurface *loadFrameCPCIndexed(Common::SeekableReadStream *file, Graphics::ManagedSurface *surface, int widthBytes, int height);
Graphics::ManagedSurface *loadAndConvertDoodleImage(Common::SeekableReadStream *bitmap, Common::SeekableReadStream *color1, Common::SeekableReadStream *color2, byte *palette);
void loadPalettes(Common::SeekableReadStream *file, int offset);
diff --git a/engines/freescape/games/castle/castle.cpp b/engines/freescape/games/castle/castle.cpp
index 4ba98a56eda..0b72e67c008 100644
--- a/engines/freescape/games/castle/castle.cpp
+++ b/engines/freescape/games/castle/castle.cpp
@@ -293,18 +293,7 @@ Common::Array<Graphics::ManagedSurface *> CastleEngine::loadFramesWithHeader(Com
return frames;
}
-Graphics::ManagedSurface *CastleEngine::loadFrame(Common::SeekableReadStream *file, Graphics::ManagedSurface *surface, int width, int height, uint32 front) {
- for (int i = 0; i < width * height; i++) {
- byte color = file->readByte();
- for (int n = 0; n < 8; n++) {
- int y = i / width;
- int x = (i % width) * 8 + (7 - n);
- if ((color & (1 << n)))
- surface->setPixel(x, y, front);
- }
- }
- return surface;
-}
+// loadFrame moved to FreescapeEngine (freescape.cpp)
Graphics::ManagedSurface *CastleEngine::loadFrameWithHeaderCPC(Common::SeekableReadStream *file, int pos, const uint32 *cpcPalette) {
Graphics::ManagedSurface *surface = new Graphics::ManagedSurface();
@@ -383,13 +372,7 @@ Graphics::ManagedSurface *CastleEngine::loadFrameWithHeaderCPCIndexed(Common::Se
Graphics::ManagedSurface *surface = new Graphics::ManagedSurface();
surface->create(w * 4, h, Graphics::PixelFormat::createFormatCLUT8());
surface->fillRect(Common::Rect(0, 0, w * 4, h), 0);
- for (int y = 0; y < h; y++)
- for (int col = 0; col < w; col++) {
- byte cpc_byte = file->readByte();
- for (int i = 0; i < 4; i++)
- surface->setPixel(col * 4 + i, y, getCPCPixel(cpc_byte, i, true));
- }
- return surface;
+ return loadFrameCPCIndexed(file, surface, w, h);
}
Common::Array<Graphics::ManagedSurface *> CastleEngine::loadFramesWithHeaderCPCIndexed(Common::SeekableReadStream *file, int pos, int numFrames) {
@@ -403,12 +386,7 @@ Common::Array<Graphics::ManagedSurface *> CastleEngine::loadFramesWithHeaderCPCI
Graphics::ManagedSurface *surface = new Graphics::ManagedSurface();
surface->create(w * 4, h, Graphics::PixelFormat::createFormatCLUT8());
surface->fillRect(Common::Rect(0, 0, w * 4, h), 0);
- for (int y = 0; y < h; y++)
- for (int col = 0; col < w; col++) {
- byte cpc_byte = file->readByte();
- for (int i = 0; i < 4; i++)
- surface->setPixel(col * 4 + i, y, getCPCPixel(cpc_byte, i, true));
- }
+ loadFrameCPCIndexed(file, surface, w, h);
frames.push_back(surface);
}
return frames;
diff --git a/engines/freescape/games/castle/castle.h b/engines/freescape/games/castle/castle.h
index 8a0d150b367..dc19aaf8fb4 100644
--- a/engines/freescape/games/castle/castle.h
+++ b/engines/freescape/games/castle/castle.h
@@ -108,7 +108,6 @@ public:
Common::Array<Graphics::ManagedSurface *> loadFramesWithHeader(Common::SeekableReadStream *file, int pos, int numFrames, uint32 front, uint32 back);
Graphics::ManagedSurface *loadFrameWithHeader(Common::SeekableReadStream *file, int pos, uint32 front, uint32 back);
- Graphics::ManagedSurface *loadFrame(Common::SeekableReadStream *file, Graphics::ManagedSurface *surface, int width, int height, uint32 back);
// CPC-specific frame loading (Mode 1: 4 pixels per byte)
// cpcPalette is a 4-entry array mapping CPC ink numbers (0-3) to ARGB colors
diff --git a/engines/freescape/games/eclipse/cpc.cpp b/engines/freescape/games/eclipse/cpc.cpp
index 7f03f6d37b5..628a43e10aa 100644
--- a/engines/freescape/games/eclipse/cpc.cpp
+++ b/engines/freescape/games/eclipse/cpc.cpp
@@ -66,7 +66,8 @@ byte kCPCPaletteEclipseBorderData[4][3] = {
void EclipseEngine::loadHeartFramesCPC(Common::SeekableReadStream *file, int restOffset, int beatOffset) {
// Decode into _eclipseSprites[0] (beat) and _eclipseSprites[1] (rest),
// matching the Atari ST convention for future unification.
- // Same CLUT8âARGB approach as Castle's loadFrameWithHeaderCPCIndexed + convertCPCSprite.
+ // Uses loadFrameCPCIndexed (shared with Castle) for pixel decoding,
+ // then converts CLUT8âARGB via convertImageFormatIfNecessary.
int offsets[2] = { beatOffset, restOffset };
byte palette[4 * 3];
@@ -83,19 +84,11 @@ void EclipseEngine::loadHeartFramesCPC(Common::SeekableReadStream *file, int res
int height = file->readByte();
int widthBytes = file->readByte();
- // Decode CPC mode 1 bytes into CLUT8 indexed surface (values 0-3)
Graphics::ManagedSurface clut8;
clut8.create(widthBytes * 4, height, Graphics::PixelFormat::createFormatCLUT8());
- for (int y = 0; y < height; y++)
- for (int col = 0; col < widthBytes; col++) {
- byte cpc_byte = file->readByte();
- for (int i = 0; i < 4; i++)
- clut8.setPixel(col * 4 + i, y, getCPCPixelMode1(cpc_byte, i));
- }
-
+ loadFrameCPCIndexed(file, &clut8, widthBytes, height);
clut8.setPalette(palette, 0, 4);
- // Convert CLUT8 to target pixel format
Graphics::Surface *converted = _gfx->convertImageFormatIfNecessary(&clut8);
auto *surf = new Graphics::ManagedSurface();
surf->copyFrom(*converted);
@@ -106,26 +99,6 @@ void EclipseEngine::loadHeartFramesCPC(Common::SeekableReadStream *file, int res
}
}
-void EclipseEngine::drawHeartIndicator(Graphics::Surface *surface, int x, int y) {
- // CPC original: timer counts down from shield at 50Hz (_ticks rate).
- // Beat frame shown for last 5 ticks of each cycle, rest frame for the remainder.
- // Lower shield = faster heartbeat. At shield <= 5, heart beats constantly.
- if (_eclipseSprites.size() < 2)
- return;
-
- int shield = _gameStateVars[k8bitVariableShield];
- int beatCycle = MAX(shield, 1);
- int phase = _ticks % beatCycle;
- int beatStart = MAX(beatCycle - 5, 0);
- int frame = (phase >= beatStart) ? 0 : 1;
-
- if (phase == beatStart)
- playSound(1, false, _soundFxHandle);
-
- surface->copyRectToSurface(*_eclipseSprites[frame], x, y,
- Common::Rect(_eclipseSprites[frame]->w, _eclipseSprites[frame]->h));
-}
-
void EclipseEngine::loadAssetsCPCFullGame() {
Common::File file;
diff --git a/engines/freescape/games/eclipse/eclipse.cpp b/engines/freescape/games/eclipse/eclipse.cpp
index bf093963bbd..290b8810fa2 100644
--- a/engines/freescape/games/eclipse/eclipse.cpp
+++ b/engines/freescape/games/eclipse/eclipse.cpp
@@ -797,6 +797,27 @@ void EclipseEngine::drawIndicator(Graphics::Surface *surface, int xPosition, int
}
}
+void EclipseEngine::drawHeartIndicator(Graphics::Surface *surface, int x, int y) {
+ // Heartbeat animation shared across platforms.
+ // Timer counts down from shield at 50Hz (_ticks rate).
+ // Beat frame shown for last 5 ticks of each cycle, rest frame for the remainder.
+ // Lower shield = faster heartbeat. At shield <= 5, heart beats constantly.
+ if (_eclipseSprites.size() < 2)
+ return;
+
+ int shield = _gameStateVars[k8bitVariableShield];
+ int beatCycle = MAX(shield, 1);
+ int phase = _ticks % beatCycle;
+ int beatStart = MAX(beatCycle - 5, 0);
+ int frame = (phase >= beatStart) ? 0 : 1;
+
+ if (phase == beatStart)
+ playSound(1, false, _soundFxHandle);
+
+ surface->copyRectToSurface(*_eclipseSprites[frame], x, y,
+ Common::Rect(_eclipseSprites[frame]->w, _eclipseSprites[frame]->h));
+}
+
void EclipseEngine::drawSensorShoot(Sensor *sensor) {
Math::Vector3d target;
float distance = 5;
diff --git a/engines/freescape/games/eclipse/eclipse.h b/engines/freescape/games/eclipse/eclipse.h
index 298b8d8cf68..00d8fa8e421 100644
--- a/engines/freescape/games/eclipse/eclipse.h
+++ b/engines/freescape/games/eclipse/eclipse.h
@@ -98,6 +98,7 @@ public:
soundFx *load1bPCM(Common::SeekableReadStream *file, int offset);
void loadHeartFramesCPC(Common::SeekableReadStream *file, int restOffset, int beatOffset);
+ void loadHeartFramesZX(Common::SeekableReadStream *file, int restOffset, int beatOffset);
void drawHeartIndicator(Graphics::Surface *surface, int x, int y);
Common::Array<byte> _musicData; // TEMUSIC.ST TEXT segment (Atari ST)
diff --git a/engines/freescape/games/eclipse/zx.cpp b/engines/freescape/games/eclipse/zx.cpp
index ae33ab9dadf..6b25aae7d68 100644
--- a/engines/freescape/games/eclipse/zx.cpp
+++ b/engines/freescape/games/eclipse/zx.cpp
@@ -52,6 +52,36 @@ void EclipseEngine::initZX() {
_soundIndexMissionComplete = 16;
}
+void EclipseEngine::loadHeartFramesZX(Common::SeekableReadStream *file, int restOffset, int beatOffset) {
+ // ZX monochrome heart sprites with 2-byte header (height, width_bytes).
+ // Stores into _eclipseSprites[0] (beat) and [1] (rest), matching Atari convention.
+ // Uses FreescapeEngine::loadFrame for the monochrome pixel decoding.
+ //
+ // The two frames have opposite bit polarity:
+ // - BEAT: "1" bits = heart shape (ink/yellow), "0" = background (paper/red)
+ // - REST: "1" bits = background (paper/red), "0" = small heart outline (ink/yellow)
+ // So front/back colors are swapped between frames.
+ int offsets[2] = { beatOffset, restOffset };
+
+ uint32 yellow = _gfx->_texturePixelFormat.ARGBToColor(0xFF, 0xd8, 0xd8, 0x00);
+ uint32 red = _gfx->_texturePixelFormat.ARGBToColor(0xFF, 0xd8, 0x00, 0x00);
+ uint32 frontColors[2] = { red, red };
+ uint32 backColors[2] = { yellow, yellow };
+
+ for (int f = 0; f < 2; f++) {
+ file->seek(offsets[f]);
+ int height = file->readByte();
+ int widthBytes = file->readByte();
+
+ auto *surf = new Graphics::ManagedSurface();
+ surf->create(widthBytes * 8, height, _gfx->_texturePixelFormat);
+ surf->fillRect(Common::Rect(0, 0, widthBytes * 8, height), backColors[f]);
+
+ loadFrame(file, surf, widthBytes, height, frontColors[f]);
+ _eclipseSprites.push_back(surf);
+ }
+}
+
void EclipseEngine::loadAssetsZXFullGame() {
Common::File file;
@@ -83,6 +113,7 @@ void EclipseEngine::loadAssetsZXFullGame() {
loadFonts(&file, 0x6163);
loadSpeakerFxZX(&file, 0x816, 0x86a);
load8bitBinary(&file, 0x635b, 4);
+ loadHeartFramesZX(&file, 0x0D62, 0x0D7C);
// These paper colors are also invalid, but to signal the use of a special effect (only in zx release)
_areaMap[42]->_paperColor = 0;
@@ -213,6 +244,8 @@ void EclipseEngine::drawZXUI(Graphics::Surface *surface) {
surface->fillRect(Common::Rect(227, 168, 235, 187), gray);
drawCompass(surface, 231, 177, _yaw, 10, back);
+ drawHeartIndicator(surface, 176, 167);
+
drawIndicator(surface, 65, 7, 8);
drawEclipseIndicator(surface, 215, 3, front, gray);
}
Commit: 8b48455b1f845ca70009d3806585a36952190a14
https://github.com/scummvm/scummvm/commit/8b48455b1f845ca70009d3806585a36952190a14
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-03-26T18:16:57+01:00
Commit Message:
FREESCAPE: completed shake off effect for shaders and tinygl
Changed paths:
engines/freescape/gfx_opengl.cpp
engines/freescape/gfx_opengl_shaders.cpp
engines/freescape/gfx_tinygl.cpp
engines/freescape/shaders/freescape_triangle.vertex
diff --git a/engines/freescape/gfx_opengl.cpp b/engines/freescape/gfx_opengl.cpp
index 3bf43dcd3e0..40ce2ca2186 100644
--- a/engines/freescape/gfx_opengl.cpp
+++ b/engines/freescape/gfx_opengl.cpp
@@ -276,7 +276,7 @@ void OpenGLRenderer::positionCamera(const Math::Vector3d &pos, const Math::Vecto
GLfloat projMatrix[16];
glGetFloatv(GL_PROJECTION_MATRIX, projMatrix);
glLoadIdentity();
- glTranslatef(_shakeOffset.x * 0.05f, _shakeOffset.y * 0.05f, 0.0f);
+ glTranslatef(_shakeOffset.x * 0.025f, _shakeOffset.y * 0.025f, 0.0f);
glMultMatrixf(projMatrix);
glMatrixMode(GL_MODELVIEW);
}
diff --git a/engines/freescape/gfx_opengl_shaders.cpp b/engines/freescape/gfx_opengl_shaders.cpp
index 16976d074ec..9ed3d1464d5 100644
--- a/engines/freescape/gfx_opengl_shaders.cpp
+++ b/engines/freescape/gfx_opengl_shaders.cpp
@@ -305,7 +305,12 @@ void OpenGLShaderRenderer::positionCamera(const Math::Vector3d &pos, const Math:
model.transpose();
_mvpMatrix = proj * model;
_mvpMatrix.transpose();
+
+ _triangleShader->use();
+ _triangleShader->setUniform("shakeOffset",
+ Math::Vector2d(_shakeOffset.x * 0.025f, _shakeOffset.y * 0.025f));
}
+
void OpenGLShaderRenderer::renderSensorShoot(byte color, const Math::Vector3d sensor, const Math::Vector3d target, const Common::Rect &viewArea) {
glEnable(GL_BLEND);
glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);
@@ -343,6 +348,7 @@ void OpenGLShaderRenderer::renderPlayerShootBall(byte color, const Common::Point
_triangleShader->use();
_triangleShader->setUniform("useStipple", false);
_triangleShader->setUniform("mvpMatrix", identity);
+ _triangleShader->setUniform("shakeOffset", Math::Vector2d(0, 0));
if (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderZX) {
r = g = b = 255;
@@ -407,6 +413,7 @@ void OpenGLShaderRenderer::renderPlayerShootRay(byte color, const Common::Point
_triangleShader->use();
_triangleShader->setUniform("useStipple", false);
_triangleShader->setUniform("mvpMatrix", identity);
+ _triangleShader->setUniform("shakeOffset", Math::Vector2d(0, 0));
if (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderZX) {
r = g = b = 255;
@@ -525,6 +532,7 @@ void OpenGLShaderRenderer::drawCelestialBody(const Math::Vector3d position, floa
// === Shader uniforms ===
_triangleShader->use();
_triangleShader->setUniform("mvpMatrix", billboardMVP);
+ _triangleShader->setUniform("shakeOffset", Math::Vector2d(0, 0));
_triangleShader->setUniform("useStipple", false);
// === Render settings ===
@@ -621,6 +629,7 @@ void OpenGLShaderRenderer::renderCrossair(const Common::Point &crossairPosition)
_triangleShader->use();
_triangleShader->setUniform("useStipple", false);
_triangleShader->setUniform("mvpMatrix", identity);
+ _triangleShader->setUniform("shakeOffset", Math::Vector2d(0, 0));
glEnable(GL_BLEND);
glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);
diff --git a/engines/freescape/gfx_tinygl.cpp b/engines/freescape/gfx_tinygl.cpp
index f4b094c617f..5b2db657cfa 100644
--- a/engines/freescape/gfx_tinygl.cpp
+++ b/engines/freescape/gfx_tinygl.cpp
@@ -211,6 +211,16 @@ void TinyGLRenderer::positionCamera(const Math::Vector3d &pos, const Math::Vecto
tglMultMatrixf(lookMatrix.getData());
tglRotatef(rollAngle, 0.0f, 0.0f, 1.0f);
tglTranslatef(-pos.x(), -pos.y(), -pos.z());
+
+ // Apply a 2D shake effect on the projection matrix,
+ // matching the OpenGL fixed-function implementation.
+ tglMatrixMode(TGL_PROJECTION);
+ TGLfloat projMatrix[16];
+ tglGetFloatv(TGL_PROJECTION_MATRIX, projMatrix);
+ tglLoadIdentity();
+ tglTranslatef(_shakeOffset.x * 0.025f, _shakeOffset.y * 0.025f, 0.0f);
+ tglMultMatrixf(projMatrix);
+ tglMatrixMode(TGL_MODELVIEW);
}
void TinyGLRenderer::renderSensorShoot(byte color, const Math::Vector3d sensor, const Math::Vector3d player, const Common::Rect &viewArea) {
diff --git a/engines/freescape/shaders/freescape_triangle.vertex b/engines/freescape/shaders/freescape_triangle.vertex
index 6483e9a8adb..619e2720761 100644
--- a/engines/freescape/shaders/freescape_triangle.vertex
+++ b/engines/freescape/shaders/freescape_triangle.vertex
@@ -2,11 +2,13 @@ in vec3 position;
uniform mat4 mvpMatrix;
uniform vec3 color;
+uniform vec2 shakeOffset;
varying vec4 var_color;
void main()
{
var_color = vec4(color, 1.0);
- gl_Position = mvpMatrix * vec4(position, 1.0);
+ gl_Position = mvpMatrix * vec4(position, 1.0);
+ gl_Position.xy += shakeOffset * gl_Position.w;
}
\ No newline at end of file
Commit: f5b782fee552425073b641f7c093bc60d2753b91
https://github.com/scummvm/scummvm/commit/f5b782fee552425073b641f7c093bc60d2753b91
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-03-26T18:16:57+01:00
Commit Message:
FREESCAPE: draw the UI correctly when riddles are displayed
Changed paths:
engines/freescape/freescape.h
engines/freescape/games/castle/castle.cpp
engines/freescape/ui.cpp
diff --git a/engines/freescape/freescape.h b/engines/freescape/freescape.h
index 3e23d43c2e1..202dceaa245 100644
--- a/engines/freescape/freescape.h
+++ b/engines/freescape/freescape.h
@@ -227,6 +227,7 @@ public:
void drawTitle();
virtual void drawBackground();
void clearBackground();
+ void drawPlatformUI(Graphics::Surface *surface);
virtual void drawUI();
virtual void drawInfoMenu();
void drawBorderScreenAndWait(Graphics::Surface *surface, int maxWait = INT_MAX);
diff --git a/engines/freescape/games/castle/castle.cpp b/engines/freescape/games/castle/castle.cpp
index 0b72e67c008..bb914255e73 100644
--- a/engines/freescape/games/castle/castle.cpp
+++ b/engines/freescape/games/castle/castle.cpp
@@ -1559,10 +1559,16 @@ void CastleEngine::drawFullscreenRiddleAndWait(uint16 riddle) {
break;
}
}
+ updateTimeVariables();
_gfx->clear(0, 0, 0, true);
drawBorder();
- if (_currentArea)
- drawUI();
+ if (_currentArea) {
+ // Draw both UI and riddle on the same surface, since
+ // drawFullscreenSurface uses a single shared texture.
+ uint32 gray = _gfx->_texturePixelFormat.ARGBToColor(0x00, 0xA0, 0xA0, 0xA0);
+ surface->fillRect(Common::Rect(0, 0, _screenW, _screenH), gray);
+ drawPlatformUI(surface);
+ }
drawRiddle(riddle, front, transparent, surface);
_gfx->flipBuffer();
g_system->updateScreen();
diff --git a/engines/freescape/ui.cpp b/engines/freescape/ui.cpp
index eff56e7b54a..819678d617d 100644
--- a/engines/freescape/ui.cpp
+++ b/engines/freescape/ui.cpp
@@ -368,16 +368,7 @@ void FreescapeEngine::drawFullscreenSurface(Graphics::Surface *surface) {
_gfx->setViewport(_viewArea);
}
-void FreescapeEngine::drawUI() {
- Graphics::Surface *surface = nullptr;
- if (_border) { // This can be removed when all the borders are loaded
- uint32 gray = _gfx->_texturePixelFormat.ARGBToColor(0x00, 0xA0, 0xA0, 0xA0);
- surface = new Graphics::Surface();
- surface->create(_screenW, _screenH, _gfx->_texturePixelFormat);
- surface->fillRect(_fullscreenViewArea, gray);
- } else
- return;
-
+void FreescapeEngine::drawPlatformUI(Graphics::Surface *surface) {
if (isDOS())
drawDOSUI(surface);
else if (isC64())
@@ -388,6 +379,19 @@ void FreescapeEngine::drawUI() {
drawCPCUI(surface);
else if (isAmiga() || isAtariST())
drawAmigaAtariSTUI(surface);
+}
+
+void FreescapeEngine::drawUI() {
+ Graphics::Surface *surface = nullptr;
+ if (_border) { // This can be removed when all the borders are loaded
+ uint32 gray = _gfx->_texturePixelFormat.ARGBToColor(0x00, 0xA0, 0xA0, 0xA0);
+ surface = new Graphics::Surface();
+ surface->create(_screenW, _screenH, _gfx->_texturePixelFormat);
+ surface->fillRect(_fullscreenViewArea, gray);
+ } else
+ return;
+
+ drawPlatformUI(surface);
drawFullscreenSurface(surface);
Commit: e0091f244440bef46498393609c150888c04937a
https://github.com/scummvm/scummvm/commit/e0091f244440bef46498393609c150888c04937a
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-03-26T18:16:57+01:00
Commit Message:
FREESCAPE: pause game while text is displayed
Changed paths:
engines/freescape/games/castle/castle.cpp
engines/freescape/ui.cpp
diff --git a/engines/freescape/games/castle/castle.cpp b/engines/freescape/games/castle/castle.cpp
index bb914255e73..4bda08d0893 100644
--- a/engines/freescape/games/castle/castle.cpp
+++ b/engines/freescape/games/castle/castle.cpp
@@ -1559,7 +1559,6 @@ void CastleEngine::drawFullscreenRiddleAndWait(uint16 riddle) {
break;
}
}
- updateTimeVariables();
_gfx->clear(0, 0, 0, true);
drawBorder();
if (_currentArea) {
diff --git a/engines/freescape/ui.cpp b/engines/freescape/ui.cpp
index 819678d617d..7aa78105b17 100644
--- a/engines/freescape/ui.cpp
+++ b/engines/freescape/ui.cpp
@@ -302,6 +302,7 @@ void FreescapeEngine::drawFullscreenMessageAndWait(Common::String message) {
}
void FreescapeEngine::drawBorderScreenAndWait(Graphics::Surface *surface, int maxWait) {
+ PauseToken pauseToken = pauseEngine();
for (int i = 0; i < maxWait; i++) {
Common::Event event;
while (_eventManager->pollEvent(event)) {
@@ -347,12 +348,16 @@ void FreescapeEngine::drawBorderScreenAndWait(Graphics::Surface *surface, int ma
_gfx->clear(0, 0, 0, true);
drawBorder();
- if (surface)
+ if (surface) {
+ if (_currentArea)
+ drawPlatformUI(surface);
drawFullscreenSurface(surface);
+ }
_gfx->flipBuffer();
g_system->updateScreen();
g_system->delayMillis(15); // try to target ~60 FPS
}
+ pauseToken.clear();
playSound(_soundIndexMenu, false, _soundFxHandle);
_gfx->clear(0, 0, 0, true);
}
More information about the Scummvm-git-logs
mailing list