OBD:TXMP: Difference between revisions

added detail on effects options and PS2 palette format; added section on pixel byte storage order; made formal subsections out of informal subsections
(Claude helped me finish REing the PS2 format; I've arranged the existing information better and integrated Claude's suggested corrections)
(added detail on effects options and PS2 palette format; added section on pixel byte storage order; made formal subsections out of informal subsections)
Line 27: Line 27:
:0x200 - has environment map texture
:0x200 - has environment map texture
:0x400 - additive alpha blending
:0x400 - additive alpha blending
:0x1000 - little endian data
:0x1000 - little-endian data
:0x4000 - animation time: ignore game time (see below)
:0x4000 - animation time: ignore game time (see below)
:0x8000 - effect: phase shield (blue)
:0x8000 - effect: blue shield
:0x10000 - effect: invisibility
:0x10000 - effect: invisibility
:0x20000 - effect: boss shield (red) }}
:0x20000 - effect: Daodan shield}}
{{OBDtr| 0x8C | int16    |C8FFC8| 80 00      | 128      | width of the image in pixels }}
{{OBDtr| 0x8C | int16    |C8FFC8| 80 00      | 128      | width of the image in pixels }}
{{OBDtr| 0x8E | int16    |C8FFC8| 80 00      | 128      | height of the image in pixels }}
{{OBDtr| 0x8E | int16    |C8FFC8| 80 00      | 128      | height of the image in pixels }}
Line 77: Line 77:
|}
|}


===Effect options===
The "blue shield", "invisibility" and "Daodan shield" options tell the engine to vary the texture's Gouraud shading with certain preset colors that vary with time.


;Effect options
{| class="wikitable"
:"Shield", "Invisibility" and "Daodan shield" options do not affect the texture reading/drawing in any way. The texture data is still RGB555 or whatever format the texture format field says it is. The effect of these flags is that the engine uses vertex shading with a colour that varies with time.
!Flag name
!Texture with flag
!Used for
|-
|"blue shield"
|TXMPSHIELD
|force shield
|-
|"invisibility"
|TXMPINVIS
|phase cloak
|-
|"Daodan shield"
|TXMPDAODAN_SHIELD
|red boss shield and [[supershield]]
|}


;Animation time
In the vanilla game data, these flags are only used by the above-named textures. The engine also calls upon these textures by hardcoded name in order to create a character's shield or phase cloak effect.
 
===Animation time===
When using animated textures the image to display is selected using the game time and animation speed. For textures that are used by particles the local (particle) time can be used either to replace or offset the game time.
When using animated textures the image to display is selected using the game time and animation speed. For textures that are used by particles the local (particle) time can be used either to replace or offset the game time.


;Pixel storage order
===Pixel byte storage order===
:Pixels are stored in row-major order, meaning that all the pixels forming a scanline (image row) are grouped together (stored in left-to right order); the rows are stored in bottom-to-top order (see illustration below).
As noted above under each format description, the bytes of multibyte texture formats are generally stored "backwards" compared to their names, so if a format is named "RGBA"-something then its bytes will be in ABGR order on disk. This convention was established in the Windows world where PCs were little-endian and loading the bytes AA BB GG RR into a 32-bit int in memory would place them in the correct order, 0xRRGGBBAA. Macintoshes, being big-endian at the time, expected the data to be stored in reverse order and thus Oni would perform a byte swap on most of these types when it loaded them into memory to ensure that they ended up as 0xRRGGBBAA in memory. The sole exceptions to this little-endian storage rule among Oni's supported texture formats are RGB_Bytes and RGBA_Bytes, which actually store their bytes in the stated order, RGB and RGBA respectively. However these formats were never used by any textures in Oni.
:In the case of the DXT1 storage format, the row-major, left-to-right, bottom-to-top order applies to the 4x4 blocks composing the image, and also inside each 4x4 block for the storage of 2-bit pixels.
 
:In the case of the I1 format (several pixels per byte), the row-major, left-to-right, bottom-to-top order applies to the 1-bit pixels composing the image.
===Pixel storage order===
Pixels are stored in row-major order, meaning that all the pixels forming a scanline (image row) are grouped together (stored in left-to right order); the rows are stored in bottom-to-top order (see illustration below). In the case of the DXT1 storage format, the row-major, left-to-right, bottom-to-top order applies to the 4x4 blocks composing the image, and also inside each 4x4 block for the storage of 2-bit pixels. In the case of the I1 format (several pixels per byte), the row-major, left-to-right, bottom-to-top order applies to the 1-bit pixels composing the image.
{|border=0
{|border=0
|+Pixel arrangement
|+Pixel arrangement
Line 122: Line 142:
|}
|}


 
===Palette file format===
;Palette file format
*Palettes are stored per-level in level#_palette.pal files in a pal/ subdirectory of GameDataFolder, corresponding to how .raw and .sep files are stored in raw/ and sep/ subdirectories.
*Palettes are stored per-level in level#_palette.pal files in a pal/ subdirectory of GameDataFolder, corresponding to how .raw and .sep files are stored in raw/ and sep/ subdirectories.
*Each level#_palette.pal file contains between 85 and 179 palettes, not counting the first palette (index 0) at the start of each .pal file which is always blank.
*Each level#_palette.pal file contains between 85 and 179 palettes, not counting the first palette (index 0) at the start of each .pal file which is always blank.


;Palette format
===Palette format===
*Valid palette indices start at 1.  Each palette consists of 256 32-bit colors and takes up 1024 bytes.
*Valid palette indices start at 1 because of palette 0 always being empty.
*Each 4-byte palette entry is stored as R, G, B, A in memory order (byte 0 = red, byte 1 = green, byte 2 = blue, byte 3 = alpha). This is the same layout as RGBA_Bytes (type 11), not the reversed BGRA order used by most of the other texture formats.
*Each color in a palette entry is 4 bytes, stored on disk in RGBA order (byte 0 = red, byte 1 = green, byte 2 = blue, byte 3 = alpha). This is the same layout as RGB_Bytes (type 10) and RGBA_Bytes (type 11), not the reversed BGRA order used by most of the other texture formats.
*Each palette consists of 256 32-bit color slots and thus takes up 1024 bytes. If a palette does not use all 256 entries then the palette is closed out with a series of {0x00, 0x00, 0x00, 0x80} entries.
*Each pixel in the .raw or .sep data is stored as a 1-byte index into the image's chosen color palette.
*Each pixel in the .raw or .sep data is stored as a 1-byte index into the image's chosen color palette.


;Palette CLUT swizzle
===Palette CLUT swizzle===
:The PS2 Graphics Synthesizer (GS) stores CLUT entries in a scrambled order due to its hardware cache line layout. Within every 32-entry block of the palette, entries 8–15 and 16–23 are swapped relative to their logical positions. Software reading the palette must undo this before using it as a palette index.
:The PS2 Graphics Synthesizer (GS) stores CLUT entries in a scrambled order due to its hardware cache line layout. Within every 32-entry block of the palette, entries 8–15 and 16–23 are swapped relative to their logical positions. Software reading the palette must undo this before using it as a palette index.


;Ignored alpha byte for type 16
===Ignored alpha byte for type 16===
:The fourth byte would represent alpha, but in RGB888 it is merely a padding byte, always set to 0x80.
:The fourth byte would represent alpha, but in RGB888 it is merely a padding byte, always set to 0x80.


;Alpha scaling for type 17
===Alpha scaling for type 17===
:The PS2 GS uses a half-range alpha where 0x00 = fully transparent and 0x80 = fully opaque (values above 0x80 are technically possible but indicate "source alpha contribution > 1" in GS blending, which doesn't arise in Oni).
:The PS2 GS uses a half-range alpha where 0x00 = fully transparent and 0x80 = fully opaque (values above 0x80 are technically possible but indicate "source alpha contribution > 1" in GS blending, which doesn't arise in Oni).


;Alternating use of .raw or .sep storage
===Alternating use of .raw or .sep storage===
Unlike the Win/Mac game data (where pixel data is stored exclusively in .raw or exclusively in .sep for all TXMPs), PS2 TXMPs use .raw and .sep storage alternatingly, depending on the TXMP. The engine apparently uses the .sep pointer if there is no .raw pointer (or vice versa).
Unlike the Win/Mac game data (where pixel data is stored exclusively in .raw or exclusively in .sep for all TXMPs), PS2 TXMPs use .raw and .sep storage alternatingly, depending on the TXMP. The engine apparently uses the .sep pointer if there is no .raw pointer (or vice versa).


Line 149: Line 169:


==Oni's internal storage types==
==Oni's internal storage types==
Some of Oni's 16 types of image storage are elaborated on below in order to illustrate exactly how they work. The "Mem view" column shows the bytes in memory as big-endian and the "Disk view" column shows the bytes as they are stored in little-endian order. For example the bytes in memory shown as 0xFC00 are stored as "00 FC" on disk.
Some of Oni's 18 types of image storage are elaborated on below in order to illustrate exactly how they work. The "Mem view" column shows the bytes in big-endian format and the "Disk view" column shows the bytes as they are actually stored in little-endian order. For example, bytes in memory shown as 0xFC00 are stored as "00 FC" on disk.


===ARGB4444 (type 0)===
===ARGB4444 (type 0)===