Both sides previous revisionPrevious revisionNext revision | Previous revision |
trs:fundamentals [2017/02/02 19:56] – ↷ Page moved from opentomb:trs:fundamentals to trs:fundamentals stohrendorf | trs:fundamentals [2020/05/19 12:16] (current) – [Fixed Point Data Types] zdimension |
---|
| {{indexmenu_n>1}} |
| |
====== The Fundamentals ====== | ====== The Fundamentals ====== |
| |
===== File Types ===== | ===== File Types ===== |
| |
Tomb Raider is driven by various sets of files — [[trs:file_formats|level files]], [[opentomb:trs:scripting_tr2_tr3|script]] [[opentomb:trs:scripting_tr4_tr5|files]], FMVs, [[opentomb:trs:sound#audio_tracks|audio tracks]] and [[opentomb:trs:sound#sound_files|sound files]]. In TR4 and TR5, there is also specific file type which contains cutscene data — [[trs:cutseq|cutseq pack]]. | Tomb Raider is driven by various sets of files — [[trs:file_formats|level files]], [[trs:scripting_tr2_tr3|script]] [[trs:scripting_tr4_tr5|files]], FMVs, [[trs:sound#audio_tracks|audio tracks]] and [[trs:sound#sound_files|sound files]]. In TR4 and TR5, there is also specific file type which contains cutscene data — [[trs:cutseq|cutseq pack]]. |
| |
==== The Script Files ==== | ==== The Script Files ==== |
|''%%float%%'' |specifies a 32-bit IEEE-754 floating-point number | | |''%%float%%'' |specifies a 32-bit IEEE-754 floating-point number | |
|''%%fixed%%'' |specifies a 32-bit non-trivial 16.16 fixed point value — see further| | |''%%fixed%%'' |specifies a 32-bit non-trivial 16.16 fixed point value — see further| |
| |''%%ufixed16%%'' |specifies a 16-bit non-trivial 8.8 fixed point value — see further| |
| |
All multi-byte integers (''%%{u}int16_t%%'', ''%%{u}int32_t%%'') are stored in little-endian (Intel-x86, etc.) format, with the least significant byte stored first and the most significant byte stored last. When using this data in platforms with big-endian (PowerPC, etc.) number format, be sure to reverse the order of bytes. | All multi-byte integers (''%%{u}int16_t%%'', ''%%{u}int32_t%%'') are stored in little-endian (Intel-x86, etc.) format, with the least significant byte stored first and the most significant byte stored last. When using this data in platforms with big-endian (PowerPC, etc.) number format, be sure to reverse the order of bytes. |
| |
==== 32 bit Fixed Point Data Type ==== | ==== Fixed Point Data Types ==== |
| |
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}]$. | These very specific data types mimic floating-point behaviour, //while remaining integer//. It is done by splitting floating-point value into whole and fractional parts, and keeping each part as ''int16_t'' and ''uint16_t'' correspondingly for `fixed` type and as ''uint8_t'' and ''uint8_t'' for ''ufixed16'' type. Whole part is kept as it is, while fractional part is multiplied by 65536 (for ''fixed'') or by 255 (for ''ufixed16''), and then kept as unsigned integer. So, the formula to calculate floating-point from ''fixed'' is: |
| |
There are certain cases where special caution must be paid. A multiplication $f = f_1 \cdot f_2$ must be calculated as | $F_{real} = P_{whole} + ( P_{frac} \div 65536 )$ |
| |
$f = f_1 \cdot f_2 \Leftrightarrow f = (p_1/2^{16}) \cdot (p_1/2^{16}) \Leftrightarrow f = p/2^{16} = \frac{p_1 \cdot p_2}{2^{32}} \Leftrightarrow p = \frac{p_1 \cdot p_2}{2^{16}}$ | Formula to calculate floating-point from ''ufixed16'' is: |
| |
| $F_{real} = P_{whole} + ( P_{frac} \div 255 )$ |
| |
| ...where $P_{whole}$ is whole part of mixed float (signed for ''fixed'', unsigned for ''ufixed16''), and $P_{frac}$ is fractional part (unsigned). |
| |
| <note> |
| The reason why such complicated setup was invented is to avoid using floating-point numbers. In 90% of all cases, Tomb Raider engines use integer numbers, even |
| for geometry calculations and animation interpolations. The root of this setup lies in multi-platform nature of the code, which was simultaneously written for PC and PlayStation. While PCs had enough computational power to deal with floats at that time, PlayStation relied only on integers. |
| |
| However, some internal variables and constants (like drawing distance, fog distance constants and some light properties) are PC-specific and stored in floating |
| point numbers. Also, last game in series, TR5, extensively used floating-point numbers for certain data types – like colours, vertices and coordinates. |
| </note> |
| |
==== Data Alignment ==== | ==== Data Alignment ==== |
==== Colours ==== | ==== Colours ==== |
| |
All colours in TR are specified either explicitly (using either the [[opentomb:trs:fundamentals#tr_colour|[tr_colour]]] structure, described below, 16-bit structures or 32-bit structures) or implicitly, by indexing one of the palettes. However, it is only applicable to TR1-3 — there is no palette in TR4 and TR5. | All colours in TR are specified either explicitly (using either the [[fundamentals#tr_colour|[tr_colour]]] structure, described below, 16-bit structures or 32-bit structures) or implicitly, by indexing one of the palettes. However, it is only applicable to TR1-3 — there is no palette in TR4 and TR5. |
| |
In TR1-3, mesh surfaces could be either //coloured// or //textured//. //Coloured// surfaces are “painted” with a single colour that is either specified explicitly or using an index into the palette. | In TR1-3, mesh surfaces could be either //coloured// or //textured//. //Coloured// surfaces are “painted” with a single colour that is either specified explicitly or using an index into the palette. |
==== Textures ==== | ==== Textures ==== |
| |
//Textured// surfaces map textures (bitmapped images) from the texture tiles (textiles) to each point on the mesh surface. This is done using conventional UV mapping, which is specified in “Object Textures” below; each object texture specifies a mapping from a set of vertices to locations in the textile, and these texture vertices are associated with position vertices specified here. Each textile is a 256x256 pixels wide area. | //Textured// surfaces map textures from the texture atlases (textiles) to each point on the mesh surface. This is done using conventional UV mapping, which is specified in “Object Textures” below; each object texture specifies a mapping from a set of vertices to locations in an atlas, and these texture vertices are associated with position vertices specified here. Each atlas has a size of 256x256 pixels. |
| |
The 16-bit textile array, which contains [[opentomb:trs:fundamentals#tr_textile16|[tr_textile16]]] structures, specifies colours using 16-bit ARGB, where the highest bit (''%%0x8000%%'') is a crude alpha channel (really just simple transparency — //0 = transparent//, //1 = opaque//). The next 5 bits (''%%0x7C00%%'') specify the red channel, the next 5 bits (''%%0x03E0%%'') specify the green channel, and the last 5 bits (''%%0x001F%%'') specify the blue channel, each on a scale from 0..31. | The 16-bit atlas array, which contains [[fundamentals#tr_image16|[tr_image16]]] structures, specifies colours using 16-bit 1-5-5-5 ARGB encoding. |
| |
{{:icons:tr1.png?nolink|TR1 only}}{{:icons:tr2.png?nolink|TR2 only}}{{:icons:tr3.png?nolink|TR3 only}} If, for some reason, 16-bit textures are turned off, all colours and textures use an 8-bit palette that is stored in the level file. This palette consists of a 256-element array of [[opentomb:trs:fundamentals#tr_colour|[tr_colour]]] structures, each designating some colour; textures and other elements that need to reference a colour specify an index (0..255) into the ''%%Palette[]%%'' array. There is also a 16-bit palette, which is used for identifying colours of solid polygons. The 16-bit palette contains up to 256 four-byte entries; the first three bytes are a [[opentomb:trs:fundamentals#tr_colour|[tr_colour]]], while the last byte is ignored (set to 0). | {{:icons:tr1.png?nolink|TR1 only}}{{:icons:tr2.png?nolink|TR2 only}}{{:icons:tr3.png?nolink|TR3 only}} If, for some reason, 16-bit textures are turned off, all colours and textures use an 8-bit palette that is stored in the level file. This palette consists of a 256-element array of [[fundamentals#tr_colour|[tr_colour]]] structures, each designating some colour; textures and other elements that need to reference a colour specify an index (0..255) into the ''%%Palette[]%%'' array. There is also a 16-bit palette, which is used for identifying colours of solid polygons. The 16-bit palette contains up to 256 four-byte entries; the first three bytes are a [[fundamentals#tr_colour|[tr_colour]]], while the last byte is ignored (set to 0). |
| |
{{:icons:tr4.png?nolink|TR4 only}}{{:icons:tr5.png?nolink|TR5 only}} The 32-bit textile array, which contains [[opentomb:trs:fundamentals#tr4_textile32|[tr4_textile32]]] structures, specifies colours using 32-bit ARGB, where the highest byte (A) is unused. The next bytes specify (in this order) the red / green / blue channels. The 16-bit and 32-bit textile arrays depict the same graphics data, but of course the 32-bit array has a better colour resolution. It’s the one used if you select a 32-bit A8R8G8B8 texture format in the setup menu from TR4 and TR5. | {{:icons:tr4.png?nolink|TR4 only}}{{:icons:tr5.png?nolink|TR5 only}} The 32-bit texture atlas array, which contains [[fundamentals#tr4_image32|[tr4_image32]]] structures, specifies colours using 32-bit ARGB, where the alpha channel is unused. The 16-bit and 32-bit texture atlas arrays depict the same graphics data, but of course the 32-bit array has a better colour resolution. It’s the one used if you select a 32-bit A8R8G8B8 texture format in the setup menu from TR4 and TR5. |
| |
==== Meshes and Sprites ==== | ==== Meshes and Sprites ==== |
The only difference is the extra field ''%%Effects%%''. It has this layout: | The only difference is the extra field ''%%Effects%%''. It has this layout: |
| |
* //Bit 0:// if set, face has //additive alpha blending// (same meaning that when the ''%%Attribute%%'' field of [[opentomb:trs:miscellany#tr_object_texture|[tr_object_texture]]] is 2, but this flag overrides it). | * //Bit 0:// if set, face has //additive alpha blending// (same meaning that when the ''%%Attribute%%'' field of [[trs:miscellany#tr_object_texture|[tr_object_texture]]] is 2, but this flag overrides it). |
| |
|{{:illustrations:face_blend.jpg?nolink|illustrations/face_blend.jpg}}|{{:illustrations:face_noblend.jpg?nolink|illustrations/face_noblend.jpg}}| | |{{:illustrations:face_blend.jpg?nolink|illustrations/face_blend.jpg}}|{{:illustrations:face_noblend.jpg?nolink|illustrations/face_noblend.jpg}}| |
|//Bit 0 set, blending enabled// |//Bit 0 not set, blending disabled// | | |//Bit 0 set, blending enabled// |//Bit 0 not set, blending disabled// | |
| |
* //Bits 1..7:// strength of //environment mapping// effect (so-called “shiny effect” in TRLE community). Environment map is derived from special pre-rendered texture. The bigger the value is, the more visible the effect is. | * //Bit 1:// if set, face has //environment mapping// effect (so-called "shiny effect" in TRLE community). Environment map is derived from special pre-rendered texture. |
| * //Bits 2..7:// strength of //environment mapping// effect. The bigger the value is, the more visible the effect is. |
| |
|{{:illustrations:shine-on.jpg?nolink|illustrations/shine-on.jpg}}|{{:illustrations:shine-off.jpg?nolink|illustrations/shine-off.jpg}}| | |{{:illustrations:shine-on.jpg?nolink|illustrations/shine-on.jpg}}|{{:illustrations:shine-off.jpg?nolink|illustrations/shine-off.jpg}}| |
}; | }; |
</code> | </code> |
All the info about ''%%Texture%%'' and ''%%Effects%%'' fields is also similar to same info from [[opentomb:trs:fundamentals#tr_face4|[tr_face4]]] and [[opentomb:trs:fundamentals#tr4_mesh_face4|[tr4_mesh_face4]]] respectively. | All the info about ''%%Texture%%'' and ''%%Effects%%'' fields is also similar to same info from [[fundamentals#tr_face4|[tr_face4]]] and [[fundamentals#tr4_mesh_face4|[tr4_mesh_face4]]] respectively. |
| |
==== 8-bit Texture Tile ==== | ==== 8-bit Texture Tile ==== |
{{anchor:tr_textile8}} | {{anchor:tr_textile8}} |
<code cpp> | <code cpp> |
struct tr_textile8 // 65536 bytes | struct tr_image8 // 65536 bytes |
{ | { |
uint8_t Tile[256 * 256]; | uint8_t pixels[256 * 256]; |
}; | }; |
</code> | </code> |
==== 16-bit Texture Tile ==== | ==== 16-bit Texture Tile ==== |
| |
Each ''%%uint16_t%%'' represents a pixel whose colour is of the form ARGB, MSB-to-LSB: | Each ''%%uint16_t%%'' represents a pixel, encoded as 1-5-5-5 ARGB. |
| |
1-bit transparency (''%%0%%'' = transparent, ''%%1%%'' = opaque) (''%%0x8000%%'')\\ | |
5-bit red channel (''%%0x7C00%%'')\\ | |
5-bit green channel (''%%0x03E0%%'')\\ | |
5-bit blue channel (''%%0x001F%%'') | |
| |
{{anchor:tr_textile16}} | {{anchor:tr_image16}} |
<code cpp> | <code cpp> |
struct tr_textile16 // 131072 bytes | struct tr_image16 // 131072 bytes |
{ | { |
uint16_t Tile[256 * 256]; | uint16_t pixels[256 * 256]; |
}; | }; |
</code> | </code> |
==== 32-bit Texture Tile ==== | ==== 32-bit Texture Tile ==== |
| |
Each ''%%uint32_t%%'' represents a pixel whose colour is of the form ARGB, (A = most significant byte), each component being one byte. | Each ''%%uint32_t%%'' represents a pixel encoded in ARGB8. |
| |
{{anchor:tr4_textile32}} | {{anchor:tr4_textile32}} |
<code cpp> | <code cpp> |
struct tr4_textile32 // 262144 bytes | struct tr4_image32 // 262144 bytes |
{ | { |
uint32_t Tile[256 * 256]; | uint32_t pixels[256 * 256]; |
}; | }; |
</code> | </code> |
| |