ORF

From ODF::Wiki

Jump to: navigation, search

OutrageRoomFile

Rooms are small units of a level in Descent 3.

Here is a short but hopefully useful document on how the Outrage Room Format (ORF) works. This document is meant to help gamers who want to write their own exporters and use their favorite 3d modelling program and D3edit together.


An ORF file describes one room. A room is a collection of faces defined by any number of 3d vectors. To help conserve memory, faces can share vectors.

The ORF file is broken up into chunks which describe a certain aspect of the room like header, vectors, and textures. A chunk is a CHUNK_ID (int, 4 bytes), a size (int, 4bytes), and the corresponding data.

Here, in C, is a code that saves a room. For our purposes, the room structure would be your 3d modelers data coverted in a way that could be used by the following routine.


#define ROOM_VERTEX_CHUNK	1
#define ROOM_FACES_CHUNK	2
#define ROOM_END_CHUNK		3
#define ROOM_TEXTURE_CHUNK	4
#define ROOM_HEADER_CHUNK	5
 
#define ROOMFILE_VERSION	4	
#define LIGHT_MULTIPLE_DEFAULT	4
#define TEXTURE_DEFAULT			0
 
// saves a room in our ORF (Outrage room file) format
void SaveRoom (char *filename)
{
	CFILE *outfile;
	int headsize,savepos,vertsize,facesize,texsize;
	int highest_index=0;
	short Room_to_texture[MAX_TEXTURES];
	int t,found_it=0;
 
 
	// Open the file for writing
	outfile=(CFILE *)cfopen (filename,"wb");
	if (!outfile)
	{
		return; // Couldn't open file for writing!
	}
 
	// write out header info
	cf_WriteInt (outfile,ROOM_NEW_HEADER_CHUNK);
	headsize=cftell(outfile);  // Save this file position so we know where to write the size of the chunk
	cf_WriteInt (outfile,-1);
 
	cf_WriteInt (outfile,ROOMFILE_VERSION);
	cf_WriteInt (outfile,Room.num_verts);
	cf_WriteInt (outfile,Room.num_faces);
 
	// Now go back and fill in the size of the chunk
	savepos=cftell (outfile);
	cfseek (outfile,headsize,SEEK_SET);
	cf_WriteInt (outfile,(savepos-headsize)-4);
	cfseek (outfile,savepos,SEEK_SET);
 
	// write out vertex info
	cf_WriteInt (outfile,ROOM_VERTEX_CHUNK);
	vertsize=cftell(outfile);
	cf_WriteInt (outfile,-1);
 
	for (int i=0;i<Room.num_verts;i++)
	{
		cf_WriteFloat (outfile,Room.verts[i].x);
		cf_WriteFloat (outfile,Room.verts[i].y);
		cf_WriteFloat (outfile,Room.verts[i].z);
	}
 
	savepos=cftell (outfile);
	cfseek (outfile,vertsize,SEEK_SET);
	cf_WriteInt (outfile,(savepos-vertsize)-4);
	cfseek (outfile,savepos,SEEK_SET);
 
	// write out face info
	cf_WriteInt (outfile,ROOM_FACES_CHUNK);
	facesize=cftell(outfile);
	cf_WriteInt (outfile,-1);
 
	for (i=0;i<Room.num_faces;i++)
	{
		// For our purposes, the light multiple is always the same
		cf_WriteByte (outfile,LIGHT_MULTIPLE_DEFAULT);
 
		cf_WriteInt (outfile,Room.faces[i].num_verts);
 
		// Write out the normal for this face
		cf_WriteFloat (outfile,Room.faces[i].normal.x);
		cf_WriteFloat (outfile,Room.faces[i].normal.y);
		cf_WriteFloat (outfile,Room.faces[i].normal.z);
 
		cf_WriteShort (outfile,TEXTURE_DEFAULT); // Bash to texture 0
 
 
		// Write out vertex specific info		
		for (t=0;t<Room.faces[i].num_verts;t++)
		{
			// This field is an index into the global Room.verts field.  This allows faces to
			// share vectors without duplicating their x,y,and z info.
			cf_WriteShort (outfile,Room.faces[i].face_verts[t]);
 
			// Write out UV info
			cf_WriteFloat (outfile,Room.faces[i].face_uvls[t].u);
			cf_WriteFloat (outfile,Room.faces[i].face_uvls[t].v);
			cf_WriteFloat (outfile,0); // These are zero to maintain compat with older room readers
			cf_WriteFloat (outfile,0);
			cf_WriteFloat (outfile,0);
			cf_WriteFloat (outfile,0);
			cf_WriteFloat (outfile,1.0); // Alpha for vert
		}
 
	}
 
	savepos=cftell (outfile);
	cfseek (outfile,facesize,SEEK_SET);
	cf_WriteInt (outfile,(savepos-facesize)-4);
	cfseek (outfile,savepos,SEEK_SET);
 
	// Write the end chunk
	cf_WriteInt (outfile,ROOM_END_CHUNK);
	cf_WriteInt (outfile,4);
 
	// Close the file
	cfclose (outfile);
 
	// We're done!
	return;
 
}
Personal tools