tools: bmp2tiles create pallete data
[swan-dev] / tools / bmp2tiles / bmp2tiles.c
1 /**
2  * File              : bmp2tiles.c
3  * Author            : Robin Krens <robin@robinkrens.nl>
4  * Date              : 04.06.2022
5  * Last Modified Date: 12.06.2022
6  * Last Modified By  : Robin Krens <robin@robinkrens.nl>
7  */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <stdint.h>
12 #include <stdbool.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <getopt.h>
16 #include <SDL2/SDL_image.h>
17
18 #define TILE_SZ         32
19 #define FOURBBP_ROW     8
20 #define FOURBPP_COL     8
21
22 typedef struct {
23         unsigned width;
24         unsigned height;
25         unsigned bpp;
26         unsigned char * data;
27         SDL_Colour * palette;
28         unsigned short outpal[8];
29 } swan_gfx_t;
30
31 void set_info(swan_gfx_t * gfx, SDL_Surface * img)
32 {
33         gfx->width = img->w;
34         gfx->height = img->h;
35         gfx->bpp = img->format->BitsPerPixel;
36         
37         /* set userdata to iterate */
38         SDL_LockSurface(img);
39         img->userdata = img->pixels;
40         gfx->data = (unsigned char *) img->userdata;
41         gfx->palette = img->format->palette->colors;
42         SDL_UnlockSurface(img);
43
44 }
45
46 void generate_4bpp_tile(unsigned char *buf, swan_gfx_t * gfx,
47                 bool packed)
48 {
49         unsigned char * ptr = gfx->data;
50         for (int i = 0; i < TILE_SZ; i+=4) {
51                 for (int j = 0; j < 4; ++j) {
52                         if (packed) { /* packed format */
53                                 gfx->outpal[ptr[0]] = (gfx->palette[ptr[0]].r >> 4) << 8 |
54                                                       (gfx->palette[ptr[0]].g >> 4) << 4 |
55                                                       gfx->palette[ptr[0]].b >> 4;
56                                 buf[i+j] = ptr[0] << 4;
57                                 buf[i+j] |= ptr[1];
58                                 ptr += 2;
59                         } else { /* planar format */
60                                 for (int x = 0; x < 8; ++x) {
61                                         buf[i + j] = ptr[x] << j; 
62                                 }
63                         }
64                 }
65                 if (!packed)
66                         ptr += 8;
67         }
68 }
69
70 int main(int argc, char *argv[])
71 {
72         SDL_Surface * rawbmp;
73         FILE * gfxstream;
74         FILE * palstream;
75         int opt;
76         char * infile;
77         char outfile[256];
78         bool bout = false;
79
80         while ((opt = getopt(argc, argv, "po:sv:")) != -1) {
81                 switch (opt) {
82                         case 'p':
83                                 printf("include palette");
84                                 break;
85                         case 'o':
86                                 printf("output file %s\n", optarg);
87                                 strcpy(outfile, optarg);
88                                 bout = true;
89                                 break;
90                         case 's':
91                                 printf("generate gfx per 16x16 tile \n");
92                                 break;
93                         case 'v':
94                                 break;
95                         default: /* '?' */
96                                 fprintf(stderr, "Usage: %s [-s] [-o output] file \n", argv[0]);
97                                 exit(EXIT_FAILURE);
98                }
99         }
100
101         if (optind >= argc) {
102                 fprintf(stderr, "Expected infile\n");
103                 fprintf(stderr, "Usage: %s [-s] [-o output] [file]\n", argv[0]);
104                 exit(EXIT_FAILURE);
105         }
106
107         infile = argv[optind];
108
109         rawbmp = SDL_LoadBMP(infile);
110         if (!rawbmp) {
111                 fprintf(stderr, "can not load %s file\n", infile);
112                 exit(EXIT_FAILURE);
113         }
114
115         swan_gfx_t * gfx = malloc(sizeof(swan_gfx_t));
116         set_info(gfx, rawbmp);
117
118         unsigned char *tile_buf = malloc(sizeof(unsigned char) * TILE_SZ);
119         
120         if (gfx->bpp != 8) {
121                 fprintf(stderr, "warning: %d bpp format detected\n", rawbmp->format->BitsPerPixel);
122                 fprintf(stderr, "use --force in command to run\n");
123                 exit(EXIT_FAILURE);
124         }
125
126         if (!bout) 
127                 gfxstream = fopen("out.gfx", "w");
128         else { 
129                 printf("opening %s\n", outfile);
130                 gfxstream = fopen(outfile, "w");
131         }
132         
133         if (!gfxstream) {
134                 fprintf(stderr, "can not open file for writing!\n");
135                 exit(EXIT_FAILURE);
136         }
137
138         unsigned nr_tiles = 1;
139
140         for (int i = 0; i < nr_tiles; ++i) {
141                 generate_4bpp_tile(tile_buf, gfx, true);
142                 int ret = fwrite(tile_buf, sizeof(unsigned char), TILE_SZ, gfxstream);
143                 if (ret != TILE_SZ) {
144                         fprintf(stderr, "failed to convert, only write %d instead of %d\n", ret, TILE_SZ);
145                         goto cleanup;
146                 }
147         }
148         
149         palstream = fopen("out.pal", "w");
150         if (!palstream) {
151                 fprintf(stderr, "can not open file for writing!\n");
152                 exit(EXIT_FAILURE);
153         }
154
155         fwrite(gfx->outpal, sizeof(unsigned short), 8, palstream);
156         const short fill = 0xFFFF;
157         for (int i = 0; i < 8; ++i) 
158                 fwrite(&fill, sizeof(unsigned short), 1, palstream);
159
160 cleanup:
161         free(gfx);
162         SDL_FreeSurface(rawbmp);
163         fclose(gfxstream);
164         fclose(palstream);
165 }