[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(¤tObj);
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