diff --git a/Src/Graphics/New3D/backup/16 bit textures native/Texture.cpp b/Src/Graphics/New3D/backup/16 bit textures native/Texture.cpp
deleted file mode 100644
index 770e326..0000000
--- a/Src/Graphics/New3D/backup/16 bit textures native/Texture.cpp	
+++ /dev/null
@@ -1,352 +0,0 @@
-#include "Texture.h"
-#include <stdio.h>
-#include <math.h>
-
-namespace New3D {
-
-Texture::Texture()
-{
-	Reset();
-}
-
-Texture::~Texture()
-{
-	DeleteTexture();		// make sure to have valid context before destroying
-}
-
-void Texture::DeleteTexture()
-{
-	if (m_textureID) {
-		glDeleteTextures(1, &m_textureID);
-		printf("-----> deleting %i %i %i %i %i\n", m_format, m_x, m_y, m_width, m_height);
-		Reset();
-	}
-}
-
-void Texture::Reset()
-{
-	m_x = 0;
-	m_y = 0;
-	m_width = 0;
-	m_height = 0;
-	m_format = 0;
-	m_textureID = 0;
-	m_mirrorU = false;
-	m_mirrorV = false;
-}
-
-void Texture::BindTexture()
-{
-	glBindTexture(GL_TEXTURE_2D, m_textureID);
-}
-
-void Texture::GetCoordinates(UINT16 uIn, UINT16 vIn, float uvScale, float& uOut, float& vOut)
-{
-	uOut = (uIn*uvScale) / m_width;
-	vOut = (vIn*uvScale) / m_height;
-}
-
-void Texture::GetCoordinates(int width, int height, UINT16 uIn, UINT16 vIn, float uvScale, float& uOut, float& vOut)
-{
-	uOut = (uIn*uvScale) / width;
-	vOut = (vIn*uvScale) / height;
-}
-
-void Texture::SetWrapMode(bool mirrorU, bool mirrorV)
-{
-	if (mirrorU != m_mirrorU) {
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mirrorU ? GL_MIRRORED_REPEAT : GL_REPEAT);
-		m_mirrorU = mirrorU;
-	}
-
-	if (mirrorV != m_mirrorV) {
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mirrorV ? GL_MIRRORED_REPEAT : GL_REPEAT);
-		m_mirrorV = mirrorV;
-	}
-}
-
-UINT32 Texture::UploadTexture(const UINT16* src, UINT8* scratch, int format, bool mirrorU, bool mirrorV, int x, int y, int width, int height)
-{
-	int		xi, yi, i;
-	GLubyte	texel;
-	GLubyte	c, a;
-	UINT16* scratch16;
-	GLenum	type;
-
-	if (!src || !scratch) {
-		return 0;		// sanity checking
-	}
-
-	DeleteTexture();	// free any existing texture
-
-	i			= 0;
-	type		= GL_UNSIGNED_BYTE;
-	scratch16	= (UINT16*)scratch;
-
-	switch (format)
-	{
-	default:	// Debug texture
-		for (yi = y; yi < (y + height); yi++)
-		{
-			for (xi = x; xi < (x + width); xi++)
-			{
-				scratch[i++] = 255;	// R
-				scratch[i++] = 0;	// G
-				scratch[i++] = 0;	// B
-				scratch[i++] = 255;	// A
-			}
-		}
-		break;
-
-	case 0:	// T1RGB5 <- correct
-		type = GL_UNSIGNED_SHORT_5_5_5_1;
-		for (yi = y; yi < (y + height); yi++)
-		{
-			for (xi = x; xi < (x + width); xi++)
-			{
-				scratch16[i++] = src[yi * 2048 + xi] << 1 | ((src[yi * 2048 + xi] >> 15) ^ 0x1); // flip alpha
-			}
-		}
-		break;
-
-	case 1:	// Interleaved A4L4 (low byte)
-		for (yi = y; yi < (y + height); yi++)
-		{
-			for (xi = x; xi < (x + width); xi++)
-			{
-				// Interpret as A4L4
-				texel = src[yi * 2048 + xi] & 0xFF;
-				c = (texel & 0xF) * 17;
-				a = (texel >> 4) * 17;
-				scratch[i++] = c;
-				scratch[i++] = c;
-				scratch[i++] = c;
-				scratch[i++] = a;
-			}
-		}
-		break;
-
-	case 2:	// luminance alpha texture <- this one is correct
-		for (yi = y; yi < (y + height); yi++)
-		{
-			for (xi = x; xi < (x + width); xi++)
-			{
-				texel = src[yi * 2048 + xi] & 0xFF;
-				c = ((texel >> 4) & 0xF) * 17;
-				a = (texel & 0xF) * 17;
-				scratch[i++] = c;
-				scratch[i++] = c;
-				scratch[i++] = c;
-				scratch[i++] = a;
-			}
-		}
-		break;
-
-	case 3:	// 8-bit, A4L4 (high byte)
-		for (yi = y; yi < (y + height); yi++)
-		{
-			for (xi = x; xi < (x + width); xi++)
-			{
-				texel = src[yi * 2048 + xi] >> 8;
-				c = (texel & 0xF) * 17;
-				a = (texel >> 4) * 17;
-				scratch[i++] = c;
-				scratch[i++] = c;
-				scratch[i++] = c;
-				scratch[i++] = a;
-			}
-		}
-		break;
-
-	case 4: // 8-bit, L4A4 (high byte)
-
-		for (yi = y; yi < (y + height); yi++)
-		{
-			for (xi = x; xi < (x + width); xi++)
-			{
-				texel = src[yi * 2048 + xi] >> 8;
-				c = ((texel >> 4) & 0xF) * 17;
-				a = (texel & 0xF) * 17;
-				scratch[i++] = c;
-				scratch[i++] = c;
-				scratch[i++] = c;
-				scratch[i++] = a;
-			}
-		}
-		break;
-
-	case 5:	// 8-bit grayscale
-		for (yi = y; yi < (y + height); yi++)
-		{
-			for (xi = x; xi < (x + width); xi++)
-			{
-				texel = src[yi * 2048 + xi] & 0xFF;
-				scratch[i++] = texel;
-				scratch[i++] = texel;
-				scratch[i++] = texel;
-				scratch[i++] = (texel==255 ? 0 : 255);
-			}
-		}
-		break;
-
-	case 6:	// 8-bit grayscale <-- this one is correct
-		for (yi = y; yi < (y + height); yi++)
-		{
-			for (xi = x; xi < (x + width); xi++)
-			{
-				texel = src[yi * 2048 + xi] >> 8;
-				scratch[i++] = texel;
-				scratch[i++] = texel;
-				scratch[i++] = texel;
-				scratch[i++] = (texel == 255 ? 0 : 255);
-			}
-		}
-		break;
-
-	case 7:	// RGBA4
-		type = GL_UNSIGNED_SHORT_4_4_4_4;
-		for (yi = y; yi < (y + height); yi++)
-		{
-			for (xi = x; xi < (x + width); xi++)
-			{
-				scratch16[i++] = src[yi * 2048 + xi];
-			}
-		}
-		break;
-
-		//
-		// 4 bit texture types - all luminance textures (no alpha), only seem to be enabled when contour is enabled ( white = contour value )
-		//
-
-	case 8: // low byte, low nibble
-		for (yi = y; yi < (y + height); yi++)
-		{
-			for (xi = x; xi < (x + width); xi++)
-			{
-				texel = src[yi * 2048 + xi] & 0xFF;
-				c = (texel & 0xF) * 17;
-				scratch[i++] = c;
-				scratch[i++] = c;
-				scratch[i++] = c;
-				scratch[i++] = (c == 255 ? 0 : 255);
-			}
-		}
-		break;
-
-	case 9:	// low byte, high nibble
-		for (yi = y; yi < (y + height); yi++)
-		{
-			for (xi = x; xi < (x + width); xi++)
-			{
-				texel = src[yi * 2048 + xi] & 0xFF;
-				c = ((texel >> 4) & 0xF) * 17;
-				scratch[i++] = c;
-				scratch[i++] = c;
-				scratch[i++] = c;
-				scratch[i++] = (c == 255 ? 0 : 255);
-			}
-		}
-		break;
-
-	case 10:	// high byte, low nibble
-		for (yi = y; yi < (y + height); yi++)
-		{
-			for (xi = x; xi < (x + width); xi++)
-			{
-				texel = src[yi * 2048 + xi] >> 8;
-				c = (texel & 0xF) * 17;
-				scratch[i++] = c;
-				scratch[i++] = c;
-				scratch[i++] = c;
-				scratch[i++] = (c == 255 ? 0 : 255);
-			}
-		}
-		break;
-
-	case 11: // high byte, high nibble
-
-		for (yi = y; yi < (y + height); yi++)
-		{
-			for (xi = x; xi < (x + width); xi++)
-			{
-				texel = src[yi * 2048 + xi] >> 8;
-				c = ((texel >> 4) & 0xF) * 17;
-				scratch[i++] = c;
-				scratch[i++] = c;
-				scratch[i++] = c;
-				scratch[i++] = (c == 255 ? 0 : 255);
-			}
-		}
-		break;
-	}
-
-
-	GLfloat maxAnistrophy;
-
-	glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnistrophy);
-
-	if (maxAnistrophy > 8) {
-		maxAnistrophy = 8.0f;	//anymore than 8 can get expensive for little gain
-	}
-
-	glPixelStorei(GL_UNPACK_ALIGNMENT, 4);	// rgba is always 4 byte aligned
-	glGenTextures(1, &m_textureID);
-	glBindTexture(GL_TEXTURE_2D, m_textureID);
-
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mirrorU ? GL_MIRRORED_REPEAT : GL_REPEAT);	//todo this in shaders?
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mirrorV ? GL_MIRRORED_REPEAT : GL_REPEAT);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
-	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, maxAnistrophy);
-	glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
-	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, type, scratch);
-
-	// assuming successful we can copy details
-
-	m_x = x;
-	m_y = y;
-	m_width = width;
-	m_height = height;
-	m_format = format;
-	m_mirrorU = mirrorU;
-	m_mirrorV = mirrorV;
-
-	printf("create format %i x: %i y: %i width: %i height: %i\n", format, x, y, width, height);
-
-	return m_textureID;
-}
-
-void Texture::GetDetails(int& x, int&y, int& width, int& height, int& format)
-{
-	x = m_x;
-	y = m_y;
-	width = m_width;
-	height = m_height;
-	format = m_format;
-}
-
-bool Texture::Compare(int x, int y, int width, int height, int format)
-{
-	if (m_x == x && m_y == y && m_width == width && m_height == height && m_format == format) {
-		return true;
-	}
-
-	return false;
-}
-
-bool Texture::CheckMapPos(int ax1, int ax2, int ay1, int ay2)
-{
-	int bx1 = m_x;
-	int bx2 = m_x + m_width;
-	int by1 = m_y;
-	int by2 = m_y + m_height;
-
-	if (ax1<bx2 && ax2>bx1 &&
-		ay1<by2 && ay2>by1) {
-		return true;			// rectangles overlap
-	}
-
-	return false;
-}
-
-} // New3D
diff --git a/Src/Graphics/New3D/backup/New3D.cpp b/Src/Graphics/New3D/backup/New3D.cpp
deleted file mode 100644
index 60caeaa..0000000
--- a/Src/Graphics/New3D/backup/New3D.cpp
+++ /dev/null
@@ -1,1415 +0,0 @@
-#include "New3D.h"
-#include "PolyHeader.h"
-#include "Texture.h"
-#include "Vec.h"
-#include <cmath>
-#include <algorithm>
-#include <limits>
-#include "R3DFloat.h"
-
-#define MAX_RAM_POLYS 100000	
-#define MAX_ROM_POLYS 500000
-
-#ifndef M_PI
-#define M_PI 3.14159265359
-#endif
-
-namespace New3D {
-
-CNew3D::CNew3D()
-{
-	m_cullingRAMLo	= nullptr;
-	m_cullingRAMHi	= nullptr;
-	m_polyRAM		= nullptr;
-	m_vrom			= nullptr;
-	m_textureRAM	= nullptr;
-}
-
-CNew3D::~CNew3D()
-{
-	m_vbo.Destroy();
-}
-
-void CNew3D::AttachMemory(const UINT32 *cullingRAMLoPtr, const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr, const UINT32 *vromPtr, const UINT16 *textureRAMPtr)
-{
-	m_cullingRAMLo	= cullingRAMLoPtr;
-	m_cullingRAMHi	= cullingRAMHiPtr;
-	m_polyRAM		= polyRAMPtr;
-	m_vrom			= vromPtr;
-	m_textureRAM	= textureRAMPtr;
-}
-
-void CNew3D::SetStep(int stepID)
-{
-	m_step = stepID;
-
-	if ((m_step != 0x10) && (m_step != 0x15) && (m_step != 0x20) && (m_step != 0x21)) {
-		m_step = 0x10;
-	}
-
-	if (m_step > 0x10) {
-		m_offset = 0;							// culling nodes are 10 words
-		m_vertexFactor = (1.0f / 2048.0f);		// vertices are in 13.11 format
-	}
-	else {
-		m_offset = 2;							// 8 words
-		m_vertexFactor = (1.0f / 128.0f);		// 17.7
-	}
-
-	m_vbo.Create(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(Poly) * (MAX_RAM_POLYS + MAX_ROM_POLYS));
-}
-
-bool CNew3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXResParam, unsigned totalYResParam)
-{
-	// Resolution and offset within physical display area
-	m_xRatio	= xRes / 496.0f;
-	m_yRatio	= yRes / 384.0f;
-	m_xOffs		= xOffset;
-	m_yOffs		= yOffset;
-	m_totalXRes	= totalXResParam;
-	m_totalYRes = totalYResParam;
-
-	m_r3dShader.LoadShader();
-
-	glUseProgram(0);
-
-	return OKAY;	// OKAY ? wtf ..
-}
-
-void CNew3D::UploadTextures(unsigned x, unsigned y, unsigned width, unsigned height)
-{
-	m_texSheet.Invalidate(x, y, width, height);
-}
-
-void CNew3D::RenderScene(int priority, bool alpha)
-{
-	if (alpha) {
-		glEnable(GL_BLEND);
-	}
-
-	for (auto &n : m_nodes) {
-
-		if (n.viewport.priority != priority || n.models.empty()) {
-			continue;
-		}
-
-		std::shared_ptr<Texture> tex1;
-
-		glViewport		(n.viewport.x, n.viewport.y, n.viewport.width, n.viewport.height);
-		glMatrixMode	(GL_PROJECTION);
-		glLoadMatrixf	(n.viewport.projectionMatrix);
-		glMatrixMode	(GL_MODELVIEW);
-
-		m_r3dShader.SetViewportUniforms(&n.viewport);
-
-		for (auto &m : n.models) {
-
-			bool matrixLoaded = false;
-
-			if (m.meshes->empty()) {
-				continue;
-			}
-
-			m_r3dShader.SetModelStates(&m);
-
-			for (auto &mesh : *m.meshes) {
-
-				if (alpha) {
-					if (!mesh.textureAlpha && !mesh.polyAlpha) {
-						continue;
-					}
-				}
-				else {
-					if (mesh.textureAlpha || mesh.polyAlpha) {
-						continue;
-					}
-				}
-
-				if (!matrixLoaded) {
-					glLoadMatrixf(m.modelMat);
-					matrixLoaded = true;		// do this here to stop loading matrices we don't need. Ie when rendering non transparent etc
-				}
-				
-				if (mesh.textured) {
-
-					int x, y;
-					CalcTexOffset(m.textureOffsetX, m.textureOffsetY, m.page, mesh.x, mesh.y, x, y);
-
-					if (tex1 && tex1->Compare(x, y, mesh.width, mesh.height, mesh.format)) {
-						tex1->SetWrapMode(mesh.mirrorU, mesh.mirrorV);	
-					}
-					else {
-						tex1 = m_texSheet.BindTexture(m_textureRAM, mesh.format, mesh.mirrorU, mesh.mirrorV, x, y, mesh.width, mesh.height);
-						if (tex1) {
-							tex1->BindTexture();
-							tex1->SetWrapMode(mesh.mirrorU, mesh.mirrorV);
-						}
-					}
-
-					if (mesh.microTexture) {
-
-						int mX, mY;
-						glActiveTexture(GL_TEXTURE1);
-						m_texSheet.GetMicrotexPos(y / 1024, mesh.microTextureID, mX, mY);
-						auto tex2 = m_texSheet.BindTexture(m_textureRAM, 0, false, false, mX, mY, 128, 128);
-						if (tex2) {
-							tex2->BindTexture();
-						}
-						glActiveTexture(GL_TEXTURE0);
-					}
-				}
-				
-				m_r3dShader.SetMeshUniforms(&mesh);
-				glDrawArrays(GL_TRIANGLES, mesh.vboOffset*3, mesh.triangleCount*3);			// times 3 to convert triangles to vertices
-			}
-		}
-	}
-
-	glDisable(GL_BLEND);
-	glDepthMask(GL_TRUE);
-	glDisable(GL_STENCIL_TEST);
-}
-
-void CNew3D::RenderFrame(void)
-{
-	// release any resources from last frame
-	m_polyBufferRam.clear();	// clear dyanmic model memory buffer
-	m_nodes.clear();		// memory will grow during the object life time, that's fine, no need to shrink to fit
-	m_modelMat.Release();	// would hope we wouldn't need this but no harm in checking
-	m_nodeAttribs.Reset();
-
-	memset(layerMax, 0, sizeof(UINT32) * 4);
-
-	glDepthFunc		(GL_LEQUAL);
-	glEnable		(GL_DEPTH_TEST);
-	glActiveTexture	(GL_TEXTURE0);
-	glEnable		(GL_CULL_FACE);
-	glFrontFace		(GL_CW);
-
-	glStencilFunc	(GL_EQUAL, 0, 0xFF);			// basically stencil test passes if the value is zero
-	glStencilOp		(GL_KEEP, GL_INCR, GL_INCR);	// if the stencil test passes, we incriment the value
-	glStencilMask	(0xFF);
-
-	RenderViewport(0x800000);		// build model structure
-	
-	m_vbo.Bind(true);
-	m_vbo.BufferSubData(MAX_ROM_POLYS*sizeof(Poly), m_polyBufferRam.size()*sizeof(Poly), m_polyBufferRam.data());	// upload all the dynamic data to GPU in one go
-
-	if (m_polyBufferRom.size()) {
-
-		// sync rom memory with vbo
-		int romBytes	= (int)m_polyBufferRom.size() * sizeof(Poly);
-		int vboBytes	= m_vbo.GetSize();
-		int size		= romBytes - vboBytes;
-
-		if (size) {
-			//check we haven't blown up the memory buffers
-			//we will lose rom models for 1 frame is this happens, not the end of the world, as probably won't ever happen anyway
-			if (m_polyBufferRom.size() >= MAX_ROM_POLYS) {
-				m_polyBufferRom.clear();
-				m_romMap.clear();
-				m_vbo.Reset();
-			}
-			else {
-				m_vbo.AppendData(size, &m_polyBufferRom[vboBytes / sizeof(Poly)]);
-			}
-		}
-	}
-	
-	glEnableClientState(GL_VERTEX_ARRAY);
-	glEnableClientState(GL_NORMAL_ARRAY);
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-	glEnableClientState(GL_COLOR_ARRAY);
-
-	// before draw, specify vertex and index arrays with their offsets, offsetof is maybe evil ..
-	glVertexPointer		(3, GL_FLOAT, sizeof(Vertex), 0);
-	glNormalPointer		(GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, normal));
-	glTexCoordPointer	(2, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, texcoords));
-	glColorPointer		(4, GL_UNSIGNED_BYTE, sizeof(Vertex), (void*)offsetof(Vertex, color));
-	
-	m_r3dShader.SetShader(true);
-
-	for (int pri = 0; pri <= 3; pri++) {
-		glClear		(GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
-		RenderScene	(pri, false);
-		RenderScene	(pri, true);
-	}
-
-	m_r3dShader.SetShader(false);		// unbind shader
-	m_vbo.Bind(false);
-
-	glDisable(GL_CULL_FACE);
-	glDisableClientState(GL_VERTEX_ARRAY);
-	glDisableClientState(GL_NORMAL_ARRAY);
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-	glDisableClientState(GL_COLOR_ARRAY);
-
-	printf("layer max %f %f %f %f\n", layerMax[0], layerMax[1], layerMax[2], layerMax[3]);
-}
-
-void CNew3D::BeginFrame(void)
-{
-}
-
-void CNew3D::EndFrame(void)
-{
-}
-
-/******************************************************************************
-Real3D Address Translation
-
-Functions that interpret word-granular Real3D addresses and return pointers.
-******************************************************************************/
-
-// Translates 24-bit culling RAM addresses
-const UINT32* CNew3D::TranslateCullingAddress(UINT32 addr)
-{
-	addr &= 0x00FFFFFF;	// caller should have done this already
-
-	if ((addr >= 0x800000) && (addr < 0x840000)) {
-		return &m_cullingRAMHi[addr & 0x3FFFF];
-	}
-	else if (addr < 0x100000) {
-		return &m_cullingRAMLo[addr];
-	}
-
-	return NULL;
-}
-
-// Translates model references
-const UINT32* CNew3D::TranslateModelAddress(UINT32 modelAddr)
-{
-	modelAddr &= 0x00FFFFFF;	// caller should have done this already
-
-	if (modelAddr < 0x100000) {
-		return &m_polyRAM[modelAddr];
-	}
-	else {
-		return &m_vrom[modelAddr];
-	}
-}
-
-bool CNew3D::DrawModel(UINT32 modelAddr)
-{
-	const UINT32*	modelAddress;
-	bool			cached = false;
-	Model*			m;
-
-	modelAddress = TranslateModelAddress(modelAddr);
-
-	// create a new model to push onto the vector
-	m_nodes.back().models.emplace_back(Model());
-
-	// get the last model in the array
-	m = &m_nodes.back().models.back();
-
-	if (IsVROMModel(modelAddr) && !IsDynamicModel((UINT32*)modelAddress)) {
-
-		// try to find meshes in the rom cache
-
-		m->meshes = m_romMap[modelAddr];	// will create an entry with a null pointer if empty
-
-		if (m->meshes) {
-			cached = true;
-		}
-		else {
-			m->meshes = std::make_shared<std::vector<Mesh>>();
-			m_romMap[modelAddr] = m->meshes;		// store meshes in our rom map here
-		}
-
-		m->dynamic = false;
-	}
-	else {
-		m->meshes = std::make_shared<std::vector<Mesh>>();
-	}
-
-	// copy current model matrix
-	for (int i = 0; i < 16; i++) {
-		m->modelMat[i] = m_modelMat.currentMatrix[i];
-	}
-
-	//calculate determinant
-	m->determinant = Determinant3x3(m_modelMat);
-
-	// update texture offsets
-	m->textureOffsetX = m_nodeAttribs.currentTexOffsetX;
-	m->textureOffsetY = m_nodeAttribs.currentTexOffsetY;
-	m->page = m_nodeAttribs.currentPage;
-
-	if (!cached) {
-		CacheModel(m, modelAddress);
-	}
-
-	return true;
-}
-
-// Descends into a 10-word culling node
-void CNew3D::DescendCullingNode(UINT32 addr)
-{
-	const UINT32	*node, *lodTable;
-	UINT32			matrixOffset, child1Ptr, sibling2Ptr;
-	float			x, y, z;
-	int				tx, ty;
-	BBox			bbox;
-
-	if (m_nodeAttribs.StackLimit()) {
-		return;
-	}
-
-	node = TranslateCullingAddress(addr);
-
-	if (NULL == node) {
-		return;
-	}
-
-	// Extract known fields
-	child1Ptr		= node[0x07 - m_offset] & 0x7FFFFFF;	// mask colour table bits
-	sibling2Ptr		= node[0x08 - m_offset] & 0x1FFFFFF;	// mask colour table bits
-	matrixOffset	= node[0x03 - m_offset] & 0xFFF;
-
-	if ((node[0x00] & 0x07) != 0x06) {						// colour table seems to indicate no siblings
-		if (!(sibling2Ptr & 0x1000000) && sibling2Ptr) {
-			DescendCullingNode(sibling2Ptr);				// no need to mask bit, would already be zero
-		}
-	}
-
-	if ((node[0x00] & 0x04)) {
-		m_colorTableAddr = ((node[0x03 - m_offset] >> 19) << 0) | ((node[0x07 - m_offset] >> 28) << 13) | ((node[0x08 - m_offset] >> 25) << 17);
-		m_colorTableAddr &= 0x000FFFFF; // clamp to 4MB (in words) range
-	}
-
-	x = *(float *)&node[0x04 - m_offset];
-	y = *(float *)&node[0x05 - m_offset];
-	z = *(float *)&node[0x06 - m_offset];
-
-	m_nodeAttribs.Push();	// save current attribs
-
-	if (!m_offset)	// Step 1.5+
-	{
-		tx = 32 * ((node[0x02] >> 7) & 0x3F);
-		ty = 32 * (node[0x02] & 0x1F);
-
-		// apply texture offsets, else retain current ones
-		if ((node[0x02] & 0x8000))	{
-			m_nodeAttribs.currentTexOffsetX = tx;
-			m_nodeAttribs.currentTexOffsetY = ty;
-			m_nodeAttribs.currentPage = (node[0x02] & 0x4000) >> 14;
-		}
-	}
-
-	// Apply matrix and translation
-	m_modelMat.PushMatrix();
-
-	// apply translation vector
-	if ((node[0x00] & 0x10)) {
-		m_modelMat.Translate(x, y, z);
-	}
-	// multiply matrix, if specified
-	else if (matrixOffset) {
-		MultMatrix(matrixOffset,m_modelMat);
-	}
-
-	if (m_nodeAttribs.currentClipStatus != Clip::INSIDE) {
-
-		float distance = R3DFloat::GetFloat16(node[9 - m_offset] & 0xFFFF);
-
-		auto test = node[9 - m_offset] & 0xFFFF;
-
-		CalcBox(distance, bbox);
-		TransformBox(m_modelMat, bbox);
-
-		m_nodeAttribs.currentClipStatus = ClipBox(bbox, m_planes);
-
-		if (m_nodeAttribs.currentClipStatus != Clip::OUTSIDE && test != 0x7fff) {
-
-			for (int i = 0; i < 8; i++) {
-				layerMax[cLayer] = std::max(layerMax[cLayer], std::abs(bbox.points[i][2]));
-			}
-
-		}
-	}
-
-	if (m_nodeAttribs.currentClipStatus != Clip::OUTSIDE) {
-
-		// Descend down first link
-		if ((node[0x00] & 0x08))	// 4-element LOD table
-		{
-			lodTable = TranslateCullingAddress(child1Ptr);
-
-			if (NULL != lodTable) {
-				if ((node[0x03 - m_offset] & 0x20000000)) {
-					DescendCullingNode(lodTable[0] & 0xFFFFFF);
-				}
-				else {
-					DrawModel(lodTable[0] & 0xFFFFFF);	//TODO
-				}
-			}
-		}
-		else {
-			DescendNodePtr(child1Ptr);
-		}
-
-	}
-
-	m_modelMat.PopMatrix();
-
-	// Restore old texture offsets
-	m_nodeAttribs.Pop();
-}
-
-void CNew3D::DescendNodePtr(UINT32 nodeAddr)
-{
-	// Ignore null links
-	if ((nodeAddr & 0x00FFFFFF) == 0) {
-		return;
-	}
-
-	switch ((nodeAddr >> 24) & 0xFF)	// pointer type encoded in upper 8 bits
-	{
-	case 0x00:	// culling node
-		DescendCullingNode(nodeAddr & 0xFFFFFF);
-		break;
-	case 0x01:	// model (perhaps bit 2 is a flag in this case?)
-	case 0x03:
-		DrawModel(nodeAddr & 0xFFFFFF);
-		break;
-	case 0x04:	// pointer list
-		DescendPointerList(nodeAddr & 0xFFFFFF);
-		break;
-	default:
-		break;
-	}
-}
-
-void CNew3D::DescendPointerList(UINT32 addr)
-{
-	const UINT32*	list;
-	UINT32			nodeAddr;
-	int				index;
-
-	list = TranslateCullingAddress(addr);
-
-	if (NULL == list) {
-		return;
-	}
-
-	index = 0;
-
-	while (true) {
-
-		if (list[index] & 0x01000000) {
-			break;	// empty list
-		}
-
-		nodeAddr = list[index] & 0x00FFFFFF;	// clear upper 8 bits to ensure this is processed as a culling node
-
-		DescendCullingNode(nodeAddr);
-
-		if (list[index] & 0x02000000) {
-			break;	// list end
-		}
-
-		index++;
-	}
-}
-
-
-/******************************************************************************
-Matrix Stack
-******************************************************************************/
-
-// Macro to generate column-major (OpenGL) index from y,x subscripts
-#define CMINDEX(y,x)	(x*4+y)
-
-/*
-* MultMatrix():
-*
-* Multiplies the matrix stack by the specified Real3D matrix. The matrix
-* index is a 12-bit number specifying a matrix number relative to the base.
-* The base matrix MUST be set up before calling this function.
-*/
-void CNew3D::MultMatrix(UINT32 matrixOffset, Mat4& mat)
-{
-	GLfloat		m[4*4];
-	const float	*src = &m_matrixBasePtr[matrixOffset * 12];
-
-	if (m_matrixBasePtr == NULL)	// LA Machineguns
-		return;
-
-	m[CMINDEX(0, 0)] = src[3];
-	m[CMINDEX(0, 1)] = src[4];
-	m[CMINDEX(0, 2)] = src[5];
-	m[CMINDEX(0, 3)] = src[0];
-	m[CMINDEX(1, 0)] = src[6];
-	m[CMINDEX(1, 1)] = src[7];
-	m[CMINDEX(1, 2)] = src[8];
-	m[CMINDEX(1, 3)] = src[1];
-	m[CMINDEX(2, 0)] = src[9];
-	m[CMINDEX(2, 1)] = src[10];
-	m[CMINDEX(2, 2)] = src[11];
-	m[CMINDEX(2, 3)] = src[2];
-	m[CMINDEX(3, 0)] = 0.0;
-	m[CMINDEX(3, 1)] = 0.0;
-	m[CMINDEX(3, 2)] = 0.0;
-	m[CMINDEX(3, 3)] = 1.0;
-
-	mat.MultMatrix(m);
-}
-
-/*
-* InitMatrixStack():
-*
-* Initializes the modelview (model space -> view space) matrix stack and
-* Real3D coordinate system. These are the last transforms to be applied (and
-* the first to be defined on the stack) before projection.
-*
-* Model 3 games tend to define the following unusual base matrix:
-*
-*		0	0	-1	0
-*		1	0	0	0
-*		0	-1	0	0
-*		0	0	0	1
-*
-* When this is multiplied by a column vector, the output is:
-*
-*		-Z
-*		X
-*		-Y
-*		1
-*
-* My theory is that the Real3D GPU accepts vectors in Z,X,Y order. The games
-* store everything as X,Y,Z and perform the translation at the end. The Real3D
-* also has Y and Z coordinates opposite of the OpenGL convention. This
-* function inserts a compensating matrix to undo these things.
-*
-* NOTE: This function assumes we are in GL_MODELVIEW matrix mode.
-*/
-
-void CNew3D::InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat)
-{
-	GLfloat m[4 * 4];
-
-	// This matrix converts vectors back from the weird Model 3 Z,X,Y ordering
-	// and also into OpenGL viewspace (-Y,-Z)
-	m[CMINDEX(0, 0)] = 0.0;	m[CMINDEX(0, 1)] = 1.0;	m[CMINDEX(0, 2)] = 0.0;	m[CMINDEX(0, 3)] = 0.0;
-	m[CMINDEX(1, 0)] = 0.0;	m[CMINDEX(1, 1)] = 0.0;	m[CMINDEX(1, 2)] =-1.0; m[CMINDEX(1, 3)] = 0.0;
-	m[CMINDEX(2, 0)] =-1.0; m[CMINDEX(2, 1)] = 0.0;	m[CMINDEX(2, 2)] = 0.0;	m[CMINDEX(2, 3)] = 0.0;
-	m[CMINDEX(3, 0)] = 0.0;	m[CMINDEX(3, 1)] = 0.0;	m[CMINDEX(3, 2)] = 0.0;	m[CMINDEX(3, 3)] = 1.0;
-
-	mat.LoadMatrix(m);
-
-	// Set matrix base address and apply matrix #0 (coordinate system matrix)
-	m_matrixBasePtr = (float *)TranslateCullingAddress(matrixBaseAddr);
-	MultMatrix(0, mat);
-}
-
-// Draws viewports of the given priority
-void CNew3D::RenderViewport(UINT32 addr)
-{
-	static const GLfloat	color[8][3] =
-	{											// RGB1 color translation
-		{ 0.0, 0.0, 0.0 },	// off
-		{ 0.0, 0.0, 1.0 },	// blue
-		{ 0.0, 1.0, 0.0 },	// green
-		{ 0.0, 1.0, 1.0 },	// cyan
-		{ 1.0, 0.0, 0.0 }, 	// red
-		{ 1.0, 0.0, 1.0 },	// purple
-		{ 1.0, 1.0, 0.0 },	// yellow
-		{ 1.0, 1.0, 1.0 }	// white
-	};
-
-	// Translate address and obtain pointer
-	const uint32_t *vpnode = TranslateCullingAddress(addr);
-
-	if (NULL == vpnode) {
-		return;
-	}
-
-	if (vpnode[0x01] == 0) {		// memory probably hasn't been set up yet, abort
-		return;
-	}
-
-	if (!(vpnode[0] & 0x20)) {	// only if viewport enabled
-		uint32_t curPri	= (vpnode[0x00] >> 3) & 3;		// viewport priority
-		uint32_t nodeAddr	= vpnode[0x02];							// scene database node pointer
-
-		// create node object 
-		m_nodes.emplace_back(Node());
-		m_nodes.back().models.reserve(2048);			// create space for models
-
-		// get pointer to its viewport
-		Viewport *vp = &m_nodes.back().viewport;
-
-		vp->priority = curPri;
-
-		cLayer = curPri;
-
-		// Fetch viewport parameters (TO-DO: would rounding make a difference?)
-		int vpX			= (int)(((vpnode[0x1A] & 0xFFFF) / 16.0f) + 0.5f);		// viewport X (12.4 fixed point)
-		int vpY			= (int)(((vpnode[0x1A] >> 16) / 16.0f) + 0.5f);			// viewport Y (12.4)
-		int vpWidth		= (int)(((vpnode[0x14] & 0xFFFF) / 4.0f) + 0.5f);		// width (14.2)
-		int vpHeight	= (int)(((vpnode[0x14] >> 16) / 4.0f) + 0.5f);			// height (14.2)
-		uint32_t matrixBase	= vpnode[0x16] & 0xFFFFFF;							// matrix base address
-
-		if (vpX) {
-			vpX += 2;
-		}
-
-		if (vpY) {
-			vpY += 2;
-		}
-
-		LODBlendTable* tableTest = (LODBlendTable*)TranslateCullingAddress(vpnode[0x17]);
-
-		float angle_left	= -atan2(*(float *)&vpnode[12],  *(float *)&vpnode[13]);
-		float angle_right	=  atan2(*(float *)&vpnode[16], -*(float *)&vpnode[17]);
-		float angle_top		=  atan2(*(float *)&vpnode[14],  *(float *)&vpnode[15]);
-		float angle_bottom	= -atan2(*(float *)&vpnode[18], -*(float *)&vpnode[19]);
-
-		float near = 10.5f;
-		float far = 1e6;
-		//float far = 13696.f;
-
-		if (m_step == 0x10) {
-			near = 8;
-		}
-
-		//near = 5.02f;
-		//far = 20000;
-
-		float l = near * tanf(angle_left);
-		float r = near * tanf(angle_right);
-		float t = near * tanf(angle_top);
-		float b = near * tanf(angle_bottom);
-
-		// TO-DO: investigate clipping near/far planes
-
-		if ((vpX == 0) && (vpWidth >= 495) && (vpY == 0) && (vpHeight >= 383))
-		{
-			float windowAR		= (float)m_totalXRes / (float)m_totalYRes;
-			float originalAR	= 496 / 384.f;
-			float correction	= windowAR / originalAR;	// expand horizontal frustum planes
-
-			vp->x		= 0;
-			vp->y		= m_yOffs + (GLint)((float)(384 - (vpY + vpHeight))*m_yRatio);
-			vp->width	= m_totalXRes;
-			vp->height	= (GLint)((float)vpHeight*m_yRatio);
-
-			vp->projectionMatrix.Frustum(l*correction, r*correction, b, t, near, far);
-		}
-		else
-		{
-			vp->x		= m_xOffs + (GLint)((float)vpX*m_xRatio);
-			vp->y		= m_yOffs + (GLint)((float)(384 - (vpY + vpHeight))*m_yRatio);
-			vp->width	= (GLint)((float)vpWidth*m_xRatio);
-			vp->height	= (GLint)((float)vpHeight*m_yRatio);
-
-			vp->projectionMatrix.Frustum(l, r, b, t, near, far);
-		}
-
-		// calculate frustum planes
-		CalcFrustumPlanes(m_planes, vp->projectionMatrix);
-
-		// Lighting (note that sun vector points toward sun -- away from vertex)
-		vp->lightingParams[0] = *(float *)&vpnode[0x05];								// sun X
-		vp->lightingParams[1] = *(float *)&vpnode[0x06];								// sun Y
-		vp->lightingParams[2] = *(float *)&vpnode[0x04];								// sun Z
-		vp->lightingParams[3] = *(float *)&vpnode[0x07];								// sun intensity
-		vp->lightingParams[4] = (float)((vpnode[0x24] >> 8) & 0xFF) * (1.0f / 255.0f);	// ambient intensity
-		vp->lightingParams[5] = 0.0;	// reserved
-
-		// Spotlight
-		int spotColorIdx = (vpnode[0x20] >> 11) & 7;									// spotlight color index
-		vp->spotEllipse[0] = (float)((vpnode[0x1E] >> 3) & 0x1FFF);						// spotlight X position (fractional component?)
-		vp->spotEllipse[1] = (float)((vpnode[0x1D] >> 3) & 0x1FFF);						// spotlight Y
-		vp->spotEllipse[2] = (float)((vpnode[0x1E] >> 16) & 0xFFFF);					// spotlight X size (16-bit? May have fractional component below bit 16)
-		vp->spotEllipse[3] = (float)((vpnode[0x1D] >> 16) & 0xFFFF);					// spotlight Y size
-
-		vp->spotRange[0] = 1.0f / (*(float *)&vpnode[0x21]);							// spotlight start
-		vp->spotRange[1] = *(float *)&vpnode[0x1F];										// spotlight extent
-
-		if (vp->spotRange[1] == 0) {													// if light extent = 0 light is effectively disabled
-			spotColorIdx = 0;															
-		}
-
-		vp->spotColor[0] = color[spotColorIdx][0];										// spotlight color
-		vp->spotColor[1] = color[spotColorIdx][1];
-		vp->spotColor[2] = color[spotColorIdx][2];
-
-		// Spotlight is applied on a per pixel basis, must scale its position and size to screen
-		vp->spotEllipse[1] = 384.0f - vp->spotEllipse[1];
-		vp->spotRange[1] += vp->spotRange[0];	// limit
-		vp->spotEllipse[2] = 496.0f / sqrt(vp->spotEllipse[2]);	// spotlight appears to be specified in terms of physical resolution (unconfirmed)
-		vp->spotEllipse[3] = 384.0f / sqrt(vp->spotEllipse[3]);
-
-		// Scale the spotlight to the OpenGL viewport
-		vp->spotEllipse[0] = vp->spotEllipse[0] * m_xRatio + m_xOffs;
-		vp->spotEllipse[1] = vp->spotEllipse[1] * m_yRatio + m_yOffs;
-		vp->spotEllipse[2] *= m_xRatio;
-		vp->spotEllipse[3] *= m_yRatio;
-
-		// Fog
-		vp->fogParams[0] = (float)((vpnode[0x22] >> 16) & 0xFF) * (1.0f / 255.0f);	// fog color R
-		vp->fogParams[1] = (float)((vpnode[0x22] >> 8) & 0xFF) * (1.0f / 255.0f);	// fog color G
-		vp->fogParams[2] = (float)((vpnode[0x22] >> 0) & 0xFF) * (1.0f / 255.0f);	// fog color B
-		vp->fogParams[3] = *(float *)&vpnode[0x23];									// fog density
-		vp->fogParams[4] = (float)(INT16)(vpnode[0x25] & 0xFFFF)*(1.0f / 255.0f);	// fog start
-
-		{
-			//test fog paramaters
-			float lightFogColour[3];
-			int fogColourIdx;
-
-			fogColourIdx = (vpnode[0x20] >> 8) & 7;
-
-			lightFogColour[0] = color[fogColourIdx][0];
-			lightFogColour[1] = color[fogColourIdx][1];
-			lightFogColour[2] = color[fogColourIdx][2];
-
-			float fogAttenuation = ((vpnode[0x24] >> 16) & 0xFF) / 255.f;
-			float fogAmbient	 = ((vpnode[0x25] >> 16) & 0xFF) / 255.f;
-			int debug = 0;
-		}
-		
-		if (std::isinf(vp->fogParams[3]) || std::isnan(vp->fogParams[3]) || std::isinf(vp->fogParams[4]) || std::isnan(vp->fogParams[4])) {	// Star Wars Trilogy
-			vp->fogParams[3] = vp->fogParams[4] = 0.0f;
-		}
-
-		// Unknown light/fog parameters
-		float scrollFog = (float)(vpnode[0x20] & 0xFF) * (1.0f / 255.0f);	// scroll fog
-		float scrollAtt = (float)(vpnode[0x24] & 0xFF) * (1.0f / 255.0f);	// scroll attenuation
-
-		// Clear texture offsets before proceeding
-		m_nodeAttribs.Reset();
-
-		// Set up coordinate system and base matrix
-		InitMatrixStack(matrixBase, m_modelMat);
-
-		// Safeguard: weird coordinate system matrices usually indicate scenes that will choke the renderer
-		if (NULL != m_matrixBasePtr)
-		{
-			float	m21, m32, m13;
-
-			// Get the three elements that are usually set and see if their magnitudes are 1
-			m21 = m_matrixBasePtr[6];
-			m32 = m_matrixBasePtr[10];
-			m13 = m_matrixBasePtr[5];
-
-			m21 *= m21;
-			m32 *= m32;
-			m13 *= m13;
-
-			if ((m21>1.05) || (m21<0.95))
-				return;
-			if ((m32>1.05) || (m32<0.95))
-				return;
-			if ((m13>1.05) || (m13<0.95))
-				return;
-		}
-
-		// Descend down the node link: Use recursive traversal
-		DescendNodePtr(nodeAddr);
-	}
-
-	// render next viewport
-	if (vpnode[0x01] != 0x01000000) {
-		RenderViewport(vpnode[0x01]);
-	}
-}
-
-void CNew3D::CopyVertexData(const R3DPoly& r3dPoly, std::vector<Poly>& polyArray)
-{
-	//====================
-	Poly		p;
-	V3::Vec3	normal;
-	float		dotProd;
-	bool		clockWise;
-	//====================
-
-	V3::createNormal(r3dPoly.v[0].pos, r3dPoly.v[1].pos, r3dPoly.v[2].pos, normal);
-
-	dotProd		= V3::dotProduct(normal, r3dPoly.faceNormal);
-	clockWise	= dotProd >= 0.0;
-
-	if (clockWise) {
-		p.p1 = r3dPoly.v[0];
-		p.p2 = r3dPoly.v[1];
-		p.p3 = r3dPoly.v[2];
-	}
-	else {
-		p.p1 = r3dPoly.v[2];
-		p.p2 = r3dPoly.v[1];
-		p.p3 = r3dPoly.v[0];
-	}
-
-	//multiply face attributes with vertex attributes if required
-	for (int i = 0; i < 4; i++) {
-		p.p1.color[i] = (UINT8)(p.p1.color[i] * r3dPoly.faceColour[i]);
-		p.p2.color[i] = (UINT8)(p.p2.color[i] * r3dPoly.faceColour[i]);
-		p.p3.color[i] = (UINT8)(p.p3.color[i] * r3dPoly.faceColour[i]);
-	}
-	
-	polyArray.emplace_back(p);
-
-	if (r3dPoly.number == 4) {
-
-		if (clockWise) {
-			p.p1 = r3dPoly.v[0];
-			p.p2 = r3dPoly.v[2];
-			p.p3 = r3dPoly.v[3];
-		}
-		else {
-			p.p1 = r3dPoly.v[0];
-			p.p2 = r3dPoly.v[3];
-			p.p3 = r3dPoly.v[2];
-		}
-
-		//multiply face attributes with vertex attributes if required
-		for (int i = 0; i < 4; i++) {
-			p.p1.color[i] = (UINT8)(p.p1.color[i] * r3dPoly.faceColour[i]);
-			p.p2.color[i] = (UINT8)(p.p2.color[i] * r3dPoly.faceColour[i]);
-			p.p3.color[i] = (UINT8)(p.p3.color[i] * r3dPoly.faceColour[i]);
-		}
-
-		polyArray.emplace_back(p);
-	}
-}
-
-// non smooth texturing on the pro-1000 seems to sample like gl_nearest
-// ie not outside of the texture coordinates, but with bilinear filtering
-// this is about as close as we can emulate in hardware
-// if we don't do this with gl_repeat enabled, it will wrap around and sample the 
-// other side of the texture which produces ugly seems
-void CNew3D::OffsetTexCoords(R3DPoly& r3dPoly, float offset[2])
-{
-	for (int i = 0; i < 2; i++) {
-
-		float min =  std::numeric_limits<float>::max();
-		float max = -std::numeric_limits<float>::max();
-
-		if (!offset[i]) continue;
-
-		for (int j = 0; j < r3dPoly.number; j++) {
-			min = std::min(r3dPoly.v[j].texcoords[i], min);
-			max = std::max(r3dPoly.v[j].texcoords[i], max);
-		}
-
-		float fTemp;
-		float iTemp;
-		bool fractMin;
-		bool fractMax;
-		
-		fTemp		= std::modf(min, &iTemp);
-		fractMin	= fTemp > 0;
-
-		fTemp		= std::modf(max, &iTemp);
-		fractMax	= fTemp > 0;
-
-		for (int j = 0; j < r3dPoly.number && min != max; j++) {
-
-			if (!fractMin) {
-				if (r3dPoly.v[j].texcoords[i] == min) {
-					r3dPoly.v[j].texcoords[i] += offset[i];
-				}
-			}
-
-			if (!fractMax) {
-				if (r3dPoly.v[j].texcoords[i] == max) {
-					r3dPoly.v[j].texcoords[i] -= offset[i];
-				}
-			}
-		}
-	}
-}
-
-void CNew3D::CacheModel(Model *m, const UINT32 *data)
-{
-	Vertex			prev[4];
-	PolyHeader		ph;
-	int				numPolys	= 0;
-	UINT64			lastHash	= -1;
-	SortingMesh*	currentMesh = nullptr;
-	
-	std::map<UINT64, SortingMesh> sMap;
-
-	if (data == NULL)
-		return;
-
-	ph = data; 
-	int numTriangles = ph.NumTrianglesTotal();
-
-	// Cache all polygons
-	do {
-
-		R3DPoly		p;					// current polygon
-		GLfloat		uvScale;
-		int			i, j;
-
-		if (ph.header[6] == 0) {
-			break;
-		}
-
-		if (ph.Disabled() || !numPolys && (ph.NumSharedVerts() != 0)) {
-			continue;
-		}
-
-		// create a hash value based on poly attributes -todo add more attributes
-		auto hash = ph.Hash();
-
-		if (hash != lastHash) {
-
-			if (sMap.count(hash) == 0) {
-
-				sMap[hash] = SortingMesh();
-
-				currentMesh = &sMap[hash];
-
-				//make space for our vertices
-				currentMesh->polys.reserve(numTriangles);
-
-				//copy attributes
-				currentMesh->doubleSided	= false;			// we will double up polys
-				currentMesh->textured		= ph.TexEnabled();
-				currentMesh->alphaTest		= ph.AlphaTest();
-				currentMesh->textureAlpha	= ph.TextureAlpha();
-				currentMesh->polyAlpha		= ph.PolyAlpha();
-				currentMesh->lighting		= ph.LightEnabled() && !ph.FixedShading();
-
-				if (ph.Layered() || (!ph.TexEnabled() && ph.PolyAlpha())) {
-					currentMesh->layered = true;
-				}
-				
-				if (currentMesh->lighting) {
-					if (ph.SpecularEnabled()) {
-						currentMesh->specular = true;
-						currentMesh->shininess = 0;// ph.Shininess();
-						currentMesh->specularCoefficient = 0; // ph.SpecularValue();
-					}
-				}
-	
-				currentMesh->fogIntensity = ph.LightModifier();
-
-				if (ph.TexEnabled()) {
-					currentMesh->format			= m_texSheet.GetTexFormat(ph.TexFormat(), ph.AlphaTest());
-
-					if (currentMesh->format == 7) {
-						currentMesh-> alphaTest = false;	// alpha test is a 1 bit test, this format needs a lower threshold, since it has 16 levels of transparency
-					}
-
-					currentMesh->x				= ph.X();
-					currentMesh->y				= ph.Y();
-					currentMesh->width			= ph.TexWidth();
-					currentMesh->height			= ph.TexHeight();
-					currentMesh->mirrorU		= ph.TexUMirror();
-					currentMesh->mirrorV		= ph.TexVMirror();
-					currentMesh->microTexture	= ph.MicroTexture();
-					currentMesh->microTextureID = ph.MicroTextureID();
-				}
-			}
-
-			currentMesh = &sMap[hash];
-		}
-
-		lastHash = hash;		
-
-		// Obtain basic polygon parameters
-		p.number	= ph.NumVerts();
-		uvScale		= ph.UVScale();
-
-		ph.FaceNormal(p.faceNormal);
-
-		// Fetch reused vertices according to bitfield, then new verts
-		i = 0;
-		j = 0;
-		for (i = 0; i < 4; i++)		// up to 4 reused vertices
-		{
-			if (ph.SharedVertex(i))
-			{
-				p.v[j] = prev[i];
-				++j;
-			}
-		}
-
-		// copy face attributes
-
-		if ((ph.header[1] & 2) == 0) {
-			int colorIdx = ph.ColorIndex();
-			p.faceColour[2] = (m_polyRAM[m_colorTableAddr + colorIdx] & 0xFF) / 255.f;
-			p.faceColour[1] = ((m_polyRAM[m_colorTableAddr + colorIdx] >> 8) & 0xFF) / 255.f;
-			p.faceColour[0] = ((m_polyRAM[m_colorTableAddr + colorIdx] >> 16) & 0xFF) / 255.f;
-		}
-		else {
-			if (ph.ColorDisabled()) {		// no colours were set
-				p.faceColour[0] = 1.0f;
-				p.faceColour[1] = 1.0f;
-				p.faceColour[2] = 1.0f;
-			}
-			else {
-				p.faceColour[0] = ((ph.header[4] >> 24)) / 255.f;
-				p.faceColour[1] = ((ph.header[4] >> 16) & 0xFF) / 255.f;
-				p.faceColour[2] = ((ph.header[4] >> 8) & 0xFF) / 255.f;
-			}
-		}
-
-		if (cLayer == 3) {
-			p.faceColour[0] = 1;
-			p.faceColour[1] = 0;
-			p.faceColour[2] = 0;
-		}
-
-		p.faceColour[3] = ph.Transparency() / 255.f;
-				
-		// if we have flat shading, we can't re-use normals from shared vertices
-		for (i = 0; i < p.number && !ph.SmoothShading(); i++) {
-			p.v[i].normal[0] = p.faceNormal[0];
-			p.v[i].normal[1] = p.faceNormal[1];
-			p.v[i].normal[2] = p.faceNormal[2];
-		}
-
-		UINT32* vData = ph.StartOfData();	// vertex data starts here
-
-		// remaining vertices are new and defined here
-		for (; j < p.number; j++)	
-		{
-			// Fetch vertices
-			UINT32 ix = vData[0];
-			UINT32 iy = vData[1];
-			UINT32 iz = vData[2];
-			UINT32 it = vData[3];
-
-			// Decode vertices
-			p.v[j].pos[0] = (GLfloat)(((INT32)ix) >> 8) * m_vertexFactor;
-			p.v[j].pos[1] = (GLfloat)(((INT32)iy) >> 8) * m_vertexFactor;
-			p.v[j].pos[2] = (GLfloat)(((INT32)iz) >> 8) * m_vertexFactor;
-
-			// Per vertex normals
-			if (ph.SmoothShading()) {
-				p.v[j].normal[0] = (INT8)(ix & 0xFF) / 128.f;
-				p.v[j].normal[1] = (INT8)(iy & 0xFF) / 128.f;
-				p.v[j].normal[2] = (INT8)(iz & 0xFF) / 128.f;
-			}
-
-			if (ph.FixedShading() && ph.LightEnabled()) {
-				UINT8 shade = (UINT8)((ix + 128) & 0xFF);
-				p.v[j].color[0] = shade;	// hardware doesn't really have per vertex colours, only per poly
-				p.v[j].color[1] = shade;
-				p.v[j].color[2] = shade;
-				p.v[j].color[3] = 255;
-			}
-			else {
-				p.v[j].color[0] = 255;
-				p.v[j].color[1] = 255;
-				p.v[j].color[2] = 255;
-				p.v[j].color[3] = 255;
-			}
-
-			float texU, texV = 0;
-
-			// tex coords
-			if (currentMesh->textured) {
-				Texture::GetCoordinates(currentMesh->width, currentMesh->height, (UINT16)(it >> 16), (UINT16)(it & 0xFFFF), uvScale, texU, texV);
-			}
-
-			p.v[j].texcoords[0] = texU;
-			p.v[j].texcoords[1] = texV;
-
-			vData += 4;
-		}
-
-		// check if we need to modify the texture coordinates
-		{
-			float offset[2] = { 0 };
-
-			if (ph.TexEnabled()) {
-
-				if (!ph.TexSmoothU() && !ph.TexUMirror()) {
-					offset[0] = 0.5f / ph.TexWidth();	// half texel
-				}
-
-				if (!ph.TexSmoothV() && !ph.TexVMirror()) {
-					offset[1] = 0.5f / ph.TexHeight();	// half texel
-				}
-
-				OffsetTexCoords(p, offset);
-			}
-		}
-
-		// check if we need double up vertices for two sided lighting
-		if (ph.DoubleSided()) {
-
-			R3DPoly tempP = p;
-
-			// flip normals
-			V3::inverse(tempP.faceNormal);
-
-			for (int i = 0; i < tempP.number; i++) {
-				V3::inverse(tempP.v[i].normal);
-			}
-
-			CopyVertexData(tempP, currentMesh->polys);
-		}
-
-		// Copy this polygon into the model buffer
-		CopyVertexData(p, currentMesh->polys);
-		numPolys++;
-		
-		// Copy current vertices into previous vertex array
-		for (i = 0; i < 4; i++) {
-			prev[i] = p.v[i];
-		}
-
-	} while (ph.NextPoly());
-
-	//sorted the data, now copy to main data structures
-
-	// we know how many meshes we have so reserve appropriate space
-	m->meshes->reserve(sMap.size());
-
-	for (auto& it : sMap) {
-
-		if (m->dynamic) {
-
-			// calculate VBO values for current mesh
-			it.second.vboOffset		= m_polyBufferRam.size() + MAX_ROM_POLYS;
-			it.second.triangleCount = it.second.polys.size();
-
-			// copy poly data to main buffer
-			m_polyBufferRam.insert(m_polyBufferRam.end(), it.second.polys.begin(), it.second.polys.end());
-		}
-		else {
-			// calculate VBO values for current mesh
-			it.second.vboOffset		= m_polyBufferRom.size();
-			it.second.triangleCount = it.second.polys.size();
-
-			// copy poly data to main buffer
-			m_polyBufferRom.insert(m_polyBufferRom.end(), it.second.polys.begin(), it.second.polys.end());
-		}
-
-		//copy the temp mesh into the model structure
-		//this will lose the associated vertex data, which is now copied to the main buffer anyway
-		m->meshes->push_back(it.second);
-	}
-}
-
-float CNew3D::Determinant3x3(const float m[16]) {
-
-	/*
-		| A B C |
-	M = | D E F |
-		| G H I |
-
-	then the determinant is calculated as follows:
-
-	det M = A * (EI - HF) - B * (DI - GF) + C * (DH - GE)
-	*/
-
-	return m[0] * ((m[5] * m[10]) - (m[6] * m[9])) - m[4] * ((m[1] * m[10]) - (m[2] * m[9])) + m[8] * ((m[1] * m[6]) - (m[2] * m[5]));
-}
-
-bool CNew3D::IsDynamicModel(UINT32 *data)
-{
-	if (data == NULL) {
-		return false;
-	}
-
-	PolyHeader p(data);
-
-	do {
-
-		if ((p.header[1] & 2) == 0) {		// model has rgb colour palette 
-			return true;
-		}
-
-		if (p.header[6] == 0) {
-			break;
-		}
-
-	} while (p.NextPoly());
-
-	return false;
-}
-
-bool CNew3D::IsVROMModel(UINT32 modelAddr)
-{
-	return modelAddr >= 0x100000;
-}
-
-void CNew3D::CalcTexOffset(int offX, int offY, int page, int x, int y, int& newX, int& newY)
-{
-	newX = (x + offX) & 2047;	// wrap around 2048, shouldn't be required
-
-	int oldPage = y / 1024;
-
-	y -= (oldPage * 1024);	// remove page from tex y
-
-	// calc newY with wrap around, wraps around in the same sheet, not into another memory sheet
-
-	newY = (y + offY) & 1023;
-
-	// add page to Y
-
-	newY += ((oldPage + page) & 1) * 1024;		// max page 0-1
-}
-
-void CNew3D::CalcFrustumPlanes(Plane p[6], const float* matrix)
-{
-	// Left Plane
-	p[0].a = matrix[3] + matrix[0];
-	p[0].b = matrix[7] + matrix[4];
-	p[0].c = matrix[11] + matrix[8];
-	p[0].d = matrix[15] + matrix[12];
-	p[0].Normalise();
-
-	// Right Plane
-	p[1].a = matrix[3] - matrix[0];
-	p[1].b = matrix[7] - matrix[4];
-	p[1].c = matrix[11] - matrix[8];
-	p[1].d = matrix[15] - matrix[12];
-	p[1].Normalise();
-
-	// Bottom Plane
-	p[2].a = matrix[3] + matrix[1];
-	p[2].b = matrix[7] + matrix[5];
-	p[2].c = matrix[11] + matrix[9];
-	p[2].d = matrix[15] + matrix[13];
-	p[2].Normalise();
-
-	// Top Plane
-	p[3].a = matrix[3] - matrix[1];
-	p[3].b = matrix[7] - matrix[5];
-	p[3].c = matrix[11] - matrix[9];
-	p[3].d = matrix[15] - matrix[13];
-	p[3].Normalise();
-
-	// Near Plane
-	p[4].a = matrix[3] + matrix[2];
-	p[4].b = matrix[7] + matrix[6];
-	p[4].c = matrix[11] + matrix[10];
-	p[4].d = matrix[15] + matrix[14];
-	p[4].Normalise();
-
-	// Far Plane
-	p[5].a = matrix[3] - matrix[2];
-	p[5].b = matrix[7] - matrix[6];
-	p[5].c = matrix[11] - matrix[10];
-	p[5].d = matrix[15] - matrix[14];
-	p[5].Normalise();
-}
-
-void CNew3D::CalcBox(float distance, BBox& box)
-{
-	//bottom left front
-	box.points[0][0] = -distance;
-	box.points[0][1] = -distance;
-	box.points[0][2] = distance;
-	box.points[0][3] = 1;
-
-	//bottom left back
-	box.points[1][0] = -distance;
-	box.points[1][1] = -distance;
-	box.points[1][2] = -distance;
-	box.points[1][3] = 1;
-
-	//bottom right back
-	box.points[2][0] = distance;
-	box.points[2][1] = -distance;
-	box.points[2][2] = -distance;
-	box.points[2][3] = 1;
-
-	//bottom right front
-	box.points[3][0] = distance;
-	box.points[3][1] = -distance;
-	box.points[3][2] = distance;
-	box.points[3][3] = 1;
-
-	//top left front
-	box.points[4][0] = -distance;
-	box.points[4][1] = distance;
-	box.points[4][2] = distance;
-	box.points[4][3] = 1;
-
-	//top left back
-	box.points[5][0] = -distance;
-	box.points[5][1] = distance;
-	box.points[5][2] = -distance;
-	box.points[5][3] = 1;
-
-	//top right back
-	box.points[6][0] = distance;
-	box.points[6][1] = distance;
-	box.points[6][2] = -distance;
-	box.points[6][3] = 1;
-
-	//top right front
-	box.points[7][0] = distance;
-	box.points[7][1] = distance;
-	box.points[7][2] = distance;
-	box.points[7][3] = 1;
-}
-
-void CNew3D::MultVec(const float matrix[16], const float in[4], float out[4]) 
-{
-	for (int i = 0; i < 4; i++) {
-		out[i] =
-			in[0] * matrix[0 * 4 + i] +
-			in[1] * matrix[1 * 4 + i] +
-			in[2] * matrix[2 * 4 + i] +
-			in[3] * matrix[3 * 4 + i];
-	}
-}
-
-void CNew3D::TransformBox(const float *m, BBox& box)
-{
-	for (int i = 0; i < 8; i++) {
-		float v[4];
-		MultVec(m, box.points[i], v);
-		box.points[i][0] = v[0];
-		box.points[i][1] = v[1];
-		box.points[i][2] = v[2];
-	}
-}
-
-Clip CNew3D::ClipBox(BBox& box, Plane planes[6])
-{
-	int count = 0;
-
-	for (int i = 0; i < 8; i++) {
-
-		int temp = 0;
-
-		for (int j = 0; j < 6; j++) {
-			if (planes[j].DistanceToPoint(box.points[i]) >= 0) {
-				temp++;
-			}
-		}
-
-		if (temp == 6) count++;		// point is inside all 6 frustum planes
-	}
-
-	if (count == 8)	return Clip::INSIDE;
-	if (count > 0)	return Clip::INTERCEPT;
-	
-	//if we got here all points are outside of the view frustum
-	//check for all points being side same of any plane, means box outside of view
-
-	for (int i = 0; i < 6; i++) {
-
-		int temp = 0;
-
-		for (int j = 0; j < 8; j++) {
-			if (planes[i].DistanceToPoint(box.points[j]) >= 0) {
-				float distance = planes[i].DistanceToPoint(box.points[j]);
-				temp++;
-			}
-		}
-
-		if (temp == 0) return Clip::OUTSIDE;
-	}
-
-	//if we got here, box is traversing view frustum
-
-	return Clip::INTERCEPT;
-}
-
-} // New3D
-
diff --git a/Src/Graphics/New3D/backup/New3D.h b/Src/Graphics/New3D/backup/New3D.h
deleted file mode 100644
index a35c6ba..0000000
--- a/Src/Graphics/New3D/backup/New3D.h
+++ /dev/null
@@ -1,239 +0,0 @@
-/**
-** Supermodel
-** A Sega Model 3 Arcade Emulator.
-** Copyright 2011 Bart Trzynadlowski, Nik Henson
-**
-** This file is part of Supermodel.
-**
-** Supermodel is free software: you can redistribute it and/or modify it under
-** the terms of the GNU General Public License as published by the Free
-** Software Foundation, either version 3 of the License, or (at your option)
-** any later version.
-**
-** Supermodel is distributed in the hope that it will be useful, but WITHOUT
-** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-** FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-** more details.
-**
-** You should have received a copy of the GNU General Public License along
-** with Supermodel.  If not, see <http://www.gnu.org/licenses/>.
-**/
-
-/*
-* New3D.h
-*
-* Header file defining the CNew3D class: OpenGL Real3D graphics engine.
-*/
-
-#ifndef INCLUDED_NEW3D_H
-#define INCLUDED_NEW3D_H
-
-#include "Pkgs/glew.h"
-#include "Types.h"
-#include "TextureSheet.h"
-#include "Graphics/IRender3D.h"
-#include "Model.h"
-#include "Mat4.h"
-#include "R3DShader.h"
-#include "VBO.h"
-#include "R3DData.h"
-#include "Plane.h"
-#include "Vec.h"
-
-namespace New3D {
-
-class CNew3D : public IRender3D
-{
-public:
-	/*
-	* RenderFrame(void):
-	*
-	* Renders the complete scene database. Must be called between BeginFrame() and
-	* EndFrame(). This function traverses the scene database and builds up display
-	* lists.
-	*/
-	void RenderFrame(void);
-
-	/*
-	* BeginFrame(void):
-	*
-	* Prepare to render a new frame. Must be called once per frame prior to
-	* drawing anything.
-	*/
-	void BeginFrame(void);
-
-	/*
-	* EndFrame(void):
-	*
-	* Signals the end of rendering for this frame. Must be called last during
-	* the frame.
-	*/
-	void EndFrame(void);
-
-	/*
-	* UploadTextures(x, y, width, height):
-	*
-	* Signals that a portion of texture RAM has been updated.
-	*
-	* Parameters:
-	*		x		X position within texture RAM.
-	*		y		Y position within texture RAM.
-	*		width	Width of texture data in texels.
-	*		height	Height.
-	*/
-	void UploadTextures(unsigned x, unsigned y, unsigned width, unsigned height);
-
-	/*
-	* AttachMemory(cullingRAMLoPtr, cullingRAMHiPtr, polyRAMPtr, vromPtr,
-	* 				textureRAMPtr):
-	*
-	* Attaches RAM and ROM areas. This must be done prior to any rendering
-	* otherwise the program may crash with an access violation.
-	*
-	* Parameters:
-	*		cullingRAMLoPtr		Pointer to low culling RAM (4 MB).
-	*		cullingRAMHiPtr		Pointer to high culling RAM (1 MB).
-	*		polyRAMPtr			Pointer to polygon RAM (4 MB).
-	*		vromPtr				Pointer to video ROM (64 MB).
-	*		textureRAMPtr		Pointer to texture RAM (8 MB).
-	*/
-	void AttachMemory(const UINT32 *cullingRAMLoPtr,
-		const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr,
-		const UINT32 *vromPtr, const UINT16 *textureRAMPtr);
-
-	/*
-	* SetStep(stepID):
-	*
-	* Sets the Model 3 hardware stepping, which also determines the Real3D
-	* functionality. The default is Step 1.0. This should be called prior to
-	* any other emulation functions and after Init().
-	*
-	* Parameters:
-	*		stepID	0x10 for Step 1.0, 0x15 for Step 1.5, 0x20 for Step 2.0,
-	*				or 0x21 for Step 2.1. Anything else defaults to 1.0.
-	*/
-	void SetStep(int stepID);
-
-	/*
-	* Init(xOffset, yOffset, xRes, yRes, totalXRes, totalYRes):
-	*
-	* One-time initialization of the context. Must be called before any other
-	* members (meaning it should be called even before being attached to any
-	* other objects that want to use it).
-	*
-	* External shader files are loaded according to configuration settings.
-	*
-	* Parameters:
-	*		xOffset		X offset of the viewable area within OpenGL display
-	*                  surface, in pixels.
-	*		yOffset		Y offset.
-	*		xRes		Horizontal resolution of the viewable area.
-	*		yRes		Vertical resolution.
-	*		totalXRes	Horizontal resolution of the complete display area.
-	*		totalYRes	Vertical resolution.
-	*
-	* Returns:
-	*		OKAY is successful, otherwise FAILED if a non-recoverable error
-	*		occurred. Any allocated memory will not be freed until the
-	*		destructor is called. Prints own error messages.
-	*/
-	bool Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXRes, unsigned totalYRes);
-
-	/*
-	* CRender3D(void):
-	* ~CRender3D(void):
-	*
-	* Constructor and destructor.
-	*/
-	CNew3D(void);
-	~CNew3D(void);
-
-private:
-	/*
-	* Private Members
-	*/
-
-	// Real3D address translation
-	const UINT32 *TranslateCullingAddress(UINT32 addr);
-	const UINT32 *TranslateModelAddress(UINT32 addr);
-
-	// Matrix stack
-	void MultMatrix(UINT32 matrixOffset, Mat4& mat);
-	void InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat);
-
-	// Scene database traversal
-	bool DrawModel(UINT32 modelAddr);
-	void DescendCullingNode(UINT32 addr);
-	void DescendPointerList(UINT32 addr);
-	void DescendNodePtr(UINT32 nodeAddr);
-	void RenderViewport(UINT32 addr);
-
-	// building the scene
-	void CacheModel(Model *m, const UINT32 *data);
-	void CopyVertexData(const R3DPoly& r3dPoly, std::vector<Poly>& polyArray);
-	void OffsetTexCoords(R3DPoly& r3dPoly, float offset[2]);
-
-	void RenderScene(int priority, bool alpha);
-	float Determinant3x3(const float m[16]);
-	bool IsDynamicModel(UINT32 *data);		// check if the model has a colour palette
-	bool IsVROMModel(UINT32 modelAddr);
-
-	void CalcTexOffset(int offX, int offY, int page, int x, int y, int& newX, int& newY);	
-
-	/*
-	* Data
-	*/
-
-	// Stepping
-	int		m_step;
-	int		m_offset;			// offset to subtract for words 3 and higher of culling nodes
-	float	m_vertexFactor;		// fixed-point conversion factor for vertices
-
-	// Memory (passed from outside)
-	const UINT32	*m_cullingRAMLo;	// 4 MB
-	const UINT32	*m_cullingRAMHi;	// 1 MB
-	const UINT32	*m_polyRAM;			// 4 MB
-	const UINT32	*m_vrom;			// 64 MB
-	const UINT16	*m_textureRAM;		// 8 MB
-
-	// Resolution and scaling factors (to support resolutions higher than 496x384) and offsets
-	float		m_xRatio, m_yRatio;
-	unsigned	m_xOffs, m_yOffs;
-	unsigned 	m_totalXRes, m_totalYRes;
-
-	// Real3D Base Matrix Pointer
-	const float	*m_matrixBasePtr;
-	UINT32 m_colorTableAddr = 0x400;		// address of color table in polygon RAM
-
-	TextureSheet	m_texSheet;
-	NodeAttributes	m_nodeAttribs;
-	Mat4			m_modelMat;				// current modelview matrix
-
-	std::vector<Node> m_nodes;				// this represents the entire render frame
-	std::vector<Poly> m_polyBufferRam;		// dynamic polys
-	std::vector<Poly> m_polyBufferRom;		// rom polys
-	std::unordered_map<UINT32, std::shared_ptr<std::vector<Mesh>>> m_romMap;	// a hash table for all the ROM models. The meshes don't have model matrices or tex offsets yet
-
-	VBO m_vbo;								// large VBO to hold our poly data, start of VBO is ROM data, ram polys follow
-	R3DShader m_r3dShader;
-
-	Plane m_planes[6];
-
-	struct BBox
-	{
-		V4::Vec4 points[8];
-	};
-
-	void CalcFrustumPlanes	(Plane p[6], const float* matrix);
-	void CalcBox			(float distance, BBox& box);
-	void TransformBox		(const float *m, BBox& box);
-	void MultVec			(const float matrix[16], const float in[4], float out[4]);
-	Clip ClipBox			(BBox& box, Plane planes[6]);
-
-	float layerMax[4];
-	int cLayer;
-};
-
-} // New3D
-
-#endif  // INCLUDED_NEW3D_H
diff --git a/Src/Graphics/New3D/backup/Texture.cpp b/Src/Graphics/New3D/backup/Texture.cpp
deleted file mode 100644
index 3404e29..0000000
--- a/Src/Graphics/New3D/backup/Texture.cpp
+++ /dev/null
@@ -1,311 +0,0 @@
-#include "Texture.h"
-#include <stdio.h>
-#include <math.h>
-
-namespace New3D {
-
-Texture::Texture()
-{
-	Reset();
-}
-
-Texture::~Texture()
-{
-	DeleteTexture();		// make sure to have valid context before destroying
-}
-
-void Texture::DeleteTexture()
-{
-	if (m_textureID) {
-		glDeleteTextures(1, &m_textureID);
-		printf("-----> deleting %i %i %i %i %i\n", m_format, m_x, m_y, m_width, m_height);
-		Reset();
-	}
-}
-
-void Texture::Reset()
-{
-	m_x = 0;
-	m_y = 0;
-	m_width = 0;
-	m_height = 0;
-	m_format = 0;
-	m_textureID = 0;
-	m_mirrorU = false;
-	m_mirrorV = false;
-}
-
-void Texture::BindTexture()
-{
-	glBindTexture(GL_TEXTURE_2D, m_textureID);
-}
-
-void Texture::GetCoordinates(UINT16 uIn, UINT16 vIn, float uvScale, float& uOut, float& vOut)
-{
-	uOut = (uIn*uvScale) / m_width;
-	vOut = (vIn*uvScale) / m_height;
-}
-
-void Texture::GetCoordinates(bool mirror, int width, int height, UINT16 uIn, UINT16 vIn, float uvScale, float& uOut, float& vOut)
-{
-	uOut = (uIn*uvScale) / width;
-	vOut = (vIn*uvScale) / height;
-	/*
-
-	if (!mirror) {
-
-		float flu = uOut - floor(uOut);
-		float flv = uOut - floor(uOut);
-
-		int iu = (int)uOut;
-		int iv = (int)vOut;
-
-		float offu = 1 / (width*2.f);
-		float offv = 1 / (height*2.f);
-
-		if (iu % 2) {
-			if (!flu) {
-				flu = 1.0f;
-			}
-		}
-
-		if ((iv % 2)) {
-			if (!flv) {
-				flv = -1.0f;
-			}
-		}
-
-		uOut = flu;
-		vOut = flv;
-
-
-		if (flu < 0.5f) {
-			uOut += offu;
-		}
-		else {
-			uOut -= offu;
-		}
-
-		if (flv < 0.5f) {
-			vOut += offu;
-		}
-		else {
-			vOut -= offu;
-		}
-	}
-	*/
-}
-
-void Texture::SetWrapMode(bool mirrorU, bool mirrorV)
-{
-	if (mirrorU != m_mirrorU) {
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mirrorU ? GL_MIRRORED_REPEAT : GL_REPEAT);
-		m_mirrorU = mirrorU;
-	}
-
-	if (mirrorV != m_mirrorV) {
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mirrorV ? GL_MIRRORED_REPEAT : GL_REPEAT);
-		m_mirrorV = mirrorV;
-	}
-}
-
-UINT32 Texture::UploadTexture(const UINT16* src, UINT8* scratch, int format, bool mirrorU, bool mirrorV, int x, int y, int width, int height)
-{
-	int		xi, yi, i;
-	GLubyte	texel;
-	GLubyte	c, a;
-
-	if (!src || !scratch) {
-		return 0;		// sanity checking
-	}
-
-	DeleteTexture();	// free any existing texture
-
-	i = 0;
-
-	switch (format)
-	{
-	default:	// Debug texture, use TEXTURE_DEBUG mask
-		for (yi = y; yi < (y + height); yi++)
-		{
-			for (xi = x; xi < (x + width); xi++)
-			{
-				scratch[i++] = 255;	// R
-				scratch[i++] = 0;	// G
-				scratch[i++] = 0;	// B
-				scratch[i++] = 255;	// A
-			}
-		}
-		break;
-
-	case 0:	// T1RGB5 <- correct
-		for (yi = y; yi < (y + height); yi++)
-		{
-			for (xi = x; xi < (x + width); xi++)
-			{
-				scratch[i++] = (GLubyte)(((src[yi * 2048 + xi] >> 10) & 0x1F) * 255.f / 0x1F);	// R
-				scratch[i++] = (GLubyte)(((src[yi * 2048 + xi] >> 5) & 0x1F) * 255.f / 0x1F);	// G
-				scratch[i++] = (GLubyte)(((src[yi * 2048 + xi] >> 0) & 0x1F) * 255.f / 0x1F);	// B
-				scratch[i++] = ((src[yi * 2048 + xi] & 0x8000) ? 0 : 255);						// T
-			}
-		}
-		break;
-
-	case 1:	// Interleaved A4L4 (low byte)
-		for (yi = y; yi < (y + height); yi++)
-		{
-			for (xi = x; xi < (x + width); xi++)
-			{
-				// Interpret as A4L4
-				texel = src[yi * 2048 + xi] & 0xFF;
-				c = (texel & 0xF) * 17;
-				a = (texel >> 4) * 17;
-				scratch[i++] = c;
-				scratch[i++] = c;
-				scratch[i++] = c;
-				scratch[i++] = a;
-			}
-		}
-		break;
-
-	case 2:	// luminance alpha texture <- this one is correct
-		for (yi = y; yi < (y + height); yi++)
-		{
-			for (xi = x; xi < (x + width); xi++)
-			{
-				texel = src[yi * 2048 + xi] & 0xFF;
-				c = ((texel >> 4) & 0xF) * 17;
-				a = (texel & 0xF) * 17;
-				scratch[i++] = c;
-				scratch[i++] = c;
-				scratch[i++] = c;
-				scratch[i++] = a;
-			}
-		}
-		break;
-
-	case 3:	// 8-bit, A4L4 (high byte)
-		for (yi = y; yi < (y + height); yi++)
-		{
-			for (xi = x; xi < (x + width); xi++)
-			{
-				texel = src[yi * 2048 + xi] >> 8;
-				c = (texel & 0xF) * 17;
-				a = (texel >> 4) * 17;
-				scratch[i++] = c;
-				scratch[i++] = c;
-				scratch[i++] = c;
-				scratch[i++] = a;
-			}
-		}
-		break;
-
-	case 4: // 8-bit, L4A4 (high byte)
-
-		for (yi = y; yi < (y + height); yi++)
-		{
-			for (xi = x; xi < (x + width); xi++)
-			{
-				texel = src[yi * 2048 + xi] >> 8;
-				c = ((texel >> 4) & 0xF) * 17;
-				a = (texel & 0xF) * 17;
-				scratch[i++] = c;
-				scratch[i++] = c;
-				scratch[i++] = c;
-				scratch[i++] = a;
-			}
-		}
-		break;
-
-	case 5:	// 8-bit grayscale
-		for (yi = y; yi < (y + height); yi++)
-		{
-			for (xi = x; xi < (x + width); xi++)
-			{
-				texel = src[yi * 2048 + xi] & 0xFF;
-				scratch[i++] = texel;
-				scratch[i++] = texel;
-				scratch[i++] = texel;
-				scratch[i++] = (texel==255 ? 0 : 255);
-			}
-		}
-		break;
-
-	case 6:	// 8-bit grayscale <-- this one is correct
-		for (yi = y; yi < (y + height); yi++)
-		{
-			for (xi = x; xi < (x + width); xi++)
-			{
-				texel = src[yi * 2048 + xi] >> 8;
-				scratch[i++] = texel;
-				scratch[i++] = texel;
-				scratch[i++] = texel;
-				scratch[i++] = (texel == 255 ? 0 : 255);
-			}
-		}
-		break;
-
-	case 7:	// RGBA4
-		for (yi = y; yi < (y + height); yi++)
-		{
-			for (xi = x; xi < (x + width); xi++)
-			{
-				scratch[i++] = ((src[yi * 2048 + xi] >> 12) & 0xF) * 17;// R
-				scratch[i++] = ((src[yi * 2048 + xi] >> 8) & 0xF) * 17;	// G
-				scratch[i++] = ((src[yi * 2048 + xi] >> 4) & 0xF) * 17;	// B
-				scratch[i++] = ((src[yi * 2048 + xi] >> 0) & 0xF) * 17;	// A
-			}
-		}
-		break;
-	}
-
-	//remove debug mask
-	format &= 7;
-
-	GLfloat maxAnistrophy;
-
-	glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnistrophy);
-
-	if (maxAnistrophy > 8) {
-		maxAnistrophy = 8.0f;	//anymore than 8 can get expensive for little gain
-	}
-
-	glPixelStorei(GL_UNPACK_ALIGNMENT, 4);	// rgba is always 4 byte aligned
-	glActiveTexture(GL_TEXTURE0);           // activate correct texture unit
-
-	glGenTextures(1, &m_textureID);
-	glBindTexture(GL_TEXTURE_2D, m_textureID);
-
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mirrorU ? GL_MIRRORED_REPEAT : GL_REPEAT);	//todo this in shaders?
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mirrorV ? GL_MIRRORED_REPEAT : GL_REPEAT);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
-	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, maxAnistrophy);
-	glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
-	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scratch);
-
-	// assuming successful we can copy details
-
-	m_x = x;
-	m_y = y;
-	m_width = width;
-	m_height = height;
-	m_format = format;
-	m_mirrorU = mirrorU;
-	m_mirrorV = mirrorV;
-
-	printf("create format %i x: %i y: %i width: %i height: %i\n", format, x, y, width, height);
-
-	return m_textureID;
-}
-
-void Texture::GetDetails(int& x, int&y, int& width, int& height, int& format)
-{
-	x = m_x;
-	y = m_y;
-	width = m_width;
-	height = m_height;
-	format = m_format;
-}
-
-} // New3D
diff --git a/Src/Graphics/New3D/backup/Texture.h b/Src/Graphics/New3D/backup/Texture.h
deleted file mode 100644
index cab6518..0000000
--- a/Src/Graphics/New3D/backup/Texture.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef _TEXTURE_H_
-#define _TEXTURE_H_
-
-#include "Types.h"
-#include "Pkgs/glew.h"	//arg
-
-namespace New3D {
-  
-#define TEXTURE_DEBUG		0x8
-#define TEXTURE_DEBUG_MASK	0x7
-
-class Texture
-{
-public:
-
-	Texture();
-	~Texture();
-
-	UINT32	UploadTexture	(const UINT16* src, UINT8* scratch, int format, bool mirrorU, bool mirrorV, int x, int y, int width, int height);
-	void	DeleteTexture	();
-	void	BindTexture		();
-	void	GetCoordinates	(UINT16 uIn, UINT16 vIn, float uvScale, float& uOut, float& vOut);
-	void	GetDetails		(int& x, int&y, int& width, int& height, int& format);
-	void	SetWrapMode		(bool mirrorU, bool mirrorV);
-
-	static void GetCoordinates(bool mirror, int width, int height, UINT16 uIn, UINT16 vIn, float uvScale, float& uOut, float& vOut);
-
-private:
-
-	void Reset();
-
-	int m_x;
-	int m_y;
-	int m_width;
-	int m_height;
-	int m_format;
-	bool m_mirrorU;
-	bool m_mirrorV;
-	GLuint m_textureID;
-};
-
-} // New3D
-
-#endif
diff --git a/Src/Graphics/New3D/backup/VBO.cpp b/Src/Graphics/New3D/backup/VBO.cpp
deleted file mode 100644
index 364bd24..0000000
--- a/Src/Graphics/New3D/backup/VBO.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-#include "VBO.h"
-
-namespace New3D {
-
-VBO::VBO()
-{
-	m_id		= 0;
-	m_target	= 0;
-	m_capacity	= 0;
-	m_size		= 0;
-}
-
-void VBO::Create(GLenum target, GLenum usage, GLsizeiptr size, const void* data)
-{
-	glGenBuffers(1, &m_id);							// create a vbo
-	glBindBuffer(target, m_id);						// activate vbo id to use
-	glBufferData(target, size, data, usage);		// upload data to video card
-
-	m_target	= target;
-	m_capacity	= size;
-	m_size		= 0;
-
-	Bind(false);		// unbind
-}
-
-void VBO::BufferSubData(GLintptr offset, GLsizeiptr size, const GLvoid* data)
-{
-	glBufferSubData(m_target, offset, size, data);
-}
-
-bool VBO::AppendData(GLsizeiptr size, const GLvoid* data)
-{
-	if (size == 0 || !data) {
-		return true;	// nothing to do
-	}
-
-	if (m_size + size >= m_capacity) {
-		return false;
-	}
-
-	BufferSubData(m_size, size, data);
-
-	m_size += size;
-
-	return true;
-}
-
-void VBO::Reset()
-{
-	m_size = 0;
-}
-
-void VBO::Destroy()
-{
-	if (m_id) {
-		glDeleteBuffers(1, &m_id);
-		m_id		= 0;
-		m_target	= 0;
-		m_capacity	= 0;
-		m_size		= 0;
-	}
-}
-
-void VBO::Bind(bool enable)
-{
-	if (enable) {
-		glBindBuffer(m_target, m_id);
-	}
-	else {
-		glBindBuffer(m_target, 0);
-	}
-}
-
-int VBO::GetSize()
-{
-	return m_size;
-}
-
-int VBO::GetCapacity()
-{
-	return m_capacity;
-}
-
-} // New3D
diff --git a/Src/Graphics/New3D/backup/bounding box code/Mat4.h b/Src/Graphics/New3D/backup/bounding box code/Mat4.h
deleted file mode 100644
index e9aa647..0000000
--- a/Src/Graphics/New3D/backup/bounding box code/Mat4.h	
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef _MAT4_H_
-#define _MAT4_H_
-
-#include <vector>
-
-namespace New3D {
-
-class Mat4
-{
-public:
-
-	Mat4();
-
-	void LoadIdentity			();
-	void Translate				(float x, float y, float z);
-	void Rotate					(float angle, float x, float y, float z);
-	void Scale					(float x, float y, float z);
-	void Frustum				(float left, float right, float bottom, float top, float nearVal, float farVal);
-	void Ortho					(float left, float right, float bottom, float top, float nearVal, float farVal);
-	void Perspective			(float fovy, float aspect, float zNear, float zFar);
-	void MultMatrix				(const float *m);
-	void LoadMatrix				(const float *m);
-	void LoadTransposeMatrix	(const float *m);
-	void MultTransposeMatrix	(const float *m);
-	void PushMatrix				();
-	void PopMatrix				();
-	void Release				();
-
-	operator const float*		() { return currentMatrix; }
-
-	float currentMatrix[16];
-
-	struct Mat4Container {
-		float mat[16];	// we must wrap the matrix inside a struct otherwise vector doesn't work
-	};
-
-	std::vector<Mat4Container> m_vMat4;
-private:
-
-	void MultiMatrices			(const float a[16], const float b[16], float r[16]);
-	void Copy					(const float in[16], float out[16]);
-	void Transpose				(float m[16]);
-
-
-
-	
-};
-
-} // New3D
-
-#endif
-
diff --git a/Src/Graphics/New3D/backup/bounding box code/New3D.cpp b/Src/Graphics/New3D/backup/bounding box code/New3D.cpp
deleted file mode 100644
index b970df9..0000000
--- a/Src/Graphics/New3D/backup/bounding box code/New3D.cpp	
+++ /dev/null
@@ -1,1315 +0,0 @@
-#include "New3D.h"
-#include "PolyHeader.h"
-#include "Texture.h"
-#include "Vec.h"
-#include <cmath>
-#include <algorithm>
-#include <limits>
-
-#define MAX_RAM_POLYS 100000	
-#define MAX_ROM_POLYS 500000
-
-#ifndef M_PI
-#define M_PI 3.14159265359
-#endif
-
-namespace New3D {
-
-CNew3D::CNew3D()
-{
-	m_cullingRAMLo	= nullptr;
-	m_cullingRAMHi	= nullptr;
-	m_polyRAM		= nullptr;
-	m_vrom			= nullptr;
-	m_textureRAM	= nullptr;
-}
-
-CNew3D::~CNew3D()
-{
-	m_vbo.Destroy();
-}
-
-void CNew3D::AttachMemory(const UINT32 *cullingRAMLoPtr, const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr, const UINT32 *vromPtr, const UINT16 *textureRAMPtr)
-{
-	m_cullingRAMLo	= cullingRAMLoPtr;
-	m_cullingRAMHi	= cullingRAMHiPtr;
-	m_polyRAM		= polyRAMPtr;
-	m_vrom			= vromPtr;
-	m_textureRAM	= textureRAMPtr;
-}
-
-void CNew3D::SetStep(int stepID)
-{
-	m_step = stepID;
-
-	if ((m_step != 0x10) && (m_step != 0x15) && (m_step != 0x20) && (m_step != 0x21)) {
-		m_step = 0x10;
-	}
-
-	if (m_step > 0x10) {
-		m_offset = 0;							// culling nodes are 10 words
-		m_vertexFactor = (1.0f / 2048.0f);		// vertices are in 13.11 format
-	}
-	else {
-		m_offset = 2;							// 8 words
-		m_vertexFactor = (1.0f / 128.0f);		// 17.7
-	}
-
-	m_vbo.Create(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(Poly) * (MAX_RAM_POLYS + MAX_ROM_POLYS));
-}
-
-bool CNew3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXResParam, unsigned totalYResParam)
-{
-	// Resolution and offset within physical display area
-	m_xRatio	= xRes / 496.0f;
-	m_yRatio	= yRes / 384.0f;
-	m_xOffs		= xOffset;
-	m_yOffs		= yOffset;
-	m_totalXRes	= totalXResParam;
-	m_totalYRes = totalYResParam;
-
-	m_r3dShader.LoadShader();
-
-	glUseProgram(0);
-
-	return OKAY;	// OKAY ? wtf ..
-}
-
-void CNew3D::UploadTextures(unsigned x, unsigned y, unsigned width, unsigned height)
-{
-	m_texSheet.Invalidate(x, y, width, height);
-}
-
-void CNew3D::RenderScene(int priority, bool alpha)
-{
-	if (alpha) {
-		glEnable(GL_BLEND);
-	}
-
-	for (auto &n : m_nodes) {
-
-		if (n.viewport.priority != priority || n.models.empty()) {
-			continue;
-		}
-
-		glViewport		(n.viewport.x, n.viewport.y, n.viewport.width, n.viewport.height);
-		glMatrixMode	(GL_PROJECTION);
-		glLoadMatrixf	(n.viewport.projectionMatrix);
-		glMatrixMode	(GL_MODELVIEW);
-
-		m_r3dShader.SetViewportUniforms(&n.viewport);
-
-		for (auto &m : n.models) {
-
-			bool matrixLoaded = false;
-
-			if (m.meshes->empty()) {
-				continue;
-			}
-
-			m_r3dShader.SetModelStates(&m);
-
-			for (auto &mesh : *m.meshes) {
-
-				if (alpha) {
-					if (!mesh.textureAlpha && !mesh.polyAlpha) {
-						continue;
-					}
-				}
-				else {
-					if (mesh.textureAlpha || mesh.polyAlpha) {
-						continue;
-					}
-				}
-
-				if (!matrixLoaded) {
-					glLoadMatrixf(m.modelMat);
-					matrixLoaded = true;		// do this here to stop loading matrices we don't need. Ie when rendering non transparent etc
-				}
-				
-				if (mesh.textured) {
-
-					int x, y;
-					CalcTexOffset(m.textureOffsetX, m.textureOffsetY, m.page, mesh.x, mesh.y, x, y);
-
-					auto tex1 = m_texSheet.BindTexture(m_textureRAM, mesh.format, mesh.mirrorU, mesh.mirrorV, x, y, mesh.width, mesh.height);
-					if (tex1) {
-						tex1->BindTexture();
-						tex1->SetWrapMode(mesh.mirrorU, mesh.mirrorV);
-					}
-
-					if (mesh.microTexture) {
-						glActiveTexture(GL_TEXTURE1);
-						auto tex2 = m_texSheet.BindTexture(m_textureRAM, 0, false, false, 0, 1024, 128, 128);
-						if (tex2) {
-							tex2->BindTexture();
-						}
-						glActiveTexture(GL_TEXTURE0);
-					}
-				}
-				
-				m_r3dShader.SetMeshUniforms(&mesh);
-				glDrawArrays(GL_TRIANGLES, mesh.vboOffset*3, mesh.triangleCount*3);			// times 3 to convert triangles to vertices
-			}
-		}
-	}
-
-	glDisable(GL_BLEND);
-	glDepthMask(GL_TRUE);
-	glDisable(GL_STENCIL_TEST);
-}
-
-void CNew3D::DrawBoundingBoxes()
-{
-	glColor3ub(255, 255, 255);
-	glDisable(GL_TEXTURE_2D);
-	glEnable(GL_DEPTH_TEST);
-	glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
-
-	if (m_nodes.size()) {
-		glViewport(m_nodes[0].viewport.x, m_nodes[0].viewport.y, m_nodes[0].viewport.width, m_nodes[0].viewport.height);
-	}
-
-	for (auto &b : m_bBoxes) {
-		glLoadMatrixf(b.mat);
-
-		//top
-		glBegin(GL_LINE_LOOP);
-
-		for (int i = 0; i < 4; i++) {
-			glVertex3fv(b.points[i]);
-		}
-
-		glEnd();
-
-		//bottom
-
-		glBegin(GL_LINE_LOOP);
-
-		for (int i = 4; i < 8; i++) {
-			glVertex3fv(b.points[i]);
-		}
-
-		glEnd();
-
-		// pillars
-		glBegin(GL_LINES);
-
-		glVertex3fv(b.points[0]);
-		glVertex3fv(b.points[4]);
-
-		glVertex3fv(b.points[1]);
-		glVertex3fv(b.points[5]);
-
-		glVertex3fv(b.points[2]);
-		glVertex3fv(b.points[6]);
-
-		glVertex3fv(b.points[3]);
-		glVertex3fv(b.points[7]);
-
-		glEnd();
-	}
-}
-
-void CNew3D::RenderFrame(void)
-{
-	// release any resources from last frame
-	m_polyBufferRam.clear();	// clear dyanmic model memory buffer
-	m_nodes.clear();		// memory will grow during the object life time, that's fine, no need to shrink to fit
-	m_modelMat.Release();	// would hope we wouldn't need this but no harm in checking
-	m_nodeAttribs.Reset();
-	m_bBoxes.clear();
-
-	glDepthFunc		(GL_LEQUAL);
-	glEnable		(GL_DEPTH_TEST);
-	glActiveTexture	(GL_TEXTURE0);
-	glEnable		(GL_CULL_FACE);
-	glFrontFace		(GL_CW);
-
-	glStencilFunc	(GL_EQUAL, 0, 0xFF);			// basically stencil test passes if the value is zero
-	glStencilOp		(GL_KEEP, GL_INCR, GL_INCR);	// if the stencil test passes, we incriment the value
-	glStencilMask	(0xFF);
-
-	RenderViewport(0x800000);		// build model structure
-	
-	m_vbo.Bind(true);
-	m_vbo.BufferSubData(MAX_ROM_POLYS*sizeof(Poly), m_polyBufferRam.size()*sizeof(Poly), m_polyBufferRam.data());	// upload all the dynamic data to GPU in one go
-
-	if (m_polyBufferRom.size()) {
-
-		// sync rom memory with vbo
-		int romBytes	= (int)m_polyBufferRom.size() * sizeof(Poly);
-		int vboBytes	= m_vbo.GetSize();
-		int size		= romBytes - vboBytes;
-
-		if (size) {
-			//check we haven't blown up the memory buffers
-			//we will lose rom models for 1 frame is this happens, not the end of the world, as probably won't ever happen anyway
-			if (m_polyBufferRom.size() >= MAX_ROM_POLYS) {
-				m_polyBufferRom.clear();
-				m_romMap.clear();
-				m_vbo.Reset();
-			}
-			else {
-				m_vbo.AppendData(size, &m_polyBufferRom[vboBytes / sizeof(Poly)]);
-			}
-		}
-	}
-	
-	glEnableClientState(GL_VERTEX_ARRAY);
-	glEnableClientState(GL_NORMAL_ARRAY);
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-	glEnableClientState(GL_COLOR_ARRAY);
-
-	// before draw, specify vertex and index arrays with their offsets, offsetof is maybe evil ..
-	glVertexPointer		(3, GL_FLOAT, sizeof(Vertex), 0);
-	glNormalPointer		(GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, normal));
-	glTexCoordPointer	(2, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, texcoords));
-	glColorPointer		(4, GL_UNSIGNED_BYTE, sizeof(Vertex), (void*)offsetof(Vertex, color));
-	
-	m_r3dShader.SetShader(true);
-
-	for (int pri = 0; pri <= 3; pri++) {
-		glClear		(GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
-		RenderScene	(pri, false);
-		RenderScene	(pri, true);
-	}
-
-	m_r3dShader.SetShader(false);		// unbind shader
-	m_vbo.Bind(false);
-
-	glDisable(GL_CULL_FACE);
-	glDisableClientState(GL_VERTEX_ARRAY);
-	glDisableClientState(GL_NORMAL_ARRAY);
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-	glDisableClientState(GL_COLOR_ARRAY);
-
-	DrawBoundingBoxes();
-}
-
-void CNew3D::BeginFrame(void)
-{
-}
-
-void CNew3D::EndFrame(void)
-{
-}
-
-/******************************************************************************
-Real3D Address Translation
-
-Functions that interpret word-granular Real3D addresses and return pointers.
-******************************************************************************/
-
-// Translates 24-bit culling RAM addresses
-const UINT32* CNew3D::TranslateCullingAddress(UINT32 addr)
-{
-	addr &= 0x00FFFFFF;	// caller should have done this already
-
-	if ((addr >= 0x800000) && (addr < 0x840000)) {
-		return &m_cullingRAMHi[addr & 0x3FFFF];
-	}
-	else if (addr < 0x100000) {
-		return &m_cullingRAMLo[addr];
-	}
-
-	return NULL;
-}
-
-// Translates model references
-const UINT32* CNew3D::TranslateModelAddress(UINT32 modelAddr)
-{
-	modelAddr &= 0x00FFFFFF;	// caller should have done this already
-
-	if (modelAddr < 0x100000) {
-		return &m_polyRAM[modelAddr];
-	}
-	else {
-		return &m_vrom[modelAddr];
-	}
-}
-
-bool CNew3D::DrawModel(UINT32 modelAddr)
-{
-	const UINT32*	modelAddress;
-	bool			cached = false;
-	Model*			m;
-
-	modelAddress = TranslateModelAddress(modelAddr);
-
-	// create a new model to push onto the vector
-	m_nodes.back().models.emplace_back(Model());
-
-	// get the last model in the array
-	m = &m_nodes.back().models.back();
-
-	if (IsVROMModel(modelAddr) && !IsDynamicModel((UINT32*)modelAddress)) {
-
-		// try to find meshes in the rom cache
-
-		m->meshes = m_romMap[modelAddr];	// will create an entry with a null pointer if empty
-
-		if (m->meshes) {
-			cached = true;
-		}
-		else {
-			m->meshes = std::make_shared<std::vector<Mesh>>();
-			m_romMap[modelAddr] = m->meshes;		// store meshes in our rom map here
-		}
-
-		m->dynamic = false;
-	}
-	else {
-		m->meshes = std::make_shared<std::vector<Mesh>>();
-	}
-
-	// copy current model matrix
-	for (int i = 0; i < 16; i++) {
-		m->modelMat[i] = m_modelMat.currentMatrix[i];
-	}
-
-	//calculate determinant
-	m->determinant = Determinant3x3(m_modelMat);
-
-	// update texture offsets
-	m->textureOffsetX = m_nodeAttribs.currentTexOffsetX;
-	m->textureOffsetY = m_nodeAttribs.currentTexOffsetY;
-	m->page = m_nodeAttribs.page;
-
-	if (!cached) {
-		CacheModel(m, modelAddress);
-	}
-
-	return true;
-}
-
-// Descends into a 10-word culling node
-void CNew3D::DescendCullingNode(UINT32 addr)
-{
-	const UINT32	*node, *lodTable;
-	UINT32			matrixOffset, child1Ptr, sibling2Ptr;
-	float			x, y, z;
-	int				tx, ty;
-
-	if (m_nodeAttribs.StackLimit()) {
-		return;
-	}
-
-	node = TranslateCullingAddress(addr);
-
-	if (NULL == node) {
-		return;
-	}
-
-	// Extract known fields
-	child1Ptr		= node[0x07 - m_offset] & 0x7FFFFFF;	// mask colour table bits
-	sibling2Ptr		= node[0x08 - m_offset] & 0x1FFFFFF;	// mask colour table bits
-	matrixOffset	= node[0x03 - m_offset] & 0xFFF;
-
-	float test = ToFloat(Convert16BitProFloat(node[9 - m_offset]&0xFFFF));
-
-	if (test > 100000) {
-		int debugb = 0;
-	}
-
-	if ((node[0x00] & 0x07) != 0x06) {						// colour table seems to indicate no siblings
-		if (!(sibling2Ptr & 0x1000000) && sibling2Ptr) {
-			DescendCullingNode(sibling2Ptr);				// no need to mask bit, would already be zero
-		}
-	}
-
-	if ((node[0x00] & 0x04)) {
-		m_colorTableAddr = ((node[0x03 - m_offset] >> 19) << 0) | ((node[0x07 - m_offset] >> 28) << 13) | ((node[0x08 - m_offset] >> 25) << 17);
-		m_colorTableAddr &= 0x000FFFFF; // clamp to 4MB (in words) range
-	}
-
-	x = *(float *)&node[0x04 - m_offset];
-	y = *(float *)&node[0x05 - m_offset];
-	z = *(float *)&node[0x06 - m_offset];
-
-	m_nodeAttribs.Push();	// save current attribs
-
-	if (!m_offset)	// Step 1.5+
-	{
-		tx = 32 * ((node[0x02] >> 7) & 0x3F);
-		ty = 32 * (node[0x02] & 0x1F);
-
-		// apply texture offsets, else retain current ones
-		if ((node[0x02] & 0x8000))	{
-			m_nodeAttribs.currentTexOffsetX = tx;
-			m_nodeAttribs.currentTexOffsetY = ty;
-			m_nodeAttribs.page = (node[0x02] & 0x4000) >> 14;
-		}
-	}
-
-	// Apply matrix and translation
-	m_modelMat.PushMatrix();
-
-	// apply translation vector
-	if ((node[0x00] & 0x10)) {
-		m_modelMat.Translate(x, y, z);
-	}
-	// multiply matrix, if specified
-	else if (matrixOffset) {
-		MultMatrix(matrixOffset,m_modelMat);
-	}	
-
-
-	{
-		if (test < 10000000 ) {
-			BBox box;
-			//copy current matrix
-
-			box.mat.LoadMatrix(m_modelMat);
-			CalcBox(test, box);
-
-			m_bBoxes.emplace_back(box);
-		}
-	}
-
-	// Descend down first link
-	if ((node[0x00] & 0x08))	// 4-element LOD table
-	{
-		lodTable = TranslateCullingAddress(child1Ptr);
-
-		if (NULL != lodTable) {
-			if ((node[0x03 - m_offset] & 0x20000000)) {
-				DescendCullingNode(lodTable[0] & 0xFFFFFF);
-			}
-			else {
-				DrawModel(lodTable[0] & 0xFFFFFF);	//TODO
-			}
-		}
-	}
-	else {
-		DescendNodePtr(child1Ptr);
-	}
-
-	m_modelMat.PopMatrix();
-
-	// Restore old texture offsets
-	m_nodeAttribs.Pop();
-}
-
-void CNew3D::DescendNodePtr(UINT32 nodeAddr)
-{
-	// Ignore null links
-	if ((nodeAddr & 0x00FFFFFF) == 0) {
-		return;
-	}
-
-	switch ((nodeAddr >> 24) & 0xFF)	// pointer type encoded in upper 8 bits
-	{
-	case 0x00:	// culling node
-		DescendCullingNode(nodeAddr & 0xFFFFFF);
-		break;
-	case 0x01:	// model (perhaps bit 2 is a flag in this case?)
-	case 0x03:
-		DrawModel(nodeAddr & 0xFFFFFF);
-		break;
-	case 0x04:	// pointer list
-		DescendPointerList(nodeAddr & 0xFFFFFF);
-		break;
-	default:
-		break;
-	}
-}
-
-void CNew3D::DescendPointerList(UINT32 addr)
-{
-	const UINT32*	list;
-	UINT32			nodeAddr;
-	int				index;
-
-	list = TranslateCullingAddress(addr);
-
-	if (NULL == list) {
-		return;
-	}
-
-	index = 0;
-
-	while (true) {
-
-		if (list[index] & 0x01000000) {
-			break;	// empty list
-		}
-
-		nodeAddr = list[index] & 0x00FFFFFF;	// clear upper 8 bits to ensure this is processed as a culling node
-
-		DescendCullingNode(nodeAddr);
-
-		if (list[index] & 0x02000000) {
-			break;	// list end
-		}
-
-		index++;
-	}
-}
-
-
-/******************************************************************************
-Matrix Stack
-******************************************************************************/
-
-// Macro to generate column-major (OpenGL) index from y,x subscripts
-#define CMINDEX(y,x)	(x*4+y)
-
-/*
-* MultMatrix():
-*
-* Multiplies the matrix stack by the specified Real3D matrix. The matrix
-* index is a 12-bit number specifying a matrix number relative to the base.
-* The base matrix MUST be set up before calling this function.
-*/
-void CNew3D::MultMatrix(UINT32 matrixOffset, Mat4& mat)
-{
-	GLfloat		m[4*4];
-	const float	*src = &m_matrixBasePtr[matrixOffset * 12];
-
-	if (m_matrixBasePtr == NULL)	// LA Machineguns
-		return;
-
-	m[CMINDEX(0, 0)] = src[3];
-	m[CMINDEX(0, 1)] = src[4];
-	m[CMINDEX(0, 2)] = src[5];
-	m[CMINDEX(0, 3)] = src[0];
-	m[CMINDEX(1, 0)] = src[6];
-	m[CMINDEX(1, 1)] = src[7];
-	m[CMINDEX(1, 2)] = src[8];
-	m[CMINDEX(1, 3)] = src[1];
-	m[CMINDEX(2, 0)] = src[9];
-	m[CMINDEX(2, 1)] = src[10];
-	m[CMINDEX(2, 2)] = src[11];
-	m[CMINDEX(2, 3)] = src[2];
-	m[CMINDEX(3, 0)] = 0.0;
-	m[CMINDEX(3, 1)] = 0.0;
-	m[CMINDEX(3, 2)] = 0.0;
-	m[CMINDEX(3, 3)] = 1.0;
-
-	mat.MultMatrix(m);
-}
-
-/*
-* InitMatrixStack():
-*
-* Initializes the modelview (model space -> view space) matrix stack and
-* Real3D coordinate system. These are the last transforms to be applied (and
-* the first to be defined on the stack) before projection.
-*
-* Model 3 games tend to define the following unusual base matrix:
-*
-*		0	0	-1	0
-*		1	0	0	0
-*		0	-1	0	0
-*		0	0	0	1
-*
-* When this is multiplied by a column vector, the output is:
-*
-*		-Z
-*		X
-*		-Y
-*		1
-*
-* My theory is that the Real3D GPU accepts vectors in Z,X,Y order. The games
-* store everything as X,Y,Z and perform the translation at the end. The Real3D
-* also has Y and Z coordinates opposite of the OpenGL convention. This
-* function inserts a compensating matrix to undo these things.
-*
-* NOTE: This function assumes we are in GL_MODELVIEW matrix mode.
-*/
-
-void CNew3D::InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat)
-{
-	GLfloat m[4 * 4];
-
-	// This matrix converts vectors back from the weird Model 3 Z,X,Y ordering
-	// and also into OpenGL viewspace (-Y,-Z)
-	m[CMINDEX(0, 0)] = 0.0;	m[CMINDEX(0, 1)] = 1.0;	m[CMINDEX(0, 2)] = 0.0;	m[CMINDEX(0, 3)] = 0.0;
-	m[CMINDEX(1, 0)] = 0.0;	m[CMINDEX(1, 1)] = 0.0;	m[CMINDEX(1, 2)] =-1.0; m[CMINDEX(1, 3)] = 0.0;
-	m[CMINDEX(2, 0)] =-1.0; m[CMINDEX(2, 1)] = 0.0;	m[CMINDEX(2, 2)] = 0.0;	m[CMINDEX(2, 3)] = 0.0;
-	m[CMINDEX(3, 0)] = 0.0;	m[CMINDEX(3, 1)] = 0.0;	m[CMINDEX(3, 2)] = 0.0;	m[CMINDEX(3, 3)] = 1.0;
-
-
-	mat.LoadMatrix(m);
-
-	// Set matrix base address and apply matrix #0 (coordinate system matrix)
-	m_matrixBasePtr = (float *)TranslateCullingAddress(matrixBaseAddr);
-	MultMatrix(0, mat);
-}
-
-// Draws viewports of the given priority
-void CNew3D::RenderViewport(UINT32 addr)
-{
-	static const GLfloat	color[8][3] =
-	{											// RGB1 color translation
-		{ 0.0, 0.0, 0.0 },	// off
-		{ 0.0, 0.0, 1.0 },	// blue
-		{ 0.0, 1.0, 0.0 },	// green
-		{ 0.0, 1.0, 1.0 },	// cyan
-		{ 1.0, 0.0, 0.0 }, 	// red
-		{ 1.0, 0.0, 1.0 },	// purple
-		{ 1.0, 1.0, 0.0 },	// yellow
-		{ 1.0, 1.0, 1.0 }	// white
-	};
-
-	// Translate address and obtain pointer
-	const uint32_t *vpnode = TranslateCullingAddress(addr);
-
-	if (NULL == vpnode) {
-		return;
-	}
-
-	if (vpnode[0x01] == 0) {		// memory probably hasn't been set up yet, abort
-		return;
-	}
-
-	if (!(vpnode[0] & 0x20)) {	// only if viewport enabled
-		uint32_t curPri	= (vpnode[0x00] >> 3) & 3;		// viewport priority
-		uint32_t nodeAddr	= vpnode[0x02];							// scene database node pointer
-
-		// create node object 
-		m_nodes.emplace_back(Node());
-		m_nodes.back().models.reserve(2048);			// create space for models
-
-		// get pointer to its viewport
-		Viewport *vp = &m_nodes.back().viewport;
-
-		vp->priority = curPri;
-
-		// Fetch viewport parameters (TO-DO: would rounding make a difference?)
-		int vpX			= (int)(((vpnode[0x1A] & 0xFFFF) / 16.0f) + 0.5f);		// viewport X (12.4 fixed point)
-		int vpY			= (int)(((vpnode[0x1A] >> 16) / 16.0f) + 0.5f);			// viewport Y (12.4)
-		int vpWidth		= (int)(((vpnode[0x14] & 0xFFFF) / 4.0f) + 0.5f);		// width (14.2)
-		int vpHeight	= (int)(((vpnode[0x14] >> 16) / 4.0f) + 0.5f);			// height (14.2)
-		uint32_t matrixBase	= vpnode[0x16] & 0xFFFFFF;							// matrix base address
-
-		if (vpX) {
-			vpX += 2;
-		}
-
-		if (vpY) {
-			vpY += 2;
-		}
-
-		LODBlendTable* tableTest = (LODBlendTable*)TranslateCullingAddress(vpnode[0x17]);
-
-		float angle_left	= -atan2(*(float *)&vpnode[12],  *(float *)&vpnode[13]);
-		float angle_right	=  atan2(*(float *)&vpnode[16], -*(float *)&vpnode[17]);
-		float angle_top		=  atan2(*(float *)&vpnode[14],  *(float *)&vpnode[15]);
-		float angle_bottom	= -atan2(*(float *)&vpnode[18], -*(float *)&vpnode[19]);
-
-		float near = 0.25f;
-		float far = 2e6;
-
-		if (m_step == 0x10) {
-			near = 8;
-		}
-
-		float l = near * tanf(angle_left);
-		float r = near * tanf(angle_right);
-		float t = near * tanf(angle_top);
-		float b = near * tanf(angle_bottom);
-
-		// TO-DO: investigate clipping near/far planes
-
-		if ((vpX == 0) && (vpWidth >= 495) && (vpY == 0) && (vpHeight >= 383))
-		{
-			float windowAR		= (float)m_totalXRes / (float)m_totalYRes;
-			float originalAR	= 496 / 384.f;
-			float correction	= windowAR / originalAR;	// expand horizontal frustum planes
-
-			vp->x		= 0;
-			vp->y		= m_yOffs + (GLint)((float)(384 - (vpY + vpHeight))*m_yRatio);
-			vp->width	= m_totalXRes;
-			vp->height	= (GLint)((float)vpHeight*m_yRatio);
-
-			vp->projectionMatrix.Frustum(l*correction, r*correction, b, t, near, far);
-		}
-		else
-		{
-			vp->x		= m_xOffs + (GLint)((float)vpX*m_xRatio);
-			vp->y		= m_yOffs + (GLint)((float)(384 - (vpY + vpHeight))*m_yRatio);
-			vp->width	= (GLint)((float)vpWidth*m_xRatio);
-			vp->height	= (GLint)((float)vpHeight*m_yRatio);
-
-			vp->projectionMatrix.Frustum(l, r, b, t, near, far);
-		}
-
-		// Lighting (note that sun vector points toward sun -- away from vertex)
-		vp->lightingParams[0] = *(float *)&vpnode[0x05];								// sun X
-		vp->lightingParams[1] = *(float *)&vpnode[0x06];								// sun Y
-		vp->lightingParams[2] = *(float *)&vpnode[0x04];								// sun Z
-		vp->lightingParams[3] = *(float *)&vpnode[0x07];								// sun intensity
-		vp->lightingParams[4] = (float)((vpnode[0x24] >> 8) & 0xFF) * (1.0f / 255.0f);	// ambient intensity
-		vp->lightingParams[5] = 0.0;	// reserved
-
-		// Spotlight
-		int spotColorIdx = (vpnode[0x20] >> 11) & 7;			// spotlight color index
-		vp->spotEllipse[0] = (float)((vpnode[0x1E] >> 3) & 0x1FFF);	// spotlight X position (fractional component?)
-		vp->spotEllipse[1] = (float)((vpnode[0x1D] >> 3) & 0x1FFF);	// spotlight Y
-		vp->spotEllipse[2] = (float)((vpnode[0x1E] >> 16) & 0xFFFF);	// spotlight X size (16-bit? May have fractional component below bit 16)
-		vp->spotEllipse[3] = (float)((vpnode[0x1D] >> 16) & 0xFFFF);	// spotlight Y size
-
-		vp->spotRange[0] = 1.0f / (*(float *)&vpnode[0x21]);		// spotlight start
-		vp->spotRange[1] = *(float *)&vpnode[0x1F];				// spotlight extent
-		vp->spotColor[0] = color[spotColorIdx][0];				// spotlight color
-		vp->spotColor[1] = color[spotColorIdx][1];
-		vp->spotColor[2] = color[spotColorIdx][2];
-
-		// Spotlight is applied on a per pixel basis, must scale its position and size to screen
-		vp->spotEllipse[1] = 384.0f - vp->spotEllipse[1];
-		vp->spotRange[1] += vp->spotRange[0];	// limit
-		vp->spotEllipse[2] = 496.0f / sqrt(vp->spotEllipse[2]);	// spotlight appears to be specified in terms of physical resolution (unconfirmed)
-		vp->spotEllipse[3] = 384.0f / sqrt(vp->spotEllipse[3]);
-
-		// Scale the spotlight to the OpenGL viewport
-		vp->spotEllipse[0] = vp->spotEllipse[0] * m_xRatio + m_xOffs;
-		vp->spotEllipse[1] = vp->spotEllipse[1] * m_yRatio + m_yOffs;
-		vp->spotEllipse[2] *= m_xRatio;
-		vp->spotEllipse[3] *= m_yRatio;
-
-		// Fog
-		vp->fogParams[0] = (float)((vpnode[0x22] >> 16) & 0xFF) * (1.0f / 255.0f);	// fog color R
-		vp->fogParams[1] = (float)((vpnode[0x22] >> 8) & 0xFF) * (1.0f / 255.0f);	// fog color G
-		vp->fogParams[2] = (float)((vpnode[0x22] >> 0) & 0xFF) * (1.0f / 255.0f);	// fog color B
-		vp->fogParams[3] = *(float *)&vpnode[0x23];									// fog density
-		vp->fogParams[4] = (float)(INT16)(vpnode[0x25] & 0xFFFF)*(1.0f / 255.0f);	// fog start
-
-		
-		if (std::isinf(vp->fogParams[3]) || std::isnan(vp->fogParams[3]) || std::isinf(vp->fogParams[4]) || std::isnan(vp->fogParams[4])) {	// Star Wars Trilogy
-			vp->fogParams[3] = vp->fogParams[4] = 0.0f;
-		}
-
-		// Unknown light/fog parameters
-		float scrollFog = (float)(vpnode[0x20] & 0xFF) * (1.0f / 255.0f);	// scroll fog
-		float scrollAtt = (float)(vpnode[0x24] & 0xFF) * (1.0f / 255.0f);	// scroll attenuation
-
-		// Clear texture offsets before proceeding
-		m_nodeAttribs.Reset();
-
-		// Set up coordinate system and base matrix
-		InitMatrixStack(matrixBase, m_modelMat);
-
-		// Safeguard: weird coordinate system matrices usually indicate scenes that will choke the renderer
-		if (NULL != m_matrixBasePtr)
-		{
-			float	m21, m32, m13;
-
-			// Get the three elements that are usually set and see if their magnitudes are 1
-			m21 = m_matrixBasePtr[6];
-			m32 = m_matrixBasePtr[10];
-			m13 = m_matrixBasePtr[5];
-
-			m21 *= m21;
-			m32 *= m32;
-			m13 *= m13;
-
-			if ((m21>1.05) || (m21<0.95))
-				return;
-			if ((m32>1.05) || (m32<0.95))
-				return;
-			if ((m13>1.05) || (m13<0.95))
-				return;
-		}
-
-		// Descend down the node link: Use recursive traversal
-		DescendNodePtr(nodeAddr);
-	}
-
-	// render next viewport
-	if (vpnode[0x01] != 0x01000000) {
-		RenderViewport(vpnode[0x01]);
-	}
-}
-
-void CNew3D::CopyVertexData(const R3DPoly& r3dPoly, std::vector<Poly>& polyArray)
-{
-	//====================
-	Poly		p;
-	V3::Vec3	normal;
-	float		dotProd;
-	bool		clockWise;
-	//====================
-
-	V3::createNormal(r3dPoly.v[0].pos, r3dPoly.v[1].pos, r3dPoly.v[2].pos, normal);
-
-	dotProd		= V3::dotProduct(normal, r3dPoly.faceNormal);
-	clockWise	= dotProd >= 0.0;
-
-	if (clockWise) {
-		p.p1 = r3dPoly.v[0];
-		p.p2 = r3dPoly.v[1];
-		p.p3 = r3dPoly.v[2];
-	}
-	else {
-		p.p1 = r3dPoly.v[2];
-		p.p2 = r3dPoly.v[1];
-		p.p3 = r3dPoly.v[0];
-	}
-
-	//multiply face attributes with vertex attributes if required
-	for (int i = 0; i < 4; i++) {
-		p.p1.color[i] = (UINT8)(p.p1.color[i] * r3dPoly.faceColour[i]);
-		p.p2.color[i] = (UINT8)(p.p2.color[i] * r3dPoly.faceColour[i]);
-		p.p3.color[i] = (UINT8)(p.p3.color[i] * r3dPoly.faceColour[i]);
-	}
-	
-	polyArray.emplace_back(p);
-
-	if (r3dPoly.number == 4) {
-
-		if (clockWise) {
-			p.p1 = r3dPoly.v[0];
-			p.p2 = r3dPoly.v[2];
-			p.p3 = r3dPoly.v[3];
-		}
-		else {
-			p.p1 = r3dPoly.v[0];
-			p.p2 = r3dPoly.v[3];
-			p.p3 = r3dPoly.v[2];
-		}
-
-		//multiply face attributes with vertex attributes if required
-		for (int i = 0; i < 4; i++) {
-			p.p1.color[i] = (UINT8)(p.p1.color[i] * r3dPoly.faceColour[i]);
-			p.p2.color[i] = (UINT8)(p.p2.color[i] * r3dPoly.faceColour[i]);
-			p.p3.color[i] = (UINT8)(p.p3.color[i] * r3dPoly.faceColour[i]);
-		}
-
-		polyArray.emplace_back(p);
-	}
-}
-
-// non smooth texturing on the pro-1000 seems to sample like gl_nearest
-// ie not outside of the texture coordinates, but with bilinear filtering
-// this is about as close as we can emulate in hardware
-// if we don't do this with gl_repeat enabled, it will wrap around and sample the 
-// other side of the texture which produces ugly seems
-void CNew3D::OffsetTexCoords(R3DPoly& r3dPoly, float offset[2])
-{
-	for (int i = 0; i < 2; i++) {
-
-		float min =  std::numeric_limits<float>::max();
-		float max = -std::numeric_limits<float>::max();
-
-		if (!offset[i]) continue;
-
-		for (int j = 0; j < r3dPoly.number; j++) {
-			min = std::min(r3dPoly.v[j].texcoords[i], min);
-			max = std::max(r3dPoly.v[j].texcoords[i], max);
-		}
-
-		float fTemp;
-		float iTemp;
-		bool fractMin;
-		bool fractMax;
-		
-		fTemp		= std::modf(min, &iTemp);
-		fractMin	= fTemp > 0;
-
-		fTemp		= std::modf(max, &iTemp);
-		fractMax	= fTemp > 0;
-
-		for (int j = 0; j < r3dPoly.number && min != max; j++) {
-
-			if (!fractMin) {
-				if (r3dPoly.v[j].texcoords[i] == min) {
-					r3dPoly.v[j].texcoords[i] += offset[i];
-				}
-			}
-
-			if (!fractMax) {
-				if (r3dPoly.v[j].texcoords[i] == max) {
-					r3dPoly.v[j].texcoords[i] -= offset[i];
-				}
-			}
-		}
-	}
-}
-
-void CNew3D::CacheModel(Model *m, const UINT32 *data)
-{
-	Vertex			prev[4];
-	PolyHeader		ph;
-	int				numPolys	= 0;
-	UINT64			lastHash	= -1;
-	SortingMesh*	currentMesh = nullptr;
-	
-	std::map<UINT64, SortingMesh> sMap;
-
-	if (data == NULL)
-		return;
-
-	ph = data; 
-	int numTriangles = ph.NumTrianglesTotal();
-
-	// Cache all polygons
-	do {
-
-		R3DPoly		p;					// current polygon
-		GLfloat		uvScale;
-		int			i, j;
-
-		if (ph.header[6] == 0) {
-			break;
-		}
-
-		if (ph.Disabled() || !numPolys && (ph.NumSharedVerts() != 0)) {
-			continue;
-		}
-
-		// create a hash value based on poly attributes -todo add more attributes
-		auto hash = ph.Hash();
-
-		if (hash != lastHash) {
-
-			if (sMap.count(hash) == 0) {
-
-				sMap[hash] = SortingMesh();
-
-				currentMesh = &sMap[hash];
-
-				//make space for our vertices
-				currentMesh->polys.reserve(numTriangles);
-
-				//copy attributes
-				currentMesh->doubleSided	= false;			// we will double up polys
-				currentMesh->textured		= ph.TexEnabled();
-				currentMesh->alphaTest		= ph.AlphaTest();
-				currentMesh->textureAlpha	= ph.TextureAlpha();
-				currentMesh->polyAlpha		= ph.PolyAlpha();
-				currentMesh->lighting		= ph.LightEnabled() && !ph.FixedShading();
-				currentMesh->layered		= ph.Layered();
-				
-				if (currentMesh->lighting) {
-					if (ph.SpecularEnabled()) {
-						currentMesh->specular = true;
-						currentMesh->shininess = 0;// ph.Shininess();
-						currentMesh->specularCoefficient = 0; // ph.SpecularValue();
-					}
-				}
-	
-				currentMesh->fogIntensity = ph.LightModifier();
-
-				if (ph.TexEnabled()) {
-					currentMesh->format			= m_texSheet.GetTexFormat(ph.TexFormat(), ph.AlphaTest());
-
-					if (currentMesh->format == 7) {
-						currentMesh-> alphaTest = false;	// alpha test is a 1 bit test, this format needs a lower threshold, since it has 16 levels of transparency
-					}
-
-					currentMesh->x				= ph.X();
-					currentMesh->y				= ph.Y();
-					currentMesh->width			= ph.TexWidth();
-					currentMesh->height			= ph.TexHeight();
-					currentMesh->mirrorU		= ph.TexUMirror();
-					currentMesh->mirrorV		= ph.TexVMirror();
-					currentMesh->microTexture	= ph.MicroTexture();
-				}
-			}
-
-			currentMesh = &sMap[hash];
-		}
-
-		lastHash = hash;		
-
-		// Obtain basic polygon parameters
-		p.number	= ph.NumVerts();
-		uvScale		= ph.UVScale();
-
-		ph.FaceNormal(p.faceNormal);
-
-		// Fetch reused vertices according to bitfield, then new verts
-		i = 0;
-		j = 0;
-		for (i = 0; i < 4; i++)		// up to 4 reused vertices
-		{
-			if (ph.SharedVertex(i))
-			{
-				p.v[j] = prev[i];
-				++j;
-			}
-		}
-
-		// copy face attributes
-
-		if ((ph.header[1] & 2) == 0) {
-			int colorIdx = ph.ColorIndex();
-			p.faceColour[2] = (m_polyRAM[m_colorTableAddr + colorIdx] & 0xFF) / 255.f;
-			p.faceColour[1] = ((m_polyRAM[m_colorTableAddr + colorIdx] >> 8) & 0xFF) / 255.f;
-			p.faceColour[0] = ((m_polyRAM[m_colorTableAddr + colorIdx] >> 16) & 0xFF) / 255.f;
-		}
-		else {
-			if (ph.ColorDisabled()) {		// no colours were set
-				p.faceColour[0] = 1.0f;
-				p.faceColour[1] = 1.0f;
-				p.faceColour[2] = 1.0f;
-			}
-			else {
-				p.faceColour[0] = ((ph.header[4] >> 24)) / 255.f;
-				p.faceColour[1] = ((ph.header[4] >> 16) & 0xFF) / 255.f;
-				p.faceColour[2] = ((ph.header[4] >> 8) & 0xFF) / 255.f;
-			}
-		}
-
-		p.faceColour[3] = ph.Transparency() / 255.f;
-				
-		// if we have flat shading, we can't re-use normals from shared vertices
-		for (i = 0; i < p.number && !ph.SmoothShading(); i++) {
-			p.v[i].normal[0] = p.faceNormal[0];
-			p.v[i].normal[1] = p.faceNormal[1];
-			p.v[i].normal[2] = p.faceNormal[2];
-		}
-
-		UINT32* vData = ph.StartOfData();	// vertex data starts here
-
-		// remaining vertices are new and defined here
-		for (; j < p.number; j++)	
-		{
-			// Fetch vertices
-			UINT32 ix = vData[0];
-			UINT32 iy = vData[1];
-			UINT32 iz = vData[2];
-			UINT32 it = vData[3];
-
-			// Decode vertices
-			p.v[j].pos[0] = (GLfloat)(((INT32)ix) >> 8) * m_vertexFactor;
-			p.v[j].pos[1] = (GLfloat)(((INT32)iy) >> 8) * m_vertexFactor;
-			p.v[j].pos[2] = (GLfloat)(((INT32)iz) >> 8) * m_vertexFactor;
-
-			// Per vertex normals
-			if (ph.SmoothShading()) {
-				p.v[j].normal[0] = (INT8)(ix & 0xFF) / 128.f;
-				p.v[j].normal[1] = (INT8)(iy & 0xFF) / 128.f;
-				p.v[j].normal[2] = (INT8)(iz & 0xFF) / 128.f;
-			}
-
-			if (ph.FixedShading() && ph.LightEnabled()) {
-				UINT8 shade = (UINT8)((ix + 128) & 0xFF);
-				p.v[j].color[0] = shade;	// hardware doesn't really have per vertex colours, only per poly
-				p.v[j].color[1] = shade;
-				p.v[j].color[2] = shade;
-				p.v[j].color[3] = 255;
-			}
-			else {
-				p.v[j].color[0] = 255;
-				p.v[j].color[1] = 255;
-				p.v[j].color[2] = 255;
-				p.v[j].color[3] = 255;
-			}
-
-			float texU, texV = 0;
-
-			// tex coords
-			if (currentMesh->textured) {
-				Texture::GetCoordinates(currentMesh->width, currentMesh->height, (UINT16)(it >> 16), (UINT16)(it & 0xFFFF), uvScale, texU, texV);
-			}
-
-			p.v[j].texcoords[0] = texU;
-			p.v[j].texcoords[1] = texV;
-
-			vData += 4;
-		}
-
-		// check if we need to modify the texture coordinates
-		{
-			float offset[2] = { 0 };
-
-			if (ph.TexEnabled()) {
-
-				if (!ph.TexSmoothU() && !ph.TexUMirror()) {
-					offset[0] = 0.5f / ph.TexWidth();	// half texel
-				}
-
-				if (!ph.TexSmoothV() && !ph.TexVMirror()) {
-					offset[1] = 0.5f / ph.TexHeight();	// half texel
-				}
-
-				OffsetTexCoords(p, offset);
-			}
-		}
-
-		// check if we need double up vertices for two sided lighting
-		if (ph.DoubleSided()) {
-
-			R3DPoly tempP = p;
-
-			// flip normals
-			V3::inverse(tempP.faceNormal);
-
-			for (int i = 0; i < tempP.number; i++) {
-				V3::inverse(tempP.v[i].normal);
-			}
-
-			CopyVertexData(tempP, currentMesh->polys);
-		}
-
-		// Copy this polygon into the model buffer
-		CopyVertexData(p, currentMesh->polys);
-		numPolys++;
-		
-		// Copy current vertices into previous vertex array
-		for (i = 0; i < 4; i++) {
-			prev[i] = p.v[i];
-		}
-
-	} while (ph.NextPoly());
-
-	//sorted the data, now copy to main data structures
-
-	// we know how many meshes we have so reserve appropriate space
-	m->meshes->reserve(sMap.size());
-
-	for (auto& it : sMap) {
-
-		if (m->dynamic) {
-
-			// calculate VBO values for current mesh
-			it.second.vboOffset		= m_polyBufferRam.size() + MAX_ROM_POLYS;
-			it.second.triangleCount = it.second.polys.size();
-
-			// copy poly data to main buffer
-			m_polyBufferRam.insert(m_polyBufferRam.end(), it.second.polys.begin(), it.second.polys.end());
-		}
-		else {
-			// calculate VBO values for current mesh
-			it.second.vboOffset		= m_polyBufferRom.size();
-			it.second.triangleCount = it.second.polys.size();
-
-			// copy poly data to main buffer
-			m_polyBufferRom.insert(m_polyBufferRom.end(), it.second.polys.begin(), it.second.polys.end());
-		}
-
-		//copy the temp mesh into the model structure
-		//this will lose the associated vertex data, which is now copied to the main buffer anyway
-		m->meshes->push_back(it.second);
-	}
-}
-
-float CNew3D::Determinant3x3(const float m[16]) {
-
-	/*
-		| A B C |
-	M = | D E F |
-		| G H I |
-
-	then the determinant is calculated as follows:
-
-	det M = A * (EI - HF) - B * (DI - GF) + C * (DH - GE)
-	*/
-
-	return m[0] * ((m[5] * m[10]) - (m[6] * m[9])) - m[4] * ((m[1] * m[10]) - (m[2] * m[9])) + m[8] * ((m[1] * m[6]) - (m[2] * m[5]));
-}
-
-bool CNew3D::IsDynamicModel(UINT32 *data)
-{
-	if (data == NULL) {
-		return false;
-	}
-
-	PolyHeader p(data);
-
-	do {
-
-		if ((p.header[1] & 2) == 0) {		// model has rgb colour palette 
-			return true;
-		}
-
-		if (p.header[6] == 0) {
-			break;
-		}
-
-	} while (p.NextPoly());
-
-	return false;
-}
-
-bool CNew3D::IsVROMModel(UINT32 modelAddr)
-{
-	return modelAddr >= 0x100000;
-}
-
-void CNew3D::CalcTexOffset(int offX, int offY, int page, int x, int y, int& newX, int& newY)
-{
-	newX = (x + offX) & 2047;	// wrap around 2048, shouldn't be required
-
-	int oldPage = y / 1024;
-
-	y -= (oldPage * 1024);	// remove page from tex y
-
-	// calc newY with wrap around, wraps around in the same sheet, not into another memory sheet
-
-	newY = (y + offY) & 1023;
-
-	// add page to Y
-
-	newY += ((oldPage + page) & 1) * 1024;		// max page 0-1
-}
-
-UINT32 CNew3D::ConvertProFloat(UINT32 a1)
-{
-	int exponent = (a1 & 0x7E000000) >> 25;
-
-	if (exponent <= 31) {	// positive
-		exponent += 127;
-	}
-	else {					// negative exponent
-		exponent -= 64;
-		exponent += 127;
-	}
-	
-	int mantissa = (a1 & 0x1FFFFFF) >> 2;
-
-	return (a1 & 0x80000000) | (exponent << 23) | mantissa;
-}
-
-UINT32 CNew3D::Convert16BitProFloat(UINT32 a1)
-{
-	return ConvertProFloat(a1 << 15);
-}
-
-float CNew3D::ToFloat(UINT32 a1)
-{
-	return *(float*)(&a1);
-}
-
-void CNew3D::CalcBox(float distance, BBox& box)
-{
-	//bottom 
-	box.points[0][0] = -distance;
-	box.points[0][1] = -distance;
-	box.points[0][2] =  distance;
-
-	box.points[1][0] = -distance;
-	box.points[1][1] = -distance;
-	box.points[1][2] = -distance;
-
-	box.points[2][0] =  distance;
-	box.points[2][1] = -distance;
-	box.points[2][2] = -distance;
-
-	box.points[3][0] =  distance;
-	box.points[3][1] = -distance;
-	box.points[3][2] =  distance;
-
-	//top
-	box.points[4][0] = -distance;
-	box.points[4][1] =  distance;
-	box.points[4][2] =  distance;
-
-	box.points[5][0] = -distance;
-	box.points[5][1] =  distance;
-	box.points[5][2] = -distance;
-
-	box.points[6][0] =  distance;
-	box.points[6][1] =  distance;
-	box.points[6][2] = -distance;
-
-	box.points[7][0] = distance;
-	box.points[7][1] = distance;
-	box.points[7][2] = distance;
-}
-
-} // New3D
-
diff --git a/Src/Graphics/New3D/backup/bounding box code/New3D.h b/Src/Graphics/New3D/backup/bounding box code/New3D.h
deleted file mode 100644
index b558a13..0000000
--- a/Src/Graphics/New3D/backup/bounding box code/New3D.h	
+++ /dev/null
@@ -1,237 +0,0 @@
-/**
-** Supermodel
-** A Sega Model 3 Arcade Emulator.
-** Copyright 2011 Bart Trzynadlowski, Nik Henson
-**
-** This file is part of Supermodel.
-**
-** Supermodel is free software: you can redistribute it and/or modify it under
-** the terms of the GNU General Public License as published by the Free
-** Software Foundation, either version 3 of the License, or (at your option)
-** any later version.
-**
-** Supermodel is distributed in the hope that it will be useful, but WITHOUT
-** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-** FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-** more details.
-**
-** You should have received a copy of the GNU General Public License along
-** with Supermodel.  If not, see <http://www.gnu.org/licenses/>.
-**/
-
-/*
-* New3D.h
-*
-* Header file defining the CNew3D class: OpenGL Real3D graphics engine.
-*/
-
-#ifndef INCLUDED_NEW3D_H
-#define INCLUDED_NEW3D_H
-
-#include "Pkgs/glew.h"
-#include "Types.h"
-#include "TextureSheet.h"
-#include "Graphics/IRender3D.h"
-#include "Model.h"
-#include "Mat4.h"
-#include "R3DShader.h"
-#include "VBO.h"
-#include "R3DData.h"
-#include "Vec.h"
-
-namespace New3D {
-
-class CNew3D : public IRender3D
-{
-public:
-	/*
-	* RenderFrame(void):
-	*
-	* Renders the complete scene database. Must be called between BeginFrame() and
-	* EndFrame(). This function traverses the scene database and builds up display
-	* lists.
-	*/
-	void RenderFrame(void);
-
-	/*
-	* BeginFrame(void):
-	*
-	* Prepare to render a new frame. Must be called once per frame prior to
-	* drawing anything.
-	*/
-	void BeginFrame(void);
-
-	/*
-	* EndFrame(void):
-	*
-	* Signals the end of rendering for this frame. Must be called last during
-	* the frame.
-	*/
-	void EndFrame(void);
-
-	/*
-	* UploadTextures(x, y, width, height):
-	*
-	* Signals that a portion of texture RAM has been updated.
-	*
-	* Parameters:
-	*		x		X position within texture RAM.
-	*		y		Y position within texture RAM.
-	*		width	Width of texture data in texels.
-	*		height	Height.
-	*/
-	void UploadTextures(unsigned x, unsigned y, unsigned width, unsigned height);
-
-	/*
-	* AttachMemory(cullingRAMLoPtr, cullingRAMHiPtr, polyRAMPtr, vromPtr,
-	* 				textureRAMPtr):
-	*
-	* Attaches RAM and ROM areas. This must be done prior to any rendering
-	* otherwise the program may crash with an access violation.
-	*
-	* Parameters:
-	*		cullingRAMLoPtr		Pointer to low culling RAM (4 MB).
-	*		cullingRAMHiPtr		Pointer to high culling RAM (1 MB).
-	*		polyRAMPtr			Pointer to polygon RAM (4 MB).
-	*		vromPtr				Pointer to video ROM (64 MB).
-	*		textureRAMPtr		Pointer to texture RAM (8 MB).
-	*/
-	void AttachMemory(const UINT32 *cullingRAMLoPtr,
-		const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr,
-		const UINT32 *vromPtr, const UINT16 *textureRAMPtr);
-
-	/*
-	* SetStep(stepID):
-	*
-	* Sets the Model 3 hardware stepping, which also determines the Real3D
-	* functionality. The default is Step 1.0. This should be called prior to
-	* any other emulation functions and after Init().
-	*
-	* Parameters:
-	*		stepID	0x10 for Step 1.0, 0x15 for Step 1.5, 0x20 for Step 2.0,
-	*				or 0x21 for Step 2.1. Anything else defaults to 1.0.
-	*/
-	void SetStep(int stepID);
-
-	/*
-	* Init(xOffset, yOffset, xRes, yRes, totalXRes, totalYRes):
-	*
-	* One-time initialization of the context. Must be called before any other
-	* members (meaning it should be called even before being attached to any
-	* other objects that want to use it).
-	*
-	* External shader files are loaded according to configuration settings.
-	*
-	* Parameters:
-	*		xOffset		X offset of the viewable area within OpenGL display
-	*                  surface, in pixels.
-	*		yOffset		Y offset.
-	*		xRes		Horizontal resolution of the viewable area.
-	*		yRes		Vertical resolution.
-	*		totalXRes	Horizontal resolution of the complete display area.
-	*		totalYRes	Vertical resolution.
-	*
-	* Returns:
-	*		OKAY is successful, otherwise FAILED if a non-recoverable error
-	*		occurred. Any allocated memory will not be freed until the
-	*		destructor is called. Prints own error messages.
-	*/
-	bool Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXRes, unsigned totalYRes);
-
-	/*
-	* CRender3D(void):
-	* ~CRender3D(void):
-	*
-	* Constructor and destructor.
-	*/
-	CNew3D(void);
-	~CNew3D(void);
-
-private:
-	/*
-	* Private Members
-	*/
-
-	// Real3D address translation
-	const UINT32 *TranslateCullingAddress(UINT32 addr);
-	const UINT32 *TranslateModelAddress(UINT32 addr);
-
-	// Matrix stack
-	void MultMatrix(UINT32 matrixOffset, Mat4& mat);
-	void InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat);
-
-	// Scene database traversal
-	bool DrawModel(UINT32 modelAddr);
-	void DescendCullingNode(UINT32 addr);
-	void DescendPointerList(UINT32 addr);
-	void DescendNodePtr(UINT32 nodeAddr);
-	void RenderViewport(UINT32 addr);
-	void DrawBoundingBoxes();
-
-	// building the scene
-	void CacheModel(Model *m, const UINT32 *data);
-	void CopyVertexData(const R3DPoly& r3dPoly, std::vector<Poly>& polyArray);
-	void OffsetTexCoords(R3DPoly& r3dPoly, float offset[2]);
-
-	void RenderScene(int priority, bool alpha);
-	float Determinant3x3(const float m[16]);
-	bool IsDynamicModel(UINT32 *data);		// check if the model has a colour palette
-	bool IsVROMModel(UINT32 modelAddr);
-
-	void CalcTexOffset(int offX, int offY, int page, int x, int y, int& newX, int& newY);
-
-	UINT32 ConvertProFloat(UINT32 a1);			// return float in hex or integer format
-	UINT32 Convert16BitProFloat(UINT32 a1);
-	float ToFloat(UINT32 a1);					// integer float to actual IEEE 754 float			
-
-	/*
-	* Data
-	*/
-
-	// Stepping
-	int		m_step;
-	int		m_offset;			// offset to subtract for words 3 and higher of culling nodes
-	float	m_vertexFactor;		// fixed-point conversion factor for vertices
-
-	// Memory (passed from outside)
-	const UINT32	*m_cullingRAMLo;	// 4 MB
-	const UINT32	*m_cullingRAMHi;	// 1 MB
-	const UINT32	*m_polyRAM;			// 4 MB
-	const UINT32	*m_vrom;			// 64 MB
-	const UINT16	*m_textureRAM;		// 8 MB
-
-	// Resolution and scaling factors (to support resolutions higher than 496x384) and offsets
-	float		m_xRatio, m_yRatio;
-	unsigned	m_xOffs, m_yOffs;
-	unsigned 	m_totalXRes, m_totalYRes;
-
-	// Real3D Base Matrix Pointer
-	const float	*m_matrixBasePtr;
-	UINT32 m_colorTableAddr = 0x400;		// address of color table in polygon RAM
-
-	TextureSheet	m_texSheet;
-	NodeAttributes	m_nodeAttribs;
-	Mat4			m_modelMat;				// current modelview matrix
-
-	std::vector<Node> m_nodes;				// this represents the entire render frame
-	std::vector<Poly> m_polyBufferRam;		// dynamic polys
-	std::vector<Poly> m_polyBufferRom;		// rom polys
-	std::unordered_map<UINT32, std::shared_ptr<std::vector<Mesh>>> m_romMap;	// a hash table for all the ROM models. The meshes don't have model matrices or tex offsets yet
-
-	VBO m_vbo;								// large VBO to hold our poly data, start of VBO is ROM data, ram polys follow
-	R3DShader m_r3dShader;
-
-	struct BBox
-	{
-		V3::Vec3 points[8];
-		Mat4 mat;
-	};
-
-	void CalcBox(float distance, BBox& box);
-
-	std::vector<BBox> m_bBoxes;
-};
-
-} // New3D
-
-#endif  // INCLUDED_NEW3D_H
diff --git a/Src/Graphics/New3D/backup/clipping plane attempt/Model.h b/Src/Graphics/New3D/backup/clipping plane attempt/Model.h
deleted file mode 100644
index aa49076..0000000
--- a/Src/Graphics/New3D/backup/clipping plane attempt/Model.h	
+++ /dev/null
@@ -1,147 +0,0 @@
-#ifndef _MODEL_H_
-#define _MODEL_H_
-
-#include "Types.h"
-#include <vector>
-#include <unordered_map>
-#include <map>
-#include <memory>
-#include "Texture.h"
-#include "Mat4.h"
-
-namespace New3D {
-
-struct Vertex
-{
-	float pos[3];
-	float normal[3];
-	float texcoords[2];
-	float color[4];			//rgba
-};
-
-struct Poly		// our polys are always 3 triangles, unlike the real h/w
-{
-	Vertex p1;
-	Vertex p2;
-	Vertex p3;
-};
-
-struct R3DPoly
-{
-	Vertex v[4];			// just easier to have them as an array
-	float faceNormal[3];	// we need this to help work out poly winding, i assume the h/w uses this instead of calculating normals itself
-	float faceColour[4];	// per face colour
-	int number = 4;
-};
-
-struct Mesh
-{
-	// texture
-	int format, x, y, width, height = 0;
-	bool microTexture = false;
-	int microTextureID = 0;
-	bool mirrorU = false;
-	bool mirrorV = false;
-
-	// attributes
-	bool doubleSided	= false;
-	bool textured		= false;
-	bool polyAlpha		= false;		// specified in the rgba colour
-	bool textureAlpha	= false;		// use alpha in texture
-	bool alphaTest		= false;		// discard fragment based on alpha (ogl does this with fixed function)
-	bool clockWise		= true;			// we need to check if the matrix will change the winding
-	bool layered		= false;		// stencil poly
-
-	// lighting
-	bool lighting		= false;
-	bool specular		= false;
-	float shininess		= 0;
-	float specularCoefficient = 0;
-	
-	// fog
-	float fogIntensity = 1.0f;
-
-	// opengl resources
-	int vboOffset		= 0;			// this will be calculated later
-	int triangleCount	= 0;
-};
-
-struct SortingMesh : public Mesh		// This struct temporarily holds the model data, before it gets copied to the main buffer
-{
-	std::vector<Poly> polys;
-};
-
-struct Model
-{
-	std::shared_ptr<std::vector<Mesh>> meshes;	// this reason why this is a shared ptr to an array, is that multiple models might use the same meshes
-
-	//which memory are we in
-	bool dynamic = true;
-
-	// texture offsets for model
-	int textureOffsetX = 0;
-	int textureOffsetY = 0;
-	int page = 0;
-
-	//matrices
-	float modelMat[16];
-	float determinant;				// we check if the determinant of the matrix is negative, if it is, the matrix will swap the axis order
-};
-
-struct Viewport
-{
-	int		vpX, vpY, vpWidth, vpHeight;// real3d viewport paramaters
-	float	left, right, bottom, top;	// angles for projection matrix - near/far calculated later
-
-	Mat4	projectionMatrix;			// projection matrix
-	float	lightingParams[6];			// lighting parameters (see RenderViewport() and vertex shader)
-	float	spotEllipse[4];				// spotlight ellipse (see RenderViewport())
-	float	spotRange[2];				// Z range
-	float	spotColor[3];				// color
-	float	fogParams[5];				// fog parameters (...)
-	float	scrollFog;					// a transparency value that determines if fog is blended over the bottom 2D layer
-	int		x, y;						// viewport coordinates (scaled and in OpenGL format)
-	int		width, height;				// viewport dimensions (scaled for display surface size)
-	int		priority;
-};
-
-enum class Clip { INSIDE, OUTSIDE, INTERCEPT };
-
-class NodeAttributes
-{
-public:
-
-	NodeAttributes();
-
-	bool Push();
-	bool Pop();
-	bool StackLimit();
-	void Reset();
-
-	int currentTexOffsetX;
-	int currentTexOffsetY;
-	int currentPage;
-	Clip currentClipStatus;
-
-private:
-
-	struct NodeAttribs
-	{
-		int texOffsetX;
-		int texOffsetY;
-		int page;
-		Clip clip;
-	};
-	std::vector<NodeAttribs> m_vecAttribs;
-};
-
-struct Node
-{
-	Viewport viewport;
-	std::vector<Model> models;
-};
-
-} // New3D
-
-
-#endif
\ No newline at end of file
diff --git a/Src/Graphics/New3D/backup/clipping plane attempt/New3D.cpp b/Src/Graphics/New3D/backup/clipping plane attempt/New3D.cpp
deleted file mode 100644
index a066b3f..0000000
--- a/Src/Graphics/New3D/backup/clipping plane attempt/New3D.cpp	
+++ /dev/null
@@ -1,1431 +0,0 @@
-#include "New3D.h"
-#include "PolyHeader.h"
-#include "Texture.h"
-#include "Vec.h"
-#include <cmath>
-#include <algorithm>
-#include <limits>
-#include "R3DFloat.h"
-
-#define MAX_RAM_POLYS 100000	
-#define MAX_ROM_POLYS 500000
-
-#ifndef M_PI
-#define M_PI 3.14159265359
-#endif
-
-namespace New3D {
-
-CNew3D::CNew3D()
-{
-	m_cullingRAMLo	= nullptr;
-	m_cullingRAMHi	= nullptr;
-	m_polyRAM		= nullptr;
-	m_vrom			= nullptr;
-	m_textureRAM	= nullptr;
-}
-
-CNew3D::~CNew3D()
-{
-	m_vbo.Destroy();
-}
-
-void CNew3D::AttachMemory(const UINT32 *cullingRAMLoPtr, const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr, const UINT32 *vromPtr, const UINT16 *textureRAMPtr)
-{
-	m_cullingRAMLo	= cullingRAMLoPtr;
-	m_cullingRAMHi	= cullingRAMHiPtr;
-	m_polyRAM		= polyRAMPtr;
-	m_vrom			= vromPtr;
-	m_textureRAM	= textureRAMPtr;
-}
-
-void CNew3D::SetStep(int stepID)
-{
-	m_step = stepID;
-
-	if ((m_step != 0x10) && (m_step != 0x15) && (m_step != 0x20) && (m_step != 0x21)) {
-		m_step = 0x10;
-	}
-
-	if (m_step > 0x10) {
-		m_offset = 0;							// culling nodes are 10 words
-		m_vertexFactor = (1.0f / 2048.0f);		// vertices are in 13.11 format
-	}
-	else {
-		m_offset = 2;							// 8 words
-		m_vertexFactor = (1.0f / 128.0f);		// 17.7
-	}
-
-	m_vbo.Create(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(Poly) * (MAX_RAM_POLYS + MAX_ROM_POLYS));
-}
-
-bool CNew3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXResParam, unsigned totalYResParam)
-{
-	// Resolution and offset within physical display area
-	m_xRatio	= xRes / 496.0f;
-	m_yRatio	= yRes / 384.0f;
-	m_xOffs		= xOffset;
-	m_yOffs		= yOffset;
-	m_totalXRes	= totalXResParam;
-	m_totalYRes = totalYResParam;
-
-	m_r3dShader.LoadShader();
-
-	glUseProgram(0);
-
-	return OKAY;	// OKAY ? wtf ..
-}
-
-void CNew3D::UploadTextures(unsigned x, unsigned y, unsigned width, unsigned height)
-{
-	if (x >= 1024) {
-		if (y >= 512 && y < 1024 || y >= 1536 && y < 2048) {
-			return;
-		}
-	}
-
-	m_texSheet.Invalidate(x, y, width, height);
-}
-
-void CNew3D::DrawScrollFog()
-{
-	for (int i = 0; i < 4; i++) {
-
-		for (auto &n : m_nodes) {
-
-			if (n.viewport.scrollFog > 0 && n.viewport.priority==i) {
-
-				float *rgb = n.viewport.fogParams;
-				m_r3dScrollFog.DrawScrollFog(rgb[0], rgb[1], rgb[2], n.viewport.scrollFog);
-
-				return;	// only allowed once per frame?
-			}
-		}
-	}
-}
-
-void CNew3D::RenderScene(int priority, bool alpha)
-{
-	if (alpha) {
-		glEnable(GL_BLEND);
-	}
-
-	for (auto &n : m_nodes) {
-
-		if (n.viewport.priority != priority || n.models.empty()) {
-			continue;
-		}
-
-		std::shared_ptr<Texture> tex1;
-
-		glViewport		(n.viewport.x, n.viewport.y, n.viewport.width, n.viewport.height);
-		glMatrixMode	(GL_PROJECTION);
-		glLoadMatrixf	(n.viewport.projectionMatrix);
-		glMatrixMode	(GL_MODELVIEW);
-
-		m_r3dShader.SetViewportUniforms(&n.viewport);
-
-		for (auto &m : n.models) {
-
-			bool matrixLoaded = false;
-
-			if (m.meshes->empty()) {
-				continue;
-			}
-
-			m_r3dShader.SetModelStates(&m);
-
-			for (auto &mesh : *m.meshes) {
-
-				if (alpha) {
-					if (!mesh.textureAlpha && !mesh.polyAlpha) {
-						continue;
-					}
-				}
-				else {
-					if (mesh.textureAlpha || mesh.polyAlpha) {
-						continue;
-					}
-				}
-
-				if (!matrixLoaded) {
-					glLoadMatrixf(m.modelMat);
-					matrixLoaded = true;		// do this here to stop loading matrices we don't need. Ie when rendering non transparent etc
-				}
-				
-				if (mesh.textured) {
-
-					int x, y;
-					CalcTexOffset(m.textureOffsetX, m.textureOffsetY, m.page, mesh.x, mesh.y, x, y);
-
-					if (tex1 && tex1->Compare(x, y, mesh.width, mesh.height, mesh.format)) {
-						tex1->SetWrapMode(mesh.mirrorU, mesh.mirrorV);	
-					}
-					else {
-						tex1 = m_texSheet.BindTexture(m_textureRAM, mesh.format, mesh.mirrorU, mesh.mirrorV, x, y, mesh.width, mesh.height);
-						if (tex1) {
-							tex1->BindTexture();
-							tex1->SetWrapMode(mesh.mirrorU, mesh.mirrorV);
-						}
-					}
-
-					if (mesh.microTexture) {
-
-						int mX, mY;
-						glActiveTexture(GL_TEXTURE1);
-						m_texSheet.GetMicrotexPos(y / 1024, mesh.microTextureID, mX, mY);
-						auto tex2 = m_texSheet.BindTexture(m_textureRAM, 0, false, false, mX, mY, 128, 128);
-						if (tex2) {
-							tex2->BindTexture();
-						}
-						glActiveTexture(GL_TEXTURE0);
-					}
-				}
-				
-				m_r3dShader.SetMeshUniforms(&mesh);
-				glDrawArrays(GL_TRIANGLES, mesh.vboOffset*3, mesh.triangleCount*3);			// times 3 to convert triangles to vertices
-			}
-		}
-	}
-
-	glDisable(GL_BLEND);
-	glDepthMask(GL_TRUE);
-	glDisable(GL_STENCIL_TEST);
-}
-
-void CNew3D::RenderFrame(void)
-{
-	// reset our min/max near/far planes
-	for (int i = 0; i < 4; i++) {
-		m_nfPair[i].nearVal = std::numeric_limits<float>::max();
-		m_nfPair[i].farVal = 0;
-	}
-
-	// release any resources from last frame
-	m_polyBufferRam.clear();	// clear dyanmic model memory buffer
-	m_nodes.clear();		// memory will grow during the object life time, that's fine, no need to shrink to fit
-	m_modelMat.Release();	// would hope we wouldn't need this but no harm in checking
-	m_nodeAttribs.Reset();
-
-	RenderViewport(0x800000);					// build model structure
-	CalcViewports();							// calculate derived frustum paramaters
-	DrawScrollFog();							// fog layer if applicable must be drawn here
-
-	glDepthFunc		(GL_LEQUAL);
-	glEnable		(GL_DEPTH_TEST);
-	glActiveTexture	(GL_TEXTURE0);
-	glEnable		(GL_CULL_FACE);
-	glFrontFace		(GL_CW);
-
-	glStencilFunc	(GL_EQUAL, 0, 0xFF);			// basically stencil test passes if the value is zero
-	glStencilOp		(GL_KEEP, GL_INCR, GL_INCR);		// if the stencil test passes, we incriment the value
-	glStencilMask	(0xFF);
-	
-	m_vbo.Bind(true);
-	m_vbo.BufferSubData(MAX_ROM_POLYS*sizeof(Poly), m_polyBufferRam.size()*sizeof(Poly), m_polyBufferRam.data());	// upload all the dynamic data to GPU in one go
-
-	if (m_polyBufferRom.size()) {
-
-		// sync rom memory with vbo
-		int romBytes	= (int)m_polyBufferRom.size() * sizeof(Poly);
-		int vboBytes	= m_vbo.GetSize();
-		int size		= romBytes - vboBytes;
-
-		if (size) {
-			//check we haven't blown up the memory buffers
-			//we will lose rom models for 1 frame is this happens, not the end of the world, as probably won't ever happen anyway
-			if (m_polyBufferRom.size() >= MAX_ROM_POLYS) {
-				m_polyBufferRom.clear();
-				m_romMap.clear();
-				m_vbo.Reset();
-			}
-			else {
-				m_vbo.AppendData(size, &m_polyBufferRom[vboBytes / sizeof(Poly)]);
-			}
-		}
-	}
-	
-	glEnableClientState(GL_VERTEX_ARRAY);
-	glEnableClientState(GL_NORMAL_ARRAY);
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-	glEnableClientState(GL_COLOR_ARRAY);
-
-	// before draw, specify vertex and index arrays with their offsets, offsetof is maybe evil ..
-	glVertexPointer		(3, GL_FLOAT, sizeof(Vertex), 0);
-	glNormalPointer		(GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, normal));
-	glTexCoordPointer	(2, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, texcoords));
-	glColorPointer		(4, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, color));
-
-	m_r3dShader.SetShader(true);
-
-	for (int pri = 0; pri <= 3; pri++) {
-		glClear		(GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
-		RenderScene	(pri, false);
-		RenderScene	(pri, true);
-	}
-
-	m_r3dShader.SetShader(false);		// unbind shader
-	m_vbo.Bind(false);
-
-	glDisable(GL_CULL_FACE);
-	glDisableClientState(GL_VERTEX_ARRAY);
-	glDisableClientState(GL_NORMAL_ARRAY);
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-	glDisableClientState(GL_COLOR_ARRAY);
-
-	for (int i = 0; i < 4; i++) {
-		printf("index %i - pair %f %f\n", i, m_nfPair[i].nearVal, m_nfPair[i].farVal);
-	}
-	printf("\n");
-}
-
-void CNew3D::BeginFrame(void)
-{
-}
-
-void CNew3D::EndFrame(void)
-{
-}
-
-/******************************************************************************
-Real3D Address Translation
-
-Functions that interpret word-granular Real3D addresses and return pointers.
-******************************************************************************/
-
-// Translates 24-bit culling RAM addresses
-const UINT32* CNew3D::TranslateCullingAddress(UINT32 addr)
-{
-	addr &= 0x00FFFFFF;	// caller should have done this already
-
-	if ((addr >= 0x800000) && (addr < 0x840000)) {
-		return &m_cullingRAMHi[addr & 0x3FFFF];
-	}
-	else if (addr < 0x100000) {
-		return &m_cullingRAMLo[addr];
-	}
-
-	return NULL;
-}
-
-// Translates model references
-const UINT32* CNew3D::TranslateModelAddress(UINT32 modelAddr)
-{
-	modelAddr &= 0x00FFFFFF;	// caller should have done this already
-
-	if (modelAddr < 0x100000) {
-		return &m_polyRAM[modelAddr];
-	}
-	else {
-		return &m_vrom[modelAddr];
-	}
-}
-
-bool CNew3D::DrawModel(UINT32 modelAddr)
-{
-	const UINT32*	modelAddress;
-	bool			cached = false;
-	Model*			m;
-
-	modelAddress = TranslateModelAddress(modelAddr);
-
-	// create a new model to push onto the vector
-	m_nodes.back().models.emplace_back(Model());
-
-	// get the last model in the array
-	m = &m_nodes.back().models.back();
-
-	if (IsVROMModel(modelAddr) && !IsDynamicModel((UINT32*)modelAddress)) {
-
-		// try to find meshes in the rom cache
-
-		m->meshes = m_romMap[modelAddr];	// will create an entry with a null pointer if empty
-
-		if (m->meshes) {
-			cached = true;
-		}
-		else {
-			m->meshes = std::make_shared<std::vector<Mesh>>();
-			m_romMap[modelAddr] = m->meshes;		// store meshes in our rom map here
-		}
-
-		m->dynamic = false;
-	}
-	else {
-		m->meshes = std::make_shared<std::vector<Mesh>>();
-	}
-
-	// copy current model matrix
-	for (int i = 0; i < 16; i++) {
-		m->modelMat[i] = m_modelMat.currentMatrix[i];
-	}
-
-	//calculate determinant
-	m->determinant = Determinant3x3(m_modelMat);
-
-	// update texture offsets
-	m->textureOffsetX = m_nodeAttribs.currentTexOffsetX;
-	m->textureOffsetY = m_nodeAttribs.currentTexOffsetY;
-	m->page = m_nodeAttribs.currentPage;
-
-	if (!cached) {
-		CacheModel(m, modelAddress);
-	}
-
-	return true;
-}
-
-// Descends into a 10-word culling node
-void CNew3D::DescendCullingNode(UINT32 addr)
-{
-	const UINT32	*node, *lodTable;
-	UINT32			matrixOffset, child1Ptr, sibling2Ptr;
-	float			x, y, z;
-	int				tx, ty;
-	BBox			bbox;
-
-	if (m_nodeAttribs.StackLimit()) {
-		return;
-	}
-
-	node = TranslateCullingAddress(addr);
-
-	if (NULL == node) {
-		return;
-	}
-
-	// Extract known fields
-	child1Ptr		= node[0x07 - m_offset] & 0x7FFFFFF;	// mask colour table bits
-	sibling2Ptr		= node[0x08 - m_offset] & 0x1FFFFFF;	// mask colour table bits
-	matrixOffset	= node[0x03 - m_offset] & 0xFFF;
-
-	if ((node[0x00] & 0x07) != 0x06) {						// colour table seems to indicate no siblings
-		if (!(sibling2Ptr & 0x1000000) && sibling2Ptr) {
-			DescendCullingNode(sibling2Ptr);				// no need to mask bit, would already be zero
-		}
-	}
-
-	if ((node[0x00] & 0x04)) {
-		m_colorTableAddr = ((node[0x03 - m_offset] >> 19) << 0) | ((node[0x07 - m_offset] >> 28) << 13) | ((node[0x08 - m_offset] >> 25) << 17);
-		m_colorTableAddr &= 0x000FFFFF; // clamp to 4MB (in words) range
-	}
-
-	x = *(float *)&node[0x04 - m_offset];
-	y = *(float *)&node[0x05 - m_offset];
-	z = *(float *)&node[0x06 - m_offset];
-
-	m_nodeAttribs.Push();	// save current attribs
-
-	if (!m_offset)	// Step 1.5+
-	{
-		tx = 32 * ((node[0x02] >> 7) & 0x3F);
-		ty = 32 * (node[0x02] & 0x1F);
-
-		// apply texture offsets, else retain current ones
-		if ((node[0x02] & 0x8000))	{
-			m_nodeAttribs.currentTexOffsetX = tx;
-			m_nodeAttribs.currentTexOffsetY = ty;
-			m_nodeAttribs.currentPage = (node[0x02] & 0x4000) >> 14;
-		}
-	}
-
-	// Apply matrix and translation
-	m_modelMat.PushMatrix();
-
-	// apply translation vector
-	if ((node[0x00] & 0x10)) {
-		m_modelMat.Translate(x, y, z);
-	}
-	// multiply matrix, if specified
-	else if (matrixOffset) {
-		MultMatrix(matrixOffset,m_modelMat);
-	}
-
-	if (m_nodeAttribs.currentClipStatus != Clip::INSIDE && !(node[0] & 0x1) && !(node[0] & 0x4)) {	// and not root node and not colour table
-
-		float distance = R3DFloat::GetFloat16(node[9 - m_offset] & 0xFFFF);
-
-		if (distance > 1e-7) {	// seems to be some 16bit float min value which probably says no values here, im guessing
-			m_nfPair[m_currentPriority].nearVal = std::min(distance, m_nfPair[m_currentPriority].nearVal);	
-		}
-
-		CalcBox(distance, bbox);
-		TransformBox(m_modelMat, bbox);
-		GetBBMaxZ(m_nfPair[m_currentPriority].farVal, bbox);
-
-		m_nodeAttribs.currentClipStatus = ClipBox(bbox, m_planes);
-	}
-
-	if (m_nodeAttribs.currentClipStatus != Clip::OUTSIDE) {
-
-		// Descend down first link
-		if ((node[0x00] & 0x08))	// 4-element LOD table
-		{
-			lodTable = TranslateCullingAddress(child1Ptr);
-
-			if (NULL != lodTable) {
-				if ((node[0x03 - m_offset] & 0x20000000)) {
-					DescendCullingNode(lodTable[0] & 0xFFFFFF);
-				}
-				else {
-					DrawModel(lodTable[0] & 0xFFFFFF);	//TODO
-				}
-			}
-		}
-		else {
-			DescendNodePtr(child1Ptr);
-		}
-
-	}
-
-	m_modelMat.PopMatrix();
-
-	// Restore old texture offsets
-	m_nodeAttribs.Pop();
-}
-
-void CNew3D::DescendNodePtr(UINT32 nodeAddr)
-{
-	// Ignore null links
-	if ((nodeAddr & 0x00FFFFFF) == 0) {
-		return;
-	}
-
-	switch ((nodeAddr >> 24) & 0xFF)	// pointer type encoded in upper 8 bits
-	{
-	case 0x00:	// culling node
-		DescendCullingNode(nodeAddr & 0xFFFFFF);
-		break;
-	case 0x01:	// model (perhaps bit 2 is a flag in this case?)
-	case 0x03:
-		DrawModel(nodeAddr & 0xFFFFFF);
-		break;
-	case 0x04:	// pointer list
-		DescendPointerList(nodeAddr & 0xFFFFFF);
-		break;
-	default:
-		break;
-	}
-}
-
-void CNew3D::DescendPointerList(UINT32 addr)
-{
-	const UINT32*	list;
-	UINT32			nodeAddr;
-	int				index;
-
-	list = TranslateCullingAddress(addr);
-
-	if (NULL == list) {
-		return;
-	}
-
-	index = 0;
-
-	while (true) {
-
-		if (list[index] & 0x01000000) {
-			break;	// empty list
-		}
-
-		nodeAddr = list[index] & 0x00FFFFFF;	// clear upper 8 bits to ensure this is processed as a culling node
-
-		DescendCullingNode(nodeAddr);
-
-		if (list[index] & 0x02000000) {
-			break;	// list end
-		}
-
-		index++;
-	}
-}
-
-
-/******************************************************************************
-Matrix Stack
-******************************************************************************/
-
-// Macro to generate column-major (OpenGL) index from y,x subscripts
-#define CMINDEX(y,x)	(x*4+y)
-
-/*
-* MultMatrix():
-*
-* Multiplies the matrix stack by the specified Real3D matrix. The matrix
-* index is a 12-bit number specifying a matrix number relative to the base.
-* The base matrix MUST be set up before calling this function.
-*/
-void CNew3D::MultMatrix(UINT32 matrixOffset, Mat4& mat)
-{
-	GLfloat		m[4*4];
-	const float	*src = &m_matrixBasePtr[matrixOffset * 12];
-
-	if (m_matrixBasePtr == NULL)	// LA Machineguns
-		return;
-
-	m[CMINDEX(0, 0)] = src[3];
-	m[CMINDEX(0, 1)] = src[4];
-	m[CMINDEX(0, 2)] = src[5];
-	m[CMINDEX(0, 3)] = src[0];
-	m[CMINDEX(1, 0)] = src[6];
-	m[CMINDEX(1, 1)] = src[7];
-	m[CMINDEX(1, 2)] = src[8];
-	m[CMINDEX(1, 3)] = src[1];
-	m[CMINDEX(2, 0)] = src[9];
-	m[CMINDEX(2, 1)] = src[10];
-	m[CMINDEX(2, 2)] = src[11];
-	m[CMINDEX(2, 3)] = src[2];
-	m[CMINDEX(3, 0)] = 0.0;
-	m[CMINDEX(3, 1)] = 0.0;
-	m[CMINDEX(3, 2)] = 0.0;
-	m[CMINDEX(3, 3)] = 1.0;
-
-	mat.MultMatrix(m);
-}
-
-/*
-* InitMatrixStack():
-*
-* Initializes the modelview (model space -> view space) matrix stack and
-* Real3D coordinate system. These are the last transforms to be applied (and
-* the first to be defined on the stack) before projection.
-*
-* Model 3 games tend to define the following unusual base matrix:
-*
-*		0	0	-1	0
-*		1	0	0	0
-*		0	-1	0	0
-*		0	0	0	1
-*
-* When this is multiplied by a column vector, the output is:
-*
-*		-Z
-*		X
-*		-Y
-*		1
-*
-* My theory is that the Real3D GPU accepts vectors in Z,X,Y order. The games
-* store everything as X,Y,Z and perform the translation at the end. The Real3D
-* also has Y and Z coordinates opposite of the OpenGL convention. This
-* function inserts a compensating matrix to undo these things.
-*
-* NOTE: This function assumes we are in GL_MODELVIEW matrix mode.
-*/
-
-void CNew3D::InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat)
-{
-	GLfloat m[4 * 4];
-
-	// This matrix converts vectors back from the weird Model 3 Z,X,Y ordering
-	// and also into OpenGL viewspace (-Y,-Z)
-	m[CMINDEX(0, 0)] = 0.0;	m[CMINDEX(0, 1)] = 1.0;	m[CMINDEX(0, 2)] = 0.0;	m[CMINDEX(0, 3)] = 0.0;
-	m[CMINDEX(1, 0)] = 0.0;	m[CMINDEX(1, 1)] = 0.0;	m[CMINDEX(1, 2)] =-1.0; m[CMINDEX(1, 3)] = 0.0;
-	m[CMINDEX(2, 0)] =-1.0; m[CMINDEX(2, 1)] = 0.0;	m[CMINDEX(2, 2)] = 0.0;	m[CMINDEX(2, 3)] = 0.0;
-	m[CMINDEX(3, 0)] = 0.0;	m[CMINDEX(3, 1)] = 0.0;	m[CMINDEX(3, 2)] = 0.0;	m[CMINDEX(3, 3)] = 1.0;
-
-	mat.LoadMatrix(m);
-
-	// Set matrix base address and apply matrix #0 (coordinate system matrix)
-	m_matrixBasePtr = (float *)TranslateCullingAddress(matrixBaseAddr);
-	MultMatrix(0, mat);
-}
-
-// Draws viewports of the given priority
-void CNew3D::RenderViewport(UINT32 addr)
-{
-	static const GLfloat	color[8][3] =
-	{											// RGB1 color translation
-		{ 0.0, 0.0, 0.0 },	// off
-		{ 0.0, 0.0, 1.0 },	// blue
-		{ 0.0, 1.0, 0.0 },	// green
-		{ 0.0, 1.0, 1.0 },	// cyan
-		{ 1.0, 0.0, 0.0 }, 	// red
-		{ 1.0, 0.0, 1.0 },	// purple
-		{ 1.0, 1.0, 0.0 },	// yellow
-		{ 1.0, 1.0, 1.0 }	// white
-	};
-
-	// Translate address and obtain pointer
-	const uint32_t *vpnode = TranslateCullingAddress(addr);
-
-	if (NULL == vpnode) {
-		return;
-	}
-
-	if (vpnode[0x01] == 0) {		// memory probably hasn't been set up yet, abort
-		return;
-	}
-
-	if (!(vpnode[0] & 0x20)) {	// only if viewport enabled
-
-		uint32_t nodeAddr	= vpnode[0x02];				// scene database node pointer
-		uint32_t matrixBase = vpnode[0x16] & 0xFFFFFF;	// matrix base address
-
-		// create node object 
-		m_nodes.emplace_back(Node());
-		m_nodes.back().models.reserve(2048);			// create space for models
-
-		// get pointer to its viewport
-		Viewport *vp = &m_nodes.back().viewport;
-
-		vp->priority = (vpnode[0x00] >> 3) & 3;			// viewport priority
-		m_currentPriority = vp->priority;
-
-		// Fetch viewport parameters (TO-DO: would rounding make a difference?)
-		vp->vpX			= (int)(((vpnode[0x1A] & 0xFFFF) / 16.0f) + 0.5f);		// viewport X (12.4 fixed point)
-		vp->vpY			= (int)(((vpnode[0x1A] >> 16) / 16.0f) + 0.5f);			// viewport Y (12.4)
-		vp->vpWidth		= (int)(((vpnode[0x14] & 0xFFFF) / 4.0f) + 0.5f);		// width (14.2)
-		vp->vpHeight	= (int)(((vpnode[0x14] >> 16) / 4.0f) + 0.5f);			// height (14.2)
-
-		if (vp->vpX) {
-			vp->vpX += 2;	// bit of a hack but seems to work
-		}
-
-		if (vp->vpY) {
-			vp->vpY += 2;
-		}
-
-		LODBlendTable* tableTest = (LODBlendTable*)TranslateCullingAddress(vpnode[0x17]);
-
-		vp->left	= -atan2(*(float *)&vpnode[12],  *(float *)&vpnode[13]);
-		vp->right	=  atan2(*(float *)&vpnode[16], -*(float *)&vpnode[17]);
-		vp->top		=  atan2(*(float *)&vpnode[14],  *(float *)&vpnode[15]);
-		vp->bottom	= -atan2(*(float *)&vpnode[18], -*(float *)&vpnode[19]);
-
-		// calculate frustum planes
-		CalcFrustumPlanes(m_planes, (float *)&vpnode[12]);
-
-		// Lighting (note that sun vector points toward sun -- away from vertex)
-		vp->lightingParams[0] = *(float *)&vpnode[0x05];								// sun X
-		vp->lightingParams[1] = *(float *)&vpnode[0x06];								// sun Y
-		vp->lightingParams[2] = *(float *)&vpnode[0x04];								// sun Z
-		vp->lightingParams[3] = *(float *)&vpnode[0x07];								// sun intensity
-		vp->lightingParams[4] = (float)((vpnode[0x24] >> 8) & 0xFF) * (1.0f / 255.0f);	// ambient intensity
-		vp->lightingParams[5] = 0.0;	// reserved
-
-		// Spotlight
-		int spotColorIdx = (vpnode[0x20] >> 11) & 7;									// spotlight color index
-		vp->spotEllipse[0] = (float)((vpnode[0x1E] >> 3) & 0x1FFF);						// spotlight X position (fractional component?)
-		vp->spotEllipse[1] = (float)((vpnode[0x1D] >> 3) & 0x1FFF);						// spotlight Y
-		vp->spotEllipse[2] = (float)((vpnode[0x1E] >> 16) & 0xFFFF);					// spotlight X size (16-bit? May have fractional component below bit 16)
-		vp->spotEllipse[3] = (float)((vpnode[0x1D] >> 16) & 0xFFFF);					// spotlight Y size
-
-		vp->spotRange[0] = 1.0f / (*(float *)&vpnode[0x21]);							// spotlight start
-		vp->spotRange[1] = *(float *)&vpnode[0x1F];										// spotlight extent
-
-		if (vp->spotRange[1] == 0) {													// if light extent = 0 light is effectively disabled
-			spotColorIdx = 0;
-		}
-
-		vp->spotColor[0] = color[spotColorIdx][0];										// spotlight color
-		vp->spotColor[1] = color[spotColorIdx][1];
-		vp->spotColor[2] = color[spotColorIdx][2];
-
-		// Spotlight is applied on a per pixel basis, must scale its position and size to screen
-		vp->spotEllipse[1] = 384.0f - vp->spotEllipse[1];
-		vp->spotRange[1] += vp->spotRange[0];	// limit
-		vp->spotEllipse[2] = 496.0f / sqrt(vp->spotEllipse[2]);	// spotlight appears to be specified in terms of physical resolution (unconfirmed)
-		vp->spotEllipse[3] = 384.0f / sqrt(vp->spotEllipse[3]);
-
-		// Scale the spotlight to the OpenGL viewport
-		vp->spotEllipse[0] = vp->spotEllipse[0] * m_xRatio + m_xOffs;
-		vp->spotEllipse[1] = vp->spotEllipse[1] * m_yRatio + m_yOffs;
-		vp->spotEllipse[2] *= m_xRatio;
-		vp->spotEllipse[3] *= m_yRatio;
-
-		// Fog
-		vp->fogParams[0] = (float)((vpnode[0x22] >> 16) & 0xFF) * (1.0f / 255.0f);	// fog color R
-		vp->fogParams[1] = (float)((vpnode[0x22] >> 8) & 0xFF) * (1.0f / 255.0f);	// fog color G
-		vp->fogParams[2] = (float)((vpnode[0x22] >> 0) & 0xFF) * (1.0f / 255.0f);	// fog color B
-		vp->fogParams[3] = std::abs(*(float *)&vpnode[0x23]);						// fog density	- ocean hunter uses negative values, but looks the same
-		vp->fogParams[4] = (float)(INT16)(vpnode[0x25] & 0xFFFF)*(1.0f / 255.0f);	// fog start
-
-		vp->scrollFog = (float)(vpnode[0x20] & 0xFF) * (1.0f / 255.0f);				// scroll fog
-
-		{
-			//test fog paramaters
-			float lightFogColour[3];
-			int fogColourIdx;
-
-			fogColourIdx = (vpnode[0x20] >> 8) & 7;
-
-			lightFogColour[0] = color[fogColourIdx][0];
-			lightFogColour[1] = color[fogColourIdx][1];
-			lightFogColour[2] = color[fogColourIdx][2];
-
-			float fogAttenuation = ((vpnode[0x24] >> 16) & 0xFF) / 255.f;
-			float fogAmbient = ((vpnode[0x25] >> 16) & 0xFF) / 255.f;
-			int debug = 0;
-		}
-
-		if (std::isinf(vp->fogParams[3]) || std::isnan(vp->fogParams[3]) || std::isinf(vp->fogParams[4]) || std::isnan(vp->fogParams[4])) {	// Star Wars Trilogy
-			vp->fogParams[3] = vp->fogParams[4] = 0.0f;
-		}
-
-		// Unknown light/fog parameters
-		float scrollAtt = (float)(vpnode[0x24] & 0xFF) * (1.0f / 255.0f);	// scroll attenuation
-
-		// Clear texture offsets before proceeding
-		m_nodeAttribs.Reset();
-
-		// Set up coordinate system and base matrix
-		InitMatrixStack(matrixBase, m_modelMat);
-
-		// Safeguard: weird coordinate system matrices usually indicate scenes that will choke the renderer
-		if (NULL != m_matrixBasePtr)
-		{
-			float	m21, m32, m13;
-
-			// Get the three elements that are usually set and see if their magnitudes are 1
-			m21 = m_matrixBasePtr[6];
-			m32 = m_matrixBasePtr[10];
-			m13 = m_matrixBasePtr[5];
-
-			m21 *= m21;
-			m32 *= m32;
-			m13 *= m13;
-
-			if ((m21 > 1.05) || (m21 < 0.95))
-				return;
-			if ((m32 > 1.05) || (m32 < 0.95))
-				return;
-			if ((m13 > 1.05) || (m13 < 0.95))
-				return;
-		}
-
-		// Descend down the node link: Use recursive traversal
-		DescendNodePtr(nodeAddr);
-	}
-
-	// render next viewport
-	if (vpnode[0x01] != 0x01000000) {
-		RenderViewport(vpnode[0x01]);
-	}
-}
-
-void CNew3D::CopyVertexData(const R3DPoly& r3dPoly, std::vector<Poly>& polyArray)
-{
-	//====================
-	Poly		p;
-	V3::Vec3	normal;
-	float		dotProd;
-	bool		clockWise;
-	//====================
-
-	V3::createNormal(r3dPoly.v[0].pos, r3dPoly.v[1].pos, r3dPoly.v[2].pos, normal);
-
-	dotProd		= V3::dotProduct(normal, r3dPoly.faceNormal);
-	clockWise	= dotProd >= 0.0;
-
-	if (clockWise) {
-		p.p1 = r3dPoly.v[0];
-		p.p2 = r3dPoly.v[1];
-		p.p3 = r3dPoly.v[2];
-	}
-	else {
-		p.p1 = r3dPoly.v[2];
-		p.p2 = r3dPoly.v[1];
-		p.p3 = r3dPoly.v[0];
-	}
-
-	//multiply face attributes with vertex attributes if required
-	for (int i = 0; i < 4; i++) {
-		p.p1.color[i] = p.p1.color[i] * r3dPoly.faceColour[i];
-		p.p2.color[i] = p.p2.color[i] * r3dPoly.faceColour[i];
-		p.p3.color[i] = p.p3.color[i] * r3dPoly.faceColour[i];
-	}
-	
-	polyArray.emplace_back(p);
-
-	if (r3dPoly.number == 4) {
-
-		if (clockWise) {
-			p.p1 = r3dPoly.v[0];
-			p.p2 = r3dPoly.v[2];
-			p.p3 = r3dPoly.v[3];
-		}
-		else {
-			p.p1 = r3dPoly.v[0];
-			p.p2 = r3dPoly.v[3];
-			p.p3 = r3dPoly.v[2];
-		}
-
-		//multiply face attributes with vertex attributes if required
-		for (int i = 0; i < 4; i++) {
-			p.p1.color[i] = p.p1.color[i] * r3dPoly.faceColour[i];
-			p.p2.color[i] = p.p2.color[i] * r3dPoly.faceColour[i];
-			p.p3.color[i] = p.p3.color[i] * r3dPoly.faceColour[i];
-		}
-
-		polyArray.emplace_back(p);
-	}
-}
-
-// non smooth texturing on the pro-1000 seems to sample like gl_nearest
-// ie not outside of the texture coordinates, but with bilinear filtering
-// this is about as close as we can emulate in hardware
-// if we don't do this with gl_repeat enabled, it will wrap around and sample the 
-// other side of the texture which produces ugly seems
-void CNew3D::OffsetTexCoords(R3DPoly& r3dPoly, float offset[2])
-{
-	for (int i = 0; i < 2; i++) {
-
-		float min =  std::numeric_limits<float>::max();
-		float max = -std::numeric_limits<float>::max();
-
-		if (!offset[i]) continue;
-
-		for (int j = 0; j < r3dPoly.number; j++) {
-			min = std::min(r3dPoly.v[j].texcoords[i], min);
-			max = std::max(r3dPoly.v[j].texcoords[i], max);
-		}
-
-		float fTemp;
-		float iTemp;
-		bool fractMin;
-		bool fractMax;
-		
-		fTemp		= std::modf(min, &iTemp);
-		fractMin	= fTemp > 0;
-
-		fTemp		= std::modf(max, &iTemp);
-		fractMax	= fTemp > 0;
-
-		for (int j = 0; j < r3dPoly.number && min != max; j++) {
-
-			if (!fractMin) {
-				if (r3dPoly.v[j].texcoords[i] == min) {
-					r3dPoly.v[j].texcoords[i] += offset[i];
-				}
-			}
-
-			if (!fractMax) {
-				if (r3dPoly.v[j].texcoords[i] == max) {
-					r3dPoly.v[j].texcoords[i] -= offset[i];
-				}
-			}
-		}
-	}
-}
-
-void CNew3D::CacheModel(Model *m, const UINT32 *data)
-{
-	Vertex			prev[4];
-	PolyHeader		ph;
-	int				numPolys	= 0;
-	UINT64			lastHash	= -1;
-	SortingMesh*	currentMesh = nullptr;
-	
-	std::map<UINT64, SortingMesh> sMap;
-
-	if (data == NULL)
-		return;
-
-	ph = data; 
-	int numTriangles = ph.NumTrianglesTotal();
-
-	// Cache all polygons
-	do {
-
-		R3DPoly		p;					// current polygon
-		GLfloat		uvScale;
-		int			i, j;
-
-		if (ph.header[6] == 0) {
-			break;
-		}
-
-		if (ph.Disabled() || !numPolys && (ph.NumSharedVerts() != 0)) {
-			continue;
-		}
-
-		// create a hash value based on poly attributes -todo add more attributes
-		auto hash = ph.Hash();
-
-		if (hash != lastHash) {
-
-			if (sMap.count(hash) == 0) {
-
-				sMap[hash] = SortingMesh();
-
-				currentMesh = &sMap[hash];
-
-				//make space for our vertices
-				currentMesh->polys.reserve(numTriangles);
-
-				//copy attributes
-				currentMesh->doubleSided	= false;			// we will double up polys
-				currentMesh->textured		= ph.TexEnabled();
-				currentMesh->alphaTest		= ph.AlphaTest();
-				currentMesh->textureAlpha	= ph.TextureAlpha();
-				currentMesh->polyAlpha		= ph.PolyAlpha();
-				currentMesh->lighting		= ph.LightEnabled() && !ph.FixedShading();
-
-				if (ph.Layered() || (!ph.TexEnabled() && ph.PolyAlpha())) {
-					currentMesh->layered = true;
-				}
-				
-				if (currentMesh->lighting) {
-					if (ph.SpecularEnabled()) {
-						currentMesh->specular = true;
-						currentMesh->shininess = 0;// ph.Shininess();
-						currentMesh->specularCoefficient = 0; // ph.SpecularValue();
-					}
-				}
-	
-				currentMesh->fogIntensity = ph.LightModifier();
-
-				if (ph.TexEnabled()) {
-					currentMesh->format			= m_texSheet.GetTexFormat(ph.TexFormat(), ph.AlphaTest());
-
-					if (currentMesh->format == 7) {
-						currentMesh-> alphaTest = false;	// alpha test is a 1 bit test, this format needs a lower threshold, since it has 16 levels of transparency
-					}
-
-					currentMesh->x				= ph.X();
-					currentMesh->y				= ph.Y();
-					currentMesh->width			= ph.TexWidth();
-					currentMesh->height			= ph.TexHeight();
-					currentMesh->mirrorU		= ph.TexUMirror();
-					currentMesh->mirrorV		= ph.TexVMirror();
-					currentMesh->microTexture	= ph.MicroTexture();
-					currentMesh->microTextureID = ph.MicroTextureID();
-				}
-			}
-
-			currentMesh = &sMap[hash];
-		}
-
-		lastHash = hash;		
-
-		// Obtain basic polygon parameters
-		p.number	= ph.NumVerts();
-		uvScale		= ph.UVScale();
-
-		ph.FaceNormal(p.faceNormal);
-
-		// Fetch reused vertices according to bitfield, then new verts
-		i = 0;
-		j = 0;
-		for (i = 0; i < 4; i++)		// up to 4 reused vertices
-		{
-			if (ph.SharedVertex(i))
-			{
-				p.v[j] = prev[i];
-				++j;
-			}
-		}
-
-		// copy face attributes
-
-		if ((ph.header[1] & 2) == 0) {
-			int colorIdx = ph.ColorIndex();
-			p.faceColour[2] = (m_polyRAM[m_colorTableAddr + colorIdx] & 0xFF) / 255.f;
-			p.faceColour[1] = ((m_polyRAM[m_colorTableAddr + colorIdx] >> 8) & 0xFF) / 255.f;
-			p.faceColour[0] = ((m_polyRAM[m_colorTableAddr + colorIdx] >> 16) & 0xFF) / 255.f;
-		}
-		else {
-			if (ph.ColorDisabled()) {		// no colours were set
-				p.faceColour[0] = 1.0f;
-				p.faceColour[1] = 1.0f;
-				p.faceColour[2] = 1.0f;
-			}
-			else {
-				p.faceColour[0] = ((ph.header[4] >> 24)) / 255.f;
-				p.faceColour[1] = ((ph.header[4] >> 16) & 0xFF) / 255.f;
-				p.faceColour[2] = ((ph.header[4] >> 8) & 0xFF) / 255.f;
-			}
-		}
-
-		p.faceColour[3] = ph.Transparency() / 255.f;
-				
-		// if we have flat shading, we can't re-use normals from shared vertices
-		for (i = 0; i < p.number && !ph.SmoothShading(); i++) {
-			p.v[i].normal[0] = p.faceNormal[0];
-			p.v[i].normal[1] = p.faceNormal[1];
-			p.v[i].normal[2] = p.faceNormal[2];
-		}
-
-		UINT32* vData = ph.StartOfData();	// vertex data starts here
-
-		// remaining vertices are new and defined here
-		for (; j < p.number; j++)	
-		{
-			// Fetch vertices
-			UINT32 ix = vData[0];
-			UINT32 iy = vData[1];
-			UINT32 iz = vData[2];
-			UINT32 it = vData[3];
-
-			// Decode vertices
-			p.v[j].pos[0] = (GLfloat)(((INT32)ix) >> 8) * m_vertexFactor;
-			p.v[j].pos[1] = (GLfloat)(((INT32)iy) >> 8) * m_vertexFactor;
-			p.v[j].pos[2] = (GLfloat)(((INT32)iz) >> 8) * m_vertexFactor;
-
-			// Per vertex normals
-			if (ph.SmoothShading()) {
-				p.v[j].normal[0] = (INT8)(ix & 0xFF) / 128.f;
-				p.v[j].normal[1] = (INT8)(iy & 0xFF) / 128.f;
-				p.v[j].normal[2] = (INT8)(iz & 0xFF) / 128.f;
-			}
-
-			if (ph.FixedShading() && ph.TexEnabled() && !ph.SmoothShading()) {		// fixed shading seems to be disabled if actual normals are set
-				float offset = !ph.LightEnabled() ? 1.f : 0.f;						// if lighting is disabled colour seems to be an offset 
-				float shade = (((ix + 128) & 0xFF) / 255.f) + offset;
-				p.v[j].color[0] = shade;											// hardware doesn't really have per vertex colours, only per poly
-				p.v[j].color[1] = shade;
-				p.v[j].color[2] = shade;
-				p.v[j].color[3] = 1;
-			}
-			else {
-				p.v[j].color[0] = 1;
-				p.v[j].color[1] = 1;
-				p.v[j].color[2] = 1;
-				p.v[j].color[3] = 1;
-			}
-
-			float texU, texV = 0;
-
-			// tex coords
-			if (currentMesh->textured) {
-				Texture::GetCoordinates(currentMesh->width, currentMesh->height, (UINT16)(it >> 16), (UINT16)(it & 0xFFFF), uvScale, texU, texV);
-			}
-
-			p.v[j].texcoords[0] = texU;
-			p.v[j].texcoords[1] = texV;
-
-			vData += 4;
-		}
-
-		// check if we need to modify the texture coordinates
-		{
-			float offset[2] = { 0 };
-
-			if (ph.TexEnabled()) {
-
-				if (!ph.TexSmoothU() && !ph.TexUMirror()) {
-					offset[0] = 0.5f / ph.TexWidth();	// half texel
-				}
-
-				if (!ph.TexSmoothV() && !ph.TexVMirror()) {
-					offset[1] = 0.5f / ph.TexHeight();	// half texel
-				}
-
-				OffsetTexCoords(p, offset);
-			}
-		}
-
-		// check if we need double up vertices for two sided lighting
-		if (ph.DoubleSided()) {
-
-			R3DPoly tempP = p;
-
-			// flip normals
-			V3::inverse(tempP.faceNormal);
-
-			for (int i = 0; i < tempP.number; i++) {
-				V3::inverse(tempP.v[i].normal);
-			}
-
-			CopyVertexData(tempP, currentMesh->polys);
-		}
-
-		// Copy this polygon into the model buffer
-		CopyVertexData(p, currentMesh->polys);
-		numPolys++;
-		
-		// Copy current vertices into previous vertex array
-		for (i = 0; i < 4; i++) {
-			prev[i] = p.v[i];
-		}
-
-	} while (ph.NextPoly());
-
-	//sorted the data, now copy to main data structures
-
-	// we know how many meshes we have so reserve appropriate space
-	m->meshes->reserve(sMap.size());
-
-	for (auto& it : sMap) {
-
-		if (m->dynamic) {
-
-			// calculate VBO values for current mesh
-			it.second.vboOffset		= m_polyBufferRam.size() + MAX_ROM_POLYS;
-			it.second.triangleCount = it.second.polys.size();
-
-			// copy poly data to main buffer
-			m_polyBufferRam.insert(m_polyBufferRam.end(), it.second.polys.begin(), it.second.polys.end());
-		}
-		else {
-			// calculate VBO values for current mesh
-			it.second.vboOffset		= m_polyBufferRom.size();
-			it.second.triangleCount = it.second.polys.size();
-
-			// copy poly data to main buffer
-			m_polyBufferRom.insert(m_polyBufferRom.end(), it.second.polys.begin(), it.second.polys.end());
-		}
-
-		//copy the temp mesh into the model structure
-		//this will lose the associated vertex data, which is now copied to the main buffer anyway
-		m->meshes->push_back(it.second);
-	}
-}
-
-float CNew3D::Determinant3x3(const float m[16]) {
-
-	/*
-		| A B C |
-	M = | D E F |
-		| G H I |
-
-	then the determinant is calculated as follows:
-
-	det M = A * (EI - HF) - B * (DI - GF) + C * (DH - GE)
-	*/
-
-	return m[0] * ((m[5] * m[10]) - (m[6] * m[9])) - m[4] * ((m[1] * m[10]) - (m[2] * m[9])) + m[8] * ((m[1] * m[6]) - (m[2] * m[5]));
-}
-
-bool CNew3D::IsDynamicModel(UINT32 *data)
-{
-	if (data == NULL) {
-		return false;
-	}
-
-	PolyHeader p(data);
-
-	do {
-
-		if ((p.header[1] & 2) == 0) {		// model has rgb colour palette 
-			return true;
-		}
-
-		if (p.header[6] == 0) {
-			break;
-		}
-
-	} while (p.NextPoly());
-
-	return false;
-}
-
-bool CNew3D::IsVROMModel(UINT32 modelAddr)
-{
-	return modelAddr >= 0x100000;
-}
-
-void CNew3D::CalcTexOffset(int offX, int offY, int page, int x, int y, int& newX, int& newY)
-{
-	newX = (x + offX) & 2047;	// wrap around 2048, shouldn't be required
-
-	int oldPage = y / 1024;
-
-	y -= (oldPage * 1024);	// remove page from tex y
-
-	// calc newY with wrap around, wraps around in the same sheet, not into another memory sheet
-
-	newY = (y + offY) & 1023;
-
-	// add page to Y
-
-	newY += ((oldPage + page) & 1) * 1024;		// max page 0-1
-}
-
-void CNew3D::CalcFrustumPlanes(Plane p[5], const float *vpNodeData)
-{
-	// Left Plane
-	p[0].a = vpNodeData[1];
-	p[0].b = 0;
-	p[0].c = -vpNodeData[0];
-	p[0].d = 0;
-
-	// Top Plane
-	p[1].a = 0;
-	p[1].b = vpNodeData[3];
-	p[1].c = -vpNodeData[2];
-	p[1].d = 0;
-
-	// Right Plane
-	p[2].a = vpNodeData[5];
-	p[2].b = 0;
-	p[2].c = -vpNodeData[4];
-	p[2].d = 0;
-
-	// Bottom Plane
-	p[3].a = 0;
-	p[3].b = vpNodeData[7];
-	p[3].c = -vpNodeData[6];
-	p[3].d = 0;
-
-	// Near Plane
-	p[4].a = 0;
-	p[4].b = 0;
-	p[4].c = -1;
-	p[4].d = 0;
-}
-
-void CNew3D::CalcBox(float distance, BBox& box)
-{
-	//bottom left front
-	box.points[0][0] = -distance;
-	box.points[0][1] = -distance;
-	box.points[0][2] = distance;
-	box.points[0][3] = 1;
-
-	//bottom left back
-	box.points[1][0] = -distance;
-	box.points[1][1] = -distance;
-	box.points[1][2] = -distance;
-	box.points[1][3] = 1;
-
-	//bottom right back
-	box.points[2][0] = distance;
-	box.points[2][1] = -distance;
-	box.points[2][2] = -distance;
-	box.points[2][3] = 1;
-
-	//bottom right front
-	box.points[3][0] = distance;
-	box.points[3][1] = -distance;
-	box.points[3][2] = distance;
-	box.points[3][3] = 1;
-
-	//top left front
-	box.points[4][0] = -distance;
-	box.points[4][1] = distance;
-	box.points[4][2] = distance;
-	box.points[4][3] = 1;
-
-	//top left back
-	box.points[5][0] = -distance;
-	box.points[5][1] = distance;
-	box.points[5][2] = -distance;
-	box.points[5][3] = 1;
-
-	//top right back
-	box.points[6][0] = distance;
-	box.points[6][1] = distance;
-	box.points[6][2] = -distance;
-	box.points[6][3] = 1;
-
-	//top right front
-	box.points[7][0] = distance;
-	box.points[7][1] = distance;
-	box.points[7][2] = distance;
-	box.points[7][3] = 1;
-}
-
-void CNew3D::MultVec(const float matrix[16], const float in[4], float out[4]) 
-{
-	for (int i = 0; i < 4; i++) {
-		out[i] =
-			in[0] * matrix[0 * 4 + i] +
-			in[1] * matrix[1 * 4 + i] +
-			in[2] * matrix[2 * 4 + i] +
-			in[3] * matrix[3 * 4 + i];
-	}
-}
-
-void CNew3D::TransformBox(const float *m, BBox& box)
-{
-	for (int i = 0; i < 8; i++) {
-		float v[4];
-		MultVec(m, box.points[i], v);
-		box.points[i][0] = v[0];
-		box.points[i][1] = v[1];
-		box.points[i][2] = v[2];
-	}
-}
-
-Clip CNew3D::ClipBox(BBox& box, Plane planes[6])
-{
-	int count = 0;
-
-	for (int i = 0; i < 8; i++) {
-
-		int temp = 0;
-
-		for (int j = 0; j < 5; j++) {
-			if (planes[j].DistanceToPoint(box.points[i]) >= 0) {
-				temp++;
-			}
-		}
-
-		if (temp == 5) count++;		// point is inside all 6 frustum planes
-	}
-
-	if (count == 8)	return Clip::INSIDE;
-	if (count > 0)	return Clip::INTERCEPT;
-	
-	//if we got here all points are outside of the view frustum
-	//check for all points being side same of any plane, means box outside of view
-
-	for (int i = 0; i < 5; i++) {
-
-		int temp = 0;
-
-		for (int j = 0; j < 8; j++) {
-			if (planes[i].DistanceToPoint(box.points[j]) >= 0) {
-				float distance = planes[i].DistanceToPoint(box.points[j]);
-				temp++;
-			}
-		}
-
-		if (temp == 0) return Clip::OUTSIDE;
-	}
-
-	//if we got here, box is traversing view frustum
-
-	return Clip::INTERCEPT;
-}
-
-void CNew3D::GetBBMaxZ(float &compare, BBox &box)
-{
-	for (int i = 0; i < 8; i++) {
-		compare = std::max(compare, std::abs(box.points[i][2]));
-	}
-}
-
-void CNew3D::CalcViewports()
-{
-	for (auto &n : m_nodes) {
-
-		auto *vp = &n.viewport;
-
-		float near	= m_nfPair[vp->priority].nearVal * 0.5f;
-		float far	= m_nfPair[vp->priority].farVal;
-		
-		float l = near * tanf(vp->left);
-		float r = near * tanf(vp->right);
-		float t = near * tanf(vp->top);
-		float b = near * tanf(vp->bottom);
-
-		if ((vp->vpX == 0) && (vp->vpWidth >= 495) && (vp->vpY == 0) && (vp->vpHeight >= 383))
-		{
-			float windowAR = (float)m_totalXRes / (float)m_totalYRes;
-			float originalAR = 496 / 384.f;
-			float correction = windowAR / originalAR;	// expand horizontal frustum planes
-
-			vp->x = 0;
-			vp->y = m_yOffs + (GLint)((float)(384 - (vp->vpY + vp->vpHeight))*m_yRatio);
-			vp->width = m_totalXRes;
-			vp->height = (GLint)((float)vp->vpHeight*m_yRatio);
-
-			vp->projectionMatrix.Frustum(l*correction, r*correction, b, t, near, far);
-		}
-		else
-		{
-			vp->x = m_xOffs + (GLint)((float)vp->vpX*m_xRatio);
-			vp->y = m_yOffs + (GLint)((float)(384 - (vp->vpY + vp->vpHeight))*m_yRatio);
-			vp->width = (GLint)((float)vp->vpWidth*m_xRatio);
-			vp->height = (GLint)((float)vp->vpHeight*m_yRatio);
-
-			vp->projectionMatrix.Frustum(l, r, b, t, near, far);
-		}
-
-	}
-}
-
-} // New3D
-
diff --git a/Src/Graphics/New3D/backup/clipping plane attempt/New3D.h b/Src/Graphics/New3D/backup/clipping plane attempt/New3D.h
deleted file mode 100644
index f5a5aa3..0000000
--- a/Src/Graphics/New3D/backup/clipping plane attempt/New3D.h	
+++ /dev/null
@@ -1,252 +0,0 @@
-/**
-** Supermodel
-** A Sega Model 3 Arcade Emulator.
-** Copyright 2011 Bart Trzynadlowski, Nik Henson
-**
-** This file is part of Supermodel.
-**
-** Supermodel is free software: you can redistribute it and/or modify it under
-** the terms of the GNU General Public License as published by the Free
-** Software Foundation, either version 3 of the License, or (at your option)
-** any later version.
-**
-** Supermodel is distributed in the hope that it will be useful, but WITHOUT
-** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-** FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-** more details.
-**
-** You should have received a copy of the GNU General Public License along
-** with Supermodel.  If not, see <http://www.gnu.org/licenses/>.
-**/
-
-/*
-* New3D.h
-*
-* Header file defining the CNew3D class: OpenGL Real3D graphics engine.
-*/
-
-#ifndef INCLUDED_NEW3D_H
-#define INCLUDED_NEW3D_H
-
-#include "Pkgs/glew.h"
-#include "Types.h"
-#include "TextureSheet.h"
-#include "Graphics/IRender3D.h"
-#include "Model.h"
-#include "Mat4.h"
-#include "R3DShader.h"
-#include "VBO.h"
-#include "R3DData.h"
-#include "Plane.h"
-#include "Vec.h"
-#include "R3DScrollFog.h"
-
-namespace New3D {
-
-class CNew3D : public IRender3D
-{
-public:
-	/*
-	* RenderFrame(void):
-	*
-	* Renders the complete scene database. Must be called between BeginFrame() and
-	* EndFrame(). This function traverses the scene database and builds up display
-	* lists.
-	*/
-	void RenderFrame(void);
-
-	/*
-	* BeginFrame(void):
-	*
-	* Prepare to render a new frame. Must be called once per frame prior to
-	* drawing anything.
-	*/
-	void BeginFrame(void);
-
-	/*
-	* EndFrame(void):
-	*
-	* Signals the end of rendering for this frame. Must be called last during
-	* the frame.
-	*/
-	void EndFrame(void);
-
-	/*
-	* UploadTextures(x, y, width, height):
-	*
-	* Signals that a portion of texture RAM has been updated.
-	*
-	* Parameters:
-	*		x		X position within texture RAM.
-	*		y		Y position within texture RAM.
-	*		width	Width of texture data in texels.
-	*		height	Height.
-	*/
-	void UploadTextures(unsigned x, unsigned y, unsigned width, unsigned height);
-
-	/*
-	* AttachMemory(cullingRAMLoPtr, cullingRAMHiPtr, polyRAMPtr, vromPtr,
-	* 				textureRAMPtr):
-	*
-	* Attaches RAM and ROM areas. This must be done prior to any rendering
-	* otherwise the program may crash with an access violation.
-	*
-	* Parameters:
-	*		cullingRAMLoPtr		Pointer to low culling RAM (4 MB).
-	*		cullingRAMHiPtr		Pointer to high culling RAM (1 MB).
-	*		polyRAMPtr			Pointer to polygon RAM (4 MB).
-	*		vromPtr				Pointer to video ROM (64 MB).
-	*		textureRAMPtr		Pointer to texture RAM (8 MB).
-	*/
-	void AttachMemory(const UINT32 *cullingRAMLoPtr,
-		const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr,
-		const UINT32 *vromPtr, const UINT16 *textureRAMPtr);
-
-	/*
-	* SetStep(stepID):
-	*
-	* Sets the Model 3 hardware stepping, which also determines the Real3D
-	* functionality. The default is Step 1.0. This should be called prior to
-	* any other emulation functions and after Init().
-	*
-	* Parameters:
-	*		stepID	0x10 for Step 1.0, 0x15 for Step 1.5, 0x20 for Step 2.0,
-	*				or 0x21 for Step 2.1. Anything else defaults to 1.0.
-	*/
-	void SetStep(int stepID);
-
-	/*
-	* Init(xOffset, yOffset, xRes, yRes, totalXRes, totalYRes):
-	*
-	* One-time initialization of the context. Must be called before any other
-	* members (meaning it should be called even before being attached to any
-	* other objects that want to use it).
-	*
-	* External shader files are loaded according to configuration settings.
-	*
-	* Parameters:
-	*		xOffset		X offset of the viewable area within OpenGL display
-	*                  surface, in pixels.
-	*		yOffset		Y offset.
-	*		xRes		Horizontal resolution of the viewable area.
-	*		yRes		Vertical resolution.
-	*		totalXRes	Horizontal resolution of the complete display area.
-	*		totalYRes	Vertical resolution.
-	*
-	* Returns:
-	*		OKAY is successful, otherwise FAILED if a non-recoverable error
-	*		occurred. Any allocated memory will not be freed until the
-	*		destructor is called. Prints own error messages.
-	*/
-	bool Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXRes, unsigned totalYRes);
-
-	/*
-	* CRender3D(void):
-	* ~CRender3D(void):
-	*
-	* Constructor and destructor.
-	*/
-	CNew3D(void);
-	~CNew3D(void);
-
-private:
-	/*
-	* Private Members
-	*/
-
-	// Real3D address translation
-	const UINT32 *TranslateCullingAddress(UINT32 addr);
-	const UINT32 *TranslateModelAddress(UINT32 addr);
-
-	// Matrix stack
-	void MultMatrix(UINT32 matrixOffset, Mat4& mat);
-	void InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat);
-
-	// Scene database traversal
-	bool DrawModel(UINT32 modelAddr);
-	void DescendCullingNode(UINT32 addr);
-	void DescendPointerList(UINT32 addr);
-	void DescendNodePtr(UINT32 nodeAddr);
-	void RenderViewport(UINT32 addr);
-	void CalcViewports();
-
-	// building the scene
-	void CacheModel(Model *m, const UINT32 *data);
-	void CopyVertexData(const R3DPoly& r3dPoly, std::vector<Poly>& polyArray);
-	void OffsetTexCoords(R3DPoly& r3dPoly, float offset[2]);
-
-	void RenderScene(int priority, bool alpha);
-	float Determinant3x3(const float m[16]);
-	bool IsDynamicModel(UINT32 *data);		// check if the model has a colour palette
-	bool IsVROMModel(UINT32 modelAddr);
-	void DrawScrollFog();
-
-	void CalcTexOffset(int offX, int offY, int page, int x, int y, int& newX, int& newY);	
-
-	/*
-	* Data
-	*/
-
-	// Stepping
-	int		m_step;
-	int		m_offset;			// offset to subtract for words 3 and higher of culling nodes
-	float	m_vertexFactor;		// fixed-point conversion factor for vertices
-
-	// Memory (passed from outside)
-	const UINT32	*m_cullingRAMLo;	// 4 MB
-	const UINT32	*m_cullingRAMHi;	// 1 MB
-	const UINT32	*m_polyRAM;			// 4 MB
-	const UINT32	*m_vrom;			// 64 MB
-	const UINT16	*m_textureRAM;		// 8 MB
-
-	// Resolution and scaling factors (to support resolutions higher than 496x384) and offsets
-	float		m_xRatio, m_yRatio;
-	unsigned	m_xOffs, m_yOffs;
-	unsigned 	m_totalXRes, m_totalYRes;
-
-	// Real3D Base Matrix Pointer
-	const float	*m_matrixBasePtr;
-	UINT32 m_colorTableAddr = 0x400;		// address of color table in polygon RAM
-
-	TextureSheet	m_texSheet;
-	NodeAttributes	m_nodeAttribs;
-	Mat4			m_modelMat;				// current modelview matrix
-
-	std::vector<Node> m_nodes;				// this represents the entire render frame
-	std::vector<Poly> m_polyBufferRam;		// dynamic polys
-	std::vector<Poly> m_polyBufferRom;		// rom polys
-	std::unordered_map<UINT32, std::shared_ptr<std::vector<Mesh>>> m_romMap;	// a hash table for all the ROM models. The meshes don't have model matrices or tex offsets yet
-
-	VBO m_vbo;								// large VBO to hold our poly data, start of VBO is ROM data, ram polys follow
-	R3DShader m_r3dShader;
-	R3DScrollFog m_r3dScrollFog;
-
-	Plane m_planes[5];
-
-	struct NFPair
-	{
-		float nearVal;
-		float farVal;
-	};
-
-	NFPair m_nfPair[4];		// near/far value for each priority layer
-	int m_currentPriority;
-
-	struct BBox
-	{
-		V4::Vec4 points[8];
-	};
-
-	void CalcFrustumPlanes	(Plane p[6], const float *vpNodeData);
-	void CalcBox			(float distance, BBox& box);
-	void TransformBox		(const float *m, BBox& box);
-	void MultVec			(const float matrix[16], const float in[4], float out[4]);
-	Clip ClipBox			(BBox& box, Plane planes[6]);
-	void GetBBMaxZ			(float &compare, BBox &box);
-
-	float m_minTest;
-};
-
-} // New3D
-
-#endif  // INCLUDED_NEW3D_H
diff --git a/Src/Graphics/New3D/backup/lost world debug/New3D.cpp b/Src/Graphics/New3D/backup/lost world debug/New3D.cpp
deleted file mode 100644
index 7d94e18..0000000
--- a/Src/Graphics/New3D/backup/lost world debug/New3D.cpp	
+++ /dev/null
@@ -1,1516 +0,0 @@
-#include "New3D.h"
-#include "PolyHeader.h"
-#include "Texture.h"
-#include "Vec.h"
-#include <cmath>
-#include <algorithm>
-#include <limits>
-#include "R3DFloat.h"
-
-#define MAX_RAM_POLYS 100000	
-#define MAX_ROM_POLYS 500000
-
-#ifndef M_PI
-#define M_PI 3.14159265359
-#endif
-
-namespace New3D {
-
-CNew3D::CNew3D()
-{
-	m_cullingRAMLo	= nullptr;
-	m_cullingRAMHi	= nullptr;
-	m_polyRAM		= nullptr;
-	m_vrom			= nullptr;
-	m_textureRAM	= nullptr;
-}
-
-CNew3D::~CNew3D()
-{
-	m_vbo.Destroy();
-}
-
-void CNew3D::AttachMemory(const UINT32 *cullingRAMLoPtr, const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr, const UINT32 *vromPtr, const UINT16 *textureRAMPtr)
-{
-	m_cullingRAMLo	= cullingRAMLoPtr;
-	m_cullingRAMHi	= cullingRAMHiPtr;
-	m_polyRAM		= polyRAMPtr;
-	m_vrom			= vromPtr;
-	m_textureRAM	= textureRAMPtr;
-}
-
-void CNew3D::SetStep(int stepID)
-{
-	m_step = stepID;
-
-	if ((m_step != 0x10) && (m_step != 0x15) && (m_step != 0x20) && (m_step != 0x21)) {
-		m_step = 0x10;
-	}
-
-	if (m_step > 0x10) {
-		m_offset = 0;							// culling nodes are 10 words
-		m_vertexFactor = (1.0f / 2048.0f);		// vertices are in 13.11 format
-	}
-	else {
-		m_offset = 2;							// 8 words
-		m_vertexFactor = (1.0f / 128.0f);		// 17.7
-	}
-
-	m_vbo.Create(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(Poly) * (MAX_RAM_POLYS + MAX_ROM_POLYS));
-}
-
-bool CNew3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXResParam, unsigned totalYResParam)
-{
-	// Resolution and offset within physical display area
-	m_xRatio	= xRes / 496.0f;
-	m_yRatio	= yRes / 384.0f;
-	m_xOffs		= xOffset;
-	m_yOffs		= yOffset;
-	m_totalXRes	= totalXResParam;
-	m_totalYRes = totalYResParam;
-
-	m_r3dShader.LoadShader();
-
-	glUseProgram(0);
-
-	return OKAY;	// OKAY ? wtf ..
-}
-
-void CNew3D::UploadTextures(unsigned x, unsigned y, unsigned width, unsigned height)
-{
-	m_texSheet.Invalidate(x, y, width, height);
-}
-
-void CNew3D::DrawScrollFog()
-{
-	for (int i = 0; i < 4; i++) {
-
-		for (auto &n : m_nodes) {
-
-			if (n.viewport.scrollFog > 0 && n.viewport.priority==i) {
-
-				float *rgb = n.viewport.fogParams;
-				m_r3dScrollFog.DrawScrollFog(rgb[0], rgb[1], rgb[2], n.viewport.scrollFog);
-
-				return;	// only allowed once per frame?
-			}
-		}
-	}
-}
-
-void CNew3D::RenderScene(int priority, bool alpha)
-{
-	if (alpha) {
-		glEnable(GL_BLEND);
-	}
-
-	for (auto &n : m_nodes) {
-
-		if (n.viewport.priority != priority || n.models.empty()) {
-			continue;
-		}
-
-		if (n.viewport.priority == 3) {
-			//return;
-		}
-
-		std::shared_ptr<Texture> tex1;
-
-		glViewport		(n.viewport.x, n.viewport.y, n.viewport.width, n.viewport.height);
-		glMatrixMode	(GL_PROJECTION);
-		glLoadMatrixf	(n.viewport.projectionMatrix);
-		glMatrixMode	(GL_MODELVIEW);
-
-		m_r3dShader.SetViewportUniforms(&n.viewport);
-
-		int modelIndex = 0;
-
-		for (auto &m : n.models) {
-
-			bool matrixLoaded = false;
-
-			if (m.meshes->empty()) {
-				continue;
-			}
-
-
-			m_r3dShader.SetModelStates(&m);
-
-			for (auto &mesh : *m.meshes) {
-
-				if (alpha) {
-					if (!mesh.textureAlpha && !mesh.polyAlpha) {
-						continue;
-					}
-				}
-				else {
-					if (mesh.textureAlpha || mesh.polyAlpha) {
-						continue;
-					}
-				}
-
-				if (!matrixLoaded) {
-					glLoadMatrixf(m.modelMat);
-					matrixLoaded = true;		// do this here to stop loading matrices we don't need. Ie when rendering non transparent etc
-				}
-
-				if (mesh.textured) {
-
-					int x, y;
-					CalcTexOffset(m.textureOffsetX, m.textureOffsetY, m.page, mesh.x, mesh.y, x, y);
-
-					if (tex1 && tex1->Compare(x, y, mesh.width, mesh.height, mesh.format)) {
-						tex1->SetWrapMode(mesh.mirrorU, mesh.mirrorV);
-					}
-					else {
-						tex1 = m_texSheet.BindTexture(m_textureRAM, mesh.format, mesh.mirrorU, mesh.mirrorV, x, y, mesh.width, mesh.height);
-						if (tex1) {
-							tex1->BindTexture();
-							tex1->SetWrapMode(mesh.mirrorU, mesh.mirrorV);
-						}
-					}
-
-					if (mesh.microTexture) {
-
-						int mX, mY;
-						glActiveTexture(GL_TEXTURE1);
-						m_texSheet.GetMicrotexPos(y / 1024, mesh.microTextureID, mX, mY);
-						auto tex2 = m_texSheet.BindTexture(m_textureRAM, 0, false, false, mX, mY, 128, 128);
-						if (tex2) {
-							tex2->BindTexture();
-						}
-						glActiveTexture(GL_TEXTURE0);
-					}
-				}
-
-				m_r3dShader.SetMeshUniforms(&mesh);
-				glDrawArrays(GL_TRIANGLES, mesh.vboOffset * 3, mesh.triangleCount * 3);			// times 3 to convert triangles to vertices
-			}
-		}
-	}
-
-	glDisable(GL_BLEND);
-	glDepthMask(GL_TRUE);
-	glDisable(GL_STENCIL_TEST);
-}
-
-void CNew3D::TestDraw()
-{
-	for (auto &n : m_nodes) {
-
-		glViewport(n.viewport.x, n.viewport.y, n.viewport.width, n.viewport.height);
-		glMatrixMode(GL_PROJECTION);
-		glLoadMatrixf(n.viewport.projectionMatrix);
-		glMatrixMode(GL_MODELVIEW);
-
-		int modelIndex = 0;
-
-		for (auto &m : n.models) {
-
-			bool matrixLoaded = false;
-
-			if (m.meshes->empty()) {
-				continue;
-			}
-
-
-			for (auto &mesh : *m.meshes) {
-
-				if (!matrixLoaded) {
-					glLoadMatrixf(m.modelMat);
-					matrixLoaded = true;		// do this here to stop loading matrices we don't need. Ie when rendering non transparent etc
-
-					printf("%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f \n\n", 
-						m.modelMat[0], m.modelMat[1], m.modelMat[2], m.modelMat[3], 
-						m.modelMat[4], m.modelMat[5], m.modelMat[6], m.modelMat[7],
-						m.modelMat[8], m.modelMat[8], m.modelMat[10], m.modelMat[11], 
-						m.modelMat[12], m.modelMat[13], m.modelMat[14], m.modelMat[15]);
-				}
-
-
-
-				m_r3dShader.SetMeshUniforms(&mesh);
-				glDrawArrays(GL_TRIANGLES, mesh.vboOffset * 3, mesh.triangleCount * 3);			// times 3 to convert triangles to vertices
-			}
-		}
-	}
-
-	glDisable(GL_BLEND);
-	glDepthMask(GL_TRUE);
-	glDisable(GL_STENCIL_TEST);
-
-}
-
-void CNew3D::RenderFrame(void)
-{
-	//glClear(GL_COLOR_BUFFER_BIT);
-	// release any resources from last frame
-	m_polyBufferRam.clear();	// clear dyanmic model memory buffer
-	m_nodes.clear();		// memory will grow during the object life time, that's fine, no need to shrink to fit
-	m_modelMat.Release();	// would hope we wouldn't need this but no harm in checking
-	m_nodeAttribs.Reset();
-
-	RenderViewport(0x800000);					// build model structure
-
-	DrawScrollFog();							// fog layer if applicable must be drawn here
-
-	glDepthFunc		(GL_LEQUAL);
-	//glEnable		(GL_DEPTH_TEST);
-	glActiveTexture	(GL_TEXTURE0);
-	//glEnable		(GL_CULL_FACE);
-	glFrontFace		(GL_CW);
-
-	glStencilFunc	(GL_EQUAL, 0, 0xFF);			// basically stencil test passes if the value is zero
-	glStencilOp		(GL_KEEP, GL_INCR, GL_INCR);		// if the stencil test passes, we incriment the value
-	glStencilMask	(0xFF);
-
-	glUseProgram(0);
-	glMatrixMode(GL_PROJECTION);
-	glLoadIdentity();
-	glOrtho(-10, 10, -10, 10, -10, 10);
-	glMatrixMode(GL_MODELVIEW);
-	glLoadIdentity();
-
-	glPointSize(10);
-	glDisable(GL_TEXTURE_2D);
-	glColor3f(1, 0, 0);
-
-
-	m_vbo.Bind(true);
-	m_vbo.BufferSubData(MAX_ROM_POLYS*sizeof(Poly), m_polyBufferRam.size()*sizeof(Poly), m_polyBufferRam.data());	// upload all the dynamic data to GPU in one go
-
-	if (m_polyBufferRom.size()) {
-
-		// sync rom memory with vbo
-		int romBytes = (int)m_polyBufferRom.size() * sizeof(Poly);
-		int vboBytes = m_vbo.GetSize();
-		int size = romBytes - vboBytes;
-
-		if (size) {
-			//check we haven't blown up the memory buffers
-			//we will lose rom models for 1 frame is this happens, not the end of the world, as probably won't ever happen anyway
-			if (m_polyBufferRom.size() >= MAX_ROM_POLYS) {
-				m_polyBufferRom.clear();
-				m_romMap.clear();
-				m_vbo.Reset();
-			}
-			else {
-				m_vbo.AppendData(size, &m_polyBufferRom[vboBytes / sizeof(Poly)]);
-			}
-		}
-	}
-
-	glEnableClientState(GL_VERTEX_ARRAY);
-	glEnableClientState(GL_NORMAL_ARRAY);
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-	glEnableClientState(GL_COLOR_ARRAY);
-
-	glVertexPointer(3, GL_FLOAT, sizeof(Vertex), 0);
-	glNormalPointer(GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, normal));
-	glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, texcoords));
-	glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), (void*)offsetof(Vertex, color));
-
-	for (auto &n : m_nodes) {
-
-		//glViewport(n.viewport.x, n.viewport.y, n.viewport.width, n.viewport.height);
-		glMatrixMode(GL_PROJECTION);
-		//glLoadMatrixf(n.viewport.projectionMatrix);
-		glOrtho(-10, 10, -10, 10, -100, 100);
-		glMatrixMode(GL_MODELVIEW);
-
-		for (auto &m : n.models) {
-
-			glLoadMatrixf(m.modelMat);
-
-			printf("%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f \n\n",
-				m.modelMat[0], m.modelMat[1], m.modelMat[2], m.modelMat[3],
-				m.modelMat[4], m.modelMat[5], m.modelMat[6], m.modelMat[7],
-				m.modelMat[8], m.modelMat[8], m.modelMat[10], m.modelMat[11],
-				m.modelMat[12], m.modelMat[13], m.modelMat[14], m.modelMat[15]);
-
-			for (auto &mesh : *m.meshes) {
-				glDrawArrays(GL_POINTS, mesh.vboOffset * 3, mesh.triangleCount * 3);			// times 3 to convert triangles to vertices
-			}
-		}
-
-	}
-
-	m_vbo.Bind(false);
-
-	return;
-
-
-	glEnableClientState(GL_VERTEX_ARRAY);
-	glEnableClientState(GL_NORMAL_ARRAY);
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-	glEnableClientState(GL_COLOR_ARRAY);
-
-	// before draw, specify vertex and index arrays with their offsets, offsetof is maybe evil ..
-	glVertexPointer		(3, GL_FLOAT, sizeof(Vertex), 0);
-	glNormalPointer		(GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, normal));
-	glTexCoordPointer	(2, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, texcoords));
-	glColorPointer		(4, GL_UNSIGNED_BYTE, sizeof(Vertex), (void*)offsetof(Vertex, color));
-
-	m_r3dShader.SetShader(true);
-
-	for (int pri = 0; pri <= 3; pri++) {
-		glClear		(GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
-		RenderScene	(pri, false);
-		RenderScene	(pri, true);
-	}
-
-	m_r3dShader.SetShader(false);		// unbind shader
-	m_vbo.Bind(false);
-
-	glDisable(GL_CULL_FACE);
-	glDisableClientState(GL_VERTEX_ARRAY);
-	glDisableClientState(GL_NORMAL_ARRAY);
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-	glDisableClientState(GL_COLOR_ARRAY);
-}
-
-void CNew3D::BeginFrame(void)
-{
-}
-
-void CNew3D::EndFrame(void)
-{
-}
-
-/******************************************************************************
-Real3D Address Translation
-
-Functions that interpret word-granular Real3D addresses and return pointers.
-******************************************************************************/
-
-// Translates 24-bit culling RAM addresses
-const UINT32* CNew3D::TranslateCullingAddress(UINT32 addr)
-{
-	addr &= 0x00FFFFFF;	// caller should have done this already
-
-	if ((addr >= 0x800000) && (addr < 0x840000)) {
-		return &m_cullingRAMHi[addr & 0x3FFFF];
-	}
-	else if (addr < 0x100000) {
-		return &m_cullingRAMLo[addr];
-	}
-
-	return NULL;
-}
-
-// Translates model references
-const UINT32* CNew3D::TranslateModelAddress(UINT32 modelAddr)
-{
-	modelAddr &= 0x00FFFFFF;	// caller should have done this already
-
-	if (modelAddr < 0x100000) {
-		return &m_polyRAM[modelAddr];
-	}
-	else {
-		return &m_vrom[modelAddr];
-	}
-}
-
-bool CNew3D::DrawModel(UINT32 modelAddr)
-{
-	const UINT32*	modelAddress;
-	bool			cached = false;
-	Model*			m;
-
-	modelAddress = TranslateModelAddress(modelAddr);
-
-	// create a new model to push onto the vector
-	m_nodes.back().models.emplace_back(Model());
-
-	// get the last model in the array
-	m = &m_nodes.back().models.back();
-
-	if (IsVROMModel(modelAddr) && !IsDynamicModel((UINT32*)modelAddress)) {
-
-		// try to find meshes in the rom cache
-
-		m->meshes = m_romMap[modelAddr];	// will create an entry with a null pointer if empty
-
-		if (m->meshes) {
-			cached = true;
-		}
-		else {
-			m->meshes = std::make_shared<std::vector<Mesh>>();
-			m_romMap[modelAddr] = m->meshes;		// store meshes in our rom map here
-		}
-
-		m->dynamic = false;
-	}
-	else {
-		m->meshes = std::make_shared<std::vector<Mesh>>();
-	}
-
-	// copy current model matrix
-	for (int i = 0; i < 16; i++) {
-		m->modelMat[i] = m_modelMat.currentMatrix[i];
-	}
-
-	//calculate determinant
-	m->determinant = Determinant3x3(m_modelMat);
-
-	// update texture offsets
-	m->textureOffsetX = m_nodeAttribs.currentTexOffsetX;
-	m->textureOffsetY = m_nodeAttribs.currentTexOffsetY;
-	m->page = m_nodeAttribs.currentPage;
-
-	if (!cached) {
-		CacheModel(m, modelAddress);
-	}
-
-	return true;
-}
-
-// Descends into a 10-word culling node
-void CNew3D::DescendCullingNode(UINT32 addr)
-{
-	const UINT32	*node, *lodTable;
-	UINT32			matrixOffset, child1Ptr, sibling2Ptr;
-	float			x, y, z;
-	int				tx, ty;
-	BBox			bbox;
-
-	if (m_nodeAttribs.StackLimit()) {
-		return;
-	}
-
-	node = TranslateCullingAddress(addr);
-
-	if (NULL == node) {
-		return;
-	}
-
-	// Extract known fields
-	child1Ptr		= node[0x07 - m_offset] & 0x7FFFFFF;	// mask colour table bits
-	sibling2Ptr		= node[0x08 - m_offset] & 0x1FFFFFF;	// mask colour table bits
-	matrixOffset	= node[0x03 - m_offset] & 0xFFF;
-
-	if ((node[0x00] & 0x07) != 0x06) {						// colour table seems to indicate no siblings
-		if (!(sibling2Ptr & 0x1000000) && sibling2Ptr) {
-			DescendCullingNode(sibling2Ptr);				// no need to mask bit, would already be zero
-		}
-	}
-
-	if ((node[0x00] & 0x04)) {
-		m_colorTableAddr = ((node[0x03 - m_offset] >> 19) << 0) | ((node[0x07 - m_offset] >> 28) << 13) | ((node[0x08 - m_offset] >> 25) << 17);
-		m_colorTableAddr &= 0x000FFFFF; // clamp to 4MB (in words) range
-	}
-
-	x = *(float *)&node[0x04 - m_offset];
-	y = *(float *)&node[0x05 - m_offset];
-	z = *(float *)&node[0x06 - m_offset];
-
-	m_nodeAttribs.Push();	// save current attribs
-
-	if (!m_offset)	// Step 1.5+
-	{
-		tx = 32 * ((node[0x02] >> 7) & 0x3F);
-		ty = 32 * (node[0x02] & 0x1F);
-
-		// apply texture offsets, else retain current ones
-		if ((node[0x02] & 0x8000))	{
-			m_nodeAttribs.currentTexOffsetX = tx;
-			m_nodeAttribs.currentTexOffsetY = ty;
-			m_nodeAttribs.currentPage = (node[0x02] & 0x4000) >> 14;
-		}
-	}
-
-	// Apply matrix and translation
-	m_modelMat.PushMatrix();
-
-	// apply translation vector
-	if ((node[0x00] & 0x10)) {
-		m_modelMat.Translate(x, y, z);
-	}
-	// multiply matrix, if specified
-	else if (matrixOffset) {
-		MultMatrix(matrixOffset,m_modelMat);
-	}
-
-	if (m_nodeAttribs.currentClipStatus != Clip::INSIDE) {
-
-		float distance = R3DFloat::GetFloat16(node[9 - m_offset] & 0xFFFF);
-
-		CalcBox(distance, bbox);
-		TransformBox(m_modelMat, bbox);
-
-		m_nodeAttribs.currentClipStatus = ClipBox(bbox, m_planes);
-	}
-
-	if (m_nodeAttribs.currentClipStatus != Clip::OUTSIDE) {
-
-		// Descend down first link
-		if ((node[0x00] & 0x08))	// 4-element LOD table
-		{
-			lodTable = TranslateCullingAddress(child1Ptr);
-
-			if (NULL != lodTable) {
-				if ((node[0x03 - m_offset] & 0x20000000)) {
-					DescendCullingNode(lodTable[0] & 0xFFFFFF);
-				}
-				else {
-					DrawModel(lodTable[0] & 0xFFFFFF);	//TODO
-				}
-			}
-		}
-		else {
-			DescendNodePtr(child1Ptr);
-		}
-
-	}
-
-	m_modelMat.PopMatrix();
-
-	// Restore old texture offsets
-	m_nodeAttribs.Pop();
-}
-
-void CNew3D::DescendNodePtr(UINT32 nodeAddr)
-{
-	// Ignore null links
-	if ((nodeAddr & 0x00FFFFFF) == 0) {
-		return;
-	}
-
-	switch ((nodeAddr >> 24) & 0xFF)	// pointer type encoded in upper 8 bits
-	{
-	case 0x00:	// culling node
-		DescendCullingNode(nodeAddr & 0xFFFFFF);
-		break;
-	case 0x01:	// model (perhaps bit 2 is a flag in this case?)
-	case 0x03:
-		DrawModel(nodeAddr & 0xFFFFFF);
-		break;
-	case 0x04:	// pointer list
-		DescendPointerList(nodeAddr & 0xFFFFFF);
-		break;
-	default:
-		break;
-	}
-}
-
-void CNew3D::DescendPointerList(UINT32 addr)
-{
-	const UINT32*	list;
-	UINT32			nodeAddr;
-	int				index;
-
-	list = TranslateCullingAddress(addr);
-
-	if (NULL == list) {
-		return;
-	}
-
-	index = 0;
-
-	while (true) {
-
-		if (list[index] & 0x01000000) {
-			break;	// empty list
-		}
-
-		nodeAddr = list[index] & 0x00FFFFFF;	// clear upper 8 bits to ensure this is processed as a culling node
-
-		DescendCullingNode(nodeAddr);
-
-		if (list[index] & 0x02000000) {
-			break;	// list end
-		}
-
-		index++;
-	}
-}
-
-
-/******************************************************************************
-Matrix Stack
-******************************************************************************/
-
-// Macro to generate column-major (OpenGL) index from y,x subscripts
-#define CMINDEX(y,x)	(x*4+y)
-
-/*
-* MultMatrix():
-*
-* Multiplies the matrix stack by the specified Real3D matrix. The matrix
-* index is a 12-bit number specifying a matrix number relative to the base.
-* The base matrix MUST be set up before calling this function.
-*/
-void CNew3D::MultMatrix(UINT32 matrixOffset, Mat4& mat)
-{
-	GLfloat		m[4*4];
-	const float	*src = &m_matrixBasePtr[matrixOffset * 12];
-
-	if (m_matrixBasePtr == NULL)	// LA Machineguns
-		return;
-
-	m[CMINDEX(0, 0)] = src[3];
-	m[CMINDEX(0, 1)] = src[4];
-	m[CMINDEX(0, 2)] = src[5];
-	m[CMINDEX(0, 3)] = src[0];
-	m[CMINDEX(1, 0)] = src[6];
-	m[CMINDEX(1, 1)] = src[7];
-	m[CMINDEX(1, 2)] = src[8];
-	m[CMINDEX(1, 3)] = src[1];
-	m[CMINDEX(2, 0)] = src[9];
-	m[CMINDEX(2, 1)] = src[10];
-	m[CMINDEX(2, 2)] = src[11];
-	m[CMINDEX(2, 3)] = src[2];
-	m[CMINDEX(3, 0)] = 0.0;
-	m[CMINDEX(3, 1)] = 0.0;
-	m[CMINDEX(3, 2)] = 0.0;
-	m[CMINDEX(3, 3)] = 1.0;
-
-	mat.MultMatrix(m);
-}
-
-/*
-* InitMatrixStack():
-*
-* Initializes the modelview (model space -> view space) matrix stack and
-* Real3D coordinate system. These are the last transforms to be applied (and
-* the first to be defined on the stack) before projection.
-*
-* Model 3 games tend to define the following unusual base matrix:
-*
-*		0	0	-1	0
-*		1	0	0	0
-*		0	-1	0	0
-*		0	0	0	1
-*
-* When this is multiplied by a column vector, the output is:
-*
-*		-Z
-*		X
-*		-Y
-*		1
-*
-* My theory is that the Real3D GPU accepts vectors in Z,X,Y order. The games
-* store everything as X,Y,Z and perform the translation at the end. The Real3D
-* also has Y and Z coordinates opposite of the OpenGL convention. This
-* function inserts a compensating matrix to undo these things.
-*
-* NOTE: This function assumes we are in GL_MODELVIEW matrix mode.
-*/
-
-void CNew3D::InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat)
-{
-	GLfloat m[4 * 4];
-
-	// This matrix converts vectors back from the weird Model 3 Z,X,Y ordering
-	// and also into OpenGL viewspace (-Y,-Z)
-	m[CMINDEX(0, 0)] = 0.0;	m[CMINDEX(0, 1)] = 1.0;	m[CMINDEX(0, 2)] = 0.0;	m[CMINDEX(0, 3)] = 0.0;
-	m[CMINDEX(1, 0)] = 0.0;	m[CMINDEX(1, 1)] = 0.0;	m[CMINDEX(1, 2)] =-1.0; m[CMINDEX(1, 3)] = 0.0;
-	m[CMINDEX(2, 0)] =-1.0; m[CMINDEX(2, 1)] = 0.0;	m[CMINDEX(2, 2)] = 0.0;	m[CMINDEX(2, 3)] = 0.0;
-	m[CMINDEX(3, 0)] = 0.0;	m[CMINDEX(3, 1)] = 0.0;	m[CMINDEX(3, 2)] = 0.0;	m[CMINDEX(3, 3)] = 1.0;
-
-	mat.LoadMatrix(m);
-
-	// Set matrix base address and apply matrix #0 (coordinate system matrix)
-	m_matrixBasePtr = (float *)TranslateCullingAddress(matrixBaseAddr);
-	MultMatrix(0, mat);
-}
-
-// Draws viewports of the given priority
-void CNew3D::RenderViewport(UINT32 addr)
-{
-	static const GLfloat	color[8][3] =
-	{											// RGB1 color translation
-		{ 0.0, 0.0, 0.0 },	// off
-		{ 0.0, 0.0, 1.0 },	// blue
-		{ 0.0, 1.0, 0.0 },	// green
-		{ 0.0, 1.0, 1.0 },	// cyan
-		{ 1.0, 0.0, 0.0 }, 	// red
-		{ 1.0, 0.0, 1.0 },	// purple
-		{ 1.0, 1.0, 0.0 },	// yellow
-		{ 1.0, 1.0, 1.0 }	// white
-	};
-
-	// Translate address and obtain pointer
-	const uint32_t *vpnode = TranslateCullingAddress(addr);
-
-	if (NULL == vpnode) {
-		return;
-	}
-
-	if (vpnode[0x01] == 0) {		// memory probably hasn't been set up yet, abort
-		return;
-	}
-
-	if (!(vpnode[0] & 0x20)) {	// only if viewport enabled
-		uint32_t curPri	= (vpnode[0x00] >> 3) & 3;		// viewport priority
-		uint32_t nodeAddr	= vpnode[0x02];							// scene database node pointer
-
-		// create node object 
-		m_nodes.emplace_back(Node());
-		m_nodes.back().models.reserve(2048);			// create space for models
-
-		// get pointer to its viewport
-		Viewport *vp = &m_nodes.back().viewport;
-
-		vp->priority = curPri;
-
-		// Fetch viewport parameters (TO-DO: would rounding make a difference?)
-		int vpX			= (int)(((vpnode[0x1A] & 0xFFFF) / 16.0f) + 0.5f);		// viewport X (12.4 fixed point)
-		int vpY			= (int)(((vpnode[0x1A] >> 16) / 16.0f) + 0.5f);			// viewport Y (12.4)
-		int vpWidth		= (int)(((vpnode[0x14] & 0xFFFF) / 4.0f) + 0.5f);		// width (14.2)
-		int vpHeight	= (int)(((vpnode[0x14] >> 16) / 4.0f) + 0.5f);			// height (14.2)
-		uint32_t matrixBase	= vpnode[0x16] & 0xFFFFFF;							// matrix base address
-
-		if (vpX) {
-			vpX += 2;
-		}
-
-		if (vpY) {
-			vpY += 2;
-		}
-
-		LODBlendTable* tableTest = (LODBlendTable*)TranslateCullingAddress(vpnode[0x17]);
-
-		float angle_left	= -atan2(*(float *)&vpnode[12],  *(float *)&vpnode[13]);
-		float angle_right	=  atan2(*(float *)&vpnode[16], -*(float *)&vpnode[17]);
-		float angle_top		=  atan2(*(float *)&vpnode[14],  *(float *)&vpnode[15]);
-		float angle_bottom	= -atan2(*(float *)&vpnode[18], -*(float *)&vpnode[19]);
-
-		float near = 0.25f;
-		float far = 2e6;
-
-		if (m_step == 0x10) {
-			near = 8;
-		}
-
-		float l = near * tanf(angle_left);
-		float r = near * tanf(angle_right);
-		float t = near * tanf(angle_top);
-		float b = near * tanf(angle_bottom);
-
-		// TO-DO: investigate clipping near/far planes
-
-		if ((vpX == 0) && (vpWidth >= 495) && (vpY == 0) && (vpHeight >= 383))
-		{
-			float windowAR		= (float)m_totalXRes / (float)m_totalYRes;
-			float originalAR	= 496 / 384.f;
-			float correction	= windowAR / originalAR;	// expand horizontal frustum planes
-
-			vp->x		= 0;
-			vp->y		= m_yOffs + (GLint)((float)(384 - (vpY + vpHeight))*m_yRatio);
-			vp->width	= m_totalXRes;
-			vp->height	= (GLint)((float)vpHeight*m_yRatio);
-
-			vp->projectionMatrix.Frustum(l*correction, r*correction, b, t, near, far);
-		}
-		else
-		{
-			vp->x		= m_xOffs + (GLint)((float)vpX*m_xRatio);
-			vp->y		= m_yOffs + (GLint)((float)(384 - (vpY + vpHeight))*m_yRatio);
-			vp->width	= (GLint)((float)vpWidth*m_xRatio);
-			vp->height	= (GLint)((float)vpHeight*m_yRatio);
-
-			vp->projectionMatrix.Frustum(l, r, b, t, near, far);
-		}
-
-		// calculate frustum planes
-		CalcFrustumPlanes(m_planes, vp->projectionMatrix);
-
-		// Lighting (note that sun vector points toward sun -- away from vertex)
-		vp->lightingParams[0] = *(float *)&vpnode[0x05];								// sun X
-		vp->lightingParams[1] = *(float *)&vpnode[0x06];								// sun Y
-		vp->lightingParams[2] = *(float *)&vpnode[0x04];								// sun Z
-		vp->lightingParams[3] = *(float *)&vpnode[0x07];								// sun intensity
-		vp->lightingParams[4] = (float)((vpnode[0x24] >> 8) & 0xFF) * (1.0f / 255.0f);	// ambient intensity
-		vp->lightingParams[5] = 0.0;	// reserved
-
-		// Spotlight
-		int spotColorIdx = (vpnode[0x20] >> 11) & 7;									// spotlight color index
-		vp->spotEllipse[0] = (float)((vpnode[0x1E] >> 3) & 0x1FFF);						// spotlight X position (fractional component?)
-		vp->spotEllipse[1] = (float)((vpnode[0x1D] >> 3) & 0x1FFF);						// spotlight Y
-		vp->spotEllipse[2] = (float)((vpnode[0x1E] >> 16) & 0xFFFF);					// spotlight X size (16-bit? May have fractional component below bit 16)
-		vp->spotEllipse[3] = (float)((vpnode[0x1D] >> 16) & 0xFFFF);					// spotlight Y size
-
-		vp->spotRange[0] = 1.0f / (*(float *)&vpnode[0x21]);							// spotlight start
-		vp->spotRange[1] = *(float *)&vpnode[0x1F];										// spotlight extent
-
-		if (vp->spotRange[1] == 0) {													// if light extent = 0 light is effectively disabled
-			spotColorIdx = 0;															
-		}
-
-		vp->spotColor[0] = color[spotColorIdx][0];										// spotlight color
-		vp->spotColor[1] = color[spotColorIdx][1];
-		vp->spotColor[2] = color[spotColorIdx][2];
-
-		// Spotlight is applied on a per pixel basis, must scale its position and size to screen
-		vp->spotEllipse[1] = 384.0f - vp->spotEllipse[1];
-		vp->spotRange[1] += vp->spotRange[0];	// limit
-		vp->spotEllipse[2] = 496.0f / sqrt(vp->spotEllipse[2]);	// spotlight appears to be specified in terms of physical resolution (unconfirmed)
-		vp->spotEllipse[3] = 384.0f / sqrt(vp->spotEllipse[3]);
-
-		// Scale the spotlight to the OpenGL viewport
-		vp->spotEllipse[0] = vp->spotEllipse[0] * m_xRatio + m_xOffs;
-		vp->spotEllipse[1] = vp->spotEllipse[1] * m_yRatio + m_yOffs;
-		vp->spotEllipse[2] *= m_xRatio;
-		vp->spotEllipse[3] *= m_yRatio;
-
-		// Fog
-		vp->fogParams[0] = (float)((vpnode[0x22] >> 16) & 0xFF) * (1.0f / 255.0f);	// fog color R
-		vp->fogParams[1] = (float)((vpnode[0x22] >> 8) & 0xFF) * (1.0f / 255.0f);	// fog color G
-		vp->fogParams[2] = (float)((vpnode[0x22] >> 0) & 0xFF) * (1.0f / 255.0f);	// fog color B
-		vp->fogParams[3] = std::abs(*(float *)&vpnode[0x23]);						// fog density	- ocean hunter uses negative values, but looks the same
-		vp->fogParams[4] = (float)(INT16)(vpnode[0x25] & 0xFFFF)*(1.0f / 255.0f);	// fog start
-
-		vp->scrollFog = (float)(vpnode[0x20] & 0xFF) * (1.0f / 255.0f);				// scroll fog
-
-		{
-			//test fog paramaters
-			float lightFogColour[3];
-			int fogColourIdx;
-
-			fogColourIdx = (vpnode[0x20] >> 8) & 7;
-
-			lightFogColour[0] = color[fogColourIdx][0];
-			lightFogColour[1] = color[fogColourIdx][1];
-			lightFogColour[2] = color[fogColourIdx][2];
-
-			float fogAttenuation = ((vpnode[0x24] >> 16) & 0xFF) / 255.f;
-			float fogAmbient	 = ((vpnode[0x25] >> 16) & 0xFF) / 255.f;
-			int debug = 0;
-		}
-		
-		if (std::isinf(vp->fogParams[3]) || std::isnan(vp->fogParams[3]) || std::isinf(vp->fogParams[4]) || std::isnan(vp->fogParams[4])) {	// Star Wars Trilogy
-			vp->fogParams[3] = vp->fogParams[4] = 0.0f;
-		}
-
-		// Unknown light/fog parameters
-		float scrollAtt = (float)(vpnode[0x24] & 0xFF) * (1.0f / 255.0f);	// scroll attenuation
-
-		// Clear texture offsets before proceeding
-		m_nodeAttribs.Reset();
-
-		// Set up coordinate system and base matrix
-		InitMatrixStack(matrixBase, m_modelMat);
-
-		// Safeguard: weird coordinate system matrices usually indicate scenes that will choke the renderer
-		if (NULL != m_matrixBasePtr)
-		{
-			float	m21, m32, m13;
-
-			// Get the three elements that are usually set and see if their magnitudes are 1
-			m21 = m_matrixBasePtr[6];
-			m32 = m_matrixBasePtr[10];
-			m13 = m_matrixBasePtr[5];
-
-			m21 *= m21;
-			m32 *= m32;
-			m13 *= m13;
-
-			if ((m21>1.05) || (m21<0.95))
-				return;
-			if ((m32>1.05) || (m32<0.95))
-				return;
-			if ((m13>1.05) || (m13<0.95))
-				return;
-		}
-
-		// Descend down the node link: Use recursive traversal
-		DescendNodePtr(nodeAddr);
-	}
-
-	// render next viewport
-	if (vpnode[0x01] != 0x01000000) {
-		RenderViewport(vpnode[0x01]);
-	}
-}
-
-void CNew3D::CopyVertexData(const R3DPoly& r3dPoly, std::vector<Poly>& polyArray)
-{
-	//====================
-	Poly		p;
-	V3::Vec3	normal;
-	float		dotProd;
-	bool		clockWise;
-	//====================
-
-	V3::createNormal(r3dPoly.v[0].pos, r3dPoly.v[1].pos, r3dPoly.v[2].pos, normal);
-
-	dotProd		= V3::dotProduct(normal, r3dPoly.faceNormal);
-	clockWise	= dotProd >= 0.0;
-
-	if (clockWise) {
-		p.p1 = r3dPoly.v[0];
-		p.p2 = r3dPoly.v[1];
-		p.p3 = r3dPoly.v[2];
-	}
-	else {
-		p.p1 = r3dPoly.v[2];
-		p.p2 = r3dPoly.v[1];
-		p.p3 = r3dPoly.v[0];
-	}
-
-	//multiply face attributes with vertex attributes if required
-	for (int i = 0; i < 4; i++) {
-		p.p1.color[i] = (UINT8)(p.p1.color[i] * r3dPoly.faceColour[i]);
-		p.p2.color[i] = (UINT8)(p.p2.color[i] * r3dPoly.faceColour[i]);
-		p.p3.color[i] = (UINT8)(p.p3.color[i] * r3dPoly.faceColour[i]);
-	}
-	
-	polyArray.emplace_back(p);
-
-	if (r3dPoly.number == 4) {
-
-		if (clockWise) {
-			p.p1 = r3dPoly.v[0];
-			p.p2 = r3dPoly.v[2];
-			p.p3 = r3dPoly.v[3];
-		}
-		else {
-			p.p1 = r3dPoly.v[0];
-			p.p2 = r3dPoly.v[3];
-			p.p3 = r3dPoly.v[2];
-		}
-
-		//multiply face attributes with vertex attributes if required
-		for (int i = 0; i < 4; i++) {
-			p.p1.color[i] = (UINT8)(p.p1.color[i] * r3dPoly.faceColour[i]);
-			p.p2.color[i] = (UINT8)(p.p2.color[i] * r3dPoly.faceColour[i]);
-			p.p3.color[i] = (UINT8)(p.p3.color[i] * r3dPoly.faceColour[i]);
-		}
-
-		polyArray.emplace_back(p);
-	}
-}
-
-// non smooth texturing on the pro-1000 seems to sample like gl_nearest
-// ie not outside of the texture coordinates, but with bilinear filtering
-// this is about as close as we can emulate in hardware
-// if we don't do this with gl_repeat enabled, it will wrap around and sample the 
-// other side of the texture which produces ugly seems
-void CNew3D::OffsetTexCoords(R3DPoly& r3dPoly, float offset[2])
-{
-	for (int i = 0; i < 2; i++) {
-
-		float min =  std::numeric_limits<float>::max();
-		float max = -std::numeric_limits<float>::max();
-
-		if (!offset[i]) continue;
-
-		for (int j = 0; j < r3dPoly.number; j++) {
-			min = std::min(r3dPoly.v[j].texcoords[i], min);
-			max = std::max(r3dPoly.v[j].texcoords[i], max);
-		}
-
-		float fTemp;
-		float iTemp;
-		bool fractMin;
-		bool fractMax;
-		
-		fTemp		= std::modf(min, &iTemp);
-		fractMin	= fTemp > 0;
-
-		fTemp		= std::modf(max, &iTemp);
-		fractMax	= fTemp > 0;
-
-		for (int j = 0; j < r3dPoly.number && min != max; j++) {
-
-			if (!fractMin) {
-				if (r3dPoly.v[j].texcoords[i] == min) {
-					r3dPoly.v[j].texcoords[i] += offset[i];
-				}
-			}
-
-			if (!fractMax) {
-				if (r3dPoly.v[j].texcoords[i] == max) {
-					r3dPoly.v[j].texcoords[i] -= offset[i];
-				}
-			}
-		}
-	}
-}
-
-void CNew3D::CacheModel(Model *m, const UINT32 *data)
-{
-	Vertex			prev[4];
-	PolyHeader		ph;
-	int				numPolys	= 0;
-	UINT64			lastHash	= -1;
-	SortingMesh*	currentMesh = nullptr;
-	
-	std::map<UINT64, SortingMesh> sMap;
-
-	if (data == NULL)
-		return;
-
-	ph = data; 
-	int numTriangles = ph.NumTrianglesTotal();
-
-	// Cache all polygons
-	do {
-
-		R3DPoly		p;					// current polygon
-		GLfloat		uvScale;
-		int			i, j;
-
-		if (ph.header[6] == 0) {
-			break;
-		}
-
-		if (ph.Disabled() || !numPolys && (ph.NumSharedVerts() != 0)) {
-			continue;
-		}
-
-		// create a hash value based on poly attributes -todo add more attributes
-		auto hash = ph.Hash();
-
-		if (hash != lastHash) {
-
-			if (sMap.count(hash) == 0) {
-
-				sMap[hash] = SortingMesh();
-
-				currentMesh = &sMap[hash];
-
-				//make space for our vertices
-				currentMesh->polys.reserve(numTriangles);
-
-				//copy attributes
-				currentMesh->doubleSided	= false;			// we will double up polys
-				currentMesh->textured		= ph.TexEnabled();
-				currentMesh->alphaTest		= ph.AlphaTest();
-				currentMesh->textureAlpha	= ph.TextureAlpha();
-				currentMesh->polyAlpha		= ph.PolyAlpha();
-				currentMesh->lighting		= ph.LightEnabled() && !ph.FixedShading();
-
-				if (ph.Layered() || (!ph.TexEnabled() && ph.PolyAlpha())) {
-					currentMesh->layered = true;
-				}
-				
-				if (currentMesh->lighting) {
-					if (ph.SpecularEnabled()) {
-						currentMesh->specular = true;
-						currentMesh->shininess = 0;// ph.Shininess();
-						currentMesh->specularCoefficient = 0; // ph.SpecularValue();
-					}
-				}
-	
-				currentMesh->fogIntensity = ph.LightModifier();
-
-				if (ph.TexEnabled()) {
-					currentMesh->format			= m_texSheet.GetTexFormat(ph.TexFormat(), ph.AlphaTest());
-
-					if (currentMesh->format == 7) {
-						currentMesh-> alphaTest = false;	// alpha test is a 1 bit test, this format needs a lower threshold, since it has 16 levels of transparency
-					}
-
-					currentMesh->x				= ph.X();
-					currentMesh->y				= ph.Y();
-					currentMesh->width			= ph.TexWidth();
-					currentMesh->height			= ph.TexHeight();
-					currentMesh->mirrorU		= ph.TexUMirror();
-					currentMesh->mirrorV		= ph.TexVMirror();
-					currentMesh->microTexture	= ph.MicroTexture();
-					currentMesh->microTextureID = ph.MicroTextureID();
-				}
-			}
-
-			currentMesh = &sMap[hash];
-		}
-
-		lastHash = hash;		
-
-		// Obtain basic polygon parameters
-		p.number	= ph.NumVerts();
-		uvScale		= ph.UVScale();
-
-		ph.FaceNormal(p.faceNormal);
-
-		// Fetch reused vertices according to bitfield, then new verts
-		i = 0;
-		j = 0;
-		for (i = 0; i < 4; i++)		// up to 4 reused vertices
-		{
-			if (ph.SharedVertex(i))
-			{
-				p.v[j] = prev[i];
-				++j;
-			}
-		}
-
-		// copy face attributes
-
-		if ((ph.header[1] & 2) == 0) {
-			int colorIdx = ph.ColorIndex();
-			p.faceColour[2] = (m_polyRAM[m_colorTableAddr + colorIdx] & 0xFF) / 255.f;
-			p.faceColour[1] = ((m_polyRAM[m_colorTableAddr + colorIdx] >> 8) & 0xFF) / 255.f;
-			p.faceColour[0] = ((m_polyRAM[m_colorTableAddr + colorIdx] >> 16) & 0xFF) / 255.f;
-		}
-		else {
-			if (ph.ColorDisabled()) {		// no colours were set
-				p.faceColour[0] = 1.0f;
-				p.faceColour[1] = 1.0f;
-				p.faceColour[2] = 1.0f;
-			}
-			else {
-				p.faceColour[0] = ((ph.header[4] >> 24)) / 255.f;
-				p.faceColour[1] = ((ph.header[4] >> 16) & 0xFF) / 255.f;
-				p.faceColour[2] = ((ph.header[4] >> 8) & 0xFF) / 255.f;
-			}
-		}
-
-		p.faceColour[3] = ph.Transparency() / 255.f;
-				
-		// if we have flat shading, we can't re-use normals from shared vertices
-		for (i = 0; i < p.number && !ph.SmoothShading(); i++) {
-			p.v[i].normal[0] = p.faceNormal[0];
-			p.v[i].normal[1] = p.faceNormal[1];
-			p.v[i].normal[2] = p.faceNormal[2];
-		}
-
-		UINT32* vData = ph.StartOfData();	// vertex data starts here
-
-		// remaining vertices are new and defined here
-		for (; j < p.number; j++)	
-		{
-			// Fetch vertices
-			UINT32 ix = vData[0];
-			UINT32 iy = vData[1];
-			UINT32 iz = vData[2];
-			UINT32 it = vData[3];
-
-			// Decode vertices
-			p.v[j].pos[0] = (GLfloat)(((INT32)ix) >> 8) * m_vertexFactor;
-			p.v[j].pos[1] = (GLfloat)(((INT32)iy) >> 8) * m_vertexFactor;
-			p.v[j].pos[2] = (GLfloat)(((INT32)iz) >> 8) * m_vertexFactor;
-
-			// Per vertex normals
-			if (ph.SmoothShading()) {
-				p.v[j].normal[0] = (INT8)(ix & 0xFF) / 128.f;
-				p.v[j].normal[1] = (INT8)(iy & 0xFF) / 128.f;
-				p.v[j].normal[2] = (INT8)(iz & 0xFF) / 128.f;
-			}
-
-			if (ph.FixedShading() && ph.LightEnabled()) {
-				UINT8 shade = (UINT8)((ix + 128) & 0xFF);
-				p.v[j].color[0] = shade;	// hardware doesn't really have per vertex colours, only per poly
-				p.v[j].color[1] = shade;
-				p.v[j].color[2] = shade;
-				p.v[j].color[3] = 255;
-			}
-			else {
-				p.v[j].color[0] = 255;
-				p.v[j].color[1] = 255;
-				p.v[j].color[2] = 255;
-				p.v[j].color[3] = 255;
-			}
-
-			float texU, texV = 0;
-
-			// tex coords
-			if (currentMesh->textured) {
-				Texture::GetCoordinates(currentMesh->width, currentMesh->height, (UINT16)(it >> 16), (UINT16)(it & 0xFFFF), uvScale, texU, texV);
-			}
-
-			p.v[j].texcoords[0] = texU;
-			p.v[j].texcoords[1] = texV;
-
-			vData += 4;
-		}
-
-		// check if we need to modify the texture coordinates
-		{
-			float offset[2] = { 0 };
-
-			if (ph.TexEnabled()) {
-
-				if (!ph.TexSmoothU() && !ph.TexUMirror()) {
-					offset[0] = 0.5f / ph.TexWidth();	// half texel
-				}
-
-				if (!ph.TexSmoothV() && !ph.TexVMirror()) {
-					offset[1] = 0.5f / ph.TexHeight();	// half texel
-				}
-
-				OffsetTexCoords(p, offset);
-			}
-		}
-
-		// check if we need double up vertices for two sided lighting
-		if (ph.DoubleSided()) {
-
-			R3DPoly tempP = p;
-
-			// flip normals
-			V3::inverse(tempP.faceNormal);
-
-			for (int i = 0; i < tempP.number; i++) {
-				V3::inverse(tempP.v[i].normal);
-			}
-
-			CopyVertexData(tempP, currentMesh->polys);
-		}
-
-		// Copy this polygon into the model buffer
-		CopyVertexData(p, currentMesh->polys);
-		numPolys++;
-		
-		// Copy current vertices into previous vertex array
-		for (i = 0; i < 4; i++) {
-			prev[i] = p.v[i];
-		}
-
-	} while (ph.NextPoly());
-
-	//sorted the data, now copy to main data structures
-
-	// we know how many meshes we have so reserve appropriate space
-	m->meshes->reserve(sMap.size());
-
-	for (auto& it : sMap) {
-
-		if (m->dynamic) {
-
-			// calculate VBO values for current mesh
-			it.second.vboOffset		= m_polyBufferRam.size() + MAX_ROM_POLYS;
-			it.second.triangleCount = it.second.polys.size();
-
-			// copy poly data to main buffer
-			m_polyBufferRam.insert(m_polyBufferRam.end(), it.second.polys.begin(), it.second.polys.end());
-		}
-		else {
-			// calculate VBO values for current mesh
-			it.second.vboOffset		= m_polyBufferRom.size();
-			it.second.triangleCount = it.second.polys.size();
-
-			// copy poly data to main buffer
-			m_polyBufferRom.insert(m_polyBufferRom.end(), it.second.polys.begin(), it.second.polys.end());
-		}
-
-		//copy the temp mesh into the model structure
-		//this will lose the associated vertex data, which is now copied to the main buffer anyway
-		m->meshes->push_back(it.second);
-	}
-}
-
-float CNew3D::Determinant3x3(const float m[16]) {
-
-	/*
-		| A B C |
-	M = | D E F |
-		| G H I |
-
-	then the determinant is calculated as follows:
-
-	det M = A * (EI - HF) - B * (DI - GF) + C * (DH - GE)
-	*/
-
-	return m[0] * ((m[5] * m[10]) - (m[6] * m[9])) - m[4] * ((m[1] * m[10]) - (m[2] * m[9])) + m[8] * ((m[1] * m[6]) - (m[2] * m[5]));
-}
-
-bool CNew3D::IsDynamicModel(UINT32 *data)
-{
-	if (data == NULL) {
-		return false;
-	}
-
-	PolyHeader p(data);
-
-	do {
-
-		if ((p.header[1] & 2) == 0) {		// model has rgb colour palette 
-			return true;
-		}
-
-		if (p.header[6] == 0) {
-			break;
-		}
-
-	} while (p.NextPoly());
-
-	return false;
-}
-
-bool CNew3D::IsVROMModel(UINT32 modelAddr)
-{
-	return modelAddr >= 0x100000;
-}
-
-void CNew3D::CalcTexOffset(int offX, int offY, int page, int x, int y, int& newX, int& newY)
-{
-	newX = (x + offX) & 2047;	// wrap around 2048, shouldn't be required
-
-	int oldPage = y / 1024;
-
-	y -= (oldPage * 1024);	// remove page from tex y
-
-	// calc newY with wrap around, wraps around in the same sheet, not into another memory sheet
-
-	newY = (y + offY) & 1023;
-
-	// add page to Y
-
-	newY += ((oldPage + page) & 1) * 1024;		// max page 0-1
-}
-
-void CNew3D::CalcFrustumPlanes(Plane p[6], const float* matrix)
-{
-	// Left Plane
-	p[0].a = matrix[3] + matrix[0];
-	p[0].b = matrix[7] + matrix[4];
-	p[0].c = matrix[11] + matrix[8];
-	p[0].d = matrix[15] + matrix[12];
-	p[0].Normalise();
-
-	// Right Plane
-	p[1].a = matrix[3] - matrix[0];
-	p[1].b = matrix[7] - matrix[4];
-	p[1].c = matrix[11] - matrix[8];
-	p[1].d = matrix[15] - matrix[12];
-	p[1].Normalise();
-
-	// Bottom Plane
-	p[2].a = matrix[3] + matrix[1];
-	p[2].b = matrix[7] + matrix[5];
-	p[2].c = matrix[11] + matrix[9];
-	p[2].d = matrix[15] + matrix[13];
-	p[2].Normalise();
-
-	// Top Plane
-	p[3].a = matrix[3] - matrix[1];
-	p[3].b = matrix[7] - matrix[5];
-	p[3].c = matrix[11] - matrix[9];
-	p[3].d = matrix[15] - matrix[13];
-	p[3].Normalise();
-
-	// Near Plane
-	p[4].a = matrix[3] + matrix[2];
-	p[4].b = matrix[7] + matrix[6];
-	p[4].c = matrix[11] + matrix[10];
-	p[4].d = matrix[15] + matrix[14];
-	p[4].Normalise();
-
-	// Far Plane
-	p[5].a = matrix[3] - matrix[2];
-	p[5].b = matrix[7] - matrix[6];
-	p[5].c = matrix[11] - matrix[10];
-	p[5].d = matrix[15] - matrix[14];
-	p[5].Normalise();
-}
-
-void CNew3D::CalcBox(float distance, BBox& box)
-{
-	//bottom left front
-	box.points[0][0] = -distance;
-	box.points[0][1] = -distance;
-	box.points[0][2] = distance;
-	box.points[0][3] = 1;
-
-	//bottom left back
-	box.points[1][0] = -distance;
-	box.points[1][1] = -distance;
-	box.points[1][2] = -distance;
-	box.points[1][3] = 1;
-
-	//bottom right back
-	box.points[2][0] = distance;
-	box.points[2][1] = -distance;
-	box.points[2][2] = -distance;
-	box.points[2][3] = 1;
-
-	//bottom right front
-	box.points[3][0] = distance;
-	box.points[3][1] = -distance;
-	box.points[3][2] = distance;
-	box.points[3][3] = 1;
-
-	//top left front
-	box.points[4][0] = -distance;
-	box.points[4][1] = distance;
-	box.points[4][2] = distance;
-	box.points[4][3] = 1;
-
-	//top left back
-	box.points[5][0] = -distance;
-	box.points[5][1] = distance;
-	box.points[5][2] = -distance;
-	box.points[5][3] = 1;
-
-	//top right back
-	box.points[6][0] = distance;
-	box.points[6][1] = distance;
-	box.points[6][2] = -distance;
-	box.points[6][3] = 1;
-
-	//top right front
-	box.points[7][0] = distance;
-	box.points[7][1] = distance;
-	box.points[7][2] = distance;
-	box.points[7][3] = 1;
-}
-
-void CNew3D::MultVec(const float matrix[16], const float in[4], float out[4]) 
-{
-	for (int i = 0; i < 4; i++) {
-		out[i] =
-			in[0] * matrix[0 * 4 + i] +
-			in[1] * matrix[1 * 4 + i] +
-			in[2] * matrix[2 * 4 + i] +
-			in[3] * matrix[3 * 4 + i];
-	}
-}
-
-void CNew3D::TransformBox(const float *m, BBox& box)
-{
-	for (int i = 0; i < 8; i++) {
-		float v[4];
-		MultVec(m, box.points[i], v);
-		box.points[i][0] = v[0];
-		box.points[i][1] = v[1];
-		box.points[i][2] = v[2];
-	}
-}
-
-Clip CNew3D::ClipBox(BBox& box, Plane planes[6])
-{
-	int count = 0;
-
-	for (int i = 0; i < 8; i++) {
-
-		int temp = 0;
-
-		for (int j = 0; j < 6; j++) {
-			if (planes[j].DistanceToPoint(box.points[i]) >= 0) {
-				temp++;
-			}
-		}
-
-		if (temp == 6) count++;		// point is inside all 6 frustum planes
-	}
-
-	if (count == 8)	return Clip::INSIDE;
-	if (count > 0)	return Clip::INTERCEPT;
-	
-	//if we got here all points are outside of the view frustum
-	//check for all points being side same of any plane, means box outside of view
-
-	for (int i = 0; i < 6; i++) {
-
-		int temp = 0;
-
-		for (int j = 0; j < 8; j++) {
-			if (planes[i].DistanceToPoint(box.points[j]) >= 0) {
-				float distance = planes[i].DistanceToPoint(box.points[j]);
-				temp++;
-			}
-		}
-
-		if (temp == 0) return Clip::OUTSIDE;
-	}
-
-	//if we got here, box is traversing view frustum
-
-	return Clip::INTERCEPT;
-}
-
-} // New3D
-
diff --git a/Src/Graphics/New3D/backup/lost world debug/New3D.h b/Src/Graphics/New3D/backup/lost world debug/New3D.h
deleted file mode 100644
index 4ff0b41..0000000
--- a/Src/Graphics/New3D/backup/lost world debug/New3D.h	
+++ /dev/null
@@ -1,241 +0,0 @@
-/**
-** Supermodel
-** A Sega Model 3 Arcade Emulator.
-** Copyright 2011 Bart Trzynadlowski, Nik Henson
-**
-** This file is part of Supermodel.
-**
-** Supermodel is free software: you can redistribute it and/or modify it under
-** the terms of the GNU General Public License as published by the Free
-** Software Foundation, either version 3 of the License, or (at your option)
-** any later version.
-**
-** Supermodel is distributed in the hope that it will be useful, but WITHOUT
-** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-** FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-** more details.
-**
-** You should have received a copy of the GNU General Public License along
-** with Supermodel.  If not, see <http://www.gnu.org/licenses/>.
-**/
-
-/*
-* New3D.h
-*
-* Header file defining the CNew3D class: OpenGL Real3D graphics engine.
-*/
-
-#ifndef INCLUDED_NEW3D_H
-#define INCLUDED_NEW3D_H
-
-#include "Pkgs/glew.h"
-#include "Types.h"
-#include "TextureSheet.h"
-#include "Graphics/IRender3D.h"
-#include "Model.h"
-#include "Mat4.h"
-#include "R3DShader.h"
-#include "VBO.h"
-#include "R3DData.h"
-#include "Plane.h"
-#include "Vec.h"
-#include "R3DScrollFog.h"
-
-namespace New3D {
-
-class CNew3D : public IRender3D
-{
-public:
-	/*
-	* RenderFrame(void):
-	*
-	* Renders the complete scene database. Must be called between BeginFrame() and
-	* EndFrame(). This function traverses the scene database and builds up display
-	* lists.
-	*/
-	void RenderFrame(void);
-
-	/*
-	* BeginFrame(void):
-	*
-	* Prepare to render a new frame. Must be called once per frame prior to
-	* drawing anything.
-	*/
-	void BeginFrame(void);
-
-	/*
-	* EndFrame(void):
-	*
-	* Signals the end of rendering for this frame. Must be called last during
-	* the frame.
-	*/
-	void EndFrame(void);
-
-	/*
-	* UploadTextures(x, y, width, height):
-	*
-	* Signals that a portion of texture RAM has been updated.
-	*
-	* Parameters:
-	*		x		X position within texture RAM.
-	*		y		Y position within texture RAM.
-	*		width	Width of texture data in texels.
-	*		height	Height.
-	*/
-	void UploadTextures(unsigned x, unsigned y, unsigned width, unsigned height);
-
-	/*
-	* AttachMemory(cullingRAMLoPtr, cullingRAMHiPtr, polyRAMPtr, vromPtr,
-	* 				textureRAMPtr):
-	*
-	* Attaches RAM and ROM areas. This must be done prior to any rendering
-	* otherwise the program may crash with an access violation.
-	*
-	* Parameters:
-	*		cullingRAMLoPtr		Pointer to low culling RAM (4 MB).
-	*		cullingRAMHiPtr		Pointer to high culling RAM (1 MB).
-	*		polyRAMPtr			Pointer to polygon RAM (4 MB).
-	*		vromPtr				Pointer to video ROM (64 MB).
-	*		textureRAMPtr		Pointer to texture RAM (8 MB).
-	*/
-	void AttachMemory(const UINT32 *cullingRAMLoPtr,
-		const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr,
-		const UINT32 *vromPtr, const UINT16 *textureRAMPtr);
-
-	/*
-	* SetStep(stepID):
-	*
-	* Sets the Model 3 hardware stepping, which also determines the Real3D
-	* functionality. The default is Step 1.0. This should be called prior to
-	* any other emulation functions and after Init().
-	*
-	* Parameters:
-	*		stepID	0x10 for Step 1.0, 0x15 for Step 1.5, 0x20 for Step 2.0,
-	*				or 0x21 for Step 2.1. Anything else defaults to 1.0.
-	*/
-	void SetStep(int stepID);
-
-	/*
-	* Init(xOffset, yOffset, xRes, yRes, totalXRes, totalYRes):
-	*
-	* One-time initialization of the context. Must be called before any other
-	* members (meaning it should be called even before being attached to any
-	* other objects that want to use it).
-	*
-	* External shader files are loaded according to configuration settings.
-	*
-	* Parameters:
-	*		xOffset		X offset of the viewable area within OpenGL display
-	*                  surface, in pixels.
-	*		yOffset		Y offset.
-	*		xRes		Horizontal resolution of the viewable area.
-	*		yRes		Vertical resolution.
-	*		totalXRes	Horizontal resolution of the complete display area.
-	*		totalYRes	Vertical resolution.
-	*
-	* Returns:
-	*		OKAY is successful, otherwise FAILED if a non-recoverable error
-	*		occurred. Any allocated memory will not be freed until the
-	*		destructor is called. Prints own error messages.
-	*/
-	bool Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXRes, unsigned totalYRes);
-
-	/*
-	* CRender3D(void):
-	* ~CRender3D(void):
-	*
-	* Constructor and destructor.
-	*/
-	CNew3D(void);
-	~CNew3D(void);
-
-private:
-	/*
-	* Private Members
-	*/
-
-	// Real3D address translation
-	const UINT32 *TranslateCullingAddress(UINT32 addr);
-	const UINT32 *TranslateModelAddress(UINT32 addr);
-
-	// Matrix stack
-	void MultMatrix(UINT32 matrixOffset, Mat4& mat);
-	void InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat);
-
-	// Scene database traversal
-	bool DrawModel(UINT32 modelAddr);
-	void DescendCullingNode(UINT32 addr);
-	void DescendPointerList(UINT32 addr);
-	void DescendNodePtr(UINT32 nodeAddr);
-	void RenderViewport(UINT32 addr);
-
-	// building the scene
-	void CacheModel(Model *m, const UINT32 *data);
-	void CopyVertexData(const R3DPoly& r3dPoly, std::vector<Poly>& polyArray);
-	void OffsetTexCoords(R3DPoly& r3dPoly, float offset[2]);
-
-	void RenderScene(int priority, bool alpha);
-	float Determinant3x3(const float m[16]);
-	bool IsDynamicModel(UINT32 *data);		// check if the model has a colour palette
-	bool IsVROMModel(UINT32 modelAddr);
-	void DrawScrollFog();
-
-	void CalcTexOffset(int offX, int offY, int page, int x, int y, int& newX, int& newY);	
-
-	/*
-	* Data
-	*/
-
-	// Stepping
-	int		m_step;
-	int		m_offset;			// offset to subtract for words 3 and higher of culling nodes
-	float	m_vertexFactor;		// fixed-point conversion factor for vertices
-
-	// Memory (passed from outside)
-	const UINT32	*m_cullingRAMLo;	// 4 MB
-	const UINT32	*m_cullingRAMHi;	// 1 MB
-	const UINT32	*m_polyRAM;			// 4 MB
-	const UINT32	*m_vrom;			// 64 MB
-	const UINT16	*m_textureRAM;		// 8 MB
-
-	// Resolution and scaling factors (to support resolutions higher than 496x384) and offsets
-	float		m_xRatio, m_yRatio;
-	unsigned	m_xOffs, m_yOffs;
-	unsigned 	m_totalXRes, m_totalYRes;
-
-	// Real3D Base Matrix Pointer
-	const float	*m_matrixBasePtr;
-	UINT32 m_colorTableAddr = 0x400;		// address of color table in polygon RAM
-
-	TextureSheet	m_texSheet;
-	NodeAttributes	m_nodeAttribs;
-	Mat4			m_modelMat;				// current modelview matrix
-
-	std::vector<Node> m_nodes;				// this represents the entire render frame
-	std::vector<Poly> m_polyBufferRam;		// dynamic polys
-	std::vector<Poly> m_polyBufferRom;		// rom polys
-	std::unordered_map<UINT32, std::shared_ptr<std::vector<Mesh>>> m_romMap;	// a hash table for all the ROM models. The meshes don't have model matrices or tex offsets yet
-
-	VBO m_vbo;								// large VBO to hold our poly data, start of VBO is ROM data, ram polys follow
-	R3DShader m_r3dShader;
-	R3DScrollFog m_r3dScrollFog;
-
-	Plane m_planes[6];
-
-	struct BBox
-	{
-		V4::Vec4 points[8];
-	};
-
-	void CalcFrustumPlanes	(Plane p[6], const float* matrix);
-	void CalcBox			(float distance, BBox& box);
-	void TransformBox		(const float *m, BBox& box);
-	void MultVec			(const float matrix[16], const float in[4], float out[4]);
-	Clip ClipBox			(BBox& box, Plane planes[6]);
-
-	void TestDraw();
-};
-
-} // New3D
-
-#endif  // INCLUDED_NEW3D_H
diff --git a/Src/Graphics/New3D/backup/lost world debug/R3DShader.cpp b/Src/Graphics/New3D/backup/lost world debug/R3DShader.cpp
deleted file mode 100644
index c6044b0..0000000
--- a/Src/Graphics/New3D/backup/lost world debug/R3DShader.cpp	
+++ /dev/null
@@ -1,355 +0,0 @@
-#include "R3DShader.h"
-#include "Graphics/Shader.h"
-
-namespace New3D {
-
-static const char *vertexShaderBasic =
-
-// uniforms
-"uniform float	fogIntensity;\n"
-"uniform float	fogDensity;\n"
-"uniform float	fogStart;\n"
-
-//outputs to fragment shader
-"varying float	fsFogFactor;\n"
-"varying float	fsSpecularTerm;\n"		// specular light term (additive)
-"varying vec3	fsViewVertex;\n"
-"varying vec3	fsViewNormal;\n"		// per vertex normal vector
-
-"void main(void)\n"
-"{\n"
-	"fsViewVertex	= vec3(gl_ModelViewMatrix * gl_Vertex);\n"
-	"fsViewNormal	= normalize(gl_NormalMatrix  *gl_Normal);\n"
-	"float z		= length(fsViewVertex);\n"
-	"fsFogFactor	= fogIntensity * clamp(fogStart + z * fogDensity, 0.0, 1.0);\n"
-
-	"gl_FrontColor	= gl_Color;\n"
-	"gl_TexCoord[0]	= gl_MultiTexCoord0;\n"
-	"gl_Position	= gl_ModelViewProjectionMatrix * gl_Vertex;\n"
-"}\n";
-
-static const char *fragmentShaderBasic =
-
-"uniform sampler2D tex1;\n"			// base tex
-"uniform sampler2D tex2;\n"			// micro tex (optional)
-
-"uniform int	textureEnabled;\n"
-"uniform int	microTexture;\n"
-"uniform int	alphaTest;\n"
-"uniform int	textureAlpha;\n"
-"uniform vec3	fogColour;\n"
-"uniform vec4	spotEllipse;\n"			// spotlight ellipse position: .x=X position (screen coordinates), .y=Y position, .z=half-width, .w=half-height)
-"uniform vec2	spotRange;\n"			// spotlight Z range: .x=start (viewspace coordinates), .y=limit
-"uniform vec3	spotColor;\n"			// spotlight RGB color
-"uniform vec3	lighting[2];\n"			// lighting state (lighting[0] = sun direction, lighting[1].x,y = diffuse, ambient intensities from 0-1.0)
-"uniform int	lightEnable;\n"			// lighting enabled (1.0) or luminous (0.0), drawn at full intensity
-"uniform float	specularCoefficient;\n"	// specular coefficient
-"uniform float	shininess;\n"			// specular shininess
-
-//interpolated inputs from vertex shader
-"varying float	fsFogFactor;\n"
-"varying float	fsSpecularTerm;\n"		// specular light term (additive)
-"varying vec3	fsViewVertex;\n"
-"varying vec3	fsViewNormal;\n"		// per vertex normal vector
-
-"void main()\n"
-"{\n"
-  "vec4 tex1Data;\n"
-  "vec4 colData;\n"
-  "vec4 finalData;\n"
-
-  "bool discardFragment = false;\n"
-
-  "tex1Data = vec4(1.0, 1.0, 1.0, 1.0);\n"
-
-  "if(textureEnabled==1) {\n"
-
-    "tex1Data = texture2D( tex1, gl_TexCoord[0].st);\n"
-
-    "if (microTexture==1) {\n"
-      "vec4 tex2Data = texture2D( tex2, gl_TexCoord[0].st * 4.0);\n"
-      "tex1Data = (tex1Data+tex2Data)/2.0;\n"
-    "}\n"
-
-    "if (alphaTest==1) {\n"         // does it make any sense to do this later?
-      "if (tex1Data.a < (8.0/16.0)) {\n"
-        "discardFragment = true;\n"
-      "}\n"
-    "}\n"
-
-    "if (textureAlpha == 0) {\n"
-      "tex1Data.a = 1.0;\n"
-    "}\n"
-  "}\n"
-
-  "colData = gl_Color;\n"
-
-  "finalData = tex1Data * colData;\n"
-  "if (finalData.a < (1.0/16.0)) {\n"      // basically chuck out any totally transparent pixels value = 1/16 the smallest transparency level h/w supports
-    "discardFragment = true;\n"
-  "}\n"
-
-  "if (discardFragment) {\n"
-    "discard;\n"
-  "}\n"
-   
-  "if (lightEnable==1) {\n"
-    "vec3   lightIntensity;\n"
-    "vec3   sunVector;\n"     // sun lighting vector (as reflecting away from vertex)
-    "float   sunFactor;\n"    // sun light projection along vertex normal (0.0 to 1.0)
-
-    // Real3D -> OpenGL view space convention (TO-DO: do this outside of shader)
-    "sunVector = lighting[0] * vec3(1.0, -1.0, -1.0);\n"
-
-    // Compute diffuse factor for sunlight
-    "sunFactor = max(dot(sunVector, fsViewNormal), 0.0);\n"
-
-    // Total light intensity: sum of all components 
-    "lightIntensity = vec3(sunFactor*lighting[1].x + lighting[1].y);\n"   // ambient + diffuse
-
-    "lightIntensity = clamp(lightIntensity,0.0,1.0);\n"
-
-    "vec2   ellipse;\n"
-    "float   insideSpot;\n"
-
-    // Compute spotlight and apply lighting
-    "ellipse   = (gl_FragCoord.xy - spotEllipse.xy) / spotEllipse.zw;\n"
-    "insideSpot = dot(ellipse, ellipse);\n"
-
-    "if ((insideSpot <= 1.0) && (-fsViewVertex.z >= spotRange.x)) {\n"
-      "lightIntensity.rgb += (1.0 - insideSpot)*spotColor;\n"
-    "}\n"
-
-   
-    "finalData.rgb *= lightIntensity;\n"
-
-    "if (sunFactor > 0.0 && specularCoefficient > 0.0) {\n"
-
-      "vec3 v = normalize(-fsViewVertex);\n"
-      "vec3 h = normalize(sunVector + v);\n"   // halfway vector
-
-      "float NdotHV = max(dot(fsViewNormal,h),0.0);\n"
-
-      "finalData.rgb += vec3(specularCoefficient * pow(NdotHV,shininess));\n"
-    "}\n"
-  "}\n"
-
-
-  "finalData.rgb = mix(finalData.rgb, fogColour, fsFogFactor);\n"
-
-  "gl_FragColor = finalData;\n"
-"}\n";
-
-R3DShader::R3DShader()
-{
-	m_shaderProgram		= 0;
-	m_vertexShader		= 0;
-	m_fragmentShader	= 0;
-
-	Start();	// reset attributes
-}
-
-void R3DShader::Start()
-{
-	m_textured1		= false;
-	m_textured2		= false;
-	m_textureAlpha	= false;		// use alpha in texture
-	m_alphaTest		= false;		// discard fragment based on alpha (ogl does this with fixed function)
-	m_doubleSided	= false;
-	m_lightEnabled	= false;
-	m_layered		= false;
-
-	m_shininess = 0;
-	m_specularCoefficient = 0;
-
-	m_matDet = MatDet::notset;
-
-	m_dirtyMesh		= true;			// dirty means all the above are dirty, ie first run
-	m_dirtyModel	= true;
-}
-
-bool R3DShader::LoadShader(const char* vertexShader, const char* fragmentShader)
-{
-	const char* vShader;
-	const char* fShader;
-	bool success;
-
-	if (vertexShader) {
-		vShader = vertexShader;
-	}
-	else {
-		vShader = vertexShaderBasic;
-	}
-
-	if (fragmentShader) {
-		fShader = fragmentShader;
-	}
-	else {
-		fShader = fragmentShaderBasic;
-	}
-
-	success = LoadShaderProgram(&m_shaderProgram, &m_vertexShader, &m_fragmentShader, nullptr, nullptr, vShader, fShader);
-
-	m_locTexture1		= glGetUniformLocation(m_shaderProgram, "tex1");
-	m_locTexture2		= glGetUniformLocation(m_shaderProgram, "tex2");
-	m_locTexture1Enabled= glGetUniformLocation(m_shaderProgram, "textureEnabled");
-	m_locTexture2Enabled= glGetUniformLocation(m_shaderProgram, "microTexture");
-	m_locTextureAlpha	= glGetUniformLocation(m_shaderProgram, "textureAlpha");
-	m_locAlphaTest		= glGetUniformLocation(m_shaderProgram, "alphaTest");
-
-	m_locFogIntensity	= glGetUniformLocation(m_shaderProgram, "fogIntensity");
-	m_locFogDensity		= glGetUniformLocation(m_shaderProgram, "fogDensity");
-	m_locFogStart		= glGetUniformLocation(m_shaderProgram, "fogStart");
-	m_locFogColour		= glGetUniformLocation(m_shaderProgram, "fogColour");
-
-	m_locLighting		= glGetUniformLocation(m_shaderProgram, "lighting");
-	m_locLightEnable	= glGetUniformLocation(m_shaderProgram, "lightEnable");
-	m_locShininess		= glGetUniformLocation(m_shaderProgram, "shininess");
-	m_locSpecCoefficient= glGetUniformLocation(m_shaderProgram, "specularCoefficient");
-	m_locSpotEllipse	= glGetUniformLocation(m_shaderProgram, "spotEllipse");
-	m_locSpotRange		= glGetUniformLocation(m_shaderProgram, "spotRange");
-	m_locSpotColor		= glGetUniformLocation(m_shaderProgram, "spotColor");
-
-	return success;
-}
-
-void R3DShader::SetShader(bool enable)
-{
-	if (enable) {
-		glUseProgram(m_shaderProgram);
-		Start();
-	}
-	else {
-		glUseProgram(0);
-	}
-}
-
-void R3DShader::SetMeshUniforms(const Mesh* m)
-{
-	if (m == nullptr) {
-		return;			// sanity check
-	}
-
-	if (m_dirtyMesh) {
-		glUniform1i(m_locTexture1, 0);
-		glUniform1i(m_locTexture2, 1);
-	}
-
-	if (m_dirtyMesh || m->textured != m_textured1) {
-		glUniform1i(m_locTexture1Enabled, m->textured);
-		m_textured1 = m->textured;
-	}
-
-	if (m_dirtyMesh || m->microTexture != m_textured2) {
-		glUniform1i(m_locTexture2Enabled, m->microTexture);
-		m_textured2 = m->microTexture;
-	}
-
-	if (m_dirtyMesh || m->alphaTest != m_alphaTest) {
-		glUniform1i(m_locAlphaTest, m->alphaTest);
-		m_alphaTest = m->alphaTest;
-	}
-
-	if (m_dirtyMesh || m->textureAlpha != m_textureAlpha) {
-		glUniform1i(m_locTextureAlpha, m->textureAlpha);
-		m_textureAlpha = m->textureAlpha;
-	}
-
-	if (m_dirtyMesh || m->fogIntensity != m_fogIntensity) {
-		glUniform1f(m_locFogIntensity, m->fogIntensity);
-		m_fogIntensity = m->fogIntensity;
-	}
-
-	if (m_dirtyMesh || m->lighting != m_lightEnabled) {
-		glUniform1i(m_locLightEnable, m->lighting);
-		m_lightEnabled = m->lighting;
-	}
-
-	if (m_dirtyMesh || m->shininess != m_shininess) {
-		glUniform1f(m_locShininess, (m->shininess + 1) * 4);
-		m_shininess = m->shininess;
-	}
-
-	if (m_dirtyMesh || m->specularCoefficient != m_specularCoefficient) {
-		glUniform1f(m_locSpecCoefficient, m->specularCoefficient);
-		m_specularCoefficient = m->specularCoefficient;
-	}
-
-	if (m_dirtyMesh || m->layered != m_layered) {
-		m_layered = m->layered;
-		if (m_layered) {
-			glEnable(GL_STENCIL_TEST);
-		}
-		else {
-			glDisable(GL_STENCIL_TEST);
-		}
-	}
-
-	if (m_matDet!=MatDet::zero) {
-
-		if (m_dirtyMesh || m->doubleSided != m_doubleSided) {
-
-			m_doubleSided = m->doubleSided;
-
-			if (m_doubleSided) {
-				glDisable(GL_CULL_FACE);
-			}
-			else {
-				//glEnable(GL_CULL_FACE);
-			}
-		}
-	}
-
-
-	m_dirtyMesh = false;
-}
-
-void R3DShader::SetViewportUniforms(const Viewport *vp)
-{	
-	//didn't bother caching these, they don't get frequently called anyway
-	glUniform1f	(m_locFogDensity, vp->fogParams[3]);
-	glUniform1f	(m_locFogStart, vp->fogParams[4]);
-	glUniform3fv(m_locFogColour, 1, vp->fogParams);
-
-	glUniform3fv(m_locLighting, 2, vp->lightingParams);
-	glUniform4fv(m_locSpotEllipse, 1, vp->spotEllipse);
-	glUniform2fv(m_locSpotRange, 1, vp->spotRange);
-	glUniform3fv(m_locSpotColor, 1, vp->spotColor);
-}
-
-void R3DShader::SetModelStates(const Model* model)
-{
-	//==========
-	MatDet test;
-	//==========
-
-	test = MatDet::notset;		// happens for bad matrices with NaN
-
-	if (model->determinant < 0)			{ test = MatDet::negative; }
-	else if (model->determinant > 0)	{ test = MatDet::positive; }
-	else if (model->determinant == 0)	{ test = MatDet::zero; }
-
-	if (m_dirtyModel || m_matDet!=test) {
-
-		switch (test) {
-		case MatDet::negative:
-			glCullFace(GL_FRONT);
-			//glEnable(GL_CULL_FACE);
-			m_doubleSided = false;
-			break;
-		case MatDet::positive:
-			glCullFace(GL_BACK);
-			//glEnable(GL_CULL_FACE);
-			m_doubleSided = false;
-			break;
-		default:
-			glDisable(GL_CULL_FACE);
-			m_doubleSided = true;		// basically drawing on both sides now
-		}
-	}
-
-	m_matDet		= test;
-	m_dirtyModel	= false;
-}
-
-} // New3D
diff --git a/Src/Graphics/New3D/backup/static model attempt 1/Model.h b/Src/Graphics/New3D/backup/static model attempt 1/Model.h
deleted file mode 100644
index 590a1bd..0000000
--- a/Src/Graphics/New3D/backup/static model attempt 1/Model.h	
+++ /dev/null
@@ -1,124 +0,0 @@
-#ifndef _MODEL_H_
-#define _MODEL_H_
-
-#include "types.h"
-#include <vector>
-#include <unordered_map>
-#include <map>
-#include <memory>
-#include "Texture.h"
-#include "Mat4.h"
-
-namespace New3D {
-
-struct Vertex
-{
-	float pos[3];
-	float normal[3];
-	float texcoords[2];
-	UINT8 color[4];			//rgba
-};
-
-struct Poly		// our polys are always 3 triangles, unlike the real h/w
-{
-	Vertex p1;
-	Vertex p2;
-	Vertex p3;
-};
-
-struct R3DPoly
-{
-	Vertex v[4];			// just easier to have them as an array
-	float faceNormal[3];	// we need this to help work out poly winding, i assume the h/w uses this instead of calculating normals itself
-	int number = 4;
-};
-
-struct Mesh
-{
-	// texture
-	int format, x, y, width, height;
-	bool mirrorU = false;
-	bool mirrorV = false;
-
-	// attributes
-	bool doubleSided	= false;
-	bool textured		= false;
-	bool polyAlpha		= false;		// specified in the rgba colour
-	bool textureAlpha	= false;		// use alpha in texture
-	bool alphaTest		= false;		// discard fragment based on alpha (ogl does this with fixed function)
-	bool lighting		= false;
-	bool testBit		= false;
-	bool clockWise		= true;			// we need to check if the matrix will change the winding
-
-	float fogIntensity = 1.0f;
-
-	// opengl resources
-	int vboOffset		= 0;			// this will be calculated later
-	int triangleCount	= 0;
-};
-
-struct SortingMesh : public Mesh		// This struct temporarily holds the model data, before it gets copied to the main buffer
-{
-	std::vector<Poly> polys;
-};
-
-struct Model
-{
-	std::vector<Mesh> meshes;
-
-	bool dynamic = true;
-
-	//matrices
-	float modelMat[16];
-	float determinant;				// we check if the determinant of the matrix is negative, if it is, the matrix will swap the axis order
-};
-
-struct Viewport
-{
-	Mat4	projectionMatrix;		// projection matrix
-	float	lightingParams[6];		// lighting parameters (see RenderViewport() and vertex shader)
-	float	spotEllipse[4];			// spotlight ellipse (see RenderViewport())
-	float	spotRange[2];			// Z range
-	float	spotColor[3];			// color
-	float	fogParams[5];			// fog parameters (...)
-	int		x, y;					// viewport coordinates (scaled and in OpenGL format)
-	int		width, height;			// viewport dimensions (scaled for display surface size)
-	int		priority;
-};
-
-class NodeAttributes
-{
-public:
-
-	NodeAttributes();
-
-	bool Push();
-	bool Pop();
-	bool StackLimit();
-	void Reset();
-
-	int currentTexOffsetX;
-	int currentTexOffsetY;
-	int currentTexOffset;		// raw value
-
-private:
-
-	struct NodeAttribs
-	{
-		int texOffsetX;
-		int texOffsetY;
-		int texOffset;
-	};
-	std::vector<NodeAttribs> m_vecAttribs;
-};
-
-struct Node
-{
-	Viewport viewport;
-	std::vector<std::shared_ptr<Model>> models;
-};
-
-} // New3D
-
-
-#endif
\ No newline at end of file
diff --git a/Src/Graphics/New3D/backup/static model attempt 1/New3D.cpp b/Src/Graphics/New3D/backup/static model attempt 1/New3D.cpp
deleted file mode 100644
index e1eb1f8..0000000
--- a/Src/Graphics/New3D/backup/static model attempt 1/New3D.cpp	
+++ /dev/null
@@ -1,1058 +0,0 @@
-#include "New3D.h"
-#include "PolyHeader.h"
-#include "Texture.h"
-#include "Vec.h"
-#include <cmath>  // needed by gcc
-
-#define MAX_RAM_POLYS 100000	
-#define MAX_ROM_POLYS 500000
-
-#ifndef M_PI
-#define M_PI 3.14159265359
-#endif
-
-namespace New3D {
-
-CNew3D::CNew3D()
-{
-	m_cullingRAMLo	= nullptr;
-	m_cullingRAMHi	= nullptr;
-	m_polyRAM		= nullptr;
-	m_vrom			= nullptr;
-	m_textureRAM	= nullptr;
-}
-
-CNew3D::~CNew3D()
-{
-	m_vbo.Destroy();
-}
-
-void CNew3D::AttachMemory(const UINT32 *cullingRAMLoPtr, const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr, const UINT32 *vromPtr, const UINT16 *textureRAMPtr)
-{
-	m_cullingRAMLo	= cullingRAMLoPtr;
-	m_cullingRAMHi	= cullingRAMHiPtr;
-	m_polyRAM		= polyRAMPtr;
-	m_vrom			= vromPtr;
-	m_textureRAM	= textureRAMPtr;
-}
-
-void CNew3D::SetStep(int stepID)
-{
-	m_step = stepID;
-
-	if ((m_step != 0x10) && (m_step != 0x15) && (m_step != 0x20) && (m_step != 0x21)) {
-		m_step = 0x10;
-	}
-
-	if (m_step > 0x10) {
-		m_offset = 0;							// culling nodes are 10 words
-		m_vertexFactor = (1.0f / 2048.0f);		// vertices are in 13.11 format
-	}
-	else {
-		m_offset = 2;							// 8 words
-		m_vertexFactor = (1.0f / 128.0f);		// 17.7
-	}
-
-	m_vbo.Create(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(Poly) * (MAX_RAM_POLYS + MAX_ROM_POLYS));
-}
-
-bool CNew3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXResParam, unsigned totalYResParam)
-{
-	// Resolution and offset within physical display area
-	m_xRatio	= xRes / 496.0f;
-	m_yRatio	= yRes / 384.0f;
-	m_xOffs		= xOffset;
-	m_yOffs		= yOffset;
-	m_totalXRes	= totalXResParam;
-	m_totalYRes = totalYResParam;
-
-	m_r3dShader.LoadShader();
-
-	glUseProgram(0);
-
-	return OKAY;	// OKAY ? wtf ..
-}
-
-void CNew3D::UploadTextures(unsigned x, unsigned y, unsigned width, unsigned height)
-{
-	m_texSheet.Invalidate(x, y, width, height);
-}
-
-void CNew3D::RenderScene(int priority, bool alpha)
-{
-	if (alpha) {
-		glEnable(GL_BLEND);
-	}
-
-	for (auto &n : m_nodes) {
-
-		if (n.viewport.priority != priority || n.models.empty()) {
-			continue;
-		}
-
-		glViewport		(n.viewport.x, n.viewport.y, n.viewport.width, n.viewport.height);
-		glMatrixMode	(GL_PROJECTION);
-		glLoadMatrixf	(n.viewport.projectionMatrix);
-		glMatrixMode	(GL_MODELVIEW);
-
-		m_r3dShader.SetViewportUniforms(&n.viewport);
-
-		for (auto &m : n.models) {
-
-			bool matrixLoaded = false;
-
-			if (m->meshes.empty()) {
-				continue;
-			}
-
-			m_r3dShader.SetModelStates(m.get());
-
-			for (auto &mesh : m->meshes) {
-
-				if (alpha) {
-					if (!mesh.textureAlpha && !mesh.polyAlpha) {
-						continue;
-					}
-				}
-				else {
-					if (mesh.textureAlpha || mesh.polyAlpha) {
-						continue;
-					}
-				}
-
-				if (!matrixLoaded) {
-					glLoadMatrixf(m->modelMat);
-					matrixLoaded = true;		// do this here to stop loading matrices we don't need. Ie when rendering non transparent etc
-				}
-				
-				if (mesh.textured) {
-					auto tex = m_texSheet.BindTexture(m_textureRAM, mesh.format, mesh.mirrorU, mesh.mirrorV, mesh.x, mesh.y, mesh.width, mesh.height);
-					if (tex) {
-						tex->BindTexture();
-						tex->SetWrapMode(mesh.mirrorU, mesh.mirrorV);
-					}
-				}
-				
-				m_r3dShader.SetMeshUniforms(&mesh);
-				glDrawArrays(GL_TRIANGLES, mesh.vboOffset*3, mesh.triangleCount*3);			// times 3 to convert triangles to vertices
-			}
-		}
-	}
-
-	glDisable(GL_BLEND);
-	glDepthMask(GL_TRUE);
-}
-
-void CNew3D::RenderFrame(void)
-{
-	// release any resources from last frame
-	m_polyBufferRam.clear();	// clear dyanmic model memory buffer
-	m_nodes.clear();		// memory will grow during the object life time, that's fine, no need to shrink to fit
-	m_modelMat.Release();	// would hope we wouldn't need this but no harm in checking
-	m_nodeAttribs.Reset();
-
-	glDepthFunc		(GL_LEQUAL);
-	glEnable		(GL_DEPTH_TEST);
-	glActiveTexture	(GL_TEXTURE0);
-	glEnable		(GL_CULL_FACE);
-	glFrontFace		(GL_CW);
-
-	for (int pri = 0; pri <= 3; pri++) {
-		RenderViewport(0x800000, pri);		// build model structure
-	}
-
-	m_vbo.Bind(true);
-	m_vbo.BufferSubData(MAX_ROM_POLYS*sizeof(Poly), m_polyBufferRam.size()*sizeof(Poly), m_polyBufferRam.data());	// upload all the dynamic data to GPU in one go
-
-	if (m_polyBufferRom.size()) {
-
-		// sync rom memory with vbo
-		int romBytes	= (int)m_polyBufferRom.size() * sizeof(Poly);
-		int vboBytes	= m_vbo.GetSize();
-		int size		= romBytes - vboBytes;
-
-		if (size) {
-			m_vbo.AppendData(size, &m_polyBufferRom[vboBytes / sizeof(Poly)]);
-		}
-	}
-	
-	glEnableClientState(GL_VERTEX_ARRAY);
-	glEnableClientState(GL_NORMAL_ARRAY);
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-	glEnableClientState(GL_COLOR_ARRAY);
-
-	// before draw, specify vertex and index arrays with their offsets, offsetof is maybe evil ..
-	glVertexPointer		(3, GL_FLOAT, sizeof(Vertex), 0);
-	glNormalPointer		(GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, normal));
-	glTexCoordPointer	(2, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, texcoords));
-	glColorPointer		(4, GL_UNSIGNED_BYTE, sizeof(Vertex), (void*)offsetof(Vertex, color));
-	
-	m_r3dShader.SetShader(true);
-
-	for (int pri = 0; pri <= 3; pri++) {
-		glClear		(GL_DEPTH_BUFFER_BIT);
-		RenderScene	(pri, false);
-		RenderScene	(pri, true);
-	}
-
-	m_r3dShader.SetShader(false);		// unbind shader
-	m_vbo.Bind(false);
-
-	glDisable(GL_CULL_FACE);
-	glDisableClientState(GL_VERTEX_ARRAY);
-	glDisableClientState(GL_NORMAL_ARRAY);
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-	glDisableClientState(GL_COLOR_ARRAY);
-}
-
-void CNew3D::BeginFrame(void)
-{
-}
-
-void CNew3D::EndFrame(void)
-{
-}
-
-/******************************************************************************
-Real3D Address Translation
-
-Functions that interpret word-granular Real3D addresses and return pointers.
-******************************************************************************/
-
-// Translates 24-bit culling RAM addresses
-const UINT32* CNew3D::TranslateCullingAddress(UINT32 addr)
-{
-	addr &= 0x00FFFFFF;	// caller should have done this already
-
-	if ((addr >= 0x800000) && (addr < 0x840000)) {
-		return &m_cullingRAMHi[addr & 0x3FFFF];
-	}
-	else if (addr < 0x100000) {
-		return &m_cullingRAMLo[addr];
-	}
-
-	return NULL;
-}
-
-// Translates model references
-const UINT32* CNew3D::TranslateModelAddress(UINT32 modelAddr)
-{
-	modelAddr &= 0x00FFFFFF;	// caller should have done this already
-
-	if (modelAddr < 0x100000) {
-		return &m_polyRAM[modelAddr];
-	}
-	else {
-		return &m_vrom[modelAddr];
-	}
-}
-
-bool CNew3D::DrawModel(UINT32 modelAddr)
-{
-	const UINT32*			modelAddress;
-	std::shared_ptr<Model>	m;
-	bool					cached = false;
-
-	modelAddress = TranslateModelAddress(modelAddr);
-
-	// create a new model to push onto the vector
-	//m_nodes.back().models.emplace_back(Model());
-
-	if (IsVROMModel(modelAddr) && !IsDynamicModel((UINT32*)modelAddress)) {
-
-		// try to find the model in our cache
-
-		auto key = GetRomMapKey(modelAddr, m_nodeAttribs.currentTexOffset);
-
-		if (m_romMap.count(key)) {
-			m = m_romMap[key];		// probably better using a shared_ptr instead of copying, but for now it'll do
-			cached	= true;
-		}
-		else {
-			m = std::make_shared<Model>();
-			m->dynamic = false;
-			m_romMap[key] = m;		// store model in our rom map here
-		}
-	}
-	else {
-		m = std::make_shared<Model>();
-	}
-
-	// copy model matrix
-	for (int i = 0; i < 16; i++) {
-		m->modelMat[i] = m_modelMat.currentMatrix[i];
-	}
-
-	//calculate determinant
-	m->determinant = Determinant3x3(m_modelMat);
-
-	if (!cached) {
-		CacheModel(m.get(), modelAddress);
-	}
-
-	m_nodes.back().models.push_back(m);		// add model to scene
-
-	return true;
-}
-
-// Descends into a 10-word culling node
-void CNew3D::DescendCullingNode(UINT32 addr)
-{
-	const UINT32	*node, *lodTable;
-	UINT32			matrixOffset, node1Ptr, node2Ptr;
-	float			x, y, z;
-	int				tx, ty;
-
-	if (m_nodeAttribs.StackLimit()) {
-		return;
-	}
-
-	node = TranslateCullingAddress(addr);
-
-	if (NULL == node) {
-		return;
-	}
-
-	// Extract known fields
-	node1Ptr		= node[0x07 - m_offset];
-	node2Ptr		= node[0x08 - m_offset];
-	matrixOffset	= node[0x03 - m_offset] & 0xFFF;
-
-	x = *(float *)&node[0x04 - m_offset];	// magic numbers everywhere !
-	y = *(float *)&node[0x05 - m_offset];
-	z = *(float *)&node[0x06 - m_offset];
-
-	m_nodeAttribs.Push();	// save current attribs
-
-	if (!m_offset)	// Step 1.5+
-	{
-		tx = 32 * ((node[0x02] >> 7) & 0x3F);
-		ty = 32 * (node[0x02] & 0x3F) + ((node[0x02] & 0x4000) ? 1024 : 0);	// TODO: 5 or 6 bits for Y coord?
-
-		// apply texture offsets, else retain current ones
-		if ((node[0x02] & 0x8000))	{
-			m_nodeAttribs.currentTexOffsetX = tx;
-			m_nodeAttribs.currentTexOffsetY = ty;
-			m_nodeAttribs.currentTexOffset	= node[0x02] & 0x7FFF;
-		}
-	}
-
-	// Apply matrix and translation
-	m_modelMat.PushMatrix();
-
-	// apply translation vector
-	if ((node[0x00] & 0x10)) {
-		m_modelMat.Translate(x, y, z);
-	}
-	// multiply matrix, if specified
-	else if (matrixOffset) {
-		MultMatrix(matrixOffset,m_modelMat);
-	}		
-
-	// Descend down first link
-	if ((node[0x00] & 0x08))	// 4-element LOD table
-	{
-		lodTable = TranslateCullingAddress(node1Ptr);
-
-		if (NULL != lodTable) {
-			if ((node[0x03 - m_offset] & 0x20000000)) {
-				DescendCullingNode(lodTable[0] & 0xFFFFFF);
-			}
-			else {
-				DrawModel(lodTable[0] & 0xFFFFFF);	//TODO
-			}
-		}
-	}
-	else {
-		DescendNodePtr(node1Ptr);
-	}
-
-	// Proceed to second link
-	m_modelMat.PopMatrix();
-
-	// seems to indicate second link is invalid (fixes circular references)
-	if ((node[0x00] & 0x07) != 0x06) {
-		DescendNodePtr(node2Ptr);
-	}
-
-	// Restore old texture offsets
-	m_nodeAttribs.Pop();
-}
-
-void CNew3D::DescendNodePtr(UINT32 nodeAddr)
-{
-	// Ignore null links
-	if ((nodeAddr & 0x00FFFFFF) == 0) {
-		return;
-	}
-
-	switch ((nodeAddr >> 24) & 0xFF)	// pointer type encoded in upper 8 bits
-	{
-	case 0x00:	// culling node
-		DescendCullingNode(nodeAddr & 0xFFFFFF);
-		break;
-	case 0x01:	// model (perhaps bit 1 is a flag in this case?)
-	case 0x03:
-		DrawModel(nodeAddr & 0xFFFFFF);
-		break;
-	case 0x04:	// pointer list
-		DescendPointerList(nodeAddr & 0xFFFFFF);
-		break;
-	default:
-		//printf("ATTENTION: Unknown pointer format: %08X\n\n", nodeAddr);
-		break;
-	}
-}
-
-void CNew3D::DescendPointerList(UINT32 addr)
-{
-	const UINT32*	list;
-	UINT32			nodeAddr;
-	int				listEnd;
-
-	if (m_listDepth > 2) {	// several Step 2.1 games require this safeguard
-		return;
-	}
-
-	list = TranslateCullingAddress(addr);
-
-	if (NULL == list) {
-		return;
-	}
-
-	m_listDepth++;
-
-	// Traverse the list forward and print it out
-	listEnd = 0;
-
-	while (1)
-	{
-		if ((list[listEnd] & 0x02000000)) {	// end of list (?)
-			break;
-		}
-
-		if ((list[listEnd] == 0) || (((list[listEnd]) >> 24) != 0)) {
-			listEnd--;	// back up to last valid list element
-			break;
-		}
-
-		listEnd++;
-	}
-
-	for (int i = 0; i <= listEnd; i++) {
-
-		nodeAddr = list[i] & 0x00FFFFFF;	// clear upper 8 bits to ensure this is processed as a culling node
-
-		if (!(list[i] & 0x01000000)) {	//Fighting Vipers
-
-			if ((nodeAddr != 0) && (nodeAddr != 0x800800)) {
-				DescendCullingNode(nodeAddr);
-			}
-		}
-	}
-
-
-	/*
-	// Traverse the list backward and descend into each pointer
-	while (listEnd >= 0)
-	{
-		nodeAddr = list[listEnd] & 0x00FFFFFF;	// clear upper 8 bits to ensure this is processed as a culling node
-
-		if (!(list[listEnd] & 0x01000000)) {	//Fighting Vipers
-			
-			if ((nodeAddr != 0) && (nodeAddr != 0x800800)) {
-				DescendCullingNode(nodeAddr);
-			}
-		}
-
-		listEnd--;
-	}
-	*/
-
-	m_listDepth--;
-}
-
-
-/******************************************************************************
-Matrix Stack
-******************************************************************************/
-
-// Macro to generate column-major (OpenGL) index from y,x subscripts
-#define CMINDEX(y,x)	(x*4+y)
-
-/*
-* MultMatrix():
-*
-* Multiplies the matrix stack by the specified Real3D matrix. The matrix
-* index is a 12-bit number specifying a matrix number relative to the base.
-* The base matrix MUST be set up before calling this function.
-*/
-void CNew3D::MultMatrix(UINT32 matrixOffset, Mat4& mat)
-{
-	GLfloat		m[4*4];
-	const float	*src = &m_matrixBasePtr[matrixOffset * 12];
-
-	if (m_matrixBasePtr == NULL)	// LA Machineguns
-		return;
-
-	m[CMINDEX(0, 0)] = src[3];
-	m[CMINDEX(0, 1)] = src[4];
-	m[CMINDEX(0, 2)] = src[5];
-	m[CMINDEX(0, 3)] = src[0];
-	m[CMINDEX(1, 0)] = src[6];
-	m[CMINDEX(1, 1)] = src[7];
-	m[CMINDEX(1, 2)] = src[8];
-	m[CMINDEX(1, 3)] = src[1];
-	m[CMINDEX(2, 0)] = src[9];
-	m[CMINDEX(2, 1)] = src[10];
-	m[CMINDEX(2, 2)] = src[11];
-	m[CMINDEX(2, 3)] = src[2];
-	m[CMINDEX(3, 0)] = 0.0;
-	m[CMINDEX(3, 1)] = 0.0;
-	m[CMINDEX(3, 2)] = 0.0;
-	m[CMINDEX(3, 3)] = 1.0;
-
-	mat.MultMatrix(m);
-}
-
-/*
-* InitMatrixStack():
-*
-* Initializes the modelview (model space -> view space) matrix stack and
-* Real3D coordinate system. These are the last transforms to be applied (and
-* the first to be defined on the stack) before projection.
-*
-* Model 3 games tend to define the following unusual base matrix:
-*
-*		0	0	-1	0
-*		1	0	0	0
-*		0	-1	0	0
-*		0	0	0	1
-*
-* When this is multiplied by a column vector, the output is:
-*
-*		-Z
-*		X
-*		-Y
-*		1
-*
-* My theory is that the Real3D GPU accepts vectors in Z,X,Y order. The games
-* store everything as X,Y,Z and perform the translation at the end. The Real3D
-* also has Y and Z coordinates opposite of the OpenGL convention. This
-* function inserts a compensating matrix to undo these things.
-*
-* NOTE: This function assumes we are in GL_MODELVIEW matrix mode.
-*/
-
-void CNew3D::InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat)
-{
-	GLfloat m[4 * 4];
-
-	// This matrix converts vectors back from the weird Model 3 Z,X,Y ordering
-	// and also into OpenGL viewspace (-Y,-Z)
-	m[CMINDEX(0, 0)] = 0.0;	m[CMINDEX(0, 1)] = 1.0;	m[CMINDEX(0, 2)] = 0.0;	m[CMINDEX(0, 3)] = 0.0;
-	m[CMINDEX(1, 0)] = 0.0;	m[CMINDEX(1, 1)] = 0.0;	m[CMINDEX(1, 2)] =-1.0; m[CMINDEX(1, 3)] = 0.0;
-	m[CMINDEX(2, 0)] =-1.0; m[CMINDEX(2, 1)] = 0.0;	m[CMINDEX(2, 2)] = 0.0;	m[CMINDEX(2, 3)] = 0.0;
-	m[CMINDEX(3, 0)] = 0.0;	m[CMINDEX(3, 1)] = 0.0;	m[CMINDEX(3, 2)] = 0.0;	m[CMINDEX(3, 3)] = 1.0;
-
-	if (m_step > 0x10) {
-		mat.LoadMatrix(m);
-	}
-	else {
-		// Scaling seems to help w/ Step 1.0's extremely large coordinates
-		GLfloat s = 1.0f / 2048.0f;	// this will fuck up normals
-		mat.LoadIdentity();
-		mat.Scale(s, s, s);
-		mat.MultMatrix(m);
-	}
-
-	// Set matrix base address and apply matrix #0 (coordinate system matrix)
-	m_matrixBasePtr = (float *)TranslateCullingAddress(matrixBaseAddr);
-	MultMatrix(0, mat);
-}
-
-// Draws viewports of the given priority
-void CNew3D::RenderViewport(UINT32 addr, int pri)
-{
-	GLfloat	color[8][3] =	// RGB1 translation
-	{
-		{ 0.0, 0.0, 0.0 },	// off
-		{ 0.0, 0.0, 1.0 },	// blue
-		{ 0.0, 1.0, 0.0 },	// green
-		{ 0.0, 1.0, 1.0 },	// cyan
-		{ 1.0, 0.0, 0.0 }, 	// red
-		{ 1.0, 0.0, 1.0 },	// purple
-		{ 1.0, 1.0, 0.0 },	// yellow
-		{ 1.0, 1.0, 1.0 }	// white
-	};
-	const UINT32	*vpnode;
-	UINT32			nextAddr, nodeAddr, matrixBase;
-	int				curPri;
-	int				vpX, vpY, vpWidth, vpHeight;
-	int				spotColorIdx;
-	GLfloat			vpTopAngle, vpBotAngle, fovYDegrees;
-	GLfloat			scrollFog, scrollAtt;
-	Viewport*		vp;
-
-	// Translate address and obtain pointer
-	vpnode = TranslateCullingAddress(addr);
-
-	if (NULL == vpnode) {
-		return;
-	}
-
-	curPri		= (vpnode[0x00] >> 3) & 3;	// viewport priority
-	nextAddr	= vpnode[0x01] & 0xFFFFFF;	// next viewport
-	nodeAddr	= vpnode[0x02];				// scene database node pointer
-
-	// Recursively process next viewport
-	if (vpnode[0x01] == 0) {				// memory probably hasn't been set up yet, abort
-		return;
-	}
-	if (vpnode[0x01] != 0x01000000) {
-		RenderViewport(vpnode[0x01], pri);
-	}
-
-	// If the priority doesn't match, do not process
-	if (curPri != pri) {
-		return;
-	}
-
-	// create node object 
-	m_nodes.emplace_back(Node());
-	m_nodes.back().models.reserve(2048);			// create space for models
-
-	// get pointer to its viewport
-	vp = &m_nodes.back().viewport;
-
-	vp->priority = pri;
-
-	// Fetch viewport parameters (TO-DO: would rounding make a difference?)
-	vpX			= (vpnode[0x1A] & 0xFFFF) >> 4;		// viewport X (12.4 fixed point)
-	vpY			= (vpnode[0x1A] >> 20) & 0xFFF;		// viewport Y (12.4)
-	vpWidth		= (vpnode[0x14] & 0xFFFF) >> 2;		// width (14.2)
-	vpHeight	= (vpnode[0x14] >> 18) & 0x3FFF;	// height (14.2)
-	matrixBase	= vpnode[0x16] & 0xFFFFFF;		// matrix base address
-
-	// Field of view and clipping
-	vpTopAngle	= (float)asin(*(float *)&vpnode[0x0E]);	// FOV Y upper half-angle (radians)
-	vpBotAngle	= (float)asin(*(float *)&vpnode[0x12]);	// FOV Y lower half-angle
-	fovYDegrees	= (vpTopAngle + vpBotAngle)*(float)(180.0 / 3.14159265358979323846);
-
-	// TO-DO: investigate clipping planes
-
-	//if (g_Config.wideScreen && (vpX == 0) && (vpWidth >= 495) && (vpY == 0) && (vpHeight >= 383))		// only expand viewports that occupy whole screen
-	//if (0)
-	if ((vpX == 0) && (vpWidth >= 495) && (vpY == 0) && (vpHeight >= 383))
-	{
-		// Wide screen hack only modifies X axis and not the Y FOV
-		vp->x		= 0;
-		vp->y		= m_yOffs + (GLint)((float)(384 - (vpY + vpHeight))*m_yRatio);
-		vp->width	= m_totalXRes;
-		vp->height	= (GLint)((float)vpHeight*m_yRatio);
-
-		vp->projectionMatrix.Perspective(fovYDegrees, (GLfloat)vp->width / (GLfloat)vp->height, 0.1f, 1e5);	// use actual full screen ratio to get proper X FOV
-	}
-	else
-	{
-		vp->x		= m_xOffs + (GLint)((float)vpX*m_xRatio);
-		vp->y		= m_yOffs + (GLint)((float)(384 - (vpY + vpHeight))*m_yRatio);
-		vp->width	= (GLint)((float)vpWidth*m_xRatio);
-		vp->height	= (GLint)((float)vpHeight*m_yRatio);
-
-		vp->projectionMatrix.Perspective(fovYDegrees, (GLfloat)vpWidth / (GLfloat)vpHeight, 0.1f, 1e5);		// use Model 3 viewport ratio
-	}
-
-	// Lighting (note that sun vector points toward sun -- away from vertex)
-	vp->lightingParams[0] = *(float *)&vpnode[0x05];								// sun X
-	vp->lightingParams[1] = *(float *)&vpnode[0x06];								// sun Y
-	vp->lightingParams[2] = *(float *)&vpnode[0x04];								// sun Z
-	vp->lightingParams[3] = *(float *)&vpnode[0x07];								// sun intensity
-	vp->lightingParams[4] = (float)((vpnode[0x24] >> 8) & 0xFF) * (1.0f / 255.0f);	// ambient intensity
-	vp->lightingParams[5] = 0.0;	// reserved
-
-	// Spotlight
-	spotColorIdx = (vpnode[0x20] >> 11) & 7;					// spotlight color index
-	vp->spotEllipse[0] = (float)((vpnode[0x1E] >> 3) & 0x1FFF);	// spotlight X position (fractional component?)
-	vp->spotEllipse[1] = (float)((vpnode[0x1D] >> 3) & 0x1FFF);	// spotlight Y
-	vp->spotEllipse[2] = (float)((vpnode[0x1E] >> 16) & 0xFFFF);	// spotlight X size (16-bit? May have fractional component below bit 16)
-	vp->spotEllipse[3] = (float)((vpnode[0x1D] >> 16) & 0xFFFF);	// spotlight Y size
-
-	vp->spotRange[0] = 1.0f / (*(float *)&vpnode[0x21]);		// spotlight start
-	vp->spotRange[1] = *(float *)&vpnode[0x1F];				// spotlight extent
-	vp->spotColor[0] = color[spotColorIdx][0];				// spotlight color
-	vp->spotColor[1] = color[spotColorIdx][1];
-	vp->spotColor[2] = color[spotColorIdx][2];
-
-	// Spotlight is applied on a per pixel basis, must scale its position and size to screen
-	vp->spotEllipse[1] = 384.0f - vp->spotEllipse[1];
-	vp->spotRange[1] += vp->spotRange[0];	// limit
-	vp->spotEllipse[2] = 496.0f / sqrt(vp->spotEllipse[2]);	// spotlight appears to be specified in terms of physical resolution (unconfirmed)
-	vp->spotEllipse[3] = 384.0f / sqrt(vp->spotEllipse[3]);
-
-	// Scale the spotlight to the OpenGL viewport
-	vp->spotEllipse[0] = vp->spotEllipse[0] * m_xRatio + m_xOffs;
-	vp->spotEllipse[1] = vp->spotEllipse[1] * m_yRatio + m_yOffs;
-	vp->spotEllipse[2] *= m_xRatio;
-	vp->spotEllipse[3] *= m_yRatio;
-
-	// Fog
-	vp->fogParams[0] = (float)((vpnode[0x22] >> 16) & 0xFF) * (1.0f / 255.0f);	// fog color R
-	vp->fogParams[1] = (float)((vpnode[0x22] >> 8) & 0xFF) * (1.0f / 255.0f);	// fog color G
-	vp->fogParams[2] = (float)((vpnode[0x22] >> 0) & 0xFF) * (1.0f / 255.0f);	// fog color B
-	vp->fogParams[3] = *(float *)&vpnode[0x23];									// fog density
-	vp->fogParams[4] = (float)(INT16)(vpnode[0x25] & 0xFFFF)*(1.0f / 255.0f);	// fog start
-
-	
-	if (std::isinf(vp->fogParams[3]) || std::isnan(vp->fogParams[3]) || std::isinf(vp->fogParams[4]) || std::isnan(vp->fogParams[4])) {	// Star Wars Trilogy
-		vp->fogParams[3] = vp->fogParams[4] = 0.0f;
-	}
-
-	// Unknown light/fog parameters
-	scrollFog = (float)(vpnode[0x20] & 0xFF) * (1.0f / 255.0f);	// scroll fog
-	scrollAtt = (float)(vpnode[0x24] & 0xFF) * (1.0f / 255.0f);	// scroll attenuation
-
-	// Clear texture offsets before proceeding
-	m_nodeAttribs.Reset();
-
-	// Set up coordinate system and base matrix
-	InitMatrixStack(matrixBase, m_modelMat);
-
-	// Safeguard: weird coordinate system matrices usually indicate scenes that will choke the renderer
-	if (NULL != m_matrixBasePtr)
-	{
-		float	m21, m32, m13;
-
-		// Get the three elements that are usually set and see if their magnitudes are 1
-		m21 = m_matrixBasePtr[6];
-		m32 = m_matrixBasePtr[10];
-		m13 = m_matrixBasePtr[5];
-
-		m21 *= m21;
-		m32 *= m32;
-		m13 *= m13;
-
-		if ((m21>1.05) || (m21<0.95))
-			return;
-		if ((m32>1.05) || (m32<0.95))
-			return;
-		if ((m13>1.05) || (m13<0.95))
-			return;
-	}
-
-	m_listDepth = 0;
-
-	// Descend down the node link: Use recursive traversal
-	DescendNodePtr(nodeAddr);
-}
-
-void CNew3D::CopyVertexData(R3DPoly& r3dPoly, std::vector<Poly>& polyArray)
-{
-	//====================
-	Poly		p;
-	V3::Vec3	normal;
-	float		dotProd;
-	bool		clockWise;
-	//====================
-
-	V3::createNormal(r3dPoly.v[0].pos, r3dPoly.v[1].pos, r3dPoly.v[2].pos, normal);
-
-	dotProd		= V3::dotProduct(normal, r3dPoly.faceNormal);
-	clockWise	= dotProd >= 0.0;
-
-	if (clockWise) {
-		p.p1 = r3dPoly.v[0];
-		p.p2 = r3dPoly.v[1];
-		p.p3 = r3dPoly.v[2];
-	}
-	else {
-		p.p1 = r3dPoly.v[2];
-		p.p2 = r3dPoly.v[1];
-		p.p3 = r3dPoly.v[0];
-	}
-	
-	polyArray.emplace_back(p);
-
-	if (r3dPoly.number == 4) {
-
-		if (clockWise) {
-			p.p1 = r3dPoly.v[0];
-			p.p2 = r3dPoly.v[2];
-			p.p3 = r3dPoly.v[3];
-		}
-		else {
-			p.p1 = r3dPoly.v[0];
-			p.p2 = r3dPoly.v[3];
-			p.p3 = r3dPoly.v[2];
-		}
-
-		polyArray.emplace_back(p);
-	}
-}
-
-void CNew3D::CacheModel(Model *m, const UINT32 *data)
-{
-	Vertex			prev[4];
-	PolyHeader		ph;
-	int				numPolys	= 0;
-	bool			done		= false;
-	UINT64			lastHash	= -1;
-	SortingMesh*	currentMesh = nullptr;
-	
-	std::shared_ptr<Texture> tex;
-	std::map<UINT64, SortingMesh> sMap;
-
-	if (data == NULL)
-		return;
-
-	ph = data; 
-	int numTriangles = ph.NumTrianglesTotal();
-
-	// Cache all polygons
-	while (!done)
-	{
-		R3DPoly		p;					// current polygon
-		GLfloat		uvScale;
-		int			i, j;
-		bool		validPoly = true;
-
-		ph = data;
-
-		if (ph.header[6] == 0) {
-			break;
-		}
-
-		if ((ph.header[0] & 0x100) && (ph.header[0] & 0x200)) {	// assuming these two bits mean z and colour writes are disabled
-			validPoly = false;
-		}
-		else {
-			if (!numPolys && (ph.NumSharedVerts() != 0)) {			// sharing vertices, but we haven't started the model yet
-				printf("incomplete data\n");
-				validPoly = false;
-			}
-		}
-
-		// Set current header pointer (header is 7 words)
-		data += 7;	// data will now point to first vertex
-
-		// create a hash value based on poly attributes -todo add more attributes
-		auto hash = ph.Hash(m_nodeAttribs.currentTexOffsetX, m_nodeAttribs.currentTexOffsetY);
-
-		if (hash != lastHash && validPoly) {
-
-			if (sMap.count(hash) == 0) {
-
-				sMap[hash] = SortingMesh();
-
-				currentMesh = &sMap[hash];
-
-				//make space for our vertices
-				currentMesh->polys.reserve(numTriangles);
-
-				//copy attributes
-				currentMesh->doubleSided	= ph.DoubleSided();
-				currentMesh->textured		= ph.TexEnabled();
-				currentMesh->alphaTest		= ph.AlphaTest();
-				currentMesh->textureAlpha	= ph.TextureAlpha();
-				currentMesh->polyAlpha		= ph.PolyAlpha();
-				currentMesh->lighting		= ph.LightEnabled();
-
-				if (!ph.Luminous()) {
-					currentMesh->fogIntensity = 1.0f;
-				}
-				else {
-					currentMesh->fogIntensity = ph.LightModifier();
-				}
-
-				if (ph.TexEnabled()) {
-					currentMesh->format		= ph.TexFormat();
-					currentMesh->x			= ph.X(m_nodeAttribs.currentTexOffsetX);
-					currentMesh->y			= ph.Y(m_nodeAttribs.currentTexOffsetX);
-					currentMesh->width		= ph.TexWidth();
-					currentMesh->height		= ph.TexHeight();
-					currentMesh->mirrorU	= ph.TexUMirror();
-					currentMesh->mirrorV	= ph.TexVMirror();
-					tex = m_texSheet.BindTexture(m_textureRAM, ph.TexFormat(), ph.TexUMirror(), ph.TexVMirror(), ph.X(m_nodeAttribs.currentTexOffsetX), ph.Y(m_nodeAttribs.currentTexOffsetY), ph.TexWidth(), ph.TexHeight());
-				}
-			}
-
-			currentMesh = &sMap[hash];
-
-			if (ph.TexEnabled()) {
-				tex = m_texSheet.BindTexture(m_textureRAM, ph.TexFormat(), ph.TexUMirror(), ph.TexVMirror(), ph.X(m_nodeAttribs.currentTexOffsetX), ph.Y(m_nodeAttribs.currentTexOffsetY), ph.TexWidth(), ph.TexHeight());
-			}
-			else {
-				tex = nullptr;
-			}
-		}
-
-		if (validPoly) {
-			lastHash = hash;
-		}
-
-		// Obtain basic polygon parameters
-		done		= ph.LastPoly();
-		p.number	= ph.NumVerts();
-		uvScale		= ph.UVScale();
-
-		ph.FaceNormal(p.faceNormal);
-
-		// Fetch reused vertices according to bitfield, then new verts
-		i = 0;
-		j = 0;
-		for (i = 0; i < 4; i++)		// up to 4 reused vertices
-		{
-			if (ph.SharedVertex(i))
-			{
-				p.v[j] = prev[i];
-				++j;
-			}
-		}
-
-		for (; j < p.number; j++)	// remaining vertices are new and defined here
-		{
-			// Fetch vertices
-			UINT32 ix = data[0];
-			UINT32 iy = data[1];
-			UINT32 iz = data[2];
-			UINT32 it = data[3];
-
-			// Decode vertices
-			p.v[j].pos[0] = (GLfloat)(((INT32)ix) >> 8) * m_vertexFactor;
-			p.v[j].pos[1] = (GLfloat)(((INT32)iy) >> 8) * m_vertexFactor;
-			p.v[j].pos[2] = (GLfloat)(((INT32)iz) >> 8) * m_vertexFactor;
-
-			p.v[j].normal[0] = p.faceNormal[0] + (GLfloat)(INT8)(ix & 0xFF);	// vertex normals are offset from polygon normal - we can normalise them in the shader
-			p.v[j].normal[1] = p.faceNormal[1] + (GLfloat)(INT8)(iy & 0xFF);
-			p.v[j].normal[2] = p.faceNormal[2] + (GLfloat)(INT8)(iz & 0xFF);
-
-			if ((ph.header[1] & 2) == 0) {
-				UINT32 colorIdx = ((ph.header[4] >> 20) & 0x7FF);
-				p.v[j].color[0] = (m_polyRAM[0x400 + colorIdx] & 0xFF);
-				p.v[j].color[1] = (m_polyRAM[0x400 + colorIdx] >> 8) & 0xFF;
-				p.v[j].color[2] = (m_polyRAM[0x400 + colorIdx] >> 16) & 0xFF;
-			}
-			else if (ph.FixedShading()) {
-				UINT8 shade = ph.ShadeValue();
-				p.v[j].color[0] = shade;
-				p.v[j].color[1] = shade;
-				p.v[j].color[2] = shade;
-			}
-			else {
-				p.v[j].color[0] = (ph.header[4] >> 24);
-				p.v[j].color[1] = (ph.header[4] >> 16) & 0xFF;
-				p.v[j].color[2] = (ph.header[4] >> 8) & 0xFF;
-			}
-
-			if ((ph.header[6] & 0x00800000)) {	// if set, polygon is opaque
-				p.v[j].color[3] = 255;
-			}
-			else {
-				p.v[j].color[3] = ph.Transparency();
-			}
-
-			float texU, texV = 0;
-
-			// tex coords
-			if (tex) {
-				tex->GetCoordinates((UINT16)(it >> 16), (UINT16)(it & 0xFFFF), uvScale, texU, texV);
-			}
-
-			p.v[j].texcoords[0] = texU;
-			p.v[j].texcoords[1] = texV;
-
-			data += 4;
-		}
-
-		// Copy current vertices into previous vertex array
-		for (i = 0; i < 4 && validPoly; i++) {
-			prev[i] = p.v[i];
-		}
-
-		// Copy this polygon into the model buffer
-		if (validPoly) {
-			CopyVertexData(p, currentMesh->polys);
-			numPolys++;
-		}
-	}
-
-	//sorted the data, now copy to main data structures
-
-	// we know how many meshes we have so reserve appropriate space
-	m->meshes.reserve(sMap.size());
-
-	for (auto& it : sMap) {
-
-		if (m->dynamic) {
-
-			// calculate VBO values for current mesh
-			it.second.vboOffset		= m_polyBufferRam.size() + MAX_ROM_POLYS;
-			it.second.triangleCount = it.second.polys.size();
-
-			// copy poly data to main buffer
-			m_polyBufferRam.insert(m_polyBufferRam.end(), it.second.polys.begin(), it.second.polys.end());
-		}
-		else {
-			// calculate VBO values for current mesh
-			it.second.vboOffset = m_polyBufferRom.size();
-			it.second.triangleCount = it.second.polys.size();
-
-			// copy poly data to main buffer
-			m_polyBufferRom.insert(m_polyBufferRom.end(), it.second.polys.begin(), it.second.polys.end());
-		}
-
-		//copy the temp mesh into the model structure
-		//this will lose the associated vertex data, which is now copied to the main buffer anyway
-		m->meshes.push_back(it.second);
-	}
-}
-
-float CNew3D::Determinant3x3(const float m[16]) {
-
-	/*
-		| A B C |
-	M = | D E F |
-		| G H I |
-
-	then the determinant is calculated as follows:
-
-	det M = A * (EI - HF) - B * (DI - GF) + C * (DH - GE)
-	*/
-
-	return m[0] * ((m[5] * m[10]) - (m[6] * m[9])) - m[4] * ((m[1] * m[10]) - (m[2] * m[9])) + m[8] * ((m[1] * m[6]) - (m[2] * m[5]));
-}
-
-bool CNew3D::IsDynamicModel(UINT32 *data)
-{
-	if (data == NULL) {
-		return false;
-	}
-
-	PolyHeader p(data);
-
-	do {
-
-		if ((p.header[1] & 2) == 0) {		// model has rgb colour palette 
-			return true;
-		}
-
-		if (p.header[6] == 0) {
-			break;
-		}
-
-	} while (p.NextPoly());
-
-	return false;
-}
-
-bool CNew3D::IsVROMModel(UINT32 modelAddr)
-{
-	return modelAddr >= 0x100000;
-}
-
-UINT64 CNew3D::GetRomMapKey(int address, int texOffset)
-{
-	return (UINT64)address << 32 | texOffset;
-}
-
-} // New3D
diff --git a/Src/Graphics/New3D/backup/static model attempt 1/New3D.h b/Src/Graphics/New3D/backup/static model attempt 1/New3D.h
deleted file mode 100644
index 065b342..0000000
--- a/Src/Graphics/New3D/backup/static model attempt 1/New3D.h	
+++ /dev/null
@@ -1,221 +0,0 @@
-/**
-** Supermodel
-** A Sega Model 3 Arcade Emulator.
-** Copyright 2011 Bart Trzynadlowski, Nik Henson
-**
-** This file is part of Supermodel.
-**
-** Supermodel is free software: you can redistribute it and/or modify it under
-** the terms of the GNU General Public License as published by the Free
-** Software Foundation, either version 3 of the License, or (at your option)
-** any later version.
-**
-** Supermodel is distributed in the hope that it will be useful, but WITHOUT
-** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-** FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-** more details.
-**
-** You should have received a copy of the GNU General Public License along
-** with Supermodel.  If not, see <http://www.gnu.org/licenses/>.
-**/
-
-/*
-* New3D.h
-*
-* Header file defining the CNew3D class: OpenGL Real3D graphics engine.
-*/
-
-#ifndef INCLUDED_NEW3D_H
-#define INCLUDED_NEW3D_H
-
-#include "Pkgs/glew.h"
-#include "Types.h"
-#include "TextureSheet.h"
-#include "Graphics/IRender3D.h"
-#include "Model.h"
-#include "Mat4.h"
-#include "R3DShader.h"
-#include "VBO.h"
-
-namespace New3D {
-
-class CNew3D : public IRender3D
-{
-public:
-	/*
-	* RenderFrame(void):
-	*
-	* Renders the complete scene database. Must be called between BeginFrame() and
-	* EndFrame(). This function traverses the scene database and builds up display
-	* lists.
-	*/
-	void RenderFrame(void);
-
-	/*
-	* BeginFrame(void):
-	*
-	* Prepare to render a new frame. Must be called once per frame prior to
-	* drawing anything.
-	*/
-	void BeginFrame(void);
-
-	/*
-	* EndFrame(void):
-	*
-	* Signals the end of rendering for this frame. Must be called last during
-	* the frame.
-	*/
-	void EndFrame(void);
-
-	/*
-	* UploadTextures(x, y, width, height):
-	*
-	* Signals that a portion of texture RAM has been updated.
-	*
-	* Parameters:
-	*		x		X position within texture RAM.
-	*		y		Y position within texture RAM.
-	*		width	Width of texture data in texels.
-	*		height	Height.
-	*/
-	void UploadTextures(unsigned x, unsigned y, unsigned width, unsigned height);
-
-	/*
-	* AttachMemory(cullingRAMLoPtr, cullingRAMHiPtr, polyRAMPtr, vromPtr,
-	* 				textureRAMPtr):
-	*
-	* Attaches RAM and ROM areas. This must be done prior to any rendering
-	* otherwise the program may crash with an access violation.
-	*
-	* Parameters:
-	*		cullingRAMLoPtr		Pointer to low culling RAM (4 MB).
-	*		cullingRAMHiPtr		Pointer to high culling RAM (1 MB).
-	*		polyRAMPtr			Pointer to polygon RAM (4 MB).
-	*		vromPtr				Pointer to video ROM (64 MB).
-	*		textureRAMPtr		Pointer to texture RAM (8 MB).
-	*/
-	void AttachMemory(const UINT32 *cullingRAMLoPtr,
-		const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr,
-		const UINT32 *vromPtr, const UINT16 *textureRAMPtr);
-
-	/*
-	* SetStep(stepID):
-	*
-	* Sets the Model 3 hardware stepping, which also determines the Real3D
-	* functionality. The default is Step 1.0. This should be called prior to
-	* any other emulation functions and after Init().
-	*
-	* Parameters:
-	*		stepID	0x10 for Step 1.0, 0x15 for Step 1.5, 0x20 for Step 2.0,
-	*				or 0x21 for Step 2.1. Anything else defaults to 1.0.
-	*/
-	void SetStep(int stepID);
-
-	/*
-	* Init(xOffset, yOffset, xRes, yRes, totalXRes, totalYRes):
-	*
-	* One-time initialization of the context. Must be called before any other
-	* members (meaning it should be called even before being attached to any
-	* other objects that want to use it).
-	*
-	* External shader files are loaded according to configuration settings.
-	*
-	* Parameters:
-	*		xOffset		X offset of the viewable area within OpenGL display
-	*                  surface, in pixels.
-	*		yOffset		Y offset.
-	*		xRes		Horizontal resolution of the viewable area.
-	*		yRes		Vertical resolution.
-	*		totalXRes	Horizontal resolution of the complete display area.
-	*		totalYRes	Vertical resolution.
-	*
-	* Returns:
-	*		OKAY is successful, otherwise FAILED if a non-recoverable error
-	*		occurred. Any allocated memory will not be freed until the
-	*		destructor is called. Prints own error messages.
-	*/
-	bool Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXRes, unsigned totalYRes);
-
-	/*
-	* CRender3D(void):
-	* ~CRender3D(void):
-	*
-	* Constructor and destructor.
-	*/
-	CNew3D(void);
-	~CNew3D(void);
-
-private:
-	/*
-	* Private Members
-	*/
-
-	// Real3D address translation
-	const UINT32 *TranslateCullingAddress(UINT32 addr);
-	const UINT32 *TranslateModelAddress(UINT32 addr);
-
-	// Matrix stack
-	void MultMatrix(UINT32 matrixOffset, Mat4& mat);
-	void InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat);
-
-	// Scene database traversal
-	bool DrawModel(UINT32 modelAddr);
-	void DescendCullingNode(UINT32 addr);
-	void DescendPointerList(UINT32 addr);
-	void DescendNodePtr(UINT32 nodeAddr);
-	void RenderViewport(UINT32 addr, int pri);
-
-	// building the scene
-	void CacheModel(Model *m, const UINT32 *data);
-	void CopyVertexData(R3DPoly& r3dPoly, std::vector<Poly>& polyArray);
-
-	void RenderScene(int priority, bool alpha);
-	float Determinant3x3(const float m[16]);
-	bool IsDynamicModel(UINT32 *data);		// check if the model has a colour palette
-	bool IsVROMModel(UINT32 modelAddr);
-	UINT64 GetRomMapKey(int address, int texOffset);
-
-
-	/*
-	* Data
-	*/
-
-	// Stepping
-	int		m_step;
-	int		m_offset;			// offset to subtract for words 3 and higher of culling nodes
-	float	m_vertexFactor;		// fixed-point conversion factor for vertices
-
-	// Memory (passed from outside)
-	const UINT32	*m_cullingRAMLo;	// 4 MB
-	const UINT32	*m_cullingRAMHi;	// 1 MB
-	const UINT32	*m_polyRAM;			// 4 MB
-	const UINT32	*m_vrom;			// 64 MB
-	const UINT16	*m_textureRAM;		// 8 MB
-
-	// Resolution and scaling factors (to support resolutions higher than 496x384) and offsets
-	float		m_xRatio, m_yRatio;
-	unsigned	m_xOffs, m_yOffs;
-	unsigned 	m_totalXRes, m_totalYRes;
-
-	// Real3D Base Matrix Pointer
-	const float	*m_matrixBasePtr;
-
-	TextureSheet	m_texSheet;
-	NodeAttributes	m_nodeAttribs;
-	Mat4			m_modelMat;				// current modelview matrix
-	int				m_listDepth;
-
-	std::vector<Node> m_nodes;				// this represents the entire render frame
-	std::vector<Poly> m_polyBufferRam;		// dynamic polys
-	std::vector<Poly> m_polyBufferRom;		// rom polys
-	std::unordered_map<UINT64, std::shared_ptr<Model>> m_romMap;	// a hash table for all the ROM models
-
-	VBO m_vbo;								// large VBO to hold our poly data, start of VBO is ROM data, ram polys follow
-
-	R3DShader m_r3dShader;
-	int m_currentVPPriority;
-};
-
-} // New3D
-
-#endif  // INCLUDED_NEW3D_H
diff --git a/Src/Graphics/New3D/backup/static model attempt 1/VBO.cpp b/Src/Graphics/New3D/backup/static model attempt 1/VBO.cpp
deleted file mode 100644
index 364bd24..0000000
--- a/Src/Graphics/New3D/backup/static model attempt 1/VBO.cpp	
+++ /dev/null
@@ -1,84 +0,0 @@
-#include "VBO.h"
-
-namespace New3D {
-
-VBO::VBO()
-{
-	m_id		= 0;
-	m_target	= 0;
-	m_capacity	= 0;
-	m_size		= 0;
-}
-
-void VBO::Create(GLenum target, GLenum usage, GLsizeiptr size, const void* data)
-{
-	glGenBuffers(1, &m_id);							// create a vbo
-	glBindBuffer(target, m_id);						// activate vbo id to use
-	glBufferData(target, size, data, usage);		// upload data to video card
-
-	m_target	= target;
-	m_capacity	= size;
-	m_size		= 0;
-
-	Bind(false);		// unbind
-}
-
-void VBO::BufferSubData(GLintptr offset, GLsizeiptr size, const GLvoid* data)
-{
-	glBufferSubData(m_target, offset, size, data);
-}
-
-bool VBO::AppendData(GLsizeiptr size, const GLvoid* data)
-{
-	if (size == 0 || !data) {
-		return true;	// nothing to do
-	}
-
-	if (m_size + size >= m_capacity) {
-		return false;
-	}
-
-	BufferSubData(m_size, size, data);
-
-	m_size += size;
-
-	return true;
-}
-
-void VBO::Reset()
-{
-	m_size = 0;
-}
-
-void VBO::Destroy()
-{
-	if (m_id) {
-		glDeleteBuffers(1, &m_id);
-		m_id		= 0;
-		m_target	= 0;
-		m_capacity	= 0;
-		m_size		= 0;
-	}
-}
-
-void VBO::Bind(bool enable)
-{
-	if (enable) {
-		glBindBuffer(m_target, m_id);
-	}
-	else {
-		glBindBuffer(m_target, 0);
-	}
-}
-
-int VBO::GetSize()
-{
-	return m_size;
-}
-
-int VBO::GetCapacity()
-{
-	return m_capacity;
-}
-
-} // New3D
diff --git a/Src/Graphics/New3D/backup/static vbo/Model.h b/Src/Graphics/New3D/backup/static vbo/Model.h
deleted file mode 100644
index db94306..0000000
--- a/Src/Graphics/New3D/backup/static vbo/Model.h	
+++ /dev/null
@@ -1,125 +0,0 @@
-#ifndef _MODEL_H_
-#define _MODEL_H_
-
-#include "types.h"
-#include <vector>
-#include <unordered_map>
-#include <map>
-#include <memory>
-#include "Texture.h"
-#include "Mat4.h"
-
-namespace New3D {
-
-struct Vertex
-{
-	float pos[3];
-	float normal[3];
-	float texcoords[2];
-	UINT8 color[4];			//rgba
-};
-
-struct Poly		// our polys are always 3 triangles, unlike the real h/w
-{
-	Vertex p1;
-	Vertex p2;
-	Vertex p3;
-};
-
-struct R3DPoly
-{
-	Vertex v[4];			// just easier to have them as an array
-	float faceNormal[3];	// we need this to help work out poly winding, i assume the h/w uses this instead of calculating normals itself
-	int number = 4;
-};
-
-struct Mesh
-{
-	std::shared_ptr<Texture> texture;
-
-	// attributes
-	bool doubleSided	= false;
-	bool textured		= false;
-	bool polyAlpha		= false;		// specified in the rgba colour
-	bool textureAlpha	= false;		// use alpha in texture
-	bool alphaTest		= false;		// discard fragment based on alpha (ogl does this with fixed function)
-	bool lighting		= false;
-	bool testBit		= false;
-	bool clockWise		= true;			// we need to check if the matrix will change the winding
-
-	float fogIntensity = 1.0f;
-
-	// texture
-	bool mirrorU		= false;
-	bool mirrorV		= false;
-
-	// opengl resources
-	int vboOffset		= 0;			// this will be calculated later
-	int triangleCount	= 0;
-};
-
-struct SortingMesh : public Mesh		// This struct temporarily holds the model data, before it gets copied to the main buffer
-{
-	std::vector<Poly> polys;
-};
-
-struct Model
-{
-	std::vector<Mesh> meshes;
-
-	bool dynamic = true;
-
-	//matrices
-	float modelMat[16];
-	float determinant;				// we check if the determinant of the matrix is negative, if it is, the matrix will swap the axis order
-};
-
-struct Viewport
-{
-	Mat4	projectionMatrix;		// projection matrix
-	float	lightingParams[6];		// lighting parameters (see RenderViewport() and vertex shader)
-	float	spotEllipse[4];			// spotlight ellipse (see RenderViewport())
-	float	spotRange[2];			// Z range
-	float	spotColor[3];			// color
-	float	fogParams[5];			// fog parameters (...)
-	int		x, y;					// viewport coordinates (scaled and in OpenGL format)
-	int		width, height;			// viewport dimensions (scaled for display surface size)
-	int		priority;
-};
-
-class NodeAttributes
-{
-public:
-
-	NodeAttributes();
-
-	bool Push();
-	bool Pop();
-	bool StackLimit();
-	void Reset();
-
-	int currentTexOffsetX;
-	int currentTexOffsetY;
-	int currentTexOffset;		// raw value
-
-private:
-
-	struct NodeAttribs
-	{
-		int texOffsetX;
-		int texOffsetY;
-		int texOffset;
-	};
-	std::vector<NodeAttribs> m_vecAttribs;
-};
-
-struct Node
-{
-	Viewport viewport;
-	std::vector<Model> models;
-};
-
-} // New3D
-
-
-#endif
\ No newline at end of file
diff --git a/Src/Graphics/New3D/backup/static vbo/New3D.cpp b/Src/Graphics/New3D/backup/static vbo/New3D.cpp
deleted file mode 100644
index ecfec4d..0000000
--- a/Src/Graphics/New3D/backup/static vbo/New3D.cpp	
+++ /dev/null
@@ -1,1055 +0,0 @@
-#include "New3D.h"
-#include "PolyHeader.h"
-#include "Texture.h"
-#include "Vec.h"
-#include <cmath>  // needed by gcc
-
-#define MAX_RAM_POLYS 100000	
-#define MAX_ROM_POLYS 500000
-
-#ifndef M_PI
-#define M_PI 3.14159265359
-#endif
-
-namespace New3D {
-
-CNew3D::CNew3D()
-{
-	m_cullingRAMLo	= nullptr;
-	m_cullingRAMHi	= nullptr;
-	m_polyRAM		= nullptr;
-	m_vrom			= nullptr;
-	m_textureRAM	= nullptr;
-}
-
-CNew3D::~CNew3D()
-{
-	m_vbo.Destroy();
-}
-
-void CNew3D::AttachMemory(const UINT32 *cullingRAMLoPtr, const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr, const UINT32 *vromPtr, const UINT16 *textureRAMPtr)
-{
-	m_cullingRAMLo	= cullingRAMLoPtr;
-	m_cullingRAMHi	= cullingRAMHiPtr;
-	m_polyRAM		= polyRAMPtr;
-	m_vrom			= vromPtr;
-	m_textureRAM	= textureRAMPtr;
-}
-
-void CNew3D::SetStep(int stepID)
-{
-	m_step = stepID;
-
-	if ((m_step != 0x10) && (m_step != 0x15) && (m_step != 0x20) && (m_step != 0x21)) {
-		m_step = 0x10;
-	}
-
-	if (m_step > 0x10) {
-		m_offset = 0;							// culling nodes are 10 words
-		m_vertexFactor = (1.0f / 2048.0f);		// vertices are in 13.11 format
-	}
-	else {
-		m_offset = 2;							// 8 words
-		m_vertexFactor = (1.0f / 128.0f);		// 17.7
-	}
-
-	m_vbo.Create(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(Poly) * (MAX_RAM_POLYS + MAX_ROM_POLYS));
-}
-
-bool CNew3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXResParam, unsigned totalYResParam)
-{
-	// Resolution and offset within physical display area
-	m_xRatio	= xRes / 496.0f;
-	m_yRatio	= yRes / 384.0f;
-	m_xOffs		= xOffset;
-	m_yOffs		= yOffset;
-	m_totalXRes	= totalXResParam;
-	m_totalYRes = totalYResParam;
-
-	m_r3dShader.LoadShader();
-
-	glUseProgram(0);
-
-	return OKAY;	// OKAY ? wtf ..
-}
-
-void CNew3D::UploadTextures(unsigned x, unsigned y, unsigned width, unsigned height)
-{
-	m_texSheet.Invalidate(x, y, width, height);
-}
-
-void CNew3D::RenderScene(int priority, bool alpha)
-{
-	if (alpha) {
-		glEnable(GL_BLEND);
-	}
-
-	for (auto &n : m_nodes) {
-
-		if (n.viewport.priority != priority || n.models.empty()) {
-			continue;
-		}
-
-		glViewport		(n.viewport.x, n.viewport.y, n.viewport.width, n.viewport.height);
-		glMatrixMode	(GL_PROJECTION);
-		glLoadMatrixf	(n.viewport.projectionMatrix);
-		glMatrixMode	(GL_MODELVIEW);
-
-		m_r3dShader.SetViewportUniforms(&n.viewport);
-
-		for (auto &m : n.models) {
-
-			bool matrixLoaded = false;
-
-			if (m.meshes.empty()) {
-				continue;
-			}
-
-			m_r3dShader.SetModelStates(&m);
-
-			for (auto &mesh : m.meshes) {
-
-				if (alpha) {
-					if (!mesh.textureAlpha && !mesh.polyAlpha) {
-						continue;
-					}
-				}
-				else {
-					if (mesh.textureAlpha || mesh.polyAlpha) {
-						continue;
-					}
-				}
-
-				if (!matrixLoaded) {
-					glLoadMatrixf(m.modelMat);
-					matrixLoaded = true;		// do this here to stop loading matrices we don't need. Ie when rendering non transparent etc
-				}
-				
-				if (mesh.texture) {
-					mesh.texture->BindTexture();
-					mesh.texture->SetWrapMode(mesh.mirrorU, mesh.mirrorV);
-				}
-				
-				m_r3dShader.SetMeshUniforms(&mesh);
-				glDrawArrays(GL_TRIANGLES, mesh.vboOffset*3, mesh.triangleCount*3);			// times 3 to convert triangles to vertices
-			}
-		}
-	}
-
-	glDisable(GL_BLEND);
-	glDepthMask(GL_TRUE);
-}
-
-void CNew3D::RenderFrame(void)
-{
-	// release any resources from last frame
-	m_polyBufferRam.clear();	// clear dyanmic model memory buffer
-	m_nodes.clear();		// memory will grow during the object life time, that's fine, no need to shrink to fit
-	m_modelMat.Release();	// would hope we wouldn't need this but no harm in checking
-	m_nodeAttribs.Reset();
-
-	glDepthFunc		(GL_LEQUAL);
-	glEnable		(GL_DEPTH_TEST);
-	glActiveTexture	(GL_TEXTURE0);
-	glEnable		(GL_CULL_FACE);
-	glFrontFace		(GL_CW);
-
-	for (int pri = 0; pri <= 3; pri++) {
-		RenderViewport(0x800000, pri);		// build model structure
-	}
-
-	m_vbo.Bind(true);
-	m_vbo.BufferSubData(MAX_ROM_POLYS*sizeof(Poly), m_polyBufferRam.size()*sizeof(Poly), m_polyBufferRam.data());	// upload all the dynamic data to GPU in one go
-
-	if (m_polyBufferRom.size()) {
-
-		// sync rom memory with vbo
-		int romBytes	= (int)m_polyBufferRom.size() * sizeof(Poly);
-		int vboBytes	= m_vbo.GetSize();
-		int size		= romBytes - vboBytes;
-
-		if (size) {
-			m_vbo.AppendData(size, &m_polyBufferRom[vboBytes / sizeof(Poly)]);
-		}
-	}
-	
-	glEnableClientState(GL_VERTEX_ARRAY);
-	glEnableClientState(GL_NORMAL_ARRAY);
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-	glEnableClientState(GL_COLOR_ARRAY);
-
-	// before draw, specify vertex and index arrays with their offsets, offsetof is maybe evil ..
-	glVertexPointer		(3, GL_FLOAT, sizeof(Vertex), 0);
-	glNormalPointer		(GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, normal));
-	glTexCoordPointer	(2, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, texcoords));
-	glColorPointer		(4, GL_UNSIGNED_BYTE, sizeof(Vertex), (void*)offsetof(Vertex, color));
-	
-	m_r3dShader.SetShader(true);
-
-	for (int pri = 0; pri <= 3; pri++) {
-		glClear		(GL_DEPTH_BUFFER_BIT);
-		RenderScene	(pri, false);
-		RenderScene	(pri, true);
-	}
-
-	m_r3dShader.SetShader(false);		// unbind shader
-	m_vbo.Bind(false);
-
-	glDisable(GL_CULL_FACE);
-	glDisableClientState(GL_VERTEX_ARRAY);
-	glDisableClientState(GL_NORMAL_ARRAY);
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-	glDisableClientState(GL_COLOR_ARRAY);
-}
-
-void CNew3D::BeginFrame(void)
-{
-}
-
-void CNew3D::EndFrame(void)
-{
-}
-
-/******************************************************************************
-Real3D Address Translation
-
-Functions that interpret word-granular Real3D addresses and return pointers.
-******************************************************************************/
-
-// Translates 24-bit culling RAM addresses
-const UINT32* CNew3D::TranslateCullingAddress(UINT32 addr)
-{
-	addr &= 0x00FFFFFF;	// caller should have done this already
-
-	if ((addr >= 0x800000) && (addr < 0x840000)) {
-		return &m_cullingRAMHi[addr & 0x3FFFF];
-	}
-	else if (addr < 0x100000) {
-		return &m_cullingRAMLo[addr];
-	}
-
-	return NULL;
-}
-
-// Translates model references
-const UINT32* CNew3D::TranslateModelAddress(UINT32 modelAddr)
-{
-	modelAddr &= 0x00FFFFFF;	// caller should have done this already
-
-	if (modelAddr < 0x100000) {
-		return &m_polyRAM[modelAddr];
-	}
-	else {
-		return &m_vrom[modelAddr];
-	}
-}
-
-bool CNew3D::DrawModel(UINT32 modelAddr)
-{
-	const UINT32*	modelAddress;
-	Model*			m;
-	bool			cached = false;
-
-	modelAddress = TranslateModelAddress(modelAddr);
-
-	// create a new model to push onto the vector
-	m_nodes.back().models.emplace_back(Model());
-
-	// get the pointer to the last element in the array
-	m = &m_nodes.back().models.back();
-
-	if (IsVROMModel(modelAddr) && !IsDynamicModel((UINT32*)modelAddress)) {
-
-		m->dynamic = false;
-		
-		// try to find the model in our cache
-
-		auto key = GetRomMapKey(modelAddr, m_nodeAttribs.currentTexOffset);
-
-		if (m_romMap.count(key)) {
-			(*m)	= m_romMap[key];		// probably better using a shared_ptr instead of copying, but for now it'll do
-			cached	= true;
-		}
-	}
-
-	// copy model matrix
-	for (int i = 0; i < 16; i++) {
-		m->modelMat[i] = m_modelMat.currentMatrix[i];
-	}
-
-	//calculate determinant
-	m->determinant = Determinant3x3(m_modelMat);
-
-	if (!cached) {
-		CacheModel(m, modelAddress);
-	}
-
-	//if it was a ROM model, add it to the hash map for later if it wasn't already there
-	if (!m->dynamic && !cached) {
-		auto key = GetRomMapKey(modelAddr, m_nodeAttribs.currentTexOffset);
-		m_romMap[key] = *m;
-	}
-
-	return true;
-}
-
-// Descends into a 10-word culling node
-void CNew3D::DescendCullingNode(UINT32 addr)
-{
-	const UINT32	*node, *lodTable;
-	UINT32			matrixOffset, node1Ptr, node2Ptr;
-	float			x, y, z;
-	int				tx, ty;
-
-	if (m_nodeAttribs.StackLimit()) {
-		return;
-	}
-
-	node = TranslateCullingAddress(addr);
-
-	if (NULL == node) {
-		return;
-	}
-
-	// Extract known fields
-	node1Ptr		= node[0x07 - m_offset];
-	node2Ptr		= node[0x08 - m_offset];
-	matrixOffset	= node[0x03 - m_offset] & 0xFFF;
-
-	x = *(float *)&node[0x04 - m_offset];	// magic numbers everywhere !
-	y = *(float *)&node[0x05 - m_offset];
-	z = *(float *)&node[0x06 - m_offset];
-
-	m_nodeAttribs.Push();	// save current attribs
-
-	if (!m_offset)	// Step 1.5+
-	{
-		tx = 32 * ((node[0x02] >> 7) & 0x3F);
-		ty = 32 * (node[0x02] & 0x3F) + ((node[0x02] & 0x4000) ? 1024 : 0);	// TODO: 5 or 6 bits for Y coord?
-
-		// apply texture offsets, else retain current ones
-		if ((node[0x02] & 0x8000))	{
-			m_nodeAttribs.currentTexOffsetX = tx;
-			m_nodeAttribs.currentTexOffsetY = ty;
-			m_nodeAttribs.currentTexOffset	= node[0x02] & 0x7FFF;
-		}
-	}
-
-	// Apply matrix and translation
-	m_modelMat.PushMatrix();
-
-	// apply translation vector
-	if ((node[0x00] & 0x10)) {
-		m_modelMat.Translate(x, y, z);
-	}
-	// multiply matrix, if specified
-	else if (matrixOffset) {
-		MultMatrix(matrixOffset,m_modelMat);
-	}		
-
-	// Descend down first link
-	if ((node[0x00] & 0x08))	// 4-element LOD table
-	{
-		lodTable = TranslateCullingAddress(node1Ptr);
-
-		if (NULL != lodTable) {
-			if ((node[0x03 - m_offset] & 0x20000000)) {
-				DescendCullingNode(lodTable[0] & 0xFFFFFF);
-			}
-			else {
-				DrawModel(lodTable[0] & 0xFFFFFF);	//TODO
-			}
-		}
-	}
-	else {
-		DescendNodePtr(node1Ptr);
-	}
-
-	// Proceed to second link
-	m_modelMat.PopMatrix();
-
-	// seems to indicate second link is invalid (fixes circular references)
-	if ((node[0x00] & 0x07) != 0x06) {
-		DescendNodePtr(node2Ptr);
-	}
-
-	// Restore old texture offsets
-	m_nodeAttribs.Pop();
-}
-
-void CNew3D::DescendNodePtr(UINT32 nodeAddr)
-{
-	// Ignore null links
-	if ((nodeAddr & 0x00FFFFFF) == 0) {
-		return;
-	}
-
-	switch ((nodeAddr >> 24) & 0xFF)	// pointer type encoded in upper 8 bits
-	{
-	case 0x00:	// culling node
-		DescendCullingNode(nodeAddr & 0xFFFFFF);
-		break;
-	case 0x01:	// model (perhaps bit 1 is a flag in this case?)
-	case 0x03:
-		DrawModel(nodeAddr & 0xFFFFFF);
-		break;
-	case 0x04:	// pointer list
-		DescendPointerList(nodeAddr & 0xFFFFFF);
-		break;
-	default:
-		//printf("ATTENTION: Unknown pointer format: %08X\n\n", nodeAddr);
-		break;
-	}
-}
-
-void CNew3D::DescendPointerList(UINT32 addr)
-{
-	const UINT32*	list;
-	UINT32			nodeAddr;
-	int				listEnd;
-
-	if (m_listDepth > 2) {	// several Step 2.1 games require this safeguard
-		return;
-	}
-
-	list = TranslateCullingAddress(addr);
-
-	if (NULL == list) {
-		return;
-	}
-
-	m_listDepth++;
-
-	// Traverse the list forward and print it out
-	listEnd = 0;
-
-	while (1)
-	{
-		if ((list[listEnd] & 0x02000000)) {	// end of list (?)
-			break;
-		}
-
-		if ((list[listEnd] == 0) || (((list[listEnd]) >> 24) != 0)) {
-			listEnd--;	// back up to last valid list element
-			break;
-		}
-
-		listEnd++;
-	}
-
-	for (int i = 0; i <= listEnd; i++) {
-
-		nodeAddr = list[i] & 0x00FFFFFF;	// clear upper 8 bits to ensure this is processed as a culling node
-
-		if (!(list[i] & 0x01000000)) {	//Fighting Vipers
-
-			if ((nodeAddr != 0) && (nodeAddr != 0x800800)) {
-				DescendCullingNode(nodeAddr);
-			}
-		}
-	}
-
-
-	/*
-	// Traverse the list backward and descend into each pointer
-	while (listEnd >= 0)
-	{
-		nodeAddr = list[listEnd] & 0x00FFFFFF;	// clear upper 8 bits to ensure this is processed as a culling node
-
-		if (!(list[listEnd] & 0x01000000)) {	//Fighting Vipers
-			
-			if ((nodeAddr != 0) && (nodeAddr != 0x800800)) {
-				DescendCullingNode(nodeAddr);
-			}
-		}
-
-		listEnd--;
-	}
-	*/
-
-	m_listDepth--;
-}
-
-
-/******************************************************************************
-Matrix Stack
-******************************************************************************/
-
-// Macro to generate column-major (OpenGL) index from y,x subscripts
-#define CMINDEX(y,x)	(x*4+y)
-
-/*
-* MultMatrix():
-*
-* Multiplies the matrix stack by the specified Real3D matrix. The matrix
-* index is a 12-bit number specifying a matrix number relative to the base.
-* The base matrix MUST be set up before calling this function.
-*/
-void CNew3D::MultMatrix(UINT32 matrixOffset, Mat4& mat)
-{
-	GLfloat		m[4*4];
-	const float	*src = &m_matrixBasePtr[matrixOffset * 12];
-
-	if (m_matrixBasePtr == NULL)	// LA Machineguns
-		return;
-
-	m[CMINDEX(0, 0)] = src[3];
-	m[CMINDEX(0, 1)] = src[4];
-	m[CMINDEX(0, 2)] = src[5];
-	m[CMINDEX(0, 3)] = src[0];
-	m[CMINDEX(1, 0)] = src[6];
-	m[CMINDEX(1, 1)] = src[7];
-	m[CMINDEX(1, 2)] = src[8];
-	m[CMINDEX(1, 3)] = src[1];
-	m[CMINDEX(2, 0)] = src[9];
-	m[CMINDEX(2, 1)] = src[10];
-	m[CMINDEX(2, 2)] = src[11];
-	m[CMINDEX(2, 3)] = src[2];
-	m[CMINDEX(3, 0)] = 0.0;
-	m[CMINDEX(3, 1)] = 0.0;
-	m[CMINDEX(3, 2)] = 0.0;
-	m[CMINDEX(3, 3)] = 1.0;
-
-	mat.MultMatrix(m);
-}
-
-/*
-* InitMatrixStack():
-*
-* Initializes the modelview (model space -> view space) matrix stack and
-* Real3D coordinate system. These are the last transforms to be applied (and
-* the first to be defined on the stack) before projection.
-*
-* Model 3 games tend to define the following unusual base matrix:
-*
-*		0	0	-1	0
-*		1	0	0	0
-*		0	-1	0	0
-*		0	0	0	1
-*
-* When this is multiplied by a column vector, the output is:
-*
-*		-Z
-*		X
-*		-Y
-*		1
-*
-* My theory is that the Real3D GPU accepts vectors in Z,X,Y order. The games
-* store everything as X,Y,Z and perform the translation at the end. The Real3D
-* also has Y and Z coordinates opposite of the OpenGL convention. This
-* function inserts a compensating matrix to undo these things.
-*
-* NOTE: This function assumes we are in GL_MODELVIEW matrix mode.
-*/
-
-void CNew3D::InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat)
-{
-	GLfloat m[4 * 4];
-
-	// This matrix converts vectors back from the weird Model 3 Z,X,Y ordering
-	// and also into OpenGL viewspace (-Y,-Z)
-	m[CMINDEX(0, 0)] = 0.0;	m[CMINDEX(0, 1)] = 1.0;	m[CMINDEX(0, 2)] = 0.0;	m[CMINDEX(0, 3)] = 0.0;
-	m[CMINDEX(1, 0)] = 0.0;	m[CMINDEX(1, 1)] = 0.0;	m[CMINDEX(1, 2)] =-1.0; m[CMINDEX(1, 3)] = 0.0;
-	m[CMINDEX(2, 0)] =-1.0; m[CMINDEX(2, 1)] = 0.0;	m[CMINDEX(2, 2)] = 0.0;	m[CMINDEX(2, 3)] = 0.0;
-	m[CMINDEX(3, 0)] = 0.0;	m[CMINDEX(3, 1)] = 0.0;	m[CMINDEX(3, 2)] = 0.0;	m[CMINDEX(3, 3)] = 1.0;
-
-	if (m_step > 0x10) {
-		mat.LoadMatrix(m);
-	}
-	else {
-		// Scaling seems to help w/ Step 1.0's extremely large coordinates
-		GLfloat s = 1.0f / 2048.0f;	// this will fuck up normals
-		mat.LoadIdentity();
-		mat.Scale(s, s, s);
-		mat.MultMatrix(m);
-	}
-
-	// Set matrix base address and apply matrix #0 (coordinate system matrix)
-	m_matrixBasePtr = (float *)TranslateCullingAddress(matrixBaseAddr);
-	MultMatrix(0, mat);
-}
-
-// Draws viewports of the given priority
-void CNew3D::RenderViewport(UINT32 addr, int pri)
-{
-	GLfloat	color[8][3] =	// RGB1 translation
-	{
-		{ 0.0, 0.0, 0.0 },	// off
-		{ 0.0, 0.0, 1.0 },	// blue
-		{ 0.0, 1.0, 0.0 },	// green
-		{ 0.0, 1.0, 1.0 },	// cyan
-		{ 1.0, 0.0, 0.0 }, 	// red
-		{ 1.0, 0.0, 1.0 },	// purple
-		{ 1.0, 1.0, 0.0 },	// yellow
-		{ 1.0, 1.0, 1.0 }	// white
-	};
-	const UINT32	*vpnode;
-	UINT32			nextAddr, nodeAddr, matrixBase;
-	int				curPri;
-	int				vpX, vpY, vpWidth, vpHeight;
-	int				spotColorIdx;
-	GLfloat			vpTopAngle, vpBotAngle, fovYDegrees;
-	GLfloat			scrollFog, scrollAtt;
-	Viewport*		vp;
-
-	// Translate address and obtain pointer
-	vpnode = TranslateCullingAddress(addr);
-
-	if (NULL == vpnode) {
-		return;
-	}
-
-	curPri		= (vpnode[0x00] >> 3) & 3;	// viewport priority
-	nextAddr	= vpnode[0x01] & 0xFFFFFF;	// next viewport
-	nodeAddr	= vpnode[0x02];				// scene database node pointer
-
-	// Recursively process next viewport
-	if (vpnode[0x01] == 0) {				// memory probably hasn't been set up yet, abort
-		return;
-	}
-	if (vpnode[0x01] != 0x01000000) {
-		RenderViewport(vpnode[0x01], pri);
-	}
-
-	// If the priority doesn't match, do not process
-	if (curPri != pri) {
-		return;
-	}
-
-	// create node object 
-	m_nodes.emplace_back(Node());
-	m_nodes.back().models.reserve(2048);			// create space for models
-
-	// get pointer to its viewport
-	vp = &m_nodes.back().viewport;
-
-	vp->priority = pri;
-
-	// Fetch viewport parameters (TO-DO: would rounding make a difference?)
-	vpX			= (vpnode[0x1A] & 0xFFFF) >> 4;		// viewport X (12.4 fixed point)
-	vpY			= (vpnode[0x1A] >> 20) & 0xFFF;		// viewport Y (12.4)
-	vpWidth		= (vpnode[0x14] & 0xFFFF) >> 2;		// width (14.2)
-	vpHeight	= (vpnode[0x14] >> 18) & 0x3FFF;	// height (14.2)
-	matrixBase	= vpnode[0x16] & 0xFFFFFF;		// matrix base address
-
-	// Field of view and clipping
-	vpTopAngle	= (float)asin(*(float *)&vpnode[0x0E]);	// FOV Y upper half-angle (radians)
-	vpBotAngle	= (float)asin(*(float *)&vpnode[0x12]);	// FOV Y lower half-angle
-	fovYDegrees	= (vpTopAngle + vpBotAngle)*(float)(180.0 / 3.14159265358979323846);
-
-	// TO-DO: investigate clipping planes
-
-	//if (g_Config.wideScreen && (vpX == 0) && (vpWidth >= 495) && (vpY == 0) && (vpHeight >= 383))		// only expand viewports that occupy whole screen
-	//if (0)
-	if ((vpX == 0) && (vpWidth >= 495) && (vpY == 0) && (vpHeight >= 383))
-	{
-		// Wide screen hack only modifies X axis and not the Y FOV
-		vp->x		= 0;
-		vp->y		= m_yOffs + (GLint)((float)(384 - (vpY + vpHeight))*m_yRatio);
-		vp->width	= m_totalXRes;
-		vp->height	= (GLint)((float)vpHeight*m_yRatio);
-
-		vp->projectionMatrix.Perspective(fovYDegrees, (GLfloat)vp->width / (GLfloat)vp->height, 0.1f, 1e5);	// use actual full screen ratio to get proper X FOV
-	}
-	else
-	{
-		vp->x		= m_xOffs + (GLint)((float)vpX*m_xRatio);
-		vp->y		= m_yOffs + (GLint)((float)(384 - (vpY + vpHeight))*m_yRatio);
-		vp->width	= (GLint)((float)vpWidth*m_xRatio);
-		vp->height	= (GLint)((float)vpHeight*m_yRatio);
-
-		vp->projectionMatrix.Perspective(fovYDegrees, (GLfloat)vpWidth / (GLfloat)vpHeight, 0.1f, 1e5);		// use Model 3 viewport ratio
-	}
-
-	// Lighting (note that sun vector points toward sun -- away from vertex)
-	vp->lightingParams[0] = *(float *)&vpnode[0x05];								// sun X
-	vp->lightingParams[1] = *(float *)&vpnode[0x06];								// sun Y
-	vp->lightingParams[2] = *(float *)&vpnode[0x04];								// sun Z
-	vp->lightingParams[3] = *(float *)&vpnode[0x07];								// sun intensity
-	vp->lightingParams[4] = (float)((vpnode[0x24] >> 8) & 0xFF) * (1.0f / 255.0f);	// ambient intensity
-	vp->lightingParams[5] = 0.0;	// reserved
-
-	// Spotlight
-	spotColorIdx = (vpnode[0x20] >> 11) & 7;					// spotlight color index
-	vp->spotEllipse[0] = (float)((vpnode[0x1E] >> 3) & 0x1FFF);	// spotlight X position (fractional component?)
-	vp->spotEllipse[1] = (float)((vpnode[0x1D] >> 3) & 0x1FFF);	// spotlight Y
-	vp->spotEllipse[2] = (float)((vpnode[0x1E] >> 16) & 0xFFFF);	// spotlight X size (16-bit? May have fractional component below bit 16)
-	vp->spotEllipse[3] = (float)((vpnode[0x1D] >> 16) & 0xFFFF);	// spotlight Y size
-
-	vp->spotRange[0] = 1.0f / (*(float *)&vpnode[0x21]);		// spotlight start
-	vp->spotRange[1] = *(float *)&vpnode[0x1F];				// spotlight extent
-	vp->spotColor[0] = color[spotColorIdx][0];				// spotlight color
-	vp->spotColor[1] = color[spotColorIdx][1];
-	vp->spotColor[2] = color[spotColorIdx][2];
-
-	// Spotlight is applied on a per pixel basis, must scale its position and size to screen
-	vp->spotEllipse[1] = 384.0f - vp->spotEllipse[1];
-	vp->spotRange[1] += vp->spotRange[0];	// limit
-	vp->spotEllipse[2] = 496.0f / sqrt(vp->spotEllipse[2]);	// spotlight appears to be specified in terms of physical resolution (unconfirmed)
-	vp->spotEllipse[3] = 384.0f / sqrt(vp->spotEllipse[3]);
-
-	// Scale the spotlight to the OpenGL viewport
-	vp->spotEllipse[0] = vp->spotEllipse[0] * m_xRatio + m_xOffs;
-	vp->spotEllipse[1] = vp->spotEllipse[1] * m_yRatio + m_yOffs;
-	vp->spotEllipse[2] *= m_xRatio;
-	vp->spotEllipse[3] *= m_yRatio;
-
-	// Fog
-	vp->fogParams[0] = (float)((vpnode[0x22] >> 16) & 0xFF) * (1.0f / 255.0f);	// fog color R
-	vp->fogParams[1] = (float)((vpnode[0x22] >> 8) & 0xFF) * (1.0f / 255.0f);	// fog color G
-	vp->fogParams[2] = (float)((vpnode[0x22] >> 0) & 0xFF) * (1.0f / 255.0f);	// fog color B
-	vp->fogParams[3] = *(float *)&vpnode[0x23];									// fog density
-	vp->fogParams[4] = (float)(INT16)(vpnode[0x25] & 0xFFFF)*(1.0f / 255.0f);	// fog start
-
-	
-	if (std::isinf(vp->fogParams[3]) || std::isnan(vp->fogParams[3]) || std::isinf(vp->fogParams[4]) || std::isnan(vp->fogParams[4])) {	// Star Wars Trilogy
-		vp->fogParams[3] = vp->fogParams[4] = 0.0f;
-	}
-
-	// Unknown light/fog parameters
-	scrollFog = (float)(vpnode[0x20] & 0xFF) * (1.0f / 255.0f);	// scroll fog
-	scrollAtt = (float)(vpnode[0x24] & 0xFF) * (1.0f / 255.0f);	// scroll attenuation
-
-	// Clear texture offsets before proceeding
-	m_nodeAttribs.Reset();
-
-	// Set up coordinate system and base matrix
-	InitMatrixStack(matrixBase, m_modelMat);
-
-	// Safeguard: weird coordinate system matrices usually indicate scenes that will choke the renderer
-	if (NULL != m_matrixBasePtr)
-	{
-		float	m21, m32, m13;
-
-		// Get the three elements that are usually set and see if their magnitudes are 1
-		m21 = m_matrixBasePtr[6];
-		m32 = m_matrixBasePtr[10];
-		m13 = m_matrixBasePtr[5];
-
-		m21 *= m21;
-		m32 *= m32;
-		m13 *= m13;
-
-		if ((m21>1.05) || (m21<0.95))
-			return;
-		if ((m32>1.05) || (m32<0.95))
-			return;
-		if ((m13>1.05) || (m13<0.95))
-			return;
-	}
-
-	m_listDepth = 0;
-
-	// Descend down the node link: Use recursive traversal
-	DescendNodePtr(nodeAddr);
-}
-
-void CNew3D::CopyVertexData(R3DPoly& r3dPoly, std::vector<Poly>& polyArray)
-{
-	//====================
-	Poly		p;
-	V3::Vec3	normal;
-	float		dotProd;
-	bool		clockWise;
-	//====================
-
-	V3::createNormal(r3dPoly.v[0].pos, r3dPoly.v[1].pos, r3dPoly.v[2].pos, normal);
-
-	dotProd		= V3::dotProduct(normal, r3dPoly.faceNormal);
-	clockWise	= dotProd >= 0.0;
-
-	if (clockWise) {
-		p.p1 = r3dPoly.v[0];
-		p.p2 = r3dPoly.v[1];
-		p.p3 = r3dPoly.v[2];
-	}
-	else {
-		p.p1 = r3dPoly.v[2];
-		p.p2 = r3dPoly.v[1];
-		p.p3 = r3dPoly.v[0];
-	}
-	
-	polyArray.emplace_back(p);
-
-	if (r3dPoly.number == 4) {
-
-		if (clockWise) {
-			p.p1 = r3dPoly.v[0];
-			p.p2 = r3dPoly.v[2];
-			p.p3 = r3dPoly.v[3];
-		}
-		else {
-			p.p1 = r3dPoly.v[0];
-			p.p2 = r3dPoly.v[3];
-			p.p3 = r3dPoly.v[2];
-		}
-
-		polyArray.emplace_back(p);
-	}
-}
-
-void CNew3D::CacheModel(Model *m, const UINT32 *data)
-{
-	Vertex			prev[4];
-	PolyHeader		ph;
-	int				numPolys	= 0;
-	bool			done		= false;
-	UINT64			lastHash	= -1;
-	SortingMesh*	currentMesh = nullptr;
-	
-	std::shared_ptr<Texture> tex;
-	std::map<UINT64, SortingMesh> sMap;
-
-	if (data == NULL)
-		return;
-
-	ph = data; 
-	int numTriangles = ph.NumTrianglesTotal();
-
-	// Cache all polygons
-	while (!done)
-	{
-		R3DPoly		p;					// current polygon
-		GLfloat		uvScale;
-		int			i, j;
-		bool		validPoly = true;
-
-		ph = data;
-
-		if (ph.header[6] == 0) {
-			break;
-		}
-
-		if ((ph.header[0] & 0x100) && (ph.header[0] & 0x200)) {	// assuming these two bits mean z and colour writes are disabled
-			validPoly = false;
-		}
-		else {
-			if (!numPolys && (ph.NumSharedVerts() != 0)) {			// sharing vertices, but we haven't started the model yet
-				printf("incomplete data\n");
-				validPoly = false;
-			}
-		}
-
-		// Set current header pointer (header is 7 words)
-		data += 7;	// data will now point to first vertex
-
-		// create a hash value based on poly attributes -todo add more attributes
-		auto hash = ph.Hash(m_nodeAttribs.currentTexOffsetX, m_nodeAttribs.currentTexOffsetY);
-
-		if (hash != lastHash && validPoly) {
-
-			if (sMap.count(hash) == 0) {
-
-				sMap[hash] = SortingMesh();
-
-				currentMesh = &sMap[hash];
-
-				//make space for our vertices
-				currentMesh->polys.reserve(numTriangles);
-
-				//copy attributes
-				currentMesh->doubleSided	= ph.DoubleSided();
-				currentMesh->mirrorU		= ph.TexUMirror();
-				currentMesh->mirrorV		= ph.TexVMirror();
-				currentMesh->textured		= ph.TexEnabled();
-				currentMesh->alphaTest		= ph.AlphaTest();
-				currentMesh->textureAlpha	= ph.TextureAlpha();
-				currentMesh->polyAlpha		= ph.PolyAlpha();
-				currentMesh->lighting		= ph.LightEnabled();
-
-				if (ph.header[6] & 0x10000) {
-					currentMesh->testBit = true;
-				}
-
-				if (!ph.Luminous()) {
-					currentMesh->fogIntensity = 1.0f;
-				}
-				else {
-					currentMesh->fogIntensity = ph.LightModifier();
-				}
-
-				if (ph.TexEnabled()) {
-					currentMesh->texture = m_texSheet.BindTexture(m_textureRAM, ph.TexFormat(), ph.TexUMirror(), ph.TexVMirror(), ph.X(m_nodeAttribs.currentTexOffsetX), ph.Y(m_nodeAttribs.currentTexOffsetY), ph.TexWidth(), ph.TexHeight());
-				}
-			}
-
-			currentMesh = &sMap[hash];
-
-			if (ph.TexEnabled()) {
-				tex = currentMesh->texture;
-			}
-			else {
-				tex = nullptr;
-			}
-		}
-
-		if (validPoly) {
-			lastHash = hash;
-		}
-
-		// Obtain basic polygon parameters
-		done		= ph.LastPoly();
-		p.number	= ph.NumVerts();
-		uvScale		= ph.UVScale();
-
-		ph.FaceNormal(p.faceNormal);
-
-		// Fetch reused vertices according to bitfield, then new verts
-		i = 0;
-		j = 0;
-		for (i = 0; i < 4; i++)		// up to 4 reused vertices
-		{
-			if (ph.SharedVertex(i))
-			{
-				p.v[j] = prev[i];
-				++j;
-			}
-		}
-
-		for (; j < p.number; j++)	// remaining vertices are new and defined here
-		{
-			// Fetch vertices
-			UINT32 ix = data[0];
-			UINT32 iy = data[1];
-			UINT32 iz = data[2];
-			UINT32 it = data[3];
-
-			// Decode vertices
-			p.v[j].pos[0] = (GLfloat)(((INT32)ix) >> 8) * m_vertexFactor;
-			p.v[j].pos[1] = (GLfloat)(((INT32)iy) >> 8) * m_vertexFactor;
-			p.v[j].pos[2] = (GLfloat)(((INT32)iz) >> 8) * m_vertexFactor;
-
-			p.v[j].normal[0] = p.faceNormal[0] + (GLfloat)(INT8)(ix & 0xFF);	// vertex normals are offset from polygon normal - we can normalise them in the shader
-			p.v[j].normal[1] = p.faceNormal[1] + (GLfloat)(INT8)(iy & 0xFF);
-			p.v[j].normal[2] = p.faceNormal[2] + (GLfloat)(INT8)(iz & 0xFF);
-
-			if ((ph.header[1] & 2) == 0) {
-				UINT32 colorIdx = ((ph.header[4] >> 20) & 0x7FF);
-				p.v[j].color[0] = (m_polyRAM[0x400 + colorIdx] & 0xFF);
-				p.v[j].color[1] = (m_polyRAM[0x400 + colorIdx] >> 8) & 0xFF;
-				p.v[j].color[2] = (m_polyRAM[0x400 + colorIdx] >> 16) & 0xFF;
-			}
-			else if (ph.FixedShading()) {
-				UINT8 shade = ph.ShadeValue();
-				p.v[j].color[0] = shade;
-				p.v[j].color[1] = shade;
-				p.v[j].color[2] = shade;
-			}
-			else {
-				p.v[j].color[0] = (ph.header[4] >> 24);
-				p.v[j].color[1] = (ph.header[4] >> 16) & 0xFF;
-				p.v[j].color[2] = (ph.header[4] >> 8) & 0xFF;
-			}
-
-			if ((ph.header[6] & 0x00800000)) {	// if set, polygon is opaque
-				p.v[j].color[3] = 255;
-			}
-			else {
-				p.v[j].color[3] = ph.Transparency();
-			}
-
-			float texU, texV = 0;
-
-			// tex coords
-			if (tex) {
-				tex->GetCoordinates((UINT16)(it >> 16), (UINT16)(it & 0xFFFF), uvScale, texU, texV);
-			}
-
-			p.v[j].texcoords[0] = texU;
-			p.v[j].texcoords[1] = texV;
-
-			data += 4;
-		}
-
-		// Copy current vertices into previous vertex array
-		for (i = 0; i < 4 && validPoly; i++) {
-			prev[i] = p.v[i];
-		}
-
-		// Copy this polygon into the model buffer
-		if (validPoly) {
-			CopyVertexData(p, currentMesh->polys);
-			numPolys++;
-		}
-	}
-
-	//sorted the data, now copy to main data structures
-
-	// we know how many meshes we have so reserve appropriate space
-	m->meshes.reserve(sMap.size());
-
-	for (auto& it : sMap) {
-
-		if (m->dynamic) {
-
-			// calculate VBO values for current mesh
-			it.second.vboOffset		= m_polyBufferRam.size() + MAX_ROM_POLYS;
-			it.second.triangleCount = it.second.polys.size();
-
-			// copy poly data to main buffer
-			m_polyBufferRam.insert(m_polyBufferRam.end(), it.second.polys.begin(), it.second.polys.end());
-		}
-		else {
-			// calculate VBO values for current mesh
-			it.second.vboOffset = m_polyBufferRom.size();
-			it.second.triangleCount = it.second.polys.size();
-
-			// copy poly data to main buffer
-			m_polyBufferRom.insert(m_polyBufferRom.end(), it.second.polys.begin(), it.second.polys.end());
-		}
-
-		//copy the temp mesh into the model structure
-		//this will lose the associated vertex data, which is now copied to the main buffer anyway
-		m->meshes.push_back(it.second);
-	}
-}
-
-float CNew3D::Determinant3x3(const float m[16]) {
-
-	/*
-		| A B C |
-	M = | D E F |
-		| G H I |
-
-	then the determinant is calculated as follows:
-
-	det M = A * (EI - HF) - B * (DI - GF) + C * (DH - GE)
-	*/
-
-	return m[0] * ((m[5] * m[10]) - (m[6] * m[9])) - m[4] * ((m[1] * m[10]) - (m[2] * m[9])) + m[8] * ((m[1] * m[6]) - (m[2] * m[5]));
-}
-
-bool CNew3D::IsDynamicModel(UINT32 *data)
-{
-	if (data == NULL) {
-		return false;
-	}
-
-	PolyHeader p(data);
-
-	do {
-
-		if ((p.header[1] & 2) == 0) {		// model has rgb colour palette 
-			return true;
-		}
-
-		if (p.header[6] == 0) {
-			break;
-		}
-
-	} while (p.NextPoly());
-
-	return false;
-}
-
-bool CNew3D::IsVROMModel(UINT32 modelAddr)
-{
-	return modelAddr >= 0x100000;
-}
-
-UINT64 CNew3D::GetRomMapKey(int address, int texOffset)
-{
-	return (UINT64)address << 32 | texOffset;
-}
-
-} // New3D
diff --git a/Src/Graphics/New3D/backup/static vbo/New3D.h b/Src/Graphics/New3D/backup/static vbo/New3D.h
deleted file mode 100644
index d5071dd..0000000
--- a/Src/Graphics/New3D/backup/static vbo/New3D.h	
+++ /dev/null
@@ -1,226 +0,0 @@
-/**
-** Supermodel
-** A Sega Model 3 Arcade Emulator.
-** Copyright 2011 Bart Trzynadlowski, Nik Henson
-**
-** This file is part of Supermodel.
-**
-** Supermodel is free software: you can redistribute it and/or modify it under
-** the terms of the GNU General Public License as published by the Free
-** Software Foundation, either version 3 of the License, or (at your option)
-** any later version.
-**
-** Supermodel is distributed in the hope that it will be useful, but WITHOUT
-** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-** FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-** more details.
-**
-** You should have received a copy of the GNU General Public License along
-** with Supermodel.  If not, see <http://www.gnu.org/licenses/>.
-**/
-
-/*
-* New3D.h
-*
-* Header file defining the CNew3D class: OpenGL Real3D graphics engine.
-*/
-
-#ifndef INCLUDED_NEW3D_H
-#define INCLUDED_NEW3D_H
-
-#include "Pkgs/glew.h"
-#include "Types.h"
-#include "TextureSheet.h"
-#include "Graphics/IRender3D.h"
-#include "Model.h"
-#include "Mat4.h"
-#include "R3DShader.h"
-#include "VBO.h"
-
-namespace New3D {
-
-class CNew3D : public IRender3D
-{
-public:
-	/*
-	* RenderFrame(void):
-	*
-	* Renders the complete scene database. Must be called between BeginFrame() and
-	* EndFrame(). This function traverses the scene database and builds up display
-	* lists.
-	*/
-	void RenderFrame(void);
-
-	/*
-	* BeginFrame(void):
-	*
-	* Prepare to render a new frame. Must be called once per frame prior to
-	* drawing anything.
-	*/
-	void BeginFrame(void);
-
-	/*
-	* EndFrame(void):
-	*
-	* Signals the end of rendering for this frame. Must be called last during
-	* the frame.
-	*/
-	void EndFrame(void);
-
-	/*
-	* UploadTextures(x, y, width, height):
-	*
-	* Signals that a portion of texture RAM has been updated.
-	*
-	* Parameters:
-	*		x		X position within texture RAM.
-	*		y		Y position within texture RAM.
-	*		width	Width of texture data in texels.
-	*		height	Height.
-	*/
-	void UploadTextures(unsigned x, unsigned y, unsigned width, unsigned height);
-
-	/*
-	* AttachMemory(cullingRAMLoPtr, cullingRAMHiPtr, polyRAMPtr, vromPtr,
-	* 				textureRAMPtr):
-	*
-	* Attaches RAM and ROM areas. This must be done prior to any rendering
-	* otherwise the program may crash with an access violation.
-	*
-	* Parameters:
-	*		cullingRAMLoPtr		Pointer to low culling RAM (4 MB).
-	*		cullingRAMHiPtr		Pointer to high culling RAM (1 MB).
-	*		polyRAMPtr			Pointer to polygon RAM (4 MB).
-	*		vromPtr				Pointer to video ROM (64 MB).
-	*		textureRAMPtr		Pointer to texture RAM (8 MB).
-	*/
-	void AttachMemory(const UINT32 *cullingRAMLoPtr,
-		const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr,
-		const UINT32 *vromPtr, const UINT16 *textureRAMPtr);
-
-	/*
-	* SetStep(stepID):
-	*
-	* Sets the Model 3 hardware stepping, which also determines the Real3D
-	* functionality. The default is Step 1.0. This should be called prior to
-	* any other emulation functions and after Init().
-	*
-	* Parameters:
-	*		stepID	0x10 for Step 1.0, 0x15 for Step 1.5, 0x20 for Step 2.0,
-	*				or 0x21 for Step 2.1. Anything else defaults to 1.0.
-	*/
-	void SetStep(int stepID);
-
-	/*
-	* Init(xOffset, yOffset, xRes, yRes, totalXRes, totalYRes):
-	*
-	* One-time initialization of the context. Must be called before any other
-	* members (meaning it should be called even before being attached to any
-	* other objects that want to use it).
-	*
-	* External shader files are loaded according to configuration settings.
-	*
-	* Parameters:
-	*		xOffset		X offset of the viewable area within OpenGL display
-	*                  surface, in pixels.
-	*		yOffset		Y offset.
-	*		xRes		Horizontal resolution of the viewable area.
-	*		yRes		Vertical resolution.
-	*		totalXRes	Horizontal resolution of the complete display area.
-	*		totalYRes	Vertical resolution.
-	*
-	* Returns:
-	*		OKAY is successful, otherwise FAILED if a non-recoverable error
-	*		occurred. Any allocated memory will not be freed until the
-	*		destructor is called. Prints own error messages.
-	*/
-	bool Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXRes, unsigned totalYRes);
-
-	/*
-	* CRender3D(void):
-	* ~CRender3D(void):
-	*
-	* Constructor and destructor.
-	*/
-	CNew3D(void);
-	~CNew3D(void);
-
-private:
-	/*
-	* Private Members
-	*/
-
-	// Real3D address translation
-	const UINT32 *TranslateCullingAddress(UINT32 addr);
-	const UINT32 *TranslateModelAddress(UINT32 addr);
-
-	// Matrix stack
-	void MultMatrix(UINT32 matrixOffset, Mat4& mat);
-	void InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat);
-
-	// Scene database traversal
-	bool DrawModel(UINT32 modelAddr);
-	void DescendCullingNode(UINT32 addr);
-	void DescendPointerList(UINT32 addr);
-	void DescendNodePtr(UINT32 nodeAddr);
-	void RenderViewport(UINT32 addr, int pri);
-
-	// building the scene
-	void CacheModel(Model *m, const UINT32 *data);
-	void CopyVertexData(R3DPoly& r3dPoly, std::vector<Poly>& polyArray);
-
-	void RenderScene(int priority, bool alpha);
-	float Determinant3x3(const float m[16]);
-	bool IsDynamicModel(UINT32 *data);		// check if the model has a colour palette
-	bool IsVROMModel(UINT32 modelAddr);
-	UINT64 GetRomMapKey(int address, int texOffset);
-
-
-	/*
-	* Data
-	*/
-
-	// Stepping
-	int		m_step;
-	int		m_offset;			// offset to subtract for words 3 and higher of culling nodes
-	float	m_vertexFactor;		// fixed-point conversion factor for vertices
-
-	// Memory (passed from outside)
-	const UINT32	*m_cullingRAMLo;	// 4 MB
-	const UINT32	*m_cullingRAMHi;	// 1 MB
-	const UINT32	*m_polyRAM;			// 4 MB
-	const UINT32	*m_vrom;			// 64 MB
-	const UINT16	*m_textureRAM;		// 8 MB
-
-	// Resolution and scaling factors (to support resolutions higher than 496x384) and offsets
-	float		m_xRatio, m_yRatio;
-	unsigned	m_xOffs, m_yOffs;
-	unsigned 	m_totalXRes, m_totalYRes;
-
-	// Real3D Base Matrix Pointer
-	const float	*m_matrixBasePtr;
-
-	TextureSheet	m_texSheet;
-	NodeAttributes	m_nodeAttribs;
-	Mat4			m_modelMat;			// current modelview matrix
-	int				m_listDepth;
-
-	std::vector<Node> m_nodes;			// build the scene
-	std::vector<Poly> m_polyBufferRam;
-	std::vector<Poly> m_polyBufferRom;
-	VBO m_vbo;							// large VBO to hold our poly data, start of VBO is ROM data, ram polys follow
-
-	struct ModelKey {
-		int lutIdx;
-		int texOffset;
-	};
-
-	std::unordered_map<UINT64, Model> m_romMap;
-
-	R3DShader m_r3dShader;
-	int m_currentVPPriority;
-};
-
-} // New3D
-
-#endif  // INCLUDED_NEW3D_H