Coherent UI  2.5.3
A modern user interface library for games
 All Classes Namespaces Functions Variables Enumerations Enumerator Pages
Sample - Multiple Views

This tutorial demonstrates showing different views on different objects in the world.

You can move in the world using W/A/S/D, look around using the mouse and lock/unlock the mouse by pressing Alt. Input forwarding works only when the mouse is unlocked.

Note
Supplied code, unrelated to Coherent UI integration, is not representative for a well-designed, high-performance solution. It's written for simplicity and its purpose is to demonstrate integration in an existing game framework.

Building the sample

The sample solution is already configured and you only have to compile and run it.

It uses a sample mini game framework that provides very basic functionality.

The output will be in the Coherent/Samples/UI/bin directory.

Prerequisites

  1. This sample assumes you read and understood Sample - Input in 3D.

Key points

Note
This section is provided for completeness and describes the changes in the supplied mini game framework from the previous samples. Feel free to skip it.
  1. The Renderer now exposes a method for creating textures with user provided IDs. It also has a map of IDs to their corresponding textures.
  2. The Z-Buffer is turned on, since we draw multiple objects.
  3. The Renderer::DrawScene method has its signature changed to easily draw multiple objects.
  4. The GameObject now stores a texture ID of the texture that's mapped onto it.

Sample walkthrough

You'll notice a few changes in the ViewEventListener and ContextEventListener classes.

ViewEventListener now has methods for setting/unsetting focus (ViewEventListener::SetFocus and ViewEventListener::KillFocus) and doesn't set the focus when the view is created, because now we have more than one view and it wouldn't make sense to set the focus every time a view is created. Each view requests a new texture when created and uses can be queried for its ID so it can be drawn.

ContextEventListener now exposes a method CreateView, instead of creating one when the context is ready. This is more flexible, as the ContextEventListener is a single instance and the ContextReady event is fired only once. With this method exposed, we can create views dynamically.

By default, this sample creates 5 views, as defined in Application.h

const int VIEWS_COUNT = 5;

In the Application::Initialize method, we set up a listener and a game object texture for each view.

Since this time we do not create views in the ContextReady handler, we'll have to do it elsewhere. In this sample we'll just try to create all the views every frame in the main loop, that is if the view context is ready and we have not created them yet.

void Application::CreateViews() // Called every frame
{
static bool alreadyCreated = false;
if (alreadyCreated)
{
return;
}
if (m_ContextListener.IsContextReady())
{
const wchar_t* sampleUrls[] =
{
L"http://www.google.com",
L"http://www.msn.com",
L"http://www.yahoo.com",
L"http://www.facebook.com",
L"http://www.twitter.com",
L"http://www.coherent-labs.com"
};
const size_t sampleUrlsCount = sizeof(sampleUrls) / sizeof(sampleUrls[0]);
for (int i = 0; i < VIEWS_COUNT; ++i)
{
m_ContextListener.CreateView(
VIEW_WIDTH, VIEW_HEIGHT,
m_ViewListeners[i].get(),
sampleUrls[i % sampleUrlsCount]);
}
alreadyCreated = true;
}
}

In the Application::OnIdle callback, we have 2 new methods - UpdateGameObjectsTransformations and UpdatePickedObject.

UpdateGameObjectsTransformations updates the rotation and scaling of each object, so that the objects are always facing the camera (using a billboarding technique) and the selected object is enlarged.

UpdatePickedObject intersects every object with the ray, computed from the mouse position, updates the index of the picked object and sets/unsets view focus when the selection changes. The following new member variables are used for game logic and are not related to Coherent UI integration:

float m_ScaleFactor[VIEWS_COUNT];
float m_ScaleStep[VIEWS_COUNT];
float m_TargetScale[VIEWS_COUNT];
int m_FocusedObjectIndex;
static const int NO_FOCUSED_OBJECT = -1;

After we've updated the transformations and picking information, we dim the views that are not selected with a color multiplier and draw all objects.