From 6614a6904c261256914811252db3dd903bd97799 Mon Sep 17 00:00:00 2001 From: spencerleemeredith Date: Mon, 29 Jun 2026 17:34:19 -0700 Subject: [PATCH 1/2] fix: topbar stale resource So I just drew the numbers outside the cached texture. In gui_top_bar.lua: I added drawResbarNumbersLive() So what it does it draws the current value, pull and income, and storage directly through the font2:Print() each frame, reusing the existing resbarDrawinfo positions and short() formatter. Also I removed renderResbarText, the scissor block, the r2tHelper.RenderToTexture(uiTex, renderResbarText) call, and the storageScissors pre clear you mentioned in #7644. Then I removed the now unused drawResbarValue, drawResbarPullIncome, drawResbarStorage, and clearFn helpers. The bar fills, glow, and overflow warnings still go through uiTex like before only the four numbers per resource are drawn live. The reason I did it this way was because you said the issue, measured width clear rects don't fully cover the anchor shift cases. So the problem is not really just the clear rect width. It is the text anchor positions shift when switching spectated players or when layout changes. So a perfectly sized clear rect can miss the old digits and drawing live sidesteps the whole cache scissor path. There is nothing to clear because the numbers are never stored. The perf cost is negligible since font2:Print() is already on the draw path. Fixes https://github.com/beyond-all-reason/Beyond-All-Reason/issues/7996 --- luaui/Widgets/gui_top_bar.lua | 193 ++++++++-------------------------- 1 file changed, 46 insertions(+), 147 deletions(-) diff --git a/luaui/Widgets/gui_top_bar.lua b/luaui/Widgets/gui_top_bar.lua index 01c9895bb1f..003c2b3fe6c 100644 --- a/luaui/Widgets/gui_top_bar.lua +++ b/luaui/Widgets/gui_top_bar.lua @@ -201,7 +201,6 @@ local cache = { lastStorageText = { metal = '', energy = '' }, lastWarning = { metal = nil, energy = nil }, lastValueWidth = { metal = -1, energy = -1 }, - lastResbarValueWidth = { metal = 1, energy = 1 }, prevShowButtons = showButtons, } @@ -209,8 +208,6 @@ local cache = { local resourceNames = { 'metal', 'energy' } local windTextScissor = { 0, 0, 0, 0 } local comCounterScissor = { 0, 0, 0, 0 } -local storageScissors = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 } } -local activeStorageScissors = { nil, nil } -- Smoothing @@ -537,31 +534,6 @@ local function updateTidal() end end -local function drawResbarPullIncome(res) - font2:Begin(true) - font2:SetOutlineColor(0,0,0,1) - -- Text: pull - font2:Print("\255\240\125\125" .. "-" .. short(r[res][3]), resbarDrawinfo[res].textPull[2], resbarDrawinfo[res].textPull[3], resbarDrawinfo[res].textPull[4], resbarDrawinfo[res].textPull[5]) - -- Text: expense - --font2:Print("\255\240\180\145" .. "-" .. short(r[res][5]), resbarDrawinfo[res].textExpense[2], resbarDrawinfo[res].textExpense[3], resbarDrawinfo[res].textExpense[4], resbarDrawinfo[res].textExpense[5]) - -- income - font2:Print("\255\120\235\120" .. "+" .. short(r[res][4]), resbarDrawinfo[res].textIncome[2], resbarDrawinfo[res].textIncome[3], resbarDrawinfo[res].textIncome[4], resbarDrawinfo[res].textIncome[5]) - font2:End() -end - -local function drawResbarStorage(res) - if showingWarning[res] then return end - font2:Begin(true) - font2:SetOutlineColor(0,0,0,1) - if res == 'metal' then - font2:SetTextColor(0.55, 0.55, 0.55, 1) - else - font2:SetTextColor(0.57, 0.57, 0.45, 1) - end - font2:Print(cache.lastStorageText[res], resbarDrawinfo[res].textStorage[2], resbarDrawinfo[res].textStorage[3], resbarDrawinfo[res].textStorage[4], resbarDrawinfo[res].textStorage[5]) - font2:End() -end - local function updateResbarText(res, force) if not showResourceBars then return @@ -707,20 +679,6 @@ local function updateResbarText(res, force) end end -local function drawResbarValue(res) - local value = short(smoothedResources[res][1]) - cache.lastResbarValueWidth[res] = font2:GetTextWidth(value) * resbarDrawinfo[res].textCurrent[4] - font2:Begin(true) - if res == 'metal' then - font2:SetTextColor(0.95, 0.95, 0.95, 1) - else - font2:SetTextColor(1, 1, 0.74, 1) - end - font2:SetOutlineColor(0, 0, 0, 1) - font2:Print(value, resbarDrawinfo[res].textCurrent[2], resbarDrawinfo[res].textCurrent[3], resbarDrawinfo[res].textCurrent[4], resbarDrawinfo[res].textCurrent[5]) - font2:End() -end - local function updateResbar(res) if not showResourceBars then return @@ -1364,35 +1322,53 @@ function widget:Update(dt) end end --- --- OPTIMIZATION: Pre-defined function for RenderToTexture to avoid creating a closure. -local function clearFn() end -- no-op used for pre-clearing regions in uiTex -local function renderResbarText() - glTranslate(-1, -1, 0) - glScale(2 / (topbarArea[3]-topbarArea[1]), 2 / (topbarArea[4]-topbarArea[2]), 0) - glTranslate(-topbarArea[1], -topbarArea[2], 0) - - local res = 'metal' - drawResbarValue(res) - if updateRes[res][2] then - updateRes[res][2] = false - drawResbarPullIncome(res) - end - if updateRes[res][3] then - if not showingWarning[res] then updateRes[res][3] = false end - drawResbarStorage(res) +-- START: I drew the resource numbers live instead of baking into uiTex +-- (So the old "RenderToTexture" path with the fixed size clear rects with left stale digits +-- The wide values or anchor shifts escaped the clear rects +local function drawResbarNumbersLive() + if not showResourceBars then + return end - res = 'energy' - drawResbarValue(res) - if updateRes[res][2] then - updateRes[res][2] = false - drawResbarPullIncome(res) - end - if updateRes[res][3] then - if not showingWarning[res] then updateRes[res][3] = false end - drawResbarStorage(res) + font2:Begin(true) + font2:SetOutlineColor(0,0,0,1) + + for i = 1, 2 do + local res = resourceNames[i] + if resbarDrawinfo[res] and resbarDrawinfo[res].textCurrent then + local value = short(smoothedResources[res][1]) + if res == 'metal' then + font2:SetTextColor(0.95, 0.95, 0.95, 1) + else + font2:SetTextColor(1, 1, 0.74, 1) + end + font2:Print(value, resbarDrawinfo[res].textCurrent[2], resbarDrawinfo[res].textCurrent[3], resbarDrawinfo[res].textCurrent[4], resbarDrawinfo[res].textCurrent[5]) + + + --START The PULL Section + font2:Print("\255\240\125\125" .. "-" .. short(r[res][3]), resbarDrawinfo[res].textPull[2], resbarDrawinfo[res].textPull[3], resbarDrawinfo[res].textPull[4], resbarDrawinfo[res].textPull[5]) + --End The PULL Section + + -- START INCOME Section + font2:Print("\255\120\235\120" .. "+" .. short(r[res][4]), resbarDrawinfo[res].textIncome[2], resbarDrawinfo[res].textIncome[3], resbarDrawinfo[res].textIncome[4], resbarDrawinfo[res].textIncome[5]) + -- END INCOME Section + + -- START STORAGE Section (hiding the overflow warning) + if not showingWarning[res] then + if res == 'metal' then + font2:SetTextColor(0.55, 0.55, 0.55, 1) + else + font2:SetTextColor(0.57, 0.57, 0.45, 1) + end + font2:Print(cache.lastStorageText[res], resbarDrawinfo[res].textStorage[2], resbarDrawinfo[res].textStorage[3], resbarDrawinfo[res].textStorage[4], resbarDrawinfo[res].textStorage[5]) + end + -- END STORAGE Section + end end + + font2:End() end +-- END: The drew resource numbers live local function drawResBars() if not showResourceBars then @@ -1476,61 +1452,9 @@ local function drawResBars() end glPopMatrix() - if update then - local scissors = {} - res = 'metal' - if updateRes[res][1] then - scissors[#scissors+1] = { - (resbarDrawinfo[res].textCurrent[2]-topbarArea[1])-(cache.lastResbarValueWidth[res]*0.75), - (topbarArea[4]-topbarArea[2])*0.48, - resbarDrawinfo[res].textCurrent[4]+cache.lastResbarValueWidth[res], - topbarArea[4]-topbarArea[2] - } - end - if updateRes[res][2] then - scissors[#scissors+1] = { - (resbarDrawinfo[res].textPull[2]-topbarArea[1])-(resbarDrawinfo[res].textPull[4]*3.4), - 0, - resbarDrawinfo[res].textPull[4]*3.5, - topbarArea[4]-topbarArea[2] - } - end - if updateRes[res][3] then - scissors[#scissors+1] = { - (resbarDrawinfo[res].textStorage[2]-topbarArea[1])-(resbarDrawinfo[res].textStorage[4]*4), - (topbarArea[4]-topbarArea[2])*0.48, - resbarDrawinfo[res].textStorage[4]*4.1, - topbarArea[4]-topbarArea[2] - } - end - res = 'energy' - if updateRes[res][1] then - scissors[#scissors+1] = { - (resbarDrawinfo[res].textCurrent[2]-topbarArea[1])-(cache.lastResbarValueWidth[res]*0.75), - (topbarArea[4]-topbarArea[2])*0.48, - resbarDrawinfo[res].textCurrent[4]+cache.lastResbarValueWidth[res], - topbarArea[4]-topbarArea[2] - } - end - if updateRes[res][2] then - scissors[#scissors+1] = { - (resbarDrawinfo[res].textPull[2]-topbarArea[1])-(resbarDrawinfo[res].textPull[4]*3.4), - 0, - resbarDrawinfo[res].textPull[4]*3.5, - topbarArea[4]-topbarArea[2] - } - end - if updateRes[res][3] then - scissors[#scissors+1] = { - (resbarDrawinfo[res].textStorage[2]-topbarArea[1])-(resbarDrawinfo[res].textStorage[4]*4), - (topbarArea[4]-topbarArea[2])*0.48, - resbarDrawinfo[res].textStorage[4]*4.1, - topbarArea[4]-topbarArea[2] - } - end - - r2tHelper.RenderToTexture(uiTex, renderResbarText, true, scissors) - end + -- START: draw numbers live (bypass uiTex cache so stale digits dont pile up) + drawResbarNumbersLive() + -- END: draw numbers live end local function drawQuitScreen() @@ -1870,31 +1794,6 @@ function widget:DrawScreen() glCallList(dlist.tidal2) end - -- Pre-clear storage text from uiTex before rendering it to screen. - -- drawResBars() updates uiTex AFTER BlendTexRect each frame, so without this - -- the stale storage text is visible for up to ~50ms when the warning first activates. - if uiTex and (showingWarning.metal or showingWarning.energy) then - local scissorsCount = 0 - for i = 1, 2 do - local res = resourceNames[i] - if showingWarning[res] and resbarDrawinfo[res] and resbarDrawinfo[res].textStorage then - scissorsCount = scissorsCount + 1 - local scissor = storageScissors[scissorsCount] - scissor[1] = (resbarDrawinfo[res].textStorage[2]-topbarArea[1])-(resbarDrawinfo[res].textStorage[4]*4) - scissor[2] = topbarHeight * 0.48 - scissor[3] = resbarDrawinfo[res].textStorage[4]*4.1 - scissor[4] = topbarHeight - end - end - if scissorsCount > 0 then - for i = 1, scissorsCount do - activeStorageScissors[i] = storageScissors[i] - end - activeStorageScissors[scissorsCount + 1] = nil - r2tHelper.RenderToTexture(uiTex, clearFn, true, activeStorageScissors) - end - end - if uiTex then r2tHelper.BlendTexRect(uiTex, topbarArea[1], topbarArea[2], topbarArea[3], topbarArea[4], true) end From 19ef6168bc6975b02f8d6fa7f14ed914f4b1e2fb Mon Sep 17 00:00:00 2001 From: Spencer Lee Meredith <16077691+spencerleemeredith@users.noreply.github.com> Date: Tue, 30 Jun 2026 20:33:23 +0000 Subject: [PATCH 2/2] Update luaui/Widgets/gui_top_bar.lua Co-authored-by: sprunk --- luaui/Widgets/gui_top_bar.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/luaui/Widgets/gui_top_bar.lua b/luaui/Widgets/gui_top_bar.lua index 003c2b3fe6c..56b40360ea9 100644 --- a/luaui/Widgets/gui_top_bar.lua +++ b/luaui/Widgets/gui_top_bar.lua @@ -1452,9 +1452,9 @@ local function drawResBars() end glPopMatrix() - -- START: draw numbers live (bypass uiTex cache so stale digits dont pile up) + -- START: call a function to draw resbar numbers live (bypass uiTex cache so stale digits dont pile up) drawResbarNumbersLive() - -- END: draw numbers live + -- END: called a function to draw resbar numbers live end local function drawQuitScreen()