562 lines
19 KiB
Lua
562 lines
19 KiB
Lua
if not WeakAuras.IsLibsOK() then return end
|
|
local AddonName, Private = ...
|
|
|
|
local texture_data = WeakAuras.StopMotion.texture_data;
|
|
local L = WeakAuras.L;
|
|
|
|
local default = {
|
|
progressSource = {-1, "" },
|
|
adjustedMax = "",
|
|
adjustedMin = "",
|
|
foregroundTexture = "Interface\\AddOns\\WeakAuras\\Media\\Textures\\StopMotion",
|
|
backgroundTexture = "Interface\\AddOns\\WeakAuras\\Media\\Textures\\StopMotion",
|
|
desaturateBackground = false,
|
|
desaturateForeground = false,
|
|
sameTexture = true,
|
|
width = 128,
|
|
height = 128,
|
|
foregroundColor = {1, 1, 1, 1},
|
|
backgroundColor = {0.5, 0.5, 0.5, 0.5},
|
|
blendMode = "BLEND",
|
|
rotation = 0,
|
|
discrete_rotation = 0,
|
|
mirror = false,
|
|
rotate = true,
|
|
selfPoint = "CENTER",
|
|
anchorPoint = "CENTER",
|
|
anchorFrameType = "SCREEN",
|
|
xOffset = 0,
|
|
yOffset = 0,
|
|
frameStrata = 1,
|
|
startPercent = 0,
|
|
endPercent = 1,
|
|
backgroundPercent = 1,
|
|
frameRate = 15,
|
|
animationType = "loop",
|
|
inverse = false,
|
|
customForegroundFrames = 0,
|
|
customForegroundRows = 16,
|
|
customForegroundColumns = 16,
|
|
customBackgroundFrames = 0,
|
|
customForegroundFileWidth = 0,
|
|
customForegroundFileHeight = 0,
|
|
customForegroundFrameWidth = 0,
|
|
customForegroundFrameHeight = 0,
|
|
customBackgroundRows = 16,
|
|
customBackgroundColumns = 16,
|
|
hideBackground = true
|
|
};
|
|
|
|
Private.regionPrototype.AddProgressSourceToDefault(default)
|
|
|
|
local screenWidth, screenHeight = math.ceil(GetScreenWidth() / 20) * 20, math.ceil(GetScreenHeight() / 20) * 20;
|
|
|
|
local properties = {
|
|
desaturateForeground = {
|
|
display = L["Desaturate Foreground"],
|
|
setter = "SetForegroundDesaturated",
|
|
type = "bool",
|
|
},
|
|
desaturateBackground = {
|
|
display = L["Desaturate Background"],
|
|
setter = "SetBackgroundDesaturated",
|
|
type = "bool",
|
|
},
|
|
foregroundColor = {
|
|
display = L["Foreground Color"],
|
|
setter = "Color",
|
|
type = "color"
|
|
},
|
|
backgroundColor = {
|
|
display = L["Background Color"],
|
|
setter = "SetBackgroundColor",
|
|
type = "color"
|
|
},
|
|
width = {
|
|
display = L["Width"],
|
|
setter = "SetRegionWidth",
|
|
type = "number",
|
|
min = 1,
|
|
softMax = screenWidth,
|
|
bigStep = 1,
|
|
},
|
|
height = {
|
|
display = L["Height"],
|
|
setter = "SetRegionHeight",
|
|
type = "number",
|
|
min = 1,
|
|
softMax = screenHeight,
|
|
bigStep = 1
|
|
},
|
|
}
|
|
|
|
Private.regionPrototype.AddProperties(properties, default);
|
|
|
|
local function GetProperties(data)
|
|
local result = CopyTable(properties)
|
|
result.progressSource.values = Private.GetProgressSourcesForUi(data)
|
|
return result
|
|
end
|
|
|
|
local function create(parent)
|
|
local frame = CreateFrame("Frame", nil, UIParent);
|
|
frame.regionType = "stopmotion"
|
|
frame:SetMovable(true);
|
|
frame:SetResizable(true);
|
|
frame:SetMinResize(1, 1);
|
|
|
|
local background = frame:CreateTexture(nil, "BACKGROUND");
|
|
frame.background = background;
|
|
background:SetAllPoints(frame);
|
|
|
|
local foreground = frame:CreateTexture(nil, "ARTWORK");
|
|
frame.foreground = foreground;
|
|
foreground:SetAllPoints(frame);
|
|
|
|
Private.regionPrototype.create(frame);
|
|
|
|
return frame;
|
|
end
|
|
|
|
local function SetTextureViaAtlas(self, texture)
|
|
self:SetTexture(texture);
|
|
end
|
|
|
|
local function setTile(texture, frame, rows, columns, frameScaleW, frameScaleH)
|
|
frame = frame - 1;
|
|
local row = floor(frame / columns);
|
|
local column = frame % columns;
|
|
|
|
local deltaX = frameScaleW / columns
|
|
local deltaY = frameScaleH / rows
|
|
|
|
local left = deltaX * column;
|
|
local right = left + deltaX;
|
|
|
|
local top = deltaY * row;
|
|
local bottom = top + deltaY;
|
|
pcall(function() texture:SetTexCoord(left, right, top, bottom) end)
|
|
end
|
|
|
|
WeakAuras.setTile = setTile;
|
|
|
|
local function SetFrameViaAtlas(self, texture, frame)
|
|
local frameScaleW = 1
|
|
local frameScaleH = 1
|
|
if self.fileWidth and self.frameWidth and self.fileWidth > 0 and self.frameWidth > 0 then
|
|
frameScaleW = (self.frameWidth * self.columns) / self.fileWidth
|
|
end
|
|
if self.fileHeight and self.frameHeight and self.fileHeight > 0 and self.frameHeight > 0 then
|
|
frameScaleH = (self.frameHeight * self.rows) / self.fileHeight
|
|
end
|
|
setTile(self, frame, self.rows, self.columns, frameScaleW, frameScaleH);
|
|
end
|
|
|
|
local function SetTextureViaFrames(self, texture)
|
|
self:SetTexture(texture .. format("%03d", 0));
|
|
self:SetTexCoord(0, 1, 0, 1);
|
|
end
|
|
|
|
local function SetFrameViaFrames(self, texture, frame)
|
|
self:SetTexture(texture .. format("%03d", frame));
|
|
end
|
|
|
|
local function SetProgress(self, progress)
|
|
local frames
|
|
local startFrame = self.startFrame
|
|
local endFrame = self.endFrame
|
|
local inverse = self.inverseDirection
|
|
if (endFrame >= startFrame) then
|
|
frames = endFrame - startFrame + 1
|
|
else
|
|
frames = startFrame - endFrame + 1
|
|
startFrame, endFrame = endFrame, startFrame
|
|
inverse = not inverse
|
|
end
|
|
local frame = floor( (frames - 1) * progress) + startFrame
|
|
|
|
if (inverse) then
|
|
frame = endFrame - frame + startFrame;
|
|
end
|
|
|
|
if (frame > endFrame) then
|
|
frame = endFrame
|
|
end
|
|
|
|
if (frame < startFrame) then
|
|
frame = startFrame
|
|
end
|
|
self.foreground:SetFrame(self.foregroundTexture, frame);
|
|
end
|
|
|
|
local FrameTickFunctions = {
|
|
progressTimer = function(self)
|
|
Private.StartProfileSystem("stopmotion")
|
|
Private.StartProfileAura(self.id)
|
|
local remaining = self.expirationTime - GetTime()
|
|
local progress = 1 - (remaining / self.duration)
|
|
|
|
self:SetProgress(progress)
|
|
|
|
Private.StopProfileAura(self.id)
|
|
Private.StopProfileSystem("stopmotion")
|
|
end,
|
|
timed = function(self)
|
|
if (not self.startTime) then return end
|
|
|
|
Private.StartProfileSystem("stopmotion")
|
|
Private.StartProfileAura(self.id)
|
|
|
|
local timeSinceStart = (GetTime() - self.startTime)
|
|
local newCurrentFrame = floor(timeSinceStart * (self.frameRate or 15))
|
|
if (newCurrentFrame == self.currentFrame) then
|
|
Private.StopProfileAura(self.id)
|
|
Private.StopProfileSystem("stopmotion")
|
|
return
|
|
end
|
|
|
|
self.currentFrame = newCurrentFrame
|
|
|
|
local frames
|
|
local startFrame = self.startFrame
|
|
local endFrame = self.endFrame
|
|
local inverse = self.inverseDirection
|
|
if (endFrame >= startFrame) then
|
|
frames = endFrame - startFrame + 1
|
|
else
|
|
frames = startFrame - endFrame + 1
|
|
startFrame, endFrame = endFrame, startFrame
|
|
inverse = not inverse
|
|
end
|
|
|
|
local frame = 0
|
|
if (self.animationType == "loop") then
|
|
frame = (newCurrentFrame % frames) + startFrame
|
|
elseif (self.animationType == "bounce") then
|
|
local direction = floor(newCurrentFrame / frames) % 2
|
|
if (direction == 0) then
|
|
frame = (newCurrentFrame % frames) + startFrame
|
|
else
|
|
frame = endFrame - (newCurrentFrame % frames)
|
|
end
|
|
elseif (self.animationType == "once") then
|
|
frame = newCurrentFrame + startFrame
|
|
if (frame > endFrame) then
|
|
frame = endFrame
|
|
end
|
|
end
|
|
if (inverse) then
|
|
frame = endFrame - frame + startFrame
|
|
end
|
|
|
|
if (frame > endFrame) then
|
|
frame = endFrame
|
|
end
|
|
|
|
if (frame < startFrame) then
|
|
frame = startFrame
|
|
end
|
|
self.foreground:SetFrame(self.foregroundTexture, frame)
|
|
|
|
Private.StopProfileAura(self.id)
|
|
Private.StopProfileSystem("stopmotion")
|
|
end,
|
|
}
|
|
|
|
local function modify(parent, region, data)
|
|
Private.regionPrototype.modify(parent, region, data);
|
|
region.foreground = region.foreground or {}
|
|
region.background = region.background or {}
|
|
region.frameRate = data.frameRate
|
|
region.inverseDirection = data.inverse
|
|
region.animationType = data.animationType
|
|
region.foregroundTexture = data.foregroundTexture
|
|
region.FrameTick = nil
|
|
local pattern = "%.x(%d+)y(%d+)f(%d+)%.[tb][gl][ap]"
|
|
local pattern2 = "%.x(%d+)y(%d+)f(%d+)w(%d+)h(%d+)W(%d+)H(%d+)%.[tb][gl][ap]"
|
|
|
|
do
|
|
local tdata = texture_data[data.foregroundTexture];
|
|
if (tdata) then
|
|
local lastFrame = tdata.count - 1;
|
|
region.foreground.lastFrame = lastFrame
|
|
region.startFrame = floor( (data.startPercent or 0) * lastFrame) + 1;
|
|
region.endFrame = floor( (data.endPercent or 1) * lastFrame) + 1;
|
|
region.foreground.rows = tdata.rows;
|
|
region.foreground.columns = tdata.columns;
|
|
region.foreground.fileWidth = 0
|
|
region.foreground.fileHeight = 0
|
|
region.foreground.frameWidth = 0
|
|
region.foreground.frameHeight = 0
|
|
else
|
|
local rows, columns, frames = data.foregroundTexture:lower():match(pattern)
|
|
if rows then
|
|
local lastFrame = tonumber(frames) - 1;
|
|
region.foreground.lastFrame = lastFrame
|
|
region.startFrame = floor( (data.startPercent or 0) * lastFrame) + 1;
|
|
region.endFrame = floor( (data.endPercent or 1) * lastFrame) + 1;
|
|
region.foreground.rows = tonumber(rows)
|
|
region.foreground.columns = tonumber(columns)
|
|
region.foreground.fileWidth = 0
|
|
region.foreground.fileHeight = 0
|
|
region.foreground.frameWidth = 0
|
|
region.foreground.frameHeight = 0
|
|
else
|
|
local rows, columns, frames, frameWidth, frameHeight, fileWidth, fileHeight = data.foregroundTexture:match(pattern2)
|
|
if rows then
|
|
local lastFrame = tonumber(frames) - 1;
|
|
region.foreground.lastFrame = lastFrame
|
|
region.startFrame = floor( (data.startPercent or 0) * lastFrame) + 1;
|
|
region.endFrame = floor( (data.endPercent or 1) * lastFrame) + 1;
|
|
region.foreground.rows = tonumber(rows)
|
|
region.foreground.columns = tonumber(columns)
|
|
region.foreground.fileWidth = tonumber(fileWidth)
|
|
region.foreground.fileHeight = tonumber(fileHeight)
|
|
region.foreground.frameWidth = tonumber(frameWidth)
|
|
region.foreground.frameHeight = tonumber(frameHeight)
|
|
else
|
|
local lastFrame = (data.customForegroundFrames or 256) - 1;
|
|
region.foreground.lastFrame = lastFrame
|
|
region.startFrame = floor( (data.startPercent or 0) * lastFrame) + 1;
|
|
region.endFrame = floor( (data.endPercent or 1) * lastFrame) + 1;
|
|
region.foreground.rows = data.customForegroundRows;
|
|
region.foreground.columns = data.customForegroundColumns;
|
|
region.foreground.fileWidth = data.customForegroundFileWidth
|
|
region.foreground.fileHeight = data.customForegroundFileHeight
|
|
region.foreground.frameWidth = data.customForegroundFrameWidth
|
|
region.foreground.frameHeight = data.customForegroundFrameHeight
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local backgroundTexture = data.sameTexture
|
|
and data.foregroundTexture
|
|
or data.backgroundTexture;
|
|
|
|
do
|
|
if data.sameTexture then
|
|
region.backgroundFrame = floor( (data.backgroundPercent or 1) * region.foreground.lastFrame + 1);
|
|
region.background.rows = region.foreground.rows
|
|
region.background.columns = region.foreground.columns
|
|
region.background.fileWidth = region.foreground.fileWidth
|
|
region.background.fileHeight = region.foreground.fileHeight
|
|
region.background.frameWidth = region.foreground.frameWidth
|
|
region.background.frameHeight = region.foreground.frameHeight
|
|
else
|
|
local tdata = texture_data[data.backgroundTexture];
|
|
if (tdata) then
|
|
local lastFrame = tdata.count - 1;
|
|
region.backgroundFrame = floor( (data.backgroundPercent or 1) * lastFrame + 1);
|
|
region.background.rows = tdata.rows;
|
|
region.background.columns = tdata.columns;
|
|
region.background.fileWidth = 0
|
|
region.background.fileHeight = 0
|
|
region.background.frameWidth = 0
|
|
region.background.frameHeight = 0
|
|
else
|
|
local rows, columns, frames = data.backgroundTexture:lower():match(pattern)
|
|
if rows then
|
|
local lastFrame = frames - 1;
|
|
region.backgroundFrame = floor( (data.backgroundPercent or 1) * lastFrame + 1);
|
|
region.background.rows = tonumber(rows)
|
|
region.background.columns = tonumber(columns)
|
|
region.background.fileWidth = 0
|
|
region.background.fileHeight = 0
|
|
region.background.frameWidth = 0
|
|
region.background.frameHeight = 0
|
|
else
|
|
local rows, columns, frames, frameWidth, frameHeight, fileWidth, fileHeight = data.backgroundTexture:match(pattern2)
|
|
if rows then
|
|
local lastFrame = frames - 1;
|
|
region.backgroundFrame = floor( (data.backgroundPercent or 1) * lastFrame + 1);
|
|
region.background.rows = tonumber(rows)
|
|
region.background.columns = tonumber(columns)
|
|
region.background.fileWidth = tonumber(fileWidth)
|
|
region.background.fileHeight = tonumber(fileHeight)
|
|
region.background.frameWidth = tonumber(frameWidth)
|
|
region.background.frameHeight = tonumber(frameHeight)
|
|
else
|
|
local lastFrame = (data.customBackgroundFrames or 256) - 1;
|
|
region.backgroundFrame = floor( (data.backgroundPercent or 1) * lastFrame + 1);
|
|
region.background.rows = data.customBackgroundRows;
|
|
region.background.columns = data.customBackgroundColumns;
|
|
region.background.fileWidth = data.customBackgroundFileWidth
|
|
region.background.fileHeight = data.customBackgroundFileHeight
|
|
region.background.frameWidth = data.customBackgroundFrameWidth
|
|
region.background.frameHeight = data.customBackgroundFrameHeight
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if (region.foreground.rows and region.foreground.columns) then
|
|
region.foreground.SetBaseTexture = SetTextureViaAtlas;
|
|
region.foreground.SetFrame = SetFrameViaAtlas;
|
|
else
|
|
region.foreground.SetBaseTexture = SetTextureViaFrames;
|
|
region.foreground.SetFrame = SetFrameViaFrames;
|
|
end
|
|
|
|
if (region.background.rows and region.background.columns) then
|
|
region.background.SetBaseTexture = SetTextureViaAtlas;
|
|
region.background.SetFrame = SetFrameViaAtlas;
|
|
else
|
|
region.background.SetBaseTexture = SetTextureViaFrames;
|
|
region.background.SetFrame = SetFrameViaFrames;
|
|
end
|
|
|
|
|
|
region.background:SetBaseTexture(backgroundTexture);
|
|
region.background:SetFrame(backgroundTexture, region.backgroundFrame or 1);
|
|
region.background:SetDesaturated(data.desaturateBackground)
|
|
region.background:SetVertexColor(data.backgroundColor[1], data.backgroundColor[2], data.backgroundColor[3], data.backgroundColor[4]);
|
|
region.background:SetBlendMode(data.blendMode);
|
|
|
|
if (data.hideBackground) then
|
|
region.background:Hide();
|
|
else
|
|
region.background:Show();
|
|
end
|
|
|
|
region.foreground:SetBaseTexture(data.foregroundTexture);
|
|
region.foreground:SetFrame(data.foregroundTexture, 1);
|
|
region.foreground:SetDesaturated(data.desaturateForeground);
|
|
region.foreground:SetBlendMode(data.blendMode);
|
|
|
|
region:SetWidth(data.width);
|
|
region:SetHeight(data.height);
|
|
region.width = data.width;
|
|
region.height = data.height;
|
|
region.scalex = 1;
|
|
region.scaley = 1;
|
|
|
|
function region:Scale(scalex, scaley)
|
|
region.scalex = scalex;
|
|
region.scaley = scaley;
|
|
if(scalex < 0) then
|
|
region.mirror_h = true;
|
|
scalex = scalex * -1;
|
|
else
|
|
region.mirror_h = nil;
|
|
end
|
|
region:SetWidth(region.width * scalex);
|
|
if(scaley < 0) then
|
|
scaley = scaley * -1;
|
|
region.mirror_v = true;
|
|
else
|
|
region.mirror_v = nil;
|
|
end
|
|
region:SetHeight(region.height * scaley);
|
|
end
|
|
|
|
function region:Color(r, g, b, a)
|
|
region.color_r = r;
|
|
region.color_g = g;
|
|
region.color_b = b;
|
|
region.color_a = a;
|
|
if (r or g or b) then
|
|
a = a or 1;
|
|
end
|
|
region.foreground:SetVertexColor(region.color_anim_r or r, region.color_anim_g or g, region.color_anim_b or b, region.color_anim_a or a);
|
|
end
|
|
|
|
function region:ColorAnim(r, g, b, a)
|
|
region.color_anim_r = r;
|
|
region.color_anim_g = g;
|
|
region.color_anim_b = b;
|
|
region.color_anim_a = a;
|
|
if (r or g or b) then
|
|
a = a or 1;
|
|
end
|
|
region.foreground:SetVertexColor(r or region.color_r, g or region.color_g, b or region.color_b, a or region.color_a);
|
|
end
|
|
|
|
function region:GetColor()
|
|
return region.color_r or data.color[1], region.color_g or data.color[2],
|
|
region.color_b or data.color[3], region.color_a or data.color[4];
|
|
end
|
|
|
|
region:Color(data.foregroundColor[1], data.foregroundColor[2], data.foregroundColor[3], data.foregroundColor[4]);
|
|
|
|
function region:PreShow()
|
|
region.startTime = GetTime();
|
|
if region.FrameTick then
|
|
region:FrameTick()
|
|
end
|
|
end
|
|
|
|
region.SetProgress = SetProgress
|
|
|
|
if data.animationType == "loop" or data.animationType == "bounce" or data.animationType == "once" then
|
|
region.FrameTick = FrameTickFunctions.timed
|
|
region.subRegionEvents:AddSubscriber("FrameTick", region, true)
|
|
function region:Update()
|
|
region:UpdateProgress()
|
|
end
|
|
|
|
elseif data.animationType == "progress" then
|
|
function region:Update()
|
|
region:UpdateProgress()
|
|
end
|
|
|
|
function region:UpdateValue()
|
|
local progress = 0;
|
|
if (self.total ~= 0) then
|
|
progress = self.value / self.total
|
|
end
|
|
self:SetProgress(progress)
|
|
if self.FrameTick then
|
|
self.FrameTick = nil
|
|
self.subRegionEvents:RemoveSubscriber("FrameTick", self)
|
|
end
|
|
end
|
|
|
|
function region:UpdateTime()
|
|
if self.paused and self.FrameTick then
|
|
self.FrameTick = nil
|
|
self.subRegionEvents:RemoveSubscriber("FrameTick", self)
|
|
end
|
|
self.expirationTime = self.expirationTime
|
|
self.duration = self.duration
|
|
if not self.paused then
|
|
if not self.FrameTick then
|
|
self.FrameTick = FrameTickFunctions.progressTimer
|
|
self.subRegionEvents:AddSubscriber("FrameTick", self)
|
|
end
|
|
self:FrameTick()
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
function region:SetForegroundDesaturated(b)
|
|
region.foreground:SetDesaturated(b);
|
|
end
|
|
|
|
function region:SetBackgroundDesaturated(b)
|
|
region.background:SetDesaturated(b);
|
|
end
|
|
|
|
function region:SetBackgroundColor(r, g, b, a)
|
|
region.background:SetVertexColor(r, g, b, a);
|
|
end
|
|
|
|
function region:SetRegionWidth(width)
|
|
region.width = width;
|
|
region:Scale(region.scalex, region.scaley);
|
|
end
|
|
|
|
function region:SetRegionHeight(height)
|
|
region.height = height;
|
|
region:Scale(region.scalex, region.scaley);
|
|
end
|
|
end
|
|
|
|
local function validate(data)
|
|
Private.EnforceSubregionExists(data, "subbackground")
|
|
end
|
|
|
|
Private.RegisterRegionType("stopmotion", create, modify, default, GetProperties, validate);
|