[Scummvm-git-logs] scummvm master -> 4e9b273bd646ec4a209668e87e8fabd32069ef9c
sdelamarre
noreply at scummvm.org
Fri Apr 17 20:58:03 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:
4354229d95 GOB: Implement o7_getVmdCurrentFrameRect (Adi4)
f8024e1096 GOB: Implement o7_calculator (Adi4)
2043a7edad GOB: Fix a transparency bug with 32-bits pixel formats
9b02e43a11 GOB: Fix underline width in printTotText
584cb3d7d0 GOB: Fix o2_addHotspot behavior for Adibou2/Adi4
1119022d3b GOB: Fix swapped width/height issue in an error message
4e9b273bd6 GOB: Fix a video glitch in Adi4 applications
Commit: 4354229d95b6161d5324a8bd22404a550f5554d5
https://github.com/scummvm/scummvm/commit/4354229d95b6161d5324a8bd22404a550f5554d5
Author: Simon Delamarre (simon.delamarre14 at gmail.com)
Date: 2026-04-17T22:57:26+02:00
Commit Message:
GOB: Implement o7_getVmdCurrentFrameRect (Adi4)
Changed paths:
engines/gob/inter.h
engines/gob/inter_v7.cpp
engines/gob/videoplayer.cpp
engines/gob/videoplayer.h
diff --git a/engines/gob/inter.h b/engines/gob/inter.h
index fcdf026d009..605594c1933 100644
--- a/engines/gob/inter.h
+++ b/engines/gob/inter.h
@@ -731,6 +731,7 @@ protected:
void o7_findNextFile();
void o7_getFileInfo();
void o7_getSystemProperty();
+ void o7_getVmdCurrentFrameRect();
void o7_loadImage();
void o7_copyDataToClipboard();
void o7_setVolume();
diff --git a/engines/gob/inter_v7.cpp b/engines/gob/inter_v7.cpp
index 938c925030a..024ed9c8415 100644
--- a/engines/gob/inter_v7.cpp
+++ b/engines/gob/inter_v7.cpp
@@ -87,6 +87,7 @@ void Inter_v7::setupOpcodesDraw() {
OPCODEDRAW(0x8A, o7_findFile);
OPCODEDRAW(0x8B, o7_findNextFile);
OPCODEDRAW(0x8C, o7_getSystemProperty);
+ OPCODEDRAW(0x8D, o7_getVmdCurrentFrameRect);
OPCODEDRAW(0x8E, o7_getFileInfo);
OPCODEDRAW(0x90, o7_loadImage);
OPCODEDRAW(0x91, o7_copyDataToClipboard);
@@ -993,6 +994,24 @@ void Inter_v7::o7_findNextFile() {
storeValue(file.empty() ? 0 : 1);
}
+void Inter_v7::o7_getVmdCurrentFrameRect() {
+ int16 slot = _vm->_game->_script->readValExpr();
+
+ int16 x, y, width, height;
+ if (slot >= 0 && slot < 7 && _vm->_vidPlayer->slotIsOpen(slot) &&
+ _vm->_vidPlayer->getFrameCoords(slot, _vm->_vidPlayer->getCurrentFrame(slot), x, y, width, height)) {
+ storeValue((uint32)x); // left
+ storeValue((uint32)(x + width - 1)); // right
+ storeValue((uint32)y); // top
+ storeValue((uint32)(y + height - 1)); // bottom
+ } else {
+ storeValue((uint32)-1);
+ storeValue((uint32)-1);
+ storeValue((uint32)-1);
+ storeValue((uint32)-1);
+ }
+}
+
void Inter_v7::o7_getSystemProperty() {
const char *property = _vm->_game->_script->evalString();
if (!scumm_stricmp(property, "TotalPhys")) {
diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp
index 0d91e671318..a493dcde250 100644
--- a/engines/gob/videoplayer.cpp
+++ b/engines/gob/videoplayer.cpp
@@ -1066,6 +1066,14 @@ Common::SeekableReadStream *VideoPlayer::getEmbeddedFile(const Common::String &f
return video->decoder->getEmbeddedFile(fileName);
}
+bool VideoPlayer::getFrameCoords(int slot, int16 frame, int16 &x, int16 &y, int16 &width, int16 &height) const {
+ const Video *video = getVideoBySlot(slot);
+ if (!video)
+ return false;
+
+ return video->decoder->getFrameCoords(frame, x, y, width, height);
+}
+
int32 VideoPlayer::getSubtitleIndex(int slot) const {
const Video *video = getVideoBySlot(slot);
if (!video)
diff --git a/engines/gob/videoplayer.h b/engines/gob/videoplayer.h
index 8048b85e374..b038882d291 100644
--- a/engines/gob/videoplayer.h
+++ b/engines/gob/videoplayer.h
@@ -159,6 +159,8 @@ public:
bool hasVideo (int slot = 0) const;
+ bool getFrameCoords(int slot, int16 frame, int16 &x, int16 &y, int16 &width, int16 &height) const;
+
const Common::List<Common::Rect> *getDirtyRects(int slot = 0) const;
bool hasEmbeddedFile(const Common::String &fileName, int slot = 0) const;
Commit: f8024e1096a67a583dc4f5bd21769304bc552e71
https://github.com/scummvm/scummvm/commit/f8024e1096a67a583dc4f5bd21769304bc552e71
Author: Simon Delamarre (simon.delamarre14 at gmail.com)
Date: 2026-04-17T22:57:26+02:00
Commit Message:
GOB: Implement o7_calculator (Adi4)
Used in the "calculator" tool on Adi's desk.
Changed paths:
engines/gob/inter.h
engines/gob/inter_v7.cpp
diff --git a/engines/gob/inter.h b/engines/gob/inter.h
index 605594c1933..91a5ae58e27 100644
--- a/engines/gob/inter.h
+++ b/engines/gob/inter.h
@@ -816,6 +816,7 @@ protected:
void o7_setDBStringEncoding(OpGobParams ¶ms);
void o7_gob0x201(OpGobParams ¶ms);
void o7_getFreeDiskSpace(OpGobParams ¶ms);
+ void o7_calculator(OpGobParams ¶ms);
void o7_dummy(OpGobParams ¶ms);
private:
diff --git a/engines/gob/inter_v7.cpp b/engines/gob/inter_v7.cpp
index 024ed9c8415..4ad97f52e2b 100644
--- a/engines/gob/inter_v7.cpp
+++ b/engines/gob/inter_v7.cpp
@@ -167,6 +167,7 @@ void Inter_v7::setupOpcodesGob() {
OPCODEGOB(410, o7_resolvePath);
OPCODEGOB(420, o7_ansiToOEM);
OPCODEGOB(421, o7_oemToANSI);
+ OPCODEGOB(457, o7_calculator);
OPCODEGOB(512, o7_setDBStringEncoding);
OPCODEGOB(513, o7_gob0x201);
OPCODEGOB(600, o7_getFreeDiskSpace);
@@ -2417,6 +2418,153 @@ void Inter_v7::o7_gob0x201(OpGobParams ¶ms) {
WRITE_VAR(varIndex, 1);
}
+enum CalcOp {
+ kCalcAdd = 1,
+ kCalcSubtract = 2,
+ kCalcDivide = 3,
+ kCalcMultiply = 4,
+ kCalcInverse = 5,
+ kCalcSquare = 6,
+ kCalcSqrt = 7,
+ kCalcPower = 8,
+ kCalcExp = 9,
+ kCalcSin = 10,
+ kCalcTan = 11,
+ kCalcAcos = 12,
+ kCalcAsin = 13,
+ kCalcLn = 14
+};
+
+enum CalcError {
+ kCalcErrNone = 0,
+ kCalcErrInf = 2,
+ kCalcErrNaN = 3,
+ kCalcErrDomain = 4,
+ kCalcErrDivByZero = 5,
+ kCalcErrFPU = 6
+};
+
+void Inter_v7::o7_calculator(OpGobParams ¶ms) {
+ // Calculator opcode, used by the Adi4 calculator tool.
+
+ uint16 operandAAndResultVarIndex = _vm->_game->_script->readUint16();
+ uint16 operandBVarIndex = _vm->_game->_script->readUint16();
+ uint16 operationVarIndex = _vm->_game->_script->readUint16();
+ int operation = VAR(operationVarIndex);
+
+ const char *strA = _vm->_inter->_variables->getAddressVarString(operandAAndResultVarIndex);
+ const char *strB = _vm->_inter->_variables->getAddressVarString(operandBVarIndex);
+ double a = atof(strA);
+ double b = atof(strB);
+ double result = 0.0;
+ int errorCode = kCalcErrNone;
+
+ switch (operation) {
+ case kCalcAdd:
+ result = a + b;
+ break;
+
+ case kCalcSubtract:
+ result = a - b;
+ break;
+
+ case kCalcDivide:
+ if (b == 0.0)
+ errorCode = kCalcErrDivByZero;
+ else
+ result = a / b;
+ break;
+
+ case kCalcMultiply:
+ result = a * b;
+ break;
+
+ case kCalcInverse:
+ if (b == 0.0)
+ errorCode = kCalcErrDivByZero;
+ else
+ result = 1.0 / b;
+ break;
+
+ case kCalcSquare:
+ result = pow(b, 2.0);
+ break;
+
+ case kCalcSqrt:
+ if (b < 0.0)
+ errorCode = kCalcErrDomain;
+ else
+ result = sqrt(b);
+ break;
+
+ case kCalcPower:
+ if (a == 0.0 && b == 0.0)
+ result = 1.0;
+ else
+ result = pow(a, b);
+ break;
+
+ case kCalcExp:
+ result = exp(b);
+ break;
+
+ case kCalcSin:
+ result = sin(b);
+ break;
+
+ case kCalcTan:
+ if (sin(b) == 0.0)
+ errorCode = kCalcErrDomain;
+ else
+ result = tan(b);
+ break;
+
+ case kCalcAcos:
+ if (b < 0.0 || b > 1.0)
+ errorCode = kCalcErrDomain;
+ else
+ result = acos(b);
+ break;
+
+ case kCalcAsin:
+ if (b < 0.0 || b > 1.0)
+ errorCode = kCalcErrDomain;
+ else
+ result = asin(b);
+ break;
+
+ case kCalcLn:
+ result = log(b);
+ break;
+
+ default:
+ warning("o7_calculator: unknown operation %d", operation);
+ break;
+ }
+
+ if (errorCode == kCalcErrNone) {
+ // Check for overflow/special values in the formatted result
+ Common::String resultFormatted = Common::String::format("%-12g", result);
+ if (resultFormatted.contains("nan") || resultFormatted.contains("NAN")) {
+ errorCode = kCalcErrNaN;
+ result = 0.0;
+ } else if (resultFormatted.contains("inf") || resultFormatted.contains("INF")) {
+ errorCode = kCalcErrInf;
+ result = 0.0;
+ }
+ }
+
+ uint8 *resultData = _vm->_inter->_variables->getAddressVar8(operandAAndResultVarIndex);
+ if (errorCode != kCalcErrNone) {
+ // Error: write empty string + error code in second byte
+ resultData[0] = '\0';
+ resultData[1] = (uint8)errorCode;
+ } else {
+ Common::String formatted = Common::String::format("%-12g", result);
+ WRITE_VAR_STR(operandAAndResultVarIndex, formatted.c_str());
+ }
+}
+
void Inter_v7::o7_getFreeDiskSpace(OpGobParams ¶ms) {
// This opcode is called by the game scripts to check if there is enough free space on the hard disk, before
// copying some data from the CD (e.g. when starting Adibou2/Sciences for the first time).
Commit: 2043a7edad6fc738e86c1e99c4fcd5f7375338cd
https://github.com/scummvm/scummvm/commit/2043a7edad6fc738e86c1e99c4fcd5f7375338cd
Author: Simon Delamarre (simon.delamarre14 at gmail.com)
Date: 2026-04-17T22:57:27+02:00
Commit Message:
GOB: Fix a transparency bug with 32-bits pixel formats
The "-1" sentinel meaning "no transparency" overlapped with pure white
0xFFFFFF, resulting in transparency bugs.
Move the per-pixel Surface::blit into a templated helper, distinguishing
properly the "transparency disabled" case at compile time, instead of
comparing the pixels with the sentinel assuming they will never be -1.
This fixes a transparency bug in Adi4's calculator for backends with
a 32-bits Pixel format.
Changed paths:
engines/gob/surface.cpp
diff --git a/engines/gob/surface.cpp b/engines/gob/surface.cpp
index e433b7af63f..452492a62f1 100644
--- a/engines/gob/surface.cpp
+++ b/engines/gob/surface.cpp
@@ -364,6 +364,40 @@ uint32 Surface::getColorFromIndex(uint8 index) const {
return _highColorMap[index];
}
+template<bool yAxisReflection, bool kTransp, bool kSameBpp>
+static void blitPixels(Pixel dst, ConstPixel src,
+ uint16 width, uint16 height,
+ int16 dstPitch, int16 srcPitch,
+ int32 transp, const uint32 *highColorMap) {
+ while (height-- > 0) {
+ Pixel dstRow = dst;
+ ConstPixel srcRow = src;
+
+ if (yAxisReflection)
+ srcRow += width - 1;
+
+ for (uint16 i = 0; i < width; i++, ++dstRow) {
+ uint32 pixel = srcRow.get();
+
+ if (yAxisReflection)
+ --srcRow;
+ else
+ ++srcRow;
+
+ if (kTransp && pixel == (uint32)transp)
+ continue;
+
+ if (kSameBpp)
+ dstRow.set(pixel);
+ else
+ dstRow.set(highColorMap[pixel]);
+ }
+
+ dst += dstPitch;
+ src += srcPitch;
+ }
+}
+
void Surface::blit(const Surface &from, int16 left, int16 top, int16 right, int16 bottom,
int16 x, int16 y, int32 transp, bool yAxisReflection) {
@@ -399,7 +433,7 @@ void Surface::blit(const Surface &from, int16 left, int16 top, int16 right, int1
return;
}
- if (transp == -1 && !yAxisReflection && from._bpp == _bpp && _bpp == 1) {
+ if (transp == -1 && !yAxisReflection && from._bpp == _bpp) {
// We don't have to look for transparency => we can use memmove line-wise
// Pointers to the blit destination and source start points
@@ -422,37 +456,30 @@ void Surface::blit(const Surface &from, int16 left, int16 top, int16 right, int1
Pixel dst = get(x , y);
ConstPixel src = from.get(left, top);
- while (height-- > 0) {
- Pixel dstRow = dst;
- ConstPixel srcRow = src;
-
- if (yAxisReflection) {
- srcRow += width - 1;
- for (uint16 i = 0; i < width; i++, ++dstRow, --srcRow) {
- if (srcRow.get() != ((uint32) transp)) {
- if (_bpp == from._bpp)
- dstRow.set(srcRow.get());
- else {
- uint32 index = srcRow.get();
- dstRow.set(from._highColorMap[index]);
- }
- }
- }
+ if (yAxisReflection) {
+ if (transp == -1) {
+ if (_bpp == from._bpp)
+ blitPixels<true, false, true>(dst, src, width, height, _width, from._width, transp, from._highColorMap);
+ else
+ blitPixels<true, false, false>(dst, src, width, height, _width, from._width, transp, from._highColorMap);
} else {
- for (uint16 i = 0; i < width; i++, ++dstRow, ++srcRow) {
- if (srcRow.get() != ((uint32) transp)) {
- if (_bpp == from._bpp)
- dstRow.set(srcRow.get());
- else {
- uint32 index = srcRow.get();
- dstRow.set(from._highColorMap[index]);
- }
- }
- }
+ if (_bpp == from._bpp)
+ blitPixels<true, true, true>(dst, src, width, height, _width, from._width, transp, from._highColorMap);
+ else
+ blitPixels<true, true, false>(dst, src, width, height, _width, from._width, transp, from._highColorMap);
+ }
+ } else {
+ if (transp == -1) {
+ if (_bpp == from._bpp)
+ blitPixels<false, false, true>(dst, src, width, height, _width, from._width, transp, from._highColorMap);
+ else
+ blitPixels<false, false, false>(dst, src, width, height, _width, from._width, transp, from._highColorMap);
+ } else {
+ if (_bpp == from._bpp)
+ blitPixels<false, true, true>(dst, src, width, height, _width, from._width, transp, from._highColorMap);
+ else
+ blitPixels<false, true, false>(dst, src, width, height, _width, from._width, transp, from._highColorMap);
}
-
- dst += _width;
- src += from._width;
}
}
@@ -571,7 +598,7 @@ void Surface::blitShaded(const Surface &from, int16 left, int16 top, int16 right
Pixel dstRow = dst;
ConstPixel srcRow = src;
for (uint16 i = 0; i < width; i++, ++dstRow, ++srcRow) {
- if (srcRow.get() == ((uint32) transp))
+ if (transp != -1 && srcRow.get() == ((uint32) transp))
continue;
uint8 srcR = 0;
Commit: 9b02e43a117fb85ca751cf2a38fc52dcd7fae8e2
https://github.com/scummvm/scummvm/commit/9b02e43a117fb85ca751cf2a38fc52dcd7fae8e2
Author: Simon Delamarre (simon.delamarre14 at gmail.com)
Date: 2026-04-17T22:57:27+02:00
Commit Message:
GOB: Fix underline width in printTotText
This fixes incorrect underlined text in the "Calendar - Centuries"
activity of "Adi4/Math CE2" application.
Changed paths:
engines/gob/draw_playtoons.cpp
diff --git a/engines/gob/draw_playtoons.cpp b/engines/gob/draw_playtoons.cpp
index 5f9a8faf4b8..95b0646543c 100644
--- a/engines/gob/draw_playtoons.cpp
+++ b/engines/gob/draw_playtoons.cpp
@@ -346,7 +346,7 @@ void Draw_Playtoons::printTotText(int16 id) {
rectTop = _fonts[fontIndex]->getCharHeight();
adjustCoords(1, nullptr, &rectTop);
- _spriteRight = _destSpriteX + rectLeft - 1;
+ _spriteRight = rectLeft - 1;
_spriteBottom = offY + rectTop;
_destSpriteY = _spriteBottom;
spriteOperation(DRAW_DRAWLINE);
Commit: 584cb3d7d09fa5161beb87eee8dedfce9181654e
https://github.com/scummvm/scummvm/commit/584cb3d7d09fa5161beb87eee8dedfce9181654e
Author: Simon Delamarre (simon.delamarre14 at gmail.com)
Date: 2026-04-17T22:57:27+02:00
Commit Message:
GOB: Fix o2_addHotspot behavior for Adibou2/Adi4
Fixes a bug in "Draw symmetric figure" exercise in the "Maths CE2" Adi4
application, where points and lines where not aligned with the
background grid.
Changed paths:
engines/gob/inter_v2.cpp
diff --git a/engines/gob/inter_v2.cpp b/engines/gob/inter_v2.cpp
index eaa61e211f5..43ea67d4b4b 100644
--- a/engines/gob/inter_v2.cpp
+++ b/engines/gob/inter_v2.cpp
@@ -1207,10 +1207,21 @@ void Inter_v2::o2_addHotspot(OpFuncParams ¶ms) {
top = 0;
}
- if (id < 0)
- _vm->_game->_hotspots->add(0xD000 - id, left & 0xFFFC, top & 0xFFFC,
+ if (id < 0) {
+ int16 hotspotLeft = 0;
+ int16 hotspotTop = 0;
+ if (_vm->getGameType() == kGameTypeAdibou2 || _vm->getGameType() == kGameTypeAdi4) {
+ // The operation is no longer a "floor to previous multiple of 4", but a "minus 4"
+ // NOTE: may be needed by other games as well
+ hotspotLeft = left - 4;
+ hotspotTop = top - 4;
+ } else {
+ hotspotLeft = left & 0xFFFC;
+ hotspotTop = top & 0xFFFC;
+ }
+ _vm->_game->_hotspots->add(0xD000 - id, hotspotLeft, hotspotTop,
left + width + 3, top + height + 3, flags, key, 0, 0, funcPos);
- else
+ } else
_vm->_game->_hotspots->add(0xE000 + id, left, top,
left + width - 1, top + height - 1, flags, key, 0, 0, funcPos);
}
Commit: 1119022d3b8117229efb8a29dd831c54069edcad
https://github.com/scummvm/scummvm/commit/1119022d3b8117229efb8a29dd831c54069edcad
Author: Simon Delamarre (simon.delamarre14 at gmail.com)
Date: 2026-04-17T22:57:27+02:00
Commit Message:
GOB: Fix swapped width/height issue in an error message
Changed paths:
engines/gob/videoplayer.cpp
diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp
index a493dcde250..fac7afb5c45 100644
--- a/engines/gob/videoplayer.cpp
+++ b/engines/gob/videoplayer.cpp
@@ -234,14 +234,12 @@ int VideoPlayer::openVideo(bool primary, const Common::String &file, Properties
bool screenSize = properties.flags & kFlagScreenSurface;
if (ownSurf) {
- uint16 height = screenSize ? _vm->_width : video->decoder->getWidth();
- uint16 width = screenSize ? _vm->_height : video->decoder->getHeight();
+ uint16 width = screenSize ? _vm->_width : video->decoder->getWidth();
+ uint16 height = screenSize ? _vm->_height : video->decoder->getHeight();
if (height > 0 && width > 0) {
_vm->_draw->_spritesArray[properties.sprite] =
- _vm->_video->initSurfDesc(screenSize ? _vm->_width : video->decoder->getWidth(),
- screenSize ? _vm->_height : video->decoder->getHeight(), 0,
- 0);
+ _vm->_video->initSurfDesc(width, height, 0, 0);
} else {
warning("VideoPlayer::openVideo() file=%s:"
"Invalid surface dimensions (%dx%d)", file.c_str(), width, height);
Commit: 4e9b273bd646ec4a209668e87e8fabd32069ef9c
https://github.com/scummvm/scummvm/commit/4e9b273bd646ec4a209668e87e8fabd32069ef9c
Author: Simon Delamarre (simon.delamarre14 at gmail.com)
Date: 2026-04-17T22:57:27+02:00
Commit Message:
GOB: Fix a video glitch in Adi4 applications
Some Adi's animations, when Adi is waiting for a player action, were not
displayed at their correct location. This was due to a special case in
o2_getImdInfo that have been removed in later versions of the engine.
Changed paths:
engines/gob/videoplayer.cpp
diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp
index fac7afb5c45..01b75bad8d0 100644
--- a/engines/gob/videoplayer.cpp
+++ b/engines/gob/videoplayer.cpp
@@ -1096,8 +1096,11 @@ void VideoPlayer::writeVideoInfo(const Common::String &file, uint16 varX, uint16
width = video.decoder->getWidth();
height = video.decoder->getHeight();
- if (VAR_OFFSET(varX) == 0xFFFFFFFF)
- video.decoder->getFrameCoords(1, x, y, width, height);
+ if (_vm->getGameType() != kGameTypeAdibou2 && _vm->getGameType() != kGameTypeAdi4) {
+ // Note: not found in Adibou2/Adi4 disasm, and cause video gltiches
+ if (VAR_OFFSET(varX) == 0xFFFFFFFF)
+ video.decoder->getFrameCoords(1, x, y, width, height);
+ }
WRITE_VAR_OFFSET(varX , x);
WRITE_VAR_OFFSET(varY , y);
More information about the Scummvm-git-logs
mailing list