# Language Constructs

### Expressions

Expressions are built from arithmetic operators, function calls and variables. The language supports the common arithmetic operators, (+, -, *, and /) plus the vector operators ^ (cross product) and . (dot product), and the C conditional expression (binary relation ? expr1 : expr2).

When operating on points, vectors, normals or colors an arithmetic operation is performed in parallel on each component. If a binary operator involves a point or color and a float, the float is promoted to the appropriate type by duplicating its value into each component. It is illegal to perform a binary operation between a point and a color. Cross products only apply to vectors; dot products apply to both vectors and colors. Two points, two colors, or two strings can be compared using == and !=. Points cannot be compared to colors.

The usual common-sense mathematical rules apply to point/vector/normal arithmetic. For example, a vector added to a point yields a point, a vector added to a vector yields a vector, and a point subtracted from a point yields a vector. Mixing the types of vectors, normals and points (for example, taking across product of two points, rather than two vectors) is allowed, but discouraged. A particular implementation may choose to issue a compiler warning in such cases. Note that vectors and normals may be used nearly interchangeably in arithmetic expressions, but care should be taken to distinguish between them when performing coordinate system transformations.

Matrix variables can be tested for equality and inequality with the == and != boolean operators. The * operator between matrices denotes matrix multiplication, while m1/m2 denotes multiplying m1 by the inverse of matrix m2. Thus, a matrix can be inverted by writing 1/m.

### Standard Control Flow Constructs

The basic explicit control flow constructs are:

• block-structured statement grouping,
• conditional execution,
• loops, and
• function calls.

These constructs are all modeled after C. Statement grouping allows a single statement to be replaced with a sequence of statements.

```{
stmt;
...
stmt;
}
```

Any variables declared within such a brace-delimited series of statements are only visible with that block. In other words, variables follow the same local scoping rules as in the C language.

Conditional execution is controlled by

```if ( boolean expression ) stmt else stmt
```

There are two loop statements,

```while ( boolean expression ) stmt
```

and

```for ( expr ; boolean expression ; expr ) stmt
```

A boolean expression is an expression involving a relational operator, one of: <, >, <=, >=, ==, and !=. It is not legal to use an arbitrary float, point or color expression directly as a boolean expression to control execution. A boolean expression can not be used as a floating point expression.

The

```break [n]
```

and

```continue [n]
```

statements cause either the for or the while loop at level n to be exited or to begin the next iteration. The default value for n is 1 and refers to the immediately enclosing loop.

Built-in and user-programmed functions are called just as in C. The

```return expr
```

statement is used to return a value to the caller. Any functions that do not return a value should be declared as void, just as in ANSI C; they may contain return statements with no arguments.

Return statements may now appear anywhere in a function, rather than being restricted to the end of the function. For example:

```float positive(float x) {
if (x > 0)
return 1;
else
return 0;
}
```

Uniform values returned from varying conditionals are promoted to varying. For example, the function above returns a varying value if x is varying.

### gather(), illuminance() and illuminate() Statements

The Shading Language contains five block statement constructs: gather, illuminance, illuminate, solar and ambience. gather is used to control the ray-traced sampling of incoming illumination and other forms of information. illuminance is used to control the integration of incoming light over a hemisphere centered on a surface in a surface shader. illuminate and solar are used to specify the directional properties of light sources in light shaders. If a light source does not have an illuminate or solar statement, it is a non-directional ambient light source. ambience can be used to explicitly specify a contribution to the ambient component.

Unlike other control statements, illuminance, illuminate, and solar statements cannot be nested. However, multiple illuminance, illuminate, or solar statements may be given sequentially within a single shader.

```gather ( string category, point P, vector dir, float angle, float samples, ... )
{statements} [else {statements}]
```

The gather looping construct collects information via ray tracing. It typically controls integration of a procedural reflectance model over incoming light whose source is other surfaces; that is, it collects indirect light. Direct light from light sources is collected with illuminance loops.

Further details are available in the gather() section of the RSL Functions documentation.

```illuminance([string category], point position )
statement
illuminance([string category], point position, vector axis, float angle )
statement
```

The illuminance statement controls integration of a procedural reflectance model over the incoming light. Inside the illuminance block two additional variables are defined: Cl or light color, and L or light direction. The arguments to the illuminance statement specify a three-dimensional solid cone and, optionally, the effective number of samples or step size of the integral.

Further details are available in the illuminance() section of the RSL Functions documentation.

```illuminate( point position ) stmt
illuminate( point position, vector axis, float angle ) stmt
```
```solar( ) stmt
solar( vector axis, float angle ) stmt
```

The illuminate and solar statements are inverses of the illuminance statement. They control the casting of light in different directions. The vector variable L corresponding to a particular light direction is available inside this block. This vector points outward from the light source. The color variable Cl corresponds to the color in this direction and should be set. Like the illuminance statements, illuminate and solar statements cannot be nested.

The illuminate statement is used to specify light cast by local light sources. The solar statement is used to specify light cast by distant light sources. The arguments to the illuminate and solar statements specify a three-dimensional cone.

Further details are available in the illuminate()/solar() section of the RSL Functions documentation.

### ambience() Statement

Lights are classified at compile-time whether they will contain ambient contributions or not, thus permitting the renderer to refrain from executing certain lights when only the ambient contribution is being computed. The criteria is simple. If the light contains "solar" or "illuminate" blocks, it is considered non-ambient and will not be forced to execute by the ambient() surface shader shadeop. If the light contains neither op, it is considered ambient and is not run by diffuse(), specular(), or illuminance().

This behavior can be overridden by using an ambience() block. Any light shader that contains an ambience() block specifies a "run-it-and-check" behavior. ambience() is a simple block structure like solar(), but has no parameters. It automatically sets L to 0, so it is not necessary (nor advisable) to tweak L inside the block. For example:

```if (goofytest != 0) {
illuminate(from, axis, coneangle) {
Cl = lightcolor * atten;
}
} else {
ambience() {
Cl = 0.5;
}
}
```

However, it continues to be useful to set L = 0 in the case where you wish to dynamically "turn off" a non-ambient light.