summaryrefslogtreecommitdiff
path: root/extractor/sprite.gd
diff options
context:
space:
mode:
Diffstat (limited to 'extractor/sprite.gd')
-rw-r--r--extractor/sprite.gd204
1 files changed, 204 insertions, 0 deletions
diff --git a/extractor/sprite.gd b/extractor/sprite.gd
new file mode 100644
index 0000000..410ce07
--- /dev/null
+++ b/extractor/sprite.gd
@@ -0,0 +1,204 @@
+class_name Sprite
+
+
+## Byte Length: 2 [br]
+## SP
+var signature: String = "SP"
+
+## Byte Type: u8 [br]
+## Byte Length: 2
+var version: Version
+
+## Byte Type: u16 [br]
+## Byte Length: 2
+var palette_image_count: int
+
+## Byte Type: u16 [br]
+## Byte Length: 2
+var rgba_image_count: int
+
+## Length: [member palette_image_count]
+var palette_image_data: Array[PaletteImageData]
+
+## Byte Type: u8 [br]
+## Byte Length: [member rgba_image_count]
+var rgba_image_data: Array[RGBAImageData]
+
+## Byte Type: u16 [br]
+## Byte Length: 256 * 4 (rgba u8) [br]
+## The color with palette index 0 can be considered the "background color". [br]
+## It must be cleared manually on load.
+var palette: Array[PaletteColor]
+
+
+static func from_bytes(bytes: PackedByteArray):
+ var sprite = Sprite.new()
+
+ @warning_ignore("shadowed_variable")
+ var version = Version.new()
+ version.minor = bytes.decode_u8(2)
+ version.major = bytes.decode_u8(3)
+ sprite.version = version
+
+ sprite.palette_image_count = bytes.decode_u16(4)
+ sprite.rgba_image_count = bytes.decode_u16(6)
+
+ sprite.palette_image_data = [] as Array[PaletteImageData]
+ var palette_image_offset = 8
+ var processed_palette_images = 0
+ while processed_palette_images < sprite.palette_image_count:
+ var data = PaletteImageData.new()
+ data.width = bytes.decode_u16(palette_image_offset)
+ data.height = bytes.decode_u16(palette_image_offset + 2)
+
+ data.data_size = bytes.decode_u16(palette_image_offset + 4)
+ data.encoded_data = bytes.slice(
+ palette_image_offset + 6,
+ palette_image_offset + 6 + data.data_size
+ )
+
+ data.decode()
+
+ sprite.palette_image_data.append(data)
+ processed_palette_images += 1
+ palette_image_offset += data.get_byte_length()
+
+ sprite.rgba_image_data = [] as Array[RGBAImageData]
+ var rgba_image_offset = palette_image_offset
+ var processed_rgba_images = 0
+ while processed_rgba_images < sprite.rgba_image_count:
+ var data = RGBAImageData.new()
+ data.width = bytes.decode_u16(rgba_image_offset)
+ data.height = bytes.decode_u16(rgba_image_offset + 2)
+
+ data.data = bytes.slice(
+ rgba_image_offset + 4,
+ rgba_image_offset + 4 + (data.width * data.height * 4)
+ )
+
+ sprite.rgba_image_data.append(data)
+ processed_rgba_images += 1
+ rgba_image_offset += data.get_byte_length()
+
+ sprite.palette = [] as Array[PaletteColor]
+ var palette_offset = rgba_image_offset
+ while palette_offset < bytes.size():
+ var color = PaletteColor.new()
+ color.r = bytes.decode_u8(palette_offset)
+ color.g = bytes.decode_u8(palette_offset + 1)
+ color.b = bytes.decode_u8(palette_offset + 2)
+ color.a = bytes.decode_u8(palette_offset + 3)
+ sprite.palette.append(color)
+ palette_offset += 4
+
+ #print(sprite.palette_image_data[0].get_rgba_data(sprite.palette))
+
+ for idx in sprite.palette_image_data.size():
+ var d: PaletteImageData = sprite.palette_image_data[idx]
+ var i = Image.create_from_data(
+ d.width,
+ d.height,
+ false,
+ Image.FORMAT_RGBA8,
+ d.get_rgba_data(sprite.palette)
+ )
+ i.save_png("res://extractor/test/test-" + str(idx).pad_zeros(3) + ".png")
+
+ return sprite
+
+
+class PaletteImageData:
+ ## Byte Type: u16
+ ## Byte Length: 2
+ var width: int
+
+ ## Byte Type: u16
+ ## Byte Length: 2
+ var height: int
+
+ ## Byte Type: u16
+ ## Byte Length: 2
+ var data_size: int
+
+ ## Byte Type: u8
+ ## Byte Length: [member data_size]
+ var encoded_data: PackedByteArray
+
+ var decoded_data: PackedByteArray
+
+
+ func get_byte_length() -> int:
+ return 6 + data_size
+
+
+ func decode():
+ decoded_data = PackedByteArray([])
+
+ var offset = 0
+ while offset < encoded_data.size():
+ var byte = encoded_data.decode_u8(offset)
+ if byte == 0:
+ var length = encoded_data.decode_u8(offset + 1)
+ var padding = PackedByteArray([])
+ padding.resize(length)
+ padding.fill(0)
+ decoded_data.append_array(padding)
+
+ offset += 2
+ else:
+ decoded_data.append(byte)
+ offset += 1
+
+
+ func get_rgba_data(palette: Array[PaletteColor]) -> PackedByteArray:
+ var rgba := PackedByteArray([])
+ var background_color := palette[0]
+
+ for idx in decoded_data:
+ var color := palette[idx]
+ if color == background_color:
+ rgba.append_array(PackedByteArray([0, 0, 0, 0]))
+ else:
+ rgba.append_array(color.to_bytes())
+
+ return rgba
+
+
+class PaletteColor:
+ const BYTE_LENGTH := 4
+
+ var r: int
+ var g: int
+ var b: int
+ var a: int
+
+
+ func to_bytes():
+ return PackedByteArray([r, g, b, 255])
+
+
+class RGBAImageData:
+ ## Byte Type: u16
+ ## Byte Length: 2
+ var width: int
+
+ ## Byte Type: u16
+ ## Byte Length: 2
+ var height: int
+
+ ## Byte Type: u8
+ ## Byte Length: width * height * RGBAPixel.byte_length
+ var data: Array[Pixel]
+
+
+ class Pixel:
+ const BYTE_LENGTH := 4
+
+ var r: int
+ var g: int
+ var b: int
+ var a: int
+
+
+ func get_byte_length() -> int:
+ return width * height * data.size()