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

Strangerke noreply at scummvm.org
Sat Jan 3 08:18:53 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:
bfa2d8d287 HUGO: Implement DOS displayFrame() (#7108)


Commit: bfa2d8d28720561045551ed660946ada2c9795c3
    https://github.com/scummvm/scummvm/commit/bfa2d8d28720561045551ed660946ada2c9795c3
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2026-01-03T09:18:49+01:00

Commit Message:
HUGO: Implement DOS displayFrame() (#7108)

- Fixes HUGO2 priority glitches in `hall2` doorways, bug #5667
- Fixes HUGO2 priority glitches in front of bed

The Windows version of HUGO2 still has a priority glitch in
front of the bed, but that is a bug in the original game.

Changed paths:
    engines/hugo/display.cpp
    engines/hugo/display.h


diff --git a/engines/hugo/display.cpp b/engines/hugo/display.cpp
index e0a2943d7e2..6ff37bc76ed 100644
--- a/engines/hugo/display.cpp
+++ b/engines/hugo/display.cpp
@@ -238,42 +238,6 @@ void Screen::setBackgroundColor(const uint16 color) {
 	remapPal(0, color);
 }
 
-/**
- * Merge an object frame into _frontBuffer at sx, sy and update rectangle list.
- * If fore TRUE, force object above any overlay
- */
-void Screen::displayFrame(const int sx, const int sy, Seq *seq, const bool foreFl) {
-	debugC(3, kDebugDisplay, "displayFrame(%d, %d, seq, %d)", sx, sy, (foreFl) ? 1 : 0);
-
-	ImagePtr image = seq->_imagePtr;                 // Ptr to object image data
-	ImagePtr subFrontBuffer = &_frontBuffer[sy * kXPix + sx]; // Ptr to offset in _frontBuffer
-	int16 frontBufferwrap = kXPix - seq->_x2 - 1;     // Wraps dest_p after each line
-	int16 imageWrap = seq->_bytesPerLine8 - seq->_x2 - 1;
-	OverlayState overlayState = (foreFl) ? kOvlForeground : kOvlUndef; // Overlay state of object
-	for (uint16 y = 0; y < seq->_lines; y++) {       // Each line in object
-		for (uint16 x = 0; x <= seq->_x2; x++) {
-			if (*image) {                           // Non-transparent
-				byte ovlBound = _vm->_object->getFirstOverlay((uint16)(subFrontBuffer - _frontBuffer) >> 3); // Ptr into overlay bits
-				if (ovlBound & (0x80 >> ((uint16)(subFrontBuffer - _frontBuffer) & 7))) { // Overlay bit is set
-					if (overlayState == kOvlUndef)  // Overlay defined yet?
-						overlayState = findOvl(seq, subFrontBuffer, y);// No, find it.
-					if (overlayState == kOvlForeground) // Object foreground
-						*subFrontBuffer = *image;   // Copy pixel
-				} else {                            // No overlay
-					*subFrontBuffer = *image;       // Copy pixel
-				}
-			}
-			image++;
-			subFrontBuffer++;
-		}
-		image += imageWrap;
-		subFrontBuffer += frontBufferwrap;
-	}
-
-	// Add this rectangle to the display list
-	displayList(kDisplayAdd, sx, sy, seq->_x2 + 1, seq->_lines);
-}
-
 /**
  * Merge rectangles A,B leaving result in B
  */
@@ -741,17 +705,71 @@ void Screen_v1d::loadFontArr(Common::ReadStream &in) {
 	}
 }
 
+/**
+ * Merge an object frame into _frontBuffer at sx, sy and update rectangle list.
+ * If fore TRUE, force object above any overlay
+ *
+ * Note: The DOS version has subtlety different overlay logic than the Windows version.
+ * The overlay base comparison occurs in a different order, and this alters the outcome.
+ * This may have been unintentional when the original DOS code was rewritten from assembly
+ * in C for Windows, as the Windows version introduces a priority bug when standing in
+ * front of the bed in the second room of Hugo2.
+ */
+void Screen_v1d::displayFrame(const int sx, const int sy, Seq *seq, const bool foreFl) {
+	debugC(3, kDebugDisplay, "displayFrame(%d, %d, seq, %d)", sx, sy, (foreFl) ? 1 : 0);
+
+	ImagePtr image = seq->_imagePtr;                 // Ptr to object image data
+	ImagePtr subFrontBuffer = &_frontBuffer[sy * kXPix + sx]; // Ptr to offset in _frontBuffer
+	int16 frontBufferwrap = kXPix - seq->_x2 - 1;     // Wraps dest_p after each line
+	int16 imageWrap = seq->_bytesPerLine8 - seq->_x2 - 1;
+	OverlayState overlayState = (foreFl) ? kOvlForeground : kOvlUndef; // Overlay state of object
+	for (uint16 y = 0; y < seq->_lines; y++) {       // Each line in object
+		for (uint16 x = 0; x <= seq->_x2; x++) {
+			byte ovlBound = _vm->_object->getFirstOverlay((uint16)(subFrontBuffer - _frontBuffer) >> 3); // Ptr into overlay bits
+			if (ovlBound != 0) {
+				if (overlayState == kOvlUndef)  // Overlay defined yet?
+					overlayState = findOvl(seq, subFrontBuffer, y);// No, find it.
+			}
+
+			if (*image) {                           // Non-transparent
+				if (ovlBound & (0x80 >> ((uint16)(subFrontBuffer - _frontBuffer) & 7))) { // Overlay bit is set
+					if (overlayState == kOvlForeground) // Object foreground
+						*subFrontBuffer = *image;   // Copy pixel
+				} else {                            // No overlay
+					*subFrontBuffer = *image;       // Copy pixel
+				}
+			}
+			image++;
+			subFrontBuffer++;
+		}
+		image += imageWrap;
+		subFrontBuffer += frontBufferwrap;
+	}
+
+	// Add this rectangle to the display list
+	displayList(kDisplayAdd, sx, sy, seq->_x2 + 1, seq->_lines);
+}
+
 /**
  * Return the overlay state (Foreground/Background) of the currently
  * processed object by looking down the current column for an overlay
  * base byte set (in which case the object is foreground).
+ *
+ * Note: This DOS function was originally in assembly. We have structured
+ * it to resemble the Windows C code, but the original DOS assembly takes
+ * "y" as the number of lines left to scan, not the number of lines that
+ * have been scanned, so we invert it here. For example, if an object is
+ * 45 lines and and processFrame() locates an overlay byte on the second
+ * line, it will pass 1 for y, so we must scan 44 rows for a base byte
+ * starting from dstPtr (the second row from the top).
  */
 OverlayState Screen_v1d::findOvl(Seq *seqPtr, ImagePtr dstPtr, uint16 y) {
 	debugC(4, kDebugDisplay, "findOvl()");
 
 	uint16 index = (uint16)(dstPtr - _frontBuffer) >> 3;
 
-	for (int i = 0; i < seqPtr->_lines-y; i++) {      // Each line in object
+	int linesToScan = seqPtr->_lines - y;
+	for (int i = 0; i < linesToScan; i++) {         // Each line in object
 		if (_vm->_object->getBaseBoundary(index))   // If any overlay base byte is non-zero then the object is foreground, else back.
 			return kOvlForeground;
 		index += kCompLineSize;
@@ -810,6 +828,42 @@ void Screen_v1w::loadFontArr(Common::ReadStream &in) {
 	}
 }
 
+/**
+ * Merge an object frame into _frontBuffer at sx, sy and update rectangle list.
+ * If fore TRUE, force object above any overlay
+ */
+void Screen_v1w::displayFrame(const int sx, const int sy, Seq *seq, const bool foreFl) {
+	debugC(3, kDebugDisplay, "displayFrame(%d, %d, seq, %d)", sx, sy, (foreFl) ? 1 : 0);
+
+	ImagePtr image = seq->_imagePtr;                 // Ptr to object image data
+	ImagePtr subFrontBuffer = &_frontBuffer[sy * kXPix + sx]; // Ptr to offset in _frontBuffer
+	int16 frontBufferwrap = kXPix - seq->_x2 - 1;     // Wraps dest_p after each line
+	int16 imageWrap = seq->_bytesPerLine8 - seq->_x2 - 1;
+	OverlayState overlayState = (foreFl) ? kOvlForeground : kOvlUndef; // Overlay state of object
+	for (uint16 y = 0; y < seq->_lines; y++) {       // Each line in object
+		for (uint16 x = 0; x <= seq->_x2; x++) {
+			if (*image) {                           // Non-transparent
+				byte ovlBound = _vm->_object->getFirstOverlay((uint16)(subFrontBuffer - _frontBuffer) >> 3); // Ptr into overlay bits
+				if (ovlBound & (0x80 >> ((uint16)(subFrontBuffer - _frontBuffer) & 7))) { // Overlay bit is set
+					if (overlayState == kOvlUndef)  // Overlay defined yet?
+						overlayState = findOvl(seq, subFrontBuffer, y);// No, find it.
+					if (overlayState == kOvlForeground) // Object foreground
+						*subFrontBuffer = *image;   // Copy pixel
+				} else {                            // No overlay
+					*subFrontBuffer = *image;       // Copy pixel
+				}
+			}
+			image++;
+			subFrontBuffer++;
+		}
+		image += imageWrap;
+		subFrontBuffer += frontBufferwrap;
+	}
+
+	// Add this rectangle to the display list
+	displayList(kDisplayAdd, sx, sy, seq->_x2 + 1, seq->_lines);
+}
+
 /**
  * Return the overlay state (Foreground/Background) of the currently
  * processed object by looking down the current column for an overlay
diff --git a/engines/hugo/display.h b/engines/hugo/display.h
index 554c83af0d4..1982634e9c3 100644
--- a/engines/hugo/display.h
+++ b/engines/hugo/display.h
@@ -59,7 +59,7 @@ public:
 	int16    stringLength(const char *s) const;
 
 	void     displayBackground();
-	void     displayFrame(const int sx, const int sy, Seq *seq, const bool foreFl);
+	virtual void displayFrame(const int sx, const int sy, Seq *seq, const bool foreFl) = 0;
 	void     displayList(int update, ...);
 	void     displayRect(const int16 x, const int16 y, const int16 dx, const int16 dy);
 	void     drawBoundaries();
@@ -118,8 +118,6 @@ protected:
 	inline bool isInY(const int16 y, const Rect *rect) const;
 	inline bool isOverlapping(const Rect *rectA, const Rect *rectB) const;
 
-	virtual OverlayState findOvl(Seq *seqPtr, ImagePtr dstPtr, uint16 y) = 0;
-
 private:
 	byte     *_curPalette;
 	byte      _iconImage[kInvDx * kInvDy];
@@ -153,8 +151,10 @@ public:
 
 	void loadFont(int16 fontId) override;
 	void loadFontArr(Common::ReadStream &in) override;
+
+	void displayFrame(const int sx, const int sy, Seq *seq, const bool foreFl) override;
 protected:
-	OverlayState findOvl(Seq *seqPtr, ImagePtr dstPtr, uint16 y) override;
+	OverlayState findOvl(Seq *seqPtr, ImagePtr dstPtr, uint16 y);
 };
 
 class Screen_v1w : public Screen {
@@ -164,8 +164,10 @@ public:
 
 	void loadFont(int16 fontId) override;
 	void loadFontArr(Common::ReadStream &in) override;
+
+	void displayFrame(const int sx, const int sy, Seq *seq, const bool foreFl) override;
 protected:
-	OverlayState findOvl(Seq *seqPtr, ImagePtr dstPtr, uint16 y) override;
+	OverlayState findOvl(Seq *seqPtr, ImagePtr dstPtr, uint16 y);
 };
 
 } // End of namespace Hugo




More information about the Scummvm-git-logs mailing list