in Engine

Castle Game Engine: Delphi porting progress — basic CGE window with images and text works!

From Castle Game Engine: link to original post

Castle Game Engine window rendered from Delphi Castle Game Engine in Delphi Castle Game Engine in Delphi

We have great news about Delphi compatibility with Castle Game Engine: We have basics (window, with images and text) working!

You can observe the work in this PR by Andrzej Kilijański.

Plans

The first goal is to make TCastleWindowBase with WinAPI backend working fully. This will make CGE working with Delphi for native Windows applications, using our advised approach (TCastleWindowBase). Of course more things will follow — we will want to have TCastleWindowBase running on other platforms supported by Delphi too (like mobile). And we will want to have TCastleControlBase that you can drop on FMX (and maybe VCL?) form too.

The immediate goal is now to enhance PR to include working JSON (which includes our serialization of designs) and then TCastleScene (which includes our most important rendering of 3D and 2D assets). Once this is done, most CGE examples will be compileable+runnable from Delphi.

Delphi versions

  • We target the recent Delphi versions, up to and including the latest Delphi 11 of course.

  • The port should work in principle on all Delphi versions with generics (>= 2009), though we may not be able to test it everywhere. But we’ll test at least on 10.4 and 11, and welcome anyone with older Delphi versions (but still >= 2009) to report.

  • Every variant (free Community Edition, paid Enterprise) will be supported and tested.

  • Note that we will not support ancient Delphi versions like Delphi 7. We’re aware some people use really old Delphi versions, but supporting these versions is not reasonable for us. It would require a serious effort to port code (e.g. generics) and then to keep testing every release with these old Delphi versions. In the end, Delphi 7 is really old. I advise everyone with Delphi 7 to either upgrade to the latest Delphi (the latest Community Edition is free, with some usage limits) or just switch to open-source cross-platform FPC/Lazarus.

Strings

We want the CGE API to be natural in Delphi, so the String type we use (when compiled by Delphi) is the default 16-bit Unicode Delphi string. Our font drawing (that has to deconstruct String -> sequence of Unicode numbers), and everything else, is adjusted to work with it.

Note: When compiled by FPC, we continue to follow FPC/Lazarus conventions: String is AnsiString and it just holds UTF-8 on all platforms.

(Sidenote: To be more precise, using UTF-8 everywhere is Lazarus/LCL convention. FPC AnsiString can use more complicated code-page aware mechanism. See 1, 2, 3, 4. Lazarus/LCL simplifies this (by adjusting some global vars) to “just use UTF-8 everywhere” and I think this is much simpler and thus better. It is also probably what many people expect (as a lot of FPC users are just Lazarus/LCL users). So we follow this in CGE too, setting the same global vars as LCL, to “just use UTF-8 everywhere”.)

So it’s a bit different between Delphi and FPC/Lazarus, but with the same goal: just follow the established default String meaning. Have the API natural for users coming from any compiler. For simple string usage from user code, this difference should not really matter — you write and glue strings as usual in Pascal, and both in FPC and Delphi the type and operators behave in a way that is natural.

External dependencies

For external dependencies (stuff specific to compiler and/or external to Pascal), we decide case-by-case on a best solution.

  • For XML stuff, we have a small wrapper to expose Delphi XML API in a compatible manner to FPC API. You can use this XML API in your own programs too (thus handling XML in a way that is compatible to both Delphi and FPC), but you don’t have to.

  • For URL stuff, we use FPC units with Delphi. (LGPL license of FPC RTL allows this.) This concerns units like URIParser. Majority of your code will use CGE API anyway, from CastleURIUtils and CastleDownload units, that of course work the same with Delphi and FPC.

  • For JSON — the decision will come (but preferably we’ll just use FpJsonRtti with Delphi, as it would be easiest). Your code will use CGE API anyway in CastleComponentSerialize (or even higher-level TUIState.DesignUrl) so it will not matter for you.

  • For FpImage — we will not use it with Delphi, instead relying on own image loading code (DDS, KTX, libpng for PNG etc.). It would be too cumbersome to try to pull whole FpImage into Delphi, and FpImage is not that important for us anyway (e.g. we load PNGs using libpng, without FpImage, due to FpImage being terribly slow; we load DDS and KTX without FpImage, as we need to load them efficiently to RAM and then to GPU, preserving compression like S3TC or ASTC).

Tools

Our first goal is to port the CGE runtime to Delphi — to make games using Delphi. The engine tools will mostly continue to be developed using FPC/Lazarus and they’ll just enable Delphi compiler as an alternative option. This means:

  • Build tool and editor will allow to use Delphi dcc under the hood, instead of FPC.

    Ideally, they’ll just auto-detect the compiler, by default. If you don’t have FPC/Lazarus installed, but you have Delphi installed, they should just use Delphi by default.

  • The editor itself will be compileable only by FPC/Lazarus, at least for now. As it seems not really reasonable to maintain it for both LCL and VCL/FMX at the same time, the differences are too much to maintain both versions in a painless way.

    This will make building editor with custom components on Delphi problematic at first. I mean, it will be possible — but you’ll just need an FPC/Lazarus for this, even if your game is using Delphi for the actual game build.

    We’ll be looking at better solutions for this. Maybe we’ll just have to figure out how to maintain editor that compiles with both LCL and VCL/FMX. But we have to experiment how to have it without a big maintenance burden (we do not want to just fork the editor for VCL/FMX, as it would not be maintainable in the long run).