Previous Next Table of Contents

5. File structure

To describe the file structure, which is very complicated, I use C like program fragments and struct definitions. This simplifies my task a lot.

I invented all used names (messages, variables etc.) for myself, took them from the Quake binary, QuakeEd or from the QuakeC examples.

All DEM files start with an ASCII string of the cd track which was given to the record command. The string is terminated by a new line character (0x0A). If you didn't give a cd track number the string is ``-1''. This means almost all DEM files start with ``-1\n''. It seems that this header was included at the very end of the developement. It doesn't fit to the rest at all.

All the rest of the DEM file consists of ``blocks'' of ``messages''.

5.1 Block of Messages

At first some coordinate typedef's:

typedef float vec_t;

typedef vec_t[3] vec3_t;

This is the block structure:

typedef struct {
                 long            blocksize;
                 vec3_t          angles;
                 char[blocksize] messages;
               } block_t;
A block of messages starts with a size. Then follow 3 angles which describe the camera viewing direction. All the rest of a block are bytes which form one or more messages.

I believe that one block is one network packet from the server to the client.

5.2 Message

This is the message structure:

typedef struct {
                 unsigned char ID;
                 char[???]     messagecontent;
               } message_t;
The length of a message depends on its type (or ID).

5.3 Auxilliary routines

Here comes the definition of some small auxilliary routines to simplify the main message description. get_next_unsigned_char, get_next_signed_char, get_next_short and get_next_long are basic functions and they do exactly what they are called. Please note: byte, char or short will be converted to long. Second note: all multi-byte structures in the DEM file are Intel ordered.

In the following I often use a count variable

int i;
without declaration. I hope this does not confuse you.

long ReadByte
  return (long) get_next_unsigned_char;

long ReadChar
  return (long) get_next_signed_char;

long ReadShort
  return (long) get_next_short;

long ReadLong
  return get_next_long;

Note: A signed angle in a single byte. There are only 256 possible direction to look into.

vec_t ReadAngle
  return (vec_t) ReadChar / 256.0 * 360.0;

vec_t ReadCoord
  return (vec_t) ReadShort * 0.125;

The string reading stops at '\0' or after 0x7FF bytes. The internal buffer has only 0x800 bytes available.

char* ReadString
  char* string_pointer;
  char string_buffer[0x800];

  for (i=0 ; i<0x7FF ; i++, string_pointer++) {
    if (! (*string_pointer = ReadChar) ) break;
  *string_pointer = '\0';
  return strdup(string_buffer);

long ReadEntity
  return ReadShort;

Previous Next Table of Contents