Skip to content

Commit

Permalink
VTX1: Implement reading and writing RGBA8 color data
Browse files Browse the repository at this point in the history
  • Loading branch information
LagoLunatic committed Jan 5, 2023
1 parent d12b8ab commit a2df2ac
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 45 deletions.
11 changes: 11 additions & 0 deletions wwlib/gx_enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,19 @@ class GXComponentCount(Enum):
TexCoord_ST = 0x01

class GXCompType(Enum):
pass

class GXCompTypeNumber(GXCompType):
Unsigned8 = 0x00
Signed8 = 0x01
Unsigned16 = 0x02
Signed16 = 0x03
Float32 = 0x04

class GXCompTypeColor(GXCompType):
RGB565 = 0x00
RGB8 = 0x01
RGBX8 = 0x02
RGBA4 = 0x03
RGBA6 = 0x04
RGBA8 = 0x05
133 changes: 88 additions & 45 deletions wwlib/j3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from fs_helpers import *
from wwlib.bti import BTI
from wwlib.yaz0 import Yaz0
from wwlib.gx_enums import GXAttr, GXComponentCount, GXCompType
from wwlib.gx_enums import GXAttr, GXComponentCount, GXCompType, GXCompTypeNumber, GXCompTypeColor

IMPLEMENTED_CHUNK_TYPES = [
#"INF1",
Expand Down Expand Up @@ -312,12 +312,21 @@ class VTX1DataOffsetIndex(IntEnum):
GXAttr.Tex7 : VTX1DataOffsetIndex.TexCoord7Data,
}

GXCompType_TO_COMPONENT_BYTE_SIZE = {
GXCompType.Unsigned8 : 1,
GXCompType.Signed8 : 1,
GXCompType.Unsigned16: 2,
GXCompType.Signed16 : 2,
GXCompType.Float32 : 4,
GXCompTypeNumber_TO_COMPONENT_BYTE_SIZE = {
GXCompTypeNumber.Unsigned8 : 1,
GXCompTypeNumber.Signed8 : 1,
GXCompTypeNumber.Unsigned16: 2,
GXCompTypeNumber.Signed16 : 2,
GXCompTypeNumber.Float32 : 4,
}

GXCompTypeColor_TO_COMPONENT_BYTE_SIZE = {
GXCompTypeColor.RGB565: 2,
GXCompTypeColor.RGB8 : 1,
GXCompTypeColor.RGBX8 : 1,
GXCompTypeColor.RGBA4 : 2,
GXCompTypeColor.RGBA6 : 1,
GXCompTypeColor.RGBA8 : 1,
}

@dataclass
Expand All @@ -336,8 +345,13 @@ def __init__(self, data):
def read(self, offset):
self.attribute_type = GXAttr(read_u32(self.data, offset))
self.component_count_type = GXComponentCount(read_u32(self.data, offset+4))
self.component_type = GXCompType(read_u32(self.data, offset+8))
comp_type_raw = read_u32(self.data, offset+8)
self.component_shift = read_u8(self.data, offset+0xC)

if self.is_color_attr:
self.component_type = GXCompTypeColor(comp_type_raw)
else:
self.component_type = GXCompTypeNumber(comp_type_raw)

def save(self, offset):
write_u32(self.data, offset+0x0, self.attribute_type.value)
Expand All @@ -350,27 +364,51 @@ def save(self, offset):
def data_offset_index(self):
return GXAttr_TO_VTX1DataOffsetIndex[self.attribute_type]

@property
def is_color_attr(self):
return self.attribute_type in [GXAttr.Color0, GXAttr.Color1]

@property
def component_count(self):
match self.attribute_type:
case GXAttr.Position:
match self.component_count_type:
case GXComponentCount.Position_XY:
return 2
case GXComponentCount.Position_XYZ:
return 3
case GXAttr.Normal:
match self.component_count_type:
case GXComponentCount.Normal_XYZ:
return 3
case GXAttr.Tex0|GXAttr.Tex1|GXAttr.Tex2|GXAttr.Tex3|GXAttr.Tex4|GXAttr.Tex5|GXAttr.Tex6|GXAttr.Tex7:
match self.component_count_type:
case GXComponentCount.TexCoord_S:
return 1
case GXComponentCount.TexCoord_ST:
return 2
if self.is_color_attr:
if self.component_type in [GXCompTypeColor.RGB565, GXCompTypeColor.RGBA4]:
return 1
elif self.component_type in [GXCompTypeColor.RGB8, GXCompTypeColor.RGBX8, GXCompTypeColor.RGBA6, GXCompTypeColor.RGBA8]:
return 4
else:
raise NotImplementedError

if self.attribute_type == GXAttr.Position:
if self.component_count_type == GXComponentCount.Position_XY:
return 2
elif self.component_count_type == GXComponentCount.Position_XYZ:
return 3
elif self.attribute_type == GXAttr.Normal:
if self.component_count_type == GXComponentCount.Normal_XYZ:
return 3
elif self.attribute_type in [
GXAttr.Tex0,
GXAttr.Tex1,
GXAttr.Tex2,
GXAttr.Tex3,
GXAttr.Tex4,
GXAttr.Tex5,
GXAttr.Tex6,
GXAttr.Tex7,
]:
if self.component_count_type == GXComponentCount.TexCoord_S:
return 1
elif self.component_count_type == GXComponentCount.TexCoord_ST:
return 2

raise NotImplementedError

@property
def component_size(self):
if self.is_color_attr:
return GXCompTypeColor_TO_COMPONENT_BYTE_SIZE[self.component_type]
else:
return GXCompTypeNumber_TO_COMPONENT_BYTE_SIZE[self.component_type]

class VTX1(J3DChunk):
def read_chunk_specific_data(self):
Expand Down Expand Up @@ -448,32 +486,34 @@ def load_attribute_data(self, vertex_format: VertexFormat):
vertex_format.data_offset_index,
vertex_format.component_count,
vertex_format.component_type,
vertex_format.component_size,
vertex_format.component_shift,
)

def load_attribute_list(self, offset_index, component_count, component_type, comp_shift):
def load_attribute_list(self, offset_index, component_count, comp_type, comp_size, comp_shift):
data_offset = self.vertex_data_offsets[offset_index]
component_size = GXCompType_TO_COMPONENT_BYTE_SIZE[component_type]
attrib_count = self.get_attribute_data_count(offset_index, component_count, component_size)
attrib_count = self.get_attribute_data_count(offset_index, component_count, comp_size)
attr_data = []
for i in range(0, attrib_count):
components = self.read_components(component_count, component_type, comp_shift, data_offset)
components = self.read_components(component_count, comp_type, comp_size, comp_shift, data_offset)
attr_data.append(components)
data_offset += component_count * component_size
data_offset += component_count * comp_size
return attr_data

def read_components(self, component_count, component_type, component_shift, data_offset):
divisor = (1 << component_shift)
def read_components(self, component_count, comp_type, comp_size, comp_shift, data_offset):
divisor = (1 << comp_shift)
components = []
for i in range(component_count):
match component_type:
case GXCompType.Signed16:
match comp_type:
case GXCompTypeNumber.Signed16:
components.append(read_s16(self.data, data_offset) / divisor)
case GXCompType.Float32:
case GXCompTypeNumber.Float32:
components.append(read_float(self.data, data_offset) / divisor)
case GXCompTypeColor.RGBA8:
components.append(read_u8(self.data, data_offset) / 255)
case _:
raise NotImplementedError
data_offset += GXCompType_TO_COMPONENT_BYTE_SIZE[component_type]
data_offset += comp_size
return tuple(components)

def save_chunk_specific_data(self):
Expand Down Expand Up @@ -502,7 +542,7 @@ def save_chunk_specific_data(self):
offset = self.save_attribute_data(vertex_format, offset)
align_data_to_nearest(self.data, 0x20)
offset = data_len(self.data)

# Write the header.
write_magic_str(self.data, 0, "VTX1", 4)

Expand All @@ -516,28 +556,31 @@ def save_attribute_data(self, vertex_format: VertexFormat, data_offset):
self.attributes[vertex_format.attribute_type],
vertex_format.component_count,
vertex_format.component_type,
vertex_format.component_size,
vertex_format.component_shift,
data_offset,
)
return data_offset

def save_attribute_list(self, attr_data, component_count, component_type: GXCompType, component_shift, data_offset):
def save_attribute_list(self, attr_data, component_count, comp_type: GXCompType, comp_size, comp_shift, data_offset):
for components in attr_data:
assert len(components) == component_count
data_offset = self.save_components(component_type, component_shift, components, data_offset)
data_offset = self.save_components(comp_type, comp_size, comp_shift, components, data_offset)
return data_offset

def save_components(self, component_type: GXCompType, component_shift, components, data_offset):
divisor = (1 << component_shift)
def save_components(self, comp_type: GXCompType, comp_size, comp_shift, components, data_offset):
divisor = (1 << comp_shift)
for component in components:
match component_type:
case GXCompType.Signed16:
match comp_type:
case GXCompTypeNumber.Signed16:
write_s16(self.data, data_offset, round(component*divisor))
case GXCompType.Float32:
case GXCompTypeNumber.Float32:
write_float(self.data, data_offset, component*divisor)
case GXCompTypeColor.RGBA8:
write_u8(self.data, data_offset, round(component*255))
case _:
raise NotImplementedError
data_offset += GXCompType_TO_COMPONENT_BYTE_SIZE[component_type]
data_offset += comp_size
return data_offset

class TEX1(J3DChunk):
Expand Down

0 comments on commit a2df2ac

Please sign in to comment.