Skip to content

Instantly share code, notes, and snippets.

@toger5
Last active May 10, 2019 20:28
Show Gist options
  • Save toger5/935ce8b29d533d5a258683b6173f9f6a to your computer and use it in GitHub Desktop.
Save toger5/935ce8b29d533d5a258683b6173f9f6a to your computer and use it in GitHub Desktop.

Implementation of dpi adaption in Godot

The theme is the master class that gets asked for style boxes, constants and fonts all the time. The theme is asked multiple times per node and hundreds of times a frame.

It's that simple. However, there is one great additional thing in Godot which makes the dpi addition easy to implement. There are two ways of accessing values in a theme. theme->get_styebox() and my_control->get_stylebox().

  • When asking the theme, it just calls the hash map with styles, and that's it.
  • When asking a control, it does some logic:
    1. font (cached) the next node up to the tree that has a theme assigned.
    2. check if the theme has the requested style. Yes: return it! No: go to the next Control with a theme. If nothing got found search with the next class name (if it was a Texture Button, search for styles for Button) and so on.

There is no better place than doing the dpi in that section. This way it can be a property of a node subtree and not for an entire theme!

So whenever a style is asked for the correct dpi gets calculated and an adapted sb gets returned. (This does not interfere with any inspector stuff since the inspector does not use the Control::get_stylebox method) That's it, almost ;)

How to use

Just add a theme to the Control you want to change the dpi. ALL CHILDREN WILL GET DPI SCALED AS WELL. You don't need to add any other theme property then the dpi_scale. For the Rest of the values (fonts styles icons), Godot will use the next theme in the tree (worst case the default theme).

Performance

It is already quite bad that each Control::get_stylebox request results in multiple while loops with hash map calls. However, with the dpi stuff I saw the opportunity to cache everything. So only on NOTIFICATION::THEME_CHANGED the while loop and the dpi adaption gets executed. Otherwise, it just calls a local hash map on the Control itself which only has the elements needed (Only a Ref actually to be more precise) So the performance should be better than without the dpi patch

Dpi adaption

I mentioned that the dpi gets adapted. What does that mean?

  • For Textures (icons) A new class got added. Scaled/Theme_texture (haven't decided on the name yet). This texture also stores a custom size value and fakes its size to be bigger than the texture res. The draw function is overridden and draws a stretched version of the texture. I Also have the plan to give that texture wrapper a modulate color. so that you can have multiple textures with the same Bitmap but with different colors. The editor could use white icons in many places and use those wrapped textures.
  • For Fonts Only dynamic fonts are supported atm. They just get duplicated, and the size gets changed. The font itself is a small class and uses the font data which is already designed to support multiple size versions. So basically it is the same than a wrapped font.
  • For style box flat/texture A wrapper class with a ref to the node that requested the style box. When the style box gets asked for margins, it scales it by the dpi environment of the Control. Whenever the style box draws, it uses the dpi value of the next theme in the controls (in the draw the get_current_drawn control function is used) tree.

So basically all the objects used by nodes are just wrappers which have the correct behavior in the right context. In addition to that also those wrappers are cached and the Control::get_stylebox/font/icon... functions perform much better now.

The improvement allows for an excellent performance. When not changing the dpi it should run faster than before thanks to the caching. If the dpi_scale gets changed it only reloads all controls which use the changed theme. That is as heavy as drawing was before since it will loop through the themes again as explained at the beginning. It is still fast enough to animate the dpi scale. I tweeted about that some time ago.

Created a dynamic dpi system for #GodotEngine. So no recreation of the theme is needed to provide multiple dpi lvls. The editor hacks for the dpi scale can get removed and all Godot projects can provide different dpi lvls without setting up multiple themes. pic.twitter.com/tGWFkSCvW9

— Timo K (@Toger50) March 24, 2019
@fire
Copy link

fire commented May 9, 2019

@toger5
Copy link
Author

toger5 commented May 10, 2019

Ty, updated the gits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment