WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   Lua/XML Help (https://www.wowinterface.com/forums/forumdisplay.php?f=16)
-   -   Achieving pixel perfection (https://www.wowinterface.com/forums/showthread.php?t=56898)

Lyak 12-14-18 11:47 PM

Achieving pixel perfection
 
Hi all,

I wasn't really worried about the pixel perfection, but my frames started to cause an issue with the placement and sizing.

Where should I start? If possible, I would like to get some explanation on how and why(?) it works rather than just using an already existing solution.

Could anyone please help me out regarding this?

Thank you!

d87 12-15-18 02:51 AM

WoW screen is using these sort of floating point virtual pixels, they go up to 768 in height and proportionally for aspect ratio in width, and they map onto your real resolution. And then there's possibly global UI scale in the mix. In the end the line that you wanted to be 2 virtual pixels wide ends up snapping to either 2 or 3 real pixels depending on where it is
So you need to reverse this process and find out what amount of virtual pixels is corresponding to real pixels

Here's what i use to find it:
Code:

local res = GetCVar("gxWindowedResolution")
if res then
    local w,h = string.match(res, "(%d+)x(%d+)")
    pmult = (768/h) / UIParent:GetScale()
end

Not sure if consistently using whole number of real pixels guarantees perfection, but in my experience it makes it better at least. Also ideally you don't want to use UI scale

myrroddin 12-15-18 03:39 AM

If your display, or if writing a public addon, the user's display, is greater than 1920x1080, you need to do two things:
  1. Set the CVar scale to 768/height
  2. Set UIParent's scale to 768/height
This is because WoW won't let you set a CVar scale lower than 0.64 which won't look correct on monitors with a resolution greater than 1080p.

If the height is equal to or less than 1920, only do the first thing. Now here are the hard parts:
  1. Scale your frame initially by the above scale, in which it will look tiny with unreadable text.
  2. Increase the height and/or width of the frame until it looks good, but leave the scale alone.
  3. As mentioned, you need to place your newly scaled frame on an even pixel, unless that isn't centered. You'll have to figure that out frame by frame.
  4. Assuming you let the user set a scale, which is a bad idea at this point, wrap your "user scale" instead in height or width adjustments providing the illusion of scaling up or down. A better idea is to not provide a scaling option and go straight for height or width.
  5. Place the adjusted frame again so it sits evenly.

Lyak 12-15-18 08:40 PM

Quote:

Originally Posted by d87 (Post 331037)
WoW screen is using these sort of floating point virtual pixels, they go up to 768 in height and proportionally for aspect ratio in width, and they map onto your real resolution. And then there's possibly global UI scale in the mix. In the end the line that you wanted to be 2 virtual pixels wide ends up snapping to either 2 or 3 real pixels depending on where it is
So you need to reverse this process and find out what amount of virtual pixels is corresponding to real pixels

Here's what i use to find it:
Code:

local res = GetCVar("gxWindowedResolution")
if res then
    local w,h = string.match(res, "(%d+)x(%d+)")
    pmult = (768/h) / UIParent:GetScale()
end

Not sure if consistently using whole number of real pixels guarantees perfection, but in my experience it makes it better at least. Also ideally you don't want to use UI scale

So, basically what wow does is it take the real value, goes through some calculation then converts the real value to wow sepcific virtual value. Am I getting it right?

And after all what I'll have to do is multiply pmult whenever I'm setting the position or the size?

Like:
Lua Code:
  1. frame:SetSize(width * pmult, height * pmult);
  2. frame:SetPoint("CENTER", UIParent, "CENTER", oX * pmult, oY * pmult);

Quote:

Originally Posted by myrroddin (Post 331038)
If your display, or if writing a public addon, the user's display, is greater than 1920x1080, you need to do two things:
  1. Set the CVar scale to 768/height
  2. Set UIParent's scale to 768/height
This is because WoW won't let you set a CVar scale lower than 0.64 which won't look correct on monitors with a resolution greater than 1080p.

If the height is equal to or less than 1920, only do the first thing. Now here are the hard parts:
  1. Scale your frame initially by the above scale, in which it will look tiny with unreadable text.
  2. Increase the height and/or width of the frame until it looks good, but leave the scale alone.
  3. As mentioned, you need to place your newly scaled frame on an even pixel, unless that isn't centered. You'll have to figure that out frame by frame.
  4. Assuming you let the user set a scale, which is a bad idea at this point, wrap your "user scale" instead in height or width adjustments providing the illusion of scaling up or down. A better idea is to not provide a scaling option and go straight for height or width.
  5. Place the adjusted frame again so it sits evenly.

Let me get things one by one.

If the screen size is greater than 1920x1080, I'll have to set both UIScale CVar and UIParent's scale to 768/height as you have advised. However, if I switch UIParent's scale to such, wouldn't that affect all other frames having UIParent as a parent frame? If the answer is yes, would it be okay to use my own UIParent like the following to avoid such issues?

Lua Code:
  1. local uiParent = CreateFrame("Frame", nil, UIParent);
  2. uiParent:SetAllPoints(true);
  3. uiParent:SetScale(xxxx);
  4.  
  5. addon.UIParent = uiParent;
  6.  
  7. local frame = CreateFrame("Frame", nil, addon.UIParent);
  8. -- Continue positioning, sizing and etc.

myrroddin 12-16-18 06:14 AM

About UIParent, yes, that would be true, which is why, among other pixel perfect enabled addons, ElvUI creates their own "ElvUIParent". I'm not 100% sure of what name they chose, but it doesn't matter, as that is just a variable.

When doing pixel perfection, ElvUI doesn't scale UIParent, instead scaling their own version then SetAllPoints so it fits on UIParent.

This has the added benefit of not messing with other addons that depend on UIParent's scale.

myrroddin 12-16-18 06:33 AM

While I have never tested it, I'm going to assume that your pmult example will be not what you want if you multiply height and width.

Height and width are integers representing pixels. If pmult is not an integer (it will always be a real or whole number, never an integer) then there is no possible way for either height or width to sit on a pixel. Instead, height and width will sit in between pixels, and look wrong.

That's why I suggested to never apply pmult to height or width. Scale on the other hand is a whole or real number, which means it includes integers, albeit as 1.0, 2.0, 3.0 rather than 1, 2, 3.

Should you be hellbent on allowing pmult on height or width, then you need to round up or down to the nearest integer after you multiply by pmult. It's a couple of extra steps.

When rounding, I further suggest a couple of sanity checks:
  • Use advanced rounding. If < 0.5 then round down, if >= 0.5 round up.
  • Use SetClampedToScreen(true). It becomes your friend.
  • Check that your rounded value is >=1 and <= (width - frameSize). You are trying to get the frame to fit on UIParent.
  • Double check height and width are modulo 2 == 0 (% 2 == 0). Should the result <= 1 and you are trying to center the frame, use math.ceil. That's the best you can do.

Lyak 12-17-18 02:40 PM

Quote:

Originally Posted by myrroddin (Post 331049)
That's why I suggested to never apply pmult to height or width. Scale on the other hand is a whole or real number, which means it includes integers, albeit as 1.0, 2.0, 3.0 rather than 1, 2, 3.

So, your original solution would not cause such issues, right?

Hm... if that's the case I should stick to your way.

Let me test them first and I'll come back for further advice.

Thank you!

Leaker 01-14-19 05:48 PM

Quote:

Originally Posted by myrroddin (Post 331038)
If your display, or if writing a public addon, the user's display, is greater than 1920x1080, you need to do two things:
  1. Set the CVar scale to 768/height
  2. Set UIParent's scale to 768/height
This is because WoW won't let you set a CVar scale lower than 0.64 which won't look correct on monitors with a resolution greater than 1080p.

If the height is equal to or less than 1920, only do the first thing. Now here are the hard parts:
  1. Scale your frame initially by the above scale, in which it will look tiny with unreadable text.
  2. Increase the height and/or width of the frame until it looks good, but leave the scale alone.
  3. As mentioned, you need to place your newly scaled frame on an even pixel, unless that isn't centered. You'll have to figure that out frame by frame.
  4. Assuming you let the user set a scale, which is a bad idea at this point, wrap your "user scale" instead in height or width adjustments providing the illusion of scaling up or down. A better idea is to not provide a scaling option and go straight for height or width.
  5. Place the adjusted frame again so it sits evenly.

I am also interested in creating a pixel perfection, but having difficulties with fully understanding your method as a newb developer :confused:

If you don't mind, could you please provide me some working example?

My current screen resolution is 1920x1080, but am not willing to limit this to such.

Many thanks!

myrroddin 01-15-19 06:49 PM

https://wow.gamepedia.com/UI_Scale


All times are GMT -6. The time now is 12:19 PM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2004 - 2022 MMOUI