Skip to content

Guerrilla Renderer

Twarit Waikar edited this page Aug 6, 2018 · 13 revisions

Rubeus: Guerrilla Renderer

Curated by SDSLabs with ❤️

Guerrilla Renderer is the standard renderer that Rubeus uses to render 2D sprites. The name Guerrilla comes from the fact that it attempts to add all the sprites to the GPU memory at once, instead of adding them one by one to provide a performance boost. (which makes the name a bit ironic)

User guide

The Guerrilla Renderer jargon

  • Layers

    • Each layer is a collection of groups of game objects.
    • Each group is a collection of game objects that can be sent to the Guerrilla Renderer to be rendered every frame.
    • The layer is drawn to the screen in a single draw call per frame, which effectively means that more the number of layers, more the number of draw calls(which can reduce performance).
  • Groups

    • A Group in Guerrilla Renderer can be regarded as a hierarchy of parent and child game objects.
    • All the children game objects receive the position and rotation set by their parents in absolute space so that the children game objects are positioned relative to the parent objects.
  • Sprites

    • Sprite is similar to a POD data structure which contains all the data required to approximate a particular 2D image or colour on the screen within some specified bounds.
    • These sprites are added directly to group objects, and these group objects are in turn sent to the Guerrilla Renderer and nothing else is required by the user to be done from that point on.
  • Game object hierarchies

    • Each game object also has a Sprite object which is the source of any visual renders we are able to see in the game. These sprite objects are to be specified while constructing the game object. Sprites can be constructed by specifying the colour values in an RML::Vector4D structure or a path to the image texture to be used instead of plain colours.

Notes

Every layer object contains its own Guerrilla Renderer object. When draw() is called on the layer object, the layer object submits all groups of game objects inside it to the corresponding layer's Guerrilla Renderer for drawing.

A Group in Guerrilla Renderer can be regarded as a hierarchy of parent and child game objects. All the children game objects receive the position and rotation set by their parents.

A group is also class game object, thus you can add groups within other groups to have a denser group hierarchy. This will allow you to create game objects which recursively inherit the position and rotation of their immediate parents.

Usage in C++:

using namespace Rubeus;
// Adds Rubeus sub-systems to active scope

using namespace GraphicComponents;
// Adds Rendering components and helper objects

using namespace RML;
// Adds a custom maths library, being developed to work for Rubeus

RShaderComponent * shader = new RShaderComponent("Shaders/basic.vert", "Shaders/basic.frag");
// These shaders are present in the repository. These are very simple shaders that just display textures/colours on the 
// screen without any contextual modifications.

RStaticLayer * layer = new RStaticLayer(*shader);
// StaticLayer class is an implementation of the Layer class that is customised for 2D projections.

RGroup * g = new RGroup(Matrix4::translation(Vector3D(0.0f, 0.0f, 0.0f)) * Matrix4::rotation(0, Vector3D(0, 0, 1)));
// Each of the group objects can be displaced from the origin in such a way that the objects contained inside the group 
// are also displaced simultaneously. Thus the transform matrices being sent in to the Group constructor help specify the 
// initial transform matrix.

RTexture * texture = new RTexture("Assets/test8.png");
// Loads a texture which needs to be passed into Sprite objects to apply textures to sprites

g->add(new RSprite(3.0f, 3.0f, 3.0f, 3.0f, texture));
// Adds a sprite object that uses the image Assets/test8.png.
// Object is owned by the group, which makes the sprite object not needed to be deleted outside the renderer.
// Look up Sprite.h for specific parameter documentation

layer0->addGroup(*g);
// Prepare a group to be added to the rendering queue

RWindowComponent * GameWindow = new RWindowComponent("Hello World",
						      1280, 720,							 
                                                      EWindowParameters::WINDOWED_MODE,
						      EWindowParameters::NON_RESIZABLE_WINDOW,
						      0);
// Initialises a window. Look up WindowComponent for more details.

while(!GameWindow->closed())
{
	GameWindow->clearWindow();

        layer->draw();
        // Draws the layer contents to the screen

	GameWindow->updateWindow();
}

// Always remember to delete owned pointers
delete shader;
delete layer;
delete group;
delete texture;

Contributor's guide

Guerrilla Renderer is a member object of a Static Layer class. The layer's draw() function uses the member renderer and calls the submit() function on the sprite objects which also sends a reference to the layer's renderer and calls the submit() function on the passed-in renderer.

This type of a system where the responsibility of adding the sprite to the rendering queue is put on the sprite itself was done to incorporate children group objects in the game object hierarchy.

All group objects also have an overriding submit() function that is used by the static layer's draw() function, in case one of the children of the parent group object is a group object instead of a game object. To achieve this form of a functional polymorphism, the Group class and the Sprite class inherit from the RenderableObject class. The RenderableObject class provides a compulsorily overridable submit() function, which is polymorphed to be behaving differently when the object is of group type from when the object is of a game object type.

Rubeus' Guerrilla renderer is highly inspired by an older version of Sparky Engine, initially a cross-platform, high-performance 2D game engine.

The naive game loop implemented above will be hidden into the engine implementation later when the architecture has been decided.