public static void ParseScript( CompositorManager compositorManager, Stream data, string groupName, string fileName )
{
string file = ( (FileStream)data ).Name;
string line = "";
CompositorScriptContext context = new CompositorScriptContext();
context.filename = file;
context.lineNo = 0;
StreamReader script = new StreamReader( data, System.Text.Encoding.UTF8 );
// parse through the data to the end
while ( ( line = ParseHelper.ReadLine( script ) ) != null )
{
context.lineNo++;
string[] splitCmd;
string[] args;
string arg;
// ignore blank lines and comments
if ( !( line.Length == 0 || line.StartsWith( "//" ) ) )
{
context.line = line;
splitCmd = SplitByWhitespace( line, 2 );
string token = splitCmd[ 0 ];
args = SplitArgs( splitCmd.Length == 2 ? splitCmd[ 1 ] : "" );
arg = ( args.Length > 0 ? args[ 0 ] : "" );
if ( context.section == CompositorScriptSection.None )
{
if ( token != "compositor" )
{
LogError( context, "First token is not 'compositor'!" );
break; // Give up
}
string compositorName = RemoveQuotes( splitCmd[ 1 ].Trim() );
context.compositor = (Compositor)compositorManager.Create( compositorName, groupName );
context.section = CompositorScriptSection.Compositor;
context.seenOpen = false;
continue; // next line
}
else
{
if ( !context.seenOpen )
{
if ( token == "{" )
context.seenOpen = true;
else
LogError( context, "Expected open brace; instead got {0}", token );
continue; // next line
}
switch ( context.section )
{
case CompositorScriptSection.Compositor:
switch ( token )
{
case "technique":
context.section = CompositorScriptSection.Technique;
context.technique = context.compositor.CreateTechnique();
context.seenOpen = false;
continue; // next line
case "}":
context.section = CompositorScriptSection.None;
context.seenOpen = false;
if ( context.technique == null )
{
LogError( context, "No 'technique' section in compositor" );
continue;
}
break;
default:
LogError( context,
"After opening brace '{' of compositor definition, expected 'technique', but got '{0}'",
token );
continue; // next line
}
break;
case CompositorScriptSection.Technique:
switch ( token )
{
case "texture":
ParseTextureLine( context, args );
break;
case "target":
context.section = CompositorScriptSection.Target;
context.target = context.technique.CreateTargetPass();
context.target.OutputName = arg.Trim();
context.seenOpen = false;
break;
case "target_output":
context.section = CompositorScriptSection.Target;
context.target = context.technique.OutputTarget;
context.seenOpen = false;
break;
case "compositor_logic":
if ( !OptionCount( context, token, 1, args.Length ) )
break;
context.technique.CompositorLogicName = args[ 0 ].Trim();
break;
case "}":
context.section = CompositorScriptSection.Compositor;
context.seenOpen = true;
break;
default:
LogIllegal( context, "technique", token );
break;
}
break;
case CompositorScriptSection.Target:
switch ( token )
{
case "input":
if ( OptionCount( context, token, 1, args.Length ) )
{
arg = args[ 0 ];
if ( arg == "previous" )
context.target.InputMode = CompositorInputMode.Previous;
else if ( arg == "none" )
context.target.InputMode = CompositorInputMode.None;
else
LogError( context, "Illegal 'input' arg '{0}'", arg );
}
break;
case "only_initial":
context.target.OnlyInitial = OnOffArg( context, token, args );
break;
case "visibility_mask":
if ( !OptionCount( context, token, 1, args.Length ) )
break;
context.target.VisibilityMask = ParseUint( context, arg );
break;
case "lod_bias":
if ( !OptionCount( context, token, 1, args.Length ) )
break;
context.target.LodBias = ParseInt( context, arg );
break;
case "material_scheme":
if ( !OptionCount( context, token, 1, args.Length ) )
break;
context.target.MaterialScheme = arg.Trim();
break;
case "pass":
context.section = CompositorScriptSection.Pass;
context.pass = context.target.CreatePass();
context.seenOpen = false;
if ( !OptionCount( context, token, 1, args.Length ) && !OptionCount( context, token, 2, args.Length ) )
break;
arg = args[ 0 ].Trim();
switch ( arg )
{
case "render_quad":
context.pass.Type = CompositorPassType.RenderQuad;
break;
case "clear":
context.pass.Type = CompositorPassType.Clear;
break;
case "stencil":
context.pass.Type = CompositorPassType.Stencil;
break;
case "render_scene":
context.pass.Type = CompositorPassType.RenderScene;
break;
case "render_custom":
context.pass.Type = CompositorPassType.RenderCustom;
context.pass.CustomType = args[ 1 ].Trim();
break;
default:
LogError( context, "In line '{0}', unrecognized compositor pass type '{1}'", arg );
break;
}
break;
case "}":
context.section = CompositorScriptSection.Technique;
context.seenOpen = true;
break;
default:
LogIllegal( context, "target", token );
break;
}
break;
case CompositorScriptSection.Pass:
switch ( token )
{
case "first_render_queue":
if ( !OptionCount( context, token, 1, args.Length ) )
break;
context.pass.FirstRenderQueue = (RenderQueueGroupID)ParseInt( context, args[ 0 ] );
break;
case "last_render_queue":
if ( !OptionCount( context, token, 1, args.Length ) )
break;
context.pass.LastRenderQueue = (RenderQueueGroupID)ParseInt( context, args[ 0 ] );
break;
case "identifier":
if ( !OptionCount( context, token, 1, args.Length ) )
break;
context.pass.Identifier = ParseUint( context, args[ 0 ] );
break;
case "material":
if ( !OptionCount( context, token, 1, args.Length ) )
break;
context.pass.MaterialName = args[ 0 ].Trim();
break;
case "input":
if ( !OptionCount( context, token, 3, args.Length ) )
break;
int index = 0;
if ( args.Length == 3 )
index = ParseInt( context, args[ 2 ] );
context.pass.SetInput( ParseInt( context, args[ 0 ] ), args[ 1 ].Trim(), index );
break;
case "clear":
context.section = CompositorScriptSection.Clear;
context.seenOpen = false;
break;
case "stencil":
context.section = CompositorScriptSection.Clear;
context.seenOpen = false;
break;
case "}":
context.section = CompositorScriptSection.Target;
context.seenOpen = true;
break;
default:
LogIllegal( context, "pass", token );
break;
}
break;
case CompositorScriptSection.Clear:
switch ( token )
{
case "buffers":
FrameBufferType fb = (FrameBufferType)0;
foreach ( string cb in args )
{
switch ( cb )
{
case "colour":
fb |= FrameBufferType.Color;
break;
case "color":
fb |= FrameBufferType.Color;
break;
case "depth":
fb |= FrameBufferType.Depth;
break;
case "stencil":
fb |= FrameBufferType.Stencil;
break;
default:
LogError( context, "When parsing pass clear buffers options, illegal option '{0}'", cb );
break;
}
}
break;
case "colour":
context.pass.ClearColor = ParseClearColor( context, args );
break;
case "color":
context.pass.ClearColor = ParseClearColor( context, args );
break;
case "depth_value":
if ( !OptionCount( context, token, 1, args.Length ) )
break;
context.pass.ClearDepth = ParseFloat( context, args[ 0 ] );
break;
case "stencil_value":
if ( !OptionCount( context, token, 1, args.Length ) )
break;
context.pass.ClearDepth = ParseInt( context, args[ 0 ] );
break;
case "}":
context.section = CompositorScriptSection.Pass;
context.seenOpen = true;
break;
default:
LogIllegal( context, "clear", token );
break;
}
break;
case CompositorScriptSection.Stencil:
switch ( token )
{
case "check":
context.pass.StencilCheck = OnOffArg( context, token, args );
break;
case "compare_func":
if ( !OptionCount( context, token, 1, args.Length ) )
break;
context.pass.StencilFunc = ParseCompareFunc( context, arg );
break;
case "ref_value":
if ( !OptionCount( context, token, 1, args.Length ) )
break;
context.pass.StencilRefValue = ParseInt( context, arg );
break;
case "mask":
if ( !OptionCount( context, token, 1, args.Length ) )
break;
context.pass.StencilMask = ParseInt( context, arg );
break;
case "fail_op":
if ( !OptionCount( context, token, 1, args.Length ) )
break;
context.pass.StencilFailOp = ParseStencilOperation( context, arg );
break;
case "depth_fail_op":
if ( !OptionCount( context, token, 1, args.Length ) )
break;
context.pass.StencilDepthFailOp = ParseStencilOperation( context, arg );
break;
case "pass_op":
if ( !OptionCount( context, token, 1, args.Length ) )
break;
context.pass.StencilPassOp = ParseStencilOperation( context, arg );
break;
case "two_sided":
if ( !OptionCount( context, token, 1, args.Length ) )
break;
context.pass.StencilTwoSidedOperation = OnOffArg( context, token, args );
break;
case "}":
context.section = CompositorScriptSection.Pass;
context.seenOpen = true;
break;
default:
LogIllegal( context, "stencil", token );
break;
}
break;
default:
LogError( context, "Internal compositor parser error: illegal context" );
break;
}
} // if
} // if
} // while
if ( context.section != CompositorScriptSection.None )
LogError( context, "At end of file, unterminated compositor script!" );
}