In the last post I wrote down a first draft for the specification for widgets. All nice and fine, but not really pretty. Pretty ugly actually, so there's tons of room for improvement. And there was not much on rendering. So this week I decided to work on ... *drum roll* widget rendering! So here's how it looks like now:
... and the extra config bits are the "MainRenderer" and "MarginRenderer"
So what's different? First, instead of a constant color, we now specify a renderer for margins, and a renderer for the main body. These renderers can be specialized for constant colors, textures, animated textures, and whatever we want. In the examples above, the margins renderer uses a closed door tile from a tilemap for the four margin corners, and a swamp dragon (from the DCSS tilemap) tiled along the sides, rotated properly (my definition of properly, that is). I've intentionally set the margins to be different sizes, to demonstrated that the textures will scale in order to fit properly with minimal distortion.
The texture rects don't have to be square, and that's demonstrated with the other margins, where I use this texture "atlas" composed of two elements: a square corner (highlighted above) and a rectangular "side" tile. Again, the renderer automatically calculates how many times it can fit the texture rect on a margin side with minimal distortion, and maps it appropriately.
The renderers are completely optional of course: no margin renderer specified -> no margins rendered. Also, if margin is 0 on the left, no margin will be rendered on the left (but the rest will).
To make the above happen, I also had to implement some general resource database for the application, storing currently textures, texture atlases and shader effects. The texture atlases are .json files that reference a texture and store a mapping of (name, rectangle). For example, the RGB-lines atlas file is the following:
Shader Rects and useless (for now) optimisations
The game is grid-based. The grids will never be humongous. Therefore, I decided early on, 16 bits are enough to represent a grid cell in the overworld or the dungeon. Hell, even a 16-bit signed integer would do (32768), and on the plus side, negative values allow me to quickly check if a coordinate is invalid. So, I'm using a pair of 16-bit integers as tile coordinates for most grid operations in the engine, with pretty much zero chance for overflow.
Now, with widget rendering, I realized I'll frequently need to pass rotated rectangles in the shader. Easy way: make a 2d rotation matrix and pass it to the shader; problem solved. But hey, that's 4 32-bit floats (matrix) in addition to 4 16-bit integers (rect). That's a bit overkill, no? Well, it is, as suddenly the data footprint grew by 200%, for typically 3 possible rotations: 90, 180 and 270 degrees. Is there a way to express it better? Most likely.
I know I have a sign bits at the end of each of the 4 16-bit integers for a rect which are pretty much unused (WARNING: There might be a scenario where a rect "enters" the viewport from negative coordinates, so I need to keep an eye on that). So, that's 4 bits to pack stuff in! 2 bits can be used to represent the 0,90,180,270 rotations, and two bits can be used to represent flips (horz/vert). That's it! I actually implemented it, so that's what I'm going to be using for the vast majority of tile rendering, as well as GUI margins.
Next to tackle is input handling for widgets, and perhaps if there's time a tilegrid widget, to view for example a few tilesets with a GUI.