PVR Spritesheets

From DCEmulation
Revision as of 14:20, 20 March 2016 by Bogglez (talk | contribs) (Makefile)
Jump to navigation Jump to search

(currently working on this)

About this tutorial

In this tutorial you will learn:

  • Generating a spritesheet from a directory full of single images automatically.
  • Converting the spritesheet into a PVR paletted texture automatically.
  • Loading the spritesheet into the PVR for drawing.
  • Setting up the palette for drawing.
  • Drawing a user interface (with a dynamic health bar).
  • Drawing animated characters.
  • Using the PVR's sprite drawing mode (instead of polygons)

This will be the end result:

Spritesheet tutorial.gif

Required software

Before you can get started, you will need to install two tools.


The first tool you need is TexturePacker. It packs single images together into one big spritesheet, so you don't need to do this manually. We will make it do it for us using Make.

TexturePacker has some Pro features, but this tutorial limits itself to its free features.

This image should give you an idea about this tools's usefulness:

Spritesheet tutorial texturepacker.png

It will also create text files of the following format:

mage_mage_combat6, 244, 103, 122, 103, 0, 0, 0, 0
mage_mage_combat7, 366, 103, 122, 103, 0, 0, 0, 0
mage_mage_idle0, 0, 206, 79, 93, 0, 0, 0, 0
mage_mage_idle1, 79, 206, 79, 94, 0, 0, 0, 0
mage_mage_idle2, 158, 206, 82, 94, 0, 0, 0, 0
mage_mage_idle3, 240, 206, 85, 94, 0, 0, 0, 0

The example code will parse this information to find out where each sprite within the spritesheet is.


The next tool you need is texconv by tvspelsfreak.

texconv is an alternative to KOS' vqenc for converting images such as PNG into texture formats supported by the Dreamcast's PVR graphics chip. It doesn't create KMG files, instead it creates its own DTEX format, but provides other nice features. For this tutorial paletted textures are essential.

Another feature that is used is its preview feature. It will basically convert the converted texture back to PNG so you can check the quality of the conversion.

texconv has a dependency on Qt5, so install that first.

On Debian-based systems this will get you running:

sudo apt install qt5-default qtbase5-dev
git clone https://github.com/tvspelsfreak/texconv
cd texconv

You can then use ./texconv. I suggest you put it somewhere in your PATH for convenient global access.

texconv offers the following options (options used in this tutorial are marked as bold):

Usage: ./texconv [options]
Texture formats:
 -h, --help                Displays this help.
 -i, --in <filename>       Input file(s). (REQUIRED)
 -o, --out <filename>      Output file. (REQUIRED)
 -f, --format <format>     Texture format. (REQUIRED)
 -m, --mipmap              Generate/allow mipmaps.
 -c, --compress            Output a compressed texture.
 -s, --stride              Output a stride texture.
 -p, --preview <filename>  Generate a texture preview.
 -v, --verbose             Extra printouts.
 -n, --nearest             Use nearest-neighbor filtering for scaling mipmaps.
 -b, --bilinear            Use bilinear filtering for scaling mipmaps.
 --vqcodeusage <filename>  Output an image that visualizes compression code

Downloading and running the example code

After installing the required software, you can download the example source code for this tutorial.

Unzip the archive and open the directory kos_spritesheet_tutorial. You will find the following directory and file structure:

  • assets: Raw art assets that will be turned into spritesheets and converted to Dreamcast PVR textures.
  • build: Contains temporary files. For example build/ui_sheet.png will contain all art assets from assets/spritesheets/ui/*.
  • main.c: Loading, parsing and drawing code.
  • Makefile: Build system. Also calls TexturePacker and texconv to create the spritesheets automatically upong changing anything.
  • readme.txt: License for the used artwork.
  • romdisk: Contains the files that will be available at runtime of the game.

After typing make, you should get the following output:

kos-cc -std=c11 -c main.c -o main.o
Generating spritesheet build/stage1_actors_sheet.png from assets/spritesheets/stage1_actors
TexturePacker --sheet build/stage1_actors_sheet.png \
       --format gideros --data romdisk/stage1_actors_sheet.txt \
       --size-constraints POT --max-width 1024 --max-height 1024 \
       --pack-mode Best --disable-rotation --trim-mode None \
       --trim-sprite-names \
       --algorithm Basic --png-opt-level 0 --extrude 0 --disable-auto-alias \
Resulting sprite sheet is 512x1024
Writing sprite sheet to build/stage1_actors_sheet.png
Writing romdisk/stage1_actors_sheet.txt
Converting romdisk/stage1_actors_sheet.dtex < build/stage1_actors_sheet.png
texconv -i build/stage1_actors_sheet.png -o romdisk/stage1_actors_sheet.dtex -f PAL8BPP -p build/stage1_actors_preview.png
Generating spritesheet build/ui_sheet.png from assets/spritesheets/ui
TexturePacker --sheet build/ui_sheet.png \
       --format gideros --data romdisk/ui_sheet.txt \
       --size-constraints POT --max-width 1024 --max-height 1024 \
       --pack-mode Best --disable-rotation --trim-mode None \
       --trim-sprite-names \
       --algorithm Basic --png-opt-level 0 --extrude 0 --disable-auto-alias \
Resulting sprite sheet is 512x128
Writing sprite sheet to build/ui_sheet.png
Writing romdisk/ui_sheet.txt
Converting romdisk/ui_sheet.dtex < build/ui_sheet.png
texconv -i build/ui_sheet.png -o romdisk/ui_sheet.dtex -f PAL8BPP -p build/ui_preview.png
/opt/toolchains/dc/kos/utils/genromfs/genromfs -f romdisk.img -d romdisk -v
0    rom 56ef0c99         [0xffffffff, 0xffffffff] 37777777777, sz     0, at 0x0     
1    .                    [0x802     , 0x566411  ] 0040755, sz     0, at 0x20    
1    ..                   [0x802     , 0x56639f  ] 0040755, sz     0, at 0x40     [link to 0x20    ]
1    ui_sheet.dtex.pal    [0x802     , 0x5654fa  ] 0100644, sz  1032, at 0x60    
1    ui_sheet.txt         [0x802     , 0x5654f7  ] 0100644, sz   392, at 0x4a0   
1    stage1_actors_sheet.dtex [0x802     , 0x5654f3  ] 0100644, sz 524304, at 0x650   
1    stage1_actors_sheet.dtex.pal [0x802     , 0x5654f4  ] 0100644, sz   104, at 0x80690 
1    stage1_actors_sheet.txt [0x802     , 0x5654f2  ] 0100644, sz  1818, at 0x80730 
1    ui_sheet.dtex        [0x802     , 0x5654f8  ] 0100644, sz 65552, at 0x80e80 
/opt/toolchains/dc/kos/utils/bin2o/bin2o romdisk.img romdisk romdisk.o
kos-cc -o spritesheet.elf main.o romdisk.o -lkmg -lkosutils -lm

The executable will be called spritesheet.elf and can be run in an emulator or on your Dreamcast.


The Makefile and main.c are heavily commented, so I will only refer to the most important bits here.


If any of these rules confuse you, compare them to the output of the make command above and things should become clear.

The Makefile target spritesheet.elf (the executable of the game) depends on romdisk.o, which depends on romdisk.img.

All the converted spritesheets, their palettes, and the sprite geometry info will be stored in this romdisk, therefore romdisk.img must depend on those files. We don't care about the raw art assets, however, since they're not used at runtime.

To achieve this in Make, the name of all spritesheets needs to be generated first, i.e. assets/spritesheets/foo/*.png assets/spritesheets/bar/*.png needs to turn into foo bar

SPRITESHEET_NAMES := $(notdir $(wildcard assets/spritesheets/*))

Now romdisk.img should depend on romdisk/foo_sheet.dtex and romdisk/bar_sheet.dtex. But texconv will save the palette file separately, so we add romdisk/foo_sheet.dtex.pal etc.

SPRITESHEET_RESULT_FILES := $(patsubst %,romdisk/%_sheet.dtex,$(SPRITESHEET_NAMES))
	$(KOS_GENROMFS) -f romdisk.img -d romdisk -v

Next Make needs to know how to generate the dtex and dtex.pal files from the corresponding PNG using texconv.

romdisk/%_sheet.dtex romdisk/%_sheet.dtex.pal: build/%_sheet.png
	$(info Converting $@ < $<)
	texconv -i $< -o $@ -f PAL8BPP -p build/$*_preview.png

This rule requires that the sprites have been assembled as build/foo_sheet.png before (using TexturePacker), so that file becomes a dependency.

Notice how the texture format is set to PAL8BPP, allowing for 256 different colors in the palette. PAL4BPP is also a possibility. texconv assumes 32 bit colors in the palette. It implicitly creates the .dtex.pal file.

Also take a look at the build/foo_preview.png file to see whether you suffered quality loss during the conversion. This will happen if your input image has more than 256 colors in this case.

Lastly TexturePacker is called to turn all images in the directory assets/spritesheets/foo/ into build/foo_sheet.png and generate romdisk/foo_sheet.txt with the sprite geometry information. The txt file is stored in romdisk/ because we will parse it during runtime in order to draw the sprites. build/foo_sheet.png is just the temporary file to create the Dreamcast PVR texture romdisk/foo_sheet.dtex (and .pal).

TexturePacker is instructed to create power-of-two textures (e.g. 64x256) of maximum dimensions 1024x1024, because of the PVR graphics chip's limitations.

The options in the last line are necessary to disable pro-version features (otherwise TexturePacker will turn some sprites red).

build/%_sheet.png: assets/spritesheets/%
	$(info Generating spritesheet $@ from $^)
	TexturePacker --sheet $@ \
		--format gideros --data romdisk/$*_sheet.txt \
		--size-constraints POT --max-width 1024 --max-height 1024 \
		--pack-mode Best --disable-rotation --trim-mode None \
		--trim-sprite-names \
		--algorithm Basic --png-opt-level 0 --extrude 0 --disable-auto-alias \