From 407cc703b84099d84efbcd85523fd38cf4ba6d55 Mon Sep 17 00:00:00 2001
From: Magnus Norddahl <dpjudas@users.noreply.github.com>
Date: Fri, 9 Aug 2019 23:15:48 +0200
Subject: [PATCH] - implement enough of BuilderNative for GZDB to successfully
 run without crashing

---
 Source/Core/Data/DataManager.cs          | 19 ++---
 Source/Core/Data/ImageData.cs            | 18 +----
 Source/Core/GZBuilder/md3/ModelReader.cs | 35 +++------
 Source/Core/Rendering/D3DDevice.cs       |  1 -
 Source/Core/Rendering/Renderer2D.cs      | 10 +--
 Source/Core/Rendering/TextLabel.cs       | 15 ++--
 Source/Core/Rendering/Texture.cs         | 90 +++++++++++++++++-------
 Source/Native/IndexBuffer.cpp            |  4 +-
 Source/Native/IndexBuffer.h              |  4 ++
 Source/Native/Texture.cpp                | 68 ++++++++++++++++++
 Source/Native/Texture.h                  | 27 +++++++
 Source/Native/VertexBuffer.cpp           |  6 +-
 Source/Native/VertexBuffer.h             |  4 ++
 Source/Native/exports.def                |  6 ++
 14 files changed, 213 insertions(+), 94 deletions(-)

diff --git a/Source/Core/Data/DataManager.cs b/Source/Core/Data/DataManager.cs
index c8bbb4a13..9668e58c2 100755
--- a/Source/Core/Data/DataManager.cs
+++ b/Source/Core/Data/DataManager.cs
@@ -3424,7 +3424,7 @@ namespace CodeImp.DoomBuilder.Data
 
 			// Make custom rendertarget
 			const int cubemaptexsize = 1024;
-			Texture rendertarget = new Texture(cubemaptexsize, cubemaptexsize, 1, Format.A8R8G8B8);
+			Texture rendertarget = new Texture(cubemaptexsize, cubemaptexsize);
 
             // Start rendering
             General.Map.Graphics.StartRendering(true, new Color4(), rendertarget, true);
@@ -3452,7 +3452,7 @@ namespace CodeImp.DoomBuilder.Data
 			yscale *= 1.65f;
 
 			// Make cubemap texture
-			CubeTexture cubemap = new CubeTexture(cubemaptexsize, 1, Format.A8R8G8B8);
+			CubeTexture cubemap = new CubeTexture(cubemaptexsize);
 
             // Set render settings...
             General.Map.Graphics.SetRenderState(RenderState.ZEnable, false);
@@ -3652,7 +3652,7 @@ namespace CodeImp.DoomBuilder.Data
 		// sides[] must contain 6 square Po2 images in this order: North, East, South, West, Top, Bottom
 		private static CubeTexture MakeSkyBox(Bitmap[] sides, int targetsize, bool fliptop)
 		{
-			CubeTexture cubemap = new CubeTexture(targetsize, 1, Format.A8R8G8B8);
+			CubeTexture cubemap = new CubeTexture(targetsize);
 
 			// Draw faces
 			sides[3].RotateFlip(RotateFlipType.Rotate90FlipNone);
@@ -3752,15 +3752,10 @@ namespace CodeImp.DoomBuilder.Data
 
 		private static Texture TextureFromBitmap(Image image)
 		{
-			using(MemoryStream ms = new MemoryStream())
-			{
-				image.Save(ms, ImageFormat.Png);
-				ms.Seek(0, SeekOrigin.Begin);
-
-				// Classic skies textures can be NPo2 (and D3D Texture is resized to Po2 by default),
-				// so we need to explicitly specify the size
-				return Texture.FromStream(ms, (int) ms.Length, image.Size.Width, image.Size.Height, 0, Format.Unknown);
-			}
+            using (var bitmap = new Bitmap(image))
+            {
+                return new Texture(bitmap);
+            }
 		}
 		
 		#endregion
diff --git a/Source/Core/Data/ImageData.cs b/Source/Core/Data/ImageData.cs
index d7e3a0d9b..3be3ccc42 100755
--- a/Source/Core/Data/ImageData.cs
+++ b/Source/Core/Data/ImageData.cs
@@ -464,22 +464,10 @@ namespace CodeImp.DoomBuilder.Data
 				// Only do this when texture is not created yet
 				if(((texture == null) || (texture.Disposed)) && this.IsImageLoaded && !loadfailed)
 				{
-					Image img = bitmap;
+					Bitmap img = bitmap;
 					if(loadfailed) img = Properties.Resources.Failed;
-					
-					// Write to memory stream and read from memory
-					MemoryStream memstream = new MemoryStream((img.Size.Width * img.Size.Height * 4) + 4096);
-					img.Save(memstream, ImageFormat.Bmp);
-					memstream.Seek(0, SeekOrigin.Begin);
-					if(dynamictexture)
-					{
-						texture = Texture.FromStream(memstream, (int)memstream.Length, img.Size.Width, img.Size.Height, mipmaplevels, Format.A8R8G8B8);
-					}
-					else
-					{
-						texture = Texture.FromStream(memstream, (int)memstream.Length, img.Size.Width, img.Size.Height, mipmaplevels, Format.Unknown);
-					}
-					memstream.Dispose();
+
+                    texture = new Texture(img);
 					
 					if(dynamictexture)
 					{
diff --git a/Source/Core/GZBuilder/md3/ModelReader.cs b/Source/Core/GZBuilder/md3/ModelReader.cs
index da21e5299..8d5555114 100755
--- a/Source/Core/GZBuilder/md3/ModelReader.cs
+++ b/Source/Core/GZBuilder/md3/ModelReader.cs
@@ -1160,16 +1160,11 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
 			// Calculate model radius
 			mde.Model.Radius = Math.Max(Math.Max(Math.Abs(minY), Math.Abs(maxY)), Math.Max(Math.Abs(minX), Math.Abs(maxX)));
 
-			// Create texture
-			MemoryStream memstream = new MemoryStream((4096 * 4) + 4096);
-			using(Bitmap bmp = CreateVoxelTexture(palette)) bmp.Save(memstream, ImageFormat.Bmp);
-			memstream.Seek(0, SeekOrigin.Begin);
-
-			Texture texture = Texture.FromStream(memstream, (int)memstream.Length, 64, 64, 0, Format.Unknown);
-			memstream.Dispose();
-
-			// Add texture
-			mde.Model.Textures.Add(texture);
+			// Create texture new Texture(bmp.Width)
+            using(Bitmap bmp = CreateVoxelTexture(palette))
+            {
+                mde.Model.Textures.Add(new Texture(bmp));
+            }
 
 			// Create mesh
 			Mesh mesh = new Mesh(vertexElements, verts.ToArray(), indices.ToArray());
@@ -1666,23 +1661,13 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
 			Texture texture = null;
 
 			//create texture
-			if(Path.GetExtension(path) == ".pcx") //pcx format requires special handling...
-			{
-				FileImageReader fir = new FileImageReader();
-				Bitmap bitmap = fir.ReadAsBitmap(ms);
-
-				ms.Close();
+			FileImageReader fir = new FileImageReader();
+			Bitmap bitmap = fir.ReadAsBitmap(ms);
+			ms.Close();
 
-				if(bitmap != null)
-				{
-                    texture.SetPixels(bitmap);
-				}
-			}
-			else
+			if(bitmap != null)
 			{
-				texture = Texture.FromStream(ms);
-
-				ms.Close();
+                texture = new Texture(bitmap);
 			}
 
 			return texture;
diff --git a/Source/Core/Rendering/D3DDevice.cs b/Source/Core/Rendering/D3DDevice.cs
index d42083fca..c08ed1545 100755
--- a/Source/Core/Rendering/D3DDevice.cs
+++ b/Source/Core/Rendering/D3DDevice.cs
@@ -264,7 +264,6 @@ namespace CodeImp.DoomBuilder.Rendering
     public enum TransformState { World, View, Projection }
     public enum SamplerState { AddressU, AddressV, AddressW }
     public enum TextureAddress { Wrap, Clamp }
-    public enum Format { Unknown, A8R8G8B8 }
     public enum ShaderFlags { None, Debug }
     public enum PrimitiveType { LineList, TriangleList, TriangleStrip }
     public enum TextureFilter { None, Point, Linear, Anisotropic }
diff --git a/Source/Core/Rendering/Renderer2D.cs b/Source/Core/Rendering/Renderer2D.cs
index 89446a7d4..88996af39 100755
--- a/Source/Core/Rendering/Renderer2D.cs
+++ b/Source/Core/Rendering/Renderer2D.cs
@@ -361,11 +361,11 @@ namespace CodeImp.DoomBuilder.Rendering
 			windowsize.Height = graphics.RenderTarget.ClientSize.Height;
 
 			// Create rendertargets textures
-			plottertex = new Texture(windowsize.Width, windowsize.Height, 1, Format.A8R8G8B8);
-			thingstex = new Texture(windowsize.Width, windowsize.Height, 1, Format.A8R8G8B8);
-			backtex = new Texture(windowsize.Width, windowsize.Height, 1, Format.A8R8G8B8);
-			overlaytex = new Texture(windowsize.Width, windowsize.Height, 1, Format.A8R8G8B8);
-			surfacetex = new Texture(windowsize.Width, windowsize.Height, 1, Format.A8R8G8B8);
+			plottertex = new Texture(windowsize.Width, windowsize.Height);
+			thingstex = new Texture(windowsize.Width, windowsize.Height);
+			backtex = new Texture(windowsize.Width, windowsize.Height);
+			overlaytex = new Texture(windowsize.Width, windowsize.Height);
+			surfacetex = new Texture(windowsize.Width, windowsize.Height);
 			
 			// Get the real surface sizes
 			structsize.Width = plottertex.Width;
diff --git a/Source/Core/Rendering/TextLabel.cs b/Source/Core/Rendering/TextLabel.cs
index 63eaafac6..d49b2654d 100755
--- a/Source/Core/Rendering/TextLabel.cs
+++ b/Source/Core/Rendering/TextLabel.cs
@@ -326,16 +326,11 @@ namespace CodeImp.DoomBuilder.Rendering
 							texture = null;
 						}
 
-						// Create label image
-						Bitmap img = CreateLabelImage(text, font, color, backcolor, drawbg, textrect, bgrect, texturesize, textorigin);
-						//texturesize = img.Size;
-
-						// Create texture
-						MemoryStream memstream = new MemoryStream((img.Size.Width * img.Size.Height * 4) + 4096);
-						img.Save(memstream, ImageFormat.Bmp);
-						memstream.Seek(0, SeekOrigin.Begin);
-
-						texture = Texture.FromStream(memstream, (int)memstream.Length, img.Size.Width, img.Size.Height, 1, Format.Unknown);
+                        // Create label image
+                        using (Bitmap img = CreateLabelImage(text, font, color, backcolor, drawbg, textrect, bgrect, texturesize, textorigin))
+                        {
+                            texture = new Texture(img);
+                        }
 					}
 
 					//mxd. Create the buffer
diff --git a/Source/Core/Rendering/Texture.cs b/Source/Core/Rendering/Texture.cs
index 0be8ca321..b8928b304 100644
--- a/Source/Core/Rendering/Texture.cs
+++ b/Source/Core/Rendering/Texture.cs
@@ -32,19 +32,59 @@ namespace CodeImp.DoomBuilder.Rendering
             }
         }
 
-        IntPtr Handle;
+        protected IntPtr Handle;
 
         [DllImport("BuilderNative.dll", CallingConvention = CallingConvention.Cdecl)]
-        static extern IntPtr Texture_New();
+        protected static extern IntPtr Texture_New();
 
         [DllImport("BuilderNative.dll", CallingConvention = CallingConvention.Cdecl)]
-        static extern void Texture_Delete(IntPtr handle);
+        protected static extern void Texture_Delete(IntPtr handle);
+
+        [DllImport("BuilderNative.dll", CallingConvention = CallingConvention.Cdecl)]
+        protected static extern void Texture_Set2DImage(IntPtr handle, int width, int height);
+
+        [DllImport("BuilderNative.dll", CallingConvention = CallingConvention.Cdecl)]
+        protected static extern void Texture_SetPixels(IntPtr handle, IntPtr data);
+
+        [DllImport("BuilderNative.dll", CallingConvention = CallingConvention.Cdecl)]
+        protected static extern IntPtr Texture_Lock(IntPtr handle);
+
+        [DllImport("BuilderNative.dll", CallingConvention = CallingConvention.Cdecl)]
+        protected static extern void Texture_Unlock(IntPtr handle);
+
+        [DllImport("BuilderNative.dll", CallingConvention = CallingConvention.Cdecl)]
+        protected static extern void Texture_SetCubeImage(IntPtr handle, int size);
+
+        [DllImport("BuilderNative.dll", CallingConvention = CallingConvention.Cdecl)]
+        protected static extern void Texture_SetCubePixels(IntPtr handle, CubeMapFace face, IntPtr data);
     }
 
     public class Texture : BaseTexture
     {
-        public Texture(int width, int height, int levels, Format format)
+        public Texture(int width, int height)
         {
+            Width = width;
+            Height = height;
+            Texture_Set2DImage(Handle, Width, Height);
+        }
+
+        public Texture(System.Drawing.Bitmap bitmap)
+        {
+            Width = bitmap.Width;
+            Height = bitmap.Height;
+            Texture_Set2DImage(Handle, Width, Height);
+            SetPixels(bitmap);
+        }
+
+        public Texture(System.Drawing.Image image)
+        {
+            using (var bitmap = new System.Drawing.Bitmap(image))
+            {
+                Width = bitmap.Width;
+                Height = bitmap.Height;
+                Texture_Set2DImage(Handle, Width, Height);
+                SetPixels(bitmap);
+            }
         }
 
         public int Width { get; private set; }
@@ -54,48 +94,50 @@ namespace CodeImp.DoomBuilder.Rendering
 
         public void SetPixels(System.Drawing.Bitmap bitmap)
         {
-            /*
-            BitmapData bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Size.Width, bitmap.Size.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
+            System.Drawing.Imaging.BitmapData bmpdata = bitmap.LockBits(
+                new System.Drawing.Rectangle(0, 0, bitmap.Size.Width, bitmap.Size.Height),
+                System.Drawing.Imaging.ImageLockMode.ReadOnly,
+                System.Drawing.Imaging.PixelFormat.Format32bppArgb);
 
-            DataRectangle textureLock = texture.LockRectangle(0, LockFlags.None);
-            textureLock.Data.WriteRange(bmlock.Scan0, bmlock.Height * bmlock.Stride);
-            texture.UnlockRectangle(0);
+            Texture_SetPixels(Handle, bmpdata.Scan0);
 
             bitmap.UnlockBits(bmpdata);
-            */
         }
 
         internal Plotter LockPlotter(int visibleWidth, int visibleHeight)
         {
-            //return new Plotter((PixelColor*)plotlocked.Data.DataPointer.ToPointer(), plotlocked.Pitch / sizeof(PixelColor), Height, visibleWidth, visibleHeight);
-            return null;
+            unsafe
+            {
+                IntPtr data = Texture_Lock(Handle);
+                return new Plotter((PixelColor*)data.ToPointer(), Width, Height, Math.Min(Width, visibleWidth), Math.Min(Height, visibleHeight));
+            }
         }
 
         public void UnlockPlotter()
         {
-        }
-
-        public static Texture FromStream(System.IO.Stream stream)
-        {
-            return null;
-        }
-
-        public static Texture FromStream(System.IO.Stream stream, int length, int width, int height, int levels, Format format)
-        {
-            return null;
+            Texture_Unlock(Handle);
         }
     }
 
     public class CubeTexture : BaseTexture
     {
-        public CubeTexture(int size, int levels, Format format)
+        public CubeTexture(int size)
         {
+            Texture_SetCubeImage(Handle, size);
         }
 
         public void SetPixels(CubeMapFace face, System.Drawing.Bitmap bitmap)
         {
+            System.Drawing.Imaging.BitmapData bmpdata = bitmap.LockBits(
+                new System.Drawing.Rectangle(0, 0, bitmap.Size.Width, bitmap.Size.Height),
+                System.Drawing.Imaging.ImageLockMode.ReadOnly,
+                System.Drawing.Imaging.PixelFormat.Format32bppArgb);
+
+            Texture_SetCubePixels(Handle, face, bmpdata.Scan0);
+
+            bitmap.UnlockBits(bmpdata);
         }
     }
 
-    public enum CubeMapFace { PositiveX, PositiveY, PositiveZ, NegativeX, NegativeY, NegativeZ }
+    public enum CubeMapFace : int { PositiveX, PositiveY, PositiveZ, NegativeX, NegativeY, NegativeZ }
 }
diff --git a/Source/Native/IndexBuffer.cpp b/Source/Native/IndexBuffer.cpp
index 578f76ec6..29ec49bdf 100644
--- a/Source/Native/IndexBuffer.cpp
+++ b/Source/Native/IndexBuffer.cpp
@@ -1,12 +1,14 @@
 
 #include "IndexBuffer.h"
 
-IndexBuffer::IndexBuffer(int sizeInBytes)
+IndexBuffer::IndexBuffer(int sizeInBytes) : mData(sizeInBytes)
 {
 }
 
 void IndexBuffer::SetBufferData(const void* data, int64_t size)
 {
+	if (size > 0 && size < (int64_t)mData.size())
+		memcpy(mData.data(), data, size);
 }
 
 /////////////////////////////////////////////////////////////////////////////
diff --git a/Source/Native/IndexBuffer.h b/Source/Native/IndexBuffer.h
index 25f844b78..a4367b8f9 100644
--- a/Source/Native/IndexBuffer.h
+++ b/Source/Native/IndexBuffer.h
@@ -1,6 +1,7 @@
 #pragma once
 
 #include <cstdint>
+#include <vector>
 
 class IndexBuffer
 {
@@ -8,4 +9,7 @@ public:
 	IndexBuffer(int sizeInBytes);
 
 	void SetBufferData(const void* data, int64_t size);
+
+private:
+	std::vector<uint8_t> mData;
 };
diff --git a/Source/Native/Texture.cpp b/Source/Native/Texture.cpp
index 2a2339720..b4a6841fe 100644
--- a/Source/Native/Texture.cpp
+++ b/Source/Native/Texture.cpp
@@ -5,6 +5,44 @@ Texture::Texture()
 {
 }
 
+void Texture::Set2DImage(int width, int height)
+{
+	mCubeTexture = false;
+	mWidth = width;
+	mHeight = height;
+}
+
+void Texture::SetCubeImage(int size)
+{
+	mCubeTexture = true;
+	mWidth = size;
+	mHeight = size;
+}
+
+void Texture::SetPixels(const void* data)
+{
+	mPixels[0].resize(mWidth * (size_t)mHeight);
+	memcpy(mPixels[0].data(), data, sizeof(uint32_t) * mWidth * mHeight);
+}
+
+void Texture::SetCubePixels(CubeMapFace face, const void* data)
+{
+	mPixels[(int)face].resize(mWidth * (size_t)mHeight);
+	memcpy(mPixels[(int)face].data(), data, sizeof(uint32_t) * mWidth * mHeight);
+}
+
+void* Texture::Lock()
+{
+	mPixels[0].resize(mWidth * (size_t)mHeight);
+	return mPixels[0].data();
+}
+
+void Texture::Unlock()
+{
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
 Texture* Texture_New()
 {
 	return new Texture();
@@ -14,3 +52,33 @@ void Texture_Delete(Texture* tex)
 {
 	delete tex;
 }
+
+void Texture_Set2DImage(Texture* handle, int width, int height)
+{
+	handle->Set2DImage(width, height);
+}
+
+void Texture_SetPixels(Texture* handle, const void* data)
+{
+	handle->SetPixels(data);
+}
+
+void* Texture_Lock(Texture* handle)
+{
+	return handle->Lock();
+}
+
+void Texture_Unlock(Texture* handle)
+{
+	handle->Unlock();
+}
+
+void Texture_SetCubeImage(Texture* handle, int size)
+{
+	handle->SetCubeImage(size);
+}
+
+void Texture_SetCubePixels(Texture* handle, CubeMapFace face, const void *data)
+{
+	handle->SetCubePixels(face, data);
+}
diff --git a/Source/Native/Texture.h b/Source/Native/Texture.h
index 3896b0eb6..f0654a315 100644
--- a/Source/Native/Texture.h
+++ b/Source/Native/Texture.h
@@ -1,9 +1,36 @@
 #pragma once
 
 #include <cstdint>
+#include <vector>
+#include <map>
+
+enum class CubeMapFace : int
+{
+	PositiveX,
+	PositiveY,
+	PositiveZ,
+	NegativeX,
+	NegativeY,
+	NegativeZ
+};
 
 class Texture
 {
 public:
 	Texture();
+
+	void Set2DImage(int width, int height);
+	void SetCubeImage(int size);
+
+	void SetPixels(const void* data);
+	void SetCubePixels(CubeMapFace face, const void* data);
+
+	void* Lock();
+	void Unlock();
+
+private:
+	int mWidth = 0;
+	int mHeight = 0;
+	bool mCubeTexture = false;
+	std::map<int, std::vector<uint32_t>> mPixels;
 };
diff --git a/Source/Native/VertexBuffer.cpp b/Source/Native/VertexBuffer.cpp
index a13b3665b..97c09bd9f 100644
--- a/Source/Native/VertexBuffer.cpp
+++ b/Source/Native/VertexBuffer.cpp
@@ -1,16 +1,20 @@
 
 #include "VertexBuffer.h"
 
-VertexBuffer::VertexBuffer(int sizeInBytes)
+VertexBuffer::VertexBuffer(int sizeInBytes) : mData(sizeInBytes)
 {
 }
 
 void VertexBuffer::SetBufferData(const void* data, int64_t size)
 {
+	if (size > 0 && size < (int64_t)mData.size())
+		memcpy(mData.data(), data, size);
 }
 
 void VertexBuffer::SetBufferSubdata(int64_t destOffset, const void* data, int64_t size)
 {
+	if (destOffset >= 0 && size > 0 && size < (int64_t)mData.size() - destOffset)
+		memcpy(mData.data() + destOffset, data, size);
 }
 
 /////////////////////////////////////////////////////////////////////////////
diff --git a/Source/Native/VertexBuffer.h b/Source/Native/VertexBuffer.h
index 88cd17cda..bf9caba57 100644
--- a/Source/Native/VertexBuffer.h
+++ b/Source/Native/VertexBuffer.h
@@ -1,6 +1,7 @@
 #pragma once
 
 #include <cstdint>
+#include <vector>
 
 class VertexBuffer
 {
@@ -9,4 +10,7 @@ public:
 
 	void SetBufferData(const void* data, int64_t size);
 	void SetBufferSubdata(int64_t destOffset, const void* data, int64_t size);
+	
+private:
+	std::vector<uint8_t> mData;
 };
diff --git a/Source/Native/exports.def b/Source/Native/exports.def
index 743769a98..0a6d2afba 100644
--- a/Source/Native/exports.def
+++ b/Source/Native/exports.def
@@ -14,3 +14,9 @@ EXPORTS
 	IndexBuffer_SetBufferData
 	Texture_New
 	Texture_Delete
+	Texture_Set2DImage
+	Texture_SetPixels
+	Texture_Lock
+	Texture_Unlock
+	Texture_SetCubeImage
+	Texture_SetCubePixels
-- 
GitLab