owned this note
owned this note
Published
Linked with GitHub
# Sneak peek into macroquad 0.4
Reflection on 0.3 API problems and some thoughts about macroquad 0.4 design.
# Rendering
Right now macroquad's drawing API looks like this.
![image](https://user-images.githubusercontent.com/910977/137642171-ef34ca58-3368-4487-b5ba-75859ebdf9e2.png)
[examples/basic_shapes.rs](https://github.com/not-fl3/macroquad/blob/master/examples/basic_shapes.rs
)
Main loop with lots of `draw_*` calls. It is safe to assume that each `draw_*`` call immidiately draw things on the screen.
What actually happens here is "dynamic batching".
There is a "current batch" - a fixed sized vertex/index array + material + texture.
Each `draw_*` call will check
- there is still room in the array
- current active material is the same with the "current batch"
- texture, uniforms or anything else gpu-related is the same with the "current batch"
If all the checks pass, vertices/indices will be added into a "current batch" array.
If not - "current batch" data will be uploaded to the GPU and rendered to the screen, and the new batch will start.
There are some helpers and optimisations on top of that, like it is possible to build texture atlas on runtime to prevent batch breaking. Also it is possible to "flush" current batch, draw everything to a screen and give raw miniquad context to a plugin - it helps with things like particles.
It works good enough for 2D games. For a 2-3 thousands sprites it will be just a few draw calls for a frame, which is usually good enough.
## Problems with batching
But dynamic and always on batching is very, very far from an ultimate rendering technique. Things starts to fall apart with introducing 3D.
In 3D objects may have more than 2 triangles and 1 texture. Also it is very common for individual objects in 3d to have their own individual materials, uniforms etc.
Think about an animated and skinned high-poly character. Trying to batch it with the background will not make any sense, never.
This naturally gives a requirement - it should be easy to draw objects without any batching on.
Another thing - sometimes it would be nice to do a batching just once, and than use batched mesh forever. Think about a static level background. It doesnt change too often and consists of lots of individual parts. Dynamic batching helps here, but "static" batching will be way more efficient - batch all little tiles into one mesh ones and than just use this mesh.
This is possible with 0.3 macroquad (Zemeroth is doing exactly this for level backgrounds), but it requires lots of manual manipulations.
## Problems with the API
![](https://i.imgur.com/4GygzA2.png)
`draw_*` originally came from Raylib. Back than macroquad did not had a `math` module, and all the functions had `x: f32, y: f32` instead of `pos: Vec2` arguments.
But "(x, y)" vs "Vec2" is not the worst problem. The worst one - is the `draw_*_ex` functions. They have some arguments as a normal funciton arguments, and some - as a `Draw*Params` struct memebers.
It looks like a mess, api discoverability suffers and lots of code got dublicated. For example, there is `draw_rectangle` function. And `draw_texture` function. Isn't a texture just a textured rectangle? And why there is no way to apply texture to a circle?
It would be nice to draw any primitive with any params and any batching mode.
Something like "draw a square with given size and texture, batched with previous squares".
## 0.4 vision
![](https://i.imgur.com/wX2CmlL.gif)
*test game, utilising new rendering API proposal*
[src](https://github.com/not-fl3/macroquad/blob/0.4_experiment/examples/gltf.rs)
![](https://i.imgur.com/zpFS9qa.png)
This is very, very, very work in progress code.
But the idea here - current "dynamic batcher" is still available, but optional. During a frame there may be lots of them. Not all of them may be updated each frame.
Each draw call utilise a builder API. All the objects used for draw calls are stateless (no GPU buffers allocated, just some data). Those thin objects may be batched with a dynamic batcher, may be allocated on a GPU to be turned into a "Model" for later use as individual drawing primitive.
# Scenes and all the macroquad::experimental
What to do here is still unsolved question. There is a thing I want to try and see if it will work:
Make a "scene graph" in macroquad. It will be a low level rendering thing, not architectural thing. You add a model to a "scene", got a handle, and is free to do whatever with this handle later. Same with sprite layers and everything from the previous chapter.
So, the "scene" will be a rendering primitive, about lights, models, occlusion etc.
And macroquad will not have anything about main loop organisation. Coroutines, "ecs" and so on will just move to another, even more optional crate.
Wasm "no-blocking" problem is still with us, tho. So I am not sure if it will work out great. But, worth a try!
# Compatibility with 0.3
0.4 is going to be quite different from 0.3, no doubts about it. But, to keep compatiblity - I am thinking on implementing an old, 0.3-style API on top of macroquad 0.4. Maybe even extend it to encapsulate more raylib features.
0.3 examples and projects should be able to run on 0.4 with maybe some minor changes.
# When?!
Well, I do not really know. I am thinking about all those things quite a lot, but I am not particullary good in making macroquad features without backporting it from some game. So, probably, I'll either start using 0.4 in the fish game, or will finish the fish story and will do some other game on 0.4, finishing it along the way.
The WIP branch will (and, actually, is: "0.4-experiment") available on GitHub. But cant promising anything on its stability anytime soon.