Hocus Pocus Sprite Format

From ModdingWiki
Jump to navigation Jump to search
Hocus Pocus Sprite Format
There is no example of an image in this format — upload one!
Format typeImage
HardwareVGA
Colour depth8-bit (VGA)
Minimum size (pixels)0×0
Maximum size (pixels)262140×65535
PaletteExternal
Plane count4
Transparent pixels?Yes
Hitmap pixels?No
Games

The Hocus Pocus Sprite Format is used by Hocus Pocus to store images for game items.

File format

The file begins with a number of sprite info blocks of the following structure:

  0 UINT32LE     iOffset          offset to the start of this sprite's data
  4 CHAR[22]     cSpriteName
 26 UINT16LE     iWidth4          (width in pixels = 4*iWidth4)
 28 UINT16LE     iHeight          height in pixels
 30 UINT16LE     iStandFrame
 32 UINT16LE     iStandFrame2     maybe for animation? no effect for Hocus.
 34 UINT16LE     iWalkFrame1      beginning frame of walking animation
 36 UINT16LE     iWalkFrame2      ending frame of walking animation
 38 UINT16LE     iJumpFrame
 40 UINT16LE     iFallFrame
 42 UINT16LE     iShootDashFrame1 beginning frame of dashing animation/first shooting frame (Hocus' shooting up frame is always this plus one)
 44 UINT16LE     iShootDashFrame2 ending frame of dashing animation/second shooting frame
 46 UINT16LE     iProjectileWidth4 (width in pixels = 4*iProjectileWidth4)
 48 UINT16LE     iProjectileHeight height in pixels
 50 UINT16LE     iProjectileY     vertical offset of projectile when fired horizontally
 52 UINT16LE     iProjectileFrame frame number for projectile (Hocus' upwards shot is this plus one)
 54 UINT16LE     iProjectileF2     no idea
 56 UINT16LE     iPixelsOff       offset to the start of pixel data (relative to iOffset)
 58 UINT16LE     iPixelsSize      size of pixel data
 60 UINT16LE[20] iLayoutStartsE   (relative to iOffset)
100 UINT16LE[20] iLayoutStartsW   (relative to iOffset)
140 UINT16LE[20] iPixelStartsE    (relative to iPixelsOff; multiply by 4)
180 UINT16LE[20] iPixelStartsW    (relative to iPixelsOff; multiply by 4)

The number of sprite info blocks can be calculated by reading the iOffset value of the first block and dividing it by 220 (size of the sprite info block). It is also worth noting that the size of the sprite data stored at iOffset can be calculated by adding iPixelsOff and iPixelsSize. If you add that size to iOffset you get the iOffset value for the next sprite info block or the size of the entire sprite file if you have reached the last sprite info block in the file. This might be used to perform an integrity check on the sprite file.

Notes:

  • The iLayoutStartsE and iLayoutStartsW (E and W indicate the sprites facing East or West) might also be a single array. They are listed as seperate arrays since only the first 15 slots of each array are ever used by a sprite and one array with a bunch of unused slots in the middle seemed nonsensical. The same goes for the iPixelStart arrays.

All sprite frames appear to have the same width and height as given in the sprite info.

The number of sprite frames for the current sprite can be calculated from the Frame values. The last value in this array that is neither 0x0000 nor 0xFFFF represents the maximum frame index, and therefore, that index plus 1 is the number of frames the current sprite has.

Sprite Data

The sprite data starting at iOffset is divided into two blocks. The first block contains layout data that is required to reconstruct the sprite images from the pixel data that forms the second block.

Layout Data

The layout data uses four flag values, each one byte in size:

  • 0x00
    • read transparency type (BYTE value) from layout data (see Pixel Data for more info)
    • set image pointer back to 0
  • 0x01
    • read length (UINT16LE value) from layout data
    • increase image pointer by length
  • 0x02
    • read 4 bytes from pixel data
    • write 4 bytes to image
    • increase image pointer
    • increase pixel data pointer
  • 0x03
    • stop marker (this frame is done)

The image pointer is an index into the linear image buffer in which the sprite image is to be recreated. The algorithm expects an image that is exactly 320 pixels wide (and at least iHeight pixels high)! However, all pointers/indices need to be multiplied by 4 to get the actual pixel index (the sprites were probably created treating all image buffers as arrays of 32 bit integers).

During the process of recreating a sprite image, both the layout data and the pixel data need to be accessed simultaneously. Loading the pixel data of the sprite frame into a buffer prevents you from having to manage two file pointers to the same file.

This is how to create a sprite image from the sprite file:

  • read sprite info block
  • seek to iOffset+iPixelsOff
  • read iPixelsSize bytes from the file (entire pixel data block)
  • create an image buffer (320 * iHeight pixels)
  • (treat both image buffer and pixel data buffer as INT32 arrays)
  • initialize pixel data index to PixelStartsX[frame]
  • seek to iOffset+LayoutStartsX[frame]
  • read flag bytes and perform corresponding operations until flag byte is 0x03

Pixel Data

The pixel data consists of numerous short rows, each four pixels wide. The order in which the rows are stored depends on the number and location of transparent pixels in the row and the location of the row in the original image. Rows that consist entirely of transparent pixels are NOT stored. The rows were probably created from the original image using the following scheme:

  • for every row of 4 pixels:
    • store a transparency type value of at least 4 bits where bit i is set if and only if pixel i is not transparent
  • for v = 15 down to 1:
    • for every row of 4 pixels:
      • if the stored value is equal to v then write this row to the file

This "compression" method (omitting fully transparent rows) appears to be rather useless as the layout data required to reconstruct the original image is usually larger than the amount of bytes that were saved by omitting the transparent rows.

The color indices in the pixel data should never be larger than 127 as the last 128 colors in the palette are specific to the backdrop files. The palette data from GAMEPAL.PAL should be used to display the sprite images, with color index 0 indicating a transparent pixel.

Credits

This file format was reverse engineered by K1n9_Duk3. If you find this information helpful in a project you're working on, please give credit where credit is due. (A link back to this wiki would be nice too!)