diff --git a/Src/Graphics/New3D/Texture.cpp b/Src/Graphics/New3D/Texture.cpp
index 3022017..366482d 100644
--- a/Src/Graphics/New3D/Texture.cpp
+++ b/Src/Graphics/New3D/Texture.cpp
@@ -65,18 +65,12 @@ void Texture::SetWrapMode(bool mirrorU, bool mirrorV)
 	}
 }
 
-UINT32 Texture::UploadTexture(const UINT16* src, UINT8* scratch, int format, bool mirrorU, bool mirrorV, int x, int y, int width, int height)
+void Texture::UploadTextureMip(int level, const UINT16* src, UINT8* scratch, int format, 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)
@@ -100,8 +94,8 @@ UINT32 Texture::UploadTexture(const UINT16* src, UINT8* scratch, int format, boo
 			for (xi = x; xi < (x + width); xi++)
 			{
 				scratch[i++] = ((src[yi * 2048 + xi] >> 10) & 0x1F) * 255 / 0x1F;	// R
-				scratch[i++] = ((src[yi * 2048 + xi] >> 5 ) & 0x1F) * 255 / 0x1F;	// G
-				scratch[i++] = ((src[yi * 2048 + xi] >> 0 ) & 0x1F) * 255 / 0x1F;	// B
+				scratch[i++] = ((src[yi * 2048 + xi] >> 5) & 0x1F) * 255 / 0x1F;	// G
+				scratch[i++] = ((src[yi * 2048 + xi] >> 0) & 0x1F) * 255 / 0x1F;	// B
 				scratch[i++] = ((src[yi * 2048 + xi] & 0x8000) ? 0 : 255);			// T
 			}
 		}
@@ -182,7 +176,7 @@ UINT32 Texture::UploadTexture(const UINT16* src, UINT8* scratch, int format, boo
 				scratch[i++] = texel;
 				scratch[i++] = texel;
 				scratch[i++] = texel;
-				scratch[i++] = (texel==255 ? 0 : 255);
+				scratch[i++] = (texel == 255 ? 0 : 255);
 			}
 		}
 		break;
@@ -280,38 +274,36 @@ UINT32 Texture::UploadTexture(const UINT16* src, UINT8* scratch, int format, boo
 		break;
 	}
 
+	glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scratch);
+}
 
-	GLfloat maxAnistrophy;
+UINT32 Texture::UploadTexture(const UINT16* src, UINT8* scratch, int format, bool mirrorU, bool mirrorV, int x, int y, int width, int height)
+{
+	const int mipXBase[] = { 0, 1024, 1536, 1792, 1920, 1984, 2016, 2032, 2040, 2044, 2046, 2047 };
+	const int mipYBase[] = { 0, 512, 768, 896, 960, 992, 1008, 1016, 1020, 1022, 1023 };
+	const int mipDivisor[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 };
 
-	glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnistrophy);
-
-	if (maxAnistrophy > 8) {
-		maxAnistrophy = 8.0f;	//anymore than 8 can get expensive for little gain
+	if (!src || !scratch) {
+		return 0;		// sanity checking
 	}
 
-	glPixelStorei(GL_UNPACK_ALIGNMENT, 4);	// rgba is always 4 byte aligned
-	glGenTextures(1, &m_textureID);
-	glBindTexture(GL_TEXTURE_2D, m_textureID);
+	DeleteTexture();	// free any existing texture
+	CreateTextureObject(format, mirrorU, mirrorV, x, y, width, height);
 
-	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);
+	int page = y / 1024;
 
-	// assuming successful we can copy details
+	y -= (page * 1024);	// remove page from tex y
+	
+	for (int i = 0; i < 6; i++) {
 
-	m_x = x;
-	m_y = y;
-	m_width = width;
-	m_height = height;
-	m_format = format;
-	m_mirrorU = mirrorU;
-	m_mirrorV = mirrorV;
+		int xPos = mipXBase[i] + (x / mipDivisor[i]);
+		int yPos = mipYBase[i] + (y / mipDivisor[i]);
 
-	printf("create format %i x: %i y: %i width: %i height: %i\n", format, x, y, width, height);
+		UploadTextureMip(i, src, scratch, format, xPos, yPos + (page * 1024), width, height);
+
+		width /= 2;
+		height /= 2;
+	}
 
 	return m_textureID;
 }
@@ -349,4 +341,35 @@ bool Texture::CheckMapPos(int ax1, int ax2, int ay1, int ay2)
 	return false;
 }
 
+void Texture::CreateTextureObject(int format, bool mirrorU, bool mirrorV, int x, int y, int width, int height)
+{
+	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);
+	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_TEXTURE_BASE_LEVEL, 0);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 5);		// 0-5 (real3d only uses 6 possible mipmap levels)
+
+	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);
+}
+
 } // New3D
diff --git a/Src/Graphics/New3D/Texture.h b/Src/Graphics/New3D/Texture.h
index 5fa6d57..8855da3 100644
--- a/Src/Graphics/New3D/Texture.h
+++ b/Src/Graphics/New3D/Texture.h
@@ -26,6 +26,8 @@ public:
 
 private:
 
+	void CreateTextureObject(int format, bool mirrorU, bool mirrorV, int x, int y, int width, int height);
+	void UploadTextureMip(int level, const UINT16* src, UINT8* scratch, int format, int x, int y, int width, int height);
 	void Reset();
 
 	int m_x;