I generally don’t post huge code dumps, mainly because I find them more annoying and less helpful than some books/authors might. But you know, I’ve been playing with IronPython/SlimDX recently and decided to do up another SlimDX Sample (demonstrating DX11), except in IronPython this time. This will be in the SlimDX samples sometime soon!
import clr clr.AddReference('System.Windows.Forms') clr.AddReference('System.Drawing') clr.AddReference('SlimDX') from System import * from System.Drawing import Size from System.Windows.Forms import Form, Application, MessageBox, FormBorderStyle from SlimDX import * from SlimDX.Direct3D11 import * from SlimDX.DXGI import SwapChainDescription, SwapChainFlags, ModeDescription, SampleDescription, Usage, SwapEffect, Format, PresentFlags, Factory, WindowAssociationFlags from SlimDX.D3DCompiler import * from SlimDX.Windows import MessagePump class GameObject: def Render(self): pass def Tick(self): pass class GraphicsDevice(IDisposable): Context = property(lambda self: self.context) Device = property(lambda self: self.device) SwapChain = property(lambda self: self.swapChain) def __init__(self, control, fullscreen): self.fullscreen = fullscreen self.control = control control.Resize += lambda sender, args: self.Resize() swapChainDesc = self.CreateSwapChainDescription(); success,self.device,self.swapChain = Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.None, Array[FeatureLevel]([FeatureLevel.Level_11_0, FeatureLevel.Level_10_1, FeatureLevel.Level_10_0]), swapChainDesc) self.context = self.Device.ImmediateContext with self.swapChain.GetParent[Factory]() as factory: factory.SetWindowAssociation(self.control.Handle, WindowAssociationFlags.IgnoreAll) with Resource.FromSwapChain[Texture2D](self.swapChain, 0) as backBuffer: self.backBufferRTV = RenderTargetView(self.Device, backBuffer) self.Resize() def CreateSwapChainDescription(self): swapChainDesc = SwapChainDescription() swapChainDesc.IsWindowed = not self.fullscreen swapChainDesc.BufferCount = 1 swapChainDesc.ModeDescription = ModeDescription(self.control.ClientSize.Width, self.control.ClientSize.Height, Rational(60, 1), Format.R8G8B8A8_UNorm) swapChainDesc.Flags = SwapChainFlags.None swapChainDesc.SwapEffect = SwapEffect.Discard swapChainDesc.Usage = Usage.RenderTargetOutput swapChainDesc.SampleDescription = SampleDescription(1, 0) swapChainDesc.OutputHandle = self.control.Handle return swapChainDesc def Resize(self): self.Context.ClearState() self.backBufferRTV.Dispose() self.swapChain.ResizeBuffers(1, self.control.ClientSize.Width, self.control.ClientSize.Height, Format.R8G8B8A8_UNorm, SwapChainFlags.None) with Resource.FromSwapChain[Texture2D](self.swapChain, 0) as backBuffer: self.backBufferRTV = RenderTargetView(self.Device, backBuffer) self.Context.Rasterizer.SetViewports(Viewport(0, 0, self.control.ClientSize.Width, self.control.ClientSize.Height, 0.0, 1.0)) def BeginRender(self): self.Context.ClearRenderTargetView(self.backBufferRTV, Color4(0, 0, 0, 0)) self.Context.OutputMerger.SetTargets(self.backBufferRTV) def EndRender(self): self.swapChain.Present(0, PresentFlags.None) def Dispose(self): self.backBufferRTV.Dispose() self.swapChain.Dispose() self.device.Dispose() class TriangleObject(GameObject): def __init__(self, game): self.game = game device = game.GraphicsDevice.Device context = game.GraphicsDevice.Context err = clr.Reference[str]() with ShaderBytecode.CompileFromFile("SimpleTriangle10.fx", "fx_5_0", ShaderFlags.None, EffectFlags.None, None, None, err) as shaderByteCode: self.effect = Effect(device, shaderByteCode) shaderTechnique = self.effect.GetTechniqueByIndex(0) self.shaderPass = shaderTechnique.GetPassByIndex(0) sig = self.shaderPass.Description.Signature self.inputLayout = InputLayout(device, sig, Array[InputElement]([InputElement("POSITION", 0, Format.R32G32B32A32_Float, 0, 0), InputElement("COLOR", 0, Format.R32G32B32A32_Float, 16, 0)])) bufferDesc = BufferDescription(3 * 32, ResourceUsage.Dynamic, BindFlags.VertexBuffer, CpuAccessFlags.Write, ResourceOptionFlags.None, 0) self.vertexBuffer = Buffer(device, bufferDesc) stream = context.MapSubresource(self.vertexBuffer, 0, 3 * 32, MapMode.WriteDiscard, MapFlags.None).Data data = Array[Vector4]([ Vector4(0.0, 0.5, 0.5, 1.0), Vector4(1.0, 0.0, 0.0, 1.0), Vector4(0.5, -0.5, 0.5, 1.0), Vector4(0.0, 1.0, 0.0, 1.0), Vector4(-0.5, -0.5, 0.5, 1.0), Vector4(0.0, 0.0, 1.0, 1.0) ]) stream.WriteRange(data) context.UnmapSubresource(self.vertexBuffer, 0) def Render(self): context = self.game.GraphicsDevice.Context context.InputAssembler.InputLayout = self.inputLayout context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList context.InputAssembler.SetVertexBuffers(0, VertexBufferBinding(self.vertexBuffer, 32, 0)) self.shaderPass.Apply(context) context.Draw(3, 0) def Dispose(self): self.effect.Dispose() self.inputLayout.Dispose() self.vertexBuffer.Dispose() class Game(IDisposable): GraphicsDevice = property(lambda self: self.graphicsDevice) def __init__(self, width, height, fullscreen = False): self.fullscreen = fullscreen self.form = GameForm(width, height, fullscreen) self.form.Visible = True self.graphicsDevice = GraphicsDevice(self.form, self.fullscreen) self.gameObjects = [TriangleObject(self)] def Run(self): Application.Idle += self.OnIdle Application.Run(self.form) def OnIdle(self, ea, sender): while MessagePump.IsApplicationIdle: self.Update() self.Render() def Update(self): for i in self.gameObjects: i.Tick() def Render(self): self.GraphicsDevice.BeginRender() for i in self.gameObjects: i.Render() self.GraphicsDevice.EndRender() def Dispose(self): self.GraphicsDevice.Dispose() for i in self.gameObjects: if 'Dispose' in dir(i): i.Dispose() self.form.Dispose(True) class GameForm(Form): def __init__(self, width, height, fullscreen): self.ClientSize = Size(width, height) if fullscreen: self.FormBorderStyle = FormBorderStyle.None if __name__ == "__main__": try: with Game(640, 480) as game: game.Run() except Exception as e: MessageBox.Show(e.ToString())