class InteractiveImage(mrc.Block): """Represents the sprite data for an interactive object.""" image_data = mrc.Bytes( 0x0000, transform=img.Planarizer( bpp=4, width=mrc.Ref('_parent.width'), height=mrc.Ref('_parent.height'), frame_count=mrc.Ref('_parent.end_frame'), frame_stride=mrc.Ref('_parent.frame_data_size'))) mask_data = mrc.Bytes(mrc.Ref('_parent.mask_rel_offset'), transform=img.Planarizer( bpp=1, width=mrc.Ref('_parent.width'), height=mrc.Ref('_parent.height'), frame_count=mrc.Ref('_parent.end_frame'), frame_stride=mrc.Ref('_parent.frame_data_size'))) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.image = img.IndexedImage( self, width=mrc.Ref('_parent.width'), height=mrc.Ref('_parent.height'), source=mrc.Ref('image_data'), frame_count=mrc.Ref('_parent.end_frame'), palette=mrc.Ref('_parent._parent.palette'), mask=mrc.Ref('mask_data'))
class SAMTileset8( mrc.Block ): count = mrc.UInt8( 0x00 ) width_raw = mrc.UInt8( 0x01 ) height = mrc.UInt8( 0x02 ) mask_data = mrc.Bytes( 0x03, length=0x7fd, transform=img.Planarizer( bpp=5, plane_size=mrc.Ref( 'plane_size' ), row_planar_size=1, plane_order=(0,) ) ) image_data = mrc.Bytes( 0x03, length=0x7fd, transform=img.Planarizer( bpp=5, plane_size=mrc.Ref( 'plane_size' ), row_planar_size=1, plane_order=(1,2,3,4) ) ) def __init__( self, *args, **kwargs ): super().__init__( *args, **kwargs ) self.image = img.IndexedImage( self, width=mrc.Ref( 'width' ), height=mrc.Ref( 'height' ), source=mrc.Ref( 'image_data' ), frame_count=mrc.Ref( 'count' ), palette=ibm_pc.EGA_DEFAULT_PALETTE ) self.mask = img.IndexedImage( self, width=mrc.Ref( 'width' ), height=mrc.Ref( 'height' ), source=mrc.Ref( 'mask_data' ), frame_count=mrc.Ref( 'count' ), palette=ibm_pc.EGA_DEFAULT_PALETTE ) @property def plane_size( self ): return self.count*self.width_raw*self.height @property def width( self ): return self.width_raw*8
class PreviewCompressor( mrc.Transform ): rle = RLECompressor() # each plane is stored with 192 bytes padding at the end plan = img.Planarizer( bpp=4, width=320, height=200, plane_padding=192 ) def import_data( self, buffer, parent=None ): assert utils.is_bytes( buffer ) stage_1 = self.rle.import_data( buffer ) stage_2 = self.plan.import_data( stage_1.payload ) return mrc.TransformResult( payload=stage_2.payload, end_offset=stage_1.end_offset )
class SplashEGA(mrc.Block): image_data = mrc.Bytes(0x0000, transform=img.Planarizer(bpp=4, width=320, height=200)) def __init__(self, *args, **kwargs): mrc.Block.__init__(self, *args, **kwargs) self.image = img.IndexedImage(self, width=320, height=200, palette=ibm_pc.EGA_DEFAULT_PALETTE, source=mrc.Ref('image_data'))
class TerrainImage(mrc.Block): image_data = mrc.Bytes(0x0000, transform=img.Planarizer( bpp=4, width=mrc.Ref('_parent.width'), height=mrc.Ref('_parent.height'), )) mask_data = mrc.Bytes(mrc.Ref('_parent.mask_offset'), transform=img.Planarizer( bpp=1, width=mrc.Ref('_parent.width'), height=mrc.Ref('_parent.height'), )) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.image = img.IndexedImage( self, width=mrc.Ref('_parent.width'), height=mrc.Ref('_parent.height'), source=mrc.Ref('image_data'), palette=mrc.Ref('_parent._parent.palette'), mask=mrc.Ref('mask_data'))
class Anim(mrc.Block): image_data = mrc.Bytes(0x0000, transform=img.Planarizer( bpp=mrc.Ref('bpp'), width=mrc.Ref('width'), height=mrc.Ref('height'), frame_count=mrc.Ref('frame_count'))) def __init__(self, width, height, bpp, frame_count, *args, **kwargs): self.width = width self.height = height self.bpp = bpp self.frame_count = frame_count self.image = img.IndexedImage(self, width=width, height=height, source=mrc.Ref('image_data'), frame_count=frame_count, palette=LEMMINGS_VGA_DEFAULT_PALETTE) super().__init__(*args, **kwargs)
class EGATileStore(mrc.Block): data = mrc.Bytes( 0x00, transform=img.Planarizer( bpp=4, plane_size=mrc.Ref('_parent._egahead.latch_plane_size'))) tile8 = mrc.StoreRef(EGATile8, mrc.Ref('store'), mrc.Ref('tile8_offset'), mrc.Ref('tile8_size')) tile16 = mrc.StoreRef(EGATile16, mrc.Ref('store'), mrc.Ref('tile16_offset'), mrc.Ref('tile16_size')) tile32 = mrc.StoreRef(EGATile32, mrc.Ref('store'), mrc.Ref('tile32_offset'), mrc.Ref('tile32_size')) def __init__(self, *args, **kwargs): self.store = mrc.Store(self, mrc.Ref('data')) super().__init__(*args, **kwargs) @property def tile8_offset(self): return self._parent._egahead.tile8_offset * 8 @property def tile16_offset(self): return self._parent._egahead.tile16_offset * 8 @property def tile32_offset(self): return self._parent._egahead.tile32_offset * 8 @property def tile8_size(self): return self._parent._egahead.tile8_count * 8 * 8 @property def tile16_size(self): return self._parent._egahead.tile16_count * 16 * 16 @property def tile32_size(self): return self._parent._egahead.tile16_count * 32 * 32
class SpecialCompressor(mrc.Transform): DECOMPRESSED_SIZE = 14400 plan = img.Planarizer(bpp=3, width=960, height=40) def import_data(self, buffer, parent=None): assert utils.is_bytes(buffer) result = [] buf_out = [] i = 0 while i < len(buffer): # 0x00 <= n < 0x80: copy next n+1 bytes to output stream if buffer[i] in range(0x00, 0x80): count = buffer[i] + 1 buf_out.append(buffer[i + 1:i + 1 + count]) i += count + 1 # n == 0x80: end of segment elif buffer[i] == 0x80: product = b''.join(buf_out) if len(product) != self.DECOMPRESSED_SIZE: logger.warning( '{}: was expecting {} bytes of data, got {}'.format( self, self.DECOMPRESSED_SIZE, len(product))) result.append(product) buf_out = [] i += 1 # 0x81 <= n < 0xff: repeat next byte (257-n) times else: count = 257 - buffer[i] buf_out.append(buffer[i + 1:i + 2] * count) i += 2 if buf_out: logger.warning( '{}: EOF reached before last RLE block closed'.format(self)) result.append(b''.join(buf_out)) # result is a 960x160 3bpp image, divided into 4x 40 scanline segments unpack = (self.plan.import_data(x).payload for x in result) return mrc.TransformResult(payload=bytes(itertools.chain(*unpack)), end_offset=i) def export_data(self, buffer, parent=None): assert utils.is_bytes(buffer) assert len(buffer) == 960 * 160 segments = (buffer[960 * 40 * i:960 * 40 * (i + 1)] for i in range(4)) segments = (self.plan.export_data(x).payload for x in segments) result = bytearray() for segment in segments: pointer = 0 while pointer < len(segment): start = pointer end = pointer + 1 if end >= len(segment): result.append(0x00) result.append(segment[start]) pointer += 1 elif segment[end] == segment[start]: while ((end + 1) < len(segment)) and ( segment[end + 1] == segment[end]) and (end - start < 127): end += 1 result.append(257 - (end + 1 - start)) result.append(segment[start]) pointer = end + 1 else: while ((end + 1) < len(segment)) and ( segment[end + 1] != segment[end]) and (end - 1 - start < 128): end += 1 result.append(end - 1 - start) result.extend(segment[start:end]) pointer = end result.append(0x80) return mrc.TransformResult(payload=bytes(result))