Restructure repository and introduce json format for scenes
2023-04-06
Today I took some time to do some prep work for testability and restructure the repository to allow for demo apps and debug tools. The idea is to introduce a scene struct which contains all of the renderable primitives that we can currently draw and make it serializable from json. Then we can write tests that specify a scene in this json format as well as an expected image. If the rendering changes, we can either show them side by side or compute a diff image highlighting the changes.
Cargo Workspace
Step one was to restructure things so that the renderer is a
library crate rather than a binary executable and to
introduce a scene_renderer
crate which depends on the
renderer. The plan is to make it so that the api exposed by
the renderer is sufficient to power both Neovide eventually
and whatever test executables there might be.
In the past, Neovide has been an exclusively single crate project with some dependent crates in subfolders for things like proc macros. This works for a while, but has draw backs in terms of compile time and organization. Its hard to test components individually when structure in this way and when you make a change, often the entire crate needs to be recompiled.
Cargo has a solution for this in the form of workspaces which let you define multiple crate with some shared configuration and which all get compiled to the same target directory.
With this migration completed, I now have the shader
crate
which compiles rust code to spirv, the renderer
crate
which exposes the Renderer
struct in charge of managing
all of the shader and gpu specific code with a high level 2d
graphics interface, and the scene_renderer
crate which
uses the Renderer
to draw scenes
from file. Eventually I
think its possible more sub crates will be introduced and or
this pattern will get ported to Neovide once the crate is
more stable.
Scene Watcher
I introduced a simple Scene
struct containing some details
about the window and fonts and a list of primitives. Right
now this is just the Quads
, Glyphs
, and Texts
that I
support so far, but eventually this will likely include all
of the details we support such as layers with clipping
boundaries and blurred backgrounds as well as more complex
paths such as that of the cursor.
The only really interesting thing here is the utilization of
serde's default field constructors which specify a function
to fill if the json doesn't have the relevant field. With
this in place I added a draw_scene
function to the Renderer
which takes one of these scene objects and calls the
relevant add_*
function for each element.
From there I used the notify
crate to watch a json file in
the root of the repository containing one of these
serialized scenes. When the file changes, I read from the
file and trigger a redraw of the window with the updated
scene contents.
let event_loop = new;
let scene: = Default default;
let scene_path = from;
read_scene;
let mut watcher = recommended_watcher
.expect;
watcher
.watch
.unwrap;
This lets me edit the scene dynamically from my text editor and see changes live for debugging purposes. And as I mentioned earlier, this same system could power automated testing that specifies exactly what we expect each scene should look like.
The work here wasn't necessary to make progress, but helps me to have confidence in the work so far. I'm hopeful it can be used to test apps like neovide in the future as well.
With this work out of the way, I'm more confident I can get a better idea of whats going wrong with the text shaping. Once that's out of the way, I hope to add scissor based clipping and blurred background layers which is the last hard requirement before I can start integrating this work into Neovide.
Till tomorrow,
Kaylee