From 64b822b903247faa72802342ff63e35690b36f14 Mon Sep 17 00:00:00 2001 From: MaxED <j.maxed@gmail.com> Date: Wed, 30 Dec 2015 11:53:03 +0000 Subject: [PATCH] Implemented, TEXTURES: ZDoom can use any graphic as a texture patch. Fixed a typo. --- Source/Core/Config/ResourceTextureSet.cs | 2 +- Source/Core/Data/HighResImage.cs | 376 +++++++++++++---------- Source/Core/Editing/ThingsFilter.cs | 2 +- 3 files changed, 208 insertions(+), 172 deletions(-) diff --git a/Source/Core/Config/ResourceTextureSet.cs b/Source/Core/Config/ResourceTextureSet.cs index ca46c5f69..edaf0423c 100644 --- a/Source/Core/Config/ResourceTextureSet.cs +++ b/Source/Core/Config/ResourceTextureSet.cs @@ -73,7 +73,7 @@ namespace CodeImp.DoomBuilder.Config // Add a flat internal void AddFlat(ImageData image) { - if(flats.ContainsKey(image.LongName)) + if(flats.ContainsKey(image.LongName) && (!General.Map.Config.MixTexturesFlats || !image.HasPatchWithSameName)) General.ErrorLogger.Add(ErrorType.Warning, "Flat \"" + image.Name + "\" is double defined in resource \"" + this.Location.location + "\"."); flats[image.LongName] = image; } diff --git a/Source/Core/Data/HighResImage.cs b/Source/Core/Data/HighResImage.cs index 03a6b8524..c0b3bdbd1 100644 --- a/Source/Core/Data/HighResImage.cs +++ b/Source/Core/Data/HighResImage.cs @@ -129,7 +129,7 @@ namespace CodeImp.DoomBuilder.Data loadfailed = true; } - int failCount = 0; //mxd + int missingpatches = 0; //mxd if(!loadfailed) { @@ -157,11 +157,12 @@ namespace CodeImp.DoomBuilder.Data { reader = ImageDataFormat.GetImageReader(mem, ImageDataFormat.DOOMFLAT, General.Map.Data.Palette); } + if(reader is UnknownImageReader) { // Data is in an unknown format! General.ErrorLogger.Add(ErrorType.Error, "Patch lump '" + p.lumpname + "' data format could not be read, while loading texture '" + this.Name + "'"); - failCount++; //mxd + missingpatches++; //mxd } } @@ -175,176 +176,14 @@ namespace CodeImp.DoomBuilder.Data { // Data cannot be read! General.ErrorLogger.Add(ErrorType.Error, "Patch lump '" + p.lumpname + "' data format could not be read, while loading texture '" + this.Name + "'"); - failCount++; //mxd + missingpatches++; //mxd } + if(patchbmp != null) { - //mxd. Flip - if(p.flipx || p.flipy) - { - RotateFlipType flip; - if(p.flipx && !p.flipy) - flip = RotateFlipType.RotateNoneFlipX; - else if(!p.flipx && p.flipy) - flip = RotateFlipType.RotateNoneFlipY; - else - flip = RotateFlipType.RotateNoneFlipXY; - patchbmp.RotateFlip(flip); - } + //mxd. Apply transformations from TexturePatch + patchbmp = TransformPatch(p, patchbmp); - //mxd. Then rotate. I do it this way because RotateFlip function rotates THEN flips, and GZDoom does it the other way around. - if(p.rotate != 0) - { - RotateFlipType rotate; - switch(p.rotate) - { - case 90: rotate = RotateFlipType.Rotate90FlipNone; break; - case 180: rotate = RotateFlipType.Rotate180FlipNone; break; - default: rotate = RotateFlipType.Rotate270FlipNone; break; - } - patchbmp.RotateFlip(rotate); - } - - // Adjust patch alpha, apply tint or blend - if(p.blendstyle != TexturePathBlendStyle.None || p.style != TexturePathRenderStyle.Copy) - { - BitmapData bmpdata = null; - - try - { - bmpdata = patchbmp.LockBits(new Rectangle(0, 0, patchbmp.Size.Width, patchbmp.Size.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); - } - catch(Exception e) - { - General.ErrorLogger.Add(ErrorType.Error, "Cannot lock image '" + p.lumpname + "' for alpha adjustment. " + e.GetType().Name + ": " + e.Message); - } - - if(bmpdata != null) - { - PixelColor* pixels = (PixelColor*)(bmpdata.Scan0.ToPointer()); - int numpixels = bmpdata.Width * bmpdata.Height; - int patchalpha = (int)Math.Round(General.Clamp(p.alpha, 0f, 1f) * 255); //convert alpha to [0-255] range - - //mxd. Blend/Tint support - if(p.blendstyle == TexturePathBlendStyle.Blend) - { - for(PixelColor* cp = pixels + numpixels - 1; cp >= pixels; cp--) - { - cp->r = (byte)((cp->r * p.blend.r) * PixelColor.BYTE_TO_FLOAT); - cp->g = (byte)((cp->g * p.blend.g) * PixelColor.BYTE_TO_FLOAT); - cp->b = (byte)((cp->b * p.blend.b) * PixelColor.BYTE_TO_FLOAT); - } - } - else if(p.blendstyle == TexturePathBlendStyle.Tint) - { - float tintammount = p.tintammount - 0.1f; - - if(tintammount > 0) - { - float br = p.blend.r * PixelColor.BYTE_TO_FLOAT * tintammount; - float bg = p.blend.g * PixelColor.BYTE_TO_FLOAT * tintammount; - float bb = p.blend.b * PixelColor.BYTE_TO_FLOAT * tintammount; - float invTint = 1.0f - tintammount; - - for(PixelColor* cp = pixels + numpixels - 1; cp >= pixels; cp--) - { - cp->r = (byte)(((cp->r * PixelColor.BYTE_TO_FLOAT) * invTint + br) * 255.0f); - cp->g = (byte)(((cp->g * PixelColor.BYTE_TO_FLOAT) * invTint + bg) * 255.0f); - cp->b = (byte)(((cp->b * PixelColor.BYTE_TO_FLOAT) * invTint + bb) * 255.0f); - } - } - } - //mxd. apply RenderStyle - if(p.style == TexturePathRenderStyle.Blend) - { - for(PixelColor* cp = pixels + numpixels - 1; cp >= pixels; cp--) - cp->a = (byte)((cp->a * patchalpha) * PixelColor.BYTE_TO_FLOAT); - - - } - //mxd. we need a copy of underlying part of texture for these styles - else if(p.style != TexturePathRenderStyle.Copy) - { - //copy portion of texture - int lockWidth = (p.x + patchbmp.Size.Width > bitmap.Width) ? bitmap.Width - p.x : patchbmp.Size.Width; - int lockHeight = (p.y + patchbmp.Size.Height > bitmap.Height) ? bitmap.Height - p.y : patchbmp.Size.Height; - - Bitmap source = new Bitmap(patchbmp.Size.Width, patchbmp.Size.Height); - using(Graphics sg = Graphics.FromImage(source)) - sg.DrawImageUnscaled(bitmap, new Rectangle(-p.x, -p.y, lockWidth, lockHeight)); - - //lock texture - BitmapData texturebmpdata = null; - - try - { - texturebmpdata = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); - } - catch(Exception e) - { - General.ErrorLogger.Add(ErrorType.Error, "Cannot lock texture '" + this.Name + "' to apply render style. " + e.GetType().Name + ": " + e.Message); - } - - if(texturebmpdata != null) - { - PixelColor* texturepixels = (PixelColor*)(texturebmpdata.Scan0.ToPointer()); - PixelColor* tcp = texturepixels + numpixels - 1; - - switch(p.style) - { - case TexturePathRenderStyle.Add: - for(PixelColor* cp = pixels + numpixels - 1; cp >= pixels; cp--) - { - cp->r = (byte)Math.Min(255, cp->r + tcp->r); - cp->g = (byte)Math.Min(255, cp->g + tcp->g); - cp->b = (byte)Math.Min(255, cp->b + tcp->b); - cp->a = (byte)((cp->a * patchalpha) * PixelColor.BYTE_TO_FLOAT); - tcp--; - } - break; - - case TexturePathRenderStyle.Subtract: - for(PixelColor* cp = pixels + numpixels - 1; cp >= pixels; cp--) - { - cp->r = (byte)Math.Max(0, tcp->r - cp->r); - cp->g = (byte)Math.Max(0, tcp->g - cp->g); - cp->b = (byte)Math.Max(0, tcp->b - cp->b); - cp->a = (byte)((cp->a * patchalpha) * PixelColor.BYTE_TO_FLOAT); - tcp--; - } - break; - - case TexturePathRenderStyle.ReverseSubtract: - for(PixelColor* cp = pixels + numpixels - 1; cp >= pixels; cp--) - { - cp->r = (byte)Math.Max(0, cp->r - tcp->r); - cp->g = (byte)Math.Max(0, cp->g - tcp->g); - cp->b = (byte)Math.Max(0, cp->b - tcp->b); - cp->a = (byte)((cp->a * patchalpha) * PixelColor.BYTE_TO_FLOAT); - tcp--; - } - break; - - case TexturePathRenderStyle.Modulate: - for(PixelColor* cp = pixels + numpixels - 1; cp >= pixels; cp--) - { - cp->r = (byte)((cp->r * tcp->r) * PixelColor.BYTE_TO_FLOAT); - cp->g = (byte)((cp->g * tcp->g) * PixelColor.BYTE_TO_FLOAT); - cp->b = (byte)((cp->b * tcp->b) * PixelColor.BYTE_TO_FLOAT); - - tcp--; - } - break; - - } - - source.UnlockBits(texturebmpdata); - } - } - patchbmp.UnlockBits(bmpdata); - } - } - // Draw the patch on the texture image Rectangle tgtrect = new Rectangle(p.x, p.y, patchbmp.Size.Width, patchbmp.Size.Height); g.DrawImageUnscaledAndClipped(patchbmp, tgtrect); @@ -357,15 +196,35 @@ namespace CodeImp.DoomBuilder.Data } else { + //mxd. ZDoom can use any known graphic as patch + if(General.Map.Config.MixTexturesFlats) + { + ImageData img = General.Map.Data.GetTextureImage(p.lumpname); + if(!(img is UnknownImage)) + { + if(!img.IsImageLoaded) img.LoadImage(); + + //mxd. Apply transformations from TexturePatch. We don't want to modify the original bitmap here, so make a copy + Bitmap patchbmp = TransformPatch(p, new Bitmap(img.GetBitmap())); + + // Draw the patch on the texture image + Rectangle tgtrect = new Rectangle(p.x, p.y, patchbmp.Size.Width, patchbmp.Size.Height); + g.DrawImageUnscaledAndClipped(patchbmp, tgtrect); + patchbmp.Dispose(); + + continue; + } + } + // Missing a patch lump! General.ErrorLogger.Add(ErrorType.Error, "Missing patch lump '" + p.lumpname + "' while loading texture '" + this.Name + "'"); - failCount++; //mxd + missingpatches++; //mxd } } } // Dispose bitmap if load failed - if((bitmap != null) && (loadfailed || failCount >= patches.Count)) //mxd. We can still display texture if at least one of the patches was loaded + if((bitmap != null) && (loadfailed || missingpatches >= patches.Count)) //mxd. We can still display texture if at least one of the patches was loaded { bitmap.Dispose(); bitmap = null; @@ -377,6 +236,183 @@ namespace CodeImp.DoomBuilder.Data } } + //mxd + private Bitmap TransformPatch(TexturePatch p, Bitmap patchbmp) + { + //mxd. Flip + if(p.flipx || p.flipy) + { + RotateFlipType flip; + if(p.flipx && !p.flipy) + flip = RotateFlipType.RotateNoneFlipX; + else if(!p.flipx && p.flipy) + flip = RotateFlipType.RotateNoneFlipY; + else + flip = RotateFlipType.RotateNoneFlipXY; + patchbmp.RotateFlip(flip); + } + + //mxd. Then rotate. I do it this way because RotateFlip function rotates THEN flips, and GZDoom does it the other way around. + if(p.rotate != 0) + { + RotateFlipType rotate; + switch(p.rotate) + { + case 90: + rotate = RotateFlipType.Rotate90FlipNone; + break; + case 180: + rotate = RotateFlipType.Rotate180FlipNone; + break; + default: + rotate = RotateFlipType.Rotate270FlipNone; + break; + } + patchbmp.RotateFlip(rotate); + } + + // Adjust patch alpha, apply tint or blend + if(p.blendstyle != TexturePathBlendStyle.None || p.style != TexturePathRenderStyle.Copy) + { + BitmapData bmpdata = null; + + try + { + bmpdata = patchbmp.LockBits(new Rectangle(0, 0, patchbmp.Size.Width, patchbmp.Size.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); + } + catch(Exception e) + { + General.ErrorLogger.Add(ErrorType.Error, "Cannot lock image '" + p.lumpname + "' for alpha adjustment. " + e.GetType().Name + ": " + e.Message); + } + + if(bmpdata != null) + { + PixelColor* pixels = (PixelColor*)(bmpdata.Scan0.ToPointer()); + int numpixels = bmpdata.Width * bmpdata.Height; + int patchalpha = (int)Math.Round(General.Clamp(p.alpha, 0f, 1f) * 255); //convert alpha to [0-255] range + + //mxd. Blend/Tint support + if(p.blendstyle == TexturePathBlendStyle.Blend) + { + for(PixelColor* cp = pixels + numpixels - 1; cp >= pixels; cp--) + { + cp->r = (byte)((cp->r * p.blend.r) * PixelColor.BYTE_TO_FLOAT); + cp->g = (byte)((cp->g * p.blend.g) * PixelColor.BYTE_TO_FLOAT); + cp->b = (byte)((cp->b * p.blend.b) * PixelColor.BYTE_TO_FLOAT); + } + } + else if(p.blendstyle == TexturePathBlendStyle.Tint) + { + float tintammount = p.tintammount - 0.1f; + + if(tintammount > 0) + { + float br = p.blend.r * PixelColor.BYTE_TO_FLOAT * tintammount; + float bg = p.blend.g * PixelColor.BYTE_TO_FLOAT * tintammount; + float bb = p.blend.b * PixelColor.BYTE_TO_FLOAT * tintammount; + float invTint = 1.0f - tintammount; + + for(PixelColor* cp = pixels + numpixels - 1; cp >= pixels; cp--) + { + cp->r = (byte)(((cp->r * PixelColor.BYTE_TO_FLOAT) * invTint + br) * 255.0f); + cp->g = (byte)(((cp->g * PixelColor.BYTE_TO_FLOAT) * invTint + bg) * 255.0f); + cp->b = (byte)(((cp->b * PixelColor.BYTE_TO_FLOAT) * invTint + bb) * 255.0f); + } + } + } + + //mxd. Apply RenderStyle + if(p.style == TexturePathRenderStyle.Blend) + { + for(PixelColor* cp = pixels + numpixels - 1; cp >= pixels; cp--) + cp->a = (byte)((cp->a * patchalpha) * PixelColor.BYTE_TO_FLOAT); + } + //mxd. We need a copy of underlying part of texture for these styles + else if(p.style != TexturePathRenderStyle.Copy) + { + // Copy portion of texture + int lockWidth = (p.x + patchbmp.Size.Width > bitmap.Width) ? bitmap.Width - p.x : patchbmp.Size.Width; + int lockHeight = (p.y + patchbmp.Size.Height > bitmap.Height) ? bitmap.Height - p.y : patchbmp.Size.Height; + + Bitmap source = new Bitmap(patchbmp.Size.Width, patchbmp.Size.Height); + using(Graphics sg = Graphics.FromImage(source)) + sg.DrawImageUnscaled(bitmap, new Rectangle(-p.x, -p.y, lockWidth, lockHeight)); + + // Lock texture + BitmapData texturebmpdata = null; + + try + { + texturebmpdata = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); + } + catch(Exception e) + { + General.ErrorLogger.Add(ErrorType.Error, "Cannot lock texture '" + this.Name + "' to apply render style. " + e.GetType().Name + ": " + e.Message); + } + + if(texturebmpdata != null) + { + PixelColor* texturepixels = (PixelColor*)(texturebmpdata.Scan0.ToPointer()); + PixelColor* tcp = texturepixels + numpixels - 1; + + switch(p.style) + { + case TexturePathRenderStyle.Add: + for(PixelColor* cp = pixels + numpixels - 1; cp >= pixels; cp--) + { + cp->r = (byte)Math.Min(255, cp->r + tcp->r); + cp->g = (byte)Math.Min(255, cp->g + tcp->g); + cp->b = (byte)Math.Min(255, cp->b + tcp->b); + cp->a = (byte)((cp->a * patchalpha) * PixelColor.BYTE_TO_FLOAT); + tcp--; + } + break; + + case TexturePathRenderStyle.Subtract: + for(PixelColor* cp = pixels + numpixels - 1; cp >= pixels; cp--) + { + cp->r = (byte)Math.Max(0, tcp->r - cp->r); + cp->g = (byte)Math.Max(0, tcp->g - cp->g); + cp->b = (byte)Math.Max(0, tcp->b - cp->b); + cp->a = (byte)((cp->a * patchalpha) * PixelColor.BYTE_TO_FLOAT); + tcp--; + } + break; + + case TexturePathRenderStyle.ReverseSubtract: + for(PixelColor* cp = pixels + numpixels - 1; cp >= pixels; cp--) + { + cp->r = (byte)Math.Max(0, cp->r - tcp->r); + cp->g = (byte)Math.Max(0, cp->g - tcp->g); + cp->b = (byte)Math.Max(0, cp->b - tcp->b); + cp->a = (byte)((cp->a * patchalpha) * PixelColor.BYTE_TO_FLOAT); + tcp--; + } + break; + + case TexturePathRenderStyle.Modulate: + for(PixelColor* cp = pixels + numpixels - 1; cp >= pixels; cp--) + { + cp->r = (byte)((cp->r * tcp->r) * PixelColor.BYTE_TO_FLOAT); + cp->g = (byte)((cp->g * tcp->g) * PixelColor.BYTE_TO_FLOAT); + cp->b = (byte)((cp->b * tcp->b) * PixelColor.BYTE_TO_FLOAT); + tcp--; + } + break; + + } + + source.UnlockBits(texturebmpdata); + } + } + + patchbmp.UnlockBits(bmpdata); + } + } + + return patchbmp; + } + #endregion } } diff --git a/Source/Core/Editing/ThingsFilter.cs b/Source/Core/Editing/ThingsFilter.cs index d8a2e5535..872518e31 100644 --- a/Source/Core/Editing/ThingsFilter.cs +++ b/Source/Core/Editing/ThingsFilter.cs @@ -272,7 +272,7 @@ namespace CodeImp.DoomBuilder.Editing //Integrity check if(!IsValid()) - General.ErrorLogger.Add(ErrorType.Warning, "Things filter '" + name + "' has invalid properties. Configure the thing filter to fix this!"); + General.ErrorLogger.Add(ErrorType.Warning, "Things filter '" + name + "' has invalid properties. Configure the things filter to fix this!"); } //mxd -- GitLab