diff --git a/LEGO1/lego/legoomni/src/video/legovideomanager.cpp b/LEGO1/lego/legoomni/src/video/legovideomanager.cpp index 7c5a2cbb..fcaada49 100644 --- a/LEGO1/lego/legoomni/src/video/legovideomanager.cpp +++ b/LEGO1/lego/legoomni/src/video/legovideomanager.cpp @@ -19,6 +19,8 @@ #include "tgl/d3drm/impl.h" #include "viewmanager/viewroi.h" +#include + DECOMP_SIZE_ASSERT(LegoVideoManager, 0x590) DECOMP_SIZE_ASSERT(MxStopWatch, 0x18) DECOMP_SIZE_ASSERT(MxFrequencyMeter, 0x20) @@ -390,10 +392,125 @@ inline void LegoVideoManager::DrawCursor() ->BltFast(m_cursorXCopy, m_cursorYCopy, m_cursorSurface, &m_cursorRect, DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY); } -// STUB: LEGO1 0x1007bbc0 +// FUNCTION: LEGO1 0x1007bbc0 void LegoVideoManager::DrawFPS() { - // TODO + char zeros[8] = "0000.00"; + + if (m_unk0x528 == NULL) { + m_arialFont = CreateFontA( + 12, + 0, + 0, + 0, + FW_NORMAL, + FALSE, + FALSE, + FALSE, + ANSI_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + FF_DONTCARE | VARIABLE_PITCH, + "Arial" + ); + + HDC dc = GetDC(NULL); + SelectObject(dc, m_arialFont); + GetTextExtentPointA(dc, zeros, strlen(zeros), &m_fpsSize); + ReleaseDC(NULL, dc); + + m_unk0x528 = m_displaySurface->FUN_100bc8b0(m_fpsSize.cx, m_fpsSize.cy); + SetRect(&m_fpsRect, 0, 0, m_fpsSize.cx, m_fpsSize.cy); + + if (m_unk0x528 == NULL) { + DeleteObject(m_arialFont); + m_arialFont = NULL; + return; + } + + DDCOLORKEY colorKey; + memset(&colorKey, 0, sizeof(colorKey)); + m_unk0x528->SetColorKey(DDCKEY_SRCBLT, &colorKey); + + DDSURFACEDESC surfaceDesc; + memset(&surfaceDesc, 0, sizeof(surfaceDesc)); + surfaceDesc.dwSize = sizeof(surfaceDesc); + + if (m_unk0x528->Lock(NULL, &surfaceDesc, DDLOCK_WAIT, NULL) != DD_OK) { + m_unk0x528->Release(); + DeleteObject(m_arialFont); + m_unk0x528 = NULL; + m_arialFont = NULL; + } + else { + DWORD i; + char* ptr = (char*) surfaceDesc.lpSurface; + + for (i = 0; i < surfaceDesc.dwHeight; i++) { + memset(ptr, 0, surfaceDesc.dwWidth * surfaceDesc.ddpfPixelFormat.dwRGBBitCount / 8); + ptr += surfaceDesc.lPitch; + } + + m_unk0x528->Unlock(surfaceDesc.lpSurface); + m_unk0x54c = Timer()->GetTime(); + m_unk0x550 = 1.f; + } + } + else { + if (Timer()->GetTime() > m_unk0x54c + 5000.f) { + char buffer[32]; + MxFloat time = (Timer()->GetTime() - m_unk0x54c) / 1000.0f; + MxS32 nb = sprintf(buffer, "%.02f", m_unk0x550 / time); + m_unk0x54c = Timer()->GetTime(); + + DDSURFACEDESC surfaceDesc; + memset(&surfaceDesc, 0, sizeof(surfaceDesc)); + surfaceDesc.dwSize = sizeof(surfaceDesc); + + if (m_unk0x528->Lock(NULL, &surfaceDesc, DDLOCK_WAIT, NULL) == DD_OK) { + DWORD i; + char* ptr = (char*) surfaceDesc.lpSurface; + + for (i = 0; i < surfaceDesc.dwHeight; i++) { + memset(ptr, 0, surfaceDesc.dwWidth * surfaceDesc.ddpfPixelFormat.dwRGBBitCount / 8); + ptr += surfaceDesc.lPitch; + } + + m_unk0x528->Unlock(surfaceDesc.lpSurface); + } + + HDC dc; + if (m_unk0x528->GetDC(&dc) != DD_OK) { + m_unk0x528->Release(); + m_unk0x528 = NULL; + DeleteObject(m_arialFont); + m_arialFont = NULL; + return; + } + + SelectObject(dc, m_arialFont); + SetTextColor(dc, RGB(255, 255, 0)); + SetBkColor(dc, RGB(0, 0, 0)); + SetBkMode(dc, OPAQUE); + GetTextExtentPoint32A(dc, buffer, nb, &m_fpsSize); + + RECT rect; + SetRect(&rect, 0, 0, m_fpsSize.cx, m_fpsSize.cy); + ExtTextOutA(dc, 0, 0, ETO_OPAQUE, &rect, buffer, nb, NULL); + m_unk0x528->ReleaseDC(dc); + m_unk0x550 = 1.f; + } + else { + m_unk0x550 += 1.f; + } + + if (m_unk0x528 != NULL) { + m_displaySurface->GetDirectDrawSurface2() + ->BltFast(20, 20, m_unk0x528, &m_fpsRect, DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY); + m_3dManager->GetLego3DView()->GetView()->ForceUpdate(20, 20, m_fpsRect.right, m_fpsRect.bottom); + } + } } // FUNCTION: LEGO1 0x1007c080 @@ -531,7 +648,7 @@ void LegoVideoManager::SetSkyColor(float p_red, float p_green, float p_blue) // FUNCTION: LEGO1 0x1007c4c0 void LegoVideoManager::OverrideSkyColor(MxBool p_shouldOverride) { - this->m_videoParam.GetPalette()->SetOverrideSkyColor(p_shouldOverride); + m_videoParam.GetPalette()->SetOverrideSkyColor(p_shouldOverride); } // FUNCTION: LEGO1 0x1007c4d0 diff --git a/LEGO1/omni/include/mxdisplaysurface.h b/LEGO1/omni/include/mxdisplaysurface.h index 3c2c83a7..43606bd0 100644 --- a/LEGO1/omni/include/mxdisplaysurface.h +++ b/LEGO1/omni/include/mxdisplaysurface.h @@ -109,6 +109,8 @@ public: MxU8 p_bpp ); + LPDIRECTDRAWSURFACE FUN_100bc8b0(MxS32 width, MxS32 height); + private: MxU8 CountTotalBitsSetTo1(MxU32 p_param); MxU8 CountContiguousBitsSetTo1(MxU32 p_param); diff --git a/LEGO1/omni/src/video/mxdisplaysurface.cpp b/LEGO1/omni/src/video/mxdisplaysurface.cpp index 3a301af1..647de44a 100644 --- a/LEGO1/omni/src/video/mxdisplaysurface.cpp +++ b/LEGO1/omni/src/video/mxdisplaysurface.cpp @@ -1092,3 +1092,39 @@ MxBool MxDisplaySurface::VTable0x2c( { return 0; } + +// FUNCTION: LEGO1 0x100bc8b0 +LPDIRECTDRAWSURFACE MxDisplaySurface::FUN_100bc8b0(MxS32 width, MxS32 height) +{ + LPDIRECTDRAWSURFACE surface = NULL; + + LPDIRECTDRAW ddraw = MVideoManager()->GetDirectDraw(); + MxVideoParam& unused = MVideoManager()->GetVideoParam(); + + DDSURFACEDESC surfaceDesc; + memset(&surfaceDesc, 0, sizeof(surfaceDesc)); + surfaceDesc.dwSize = sizeof(surfaceDesc); + + if (ddraw->GetDisplayMode(&surfaceDesc) != DD_OK) { + return NULL; + } + + if (surfaceDesc.ddpfPixelFormat.dwRGBBitCount != 16) { + return NULL; + } + + surfaceDesc.dwWidth = width; + surfaceDesc.dwHeight = height; + surfaceDesc.dwFlags = DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; + surfaceDesc.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN; + + if (ddraw->CreateSurface(&surfaceDesc, &surface, NULL) != DD_OK) { + surfaceDesc.ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY; + surfaceDesc.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; + if (ddraw->CreateSurface(&surfaceDesc, &surface, NULL) != DD_OK) { + return NULL; + } + } + + return surface; +}