Old 01-12-2020, 02:32 PM   #1
mespotine
Human being with feelings
 
mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig, Germany
Posts: 1,782
Default Code: How to Retina/HiDPI-your gfx-windows.

We're working on retina/hidpi-changes in Ultraschall and I think we can provide some basic code-snippets in that regard.

And it seems to be real simple:

Code:
retval, dpi = reaper.ThemeLayout_GetLayout("mcp", -3) -- get the current dpi; 256 for non retina; 512 for retina


--Now we need to tell the gfx-functions, that Retina/HiDPI is available(512)
if dpi==512 then -- if dpi==retina, set the gfx.ext_retina to 1, else to 0
  gfx.ext_retina=1 -- Retina
else
  gfx.ext_retina=0 -- no Retina
end
This should immediately make your gfx-window HiDPI/Retina. You can see it, when the blurryness isn't there anymore.

If not, please post your questions, so we can figure the rest out together.

Thanks to @rstockm, who spend a lot of time to figure that out, reading WhiteTie's theme and script.
__________________
Ultraschall-API - a Lua-functions-library4Reaper: https://forum.cockos.com/showthread....98#post2067798
Reaper Internals - Developerdocs4Reaper: https://forum.cockos.com/showthread.php?t=207635
mespotine is offline   Reply With Quote
Old 01-12-2020, 05:54 PM   #2
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 6,189
Default

so we have to add that to every gfx scripts ?


Is it compatible with reaper 5 without triggering error.?


also, no utlraschall dependency needed ?
X-Raym is offline   Reply With Quote
Old 01-12-2020, 06:40 PM   #3
mespotine
Human being with feelings
 
mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig, Germany
Posts: 1,782
Default

Independent from Ultraschall-Api.

As if Reaper 5,it should work with all versions, who have the ThemeLayout-functions available,but haven't tested.

And yes, you need to add that to every script, otherwise it will not show Retina-stuff on Retina-devices.
Maybe setting gfx.ext_retina=1 works anyway but haven't tested yet.
__________________
Ultraschall-API - a Lua-functions-library4Reaper: https://forum.cockos.com/showthread....98#post2067798
Reaper Internals - Developerdocs4Reaper: https://forum.cockos.com/showthread.php?t=207635

Last edited by mespotine; 01-12-2020 at 06:46 PM.
mespotine is offline   Reply With Quote
Old 01-14-2020, 09:16 AM   #4
mespotine
Human being with feelings
 
mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig, Germany
Posts: 1,782
Default

I have worked some more on the code-snippet, as in some places, you need to scale things up, when Retina is existing.
So, the following not only works on Reaper 5, it also gives you an additional variable "scale", with which you can scale things up.

Just use the value*scale and it should work.

The following example-code scales properly on non-Retina/HiDPI and Retina/HiDPI:

Code:
-- backwards-compatibility with gfx-scripts who shall work with early
-- Reaper 5 versions, who don't have function ThemeLayout_GetLayout available
if reaper.ThemeLayout_GetLayout~=nil then
  -- if ThemeLayout_GetLayout exists, get the dpi-value
  retval, dpi = reaper.ThemeLayout_GetLayout("tcp", -3)
end


-- Now set the gfx-window to retina/HiDPI-style by setting gfx.ext_retina 
-- and decide the proper scaling.
-- The variable scale will hold the multiplier for that.
-- So every coordinate, font-size, image-scaling that isn't scaled by Reaper itself,
-- can be altered by value*scale
if dpi=="512" then
  gfx.ext_retina=1
  scale=2
else
  gfx.ext_retina=0
  scale=1
end


gfx.init()
-- load an image and show it with correct scaling; in this case 1*scale
gfx.loadimg(1, reaper.GetResourcePath().."/data/track_icons/pads.png")
gfx.blit(1, 1*scale, 0) -- show correctly scaled picture

-- show some text with correct font-size-scaling; in this case 20*scale
gfx.setfont(1, "Times", 20*scale)
gfx.drawstr("Hello World")
__________________
Ultraschall-API - a Lua-functions-library4Reaper: https://forum.cockos.com/showthread....98#post2067798
Reaper Internals - Developerdocs4Reaper: https://forum.cockos.com/showthread.php?t=207635

Last edited by mespotine; 01-14-2020 at 11:56 AM.
mespotine is offline   Reply With Quote
Old 01-14-2020, 09:24 AM   #5
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 6,189
Default

@mespotine
Ok so if I'm correct, the * scale multiplicator have to be put in front of every blit and set font,


this means a bit more rewriting to update the scripts.


Don't you think it would be better if REAPER internally took care of blit and set font scale based on the gfx.ext_retina value ?
And why not if it also took care or determining DPI etc so we wouldn't have to update anything ?




Thx for digging this subject, it will come handy at some point
X-Raym is offline   Reply With Quote
Old 01-14-2020, 09:31 AM   #6
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,530
Default

Fonts aren't measured in pixels, so you can't necessarily multiply them directly by the scale. That is, 24pt Arial isn't twice the size of 12pt Arial.

The "correct" approach would be to measure the font for a given point size so you can convert 12pt -> 16px, double it to 32 px, and then 32px -> 18pt, etc. This can be done dynamically as each font size is requested by the script and memoized so calculations are only ever done once for a given size.
Lokasenna is offline   Reply With Quote
Old 01-14-2020, 09:33 AM   #7
mespotine
Human being with feelings
 
mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig, Germany
Posts: 1,782
Default

I haven't tested these things completely, and I agree that this should be the case.

However, I think it's still better, if you can control, which thing is scaled and which not. We currently run into the same issue, that when retinarizing our theme, we need to rebuild many parts from scratch, even though it looked good on non-retina.
So I think, HiDPI/Retina isn't just "scale things up" but rather some more difficult.


tl;dr; just test it and share your experience. The code-snippet above is just meant to be a start, but all the edge-cases are completely undiscovered yet.
__________________
Ultraschall-API - a Lua-functions-library4Reaper: https://forum.cockos.com/showthread....98#post2067798
Reaper Internals - Developerdocs4Reaper: https://forum.cockos.com/showthread.php?t=207635
mespotine is offline   Reply With Quote
Old 01-14-2020, 09:34 AM   #8
mespotine
Human being with feelings
 
mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig, Germany
Posts: 1,782
Default

Quote:
Originally Posted by Lokasenna View Post
Fonts aren't measured in pixels, so you can't necessarily multiply them directly by the scale. That is, 24pt Arial isn't twice the size of 12pt Arial.

The "correct" approach would be to measure the font for a given point size so you can convert 12pt -> 16px, double it to 32 px, and then 32px -> 18pt, etc. This can be done dynamically as each font size is requested by the script and memoized so calculations are only ever done once for a given size.
Any idea on how to do that properly? Would be really helpful for us right now...
__________________
Ultraschall-API - a Lua-functions-library4Reaper: https://forum.cockos.com/showthread....98#post2067798
Reaper Internals - Developerdocs4Reaper: https://forum.cockos.com/showthread.php?t=207635
mespotine is offline   Reply With Quote
Old 01-14-2020, 10:12 AM   #9
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,530
Default

Quote:
Originally Posted by mespotine View Post
Any idea on how to do that properly? Would be really helpful for us right now...
I don't have Reaper on my work machine so I can't test this, but something like:
Code:
local scale = 1.3
local CHAR = "M"

local scaledFontCache = {
  --[[
  Will have the following structure:

  Arial = {     font face
    [12] = 18   original point size: scaled point size
  }
  ]]--
}

local fontSizeCache = {
  --[[
  Will have the following structure:

  Arial = {     font face
    [12] = 32   point size: pixel size
  }
  ]]--
}

local function getScaledFontSize(font, size)
  -- See if we've scaled this font + size already
  local cached = scaledFontCache[font] and scaledFontCache[font][size]
  if cached then return cached end

  -- Initialize tables for this font if necessary
  if not scaledFontCache[font] then 
    scaledFontCache[font] = {} 
    fontSizeCache[font] = {}
  end

  gfx.setfont(font, size)
  local _, originalHeight = gfx.measurestr(CHAR)
  local targetHeight = originalHeight * scale

  -- Increase the size and measure until we hit the target height
  -- This could be done more efficiently with something like a binary search
  local currentSize = size
  local currentHeight = 0
  repeat
    currentSize = currentSize + 1

    -- See if we've measured this font + size already
    if fontSizeCache[font][currentSize] then
      currentHeight = fontSizeCache[font][currentSize]
    else
      gfx.setfont(font, currentSize)
      _, currentHeight = gfx.measurestr(CHAR)

      -- Add this measurement to the size cache
      fontSizeCache[font][currentSize] = currentHeight
    end
  until (currentHeight >= targetHeight)

  -- Add this scaled font + size to the cache
  scaledFontCache[font][size] = currentSize

  return currentSize
end
Lokasenna is offline   Reply With Quote
Old 01-14-2020, 10:13 AM   #10
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,530
Default

My GUI does something similar but with every individual character in the font so it can fit text to a given size: https://github.com/jalovatt/Lokasenn...Core.lua#L1784
Lokasenna is offline   Reply With Quote
Old 01-14-2020, 11:46 AM   #11
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 438
Default

Quote:
Originally Posted by mespotine View Post
Code:
if reaper.ThemeLayout_GetLayout~=nil then
  -- if ThemeLayout_GetLayout exists, get the dpi-value
  retval, dpi = reaper.ThemeLayout_GetLayout("tcp", -3)
end
...
if dpi==512 then
  gfx.ext_retina=1
  scale=2
else
  gfx.ext_retina=0
  scale=1
end
Since
Code:
 reaper.ThemeLayout_GetLayout()
returns a string as a value, shouldn't dpi be converted using
Code:
tonumber(dpi)
???
__________________
MP 12 Core 3.46GHZ 48GB OSX10.11.6, MBP 15" 2012 OSX10.12, RME Fireface UFX, MCU,
Reaper 5, SD2, Omnisphere, Wave Altiverb, PSP, VB3, Izotope, Scuffham, Soundtoys 5, Slate All Plugins.
lexaproductions is offline   Reply With Quote
Old 01-14-2020, 11:48 AM   #12
mespotine
Human being with feelings
 
mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig, Germany
Posts: 1,782
Default

Not necessary, as Lua should be able to convert it automatically.

Unlike other programming-languages.
__________________
Ultraschall-API - a Lua-functions-library4Reaper: https://forum.cockos.com/showthread....98#post2067798
Reaper Internals - Developerdocs4Reaper: https://forum.cockos.com/showthread.php?t=207635
mespotine is offline   Reply With Quote
Old 01-14-2020, 11:53 AM   #13
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 6,189
Default

I think lexaproduction is right in this case :P


dpi = "512"
if dpi==512 then

scale=2
else

scale=1
end

print (scale)
-- this return scale = 1

Lua automatic type conversions works in other context like string concatenation.

Last edited by X-Raym; 01-14-2020 at 11:53 AM. Reason: type conversion
X-Raym is offline   Reply With Quote
Old 01-14-2020, 11:53 AM   #14
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,530
Default

Quote:
Originally Posted by mespotine View Post
Not necessary, as Lua should be able to convert it automatically.

Unlike other programming-languages.
Not for comparisons; 512 == "512" is false in Lua.

"512" + 1 gives you 513.0 though.
Lokasenna is offline   Reply With Quote
Old 01-14-2020, 11:55 AM   #15
mespotine
Human being with feelings
 
mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig, Germany
Posts: 1,782
Default

Okay, these kind of edge-cases were a reason, why I always demand the right datatype in my US-API-functions.

I'll correct my code above...

Edit: put the 512 in "" now.
__________________
Ultraschall-API - a Lua-functions-library4Reaper: https://forum.cockos.com/showthread....98#post2067798
Reaper Internals - Developerdocs4Reaper: https://forum.cockos.com/showthread.php?t=207635
mespotine is offline   Reply With Quote
Old 01-14-2020, 11:59 AM   #16
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 438
Default

Well this works
Code:
  local function gfx_RetinaMode()
    local dpi_retval, dpi_value = reaper.ThemeLayout_GetLayout("mcp", -3)
    if tonumber(dpi_value) == 256 then
	gfx.ext_retina=0 -- no Retina
	return false
    end
    gfx.ext_retina=1 -- Retina
    return true
    end
  end
But this always return "TRUE" no matter if I use a retina laptop or not
Code:
  
  local function gfx_RetinaMode()
    local dpi_retval, dpi_value = reaper.ThemeLayout_GetLayout("mcp", -3)
    if dpi_value == 256 then
	gfx.ext_retina=0 -- no Retina
	return false
    end
    gfx.ext_retina=1 -- Retina
    return true
    end
  end

Edit: Ooops you guys beat me to it.
__________________
MP 12 Core 3.46GHZ 48GB OSX10.11.6, MBP 15" 2012 OSX10.12, RME Fireface UFX, MCU,
Reaper 5, SD2, Omnisphere, Wave Altiverb, PSP, VB3, Izotope, Scuffham, Soundtoys 5, Slate All Plugins.
lexaproductions is offline   Reply With Quote
Reply

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

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

Forum Jump


All times are GMT -7. The time now is 02:50 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2020, vBulletin Solutions Inc.