Merge into vtable branch (#3)

* Implement MxDisplaySurface::VTable0x44 (#467)

* Update mxdisplaysurface.cpp

* add arguments to header

* Fix glitched bitmaps

* WIP fixes

* Match

* Fix

* Changes

* Fixes

---------

Co-authored-by: Christian Semmler <mail@csemmler.com>

* Implmement PoliceState::VTable0x1c (#468)

* Implmement PoliceState::VTable0x1c

* Fixes

---------

Co-authored-by: Christian Semmler <mail@csemmler.com>

* Implement Lego3DView::Render (#470)

* Implement Lego3DView::Render

* use MxDouble

* Revert "use MxDouble"

This reverts commit a006b60e20.

* Begin work on Police class (#469)

* Begin work on Police class

* Use JukeBox::e_policeStation value

* Fixes

---------

Co-authored-by: Christian Semmler <mail@csemmler.com>

* Implement MxDisplaySurface::CreateCursorSurface (#471)

* Update mxdisplaysurface.cpp

* Fixes

* Update legovideomanager.cpp

* Match to 100%

---------

Co-authored-by: Christian Semmler <mail@csemmler.com>

---------

Co-authored-by: Misha <106913236+MishaProductions@users.noreply.github.com>
Co-authored-by: Christian Semmler <mail@csemmler.com>
Co-authored-by: Joshua Peisach <itzswirlz2020@outlook.com>
This commit is contained in:
MS 2024-01-20 16:50:43 -05:00 committed by GitHub
parent 966b24abf3
commit f084f280ca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 347 additions and 72 deletions

View File

@ -72,8 +72,8 @@ class LegoVideoManager : public MxVideoManager {
MxS32 m_cursorYCopy; // 0x508 MxS32 m_cursorYCopy; // 0x508
MxS32 m_cursorX; // 0x50c MxS32 m_cursorX; // 0x50c
MxS32 m_cursorY; // 0x510 MxS32 m_cursorY; // 0x510
LPDIRECTDRAWSURFACE m_unk0x514; // 0x514 LPDIRECTDRAWSURFACE m_cursorSurface; // 0x514
RECT m_unk0x518; // 0x518 RECT m_cursorRect; // 0x518
undefined4 m_unk0x528; // 0x528 undefined4 m_unk0x528; // 0x528
MxBool m_drawFPS; // 0x52c MxBool m_drawFPS; // 0x52c
RECT m_fpsRect; // 0x530 RECT m_fpsRect; // 0x530

View File

@ -1,7 +1,11 @@
#ifndef POLICE_H #ifndef POLICE_H
#define POLICE_H #define POLICE_H
#include "decomp.h"
#include "legoworld.h" #include "legoworld.h"
#include "mxdsaction.h"
#include "policestate.h"
#include "radio.h"
// VTABLE: LEGO1 0x100d8a80 // VTABLE: LEGO1 0x100d8a80
// SIZE 0x110 // SIZE 0x110
@ -34,6 +38,14 @@ class Police : public LegoWorld {
// SYNTHETIC: LEGO1 0x1005e300 // SYNTHETIC: LEGO1 0x1005e300
// Police::`scalar deleting destructor' // Police::`scalar deleting destructor'
virtual MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18
virtual void VTable0x50() override; // vtable+0x50
private:
Radio m_radio; // 0xf8
PoliceState* m_policeState; // 0x108
undefined4 m_unk0x10c; // 0x10c
}; };
#endif // POLICE_H #endif // POLICE_H

View File

@ -28,6 +28,8 @@ class PoliceState : public LegoState {
// SYNTHETIC: LEGO1 0x1005e920 // SYNTHETIC: LEGO1 0x1005e920
// PoliceState::`scalar deleting destructor' // PoliceState::`scalar deleting destructor'
virtual MxResult VTable0x1c(LegoFileStream* p_legoFileStream) override; // vtable+0x1C
private: private:
undefined4 m_unk0x8; // 0x8 undefined4 m_unk0x8; // 0x8
undefined4 m_unk0xc; // 0xc undefined4 m_unk0xc; // 0xc

View File

@ -1,9 +1,20 @@
#include "police.h" #include "police.h"
// STUB: LEGO1 0x1005e130 #include "jukebox.h"
#include "legocontrolmanager.h"
#include "legogamestate.h"
#include "legoinputmanager.h"
#include "legoomni.h"
#include "mxnotificationmanager.h"
DECOMP_SIZE_ASSERT(Police, 0x110)
// FUNCTION: LEGO1 0x1005e130
Police::Police() Police::Police()
{ {
// TODO m_policeState = NULL;
m_unk0x10c = 0;
NotificationManager()->Register(this);
} }
// STUB: LEGO1 0x1005e1d0 // STUB: LEGO1 0x1005e1d0
@ -13,10 +24,40 @@ MxBool Police::VTable0x5c()
return FALSE; return FALSE;
} }
// STUB: LEGO1 0x1005e320 // FUNCTION: LEGO1 0x1005e320
Police::~Police() Police::~Police()
{ {
// TODO if (InputManager()->GetWorld() == this) {
InputManager()->ClearWorld();
}
ControlManager()->Unregister(this);
InputManager()->UnRegister(this);
NotificationManager()->Unregister(this);
}
// FUNCTION: LEGO1 0x1005e3e0
MxResult Police::Create(MxDSAction& p_dsAction)
{
MxResult ret = LegoWorld::Create(p_dsAction);
if (ret == SUCCESS) {
InputManager()->SetWorld(this);
ControlManager()->Register(this);
}
SetIsWorldActive(FALSE);
InputManager()->Register(this);
LegoGameState* gameState = GameState();
PoliceState* policeState = (PoliceState*) gameState->GetState("PoliceState");
if (!policeState) {
policeState = (PoliceState*) gameState->CreateState("PoliceState");
}
m_policeState = policeState;
GameState()->SetUnknown424(0x22);
GameState()->FUN_1003a720(0);
return ret;
} }
// STUB: LEGO1 0x1005e3e0 // STUB: LEGO1 0x1005e3e0
@ -34,10 +75,12 @@ MxLong Police::Notify(MxParam& p_param)
return 0; return 0;
} }
// STUB: LEGO1 0x1005e530 // FUNCTION: LEGO1 0x1005e530
void Police::VTable0x50() void Police::VTable0x50()
{ {
// TODO LegoWorld::VTable0x50();
PlayMusic(JukeBox::e_policeStation);
FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen);
} }
// STUB: LEGO1 0x1005e740 // STUB: LEGO1 0x1005e740

View File

@ -11,9 +11,20 @@ PoliceState::PoliceState()
m_unk0x8 = (rand() % 2 == 0) ? 501 : 500; m_unk0x8 = (rand() % 2 == 0) ? 501 : 500;
} }
// STUB: LEGO1 0x1005e990 // FUNCTION: LEGO1 0x1005e990
MxResult PoliceState::VTable0x1c(LegoFileStream* p_legoFileStream) MxResult PoliceState::VTable0x1c(LegoFileStream* p_legoFileStream)
{ {
// TODO if (p_legoFileStream->IsWriteMode()) {
p_legoFileStream->FUN_10006030(ClassName());
}
if (p_legoFileStream->IsReadMode()) {
p_legoFileStream->Read(&m_unk0x8, sizeof(m_unk0x8));
}
else {
undefined4 unk0x8 = m_unk0x8;
p_legoFileStream->Write(&unk0x8, sizeof(m_unk0x8));
}
return SUCCESS; return SUCCESS;
} }

View File

@ -28,18 +28,6 @@ MxResult TowTrackMissionState::VTable0x1c(LegoFileStream* p_legoFileStream)
} }
if (p_legoFileStream->IsReadMode()) { if (p_legoFileStream->IsReadMode()) {
p_legoFileStream->Write(&m_unk0x12, sizeof(MxU16));
p_legoFileStream->Write(&m_unk0x14, sizeof(MxU16));
p_legoFileStream->Write(&m_unk0x16, sizeof(MxU16));
p_legoFileStream->Write(&m_unk0x18, sizeof(MxU16));
p_legoFileStream->Write(&m_unk0x1a, sizeof(MxU16));
p_legoFileStream->Write(&m_unk0x1c, sizeof(MxU16));
p_legoFileStream->Write(&m_color1, sizeof(MxU16));
p_legoFileStream->Write(&m_color2, sizeof(MxU16));
p_legoFileStream->Write(&m_color3, sizeof(MxU16));
p_legoFileStream->Write(&m_color4, sizeof(MxU16));
}
else if (p_legoFileStream->IsWriteMode()) {
p_legoFileStream->Read(&m_unk0x12, sizeof(MxU16)); p_legoFileStream->Read(&m_unk0x12, sizeof(MxU16));
p_legoFileStream->Read(&m_unk0x14, sizeof(MxU16)); p_legoFileStream->Read(&m_unk0x14, sizeof(MxU16));
p_legoFileStream->Read(&m_unk0x16, sizeof(MxU16)); p_legoFileStream->Read(&m_unk0x16, sizeof(MxU16));
@ -51,6 +39,37 @@ MxResult TowTrackMissionState::VTable0x1c(LegoFileStream* p_legoFileStream)
p_legoFileStream->Read(&m_color3, sizeof(MxU16)); p_legoFileStream->Read(&m_color3, sizeof(MxU16));
p_legoFileStream->Read(&m_color4, sizeof(MxU16)); p_legoFileStream->Read(&m_color4, sizeof(MxU16));
} }
else if (p_legoFileStream->IsWriteMode()) {
MxU16 write = m_unk0x12;
p_legoFileStream->Write(&write, sizeof(MxU16));
write = m_unk0x14;
p_legoFileStream->Write(&write, sizeof(MxU16));
write = m_unk0x16;
p_legoFileStream->Write(&write, sizeof(MxU16));
write = m_unk0x18;
p_legoFileStream->Write(&write, sizeof(MxU16));
write = m_unk0x1a;
p_legoFileStream->Write(&write, sizeof(MxU16));
write = m_unk0x1c;
p_legoFileStream->Write(&write, sizeof(MxU16));
write = m_color1;
p_legoFileStream->Write(&write, sizeof(MxU16));
write = m_color2;
p_legoFileStream->Write(&write, sizeof(MxU16));
write = m_color3;
p_legoFileStream->Write(&write, sizeof(MxU16));
write = m_color4;
p_legoFileStream->Write(&write, sizeof(MxU16));
}
return SUCCESS; return SUCCESS;
} }

View File

@ -30,7 +30,7 @@ LegoVideoManager::LegoVideoManager()
m_cursorX = m_cursorY; m_cursorX = m_cursorY;
m_cursorYCopy = m_cursorY; m_cursorYCopy = m_cursorY;
m_cursorXCopy = m_cursorY; m_cursorXCopy = m_cursorY;
m_unk0x514 = NULL; m_cursorSurface = NULL;
m_fullScreenMovie = FALSE; m_fullScreenMovie = FALSE;
m_drawFPS = FALSE; m_drawFPS = FALSE;
m_unk0x528 = 0; m_unk0x528 = 0;
@ -309,18 +309,19 @@ inline void LegoVideoManager::DrawCursor()
LPDIRECTDRAWSURFACE ddSurface2 = m_displaySurface->GetDirectDrawSurface2(); LPDIRECTDRAWSURFACE ddSurface2 = m_displaySurface->GetDirectDrawSurface2();
if (!m_unk0x514) { if (!m_cursorSurface) {
m_unk0x518.top = 0; m_cursorRect.top = 0;
m_unk0x518.left = 0; m_cursorRect.left = 0;
m_unk0x518.bottom = 16; m_cursorRect.bottom = 16;
m_unk0x518.right = 16; m_cursorRect.right = 16;
m_unk0x514 = MxDisplaySurface::FUN_100bc070(); m_cursorSurface = MxDisplaySurface::CreateCursorSurface();
if (!m_unk0x514) if (!m_cursorSurface)
m_drawCursor = FALSE; m_drawCursor = FALSE;
} }
ddSurface2->BltFast(m_cursorXCopy, m_cursorYCopy, m_unk0x514, &m_unk0x518, DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY); ddSurface2
->BltFast(m_cursorXCopy, m_cursorYCopy, m_cursorSurface, &m_cursorRect, DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY);
} }
// STUB: LEGO1 0x1007bbc0 // STUB: LEGO1 0x1007bbc0

View File

@ -138,15 +138,12 @@ BOOL Lego3DView::Moved(ViewROI& rROI)
return TRUE; return TRUE;
} }
// STUB: LEGO1 0x100ab270 // FUNCTION: LEGO1 0x100ab270
double Lego3DView::Render(double p_und) double Lego3DView::Render(double p_und)
{ {
// assert(m_pViewManager); assert(m_pViewManager);
m_pViewManager->Update(m_previousRenderTime, p_und);
// m_pViewManager->Update(m_previousRenderTime); m_previousRenderTime = TglSurface::Render();
// m_previousRenderTime = LegoView1::Render();
return m_previousRenderTime; return m_previousRenderTime;
} }

View File

@ -83,10 +83,15 @@ class MxDisplaySurface : public MxCore {
); // vtable+0x38 ); // vtable+0x38
virtual void GetDC(HDC* p_hdc); // vtable+0x3c virtual void GetDC(HDC* p_hdc); // vtable+0x3c
virtual void ReleaseDC(HDC p_hdc); // vtable+0x40 virtual void ReleaseDC(HDC p_hdc); // vtable+0x40
virtual LPDIRECTDRAWSURFACE VTable0x44(MxBitmap*, undefined4*, undefined4, undefined4); // vtable+0x44 virtual LPDIRECTDRAWSURFACE VTable0x44(
MxBitmap* p_bitmap,
undefined4* p_ret,
undefined4 p_doNotWriteToSurface,
undefined4 p_transparent
); // vtable+0x44
void ClearScreen(); void ClearScreen();
static LPDIRECTDRAWSURFACE FUN_100bc070(); static LPDIRECTDRAWSURFACE CreateCursorSurface();
inline LPDIRECTDRAWSURFACE GetDirectDrawSurface1() { return this->m_ddSurface1; } inline LPDIRECTDRAWSURFACE GetDirectDrawSurface1() { return this->m_ddSurface1; }
inline LPDIRECTDRAWSURFACE GetDirectDrawSurface2() { return this->m_ddSurface2; } inline LPDIRECTDRAWSURFACE GetDirectDrawSurface2() { return this->m_ddSurface2; }

View File

@ -328,30 +328,7 @@ void MxDisplaySurface::VTable0x28(
} }
if (hr == DD_OK) { if (hr == DD_OK) {
MxU8* data; MxU8* data = p_bitmap->GetStart(p_left, p_top);
switch (p_bitmap->GetBmiHeader()->biCompression) {
case BI_RGB: {
MxS32 rowsBeforeTop;
if (p_bitmap->GetBmiHeight() < 0)
rowsBeforeTop = p_top;
else
rowsBeforeTop = p_bitmap->GetBmiHeightAbs() - p_top - 1;
data = p_bitmap->GetBitmapData() + p_left + (p_bitmap->GetBmiStride() * rowsBeforeTop);
break;
}
case BI_RGB_TOPDOWN:
data = p_bitmap->GetBitmapData();
break;
default: {
MxS32 rowsBeforeTop;
if (p_bitmap->GetBmiHeight() < 0)
rowsBeforeTop = 0;
else
rowsBeforeTop = p_bitmap->GetBmiHeightAbs() - 1;
data = p_bitmap->GetBitmapData() + (p_bitmap->GetBmiStride() * rowsBeforeTop);
}
}
if (m_videoParam.Flags().GetF1bit3()) { if (m_videoParam.Flags().GetF1bit3()) {
p_bottom *= 2; p_bottom *= 2;
@ -564,15 +541,217 @@ void MxDisplaySurface::ReleaseDC(HDC p_hdc)
this->m_ddSurface2->ReleaseDC(p_hdc); this->m_ddSurface2->ReleaseDC(p_hdc);
} }
// STUB: LEGO1 0x100bbc60 // FUNCTION: LEGO1 0x100bbc60
LPDIRECTDRAWSURFACE MxDisplaySurface::VTable0x44(MxBitmap*, undefined4*, undefined4, undefined4) LPDIRECTDRAWSURFACE MxDisplaySurface::VTable0x44(
MxBitmap* p_bitmap,
undefined4* p_ret,
undefined4 p_doNotWriteToSurface,
undefined4 p_transparent
)
{ {
LPDIRECTDRAWSURFACE surface = NULL;
LPDIRECTDRAW draw = MVideoManager()->GetDirectDraw();
MVideoManager();
DDSURFACEDESC ddsd;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
if (draw->GetDisplayMode(&ddsd))
return NULL; return NULL;
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
ddsd.dwWidth = p_bitmap->GetBmiWidth();
ddsd.dwHeight = p_bitmap->GetBmiHeightAbs();
*p_ret = 0;
ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
if (draw->CreateSurface(&ddsd, &surface, NULL) != S_OK) {
if (*p_ret) {
*p_ret = 0;
// Try creating bitmap surface in vram if system ram ran out
ddsd.ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY;
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
if (draw->CreateSurface(&ddsd, &surface, NULL) != S_OK) {
surface = NULL;
}
}
else
surface = NULL;
}
if (surface) {
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
if (surface->Lock(NULL, &ddsd, DDLOCK_WAIT, 0) != S_OK) {
surface->Release();
surface = NULL;
goto done;
}
if (p_doNotWriteToSurface) {
goto done;
}
MxU8* bitmapSrcPtr = p_bitmap->GetStart(0, 0);
MxU16* surfaceData = (MxU16*) ddsd.lpSurface;
MxLong widthNormal = p_bitmap->GetBmiWidth();
MxLong heightAbs = p_bitmap->GetBmiHeightAbs();
// TODO: Probably p_bitmap->GetAdjustedStride()
MxS32 rowSeek = p_bitmap->GetBmiStride();
if (p_bitmap->GetBmiHeader()->biCompression != BI_RGB_TOPDOWN && p_bitmap->GetBmiHeight() >= 0)
rowSeek = -rowSeek;
MxLong newPitch = ddsd.lPitch;
switch (ddsd.ddpfPixelFormat.dwRGBBitCount) {
case 8: {
for (MxS32 y = heightAbs; y > 0; y--) {
memcpy(surfaceData, bitmapSrcPtr, p_bitmap->GetBmiHeight());
bitmapSrcPtr += rowSeek;
surfaceData = (MxU16*) ((MxU8*) surfaceData + newPitch);
}
surface->Unlock(ddsd.lpSurface);
if (p_transparent && surface) {
DDCOLORKEY key;
key.dwColorSpaceHighValue = 0;
key.dwColorSpaceLowValue = 0;
surface->SetColorKey(DDCKEY_SRCBLT, &key);
}
break;
}
case 16:
if (m_16bitPal == NULL) {
if (surface) {
surface->Release();
}
return NULL;
}
else {
rowSeek -= p_bitmap->GetBmiWidth();
newPitch -= 2 * p_bitmap->GetBmiWidth();
if (p_transparent) {
for (MxS32 y = heightAbs; y > 0; y--) {
for (MxS32 x = widthNormal; x > 0; x--) {
if (*bitmapSrcPtr) {
*surfaceData = m_16bitPal[*bitmapSrcPtr];
}
else {
*surfaceData = 31775;
}
bitmapSrcPtr++;
surfaceData++;
}
bitmapSrcPtr += rowSeek;
surfaceData = (MxU16*) ((MxU8*) surfaceData + newPitch);
}
DDCOLORKEY key;
key.dwColorSpaceHighValue = 31775;
key.dwColorSpaceLowValue = 31775;
surface->SetColorKey(DDCKEY_SRCBLT, &key);
}
else {
for (MxS32 y = heightAbs; y > 0; y--) {
for (MxS32 x = widthNormal; x > 0; x--) {
*surfaceData++ = m_16bitPal[*bitmapSrcPtr++];
}
bitmapSrcPtr += rowSeek;
surfaceData = (MxU16*) ((MxU8*) surfaceData + newPitch);
}
}
surface->Unlock(ddsd.lpSurface);
}
}
}
done:
return surface;
} }
// STUB: LEGO1 0x100bc070 // FUNCTION: LEGO1 0x100bc070
LPDIRECTDRAWSURFACE MxDisplaySurface::FUN_100bc070() LPDIRECTDRAWSURFACE MxDisplaySurface::CreateCursorSurface()
{ {
LPDIRECTDRAWSURFACE newSurface = NULL;
IDirectDraw* draw = MVideoManager()->GetDirectDraw();
MVideoManager();
DDSURFACEDESC ddsd;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
if (draw->GetDisplayMode(&ddsd) != S_OK) {
return NULL;
}
if (ddsd.ddpfPixelFormat.dwRGBBitCount != 16) {
return NULL;
}
ddsd.dwWidth = 16;
ddsd.dwHeight = 16;
ddsd.dwFlags = DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN;
if (draw->CreateSurface(&ddsd, &newSurface, NULL) != S_OK) {
ddsd.ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY;
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
if (draw->CreateSurface(&ddsd, &newSurface, NULL) != S_OK)
goto done;
}
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
if (newSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) != S_OK)
goto done;
else {
MxU16* surface = (MxU16*) ddsd.lpSurface;
MxLong pitch = ddsd.lPitch;
// draw a simple cursor to the surface
for (MxS32 x = 0; x < 16; x++) {
MxU16* surface2 = surface;
for (MxS32 y = 0; y < 16; y++) {
if ((y > 10 || x) && (x > 10 || y) && x + y != 10) {
if (x + y > 10)
*surface2 = 31775;
else
*surface2 = -1;
}
else {
*surface2 = 0;
}
surface2++;
}
surface = (MxU16*) ((MxU8*) surface + pitch);
}
newSurface->Unlock(ddsd.lpSurface);
DDCOLORKEY colorkey;
colorkey.dwColorSpaceHighValue = 31775;
colorkey.dwColorSpaceLowValue = 31775;
newSurface->SetColorKey(DDCKEY_SRCBLT, &colorkey);
return newSurface;
}
done:
if (newSurface) {
newSurface->Release();
}
return NULL; return NULL;
} }

View File

@ -16,6 +16,11 @@ void ViewManager::RemoveAll(ViewROI*)
// TODO // TODO
} }
// STUB: LEGO1 0x100a6930
void ViewManager::Update(float p_previousRenderTime, float p_und2)
{
}
// STUB: LEGO1 0x100a6d50 // STUB: LEGO1 0x100a6d50
void ViewManager::SetResolution(int width, int height) void ViewManager::SetResolution(int width, int height)
{ {

View File

@ -15,6 +15,7 @@ class ViewManager {
void SetPOVSource(const OrientableROI* point_of_view); void SetPOVSource(const OrientableROI* point_of_view);
void SetResolution(int width, int height); void SetResolution(int width, int height);
void SetFrustrum(float fov, float front, float back); void SetFrustrum(float fov, float front, float back);
void Update(float p_previousRenderTime, float p_und2);
// SYNTHETIC: LEGO1 0x100a6000 // SYNTHETIC: LEGO1 0x100a6000
// ViewManager::`scalar deleting destructor' // ViewManager::`scalar deleting destructor'