From 935ebe69102062d12273af3f0fc430b6d3d45e89 Mon Sep 17 00:00:00 2001
From: Christian Semmler <mail@csemmler.com>
Date: Mon, 1 Jan 2024 19:17:38 -0500
Subject: [PATCH] Implement LegoVideoManager::Create and related (#393)

* WIP

* Match

* Changes

* Fix format

* Style fixes

* Update naming.yml

* Match to ~85%
---
 .github/workflows/format.yml      |   1 +
 .github/workflows/naming.yml      |   2 +-
 CMakeLists.txt                    |   4 +-
 LEGO1/lego3dmanager.cpp           |  49 +++++---
 LEGO1/lego3dmanager.h             |  26 ++++-
 LEGO1/lego3dview.cpp              |  14 ++-
 LEGO1/lego3dview.h                |   6 +-
 LEGO1/legoomni.cpp                |  14 +--
 LEGO1/legoomni.h                  |   4 +-
 LEGO1/legoroi.cpp                 |  21 ++++
 LEGO1/legoroi.h                   |  16 +++
 LEGO1/legovideomanager.cpp        | 167 ++++++++++++++++++++++++++--
 LEGO1/legovideomanager.h          |  19 ++--
 LEGO1/mxdirect3d.cpp              |  56 ++++++++--
 LEGO1/mxdirect3d.h                |  85 ++++++++------
 LEGO1/mxdirectdraw.h              |  15 ++-
 LEGO1/mxdirectx/mxstopwatch.h     | 179 ++++++++++++++++++++++++++++++
 LEGO1/mxrendersettings.cpp        |  21 ----
 LEGO1/mxrendersettings.h          |  28 -----
 LEGO1/mxstring.h                  |   5 +-
 LEGO1/mxunknown100d7c88.cpp       |  12 ++
 LEGO1/mxunknown100d7c88.h         |  19 ++++
 LEGO1/mxunknown100d9d00.h         |  42 +++++++
 LEGO1/mxunknown100dbdbc.cpp       |  17 ---
 LEGO1/mxunknown100dbdbc.h         |  18 ---
 LEGO1/mxvideomanager.cpp          |  10 +-
 LEGO1/mxvideomanager.h            |   6 +-
 LEGO1/mxvideoparam.h              |   2 +-
 LEGO1/tglsurface.h                |  27 +++++
 LEGO1/viewmanager/viewlodlist.cpp |  28 +++++
 LEGO1/viewmanager/viewlodlist.h   |   3 +
 LEGO1/viewmanager/viewroi.cpp     |  12 +-
 LEGO1/viewmanager/viewroi.h       |  13 ++-
 33 files changed, 742 insertions(+), 199 deletions(-)
 create mode 100644 LEGO1/mxdirectx/mxstopwatch.h
 delete mode 100644 LEGO1/mxrendersettings.cpp
 delete mode 100644 LEGO1/mxrendersettings.h
 create mode 100644 LEGO1/mxunknown100d7c88.cpp
 create mode 100644 LEGO1/mxunknown100d7c88.h
 create mode 100644 LEGO1/mxunknown100d9d00.h
 delete mode 100644 LEGO1/mxunknown100dbdbc.cpp
 delete mode 100644 LEGO1/mxunknown100dbdbc.h
 create mode 100644 LEGO1/tglsurface.h
 create mode 100644 LEGO1/viewmanager/viewlodlist.cpp

diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml
index 22b39806..d8fbe442 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/mxdirectx/*.h \
           LEGO1/mxstl/*.h \
           LEGO1/realtime/*.cpp LEGO1/realtime/*.h \
           LEGO1/tgl/*.h \
diff --git a/.github/workflows/naming.yml b/.github/workflows/naming.yml
index 11738779..f0d72616 100644
--- a/.github/workflows/naming.yml
+++ b/.github/workflows/naming.yml
@@ -24,6 +24,6 @@ jobs:
           --clang-lib ${{ env.LLVM_PATH }}/lib/libclang.so \
           --style tools/ncc/ncc.style \
           --skip tools/ncc/skip.yml \
-          --definition WINAPI FAR HWND__=HWND \
+          --definition WINAPI FAR CALLBACK HWND__=HWND \
           --include util \
           --path LEGO1
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3b31a548..61a70e1c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -163,7 +163,6 @@ add_library(lego1 SHARED
   LEGO1/mxramstreamprovider.cpp
   LEGO1/mxregion.cpp
   LEGO1/mxregioncursor.cpp
-  LEGO1/mxrendersettings.cpp
   LEGO1/mxscheduler.cpp
   LEGO1/mxsemaphore.cpp
   LEGO1/mxsmack.cpp
@@ -182,7 +181,7 @@ add_library(lego1 SHARED
   LEGO1/mxtimer.cpp
   LEGO1/mxtransitionmanager.cpp
   LEGO1/mxtype17notificationparam.cpp
-  LEGO1/mxunknown100dbdbc.cpp
+  LEGO1/mxunknown100d7c88.cpp
   LEGO1/mxvariable.cpp
   LEGO1/mxvariabletable.cpp
   LEGO1/mxvideomanager.cpp
@@ -222,6 +221,7 @@ add_library(lego1 SHARED
   LEGO1/tgl/d3drm/view.cpp
   LEGO1/towtrack.cpp
   LEGO1/towtrackmissionstate.cpp
+  LEGO1/viewmanager/viewlodlist.cpp
   LEGO1/viewmanager/viewmanager.cpp
   LEGO1/viewmanager/viewroi.cpp
 )
diff --git a/LEGO1/lego3dmanager.cpp b/LEGO1/lego3dmanager.cpp
index c399b1a8..2b52fbd9 100644
--- a/LEGO1/lego3dmanager.cpp
+++ b/LEGO1/lego3dmanager.cpp
@@ -1,18 +1,34 @@
 #include "lego3dmanager.h"
 
 #include "decomp.h"
-#include "mxrendersettings.h"
-#include "mxunknown100dbdbc.h"
 #include "tgl/tgl.h"
+#include "tglsurface.h"
+#include "viewmanager/viewlodlist.h"
 
 DECOMP_SIZE_ASSERT(Lego3DManager, 0x10);
 
+// FUNCTION: LEGO1 0x100ab2d0
+BOOL InitializeCreateStruct(TglSurface::CreateStruct& p_tglSurface, const Lego3DManager::CreateStruct& p_createStruct)
+{
+	p_tglSurface.m_unk0x00 = p_createStruct.m_unk0x00;
+	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_isFullScreen = p_createStruct.m_isFullScreen;
+	p_tglSurface.m_flags = p_createStruct.m_flags;
+	p_tglSurface.m_direct3d = p_createStruct.m_direct3d;
+	p_tglSurface.m_d3dDevice = p_createStruct.m_d3dDevice;
+	return TRUE;
+}
+
 // FUNCTION: LEGO1 0x100ab320
 Lego3DManager::Lego3DManager()
 {
-	m_render = NULL;
+	m_renderer = NULL;
 	m_3dView = NULL;
-	m_unk0x0c = NULL;
+	m_viewLODListManager = NULL;
 }
 
 // FUNCTION: LEGO1 0x100ab360
@@ -22,16 +38,17 @@ Lego3DManager::~Lego3DManager()
 }
 
 // FUNCTION: LEGO1 0x100ab370
-void Lego3DManager::Init(MxRenderSettings& p_settings)
+BOOL Lego3DManager::Create(Lego3DManager::CreateStruct& p_createStruct)
 {
-	m_unk0x0c = new MxUnknown100dbdbc();
-	m_render = Tgl::CreateRenderer();
-	m_3dView = new Lego3DView();
+	TglSurface::CreateStruct surfaceCreateStruct;
 
-	MxRenderSettings settings;
-	MxRenderSettings::CopyFrom(settings, p_settings);
+	m_viewLODListManager = new ViewLODListManager;
+	m_renderer = Tgl::CreateRenderer();
+	m_3dView = new Lego3DView;
 
-	m_3dView->Init(settings, *m_render);
+	InitializeCreateStruct(surfaceCreateStruct, p_createStruct);
+
+	return m_3dView->Create(surfaceCreateStruct, m_renderer);
 }
 
 // FUNCTION: LEGO1 0x100ab460
@@ -39,8 +56,10 @@ void Lego3DManager::Destroy()
 {
 	delete m_3dView;
 	m_3dView = NULL;
-	delete m_render;
-	m_render = NULL;
-	delete m_unk0x0c;
-	m_unk0x0c = NULL;
+
+	delete m_renderer;
+	m_renderer = NULL;
+
+	delete m_viewLODListManager;
+	m_viewLODListManager = NULL;
 }
diff --git a/LEGO1/lego3dmanager.h b/LEGO1/lego3dmanager.h
index 78c532a5..0a856f90 100644
--- a/LEGO1/lego3dmanager.h
+++ b/LEGO1/lego3dmanager.h
@@ -3,23 +3,39 @@
 
 #include "lego3dview.h"
 
-class MxUnknown100dbdbc;
+class ViewLODListManager;
 
 // VTABLE: LEGO1 0x100dbfa4
 // SIZE 0x10
 class Lego3DManager {
 public:
+	// SIZE 0x28
+	struct CreateStruct {
+		undefined4 m_unk0x00;             // 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
+		IDirect3D* m_direct3d;            // 0x20
+		IDirect3DDevice* m_d3dDevice;     // 0x24
+	};
+
 	Lego3DManager();
 	virtual ~Lego3DManager();
 
+	BOOL Create(CreateStruct& p_createStruct);
+
 	inline Lego3DView* GetLego3DView() { return this->m_3dView; }
+	inline ViewLODListManager* GetViewLODListManager() { return this->m_viewLODListManager; }
 
 private:
-	Tgl::Renderer* m_render;      // 0x04
-	Lego3DView* m_3dView;         // 0x08
-	MxUnknown100dbdbc* m_unk0x0c; // 0x0c
+	Tgl::Renderer* m_renderer;                // 0x04
+	Lego3DView* m_3dView;                     // 0x08
+	ViewLODListManager* m_viewLODListManager; // 0x0c
 
-	void Init(MxRenderSettings& p_settings);
 	void Destroy();
 };
 
diff --git a/LEGO1/lego3dview.cpp b/LEGO1/lego3dview.cpp
index 096e7b9e..efe79db1 100644
--- a/LEGO1/lego3dview.cpp
+++ b/LEGO1/lego3dview.cpp
@@ -16,11 +16,23 @@ Lego3DView::~Lego3DView()
 }
 
 // STUB: LEGO1 0x100aaf90
-MxBool Lego3DView::Init(MxRenderSettings& p_renderSettings, Tgl::Renderer& p_render)
+BOOL Lego3DView::Create(TglSurface::CreateStruct& p_createStruct, Tgl::Renderer* p_renderer)
 {
 	return FALSE;
 }
 
+// STUB: LEGO1 0x100ab100
+void Lego3DView::FUN_100ab100(LegoROI* p_roi)
+{
+	// TODO
+}
+
+// STUB: LEGO1 0x100ab1b0
+void Lego3DView::FUN_100ab1b0(LegoROI* p_roi)
+{
+	// TODO
+}
+
 // STUB: LEGO1 0x100ab2b0
 LegoROI* Lego3DView::PickROI(MxLong p_a, MxLong p_b)
 {
diff --git a/LEGO1/lego3dview.h b/LEGO1/lego3dview.h
index 0681003f..49e64567 100644
--- a/LEGO1/lego3dview.h
+++ b/LEGO1/lego3dview.h
@@ -1,9 +1,9 @@
 #ifndef LEGO3DVIEW_H
 #define LEGO3DVIEW_H
 
-#include "mxrendersettings.h"
 #include "mxtypes.h"
 #include "tgl/d3drm/impl.h"
+#include "tglsurface.h"
 #include "viewmanager/viewmanager.h"
 
 class LegoROI;
@@ -18,8 +18,10 @@ public:
 
 	inline ViewManager* GetViewManager() { return this->m_viewManager; }
 	inline TglImpl::ViewImpl* GetViewPort() { return this->m_viewPort; }
-	MxBool Init(MxRenderSettings& p_renderSettings, Tgl::Renderer& p_render);
+	BOOL Create(TglSurface::CreateStruct& p_createStruct, Tgl::Renderer* p_renderer);
 	LegoROI* PickROI(MxLong p_a, MxLong p_b);
+	void FUN_100ab100(LegoROI* p_roi);
+	void FUN_100ab1b0(LegoROI* p_roi);
 
 private:
 	// TODO: all of these fields are in various base classes
diff --git a/LEGO1/legoomni.cpp b/LEGO1/legoomni.cpp
index 48c7a1f5..f8c6b819 100644
--- a/LEGO1/legoomni.cpp
+++ b/LEGO1/legoomni.cpp
@@ -21,7 +21,6 @@
 #include "mxomnicreateparam.h"
 #include "mxticklemanager.h"
 #include "mxtransitionmanager.h"
-#include "mxunknown100dbdbc.h"
 
 DECOMP_SIZE_ASSERT(LegoWorldList, 0x18);
 
@@ -386,7 +385,7 @@ void LegoOmni::Init()
 	MxOmni::Init();
 	m_unk0x68 = 0;
 	m_inputMgr = NULL;
-	m_renderMgr = NULL;
+	m_viewLODListManager = NULL;
 	m_gifManager = NULL;
 	m_worldList = NULL;
 	m_currentWorld = NULL;
@@ -444,9 +443,9 @@ void LegoOmni::Destroy()
 		m_gifManager = NULL;
 	}
 
-	if (m_renderMgr) {
-		delete m_renderMgr;
-		m_renderMgr = NULL;
+	if (m_viewLODListManager) {
+		delete m_viewLODListManager;
+		m_viewLODListManager = NULL;
 	}
 
 	if (m_inputMgr) {
@@ -524,7 +523,7 @@ MxResult LegoOmni::Create(MxOmniCreateParam& p_param)
 		}
 	}
 
-	m_renderMgr = new MxUnknown100dbdbc();
+	m_viewLODListManager = new ViewLODListManager();
 	m_gifManager = new GifManager();
 	// TODO: there is another class here
 	m_plantManager = new LegoPlantManager();
@@ -533,7 +532,8 @@ MxResult LegoOmni::Create(MxOmniCreateParam& p_param)
 	m_gameState = new LegoGameState();
 	m_worldList = new LegoWorldList(TRUE);
 
-	if (m_renderMgr && m_gifManager && m_worldList && m_plantManager && m_animationManager && m_buildingManager) {
+	if (m_viewLODListManager && m_gifManager && m_worldList && m_plantManager && m_animationManager &&
+		m_buildingManager) {
 		// TODO: initialize a bunch of MxVariables
 		RegisterScripts();
 		FUN_1001a700();
diff --git a/LEGO1/legoomni.h b/LEGO1/legoomni.h
index 2aaba4cc..613ddd85 100644
--- a/LEGO1/legoomni.h
+++ b/LEGO1/legoomni.h
@@ -27,7 +27,7 @@ class MxAtomId;
 class MxBackgroundAudioManager;
 class MxDSFile;
 class MxTransitionManager;
-class MxUnknown100dbdbc;
+class ViewLODListManager;
 
 extern MxAtomId* g_copterScript;
 extern MxAtomId* g_dunecarScript;
@@ -120,7 +120,7 @@ public:
 
 private:
 	undefined4* m_unk0x68;                       // 0x68
-	MxUnknown100dbdbc* m_renderMgr;              // 0x6c
+	ViewLODListManager* m_viewLODListManager;    // 0x6c
 	LegoInputManager* m_inputMgr;                // 0x70
 	GifManager* m_gifManager;                    // 0x74
 	LegoWorldList* m_worldList;                  // 0x78
diff --git a/LEGO1/legoroi.cpp b/LEGO1/legoroi.cpp
index f23901ad..dab06a1a 100644
--- a/LEGO1/legoroi.cpp
+++ b/LEGO1/legoroi.cpp
@@ -2,6 +2,8 @@
 
 #include <string.h>
 
+DECOMP_SIZE_ASSERT(LegoROI, 0x10c);
+
 // SIZE 0x14
 typedef struct {
 	const char* m_name;
@@ -35,6 +37,12 @@ MxS32 g_roiConfig = 100;
 // GLOBAL: LEGO1 0x101013ac
 ROIHandler g_someHandlerFunction = NULL;
 
+// FUNCTION: LEGO1 0x100a46a0
+void LegoROI::WrappedSetLocalTransform(Matrix4Impl& p_transform)
+{
+	SetLocalTransform(p_transform);
+}
+
 // STUB: LEGO1 0x100a46b0
 void LegoROI::FUN_100a46b0(Matrix4Impl& p_transform)
 {
@@ -51,6 +59,12 @@ void LegoROI::configureLegoROI(MxS32 p_roiConfig)
 	g_roiConfig = p_roiConfig;
 }
 
+// STUB: LEGO1 0x100a9a50
+LegoROI::LegoROI(Tgl::Renderer* p_renderer, ViewLODList* p_lodList, MxTime p_time) : ViewROI(p_renderer, p_lodList)
+{
+	m_time = p_time;
+}
+
 // FUNCTION: LEGO1 0x100a9bf0
 MxBool LegoROI::CallTheHandlerFunction(
 	char* p_param,
@@ -104,3 +118,10 @@ void LegoROI::SetDisplayBB(MxS32 p_displayBB)
 {
 	// Intentionally empty function
 }
+
+// Note: Actually part of parent class (doesn't exist yet)
+// STUB: LEGO1 0x100aa350
+void LegoROI::UpdateWorldBoundingVolumes()
+{
+	// TODO
+}
diff --git a/LEGO1/legoroi.h b/LEGO1/legoroi.h
index 74024ce6..d84e8df4 100644
--- a/LEGO1/legoroi.h
+++ b/LEGO1/legoroi.h
@@ -6,8 +6,15 @@
 
 typedef MxBool (*ROIHandler)(char*, char*, MxU32);
 
+// Note: There is an extra class between LegoROI and ViewROI,
+// maybe called "AutoROI". VTABLE 0x100dbe38
+
+// VTABLE: LEGO1 0x100dbea8
+// SIZE 0x10c
 class LegoROI : public ViewROI {
 public:
+	LegoROI(Tgl::Renderer* p_renderer, ViewLODList* p_lodList, MxTime p_time);
+
 	__declspec(dllexport) void SetDisplayBB(MxS32 p_displayBB);
 	__declspec(dllexport) static void configureLegoROI(MxS32 p_roi);
 
@@ -20,8 +27,17 @@ public:
 		MxFloat& p_other
 	);
 	static MxBool ColorAliasLookup(char* p_param, MxFloat& p_red, MxFloat& p_green, MxFloat& p_blue, MxFloat& p_other);
+
+	void WrappedSetLocalTransform(Matrix4Impl& p_transform);
 	void FUN_100a46b0(Matrix4Impl& p_transform);
 	void FUN_100a58f0(Matrix4Impl& p_transform);
+
+	// Note: Actually part of parent class (doesn't exist yet)
+	virtual void UpdateWorldBoundingVolumes() override; // vtable+0x18
+
+private:
+	undefined m_pad[0x28]; // 0xe0
+	MxTime m_time;         // 0x108
 };
 
 #endif // LEGOROI_H
diff --git a/LEGO1/legovideomanager.cpp b/LEGO1/legovideomanager.cpp
index b6a44a79..b061faef 100644
--- a/LEGO1/legovideomanager.cpp
+++ b/LEGO1/legovideomanager.cpp
@@ -1,21 +1,28 @@
 #include "legovideomanager.h"
 
+#include "legoomni.h"
+#include "legoroi.h"
+#include "mxtimer.h"
+#include "realtime/matrix.h"
+#include "viewmanager/viewroi.h"
+
 DECOMP_SIZE_ASSERT(LegoVideoManager, 0x590);
+DECOMP_SIZE_ASSERT(MxStopWatch, 0x18);
 
 // FUNCTION: LEGO1 0x1007aa20
 LegoVideoManager::LegoVideoManager()
 {
-	m_unk0x64 = 0;
+	m_renderer = NULL;
 	m_3dManager = NULL;
-	m_unk0x6c = 0;
+	m_viewROI = NULL;
 	m_direct3d = 0;
 	m_unk0xe6 = FALSE;
 	memset(m_unk0x78, 0, sizeof(m_unk0x78));
 	m_unk0x78[0] = 0x6c;
-	m_unk0x4e8 = 0;
+	m_unk0x100d9d00 = NULL;
 	m_isFullscreenMovie = FALSE;
 	m_palette = NULL;
-	m_prefCounter = NULL;
+	m_stopWatch = NULL;
 	m_cursorMoved = FALSE;
 	m_cursorX = m_cursorY;
 	m_cursorYCopy = m_cursorY;
@@ -37,11 +44,148 @@ LegoVideoManager::~LegoVideoManager()
 	delete m_palette;
 }
 
-// STUB: LEGO1 0x1007ac40
+// STUB: LEGO1 0x1007abb0
+MxResult LegoVideoManager::CreateDirect3D()
+{
+	return SUCCESS;
+}
+
+// FUNCTION: LEGO1 0x1007ac40
 MxResult LegoVideoManager::Create(MxVideoParam& p_videoParam, MxU32 p_frequencyMS, MxBool p_createThread)
 {
-	MxResult result = MxVideoManager::Create(p_videoParam, p_frequencyMS, p_createThread);
-	m_videoParam.GetPalette()->CreateNativePalette();
+	MxBool paletteCreated = FALSE;
+	undefined* und1 = NULL;
+	undefined* und2 = NULL;
+	MxResult result = FAILURE;
+
+	MxDeviceEnumerate100d9cc8 deviceEnumerate;
+	Vector3Data posVec(0.0, 1.25, -50.0);
+	Vector3Data dirVec(0.0, 0.0, 1.0);
+	Vector3Data upVec(0.0, 1.0, 0.0);
+	Matrix4Data outMatrix;
+	HWND hwnd = MxOmni::GetInstance()->GetWindowHandle();
+	MxS32 bits = p_videoParam.Flags().Get16Bit() ? 16 : 8;
+	MxS32 und3 = -1;
+
+	if (!p_videoParam.GetPalette()) {
+		MxPalette* palette = new MxPalette;
+		p_videoParam.SetPalette(palette);
+
+		if (!palette)
+			goto done;
+		paletteCreated = TRUE;
+	}
+
+	PALETTEENTRY paletteEntries[256];
+	p_videoParam.GetPalette()->GetEntries(paletteEntries);
+
+	if (CreateDirect3D() != SUCCESS)
+		goto done;
+
+	if (deviceEnumerate.DoEnumerate() != SUCCESS)
+		goto done;
+
+	if (p_videoParam.GetDeviceName()) {
+		und3 = deviceEnumerate.ParseDeviceName(p_videoParam.GetDeviceName());
+		if (und3 >= 0) {
+			if ((und3 = deviceEnumerate.FUN_1009d030(und3, &und1, &und2)) != SUCCESS)
+				und3 = -1;
+		}
+	}
+
+	if (und3 < 0) {
+		deviceEnumerate.FUN_1009d210();
+		und3 = deviceEnumerate.FUN_1009d0d0();
+		deviceEnumerate.FUN_1009d030(und3, &und1, &und2);
+	}
+
+	m_direct3d->FUN_1009b5f0(deviceEnumerate, und1, und2);
+
+	if (!*((MxU32*) &und1[0x14]) && *((MxU32*) &und1[0xe0]) != 2)
+		p_videoParam.Flags().SetF2bit0(TRUE);
+	else
+		p_videoParam.Flags().SetF2bit0(FALSE);
+
+	ViewROI::SetUnk101013d8(p_videoParam.Flags().GetF2bit0() == FALSE);
+
+	if (!m_direct3d->Create(
+			hwnd,
+			p_videoParam.Flags().GetFullScreen(),
+			p_videoParam.Flags().GetFlipSurfaces(),
+			p_videoParam.Flags().GetBackBuffers() == FALSE,
+			p_videoParam.GetRect().GetWidth(),
+			p_videoParam.GetRect().GetHeight(),
+			bits,
+			paletteEntries,
+			sizeof(paletteEntries) / sizeof(paletteEntries[0])
+		))
+		goto done;
+
+	if (MxVideoManager::VTable0x28(
+			p_videoParam,
+			m_direct3d->GetDirectDraw(),
+			m_direct3d->GetDirect3D(),
+			m_direct3d->GetFrontBuffer(),
+			m_direct3d->GetBackBuffer(),
+			m_direct3d->GetClipper(),
+			p_frequencyMS,
+			p_createThread
+		) != SUCCESS)
+		goto done;
+
+	m_renderer = Tgl::CreateRenderer();
+
+	if (!m_renderer)
+		goto done;
+
+	m_3dManager = new Lego3DManager;
+
+	if (!m_3dManager)
+		goto done;
+
+	Lego3DManager::CreateStruct createStruct;
+	memset(&createStruct, 0, sizeof(createStruct));
+	createStruct.m_hwnd = LegoOmni::GetInstance()->GetWindowHandle();
+	createStruct.m_directDraw = m_pDirectDraw;
+	createStruct.m_ddSurface1 = m_displaySurface->GetDirectDrawSurface1();
+	createStruct.m_ddSurface2 = m_displaySurface->GetDirectDrawSurface2();
+	createStruct.m_ddPalette = m_videoParam.GetPalette()->CreateNativePalette();
+	createStruct.m_isFullScreen = FALSE;
+	createStruct.m_flags = m_videoParam.Flags().GetWideViewAngle();
+	createStruct.m_direct3d = m_direct3d->GetDirect3D();
+	createStruct.m_d3dDevice = m_direct3d->GetDirect3DDevice();
+
+	if (!m_3dManager->Create(createStruct))
+		goto done;
+
+	ViewLODList* pLODList;
+
+	if (FUN_1007c930() != SUCCESS)
+		goto done;
+
+	pLODList = m_3dManager->GetViewLODListManager()->Create("CameraROI", 1);
+	m_viewROI = new LegoROI(m_renderer, pLODList, Timer()->GetTime());
+	pLODList->Release();
+
+	CalcLocalTransform(posVec, dirVec, upVec, outMatrix);
+	m_viewROI->WrappedSetLocalTransform(outMatrix);
+
+	m_3dManager->GetLego3DView()->FUN_100ab100(m_viewROI);
+	m_3dManager->GetLego3DView()->FUN_100ab1b0(m_viewROI);
+
+	m_unk0x100d9d00 = new MxUnknown100d9d00;
+	m_unk0xe4 = FALSE;
+	m_stopWatch = new MxStopWatch;
+	m_stopWatch->Start();
+
+	result = SUCCESS;
+
+done:
+	if (paletteCreated) {
+		delete p_videoParam.GetPalette();
+		p_videoParam.SetPalette(NULL);
+	}
+
 	return result;
 }
 
@@ -59,8 +203,7 @@ void LegoVideoManager::Destroy()
 
 	delete m_3dManager;
 	MxVideoManager::Destroy();
-	// todo: delete m_unk0x4e8
-	delete[] m_prefCounter;
+	delete m_stopWatch;
 }
 
 // FUNCTION: LEGO1 0x1007b6a0
@@ -205,3 +348,9 @@ int LegoVideoManager::DisableRMDevice()
 	// TODO
 	return 0;
 }
+
+// STUB: LEGO1 0x1007c930
+MxResult LegoVideoManager::FUN_1007c930()
+{
+	return SUCCESS;
+}
diff --git a/LEGO1/legovideomanager.h b/LEGO1/legovideomanager.h
index 122505de..1f9c49d0 100644
--- a/LEGO1/legovideomanager.h
+++ b/LEGO1/legovideomanager.h
@@ -4,6 +4,8 @@
 #include "decomp.h"
 #include "lego3dmanager.h"
 #include "mxdirect3d.h"
+#include "mxdirectx/mxstopwatch.h"
+#include "mxunknown100d9d00.h"
 #include "mxvideomanager.h"
 
 #include <ddraw.h>
@@ -29,7 +31,7 @@ public:
 	virtual void VTable0x34(MxU32 p_x, MxU32 p_y, MxU32 p_width, MxU32 p_height) override; // vtable+0x34
 	virtual void VTable0x38(undefined4, undefined4);                                       // vtable+0x38
 	// FUNCTION: LGEO1 0x1007ab10
-	virtual undefined4 VTable0x3c() { return m_unk0x4e8; } // vtable+0x3c
+	virtual MxUnknown100d9d00* VTable0x3c() { return m_unk0x100d9d00; } // vtable+0x3c
 
 	void SetSkyColor(float p_red, float p_green, float p_blue);
 	void OverrideSkyColor(MxBool p_shouldOverride);
@@ -39,9 +41,12 @@ public:
 	inline void SetUnkE4(MxBool p_unk0xe4) { this->m_unk0xe4 = p_unk0xe4; }
 
 private:
-	undefined4 m_unk0x64;
+	MxResult CreateDirect3D();
+	MxResult FUN_1007c930();
+
+	Tgl::Renderer* m_renderer;
 	Lego3DManager* m_3dManager; // 0x68
-	undefined4 m_unk0x6c;
+	LegoROI* m_viewROI;         // 0x6c
 	undefined4 m_unk0x70;
 	MxDirect3D* m_direct3d; // 0x74
 	undefined4 m_unk0x78[27];
@@ -50,10 +55,10 @@ private:
 	MxBool m_unk0xe6;
 	PALETTEENTRY m_paletteEntries[256]; // 0xe7
 	undefined m_padding0x4e7;
-	undefined4 m_unk0x4e8;
-	MxBool m_isFullscreenMovie;   // 0x4ec
-	MxPalette* m_palette;         // 0x4f0
-	LARGE_INTEGER* m_prefCounter; // 0x4f4
+	MxUnknown100d9d00* m_unk0x100d9d00; // 0x4e8
+	MxBool m_isFullscreenMovie;         // 0x4ec
+	MxPalette* m_palette;               // 0x4f0
+	MxStopWatch* m_stopWatch;           // 0x4f4
 	undefined m_padding0x4f4[8];
 	MxBool m_unk0x500;
 	MxBool m_cursorMoved; // 0x501
diff --git a/LEGO1/mxdirect3d.cpp b/LEGO1/mxdirect3d.cpp
index 58a982b3..619dbcb6 100644
--- a/LEGO1/mxdirect3d.cpp
+++ b/LEGO1/mxdirect3d.cpp
@@ -2,9 +2,10 @@
 
 #include <stdio.h> // for vsprintf
 
-DECOMP_SIZE_ASSERT(MxDirect3D, 0x894);
 DECOMP_SIZE_ASSERT(MxDeviceModeFinder, 0xe4);
-DECOMP_SIZE_ASSERT(MxDeviceEnumerate, 0x198);
+DECOMP_SIZE_ASSERT(MxDirect3D, 0x894);
+DECOMP_SIZE_ASSERT(MxDeviceEnumerateElement, 0x190);
+DECOMP_SIZE_ASSERT(MxDeviceEnumerate, 0x14);
 
 // FUNCTION: LEGO1 0x1009b0a0
 MxDirect3D::MxDirect3D()
@@ -85,7 +86,7 @@ void MxDirect3D::Destroy()
 }
 
 // FUNCTION: LEGO1 0x1009b290
-void MxDirect3D::Clear()
+void MxDirect3D::DestroyButNotDirectDraw()
 {
 	if (this->m_pDirect3dDevice) {
 		this->m_pDirect3dDevice->Release();
@@ -122,6 +123,12 @@ BOOL MxDirect3D::D3DSetMode()
 	return TRUE;
 }
 
+// STUB: LEGO1 0x1009b5f0
+BOOL MxDirect3D::FUN_1009b5f0(MxDeviceEnumerate& p_deviceEnumerate, undefined* p_und1, undefined* p_und2)
+{
+	return TRUE;
+}
+
 // FUNCTION: LEGO1 0x1009b8b0
 MxDeviceModeFinder::MxDeviceModeFinder()
 {
@@ -137,6 +144,12 @@ MxDeviceModeFinder::~MxDeviceModeFinder()
 	}
 }
 
+// FUNCTION: LEGO1 0x1009bec0
+MxDeviceEnumerate::MxDeviceEnumerate()
+{
+	m_unk0x10 = FALSE;
+}
+
 // STUB: LEGO1 0x1009c070
 BOOL MxDeviceEnumerate::FUN_1009c070()
 {
@@ -144,14 +157,14 @@ BOOL MxDeviceEnumerate::FUN_1009c070()
 	// HRESULT ret = DirectDrawCreate();
 	HRESULT ret = 0;
 	if (ret) {
-		MxDirect3D::BuildErrorString("GetCaps failed: %s\n", EnumerateErrorToString(ret));
+		BuildErrorString("GetCaps failed: %s\n", EnumerateErrorToString(ret));
 	}
 	// IDirect3D2_EnumDevices
 	return TRUE;
 }
 
 // FUNCTION: LEGO1 0x1009c4c0
-void MxDirect3D::BuildErrorString(const char* p_format, ...)
+void MxDeviceEnumerate::BuildErrorString(const char* p_format, ...)
 {
 	va_list args;
 	char buf[512];
@@ -166,22 +179,21 @@ void MxDirect3D::BuildErrorString(const char* p_format, ...)
 // FUNCTION: LEGO1 0x1009c6c0
 MxResult MxDeviceEnumerate::DoEnumerate()
 {
-	// TODO: what does ECX refer to in this context?
-	if (m_unk0x010)
+	if (m_unk0x10)
 		return FAILURE;
 
 	HRESULT ret = DirectDrawEnumerate(EnumerateCallback, this);
 	if (ret) {
-		MxDirect3D::BuildErrorString("DirectDrawEnumerate returned error %s\n", EnumerateErrorToString(ret));
+		BuildErrorString("DirectDrawEnumerate returned error %s\n", EnumerateErrorToString(ret));
 		return FAILURE;
 	}
 
-	m_unk0x010 = TRUE;
+	m_unk0x10 = TRUE;
 	return SUCCESS;
 }
 
 // STUB: LEGO1 0x1009c710
-BOOL FAR PASCAL EnumerateCallback(GUID FAR*, LPSTR, LPSTR, LPVOID)
+BOOL CALLBACK EnumerateCallback(GUID FAR*, LPSTR, LPSTR, LPVOID)
 {
 	// TODO
 	return FALSE;
@@ -195,3 +207,27 @@ const char* MxDeviceEnumerate::EnumerateErrorToString(HRESULT p_error)
 	// Probably just copied from a sample file in the dx5 sdk.
 	return "";
 }
+
+// STUB: LEGO1 0x1009ce60
+MxS32 MxDeviceEnumerate::ParseDeviceName(const char* p_deviceId)
+{
+	return -1;
+}
+
+// STUB: LEGO1 0x1009d030
+MxResult MxDeviceEnumerate::FUN_1009d030(MxS32 p_und1, undefined** p_und2, undefined** p_und3)
+{
+	return FAILURE;
+}
+
+// STUB: LEGO1 0x1009d0d0
+MxResult MxDeviceEnumerate::FUN_1009d0d0()
+{
+	return FAILURE;
+}
+
+// STUB: LEGO1 0x1009d210
+MxResult MxDeviceEnumerate::FUN_1009d210()
+{
+	return FAILURE;
+}
diff --git a/LEGO1/mxdirect3d.h b/LEGO1/mxdirect3d.h
index 34178023..d22b3873 100644
--- a/LEGO1/mxdirect3d.h
+++ b/LEGO1/mxdirect3d.h
@@ -3,6 +3,7 @@
 
 #include "decomp.h"
 #include "mxdirectdraw.h"
+#include "mxstl/stlcompat.h"
 #include "mxtypes.h"
 
 #include <d3d.h>
@@ -13,40 +14,19 @@ public:
 	MxDeviceModeFinder();
 	~MxDeviceModeFinder();
 
-	undefined4 m_pad[56];
-	MxDirectDraw::DeviceModesInfo* m_deviceInfo; // +0xe0
+	undefined m_pad[0xe0];                       // 0x00
+	MxDirectDraw::DeviceModesInfo* m_deviceInfo; // 0xe0
 };
 
-// VTABLE: LEGO1 0x100db814
-// or is it 0x100d9cc8?
-// SIZE 0x198
-class MxDeviceEnumerate {
-public:
-	MxDeviceEnumerate();
-	virtual MxResult DoEnumerate();
-
-	BOOL FUN_1009c070();
-
-	const char* EnumerateErrorToString(HRESULT p_error);
-
-	undefined4 m_unk0x004;
-	undefined4 m_unk0x008;
-	undefined4 m_unk0x00c;
-	MxBool m_unk0x010; // +0x10
-
-	undefined4 m_unk0x014[97];
-};
+class MxDeviceEnumerate;
 
 // VTABLE: LEGO1 0x100db800
 // SIZE 0x894
 class MxDirect3D : public MxDirectDraw {
 public:
 	MxDirect3D();
-
-	void Clear();
-	inline MxDeviceModeFinder* GetDeviceModeFinder() { return this->m_pDeviceModeFinder; };
-
 	virtual ~MxDirect3D();
+
 	virtual BOOL Create(
 		HWND hWnd,
 		BOOL fullscreen_1,
@@ -57,22 +37,59 @@ public:
 		int bpp,
 		const PALETTEENTRY* pPaletteEntries,
 		int paletteEntryCount
-	);
-	virtual void Destroy();
+	) override;                                      // vtable+0x04
+	virtual void Destroy() override;                 // vtable+0x08
+	virtual void DestroyButNotDirectDraw() override; // vtable+0x0c
 
 	BOOL CreateIDirect3D();
 	BOOL D3DSetMode();
+	BOOL FUN_1009b5f0(MxDeviceEnumerate& p_deviceEnumerate, undefined* p_und1, undefined* p_und2);
+
+	inline MxDeviceModeFinder* GetDeviceModeFinder() { return this->m_pDeviceModeFinder; };
+	inline IDirect3D* GetDirect3D() { return this->m_pDirect3d; }
+	inline IDirect3DDevice* GetDirect3DDevice() { return this->m_pDirect3dDevice; }
+
+private:
+	MxDeviceModeFinder* m_pDeviceModeFinder; // 0x880
+	IDirect3D* m_pDirect3d;                  // 0x884
+	IDirect3DDevice* m_pDirect3dDevice;      // 0x888
+	undefined4 m_unk0x88c;                   // 0x88c
+	undefined4 m_unk0x890;                   // 0x890
+};
+
+// SIZE 0x190
+struct MxDeviceEnumerateElement {
+	undefined m_pad[0x190]; // 0x00
+
+	MxBool operator==(MxDeviceEnumerateElement) const { return TRUE; }
+	MxBool operator<(MxDeviceEnumerateElement) const { return TRUE; }
+};
+
+// VTABLE: LEGO1 0x100db814
+// SIZE 0x14
+class MxDeviceEnumerate {
+public:
+	MxDeviceEnumerate();
+
+	virtual MxResult DoEnumerate(); // vtable+0x00
+
+	BOOL FUN_1009c070();
+	const char* EnumerateErrorToString(HRESULT p_error);
+	MxS32 ParseDeviceName(const char* p_deviceId);
+	MxResult FUN_1009d030(MxS32 p_und1, undefined** p_und2, undefined** p_und3);
+	MxResult FUN_1009d0d0();
+	MxResult FUN_1009d210();
 
 	static void BuildErrorString(const char*, ...);
 
-private:
-	MxDeviceModeFinder* m_pDeviceModeFinder; // +0x880
-	IDirect3D* m_pDirect3d;                  // +0x884
-	IDirect3DDevice* m_pDirect3dDevice;
-	undefined4 m_unk0x88c;
-	undefined4 m_unk0x890;
+	list<MxDeviceEnumerateElement> m_list; // 0x04
+	MxBool m_unk0x10;                      // 0x10
 };
 
-BOOL FAR PASCAL EnumerateCallback(GUID FAR*, LPSTR, LPSTR, LPVOID);
+BOOL CALLBACK EnumerateCallback(GUID FAR*, LPSTR, LPSTR, LPVOID);
+
+// VTABLE: LEGO1 0x100d9cc8
+// SIZE 0x14
+class MxDeviceEnumerate100d9cc8 : public MxDeviceEnumerate {};
 
 #endif // MXDIRECT3D_H
diff --git a/LEGO1/mxdirectdraw.h b/LEGO1/mxdirectdraw.h
index 8c51b220..6d3d190b 100644
--- a/LEGO1/mxdirectdraw.h
+++ b/LEGO1/mxdirectdraw.h
@@ -76,8 +76,8 @@ public:
 	__declspec(dllexport) int Pause(int);
 
 	MxDirectDraw();
-
 	virtual ~MxDirectDraw();
+
 	virtual BOOL Create(
 		HWND hWnd,
 		BOOL fullscreen_1,
@@ -88,10 +88,15 @@ public:
 		int bpp,
 		const PALETTEENTRY* pPaletteEntries,
 		int paletteEntryCount
-	);
-	virtual void Destroy();
-	virtual void DestroyButNotDirectDraw();
-	virtual const char* ErrorToString(HRESULT p_error);
+	);                                                  // vtable+0x04
+	virtual void Destroy();                             // vtable+0x08
+	virtual void DestroyButNotDirectDraw();             // vtable+0x0c
+	virtual const char* ErrorToString(HRESULT p_error); // vtable+0x10
+
+	inline IDirectDraw* GetDirectDraw() { return m_pDirectDraw; }
+	inline IDirectDrawSurface* GetFrontBuffer() { return m_pFrontBuffer; }
+	inline IDirectDrawSurface* GetBackBuffer() { return m_pBackBuffer; }
+	inline IDirectDrawClipper* GetClipper() { return m_pClipper; }
 
 protected:
 	BOOL CacheOriginalPaletteEntries();
diff --git a/LEGO1/mxdirectx/mxstopwatch.h b/LEGO1/mxdirectx/mxstopwatch.h
new file mode 100644
index 00000000..bb37e484
--- /dev/null
+++ b/LEGO1/mxdirectx/mxstopwatch.h
@@ -0,0 +1,179 @@
+#ifndef _MxStopWatch_h
+#define _MxStopWatch_h
+
+#include "assert.h"
+#include "winbase.h"
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// MxStopWatch
+//
+// NOTE:	MxStopWatch measures elapsed (wall clock) time.
+//
+
+class MxStopWatch {
+public:
+	MxStopWatch();
+	~MxStopWatch() {}
+
+	void Start();
+	void Stop();
+	void Reset();
+
+	double ElapsedSeconds() const;
+
+protected:
+	unsigned long TicksPerSeconds() const;
+
+private:
+	LARGE_INTEGER m_startTick;
+	// ??? when we provide LARGE_INTEGER arithmetic, use a
+	//     LARGE_INTEGER m_elapsedTicks rather than m_elapsedSeconds
+	double m_elapsedSeconds;
+	unsigned long m_ticksPerSeconds;
+};
+
+inline MxStopWatch::MxStopWatch()
+{
+	Reset();
+	m_ticksPerSeconds = TicksPerSeconds();
+}
+
+inline void MxStopWatch::Start()
+{
+	QueryPerformanceCounter(&m_startTick);
+}
+
+inline void MxStopWatch::Stop()
+{
+	LARGE_INTEGER endTick;
+	BOOL result;
+
+	result = QueryPerformanceCounter(&endTick);
+	assert(result);
+
+	if (endTick.HighPart != m_startTick.HighPart) {
+		// LARGE_INTEGER arithmetic not yet provided
+		m_elapsedSeconds = HUGE_VAL;
+	}
+	else {
+		m_elapsedSeconds += ((endTick.LowPart - m_startTick.LowPart) / (double) m_ticksPerSeconds);
+	}
+}
+
+inline void MxStopWatch::Reset()
+{
+	m_startTick.LowPart = 0;
+	m_startTick.HighPart = 0;
+	m_elapsedSeconds = 0;
+}
+
+inline unsigned long MxStopWatch::TicksPerSeconds() const
+{
+	LARGE_INTEGER ticksPerSeconds;
+	BOOL result;
+
+	result = QueryPerformanceFrequency(&ticksPerSeconds);
+	assert(result);
+
+	if (ticksPerSeconds.HighPart) {
+		// LARGE_INTEGER arithmetic not yet provided
+
+		// timer is too fast (faster than 32bits/s, i.e. faster than 4GHz)
+		return ULONG_MAX;
+	}
+	else {
+		return ticksPerSeconds.LowPart;
+	}
+}
+
+inline double MxStopWatch::ElapsedSeconds() const
+{
+	return m_elapsedSeconds;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// MxFrequencyMeter
+//
+
+class MxFrequencyMeter {
+public:
+	MxFrequencyMeter();
+
+	void StartOperation();
+	void EndOperation();
+	double Frequency() const;
+	void Reset();
+
+	unsigned long OperationCount() const;
+	double ElapsedSeconds() const;
+
+	void IncreaseOperationCount(unsigned long);
+
+private:
+	unsigned long m_operationCount;
+	MxStopWatch m_stopWatch;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// MxFrequencyMeter implementation
+//
+
+inline MxFrequencyMeter::MxFrequencyMeter() : m_operationCount(0)
+{
+}
+
+inline void MxFrequencyMeter::StartOperation()
+{
+	m_stopWatch.Start();
+}
+
+inline void MxFrequencyMeter::EndOperation()
+{
+	m_stopWatch.Stop();
+	m_operationCount++;
+}
+
+inline double MxFrequencyMeter::Frequency() const
+{
+	double elapsedSeconds = m_stopWatch.ElapsedSeconds();
+
+	if (elapsedSeconds > 0) {
+		return m_operationCount / elapsedSeconds;
+	}
+	else {
+		if (m_operationCount) {
+			// operations performed - no time elapsed
+			return HUGE_VAL;
+		}
+		else {
+			// no operations performed - no time elapsed
+			return 0;
+		}
+	}
+}
+
+inline void MxFrequencyMeter::Reset()
+{
+	m_stopWatch.Reset();
+	m_operationCount = 0;
+}
+
+inline unsigned long MxFrequencyMeter::OperationCount() const
+{
+	return m_operationCount;
+}
+
+inline void MxFrequencyMeter::IncreaseOperationCount(unsigned long delta)
+{
+	m_operationCount += delta;
+}
+
+inline double MxFrequencyMeter::ElapsedSeconds() const
+{
+	return m_stopWatch.ElapsedSeconds();
+}
+
+#endif /* _MxStopWatch_h */
diff --git a/LEGO1/mxrendersettings.cpp b/LEGO1/mxrendersettings.cpp
deleted file mode 100644
index 4d4476ec..00000000
--- a/LEGO1/mxrendersettings.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-#include "mxrendersettings.h"
-
-#include "decomp.h"
-
-DECOMP_SIZE_ASSERT(MxRenderSettings, 0x28)
-
-// FUNCTION: LEGO1 0x100ab2d0
-MxU32 MxRenderSettings::CopyFrom(MxRenderSettings& p_dest, const MxRenderSettings& p_src)
-{
-	p_dest.m_unk0x00 = p_src.m_unk0x00;
-	p_dest.m_hwnd = p_src.m_hwnd;
-	p_dest.m_directDraw = p_src.m_directDraw;
-	p_dest.m_ddSurface1 = p_src.m_ddSurface1;
-	p_dest.m_ddSurface2 = p_src.m_ddSurface2;
-	p_dest.m_flags = p_src.m_flags;
-	p_dest.m_unk0x18 = p_src.m_unk0x18;
-	p_dest.m_flags2 = p_src.m_flags2;
-	p_dest.m_direct3d = p_src.m_direct3d;
-	p_dest.m_d3dDevice = p_src.m_d3dDevice;
-	return 1;
-}
diff --git a/LEGO1/mxrendersettings.h b/LEGO1/mxrendersettings.h
deleted file mode 100644
index 14909ade..00000000
--- a/LEGO1/mxrendersettings.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef MXRENDERSETTINGS_H
-#define MXRENDERSETTINGS_H
-
-#include "decomp.h"
-#include "mxtypes.h"
-
-#include <d3d.h>
-#include <ddraw.h>
-#include <windows.h>
-
-// SIZE 0x28
-struct MxRenderSettings {
-public:
-	static MxU32 CopyFrom(MxRenderSettings& p_dest, const MxRenderSettings& p_src);
-
-	undefined4 m_unk0x00;             // 0x00
-	HWND m_hwnd;                      // 0x04
-	IDirectDraw* m_directDraw;        // 0x08
-	IDirectDrawSurface* m_ddSurface1; // 0x0c
-	IDirectDrawSurface* m_ddSurface2; // 0x10
-	MxU32 m_flags;                    // 0x14
-	undefined4 m_unk0x18;             // 0x18
-	MxU32 m_flags2;                   // 0x1c
-	IDirect3D* m_direct3d;            // 0x20
-	IDirect3DDevice* m_d3dDevice;     // 0x24
-};
-
-#endif // MXRENDERSETTINGS_H
diff --git a/LEGO1/mxstring.h b/LEGO1/mxstring.h
index 13130a70..6d8a9936 100644
--- a/LEGO1/mxstring.h
+++ b/LEGO1/mxstring.h
@@ -4,6 +4,7 @@
 #include "mxcore.h"
 
 // VTABLE: LEGO1 0x100dc110
+// SIZE 0x10
 class MxString : public MxCore {
 public:
 	__declspec(dllexport) MxString(const MxString& p_str);
@@ -22,8 +23,8 @@ public:
 	inline const char* GetData() const { return m_data; }
 
 private:
-	char* m_data;
-	MxU16 m_length;
+	char* m_data;   // 0x08
+	MxU16 m_length; // 0x0c
 };
 
 #endif // MXSTRING_H
diff --git a/LEGO1/mxunknown100d7c88.cpp b/LEGO1/mxunknown100d7c88.cpp
new file mode 100644
index 00000000..04ddbf4f
--- /dev/null
+++ b/LEGO1/mxunknown100d7c88.cpp
@@ -0,0 +1,12 @@
+#include "mxunknown100d7c88.h"
+
+// FUNCTION: LEGO1 0x10044e50
+MxUnknown100d7c88::~MxUnknown100d7c88()
+{
+}
+
+// FUNCTION: LEGO1 0x10044eb0
+MxU32 MxUnknown100d7c88::VTable0x00()
+{
+	return m_unk0x14;
+}
diff --git a/LEGO1/mxunknown100d7c88.h b/LEGO1/mxunknown100d7c88.h
new file mode 100644
index 00000000..eccc6ee4
--- /dev/null
+++ b/LEGO1/mxunknown100d7c88.h
@@ -0,0 +1,19 @@
+#ifndef MXUNKNOWN100D7C88_H
+#define MXUNKNOWN100D7C88_H
+
+#include "decomp.h"
+#include "mxstring.h"
+
+class MxUnknown100d7c88 {
+public:
+	~MxUnknown100d7c88();
+
+	virtual undefined4 VTable0x00(); // vtable+0x00
+									 // More virtual functions
+
+private:
+	MxString m_unk0x04;   // 0x04
+	undefined4 m_unk0x14; // 0x14
+};
+
+#endif // MXUNKNOWN100D7C88_H
diff --git a/LEGO1/mxunknown100d9d00.h b/LEGO1/mxunknown100d9d00.h
new file mode 100644
index 00000000..d5dd456f
--- /dev/null
+++ b/LEGO1/mxunknown100d9d00.h
@@ -0,0 +1,42 @@
+#ifndef MXUNKNOWN100D9D00_H
+#define MXUNKNOWN100D9D00_H
+
+#include "decomp.h"
+#include "mxlist.h"
+#include "mxunknown100d7c88.h"
+
+// VTABLE: LEGO1 0x100d9cd0
+// class MxCollection<MxUnknown100d7c88 *>
+
+// VTABLE: LEGO1 0x100d9ce8
+// class MxList<MxUnknown100d7c88 *>
+
+// VTABLE: LEGO1 0x100d9d00
+// SIZE 0x18
+class MxUnknown100d9d00 : public MxList<MxUnknown100d7c88*> {
+public:
+	MxUnknown100d9d00() { SetDestroy(Destroy); }
+
+	// STUB: LEGO1 0x1007b210
+	virtual MxS8 Compare(MxUnknown100d7c88* p_a, MxUnknown100d7c88* p_b) override { return -1; } // vtable+0x14
+
+	// FUNCTION: LEGO1 0x1007b2e0
+	static void Destroy(MxUnknown100d7c88* p_element) { delete p_element; }
+};
+
+// TEMPLATE: LEGO1 0x1007b300
+// MxCollection<MxUnknown100d7c88 *>::Compare
+
+// TEMPLATE: LEGO1 0x1007b360
+// MxCollection<MxUnknown100d7c88 *>::Destroy
+
+// SYNTHETIC: LEGO1 0x1007b400
+// MxUnknown100d9d00::`scalar deleting destructor'
+
+// SYNTHETIC: LEGO1 0x1007b470
+// MxCollection<MxUnknown100d7c88 *>::`scalar deleting destructor'
+
+// SYNTHETIC: LEGO1 0x1007b4e0
+// MxList<MxUnknown100d7c88 *>::`scalar deleting destructor'
+
+#endif // MXUNKNOWN100D9D00_H
diff --git a/LEGO1/mxunknown100dbdbc.cpp b/LEGO1/mxunknown100dbdbc.cpp
deleted file mode 100644
index 64254f0b..00000000
--- a/LEGO1/mxunknown100dbdbc.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-#include "mxunknown100dbdbc.h"
-
-#include "decomp.h"
-
-DECOMP_SIZE_ASSERT(MxUnknown100dbdbc, 0x14)
-
-// STUB: LEGO1 0x100a6fd0
-MxUnknown100dbdbc::MxUnknown100dbdbc()
-{
-	// TODO
-}
-
-// STUB: LEGO1 0x100a7130
-MxUnknown100dbdbc::~MxUnknown100dbdbc()
-{
-	// TODO
-}
diff --git a/LEGO1/mxunknown100dbdbc.h b/LEGO1/mxunknown100dbdbc.h
deleted file mode 100644
index b5049760..00000000
--- a/LEGO1/mxunknown100dbdbc.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef MXUNKNOWN100DBDBC_H
-#define MXUNKNOWN100DBDBC_H
-
-#include "decomp.h"
-#include "mxtypes.h"
-
-// VTABLE: LEGO1 0x100dbdbc
-// SIZE 0x14
-class MxUnknown100dbdbc {
-public:
-	MxUnknown100dbdbc();
-	virtual ~MxUnknown100dbdbc();
-
-private:
-	undefined m_unk0x4[0x10];
-};
-
-#endif // MXUNKNOWN100DBDBC_H
diff --git a/LEGO1/mxvideomanager.cpp b/LEGO1/mxvideomanager.cpp
index aa2158f0..3ffd8e7a 100644
--- a/LEGO1/mxvideomanager.cpp
+++ b/LEGO1/mxvideomanager.cpp
@@ -28,7 +28,7 @@ MxVideoManager::~MxVideoManager()
 MxResult MxVideoManager::Init()
 {
 	this->m_pDirectDraw = NULL;
-	this->m_pDDSurface = NULL;
+	this->m_pDirect3D = NULL;
 	this->m_displaySurface = NULL;
 	this->m_region = NULL;
 	this->m_videoParam.SetPalette(NULL);
@@ -60,8 +60,8 @@ void MxVideoManager::Destroy(MxBool p_fromDestructor)
 	if (m_unk0x60) {
 		if (m_pDirectDraw)
 			m_pDirectDraw->Release();
-		if (m_pDDSurface)
-			m_pDDSurface->Release();
+		if (m_pDirect3D)
+			m_pDirect3D->Release();
 	}
 
 	Init();
@@ -120,7 +120,7 @@ void MxVideoManager::SortPresenterList()
 MxResult MxVideoManager::VTable0x28(
 	MxVideoParam& p_videoParam,
 	LPDIRECTDRAW p_pDirectDraw,
-	LPDIRECTDRAWSURFACE p_pDDSurface,
+	LPDIRECT3D p_pDirect3D,
 	LPDIRECTDRAWSURFACE p_ddSurface1,
 	LPDIRECTDRAWSURFACE p_ddSurface2,
 	LPDIRECTDRAWCLIPPER p_ddClipper,
@@ -146,7 +146,7 @@ MxResult MxVideoManager::VTable0x28(
 		goto done;
 
 	m_pDirectDraw = p_pDirectDraw;
-	m_pDDSurface = p_pDDSurface;
+	m_pDirect3D = p_pDirect3D;
 
 	MxPalette* palette;
 	if (p_videoParam.GetPalette() == NULL) {
diff --git a/LEGO1/mxvideomanager.h b/LEGO1/mxvideomanager.h
index 8d4d088c..4b458f1b 100644
--- a/LEGO1/mxvideomanager.h
+++ b/LEGO1/mxvideomanager.h
@@ -7,6 +7,8 @@
 #include "mxregion.h"
 #include "mxvideoparam.h"
 
+#include <d3d.h>
+
 // VTABLE: LEGO1 0x100dc810
 // SIZE 0x64
 class MxVideoManager : public MxMediaManager {
@@ -19,7 +21,7 @@ public:
 	virtual MxResult VTable0x28(
 		MxVideoParam& p_videoParam,
 		LPDIRECTDRAW p_pDirectDraw,
-		LPDIRECTDRAWSURFACE p_pDDSurface,
+		LPDIRECT3D p_pDirect3D,
 		LPDIRECTDRAWSURFACE p_ddSurface1,
 		LPDIRECTDRAWSURFACE p_ddSurface2,
 		LPDIRECTDRAWCLIPPER p_ddClipper,
@@ -45,7 +47,7 @@ public:
 protected:
 	MxVideoParam m_videoParam;          // 0x2c
 	LPDIRECTDRAW m_pDirectDraw;         // 0x50
-	LPDIRECTDRAWSURFACE m_pDDSurface;   // 0x54
+	LPDIRECT3D m_pDirect3D;             // 0x54
 	MxDisplaySurface* m_displaySurface; // 0x58
 	MxRegion* m_region;                 // 0x5c
 	MxBool m_unk0x60;                   // 0x60
diff --git a/LEGO1/mxvideoparam.h b/LEGO1/mxvideoparam.h
index 977c0b48..33aecb32 100644
--- a/LEGO1/mxvideoparam.h
+++ b/LEGO1/mxvideoparam.h
@@ -23,7 +23,6 @@ public:
 	);
 	__declspec(dllexport) MxVideoParam& operator=(const MxVideoParam& p_videoParam);
 	__declspec(dllexport) ~MxVideoParam();
-
 	__declspec(dllexport) void SetDeviceName(char* p_deviceId);
 
 	inline MxVideoParamFlags& Flags() { return m_flags; }
@@ -34,6 +33,7 @@ public:
 	inline MxRect32& GetRect() { return this->m_rect; }
 	inline MxPalette* GetPalette() { return this->m_palette; }
 	inline MxU32 GetBackBuffers() { return this->m_backBuffers; }
+	inline char* GetDeviceName() { return this->m_deviceId; }
 
 private:
 	MxRect32 m_rect;           // 0x00
diff --git a/LEGO1/tglsurface.h b/LEGO1/tglsurface.h
new file mode 100644
index 00000000..bafb2fb3
--- /dev/null
+++ b/LEGO1/tglsurface.h
@@ -0,0 +1,27 @@
+#ifndef TGLSURFACE_H
+#define TGLSURFACE_H
+
+#include "decomp.h"
+#include "mxtypes.h"
+
+#include <d3d.h>
+#include <windows.h>
+
+class TglSurface {
+public:
+	// SIZE 0x28
+	struct CreateStruct {
+		undefined4 m_unk0x00;             // 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
+		IDirect3D* m_direct3d;            // 0x20
+		IDirect3DDevice* m_d3dDevice;     // 0x24
+	};
+};
+
+#endif // TGLSURFACE_H
diff --git a/LEGO1/viewmanager/viewlodlist.cpp b/LEGO1/viewmanager/viewlodlist.cpp
new file mode 100644
index 00000000..50628b18
--- /dev/null
+++ b/LEGO1/viewmanager/viewlodlist.cpp
@@ -0,0 +1,28 @@
+#include "viewlodlist.h"
+
+#include "decomp.h"
+
+DECOMP_SIZE_ASSERT(ViewLODListManager, 0x14);
+
+// FUNCTION: LEGO1 0x100a6fd0
+ViewLODListManager::ViewLODListManager()
+{
+}
+
+// STUB: LEGO1 0x100a7130
+ViewLODListManager::~ViewLODListManager()
+{
+	// TODO
+}
+
+// STUB: LEGO1 0x100a72c0
+ViewLODList* ViewLODListManager::Create(const ROIName&, int lodCount)
+{
+	// TODO
+	return NULL;
+}
+
+// STUB: LEGO1 0x100a7680
+void ViewLODListManager::Destroy(ViewLODList* lodList)
+{
+}
diff --git a/LEGO1/viewmanager/viewlodlist.h b/LEGO1/viewmanager/viewlodlist.h
index 5fa31454..fe86f04e 100644
--- a/LEGO1/viewmanager/viewlodlist.h
+++ b/LEGO1/viewmanager/viewlodlist.h
@@ -1,6 +1,7 @@
 #ifndef VIEWLODLIST_H
 #define VIEWLODLIST_H
 
+#include "../mxstl/stlcompat.h"
 #include "../realtime/lodlist.h"
 #include "assert.h"
 #include "compat.h"
@@ -59,6 +60,8 @@ struct ROINameComparator {
 // It stores ViewLODLists under a name, the name of the ROI where
 // the ViewLODList belongs.
 
+// VTABLE: LEGO1 0x100dbdbc
+// SIZE 0x14
 class ViewLODListManager {
 
 	typedef map<ROIName, ViewLODList*, ROINameComparator> ViewLODListMap;
diff --git a/LEGO1/viewmanager/viewroi.cpp b/LEGO1/viewmanager/viewroi.cpp
index bb5dcaab..523814a2 100644
--- a/LEGO1/viewmanager/viewroi.cpp
+++ b/LEGO1/viewmanager/viewroi.cpp
@@ -4,6 +4,9 @@
 
 DECOMP_SIZE_ASSERT(ViewROI, 0xe0)
 
+// GLOBAL: LEGO1 0x101013d8
+undefined g_unk101013d8 = 0;
+
 // FUNCTION: LEGO1 0x100a9eb0
 float ViewROI::IntrinsicImportance() const
 {
@@ -34,9 +37,10 @@ void ViewROI::UpdateWorldData(const Matrix4Data& parent2world)
 	}
 }
 
-inline ViewROI::~ViewROI()
+// FUNCTION: LEGO1 0x100aa500
+undefined ViewROI::SetUnk101013d8(undefined p_flag)
 {
-	// SetLODList() will decrease refCount of LODList
-	SetLODList(0);
-	delete geometry;
+	undefined oldFlag = g_unk101013d8;
+	g_unk101013d8 = p_flag;
+	return oldFlag;
 }
diff --git a/LEGO1/viewmanager/viewroi.h b/LEGO1/viewmanager/viewroi.h
index e54e6113..fb2e8e54 100644
--- a/LEGO1/viewmanager/viewroi.h
+++ b/LEGO1/viewmanager/viewroi.h
@@ -3,6 +3,7 @@
 
 #include "../realtime/orientableroi.h"
 #include "../tgl/tgl.h"
+#include "decomp.h"
 #include "viewlodlist.h"
 
 /*
@@ -10,6 +11,9 @@
 	etc. Basically, anything which can be placed in a scene and manipilated
 	by the view manager is a ViewROI.
 */
+
+// VTABLE: LEGO1 0x100dbe70
+// SIZE 0xe0
 class ViewROI : public OrientableROI {
 public:
 	inline ViewROI(Tgl::Renderer* pRenderer, ViewLODList* lodList)
@@ -17,7 +21,12 @@ public:
 		SetLODList(lodList);
 		geometry = pRenderer->CreateGroup();
 	}
-	inline ~ViewROI();
+	inline ~ViewROI()
+	{
+		// SetLODList() will decrease refCount of LODList
+		SetLODList(0);
+		delete geometry;
+	}
 	inline void SetLODList(ViewLODList* lodList)
 	{
 		// ??? inherently type unsafe - kind of... because, now, ROI
@@ -39,6 +48,8 @@ public:
 	virtual Tgl::Group* GetGeometry();
 	virtual const Tgl::Group* GetGeometry() const;
 
+	static undefined SetUnk101013d8(undefined p_flag);
+
 protected:
 	Tgl::Group* geometry;
 	void UpdateWorldData(const Matrix4Data& parent2world);