2014-02-21 14:42:12 +00:00
using System.Drawing ;
2012-06-01 10:17:47 +00:00
using System.Globalization ;
using System.IO ;
using SlimDX ;
using CodeImp.DoomBuilder.ZDoom ;
using CodeImp.DoomBuilder.GZBuilder.Data ;
namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
2013-09-11 09:47:53 +00:00
public sealed class MapinfoParser : ZDTextParser {
2012-06-01 10:17:47 +00:00
2013-09-11 09:47:53 +00:00
private MapInfo mapInfo ;
public MapInfo MapInfo { get { return mapInfo ; } }
2012-06-01 10:17:47 +00:00
2014-12-03 23:15:26 +00:00
public bool Parse ( Stream stream , string sourcefilename , string mapName )
{
2013-09-11 09:47:53 +00:00
base . Parse ( stream , sourcefilename ) ;
mapName = mapName . ToLowerInvariant ( ) ;
mapInfo = new MapInfo ( ) ;
2012-06-01 10:17:47 +00:00
2014-12-03 23:15:26 +00:00
while ( SkipWhitespace ( true ) )
{
2013-09-11 09:47:53 +00:00
string token = ReadToken ( ) ;
2014-12-03 23:15:26 +00:00
if ( token ! = null )
{
2013-09-11 09:47:53 +00:00
token = token . ToLowerInvariant ( ) ;
2014-12-03 23:15:26 +00:00
if ( ParseBlock ( token , mapName ) ) break ;
2013-09-11 09:47:53 +00:00
}
}
2012-06-01 10:17:47 +00:00
2013-09-11 09:47:53 +00:00
//check values
if ( mapInfo . FadeColor . Red > 0 | | mapInfo . FadeColor . Green > 0 | | mapInfo . FadeColor . Blue > 0 )
mapInfo . HasFadeColor = true ;
2012-06-01 10:17:47 +00:00
2013-09-11 09:47:53 +00:00
if ( mapInfo . OutsideFogColor . Red > 0 | | mapInfo . OutsideFogColor . Green > 0 | | mapInfo . OutsideFogColor . Blue > 0 )
mapInfo . HasOutsideFogColor = true ;
2012-06-01 10:17:47 +00:00
2013-09-11 09:47:53 +00:00
//Cannot fail here
return true ;
}
2012-06-01 10:17:47 +00:00
2013-09-11 09:47:53 +00:00
//returns true if parsing is finished
2014-12-03 23:15:26 +00:00
private bool ParseBlock ( string token , string mapName )
{
2013-09-11 09:47:53 +00:00
string curBlockName ;
2014-12-03 23:15:26 +00:00
if ( token = = "map" | | token = = "defaultmap" | | token = = "adddefaultmap" )
{
2013-09-11 09:47:53 +00:00
curBlockName = token ;
2014-12-03 23:15:26 +00:00
if ( token = = "map" ) //check map name
{
2013-09-11 09:47:53 +00:00
//get map name
SkipWhitespace ( true ) ;
token = ReadToken ( ) . ToLowerInvariant ( ) ;
2012-06-01 10:17:47 +00:00
2014-12-03 23:15:26 +00:00
if ( token ! = mapName ) return false ; //not finished, search for next "map", "defaultmap" or "adddefaultmap" block
}
else if ( token = = "defaultmap" )
{
2013-09-11 09:47:53 +00:00
//reset MapInfo
mapInfo = new MapInfo ( ) ;
}
2012-06-01 10:17:47 +00:00
2013-09-11 09:47:53 +00:00
//search for required keys
2014-12-03 23:15:26 +00:00
while ( SkipWhitespace ( true ) )
{
2013-09-11 09:47:53 +00:00
token = ReadToken ( ) . ToLowerInvariant ( ) ;
2013-09-11 08:49:45 +00:00
//sky1 or sky2
2014-12-03 23:15:26 +00:00
if ( token = = "sky1" | | token = = "sky2" )
{
2013-09-11 09:47:53 +00:00
string skyType = token ;
SkipWhitespace ( true ) ;
token = StripTokenQuotes ( ReadToken ( ) ) . ToLowerInvariant ( ) ;
//new format
2014-12-03 23:15:26 +00:00
if ( token = = "=" )
{
2013-09-11 09:47:53 +00:00
SkipWhitespace ( true ) ;
//should be sky texture name
token = StripTokenQuotes ( ReadToken ( ) ) ;
bool gotComma = ( token . IndexOf ( "," ) ! = - 1 ) ;
2013-09-12 09:51:56 +00:00
if ( gotComma ) token = token . Replace ( "," , "" ) ;
2013-09-11 09:47:53 +00:00
string skyTexture = StripTokenQuotes ( token ) . ToLowerInvariant ( ) ;
2014-12-03 23:15:26 +00:00
if ( ! string . IsNullOrEmpty ( skyTexture ) )
{
2013-09-11 09:47:53 +00:00
if ( skyType = = "sky1" )
mapInfo . Sky1 = skyTexture ;
else
mapInfo . Sky2 = skyTexture ;
//check if we have scrollspeed
SkipWhitespace ( true ) ;
token = StripTokenQuotes ( ReadToken ( ) ) ;
2014-12-03 23:15:26 +00:00
if ( ! gotComma & & token = = "," )
{
2013-09-11 09:47:53 +00:00
gotComma = true ;
SkipWhitespace ( true ) ;
token = ReadToken ( ) ;
}
2014-12-03 23:15:26 +00:00
if ( gotComma )
{
2013-09-11 09:47:53 +00:00
float scrollSpeed = 0 ;
2014-12-03 23:15:26 +00:00
if ( ! ReadSignedFloat ( token , ref scrollSpeed ) )
{
2013-09-11 09:47:53 +00:00
// 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 ;
2014-12-03 23:15:26 +00:00
}
else
{
2013-09-11 09:47:53 +00:00
datastream . Seek ( - token . Length - 1 , SeekOrigin . Current ) ; //step back and try parsing this token again
}
2014-12-03 23:15:26 +00:00
}
else
{
2013-09-11 09:47:53 +00:00
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." ) ;
}
2014-12-03 23:15:26 +00:00
}
//old format
else
{
2013-09-11 09:47:53 +00:00
//token should be sky1/2 name
2014-12-03 23:15:26 +00:00
if ( ! string . IsNullOrEmpty ( token ) )
{
2013-09-11 09:47:53 +00:00
if ( skyType = = "sky1" )
mapInfo . Sky1 = token ;
else
mapInfo . Sky2 = token ;
//try to read scroll speed
SkipWhitespace ( true ) ;
token = StripTokenQuotes ( ReadToken ( ) ) ;
float scrollSpeed = 0 ;
2014-12-03 23:15:26 +00:00
if ( ! ReadSignedFloat ( token , ref scrollSpeed ) )
{
2013-09-11 09:47:53 +00:00
// 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 ;
2014-12-03 23:15:26 +00:00
}
else
{
2013-09-11 09:47:53 +00:00
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." ) ;
}
}
2014-12-03 23:15:26 +00:00
}
2013-09-11 08:49:45 +00:00
//fade or outsidefog
2014-12-03 23:15:26 +00:00
else if ( token = = "fade" | | token = = "outsidefog" )
{
2013-09-11 09:47:53 +00:00
string fadeType = token ;
SkipWhitespace ( true ) ;
token = StripTokenQuotes ( ReadToken ( ) ) . ToLowerInvariant ( ) ;
2013-09-12 09:51:56 +00:00
//new format?
2014-12-03 23:15:26 +00:00
if ( token = = "=" )
{
2013-09-11 09:47:53 +00:00
SkipWhitespace ( true ) ;
token = ReadToken ( ) ;
2013-09-12 09:51:56 +00:00
}
2013-09-11 09:47:53 +00:00
2013-09-12 09:51:56 +00:00
//get the color value
string colorVal = StripTokenQuotes ( token ) . ToLowerInvariant ( ) . Replace ( " " , "" ) ;
2014-12-03 23:15:26 +00:00
if ( ! string . IsNullOrEmpty ( colorVal ) )
{
2013-09-12 09:51:56 +00:00
Color4 color = new Color4 ( ) ;
//try to get the color...
2014-12-03 23:15:26 +00:00
if ( GetColor ( colorVal , ref color ) )
{
2013-09-12 09:51:56 +00:00
if ( fadeType = = "fade" )
2013-09-11 09:47:53 +00:00
mapInfo . FadeColor = color ;
else
mapInfo . OutsideFogColor = color ;
2014-12-03 23:15:26 +00:00
}
else //...or not
{
2014-01-03 10:33:45 +00:00
General . ErrorLogger . Add ( ErrorType . Error , "Failed to parse " + fadeType + " value from string '" + colorVal + "' in '" + sourcename + "' at line " + GetCurrentLineNumber ( ) ) ;
2013-09-11 09:47:53 +00:00
datastream . Seek ( - token . Length - 1 , SeekOrigin . Current ) ; //step back and try parsing this token again
}
2014-12-03 23:15:26 +00:00
}
else
{
2013-09-12 09:51:56 +00:00
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
2013-09-11 09:47:53 +00:00
}
2014-12-03 23:15:26 +00:00
}
2013-09-11 08:49:45 +00:00
//vertwallshade or horizwallshade
2014-12-03 23:15:26 +00:00
else if ( token = = "vertwallshade" | | token = = "horizwallshade" )
{
2013-09-11 08:49:45 +00:00
string shadeType = token ;
SkipWhitespace ( true ) ;
token = StripTokenQuotes ( ReadToken ( ) ) ;
//new format
2014-12-03 23:15:26 +00:00
if ( token = = "=" )
{
2013-09-11 08:49:45 +00:00
SkipWhitespace ( true ) ;
token = StripTokenQuotes ( ReadToken ( ) ) ;
}
int val = 0 ;
2014-12-03 23:15:26 +00:00
if ( ! ReadSignedInt ( token , ref val ) )
{
2013-09-11 08:49:45 +00:00
// 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 ) ;
2014-12-03 23:15:26 +00:00
}
2013-09-11 08:49:45 +00:00
//fogdensity or outsidefogdensity
2014-12-03 23:15:26 +00:00
else if ( token = = "fogdensity" | | token = = "outsidefogdensity" )
{
2013-09-11 08:49:45 +00:00
string densityType = token ;
SkipWhitespace ( true ) ;
token = StripTokenQuotes ( ReadToken ( ) ) ;
//new format
2014-12-03 23:15:26 +00:00
if ( token = = "=" )
{
2013-09-11 08:49:45 +00:00
SkipWhitespace ( true ) ;
token = StripTokenQuotes ( ReadToken ( ) ) ;
}
int val ;
2014-12-03 23:15:26 +00:00
if ( ! int . TryParse ( token , NumberStyles . Integer , CultureInfo . InvariantCulture , out val ) )
{
2013-09-11 08:49:45 +00:00
// 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 ;
}
2014-12-03 23:15:26 +00:00
if ( densityType = = "fogdensity" )
2013-09-11 08:49:45 +00:00
mapInfo . FogDensity = ( int ) ( 1024 * ( 256.0f / val ) ) ;
2014-12-03 23:15:26 +00:00
else
2013-09-11 08:49:45 +00:00
mapInfo . OutsideFogDensity = ( int ) ( 1024 * ( 256.0f / val ) ) ;
2014-12-03 23:15:26 +00:00
}
//doublesky
else if ( token = = "doublesky" )
{
2013-09-11 09:47:53 +00:00
mapInfo . DoubleSky = true ;
2014-12-03 23:15:26 +00:00
}
2013-09-11 08:49:45 +00:00
//evenlighting
2014-12-03 23:15:26 +00:00
else if ( token = = "evenlighting" )
{
2013-09-11 09:47:53 +00:00
mapInfo . EvenLighting = true ;
2014-12-03 23:15:26 +00:00
}
2013-09-11 08:49:45 +00:00
//smoothlighting
2014-12-03 23:15:26 +00:00
else if ( token = = "smoothlighting" )
{
2013-09-11 09:47:53 +00:00
mapInfo . SmoothLighting = true ;
2014-12-03 23:15:26 +00:00
}
//block end
else if ( token = = "}" )
{
return ( curBlockName = = "map" | | ParseBlock ( token , mapName ) ) ;
2013-09-11 09:47:53 +00:00
}
}
}
return false ;
}
2014-12-03 23:15:26 +00:00
private static bool GetColor ( string name , ref Color4 color )
{
2013-09-11 09:47:53 +00:00
if ( name = = "black" ) return true ;
2013-09-11 08:49:45 +00:00
//probably it's a hex color (like FFCC11)?
int ci ;
2014-12-03 23:15:26 +00:00
if ( int . TryParse ( name , NumberStyles . HexNumber , CultureInfo . InvariantCulture , out ci ) )
{
2013-09-11 08:49:45 +00:00
color = new Color4 ( ci ) { Alpha = 1.0f } ;
return true ;
}
2012-06-01 10:17:47 +00:00
2013-09-11 08:49:45 +00:00
//probably it's a color name?
2013-09-11 09:47:53 +00:00
Color c = Color . FromName ( name ) ; //should be similar to C++ color name detection, I suppose
2014-12-03 23:15:26 +00:00
if ( c . IsKnownColor )
{
2013-09-11 09:47:53 +00:00
color = new Color4 ( c ) ;
return true ;
}
return false ;
}
}
2012-06-01 10:17:47 +00:00
}