[Scummvm-git-logs] scummvm master -> 3a7b808800bb90fc3ec748f01894a5eb2ccf88e6
neuromancer
noreply at scummvm.org
Tue Sep 1 10:07:50 UTC 2026
This automated email contains information about 5 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
0d74b4e06c COLONY: make sure dos rendering follows the original source
6bb6a93d98 COLONY: fix DOS polygon fills and eye rendering
5de262b804 COLONY: fix aspect ratio rendering for DOS release
f5786b13ba COLONY: better rendering of stair going down
3a7b808800 COLONY: improved instructions in the reactor console
Commit: 0d74b4e06c5b686396f7d1617797ca8ce968723f
https://github.com/scummvm/scummvm/commit/0d74b4e06c5b686396f7d1617797ca8ce968723f
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-09-01T12:07:23+02:00
Commit Message:
COLONY: make sure dos rendering follows the original source
Changed paths:
engines/colony/colony.cpp
engines/colony/render.cpp
engines/colony/render_internal.h
diff --git a/engines/colony/colony.cpp b/engines/colony/colony.cpp
index 7586914bf0b..47320c98dbd 100644
--- a/engines/colony/colony.cpp
+++ b/engines/colony/colony.cpp
@@ -150,7 +150,8 @@ ColonyEngine::ColonyEngine(OSystem *syst, const ADGameDescription *gd) : Engine(
_widescreen = ConfMan.getBool("widescreen_mod");
_invertY = ConfMan.getBool("invert_y");
- // Render mode: EGA (DOS wireframe default) or Macintosh (filled polygons)
+ // Render mode: EGA or Macintosh. The shipped DOS launcher passes /fill,
+ // so both platforms start with filled polygons.
if (!ConfMan.hasKey("render_mode") || ConfMan.get("render_mode").empty())
_renderMode = Common::kRenderDefault;
else
@@ -163,7 +164,7 @@ ColonyEngine::ColonyEngine(OSystem *syst, const ADGameDescription *gd) : Engine(
_renderMode = Common::kRenderEGA;
}
- _wireframe = !isMacRenderMode();
+ _wireframe = false;
_fullscreen = false;
_speedShift = 2; // DOS default: speedshift=1, but 2 feels better with our frame rate
_moveForward = false;
diff --git a/engines/colony/render.cpp b/engines/colony/render.cpp
index aa9b9fb8e25..1176e970289 100644
--- a/engines/colony/render.cpp
+++ b/engines/colony/render.cpp
@@ -43,24 +43,23 @@ const int g_indexTable[4][10] = {
{0, 0, 0, 1, 1, 0, 0, -1, 2, 1}
};
-// DOS lsColor table from ROBOCOLR.C maps color index to rendering attributes.
-// Fields: monochrome (MONOCHROME Mac B&W dither pattern, matches MacPattern enum),
-// backColor (BACKCOLOR), fillColor (FILLCOLOR), lineFillColor (LINEFILLCOLOR),
-// lineColor (LINECOLOR), pattern (PATTERN).
+// DOS lsColor table from ROBOCOLR.C maps color index to rendering attributes.
+// Source column order: MONOCHROME, LINEFILLCOLOR, FILLCOLOR, BACKCOLOR,
+// LINECOLOR, PATTERN.
// DrawPrism uses: polyfill ON â fill with fillColor/backColor/pattern, outline with lineFillColor.
// polyfill OFF â outline only with lineColor.
// Mac B&W uses: monochrome field for dither pattern (WHITE/LTGRAY/GRAY/DKGRAY/BLACK/CLEAR).
struct DOSColorEntry {
uint8 monochrome;
- uint8 backColor;
- uint8 fillColor;
uint8 lineFillColor;
+ uint8 fillColor;
+ uint8 backColor;
uint8 lineColor;
uint8 pattern;
};
const DOSColorEntry g_dosColors[79] = {
- // MONO BK FILL LFIL LINE PAT
+ // MONO LFIL FILL BK LINE PAT
/* 0 cCLEAR */ { 5, 0, 0, 0, 0, 1},
/* 1 cBLACK */ { 4, 0, 0, 0, 0, 1},
/* 2 cBLUE */ { 2, 0, 1, 1, 1, 1},
@@ -181,6 +180,37 @@ const DOSColorEntry &lookupDOSColor(int colorIdx, int level) {
}
}
+// Reproduce the DOS driver's SetFill/FILLPATTERN material setup. Patterns 3,
+// 4 and 5 are respectively 50%, 25% and 12.5% foreground coverage; pattern 1
+// is a solid FILLCOLOR fill.
+const byte *setupDOSMaterial(Renderer *gfx, const DOSColorEntry &color) {
+ const byte *stipple = nullptr;
+ switch (color.pattern) {
+ case 3:
+ stipple = kStippleGray;
+ break;
+ case 4:
+ stipple = kStippleLtGray;
+ break;
+ case 5:
+ stipple = kDOSStipplePattern5;
+ break;
+ default:
+ break;
+ }
+
+ if (stipple) {
+ gfx->setMacColors(color.fillColor, color.backColor);
+ gfx->setStippleData(stipple);
+ gfx->setWireframe(true, color.backColor);
+ } else {
+ gfx->setStippleData(nullptr);
+ gfx->setWireframe(true, color.fillColor);
+ }
+
+ return stipple;
+}
+
// Map ObjColor â Mac B&W dither pattern (from ROBOCOLR.C MONOCHROME field).
// The monochrome field in the DOS table matches MacPattern enum values directly:
// WHITE=0, LTGRAY=1, GRAY=2, DKGRAY=3, BLACK=4, CLEAR=5.
@@ -613,17 +643,15 @@ void ColonyEngine::draw3DPrism(Thing &obj, const PrismPartDef &def, bool useLook
_gfx->draw3DPolygon(px, py, pz, count, 0); // black outline
_gfx->setStippleData(nullptr);
} else {
- // EGA: per-surface colors from DOS lsColor table.
- // polyfill ON â B&W fill (from MONOCHROME field), colored LINECOLOR outline.
+ // EGA: per-surface materials from the DOS lsColor table.
+ // polyfill ON â FILLCOLOR/BACKCOLOR/PATTERN fill, LINEFILLCOLOR outline.
// polyfill OFF â outline only with LINECOLOR.
const DOSColorEntry &dc = lookupDOSColor(colorIdx, _level);
if (!_wireframe) {
- // Polyfill mode: B&W fill + colored LINECOLOR outline.
- // LINECOLOR (not LINEFILLCOLOR) has proper contrast against B&W fills.
- if (dc.monochrome == kPatternClear)
- continue;
- _gfx->setWireframe(true, 7); // all surfaces white; colored outlines provide distinction
- _gfx->draw3DPolygon(px, py, pz, count, (uint32)dc.lineColor);
+ const byte *stipple = setupDOSMaterial(_gfx, dc);
+ _gfx->draw3DPolygon(px, py, pz, count, (uint32)dc.lineFillColor);
+ if (stipple)
+ _gfx->setStippleData(nullptr);
} else {
// Wireframe only: LINECOLOR outline, no fill.
_gfx->draw3DPolygon(px, py, pz, count, (uint32)dc.lineColor);
@@ -945,9 +973,9 @@ void ColonyEngine::renderCorridor3D() {
ceilColor = wallFill;
}
} else {
- // IBM_DISP.C: lit â BackColor(vWHITE)=15, color_wall=vwall_Light=0 (black lines on white bg)
+ // IBM_DISP.C: lit â BackColor(vWHITE)=7, color_wall=vwall_Light=0 (black lines on white bg)
// dark â BackColor(vBLACK)=0, color_wall=vINTWHITE=15 (white lines on black bg)
- wallFill = lit ? (macMode ? 255 : 15) : 0;
+ wallFill = lit ? (macMode ? 255 : 7) : 0;
wallLine = lit ? 0 : (macMode ? 255 : 15);
floorColor = macMode ? (lit ? 255 : 0) : wallFill;
ceilColor = macMode ? (lit ? 255 : 0) : wallFill;
@@ -1021,9 +1049,9 @@ void ColonyEngine::renderCorridor3D() {
// Full depth range objects beat walls and features at the same distance.
_gfx->setDepthRange(0.0f, 1.0f);
- // F7 toggles object fill.
- // EGA: default is filled (wall background); F7 = outline-only (see-through).
- // Mac: default is per-surface fill; F7 = "Fast mode" (outline-only).
+ // F8 toggles object fill.
+ // EGA: default is filled (wall background); F8 = outline-only (see-through).
+ // Mac: default is per-surface fill; F8 = "Fast mode" (outline-only).
if (_wireframe) {
_gfx->setWireframe(true); // No fill = outline-only objects
}
diff --git a/engines/colony/render_internal.h b/engines/colony/render_internal.h
index 3d61af62c9f..0e0bd948502 100644
--- a/engines/colony/render_internal.h
+++ b/engines/colony/render_internal.h
@@ -84,6 +84,19 @@ static const byte kStippleGray[128] = {
0xAA,0xAA,0xAA,0xAA, 0x55,0x55,0x55,0x55, 0xAA,0xAA,0xAA,0xAA, 0x55,0x55,0x55,0x55,
};
+// DOS FILLPATTERN 5 from METAWNDO.EXE: 12.5% foreground coverage.
+// The driver's 8x8 rows (88 00 22 00 88 00 22 00) are tiled to 32x32.
+static const byte kDOSStipplePattern5[128] = {
+ 0x88,0x88,0x88,0x88, 0x00,0x00,0x00,0x00, 0x22,0x22,0x22,0x22, 0x00,0x00,0x00,0x00,
+ 0x88,0x88,0x88,0x88, 0x00,0x00,0x00,0x00, 0x22,0x22,0x22,0x22, 0x00,0x00,0x00,0x00,
+ 0x88,0x88,0x88,0x88, 0x00,0x00,0x00,0x00, 0x22,0x22,0x22,0x22, 0x00,0x00,0x00,0x00,
+ 0x88,0x88,0x88,0x88, 0x00,0x00,0x00,0x00, 0x22,0x22,0x22,0x22, 0x00,0x00,0x00,0x00,
+ 0x88,0x88,0x88,0x88, 0x00,0x00,0x00,0x00, 0x22,0x22,0x22,0x22, 0x00,0x00,0x00,0x00,
+ 0x88,0x88,0x88,0x88, 0x00,0x00,0x00,0x00, 0x22,0x22,0x22,0x22, 0x00,0x00,0x00,0x00,
+ 0x88,0x88,0x88,0x88, 0x00,0x00,0x00,0x00, 0x22,0x22,0x22,0x22, 0x00,0x00,0x00,0x00,
+ 0x88,0x88,0x88,0x88, 0x00,0x00,0x00,0x00, 0x22,0x22,0x22,0x22, 0x00,0x00,0x00,0x00,
+};
+
static const byte kStippleDkGray[128] = {
// 0x77,0xDD alternating rows = 75% coverage (dense dots)
0x77,0x77,0x77,0x77, 0xDD,0xDD,0xDD,0xDD, 0x77,0x77,0x77,0x77, 0xDD,0xDD,0xDD,0xDD,
Commit: 6bb6a93d9807fb9e2591f9759a5d9e6e7aa76194
https://github.com/scummvm/scummvm/commit/6bb6a93d9807fb9e2591f9759a5d9e6e7aa76194
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-09-01T12:07:23+02:00
Commit Message:
COLONY: fix DOS polygon fills and eye rendering
Changed paths:
engines/colony/colony.h
engines/colony/render.cpp
engines/colony/render_features.cpp
engines/colony/render_internal.h
engines/colony/render_objects.cpp
diff --git a/engines/colony/colony.h b/engines/colony/colony.h
index a8178fd0114..c063e59b80a 100644
--- a/engines/colony/colony.h
+++ b/engines/colony/colony.h
@@ -203,8 +203,21 @@ enum ObjectType {
enum ObjColor {
kColorClear = 0,
kColorBlack = 1,
+ kColorBlue = 2,
+ kColorGreen = 3,
+ kColorCyan = 4,
+ kColorRed = 5,
+ kColorMagenta = 6,
+ kColorBrown = 7,
+ kColorWhite = 8,
kColorDkGray = 9,
+ kColorLtBlue = 10,
kColorLtGreen = 11,
+ kColorLtCyan = 12,
+ kColorLtRed = 13,
+ kColorLtMagenta = 14,
+ kColorYellow = 15,
+ kColorIntWhite = 16,
kColorBath = 17,
kColorWater = 18,
kColorSilver = 19,
@@ -264,6 +277,8 @@ enum ObjColor {
kColorBottomSnoop = 60,
kColorUPyramid = 68,
kColorShadow = 74,
+ kColorLtGray = 75,
+ kColorGray = 76,
// Animated reactor/power suit colors (Mac: c_hcore1..c_hcore4, c_ccore, c_color0..c_color3)
kColorHCore1 = 100,
kColorHCore2 = 101,
@@ -696,10 +711,13 @@ private:
void draw3DPrism(Thing &obj, const PrismPartDef &def, bool useLook, int colorOverride = -1, bool accumulateBounds = false, bool forceVisible = false);
void draw3DLeaf(const Thing &obj, const PrismPartDef &def);
void draw3DSphere(Thing &obj, int pt0x, int pt0y, int pt0z,
- int pt1x, int pt1y, int pt1z, uint32 fillColor, uint32 outlineColor, bool accumulateBounds = false);
- void drawPrismOval3D(Thing &thing, const PrismPartDef &def, bool useLook, int colorOverride, bool forceVisible = false);
+ int pt1x, int pt1y, int pt1z, uint32 fillColor, uint32 outlineColor,
+ bool accumulateBounds = false, bool dosFill = true);
+ void drawPrismOval3D(Thing &thing, const PrismPartDef &def, bool useLook, int colorOverride,
+ bool forceVisible = false, bool dosFill = true);
void drawEyeOverlays3D(Thing &thing, const PrismPartDef &irisDef, int irisColorOverride,
- const PrismPartDef &pupilDef, int pupilColorOverride, bool useLook);
+ const PrismPartDef &pupilDef, int pupilColorOverride, bool useLook, bool dosFill = true);
+ void drawDOSEyeSlit3D(Thing &thing, const PrismPartDef &irisDef, bool useLook);
void drawBodyEye3D(Thing &obj, int eyeballColor, int pupilColor, float pull);
void drawEnemyEye3D(Thing &obj, Thing &eye, int eyeballColor, int irisColor, int pupilColor);
void pullTowardCamera(float *px, float *py, float *pz, int count) const;
diff --git a/engines/colony/render.cpp b/engines/colony/render.cpp
index 1176e970289..3628d03fa90 100644
--- a/engines/colony/render.cpp
+++ b/engines/colony/render.cpp
@@ -180,12 +180,11 @@ const DOSColorEntry &lookupDOSColor(int colorIdx, int level) {
}
}
-// Reproduce the DOS driver's SetFill/FILLPATTERN material setup. Patterns 3,
-// 4 and 5 are respectively 50%, 25% and 12.5% foreground coverage; pattern 1
-// is a solid FILLCOLOR fill.
-const byte *setupDOSMaterial(Renderer *gfx, const DOSColorEntry &color) {
+// Reproduce the DOS driver's SetFill/FILLPATTERN setup. Patterns 3, 4 and 5
+// are respectively 50%, 25% and 12.5% foreground coverage; pattern 1 is solid.
+void setupDOSFill(Renderer *gfx, uint32 fillColor, uint32 backColor, int pattern) {
const byte *stipple = nullptr;
- switch (color.pattern) {
+ switch (pattern) {
case 3:
stipple = kStippleGray;
break;
@@ -200,15 +199,19 @@ const byte *setupDOSMaterial(Renderer *gfx, const DOSColorEntry &color) {
}
if (stipple) {
- gfx->setMacColors(color.fillColor, color.backColor);
+ gfx->setMacColors(fillColor, backColor);
gfx->setStippleData(stipple);
- gfx->setWireframe(true, color.backColor);
+ gfx->setWireframe(true, backColor);
} else {
gfx->setStippleData(nullptr);
- gfx->setWireframe(true, color.fillColor);
+ gfx->setWireframe(true, fillColor);
}
+}
- return stipple;
+uint32 setupDOSMaterial(Renderer *gfx, int colorIdx, int level) {
+ const DOSColorEntry &color = lookupDOSColor(colorIdx, level);
+ setupDOSFill(gfx, color.fillColor, color.backColor, color.pattern);
+ return color.lineFillColor;
}
// Map ObjColor â Mac B&W dither pattern (from ROBOCOLR.C MONOCHROME field).
@@ -648,10 +651,9 @@ void ColonyEngine::draw3DPrism(Thing &obj, const PrismPartDef &def, bool useLook
// polyfill OFF â outline only with LINECOLOR.
const DOSColorEntry &dc = lookupDOSColor(colorIdx, _level);
if (!_wireframe) {
- const byte *stipple = setupDOSMaterial(_gfx, dc);
- _gfx->draw3DPolygon(px, py, pz, count, (uint32)dc.lineFillColor);
- if (stipple)
- _gfx->setStippleData(nullptr);
+ const uint32 outlineColor = setupDOSMaterial(_gfx, colorIdx, _level);
+ _gfx->draw3DPolygon(px, py, pz, count, outlineColor);
+ _gfx->setStippleData(nullptr);
} else {
// Wireframe only: LINECOLOR outline, no fill.
_gfx->draw3DPolygon(px, py, pz, count, (uint32)dc.lineColor);
@@ -731,7 +733,7 @@ void ColonyEngine::pullTowardCamera(float *px, float *py, float *pz, int count)
void ColonyEngine::draw3DSphere(Thing &obj, int pt0x, int pt0y, int pt0z,
int pt1x, int pt1y, int pt1z,
- uint32 fillColor, uint32 outlineColor, bool accumulateBounds) {
+ uint32 fillColor, uint32 outlineColor, bool accumulateBounds, bool dosFill) {
// Original Colony eye/ball primitives store the bottom pole in pt0 and the
// sphere center in pt1. The classic renderer builds the oval from the
// screen-space delta between those two projected points, so the world-space
@@ -840,25 +842,30 @@ void ColonyEngine::draw3DSphere(Thing &obj, int pt0x, int pt0y, int pt0z,
_gfx->draw3DPolygon(px, py, pz, N, line);
if (stipple)
_gfx->setStippleData(nullptr);
- } else if (lit) {
- if (isMacRenderMode()) {
- int pattern = lookupMacPattern((int)fillColor, _level);
- if (pattern == kPatternClear)
- pattern = kPatternGray;
- if (!_wireframe) {
- _gfx->setWireframe(true, pattern == kPatternBlack ? 0 : 255);
- }
- _gfx->setStippleData(kMacStippleData[pattern]);
- _gfx->draw3DPolygon(px, py, pz, N, lookupDOSColor((int)outlineColor, _level).lineColor);
+ } else if (!isMacRenderMode()) {
+ // DOS eye ovals are independent of the polygon-fill toggle. FillOval()
+ // uses the selected material while FrameOval() uses the caller's pen.
+ const DOSColorEntry &fill = lookupDOSColor((int)fillColor, _level);
+ const DOSColorEntry &outline = lookupDOSColor((int)outlineColor, _level);
+ if (dosFill)
+ setupDOSFill(_gfx, fill.fillColor, fill.backColor, fill.pattern);
+ else {
_gfx->setStippleData(nullptr);
- } else {
- const DOSColorEntry &fill = lookupDOSColor((int)fillColor, _level);
- const DOSColorEntry &outline = lookupDOSColor((int)outlineColor, _level);
- if (!_wireframe) {
- _gfx->setWireframe(true, fill.fillColor);
- }
- _gfx->draw3DPolygon(px, py, pz, N, outline.lineColor);
+ _gfx->setWireframe(true);
}
+ _gfx->draw3DPolygon(px, py, pz, N, outline.lineColor);
+ _gfx->setStippleData(nullptr);
+ if (_wireframe)
+ _gfx->setWireframe(true);
+ } else if (lit) {
+ int pattern = lookupMacPattern((int)fillColor, _level);
+ if (pattern == kPatternClear)
+ pattern = kPatternGray;
+ if (!_wireframe)
+ _gfx->setWireframe(true, pattern == kPatternBlack ? 0 : 255);
+ _gfx->setStippleData(kMacStippleData[pattern]);
+ _gfx->draw3DPolygon(px, py, pz, N, lookupDOSColor((int)outlineColor, _level).lineColor);
+ _gfx->setStippleData(nullptr);
} else {
// Unlit: black fill, white outline.
if (!_wireframe) {
diff --git a/engines/colony/render_features.cpp b/engines/colony/render_features.cpp
index 7d5ca1af7e2..50f90d4f5b3 100644
--- a/engines/colony/render_features.cpp
+++ b/engines/colony/render_features.cpp
@@ -512,7 +512,7 @@ void ColonyEngine::drawCellFeature3D(int cellX, int cellY) {
const bool macMode = isMacRenderMode();
const bool macColors = isMacColorMode();
- // Helper lambda: draw a filled hole polygon with Mac color or B&W fallback
+ // Helper lambda: draw a filled hole polygon with the platform material.
auto drawHolePoly = [&](const float *u, const float *v, int cnt, int macIdx) {
if (macColors) {
uint32 fg = packMacColor(_macColors[macIdx].fg);
@@ -526,7 +526,12 @@ void ColonyEngine::drawCellFeature3D(int cellX, int cellY) {
_gfx->setStippleData(kStippleGray);
wallPolygon(corners, u, v, cnt, 0);
_gfx->setStippleData(nullptr);
+ } else if (!_wireframe) {
+ const uint32 outline = setupDOSMaterial(_gfx, kColorLtGray, _level);
+ wallPolygon(corners, u, v, cnt, outline);
+ _gfx->setStippleData(nullptr);
} else {
+ _gfx->setWireframe(true);
wallPolygon(corners, u, v, cnt, holeColor);
}
};
@@ -554,6 +559,10 @@ void ColonyEngine::drawCellFeature3D(int cellX, int cellY) {
float v[4] = {0.0f, 0.0f, 1.0f, 1.0f};
if (macMode) {
drawHolePoly(u, v, 4, 31); // c_hotplate
+ } else if (!_wireframe) {
+ const uint32 outline = setupDOSMaterial(_gfx, kColorTele, _level);
+ wallPolygon(corners, u, v, 4, outline);
+ _gfx->setStippleData(nullptr);
} else {
// DOS non-polyfill: X pattern (two diagonals)
wallLine(corners, 0.0f, 0.0f, 1.0f, 1.0f, holeColor);
@@ -564,6 +573,12 @@ void ColonyEngine::drawCellFeature3D(int cellX, int cellY) {
default:
break;
}
+
+ _gfx->setStippleData(nullptr);
+ const uint32 wallFill = macColors
+ ? packMacColor(_macColors[8 + _level - 1].fg)
+ : (macMode ? 255u : 7u);
+ _gfx->setWireframe(true, wallFill);
}
float stairStepHeight(const float *vf, const float *vc, int d, int s) {
@@ -620,9 +635,24 @@ void ColonyEngine::drawWallFeature3D(int cellX, int cellY, int direction) {
_gfx->setStippleData(nullptr);
};
+ // DOS SuperPoly(): material fill followed by its LINEFILLCOLOR frame.
+ auto dosFillPoly = [&](const float *u, const float *v, int cnt, int colorIdx) {
+ const uint32 outline = setupDOSMaterial(_gfx, colorIdx, _level);
+ wallPolygon(corners, u, v, cnt, outline);
+ _gfx->setStippleData(nullptr);
+ };
+
+ auto dosFillRecess = [&](const float nearC[4][3], const float farC[4][3],
+ const float *u, const float *v, const float *d, int cnt, int colorIdx) {
+ const uint32 outline = setupDOSMaterial(_gfx, colorIdx, _level);
+ recessQuad(nearC, farC, u, v, d, cnt, outline);
+ _gfx->setStippleData(nullptr);
+ };
+
switch (map[0]) {
case kWallFeatureDoor: {
- const uint32 doorColor = macColors ? (uint32)0xFF000000 : (macMode ? 0 : 8);
+ const uint32 doorColor = macColors ? (uint32)0xFF000000 :
+ (macMode ? 0u : (_wireframe ? 8u : 0u));
bool shipLevel = (_level == 1 || _level == 5 || _level == 6);
if (shipLevel) {
@@ -645,15 +675,7 @@ void ColonyEngine::drawWallFeature3D(int cellX, int cellY, int direction) {
wallPolygon(corners, uSs, vSs, 8, 0);
}
} else if (!_wireframe) {
- if (map[1] != 0) {
- const byte *stipple = setupMacPattern(_gfx, kPatternLtGray, 0, 15);
- wallPolygon(corners, uSs, vSs, 8, 0);
- if (stipple)
- _gfx->setStippleData(nullptr);
- } else {
- _gfx->setWireframe(true, 0);
- wallPolygon(corners, uSs, vSs, 8, 0);
- }
+ dosFillPoly(uSs, vSs, 8, map[1] != 0 ? kColorSilver : kColorBlack);
} else {
_gfx->setWireframe(true);
wallPolygon(corners, uSs, vSs, 8, 8);
@@ -671,10 +693,10 @@ void ColonyEngine::drawWallFeature3D(int cellX, int cellY, int direction) {
} else {
const float xl = 0.25f, xr = 0.75f;
const float yb = 0.0f, yt = 0.875f;
+ float ud[4] = {xl, xr, xr, xl};
+ float vd[4] = {yb, yb, yt, yt};
if (macMode) {
- float ud[4] = {xl, xr, xr, xl};
- float vd[4] = {yb, yb, yt, yt};
if (map[1] != 0) {
if (macColors) {
macFillPoly(ud, vd, 4, 16); // c_door
@@ -689,6 +711,16 @@ void ColonyEngine::drawWallFeature3D(int cellX, int cellY, int direction) {
wallPolygon(corners, ud, vd, 4, 0);
_gfx->setWireframe(true, 255);
}
+ } else if (!_wireframe) {
+ dosFillPoly(ud, vd, 4, map[1] != 0 ? kColorLtRed : kColorBlack);
+ if (map[1] == 0) {
+ float farC[4][3];
+ getWallRecess3D(corners, farC);
+ const float floorU[4] = {xl, xl, xr, xr};
+ const float floorV[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ const float floorD[4] = {0.0f, 1.0f, 1.0f, 0.0f};
+ dosFillRecess(corners, farC, floorU, floorV, floorD, 4, kColorWhite);
+ }
}
wallLine(corners, xl, yb, xl, yt, doorColor);
@@ -697,21 +729,22 @@ void ColonyEngine::drawWallFeature3D(int cellX, int cellY, int direction) {
wallLine(corners, xr, yb, xl, yb, doorColor);
if (map[1] != 0) {
- wallLine(corners, 0.3125f, 0.4375f, 0.6875f, 0.4375f, doorColor);
+ const uint32 detailColor = macMode ? doorColor : 8u;
+ wallLine(corners, 0.3125f, 0.4375f, 0.6875f, 0.4375f, detailColor);
}
}
break;
}
case kWallFeatureWindow: {
- const uint32 winColor = macColors ? (uint32)0xFF000000 : (macMode ? 0 : 8);
+ const uint32 winColor = macColors ? (uint32)0xFF000000 : 0;
float xl = 0.25f, xr = 0.75f;
float yb = 0.25f, yt = 0.75f;
float xc = 0.5f, yc = 0.5f;
+ float uw[4] = {xl, xr, xr, xl};
+ float vw[4] = {yb, yb, yt, yt};
// Mac: fill window pane
if (macMode) {
- float uw[4] = {xl, xr, xr, xl};
- float vw[4] = {yb, yb, yt, yt};
if (macColors) {
macFillPoly(uw, vw, 4, 17); // c_window
} else {
@@ -719,6 +752,8 @@ void ColonyEngine::drawWallFeature3D(int cellX, int cellY, int direction) {
wallPolygon(corners, uw, vw, 4, 0);
_gfx->setStippleData(nullptr);
}
+ } else if (!_wireframe) {
+ dosFillPoly(uw, vw, 4, kColorSilver);
}
wallLine(corners, xl, yb, xl, yt, winColor);
@@ -803,6 +838,29 @@ void ColonyEngine::drawWallFeature3D(int cellX, int cellY, int direction) {
const float vb[4] = {hgt[6], hgt[6], hgt[6], hgt[6]};
const float db[4] = {dep[6], 1.0f, 1.0f, dep[6]};
macFillRecess(corners, farC, ub, vb, db, 4, 19, macColors);
+ } else if (!_wireframe) {
+ const float uw[4] = {0.0f, 1.0f, 1.0f, 0.0f};
+ const float vw[4] = {0.0f, 0.0f, 1.0f, 1.0f};
+ const float dw[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ dosFillRecess(corners, farC, uw, vw, dw, 4, kColorGray);
+
+ for (int i = 6; i >= 0; i--) {
+ const float lowV = (i > 0) ? hgt[i - 1] : 0.0f;
+ const float backD = (i > 0) ? dep[i - 1] : 0.0f;
+ const float uq[4] = {0.0f, 0.0f, 1.0f, 1.0f};
+ const float vRiser[4] = {hgt[i], lowV, lowV, hgt[i]};
+ const float dRiser[4] = {dep[i], dep[i], dep[i], dep[i]};
+ dosFillRecess(corners, farC, uq, vRiser, dRiser, 4, kColorGray);
+
+ const float vTread[4] = {lowV, lowV, lowV, lowV};
+ const float dTread[4] = {backD, dep[i], dep[i], backD};
+ dosFillRecess(corners, farC, uq, vTread, dTread, 4, kColorLtGray);
+ }
+
+ const float ub[4] = {0.0f, 0.0f, 1.0f, 1.0f};
+ const float vb[4] = {hgt[6], hgt[6], hgt[6], hgt[6]};
+ const float db[4] = {dep[6], 1.0f, 1.0f, dep[6]};
+ dosFillRecess(corners, farC, ub, vb, db, 4, kColorLtGray);
}
// Back landing and far mouth
@@ -907,11 +965,11 @@ void ColonyEngine::drawWallFeature3D(int cellX, int cellY, int direction) {
const uint32 elevColor = macColors ? (uint32)0xFF000000 : (macMode ? 0 : 8);
float xl = 0.2f, xr = 0.8f;
float yb = 0.1f, yt = 0.9f;
+ float ue[4] = {xl, xr, xr, xl};
+ float ve[4] = {yb, yb, yt, yt};
// Mac: fill elevator door
if (macMode) {
- float ue[4] = {xl, xr, xr, xl};
- float ve[4] = {yb, yb, yt, yt};
if (macColors) {
macFillPoly(ue, ve, 4, 23); // c_elevator
} else {
@@ -919,6 +977,8 @@ void ColonyEngine::drawWallFeature3D(int cellX, int cellY, int direction) {
wallPolygon(corners, ue, ve, 4, 0);
_gfx->setStippleData(nullptr);
}
+ } else if (!_wireframe) {
+ dosFillPoly(ue, ve, 4, kColorGray);
}
wallLine(corners, xl, yb, xl, yt, elevColor);
@@ -940,8 +1000,11 @@ void ColonyEngine::drawWallFeature3D(int cellX, int cellY, int direction) {
wallPolygon(corners, uT, vT, 6, 0);
_gfx->setStippleData(nullptr);
}
+ } else if (!_wireframe) {
+ dosFillPoly(uT, vT, 6, kColorBlack);
} else {
- wallPolygon(corners, uT, vT, 6, 0); // vBLACK outline
+ _gfx->setWireframe(true);
+ wallPolygon(corners, uT, vT, 6, 8); // vDKGRAY outline
}
break;
}
@@ -957,11 +1020,15 @@ void ColonyEngine::drawWallFeature3D(int cellX, int cellY, int direction) {
if (map[1] == 0) {
// Original drawALOpen: solid black opening on both DOS and Mac.
- if (macMode || !_wireframe)
+ if (macMode) {
_gfx->setWireframe(true, 0);
- else
+ wallPolygon(corners, u, v, 8, 0);
+ } else if (!_wireframe) {
+ dosFillPoly(u, v, 8, kColorBlack);
+ } else {
_gfx->setWireframe(true);
- wallPolygon(corners, u, v, 8, 0);
+ wallPolygon(corners, u, v, 8, 0);
+ }
} else {
// Mac: fill airlock when closed
if (macMode) {
@@ -973,10 +1040,7 @@ void ColonyEngine::drawWallFeature3D(int cellX, int cellY, int direction) {
_gfx->setStippleData(nullptr);
}
} else if (!_wireframe) {
- const byte *stipple = setupMacPattern(_gfx, kPatternLtGray, 0, 15);
- wallPolygon(corners, u, v, 8, 0);
- if (stipple)
- _gfx->setStippleData(nullptr);
+ dosFillPoly(u, v, 8, kColorLtGray);
}
const uint32 airlockColor = macColors ? (uint32)0xFF000000 : (macMode ? 0 : 8);
@@ -1042,12 +1106,47 @@ void ColonyEngine::drawWallFeature3D(int cellX, int cellY, int direction) {
}
}
}
+ } else if (!_wireframe) {
+ for (int i = 0; i < 4; i++) {
+ const int value = map[i + 1];
+ int material = -1;
+ if (value <= 4) {
+ switch (value) {
+ case 1: material = kColorLtRed; break;
+ case 2: material = kColorLtBlue; break;
+ case 3: material = kColorMagenta; break;
+ case 4: material = kColorBlue; break;
+ default: break; // WHITE leaves the corridor background intact
+ }
+ } else {
+ const int color = (value + _displayCount / 6) % 5;
+ switch (color) {
+ case 1: material = kColorLtRed; break;
+ case 2: material = kColorMagenta; break;
+ case 3: material = kColorRed; break;
+ case 4: material = kColorCyan; break;
+ default: break;
+ }
+ }
+
+ if (material >= 0) {
+ const float vb = (3 - i) / 4.0f;
+ const float vt = (4 - i) / 4.0f;
+ const float ub[4] = {0.0f, 1.0f, 1.0f, 0.0f};
+ const float vb4[4] = {vb, vb, vt, vt};
+ dosFillPoly(ub, vb4, 4, material);
+ }
+ }
+ } else if (map[1] || map[2] || map[3] || map[4]) {
+ _gfx->setWireframe(true);
+ for (int i = 1; i <= 3; i++) {
+ const float v = (float)i / 4.0f;
+ wallLine(corners, 0.0f, v, 1.0f, v, 0);
+ }
}
- // EGA / Mac B&W: colored lines at band boundaries.
- // DOS non-polyfill draws 3 lines; we animate line colors for bands > 4.
- // Mac color mode uses macFillPoly for band fills instead.
- if (!macColors) {
+ // Preserve the Mac B&W boundary treatment after its pattern fills.
+ if (macMode && !macColors) {
for (int i = 1; i <= 3; i++) {
int val = map[i];
if (val > 4)
diff --git a/engines/colony/render_internal.h b/engines/colony/render_internal.h
index 0e0bd948502..48b1acdb354 100644
--- a/engines/colony/render_internal.h
+++ b/engines/colony/render_internal.h
@@ -39,6 +39,12 @@ void projectCorridorPointClamped(const Common::Rect &screenR, int look, int look
float worldX, float worldY, float worldZ,
int &screenX, int &screenY);
+// DOS MetaWINDOW polygon material setup. setupDOSFill() accepts EGA palette
+// indices directly; setupDOSMaterial() resolves an lsColor material and returns
+// the LINEFILLCOLOR used to frame the filled polygon.
+void setupDOSFill(Renderer *gfx, uint32 fillColor, uint32 backColor, int pattern);
+uint32 setupDOSMaterial(Renderer *gfx, int colorIdx, int level);
+
// Mac Classic dither patterns (from colorize.c cColor[].pattern).
// Mac Classic was a 1-bit B&W display. QuickDraw used 8x8 dither patterns
// to simulate grayscale: WHITE, LTGRAY, GRAY, DKGRAY, BLACK, CLEAR.
@@ -122,7 +128,7 @@ static const byte *kMacStippleData[] = {
// Helper: set up Mac color stipple rendering for a given cColor[] pattern.
// Configures setMacColors/setStippleData/setWireframe for the pattern type.
// Returns the stipple pointer (null for solid patterns) caller must clear with setStippleData(nullptr).
-static const byte *setupMacPattern(Renderer *gfx, int pattern, uint32 fg, uint32 bg) {
+inline const byte *setupMacPattern(Renderer *gfx, int pattern, uint32 fg, uint32 bg) {
const byte *stipple = (pattern >= 1 && pattern <= 3) ? kMacStippleData[pattern] : nullptr;
if (stipple) {
gfx->setMacColors(fg, bg);
diff --git a/engines/colony/render_objects.cpp b/engines/colony/render_objects.cpp
index e0dbf38e32e..caa7a692fbd 100644
--- a/engines/colony/render_objects.cpp
+++ b/engines/colony/render_objects.cpp
@@ -50,26 +50,26 @@ int mapEyeOverlayColorToMacColor(int colorIdx, int level) {
}
}
-uint8 mapEyeOverlayColorToDOSFill(int colorIdx, int level) {
+uint32 setupDOSEyeOverlayMaterial(Renderer *gfx, int colorIdx, int level) {
switch (colorIdx) {
case kColorBlack:
case kColorPupil:
+ setupDOSFill(gfx, 0, 0, 1); // solid vBLACK
return 0;
- case kColorEyeball:
- return 15;
- case kColorIris:
- case kColorEyeIris:
- case kColorMiniEyeIris:
case kColorDroneEye:
case kColorSoldierEye:
case kColorQueenEye:
- return 1;
+ // QUEEN.C draweyes(): vGREEN over vYELLOW with pattern 4 on
+ // level 7; otherwise vGREEN over vINTWHITE with pattern 3.
+ setupDOSFill(gfx, 2, level == 7 ? 14 : 15, level == 7 ? 4 : 3);
+ return 2;
+ case kColorIris:
+ case kColorEyeIris:
+ case kColorMiniEyeIris:
default:
- if (colorIdx >= 0 && colorIdx <= 15)
- return (uint8)colorIdx;
- if (colorIdx == kColorQueenBody && level == 7)
- return 15;
- return 7;
+ // EYE.C/PYRAMID.C: vBLUE over vINTWHITE with pattern 3.
+ setupDOSFill(gfx, 1, 15, 3);
+ return 1;
}
}
@@ -1318,7 +1318,8 @@ void ColonyEngine::drawStaticObjects() {
_insight = _weapons > 0 && hasAimedRobotTarget();
}
-void ColonyEngine::drawPrismOval3D(Thing &thing, const PrismPartDef &def, bool useLook, int colorOverride, bool forceVisible) {
+void ColonyEngine::drawPrismOval3D(Thing &thing, const PrismPartDef &def, bool useLook,
+ int colorOverride, bool forceVisible, bool dosFill) {
if (def.pointCount < 4 || def.surfaceCount < 1)
return;
@@ -1412,21 +1413,25 @@ void ColonyEngine::drawPrismOval3D(Thing &thing, const PrismPartDef &def, bool u
_gfx->draw3DPolygon(px, py, pz, kSegments, line);
if (stipple)
_gfx->setStippleData(nullptr);
- } else if (lit) {
- if (isMacRenderMode()) {
- int pattern = mapEyeOverlayColorToMacPattern(fillColorIdx);
- if (pattern == kPatternClear)
- return;
- if (!_wireframe)
- _gfx->setWireframe(true, pattern == kPatternBlack ? 0 : 255);
- _gfx->setStippleData(kMacStippleData[pattern]);
- _gfx->draw3DPolygon(px, py, pz, kSegments, 0);
+ } else if (!isMacRenderMode()) {
+ const uint32 outline = setupDOSEyeOverlayMaterial(_gfx, fillColorIdx, _level);
+ if (!dosFill) {
_gfx->setStippleData(nullptr);
- } else {
- if (!_wireframe)
- _gfx->setWireframe(true, mapEyeOverlayColorToDOSFill(fillColorIdx, _level));
- _gfx->draw3DPolygon(px, py, pz, kSegments, 0);
+ _gfx->setWireframe(true);
}
+ _gfx->draw3DPolygon(px, py, pz, kSegments, outline);
+ _gfx->setStippleData(nullptr);
+ if (_wireframe)
+ _gfx->setWireframe(true);
+ } else if (lit) {
+ int pattern = mapEyeOverlayColorToMacPattern(fillColorIdx);
+ if (pattern == kPatternClear)
+ return;
+ if (!_wireframe)
+ _gfx->setWireframe(true, pattern == kPatternBlack ? 0 : 255);
+ _gfx->setStippleData(kMacStippleData[pattern]);
+ _gfx->draw3DPolygon(px, py, pz, kSegments, 0);
+ _gfx->setStippleData(nullptr);
} else {
if (!_wireframe)
_gfx->setWireframe(true, 0);
@@ -1439,25 +1444,94 @@ void ColonyEngine::drawPrismOval3D(Thing &thing, const PrismPartDef &def, bool u
thing.where.zmx = MAX(thing.where.zmx, bottom);
}
+void ColonyEngine::drawDOSEyeSlit3D(Thing &thing, const PrismPartDef &irisDef, bool useLook) {
+ if (irisDef.pointCount < 4)
+ return;
+
+ const uint8 ang = (useLook ? thing.where.look : thing.where.ang) + 32;
+ const int32 rotCos = _cost[ang];
+ const int32 rotSin = _sint[ang];
+ float eye[4][3];
+ for (int i = 0; i < 4; i++) {
+ const int32 rx = ((int32)irisDef.points[i][0] * rotCos -
+ (int32)irisDef.points[i][1] * rotSin) >> 7;
+ const int32 ry = ((int32)irisDef.points[i][0] * rotSin +
+ (int32)irisDef.points[i][1] * rotCos) >> 7;
+ eye[i][0] = (float)(rx + thing.where.xloc);
+ eye[i][1] = (float)(ry + thing.where.yloc);
+ eye[i][2] = (float)(irisDef.points[i][2] - 160);
+ }
+
+ float center[3];
+ float halfWidth[3];
+ float halfHeight[3];
+ for (int axis = 0; axis < 3; axis++) {
+ center[axis] = (eye[0][axis] + eye[1][axis] + eye[2][axis] + eye[3][axis]) * 0.25f;
+ // QUEEN.C uses an iris-width/8 pen and leaves 1/16 of the iris
+ // height clear at each end of the vertical slit.
+ halfWidth[axis] = (eye[1][axis] - eye[3][axis]) / 16.0f;
+ halfHeight[axis] = (eye[2][axis] - eye[0][axis]) * (7.0f / 16.0f);
+ }
+
+ float px[4];
+ float py[4];
+ float pz[4];
+ const float widthSign[4] = {-1.0f, 1.0f, 1.0f, -1.0f};
+ const float heightSign[4] = {-1.0f, -1.0f, 1.0f, 1.0f};
+ for (int i = 0; i < 4; i++) {
+ px[i] = center[0] + widthSign[i] * halfWidth[0] + heightSign[i] * halfHeight[0];
+ py[i] = center[1] + widthSign[i] * halfWidth[1] + heightSign[i] * halfHeight[1];
+ pz[i] = center[2] + widthSign[i] * halfWidth[2] + heightSign[i] * halfHeight[2];
+ }
+
+ pullTowardCamera(px, py, pz, 4);
+ setupDOSFill(_gfx, 0, 0, 1);
+ _gfx->draw3DPolygon(px, py, pz, 4, 0);
+ _gfx->setStippleData(nullptr);
+ if (_wireframe)
+ _gfx->setWireframe(true);
+}
+
void ColonyEngine::drawEyeOverlays3D(Thing &thing, const PrismPartDef &irisDef, int irisColorOverride,
- const PrismPartDef &pupilDef, int pupilColorOverride, bool useLook) {
+ const PrismPartDef &pupilDef, int pupilColorOverride, bool useLook, bool dosFill) {
if (!isProjectedPrismSurfaceVisible(_screenR, thing, irisDef, useLook, 0,
_me.look, _me.lookY, _me.xloc, _me.yloc, _sint, _cost)) {
return;
}
- // Original Mac eye rendering uses the iris quad as the single visibility
- // gate, then draws both iris and pupil unconditionally.
- drawPrismOval3D(thing, irisDef, useLook, irisColorOverride, true);
- drawPrismOval3D(thing, pupilDef, useLook, pupilColorOverride, true);
+ // The original uses the iris quad as the single visibility gate, then draws
+ // both overlays unconditionally.
+ drawPrismOval3D(thing, irisDef, useLook, irisColorOverride, true, dosFill);
+
+ const int irisColor = irisColorOverride >= 0 ? irisColorOverride : irisDef.surfaces[0][0];
+ const bool dosEnemyEye = !isMacRenderMode() &&
+ (irisColor == kColorQueenEye || irisColor == kColorDroneEye || irisColor == kColorSoldierEye);
+ if (dosEnemyEye && _level == 7) {
+ drawDOSEyeSlit3D(thing, irisDef, useLook);
+ } else {
+ const int pupilColor = isMacRenderMode() ? pupilColorOverride : kColorPupil;
+ drawPrismOval3D(thing, pupilDef, useLook, pupilColor, true, dosFill);
+ }
}
// draweyes() of Queen/Drone/Soldier. Writes off: a turned eye leaves the iris
// quad behind the camera-facing ball, which would then clip it.
void ColonyEngine::drawEnemyEye3D(Thing &obj, Thing &eye, int eyeballColor, int irisColor, int pupilColor) {
+ bool dosFill = true;
+ if (!isMacRenderMode()) {
+ const uint8 eyeAng = obj.where.ang + 32;
+ const int32 eyeBaseX = obj.where.xloc + (_cost[eyeAng] >> 1);
+ const int32 eyeBaseY = obj.where.yloc + (_sint[eyeAng] >> 1);
+ const int64 dx = eyeBaseX - _me.xloc;
+ const int64 dy = eyeBaseY - _me.yloc;
+ dosFill = dx * dx + dy * dy > 64 * 64;
+ }
+
_gfx->setDepthState(true, false);
- draw3DSphere(eye, 0, 0, 130, 0, 0, 155, eyeballColor, kColorBlack, true);
- drawEyeOverlays3D(eye, kQIrisDef, irisColor, kQPupilDef, pupilColor, true);
+ const int ballColor = isMacRenderMode() ? eyeballColor : kColorRed;
+ const int ballOutline = isMacRenderMode() ? kColorBlack : kColorIntWhite;
+ draw3DSphere(eye, 0, 0, 130, 0, 0, 155, ballColor, ballOutline, true, dosFill);
+ drawEyeOverlays3D(eye, kQIrisDef, irisColor, kQPupilDef, pupilColor, true, dosFill);
_gfx->setDepthState(true, true);
mergeObjectBounds(obj.where, eye.where);
}
@@ -1468,7 +1542,8 @@ void ColonyEngine::drawEnemyEye3D(Thing &obj, Thing &eye, int eyeballColor, int
void ColonyEngine::drawBodyEye3D(Thing &obj, int eyeballColor, int pupilColor, float pull) {
_eyeDepthPull = pull;
_gfx->setDepthState(true, false);
- draw3DSphere(obj, 0, 0, 175, 0, 0, 200, eyeballColor, kColorBlack, true);
+ const int ballColor = isMacRenderMode() ? eyeballColor : kColorEye;
+ draw3DSphere(obj, 0, 0, 175, 0, 0, 200, ballColor, kColorBlack, true);
drawEyeOverlays3D(obj, kPIrisDef, -1, kPPupilDef, pupilColor, false);
_gfx->setDepthState(true, true);
_eyeDepthPull = 0.0f;
@@ -1586,7 +1661,9 @@ void ColonyEngine::drawInterpolatedGrowEye(Thing &obj, int fromStage, int toStag
const int z0 = interpolatedRobotPoint(sphereZ[fromStage][0], sphereZ[toStage][0], progress);
const int z1 = interpolatedRobotPoint(sphereZ[fromStage][1], sphereZ[toStage][1], progress);
_gfx->setDepthState(true, false);
- draw3DSphere(obj, 0, 0, z0, 0, 0, z1, eyeballColor, kColorBlack, true);
+ const int ballColor = isMacRenderMode() ? eyeballColor : kColorEye;
+ const int ballOutline = isMacRenderMode() ? kColorBlack : kColorEye;
+ draw3DSphere(obj, 0, 0, z0, 0, 0, z1, ballColor, ballOutline, true);
const PrismPartDef &fromIris = growEyeIrisDefForStage(fromStage);
const PrismPartDef &toIris = growEyeIrisDefForStage(toStage);
@@ -1649,6 +1726,8 @@ bool ColonyEngine::drawInterpolatedGrowRobot(Thing &obj, int eyeballColor, int p
bool ColonyEngine::drawStaticObjectPrisms3D(Thing &obj) {
const int eyeballColor = (_level == 1 || _level == 7) ? kColorPupil : kColorEyeball;
const int pupilColor = (_level == 1 || _level == 7) ? kColorEyeball : kColorPupil;
+ const int standaloneBallColor = isMacRenderMode() ? eyeballColor : kColorEye;
+ const int standaloneBallOutline = isMacRenderMode() ? kColorBlack : kColorEye;
switch (obj.type) {
case kObjConsole:
@@ -1933,7 +2012,8 @@ bool ColonyEngine::drawStaticObjectPrisms3D(Thing &obj) {
}
// Writes off, as in drawEnemyEye3D().
_gfx->setDepthState(true, false);
- draw3DSphere(obj, 0, 0, 100, 0, 0, 200, eyeballColor, kColorBlack, true);
+ draw3DSphere(obj, 0, 0, 100, 0, 0, 200,
+ standaloneBallColor, standaloneBallOutline, true);
drawEyeOverlays3D(obj, kEyeIrisDef, -1, kEyePupilDef, pupilColor, false);
_gfx->setDepthState(true, true);
break;
@@ -1965,7 +2045,8 @@ bool ColonyEngine::drawStaticObjectPrisms3D(Thing &obj) {
if (drawInterpolatedGrowRobot(obj, eyeballColor, pupilColor))
break;
_gfx->setDepthState(true, false);
- draw3DSphere(obj, 0, 0, 0, 0, 0, 100, eyeballColor, kColorBlack, true);
+ draw3DSphere(obj, 0, 0, 0, 0, 0, 100,
+ standaloneBallColor, standaloneBallOutline, true);
drawEyeOverlays3D(obj, kFEyeIrisDef, -1, kFEyePupilDef, pupilColor, false);
_gfx->setDepthState(true, true);
break;
@@ -1988,7 +2069,8 @@ bool ColonyEngine::drawStaticObjectPrisms3D(Thing &obj) {
if (drawInterpolatedGrowRobot(obj, eyeballColor, pupilColor))
break;
_gfx->setDepthState(true, false);
- draw3DSphere(obj, 0, 0, 0, 0, 0, 50, eyeballColor, kColorBlack, true);
+ draw3DSphere(obj, 0, 0, 0, 0, 0, 50,
+ standaloneBallColor, standaloneBallOutline, true);
drawEyeOverlays3D(obj, kSEyeIrisDef, -1, kSEyePupilDef, pupilColor, false);
_gfx->setDepthState(true, true);
break;
@@ -2011,7 +2093,8 @@ bool ColonyEngine::drawStaticObjectPrisms3D(Thing &obj) {
if (drawInterpolatedGrowRobot(obj, eyeballColor, pupilColor))
break;
_gfx->setDepthState(true, false);
- draw3DSphere(obj, 0, 0, 0, 0, 0, 25, eyeballColor, kColorBlack, true);
+ draw3DSphere(obj, 0, 0, 0, 0, 0, 25,
+ standaloneBallColor, standaloneBallOutline, true);
drawEyeOverlays3D(obj, kMEyeIrisDef, kColorMiniEyeIris, kMEyePupilDef, pupilColor, false);
_gfx->setDepthState(true, true);
break;
Commit: 5de262b804e39b72977b9b3ca6ff214e0553e39c
https://github.com/scummvm/scummvm/commit/5de262b804e39b72977b9b3ca6ff214e0553e39c
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-09-01T12:07:23+02:00
Commit Message:
COLONY: fix aspect ratio rendering for DOS release
Changed paths:
engines/colony/animation.cpp
engines/colony/battle.cpp
engines/colony/gfx.cpp
engines/colony/intro.cpp
engines/colony/render.cpp
engines/colony/render_objects.cpp
engines/colony/renderer.h
engines/colony/renderer_opengl.cpp
engines/colony/renderer_opengl_shaders.cpp
diff --git a/engines/colony/animation.cpp b/engines/colony/animation.cpp
index fa1cffc3b5e..3bc87683dd6 100644
--- a/engines/colony/animation.cpp
+++ b/engines/colony/animation.cpp
@@ -409,6 +409,9 @@ void ColonyEngine::playAnimation() {
_coderWin = Common::Rect();
_coderPressed = -1;
_coderPressInside = false;
+ const bool useSquarePixelViewport = !isMacRenderMode();
+ if (useSquarePixelViewport)
+ _gfx->setSquarePixelViewport(true);
_system->lockMouse(false);
warpMouseLogical(_centerX, _centerY);
const char *cursorName = "default arrow cursor";
@@ -599,7 +602,7 @@ void ColonyEngine::playAnimation() {
while (_system->getEventManager()->pollEvent(event)) {
if (event.type == Common::EVENT_QUIT || event.type == Common::EVENT_RETURN_TO_LAUNCHER) {
_animationRunning = false;
- return;
+ break;
} else if (event.type == Common::EVENT_SCREEN_CHANGED) {
_gfx->computeScreenViewport();
needsDraw = true;
@@ -700,6 +703,8 @@ void ColonyEngine::playAnimation() {
}
}
}
+ if (!_animationRunning || shouldQuit())
+ break;
// updateAnimation has its own 50ms throttle; only redraw when we know
// the visible state changed (click feedback) or the cadence is due.
@@ -720,6 +725,8 @@ void ColonyEngine::playAnimation() {
_system->delayMillis(2);
}
+ if (useSquarePixelViewport)
+ _gfx->setSquarePixelViewport(false);
_system->lockMouse(true);
CursorMan.showMouse(false);
CursorMan.popAllCursors();
diff --git a/engines/colony/battle.cpp b/engines/colony/battle.cpp
index b019fe1b1cf..90ecaf7c7db 100644
--- a/engines/colony/battle.cpp
+++ b/engines/colony/battle.cpp
@@ -46,7 +46,6 @@ const int kBattleSize = 150; // BSIZE: collision/spawn radius
const int kMaxQuad = 15; // pyramids per quadrant
const int kTankMax = 24; // turret pincer animation range
const int kFloor = 160; // ground z-offset
-const float kBattleFovY = 75.0f;
// =====================================================================
// Battle color constants (original Mac QuickDraw pattern indices)
@@ -78,9 +77,8 @@ int battleHorizonY(const Common::Rect &screenR, int lookY) {
const float centerY = screenR.top + halfHeight;
const float clampedLookY = CLIP<float>((float)lookY, -63.5f, 63.5f);
const float pitchRad = clampedLookY * 2.0f * (float)M_PI / 256.0f;
- const float focalY = halfHeight / tanf(kBattleFovY * (float)M_PI / 360.0f);
- return (int)roundf(centerY - focalY * tanf(pitchRad));
+ return (int)roundf(centerY - kProjectionFocalLength * tanf(pitchRad));
}
int battlePowerLevel(int32 power) {
@@ -126,12 +124,11 @@ bool battleProjectPoint(const Common::Rect &screenR, uint8 look, int8 lookY, con
if (eyeZ >= -1.0f)
return false;
- const float focal = (screenR.height() * 0.5f) / tanf(kBattleFovY * (float)M_PI / 360.0f);
const float centerX = screenR.left + screenR.width() * 0.5f;
const float centerY = screenR.top + screenR.height() * 0.5f;
- screenX = (int)roundf(centerX + (eyeX * focal / -eyeZ));
- screenY = (int)roundf(centerY - (eyeY * focal / -eyeZ));
+ screenX = (int)roundf(centerX + (eyeX * kProjectionFocalLength / -eyeZ));
+ screenY = (int)roundf(centerY - (eyeY * kProjectionFocalLength / -eyeZ));
return true;
}
diff --git a/engines/colony/gfx.cpp b/engines/colony/gfx.cpp
index 2525477cad5..cc0f721ff41 100644
--- a/engines/colony/gfx.cpp
+++ b/engines/colony/gfx.cpp
@@ -99,7 +99,11 @@ static Graphics::RendererType pickRendererType() {
Renderer *createRenderer(OSystem *system, int width, int height) {
const Graphics::RendererType type = pickRendererType();
- initGraphics3d(width, height);
+ // The DOS widescreen canvas keeps its original 350-line EGA coordinate
+ // system, but its display aspect is still 16:9 after pixel-aspect
+ // correction. Request a 16:9 window instead of the raw 853:350 canvas.
+ const int displayHeight = ConfMan.getBool("widescreen_mod") ? (width * 9 + 8) / 16 : height;
+ initGraphics3d(width, displayHeight);
#if defined(USE_OPENGL_SHADERS)
if (type == Graphics::kRendererTypeOpenGLShaders) {
diff --git a/engines/colony/intro.cpp b/engines/colony/intro.cpp
index dc00baa3688..ba15bac6f9e 100644
--- a/engines/colony/intro.cpp
+++ b/engines/colony/intro.cpp
@@ -445,8 +445,10 @@ void ColonyEngine::playIntro() {
_sound->play(Sound::kStars1);
_gfx->clear(_gfx->black());
if (loadAnimation("logo2")) {
+ _gfx->setSquarePixelViewport(true);
drawAnimation();
_gfx->copyToScreen();
+ _gfx->setSquarePixelViewport(false);
}
qt = makeStars(_screenR, 0);
_gfx->clear(_gfx->black());
@@ -457,8 +459,10 @@ void ColonyEngine::playIntro() {
_sound->stop();
_sound->play(Sound::kStars2);
if (loadAnimation("logo1")) {
+ _gfx->setSquarePixelViewport(true);
drawAnimation();
_gfx->copyToScreen();
+ _gfx->setSquarePixelViewport(false);
}
qt = makeStars(_screenR, 0);
_gfx->clear(_gfx->black());
diff --git a/engines/colony/render.cpp b/engines/colony/render.cpp
index 3628d03fa90..a35f1ae59e0 100644
--- a/engines/colony/render.cpp
+++ b/engines/colony/render.cpp
@@ -324,12 +324,11 @@ void projectCorridorPointClamped(const Common::Rect &screenR, int look, int look
const float eyeZ = dz * sinPitch - forward * cosPitch;
const float depth = MAX(-eyeZ, 1.0f);
- const float focal = (screenR.height() * 0.5f) / tanf(75.0f * (float)M_PI / 360.0f);
const float centerX = screenR.left + screenR.width() * 0.5f;
const float centerY = screenR.top + screenR.height() * 0.5f;
- screenX = (int)roundf(centerX + (eyeX * focal / depth));
- screenY = (int)roundf(centerY - (eyeY * focal / depth));
+ screenX = (int)roundf(centerX + (eyeX * kProjectionFocalLength / depth));
+ screenY = (int)roundf(centerY - (eyeY * kProjectionFocalLength / depth));
}
bool isSurfaceVisible(const int *surface, int pointCount, const int *screenX, const int *screenY) {
@@ -481,12 +480,11 @@ bool projectCorridorPoint(const Common::Rect &screenR, uint8 look, int8 lookY,
if (eyeZ >= -1.0f)
return false;
- const float focal = (screenR.height() * 0.5f) / tanf(75.0f * (float)M_PI / 360.0f);
const float centerX = screenR.left + screenR.width() * 0.5f;
const float centerY = screenR.top + screenR.height() * 0.5f;
- screenX = (int)roundf(centerX + (eyeX * focal / -eyeZ));
- screenY = (int)roundf(centerY - (eyeY * focal / -eyeZ));
+ screenX = (int)roundf(centerX + (eyeX * kProjectionFocalLength / -eyeZ));
+ screenY = (int)roundf(centerY - (eyeY * kProjectionFocalLength / -eyeZ));
return true;
}
diff --git a/engines/colony/render_objects.cpp b/engines/colony/render_objects.cpp
index caa7a692fbd..8ddf4e03dcf 100644
--- a/engines/colony/render_objects.cpp
+++ b/engines/colony/render_objects.cpp
@@ -114,12 +114,11 @@ bool projectCorridorPointRaw(const Common::Rect &screenR, uint8 look, int8 lookY
if (eyeZ >= -1.0f)
return false;
- const float focal = (screenR.height() * 0.5f) / tanf(75.0f * (float)M_PI / 360.0f);
const float centerX = screenR.left + screenR.width() * 0.5f;
const float centerY = screenR.top + screenR.height() * 0.5f;
- screenX = (int)roundf(centerX + (eyeX * focal / -eyeZ));
- screenY = (int)roundf(centerY - (eyeY * focal / -eyeZ));
+ screenX = (int)roundf(centerX + (eyeX * kProjectionFocalLength / -eyeZ));
+ screenY = (int)roundf(centerY - (eyeY * kProjectionFocalLength / -eyeZ));
return true;
}
diff --git a/engines/colony/renderer.h b/engines/colony/renderer.h
index eec455a4ba6..47ed2aae323 100644
--- a/engines/colony/renderer.h
+++ b/engines/colony/renderer.h
@@ -35,6 +35,9 @@
namespace Colony {
+// CALCROBO.C projects both axes with (coordinate << 8) / depth.
+const float kProjectionFocalLength = 256.0f;
+
class Renderer {
public:
virtual ~Renderer() {}
@@ -73,10 +76,10 @@ public:
// features.c clipped each wall feature to its own wall (ClipRect(&rClip)).
virtual void setFeatureClipX(int left, int right) {}
virtual void clearFeatureClipX() {}
+ virtual void setSquarePixelViewport(bool enable) = 0;
virtual void computeScreenViewport() = 0;
- // Window-pixel rect the logical canvas is drawn into: the whole window
- // with the widescreen mod on, pillar/letterboxed otherwise.
+ // Window-pixel rect the logical canvas is currently drawn into.
const Common::Rect &screenViewport() const { return _screenViewport; }
// Overlay a RGBA software surface onto the GL framebuffer (for Mac menu bar).
diff --git a/engines/colony/renderer_opengl.cpp b/engines/colony/renderer_opengl.cpp
index d967daafff9..88312b5807a 100644
--- a/engines/colony/renderer_opengl.cpp
+++ b/engines/colony/renderer_opengl.cpp
@@ -117,6 +117,7 @@ public:
void clearFeatureClipX() override {
applyScissorRect(_active3DViewport);
}
+ void setSquarePixelViewport(bool enable) override;
void computeScreenViewport() override;
void drawSurface(const Graphics::Surface *surf, int x, int y) override;
Graphics::Surface *getScreenshot() override;
@@ -137,6 +138,7 @@ private:
Common::Rect _active3DViewport;
int _width = 0;
int _height = 0;
+ bool _squarePixelViewport = false;
byte _palette[256 * 3] = {};
bool _wireframe = true;
int64_t _wireframeFillColor = 0; // -1 = no fill (outline only)
@@ -308,15 +310,12 @@ void OpenGLRenderer::begin3D(int camX, int camY, int camZ, int angle, int angleY
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
- // Use a proper FOV-based perspective projection (like Freescape).
- // A fixed vertical FOV ensures the forward direction stays centered
- // regardless of viewport dimensions (e.g. when dashboard narrows it).
- float aspectRatio = (float)viewport.width() / (float)viewport.height();
- float fov = 75.0f; // vertical FOV in degrees
- float nearClip = 1.0f;
- float farClip = 10000.0f;
- float ymax = nearClip * tanf(fov * M_PI / 360.0f);
- float xmax = ymax * aspectRatio;
+ // The original projection is center + (coordinate << 8) / depth, so
+ // derive the frustum from its fixed 256-logical-pixel focal length.
+ const float nearClip = 1.0f;
+ const float farClip = 10000.0f;
+ const float xmax = nearClip * viewport.width() * 0.5f / kProjectionFocalLength;
+ const float ymax = nearClip * viewport.height() * 0.5f / kProjectionFocalLength;
glFrustum(-xmax, xmax, -ymax, ymax, nearClip, farClip);
glMatrixMode(GL_MODELVIEW);
@@ -575,14 +574,38 @@ void OpenGLRenderer::end3D() {
glOrtho(0, _width, _height, 0, -1, 1);
}
+void OpenGLRenderer::setSquarePixelViewport(bool enable) {
+ if (_squarePixelViewport == enable)
+ return;
+
+ _squarePixelViewport = enable;
+ computeScreenViewport();
+}
+
void OpenGLRenderer::computeScreenViewport() {
int32 screenWidth = _system->getWidth();
int32 screenHeight = _system->getHeight();
bool widescreen = ConfMan.getBool("widescreen_mod");
- if (widescreen) {
- _screenViewport = Common::Rect(screenWidth, screenHeight);
+ if (_squarePixelViewport) {
+ // Animation bitmaps use square pixels. Fit the uncorrected logical
+ // canvas so their authored 416x264 geometry matches the Mac version.
+ const int32 viewportWidth = MIN<int32>(screenWidth,
+ (screenHeight * _width + _height / 2) / _height);
+ const int32 viewportHeight = MIN<int32>(screenHeight,
+ (screenWidth * _height + _width / 2) / _width);
+ _screenViewport = Common::Rect(viewportWidth, viewportHeight);
+ _screenViewport.translate((screenWidth - viewportWidth) / 2,
+ (screenHeight - viewportHeight) / 2);
+ } else if (widescreen) {
+ // Widescreen is a 16:9 presentation even when fullscreen uses a
+ // taller or wider display. Keep it centered instead of stretching it.
+ const int32 viewportWidth = MIN<int32>(screenWidth, (screenHeight * 16 + 4) / 9);
+ const int32 viewportHeight = MIN<int32>(screenHeight, (screenWidth * 9 + 8) / 16);
+ _screenViewport = Common::Rect(viewportWidth, viewportHeight);
+ _screenViewport.translate((screenWidth - viewportWidth) / 2,
+ (screenHeight - viewportHeight) / 2);
} else if (_system->getFeatureState(OSystem::kFeatureAspectRatioCorrection)) {
// Aspect ratio correction (4:3)
int32 viewportWidth = MIN<int32>(screenWidth, screenHeight * 4 / 3);
diff --git a/engines/colony/renderer_opengl_shaders.cpp b/engines/colony/renderer_opengl_shaders.cpp
index e97a898c68e..bdd1034bebf 100644
--- a/engines/colony/renderer_opengl_shaders.cpp
+++ b/engines/colony/renderer_opengl_shaders.cpp
@@ -83,6 +83,7 @@ public:
void setFeatureClipX(int left, int right) override;
void clearFeatureClipX() override;
void applyScissorRect(const Common::Rect &logical);
+ void setSquarePixelViewport(bool enable) override;
void computeScreenViewport() override;
void drawSurface(const Graphics::Surface *surf, int x, int y) override;
@@ -122,6 +123,7 @@ private:
Common::Rect _active3DViewport;
int _width = 0;
int _height = 0;
+ bool _squarePixelViewport = false;
byte _palette[256 * 3] = {};
OpenGL::Shader *_solidShader = nullptr;
@@ -630,13 +632,35 @@ void OpenGLShaderRenderer::setPalette(const byte *palette, uint start, uint coun
memcpy(_palette + start * 3, palette, count * 3);
}
+void OpenGLShaderRenderer::setSquarePixelViewport(bool enable) {
+ if (_squarePixelViewport == enable)
+ return;
+
+ _squarePixelViewport = enable;
+ computeScreenViewport();
+}
+
void OpenGLShaderRenderer::computeScreenViewport() {
const int32 screenWidth = _system->getWidth();
const int32 screenHeight = _system->getHeight();
const bool widescreen = ConfMan.getBool("widescreen_mod");
- if (widescreen) {
- _screenViewport = Common::Rect(screenWidth, screenHeight);
+ if (_squarePixelViewport) {
+ // Animation bitmaps use square pixels. Fit the uncorrected logical
+ // canvas so their authored 416x264 geometry matches the Mac version.
+ const int32 vpW = MIN<int32>(screenWidth,
+ (screenHeight * _width + _height / 2) / _height);
+ const int32 vpH = MIN<int32>(screenHeight,
+ (screenWidth * _height + _width / 2) / _width);
+ _screenViewport = Common::Rect(vpW, vpH);
+ _screenViewport.translate((screenWidth - vpW) / 2, (screenHeight - vpH) / 2);
+ } else if (widescreen) {
+ // Widescreen is a 16:9 presentation even when fullscreen uses a
+ // taller or wider display. Keep it centered instead of stretching it.
+ const int32 vpW = MIN<int32>(screenWidth, (screenHeight * 16 + 4) / 9);
+ const int32 vpH = MIN<int32>(screenHeight, (screenWidth * 9 + 8) / 16);
+ _screenViewport = Common::Rect(vpW, vpH);
+ _screenViewport.translate((screenWidth - vpW) / 2, (screenHeight - vpH) / 2);
} else if (_system->getFeatureState(OSystem::kFeatureAspectRatioCorrection)) {
const int32 vpW = MIN<int32>(screenWidth, screenHeight * 4 / 3);
const int32 vpH = MIN<int32>(screenHeight, screenWidth * 3 / 4);
@@ -773,14 +797,12 @@ void OpenGLShaderRenderer::begin3D(int camX, int camY, int camZ, int angle, int
glDepthFunc(GL_LEQUAL);
glDepthMask(GL_TRUE);
- // Perspective: 75° vertical FOV, near=1, far=10000 â matches the
- // fixed-function path so geometry lands at the same screen positions.
- const float aspectRatio = (float)viewport.width() / (float)viewport.height();
- const float fov = 75.0f;
+ // Match CALCROBO.C's center + (coordinate << 8) / depth projection and
+ // the fixed-function path by using a 256-logical-pixel focal length.
const float nearClip = 1.0f;
const float farClip = 10000.0f;
- const float ymax = nearClip * tanf(fov * (float)M_PI / 360.0f);
- const float xmax = ymax * aspectRatio;
+ const float xmax = nearClip * viewport.width() * 0.5f / kProjectionFocalLength;
+ const float ymax = nearClip * viewport.height() * 0.5f / kProjectionFocalLength;
// Build perspective frustum directly. Math::makeFrustumMatrix exists in
// math/glmath.h, but its sign convention requires a final transpose to
Commit: f5786b13ba79a6b3f4be58e88965885c0718bed6
https://github.com/scummvm/scummvm/commit/f5786b13ba79a6b3f4be58e88965885c0718bed6
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-09-01T12:07:23+02:00
Commit Message:
COLONY: better rendering of stair going down
Changed paths:
engines/colony/render_features.cpp
diff --git a/engines/colony/render_features.cpp b/engines/colony/render_features.cpp
index 50f90d4f5b3..b8d1a07382f 100644
--- a/engines/colony/render_features.cpp
+++ b/engines/colony/render_features.cpp
@@ -889,45 +889,106 @@ void ColonyEngine::drawWallFeature3D(int cellX, int cellY, int direction) {
break;
}
case kWallFeatureDnStairs: {
- // wallftrs.c draw_dn_stairs(): the same well, dropping away.
+ // A full storey drop over one cell projects through the corridor floor
+ // when viewed from above. Use a shallower render-only drop so the same
+ // tread/riser construction as the up stairs remains visible in the well.
const uint32 col = macColors ? (uint32)0xFF000000 : 0; // vBLACK
float farC[4][3];
getWallRecess3D(corners, farC);
clipToWallFace(corners);
float dep[7];
- for (int i = 0; i < 7; i++)
+ float hgt[7];
+ for (int i = 0; i < 7; i++) {
dep[i] = (float)(i + 1) / 8.0f;
+ hgt[i] = -(float)(i + 1) / 32.0f;
+ }
+
+ // Fill the shaft sides without framing each panel, so their shared edges
+ // form one continuous wall rather than a row of transparent-looking bars.
+ if (isMacRenderMode() || !_wireframe) {
+ _gfx->setStippleData(nullptr);
+ _gfx->setWireframe(false);
+ for (int i = 1; i <= 7; i++) {
+ const float nearD = dep[i - 1];
+ const float farD = (i < 7) ? dep[i] : 1.0f;
+ const float bottomV = hgt[i - 1];
+ const float sideV[4] = {0.0f, bottomV, bottomV, 0.0f};
+ const float sideD[4] = {nearD, nearD, farD, farD};
+ const float leftU[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ const float rightU[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ recessQuad(corners, farC, leftU, sideV, sideD, 4, wallFeatureFill);
+ recessQuad(corners, farC, rightU, sideV, sideD, 4, wallFeatureFill);
+ }
+ }
if (isMacRenderMode()) {
const float uw[4] = {0.0f, 1.0f, 1.0f, 0.0f};
- const float vw[4] = {0.0f, 0.0f, 1.0f, 1.0f};
+ const float vw[4] = {hgt[6], hgt[6], 1.0f, 1.0f};
const float dw[4] = {1.0f, 1.0f, 1.0f, 1.0f};
macFillRecess(corners, farC, uw, vw, dw, 4, 21, macColors); // c_dnstairs
- // Well floor
- const float uq[4] = {0.0f, 0.0f, 1.0f, 1.0f};
- const float vFloor[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- const float dFloor[4] = {0.0f, 1.0f, 1.0f, 0.0f};
- macFillRecess(corners, farC, uq, vFloor, dFloor, 4, 21, macColors);
+ // Match the up-stair materials: dark risers and lighter treads.
+ for (int i = 6; i >= 0; i--) {
+ const float nearV = (i > 0) ? hgt[i - 1] : 0.0f;
+ const float nearD = (i > 0) ? dep[i - 1] : 0.0f;
+ const float uq[4] = {0.0f, 0.0f, 1.0f, 1.0f};
+ const float vRiser[4] = {nearV, hgt[i], hgt[i], nearV};
+ const float dRiser[4] = {dep[i], dep[i], dep[i], dep[i]};
+ macFillRecess(corners, farC, uq, vRiser, dRiser, 4, 20, macColors);
+
+ const float vTread[4] = {nearV, nearV, nearV, nearV};
+ const float dTread[4] = {nearD, dep[i], dep[i], nearD};
+ macFillRecess(corners, farC, uq, vTread, dTread, 4, 19, macColors);
+ }
+
+ const float ub[4] = {0.0f, 0.0f, 1.0f, 1.0f};
+ const float vb[4] = {hgt[6], hgt[6], hgt[6], hgt[6]};
+ const float db[4] = {dep[6], 1.0f, 1.0f, dep[6]};
+ macFillRecess(corners, farC, ub, vb, db, 4, 19, macColors);
+ } else if (!_wireframe) {
+ const float uw[4] = {0.0f, 1.0f, 1.0f, 0.0f};
+ const float vw[4] = {hgt[6], hgt[6], 1.0f, 1.0f};
+ const float dw[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ dosFillRecess(corners, farC, uw, vw, dw, 4, kColorGray);
+
+ for (int i = 6; i >= 0; i--) {
+ const float nearV = (i > 0) ? hgt[i - 1] : 0.0f;
+ const float nearD = (i > 0) ? dep[i - 1] : 0.0f;
+ const float uq[4] = {0.0f, 0.0f, 1.0f, 1.0f};
+ const float vRiser[4] = {nearV, hgt[i], hgt[i], nearV};
+ const float dRiser[4] = {dep[i], dep[i], dep[i], dep[i]};
+ dosFillRecess(corners, farC, uq, vRiser, dRiser, 4, kColorGray);
+
+ const float vTread[4] = {nearV, nearV, nearV, nearV};
+ const float dTread[4] = {nearD, dep[i], dep[i], nearD};
+ dosFillRecess(corners, farC, uq, vTread, dTread, 4, kColorLtGray);
+ }
+
+ const float ub[4] = {0.0f, 0.0f, 1.0f, 1.0f};
+ const float vb[4] = {hgt[6], hgt[6], hgt[6], hgt[6]};
+ const float db[4] = {dep[6], 1.0f, 1.0f, dep[6]};
+ dosFillRecess(corners, farC, ub, vb, db, 4, kColorLtGray);
}
- // Ceiling, then the slant to the far mouth
- recessLine(corners, farC, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, dep[3], col);
- recessLine(corners, farC, 0.0f, 1.0f, dep[3], 1.0f, 1.0f, dep[3], col);
- recessLine(corners, farC, 1.0f, 1.0f, dep[3], 1.0f, 1.0f, 0.0f, col);
- recessLine(corners, farC, 0.0f, 1.0f, dep[3], 0.0f, 0.5f, 1.0f, col);
- recessLine(corners, farC, 0.0f, 0.5f, 1.0f, 1.0f, 0.5f, 1.0f, col);
- recessLine(corners, farC, 1.0f, 0.5f, 1.0f, 1.0f, 1.0f, dep[3], col);
-
- // Side walls down to the well floor
- recessLine(corners, farC, 0.0f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, col);
- recessLine(corners, farC, 1.0f, 0.5f, 1.0f, 1.0f, 0.0f, 1.0f, col);
- recessLine(corners, farC, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, col);
- recessLine(corners, farC, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, col);
-
- // First step
- recessLine(corners, farC, 0.0f, 0.0f, dep[0], 1.0f, 0.0f, dep[0], col);
+ // Lower landing and closed far mouth.
+ recessLine(corners, farC, 0.0f, hgt[6], dep[6], 0.0f, hgt[6], 1.0f, col);
+ recessLine(corners, farC, 0.0f, hgt[6], 1.0f, 1.0f, hgt[6], 1.0f, col);
+ recessLine(corners, farC, 1.0f, hgt[6], 1.0f, 1.0f, hgt[6], dep[6], col);
+ recessLine(corners, farC, 0.0f, hgt[6], 1.0f, 0.0f, 1.0f, 1.0f, col);
+ recessLine(corners, farC, 1.0f, hgt[6], 1.0f, 1.0f, 1.0f, 1.0f, col);
+
+ // Treads and risers.
+ for (int i = 6; i >= 0; i--) {
+ const float nearV = (i > 0) ? hgt[i - 1] : 0.0f;
+ const float nearD = (i > 0) ? dep[i - 1] : 0.0f;
+ recessLine(corners, farC, 0.0f, nearV, nearD, 0.0f, nearV, dep[i], col);
+ recessLine(corners, farC, 1.0f, nearV, nearD, 1.0f, nearV, dep[i], col);
+ recessLine(corners, farC, 0.0f, nearV, dep[i], 1.0f, nearV, dep[i], col);
+ recessLine(corners, farC, 0.0f, nearV, dep[i], 0.0f, hgt[i], dep[i], col);
+ recessLine(corners, farC, 1.0f, nearV, dep[i], 1.0f, hgt[i], dep[i], col);
+ recessLine(corners, farC, 0.0f, hgt[i], dep[i], 1.0f, hgt[i], dep[i], col);
+ }
// Handrails
recessLine(corners, farC, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, dep[3], col);
Commit: 3a7b808800bb90fc3ec748f01894a5eb2ccf88e6
https://github.com/scummvm/scummvm/commit/3a7b808800bb90fc3ec748f01894a5eb2ccf88e6
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-09-01T12:07:23+02:00
Commit Message:
COLONY: improved instructions in the reactor console
Changed paths:
engines/colony/animation.cpp
diff --git a/engines/colony/animation.cpp b/engines/colony/animation.cpp
index 3bc87683dd6..217fb1ae837 100644
--- a/engines/colony/animation.cpp
+++ b/engines/colony/animation.cpp
@@ -1043,7 +1043,7 @@ void ColonyEngine::drawColonyCoder(int animOx, int animOy) {
const int contentW = 172;
const char *instrText = (_animationName == "security")
? "Press the symbols as shown on the display to determine the correct value."
- : "Press the symbols from the desk in reverse order to determine the correct value.";
+ : "Enter the appropriate symbol sequence to determine this reactor's code.";
Common::Array<Common::U32String> instrLines;
instrFont->wordWrapText(Common::U32String(instrText), contentW - 16, instrLines);
const int instrLineH = instrFont->getFontHeight() + 1;
More information about the Scummvm-git-logs
mailing list