Dreamcast textures

Anything related in any way to game development as a whole is welcome here. Tell us about your game, grace us with your project, show us your new YouTube video, etc.

Moderator: PC Supremacists

Dreamcast textures

Postby Tvspelsfreak on Fri Apr 25, 2014 10:20 pm

I have done a lot of research on the topic of Dreamcast textures lately, and I've made some major discoveries in the process. The top one being that any format can be compressed, including normal maps and paletted textures.

I've created a tool that can convert images to any format supported by the Dreamcast. You can find it here:
https://github.com/tvspelsfreak/texconv

Some key features:
* Full support for all Dreamcast formats.
* Supports compression of all formats.
* Support for strided textures.
* Mipmaps can be generated automatically or be input by the user, or any mix of the two.
* Can generate previews of all texture formats. No need to load the texture on hardware to see what it looks like.
* Can generate images that visualize codebook usage for compressed textures.

The readme has a good deal of information, so I'll include it here as well. I'm sure there's a lot of stuff I forgot to mention but I'll fill in the blanks later. I haven't released a loader either, but the file format is pretty simple and documented in the readme.

I doubt it's possible to try out compressed bumpmaps or compressed paletted textures in emulators since I haven't seen a single emulator that handles it. I even doubt any game ever made use of it since it was added to the official SDK about a month before the system was discontinued.

Let me know if you find any issues with the converter. It should be fully platform independent, but I've only tested it on linux. Also, the file handling should be endian-independent, but I've only tested it on little endian.

Code: Select all
texconv is a utility for creating textures for the SEGA Dreamcast hardware.

Requires Qt 5.2 or newer.

Supports all image formats supported by Qt.
At the time I'm writing this, these formats are supported:

Format   Description                        Qt's support
BMP      Windows Bitmap                     Read/write
GIF      Graphic Interchange Format (optional)   Read
JPG      Joint Photographic Experts Group      Read/write
JPEG   Joint Photographic Experts Group      Read/write
PNG      Portable Network Graphics            Read/write
PBM      Portable Bitmap                     Read
PGM      Portable Graymap                  Read
PPM      Portable Pixmap                     Read/write
XBM      X11 Bitmap                        Read/write
XPM      X11 Pixmap                        Read/write



USAGE
=====

texconv --in <filename> --out <filename> --format <pixelformat> [flags...]



EXAMPLES
========

texconv --in img.jpg --out a.tex --format RGB565
   Creates an RGB565 texture called 'a.tex' using 'img.jpg' as input.

texconv --in img.jpg --out a.tex --format PAL8BPP
   Creates an 8-bit paletted texture called 'a.tex' using 'img.jpg' as input.
   A palette file 'a.tex.pal' will also be created.

texconv --in img.jpg --out a.tex --format YUV422 --compress --mipmap
   Creates a compressed, mipmapped YUV texture 'a.tex' using 'img.jpg' as
   input.

texconv --in img1.jpg --in img2.png --format RGB565 --mipmap
   Also assuming "img1.jpg" is 64x64 and 'img2.png' is 16x16, creates a
   mipmapped RGB565 texture with mipmap levels like this:
      64x64 - 'img1.jpg'
      32x32 - 'img1.jpg' (downscaled)
      16x16 - 'img2.png'
        8x8 - 'img2.png' (downscaled)
        4x4 - 'img2.png' (downscaled)
        2x2 - 'img2.png' (downscaled)
        1x1 - 'img2.png' (downscaled)

texconv --in img.jpg --out a.tex --format PAL4BPP --compress
      --preview preview.png --vqcodeusage --usage.png
   Creates a compressed 4-bit paletted texture 'a.tex' using 'img.jpg' as
   input. A palette file 'a.tex.pal' will also be created. A preview file
   'preview.png' showing what the texture looks is generated as well as
   an image 'usage.png' that visualizes codebook usage for 'a.tex'.


GENERAL INFO
============

These are all limitations set by the hardware.

*   Input image dimensions must be one of the following: 8, 16, 32, 64, 128,
   256, 512 or 1024. There are two exceptions to this rule, see the -mipmap
   and -stride flags for more info.

*   Mipmapped and compressed textures must be square.

*   Strided textures can't be compressed, twiddled or mipmapped.

*   Bumpmaps and paletted textures can't be strided.


PIXEL FORMATS
=============

RGB565
   16-bit RGB texture without alpha.

ARGB1555
   16-bit texture with 1-bit alpha. Each texel is either fully opaque or fully
   transparent.

ARGB4444
   16-bit texture with full alpha.

YUV422
   16-bit texture without alpha. The YUV color space takes human perception
   into account, and thus offers higher percieved quality than the RGB color
   space.

BUMPMAP
   16-bit normal map. Each texel consist of a pair of 8-bit values (S and R)
   which represent a normal in spherical coordinates.
   S = polar angle. 0-255 maps to 0-89 degrees.
   R = azimuthal angle. 0-255 maps to 0-359 degrees.

PAL4BPP
   4BPP paletted texture. The palette can contain a maximum of 16 colors.
   If the input images contain more colors than the palette can hold,
   the color count will be automatically reduced by the converter.
   An additional palette file <outfile>.pal will be written for this format.

PAL8BPP
   8BPP paletted texture. The palette can contain a maximum of 256 colors.
   If the input images contain more colors than the palette can hold,
   the color count will be automatically reduced by the converter.
   An additional palette file <outfile>.pal will be written for this format.



PROGRAM FLAGS
=============

-i <filename> or -in <filename>
   One or more images to use as input. Specify one image for non-mipmapped
   textures and one or more images for   mipmapped textures.

-o <filename> or -out <filename>
   Output file.

-f <format> or -format <format>
   One of the aforementioned pixel formats.

-m or -mipmap
   Generate/allow mipmaps. If this flag is specified, you can supply
   additional images down to a 1x1 size with the '-in' flag to be used for the
   different mipmap levels. Keep in mind though that at least one image must
   be 8x8 or larger. Any missing mipmap levels will be generated by
   downscaling the   next size up.

-c or -compress
   Output a compressed texture. Compressed textures are 1/8th the size of
   their uncompressed counterparts, plus a 2kB codebook overhead per texture.

-s or -stride
   Output a strided texture. Strided textures allow for the width of the
   texture to be any multiple of 32 from 32 to 992. See the topic on strided
   textures for more info.

-p <filename> or -preview <filename>
   Generate a preview image showing what the texture looks like.

-v or -verbose
   Extra printouts. The converter will only print warnings and errors unless
   this flags is set.

-n or -nearest
   Use nearest-neighbor filtering when generating missing mipmap levels. This
   is the default filter for paletted, mipmapped textures to avoid introducing
   additional colors to the palette.

-b or -bilinear
   Use bilinear filtering when generating missing mipmap levels. This is the
   default filter for all 16-bit textures, for higher quality mipmaps.

-vqcodeusage <filename>
   Outputs an image that visualizes compression code usage. Will only do
   something for compressed textures.



TEXTURE FILE FORMAT
===================

Each texture starts with a 16-byte header:

typedef struct {
   char   id[4];   // 'DTEX'
   short   width;
   short   height;
   int      type;
   int      size;
} header_t;

It is then followed by 'size' bytes of texture data which can be uploaded
directly to VRAM. The size will always be a multiple of 32 bytes to allow
for DMA transfers.

'type' contains the various flags and the pixel format packed together:
bits 0-4 : Stride setting.
   The width of stride textures is NOT stored in 'width'. To get the actual
   width, multiply the stride setting by 32. The next power of two size up
   from the stride width will be stored in 'width'.
bit 25 : Stride flag
   0 = Non-strided
   1 = Strided
bit 26 : Untwiddled flag
   0 = Twiddled
   1 = Untwiddled
bits 27-29 : Pixel format
   0 = ARGB1555
   1 = RGB565
   2 = ARGB4444
   3 = YUV422
   4 = BUMPMAP
   5 = PAL4BPP
   6 = PAL8BPP
bit 30 : Compressed flag
   0 = Uncompressed
   1 = Compressed
bit 31 : Mipmapped flag
   0 = No mipmaps
   1 = Mipmapped



PALETTE FILE FORMAT
===================

Each palette starts with an 8-byte header:

typedef struct {
   char   id[4];   // 'DPAL'
   int      numcolors;
} header_t;

It is then followed by 'numcolors' 32-bit packed ARGB values.

The Dreamcast supports four different palette color formats, RGB565, ARGB1555
ARGB4444 and ARGB8888. The palette format only uses the last one. But it can
easily be converted by the user to any of the other formats when the palette
is loaded. See the 'to16BPP' function if you need to know how to do the
conversion.



TWIDDLED TEXTURES
=================

For twiddled textures, the texels will be arranged in a way that is more cache
friendly. Adjacent texels will be closer to each other in memory compared to
textures stored in normal scan order. This increases rendering performance.
All textures (except for strided ones) output by the converter are twiddled.



STRIDED TEXTURES
================

Strided textures allow for the width of the texture to be any multiple of 32
from 32 to 992. The stride texture width is a global setting on the Dreamcast,
so all strided textures rendered in the same frame must have the same width.
They also cannot be twiddled, mipmapped or compressed, and cannot be used
with the bumpmap or paletted formats.

Since they cannot be twiddled, the rendering performance will also be lowered
for strided textures.

The texture width for strided textures will be set to the next power of two
size up while the actual size is divided by 32 and packed in the 'type' field.
This is because the width set in the polygon header must be a power of two.
So for a 320x256 texture you would get:
width = 512
height = 256
packed stride setting = 10 (320/32)

So basically, when loading a strided texture, set the width in the polygon
header to 'width' and set the global stride setting to the packed setting
in 'type'.

You will also need to specify the U texture coordinate as if the texture
is actually 'width' wide.



COMPRESSED TEXTURES
===================

All textures (except strided ones) can be compressed using vector quantization.
This is a hardware feature on the Dreamcast and using compressed textures will
increase rendering performance at the possible cost of quality.

The compressed texture data always starts with a 2kB codebook followed by
compressed index data. The codebook contains 256 blocks of texels. For 16-bit
textures, each block represents 2x2 texels.

The codebook is followed by (width/blockwidth)x(height/blockheight) 8-bit
indices where each index refers to a block in the codebook. So if the first
index is 35, it means that the top left 2x2 pixel block in the resulting
texture is block 35 in the codebook.

Compressed paletted textures work the same way except the blocks represent 4x4
4-bit indices (for PAL4BPP) or 2x4 8-bit indices (for PAL8BPP). So there's an
extra level of lookup involved.


The size of a compressed texture is always 1/8th the size of an uncompressed one of the same format, plus 2kB of overhead for the codebook. So when compared to an ordinary uncompressed 16-bit texture we get:
8:1 ratio + 2kB overhead for compressed 16-bit textures.
16:1 ratio + 2kB overhead for compressed 8-bit paletted textures.
32:1 ratio + 2kB overhead for compressed 4-bit paletted textures.
The overhead is pretty significant for compressed paletted textures so the real max compression ratio is just past 31:1. Keep in mind that today's texture compression schemes usually have 4:1 to 8:1 ratios. So a 31:1 hardware compression ratio on a console released back in 1998 is pretty amazing.

Also, because of the fixed overhead, it's not worth using compression on very small textures since they'll end up larger than their uncompressed versions.

And now for some compression comparison images. These were all generated with the preview option.

Original image:
Image
16-bit compressed
8-bit paletted
8-bit paletted, compressed
4-bit paletted
4-bit paletted, compressed

Original image:
Image
16-bit compressed
8-bit paletted
8-bit paletted, compressed
4-bit paletted
4-bit paletted, compressed

Original image:
Image
16-bit compressed
8-bit paletted
8-bit paletted, compressed
4-bit paletted
4-bit paletted, compressed

As you can see, the higher compression ratios do a pretty good job on monochromatic textures like the last one. The quality loss is evident in the first two though, especially if you choose to have mipmaps as well.

I also made a quick video to show off the compressed normal maps.


And finally, here are a couple of images showing off what happens when you generate a preview of a mipmapped texture and what the vqcodeusage option produces.

Original image:
Image
Mipmapped preview
vqcodeusage option
Tvspelsfreak
Chaos Rift Junior
Chaos Rift Junior
 
Posts: 273
Joined: Wed Sep 29, 2004 6:53 pm
Location: Umeå, Sweden

Re: Dreamcast textures

Postby Falco Girgis on Fri Apr 25, 2014 10:22 pm

Jesus. Fucking. Christ. Almighty...

The biggest problem we were facing with the DC build has just been solved... You can even compress an already paletted texture? What the FUCK?! :shock:

I will be integrating this with ESTk right after the Kickstarter. :twisted:

edit: Jesus christ dude, I'm so fucking impressed... This is AMAZING progress, especially for a game like ours, where VRAM is our primary concern...

and I was also wondering what the best way to determine the compression scheme would be, but I could literally let the artists decide with your previewer... Thank god for your command-line arguments. Good call. ;)
"So what happens if the Elysian Shadows Kickstarter fails?"
Image
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
 
Posts: 10693
Joined: Thu May 20, 2004 3:04 pm
Location: Studio Vorbis, AL

Re: Dreamcast textures

Postby Tvspelsfreak on Sat Apr 26, 2014 8:28 am

Thanks man! :)

Yeah, the preview stuff is something I've always wanted. It's difficult to get a good look at the textures on the actual hardware, especially when you throw mipmaps into the equation.

I forgot to mention something about the bumpmap conversion. It expects you to input a normal map, not a height map. It doesn't handle height maps at all. Also, the normal map parsing is set so that the blue channel (0..255) represents Z (0..1). Some normal maps might not use the full positive range, but expects it to represent Z (-1..1). I know Doom 3 does that.

Also, I should mention that the Dreamcast has 1024 on-chip palette entries. Enough for 4 8-bit palettes or 64 4-bit palettes. So there's a limit to how many paletted textures you can effectively have. I used to have a tool that could sync textures to share the same palette as long as the total color count was still within the palette limits. I guess an updated version of that would be nice to have. And now that I think about it, I could do a vector quantization pass to create an optimal shared palette for multiple textures even if the total color count is way beyond what fits in the palette...
Tvspelsfreak
Chaos Rift Junior
Chaos Rift Junior
 
Posts: 273
Joined: Wed Sep 29, 2004 6:53 pm
Location: Umeå, Sweden

Re: Dreamcast textures

Postby Falco Girgis on Sat Apr 26, 2014 9:32 am

Yeah, I think an updated version of palsync would be very nice to have!

And the normal map part is fine, that's what our engine loads anyway (rather than a height map). I may have to add some intermediary code to ESTk to fuck with the Z channel of the normal map before passing it to your tool, but that's not a big deal at all. :D
"So what happens if the Elysian Shadows Kickstarter fails?"
Image
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
 
Posts: 10693
Joined: Thu May 20, 2004 3:04 pm
Location: Studio Vorbis, AL

Re: Dreamcast textures

Postby dandymcgee on Sat Apr 26, 2014 12:05 pm

This is some seriously impressive stuff man! Very interesting read, thank you for posting it here.
Falco Girgis wrote:It is imperative that I can broadcast my narcissistic commit strings to the Twitter! Tweet Tweet, bitches! :twisted:
User avatar
dandymcgee
ES Beta Backer
ES Beta Backer
 
Posts: 4911
Joined: Tue Apr 29, 2008 4:24 pm
Location: New Hampshire

Re: Dreamcast textures

Postby Light-Dark on Sat Apr 26, 2014 3:00 pm

:worship: Great job and timing man! I've coincidentally been looking into/working on integrating texture compression into the Dreamcast build of my engine. Thanks for sharing this:D!
<tpw_rules> LightDark: java is a consequence of inverse moore's law: every 18 months, the average program will be twice as slow. therefore, computers always run at the same percevied speed. java's invention was a monumental step

Image
User avatar
Light-Dark
Dreamcast Developer
Dreamcast Developer
 
Posts: 315
Joined: Sun Mar 13, 2011 8:57 pm
Location: Canada


Return to Game Development

Who is online

Users browsing this forum: No registered users and 2 guests

cron