WOWCube Docs logo
WOWCube Docs
Mission Control
Section Shortcuts
APIExamplesSourceWOWConnectChangelog
Filters
SDK and language defaults persist in cookies.
SDK version
Navigation Tree
Collapsed by default, focused on the active path.
Made byMcKay Seamons
GitHub
  1. Home
  2. Docs
  3. Examples
  4. GFX Engine - Text
Mission NodeSDK 6.2C++renderingProject Included

GFX Engine - Text

GFX Engine Text Ok, so we've learned how to draw graphic primitives and sprites, as well as how to render a text using CubiOS native API. This could have bee...

Examples / SDK 6.2 / C++ / rendering

GFX Engine - Text

Ok, so we've learned how to draw graphic primitives and sprites, as well as how to render a text using CubiOS native API. This could have been the point where you say right, I now know enough to be dangerous, let's make a game!

And you know what?

You probably wouldn't be too far off from the truth. You really can make a complete game or some other application just by using CubiOS native API. Moreover, in Pawn language this would be literarly the only way to do. Not in C++ though...

You may ask what is wrong with native API? Nothing. Nothing except the fact the API is a rather low-level thing, which allows you implementing everything you want but also requires a lot of code writing.

Low-level programming involves writing code that interacts directly with the APIs of a device, or even with device hardware directly.

High-level programming, on the other hand, involves writing code using programming langages that are closer to natural language. This provides more abstraction and higher-level constructs, such as classes and objects, making it easier to write complex programs.

That said, it is important to understand that native CubiOS API is not the real low-level instrument that give access to WOWCube hardware, but just a programming interface that provides lesser level of abstraction comparing to what can be done with help of C++ and its object-oriented paradigm.

For example, imagine that a game has 50 sprites that need to be shown in a certain order, in certain places, and with certain delays. Of course, this can be done using the native API. But the problem is that to draw each specific sprite, you will have to use a set of the same type of native API calls, which can very quickly lead to code growth and reduce its readability and maintainability.

On the other hand, the object-oriented approach allows you to effectively "wrap" typical sequences of API calls into classes and thereby significantly increase the level of abstraction of the code as a whole, its readability, and even the possibility of reuse in other projects. And, where is a higher abstraction, there is a save of development time.

GFX Engine quick intro

A graphics engine, also known as a game engine or rendering engine, is a software system designed to create and display digital graphics, typically for video games, but also for other types of multimedia applications, such as virtual reality experiences or simulations. The graphics engine is responsible for rendeing in-game objects, sprites, texts, playing sounds and handling game logic and user input. It uses mathematical algorithms to calculate the position, movement and appearence of objects in the virtual environment, then performs the corresponding native API calls to display the result on the screen.

So, the GFX Engine is a graphics engine. It uses object-oriented approach for providing a higher-level abstraction (comparing to the native API) for the majority of things you may want to do in the code of your game.

The engine allows to structurе the code the way so that every visual or sound resource used in your game is an obect that has its own unique set of properties and interacts with other objects of the game.

This approach, of course, fully reflects the principle of the object-oriented approach, but in addition, it greatly simplifies the work with a large number of game objects. In other words, it's just more convenient!

But let's move from theory to more specific things... So, what are the main classes GFX Engine uses to represent the entire environment as a hierarchy of objects?

As we know, WOWCube device has 8 modules, each with 3 screens. In GFX Engine, each screen is an object with has the following properies:

  • Screen ID that uniquely identifies the screen
  • Screen Position on a face
  • An index of a Face the screen belongs to

screen_class

and

  • The Scene

scene_class

The Scene is an object that serves as a repository for all other game objects, including sprites, text, sounds, and so on.

When added to the scene, each object is assigned a unique identifier, which provides access to this object later.

objects

It should be noted that all objects added to the scene have both a set of common properties and properties that are specific only to an object of a certain class.

Common properties of all objects include

  • Object Id - unique object identifier
  • Object Transform - a class that holds object position, rotation and mirroring information
  • Object Color - a class for object color, if applicable
  • Object visibility flag
  • Parent screen
  • Parent screen rotation angle

Object class-specific properties depend on what that object really is, and may be quite anything. For example, one of the most important properties of Text object is Content - a string variable that hold the content of a text. But the AnimatedSprite object has a property called PlaybackMode that allows to specify how exactly sprite's animation should be played - continuously, just once or ping-pong.

Once you have all your objects loaded into the scene, you can start using them for rendering on a screen.

A typical generalized sequence of calls for scene rendering looks like this:

  • Iterate through all screens in on_Render function
  • For each Screen, call Screen::Begin() method. This will inform the GFX Engine you want to start adding object to a screen
  • Using object's ID property, find it in the scene
  • Using Scene::Add() function, add object to a screen
  • Repeat it for all objects you'd like to render
  • Call Screen::End() function to commit recently added objects to rendering

rendering

...and this would be pretty much it!

The example

Let's first try to draw some text using the engine. And let's do something a little more interesting than just Hello World too.

Initialization of an application that uses GFX Engine is practically the same as the one we are already familiar with. In the same way as in the previous examples, we will use the InitializeResources() function to create Text objects. The only difference is that before actually creating objects and adding them to the scene, we will declare the named identifiers of these objects in order to refer to them in the future by name:

GFX Engine - Text
CPP
1enum GfxObjects
2{
3 myBackground=0,
4 myText,
5 myText2,
6 myText3
7};
8
Wrapped for easier reading. Turn wrap off to inspect exact line lengths.

As you can see, we will have three text objects and one object for drawing the background.

The initialization looks like this:

GFX Engine - Text
CPP
1void GfxText::InitializeResources()
2{
3 //Create a Cubios::Gfx::Background object
4 this->Scene.CreateObjectWithID(GfxObjects::myBackground,new Background(255,0,0));
5
6 //Create a Cubios::Gfx::Text objects
7 this->Scene.CreateObjectWithID(GfxObjects::myText,new Text("WOWCUBE",120,60,9,Colors::gold));
8 this->Scene.CreateObjectWithID(GfxObjects::myText2,new Text("IS",120,120,12,Colors::gold));
9 this->Scene.CreateObjectWithID(GfxObjects::myText3,new Text(" ",120,180,9,Colors::gold));
10
11 this->SetTimer(1,250);
12}
13
Wrapped for easier reading. Turn wrap off to inspect exact line lengths.

Let's take a closer look at this function...

First - and this is very important - you should note that every application that uses the GFX Engine automatically gets a member of the Scene class, which is a scene object. This object has methods that allow you to create and delete objects displayed on screens.

So, the first step is to create and register an object of type Background in the scene. As you can see from the source code above, we initialize this object with an RGB color (255,0,0), then we register it with the id myBackground.

Next, we create three objects of type Text. The initialization parameters for these objects are set in the following order:

  • Content
  • Object position coordinates
  • Font size
  • Text color

All three objects are registered in the scene under identifiers myText, myText2 and myText3.

And at the end, we register a timer for the animation. We're planning on doing something more fun than just Hello World, right?

So, why exactly do we need a timer?

Look, we've created three text objects. The first two are initialized with the words 'WOWCUBE' and 'IS'. Hmm... WOWCUBE IS... what? The thing is, you can't describe it in one word. Therefore, we will not. Instead, we will define an entire array of words that describes WOWCube:

GFX Engine - Text
CPP
1GfxText::GfxText():a(0),currWord(0),words{"captivating","lovely","sensational","superb","undaunted","wonderful","fabulous","outstanding","grand","exemplary","trendy","posh","fresh","edgy","neat","groovy","awesome"}
2{
3}
4
Wrapped for easier reading. Turn wrap off to inspect exact line lengths.

and then set up a timer in such a way as to select a random word from this array:

GFX Engine - Text
CPP
1void GfxText::on_Timer(uint8_t timerID)
2{
3 if(timerID==1)
4 {
5 this->currWord = Cubios::random(0,this->words.size()-1);
6 }
7}
8
Wrapped for easier reading. Turn wrap off to inspect exact line lengths.

Now all that remains is to render the result!

To do this, as mentioned above, you need to take a few simple steps. Here is the on_Render() function:

GFX Engine - Text
CPP
1void GfxText::on_Render(std::array<Cubios::Screen, 3>& screens)
2{
3 Background* bkg = (Background*)this->Scene[GfxObjects::myBackground];
4
5 for(auto it = screens.begin(); it != screens.end(); ++it)
6 {
7 //Start adding objects to a screen
8 it->Begin(TOPOLOGY_orientation_mode_t::ORIENTATION_MODE_GRAVITY,true);
9
10 //Set background colors
11 switch(it->ID())
12 {
13 case 0: it->Add(bkg->SetColor(Colors::darkRed)); break;
14 case 1: it->Add(bkg->SetColor(Colors::darkGreen)); break;
15 case 2: it->Add(bkg->SetColor(Colors::darkBlue)); break;
16 }
17
18 //Use in-place setters for changing Text content and position
19 dynamic_cast<Text*>(it->Add(this->Scene[GfxObjects::myText]))
20 ->SetPosition(120,60+50*sin(a));
21
22
23 dynamic_cast<Text*>(it->Add(this->Scene[GfxObjects::myText2]))
24 ->SetPosition(120,120+50*sin(a+0.6));
25
26 dynamic_cast<Text*>(it->Add(this->Scene[GfxObjects::myText3]))
27 ->SetContent(this->words.at(this->currWord))
28 ->SetPosition(120,180+50*sin(a+1.2))
29 ->SetColor(Cubios::random(0xFFCCCCCC,0xFFFFFFFF));
30
31 //Finish adding objects
32 it->End();
33 }
34}
35
Wrapped for easier reading. Turn wrap off to inspect exact line lengths.

Let's see step by step what happens in this function. So. The iteration through screens is running.

First, a pointer to our Background object is requested from the scene. The Scene class suppots the square bracket ([ ]) operator for requesting pointers to objects by object identifier. So we request an object with id = myBackground:

GFX Engine - Text
CPP
1Background* bkg = (Background*)this->Scene[GfxObjects::myBackground];
2
Wrapped for easier reading. Turn wrap off to inspect exact line lengths.

Then depending on which screen we're currently adding objects to, we use an in-place setter function to change the color of the background object. That's it, despite that the object was initialized with (255,0,0) at creation, the actual color will be the one we just set.

GFX Engine - Text
CPP
1//Set background colors
2switch(it->ID())
3{
4 case 0: it->Add(bkg->SetColor(Colors::darkRed)); break;
5 case 1: it->Add(bkg->SetColor(Colors::darkGreen)); break;
6 case 2: it->Add(bkg->SetColor(Colors::darkBlue)); break;
7}
8
Wrapped for easier reading. Turn wrap off to inspect exact line lengths.

And finally, we are adding all three text objects to the screen, changing their positions and content along the way depending on the values of the animation variable with in-place setter functions:

GFX Engine - Text
CPP
1dynamic_cast<Text*>(it->Add(this->Scene[GfxObjects::myText]))
2 ->SetPosition(120,60+50*sin(a));
3
4
5dynamic_cast<Text*>(it->Add(this->Scene[GfxObjects::myText2]))
6 ->SetPosition(120,120+50*sin(a+0.6));
7
8dynamic_cast<Text*>(it->Add(this->Scene[GfxObjects::myText3]))
9 ->SetContent(this->words.at(this->currWord))
10 ->SetPosition(120,180+50*sin(a+1.2))
11 ->SetColor(Cubios::random(0xFFCCCCCC,0xFFFFFFFF));
12
Wrapped for easier reading. Turn wrap off to inspect exact line lengths.

That, in fact, is all. As a result, we will see animated text on the edges of the WOWCube, which will rightly tell us the WOWCube is "trendy","posh","edgy","awesome"... just run the example to see the rest.

Context Rail

Project files

GfxText.cpp
project/src/GfxText.cpp
GfxText.h
project/src/GfxText.h
wowcubeapp-build.json
project/wowcubeapp-build.json
Jump Grid

On This Page

GFX Engine TextGFX Engine quick introThe example
Context Rail

Related nodes

info.json
Examples / SDK 6.2 / C++ / rendering / GFX Engine - Text
GfxText.cpp
Examples / SDK 6.2 / C++ / rendering / GFX Engine - Text / project / src
GfxText.h
Examples / SDK 6.2 / C++ / rendering / GFX Engine - Text / project / src
wowcubeapp-build.json
Examples / SDK 6.2 / C++ / rendering / GFX Engine - Text / project
Previous Node
wowcubeapp-build.json
Examples / SDK 6.2 / C++ / rendering / Simple Shapes - Bitmaps / project
Next Node
info.json
Examples / SDK 6.2 / C++ / rendering / GFX Engine - Text