mirror of
https://github.com/isledecomp/isle-portable.git
synced 2025-10-01 00:25:02 -04:00
Faster and cleaner mosaic transition (#530)
This commit is contained in:
parent
1b8f662090
commit
58338fecfc
@ -271,8 +271,15 @@ void MxTransitionManager::DissolveTransition()
|
|||||||
// FUNCTION: LEGO1 0x1004bed0
|
// FUNCTION: LEGO1 0x1004bed0
|
||||||
void MxTransitionManager::MosaicTransition()
|
void MxTransitionManager::MosaicTransition()
|
||||||
{
|
{
|
||||||
|
static LPDIRECTDRAWSURFACE g_transitionSurface = nullptr;
|
||||||
|
static MxU32 g_colors[64][48];
|
||||||
|
|
||||||
if (m_animationTimer == 16) {
|
if (m_animationTimer == 16) {
|
||||||
m_animationTimer = 0;
|
m_animationTimer = 0;
|
||||||
|
if (g_transitionSurface) {
|
||||||
|
g_transitionSurface->Release();
|
||||||
|
g_transitionSurface = nullptr;
|
||||||
|
}
|
||||||
EndTransition(TRUE);
|
EndTransition(TRUE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -297,6 +304,84 @@ void MxTransitionManager::MosaicTransition()
|
|||||||
for (i = 0; i < 48; i++) {
|
for (i = 0; i < 48; i++) {
|
||||||
m_randomShift[i] = SDL_rand(64);
|
m_randomShift[i] = SDL_rand(64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DDSURFACEDESC srcDesc = {};
|
||||||
|
srcDesc.dwSize = sizeof(srcDesc);
|
||||||
|
HRESULT lockRes = m_ddSurface->Lock(NULL, &srcDesc, DDLOCK_WAIT | DDLOCK_READONLY, NULL);
|
||||||
|
if (lockRes == DDERR_SURFACELOST) {
|
||||||
|
m_ddSurface->Restore();
|
||||||
|
lockRes = m_ddSurface->Lock(NULL, &srcDesc, DDLOCK_WAIT | DDLOCK_READONLY, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lockRes != DD_OK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MxS32 bytesPerPixel = srcDesc.ddpfPixelFormat.dwRGBBitCount / 8;
|
||||||
|
|
||||||
|
for (MxS32 col = 0; col < 64; col++) {
|
||||||
|
for (MxS32 row = 0; row < 48; row++) {
|
||||||
|
MxS32 xBlock = (m_randomShift[row] + col) % 64;
|
||||||
|
MxS32 y = row * 10;
|
||||||
|
MxS32 x = xBlock * 10;
|
||||||
|
|
||||||
|
MxU8* pixelPtr = (MxU8*) srcDesc.lpSurface + y * srcDesc.lPitch + x * bytesPerPixel;
|
||||||
|
|
||||||
|
MxU32 pixel;
|
||||||
|
switch (bytesPerPixel) {
|
||||||
|
case 1:
|
||||||
|
pixel = *pixelPtr;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
pixel = *(MxU16*) pixelPtr;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pixel = *(MxU32*) pixelPtr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_colors[col][row] = pixel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ddSurface->Unlock(srcDesc.lpSurface);
|
||||||
|
|
||||||
|
DDSURFACEDESC mainDesc = {};
|
||||||
|
mainDesc.dwSize = sizeof(mainDesc);
|
||||||
|
if (m_ddSurface->GetSurfaceDesc(&mainDesc) != DD_OK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DDSURFACEDESC tempDesc = {};
|
||||||
|
tempDesc.dwSize = sizeof(tempDesc);
|
||||||
|
tempDesc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS;
|
||||||
|
tempDesc.dwWidth = 64;
|
||||||
|
tempDesc.dwHeight = 48;
|
||||||
|
tempDesc.ddpfPixelFormat = mainDesc.ddpfPixelFormat;
|
||||||
|
tempDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
|
||||||
|
|
||||||
|
if (MVideoManager()->GetDirectDraw()->CreateSurface(&tempDesc, &g_transitionSurface, nullptr) != DD_OK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD fillColor = 0x00000000;
|
||||||
|
switch (mainDesc.ddpfPixelFormat.dwRGBBitCount) {
|
||||||
|
case 8:
|
||||||
|
fillColor = 0x10;
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
fillColor = RGB555_CREATE(0x1f, 0, 0x1f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
DDBLTFX bltFx = {};
|
||||||
|
bltFx.dwSize = sizeof(bltFx);
|
||||||
|
bltFx.dwFillColor = fillColor;
|
||||||
|
g_transitionSurface->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &bltFx);
|
||||||
|
|
||||||
|
DDCOLORKEY key = {};
|
||||||
|
key.dwColorSpaceLowValue = key.dwColorSpaceHighValue = fillColor;
|
||||||
|
g_transitionSurface->SetColorKey(DDCKEY_SRCBLT, &key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run one tick of the animation
|
// Run one tick of the animation
|
||||||
@ -304,15 +389,18 @@ void MxTransitionManager::MosaicTransition()
|
|||||||
memset(&ddsd, 0, sizeof(ddsd));
|
memset(&ddsd, 0, sizeof(ddsd));
|
||||||
ddsd.dwSize = sizeof(ddsd);
|
ddsd.dwSize = sizeof(ddsd);
|
||||||
|
|
||||||
HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
|
HRESULT res = g_transitionSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
|
||||||
if (res == DDERR_SURFACELOST) {
|
if (res == DDERR_SURFACELOST) {
|
||||||
m_ddSurface->Restore();
|
g_transitionSurface->Restore();
|
||||||
res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
|
res = g_transitionSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res == DD_OK) {
|
if (res == DD_OK) {
|
||||||
SubmitCopyRect(&ddsd);
|
SubmitCopyRect(&ddsd);
|
||||||
|
|
||||||
|
// Combine xShift with this value to target the correct location in the buffer.
|
||||||
|
MxS32 bytesPerPixel = ddsd.ddpfPixelFormat.dwRGBBitCount / 8;
|
||||||
|
|
||||||
for (MxS32 col = 0; col < 64; col++) {
|
for (MxS32 col = 0; col < 64; col++) {
|
||||||
// Select 4 columns on each tick
|
// Select 4 columns on each tick
|
||||||
if (m_animationTimer * 4 > m_columnOrder[col]) {
|
if (m_animationTimer * 4 > m_columnOrder[col]) {
|
||||||
@ -324,69 +412,29 @@ void MxTransitionManager::MosaicTransition()
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (MxS32 row = 0; row < 48; row++) {
|
for (MxS32 row = 0; row < 48; row++) {
|
||||||
// To do the mosaic effect, we subdivide the 640x480 surface into
|
MxS32 x = (m_randomShift[row] + col) % 64;
|
||||||
// 10x10 pixel blocks. At the chosen block, we sample the top-leftmost
|
MxU8* dest = (MxU8*) ddsd.lpSurface + row * ddsd.lPitch + x * bytesPerPixel;
|
||||||
// color and set the other 99 pixels to that value.
|
|
||||||
|
|
||||||
// First, get the offset of the 10x10 block that we will sample for this row.
|
MxU32 source = g_colors[col][row];
|
||||||
MxS32 xShift = 10 * ((m_randomShift[row] + col) % 64);
|
|
||||||
|
|
||||||
// Combine xShift with this value to target the correct location in the buffer.
|
|
||||||
MxS32 bytesPerPixel = ddsd.ddpfPixelFormat.dwRGBBitCount / 8;
|
|
||||||
|
|
||||||
// Seek to the sample position.
|
|
||||||
MxU8* source = (MxU8*) ddsd.lpSurface + 10 * row * ddsd.lPitch + bytesPerPixel * xShift;
|
|
||||||
|
|
||||||
// Sample byte or word depending on display mode.
|
|
||||||
MxU32 sample;
|
|
||||||
switch (bytesPerPixel) {
|
switch (bytesPerPixel) {
|
||||||
case 1:
|
case 1:
|
||||||
sample = *source;
|
*dest = (MxU8) source;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
sample = *(MxU16*) source;
|
*((MxU16*) dest) = (MxU16) source;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sample = *(MxU32*) source;
|
*((MxU32*) dest) = source;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For each of the 10 rows in the 10x10 square:
|
|
||||||
for (MxS32 k = 10 * row; k < 10 * row + 10; k++) {
|
|
||||||
void* pos = (MxU8*) ddsd.lpSurface + k * ddsd.lPitch + bytesPerPixel * xShift;
|
|
||||||
|
|
||||||
switch (bytesPerPixel) {
|
|
||||||
case 1: {
|
|
||||||
// Optimization: If the pixel is only one byte, we can use memset
|
|
||||||
memset(pos, sample, 10);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 2: {
|
|
||||||
MxU16* p = (MxU16*) pos;
|
|
||||||
for (MxS32 tt = 0; tt < 10; tt++) {
|
|
||||||
p[tt] = (MxU16) sample;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
MxU32* p = (MxU32*) pos;
|
|
||||||
for (MxS32 tt = 0; tt < 10; tt++) {
|
|
||||||
p[tt] = (MxU32) sample;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SetupCopyRect(&ddsd);
|
SetupCopyRect(&ddsd);
|
||||||
m_ddSurface->Unlock(ddsd.lpSurface);
|
g_transitionSurface->Unlock(ddsd.lpSurface);
|
||||||
|
|
||||||
if (VideoManager()->GetVideoParam().Flags().GetFlipSurfaces()) {
|
RECT srcRect = {0, 0, 64, 48};
|
||||||
LPDIRECTDRAWSURFACE surf = VideoManager()->GetDisplaySurface()->GetDirectDrawSurface1();
|
m_ddSurface->Blt(&g_fullScreenRect, g_transitionSurface, &srcRect, DDBLT_WAIT | DDBLT_KEYSRC, NULL);
|
||||||
surf->BltFast(0, 0, m_ddSurface, &g_fullScreenRect, DDBLTFAST_WAIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_animationTimer++;
|
m_animationTimer++;
|
||||||
}
|
}
|
||||||
|
@ -162,9 +162,11 @@ ENABLE_BITMASK_OPERATORS(DDBltFastFlags)
|
|||||||
#define DDLOCK_SURFACEMEMORYPTR DDLockFlags::SURFACEMEMORYPTR
|
#define DDLOCK_SURFACEMEMORYPTR DDLockFlags::SURFACEMEMORYPTR
|
||||||
#define DDLOCK_WAIT DDLockFlags::WAIT
|
#define DDLOCK_WAIT DDLockFlags::WAIT
|
||||||
#define DDLOCK_WRITEONLY DDLockFlags::WRITEONLY
|
#define DDLOCK_WRITEONLY DDLockFlags::WRITEONLY
|
||||||
|
#define DDLOCK_READONLY DDLockFlags::READONLY
|
||||||
enum class DDLockFlags : uint32_t {
|
enum class DDLockFlags : uint32_t {
|
||||||
SURFACEMEMORYPTR = 0,
|
SURFACEMEMORYPTR = 0,
|
||||||
WAIT = 1 << 0,
|
WAIT = 1 << 0,
|
||||||
|
READONLY = 1 << 4,
|
||||||
WRITEONLY = 1 << 5,
|
WRITEONLY = 1 << 5,
|
||||||
};
|
};
|
||||||
ENABLE_BITMASK_OPERATORS(DDLockFlags)
|
ENABLE_BITMASK_OPERATORS(DDLockFlags)
|
||||||
|
@ -52,6 +52,24 @@ HRESULT DirectDrawSurfaceImpl::Blt(
|
|||||||
LPDDBLTFX lpDDBltFx
|
LPDDBLTFX lpDDBltFx
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
if ((dwFlags & DDBLT_COLORFILL) == DDBLT_COLORFILL) {
|
||||||
|
Uint8 a = (lpDDBltFx->dwFillColor >> 24) & 0xFF;
|
||||||
|
Uint8 r = (lpDDBltFx->dwFillColor >> 16) & 0xFF;
|
||||||
|
Uint8 g = (lpDDBltFx->dwFillColor >> 8) & 0xFF;
|
||||||
|
Uint8 b = lpDDBltFx->dwFillColor & 0xFF;
|
||||||
|
|
||||||
|
const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(m_surface->format);
|
||||||
|
Uint32 color = SDL_MapRGBA(details, nullptr, r, g, b, a);
|
||||||
|
if (lpDestRect) {
|
||||||
|
SDL_Rect dstRect = ConvertRect(lpDestRect);
|
||||||
|
SDL_FillSurfaceRect(m_surface, &dstRect, color);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SDL_FillSurfaceRect(m_surface, nullptr, color);
|
||||||
|
}
|
||||||
|
return DD_OK;
|
||||||
|
}
|
||||||
|
|
||||||
auto other = static_cast<DirectDrawSurfaceImpl*>(lpDDSrcSurface);
|
auto other = static_cast<DirectDrawSurfaceImpl*>(lpDDSrcSurface);
|
||||||
|
|
||||||
SDL_Rect srcRect = lpSrcRect ? ConvertRect(lpSrcRect) : SDL_Rect{0, 0, other->m_surface->w, other->m_surface->h};
|
SDL_Rect srcRect = lpSrcRect ? ConvertRect(lpSrcRect) : SDL_Rect{0, 0, other->m_surface->w, other->m_surface->h};
|
||||||
|
@ -171,6 +171,9 @@ HRESULT FrameBufferImpl::Lock(LPRECT lpDestRect, DDSURFACEDESC* lpDDSurfaceDesc,
|
|||||||
if (!DDRenderer) {
|
if (!DDRenderer) {
|
||||||
return DDERR_GENERIC;
|
return DDERR_GENERIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_readOnlyLock = (dwFlags & DDLOCK_READONLY) == DDLOCK_READONLY;
|
||||||
|
|
||||||
if ((dwFlags & DDLOCK_WRITEONLY) == DDLOCK_WRITEONLY) {
|
if ((dwFlags & DDLOCK_WRITEONLY) == DDLOCK_WRITEONLY) {
|
||||||
const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(m_transferBuffer->m_surface->format);
|
const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(m_transferBuffer->m_surface->format);
|
||||||
SDL_Palette* palette = m_palette ? static_cast<DirectDrawPaletteImpl*>(m_palette)->m_palette : nullptr;
|
SDL_Palette* palette = m_palette ? static_cast<DirectDrawPaletteImpl*>(m_palette)->m_palette : nullptr;
|
||||||
@ -223,7 +226,9 @@ HRESULT FrameBufferImpl::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette)
|
|||||||
HRESULT FrameBufferImpl::Unlock(LPVOID lpSurfaceData)
|
HRESULT FrameBufferImpl::Unlock(LPVOID lpSurfaceData)
|
||||||
{
|
{
|
||||||
m_transferBuffer->Unlock(lpSurfaceData);
|
m_transferBuffer->Unlock(lpSurfaceData);
|
||||||
BltFast(0, 0, m_transferBuffer, nullptr, DDBLTFAST_WAIT);
|
if (!m_readOnlyLock) {
|
||||||
|
BltFast(0, 0, m_transferBuffer, nullptr, DDBLTFAST_WAIT);
|
||||||
|
}
|
||||||
|
|
||||||
return DD_OK;
|
return DD_OK;
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ struct FrameBufferImpl : public IDirectDrawSurface3 {
|
|||||||
private:
|
private:
|
||||||
uint32_t m_virtualWidth;
|
uint32_t m_virtualWidth;
|
||||||
uint32_t m_virtualHeight;
|
uint32_t m_virtualHeight;
|
||||||
|
bool m_readOnlyLock;
|
||||||
DirectDrawSurfaceImpl* m_transferBuffer;
|
DirectDrawSurfaceImpl* m_transferBuffer;
|
||||||
IDirectDrawPalette* m_palette = nullptr;
|
IDirectDrawPalette* m_palette = nullptr;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user