Development news: engine 2.0

January 26, 2010
Screenshot from scene_manager_demos — two VRML scenes and one precalculated animation at once
Another screenshot from scene_manager_demos

During the last weeks I did a lot of work on the engine API. Especially the new Scene Manager approach makes quite a revolutionary change, and there's also 2D Controls manager, better Lazarus components and many more. Together, I feel these are so important for developers using my engine that the next engine version will be bumped to proud 2.0.0 :) To be released next month.

Not much noticeable for a normal user (sorry; although there are various fixes and improvements here and there). Below news post turned out quite long, and I'll keep passing you links to the current API reference of SVN code, so... developers: keep reading if you're interested, and others: well, this may get dirty, so you can stop reading now :)

  1. The number one reason behind all these changes is that it was too difficult to add new stuff to your window. This concerned 3D stuff, mainly the two most important classes of our engine: TVRMLGLScene and TVRMLGLAnimation. And it also concerned 2D controls, for example our menu with fancy GUI sliders: TGLMenu (this was used in castle and recent examples/vrml/terrain demo).

    The goal: the goal (already achieved :) ) is to allow you to make a full 3D model viewer / VRML browser (with collisions, fully optimized rendering etc.) by this simple code:

    var
      Window: TGLUIWindow;
      SceneManager: TKamSceneManager;
      Scene: TVRMLGLScene;
    begin
      Scene := TVRMLGLScene.Create(Application { Owner that will free the Scene });
      Scene.Load('my_scene.x3d');
      Scene.Spatial := [ssRendering, ssDynamicCollisions];
      Scene.ProcessEvents := true;
    
      SceneManager := TKamSceneManager.Create(Application);
      SceneManager.Items.Add(Scene);
      SceneManager.MainScene := Scene;
    
      Window := TGLUIWindow.Create(Application);
      Window.Controls.Add(SceneManager);
      Window.InitAndRun;
    end.
    

    (The source code of this is in scene_manager_basic demo inside engine examples. There's also more extensive demo in the scene_manager_demos sample.)

    This looks nice a relatively straighforward, right? You create 3D object (Scene), you create 3D world (SceneManager), and a window to display the 3D world (Window). What is really the point here is that you immediately know how to add a second 3D object: just create Scene2, and add it to SceneManager.Items.

    The idea of scene manager will soon be explained in more detail, for now let's go a litle back in time and see what was wrong without the scene manager:

    The trouble: our existing classes were nicely encapsulating some functionality (showing menu, rendering VRML etc.) but they were a pain to add to your window / 3D world.

    You could use something like TGLWindowVRMLBrowser (or equivalent Lazarus component, TKamVRMLBrowser) but these offered too little flexibility. They were made to allow easily loading only one scene.

    For anything more complicated, you had to directly create your TVRMLGLScene etc. classes, and (this is the key point) to handle various window / camera / callbacks to connect the 3D scene with a camera and with a window. For example, you had to register window OnIdle callback to increment VRML scene time (to keep animations running etc.) You had to register OnKeyDown, OnKeyUp and pass key events to VRML scene (to make VRML sensors work), OnMouseXxx callbacks had to be passed to handle VRML touch sensors, OnDraw to handle scene rendering. You also had to register camera callbacks (OnMoveAllowed, OnGetCameraHeight) to connect collision detection with your 3D scene. And the list goes on...

    As a witness to all these troubles, have a look at implementation of GLWindowVRMLBrowser or (nearly identical) implementation of KambiVRMLBrowser is last released engine version. They are long and clumsy. In current SVN code, they are nice, short and clean, and also more flexible (can handle many 3D objects, not just 1 VRML scene).

    The solution(s): There are actually two solutions, one directed at 3D objects (living in the 3D world), the other at 2D controls (merely taking some space on the 2D window) . They are quite similar, and nicely playing with each other:

    1. For 3D objects: we have a base class T3D from which all other 3D objects are derived. For example, TVRMLGLScene and TVRMLGLAnimation are both descendants of T3D now. There are some other helper 3D objects (T3DList - list of other 3D objects, and T3DTranslated - translated other 3D object). And the real beauty is that you can easily derive your own T3D descendants, just override a couple methods and you get 3D objects that can be visible, can collide etc. in 3D world.

      Now, what to do with your 3D objects? Add them to your 3D world, of course. The new great class that is fully implemented now is the TKamSceneManager. In every program you create an instance of this class (or your own dencendant of TKamSceneManager), and you add your 3D objects to the scene manager. Scene manager keeps the whole knowledge about your 3D world, as a tree of T3D objects. After adding your whole 3D world to the scene manager, you can add the scene manager to Controls (more on this next), and then scene manager will receive all necessary events from your window, and will pass them to all interested 3D objects. Also scene manager connects your camera, and defines your viewport where 3D world is rendered through this camera.

    2. For 2D controls: quite similar solution is used, although with some details different. All stuff that had to receive window events must derive from base TUIControl class. This means that TGLMenu is now a descendant of TUIControl, and in the future I would like to have a small library of generally-usable simple 2D controls available here. Also note that TKamSceneManager is TUIControl descendant, since scene manager by default acts as a viewport (2D rectangle) through which you can see your 3D world. (Possibility to easily add custom viewports from the same scene manager is the next thing on my to-do list.)

      To actually use the TUIControl, you add it to the window's Controls list. If you use Lazarus component, then you're interested in TKamOpenGLControl.Controls list. If you use our own window library, you're intersted in the TGLUIWindow.Controls. Once control is added to the controls list, it will automatically receive all interesting events from our window.

    That's it, actually. Thank you for reading this far, and I hope you'll like the changes — you can try SVN source code already and let me know how it works for you in practice.

  2. Other changes:

    • The Lazarus integration of the engine is better, with many old classes reworked as components. This is also tied to the previous change, because both T3D and TUIControl are descendants of TComponent — which means that important classes of our engine, like TVRMLGLScene, and also the cameras are now components that can be registered on Lazarus palette.

      This is not yet finished: some important properties of these classes are not published, or not possible to design from the IDE. For example, you cannot add items to the TKamOpenGLControl.Controls list yet from the IDE. This doesn't limit your possibilities, it only means that you'll have to do some work by writing source code as opposed to just clicking in Lazarus. Things for sure are already a lot better than in previous engine release.

      Mouse look is now also available in Lazarus TKamOpenGLControl component.

    • T3D/TUIControl give various improvements to all 2D/3D objects. For examples, TVRMLGLScene automatically sets cursor to "hand" when it's over a touch sensor. In fact, every T3D and TUIControl can affect cursor by Cursor property.

    • If you do not explicitly create a camera for the scene manager, a suitable one is automatically created, see TKamSceneManager.Camera.

    • All "navigator" classes, fields etc. are renamed to "camera". So e.g. TExamineCamera is just a new name for our good old TExamineNavigator and such.

      Old names navigator were coined to emphasize the fact that they do not have to represent "real" camera that is used to display the 3D scene on the screen, they can be used to manipulate any 3D object of your scene. For example shadow_fields demo uses 4 examine navigators to manipulate various scene elements, rift uses special walk navigator to represent position of the player in the room, etc. But I decided that the name is just confusing, as most of the time you use this as a "normal camera". Advanced users can probably grasp the fact that in fact "camera" doesn't have to be used to display whole scene from the screen.

    • GTK 2 backend of our TGLWindow class was much reworked. Namely, 1. we no longer use GTK's gtk_idle_add to implement our OnIdle callbacks and 2. GTK's "expose" signal no longer calls directly OnDraw callback . These caused an endless stream of troubles with stability, related to GTK idle events priorities. Our new solution is much simpler, solving some recent problems and removing ugly workarounds for the old ones.

      For more in-depth discussion of past problems, reasonings and solutions, see the document why_not_gtk_idle.txt.

    • A minor improvements to the TGLWindow are the MessageOK and the MessageYesNo methods, proving native-looking (GTK, WinAPI etc.) message boxes.

    • Oh, and f you're trying to compile the engine with newest FPC 2.4.0, please use engine SVN source for now. Current released tar.gz sources compile only with <= 2.2.4. This problem will of course disappear after new engine is released.