This commit is contained in:
bryanthaboi
2026-09-29 11:14:08 -04:00
parent b986f6475c
commit d8bce958ec
4 changed files with 111 additions and 0 deletions
Binary file not shown.
+10
View File
@@ -797,6 +797,16 @@ function LauncherSettings.open(hooks, version)
return true
end,
},
{
label = Strings("Theme Video BG"),
value = function()
return opts.themeVideoBg == false and Strings("OFF") or Strings("ON")
end,
step = function()
opts.themeVideoBg = opts.themeVideoBg == false
return true
end,
},
{
label = Strings("Splash Sound"),
value = function()
+78
View File
@@ -0,0 +1,78 @@
-- Quiet, black-keyed video layer behind the launcher UI.
local LauncherThemeVideo = {}
LauncherThemeVideo.__index = LauncherThemeVideo
local VIDEO_PATH = "assets/launcher/current_theme_vid.ogv"
function LauncherThemeVideo.new()
local self = setmetatable({}, LauncherThemeVideo)
local ok, err = pcall(function()
self.video = love.graphics.newVideo(VIDEO_PATH, { audio = false })
self.video:setFilter("linear", "linear")
local width, height = self.video:getDimensions()
self.canvas = love.graphics.newCanvas(width, height)
self.canvas:setFilter("linear", "linear")
self.shader = love.graphics.newShader([[
vec4 effect(vec4 color, Image texture, vec2 uv, vec2 screen) {
vec4 pixel = Texel(texture, uv);
float brightness = max(pixel.r, max(pixel.g, pixel.b));
float coverage = smoothstep(0.012, 0.10, brightness);
float gray = dot(pixel.rgb, vec3(0.299, 0.587, 0.114));
vec3 muted = mix(vec3(gray), pixel.rgb, 0.12);
return vec4(muted, pixel.a * coverage * 0.12) * color;
}
]])
self.video:play()
end)
if not ok then
self:release()
print("[launcher theme video] unavailable: " .. tostring(err))
return nil
end
return self
end
function LauncherThemeVideo:update()
-- LÖVE's Theora stream does not expose a reliable loop flag on every target.
-- Rewind after each pass so this stays portable across desktop and mobile.
if self.video and not self.video:isPlaying() then
self.video:rewind()
self.video:play()
end
end
function LauncherThemeVideo:draw()
local g = love.graphics
local width, height = g.getDimensions()
local vw, vh = self.video:getDimensions()
g.push("all")
g.origin()
g.setScissor()
g.setShader()
g.setBlendMode("alpha", "alphamultiply")
-- LÖVE Video exposes YUV planes; convert through RGB before black-keying.
local target = g.getCanvas()
g.setCanvas(self.canvas)
g.clear(0, 0, 0, 0)
g.setColor(1, 1, 1, 1)
g.draw(self.video, 0, 0)
g.setCanvas(target)
local scale = math.max(width / vw, height / vh)
g.setShader(self.shader)
g.draw(self.canvas, (width - vw * scale) / 2,
(height - vh * scale) / 2, 0, scale, scale)
g.pop()
end
function LauncherThemeVideo:release()
if self.video then self.video:pause() end
for _, key in ipairs({ "video", "canvas", "shader" }) do
local resource = self[key]
if resource then resource:release(); self[key] = nil end
end
end
return LauncherThemeVideo
+23
View File
@@ -123,6 +123,10 @@ function LauncherView.detach(imp)
end
Transition.reset()
Kit.occlude(nil)
if imp and imp._themeVideo then
imp._themeVideo:release()
imp._themeVideo = nil
end
if not imp or not imp._flex then return end
imp._flex = nil
if love.keyboard and love.keyboard.setKeyRepeat then
@@ -175,6 +179,24 @@ end
-- below is the other half of that guarantee.
function LauncherView.update(imp, dt)
if not imp._flex then return end
local settingsOptions = imp._settings and imp._settings.opts
if type(settingsOptions) == "table" then
imp._themeVideoOptions = settingsOptions
elseif not imp._themeVideoOptions then
local ok, options = pcall(require("src.core.SaveData").loadOptions)
imp._themeVideoOptions = ok and type(options) == "table" and options or {}
end
local videoEnabled = imp._themeVideoOptions.themeVideoBg ~= false
if videoEnabled and not imp._themeVideo then
local ok, player = pcall(function()
return require("src.import.LauncherThemeVideo").new()
end)
if ok then imp._themeVideo = player end
elseif not videoEnabled and imp._themeVideo then
imp._themeVideo:release()
imp._themeVideo = nil
end
if imp._themeVideo then imp._themeVideo:update(dt) end
if imp._launchFade then return end
local down = false
@@ -6807,6 +6829,7 @@ function LauncherView.draw(imp)
Toast.occlude(imp)
Theme.field()
if imp._themeVideo then imp._themeVideo:draw() end
-- Everything from here to buildModals sits UNDER any open modal, so the
-- whole stage draws shielded (no clicks, no hover, no focus ring) while