UltimateZoneBuilder/Source/Core/ZDoom/PatchStructure.cs
MaxED dbcc57b7a6 Fixed, Script Editor: file was marked as changed when changing script configurations.
Fixed, Script Editor: in some cases clicking on an error in the errors list didn't navigate to the error location.
Fixed, Script Editor: in some cases incorrect error line number was shown.
Fixed, Text lump parsers: fixed a crash when trying to get a filename from a quoted string with missing closing quote.
Fixed, Text lump parsers: in several cases parsing errors were ignored by overlaying data structures.
Fixed: in some cases Thing Filter thing flags were cleared when switching game configurations in the "Game Configurations" window.
Changed, PK3 reader: loading of files with invalid path chars is now skipped instead of skipping loading of the whole resource. Also more helpful warning message is now displayed.
Updated SharpCompress library to v.0.11.2.0.
2015-12-17 10:07:28 +00:00

317 lines
9.2 KiB
C#

#region ================== Copyright (c) 2007 Pascal vd Heiden
/*
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
* This program is released under GNU General Public License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#endregion
#region ================== Namespaces
using System;
using System.Globalization;
using CodeImp.DoomBuilder.Data;
using System.IO;
using CodeImp.DoomBuilder.Rendering;
#endregion
namespace CodeImp.DoomBuilder.ZDoom
{
public sealed class PatchStructure
{
#region ================== Constants
#endregion
#region ================== Variables
// Declaration
private string name;
private int offsetx;
private int offsety;
private bool flipx;
private bool flipy;
private float alpha;
private int rotation; //mxd
private TexturePathRenderStyle renderStyle; //mxd
private PixelColor blendColor; //mxd
private TexturePathBlendStyle blendStyle; //mxd
private float tintAmmount; //mxd
private static string[] renderStyles = { "copy", "translucent", "add", "subtract", "reversesubtract", "modulate", "copyalpha", "copynewalpha", "overlay" }; //mxd
#endregion
#region ================== Properties
public string Name { get { return name; } }
public int OffsetX { get { return offsetx; } }
public int OffsetY { get { return offsety; } }
public bool FlipX { get { return flipx; } }
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
#endregion
#region ================== Constructor / Disposer
// Constructor
internal PatchStructure(TexturesParser parser)
{
string tokenstr;
// Initialize
alpha = 1.0f;
renderStyle = TexturePathRenderStyle.Copy;//mxd
blendStyle = TexturePathBlendStyle.None; //mxd
// There should be 3 tokens separated by 2 commas now:
// Name, Width, Height
// First token is the class name
parser.SkipWhitespace(true);
name = parser.StripTokenQuotes(parser.ReadToken(false)); //mxd. Don't skip newline
if(string.IsNullOrEmpty(name))
{
parser.ReportError("Expected patch name");
return;
}
//mxd
name = name.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
// Now we should find a comma
parser.SkipWhitespace(true);
tokenstr = parser.ReadToken();
if(tokenstr != ",")
{
parser.ReportError("Expected a comma");
return;
}
// Next is the patch width
parser.SkipWhitespace(true);
tokenstr = parser.ReadToken();
if(string.IsNullOrEmpty(tokenstr) || !int.TryParse(tokenstr, NumberStyles.Integer, CultureInfo.InvariantCulture, out offsetx))
{
parser.ReportError("Expected offset in pixels");
return;
}
// Now we should find a comma again
parser.SkipWhitespace(true);
tokenstr = parser.ReadToken();
if(tokenstr != ",")
{
parser.ReportError("Expected a comma");
return;
}
// Next is the patch height
parser.SkipWhitespace(true);
tokenstr = parser.ReadToken();
if(string.IsNullOrEmpty(tokenstr) || !int.TryParse(tokenstr, NumberStyles.Integer, CultureInfo.InvariantCulture, out offsety))
{
parser.ReportError("Expected offset in pixels");
return;
}
// Next token is the beginning of the texture scope.
// If not, then the patch info ends here.
parser.SkipWhitespace(true);
tokenstr = parser.ReadToken();
if(tokenstr != "{")
{
// Rewind so this structure can be read again
parser.DataStream.Seek(-tokenstr.Length - 1, SeekOrigin.Current);
return;
}
// Now parse the contents of texture structure
bool done = false; //mxd
while(!done && parser.SkipWhitespace(true))
{
string token = parser.ReadToken();
token = token.ToLowerInvariant();
switch (token)
{
case "flipx":
flipx = true;
break;
case "flipy":
flipy = true;
break;
case "alpha":
if (!ReadTokenFloat(parser, token, out alpha)) return;
alpha = General.Clamp(alpha, 0.0f, 1.0f);
break;
case "rotate":
if(!ReadTokenInt(parser, token, out rotation)) return;
rotation = rotation % 360; //Coalesce multiples
if(rotation < 0) rotation += 360; //Force positive
if(rotation != 0 && rotation != 90 && rotation != 180 && rotation != 270)
{
parser.LogWarning("Got unsupported rotation (" + rotation + ") in patch '" + name + "'");
rotation = 0;
}
break;
case "style": //mxd
string s;
if(!ReadTokenString(parser, token, out s)) return;
int index = Array.IndexOf(renderStyles, s.ToLowerInvariant());
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();
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
{
blendStyle = TexturePathBlendStyle.Blend;
// Rewind so this structure can be read again
parser.DataStream.Seek(-token.Length, SeekOrigin.Current);
}
break;
case "}":
// Patch scope ends here,
// break out of this parse loop
done = true;
break;
}
}
}
#endregion
#region ================== Methods
// This reads the next token and sets a floating point value, returns false when failed
private static bool ReadTokenFloat(TexturesParser parser, string propertyname, out float value)
{
// Next token is the property value to set
parser.SkipWhitespace(true);
string strvalue = parser.ReadToken();
if(!string.IsNullOrEmpty(strvalue))
{
// Try parsing as value
if(!float.TryParse(strvalue, NumberStyles.Float, CultureInfo.InvariantCulture, out value))
{
parser.ReportError("Expected numeric value for property '" + propertyname + "'");
return false;
}
// Success
return true;
}
// Can't find the property value!
parser.ReportError("Expected a value for property '" + propertyname + "'");
value = 0.0f;
return false;
}
// This reads the next token and sets an integral value, returns false when failed
private static bool ReadTokenInt(TexturesParser parser, string propertyname, out int value)
{
// Next token is the property value to set
parser.SkipWhitespace(true);
string strvalue = parser.ReadToken();
if(!string.IsNullOrEmpty(strvalue))
{
// Try parsing as value
if(!int.TryParse(strvalue, NumberStyles.Integer, CultureInfo.InvariantCulture, out value))
{
parser.ReportError("Expected integral value for property '" + propertyname + "'");
return false;
}
// Success
return true;
}
// Can't find the property value!
parser.ReportError("Expected a value for property '" + propertyname + "'");
value = 0;
return false;
}
//mxd. This reads the next token and sets a string value, returns false when failed
private static bool ReadTokenString(TexturesParser parser, string propertyname, out string value)
{
parser.SkipWhitespace(true);
value = parser.StripTokenQuotes(parser.ReadToken());
if(string.IsNullOrEmpty(value))
{
// Can't find the property value!
parser.ReportError("Expected a value for property '" + propertyname + "'");
return false;
}
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
}
}