De-duplicate surface blitting

This commit is contained in:
Anders Jenbo 2025-08-21 00:09:31 +02:00
parent 12cad70d94
commit d054cc8660
5 changed files with 36 additions and 501 deletions

View File

@ -69,9 +69,6 @@ class MxTransitionManager : public MxCore {
void WindowsTransition();
void BrokenTransition();
void SubmitCopyRect(LPDDSURFACEDESC p_ddsc);
void SetupCopyRect(LPDDSURFACEDESC p_ddsc);
MxVideoPresenter* m_waitIndicator; // 0x08
RECT m_copyRect; // 0x0c
MxU8* m_copyBuffer; // 0x1c

View File

@ -220,8 +220,6 @@ void MxTransitionManager::DissolveTransition()
}
if (res == DD_OK) {
SubmitCopyRect(&ddsd);
for (MxS32 col = 0; col < 640; col++) {
// Select 16 columns on each tick
if (m_animationTimer * 16 > m_columnOrder[col]) {
@ -254,7 +252,6 @@ void MxTransitionManager::DissolveTransition()
}
}
SetupCopyRect(&ddsd);
m_ddSurface->Unlock(ddsd.lpSurface);
if (VideoManager()->GetVideoParam().Flags().GetFlipSurfaces()) {
@ -394,8 +391,6 @@ void MxTransitionManager::MosaicTransition()
}
if (res == DD_OK) {
SubmitCopyRect(&ddsd);
// Combine xShift with this value to target the correct location in the buffer.
MxS32 bytesPerPixel = ddsd.ddpfPixelFormat.dwRGBBitCount / 8;
@ -428,7 +423,6 @@ void MxTransitionManager::MosaicTransition()
}
}
SetupCopyRect(&ddsd);
g_transitionSurface->Unlock(ddsd.lpSurface);
RECT srcRect = {0, 0, 64, 48};
@ -515,8 +509,6 @@ void MxTransitionManager::BrokenTransition()
}
if (res == DD_OK) {
SubmitCopyRect(&ddsd);
SetupCopyRect(&ddsd);
m_ddSurface->Unlock(ddsd.lpSurface);
}
}
@ -549,113 +541,6 @@ void MxTransitionManager::SetWaitIndicator(MxVideoPresenter* p_waitIndicator)
}
}
// FUNCTION: LEGO1 0x1004c4d0
void MxTransitionManager::SubmitCopyRect(LPDDSURFACEDESC p_ddsc)
{
// Check if the copy rect is setup
if (m_copyFlags.m_bit0 == FALSE || m_waitIndicator == NULL || m_copyBuffer == NULL) {
return;
}
// Copy the copy rect onto the surface
MxU8* dst;
MxU32 bytesPerPixel = p_ddsc->ddpfPixelFormat.dwRGBBitCount / 8;
const MxU8* src = (const MxU8*) m_copyBuffer;
MxS32 copyPitch;
copyPitch = ((m_copyRect.right - m_copyRect.left) + 1) * bytesPerPixel;
MxS32 y;
dst = (MxU8*) p_ddsc->lpSurface + (p_ddsc->lPitch * m_copyRect.top) + (bytesPerPixel * m_copyRect.left);
for (y = 0; y < m_copyRect.bottom - m_copyRect.top + 1; ++y) {
memcpy(dst, src, copyPitch);
src += copyPitch;
dst += p_ddsc->lPitch;
}
// Free the copy buffer
delete[] m_copyBuffer;
m_copyBuffer = NULL;
}
// FUNCTION: LEGO1 0x1004c580
void MxTransitionManager::SetupCopyRect(LPDDSURFACEDESC p_ddsc)
{
// Check if the copy rect is setup
if (m_copyFlags.m_bit0 == FALSE || m_waitIndicator == NULL) {
return;
}
// Tickle wait indicator
m_waitIndicator->Tickle();
// Check if wait indicator has started
if (m_waitIndicator->GetCurrentTickleState() >= MxPresenter::e_streaming) {
// Setup the copy rect
MxU32 copyPitch = (p_ddsc->ddpfPixelFormat.dwRGBBitCount / 8) *
(m_copyRect.right - m_copyRect.left + 1); // This uses m_copyRect, seemingly erroneously
MxU32 bytesPerPixel = p_ddsc->ddpfPixelFormat.dwRGBBitCount / 8;
m_copyRect.left = m_waitIndicator->GetLocation().GetX();
m_copyRect.top = m_waitIndicator->GetLocation().GetY();
MxS32 height = m_waitIndicator->GetHeight();
MxS32 width = m_waitIndicator->GetWidth();
m_copyRect.right = m_copyRect.left + width - 1;
m_copyRect.bottom = m_copyRect.top + height - 1;
// Allocate the copy buffer
const MxU8* src =
(const MxU8*) p_ddsc->lpSurface + m_copyRect.top * p_ddsc->lPitch + bytesPerPixel * m_copyRect.left;
m_copyBuffer = new MxU8[bytesPerPixel * width * height];
if (!m_copyBuffer) {
return;
}
// Copy into the copy buffer
MxU8* dst = m_copyBuffer;
for (MxS32 i = 0; i < (m_copyRect.bottom - m_copyRect.top + 1); i++) {
memcpy(dst, src, copyPitch);
src += p_ddsc->lPitch;
dst += copyPitch;
}
}
// Setup display surface
if ((m_waitIndicator->GetAction()->GetFlags() & MxDSAction::c_bit5) != 0) {
MxDisplaySurface* displaySurface = VideoManager()->GetDisplaySurface();
displaySurface->VTable0x2c(
p_ddsc,
m_waitIndicator->GetBitmap(),
0,
0,
m_waitIndicator->GetLocation().GetX(),
m_waitIndicator->GetLocation().GetY(),
m_waitIndicator->GetWidth(),
m_waitIndicator->GetHeight()
);
}
else {
MxDisplaySurface* displaySurface = VideoManager()->GetDisplaySurface();
displaySurface->VTable0x24(
p_ddsc,
m_waitIndicator->GetBitmap(),
0,
0,
m_waitIndicator->GetLocation().GetX(),
m_waitIndicator->GetLocation().GetY(),
m_waitIndicator->GetWidth(),
m_waitIndicator->GetHeight()
);
}
}
void MxTransitionManager::configureMxTransitionManager(TransitionType p_transitionManagerConfig)
{
g_transitionManagerConfig = p_transitionManagerConfig;

View File

@ -34,16 +34,6 @@ class MxDisplaySurface : public MxCore {
virtual MxResult Create(MxVideoParam& p_videoParam); // vtable+0x18
virtual void Destroy(); // vtable+0x1c
virtual void SetPalette(MxPalette* p_palette); // vtable+0x20
virtual void VTable0x24(
LPDDSURFACEDESC p_desc,
MxBitmap* p_bitmap,
MxS32 p_left,
MxS32 p_top,
MxS32 p_right,
MxS32 p_bottom,
MxS32 p_width,
MxS32 p_height
); // vtable+0x24
virtual void VTable0x28(
MxBitmap* p_bitmap,
MxS32 p_left,
@ -53,25 +43,6 @@ class MxDisplaySurface : public MxCore {
MxS32 p_width,
MxS32 p_height
); // vtable+0x28
virtual void VTable0x2c(
LPDDSURFACEDESC p_desc,
MxBitmap* p_bitmap,
MxS32 p_left,
MxS32 p_top,
MxS32 p_right,
MxS32 p_bottom,
MxS32 p_width,
MxS32 p_height
); // vtable+0x2c
virtual void VTable0x30(
MxBitmap* p_bitmap,
MxS32 p_left,
MxS32 p_top,
MxS32 p_right,
MxS32 p_bottom,
MxS32 p_width,
MxS32 p_height
); // vtable+0x30
virtual void Display(
MxS32 p_left,
MxS32 p_top,

View File

@ -434,7 +434,7 @@ void MxDisplaySurface::VTable0x28(
MxBITMAPINFO* bmi = p_bitmap->GetBitmapInfo();
if (bmi) {
PALETTEENTRY pe[256];
for (int i = 0; i < 256; i++) {
for (int i = 1; i < 256; i++) {
pe[i].peRed = bmi->m_bmiColors[i].rgbRed;
pe[i].peGreen = bmi->m_bmiColors[i].rgbGreen;
pe[i].peBlue = bmi->m_bmiColors[i].rgbBlue;
@ -447,18 +447,13 @@ void MxDisplaySurface::VTable0x28(
palette->Release();
}
}
#else
if (m_surfaceDesc.ddpfPixelFormat.dwRGBBitCount != 32) {
#endif
if (ddsd.ddpfPixelFormat.dwRGBBitCount != 32) {
DDCOLORKEY colorKey;
if (m_surfaceDesc.ddpfPixelFormat.dwRGBBitCount == 8) {
colorKey.dwColorSpaceLowValue = colorKey.dwColorSpaceHighValue = 0x10;
}
else {
colorKey.dwColorSpaceLowValue = colorKey.dwColorSpaceHighValue = RGB555_CREATE(0x1f, 0, 0x1f);
}
colorKey.dwColorSpaceLowValue = colorKey.dwColorSpaceHighValue = 0;
tempSurface->SetColorKey(DDCKEY_SRCBLT, &colorKey);
}
#endif
DDSURFACEDESC tempDesc;
memset(&tempDesc, 0, sizeof(tempDesc));
@ -480,31 +475,29 @@ void MxDisplaySurface::VTable0x28(
MxS32 bytesPerPixel = tempDesc.ddpfPixelFormat.dwRGBBitCount / 8;
MxU8* surface = (MxU8*) tempDesc.lpSurface;
MxLong stride = (bytesPerPixel == 1) ? GetAdjustedStride(p_bitmap) : -p_width + GetAdjustedStride(p_bitmap);
MxLong stride = -p_width + GetAdjustedStride(p_bitmap);
MxLong length = tempDesc.lPitch - (p_width * bytesPerPixel);
for (MxS32 i = 0; i < p_height; i++) {
if (bytesPerPixel == 1) {
memcpy(surface, data, p_width);
surface += length + p_width;
}
else if (bytesPerPixel == 2) {
for (MxS32 j = 0; j < p_width; j++) {
*(MxU16*) surface = m_16bitPal[*data++];
surface += bytesPerPixel;
}
surface += length;
data += p_width + stride;
}
else {
for (MxS32 j = 0; j < p_width; j++) {
*(MxU32*) surface = m_32bitPal[*data++];
if (bytesPerPixel == 2) {
*(MxU16*) surface = m_16bitPal[*data];
}
else if (*data != 0) {
*(MxU32*) surface = m_32bitPal[*data];
}
data++;
surface += bytesPerPixel;
}
data += stride;
surface += length;
}
data += stride;
}
tempSurface->Unlock(NULL);
@ -520,122 +513,6 @@ void MxDisplaySurface::VTable0x28(
tempSurface->Release();
}
// FUNCTION: LEGO1 0x100bb1d0
// FUNCTION: BETA10 0x1014088e
void MxDisplaySurface::VTable0x30(
MxBitmap* p_bitmap,
MxS32 p_left,
MxS32 p_top,
MxS32 p_right,
MxS32 p_bottom,
MxS32 p_width,
MxS32 p_height
)
{
if (!GetRectIntersection(
p_bitmap->GetBmiWidth(),
p_bitmap->GetBmiHeightAbs(),
m_videoParam.GetRect().GetWidth(),
m_videoParam.GetRect().GetHeight(),
&p_left,
&p_top,
&p_right,
&p_bottom,
&p_width,
&p_height
)) {
return;
}
DDSURFACEDESC ddsd;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS;
ddsd.dwWidth = p_width;
ddsd.dwHeight = p_height;
#ifdef MINIWIN
ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
ddsd.ddpfPixelFormat.dwFlags = DDPF_PALETTEINDEXED8 | DDPF_RGB;
ddsd.ddpfPixelFormat.dwRGBBitCount = 8;
#else
ddsd.ddpfPixelFormat = m_surfaceDesc.ddpfPixelFormat;
#endif
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
LPDIRECTDRAW draw = MVideoManager()->GetDirectDraw();
LPDIRECTDRAWSURFACE tempSurface = nullptr;
if (draw->CreateSurface(&ddsd, &tempSurface, nullptr) != DD_OK || !tempSurface) {
return;
}
#ifdef MINIWIN
MxBITMAPINFO* bmi = p_bitmap->GetBitmapInfo();
if (bmi) {
PALETTEENTRY pe[256];
for (int i = 0; i < 256; i++) {
pe[i].peRed = bmi->m_bmiColors[i].rgbRed;
pe[i].peGreen = bmi->m_bmiColors[i].rgbGreen;
pe[i].peBlue = bmi->m_bmiColors[i].rgbBlue;
pe[i].peFlags = PC_NONE;
}
LPDIRECTDRAWPALETTE palette = nullptr;
if (draw->CreatePalette(DDPCAPS_8BIT | DDPCAPS_ALLOW256, pe, &palette, NULL) == DD_OK && palette) {
tempSurface->SetPalette(palette);
palette->Release();
}
}
#endif
DDCOLORKEY colorKey;
colorKey.dwColorSpaceLowValue = colorKey.dwColorSpaceHighValue = 0;
tempSurface->SetColorKey(DDCKEY_SRCBLT, &colorKey);
DDSURFACEDESC tempDesc;
memset(&tempDesc, 0, sizeof(tempDesc));
tempDesc.dwSize = sizeof(tempDesc);
if (tempSurface->Lock(NULL, &tempDesc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) != DD_OK) {
tempSurface->Release();
return;
}
MxU8* data = p_bitmap->GetStart(p_left, p_top);
MxS32 bytesPerPixel = tempDesc.ddpfPixelFormat.dwRGBBitCount / 8;
MxU8* surface = (MxU8*) tempDesc.lpSurface;
MxLong stride = -p_width + GetAdjustedStride(p_bitmap);
MxLong length = -bytesPerPixel * p_width + tempDesc.lPitch;
for (MxS32 i = 0; i < p_height; i++) {
for (MxS32 j = 0; j < p_width; j++) {
if (*data != 0) {
switch (bytesPerPixel) {
case 1:
*surface = *data;
break;
case 2:
*(MxU16*) surface = m_16bitPal[*data];
break;
default:
*(MxU32*) surface = m_32bitPal[*data];
break;
}
}
data++;
surface += bytesPerPixel;
}
data += stride;
surface += length;
}
tempSurface->Unlock(NULL);
m_ddSurface2->BltFast(p_right, p_bottom, tempSurface, NULL, DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY);
tempSurface->Release();
}
// FUNCTION: LEGO1 0x100bba50
void MxDisplaySurface::Display(MxS32 p_left, MxS32 p_top, MxS32 p_left2, MxS32 p_top2, MxS32 p_width, MxS32 p_height)
{
@ -758,6 +635,11 @@ LPDIRECTDRAWSURFACE MxDisplaySurface::VTable0x44(
pe[i].peBlue = bmi->m_bmiColors[i].rgbBlue;
pe[i].peFlags = PC_NONE;
}
if (p_transparent) {
pe[0].peRed = 0;
pe[0].peGreen = 0;
pe[0].peBlue = 0;
}
LPDIRECTDRAWPALETTE palette = nullptr;
if (draw->CreatePalette(DDPCAPS_8BIT | DDPCAPS_ALLOW256, pe, &palette, NULL) == DD_OK && palette) {
surface->SetPalette(palette);
@ -910,158 +792,6 @@ LPDIRECTDRAWSURFACE MxDisplaySurface::CopySurface(LPDIRECTDRAWSURFACE p_src)
return newSurface;
}
// FUNCTION: LEGO1 0x100bc200
void MxDisplaySurface::VTable0x24(
LPDDSURFACEDESC p_desc,
MxBitmap* p_bitmap,
MxS32 p_left,
MxS32 p_top,
MxS32 p_right,
MxS32 p_bottom,
MxS32 p_width,
MxS32 p_height
)
{
// DECOMP: Almost an exact copy of VTable0x28, except that it uses the argument DDSURFACEDESC
// instead of getting one from GetDisplayMode.
if (!GetRectIntersection(
p_bitmap->GetBmiWidth(),
p_bitmap->GetBmiHeightAbs(),
m_videoParam.GetRect().GetWidth(),
m_videoParam.GetRect().GetHeight(),
&p_left,
&p_top,
&p_right,
&p_bottom,
&p_width,
&p_height
)) {
return;
}
MxU8* data = p_bitmap->GetStart(p_left, p_top);
if (m_videoParam.Flags().GetDoubleScaling()) {
p_bottom *= 2;
p_right *= 2;
MxS32 bytesPerPixel = m_surfaceDesc.ddpfPixelFormat.dwRGBBitCount / 8;
MxU8* surface = (MxU8*) p_desc->lpSurface + bytesPerPixel * p_right + (p_bottom * p_desc->lPitch);
MxLong srcSkip = GetAdjustedStride(p_bitmap) - p_width;
MxLong destSkip = p_desc->lPitch - 2 * bytesPerPixel * p_width;
MxS32 copyWidth = 2 * bytesPerPixel * p_width;
while (p_height--) {
MxU8* surfaceBefore = surface;
for (MxS32 x = 0; x < p_width; x++) {
if (bytesPerPixel == 1) {
surface[0] = surface[1] = *data;
}
else if (bytesPerPixel == 2) {
MxU16 val = m_16bitPal[*data];
((MxU16*) surface)[0] = ((MxU16*) surface)[1] = val;
}
else {
MxU32 val = m_32bitPal[*data];
((MxU32*) surface)[0] = ((MxU32*) surface)[1] = val;
}
surface += bytesPerPixel * 2;
data++;
}
data += srcSkip;
surface += destSkip;
memcpy(surface, surfaceBefore, copyWidth);
surface += p_desc->lPitch;
}
}
else {
MxS32 bytesPerPixel = m_surfaceDesc.ddpfPixelFormat.dwRGBBitCount / 8;
MxU8* surface = (MxU8*) p_desc->lpSurface + bytesPerPixel * p_right + (p_bottom * p_desc->lPitch);
MxLong srcSkip = GetAdjustedStride(p_bitmap) - p_width;
MxLong destSkip = p_desc->lPitch - bytesPerPixel * p_width;
for (MxS32 y = 0; y < p_height; y++) {
for (MxS32 x = 0; x < p_width; x++) {
if (bytesPerPixel == 1) {
*surface = *data++;
}
else if (bytesPerPixel == 2) {
*(MxU16*) surface = m_16bitPal[*data++];
}
else {
*(MxU32*) surface = m_32bitPal[*data++];
}
surface += bytesPerPixel;
}
data += srcSkip;
surface += destSkip;
}
}
}
// FUNCTION: LEGO1 0x100bc630
void MxDisplaySurface::VTable0x2c(
LPDDSURFACEDESC p_desc,
MxBitmap* p_bitmap,
MxS32 p_left,
MxS32 p_top,
MxS32 p_right,
MxS32 p_bottom,
MxS32 p_width,
MxS32 p_height
)
{
// DECOMP: Almost an exact copy of VTable0x28, except that it uses the argument DDSURFACEDESC
// instead of getting one from GetDisplayMode.
if (!GetRectIntersection(
p_bitmap->GetBmiWidth(),
p_bitmap->GetBmiHeightAbs(),
m_videoParam.GetRect().GetWidth(),
m_videoParam.GetRect().GetHeight(),
&p_left,
&p_top,
&p_right,
&p_bottom,
&p_width,
&p_height
)) {
return;
}
MxU8* src = p_bitmap->GetStart(p_left, p_top);
MxS32 bytesPerPixel = m_surfaceDesc.ddpfPixelFormat.dwRGBBitCount / 8;
MxLong destStride = p_desc->lPitch;
MxU8* dest = (MxU8*) p_desc->lpSurface + bytesPerPixel * p_right + (p_bottom * destStride);
MxLong srcStride = GetAdjustedStride(p_bitmap);
MxLong srcSkip = srcStride - p_width;
MxLong destSkip = destStride - bytesPerPixel * p_width;
for (MxS32 i = 0; i < p_height; i++, src += srcSkip, dest += destSkip) {
for (MxS32 j = 0; j < p_width; j++, src++) {
if (*src != 0) {
switch (bytesPerPixel) {
case 1:
*dest = *src;
break;
case 2:
*(MxU16*) dest = m_16bitPal[*src];
break;
default:
*(MxU32*) dest = m_32bitPal[*src];
break;
}
}
dest += bytesPerPixel;
}
}
}
// FUNCTION: LEGO1 0x100bc8b0
LPDIRECTDRAWSURFACE MxDisplaySurface::FUN_100bc8b0(MxS32 p_width, MxS32 p_height)
{

View File

@ -219,77 +219,29 @@ inline MxS32 MxVideoPresenter::PrepareRects(RECT& p_rectDest, RECT& p_rectSrc)
void MxVideoPresenter::PutFrame()
{
MxDisplaySurface* displaySurface = MVideoManager()->GetDisplaySurface();
MxRegion* region = MVideoManager()->GetRegion();
MxRect32 rect(MxPoint32(0, 0), MxSize32(GetWidth(), GetHeight()));
rect += GetLocation();
LPDIRECTDRAWSURFACE ddSurface = displaySurface->GetDirectDrawSurface2();
if (m_action->GetFlags() & MxDSAction::c_bit5) {
if (m_surface) {
RECT src, dest;
src.top = 0;
src.left = 0;
src.right = GetWidth();
src.bottom = GetHeight();
RECT src, dest;
dest.left = GetX();
dest.top = GetY();
dest.right = dest.left + GetWidth();
dest.bottom = dest.top + GetHeight();
if (m_surface) {
src.left = 0;
src.top = 0;
src.right = GetWidth();
src.bottom = GetHeight();
switch (PrepareRects(src, dest)) {
case 0:
ddSurface->Blt(&dest, m_surface, &src, DDBLT_KEYSRC, NULL);
break;
case 1:
ddSurface->BltFast(dest.left, dest.top, m_surface, &src, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT);
}
}
else {
displaySurface->VTable0x30(
m_frameBitmap,
0,
0,
rect.GetLeft(),
rect.GetTop(),
m_frameBitmap->GetBmiWidth(),
m_frameBitmap->GetBmiHeightAbs()
);
dest.left = GetX();
dest.top = GetY();
dest.right = dest.left + GetWidth();
dest.bottom = dest.top + GetHeight();
}
if (m_surface) {
if (PrepareRects(src, dest) >= 0) {
ddSurface->Blt(&dest, m_surface, &src, DDBLT_KEYSRC, NULL);
}
}
else {
RECT src, dest;
if (m_surface) {
src.left = 0;
src.top = 0;
src.right = GetWidth();
src.bottom = GetHeight();
dest.left = GetX();
dest.top = GetY();
dest.right = dest.left + GetWidth();
dest.bottom = dest.top + GetHeight();
}
if (m_action->GetFlags() & MxDSAction::c_bit4) {
if (m_surface) {
if (PrepareRects(src, dest) >= 0) {
ddSurface->Blt(&dest, m_surface, &src, DDBLT_KEYSRC, NULL);
}
}
else {
displaySurface->VTable0x30(m_frameBitmap, 0, 0, GetX(), GetY(), GetWidth(), GetHeight());
}
}
else if (m_surface) {
if (PrepareRects(src, dest) >= 0) {
ddSurface->Blt(&dest, m_surface, &src, DDBLT_NONE, NULL);
}
}
else {
displaySurface->VTable0x28(m_frameBitmap, 0, 0, GetX(), GetY(), GetWidth(), GetHeight());
}
displaySurface->VTable0x28(m_frameBitmap, 0, 0, GetX(), GetY(), GetWidth(), GetHeight());
}
}