Sunday, 6 May 2018

i got first post! woo!

Hello!

My current videogame engine project, Drift, currently sports the following features:

  • Parsing of id Software's Quake 1 .map format into dictionaries of key-value pairs, and models consisting of convex solids. However, I am not using the original entity class set.
  • Decomposition of this graph into convex regions by way of BSP.
  • Manual placement of portals carried out by a deigner prior to map parsing. I believe the method I use is simpler than that of the id Tech 5 editor, since all that is required here is a single point and an axis alignment. The engine works out what shape the portal should be.
  • Grouping of BSP leaves into concave cells, with the ruling that a cell cannot include any space that crosses a portal. This enables high-level culling of the scene, performed at runtime.
  • Limited collision detection and resolution.
  • Designer-influenced BSP and collision complexity. A particular solid in the graph may be considered too small or subtle to have any effect on gameplay, so it can be labelled as detail.
  • Object-oriented, serialised archiving system. As of this time, fully compatible with all previous versions of archived data structures. Some standard compression is performed at the common level (e.g. A string re-ocurrence table), and certain classes carry out particular actions to compress their on-disk representations.
  • An object-oriented, hierarchical scripting system and virtual machine, which is yet to be fully integrated into the rest of the engine. It is rather similar to UnrealScript (used in Epic's Unreal series of games) and JavaScript, but has a slightly different approach. Plus a rather embarrassing number of possible operations (over 300, and I had to write a separate function for each!).
  • Realtime coloured, attenuated lighting. Scissor tests and BSP leaf AABB tests are used to optimise this. Nothing spectacular yet, but I have been working on separate programs that show normal mapping, shadow mapping, and extruded-volume shadowing. The latter of which I am thinking of not using at all.
  • Destructable scenery. The engine has a powerful set of CSG tools which are used in this case to naively simulate the fracture of any solids labelled as destructable by a designer. Most obviously, this can be triggered by an explosion. Note that this kind of event will be orchestrated by the scripting system.

I've probably forgotten some finer points.

I will be detailing the progress of Drift's development

A comparison between Orb-C, UnrealScript and QuakeC

Orb is the scripting module for Drift. It is hierarchical, object-oriented, and modular. The way it is integrated into the engine is more like Quake than Unreal, since the Unreal engine's scripts are very deeply linked with the native code.

The easiest way to compare these three scripting language are to present 3 functions written in each language, that do the exact same thing. But please remember that I am not fully competant with UnrealScript.

Here's the function in Orb-C:


function PlasmaGun::Fire()
{
 print("...\n");

 if(time > Owner.ReloadFinishTime)
 {
  print("FIRE!!!\n");

  PlasmaBolt P;
  P = new PlasmaBolt;
  
  P.Location = Owner.Location;
  P.Velocity = Owner.Direction * {5,5,5};
  
  Owner.ReloadFinishTime = time + 1;
 }
 
}

It should be obvious. An object of class PlasmaBolt is created, set to the weapon's owner's location, and pushed in a direction. A timer is set to control the rate of fire.

Here's the same thing again, but in QuakeC (in the style of the original Quake 1 prog sources):


void() plasmagun_fire = 
{
 local entity p;

 print ("...\n");
 
 if(time > owner.reloadfinished)
 {
  print ("FIRE!!!\n");
  
  p = spawn();
  
  missile.movetype = MOVETYPE_FLYMISSILE;
  missile.solid = SOLID_BBOX;
  
  p.classname="plasmabolt";
  
  p.velocity = owner.dir * 5;
  
  p.owner = self;

  p.touch = T_MissileTouch;

  setmodel (p, "progs/plasmabolt.mdl");
  setsize (p, '0 0 0', '0 0 0');  
  setorigin (p,owner.origin);
   
   
  owner.reloadfinished=time+1;
 }
 
}


Due to a lack of class definitions in QC, the function must be named specifically for the 'class'. Also, a lot of extra code is needed since there is no equivalent of the per-class main() function Orb-C has.

At this time, Orb-C vectors can only be multiplied by another vector. QC allows a single value to be the multiple. This is not hard to fix, I just haven't got round to it.

Now lets take a look at some UnrealScript.


function Fire()
{
 Log("...");
 
 if(Time > Owner.ReloadFinishTime)
 {
  Log("FIRE!!!");

  local PlasmaBolt P = Spawn(class'PlasmaBolt',,, Owner.Location);
  
  P.Velocity = Owner.Direction * 5;
  
  Owner.ReloadFinishTime = Time + 1;
 }
}


I'm not sure this is completely correct, but from looking at the UC sources exported from UnrealEd for Unreal Engine 1, this is basically what's needed.

You can probably see there's slightly less code, and it's not much different from Orb-C. You can't see it from this example, but UnrealScript has a lot more features than my scripting engine and language.

You may also notice that the function is simply called Fire(). This is because Unreal separates each class definition into it's own UC source file. There's no need to use a namespace since there won't be any definitions related to other classes in the entire text file.

So those people experienced in UnrealScript would pick up Orb-C very easily, but find less power at their disposal. I'll be brave and say that development with Orb-C is faster, but since it's development has some way to go, it's hard to put it in a real place right now.

I will post more information about the workings and usage of Orb in the near future.

Just a short post.

Bounding-box culling is now being performed between BSP leaves and the view frustum. The modelview and projection matrices are used to calculate 6 planes. If a box is entirely outside of this convex space (a VERY easy test to do, just dot products), then it there's no point attempting to draw it. I want to extend this so a new set of planes are formed for portals. If this works out fast enough, then I can replace the existing hardware occlusion queries (they seem to have high bandwidth usage because they stall the pipeline in some way).

Also, I managed to get multiple Orb modules co-operating. This was difficult because it's easier for a pointer from one module to point to something belonging to a different module. When the pointer is serialized, a domino effect would occur which would result in the entire other module being archived in the same file. NOT desirable.

I'm having problems with the map loading code, which is delaying the implementation of normal mapped surfaces. The structures are there, but I can't use them yet. Frustrating.

Thursday, 13 September 2007

Just a short post.

Bounding-box culling is now being performed between BSP leaves and the view frustum. The modelview and projection matrices are used to calculate 6 planes. If a box is entirely outside of this convex space (a VERY easy test to do, just dot products), then there's no point attempting to draw it. I want to extend this so a new set of planes are formed for portals. If this works out fast enough, then I can replace the existing hardware occlusion queries (they seem to have high bandwidth usage because they stall the pipeline in some way).

Also, I managed to get multiple Orb modules co-operating. This was difficult because it's easy for a pointer from one module to point to something belonging to a different module. When the pointer is serialized, a domino effect would occur which would result in the entire other module being archived in the same file. NOT desirable.

I'm having problems with the map loading code, which is delaying the implementation of normal mapped surfaces. The structures are there, but I can't use them yet. Frustrating.

Friday, 7 September 2007

Why does id Tech 4 employ so much markup?

Something about Drift I didn't mention in my last post:

  • Terrain generation. A cuboid region can be created, and control points used to make outcrops of varying height and radius. Very easy to do, since the control point is added as a point entity with one extra field, 'radius'. I really want this to have dynamic level-of-detail in the form of quadtrees, and I have done some research into that, but it may be a while before I get round to implementing it.

I have just been rooting around the packages that come with Quake 4 and it seems that much of the resources in that game are plain-text. The level geometry is entirely in markup, which is largely human-readable and specifies everything from AI accessibility and entity dictionaries to brush planes and general decomposition (this appears to still be BSP but it's not clear). I say 'largely' human-readable, since sometimes all you are looking at is numbers. In the md5mesh format, there are tables of indices which are completely useless to a person, so exactly why has this move been made?

My first thought is machine independence. At load time, you simply parse the text into whatever is easiest for the machine to deal with, and these days that's not much of a speed hit. In the past, id has byteswapped structures when needed, and that's not a brilliant solution since it means machines engineered for architectures that require this byteswapping, will suffer a small performance hit. The solution I've gone for is to swap at the lowest level of the stream. This doesn't overcome the extra time needed, but it's as transparent as it's going to be. It's very nice to only care about these things once, and then be confident that all the upper layers will benefit.

I've been working on a way to serialise objects across the native filesystem, and I currently have a package file format, and cross-package references within the format. Each package provides a table of exports and imports, but the major problem is verifying that the data in the other package does indeed represent the original object that was pointed to. All I have right now is a unique number, which may become an MD5 hash or similar. Furthermore, is it really desirable to only allow the original object? The ability to 'supersede' the object with a modification would be interesting, but potentially unsafe. Adding an extra verification function to each class is a daunting task, but that might be the best option.

This weekend I plan to write a Quake 4 .map parser. I can already see how to parse the brushes. They are just a list of planes. Maybe that's why there's so much markup. To allow people like me to do things like that!

Why does id Tech 4 employ so much markup?

Some things I didn't mention in my last post: