Managing LIAV

From EQUIS Lab Wiki

Jump to: navigation, search

Contents

Our Goal

We want to have LIAV in using the Workspace .NET environment that Chris has cooked up. In order to do this, we need to make LIAV run in the CLR. Dave has determined that the best way to go about doing that is to reference unmanaged code from managed C++ classes. This will require us to bundle all graphical routines (Ogre) in managed code via adapter classes. The adapter class will make low-level calls to Ogre, and the game will make high-level calls to the adapter class.

We have some milestones to hit along the way:

  • Build the Ogre Adapter
  • Manage everything else, make it workspaced
  • Migrate slow pieces of managed code (like pathfinding) back to wrapped unmanaged code

Managed Project

The first step is to make a VC2005 project "managable", you have to first tell it to use Common Language Runtime support. Go to your project's Properties -> Configuration Properties -> General. On the right, there will be an option under Project Defaults called Common Language Runtime Support. Select the option Common Language Runtime Support (/clr), and we're all set.

How to make a C++ class Managed

There was originally old, less attractive syntax for making certain C++ class. It required you to tuck things like __gc before class definitions (that one means 'garbage collected'). When Banani and I tried this, VC2005 gave us some errors about using /clr:oldsyntax.

The new syntax is much more elegant. Classes which are to be managed now have either 'ref' or 'value' in their definition. The distinction is discussed here.

I experimentally added 'ref' to the front of the main application class, and it did not compile. It gave me an error about missing a semicolon before the class head. This was my fault, because I hadn't set /clr:oldsyntax back to normal /clr. It compiled right away after that.

New Managed C++ Toys

The hat or caret (^) is a new thing introduced to managed C++ code. It is used with respect to declaring handles, much the same way that pointers are used. When code becomes managed, a new heap comes into play. The managed heap. The managed heap manages all pointers with more features, such as garbage collection. Here is a page that talks about it a little bit. A snippet stolen from that page:

int m = 42;             // integer on the stack
int* n = new int(42);   // integer on a native heap
int^ o = gcnew int(42); // boxed integer on the GC heap
Object^ o = f();
o->ToString();

I haven't dug too deeply into this yet, but it seems like when I'm worried about collecting garbage, I can just swap * for ^. Of course, properly combing through all of the existing LIAV code to make it properly managed is not our highest priority. We just want it to work enough so that we can use the fiaa.net toolkit to let us test Workspace out.

The Ogre Adapter

We want to wrap all of the graphical routines with an adapter class which will allow us to (theoretically) painlessly swap out graphical engines, but more specifically let the graphics be a managed workspace component which makes unmanaged calls to native code for rendering.

There should be no Ogre-related code anywhere in the project except for in the adapter class.

This was a bit of a problem, because certain classes like Vector3, Vector2, ColourValue were defined in Ogre, but were little more than glorified structs which could apply to any rendering engine. Because of this, we've started replacing Vector2, Vector3, and ColourValue with new objects called CAXVector2, CAXVector3, CAXColourValue whose functionality mimics it's predecessor's.

Issues with Managed CAXColorValue

For some reason, our quick fix (typedef) for Vector2 & Vector3 did not work on ColourValue. The compiler complained that it was an unmanaged class and it was getting mixed up with managed code.

Solution pending! It would seem that this kind of issue will come up a few more times before we get the adapter all ready to go.

Readings:

Rob's Dev Diary

I've forgotten to pick up a lab workbook, so I'm just putting what I've done in here in the meantime.

Moving out of CAXApplication

I've moved most of the contents of CAXApplication into CAXOgreAdapter. There were some problems with the class that crossed across Ogre and LIAV. I thought I had that fixed with a nice little wrapping class, but it sometimes throws errors when they are constructed or removed. These are just picky little things (that are 100% needed to be done) but I've commented out the occurrences of these methods ("ColourValue" was the real problematic one) just to make sure that once things were encapsulated in Ogre, they would run fine.

Right now CAXAdapter has a function for "startup" "startrendering" and "cleanup", and all the CAXApplication code that initialized and got things started have been hidden into these. And this compiles and runs. CAXAdapter is a managed class. This is an excellent foothold to start moving other elements into the Adapter.

One class CAXFrameListener is now OgreFrameListener, and is full of Ogre-specific code. It's an unmanaged class that is used by OgreAdapter to do the rendering. We discussed how much better it would be if instead of a FrameListener, we put the main thread of execution into the game loop and make calls to the renderer (instead of waiting on the renderer). That requires a bit more Ogre-spelunking, and right now we just want to get this managed.