, in the last few weeks (actually months, haven't been working actively on it), I've been creating a generic ingame GUI, which is fully movable/draggable around, features control support and with which you can make your own modifications to the game user interface easily. I changed my mind about releasing the full open-source application which features a totally Silkroad-like interface - because the code is too much complicated and it definetly requires a rewrite (I didn't know much stuff back then). After the rewrite, I might release it.Seeing the
tutorials, I will be writing this tutorial in his style (breaking it into a few parts).Creating your own ingame Silkroad GUI
I. Purpose
Why would you actually want to make a built-in GUI ? Well, did you ever think of a bot with a GUI inside the actual game ? Like, you press one key and all options appear there, without even alt-tabbing ! Have you ever thought of building some utilities, like an ingame IRC or Winamp / WMP control in game ? Well, if you did, this guide should help you.
II. Requirements
I assume that you have some basic knowledge of C++ and D3D (you'll actually need to know the screen coordinate system). The tools you are going to need are as following :
- Microsoft Visual Studio 2008, or any other IDE you use that properly works with the following :
- DirectX SDK (I use the one from February 2008, so even older should do)
- A DirectX 9.0 game to test the application on (Silkroad)
- A DirectX 9.0 hook, I made my own, but for this guide's sake, we are going to use Direct3D StarterKit v3.0b by Azorbix, which you can
- the hook is great and should work properly with our GUI - A LOT of patience, the guide is huge
Obviously, the following application created in this guide is generic, which means it will work on almost every DX9.0 game, as long as you hooked the DirectX interface properly. Incase you want to do this only for Silkroad, you can use
and
, which will help you in hooking the Silkroad DX interface.III. Theory
Well, in theory, what we are trying to do should not be very hard, and it truly isn't hard at all once we see some code. We are going to make a DLL which will hook the DirectX interface, which will also make a global hook for mouse so we can enable dragging the windows around. Also we will need a DLL injector (you can use any around, there's also an other great guide from pushedx which will help you in that), so we can inject our DLL into our game. Our GUI will be consisting of windows and controls, to whom which we will, from now on, refer as to widgets. We will have two kinds of widgets; parent and child widgets. Child widgets are controls (altho you can make them parent also). Since we don't need anything complicated (like moving a window in a window), child widgets are those widgets whose coordinates are relative to the parent widgets. For example, if parent's coordinates would be X: 10, Y:20, and child's widgets would be X: 5 and Y: 7, then, when drawing on screen, we would have to draw the child widget at coordinate X: 15, Y: 27. Yeah, it's a bit complicated now, but as I said in Requirements, I assume you have some idea about these coordinates. There will be a lot of code, so prepare to read ! I will be commenting the code as much as I can, so you could understand everything.
IV. Implementation
First of all, we need to open up our project. Open the folder where you have extracted Direct3D Starterkit v3.0b, then go to folder D3D9 and open TatniumD3D solution (incase you are using VS6, you'd have to go to D3D9/old_workspace). Create 3 new files:
- cUI.cpp
- cUI.h
- Common.h
And include them to your project. Now, let's get down to the real deal !
As I already mentioned before, I assume you have some basic knowledge of D3D. I'm going to post up the DrawRectangle function right here, because we will use it for creating our widgets :
Code:
// Can't remember who wrote it :'(
// Draws a simple rectangle
// x, y are the coordinates
// w, h are width and height
// col is the color of the box (you can use alpha transparency - ARGB),
// eg. D3DCOLOR_ARGB(255, 255, 255, 255) is white color with zero transparency
void cUI::DrawRectangle(IDirect3DDevice9 *pD3Ddev, int x, int y, int w, int h, D3DCOLOR col)
{
sQuadVertex qV[4];
qV[0].dwColor = qV[1].dwColor = qV[2].dwColor = qV[3].dwColor = col;
qV[0].z = qV[1].z = qV[2].z = qV[3].z = 0.0f;
qV[0].rhw = qV[1].rhw = qV[2].rhw = qV[3].rhw = 0.0f;
qV[0].x = (float)x;
qV[0].y = (float)(y + h);
qV[1].x = (float)x;
qV[1].y = (float)y;
qV[2].x = (float)(x + w);
qV[2].y = (float)(y + h);
qV[3].x = (float)(x + w);
qV[3].y = (float)y;
pD3Ddev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, qV, sizeof(sQuadVertex));
}
Code:
// d3d9dev.cpp /* Direct3D9 Device */ #include "cUI.h" #define D3DHOOK_TEXTURES //comment this to disable texture hooking
Code:
// cUI.h #include "Common.h"
Code:
// Common.h #include <iostream> #include <vector> #include <io.h> #include <fcntl.h> #include <windows.h> #include <basetsd.h> #include <string> #include "main.h" #include "d3d9.h"
Let's see what data will our widget have. We will need the following :
- X Coordinate
- Y Coordinate
- Width of the widget
- Height of the widget
- Type of the widget (window, control ...)
- Unique ID of the widget for handling events (on click etc.)
- Unique ID of the widget's parent (-1 if none)
- Color of the widget (this should support alpha channels)
- Text (if any - we could use this for more stuff, like if the widget is a picture - path to the picture)
- Color of the text
- Default font size (default will be 16)
- bool - Is the mouse over widget?
- bool - Is the widget being pressed ?
- Look of the button (3D look, just-border etc.)
- Value of the widget, for controls like progressbar or checkbox (0 for widgets who won't support value)
After a little brainstorming, we decide that our widget struct should be as following (used PHP tags so it keeps the format atleast a little) :
PHP Code:
struct sWidget
{
int x; // X coordinate
int y; // Y coordinate
int w; // Width of the widget
int h; // Height of the widget
int type; // Type of the widget (control, static graphic object etc.)
int id; // Unique ID of the widget for handling events
int parent; // Unique ID of widget's parent
D3DCOLOR color; // Color of the widget
char *text; // Text (if any)
D3DCOLOR txtColor; // Color of the text
int fontSize; // Default font size
bool over; // Is the mouse over this widget
bool pressed; // Is the button pressed
int look; // The look of the widget
int value; // Value of the widget
};
Code:
struct sQuadVertex
{
float x, y, z, rhw;
DWORD dwColor;
};
We should think about what should be private and what not. I will not explain this either, if you're interested go read some C++ tutorials concerning classes. After some more brainstorming, we decided which members should be private, so our cUI class looks like this now :Quote:
//cUI.h
#include "Common.h"
class cUI
{
};
Code:
class cUI
{
private:
// Vector of all widgets
vector<sWidget> widgets;
// Default font drawing class
ID3DXFont *defFont;
// The coordinates of the mouse; to be explained later
int lastX;
int lastY;
int lastClick;
// Is the UI visible or not
bool visible;
}
Now, how we should create our windows ? Again, after some thinking, we quickly thought up of an idea :
Code:
// Adds a new window to UI void AddWindow(int x, int y, int w, int h, char *title, int fontSize, D3DCOLOR col, int id, int look);
Code:
class cUI
{
private:
// Vector of all widgets
vector<sWidget> widgets;
// Default font drawing class
ID3DXFont *defFont;
int lastX;
int lastY;
int lastClick;
// Is the UI visible or not
bool visible;
public:
// Default constructor
cUI();
// Adds a new window to UI
void AddWindow(int x, int y, int w, int h, char *title, int fontSize, D3DCOLOR col, int id, int look);
// Adds a button to some window
void AddButton(int parentWnd, int x, int y, int w, int h, char *text, int fontSize, D3DCOLOR col, int id, int look);
// Sets the font color of a widget
void SetWidgetFontColor(int id, D3DCOLOR col);
// Draw UI - this MUST be called every EndScene, it's the main drawing function
void DrawUI(IDirect3DDevice9 *pD3Ddev);
// Main event handler
void HandleCtrlEvents(int id);
// This takes care of mouse drag events
bool HandleMouseEvents(WPARAM wParam, LPARAM lParam);
// Returns the position of a widget in the vector by passing only ID
int GetWidget(int id);
// Makes the UI visible
void MakeVisible();
// Draws a simple rectangle
void DrawRectangle(IDirect3DDevice9 *pD3Ddev, int x, int y, int w, int h, D3DCOLOR col);
// Initialize all stuff we have
void Initialize(IDirect3DDevice9 *pD3Ddev);
// Deinitialize all stuff we have
void Deinitialize(IDirect3DDevice9 *pD3Ddev);
};
Since we now have 50% of the class work done, we can now begin actually writing our functions. We are going to start with the simplest ones, so let's start (the code below is meant to be added in cUI.cpp) :
Code:
// Default constructor
// Use this to create some default widgets
cUI::cUI()
{
// We won't show the UI by default
visible = false;
defFont = NULL;
}
Code:
// Adds a window to the UI
// Coordinates are relative to the client's screen
// Everything else is probably self-explanatory
// Incase the width and/or height of the button is not enough for the
// title to be printed, the window WON'T automatically resize
void cUI::AddWindow(int x, int y, int w, int h, char *title, int fontSize, D3DCOLOR col, int id, int look)
{
sWidget wnd;
wnd.x = x; wnd.y = y;
wnd.w = w; wnd.h = h;
wnd.id = id;
wnd.parent = -1;
wnd.color = col;
wnd.text = title;
wnd.txtColor = D3DCOLOR_ARGB(255, 255, 255, 255);
wnd.fontSize = fontSize;
wnd.type = W_WINDOW;
wnd.look = look;
wnd.over = false;
wnd.pressed = false;
widgets.push_back(wnd);
}
// Adds a button to an existing window
// Coordinates are relative to the parent window
// The first parameter is the ID of the parent window
// Everything else is probably self-explanatory
void cUI::AddButton(int parentWnd, int x, int y, int w, int h, char *text, int fontSize, D3DCOLOR col, int id, int look)
{
sWidget button;
button.x = x; button.y = y;
button.w = w; button.h = h;
button.id = id;
button.parent = parentWnd;
button.color = col;
button.text = text;
button.txtColor = D3DCOLOR_ARGB(255, 255, 255, 255);
button.fontSize = fontSize;
button.type = W_CTRL_BUTTON;
button.look = look;
button.over = false;
button.pressed = false;
widgets.push_back(button);
}
Code:
// Add this to Common.h #define W_WINDOW 1 #define W_STATIC_GRAPHIC 2 #define W_STATIC_TEXT 3 #define W_CTRL_BUTTON 4 #define W_CTRL_EDITBOX 5
Next, we will need our font drawing class. So, we are going to make the Initialize() function :
Code:
// Initialize all stuff we have
void cUI::Initialize(IDirect3DDevice9 *pD3Ddev)
{
D3DXCreateFont(pD3Ddev, //D3D Device
16, //Font height
0, //Font width
FW_NORMAL, //Font Weight
1, //MipLevels
false, //Italic
DEFAULT_CHARSET, //CharSet
OUT_DEFAULT_PRECIS, //OutputPrecision
ANTIALIASED_QUALITY, //Quality
DEFAULT_PITCH|FF_DONTCARE, //Pitch and family
"Arial", //pFacename,
&defFont); //ppFont
}
// Deinitialize all stuff we have
void cUI::Deinitialize(IDirect3DDevice9 *pD3Ddev)
{
// DEINITIALIZE ALL STUF HERE !
// Otherwise, you would crash the application
// on exit !
}
Code:
// Returns the position of a widget in the vector by passing the ID
// Everything is self-explanatory
int cUI::GetWidget(int id)
{
for(int i = 0; i < widgets.size(); i++)
if(widgets[i].id == id) return i;
return -1;
}
// Makes the UI visible
// Just so I don't need to make the visible variable public lol
// Oh and, this switched between visible / invisible
void cUI::MakeVisible()
{
visible =! visible;
}
// Changes the font color of a widget
// Nothing complicated
void cUI::SetWidgetFontColor(int id, D3DCOLOR col)
{
for(int i = 0; i < widgets.size(); i++)
if(widgets[i].id == id) widgets[i].txtColor = col;
}
The function HandleMouseEvents() will require us to build a global (system-wide) mouse hook, so let's get right to the point. In d3d9dev.cpp, put the following code (either on top, or on bottom, then later declare the functions):
Code:
HHOOK mouseHook;
// Mouse hook
// We need it to track down the mouse and DOWN and UP events
// For some weird reason I couldn't implement it into UI class
// I always get a weird error with something about typecast & __stdcall
// Incase you fix it, submit it
LRESULT WINAPI CALLBACK MouseProc(int code, WPARAM wParam, LPARAM lParam)
{
if(code > 0)
{
bool ret = cUI.HandleMouseEvents(wParam, lParam);
if(ret == false) return 1;
}
return CallNextHookEx(mouseHook,code,wParam,lParam);
}
// As the function name says,hooks the mouse
void HookMouse()
{
HWND hWnd = FindWindow(NULL, "SRO_Client"); // Obviously, change SRO_Client to the title of the game you're testing this on
mouseHook = SetWindowsHookEx(WH_MOUSE, (HOOKPROC)MouseProc, GetModuleHandle(NULL), GetWindowThreadProcessId(hWnd,NULL));
}
// Self-explanatory
void UnhookMouse()
{
UnhookWindowsHookEx(mouseHook);
}
Code:
// This takes care of control events
// You HAVE to add your code here in order to
// register the mouse clicks for your controls.
// In the ID switch, you have to add your own
// case for your own control ID
// For example, if you created a button with ID
// 2, then you would have to deal with that button
// under case 2. It's easy :)
void cUI::HandleCtrlEvents(int id)
{
switch(id)
{
case 1:
{
// If a control with ID 1 has been pressed
} break;
case 2:
{
// If a control with ID 2 has been pressed
} break;
}
}
Code:
// This takes care of all mouse events
// Call the function in your mouse callback
bool cUI::HandleMouseEvents(WPARAM wParam, LPARAM lParam)
{
// Now calculate
// May seem complicated, it's easy actually
if(visible)
{
// X and Y coordinates of the mouse
int x, y;
// Let's get the current position of the mouse
POINT cPos;
GetCursorPos(&cPos);
x = cPos.x; y = cPos.y;
// Now let's handle the messages
switch(wParam)
{
// Mouse pressed down
case WM_LBUTTONDOWN:
{
if(lastClick == 0)
{
lastClick++;
lastX = x;
lastY = y;
// We're going to apply the mouse pressed effect
// for the child widgets
for(int i = 0; i <= widgets.size(); i++)
{
if(widgets[i].parent != -1)
{
// Parent widget
int p = GetWidget(widgets[i].parent);
// Child widget coordinates
int cX, cY;
cX = widgets[p].x + widgets[i].x;
cY = widgets[p].y + widgets[i].y;
// If we pressed some child widget
if((x >= cX) && (x <= cX + widgets[i].w) &&
(y >= cY) && (y <= cY + widgets[i].h))
{
widgets[i].pressed = true;
}
else
{
widgets[i].pressed = false;
}
}
}
}
} break;
// Mouse is being moved
case WM_MOUSEMOVE:
{
// Mouse is actually being dragged
// We could have done this on easier way (GetAsyncKeyState), but meh
if(lastClick == 1)
{
// First we have to deal with the parent widgets
// We'll only make window widgets draggable
for(int i = 0; i <= widgets.size(); i++)
{
if(widgets[i].parent == -1)
{
if((x >= widgets[i].x) && (x <= widgets[i].x + widgets[i].w) &&
(y >= widgets[i].y) && (y <= widgets[i].y + W_WINDOW_TITLEBAR) &&
widgets[i].type == W_WINDOW)
{
// Widget is being moved to the right
if(x > lastX)
{
widgets[i].x += x - lastX;
// You can do more stuff here, like add some effects
// eg. trail or something. Try some stuff :)
}
// Widget is being moved left
if(x < lastX)
{
widgets[i].x -= lastX - x;
}
// Widget is being moved down
if(y > lastY)
{
widgets[i].y += y - lastY;
}
// Widget is being moved up
if(y < lastY)
{
widgets[i].y -= lastY - y;
}
}
}
else
{
// Do the child widgets dragging logic here
// We won't make child widgets draggable,
// so we are only going to add the pressed effect
// while you are dragging
if(widgets[i].parent != -1)
{
// Parent window
int p = GetWidget(widgets[i].parent);
// Child widget coordinates
int cX, cY;
cX = widgets[p].x + widgets[i].x;
cY = widgets[p].y + widgets[i].y;
// If we're hovering over some child widget
if((x >= cX) && (x <= cX + widgets[i].w) &&
(y >= cY) && (y <= cY + widgets[i].h))
{
// Just an empty space for an else, cbf to do it on the normal way
}
else
{
widgets[i].pressed = false;
}
}
}
}
lastX = x;
lastY = y;
}
else
{
// You can apply some effects here
// eg. mouse over effect and other stuff
// We're going to apply the mouse over effect
// for the child widgets
for(int i = 0; i <= widgets.size(); i++)
{
if(widgets[i].parent != -1)
{
// Parent window
int p = GetWidget(widgets[i].parent);
// Child widget coordinates
int cX, cY;
cX = widgets[p].x + widgets[i].x;
cY = widgets[p].y + widgets[i].y;
// If we're hovering over some child widget
if((x >= cX) && (x <= cX + widgets[i].w) &&
(y >= cY) && (y <= cY + widgets[i].h))
{
widgets[i].over = true;
}
else
{
widgets[i].over = false;
}
}
}
}
} break;
// Left mouse button isn't pressed anymore
case WM_LBUTTONUP:
{
if(lastClick == 1)
lastClick--;
// Now, we're going to handle events
for(int i = 0; i <= widgets.size(); i++)
{
if(widgets[i].parent != -1)
{
// Parent window
int p = GetWidget(widgets[i].parent);
// Child widget coordinates
int cX, cY;
cX = widgets[p].x + widgets[i].x;
cY = widgets[p].y + widgets[i].y;
// If we pressed some child widget
if((x >= cX) && (x <= cX + widgets[i].w) &&
(y >= cY) && (y <= cY + widgets[i].h))
{
widgets[i].pressed = false;
// Call the event handler
HandleCtrlEvents(widgets[i].id);
}
}
}
} break;
}
}
return true;
}
By now, we have done most of the work concerning the dragging / moving of the widgets, firing up proper events on clicking controls and other stuff I may have forgot.
Also, you may have seen another stuff we're not familiar with. Add the following to the Common.h file :
Code:
#define W_WINDOW_TITLEBAR 30 // Height of the widget window title bar #define W_LOOK_3D 100
Code:
// Draws everything, incase you want to
// modify the look of the controls -
// this is where you should do it
// This is the main drawing functions, so a lot
// of stuff is done here. I recommend that you
// read this function line-by-line to understand
// what it does. It's not hard actually, even though
// it looks complicated
void cUI::DrawUI(IDirect3DDevice9 *pD3Ddev)
{
if(visible)
{
for(int i = 0; i < widgets.size(); i++)
{
switch(widgets[i].type)
{
case W_WINDOW:
{
// Draw the window
DrawRectangle(pD3Ddev, widgets[i].x, widgets[i].y, widgets[i].w, widgets[i].h, widgets[i].color);
D3DCOLOR bColor;
// The 3D look
if(widgets[i].look == W_LOOK_3D)
{
// We need to make the border to give the control the 3Dish look
// Incase you want to make the borders thicker, you'll
// have to change some stuff: you'll notice the +-2,
// just change the 2 and you should be good.
// Oh and, 4 is the 2x of the thickness
// Oh and #2, is drawing 8 lines faster than drawing 4
// rectangles ? Decide by yourself.
bColor = D3DCOLOR_ARGB(100, 255, 255, 255);
// The top line
DrawRectangle(pD3Ddev, widgets[i].x, widgets[i].y, widgets[i].w, 2, bColor);
// The left line
DrawRectangle(pD3Ddev, widgets[i].x, widgets[i].y + 2, 2, widgets[i].h - 2, bColor);
// Now the darker color
bColor = D3DCOLOR_ARGB(100, 0, 0, 0);
// The bottom line
DrawRectangle(pD3Ddev, widgets[i].x + 2, widgets[i].y + widgets[i].h - 2, widgets[i].w - 2, 2, bColor);
// The right line
DrawRectangle(pD3Ddev, widgets[i].x + widgets[i].w - 2, widgets[i].y + 2, 2, widgets[i].h - 4, bColor);
}
// The title bar should be darker
D3DCOLOR titleCol = D3DCOLOR_ARGB(50, 0, 0, 0);
DrawRectangle(pD3Ddev, widgets[i].x, widgets[i].y, widgets[i].w, W_WINDOW_TITLEBAR, titleCol);
// Now let's draw the title
RECT r;
// widgets[i].x + 5 adds a little padding to the left
SetRect(&r, widgets[i].x + 5, widgets[i].y, widgets[i].x + widgets[i].w, widgets[i].y + W_WINDOW_TITLEBAR);
defFont->DrawText(NULL, widgets[i].text, -1, &r, DT_VCENTER | DT_NOCLIP | DT_WORDBREAK, widgets[i].txtColor);
} break;
case W_CTRL_BUTTON:
{
// Draw the button
// Incase the button is a child
if(widgets[i].parent != -1)
{
// The parent widget
int p = GetWidget(widgets[i].parent);
// Child widget coordinates
int cX, cY;
cX = widgets[p].x + widgets[i].x;
cY = widgets[p].y + widgets[i].y;
// Now we have to draw the widget inside the parent
// We already made the coordinates relative, so it will be easy
DrawRectangle(pD3Ddev, cX, cY, widgets[i].w, widgets[i].h, widgets[i].color);
// Now let's draw the button text
RECT rR;
SetRect(&rR, cX, cY, cX + widgets[i].w, cY + widgets[i].h);
defFont->DrawText(NULL, widgets[i].text, -1, &rR, DT_CENTER | DT_VCENTER | DT_NOCLIP | DT_WORDBREAK, widgets[i].txtColor);
D3DCOLOR bColor;
if(widgets[i].look == W_LOOK_3D)
{
// We need to make the border,
// to give the control the 3Dish look
// Incase you want to make the borders thicker, you'll
// have to change some stuff: you'll notice the +-2,
// just change the 2 and you should be good.
// Oh and, 4 is the 2x of the thickness
bColor = D3DCOLOR_ARGB(100, 255, 255, 255);
// The top line
DrawRectangle(pD3Ddev, cX, cY, widgets[i].w, 2, bColor);
// The left line
DrawRectangle(pD3Ddev, cX, cY + 2, 2, widgets[i].h - 2, bColor);
// Now the darker color
bColor = D3DCOLOR_ARGB(100, 0, 0, 0);
// The bottom line
DrawRectangle(pD3Ddev, cX + 2, cY + widgets[i].h - 2, widgets[i].w - 2, 2, bColor);
// The right line
DrawRectangle(pD3Ddev, cX + widgets[i].w - 2, cY + 2, 2, widgets[i].h - 4, bColor);
}
// If the mouse is over the widget
// We're going to apply the mouseover effect
if(widgets[i].over)
{
D3DCOLOR oColor = D3DCOLOR_ARGB(50, 255, 255, 255);
DrawRectangle(pD3Ddev, cX, cY, widgets[i].w, widgets[i].h, oColor);
}
// If the mouse is pressed and over the widget
// We're going to apply the pressed effect
if(widgets[i].pressed)
{
if(widgets[i].look = W_LOOK_3D)
{
// The top line
DrawRectangle(pD3Ddev, cX, cY, widgets[i].w, 2, bColor);
// The left line
DrawRectangle(pD3Ddev, cX, cY + 2, 2, widgets[i].h - 2, bColor);
bColor = D3DCOLOR_ARGB(100, 255, 255, 255);
// The bottom line
DrawRectangle(pD3Ddev, cX + 2, cY + widgets[i].h - 2, widgets[i].w - 2, 2, bColor);
// The right line
DrawRectangle(pD3Ddev, cX + widgets[i].w - 2, cY + 2, 2, widgets[i].h - 4, bColor);
}
bColor = D3DCOLOR_ARGB(50, 0, 0, 0);
DrawRectangle(pD3Ddev, cX, cY, widgets[i].w, widgets[i].h, bColor);
}
}
// Incase it's not a child widget
else
{
// You'll have to add your own drawing for non-child buttons :)
// DrawRectangle(pD3Ddev, widgets[i].x, widgets[i].y, widgets[i].w, widgets[i].h, widgets[i].color);
}
} break;
case W_STATIC_GRAPHIC:
{
// Handle graphics with the image class here
// The "text" attribute should be the filename
// Can be either relative or absolute path
} break;
case W_STATIC_TEXT:
{
// Draw the text here
} break;
}
}
}
}
Code:
cUI cUI;
Code:
HRESULT CD3DManager::Initialize()
{
/*
initialize Resources such as textures
(managed and unmanaged [D3DPOOL]),
vertex buffers, and other D3D rendering resources
...
m_pD3Ddev->CreateTexture(..., ..., &m_pD3Dtexture);
*/
cUI.Initialize(m_pD3Ddev);
HookMouse();
return S_OK;
}
Code:
HRESULT APIENTRY hkIDirect3DDevice9::EndScene()
{
if(GetAsyncKeyState(VK_NUMPAD0)&1)
cUI.MakeVisible();
cUI.DrawUI(m_pD3Ddev);
return m_pD3Ddev->EndScene();
}
Last thing, if you want to make an example widget, your ctor should look something like :
Code:
// Default constructor
// Use this to create some default windows
cUI::cUI()
{
visible = false;
AddWindow(200, 200, 400, 400, "A Widget Window", 16, D3DCOLOR_ARGB(100, 0, 0, 200), 1, W_LOOK_3D);
AddButton(1, 50, 50, 100, 100, "Cool btn", 16, D3DCOLOR_ARGB(255, 0, 0, 255), 2, W_LOOK_3D);
defFont = NULL;
}

V. Conclusion
Let me congratulate you, since you have read the whole guide !
If you just take a look at how this article is long, then I believe that you will understand how much time the actual coding, not to mention writing this guide took. You can show your gratitude by pressing the Thanks button below and posting screenshots of your GUI
Enjoy!






