From 790c8e17e507ec34d839836f9cb3d4e587110f7e Mon Sep 17 00:00:00 2001 From: FluffyQuack Date: Thu, 21 Jan 2021 23:42:00 +0100 Subject: [PATCH] Implemented blended tranparency --- Source/diablo.cpp | 23 +++ Source/diablo.h | 7 + Source/engine.cpp | 79 +++++++- Source/engine.h | 1 - Source/mainmenu.cpp | 4 +- Source/palette.cpp | 47 +++++ Source/palette.h | 1 + Source/render.cpp | 477 +++++++++++++++++++++++++++++++++----------- Source/scrollrt.cpp | 10 + 9 files changed, 525 insertions(+), 124 deletions(-) diff --git a/Source/diablo.cpp b/Source/diablo.cpp index ac74d9a8a..d9342cbe5 100644 --- a/Source/diablo.cpp +++ b/Source/diablo.cpp @@ -55,6 +55,8 @@ char sgbMouseDown; int color_cycle_timer; int ticks_per_sec = 20; WORD tick_delay = 50; +/** Game options */ +Options sgOptions; /* rdata */ @@ -408,6 +410,25 @@ BOOL StartGame(BOOL bNewGame, BOOL bSinglePlayer) return gbRunGameResult; } +/** + * @brief Save game configurations to ini file + */ +static void SaveOptions() +{ + SRegSaveValue("devilutionx", "game speed", 0, sgOptions.ticksPerSecound); + SRegSaveValue("devilutionx", "blended transparency", 0, sgOptions.blendedTransparancy); +} + +/** + * @brief Load game configurations from ini file + */ +static void LoadOptions() +{ + sgOptions.ticksPerSecound = ticks_per_sec; + SRegLoadValue("devilutionx", "game speed", 0, &sgOptions.ticksPerSecound); + sgOptions.blendedTransparancy = getIniBool("devilutionx", "blended transparency", true); +} + static void diablo_init_screen() { MouseX = SCREEN_WIDTH / 2; @@ -498,9 +519,11 @@ void diablo_quit(int exitStatus) int DiabloMain(int argc, char **argv) { diablo_parse_flags(argc, argv); + LoadOptions(); diablo_init(); diablo_splash(); mainmenu_loop(); + SaveOptions(); diablo_deinit(); return 0; diff --git a/Source/diablo.h b/Source/diablo.h index 791c92e80..53cb774d2 100644 --- a/Source/diablo.h +++ b/Source/diablo.h @@ -12,6 +12,11 @@ DEVILUTION_BEGIN_NAMESPACE extern "C" { #endif +typedef struct Options { + bool blendedTransparancy; // Use blended transparency rather than stippled + int ticksPerSecound; // Game play ticks per secound +} Options; + extern SDL_Window *ghMainWnd; extern DWORD glSeedTbl[NUMLEVELS]; extern int gnLevelTypeTbl[NUMLEVELS]; @@ -46,6 +51,7 @@ extern BOOLEAN UseMultiTest; extern char sgbMouseDown; extern int ticks_per_sec; extern WORD tick_delay; +extern Options sgOptions; void FreeGameMem(); BOOL StartGame(BOOL bNewGame, BOOL bSinglePlayer); @@ -59,6 +65,7 @@ void GM_Game(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void LoadGameLevel(BOOL firstflag, int lvldir); void game_loop(BOOL bStartup); void diablo_color_cyc_logic(); +void LoadOptions(); /* rdata */ diff --git a/Source/engine.cpp b/Source/engine.cpp index f4e7924cf..5c4e4f2ac 100644 --- a/Source/engine.cpp +++ b/Source/engine.cpp @@ -330,13 +330,13 @@ void CelBlitLightSafe(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidt } /** - * @brief Same as CelBlitLightSafe, with transparancy applied + * @brief Same as CelBlitLightSafe, with stippled transparancy applied * @param pDecodeTo The output buffer * @param pRLEBytes CEL pixel stream (run-length encoded) * @param nDataSize Size of CEL in bytes * @param nWidth Width of sprite */ -void CelBlitLightTransSafe(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth) +static void CelBlitLightTransSafe(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth) { int w; BOOL shift; @@ -420,7 +420,71 @@ void CelBlitLightTransSafe(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int } /** - * @brief Same as CelBlitLightTransSafe + * @brief Same as CelBlitLightSafe, with blended transparancy applied + * @param pDecodeTo The output buffer + * @param pRLEBytes CEL pixel stream (run-length encoded) + * @param nDataSize Size of CEL in bytes + * @param nWidth Width of sprite + * @param tbl Palette translation table + */ +static void CelBlitLightBlendedSafe(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth, BYTE *tbl) +{ + int i, w; + BYTE width; + BYTE *src, *dst; + + assert(pDecodeTo != NULL); + assert(pRLEBytes != NULL); + assert(gpBuffer); + + src = pRLEBytes; + dst = pDecodeTo; + if (tbl == NULL) + tbl = &pLightTbl[light_table_index * 256]; + w = nWidth; + + for (; src != &pRLEBytes[nDataSize]; dst -= BUFFER_WIDTH + w) { + for (i = w; i;) { + width = *src++; + if (!(width & 0x80)) { + i -= width; + if (dst < gpBufEnd && dst > gpBufStart) { + if (width & 1) { + dst[0] = paletteTransparencyLookup[dst[0]][tbl[src[0]]]; + src++; + dst++; + } + width >>= 1; + if (width & 1) { + dst[0] = paletteTransparencyLookup[dst[0]][tbl[src[0]]]; + dst[1] = paletteTransparencyLookup[dst[1]][tbl[src[1]]]; + src += 2; + dst += 2; + } + width >>= 1; + for (; width; width--) { + dst[0] = paletteTransparencyLookup[dst[0]][tbl[src[0]]]; + dst[1] = paletteTransparencyLookup[dst[1]][tbl[src[1]]]; + dst[2] = paletteTransparencyLookup[dst[2]][tbl[src[2]]]; + dst[3] = paletteTransparencyLookup[dst[3]][tbl[src[3]]]; + src += 4; + dst += 4; + } + } else { + src += width; + dst += width; + } + } else { + width = -(char)width; + dst += width; + i -= width; + } + } + } +} + +/** + * @brief Same as CelBlitLightSafe, with stippled transparancy applied * @param pBuff Target buffer * @param pCelBuff Cel data * @param nCel CEL frame number @@ -435,9 +499,12 @@ void CelClippedBlitLightTrans(BYTE *pBuff, BYTE *pCelBuff, int nCel, int nWidth) pRLEBytes = CelGetFrameClipped(pCelBuff, nCel, &nDataSize); - if (cel_transparency_active) - CelBlitLightTransSafe(pBuff, pRLEBytes, nDataSize, nWidth); - else if (light_table_index) + if (cel_transparency_active) { + if (sgOptions.blendedTransparancy) + CelBlitLightBlendedSafe(pBuff, pRLEBytes, nDataSize, nWidth, NULL); + else + CelBlitLightTransSafe(pBuff, pRLEBytes, nDataSize, nWidth); + } else if (light_table_index) CelBlitLightSafe(pBuff, pRLEBytes, nDataSize, nWidth, NULL); else CelBlitSafe(pBuff, pRLEBytes, nDataSize, nWidth); diff --git a/Source/engine.h b/Source/engine.h index 597ad815e..f28c36cf1 100644 --- a/Source/engine.h +++ b/Source/engine.h @@ -59,7 +59,6 @@ void CelDrawLightRed(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, char void CelBlitSafe(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth); void CelClippedDrawSafe(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth); void CelBlitLightSafe(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth, BYTE *tbl); -void CelBlitLightTransSafe(BYTE *pDecodeTo, BYTE *pRLEBytes, int nDataSize, int nWidth); void CelDrawLightRedSafe(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, char light); void CelBlitWidth(BYTE *pBuff, int x, int y, int wdt, BYTE *pCelBuff, int nCel, int nWidth); void CelBlitOutline(char col, int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth); diff --git a/Source/mainmenu.cpp b/Source/mainmenu.cpp index 8664d31cb..f468df556 100644 --- a/Source/mainmenu.cpp +++ b/Source/mainmenu.cpp @@ -60,9 +60,7 @@ static BOOL mainmenu_single_player() gbIsMultiplayer = false; - if (!SRegLoadValue("devilutionx", "game speed", 0, &ticks_per_sec)) { - SRegSaveValue("devilutionx", "game speed", 0, ticks_per_sec); - } + ticks_per_sec = sgOptions.ticksPerSecound; return mainmenu_init_menu(SELHERO_NEW_DUNGEON); } diff --git a/Source/palette.cpp b/Source/palette.cpp index 5f876ef5e..71aec5a9d 100644 --- a/Source/palette.cpp +++ b/Source/palette.cpp @@ -12,6 +12,7 @@ DEVILUTION_BEGIN_NAMESPACE SDL_Color logical_palette[256]; SDL_Color system_palette[256]; SDL_Color orig_palette[256]; +Uint8 paletteTransparencyLookup[256][256]; //Lookup table for transparency /* data */ @@ -79,6 +80,48 @@ void palette_init() InitPalette(); } +/** + * Generate lookup table for transparency + * + * This is based of the same technique found in Quake2. + * + * To mimic 50% transparency we figure out what colours in the existing palette are the best match for the combination of any 2 colours. + * We save this into a lookup table for use during rendering. + */ +void GenerateBlendedLookupTable() +{ + for (int i = 0; i < 256; i++) { + for (int j = 0; j < 256; j++) { + if (i == j) { // No need to calculate transparency between 2 identical colours + paletteTransparencyLookup[i][j] = j; + continue; + } + if (i > j) { // Half the blends will be mirror identical ([i][j] is the same as [j][i]), so simply copy the existing combination. + paletteTransparencyLookup[i][j] = paletteTransparencyLookup[j][i]; + continue; + } + + Uint8 r = ((int)orig_palette[i].r + (int)orig_palette[j].r) / 2; + Uint8 g = ((int)orig_palette[i].g + (int)orig_palette[j].g) / 2; + Uint8 b = ((int)orig_palette[i].b + (int)orig_palette[j].b) / 2; + Uint8 best; + Uint32 bestDiff = SDL_MAX_UINT32; + for (int k = 0; k < 256; k++) { + int diffr = orig_palette[k].r - r; + int diffg = orig_palette[k].g - g; + int diffb = orig_palette[k].b - b; + int diff = diffr * diffr + diffg * diffg + diffb * diffb; + + if (bestDiff > diff) { + best = k; + bestDiff = diff; + } + } + paletteTransparencyLookup[i][j] = best; + } + } +} + void LoadPalette(const char *pszFileName) { int i; @@ -99,6 +142,10 @@ void LoadPalette(const char *pszFileName) orig_palette[i].a = SDL_ALPHA_OPAQUE; #endif } + + if (sgOptions.blendedTransparancy) { + GenerateBlendedLookupTable(); + } } void LoadRndLvlPal(int l) diff --git a/Source/palette.h b/Source/palette.h index f648cfb11..bee956717 100644 --- a/Source/palette.h +++ b/Source/palette.h @@ -15,6 +15,7 @@ extern "C" { extern SDL_Color logical_palette[256]; extern SDL_Color system_palette[256]; extern SDL_Color orig_palette[256]; +extern Uint8 paletteTransparencyLookup[256][256]; void palette_update(); void SaveGamma(); diff --git a/Source/render.cpp b/Source/render.cpp index 464e5200b..e28d067af 100644 --- a/Source/render.cpp +++ b/Source/render.cpp @@ -18,119 +18,320 @@ enum { RT_RTRAPEZOID }; +/** Fully transparent variant of WallMask. */ +static DWORD WallMask_FullyTrasparent[TILE_HEIGHT] = { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000 +}; +/** Transparent variant of RightMask. */ +static DWORD RightMask_Transparent[TILE_HEIGHT] = { + 0xE0000000, + 0xF0000000, + 0xFE000000, + 0xFF000000, + 0xFFE00000, + 0xFFF00000, + 0xFFFE0000, + 0xFFFF0000, + 0xFFFFE000, + 0xFFFFF000, + 0xFFFFFE00, + 0xFFFFFF00, + 0xFFFFFFE0, + 0xFFFFFFF0, + 0xFFFFFFFE, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF +}; +/** Transparent variant of LeftMask. */ +static DWORD LeftMask_Transparent[TILE_HEIGHT] = { + 0x00000003, + 0x0000000F, + 0x0000003F, + 0x000000FF, + 0x000003FF, + 0x00000FFF, + 0x00003FFF, + 0x0000FFFF, + 0x0003FFFF, + 0x000FFFFF, + 0x003FFFFF, + 0x00FFFFFF, + 0x03FFFFFF, + 0x0FFFFFFF, + 0x3FFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF +}; /** Specifies the draw masks used to render transparency of the right side of tiles. */ static DWORD RightMask[TILE_HEIGHT] = { - 0xEAAAAAAA, 0xF5555555, - 0xFEAAAAAA, 0xFF555555, - 0xFFEAAAAA, 0xFFF55555, - 0xFFFEAAAA, 0xFFFF5555, - 0xFFFFEAAA, 0xFFFFF555, - 0xFFFFFEAA, 0xFFFFFF55, - 0xFFFFFFEA, 0xFFFFFFF5, - 0xFFFFFFFE, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF + 0xEAAAAAAA, + 0xF5555555, + 0xFEAAAAAA, + 0xFF555555, + 0xFFEAAAAA, + 0xFFF55555, + 0xFFFEAAAA, + 0xFFFF5555, + 0xFFFFEAAA, + 0xFFFFF555, + 0xFFFFFEAA, + 0xFFFFFF55, + 0xFFFFFFEA, + 0xFFFFFFF5, + 0xFFFFFFFE, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF }; /** Specifies the draw masks used to render transparency of the left side of tiles. */ static DWORD LeftMask[TILE_HEIGHT] = { - 0xAAAAAAAB, 0x5555555F, - 0xAAAAAABF, 0x555555FF, - 0xAAAAABFF, 0x55555FFF, - 0xAAAABFFF, 0x5555FFFF, - 0xAAABFFFF, 0x555FFFFF, - 0xAABFFFFF, 0x55FFFFFF, - 0xABFFFFFF, 0x5FFFFFFF, - 0xBFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF + 0xAAAAAAAB, + 0x5555555F, + 0xAAAAAABF, + 0x555555FF, + 0xAAAAABFF, + 0x55555FFF, + 0xAAAABFFF, + 0x5555FFFF, + 0xAAABFFFF, + 0x555FFFFF, + 0xAABFFFFF, + 0x55FFFFFF, + 0xABFFFFFF, + 0x5FFFFFFF, + 0xBFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF }; /** Specifies the draw masks used to render transparency of wall tiles. */ static DWORD WallMask[TILE_HEIGHT] = { - 0xAAAAAAAA, 0x55555555, - 0xAAAAAAAA, 0x55555555, - 0xAAAAAAAA, 0x55555555, - 0xAAAAAAAA, 0x55555555, - 0xAAAAAAAA, 0x55555555, - 0xAAAAAAAA, 0x55555555, - 0xAAAAAAAA, 0x55555555, - 0xAAAAAAAA, 0x55555555, - 0xAAAAAAAA, 0x55555555, - 0xAAAAAAAA, 0x55555555, - 0xAAAAAAAA, 0x55555555, - 0xAAAAAAAA, 0x55555555, - 0xAAAAAAAA, 0x55555555, - 0xAAAAAAAA, 0x55555555, - 0xAAAAAAAA, 0x55555555, - 0xAAAAAAAA, 0x55555555 + 0xAAAAAAAA, + 0x55555555, + 0xAAAAAAAA, + 0x55555555, + 0xAAAAAAAA, + 0x55555555, + 0xAAAAAAAA, + 0x55555555, + 0xAAAAAAAA, + 0x55555555, + 0xAAAAAAAA, + 0x55555555, + 0xAAAAAAAA, + 0x55555555, + 0xAAAAAAAA, + 0x55555555, + 0xAAAAAAAA, + 0x55555555, + 0xAAAAAAAA, + 0x55555555, + 0xAAAAAAAA, + 0x55555555, + 0xAAAAAAAA, + 0x55555555, + 0xAAAAAAAA, + 0x55555555, + 0xAAAAAAAA, + 0x55555555, + 0xAAAAAAAA, + 0x55555555, + 0xAAAAAAAA, + 0x55555555 }; - +/** Fully opaque mask */ static DWORD SolidMask[TILE_HEIGHT] = { - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF }; - +/** Used to mask out the left half of the tile diamond and only render additional content */ static DWORD RightFoliageMask[TILE_HEIGHT] = { - 0xFFFFFFFF, 0x3FFFFFFF, - 0x0FFFFFFF, 0x03FFFFFF, - 0x00FFFFFF, 0x003FFFFF, - 0x000FFFFF, 0x0003FFFF, - 0x0000FFFF, 0x00003FFF, - 0x00000FFF, 0x000003FF, - 0x000000FF, 0x0000003F, - 0x0000000F, 0x00000003, - 0x00000000, 0x00000003, - 0x0000000F, 0x0000003F, - 0x000000FF, 0x000003FF, - 0x00000FFF, 0x00003FFF, - 0x0000FFFF, 0x0003FFFF, - 0x000FFFFF, 0x003FFFFF, - 0x00FFFFFF, 0x03FFFFFF, - 0x0FFFFFFF, 0x3FFFFFFF, + 0xFFFFFFFF, + 0x3FFFFFFF, + 0x0FFFFFFF, + 0x03FFFFFF, + 0x00FFFFFF, + 0x003FFFFF, + 0x000FFFFF, + 0x0003FFFF, + 0x0000FFFF, + 0x00003FFF, + 0x00000FFF, + 0x000003FF, + 0x000000FF, + 0x0000003F, + 0x0000000F, + 0x00000003, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, }; - +/** Used to mask out the left half of the tile diamond and only render additional content */ static DWORD LeftFoliageMask[TILE_HEIGHT] = { - 0xFFFFFFFF, 0xFFFFFFFC, - 0xFFFFFFF0, 0xFFFFFFC0, - 0xFFFFFF00, 0xFFFFFC00, - 0xFFFFF000, 0xFFFFC000, - 0xFFFF0000, 0xFFFC0000, - 0xFFF00000, 0xFFC00000, - 0xFF000000, 0xFC000000, - 0xF0000000, 0xC0000000, - 0x00000000, 0xC0000000, - 0xF0000000, 0xFC000000, - 0xFF000000, 0xFFC00000, - 0xFFF00000, 0xFFFC0000, - 0xFFFF0000, 0xFFFFC000, - 0xFFFFF000, 0xFFFFFC00, - 0xFFFFFF00, 0xFFFFFFC0, - 0xFFFFFFF0, 0xFFFFFFFC, + 0xFFFFFFFF, + 0xFFFFFFFC, + 0xFFFFFFF0, + 0xFFFFFFC0, + 0xFFFFFF00, + 0xFFFFFC00, + 0xFFFFF000, + 0xFFFFC000, + 0xFFFF0000, + 0xFFFC0000, + 0xFFF00000, + 0xFFC00000, + 0xFF000000, + 0xFC000000, + 0xF0000000, + 0xC0000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, }; inline static int count_leading_zeros(DWORD mask) @@ -179,12 +380,12 @@ inline static void RenderLine(BYTE **dst, BYTE **src, int n, BYTE *tbl, DWORD ma } #endif - if (mask == 0xFFFFFFFF) { - if (light_table_index == lightmax) { + if (mask == 0xFFFFFFFF) { // Opaque line + if (light_table_index == lightmax) { // Complete darkness memset(*dst, 0, n); - } else if (light_table_index == 0) { + } else if (light_table_index == 0) { // Fully lit memcpy(*dst, *src, n); - } else { + } else { // Partially lit for (int i = 0; i < n; i++) { (*dst)[i] = tbl[(*src)[i]]; } @@ -197,12 +398,37 @@ inline static void RenderLine(BYTE **dst, BYTE **src, int n, BYTE *tbl, DWORD ma assert(n != 0 && n <= sizeof(DWORD) * CHAR_BIT); mask &= DWORD(-1) << ((sizeof(DWORD) * CHAR_BIT) - n); - if (light_table_index == lightmax) { - foreach_set_bit(mask, [=](int i) { (*dst)[i] = 0; }); - } else if (light_table_index == 0) { - foreach_set_bit(mask, [=](int i) { (*dst)[i] = (*src)[i]; }); - } else { - foreach_set_bit(mask, [=](int i) { (*dst)[i] = tbl[(*src)[i]]; }); + if (sgOptions.blendedTransparancy && !cel_foliage_active) { // Blended transparancy + if (light_table_index == lightmax) { // Complete darkness + for (int i = 0; i < n; i++, mask <<= 1) { + if (mask & 0x80000000) + (*dst)[i] = 0; + else + (*dst)[i] = paletteTransparencyLookup[0][(*dst)[i]]; + } + } else if (light_table_index == 0) { // Fully lit + for (int i = 0; i < n; i++, mask <<= 1) { + if (mask & 0x80000000) + (*dst)[i] = (*src)[i]; + else + (*dst)[i] = paletteTransparencyLookup[(*dst)[i]][(*src)[i]]; + } + } else { // Partially lit + for (int i = 0; i < n; i++, mask <<= 1) { + if (mask & 0x80000000) + (*dst)[i] = tbl[(*src)[i]]; + else + (*dst)[i] = paletteTransparencyLookup[(*dst)[i]][tbl[(*src)[i]]]; + } + } + } else { // Stippled transparancy + if (light_table_index == lightmax) { // Complete darkness + foreach_set_bit(mask, [=](int i) { (*dst)[i] = 0; }); + } else if (light_table_index == 0) { // Fully lit + foreach_set_bit(mask, [=](int i) { (*dst)[i] = (*src)[i]; }); + } else { // Partially lit + foreach_set_bit(mask, [=](int i) { (*dst)[i] = tbl[(*src)[i]]; }); + } } } @@ -218,7 +444,8 @@ __attribute__((no_sanitize("shift-base"))) * @brief Blit current world CEL to the given buffer * @param pBuff Output buffer */ -void RenderTile(BYTE *pBuff) +void +RenderTile(BYTE *pBuff) { int i, j; char c, v, tile; @@ -232,22 +459,32 @@ void RenderTile(BYTE *pBuff) tile = (level_cel_block & 0x7000) >> 12; tbl = &pLightTbl[256 * light_table_index]; + // The mask defines what parts of the tile is opaque mask = &SolidMask[TILE_HEIGHT - 1]; if (cel_transparency_active) { if (arch_draw_type == 0) { - mask = &WallMask[TILE_HEIGHT - 1]; + if (sgOptions.blendedTransparancy) // Use a fully transparent mask + mask = &WallMask_FullyTrasparent[TILE_HEIGHT - 1]; + else + mask = &WallMask[TILE_HEIGHT - 1]; } if (arch_draw_type == 1 && tile != RT_LTRIANGLE) { c = block_lvid[level_piece_id]; if (c == 1 || c == 3) { - mask = &LeftMask[TILE_HEIGHT - 1]; + if (sgOptions.blendedTransparancy) // Use a fully transparent mask + mask = &LeftMask_Transparent[TILE_HEIGHT - 1]; + else + mask = &LeftMask[TILE_HEIGHT - 1]; } } if (arch_draw_type == 2 && tile != RT_RTRIANGLE) { c = block_lvid[level_piece_id]; if (c == 2 || c == 3) { - mask = &RightMask[TILE_HEIGHT - 1]; + if (sgOptions.blendedTransparancy) // Use a fully transparent mask + mask = &RightMask_Transparent[TILE_HEIGHT - 1]; + else + mask = &RightMask[TILE_HEIGHT - 1]; } } } else if (arch_draw_type && cel_foliage_active) { @@ -377,9 +614,21 @@ void trans_rect(int sx, int sy, int width, int height) { int row, col; BYTE *pix = &gpBuffer[SCREENXY(sx, sy)]; + + if (sgOptions.blendedTransparancy) { // Blended + for (row = 0; row < height; row++) { + for (col = 0; col < width; col++) { + *pix = paletteTransparencyLookup[0][*pix]; + pix++; + } + pix += BUFFER_WIDTH - width; + } + return; + } + for (row = 0; row < height; row++) { for (col = 0; col < width; col++) { - if ((row & 1 && col & 1) || (!(row & 1) && !(col & 1))) + if ((row & 1 && col & 1) || (!(row & 1) && !(col & 1))) // Stippled *pix = 0; pix++; } diff --git a/Source/scrollrt.cpp b/Source/scrollrt.cpp index 81931921d..62a7782fb 100644 --- a/Source/scrollrt.cpp +++ b/Source/scrollrt.cpp @@ -742,7 +742,17 @@ static void scrollrt_draw_dungeon(int sx, int sy, int dx, int dy) bArch = dSpecial[sx][sy]; if (bArch != 0) { cel_transparency_active = TransList[bMap]; +#ifdef _DEBUG + if (GetAsyncKeyState(DVL_VK_MENU) & 0x8000) { + cel_transparency_active = 0; // Turn transparency off here for debugging + } +#endif CelClippedBlitLightTrans(&gpBuffer[dx + BUFFER_WIDTH * dy], pSpecialCels, bArch, 64); +#ifdef _DEBUG + if (GetAsyncKeyState(DVL_VK_MENU) & 0x8000) { + cel_transparency_active = TransList[bMap]; // Turn transparency back to its normal state + } +#endif } } else { // Tree leaves should always cover player when entering or leaving the tile,