cammy/bin/tile.c
2021-11-28 12:17:24 -05:00

287 lines
7 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <cammy/image.h>
#include <cammy/screen.h>
#include <cammy/photo.h>
#include <cammy/sram.h>
#include "pnglite.h"
#include "png.h"
#include "commands.h"
static cammy_tile_palette palette = {
.colors = {
{ 0, 0, 0 },
{ 85, 85, 85 },
{ 171, 171, 171 },
{ 255, 255, 255 }
}
};
static void import_usage(int argc, char **argv, const char *message, ...) {
if (message) {
va_list args;
va_start(args, message);
vfprintf(stderr, message, args);
va_end(args);
fprintf(stderr, "\n");
}
fprintf(stderr, "usage: %1$s tile-import file.sav 1..30 printer.tile\n"
" %1$s tile-export file.sav 1..30 output.tile\n"
" %1$s tile-convert printer.tile output.png\n",
argv[0]);
exit(1);
}
int cammy_tile_import(int argc, char **argv) {
cammy_sram *sram;
cammy_image dest, *src;
int photo;
cammy_image_point to = {
0, 0
};
cammy_image_region from = {
16, 16, CAMMY_PHOTO_WIDTH, CAMMY_PHOTO_HEIGHT
};
if (argc < 2) {
import_usage(argc, argv, "No camera SRAM file provided");
} else if (argc < 3) {
import_usage(argc, argv, "No picture number provided");
} else if (argc < 4) {
import_usage(argc, argv,
"No Game Boy screen tile data file provided");
}
photo = atoi(argv[3]);
if (photo < 1 || photo > CAMMY_SRAM_PHOTO_COUNT) {
import_usage(argc, argv, "Invalid photo number");
}
if ((sram = cammy_sram_open(argv[2])) == NULL) {
fprintf(stderr, "%s: %s: %s: %s\n",
argv[0], "cammy_sram_open()", argv[2], strerror(errno));
goto error_sram_open;
}
if ((src = cammy_image_open_tile(argv[4], CAMMY_SCREEN_WIDTH,
CAMMY_SCREEN_HEIGHT)) == NULL) {
fprintf(stderr, "%s: %s: %s: %s\n",
argv[0], "cammy_image_open_tile()", argv[4], strerror(errno));
goto error_image_open_tile;
}
dest.format = CAMMY_IMAGE_2BPP_TILE;
dest.tiles = (cammy_tile *)&sram->data->photos[photo-1].tiles;
dest.width = CAMMY_PHOTO_WIDTH;
dest.height = CAMMY_PHOTO_HEIGHT;
cammy_image_copy(&dest, src, &to, &from);
cammy_image_close(src);
cammy_sram_close(sram);
return 0;
error_image_open_tile:
cammy_sram_close(sram);
error_sram_open:
return 1;
}
static void export_usage(int argc, char **argv, const char *message, ...) {
if (message) {
va_list args;
va_start(args, message);
vfprintf(stderr, message, args);
va_end(args);
fprintf(stderr, "\n");
}
fprintf(stderr, "usage: %1$s tile-import file.sav 1..30 printer.tile\n"
" %1$s tile-export file.sav 1..30 output.tile\n"
" %1$s tile-convert printer.tile output.png\n",
argv[0]);
exit(1);
}
int cammy_tile_export(int argc, char **argv) {
cammy_sram *sram;
cammy_image *dest, src;
int photo;
cammy_image_point to = {
16, 16
};
cammy_image_region from = {
0, 0, CAMMY_PHOTO_WIDTH, CAMMY_PHOTO_HEIGHT
};
if (argc < 2) {
export_usage(argc, argv, "No camera SRAM file provided");
} else if (argc < 3) {
export_usage(argc, argv, "No picture number provided");
} else if (argc < 4) {
export_usage(argc, argv,
"No Game Boy screen tile data file provided");
}
photo = atoi(argv[3]);
if (photo < 1 || photo > CAMMY_SRAM_PHOTO_COUNT) {
export_usage(argc, argv, "Invalid photo number");
}
if ((sram = cammy_sram_open(argv[2])) == NULL) {
fprintf(stderr, "%s: %s: %s: %s\n",
argv[0], "cammy_sram_open()", argv[2], strerror(errno));
goto error_sram_open;
}
src.format = CAMMY_IMAGE_2BPP_TILE;
src.size = CAMMY_PHOTO_SIZE;
src.width = CAMMY_PHOTO_WIDTH;
src.height = CAMMY_PHOTO_HEIGHT;
src.tiles = (cammy_tile *)&sram->data->photos[photo-1].tiles;
if ((dest = cammy_image_new(CAMMY_IMAGE_2BPP_TILE,
CAMMY_SCREEN_WIDTH,
CAMMY_SCREEN_HEIGHT)) == NULL) {
fprintf(stderr, "%s: %s: %s\n",
argv[0], "cammy_image_new()", strerror(errno));
goto error_image_new_dest;
}
memset(dest->buf, '\0', dest->size);
cammy_image_copy(dest, &src, &to, &from);
if (cammy_image_save_tile(dest, argv[4]) < 0) {
fprintf(stderr, "%s: %s: %s: %s\n",
argv[0], "cammy_image_save_tile()", argv[4], strerror(errno));
goto error_image_save_tile_dest;
}
cammy_image_close(dest);
cammy_sram_close(sram);
return 0;
error_image_save_tile_dest:
cammy_image_destroy(dest);
error_image_new_dest:
cammy_sram_close(sram);
error_sram_open:
return errno || 1;
}
static void convert_usage(int argc, char **argv, const char *message, ...) {
if (message) {
va_list args;
va_start(args, message);
vfprintf(stderr, message, args);
va_end(args);
fprintf(stderr, "\n");
}
fprintf(stderr, "usage: %1$s tile-convert printer.tile output.png\n",
argv[0]);
exit(1);
}
int cammy_tile_convert(int argc, char **argv) {
int fd;
void *in, *out;
if (argc < 3) {
convert_usage(argc, argv,
"No input Game Boy screen tile data file provided");
} else if (argc < 4) {
convert_usage(argc, argv, "No output PNG filename provided");
}
if ((fd = open(argv[2], O_RDONLY)) < 0) {
fprintf(stderr, "%s: %s: %s: %s\n",
argv[0], "open()", argv[2], strerror(errno));
goto error_open;
}
if ((in = malloc(CAMMY_SCREEN_SIZE)) == NULL) {
fprintf(stderr, "%s: %s: %s\n",
argv[0], "malloc()", strerror(errno));
goto error_malloc_in;
}
if (read(fd, in, CAMMY_SCREEN_SIZE) < 0) {
fprintf(stderr, "%s: %s: %s: %s\n",
argv[0], "read()", argv[2], strerror(errno));
goto error_read;
}
if ((out = malloc(CAMMY_SCREEN_WIDTH * CAMMY_SCREEN_HEIGHT * 3)) == NULL) {
fprintf(stderr, "%s: %s: %s\n",
argv[0], "malloc()", strerror(errno));
goto error_malloc_out;
}
cammy_image_copy_from_tile(out, in,
CAMMY_SCREEN_WIDTH,
CAMMY_SCREEN_HEIGHT, 3, &palette);
if (cammy_png_save(argv[3], out,
CAMMY_SCREEN_WIDTH,
CAMMY_SCREEN_HEIGHT, 8, PNG_TRUECOLOR) < 0) {
fprintf(stderr, "%s: %s: %s: %s\n",
argv[0], "cammy_png_save()", argv[3], strerror(errno));
goto error_png_save;
}
return 0;
error_png_save:
free(out);
error_malloc_out:
error_read:
free(in);
error_malloc_in:
close(fd);
error_open:
return errno;
}