[Scummvm-git-logs] scummvm master -> d16c0c72818d46526406921c25f47432939eb4d7

neuromancer noreply at scummvm.org
Tue Aug 18 11:35:38 UTC 2026


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .

Summary:
d16c0c7281 COLONY: added missing perspective for stair rendering


Commit: d16c0c72818d46526406921c25f47432939eb4d7
    https://github.com/scummvm/scummvm/commit/d16c0c72818d46526406921c25f47432939eb4d7
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-08-18T13:35:24+02:00

Commit Message:
COLONY: added missing perspective for stair 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
    engines/colony/renderer.h
    engines/colony/renderer_opengl.cpp
    engines/colony/renderer_opengl_shaders.cpp


diff --git a/engines/colony/colony.h b/engines/colony/colony.h
index b2868f854e4..ab065095e88 100644
--- a/engines/colony/colony.h
+++ b/engines/colony/colony.h
@@ -713,6 +713,17 @@ private:
 	void drawWallFeature3D(int cellX, int cellY, int direction);
 	void drawCellFeature3D(int cellX, int cellY);
 	void getWallFace3D(int cellX, int cellY, int direction, float corners[4][3]);
+	bool isRecessFeature(int x, int y, int direction) const;
+	bool wallSegmentIsOpenWell(int x, int y, uint8 bit) const;
+	void getWallRecess3D(const float corners[4][3], float farC[4][3]) const;
+	void recessPoint(const float nearC[4][3], const float farC[4][3], float u, float v, float depth, float out[3]) const;
+	void recessLine(const float nearC[4][3], const float farC[4][3], float u1, float v1, float d1,
+		float u2, float v2, float d2, uint32 color);
+	void recessQuad(const float nearC[4][3], const float farC[4][3], const float *u, const float *v,
+		const float *d, int count, uint32 color);
+	void clipToWallFace(const float corners[4][3]);
+	void macFillRecess(const float nearC[4][3], const float farC[4][3], const float *u, const float *v,
+		const float *d, int count, int macIdx, bool macColors);
 	void getCellFace3D(int cellX, int cellY, bool ceiling, float corners[4][3]);
 
 	int occupiedObjectAt(int xnew, int ynew, int x, int y, const Locate *pobject);
diff --git a/engines/colony/render.cpp b/engines/colony/render.cpp
index df6437b0049..aa9b9fb8e25 100644
--- a/engines/colony/render.cpp
+++ b/engines/colony/render.cpp
@@ -404,6 +404,21 @@ uint8 ColonyEngine::wallAt(int x, int y) const {
 	return _wall[x][y];
 }
 
+bool ColonyEngine::isRecessFeature(int x, int y, int direction) const {
+	const uint8 *map = mapFeatureAt(x, y, direction);
+	if (!map)
+		return false;
+	return map[0] == kWallFeatureUpStairs || map[0] == kWallFeatureDnStairs;
+}
+
+// Bit 0x01 spans (x,y-1)/(x,y); bit 0x02 spans (x-1,y)/(x,y). Either side may
+// record the well.
+bool ColonyEngine::wallSegmentIsOpenWell(int x, int y, uint8 bit) const {
+	if (bit == 0x01)
+		return isRecessFeature(x, y, kDirSouth) || isRecessFeature(x, y - 1, kDirNorth);
+	return isRecessFeature(x, y, kDirWest) || isRecessFeature(x - 1, y, kDirEast);
+}
+
 const uint8 *ColonyEngine::mapFeatureAt(int x, int y, int direction) const {
 	if (x < 0 || x >= 31 || y < 0 || y >= 31 || direction < 0 || direction >= 5)
 		return nullptr;
@@ -986,10 +1001,11 @@ void ColonyEngine::renderCorridor3D() {
 	for (int y = 0; y < 32; y++) {
 		for (int x = 0; x < 32; x++) {
 			uint8 w = _wall[x][y];
-			if (w & 0x01) {
+			// A stair well is a hole: the feature draws the opening itself.
+			if ((w & 0x01) && !wallSegmentIsOpenWell(x, y, 0x01)) {
 				_gfx->draw3DWall(x, y, x + 1, y, wallColor);
 			}
-			if (w & 0x02) {
+			if ((w & 0x02) && !wallSegmentIsOpenWell(x, y, 0x02)) {
 				_gfx->draw3DWall(x, y, x, y + 1, wallColor);
 			}
 		}
diff --git a/engines/colony/render_features.cpp b/engines/colony/render_features.cpp
index ec211480f47..7d5ca1af7e2 100644
--- a/engines/colony/render_features.cpp
+++ b/engines/colony/render_features.cpp
@@ -87,6 +87,122 @@ void wallPoint(const float corners[4][3], float u, float v, float out[3]) {
 	out[2] = botZ + (topZ - botZ) * v;
 }
 
+// Far mouth of a one-cell recess. Taking the direction from the quad's own normal
+// keeps it in step with whichever face getWallFace3D() built.
+void ColonyEngine::getWallRecess3D(const float corners[4][3], float farC[4][3]) const {
+	const float ux = corners[1][0] - corners[0][0];
+	const float uy = corners[1][1] - corners[0][1];
+	const float uz = corners[1][2] - corners[0][2];
+	const float vx = corners[3][0] - corners[0][0];
+	const float vy = corners[3][1] - corners[0][1];
+	const float vz = corners[3][2] - corners[0][2];
+
+	float nx = uy * vz - uz * vy;
+	float ny = uz * vx - ux * vz;
+	float nz = ux * vy - uy * vx;
+	const float len = sqrtf(nx * nx + ny * ny + nz * nz);
+	if (len < 0.001f) {
+		memcpy(farC, corners, sizeof(float) * 12);
+		return;
+	}
+	nx /= len;
+	ny /= len;
+	nz /= len;
+
+	const float awayX = corners[0][0] - (float)_me.xloc;
+	const float awayY = corners[0][1] - (float)_me.yloc;
+	const float awayZ = corners[0][2];
+	if (nx * awayX + ny * awayY + nz * awayZ < 0.0f) {
+		nx = -nx;
+		ny = -ny;
+		nz = -nz;
+	}
+
+	for (int i = 0; i < 4; i++) {
+		farC[i][0] = corners[i][0] + nx * 256.0f;
+		farC[i][1] = corners[i][1] + ny * 256.0f;
+		farC[i][2] = corners[i][2] + nz * 256.0f;
+	}
+}
+
+// Depth 0 at the wall face, 1 a cell in. renderCorridor3D() drops the wall
+// segment, so this needs no depth trickery.
+void ColonyEngine::recessPoint(const float nearC[4][3], const float farC[4][3],
+		float u, float v, float depth, float out[3]) const {
+	float pn[3];
+	float pf[3];
+	wallPoint(nearC, u, v, pn);
+	wallPoint(farC, u, v, pf);
+	for (int i = 0; i < 3; i++)
+		out[i] = pn[i] + (pf[i] - pn[i]) * depth;
+}
+
+void ColonyEngine::recessLine(const float nearC[4][3], const float farC[4][3],
+		float u1, float v1, float d1, float u2, float v2, float d2, uint32 color) {
+	float p1[3];
+	float p2[3];
+	recessPoint(nearC, farC, u1, v1, d1, p1);
+	recessPoint(nearC, farC, u2, v2, d2, p2);
+	_gfx->draw3DLine(p1[0], p1[1], p1[2], p2[0], p2[1], p2[2], color);
+}
+
+void ColonyEngine::recessQuad(const float nearC[4][3], const float farC[4][3],
+		const float *u, const float *v, const float *d, int count, uint32 color) {
+	float px[8];
+	float py[8];
+	float pz[8];
+	if (count > 8)
+		count = 8;
+	for (int i = 0; i < count; i++) {
+		float p[3];
+		recessPoint(nearC, farC, u[i], v[i], d[i], p);
+		px[i] = p[0];
+		py[i] = p[1];
+		pz[i] = p[2];
+	}
+	_gfx->draw3DPolygon(px, py, pz, count, color);
+}
+
+// A well legitimately projects outside its opening, so it needs the original's
+// per-wall clip or it paints over the neighbours.
+void ColonyEngine::clipToWallFace(const float corners[4][3]) {
+	int minX = 0;
+	int maxX = 0;
+	for (int i = 0; i < 4; i++) {
+		int sx = 0;
+		int sy = 0;
+		projectCorridorPointClamped(_screenR, _me.look, _me.lookY, _sint, _cost, _me.xloc, _me.yloc,
+			corners[i][0], corners[i][1], corners[i][2], sx, sy);
+		if (i == 0) {
+			minX = sx;
+			maxX = sx;
+			continue;
+		}
+		if (sx < minX)
+			minX = sx;
+		if (sx > maxX)
+			maxX = sx;
+	}
+	_gfx->setFeatureClipX(minX, maxX + 1);
+}
+
+void ColonyEngine::macFillRecess(const float nearC[4][3], const float farC[4][3],
+		const float *u, const float *v, const float *d, int count, int macIdx, bool macColors) {
+	if (macColors) {
+		uint32 fg = packMacColor(_macColors[macIdx].fg);
+		uint32 bg = packMacColor(_macColors[macIdx].bg);
+		const byte *stipple = setupMacPattern(_gfx, _macColors[macIdx].pattern, fg, bg);
+		recessQuad(nearC, farC, u, v, d, count, fg);
+		if (stipple)
+			_gfx->setStippleData(nullptr);
+		return;
+	}
+
+	_gfx->setStippleData(kStippleGray);
+	recessQuad(nearC, farC, u, v, d, count, 0);
+	_gfx->setStippleData(nullptr);
+}
+
 // Draw a line on a wall face using normalized (u,v) coordinates
 void ColonyEngine::wallLine(const float corners[4][3], float u1, float v1, float u2, float v2, uint32 color) {
 	float p1[3], p2[3];
@@ -649,130 +765,116 @@ void ColonyEngine::drawWallFeature3D(int cellX, int cellY, int direction) {
 		break;
 	}
 	case kWallFeatureUpStairs: {
-		// DOS: draw_up_stairs  staircase ascending into the wall with perspective
+		// wallftrs.c draw_up_stairs(): a well one cell deep, so it recedes for real.
 		const uint32 col = macColors ? (uint32)0xFF000000 : 0; // vBLACK
+		float farC[4][3];
+		getWallRecess3D(corners, farC);
+		clipToWallFace(corners);
 
-		// Mac: fill entire wall face (c_upstairs)
+		float dep[7];
+		float hgt[7];
+		for (int i = 0; i < 7; i++) {
+			dep[i] = (float)(i + 1) / 8.0f;
+			hgt[i] = (float)(i + 1) / 8.0f;
+		}
+
+		// ColorWall(), now the back of the hole.
 		if (isMacRenderMode()) {
-			float uf[4] = {0.0f, 1.0f, 1.0f, 0.0f};
-			float vf2[4] = {0.0f, 0.0f, 1.0f, 1.0f};
-			if (macColors) {
-				macFillPoly(uf, vf2, 4, 19); // c_upstairs1
-			} else {
-				_gfx->setStippleData(kStippleGray);
-				wallPolygon(corners, uf, vf2, 4, 0);
-				_gfx->setStippleData(nullptr);
+			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};
+			macFillRecess(corners, farC, uw, vw, dw, 4, 19, macColors); // c_upstairs1
+
+			// Treads c_upstairs1, risers c_upstairs2, back to front.
+			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]};
+				macFillRecess(corners, farC, uq, vRiser, dRiser, 4, 20, macColors);
+
+				const float vTread[4] = {lowV, lowV, lowV, lowV};
+				const float dTread[4] = {backD, dep[i], dep[i], backD};
+				macFillRecess(corners, farC, uq, vTread, dTread, 4, 19, macColors);
 			}
-		}
 
-		// Perspective convergence: back of passage at ~1/3 width (1 cell deep)
-		float ul[7], ur[7], vf[7], vc[7];
-		for (int i = 0; i < 7; i++) {
-			float f = (i + 1) / 8.0f;
-			float inset = f * (1.0f / 3.0f);
-			ul[i] = inset;
-			ur[i] = 1.0f - inset;
-			vf[i] = inset;        // floor rises toward center
-			vc[i] = 1.0f - inset; // ceiling drops toward center
-		}
-		// Back of passage (full depth)
-		float bi = 1.0f / 3.0f; // back inset
-		float bu = bi, bur = 1.0f - bi, bvc = 1.0f - bi;
-
-		// 1. Side wall verticals at back of passage
-		wallLine(corners, bu, bvc, bu, 0.5f, col);
-		wallLine(corners, bur, 0.5f, bur, bvc, col);
-
-		// 2. Back wall landing (depth 6 to full depth)
-		wallLine(corners, ul[6], stairStepHeight(vf, vc, 6, 6), bu, bvc, col);
-		wallLine(corners, bu, bvc, bur, bvc, col);
-		wallLine(corners, bur, bvc, ur[6], stairStepHeight(vf, vc, 6, 6), col);
-		wallLine(corners, ur[6], stairStepHeight(vf, vc, 6, 6), ul[6], stairStepHeight(vf, vc, 6, 6), col);
-
-		// 3. First step tread (floor from wall face to depth 0)
-		wallLine(corners, 0.0f, 0.0f, ul[0], vf[0], col);
-		wallLine(corners, ul[0], vf[0], ur[0], vf[0], col);
-		wallLine(corners, ur[0], vf[0], 1.0f, 0.0f, col);
-		wallLine(corners, 1.0f, 0.0f, 0.0f, 0.0f, col);
-
-		// 4. First step riser (at depth 0)
-		wallLine(corners, ul[0], stairStepHeight(vf, vc, 0, 0), ul[0], vf[0], col);
-		wallLine(corners, ur[0], vf[0], ur[0], stairStepHeight(vf, vc, 0, 0), col);
-		wallLine(corners, ur[0], stairStepHeight(vf, vc, 0, 0), ul[0], stairStepHeight(vf, vc, 0, 0), col);
-
-		// 5. Step treads (i=3..0: depth i to depth i+1)
-		for (int i = 3; i >= 0; i--) {
-			wallLine(corners, ul[i], stairStepHeight(vf, vc, i, i), ul[i + 1], stairStepHeight(vf, vc, i + 1, i), col);
-			wallLine(corners, ul[i + 1], stairStepHeight(vf, vc, i + 1, i), ur[i + 1], stairStepHeight(vf, vc, i + 1, i), col);
-			wallLine(corners, ur[i + 1], stairStepHeight(vf, vc, i + 1, i), ur[i], stairStepHeight(vf, vc, i, i), col);
-			wallLine(corners, ur[i], stairStepHeight(vf, vc, i, i), ul[i], stairStepHeight(vf, vc, i, i), col);
+			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);
 		}
 
-		// 6. Step risers (i=5..0: vertical face at depth i+1)
-		for (int i = 5; i >= 0; i--) {
-			wallLine(corners, ul[i + 1], stairStepHeight(vf, vc, i + 1, i + 1), ul[i + 1], stairStepHeight(vf, vc, i + 1, i), col);
-			wallLine(corners, ul[i + 1], stairStepHeight(vf, vc, i + 1, i), ur[i + 1], stairStepHeight(vf, vc, i + 1, i), col);
-			wallLine(corners, ur[i + 1], stairStepHeight(vf, vc, i + 1, i), ur[i + 1], stairStepHeight(vf, vc, i + 1, i + 1), col);
-			wallLine(corners, ur[i + 1], stairStepHeight(vf, vc, i + 1, i + 1), ul[i + 1], stairStepHeight(vf, vc, i + 1, i + 1), col);
+		// Back landing and 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 lowV = (i > 0) ? hgt[i - 1] : 0.0f;
+			const float backD = (i > 0) ? dep[i - 1] : 0.0f;
+			recessLine(corners, farC, 0.0f, lowV, backD, 0.0f, lowV, dep[i], col);
+			recessLine(corners, farC, 1.0f, lowV, backD, 1.0f, lowV, dep[i], col);
+			recessLine(corners, farC, 0.0f, lowV, dep[i], 1.0f, lowV, dep[i], col);
+			recessLine(corners, farC, 0.0f, lowV, dep[i], 0.0f, hgt[i], dep[i], col);
+			recessLine(corners, farC, 1.0f, lowV, 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);
 		}
 
-		// 7. Handrails: from center of wall edges up to near-ceiling at mid-depth
-		wallLine(corners, 0.0f, 0.5f, ul[3], vc[0], col);
-		wallLine(corners, 1.0f, 0.5f, ur[3], vc[0], col);
+		// Handrails
+		recessLine(corners, farC, 0.0f, 0.5f, 0.0f, 0.0f, 1.0f, dep[3], col);
+		recessLine(corners, farC, 1.0f, 0.5f, 0.0f, 1.0f, 1.0f, dep[3], col);
+		_gfx->clearFeatureClipX();
 		break;
 	}
 	case kWallFeatureDnStairs: {
-		// DOS: draw_dn_stairs  staircase descending into the wall with perspective
+		// wallftrs.c draw_dn_stairs(): the same well, dropping away.
 		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++)
+			dep[i] = (float)(i + 1) / 8.0f;
 
-		// Mac: fill entire wall face (c_dnstairs)
 		if (isMacRenderMode()) {
-			float uf[4] = {0.0f, 1.0f, 1.0f, 0.0f};
-			float vf2[4] = {0.0f, 0.0f, 1.0f, 1.0f};
-			if (macColors) {
-				macFillPoly(uf, vf2, 4, 21); // c_dnstairs
-			} else {
-				_gfx->setStippleData(kStippleGray);
-				wallPolygon(corners, uf, vf2, 4, 0);
-				_gfx->setStippleData(nullptr);
-			}
+			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};
+			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);
 		}
 
-		float ul[7], ur[7], vf[7], vc[7];
-		for (int i = 0; i < 7; i++) {
-			float f = (i + 1) / 8.0f;
-			float inset = f * (1.0f / 3.0f);
-			ul[i] = inset;
-			ur[i] = 1.0f - inset;
-			vf[i] = inset;
-			vc[i] = 1.0f - inset;
-		}
-		float bi = 1.0f / 3.0f;
-		float bu = bi, bur = 1.0f - bi;
-
-		// 1. Ceiling: front ceiling slopes down to mid-depth
-		wallLine(corners, 0.0f, 1.0f, ul[3], vc[3], col);
-		wallLine(corners, ul[3], vc[3], ur[3], vc[3], col);
-		wallLine(corners, ur[3], vc[3], 1.0f, 1.0f, col);
-
-		// 2. Slant: from mid-depth ceiling down to center at back
-		wallLine(corners, ul[3], vc[3], bu, 0.5f, col);
-		wallLine(corners, bu, 0.5f, bur, 0.5f, col);
-		wallLine(corners, bur, 0.5f, ur[3], vc[3], col);
-
-		// 3. Side wall verticals: from center at back down to floor level
-		wallLine(corners, bu, 0.5f, bu, vf[0], col);
-		wallLine(corners, bur, 0.5f, bur, vf[0], col);
-
-		// 4. First step (floor from wall face to depth 0)
-		wallLine(corners, 0.0f, 0.0f, ul[0], vf[0], col);
-		wallLine(corners, ul[0], vf[0], ur[0], vf[0], col);
-		wallLine(corners, ur[0], vf[0], 1.0f, 0.0f, col);
-		wallLine(corners, 1.0f, 0.0f, 0.0f, 0.0f, col);
-
-		// 5. Handrails: from center of wall edges down to floor at mid-depth
-		wallLine(corners, 0.0f, 0.5f, ul[3], vf[3], col);
-		wallLine(corners, 1.0f, 0.5f, ur[3], vf[3], col);
+		// 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);
+
+		// Handrails
+		recessLine(corners, farC, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, dep[3], col);
+		recessLine(corners, farC, 1.0f, 0.5f, 0.0f, 1.0f, 0.0f, dep[3], col);
+		_gfx->clearFeatureClipX();
 		break;
 	}
 	case kWallFeatureChar:
diff --git a/engines/colony/render_internal.h b/engines/colony/render_internal.h
index 0af6bb1b877..3d61af62c9f 100644
--- a/engines/colony/render_internal.h
+++ b/engines/colony/render_internal.h
@@ -33,6 +33,12 @@
 
 namespace Colony {
 
+// render.cpp; shared with the wall-feature renderer.
+void projectCorridorPointClamped(const Common::Rect &screenR, int look, int lookY,
+	const int *sint, const int *cost, int camX, int camY,
+	float worldX, float worldY, float worldZ,
+	int &screenX, int &screenY);
+
 // 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.
diff --git a/engines/colony/render_objects.cpp b/engines/colony/render_objects.cpp
index 59b1434a743..e0dbf38e32e 100644
--- a/engines/colony/render_objects.cpp
+++ b/engines/colony/render_objects.cpp
@@ -1141,7 +1141,6 @@ const int kSnoopHeadSurf[3][8] = {
 };
 
 const Colony::ColonyEngine::PrismPartDef kSnoopAbdomenDef = {4, kSnoopAbdomenPts, 2, kSnoopAbdomenSurf};
-const Colony::ColonyEngine::PrismPartDef kSnoopHeadDef = {4, kSnoopHeadPts, 3, kSnoopHeadSurf};
 
 int wrapAngle256(int angle) {
 	angle %= 256;
diff --git a/engines/colony/renderer.h b/engines/colony/renderer.h
index 179c890a62b..eec455a4ba6 100644
--- a/engines/colony/renderer.h
+++ b/engines/colony/renderer.h
@@ -70,6 +70,9 @@ public:
 	virtual void setMacColors(uint32 fg, uint32 bg) {}
 	virtual void setDepthState(bool testEnabled, bool writeEnabled) {}
 	virtual void setDepthRange(float nearVal, float farVal) {}
+	// features.c clipped each wall feature to its own wall (ClipRect(&rClip)).
+	virtual void setFeatureClipX(int left, int right) {}
+	virtual void clearFeatureClipX() {}
 	virtual void computeScreenViewport() = 0;
 
 	// Window-pixel rect the logical canvas is drawn into: the whole window
diff --git a/engines/colony/renderer_opengl.cpp b/engines/colony/renderer_opengl.cpp
index c4818ac0db7..d967daafff9 100644
--- a/engines/colony/renderer_opengl.cpp
+++ b/engines/colony/renderer_opengl.cpp
@@ -93,6 +93,30 @@ public:
 	void setDepthRange(float nearVal, float farVal) override {
 		glDepthRange(nearVal, farVal);
 	}
+
+	void applyScissorRect(const Common::Rect &logical) {
+		const float scaleX = (float)_screenViewport.width() / (float)_width;
+		const float scaleY = (float)_screenViewport.height() / (float)_height;
+		const int sysH = _system->getHeight();
+		const int vpX = _screenViewport.left + (int)(logical.left * scaleX);
+		const int vpY = sysH - (_screenViewport.top + (int)(logical.bottom * scaleY));
+		const int vpW = (int)(logical.width() * scaleX);
+		const int vpH = (int)(logical.height() * scaleY);
+		glScissor(vpX, vpY, vpW > 0 ? vpW : 0, vpH > 0 ? vpH : 0);
+	}
+	void setFeatureClipX(int left, int right) override {
+		Common::Rect clipped = _active3DViewport;
+		if (left > clipped.left)
+			clipped.left = left;
+		if (right < clipped.right)
+			clipped.right = right;
+		if (clipped.left >= clipped.right)
+			clipped.right = clipped.left;
+		applyScissorRect(clipped);
+	}
+	void clearFeatureClipX() override {
+		applyScissorRect(_active3DViewport);
+	}
 	void computeScreenViewport() override;
 	void drawSurface(const Graphics::Surface *surf, int x, int y) override;
 	Graphics::Surface *getScreenshot() override;
@@ -110,6 +134,7 @@ private:
 	GLuint _overlayTexId = 0;
 
 	OSystem *_system = nullptr;
+	Common::Rect _active3DViewport;
 	int _width = 0;
 	int _height = 0;
 	byte _palette[256 * 3] = {};
@@ -274,6 +299,7 @@ void OpenGLRenderer::begin3D(int camX, int camY, int camZ, int angle, int angleY
  
 	glViewport(vpX, vpY, vpW, vpH);
 	glScissor(vpX, vpY, vpW, vpH);
+	_active3DViewport = viewport;
 	glEnable(GL_SCISSOR_TEST);
 	glEnable(GL_DEPTH_TEST);
 	glDepthFunc(GL_LEQUAL);
diff --git a/engines/colony/renderer_opengl_shaders.cpp b/engines/colony/renderer_opengl_shaders.cpp
index f05bb02c14d..e97a898c68e 100644
--- a/engines/colony/renderer_opengl_shaders.cpp
+++ b/engines/colony/renderer_opengl_shaders.cpp
@@ -80,6 +80,9 @@ public:
 	void setMacColors(uint32 fg, uint32 bg) override;
 	void setDepthState(bool testEnabled, bool writeEnabled) override;
 	void setDepthRange(float nearVal, float farVal) override;
+	void setFeatureClipX(int left, int right) override;
+	void clearFeatureClipX() override;
+	void applyScissorRect(const Common::Rect &logical);
 	void computeScreenViewport() override;
 
 	void drawSurface(const Graphics::Surface *surf, int x, int y) override;
@@ -116,6 +119,7 @@ private:
 	void drawWireframeable3D(const float *positions, int vertCount, uint32 color);
 
 	OSystem *_system = nullptr;
+	Common::Rect _active3DViewport;
 	int _width = 0;
 	int _height = 0;
 	byte _palette[256 * 3] = {};
@@ -722,6 +726,32 @@ void OpenGLShaderRenderer::setDepthRange(float nearVal, float farVal) {
 	setGLDepthRange(nearVal, farVal);
 }
 
+void OpenGLShaderRenderer::applyScissorRect(const Common::Rect &logical) {
+	const float scaleX = (float)_screenViewport.width() / (float)_width;
+	const float scaleY = (float)_screenViewport.height() / (float)_height;
+	const int sysH = _system->getHeight();
+	const int vpX = _screenViewport.left + (int)(logical.left * scaleX);
+	const int vpY = sysH - (_screenViewport.top + (int)(logical.bottom * scaleY));
+	const int vpW = (int)(logical.width() * scaleX);
+	const int vpH = (int)(logical.height() * scaleY);
+	glScissor(vpX, vpY, vpW > 0 ? vpW : 0, vpH > 0 ? vpH : 0);
+}
+
+void OpenGLShaderRenderer::setFeatureClipX(int left, int right) {
+	Common::Rect clipped = _active3DViewport;
+	if (left > clipped.left)
+		clipped.left = left;
+	if (right < clipped.right)
+		clipped.right = right;
+	if (clipped.left >= clipped.right)
+		clipped.right = clipped.left;
+	applyScissorRect(clipped);
+}
+
+void OpenGLShaderRenderer::clearFeatureClipX() {
+	applyScissorRect(_active3DViewport);
+}
+
 void OpenGLShaderRenderer::begin3D(int camX, int camY, int camZ, int angle, int angleY,
 		const Common::Rect &viewport) {
 	glEnable(GL_DEPTH_TEST);
@@ -738,6 +768,7 @@ void OpenGLShaderRenderer::begin3D(int camX, int camY, int camZ, int angle, int
 	const int vpH = (int)(viewport.height() * scaleY);
 	glViewport(vpX, vpY, vpW, vpH);
 	glScissor(vpX, vpY, vpW, vpH);
+	_active3DViewport = viewport;
 	glEnable(GL_SCISSOR_TEST);
 	glDepthFunc(GL_LEQUAL);
 	glDepthMask(GL_TRUE);




More information about the Scummvm-git-logs mailing list