2.9.16
Coherent GT
A modern user interface library for games
Sample application

For this guide we'll use the SampleApplicationBase class. It is placed in "Samples\Common\Application.h" and implements the whole part of initializing and deinitializing Coherent UI GT. It also offers methods for creating and destroying views.

Initializing Coherent UI GT

The first step of the initialization, is to initialize an instance of the Coherent::UIGT::UISystem class. In SampleApplicationBase, this is done in the Initialize method. Here's sample code:

settings.DebuggerPort = 9999;
m_UISystem = InitializeUIGTSystem(COHERENT_UI_GT_LICENSE,
settings,
Coherent::LoggingGT::Debug,
&m_LogHandler);

Next, you need to initialize the Coherent::UIGT::UISystemRenderer, this class is used for encapsulation of the rendering back-end of the UI system. To achieve this, you have to create renoir::RendererBackend and pass it to the CreateRenderer method of the already created instance of the UISystem. The backend implements an abstraction over the graphics device. You can use any of the provided backends (for DX11, OpenGL, etc.) or your own implementation

Note
It is safe to call UISystemRenderer's methods from a rendering thread.
//Setup the rendering parameters
Coherent::UIGT::RenderingParameters params;
params.Type = CRDT_Software;
//Check the application options and use the specified renderer type
switch (m_Options.Renderer)
{
case Coherent::Application::IRenderer::RE_OpenGL:
params.Type = Coherent::UIGT::CRDT_OpenGL;
break;
case Coherent::Application::IRenderer::RE_DirectX9Ex:
params.Type = Coherent::UIGT::CRDT_Dx9Ex;
break;
case Coherent::Application::IRenderer::RE_DirectX9:
params.Type = Coherent::UIGT::CRDT_Dx9;
break;
case Coherent::Application::IRenderer::RE_DirectX11:
params.Type = Coherent::UIGT::CRDT_Dx11;
break;
}
//Get the Application's renderer device so Coherent UI GT can
//use it for rendering
params.Device = m_Renderer->GetNativeDevice();
//Create a system renderer with the rendering params filled from above
m_UISystemRenderer = m_UISystem->CreateRenderer(params);
Note
The UISystemRenderer should be created before creating any views since it's used for the creation of a view renderer for the newly-created view.

De-initialize Coherent UI GT

When de-initializing Coherent GT one should take care to destroy the UISystemRenderer instance, the view renderers for every view created, the corresponding view textures and the views themselves, and then, the UISystem should be uninitialized.

You can checkout SampleApplicationBase::Uninitialize's method about de-initialization.

Creating views

The Sample Application class provides an SampleApplicationBase::AddView that serves for creating a view. It takes two arguments - a Coherent::UIGT::ViewInfo structure and a std::string for the page url. You can checkout quickstart about filling the first one. Please note that if you specify a page with "coui://" as a scheme, you should also pass a valid pointer to an instance of the ResourceFileHandler class (the SampleApplicationFramework provides an example of FileResourceHandler class for dealing with local resources). Otherwise, it is acceptable to leave nullptr. You can checkout the samples for usage.

First, the view is created by calling the CreateView method of the UISystem with the arguments given.

view = m_UISystem->CreateView(info, url.c_str());
if (view)
{
m_Views.push_back(view);
// ...
}

The next two steps are related to the rendering of the newly-created view. First, a texture is created for the view and is added to the application's vector of view textures. Then, in order to be able to draw the view, we create a view renderer. It's responsibility is drawing the view and should be destroyed before the view that it draws.

int texId = m_Renderer->CreateTexture(
view->GetWidth(),
view->GetHeight(),
false,
isDynamic,
isRT,
Coherent::Application::IRenderer::TFMT_ARGB8);
m_ViewTextures.push_back(texId);
auto viewRenderer = m_UISystemRenderer->CreateViewRenderer(
view,
(void*)m_Renderer->GetNativeTexture(texId),
view->GetWidth(),
view->GetHeight());
m_ViewRenderers.push_back(ViewRendererPtr(viewRenderer));

In the sample application, it is alive as long as the view is alive - it is destroyed just before the view is destroyed on its removal from the application.

View Destruction

If you want to remove a particular view from the application, you can achieve this by calling Application::RemoveView method. It simply destroys the view renderer and the view (in this order), thus freeing the resources used by the specified view. Destruction of view renderers and views goes hand in hand!

Note
After calling this method, this view is no longer usable, and calling any of its methods will result in undefined behaviour.

If you do not remove a view explicitly by calling RemoveView it will be destroyed along with its corresponding view renderer upon uninitializing the application.

When using smart pointers for storing views and view renderers, destroying views requires simply resetting the smart pointer, this will actually call the appropriate Destroy() methods.

m_ViewRenderers[m_CurrentView].reset(nullptr);
m_ViewRenderers.erase(m_ViewRenderers.begin() + m_CurrentView);
m_Views[m_CurrentView].reset(nullptr);
m_Views.erase(m_Views.begin() + m_CurrentView);

Another way to do this is by calling the Destroy() method yourself when there is no smart pointers involved.

m_ViewRenderers[m_CurrentView]->Destroy();
m_ViewRenderers.erase(m_ViewRenderers.begin() + m_CurrentView);
m_Views[m_CurrentView]->Destroy();
m_Views.erase(m_Views.begin() + m_CurrentView);

Updating, drawing and resizing the application

The Update, DrawScene and ResizeRendering methods are intentionally left empty, and are overridden and implemented in the samples, so as to match the specifics of the concrete sample.