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

peterkohaut peterkohaut at users.noreply.github.com
Fri Feb 26 09:26:32 UTC 2021


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:
3ea299fca6 TINSEL: Updated drawing routines for V3


Commit: 3ea299fca6b26cdf8f43aa53b214097a14279852
    https://github.com/scummvm/scummvm/commit/3ea299fca6b26cdf8f43aa53b214097a14279852
Author: Peter Kohaut (peter.kohaut at gmail.com)
Date: 2021-02-26T10:22:18+01:00

Commit Message:
TINSEL: Updated drawing routines for V3

Updated drawing of the background
Implemented drawing of transparent sprites

Changed paths:
    engines/tinsel/cliprect.cpp
    engines/tinsel/cursor.cpp
    engines/tinsel/graphics.cpp
    engines/tinsel/graphics.h
    engines/tinsel/object.cpp
    engines/tinsel/object.h


diff --git a/engines/tinsel/cliprect.cpp b/engines/tinsel/cliprect.cpp
index 6212a1491e..57f7db8663 100644
--- a/engines/tinsel/cliprect.cpp
+++ b/engines/tinsel/cliprect.cpp
@@ -293,13 +293,18 @@ void UpdateClipRect(OBJECT **pObjList, Common::Point *pWin, Common::Rect *pClip)
 		}
 
 		// copy objects properties to local object
-		currentObj.width    = pObj->width;
-		currentObj.height   = pObj->height;
-		currentObj.xPos     = (short)x;
-		currentObj.yPos     = (short)y;
-		currentObj.pPal     = pObj->pPal;
-		currentObj.constant = pObj->constant;
-		currentObj.hBits    = pObj->hBits;
+		currentObj.width          = pObj->width;
+		currentObj.height         = pObj->height;
+		currentObj.xPos           = (short)x;
+		currentObj.yPos           = (short)y;
+		if (!TinselV3) {
+			currentObj.pPal       = pObj->pPal;
+		} else {
+			currentObj.isRLE      = pObj->isRLE;
+			currentObj.colorFlags = pObj->colorFlags;
+		}
+		currentObj.constant       = pObj->constant;
+		currentObj.hBits          = pObj->hBits;
 
 		// draw the object
 		DrawObject(&currentObj);
diff --git a/engines/tinsel/cursor.cpp b/engines/tinsel/cursor.cpp
index caea9afcc0..5883141854 100644
--- a/engines/tinsel/cursor.cpp
+++ b/engines/tinsel/cursor.cpp
@@ -467,12 +467,14 @@ void Cursor::InitCurObj() {
 	const MULTI_INIT *pmi;
 	IMAGE *pim;
 
-	if (TinselV2) {
+	if (TinselV2 || TinselV3) {
 		pFilm = (const FILM *)_vm->_handle->LockMem(_cursorFilm);
 		pfr = (const FREEL *)&pFilm->reels[0];
 		pmi = (MULTI_INIT *)_vm->_handle->LockMem(FROM_32(pfr->mobj));
 
-		PokeInPalette(pmi);
+		if (!TinselV3) {
+			PokeInPalette(pmi);
+		}
 	} else {
 		assert(_vm->_bg->BgPal()); // no background palette
 
diff --git a/engines/tinsel/graphics.cpp b/engines/tinsel/graphics.cpp
index 092376a29a..00dc636e8b 100644
--- a/engines/tinsel/graphics.cpp
+++ b/engines/tinsel/graphics.cpp
@@ -44,6 +44,17 @@ extern uint8 g_transPalette[MAX_COLORS];
 
 //----------------- SUPPORT FUNCTIONS ---------------------
 
+// using ScummVM pixel format functions is too slow on some ports because of runtime overhead, let the compiler do the optimizations instead
+static inline void t3getRGB(uint16 color, uint8 &r, uint8 &g, uint8 &b) {
+	r = (color >> 11) & 0b011111;
+	g = (color >>  5) & 0b111111;
+	b = (color      ) & 0b011111;
+}
+
+static inline uint16 t3getColor(uint8 r, uint8 g, uint8 b) {
+	return ((r & 0b011111) << 11) | ((g & 0b111111) << 5) | (b & 0b011111);
+}
+
 /**
  * PSX Block list unwinder.
  * Chunk type 0x0003 (CHUNK_CHARPTR) in PSX version of DW 1 & 2 is compressed (original code
@@ -618,6 +629,76 @@ static void WrtConst(DRAWOBJECT *pObj, uint8 *destP, bool applyClipping) {
 	}
 }
 
+/**
+ * Tinsel 3 Rendering with transparency support, run-length is not supported
+ */
+static void t3TransWNZ(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP) {
+	bool applyClipping = (pObj->flags & DMA_CLIP) != 0;
+
+	int leftClip = 0;
+	int rightClip = 0;
+
+	if (applyClipping)
+	{
+		pObj->height -= pObj->topClip;
+		pObj->width -= pObj->leftClip + pObj->rightClip;
+
+		leftClip = pObj->leftClip;
+		rightClip = pObj->rightClip;
+	}
+
+	for (int y = 0; y < pObj->height; ++y) {
+		// Get the position to start writing out from
+		uint8 *tempP = destP;
+		srcP += leftClip * 2;
+		for (int x = 0; x < pObj->width; ++x) {
+			uint32 color = READ_UINT16(srcP); //uint32 for checking overflow in blending
+			if (color != 0b1111100000011111) { // "zero" for Tinsel 3 - magenta in 565
+				uint8 srcR, srcG, srcB;
+				t3getRGB(color, srcR, srcG, srcB);
+
+				uint16 dstColor = READ_UINT16(tempP);
+				uint8 dstR, dstG, dstB;
+				t3getRGB(dstColor, dstR, dstG, dstB);
+
+				if ((pObj->colorFlags & 4) != 0) { // additive blending
+					// orginal algo:
+					// color &= 0b1111011111011111;
+					// color += dstColor & 0b1111011111011111;
+					// if (color > 0xFFFF) {
+					// 	color |= 0b1111000000000000;
+					// }
+					// if (color &  0b0000100000000000) {
+					// 	color |= 0b0000011111000000;
+					// }
+					// if (color &  0b0000000000100000) {
+					// 	color |= 0b0000000000011111;
+					// }
+					// color     &= 0b1111011111011111;
+					color = t3getColor(
+						MIN(srcR + dstR, 0b011111),
+						MIN(srcG + dstG, 0b111111),
+						MIN(srcB + dstB, 0b011111)
+					);
+				} else {
+					// original algo looks simple but does not check for overflow
+					// color += (dstColor & 0b1111011111011111) >> 1;
+					color = t3getColor(
+						MIN(srcR + (dstR / 2), 0b011111),
+						MIN(srcG + (dstG / 2), 0b111111),
+						MIN(srcB + (dstB / 2), 0b011111)
+					);
+				}
+				WRITE_UINT16(tempP, color);
+			}
+			tempP += 2;
+			srcP += 2;
+		}
+		srcP += rightClip * 2;
+		destP += SCREEN_WIDTH * 2;
+	}
+}
+
 /**
  * Translates the destination surface within the object's bounds using the transparency
  * lookup table from transpal.cpp (the contents of which have been moved into palette.cpp)
@@ -667,6 +748,31 @@ static void WrtAll(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP, bool applyClippi
 	}
 }
 
+/**
+ * Copies an uncompressed block of data straight to the screen, Tinsel 3 is using 16bpp, hence "* 2"
+ */
+static void t3WrtAll(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP) {
+	bool applyClipping = (pObj->flags & DMA_CLIP) != 0;
+	int objWidth = pObj->width;
+
+	if (applyClipping) {
+		srcP += ((pObj->topClip * pObj->width) + pObj->leftClip) * 2;
+
+		pObj->height -= pObj->topClip + pObj->botClip;
+		pObj->width -= pObj->leftClip + pObj->rightClip;
+
+		if (pObj->width <= 0)
+			return;
+	}
+
+	for (int y = 0; y < pObj->height; ++y) {
+		Common::copy(srcP, srcP + (pObj->width * 2), destP);
+		srcP += objWidth * 2;
+		destP += SCREEN_WIDTH * 2;
+	}
+}
+
+
 /**
  * Renders a packed data stream with a variable sized palette
  */
@@ -922,12 +1028,10 @@ void DrawObject(DRAWOBJECT *pObj) {
 		case 0x11:	// TinselV2, draw sprite without clipping, flipped horizontally
 		case 0x42:	// TinselV2, draw sprite with clipping
 		case 0x51:	// TinselV2, draw sprite with clipping, flipped horizontally
-		case 0x81:	// TinselV2, draw sprite with clipping
-		case 0xC1:	// TinselV2, draw sprite with clipping
 			assert(TinselV2 || (typeId == 0x01 || typeId == 0x41));
 
 			if (TinselV2)
-				t2WrtNonZero(pObj, srcPtr, destPtr, typeId >= 0x40, (typeId & 0x10) != 0);
+				t2WrtNonZero(pObj, srcPtr, destPtr, (typeId & DMA_CLIP) != 0, (typeId & DMA_FLIPH) != 0);
 			else if (TinselV1PSX)
 				PsxDrawTiles(pObj, srcPtr, destPtr, typeId == 0x41, psxFourBitClut, psxSkipBytes, psxMapperTable, true);
 			else if (TinselV1Mac)
@@ -939,7 +1043,9 @@ void DrawObject(DRAWOBJECT *pObj) {
 			break;
 		case 0x08:	// draw background without clipping
 		case 0x48:	// draw background with clipping
-			if (TinselV2 || TinselV1Mac || TinselV0)
+			if (TinselV3)
+				t3WrtAll(pObj, srcPtr, destPtr);
+			else if (TinselV2 || TinselV1Mac || TinselV0)
 				WrtAll(pObj, srcPtr, destPtr, typeId == 0x48);
 			else if (TinselV1PSX)
 				PsxDrawTiles(pObj, srcPtr, destPtr, typeId == 0x48, psxFourBitClut, psxSkipBytes, psxMapperTable, false);
@@ -950,6 +1056,13 @@ void DrawObject(DRAWOBJECT *pObj) {
 		case 0x44:	// fill with constant color with clipping
 			WrtConst(pObj, destPtr, typeId == 0x44);
 			break;
+		case 0x81:	// TinselV3, draw sprite with transparency
+		case 0xC1:	// TinselV3, draw sprite with transparency & clipping
+			if (TinselV3)
+				t3TransWNZ(pObj, srcPtr, destPtr);
+			else if (TinselV2)
+				t2WrtNonZero(pObj, srcPtr, destPtr, (typeId & DMA_CLIP) != 0, (typeId & DMA_FLIPH) != 0);
+			break;
 		case 0x84:	// draw transparent surface without clipping
 		case 0xC4:	// draw transparent surface with clipping
 			WrtTrans(pObj, destPtr, typeId == 0xC4);
diff --git a/engines/tinsel/graphics.h b/engines/tinsel/graphics.h
index b2144247c2..0f05dfcaa7 100644
--- a/engines/tinsel/graphics.h
+++ b/engines/tinsel/graphics.h
@@ -40,6 +40,8 @@ struct DRAWOBJECT {
 	int transOffset;	// transparent character offset
 	int flags;		// object flags - see above for list
 	PALQ *pPal;		// objects palette Q position
+	short isRLE;	// TinselV3, if image is using run-length encoding
+	short colorFlags;	// TinselV3, type of color blending
 	int constant;		// which color in palette for monochrome objects
 	int width;		// width of object
 	int height;		// height of object
diff --git a/engines/tinsel/object.cpp b/engines/tinsel/object.cpp
index 5c0d88ca8f..d71fa6875e 100644
--- a/engines/tinsel/object.cpp
+++ b/engines/tinsel/object.cpp
@@ -373,16 +373,29 @@ OBJECT *InitObject(const OBJ_INIT *pInitTbl) {
 		PALQ *pPalQ= nullptr;	// palette queue pointer
 		const IMAGE *pImg = (const IMAGE *)_vm->_handle->LockMem(pInitTbl->hObjImg); // handle to image
 
-		if (pImg->hImgPal) {
-			// allocate a palette for this object
-			pPalQ = AllocPalette(FROM_32(pImg->hImgPal));
+		if (!TinselV3) {
+			if (pImg->hImgPal) {
+				// allocate a palette for this object
+				pPalQ = AllocPalette(FROM_32(pImg->hImgPal));
 
-			// make sure palette allocated
-			assert(pPalQ != NULL);
-		}
+				// make sure palette allocated
+				assert(pPalQ != NULL);
+			}
+
+			// assign palette to object
+			pObj->pPal = pPalQ;
+		} else {
+			const IMAGE_T3 *pImgT3 = (const IMAGE_T3 *)pImg;
 
-		// assign palette to object
-		pObj->pPal = pPalQ;
+			if ((pImgT3->colorFlags & 0b110U) == 0) {
+				pObj->flags = pObj->flags & ~DMA_GHOST;
+			} else {
+				assert((pObj->flags & DMA_WNZ) != 0);
+				pObj->flags |= DMA_GHOST;
+			}
+			pObj->isRLE = pImgT3->isRLE;
+			pObj->colorFlags = pImgT3->colorFlags;
+		}
 
 		// set objects size
 		pObj->width  = FROM_16(pImg->imgWidth);
diff --git a/engines/tinsel/object.h b/engines/tinsel/object.h
index 95d918a01e..f7384e6fc5 100644
--- a/engines/tinsel/object.h
+++ b/engines/tinsel/object.h
@@ -38,7 +38,8 @@ enum {
 
 	// object flags
 	DMA_WNZ		= 0x0001,	///< write non-zero data
-	DMA_CNZ		= 0x0002,	///< write constant on non-zero data
+	DMA_CNZ		= 0x0002,	///< TinselV1 write constant on non-zero data
+	DMA_RLWA	= 0x0002,	///< TenselV2+ run-length write all
 	DMA_CONST	= 0x0004,	///< write constant on both zero & non-zero data
 	DMA_WA		= 0x0008,	///< write all data
 	DMA_FLIPH	= 0x0010,	///< flip object horizontally
@@ -50,7 +51,6 @@ enum {
 	DMA_USERDEF	= 0x0400,	///< user defined flags start here
 	DMA_GHOST	= 0x0080,
 
-
 	/** flags that effect an objects appearance */
 	DMA_HARDFLAGS	= (DMA_WNZ | DMA_CNZ | DMA_CONST | DMA_WA | DMA_FLIPH | DMA_FLIPV | DMA_TRANS)
 };
@@ -67,6 +67,19 @@ struct IMAGE {
 } PACKED_STRUCT;
 #include "common/pack-end.h"	// END STRUCT PACKING
 
+/** structure for image in Tinsel 3 */
+#include "common/pack-start.h"	// START STRUCT PACKING
+struct IMAGE_T3 {
+	short imgWidth;		///< image width
+	unsigned short imgHeight;	///< image height
+	short anioffX;		///< image x animation offset
+	short anioffY;		///< image y animation offset
+	SCNHANDLE hImgBits;	///< image bitmap handle
+	short isRLE;		///< if image is using run-length encoding
+	short colorFlags;	///< type of blending
+} PACKED_STRUCT;
+#include "common/pack-end.h"	// END STRUCT PACKING
+
 /** a multi-object animation frame is a list of multi-image handles */
 typedef uint32 FRAME;
 
@@ -84,6 +97,8 @@ struct OBJECT {
 	Common::Rect rcPrev;		///< previous screen coordinates of object bounding rectangle
 	int flags;			///< object flags - see above for list
 	PALQ *pPal;			///< objects palette Q position
+	short isRLE;		///< TinselV3, if image is using run-length encoding
+	short colorFlags;	/// TinselV3, type of color blending
 	int constant;		///< which color in palette for monochrome objects
 	int width;			///< width of object
 	int height;			///< height of object




More information about the Scummvm-git-logs mailing list