Продолжаем миграцию Managed DirectX в SlimDX framework, на примере MDX приложения Патрика Мурриса Terrain Viewer.
Как и раньше, в виде комментариев показан Managed DirectX код, и рядом с ним новый код, работающий с SlimDX.
Установка света
// Light setup private void LightSetup() { // Use a white, directional light //device.Lights[0].Diffuse = Color.White; //device.Lights[0].Specular = Color.FromArgb(0x80, 0x80, 0x80); // soft highlight //device.Lights[0].Type = LightType.Directional; Light light = new Light(); light.Diffuse = new Color4(Color.White); light.Specular = new Color4(0.5f, 0.5f, 0.5f); // soft highlight light.Type = LightType.Directional; //device.SetLight(0, light); // (***1) // Compute light direction (Vector3 pos) ... //device.Lights[0].Direction = -pos; //device.Lights[0].Update(); // Вместо Update, используем EnableLight() //device.Lights[0].Enabled = true; light.Direction = -pos; device.SetLight(0, light); // Перемещено сюда из (***1) device.EnableLight(0, true); ... }
Текстуры
Загрузка текстур
//Texture texture = TextureLoader.FromFile(device, filename); Texture texture = Texture.FromFile(device, fileName); Texture texture = Texture.FromStream(device, stream); А вот аналога для этого метода пока не нашёл (создание текстуры из Bitmap): //Texture t = new Texture(device, b, 0, Pool.Managed);
Работа с клавиатурой
Инициализация
//Keyboard keyb = new Microsoft.DirectX.DirectInput.Device(SystemGuid.Keyboard); //keyb.SetCooperativeLevel(this, CooperativeLevelFlags.Background | CooperativeLevelFlags.NonExclusive); //keyb.Acquire(); _directInput = new SlimDX.DirectInput.DirectInput(); _keyb = new Keyboard(_directInput); _keyb.SetCooperativeLevel(this, SlimDX.DirectInput.CooperativeLevel.Background | SlimDX.DirectInput.CooperativeLevel.Nonexclusive); _keyb.Acquire();
Чтение
//KeyboardState keys = keyb.GetCurrentKeyboardState(); //bool shift = keys[Key.LeftShift] || keys[Key.RightShift]; //bool ctrl = keys[Key.LeftControl] || keys[Key.RightControl];
Проверки
//if (keys[Key.L] && !shift && !ctrl) if (keys.IsPressed(Key.L) && !shift && !ctrl)
Установка камеры
//_device.Transform.Projection = Matrix.PerspectiveFovLH(fov, aspectRatio, mapWidth == 0 ? 15f : (float)(mapWidth / 30f), mapWidth == 0 ? 5000f : (float)(mapWidth * 3)); //_device.Transform.View = Matrix.LookAtLH(new Vector3(0, 0, dist), new Vector3(0, 0, 0), new Vector3(1, 0, 0)); Matrix perspectiveFovLH = Matrix.PerspectiveFovLH(fov, aspectRatio, mapWidth == 0 ? 15f : (float)(mapWidth / 30f), mapWidth == 0 ? 5000f : (float)(mapWidth * 3)); Matrix lookAtLH = Matrix.LookAtLH(new Vector3(0, 0, dist), new Vector3(0, 0, 0), new Vector3(1, 0, 0)); _device.SetTransform(TransformState.Projection, perspectiveFovLH); _device.SetTransform(TransformState.View, lookAtLH);
Mesh
//Mesh mesh = new Mesh(numFaces, numVertices, MeshFlags.Managed, CustomVertex.PositionNormalTextured.Format, device); Mesh mesh = new Mesh(device, numFaces, numVertices, MeshFlags.Managed, CustomVertex.PositionNormalTextured.Format);
mesh.VertexBuffer
Очень серьёзные отличия. В SlimDX мы используем потоки, а в MDX использовался System.Array.
//int[] ranks = new int[1]; //ranks[0] = mesh.NumberVertices; //ranks[0] = mesh.VertexCount; //System.Array arr = mesh.VertexBuffer.Lock(0, typeof(CustomVertex.PositionNormalTextured), LockFlags.None, ranks); //for (int y = startY; y <= endY; y++) //{ // for (int x = startX; x <= endX; x++) // { // CustomVertex.PositionNormalTextured pnt = new CustomVertex.PositionNormalTextured(); // ... // arr.SetValue(pnt, vertIndex++); // } //} //mesh.VertexBuffer.Unlock(); // Size = sizeof(CustomVertex.PositionNormalTextured) * mesh.VertexCount using (DataStream stream = mesh.VertexBuffer.Lock(0, mesh.VertexBuffer.Description.SizeInBytes, LockFlags.None)) { CustomVertex.PositionNormalTextured[] arr = new CustomVertex.PositionNormalTextured[mesh.VertexCount]; for (int y = startY; y <= endY; y++) { for (int x = startX; x <= endX; x++) { CustomVertex.PositionNormalTextured pnt = new CustomVertex.PositionNormalTextured(); ... arr.SetValue(pnt, vertIndex++); } } stream.WriteRange(arr); mesh.VertexBuffer.Unlock(); }
CustomVertex
Класс CustomVertex есть в MDX, но отсутствует в SlimDX, по причине отсутствия прямого аналога в DirectX. Однозначного решения тут не существует, поэтому сразу делюсь окончательным вариантом. Просто нужно создать структуры строго определенного вида, а вот создавать ли класс CustomVertex — ваше дело, я создал для совместимости кода с MDX. Внутреннее содержимое структур также можно реализовать разными способами, векторами или простыми типами данных.
using System; using System.Runtime.InteropServices; using SlimDX; using SlimDX.Direct3D9; namespace TerrainViewer { public struct CustomVertex { //This sentence forces the bytes to be stored in the order the GPU expects the data [StructLayout(LayoutKind.Sequential)] public struct PositionNormalTextured //VertexTypePNT { public float X; // Position public float Y; // Position public float Z; // Position public float Xn; // Normal public float Yn; // Normal public float Zn; // Normal public float Tu; // Texture position (tx) public float Tv; // Texture position (ty) public const VertexFormat Format = VertexFormat.Position | VertexFormat.Normal | VertexFormat.Texture1; // Вариант //public Vector3 Position; //public Vector3 Normal; //public Vector2 TexturePosition; //public static int SizeBytes { get { return Marshal.SizeOf(typeof(PositionNormalTextured)); } } } //This sentence forces the bytes to be stored in the order the GPU expects the data [StructLayout(LayoutKind.Sequential)] public struct PositionNormalColored //VertexTypePNT { public float X; // Position public float Y; // Position public float Z; // Position public float Xn; // Normal public float Yn; // Normal public float Zn; // Normal public int Color; // Color public const VertexFormat Format = VertexFormat.Position | VertexFormat.Normal | VertexFormat.Diffuse; // Вариант //public Vector3 Position; //public Vector3 Normal; //public Color4 Color; // MDX //public static int SizeBytes { get { return Marshal.SizeOf(typeof(PositionNormalColored)); } } } } }
Font
////// Creates a font. /// //http://www.gamedev.net/community/forums/topic.asp?topic_id=557531 //public Microsoft.DirectX.Direct3D.Font CreateFont(string familyName, float emSize, System.Drawing.FontStyle style) public SlimDX.Direct3D9.Font CreateFont(string familyName, float emSize, System.Drawing.FontStyle style) { try { FontDescription description = new FontDescription(); description.FaceName = familyName; //description.Height = (int)(1.9 * emSize); //description.Quality = FontQuality.ClearTypeNatural; if (style != System.Drawing.FontStyle.Regular) { //if ((style & System.Drawing.FontStyle.Italic) != 0) description.IsItalic = true; if ((style & System.Drawing.FontStyle.Italic) != 0) description.Italic = true; if ((style & System.Drawing.FontStyle.Bold) != 0) description.Weight = FontWeight.Heavy; //description.Quality = FontQuality.AntiAliased; // MDX description.Quality = FontQuality.Antialiased; } //font = new SlimDX.Direct3D9.Font(device, 15, 0, FontWeight.Bold, 0, false, //CharacterSet.Default, Precision.TrueType, FontQuality.ClearTypeNatural, //PitchAndFamily.Default | PitchAndFamily.DontCare, "Arial"); return new SlimDX.Direct3D9.Font(device, (int)(1.9 * emSize), 0, FontWeight.Bold, 0, false, CharacterSet.Default, Precision.TrueType, FontQuality.Antialiased, PitchAndFamily.Default | PitchAndFamily.DontCare, familyName); //return new Microsoft.DirectX.Direct3D.Font(device, description); // MDX //System.Drawing.Font f = new System.Drawing.Font(new FontFamily(familyName), emSize); //return new SlimDX.Direct3D9.Font(device, f); } catch { return null; } }
Рисование текста
//sprite.Begin(SpriteFlags.None); //font.DrawText(sprite, infoText, rect, DrawTextFormat.Left, Color.Black); sprite.Begin(SpriteFlags.AlphaBlend); font.DrawString(sprite, infoText, rect, DrawTextFormat.Left, Color.Black);