[Scummvm-git-logs] scummvm master -> 2fd664020d16e5d6e9e687791ed4978d98b7ab90
neuromancer
noreply at scummvm.org
Sun Jul 5 09:43:06 UTC 2026
This automated email contains information about 4 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
f0b2600883 FREESCAPE: fixed incorrect color in ZX UI for driller/dark
a92e02d1b4 FREESCAPE: fixed incorrect sky color in Amiga/Atari for dark
453681fb76 FREESCAPE: added a workaround for wall/camera clipping issues in castle
2fd664020d FREESCAPE: fixed isOutside for castle
Commit: f0b2600883d792774ec929ba52d39b198e6a554e
https://github.com/scummvm/scummvm/commit/f0b2600883d792774ec929ba52d39b198e6a554e
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-07-05T11:29:58+02:00
Commit Message:
FREESCAPE: fixed incorrect color in ZX UI for driller/dark
Changed paths:
engines/freescape/games/dark/dark.cpp
diff --git a/engines/freescape/games/dark/dark.cpp b/engines/freescape/games/dark/dark.cpp
index 1bb05238581..c1eab0dc025 100644
--- a/engines/freescape/games/dark/dark.cpp
+++ b/engines/freescape/games/dark/dark.cpp
@@ -926,6 +926,9 @@ void DarkEngine::drawHorizontalCompass(int x, int y, float angle, uint32 front,
uint8 r, g, b;
_gfx->selectColorFromFourColorPalette(3, r, g, b);
green = _gfx->_texturePixelFormat.ARGBToColor(0xFF, r, g, b);
+ } else if (isSpectrum()) {
+ // The ZX HUD uses a single ink color for all the text, including the compass.
+ green = front;
}
int delta = (angle - 180) / 5.5;
Commit: a92e02d1b444efcdc90bc0151aaa5cec459bb95b
https://github.com/scummvm/scummvm/commit/a92e02d1b444efcdc90bc0151aaa5cec459bb95b
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-07-05T11:29:58+02:00
Commit Message:
FREESCAPE: fixed incorrect sky color in Amiga/Atari for dark
Changed paths:
engines/freescape/loaders/8bitBinaryLoader.cpp
diff --git a/engines/freescape/loaders/8bitBinaryLoader.cpp b/engines/freescape/loaders/8bitBinaryLoader.cpp
index a604be0ebc0..0e8391c5e34 100644
--- a/engines/freescape/loaders/8bitBinaryLoader.cpp
+++ b/engines/freescape/loaders/8bitBinaryLoader.cpp
@@ -747,6 +747,10 @@ Area *FreescapeEngine::load8bitArea(Common::SeekableReadStream *file, uint16 nco
name = name + char(readField(file, 8));
i++;
}
+
+ // The 16-bit renderer keeps the hardware background black; the sky nibble is 8-bit legacy data.
+ if (isDark() && (isAmiga() || isAtariST()))
+ skyColor = 0;
} else if (isCastle()) {
byte idx = readField(file, 8);
if (isAmiga() || isAtariST())
Commit: 453681fb7678ce7e553f7c24053bdbe3b61bfc27
https://github.com/scummvm/scummvm/commit/453681fb7678ce7e553f7c24053bdbe3b61bfc27
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-07-05T11:29:58+02:00
Commit Message:
FREESCAPE: added a workaround for wall/camera clipping issues in castle
Changed paths:
engines/freescape/area.cpp
engines/freescape/area.h
engines/freescape/freescape.cpp
engines/freescape/freescape.h
diff --git a/engines/freescape/area.cpp b/engines/freescape/area.cpp
index 144db15a0f9..7b6894c7c32 100644
--- a/engines/freescape/area.cpp
+++ b/engines/freescape/area.cpp
@@ -836,6 +836,47 @@ Math::Vector3d Area::separateFromWall(const Math::Vector3d &_position) {
return position;
}
+// Render-only: nudge the eye at least `separation` away from wall sides so they never cross the near plane.
+Math::Vector3d Area::separateCameraFromWall(const Math::Vector3d &eye, float separation) {
+ Math::Vector3d cam = eye;
+ for (int pass = 0; pass < 4; pass++) { // corners: leaving one wall's band can enter another's
+ bool adjusted = false;
+ for (auto &obj : _drawableObjects) {
+ if (obj->isDestroyed() || obj->isInvisible() || !obj->isGeometric())
+ continue;
+ const Math::AABB &box = ((GeometricObject *)obj)->_boundingBox;
+ if (!box.isValid())
+ continue;
+ Math::Vector3d mn = box.getMin();
+ Math::Vector3d mx = box.getMax();
+ if (cam.y() <= mn.y() || cam.y() >= mx.y()) // only walls at eye level can clip the view
+ continue;
+
+ float dx = cam.x() - CLIP<float>(cam.x(), mn.x(), mx.x());
+ float dz = cam.z() - CLIP<float>(cam.z(), mn.z(), mx.z());
+ float dist = sqrtf(dx * dx + dz * dz);
+ if (dist >= separation)
+ continue;
+
+ if (dist > 0.0001f) { // in the band: push straight out
+ cam.x() += dx / dist * (separation - dist);
+ cam.z() += dz / dist * (separation - dist);
+ } else { // inside the footprint: eject through the nearest side
+ float left = cam.x() - mn.x(), right = mx.x() - cam.x();
+ float back = cam.z() - mn.z(), front = mx.z() - cam.z();
+ if (MIN(left, right) <= MIN(back, front))
+ cam.x() += (left < right) ? -(left + separation) : (right + separation);
+ else
+ cam.z() += (back < front) ? -(back + separation) : (front + separation);
+ }
+ adjusted = true;
+ }
+ if (!adjusted)
+ break;
+ }
+ return cam;
+}
+
Math::Vector3d Area::resolveCollisions(const Math::Vector3d &lastPosition_, const Math::Vector3d &newPosition_, int playerHeight) {
Math::Vector3d position = newPosition_;
Math::Vector3d lastPosition = lastPosition_;
diff --git a/engines/freescape/area.h b/engines/freescape/area.h
index 18604f84736..45b42c949db 100644
--- a/engines/freescape/area.h
+++ b/engines/freescape/area.h
@@ -72,6 +72,7 @@ public:
Object *checkCollisionRay(const Math::Ray &ray, int raySize, bool skipTransparent = false);
bool checkInSight(const Math::Ray &ray, float maxDistance);
Math::Vector3d separateFromWall(const Math::Vector3d &position);
+ Math::Vector3d separateCameraFromWall(const Math::Vector3d &eye, float separation);
ObjectArray checkCollisions(const Math::AABB &boundingBox);
bool checkIfPlayerWasCrushed(const Math::AABB &boundingBox);
Math::Vector3d resolveCollisions(Math::Vector3d const &lastPosition, Math::Vector3d const &newPosition, int playerHeight);
diff --git a/engines/freescape/freescape.cpp b/engines/freescape/freescape.cpp
index 81d5fb51276..e435cbc80b6 100644
--- a/engines/freescape/freescape.cpp
+++ b/engines/freescape/freescape.cpp
@@ -703,6 +703,13 @@ static float getStereoSeparation(FreescapeEngine *engine, float fov, float aspec
return MIN(maxSeparation, maxDisparity / denominator);
}
+Math::Vector3d FreescapeEngine::getCameraRenderPosition() {
+ // Keep the eye off wall surfaces so the near plane never crosses them; collisions still use _position.
+ if (isCastle() && !_noClipMode)
+ return _currentArea->separateCameraFromWall(_position, _nearClipPlane + 1.0f);
+ return _position;
+}
+
void FreescapeEngine::drawFrame() {
_gfx->updateColorCycling();
int farClipPlane = _farClipPlane;
@@ -716,8 +723,11 @@ void FreescapeEngine::drawFrame() {
const float fov = 75.0f;
float aspectRatio = isCastle() ? 1.6 : 2.18;
+
+ Math::Vector3d renderPosition = getCameraRenderPosition();
+
_gfx->updateProjectionMatrix(fov, aspectRatio, _nearClipPlane, farClipPlane);
- _gfx->positionCamera(_position, _position + _cameraFront, _roll);
+ _gfx->positionCamera(renderPosition, renderPosition + _cameraFront, _roll);
if (_underFireFrames > 0) {
int underFireColor = _currentArea->_underFireBackgroundColor;
@@ -737,7 +747,7 @@ void FreescapeEngine::drawFrame() {
drawBackground();
if (_avoidRenderingFrames == 0) { // Avoid rendering inside objects
- _currentArea->draw(_gfx, _ticks / 10, _position, _cameraFront, false, fov, aspectRatio, _nearClipPlane, farClipPlane);
+ _currentArea->draw(_gfx, _ticks / 10, renderPosition, _cameraFront, false, fov, aspectRatio, _nearClipPlane, farClipPlane);
if (_gameStateControl == kFreescapeGameStatePlaying &&
_currentArea->hasActiveGroups() && _ticks % 50 == 0) {
executeMovementConditions();
@@ -779,6 +789,9 @@ void FreescapeEngine::drawFrame() {
void FreescapeEngine::drawFrameStereo(int farClipPlane) {
const float fov = 75.0f;
float aspectRatio = isCastle() ? 1.6 : 2.18;
+
+ Math::Vector3d renderPosition = getCameraRenderPosition();
+
const float stereoConvergence = getStereoConvergence(this);
const float stereoMaxSeparation = getStereoMaxSeparation(this, stereoConvergence);
const float stereoForegroundDistance = getStereoForegroundDistance(this, stereoConvergence);
@@ -804,21 +817,21 @@ void FreescapeEngine::drawFrameStereo(int farClipPlane) {
_gfx->clear(0, 0, 0, true);
_gfx->setStereoEye(Renderer::kStereoEyeFlatAnaglyph);
_gfx->updateProjectionMatrix(fov, aspectRatio, _nearClipPlane, farClipPlane);
- _gfx->positionCamera(_position, _position + _cameraFront, _roll);
+ _gfx->positionCamera(renderPosition, renderPosition + _cameraFront, _roll);
drawBackground();
if (_avoidRenderingFrames == 0)
- _currentArea->drawDepthLayer(_gfx, _ticks / 10, _position, _cameraFront, false, Area::kRenderDepthBackground, stereoForegroundDistance, fov, aspectRatio, _nearClipPlane, farClipPlane);
+ _currentArea->drawDepthLayer(_gfx, _ticks / 10, renderPosition, _cameraFront, false, Area::kRenderDepthBackground, stereoForegroundDistance, fov, aspectRatio, _nearClipPlane, farClipPlane);
for (int pass = 0; pass < 2; pass++) {
_gfx->setStereoEye(pass == 0 ? Renderer::kStereoEyeLeft : Renderer::kStereoEyeRight);
_gfx->updateProjectionMatrix(fov, aspectRatio, _nearClipPlane, farClipPlane);
- _gfx->positionCamera(_position, _position + _cameraFront, _roll);
+ _gfx->positionCamera(renderPosition, renderPosition + _cameraFront, _roll);
_gfx->clearDepthBuffer();
if (_avoidRenderingFrames == 0) // Avoid rendering inside objects
- _currentArea->drawDepthLayer(_gfx, _ticks / 10, _position, _cameraFront, false, Area::kRenderDepthForeground, stereoForegroundDistance, fov, aspectRatio, _nearClipPlane, farClipPlane);
+ _currentArea->drawDepthLayer(_gfx, _ticks / 10, renderPosition, _cameraFront, false, Area::kRenderDepthForeground, stereoForegroundDistance, fov, aspectRatio, _nearClipPlane, farClipPlane);
if (_underFireFrames > 0) {
for (auto &it : _sensors) {
diff --git a/engines/freescape/freescape.h b/engines/freescape/freescape.h
index 092ff619940..6ab4fa73526 100644
--- a/engines/freescape/freescape.h
+++ b/engines/freescape/freescape.h
@@ -563,6 +563,7 @@ public:
int _shootingFrames;
GeometricObject *_delayedShootObject;
void drawFrame();
+ Math::Vector3d getCameraRenderPosition();
void drawFrameStereo(int farClipPlane);
// Red/blue anaglyph 3D ("two eyes") effect, toggled with the 3 key.
Commit: 2fd664020d16e5d6e9e687791ed4978d98b7ab90
https://github.com/scummvm/scummvm/commit/2fd664020d16e5d6e9e687791ed4978d98b7ab90
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-07-05T11:29:58+02:00
Commit Message:
FREESCAPE: fixed isOutside for castle
Changed paths:
engines/freescape/area.cpp
engines/freescape/area.h
diff --git a/engines/freescape/area.cpp b/engines/freescape/area.cpp
index 7b6894c7c32..61894ad188c 100644
--- a/engines/freescape/area.cpp
+++ b/engines/freescape/area.cpp
@@ -68,6 +68,7 @@ Area::Area(uint16 areaID_, uint16 areaFlags_, ObjectMap *objectsByID_, ObjectMap
_isCastle = isCastle_;
_scale = 0;
+ _hasSyntheticFloor = false;
_skyColor = 255;
_groundColor = 255;
_usualBackgroundColor = 255;
@@ -1021,6 +1022,7 @@ void Area::addGroupFromArea(int16 id, Area *global) {
void Area::addFloor() {
+ _hasSyntheticFloor = true;
int id = 0;
assert(!_objectsByID->contains(id));
Common::Array<uint8> *gColors = new Common::Array<uint8>;
@@ -1071,6 +1073,9 @@ void Area::changeObjectID(uint16 objectID, uint16 newObjectID) {
bool Area::isOutside() {
+ // Castle outdoor areas are exactly the ones that get the synthetic floor (Wilderness and Courtyard).
+ if (_isCastle)
+ return _hasSyntheticFloor;
return _skyColor < 255 && _groundColor < 255;
}
diff --git a/engines/freescape/area.h b/engines/freescape/area.h
index 45b42c949db..0e1d908cc7c 100644
--- a/engines/freescape/area.h
+++ b/engines/freescape/area.h
@@ -135,6 +135,7 @@ private:
uint16 _areaID;
uint16 _areaFlags;
+ bool _hasSyntheticFloor;
ObjectMap *_objectsByID;
ObjectMap *_entrancesByID;
ObjectArray _drawableObjects;
More information about the Scummvm-git-logs
mailing list