2012-05-21 23:51:32 +00:00
using System ;
2012-06-01 10:17:47 +00:00
using System.IO ;
2012-05-21 23:51:32 +00:00
using System.Collections.Generic ;
using System.Globalization ;
using System.Text ;
using SlimDX ;
using SlimDX.Direct3D9 ;
using CodeImp.DoomBuilder.GZBuilder.Data ;
namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
2012-07-12 22:34:12 +00:00
internal sealed class ModeldefStructure {
2012-06-01 19:53:14 +00:00
private const int MAX_MODELS = 4 ; //maximum models per modeldef entry, zero-based
2012-05-21 23:51:32 +00:00
2012-07-12 22:34:12 +00:00
internal ModeldefEntry Parse ( ModeldefParser parser ) {
2012-06-01 10:17:47 +00:00
string [ ] textureNames = new string [ 4 ] ;
string [ ] modelNames = new string [ 4 ] ;
2012-05-21 23:51:32 +00:00
string path = "" ;
Vector3 scale = new Vector3 ( 1 , 1 , 1 ) ;
float zOffset = 0 ;
2012-07-28 20:36:28 +00:00
float angleOffset = 0 ;
float pitchOffset = 0 ;
float rollOffset = 0 ;
2012-05-21 23:51:32 +00:00
string token ;
bool gotErrors = false ;
//read modeldef structure contents
while ( parser . SkipWhitespace ( true ) ) {
token = parser . ReadToken ( ) ;
if ( ! string . IsNullOrEmpty ( token ) ) {
2012-06-01 10:17:47 +00:00
token = parser . StripTokenQuotes ( token ) . ToLowerInvariant ( ) ; //ANYTHING can be quoted...
2012-07-28 20:36:28 +00:00
//path
2012-05-21 23:51:32 +00:00
if ( token = = "path" ) {
parser . SkipWhitespace ( true ) ;
path = parser . StripTokenQuotes ( parser . ReadToken ( ) ) . Replace ( "/" , "\\" ) ;
if ( string . IsNullOrEmpty ( path ) ) {
2012-06-01 10:17:47 +00:00
GZBuilder . GZGeneral . LogAndTraceWarning ( "Error in " + parser . Source + " at line " + parser . GetCurrentLineNumber ( ) + ": expected path to model, but got '" + token + "'" ) ;
2012-05-21 23:51:32 +00:00
gotErrors = true ;
break ;
}
2012-07-28 20:36:28 +00:00
//model
2012-05-21 23:51:32 +00:00
} else if ( token = = "model" ) {
parser . SkipWhitespace ( true ) ;
//model index
int modelIndex ;
2012-06-01 10:17:47 +00:00
token = parser . StripTokenQuotes ( parser . ReadToken ( ) ) ;
2012-05-21 23:51:32 +00:00
if ( ! int . TryParse ( token , NumberStyles . Integer , CultureInfo . InvariantCulture , out modelIndex ) ) {
// Not numeric!
2012-05-22 22:56:42 +00:00
GZBuilder . GZGeneral . LogAndTraceWarning ( "Error in " + parser . Source + " at line " + parser . GetCurrentLineNumber ( ) + ": expected model index, but got '" + token + "'" ) ;
2012-05-21 23:51:32 +00:00
gotErrors = true ;
break ;
}
2012-06-01 19:53:14 +00:00
if ( modelIndex > = MAX_MODELS ) {
2012-06-01 10:17:47 +00:00
GZBuilder . GZGeneral . LogAndTraceWarning ( "Error in " + parser . Source + " at line " + parser . GetCurrentLineNumber ( ) + ": GZDoom doesn't allow more than " + MAX_MODELS + " per MODELDEF entry!" ) ;
break ;
}
2012-07-28 20:36:28 +00:00
//model path
2012-05-21 23:51:32 +00:00
token = parser . StripTokenQuotes ( parser . ReadToken ( ) ) . ToLowerInvariant ( ) ;
if ( string . IsNullOrEmpty ( token ) ) {
2012-05-22 22:56:42 +00:00
GZBuilder . GZGeneral . LogAndTraceWarning ( "Error in " + parser . Source + " at line " + parser . GetCurrentLineNumber ( ) + ": expected model name, but got '" + token + "'" ) ;
2012-05-21 23:51:32 +00:00
gotErrors = true ;
break ;
} else {
//check extension
int dotPos = token . LastIndexOf ( "." ) ;
string fileExt = token . Substring ( token . LastIndexOf ( "." ) , token . Length - dotPos ) ;
if ( fileExt ! = ".md3" & & fileExt ! = ".md2" ) {
2012-06-01 10:17:47 +00:00
GZBuilder . GZGeneral . LogAndTraceWarning ( "Error in " + parser . Source + " at line " + parser . GetCurrentLineNumber ( ) + ": model '" + token + "' not parsed. Only MD3 and MD2 models are supported." ) ;
2012-05-21 23:51:32 +00:00
gotErrors = true ;
break ;
}
2012-06-01 10:17:47 +00:00
//GZDoom allows models with identical modelIndex, it uses the last one encountered
modelNames [ modelIndex ] = token ;
2012-05-21 23:51:32 +00:00
}
2012-07-28 20:36:28 +00:00
//skin
2012-05-21 23:51:32 +00:00
} else if ( token = = "skin" ) {
parser . SkipWhitespace ( true ) ;
//skin index
int skinIndex ;
2012-06-01 10:17:47 +00:00
token = parser . StripTokenQuotes ( parser . ReadToken ( ) ) ;
2012-05-21 23:51:32 +00:00
if ( ! int . TryParse ( token , NumberStyles . Integer , CultureInfo . InvariantCulture , out skinIndex ) ) {
// Not numeric!
2012-05-22 22:56:42 +00:00
GZBuilder . GZGeneral . LogAndTraceWarning ( "Error in " + parser . Source + " at line " + parser . GetCurrentLineNumber ( ) + ": expected skin index, but got '" + token + "'" ) ;
2012-05-21 23:51:32 +00:00
gotErrors = true ;
break ;
}
2012-06-01 19:53:14 +00:00
if ( skinIndex > = MAX_MODELS ) {
2012-06-01 10:17:47 +00:00
GZBuilder . GZGeneral . LogAndTraceWarning ( "Error in " + parser . Source + " at line " + parser . GetCurrentLineNumber ( ) + ": GZDoom doesn't allow more than " + MAX_MODELS + " per MODELDEF entry!" ) ;
break ;
}
2012-07-28 20:36:28 +00:00
//skin path
2012-05-21 23:51:32 +00:00
token = parser . StripTokenQuotes ( parser . ReadToken ( ) ) . ToLowerInvariant ( ) ;
if ( string . IsNullOrEmpty ( token ) ) {
2012-05-22 22:56:42 +00:00
GZBuilder . GZGeneral . LogAndTraceWarning ( "Error in " + parser . Source + " at line " + parser . GetCurrentLineNumber ( ) + ": expected skin name, but got '" + token + "'" ) ;
2012-05-21 23:51:32 +00:00
gotErrors = true ;
break ;
} else {
//check extension
int dotPos = token . LastIndexOf ( "." ) ;
string fileExt = token . Substring ( token . LastIndexOf ( "." ) , token . Length - dotPos ) ;
2012-06-01 10:17:47 +00:00
if ( Array . IndexOf ( TextureData . SUPPORTED_TEXTURE_EXTENSIONS , fileExt ) = = - 1 )
token = TextureData . INVALID_TEXTURE ;
2012-05-21 23:51:32 +00:00
2012-06-01 10:17:47 +00:00
//GZDoom allows skins with identical modelIndex, it uses the last one encountered
textureNames [ skinIndex ] = token ;
2012-05-21 23:51:32 +00:00
}
2012-07-28 20:36:28 +00:00
//scale
2012-05-21 23:51:32 +00:00
} else if ( token = = "scale" ) {
parser . SkipWhitespace ( true ) ;
2012-06-01 10:17:47 +00:00
token = parser . StripTokenQuotes ( parser . ReadToken ( ) ) ;
if ( ! parser . ReadSignedFloat ( token , ref scale . X ) ) {
2012-05-21 23:51:32 +00:00
// Not numeric!
2012-05-22 22:56:42 +00:00
GZBuilder . GZGeneral . LogAndTraceWarning ( "Error in " + parser . Source + " at line " + parser . GetCurrentLineNumber ( ) + ": expected scale X value, but got '" + token + "'" ) ;
2012-05-21 23:51:32 +00:00
gotErrors = true ;
break ;
}
parser . SkipWhitespace ( true ) ;
2012-06-01 10:17:47 +00:00
token = parser . StripTokenQuotes ( parser . ReadToken ( ) ) ;
if ( ! parser . ReadSignedFloat ( token , ref scale . Y ) ) {
2012-05-21 23:51:32 +00:00
// Not numeric!
2012-05-22 22:56:42 +00:00
GZBuilder . GZGeneral . LogAndTraceWarning ( "Error in " + parser . Source + " at line " + parser . GetCurrentLineNumber ( ) + ": expected scale Y value, but got '" + token + "'" ) ;
2012-05-21 23:51:32 +00:00
gotErrors = true ;
break ;
}
parser . SkipWhitespace ( true ) ;
2012-06-01 10:17:47 +00:00
token = parser . StripTokenQuotes ( parser . ReadToken ( ) ) ;
if ( ! parser . ReadSignedFloat ( token , ref scale . Z ) ) {
2012-05-21 23:51:32 +00:00
// Not numeric!
2012-05-22 22:56:42 +00:00
GZBuilder . GZGeneral . LogAndTraceWarning ( "Error in " + parser . Source + " at line " + parser . GetCurrentLineNumber ( ) + ": expected scale Z value, but got '" + token + "'" ) ;
2012-05-21 23:51:32 +00:00
gotErrors = true ;
break ;
}
2012-07-28 20:36:28 +00:00
//zoffset
2012-05-21 23:51:32 +00:00
} else if ( token = = "zoffset" ) {
parser . SkipWhitespace ( true ) ;
2012-06-01 10:17:47 +00:00
token = parser . StripTokenQuotes ( parser . ReadToken ( ) ) ;
if ( ! parser . ReadSignedFloat ( token , ref zOffset ) ) {
2012-05-21 23:51:32 +00:00
// Not numeric!
2012-05-22 22:56:42 +00:00
GZBuilder . GZGeneral . LogAndTraceWarning ( "Error in " + parser . Source + " at line " + parser . GetCurrentLineNumber ( ) + ": expected ZOffset value, but got '" + token + "'" ) ;
2012-05-21 23:51:32 +00:00
gotErrors = true ;
break ;
}
2012-07-28 20:36:28 +00:00
//angleoffset
} else if ( token = = "angleoffset" ) {
parser . SkipWhitespace ( true ) ;
token = parser . StripTokenQuotes ( parser . ReadToken ( ) ) ;
if ( ! parser . ReadSignedFloat ( token , ref angleOffset ) ) {
// Not numeric!
GZBuilder . GZGeneral . LogAndTraceWarning ( "Error in " + parser . Source + " at line " + parser . GetCurrentLineNumber ( ) + ": expected AngleOffset value, but got '" + token + "'" ) ;
gotErrors = true ;
break ;
}
//pitchoffset
} else if ( token = = "pitchoffset" ) {
parser . SkipWhitespace ( true ) ;
token = parser . StripTokenQuotes ( parser . ReadToken ( ) ) ;
if ( ! parser . ReadSignedFloat ( token , ref pitchOffset ) ) {
// Not numeric!
GZBuilder . GZGeneral . LogAndTraceWarning ( "Error in " + parser . Source + " at line " + parser . GetCurrentLineNumber ( ) + ": expected PitchOffset value, but got '" + token + "'" ) ;
gotErrors = true ;
break ;
}
//rolloffset
} else if ( token = = "rolloffset" ) {
parser . SkipWhitespace ( true ) ;
token = parser . StripTokenQuotes ( parser . ReadToken ( ) ) ;
if ( ! parser . ReadSignedFloat ( token , ref rollOffset ) ) {
// Not numeric!
GZBuilder . GZGeneral . LogAndTraceWarning ( "Error in " + parser . Source + " at line " + parser . GetCurrentLineNumber ( ) + ": expected RollOffset value, but got '" + token + "'" ) ;
gotErrors = true ;
break ;
}
//frameindex
2012-08-14 12:47:27 +00:00
} else if ( token = = "frameindex" | | token = = "frame" ) {
2012-06-01 10:17:47 +00:00
//parsed all required fields. if got more than one model - find which one(s) should be displayed
int len = modelNames . GetLength ( 0 ) ;
if ( ! gotErrors & & len > 1 ) {
string spriteLump = null ;
string spriteFrame = null ;
bool [ ] modelsUsed = new bool [ MAX_MODELS ] ;
//step back
parser . DataStream . Seek ( - token . Length - 1 , SeekOrigin . Current ) ;
//here we check which models are used in first encountered lump and frame
while ( parser . SkipWhitespace ( true ) ) {
token = parser . StripTokenQuotes ( parser . ReadToken ( ) ) . ToLowerInvariant ( ) ;
2012-08-14 12:47:27 +00:00
if ( token = = "frameindex" | | token = = "frame" ) {
bool frameIndex = ( token = = "frameindex" ) ;
parser . SkipWhitespace ( true ) ;
2012-06-01 10:17:47 +00:00
//should be sprite lump
token = parser . StripTokenQuotes ( parser . ReadToken ( ) ) . ToLowerInvariant ( ) ;
if ( string . IsNullOrEmpty ( spriteLump ) ) {
spriteLump = token ;
} else if ( spriteLump ! = token ) { //got another lump
for ( int i = 0 ; i < modelsUsed . Length ; i + + ) {
if ( ! modelsUsed [ i ] ) {
modelNames [ i ] = null ;
textureNames [ i ] = null ;
}
}
break ;
}
parser . SkipWhitespace ( true ) ;
//should be sprite frame
token = parser . StripTokenQuotes ( parser . ReadToken ( ) ) . ToLowerInvariant ( ) ;
if ( string . IsNullOrEmpty ( spriteFrame ) ) {
spriteFrame = token ;
} else if ( spriteFrame ! = token ) { //got another frame
for ( int i = 0 ; i < modelsUsed . Length ; i + + ) {
if ( ! modelsUsed [ i ] ) {
modelNames [ i ] = null ;
textureNames [ i ] = null ;
}
}
break ;
}
parser . SkipWhitespace ( true ) ;
//should be model index
token = parser . StripTokenQuotes ( parser . ReadToken ( ) ) ;
int modelIndex ;
if ( ! int . TryParse ( token , NumberStyles . Integer , CultureInfo . InvariantCulture , out modelIndex ) ) {
// Not numeric!
GZBuilder . GZGeneral . LogAndTraceWarning ( "Error in " + parser . Source + " at line " + parser . GetCurrentLineNumber ( ) + ": expected model index, but got '" + token + "'" ) ;
gotErrors = true ;
break ;
}
2012-06-01 19:53:14 +00:00
if ( modelIndex > = MAX_MODELS ) {
2012-06-01 10:17:47 +00:00
GZBuilder . GZGeneral . LogAndTraceWarning ( "Error in " + parser . Source + " at line " + parser . GetCurrentLineNumber ( ) + ": GZDoom doesn't allow more than " + MAX_MODELS + " per MODELDEF entry!" ) ;
gotErrors = true ;
break ;
}
if ( modelNames [ modelIndex ] = = null ) {
GZBuilder . GZGeneral . LogAndTraceWarning ( "Error in " + parser . Source + " at line " + parser . GetCurrentLineNumber ( ) + ": got model index, which doesn't correspond to any defined model!" ) ;
gotErrors = true ;
break ;
}
modelsUsed [ modelIndex ] = true ;
parser . SkipWhitespace ( true ) ;
2012-08-14 12:47:27 +00:00
//should be frame name or index. Currently I have no use for it
2012-06-01 10:17:47 +00:00
token = parser . StripTokenQuotes ( parser . ReadToken ( ) ) ;
2012-08-14 12:47:27 +00:00
if ( frameIndex ) {
int frame ;
if ( ! int . TryParse ( token , NumberStyles . Integer , CultureInfo . InvariantCulture , out frame ) ) {
// Not numeric!
GZBuilder . GZGeneral . LogAndTraceWarning ( "Error in " + parser . Source + " at line " + parser . GetCurrentLineNumber ( ) + ": expected model frame, but got '" + token + "'" ) ;
gotErrors = true ;
break ;
}
}
2012-06-01 10:17:47 +00:00
} else {
//must be "}", step back
parser . DataStream . Seek ( - token . Length - 1 , SeekOrigin . Current ) ;
break ;
}
}
}
2012-05-21 23:51:32 +00:00
break ;
}
}
}
//find closing brace, then quit;
while ( parser . SkipWhitespace ( true ) ) {
token = parser . ReadToken ( ) ;
if ( token = = "}" )
break ;
}
2012-07-28 20:36:28 +00:00
if ( gotErrors ) return null ;
2012-05-21 23:51:32 +00:00
//classname is set in ModeldefParser
ModeldefEntry mde = new ModeldefEntry ( ) ;
mde . Path = path ;
mde . Scale = scale ;
mde . zOffset = zOffset ;
2012-07-28 20:36:28 +00:00
mde . AngleOffset = angleOffset * ( float ) Math . PI / 180.0f ;
mde . RollOffset = rollOffset * ( float ) Math . PI / 180.0f ;
mde . PitchOffset = pitchOffset * ( float ) Math . PI / 180.0f ;
2012-05-21 23:51:32 +00:00
2012-06-01 10:17:47 +00:00
for ( int i = 0 ; i < textureNames . Length ; i + + ) {
2012-05-21 23:51:32 +00:00
if ( textureNames [ i ] ! = null & & modelNames [ i ] ! = null ) {
mde . TextureNames . Add ( textureNames [ i ] ) ;
mde . ModelNames . Add ( modelNames [ i ] ) ;
}
}
return mde ;
}
}
}