// Renders an ascii art mandelbrot.
// This uses integer based fixed point because
// float support is not yet implemented.
using s32 = sint(32)
using u32 = uint(32)
using u8 = uint(8)
s32 IntToFixedWidthDec( s32 i )
// Restrict the input range to avoid overflows
requires [
i < ( 1 << 12 )
i > ( -1 << 12 )
]
{
return i << 12
}
using width = 100
using height = 32
using minU = IntToFixedWidthDec( -2 )
using maxU = IntToFixedWidthDec( 1 )
using minV = IntToFixedWidthDec( -1 )
using maxV = IntToFixedWidthDec( 1 )
using maxIterations = 50
using threshold = 4 << 24
using fflush = ExternalFunction( u32 ( pointer(void) stream ), "fflush" )
using putchar = ExternalFunction( u32 ( u8 c ), "putchar" )
void put( $c )
{
putchar( cast( ct_int, $c ) )
}
void renderPixel( s32 x, s32 y )
requires [
width > 0
height > 0
x < width
y < height
]
{
// Using tuples to declare and initialize both variables
// at once isn't really necessary here but it serves as
// a drive-by test for that feature.
var cr, var ci = minU + x * ( maxU - minU ) / width,
minV + y * ( maxV - minV ) / height
s32 zr = 0 s32 zi = 0
u32 i = 0
while i < maxIterations
{
// By using a tuple assignment, we compute
// the new values of both zr and zi first, and only after
// we update the variables. With individual assignemnts,
// we'd need to create temporary variables to compute
// the new values of zr and zi and then copy
// the results back in zr and zi.
zr, zi = ( zr*zr - zi*zi ) >> 12,
2 * zr * zi >> 12
zr, zi += cr, ci
if ( zr*zr + zi*zi ) > threshold
{
if ( i & 1 ) == 0
put( ' ' )
else
put( '.' )
return
}
i += 1
}
put( '#' )
}
s32 y = 0
while y < height
{
s32 x = 0
while x < width
{
renderPixel( x, y )
x += 1
}
put( '\n' )
y += 1
}
fflush( nullptr )