c64c25236901cf632d7e9a6b5c708d571f299dac
[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 row_tiles;
26         unsigned col_tiles;
27         unsigned bpp;
28         unsigned char * data;
29         SDL_Colour * palette;
30         unsigned short outpal[8];
31 } swan_gfx_t;
32
33 int set_info(swan_gfx_t * gfx, SDL_Surface * img)
34 {
35         gfx->width = img->w;
36         gfx->height = img->h;
37         gfx->bpp = img->format->BitsPerPixel;
38
39         if (gfx->bpp != 8) {
40                 fprintf(stderr, "warning: %d bpp format detected\n", img->format->BitsPerPixel);
41                 return -1;
42         }
43
44         if (gfx->width % 8 | gfx->height % 8) {
45                 fprintf(stderr, "warning: image not multiple of 16x16 tiles\n \
46                                 width: %d\theight: %d\n", gfx->width, gfx->height);
47                 return -1;
48         }
49
50         gfx->row_tiles = gfx->height / 8;
51         gfx->col_tiles = gfx->width / 8;
52
53         /* set userdata to iterate over
54          * pixels */
55         SDL_LockSurface(img);
56         img->userdata = img->pixels;
57         gfx->data = (unsigned char *) img->userdata;
58         gfx->palette = img->format->palette->colors;
59         SDL_UnlockSurface(img);
60         
61         return 0;
62 }
63
64 void generate_4bpp_tile(unsigned char *buf, swan_gfx_t * gfx,
65                 bool packed)
66 {
67         unsigned char * ptr = gfx->data;
68         for (int i = 0; i < TILE_SZ; i+=4) {
69                 for (int j = 0; j < 4; ++j) {
70                         if (packed) { /* packed format */
71                                 gfx->outpal[ptr[0]] = (gfx->palette[ptr[0]].r >> 4) << 8 |
72                                                       (gfx->palette[ptr[0]].g >> 4) << 4 |
73                                                       gfx->palette[ptr[0]].b >> 4;
74                                 buf[i+j] = ptr[0] << 4;
75                                 buf[i+j] |= ptr[1];
76                                 ptr += 2;
77                         } else { /* planar format */
78                                 for (int x = 0; x < 8; ++x) {
79                                         buf[i + j] = ptr[x] << j; 
80                                 }
81                         }
82                 }
83                 if (!packed)
84                         ptr += 8;
85         }
86 }
87
88 int main(int argc, char *argv[])
89 {
90         SDL_Surface * rawbmp;
91         FILE * gfxstream;
92         FILE * palstream;
93         int opt;
94         char * infile;
95         char outfile[256];
96         bool bout = false;
97
98         while ((opt = getopt(argc, argv, "po:sv:")) != -1) {
99                 switch (opt) {
100                         case 'p':
101                                 printf("include palette");
102                                 break;
103                         case 'o':
104                                 printf("output file %s\n", optarg);
105                                 strcpy(outfile, optarg);
106                                 bout = true;
107                                 break;
108                         case 's':
109                                 printf("generate gfx per 16x16 tile \n");
110                                 break;
111                         case 'v':
112                                 break;
113                         default: /* '?' */
114                                 fprintf(stderr, "Usage: %s [-s] [-o output] file \n", argv[0]);
115                                 exit(EXIT_FAILURE);
116                }
117         }
118
119         if (optind >= argc) {
120                 fprintf(stderr, "Expected infile\n");
121                 fprintf(stderr, "Usage: %s [-s] [-o output] [file]\n", argv[0]);
122                 exit(EXIT_FAILURE);
123         }
124
125         infile = argv[optind];
126
127         rawbmp = SDL_LoadBMP(infile);
128         if (!rawbmp) {
129                 fprintf(stderr, "can not load %s file\n", infile);
130                 exit(EXIT_FAILURE);
131         }
132
133         swan_gfx_t * gfx = malloc(sizeof(swan_gfx_t));
134         int ret = set_info(gfx, rawbmp);
135
136         if (ret != 0)
137                 goto cleanup;
138
139         unsigned char *tile_buf = malloc(sizeof(unsigned char) * TILE_SZ);
140         
141         if (!bout) 
142                 gfxstream = fopen("out.gfx", "w");
143         else { 
144                 printf("opening %s\n", outfile);
145                 gfxstream = fopen(outfile, "w");
146         }
147         
148         if (!gfxstream) {
149                 fprintf(stderr, "can not open file for writing!\n");
150                 goto close;
151         }
152
153         unsigned nr_tiles = 1;
154
155         for (int i = 0; i < nr_tiles; ++i) {
156                 generate_4bpp_tile(tile_buf, gfx, true);
157                 int ret = fwrite(tile_buf, sizeof(unsigned char), TILE_SZ, gfxstream);
158                 if (ret != TILE_SZ) {
159                         fprintf(stderr, "failed to convert, only write %d instead of %d\n", ret, TILE_SZ);
160                         goto cleanup;
161                 }
162         }
163         
164         palstream = fopen("out.pal", "w");
165         if (!palstream) {
166                 fprintf(stderr, "can not open file for writing!\n");
167                 fclose(palstream);
168                 goto close;
169         }
170
171         fwrite(gfx->outpal, sizeof(unsigned short), 8, palstream);
172         const short fill = 0xFFFF;
173         for (int i = 0; i < 8; ++i) 
174                 fwrite(&fill, sizeof(unsigned short), 1, palstream);
175
176         fclose(palstream);
177
178 close:
179         fclose(gfxstream);
180 cleanup:
181         free(gfx);
182         SDL_FreeSurface(rawbmp);
183 }