I have a widget that does a bit of management of what units are visible at any given time. This is just a few hundred lines of code, that check wether they are truly drawn, and tracks them incrementally.
I would like this widget to implement a few new widget:VisibleUnitAdd, widget:VisibleUnitRemove, etc calls.
Does anyone have a bit of info, or maybe an example of how to do this correctly? As I have a good dozen widget that use these calls instead of repeating a ton of boilerplate code.
How to write a new widget:... callin?
Moderator: Moderators
- Silentwings
- Posts: 3720
- Joined: 25 Oct 2008, 00:23
Re: How to write a new widget:... callin?
Seems like a clean one - https://github.com/spring/spring/commit ... 880d2d4dc2
Or did you mean add it as a "fake" lua-powered callin to the widgethandler without engine interaction?
But from your use case (which I don't completely follow) I wonder if you'd be better off with a callout e.g. Spring.GetVisible(Unit,Feature)s / Spring.(Get,Set)(Unit,Feature)Visibility
Or did you mean add it as a "fake" lua-powered callin to the widgethandler without engine interaction?
But from your use case (which I don't completely follow) I wonder if you'd be better off with a callout e.g. Spring.GetVisible(Unit,Feature)s / Spring.(Get,Set)(Unit,Feature)Visibility
Re: How to write a new widget:... callin?
Thanks Silentwings, that is very good info for a gadget-side engine one. Ive written a similar callin into barspring for AllowUnitCaptureStep() .
But I needed a purely Lua widget-side one: Watch The Fort and Sprung/Sprunk assisted me in this one:
Trigger the callin from a widget:
Handle the callin in another widget:
My use case is the following: for GL4 widgets, especially widgets that draw stuff at units, its best to have a vertex buffer object that always contains the things we need to draw, and is updated incrementally whenever new units enter los/get created or old units die/go out of los.
This way, the widgets dont have to do any work to do occlusion culling ever, its all done GPU side.
This whole new widget callin system was needed to reduce the 100 lines of boilerplate code on each widget which tracked the nasty edge cases of unitgiven, unittaken, the even nastier cases where a zombie unit (no longer alive but not invalid yet) could enter LOS, and all the management of rebuilding the table of valid visible units on PlayerChanged callins.
Using all of this stuff, making a widget that draws something at every single unit with 0 cpu overhead gets simplified to:
Edit: All of this is allowing us single digit LuaUI load even in heavy lategame situations, and most of that goes to UI element rendering :)
With all the bells and whistles enabled, like gpu rendered healthbars, paralyze effects, stenciled LOS and radar ranges, rank icons, AO plates for features, AO plates for units etc.
But I needed a purely Lua widget-side one: Watch The Fort and Sprung/Sprunk assisted me in this one:
Code: Select all
Beyond-All-Reason.sdd\luaui\barwidgets.lua
174: 'LanguageChanged', -- add to list of callins
1639: function widgetHandler:LanguageChanged()
1640: for _, w in ipairs(self.LanguageChangedList) do
1641: w:LanguageChanged()
Trigger the callin from a widget:
Code: Select all
C:\Users\Peti\Documents\My Games\Spring\games\Beyond-All-Reason.sdd\luaui\Widgets\gui_language.lua
54: if Script.LuaUI('LanguageChanged') then
55: Script.LuaUI.LanguageChanged()
Handle the callin in another widget:
Code: Select all
C:\Users\Peti\Documents\My Games\Spring\games\Beyond-All-Reason.sdd\luaui\Widgets\gui_info.lua
1561: function widget:LanguageChanged()
This way, the widgets dont have to do any work to do occlusion culling ever, its all done GPU side.
This whole new widget callin system was needed to reduce the 100 lines of boilerplate code on each widget which tracked the nasty edge cases of unitgiven, unittaken, the even nastier cases where a zombie unit (no longer alive but not invalid yet) could enter LOS, and all the management of rebuilding the table of valid visible units on PlayerChanged callins.
Using all of this stuff, making a widget that draws something at every single unit with 0 cpu overhead gets simplified to:
Code: Select all
function widget:GetInfo()
return {
name = "API Unit Tracker Tester GL4",
desc = "Tracks visibleunitslist",
author = "Beherith",
date = "2022.03.01",
license = "GNU GPL, v2 or later",
layer = -88888888,
enabled = true
}
end
local myvisibleUnits = {} -- table of unitID : unitDefID
local unitTrackerVBO = nil
local unitTrackerShader = nil
local luaShaderDir = "LuaUI/Widgets/Include/"
local texture = "luaui/images/solid.png"
local function initGL4()
local DrawPrimitiveAtUnit = VFS.Include(luaShaderDir.."DrawPrimitiveAtUnit.lua")
local InitDrawPrimitiveAtUnit = DrawPrimitiveAtUnit.InitDrawPrimitiveAtUnit
local shaderConfig = DrawPrimitiveAtUnit.shaderConfig -- MAKE SURE YOU READ THE SHADERCONFIG TABLE in DrawPrimitiveAtUnit.lua
shaderConfig.TRANSPARENCY = 0.5
shaderConfig.ANIMATION = 0
shaderConfig.HEIGHTOFFSET = 3.99
unitTrackerVBO, unitTrackerShader = InitDrawPrimitiveAtUnit(shaderConfig, "unitTrackerTester")
end
function widget:VisibleUnitAdded(unitID, unitDefID, unitTeam)
Spring.Echo("widget:VisibleUnitAdded",unitID, unitDefID, unitTeam)
local teamID = Spring.GetUnitTeam(unitID) or 0
local gf = Spring.GetGameFrame()
myvisibleUnits[unitID] = unitDefID
pushElementInstance(
unitTrackerVBO, -- push into this Instance VBO Table
{
96, 96, 8, 8, -- lengthwidthcornerheight
teamID, -- teamID
12, -- how many trianges should we make (2 = cornerrect)
gf, 0, 0, 0, -- the gameFrame (for animations), and any other parameters one might want to add
0, 1, 0, 1, -- These are our default UV atlas tranformations
0, 0, 0, 0 -- these are just padding zeros, that will get filled in
},
unitID, -- this is the key inside the VBO TAble,
true, -- update existing element
nil, -- noupload, dont use unless you know what you are doing
unitID -- last one should be UNITID?
)
end
function widget:VisibleUnitsChanged(extVisibleUnits, extNumVisibleUnits)
Spring.Echo("widget:VisibleUnitsChanged",extVisibleUnits, extNumVisibleUnits)
clearInstanceTable(unitTrackerVBO)
for unitID, unitDefID in pairs(extVisibleUnits) do
widget:VisibleUnitAdded(unitID, unitDefID, Spring.GetUnitTeam(unitID))
end
end
function widget:VisibleUnitRemoved(unitID)
Spring.Echo("widget:VisibleUnitRemoved",unitID)
if unitTrackerVBO.instanceIDtoIndex[unitID] then
popElementInstance(unitTrackerVBO, unitID)
myvisibleUnits[unitID] = nil
end
end
function widget:DrawWorldPreUnit()
if Spring.IsGUIHidden() then
return
end
if unitTrackerVBO.usedElements > 0 then
gl.Texture(0, texture)
unitTrackerShader:Activate()
unitTrackerShader:SetUniform("iconDistance", 99999) -- pass
unitTrackerShader:SetUniform("addRadius", 0)
gl.DepthTest(true)
gl.DepthMask(false)
unitTrackerVBO.VAO:DrawArrays(GL.POINTS, unitTrackerVBO.usedElements)
unitTrackerShader:Deactivate()
gl.Texture(0, false)
end
end
function widget:Initialize()
initGL4()
end
With all the bells and whistles enabled, like gpu rendered healthbars, paralyze effects, stenciled LOS and radar ranges, rank icons, AO plates for features, AO plates for units etc.