itch.io is community of indie game creators and players

Devlogs

Sprite rendering

War 1
A downloadable game for Windows

This series of articles is not intended to teach how to write game engines, nor is it intended to claim the correct way of doing things.

The first thing was to render a sprite on the screen. For that I needed some mechanism that allows me to send sprite data (a.k.a. an array of pixel data (a.k.a. 4 bytes one for each red, green, blue, alpha channels)) to the screen. Since I decided early on that I wanted to do the project on C (I’ve been working on C for the past couple of years) and I knew I would want at some point to be able to execute the game on Linux or Windows, the use OpenGL felt right (I could do an abstraction layer to be able to use DirectX on Windows, but I prefer not to have that and work with a single API).

The game is entirely in 2D, so I knew I wouldn’t be needing any “advanced” rendering techniques, just a function that allows me to do:

renderSprite(gfx, sprite, position);<span></span>

So I did that and used it for a while to render sprites on the screen.

Later on, I realized that I had the problem to render some portion of a sprite because the animations of the units come in big sprite sheets with tons of animation frames. Then I needed some functionality that allows me to do render the `nth` sprite in a sprite sheet:

renderSubSprite(gfx, sprite, index, position);

I kept those functionalities for a while.

That’s all I needed to start because I knew that animation is just to render different sprites in a sprite sheet very fast, to archive the sense of motion.


Now, behind those function calls is OpenGL, and I started to build the functionalities by hand. That implied dealing with OpenGL initialization code, creating and managing vertex and index buffers, shaders, textures and several settings on the OpenGL pipeline. OpenGL is a 3D API, so any rendering you need in 2D happens using a couple of triangles to form a rectangular shape, and then texturing it with the sprite you need to visualize.

That means that when you need to render non-sprite things, like rectangles, lines or other kinds of shapes, you need to make a set of triangles that conform to those shapes (yes, lines are rendered with two very thin triangles). In the end, all I wanted is a function that allowed me to draw a shape as conceptually I conceive it. For instance, I would want something like:

renderRect(x, y, width, height, color);
renderLine(point1, point2, color);
renderPolyline(points, color);

And hide the work with OpenGL behind those functions, but at the same time being open to optimizations. The optimizations part is important because I ended up needing to group data and make as few OpenGL calls as I could.  

There is another aspect that the rendering system needed to deal with, and that was transformations.

I knew something else and is that in the end, I would need a more stable set of functions because I would need sometimes to render other things than just sprites, I would need to render rectangles, lines, and polylines. I have always been comfortable with the API that browsers implement for the HTML 5 Canvas element (I had worked with that in extensively other projects) so I wanted a set of functions like that.

I started to implement a library in C that complies with that standard <link: https://www.w3.org/TR/2dcontext/>. After a while, I had some of the functionalities implemented, but I quickly notice that that would be a nice side project to do, and if I spend to much time on it I would be got sidetracked from the development of the game. So I make a little search and found: NanoVG <link: https://github.com/memononen/nanovg>, which do exactly what I want and has no dependencies. So I gave it a try, and today is the rendering library that I use in the project.

That way I could render other stuff, like the selection rectangles and the viewport in the minimap.


Now that I had some sprites and animations on the screen, I could move forward to other systems in the game. That didn’t mean that I didn’t need to revisit those functionalities. When the game became serious enough about rendering a lot of stuff on the screen at once, I needed to review and optimize those functions. One example is that at first, I have the naive way of doing it, just render one sprite at the time. Later on, I needed to optimize to batch together entities that have the same sprite so I don’t switch the OpenGL textures that much.

Files

  • war1-win64.zip 2.3 MB
    Sep 17, 2019
  • war1-win32.zip 2.3 MB
    Sep 17, 2019
Download War 1
Leave a comment