summaryrefslogtreecommitdiff
path: root/tools/bmp2tim.c
diff options
context:
space:
mode:
authorXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
committerXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
commit7c24e9a9b02b04dcaf9507acb94091ea70a2c02d (patch)
treec28d0748652ad4b4222309e46e6cfc82c0906220 /tools/bmp2tim.c
parenta2b7b6bb1cc2f4a3258b7b2dbc92399d151f864d (diff)
downloadpsxsdk-7c24e9a9b02b04dcaf9507acb94091ea70a2c02d.tar.gz
Imported pristine psxsdk-20190410 from official repo
Diffstat (limited to 'tools/bmp2tim.c')
-rwxr-xr-xtools/bmp2tim.c895
1 files changed, 895 insertions, 0 deletions
diff --git a/tools/bmp2tim.c b/tools/bmp2tim.c
new file mode 100755
index 0000000..12558b7
--- /dev/null
+++ b/tools/bmp2tim.c
@@ -0,0 +1,895 @@
+/*
+ * bmp2tim
+ *
+ * Converts a bitmap to a TIM image
+ *
+ * TEST output in various color depths... and check for issues on big-endian machines
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define BMP2TIM_VERSION "0.5"
+
+enum
+{
+ BITMAPINFOHEADER,
+ BITMAPV2INFOHEADER,
+ BITMAPV3INFOHEADER,
+ BITMAPV4HEADER,
+ BITMAPV5HEADER,
+};
+
+typedef struct
+{
+ unsigned char r, g, b;
+}PS_RGB;
+
+typedef struct
+{
+ int w, h;
+ int depth;
+ // 0 = r, 1 = g, 2 = b, 3 = alpha
+ unsigned int mask[4];
+ unsigned int shift[4];
+ unsigned int bits[4];
+ unsigned char hdr_type;
+ void *data;
+}PS_BITMAP;
+
+int do_clut = 0;
+unsigned int clut_x, clut_y;
+
+unsigned int org_x = 0;
+unsigned int org_y = 0;
+
+int tim_depth;
+
+unsigned int tim_flag;
+
+int set_stp_bit = 0;
+
+int transparent_black = 0;
+int magic_pink = 0;
+int raw_flag = 0;
+
+PS_RGB *ps_default_palette;
+
+unsigned short read_le_word(FILE *f)
+{
+ unsigned char c;
+ unsigned short i;
+
+ fread(&c, sizeof(char), 1, f);
+ i = c;
+ fread(&c, sizeof(char), 1, f);
+ i|=(c<<8);
+
+ return i;
+}
+
+unsigned int read_le_dword(FILE *f)
+{
+ unsigned char c;
+ unsigned int i;
+
+ fread(&c, sizeof(char), 1, f);
+ i = c;
+ fread(&c, sizeof(char), 1, f);
+ i|=(c<<8);
+ fread(&c, sizeof(char), 1, f);
+ i|=(c<<16);
+ fread(&c, sizeof(char), 1, f);
+ i|=(c<<24);
+
+ return i;
+}
+
+
+void write_le_word(FILE *f, unsigned short leword)
+{
+ unsigned char c;
+
+ c = leword & 0xff;
+ fwrite(&c, sizeof(char), 1, f);
+ c = leword >> 8;
+ fwrite(&c, sizeof(char), 1, f);
+}
+
+void write_le_dword(FILE *f, unsigned int ledword)
+{
+ unsigned char c;
+ int x;
+
+ for(x = 0; x < 4; x++)
+ {
+ c = (ledword >> (x<<3)) & 0xff;
+ fwrite(&c, sizeof(char), 1, f);
+ }
+}
+
+PS_BITMAP *ps_create_bitmap(int w, int h, int depth)
+{
+ PS_BITMAP *bm;
+
+ bm = malloc(sizeof(PS_BITMAP));
+
+ bm->w = w;
+ bm->h = h;
+ bm->depth = depth;
+
+ switch(depth)
+ {
+ case 1:
+ bm->data = malloc((w*h)/8);
+ break;
+ case 4:
+ bm->data = malloc((w*h)/2);
+ break;
+ case 8:
+ bm->data = malloc(w*h);
+ break;
+ case 15:
+ case 16:
+ bm->data = malloc((w*h)*2);
+ break;
+ case 24:
+ bm->data = malloc((w*h)*3);
+ break;
+ case 32:
+ bm->data = malloc((w*h)*4);
+ break;
+ }
+
+ return bm;
+}
+
+void ps_destroy_bitmap(PS_BITMAP *bm)
+{
+ free(bm->data);
+ free(bm);
+}
+
+
+PS_BITMAP *ps_load_bitmap(char *filename, PS_RGB *palette)
+{
+ FILE *bf;
+ //unsigned int bsize;
+ unsigned int bisize;
+ unsigned int bwidth, bheight, bbpp, boff, blw;
+// unsigned int bcompr;
+ unsigned char *bdata;
+ PS_BITMAP *bm;
+ int x, y, z, i, l;
+
+ bf = fopen(filename, "rb");
+
+ if(bf == NULL)
+ return NULL;
+
+ if(read_le_word(bf) != 19778) // 'BM'
+ {
+ fclose(bf);
+ return NULL;
+ }
+
+ /* bsize = */ read_le_dword(bf);
+
+// Read bitmap data offset
+ fseek(bf, 10, SEEK_SET);
+ boff = read_le_dword(bf);
+
+// printf("BOFF = %d\n", boff);
+
+// Read information header size, width and height
+
+ bisize = read_le_dword(bf);
+
+
+
+ bwidth = read_le_dword(bf);
+ bheight = read_le_dword(bf);
+
+// printf("bwidth = %d, bheight = %d\n", bwidth, bheight);
+
+// Read BPP
+
+ fseek(bf, 28, SEEK_SET);
+
+ bbpp = read_le_word(bf);
+
+// Check if there is compression, if there is, abort
+
+ /* bcompr = */ read_le_dword(bf);
+// printf("BCOMPR = %d\n", bcompr);
+
+ bm = ps_create_bitmap(bwidth, bheight, bbpp);
+
+ if(palette != NULL && bm->depth <= 8)
+ {
+ fseek(bf, 14 + bisize, SEEK_SET);
+
+ if(bm->depth == 4) l = 16;
+ else if(bm->depth == 8) l = 256;
+ else if(bm->depth == 1) l = 2;
+
+ for(x=0;x<l;x++)
+ {
+ palette[x].b = fgetc(bf);
+ palette[x].g = fgetc(bf);
+ palette[x].r = fgetc(bf);
+ fgetc(bf);
+ }
+ }
+
+// nextvolume FIX 2011-07-08: Now blw (line width with padding) and bwidth
+// (line width without padding) are calculated in a much cleaner and correct manner.
+
+// printf("BPP = %d\n", bbpp);
+
+ bwidth = (bwidth * bbpp) >> 3;
+ blw = bwidth;
+ if(blw & 3) blw = (blw & ~3) + 4;
+
+ bdata = (unsigned char*)bm->data;
+
+// Bit mask and colour stuff... Added 2011-07-09
+
+ switch(bisize)
+ {
+ case 40: bm->hdr_type = BITMAPINFOHEADER; break;
+ case 52: bm->hdr_type = BITMAPV2INFOHEADER; break;
+ case 56: bm->hdr_type = BITMAPV3INFOHEADER; break;
+ case 108: bm->hdr_type = BITMAPV4HEADER; break;
+ case 124: bm->hdr_type = BITMAPV5HEADER; break;
+ }
+
+// For now clear Alpha, it will be filled only if it will be found
+
+ bm->mask[3] = 0;
+ bm->shift[3] = 0;
+ bm->bits[3] = 0;
+
+ if(bm->hdr_type == BITMAPINFOHEADER && bbpp == 16)
+ {
+ // Old header type and no bitmasks specified - force defaults
+ // X1 R5 G5 B5
+ bm->mask[2] = 0x1f;
+ bm->mask[1] = 0x1f << 5;
+ bm->mask[0] = 0x1f << 10;
+ bm->shift[2] = 0;
+ bm->shift[1] = 5;
+ bm->shift[0] = 10;
+ bm->bits[2] = 5;
+ bm->bits[1] = 5;
+ bm->bits[0] = 5;
+ }
+ else if(bm->hdr_type >= BITMAPV2INFOHEADER)
+ {
+ fseek(bf, 54, SEEK_SET);
+
+// Calculate rshift and rbits
+
+ if(bm->hdr_type >= BITMAPV3INFOHEADER)
+ l = 4;
+ else
+ l = 3;
+
+ for(i = 0; i < l; i++)
+ {
+ bm->mask[i] = read_le_dword(bf);
+
+ y = 0; // rshift
+ z = 0; // rbits
+
+ for(x = 31; x >= 0; x--)
+ {
+ if(bm->mask[i] & (1<<x))
+ {
+ y = x;
+ z++;
+ }
+ }
+
+ bm->shift[i] = y;
+ bm->bits[i] = z;
+
+ //printf("shift[%d] = %d, bits[%d] = %d\n", i, bm->shift[i],
+ // i, bm->bits[i]);
+ }
+ }
+
+// Copy data in allocated memory
+
+ for(y = 0; y < bm->h; y++)
+ {
+ fseek(bf, boff + (blw * (bm->h - (1+y))), SEEK_SET);
+
+ for(x = 0; x < bwidth; x++)
+ fread(&bdata[(y*bwidth)+x], sizeof(char), 1, bf);
+ }
+
+ fclose(bf);
+
+ return bm;
+}
+
+unsigned int ps_makecol(int r, int g, int b, int a)
+{
+ return (a<<24)|(r<<16)|(g<<8)|b;
+}
+
+unsigned int ps_getr(int c)
+{
+ return (c>>16)&0xff;
+}
+
+unsigned int ps_getg(int c)
+{
+ return (c>>8)&0xff;
+}
+
+unsigned int ps_getb(int c)
+{
+ return c&0xff;
+}
+
+unsigned int ps_geta(int c)
+{
+ return (c>>24)&0xff;
+}
+
+unsigned int ps_getpixel(PS_BITMAP *bm, int x, int y)
+{
+ unsigned short shortbuf;
+ unsigned int intbuf;
+ unsigned char r, g, b, a;
+ unsigned char *dataptrb = (unsigned char*)bm->data;
+ int off;
+
+ if(bm->depth == 16)
+ {
+ off = ((y*bm->w)+x)*2;
+
+ // Little endian, guys...
+
+ shortbuf = dataptrb[off];
+ shortbuf|= dataptrb[off+1]<<8;
+
+ b = ((shortbuf & bm->mask[2]) >> bm->shift[2]) << (8-bm->bits[2]);
+ g = ((shortbuf & bm->mask[1]) >> bm->shift[1]) << (8-bm->bits[1]);
+ r = ((shortbuf & bm->mask[0]) >> bm->shift[0]) << (8-bm->bits[0]);
+ a = ((shortbuf & bm->mask[3]) >> bm->shift[3]) << (8-bm->bits[3]);
+
+ return ps_makecol(r, g, b, a);
+ }
+ else if(bm->depth == 24)
+ {
+ // 24-bit bitmaps never have bitmasks.
+
+ off = ((y*bm->w)+x)*3;
+ r = dataptrb[off+2];
+ g = dataptrb[off+1];
+ b = dataptrb[off];
+ a = 255;
+
+ return ps_makecol(r, g, b, 255);
+ }
+ else if(bm->depth == 32)
+ {
+ off = ((y*bm->w)+x)*4;
+ /* r = dataptrb[off+3];
+ g = dataptrb[off+2];
+ b = dataptrb[off+1];*/
+ intbuf = dataptrb[off];
+ intbuf|= dataptrb[off+1]<<8;
+ intbuf|= dataptrb[off+2]<<16;
+ intbuf|= dataptrb[off+3]<<24;
+
+ r = ((intbuf & bm->mask[0]) >> bm->shift[0]) << (8-bm->bits[0]);
+ g = ((intbuf & bm->mask[1]) >> bm->shift[1]) << (8-bm->bits[1]);
+ b = ((intbuf & bm->mask[2]) >> bm->shift[2]) << (8-bm->bits[2]);
+ a = ((intbuf & bm->mask[3]) >> bm->shift[3]) << (8-bm->bits[3]);
+
+ return ps_makecol(r, g, b, a);
+ }
+ else if(bm->depth == 8)
+ {
+ r = dataptrb[(y*bm->w)+x];
+
+ return ps_makecol(ps_default_palette[r].r,
+ ps_default_palette[r].g, ps_default_palette[r].b, 255);
+ }
+ else if(bm->depth == 4)
+ {
+ off = (y*bm->w)+x;
+ off/= 2;
+
+ if(x & 1)
+ r = dataptrb[off] & 0xf;
+ else
+ r = dataptrb[off] >> 4;
+
+ return ps_makecol(ps_default_palette[r].r,
+ ps_default_palette[r].g, ps_default_palette[r].b, 255);
+ }
+ else if(bm->depth == 1)
+ {
+ off = (y*bm->w)+x;
+ off/= 8;
+
+ r = (dataptrb[off] & (1<<(7-(x&7)))) ? 1 : 0;
+
+ return ps_makecol(ps_default_palette[r].r,
+ ps_default_palette[r].g, ps_default_palette[r].b, 255);
+ }
+
+ return 0;
+}
+
+unsigned int ps_getpixel_pal(PS_BITMAP *bm, int x, int y)
+{
+ unsigned char *dataptrb = (unsigned char*)bm->data;
+ int off;
+
+ if(bm->depth == 8)
+ {
+ return dataptrb[(y*bm->w)+x];
+ }
+ else if(bm->depth == 4)
+ {
+ off = (y*bm->w)+x;
+ off/= 2;
+
+ if(x & 1)
+ return dataptrb[off] & 0xf;
+ else
+ return dataptrb[off] >> 4;
+ }
+ else if(bm->depth == 1)
+ {
+ off = (y*bm->w)+x;
+ off/= 8;
+
+ return (dataptrb[off] & (1<<(7-(x&7)))) ? 1 : 0;
+ }
+
+ return 0;
+}
+
+void parse_options(int argc, char *argv[])
+{
+ int x;
+
+ for(x=4;x<argc;x++)
+ {
+ if(strncmp("-clut=", argv[x], 6) == 0)
+ {
+ sscanf(argv[x], "-clut=%d,%d", &clut_x, &clut_y);
+ do_clut = 1;
+ }else if(strncmp("-org=", argv[x], 5) == 0)
+ sscanf(argv[x], "-org=%d,%d", &org_x, &org_y);
+ else if(strcmp("-stp", argv[x]) == 0)
+ set_stp_bit = 1;
+ else if(strcmp("-noblack", argv[x]) == 0)
+ transparent_black = 1;
+ else if(strcmp("-mpink", argv[x]) == 0)
+ magic_pink = 1;
+ else if(strcmp("-raw", argv[x]) == 0)
+ raw_flag = 1;
+ }
+}
+
+unsigned short rgb24_to_rgbpsx(unsigned char r, unsigned char g, unsigned char b)
+{
+ unsigned short c;
+
+ c = r>>3;
+ c|= (g>>3)<<5;
+ c|= (b>>3)<<10;
+
+ /*if(set_stp_bit) c|=0x8000;*/
+// this code is a bit messy, tidy it up.
+
+ if(c == 0 && !transparent_black)
+ c|=0x8000;
+
+ if(c == ((31)|(31<<10)) && magic_pink)
+ c=0;
+
+ if(set_stp_bit)
+ {
+ if(transparent_black && c == 0)
+ return c;
+
+ if(magic_pink && c == ((31)|(31<<10)))
+ return c;
+
+ c|=0x8000;
+ }
+
+ return c;
+}
+
+int main(int argc, char *argv[])
+{
+ PS_BITMAP *in_bitmap;
+ FILE *out_tim;
+ PS_RGB in_palette[256];
+ int x, y, z, c, c2;
+ unsigned short shortbuf;
+ int cx_out = 0;
+
+ ps_default_palette = in_palette;
+
+ for(x=1;x<argc;x++)
+ {
+ if(strcmp("-version", argv[x]) == 0)
+ {
+ printf("bmp2tim version "BMP2TIM_VERSION"\n");
+ return EXIT_SUCCESS;
+ }
+ }
+
+ if(argc < 4)
+ {
+ printf("bmp2tim "BMP2TIM_VERSION" - converts a bitmap to a TIM image\n");
+ printf("usage: bmp2tim <inbmp> <outtim> <depth> [options]\n\n");
+ printf("Options:\n");
+ printf(" -clut=x,y - Generate a Color Look Up Table (default: OFF)\n");
+ printf(" -org=x,y - Set image origin in framebuffer (default: 0, 0)\n");
+ printf(" -stp - Set semi transparency bit (default: BLACK ONLY)\n");
+ printf(" -noblack - Make black transparent (default: OFF)\n");
+ printf(" -mpink - Magic pink, 255,0,255 transparent (default: OFF)\n");
+ printf(" -raw - Do not save header and CLUT (default: OFF)\n");
+ printf(" -version - Print program version on screen\n\n");
+ printf("Valid TIM depths are 4 (16-color), 8 (256-color), 16 (RGB555) and 24 (RGB888)\n");
+ return EXIT_SUCCESS;
+ }
+
+ tim_depth = atoi(argv[3]);
+
+ parse_options(argc, argv);
+
+ if(do_clut && tim_depth >= 16)
+ {
+ printf("Images with depths higher than 8-bit can't have a color look up table.\n");
+ return EXIT_FAILURE;
+ }
+
+ if(clut_x & 0xf)
+ {
+ printf("The X position of the CLUT in the framebuffer must be a multiplier of 16.\n");
+ return EXIT_FAILURE;
+ }
+
+ switch(tim_depth)
+ {
+ case 4:
+ if(clut_x > (1024-16))
+ cx_out = 1;
+ break;
+ case 8:
+ if(clut_x > (1024-256))
+ cx_out = 1;
+ break;
+ }
+
+ if(cx_out)
+ {
+ printf("X position specified for CLUT out of bounds.\n");
+ return EXIT_FAILURE;
+ }
+
+ if(clut_y >= 512)
+ {
+ printf("Y position specified for CLUT out of bounds.\n");
+ return EXIT_FAILURE;
+ }
+
+ if(do_clut)
+ printf("Generating a Color Look Up Table (CLUT)\n");
+
+ if(tim_depth != 4 && tim_depth != 8 && tim_depth != 16 && tim_depth != 24)
+ {
+ printf("Invalid color depth specified!\n");
+ return EXIT_FAILURE;
+ }
+
+ in_bitmap = ps_load_bitmap(argv[1], in_palette);
+
+ if(in_bitmap == NULL)
+ {
+ printf("Unable to load bitmap. Unsupported format or file is unreadable or does not exist.\n");
+ return EXIT_FAILURE;
+ }
+
+ if(tim_depth == 4 && in_bitmap->depth > 4)
+ {
+ printf("Error: Only a 4-bit bitmap or a bitmap of lower depth can be used to obtain a 4-bit TIM!\n");
+ return EXIT_FAILURE;
+ }
+
+ if(tim_depth == 8 && in_bitmap->depth > 8)
+ {
+ printf("Error: Only a 8-bit or a bitmap of lower depth can be used to obtain a 8-bit TIM!\n");
+ return EXIT_FAILURE;
+ }
+
+/* allegro_init();
+ set_color_depth(32);
+ install_keyboard();
+ set_gfx_mode(GFX_AUTODETECT_WINDOWED, in_bitmap->w, in_bitmap->h, 0, 0);
+
+ for(y=0;y<in_bitmap->h;y++)
+ {
+ for(x=0;x<in_bitmap->w;x++)
+ {
+ c = ps_getpixel_pal(in_bitmap, x, y);
+
+ //putpixel(screen, x, y, makecol(ps_getr(c), ps_getg(c), ps_getb(c)));
+ putpixel(screen, x, y, makecol(in_palette[c].r, in_palette[c].g,
+ in_palette[c].b));
+ }
+ }
+
+ while(!key[KEY_ESC]);*/
+
+ if(in_bitmap == NULL)
+ {
+ printf("Could not open bitmap. Aborting.\n");
+ return EXIT_FAILURE;
+ }
+
+ switch(tim_depth)
+ {
+ case 4:
+ if(in_bitmap->w & 3)
+ {
+ printf("Error: A 4-bit bitmap must have a width divisible by four.\n");
+ return EXIT_FAILURE;
+ }
+
+ z = in_bitmap->w/4;
+ break;
+ case 8:
+ if(in_bitmap->w & 1)
+ {
+ printf("Error: A 8-bit bitmap must have a width divisible by two.\n");
+ return EXIT_FAILURE;
+ }
+
+ z = in_bitmap->w/2;
+ break;
+ case 16:
+ z = in_bitmap->w;
+ break;
+ }
+
+ if((org_x+z) > 1024)
+ {
+ printf("X position specified for image data out of bounds.\n");
+ return EXIT_FAILURE;
+ }
+
+ switch(tim_depth)
+ {
+ case 4:
+ z = in_bitmap->h/4;
+ break;
+ case 8:
+ z = in_bitmap->h/2;
+ break;
+ case 16:
+ z = in_bitmap->h;
+ break;
+ }
+
+ if((org_y+z) > 512)
+ {
+ printf("Y position specified for image data out of bounds.\n");
+ return EXIT_FAILURE;
+ }
+
+ out_tim = fopen(argv[2], "wb");
+
+ if(out_tim == NULL)
+ {
+ printf("Couldn't open file at path %s for writing. Aborting.\n", argv[2]);
+ return EXIT_FAILURE;
+ }
+
+ if(!raw_flag)
+ {
+
+ write_le_dword(out_tim, 0x10); /* ID = 0x10, Version = 0x00 */
+
+ /*
+ * Now let's fill the TIM flag double word
+ */
+
+ /*
+ * Pixel mode (PMODE)
+ */
+
+ switch(tim_depth)
+ {
+ case 4:
+ tim_flag = 0;
+ break;
+ case 8:
+ tim_flag = 1;
+ break;
+ case 16:
+ tim_flag = 2;
+ break;
+ case 24:
+ tim_flag = 3;
+ break;
+ }
+
+ /*
+ * Clut flag (CF)
+ */
+ //tim_flag|=8;
+ if(do_clut)tim_flag|=8;
+
+ write_le_dword(out_tim, tim_flag);
+
+ /*
+ * If we have to write a CLUT now, we have to write its data block
+ */
+
+ if(do_clut)
+ {
+ /*
+ * Let's write the information for the block - we already know
+ * everything about it.
+ */
+
+ switch(tim_depth)
+ {
+ case 4:
+ write_le_dword(out_tim, 44); // Number of bytes contained by the block
+ write_le_dword(out_tim, (clut_y<<16)|clut_x); // X, Y position
+ write_le_dword(out_tim, (1<<16)|16); // Width = 16, Height = 1
+ break;
+ case 8:
+ write_le_dword(out_tim, 524);
+ write_le_dword(out_tim, (clut_y<<16)|clut_x);
+ write_le_dword(out_tim, (1<<16)|256); // Width = 256, Height = 1
+ break;
+ }
+
+ /*
+ * Let's write the CLUT data
+ */
+
+ switch(tim_depth)
+ {
+ case 4:
+ for(x = 0; x < 16; x++)
+ {
+ shortbuf = rgb24_to_rgbpsx(in_palette[x].r, in_palette[x].g,
+ in_palette[x].b);
+
+ write_le_word(out_tim, shortbuf);
+ }
+ break;
+ case 8:
+ for(x = 0; x < 256; x++)
+ {
+ shortbuf = rgb24_to_rgbpsx(in_palette[x].r, in_palette[x].g,
+ in_palette[x].b);
+
+ write_le_word(out_tim, shortbuf);
+ }
+ break;
+ }
+ }
+
+ /*
+ * Write image data block
+ */
+
+ switch(tim_depth)
+ {
+ case 4:
+ x = 12 + ((in_bitmap->w * in_bitmap->h) / 2);
+ break;
+ case 8:
+ x = 12 + (in_bitmap->w * in_bitmap->h);
+ break;
+ case 16:
+ x = 12 + ((in_bitmap->w * in_bitmap->h) * 2);
+ break;
+ case 24:
+ x = 12 + ((in_bitmap->w * in_bitmap->h) * 3);
+ break;
+ }
+
+ write_le_dword(out_tim, x);
+ write_le_dword(out_tim, (org_y<<16)|org_x);
+
+ switch(tim_depth)
+ {
+ case 4:
+ write_le_dword(out_tim, (in_bitmap->h<<16)|(in_bitmap->w/4));
+ break;
+ case 8:
+ write_le_dword(out_tim, (in_bitmap->h<<16)|(in_bitmap->w/2));
+ break;
+ case 16:
+ write_le_dword(out_tim, (in_bitmap->h<<16)|in_bitmap->w);
+ break;
+ case 24:
+ write_le_dword(out_tim, (in_bitmap->h<<16)|(in_bitmap->w+
+ (in_bitmap->w/2)));
+ break;
+ }
+
+ }
+
+// Write image pixel data...
+
+ switch(tim_depth)
+ {
+ case 24:
+ for(y = 0; y < in_bitmap->h; y++)
+ {
+ for(x = 0; x < in_bitmap->w; x+=2)
+ {
+ c = ps_getpixel(in_bitmap, x, y);
+ c2 = ps_getpixel(in_bitmap, x+1, y);
+
+ write_le_word(out_tim, (ps_getg(c)<<8)|ps_getr(c));
+ write_le_word(out_tim, (ps_getr(c2)<<8)|ps_getb(c));
+ write_le_word(out_tim, (ps_getb(c2)<<8)|ps_getg(c2));
+ }
+ }
+ break;
+ case 16:
+ for(y = 0; y < in_bitmap->h; y++)
+ {
+ for(x = 0; x < in_bitmap->w; x++)
+ {
+ c = ps_getpixel(in_bitmap, x, y);
+ shortbuf = rgb24_to_rgbpsx(ps_getr(c), ps_getg(c), ps_getb(c));
+ write_le_word(out_tim, shortbuf);
+ }
+ }
+ break;
+ case 4:
+ for(y = 0; y < in_bitmap->h; y++)
+ {
+ for(x = 0; x < in_bitmap->w; x+=4)
+ {
+ shortbuf = 0;
+ for(c = 0; c < 4; c++)
+ shortbuf |= (ps_getpixel_pal(in_bitmap, x+c, y)&0xf) << (c<<2);
+
+ write_le_word(out_tim, shortbuf);
+ }
+ }
+ break;
+ case 8:
+ for(y = 0; y < in_bitmap->h; y++)
+ {
+ for(x = 0; x < in_bitmap->w; x+=2)
+ {
+ shortbuf = 0;
+ for(c = 0; c < 2; c++)
+ shortbuf |= (ps_getpixel_pal(in_bitmap, x+c, y)&0xff) << (c<<3);
+
+ write_le_word(out_tim, shortbuf);
+ }
+ }
+ break;
+ }
+
+ fclose(out_tim);
+ //printf("Bitmap converted to TIM file successfully!\n");
+ return EXIT_SUCCESS;
+}