TIM file format

Code example

https://github.com/ABelliqueux/nolibgs_hello_worlds/tree/main/hello_sprt
https://github.com/ABelliqueux/nolibgs_hello_worlds/tree/main/hello_poly_ft
https://github.com/ABelliqueux/nolibgs_hello_worlds/tree/main/hello_poly_gt

Standard bitmap images that can be transferred directly to the PSX VRAM.

Can be 4bit or 8bit with a CLUT (Colour Look Up Table), 16bit or 24 bit in direct color.

See this page for further information on how information is stored in the 16/24bpp modes.

You can access the TIM mode through TIM_IMAGE->mode. Mode can be :

See FileFormat47.pdf, p.179

Transparency

In 16bpp mode, only 15b are used for colors (R 5, G 5, B 5). The 15th bit is defined as the STP or Semi-Transparency flag.

A primitive transparency is set with SetSemiTrans().

The only case where a primitive with unset (=0) STP is transparent is when all values are 0. i.e ; using STP 0, B 0, G 0, R 0
will result in a transparent pixel wether the primitive is set to semi-tranparent or not.

Here are the transparency modes for various values on semi-transparent and opaque primitives :

STP, B, G, R (0, 0, 0, 0) (1, 0, 0, 0) (0, n, n, n) (1, n, n, n)
Non-transparent primitive Transparent Black Non-transparent Non-transparent
Semi-transparent primitive Transparent Semi-transparent Non-transparent black Semi-transparent

See FileFormat47.pdf, p.56, p.192,
LibOver47.pdf, p.107, Table 8-12:

Here is an overview of the various STP modes :

STP

In the following picture, STP refers to the transparency rate mode as seen in LibRef47.pdf, p.306 :

STP rate

img2tim semi-transparency options

img2tim has several options related to pixel transparency :

Tools

You can use open source tools : Gimp, Aseprite

To convert your image files to TIM, use IMG2TIM :

4bpp and 8bpp specificities

If you want to generate 4bpp and 8bpp TIMs, your original image must be in indexed mode with a palette.

See FileFormat47.pdf, p.182

You can use TIMTOOL.EXE from legacy PsyQ to check your TIM files, or use Lameguy64's TIMedit

Reproducing the TIM in this example

Image > 4bpp, 8bpp

To convert your images to palettized 4bpp and 8bpp pngs, you can use pngquant :

4bpp (16 colors) image :

pngquant 16 input.png -o output.png --force 

8bpp (256 colors) image :

pngquant 256 input.png -o output.png --force 

Alternatively, you can use imagemagick :

4bpp (16 colors) image :

convert input.png -colors 16 output.png 

8bpp (256 colors) image :

convert input.png -colors 256 output.png

PNG > Tim

img2tim -bpp 4 -org 512 0 -plt 0 481 -usealpha -o TIM4.tim TIM4.png 
img2tim -bpp 8 -org 512 256 -plt 0 480 -usealpha -o TIM8.tim TIM8.png 
img2tim -bpp 16 -org 768 0 -usealpha -o TIM16.tim TIM16.png 

Content of Makefile :

SRCS = hello_sprt.c \
../common/crt0/crt0.s \
TIM/TIM16.tim \
TIM/TIM8.tim \
TIM/TIM4.tim \

Using the TIM file in code

TODO : Make this presentable

// Some structures to handle TIM files 

// Access Pixels STP, R, G, B 
typedef struct RGB_PIX {
    u_int  R:5, G:5, B:5, STP:1;
} RGB_PIX;


typedef struct PIXEL {
    u_long bnum;
    u_short DX, DY;
    u_short W, H;
    RGB_PIX data[]; 
} PIXEL;

typedef struct CLUT {
    u_long bnum;
    u_short DX, DY;
    u_short W, H;
    u_short clut[]; 
} CLUT;

typedef struct TIM_FILE_CLUT{
    u_long ID;
    u_long flag;
    u_long clut;
    PIXEL pixel[];
} TIM_FILE_CLUT;

typedef struct TIM_FILE{
    u_long ID;
    u_long flag;
    PIXEL pixel[];
} TIM_FILE;

// If we were using C++, we could use templates 
//~ struct EmbeddedClut { u_long clut; };
//~ struct NoEmbeddedClut { };
//~ template<has_clut>
//~ struct TIM_FILE {
    //~ u_long ID;
    //~ u_long flag;
    //~ std::conditional<has_clut, EmbeddedClut, NoEmbeddedClut> clut;
    //~ PIXEL pixel[];
//~ };

// 16bpp TIM
// STP set on black pixels ( STP, B, R, G == 1, 0, 0 ,0)
extern TIM_FILE _binary_TIM_transBlack_tim_start;
// STP set on image's alpha ( STP, B, R, G == 1, n, n ,n)
extern TIM_FILE _binary_TIM_transAlpha_tim_start;
// STP set on image's alpha ( STP, B, R, G == 1, n, n ,n) with threshold (img2tim -alpt option)
extern TIM_FILE _binary_TIM_transAlphaS_tim_start;
// STP set on 8bpp TIM's CLUT index 
extern TIM_FILE _binary_TIM_trans8bpp_tim_start;
// Store in an array so we can iterate over it
TIM_FILE * timFiles[4];
TIM_IMAGE timImages[4];

FntPrint("RGB: %d\n", _binary_TIM_transBlack_tim_start.pixel->data[0].R );                   
FntPrint("RGB: %d %d %d %d", timFiles[0]->pixel->data[8192].STP, timFiles[0]->pixel->data[8192].R, timFiles[0]->pixel->data[8192].G, timFiles[0]->pixel->data[8192].B );  

Links