More IL examples


Multi-threading

IL is now fully multi-threaded. A new thread is started with: thread( f, arg1, arg2, ...) where f is the name of a function string and arg1, arg2, etc. are the arguments that function is started with in the new thread. thread( .. ) returns an integer identification of the thread. The boolean status of a thread t is returned by isready( t ).When a thread is finished, You can call end( t ), which also returns the result of the associated function.. threads() returns a list of integers indicating active threads.

String and Diferential operators

Recently I extended the functionality of the String function. It is of course the function linked to the Stringtyp, converting any coercible type to a String. Now it can also be applied to any map, returning a string, which, when executed as a function, again generates that map.

} m = exp(m3()'0)
map
} String(m)
exp( ( m3() ' 0 ) )
} String(m)()
map

To improve readability, there is a mode xyzuvt which, when set, replaces the domain components by , surprise, x, y, z, u, v, and t.

} xyzuvt(T)
       T
} String(m)
exp( x )
} String(m)()
error 127: identifier unknown x

Of course when calling this string as a function, x has to be defined. Initially doing read( "xyz" )takes care of all of this:

} read("xyz")
xyz = m3();
x = xyz'0;
y = xyz'1;
z = xyz'2;
uv = m2();
u = uv'0;
v = uv'1;
t = m1();
xyzuvt( T );

To have even more fun with this, I introduced differential operators. Each domain has it's own, and they are generated by functions: D1, D2, D3. They are applied by multiplication.
For maps representing a scalar function (Real valued), they can be regarded as gradient. For a vector field (for instance Real3 valued), they are the divergence. http://en.wikipedia.org/wiki/Del
To apply them as curl, use cross product notation: **.

} ma = exp(x) / log(y*z)
map
} dma = D3()*ma
map
} String(dma)
real3( ( ( exp( x ) * log( ( y * z ) ) ) / sqr( log( ( y * z ) ) ) ), ( exp( x ) / sqr( log( ( y * z ) ) ) ), ( exp( x ) / sqr( log( ( y * z ) ) ) ) )

} mb = real3( x^2, sin(y), tan(z) )
map
} dmb = D3()*mb
map
} String(dmb)
( ( 2 * x ) + ( cos( y ) + ( 1 + sqr( tan( z ) ) ) ) )

} mc = real3( log( y * sin(z) ) , exp(z) / cos( x), tan( x*y ) )

map
} String( D3()**mc )
real3( ( ( x * ( 1 + sqr( tan( ( x * y ) ) ) ) ) - ( ( exp( z ) * cos( x ) ) / sqr( cos( x ) ) ) ), ( ( ( y * cos( z ) ) / ( y * sin( z ) ) ) - ( y * ( 1 + sqr( tan( ( x * y ) ) ) ) ) ), ( ( exp( z ) / sqr( cos( x ) ) ) - ( sin( z ) / ( y * sin( z ) ) ) ) )


OpenGL binding

OpenGL is integrated in the language. It works by linking a list of lists to a window. Every list is one of:
A shader program is created by glslprogram(), followed by setshader and linkshader calls.
Look at glalphatest.il for instance.
glrendertotex.il is a framebuffer example. Also notice here how easy it is to do a simple animation by just using a m1 (time) based map in a transform expression.
Other files you can try are: glalphatestI.il for simple mouse interaction, glcubmap(I).il, glcubemap_refract(I).il, gldiscardI.il and gledge.il.
All these examples are based on the book "OpenGL 4.0 Shading Language Cookbook" by David Wolff.


Dual number magic

Look here about dual numbers. In IL they are pretty much implemented analogous to complex numbers. When you have an expression calculating dual numbers and you apply that to dual( x, 1 ), the real part of the result is the value as if that expression simply was applied to the real value, but the dual part of the result is the value of the derivative at x.

} f = "( log( %1 ) + sin( %1 ) ) / tan( %1 )"
( log( %1 ) + sin( %1 ) ) / tan( %1 )
} f( 5 )
-0.19243
} f(dual(5,1))
-0.19243 - 0.85051 e
} m = f( t )
map
} setmapdom(5.0)
 5.0
} evalmap( D1() * m )
-0.85051
}


Random Constructors

In il.il several random constructor functions are defined:

vr = "real3( normrand(), normrand(), normrand() )";
zr := "cmplx( normrand(), normrand() )";
nzr := "norm( zr() )";
dr = "dual( normrand(), normrand() )";
qr := "quat( normrand(), normrand(), normrand(), normrand() )";
nqr := "norm( qr() )";
nor := "norm( or() )";
dqr = "dualquat( qr(), qr() )";
ndqr = "norm( dqr() )";


Dual Quaternions

Look here for an introduction. For construction, dualquat takes 2 quaternions or 4 duals. Q0 and Qe give back the 2 quaternion parts.There are two versions of the conjugate:

} dq = ndqr()
 0.52269 0.04899
 0.81424-0.009
-0.13412 0.19706
 0.21407 0.0381
} conj(dq)
 0.52269 0.04899
-0.81424 0.009
 0.13412-0.19706
-0.21407-0.0381
} dconj(dq)
 0.52269-0.04899
 0.81424 0.009
-0.13412-0.19706
 0.21407-0.0381
}

A dual quaternion is equivalent to a rigid transformation:

} Transform(dq)
 0.87237  -0.4422    0.20841  -0.18378
 0.00538  -0.41762  -0.9086    0.15325
 0.48882   0.79376  -0.36194   0.33735
 0.0       0.0       0.0       1.0

} tt = rotate( 0.5*pi, lx ) * translate( 1,2,3 )
 1.0       0.0       0.0       1.0
 0.0       0.0      -1.0      -3.0
 0.0       1.0       0.0       2.0
 0.0       0.0       0.0       1.0
} DualQuat( tt )
 0.70711-0.35355
 0.70711 0.35355
 0.0    -0.35355
 0.0     1.7678
}


In il.il a function is defined how to transform with a dual quaternion:

dqtrf = "im( Qe( %1 * DualQuat( %2 ) * conj( dconj( %1 ) ) ) )";

} dq = ndqr()
 0.52269 0.04899
 0.81424-0.009
-0.13412 0.19706
 0.21407 0.0381
} w = vr()
-0.40635
 1.7416
-1.1295
} Transform(dq) * w
-1.5438
 0.44997
 1.93
} dqtrf(dq,w)
-1.5438
 0.44997
 1.93
}