diff --git a/Source/Data/DataLocationList.cs b/Source/Data/DataLocationList.cs index 96ece9e6..4f6e21f8 100644 --- a/Source/Data/DataLocationList.cs +++ b/Source/Data/DataLocationList.cs @@ -8,7 +8,7 @@ using System.Collections.Specialized; namespace CodeImp.DoomBuilder.Data { - internal class DataLocationList : List + internal sealed class DataLocationList : List { #region ================== Constructors diff --git a/Source/Data/DataManager.cs b/Source/Data/DataManager.cs index 844f08b1..60ed9c0c 100644 --- a/Source/Data/DataManager.cs +++ b/Source/Data/DataManager.cs @@ -30,7 +30,7 @@ using CodeImp.DoomBuilder.IO; namespace CodeImp.DoomBuilder.Data { - internal class DataManager : IDisposable + internal sealed class DataManager : IDisposable { #region ================== Constants @@ -60,7 +60,7 @@ namespace CodeImp.DoomBuilder.Data #region ================== Properties - // Disposing + public Playpal Palette { get { return palette; } } public bool IsDisposed { get { return isdisposed; } } #endregion diff --git a/Source/Data/DirectoryReader.cs b/Source/Data/DirectoryReader.cs index 35207c85..dc0877a1 100644 --- a/Source/Data/DirectoryReader.cs +++ b/Source/Data/DirectoryReader.cs @@ -30,7 +30,7 @@ using CodeImp.DoomBuilder.IO; namespace CodeImp.DoomBuilder.Data { - internal class DirectoryReader : DataReader + internal sealed class DirectoryReader : DataReader { #region ================== Constants diff --git a/Source/Data/FileImage.cs b/Source/Data/FileImage.cs index 4a707344..99c3e830 100644 --- a/Source/Data/FileImage.cs +++ b/Source/Data/FileImage.cs @@ -29,7 +29,7 @@ using System.IO; namespace CodeImp.DoomBuilder.Data { - internal class FileImage : ImageData + internal sealed class FileImage : ImageData { #region ================== Variables diff --git a/Source/Data/FlatImage.cs b/Source/Data/FlatImage.cs index 977e64d8..6e4ab1d5 100644 --- a/Source/Data/FlatImage.cs +++ b/Source/Data/FlatImage.cs @@ -6,7 +6,7 @@ using System.Text; namespace CodeImp.DoomBuilder.Data { - internal class FlatImage : ImageData + internal sealed class FlatImage : ImageData { #region ================== Constants diff --git a/Source/Data/ImageData.cs b/Source/Data/ImageData.cs index 37c6f5c6..b70253fb 100644 --- a/Source/Data/ImageData.cs +++ b/Source/Data/ImageData.cs @@ -42,6 +42,10 @@ namespace CodeImp.DoomBuilder.Data // Properties private string name; private long longname; + protected int width; + protected int height; + protected float scaledwidth; + protected float scaledheight; // GDI bitmap protected Bitmap bitmap; @@ -65,8 +69,12 @@ namespace CodeImp.DoomBuilder.Data public PixelColor* PixelData { get { return pixeldata; } } public Bitmap Bitmap { get { return bitmap; } } public Texture Texture { get { return texture; } } - public bool IsLoaded { get { return (bitmap == null); } } + public bool IsLoaded { get { return (bitmap != null); } } public bool IsDisposed { get { return isdisposed; } } + public int Width { get { return width; } } + public int Height { get { return height; } } + public float ScaledWidth { get { return scaledwidth; } } + public float ScaledHeight { get { return scaledheight; } } #endregion diff --git a/Source/Data/PatchNames.cs b/Source/Data/PatchNames.cs index 94affacc..db8ae8ee 100644 --- a/Source/Data/PatchNames.cs +++ b/Source/Data/PatchNames.cs @@ -28,7 +28,7 @@ using CodeImp.DoomBuilder.IO; namespace CodeImp.DoomBuilder.Data { - internal class PatchNames + internal sealed class PatchNames { #region ================== Constants diff --git a/Source/Data/Playpal.cs b/Source/Data/Playpal.cs index b562da3b..6e070050 100644 --- a/Source/Data/Playpal.cs +++ b/Source/Data/Playpal.cs @@ -28,7 +28,7 @@ using CodeImp.DoomBuilder.Rendering; namespace CodeImp.DoomBuilder.Data { - internal class Playpal + internal sealed class Playpal { #region ================== Constants diff --git a/Source/Data/SpriteImage.cs b/Source/Data/SpriteImage.cs index 69f791ab..cf51e07d 100644 --- a/Source/Data/SpriteImage.cs +++ b/Source/Data/SpriteImage.cs @@ -6,7 +6,7 @@ using System.Text; namespace CodeImp.DoomBuilder.Data { - internal class SpriteImage : ImageData + internal sealed class SpriteImage : ImageData { #region ================== Constants diff --git a/Source/Data/TextureImage.cs b/Source/Data/TextureImage.cs index 7dbe5852..62c4e2ef 100644 --- a/Source/Data/TextureImage.cs +++ b/Source/Data/TextureImage.cs @@ -21,12 +21,17 @@ using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Text; +using System.Drawing; +using System.Drawing.Imaging; +using CodeImp.DoomBuilder.Rendering; +using CodeImp.DoomBuilder.IO; +using System.IO; #endregion namespace CodeImp.DoomBuilder.Data { - internal class TextureImage : ImageData + internal sealed unsafe class TextureImage : ImageData { #region ================== Constants @@ -35,8 +40,6 @@ namespace CodeImp.DoomBuilder.Data #region ================== Variables private List patches; - private int width; - private int height; private float scalex; private float scaley; @@ -56,6 +59,8 @@ namespace CodeImp.DoomBuilder.Data this.height = height; this.scalex = scalex; this.scaley = scaley; + this.scaledwidth = (float)width * scalex; + this.scaledheight = (float)height * scaley; this.patches = new List(); SetName(name); @@ -90,9 +95,36 @@ namespace CodeImp.DoomBuilder.Data // This loads the image public override void LoadImage() { + uint datalength = (uint)(width * height * sizeof(PixelColor)); + DoomPictureReader reader = new DoomPictureReader(General.Map.Data.Palette); + BitmapData bitmapdata; + PixelColor* pixels; + Stream patchdata; + // Leave when already loaded if(this.IsLoaded) return; + // Create texture bitmap + bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); + bitmapdata = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); + pixels = (PixelColor*)bitmapdata.Scan0.ToPointer(); + General.ZeroMemory(new IntPtr(pixels), width * height * sizeof(PixelColor)); + + // Go for all patches + foreach(TexturePatch p in patches) + { + // Get the patch data stream + patchdata = General.Map.Data.GetPatchData(p.lumpname); + if(patchdata != null) + { + // Read the patch and draw it onto the memory + patchdata.Seek(0, SeekOrigin.Begin); + reader.DrawToPixelData(patchdata, pixels, width, height, p.x, p.y); + } + } + + // Done + bitmap.UnlockBits(bitmapdata); // Pass on to base base.LoadImage(); diff --git a/Source/Data/TexturePatch.cs b/Source/Data/TexturePatch.cs index e24b0a0a..6c61bc74 100644 --- a/Source/Data/TexturePatch.cs +++ b/Source/Data/TexturePatch.cs @@ -32,9 +32,9 @@ namespace CodeImp.DoomBuilder.Data { internal struct TexturePatch { - private string lumpname; - private int x; - private int y; + public string lumpname; + public int x; + public int y; // Constructor public TexturePatch(string lumpname, int x, int y) diff --git a/Source/Data/WADReader.cs b/Source/Data/WADReader.cs index 05fc6d83..4bc305e8 100644 --- a/Source/Data/WADReader.cs +++ b/Source/Data/WADReader.cs @@ -30,7 +30,7 @@ using CodeImp.DoomBuilder.IO; namespace CodeImp.DoomBuilder.Data { - internal class WADReader : DataReader + internal sealed class WADReader : DataReader { #region ================== Constants diff --git a/Source/IO/DoomPictureReader.cs b/Source/IO/DoomPictureReader.cs index 4e1bea96..64e42fe9 100644 --- a/Source/IO/DoomPictureReader.cs +++ b/Source/IO/DoomPictureReader.cs @@ -27,6 +27,7 @@ using CodeImp.DoomBuilder.Geometry; using System.Drawing; using CodeImp.DoomBuilder.Data; using CodeImp.DoomBuilder.Rendering; +using System.Drawing.Imaging; #endregion @@ -63,45 +64,103 @@ namespace CodeImp.DoomBuilder.IO #region ================== Methods // This creates a Bitmap from the given data + // Returns null on failure public Bitmap ReadAsBitmap(Stream stream) { - // TODO: Read as pixel data and copy pixels - return null; + BitmapData bitmapdata; + PixelColor* pixeldata; + PixelColor* targetdata; + int width, height, x, y; + Bitmap bmp; + + // Read pixel data + pixeldata = ReadAsPixelData(stream, out width, out height, out x, out y); + if(pixeldata != null) + { + // Create bitmap and lock pixels + bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb); + bitmapdata = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); + targetdata = (PixelColor*)bitmapdata.Scan0.ToPointer(); + + // Copy the pixels + General.CopyMemory((void*)targetdata, (void*)pixeldata, new UIntPtr((uint)(width * height * sizeof(PixelColor)))); + + // Done + bmp.UnlockBits(bitmapdata); + return bmp; + } + else + { + // Failed loading picture + return null; + } } // This draws the picture to the given pixel color data + // Throws exception on failure public void DrawToPixelData(Stream stream, PixelColor* target, int targetwidth, int targetheight, int x, int y) { - // TODO: Read as pixel data and copy pixels + PixelColor* pixeldata; + int width, height, ox, oy, tx, ty; + + // Read pixel data + pixeldata = ReadAsPixelData(stream, out width, out height, out ox, out oy); + if(pixeldata != null) + { + // Go for all source pixels + // We don't care about the original image offset, so reuse ox/oy + for(ox = 0; ox < width; ox++) + { + for(oy = 0; oy < height; oy++) + { + // Copy this pixel? + if(pixeldata[oy * width + ox].a > 0.5f) + { + // Calculate target pixel and copy when within bounds + tx = x + ox; + ty = y + oy; + if((tx >= 0) && (tx < targetwidth) && (ty >= 0) && (ty < targetheight)) + target[ty * targetwidth + tx] = pixeldata[oy * width + ox]; + } + } + } + } } - + // This creates pixel color data from the given data + // Returns null on failure public PixelColor* ReadAsPixelData(Stream stream, out int width, out int height, out int offsetx, out int offsety) { BinaryReader reader = new BinaryReader(stream); PixelColor* pixeldata = null; uint datalength = 0; int y, count, p; - + int[] columns; + int dataoffset; + // Initialize width = 0; height = 0; offsetx = 0; offsety = 0; - + dataoffset = (int)stream.Position; + // Need at least 4 bytes if((stream.Length - stream.Position) < 4) return null; + #if !DEBUG try { + #endif // Read size and offset width = reader.ReadInt16(); height = reader.ReadInt16(); offsetx = reader.ReadInt16(); offsety = reader.ReadInt16(); - // Skip the column addresses - stream.Seek(4 * width, SeekOrigin.Current); + // Read the column addresses + columns = new int[width]; + for(int x = 0; x < width; x++) columns[x] = reader.ReadInt32(); // Allocate memory datalength = (uint)(sizeof(PixelColor) * width * height); @@ -111,6 +170,9 @@ namespace CodeImp.DoomBuilder.IO // Go for all columns for(int x = 0; x < width; x++) { + // Seek to column start + stream.Seek(dataoffset + columns[x], SeekOrigin.Begin); + // Read first post start y = reader.ReadByte(); @@ -143,6 +205,7 @@ namespace CodeImp.DoomBuilder.IO // Return pointer return pixeldata; + #if !DEBUG } catch(Exception) { @@ -152,6 +215,7 @@ namespace CodeImp.DoomBuilder.IO // Return nothing return null; } + #endif } #endregion diff --git a/Source/Rendering/PixelColor.cs b/Source/Rendering/PixelColor.cs index 3eb616e9..98001bf7 100644 --- a/Source/Rendering/PixelColor.cs +++ b/Source/Rendering/PixelColor.cs @@ -61,6 +61,21 @@ namespace CodeImp.DoomBuilder.Rendering #region ================== Methods + // This blends two colors with respect to alpha + public PixelColor Blend(PixelColor a, PixelColor b) + { + PixelColor c = new PixelColor(); + float ba; + + ba = (float)a.a * 0.003921568627450980392156862745098f; + c.r = (byte)((float)a.r * (1f - ba) + (float)b.r * ba); + c.g = (byte)((float)a.g * (1f - ba) + (float)b.g * ba); + c.b = (byte)((float)a.b * (1f - ba) + (float)b.b * ba); + c.a = (byte)((float)a.a * (1f - ba) + ba); + + return c; + } + #endregion } } diff --git a/Source/Rendering/Renderer2D.cs b/Source/Rendering/Renderer2D.cs index 056368ed..a1d8efe7 100644 --- a/Source/Rendering/Renderer2D.cs +++ b/Source/Rendering/Renderer2D.cs @@ -208,6 +208,8 @@ namespace CodeImp.DoomBuilder.Rendering // This draws a pixel alpha blended private void DrawPixelAlpha(int x, int y, PixelColor c) { + float a; + // Draw only when within range if((x >= 0) && (x < width) && (y >= 0) && (y < height)) { @@ -223,10 +225,11 @@ namespace CodeImp.DoomBuilder.Rendering else { // Blend with pixel + a = (float)c.a * 0.003921568627450980392156862745098f; if((int)p->a + (int)c.a > 255) p->a = 255; else p->a += c.a; - p->r = (byte)((float)p->r * (1f - (float)c.a) + (float)c.r * (float)c.a); - p->g = (byte)((float)p->g * (1f - (float)c.a) + (float)c.g * (float)c.a); - p->b = (byte)((float)p->b * (1f - (float)c.a) + (float)c.b * (float)c.a); + p->r = (byte)((float)p->r * (1f - a) + (float)c.r * a); + p->g = (byte)((float)p->g * (1f - a) + (float)c.g * a); + p->b = (byte)((float)p->b * (1f - a) + (float)c.b * a); } } }