Skip to content

Commit

Permalink
H2 bitmap parsing and writing
Browse files Browse the repository at this point in the history
  • Loading branch information
Steven Garcia committed Nov 25, 2023
1 parent 24181d3 commit 624fe37
Show file tree
Hide file tree
Showing 4 changed files with 421 additions and 13 deletions.
66 changes: 63 additions & 3 deletions io_scene_halo/file_tag/h2/file_bitmap/build_asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,74 @@ def write_body(output_stream, BITMAP, TAG):
output_stream.write(struct.pack('<H', BITMAP.bitmap_body.force_format))
BITMAP.bitmap_body.sequences_tag_block.write(output_stream, False)
BITMAP.bitmap_body.bitmaps_tag_block.write(output_stream, False)
output_stream.write(struct.pack('<b', BITMAP.bitmap_body.color_compression_quality))
output_stream.write(struct.pack('<b', BITMAP.bitmap_body.alpha_compression_quality))
output_stream.write(struct.pack('<b', BITMAP.bitmap_body.overlap))
output_stream.write(struct.pack('<B', BITMAP.bitmap_body.color_compression_quality))
output_stream.write(struct.pack('<B', BITMAP.bitmap_body.alpha_compression_quality))
output_stream.write(struct.pack('<B', BITMAP.bitmap_body.overlap))
output_stream.write(struct.pack('<B', BITMAP.bitmap_body.color_subsampling))

def write_sequences(output_stream, BITMAP, TAG):
if len(BITMAP.sequences) > 0:
BITMAP.sequence_header.write(output_stream, TAG, True)
for sequence in BITMAP.sequences:
output_stream.write(struct.pack('>31sx', TAG.string_to_bytes(sequence.name, False)))
output_stream.write(struct.pack('>h', sequence.first_bitmap_index))
output_stream.write(struct.pack('>h', sequence.bitmap_count))
output_stream.write(struct.pack('>16x'))
sequence.sprites_tag_block.write(output_stream, False)

for sequence in BITMAP.sequences:
if len(sequence.sprites) > 0:
sequence.sprites_header.write(output_stream, TAG, True)
for sprite in sequence.sprites:
output_stream.write(struct.pack('>h', sprite.bitmap_index))
output_stream.write(struct.pack('>6x'))
output_stream.write(struct.pack('>f', sprite.left))
output_stream.write(struct.pack('>f', sprite.right))
output_stream.write(struct.pack('>f', sprite.top))
output_stream.write(struct.pack('>f', sprite.bottom))
output_stream.write(struct.pack('>ff', sprite.registration_point[0], sprite.registration_point[1]))

def write_bitmaps(output_stream, BITMAP, TAG):
if len(BITMAP.bitmaps) > 0:
BITMAP.bitmap_header.write(output_stream, TAG, True)
for bitmap in BITMAP.bitmaps:
output_stream.write(struct.pack('>4s', TAG.string_to_bytes(bitmap.signature, False)))
output_stream.write(struct.pack('>h', bitmap.width))
output_stream.write(struct.pack('>h', bitmap.height))
output_stream.write(struct.pack('>b', bitmap.depth))
output_stream.write(struct.pack('>b', bitmap.more_flags))
output_stream.write(struct.pack('>h', bitmap.bitmap_type))
output_stream.write(struct.pack('>h', bitmap.bitmap_format))
output_stream.write(struct.pack('>h', bitmap.flags))
output_stream.write(struct.pack('>hh', bitmap.registration_point[0], bitmap.registration_point[1]))
output_stream.write(struct.pack('>h', bitmap.mipmap_count))
output_stream.write(struct.pack('>b', bitmap.lod_adjust))
output_stream.write(struct.pack('>b', bitmap.cache_usage))
output_stream.write(struct.pack('>i', bitmap.pixels_offset))
output_stream.write(struct.pack('>4x'))
bitmap.native_mipmap_info_tag_block.write(output_stream, False)
output_stream.write(struct.pack('>i', bitmap.native_size))
output_stream.write(struct.pack('>i', bitmap.tile_mode))
output_stream.write(struct.pack('>88x'))

for bitmap in BITMAP.bitmaps:
bitmap.nbmi_header.write(output_stream, TAG, True)
if len(bitmap.native_mipmap_info) > 0:
bitmap.native_mipmap_info_header.write(output_stream, TAG, True)
for native_mipmap_info in bitmap.native_mipmap_info:
output_stream.write(struct.pack('>i', native_mipmap_info.offset))
output_stream.write(struct.pack('>i', native_mipmap_info.pitch_row))
output_stream.write(struct.pack('>i', native_mipmap_info.pitch_slice))

def build_asset(output_stream, BITMAP, tag_format, report):
TAG = tag_format.TagAsset()
TAG.big_endian = False

BITMAP.header.write(output_stream, TAG.big_endian, True)
write_body(output_stream, BITMAP, TAG)

output_stream.write(BITMAP.bitmap_body.compressed_color_plate)
output_stream.write(BITMAP.bitmap_body.processed_pixels)

write_sequences(output_stream, BITMAP, TAG)
write_bitmaps(output_stream, BITMAP, TAG)
125 changes: 118 additions & 7 deletions io_scene_halo/file_tag/h2/file_bitmap/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

from enum import Flag, Enum, auto

class BitmapTypeEnum(Enum):
class ImportTypeEnum(Enum):
_2d_textures = 0
_3d_textures = auto()
cube_maps = auto()
Expand Down Expand Up @@ -54,7 +54,7 @@ class UsageEnum(Enum):
height_map_g8b8 = auto()
height_map_g8b8_with_alpha = auto()

class BitmapFlags(Flag):
class ImportFlags(Flag):
enable_diffusion_dithering = auto()
disable_height_map_compression = auto()
uniform_sprite_sequences = auto()
Expand Down Expand Up @@ -92,11 +92,74 @@ class ForceFormatEnum(Enum):
force_alpha_lumincance8 = auto()
force_a4r4g4b4 = auto()

class ColorSubsamplingEnum(Enum):
_4_0_0 = 0
_4_2_0 = auto()
_4_2_2 = auto()
_4_4_4 = auto()
class MoreFlags(Flag):
delete_from_cache_file = auto()
bitmap_create_attempted = auto()
bitmap_recreate_allowed = auto()
bitmap_sampling_allowed = auto()

class BitmapTypeEnum(Enum):
_2d_texture = 0
_3d_texture = auto()
cube_map = auto()

class BitmapFormatEnum(Enum):
a8 = 0
y8 = auto()
ay8 = auto()
a8y8 = auto()
unused1 = auto()
unused2 = auto()
r5g6b5 = auto()
unused3 = auto()
a1r5g5b5 = auto()
a4r4g4b4 = auto()
x8r8g8b8 = auto()
a8r8g8b8 = auto()
unused4 = auto()
unused5 = auto()
dxt1 = auto()
dxt3 = auto()
dxt5 = auto()
p8_bump = auto()
p8 = auto()
argbfb32 = auto()
rgbfb32 = auto()
rgbfb16 = auto()
v8u8 = auto()
g8b8 = auto()

class BitmapFlags(Flag):
power_of_two_dimensions = auto()
compressed = auto()
palettized = auto()
swizzled = auto()
linear = auto()
v16u16 = auto()
mipmap_debug_level = auto()
prefer_stutter = auto()

class CacheUsageEnum(Enum):
default = 0
environment = auto()
environment_bump = auto()
environment_lightmap = auto()
scenery = auto()
scenery_bump = auto()
weapon = auto()
weapon_bump = auto()
vehicle = auto()
vehicle_bump = auto()
biped = auto()
biped_bump = auto()
object = auto()
object_bump = auto()
effect = auto()
hud = auto()
ui = auto()
sky = auto()
first_person = auto()
rasterizer = auto()

class BitmapAsset():
def __init__(self):
Expand Down Expand Up @@ -140,3 +203,51 @@ def __init__(self, type=0, format=0, usage=0, flags=0, detail_fade_factor=0.0, s
self.alpha_compression_quality = alpha_compression_quality
self.overlap = overlap
self.color_subsampling = color_subsampling

class Sequence:
def __init__(self, name="", first_bitmap_index=0, bitmap_count=0, sprites_tag_block=None, sprites_header=None, sprites=None):
self.name = name
self.first_bitmap_index = first_bitmap_index
self.bitmap_count = bitmap_count
self.sprites_tag_block = sprites_tag_block
self.sprites_header = sprites_header
self.sprites = sprites

class Sprite:
def __init__(self, bitmap_index=0, left=0, right=0, top=0, bottom=0, registration_point=(0.0, 0.0)):
self.bitmap_index = bitmap_index
self.left = left
self.right = right
self.top = top
self.bottom = bottom
self.registration_point = registration_point

class Bitmap:
def __init__(self, signature="", width=0, height=0, depth=0, more_flags=0, bitmap_type=0, bitmap_format=0, flags=0, registration_point=(0.0, 0.0), mipmap_count=0,
lod_adjust=0, cache_usage=0, pixels_offset=0, native_mipmap_info_tag_block=None, native_mipmap_info_header=None, native_mipmap_info=None, native_size=0,
tile_mode=0, nbmi_header=None):
self.signature = signature
self.width = width
self.height = height
self.depth = depth
self.more_flags = more_flags
self.bitmap_type = bitmap_type
self.bitmap_format = bitmap_format
self.flags = flags
self.registration_point = registration_point
self.mipmap_count = mipmap_count
self.lod_adjust = lod_adjust
self.cache_usage = cache_usage
self.pixels_offset = pixels_offset
self.native_mipmap_info_tag_block = native_mipmap_info_tag_block
self.native_mipmap_info_header = native_mipmap_info_header
self.native_mipmap_info = native_mipmap_info
self.native_size = native_size
self.tile_mode = tile_mode
self.nbmi_header = nbmi_header

class NativeMipMapInfo:
def __init__(self, offset=0, pitch_row=0, pitch_slice=0):
self.offset = offset
self.pitch_row = pitch_row
self.pitch_slice = pitch_slice
Loading

0 comments on commit 624fe37

Please sign in to comment.