Thread Tools Display Modes
06-28-13, 09:42 AM   #1
zork
A Pyroguard Emberseer
 
zork's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 1,740
Nameplate FPS drop research

I'm currently investigating nameplates on patch 5.4 ptr.

Default nameplates:


rDiabloPlates enabled:


rDiabloPlates enabled ... everything removed, healthbar texture replaced


So actually I gain fps on the last screenshot. I think the fps drop is not an issue with the nameplate addons in general. I think it has sth to do with how many objects you create etc.

So one has to be very carefully when building nameplate addons. They can eat your fps alive.

Currently investigating all that stuff a little bit more.
__________________
| Simple is beautiful.
| WoWI AddOns | GitHub | Zork (WoW)

"I wonder what the non-pathetic people are doing tonight?" - Rajesh Koothrappali (The Big Bang Theory)
  Reply With Quote
06-28-13, 10:22 AM   #2
Haleth
This Space For Rent
 
Haleth's Avatar
Featured
Join Date: Sep 2008
Posts: 1,173
I'll look into this. Something else I've noticed on the last couple of patches though - when you have certain UI panels open, like the friends list, even without addons your fps can drop dramatically for no apparent reason. Ever seen that?
  Reply With Quote
06-28-13, 06:13 PM   #3
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,060
I ran into this in my map project when I tried to draw very large numbers of textures and font strings at once. Just having them on-screen caused a noticeable dip in the frame rate, but attempting to move the frame they were attached to practically froze the game.

I had created many font strings as labels for various POIs on the map..


And displaying them for the entire continent greatly impacted frame rates.


However, since you could both drag and zoom the map, it quickly became obvious that moving or scaling the frame caused exponentially more of a problem for FPS.

When I adjusted the script to hide the labels while dragging, and showing them when finished, it completely solved the problem. As long as the regions aren't visible while they're being repositioned they have almost no impact on the frame rate.

This leads me to believe that simply recalculating the positions of the regions isn't the problem, but redrawing them every time they move is. Therefor, if you can limit how often they're redrawn you should be able to limit the impact on frame rate.

This may not make any sense, but instead of anchoring your nameplates directly to the existing one, try attaching them to the WorldFrame and using an OnUpdate script to reposition them only once per frame.

The author of kui nameplates uses this method to keep their nameplates pixel perfect, although an unexpected side effect is higher frame rates.
  Reply With Quote
06-28-13, 06:38 PM   #4
Haleth
This Space For Rent
 
Haleth's Avatar
Featured
Join Date: Sep 2008
Posts: 1,173
That's a very interesting read. However...

Originally Posted by semlar View Post
This may not make any sense, but instead of anchoring your nameplates directly to the existing one, try attaching them to the WorldFrame and using an OnUpdate script to reposition them only once per frame.
Isn't once per frame refresh already the speed at which frames and regions are repositioned/redrawn? I don't see how dumping the positioning into a separate OnUpdate script will improve the situation.

Unless, of course, all UI code normally runs on the same thread, and only by using OnUpdate can you allow proper multi-threading...

Or perhaps frame/region positions might simply not be calculated at all when the object is hidden.

Last edited by Haleth : 06-28-13 at 06:43 PM.
  Reply With Quote
06-29-13, 03:16 AM   #5
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,060
Alright, I wrote a small proof of concept that demonstrates just how much of a difference hiding the frame before you reposition it makes, even if it makes no visible difference in-game.
Lua Code:
  1. local Nameplates, PreviousWorldChildren = {}, 0 -- Table to hold our list of detected nameplates
  2. WorldFrame:HookScript('OnUpdate', function(self)
  3.     local currentWorldChildren = self:GetNumChildren()
  4.     if currentWorldChildren ~= PreviousWorldChildren then PreviousWorldChildren = currentWorldChildren
  5.         for _, plate in pairs({self:GetChildren()}) do
  6.             if not Nameplates[plate] then -- Check if it's already been seen
  7.                 local name = plate:GetName()
  8.                 if name and strmatch(name, '^NamePlate%d+$') then -- Test that it's a nameplate
  9.                     Nameplates[plate] = CreateFrame('frame', nil, WorldFrame) -- Record our new frame
  10.                     for i = 1, 500 do -- Make a bunch of regions for a stress test
  11.                         local fs = Nameplates[plate]:CreateFontString(nil, nil, 'GameFontNormalHuge')
  12.                         fs:SetText('LAG')
  13.                         fs:SetPoint('CENTER', math.random(-50,50), math.random(-12,12)) -- This is just to make it look more interesting
  14.                     end
  15.                 end
  16.             end
  17.         end
  18.     end
  19.     for plate, f in pairs(Nameplates) do -- Iterate over existing nameplates every frame
  20.         if plate:IsShown() then -- Check visibility
  21.             f:Hide() -- Try commenting this out and see what happens to your frame rate
  22.             f:SetSize(plate:GetSize()) -- This isn't necessary to call every update but it simplifies the example
  23.             f:SetPoint('CENTER', WorldFrame, 'BOTTOMLEFT', plate:GetCenter()) -- Position our frame relative to the nameplate
  24.             f:Show()
  25.         else -- Hide if nameplate is hidden
  26.             f:Hide()
  27.         end
  28.     end
  29. end)

You can forget about repositioning the frame OnUpdate without hiding it first, it doesn't seem to make as much of a difference as I thought. On the other hand, this trick seems to make a huge difference.

The only downside is it lags one frame behind the default nameplate, but maybe there's a way to overcome that.

There are 2000 font strings per nameplate in this screenshot, and while it has dropped my frame rate down to around 15 fps I can still smoothly rotate the camera and run around without any issues. Attaching them directly to the nameplate completely freezes the game in this same test.

Last edited by semlar : 08-21-13 at 06:17 AM.
  Reply With Quote
06-29-13, 03:46 AM   #6
zork
A Pyroguard Emberseer
 
zork's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 1,740
Thanks semlar. The difference in FPS is hilarious btw. You can even see how the fontstrings move point-by-point.

I never used an OnUpdate script that runs on every frame before though.



So semlars solution to this is:

Instead of putting all your frames on the nameplate itself we create a new frame on the Worldframe that still has a link to the corresponding Blizzard nameplate. On every frame update we hide our plate first, do our calculations and show it thereafter.

Two things in his example will lag you out by a mile.
  • Adding frames directly to the Blizzard nameplate
  • Not hiding our new nameplate frame before doing calculations

If you want the fastest nameplates on the planet you need to build them like semlar posted.
To make it clear... on the screenshot are 500 fontstrings per nameplate. Not 5. And it still runs smoothly.

This also has a major bonus. Since we are living in the environment of OnUpdate we can do all the calculations we want. (color calculation etc.)

Thanks alot semlar that was exactly what I was looking for.

Sidepoint...if some needs the current nameplate regions. Here we go:

Lua Code:
  1. --do dat
  2.     local f = NamePlate1
  3.     f.barFrame, f.nameFrame = f:GetChildren()
  4.     f.healthbar, f.castbar = f.barFrame:GetChildren()
  5.     f.threat, f.border, f.highlight, f.level, f.boss, f.raid, f.dragon = f.barFrame:GetRegions()
  6.     f.name = f.nameFrame:GetRegions()
  7.     f.healthbar.texture = f.healthbar:GetRegions()
  8.     f.castbar.texture, f.castbar.border, f.castbar.shield, f.castbar.icon, f.castbar.name, f.castbar.nameShadow = f.castbar:GetRegions()
__________________
| Simple is beautiful.
| WoWI AddOns | GitHub | Zork (WoW)

"I wonder what the non-pathetic people are doing tonight?" - Rajesh Koothrappali (The Big Bang Theory)

Last edited by zork : 06-29-13 at 04:38 AM.
  Reply With Quote
06-29-13, 04:02 AM   #7
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,060
I know it's not exactly what you were looking for since you still get the fps dip from just having the regions on your screen, but it makes a pretty big difference in playability when you try to rotate the camera around.

The two important things are:
  • Don't make your frame a child of the nameplate
  • Hide the frame before you reposition it and show it afterwards
Also I have no idea why this works, so that's probably something to investigate.
  Reply With Quote
06-29-13, 04:25 AM   #8
zork
A Pyroguard Emberseer
 
zork's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 1,740
No actually it is exactly what I was looking for, a fix for my fps issues.

Another important point:
  • Do not reparent anything from the Blizzard nameplate to the new nameplate. It will catch you a taint.

Sth that you can add is:
Lua Code:
  1. plate.barFrame, plate.nameFrame = plate:GetChildren()
  2. plate.barFrame:Hide()
  3. plate.nameFrame:Hide()

This will hide every child of the Blizzard nameplate. So the only frames that will live are the ones on your newly created frame.

*edit*
Seems like reparenting some frames is possible. This worked without issues:
Lua Code:
  1. plate.nameFrame:SetParent(Nameplates[plate])

Here are some other hooks that might come in handy later:
Lua Code:
  1. plate:HookScript("OnShow", NamePlateOnShow)
  2. plate.castbar:HookScript("OnShow", CastbarOnShow)
  3. plate.castbar:HookScript("OnHide", CastbarOnHide)
  4. plate.healthbar:HookScript("OnValueChanged", HealthbarOnValueChanged)
  5. plate.castbar:HookScript("OnValueChanged", CastbarOnValueChanged)

If there is no script yet set change HookScript to SetScript.

So we could only change our castbar values if there is an actual change involved and not on every frame drawn.
__________________
| Simple is beautiful.
| WoWI AddOns | GitHub | Zork (WoW)

"I wonder what the non-pathetic people are doing tonight?" - Rajesh Koothrappali (The Big Bang Theory)

Last edited by zork : 06-29-13 at 05:50 AM.
  Reply With Quote
06-29-13, 05:42 AM   #9
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,060
I cleaned up the code in my post a little and added some comments to make it more readable.

You can use a different method for detecting the nameplates if you want, this is just how I did it in my example (mostly pulled out of my QuestPlates addon).

There isn't really any reason to use SetScript over HookScript since HookScript will create the script if it doesn't already exist, and you also might want to just create your own frame for the OnUpdate script just to be safe, although I can't think of a reason why that should break.

Oh one more thing, since we are iterating over the WorldFrame children, we might want to create our new frames under a different parent to save a little overhead, for example create a single frame under WorldFrame to use as the parent for all of the rest of the frames.

This gives you a reason to create a frame for the OnUpdate script and also allows you to toggle the visibility for all of the frames at once if you needed to.

Just make sure you factor in the scale if you parent them somewhere else.

Last edited by semlar : 06-29-13 at 06:08 AM.
  Reply With Quote
06-29-13, 09:12 AM   #10
Kesava
A Murloc Raider
 
Kesava's Avatar
AddOn Author - Click to view addons
Join Date: Jun 2008
Posts: 4
Semlar mentioned me, so I'll pop in...

As Semlar mentioned, I've been doing the WorldFrame trick with my nameplate addon for a while but for a different purpose. I wanted to manuallly set the position of my nameplates every frame so that I could make sure they were on 1:1 pixels and overcome the UI anti-aliasing issues. I noticed as a result of doing this, and of manually setting the position rather than using something like SetAllPoints, my nameplates had practically no effect on FPS over the default nameplates. Initially it was faster, but I'm not sure if that's the case anymore as I can't :Hide() the default UI elements otherwise I'd break compatibility with other addons.

I mentioned this to the author of TidyPlates a while ago and had the conclusion that what creates the most lag is adding frames as children directly to the default nameplates. I believe he made a test version with his nameplates parented to the WorldFrame and that alone drastically reduced the impact.

Since I'm doing this to make the nameplates pixel-perfect, I obviously have to do a little maths every frame aswell but even with that it still has a positive effect on FPS.

A particularly negative effect I've noticed from doing this is that when using stacking nameplates (the default UI option), if there are too many nameplates displayed and the stacking method "gives up", nameplates will jitter around slightly. This seems to only happen when using stacking, not spreading. That may be a result of my 1:1 code however.

Edit: no such luck with some potential improvements, I'll have to look into this more during my still-in-progress complete rewrite. I have a lot of stuff to look in to.

Last edited by Kesava : 06-29-13 at 10:07 AM.
  Reply With Quote
06-29-13, 11:36 AM   #11
zork
A Pyroguard Emberseer
 
zork's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 1,740
I cleaned up my testcode aswell. I will use it as a start for my new nameplate addon.



Lua Code:
  1. --RDP3
  2.     local RDP = CreateFrame("Frame", nil, WorldFrame)
  3.     RDP.nameplates = {}
  4.  
  5.     local function NameplateOnShow(...)
  6.       local self = ...
  7.       --print(...)
  8.       print(self:GetName().. "NameplateOnShow")
  9.     end
  10.  
  11.     local function NameplateOnHide(...)
  12.       local self = ...
  13.       --print(...)
  14.       print(self:GetName().. "NameplateOnHide")
  15.     end
  16.  
  17.     local function CastbarOnValueChanged(...)
  18.       local self = ...
  19.       --print(...)
  20.       print(self:GetParent():GetParent():GetName().. "CastbarOnValueChanged")
  21.     end
  22.  
  23.     local function HealthbarOnValueChanged(...)
  24.       local self = ...
  25.       --print(...)
  26.       print(self:GetParent():GetParent():GetName().."HealthbarOnValueChanged")
  27.     end
  28.  
  29.     local function IsNamePlateFrame(obj)
  30.       local name = obj:GetName()
  31.       if name and name:find("NamePlate") then
  32.         return true
  33.       end
  34.       obj.rdp_checked = true --don't touch this frame again
  35.       return false
  36.     end
  37.  
  38.     local function AddNamePlateToList(plate)
  39.       plate.barFrame, plate.nameFrame = plate:GetChildren()
  40.       plate.healthbar, plate.castbar = plate.barFrame:GetChildren()
  41.       plate.threat, plate.border, plate.highlight, plate.level, plate.boss, plate.raid, plate.dragon = plate.barFrame:GetRegions()
  42.       plate.name = plate.nameFrame:GetRegions()
  43.       plate.healthbar.texture = plate.healthbar:GetRegions()
  44.       plate.castbar.texture, plate.castbar.border, plate.castbar.shield, plate.castbar.icon, plate.castbar.name, plate.castbar.nameShadow = plate.castbar:GetRegions()
  45.       plate.rdp_checked = true
  46.  
  47.       RDP.nameplates[plate] = CreateFrame("Frame", nil, RDP)
  48.       RDP.nameplates[plate]:SetSize(128,32)
  49.       local t = RDP.nameplates[plate]:CreateTexture()
  50.       t:SetAllPoints()
  51.       t:SetTexture(1,0,1,0.3)
  52.  
  53.       --keep the frame reference for later
  54.       --RDP.nameplates[plate].blizzPlate = plate
  55.       --plate.newPlate = RDP.nameplates[plate]
  56.  
  57.       --plate:Hide()
  58.       --plate.barFrame:SetParent(Nameplates[plate])
  59.       plate.nameFrame:SetParent(RDP.nameplates[plate])
  60.       plate.barFrame:Hide()
  61.       --plate.nameFrame:Hide()
  62.       plate:HookScript("OnShow", NameplateOnShow)
  63.       plate:HookScript("OnHide", NameplateOnHide)
  64.       plate.healthbar:HookScript("OnValueChanged", HealthbarOnValueChanged)
  65.       plate.castbar:HookScript("OnValueChanged", CastbarOnValueChanged)
  66.  
  67.       local t = plate:CreateTexture()
  68.       t:SetAllPoints()
  69.       t:SetTexture(1,1,0,0.3)
  70.  
  71.     end
  72.  
  73.     local function SearchForNamePlates(self)
  74.       local currentChildren = self:GetNumChildren()
  75.       if not currentChildren or currentChildren == 0 then return end
  76.       for _, obj in pairs({self:GetChildren()}) do
  77.         if not obj.rdp_checked and IsNamePlateFrame(obj) then
  78.           AddNamePlateToList(obj)
  79.         end
  80.       end
  81.     end
  82.  
  83.     local function OnUpdate(self)
  84.       SearchForNamePlates(self)
  85.       RDP:Hide()
  86.       for blizzPlate, plate in pairs(RDP.nameplates) do
  87.           plate:Hide()
  88.           if blizzPlate:IsShown() then
  89.             plate:SetPoint("CENTER", WorldFrame, "BOTTOMLEFT", blizzPlate:GetCenter())
  90.             plate:Show()
  91.           end
  92.       end
  93.       RDP:Show()
  94.     end
  95.  
  96.     WorldFrame:HookScript("OnUpdate", OnUpdate)
__________________
| Simple is beautiful.
| WoWI AddOns | GitHub | Zork (WoW)

"I wonder what the non-pathetic people are doing tonight?" - Rajesh Koothrappali (The Big Bang Theory)
  Reply With Quote
07-01-13, 12:50 AM   #12
zork
A Pyroguard Emberseer
 
zork's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 1,740
Some further infos. I tested combat mode a bit and found that you are not allowed to hide the plate.barFrame without tainting it.

You can however reparent or hide the nameframe, healthbar and castbar frame freely without tainting it.

But...OnShow you have to that again because the frame will reset.
__________________
| Simple is beautiful.
| WoWI AddOns | GitHub | Zork (WoW)

"I wonder what the non-pathetic people are doing tonight?" - Rajesh Koothrappali (The Big Bang Theory)
  Reply With Quote
07-10-13, 01:25 AM   #13
cremor
A Murloc Raider
Join Date: Jun 2008
Posts: 9
Do I understand this correctly that the problem is way worse on 5.4 PTR than on 5.3 live? Because I don't get that huge differences in FPS when hiding my namespates on 5.3 live servers (using Tidy Plates Threat Plates).
  Reply With Quote
07-10-13, 01:30 AM   #14
zork
A Pyroguard Emberseer
 
zork's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 1,740
Yes there is. On the PTR the nameplate viewable distance is increased way above what we have on live. Thus you get tons of nameplates on PTR.

Easily testable by moving into any instance. You will see nameplates of mobs 100m+ away. It can change on live though.
__________________
| Simple is beautiful.
| WoWI AddOns | GitHub | Zork (WoW)

"I wonder what the non-pathetic people are doing tonight?" - Rajesh Koothrappali (The Big Bang Theory)
  Reply With Quote
07-10-13, 07:12 AM   #15
Rainrider
A Firelord
AddOn Author - Click to view addons
Join Date: Nov 2008
Posts: 454
Do we actually get any advantage from being able to view nameplates at that great distances? Why did they do it?
  Reply With Quote
07-10-13, 10:24 AM   #16
ravagernl
Proceritate Corporis
Premium Member
AddOn Author - Click to view addons
Join Date: Feb 2006
Posts: 1,176
Originally Posted by zork View Post
On the PTR the nameplate viewable distance is increased way above what we have on live.
How much yards is the viewable distance on the PTR approximately? From the screenshot it looks like about 100 yards.

I'm hoping blizz will implement an option for this (so I can set it to 45 yards for my hunter and 30 yards for my paladin, for example)
  Reply With Quote
08-21-13, 02:04 AM   #17
zork
A Pyroguard Emberseer
 
zork's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 1,740
I case anyone is interested. Here is my test addon using semlars approach.

I recycled as much frames as I could.

Lua Code:
  1. --if 1 == 1 then return end
  2.  
  3.     -----------------------------------------
  4.     -- CONFIG
  5.     -----------------------------------------
  6.  
  7.     local cfg = {}
  8.  
  9.     cfg.width = 100
  10.     cfg.height = 26
  11.  
  12.     -----------------------------------------
  13.     -- VARIABLES
  14.     -----------------------------------------
  15.  
  16.     --add a new global frame
  17.     local RDP = CreateFrame("Frame", "PlateCollector", WorldFrame)
  18.     RDP:SetAllPoints()
  19.     RDP.nameplates = {}
  20.  
  21.     local RAID_CLASS_COLORS = RAID_CLASS_COLORS
  22.     local FACTION_BAR_COLORS = FACTION_BAR_COLORS
  23.     local unpack = unpack
  24.  
  25.     -----------------------------------------
  26.     -- FUNCTIONS
  27.     -----------------------------------------
  28.  
  29.     local function RGBPercToHex(r, g, b)
  30.       r = r <= 1 and r >= 0 and r or 0
  31.       g = g <= 1 and g >= 0 and g or 0
  32.       b = b <= 1 and b >= 0 and b or 0
  33.       return string.format("%02x%02x%02x", r*255, g*255, b*255)
  34.     end
  35.  
  36.     local function FixColor(color)
  37.       color.r,color.g,color.b = floor(color.r*100+.5)/100, floor(color.g*100+.5)/100, floor(color.b*100+.5)/100
  38.     end
  39.  
  40.     --NamePlateOnShow func
  41.     local function NamePlateOnShow(self)
  42.       --new plate
  43.       local newPlate = self.healthbar:GetParent()
  44.       --hide level
  45.       self.level:Hide()
  46.       --healthbar
  47.       self.healthbar:ClearAllPoints()
  48.       self.healthbar:SetPoint("TOP", newPlate)
  49.       self.healthbar:SetPoint("LEFT", newPlate)
  50.       self.healthbar:SetPoint("RIGHT", newPlate)
  51.       self.healthbar:SetHeight(newPlate.height/2)
  52.       --name
  53.       self.name:ClearAllPoints()
  54.       self.name:SetPoint("BOTTOM", newPlate, "TOP")
  55.       self.name:SetPoint("LEFT", newPlate,-10,0)
  56.       self.name:SetPoint("RIGHT", newPlate,10,0)
  57.       self.name:SetFont(STANDARD_TEXT_FONT,11,"THINOUTLINE")
  58.       self.realName = self.name:GetText()
  59.     end
  60.  
  61.     --NamePlateCastbarOnShow func
  62.     local function NamePlateCastbarOnShow(self)
  63.         --new plate
  64.         local newPlate = self:GetParent()
  65.         --castbar
  66.         self:ClearAllPoints()
  67.         self:SetPoint("BOTTOM",newPlate)
  68.         self:SetPoint("LEFT",newPlate)
  69.         self:SetPoint("RIGHT",newPlate)
  70.         self:SetHeight(newPlate.height/2)
  71.         --castbar icon
  72.         self.icon:ClearAllPoints()
  73.         self.icon:SetPoint("RIGHT",newPlate, "LEFT")
  74.     end
  75.  
  76.     --NamePlateNameUpdate func
  77.     local function NamePlateNameUpdate(self)
  78.       if not self.realName then return end
  79.       local cs = RGBPercToHex(self.level:GetTextColor())
  80.       --name string
  81.       local name = self.realName
  82.       local level = self.level:GetText()
  83.       if self.boss:IsShown() == 1 then
  84.         level = "??"
  85.         cs = "ff6600"
  86.       elseif self.dragon:IsShown() == 1 then
  87.         level = level.."+"
  88.       end
  89.       self.name:SetText("|cff"..cs..""..level.."|r "..name)
  90.       self.level:Hide()
  91.     end
  92.  
  93.     --NamePlateHealthBarUpdate func
  94.     local function NamePlateHealthBarUpdate(self)
  95.       local color = {}
  96.       if self.threat:IsShown() then
  97.         color.r, color.g, color.b = self.threat:GetVertexColor()
  98.         FixColor(color)
  99.         if color.r+color.g+color.b < 3 then
  100.           self.healthbar:SetStatusBarColor(color.r,color.g,color.b)
  101.           return
  102.         end
  103.       end
  104.       color.r, color.g, color.b = self.healthbar:GetStatusBarColor()
  105.       FixColor(color)
  106.       for class, _ in pairs(RAID_CLASS_COLORS) do
  107.         if RAID_CLASS_COLORS[class].r == color.r and RAID_CLASS_COLORS[class].g == color.g and RAID_CLASS_COLORS[class].b == color.b then
  108.           self.healthbar:SetStatusBarColor(RAID_CLASS_COLORS[class].r,RAID_CLASS_COLORS[class].g,RAID_CLASS_COLORS[class].b)
  109.           return --no color change needed, bar is in class color
  110.         end
  111.       end
  112.       if color.g+color.b == 0 then -- hostile
  113.         self.healthbar:SetStatusBarColor(FACTION_BAR_COLORS[2].r,FACTION_BAR_COLORS[2].g,FACTION_BAR_COLORS[2].b)
  114.         return
  115.       elseif color.r+color.b == 0 then -- friendly npc
  116.         self.healthbar:SetStatusBarColor(FACTION_BAR_COLORS[6].r,FACTION_BAR_COLORS[6].g,FACTION_BAR_COLORS[6].b)
  117.         return
  118.       elseif color.r+color.g == 2 then -- neutral
  119.         self.healthbar:SetStatusBarColor(FACTION_BAR_COLORS[4].r,FACTION_BAR_COLORS[4].g,FACTION_BAR_COLORS[4].b)
  120.         return
  121.       elseif color.r+color.g == 0 then -- friendly player, we don't like 0,0,1 so we change it to a more likable color
  122.         self.healthbar:SetStatusBarColor(0/255, 100/255, 255/255)
  123.         return
  124.       else -- enemy player
  125.         --whatever is left
  126.         return
  127.       end
  128.     end
  129.  
  130.     --NamePlateInit func
  131.     local function NamePlateInit(plate)
  132.       --add some references
  133.       plate.barFrame, plate.nameFrame = plate:GetChildren()
  134.       plate.healthbar, plate.castbar = plate.barFrame:GetChildren()
  135.       plate.threat, plate.border, plate.highlight, plate.level, plate.boss, plate.raid, plate.dragon = plate.barFrame:GetRegions()
  136.       plate.name = plate.nameFrame:GetRegions()
  137.       plate.healthbar.texture = plate.healthbar:GetRegions()
  138.       plate.castbar.texture, plate.castbar.border, plate.castbar.shield, plate.castbar.icon, plate.castbar.name, plate.castbar.nameShadow = plate.castbar:GetRegions()
  139.       plate.rdp_checked = true
  140.       --create new plate and parent it to RDP
  141.       RDP.nameplates[plate] = CreateFrame("Frame", "New"..plate:GetName(), RDP)
  142.       RDP.nameplates[plate]:SetSize(cfg.width,cfg.height)
  143.       RDP.nameplates[plate].width, RDP.nameplates[plate].height = RDP.nameplates[plate]:GetSize()
  144.       --keep the frame reference for later
  145.       RDP.nameplates[plate].blizzPlate = plate
  146.       plate.newPlate = RDP.nameplates[plate]
  147.       --reparent
  148.       plate.raid:SetParent(RDP.nameplates[plate])
  149.       plate.nameFrame:SetParent(RDP.nameplates[plate])
  150.       plate.castbar:SetParent(RDP.nameplates[plate])
  151.       plate.healthbar:SetParent(RDP.nameplates[plate])
  152.       --reparent raid mark
  153.       plate.raid:ClearAllPoints()
  154.       plate.raid:SetPoint("BOTTOM",RDP.nameplates[plate],"TOP")
  155.       --hide level
  156.       plate.level:Hide()
  157.       --hide textures
  158.       plate.dragon:SetTexture(nil)
  159.       plate.border:SetTexture(nil)
  160.       plate.boss:SetTexture(nil)
  161.       plate.highlight:SetTexture(nil)
  162.       plate.castbar.border:SetTexture(nil)
  163.       plate.castbar.shield:SetTexture(nil)
  164.       plate.threat:SetTexture(nil)
  165.       --plate.castbar.nameShadow:SetTexture(nil)
  166.       --healthbar bg
  167.       plate.healthbar.bg = plate.healthbar:CreateTexture(nil,"BACKGROUND",nil,-8)
  168.       plate.healthbar.bg:SetTexture(0,0,0,1)
  169.       plate.healthbar.bg:SetAllPoints()
  170.       --name
  171.       plate.name:SetFont(STANDARD_TEXT_FONT,11,"THINOUTLINE")
  172.       plate.name:SetShadowColor(0,0,0,0)
  173.       --castbar icon
  174.       plate.castbar.icon:SetTexCoord(0.1,0.9,0.1,0.9)
  175.       plate.castbar.icon:SetSize(RDP.nameplates[plate].height,RDP.nameplates[plate].height)
  176.       --castbar bg
  177.       plate.castbar.bg = plate.castbar:CreateTexture(nil,"BACKGROUND",nil,-8)
  178.       plate.castbar.bg:SetTexture(0,0,0,1)
  179.       plate.castbar.bg:SetAllPoints()
  180.       --castbar spellname
  181.       plate.castbar.name:ClearAllPoints()
  182.       plate.castbar.name:SetPoint("BOTTOM",plate.castbar,0,-5)
  183.       plate.castbar.name:SetPoint("LEFT",plate.castbar,5,0)
  184.       plate.castbar.name:SetPoint("RIGHT",plate.castbar,-5,0)
  185.       plate.castbar.name:SetFont(STANDARD_TEXT_FONT,10,"THINOUTLINE")
  186.       plate.castbar.name:SetShadowColor(0,0,0,0)
  187.       --nameplate on show hook
  188.       plate:HookScript("OnShow", NamePlateOnShow)
  189.       --nameplate castbar on show hook
  190.       plate.castbar:HookScript("OnShow", NamePlateCastbarOnShow)
  191.       --i fix
  192.       NamePlateOnShow(plate)
  193.       --debug
  194.       --local t = plate:CreateTexture()
  195.       --t:SetTexture(1,0,0,0.3)
  196.       --t:SetAllPoints()
  197.     end
  198.  
  199.     --IsNamePlateFrame func
  200.     local function IsNamePlateFrame(obj)
  201.       local name = obj:GetName()
  202.       if name and name:find("NamePlate") then
  203.         return true
  204.       end
  205.       obj.rdp_checked = true
  206.       return false
  207.     end
  208.  
  209.     --SearchForNamePlates func
  210.     local function SearchForNamePlates(self)
  211.       local currentChildren = self:GetNumChildren()
  212.       if not currentChildren or currentChildren == 0 then return end
  213.       for _, obj in pairs({self:GetChildren()}) do
  214.         if not obj.rdp_checked and IsNamePlateFrame(obj) then
  215.           NamePlateInit(obj)
  216.         end
  217.       end
  218.     end
  219.  
  220.     --NamePlateOnUpdate func
  221.     local function NamePlateOnUpdate()
  222.       RDP:Hide()
  223.       for blizzPlate, newPlate in pairs(RDP.nameplates) do
  224.           newPlate:Hide()
  225.           if blizzPlate:IsShown() then
  226.             newPlate:SetPoint("CENTER", WorldFrame, "BOTTOMLEFT", blizzPlate:GetCenter())
  227.             newPlate:SetAlpha(blizzPlate:GetAlpha())
  228.             NamePlateNameUpdate(blizzPlate)
  229.             NamePlateHealthBarUpdate(blizzPlate)
  230.             newPlate:Show()
  231.           end
  232.       end
  233.       RDP:Show()
  234.     end
  235.  
  236.     --OnUpdate func
  237.     local function OnUpdate(self)
  238.       SearchForNamePlates(self)
  239.       NamePlateOnUpdate()
  240.     end
  241.  
  242.     -----------------------------------------
  243.     -- INIT
  244.     -----------------------------------------
  245.  
  246.     WorldFrame:HookScript("OnUpdate", OnUpdate)

SVN: http://code.google.com/p/rothui/sour...ePlateTest.lua

Maybe someone can check the code.

If you disable RDP:Show() at the bottom no nameplate will show up. This shows at all the reparenting and stuff has worked.

FPS-wise it works as intended.

I tried integrating the threat glow color into the healthbar color. This kind of works but I don't like it that much.
__________________
| Simple is beautiful.
| WoWI AddOns | GitHub | Zork (WoW)

"I wonder what the non-pathetic people are doing tonight?" - Rajesh Koothrappali (The Big Bang Theory)

Last edited by zork : 08-21-13 at 02:48 AM.
  Reply With Quote
08-21-13, 04:06 AM   #18
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,060
message redacted

Last edited by semlar : 11-04-15 at 01:50 AM.
  Reply With Quote
08-21-13, 05:46 AM   #19
zork
A Pyroguard Emberseer
 
zork's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 1,740
Hmm. I will recheck on that one. I tested critters and they looked ok.

What I'm probably going to add is a throttle for search/update function calls. Currently they run on every OnUpdate. But that is only needed for the reposition functionality.
__________________
| Simple is beautiful.
| WoWI AddOns | GitHub | Zork (WoW)

"I wonder what the non-pathetic people are doing tonight?" - Rajesh Koothrappali (The Big Bang Theory)
  Reply With Quote
08-21-13, 06:15 AM   #20
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,060
Oh, you're right. I was actually using the scale of the bar group instead of the actual nameplate because I was experimenting with something.

Apparently the bar is scaled down, not the actual plate frame, so just disregard what I said.

On an unrelated note, I've been working on a way to show friendly nameplates but prevent you from interacting with them because I want to be able to see them without them getting in the way of what you're trying to click on.

Since you can't just :Hide() the nameplate in combat because of secure frame restrictions, I've had to get a little creative with SetCVar('nameplateShowFriends', 0) toggling them on to get the frame positions and immediately back off to prevent mouse interaction.

This actually works, but there is a 2 frame delay before plates appear after toggling them on which isn't a huge deal but it also causes the cursor to blink like crazy while it switches between states. I can probably counter that but I was wondering if anyone had any better ideas for how to do this.
  Reply With Quote

WoWInterface » Developer Discussions » General Authoring Discussion » Nameplate FPS drop research

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off