Colour Cube: Difference between revisions

m
Changed ^3 to ³ to avoid confusion with bitwise XOR.
(Added information about the Xbox 360 swizzle algorithm)
m (Changed ^3 to ³ to avoid confusion with bitwise XOR.)
 
(16 intermediate revisions by 4 users not shown)
Line 1:
{{ParadiseResourceTypeInfobox
| 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.
 
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'').
[[File:Paradise_ColourCubes.png|thumb|200px|ColourCubes used in Burnout Paradise.]]
 
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.
A ColourCube is a set of 32 32x32 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 (i.e., the red filter when wrecking a vehicle in versions 1.0-1.3 of Burnout Paradise).
 
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.
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.
 
= Structures =
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.
=== rw::graphics::postfx::ColourCube ===
 
==== Layout32-bit ====
=== 32-bit ===
{| class="wikitable"
|-
! Offset !! Length !! Type !! Name !! Description !! Comments
|-
| 0x0 || 0x4 || uint32_t || m_size || Either theThe number of textures orand thetheir 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. ||
|}
 
=== 64-bit ===
==== 64-bit ====
{| class="wikitable"
|-
! Offset !! Length !! Type !! Name !! Description !! Comments
|-
| 0x0 || 0x4 || uint32_t || m_size || Either theThe number of textures orand thetheir 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. ||
Line 30 ⟶ 40:
 
= 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].
 
== Xbox 360 Swizzle Algorithm ==
The following algorithm assumes that the data is stored and accessed as m_sizea cubes,cube eachof 32x32 pixels, oriented left to right with ansize m_size*32m_size*3m_size bytes stridepixels, ratheraccessed than as m_size cubes oriented topaccording to bottom with a 32*3certain bytes stride (i.ealgorithm. onlyThe one cube's data per line). Regardless of whichalgorithm is true,different itfor seems''Burnout thatParadise'' the32*32*32 followingcubes algorithmand works''Need tofor produceSpeed: exactHot conversionsPursuit'' from16*16*16 Xbox 360 colourcubes to PC colourcubescubes.
 
With the above in mind, toTo find the 3-byte 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 yz are represented as a number of bits, x0 to x9x4, (valuesy0 0-1023)to y4 and y0z0 to y4z4 (all values between 0 and m_size -31 1).
 
{| class="wikitable"
! x !! y !! z !! offset (m_size = 16)
|-
! x !! y !! offset
|- 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
o2=x5y0
o3=x2
o4=x3
o5=x4^x8^y2y1
o6=x6y2
o7=x7z0
o8=y0y3^z2
o9=x8^y2z1
o10=y1z2
o11=x9z3</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 ⟶ 99:
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)
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
Line 76 ⟶ 146:
x3 = (x >> 3) & 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
y1 = (y >> 1) & 0b1
Line 86 ⟶ 151:
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=(y4z4<<14)|
(y3z3<<13)|
(y2z2<<12)|
(x9y4<<11)|
(y1z1<<10)|
((y2z2<<9)^(x8y3<<9))|
(y0z0<<8)|
(x7y2<<7)|
(x6y1<<6)|
((y2z2<<5)^(x8y3<<5)^(x4<<5))|
(x3<<4)|
(x2<<3)|
(x5y0<<2)|
(x1<<1)|
(x0<<0)
Line 109 ⟶ 179:
# now, convert the m_pixels data
data="".b
32m_size.times do |yz|
(m_size*32).times do |xy|
m_size.times do |x|
offset = calc_offset(x, y)
pixel_data = m_pixels[offset.pixels... = calc_offset(offsetx, +y, 1z).pixels]
data << pixel_data = m_pixels[offset.pixels...(offset + 1).pixels]
data << pixel_data
end
end
end
 
# write "converted to PC" data to file
# ...
‎</syntaxhighlight>