Skip to content

add bar healthbars.#5399

Draft
amnykon wants to merge 45 commits into
ZeroK-RTS:masterfrom
amnykon:BarHealthbars
Draft

add bar healthbars.#5399
amnykon wants to merge 45 commits into
ZeroK-RTS:masterfrom
amnykon:BarHealthbars

Conversation

@amnykon

@amnykon amnykon commented Dec 15, 2024

Copy link
Copy Markdown
Contributor

This PR is mainly to create discussion on the future of Zero-k healthbars.

#extension GL_ARB_uniform_buffer_object : require
#extension GL_ARB_shading_language_420pack: require

// This shader is (c) Beherith ([email protected])

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be a killer is using the shaders.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beherith said he would release his shaders as MIT and there's beyond-all-reason/Beyond-All-Reason#3568 but it was somewhat ignored.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. So it's a question if we want MIT shaders. I think just add the MIT headers to the files and asking Beherith to approve the PR, which would give us his consent to use it under MIT. Since the file doesn't currently have these licenses, it could be argued that they are not released under the license.

@GoogleFrog GoogleFrog Dec 16, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the license at this moment in time:

// This file is going to be licensed under some sort of GPL-compatible license, but authors are dragging
// their feet. Avoid copying for now (unless this header rots for years on end), and check back later.
// See https://github.com/ZeroK-RTS/Zero-K/issues/5328

I don't want to put anything that looks more like an actual license here until the BAR issue is resolved with an actual license.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From Beherith "I choose MIT. Thank you for your input."
IMO the best option is to simply ask Beherith. @sprunk since your working with him with licencing for BAR, can you ask him?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll raise the topic at the next bar contributor meeting.
which should be on the second of January 2025
if not it will be the next thursday.

@amnykon amnykon Jan 5, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@drivver44 how did the topic on the bar contributors meeting go?

Sprunk also brought up licensing for the artwork. Currently I am recreating it other than the font. Are there any licensing issues of using the fonts in the health bar image?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently the meeting was moved to 01-09.

@amnykon

amnykon commented Dec 16, 2024

Copy link
Copy Markdown
Contributor Author

I am starting to understand this I need a lot more time. I have no background on GL shaders, so this is new to me.
How do we profile this to compare it with jK healthbars? I would assume bar healthbars would run faster as the rendering should be parallelized on the gpu.

@sprunk

sprunk commented Dec 16, 2024

Copy link
Copy Markdown
Member

There is some sort of "Widget Profiler" widget available via Alt+F11, it is vrey flawed though. The shader approach may be an order of magnitude faster and visible there anyway, hard to tell.

For proper, accurate profiling there's Tracy https://beyond-all-reason.github.io/spring/development/profiling-with-tracy but that one requires adding tracy scope points all over gameside code (it's free perf-wise in non-tracy engine builds but clutters up the code a bit) which looks like this https://github.com/search?q=repo%3Abeyond-all-reason%2FBeyond-All-Reason%20tracy&type=code

@GoogleFrog

Copy link
Copy Markdown
Contributor

Tracy is a good subproject, one that probably wants to be done before any large profiling efforts. I didn't know it required manual scoping though, that sounds like a lot of legwork. So perfect for a PR.

On GL4 healthbars, I think we can safely assume that they are much faster than jK bars. The tricky part will be using the tech to make something that fits ZK.

@amnykon

amnykon commented Dec 17, 2024

Copy link
Copy Markdown
Contributor Author

Editing the lua should be easy. Just copy the kj "getters" into the bar health bars, though it does handle them differently, keeping track of the status, similarly to how we do morph. I was thinking of doing something similar so units that are no longer in Los can have outdated health bars. That is a separate feature.

@amnykon

amnykon commented Dec 17, 2024

Copy link
Copy Markdown
Contributor Author

@GoogleFrog Do you want me to work towards replacing the jk health bars and experimental gui_healthbars with bar healthbars?

@GoogleFrog

Copy link
Copy Markdown
Contributor

Yes, that would be good. The existing widget shouldn't be touched, unless perhaps you want to make a shared config file that controls both widgets. We'll probably want to use the existing widget as a shaderless fallback. The unused shader widget looks removable.

@amnykon

amnykon commented Dec 19, 2024

Copy link
Copy Markdown
Contributor Author

Data is passed to to the shaders using struct SUniformsBuffer{...vec4[4] userDefined;}. What I understand, each unit receives their own SUniformsBuffer, meaning we can only pass 17 data points (4 for each vec4 + health which is passed in a different field of the buffer).
currently we have 22 bars, so we need to share some channels. This is what I propose:
(*) health (different field in the buffer)
(0) morph, reclaim
(1) building, resurrect
(2) paralyze
(3) disarm
(4) slow
(5) reload
(6) dgun (currently dgun and reload are the same. I want to separate them.)
(7) teleport, heat, speed, reammo, jump, goo, capture_reload, ability, stockpile, capture_reload, shield
(8) teleport_pw?
(9) capture
(don't import) water_tank
Any issues with using the proposed channels? I overloaded slot 7 with unit specific bar, which I believe no unit shares. Any known collisions (current or future) with this proposal?
I may swap the numbers around and what gets paired with reclaim/resurrect.

@sprunk

sprunk commented Dec 19, 2024

Copy link
Copy Markdown
Member

Some notes:

  • campaign commander can have jump and shield at the same time IIRC.
  • modders can add any combination from channel 7 (up to all of them)
    • Perhaps fallback to old style bars when this is the case?
    • Could reserve say 2-3 bars and draw the first 2-3 found abilities, though see below
    • Or ask engine to provide more room.
  • remember some channels will need to be reserved for migrating various other rendering to GL4:
    • whether a unit is selected (for selection shapes)
    • cloak shader
    • construction shader?
    • tint, glow?
    • others?

@amnykon

amnykon commented Dec 19, 2024

Copy link
Copy Markdown
Contributor Author

I didn't realize that the uniform was shared between all shaders. That makes things much harder. If this is the case, I feel we should have a widget that caches and updates the uniform for all unit status. Other widgets can read the cache directly (for non shaders) or relay on the widget to update the uniform for their shaders. Once I get all the bars working, I can split this widget.
Current working bars: health, shields, paralyze (percent and duration both work).

@GoogleFrog

Copy link
Copy Markdown
Contributor

Perhaps what we need is a uniform that tells the shader which bars are being drawn (via a bitmask?), and then four or five uniforms that contain the data to draw in each case.

@amnykon

amnykon commented Dec 20, 2024

Copy link
Copy Markdown
Contributor Author

I think we can wait until we are closer to running out of channels before we resort to a bitmap of what the values are. We are using just over half. I think other shaders will need the status provided anyway. Most of the other shaders Sprung mentioned can easily use the status provided by the bar, or overload one already in use. If we want to flash bars based on unit selection and command, that info will also need to be sent.

@amnykon

amnykon commented Dec 20, 2024

Copy link
Copy Markdown
Contributor Author

Connected more bars. The remaining bars to connect are: Morph, Reload, Dgun, Teleport, Ability, Stockpile.

@GoogleFrog

Copy link
Copy Markdown
Contributor

I've been thinking there should be a stable before Christmas, but after the tournament tomorrow. This PR is too large and late to get into that stable, but I should be able to look at it shortly after. We will want some sort of solid handling of which healthbars are enabled. Eg, setting the default to be disabled for the old bars won't disable them for existing players.

I think there should be a setting for which bar the player wants enabled, and a fallback that enables the old bars if the player has insufficient shader support. The new setting should be a strong enough source of truth to disable the old bars for existing players.

@amnykon

amnykon commented Dec 21, 2024

Copy link
Copy Markdown
Contributor Author

I agree, this is too large to be ready in a few days.

I do plan on adding a bar style selection option. When I do this, I plan on making a plain shader less option. With this option, we can remove the jk bar widget.

I have grand plans for the bars. The difficulty is deciding what is mvp.

MVP IMO:

  • Connect all bars.Remaining:
    • Morph (done just not commited)
    • Reload
    • Dgun
    • Teleport
    • Ability
    • Stockpile.
  • some options
    • style
      • basic bars (shaderless)
      • bars (current shaders)
    • size/position
    • when to hide
  • artwork or at least color for all bars so you can tell them apart.
  • Bug fixes
    • 100% text is drawn as 0%
    • 0% shows a bar the size of both round corners. (Probably just hide the bar for mvp, and deal with it later)
  • Resolve shader licences or rewrite them.

So there is still a lot to work on before this is ready.

@amnykon amnykon marked this pull request as draft August 3, 2025 01:48
amnykon and others added 20 commits June 14, 2026 15:55
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
# Conflicts:
#	LuaUI/Widgets/unit_healthbars.lua
#	units/tele_beacon.lua
- Add feature channel constants to gl_uniform_channels.lua
- Migrate all unit uniform updates (reload, dgun, ability, teleport, heat,
  speed, reammo, goo, jump, captureReload, shield, stockpile) to updater
- Fix stale unitUniform values by zeroing before each update; write in two
  blocks to preserve channel 10 (morph) managed separately
- Fix undefined gameSpeed, paralyzeOnMaxHealth, myAllyTeamID in updater
- Fix typo in removeUnit (postion -> position)
- Fix feature barTypeMap to use featureHealthChannel/Reclaim/Resurrect
- Fix stockpile uniformindex (unitStockpileChannel -> unitStockpileProgressChannel)
- Fix widget:Shutdown morph deregister (was passing undefined MorphFinished/MorphStop)
- Remove all watch tables and GameFrame update code from gui_healthbars_gl4

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
- gui_healthbars_gl4 fans MorphUpdate/Start/Stop out to WG.MorphUpdateCallbacks,
  WG.MorphStartCallbacks, WG.MorphStopCallbacks tables instead of handling
  uniforms directly; retains VBO add/remove
- unit_gl_uniform_updater registers for MorphUpdate/Stop to maintain
  unitMorphProgress per unit, written as channel 10 in updateUnit
- Collapse back to single unitUniform write now that morph channel is owned here

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Replace the weapon_class -> representative-icon mapping with a per-weapon
`icon` customParam (image path), registered on demand. Badges with no icon
draw just the countdown ring. Populate icon across unit + modular comm
weapon defs (slow weapons -> slowbeam). Dynamic comms now show both
weapon slots (comm_weapon_id_1/_2), each with its own icon and countdown.
Also fix morph badge centering to count only visible below-badges.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GqE6GMGoMD893v6jwAE8JA
…Band=0.05

Remove the ignoreDepth option and hardcode the shader's overlayDepthBand
uniform to 0.05 so overlays are always squeezed into the near-plane depth
sliver and win the depth test against world geometry (factories, build
plates, air pads). Overlays still depth-write, so they sort correctly
among themselves.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Claude-Session: https://claude.ai/code/session_01FdHcCjZPUrZRgPfDCyECiA
…uge, row gap)

- Item 1: center unit icon turns white when unit is selected (bit 23 of userDefined[0][2])
- Item 2: add statusFadeDistance option — hides status/state row icons beyond that distance (0=never)
- Item 3: add iconHideDistance option — hides center unit icon closer than that distance (0=never)
- Item 4: fix Picket burst gauge: was dividing absolute reload frame by duration; now computes
  remaining frames correctly so gauge fills from 0% (just fired) to 100% (ready)
- Item 5: omit ROW_GAP between bars and status/state row when there are no bars

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Claude-Session: https://claude.ai/code/session_01FdHcCjZPUrZRgPfDCyECiA
When VisibleUnitRemoved fired, removeBarsFromUnit cleared the health/ability
bar VBO instances but left the icon-cluster instances (_wgicon_*) and the
per-unit state tables (wgUnitIcons, wgUnitGroup, wgUnitCommand) intact.

If the engine recycled that unitID for a new unit before the next DrawWorld
relayout ran, the orphaned VBO instance -- position-bound to unitID via
InstanceDataFromUnitIDs -- would immediately track the new unit's position,
producing a second, wrong-type icon hovering over it.

Fix: call onUnitIconHolderReset (pops icon VBO instances), then clear all
four per-unit state tables and remove the unit from wgDirtyUnits so no
deferred relayout fires on a now-dead ID.

Co-Authored-By: Claude <[email protected]>
Carry per-unit status-effect magnitudes (slow/disarm/paralyze/build) from
the VS to the FS via v_uvoffsets -> the new g_effect varying, populated only
for the center unit icon. Apply the first effect: a magenta slow wash on the
icon, echoing the on-model gfx_paralyze slow tint, so the cue is visible at
radar range where only the icon is drawn.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MryW1fYiSYV7MPN7kg1f2o
Add the disarm cue on the center icon: a desaturated khaki/tan wash driven by
the disarm magnitude already carried in g_effect.y, mirroring the on-model
disarm tone from gfx_paralyze_effect. FS-only change; the data plumbing landed
with the slow effect.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MryW1fYiSYV7MPN7kg1f2o
Add the paralyze/EMP cue on the center icon: a light-blue wash driven by the
paralyze magnitude in g_effect.z, mirroring the on-model EMP base tone from
gfx_paralyze_effect. Tinted slightly harder than slow/disarm so a stunned unit
reads as the dominant state. FS-only change.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MryW1fYiSYV7MPN7kg1f2o
The slow/disarm/paralyze washes stacked and overrode the icon's own colour
(including team shade), risking a muddy, hard-to-read icon at radar range.
Show only the dominant effect (paralyze > disarm > slow) instead of stacking,
tint hue-only by scaling the effect colour with the icon's own luminance so the
silhouette and team brightness survive, and lower the mix strengths. The
bars/badges still carry the precise per-effect state.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MryW1fYiSYV7MPN7kg1f2o
Read cloakTime from the shared per-unit uniform (userDefined[3].x, the slot the
CUS gadget writes and the model shader reads), replicate the cus cloakedness
ramp in the VS, and carry it to the FS via a new v_iconCloak -> g_cloak varying.
The FS fades the center icon's alpha so your own/allied units visibly cloak like
their models do, floored at 0.45 alpha so they stay locatable.

Enemies are excluded for free: the cus encodes enemy cloak as abs(cloakTime) > 1e6,
so gating on abs(cloakTime) < 1e6 never fades an enemy's icon -- no info leak.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MryW1fYiSYV7MPN7kg1f2o
Echo the on-model nanoframe build on the icon: a fill that rises bottom-to-top
by build progress, using the build fraction already plumbed in g_effect.w. The
not-yet-built (upper) part is dimmed rather than erased, with a bright
team-coloured line marking the build front, keeping the icon legible. FS-only;
static (no time term) so it doesn't depend on timeInfo in the fragment stage.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MryW1fYiSYV7MPN7kg1f2o
…ntdown

When a status (paralyze/disarm/slow) is locked at max the horizontal bar used
to flash and swap its percentage readout for a seconds-left countdown. Drop
both: remove the bar flash (extraColor blink) and the printed seconds, so the
bar simply reads 100% (health = min(1, value)) while locked. The top-band
radial timer badge, a visual pie rather than a printed number, is unchanged.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MryW1fYiSYV7MPN7kg1f2o
Paralyze and disarm are binary states -- a unit isn't disabled while the effect
is merely charging, only once it crosses the threshold (gfx_paralyze keys these
off utGetIsUnitEmped / disarmed==1, both boolean). Gate the icon's paralyze and
disarm tints to the locked encoding (value > 1) so a charging-but-functional
unit isn't mislabelled. Slow stays continuous, since a partially slowed unit
really is slowed.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MryW1fYiSYV7MPN7kg1f2o
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants