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.