Managed DirectX, конвертация из MDX в SlimDX (3/3)

Опубликовано Июн 26, 2010 в .NET, DirectX | Нет комментариев

Продолжаем миграцию 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);

Оставить комментарий