Optimizing memory usage, part 1: efficient step animation, using component system in X3D nodes (no interfaces), less memory used by sprite sheets

Posted on

Lots of sprite sheets with lots of animations

Nudged by the report of high memory usage I want to seriously optimize memory usage of CGE. Right now X3D nodes cost too much in memory — which limits some use-cases (when spawning a lot of TCastleScenes would be the most natural solution), and it affects both loading and runtime performance (as loading is slower when you need to clone/initialize more memory, and performance is slow when the cache is underutilized).

A first wave of improvements has already landed in the engine. A 2nd wave is in progress — it depends on remaking how all X3D nodes are set up, so it’s a big rework (but it was a long time coming).

Things done now:

  1. We now have an efficient step interpolation mode (see TInterpolation), used automatically by sprite sheets and glTF models with step animation.

    While “step” interpolation was possible previously, but it was (ab)using the linear interpolation calculation, by duplicating keys. This was wasting both memory (2x data needed) and time (doing useless lerp operations).

  2. We have simplified our X3D nodes inheritance. We use now TNodeFunctionality (a simple component system inside X3D nodes) with some descendants like TTimeDependentFunctionality and TTransformFunctionality. We no longer use Pascal interfaces for them. There are actually 2 reasons for it:

    1. In some cases, we really wanted to share implementation, not just API. So interfaces were never a proper tool.

      In effect our new TTimeDependentFunctionality is a much simplified and more natural old TInternalTimeDependentHandler, the new concept just fits our needs better.

    2. I never really grew to like COM interfaces. In FPC/Lazarus we have CORBA interfaces, and I made no secret that I like CORBA interfaces much more (basically, they work more like Java and C# interfaces, and are not entangled with unrelated things like memory management or COM technology). But Delphi only has COM interfaces, so CORBA interfaces are not available to us.

      This introduces quirky code when using interfaces, as we do not want the automatic garbage collection that the COM interfaces bring (and one has to watch out for it, even with hacked _AddRef, _Release like TComponent does). So one has to watch for lifetime of temporary values.

  3. CoordinateInterpolator in sprite sheets can be often much simpler or even removed completely. This saves memory and execution time.

Comments on the forum ➤

Watch our presentation at DelphiCon on November 17th

Posted on

Castle Game Engine window rendered from Delphi

This year DelphiCon, an annual Delphi conference, is fully online and free. As we’re working hard on a Delphi port right now of course I will show Castle Game Engine there! I guess it will be the first public showing of CGE on Delphi.

Register for the talk here!

Our presentation is on November 17 (Wednesday). The whole conference is 16-18 November, there’s a lot of talks including stuff around cross-platform dev — check it out 🙂

Comments on the forum ➤

Editor gizmos improvements: XY movement comfortable for 2D games and 2 important fixes

Posted on

Gizmo in 2D game

We improved behavior of gizmos (for translating, rotating, scaling TCastleTransform in the editor):

  1. The translation mode is more comfortable for 2D games. When you have typical 2D projection (orthographic, and camera looks along -Z axis) then

    • clicking on a special box in the middle of the gizmo,

    • or clicking on the Z arrow (previously a useless blue dot in case of such typical 2D projection)

    … allows to move the object simultaneously in X and Y. This allows to just move the object in 2D freely. This is done thanks to Andrzej Kilijański!

  2. Fixed a case when translation may behave a bit crazy when the transformation had both rotation and non-uniform scale applied.

  3. Fixed imprecise calculations (that caused the gizmo size to “tremble” sometimes) when using on a scene with large bounding box.

Comments on the forum ➤

Occlusion query (documentation and fixes)

Posted on

Occlusion Query

We now have an extensive docs about occlusion query in Castle Game Engine.

We also fixed occlusion query for shapes with blending, and made it behave correctly when batching is used (right now, batching has to be disabled for the scenes that use occlusion query).

On a more general note: Sorry for the relative silence in the news in last 2 weeks. We’re busy making a few things at once, big (memory optimizations, Delphi compatibility, docking editor) and small (Android x86, editor gizmos improvements). I will gradually post about them 🙂

Comments on the forum ➤

Creating OpenGLES 3 context on mobile

Posted on

Gallery of Particle System

We now load OpenGLES 3 context on mobile when possible (but still fallback to OpenGLES 2).

Core Castle Game Engine for now doesn’t actually use any OpenGLES 3 functionality. But we make available SetTransformFeedbackVaryings for shaders, which can be utilized by components like Particle Emitter (particle system for 3D and 2D in CGE) to now work on mobile.

Many thanks go to Trung Le (Kagamma) for implementing this!

iOS note

We made it work for both Android and iOS. But then we disabled it for iOS, at least for now.

Because it caused a small regression in Unholy Society — sometimes using FBOs causes a weird shift in further display. This was observed only on iOS + OpenGLES 3 (same code works OK on everything else: OpenGL on desktops, Android with OpenGLES 2 and 3, iOS + OpenGLES 2). Evidently Apple didn’t make the OpenGLES 3 truly backward compatible with OpenGLES 2. If you want to try it anyway (everything else works, the regression likely doesn’t affect most applications), adjust the code responsible for context creation on iOS in tools/build-tool/data/ios/xcode_project/cge_project_name/OpenGLController.m. You want to use this:

    EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
    if (context == nil) {
        context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    }

Further details about this will follow. Ideally we want to workaround this problem at CGE level, and just create OpenGLES 3 context on iOS by default, same as on Android. If this will be impossible, we’ll give you a choice whether to try creating OpenGLES 3 context on iOS in CastleEngineManifest.xml.

Comments on the forum ➤

Delphi Port Progress – window, UI, designs (JSON) serialization, XML compatibility, Delphi 11 / 10.4, Windows 32 and 64, PNG using PngImage

Posted on

state_events example using Delphi
TCastleEdit in Delphi
Various UI controls using CGE in Delphi
test_all_state_events example using Delphi
TCastleTimer in Delphi

We made great progress porting Castle Game Engine to Delphi.

  • Running an engine in a window (using TCastleWindowBase) on Windows works.

  • User interface controls (things in CastleControls, CastleUIControls units, like buttons, images, edit boxes etc.) all work.

  • Reading and writing design files, like .castle-user-interface, that you create using CGE editor works. We’re using a version of FpJson and FpJsonRtti from FPC, with minimal adjustments to make them compile in Delphi.

  • Examples from examples/user_interface now work in Delphi.

  • XML compatibility much improved. This gives us compatibility layer to access XML in Delphi using similar classes as we use in FPC DOM and friends.

  • Tested now on both Delphi 11 and 10.4.

  • Tested now on both Windows 32-bit and 64-bit.

  • Reading PNG has a fallback on built-in PngImage unit available in Delphi. This is used if libpng DLL is not available at runtime.

See the previous news post for all plans about Delphi port. Everything described here is public of course, you can take a look at how it works already: see the pull request. In particular you can try it yourself, just take delphi branch from Andrzej Kilijański’s CGE fork.

Comments on the forum (1) ➤

Arch Linux package

Posted on

CGE editor on Arch Linux

Arch Linux users can now install Castle Game Engine from AUR (Arch User Repository).

The package is available on https://aur.archlinux.org/packages/castle-engine-git/ . Follow the standard AUR installation process:

  • Do it manually following AUR docs, like

    wget https://aur.archlinux.org/cgit/aur.git/snapshot/castle-engine-git.tar.gz
    tar xzvf castle-engine-git.tar.gz 
    cd castle-engine-git/
    makepkg -sri
    
  • Or use a helper like paru. Once you have it working, just use paru -S castle-engine-git.

Thanks go to Kagamma (Trung Le) for doing this!

Comments on the forum ➤

Google Play Billing Library upgrade

Posted on

unholy_iap

To implement in-app purchases on Android, under the hood we use Google Play Billing Library. We have just upgraded the way we use it, to follow the latest API (no AIDL, and use built-in asynchronous methods).

This is important if you use in-app purchases on Android. Since November 2021 (in one month) Google will no longer allow uploading Android builds (APK, AAB) that use the old API.

There’s no change to the Castle Game Engine public API. Just use the Pascal unit CastleInAppPurchases, following the documentation how to implement in-app purchases on both Android and iOS. Both consumable and non-consumable in-app purchases are supported.

The Unholy Society is already using the new API for our only purchase in the game.

Comments on the forum ➤

Android builds now include libpng (over 10x speedup at PNG loading), new platformer release

Posted on

Platformer demo - jumping on higher platforms

Enjoy much faster PNG loading on Android now, as the libpng library is automatically packaged with your applications. Various measurements, like this one, or testing “The Unholy Society” UI loading time confirm that the speedup is huge, even more than 10x compared to previous FpImage that we used on Android.

In general, there’s no need to do anything for developers. The Android service “png” will be automatically added to the projects that include some PNG files in their data. But you can also request PNG explicitly (just for Android, or for all applicable platforms), follow the docs.

And you can enjoy a new faster level loading in our new platformer release on itch.io, that includes an Android (APK) build.

Comments on the forum ➤

FMOD sound backend improvements: spatial sounds, priority, distance model, offset

Posted on

FMOD logo

Our FMOD sound backend, that integrates CGE with the FMOD sound system, supports now 3D (spatial) sounds. This means that sound position in 3D is reflected in your ears — things that are closer are louder, things that are on your right are mostly in your right speakers etc.

The improvements outlined here make our FMOD sound backend at par (the same features, with the same CGE API) with our default OpenAL sound backend. This matters, as it opens the door for future integration with FMOD Studio. The goal of FMOD Studio is to make the work of sound designer easier. The sfx person can create sound effects in FMOD Studio, in a way that is agnostic to the game engine, and the code (like your game) simply sends “events” that may cause some sound effect (playing something, stopping something, fading in/out something…).

Note: OpenAL remains our default sound backend, as an open-source audio library, for our open-source game engine. The FMOD backend is just an option — when you are OK with using proprietary and commercial (though free in some cases, for indie devs) solution, in exchange for features like FMOD Studio and Nintendo Switch compatibility.

Our FMOD support improvements are:

  • We now pass to FMOD correct values of sound 3D position, velocity, listener 3D position and orientation, request right-handed coordinate system, and we set sounds to be spatial when appropriate.

  • The SoundEngine.DistanceModel is supported by FMOD (so you can change the distance model to “linear” if desired; default is equivalent to FMOD default, “inverse”).

  • The TCastlePlayingSound.Offset (reading and setting) works with FMOD.

  • Sound priority is now passed to FMOD in a more straightforward way, to allow FMOD to manage sound sources.

    CGE Priority (float in 0..1 range, higher is more important) is converted into FMOD priority (int in 0..256 range, lower is more important). Yeah, the word priority is inconsistent, and we cannot really win here — Unity, FMOD, Wwise, X3D… all have inconsistent ideas what does priority mean.

    If you’re curious about the decisions behind our TCastleSound.Priority definition, see this commit’s log. Sometimes it is just impossible to be consistent with everything… And inventing our own name for the same concept also felt wrong. We used the term Importance for quite some time, and it was documented as “This is a priority…” 🙂

  • Internal example moved to examples/audio/internal/fmod_api_test/ . This is a useful example for people that want to work directly with FMOD or extend our FMOD backend in CGE. It should not be followed by normal CGE users.

There’s no new CGE API to present here. Just use the existing classes like TCastleSoundSource and TCastleSound (see previous news post, about sound API upgrades). They will work with FMOD backend as you expect, producing 3D sound.

Comments on the forum ➤