TEXTURES support: both patch Blend syntaxes are now supported (previously only "Blend <string color>[,<float alpha>]" was supported).

Added X11R6RGB parser.
Rewritten parts of unhandled exceptions handling to reduce the chance of additional exceptions happening after the first one.
This commit is contained in:
MaxED 2016-03-16 23:26:53 +00:00
parent 1703af1c82
commit adadca9d99
20 changed files with 605 additions and 390 deletions

View file

@ -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";

View file

@ -1021,6 +1021,7 @@
<Compile Include="ZDoom\TexturesParser.cs" />
<Compile Include="ZDoom\TextureStructure.cs" />
<Compile Include="ZDoom\VoxeldefParser.cs" />
<Compile Include="ZDoom\X11R6RGBParser.cs" />
<Compile Include="ZDoom\ZDTextParser.cs" />
<Compile Include="ZDoom\DecorateParser.cs" />
<Compile Include="ZDoom\StateStructure.cs" />

View file

@ -42,6 +42,7 @@ namespace CodeImp.DoomBuilder.Config
ANIMDEFS = 9,
REVERBS = 10,
TERRAIN = 11,
X11R6RGB = 12,
}
internal class ScriptConfiguration : IComparable<ScriptConfiguration>

View file

@ -97,6 +97,7 @@ namespace CodeImp.DoomBuilder.Data
private string[] soundsequences;
private string[] terrainnames;
private string[] damagetypes;
private Dictionary<string, PixelColor> knowncolors; // Colors parsed from X11R6RGB lump. Color names are lowercase without spaces
//mxd. Text resources
private Dictionary<ScriptType, HashSet<TextResource>> 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<string, PixelColor> KnownColors { get { return knowncolors; } }
internal Dictionary<ScriptType, HashSet<TextResource>> TextResources { get { return textresources; } }
//mxd
@ -326,6 +328,7 @@ namespace CodeImp.DoomBuilder.Data
terrainnames = new string[0];
textresources = new Dictionary<ScriptType, HashSet<TextResource>>();
damagetypes = new string[0];
knowncolors = new Dictionary<string, PixelColor>(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<string, TexturesParser> cachedparsers = new Dictionary<string, TexturesParser>(); //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<TextResourceData> 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<TextResource>(parser.TextResources.Values);
currentreader = null;
// Set as collection
knowncolors = parser.KnownColors;
}
//mxd
internal TextResourceData GetTextResourceData(string name)
{

View file

@ -240,6 +240,9 @@ namespace CodeImp.DoomBuilder.Data
//mxd. When implemented, this returns the TERRAIN lump
public abstract IEnumerable<TextResourceData> GetTerrainData();
//mxd. When implemented, this returns the X11R6RGB lump
public abstract IEnumerable<TextResourceData> GetX11R6RGBData();
//mxd. When implemented, this returns the list of voxel model names
public abstract IEnumerable<string> GetVoxelNames();

View file

@ -701,7 +701,6 @@ namespace CodeImp.DoomBuilder.Data
#region ================== TERRAIN (mxd)
//mxd
public override IEnumerable<TextResourceData> GetTerrainData()
{
// Error when suspended
@ -722,6 +721,28 @@ namespace CodeImp.DoomBuilder.Data
#endregion
#region ================== XBRSBSBB11 (mxd)
public override IEnumerable<TextResourceData> GetX11R6RGBData()
{
// Error when suspended
if(issuspended) throw new Exception("Data reader is suspended");
List<TextResourceData> result = new List<TextResourceData>();
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

View file

@ -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);

View file

@ -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
}

View file

@ -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;
}
}
}

View file

@ -1015,6 +1015,13 @@ namespace CodeImp.DoomBuilder.Data
return GetAllLumps("TERRAIN");
}
//mxd
public override IEnumerable<TextResourceData> GetX11R6RGBData()
{
if(issuspended) throw new Exception("Data reader is suspended");
return GetAllLumps("X11R6RGB");
}
//mxd
private IEnumerable<TextResourceData> GetFirstLump(string name)
{

View file

@ -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
}
}

View file

@ -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!",
"Im sorry, Dave, Im afraid I cant 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 CANT DO THAT!",
"Man the Lifeboats! Women and children first!",
"IMPOSSIBURU!!!",
"Now deleting all files. Goodbye",
"General Failure",
"Invalid Error",
"Beam me up Scotty, theres 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, its the humans 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!",
"Im sorry, Dave, Im afraid I cant 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 CANT DO THAT!",
"Man the Lifeboats! Women and children first!",
"IMPOSSIBURU!!!",
"Now deleting all files. Goodbye",
"General Failure",
"Invalid Error",
"Beam me up Scotty, theres 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;
}

View file

@ -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(); }
}
}

View file

@ -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)

View file

@ -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
//

View file

@ -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

View file

@ -1,7 +1,6 @@
#region ================== Namespaces
using System.Collections.Generic;
using System.IO;
using CodeImp.DoomBuilder.Config;
using CodeImp.DoomBuilder.Data;

View file

@ -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 <string color>[,<float alpha>] 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 <int r>,<int g>,<int b>[,<float alpha>] 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
}
}

View file

@ -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<string, PixelColor> knowncolors;
#endregion
#region ================== Properties
internal override ScriptType ScriptType { get { return ScriptType.X11R6RGB; } }
public Dictionary<string, PixelColor> KnownColors { get { return knowncolors; } }
#endregion
#region ================== Constructor
internal X11R6RGBParser()
{
knowncolors = new Dictionary<string, PixelColor>(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
}
}

View file

@ -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<string>()); }
protected void SkipStructure(HashSet<string> breakat)