Recent

Author Topic: Adding high DPI support to existing game  (Read 548 times)

Chronos

  • Full Member
  • ***
  • Posts: 212
    • PascalClassLibrary
Adding high DPI support to existing game
« on: June 15, 2019, 09:47:24 pm »
In my spare time I am working on Lazarus port of originally Delphi game called C-evo (https://app.zdechov.net/c-evo/) It is not "production" ready yet but it is playable. One of the problems which I still need to solve is high DPI support. Now everybody has big screen with Full HD or better resolution. Under Windows OS it is possible to let the game run in original DPI and OS will take care of up-scaling. But it simply doesn't look sharp and under Linux there isn't such option and graphics and text under Linux looks kind of messy. So you can say, just add high DPI support and the problem solved. But how to do that? Simply without much change of source code? Code base for the game is pretty huge and original author used a lot of constants for custom drawing. So to scale all these variables and numeric constants is really huge task and it would make the code much bigger and lot less readable. It would take weeks to modify and test all that code.

If I would use Delphi and VCL then the logical choice would be to convert the game to use FMX which has DPI independent coordinate system. Also as a bonus I would be able to build the game for Android and iOS. But if I need to stick with Lazarus then I need to use just LCL which is basically equivalent to VCL. And it wasn't designed for high DPI support from the start so it's high DPI support was added later and it is pretty hard to use for big projects.

I am not aware of any nice complete game with fully custom graphics written in Lazarus/FPC. Or even such game with high DPI support which is nowadays must have. So I can't simply look into source code of other such project to learn from an example.

So if you have any tips and suggestions how to proceed effectively with such task, please write them down. They may be useful for other developers as well.

Direct link to source code: https:/svn.zdechov.net/c-evo/trunk/  (if somebody would like to try on his/her own)
High DPI wiki article: https://wiki.freepascal.org/High_DPI

SymbolicFrank

  • Hero Member
  • *****
  • Posts: 635
Re: Adding high DPI support to existing game
« Reply #1 on: June 15, 2019, 10:33:22 pm »
In short: High DPI support is a total mess on any OS I know of.

If you don't support all the resolutions, the following happens:

- Windows paints it to a low-res bitmap, and stretches it.

- Apple ignores everything that isn't a power of 2 of the target resolution.

- Linux tells your application what to do.

Most everything else only supports fixed resolutions.

wp

  • Hero Member
  • *****
  • Posts: 6354
Re: Adding high DPI support to existing game
« Reply #2 on: June 15, 2019, 11:20:26 pm »
Unfortunately high-dpi support of Lazarus is not well-documented, just a short note in https://wiki.lazarus.freepascal.org/High_DPI#High_DPI_in_Lazarus_1.8_and_above.

In addition to that, some of my experiences made with conversion of several packages to high-dpi:
  • At the application level, you turn on high-dpi support by checking the box "LCL scaling" in the project options, and on Windows select a "DPI awareness" option different from "off". If you only use LCL controls you should be fine, all LCL controls are high-dpi aware (well... some rarely used dimensions are forgotten here and there, if you find one file a bug report).
  • If you create controls at runtime you probably use absolute coordinate, e.g. "Edit.Left := 6;" - this is not high-dpi aware. Use one of the scaling functions inherited from TControl: "Edit.Left := Scale96ToForm(6);" which means: "the value 6 is assumed to be for 96 ppi (100%); on other resolutions scale it to the ppi of the form".
  • It is better to avoid absolute positioning of controls altogether. Better to use the Anchor Editor to align controls with respect to others, it automatically handles high-dpi scaling correctly.
  • If you use your own components: Override the method DoAutoAdjustLayout and apply the specified multiplier to inner dimensions of your controls to be scaled. This method is called when the current resolution differs from the ppi of the form. But be warned: it may be tricky to avoid double scaling. Find examples in the LCL, such as TToolbar, or third-party components, e.g. TvPlanIt or some JVCL controls (these are maintained and were made high-dpi aware by myself)
  • If you use third-party controls and they are not high-dpi aware you are out of luck. Contact the author and report this problem. Of course you can try to work around with manual scaling like that mentioned above.
  • Images are a special problem. Use the new imagelist of Laz 2.0+. Set its "Scaled" property to true to make it rescale the images to the required size. For better quality, you can add the same image at different sizes. Since down-scaling from large images results in better quality than upscaling from small images it is preferable to primariy add large images.
  • Controls with a "Glyph" property, such a TBitBtn or TSpeedButton, have image list support now; you should put the images into image lists instead of assigning them to the Glyph property directly - this takes adavantage of the scaling features of the new image list.
  • If there are other images which are loaded from files or from the resources provide them at the largest size needed for the highest resolution and have TImage scale it down by setting is "Proportional" property to true.
Sorry, my answer cannot be more specific. If you have a particular problem post a question (along with (simple) source code), maybe I can answer. Ondrej who wrote the LCL scaling support has left the developers team, but is sometimes still around in the forum, maybe he can help, too.

The Lazarus IDE shows that is is possible to make large programs high-dpi aware.
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

Chronos

  • Full Member
  • ***
  • Posts: 212
    • PascalClassLibrary
Re: Adding high DPI support to existing game
« Reply #3 on: June 16, 2019, 12:18:58 am »
Thanks for the response. I know about LCL scaling capabilities even I don't use them all as they are still in development. All my application has that scaling enabled. Switching on scaling for new LCL application is logical step to support high DPI but if I want to modify large existing game which heavily use custom controls and textures then it is not so easy as switching on LCL scaling and using Scale96ToForm. I tried to add Scale96ToForm function call to lot of places where fixed constants are but I didn't get too far. It was really mess to have Scale96ToForm everywhere. I know, the game code is old dated back to days of old Delphi 4 version but I can't blame the author for anything. He was able to successfully release several stable versions over time and the game has nice custom graphics. Interface is almost completely covered with custom graphics. Do we have more such nice open source games in Pascal or even in Lazarus?

Also I understand the way how LCL high DPI support is trying to solve the problem. But it really has one basic flaw and limitation in the design. The coordinate system is not DPI independent. So scaling needs to be done more on programmer side than on components and widget side. If I want to paint custom graphics on Canvas then I need to use scaling function everywhere which really makes code less readable and maintainable. The ultimate solution would be to draw with DPI independent coordinates and scaling would be done at widget side. Similarly to FMX. I wonder why nobody did it already? Just because of time constraints? For LCL the decision to support high DPI only partially is clear because we don't want to break existing applications. Sure until somebody will come up with better solution then LCL implementation will better than nothing.

I am trying to find better way to scale application in Lazarus without LCL partial scaling support and heavy need of ScaleTo like function. Was somebody able to do that for his own application?

lainz

  • Hero Member
  • *****
  • Posts: 3284
    • Lainz
Re: Adding high DPI support to existing game
« Reply #4 on: June 16, 2019, 03:36:45 am »
I don't know how to do propper image scaling with bgrabitmap on Mac os retina. I don't have one at first place. But the people who knows don't use bgrabitmap so is a limitation of that library if you need to use it at any time.

Linux and windows works almost the same in my opinion.

I did a port to high dpi but scaling every constant by hand. Plus the LCL scaling that I don't like it too much... Since it works really fine if you work at 96 dpi .. im forced to use blurry Lazarus when I set windows to high dpi to don't damage forms. ( I disabled high dpi for the idea from shortcut properties).

That's my point of view. Is not hard but tricky.