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''.
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.
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
).
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];
string_pointer=string_buffer;
for (i=0 ; i<0x7FF ; i++, string_pointer++) {
if (! (*string_pointer = ReadChar) ) break;
}
*string_pointer = '\0';
return strdup(string_buffer);
}
long ReadEntity
{
return ReadShort;
}