Colour Cube
ColourCube resources are used by both the EnvironmentSettings and PostFX to change the colour and tone of the world.
A ColourCube is a set of 32 32x32 textures forming a CLUT, which is usually colour corrected to give a different art style to the game at a given time (i.e., the red filter when wrecking a vehicle in versions 1.0-1.3 of Burnout Paradise).
Some time after the February 22, 2007 build of Paradise, ColourCubes were added to the EnvironmentSettings folder and were used specifically to give the game a unique art style.
In the 1.4 update to Burnout Paradise, the ColourCubes were changed to a standard CLUT, possibly due to the extended time cycle conflicting with the ColourCube's art style. In the 1.6 update, these were again updated to use a default RGB CLUT.
Layout
32-bit
Offset | Length | Type | Name | Description | Comments |
---|---|---|---|---|---|
0x0 | 0x4 | uint32_t | m_size | Either the number of textures or the width/height. | |
0x4 | 0x4 | uint8_t* | m_pixels | Pointer to the texture data. |
64-bit
Offset | Length | Type | Name | Description | Comments |
---|---|---|---|---|---|
0x0 | 0x4 | uint32_t | m_size | Either the number of textures or the width/height. | |
0x8 | 0x8 | uint8_t* | m_pixels | Pointer to the texture data. |
Data
In Burnout Paradise: The Ultimate Box on PC and Burnout Paradise Remastered on PC and PS4, data is in a standard RGB24 format (that is, each pixel takes up 3 bytes, one for each color). Textures in the PS3, Xbox 360, and Switch versions of the game are also RGB24, but swizzled. There is a functional implementation of an Xbox 360 to PC texture converter on GitHub.
Xbox 360 Swizzle Algorithm
The following algorithm assumes that the data is stored and accessed as m_size cubes of size 32, each m_size*m_size pixels, oriented left to right with an m_size*m_size*3 bytes stride, rather than as m_size cubes oriented top to bottom with a m_size*3 bytes stride (i.e. only one cube's data per line). Regardless of which is true, it seems that the following algorithm works to produce exact conversions from Xbox 360 colourcubes to PC colourcubes. Smaller cubes, like those from NFS:HP will likely need a different algorithm for calculating the offsets.
With the above in mind, to find the 3-byte (R, G and B) pixel data for position (x,y,z) in the PC m_pixels data, 3 bytes (R, G and B) can be read from the Xbox 360 m_pixels data at the offset calculated as follows where x, y and z are represented as a number of bits, x0 to x4, y0 to y4 and z0 to z4 (all values between 0 and m_size).
x | y | z | offset |
---|---|---|---|
xxxxx
43210 |
yyyyy
43210 |
zzzzz
43210 |
o0=x0
o1=x1
o2=y0
o3=x2
o4=x3
o5=x4^y3^z2
o6=y1
o7=y2
o8=z0
o9=y3^z2
o10=z1
o11=y4
o12=z2
o13=z3
o14=z4 |
Example Ruby implementation:
class Fixnum
# calculates the number of bytes
def pixels
self * 3
end
end
# calculate offset, in pixels, of where to find the (x,y,z) pixel in the Xbox 360 data
# pixel offset in PC file is m_size * m_size * z + m_size * y + x
def calc_offset(x, y, z)
x0 = (x >> 0) & 0b1
x1 = (x >> 1) & 0b1
x2 = (x >> 2) & 0b1
x3 = (x >> 3) & 0b1
x4 = (x >> 4) & 0b1
y0 = (y >> 0) & 0b1
y1 = (y >> 1) & 0b1
y2 = (y >> 2) & 0b1
y3 = (y >> 3) & 0b1
y4 = (y >> 4) & 0b1
z0 = (z >> 0) & 0b1
z1 = (z >> 1) & 0b1
z2 = (z >> 2) & 0b1
z3 = (z >> 3) & 0b1
z4 = (z >> 4) & 0b1
o=(z4<<14)|
(z3<<13)|
(z2<<12)|
(y4<<11)|
(z1<<10)|
((z2<<9)^(y3<<9))|
(z0<<8)|
(y2<<7)|
(y1<<6)|
((z2<<5)^(y3<<5)^(x4<<5))|
(x3<<4)|
(x2<<3)|
(y0<<2)|
(x1<<1)|
(x0<<0)
end
# read m_size and m_pixels data from Xbox 360 file
# ...
# now, convert the m_pixels data
data="".b
m_size.times do |z|
m_size.times do |y|
m_size.times do |x|
offset = calc_offset(x, y, z)
pixel_data = m_pixels[offset.pixels...(offset + 1).pixels]
data << pixel_data
end
end
end
# write data to file
# ...