Skip to content
Giovanni Bajo edited this page Feb 5, 2024 · 13 revisions

Mksprite

Mksprite is libdragon's tool for converting images (such as textures or sprites) from the PNG format into a format compatible with Nintendo 64, saved on a file with the .sprite extension.

A .sprite is an image file that can contain:

  • Pixels for an image (in one of the support RDP formats)
  • (optional) a palette of colors
  • (optional) precalculated mipmap levels

Quick tutorial

Running mksprite can be as easy as:

mksprite filename.png

This will create a .sprite file. It will automatically select the N64 format that is more similar to the input PNG file, trying to avoid color conversions as much as possible.

For instance, trying to run mksprite on a RGB PNG, we obtain this:

$ mksprite --verbose ../srtitle400.png
Converting: ../srtitle400.png -> ./srtitle400.sprite [fmt=AUTO tiles=0,0 mipmap=NONE dither=NONE]
loaded ../srtitle400.png (640x400, LCT_RGB)
auto selected format: RGBA16
auto detected hslices: 40 (w=640/16)
auto detected vslices: 25 (w=400/16)

so mksprite selected the N64 RGBA16 because the input PNG is in LCT_RGB format. Instead, trying to convert a PNG file with a palette:

$ mksprite --verbose ../hoi.png
Converting: ../hoi.png -> ./hoi.sprite [fmt=AUTO tiles=0,0 mipmap=NONE dither=NONE]
loaded ../hoi.png (640x200, LCT_PALETTE)
palette: 43 colors (used: 41)
auto selected format: CI8
auto detected hslices: 40 (w=640/16)
auto detected vslices: 12 (w=200/16)

in this case, the tool selected the CI8 format, and created a sprite file that contains the exact PNG palette, without an index remapping, preserving the input data as much as possible.

It is possible to force a specific output format, via a command line flag. If necessary, mksprite will quantize the image using an industry leading quantization algorithm (exoquant), with optional dithering. For instance:

$ mksprite --format CI8 --dither ORDERED --verbose ../srtitle400.png
Converting: ../srtitle400.png -> ./srtitle400.sprite [fmt=CI8 tiles=0,0 mipmap=NONE dither=ORDERED]
loaded ../srtitle400.png (640x400, LCT_RGB)
quantizing image(s) to 256 colors
auto detected hslices: 40 (w=640/16)
auto detected vslices: 25 (w=400/16)

Another way to tell mksprite that we want a specific format is to put it as part of the filename, in an extension. For instance, if we rename srtitle400.png to srtitle400.ci8.png, mksprite will default to CI8:

$ mksprite --verbose srtitle400.ci8.png
Converting: srtitle400.ci8.png -> ./srtitle400.ci8.sprite [fmt=AUTO tiles=0,0 mipmap=NONE dither=NONE]
loading image: srtitle400.ci8.png
detected format from filename: CI8
loaded srtitle400.ci8.png (640x800, LCT_RGB)
auto selected format: CI8
quantizing image(s) to 256 colors
auto detected hslices: 40 (w=640/16)
auto detected vslices: 50 (w=800/16)
compressed: ./srtitle400.ci8.sprite (512648 -> 99883, ratio 19.5%)

Notice that mksprite also supports libdragon asset compression, and by default it will compress images using the "level 1" compression. Compression ratio is usually similar or better than PNG compression.

mksprite is also able to automatically generate mipmaps, even while quantizing:

$ mksprite --format CI4 --mipmap BOX --verbose diamond0.png
Converting: diamond0.png -> ./diamond0.sprite [fmt=CI4 tiles=0,0 mipmap=BOX dither=NONE]
loaded diamond0.png (32x32, LCT_RGBA)
mipmap: generated 16x16
mipmap: generated 8x8
mipmap: generated 4x4
quantizing image(s) to 16 colors
auto detected hslices: 2 (w=32/16)
auto detected vslices: 2 (w=32/16)
compressed: ./diamond0.sprite (784 -> 252, ratio 32.1%)

In this case, the input 32x32 RGBA image was automatically scaled multiple times to generate the various mipmaps, and then all the mipmaps were converted to a single 16 color palette through quantization. This is important as to achieve the better quality, the choice of colors should take all mipmap levels into account.

Command line options

This is mksprite usage, that gives an overview of all options:

Usage: mksprite [flags] <input files...>

Command-line flags:
   -v/--verbose          Verbose output
   -o/--output <dir>     Specify output directory (default: .)
   -f/--format <fmt>     Specify output format (default: AUTO)
   -D/--dither <dither>  Dithering algorithm (default: NONE)
   -c/--compress <level> Compress output files (default: 1)
   -d/--debug            Dump computed images (eg: mipmaps) as PNG files in output directory

Sampling flags:
   --texparms <x,s,r,m>          Sampling parameters:
                                 x=translation, s=scale, r=repetitions, m=mirror
   --texparms <x,x,s,s,r,r,m,m>  Sampling parameters (different for S/T)

Mipmapping flags:
   -m/--mipmap <algo>                    Calculate mipmap levels using the specified algorithm (default: NONE)
   --detail [<image>[,<fmt>]][,<factor>] Activate detail texture:
                                         <image> is the file to use as detail (default: reuse input image)
                                         <fmt> is the output format (default: AUTO)
                                         <factor> is the blend factor in range 0..1 (default: 0.5)
   --detail-texparms <x,x,s,s,r,r,m,m>   Sampling parameters for the detail texture

Supported formats: AUTO, RGBA32, RGBA16, IA16, CI8, I8, IA8, CI4, I4, IA4, ZBUF
Supported mipmap algorithms: NONE (disable), BOX
Supported dithering algorithms: NONE (disable), RANDOM, ORDERED.
Note that dithering is only applied while quantizing an image.

All PNG files passed on the command line are converted separately, generating one .sprite file for each of them. By default, the .sprite file is generated in the current directory, but it is possible to change this via -o/--output.

Sprite formats

This tables lists the formats supported by N64; for each one, it lists the PNG formats that are supported in input when using the --format option, and what kind of PNG must be supplied so that the format is autodetected by mksprite without an explicit --format.

N64 format Supported PNG formats Autodetection
CI4
  • LCT_PALETTE
  • LCT_RGB/LCT_RGBA (quantized)
  • LCT_PALETTE with <= 16 actually used colors
    CI8
  • LCT_PALETTE
  • LCT_RGB/LCT_RGBA (quantized)
  • LCT_PALETTE with > 16 actually used colors
    I4
  • LCT_PALETTE (greyscaled)
  • LCT_RGB/LCT_RGBA (greyscaled)
  • LCT_GREY
  • LCT_GREY_ALPHA
  • LCT_GREY with <= 16 actually used grey levels
    I8
  • LCT_PALETTE (greyscaled)
  • LCT_RGB/LCT_RGBA (greyscaled)
  • LCT_GREY
  • LCT_GREY_ALPHA
  • LCT_GREY with > 16 actually used grey levels
    IA4
  • LCT_PALETTE (greyscaled)
  • LCT_RGB/LCT_RGBA (greyscaled)
  • LCT_GREY
  • LCT_GREY_ALPHA
  • LCT_GREY_ALPHA with bitdepth < 4
    IA8
  • LCT_PALETTE (greyscaled)
  • LCT_RGB/LCT_RGBA (greyscaled)
  • LCT_GREY
  • LCT_GREY_ALPHA
  • LCT_GREY_ALPHA with bitdepth >= 4 and < 8
    IA16
  • LCT_PALETTE (greyscaled)
  • LCT_RGB/LCT_RGBA (greyscaled)
  • LCT_GREY
  • LCT_GREY_ALPHA
  • LCT_GREY_ALPHA with bitdepth >= 8
    RGBA16
  • LCT_PALETTE
  • LCT_RGB/LCT_RGBA
  • LCT_GREY
  • LCT_GREY_ALPHA
  • LCT_RGB/LCT_RGBA
    RGBA32
  • LCT_PALETTE
  • LCT_RGB/LCT_RGBA
  • LCT_GREY
  • LCT_GREY_ALPHA
  • --
    ZBUF
  • LCT_GREY (8bpp or 16bpp)
  • --

    To select a specific format which is not the auto-selected default, you can:

    • Use the --format command line option expliclty
    • Rename the file so that it contains requested format as an additional extension (eg: image.ia8.png)

    ZBUF format

    The special ZBUF format is used to create a sprite encoded in the same format of the RDP Z-Buffer (a custom 14-bit floating point format). This can be useful to preload the Z-Buffer with some precalculated values; for instance, it is useful to reproduce a 2D background which is intermexed with 3D models (like Final Fantasy 7, Resident Evil 2, etc.).

    The input image must be a greyscale PNG, where black is used for near pixels, and white for far pixels. Notice that the Z-Buffer has much more 8bpp of precision, so it is suggested to render the PNG with a depth of 16 bpp, to preserve information. 8-bit greyscale PNGs are accepted but the precision will be lower.

    Sampling parameters

    It is possible to optionally embed the RDP texture sampling parameters within the .sprite file. These parameters affect how RDP samples the texture while used, and they allow effect like wrapping, mirroring, etc. If a sprite embeds sampling parameters, they can be queried at runtime via sprite_get_texparms(), and they are automatically applied when running rdpq_sprite_upload() to load the sprite into TMEM.

    This is the option to specify the parameters:

       --texparms <x,s,r,m>          Sampling parameters:
                                     x=translation, s=scale, r=repetitions, m=mirror
    
    • translation: this is a floating point signed value that specifies a translation value applied to the texture.
    • scale: this is an integer scale factor to apply to the texture, expressed as a power-of-two exponent. For instance, specifying 3 makes the texture 8 times bigger (virtually). Notice that scale is applied before any translation. Negative values are also allowed (to shrink the texture).
    • repetitions: a positive floating point value specifying how many times the texture (virtually) repeats, before clamping. For instance, assuming a 32x32 texture, specifying 2.5 as repetitions means that the texture repeats two and a half time (creating a virtual 80x80 texture), and outside that it is clamped. NOTE: only texture whose size is a power of two can repeat. Specifying 1 causes the texture to just clamp outside. Specifying a very high number or inf (for infinite) effectively causes the texture to repeat forever.
    • mirror: either 0 or 1. When 1, at each repetition, the texture is mirrored.

    Notice that the above settings apply to both the horizontal and vertical coordinates. If you want to specify different behaviors for horizontal and vertical coordinates, you can use this variant of the command line option:

       --texparms <x,x,s,s,r,r,m,m>  Sampling parameters (different for S/T)
    

    where each parameter must be specified twice (once per axis).