Re: Quake data structures

Brian K. Martin (brian@phyast.pitt.edu)
Wed, 6 Mar 1996 02:09:55 -0500 (EST)

From: "Brian K. Martin" <brian@phyast.pitt.edu>
Message-Id: <199603060709.CAA16507@minerva.phyast.pitt.edu>
Subject: Re: Quake data structures
To: quake-editing@nvg.unit.no
Date: Wed, 6 Mar 1996 02:09:55 -0500 (EST)
In-Reply-To: <199603051239.EAA22948@netcom17.netcom.com> from "Morgan Schweers" at Mar 5, 96 04:39:58 am

I forgot if I sent these to you.
Some things are wrong. The 4'th byte in the vframe.v is the
index to the precalculated vertex normals. So you can convert
from mdl to whatever, but not back yet because I didn't figure
out the normal data structure. Later.

MDL file format
(this is what I know so far)

These are the structs I use to read in file info:

struct vframe{
unsigned char head[12];
unsigned char *v;
};

struct MDL_FILE{
char filetype[4];
int version;
float xscale,yscale,zscale;
float xoffset,yoffset,zoffset;
float radius;
float f1,f2,f3;
unsigned num_items;
unsigned bitmapw;
unsigned bitmaph;
unsigned num_vertices;
unsigned num_triangles;
unsigned num_frames;
unsigned blank;
unsigned char *bitmap;
unsigned int *vertex;
unsigned int *triangle;
struct vframe *frame;
};

void read_mdl(FILE *in)
{
int i,j,k;

fread(&mdl.filetype,4,1,in);
fread(&mdl.version,4,1,in);
fread(&mdl.xscale,4,1,in);
fread(&mdl.yscale,4,1,in);
fread(&mdl.zscale,4,1,in);
fread(&mdl.xoffset,4,1,in);
fread(&mdl.yoffset,4,1,in);
fread(&mdl.zoffset,4,1,in);
fread(&mdl.radius,4,1,in);
fread(&mdl.f1,4,1,in);
fread(&mdl.f2,4,1,in);
fread(&mdl.f3,4,1,in);
fread(&mdl.num_items,4,1,in);
fread(&mdl.bitmapw,4,1,in);
fread(&mdl.bitmaph,4,1,in);
fread(&mdl.num_vertices,4,1,in);
fread(&mdl.num_triangles,4,1,in);
fread(&mdl.num_frames,1,4,in);
fread(&mdl.blank,1,4,in);

mdl.bitmap = new (unsigned char)[mdl.bitmapw*mdl.bitmaph*mdl.num_items];

for(k=0;k<mdl.num_items;k++)
{
fseek(in,4,SEEK_CUR); // skip a blank word here

for(j=0;j<mdl.bitmaph;j++)
{
for(i=0;i<mdl.bitmapw;i++)
{
fread(mdl.bitmap+(i+mdl.bitmapw*(j+k*mdl.bitmaph)),1,1,in);
}
}
}

mdl.vertex = new (unsigned)[mdl.num_vertices*3];

for(i=0;i<mdl.num_vertices;i++)
{
// if the following is 1, you use the point for the front and back
fread(mdl.vertex+i*3,4,1,in);
// x pixel
fread(mdl.vertex+i*3+1,4,1,in);
// y pixel
fread(mdl.vertex+i*3+2,4,1,in);
}

mdl.triangle = new (unsigned)[mdl.num_triangles*4];

for(i=0;i<mdl.num_triangles;i++)
{
// clockwise/counter-clockwise flag (will need for culling and stuff)
fread(mdl.triangle+i*4,4,1,in);
// point #1
fread(mdl.triangle+i*4+1,4,1,in);
// point #2
fread(mdl.triangle+i*4+2,4,1,in);
// point #3
fread(mdl.triangle+i*4+3,4,1,in);

}

mdl.frame = new (struct vframe)[mdl.num_frames];

for(j=0; j<mdl.num_frames; j++)
{
//I don't know this header format yet
fread(mdl.frame[j].head,1,12,in);
mdl.frame[j].v = new (unsigned char)[mdl.num_vertices*4];

for(i=0;i<mdl.num_vertices;i++)
{
// x position
fread(mdl.frame[j].v+i*4 ,1,1,in);
// y position
fread(mdl.frame[j].v+i*4+1,1,1,in);
// z position
fread(mdl.frame[j].v+i*4+2,1,1,in);
// unknown, maybe a color value, prolly not a light value
fread(mdl.frame[j].v+i*4+3,1,1,in);
}
}

}

This is how I calculate the 3d points, it seems to work ok..

for frame=i
for vertex=j

x=mdl.xscale*(mdl.frame[i].v[j*4]+mdl.f1)+mdl.xoffset;
y=mdl.xscale*(mdl.frame[i].v[j*4+1]+mdl.f2)+mdl.yoffset;
z=mdl.xscale*(mdl.frame[i].v[j*4+2]+mdl.f3)+mdl.zoffset;

I'm sure if your a 3d programmer this is enough info to start.
Of course this stuff may be wrong, but it works. Also note
that some of this stuff differs from quake specs 3.0 (beta).

Later. brian martin