Lua Gui's Take 2
Lets Try Again
A few months ago I started making a Lua based GUI system. It was going well until life happened. This last week I attempted to add more features to it so I could use it in my Halloween contest entry. Knowing more lua now than I did then I realized how much of a mess it was. I scrapped the gui completely and started over. The following is some technical changes and observations I made as I rewrote it. Hopefully someone on the internet finds it insightful.
The first thing I tackled was the way the window manager handled windows. Previously, the window manager held all the windows and dealt with the window Z order. When moving a window, the old system told which window was on top and and allowed the window to move itself. Now I have the window manager handle moving the window and added the ability to for a window to know if it is focused, and a send window bottom function so if a person is using the top window a new window wouldn't take over.
Another change that was of high importance was how objects were selected. Before all objects were bounding boxes, all objects were square, this limited what could be created with the gui. In it's place all square objects generate a 2d convex polygon and the polygon is used for selection. This change was important because it now allows users to pass polygons for buttons and the gui system will automatically adjust to it. Still to be done is a 2d polygon fill algorithm (I'm wondrously bad at math).
The biggest change was done the last 2 days. I created a text placement system. It has alot of features and a few more to come. The placement system will place text in a bounding box at a location you specify. It will also line wrap, though it doesn't do a word wrap (I'll get to it one of these days...maybe). I also implemented an inline markup system. So far it supports 2 commands:
##color:r:g:b## ##linebreak##
There is a ##fontsize:size## command but I have not finished adding the required font handling system. The user can write a string "This Will Show##linebreak##On 3 lines##linebreak####color:255:0:0##This text is Red", and it will draw it in 3 lines and change the color on the last line. You can also change color mid letter.
Performance and Optimizations:
The old system was hella fast, despite it being held together by duct tape. This one at first was on the slow side. The window movement was slow but I discovered that was due to the window manager looking every update for which window was on top, if it was focused, and if the mouse was down. This was optimized my allowing it to make the assumption that if a window is focused, check to see if it's isbeingdragged property is true and if so continue with the mouse move. The old system the window took control of it'self and released control when it was done.
The text placement engine almost made me punch my monitor. I stared so long at this code I thought I was mad. At first it drew every letter one by one to make sure the color feature worked properly (sudden color changes mid-word) but that was such a performance hit it couldn't be ignored. It could take a game running at 60fps vsync on and bring it down to 30fps. The change that I made was to buffer all the text into a string and blast it out at the end of a line. If there was a color change, I would write all changes to the screen, and start a new string buffer with the new color. This brought the fps back to almost 60fps with windows being displayed in a 3d scene.
Next thing that I will implement are buttons and from there I will implement clickable objects that don't require text input.
For the Curious
The Gui System is made of 3 parts. the window manager, the window, and what you put in the window. so it would be
Window Manager(contains a collection of) - > Windows (containt a collection of) - > objects (which can contain other objects)
To use the gui system you would use the code:
function Script:Start()
self.gui = require "/scripts/gui/simplegui" -- load the gui script
self.winman = self.gui.windowmanager() -- create the window manager
self.testwindow = self.gui.window() -- create a window
self.winman.addwindow(self.testwindow) -- add window to the window manager
end
function Script:PostRender(context)
self.winman.process() -- this can go into update world if you want
self.winman.render() -- draws everything
end
This code would better be served if it was used in the app.lua so you have one window manager that will survive level loads (useful if you have create a console window or a debug panel).
No fancy animated image this time. The button doesn't work yet and the newest creation is the colored text to the left. The top 2 windows are transparent.
Well enough of my rambling. It's late, I've spent all day doing laundry, no sleep, and i need to be at work in 5 hours.
- 2
0 Comments
Recommended Comments
There are no comments to display.