2012-06-01 10:17:47 +00:00
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 {
2012-07-12 22:34:12 +00:00
public sealed class MapinfoParser : ZDTextParser {
2012-06-01 10:17:47 +00:00
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
2013-08-10 11:28:51 +00:00
if ( mapInfo . FadeColor . Red > 0 | | mapInfo . FadeColor . Green > 0 | | mapInfo . FadeColor . Blue > 0 )
2012-06-01 10:17:47 +00:00
mapInfo . HasFadeColor = true ;
2013-08-10 11:28:51 +00:00
if ( mapInfo . OutsideFogColor . Red > 0 | | mapInfo . OutsideFogColor . Green > 0 | | mapInfo . OutsideFogColor . Blue > 0 )
2012-06-01 10:17:47 +00:00
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 ( ) ;
2013-09-11 08:49:45 +00:00
//sky1 or sky2
2012-06-01 10:17:47 +00:00
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!
2013-08-29 10:05:50 +00:00
General . ErrorLogger . Add ( ErrorType . Warning , "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber ( ) + ": expected " + skyType + " scroll speed value, but got '" + token + "'" ) ;
2012-06-01 10:17:47 +00:00
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
2013-03-18 13:52:27 +00:00
General . ErrorLogger . Add ( ErrorType . Error , "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber ( ) + ": expected " + skyType + " texture name." ) ;
2012-06-01 10:17:47 +00:00
}
//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
2013-03-18 13:52:27 +00:00
General . ErrorLogger . Add ( ErrorType . Error , "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber ( ) + ": expected " + skyType + " texture name." ) ;
2012-06-01 10:17:47 +00:00
}
}
2013-09-11 08:49:45 +00:00
//fade or outsidefog
2012-06-01 10:17:47 +00:00
} 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?
2013-09-11 08:49:45 +00:00
if ( getColor ( colorVal , ref color ) ) {
2012-06-01 10:17:47 +00:00
if ( fadeType = = "fade" )
mapInfo . FadeColor = color ;
else
mapInfo . OutsideFogColor = color ;
} else { //no, it's not
//try to get color values
int r , g , b ;
2013-09-11 08:49:45 +00:00
string [ ] parts = colorVal . Split ( new [ ] { " " } , StringSplitOptions . RemoveEmptyEntries ) ;
2012-06-01 10:17:47 +00:00
if ( parts . Length ! = 3 ) {
2013-03-18 13:52:27 +00:00
General . ErrorLogger . Add ( ErrorType . Error , "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber ( ) + ": expected " + fadeType + " color values, but got '" + token + "'" ) ;
2012-06-01 10:17:47 +00:00
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 ) ) {
2013-03-18 13:52:27 +00:00
General . ErrorLogger . Add ( ErrorType . Error , "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber ( ) + ": expected " + fadeType + " red value, but got '" + parts [ 0 ] + "'" ) ;
2012-06-01 10:17:47 +00:00
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 ) ) {
2013-03-18 13:52:27 +00:00
General . ErrorLogger . Add ( ErrorType . Error , "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber ( ) + ": expected " + fadeType + " green value, but got '" + parts [ 1 ] + "'" ) ;
2012-06-01 10:17:47 +00:00
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 ) ) {
2013-03-18 13:52:27 +00:00
General . ErrorLogger . Add ( ErrorType . Error , "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber ( ) + ": expected " + fadeType + " blue value, but got '" + parts [ 2 ] + "'" ) ;
2012-06-01 10:17:47 +00:00
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 {
2013-03-18 13:52:27 +00:00
General . ErrorLogger . Add ( ErrorType . Error , "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber ( ) + ": expected " + fadeType + " color value." ) ;
2012-06-01 10:17:47 +00:00
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?
2013-09-11 08:49:45 +00:00
if ( getColor ( token , ref color ) ) {
2012-06-01 10:17:47 +00:00
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!
2013-03-18 13:52:27 +00:00
General . ErrorLogger . Add ( ErrorType . Error , "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber ( ) + ": expected " + fadeType + " green value, but got '" + token + "'" ) ;
2012-06-01 10:17:47 +00:00
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!
2013-03-18 13:52:27 +00:00
General . ErrorLogger . Add ( ErrorType . Error , "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber ( ) + ": expected " + fadeType + " blue value, but got '" + token + "'" ) ;
2012-06-01 10:17:47 +00:00
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 {
2013-03-18 13:52:27 +00:00
General . ErrorLogger . Add ( ErrorType . Error , "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber ( ) + ": expected " + fadeType + " color value." ) ;
2012-06-01 10:17:47 +00:00
datastream . Seek ( - token . Length - 1 , SeekOrigin . Current ) ; //step back and try parsing this token again
}
}
2013-09-11 08:49:45 +00:00
//vertwallshade or horizwallshade
2012-06-01 10:17:47 +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
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
2012-06-01 10:17:47 +00:00
} else if ( token = = "doublesky" ) {
mapInfo . DoubleSky = true ;
2013-09-11 08:49:45 +00:00
//evenlighting
2012-06-01 10:17:47 +00:00
} else if ( token = = "evenlighting" ) {
mapInfo . EvenLighting = true ;
2013-09-11 08:49:45 +00:00
//smoothlighting
2012-06-01 10:17:47 +00:00
} else if ( token = = "smoothlighting" ) {
mapInfo . SmoothLighting = true ;
//block end
} else if ( token = = "}" ) {
2013-08-10 11:28:51 +00:00
return ( curBlockName = = "map" | | parseBlock ( token , mapName ) ) ;
2012-06-01 10:17:47 +00:00
}
}
}
return false ;
}
2013-09-11 08:49:45 +00:00
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 ;
}
2012-06-01 10:17:47 +00:00
2013-09-11 08:49:45 +00:00
//probably it's a color name?
2012-06-01 10:17:47 +00:00
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 ;
}
}
}