Doing 2D in SlimDX
Now that I've had a couple of weeks to play around with 2D programming in Direct3D9 via SlimDX, here are a few things that I've found.
After creating the Direct3D Device (as explained in the "Graphics Enumeration and Launching the Game Form" post), I create a Direct3D Sprite object (which I will be calling a "Sprite Batch" object):
varSB = New Direct3D9.Sprite(varD3D_Device)
This will be passed through the main Nimble2D object to each of the 2D objects that will be drawing themselves to the screen.
The magical math-thingy that makes the whole thing work is how Matrices and Matrix Transformations are used to determine where and how 2D sprites are drawn. As mentioned earlier, all objects within a gamespace (including cameras) will have a location (simply a "Current X" and "Current Y") within "game space", which essentially is a way to measure their positions relative to each other. They will also have a "Facing" angle and a "Scale". These are the main pieces used within SlimDX's nifty Transformation2D function to get the matrix needed to draw things how they should appear on screen.
First, the camera:
varActualMatrix = SlimDX.Matrix.Transformation2D(New SlimDX.Vector2(varWidth / 2, varHeight / 2), 0, New SlimDX.Vector2(varScale), New SlimDX.Vector2(varWidth / 2, varHeight / 2), varN2D.QuickTrig.DegreesToWinRadians(varFacing), New SlimDX.Vector2(varCurX, varCurY))
varInverseMatrix = SlimDX.Matrix.Invert(varActualMatrix)
The parameters of that function are as follows:
-
scalingCenter - A Vector2 around which to scale things (set to the middle of the screen)
-
scalingRotation - A Single that indicates rotating the X/Y scaling away from the identity angle
-
scaling - A Vector2 that gives the actual X/Y scaling (1.0 = original size)
-
rotationCenter - A Vector2 around which to rotate things
-
rotation - The angle to rotate (I like to work with angles in degrees ... DirectX and Windows trig functions prefer radians ... so I have a translator function)
-
translation - A Vector2 to relocate everything in X/Y space
The first line sets the camera's actual matrix ... the second line uses that to create the inverse of it, which will be passed to the sprites within the gamespace to relocate them in relation to the camera.
So, the sprites go like so:
Me.varMyTransform = SlimDX.Matrix.Transformation2D(New SlimDX.Vector2(varCurX, varCurY), 0, New SlimDX.Vector2(varSourceScale.X * varScale, varSourceScale.Y * varScale), New SlimDX.Vector2(varCurX, varCurY), varN2D.QuickTrig.DegreesToWinRadians(varFacing), New SlimDX.Vector2(0))
(For my sprites, I have a "SourceScale" that indicates if the initial source image is always to be stretched.)
To draw things, the following steps are taken:
-
Begin Scene & Clear to Background color (Direct3D Device)
-
Cycle through all layers ...
-
Begin Drawing Sprites (Sprite Batch)
-
Cycle through all sprites ...
-
Transform the Sprite Batch Matrix
-
Draw the sprite
-
End Drawing Sprites
-
End Scene
-
Present to Screen
In this system, these steps are scattered through several objects, but put together, they look something like this:
varD3D_Device.BeginScene()
varD3D_Device.Clear(ClearFlags.Target, varCurGameSpace.BackgroundColorOnly, 1, 0)
varN2D.SpriteBatch.Begin(SpriteFlags.AlphaBlend Or SpriteFlags.DoNotSaveState)
varN2D.SpriteBatch.Transform = SlimDX.Matrix.Multiply(varMyTransform, LayerTransform)
varN2D.SpriteBatch.Draw(varSourceTexture, varSourceRect, New SlimDX.Vector3(varOrigin.X, varOrigin.Y, 0), New SlimDX.Vector3(varCurX, varCurY, 0), Color.FromArgb(varAlpha, varColorOnly))
varN2D.SpriteBatch.End()
varD3D_Device.EndScene()
varD3D_Device.Present()
I have other code bits in between things here and there to handle stuff like allowing for additive blending effects, full-screen fade in/out, writing "screen info" (screen size, camera position, FPS) to the screen, etc.
What I'm working through now is the sprite-based primary shapes (filled rectangles, circles, and triangles, lines, empty rectangles, filled rectangles with borders, and empty polygons using lines). I hope to give some details about the lookup-table trig system being used at some point as well.
-Matt