Short Contents

9.3 Using `lib3delight' to Interrogate Shaders

Shader interrogation is possible by using the shaderinfo command line tool (see section Using shaderinfo to Interrogate Shaders). It is also possible to "manually" interrogate shaders by using a number of calls implemented in `lib3delight'. The interrogating application should include `slo.h' (found in `$DELIGHT/include') and link with `lib3delight' (see section Linking with 3Delight).

Here is the complete list for shader interrogation calls:

void Slo_SetPath ( char* i_path )

Set the paths where the library looks for shaders. It accepts a colon separated list of paths. Refer to Search Paths Options for more information on search paths which also applies to this function.

int Slo_SetShader ( char* i_name )

Find and open the shader named i_name. Close any shader that was previously opened by Slo_SetShader. Returns 0 when the shader was successfully loaded.

char* Slo_GetName ( void )

Returns the name of the currently opened shader.

SLO_TYPE Slo_GetType ( void )

Return the type of the currently opened shader. See the file `slo.h' for details about SLO_TYPE.

int Slo_GetNArgs ( void )

Return the number of parameters accepted by this shader.

SLO_VISSYMDEF* Slo_GetArgById ( int i )

Return information about the i-th parameter of the shader. The first parameter has an id of 1. See `slo.h' for details about SLO_VISSYMDEF structure.

SLO_VISSYMDEF* Slo_GetArgByName ( char *i_name )

Return information about the parameter named i_name. See the file `slo.h' for details about SLO_VISSYMDEF.

SLO_VISSYMDEF* Slo_GetArrayArgElement ( SLO_VISSYMDEF *i_array, int i_index )

If a parameter is an array (as specified by Slo_GetArgById() or Slo_GetArgByName), each of its element should be accessed using this function.

int Slo_GetNAnnotations ( void )

Return the number of annotations contained in this shader. Annotations are further discussed in Attaching annotations to shaders.

char* Slo_GetAnnotationKeyById ( int i_id )

Returns an annotation key by it's index i_id. Acceptable indexes range from 1 to n, where n is the number of annotations available. Any index outside this range returns 0x0 (null pointer).

char* Slo_GetAnnotationByKey ( const char *i_key )

Returns an annotation specified by it's key. If i_key doesn't refer to any annotation, 0 (null pointer) is returned. It is possible to retrieve the different possible keys with Slo_GetAnnotationKeyById.

void Slo_EndShader ( void )

Close the current shader.

char* Slo_TypetoStr ( SLO_TYPE i_type )

Get a string representation of type i_type.

char* Slo_StortoStr ( SLO_STORAGE i_storage )

Get a string representation of storage class i_storage.

char* Slo_DetailtoStr ( SLO_DETAIL i_detail )

Get a string representation of variable detail i_detail.

Next is the complete source code of the shaderinfo utility, it is compilable on all supported platforms, see Linking with 3Delight.

/******************************************************************************/
/*                                                                            */
/*    Copyright (c)The 3Delight Team.                                         */
/*    All Rights Reserved.                                                    */
/*                                                                            */
/******************************************************************************/

// ===========================================================================
// = VERSION
//     $Revision$
// = DATE RELEASED
//     $Date: 2009-01-07 22:54:15 -0500 (Wed, 07 Jan 2009) $
// = RCSID
//     $Id: shaderinfo.cpp 11807 2009-01-08 03:54:15Z olivier $
// ===========================================================================

#include "slo.h"
#include "dlMsgShaderInfo.h"
#include "dlVersion.h"

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include <assert.h>

typedef enum
{
	e_prman = 1,
	e_ribout,
	e_table,
	e_source,
	e_annotations
} Format;

void PrintDefaultValue( SLO_VISSYMDEF* arg )
{
	switch(arg->svd_type)
	{
	case SLO_TYPE_SCALAR:
		printf( "%g", *arg->svd_default.scalarval );
		break;
	case SLO_TYPE_STRING:
		printf( "%s", arg->svd_default.stringval );
		break;
	case SLO_TYPE_POINT:
	case SLO_TYPE_COLOR:
	case SLO_TYPE_VECTOR:
	case SLO_TYPE_NORMAL:
		printf( "%g %g %g",
			arg->svd_default.pointval->xval,
			arg->svd_default.pointval->yval,
			arg->svd_default.pointval->zval );
		break;
	case SLO_TYPE_MATRIX:
	{
		unsigned i=0;
		for( ; i < 15; ++i )
			printf( "%g ", arg->svd_default.matrixval[i] );
		printf( "%g", arg->svd_default.matrixval[i] );
		break;
	}
	}
}
		
void printArgs( const Format i_format )
{
	int j, k, kk;

	if( i_format == e_table )
	{
		printf( "%d\n", Slo_GetNArgs() );
	}
	
	for( j = 0; j < Slo_GetNArgs(); j++ )
	{
		SLO_VISSYMDEF *parameter = Slo_GetArgById( j+1 );

		if( !parameter || !parameter->svd_valisvalid )
		{
			fprintf( stderr, DlGetText(DlText_2259_param), j );
			continue;
		}

		const char *storage = Slo_StortoStr( parameter->svd_storage );
		const char *name = parameter->svd_name;
		const char *detail = Slo_DetailtoStr( parameter->svd_detail );
		const char *type = Slo_TypetoStr( parameter->svd_type );
		unsigned arraylen = parameter->svd_arraylen;
		bool is_array = arraylen > 0 || parameter->svd_default.scalarval == 0x0;

		if( i_format == e_ribout )
		{
			/* Output a string suitable for RIB syntax */
				
			if( !is_array )
				printf( "Declare \"%s\" \"%s %s\"\n", name, detail, type );
			else
				printf( "Declare \"%s\" \"%s %s[%d]\"\n",
					name, detail, type, arraylen );

			continue;
		}
		else if( i_format == e_table )
		{
			printf( "%s,%s,%s,%s,%s,%d,",
				name, storage, detail, type,
				parameter->svd_spacename[0] ?
					parameter->svd_spacename : "<none>",
				arraylen );
		
			/* Print all default values */
			if( !is_array )
			{
				PrintDefaultValue( parameter );
			}
			else
			{
				for( int i = 0; i < parameter->svd_arraylen; i++ )
				{
					if( i != 0 )
					{
						printf( " " );
					}
					PrintDefaultValue( Slo_GetArrayArgElement(parameter, i) );
				}
			}

			printf( "\n" );
			continue;
		}

		assert( i_format == e_prman );

		printf( "    \"%s\" \"%s %s %s", name, storage, detail, type );

		if( is_array )
		{
			if( arraylen == 0 )
				printf( "[]" );
			else
				printf( "[%d]", arraylen );
		}

		printf( "\"\n" );
		printf( "\t\t%s", DlGetText(DlText_1725_default) );

		switch( parameter->svd_type )
		{
		case SLO_TYPE_COLOR:
				
			// Even if color has a different spacename,
			// it has been converted by evaluation.
				
			printf( "\"rgb\" ");
			break;

		case SLO_TYPE_POINT:
		case SLO_TYPE_VECTOR:
		case SLO_TYPE_NORMAL:
		case SLO_TYPE_MATRIX:

			if( parameter->svd_spacename[0] != (char)0 )
				printf( "\"%s\" ", parameter->svd_spacename );

			break;

		default:
			break;
		}

		if( is_array )
		{
			printf( "{" );
		}

		int num_elements = is_array ? arraylen : 1;

		for( k=0; k<num_elements; k++ )
		{
			SLO_VISSYMDEF *elem = Slo_GetArrayArgElement( parameter, k );

			if( !elem )
			{
				printf( "<error>" );
				continue;
			}

			switch( parameter->svd_type )
			{
			case SLO_TYPE_SCALAR:
				printf( "%g", *elem->svd_default.scalarval );
				break;

			case SLO_TYPE_POINT:
			case SLO_TYPE_VECTOR:
			case SLO_TYPE_NORMAL:
			case SLO_TYPE_COLOR:
				printf( "[%g %g %g]",
					elem->svd_default.pointval->xval,
					elem->svd_default.pointval->yval,
					elem->svd_default.pointval->zval );
				break;

			case SLO_TYPE_MATRIX:
				printf( "[%g ",  elem->svd_default.matrixval[0] );

				for( kk = 1; kk < 15; kk++ )
					printf( "%g ", elem->svd_default.matrixval[kk] );

				printf( "%g]",  elem->svd_default.matrixval[15] );
				break;

			case SLO_TYPE_STRING:
				printf( "\"%s\"", elem->svd_default.stringval );
				break;

			default:
				break;
			}

			if( k != (num_elements-1) )
			{
				printf( ", " );
			}
		}

		if( is_array )
			printf( "}" );

		printf( "\n" );
	}
	
	if( i_format == e_prman )
	{
		printf( "\n" );
	}
}

int main( int argc, char ** argv )
{
	int i;
	int exitCode = 0;

	Format format = e_prman;

	int start = 1;

	/* DlDebug::InitErrorSignalsHandling(); */

	if ( argc <= 1 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help") )
	{
		printf(
			"Usage: shaderinfo [<option>] [file1 ... fileN]\n"
			"Options\n"
			"  -d         : Outputs declarations in RIB format\n"
			"  -t         : Outputs declarations in parsable table format\n"
			"  -a         : Outputs available annotation keys\n"
			"  -source    : Outputs shader's source (if embedded)\n"
			"  -v         : Shows version to console\n"
			"  --version  : Same as -v\n"
			"  -h         : Shows this help\n\n"
			"Notes:\n"
			"- No arguments is the equivalent of passing -h\n"
			"- All options are exclusive. Use no more than one\n"
			"- The options -h, -v, and --version should not be used with shader names\n"
		);

		return 0;
	}

	if( argc == 2 && (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version")) )
	{
		const char* v = DlGetVersionString();
		const char* copyright = DlGetCopyrightString();

		fprintf(stderr, "shaderinfo version %s.\n%s\n", v, copyright);

		return 0;
	}

	if ( argc == 1 )
	{
		start++;
	}
	else if (!strcmp(argv[1], "-d"))
	{
		format = e_ribout;
		start++;
	}
	else if( !strcmp(argv[1], "-t") )
	{
		format = e_table;
		start++;
	}
	else if (!strcmp(argv[1], "-a"))
	{
		format = e_annotations;
		start++;
	}
	else if (!strcmp(argv[1], "-source"))
	{
		format = e_source;
		start ++;
	}

	/*
		Add '.' to the default path so shaders are still found in the current
		directory even if the default path is modified not to include '.'
	*/
	Slo_SetPath( ".:@" );

	for( i = start; i < argc; i++ )
	{
		int err = Slo_SetShader( argv[i] );

		if( err != 0 )
		{
			fprintf( stderr, DlGetText(DlText_2260_open), argv[i], err );
			exitCode = 1;
			continue;
		}

		/* Print a header indicating which shader this is */
		if( format == e_table )
		{
			printf( "%s\n%s\n",
				Slo_GetName(), Slo_TypetoStr(Slo_GetType()) );

		}
		else if( format == e_prman )
		{
			printf( "\n%s \"%s\"\n",
				Slo_TypetoStr(Slo_GetType()), Slo_GetName() );
		}
		else
		{
			printf( "%s %s\n",
				Slo_TypetoStr(Slo_GetType()), Slo_GetName() );
		}

		if( format == e_annotations )
		{
			if( Slo_GetNAnnotations() == 0 )
			{
				fprintf( stderr, DlGetText(DlText_2261_nokey), argv[i] );
				continue;
			}

			printf( "%d\n", Slo_GetNAnnotations() );
			for( int id=0; id<Slo_GetNAnnotations(); id++ )
			{
				const char *key = Slo_GetAnnotationKeyById( id+1 );

				if( !key )
				{
					assert( false );
					fprintf(stderr, DlGetText(DlText_1727_nokey), id, argv[i]);
					return 1;
				}
				
				const char *annotation = Slo_GetAnnotationByKey(key);

				printf( "\"%s\" \"%s\"\n", key, annotation );
			}
		}
		else if ( format == e_source )
		{
			const char *value = Slo_GetAnnotationByKey( "source" );

			if( value )
			{
				printf( "%s\n", value );
			}
			else
			{
				fprintf( stderr, DlGetText(DlText_1796_no_source) );
			}
		}
		else
		{
			printArgs( format );
		}

		Slo_EndShader();		
	}

	return exitCode;
}

3Delight 8.5. Copyright 2000-2009 The 3Delight Team. All Rights Reserved.