Tcl
File Filtering


return to main index



Introduction

To explain what is meant by file filtering this tutorial assumes that the contents of one or more RenderMan rib files are to be altered ie. filtered, prior to being (batch) rendered with Pixar's prman.

Although, for the purposes of this tutorial, the reader is not expected to be familiar with the structure of a rib file you may like to review RenderMan - Getting Started.

This tutorial shows how a text file, such as a rib file, is opened and its text copied to another file. During the process of copying, the text is filtered or altered in some way.


Defining the Task and the Filter

rib files are produced by 3D modeling and animation programs such as Maya and Houdini. When rendering a complicated model/scene such applications may take a significant amount of time to produce a rib file, or rib files, needed by a RenderMan complient renderer.

Tweaking a scene in order to achieve a specific image quality becomes a tedious process, especially if only a couple of key values need to altered. Rather than repeatedly adjusting a value and re-generating a rib file it is far more efficient to produce, what is in effect, a sample rib file and then use a Perl or Tcl script to edit the rib file. Such edits can be completed in a fraction of the time it may take Maya or Houdini to generate a new version of the rib file.

Lets define the task as being, "find all instances of the text ShadingRate 5 and replace it with ShadingRate 1". The ShadingRate rib statement, like all rib statements, occur as the first item on a line of text. In the case of ShadingRate only one numeric value will follow the statement. Most statements, however, are followed by a long sequence of parameter name/parameter value pairs.


Search and Replace

The script developed in this tutorial follows these steps:

  1. open the target rib file for reading
  2. open a temporary file for writing
  3. repeatedly read each line from the target file
  4. test the first word on a line to see if it matches the text to be altered
  5. if a match is not found copy the line of text to the temporary file
  6. otherwise, write the replacement text
  7. continue until all the source text has been read
  8. close the target rib file
  9. close the temporary file

Either the temporary file can be named as a copy or it can be renamed to match the name of the target file, in which case it will over-write the oribinal file.

The next 4 scripts show the development of a file filtering procedure.


Basic Procedure for Reading a File

The following script forms the basis of what is presented in the next section. The while loop continues processing text from the target file until the command eof (end of file) returns a value of 1.

    proc readText { infile } {
        # open the target file for reading
        set in [open $infile r]
            
        # upto the end-of-file print
        # each line to the console
        while { [eof $in] != 1 } {
            gets $in line
            puts $line
            }
        close $in
        }

Edit the last line so that you "point" the script to the location of the sample rib file. Run the script in Cutter and you should get an output similiar to that shown in Fig 1.



Figure 1



Copying Text from One File to Another

The next script has been modified so a temporary file called "temp.rib" is created in the same directory as the target rib file. During the while loop text is copied, without any alteration, to the temp file.

Run this script in Cutter. A duplicate of the sample.rib will be created.

    proc readText { infile } {
        set in [open $infile r]
      
        # get the path to the parent directory
        set hostDir [file dirname $infile]
        set tempfile "$hostDir/temp.rib"
      
        # open/create a temp file
        set out [open $tempfile w]
            
        while { [eof $in] != 1 } {
            gets $in line
            puts $out $line
            }
        close $in
        close $out
        }

In this final version of the procedure, renamed filterrib, the while loop has been modified so that if a match is found for "ShadingRate" a new value of ShadingRate is written to the temp file. Otherwise, text is copied line-by-line from the oribinal rib file to the temp rib file.

Run this script in Cutter. Open the oribinal sample.rib file. The value of ShadingRate will change.


Listing 1


proc filterrib { infile } {
    set in [open $infile r]
  
    # get the path to the parent directory
    set hostDir [file dirname $infile]
    set tempfile "$hostDir/temp.rib"
  
    # open/create a temp file
    set out [open $tempfile w]
        
    while { [eof $in] != 1 } {
        gets $in line
        set firstItem [lindex $line 0]
  
        # a match has been found...
        if { [$firstItem == "ShadingRate" } {
            puts $out "ShadingRate 10"
        } else { 
            puts $out $line 
            }
        }
    close $in
    close $out
  
    # over-write the existing file
    file rename -force $tempfile $infile
    }

It is sometimes useful to measure the time taken to run a procedure. Use the following code to measure time in milliseconds.

    set t1 [clock clicks -milliseconds ]
    filterrib "YOUR_PATH/sample.rib"
    set t2 [clock clicks -milliseconds ]
      
    puts "\nTime taken [expr $t2 - $t1] milliseconds"


Figure 2




© 2002- Malcolm Kesson. All rights reserved.