Skip to content

Instantly share code, notes, and snippets.

@giannitedesco
Created June 19, 2011 16:50
Show Gist options
  • Save giannitedesco/1034469 to your computer and use it in GitHub Desktop.
Save giannitedesco/1034469 to your computer and use it in GitHub Desktop.
Rip syndicate graphics tiles in to TGA files
#include <sys/mman.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <ctype.h>
#include <stdint.h>
#include <endian.h>
#include <inttypes.h>
#define SYND_NUM_TILES 256
#define SYND_NUM_SUBTILES 6
#define SYND_HBLK_MIN_OFS (SYND_NUM_TILES * \
SYND_NUM_SUBTILES * \
sizeof(uint32_t))
#define SYND_SUBTILE_X 32
#define SYND_SUBTILE_Y 16
#define SYND_SUBTILE_SZ (20 * SYND_SUBTILE_Y)
struct tga {
uint8_t tga_identsize;
uint8_t tga_colormap_type;
uint8_t tga_image_type;
uint16_t tga_color_map_start;
uint16_t tga_color_map_len;
uint8_t tga_color_map_bits;
uint16_t tga_xstart;
uint16_t tga_ystart;
uint16_t tga_width;
uint16_t tga_height;
uint8_t tga_bpp;
uint8_t tga_descriptor;
} __attribute__((packed));
struct subtile {
struct tga hdr;
uint8_t pix[SYND_SUBTILE_X * SYND_SUBTILE_Y * 4];
} __attribute__((packed));
static unsigned int palette_nr;
static uint8_t *palette;
static const uint8_t *mapfile(int fd, size_t *len)
{
struct stat st;
const uint8_t *map;
*len = 0;
if ( fstat(fd, &st) )
return NULL;
map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
if ( map == MAP_FAILED )
return NULL;
*len = st.st_size;
return map;
}
static int load_palette(const char *fn)
{
const uint8_t *map;
unsigned int i;
size_t sz;
int fd;
fd = open(fn, O_RDONLY);
if ( fd < 0 )
return 0;
map = mapfile(fd, &sz);
if ( NULL == map ) {
close(fd);
return 0;
}
palette = malloc(4 * (sz / 3));
if ( NULL == palette ) {
munmap((void *)map, sz);
close(fd);
return 0;
}
palette_nr = sz / 3;
for(i = 0; i < palette_nr; i++) {
uint8_t r, g, b;
r = map[3 * i + 0];
g = map[3 * i + 1];
b = map[3 * i + 2];
#if 0
palette[4 * i + 0] = r;
palette[4 * i + 1] = g;
palette[4 * i + 2] = b;
#else
palette[4 * i + 0] = (r << 2) | (r >> 4);
palette[4 * i + 1] = (g << 2) | (g >> 4);
palette[4 * i + 2] = (b << 2) | (b >> 4);
#endif
palette[4 * i + 3] = 0xff;
}
printf("Palette: %u colours\n", sz / 3);
munmap((void *)map, sz);
close(fd);
return 1;
}
static void unpack_row(uint8_t *dst, const uint8_t *src, unsigned int row_num)
{
uint8_t idx[SYND_SUBTILE_X];
unsigned int x, j, i;
const uint8_t *in;
uint8_t *out;
in = src + 20 * (SYND_SUBTILE_Y - (row_num + 1));
for(j = 0; j < 4; j++) {
for (i = 0; i < 8; i++) {
unsigned int pos;
pos = 7 - i;
x = j * 8 + i;
idx[x] =
(((in[j] & (1 << pos)) >> pos) << 4) |
(((in[4 + j] & (1 << pos)) >> pos) << 3) |
(((in[8 + j] & (1 << pos)) >> pos) << 2) |
(((in[12 + j] & (1 << pos)) >> pos) << 1) |
(((in[16 + j] & (1 << pos)) >> pos) << 0);
assert(0 == (idx[x] & ~0x1f));
}
}
out = dst + (4 * row_num * SYND_SUBTILE_X);
for(x = 0; x < SYND_SUBTILE_X; x++, out += 4) {
#if 1
out[2] = palette[4 * (idx[x] & 0xf) + 0];
out[1] = palette[4 * (idx[x] & 0xf) + 1];
out[0] = palette[4 * (idx[x] & 0xf) + 2];
out[3] = (idx[x] & (1 << 4)) ? 0x00 : 0xff;
#else
out[2] = palette[4 * row_num] + 0;
out[1] = palette[4 * row_num] + 1;
out[0] = palette[4 * row_num] + 2;
out[3] = 0xff;
#endif
}
}
static int load_tile(unsigned int tnum, unsigned int snum, const uint8_t *ptr)
{
struct subtile *tile;
unsigned int y;
char fnbuf[64];
int fd;
tile = calloc(1, sizeof(*tile));
if ( NULL == tile )
return 0;
tile->hdr.tga_image_type = 2; /* pixmap */
tile->hdr.tga_bpp = 32; /* bgra */
tile->hdr.tga_width = htole16(SYND_SUBTILE_X);
tile->hdr.tga_height = htole16(SYND_SUBTILE_Y);
for(y = 0; y < SYND_SUBTILE_Y; y++) {
unpack_row(tile->pix, ptr, (SYND_SUBTILE_Y - (y + 1)));
}
snprintf(fnbuf, sizeof(fnbuf), "tile%u.%u.tga", tnum, snum);
fd = open(fnbuf, O_WRONLY|O_CREAT|O_TRUNC, 0600);
if ( fd < 0 ) {
free(tile);
return 0;
}
if ( write(fd, tile, sizeof(*tile)) != sizeof(*tile) ) {
close(fd);
free(tile);
return 0;
}
close(fd);
free(tile);
printf("wrote: %s\n", fnbuf);
return 1;
}
static int load_tiles(const uint8_t *map, size_t sz)
{
const uint32_t *otbl;
unsigned int i, j;
if ( sz < SYND_HBLK_MIN_OFS ) {
fprintf(stderr, "hblk: file to small: %zu < %zu\n",
sz, SYND_HBLK_MIN_OFS);
return 0;
}
otbl = (uint32_t *)map;
for(i = 0; i < SYND_NUM_TILES; i++) {
for(j = 0; j < SYND_NUM_SUBTILES; j++) {
if ( *otbl < SYND_HBLK_MIN_OFS ||
(*otbl + SYND_SUBTILE_SZ) >= sz ) {
fprintf(stderr, "tile %u.%u: BLANK\n", i, j);
}else{
load_tile(i, j, map + *otbl);
}
otbl++;
}
}
assert((uint8_t *)otbl == (map + SYND_HBLK_MIN_OFS));
return 0;
}
int main(int argc, char **argv)
{
const uint8_t *map;
size_t sz;
if ( argc < 2 )
return EXIT_FAILURE;
if ( !load_palette(argv[1]) )
return EXIT_FAILURE;
map = mapfile(STDIN_FILENO, &sz);
if ( NULL == map )
return EXIT_FAILURE;
if ( load_tiles(map, sz) )
return EXIT_FAILURE;
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment