You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2767 lines
88 KiB

local _, addon = ...
local L = Narci.L;
local TransmogDataProvider = addon.TransmogDataProvider; --defined in Modules/DressingRoom/SlotFrame
local GetModelOffsetZ = addon.GetModelOffsetZ;
local UseCurrentClassBackground = addon.UseCurrentClassBackground;
local UseCurrentRaceBackground = addon.UseCurrentRaceBackground;
local UseModelBackgroundImage = addon.UseModelBackgroundImage;
local FadeFrame = NarciFadeUI.Fade;
local GetAnimationName = NarciAnimationInfo.GetOfficialName;
local IsShiftKeyDown = IsShiftKeyDown;
local GetCursorPosition = GetCursorPosition;
local GetCursorDelta = GetCursorDelta;
local IsHiddenVisual = C_TransmogCollection.IsAppearanceHiddenVisual;
local GetPhysicalScreenSize = GetPhysicalScreenSize;
local ROTATION_PERIOD = 1/8;
local PIXEL = 1;
local PI = math.pi;
local PI2 = math.pi * 2;
local ASPECT = 3/4;
local FOV_VERTICAL = 0.6;
local FOV_DIAGONAL = FOV_VERTICAL * math.sqrt(1 + ASPECT^2);
local TAN_FOV_V = math.tan(FOV_VERTICAL/2);
local TAN_FOV_H;
local function ConvertHorizontalFoV(fovV, aspect)
local fov_H = 2*math.atan(math.tan(fovV/2) * aspect);
return math.tan(fov_H/2);
end
TAN_FOV_H = ConvertHorizontalFoV(FOV_VERTICAL, ASPECT);
local IMAGE_WIDTH = 800;
local IMAGE_HEIGHT = 600;
local MODEL_WIDTH_RATIO = 0.75; --width:height = 3:4
local ACTOR_IS_MOUNT = false;
local LOOP_ANIMATION = false;
local SHOW_ITEM_NAME = true;
local NUM_DOUBLE_LINE_OBJECT = 0;
local MAX_DOUBLE_LINE_OBJECT = 4;
local MAX_FONTSTRING_WIDTH = 318;
local ITEM_TEXT_FONT = "Interface/AddOns/Narcissus/Font/NotoSansCJKsc-Regular.otf";
local FONT_WEIGHT = 16;
local FONT_EFFECT = "OUTLINE";
local ITEM_TEXT_HEIGHT = PIXEL * FONT_WEIGHT;
local PA_SPACING_WEIGHT = 12; --weight * pixel
local PA_SPACING = 12;
local DEFAULT_CAM_DISTANCE = 4;
local MIN_CAM_DISTANCE = 1;
local MAX_CAM_DISTANCE = 12;
local LAST_IMAGE_SIZE_WITH_TEXT;
local LAST_IMAGE_SIZE_NO_TEXT;
local PRINT_ORDERS = {
1, 3, 15, 5, 4, 19, 9, 10, 6, 7, 8, 16, 17,
};
local ANIMATION_ID = 0;
local VARIATION_ID = 1;
local MAX_ANIMATION_ID = (NarciConstants and NarciConstants.Animation.MaxAnimationID) or 1499;
local min = math.min;
local max = math.max;
local DB;
local MainFrame, ModelScene, ControlPanel, FadeOptionFrame, UtilityModel, Tooltip, DropDownPanel, TabSelection, SheatheButton, GroundShadow;
local ActiveActor, PlayerActor, MountActor;
local IDFrame, VariationButton, AnimationSlider, MountToggle, LoopToggle;
local function GetScreenAspectText(width, height)
local ratio = math.floor(100*width/height)/100;
if ratio == 1 then
ratio = "1:1";
elseif ratio == 0.75 then
ratio = "3:4";
elseif ratio == 1.33 then
ratio = "4:3";
elseif ratio == 1.77 then
ratio = "16:9";
elseif ratio == 1.6 then
ratio = "16:10";
elseif ratio == 0.5625 then
ratio = "9:16";
else
ratio = "custom";
end
return ratio
end
local DropDownOptions = {
imageSizeWithText = {
{" ", {1024, 768}},
{" ", {800, 600}},
method = "SetImageSize",
};
imageSizeNoText = {
{" ", {1080, 1080}},
{" ", {600, 800}},
{" ", {600, 600}},
method = "SetImageSize",
};
rotationPeriod = {
{"4 s", 4},
{"6 s", 6},
{"8 s", 8},
method = "SetRotationPeriod",
};
fontSize = {
{"15", 15},
{"16", 16},
{"18", 18},
method = "SetFontWeight",
};
};
for i = 1, #DropDownOptions.imageSizeWithText do
local v = DropDownOptions.imageSizeWithText[i];
local width, height = v[2][1], v[2][2];
DropDownOptions.imageSizeWithText[i][1] = string.format("%s x %s (%s)", width, height, GetScreenAspectText(width, height));
end
for i = 1, #DropDownOptions.imageSizeNoText do
local v = DropDownOptions.imageSizeNoText[i];
local width, height = v[2][1], v[2][2];
DropDownOptions.imageSizeNoText[i][1] = string.format("%s x %s (%s)", width, height, GetScreenAspectText(width, height));
end
DropDownOptions.imageSizeValid = DropDownOptions.imageSizeWithText;
local function LoadSettings()
NarciTurntableOptions = NarciTurntableOptions or {};
DB = NarciTurntableOptions;
local defaultValues = {
["ShowItemName"] = true,
["FontSize"] = 16,
["ImageWidth"] = 800,
["ImageHeight"] = 600,
["NoTextImageWidth"] = 600,
["NoTextImageHeight"] = 800,
["Period"] = 6,
["BackgroundType"] = 1,
["BackgroundImageType"] = 1,
["ShowSplash"] = true,
--["BackgroundImageID"]
--["CustomFileName"]
};
if not DB.ImageHeight then
local w, h = GetPhysicalScreenSize();
if h > 1438 then
DB.ImageWidth = 1024;
DB.ImageHeight = 768;
end
end
for k, v in pairs(defaultValues) do
if (DB[k] == nil) or (type(DB[k]) ~= type(v)) then
DB[k] = v;
end
end
SHOW_ITEM_NAME = DB.ShowItemName;
LAST_IMAGE_SIZE_WITH_TEXT = {DB.ImageWidth, DB.ImageHeight};
LAST_IMAGE_SIZE_NO_TEXT = {DB.NoTextImageWidth, DB.NoTextImageHeight};
MainFrame:ShowItemText(SHOW_ITEM_NAME);
MainFrame:SetFontWeight(DB.FontSize);
MainFrame:SetRotationPeriod(DB.Period, true);
local tab = MainFrame.ControlPanel.BackgroundTab;
local id = DB.BackgroundType;
if tab.Nodes[id] then
tab.Nodes[id]:Click();
else
tab.Nodes[1]:Click();
end
if DB.ShowSplash then
MainFrame.createSplash = true;
--/run NarciTurntableOptions.ShowSplash = true
end
end
local function SetUpDropDown(parentButton, menuName)
local p = DropDownPanel;
p:ClearAllPoints();
if p.parentButton then
p.parentButton:SetFocus(false);
if p.parentButton == parentButton then
p:Hide();
return
end
end
p.parentButton = parentButton;
p.Check:ClearAllPoints();
p.Check:Hide();
if parentButton and menuName then
parentButton:SetFocus(true);
local selectedText = parentButton.ValueText:GetText();
local width = parentButton:GetWidth();
local data = DropDownOptions[menuName];
p.method = data.method;
local numData = #data;
for i = 1, numData do
if not p.buttons then
p.buttons = {};
end
if not p.buttons[i] then
p.buttons[i] = CreateFrame("Button", nil, p, "NarciShowcaseDropDownButtonTemplate");
p.buttons[i]:SetPoint("TOPLEFT", p, "TOPLEFT", 0, -16 + 14*(1-i));
end
p.buttons[i]:SetWidth(width);
p.buttons[i]:SetValueText(data[i][1])
if selectedText == data[i][1] then
p.Check:SetPoint("LEFT", p.buttons[i], "LEFT", 3, 0.6);
p.Check:Show();
end
p.buttons[i].value = data[i][2];
p.buttons[i]:Show();
end
for i = numData + 1, #p.buttons do
p.buttons[i]:Hide();
end
p:SetPoint("TOPLEFT", parentButton, "TOPLEFT", 0, 0);
p:SetPoint("TOPRIGHT", parentButton, "TOPRIGHT", 0, 0);
p:SetHeight(numData * 14 + 4 + 14);
p:Show();
else
p:Hide();
end
end
local function MixScripts(object, scripts)
for name, script in pairs(scripts) do
object:SetScript(name, script);
end
end
local function FadeOptionFrame_OnUpdate(self, elapsed)
if self.toAlpha > self.alpha then
self.alpha = self.alpha + elapsed * 4;
if self.alpha >= self.toAlpha then
self.alpha = self.toAlpha;
self:SetScript("OnUpdate", nil);
end
elseif self.toAlpha < self.alpha then
self.alpha = self.alpha - elapsed * 4;
if self.alpha <= self.toAlpha then
self.alpha = self.toAlpha;
self:SetScript("OnUpdate", nil);
end
else
self:SetScript("OnUpdate", nil);
end
self:SetAlpha(self.alpha);
end
local ItemTexts = {
objects = {},
numUsed = 0,
};
function ItemTexts:Release()
for i = 1, #self.objects do
self.objects[i]:Hide();
end
self.numUsed = 0;
end
function ItemTexts:Acquire()
local i = self.numUsed + 1;
self.numUsed = i;
if not self.objects[i] then
self.objects[i] = MainFrame.TextFrame:CreateFontString(nil, "OVERLAY", "NarciShowcaseFontStringTemplate");
if i == 1 then
self.objects[i]:SetPoint("TOPLEFT", MainFrame.TextFrame, "TOPLEFT", 0, 0);
else
self.objects[i]:SetPoint("TOPLEFT", self.objects[i - 1], "BOTTOMLEFT", 0, -PA_SPACING);
end
self.objects[i]:SetFont(ITEM_TEXT_FONT, ITEM_TEXT_HEIGHT, FONT_EFFECT);
self.objects[i]:SetSpacing(2 * PIXEL);
self.objects[i]:SetWidth(MAX_FONTSTRING_WIDTH);
self.objects[i]:SetTextColor(0.8, 0.8, 0.8);
end
self.objects[i]:Show();
return self.objects[i]
end
local SourceCacher = CreateFrame("Frame");
local function SourceCacher_OnUpdate(self, elapsed)
self.t = self.t + elapsed;
if self.t > 1 then
self.t = 0;
self:ProcessQueue();
self:SetScript("OnUpdate", nil);
end
end
function SourceCacher:AddToQueue(fontString, sourceID)
if not self.queue then
self.queue = {};
end
table.insert(self.queue, {fontString, sourceID});
self.t = 0;
self:SetScript("OnUpdate", SourceCacher_OnUpdate);
end
function SourceCacher:ProcessQueue()
local complete = true;
for i = 1, #self.queue do
if not self.queue[i] then
return complete
end
complete = self.queue[i][1]:SetItemTextBySourceID(self.queue[i][2]);
end
end
function SourceCacher:Stop()
self:SetScript("OnUpdate", nil);
if self.queue then
self.queue = {};
end
end
local FadeFramecripts = {};
function FadeFramecripts.OnEnter(self)
self.toAlpha = 1;
if self.alpha == 1 then
self:SetScript("OnUpdate", nil);
else
self:SetScript("OnUpdate", FadeOptionFrame_OnUpdate);
end
end
function FadeFramecripts.OnLeave(self)
if not self:IsMouseOver() or (MainFrame.BackdropSelect:HasFocus()) then
self.toAlpha = 0;
self:SetScript("OnUpdate", FadeOptionFrame_OnUpdate);
end
end
function FadeFramecripts.OnHide(self)
self:SetScript("OnUpdate", nil);
self.alpha = 0;
self:SetAlpha(0);
end
local SyncButtonScripts = {};
function SyncButtonScripts.OnClick(self)
self.AnimRotate:Play();
MainFrame:SyncModel();
end
function SyncButtonScripts.OnEnter(self)
FadeFramecripts.OnEnter(FadeOptionFrame);
FadeFrame(self.Icon, 0.15, 1);
FadeFrame(self.Label, 0.15, 1);
end
function SyncButtonScripts.OnLeave(self)
FadeFramecripts.OnLeave(FadeOptionFrame);
if not self.AnimRotate:IsPlaying() then
FadeFrame(self.Icon, 0.25, 0.5);
end
FadeFrame(self.Label, 0.25, 0);
end
local function SyncButton_OnAnimFinished(self)
local button = self:GetParent();
if not button:IsMouseOver() then
FadeFrame(button.Icon, 0.5, 0.5);
end
end
local ItemNameToggleScripts = {};
ItemNameToggleScripts.OnEnter = SyncButtonScripts.OnEnter;
function ItemNameToggleScripts.OnLeave(self)
FadeFrame(self.Icon, 0.25, 0.5);
FadeFrame(self.Label, 0.25, 0);
FadeFramecripts.OnLeave(FadeOptionFrame);
end
function ItemNameToggleScripts.OnClick(self)
local state = not DB.ShowItemName;
DB.ShowItemName = state;
MainFrame:ShowItemText(state);
end
local TopLevelButtonScripts = {};
TopLevelButtonScripts.OnEnter = SyncButtonScripts.OnEnter;
TopLevelButtonScripts.OnLeave = ItemNameToggleScripts.OnLeave;
function TopLevelButtonScripts.OnClick(self)
local state = MainFrame:GetFrameStrata() ~= "DIALOG";
if state then
self.Label:SetText(L["Lower Level"]);
self.Icon:SetTexCoord(0.5, 1, 0, 1);
MainFrame:SetFrameStrata("DIALOG");
else
self.Label:SetText(L["Raise Level"]);
self.Icon:SetTexCoord(0, 0.5, 0, 1);
MainFrame:SetFrameStrata("MEDIUM");
end
end
local CloseButtonScripts = {};
function CloseButtonScripts.OnEnter(self)
self.Icon:SetVertexColor(0.84, 0.08, 0.15);
end
function CloseButtonScripts.OnLeave(self)
self.Icon:SetVertexColor(0.4, 0.4, 0.4);
end
function CloseButtonScripts.OnClick(self)
MainFrame:Close();
end
NarciShowcaseSheatheButtonMixin = {};
function NarciShowcaseSheatheButtonMixin:OnLoad()
SheatheButton = self;
self.labelText = WEAPON or "weapon";
self.Icon:SetVertexColor(0.8, 0.8, 0.8);
self:SetPropagateKeyboardInput(true);
end
function NarciShowcaseSheatheButtonMixin:OnEnter()
FadeFramecripts.OnEnter(FadeOptionFrame);
FadeFrame(self.Icon, 0.15, 1);
FadeFrame(self.Label, 0.15, 1);
end
function NarciShowcaseSheatheButtonMixin:OnLeave()
FadeFramecripts.OnLeave(FadeOptionFrame);
FadeFrame(self.Icon, 0.25, 0.5);
FadeFrame(self.Label, 0.25, 0);
end
function NarciShowcaseSheatheButtonMixin:OnClick()
ModelScene.actor:SheatheWeapon( not ModelScene.actor:GetSheathed() );
end
local function SheatheButton_OnKeyDown(self, key)
if key == self.hotkey then
self:SetPropagateKeyboardInput(true);
self:Click();
elseif key == "ESCAPE" then
if DressUpFrame:IsVisible() then
self:SetPropagateKeyboardInput(true);
else
self:SetPropagateKeyboardInput(false);
MainFrame:Close();
end
else
self:SetPropagateKeyboardInput(true);
end
end
function NarciShowcaseSheatheButtonMixin:OnShow()
local hotkey = GetBindingKey("TOGGLESHEATH");
self.hotkey = hotkey;
if hotkey then
self.Label:SetText("|cffffd100("..hotkey..")|r "..self.labelText);
else
self.Label:SetText(self.labelText);
end
self:SetScript("OnKeyDown", SheatheButton_OnKeyDown);
end
function NarciShowcaseSheatheButtonMixin:OnHide()
self:SetScript("OnKeyDown", nil);
end
function NarciShowcaseSheatheButtonMixin:UpdateIcon()
local sheathed = ModelScene.actor and ModelScene.actor:GetSheathed();
if sheathed then
self.Icon:SetTexCoord(0, 0.5, 0, 1);
else
self.Icon:SetTexCoord(0.5, 1, 0, 1);
end
end
local function SetUpSphereTexture(variationID)
if variationID == 1 then
VariationButton.Icon:SetTexCoord(0, 0.5, 0, 0.5);
elseif variationID == 2 then
VariationButton.Icon:SetTexCoord(0.5, 1, 0, 0.5);
elseif variationID == 3 then
VariationButton.Icon:SetTexCoord(0, 0.5, 0.5, 1);
else
VariationButton.Icon:SetTexCoord(0.5, 1, 0.5, 1);
end
end
local VariationButtonScripts = {};
function VariationButtonScripts.OnEnter(self)
self.Icon:SetVertexColor(1, 1, 1);
end
function VariationButtonScripts.OnLeave(self)
self.Icon:SetVertexColor(0.67, 0.67, 0.67);
end
function VariationButtonScripts.OnClick(self, button)
if button == "LeftButton" then
VARIATION_ID = VARIATION_ID + 1;
if VARIATION_ID > 4 then
VARIATION_ID = 1;
end
else
VARIATION_ID = VARIATION_ID - 1;
if VARIATION_ID < 1 then
VARIATION_ID = 4;
end
end
SetUpSphereTexture(VARIATION_ID);
ActiveActor:TryAnimation(ANIMATION_ID);
end
local function ArrowButton_OnEnter(self)
self.Icon:SetVertexColor(0.9, 0.9, 0.9);
IDFrame.EditBox.AnimationName:Show();
end
local function ArrowButton_OnLeave(self)
self.Icon:SetVertexColor(0.5, 0.5, 0.5);
IDFrame.EditBox.AnimationName:Hide();
end
local function TryNextID(direction)
local animationID = ANIMATION_ID;
if direction > 0 then
if animationID >= MAX_ANIMATION_ID then
return
end
animationID = animationID + 1;
while (not UtilityModel:HasAnimation(animationID)) and (animationID < MAX_ANIMATION_ID) do
animationID = animationID + 1;
end
else
if animationID <= 0 then
return
end
animationID = animationID - 1;
while (not UtilityModel:HasAnimation(animationID)) and (animationID > 0) do
animationID = animationID - 1;
end
end
IDFrame.EditBox:SetText(animationID, true);
IDFrame.EditBox.AnimationName:Show();
ActiveActor:TryAnimation(animationID);
ANIMATION_ID = animationID;
end
local function ArrowButton_OnClick(self)
TryNextID(self.delta);
end
local EditBoxScripts = {};
function EditBoxScripts.OnEscapePressed(self)
self:ClearFocus();
end
function EditBoxScripts.OnEnterPressed(self)
self:ClearFocus();
end
function EditBoxScripts.OnTabPressed(self)
self:ClearFocus();
end
function EditBoxScripts.OnEditFocusGained(self)
self:HighlightText();
end
function EditBoxScripts.OnEditFocusLost(self)
self:HighlightText(0, 0);
self:SetText(self:GetNumber());
if not self:IsMouseOver() then
self.Highlight:Hide();
self.AnimationName:Hide();
end
end
function EditBoxScripts.OnTextChanged(self, userInput)
local id = self:GetNumber();
if id <= 0 then
id = 0;
self:SetText(id);
elseif id > MAX_ANIMATION_ID then
id = MAX_ANIMATION_ID;
self:SetText(id);
end
ANIMATION_ID = id;
self.AnimationName:SetText(GetAnimationName(id))
if userInput then
ActiveActor:TryAnimation(id);
end
end
function EditBoxScripts.OnEnter(self)
self.Highlight:Show();
self.AnimationName:Show();
end
function EditBoxScripts.OnLeave(self)
if not self:HasFocus() then
self.Highlight:Hide();
self.AnimationName:Hide();
end
end
function EditBoxScripts.OnMouseWheel(self, delta)
TryNextID(-delta);
end
NarciShowcaseModelSceneMixin = {};
local function ConvertCursorToFrameCoord(cursorX, cursorY, frameCenterX, frameCenterY, frameHalfWidth, frameHalfHeight)
local ratioH = (cursorX - frameCenterX)/frameHalfWidth;
if ratioH > 1 then
ratioH = 1;
elseif ratioH < -1 then
ratioH = -1;
end
local ratioV = (cursorY - frameCenterY)/frameHalfHeight;
if ratioV > 1 then
ratioV = 1;
elseif ratioV < -1 then
ratioV = -1;
end
return ratioH, ratioV
end
local function GetCameraPlaneIntersection(camX, camY, camZ, forwardX, forwardY, forwardZ)
local scalar = -camX / forwardX;
return camX + scalar*forwardX, camY + scalar*forwardY, camZ + scalar*forwardZ
end
local function PlaceMountAtGroundCenter()
--We don't want Mount to use its Z center for origin so we need to place it manually
local x, y, z = ModelScene:GetVisualGroundCenter();
local scale = MountActor:GetScale();
MountActor:SetPosition(0, 0, z/scale);
MountActor:UpdateMountShadow();
end
function NarciShowcaseModelSceneMixin:OnEnter()
FadeFramecripts.OnEnter(FadeOptionFrame);
end
function NarciShowcaseModelSceneMixin:OnLeave()
FadeFramecripts.OnLeave(FadeOptionFrame);
end
function NarciShowcaseModelSceneMixin:OnMouseDown(button)
if button == "LeftButton" then
MainFrame:SpinActor(false);
self.leftButtonDown = true;
elseif button == "RightButton" then
MainFrame:SpinActor(false);
self:ShowGuideLines(true);
self.rightButtonDown = true;
elseif button == "MiddleButton" then
self:ResetView(true);
end
self:StartUpdating();
end
function NarciShowcaseModelSceneMixin:OnMouseUp(button)
if button == "LeftButton" then
self.leftButtonDown = nil;
elseif button == "RightButton" then
self.rightButtonDown = nil;
self:ShowGuideLines(false);
--[[
local x, y, z = self.actor:GetPosition();
local fileID = self.actor:GetModelFileID();
print(string.format("file: %s offsetY: %s", fileID, z));
--]]
end
end
function NarciShowcaseModelSceneMixin:OnHide()
self:SetScript("OnUpdate", nil);
self.leftButtonDown = nil;
self.rightButtonDown = nil;
self.zooming = nil;
end
function NarciShowcaseModelSceneMixin:OnMouseWheel(delta)
local camX, camY, camZ = self:GetCameraPosition();
local shiftDown = IsShiftKeyDown();
local toX;
if delta > 0 then
if camX > MIN_CAM_DISTANCE then
if shiftDown then
toX = camX - 0.6;
else
toX = camX - 0.2;
end
if toX < MIN_CAM_DISTANCE then
toX = MIN_CAM_DISTANCE;
end
else
return
end
else
if camX < MAX_CAM_DISTANCE then
if shiftDown then
toX = camX + 0.6;
else
toX = camX + 0.2;
end
if toX > MAX_CAM_DISTANCE then
toX = MAX_CAM_DISTANCE;
end
else
return
end
end
self.fromCamX = camX;
self.toCamX = toX;
self.zooming = true;
self:StartUpdating();
end
function NarciShowcaseModelSceneMixin:ShowGuideLines(state)
self.GuideLineFrame:SetShown(state);
if state then
if self.updateLines then
if not self.GuideLineFrame.lines then
self.GuideLineFrame.lines = {};
local f = self.GuideLineFrame;
f.verticalLine = f:CreateTexture(nil, "OVERLAY");
f.verticalLine:SetPoint("TOP", self, "TOP", 0, 0);
f.verticalLine:SetPoint("BOTTOM", self, "BOTTOM", 0, 0);
f.verticalLine:SetWidth(PIXEL * 2);
f.verticalLine:SetColorTexture(1, 1, 1, 0.8);
f.horizontalLine = f:CreateTexture(nil, "OVERLAY");
f.horizontalLine:SetPoint("LEFT", self, "LEFT", 0, 0);
f.horizontalLine:SetPoint("RIGHT", self, "RIGHT", 0, 0);
f.horizontalLine:SetHeight(PIXEL * 2);
f.horizontalLine:SetColorTexture(0.6, 0.6, 0.6, 0.5);
f.actorLine = f:CreateTexture(nil, "OVERLAY");
f.actorLine:SetHeight(4);
f.actorLine:SetWidth(PIXEL * 2);
f.actorLine:SetColorTexture(0.8, 0.2, 0.2, 0.8);
end
self.GuideLineFrame.actorLine:SetHeight(self:GetHeight() + 1);
local lines = self.GuideLineFrame.lines;
local lineDistance = 100 * PIXEL;
local width = self:GetWidth();
local height = self:GetHeight();
local numLinesH = math.floor(width * 0.5 / lineDistance);
local numLinesV = math.floor(height * 0.5 / lineDistance);
local n = 0;
for i = 1, numLinesH do
n = n + 1;
if not lines[n] then
lines[n] = self.GuideLineFrame:CreateTexture(nil, "ARTWORK");
lines[n]:SetColorTexture(0.6, 0.6, 0.6, 0.5);
end
lines[n]:ClearAllPoints();
lines[n]:SetPoint("CENTER", self, "CENTER", lineDistance * i, 0);
lines[n]:SetSize(PIXEL * 2, height);
lines[n]:Show();
end
for i = 1, numLinesH do
n = n + 1;
if not lines[n] then
lines[n] = self.GuideLineFrame:CreateTexture(nil, "ARTWORK");
lines[n]:SetColorTexture(0.6, 0.6, 0.6, 0.5);
end
lines[n]:ClearAllPoints();
lines[n]:SetPoint("CENTER", self, "CENTER", lineDistance * (-i), 0);
lines[n]:SetSize(PIXEL * 2, height);
lines[n]:Show();
end
for i = 1, numLinesV do
n = n + 1;
if not lines[n] then
lines[n] = self.GuideLineFrame:CreateTexture(nil, "ARTWORK");
lines[n]:SetColorTexture(0.6, 0.6, 0.6, 0.5);
end
lines[n]:ClearAllPoints();
lines[n]:SetPoint("CENTER", self, "CENTER", 0, lineDistance * i);
lines[n]:SetSize(width, PIXEL * 2);
lines[n]:Show();
end
for i = 1, numLinesV do
n = n + 1;
if not lines[n] then
lines[n] = self.GuideLineFrame:CreateTexture(nil, "ARTWORK");
lines[n]:SetColorTexture(0.6, 0.6, 0.6, 0.5);
end
lines[n]:ClearAllPoints();
lines[n]:SetPoint("CENTER", self, "CENTER", 0, lineDistance * (-i));
lines[n]:SetSize(width, PIXEL * 2);
lines[n]:Show();
end
for i = n + 1, #self.GuideLineFrame.lines do
lines[i]:Hide();
end
self.updateLines = nil;
end
else
end
end
function NarciShowcaseModelSceneMixin:ResetView(forceReset)
if not ACTOR_IS_MOUNT or forceReset then
self:SetCameraPosition(DEFAULT_CAM_DISTANCE, 0, 0);
self.actor:SetPosition(0, 0, self.actor.defaultY or 0);
self.actor:SetScale(1);
if self.actor:IsLoaded() then
self.actor:AdjustAlignment();
if ACTOR_IS_MOUNT then
PlaceMountAtGroundCenter();
end
end
end
self.zooming = nil;
end
local function ModelScene_OnUpdate(self, elapsed)
local hasAction;
if self.leftButtonDown then
hasAction = true;
local deltaX, deltaY = GetCursorDelta();
if deltaX ~= 0 then
local yaw;
if ACTOR_IS_MOUNT then
yaw = MountActor:GetYaw();
MountActor:SetYaw(yaw + deltaX * 0.02); --0.026 when size is 800x600
else
yaw = self.actor:GetYaw();
self.actor:SetYaw(yaw + deltaX * 0.02);
end
end
end
if self.rightButtonDown then
hasAction = true;
local px, py, pz = self:GetProjectedCursor3DPosition();
local scale = self.actor.scale;
local y = py - self.from3DY + self.fromActorY;
local z = pz - self.from3DZ + self.fromActorZ;
if ACTOR_IS_MOUNT then
MountActor:SetPosition(0, y/scale, z/scale);
else
self.actor:SetPosition(0, y/scale, z/scale);
end
local centerX = self:Project3DPointTo2D(0, y, z);
self.GuideLineFrame.actorLine:SetPoint("BOTTOM", self, "BOTTOMLEFT", centerX, 0);
end
if self.zooming then
local diff = self.toCamX - self.fromCamX;
if diff > 0.01 or diff < -0.01 then
hasAction = true;
self.fromCamX = self.fromCamX + elapsed*10*diff;
self:SetCameraPosition(self.fromCamX, 0, 0)
end
end
if not hasAction then
self:SetScript("OnUpdate", nil);
end
self.actor:UpdateGroundShadow();
if ACTOR_IS_MOUNT then
MountActor:UpdateMountShadow();
end
end
function NarciShowcaseModelSceneMixin:GetProjectedCursor3DPosition()
local cursorX, cursorY = GetCursorPosition();
local ratioH, ratioV = ConvertCursorToFrameCoord(cursorX, cursorY, self.frameCenterX, self.frameCenterY, self.frameHalfWidth, self.frameHalfHeight);
local camX, camY, camZ = self:GetCameraPosition();
local fx, fy, fz = self:GetCameraForward();
local rx, ry, rz = self:GetCameraRight();
local ux, uy, uz = self:GetCameraUp();
local forwardOffset = 1;
local rightOffset = -ratioH * TAN_FOV_H;
local upOffset = ratioV * TAN_FOV_V;
local rayFX, rayFY, rayFZ = forwardOffset*fx + rightOffset*rx + upOffset*ux, forwardOffset*fy + rightOffset*ry + upOffset*uy, forwardOffset*fz + rightOffset*rz + upOffset*uz;
local px, py, pz = GetCameraPlaneIntersection(camX, camY, camZ, rayFX, rayFY, rayFZ);
return px, py, pz
end
function NarciShowcaseModelSceneMixin:GetVisualGroundCenter()
local ratioH = 0;
local ratioV = -0.8;
local camX, camY, camZ = self:GetCameraPosition();
local fx, fy, fz = self:GetCameraForward();
local rx, ry, rz = self:GetCameraRight();
local ux, uy, uz = self:GetCameraUp();
local forwardOffset = 1;
local rightOffset = -ratioH * TAN_FOV_H;
local upOffset = ratioV * TAN_FOV_V;
local rayFX, rayFY, rayFZ = forwardOffset*fx + rightOffset*rx + upOffset*ux, forwardOffset*fy + rightOffset*ry + upOffset*uy, forwardOffset*fz + rightOffset*rz + upOffset*uz;
local px, py, pz = GetCameraPlaneIntersection(camX, camY, camZ, rayFX, rayFY, rayFZ);
return px, py, pz
end
function NarciShowcaseModelSceneMixin:StartUpdating()
self.fromCursorX, self.fromCursorY = GetCursorPosition();
self.frameCenterX, self.frameCenterY = self:GetCenter();
local w, h = self:GetSize();
self.frameHalfWidth, self.frameHalfHeight = 0.5*w, 0.5*h;
self.fromActorX, self.fromActorY, self.fromActorZ = self.actor:GetPosition();
local scale = self.actor:GetScale();
self.fromActorX = self.fromActorX * scale;
self.fromActorY = self.fromActorY * scale;
self.fromActorZ = self.fromActorZ * scale;
self.from3DX, self.from3DY, self.from3DZ = self:GetProjectedCursor3DPosition();
self:SetScript("OnUpdate", ModelScene_OnUpdate);
end
NarciShowcaseSpinButtonMixin = {};
local function SetUpSpinTexture(self, sequence)
local row = math.floor( (sequence - 1) * 0.25);
local col = sequence - row * 4 - 1;
self.SpinTexture:SetTexCoord(0.25*col, 0.25*(col + 1), 0.25*row, 0.25*(row + 1));
self.sequence = sequence;
end
local function SpinButton_OnUpdate(self, elapsed)
self.t = self.t + elapsed;
if self.t >= 0.125 then
self.t = 0;
self.sequence = self.sequence + 1;
if self.sequence > 16 then
self.sequence = 1;
end
SetUpSpinTexture(self, self.sequence);
end
end
function NarciShowcaseSpinButtonMixin:OnLoad()
self.minTextWidth = 24;
self.Background:SetAlpha(0.5);
SetUpSpinTexture(self, 1);
self:SetLabelText(L["Spin"]);
end
function NarciShowcaseSpinButtonMixin:OnEnter()
self.t = 0.0625;
self:SetScript("OnUpdate", SpinButton_OnUpdate);
FadeFrame(self.Background, 0.2, 1);
end
function NarciShowcaseSpinButtonMixin:OnLeave()
self:SetScript("OnUpdate", nil);
FadeFrame(self.Background, 0.2, 0.5);
end
function NarciShowcaseSpinButtonMixin:OnHide()
self:SetScript("OnUpdate", nil);
SetUpSpinTexture(self, 1);
self.AnimPushed:Stop();
end
function NarciShowcaseSpinButtonMixin:SetLabelText(text)
self.Label:SetText(text);
self:SetWidth( math.max(self.Label:GetWrappedWidth(), self.minTextWidth) + 28);
end
function NarciShowcaseSpinButtonMixin:OnMouseDown(button)
if button == "LeftButton" then
self.AnimPushed:Stop();
self.AnimPushed.Hold:SetDuration(20);
self.AnimPushed:Play();
end
end
function NarciShowcaseSpinButtonMixin:OnMouseUp(button)
if button == "LeftButton" then
self.AnimPushed.Hold:SetDuration(0);
end
end
function NarciShowcaseSpinButtonMixin:OnShow()
self:Enable();
self:EnableMouse(true);
end
function NarciShowcaseSpinButtonMixin:OnClick()
MainFrame:SpinActor(true);
end
function NarciShowcaseSpinButtonMixin:FadeIn()
self:Enable();
self:EnableMouse(true);
FadeFrame(self, 0.25, 1);
end
function NarciShowcaseSpinButtonMixin:FadeOut()
self:Disable();
self:EnableMouse(false);
FadeFrame(self, 0.25, 0);
end
local function AnimationSlider_OnValueChangedFunc(self, value)
ModelScene.actor:PauseAtFrame(value);
end
local function AnimationSlider_OnMouseDownFunc(self)
LOOP_ANIMATION = false;
LoopToggle:UpdateVisual();
end
local function SetUpTooltipText(infobutton, customText, offsetX)
Tooltip:Hide();
Tooltip.AnimIn:Stop();
if infobutton then
Tooltip:ClearAllPoints();
Tooltip:SetPoint("TOPLEFT", infobutton, "TOPRIGHT", 2 + (offsetX or 0), 3);
if customText then
Tooltip.Text:SetText(customText);
else
Tooltip.Text:SetText(L[infobutton.tooltipKey]);
end
local width = Tooltip.Text:GetWrappedWidth();
Tooltip:SetSize(width + 12, Tooltip.Text:GetHeight() + 12);
Tooltip.AnimIn:Play();
Tooltip:Show();
Tooltip:SetFrameStrata("TOOLTIP");
end
end
local DropDownPanelScripts = {};
function DropDownPanelScripts.OnShow(self)
self:RegisterEvent("GLOBAL_MOUSE_DOWN");
end
function DropDownPanelScripts.OnHide(self)
self:Hide();
self:UnregisterEvent("GLOBAL_MOUSE_DOWN");
if self.parentButton then
self.parentButton:SetFocus(false);
self.parentButton = nil;
end
end
function DropDownPanelScripts.OnEvent(self)
if not (self:IsMouseOver() or (self.parentButton and self.parentButton:IsMouseOver())) then
self:Hide();
end
end
local OBSInfoScripts = {};
function OBSInfoScripts.OnEnter(self)
self.Icon:SetVertexColor(1, 1, 1);
local w, h = GetPhysicalScreenSize();
w = (w - IMAGE_WIDTH)*0.5;
h = (h - IMAGE_HEIGHT)*0.5;
local tooltipText = string.format("OBS Settings:\nVideo Resolution: %sx%s\nCrop Filter: X:%s, Y:%s", IMAGE_WIDTH, IMAGE_HEIGHT, w, h);
SetUpTooltipText(self, tooltipText, 8);
end
function OBSInfoScripts.OnLeave(self)
self.Icon:SetVertexColor(0.5, 0.5, 0.5);
SetUpTooltipText();
end
local OutlineToggleScripts = {};
OutlineToggleScripts.OnLeave = OBSInfoScripts.OnLeave;
function OutlineToggleScripts.OnEnter(self)
self.Icon:SetVertexColor(1, 1, 1);
local tooltipText = (self.state and L["Outline Hide"]) or L["Outline Show"];
SetUpTooltipText(self, tooltipText, 8);
end
function OutlineToggleScripts.OnClick(self)
local state = not MainFrame.OutlineFrame:IsShown();
MainFrame.OutlineFrame:SetShown(state);
if state then
--self.Label:SetText(L["Outline Hide"]);
self.Icon:SetTexCoord(0.5, 1, 0, 1);
else
--self.Label:SetText(L["Outline Show"]);
self.Icon:SetTexCoord(0, 0.5, 0, 1);
end
self.state = state;
SetUpTooltipText();
end
---------------------Background Options---------------------
local function BGNode_OnClick(self)
if self.id == 2 then
--Image
MainFrame.ModelScene.Backdrop:Show();
MainFrame.ModelScene.BackdropPreview:Hide();
MainFrame.ModelScene.Vignetting:Show();
MainFrame.TextFrame.Divider:Hide();
GroundShadow:Show();
local typeID = DB.BackgroundImageType;
if typeID and self.SubFrame.Nodes[typeID] then
self.SubFrame.Nodes[typeID]:Click();
else
self.SubFrame.Nodes[1]:Click();
end
elseif self.id == 3 then
--Transparent
MainFrame.ModelScene.Backdrop:Hide();
MainFrame.ModelScene.BackdropPreview:Hide();
MainFrame.ModelScene.Vignetting:Show();
MainFrame.TextFrame.Divider:Hide();
GroundShadow:Show();
else
--Color
MainFrame.ModelScene.Backdrop:Show();
MainFrame.ModelScene.BackdropPreview:Hide();
MainFrame.ModelScene.Vignetting:Hide();
MainFrame.TextFrame.Divider:Show();
if not self.SubFrame.selectedID then
self.SubFrame.selectedID = 1;
end
self.SubFrame.Nodes[self.SubFrame.selectedID]:Click();
end
DB.BackgroundType = self.id;
end
local function BGNode_OnSelected(self, state)
if state then
self.Label:SetTextColor(0.8, 0.8, 0.8);
else
self.Label:SetTextColor(0.5, 0.5, 0.5);
end
if self.SubFrame then
self.SubFrame:SetShown(state);
end
end
local function ColorNode_OnClick(self)
if self.id == 1 then
GroundShadow:Show();
MainFrame.TextFrame.Divider:Show();
ModelScene.Backdrop:SetColorTexture(0.1, 0.1, 0.1);
else
GroundShadow:Hide();
MainFrame.TextFrame.Divider:Hide();
if self.id == 2 then
ModelScene.Backdrop:SetColorTexture(1, 0, 0);
elseif self.id == 3 then
ModelScene.Backdrop:SetColorTexture(0, 1, 0);
elseif self.id == 4 then
ModelScene.Backdrop:SetColorTexture(0, 0, 1);
end
end
self:GetParent().selectedID = self.id;
end
local function ColorNode_OnSelected(self, state)
self.HighlightTexture:SetVertexColor(1, 1, 1, 0.5);
self:UnlockHighlight();
end
local function UseCustomBackground(fileName)
if fileName then
ModelScene.Backdrop:SetTexture("Interface\\AddOns\\"..fileName);
else
ModelScene.Backdrop:SetColorTexture(0.1, 0.1, 0.1);
end
end
local FileNameEditBoxScripts = {};
function FileNameEditBoxScripts.OnEscapePressed(self)
self:ClearFocus();
end
function FileNameEditBoxScripts.OnEnterPressed(self)
self:ClearFocus();
end
function FileNameEditBoxScripts.OnTabPressed(self)
self:ClearFocus();
end
function FileNameEditBoxScripts.OnEditFocusGained(self)
end
function FileNameEditBoxScripts.OnEditFocusLost(self)
self:HighlightText(0, 0);
SetUpTooltipText();
if not self:IsMouseOver() then
self:GetParent():OnLeave();
end
end
function FileNameEditBoxScripts.OnTextChanged(self, userInput)
if userInput then
local fileName = self:GetText();
fileName = string.gsub(fileName, "(%..+)", ""); --remove file suffix
if fileName and fileName ~= "" then
UseCustomBackground(fileName);
DB.CustomFileName = fileName;
end
end
end
function FileNameEditBoxScripts.OnEnter(self)
SetUpTooltipText(self, L["File Tooltip"], 8);
self:GetParent():OnEnter();
end
function FileNameEditBoxScripts.OnLeave(self)
if not self:HasFocus() then
SetUpTooltipText();
self:GetParent():OnLeave();
end
end
local function CreateBackgroundOptions(tab)
local function CreateLink(parent, direction)
local tex = parent:CreateTexture(nil, "BACKGROUND");
tex:SetSize(6, 6);
tex:SetTexture("Interface\\AddOns\\Narcissus\\Art\\Modules\\Showcase\\NodeButton", nil, nil, "TRILINEAR");
tex:SetVertexColor(0.25, 0.25, 0.25);
if direction == "h" then
tex:SetTexCoord(0, 0.25, 0.9375, 1); --horizontal line
else
tex:SetTexCoord(0.25, 0.3125, 0.75, 1); --vertical line
end
return tex
end
local function CreateSubFrame(parent)
local f = CreateFrame("Frame", nil, parent);
f:Hide();
f:SetSize(14, 14);
f:SetPoint("LEFT", parent, "LEFT", 70, 0);
parent.SubFrame = f;
return f
end
local function CreateLabel(parent, text)
local label = parent:CreateFontString(nil, "OVERLAY", "NarciFontUniversal9");
label:SetPoint("LEFT", parent, "RIGHT", 2, 0);
label:SetJustifyH("LEFT");
label:SetJustifyV("MIDDLE");
label:SetText(text);
parent.Label = label;
local width = label:GetWidth();
if width < 14 then
width = 14;
elseif width > 62 then
width = 62;
end
parent:SetHitRectInsets(0, -width - 10, -2, -2);
return label
end
local link = CreateLink(tab, "v");
local distance = 20;
local button;
local labelNames = {COLOR, L["Picture"], NONE};
for i = 1, 3 do
button = CreateFrame("Button", nil, tab, "NarciShowcaseSharedNodeTemplate");
button.id = i;
button.onClickFunc = BGNode_OnClick;
button.onSelectedFunc = nil;
button:SetPoint("TOPLEFT", tab, "TOPLEFT", 16, -16 + distance*(1 - i));
CreateLabel(button, labelNames[i]);
button.onClickFunc = BGNode_OnClick;
button.onSelectedFunc = BGNode_OnSelected;
button.Border:SetTexCoord(0.5, 1, 0.5, 1);
if i == 1 then
link:SetPoint("TOP", button, "CENTER", 0, 0);
elseif i == 3 then
link:SetPoint("BOTTOM", button, "CENTER", 0, 0);
end
end
--Colors
local subFrame = CreateSubFrame(tab.Nodes[1]);
link = CreateLink(subFrame, "h");
for i = 1, 4 do
button = CreateFrame("Button", nil, subFrame, "NarciShowcaseSharedNodeTemplate");
button.id = i;
button:SetPoint("LEFT", subFrame, "LEFT", 24 * (i - 1), 0);
button.ColorTexture = button:CreateTexture(nil, "OVERLAY");
button.ColorTexture:SetSize(16, 16);
button.ColorTexture:SetPoint("CENTER", button, "CENTER", 0, 0);
button.ColorTexture:SetTexture("Interface\\AddOns\\Narcissus\\Art\\Modules\\Showcase\\NodeButton", nil, nil, "TRILINEAR");
button.ColorTexture:SetTexCoord(0.75, 1, 0, 0.25);
button.onSelectedFunc = ColorNode_OnSelected;
button.onClickFunc = ColorNode_OnClick;
if i == 2 then
button.ColorTexture:SetVertexColor(1, 0, 0);
elseif i == 3 then
button.ColorTexture:SetVertexColor(0, 1, 0);
elseif i == 4 then
button.ColorTexture:SetVertexColor(0, 0, 1);
link:SetPoint("RIGHT", button, "CENTER", 0, 0);
else
if i == 1 then
link:SetPoint("LEFT", button, "CENTER", 0, 0);
end
button.ColorTexture:SetVertexColor(0.2, 0.2, 0.2);
end
end
--Image
subFrame = CreateSubFrame(tab.Nodes[2]);
for i = 1, 4 do
button = CreateFrame("Button", nil, subFrame, "NarciShowcaseSharedNodeTemplate");
button.id = i;
button.onSelectedFunc = BGNode_OnSelected;
if i == 1 then
button:SetPoint("TOPLEFT", tab, "TOPLEFT", 86, -16);
CreateLabel(button, CLASS);
button.onClickFunc = function(self)
UseCurrentClassBackground();
DB.BackgroundImageType = self.id;
end
elseif i == 2 then
button:SetPoint("TOPLEFT", tab, "TOPLEFT", 156, -16);
CreateLabel(button, RACE);
button.onClickFunc = function(self)
UseCurrentRaceBackground();
DB.BackgroundImageType = self.id;
end
elseif i == 3 then
button:SetPoint("TOPLEFT", tab, "TOPLEFT", 86, -36);
CreateLabel(button, L["Preset"]);
button.onClickFunc = function(self)
UseModelBackgroundImage();
DB.BackgroundImageType = self.id;
end
local f = CreateFrame("Frame", nil, button, "NarciShowcaseThreeSliceFrameTemplate");
button.SubFrame = f;
f:SetPoint("LEFT", button.Label, "RIGHT", 4, 0);
f:SetPoint("RIGHT", tab, "RIGHT", -16, 0);
f:SetHeight(14);
f:SetFrameLevel(button:GetFrameLevel() + 2);
f.Arrow = f:CreateTexture(nil, "OVERLAY");
f.Arrow:SetSize(14, 14);
f.Arrow:SetPoint("RIGHT", f, "RIGHT", 0, 0);
f.Arrow:SetTexture("Interface/AddOns/Narcissus/Art/Modules/Showcase/NewWindowMark");
f.ValueText = f:CreateFontString(nil, "OVERLAY", "NarciFontUniversal9");
f.ValueText:SetPoint("LEFT", f, "LEFT", 4, 0);
f.ValueText:SetPoint("RIGHT", f, "RIGHT", -14, 0);
f.ValueText:SetHeight(14);
f.ValueText:SetMaxLines(1);
f.ValueText:SetTextColor(0.9, 0.9, 0.9);
f.ValueText:SetText("Select");
f.ValueText:SetJustifyH("LEFT");
f:OnLeave();
f:SetScript("OnMouseDown", function()
MainFrame.BackdropSelect:Toggle();
end);
MainFrame.BackdropSelect.swtich = f;
elseif i == 4 then
button:SetPoint("TOPLEFT", tab, "TOPLEFT", 86, -56);
CreateLabel(button, L["File"]);
button.onClickFunc = function(self)
UseCustomBackground(DB.CustomFileName);
self.SubFrame.EditBox:SetText(DB.CustomFileName or "");
DB.BackgroundImageType = self.id;
end
local f = tab.EditFrame;
button.SubFrame = f;
f:SetParent(button);
f:ClearAllPoints();
f:SetPoint("LEFT", button.Label, "RIGHT", 4, 0);
f:SetPoint("RIGHT", tab, "RIGHT", -16, 0);
f.EditBox:SetJustifyH("LEFT");
MixScripts(f.EditBox, FileNameEditBoxScripts);
end
end
end
local function UpdateMountActor(resetModel)
local mountID;
if MountJournal and MountJournal:IsVisible() and MountJournal.selectedMountID then
mountID = MountJournal.selectedMountID;
elseif IsMounted() then
local UnitBuff = UnitBuff;
local GetMountFromSpell = C_MountJournal.GetMountFromSpell;
local i = 1;
local _, count, duration;
local spellID = 0;
while spellID do
_, _, count, _, duration, _, _, _, _, spellID = UnitBuff("player", i, "PLAYER");
if spellID then
if count == 0 and duration == 0 then
mountID = GetMountFromSpell(spellID);
if mountID then
break
else
i = i + 1;
end
else
i = i + 1;
end
else
break
end
end
else
mountID = MainFrame.mountID;
end
if mountID == MainFrame.mountID and not resetModel then
return
end
if mountID and mountID ~= 0 then
local creatureDisplayID, _, _, isSelfMount, _, modelSceneID, animID, spellVisualKitID, disablePlayerMountPreview = C_MountJournal.GetMountInfoExtraByID(mountID);
if not MountActor then
MountActor = ModelScene:CreateActor(nil, "NarciAutoFittingActorTemplate");
MountActor.actorType = "mount";
MountActor:SetUseCenterForOrigin(false, false, false);
MountActor:SetPosition(0, 0, 0);
--MountActor:SetParticleOverrideScale(0);
MA = MountActor;
end
if resetModel then
MountActor:ClearModel();
end
MountActor:Show();
MountActor:SetYaw(0);
MountActor:SetModelByCreatureDisplayID(creatureDisplayID);
MountActor.creatureName = C_MountJournal.GetMountInfoByID(mountID);
if (isSelfMount) then
MountActor:SetAnimationBlendOperation(1); --LE_MODEL_BLEND_OPERATION_NONE
MountActor:SetAnimation(618);
else
MountActor:SetAnimationBlendOperation(2); --LE_MODEL_BLEND_OPERATION_ANIM
MountActor:SetAnimation(0);
end
ANIMATION_ID = 0;
IDFrame.EditBox:SetText(0);
local calcMountScale = MountActor:CalculateMountScale(PlayerActor);
local inverseScale = 1 / calcMountScale;
PlayerActor:SetScale( inverseScale );
PlayerActor:SheatheWeapon(true);
PlayerActor:SetYaw(0);
PlayerActor:SetUseCenterForOrigin(false, false, false);
MountActor:AttachToMount(PlayerActor, animID, spellVisualKitID); --fun fact: a new player model is generated and attached to the mount
ACTOR_IS_MOUNT = true;
ModelScene.actor = MountActor;
ActiveActor = MountActor;
MainFrame.mountID = mountID;
else
end
end
------------------------------------------------------------
NarciOutfitShowcaseMixin = {};
function NarciOutfitShowcaseMixin:OnLoad()
MainFrame = self;
--if UISpecialFrames then
-- table.insert(UISpecialFrames, self:GetName());
--end
end
function NarciOutfitShowcaseMixin:OnShow()
if self.Init then
self:Init();
self:RegisterEvent("DISPLAY_SIZE_CHANGED");
end
if self.pixelChanged then
self:OnDisplaySizeChanged();
end
self:SyncModel();
self.cvarMSAA = GetCVar("MSAAQuality");
if self.createSplash then
self.createSplash = nil;
local f = CreateFrame("Frame", nil, self, "NarciShowcaseSplashFrameTemplate");
f:SetScript("OnHide", function()
DB.ShowSplash = false;
end);
end
end
function NarciOutfitShowcaseMixin:Init()
ModelScene = self.ModelScene;
ControlPanel = self.ControlPanel;
UtilityModel = self.ModelScene.UtilityModel;
Tooltip = self.Tooltip;
TabSelection = self.ControlPanel.NavBar.TabSelection;
TabSelection.x = 0;
GroundShadow = self.ModelScene.GroundShadow;
NarciAPI.NineSliceUtil.SetUpBackdrop(Tooltip, "rectR6");
NarciAPI.NineSliceUtil.SetBackdropColor(Tooltip, 0.1, 0.1, 0.1);
NarciAPI.NineSliceUtil.SetUpBorder(Tooltip, "shadowR6");
NarciAPI.NineSliceUtil.SetBorderColor(Tooltip, 0.5, 0.5, 0.5);
DropDownPanel = self.ControlPanel.DropDownPanel;
DropDownPanel.Check:SetVertexColor(0.66, 0.66, 0.66);
NarciAPI.NineSliceUtil.SetUpBackdrop(DropDownPanel, "rectR6");
NarciAPI.NineSliceUtil.SetBackdropColor(DropDownPanel, 0.1, 0.1, 0.1);
NarciAPI.NineSliceUtil.SetUpBorder(DropDownPanel, "shadowR6");
NarciAPI.NineSliceUtil.SetBorderColor(DropDownPanel, 0.5, 0.5, 0.5);
MixScripts(DropDownPanel, DropDownPanelScripts);
PlayerActor = ModelScene:CreateActor(nil, "NarciAutoFittingActorTemplate");
PlayerActor:SetUseCenterForOrigin(false, false, true);
PlayerActor:SetPosition(0, 0, 0);
ActiveActor = PlayerActor;
ModelScene.actor = PlayerActor;
self.actor = PlayerActor;
ModelScene:SetCameraPosition(DEFAULT_CAM_DISTANCE, 0, 0);
ModelScene:SetCameraOrientationByYawPitchRoll(PI, 0, 0);
ModelScene:SetCameraFieldOfView(FOV_DIAGONAL);
ModelScene:SetLightDiffuseColor(0.8, 0.8, 0.8);
ModelScene:SetLightAmbientColor(0.6, 0.6, 0.6);
ModelScene:SetLightPosition(1, 0, 1);
ModelScene:SetLightDirection(-1, 0, -1);
ModelScene.GuideLineFrame.Mouse:SetTexture("Interface/AddOns/Narcissus/Art/Keyboard/Mouse", nil, nil, "TRILINEAR");
ModelScene.GuideLineFrame.Mouse:SetTexCoord(0.5, 0.75, 0, 1);
ModelScene.GuideLineFrame.MouseLabel:SetText("Reset camera");
--ModelScene:SetPaused(true, true);
FadeOptionFrame = self.FadeOptionFrame;
FadeOptionFrame.alpha = 0;
FadeOptionFrame:SetAlpha(0);
MixScripts(FadeOptionFrame, FadeFramecripts);
MixScripts(FadeOptionFrame.SyncButton, SyncButtonScripts);
FadeOptionFrame.SyncButton.AnimRotate:SetScript("OnFinished", SyncButton_OnAnimFinished);
FadeOptionFrame.SyncButton.Label:SetText(L["Sync"]);
FadeOptionFrame.SyncButton.Icon:SetVertexColor(0.8, 0.8, 0.8);
MixScripts(FadeOptionFrame.TopLevelButton, TopLevelButtonScripts);
FadeOptionFrame.TopLevelButton.Label:SetText(L["Raise Level"]);
MixScripts(FadeOptionFrame.ItemNameToggle, ItemNameToggleScripts);
MixScripts(FadeOptionFrame.CloseButton, CloseButtonScripts);
CloseButtonScripts.OnLeave(FadeOptionFrame.CloseButton);
--Animation Tab
VariationButton = self.ControlPanel.AnimationTab.VariationButton;
VariationButton.Icon:SetTexture("Interface/AddOns/Narcissus/Art/Modules/Showcase/VariationSphere", nil, nil, "TRILINEAR");
VariationButton.Label:SetText(L["Animation Variation"]);
MixScripts(VariationButton, VariationButtonScripts);
VariationButtonScripts.OnLeave(VariationButton);
SetUpSphereTexture(1);
IDFrame = self.ControlPanel.AnimationTab.IDFrame;
IDFrame.Label:SetText("ID");
IDFrame.ArrowLeft:SetScript("OnEnter", ArrowButton_OnEnter);
IDFrame.ArrowLeft:SetScript("OnLeave", ArrowButton_OnLeave);
IDFrame.ArrowLeft:SetScript("OnClick", ArrowButton_OnClick);
IDFrame.ArrowLeft.delta = -1;
ArrowButton_OnLeave(IDFrame.ArrowLeft);
IDFrame.ArrowRight:SetScript("OnEnter", ArrowButton_OnEnter);
IDFrame.ArrowRight:SetScript("OnLeave", ArrowButton_OnLeave);
IDFrame.ArrowRight:SetScript("OnClick", ArrowButton_OnClick);
IDFrame.ArrowRight.delta = 1;
ArrowButton_OnLeave(IDFrame.ArrowRight);
MixScripts(IDFrame.EditBox, EditBoxScripts);
IDFrame.EditBox:SetText(0);
AnimationSlider = self.ControlPanel.AnimationTab.AnimationSlider;
AnimationSlider.onValueChangedFunc = AnimationSlider_OnValueChangedFunc;
AnimationSlider.onMouseDownFunc = AnimationSlider_OnMouseDownFunc;
--Image Settings
local widget = self.ControlPanel.LayoutTab.ImageSize;
widget.Label:SetText(L["Image Size"]);
widget.ValueText:SetText("800 x 600 (4:3)");
widget = ControlPanel.LayoutTab.RotationPeriod;
widget.Label:SetText(L["Rotation Period"]);
widget.ValueText:SetText("4");
widget = ControlPanel.LayoutTab.FontSize;
widget.Label:SetText(L["Font Size"]);
widget.ValueText:SetText("16");
widget = self.ControlPanel.LayoutTab.OBSInfo;
--widget.Icon:SetVertexColor(0.5, 0.5, 0.5);
MixScripts(widget, OBSInfoScripts);
MixScripts(self.ControlPanel.LayoutTab.OutlineToggle, OutlineToggleScripts);
self.playerGUID = UnitGUID("player");
--Create Navigation Buttons
local bar = ControlPanel.NavBar;
local navButton;
local navButtonNames = {
"Animation", "Image", "Quality", "Background",
};
for i = 1, #navButtonNames do
navButton = CreateFrame("Button", nil, bar, "NarciShowcaseNavButtonTemplate");
if i == 1 then
navButton:SetPoint("BOTTOMLEFT", bar, "BOTTOMLEFT", 4, 0);
else
navButton:SetPoint("BOTTOMLEFT", bar.NavButtons[i - 1], "BOTTOMRIGHT", 0, 0);
end
navButton:SetButtonText(L["Turntable Tab "..navButtonNames[i]]);
navButton.id = i;
end
bar.NavButtons[2]:Click();
local fps = NarciFramerateIndicator;
fps:ClearAllPoints();
fps:SetParent(self.ControlPanel.QualityTab);
fps:SetPoint("TOPRIGHT", self.ControlPanel.QualityTab, "TOPRIGHT", -7, -48);
fps:Show();
--Backdrop Tab
CreateBackgroundOptions(self.ControlPanel.BackgroundTab);
--Load User Settings
LoadSettings();
--DEBUG Create drop-shadow
--NarciAPI.NineSliceUtil.SetUpBorder(self.DropShadow, "shadowR0");
self.ModelScene.BackdropPreview:SetTexture("Interface/AddOns/Narcissus/Art/Modules/Showcase/BackdropThumbnails", nil, nil, "NEAREST");
self.Init = nil;
NarciOutfitShowcaseMixin.Init = nil;
end
function NarciOutfitShowcaseMixin:UpdateWidgetSize()
local h = 14;
IDFrame:SetSize(4*h, h);
IDFrame.ArrowLeft:SetSize(h, h);
IDFrame.ArrowRight:SetSize(h, h);
IDFrame.EditBox:SetSize(2*h, h);
VariationButton:SetSize(h, h);
end
function NarciOutfitShowcaseMixin:UpdateTextSize()
local multiplier = IMAGE_HEIGHT/600;
if multiplier < 1 then
multiplier = 1;
end
ITEM_TEXT_HEIGHT = PIXEL * FONT_WEIGHT * multiplier;
PA_SPACING = PA_SPACING_WEIGHT * PIXEL * multiplier;
local spacing = 2 * PIXEL;
local offsetY = -PA_SPACING;
local object;
for i = 1, #ItemTexts.objects do
object = ItemTexts.objects[i];
object:SetFont(ITEM_TEXT_FONT, ITEM_TEXT_HEIGHT, FONT_EFFECT);
object:SetSpacing(spacing);
object:SetWidth(MAX_FONTSTRING_WIDTH);
if i > 1 then
object:SetPoint("TOPLEFT", ItemTexts.objects[i - 1], "BOTTOMLEFT", 0, offsetY);
end
end
end
function NarciOutfitShowcaseMixin:UpdateSize(resetCamera)
local _, screenHeight = GetPhysicalScreenSize();
local pixel = (768/screenHeight);
PIXEL = pixel;
local frameWidth = pixel*IMAGE_WIDTH;
local frameHeight = pixel*IMAGE_HEIGHT;
local modelWidth = frameHeight * MODEL_WIDTH_RATIO;
MAX_FONTSTRING_WIDTH = frameWidth - modelWidth - (32 *2*PIXEL);
--local modelWidth = pixel * 600;
--local frameHeight = modelWidth *4/3;
--local frameWidth = frameHeight*4/3;
self:SetSize(frameWidth, frameHeight);
self.ModelScene:SetSize(modelWidth, frameHeight);
self.ModelScene.BackdropPreview:SetSize(frameHeight, frameHeight);
self.BackdropSelect:SetFrameWidth(frameHeight * 4/3 - modelWidth);
self.TextFrame.Divider:SetWidth(16 * pixel);
self:UpdateTextSize();
self.ModelScene.updateLines = true;
self.pixelChanged = nil;
local w, h = self.ModelScene:GetSize();
local aspect = 0.5*w/h;
self.ModelScene.Backdrop:SetTexCoord(0.5 - aspect, 0.5 + aspect, 0, 1);
self.OutlineFrame.LeftLine:SetSize(2*pixel, frameHeight + 4*pixel);
self.OutlineFrame.RightLine:SetSize(2*pixel, frameHeight + 4*pixel);
self.OutlineFrame.TopLine:SetSize(frameWidth + 4*pixel, 2*pixel);
self.OutlineFrame.BottomLine:SetSize(frameWidth + 4*pixel, 2*pixel);
--self.ControlPanel:SetPoint("TOP", self, "BOTTOM", 0, -12*pixel);
if resetCamera then
self.ModelScene:ResetView();
end
end
function NarciOutfitShowcaseMixin:SyncModel()
--retrieve the outfit data from dressing room
--/run NarciOutfitShowcase:SyncModel()
local isSheathed = PlayerActor:GetSheathed();
PlayerActor:SetScale(1);
PlayerActor:SetModelByUnit("player", isSheathed);
PlayerActor.bowData = nil;
local sourceActor;
if WardrobeTransmogFrame and WardrobeTransmogFrame:IsVisible() and WardrobeTransmogFrame.ModelScene then
sourceActor = WardrobeTransmogFrame.ModelScene:GetPlayerActor();
self:UnregisterEvent("INSPECT_READY");
elseif DressUpFrame:IsShown() then
sourceActor = DressUpFrame.ModelScene:GetPlayerActor();
self:UnregisterEvent("INSPECT_READY");
else
sourceActor = PlayerActor;
self:RegisterEvent("INSPECT_READY");
NotifyInspect("player"); --it seems they fixed the artifact issue
end
local transmogInfoList = sourceActor and sourceActor:GetItemTransmogInfoList();
if transmogInfoList then
PlayerActor:Undress();
for slotID, info in pairs(transmogInfoList) do
if slotID == 16 or slotID == 17 then
local transmogInfo = PlayerActor:GetItemTransmogInfo(slotID);
if not (transmogInfo and transmogInfo:IsEqual(info)) then
PlayerActor:SetItemTransmogInfo(info, slotID);
end
else
PlayerActor:SetItemTransmogInfo(info, slotID);
end
end
else
return
end
PlayerActor:SheatheWeapon(isSheathed);
if self.mountMode then
UpdateMountActor(true);
end
self:UpdateItemText(transmogInfoList);
end
local function IsValidTransmogInfo(slotID, info)
return (info.appearanceID > 0) and ((slotID ~= 5 and slotID ~= 19) or ( not IsHiddenVisual(info.appearanceID) )); --skip hidden tabard/shirt
end
function NarciOutfitShowcaseMixin:UpdateItemText(transmogInfoList)
ItemTexts:Release();
SourceCacher:Stop();
NUM_DOUBLE_LINE_OBJECT = 0;
local slotID, fontString;
for i = 1, #PRINT_ORDERS do
slotID = PRINT_ORDERS[i];
if IsValidTransmogInfo(slotID, transmogInfoList[slotID]) then
fontString = ItemTexts:Acquire();
fontString:SetItemTextBySlotInfo(slotID, transmogInfoList[slotID]);
end
end
--[[
if self.mountMode and ACTOR_IS_MOUNT then
if MountActor.creatureName then
fontString = ItemTexts:Acquire();
fontString:SetItemText(MountActor.creatureName);
end
end
--]]
self:UpdateAlignment();
end
function NarciOutfitShowcaseMixin:RearangeControlPanel()
--Make ControlPanel fade if it goes out of the screen
if self.ControlPanel:GetTop() + 4 > self:GetBottom() then
if self.extruding then return end
self.extruding = true;
local function ControlPanel_OnUpdate(f, elapsed)
f.t = f.t + elapsed;
if f.t > 1 then
f.t = 0;
if f:IsMouseOver() or (DropDownPanel:IsShown() and DropDownPanel:IsMouseOver()) then
if f:GetAlpha() < 1 then
f.delta = 4;
else
f.delta = nil;
end
else
if f:GetAlpha() > 0 then
f.delta = -2;
else
f.delta = nil;
end
end
if f.delta then
f.alpha = f:GetAlpha();
end
end
if f.delta then
f.alpha = f.alpha + f.delta * elapsed;
if f.alpha >= 1 then
f.alpha = 1;
f.delta = nil;
elseif f.alpha <= 0 then
f.alpha = 0;
f.delta = nil;
end
f:SetAlpha(f.alpha);
end
end
self.ControlPanel.t = 0;
self.ControlPanel:SetScript("OnEnter", function(f)
f.t = 2;
end);
self.ControlPanel:SetScript("OnLeave", function(f)
f.t = 0;
end);
self.ControlPanel:SetScript("OnUpdate", ControlPanel_OnUpdate);
else
if self.extruding then
self.extruding = nil;
self.ControlPanel:SetScript("OnEnter", nil);
self.ControlPanel:SetScript("OnLeave", nil);
self.ControlPanel:SetScript("OnUpdate", nil);
self.ControlPanel:SetAlpha(1);
end
end
end
function NarciOutfitShowcaseMixin:OnDisplaySizeChanged(resetCamera)
--Screen resolution / Main frame size changed
self:UpdateSize(resetCamera);
self:UpdateAlignment();
PlayerActor:UpdateGroundShadow();
self:RearangeControlPanel();
end
function NarciOutfitShowcaseMixin:OnEvent(event, ...)
if event == "INSPECT_READY" then
local guid = ...;
if guid == self.playerGUID then
self:UpdateItemText( C_TransmogCollection.GetInspectItemTransmogInfoList() ); --fix for paired weapons
self:UnregisterEvent(event);
end
elseif event == "DISPLAY_SIZE_CHANGED" then
if self:IsShown() then
C_Timer.After(0, function()
self:OnDisplaySizeChanged();
end);
else
self.pixelChanged = true;
end
elseif event == "PLAYER_LOGOUT" then
self:OnHide();
elseif event == "PLAYER_MOUNT_DISPLAY_CHANGED" then
UpdateMountActor();
end
end
function NarciOutfitShowcaseMixin:UpdateAlignment()
local offsetY = -PA_SPACING;
local maxWidth = 0;
local width;
local numObjects = #ItemTexts.objects;
if numObjects == 0 then
return
end
local object, firstObject, lastObject;
for i = 1, numObjects do
object = ItemTexts.objects[i];
if object:IsShown() then
width = object:GetWrappedWidth();
if width > maxWidth then
maxWidth = width;
end
object:ClearAllPoints();
if firstObject then
object:SetPoint("TOPLEFT", lastObject, "BOTTOMLEFT", 0, offsetY);
else
object:SetPoint("TOPLEFT", self.TextFrame, "TOPLEFT", 0, 0);
firstObject = object;
end
lastObject = object;
end
end
if not firstObject then return end
local textHeight = firstObject:GetTop() - lastObject:GetBottom();
local frameWidth, frameHeight = self.TextFrame:GetSize();
firstObject:ClearAllPoints();
firstObject:SetPoint("TOPLEFT", self.TextFrame, "TOPLEFT", (frameWidth-maxWidth)*0.5, (textHeight - frameHeight)*0.5);
self.TextFrame.Divider:SetHeight(textHeight + 64*PIXEL);
end
function NarciOutfitShowcaseMixin:SetModelFromTarget()
local unit = "target";
if UnitIsPlayer(unit) then
PlayerActor:SetModelByUnit(unit);
end
end
function NarciOutfitShowcaseMixin:GetPixelSize()
return PIXEL, IMAGE_HEIGHT/600;
end
local function Turntable_OnUpdate(self, elapsed)
self.yaw = self.yaw + elapsed * PI2 * ROTATION_PERIOD;
ActiveActor:SetYaw(self.yaw);
end
function NarciOutfitShowcaseMixin:SpinActor(state)
state = state and self:IsVisible();
if state then
self.yaw = ActiveActor:GetYaw();
self:SetScript("OnUpdate", Turntable_OnUpdate);
FadeOptionFrame.SpinButton:FadeOut();
else
self:SetScript("OnUpdate", nil);
self.yaw = nil;
FadeOptionFrame.SpinButton:FadeIn();
end
self.isSpinning = state;
end
function NarciOutfitShowcaseMixin:OnHide()
SetUpTooltipText();
if self.cvarChanged and self.cvarMSAA then
SetCVar("MSAAQuality", self.cvarMSAA);
self.cvarMSAA = nil;
end
self:Hide();
self:SpinActor(false);
PlayerActor:SetYaw(0);
self:UnregisterEvent("PLAYER_LOGOUT");
self:UnregisterEvent("PLAYER_MOUNT_DISPLAY_CHANGED");
if self.dressingRoomButton then
self.dressingRoomButton.Icon:SetTexCoord(0.5, 0.75, 0.5, 0.75);
end
end
function NarciOutfitShowcaseMixin:MarkCVarChanged()
self.cvarChanged = true;
self:RegisterEvent("PLAYER_LOGOUT");
end
function NarciOutfitShowcaseMixin:Close()
self:Hide();
end
function NarciOutfitShowcaseMixin:Open()
self:Show();
self:Raise();
if self.dressingRoomButton then
self.dressingRoomButton.Icon:SetTexCoord(0.75, 1, 0.5, 0.75);
end
end
function NarciOutfitShowcaseMixin:SetImageSize(sizes)
local width, height = sizes[1], sizes[2];
if width * height < 10000 then
return
end
local ratio = math.floor(100*width/height)/100;
local resetCamera;
if ratio ~= self.lastRatio then
self.lastRatio = ratio;
resetCamera = true;
end
MODEL_WIDTH_RATIO = ratio;
if ratio > 1 then
MODEL_WIDTH_RATIO = 0.75;
end
if ratio == 1 then
ratio = "1:1";
elseif ratio == 0.75 then
ratio = "3:4";
elseif ratio == 1.33 then
ratio = "4:3";
elseif ratio == "1.77" then
ratio = "16:9";
MODEL_WIDTH_RATIO = 1;
else
ratio = "custom";
end
IMAGE_WIDTH = width;
IMAGE_HEIGHT = height;
self:OnDisplaySizeChanged(resetCamera);
self.ControlPanel.LayoutTab.ImageSize.ValueText:SetText( string.format("%d x %d (%s)", width, height, GetScreenAspectText(width, height)) );
if SHOW_ITEM_NAME then
LAST_IMAGE_SIZE_WITH_TEXT = sizes;
DB.ImageWidth = width;
DB.ImageHeight = height;
else
LAST_IMAGE_SIZE_NO_TEXT = sizes;
DB.NoTextImageWidth = width;
DB.NoTextImageHeight = height;
end
TAN_FOV_H = ConvertHorizontalFoV(FOV_VERTICAL, height/width);
end
function NarciOutfitShowcaseMixin:SetFontWeight(weight)
FONT_WEIGHT = weight;
self:UpdateTextSize();
self:UpdateAlignment();
self.ControlPanel.LayoutTab.FontSize.ValueText:SetText(weight);
DB.FontSize = weight;
end
function NarciOutfitShowcaseMixin:SetRotationPeriod(seconds, pause)
if seconds > 2 then
ROTATION_PERIOD = 1/seconds;
self:SpinActor(not pause);
self.ControlPanel.LayoutTab.RotationPeriod.ValueText:SetText(string.format("%d s", seconds));
DB.Period = seconds;
else
ROTATION_PERIOD = 2;
end
end
function NarciOutfitShowcaseMixin:ShowItemText(state)
self.TextFrame:SetShown(state);
SHOW_ITEM_NAME = state;
local b = FadeOptionFrame.ItemNameToggle;
if state then
self:SetImageSize(LAST_IMAGE_SIZE_WITH_TEXT or {800, 600});
b.Icon:SetTexCoord(0.5, 1, 0, 1);
b.Label:SetText(L["Item Name Hide"]);
DropDownOptions.imageSizeValid = DropDownOptions.imageSizeWithText;
else
self:SetImageSize(LAST_IMAGE_SIZE_NO_TEXT or {450, 600});
b.Icon:SetTexCoord(0, 0.5, 0, 1);
b.Label:SetText(L["Item Name Show"]);
DropDownOptions.imageSizeValid = DropDownOptions.imageSizeNoText;
end
DB.ShowItemName = state;
end
function NarciOutfitShowcaseMixin:ShowTab(id)
self.ControlPanel.AnimationTab:SetShown(id == 1);
self.ControlPanel.LayoutTab:SetShown(id == 2);
self.ControlPanel.QualityTab:SetShown(id == 3);
self.ControlPanel.BackgroundTab:SetShown(id == 4);
end
function NarciOutfitShowcaseMixin:SetMountMode(state)
self.mountMode = state;
if state then
self:RegisterEvent("PLAYER_MOUNT_DISPLAY_CHANGED");
UpdateMountActor();
else
self:UnregisterEvent("PLAYER_MOUNT_DISPLAY_CHANGED");
self.mountID = nil;
if ACTOR_IS_MOUNT then
ACTOR_IS_MOUNT = false;
PlayerActor:SetUseCenterForOrigin(false, false, true);
PlayerActor:ResetAnimation();
MountActor:Hide();
MountActor:ClearModel();
ModelScene.actor = PlayerActor;
ActiveActor = PlayerActor;
end
ANIMATION_ID = 0;
IDFrame.EditBox:SetText(0);
end
MainFrame:SyncModel();
MountToggle:UpdateIcon();
if LOOP_ANIMATION then
ActiveActor:TryAnimation(ANIMATION_ID);
end
end
NarciAutoFittingActorMixin = {};
function NarciAutoFittingActorMixin:OnLoad()
self.parentScene = self:GetParent();
self.scale = 1;
self.feetZ = -0.5;
self.leftX = 0.5;
self.rightX = 0.5;
end
function NarciAutoFittingActorMixin:TryAnimation(animationID)
self:SetPaused(false);
self.t = 0;
self.isPlaying = true;
self:SetAnimation(animationID, VARIATION_ID, 1);
AnimationSlider:SetCeiling();
if animationID ~= self.animationID then
self.animationID = animationID;
self.parentScene:ResetView();
end
end
function NarciAutoFittingActorMixin:OnAnimFinished()
self:SetPaused(true);
self.isPlaying = false;
if self.t then
--print("Duration: "..self.t);
AnimationSlider:SetCeiling(self.t * 1000);
end
if LOOP_ANIMATION then
self:TryAnimation(self.animationID); --loop animation
end
end
function NarciAutoFittingActorMixin:OnUpdate(elapsed)
if self.isPlaying then
self.t = self.t + elapsed;
AnimationSlider:SetValue(1000 * self.t);
end
end
function NarciAutoFittingActorMixin:PauseAtFrame(millisecond)
self.isPlaying = false;
self.f = millisecond*0.001;
self:SetAnimation(ANIMATION_ID, VARIATION_ID, 1, self.f);
self:SetPaused(true);
end
function NarciAutoFittingActorMixin:ResetAnimation()
self.isPlaying = false;
self:SetAnimation(ANIMATION_ID, VARIATION_ID, 1, self.f or 0);
self:SetPaused(true);
end
function NarciAutoFittingActorMixin:UpdateGroundShadow()
local x, y, z = self:GetPosition();
x, y, z = x*self.scale, y*self.scale, z*self.scale;
local feetX, feetY = self.parentScene:Project3DPointTo2D(x, y, z + self.feetZ);
GroundShadow:ClearAllPoints();
GroundShadow:SetPoint("CENTER", self.parentScene, "BOTTOMLEFT", feetX, feetY);
local leftX = self.parentScene:Project3DPointTo2D(x, y + self.leftX, z + self.feetZ);
local rightX = self.parentScene:Project3DPointTo2D(x, y + self.rightX, z + self.feetZ);
if not (leftX and rightX) then
return
end
local width = leftX - rightX + 25;
if width < 0 then
width = -width;
end
GroundShadow:SetSize(width, 0.5*width);
end
function NarciAutoFittingActorMixin:UpdateMountShadow()
local x, y, z = self:GetPosition();
x, y, z = x*self.scale, y*self.scale, z*self.scale;
local feetX, feetY = self.parentScene:Project3DPointTo2D(x, y, z);
GroundShadow:ClearAllPoints();
GroundShadow:SetPoint("CENTER", self.parentScene, "BOTTOMLEFT", feetX, feetY);
local leftX = self.parentScene:Project3DPointTo2D(x, y - self.averageSpan, 0);
local rightX = self.parentScene:Project3DPointTo2D(x, y + self.averageSpan, 0);
if not (leftX and rightX) then
return
end
local width = leftX - rightX;
if width < 0 then
width = -width;
end
GroundShadow:SetSize(width, 0.5*width);
end
function NarciAutoFittingActorMixin:AdjustAlignment()
local a, b, c, d, e, f = self:GetActiveBoundingBox();
local scene = self.parentScene;
local w, h = scene:GetSize();
local depth, width, height = d - a, e - b, f - c;
--print(depth, width, height)
self.width = width;
self.averageSpan = (depth + width) * 0.2; --used to calculate shadow size
if self.averageSpan > 0.8 then
self.averageSpan = 0.8;
end
d = depth*0.5;
a = -d;
e = width*0.5;
b = -e;
f = height*0.5;
c = -f;
a,d = 0, 0;
local x1, y1 = scene:Project3DPointTo2D(a, b, c);
local x2, y2 = scene:Project3DPointTo2D(a, b, f);
local x3, y3 = scene:Project3DPointTo2D(a, e, c);
local x4, y4 = scene:Project3DPointTo2D(a, e, f);
local x5, y5 = scene:Project3DPointTo2D(d, b, c);
local x6, y6 = scene:Project3DPointTo2D(d, b, f);
local x7, y7 = scene:Project3DPointTo2D(d, e, c);
local x8, y8 = scene:Project3DPointTo2D(d, e, f);
local minX = min(x1, x2, x3, x4, x5, x6, x7, x8);
local maxX = max(x1, x2, x3, x4, x5, x6, x7, x8);
local minY = min(y1, y2, y3, y4, y5, y6, y7, y8);
local maxY = max(y1, y2, y3, y4, y5, y6, y7, y8);
local spanX = maxX - minX;
local spanY = maxY - minY;
local scale = min(0.8*h/spanY, 0.8*w/spanX);
self:SetScale(scale);
self.scale = scale;
a, b, c, d, e, f = a*scale, b*scale, c*scale, d*scale, e*scale, f*scale
self.feetZ = c;
self.leftX = e;
self.rightX = b;
x1, y1 = scene:Project3DPointTo2D(a, b, c);
x2, y2 = scene:Project3DPointTo2D(a, b, f);
x3, y3 = scene:Project3DPointTo2D(a, e, c);
x4, y4 = scene:Project3DPointTo2D(a, e, f);
x5, y5 = scene:Project3DPointTo2D(d, b, c);
x6, y6 = scene:Project3DPointTo2D(d, b, f);
x7, y7 = scene:Project3DPointTo2D(d, e, c);
x8, y8 = scene:Project3DPointTo2D(d, e, f);
minX = min(x1, x2, x3, x4, x5, x6, x7, x8);
maxX = max(x1, x2, x3, x4, x5, x6, x7, x8);
minY = min(y1, y2, y3, y4, y5, y6, y7, y8);
maxY = max(y1, y2, y3, y4, y5, y6, y7, y8);
--[[
local centerX = (maxX + minX)*0.5;
local centerY = (maxY + minY)*0.5;
scene.P1:ClearAllPoints();
scene.P2:ClearAllPoints();
scene.P3:ClearAllPoints();
scene.P4:ClearAllPoints();
scene.P1:SetPoint("CENTER", scene, "BOTTOMLEFT", minX, minY);
scene.P2:SetPoint("CENTER", scene, "BOTTOMLEFT", maxX, minY);
scene.P3:SetPoint("CENTER", scene, "BOTTOMLEFT", minX, maxY);
scene.P4:SetPoint("CENTER", scene, "BOTTOMLEFT", maxX, maxY);
local x, y = scene:Project3DPointTo2D(0, 0, 0);
--]]
self:UpdateGroundShadow();
end
function NarciAutoFittingActorMixin:OnModelLoaded()
local fileID = self:GetModelFileID();
if fileID then
UtilityModel:SetModel(fileID);
end
self.defaultY = GetModelOffsetZ(fileID);
self:SetPosition(0, 0, self.defaultY);
self:AdjustAlignment();
self:SetPaused(true);
AnimationSlider:Reset();
if self.actorType == "mount" then
PlaceMountAtGroundCenter();
end
end
function NarciAutoFittingActorMixin:SheatheWeapon(state)
self:SetSheathed(state);
if self.bowData then
if state then
self:SetItemTransmogInfo(self.bowData, 16);
else
self:SetItemTransmogInfo(self.bowData, 17); --swtich bow to the left hand
self:UndressSlot(16);
end
end
SheatheButton:UpdateIcon();
end
--/run NarciOutfitShowcase:SetModelFromTarget()
NarciShowcaseItemTextMixin = {}; --advanced formating
function NarciShowcaseItemTextMixin:SetItemText(text)
self:SetMaxLines(2);
self:SetText(text);
if true then return end
local width0 = self:GetUnboundedStringWidth();
local width1 = self:GetWrappedWidth();
local diff = width0 - width1;
if diff < 0.25*width1 then
self:SetMaxLines(1);
else
if NUM_DOUBLE_LINE_OBJECT <= MAX_DOUBLE_LINE_OBJECT then
self:SetMaxLines(2);
NUM_DOUBLE_LINE_OBJECT = NUM_DOUBLE_LINE_OBJECT + 1;
else
self:SetMaxLines(1);
end
end
end
function NarciShowcaseItemTextMixin:SetItemTextBySourceID(sourceID)
self:SetItemText(TransmogDataProvider:GetSourceName(sourceID));
end
function NarciShowcaseItemTextMixin:SetItemTextBySlotInfo(slotID, transmogInfo)
local sourceID = transmogInfo.appearanceID;
if IsHiddenVisual(sourceID) then
self:SetTextColor(0.5, 0.5, 0.5);
else
self:SetTextColor(0.8, 0.8, 0.8);
end
local name = TransmogDataProvider:GetSourceName(sourceID);
if not name or name == "" then
SourceCacher:AddToQueue(self, sourceID);
end
if slotID == 3 then
--Shoulders
local secondID = transmogInfo.secondaryAppearanceID;
if secondID and secondID > 0 and secondID ~= sourceID then
self:SetText("|TInterface\\AddOns\\Narcissus\\Art\\Modules\\Showcase\\ShoulderMark:12:12:0:0:64:64:0:32:0:64|t "..name);
name = TransmogDataProvider:GetSourceName(transmogInfo.secondaryAppearanceID);
local fontString = ItemTexts:Acquire();
if name and name ~= "" then
fontString:SetText("|TInterface\\AddOns\\Narcissus\\Art\\Modules\\Showcase\\ShoulderMark:12:12:0:0:64:64:32:64:0:64|t "..name);
else
SourceCacher:AddToQueue(fontString, secondID);
end
if IsHiddenVisual(secondID) then
fontString:SetTextColor(0.5, 0.5, 0.5);
else
fontString:SetTextColor(0.8, 0.8, 0.8);
end
else
self:SetText(name);
end
else
if slotID == 16 or slotID == 17 then
if TransmogDataProvider:IsLegionArtifactBySourceID(sourceID) then
local artifactAppearanceSetName = TransmogDataProvider:GetArtifactAppearanceSetName(sourceID);
if artifactAppearanceSetName and name ~= artifactAppearanceSetName then
name = name .. " ("..artifactAppearanceSetName..")";
end
end
self:SetItemText(name);
if TransmogDataProvider:IsSourceBow(sourceID) then
ModelScene.actor.bowData = transmogInfo;
ModelScene.actor:UndressSlot(16);
ModelScene.actor:SetItemTransmogInfo(transmogInfo, 17);
else
local currentInfo = PlayerActor:GetItemTransmogInfo(slotID);
if not (currentInfo and currentInfo:IsEqual(transmogInfo)) then
PlayerActor:SetItemTransmogInfo(transmogInfo, slotID);
end
end
--Weapons
sourceID = transmogInfo.illusionID;
if sourceID > 0 and sourceID ~= 5360 then --0 ~ Constants.Transmog.NoTransmogID / 5360 ~ Hide Weapon Enchant
name = TransmogDataProvider:GetIllusionName(transmogInfo.illusionID);
local fontString = ItemTexts:Acquire();
if name and name ~= "" then
--fontString:SetText("|cff808080└|r "..name);
fontString:SetText("|TInterface\\AddOns\\Narcissus\\Art\\Modules\\Showcase\\SubTextMark:12:12:0:0:64:64:0:64:0:64|t"..name);
else
SourceCacher:AddToQueue(fontString, sourceID);
end
end
else
self:SetItemText(name);
end
end
end
NarciOutfitInfoButtonMixin = {};
function NarciOutfitInfoButtonMixin:OnLoad()
self.Icon:SetTexture("Interface/AddOns/Narcissus/Art/Modules/Showcase/InfoButton", nil, nil, "LINEAR");
self:SetColor(0.3, 0.3, 0.3);
end
function NarciOutfitInfoButtonMixin:OnEnter()
self:SetColor(0.5, 0.5, 0.5);
SetUpTooltipText(self, nil, 8);
SetCursor("Interface/CURSOR/UnableQuestTurnIn.blp");
end
function NarciOutfitInfoButtonMixin:OnLeave()
self:SetColor(0.3, 0.3, 0.3);
SetUpTooltipText();
ResetCursor();
end
function NarciOutfitInfoButtonMixin:SetColor(r, g, b)
self.Icon:SetVertexColor(r, g, b);
end
NarciShowcaseThreeSliceFrameMixin = {};
function NarciShowcaseThreeSliceFrameMixin:OnLoad()
self:SetBackdropColor(0.25, 0.25, 0.25);
end
function NarciShowcaseThreeSliceFrameMixin:SetBackdropColor(r, g, b)
self.BackdropLeft:SetVertexColor(r, g, b);
self.BackdropRight:SetVertexColor(r, g, b);
self.BackdropCenter:SetVertexColor(r, g, b);
end
function NarciShowcaseThreeSliceFrameMixin:OnEnter()
self:SetBackdropColor(0.35, 0.35, 0.35);
if self.Arrow then
self.Arrow:SetVertexColor(0.9, 0.9, 0.9);
end
end
function NarciShowcaseThreeSliceFrameMixin:OnLeave()
self:SetBackdropColor(0.25, 0.25, 0.25);
if self.Arrow then
self.Arrow:SetVertexColor(0.5, 0.5, 0.5);
end
end
NarciShowcaseDropDownFrameMixin = CreateFromMixins(NarciShowcaseThreeSliceFrameMixin);
function NarciShowcaseDropDownFrameMixin:OnLoad()
self:SetBackdropColor(0.25, 0.25, 0.25);
self.Arrow:SetVertexColor(0.5, 0.5, 0.5);
if self.InfoButton then
self.Label:ClearAllPoints();
self.Label:SetPoint("RIGHT", self, "LEFT", -20, 0);
end
end
function NarciShowcaseDropDownFrameMixin:SetFocus(state)
self.isFocused = state;
self:UpdateArrow();
if state then
self:SetFrameLevel(8);
else
self:SetFrameLevel(4);
end
end
function NarciShowcaseDropDownFrameMixin:IsFocused()
return self.isFocused
end
function NarciShowcaseDropDownFrameMixin:OnHide()
self.isFocused = nil;
self:SetBackdropColor(0.25, 0.25, 0.25);
self.Arrow:SetVertexColor(0.5, 0.5, 0.5);
end
function NarciShowcaseDropDownFrameMixin:UpdateArrow()
if self.isFocused then
self.Arrow:SetTexCoord(0, 1, 1, 0);
else
self.Arrow:SetTexCoord(0, 1, 0, 1);
end
end
function NarciShowcaseDropDownFrameMixin:OnMouseDown(button)
if button == "LeftButton" then
SetUpDropDown(self, self.menuName);
end
end
NarciShowcaseDropDownButtonMixin = {};
function NarciShowcaseDropDownButtonMixin:OnMouseDown(button)
if button == "LeftButton" then
self.ButtonText:SetPoint("LEFT", self, "LEFT", 14, -0.6);
end
end
function NarciShowcaseDropDownButtonMixin:OnMouseUp()
self.ButtonText:SetPoint("LEFT", self, "LEFT", 14, 0);
end
function NarciShowcaseDropDownButtonMixin:OnClick(button)
if button == "LeftButton" then
local method = self:GetParent().method;
MainFrame[method](MainFrame, self.value);
SetUpDropDown();
end
end
function NarciShowcaseDropDownButtonMixin:OnEnter()
self.ButtonText:SetTextColor(0.9, 0.9, 0.9);
end
function NarciShowcaseDropDownButtonMixin:OnLeave()
self.ButtonText:SetTextColor(0.67, 0.67, 0.67);
end
function NarciShowcaseDropDownButtonMixin:OnHide()
self:OnMouseUp();
end
function NarciShowcaseDropDownButtonMixin:SetValueText(text)
self.ButtonText:SetText(text);
end
local function TabSelection_OnUpdate(self, elapsed)
local complete;
local diff = self.toX - self.x;
local delta = elapsed * 16 * diff;
if diff >= 0 and (diff < 1 or (self.x + delta >= self.toX)) then
self.x = self.toX;
complete = true;
elseif diff <= 0 and (diff > -1 or (self.x + delta <= self.toX)) then
self.x = self.toX;
complete = true;
else
self.x = self.x + delta;
end
diff = self.toWidth - self.width;
delta = elapsed * 16 * diff;
if diff >= 0 and (diff < 1 or (self.width + delta >= self.toWidth)) then
self.width = self.toWidth;
complete = complete and true;
elseif diff <= 0 and (diff > -1 or (self.width + delta <= self.toWidth)) then
self.width = self.toWidth;
complete = complete and true;
else
self.width = self.width + delta;
complete = false;
end
if complete then
self:SetScript("OnUpdate", nil);
end
self:SetPoint("BOTTOM", ControlPanel.NavBar, "BOTTOMLEFT", self.x, 0);
self.Center:SetWidth(self.width);
end
NarciShowcaseNavButtonMixin = {};
function NarciShowcaseNavButtonMixin:OnEnter()
if not self.selected then
self.ButtonText:SetTextColor(0.9, 0.9, 0.9);
end
end
function NarciShowcaseNavButtonMixin:OnLeave()
if not self.selected then
self.ButtonText:SetTextColor(0.5, 0.5, 0.5);
end
end
function NarciShowcaseNavButtonMixin:OnMouseDown()
if not self.selected then
self.ButtonText:SetPoint("CENTER", self, "CENTER", 0, -0.6);
end
end
function NarciShowcaseNavButtonMixin:OnMouseUp()
self.ButtonText:SetPoint("CENTER", self, "CENTER", 0, 0);
end
function NarciShowcaseNavButtonMixin:OnClick()
if self.selected then return end;
for _, button in pairs( self:GetParent().NavButtons ) do
button:SetSelection( button == self );
end
MainFrame:ShowTab(self.id);
local leftX = self:GetParent():GetLeft();
local buttonX = self:GetCenter();
TabSelection.width = TabSelection.Center:GetWidth();
TabSelection.toWidth = self.ButtonText:GetWidth();
TabSelection.toX = buttonX - leftX;
TabSelection:SetScript("OnUpdate", TabSelection_OnUpdate);
end
function NarciShowcaseNavButtonMixin:SetSelection(state)
self.selected = state;
if state then
self.ButtonText:SetTextColor(0.188, 0.506, 0.8);
else
self.ButtonText:SetTextColor(0.5, 0.5, 0.5);
end
end
function NarciShowcaseNavButtonMixin:SetButtonText(text)
self.ButtonText:SetText(text);
self:SetWidth( math.max(self.ButtonText:GetWidth() + 8, 48) );
end
NarciShowcaseMountToggleMixin = {};
function NarciShowcaseMountToggleMixin:OnLoad()
MountToggle = self;
end
function NarciShowcaseMountToggleMixin:OnEnter()
self.Icon:SetVertexColor(1, 1, 1);
local tooltipText = (MainFrame.mountMode and L["Hide Mount"] or L["Show Mount"]);
SetUpTooltipText(self, tooltipText, 8);
end
function NarciShowcaseMountToggleMixin:OnLeave()
if not self.isOn then
self.Icon:SetVertexColor(0.8, 0.8, 0.8);
end
SetUpTooltipText();
end
function NarciShowcaseMountToggleMixin:OnClick()
MainFrame:SetMountMode(not MainFrame.mountMode);
SetUpTooltipText();
end
function NarciShowcaseMountToggleMixin:UpdateIcon()
if MainFrame.mountMode then
self.Icon:SetTexCoord(0.5, 1, 0, 1);
self.isOn = true;
else
self.Icon:SetTexCoord(0, 0.5, 0, 1);
self.isOn = nil;
end
end
NarciShowcaseLoopToggleMixin = {};
function NarciShowcaseLoopToggleMixin:OnLoad()
LoopToggle = self;
end
function NarciShowcaseLoopToggleMixin:OnEnter()
self.Icon:SetVertexColor(1, 1, 1);
local tooltipText = L["Loop Animation On"];
SetUpTooltipText(self, tooltipText, 8);
end
function NarciShowcaseLoopToggleMixin:OnLeave()
if not LOOP_ANIMATION then
self.Icon:SetVertexColor(0.8, 0.8, 0.8);
end
SetUpTooltipText();
end
function NarciShowcaseLoopToggleMixin:OnClick()
LOOP_ANIMATION = not LOOP_ANIMATION;
if LOOP_ANIMATION then
ActiveActor:TryAnimation(ANIMATION_ID);
else
ActiveActor:OnAnimFinished();
end
self:UpdateVisual();
SetUpTooltipText();
end
function NarciShowcaseLoopToggleMixin:UpdateVisual()
if LOOP_ANIMATION then
self.Icon:SetTexCoord(0.5, 1, 0, 1);
else
self.Icon:SetTexCoord(0, 0.5, 0, 1);
end
end
--/script local m=MountJournal.MountDisplay.ModelScene:GetActorByTag("unwrapped");if m then m:SetAnimation(97) end;