A quick historical note
Mandala predates the release of Valve's Portal, and I can't remember how it compares in time to its predecessor, Narbacular Drop. It also predates the game that actually got released as Prey, but obviously not the 3D Realms original that hugely inspired playing with this tech.
Having gone through the developer commentary of Portal, I'm impressed that Valve did much of the hard work "properly". The stencil-based recursive rendering approach they describe sounds pretty much exactly like Mandala's approach, plus they had the resources to handle the depth-stop case in a reasonable manner (copying the last part rendered1). Their portal transforms seem OK, although since they are working in an FPS engine gimbal lock is an issue, as you can sometimes find when trying to rotate to fire a mid-air portal while the game is re-orientating your actor's "down" vector.
Finally, while they are still working in a static BSP engine and thus have two-identical-rooms-off-one-corridor-type constructs, they do add special-case duplication of objects in their physics engine as needed around portals where two 'copies' of the same object may interact. (In fact, the area immediately around portals is treated as a distinct physical region and dealt with in a more approximate manner for performance. As a hack, it works.)
Portal doesn't run in a true portal engine, but it's closer to Doing It Right than expected.
1 For comparison, UnrealEngine's WarpZones circa UT99 fall back to a prespecified texture; UnrealEngine 2 and Mandala just fail over to a HOM unrendered area (IIRC); Mandala was ideally going to do some precalculation to prepare an appropriate deeply-rendered texture, in the hope that dynamic objects at depth would not be missed. Valve's solution, frankly, sounds like the best compromise.
"True" Portal Engines
To try and distinguish graphics engines such as Mandala's renderer, and the original Prey, from BSP- or CSG-based games that have portals as a special effect (e.g. Portal), I have dubbed them "true" portal engines.
A fairly solid introduction to what portals are all about, and why they're cool, can be found in a UseNet thread, in which William Scarboro, one of the original Prey developers, says "don't do this". Basically, the environment is carved up into mostly-convex areas dubbed "sectors" (think individual rooms and hallways in a building). These are then connected to eachother by "portals" (think doorways). If a portal leading out of the current sector isn't currently visible, then the renderer knows that it doesn't have to render the sector on the other side. This provides fairly efficient runtime visibility culling (the process of avoiding wasting time preparing to draw things which are hidden anyway), and is what portal engines were originally about.
Then someone figured out that you don't necessarily have to put all the sectors in one contiguous block. The kitchen and the dining room can be several miles apart, but if their doorways still link to eachother then they'll appear to be adjacent from inside. Standing in the doorway between them, half of you would be several miles away from the other half, but you wouldn't notice.
What you might notice were if the door to the understair cupboard lead to a massive concert hall, yet you could still walk around to the other side of the stairs and find them quite ordinary. Because this is an entirely runtime technique, by the time you go back, the cupboard may now look through to a bus station in Milton Keynes, a spinning dimensional rift inside your own head, or even a small storage area with a mop in it which just happens to be somewhere in Swaythling. This is where true portal engines get really cool: they can bend space into pretty much any shape you can imagine, but they can be as subtle about it as you like.
This is what Prey and Portal don't do—what they have is an approximation of a portal, bolted on top of a regular, BSP-based engine. (Yes, that's also the case for the Unreal engine's little-used WarpZones.) It's true that it gives them a great deal of the magic of portals, but they have their limits: they can't, as far as I can determine, support the same flexibility, because they're still based on heavy amounts of precomputation. I strongly suspect that they still have a global co-ordinate system (a true portal engine can only really express things in terms of sector-relative co-ordinates, becuase a sector may appear more than once if lots of portals lead to it—imagine a wall of 'televisions' which all share a screen, and reaching into one makes your hand also appear in all the others), and effectively have one Really Huge sector with lots of isolated areas in, connected by portals: they instead rely on existing BSP visibility culling. This kind of approach leads to a lot of rough edges, such as the inability to properly handle the potentially multiple unique locations of a single item, or correct traversal of all objects and partial-penetration collision cases through portals. In particular, lighting and splash damage do not work through these portals.
Unreal can handle the rendering, but doesn't rotate objects passing through portals at all, which means that they may appear to rotate for no reason. Such are the perils of trying to fit portals into a global-co-ordinate-system engine.
Mandala has a ton of rough edges too, I easily concede. It was developed in a few months by two-to-three students. (In a nutshell: we aimed for getting portals mathematically right. They aimed to make and ship games with cool quirks.)
Mandala is an open-source game engine written in C which supports these "true" portals. In the spirit of portal engines, there is a heavy emphasis on dynamism: Mandala prefers to use just-in-time computation and caching in favour of precalculation, allowing for enviroments which change radically without suffering large performance penalties.
It is modular to an almost pathological degree. Everything in a "world", a particular game environment, is an entity. Entities have behaviours, such as "do something for this timeslice", "work out if you're colliding with this", or "draw yourself". The upshot is that it's entirely possible to use any kind of graphical and spatial representation of an object you like—the renderer only knows about polygons becuase they're a convenient way to define the outline of a portal: everything else is up to behaviours. Of course, there are a common set of built-in behaviors for common roles such as mesh rendering and collision.
Mandala also includes an entire input binding and abstraction system which lets you write in terms of "move forward" and "alternate fire", not "W" and "right mouse button"—and it's been designed so that even joysticks, keyboards, and extra mouse buttons can all be used interchangably while still making sense. Tedium such as loading, managing memory for, and caching of models and textures is taken care of, and the system is very careful to ensure that resources get deallocated again. Rotations are handled in terms of quaternions, avoiding the horrors of gimbal lock (essential for space games such as Z Fighter Forever), and there are 'nice' methods to generate and use them for people who'd rather not think about quaternions.
Mandala's design and implementation, as well as some additional matter on portals, is covered in the project report for Z Fighter Forever below.
If you want the really technical stuff, all of the public (and private) Mandala headers are documented in doxygen syntax.
I've tried to be more helpful than the average "getFoo(): returns foo" level of most header comments.
Start with the master header, move to
mandala_engine.h, and you should find enough context to work out where you want to go from there.
Of historic interest may be the Advanced Computer Graphics project report, which describes Mandala in its pre-ZFF state. Note that this conflicts quite violently with Mandala's current state in parts.
Large thanks go to Jim Gerrard, for taking an interest in, and working out a lot of, the hairy problems with transforming between the multitudes of co-ordinate systems involved in such an engine. Further thanks for his and John-Mark Bell's work on Mandala for Z Fighter Forever.
A ritualistic, geometric design used in Hinduism, Buddhism and Discordianism (the design of which on page 43 of the Principia Discordia inspired the use of such a name for this engine, and is used for the logo) as an aid to meditation, symbolic of the universe. Fnord.
I thought that it was fitting. And shorter than "that portal engine thing that Phil's writing: you know, with the non-Euclidean geometry, and maths that drive him insane".
About Z Fighter Forever
For the group Interactive Entertainment Systems assignment, Jim and I worked with Karl Doody and John-Mark Bell on beating Mandala into shape and producing a game using it (much to our later amusement—3D Realms fans may be able to guess how much amusement by the title1). The result is Z Fighter Forever: a multiplayer little-ships-in-passages-and-caverns shooter, with realistic space physics. (You have inertia, but neither atmospheric resistance nor gravity, and hitting things will just make you bounce off of them. Getting moving is easy. Controlling where you move, or stopping, is not.)
1 Hey, that other Forever game finally got released years later. Although it probably shouldn't have been.
ZFF isn't particularly complete, but it's quasi-playable (Jim's demonstrated his relative mastery of the physics by utterly annihilating me several times), and it serves as a demonstration of game development with Mandala.
The single included level,
]|[space, has corridors in the shape of a 270-degree triangle, with three overlapping central rooms.
The spawnpoints in these rooms themselves overlap the outer corridor.
What it doesn't show is Mandala's ability to handle all this portal malarky when it's dynamically changing which polygons are portals, where they point, and where they are, during the game.
This is a limitation of ZFF's level format (blame me—I had to develop it to a deadline
The networking also had to be quite, quite rushed, unfortunately, so you may encounter some pretty horriffic lag-like effects at times.
The resimulation will occasionally cause the server to throw you about a bit: unfortunately, without this, the clients would go out of synchronisation and you wouldn't be able to shoot each other.
For more information than you ever wanted to know about Z Fighter Forever, see the (5 MB) project report, which includes plentiful design and implementation documentation. And more screenshots.
Mandala is pure C99, with some filthy hacks to also make it compile under Microsoft Visual C++. KUI and ZFF require a C++ compiler, such as g++ or MSVC. All three have been tested under Windows and Linux, and should work on any POSIX-y or Windows-y platform, possibly with some tweaking of the MSVC project/makefiles. You'll probably make your life easier if you extract all three in adjacent directories, as the "buildall" script in ZFF expects.
You will need these libraries:
- Karl's UI library
- Z Fighter Forever
- (and Mandala and KUI)
Mandala, Karl's UI library (KUI), and Z Fighter Forever are licensed under the Common Public License 1.0.
There aren't publically accessible version repositories for these. (Honestly, I'm not going to work on this, and I'd suggest you find a better engine to contribute to.)