no way to compare when less than two revisions
Differences
This shows you the differences between two versions of the page.
Previous revisionNext revision | |||
— | trs:fundamentals [2020/05/19 12:02] – [Rectangular (Quad) Face Definition] zdimension | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | {{indexmenu_n> | ||
+ | |||
+ | ====== The Fundamentals ====== | ||
+ | |||
+ | ===== File Types ===== | ||
+ | |||
+ | Tomb Raider is driven by various sets of files — [[trs: | ||
+ | |||
+ | ==== The Script Files ==== | ||
+ | |||
+ | The script file structure differs from version to version. | ||
+ | |||
+ | In TR1, all script info was embedded into executable file ('' | ||
+ | |||
+ | TR4 and TR5 introduced a new script format, where the actual script defining the gameflow was separated from text strings used in game — hence, | ||
+ | |||
+ | ==== The Level Files ==== | ||
+ | |||
+ | The level files, '' | ||
+ | |||
+ | Since TR4, the level file is divided into //several chunks//, each of them being compressed with //zlib//. Usually, each chunk of compressed data is preceded by two 32-bit unsigned integers defining the // | ||
+ | |||
+ | < | ||
+ | It’s good to note the origins of level file extension. While it is obvious that TR2/TR4/TRC extensions specify abbreviations of the game name. '' | ||
+ | </ | ||
+ | |||
+ | ==== FMVs (Full Motion Videos) ==== | ||
+ | |||
+ | TR1-3 shared the same proprietary Eidos codec for videos, called //Escape//. The extension for such files is '' | ||
+ | |||
+ | For a long time, Escape codec was largely unexplored and barely reverse-engineered; | ||
+ | |||
+ | Since TR4, all FMVs are in //Bink Video// format, which is much more common and easy to rip, convert and explore. | ||
+ | |||
+ | ==== Sound Files — Audio Tracks ==== | ||
+ | |||
+ | These are long sound files which occasionally play either on some in-game events (e.g. approaching certain important checkpoint in game, like big hall with ladder and two wolves in “Caves” — it triggers danger music theme) or in looped manner as background ambience. Audio tracks are stored differently across TR game versions — // | ||
+ | |||
+ | ==== Sound Files — Samples ==== | ||
+ | |||
+ | TR2 and TR3 also featured external sound sample files, which allowed to share samples between all level files. This sound file is called '' | ||
+ | |||
+ | ==== Cut Sequence Packs ==== | ||
+ | |||
+ | TR4 and TR5 featured special data type containing all the necessary information to play //in-game cutscenes// | ||
+ | |||
+ | The data for such cutscene setup was packed into single file titled '' | ||
+ | |||
+ | {{anchor: | ||
+ | ===== Basic Data Types ===== | ||
+ | |||
+ | For the purposes of further discussion, the following are assumed: | ||
+ | |||
+ | |'' | ||
+ | |'' | ||
+ | |'' | ||
+ | |'' | ||
+ | |'' | ||
+ | |'' | ||
+ | |'' | ||
+ | |'' | ||
+ | |||
+ | All multi-byte integers ('' | ||
+ | |||
+ | ==== 32 bit Fixed Point Data Type ==== | ||
+ | |||
+ | This is a 32 bit integer, where a unit (i.e., the 1 in the normal numerical sense) is expressed as $2^{16}$. Under the assumption that $f$ is a real number, and $p$ is a fixed-point number, the conversion is $f = p/2^{16}$, or $p = [f \cdot 2^{16}]$. | ||
+ | |||
+ | There are certain cases where special caution must be paid. A multiplication $f = f_1 \cdot f_2$ must be calculated as | ||
+ | |||
+ | $f = f_1 \cdot f_2 \Leftrightarrow | ||
+ | |||
+ | ==== Data Alignment ==== | ||
+ | |||
+ | Data alignment is something one has to be careful about. When some entity gets an address that is a multiple of $n$, it is said to be $n$-byte aligned. The reason it is important here is that some systems prefer multibyte alignment for multibyte quantities, and compilers for such systems may pad the data to get the “correct” alignments, thus making the in-memory structures out of sync with their file counterparts. However, a compiler may be commanded to use a lower level of alignment, one that will not cause padding. And for TR’s data structures, 2-byte alignment should be successful in nearly all cases, with exceptions noted below. | ||
+ | |||
+ | To set single-byte alignment in any recent compiler, use the following compiler directive: | ||
+ | |||
+ | <code cpp> | ||
+ | #pragma pack(push, 1) | ||
+ | </ | ||
+ | To return to the project’s default alignment, use the following directive: | ||
+ | |||
+ | <code cpp> | ||
+ | #pragma pack(pop) | ||
+ | </ | ||
+ | ===== Basic Terms ===== | ||
+ | |||
+ | ==== Coordinates ==== | ||
+ | |||
+ | The world coordinate system is oriented with the $X-Z$ plane horizontal and $Y$ vertical, with $-Y$ being “up” (e.g. decreasing $Y$ values indicate increasing altitude). The world coordinate system is specified using '' | ||
+ | |||
+ | There are some additional coordinate values used, such as “the number of 1024-unit blocks between points A and B”; these are simply scaled versions of more conventional coordinates. | ||
+ | |||
+ | ==== Colours ==== | ||
+ | |||
+ | All colours in TR are specified either explicitly (using either the [[fundamentals# | ||
+ | |||
+ | In TR1-3, mesh surfaces could be either // | ||
+ | |||
+ | Beginning from TR4, coloured faces feature was removed, so each face must have a texture attached to it. | ||
+ | |||
+ | ==== Textures ==== | ||
+ | |||
+ | // | ||
+ | |||
+ | The 16-bit atlas array, which contains [[fundamentals# | ||
+ | |||
+ | {{: | ||
+ | |||
+ | {{: | ||
+ | |||
+ | ==== Meshes and Sprites ==== | ||
+ | |||
+ | There are two basic types of “visible objects” in TR2 — meshes and sprites. | ||
+ | |||
+ | //Meshes// are collections of textured or coloured polygons that are assembled to form a three-dimensional object (such as a tree, a tiger, or Lara herself). The “rooms” themselves are also composed of meshes. Mesh objects may contain more than one mesh; though these meshes are moved relative to each other, each mesh is rigid. | ||
+ | |||
+ | //Sprites// are two-dimensional images that are inserted into three-dimensional space, such as the “secret” dragons, ammunition, medi-packs, etc. There are also animated sprite sequences, such as the fire at the end of “The Great Wall.” Core had presumably used this method to reduce CPU utilization on the PlayStation and/or the earlier PCs. Sprites become less and less abundant; TR2 has very few scenery sprites, and TR3’s pickups are models instead of sprites. | ||
+ | |||
+ | ==== Entities ==== | ||
+ | |||
+ | Each Tomb Raider game has an internal hardcoded set of //entity types//, each of them linked to specific //model// (hence, //entity type// and //model// can be considered equal). Entity is an individual object with its own specific function and purpose. Almost every “moving” or “acting” thing you see is an entity — like enemies, doors, pick-up items, and even Lara herself. | ||
+ | |||
+ | A level can contain numerous instances of the same entity type, e.g. ten crocodiles, five similar doors and switches, and so on. | ||
+ | |||
+ | Entities are referenced in one of two ways — as an offset into an array (e.g. '' | ||
+ | |||
+ | ==== Animations ==== | ||
+ | |||
+ | There are three basic types of animations in TR, two corresponding with textures — sprite animations and animated textures — and one corresponding directly with meshes. | ||
+ | |||
+ | === Sprite Animations === | ||
+ | |||
+ | Sprite animation (sprite sequences) consists simply of a series of sprites that are to be displayed one after another, e.g. grenade explosions. Sprite animations were quite common in earlier games (TR1 and TR2), while in TR3 onwards there are almost no sprite animations — only notable example is fire particle sprites and water splash effect. | ||
+ | |||
+ | === Animated Textures === | ||
+ | |||
+ | These are either a list of textures cycled through in endless loop, or (in TR4-5) a single texture with shifting coordinates, | ||
+ | |||
+ | === Mesh Animations === | ||
+ | |||
+ | Mesh animations are much more complex than sprite and texture animations, and done by what is essentially a skeletal-modeling scheme. These involve some arrays (Frames[] and MeshTree[]) of offsets and rotations for each element of a composite mesh. Frames are then grouped into an array (Animations[]) that describes discrete “movements”, | ||
+ | |||
+ | ==== Lighting ==== | ||
+ | |||
+ | There are two main types of lighting in Tomb Raider, // | ||
+ | |||
+ | Furthermore, | ||
+ | |||
+ | When available, external lighting also uses the vertex normals to calculate the incoming light at each vertex. Light intensities are described either with a single value or with a 16 bits color value (you can see it more like a “color filter”), depending mainly on the TR version. | ||
+ | |||
+ | Light intensities are described with a single value in TR1 and a pair of values in TR2 and TR3; the paired values are almost always equal, and the pairing may reflect some feature that was only imperfectly implemented, | ||
+ | |||
+ | ==== Sound Samples ==== | ||
+ | |||
+ | There are two ways for sound samples to play. | ||
+ | |||
+ | First one is basically sound emitter sitting at a static global position in level, and continuously emitting specified sound (such as waterfalls — these are in '' | ||
+ | |||
+ | Either way, each played sound is referred to using a three-layer indexing scheme, to provide a maximum amount of abstraction. An internal sound index references '' | ||
+ | |||
+ | ===== Basic Data Structures ===== | ||
+ | |||
+ | Much of the .TR2 file is comprised of structures based on a few fundamental data structures, described below. | ||
+ | |||
+ | ==== Colour Structures ==== | ||
+ | |||
+ | This is how most colours are specified. | ||
+ | |||
+ | {{anchor: | ||
+ | <code cpp> | ||
+ | struct tr_colour | ||
+ | { | ||
+ | uint8_t Red; // Red component (0 -- darkest, 255 -- brightest) | ||
+ | uint8_t Green; | ||
+ | uint8_t Blue; // Blue component (0 -- darkest, 255 -- brightest) | ||
+ | }; | ||
+ | </ | ||
+ | (Some compilers will pad this structure to make 4 bytes; one must either read and write 3 bytes explicitly, or else use a simple array of bytes instead of this structure.) | ||
+ | |||
+ | And as mentioned earlier, the 16-bit palette uses a similar structure: | ||
+ | |||
+ | {{anchor: | ||
+ | <code cpp> | ||
+ | struct tr_colour4 | ||
+ | { | ||
+ | uint8_t Red; | ||
+ | uint8_t Green; | ||
+ | uint8_t Blue; | ||
+ | uint8_t Unused; | ||
+ | }; | ||
+ | </ | ||
+ | In TR5, there is new additional colour type composed of floating-point numbers. This type is primarily used in light structures. | ||
+ | |||
+ | {{anchor: | ||
+ | <code cpp> | ||
+ | struct tr5_colour | ||
+ | { | ||
+ | float Red; | ||
+ | float Green; | ||
+ | float Blue; | ||
+ | float Unused; | ||
+ | }; | ||
+ | </ | ||
+ | ==== Vertex Structures ==== | ||
+ | |||
+ | This is how vertices are specified, using relative coordinates. They are generally formed into lists, such that other entities (such as quads or triangles) can refer to them by simply using their index in the list. | ||
+ | |||
+ | {{anchor: | ||
+ | <code cpp> | ||
+ | struct tr_vertex | ||
+ | { | ||
+ | int16_t x; | ||
+ | int16_t y; | ||
+ | int16_t z; | ||
+ | }; | ||
+ | </ | ||
+ | As with colours, TR5 introduced additional vertex type comprised of floating-point numbers: | ||
+ | |||
+ | {{anchor: | ||
+ | <code cpp> | ||
+ | struct tr5_vertex | ||
+ | { | ||
+ | float x; | ||
+ | float y; | ||
+ | float z; | ||
+ | }; | ||
+ | </ | ||
+ | ==== Rectangular (Quad) Face Definition ==== | ||
+ | |||
+ | Four vertices (the values are indices into the appropriate vertex list) and a texture (an index into the object-texture list) or colour (index into 8-bit palette or 16-bit palette). If the rectangle is a coloured polygon (not textured), the .Texture element contains two indices: the low byte ('' | ||
+ | |||
+ | {{anchor: | ||
+ | <code cpp> | ||
+ | struct tr_face4 | ||
+ | { | ||
+ | uint16_t Vertices[4]; | ||
+ | uint16_t Texture; | ||
+ | }; | ||
+ | </ | ||
+ | '' | ||
+ | |||
+ | {{: | ||
+ | |||
+ | {{: | ||
+ | |||
+ | {{anchor: | ||
+ | <code cpp> | ||
+ | struct tr4_mesh_face4 | ||
+ | { | ||
+ | uint16_t Vertices[4]; | ||
+ | uint16_t Texture; | ||
+ | uint16_t Effects; | ||
+ | }; | ||
+ | </ | ||
+ | The only difference is the extra field '' | ||
+ | |||
+ | * //Bit 0:// if set, face has //additive alpha blending// (same meaning that when the '' | ||
+ | |||
+ | |{{: | ||
+ | |//Bit 0 set, blending enabled// | ||
+ | |||
+ | * //Bit 1:// if set, face has // | ||
+ | * //Bits 2..7:// strength of // | ||
+ | |||
+ | |{{: | ||
+ | |//Shiny effect at max// |//No shiny effect// | ||
+ | |||
+ | - Note that only externally lit meshes can use environment mapping in original engines. If you use it with internally lit meshes, you will crash the game. | ||
+ | - TR4 engine doesn’t support environmental map for Lara’s joints. It simply wasn’t implemented, | ||
+ | |||
+ | ==== Triangular Face Definition ==== | ||
+ | |||
+ | These structures has the same layout than the quad face definitions, | ||
+ | |||
+ | {{anchor: | ||
+ | <code cpp> | ||
+ | struct tr_face3 | ||
+ | { | ||
+ | uint16_t Vertices[3]; | ||
+ | uint16_t Texture; | ||
+ | }; | ||
+ | </ | ||
+ | {{anchor: | ||
+ | <code cpp> | ||
+ | struct tr4_mesh_face3 | ||
+ | { | ||
+ | uint16_t Vertices[3]; | ||
+ | uint16_t Texture; | ||
+ | uint16_t Effects; | ||
+ | }; | ||
+ | </ | ||
+ | All the info about '' | ||
+ | |||
+ | ==== 8-bit Texture Tile ==== | ||
+ | |||
+ | Each '' | ||
+ | |||
+ | {{anchor: | ||
+ | <code cpp> | ||
+ | struct tr_image8 | ||
+ | { | ||
+ | uint8_t pixels[256 * 256]; | ||
+ | }; | ||
+ | </ | ||
+ | ==== 16-bit Texture Tile ==== | ||
+ | |||
+ | Each '' | ||
+ | |||
+ | {{anchor: | ||
+ | <code cpp> | ||
+ | struct tr_image16 | ||
+ | { | ||
+ | uint16_t pixels[256 * 256]; | ||
+ | }; | ||
+ | </ | ||
+ | ==== 32-bit Texture Tile ==== | ||
+ | |||
+ | Each '' | ||
+ | |||
+ | {{anchor: | ||
+ | <code cpp> | ||
+ | struct tr4_image32 | ||
+ | { | ||
+ | uint32_t pixels[256 * 256]; | ||
+ | }; | ||
+ | </ | ||