Building a Flexible Bindable and Drawable System with C++

Welcome back to Techal! Today, we have something different in store for you. We are diving into software engineering, specifically design and architecture. In our previous tutorials, we have been working on a function that draws a cube. However, there are some issues with the organization and efficiency of our code. In this article, we will show you how to create a system that allows us to persist objects across frames, eliminating the need to create and destroy them every time. Are you ready? Let’s get started!

Building a Flexible Bindable and Drawable System with C++
Building a Flexible Bindable and Drawable System with C++

The System Overview

In order to tackle the challenges we are facing, we need to create a system that brings together all the elements that can be bound to the pipeline, such as shaders, buffers, layouts, and state objects. Our goal is to treat them uniformly when we draw our entities.

To achieve this, we will create an abstract class called Bindable, which will define a virtual function called bind. Each specific resource that can be bound will inherit from this class and implement the bind interface according to its requirements.

On the other hand, we have the entities that are drawable, which we call Drawable. These entities will consist of one or more bindable resources. When we call the draw function on a drawable object, it will call the bind function on each of its bindable resources, bind everything to the pipeline, and then call draw on the graphics object.

The beauty of this system lies in the fact that all the bindable resources can be stored in a single homogeneous container, such as a vector. We can then loop through each object in the vector and call draw on them, regardless of the combination of bindable resources they have. This provides us with persistence and reusability while allowing flexible composition.

Further reading:  Techal Announces Exciting Updates

Implementing the System

Let’s take a closer look at how this system is implemented. We will start with the Bindable interface class. It defines the bind function that will be implemented by its child classes. Additionally, it includes a virtual destructor for proper polymorphic behavior.

In order to give the bindable child classes access to the private members of the graphics object, we use a little trick. We make the base class a friend of the graphics class and create protected static functions in the base class that give access to the required members. The child classes then use these functions to get the necessary parts of the graphics object. With this approach, we don’t need to declare a separate friend relationship for each bindable class.

Next, we have the concrete bindable classes, such as index buffer and input layout, which inherit from the Bindable class and implement their own specific binding logic. Each class knows its own creation and binding procedure, encapsulating all the details within itself.

Moving on to the Drawable class, it serves as a container for bindable resources and provides the logic for drawing a drawable object. It includes functions for adding bindable resources, as well as a draw function that loops through all the bindable resources, binds them, and finally calls draw on the graphics object.

To handle the special case of the transformation constant buffer, we use a composition approach. The TransformCBuffer class inherits directly from Bindable and includes a vertex constant buffer as a member. The TransformCBuffer maintains a reference to its parent drawable, allowing it to automatically update the constant buffer with the transform information and bind it to the pipeline when bind is called.

Further reading:  More Variables: Understanding the Power of Numeric Variables

Conclusion

In this article, we have explored the design and implementation of a bindable and drawable system in C++. By creating a uniform interface for bindable resources and utilizing composition and inheritance, we have achieved better organization, persistence, and reusability of resources. This system provides flexibility in the combination of bindable resources, allowing for efficient drawing of entities.

If you are interested in diving deeper into the code and understanding the finer details of the design, we encourage you to check out the code on our GitHub repository.

We hope you found this article informative and useful. Stay tuned for Part 2 of this tutorial, where we will further improve this system and reduce redundancy in the binding process. As always, thank you for reading, and if you have any questions or suggestions, please leave them in the comments below. We appreciate your support!

Techal

YouTube video
Building a Flexible Bindable and Drawable System with C++