TR4 FILE FORMAT NOTES
Recopilation notes from some peoples
12-21-01
Last Updated January-02-2002
Hi, This is my own recopilation about Tr4 file format notes from some peoples, this is not a complete byte-per-byte walktroug because the TR4 file format is almost the like the TR3 files, so once you have your TR3 reader working then read the notes below to help you to known what you have to change/add to your Tr3 fileformat for be able to read/write TR4 levels.
The more important thing is that TR4 files are in compressed way, the method used is called ZLIB, and you can found on internet (search the word Zlib) a Zlib.dll and a Zlib.H file that will let you descompress zlib compressed data in your program.
For uncompress each chunk data, you will found in the file:
uncompressed_size : 4 bytes telling you how long the data is
when is uncompressed, so you have to alloc a memory buffer
with this size where to store the chunk once uncompressed.
Compressed_size : 4 bytes telling you how long the data is when is compressed.
Next come the compressed data, read compressed_size bytes data, and then use your zlib rutine to uncompress the chunk and store the data in your allocated buffer.
Turbo Pascal, 12-21-01.
Note #1, By Yuri Zhivago
I don't have it in a nice neat form like the TRosettaStone; in fact, it's been so long now, I'm not at all sure where my notes on it are.
If you have the TRueView source, you have everything I know - TR2IO.C is where all of the TR4 I/O occurs. Search for "TombRaider_4" in TR2IO.C to see the places where TR4 is different from the other versions.
Having written that, I just dug out my notes as of about five months ago; they're not current, but between these notes and the TR2IO.C source, you should be able to figure things out...
--- TR4 Notes (written to myself):
The .TR4 format is similar to TR3, except (note that this list of exceptions is not intended to be complete at this point):
* The level data is zlib compressed (obviously)
* There is no 8-bit palette, nor
are there any 8-bit textures,
and LightMap is not present.
* Lara now comprises two ObjectIDs and
two sets of meshes, one
for most of her body and
the other for her joints;
this appears to be how she
is "skinned." All other
meshes that I have observed
are "normal" (e.g. are
not "skinned" in this manner).
* struct tr2_room_light is now 46 bytes (no clues yet)
* struct tr2_animation has 8 extra
bytes immediately
before .FrameStart (no clues
yet)
* Three bytes ("SPR") appear immediately before NumSpriteTextures
* struct tr2_sound_source is now 40 bytes (no clues yet)
* Between SoundSources and NumBoxes is
a new element:
bitu32
NumXYZ
struct
{ bitu8 unknown[16]; } XYZ[NumXYZ];
Before SoundSources is a new field for Flyby_Camera
data
bitu32 Number_of_FBCameras
followed by data for each camera. Data field
is 40 bytes.
[Yury had previously stated NumXYZ as a new
field incorrectly.
His NumXYZ field was the SoundSources in normal
structure format],
-Note from Roy Godbold.
Four bytes ("TEX\0") appear immediately before NumObjectTextures
struct tr2_object_texture
is now 38 bytes. The .Tile
field is now bitu32, not
bitu16; the other 16 new bytes
appear after the texture
vertices (no clues yet)
It appears that SoundMap
is either larger or variable-length,
although I'm not yet certain
how the length would be inferred
(there does not appear to
be a NumSoundMap field). This causes
my parser to behave erratically,
so I currently stop parsing at
SoundMap.
Soundmap is a fixed 740 bytes long, the
problem was that the num_cinematic fields is now 4 bytes long and
the cinematic records is now 24 bytes long, so Yury was reading incorrect
that structure causing a later problem in his reader.
-Note from Turbo Pascal
.PAK files are also zlib compressed;
the first four bytes of
the file are the uncompressed size,
while the compressed size
is inferred as the file length - 4.
The logo files decompress
to 512*256*24bits bitmaps.
There is an unused level, JOBY1B.TR4,
that looks like an abandoned
effort - the only mesh is Lara, and
there is a fair amount of
landscape, but nothing to do, really...
Things I've observed using the viewer:
TR3-style alpha transparency
doesn't work (water, rays of
light,
etc.) - in fact, it's completely wrong (there are
cases
where unintended transparency occurs). This could
conceivably
be a bug in my viewer, but it works perfectly
for all
the TR3 levels, so I'm guessing there was a change.
All the
TR4 transparencies show up as opaque greyscale.
AnimatedTextures don't seem
to work; in fact, I don't think
they are
actually used (my level dumping routine is broken
at the
moment, so I can't verify this, but a few judicious
printf()s
lead me to believe that this is the case.)
Animated textures work exactly in the same
way that TR1-Tr3, i don;t known what problem Yury had with this structure.
-Note From Turbo Pascal
While every other mesh/staticmesh
works, pickups appear to be
sunk into
the floor (or whatever they're on top of). In
fact,
they appear to be Y-centered at floor (or table) level.
TR4 has a number of new
(and cool) lighting and particle effects;
interestingly,
my viewer renders these as meshes. There
must be
some interesting FloorData or hardcoded magic going
on...
Ropes do not appear as items
or staticmeshes; at present, my
viewer
can't find them at all. They may be related to the
new NumZZZ
elements, although I have no evidence of that.
I see the continuation of
a trend that I first saw in TR3, that
being
the existence of detached rooms. TR3 has a number of
levels
that have a cube off in space somewhere, which appears
to me
to be a "practice area" (to test out textures, etc.).
In addition,
at least one TR3 level (MINES.TR4) contains a
completely
detached "room" that actually appears in the
level
(when the submersible is lowered). TR4 has quite a few
detached
areas that appear in the levels; not only do they
appear,
but Lara enters and exits them. The FloorData
presumably
now contains some "teleportation" code. I assume
that this
is to avoid the "five-dimensional space" issues
that can
occur in densely overlapping areas.
The mirrored rooms are interesting;
they really are mirror-imaged
rooms
that are bisected by two translucent planes that create
the illusion
of a mirror. Again, I assume that there is some
special
FloorData that indicates one of these rooms and its centre
plane;
that way, all the engine has to do is render Lara
in mirror-image
about that plane while following the normal
FloorData
rules. Quite clever, really...
--- end notes
Good luck.
Yuri Zhivago
Note #2, By Roy Godbold
*******************************************************
TR4 Possible File Format
rgbold March '01
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
---------------
Dword = 4 bytes
Int = 2 bytes
--------------
Dword "TR4",0
Int number of RoomTextures?
Int number of OtherTextures?
Int number of BumpMapTextures?
Dword UncompressedSize1
Dword CompressedSize1
TextureBlock1
Dword UncompressedSize2
Dword CompressedSize2
TextureBlock2
Dword UncompressedSize3
Dword CompressedSize3
TextureBlock3
Dword UncompressedSize4
Dword CompressedSize4
Rest_level_Block3 //The whole level data is in compressed
mode in this block.
/// Once the level data is uncompressed then read the level as TR3 except where noted
NOTES:
Texture needs to be masked with 0xfff (high 4 bits are flags)
//the textureID on each rectangle/triangle face.
Room Lights now 46 bytes:
TR4_RoomLight //
//Follows a D3D light structure, I think, could be wrong
Dword Xposition // world coords
Dword Yposition // world coords
Dword Zposition // world coords
TR2_Color // three
bytes rgb values
bitu8 LightType // same as D3D (i.e. 2 is for spotlight)
bitu8 unknown // always 0xff?
byte Intensity
float In
float Out
float Length
float Cutoff
floats X,Y,Z //direction??
Before SoundSources is a new field for Flyby_Camera data
bitu32 Number_of_FBCameras
followed by data for each camera. Data field is 40 bytes.
[Yury had previously stated NumXYZ as a new field incorrectly.
His NumXYZ field was the SoundSources in normal structure format]
Cinematic Frames now 24 bytes
* the field num_cinematic_frames is 4 bytes long for tr4-tr5
vice 2 bytes for tr1-tr3.
There are no colored rectangles or triangles in mesh data.
Mesh Rectangles and Triangles now
MeshRects: v0,v1,v2,v3,texture,int unknown
MeshTris: v0,v1,v2,texture,int unknown
Texture Objects now preceeded by TEX/0 (4bytes)
Object Textures now 38 bytes vice 20
Tile is now a bitu32 vice bitu16 seems need to mask with 0xff as other
bits are flags. Seems bit15 set
means triangle.
In the texture coords now 0 is used for low value vice 1
The extra 16 bytes are at the end of ObjectTexture structure
Attributes using 1 or 2 for transparent. 2 used for 2 sided textures
(water surface,etc)
Animation now 40 vice 32 bytes. extra 8 seem to be zero right before
/after the old 8 unknowns
"SPR" 3 byte ascii before sprite textures
There are no 8bit or 16 bit palettes (no colored rects or tris)
No lightmap
No 8bit textures
TR4 are 4 zlib compresed chunks, 3 for textures and 1 for rest level.
Following level data are Riff Wave Formats.
Lara 2 meshes , skin and joints.
Note # 3 From Michiel:
Go to trwad.tripod.com/download/TR5Manuel.htm for a small list from the OCB codes from TR5 objects. These codes set the password in the keypads, laser types and enemie opening animations.
These codes are includes in the item structure from TR4&5 and replaces
the old intensity2 from TR2&3 data files.
This means TR4&5 don't have 2 intensity values, but only one.
The size of the structure is still the same.
-------------------------------------------
There are no cinematic frames in TR4&5. Instead of that, there is the following structure:
long NumAIData
followed by the following data for each object
int ObjectID ; the objectID from the AI object (AI_FOLLOW is 402)
int Room
long X
long Y
long Z
int OCB
int Flags ; The trigger flags (button 1-5, first button has value 2)
long Angle ; rotation
It's directly after the item data
---------------------------------------------------------------------
The underwater Current, like the doc sais, is not located in the fully
in the floordata structure. The largest part is hidden in th tr2_camera
structure. The floordata points to this structure. The difference ith a
normal camera is that the room number is strenght of the current. The unknown
int after this seems to be 0 for a camera, 1 for a fixed camera and for
a current object it is different for every object.
Note #4 From E. POPOV
Here's my compilation of docs I have about TR4 file format augmented with infos I found when coding the TR4 support in TrViewer. I sent the HTML version to TP and I will add it to my web site.
Note: it's a lot better when seen in HTML format !, Look from here!
This was lying around
////////////////////////////////////////////////////////////////////////////
//TR4 Room_Light
// EXAMPLE FOR SPOT LIGHT TYPE //
002A0000 ~ X world position dword
80FDFFFF ~ Y world position dword
007E0000 ~ Z world position dword
F0E0D0 ~ rgb colour byte[3]
02 ~ light type byte 0= sun, 1= light, 2= spot, 3= shadow,
FF ~ constant byte
13 ~ intensity byte [ 0-31 max (8 = .25) ]
B28F703F ~ in cosine float
CA03683F ~ out cosine float
00000045 ~ len float in 1024 units
00009F45 ~ cut float in 1024 units
//last 3 floats specify a directional vector
D91E7F3E ~ cosX * sinY (float)
411884BE ~ sinX (float)
E1F76E3F ~ cosX * cosY (float)
////////////////////////////////////////////////////////////////////////////
Sun -uses position of ff,ff,8 always
uses intensity
uses X and Y for directional vector
Light - uses position
uses intensity
uses OUT in 1024 units
uses IN in 1024 units
Spot - uses all fields as above
Shadow - uses position
uses intensity as -1 to 0 ( -.50 = 16 )
uses OUT in 1024 units
uses IN in 1024 units
///////////////////////////////////////////////////////////////////////////
// TR4LIGHT structure (46 bytes)
typedef struct
{
// The first 3 values represent
the position of the light in XYZ world coordinates
// NOTE: the SUN type light does not have a position and uses -1, -1,
8 for the XYZ.
long LightXposition
long LightYposition
long LightZposition
// The next 3 bytes specify the RGB color values for the light
unsigned char LightRed
unsigned char LightGreen
unsigned char LightBlue
// The next byte specifies
the type of light. 0=sun, 1=light, 2=spot, 3=shadow
// NOTE: the 'effect' type light is not really a light but just changes
the
// the vertex lighting.
char LightType
// The following byte is a constant -1. Not used.
char LightConstant
// The next byte is for the
Intensity of the light.
// All lights but the 'shadow' type uses 0 minimum to 31 maximum. i.e.
a value
// of .25 would be represented by 8.
// NOTE: the shadow type
light uses values of -1 to 0. a -.50 value would
// be represented by 16.
char LightIntensity
// For the 'light' and 'shadow'
type lights the following 2 floats
// represent the OUT and IN (falloff and hotspot) values in TR units
(1024 = 1 sector)
// For the 'spot' type light
represent the cosine of the angle.
// The 'sun' type light does
not use these values.
float LightIN
float LightOUT
// The following two floats
are used only by the 'spot' type light
// and represent the values
in TR units (1024 = 1 sector)
float LEN
float CUT
// The final 3 floats are
used only by the 'sun' and 'spot' type lights.
// They describe the directional
vector of the light.
// This can be obtained by
:
//
if both x and y x = cosX * sinY
//
y = sinX
//
z = cosX * cosY
//
//
if only x
x = 0
//
y = sinX
//
z = cosX
//
//
if only y
x = sinY
//
y = 0
//
z = cosY
float LightDirectionVectorX
float LightDirectionVectorY
float LightDirectionVectorZ
} TR4LIGHT;
///////////////////////////////////////////////////////////////////////////
|
|
|