Non-Linear Undo/Redo, Graphics Engine, UI Library, and Roadmap
August 25, 2022
Hello everyone!
First of all, thank you so much for your patience since the last news. We're really sorry to have kept you in the dark for so long, especially now that the deadline of July 2022 (as mentioned during the Kickstarter campaign) has passed. So far, we've been mostly working on the backend technology (things that are not directly visible in the user interface), and we wanted to have at least some very minimal visible change before sharing anything.
And this time has finally come!
Non-Linear Undo/Redo
We've finished to design and implement a generic architecture that allows us to undo and redo user actions with great performance.
In VPaint, for each user action, a copy of the whole illustration is made, and undo/redo simply replaces the current illustration by another illustration previously stored. This was easy to implement but unfortunately it is quite slow and takes a lot of memory. It clearly doesn't work for complex illustrations. In VGC, instead of storing a whole copy of the illustration per user action, we only store a description of the action, with just enough data to be able to perform the reverse operation. This is much faster and takes much less memory.
Also, in VPaint (and most applications), the stored history is "linear": this means that after doing a few undos, if you draw a new stroke, then all the previous redos are lost.
In VGC, we are instead storing the history as a "tree" (also called "non-linear history"): this means that after doing a few undos, if you draw a new stroke, then it creates a new branch in your document history, without erasing the previous redos. This way, you can never lose data (unless of course you reach the undo limit).
It's exactly like in movies involving time travel: if you go back in time and change the past, what should happen? In VPaint, the previous timeline is lost forever. In VGC, it creates an alternate parallel timeline, and you can go back anytime to the previous timeline if desired.
This whole system is already implemented, except for one (important) thing: we haven't yet developed the user interface to be able to actually go back to a previous timeline. A full "tree history view" will take some time to implement and is not top-priority, but it should soon be possible to at least do "Ctrl + Alt + Z" to cycle between alternate timelines.
Graphics Engine and UI Library
As a drawing application, it is obviously important to provide a great drawing experience. In particular, we want to reduce as much as possible the "drawing latency": the lag between the mouse cursor and the sketched stroke. Unfortunately, Qt (the user interface library we're using) is making optimizing this a bit difficult.
Currently, everything you see in VPaint and VGC is drawn using OpenGL. We draw the main canvas and some UI elements using our own custom OpenGL calls, Qt draws its own widgets using OpenGL, and finally Qt performs a compositing pass to combine all of this together.
The problem is that because Qt is in charge of orchestrating this, we don't have full control of the rendering loop, which makes it impossible to apply some optimizations needed to reduce the drawing latency. Also, by using OpenGL, we could never get performances as good as using Direct3D in Windows, Metal in macOS, or Vulkan wherever supported.
For these reasons (and others), we have been slowly transitioning away from the QtWidgets
module of Qt, and instead only rely on QtGui
which gives us more control (eventually, we may also want to get away from QtGui
, but not in the near future). We are now very close to finishing this transition. Importantly, we now have a new graphics engine supporting both OpenGL and Direct3D (version 11).
Using Direct3D makes performance much better on Windows, especially noticeable with older hardware: resizing the application window is much smoother, and there is less mouse lag. All of this has been tested in the prototype below, which only uses QtGui
(not QtWidgets
) and our new engine:
Unfortunately, we cannot yet use Direct3D in VGC Illustration as long as we are still using widgets from QtWidgets
, so we are in the process of replacing them.
The first re-usable widget that we implemented is basically the most complicated: a "line edit" (a text area where users can type text). It is now fully functional and its first use in VGC Illustration is to manually select RGB values below the color selector:
Implementing a line edit isn't easy, not only because rendering text is complicated, but also because the user interaction itself is not trivial:
- Clicking with the mouse should place a cursor at the correct text position.
- Click-and-drag should select a portion of the text.
- Double-clicking should select a word.
- Triple-clicking should select the whole line.
- Double-click-and-drag should select from word to word.
- Left/right arrows should move the cursor.
- Shift + left/right arrow should move the cursor from word to word.
- If the text is longer than the line edit, the text should be clipped/cropped to avoid overflowing.
- The text should be automatically scrolled horizontally to ensure that the cursor is always visible.
- The Delete key should delete the next character...
- ...unless there is a non-empty selection, in which case the Delete key should delete the selection.
- The cursor should only be visible if the line edit has the "keyboard focus".
- If the line edit loses the keyboard focus (typically, because the user clicked somewhere else), then the selection should be cleared...
- ...unless the reason the focus was lost is because another window became active or the user is using the menu bar, in which case the selection should be preserved.
- The line edit should support copy-pasting from within the line edit, other line edits, or other applications via keyboard shortcuts (Ctrl+C / Ctrl+X / Ctrl+V).
- On Linux, copy-pasting should be possible with the mouse middle-button.
- Ctrl+A should select the whole line edit.
- The Esc key should release the keyboard focus.
- Some line edits should restrict what characters are allowed to be entered (e.g., integers in the 0-255 range for RGB values).
- The line edits should be connected to other elements of the interface (e.g., modifying the RGB values should update the selected color, and changing the selected color should update the RGB values).
- And a few other subtleties.
It basically requires to support most types of mouse and keyboard interactions possible in a user interface, so it's a great test of our architecture. In addition to the line edit, we are nearly finished implementing a layout system similar to modern HTML/CSS practices (flexbox and grid layout) to nicely arrange the different UI elements with margins/padding/gaps and make them "responsive" (stretch the widgets when there is space, shrink them when there isn't). We have also a working CSS-like engine to be able to specify all the colors/margins/etc via a stylesheet, which could be easily customizable by users to create different themes.
However, in order to get rid of QtWidgets
, we still need to implement the following building blocks:
- A menu bar
- A color palette as complete as the one provided by Qt
- A way to let users create and resize toolbars / panels on the side of the application
- And finally port the current canvas to our new engine
This should take a few weeks, then we will progressively implement and add other widgets (tool buttons, sliders, check boxes, combo boxes, etc.).
Note that we will temporarily remove the Python Console, which isn't very useful currently anyway, and we will add it back once we implement a minimal multi-line text editor (our current line edit only supports one line of text).
Roadmap
You're probably all wondering: when will you be able to actually use VGC Illustration?
We are planning to release a first usable version of VGC Illustration in around 3 months (i.e., around the end of 2022). By "usable", we mean the following top-priority features:
- Undo-redo
- Color selector and color palette
- Sketch tool with control of stroke width and smoothness
- Paint bucket
- Shared endpoints between strokes
- Shared boundaries between painted regions
- Enable/disable snapping nearby endpoints
- Enable/disable creating vertices at stroke intersections
- Selection tool to move things around
- Basic sculpting tools
- Topological operators to manually glue / cut / split / delete things
- Change depth-ordering of objects
- Copy-paste
- Basic layers (no compositing)
- PNG export
Other features will come just after, with the following tentative order of priority:
- Various cap-style / join-style
- Linear, circular, radial gradients
- Grouping
- Import-export to SVG
- Python console
- Python plugin system
- Basic shapes (rectangles, ellipses, etc.)
- Alignment tools
- Text tools
- Direct control of Bézier control points
- Color management (color profiles, CMYK support, 8bit/16bit/32bit per channel)
- Layer compositing
- Masking and clipping
- Blur
- Brush system
- Textures / patterns
- Object clones
With all these features coming soon, we'll make more effort to keep you updated on the progress. Don't forget that if you have contributed to the Kickstarter campaign or are (or have been) a Patreon supporter, you can download the alpha versions in your VGC dashboard. These versions are continuously released (sometimes several times a day) as we commit changes to the source code. Contact us at support@vgc.io if you've lost your account login/password or have any issue downloading or installing/launching the alpha versions.
Thank you again everyone for your patience and support!
Stay tuned
Found this news interesting? We can send the next ones straight to your inbox (around twice a month). Or we can simply let you know when VGC 1.0 is released. No spam guaranteed. You can unsubscribe at any time.