I. Introduction II. Data Types The following basic data types are recognized in the shader description file: - Integer numbers: These can be specified in decimal, octal or hexadecimal notation. Octal notation is indicated by a leading 0 followed by one more digits which may take on any value between 0 and 7 inclusive. Hexadecimal notation is indicated by a leading 0x or 0X followed by one or more digits which may take on values between 0 and 9 plus 'a' through 'f' or 'A' through 'F'. - Real numbers: Any number including a decimal point or exponent. The following are all examples of real numbers from the point of view of pfdLoadShader: 1.5 1. .5 0.5 2e2 2e-3 4.5e+4 .4e5 - Vectors: A vector is a group of four real or integer numbers surrounded by an opening and closing parentheses pair. Integers and reals can be mixed in a vector since all numbers will be promoted to reals. The following are legal vectors: (1 0 0 1) (1.0 1 0.0 1.0) - Matrices: A matrix is a group of four vectors which combine to represent a 4x4 row major matrix. That is, the first vector is the first row of the matrix, the second vector is the second row of the matrix, etc. - Variable identifiers: A variable identifier always begins with the character '$' followed by a letter ('a' through 'z' or 'A' through 'Z') followed by zero or more letters, the digits 0 through 9 or the character '_'. The following are all valid identifiers: $foo $Foo $FOO $Bar1 $FoO_bAr The following are not identifiers: foo $1foo $foo-bar - Strings: Strings are any number of characters between an opening and closing quote pair. - Enumerated constants: An enumerated constant always begins with an uppercase letter ('A' through 'Z') which may be followed by zero or more uppercase letters, the digits 0 through 9 or the character '_'. The following are all valid enumerated constants: ONE ZERO DST_COLOR LIGHT_1 The following are not enumerated constants: 1_ZERO _ONE III. Variables The shader description file format provides limited support for the declaration and use of variables. As in programming languages such as C, variables must be declared before they may be used. Variable declaration takes place in the shader header while variable use takes place in the definition of the shader passes. At the present time, only textures may be represented with variables and once declared in the header, a texture variable may not be changed or assigned to another. Texture declarations take may take on three different forms depending on the source of the texture. Textures may come from image files, the may be defined as a 1D texture within the shader description file or they may be used as temporary storage for the pfShader. In the case of temporary storage textures, the data within them comes from, and is restored to, the framebuffer. Textures loaded from files are declared like this: texture_def { texture_id texture_src texture_file } The enumerated constant data following the texture_src token must be equal to FILE. When one of these texture declarations is found in a shader description file, a pfTexture object is created and the image file named by the string data is loaded. If the image file is successfully read from disk, an entry is added to the symbol table which maps the texture identifier to the corresponding pfTexture. Textures specified as 1D textures within the shader description file are declared like this: texture_def { texture_id texture_src texture_table { texture_table_size texture_table_data . . . texture_table_data } } The enumerated constant data following the texture_src token must be equal to TABLE. When one of these texture declarations is found in a shader description file, the entries of the table are loaded into an array and a new pfTexture object is created. The array of table entries is specified as the pfTexture image and the dimensions of the pfTexture are set to indicate a 1D texture. An is then added to the symbol table which maps the texture identifier to the corresponding pfTexture. Textures used as temporary storage during execution of the shader passes are declared like this: texture_def { texture_id texture_src } The enumerated constant data following the texture_src token must be equal to TMP. When one of these texture declarations is found in a shader description file, pfShader::allocateTempTexture is called and the returned integer value is entered in the symbol table with the texture identifier for the texture. To provide for some optimization of texture memory usage, temporary storage textures are shared between pfShaders. For this reason, pfTexture objects are not created at load time for temporary textures. Instead, integer IDs are used indicate which temporary texture is used by a pass. Later, when pfShaders are applied to scene graph nodes, the pfShaderManager can determine the maximum number of pfTexture objects to allocate. Once the pfShaderManager has created the pfTextures, it can resolve the mapping between IDs and actual pfTexture objects in the passes of all pfShaders it is aware of. It is an error to declare the same texture identifier more than once. III. Shader Description The shader file must contain all tokens and data within a block like this: # comments can live outside the shader{} block shader { # interesting shader description stuff # should be inserted here } # comments can live outside the shader{} block It is worth noting that comments are anything on a line following the '#' character. The '#' character need not be the first character on the line. Beneath this highest level description, the shader file contains a shader header and a definition of the shader passes. IV. Shader Header The shader header describes everything about the shader which will not vary from one pass to another. This includes the name of the shader, the shader file revision, variables local to the shader and the default state of the shader. Ignoring the placement of whitespace and newlines, the shader header must always be formed in a block like this: shader_header { shader_name shader_major_rev shader_minor_rev shader_locals { . . . } shader_default_state { . . . } } Any textures which will be used by the shader must be declared within the shader_locals block. See Section II for a description of texture declarations. It is important to note that the shader_locals block may be empty. The shader_default_state block contains all the state attributes which will not change on a per pass basis. See Section VI for a description of different state attributes. It is important to note that the shader_default_state block may be empty. V. Shader Passes The shader passes definition describes the type of each pass, the order in which the passes are executed and which state should be enabled for each pass. While there can be a variable number of passes, the shader passes must always be enclosed in a block like this: shader_passes { # pass definitions must be inserted here } Shader passes can be of six different types which are described as follows: - Geometry drawing: Draws the geometry to which the shader is applied. The following state applies during this pass: - Quadritateral drawing: Draws the screen space bounding rectangle of the geometry to which the shader is applied. The following state applies during this pass: - Copy pixels: Copies from the pixels of the screen space bounding rectangle to the pixels of the screen space bounding rectangle. The following state applies during this pass: - Copy to texture: Copies from the pixels of the screen space bounding rectangle to the currently applied texture. The following state applies during this pass: - Copy from texture: Copies from the currently applied texture to the pixels of the screen space bounding rectangle. The following state applies during this pass: - Accum: Applies the current accum operation to the pixels of the screen space bounding rectangle or to the accum buffer depending on the operation. The following state applies during this pass: Shader passes are always specfied in the following form: geom_pass { . . . } quad_geom_pass { . . . } copy_pass { . . . } copy_to_tex_pass { . . . } copy_from_tex_pass { . . . } accum_pass { . . . } Per pass attributes are specified within the body of a pass block. Depending upon the pass type, certain attributes may or may not be legal. The mapping between pass types and legal attributes is described below: geom_pass: alpha test blend color color mask depth test lights material shade model stencil test texenv texgens texture texture matrix quad_geom_pass: alpha test blend color color mask depth test lights material shade model stencil test texenv texgens texture texture matrix copy_pass: alpha test blend color mask color matrix depth test pixel bias pixel scale pixmaps stencil test copy_to_tex_pass: color matrix texture pixel bias pixel scale pixmaps copy_from_tex_pass: alpha test blend color mask stencil test texture See Section VI for a description of individual attributes. VI. State Attributes State attributes enable and set parameters for various rendering state which applies during execution of shader passes. Section V describes which attributes are legal for the various pass types but it is important to note that all state attributes are optional. That is, just because a state attribute is legal for a given pass type it doesn't mean that it must be specified for that pass. That said, one must note that it is an error to specify an attribute more than once per pass even if it is a legal attribute for that pass. Each state attribute is described in detail below. The alpha test attribute is specified as follows: alpha_test { alpha_test_func alpha_test_ref } The enumerated constant data must be one of the following: LESS LEQUAL GREATER GEQUAL EQUAL NOTEQUAL ALWAYS The real number data is the value to which the current pixel's alpha is compared using the aforementioned alpha test function. To disable alpha test use this syntax: alpha_test { disable } For more information on the alpha test functions and meaning of the reference value see: man glAlphaFunc The blend attribute is specified as follows: blend { blend_eqn blend_src blend_dst } or: blend { blend_eqn blend_src blend_dst blend_color } blend_eqn must be followed by an enumerated constant which is one of the following: ADD SUBTRACT REVERSE_SUBTRACT MIN MAX LOGIC_OP blend_src must be followed by an enumerated constant which is one of the following: ZERO ONE DST_COLOR ONE_MINUS_DST_COLOR SRC_ALPHA ONE_MINUS_SRC_ALPHA DST_ALPHA ONE_MINUS_DST_ALPHA SRC_ALPHA_SATURATE CONSTANT_COLOR ONE_MINUS_CONSTANT_COLOR CONSTANT_ALPHA ONE_MINUS_CONSTANT_ALPHA blend_dst must be followed by an enumerated constant which is one of the following: ZERO ONE SRC_COLOR ONE_MINUS_SRC_COLOR SRC_ALPHA ONE_MINUS_SRC_ALPHA DST_ALPHA ONE_MINUS_DST_ALPHA SRC_ALPHA_SATURATE CONSTANT_COLOR ONE_MINUS_CONSTANT_COLOR CONSTANT_ALPHA ONE_MINUS_CONSTANT_ALPHA The vector data following the blend_color token is the constant color which corresponds to the CONSTANT_COLOR, ONE_MINUS_CONSTANT_COLOR, CONSTANT_ALPHA and ONE_MINUS_CONSTANT_ALPHA source and destination constants. To disable blend use this syntax: blend { disable } For more information on the meanings of the blend equation, source and destination factors see: man glBlendEquationext, man glBlendFunc. The color attribute is specified as follows: color { color_data } The vector data following the color_data token specifies the color with which all vertices of the geometry will be rendered. This color overrides any per vertex color applied to the geometry. The color matrix attribute is specified as follows: color_matrix { matrix_data } The matrix data following the matrix_data token specifies the row major matrix which will be pushed onto the color matrix stack. The color mask attribute is specified as follows: color_mask { color_mask_data } The lowest four bits of the integer data following the color_mask_data token specify the masking of the red, green, blue and alpha color components. Bit three corresponds to red, bit two to green, bit one to blue and bit zero to alpha. All other bits are ignored. For more information on the color mask see: man glColorMask. The depth test attribute is specified as follows: depth_test { depth_test_func } The enumerated constant data following the depth_test_func token must be one of the following: LESS LEQUAL GREATER GEQUAL EQUAL NOTEQUAL ALWAYS To disable depth test use this syntax: depth_test { disable } For more information on depth testing see: man glDepthFunc. A variable number of lights may be specified in the shader description file. A group of individual light definitions must be enlosed within a lights {} block like this: lights { light { . . . } . . . light { . . . } } Individual lights are defined with multiple, optional parameters which include the position, ambient color, diffuse color, specular color, etc. If present in the light definition, these parameters are specified as follows: light { light_position spot_light_cone { spot_light_cone_exponent spot_light_cone_cutoff } light_ambient light_diffuse light_specular light_attenuation { light_constant_attenuation light_linear_attenuation light_quadratic_attenuation } } Each light parameter is optional and they may be specified in any order within the light {} block. However, if specifed in a light definition, a parameter may only be specified once. The following light definition would not be legal: light { light_position (1 0 0 1) light_position (0 10 0 1) } It is also important to note that the parameters within the spot_light_cone {} and light_attenuation {} blocks are optional as well. For instance, if the spot_light_cone {} block is specified it is not required that both the spot_light_cone_exponent and spot_light_cone_cutoff parameters be specifed. If only one is specified, the other will take on a default value. The same applies to the light_attenuation {} block. To disable lighting use this syntax: lights { disable } Individual lights may not be disabled. For more information on lighting see: man glLight, man glLightModel. Like the definition of individual lights, materials are defined using multiple, optional parameters which specify emission color, ambient color, diffuse color, etc. If present in the material definition, these parameters are specified as follows: material { material_emission material_ambient material_diffuse material_specular material_shininess } Each material parameter is optional and they may be specified in any order within the material {} block. However, if specified, a parameter may only be specified once. The following material definition would not be legal: material { material_emission (0.25 0 0 1) material_diffuse (1 0 0 1) material_emission (0.75 0 0.25 1) } The material alpha component is taken from the fourth element of the vector data following the material_diffuse token. The fourth element of all other vectors is ignored for material definition. This follows the semantics of standard OpenGL lighting. For more information on materials see: man glMaterial. The pixel bias attribute is specified as follows: pixel_bias { pixel_bias_data } The vector data following the pixel_bias_data token specifies the per component values by which pixel color components will be biased during execution of copy_pass and copy_to_tex_pass passes. For more information on pixel bias see: man glPixelTransfer. The pixel scale attribute is specified as follows: pixel_scale { pixel_scale_data } The vector data following the pixel_scale_data token specifies the per component values by which pixel color components will be scaled during execution of copy_pass and copy_to_tex_pass passes. For more information on pixel scale see: man glPixelTransfer. As in the case of lights, multiple pixmaps can be defined for a pass. For this reason, pixmaps must grouped together in a pixmaps {} block like this: pixmaps { pixmap {} . . . pixmap {} } An individual pixmap attribute is specified as follows: pixmap { pixmap_component pixmap_size pixmap_data . . . pixmap_data } The enumerated constant following the pixmap_component token specifies which color component the pixmap will apply to and it must be one of the following: RED GREEN BLUE ALPHA The integer number following the pixmap_size token specifies the number of entries in the pixmap table. This value must be greater than zero and must be a power of two. Following the size specification, the actual pixmap data is specified as a series of pixmap_data token, real number pairs. It is an error to supply a number of pixmap values which is greater than the size of the table. It is also an error to specify a pixmap for a component more than once per pass. To disable pixmaps use this syntax: pixmaps { disable } Pixmaps may not be disabled individually. For more information on pixmaps see: man glPixelTransfer, man glPixelMap. The shade model attribute is specified as follows: shade_model { shade_model_mode } The enumerated constant following the shade_model_mode token specifies which shade model will apply when rendering geometry and it must be one of the following: SMOOTH FLAT For more information on the shade model see: man glShadeModel. The stencil attribute is specified as follows: stencil_test { stencil_test_func stencil_test_ref stencil_test_mask stencil_test_sfail stencil_test_zfail stencil_test_zpass stencil_test_wmask } The enumerated constant following the stencil_test_func token specifies which stencil test will be performed and it must be one of the following: LESS LEQUAL GREATER GEQUAL EQUAL NOTEQUAL ALWAYS When performing the stencil test, the stencil value for a pixel stored in the stencil buffer will be compared to the integer which follows the stencil_- test_ref token. The integer reference value and the stored pixel stencil value will be bitwise ANDed with the integer mask which follows the stencil_test_mask token. The outcome of the test between the masked reference value and the masked stored value determines which operation is performed on the stencil buffer. The operations are specified following the stencil_test_sfail, stencil_test_zfail and stencil_test_zpass tokens. The enumerated constant indicating the stencil operation must be one of: KEEP ZERO REPLACE INCR DECR INVERT If the outcome of the stencil test operation results in a write to the stencil buffer, the stencil value to be written will first be masked by the integer value following the stencil_test_wmask token. To disable stencil test use this syntax: stencil_test { disable } For more information on the stencil test see: man glStencilFunc, man glStencilOp The texture environment attribute is specified as follows: texenv { texenv_mode } or: texenv { texenv_mode texenv_color } The enumerated constant following the texenv_mode token must be one of the following: MODULATE BLEND DECAL REPLACE ADD ALPHA Certain texture environment modes depend on a constant color which is specified following the texenv_color token. For more information on texture environment modes and the texture environment color see: man glTexenv. As in the case of light definition, there can be multiple texgens specified in a shader description file. For this reason, the invidual texgens must be specified in a texgens {} block like this: texgens { texgen {} . . . texgen {} } Up to four texgens can be specified in the texgens {} block, one for each of the s, t, r and q texture coordinates. It is an error to specify a texgen for a coordinate more than once. An individual texgen is specified as follows: texgen { texgen_coord texgen_mode } or: texgen { texgen_coord texgen_mode texgen_plane } The enumerated constant following the texgen_coord token specifies the texture coordinate to which the texgen applies and it must be one of the following: S T R Q The enumerated constant following the texgen_mode token specifies which texgen mode will be applied to the specified token and it must be one of the following: EYE_LINEAR OBJECT_LINEAR SPHERE_MAP If specified, the vector data following the texgen_plane token specifies the reference plane to be used when computing values for the specified texture coordinate. For more information on the different texgen modes and the use of the reference plane see: man glTexgen. It is important to note that it is an error to specify a texgen for a coordinate more than once per pass. For instance, the following is illegal: texgens { texgen { texgen_coord S texgen_mode EYE_LINEAR } texgen { texgen_coord S texgen_mode OBJECT_LINEAR } } To disable texgens use this syntax: texgens { disable } The texture attribute is specified as follows: texture { texture_id } The identifier following the texture_id token must match an identifier for a texture declared in the shader header segment of the file. To refer to a texture which has not been declared is illegal. To disable texture use this syntax: texture { disable } The texture matrix is specified as follows: texture_matrix { matrix_data } The matrix data following the matrix data token specifies the matrix which will be applied to texture coordinates when drawing with an applied texture. VII. Examples Here is a very simple two pass shader which combines one pass of constant color with another pass using a table texture. shader { # one time shader setup is done here shader_header { shader_name "example shader" shader_major_rev 1 shader_minor_rev 0 shader_locals { texture_def { texture_id $table texture_src TABLE texture_table { texture_table_size 8 texture_table_data (0.00 0.00 0.00 1) texture_table_data (0.14 0.14 0.14 1) texture_table_data (0.29 0.29 0.29 1) texture_table_data (0.43 0.43 0.43 1) texture_table_data (0.57 0.57 0.57 1) texture_table_data (0.71 0.71 0.71 1) texture_table_data (0.86 0.86 0.86 1) texture_table_data (1.00 1.00 1.00 1) } } } shader_default_state { depth_test { depth_test_func LEQUAL } } } # begin specification of shader passes shader_passes { geom_pass { color { color_data (1 1 0 1) } } geom_pass { blend { blend_eqn ADD blend_src DST_COLOR blend_dst ZERO } texture { texture_id $table } texture_matrix { matrix_data (8 0 0 0) (0 1 0 0) (0 0 1 0) (0 0 0 1) } } } }