Skip to content

Commit 9239756

Browse files
committed
frame: add frame:GetEffectiveAlpha()
Own alpha times every ancestor's alpha -- the product WoW composites at render time. Vanilla has only GetAlpha (a frame's own alpha); this walks self -> parent -> ... via the engine's own GetAlpha/GetParent, so it reflects the engine exactly, including 8-bit alpha quantization (SetAlpha(0.5) -> 127/255). Frame-scoped, matching GetAlpha's registry. Verified in-game: matches an equivalent Lua GetAlpha/GetParent walk, and a two-level 0.5/0.5 chain returns (127/255)^2 = 0.248043 exactly.
1 parent f13aa19 commit 9239756

4 files changed

Lines changed: 53 additions & 1 deletion

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Full per-function reference: **[docs/API.md](docs/API.md)**.
3535
| [Expansion](docs/API.md#expansion) | `ClassicExpansionAtLeast`, `ClassicExpansionAtMost`, `GetClassicExpansionLevel` |
3636
| [Faction](docs/API.md#faction) | `C_Reputation.GetFactionDataByIndex`, `C_Reputation.GetFactionStandings`, `C_Reputation.GetLastStandingChange`, `C_Reputation.GetWatchedFactionData`, `C_Reputation.SetWatchedFactionByID`, `GetFactionIDByIndex`, `GetFactionInfoByID`, `GetFactionParentID` |
3737
| [Focus](docs/API.md#focus) | `ClearFocus`, `FocusUnit` |
38-
| [Frame](docs/API.md#frame) | `region:SetPoint("point")` (one-arg form), `region:SetSize`, `region:GetSize`, `region:IsMouseOver`, `region:GetRect`, `region:IsDragging`, `frame:SetShown`, `frame:SetResizeBounds`, `frame:HookScript`, `frame:IsEventRegistered` |
38+
| [Frame](docs/API.md#frame) | `region:SetPoint("point")` (one-arg form), `region:SetSize`, `region:GetSize`, `region:IsMouseOver`, `region:GetRect`, `region:IsDragging`, `frame:SetShown`, `frame:SetResizeBounds`, `frame:HookScript`, `frame:IsEventRegistered`, `frame:GetEffectiveAlpha` |
3939
| [FriendList](docs/API.md#friendlist) | `C_FriendList.IsWhoQueryPending`, `C_FriendList.SendWhoQueryByName` |
4040
| [GameObject](docs/API.md#gameobject) | `C_GameObjectInfo.GetGameObjectInfoByID`, `C_GameObjectInfo.RequestLoadGameObjectByID`, `ClosestGameObjectPosition` |
4141
| [Gossip](docs/API.md#gossip) | `C_GossipInfo.CloseGossip`, `C_GossipInfo.GetActiveQuests`, `C_GossipInfo.GetAvailableQuests`, `C_GossipInfo.GetNumActiveQuests`, `C_GossipInfo.GetNumAvailableQuests`, `C_GossipInfo.GetNumOptions`, `C_GossipInfo.GetOptions`, `C_GossipInfo.GetText`, `C_GossipInfo.SelectActiveQuest`, `C_GossipInfo.SelectAvailableQuest`, `C_GossipInfo.SelectOption`, `C_GossipInfo.SelectOptionByIndex` |

docs/API.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ build instructions.
162162
- [`frame:SetResizeBounds(minWidth, minHeight [, maxWidth, maxHeight])`](#framesetresizeboundsminwidth-minheight--maxwidth-maxheight)
163163
- [`frame:HookScript(scriptType, handler)`](#framehookscriptscripttype-handler)
164164
- [`frame:IsEventRegistered(event)`](#frameiseventregisteredevent)
165+
- [`frame:GetEffectiveAlpha()`](#framegeteffectivealpha)
165166

166167
- [FriendList](#friendlist)
167168
- [`C_FriendList.SendWhoQueryByName(name)`](#c_friendlistsendwhoquerybynamename)
@@ -3691,6 +3692,22 @@ f:IsEventRegistered("PLAYER_LOGIN") -- true
36913692
f:IsEventRegistered("PLAYER_LOGOUT") -- false
36923693
```
36933694

3695+
### `frame:GetEffectiveAlpha()`
3696+
3697+
Returns the frame's **effective** alpha — its own `GetAlpha()` multiplied
3698+
by every ancestor's, i.e. the opacity WoW actually composites at render
3699+
time (fading `UIParent` fades all of its children). Vanilla exposes only
3700+
`GetAlpha` (a frame's own alpha); this walks `self → parent → …` via the
3701+
engine's own `GetAlpha`/`GetParent`, so it sees exactly what the engine
3702+
does — including the 8-bit quantization of alpha (`SetAlpha(0.5)` stores
3703+
`127/255 ≈ 0.498`, and effective alpha is the product of those).
3704+
3705+
```lua
3706+
UIParent:GetEffectiveAlpha() -- 1
3707+
-- with UIParent at 0.5 and Minimap's own alpha 1:
3708+
Minimap:GetEffectiveAlpha() -- ~0.498 (0.5 truncates to 127/255)
3709+
```
3710+
36943711
## FriendList
36953712

36963713
### `C_FriendList.SendWhoQueryByName(name)`

src/Offsets.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,6 +1346,10 @@ enum Offsets {
13461346
FUN_SCRIPT_FRAME_SETMAXRESIZE = 0x007762A0,
13471347
FUN_SCRIPT_FRAME_GETSCRIPT = 0x00774780,
13481348
FUN_SCRIPT_FRAME_SETSCRIPT = 0x007748D0,
1349+
// Frame GetAlpha (own alpha, 0..1) + Region GetParent — walked by
1350+
// Frame::Modern's GetEffectiveAlpha up the parent chain.
1351+
FUN_SCRIPT_FRAME_GETALPHA = 0x00774DC0,
1352+
FUN_SCRIPT_REGION_GETPARENT = 0x007A1460,
13491353
FUN_SCRIPT_TEXTURE_SHOW = 0x0079B770,
13501354
FUN_SCRIPT_TEXTURE_HIDE = 0x0079B830,
13511355
FUN_SCRIPT_FONTSTRING_SHOW = 0x0079CDB0,

src/frame/Modern.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
// - `frame:HookScript(scriptType, handler)` — absent in vanilla
4141
// entirely. Chains after any existing handler and invokes `handler`
4242
// with modern positional args (see the implementation comment).
43+
// - `frame:GetEffectiveAlpha()` — own alpha × the parent chain's, the
44+
// product WoW composites at render time. Frame-scoped (matches
45+
// GetAlpha); walks the parents via the engine's own getters.
4346
//
4447
// Implementation style: each new method delegates to the ENGINE's own
4548
// Script_* implementations by reshaping the Lua stack and calling them
@@ -214,6 +217,33 @@ int __fastcall Script_SetShown(void *L) {
214217
return 0;
215218
}
216219

220+
// ---- GetEffectiveAlpha (Frame) ---------------------------------------------
221+
222+
// `frame:GetEffectiveAlpha()` — the frame's own alpha times every
223+
// ancestor's alpha, i.e. the product WoW composites at render time (fading
224+
// UIParent fades all children). Vanilla exposes only GetAlpha (own alpha);
225+
// we walk self → parent → … via the engine's own GetAlpha (Frame) and
226+
// GetParent (Region), so no field offsets or scale math are re-derived. The
227+
// iteration cap is a defensive guard against a pathological chain (WoW frame
228+
// trees are shallow; the loop normally ends when GetParent returns nil at
229+
// the top of the tree).
230+
int __fastcall Script_GetEffectiveAlpha(void *L) {
231+
Game::Lua::SetTop(L, 1); // (obj) = self
232+
double eff = 1.0;
233+
for (int guard = 0; guard < 128; ++guard) {
234+
CallScript(Offsets::FUN_SCRIPT_FRAME_GETALPHA, L); // (obj, alpha)
235+
eff *= Game::Lua::ToNumber(L, 2);
236+
Game::Lua::SetTop(L, 1); // (obj)
237+
CallScript(Offsets::FUN_SCRIPT_REGION_GETPARENT, L); // (obj, parent|nil)
238+
if (Game::Lua::Type(L, 2) == Game::Lua::TYPE_NIL)
239+
break;
240+
Game::Lua::Remove(L, 1); // drop obj → (parent) becomes index 1
241+
}
242+
Game::Lua::SetTop(L, 0);
243+
Game::Lua::PushNumber(L, eff);
244+
return 1;
245+
}
246+
217247
// ---- SetResizeBounds (Frame) -----------------------------------------------
218248

219249
// `frame:SetResizeBounds(minWidth, minHeight [, maxWidth, maxHeight])` —
@@ -404,6 +434,7 @@ const Game::Lua::FrameMethodEntry g_frameMethods[] = {
404434
{"SetResizeBounds", &Script_SetResizeBounds},
405435
{"HookScript", &Script_HookScript},
406436
{"IsEventRegistered", &Script_IsEventRegistered},
437+
{"GetEffectiveAlpha", &Script_GetEffectiveAlpha},
407438
};
408439

409440
const Game::Lua::FrameMethodEntry g_textureMethods[] = {

0 commit comments

Comments
 (0)