Developing GUI (1) using C and DirectX, I look at the waste time of the inventive wheel - Windows already has a very complex function of perfect gui. Unfortunately, Windows GUI applies to office software, and this is usually not suitable Game software. Games generally need more precise control than Windows (for example, using its own GUI implementation with some transparent windows created by Alpha), and use Windows GUI almost unable).
This article will tell how to use C and DirectX to create its own gui. Articles are divided into parts, each of which involves a specific GUI programming topic. This does not need to read in order, so you can start from the part you need.
Here I assume that the reader has the following background knowledge: the programming principle of the event-driven; the proficiency of PDL and C . I use C to build my GUI system, because I am a C fan club member, and C OOP It is very suitable for Windows programming and control.
Let us start from the definition work. It should be recognized that we are not to design Windows95. We just want to develop a simple GUI for a game. So we don't have to implement each simple control and GUI structure. We only need a few parts. : a mouse pointer, a common window, controlling some dialog boxes in the window, we also need a resource editor - allows us to use a drag control in a graphical environment to design the dialog box.
Starting from the basics: Rendering cycle
I will start by defining a function that calculates and draws the framework. We call this function in the rendergui () function. AndrGUI is described in PDL as follows:
Void Capplication :: Rendergui (Void) {// Get Position and Button Status of Mouse Cursor // Calculate Mouse Cursor 抯 Effects On Windows / Send Messages // Render All Windows // Render Mouse // Flip to Screen}
We get a new position of the new position and the mouse light, calculate any changes caused by new data, render all windows, mouse pointers and draw on the screen.
mouse
Class cmouse {public: cmouse (); // boring ~ cmouse (); // boring
INT INIT (LPDIRECTINPUT DI); // We 抣 L Talk about this later int rebresh (void); // We 抣 L Talk about this Later
INT getButton (INDEX) {IF (Index <0 || index> NummouseButtons) Return (0); return (m_button [index]);}
Void clear (void); // sets all vars to zero
// makes sure p is a valid on-screen point void ConstrainPosToScreenSize (CPoint & p); CPoint GetAbsPosition (void) {return (m_absposition);} CPoint GetRelPosition (void) {return (m_relposition);} enum {NUMMOUSEBUTTONS = 3}; // Three Button Mouse
Private: lpdirectinputdevice m_mousedev; char m_button [nummousebuttons]; // state of buttons cpoint m_absposition; // actual screen position cpoint m_relposition; // relative position
}
Absolute position and relative position, why do DirectInput I want to use DirectInput? This is actually a taste problem. There are two ways to get Windows mouse information, from DirectInput or through a Win32 function called getCursorpos (). The main difference is DirectInput Provided is a relative coordinate, ie the current position relative to the last position; GetCursorpos () will provide an absolute coordinate of the screen coordinate system. Absolute coordinates are useful for GUI; while relative coordinates are suitable for mice without cursor, such as in FPS Environment in the game (the translator: that is, the cursor position is fixed). However, you can calculate the relative coordinates by the absolute coordinates, and vice versa.
Due to many reasons I chose DirectInput, all these reasons beyond the scope of this article. Getcursorpos () will be a better choice for you? If so, the mouse class may be very huge. DirectInput is more skillful (also more Interesting), so this article will focus on DirectInput.
Initialization DirectInput
Before we detail CMOUSE, let's see how to initialize DirectInput. Note that these codes are not our cmouse :: init () function; DirectInput's pointer is used throughout the game, and not just in the mouse class, Therefore, initialization should DirectInput and DirectDraw, DirectSound initialization is completed while the main .DirectInput different initialization function pointers and pointers DirectInput Device; DirectInput DirectInput Device pointer pointer to give attention to understand this distinction, the following is the initialization of the main DirectInput interface pointer. Code
LPDIRECTINPUT DI = NULL;
HR = DirectInputCreate (Hinst, DirectInput_Version, & Di, Null);
IF (Failed (HR)) {// error handle_error ();}
// Now That We 抳 E Got A DirectInput Interface, Let 抯 Begin // Fleshing Out Our cmouse by Implementing Cmouse :: init ().
Bool cmouse :: init (lpdirectinput di) {// Obtain an interface to the system mouse device. hr = di-> createdevice (guid_sysmouse, (lpdirectinputDevice *) & m_mousedev, null);
IF (Failed (HR)) {/ * handle errors! * /} // set the data format to "mouse format". hr = m_mousedev-> setDataFormat; if (Failed (HR)) {/ * handle Errors ! * /} // set the cooperativity level hr = m_mousedev-> setcooperativeelevel (hwnd, discl_nonexclusive | discl_Foreground); if (failed (hr)) {/ * handle errors! * /}}
This code made three important work. First, get a valid DirectInput mouse device interface and pay him to Di_Mouse. Second, set the data format and the device's collaboration, just let Windows know we want to check the mouse The equipment, not to exclusively, (exclusive means that only our app can use the mouse, we inform Windows we will share mm and other programs) by specifying DISCL_NONEXCLUSIVE.
Detect mouse state by DirectInput
Let us now pay attention to cmouse :: refresh (). This function is responsible for updating the internal key status of the cmouse. The following is the code:
void CMouse :: Refresh (void) {char done = 0; int q; HRESULT hr; CPoint p; DIMOUSESTATE dims; // clear our struct eventually, directinput will fill this in memset (& dims, 0, sizeof (DIMOUSESTATE))? ;
IF (! m_mousedev) return; // We don 抰 Have a Pointer! Bail!
while (! done) {// query DirectInput for newest mouse data hr = m_mousedev-> GetDeviceState (sizeof (DIMOUSESTATE), & dims); if (FAILED (hr)) {if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) {// device lost ... reacquire hr = m_mousededev-> acquire (); if (Failed (HR)) {// error handling goes here clear (); done = 1;}} else {// it 抯 Some Other Error? Handle it clear (); done = 1;}} else // read mouse successfully! {done = 1;}} // End while loop? WE 抳 e Read di Correctly
// Squirrel Away Newest Rel position data m_relposition.x = dims.lx; m_relposition.y = dims.ly; m_relposition.z = dims.lz;
// Now Calc ABS Position from New Relative Data M_AbsPosition.z = DIMS.LZ; M_AbsPosition.x = DIMS.LX; M_AbsPosition.y = DIMS.LY;
// Keep The Mouse Pointer On-Screen ... construinpostoscreensize (m_absposition);
// get button data for (q = 0; q } This code made a lot of work. First, get a new absolute mouse location (using the While loop to automatically re-detection via DirectInput). Second, pay the absolute position data to M_AbsPosition, then get a new relative position. ConstrainPostoscreensize () function ensures The mouse is in the point in the screen. Finally, all keys are updated by looping. Mouse Drawing the mouse is two main principles. If you know that the entire screen will be refreshed with new pixel data, you can simply biate the mouse cursor to the new absolute position and complete the drawing. However, better The method is to get a copy of the pixel data under the mouse cursor before your BLT, then, when the mouse moves, the pixel data saved by BLT to erase the old BLT. I prefer the latter method. This article Will not discuss specific BLT surfaces and others, you should know how to implement it. Threads and traces If you don't mind multithreading, there is a better way to solve the mouse problem. The method here is a single thread, each frame will query the mouse. Suitable for high refresh rates, rather than low refresh rates. The mouse cursor will be very slow. The best way is to create a separate mouse-rendering thread, which will continue to detect the MouseMove message, and refresh the mouse when the mouse is moved. Multi-threaded advantage is no matter whether your game refresh rate How much, the mouse cursor will be very smooth. There is a separate mouse thread will make the game will be very fast in any frame frequency. Establishing a mouse trajectory is obviously an easy task. Save the last few mouse cursors in a array. When the mouse moves, discard the oldest coordinates, move all other coordinate values down one field, and Deposit the new coordinates into the top field. Then, if you want an extra effect. Use Alpha mixed and rendered the old coordinates than the new coordinates. look forward to... Now we end the work of the mouse cursor. The next section will tell how basic forms are created, and how to move the form. Please look forward to.