Colour Cube: Difference between revisions
mNo edit summary |
m (Changed ^3 to ³ to avoid confusion with bitwise XOR.) |
||
(13 intermediate revisions by 4 users not shown) | |||
Line 1: | Line 1: | ||
{{ParadiseResourceTypeInfobox |
|||
ColourCube resources are used by both the [[EnvironmentSettings]] and [[PostFX]] to change the colour and tone of the world. |
|||
| name = ColourCube |
|||
| othernames = RwColourCube |
|||
| example = [[File:Paradise_ColourCubes.png|frameless|200px]]<br />ColourCubes used in Burnout Paradise. |
|||
| id = 0x2B |
|||
| category = Generic |
|||
| memdist = Main Memory only |
|||
| importedby = [[Environment Keyframe]] |
|||
}} |
|||
ColourCube resources are used by both the [[EnvironmentSettings]] and [[PostFX]] to change the colour and tone of the world. |
|||
[[File:Paradise_ColourCubes.png|thumb|200px|ColourCubes used in Burnout Paradise.]] |
|||
A ColourCube is a set of |
A ColourCube is a set of textures forming a [https://en.wikipedia.org/wiki/Palette_(computing) CLUT], which is usually colour corrected to give a different art style to the game at a given time (e.g., the red filter when wrecking a vehicle in versions 1.0-1.3 of ''Burnout Paradise''). |
||
Some time after the [[ |
Some time after the [[Burnout 5 (2007-02-22 build)|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. |
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. |
||
= |
= Structures = |
||
=== rw::graphics::postfx::ColourCube === |
|||
=== 32-bit === |
|||
==== 32-bit ==== |
|||
{| class="wikitable" |
{| class="wikitable" |
||
|- |
|||
! Offset !! Length !! Type !! Name !! Description !! Comments |
! Offset !! Length !! Type !! Name !! Description !! Comments |
||
|- |
|- |
||
| 0x0 || 0x4 || uint32_t || m_size || |
| 0x0 || 0x4 || uint32_t || m_size || The number of textures and their width/height. || Used to calculate file size (m_size<sup><small>3</small></sup> * 3 + 16) |
||
|- |
|- |
||
| 0x4 || 0x4 || uint8_t* || m_pixels || Pointer to the texture data. || |
| 0x4 || 0x4 || uint8_t* || m_pixels || Pointer to the texture data. || |
||
|} |
|} |
||
=== 64-bit === |
|||
==== 64-bit ==== |
|||
{| class="wikitable" |
{| class="wikitable" |
||
|- |
|||
! Offset !! Length !! Type !! Name !! Description !! Comments |
! Offset !! Length !! Type !! Name !! Description !! Comments |
||
|- |
|- |
||
| 0x0 || 0x4 || uint32_t || m_size || |
| 0x0 || 0x4 || uint32_t || m_size || The number of textures and their width/height. || Used to calculate file size (m_size<sup><small>3</small></sup> * 3 + 16) |
||
|- |
|||
| 0x4 || 0x4 || || Padding || || |
|||
|- |
|- |
||
| 0x8 || 0x8 || uint8_t* || m_pixels || Pointer to the texture data. || |
| 0x8 || 0x8 || uint8_t* || m_pixels || Pointer to the texture data. || |
||
Line 30: | Line 40: | ||
= 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 [https://github.com/burninrubber0/ColourCube_Converter on GitHub]. |
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 [https://github.com/burninrubber0/ColourCube_Converter on GitHub]. |
||
== Xbox 360 Swizzle Algorithm == |
== Xbox 360 Swizzle Algorithm == |
||
The following algorithm assumes that the data is stored |
The following algorithm assumes that the data is stored as a cube of size m_size*m_size*m_size pixels, accessed according to a certain algorithm. The algorithm is different for ''Burnout Paradise'' 32*32*32 cubes and ''Need for Speed: Hot Pursuit'' 16*16*16 cubes. |
||
To find the 3 bytes (R, G and B) of 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 - 1). |
|||
{| class="wikitable" |
{| class="wikitable" |
||
! x !! y !! z !! offset (m_size = 16) |
|||
|- |
|||
! x !! y !! offset |
|||
|- style="vertical-align:top;" |
|- style="vertical-align:top;" |
||
| <pre>xxxx |
|||
| <syntaxhighlight>xxxxxxxxxx |
|||
3210</pre> || <pre>yyyy |
|||
9876543210</syntaxhighlight> || <syntaxhighlight>yyyyy |
|||
3210</pre> || <pre>zzzz |
|||
43210</syntaxhighlight> || <syntaxhighlight>o0=x0 |
|||
3210</pre> || <pre>o0=x0 |
|||
o1=x1 |
o1=x1 |
||
o2= |
o2=y0 |
||
o3=x2 |
o3=x2 |
||
o4=x3 |
o4=x3 |
||
o5= |
o5=y1 |
||
o6= |
o6=y2 |
||
o7= |
o7=z0 |
||
o8= |
o8=y3^z2 |
||
o9= |
o9=z1 |
||
o10= |
o10=z2 |
||
o11= |
o11=z3</pre> |
||
|} |
|||
o12=y2 |
|||
o13=y3 |
|||
{| class="wikitable" |
|||
o14=y4</syntaxhighlight> |
|||
! x !! y !! z !! offset (m_size = 32) |
|||
|- style="vertical-align:top;" |
|||
| <pre>xxxxx |
|||
43210</pre> || <pre>yyyyy |
|||
43210</pre> || <pre>zzzzz |
|||
43210</pre> || <pre>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</pre> |
|||
|} |
|} |
||
Line 69: | Line 99: | ||
end |
end |
||
# calculate offset, in pixels, of where to find the (x,y) pixel in the Xbox 360 data |
# 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) |
|||
def calc_offset(m_size, x, y, z) |
|||
case m_size |
|||
when 16 |
|||
calc_offset16(x, y, z) |
|||
when 32 |
|||
calc_offset32(x, y, z) |
|||
else |
|||
raise "Unsupported m_size: #{m_size}" |
|||
end |
|||
end |
|||
def calc_offset16(x, y, z) |
|||
x0 = (x >> 0) & 0b1 |
|||
x1 = (x >> 1) & 0b1 |
|||
x2 = (x >> 2) & 0b1 |
|||
x3 = (x >> 3) & 0b1 |
|||
y0 = (y >> 0) & 0b1 |
|||
y1 = (y >> 1) & 0b1 |
|||
y2 = (y >> 2) & 0b1 |
|||
y3 = (y >> 3) & 0b1 |
|||
z0 = (z >> 0) & 0b1 |
|||
z1 = (z >> 1) & 0b1 |
|||
z2 = (z >> 2) & 0b1 |
|||
z3 = (z >> 3) & 0b1 |
|||
o=(z3<<11)| |
|||
(z2<<10)| |
|||
(z1<<9)| |
|||
((y3<<8)^(z2<<8))| |
|||
(z0<<7)| |
|||
(y2<<6)| |
|||
(y1<<5)| |
|||
(x3<<4)| |
|||
(x2<<3)| |
|||
(y0<<2)| |
|||
(x1<<1)| |
|||
(x0<<0) |
|||
end |
|||
def calc_offset32(x, y, z) |
|||
x0 = (x >> 0) & 0b1 |
x0 = (x >> 0) & 0b1 |
||
x1 = (x >> 1) & 0b1 |
x1 = (x >> 1) & 0b1 |
||
Line 76: | Line 146: | ||
x3 = (x >> 3) & 0b1 |
x3 = (x >> 3) & 0b1 |
||
x4 = (x >> 4) & 0b1 |
x4 = (x >> 4) & 0b1 |
||
x5 = (x >> 5) & 0b1 |
|||
x6 = (x >> 6) & 0b1 |
|||
x7 = (x >> 7) & 0b1 |
|||
x8 = (x >> 8) & 0b1 |
|||
x9 = (x >> 9) & 0b1 |
|||
y0 = (y >> 0) & 0b1 |
y0 = (y >> 0) & 0b1 |
||
y1 = (y >> 1) & 0b1 |
y1 = (y >> 1) & 0b1 |
||
Line 86: | Line 151: | ||
y3 = (y >> 3) & 0b1 |
y3 = (y >> 3) & 0b1 |
||
y4 = (y >> 4) & 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=( |
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)| |
(x3<<4)| |
||
(x2<<3)| |
(x2<<3)| |
||
( |
(y0<<2)| |
||
(x1<<1)| |
(x1<<1)| |
||
(x0<<0) |
(x0<<0) |
||
Line 109: | Line 179: | ||
# now, convert the m_pixels data |
# now, convert the m_pixels data |
||
data="".b |
data="".b |
||
m_size.times do | |
m_size.times do |z| |
||
m_size.times do |y| |
|||
m_size.times do |x| |
|||
offset = calc_offset(x, y) |
|||
offset = calc_offset(x, y, z) |
|||
pixel_data = m_pixels[offset.pixels...(offset + 1).pixels] |
|||
data << pixel_data |
|||
end |
|||
end |
end |
||
end |
end |
||
# write data to file |
# write "converted to PC" data to file |
||
# ... |
# ... |
||
</syntaxhighlight> |
</syntaxhighlight> |
Latest revision as of 09:03, 1 November 2023
ColourCube | |||
---|---|---|---|
aka RwColourCube | |||
ColourCubes used in Burnout Paradise. | |||
Type ID | 0x2B | ||
Category | Generic | ||
Memory distribution |
Main Memory only | ||
Imported by | Environment Keyframe | ||
Editor available? |
No |
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 textures forming a CLUT, which is usually colour corrected to give a different art style to the game at a given time (e.g., 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.
Structures
rw::graphics::postfx::ColourCube
32-bit
Offset | Length | Type | Name | Description | Comments |
---|---|---|---|---|---|
0x0 | 0x4 | uint32_t | m_size | The number of textures and their width/height. | Used to calculate file size (m_size3 * 3 + 16) |
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 | The number of textures and their width/height. | Used to calculate file size (m_size3 * 3 + 16) |
0x4 | 0x4 | Padding | |||
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 as a cube of size m_size*m_size*m_size pixels, accessed according to a certain algorithm. The algorithm is different for Burnout Paradise 32*32*32 cubes and Need for Speed: Hot Pursuit 16*16*16 cubes.
To find the 3 bytes (R, G and B) of 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 - 1).
x | y | z | offset (m_size = 16) |
---|---|---|---|
xxxx 3210 |
yyyy 3210 |
zzzz 3210 |
o0=x0 o1=x1 o2=y0 o3=x2 o4=x3 o5=y1 o6=y2 o7=z0 o8=y3^z2 o9=z1 o10=z2 o11=z3 |
x | y | z | offset (m_size = 32) |
---|---|---|---|
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(m_size, x, y, z)
case m_size
when 16
calc_offset16(x, y, z)
when 32
calc_offset32(x, y, z)
else
raise "Unsupported m_size: #{m_size}"
end
end
def calc_offset16(x, y, z)
x0 = (x >> 0) & 0b1
x1 = (x >> 1) & 0b1
x2 = (x >> 2) & 0b1
x3 = (x >> 3) & 0b1
y0 = (y >> 0) & 0b1
y1 = (y >> 1) & 0b1
y2 = (y >> 2) & 0b1
y3 = (y >> 3) & 0b1
z0 = (z >> 0) & 0b1
z1 = (z >> 1) & 0b1
z2 = (z >> 2) & 0b1
z3 = (z >> 3) & 0b1
o=(z3<<11)|
(z2<<10)|
(z1<<9)|
((y3<<8)^(z2<<8))|
(z0<<7)|
(y2<<6)|
(y1<<5)|
(x3<<4)|
(x2<<3)|
(y0<<2)|
(x1<<1)|
(x0<<0)
end
def calc_offset32(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 "converted to PC" data to file
# ...