[Scummvm-git-logs] scummvm master -> 3eaebb47e29a1c286c16fdb900079e9841a968ba

antoniou79 noreply at scummvm.org
Tue May 16 12:18:10 UTC 2023


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

Summary:
3eaebb47e2 BLADERUNNER: Custom beta cursors for exits and esper


Commit: 3eaebb47e29a1c286c16fdb900079e9841a968ba
    https://github.com/scummvm/scummvm/commit/3eaebb47e29a1c286c16fdb900079e9841a968ba
Author: antoniou79 (a.antoniou79 at gmail.com)
Date: 2023-05-16T15:16:23+03:00

Commit Message:
BLADERUNNER: Custom beta cursors for exits and esper

Also fixes for the beta combat cursors (color and hotspot / target center)

Changed paths:
    engines/bladerunner/debugger.cpp
    engines/bladerunner/mouse.cpp
    engines/bladerunner/mouse.h
    engines/bladerunner/shape.cpp
    engines/bladerunner/shape.h


diff --git a/engines/bladerunner/debugger.cpp b/engines/bladerunner/debugger.cpp
index 9170dc45205..c3b235a3f98 100644
--- a/engines/bladerunner/debugger.cpp
+++ b/engines/bladerunner/debugger.cpp
@@ -1899,7 +1899,7 @@ bool Debugger::cmdRegion(int argc, const char **argv) {
 
 /**
 * click:  Toggle showing mouse click info in the text console (not the debugger window)
-* beta:   Toggle beta crosshairs for aiming in combat mode
+* beta:   Toggle beta crosshairs for aiming in combat mode, exit cursors (custom) and ESPER edge cursors (custom)
 * add0:   Toggle semi-transparent hotspot cursor (additive draw mode 0)
 * add1:   Toggle semi-transparent hotspot cursor (additive draw mode 1)
 */
diff --git a/engines/bladerunner/mouse.cpp b/engines/bladerunner/mouse.cpp
index 44d98eea9aa..5a9ef497b81 100644
--- a/engines/bladerunner/mouse.cpp
+++ b/engines/bladerunner/mouse.cpp
@@ -80,6 +80,7 @@ void Mouse::setCursor(int cursor) {
 		_hotspotX = 0;
 		_hotspotY = 0;
 		break;
+
 	case 1:
 		// normal cursor over hotspot (not exit) (green rotating)
 		// animating: 8 frames (4-11)
@@ -96,36 +97,58 @@ void Mouse::setCursor(int cursor) {
 			}
 		}
 		break;
+
 	case 2:
-		// exit cursor (upwards/North)
+		// static exit cursor (upwards/North)
 		_frame = 12;
 		_hotspotX = 12;
 		_hotspotY = 0;
+		if (_vm->_debugger->_useBetaCrosshairsCursor) {
+			_drawModeBitFlags |= (MouseDrawFlags::CUSTOM | MouseDrawFlags::ESPER_UP);
+		} else {
+			_drawModeBitFlags &= ~(MouseDrawFlags::CUSTOM | MouseDrawFlags::ESPER_UP);
+		}
 		break;
+
 	case 3:
-		// exit cursor (right/East)
+		// static exit cursor (right/East)
 		_frame = 15;
 		_hotspotX = 23;
 		_hotspotY = 12;
+		if (_vm->_debugger->_useBetaCrosshairsCursor) {
+			_drawModeBitFlags |= (MouseDrawFlags::CUSTOM | MouseDrawFlags::ESPER_RIGHT);
+		} else {
+			_drawModeBitFlags &= ~(MouseDrawFlags::CUSTOM | MouseDrawFlags::ESPER_RIGHT);
+		}
 		break;
+
 	case 4:
-		// exit cursor (downwards/South)
+		// static exit cursor (downwards/South)
 		_frame = 13;
 		_hotspotX = 12;
 		_hotspotY = 23;
+		if (_vm->_debugger->_useBetaCrosshairsCursor) {
+			_drawModeBitFlags |= (MouseDrawFlags::CUSTOM | MouseDrawFlags::ESPER_DOWN);
+		}
 		break;
+
 	case 5:
-		// exit cursor (left/West)
+		// static exit cursor (left/West)
 		_frame = 14;
 		_hotspotX = 0;
 		_hotspotY = 12;
+		if (_vm->_debugger->_useBetaCrosshairsCursor) {
+			_drawModeBitFlags |= (MouseDrawFlags::CUSTOM | MouseDrawFlags::ESPER_LEFT);
+		}
 		break;
+
 	case 6:
 		// combat cursor, simple bullets (normal / no target)
 		_frame = 16;
 		_hotspotX = 19;
 		_hotspotY = 19;
 		break;
+
 	case 7:
 		// combat cursor, simple bullets (hot target)
 		// animating: 8 frames (17-24)
@@ -133,12 +156,14 @@ void Mouse::setCursor(int cursor) {
 		_hotspotX = 19;
 		_hotspotY = 19;
 		break;
+
 	case 8:
 		// combat cursor, advanced bullets (normal / no target)
 		_frame = 25;
 		_hotspotX = 19;
 		_hotspotY = 19;
 		break;
+
 	case 9:
 		// combat cursor, advanced bullets (hot target)
 		// animating: 8 frames (26-33)
@@ -146,12 +171,14 @@ void Mouse::setCursor(int cursor) {
 		_hotspotX = 19;
 		_hotspotY = 19;
 		break;
+
 	case 10:
 		// combat cursor, best bullets (normal / no target)
 		_frame = 34;
 		_hotspotX = 19;
 		_hotspotY = 19;
 		break;
+
 	case 11:
 		// combat cursor, best bullets (hot target)
 		// animating: 8 frames (35-42)
@@ -159,6 +186,7 @@ void Mouse::setCursor(int cursor) {
 		_hotspotX = 19;
 		_hotspotY = 19;
 		break;
+
 	case 12:
 		// exit cursor (upwards/North)
 		// resets animCounter too (as opposed to _cursor == 2)
@@ -167,7 +195,11 @@ void Mouse::setCursor(int cursor) {
 		_hotspotX = 12;
 		_hotspotY = 0;
 		_animCounter = 0;
+		if (_vm->_debugger->_useBetaCrosshairsCursor) {
+			_drawModeBitFlags |= (MouseDrawFlags::CUSTOM | MouseDrawFlags::EXIT_UP);
+		}
 		break;
+
 	case 13:
 		// exit cursor (right/East)
 		// resets animCounter too (as opposed to _cursor == 3)
@@ -176,7 +208,11 @@ void Mouse::setCursor(int cursor) {
 		_hotspotX = 23;
 		_hotspotY = 12;
 		_animCounter = 0;
+		if (_vm->_debugger->_useBetaCrosshairsCursor) {
+			_drawModeBitFlags |= (MouseDrawFlags::CUSTOM | MouseDrawFlags::EXIT_RIGHT);
+		}
 		break;
+
 	case 14:
 		// exit cursor (downwards/South)
 		// resets animCounter too (as opposed to _cursor == 4)
@@ -185,7 +221,11 @@ void Mouse::setCursor(int cursor) {
 		_hotspotX = 12;
 		_hotspotY = 23;
 		_animCounter = 0;
+		if (_vm->_debugger->_useBetaCrosshairsCursor) {
+			_drawModeBitFlags |= (MouseDrawFlags::CUSTOM | MouseDrawFlags::EXIT_DOWN);
+		}
 		break;
+
 	case 15:
 		// exit cursor (left/West)
 		// resets animCounter too (as opposed to _cursor == 5)
@@ -194,11 +234,21 @@ void Mouse::setCursor(int cursor) {
 		_hotspotX = 0;
 		_hotspotY = 12;
 		_animCounter = 0;
+		if (_vm->_debugger->_useBetaCrosshairsCursor) {
+			_drawModeBitFlags |= (MouseDrawFlags::CUSTOM | MouseDrawFlags::EXIT_LEFT);
+		}
 		break;
+
 	case 16:
+		// (beta version) combat cursor (inactive)
+		_drawModeBitFlags &= ~(0x01 << _vm->_settings->getAmmoType());
+		_drawModeBitFlags &= ~(MouseDrawFlags::SPECIAL);
 #if !BLADERUNNER_ORIGINAL_BUGS
 		_frame = 0;
+		_hotspotX = 11;
+		_hotspotY = 11;
 		break;
+
 	case 17:
 #endif
 		// (beta version) combat cursor (white or flashing white/blue)
@@ -214,9 +264,13 @@ void Mouse::setCursor(int cursor) {
 		// So:
 		// id 16: inactive (beta) combat crosshairs
 		// id 17: active (beta) combat crosshairs
+		_drawModeBitFlags |= (0x01 << _vm->_settings->getAmmoType());
+		_drawModeBitFlags |=  MouseDrawFlags::SPECIAL;
 		_frame = 1;
 		_hotspotX = 11;
 		_hotspotY = 11;
+		break;
+
 	default:
 		break;
 	}
@@ -230,7 +284,7 @@ void Mouse::getXY(int *x, int *y) const {
 void Mouse::setMouseJitterUp() {
 	switch (_vm->_settings->getDifficulty()) {
 	default:
-		// fallthrough intended
+		// fall through intended
 	case kGameDifficultyEasy:
 		_randomCountdownX = 2;
 		_randomX = _vm->_rnd.getRandomNumberRng(0, 6) - 3;
@@ -254,7 +308,7 @@ void Mouse::setMouseJitterUp() {
 void Mouse::setMouseJitterDown() {
 	switch (_vm->_settings->getDifficulty()) {
 	default:
-		// fallthrough intended
+		// fall through intended
 	case kGameDifficultyEasy:
 		_randomCountdownY = 2;
 		_randomX = _vm->_rnd.getRandomNumberRng(0, 6) - 3;
@@ -332,59 +386,114 @@ void Mouse::updateCursorFrame() {
 	switch (_cursor) {
 	case 0:
 		break;
+
 	case 1:
 		if (++_frame > 11)
 			_frame = 4;
 		break;
+
 	case 2:
+		// fall through
 	case 3:
+		// fall through
 	case 4:
+		// fall through
 	case 5:
+		// fall through
+		// 2,3,4,5 are case for "static" exit arrows, used in ESPER
 	case 6:
+		// 6 is combat cursor, simple bullets (normal / no target)
 		break;
+
 	case 7:
 		if (++_frame > 24)
 			_frame = 17;
 		break;
+
 	case 8:
 		break;
+
 	case 9:
 		if (++_frame > 33)
 			_frame = 26;
 		break;
+
 	case 10:
 		break;
+
 	case 11:
 		if (++_frame > 42)
 			_frame = 35;
 		break;
+
 	case 12:
-		if (++_animCounter >= 4) {
-			_animCounter = 0;
+		if ((_drawModeBitFlags & Mouse::MouseDrawFlags::CUSTOM)
+			&& (_drawModeBitFlags & Mouse::MouseDrawFlags::EXIT_UP)) {
+			// use the 3 least significant bits in place of "frame" index
+			_drawModeBitFlags +=1;
+			if ((_drawModeBitFlags & 0x7) == 0x7) {
+				_drawModeBitFlags &= ~0x7;
+			}
+		} else {
+			if (++_animCounter >= 4) {
+				_animCounter = 0;
+			}
+			_hotspotY = -offset[_animCounter];
 		}
-		_hotspotY = -offset[_animCounter];
 		break;
+
 	case 13:
-		if (++_animCounter >= 4) {
-			_animCounter = 0;
+		if ((_drawModeBitFlags & Mouse::MouseDrawFlags::CUSTOM)
+		    && (_drawModeBitFlags & Mouse::MouseDrawFlags::EXIT_RIGHT)) {
+			// use the 3 least significant bits in place of "frame" index
+			_drawModeBitFlags +=1;
+			if ((_drawModeBitFlags & 0x7) == 0x7) {
+				_drawModeBitFlags &= ~0x7;
+			}
+		} else {
+			if (++_animCounter >= 4) {
+				_animCounter = 0;
+			}
+			_hotspotX = 23 + offset[_animCounter];
 		}
-		_hotspotX = 23 + offset[_animCounter];
 		break;
+
 	case 14:
-		if (++_animCounter >= 4) {
-			_animCounter = 0;
+		if ((_drawModeBitFlags & Mouse::MouseDrawFlags::CUSTOM)
+		    && (_drawModeBitFlags & Mouse::MouseDrawFlags::EXIT_DOWN)) {
+			// use the 3 least significant bits in place of "frame" index
+			_drawModeBitFlags +=1;
+			if ((_drawModeBitFlags & 0x7) == 0x7) {
+				_drawModeBitFlags &= ~0x7;
+			}
+		} else {
+			if (++_animCounter >= 4) {
+				_animCounter = 0;
+			}
+			_hotspotY = 23 + offset[_animCounter];
 		}
-		_hotspotY = 23 + offset[_animCounter];
 		break;
+
 	case 15:
-		if (++_animCounter >= 4) {
-			_animCounter = 0;
+		if ((_drawModeBitFlags & Mouse::MouseDrawFlags::CUSTOM)
+		    && (_drawModeBitFlags & Mouse::MouseDrawFlags::EXIT_LEFT)) {
+			// use the 3 least significant bits in place of "frame" index
+			_drawModeBitFlags +=1;
+			if ((_drawModeBitFlags & 0x7) == 0x7) {
+				_drawModeBitFlags &= ~0x7;
+			}
+		} else {
+			if (++_animCounter >= 4) {
+				_animCounter = 0;
+			}
+			_hotspotX = -offset[_animCounter];
 		}
-		_hotspotX = -offset[_animCounter];
 		break;
+
 	case 16:
 #if !BLADERUNNER_ORIGINAL_BUGS
 		break;
+
 	case 17:
 #endif
 		if (++_frame > 2)
@@ -397,6 +506,7 @@ void Mouse::updateCursorFrame() {
 			_frame = 1;
 #endif
 		break;
+
 	default:
 		break;
 	}
@@ -431,15 +541,19 @@ void Mouse::tick(int x, int y) {
 		case 0:
 			cursorId = 12;
 			break;
+
 		case 1:
 			cursorId = 13;
 			break;
+
 		case 2:
 			cursorId = 14;
 			break;
+
 		case 3:
 			cursorId = 15;
 			break;
+
 		default:
 			break;
 		}
@@ -476,19 +590,20 @@ void Mouse::tick(int x, int y) {
 	if (actorId >= 0 || itemId >= 0 || isObject) {
 		if (_vm->_debugger->_useBetaCrosshairsCursor) {
 			cursorId = 17;
-			_drawModeBitFlags |= (0x01 << _vm->_settings->getAmmoType());
-			_drawModeBitFlags |=  MouseDrawFlags::SPECIAL;
 		} else {
 			switch (_vm->_settings->getAmmoType()) {
 			case 0:
 				cursorId = 7;
 				break;
+
 			case 1:
 				cursorId = 9;
 				break;
+
 			case 2:
 				cursorId = 11;
 				break;
+
 			default:
 				break;
 			}
@@ -499,19 +614,20 @@ void Mouse::tick(int x, int y) {
 	} else {
 		if (_vm->_debugger->_useBetaCrosshairsCursor) {
 			cursorId = 16;
-			_drawModeBitFlags &= ~(0x01 << _vm->_settings->getAmmoType());
-			_drawModeBitFlags &= ~(MouseDrawFlags::SPECIAL);
 		} else {
 			switch (_vm->_settings->getAmmoType()) {
 			case 0:
 				cursorId = 6;
 				break;
+
 			case 1:
 				cursorId = 8;
 				break;
+
 			case 2:
 				cursorId = 10;
 				break;
+
 			default:
 				break;
 			}
diff --git a/engines/bladerunner/mouse.h b/engines/bladerunner/mouse.h
index 0324f2da484..a8dddf0c68c 100644
--- a/engines/bladerunner/mouse.h
+++ b/engines/bladerunner/mouse.h
@@ -50,7 +50,7 @@ class Mouse {
 	int _randomX;
 	int _randomY;
 
-	uint8 _drawModeBitFlags; // replaces the additive bool with a set of bit flags (including flags for additive mode)
+	uint16 _drawModeBitFlags; // replaces the additive bool with a set of bit flags (including flags for additive mode)
 
 public:
 	Mouse(BladeRunnerEngine *vm);
@@ -76,12 +76,21 @@ public:
 	Vector3 getXYZ(int x, int y) const;
 
 	typedef enum mouseDrawFlags {
-		REDCROSSHAIRS    = 0x01,
-		YELLOWCROSSHAIRS = 0x02,
-		BLUECROSSHAIRS   = 0x04,
-		SPECIAL          = 0x08,
-		ADDITIVE_MODE0   = 0x10,
-		ADDITIVE_MODE1   = 0x20
+		REDCROSSHAIRS    = 0x0001,
+		YELLOWCROSSHAIRS = 0x0002,
+		BLUECROSSHAIRS   = 0x0004,
+		SPECIAL          = 0x0008,
+		ADDITIVE_MODE0   = 0x0010,
+		ADDITIVE_MODE1   = 0x0020,
+		CUSTOM           = 0x0040,
+		EXIT_UP          = 0x0080,
+		EXIT_DOWN        = 0x0100,
+		EXIT_LEFT        = 0x0200,
+		EXIT_RIGHT       = 0x0400,
+		ESPER_UP         = 0x0800,
+		ESPER_DOWN       = 0x1000,
+		ESPER_LEFT       = 0x2000,
+		ESPER_RIGHT      = 0x4000
 	} MouseDrawFlags;
 };
 
diff --git a/engines/bladerunner/shape.cpp b/engines/bladerunner/shape.cpp
index 5ae26d5a3b6..1c3646ed1b2 100644
--- a/engines/bladerunner/shape.cpp
+++ b/engines/bladerunner/shape.cpp
@@ -61,7 +61,155 @@ Shape::~Shape() {
 	delete[] _data;
 }
 
-void Shape::draw(Graphics::Surface &surface, int x, int y, uint8 drawModeBitFlags) const {
+void Shape::drawFilledTriangleAux(Graphics::Surface &surface, const int &dst_x, const int &dst_y, int x1, int y1, int x2, int y2, int x3, int y3, uint32 colorRGB) const {
+	// Code used is based on the Bresenham-like algorithm as described in:
+	// https://mcejp.github.io/2020/11/06/bresenham.html
+	// http://www.sunshine2k.de/coding/java/TriangleRasterization/TriangleRasterization.html
+
+	const Vector2 triangleV1 = Vector2(x1, y1);
+	const Vector2 triangleV2 = Vector2(x2, y2); // (V2, V3) should be the flat side, so either x2 == x3 or y2 == y3
+	const Vector2 triangleV3 = Vector2(x3, y3);
+
+	// vTmp1 will be moving along the "left" side of the triangle, and vTmp2 along the "right" side.
+	Vector2 vTmp1 = triangleV1;
+	Vector2 vTmp2 = triangleV1;
+
+	bool swappedDx1WithDy1 = false;
+	bool swappedDx2WithDy2 = false;
+
+	int dx1 = abs(triangleV2.x - triangleV1.x);
+	int dy1 = abs(triangleV2.y - triangleV1.y);
+
+	if (dy1 > dx1) {
+		SWAP(dy1, dx1);
+		swappedDx1WithDy1 = true;
+	}
+
+	int dx2 = abs(triangleV3.x - triangleV1.x);
+	int dy2 = abs(triangleV3.y - triangleV1.y);
+
+	if (dy2 > dx2) {
+		SWAP(dy2, dx2);
+		swappedDx2WithDy2 = true;
+	}
+
+	int signx1 = (triangleV2.x - triangleV1.x) > 0 ? 1: -1;
+	if (triangleV2.x == triangleV1.x) {
+		signx1 = 0;
+	}
+
+	int signx2 = (triangleV3.x - triangleV1.x) > 0 ? 1: -1;
+	if (triangleV3.x == triangleV1.x) {
+		signx2 = 0;
+	}
+
+	int signy1 = (triangleV2.y - triangleV1.y) > 0 ? 1: -1;
+	if (triangleV2.y == triangleV1.y) {
+		signy1 = 0;
+	}
+
+	int signy2 = (triangleV3.y - triangleV1.y) > 0 ? 1: -1;
+	if (triangleV3.y == triangleV1.y) {
+		signy2 = 0;
+	}
+
+	int e1 = 2 * dy1 - dx1;
+	int e2 = 2 * dy2 - dx2;
+
+	for (int i = 0; i <= dx1; ++i) {
+		// dx1 here may be dy1 (if they swapped above). It is whichever was the largest of the two.
+		// We loop over each pixel of "horizontal" (triangle filling) line
+		// check if paint goes from left endpoint of "horizontal" (triangle filling) line to right or other way round
+		int leftEndPoint, rightEndPoint;
+
+		if (triangleV2.y == triangleV3.y) {
+			if (vTmp1.x < vTmp2.x) {
+				leftEndPoint = ceil(vTmp1.x);
+				rightEndPoint = int(vTmp2.x);
+			} else {
+				leftEndPoint = ceil(vTmp2.x);
+				rightEndPoint = int(vTmp1.x);
+			}
+		} else {
+			if (vTmp1.y < vTmp2.y) {
+				leftEndPoint = ceil(vTmp1.y);
+				rightEndPoint = int(vTmp2.y);
+			} else {
+				leftEndPoint = ceil(vTmp2.y);
+				rightEndPoint = int(vTmp1.y);
+			}
+		}
+
+		void *dstPtr;
+		for (int xPos = leftEndPoint; xPos <= rightEndPoint; ++xPos) {
+			if (triangleV2.y == triangleV3.y) {
+				dstPtr = surface.getBasePtr(CLIP(dst_x + xPos, 0, surface.w - 1), CLIP(dst_y + (int)ceil(vTmp1.y), 0, surface.h - 1));
+			} else {
+				dstPtr = surface.getBasePtr(CLIP(dst_x + (int)ceil(vTmp1.x), 0, surface.w - 1), CLIP(dst_y + xPos, 0, surface.h - 1));
+			}
+			drawPixel(surface, dstPtr, colorRGB);
+		}
+
+		while (e1 >= 0) {
+			if (swappedDx1WithDy1) {
+				vTmp1.x += signx1;
+			} else {
+				vTmp1.y += signy1;
+			}
+			e1 = e1 - 2 * dx1;
+		}
+
+		if (swappedDx1WithDy1) {
+			vTmp1.y += signy1;
+		} else {
+			vTmp1.x += signx1;
+		}
+		e1 = e1 + 2 * dy1;
+
+		// Here we've rendered the next point on the "left" edge triangle line.
+		// We now do the same for the "right" edge triangle line, until we are on
+		// the same y-value as on the "left" edge triangle line.
+		if (triangleV2.y == triangleV3.y) {
+			while (vTmp2.y != vTmp1.y) {
+				while (e2 >= 0) {
+					if (swappedDx2WithDy2) {
+						vTmp2.x += signx2;
+					} else {
+						vTmp2.y += signy2;
+					}
+					e2 = e2 - 2 * dx2;
+				}
+
+				if (swappedDx2WithDy2) {
+					vTmp2.y += signy2;
+				} else {
+					vTmp2.x += signx2;
+				}
+				e2 = e2 + 2 * dy2;
+			}
+		} else {
+			while (vTmp2.x != vTmp1.x) {
+				while (e2 >= 0) {
+					if (swappedDx2WithDy2) {
+						vTmp2.x += signx2;
+					} else {
+						vTmp2.y += signy2;
+					}
+					e2 = e2 - 2 * dx2;
+				}
+
+				if (swappedDx2WithDy2) {
+					vTmp2.y += signy2;
+				} else {
+					vTmp2.x += signx2;
+				}
+				e2 = e2 + 2 * dy2;
+			}
+		}
+	}
+}
+
+void Shape::draw(Graphics::Surface &surface, int x, int y, uint16 drawModeBitFlags) const {
 	int src_x = CLIP(-x, 0, _width);
 	int src_y = CLIP(-y, 0, _height);
 
@@ -77,66 +225,138 @@ void Shape::draw(Graphics::Surface &surface, int x, int y, uint8 drawModeBitFlag
 		return;
 	}
 
-	const uint8 *src_p = _data + 2 * (src_y * _width + src_x);
-
-	uint16 shpColor = 0;
-	uint32 surfaceColorRGBPrev = 0;
-	uint32 newSurfaceColorRGB = 0;
-	uint8 a, r, g, b;
-	uint8 rPrev, gPrev, bPrev;
-	uint16 rgb16bitPrev = 0;
-	uint16 rgb16bitAdd = 0;
-	for (int yi = 0; yi != rect_h; ++yi) {
-		for (int xi = 0; xi != rect_w; ++xi) {
-			shpColor = READ_LE_UINT16(src_p);
-			src_p += 2;
-
-			getGameDataColor(shpColor, a, r, g, b);
-
-			if (!a) {
-				// Ignore the alpha in the output as it is inversed in the input
-				void *dstPtr = surface.getBasePtr(CLIP(dst_x + xi, 0, surface.w - 1), CLIP(dst_y + yi, 0, surface.h - 1));
-				if (drawModeBitFlags & Mouse::MouseDrawFlags::SPECIAL) {
-					// It seems that the additive mode was supposed to be used only for cursor shapes
-					// From testing, the only cursor shape that seems to work with it is the green rotating cursor
-					// We add extra code here to cover the cases of the beta crosshairs cursor
-					// being drawn a different color based on bullet power
-					// The code for creating the specific color is custom.
-					if (drawModeBitFlags & Mouse::MouseDrawFlags::REDCROSSHAIRS) {
-						newSurfaceColorRGB = surface.format.RGBToColor((b & 0x8B) | (g >> 1), 0, 0);
-					} else if (drawModeBitFlags & Mouse::MouseDrawFlags::YELLOWCROSSHAIRS) {
-						newSurfaceColorRGB = surface.format.RGBToColor(b & 0xDF, (b & 0xA5) | (g >> 1), 0);
-					} else if (drawModeBitFlags & Mouse::MouseDrawFlags::BLUECROSSHAIRS) {
-						newSurfaceColorRGB = surface.format.RGBToColor(r, g, b);
-					} else {
-						// Additive modes
-						getPixel(surface, dstPtr, surfaceColorRGBPrev);
-						if (drawModeBitFlags & Mouse::MouseDrawFlags::ADDITIVE_MODE0) {
-							// This code makes the cursor semi-transparent
-							// but it may not be what the disassembly of the original was going for.
-							newSurfaceColorRGB = surface.format.RGBToColor(r, g, b);
-							newSurfaceColorRGB = (((uint16)surfaceColorRGBPrev >> 1) & 0xFBEF)
-												  + (((uint16)newSurfaceColorRGB >> 1) & 0xFBEF);
-						} else if (drawModeBitFlags & Mouse::MouseDrawFlags::ADDITIVE_MODE1) {
-							// This code may be closer to what the disassembly of the original was doing
-							// for additive draw mode but it doesn't look well.
-							surface.format.colorToRGB(surfaceColorRGBPrev, rPrev, gPrev, bPrev);
-							rgb16bitPrev = (  ((uint16)(rPrev >> 3) << 10)
-							                | ((uint16)(gPrev >> 3) <<  5)
-							                | ((uint16)(bPrev >> 3)));
-							rgb16bitAdd = (((uint16)rgb16bitPrev >> 1) & 0xFBEF)
-							                      + ((shpColor >> 1) & 0xFBEF);
-							getGameDataColor(rgb16bitAdd, a, r, g, b);
+	if (drawModeBitFlags & Mouse::MouseDrawFlags::CUSTOM) {
+		// for both scene exit cursors and static ESPER edge cursors
+		// we choose 25x25px -- odd dimensions chosen so that pixel 12 is the absolute middle (with edges 0-24)
+		rect_w = MIN(CLIP(25 + x, 0, 25), surface.w - x);
+		rect_h = MIN(CLIP(25 + y, 0, 25), surface.h - y);
+
+		const uint32 exitDemoShapeColors[3] = { surface.format.RGBToColor(255, 255, 143),
+		                                        surface.format.RGBToColor(228, 108,  10),
+		                                        surface.format.RGBToColor(140,   0,  37)  };
+
+		const uint32 esperExitDemoShapeColor = surface.format.RGBToColor(230, 230, 230); //  For ESPER arrows
+		Common::Rect tailRect;
+
+		// We mask out the irrelevant bitflags and exploit the fact
+		// that these exit cursor bitflags do not combine,
+		// so only one of them can be set at any time.
+		switch (drawModeBitFlags & ~0x007F) {
+		case Mouse::MouseDrawFlags::EXIT_RIGHT:
+			// 6 px h, 6 px w
+			drawFilledTriangleAux(surface, dst_x, dst_y, 24, 12, 18,  6, 18, 18, exitDemoShapeColors[ (drawModeBitFlags & 0x7)/2 % 3]);
+			drawFilledTriangleAux(surface, dst_x, dst_y, 16, 12, 10,  6, 10, 18, exitDemoShapeColors[((drawModeBitFlags & 0x7)/2 + 1) % 3]);
+			drawFilledTriangleAux(surface, dst_x, dst_y,  8, 12,  2,  6,  2, 18, exitDemoShapeColors[((drawModeBitFlags & 0x7)/2 + 2) % 3]);
+			break;
+
+		case Mouse::MouseDrawFlags::EXIT_LEFT:
+			drawFilledTriangleAux(surface, dst_x, dst_y,  0, 12,  6,  6,  6, 18, exitDemoShapeColors[ (drawModeBitFlags & 0x7)/2 % 3]);
+			drawFilledTriangleAux(surface, dst_x, dst_y,  8, 12, 14,  6, 14, 18, exitDemoShapeColors[((drawModeBitFlags & 0x7)/2 + 1) % 3]);
+			drawFilledTriangleAux(surface, dst_x, dst_y, 16, 12, 22,  6, 22, 18, exitDemoShapeColors[((drawModeBitFlags & 0x7)/2 + 2) % 3]);
+			break;
+
+		case Mouse::MouseDrawFlags::EXIT_UP:
+			drawFilledTriangleAux(surface, dst_x, dst_y, 12,  0,  6,  6, 18,  6, exitDemoShapeColors[ (drawModeBitFlags & 0x7)/2 % 3]);
+			drawFilledTriangleAux(surface, dst_x, dst_y, 12,  8,  6, 14, 18, 14, exitDemoShapeColors[((drawModeBitFlags & 0x7)/2 + 1) % 3]);
+			drawFilledTriangleAux(surface, dst_x, dst_y, 12, 16,  6, 22, 18, 22, exitDemoShapeColors[((drawModeBitFlags & 0x7)/2 + 2) % 3]);
+			break;
+
+		case Mouse::MouseDrawFlags::EXIT_DOWN:
+			drawFilledTriangleAux(surface, dst_x, dst_y, 12, 24,  6, 18, 18, 18, exitDemoShapeColors[ (drawModeBitFlags & 0x7)/2 % 3]);
+			drawFilledTriangleAux(surface, dst_x, dst_y, 12, 16,  6, 10, 18, 10, exitDemoShapeColors[((drawModeBitFlags & 0x7)/2 + 1) % 3]);
+			drawFilledTriangleAux(surface, dst_x, dst_y, 12,  8,  6,  2, 18,  2, exitDemoShapeColors[((drawModeBitFlags & 0x7)/2 + 2) % 3]);
+			break;
+
+		case Mouse::MouseDrawFlags::ESPER_RIGHT:
+			drawFilledTriangleAux(surface, dst_x, dst_y, 24, 12, 12,  0, 12, 24, esperExitDemoShapeColor);
+			tailRect = Common::Rect(dst_x +  4, dst_y + 6, dst_x + 12, dst_y + 18);
+			surface.fillRect(tailRect, esperExitDemoShapeColor);
+			break;
+
+		case Mouse::MouseDrawFlags::ESPER_LEFT:
+			drawFilledTriangleAux(surface, dst_x, dst_y,  0, 12, 12,  0, 12, 24, esperExitDemoShapeColor);
+			tailRect = Common::Rect(dst_x + 12, dst_y + 6, dst_x + 20, dst_y + 18);
+			surface.fillRect(tailRect, esperExitDemoShapeColor);
+			break;
+
+		case Mouse::MouseDrawFlags::ESPER_UP:
+			drawFilledTriangleAux(surface, dst_x, dst_y, 12,  0,  0, 12, 24, 12, esperExitDemoShapeColor);
+			tailRect = Common::Rect(dst_x +  6, dst_y + 12, dst_x + 18, dst_y + 20);
+			surface.fillRect(tailRect, esperExitDemoShapeColor);
+			break;
+
+		case Mouse::MouseDrawFlags::ESPER_DOWN:
+			drawFilledTriangleAux(surface, dst_x, dst_y, 12, 24,  0, 12, 24, 12, esperExitDemoShapeColor);
+			tailRect = Common::Rect(dst_x +  6,  dst_y + 4, dst_x + 18, dst_y + 12);
+			surface.fillRect(tailRect, esperExitDemoShapeColor);
+			break;
+
+		default:
+			debug("Unsupported custom shape %d", drawModeBitFlags &~ 0xEF);
+			break;
+		}
+	} else {
+		const uint8 *src_p = _data + 2 * (src_y * _width + src_x);
+
+		uint16 shpColor = 0;
+		uint32 surfaceColorRGBPrev = 0;
+		uint32 newSurfaceColorRGB = 0;
+		uint8 a, r, g, b;
+		uint8 rPrev, gPrev, bPrev;
+		uint16 rgb16bitPrev = 0;
+		uint16 rgb16bitAdd = 0;
+		for (int yi = 0; yi != rect_h; ++yi) {
+			for (int xi = 0; xi != rect_w; ++xi) {
+				shpColor = READ_LE_UINT16(src_p);
+				src_p += 2;
+
+				getGameDataColor(shpColor, a, r, g, b);
+
+				if (!a) {
+					// Ignore the alpha in the output as it is inversed in the input
+					void *dstPtr = surface.getBasePtr(CLIP(dst_x + xi, 0, surface.w - 1), CLIP(dst_y + yi, 0, surface.h - 1));
+					if (drawModeBitFlags & Mouse::MouseDrawFlags::SPECIAL) {
+						// It seems that the additive mode was supposed to be used only for cursor shapes
+						// From testing, the only cursor shape that seems to work with it is the green rotating cursor
+						// We add extra code here to cover the cases of the beta crosshairs cursor
+						// being drawn a different color based on bullet power
+						// The code for creating the specific color is custom.
+						if (drawModeBitFlags & Mouse::MouseDrawFlags::REDCROSSHAIRS) {
+							newSurfaceColorRGB = surface.format.RGBToColor((b & 0x8B) | (g >> 1), 0, 0);
+						} else if (drawModeBitFlags & Mouse::MouseDrawFlags::YELLOWCROSSHAIRS) {
+							newSurfaceColorRGB = surface.format.RGBToColor(b & 0xDF, (b & 0xA5) | (g >> 1), 0);
+						} else if (drawModeBitFlags & Mouse::MouseDrawFlags::BLUECROSSHAIRS) {
 							newSurfaceColorRGB = surface.format.RGBToColor(r, g, b);
+						} else {
+							// Additive modes
+							getPixel(surface, dstPtr, surfaceColorRGBPrev);
+							if (drawModeBitFlags & Mouse::MouseDrawFlags::ADDITIVE_MODE0) {
+								// This code makes the cursor semi-transparent
+								// but it may not be what the disassembly of the original was going for.
+								newSurfaceColorRGB = surface.format.RGBToColor(r, g, b);
+								newSurfaceColorRGB = (((uint16)surfaceColorRGBPrev >> 1) & 0xFBEF)
+								                    + (((uint16)newSurfaceColorRGB >> 1) & 0xFBEF);
+							} else if (drawModeBitFlags & Mouse::MouseDrawFlags::ADDITIVE_MODE1) {
+								// This code may be closer to what the disassembly of the original was doing
+								// for additive draw mode but it doesn't look well.
+								surface.format.colorToRGB(surfaceColorRGBPrev, rPrev, gPrev, bPrev);
+								rgb16bitPrev = (  ((uint16)(rPrev >> 3) << 10)
+								                | ((uint16)(gPrev >> 3) <<  5)
+								                | ((uint16)(bPrev >> 3)));
+								rgb16bitAdd = (((uint16)rgb16bitPrev >> 1) & 0xFBEF)
+								             + ((shpColor >> 1) & 0xFBEF);
+								getGameDataColor(rgb16bitAdd, a, r, g, b);
+								newSurfaceColorRGB = surface.format.RGBToColor(r, g, b);
+							}
 						}
+					} else {
+						newSurfaceColorRGB = surface.format.RGBToColor(r, g, b);
 					}
-				} else {
-					newSurfaceColorRGB = surface.format.RGBToColor(r, g, b);
+					drawPixel(surface, dstPtr, newSurfaceColorRGB);
 				}
-				drawPixel(surface, dstPtr, newSurfaceColorRGB);
 			}
+			src_p += 2 * (_width - rect_w);
 		}
-		src_p += 2 * (_width - rect_w);
 	}
 }
 
diff --git a/engines/bladerunner/shape.h b/engines/bladerunner/shape.h
index cb9249f856d..bebca4c72b4 100644
--- a/engines/bladerunner/shape.h
+++ b/engines/bladerunner/shape.h
@@ -47,10 +47,12 @@ class Shape {
 
 	bool load(Common::SeekableReadStream *stream);
 
+	void drawFilledTriangleAux(Graphics::Surface &surface, const int &dst_x, const int &dst_y, int x1, int y1, int x2, int y2, int x3, int y3, uint32 colorRGB) const;
+
 public:
 	~Shape();
 
-	void draw(Graphics::Surface &surface, int x, int y, uint8 drawModeBitFlags = 0) const;
+	void draw(Graphics::Surface &surface, int x, int y, uint16 drawModeBitFlags = 0) const;
 
 	int getWidth() const { return _width; }
 	int getHeight() const { return _height; }




More information about the Scummvm-git-logs mailing list