[Scummvm-git-logs] scummvm master -> 2e0b5c3b6d3462f7c19f380daae3fe350968ba2b

peterkohaut noreply at scummvm.org
Tue Jun 23 18:29:53 UTC 2026


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

Summary:
e4eaf7fcb9 BLADERUNNER: Simplify pixel format handling
4fce59341d BLADERUNNER: Convert the ESPER photos immediately after loading
5f6a396991 BLADERUNNER: Convert VQA codebooks ahead of time
2e0b5c3b6d BLADERUNNER: Use RGBA5551 for the screen on the 3DS


Commit: e4eaf7fcb971f3890cdea0e6b5db7d5f4918e7db
    https://github.com/scummvm/scummvm/commit/e4eaf7fcb971f3890cdea0e6b5db7d5f4918e7db
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2026-06-23T20:29:46+02:00

Commit Message:
BLADERUNNER: Simplify pixel format handling

Changed paths:
    engines/bladerunner/bladerunner.cpp
    engines/bladerunner/bladerunner.h
    engines/bladerunner/font.cpp
    engines/bladerunner/savefile.cpp
    engines/bladerunner/shape.cpp
    engines/bladerunner/ui/kia.cpp


diff --git a/engines/bladerunner/bladerunner.cpp b/engines/bladerunner/bladerunner.cpp
index ee7a12eff0d..2b75de9a7d9 100644
--- a/engines/bladerunner/bladerunner.cpp
+++ b/engines/bladerunner/bladerunner.cpp
@@ -1283,14 +1283,12 @@ void BladeRunnerEngine::gameTick() {
 		// We need to copy pixel by pixel, converting each pixel from 16 to 32bit
 		for (int y = 0; y < kOriginalGameHeight; ++y) {
 			for (int x = 0; x < kOriginalGameWidth; ++x) {
-				uint8 a, r, g, b;
-				//getGameDataColor(_zbuffer->getData()[y*kOriginalGameWidth + x], a, r, g, b);
-				a = 1;
+				uint8 r, g, b;
 				r = _zbuffer->getData()[y*kOriginalGameWidth + x] / 256;
 				g = r;
 				b = r;
 				void   *dstPixel = _surfaceFront.getBasePtr(x, y);
-				drawPixel(_surfaceFront, dstPixel, _surfaceFront.format.ARGBToColor(a, r, g, b));
+				drawPixel(_surfaceFront, dstPixel, _surfaceFront.format.RGBToColor(r, g, b));
 			}
 		}
 	}
@@ -2629,6 +2627,7 @@ bool BladeRunnerEngine::saveGame(Common::WriteStream &stream, Graphics::Surface
 		else
 			Graphics::saveThumbnail(s);
 	} else {
+		// TODO: Do we need to set the alpha channel for original save files?
 		thumb->convertToInPlace(gameDataPixelFormat());
 
 		uint16 *thumbnailData = (uint16*)thumb->getPixels();
@@ -2922,21 +2921,17 @@ void BladeRunnerEngine::blitToScreen(const Graphics::Surface &src) const {
 
 Graphics::Surface BladeRunnerEngine::generateThumbnail() const {
 	Graphics::Surface thumbnail;
-	thumbnail.create(kOriginalGameWidth / 8, kOriginalGameHeight / 8, gameDataPixelFormat());
+	thumbnail.create(kOriginalGameWidth / 8, kOriginalGameHeight / 8, _surfaceFront.format);
 
 	for (int y = 0; y < thumbnail.h; ++y) {
 		for (int x = 0; x < thumbnail.w; ++x) {
-			uint8 r, g, b;
-
-			uint32  srcPixel = READ_UINT32(_surfaceFront.getBasePtr(CLIP(x * 8, 0, _surfaceFront.w - 1), CLIP(y * 8, 0, _surfaceFront.h - 1)));
-			void   *dstPixel = thumbnail.getBasePtr(CLIP(x, 0, thumbnail.w - 1), CLIP(y, 0, thumbnail.h - 1));
-
-			// Throw away alpha channel as it is not needed
-			_surfaceFront.format.colorToRGB(srcPixel, r, g, b);
-			drawPixel(thumbnail, dstPixel, thumbnail.format.RGBToColor(r, g, b));
+			uint32 srcPixel = _surfaceFront.getPixel(CLIP(x * 8, 0, _surfaceFront.w - 1), CLIP(y * 8, 0, _surfaceFront.h - 1));
+			thumbnail.setPixel(CLIP(x, 0, thumbnail.w - 1), CLIP(y, 0, thumbnail.h - 1), srcPixel);
 		}
 	}
 
+	thumbnail.convertToInPlace(gameDataPixelFormat());
+
 	return thumbnail;
 }
 
diff --git a/engines/bladerunner/bladerunner.h b/engines/bladerunner/bladerunner.h
index c744a326f30..993b015531f 100644
--- a/engines/bladerunner/bladerunner.h
+++ b/engines/bladerunner/bladerunner.h
@@ -450,23 +450,23 @@ public:
 	void  setExtraCNotify(uint8 val);
 };
 
-static inline const Graphics::PixelFormat gameDataPixelFormat() {
-	return Graphics::PixelFormat(2, 5, 5, 5, 1, 10, 5, 0, 15);
+static inline constexpr Graphics::PixelFormat gameDataPixelFormat() {
+	return Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0);
 }
 
-static inline void getGameDataColor(uint16 color, uint8 &a, uint8 &r, uint8 &g, uint8 &b) {
-	// gameDataPixelFormat().colorToARGB(vqaColor, a, r, g, b);
+static inline bool getGameDataColor(uint16 color, uint8 &r, uint8 &g, uint8 &b) {
 	// using pixel format functions is too slow on some ports because of runtime checks
 	uint8 r5 = (color >> 10) & 0x1F;
 	uint8 g5 = (color >>  5) & 0x1F;
 	uint8 b5 = (color      ) & 0x1F;
-	a = color >> 15;
 	r = (r5 << 3) | (r5 >> 2);
 	g = (g5 << 3) | (g5 >> 2);
 	b = (b5 << 3) | (b5 >> 2);
+	// alpha is inversed for fonts and shapes
+	return !(color & 0x8000);
 }
 
-static inline const Graphics::PixelFormat screenPixelFormat() {
+static inline const Graphics::PixelFormat &screenPixelFormat() {
 	return ((BladeRunnerEngine*)g_engine)->_screenPixelFormat;
 }
 
diff --git a/engines/bladerunner/font.cpp b/engines/bladerunner/font.cpp
index 3b142de7e1d..b51ec8394c2 100644
--- a/engines/bladerunner/font.cpp
+++ b/engines/bladerunner/font.cpp
@@ -138,9 +138,8 @@ void Font::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 col
 		int currentX = x;
 		int endX = width + x - 1;
 		while (currentX <= endX && currentX < dst->w) {
-			uint8 a, r, g, b;
-			getGameDataColor(*srcPtr, a, r, g, b);
-			if (!a) { // Alpha is inversed
+			uint8 r, g, b;
+			if (getGameDataColor(*srcPtr, r, g, b)) {
 				uint32 outColor = color;
 				if (_useFontColor) {
 					// Ignore the alpha in the output as it is inversed in the input
diff --git a/engines/bladerunner/savefile.cpp b/engines/bladerunner/savefile.cpp
index 392bb5a8fcb..201ef19eb23 100644
--- a/engines/bladerunner/savefile.cpp
+++ b/engines/bladerunner/savefile.cpp
@@ -152,12 +152,11 @@ bool SaveFileManager::readHeader(Common::SeekableReadStream &in, SaveFileHeader
 		if (header._version >= 4) {
 			Graphics::loadThumbnail(s, header._thumbnail);
 		} else {
-			uint16 alphamask = (0xFF >> gameDataPixelFormat().aLoss) << gameDataPixelFormat().aShift;
 			uint16 *thumbnailData = (uint16*)malloc(kThumbnailSize); // freed by ScummVM's smartptr
 			assert(thumbnailData);
 
 			for (uint i = 0; i < kThumbnailSize / 2; ++i) {
-				thumbnailData[i] = s.readUint16LE() | alphamask; // We set all pixels to non-transparency
+				thumbnailData[i] = s.readUint16LE();
 			}
 			header._thumbnail = new Graphics::Surface();
 			header._thumbnail->init(80, 60, 160, thumbnailData, gameDataPixelFormat());
diff --git a/engines/bladerunner/shape.cpp b/engines/bladerunner/shape.cpp
index 230832cb35f..5c779b66919 100644
--- a/engines/bladerunner/shape.cpp
+++ b/engines/bladerunner/shape.cpp
@@ -301,7 +301,7 @@ void Shape::draw(Graphics::Surface &surface, int x, int y, uint16 drawModeBitFla
 		uint16 shpColor = 0;
 		uint32 surfaceColorRGBPrev = 0;
 		uint32 newSurfaceColorRGB = 0;
-		uint8 a, r, g, b;
+		uint8 r, g, b;
 		uint8 rPrev, gPrev, bPrev;
 		uint16 rgb16bitPrev = 0;
 		uint16 rgb16bitAdd = 0;
@@ -310,9 +310,7 @@ void Shape::draw(Graphics::Surface &surface, int x, int y, uint16 drawModeBitFla
 				shpColor = READ_LE_UINT16(src_p);
 				src_p += 2;
 
-				getGameDataColor(shpColor, a, r, g, b);
-
-				if (!a) {
+				if (getGameDataColor(shpColor, r, g, b)) {
 					// 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) {
@@ -345,7 +343,7 @@ void Shape::draw(Graphics::Surface &surface, int x, int y, uint16 drawModeBitFla
 								                | ((uint16)(bPrev >> 3)));
 								rgb16bitAdd = (((uint16)rgb16bitPrev >> 1) & 0xFBEF)
 								             + ((shpColor >> 1) & 0xFBEF);
-								getGameDataColor(rgb16bitAdd, a, r, g, b);
+								getGameDataColor(rgb16bitAdd, r, g, b);
 								newSurfaceColorRGB = surface.format.RGBToColor(r, g, b);
 							}
 						}
diff --git a/engines/bladerunner/ui/kia.cpp b/engines/bladerunner/ui/kia.cpp
index 85451e80dc9..56e81b1e9a2 100644
--- a/engines/bladerunner/ui/kia.cpp
+++ b/engines/bladerunner/ui/kia.cpp
@@ -628,13 +628,12 @@ void KIA::playPhotograph(int photographId) {
 void KIA::playImage(const Graphics::Surface &image) {
 	if (image.w != 80) {
 		Graphics::Surface *tmp = image.scale(80, 60);
-		_playerImage.copyFrom(*tmp);
+		_playerImage.convertFrom(*tmp, screenPixelFormat());
 		tmp->free();
 		delete tmp;
 	} else {
-		_playerImage.copyFrom(image);
+		_playerImage.convertFrom(image, screenPixelFormat());
 	}
-	_playerImage.convertToInPlace(screenPixelFormat());
 }
 
 const char *KIA::scrambleSuspectsName(const char *name) {


Commit: 4fce59341dfc4cb671ebe97639c1dd8549c34f10
    https://github.com/scummvm/scummvm/commit/4fce59341dfc4cb671ebe97639c1dd8549c34f10
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2026-06-23T20:29:46+02:00

Commit Message:
BLADERUNNER: Convert the ESPER photos immediately after loading

Changed paths:
    engines/bladerunner/ui/esper.cpp


diff --git a/engines/bladerunner/ui/esper.cpp b/engines/bladerunner/ui/esper.cpp
index d3fae00a7df..dac94e96950 100644
--- a/engines/bladerunner/ui/esper.cpp
+++ b/engines/bladerunner/ui/esper.cpp
@@ -98,7 +98,6 @@ void ESPER::open(Graphics::Surface *surface) {
 		return;
 	}
 
-	_surfacePhoto.create(kPhotoWidth, kPhotoHeight, gameDataPixelFormat());
 	_surfaceViewport.create(_screen.width(), _screen.height(), screenPixelFormat());
 
 	_viewportNext = _viewport;
@@ -1162,13 +1161,15 @@ void ESPER::copyImageScale(Graphics::Surface &src, Common::Rect srcRect, Graphic
 				dstX = CLIP(dstX, 0, dst.w - 1);
 				dstY = CLIP(dstY, 0, dst.h - 1);
 
-				uint8 r, g, b;
-				src.format.colorToRGB(READ_UINT32(src.getBasePtr(srcX, srcY)), r, g, b);
+				uint32 pixel = READ_UINT32(src.getBasePtr(srcX, srcY));
 				if (_flash) {
+					uint8 r, g, b;
+					src.format.colorToRGB(pixel, r, g, b);
 					// add blue-ish tint
 					b *= 2;
+					pixel = dst.format.RGBToColor(r, g, b);
 				}
-				drawPixel(dst, dst.getBasePtr(dstX, dstY), dst.format.RGBToColor(r, g, b));
+				drawPixel(dst, dst.getBasePtr(dstX, dstY), pixel);
 
 				srcX += srcDstWidthRatio;
 				srcXCounter += srcDstWidthRest;
@@ -1205,13 +1206,15 @@ void ESPER::copyImageScale(Graphics::Surface &src, Common::Rect srcRect, Graphic
 				dstX = CLIP(dstX, 0, dst.w - 1);
 				dstY = CLIP(dstY, 0, dst.h - 1);
 
-				uint8 r, g, b;
-				src.format.colorToRGB(READ_UINT32(src.getBasePtr(srcX, srcY)), r, g, b);
+				uint32 pixel = READ_UINT32(src.getBasePtr(srcX, srcY));
 				if (_flash) {
+					uint8 r, g, b;
+					src.format.colorToRGB(pixel, r, g, b);
 					// add blue-ish tint
 					b *= 2;
+					pixel = dst.format.RGBToColor(r, g, b);
 				}
-				drawPixel(dst, dst.getBasePtr(dstX, dstY), dst.format.RGBToColor(r, g, b));
+				drawPixel(dst, dst.getBasePtr(dstX, dstY), pixel);
 			}
 
 			srcYCounter += srcRect.height();
@@ -1270,13 +1273,15 @@ void ESPER::copyImageBlur(Graphics::Surface &src, Common::Rect srcRect, Graphics
 						dstX = CLIP(dstX, 0, dst.w - 1);
 						dstY = CLIP(dstY, 0, dst.h - 1);
 
-						uint8 r, g, b;
-						src.format.colorToRGB(READ_UINT32(src.getBasePtr(srcX, srcY)), r, g, b);
+						uint32 pixel = READ_UINT32(src.getBasePtr(srcX, srcY));
 						if (_flash) {
+							uint8 r, g, b;
+							src.format.colorToRGB(pixel, r, g, b);
 							// add blue-ish tint
 							b *= 2;
+							dst.format.RGBToColor(r, g, b);
 						}
-						drawPixel(dst, dst.getBasePtr(dstX, dstY), dst.format.RGBToColor(r, g, b));
+						drawPixel(dst, dst.getBasePtr(dstX, dstY), pixel);
 
 						++dstX;
 						++skipX;
@@ -1340,13 +1345,15 @@ void ESPER::copyImageBlur(Graphics::Surface &src, Common::Rect srcRect, Graphics
 						dstX = CLIP(dstX, 0, dst.w - 1);
 						dstY = CLIP(dstY, 0, dst.h - 1);
 
-						uint8 r, g, b;
-						src.format.colorToRGB(READ_UINT32(src.getBasePtr(srcX, srcY)), r, g, b);
+						uint32 pixel = READ_UINT32(src.getBasePtr(srcX, srcY));
 						if (_flash) {
+							uint8 r, g, b;
+							src.format.colorToRGB(pixel, r, g, b);
 							// add blue-ish tint
 							b *= 2;
+							pixel = dst.format.RGBToColor(r, g, b);
 						}
-						drawPixel(dst, dst.getBasePtr(dstX, dstY), dst.format.RGBToColor(r, g, b));
+						drawPixel(dst, dst.getBasePtr(dstX, dstY), pixel);
 
 						++dstX;
 						++skipX;
@@ -1370,9 +1377,8 @@ void ESPER::copyImageBlur(Graphics::Surface &src, Common::Rect srcRect, Graphics
 void ESPER::copyImageBlit(Graphics::Surface &src, Common::Rect srcRect, Graphics::Surface &dst, Common::Rect dstRect) {
 	for (int y = 0; y < dstRect.height(); ++y) {
 		for (int x = 0; x < dstRect.width(); ++x) {
-			uint8 r, g, b;
-			src.format.colorToRGB(READ_UINT32(src.getBasePtr(CLIP(srcRect.left + x, 0, src.w - 1), CLIP(srcRect.top + y, 0, src.h - 1))), r, g, b);
-			drawPixel(dst, dst.getBasePtr(CLIP(dstRect.left + x, 0, dst.w - 1), CLIP(dstRect.top + y, 0, dst.h - 1)), dst.format.RGBToColor(r, g, b));
+			uint32 pixel = READ_UINT32(src.getBasePtr(CLIP(srcRect.left + x, 0, src.w - 1), CLIP(srcRect.top + y, 0, src.h - 1)));
+			drawPixel(dst, dst.getBasePtr(CLIP(dstRect.left + x, 0, dst.w - 1), CLIP(dstRect.top + y, 0, dst.h - 1)), pixel);
 		}
 	}
 }
@@ -1428,19 +1434,22 @@ void ESPER::selectPhoto(int photoId) {
 
 	Common::ScopedPtr<Common::SeekableReadStream> s(_vm->getResourceStream(_photos[photoId].name));
 
-	uint photoSize = _surfacePhoto.w * _surfacePhoto.h * _surfacePhoto.format.bytesPerPixel;
+	_surfacePhoto.free();
+
+	uint photoSize = kPhotoWidth * kPhotoHeight * 2;
+	uint8 *rawData = (uint8 *)malloc(photoSize);
+	assert(rawData);
 
 	s->skip(3); // not used, but there is compression type
 	uint width  = s->readUint32LE();
 	uint height = s->readUint32LE();
 	uint photoCompressedSize = s->size() - s->pos();
-	uint8 *photoCompressed = (uint8 *)_surfacePhoto.getPixels() + photoSize - photoCompressedSize;
+	uint8 *photoCompressed = rawData + photoSize - photoCompressedSize;
 	s->read(photoCompressed, photoCompressedSize);
 
-	decompress_lcw(photoCompressed, photoCompressedSize, (uint8 *)_surfacePhoto.getPixels(), photoSize);
+	decompress_lcw(photoCompressed, photoCompressedSize, rawData, photoSize);
 #ifdef SCUMM_BIG_ENDIAN
 	// As the compression is working with 8-bit data, on big-endian architectures we have to switch order of bytes in uncompressed data
-	uint8 *rawData = (uint8 *)_surfacePhoto.getPixels();
 	for (size_t i = 0; i < photoSize - 1; i += 2) {
 		SWAP(rawData[i], rawData[i + 1]);
 	}
@@ -1451,6 +1460,9 @@ void ESPER::selectPhoto(int photoId) {
 		// _surfacePhoto[j] = Palette[_surfacePhoto[j]];
 	}
 
+	_surfacePhoto.init(kPhotoWidth, kPhotoHeight, kPhotoWidth * 2, rawData, gameDataPixelFormat());
+	_surfacePhoto.convertToInPlace(screenPixelFormat());
+
 	_shapeThumbnail = _shapesPhotos->get(_photos[photoId].shapeId);
 	_buttons->resetImages();
 	_buttons->defineImage(kPhotoCount + 2, Common::Rect(480, 350, 578, 413), _shapeThumbnail, _shapeThumbnail, _shapeThumbnail, nullptr);


Commit: 5f6a396991cf4b17451368bdba551c5260ae22d5
    https://github.com/scummvm/scummvm/commit/5f6a396991cf4b17451368bdba551c5260ae22d5
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2026-06-23T20:29:46+02:00

Commit Message:
BLADERUNNER: Convert VQA codebooks ahead of time

Changed paths:
    engines/bladerunner/vqa_decoder.cpp
    engines/bladerunner/vqa_decoder.h


diff --git a/engines/bladerunner/vqa_decoder.cpp b/engines/bladerunner/vqa_decoder.cpp
index c6813c3caee..a50e19a76ff 100644
--- a/engines/bladerunner/vqa_decoder.cpp
+++ b/engines/bladerunner/vqa_decoder.cpp
@@ -745,6 +745,8 @@ VQADecoder::VQAVideoTrack::VQAVideoTrack(VQADecoder *vqaDecoder) {
 	_codebookInfoNext         = nullptr; // stores the decompressed codebook parts and it's swapped with the active codebook
 	_countOfCBPsToCBF         = 0;
 	_accumulatedCBPZsizeToCBF = 0;
+
+	_blitFunc = Graphics::getFastBlitFunc(screenPixelFormat(), gameDataPixelFormat());
 }
 
 VQADecoder::VQAVideoTrack::~VQAVideoTrack() {
@@ -835,9 +837,13 @@ bool VQADecoder::VQAVideoTrack::readCBFZ(Common::SeekableReadStream *s, uint32 s
 		return true;
 	}
 
-	uint32 codebookSize = 2 * _maxBlocks * _blockW * _blockH;
+	uint32 codebookSize;
 	if (_vqaDecoder->_oldV2VQA) {
 		codebookSize = _maxBlocks * _cbParts;
+	} else {
+		uint bpp = screenPixelFormat().bytesPerPixel;
+		assert(bpp >= 2);
+		codebookSize = _maxBlocks * _blockW * _blockH * (bpp + 1);
 	}
 
 	// This is released in VQADecoder::~VQADecoder()
@@ -851,6 +857,41 @@ bool VQADecoder::VQAVideoTrack::readCBFZ(Common::SeekableReadStream *s, uint32 s
 
 	uint32 bytesDecomprsd = decompress_lcw(_cbfz, size, codebookInfo.data, codebookSize);
 	codebookInfo.size = bytesDecomprsd;
+
+	if (!_vqaDecoder->_oldV2VQA) {
+		// Alpha component is inversed, set srcFormat to XRGB1555 to ignore it
+		// Instead we manually transform alpha values into a mask
+		const Graphics::PixelFormat  srcFormat = gameDataPixelFormat();
+		const Graphics::PixelFormat &dstFormat = screenPixelFormat();
+		uint bpp = dstFormat.bytesPerPixel;
+
+		uint16 *block_src = (uint16 *)codebookInfo.data;
+		uint8 *mask_src = (uint8 *)codebookInfo.data + (bpp * _maxBlocks * _blockW * _blockH);
+
+		for (uint x = 0; x < _maxBlocks * _blockW * _blockH; ++x) {
+#ifdef SCUMM_BIG_ENDIAN
+			// Swap bytes to big endian as the source is little endian
+			block_src[x] = SWAP_BYTES_16(block_src[x]);
+#endif
+			// Extract and invert alpha value
+			// TODO: Can this be skipped if the mask is never used?
+			mask_src[x] = (block_src[x] >> 15) ^ 0x01;
+		}
+
+		// Convert pixel data in place
+		if (_blitFunc) {
+			_blitFunc((byte *)block_src, (const byte *)block_src,
+				_blockW * _blockH * _maxBlocks * bpp,
+				_blockW * _blockH * _maxBlocks * 2,
+				_blockW * _blockH * _maxBlocks, 1);
+		} else if (dstFormat != srcFormat) {
+			Graphics::crossBlit((byte *)block_src, (const byte *)block_src,
+				_blockW * _blockH * _maxBlocks * bpp,
+				_blockW * _blockH * _maxBlocks * 2,
+				_blockW * _blockH * _maxBlocks, 1, dstFormat, srcFormat);
+		}
+	}
+
 	return true;
 }
 
@@ -1097,7 +1138,11 @@ bool VQADecoder::VQAVideoTrack::readVPTR(Common::SeekableReadStream *s, uint32 s
 }
 
 void VQADecoder::VQAVideoTrack::VPTRWriteBlock(Graphics::Surface *surface, unsigned int dstBlock, unsigned int srcBlock, int count, bool alpha) {
-	const uint8 *const block_src = &_codebook[2 * srcBlock * _blockW * _blockH];
+	uint bpp = screenPixelFormat().bytesPerPixel;
+
+	const uint8 *const block_src = &_codebook[bpp *  srcBlock  * _blockW * _blockH];
+	const uint8 *const mask_base = &_codebook[bpp * _maxBlocks * _blockW * _blockH];
+	const uint8 *const mask_src = &mask_base[srcBlock * _blockW * _blockH];
 
 	uint16 blocks_per_line = _width / _blockW;
 
@@ -1105,41 +1150,6 @@ void VQADecoder::VQAVideoTrack::VPTRWriteBlock(Graphics::Surface *surface, unsig
 	uint32 dst_x = 0;
 	uint32 dst_y = 0;
 
-	// Alpha component is inversed, set srcFormat to XRGB1555 to ignore it
-	// Instead we manually transform alpha values into a mask
-	Graphics::PixelFormat srcFormat = Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0);
-	const uint16 *src_p = (const uint16 *)block_src;
-	uint8 *mask = nullptr;
-
-#ifdef SCUMM_BIG_ENDIAN
-	// Swap bytes to big endian as the source is little endian
-	uint16 *swapSrc = (uint16 *)malloc(2 * _blockW * _blockH);
-	if (!swapSrc) {
-		warning("Not enough memory for VPTRWriteBlock");
-		return;
-	}
-
-	for (uint x = 0; x < _blockW * _blockH; ++x) {
-		swapSrc[x] = SWAP_BYTES_16(src_p[x]);
-	}
-
-	src_p = swapSrc;
-#endif
-
-	if (alpha) {
-		mask = (uint8 *)malloc(_blockW * _blockH);
-		if (!mask) {
-			warning("Not enough memory for VPTRWriteBlock");
-			return;
-		}
-		// Create mask using alpha values
-		for (uint x = 0; x < static_cast<uint>(_blockW * _blockH); ++x) {
-			// Extract alpha value
-			// We XOR it with 1 to invert and get an actual alpha value
-			mask[x] = (byte)(READ_UINT16(src_p + x) >> 15) ^ 0x01;
-		}
-	}
-
 	for (uint i = count; i != 0; --i) {
 		intermDiv = (dstBlock + count - i) / blocks_per_line; // start of current blocks line
 		dst_x = ((dstBlock + count - i) - intermDiv * blocks_per_line) * _blockW + _offsetX;
@@ -1148,19 +1158,11 @@ void VQADecoder::VQAVideoTrack::VPTRWriteBlock(Graphics::Surface *surface, unsig
 		uint8* dstPtr = (uint8 *)surface->getBasePtr(dst_x, dst_y);
 		if (alpha) {
 			// Use mask to blit
-			Graphics::crossMaskBlit(dstPtr, (const byte *)src_p, (const byte *)mask, surface->pitch, _blockW * 2, _blockW, _blockW, _blockH, surface->format, srcFormat);
+			Graphics::maskBlit(dstPtr, block_src, mask_src, surface->pitch, _blockW * bpp, _blockW, _blockW, _blockH, bpp);
 		} else {
-			Graphics::crossBlit(dstPtr, (const byte *)src_p, surface->pitch, _blockW * 2, _blockW, _blockH, surface->format, srcFormat);
+			Graphics::copyBlit(dstPtr, block_src, surface->pitch, _blockW * bpp, _blockW, _blockH, bpp);
 		}
 	}
-
-#ifdef SCUMM_BIG_ENDIAN
-	if (swapSrc)
-		free(swapSrc);
-#endif
-
-	if (mask)
-		free(mask);
 }
 
 bool VQADecoder::VQAVideoTrack::decodeFrame(Graphics::Surface *surface) {
diff --git a/engines/bladerunner/vqa_decoder.h b/engines/bladerunner/vqa_decoder.h
index 545ac72a178..c74e632f88c 100644
--- a/engines/bladerunner/vqa_decoder.h
+++ b/engines/bladerunner/vqa_decoder.h
@@ -31,6 +31,7 @@
 #include "common/stream.h"
 #include "common/types.h"
 
+#include "graphics/blit.h"
 #include "graphics/surface.h"
 
 #include "common/array.h"
@@ -279,6 +280,8 @@ public:
 
 		CodebookInfo  *_codebookInfoNext; // Used to store the decompressed codebook data and swap with the active codebook
 
+		Graphics::FastBlitFunc _blitFunc;
+
 		void VPTRWriteBlock(Graphics::Surface *surface, unsigned int dstBlock, unsigned int srcBlock, int count, bool alpha = false);
 		bool decodeFrame(Graphics::Surface *surface);
 	};


Commit: 2e0b5c3b6d3462f7c19f380daae3fe350968ba2b
    https://github.com/scummvm/scummvm/commit/2e0b5c3b6d3462f7c19f380daae3fe350968ba2b
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2026-06-23T20:29:46+02:00

Commit Message:
BLADERUNNER: Use RGBA5551 for the screen on the 3DS

Changed paths:
    engines/bladerunner/bladerunner.cpp


diff --git a/engines/bladerunner/bladerunner.cpp b/engines/bladerunner/bladerunner.cpp
index 2b75de9a7d9..cb4062ca27e 100644
--- a/engines/bladerunner/bladerunner.cpp
+++ b/engines/bladerunner/bladerunner.cpp
@@ -383,7 +383,17 @@ Common::Error BladeRunnerEngine::run() {
 		}
 	}
 
+#ifdef __3DS__
+	// On the 3DS following pixel format is the closest supported
+	// format to the one used by the game data files. We use it here
+	// to take advantage of faster blitting functions.
+	// TODO: Determine this programatically?
+	Graphics::PixelFormat fmt5551(2, 5, 5, 5, 1, 11, 6, 1, 0);
+	initGraphics(gameBRWidth, gameBRHeight, &fmt5551);
+#else
 	initGraphics(gameBRWidth, gameBRHeight, nullptr);
+#endif
+
 	_screenPixelFormat = g_system->getScreenFormat();
 	debug("Using pixel format: %s", _screenPixelFormat.toString().c_str());
 




More information about the Scummvm-git-logs mailing list