Month: November 2017

Why you should never cast floats to ints

So a few weeks ago I wrote some code that would align my text in a rectangle. The alignment would be either top left, top center, top right, middle left, etc… After finishing that up, I noticed that my text looks bad and I figured that it was due to floating point rounding errors. This happens when you set a sprite position to something like

Vector2 position = Vector2(100.5f, 50.2f);

The problem here is that the smallest controllable element of a picture represented on the screen is a single pixel, and what you are trying to do is set your image, sprite, text or whatever to one hundered pixels and a half. There is no such thing as half a pixel. So your graphics card tries to correct that and in doing so you get artifacts like these

 

 

Notice how there are lines in between each sprite, that happens because the sprite position is not exact. The sprite position is not set to Vector2(100, 50). It is set to something in between like Vector2(100.5f, 50.5f) pixel. That causes artifacts like the lines you see above. So, how do you solve this? Either cast your floating point positions to ints then back to floats or use a function like Round or Floor to round your numbers up or down to whole numbers.

 

So let’s take a look at my text

As you can see, the text above is a lot cleaner than the text below. The text below looks like it has artifacts (which it does). Notice the letters “u”, “F”, “m”, “i”, and “e”. They all look bad. That is because these letters position is not exact. So how did I fix that? I cast my floats into ints, did my division calculations to align the text inside an imaginary rectangle and I cast those ints back to floats.

The day I wrote that code, I knew it was temporary and I would change it later on. I did not like the fact that I had to cast my numbers not once, but twice. At the time I didn’t think it had any impact on my engine performance, but oh boy was I wrong.

So a few days ago I was going through my YouTube subscription box and I found a video from CppCon about how unsigned integers are much slower than signed integers. After hours of research, I came across this article. Why you should never cast a Floats to Ints. After reading that I remembered the block I wrote that would cast my text position from float to an int back to float again. Here it is.

 

Math::Vector2 Text::GetTextAlignmentOffset(TextAlignment textAlignment)
{
    Vector2 textSize = Vector2((float)rectangle.width, (float)rectangle.height);
    Vector2 scissorRectangleSize = Vector2((float)scissorRectangle.width, (float)scissorRectangle.height);
    return Vector2((float)((int)(scissorRectangleSize.Center().x - textSize.Center().x)), (float)((int)(scissorRectangleSize.Center().y - textSize.Center().y)));
}

This horribly looking code made me want to test what the above article said about how casting floats to ints is bad. So here is what I did. I created three tests like so.

int main()
{
    BF::System::Timer t;
    
    BF::Math::Rectangle rectangle(10, 10, 100, 200);
    BF::Math::Rectangle scissorRectangle(0, 0, 200, 300);
    
    //Test1
    //------------------------------------------------------------
    t.Reset();
    
    for (size_t i = 0; i < 10000000; i++)
    {
    	Vector2 textSize = Vector2((float)rectangle.width, (float)rectangle.height);
    	Vector2 scissorRectangleSize = Vector2((float)scissorRectangle.width, (float)scissorRectangle.height);
    	Vector2 pos1 = Vector2((float)((int)(scissorRectangleSize.x - textSize.x)), (float)scissorRectangle.y);
    }
    
    std::cout << t.GetElapsedTimeInMilliseconds() << std::endl;

    //Test2
    //------------------------------------------------------------
    t.Reset();
    
    for (size_t i = 0; i < 10000000; i++)
    {
    	int p = scissorRectangle.width - rectangle.width;
    	Vector2 pos2 = Vector2((float)p, (float)scissorRectangle.height);
    }
    
    std::cout << t.GetElapsedTimeInMilliseconds() << std::endl;

    //Test3
    //------------------------------------------------------------
    t.Reset();
    
    for (size_t i = 0; i < 10000000; i++)
    {
    	Vector2i pos3 = Vector2i(scissorRectangle.width - rectangle.width, scissorRectangle.height);
    }
    
    std::cout << t.GetElapsedTimeInMilliseconds() << std::endl;
    //------------------------------------------------------------
    
    return  0;
}

The first test casts “rectangle.width” and “rectangle.height” from integers to floats and stores them inside “textSize”. The same thing is done to “scissorRectangle” and it is stored inside “scissorRectangleSize “. After that, I subtract “scissorRectangleSize.x” from “textSize.x” and cast them from float to int and back to float again. Running this ten million times took 86.4108 milliseconds. I did 7 total casts in this test.

The second test I only did two casts. Running that also ten million times took 25.1934 milliseconds.

In the third and last test, I’ve done a total of zero casts since Vector2i is a vector with two ints instead of two floats for the x and y. Running this ten million times took 25.2048 milliseconds which is around the same amount of time the second test took.

 

Keep in mind all these tests were done on release build on x64.

So, there you have it. Doing this many casts in three lines of code is very bad.


[Blue Flame Engine] Adding C# scripting support

Alright, so I started thinking of adding scripting support to my engine. There is a laundry list of things that I feel like should be done before adding scripting support, but I feel like adding scripting to the engine at this stage will motivate me to finish up some of the things that I should have finished a long time ago. Like the editor -.-

C# has been extremely popular as a scripting language for a lot of game engines like Godot, Unity, Unreal, Frostbite and more. Personally, I love C# as much as C++. So, C# will be the first official and maybe the only scripting language to be added to the engine.

So you might wonder, how will this be done. Well, this is exactly what I asked myself at the beginning of the day. A couple of hours of research later, it turns out that I could use C++/CLI to convert my C++ unmanaged code to C++ managed code and use it in C#. This process will be tedious if I do it on my own. I have a little over 10,000 lines of code in my engine thus far and I don’t feel like converting every single line to managed C++. That would drive me crazy. So I’m thinking of using or creating a tool to do that for me.

 

Well, wish me luck. I’m going to need it.


[Blue Flame Engine] Node based system

Alright, it’s has been a while since I posted anything here. But here it goes.

 

For the past couple of weeks, I have been thinking of changing the engine architecture. Instead of creating a class for each object in the game, (for example, to add a player in the game you would create a player class and call it inside the scene) now you would add a node to a scene. A node can be anything from a Camera, Sprite, Mesh or a Light node, etc… Each node will be automatically initialized, loaded, updated and drawn in the scene without you the programmer having to go and call each function for each class.

Each node can have n number of nodes as child nodes.

So basically it will kind of follow the same architecture as Godot, Unity, Oger3D engines. Eventually, when I add script support, you will also be able to add a script node.

 

I haven’t fully settled on this architecture but to me, it seems the best way to go if this is going to be an editor based engine. I’m not sure yet.

 

My main goal for this engine is speed. Unity takes a billion years to open or create a new project. It also takes a billion years to compile anything. Editing code, while the game is running, is also not great at all. I don’t want to wait around for 20 seconds for a project to compile and run. I want it to run instantly. Unity takes forever to even load a new scene, and I’m running a 16 core 1950X. Godot surprised me with how fast it builds and runs a project. If I can make my engine anywhere near as fast Godot, I will be very happy. Honestly, I would contribute to the Godot team, but I don’t think I’m good enough. I don’t think I’m at the point where I can contribute to something that big.

 

Anyways, those are my thoughts.

 

Cheers