GUI w Managed DirectX

Trudno wyobrazić sobie okienkową aplikację bez GUI (Graphical User Interface). Wyświetlanie tekstu, obsługa przycisków, wprowadzanie danych do programu za pomocą textbox’a, ustawianie opcji (RadioButton, CheckBox) to tylko wycinek operacji, które bez graficznego interfejsu użytkownika byłyby niemożliwe do zrealizowania.

Załóżmy, że piszemy niewielki projekt korzystający z Managed DirectX. Prosta, statyczna scena, kilka modeli, kamera FPP. Dodatkowe założenie jest takie, że projekt ma być rozszerzalny o kolejne elementy. Po kilku godzinach pisania scena jest, modele są, kamera się rusza i obraca. Obsługa – klawisze WSAD do ruchu, QE + ZX do obrotów kamery. Niezbyt to skomplikowane.

Przydałoby się dodać do projektu dodatkowe opcje, chociażby mgłę (włączanie/wyłączanie za pomocą klawisza F), multiteksturowanie (z różnymi zestawami tekstur: klawisz Ctrl + 1, 2, 3, 4..) czy też obracany projektor, który renderuje swój obszar widzenia do tekstury, którą następnie nakłada na inny obiekt (8 klawiszy do przesuwania i obracania projektora). Krok za krokiem obsługa programu staje się trudniejsza od zrobienia fatality w Mortal Kombat. Rozwiążmy ten problem.

Stworzenie aplikacji okienkowej korzystającej z MDX zostało już opisane na milion różnych sposobów, wg mnie najczytelniej w tutorialu Riemer’a. Meritum tkwi w skierowaniu wyniku potoku renderowania do kontrolki, a nie całej formy. Najpierw należy stworzyć klasę panelu dziedziczącego bezpośrednio po klasie Panel z Windows.Forms. W konstruktorze znajdzie się kod włączający właściwość DoubleBuffered, stąd nazwa kontrolki-dziecka:

using System.Windows.Forms;

namespace DirectX_in_Panel
{
    class DoubleBufferedPanel : Panel
    {
        public DoubleBufferedPanel()
        {
            SetStyle(ControlStyles.DoubleBuffer |
                     ControlStyles.UserPaint |
                     ControlStyles.AllPaintingInWmPaint,
                     true);
            UpdateStyles();
        }
    }
}

W konstruktorze obiektu Microsoft.Direct3D.Device jako 3. parametr (linia 29) należy przekazać obiekt Control, czyli wcześniej stworzony Canvas.

using System.Drawing;
using System.Windows.Forms;
using Microsoft.DirectX.Direct3D;

namespace DirectX_in_Panel
{
    public partial class DXForm : Form
    {
        private Device device;
        private DoubleBufferedPanel Canvas;

        public DXForm()
        {
            InitializeComponent();
            Canvas = new DoubleBufferedPanel();
            InitializeDevice();
        }

        private void InitializeDevice()
        {
            var presentParams = new PresentParameters
                                    {
                                        Windowed = true,
                                        SwapEffect = SwapEffect.Discard
                                    };

            device = new Device(0,
                                DeviceType.Hardware,
                                Canvas,
                                CreateFlags.HardwareVertexProcessing,
                                presentParams);
        }

        protected override void DXForm_Paint(PaintEventArgs e)
        {
            device.Clear(ClearFlags.Target, Color.DarkSlateBlue, 1.0f, 0);

            device.BeginScene();
            // Put your rendering code here
            device.EndScene();

            device.Present();
            Update();
            Invalidate();
        }
    }
}

Zmiana w obsłudze zdarzenia OnPaint jest intuicyjna – należy przed Invalidate() dla formy wywołać metodę Update() aby odrysować wszystkie pozostałe kontrolki, a także obsłużyć zdarzenia z kolejki.

Be Sociable, Share!
czoper opublikowano dnia 2009-11-14 Kategoria: Programowanie | Tagi:, , ,

Zostaw odpowiedź

(Ctrl + Enter)