* File : bmp2tiles.c
* Author : Robin Krens <robin@robinkrens.nl>
* Date : 04.06.2022
- * Last Modified Date: 12.06.2022
+ * Last Modified Date: 15.06.2022
* Last Modified By : Robin Krens <robin@robinkrens.nl>
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
+#include <stdbool.h>
#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <getopt.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
#include <SDL2/SDL_image.h>
#define TILE_SZ 32
#define FOURBBP_ROW 8
#define FOURBPP_COL 8
-void bmp_info(SDL_Surface * img)
+typedef struct {
+ unsigned width;
+ unsigned height;
+ unsigned row_tiles;
+ unsigned col_tiles;
+ unsigned bpp;
+ unsigned char * data;
+ SDL_Colour * palette;
+ unsigned short outpal[8];
+} swan_gfx_t;
+
+int set_info(swan_gfx_t * gfx, SDL_Surface * img)
{
- SDL_PixelFormat * fmt;
- fmt = img->format;
- fprintf(stdout,"WIDTH: %d, HEIGHT: %d, BPP: %d\n", img->w, img->h, fmt->BitsPerPixel);
-}
+ gfx->width = img->w;
+ gfx->height = img->h;
+ gfx->bpp = img->format->BitsPerPixel;
+
+ if (gfx->bpp != 8) {
+ fprintf(stderr, "error: %d bpp format detected\n", img->format->BitsPerPixel);
+ return -1;
+ }
+
+ if (gfx->width % 8 | gfx->height % 8) {
+ fprintf(stderr, "error: image not multiple of 16x16 tiles\n \
+ width: %d\theight: %d\n", gfx->width, gfx->height);
+ return -1;
+ }
+ gfx->row_tiles = gfx->height / 8;
+ gfx->col_tiles = gfx->width / 8;
-void generate_4bpp_tile_planar(unsigned char *buf, void * userdata, int sz)
+ /* set userdata to iterate over
+ * pixels */
+ SDL_LockSurface(img);
+ img->userdata = img->pixels;
+ gfx->data = (unsigned char *) img->userdata;
+ gfx->palette = img->format->palette->colors;
+ SDL_UnlockSurface(img);
+
+ return 0;
+}
+
+void generate_4bpp_tile(unsigned char *buf, swan_gfx_t * gfx,
+ bool packed)
{
- unsigned char * ptr = (unsigned char *) userdata;
- for (int i = 0; i < 32; i+=4) {
- /* fprintf(stdout, "userdata: pos: %d - %d\n", i, *ptr++); */
+ unsigned char * ptr = gfx->data;
+ for (int i = 0; i < TILE_SZ; i+=4) {
for (int j = 0; j < 4; ++j) {
- for (int x = 0; x < 8; ++x) {
- buf[i + j] = ptr[x] << j;
+ if (packed) { /* packed format */
+ //printf("%d %d ", ptr[0], ptr[1]);
+ if (ptr[0] >= 8 || ptr[1] >= 8)
+ fprintf(stdout, "warning: too many colors detected\n");
+ gfx->outpal[ptr[0]] = (gfx->palette[ptr[0]].r >> 4) << 8 |
+ (gfx->palette[ptr[0]].g >> 4) << 4 |
+ gfx->palette[ptr[0]].b >> 4;
+ buf[i+j] = ptr[0] << 4;
+ buf[i+j] |= ptr[1];
+ ptr += 2;
+ } else { /* TODO: planar format */
+ for (int x = 0; x < 8; ++x) {
+ if (ptr[x] >= 8)
+ fprintf(stdout, "warning: too many colors detected\n");
+ buf[i + j] = ptr[x] << j;
+ }
}
- /* printf("%d: %x\n", i+j, buf[i+j]); */
}
- ptr += 8;
+ if (!packed)
+ ptr += 8;
+ else {
+ ptr += (8 * (gfx->col_tiles-1));
+ }
}
}
-void generate_4bpp_tile_packed(unsigned char *buf, void * userdata, int sz)
+FILE * openstream(const char * name, const char * prefix,
+ unsigned tile_nr, bool append)
{
- unsigned char * ptr = (unsigned char *) userdata;
- for (int i = 0; i < 32; i+=4) {
- for (int j = 0; j < 4; ++j) {
- buf[i+j] = ptr[0] << 4;
- buf[i+j] |= ptr[1];
- ptr += 2;
- printf("%d: %x\n", i+j, buf[i+j]);
- }
+ assert(strlen(name) < 200);
+
+ FILE * stream;
+
+ unsigned buf_len = 256;
+ char buf[buf_len];
+ snprintf(buf, buf_len, "%s/%s%d.%s", prefix, name, tile_nr, prefix);
+
+ //printf("%s\n", buf);
+ if (!append) {
+ stream = fopen(buf, "w");
+ } else {
+ stream = fopen(buf, "a");
}
+
+ return stream;
}
-int main(void)
+int create_dir(const char *name)
{
- SDL_Surface * rawbmp;
- SDL_PixelFormat * fmt;
- char filename[] = "test.bmp";
- rawbmp = SDL_LoadBMP(filename);
+ struct stat statbuf;
+
+ if (stat(name, &statbuf) == -1)
+ return mkdir(name, 0755);
+ if ((statbuf.st_mode & S_IFMT) != S_IFDIR)
+ return -1;
+
+ return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+ SDL_Surface * rawbmp;
+ FILE * gfxstream;
+ FILE * palstream;
+ int opt;
+ char * infile;
+ char outfile[256];
+ bool bout = false;
+ const short fill = 0xFFFF;
+ bool seperate_gfx = false;
+ bool seperate_pal = false;
+
+ while ((opt = getopt(argc, argv, "po:sv")) != -1) {
+ switch (opt) {
+ case 'p':
+ seperate_pal = true;
+ printf("generate individual .pal for each tile");
+ break;
+ case 'o':
+ printf("output file %s\n", optarg);
+ strcpy(outfile, optarg);
+ bout = true;
+ break;
+ case 's':
+ seperate_gfx = true;
+ printf("generate .gfx for each tile\n");
+ break;
+ case 'v':
+ printf("verbose");
+ break;
+ default: /* '?' */
+ fprintf(stderr, "Usage: %s [-s] [-o output] file \n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (optind >= argc) {
+ fprintf(stderr, "Expected input .bmp file!\n");
+ fprintf(stderr, "Usage: %s [-s] [-o output] [file]\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ infile = argv[optind];
+
+ rawbmp = SDL_LoadBMP(infile);
if (!rawbmp) {
- fprintf(stderr, "can not load .bmp file\n");
+ fprintf(stderr, "can not load %s file\n", infile);
exit(EXIT_FAILURE);
}
- bmp_info(rawbmp);
+ swan_gfx_t * gfx = calloc(1, sizeof(swan_gfx_t));
+ int ret = set_info(gfx, rawbmp);
- SDL_LockSurface(rawbmp);
- rawbmp->userdata = rawbmp->pixels;
- SDL_UnlockSurface(rawbmp);
+ if (ret != 0)
+ goto cleanup;
- unsigned char *tile_buf = malloc(sizeof(unsigned char) * TILE_SZ);
+ unsigned char *tile_buf = calloc(TILE_SZ, sizeof(unsigned char));
- generate_4bpp_tile_packed(tile_buf, rawbmp->userdata, 64);
+ if (!bout) {
+ sprintf(outfile, "out");
+ }
- /* if (rawbmp->format->BitsPerPixel != 24) {
- fprintf(stderr, "format %d not supported\n", rawbmp->format->BitsPerPixel);
- exit(EXIT_FAILURE);
- } */
+ /* check for existing gfx/ and pal/ directories */
+ ret = create_dir("gfx/");
+ ret += create_dir("pal/");
+
+ if (ret) {
+ fprintf(stderr, "error: can not create output gfx/ or pal/ location\n");
+ goto cleanup;
+ }
+ fprintf(stdout, "generating %d tile(s) \
+ in %d gfx file(s) \
+ with %d pal file(s)\n",
+ gfx->row_tiles * gfx->col_tiles,
+ seperate_gfx ? gfx->row_tiles * gfx->col_tiles : 1,
+ seperate_pal ? gfx->row_tiles * gfx->col_tiles : 1);
- SDL_FreeSurface(rawbmp);
+ for (int i = 0, cnt = 0; i < gfx->row_tiles; ++i) {
+ for (int j = 0; j < gfx->col_tiles; ++j, ++cnt) {
+
+ if (i == 0 && j == 0) {
+ gfxstream = openstream(outfile, "gfx", 0, false);
+ palstream = openstream(outfile, "pal", 0, false);
+ } else {
+ if (seperate_gfx) {
+ gfxstream = openstream(outfile, "gfx", cnt, false);
+ }
+ if (seperate_pal) {
+ palstream = openstream(outfile, "pal", cnt, false);
+ }
+ }
+
+ generate_4bpp_tile(tile_buf, gfx, true);
+ int ret = fwrite(tile_buf, sizeof(unsigned char), TILE_SZ, gfxstream);
+ if (ret != TILE_SZ) {
+ fprintf(stderr, "failed to convert, only write %d instead of %d\n", ret, TILE_SZ);
+ fclose(gfxstream);
+ goto cleanup;
+ }
+ fwrite(gfx->outpal, sizeof(unsigned short), 8, palstream);
+ for (int i = 0; i < 8; ++i)
+ ret += fwrite(&fill, sizeof(unsigned short), 1, palstream);
+
+ gfx->data += 8; /* next column */
+
+ if (gfx->row_tiles == (i-1) && gfx->col_tiles == (j-1)) {
+ fclose(gfxstream);
+ fclose(palstream);
+ } else {
+ if (seperate_gfx)
+ fclose(gfxstream);
+ if (seperate_pal)
+ fclose(palstream);
+ }
+ }
+ gfx->data += (gfx->col_tiles * 64) - (8 * gfx->col_tiles);
+ }
+
+cleanup:
+ free(gfx);
+ free(tile_buf);
+ SDL_FreeSurface(rawbmp);
}