diff --git a/Build/Configurations/Includes/ZDoom_linedefs.cfg b/Build/Configurations/Includes/ZDoom_linedefs.cfg index 8176a7bf..56ad3112 100644 --- a/Build/Configurations/Includes/ZDoom_linedefs.cfg +++ b/Build/Configurations/Includes/ZDoom_linedefs.cfg @@ -3372,7 +3372,7 @@ zdoom { 1 = "Disable light effects"; 2 = "Restrict light inside"; - 4 = "Fog effect (GZDoom) / Fade effect (ZDoom)"; + 4 = "Fog effect (GZDoom only)"; 8 = "Ignore bottom height"; 16 = "Use upper texture"; 32 = "Use lower texture"; diff --git a/Source/Core/Builder.csproj b/Source/Core/Builder.csproj index 019fc99d..55ca8445 100644 --- a/Source/Core/Builder.csproj +++ b/Source/Core/Builder.csproj @@ -1021,6 +1021,7 @@ + diff --git a/Source/Core/Config/ScriptConfiguration.cs b/Source/Core/Config/ScriptConfiguration.cs index 602317f1..1d73c45a 100644 --- a/Source/Core/Config/ScriptConfiguration.cs +++ b/Source/Core/Config/ScriptConfiguration.cs @@ -42,6 +42,7 @@ namespace CodeImp.DoomBuilder.Config ANIMDEFS = 9, REVERBS = 10, TERRAIN = 11, + X11R6RGB = 12, } internal class ScriptConfiguration : IComparable diff --git a/Source/Core/Data/DataManager.cs b/Source/Core/Data/DataManager.cs index d55087b4..c7d7358b 100644 --- a/Source/Core/Data/DataManager.cs +++ b/Source/Core/Data/DataManager.cs @@ -97,6 +97,7 @@ namespace CodeImp.DoomBuilder.Data private string[] soundsequences; private string[] terrainnames; private string[] damagetypes; + private Dictionary knowncolors; // Colors parsed from X11R6RGB lump. Color names are lowercase without spaces //mxd. Text resources private Dictionary> textresources; @@ -156,6 +157,7 @@ namespace CodeImp.DoomBuilder.Data public string[] SoundSequences { get { return soundsequences; } } public string[] TerrainNames { get { return terrainnames; } } public string[] DamageTypes { get { return damagetypes; } } + public Dictionary KnownColors { get { return knowncolors; } } internal Dictionary> TextResources { get { return textresources; } } //mxd @@ -326,6 +328,7 @@ namespace CodeImp.DoomBuilder.Data terrainnames = new string[0]; textresources = new Dictionary>(); damagetypes = new string[0]; + knowncolors = new Dictionary(StringComparer.OrdinalIgnoreCase); // Load texture sets foreach(DefinedTextureSet ts in General.Map.ConfigSettings.TextureSets) @@ -386,6 +389,7 @@ namespace CodeImp.DoomBuilder.Data } // Load stuff + LoadX11R6RGB(); //mxd LoadPalette(); Dictionary cachedparsers = new Dictionary(); //mxd int texcount = LoadTextures(texturesonly, texturenamesshorttofull, cachedparsers); @@ -588,6 +592,7 @@ namespace CodeImp.DoomBuilder.Data terrainnames = null; //mxd textresources = null; //mxd damagetypes = null; //mxd + knowncolors = null; //mxd texturenames = null; flatnames = null; imageque = null; @@ -801,10 +806,7 @@ namespace CodeImp.DoomBuilder.Data } while(true); } - catch(ThreadInterruptedException) - { - return; - } + catch(ThreadInterruptedException) { } } // This adds an image for background loading or unloading @@ -2460,6 +2462,34 @@ namespace CodeImp.DoomBuilder.Data terrainnames = names.ToArray(); } + //mxd. This loads X11R6RGB + private void LoadX11R6RGB() + { + X11R6RGBParser parser = new X11R6RGBParser(); + + foreach(DataReader dr in containers) + { + currentreader = dr; + IEnumerable streams = dr.GetX11R6RGBData(); + + // Parse the data + foreach(TextResourceData data in streams) + { + parser.Parse(data, true); + + // Report errors? + if(parser.HasError) parser.LogError(); + } + } + + // Add to text resources collection + textresources[parser.ScriptType] = new HashSet(parser.TextResources.Values); + currentreader = null; + + // Set as collection + knowncolors = parser.KnownColors; + } + //mxd internal TextResourceData GetTextResourceData(string name) { diff --git a/Source/Core/Data/DataReader.cs b/Source/Core/Data/DataReader.cs index cfb2a870..fa4c9d20 100644 --- a/Source/Core/Data/DataReader.cs +++ b/Source/Core/Data/DataReader.cs @@ -240,6 +240,9 @@ namespace CodeImp.DoomBuilder.Data //mxd. When implemented, this returns the TERRAIN lump public abstract IEnumerable GetTerrainData(); + //mxd. When implemented, this returns the X11R6RGB lump + public abstract IEnumerable GetX11R6RGBData(); + //mxd. When implemented, this returns the list of voxel model names public abstract IEnumerable GetVoxelNames(); diff --git a/Source/Core/Data/PK3StructuredReader.cs b/Source/Core/Data/PK3StructuredReader.cs index 913dc57b..f73ff012 100644 --- a/Source/Core/Data/PK3StructuredReader.cs +++ b/Source/Core/Data/PK3StructuredReader.cs @@ -701,7 +701,6 @@ namespace CodeImp.DoomBuilder.Data #region ================== TERRAIN (mxd) - //mxd public override IEnumerable GetTerrainData() { // Error when suspended @@ -722,6 +721,28 @@ namespace CodeImp.DoomBuilder.Data #endregion + #region ================== XBRSBSBB11 (mxd) + + public override IEnumerable GetX11R6RGBData() + { + // Error when suspended + if(issuspended) throw new Exception("Data reader is suspended"); + + List result = new List(); + string[] files = GetAllFilesWithTitle("", "X11R6RGB", false); + + // Add to collection + foreach(string s in files) + result.Add(new TextResourceData(this, LoadFile(s), s, true)); + + // Find in any of the wad files + foreach(WADReader wr in wads) result.AddRange(wr.GetTerrainData()); + + return result; + } + + #endregion + #region ================== Methods // This loads the images in this directory diff --git a/Source/Core/Data/TEXTURESImage.cs b/Source/Core/Data/TEXTURESImage.cs index c39986bd..857e11f7 100644 --- a/Source/Core/Data/TEXTURESImage.cs +++ b/Source/Core/Data/TEXTURESImage.cs @@ -98,7 +98,7 @@ namespace CodeImp.DoomBuilder.Data { // Add it patches.Add(patch); - if(patch.lumpname == Name) hasPatchWithSameName = true; //mxd + if(patch.LumpName == Name) hasPatchWithSameName = true; //mxd } // This loads the image @@ -143,11 +143,11 @@ namespace CodeImp.DoomBuilder.Data foreach(TexturePatch p in patches) { //mxd. Some patches (like "TNT1A0") should be skipped - if(p.skip) continue; + if(p.Skip) continue; // Get the patch data stream string patchlocation = string.Empty; //mxd - Stream patchdata = General.Map.Data.GetPatchData(p.lumpname, p.haslongname, ref patchlocation); + Stream patchdata = General.Map.Data.GetPatchData(p.LumpName, p.HasLongName, ref patchlocation); if(patchdata != null) { // Copy patch data to memory @@ -170,7 +170,7 @@ namespace CodeImp.DoomBuilder.Data if(reader is UnknownImageReader) { // Data is in an unknown format! - General.ErrorLogger.Add(ErrorType.Error, "Patch lump \"" + Path.Combine(patchlocation, p.lumpname) + "\" data format could not be read, while loading texture \"" + this.Name + "\""); + General.ErrorLogger.Add(ErrorType.Error, "Patch lump \"" + Path.Combine(patchlocation, p.LumpName) + "\" data format could not be read, while loading texture \"" + this.Name + "\""); missingpatches++; //mxd } } @@ -184,7 +184,7 @@ namespace CodeImp.DoomBuilder.Data catch(InvalidDataException) { // Data cannot be read! - General.ErrorLogger.Add(ErrorType.Error, "Patch lump \"" + p.lumpname + "\" data format could not be read, while loading texture \"" + this.Name + "\""); + General.ErrorLogger.Add(ErrorType.Error, "Patch lump \"" + p.LumpName + "\" data format could not be read, while loading texture \"" + this.Name + "\""); missingpatches++; //mxd } @@ -194,7 +194,7 @@ namespace CodeImp.DoomBuilder.Data patchbmp = TransformPatch(p, patchbmp); // Draw the patch on the texture image - Rectangle tgtrect = new Rectangle(p.x, p.y, patchbmp.Size.Width, patchbmp.Size.Height); + Rectangle tgtrect = new Rectangle(p.X, p.Y, patchbmp.Size.Width, patchbmp.Size.Height); g.DrawImageUnscaledAndClipped(patchbmp, tgtrect); patchbmp.Dispose(); } @@ -208,7 +208,7 @@ namespace CodeImp.DoomBuilder.Data //mxd. ZDoom can use any known graphic as patch if(General.Map.Config.MixTexturesFlats) { - ImageData img = General.Map.Data.GetTextureImage(p.lumpname); + ImageData img = General.Map.Data.GetTextureImage(p.LumpName); if(!(img is UnknownImage) && img != this) { if(!img.IsImageLoaded) img.LoadImage(); @@ -217,7 +217,7 @@ namespace CodeImp.DoomBuilder.Data 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); + Rectangle tgtrect = new Rectangle(p.X, p.Y, patchbmp.Size.Width, patchbmp.Size.Height); g.DrawImageUnscaledAndClipped(patchbmp, tgtrect); patchbmp.Dispose(); @@ -226,7 +226,7 @@ namespace CodeImp.DoomBuilder.Data } // Missing a patch lump! - General.ErrorLogger.Add(ErrorType.Error, "Missing patch lump \"" + p.lumpname + "\" while loading texture \"" + this.Name + "\""); + General.ErrorLogger.Add(ErrorType.Error, "Missing patch lump \"" + p.LumpName + "\" while loading texture \"" + this.Name + "\""); missingpatches++; //mxd } } @@ -249,20 +249,20 @@ namespace CodeImp.DoomBuilder.Data private Bitmap TransformPatch(TexturePatch p, Bitmap patchbmp) { //mxd. Flip - if(p.flipx || p.flipy) + if(p.FlipX || p.FlipY) { RotateFlipType flip; - if(p.flipx && !p.flipy) flip = RotateFlipType.RotateNoneFlipX; - else if(!p.flipx && p.flipy) flip = RotateFlipType.RotateNoneFlipY; + 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) + if(p.Rotate != 0) { RotateFlipType rotate; - switch(p.rotate) + switch(p.Rotate) { case 90: rotate = RotateFlipType.Rotate90FlipNone; break; case 180: rotate = RotateFlipType.Rotate180FlipNone; break; @@ -272,7 +272,7 @@ namespace CodeImp.DoomBuilder.Data } // Adjust patch alpha, apply tint or blend - if(p.blendstyle != TexturePathBlendStyle.None || p.style != TexturePathRenderStyle.Copy) + if(p.BlendStyle != TexturePathBlendStyle.NONE || p.RenderStyle != TexturePathRenderStyle.COPY) { BitmapData bmpdata = null; @@ -282,61 +282,61 @@ namespace CodeImp.DoomBuilder.Data } catch(Exception e) { - General.ErrorLogger.Add(ErrorType.Error, "Cannot lock image \"" + p.lumpname + "\" for alpha adjustment. " + e.GetType().Name + ": " + e.Message); + 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 + 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) + 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); + cp->r = (byte)((cp->r * p.BlendColor.r) * PixelColor.BYTE_TO_FLOAT); + cp->g = (byte)((cp->g * p.BlendColor.g) * PixelColor.BYTE_TO_FLOAT); + cp->b = (byte)((cp->b * p.BlendColor.b) * PixelColor.BYTE_TO_FLOAT); } } - else if(p.blendstyle == TexturePathBlendStyle.Tint) + else if(p.BlendStyle == TexturePathBlendStyle.TINT) { - float tintammount = p.tintammount - 0.1f; + float tintammount = p.BlendColor.a * PixelColor.BYTE_TO_FLOAT;// -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; + float br = p.BlendColor.r * PixelColor.BYTE_TO_FLOAT * tintammount; + float bg = p.BlendColor.g * PixelColor.BYTE_TO_FLOAT * tintammount; + float bb = p.BlendColor.b * PixelColor.BYTE_TO_FLOAT * tintammount; + float invtintammount = 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); + cp->r = (byte)(((cp->r * PixelColor.BYTE_TO_FLOAT) * invtintammount + br) * 255.0f); + cp->g = (byte)(((cp->g * PixelColor.BYTE_TO_FLOAT) * invtintammount + bg) * 255.0f); + cp->b = (byte)(((cp->b * PixelColor.BYTE_TO_FLOAT) * invtintammount + bb) * 255.0f); } } } //mxd. Apply RenderStyle - if(p.style == TexturePathRenderStyle.Blend) + if(p.RenderStyle == 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) + else if(p.RenderStyle != 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; + 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)); + sg.DrawImageUnscaled(bitmap, new Rectangle(-p.X, -p.Y, lockWidth, lockHeight)); // Lock texture BitmapData texturebmpdata = null; @@ -355,9 +355,9 @@ namespace CodeImp.DoomBuilder.Data PixelColor* texturepixels = (PixelColor*)(texturebmpdata.Scan0.ToPointer()); PixelColor* tcp = texturepixels + numpixels - 1; - switch(p.style) + switch(p.RenderStyle) { - case TexturePathRenderStyle.Add: + case TexturePathRenderStyle.ADD: for(PixelColor* cp = pixels + numpixels - 1; cp >= pixels; cp--) { cp->r = (byte)Math.Min(255, cp->r + tcp->r); @@ -368,7 +368,7 @@ namespace CodeImp.DoomBuilder.Data } break; - case TexturePathRenderStyle.Subtract: + case TexturePathRenderStyle.SUBTRACT: for(PixelColor* cp = pixels + numpixels - 1; cp >= pixels; cp--) { cp->r = (byte)Math.Max(0, tcp->r - cp->r); @@ -379,7 +379,7 @@ namespace CodeImp.DoomBuilder.Data } break; - case TexturePathRenderStyle.ReverseSubtract: + case TexturePathRenderStyle.REVERSE_SUBTRACT: for(PixelColor* cp = pixels + numpixels - 1; cp >= pixels; cp--) { cp->r = (byte)Math.Max(0, cp->r - tcp->r); @@ -390,7 +390,7 @@ namespace CodeImp.DoomBuilder.Data } break; - case TexturePathRenderStyle.Modulate: + case TexturePathRenderStyle.MODULATE: for(PixelColor* cp = pixels + numpixels - 1; cp >= pixels; cp--) { cp->r = (byte)((cp->r * tcp->r) * PixelColor.BYTE_TO_FLOAT); diff --git a/Source/Core/Data/TextureImage.cs b/Source/Core/Data/TextureImage.cs index 3866974d..cd110dc3 100644 --- a/Source/Core/Data/TextureImage.cs +++ b/Source/Core/Data/TextureImage.cs @@ -64,7 +64,7 @@ namespace CodeImp.DoomBuilder.Data // Add it patches.Add(patch); - if(patch.lumpname == Name) hasPatchWithSameName = true; //mxd + if(patch.LumpName == Name) hasPatchWithSameName = true; //mxd } // This loads the image @@ -103,7 +103,7 @@ namespace CodeImp.DoomBuilder.Data { // Get the patch data stream string patchlocation = string.Empty; //mxd - Stream patchdata = General.Map.Data.GetPatchData(p.lumpname, p.haslongname, ref patchlocation); + Stream patchdata = General.Map.Data.GetPatchData(p.LumpName, p.HasLongName, ref patchlocation); if(patchdata != null) { // Copy patch data to memory @@ -125,7 +125,7 @@ namespace CodeImp.DoomBuilder.Data if(reader is UnknownImageReader) { // Data is in an unknown format! - General.ErrorLogger.Add(ErrorType.Error, "Patch lump \"" + Path.Combine(patchlocation, p.lumpname) + "\" data format could not be read, while loading texture \"" + this.Name + "\". Does this lump contain valid picture data at all?"); + General.ErrorLogger.Add(ErrorType.Error, "Patch lump \"" + Path.Combine(patchlocation, p.LumpName) + "\" data format could not be read, while loading texture \"" + this.Name + "\". Does this lump contain valid picture data at all?"); loadfailed = true; missingpatches++; //mxd } @@ -135,11 +135,11 @@ namespace CodeImp.DoomBuilder.Data { // Draw the patch mem.Seek(0, SeekOrigin.Begin); - try { reader.DrawToPixelData(mem, pixels, width, height, p.x, p.y); } + try { reader.DrawToPixelData(mem, pixels, width, height, p.X, p.Y); } catch(InvalidDataException) { // Data cannot be read! - General.ErrorLogger.Add(ErrorType.Error, "Patch lump \"" + p.lumpname + "\" data format could not be read, while loading texture \"" + this.Name + "\". Does this lump contain valid picture data at all?"); + General.ErrorLogger.Add(ErrorType.Error, "Patch lump \"" + p.LumpName + "\" data format could not be read, while loading texture \"" + this.Name + "\". Does this lump contain valid picture data at all?"); loadfailed = true; missingpatches++; //mxd } @@ -151,7 +151,7 @@ namespace CodeImp.DoomBuilder.Data else { // Missing a patch lump! - General.ErrorLogger.Add(ErrorType.Error, "Missing patch lump \"" + p.lumpname + "\" while loading texture \"" + this.Name + "\". Did you forget to include required resources?"); + General.ErrorLogger.Add(ErrorType.Error, "Missing patch lump \"" + p.LumpName + "\" while loading texture \"" + this.Name + "\". Did you forget to include required resources?"); loadfailed = true; missingpatches++; //mxd } diff --git a/Source/Core/Data/TexturePatch.cs b/Source/Core/Data/TexturePatch.cs index 1d71d24a..7820cc28 100644 --- a/Source/Core/Data/TexturePatch.cs +++ b/Source/Core/Data/TexturePatch.cs @@ -26,93 +26,90 @@ namespace CodeImp.DoomBuilder.Data { public enum TexturePathRenderStyle { - Copy, - Blend, - Add, - Subtract, - ReverseSubtract, - Modulate, - CopyAlpha, - CopyNewAlpha, //mxd - Overlay, //mxd + COPY, + BLEND, + ADD, + SUBTRACT, + REVERSE_SUBTRACT, + MODULATE, + COPY_ALPHA, + COPY_NEW_ALPHA, //mxd + OVERLAY, //mxd } public enum TexturePathBlendStyle //mxd { - None, - Blend, - Tint + NONE, + BLEND, + TINT } internal struct TexturePatch { - public readonly string lumpname; - public readonly int x; - public readonly int y; - public readonly bool flipx; - public readonly bool flipy; - public readonly bool haslongname; //mxd - public readonly int rotate; - public PixelColor blend; - public readonly float alpha; - public readonly TexturePathRenderStyle style; - public readonly TexturePathBlendStyle blendstyle; //mxd - public readonly float tintammount;//mxd - public readonly bool skip; //mxd + public readonly string LumpName; + public readonly int X; + public readonly int Y; + public readonly bool FlipX; + public readonly bool FlipY; + public readonly bool HasLongName; //mxd + public readonly int Rotate; + public PixelColor BlendColor; + public readonly float Alpha; + public readonly TexturePathRenderStyle RenderStyle; + public readonly TexturePathBlendStyle BlendStyle; //mxd + public readonly bool Skip; //mxd // Constructor for simple patches public TexturePatch(string lumpname, int x, int y) { // Initialize - this.lumpname = lumpname; - this.x = x; - this.y = y; - this.flipx = false; - this.flipy = false; - this.rotate = 0; - this.blend = new PixelColor(0, 0, 0, 0); - this.alpha = 1.0f; - this.style = TexturePathRenderStyle.Copy; - this.blendstyle = TexturePathBlendStyle.None;//mxd - this.tintammount = 0; //mxd - this.haslongname = false; //mxd - this.skip = false; //mxd + this.LumpName = lumpname; + this.X = x; + this.Y = y; + this.FlipX = false; + this.FlipY = false; + this.Rotate = 0; + this.BlendColor = new PixelColor(0, 0, 0, 0); + this.Alpha = 1.0f; + this.RenderStyle = TexturePathRenderStyle.COPY; + this.BlendStyle = TexturePathBlendStyle.NONE;//mxd + this.HasLongName = false; //mxd + this.Skip = false; //mxd } //mxd. Constructor for hires patches public TexturePatch(PatchStructure patch) { // Initialize - this.lumpname = patch.Name.ToUpperInvariant(); - this.x = patch.OffsetX; - this.y = patch.OffsetY; - this.flipx = patch.FlipX; - this.flipy = patch.FlipY; - this.rotate = patch.Rotation; - this.blend = patch.BlendColor; - this.alpha = patch.Alpha; - this.style = patch.RenderStyle; - this.blendstyle = patch.BlendStyle; - this.tintammount = patch.TintAmmount; - this.haslongname = (Path.GetFileNameWithoutExtension(this.lumpname) != this.lumpname); - this.skip = patch.Skip; + this.LumpName = patch.Name.ToUpperInvariant(); + this.X = patch.OffsetX; + this.Y = patch.OffsetY; + this.FlipX = patch.FlipX; + this.FlipY = patch.FlipY; + this.Rotate = patch.Rotation; + this.BlendColor = patch.BlendColor; + this.Alpha = patch.Alpha; + this.RenderStyle = patch.RenderStyle; + this.BlendStyle = patch.BlendStyle; + this.HasLongName = (Path.GetFileNameWithoutExtension(this.LumpName) != this.LumpName); + this.Skip = patch.Skip; //mxd. Check data so we don't perform unneeded operations later on - if(this.alpha == 1.0f) + if(this.Alpha == 1.0f) { - switch(this.style) + switch(this.RenderStyle) { - case TexturePathRenderStyle.Blend: - case TexturePathRenderStyle.CopyAlpha: - case TexturePathRenderStyle.CopyNewAlpha: - case TexturePathRenderStyle.Overlay: - this.style = TexturePathRenderStyle.Copy; + case TexturePathRenderStyle.BLEND: + case TexturePathRenderStyle.COPY_ALPHA: + case TexturePathRenderStyle.COPY_NEW_ALPHA: + case TexturePathRenderStyle.OVERLAY: + this.RenderStyle = TexturePathRenderStyle.COPY; break; } } //mxd. and get rid of render styles we don't support - if(this.style == TexturePathRenderStyle.Overlay) this.style = TexturePathRenderStyle.Copy; + if(this.RenderStyle == TexturePathRenderStyle.OVERLAY) this.RenderStyle = TexturePathRenderStyle.COPY; } } } diff --git a/Source/Core/Data/WADReader.cs b/Source/Core/Data/WADReader.cs index 51591f63..a79b52ee 100644 --- a/Source/Core/Data/WADReader.cs +++ b/Source/Core/Data/WADReader.cs @@ -1015,6 +1015,13 @@ namespace CodeImp.DoomBuilder.Data return GetAllLumps("TERRAIN"); } + //mxd + public override IEnumerable GetX11R6RGBData() + { + if(issuspended) throw new Exception("Data reader is suspended"); + return GetAllLumps("X11R6RGB"); + } + //mxd private IEnumerable GetFirstLump(string name) { diff --git a/Source/Core/GZBuilder/GZDoom/MapinfoParser.cs b/Source/Core/GZBuilder/GZDoom/MapinfoParser.cs index 1d3b76a4..9ab80845 100644 --- a/Source/Core/GZBuilder/GZDoom/MapinfoParser.cs +++ b/Source/Core/GZBuilder/GZDoom/MapinfoParser.cs @@ -2,12 +2,11 @@ using System; using System.Collections.Generic; -using System.Drawing; using System.Globalization; using System.IO; using CodeImp.DoomBuilder.Config; using CodeImp.DoomBuilder.Data; -using SlimDX; +using CodeImp.DoomBuilder.Rendering; using CodeImp.DoomBuilder.ZDoom; using CodeImp.DoomBuilder.GZBuilder.Data; @@ -607,16 +606,15 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom ReportError("Expected " + fadetype + " color value"); return false; } - - Color4 color = new Color4(); // Try to get the color... - if(GetColor(colorval, ref color)) + PixelColor color = new PixelColor(); + if(GetColorFromString(colorval, ref color)) { if(fadetype == "fade") - mapinfo.FadeColor = color; + mapinfo.FadeColor = color.ToColorValue(); else - mapinfo.OutsideFogColor = color; + mapinfo.OutsideFogColor = color.ToColorValue(); } else //...or not { @@ -687,30 +685,5 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom #endregion - #region ================== Methods - - private static bool GetColor(string name, ref Color4 color) - { - if(name == "black") return true; - - //probably it's a hex color (like FFCC11)? - int ci; - if(int.TryParse(name, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ci)) - { - color = new Color4(ci) {Alpha = 1.0f}; - return true; - } - - //probably it's a color name? - Color c = Color.FromName(name); //should be similar to C++ color name detection, I suppose - if(c.IsKnownColor) - { - color = new Color4(c); - return true; - } - return false; - } - - #endregion } } diff --git a/Source/Core/GZBuilder/Windows/ExceptionDialog.cs b/Source/Core/GZBuilder/Windows/ExceptionDialog.cs index bb71e7e7..283e8e67 100644 --- a/Source/Core/GZBuilder/Windows/ExceptionDialog.cs +++ b/Source/Core/GZBuilder/Windows/ExceptionDialog.cs @@ -12,34 +12,34 @@ namespace CodeImp.DoomBuilder.GZBuilder.Windows { public partial class ExceptionDialog : Form { - private readonly bool cannotContinue; - private readonly string logPath; + private readonly bool isterminating; + private readonly string logpath; public ExceptionDialog(UnhandledExceptionEventArgs e) { InitializeComponent(); - logPath = Path.Combine(General.SettingsPath, @"GZCrash.txt"); + logpath = Path.Combine(General.SettingsPath, @"GZCrash.txt"); Exception ex = (Exception)e.ExceptionObject; errorDescription.Text = "Error in " + ex.Source + ":"; string sysinfo = GetSystemInfo(); - using(StreamWriter sw = File.CreateText(logPath)) + using(StreamWriter sw = File.CreateText(logpath)) { sw.Write(sysinfo + GetExceptionDescription(ex)); } errorMessage.Text = ex.Message + Environment.NewLine + ex.StackTrace; - cannotContinue = true; //cannot recover from this... + isterminating = e.IsTerminating; // Recoverable? } public ExceptionDialog(ThreadExceptionEventArgs e) { InitializeComponent(); - logPath = Path.Combine(General.SettingsPath, @"GZCrash.txt"); + logpath = Path.Combine(General.SettingsPath, @"GZCrash.txt"); errorDescription.Text = "Error in " + e.Exception.Source + ":"; string sysinfo = GetSystemInfo(); - using(StreamWriter sw = File.CreateText(logPath)) + using(StreamWriter sw = File.CreateText(logpath)) { sw.Write(sysinfo + GetExceptionDescription(e.Exception)); } @@ -50,78 +50,92 @@ namespace CodeImp.DoomBuilder.GZBuilder.Windows public void Setup() { - bContinue.Enabled = !cannotContinue; + string[] titles = + { + "0x000000 at 0xFFFFFF. That's probaby bad", + "Here we go again...", + "Uh oh, you're screwed", + "All is lost!", + "Achievement unlocked: CRASH TIME!", + "OH NOES! TEH ERROR!", + "0001000001111011000000000011001101011120110111", + "Nuclear launch detected!", + "Don't send this to Microsoft", + "You. Shall. Not. Pass!!!", + "Yep, we have bugs", + "It's dangerous to go alone. Take this!", + "The operation completed successfully", + "Security Alert – Moving cursor is not as safe as you thought", + "Random error appears from north", + "ERROR: NO_ERROR", + "Epic fail", + "At least it's not BSoD...", + "User Error. Please Replace User", + "Brought to you by MaxED!", + "GZDoom Builder proudly presents:", + "You aren't expected to understand this", + "Back to the drawing board...", + "I'm sorry... :(", + "This is a horrbble day for you, and of course, the world", + "Abort, Retry, Fail?", + "You are making progress. I'm afraid that's something I can't allow to happen", + "You are making progress. That's not OK", + "No errors found, restarting computer", + "Does Not Compute!", + "I’m sorry, Dave, I’m afraid I can’t do that", + "What's that? Chicken?", + "It can only be attributable to human error", + "It's now safe to turn off your computer", + "I've got a bad feeling about this", + "YOU CAN’T DO THAT!", + "Man the Lifeboats! Women and children first!", + "IMPOSSIBURU!!!", + "Now deleting all files. Goodbye", + "General Failure", + "Invalid Error", + "Beam me up Scotty, there’s no life out here", + "Well, you ran into something and the game is over", + "I'm good at writing bad code", + "$FUNNY_ERROR_CAPTION", + "In Soviet Russia, exception throws YOU!", + "...and then GZDB was the demons!", + "B U S T E D", + "Freeze mode enabled", + "You feel strange...", + "That doesn't seem to work", + "This function is only available in the retail version of GZDoom Builder", + "You picked up the Random Exception.", + "Pinky says that you're the new hope. Bear that in mind.", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "Deal with it", + "Error 47", + "YOU DIED", + "Thanks, Obama", + "The God Of Exceptions Demands MORE Exceptions!", + "Good. It's boring here anyway.", + "Shameful display!", + "It's CRASHENING!", + "W-W-W-WIPEOUT!", + "EVERYTHING IS LOST!", + "Your empty is full!", + "Let's see how far this infinite loop goes...", + "Windows 10 is here! RUN!", + "You really screwed up this time!", + "[WFDS]", + "[No]", + "An error has occurred while creating an error", + "Catastrophic failure", + "This time, it’s the human’s fault", + "No error occurred", + "Hey! It looks like you're having an error!", + "What, what, what, what, what, what, what, what, what, what?", + "WARNING: PROGRAMMING BUG IN GZDB!", + "Something happened", + "The Device is Error", + }; - string[] titles = { - "0x000000 at 0xFFFFFF. That's probaby bad", - "Here we go again...", - "Uh oh, you're screwed", - "All is lost!", - "Achievement unlocked: CRASH TIME!", - "OH NOES! TEH ERROR!", - "0001000001111011000000000011001101011110110111", - "Nuclear launch detected!", - "Don't send this to Microsoft", - "You. Shall. Not. Pass!!!", - "Yep, we have bugs", - "It's dangerous to go alone. Take this!", - "The operation completed successfully", - "Security Alert – Moving cursor is not as safe as you thought", - "Random error appears from north", - "ERROR: NO_ERROR", - "Epic fail", - "At least it's not BSoD...", - "User Error. Please Replace User", - "Brought to you by MaxED!", - "GZDoom Builder proudly presents:", - "You aren't expected to understand this", - "Back to the drawing board...", - "I'm sorry... :(", - "This is a horrbble day for you, and of course, the world", - "Abort, Retry, Fail?", - "You are making progress. I'm afraid that's something I can't allow to happen", - "You are making progress. That's not OK", - "No errors found, restarting computer", - "Does Not Compute!", - "I’m sorry, Dave, I’m afraid I can’t do that", - "What's that? Chicken?", - "It can only be attributable to human error", - "It's now safe to turn off your computer", - "I've got a bad feeling about this", - "YOU CAN’T DO THAT!", - "Man the Lifeboats! Women and children first!", - "IMPOSSIBURU!!!", - "Now deleting all files. Goodbye", - "General Failure", - "Invalid Error", - "Beam me up Scotty, there’s no life out here", - "Well, you ran into something and the game is over", - "I'm good at writing bad code", - "$FUNNY_ERROR_CAPTION", - "In Soviet Russia, exception throws YOU!", - "...and then GZDB was the demons!", - "B U S T E D", - "Freeze mode enabled", - "You feel strange...", - "That doesn't seem to work", - "This function is only available in the retail version of GZDoom Builder", - "You picked up the Random Exception.", - "Pinky says that you're the new hope. Bear that in mind.", - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "Deal with it", - "Error 47", - "YOU DIED", - "Thanks, Obama", - "The God Of Exceptions Demands MORE Exceptions!", - "Good. It's boring here anyway.", - "Shameful display!", - "It's CRASHENING!", - "W-W-W-WIPEOUT!", - "EVERYTHING IS LOST!", - "Your empty is full!", - "Let's see how far this infinite loop goes...", - }; this.Text = titles[new Random().Next(0, titles.Length - 1)]; + bContinue.Enabled = !isterminating; } private static string GetSystemInfo() @@ -181,8 +195,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.Windows private void reportLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { - if(!File.Exists(logPath)) return; - System.Diagnostics.Process.Start("explorer.exe", @"/select, " + logPath); + if(!File.Exists(logpath)) return; + System.Diagnostics.Process.Start("explorer.exe", @"/select, " + logpath); reportLink.LinkVisited = true; } diff --git a/Source/Core/General/General.cs b/Source/Core/General/General.cs index e9e9d308..f1258c2d 100644 --- a/Source/Core/General/General.cs +++ b/Source/Core/General/General.cs @@ -2080,70 +2080,64 @@ namespace CodeImp.DoomBuilder #region ================== mxd. Uncaught exceptions handling + // In some cases the program can remain operational after these private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e) { try { + // Try handling it in user-friendy way... GZBuilder.Windows.ExceptionDialog dlg = new GZBuilder.Windows.ExceptionDialog(e); dlg.Setup(); - if(dlg.ShowDialog() == DialogResult.Cancel) Application.Exit(); + if(dlg.ShowDialog() == DialogResult.Cancel) Terminate(false); } - catch + catch { - try - { - MessageBox.Show("Fatal Windows Forms Error", "Fatal Windows Forms Error", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Stop); - } - finally - { - Application.Exit(); - } + string exceptionmsg; + + // Try getting exception details... + try { exceptionmsg = "Fatal Windows Forms error occurred: " + e.Exception.Message + "\n\nStack Trace:\n" + e.Exception.StackTrace; } + catch(Exception exc) { exceptionmsg = "Failed to get initial excepton details: " + exc.Message + "\n\nStack Trace:\n" + exc.StackTrace; } + + // Try logging it... + try { WriteLogLine(exceptionmsg); } catch { } + + // Try displaying it to the user... + try { MessageBox.Show("Fatal Windows Forms Error", exceptionmsg, MessageBoxButtons.OK, MessageBoxIcon.Stop); } + finally { Process.GetCurrentProcess().Kill(); } } } + // These are usually unrecoverable private static void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs e) { - string exceptionmsg = string.Empty; - - try + try { - Exception ex = (Exception)e.ExceptionObject; - exceptionmsg = "An application error occurred: " + ex.Message + "\n\nStack Trace:\n" + ex.StackTrace; - - // Since we can't prevent the app from terminating, log this to the event log. - try - { - if(!EventLog.SourceExists("ThreadException")) - EventLog.CreateEventSource("ThreadException", "Application"); - - // Create an EventLog instance and assign its source. - using(EventLog myLog = new EventLog()) - { - myLog.Source = "ThreadException"; - myLog.WriteEntry(exceptionmsg); - } - } - catch(Exception exc) - { - MessageBox.Show("Could not write the error to the event log.\nReason: " - + exc.Message + "\n\nInitial exception:\n" + exceptionmsg, "Fatal Non-UI Error", MessageBoxButtons.OK, MessageBoxIcon.Stop); - } - + // Try handling it in user-friendy way... GZBuilder.Windows.ExceptionDialog dlg = new GZBuilder.Windows.ExceptionDialog(e); dlg.Setup(); - dlg.ShowDialog(); - } - catch(Exception exc) + if(dlg.ShowDialog() == DialogResult.Cancel) Terminate(false); + } + catch { - try + string exceptionmsg; + + // Try getting exception details... + try { - MessageBox.Show("Failed to write the error to the event log or to show the Exception Dialog.\n\nReason: " - + exc.Message + "\n\nInitial exception:\n" + exceptionmsg, "Fatal Non-UI Error", MessageBoxButtons.OK, MessageBoxIcon.Stop); - } - finally - { - Application.Exit(); + Exception ex = (Exception) e.ExceptionObject; + exceptionmsg = "Fatal Non-UI error occurred: " + ex.Message + "\n\nStack Trace:\n" + ex.StackTrace; } + catch(Exception exc) + { + exceptionmsg = "Failed to get initial excepton details: " + exc.Message + "\n\nStack Trace:\n" + exc.StackTrace; + } + + // Try logging it... + try { WriteLogLine(exceptionmsg); } catch {} + + // Try displaying it to the user... + try { MessageBox.Show("Fatal Windows Forms Error", exceptionmsg, MessageBoxButtons.OK, MessageBoxIcon.Stop); } + finally { Process.GetCurrentProcess().Kill(); } } } diff --git a/Source/Core/General/MapManager.cs b/Source/Core/General/MapManager.cs index 7d21db5d..9e4ab2a9 100644 --- a/Source/Core/General/MapManager.cs +++ b/Source/Core/General/MapManager.cs @@ -724,21 +724,22 @@ namespace CodeImp.DoomBuilder string settingsfile; WAD targetwad = null; bool includenodes; + bool fileexists = File.Exists(newfilepathname); //mxd General.WriteLogLine("Saving map to file: " + newfilepathname); //mxd. Official IWAD check... - WAD hashtest = new WAD(newfilepathname, true); - if(hashtest.IsOfficialIWAD) - { - General.WriteLogLine("Map saving aborted: attempt to modify official IWAD"); - General.ShowErrorMessage("Official IWADs should not be modified.\nConsider making a PWAD instead", MessageBoxButtons.OK); - return false; - } - else + if(fileexists) { + WAD hashtest = new WAD(newfilepathname, true); + if(hashtest.IsOfficialIWAD) + { + General.WriteLogLine("Map saving aborted: attempt to modify an official IWAD"); + General.ShowErrorMessage("Official IWADs should not be modified.\nConsider making a PWAD instead", MessageBoxButtons.OK); + return false; + } + hashtest.Dispose(); - hashtest = null; } // Scripts changed? @@ -786,79 +787,85 @@ namespace CodeImp.DoomBuilder } //mxd. Target file is read-only? - FileInfo info = new FileInfo(newfilepathname); - if(info.Exists && info.IsReadOnly) + if(fileexists) { - if(General.ShowWarningMessage("Unable to save the map: target file is read-only.\nRemove read-only flag and save the map anyway?", MessageBoxButtons.YesNo) == DialogResult.Yes) + FileInfo info = new FileInfo(newfilepathname); + if(info.IsReadOnly) { - General.WriteLogLine("Removing read-only flag from the map file..."); - try + if(General.ShowWarningMessage("Unable to save the map: target file is read-only.\nRemove read-only flag and save the map anyway?", MessageBoxButtons.YesNo) == DialogResult.Yes) { - info.IsReadOnly = false; + General.WriteLogLine("Removing read-only flag from the map file..."); + try + { + info.IsReadOnly = false; + } + catch(Exception e) + { + General.ShowErrorMessage("Failed to remove read-only flag from \"" + filepathname + "\":" + Environment.NewLine + Environment.NewLine + e.Message, MessageBoxButtons.OK); + General.WriteLogLine("Failed to remove read-only flag from \"" + filepathname + "\":" + e.Message); + return false; + } } - catch(Exception e) + else { - General.ShowErrorMessage("Failed to remove read-only flag from \"" + filepathname + "\":" + Environment.NewLine + Environment.NewLine + e.Message, MessageBoxButtons.OK); - General.WriteLogLine("Failed to remove read-only flag from \"" + filepathname + "\":" + e.Message); + General.WriteLogLine("Map saving cancelled..."); return false; } } - else - { - General.WriteLogLine("Map saving cancelled..."); - return false; - } } // Suspend data resources data.Suspend(); //mxd. Check if the target file is locked - FileLockChecker.FileLockCheckResult checkresult = FileLockChecker.CheckFile(newfilepathname); - if(!string.IsNullOrEmpty(checkresult.Error)) + if(fileexists) { - if(checkresult.Processes.Count > 0) + FileLockChecker.FileLockCheckResult checkresult = FileLockChecker.CheckFile(newfilepathname); + if(!string.IsNullOrEmpty(checkresult.Error)) { - string rest = "Press 'Retry' to close " + (checkresult.Processes.Count > 1 ? "all processes" : "the process") - + " and retry." + Environment.NewLine + "Press 'Cancel' to cancel saving."; - - if(General.ShowErrorMessage(checkresult.Error + rest, MessageBoxButtons.RetryCancel) == DialogResult.Retry) + if(checkresult.Processes.Count > 0) { - // Close all processes - foreach(Process process in checkresult.Processes) - { - try - { - if(!process.HasExited) process.Kill(); - } - catch(Exception e) - { - General.ShowErrorMessage("Failed to close " + Path.GetFileName(process.MainModule.FileName) + ":" + Environment.NewLine + Environment.NewLine + e.Message, MessageBoxButtons.OK); - data.Resume(); - General.WriteLogLine("Map saving failed: failed to close " + Path.GetFileName(process.MainModule.FileName)); - return false; - } - } + string rest = "Press 'Retry' to close " + (checkresult.Processes.Count > 1 ? "all processes" : "the process") + + " and retry." + Environment.NewLine + "Press 'Cancel' to cancel saving."; - // Retry - data.Resume(); - General.WriteLogLine("Map saving restarted..."); - return SaveMap(newfilepathname, purpose); + if(General.ShowErrorMessage(checkresult.Error + rest, MessageBoxButtons.RetryCancel) == DialogResult.Retry) + { + // Close all processes + foreach(Process process in checkresult.Processes) + { + try + { + if(!process.HasExited) process.Kill(); + } + catch(Exception e) + { + General.ShowErrorMessage("Failed to close " + Path.GetFileName(process.MainModule.FileName) + ":" + Environment.NewLine + Environment.NewLine + e.Message, MessageBoxButtons.OK); + data.Resume(); + General.WriteLogLine("Map saving failed: failed to close " + Path.GetFileName(process.MainModule.FileName)); + return false; + } + } + + // Retry + data.Resume(); + General.WriteLogLine("Map saving restarted..."); + return SaveMap(newfilepathname, purpose); + } + else + { + data.Resume(); + General.WriteLogLine("Map saving cancelled..."); + return false; + } } else { + General.ShowErrorMessage(checkresult.Error, MessageBoxButtons.OK); data.Resume(); - General.WriteLogLine("Map saving cancelled..."); + General.WriteLogLine("Map saving failed: " + checkresult.Error); return false; } } - else - { - General.ShowErrorMessage(checkresult.Error, MessageBoxButtons.OK); - data.Resume(); - General.WriteLogLine("Map saving failed: " + checkresult.Error); - return false; - } } // Determine original map name @@ -867,7 +874,7 @@ namespace CodeImp.DoomBuilder try { - if(File.Exists(newfilepathname)) + if(fileexists) { // mxd. Check if target wad already has a map with the same name if(purpose == SavePurpose.IntoFile) diff --git a/Source/Core/Windows/MainForm.Designer.cs b/Source/Core/Windows/MainForm.Designer.cs index 5a440216..366ec483 100644 --- a/Source/Core/Windows/MainForm.Designer.cs +++ b/Source/Core/Windows/MainForm.Designer.cs @@ -1,3 +1,4 @@ +using System; using System.Windows.Forms; using CodeImp.DoomBuilder.Controls; @@ -407,6 +408,7 @@ namespace CodeImp.DoomBuilder.Windows this.menufile.Name = "menufile"; this.menufile.Size = new System.Drawing.Size(37, 20); this.menufile.Text = "&File"; + this.menufile.DropDownOpening += menufile_DropDownOpening; // // itemnewmap // diff --git a/Source/Core/Windows/MainForm.cs b/Source/Core/Windows/MainForm.cs index 8af1485b..80242ac5 100644 --- a/Source/Core/Windows/MainForm.cs +++ b/Source/Core/Windows/MainForm.cs @@ -2603,13 +2603,9 @@ namespace CodeImp.DoomBuilder.Windows internal void AddRecentFile(string filename) { //mxd. Recreate recent files list - if(recentitems.Length != General.Settings.MaxRecentFiles) + if(recentitems.Length != General.Settings.MaxRecentFiles) { - foreach(ToolStripMenuItem item in recentitems) - menufile.DropDownItems.Remove(item); - - SaveRecentFiles(); - CreateRecentFiles(); + UpdateRecentItems(); } int movedownto = General.Settings.MaxRecentFiles - 1; @@ -2645,6 +2641,16 @@ namespace CodeImp.DoomBuilder.Windows itemnorecent.Visible = false; } + //mxd + private void UpdateRecentItems() + { + foreach(ToolStripMenuItem item in recentitems) + menufile.DropDownItems.Remove(item); + + SaveRecentFiles(); + CreateRecentFiles(); + } + // This returns the trimmed file/path string private string GetDisplayFilename(string filename) { @@ -2689,6 +2695,12 @@ namespace CodeImp.DoomBuilder.Windows // Open this file General.OpenMapFile(item.Tag.ToString(), null); } + + //mxd + private void menufile_DropDownOpening(object sender, EventArgs e) + { + UpdateRecentItems(); + } #endregion diff --git a/Source/Core/ZDoom/AnimdefsParser.cs b/Source/Core/ZDoom/AnimdefsParser.cs index 2e834d72..1c3ef0d9 100644 --- a/Source/Core/ZDoom/AnimdefsParser.cs +++ b/Source/Core/ZDoom/AnimdefsParser.cs @@ -1,7 +1,6 @@ #region ================== Namespaces using System.Collections.Generic; -using System.IO; using CodeImp.DoomBuilder.Config; using CodeImp.DoomBuilder.Data; diff --git a/Source/Core/ZDoom/PatchStructure.cs b/Source/Core/ZDoom/PatchStructure.cs index d9e19d45..fb997a18 100644 --- a/Source/Core/ZDoom/PatchStructure.cs +++ b/Source/Core/ZDoom/PatchStructure.cs @@ -18,8 +18,8 @@ using System; using System.Globalization; -using CodeImp.DoomBuilder.Data; using System.IO; +using CodeImp.DoomBuilder.Data; using CodeImp.DoomBuilder.Rendering; #endregion @@ -45,10 +45,9 @@ namespace CodeImp.DoomBuilder.ZDoom private readonly bool flipy; private readonly float alpha; private readonly int rotation; //mxd - private readonly TexturePathRenderStyle renderStyle; //mxd - private readonly PixelColor blendColor; //mxd - private readonly TexturePathBlendStyle blendStyle; //mxd - private readonly float tintAmmount; //mxd + private readonly TexturePathRenderStyle renderstyle; //mxd + private readonly PixelColor blendcolor; //mxd + private readonly TexturePathBlendStyle blendstyle; //mxd private static readonly string[] renderStyles = { "copy", "translucent", "add", "subtract", "reversesubtract", "modulate", "copyalpha", "copynewalpha", "overlay" }; //mxd private readonly bool skip; //mxd @@ -63,10 +62,9 @@ namespace CodeImp.DoomBuilder.ZDoom public bool FlipY { get { return flipy; } } public float Alpha { get { return alpha; } } public int Rotation { get { return rotation; } } //mxd - public TexturePathRenderStyle RenderStyle { get { return renderStyle; } } //mxd - public TexturePathBlendStyle BlendStyle { get { return blendStyle; } } - public float TintAmmount { get { return tintAmmount; } } - public PixelColor BlendColor { get { return blendColor; } }//mxd + public TexturePathRenderStyle RenderStyle { get { return renderstyle; } } //mxd + public TexturePathBlendStyle BlendStyle { get { return blendstyle; } } + public PixelColor BlendColor { get { return blendcolor; } }//mxd public bool Skip { get { return skip; } } //mxd #endregion @@ -78,8 +76,8 @@ namespace CodeImp.DoomBuilder.ZDoom { // Initialize alpha = 1.0f; - renderStyle = TexturePathRenderStyle.Copy;//mxd - blendStyle = TexturePathBlendStyle.None; //mxd + renderstyle = TexturePathRenderStyle.COPY;//mxd + blendstyle = TexturePathBlendStyle.NONE; //mxd // There should be 3 tokens separated by 2 commas now: // Name, Width, Height @@ -164,30 +162,69 @@ namespace CodeImp.DoomBuilder.ZDoom string s; if(!ReadTokenString(parser, token, out s)) return; int index = Array.IndexOf(renderStyles, s.ToLowerInvariant()); - renderStyle = index == -1 ? TexturePathRenderStyle.Copy : (TexturePathRenderStyle) index; + renderstyle = index == -1 ? TexturePathRenderStyle.COPY : (TexturePathRenderStyle) index; break; case "blend": //mxd - int val; - if(!ReadTokenColor(parser, token, out val)) return; - blendColor = PixelColor.FromInt(val); - parser.SkipWhitespace(false); - token = parser.ReadToken(); + PixelColor color = new PixelColor(); - if(token == ",") //read tint ammount - { - parser.SkipWhitespace(false); - if(!ReadTokenFloat(parser, token, out tintAmmount)) return; - tintAmmount = General.Clamp(tintAmmount, 0.0f, 1.0f); - blendStyle = TexturePathBlendStyle.Tint; - } - else + // Blend [,] block? + token = parser.ReadToken(false); + if(!parser.ReadByte(token, ref color.r)) { - blendStyle = TexturePathBlendStyle.Blend; - // Rewind so this structure can be read again - parser.DataStream.Seek(-token.Length, SeekOrigin.Current); + if(!ZDTextParser.GetColorFromString(token, ref color)) + { + parser.ReportError("Unsupported patch blend definition"); + return; + } } + // That's Blend ,,[,] block + else + { + if(!parser.SkipWhitespace(false) || + !parser.NextTokenIs(",", false) || !parser.SkipWhitespace(false) || !parser.ReadByte(ref color.g) || + !parser.NextTokenIs(",", false) || !parser.SkipWhitespace(false) || !parser.ReadByte(ref color.b)) + { + parser.ReportError("Unsupported patch blend definition"); + return; + } + } + + // Alpha block? + float blendalpha = -1f; + parser.SkipWhitespace(false); + if(parser.NextTokenIs(",", false)) + { + parser.SkipWhitespace(false); + if(!ReadTokenFloat(parser, token, out blendalpha)) + { + parser.ReportError("Unsupported patch blend alpha value"); + return; + } + } + + // Blend may never be 0 when using the Tint effect + if(blendalpha > 0.0f) + { + color.a = (byte)General.Clamp((int)(blendalpha * 255), 1, 254); + blendstyle = TexturePathBlendStyle.TINT; + + } + else if(blendalpha < 0.0f) + { + color.a = 255; + blendstyle = TexturePathBlendStyle.BLEND; + } + else + { + // Ignore Blend when alpha == 0 + parser.LogWarning("Blend with zero alpha will be ignored by ZDoom"); + break; + } + + // Store the color + blendcolor = color; break; case "}": @@ -268,36 +305,6 @@ namespace CodeImp.DoomBuilder.ZDoom return true; } - //mxd. This reads the next token and sets a PixelColor value, returns false when failed - private static bool ReadTokenColor(TexturesParser parser, string propertyname, out int value) - { - parser.SkipWhitespace(true); - string strvalue = parser.StripTokenQuotes(parser.ReadToken()); - value = 0; - - if(string.IsNullOrEmpty(strvalue)) - { - // Can't find the property value! - parser.ReportError("Expected a value for property \"" + propertyname + "\""); - return false; - } - - if(strvalue[0] != '#') - { - parser.ReportError("Expected color value for property \"" + propertyname + "\""); - return false; - } - - // Try parsing as value - if(!int.TryParse(strvalue.Remove(0, 1), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out value)) - { - parser.ReportError("Expected color value for property \"" + propertyname + "\""); - return false; - } - - return true; - } - #endregion } } diff --git a/Source/Core/ZDoom/X11R6RGBParser.cs b/Source/Core/ZDoom/X11R6RGBParser.cs new file mode 100644 index 00000000..18bec45d --- /dev/null +++ b/Source/Core/ZDoom/X11R6RGBParser.cs @@ -0,0 +1,87 @@ +#region ================== Namespaces + +using System; +using System.Collections.Generic; +using System.Globalization; +using CodeImp.DoomBuilder.Config; +using CodeImp.DoomBuilder.Data; +using CodeImp.DoomBuilder.Rendering; + +#endregion + +namespace CodeImp.DoomBuilder.ZDoom +{ + internal sealed class X11R6RGBParser : ZDTextParser + { + #region ================== Variables + + private readonly Dictionary knowncolors; + + #endregion + + #region ================== Properties + + internal override ScriptType ScriptType { get { return ScriptType.X11R6RGB; } } + + public Dictionary KnownColors { get { return knowncolors; } } + + #endregion + + #region ================== Constructor + + internal X11R6RGBParser() + { + knowncolors = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + + #endregion + + #region ================== Parsing + + public override bool Parse(TextResourceData data, bool clearerrors) + { + // Already parsed? + if(!base.AddTextResource(data)) + { + if(clearerrors) ClearError(); + return true; + } + + // Cannot process? + if(!base.Parse(data, clearerrors)) return false; + + // Continue until at the end of the stream + char[] space = {' ', '\t'}; + while(SkipWhitespace(true)) + { + string line = ReadLine(); + if(string.IsNullOrEmpty(line) || line.StartsWith("!")) continue; // Skip comments + + // "R G B Name with spaces" + string[] parts = line.Split(space, StringSplitOptions.RemoveEmptyEntries); + + if(parts.Length < 4) + { + ReportError("Incorrect X11R6RGB color assignment"); + return false; + } + + // Parse colors + byte r = 0, g = 0, b = 0; + if(!ReadByte(parts[0], ref r)) { ReportError("Expected red color value in [0 .. 255] range"); return false; } + if(!ReadByte(parts[1], ref g)) { ReportError("Expected green color value in [0 .. 255] range"); return false; } + if(!ReadByte(parts[2], ref b)) { ReportError("Expected blue color value in [0 .. 255] range"); return false; } + + // Assemble name + string colorname = string.Join("", parts, 3, parts.Length - 3); + + // Add to collection + knowncolors[colorname] = new PixelColor(255, r, g, b); + } + + return true; + } + + #endregion + } +} diff --git a/Source/Core/ZDoom/ZDTextParser.cs b/Source/Core/ZDoom/ZDTextParser.cs index 851e23b4..7c11110f 100644 --- a/Source/Core/ZDoom/ZDTextParser.cs +++ b/Source/Core/ZDoom/ZDTextParser.cs @@ -24,6 +24,7 @@ using System.IO; using CodeImp.DoomBuilder.Compilers; using CodeImp.DoomBuilder.Config; using CodeImp.DoomBuilder.Data; +using CodeImp.DoomBuilder.Rendering; #endregion @@ -557,6 +558,65 @@ namespace CodeImp.DoomBuilder.ZDoom return success; } + //mxd + protected internal bool ReadByte(ref byte value) { return ReadByte(StripTokenQuotes(ReadToken(false)), ref value); } + protected internal bool ReadByte(string token, ref byte value) + { + if(token == "-") return false; + + int result; + if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out result) || result < 0 || result > 255) + { + return false; + } + + value = (byte)result; + return true; + } + + //mxd. This replicates ZDoom's V_GetColorFromString method + public static bool GetColorFromString(string name, ref PixelColor color) + { + name = StripQuotes(name.Replace(" ", "")); + + // Check for HTML-style #RRGGBB or #RGB color string + bool ishtmlcolor = false; + if(name.StartsWith("#")) + { + ishtmlcolor = true; + name = name.Remove(0, 1); + + // Expand RGB to RRGGBB + if(name.Length == 3) + { + name = name[0].ToString() + name[0] + name[1] + name[1] + name[2] + name[2]; + } + else if(name.Length != 6) + { + // Bad HTML-style; pretend it's black. + color = new PixelColor(); + return true; + } + } + + // Probably it's a hex color (like FFCC11)? + int ci; + if(int.TryParse(name, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ci)) + { + color = PixelColor.FromInt(ci).WithAlpha(255); + return true; + } + + // Probably it's a color name? + if(!ishtmlcolor && General.Map.Data.KnownColors.ContainsKey(name)) + { + color = General.Map.Data.KnownColors[name]; + return true; + } + + return false; + } + //mxd protected void SkipStructure() { SkipStructure(new HashSet()); } protected void SkipStructure(HashSet breakat)