MSIL 中的曼德勃罗集






4.83/5 (5投票s)
演示了从 CIL 使用 Windows Forms 和 GDI+
引言
要真正能够编程 .NET,一个优秀的程序员会经常使用 ILDASM,MSIL 反汇编器。这需要至少具备阅读 MSIL 的能力。不幸的是,学习阅读 MSIL 的最佳方法是花一些时间编写它!因此,我开始思考我可以编写什么,它不会太大,但会涵盖足够多的概念,使我能够阅读 MSIL。
我记得大学里的一位朋友,当他学习一门新语言时,总是将生成曼德勃罗集作为他的第一段代码(用 Postscript 编写的曼德勃罗集很有趣)。这似乎可行,所以我选择用 MSIL 编写一个曼德勃罗集生成器。
该代码使用 Windows Forms 显示一个新窗口,然后将像素绘制到该图形表面。
编译
只需使用 ilasm /exe mandelbrot.il
编译代码即可。请记住将 ilasm
添加到您的路径中——.NET Framework SDK 的 bin 文件夹中的 corvars.bat 批处理文件会为您添加它。
这应该会在同一文件夹中生成 mandelbrot.exe。
代码
该代码继承自 System.Windows.Form
并管理自己的绘制。
.class public auto ansi MandelBrotIL extends [System.Windows.Forms]System.Windows.Forms.Form {
该类重写了 System.Windows.Forms.Form
(它继承自) 的 OnPaint()
方法。OnPaint
只是设置用于绘制的图形,然后调用 DrawMandelbrot()
来执行实际的绘制
.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 // Width in pixels
ldc.i4 250 // Iterations before we assume convergence to zero
call instance void ThunderMain.Demo.MandelBrotIL::DrawMandelbrot(class
[System.Drawing]System.Drawing.Graphics, float32, int32)
ret
}
DrawMandelbrot()
只是实现了一个基本的曼德勃罗集算法,其细节可以在互联网上的许多地方找到。
.method private hidebysig instance
void DrawMandelbrot(class [System.Drawing]System.Drawing.Graphics g,
float32 fpMandelWidth, int32 ipIterations) cil managed {
.locals (
[0] float32 x, // Complex Real portion
[1] float32 y, // Complex Imaginary portion
[2] float32 fpGranularity, // Resolution of image on screen
[3] int32 ipPixelX, // X position on screen
[4] int32 ipPixelY, // Y position on screen
// Escape Velocity locals
[5] float32 fpX,
[6] float32 fpY,
[7] float32 fpXTemp,
[8] float32 fpYTemp,
[9] float32 fpX2, // X Squared
[10] float32 fpY2, // Y Squared
[11] int32 i // Loop variable used to calc escape velocity
)
// Calculate Granularity
ldc.r4 4
ldarg fpMandelWidth
div
stloc fpGranularity
// Initialise point on screen
ldc.i4.0
dup
stloc ipPixelX
stloc ipPixelY
// Start the real portion off
ldc.r4 -2.5
stloc x
NextReal:
// Start the imaginary portion off
ldc.r4 -1.5
stloc y
NextImaginary:
// Calculate Escape Velocity
// Initialise locals
ldloc x
stloc fpX
ldloc y
stloc fpY
ldloc x
dup
mul
stloc fpX2
ldloc y
dup
mul
stloc fpY2
// Initialise i
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
// Calculate X squared
ldloc fpXTemp
dup
mul
stloc fpX2
// Calculate Y squared
ldloc fpYTemp
dup
mul
stloc fpY2
// If X Squared plus Y Squared is greater than 4, then we are guaranteed
// divergence to Infinity
ldloc fpX2
ldloc fpY2
add
ldc.r4 4
bge Divergence
// The previous values in the sequence become the current values in the sequence
ldloc fpXTemp
stloc fpX
ldloc fpYTemp
stloc fpY
// Incrememt i
ldc.i4.1
ldloc i
add
stloc i
ldloc i
ldarg ipIterations
blt NextIteration // Assume convergence to zero if we reach our iteration limit
Divergence:
// Draw Pixel. i is now the escape velocity
// Load the Graphics context
ldarg g
// Calculate the color based on the escape velocity
ldarg ipIterations
ldloc i
sub
stloc i
// Red
ldloc i
ldc.i4 12
mul
ldc.i4 256
rem
// Green
ldloc i
ldc.i4 16
mul
ldc.i4 256
rem
// Blue
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)
// Create a new Pen on the stack
ldc.r4 1
newobj instance void [System.Drawing]System.Drawing.Pen::.ctor(value class
[System.Drawing]System.Drawing.Color,
float32)
// Load the coords of the point to draw
ldloc ipPixelX
ldloc ipPixelY
// Width and Height
ldc.i4.2
dup
call instance void [System.Drawing]System.Drawing.Graphics::DrawRectangle(class
[System.Drawing]System.Drawing.Pen,
int32,
int32,
int32,
int32)
// Next PixelY
ldc.i4.1
ldloc ipPixelY
add
stloc ipPixelY
// Advance through the imaginary portion
ldloc y
ldloc fpGranularity
add
stloc y
ldloc y
ldc.r4 1.5
blt NextImaginary
// Advance through ipPixelX
ldc.i4.1
ldloc ipPixelX
add
stloc ipPixelX
// Start at the top of the screen for the next column
ldc.i4.0
stloc ipPixelY
// Advance through the real portion
ldloc x
ldloc fpGranularity
add
stloc x
ldloc x
ldc.r4 1.5
blt NextReal
ret
} // method
历史
- 2002年6月24日:初始版本