My favorites | English | Sign in

Faster apps faster - GWT 2.0 with Speed Tracer New!

O3D Shading Language

Introduction

O3D is a system designed around fully programmable GPUs. At its lowest level, all functionality is expressed using programmable shaders, with no fixed-function pipeline. The O3D shading language is supported on all targeted platforms: Windows (with DirectX), Mac OSX (with OpenGL) and Linux (with OpenGL). The language uses features supported by both the HLSL Shader Model 2 and Cg (with the arbvp1/arbfp1 compiler targets).

For O3D programming, both the vertex shader and the pixel shader (the "vertex program" and "fragment program," in OpenGL terminology) are contained in the same file. In this way, the two shaders can share data structure declarations, uniform parameters, and so on.

This document covers the following material:

  • Standard annotations and semantics (SAS), which allow O3D programs to pass values for standard transform parameters in to programmable shaders
  • Differences between the O3D shading language and the HLSL and Cg shading languages.

Standard Annotations and Semantics (SAS)

In order to make programmable shaders easier to use, the O3D plug-in supports NVidia's Standard Annotations and Semantics (SAS), specifically with respect to the Transform semantics. When setting up an effect and a material, it is common to call effect.createUniformParameters(material). This call will create parameters on the material for all uniform variables located in the .fx source. However, if any matrix parameters contained in the shader are tagged with one of the 24 predefined standard transform semantics (see table below), they will be treated specially. In particular, no explicit parameter will be created on the material. This task will be handled internally by O3D. The value of the parameter will be some combination of the world, view, and projection matrices, as described below.

The world matrix in O3D is computed to be the concatenation of the current Transform path above the DrawElement being rendered (due to instancing, there may be more than one path to a DrawElement). The view and projection matrices are retrieved from the DrawContext associated with the material's DrawList in the current TreeTraversal. The DrawContext node holds view and projection parameters of Matrix4 type, which represent the viewing and projection transformations respectively.

In the following table, the Expression column describes the expression used to evaluate the given semantic. It's not a real expression syntax, but rather uses a loose foo.bar syntax to mean "the parameter named bar on the node named foo." transform is the Transform node immediately above the DrawElement being rendered, and draw_context is the DrawContext associated with the material's DrawList through the current TreeTraversal. * means matrix multiplication, inverse() is the matrix inverse of its argument, and transpose() is the matrix transpose of its argument.

Semantic Value Expression
World The concatenation of the current Transform path above the DrawElement being rendered. transform.world
WorldInverse The inverse of the World matrix. inverse(transform.world)
WorldTranspose The transpose of the World matrix. transpose(transform.world)
WorldInverseTranspose The inverse transpose of the World matrix. transpose(inverse(transform.world))
View The Context's View matrix (usually a camera transform). draw_context.view
ViewInverse The inverse of the Context's View matrix. inverse(draw_context.view)
ViewTranspose The transpose of the Context's View matrix. tranpose(draw_context.view)
ViewInverseTranspose The inverse transpose of the Context's View matrix. transpose(inverse(draw_context.view))
Projection The Context's Projection matrix (usually a perspective or orthographic projection). draw_context.projection
ProjectionInverse The inverse of the Projection matrix. inverse(draw_context.projection)
ProjectionTranspose The transpose of the Projection matrix. transpose(draw_context.projection)
ProjectionInverseTranspose The inverse transpose of the Projection matrix. transpose(inverse(draw_context.projection))
WorldView Concatenation of the World and View matrices. draw_context.view*transform.world
WorldViewInverse Inverse of the WorldView matrix. inverse(draw_context.view*transform.world)
WorldViewTranspose) Transpose of the WorldView matrix. transpose(draw_context.view*transform.world)
WorldViewInverseTranspose Inverse transpose of the WorldView matrix. transpose(inverse(draw_context.view*transform.world))
ViewProjection Concatenation of the View and Projection matrices. draw_context.projection*draw_context.view
ViewProjectionInverse Inverse of the ViewProjection matrix. inverse(draw_context.projection*draw_context.view)
ViewProjectionTranspose Transpose of the ViewProjection matrix. transpose(draw_context.projection*draw_context.view)
ViewProjectionInverseTranspose Inverse transpose of the ViewProjection matrix. transpose(inverse(draw_context.projection*draw_context.view))
WorldViewProjection Concatenation of the World, View and Projection matrices. draw_context.projection*draw_context.view*transform.world
WorldViewProjectionInverse Inverse of the WorldViewProjection matrix. inverse(draw_context.projection*draw_context.view*transform.world)
WorldViewProjectionTranspose Transpose of the WorldViewProjection matrix. transpose(draw_context.projection*draw_context.view*transform.world)
WorldViewProjectionInverseTranspose Inverse transpose of the WorldViewProjection matrix. transpose(inverse(draw_context.projection*draw_context.view*transform.world))

O3D Shading Language

Parameter Datatypes

The following table lists the datatypes supported as uniform parameters in O3D shaders and the corresponding types in the O3D JavaScript API:

Shading Language Datatype O3D Datatype
float ParamFloat
float2 ParamFloat2
float3 ParamFloat3
float4 ParamFloat4
float4x4 ParamMatrix4
int ParamInteger
bool ParamBoolean
sampler ParamSampler

Unsupported Parameter Datatypes

The following Cg/HLSL datatypes are unsupported as uniform parameters. Note that they can still be used as temporaries, varyings, and function parameters inside shaders.

int2
int3
int4
bool2
bool3
bool4
float2x2
float2x3
float2x4
float3x2
float3x3
float3x4
float4x2
float4x3

Arrays of any type other than float are also unsupported.

Mandatory Comments in O3D Shaders

O3D requires three pieces of information in a special comment format. They should appear as follows:

#o3d VertexShaderEntryPoint FunctionName
#o3d PixelShaderEntryPoint FunctionName
#o3d MatrixLoadOrder ( RowMajor | ColumnMajor )
where

VertexShaderEntryPoint

Indicates the function entry point for the vertex shader. This is the function that is called for each vertex in the current primitive when this shader is active. It can be used for computations that are performed per vertex, such as transformation from world space into clip space, or for per-vertex lighting.
PixelShaderEntryPoint Indicates the entry point for the pixel shader. This is the function that is called for each rasterized pixel in the current primitive while this shader is active. It is used for per-pixel computations, such as texture mapping or per-pixel lighting.
MatrixLoadOrder Indicates how matrix uniform parameters are loaded into the GPU. RowMajor indicates that all matrix parameters are loaded in row-major order (DX-style). Use this setting if your shaders specify matrix/vector multiplications as mul(vector, matrix). ColumnMajor indicates that all matrix parameters are loaded in column-major order (OpenGL-style). Use this setting if your shaders specify matrix/multiplications as mul(matrix, vector).

Unsupported Features

There are several features of FX and CgFX files that are not supported in O3D.

Technique Blocks

No techniques should be specified in the shader file. Instead, the mandatory comment fields described above should indicate the vertex and pixel shader entry points. The sample COLLADA Converter can be used to automatically convert CgFX and FX shader files containing techniques to the O3D format.

Multipass Techniques

FX and CgFX files may contain techniques with more than one pass. The O3D system supports only single-pass shaders and will reject shaders containing more than one pass. Multipass techniques can still be created programmatically in JavaScript using the O3D API.

Techniques with Compile-time Parameters

Although the O3D system will not accept a shader file containing a technique block, the sample COLLADA Converter will accept such technique blocks and automatically convert them to the O3D format. However, the Converter will not accept techniques containing compile statements with arguments. For example:

VertexShader = compile vs_2_0 std_dp_VS(foo, bar);

All arguments to the vertex shader entry point function should be vertex attributes, and all arguments to the pixel shader entry point function should be varying parameters.

Unsupported Cg features

Unsized Arrays

Cg allows the user to specify arrays as having no size:

uniform float kernel[];

This technique allows the programmer to change the size of the array on the fly, and the Cg runtime will automatically recompile the shader when necessary to accommodate the new array size. This technique is not supported in HLSL and hence is prohibited in O3D shaders. To achieve similar functionality in O3D, create the shader string with the size of the array as a replaceable constant string and perform a JavaScript substitution on the shader string at runtime before compiling the shader. For example, in the shader, use this code:

uniform float kernel[KERNEL_SIZE];

In JavaScript, call this code each time KERNEL_SIZE changes:

fxString = fxString.replace(/KERNEL_SIZE/, kernelSize);
var effect = g_pack.createObject('Effect');
effect.loadFromFXString(fxString);
Interfaces

Cg allows the user to specify interfaces or variables whose type can be redefined on the fly. This functionality is not supported in O3D.

Unsupported HLSL Features

Implicit Casts in Intrinsic Functions

The HLSL compiler is a bit more forgiving about datatypes than Cg. For example, the HLSL compiler will happily perform a mul() of a float3 vector and a float4x4 matrix:

uniform float4x4 worldViewProjection;
...
float3 v1 = float3(1.0, 2.0, 3.0);
float4 v2 = mul(v1, worldViewProjection);

Cg will not perform this operations and requires a conversion—in this case:

uniform float4x4 worldViewProjection;
...
float3 v1 = float3(1.0, 2.0, 3.0);
float4 v2 = mul(float4(v1, 1.0), worldViewProjection);

All parameters to intrinsic functions in O3D should match the width of their datatypes (float4x4 to float4, float3x3 to float3, etc).

Scripts

The Script feature of HLSL, used to implement complex rendering effects, is not supported in O3D.

Functions

The tex2Dbias() function is not supported in O3D pixel shaders.

COLLADAFX

There are actually two paths for using shaders in the sample COLLADA converter: separate shaders, embedded in the COLLADA file itself, or combined vertex and fragment shaders in an FX or CgFX file. The O3D sample converter currently supports a modification of the second option, where both shaders are combined in a separate file, referenced by the COLLADA file, in the special shader format described above.

Sample COLLADA Converter

As part of the O3D SDK, an executable sample COLLADA Converter can be used to convert an existing COLLADA file into a format supported by O3D. The result is a a gzipped tar file containing all assets (texture files, shader files, vertices, skinning data, and animation) as well as a sample format JSON file that contains a representation of the structure of the original COLLADA file.

In addition, the sample Converter will convert shader files in either supported format (FX shaders with a ps_2_0/vs_2_0 technique, as supported in Max, or CgFX shaders having an arbfp1/arbvp1 technique, as supported in Maya) to our internal shading language format. It will remove the technique blocks from the shader and insert the entry points into the VertexShaderEntryPoint and PixelShaderEntryPoint comment formats. It will also set the MatrixLoadOrder to RowMajor (for DX) or ColumnMajor (for OpenGL). Finally, it will remove all sampler state and render state from the shader files and place those states into the sample format JSON file as O3D State objects and settings.

O3D Shading Language Grammar

The following is the ANTLR grammar used by the Converter to recognize O3D-compatible shaders.

translation_unit
  : ( noise global_declaration )* EOF
  ;

noise
  : ( COMMENT | WHITESPACE | MULTILINE_COMMENT )*
  | LINE_DIRECTIVE
  ;

global_declaration
  : function_declaration
  | sampler_declaration
  | texture_declaration
  | struct_definition
  | typedef_definition
  | var_declaration
  | technique_definition
  ;

var_declaration
  : var_storage_class* var_type_modifier? var_datatype id_declaration semantic?
    annotation_list? ('=' initializer)? var_packoffset? var_register_bind? SEMI
  ;

var_storage_class
  : EXTERN
  | NOINTERPOLATION
  | SHARED
  | STATIC
  | UNIFORM
  | VOLATILE
  ;

var_type_modifier
  : T_CONST
  | ROW_MAJOR
  | COLUMN_MAJOR;

var_datatype
  : buffer_type_specifier
  | scalar_type_or_string_specifier
  | vector_type_specifier
  | matrix_type_specifier
  | struct_type_specifier
  ;

var_packoffset
  : 'packoffset' LPAREN register_name (DOT ID)? RPAREN
  ;

var_register_bind
  : COLON register_name
  ;

id_declaration
  : ID ( LBRACKET constant_expression RBRACKET )?
  ;

function_declaration
  : function_storage_class?
    function_type_specifier ID LPAREN argument_list RPAREN semantic?
    function_body (SEMI)?
  ;

function_storage_class
  : INLINE
  ;

function_type_specifier
  : scalar_type_specifier
  | vector_type_specifier
  | matrix_type_specifier
  | struct_type_specifier
  | T_VOID
  ;

semantic
  :    COLON semantic_specifier ;

param_type_specifier
  : scalar_type_specifier
  | vector_type_specifier
  | matrix_type_specifier
  | struct_type_specifier
  | string_type_specifier
  | sampler_type_specifier
  ;

basic_type_specifier
  : scalar_type_specifier
  | vector_type_specifier
  | matrix_type_specifier
  | string_type_specifier
  ;

typedef_definition
  : TYPEDEF
  ;

buffer_type_specifier
  : (BUFFER '<' var_datatype '>' ID)
  ;

technique_definition
  : TECHNIQUE ID annotation_list? '{' ( pass )+  '}' SEMI?
  | TECHNIQUE annotation_list? '{' ( pass )+  '}' SEMI?
  ;

pass
  : PASS ID? annotation_list? '{' ( state_assignment )*  '}' SEMI?
  ;

state_assignment [o3d
::PassDeclaration& pass]
  : VERTEXSHADER '=' 'compile' ID variable_or_call_expression SEMI
  | FRAGMENTSHADER '=' 'compile' ID variable_or_call_expression SEMI
  | ID '=' primary_expression SEMI
  ;

scalar_type_specifier
  : 'bool'
  | 'int'
  | 'uint'
  | 'half'
  | FLOAT
  | 'double'
  ;

scalar_type_or_string_specifier
  : scalar_type_specifier
  | string_type_specifier
  ;

vector_type_specifier
  : 'bool1'
  | 'bool2'
  | 'bool3'
  | 'bool4'
  | 'int1'
  | 'int2'
  | 'int3'
  | 'int4'
  | 'uint1'
  | 'uint2'
  | 'uint3'
  | 'uint4'
  | 'half1'
  | 'half2'
  | 'half3'
  | 'half4'
  | 'float1'
  | 'float2'
  | 'float3'
  | 'float4'
  | 'double1'
  | 'double2'
  | 'double3'
  | 'double4'
  | VECTOR '<' scalar_type_specifier ',' DECIMAL_LITERAL '>'
  ;

matrix_type_specifier
  : 'float1x1'
  | 'float1x2'
  | 'float1x3'
  | 'float1x4'
  | 'float2x1'
  | 'float2x2'
  | 'float2x3'
  | 'float2x4'
  | 'float3x1'
  | 'float3x2'
  | 'float3x3'
  | 'float3x4'
  | 'float4x1'
  | 'float4x2'
  | 'float4x3'
  | 'float4x4'
  | MATRIX '<' scalar_type_specifier ','
    DECIMAL_LITERAL ',' DECIMAL_LITERAL '>'
  ;

string_type_specifier
  : STRING
  ;

sampler_declaration
  : sampler_type_specifier id_declaration
    ( '=' 'sampler_state' '{' sampler_state_declaration+ '}' )? SEMI
  ;

sampler_state_declaration
  : TEXTURE '=' '<' ID '>' SEMI
  | TEXTURE '=' '(' ID ')' SEMI
  | ID '=' initializer SEMI
  ;

sampler_type_specifier
  : 'sampler'
  | 'sampler1D'
  | 'sampler2D'
  | 'sampler3D'
  | 'samplerCUBE'
  | 'sampler_state'
  | 'SamplerComparisonState' | 'samplercomparisonstate'
  ;

texture_declaration
  : texture_type_specifier ID semantic? annotation_list? SEMI
  ;

texture_type_specifier
  : TEXTURE
  | TEXTURE1D
  | TEXTURE2D
  | TEXTURE3D
  | TEXTURECUBE
  | TEXTURERECT
  ;

struct_type_specifier
  : ID
  | struct_definition
  | STRUCT ID
  ;

annotation_list
  : '<' annotation* '>'
  ;

annotation
  : basic_type_specifier ID '=' initializer SEMI
  ;

initializer
  : expression
  | '{' expression ( ',' expression )* '}'
  ;

register_name
  : REGISTER '(' input_register_name | output_register_name ')';

input_register_name
  : ID DECIMAL_LITERAL
  | ID
  ;

output_register_name
  : ID
  ;

pack_offset
  : .+ ;

argument_list
  : ( param_declaration ( COMMA param_declaration )* )?
  ;

param_declaration
  : param_direction? param_variability? param_type_specifier id_declaration semantic?
  ;

param_variability
  : T_CONST
  | UNIFORM
  ;

param_direction
  : T_IN
  | T_OUT
  | T_INOUT
  ;

function_body
  : LCURLY ( decl_or_statement )* RCURLY
  ;

decl_or_statement
  : assignment_statement
  | ( T_CONST )? vector_type_specifier init_declarator_list SEMI
  | ( T_CONST )? scalar_type_specifier init_declarator_list SEMI
  | ( T_CONST )? matrix_type_specifier init_declarator_list SEMI
  | struct_definition ( init_declarator_list )? SEMI
  | STRUCT ID init_declarator_list SEMI
  | init_declarator_list SEMI
  | statement
  ;

init_declarator_list
  : init_declarator ( COMMA init_declarator )* ;

init_declarator
  : declarator ( ASSIGN expression )? ;

declarator
  : ID ( LBRACKET ( constant_expression )? RBRACKET )*
  ;

struct_definition
  : STRUCT ( ID )? LCURLY struct_declaration_list RCURLY ID? SEMI
  ;

struct_declaration_list
  : ( struct_interpolation_modifier?
    (scalar_type_specifier|vector_type_specifier) ID
    (COLON semantic_specifier)? SEMI )+
  ;

struct_interpolation_modifier
  : T_LINEAR
  | CENTROID
  | NOINTERPOLATION
  | NOPERSPECTIVE
  ;

semantic_specifier
  : ID
  ;

statement
  : assignment_statement
  | post_modify_statement
  | pre_modify_statement
  | expression_statement
  | compound_statement
  | selection_statement
  | iteration_statement
  | jump_statement
  | SEMI
  ;

assignment_statement
  : lvalue_expression assignment_operator expression SEMI
  ;

pre_modify_statement
  : pre_modify_expression SEMI 
  ;

pre_modify_expression
  : self_modify_operator lvalue_expression 
  ;

post_modify_statement
  : post_modify_expression SEMI 
  ;

post_modify_expression
  : lvalue_expression self_modify_operator 
  ;

self_modify_operator
  : PLUS_PLUS | MINUS_MINUS 
  ;

expression_statement
  : expression SEMI
  ;

compound_statement
  : LCURLY (
          init_declarator_list SEMI
        | ( T_CONST )? vector_type_specifier init_declarator_list SEMI
        | ( T_CONST )? scalar_type_specifier init_declarator_list SEMI
        | struct_definition ( init_declarator_list )? SEMI
        | STRUCT ID init_declarator_list SEMI
        | statement
        )*
    RCURLY
  ;

selection_statement
  : IF LPAREN expression RPAREN statement ( ELSE statement )?
  ;

iteration_statement
  : WHILE LPAREN expression RPAREN statement
  | FOR LPAREN assignment_statement equality_expression SEMI modify_expression RPAREN statement
  | DO statement WHILE LPAREN expression RPAREN SEMI
  ;

modify_expression
  : lvalue_expression assignment_operator expression
  | pre_modify_expression
  | post_modify_expression
  ;

jump_statement
  : BREAK SEMI
  | CONTINUE
  | RETURN ( expression )? SEMI
  | DISCARD
  ;

expression
  : conditional_expression
  ;

assignment_operator
  : ASSIGN
  | MUL_ASSIGN
  | DIV_ASSIGN
  | ADD_ASSIGN
  | SUB_ASSIGN
  | BITWISE_AND_ASSIGN
  | BITWISE_OR_ASSIGN
  | BITWISE_XOR_ASSIGN
  | BITWISE_SHIFTL_ASSIGN
  | BITWISE_SHIFTR_ASSIGN
  ;

constant_expression
  : (ID) => variable_expression
  | literal_value
  ;

conditional_expression
  : logical_or_expression ( QUESTION expression COLON conditional_expression )?
  ;

logical_or_expression
  : exclusive_or_expression ( OR exclusive_or_expression )*
  ;

logical_and_expression
  : ( NOT )? inclusive_or_expression ( AND ( NOT )? inclusive_or_expression )*
  ;

inclusive_or_expression
  : exclusive_or_expression (BITWISE_OR exclusive_or_expression )*
  ;

exclusive_or_expression
  : and_expression ( BITWISE_XOR and_expression )*
  ;

and_expression
  : equality_expression ( BITWISE_AND equality_expression )*
  ;

equality_expression
  : relational_expression ( (EQUAL|NOT_EQUAL) relational_expression )*
  ;

relational_expression
  : shift_expression ( (LESS|GREATER|LESSEQUAL|GREATEREQUAL) shift_expression )*
  ;

shift_expression
  : additive_expression ( (BITWISE_SHIFTL|BITWISE_SHIFTR) additive_expression )*
  ;

additive_expression
  : multiplicative_expression ( (PLUS|MINUS) multiplicative_expression )*
  ;

multiplicative_expression
  : cast_expression ( (MUL|DIV|MOD) cast_expression )*
  ;

cast_expression
  : LPAREN ID RPAREN postfix_expression
  | LPAREN basic_type_specifier RPAREN postfix_expression
  | unary_expression
  ;

unary_expression
  : (PLUS|MINUS) unary_expression
  | postfix_expression
  ;

postfix_expression
  : primary_expression ( postfix_suffix )?
  ;

lvalue_expression
  : variable_expression ( postfix_suffix )?
  ;

postfix_suffix
  : ( DOT primary_expression )+
  ;

primary_expression
  : constructor
  | variable_or_call_expression
  | literal_value
  | LPAREN expression RPAREN
  ;

variable_expression
  : ID ( LBRACKET expression RBRACKET )?
  ;

variable_or_call_expression
  returns [o3d
::String identifier, o3d
::String arglist]
  : ID
    (
      ( ( LBRACKET expression RBRACKET )? )
      |
      ( LPAREN argument_expression_list RPAREN )
    )
  ;

constructor
  : ( vector_type_specifier | matrix_type_specifier )
    LPAREN expression ( COMMA expression )* RPAREN
  ;

argument_expression_list
  : ( expression ( COMMA expression )* )?
  ;

int_literal
  : DECIMAL_LITERAL
  ;

literal_value
  : DECIMAL_LITERAL
  | FLOAT_LITERAL
  | STRING_LITERAL+
  | ( T_FALSE | T_TRUE )
  ;

float_literal
  : FLOAT_LITERAL
  ;

NOT           : '!' ;
NOT_EQUAL     : '!=' ;
AND           : '&&' ;
LPAREN        : '(' ;
RPAREN        : ')' ;
MUL           : '*' ;
MUL_ASSIGN    : '*=' ;
PLUS          : '+' ;
PLUS_PLUS     : '++' ;
ADD_ASSIGN    : '+=' ;
COMMA         : ',' ;
MINUS         : '-' ;
MINUS_MINUS   : '--' ;
SUB_ASSIGN    : '-=' ;
DIV           : '/' ;
DIV_ASSIGN    : '/=' ;
MOD_ASSIGN    :  '%=';
COLON         : ':' ;
SEMI          : ';' ;
LESS          : '<' ;
LESSEQUAL     : '<=' ;
ASSIGN        : '=' ;
EQUAL         : '==' ;
GREATER       : '>' ;
GREATEREQUAL  : '>=' ;
QUESTION      : '?' ;
LBRACKET      : '[' ;
RBRACKET      : ']' ;
LCURLY        : '{' ;
OR            : '||' ;
RCURLY        : '}' ;
DOT           : '.' ;
BITWISE_NOT    : '~';
BITWISE_SHIFTL : '<<';
BITWISE_SHIFTR : '>>';
BITWISE_AND    : '&';
BITWISE_OR     : '|';
BITWISE_XOR    : '^';
BITWISE_SHIFTL_ASSIGN : '<<=';
BITWISE_SHIFTR_ASSIGN : '>>=';
BITWISE_AND_ASSIGN    : '&=';
BITWISE_OR_ASSIGN     : '|=';
BITWISE_XOR_ASSIGN    : '^=';

BREAK            : 'break';
BUFFER           : 'buffer';
COLUMN_MAJOR     : 'column_major';
CBUFFER          : 'cbuffer';
CENTROID         : 'centroid';
T_CONST          : 'const';
CONTINUE         : 'continue';
DISCARD          : 'discard';
DO               : 'do';
ELSE             : 'else';
EXTERN           : 'extern';
T_FALSE          : 'false';
FLOAT            : (('f'|'F')('l'|'L')('o'|'O')('a'|'A')('t'|'T'));
FOR              : 'for';
IF               : 'if';
T_IN             : 'in';
INLINE           : 'inline';
T_INOUT          : 'inout';
T_LINEAR         : 'linear';
MATRIX           : ('m'|'M')('a'|'A')('t'|'T')('r'|'R')('i'|'I')('x'|'X');
NAMESPACE        : 'namespace';
NOINTERPOLATION  : 'nointerpolation';
NOPERSPECTIVE    : 'noperspective';
T_OUT            : 'out';
RETURN           : 'return';
REGISTER         : 'register';
ROW_MAJOR        : 'row_major';
SHARED           : 'shared';
STATEBLOCK       : 'stateblock';
STATEBLOCK_STATE : 'stateblock_state';
STATIC           : 'static';
STRING           : ('s'|'S')('t'|'T')('r'|'R')('i'|'I')('n'|'N')('g'|'G');
STRUCT           : 'struct';
SWITCH           : 'switch';
TBUFFER          : 'tbuffer';
TEXTURE          :
  ('t'|'T')('e'|'E')('x'|'X')('t'|'T')('u'|'U')('r'|'R')('e'|'E');
TEXTURE1D        : 'Texture1D';
TEXTURE1DARRAY   : 'Texture1DArray';
TEXTURE2D        : 'Texture2D';
TEXTURE2DARRAY   : 'Texture2DArray';
TEXTURE2DMS      : 'Texture2DMS';
TEXTURE2DMSARRAY : 'Texture2DMSArray';
TEXTURE3D        : 'Texture3D';
TEXTURECUBE      : 'TextureCUBE';
TEXTURECUBEARRAY : 'TextureCUBEArray';
TEXTURERECT      : 'TextureRECT';
T_TRUE           : 'true';
TYPEDEF          : 'typedef';
UNIFORM          : 'uniform';
VECTOR           : ('v'|'V')('e'|'E')('c'|'C')('t'|'T')('o'|'O')('r'|'R');
T_VOID           : 'void';
VOLATILE         : 'volatile';
WHILE            : 'while';

PASS           : ('p'|'P')('a'|'A')('s'|'S')('s'|'S');

TECHNIQUE      : ('t'|'T')('e'|'E')('c'|'C')('h'|'H')
                 ('n'|'N')('i'|'I')('q'|'Q')('u'|'U')('e'|'E')
               ;

VERTEXSHADER
  : (('v'|'V')('e'|'E')('r'|'R')('t'|'T')('e'|'E')('x'|'X'))
    ((('s'|'S')('h'|'H')('a'|'A')('d'|'D')('e'|'E')('r'|'R')) |
     (('p'|'P')('r'|'R')('o'|'O')('g'|'G')('r'|'R')('a'|'A')('m'|'M')))
  ;

FRAGMENTSHADER
  : (('f'|'F')('r'|'R')('a'|'A')('g'|'G')('m'|'M')('e'|'E')('n'|'N')('t'|'T')
     ('p'|'P')('r'|'R')('o'|'O')('g'|'G')('r'|'R')('a'|'A')('m'|'M'))
  | (('p'|'P')('i'|'I')('x'|'X')('e'|'E')('l'|'L')
     ('s'|'S')('h'|'H')('a'|'A')('d'|'D')('e'|'E')('r'|'R'))
  ;

RESERVED_WORDS
  : (('a'|'A')('S'|'s')('m'|'M'))
  | 'asm_fragment'
  | 'auto'
  | 'case'
  | 'catch'
  | 'char'
  | 'class'
  | 'const_cast'
  | (('d'|'D')('e'|'E')('c'|'C')('l'|'L'))
  | 'default'
  | 'delete'
  | (('d'|'D')('w'|'W')('o'|'O')('r'|'R')('d'|'D'))
  | 'dynamic_cast'
  | 'emit'
  | 'enum'
  | 'explicit'
  | 'fixed'
  | 'friend'
  | 'get'
  | 'goto'
  | 'interface'
  | 'long'
  | 'mutable'
  | 'new'
  | 'operator'
  | 'packed'
  | (('p'|'P')('i'|'I')('x'|'X')('e'|'E')('l'|'L')
     ('f'|'F')('r'|'R')('a'|'A')('g'|'G')('m'|'M')('e'|'E')('n'|'N')('t'|'T'))
  | 'private'
  | 'protected'
  | 'public'
  | 'reinterpret_cast'
  | 'short'
  | 'signed'
  | 'sizeof'
  | 'snorm'
  | 'static_cast'
  | 'template'
  | 'this'
  | 'throw'
  | 'try'
  | 'typeid'
  | 'typename'
  | 'union'
  | 'unorm'
  | 'unsigned'
  | 'using'
  | (('v'|'V')('e'|'E')('r'|'R')('t'|'T')('e'|'E')('x'|'X')
     ('f'|'F')('r'|'R')('a'|'A')
     ('g'|'G')('m'|'M')('e'|'E')('n'|'N')('t'|'T'))
  | 'virtual'
  ;

ID
  : ('a'..'z'|'A'..'Z'|'_')('a'..'z'|'A'..'Z'|'_'|'0'..'9')*
  ;

DECIMAL_LITERAL
  : ('0'..'9')+
  ;

fragment ESCAPE_SEQUENCE
  : '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
  ;

CHARACTER_LITERAL
  :   '\'' ( ESCAPE_SEQUENCE | ~('\''|'\\') ) '\''
  ;

STRING_LITERAL
  :  '"' ( ESCAPE_SEQUENCE | ~('\\'|'"') )* '"'
  ;

fragment EXPONENT : ('e'|'E') (PLUS | MINUS)? ('0'..'9')+ ;

fragment FLOATSUFFIX : ('f'|'F'|'h'|'H') ;

FLOAT_LITERAL
  : ('0'..'9')+ '.' ('0'..'9')* (EXPONENT)? (FLOATSUFFIX)?
  | '.' ('0'..'9')+ (EXPONENT)? (FLOATSUFFIX)?
  ;

LINE_DIRECTIVE
  : '#line' (' '|'\t')* DECIMAL_LITERAL '\r'? '\n'
  | '#line' (' '|'\t')* DECIMAL_LITERAL (' '|'\t')* STRING_LITERAL '\r'? '\n'
  ;

WHITESPACE
  : (' '|'\r'|'\t'|'\u000C'|'\n')   { $channel = HIDDEN; }
  ;

COMMENT
  : '//' ~('\n'|'\r')* '\r'? '\n'   { $channel = HIDDEN; }
  ;

MULTILINE_COMMENT
  : '/*' ( options {greedy=false;} : . )* '*/'  { $channel = HIDDEN; }
  ;