[Scummvm-git-logs] scummvm master -> 7a4ef281779d47fd9f76674320ab86c2878ad978

eriktorbjorn noreply at scummvm.org
Sat Jan 4 10:55:22 UTC 2025


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:
7a4ef28177 PEGASUS: Replaced cicn cursor loader, fixing #15600 in the process


Commit: 7a4ef281779d47fd9f76674320ab86c2878ad978
    https://github.com/scummvm/scummvm/commit/7a4ef281779d47fd9f76674320ab86c2878ad978
Author: Torbjörn Andersson (eriktorbjorn at users.sourceforge.net)
Date: 2025-01-04T11:54:58+01:00

Commit Message:
PEGASUS: Replaced cicn cursor loader, fixing #15600 in the process

The cicn cursor loader was introduced recently for the Mac SCUMM v6-7
games. I still haven't played Pegasus Prime, but I have forced it to
load all the nine cursors (ID 128-133, 900-901, and 20000) and it seems
to work fine for all of them. At least after I made a few fixes to the
loader itself.

I did get some crashes with the old code when trying to compare them, so
it's possible that we should backport this to 2.9. But I haven't seen
any bug reports about it, so maybe not...?

Changed paths:
    engines/pegasus/cursor.cpp
    image/cicn.cpp


diff --git a/engines/pegasus/cursor.cpp b/engines/pegasus/cursor.cpp
index b4c790ff39b..c23b4645afc 100644
--- a/engines/pegasus/cursor.cpp
+++ b/engines/pegasus/cursor.cpp
@@ -27,6 +27,7 @@
 #include "common/system.h"
 #include "graphics/cursorman.h"
 #include "graphics/surface.h"
+#include "image/cicn.h"
 #include "image/pict.h"
 
 #include "pegasus/cursor.h"
@@ -154,74 +155,17 @@ void Cursor::loadCursorImage(CursorInfo &cursorInfo) {
 	// The CD version uses (only) lower color cicn images for its cursors
 	Common::SeekableReadStream *cicnStream = g_vm->_resFork->getResource(MKTAG('c', 'i', 'c', 'n'), cursorInfo.tag);
 
-	if (!cicnStream)
-		error("Failed to find color icon %d", cursorInfo.tag);
-
-	// PixMap section
-	Image::PICTDecoder::PixMap pixMap = Image::PICTDecoder::readPixMap(*cicnStream);
-
-	// Mask section
-	cicnStream->readUint32BE(); // mask baseAddr
-	uint16 maskRowBytes = cicnStream->readUint16BE(); // mask rowBytes
-	cicnStream->skip(3 * 2); // mask rect
-	/* uint16 maskHeight = */ cicnStream->readUint16BE();
-
-	// Bitmap section
-	cicnStream->readUint32BE(); // baseAddr
-	uint16 rowBytes = cicnStream->readUint16BE();
-	cicnStream->readUint16BE(); // top
-	cicnStream->readUint16BE(); // left
-	uint16 height = cicnStream->readUint16BE(); // bottom
-	cicnStream->readUint16BE(); // right
-
-	// Data section
-	cicnStream->readUint32BE(); // icon handle
-	cicnStream->skip(maskRowBytes * height); // FIXME: maskHeight doesn't work here, though the specs say it should
-	cicnStream->skip(rowBytes * height);
-
-	// Palette section
-	cicnStream->readUint32BE(); // always 0
-	cicnStream->readUint16BE(); // always 0
-	cursorInfo.colorCount = cicnStream->readUint16BE() + 1;
-
-	cursorInfo.palette = new byte[cursorInfo.colorCount * 3];
-	for (uint16 i = 0; i < cursorInfo.colorCount; i++) {
-		cicnStream->readUint16BE();
-		cursorInfo.palette[i * 3] = cicnStream->readUint16BE() >> 8;
-		cursorInfo.palette[i * 3 + 1] = cicnStream->readUint16BE() >> 8;
-		cursorInfo.palette[i * 3 + 2] = cicnStream->readUint16BE() >> 8;
-	}
-
-	// PixMap data
-	if (pixMap.pixelSize == 8) {
-		cursorInfo.surface->create(pixMap.rowBytes, pixMap.bounds.height(), Graphics::PixelFormat::createFormatCLUT8());
-		cicnStream->read(cursorInfo.surface->getPixels(), pixMap.rowBytes * pixMap.bounds.height());
-
-		// While this looks sensible, it actually doesn't work for some cursors
-		// (ie. the 'can grab' hand)
-		//cursorInfo.surface->w = pixMap.bounds.width();
-	} else if (pixMap.pixelSize == 1) {
-		cursorInfo.surface->create(pixMap.bounds.width(), pixMap.bounds.height(), Graphics::PixelFormat::createFormatCLUT8());
-
-		for (int y = 0; y < pixMap.bounds.height(); y++) {
-			byte *line = (byte *)cursorInfo.surface->getBasePtr(0, y);
-
-			for (int x = 0; x < pixMap.bounds.width();) {
-				byte b = cicnStream->readByte();
+	if (cicnStream) {
+		Image::CicnDecoder cicn;
+		if (!cicn.loadStream(*cicnStream))
+			error("Failed to decode cursor cicn %d", cursorInfo.tag);
 
-				for (int i = 0; i < 8; i++) {
-					*line++ = ((b & (1 << (7 - i))) != 0) ? 1 : 0;
-
-					if (++x == pixMap.bounds.width())
-						break;
-				}
-			}
-		}
-	} else {
-		error("Unhandled %dbpp cicn images", pixMap.pixelSize);
+		cursorInfo.surface = cicn.getSurface()->convertTo(g_system->getScreenFormat(), cicn.getPalette(), cicn.getPaletteColorCount());
+		delete cicnStream;
+		return;
 	}
 
-	delete cicnStream;
+	error("Failed to find color icon %d", cursorInfo.tag);
 }
 
 } // End of namespace Pegasus
diff --git a/image/cicn.cpp b/image/cicn.cpp
index b7c05648e9d..8ff345b381a 100644
--- a/image/cicn.cpp
+++ b/image/cicn.cpp
@@ -79,7 +79,7 @@ bool CicnDecoder::loadStream(Common::SeekableReadStream &stream) {
 	stream.readUint16BE(); // top
 	stream.readUint16BE(); // left
 	uint16 bitmapHeight = stream.readUint16BE(); // bottom
-	stream.readUint16BE(); // right
+	uint16 bitmapWidth = stream.readUint16BE(); // right
 
 	// Mask and bitmap data
 	stream.skip(4);
@@ -122,12 +122,22 @@ bool CicnDecoder::loadStream(Common::SeekableReadStream &stream) {
 	_surface = new Graphics::Surface();
 	_surface->create(pixMap.bounds.width(), pixMap.bounds.height(), Graphics::PixelFormat::createFormatCLUT8());
 
-	if (pixMap.pixelSize == 2) {
+	if (pixMap.pixelSize == 1) {
 		byte *buf = new byte[pixMap.rowBytes];
 		for (int y = 0; y < pixMap.bounds.height(); y++) {
 			stream.read(buf, pixMap.rowBytes);
-			for (int x = 0; x < pixMap.bounds.width(); x += 4) {
-				for (int i = 0; i < 4 && x + i < pixMap.bounds.width(); i++) {
+			for (int x = 0; x < bitmapWidth; x += 8) {
+				for (int i = 0; i < 8 && x + i < bitmapWidth; i++) {
+					_surface->setPixel(x + i, y, (buf[x / 8] >> (7 - i)) & 0x01);
+				}
+			}
+		}
+	} else if (pixMap.pixelSize == 2) {
+		byte *buf = new byte[pixMap.rowBytes];
+		for (int y = 0; y < bitmapHeight; y++) {
+			stream.read(buf, pixMap.rowBytes);
+			for (int x = 0; x < bitmapWidth; x += 4) {
+				for (int i = 0; i < 4 && x + i < bitmapWidth; i++) {
 					_surface->setPixel(x + i, y, (buf[x / 4] >> (6 - 2 * i)) & 0x03);
 				}
 			}
@@ -135,17 +145,21 @@ bool CicnDecoder::loadStream(Common::SeekableReadStream &stream) {
 		delete[] buf;
 	} else if (pixMap.pixelSize == 4) {
 		byte *buf = new byte[pixMap.rowBytes];
-		for (int y = 0; y < pixMap.bounds.height(); y++) {
+		for (int y = 0; y < bitmapHeight; y++) {
 			stream.read(buf, pixMap.rowBytes);
-			for (int x = 0; x < pixMap.bounds.width(); x += 2) {
-				for (int i = 0; i < 2 && x + i < pixMap.bounds.width(); i++) {
+			for (int x = 0; x < bitmapWidth; x += 2) {
+				for (int i = 0; i < 2 && x + i < bitmapWidth; i++) {
 					_surface->setPixel(x + i, y, (buf[x / 2] >> (4 - 4 * i)) & 0x0F);
 				}
 			}
 		}
 		delete[] buf;
 	} else if (pixMap.pixelSize == 8) {
-		stream.read(_surface->getPixels(), pixMap.rowBytes * pixMap.bounds.height());
+		byte *buf = new byte[pixMap.rowBytes];
+		for (int y = 0; y < bitmapHeight; y++) {
+			stream.read(buf, pixMap.rowBytes);
+			memcpy(_surface->getBasePtr(0, y), buf, bitmapWidth);
+		}
 	} else {
 		error("CicnDecoder::loadStream(): Invalid pixel size %d", pixMap.pixelSize);
 	}




More information about the Scummvm-git-logs mailing list