mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-11-27 06:02:11 +00:00
dbcc57b7a6
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.
317 lines
9.2 KiB
C#
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
|
|
}
|
|
}
|