[Scummvm-git-logs] scummvm master -> 97387c745cda25d6be49a92c3aa330b5a0207199

bluegr noreply at scummvm.org
Sun Jun 15 12:10:24 UTC 2025


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

Summary:
6767fe7dbb GRAPHICS: Add variants of Font::drawChar that preserve the alpha channel
97387c745c WINTERMUTE: Switch to Font::drawAlphaString


Commit: 6767fe7dbb9739e4217792a909114c61857484e1
    https://github.com/scummvm/scummvm/commit/6767fe7dbb9739e4217792a909114c61857484e1
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2025-06-15T15:10:21+03:00

Commit Message:
GRAPHICS: Add variants of Font::drawChar that preserve the alpha channel

Changed paths:
    graphics/font.cpp
    graphics/font.h
    graphics/fonts/ttf.cpp


diff --git a/graphics/font.cpp b/graphics/font.cpp
index 38cb0482767..ceb6d8181c1 100644
--- a/graphics/font.cpp
+++ b/graphics/font.cpp
@@ -106,7 +106,7 @@ int getStringWidthImpl(const Font &font, const StringType &str) {
 }
 
 template<class SurfaceType, class StringType>
-void drawStringImpl(const Font &font, SurfaceType *dst, const StringType &str, int x, int y, int w, uint32 color, TextAlign align, int deltax) {
+void drawStringImpl(const Font &font, SurfaceType *dst, const StringType &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool alpha) {
 	// The logic in getBoundingImpl is the same as we use here. In case we
 	// ever change something here we will need to change it there too.
 	assert(dst != 0);
@@ -129,8 +129,12 @@ void drawStringImpl(const Font &font, SurfaceType *dst, const StringType &str, i
 		Common::Rect charBox = font.getBoundingBox(cur);
 		if (x + charBox.right > rightX)
 			break;
-		if (x + charBox.right >= leftX)
-			font.drawChar(dst, cur, x, y, color);
+		if (x + charBox.right >= leftX) {
+			if (alpha)
+				font.drawAlphaChar(dst, cur, x, y, color);
+			else
+				font.drawChar(dst, cur, x, y, color);
+		}
 
 		x += font.getCharWidth(cur);
 	}
@@ -469,19 +473,40 @@ void Font::drawChar(ManagedSurface *dst, uint32 chr, int x, int y, uint32 color)
 	dst->addDirtyRect(charBox);
 }
 
+void Font::drawAlphaChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const {
+	// Generic implementation for 1bpp fonts. Fonts with alpha blending
+	// should override this function.
+
+	uint32 aMask = (0xFF >> dst->format.aLoss) << dst->format.aShift;
+
+	Common::Rect charBox = getBoundingBox(chr);
+	charBox.translate(x, y);
+	dst->fillRect(charBox, color & ~aMask);
+
+	drawChar(dst, chr, x, y, color | aMask);
+}
+
+void Font::drawAlphaChar(ManagedSurface *dst, uint32 chr, int x, int y, uint32 color) const {
+	drawAlphaChar(dst->surfacePtr(), chr, x, y, color);
+
+	Common::Rect charBox = getBoundingBox(chr);
+	charBox.translate(x, y);
+	dst->addDirtyRect(charBox);
+}
+
 void Font::drawString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis) const {
 	Common::String renderStr = useEllipsis ? handleEllipsis(*this, str, w) : str;
-	drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax);
+	drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax, false);
 }
 
 void Font::drawString(Surface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis) const {
 	Common::U32String renderStr = useEllipsis ? handleEllipsis(*this, str, w) : str;
-	drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax);
+	drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax, false);
 }
 
 void Font::drawString(ManagedSurface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis) const {
 	Common::String renderStr = useEllipsis ? handleEllipsis(*this, str, w) : str;
-	drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax);
+	drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax, false);
 
 	if (w != 0) {
 		dst->addDirtyRect(getBoundingBox(str, x, y, w, align, deltax, useEllipsis));
@@ -490,7 +515,35 @@ void Font::drawString(ManagedSurface *dst, const Common::String &str, int x, int
 
 void Font::drawString(ManagedSurface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis) const {
 	Common::U32String renderStr = useEllipsis ? handleEllipsis(*this, str, w) : str;
-	drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax);
+	drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax, false);
+
+	if (w != 0) {
+		dst->addDirtyRect(getBoundingBox(str, x, y, w, align, useEllipsis));
+	}
+}
+
+void Font::drawAlphaString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis) const {
+	Common::String renderStr = useEllipsis ? handleEllipsis(*this, str, w) : str;
+	drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax, true);
+}
+
+void Font::drawAlphaString(Surface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis) const {
+	Common::U32String renderStr = useEllipsis ? handleEllipsis(*this, str, w) : str;
+	drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax, true);
+}
+
+void Font::drawAlphaString(ManagedSurface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis) const {
+	Common::String renderStr = useEllipsis ? handleEllipsis(*this, str, w) : str;
+	drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax, true);
+
+	if (w != 0) {
+		dst->addDirtyRect(getBoundingBox(str, x, y, w, align, deltax, useEllipsis));
+	}
+}
+
+void Font::drawAlphaString(ManagedSurface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis) const {
+	Common::U32String renderStr = useEllipsis ? handleEllipsis(*this, str, w) : str;
+	drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax, true);
 
 	if (w != 0) {
 		dst->addDirtyRect(getBoundingBox(str, x, y, w, align, useEllipsis));
diff --git a/graphics/font.h b/graphics/font.h
index 58c7fa6b3fb..8562c59ba7c 100644
--- a/graphics/font.h
+++ b/graphics/font.h
@@ -213,6 +213,34 @@ public:
 	virtual void drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const = 0;
 	virtual void drawChar(ManagedSurface *dst, uint32 chr, int x, int y, uint32 color) const;
 
+	/**
+	 * Draw a character at a specific point on the surface.
+	 *
+	 * Unlike drawChar(), this stores the alpha channel for fonts
+	 * that would normally blend characters with the contents of
+	 * the surface. This is useful for 3D games, or for games that
+	 * require text on a separate surface to be blitted later.
+	 *
+	 * Note that the point describes the top left edge point where to draw
+	 * the character. This can be different from the top left edge point of the
+	 * character's bounding box. For example, TTF fonts sometimes move
+	 * characters like 't' by one (or more) pixels to the left to create better
+	 * visual results. To query the actual bounding box of a character, use
+	 * getBoundingBox.
+	 * @see getBoundingBox
+	 *
+	 * The Font implementation should take care of not drawing outside of the
+	 * specified surface.
+	 *
+	 * @param dst   The surface to draw on.
+	 * @param chr   The character to draw.
+	 * @param x     The x coordinate where to draw the character.
+	 * @param y     The y coordinate where to draw the character.
+	 * @param color The color of the character.
+	 */
+	virtual void drawAlphaChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const;
+	virtual void drawAlphaChar(ManagedSurface *dst, uint32 chr, int x, int y, uint32 color) const;
+
 	/** @overload */
 
 	/**
@@ -237,6 +265,33 @@ public:
 	/** @overload */
 	void drawString(ManagedSurface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false) const;
 
+	/**
+	 * Draw the given @p str string to the given @p dst surface.
+	 *
+	 * Unlike drawString(), this stores the alpha channel for fonts
+	 * that would normally blend characters with the contents of
+	 * the surface. This is useful for 3D games, or for games that
+	 * require text on a separate surface to be blitted later.
+	 *
+	 * @param dst     The surface on which to draw the string.
+	 * @param str     The string to draw.
+	 * @param x       The x position where to start drawing.
+	 * @param y       The y position where to start drawing.
+	 * @param w       Width of the text area.
+	 * @param color   The color with which to draw the string.
+	 * @param align   Text alignment. This can be used to center the string in the given area or to align it to the right.
+	 * @param deltax  Offset to the x starting position of the string.
+	 * @param useEllipsis  Use ellipsis if needed to fit the string in the area.
+	 *
+	 */
+	void drawAlphaString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false) const;
+	/** @overload */
+	void drawAlphaString(Surface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false) const;
+	/** @overload */
+	void drawAlphaString(ManagedSurface *dst, const Common::String &str, int x, int _y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false) const;
+	/** @overload */
+	void drawAlphaString(ManagedSurface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false) const;
+
 	/**
 	 * Compute and return the width of the string @p str when rendered using this font.
 	 *
diff --git a/graphics/fonts/ttf.cpp b/graphics/fonts/ttf.cpp
index 53c3d664555..9646e2a4d8c 100644
--- a/graphics/fonts/ttf.cpp
+++ b/graphics/fonts/ttf.cpp
@@ -179,6 +179,8 @@ public:
 
 	void drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
 	void drawChar(ManagedSurface *dst, uint32 chr, int x, int y, uint32 color) const override;
+	void drawAlphaChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
+	void drawAlphaChar(ManagedSurface *dst, uint32 chr, int x, int y, uint32 color) const override;
 
 private:
 	bool _initialized;
@@ -209,8 +211,8 @@ private:
 	int computePointSize(int size, TTFSizeMode sizeMode) const;
 	int readPointSizeFromVDMXTable(int height) const;
 	int computePointSizeFromHeaders(int height) const;
-	void drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color,
-		const uint32 *transparentColor) const;
+	void drawCharIntern(Surface *dst, uint32 chr, int x, int y, uint32 color,
+		const uint32 *transparentColor, bool alpha) const;
 
 	FT_Int32 _loadFlags;
 	FT_Render_Mode _renderMode;
@@ -646,18 +648,40 @@ static void renderGlyph(uint8 *dstPos, const int dstPitch, const uint8 *srcPos,
 	}
 }
 
+template<typename ColorType>
+static void renderAlphaGlyph(uint8 *dstPos, const int dstPitch, const uint8 *srcPos,
+		const int srcPitch, const int w, const int h, ColorType color,
+		const PixelFormat &dstFormat) {
+	uint8 sR, sG, sB;
+	dstFormat.colorToRGB(color, sR, sG, sB);
+
+	for (int y = 0; y < h; ++y) {
+		ColorType *rDst = (ColorType *)dstPos;
+		const uint8 *src = srcPos;
+
+		for (int x = 0; x < w; ++x) {
+			*rDst = dstFormat.ARGBToColor(*src, sR, sG, sB);
+			++rDst;
+			++src;
+		}
+
+		dstPos += dstPitch;
+		srcPos += srcPitch;
+	}
+}
+
 } // End of anonymous namespace
 
 void TTFFont::drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const {
-	drawChar(dst, chr, x, y, color, nullptr);
+	drawCharIntern(dst, chr, x, y, color, nullptr, false);
 }
 
 void TTFFont::drawChar(ManagedSurface *dst, uint32 chr, int x, int y, uint32 color) const {
 	if (dst->hasTransparentColor()) {
 		uint32 transColor = dst->getTransparentColor();
-		drawChar(dst->surfacePtr(), chr, x, y, color, &transColor);
+		drawCharIntern(dst->surfacePtr(), chr, x, y, color, &transColor, false);
 	} else {
-		drawChar(dst->surfacePtr(), chr, x, y, color, nullptr);
+		drawCharIntern(dst->surfacePtr(), chr, x, y, color, nullptr, false);
 	}
 
 	Common::Rect charBox = getBoundingBox(chr);
@@ -665,8 +689,20 @@ void TTFFont::drawChar(ManagedSurface *dst, uint32 chr, int x, int y, uint32 col
 	dst->addDirtyRect(charBox);
 }
 
-void TTFFont::drawChar(Surface * dst, uint32 chr, int x, int y, uint32 color,
-		const uint32 *transparentColor) const {
+void TTFFont::drawAlphaChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const {
+	drawCharIntern(dst, chr, x, y, color, nullptr, true);
+}
+
+void TTFFont::drawAlphaChar(ManagedSurface *dst, uint32 chr, int x, int y, uint32 color) const {
+	drawCharIntern(dst->surfacePtr(), chr, x, y, color, nullptr, true);
+
+	Common::Rect charBox = getBoundingBox(chr);
+	charBox.translate(x, y);
+	dst->addDirtyRect(charBox);
+}
+
+void TTFFont::drawCharIntern(Surface * dst, uint32 chr, int x, int y, uint32 color,
+		const uint32 *transparentColor, bool alpha) const {
 	assureCached(chr);
 	GlyphCache::const_iterator glyphEntry = _glyphs.find(chr);
 	if (glyphEntry == _glyphs.end())
@@ -714,30 +750,40 @@ void TTFFont::drawChar(Surface * dst, uint32 chr, int x, int y, uint32 color,
 
 	uint8 *dstPos = (uint8 *)dst->getBasePtr(x, y);
 
-	if (dst->format.isCLUT8()) {
-		for (int cy = 0; cy < h; ++cy) {
-			uint8 *rDst = dstPos;
-			const uint8 *src = srcPos;
-
-			for (int cx = 0; cx < w; ++cx) {
-				// We assume a 1Bpp mode is a color indexed mode, thus we can
-				// not take advantage of anti-aliasing here.
-				if (*src >= 0x80)
-					*rDst = color;
+	if (alpha) {
+		if (dst->format.bytesPerPixel == 1) {
+			renderAlphaGlyph<uint8>(dstPos, dst->pitch, srcPos, glyph.image.pitch, w, h, color, dst->format);
+		} else if (dst->format.bytesPerPixel == 2) {
+			renderAlphaGlyph<uint16>(dstPos, dst->pitch, srcPos, glyph.image.pitch, w, h, color, dst->format);
+		} else if (dst->format.bytesPerPixel == 4) {
+			renderAlphaGlyph<uint32>(dstPos, dst->pitch, srcPos, glyph.image.pitch, w, h, color, dst->format);
+		}
+	} else {
+		if (dst->format.isCLUT8()) {
+			for (int cy = 0; cy < h; ++cy) {
+				uint8 *rDst = dstPos;
+				const uint8 *src = srcPos;
+
+				for (int cx = 0; cx < w; ++cx) {
+					// We assume a 1Bpp mode is a color indexed mode, thus we can
+					// not take advantage of anti-aliasing here.
+					if (*src >= 0x80)
+						*rDst = color;
+
+					++rDst;
+					++src;
+				}
 
-				++rDst;
-				++src;
+				dstPos += dst->pitch;
+				srcPos += glyph.image.pitch;
 			}
-
-			dstPos += dst->pitch;
-			srcPos += glyph.image.pitch;
+		} else if (dst->format.bytesPerPixel == 1) {
+			renderGlyph<uint8>(dstPos, dst->pitch, srcPos, glyph.image.pitch, w, h, color, dst->format, transparentColor);
+		} else if (dst->format.bytesPerPixel == 2) {
+			renderGlyph<uint16>(dstPos, dst->pitch, srcPos, glyph.image.pitch, w, h, color, dst->format, transparentColor);
+		} else if (dst->format.bytesPerPixel == 4) {
+			renderGlyph<uint32>(dstPos, dst->pitch, srcPos, glyph.image.pitch, w, h, color, dst->format, transparentColor);
 		}
-	} else if (dst->format.bytesPerPixel == 1) {
-		renderGlyph<uint8>(dstPos, dst->pitch, srcPos, glyph.image.pitch, w, h, color, dst->format, transparentColor);
-	} else if (dst->format.bytesPerPixel == 2) {
-		renderGlyph<uint16>(dstPos, dst->pitch, srcPos, glyph.image.pitch, w, h, color, dst->format, transparentColor);
-	} else if (dst->format.bytesPerPixel == 4) {
-		renderGlyph<uint32>(dstPos, dst->pitch, srcPos, glyph.image.pitch, w, h, color, dst->format, transparentColor);
 	}
 }
 


Commit: 97387c745cda25d6be49a92c3aa330b5a0207199
    https://github.com/scummvm/scummvm/commit/97387c745cda25d6be49a92c3aa330b5a0207199
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2025-06-15T15:10:21+03:00

Commit Message:
WINTERMUTE: Switch to Font::drawAlphaString

Changed paths:
    engines/wintermute/base/font/base_font_truetype.cpp


diff --git a/engines/wintermute/base/font/base_font_truetype.cpp b/engines/wintermute/base/font/base_font_truetype.cpp
index 69063d6c4f8..71dc41dcea7 100644
--- a/engines/wintermute/base/font/base_font_truetype.cpp
+++ b/engines/wintermute/base/font/base_font_truetype.cpp
@@ -269,7 +269,7 @@ BaseSurface *BaseFontTT::renderTextToTexture(const WideString &text, int width,
 
 	// TODO: This debug call does not work with WideString because text.c_str() returns an uint32 array.
 	//debugC(kWintermuteDebugFont, "%s %d %d %d %d", text.c_str(), RGBCOLGetR(_layers[0]->_color), RGBCOLGetG(_layers[0]->_color), RGBCOLGetB(_layers[0]->_color), RGBCOLGetA(_layers[0]->_color));
-//	void drawString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = true) const;
+//	void drawAlphaString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = true) const;
 	Graphics::Surface *surface = new Graphics::Surface();
 	surface->create((uint16)width, (uint16)(_lineHeight * lines.size()), _gameRef->_renderer->getPixelFormat());
 	uint32 useColor = 0xffffffff;
@@ -282,33 +282,11 @@ BaseSurface *BaseFontTT::renderTextToTexture(const WideString &text, int width,
 		} else {
 			str = Common::convertBiDiU32String(*it, Common::BIDI_PAR_LTR);
 		}
-		_font->drawString(surface, str, 0, heightOffset, width, useColor, alignment);
+		_font->drawAlphaString(surface, str, 0, heightOffset, width, useColor, alignment);
 		heightOffset += (int)_lineHeight;
 	}
 
 	BaseSurface *retSurface = _gameRef->_renderer->createSurface();
-
-	if (_deletableFont) {
-		// Reconstruct the alpha channel of the font.
-
-		// Since we painted it with color 0xFFFFFFFF onto a black background,
-		// the alpha channel is gone, but the color value of each pixel corresponds
-		// to its original alpha value.
-
-		Graphics::PixelFormat format = _gameRef->_renderer->getPixelFormat();
-		uint32 *pixels = (uint32 *)surface->getPixels();
-
-		assert(surface->pitch == surface->w * 4);
-		assert(surface->format.bytesPerPixel == 4);
-
-		for (int i = 0; i < surface->w * surface->h; ++i) {
-			uint8 a, r, g, b;
-			format.colorToRGB(*pixels, r, g, b);
-			a = r;
-			*pixels++ = format.ARGBToColor(a, r, g, b);
-		}
-	}
-
 	retSurface->putSurface(*surface, true);
 	surface->free();
 	delete surface;




More information about the Scummvm-git-logs mailing list