![]() |
![]() |
| F#.NET tutorials and examples |
Minimal DirectX demoWith the advent of .NET, Managed DirectX makes graphical programming easy under Windows. This program is a minimal DirectX demo with several interesting features:
Despite having all of these features, the entire program requires only 100 lines of source code to render a 3D teapot that can be rotated with the mouse:
This example program is freely available in two forms:
The program has several interesting aspects: GUIThis is a Windows application that uses WinForms to create a window containing a DirectX device. The WinForms-related code is written in an object oriented style, forming a type Viewer = class inherit Form ... end This class encapsulates the creation and handling of a window containing a DirectX device. The constructor for this class accepts the title of the window as a string and a rendering function:
new(title, render) as form = {device=null; render=render; world=Matrix.Identity; drag=None} then
form.SetStyle(Enum.combine [ControlStyles.AllPaintingInWmPaint; ControlStyles.Opaque], true);
form.Text <- title;
form.MinimumSize <- form.Size;
form.Show()
Note that the ability to pass the rendering function as an argument to the constructor is functional programming. Mouse controlDragging is achieved by storing a mutable value in the val mutable drag : (Matrix * int * int) option When the scene is not being dragged, Inside the override form.OnMouseDown e = form.drag <- Some(form.device.Transform.World, e.X, e.Y) and the override form.OnMouseUp e = form.drag <- None The
override form.OnMouseMove e = match form.drag with
| Some(world, x, y) ->
let scale = 5.f / float32(min form.device.Viewport.Width form.device.Viewport.Height) in
form.world <- world * Matrix.RotationY(float32(x - e.X) * scale) * Matrix.RotationX(float32(y - e.Y) * scale);
form.Invalidate()
| None -> ()
This is a very succinct way to handle the mouse control of a scene. Note the use of variant types ( RenderingThe
override form.OnPaint _ =
if form.device = null then form.make_device();
try
form.device.BeginScene();
form.device.Clear(Enum.combine [ClearFlags.Target; ClearFlags.ZBuffer], Color.Black, 1.f, 0);
form.device.Transform.World <- form.world;
form.render form.device;
form.device.EndScene();
form.device.Present()
with _ -> form.make_device()
Note that this function is careful to replace the DirectX device if there is an error. This handles DirectX device loss and reset, although there are probably more elegant ways to do so. For example, if the The device.RenderState.SpecularEnable <- true; device.Lights.Item(0).Specular <- Color.White; device.Lights.Item(0).Direction <- new Vector3(-1.f, -1.f, 2.f); device.Lights.Item(0).Update(); device.Lights.Item(0).Enabled <- true; initialises the transformation matrices (representing perspective projection and the camera position and orientation relative to the scene): let aspect = float32 device.Viewport.Width / float32 device.Viewport.Height in device.Transform.Projection <- Matrix.PerspectiveFovLH(0.8f, aspect, 0.1f, 10.f); device.Transform.View <- Matrix.LookAtLH(new Vector3(0.f, 0.f, -4.f), new Vector3(0.f, 0.f, 0.f), new Vector3(0.f, 1.f, 0.f)); sets materials propertes ready to render a red teapot with a white specular highlight: let mutable material = new Material() in material.Diffuse <- Color.Red; material.Specular <- Color.White; material.SpecularSharpness <- 32.f; device.Material <- material; and finally renders the built-in teapot mesh: Idioms.using (Mesh.Teapot(device)) (fun teapot -> teapot.DrawSubset(0)) Note the use of Despite the sophistication of this application, the entire program is tiny thanks to the expressiveness of the F# programming language.
|
| © Flying Frog Consultancy Ltd., 2007 | Contact the webmaster |