2.9.16
Coherent GT
A modern user interface library for games
Quick start

This guide is about the way Coherent GT works at runtime and has to be integrated in an application. For a guide on the workflow and how to create beautiful UI with Coherent GT, please refer to our Workflow guide and the Coherent Editor guide.

This guide will show you how to

  1. Add Coherent GT as a library to project
  2. Create instances of Coherent::UIGT::UISystem and Coherent::UIGT::View
  3. Create surfaces to be used by the Coherent::UIGT::View instance
  4. Display the view using your graphics API
  5. Deploy the executable

The sample for this guide is HelloGT and the sample application framework walkthrough.

Note that the sample depends on the Coherent Sample framework and can work with OpenGL, DirectX 9, DirectX 11 and DirectX 12.

If you'd rather see a sample that doesn't depend on the sample framework, see Minimal HelloGT Sample.

Integration

Start by including the necessary headers:

#include <Coherent/UIGT/UISystem.h>
#include <Coherent/UIGT/View.h>
#include <Coherent/UIGT/LicenseGT.h>

Initialization

Initialize the system with the appropriate settings.

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

Coherent GT requires a license key as it's first initialization parameter. Starter and trial versions come with a pre-bundled "LicenseGT.h" file containing the key. Pro licenses should have received their key upon purchase. All samples presume that there is a "LicenseGT.h" in the Coherent/UIGT folder containing a COHERENT_UI_GT_LICENSE string with your license. However, you can type the string wherever you want and pass it to the initialization function.

If you are behind a proxy server, you can pass it's data to Coherent GT for network connections. The application can detect the proxy settings in the most appropriate way for the platform or let users set their proxy.

proxy.Host = "192.168.88.7";
proxy.Port = 8000;
settings.ProxyData = &proxy;

After the system has been created, one needs a view:

// Fill the view info with the desired settings
ViewInfo info;
info.Width = width;
info.Height = height;
info.IsTransparent = true;
info.ResourceHandler = m_ResourceHandler.get(); // Required for "coui" resources to work
info.ViewListener = new SimpleViewListener();
//Create a view with using the CreateView interface of the UISystem
auto myView = m_UISystem->CreateView(info, "coui://uiresources/test.html");

The code above specifies the properties of the new View that will be created The SimpleViewListener class inherits from Coherent::UIGT::ViewListener. It implements the callbacks that the Coherent GT system will invoke upon certain events.

Memory management (optional)

Coherent GT allows the application to do all memory management of the library. Enabling this happens by inheriting the Coherent::MemoryManagementGT::IAllocator interface and passing an instance of the object in the SystemSettings struct. NB: Your implementation MUST be thread-safe. The allocation/deallocation methods will be called from multiple threads.

Below you can find a referent Windows implementation:

// Sample trivial memory allocator
class MemoryAllocator : public Coherent::MemoryManagementGT::IAllocator
{
public:
virtual ~MemoryAllocator()
{}
virtual void* Allocate(size_t size) override
{
return malloc(size);
}
virtual void Deallocate(void* ptr) override
{
return free(ptr);
}
virtual void* Reallocate(void* ptr, size_t newSize) override
{
return realloc(ptr, newSize);
}
virtual void* AlignedAllocate(size_t size, size_t alignment) override
{
return _aligned_malloc(size, alignment);
}
virtual void AlignedDeallocate(void* ptr) override
{
_aligned_free(ptr);
}
virtual void* VirtualAllocate(void* hint, size_t size, int protection, int flags) override
{
DWORD winFlags = (((flags & Coherent::MemoryManagementGT::VMF_Reserve) != 0) * MEM_RESERVE) |
(((flags & Coherent::MemoryManagementGT::VMF_Commit) != 0) * MEM_COMMIT);
DWORD winProt = 0;
switch (protection)
{
case Coherent::MemoryManagementGT::VMP_None:
winProt = PAGE_NOACCESS;
break;
case Coherent::MemoryManagementGT::VMP_Execute | Coherent::MemoryManagementGT::VMP_Read |
Coherent::MemoryManagementGT::VMP_Write:
winProt = PAGE_EXECUTE_READWRITE;
break;
case Coherent::MemoryManagementGT::VMP_Execute | Coherent::MemoryManagementGT::VMP_Read:
winProt = PAGE_EXECUTE_READ;
break;
case Coherent::MemoryManagementGT::VMP_Read | Coherent::MemoryManagementGT::VMP_Write:
winProt = PAGE_READWRITE;
break;
case Coherent::MemoryManagementGT::VMP_Read:
winProt = PAGE_READONLY;
break;
}
if (flags == Coherent::MemoryManagementGT::VMF_ProtectionChange)
{
assert(flags & Coherent::MemoryManagementGT::VMF_Commit);
assert(hint);
winFlags = MEM_COMMIT;
}
return ::VirtualAlloc(hint, size, winFlags, winProt);
}
virtual bool VirtualFree(void* ptr, size_t size, int flags) override
{
DWORD winFlags = 0;
if (flags == Coherent::MemoryManagementGT::VMF_Decommit)
{
winFlags = MEM_DECOMMIT;
}
else if (flags == Coherent::MemoryManagementGT::VMF_Release)
{
assert(ptr != nullptr);
winFlags = MEM_RELEASE;
// Size must be 0 for Release
size = 0;
}
return ::VirtualFree(ptr, size, winFlags) != 0;
}
};
...
// Set the memory allocator object
settings.MemoryAllocator = &gMemoryAllocator;

If you don't specify a memory management object Coherent GT will use the default system's malloc/free/realloc and OS-specific functions for aligned/virtual memory allocation and deallocation.

Rendering

All rendering in Coherent GT is performed by the Renoir graphics library on the GPU. The API-specific piece that connects the Renoir Core to the GPU is distributed for all major graphics APIs (DirectX 9/11/12, OpenGL, libGNM etc.) in the package. User can directly use the provided code or use it to customize and integrate the rendering in their engine. The user application must link with the rendering backend object and it is passed for the creation of the Coherent::UIGT::UISystemRenderer object, which performs the rendering of all Views.

To enable rendering for the Views you must create a Coherent::UIGT::ViewRenderer object for each View, the ViewRenderers are created from the UI system renderer:

// Create rendering backend (or use the ones provided in the package)
renoir::RendererBackend* m_Backend = new MyRenderingBackend();
m_UISystemRenderer = m_UISystem->CreateRenderer(m_Backend);
auto viewRenderer = m_UISystemRenderer->CreateViewRenderer(
m_View,
renderTarget,
m_View->GetWidth(),
m_View->GetHeight(),
sampleCount);

The above code creates the UI system renderer with a custom backend and a ViewRenderer that will draw in the renderTarget's texture. The application must link itself with the appropriate backend, either the ones provided in the Coherent GT package or a custom backend developed by the user. For more information on Rendering please refer to the apposite documentation section.

Update

Each frame the UI system has to advance some time, the views have to be laid out and than drawn.

//Updates the UISystem and the current view
//Returns the id of the recorded rendering command
unsigned Application::Update(float /*dt*/)
{
m_UISystem->Advance();
unsigned frameId = m_View->Layout();
return frameId
}
void Application::DrawScene(unsigned frameId)
{
//Update the view's texture - actual rendering
//Passing the id of the rendering commands to the Paint method
m_View->Paint(frameId);
DrawGame();
}

Coherent GT provides a custom protocol for URLs - coui://. All files that are display through this protocol will be loaded from a custom Coherent::UIGT::ResourceHandler. The default one loads the files using the current working directory as root.

Rendering backends

Coherent GT supports user provided rendering backends. This allows for flexibility when integrating Coherent GT with proprietary engines. Coherent GT comes with fully functioning sample backends for every supported platform. If a deep rendering integration is targeted, the interface of provided rendering backends should be a good starting point. For more information on rendering backends, click Rendering backends .

Deployment

To deploy an application using Coherent GT you need to deploy CoherentUIGT.dll and all the libraries bundled with it. CoherentUIGT.dll is the only library you need to link with.

The CoherentUIGTDevelopment module is optional. It implements the UI debugger layer and you can safely remove it from your shipped product.

Manually loading the libraries on Windows

Sometimes the libraries for Coherent GT might be positioned in a different folder than the main application's working directory. Developers can manually set the DLL search path and load CoherentUIGT.dll. Some libraries however are delay-loaded and will not be loaded when CoherentUIGT.dll is loaded (e.g. CoherentUIGTDevelopment.dll). At the moment of their load, the application might have changed the DLL paths and they'll fail. A simple and effective solution is to simply load all libraries along with CoherentUIGT.dll. Sample code that does this:

char buffer[MAX_PATH] = "";
GetDllDirectoryA(MAX_PATH, buffer);
SetDllDirectoryA(MyDLLFolder); // Set here the folder where the DLLs are
modules.push_back(LoadLibraryA("CoherentUIGT.dll")); // Will load all other deps
modules.push_back(LoadLibraryA("CoherentUIGTDevelopment.dll"));
SetDllDirectoryA(buffer); // Restores the previusly set DLL search path

The code will set a new library path and load all libraries. The delay-loader will work correctly and detect that the libraries are loaded as soon as they are needed.

Transitioning from Coherent UI 2.x

Coherent GT makes transitioning the whole UI or just some Views from Coherent UI 2.x very easy. The API provided is very similar, with classes residing in the Coherent::UIGT and Coherent::UI namespaces respectively. When transitioning, only the initialization and rendering parts for a View require changes. The Binding and Input APIs are 100% compatible, so no changes there should be done. Note however that Coherent GT has a synchronous JavaScript execution model, while in Coherent UI 2.x it is asynchronous. This means that calls to/from JavaScript will be executed immediately in Coherent GT. Previous application code that might have relied on the fact that scripts get executed asynchronously in Coherent UI 2.x should be modified. Content created for Coherent UI 2.x should run with almost no changes on Coherent GT. Functionality that requires new OS Windows is not supported - fullscreen Youtube video and <select> for example. Note however that the 'coherent.js' file may contain differences depending on you version. Always use the correct file for the runtime that is currently rendering your View.

Compatibility with Coherent UI 2.x

Coherent GT and Coherent UI 2.x can be easily used side-by-side. Coherent GT is best used for HUDs, menus call-outs due to its high-performance rendering and simple synchronous scripting model. Coherent GT has limited browser capabilities. When advanced web APIs like video, audio, WebRTC or WebGL are required - Coherent UI 2.x is still the way to go. There is no problem in having some Views in the application use Coherent GT, while others use Coherent UI 2.x. All API is hidden in their respective namespaces, but classes and method names are kept compatible. This allows for easy switching between UI 2.x and GT. With some typedefs you can easily configure your application to be able to switch at compile time between the two products. With a bit of abstraction you can even make the change dynamic.