This tutorial intends to show how to integrate CEGUI with TV3D. This tutorial will be C++ oriented since CEGUI is originally a C++ library but a C# version of the CEGUI library is also available so the main idea could be easily converted.

The following approach will be seperated into 5 sections:

  1. Create the TVCEGUI class
  2. Init CEGUI and the renderer
  3. Load the Font, the Scheme and the Layout of the GUI (The widgets are all defined in the layout .xml file)
  4. Render the GUI
  5. Manage TV Inputs (Mouse and Keyboard) and interact with the GUI


It is possible to create all your widgets with code as well but the .xml approach is used in this tutorial in order to keep it clear and simple.




1. Create the TVCEGUI class



First, we have to create the header file for our class. Here is an example using the singleton pattern:

TV3DCEGUI.H

#pragma once
#include "StdAfx.h"
 
#include <CEGUI.h> 
#include <CEGUIImageset.h> 
#include <CEGUISystem.h> 
#include <CEGUILogger.h> 
#include <CEGUISchemeManager.h> 
#include <CEGUIWindowManager.h> 
#include <CEGUIWindow.h> 
#include <..\RendererModules\directx9GUIRenderer\d3d9renderer.h>  // Might needs to be changed depending on your directory setup
 
 
class CLTV3DCEGUI
{
private:
	CLTV3DCEGUI(void);
	~CLTV3DCEGUI(void);
 
public:
	void InitCEGUI(void);
	void Render(void);
	
	// Get n Set Function
	LPDIRECT3DDEVICE9 Get3DDevice(void) { return(d3Device); }
	CEGUI::System* GetGUISystem(void) { return(mGUISystem); }
 
	
	// Singleton Creation and Destruction functions
	static CLTV3DCEGUI *getInstance ()
	{
         if (NULL == _singleton)
          {
           _singleton =  new CLTV3DCEGUI;
          }
         return _singleton;
	}
	static void kill ()
	{
         if (NULL != _singleton)
          {
           delete _singleton;
           _singleton = NULL;
          }
	}
 
 
private:
	static CLTV3DCEGUI *_singleton;
 
	CTVInternalObjects* pTVIntObj;  // Pointer on TV3D Internal objects
	LPDIRECT3DDEVICE9 d3Device;     // Pointer on Direct3D device
	CEGUI::Renderer* mGUIRenderer;
	CEGUI::System* mGUISystem; 
	CEGUI::DefaultWindow* mGUISheet; 
};
 


Then we initialize the singleton and setup the constructor and destructor of the class:
TV3DCEGUI.CPP

#include "TV3DCegui.h"
 
// Singleton Initialization to NULL
CLTV3DCEGUI *CLTV3DCEGUI::_singleton = NULL;
 
// Constructor
CLTV3DCEGUI::CLTV3DCEGUI(void)
{
	d3Device = NULL;
	pTVIntObj = new CTVInternalObjects();  // We need a pointer on the TV Internal objects to retreive the Direct3D device.
	
	InitCEGUI();  // Automatically Init Cegui system when the object is created.
}
 
// Destructor
CLTV3DCEGUI::~CLTV3DCEGUI(void)
{
delete(mGUIRenderer); mGUIRenderer = NULL;
delete(pTVIntObj);  pTVIntObj = NULL;
}



2. Init the CEGUI and the renderer



CLTV3DCEGUI::InitCEGUI()

// Get Direct3D device from TV3D internal objects
d3Device = pTVIntObj->GetDevice3D();

Once the Direct3D device is retreived, we will setup the CEGUI system.

// Init the CEGUI Renderer and System
using namespace CEGUI; 
mGUIRenderer = new DirectX9Renderer(d3Device, 0); 
mGUISystem = new System(mGUIRenderer); 
Logger::getSingleton().setLogFilename("cegui.log", true); 
Logger::getSingleton().setLoggingLevel(CEGUI::Insane);



3. Load the Font, the Scheme and the Layout of the GUI



Still in the InitCEGUI() function, we will load the scheme and the font. We will setup defaults as well.

// Load scheme and set up defaults
SchemeManager::getSingleton().loadScheme("GUI\\TaharezLook.scheme"); 
FontManager::getSingleton().createFont("GUI\\Commonwealth-10.font"); 
 
mGUISystem->setDefaultMouseCursor("TaharezLook", "MouseArrow");

and next, we will configure the GUISheet. In CEGUI, everything is considered as a window so we will create a root window where all will be attached to. This window will be without any background and frame so it will be invisible.

So the first step is to created an instance of the WindowManager singleton:

WindowManager& winMgr = WindowManager::getSingleton();

Then we create the GUISheet and set its properties:

mGUISheet = (DefaultWindow*)winMgr.createWindow("TaharezLook/StaticImage", "gui_sheet");
mGUISheet->setPosition(UVector2(UDim(0, 0), UDim(0,0)));	// set position
mGUISheet->setSize(UVector2(UDim(1, 0), UDim(1,0)));		// set size
mGUISheet->setProperty("BackgroundEnabled", "false");		// disable standard background 
mGUISheet->setProperty("FrameEnabled", "false");		// disable frame		

And we set our GUISheet to the CEGUI system:

System::getSingleton().setGUISheet(mGUISheet);		        // install this as the root GUI sheet

In order to allow the possibility to have multiple GUI, we will create another invisible GUIWindow to which we will attached all our widgets. To switch from a GUI to another, you will simply have to set this actual GUIWindow to invisible and set another one with a complete different sets of widgets visible ( Ex: mGUIWnd1, mGUIWnd2, etc...).

Note that we will now load our first layout.xml file. This file can be created with the LayoutEditor provided by CEGUI. This .xml file contains the creation of all widgets and their initial properties(size, location, visible or not, etc...)

Load the layout and attached it to the GUISheet:

// Create a DefaultWindow which all the widgets are attach  to.
Window* mDefaultGUIWnd = WindowManager::getSingleton().loadWindowLayout("GUI\\YourLayoutFile.layout");
// Attach the Background to the 'real' root
mGUISheet->addChildWindow(mDefaultGUIWnd);

At this step, you have a configured GUI System. Let’s continue to render this GUI...




4. Render the GUI




void CLTV3DCEGUI::Render(void)
{
CEGUI::System::getSingleton().renderGUI();             //  CEGUI RENDER
//  This is needed because CEGUI changes the Renderstate during its render. 
d3Device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);  // Reverts the RenderState to its original state for TV3D.    
}

Now that the Render function is created and the GUI is configured, we are ready to display it on the screen and see what it actually looks like.

In your cpp where you have your TV3D render loop, simply include the TVCEGUI.h and in your render loop, you call:

CLTV3DCEGUI::getInstance()->Render();

Now, your GUI should be displayed on the screen but your won’t be able to interact with it until next step...




5. Manage TV Inputs and interact with the GUI




This is the most complicated step. This could be divided in 3 sub-sections:

  1. Create CEGUI events callback
  2. Link widgets to events callback
  3. Retreive Input from TV3D and Inject Inputs data to CEGUI system
1) Create CEGUI events callback

In the global section of the TV3DCegui.cpp, you will incorporate a call back function for each type of CEGUI Event. I will show a simple example on how to manage the event launch when the user click on the “X” to close a visible window.

After the destructor in the TV3DCegui.cpp, you insert the callback:

static bool GUI_Callback_WindowClosed(const CEGUI::EventArgs& e)
{
	using namespace CEGUI;						        // Use CeGUI namespace
	WindowManager& winMgr = WindowManager::getSingleton();		        // we will use the WindowManager to get access to the widgets
	FrameWindow* wnd = (FrameWindow*) ((const WindowEventArgs&)e).window;	// we know it's a window, we Get the window pointer
        wnd->setProperty("Visible","false");					// Hide the Window
 
	return true;		
}

You can name the callback function whatever you want...

2) Link widgets to events callback

In the TV3DCEGUI.cpp file, you will add a section to your InitGUI() function. For every widget, you will have to link the events you want to manage with the according callback:

// "VisibleWindow" represents the name of the widget that was created within the Layout.xml file.
FrameWindow* mVisibleWindow = (FrameWindow*)WindowManager::getSingleton().getWindow("VisibleWindow");  
// Here we link the event with the callback for this widget
mVisibleWindow->subscribeEvent(FrameWindow::EventCloseClicked, GUI_Callback_WindowClosed);

When this is done, everytime the user clicks on the VisibleWindow Close button, the GUI_Callback_WindowClosed() function will be called. But up to now, CEGUI is not aware of any input event so let’s go forward to the next step...

3) Retreive Input from TV3D and Inject Inputs data to CEGUI system

The purpose of this tutorial is not on how to manage input in tv3d so please refer to the according wiki section for this.

Let’s start by getting a pointer on the TV3DCEGUI singleton:

CLTV3DCEGUI* clCEGUI = CLTV3DCEGUI::GetInstance();


Your own ManageInput section will have to be modified a little... Once the input information is retreived, you need to inject the info to Cegui system. Let’s separate the mouse input and the keyboard input actions to see what needs to be added:

Mouse:
Here you need to retreive the absolute mouse position:

clCEGUI->GetGUISystem()->injectMousePosition(PosX, PosY);


Here you need to test the raisin and fallin edge of the mouse buttons and perform the according action:

clCEGUI->GetGUISystem()->injectMouseButtonDown(CEGUI::LeftButton);  // on Button 1 fallin edge
clCEGUI->GetGUISystem()->injectMouseButtonUp(CEGUI::LeftButton);    // on Button 1 raisin edge
clCEGUI->GetGUISystem()->injectMouseButtonDown(CEGUI::RightButton); // on Button 2 fallin edge
clCEGUI->GetGUISystem()->injectMouseButtonUp(CEGUI::RightButton);   // on Button 2 raisin edge



Keyboard:
For the keyboard data, there are 3 actions that needs to be done. First, you need to inject Keydown. Second, you need to inject Char. Third, you need to inject Keyup.

The second action is a little tricky since the TV_KEY_CODE needs to be translated to a char ASCII code. (Thx to ??? who wrote a solution for this topic on the forum)

In your Input class header, you must add:

private:
      byte KEY_PRESSED[256];  
      HKL keyboardLayout;  
 


In the constructor of your Input class, you must add:

for(int i=0; i<256;i++)
	{
	KEY_PRESSED[i] = NULL;               
	}
 
keyboardLayout = GetKeyboardLayout((UINT)0);


To Convert Scancode to ASCII, in your Input class, you must add:

char CLInput::ScancodeToASCII(cCONST_TV_KEY scancode) 
{
 char ResultChar = NULL;
 UINT virtualKey = MapVirtualKeyEx((UINT)scancode, (UINT)1, keyboardLayout);
 ToAsciiEx(virtualKey, (UINT)scancode, KEY_PRESSED, (LPWORD)&ResultChar, (UINT)0, keyboardLayout); 
 return (ResultChar);
}


In your keyboard input management, you must add:

// When you detect a key down:
clCEGUI->GetGUISystem()->injectKeyDown(Pressedkey);
char c = ScancodeToASCII(Pressedkey);  // Transfer to ASCII
if (c != (char)0)
  {
    clCEGUI->GetGUISystem()->injectChar(c); 
  }
 
 
// When you detect a key up:
clCEGUI->GetGUISystem()->injectKeyUp(Releasedkey);


And somewhere in your loop, you must add:

clCEGUI->GetGUISystem()->injectTimePulse(TimeElapsed);

This is used by the CEGUI System to create fading effect and other feature like this.

Right now, your GUI system should be up and running!


 
tutorialsarticlesandexamples/tv3d_and_cegui.txt · Last modified: 2013/11/22 13:32