Difference between revisions of "World"

From Crash Bandicoot Hacking Wiki
Jump to navigation Jump to search
(Format)
m (Texture coordinates: Fixing table)
Line 282: Line 282:
 
!0
 
!0
 
|
 
|
C
+
  C
  <nowiki> |\
+
  <nowiki>   |\
 
   | \
 
   | \
 
  A |--\ B</nowiki>
 
  A |--\ B</nowiki>
Line 312: Line 312:
 
!3
 
!3
 
|
 
|
B     C
+
  B     C
  <nowiki> |--/
+
  <nowiki>   |--/
 
   | /
 
   | /
 
  A |/</nowiki>
 
  A |/</nowiki>
Line 372: Line 372:
 
  <nowiki>----------
 
  <nowiki>----------
 
   </nowiki> yyyyyyyy (vv)
 
   </nowiki> yyyyyyyy (vv)
+
 
 
==== CLUT coordinates ====
 
==== CLUT coordinates ====
  

Revision as of 15:55, 7 October 2015

A World is a 3 dimensional gouraud-shaded textured/semi-textured or non-textured polygon mesh that represents a visible portion of a level; all together, the world(s) [entries] in an NSF file represent the entire model for the corresponding level. Worlds are Type 3 entries. Each zone specifies at most 8 world models that shall be rendered [and will appear to the player] when the player character is within its confines. For each frame of execution, the corresponding polygon primitives are re-generated from the model data for the 8 worlds in the current zone, transformed according to global matrices (i.e. camera trans, rot, and scale) including a perspective transform from 3 dimensions to 2, and finally sent to the GPU for rendering. As a result, the player observes the [up to] 8 world models from the perspective of the camera at its current point/progress along its current path within the current zone.

Introduction

It is usually unlikely that a world model lies entirely on-screen; consequently, not all polygons for that world will need to be rendered by the GPU. Polygons must be rendered in a back-to-front order-that is, the painter's algorithm can be applied directly to some 'depth sorted' list of to-be-rendered polygons. Polygons cannot be rendered in their order from the Type 3 entry; they are not depth-sorted and therefore would fail at the painter's algorithm. Furthermore the polygons that lie off-screen would still undergo transformation by the GTE and rendering by the GPU only to not appear at all-which is a waste of graphical computation time. A list known as the current polygon list then determines the back-to-front ordering of polygons, listed by Polygon ID. (during a level update, decoding of Sort Lists reorders/rebuilds the current polygon list according to camera progress)

During world model primitive creation and transformation, for each polygon ID in the current polygon list from the end to the beginning, a representative 3-point polygon primitive is generated using the vertex data for the polygon with that ID, in one of the 8 current zone world models, and transformed accordingly; for each primitive created, its tag field is pointed to the representative primitive for the previous polygon [ID] in the list (when it is created). This creates a linked list of primitives starting with that created for the last polygon and ending with that created for the first. Since the polygon list sorts IDs by depth of their corresponding polygons, the primitive linked list sorts their corresponding primitives [by depth] from back to front. During the rendering stage, the GPU then steps through this list, rendering each polygon primitive in the appropriately specified order from back to front.

Primitives generated for worlds are POLY_G3 and/or POLY_GT3 structures of the PSX Basic Graphics Run-time library. Several fields from the associated polygon's vertex data are extracted, manipulated, and rearranged before they finally occupy the various fields of the polygon's POLY_G3 or POLY_GT3 primitive.

Format

Crash 1

Item 1: Header

Offset Field Size Value
0x0 X Location 4 bytes *
0x4 Y Location 4 bytes *
0x8 Z Location 4 bytes *
0xC Polygon count 4 bytes *
0x10 Vertice count 4 bytes *
0x14 Texture info structures 4 bytes *
0x18 Texture Page Count 4 bytes t
0x1C Translate Flag

v=0 Indicates a "Backdrop"

4 bytes *
0x20 Texture Page EIDs 8 x 4 bytes *
0x40 Texture Info Array * x 4 bytes *

Data in the Texture Info Array is consisted of either 4 and/or 8 byte structures with the following formats:

Format A: 0******* RRRRRRRR GGGGGGGG BBBBBBBB

Format B: 1SS0HHHH RRRRRRRR GGGGGGGG BBBBBBBB DDDDDDDD DDMMLLXX XXXZZZZZ ZZ0YYYYY

  • S = Semi-Transparency Mode
  • M = Color Mode 
  • L = Texture Page 128/256 pixel region X index
  • X = Texture X offset
  • Y = Texture Y offset
  • D = Texture Region Index
  • Z = Primary CLUT ID 
  • H = Secondary CLUT ID
  • R = Red Value?
  • G = Green Value?
  • B = Blue Value?
  1. A structure of format A describes optional color information (unconfirmed) for a polygon that will be converted to a non-textured primitive.
  2. A structure of format B describes texture information for a polygon that will be converted to a textured/semi-textured primitive (explained in detail below).

Each polygon (see below) specifies an offset into the texture info array of the structure that describes a specific region of pixel data [in some texture page] that maps to it (or to describe no texture data at all). The texture page EIDs refer to 8 different texture pages that can be used as sources for texture data. A polygon will refer to one of these 8 EIDs as the source texture page from which to grab the pixel data.

Item 2: Polygons

Offset Field Size Value
0x0 Polygons * x 8 bytes *

This item contains a number of 8 byte structures, each of which describes an individual polygon (a 3 point triangle) in the world, by the 3 separate vertices that it consists of and with information about texture that maps to it.

Each structure has the form:

CCCCCCCC CCCCTTTT TTTTTTTT EEEPPPPP AAAAAAAA AAAABBBB BBBBBBBB VVVWWWWI

  • A = Index of Vertex A in Item 3: Vertices
  • B = Index of Vertex B in Item 3: Vertices
  • C = Index of Vertex C in Item 3: Vertices
  • E = Index of one of 8 texture page EIDs in Item 1: Header
  • T = Texture Info index, into Texture Info Array of Item 1: Header
  • P, V, W = determine an additional offset to the index into the Texture Info Array (for animated textures)
  • I = ignored?

Item 3: Vertices

Offset Field Size Value
0x0 Vertices * x 8 bytes *

This item contains a number of 8 byte structures, each of which describes a single vertex of a polygon (which may or may not be shared by more than one polygon):

ZZZZZZZZ RRRRRRRR GGGGGGGG BBBBBBBB XXXXXXXX XXXXXSSS YYYYYYYY YYYYYNNI

  • X = Vertex X Position
  • Y = Vertex Y Position
  • Z = Vertex Z Position
  • S = Vertex Sub-section (also determines z position)
  • N = Vertex Section (also determines z position)
  • R = Vertex Red Value (for gouraud shading)
  • G = Vertex Green Value (for gouraud shading)
  • B = Vertex Blue Value (for gouraud shading)
  • I = Vertex Shader/Effect Flag

Primitive Creation

A general outline of the primitive creation loop for world models:

  1. Grab next polygon referred to by the current polygon list from 1 of 8 worlds in the current zone
  2. Set GTE translation vector to that of the world's (if the world is different than that grabbed from in the last iteration)
  3. Perspective transform the 3D polygon vertex coords with GTE; (resulting X, Y will be used as 2D on-screen coordinates for the primitive's vertices)
  4. Grab vertex colors (from each vertex of the polygon) for gouraud shading
  5. Determine the type (textured, semi-textured, non-textured) and specifics of primitive to create based on polygon's associated texture information
  6. Create the gouraud-shaded primitive with the transformed coordinates, vertex colors, and texture information
  7. Grab the resulting Z coordinates from the perspective transformation and calculate their average
  8. Place a pointer to the primitive at its respective location in the ordering table (OT); if it replaces an already existing primitive [pointer] at that location in the OT, link this primitive to the replaced primitive

This happens for each frame; primitives from previous frame are overwritten.

Extracting Texture Information

For a single polygon, texture information is distributed among the bits of 3 separate fields:

1. Texture chunk index/palette

This field is resolved by processing/lookup of the texture page EID specified for the polygon. A polygon specifies a texture page EID by its index within the [array of 8] Texture Page EIDs in the world's header item (Item 1). (E bits)

00000000 0000RRRR RRRRRRPP Y??1XX??

2. Texture information

A polygon specifies texture information by its index within the Texture Info Array of the world's header item (Item 1). (T bits)

KSS0HHHH 00000000 00000000 00000000 DDDDDDDD DDMMLLXX XXXZZZZZ ZZ0YYYYY

3. Texture region

A polygon's texture information specifies its texture's region by its index within the [game's] global constant regions array.

XXXXXXXX YYYYYYYY XXXXXXXX YYYYYYYY XXXXXXXX YYYYYYYY XXXXXXXX YYYYYYYY
     vertex A          vertex B          vertex C          vertex D

From these various sources, texture information is extracted, manipulated, and rearranged before it is finally recorded in the texture-related fields of the polygon's POLY_GT3 primitive. These fields include the tpage, u0, v0, u0, v1, u2, v2, and clut fields.

PSX GPU Framebuffer

The Playstation GPU has 1MB of VRAM. Interpreted as an array of 16 bit pixels, the entire 1MB region of VRAM is a surface of 1024x512 resolution. In the Crash games, the upper left 512x256 quadrant contains the on-screen display buffer/pixel data while the upper right 512x256 quadrant contains the off-screen draw buffer/pixel data. The lower 1024x256 half is consisted of several texture pages; together, all texture pages are consisted of all texture data loaded into VRAM. A single textured polygon primitive specifies a 2-dimensional image of pixels, or texture, that is mapped to its surface when rendered. A polygon primitive specifies its texture as the 2-dimensional area, within a specific texture page, that contains the texture image/pattern.

For texture pages, VRAM is also alternatively interpreted as an array of either 2048x512 8 bit pixels or 4096x512 4 bit pixels. The pixel data in a texture page can include either 16 bit pixels, 8 bit pixels, or 4 bit pixels; some portions of a texture page may specify 4 bit pixels while the others may specify 8 or 16 bit pixels. A polygon primitive specifies the color mode for its texture as either mode 0 = 4 bits, mode 1 = 8 bits, or mode 2 = 16 bits; this means that the region of pixels that it specifies is consisted of either 4 bit, 8 bit, or 16 bit pixels.

In 16, 8, and 4 bit color modes, respectively, a texture page is a surface of 64x256, 128x256, and 256x256 pixels. The pixel data contained by a texture page does not differ with color mode-the same texture page interpreted as 4 bit pixels is interpreted as 8 or 16 bit pixels. In any color mode, only the regions of pixels of that color mode will be interpreted properly. For example, if the contents of a texture page are 'viewed' in 8 bit color mode, the 8 bit pixel regions will display properly while the 4 bit pixel regions will typically appear twice as wide as they should, with an incorrect palette, and interlaced with strangely colored lines. There are a total of 16 [horizontally contiguous] texture pages in the lower half of VRAM-that is, a single row with 16 columns of texture pages.

16 bit pixels have the following format:

SBBBBBGGGGGRRRRR
  • R = red value
  • G = green value
  • B = blue value
  • S = semi-transparency flag

16 bit pixels are raw pixels. The R, G, and B fields in a 16 bit pixel refer directly to the respective red, green, and blue brightnesses of the color.

8 bit and 4 bit pixels are instead specified as an index into a particular table of 256 or 16 colors, known as the CLUT or color lookup table; an 8 or 4 bit pixel's actual color value is thus located at its specified index in the table. CLUTs are specified in the texture pages themselves-that is, if the texture pages are viewed in 16 bit color mode, several lines of either 256 pixels (stacked vertically) or 16 pixels (can stack horizontally and vertically) with a seemingly random distribution of color may appear [typically at the top] along with the rest of the texture images. The data for such a line of pixels is actually just [the 256 or 16 16-bit colors of] a CLUT in the texture page. A polygon primitive will then specify the CLUT to use for the pixels in its [texture's] [either 4 or 8 bit pixel] region of the texture page.

NSF files store the pixel data for texture pages in texture chunks, with resolutions of 512x128 in 8 bit/1024x128 in 4 bit. The space occupied by a texture chunk takes up either the entire top or bottom half of 4 horizontally consecutive texture pages in VRAM. (512x128 / 128x256 = 4 x 1/2) 4x2 texture chunks will thus fill the texture pages in their entirety. (16x1 / 4x1/2 = 4x2). The game will page up to 8 texture chunks from an NSF file and copy their data in sequence to fill the entire bottom half/all texture pages in VRAM.

It must also be noted that what the game refers to as texture pages are actually the 4x2 texture chunks in the bottom half of VRAM, and not what the GPU views as the 16 horizontally contiguous 64/128/256x256 texture pages that hold their content. In the format section, texture page EID refers to the ID for a texture page information 'entry', texture page in this context referring to one of the 4x2 texture chunks in the bottom of VRAM. From here on, texture page will refer to one of the 16 horizontally contiguous 64/128/256x256 GPU texture pages.

Texture Page

The tpage field of a POLY_GT3 primitive specifies the texture page which contains (among other textures) the source texture for the polygon. It also specifies the color mode, and semi-transparency mode, of pixels in that texture.

Source
Texture Information Field
KSS0HHHH 00000000 00000000 00000000 DDDDDDDD DDMMLLXX XXXZZZZZ ZZ0YYYYY
  • L = 128/256 pixel region X index

The top/bottom halves of 4 [horizontally contiguous] texture pages in VRAM occupy the polygon's source texture chunk. A polygon's texture information field specifies which 1 of these 4 texture pages contains its source texture-that is, which 128x128 pixel (8 bit)/256x128 pixel (4 bit) region of the source texture chunk contains the source texture.

  • M = Color Mode (0 = 4 bit, 1 = 8 bit, 2 = 16 bi)
  • S = Semi-Transparency Mode

A polygon's texture information field also specifies the color mode and semi-transparency mode of pixels in the source texture.

Texture Chunk Index/Palette
00000000 0000RRRR RRRRRRPP Y??1XX??
  • X = Texture Chunk X Index

A polygon's texture chunk index/palette field specifies the X index of its source texture chunk in VRAM.

Note: The preceding 1 before XX is also copied to its corresponding bit in the texpage field. (Not confirmed that this is always 1 but it should be.)

Destination

The tpage field of a POLY_GT3 primitive has the following format:

0000000M MSSYXXXX
  • X = Texture Page Index (**X Base)
  • Y = Indicates the half of VRAM in which texture pages reside (0 = upper, 1 = lower) (**Y Base)
  • S = Semi-Transparency Mode
  • M = Color Mode

Texture Pages reside in the lower half of VRAM in the Crash games, so Y=1. Each texture chunk horizontally spans 4 texture pages of VRAM. Given the X index of a chunk, and the index among its 4 containing texture pages, the total texture page index is computed by:

(chunkx*4)+index    or    (chunkx << 2) | index

Thus, the complete extraction of bitfields:

KSS0HHHH 00000000 00000000 00000000 DDDDDDDD DDMMLLXX XXXZZZZZ ZZ0YYYYY
00000000 0000RRRR RRRRRRPP Y??1XX??
              |
              V
       0000000M MSS1XXLL
tpage: 0000000M MSSYXXXX

tpage.X = (X << 2) | L
tpage.Y = 1
tpage.S = S
tpage.M = M

Texture coordinates

The u0, v0, u1, v1, u2, and v2 fields of a POLY_GT3 primitive specify the texture coordinates of the polygon's source texture (relative to the texture page that contains it [the source texture]).

Note that a texture page will contain 1/4 of a texture chunk in its/the upper half [of the lower half of VRAM], and 1/4 of the texture chunk below the chunk in the upper half-in its/the lower half [of the lower half of VRAM]. Thus, some additional information from the Texture Chunk Index/Palette field-particularly, the Y index of the desired source chunk and thus whether the source texture lies within the upper half (with 1/4th of the upper chunk) or the lower half (with 1/4th of the lower chunk) of the texture page-is needed for factoring into texture [Y] coordinates.

Source
Texture Information
KSS0HHHH 00000000 00000000 00000000 DDDDDDDD DDMMLLXX XXXZZZZZ ZZ0YYYYY
  • X = Texture X Offset (8 bit mode: mult of 4; 4 bit mode: mult of 8)
  • Y = Texture Y Offset (mult of 4)

A polygon's texture information field specifies the X,Y coordinate of the upper left point of a particular rectangular region of VRAM relative to [i.e. within] the source texture page, in terms of 8x4 pixel units for 4 bit mode source textures and 4x4 pixel units for 8 bit mode source textures. A triangular half of this rectangular region determines the actual source texture mapped to the polygon.

Texture Chunk Index/Palette
00000000 0000RRRR RRRRRRPP Y??1XX??
  • Y = Texture Chunk Y Index

A polygon's texture chunk index/palette field specifies the Y index of its source texture chunk in VRAM. There are only 2 rows of texture chunks, so this value is either 0 = top row, or 1 = bottom row. Equivalently this indicates whether the top or bottom halves of the 4 [horizontally contiguous] texture pages in VRAM occupy the polygon's source texture chunk.

Texture region
XXXXXXXX YYYYYYYY XXXXXXXX YYYYYYYY XXXXXXXX YYYYYYYY XXXXXXXX YYYYYYY
     point A           point B           point C           point D

A polygon's texture region determines the triangular region relative to Texture X and Y Offsets [within the containing texture page] of the actual source texture mapped to the polygon. As mentioned previously, a polygon's texture information specifies its texture's region by its index within the [game's] global constant regions array. The regions array contains 600 x 4 point 2D quads; each point is 2 bytes in length, with the first and second bytes corresponding to its X and Y coordinates, respectively. Quads in the regions array are indexed by several different attributes:

  • width = (index % 5)
  • height = ((index / 5) % 5)
  • winding = (index / 25) % 6
  • flip = (index / 150)
Value Field
Flip Winding Width Height
0
 C
   |\
   | \
 A |--\ B
ABC 4 4
1
       C 
    /|   
   / |   
A /--| B 
ACB 8 8
2
C      B
  \--|  
   \ |  
    \| A
BCA 16 16
3
 B     C
   |--/
   | /
 A |/
BAC 32 32
4 n/a CAB 64 64
5 n/a CBA n/a n/a
actual width = 2 ^ (2 + (index % 5));
actual height = 2 ^ (2 + ((index / 5) % 5));

(Note that width and height do not depend on color mode)

Only the first 3 points of a quad determine the 3 points of the triangular region relative to Texture X and Y Offsets [within the containing texture page] of the the source texture. (The last point is used for quad primitives, created elsewhere for object sprites, fragments, and etc.) Each of the 3 points defines the relative U,V coordinates of its respective vertex in the polygon primitive.

Quads have been pre-computed such that they have the attributes described by their indices. For example, the quad at index 48 has the following attributes:

actual width = 2 ^ (2 + (48 % 5)) = 32
actual height = 2 ^ (2 + ((48 / 5) % 5)) = 32
winding = (48 / 25) % 6 = 1
flip = (48 / 150) = 0

Thus, its first 3 points are the respective A, C, and B vertices (winding 1 = ACB) of a 2D right triangle with width 32, height 32, and orientation as shown for flip = 0. The first 3 points of the quad at that index are then (0, 0), (0, 32), (32, 0). For a polygon that specifies an index of 48 in its texture information for its texture region, these 3 points would define the relative U,V texture coordinates for the respective vertices in its primitive.

Destination

For each vertex v in {0,1,2}, the uv and vv fields of a POLY_GT3 primitive are both a byte in length and should simply specify the U,V (i.e. X,Y) texture coordinates (in pixels) for that vertex, relative to the source texture page.

In calculating the texture coordinates, the Texture X and Y offsets (and Color Mode*) are first extracted from Texture Information:

KSS0HHHH 00000000 00000000 00000000 DDDDDDDD DDMMLLXX XXXZZZZZ ZZ0YYYYY

And then the Texture Chunk Y Index from Texture Chunk Index/Palette :

00000000 0000RRRR RRRRRRPP y001xx00

And finally the points from the Texture Region:

XXXXXXXX YYYYYYYY XXXXXXXX YYYYYYYY XXXXXXXX YYYYYYYY XXXXXXXX YYYYYYYY
     point A           point B           point C           point D   

(Point D is unused by world polygons, since they are only 3 point triangles)

Since each point of the triangular texture region is relative to either the top or bottom [quarter of the] chunk within the source texture page, and additionally the Texture X and Y Offsets within [that quarter of the chunk within] the source texture page, the total texture coordinates are then calculated separately for each point. Since a texture chunk is 128 pixels in height, and since the Texture X and Y Offsets are given in terms of 8x4 pixels for Color Mode = 0 (4 bit mode) and 4x4 pixels for Color Mode = 1 (8 bit mode), then the following computes the location within the source texture page that the texture region points are given relative to:

tx = ((X * 8) >> M)
ty = ((128 * y) + (Y * 4))

Each texture region point is added to (tx, ty) to get its location within the source texture page, and equivalently the U, V texture coordinates for its corresponding vertex in the polygon primitive. Since the max size of a texture page is 256x256, i.e. for when interpreted in 4 bit mode, the range of UV coordinates is restricted to (0,0)-(255,255). Further, the texture images/patterns in a texture page are aligned only to multiples of their widths and heights. A logical or, rather than an addition, of the region point(s) and (tx, ty) will thus result in the same value, but only if tx and ty respectively are multiples of the width and height of the texture region.

  XXXXXXXX       (rxv)
| XXXXX000 >> MM (txv)
----------
   xxxxxxxx (uv)
  YYYYYYYY (ryv)
| yYYYYY00 (tyv)
----------
   yyyyyyyy (vv)

CLUT coordinates

The clut field of a POLY_GT3 primitive specifies the coordinates of the CLUT [for the source texture pixels], within the source texture page. As previously explained, the primitive's CLUT specifies the 256 (8-bit mode) or 16 (4-bit mode) color palette used by pixels of its source texture, in 8 bit mode or 4 bit mode. CLUTs are arranged in narrow and long form horizontally in texture pages, 256 x 1 (8-bit mode) or 16 x 1 (4-bit mode).

The CLUTs are typically included at the top of texture chunks, such that several 512 pixel (8-bit mode)/1024 pixel (4-bit mode) horizontal lines may stack at the top n lines (where n is typically < 16) of 4 horizontally consecutive texture pages, and several 512 pixel (8-bit mode)/1024 pixel (4-bit mode) horizontal lines may stack at the top n lines in the bottom half of the same 4 texture pages. Also, some of these lines might actually instead be groups of 16 [or less] 32 pixel (8-bit mode)/64 pixel (4-bit mode) horizontally consecutive lines. Each of these lines is a CLUT, and viewed in 16-bit mode, is a horizontal line of either 256 pixels (in a line) or a horizontal line of 16 pixels (in a group of 16). Each consecutive pixel in a CLUT line has the color at its corresponding index in that CLUT ['s palette]. In 16-bit mode, texture chunks are 256x128 pixels.

The primitive's clut field specifies, and thus the GPU processes, the CLUT coordinates as an absolute location in terms of 16 x 1 pixel lines-that is, a CLUT location of (x, y) is actually the absolute location (16x, y) in VRAM. As an absolute location, unlike texture coordinates, it is not specified in relation to the source texture page.

Source
Texture Information
KSS0HHHH 00000000 00000000 00000000 DDDDDDDD DDMMLLXX XXXZZZZZ ZZ0YYYYY
  • Z = primary CLUT ID (VRAM Y location)

A polygon's Texture Information field specifies the primary ID of the CLUT to use for its 8-bit or 4-bit mode texture. Since 256 color CLUTs are stacked from the top of the source texture chunk, each CLUT is at its own line in VRAM and thus has a unique Y. Therefore, each of the chunk's CLUTs is identified by its Y location in VRAM.

  • H = secondary CLUT ID (for 16 color/4-bit mode)

A polygon's Texture Information Field also specifies the secondary ID of the CLUT to use for its 4-bit mode texture. Since any 256 color CLUT can also be a group of 16 horizontally consecutive 16 color CLUTs, the primary CLUT ID specifies the group, and the secondary CLUT ID specifies the index of the 16 color CLUT among the 16 within that group. Thus, a CLUT with given primary ID and/or secondary ID has the following location, relative to the source texture chunk, in VRAM:

X = H*16
Y = Z
Texture Chunk Index/Palette
00000000 0000RRRR RRRRRRPP Y??1XX??
  • P = Texture Chunk CLUTs X location (mult by 256)
  • R = Texture Chunk CLUTs Y location

A polygon's Texture Chunk Index/Palette field specifies the X (multiplied by 256) and Y location of the source texture chunk's CLUTs in VRAM. Since the CLUTs are located at the top of a Texture Chunk, they are positioned relative to its [upper-left] location. Thus, the X location, ultimately multiplied by 256, should actually just be the X index of the texture chunk in VRAM. The Y location should then be either 512 if the source chunk is in the upper half of the lower half of VRAM, or 768 if it is in the lower half of the lower half of VRAM (although the field is open to specify any Y, values other than these would not make sense.)

Destination

The clut field of a POLY_GT3 primitive has the following format:

0YYYYYYY YYXXXXXX
  • X = CLUT X location / 16 (in VRAM) [XXXXXX is multiplied by 16 to get total X location]
  • Y = CLUT Y location (in VRAM)

In calculating clut for the primitive, the primary and secondary CLUT IDs are first extracted from Texture Information:

KSS0HHHH 00000000 00000000 00000000 DDDDDDDD DDMMLLGG GGGZZZZZ ZZ0XXXXX

And finally the Texture Chunk CLUT X and Y locations from Texture Chunk Index/Palette (P, R):

00000000 0000RRRR RRRRRRPP Y??1XX00

Recall that a CLUT with given primary ID and/or secondary ID has the following location, relative to the source texture chunk, in VRAM:

X = H*16
Y = Z

This location is specified relative to the source texture Chunk's [CLUT] location; the Chunk [CLUTs] X Location specified by the Texture Chunk Index field (P) must first be multiplied by 256 for its actual value. The total CLUT location is then:

X = (P*256) + (H*16)
Y = R + Z

However, CLUT X location is specified in the clut field as its actual value divided by 16, so the total CLUT location (as specified by the clut field) is:

CLUT x = X/16 = (P*16) + H
CLUT y = Y = R + Z

When the game computes CLUT Y, R is logically or'ed with Z rather than added; if both operations were to always yield the same results, this implies that only the upper 2 bits of R have the option to be set. R's MSB adds nothing when clear and 512 when set, so it specifies either the top or bottom half of VRAM. Since the Texture Pages and therefore the CLUTs are located in the bottom half of VRAM, then R's MSB should always be set. Bit 9 of R adds nothing when clear and 256 when set, so it specifies whether the CLUT is located [relative to the top of its chunk] in either the top or bottom half of the bottom half (texture page portion) of VRAM. Note that, under these implications, Bit 14 in the final result for clut is always clear, which then further implies that CLUTs can only be located in the upper halves of texture chunks.

Thus, the complete extraction of bitfields:

KSS0HHHH 00000000 00000000 00000000 DDDDDDDD DDMMLLGG GGGZZZZZ ZZ0XXXXX 
00000000 0000RRRR RRRRRRPP Y??1XX00
          |
          V
   000ZZZZZ ZZPPHHHH    
 | RRRRRRRR RR000000  or if R = 1Y00000000: 1Y0ZZZZZ ZZPPHHHH
 -------------------                        -----------------
   YYYYYYYY YYXXXXXX                        YYYYYYYY YYXXXXXX