diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index d8fbe442..6f1c7065 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -17,6 +17,7 @@ jobs: --style=file \ ISLE/*.cpp ISLE/*.h \ LEGO1/*.cpp LEGO1/*.h \ + LEGO1/3dmanager/*.cpp LEGO1/3dmanager/*.h \ LEGO1/mxdirectx/*.h \ LEGO1/mxstl/*.h \ LEGO1/realtime/*.cpp LEGO1/realtime/*.h \ diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e509e01..e10f6b55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,7 @@ option(ISLE_USE_SMARTHEAP "Build with SmartHeap" ${MSVC}) option(ISLE_USE_DX5 "Build with internal DirectX 5 SDK" ON) add_library(lego1 SHARED + LEGO1/3dmanager/tglsurface.cpp LEGO1/act1state.cpp LEGO1/act2brick.cpp LEGO1/act2policestation.cpp diff --git a/LEGO1/3dmanager/tglsurface.cpp b/LEGO1/3dmanager/tglsurface.cpp new file mode 100644 index 00000000..2493e00c --- /dev/null +++ b/LEGO1/3dmanager/tglsurface.cpp @@ -0,0 +1,224 @@ +// TglSurface.cpp : implementation file + +#include "tglsurface.h" + +#include "decomp.h" + +DECOMP_SIZE_ASSERT(TglSurface, 0x70); + +using namespace Tgl; + +///////////////////////////////////////////////////////////////////////////// +// TglSurface + +// FUNCTION: LEGO1 0x100abbf0 +TglSurface::TglSurface() +{ + m_pRenderer = 0; + m_pDevice = 0; + m_pView = 0; + m_pScene = 0; + + m_width = 0; + m_height = 0; + + m_stopRendering = FALSE; + m_isInitialized = FALSE; + + // statistics + m_frameCount = 0; +#ifdef _DEBUG + m_triangleCount = 0; +#endif +} + +// FUNCTION: LEGO1 0x100abd60 +TglSurface::~TglSurface() +{ + Destroy(); +} + +// FUNCTION: LEGO1 0x100abde0 +void TglSurface::Destroy() +{ + DestroyView(); + + delete m_pDevice; + m_pDevice = 0; + + m_pRenderer = 0; + m_pScene = 0; +} + +// ??? +// FUNCTION: LEGO1 0x100abe10 +int GetBitsPerPixel(IDirectDrawSurface* pSurface) +{ + DDPIXELFORMAT pixelFormat; + HRESULT result; + + memset(&pixelFormat, 0, sizeof(pixelFormat)); + pixelFormat.dwSize = sizeof(pixelFormat); + + result = pSurface->GetPixelFormat(&pixelFormat); + assert(result == DD_OK); + assert(pixelFormat.dwFlags & DDPF_RGB); + + return pixelFormat.dwRGBBitCount; +} + +// FUNCTION: LEGO1 0x100abe50 +BOOL TglSurface::Create(const CreateStruct& rCreateStruct, Renderer* pRenderer, Group* pScene) +{ + DeviceDirect3DCreateData createData = {rCreateStruct.m_direct3d, rCreateStruct.m_d3dDevice}; + int bitsPerPixel = GetBitsPerPixel(rCreateStruct.m_pFrontBuffer); + + ColorModel colorModel = Ramp; + ShadingModel shadingModel = Gouraud; + int shadeCount = 32; + BOOL dither = TRUE; + int textureShadeCount = -1; + int textureColorCount = -1; + Result result; + + m_pRenderer = pRenderer; + m_pScene = pScene; + m_pDevice = m_pRenderer->CreateDevice(createData); + + if (!m_pDevice) { + assert(0); + m_pRenderer = 0; + m_pScene = 0; + return FALSE; + } + + if (bitsPerPixel == 1) { + shadeCount = 4; + textureShadeCount = 4; + } + else if (bitsPerPixel == 8) { + shadeCount = 16; + dither = FALSE; + textureShadeCount = 16; + textureColorCount = 256; + } + else if (bitsPerPixel == 16) { + shadeCount = 32; + dither = FALSE; + textureShadeCount = 32; + textureColorCount = 256; + } + else if (bitsPerPixel >= 24) { + shadeCount = 256; + dither = FALSE; + textureShadeCount = 256; + textureColorCount = 64; + } + else { + dither = FALSE; + } + + if (textureShadeCount != -1) { + result = pRenderer->SetTextureDefaultShadeCount(textureShadeCount); + assert(Succeeded(result)); + } + if (textureColorCount != -1) { + result = pRenderer->SetTextureDefaultColorCount(textureColorCount); + assert(Succeeded(result)); + } + + result = m_pDevice->SetColorModel(colorModel); + assert(Succeeded(result)); + result = m_pDevice->SetShadingModel(shadingModel); + assert(Succeeded(result)); + result = m_pDevice->SetShadeCount(shadeCount); + assert(Succeeded(result)); + result = m_pDevice->SetDither(dither); + assert(Succeeded(result)); + + m_width = m_pDevice->GetWidth(); + m_height = m_pDevice->GetHeight(); + + m_pView = CreateView(m_pRenderer, m_pDevice); + if (!m_pView) { + delete m_pDevice; + m_pDevice = 0; + m_pRenderer = 0; + m_pScene = 0; + return FALSE; + } + + m_frameRateMeter.Reset(); + m_renderingRateMeter.Reset(); +#ifdef _DEBUG + m_triangleRateMeter.Reset(); +#endif + m_frameRateMeter.StartOperation(); + + m_isInitialized = TRUE; + + return TRUE; +} + +// FUNCTION: LEGO1 0x100ac030 +void TglSurface::DestroyView() +{ + delete m_pView; + m_pView = 0; +} + +// FUNCTION: LEGO1 0x100ac050 +double TglSurface::Render() +{ + MxStopWatch renderTimer; + + if (m_isInitialized && !m_stopRendering) { + Result result; + +#ifdef _DEBUG + m_triangleRateMeter.StartOperation(); +#endif + m_renderingRateMeter.StartOperation(); + renderTimer.Start(); + + // TODO: Wrong interface + result = m_pView->Render((Tgl::Light*) m_pScene); + + renderTimer.Stop(); + assert(Succeeded(result)); + m_renderingRateMeter.EndOperation(); +#ifdef _DEBUG + m_triangleRateMeter.EndOperation(); +#endif + m_frameRateMeter.EndOperation(); + m_frameCount++; + +#ifdef _DEBUG + { + unsigned long triangleCount = m_pDevice->GetDrawnTriangleCount(); + + m_triangleRateMeter.IncreaseOperationCount(triangleCount - m_triangleCount - 1); + m_triangleCount = triangleCount; + } +#endif + +#if 0 + // reset rate meters every 20 frames + if ((++m_frameCount % 20) == 0) +#else + // reset rate meters every 4 seconds + if (m_frameRateMeter.ElapsedSeconds() > 4.0) +#endif + { + m_frameRateMeter.Reset(); + m_renderingRateMeter.Reset(); +#ifdef _DEBUG + m_triangleRateMeter.Reset(); +#endif + } + + m_frameRateMeter.StartOperation(); + } + + return renderTimer.ElapsedSeconds(); +} diff --git a/LEGO1/3dmanager/tglsurface.h b/LEGO1/3dmanager/tglsurface.h new file mode 100644 index 00000000..2d1935b6 --- /dev/null +++ b/LEGO1/3dmanager/tglsurface.h @@ -0,0 +1,87 @@ +#ifndef _TglSurface_h +#define _TglSurface_h + +#include "../mxdirectx/mxstopwatch.h" +#include "../tgl/tgl.h" + +class Tgl::Renderer; +class Tgl::Device; +class Tgl::View; +class Tgl::Group; + +///////////////////////////////////////////////////////////////////////////// +// TglSurface + +// VTABLE: LEGO1 0x100dc060 +// SIZE 0x70 +class TglSurface { +public: + // SIZE 0x28 + struct CreateStruct { + const GUID* m_pDriverGUID; // 0x00 + HWND m_hWnd; // 0x04 + IDirectDraw* m_pDirectDraw; // 0x08 + IDirectDrawSurface* m_pFrontBuffer; // 0x0c + IDirectDrawSurface* m_pBackBuffer; // 0x10 + IDirectDrawPalette* m_pPalette; // 0x14 + BOOL m_isFullScreen; // 0x18 + unsigned long m_flags; // 0x1c + IDirect3D2* m_direct3d; // 0x20 + IDirect3DDevice2* m_d3dDevice; // 0x24 + }; + +public: + TglSurface(); + virtual ~TglSurface(); + + virtual BOOL Create(const CreateStruct&, Tgl::Renderer*, Tgl::Group* pScene); // vtable+0x04 + virtual void Destroy(); // vtable+0x08 + virtual double Render(); // render time in seconds // vtable+0x0c + + Tgl::Renderer* GetRenderer() const { return m_pRenderer; } + Tgl::Device* GetDevice() const { return m_pDevice; } + Tgl::View* GetView() const { return m_pView; } + Tgl::Group* GetScene() const { return m_pScene; } + + unsigned long GetWidth() const { return m_width; } + unsigned long GetHeight() const { return m_height; } + + double GetRenderingRate() const { return m_renderingRateMeter.Frequency(); } + double GetFrameRate() const { return m_frameRateMeter.Frequency(); } + unsigned long GetFrameCount() const { return m_frameCount; } +#ifdef _DEBUG + double GetTriangleRate() const { return m_triangleRateMeter.Frequency(); } +#endif + +protected: + virtual Tgl::View* CreateView(Tgl::Renderer*, Tgl::Device*) = 0; // vtable+0x10 + virtual void DestroyView(); // vtable+0x14 + +private: + Tgl::Renderer* m_pRenderer; // 0x08 + Tgl::Device* m_pDevice; // 0x0c + Tgl::View* m_pView; // 0x10 + Tgl::Group* m_pScene; // 0x14 + + unsigned long m_width; // 0x18 + unsigned long m_height; // 0x1c + + BOOL m_isInitialized; // 0x20 + BOOL m_stopRendering; // 0x24 + + // statistics + MxFrequencyMeter m_renderingRateMeter; // 0x28 + MxFrequencyMeter m_frameRateMeter; // 0x48 + unsigned long m_frameCount; // 0x68 +#ifdef _DEBUG + MxFrequencyMeter m_triangleRateMeter; + unsigned long m_triangleCount; +#endif +}; + +///////////////////////////////////////////////////////////////////////////// + +// SYNTHETIC: LEGO1 0x100abcf0 +// TglSurface::`scalar deleting destructor' + +#endif /* _TglSurface_h */ diff --git a/LEGO1/lego3dmanager.cpp b/LEGO1/lego3dmanager.cpp index ebc488ff..d5c2d687 100644 --- a/LEGO1/lego3dmanager.cpp +++ b/LEGO1/lego3dmanager.cpp @@ -1,8 +1,7 @@ #include "lego3dmanager.h" +#include "3dmanager/tglsurface.h" #include "decomp.h" -#include "tgl/tgl.h" -#include "tglsurface.h" #include "viewmanager/viewlodlist.h" DECOMP_SIZE_ASSERT(Lego3DManager, 0x10); @@ -10,12 +9,12 @@ DECOMP_SIZE_ASSERT(Lego3DManager, 0x10); // FUNCTION: LEGO1 0x100ab2d0 BOOL InitializeCreateStruct(TglSurface::CreateStruct& p_tglSurface, const Lego3DManager::CreateStruct& p_createStruct) { - p_tglSurface.m_driverGUID = p_createStruct.m_driverGUID; - p_tglSurface.m_hwnd = p_createStruct.m_hwnd; - p_tglSurface.m_directDraw = p_createStruct.m_directDraw; - p_tglSurface.m_ddSurface1 = p_createStruct.m_ddSurface1; - p_tglSurface.m_ddSurface2 = p_createStruct.m_ddSurface2; - p_tglSurface.m_ddPalette = p_createStruct.m_ddPalette; + p_tglSurface.m_pDriverGUID = p_createStruct.m_driverGUID; + p_tglSurface.m_hWnd = p_createStruct.m_hwnd; + p_tglSurface.m_pDirectDraw = p_createStruct.m_directDraw; + p_tglSurface.m_pFrontBuffer = p_createStruct.m_ddSurface1; + p_tglSurface.m_pBackBuffer = p_createStruct.m_ddSurface2; + p_tglSurface.m_pPalette = p_createStruct.m_ddPalette; p_tglSurface.m_isFullScreen = p_createStruct.m_isFullScreen; p_tglSurface.m_flags = p_createStruct.m_flags; p_tglSurface.m_direct3d = p_createStruct.m_direct3d; diff --git a/LEGO1/lego3dview.cpp b/LEGO1/lego3dview.cpp index 92319630..5fd18920 100644 --- a/LEGO1/lego3dview.cpp +++ b/LEGO1/lego3dview.cpp @@ -19,11 +19,11 @@ Lego3DView::~Lego3DView() BOOL Lego3DView::Create(TglSurface::CreateStruct& p_createStruct, Tgl::Renderer* p_renderer) { Tgl::DeviceDirectDrawCreateData createData = { - p_createStruct.m_driverGUID, - p_createStruct.m_hwnd, - p_createStruct.m_directDraw, - p_createStruct.m_ddSurface1, - p_createStruct.m_ddSurface2 + p_createStruct.m_pDriverGUID, + p_createStruct.m_hWnd, + p_createStruct.m_pDirectDraw, + p_createStruct.m_pFrontBuffer, + p_createStruct.m_pBackBuffer }; m_device = p_renderer->CreateDevice(createData); diff --git a/LEGO1/lego3dview.h b/LEGO1/lego3dview.h index 4222a35f..f98aefaa 100644 --- a/LEGO1/lego3dview.h +++ b/LEGO1/lego3dview.h @@ -1,9 +1,9 @@ #ifndef LEGO3DVIEW_H #define LEGO3DVIEW_H +#include "3dmanager/tglsurface.h" +#include "decomp.h" #include "mxtypes.h" -#include "tgl/d3drm/impl.h" -#include "tglsurface.h" #include "viewmanager/viewmanager.h" class LegoROI; diff --git a/LEGO1/legovideomanager.cpp b/LEGO1/legovideomanager.cpp index 218406e6..143768de 100644 --- a/LEGO1/legovideomanager.cpp +++ b/LEGO1/legovideomanager.cpp @@ -5,6 +5,7 @@ #include "mxtimer.h" #include "mxtransitionmanager.h" #include "realtime/matrix.h" +#include "tgl/d3drm/impl.h" #include "viewmanager/viewroi.h" DECOMP_SIZE_ASSERT(LegoVideoManager, 0x590); @@ -224,31 +225,6 @@ void LegoVideoManager::MoveCursor(MxS32 p_cursorX, MxS32 p_cursorY) m_cursorY = 463; } -inline void LegoVideoManager::DrawCursor() -{ - if (m_cursorX != m_cursorXCopy || m_cursorY != m_cursorYCopy) { - if (m_cursorX >= 0 && m_cursorY >= 0) { - m_cursorXCopy = m_cursorX; - m_cursorYCopy = m_cursorY; - } - } - - LPDIRECTDRAWSURFACE ddSurface2 = m_displaySurface->GetDirectDrawSurface2(); - - if (!m_unk0x514) { - m_unk0x518.top = 0; - m_unk0x518.left = 0; - m_unk0x518.bottom = 16; - m_unk0x518.right = 16; - m_unk0x514 = MxDisplaySurface::FUN_100bc070(); - - if (!m_unk0x514) - m_drawCursor = FALSE; - } - - ddSurface2->BltFast(m_cursorXCopy, m_cursorYCopy, m_unk0x514, &m_unk0x518, DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY); -} - // FUNCTION: LEGO1 0x1007b770 MxResult LegoVideoManager::Tickle() { @@ -321,6 +297,31 @@ MxResult LegoVideoManager::Tickle() return SUCCESS; } +inline void LegoVideoManager::DrawCursor() +{ + if (m_cursorX != m_cursorXCopy || m_cursorY != m_cursorYCopy) { + if (m_cursorX >= 0 && m_cursorY >= 0) { + m_cursorXCopy = m_cursorX; + m_cursorYCopy = m_cursorY; + } + } + + LPDIRECTDRAWSURFACE ddSurface2 = m_displaySurface->GetDirectDrawSurface2(); + + if (!m_unk0x514) { + m_unk0x518.top = 0; + m_unk0x518.left = 0; + m_unk0x518.bottom = 16; + m_unk0x518.right = 16; + m_unk0x514 = MxDisplaySurface::FUN_100bc070(); + + if (!m_unk0x514) + m_drawCursor = FALSE; + } + + ddSurface2->BltFast(m_cursorXCopy, m_cursorYCopy, m_unk0x514, &m_unk0x518, DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY); +} + // STUB: LEGO1 0x1007bbc0 void LegoVideoManager::DrawFPS() { diff --git a/LEGO1/mxdirectx/mxstopwatch.h b/LEGO1/mxdirectx/mxstopwatch.h index 1ce3275f..7e7fcc38 100644 --- a/LEGO1/mxdirectx/mxstopwatch.h +++ b/LEGO1/mxdirectx/mxstopwatch.h @@ -2,7 +2,9 @@ #define _MxStopWatch_h #include "assert.h" -#include "winbase.h" + +#include +#include ////////////////////////////////////////////////////////////////////////////// // @@ -13,6 +15,7 @@ #define HUGE_VAL_IMMEDIATE 1.7976931348623157e+308 +// SIZE 0x18 class MxStopWatch { public: MxStopWatch(); @@ -28,11 +31,11 @@ class MxStopWatch { unsigned long TicksPerSeconds() const; private: - LARGE_INTEGER m_startTick; + LARGE_INTEGER m_startTick; // 0x00 // ??? when we provide LARGE_INTEGER arithmetic, use a // LARGE_INTEGER m_elapsedTicks rather than m_elapsedSeconds - double m_elapsedSeconds; - unsigned long m_ticksPerSeconds; + double m_elapsedSeconds; // 0x0c + unsigned long m_ticksPerSeconds; // 0x14 }; inline MxStopWatch::MxStopWatch() @@ -99,6 +102,7 @@ inline double MxStopWatch::ElapsedSeconds() const // MxFrequencyMeter // +// SIZE 0x20 class MxFrequencyMeter { public: MxFrequencyMeter(); @@ -114,8 +118,8 @@ class MxFrequencyMeter { void IncreaseOperationCount(unsigned long); private: - unsigned long m_operationCount; - MxStopWatch m_stopWatch; + unsigned long m_operationCount; // 0x00 + MxStopWatch m_stopWatch; // 0x08 }; ////////////////////////////////////////////////////////////////////////////// diff --git a/LEGO1/tgl/d3drm/impl.h b/LEGO1/tgl/d3drm/impl.h index e1488508..f4d85cf4 100644 --- a/LEGO1/tgl/d3drm/impl.h +++ b/LEGO1/tgl/d3drm/impl.h @@ -1,5 +1,6 @@ #include "../tgl.h" +#include "compat.h" #include "decomp.h" #include @@ -41,11 +42,11 @@ class RendererImpl : public Renderer { RendererImpl() : m_data(0) {} ~RendererImpl() { Destroy(); }; - virtual void* ImplementationDataPtr(); + virtual void* ImplementationDataPtr() override; // vtable+0x08 - virtual Device* CreateDevice(const DeviceDirect3DCreateData&); - virtual Device* CreateDevice(const DeviceDirectDrawCreateData&); + virtual Device* CreateDevice(const DeviceDirectDrawCreateData&) override; + virtual Device* CreateDevice(const DeviceDirect3DCreateData&) override; // vtable+0x10 virtual View* CreateView( @@ -55,14 +56,14 @@ class RendererImpl : public Renderer { unsigned long y, unsigned long width, unsigned long height - ); - virtual Camera* CreateCamera(); - virtual Light* CreateLight(LightType, float r, float g, float b); - virtual Group* CreateGroup(const Group* pParent); + ) override; + virtual Camera* CreateCamera() override; + virtual Light* CreateLight(LightType, float r, float g, float b) override; + virtual Group* CreateGroup(const Group* pParent) override; // vtable+0x20 - virtual Unk* CreateUnk(); - virtual Texture* CreateTexture(); + virtual Unk* CreateUnk() override; + virtual Texture* CreateTexture() override; virtual Texture* CreateTexture( int width, int height, @@ -71,11 +72,11 @@ class RendererImpl : public Renderer { int pTexelsArePersistent, int paletteEntryCount, const PaletteEntry* pEntries - ); - virtual Result SetTextureDefaultShadeCount(unsigned long); + ) override; + virtual Result SetTextureDefaultShadeCount(unsigned long) override; // vtable+0x30 - virtual Result SetTextureDefaultColorCount(unsigned long); + virtual Result SetTextureDefaultColorCount(unsigned long) override; public: inline Result Create(); diff --git a/LEGO1/tgl/tgl.h b/LEGO1/tgl/tgl.h index 4af0fae5..dfc18f3f 100644 --- a/LEGO1/tgl/tgl.h +++ b/LEGO1/tgl/tgl.h @@ -110,8 +110,8 @@ class Object { class Renderer : public Object { public: // vtable+0x08 - virtual Device* CreateDevice(const DeviceDirect3DCreateData&) = 0; virtual Device* CreateDevice(const DeviceDirectDrawCreateData&) = 0; + virtual Device* CreateDevice(const DeviceDirect3DCreateData&) = 0; // vtable+0x10 virtual View* CreateView( diff --git a/LEGO1/tglsurface.h b/LEGO1/tglsurface.h deleted file mode 100644 index 24776493..00000000 --- a/LEGO1/tglsurface.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef TGLSURFACE_H -#define TGLSURFACE_H - -#include "decomp.h" -#include "mxtypes.h" - -#include -#include - -class TglSurface { -public: - // SIZE 0x28 - struct CreateStruct { - GUID* m_driverGUID; // 0x00 - HWND m_hwnd; // 0x04 - IDirectDraw* m_directDraw; // 0x08 - IDirectDrawSurface* m_ddSurface1; // 0x0c - IDirectDrawSurface* m_ddSurface2; // 0x10 - IDirectDrawPalette* m_ddPalette; // 0x14 - BOOL m_isFullScreen; // 0x18 - MxU32 m_flags; // 0x1c - IDirect3D2* m_direct3d; // 0x20 - IDirect3DDevice2* m_d3dDevice; // 0x24 - }; -}; - -#endif // TGLSURFACE_H