Skip to main content

CHAR ("RHAC") - Character

Author(s): Gonhex
Research: NOCASH, Gonhex

The character section stores the sprite-image in form of indices to colors within a palette. The array layout is usually a tile map where each tile has a size of 8 * 8 pixels, but can also be a line buffer which maps the image directly to the target.

Table of Contents


Data Structure

Section Container

struct ContainerSectionCHAR
{
/* 0x0 */ struct NitroSectionHeader sectionHeader;
/* 0x8 */ struct ContainerCHAR sectionData;
}; // entry size = sectionHeader.lengthSection
Field NameDescriptionData Type
sectionHeaderHeader of this section. sectionHeader.signature = "RAHC".NitroSectionHeader
sectionDataContent of this section.ContainerCHAR

CHAR Container

struct ContainerCHAR
{
// header
/* 0x00 */ int16_t heightInTiles;
/* 0x02 */ int16_t widthInTiles;
/* 0x04 */ uint32_t pixelFormat;
/* 0x08 */ uint16_t mappingType0;
/* 0x0A */ uint16_t mappingType1;
/* 0x0C */ uint32_t flags;
/* 0x10 */ uint32_t lengthDataImage;
/* 0x14 */ uint32_t offsetDataImage;

// data
/* offsetDataImage */ uint8_t dataImage[lengthDataImage];
}; // entry size = offsetDataImage + lengthDataImage
Field NameDescriptionData Type
heightInTilesHeight of the sprite or -1, see Dimensions.int16_t
widthInTilesWidth of the sprite or -1, see Dimensions.int16_t
pixelFormat== 3: 4 bits per pixel. == 4: 8 bits per pixel.uint32_t
mappingType0== 0: 2D mapping, else: 1D mapping(?).uint16_t
mappingType1Sometimes used in combination with mappingType0(?).uint16_t
flagsBinary flags for different purposes. See Flags.uint32_t
lengthDataImageLength of the image data section in bytes.uint32_t
offsetDataImageOffset to the image data section relative to ContainerCHAR.uint32_t
dataImageArray holding all color indices to create an image, see Pixel Data.uint8_t[]

Specification

Pixel Data

Color

The character graphic stores indices to colors on a palette. This palette provides either 16 or 256 colors. The density of indices depends on the palette size. For a value of 0...15 only 4 bits (1 nibble) are needed. This allows to squeeze two indices into one byte, reducing the overall size by half.

  • pixelFormat == 3: use 16 colors
  • pixelFormat == 4: use 256 colors

Layout

The 2D engine uses a tile based system. The pixel layout in the file represents this and can be imagined as a box with a width of 8 pixels and an infinite length. The data is written line by line into this box. Each tile can now be accessed at y * 8. Now we have 1D mapped tiles. For 2D mapping these tiles are also layed out row by row.

If the image is to be used by the 3D engine, the "infinite length box" from before becomes a bitmap which has the dimensions of the image. There are no tiles in this case.

Dimensions

The first two entries of ContainerCHAR define the size of the sprite in tiles. To get the pixel values, multiply them with the side length of a tile (which is 8).

heightpixel=heighttiles8widthpixel=widthtiles8\begin{align} height_{pixel} &= height_{tiles}\cdot 8\\ width_{pixel} &= width_{tiles}\cdot 8 \end{align}

Sometimes the width and height values are both set to -1. In this case the image itself has no size and the CPOS section is not part of the file. To display the sprite anyway, a width of four tiles often makes the image recognizable. The real image is constructed by the cell runtime, which picks the needed tiles and positions them.

Mapping Type

These values are 0, if the image uses 2D mapping (positive values in heightInTiles an widhtInTiles). Both dimension values == -1 indicate 1D mapping. In this case mappingType0 usually has a value like 0x10. In the most cases, the cell runtime indexes 1D mapped tiles.

Flags

Apply properties to the sprite.

  • (flags & 0x00000001) > 0: Use a line buffer instead of tiles.
  • (flags & 0x00000100) > 0: Unknown. Maybe related to Mapping Type?

Files


TODO

  • Research and document "mappingType"