KMG Textures

From DCEmulation
Revision as of 08:55, 16 March 2016 by Bogglez (talk | contribs) (Created page with "= About KMG files = There are many image file formats out there. First of all the image data may be encoded in various ways. For example the pixel format could be RGB565 or A...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

About KMG files

There are many image file formats out there.

First of all the image data may be encoded in various ways. For example the pixel format could be RGB565 or ARGB4444. Furthermore the image data may be paletted, twiddled or compressed.

The image may also come with mipmaps (smaller versions of itself). The mipmaps could be stored from small to big or big to small, with padding, etc.

Lastly, meta information such as the dimensions, used pixel format, how many mipmaps are available, whether compression was applied, etc. must be stored somehow.

Therefore, instead of just storing the raw image data, so called container formats are used. KOS provides an image container format called KMG.

You are in no way forced to use this format and may want to create your own for advanced use cases, but it gets the basic job done and comes with convenient functions and a conversion program in KOS.

This tutorial will explain how to convert images to Dreamcast-friendly formats and pack them into a KMG container file. It will then explain how to load the data into memory, ready to be used in drawing code.


Directory setup

In your project's folder, you should create a folder named assets and another one named romdisk (names can be changed).

assets will contain your raw image files. assets/foo.png will be converted to romdisk/foo.kmg.

The raw asset files are put into a different directory, because only the converted files will be used in the game and the raw asset files would only take up space.

Makefile rules

Romdisk rules

These rules will create a romdisk and put the converted images in it.

romdisk.o: romdisk.img
       $(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o

This rule turns files of the form assets/foo.png into romdisk/foo.kmg and adds them to the romdisk as a requirement.

romdisk.img: $(patsubst assets/%.png,romdisk/*.kmg,$(wildcard assets/*.png))
       $(KOS_GENROMFS) -f romdisk.img -d romdisk -v

The converted image files will be available as /rd/foo.kmg during runtime.

Conversion rule

Next we need to call a program to actually convert foo.png to foo.kmg. KOS provides an image data conversion tool that can optionally put the resulting data in the KMG container format. You can find it in the folder kos/utils/vqenc.

Usage: vqenc [options] image1 [image2..]
       -t, --twiddle   create twiddled textures
       -m, --mipmap    create mipmapped textures (EXPERIMENTAL)
       -v, --verbose   verbose
       -d, --debug     show debug information
       -q, --highq     higher quality (much slower)
       -k, --kmg       write a KMG for output
       -a, --alpha     use alpha channel (and output ARGB4444)
       -b, --amask     use 1-bit alpha mask (and output ARGB1555)

The following Makefile rule should be added to use it to convert images:

romdisk/%.kmg: assets/%.png
       $(KOS_BASE)/utils/vqenc/vqenc -v -t -q -k $<
       mv assets/$*.kmg romdisk/

-v will turn on verbose conversion information and give you some additional insight.

-t will reorder the pixels into the order the PVR graphics chip can render the fastest.

-q will tell the conversion program that it can take its time to perform a better VQ compression.

-k will save the converted and compressed image data in a .kmg file. Otherwise it will create a .vq file without meta information which you could use in your own image container format.

Since vqenc does not accept a destination directory name, the result is moved to the romdisk directory manually. In Make, $* represents the result of the % placeholder in the rule line.

After typing make you should see that foo.kmg is put into the romdisk, but foo.png is not.


To gain access to the romdisk and read files in the romdisk directory as /rd/foo.kmg, you need to add the following:

extern uint8 romdisk[];

The loading function will load the texture and put its content into video memory.

#include <kmg/kmg.h>
#include <dc/pvr.h>
pvr_ptr_t load_kmg(char const* filename, uint32* w, uint32* h, uint32* format) {
       kos_img_t img;
       pvr_ptr_t rv;
       if(kmg_to_img(filename, &img)) {
               printf("Failed to load image file: %s\n", filename);
               return NULL;
       if(!(rv = pvr_mem_malloc(img.byte_count))) {
               printf("Couldn't allocate memory for texture!\n");
               kos_img_free(&img, 0);
               return NULL;
       pvr_txr_load_kimg(&img, rv, 0);
       kos_img_free(&img, 0);
       *w = img.w;
       *h = img.h;
       *format = img.fmt;
       return rv;

Usage in main():

 int main() {
       /* ... */
       uint32 w, h, format;
       pvr_ptr_t txr = load_kmg("/rd/image.kmg", &w, &h, &format);
         printf("Loaded /rd/image.kmg with dimensions %ux%u, format %u\n", w, h, format);

You can now use the PVR API to draw this texture.