Merge: gamnit: control drawing order
authorJean Privat <jean@pryen.org>
Mon, 17 Jul 2017 13:53:30 +0000 (09:53 -0400)
committerJean Privat <jean@pryen.org>
Mon, 17 Jul 2017 13:53:30 +0000 (09:53 -0400)
commitb10b8ce8d187990c8ce20cde3be8c47230204d1a
tree1f095999da269ff4ac77893e03fdf6db510fcc95
parentfee2088a7811beea29f0d1c33c836561b5368a20
parent524a0d87a641e146263d4078eba732a4da69d4d7
Merge: gamnit: control drawing order

When two sprites are overlapped, a non-opaque pixel drawn before the sprite behind it may be blended with the wrong color. The only solution is to control the draw order to ensure that sprites in the back are drawn first. However, this is hard to automate when grouping sprites in buffers to optimize the drawing of a very large number of sprites (as gamnit does). It requires to break off groups in layers and this may be very costly if the sprites move on the Z axis.

The solution it to let the programmer choose a draw order only when needed. This works pretty well in 2D games where some objects stay on the same relative depth layer.

> Example artifacts on the left, and the fixed result (with a `sprite.draw_order = 1`) on the right:
>
> ![bug1](https://user-images.githubusercontent.com/208057/28196073-3e0ec6fc-681c-11e7-98d0-019e25a7f9c3.png) ![fixed1](https://user-images.githubusercontent.com/208057/28196072-3dfe075e-681c-11e7-9f4d-8d08a45b9661.png)

This PR introduces the attribute `Sprite::draw_order` that can be set to a higher value (default at 0) for the sprite to be drawn later. In general, sprites with a non-opaque `texture` and sprites closer to the camera should have a higher value to be drawn last.

Sprites sharing a `draw_order` are drawn in the same pass. The sprite to sprite draw order is undefined and may change when adding and removing sprites, or changing their attributes. A future improvement could sort sprites in the same group automatically if it becomes an issue.

Note that changing the `draw_order` may have a negative performance impact if there are many different `draw_order` values across many sprites. This may break the grouping optimization by creating too many small groups.

---

I plan on adding the draw order to `gamnit::depth` actors too. This will be useful for games than mix 2D with 3D. However, I would have to apply a different strategy for pure 3D games, implementing two main passes, one for opaque objects and one for non-opaque objects.

Pull-Request: #2526
Reviewed-by: Jean Privat <jean@pryen.org>