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())