Implementing The New Road Profiles
Not so much show-able work done this week, but here we go!
Managing Gpu Resources
I started the week working, as expected, on my new road profile structure. I wanted to do it properly with a structure close to final one since I have a few complex generative algorithm that will rely on it, and this required referencing GPU resources (meshes and materials) in a safe way. However, so far, most of my GPU resources were improperly managed (at executable start, I have a big function that allocates GPU resources for my gym world and they are never really released).
If you are unfamiliar with how GPU memory works, know that it's not the same as RAM: you can't just create a `shared_ptr` to that mesh data you will render and hope it would be released the moment every references to that mesh are gone. You can't even release the GPU memory used for that mesh from any thread, it has to be done from the thread that is currently allowed to render (usually games make it always the same for simplicity). In OpenGL it looks like this:
glCreateBuffers(1, &bufferId);
// Once all uses of the buffer are done
glDeleteBuffers(1, &bufferId);So, most of my week has been spent working on a pattern to manage those resources. It looks a bit like a `shared_ptr`, except when last user of a resource is done using it, the `Registry` managing the resource is notified (but the resource is still allocated at this point). Then a system is responsible for processing those newly unused resources and releasing what needs to be. Here is a simplified code sample to illustrate:
template <typename T>
struct Handle
{
// among other things:
Handle(Handle const& a_other)
: m_index{ a_other.m_index }
, m_control{ a_other.m_control }
{
if (isValid())
{
if (auto const control = m_control.lock())
{
control->addReference(m_index);
}
}
}
~Handle()
{
if (isValid())
{
if (auto const control = m_control.lock())
{
control->removeReference(m_index);
}
}
}
};
template <typename T>
class Registry
{
public:
Handle<T> add(T a_resource);
T const& get(Handle<T> const& a_handle);
// Calls a_func for each resource whose use count reached 0
// since last time this function was called.
template<typename TFunc>
void processNewlyUnusedResources(TFunc a_func);
private:
std::shared_ptr<Control> m_control;
};With this done, GPU resources get properly released on last use, noice!
New Road Profiles
So now that GPU resources can be handled safely, I was able to work on setting up the road profile configuration (runtime for now, data configuration will come later). And just as I explained last week, each road profile is composed of two lists (left & right) of road sections (each optionally mirrored), and each road section is composed of extruded surfaces and repeated models/lights.
The most tricky part was handling left and/or mirrored sections because their positions/normals data (which obviously must remain constant, I don't want to have 2 versions of each section in memory depending on if it's mirrored or not) need to be flipped appropriately during construction. I did it by offsetting each section's starting point (based on whether it's a left or right section, mirrored or not mirrored), while applying an appropriate scale along the lateral axis (+/-1). I'm a bit running out of time to make a drawing, so you will have to imagine it!
To test this, I created three sections:
- a fence, with street lights on top
- a dirt road with a raised edge on the outside (it's slippery, so it helps keep the car in bounds)
- a half bump asphalt road (weird name)
And here is a few road profiles I made with those sections (yes, some are very stupid, I'm just testing):

Now that this is working, I started the generation of transition road. Here is what I got working for it so far:
Off course it's still missing the transition of incompatible surfaces (next week? yeah I don't think it's too optimistic to think this should be done), but you can see how the rest is extruded appropriately while also accounting for potential change of height between the two road profiles (here the right border is technically lower on furthest road).
