Week 21/2013: Rich text and the Log widget
Last week I was hard at work on the new GUI widgets for the next-gen engine UI.
After putting together a basic text editor based on the already existing logic in the Shell's UI, my main focus for the week has been on handling the log message history widget. It is more complicated than one might think at first: the engine may be producing hundreds of messages per second, and once received, a message has to go through the appropriate preprocessing to be suitably formatted and prepared for OpenGL rendering. Furthermore, a message may need to be wrapped onto multiple lines, and it may use a variety of different fonts and styles. The widget then also needs to be worry about not using too many OpenGL resources at once, as there's no point in keeping thousands of old messages in memory.
During the week it turned out that a major stumbling block was the performance of the rich text rendering and line wrapping routines. While Qt provides this kind of functionality, so far I've been relying on my own set of routines to have complete control of how the text is laid out:
Particularly I've been paying close attention to how lines are wrapped and how much indentation is applied to subsequent lines. Compared to the old console drawer, the major differences in the above screenshot are: 1) the font is variable-width instead of fixed-width, 2) the text style (font, color, size) can change at any point on the line, 3) indentation markers can be used to align content to specific points on previous lines, 4) messages can span more than one line, and 5) the content is rendered onto an atlas texture where it can be quickly and efficiently drawn on screen.
The performance issues with the rich text can be solved in several ways, but I've been keen to try out the new TaskPool mechanism introduced recently in libdeng2: having a set of background threads preparing incoming entries. It is turning out to be quite tricky to get the whole mechanism running fluidly and robustly. I will continue along this track for a while, but fully optimizing the new UI widgets is not a high priority for 1.11 — instead, I'm targeting a complete set of basic widgets so we can throw away the old in-game console.
There are about a 100 commits in the "ui-framework" branch waiting to be merged back to the master. As the candidate phase for 1.11 is approaching, I need to start working towards a merge. However, before that I need to set up the widgets with enough functionality to actually serve as a functional replacement for the old in-game console.
After putting together a basic text editor based on the already existing logic in the Shell's UI, my main focus for the week has been on handling the log message history widget. It is more complicated than one might think at first: the engine may be producing hundreds of messages per second, and once received, a message has to go through the appropriate preprocessing to be suitably formatted and prepared for OpenGL rendering. Furthermore, a message may need to be wrapped onto multiple lines, and it may use a variety of different fonts and styles. The widget then also needs to be worry about not using too many OpenGL resources at once, as there's no point in keeping thousands of old messages in memory.
During the week it turned out that a major stumbling block was the performance of the rich text rendering and line wrapping routines. While Qt provides this kind of functionality, so far I've been relying on my own set of routines to have complete control of how the text is laid out:
Particularly I've been paying close attention to how lines are wrapped and how much indentation is applied to subsequent lines. Compared to the old console drawer, the major differences in the above screenshot are: 1) the font is variable-width instead of fixed-width, 2) the text style (font, color, size) can change at any point on the line, 3) indentation markers can be used to align content to specific points on previous lines, 4) messages can span more than one line, and 5) the content is rendered onto an atlas texture where it can be quickly and efficiently drawn on screen.
The performance issues with the rich text can be solved in several ways, but I've been keen to try out the new TaskPool mechanism introduced recently in libdeng2: having a set of background threads preparing incoming entries. It is turning out to be quite tricky to get the whole mechanism running fluidly and robustly. I will continue along this track for a while, but fully optimizing the new UI widgets is not a high priority for 1.11 — instead, I'm targeting a complete set of basic widgets so we can throw away the old in-game console.
There are about a 100 commits in the "ui-framework" branch waiting to be merged back to the master. As the candidate phase for 1.11 is approaching, I need to start working towards a merge. However, before that I need to set up the widgets with enough functionality to actually serve as a functional replacement for the old in-game console.