Introduction
To really be able to program .NET, a good programmer will find himself/herself using ILDASM, the MSIL disassembler, on a regular basis. This necessitates an ability to, at a minimum, be competent at reading MSIL. Unfortunately, the best way to learn to read MSIL is to spend some time writing it! Thus, I set about thinking of something I could write, which would not be too large, but would cover enough of the concepts to give me an ability to read MSIL.
I remember a friend at college who, when he was learning a new language, would always generate Mandelbrot sets as his first piece of code (a mandelbrot set written in Postscript was amusing). This seemed do-able, so I chose to write a Mandelbrot set generator in MSIL.
The code uses Windows Forms to show a new window, then draws the pixels onto this graphics surface.
Compiling
Compile the code simply by ilasm /exe mandelbrot.il
. Remember to have ilasm
in your path - the batch file corvars.bat in the bin folder of the .NET Framework SDK will add it for you.
This should generate mandelbrot.exe in the same folder.
![Screenshot of Mandelbrot.il](/KB/msil/mandelbrot/screenshot.gif)
The Code
The code inherits from System.Windows.Form
and manages its own painting.
.class public auto ansi MandelBrotIL extends [System.Windows.Forms]System.Windows.Forms.Form {
This class overrides the OnPaint()
method of System.Windows.Forms.Form
(which it inherits from). OnPaint
simply sets up the graphics to draw onto, and then calls DrawMandelbrot()
to do the actual drawing:
.method family hidebysig virtual instance void OnPaint(class
[System.Windows.Forms]System.Windows.Forms.PaintEventArgs e) cil managed {
ldarg.0
ldarg e
call instance class [System.Drawing]System.Drawing.Graphics
[System.Windows.Forms]System.Windows.Forms.PaintEventArgs::get_Graphics()
ldc.r4 200
ldc.i4 250
call instance void ThunderMain.Demo.MandelBrotIL::DrawMandelbrot(class
[System.Drawing]System.Drawing.Graphics, float32, int32)
ret
}
DrawMandelbrot()
simply implements a basic Mandelbrot algorithm, details of which can be found in many places on the Internet.
.method private hidebysig instance
void DrawMandelbrot(class [System.Drawing]System.Drawing.Graphics g,
float32 fpMandelWidth, int32 ipIterations) cil managed {
.locals (
[0] float32 x,
[1] float32 y,
[2] float32 fpGranularity,
[3] int32 ipPixelX,
[4] int32 ipPixelY,
[5] float32 fpX,
[6] float32 fpY,
[7] float32 fpXTemp,
[8] float32 fpYTemp,
[9] float32 fpX2,
[10] float32 fpY2,
[11] int32 i
)
ldc.r4 4
ldarg fpMandelWidth
div
stloc fpGranularity
ldc.i4.0
dup
stloc ipPixelX
stloc ipPixelY
ldc.r4 -2.5
stloc x
NextReal:
ldc.r4 -1.5
stloc y
NextImaginary:
ldloc x
stloc fpX
ldloc y
stloc fpY
ldloc x
dup
mul
stloc fpX2
ldloc y
dup
mul
stloc fpY2
ldc.i4.0
stloc i
NextIteration:
ldloc x
ldloc fpX2
ldloc fpY2
sub
add
stloc fpXTemp
ldloc y
ldloc fpY
ldloc fpX
ldc.r4 2
mul
mul
add
stloc fpYTemp
ldloc fpXTemp
dup
mul
stloc fpX2
ldloc fpYTemp
dup
mul
stloc fpY2
ldloc fpX2
ldloc fpY2
add
ldc.r4 4
bge Divergence
ldloc fpXTemp
stloc fpX
ldloc fpYTemp
stloc fpY
ldc.i4.1
ldloc i
add
stloc i
ldloc i
ldarg ipIterations
blt NextIteration
Divergence:
ldarg g
ldarg ipIterations
ldloc i
sub
stloc i
ldloc i
ldc.i4 12
mul
ldc.i4 256
rem
ldloc i
ldc.i4 16
mul
ldc.i4 256
rem
ldloc i
ldc.i4 5
mul
ldc.i4 256
rem
call value class [System.Drawing]System.Drawing.Color
[System.Drawing]System.Drawing.Color::FromArgb(int32,
int32,
int32)
ldc.r4 1
newobj instance void [System.Drawing]System.Drawing.Pen::.ctor(value class
[System.Drawing]System.Drawing.Color,
float32)
ldloc ipPixelX
ldloc ipPixelY
ldc.i4.2
dup
call instance void [System.Drawing]System.Drawing.Graphics::DrawRectangle(class
[System.Drawing]System.Drawing.Pen,
int32,
int32,
int32,
int32)
ldc.i4.1
ldloc ipPixelY
add
stloc ipPixelY
ldloc y
ldloc fpGranularity
add
stloc y
ldloc y
ldc.r4 1.5
blt NextImaginary
ldc.i4.1
ldloc ipPixelX
add
stloc ipPixelX
ldc.i4.0
stloc ipPixelY
ldloc x
ldloc fpGranularity
add
stloc x
ldloc x
ldc.r4 1.5
blt NextReal
ret
}
History
- 24th June, 2002: Initial version