UltimateZoneBuilder/Source/Core/GZBuilder/GZDoom/MapinfoParser.cs

354 lines
13 KiB
C#
Raw Normal View History

using System;
using System.Drawing;
using System.Globalization;
using System.IO;
using SlimDX;
using CodeImp.DoomBuilder.ZDoom;
using CodeImp.DoomBuilder.GZBuilder.Data;
namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
public sealed class MapinfoParser : ZDTextParser {
private MapInfo mapInfo;
public MapInfo MapInfo { get { return mapInfo; } }
public bool Parse(Stream stream, string sourcefilename, string mapName) {
base.Parse(stream, sourcefilename);
mapName = mapName.ToLowerInvariant();
mapInfo = new MapInfo();
while (SkipWhitespace(true)) {
string token = ReadToken();
if (token != null) {
token = token.ToLowerInvariant();
if (parseBlock(token, mapName))
break;
}
}
//check values
if (mapInfo.FadeColor.Red > 0 || mapInfo.FadeColor.Green > 0 || mapInfo.FadeColor.Blue > 0)
mapInfo.HasFadeColor = true;
if (mapInfo.OutsideFogColor.Red > 0 || mapInfo.OutsideFogColor.Green > 0 || mapInfo.OutsideFogColor.Blue > 0)
mapInfo.HasOutsideFogColor = true;
//Cannot fail here
return true;
}
//returns true if parsing is finished
private bool parseBlock(string token, string mapName) {
string curBlockName;
if (token == "map" || token == "defaultmap" || token == "adddefaultmap") {
curBlockName = token;
if (token == "map") { //check map name
//get map name
SkipWhitespace(true);
token = ReadToken().ToLowerInvariant();
if (token != mapName)
return false; //not finished, search for next "map", "defaultmap" or "adddefaultmap" block
} else if (token == "defaultmap") {
//reset MapInfo
mapInfo = new MapInfo();
}
//search for required keys
while (SkipWhitespace(true)) {
token = ReadToken().ToLowerInvariant();
//sky1 or sky2
if (token == "sky1" || token == "sky2") {
string skyType = token;
SkipWhitespace(true);
token = StripTokenQuotes(ReadToken()).ToLowerInvariant();
//new format
if (token == "=") {
SkipWhitespace(true);
//should be sky texture name
token = StripTokenQuotes(ReadToken());
bool gotComma = (token.IndexOf(",") != -1);
if (gotComma)
token = token.Replace(",", "");
string skyTexture = StripTokenQuotes(token).ToLowerInvariant();
if (!string.IsNullOrEmpty(skyTexture)) {
if (skyType == "sky1")
mapInfo.Sky1 = skyTexture;
else
mapInfo.Sky2 = skyTexture;
//check if we have scrollspeed
SkipWhitespace(true);
token = StripTokenQuotes(ReadToken());
if (!gotComma && token == ",") {
gotComma = true;
SkipWhitespace(true);
token = ReadToken();
}
if (gotComma) {
float scrollSpeed = 0;
if (!ReadSignedFloat(token, ref scrollSpeed)) {
// Not numeric!
General.ErrorLogger.Add(ErrorType.Warning, "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + skyType + " scroll speed value, but got '" + token + "'");
datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
continue;
}
if (skyType == "sky1")
mapInfo.Sky1ScrollSpeed = scrollSpeed;
else
mapInfo.Sky2ScrollSpeed = scrollSpeed;
} else {
datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
}
} else {
datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
General.ErrorLogger.Add(ErrorType.Error, "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + skyType + " texture name.");
}
//old format
} else {
//token should be sky1/2 name
if (!string.IsNullOrEmpty(token)) {
if (skyType == "sky1")
mapInfo.Sky1 = token;
else
mapInfo.Sky2 = token;
//try to read scroll speed
SkipWhitespace(true);
token = StripTokenQuotes(ReadToken());
float scrollSpeed = 0;
if (!ReadSignedFloat(token, ref scrollSpeed)) {
// Not numeric!
datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
continue;
}
if (skyType == "sky1")
mapInfo.Sky1ScrollSpeed = scrollSpeed;
else
mapInfo.Sky2ScrollSpeed = scrollSpeed;
} else {
datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
General.ErrorLogger.Add(ErrorType.Error, "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + skyType + " texture name.");
}
}
//fade or outsidefog
} else if (token == "fade" || token == "outsidefog") {
string fadeType = token;
SkipWhitespace(true);
token = StripTokenQuotes(ReadToken()).ToLowerInvariant();
//new format
if (token == "=") {
SkipWhitespace(true);
//red color value or color name...
token = ReadToken();
string colorVal = StripTokenQuotes(token).ToLowerInvariant();
if (!string.IsNullOrEmpty(colorVal)) {
Color4 color = new Color4();
//is it color name?
if (getColor(colorVal, ref color)) {
if (fadeType == "fade")
mapInfo.FadeColor = color;
else
mapInfo.OutsideFogColor = color;
} else { //no, it's not
//try to get color values
int r, g, b;
string[] parts = colorVal.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length != 3) {
General.ErrorLogger.Add(ErrorType.Error, "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + fadeType + " color values, but got '" + token + "'");
datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
continue;
}
if (!int.TryParse(parts[0], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out r)) {
General.ErrorLogger.Add(ErrorType.Error, "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + fadeType + " red value, but got '" + parts[0] + "'");
datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
continue;
}
if (!int.TryParse(parts[1], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out g)) {
General.ErrorLogger.Add(ErrorType.Error, "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + fadeType + " green value, but got '" + parts[1] + "'");
datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
continue;
}
if (!int.TryParse(parts[2], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out b)) {
General.ErrorLogger.Add(ErrorType.Error, "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + fadeType + " blue value, but got '" + parts[2] + "'");
datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
continue;
}
color.Red = (float)r / 255;
color.Green = (float)g / 255;
color.Blue = (float)b / 255;
if (fadeType == "fade")
mapInfo.FadeColor = color;
else
mapInfo.OutsideFogColor = color;
}
} else {
General.ErrorLogger.Add(ErrorType.Error, "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + fadeType + " color value.");
datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
}
//old format
} else {
//token should contain red color value or color name...
if (!string.IsNullOrEmpty(token)) {
int r, g, b;
Color4 color = new Color4();
if (!int.TryParse(token, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out r)) {
//Not numeric! Maybe it's a color name?
if (getColor(token, ref color)) {
if (fadeType == "fade")
mapInfo.FadeColor = color;
else
mapInfo.OutsideFogColor = color;
} else {
datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
}
continue;
}
SkipWhitespace(true);
token = ReadToken();
//should be color, let's continue parsing it.
if (!int.TryParse(token, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out g)) {
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + fadeType + " green value, but got '" + token + "'");
datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
continue;
}
SkipWhitespace(true);
token = StripTokenQuotes(ReadToken());
if (!int.TryParse(token, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out b)) {
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + fadeType + " blue value, but got '" + token + "'");
datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
continue;
}
color.Red = (float)r / 255;
color.Green = (float)g / 255;
color.Blue = (float)b / 255;
if (fadeType == "fade")
mapInfo.FadeColor = color;
else
mapInfo.OutsideFogColor = color;
} else {
General.ErrorLogger.Add(ErrorType.Error, "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + fadeType + " color value.");
datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
}
}
//vertwallshade or horizwallshade
} else if (token == "vertwallshade" || token == "horizwallshade") {
string shadeType = token;
SkipWhitespace(true);
token = StripTokenQuotes(ReadToken());
//new format
if(token == "=") {
SkipWhitespace(true);
token = StripTokenQuotes(ReadToken());
}
int val = 0;
if(!ReadSignedInt(token, ref val)) {
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + shadeType + " value, but got '" + token + "'");
datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
continue;
}
if(shadeType == "vertwallshade")
mapInfo.VertWallShade = General.Clamp(val, -255, 255);
else
mapInfo.HorizWallShade = General.Clamp(val, -255, 255);
//fogdensity or outsidefogdensity
} else if(token == "fogdensity" || token == "outsidefogdensity") {
string densityType = token;
SkipWhitespace(true);
token = StripTokenQuotes(ReadToken());
//new format
if(token == "=") {
SkipWhitespace(true);
token = StripTokenQuotes(ReadToken());
}
int val;
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out val)) {
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + densityType + " value, but got '" + token + "'");
datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
continue;
}
if (densityType == "fogdensity") {
mapInfo.FogDensity = (int)(1024 * (256.0f / val));
} else {
mapInfo.OutsideFogDensity = (int)(1024 * (256.0f / val));
}
//doublesky
} else if (token == "doublesky") {
mapInfo.DoubleSky = true;
//evenlighting
} else if (token == "evenlighting") {
mapInfo.EvenLighting = true;
//smoothlighting
} else if (token == "smoothlighting") {
mapInfo.SmoothLighting = true;
//block end
} else if (token == "}") {
return (curBlockName == "map" || parseBlock(token, mapName));
}
}
}
return false;
}
private 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;
}
}
}