UltimateZoneBuilder/Source/Core/ZDoom/PatchStructure.cs
MaxED ae56aad3b7 Hints panel was improperly resized in some cases.
Info panel was not updated after leaving Visual mode.
Moved hints logic to ClassicMode, so hints can be displayed by any plugin.
Visual mode: dynamic light animation was not working.
Minor performance improvements in Actor, Configuration, UDMF and TEXTURES parsers.
2013-12-18 09:11:04 +00:00

301 lines
9 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());
if(string.IsNullOrEmpty(name))
{
parser.ReportError("Expected patch name");
return;
}
// 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) {
General.ErrorLogger.Add(ErrorType.Warning, "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 = 0;
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 - 1, 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 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 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 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 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
}
}