/* Copyright (C) 1992 Nathan Sidwell */ /* RCS $Id: scram.c,v 4.7 1993/11/09 16:27:47 nathan Stable $ */ /*{{{ about me*/ /* a simple program to compress the monochrome, mask & color sprites * together into one set of planes. This is done by color separation * overlay. Not particularly well written or documented, but then * its not supposed to be a general tool. * If anybody wants to make it more general, they are welcome * args * -n invert noswap * +n add edge to noswap * -s swap is ~noswap * +s swap is same as noswap * -m mask is solid (and therefore not present) * -c insert noswap as first color plane * -0 no monochrome * -[1-9] no monochrome, set color planes */ /*}}}*/ #include "ansiknr.h" /*{{{ includes*/ #include #include #include #include #include #include #ifdef TRANSPUTER #include #else #include #endif /* TRANSPUTER */ /*}}}*/ #define SUFFIXMONO ".bw" #define SUFFIXCOLOR ".rgb" #define MAX_PLANES 5 #define MAX_COLORS (1 << MAX_PLANES) /*{{{ typedef struct Coord*/ typedef struct Coord /* general coordinate store */ { int x; int y; } COORD; /*}}}*/ /*{{{ typedef struct Size*/ typedef struct Size /* general size store */ { unsigned x; unsigned y; } SIZE; /*}}}*/ /*{{{ typedef struct Bitmap*/ typedef struct Bitmap { char *bits; /* bit pattern */ SIZE size; /* size in pixels */ COORD hot; /* hot spot */ unsigned scan; /* scan line */ } BITMAP; /*}}}*/ static BITMAP source; static BITMAP current; static BITMAP scratch; static SIZE size; static BITMAP color_bitmap; static int color_planes = 0; static unsigned long mono_noswap; static unsigned long mono_swap; static BITMAP bitmaps[MAX_COLORS]; static char *noswap_colors[MAX_COLORS]; static char *swap_colors[MAX_COLORS]; static int colors; static char *filename; static int error = 0; #define GC_COPY 0 #define GC_AND 1 #define GC_XOR 2 #define GC_OR 3 #define GC_CLEAR 4 /*{{{ void *smalloc(size)*/ static VOID *smalloc FUNCARG((size), size_t size ) { VOID *ptr; ptr = malloc(size); if(!ptr) { fprintf(stderr, "Malloc failed\n"); exit(1); } return ptr; } /*}}}*/ /*{{{ unsigned read_bitmap(name, bitmap)*/ static unsigned read_bitmap FUNCARG((name, bitmap), char CONST *name /* name of file */ ARGSEP BITMAP *bitmap /* bitmap ptr */ ) /* state 0 new block * state 1 comment * state 2 { * state 3 reading * state 4 done */ { unsigned error; FILE *stream; unsigned state; char line[128]; SIZE place; unsigned extra; stream = fopen(name, "r"); if(!stream) return 1; error = 0; extra = 0; bitmap->size.x = bitmap->size.y = bitmap->scan = 0; bitmap->hot.x = bitmap->hot.y = -1; bitmap->bits = NULL; state = 0; while(fgets(line, sizeof(line), stream)) { char *ptr; ptr = line; while(*ptr == ' ' || *ptr == '\t') ptr++; if(*ptr == '\n') continue; /*{{{ new state?*/ if(state == 0) { if(ptr[0] == '/' && ptr[1] == '*') { ptr += 2; state = 1; } else if(!strncmp(ptr, "#define", 7)) /*{{{ define*/ { /* some poor saps don't have offsetof */ /*{{{ static char CONST *table[] =*/ static char CONST *table[] = { "width", "height", "x_hot", "y_hot" }; /*}}}*/ size_t length; unsigned ix; char CONST **tptr; ptr += 8; while(*ptr == ' ' || *ptr == '\t') ptr++; for(length = 0; ptr[length] != ' ' && ptr[length] != '\t' && ptr[length]; length++) /* EMPTY */; for(tptr = table, ix = 4; ix--; tptr++) { size_t len; len = strlen(*tptr); if(length >= len && !strncmp(&ptr[length - len], *tptr, len)) { int value; ptr += length; while(*ptr == ' ' || *ptr == '\t') ptr++; value = strtol(ptr, &ptr, 0); switch(ix) { case 3: bitmap->size.x = value; break; case 2: bitmap->size.y = value; break; case 1: bitmap->hot.x = value; break; case 0: bitmap->hot.y = value; break; } bitmap->scan = (bitmap->size.x + 7) / 8; break; } } } /*}}}*/ else { char *bptr; bptr = strchr(ptr, '['); if(bptr && bptr - ptr > 3 && !strncmp(bptr - 4, "bits", 4) && bptr[1] == ']') { state = 2; ptr = bptr; } } } /*}}}*/ /*{{{ in comment?*/ if(state == 1) { while(*ptr && state) { while(*ptr && *ptr != '*') ptr++; if(*ptr) { if(ptr[1] == '/') { ptr += 2; state = 0; break; } else ptr++; } } } /*}}}*/ /*{{{ {?*/ if(state == 2) { ptr = strchr(ptr, '{'); if(ptr) { int count; state = 3; ptr++; if(!bitmap->size.x || !bitmap->size.y) { error = 1; break; } count = bitmap->scan * bitmap->size.y; bitmap->bits = smalloc(count); place.x = place.y = 0; for(; count--;) bitmap->bits[count] = 0; } } /*}}}*/ /*{{{ reading?*/ if(state == 3) { while(state != 4 && *ptr && *ptr != '\n') { while(*ptr == ' ' || *ptr == '\t') ptr++; if(*ptr == '}') state = 4; else /*{{{ item*/ { unsigned val; val = strtol(ptr, &ptr, 0); if(*ptr == ',') ptr++; if(place.y != bitmap->size.y) { bitmap->bits[place.y * bitmap->scan + place.x] = val; place.x++; if(place.x == bitmap->scan) { place.x = 0; place.y++; } } else if(!extra) { fprintf(stderr, "Warning: Extra on end of bitmap '%s'\n", name); extra = 1; } } /*}}}*/ } } /*}}}*/ } error |= ferror(stream) || !bitmap->bits; fclose(stream); return error; } /*}}}*/ /*{{{ void malloc_bitmap(bitmap, x, y)*/ static VOIDFUNC malloc_bitmap FUNCARG((bitmap, x, y), BITMAP *bitmap ARGSEP unsigned x ARGSEP unsigned y ) { unsigned ix; bitmap->size.x = x; bitmap->size.y = y; bitmap->hot.x = bitmap->hot.y = -1; bitmap->scan = (x + 7) / 8; ix = bitmap->scan * y; bitmap->bits = smalloc(ix); while(ix--) bitmap->bits[ix] = 0; return; } /*}}}*/ /*{{{ unsigned is_blank(bitmap)*/ static unsigned is_blank FUNCARG((bitmap), BITMAP *bitmap ) { unsigned ix; unsigned bits; bits = 0; for(ix = bitmap->scan * bitmap->size.y; ix--;) bits |= bitmap->bits[ix] & 0xFF; return !bits; } /*}}}*/ /*{{{ void fill_area(bitmap, gc, x, y, w, h)*/ static VOIDFUNC fill_area FUNCARG((bitmap, gc, x, y, w, h), BITMAP *bitmap ARGSEP unsigned gc ARGSEP int x ARGSEP int y ARGSEP unsigned w ARGSEP unsigned h ) { unsigned ix; unsigned iy; int count; assert(!(x & 7) && w && h); assert(x >= 0 && y >= 0 && x + w <= bitmap->size.x && y + h <= bitmap->size.y); for(iy = 0; h--; iy++) { char *bptr; bptr = &bitmap->bits[iy * bitmap->scan]; for(ix = x / 8, count = w; count > 0; ix++, count -= 8) { unsigned mask; mask = count > 7 ? 0xFF : 0xFF >> (8 - count); switch(gc) { case GC_COPY: bptr[ix] |= mask; break; case GC_CLEAR: bptr[ix] &= ~mask; break; case GC_XOR: bptr[ix] ^= mask; break; case GC_OR: bptr[ix] |= mask; break; } } } return; } /*}}}*/ /*{{{ void copy_area(source, dest, gc, sx, sy, w, h, dx, dy)*/ static VOIDFUNC copy_area FUNCARG((source, dest, gc, sx, sy, w, h, dx, dy), BITMAP *source ARGSEP BITMAP *dest ARGSEP unsigned gc ARGSEP int sx ARGSEP int sy ARGSEP unsigned w ARGSEP unsigned h ARGSEP int dx ARGSEP int dy ) { unsigned ix; unsigned iy; char *sptr; char *dptr; char line[16]; int count; assert(sx >= 0 && sy >= 0 && sx + w <= source->size.x && sy + h <= source->size.y); assert(dx >= 0 && dy >= 0 && dx + w <= dest->size.x && dy + h <= dest->size.y); assert(w < sizeof(line) * 8); for(iy = h; iy--;) { sptr = &source->bits[(sy + iy) * source->scan + sx / 8]; /*{{{ set source pointer*/ if(sx & 7) { for(ix = 0, count = w; count > 0; ix++, count -= 8) { line[ix] = (sptr[ix] & 0xFF) >> (sx & 7); if(ix) line[ix - 1] |= (sptr[ix] & 0xFF) << (8 - (sx & 7)); else count += (sx & 7); } sptr = line; } /*}}}*/ dptr = &dest->bits[(dy + iy) * dest->scan + dx / 8]; for(ix = 0, count = w; count > 0; ix++) { unsigned mask; unsigned shift; shift = dx & 7; mask = (0xFF << shift) & 0xFF; if(count < 8 - shift) mask &= 0xFF >> ((8 - shift) - count); /*{{{ first half*/ switch(gc) { case GC_COPY: dptr[ix] &= ~mask; dptr[ix] |= ((sptr[ix] & 0xFF) << shift) & mask; break; case GC_AND: dptr[ix] &= (((sptr[ix] & 0xFF) << shift) & mask) | ~mask; break; case GC_OR: dptr[ix] |= ((sptr[ix] & 0xFF) << shift) & mask; break; case GC_XOR: dptr[ix] ^= ((sptr[ix] & 0xFF) << shift) & mask; break; } /*}}}*/ count -= 8 - shift; if(shift && count > 0) { mask = count >= 8 ? 0xFF : 0xFF >> (8 - count); mask >>= 8 - shift; /*{{{ second half*/ switch(gc) { case GC_COPY: dptr[ix + 1] &= ~mask; dptr[ix + 1] |= ((sptr[ix] & 0xFF) >> (8 - shift)) & mask; break; case GC_AND: dptr[ix + 1] &= (((sptr[ix] & 0xFF) >> (8 - shift)) & mask) | ~mask; break; case GC_OR: dptr[ix + 1] |= ((sptr[ix] & 0xFF) >> (8 - shift)) & mask; break; case GC_XOR: dptr[ix + 1] ^= ((sptr[ix] & 0xFF) >> (8 - shift)) & mask; break; } /*}}}*/ count -= shift; } } } return; } /*}}}*/ /*{{{ void draw_rectangle(bitmap, gc, x, y, w, h)*/ static VOIDFUNC draw_rectangle FUNCARG((bitmap, gc, x, y, w, h), BITMAP *bitmap ARGSEP unsigned gc ARGSEP int x ARGSEP int y ARGSEP unsigned w ARGSEP unsigned h ) { unsigned ix; unsigned iy; int count; char *bptr; unsigned mask; assert(w & h && !(x & 7)); assert(x >= 0 && y >= 0 && x + w < bitmap->size.x && y + h < bitmap->size.y); bptr = &bitmap->bits[y * bitmap->scan]; /*{{{ top and bottom edges*/ for(ix = x / 8, count = w + 1; count > 0; ix++, count -= 8) { mask = count > 7 ? 0xFF : 0xFF >> (8 - count); /*{{{ edge*/ switch(gc) { case GC_COPY: case GC_OR: bptr[ix] |= mask; bptr[ix + h * bitmap->scan] |= mask; break; case GC_CLEAR: bptr[ix] &= ~mask; bptr[ix + h * bitmap->scan] &= ~mask; break; case GC_XOR: bptr[ix] ^= mask; bptr[ix + h * bitmap->scan] ^= mask; break; case GC_AND: break; } /*}}}*/ } /*}}}*/ /*{{{ left and right edges*/ for(iy = y + 1, count = h - 2; count > 0; iy++, count--) { bptr = &bitmap->bits[iy * bitmap->scan + x / 8]; mask = 1 << (x & 7); /*{{{ left edge*/ switch(gc) { case GC_OR: case GC_COPY: *bptr |= mask; break; case GC_XOR: *bptr ^= mask; break; case GC_AND: break; case GC_CLEAR: *bptr &= ~mask; break; } /*}}}*/ bptr = &bitmap->bits[iy * bitmap->scan + (x + w) / 8]; mask = 1 << ((x + w) & 7); /*{{{ right edge*/ switch(gc) { case GC_OR: case GC_COPY: *bptr |= mask; break; case GC_XOR: *bptr ^= mask; break; case GC_AND: break; case GC_CLEAR: *bptr &= ~mask; break; } /*}}}*/ } /*}}}*/ return; } /*}}}*/ /*{{{ void make_color_pixmaps(char **name, BITMAP *bitmaps, char CONST *title)*/ static VOIDFUNC make_color_pixmaps FUNCARG((name, bitmaps, title), char **name ARGSEP BITMAP *bitmaps ARGSEP char CONST *title ) { unsigned ix; for(ix = 0; name[ix]; ix++) if(ix >= (1 << color_planes)) fill_area(&bitmaps[ix], GC_CLEAR, 0, 0, size.x, size.y); else { unsigned bit; copy_area(&source, &bitmaps[ix], GC_COPY, 0, 0, size.x, size.y, 0, 0); for(bit = 0; bit != color_planes; bit++) if((1 << bit) & ix) { copy_area(&color_bitmap, &bitmaps[ix], GC_AND, 0, (int)(size.y * bit), size.x, size.y, 0, 0); } else { copy_area(&color_bitmap, ¤t, GC_COPY, 0, (int)(size.y * bit), size.x, size.y, 0, 0); fill_area(¤t, GC_XOR, 0, 0, size.x, size.y); copy_area(¤t, &bitmaps[ix], GC_AND, 0, 0, size.x, size.y, 0, 0); } } copy_area(&source, ¤t, GC_COPY, 0, 0, size.x, size.y, 0, 0); for(ix = 0; name[ix]; ix++) copy_area(&bitmaps[ix], ¤t, GC_XOR, 0, 0, size.x, size.y, 0, 0); if(!is_blank(¤t)) { unsigned x, y; error = 1; fprintf(stderr, "%s: Error on %s at", filename, title); for(y = 0; y != size.y; y++) for(x = 0; x != size.x; x++) if(current.bits[y * current.scan + x / 8] & 1 << (x & 7)) fprintf(stderr, " (%d, %d)", x, y); fprintf(stderr, "\n"); } return; } /*}}}*/ /*{{{ void add_edge(unsigned ix, BITMAP *bitmaps)*/ static VOIDFUNC add_edge FUNCARG((ix, bitmaps), unsigned ix ARGSEP BITMAP *bitmaps ) { copy_area(&source, ¤t, GC_COPY, 0, 0, size.x, size.y, 0, 0); copy_area(&source, ¤t, GC_AND, 0, 0, size.x, size.y - 1, 0, 1); copy_area(&source, ¤t, GC_AND, 0, 1, size.x, size.y - 1, 0, 0); copy_area(&source, ¤t, GC_AND, 0, 0, size.x - 1, size.y, 1, 0); copy_area(&source, ¤t, GC_AND, 1, 0, size.x - 1, size.y, 0, 0); draw_rectangle(¤t, GC_CLEAR, 0, 0, size.x - 1, size.y - 1); copy_area(&source, ¤t, GC_XOR, 0, 0, size.x, size.y, 0, 0); copy_area(¤t, &bitmaps[ix], GC_COPY, 0, 0, size.x, size.y, 0, 0); fill_area(¤t, GC_XOR, 0, 0, size.x, size.y); while(ix--) copy_area(¤t, &bitmaps[ix], GC_AND, 0, 0, size.x, size.y, 0, 0); return; } /*}}}*/ /*{{{ void compress_colors(char **name, BITMAP *bitmaps, char CONST *title)*/ static VOIDFUNC compress_colors FUNCARG((name, bitmaps, title), char **name ARGSEP BITMAP *bitmaps ARGSEP char CONST *title ) { unsigned ix, j; for(ix = 0; name[ix + 1]; ix++) { for(j = ix + 1; name[j]; j++) if(!strcmp(name[ix], name[j])) { copy_area(&bitmaps[j], &bitmaps[ix], GC_OR, 0, 0, size.x, size.y, 0, 0); fill_area(&bitmaps[j], GC_CLEAR, 0, 0, size.x, size.y); name[j] = (char *)"-"; } } for(ix = 0; name[ix]; ix++) { if(is_blank(&bitmaps[ix])) { BITMAP old; if(strcmp(name[ix], "-")) fprintf(stderr, "Warning: %s color '%s' has no pixels\n", title, name[ix]); memcpy(&old, &bitmaps[ix], sizeof(BITMAP)); for(j = ix; name[j + 1]; j++) { name[j] = name[j+1]; memcpy(&bitmaps[j], &bitmaps[j+1], sizeof(BITMAP)); } name[j] = NULL; memcpy(&bitmaps[j], &old, sizeof(BITMAP)); ix--; } else if(!strcmp(name[ix], "-")) { unsigned x, y; error = 1; fprintf(stderr, "%s: Void color on %s at", filename, title); for(y = 0; y != size.y; y++) for(x = 0; x != size.x; x++) if(bitmaps[ix].bits[y * bitmaps[ix].scan + x / 8] & (1 << x & 7)) fprintf(stderr, " (%d, %d)", x, y); fprintf(stderr, "\n"); } } return; } /*}}}*/ /*{{{ void merge_mono()*/ static VOIDFUNC merge_mono FUNCARGVOID { unsigned ix; for(ix = 1; ix != colors; ix++) { if(is_blank(&source)) break; copy_area(&source, ¤t, GC_COPY, 0, 0, size.x, size.y, 0, 0); copy_area(&bitmaps[ix], ¤t, GC_AND, 0, 0, size.x, size.y, 0, 0); if(!is_blank(¤t)) { mono_swap |= (unsigned long)1 << ix; copy_area(¤t, &scratch, GC_COPY, 0, 0, size.x, size.y, 0, 0); copy_area(&bitmaps[ix], &scratch, GC_XOR, 0, 0, size.x, size.y, 0, 0); if(!is_blank(&scratch)) { copy_area(&bitmaps[ix], &bitmaps[colors], GC_COPY, 0, 0, size.x, size.y, 0, 0); copy_area(¤t, &bitmaps[colors], GC_XOR, 0, 0, size.x, size.y, 0, 0); noswap_colors[colors] = noswap_colors[ix]; swap_colors[colors] = swap_colors[ix]; mono_noswap = mono_noswap | (((mono_noswap >> ix) & 1) << colors); copy_area(¤t, &bitmaps[ix], GC_COPY, 0, 0, size.x, size.y, 0, 0); colors++; } copy_area(&bitmaps[ix], &source, GC_XOR, 0, 0, size.x, size.y, 0, 0); } } return; } /*}}}*/ /*{{{ int main(int argc, char **argv)*/ int main FUNCARG((argc, argv), int argc ARGSEP char **argv ) { BITMAP mono_bitmap; BITMAP mono_source; int planes; char *edge = NULL; char *noswap[MAX_COLORS + 1]; char *swap[MAX_COLORS + 1]; BITMAP noswap_bitmaps[MAX_COLORS]; BITMAP swap_bitmaps[MAX_COLORS]; int status; unsigned ix; BITMAP output_bitmap; unsigned noswap_edge = 0; unsigned noswap_invert = 0; unsigned swap_invert = 0; unsigned swap_copy = 0; unsigned no_mono = 0; unsigned mono_planes; unsigned color_copy = 0; unsigned solid_mask = 0; /*{{{ slurp up the arguments*/ { filename = argv[1]; if(argc > 2) { argv += 2; argc -= 2; for(; argc; argc--, argv++) { if(argv[0][0] == '+') { if(argv[0][2]) error = 1; else if(argv[0][1] == 's') swap_copy = 1; else if(argv[0][1] == 'n') noswap_edge = 1; else error = 1; } else if(argv[0][0] == '-') { if(!argv[0][1]) break; else if(argv[0][2]) error = 1; else if(argv[0][1] == 's') swap_invert = 1; else if(argv[0][1] == 'n') noswap_invert = 1; else if(argv[0][1] == 'c') color_copy = 1; else if(argv[0][1] == 'm') solid_mask = 1; else if(argv[0][1] == '0') no_mono = 1; else if(isdigit(argv[0][1])) { no_mono = 1; color_planes = argv[0][1] - '0'; } else error = 1; } else break; if(error) { fprintf(stderr, "'%s' not a flag\n", argv[0]); argc = 0; break; } } } for(ix = 0; argc && strcmp(*argv, "+"); argc--, argv++) noswap[ix++] = *argv; if(argc) argv++, argc--; while(ix != MAX_COLORS + 1) noswap[ix++] = NULL; for(ix = 0; argc && strcmp(*argv, "+"); argc--, argv++) swap[ix++] = *argv; if(argc) argv++, argc--; while(ix != MAX_COLORS + 1) swap[ix++] = NULL; if(argc) { edge = *argv; argv++, argc--; } if(argc || !filename || (no_mono && (noswap_edge || noswap_invert || swap_invert || swap_copy))) { fprintf(stderr, "Usage: scram [-|[+n][+s][-n][-s]] + + []\n"); return 1; } } /*}}}*/ if(no_mono) mono_planes = 1; else { mono_planes = noswap_edge | noswap_invert | swap_copy | swap_invert ? 2 : 3; if(solid_mask) mono_planes--; } /*{{{ read files*/ { char *name; name = smalloc(strlen(filename) + 7); strcpy(name, filename); strcat(name, SUFFIXMONO); status = read_bitmap(name, &mono_source); size.x = mono_source.size.x; size.y = mono_source.size.y; if(status || size.y % mono_planes) { fprintf(stderr, "Cannot read monochrome '%s'\n", name); return 1; } size.y /= mono_planes; strcpy(name, filename); strcat(name, SUFFIXCOLOR); status = read_bitmap(name, &color_bitmap); if(status) { fprintf(stderr, "Cannot read colour '%s'\n", name); return 1; } if(color_planes) size.y = color_bitmap.size.y / color_planes; else color_planes = color_bitmap.size.y / size.y; if(color_bitmap.size.y % size.y || color_bitmap.size.x != size.x) { fprintf(stderr, "Bitmaps are incompatible sizes\n"); return 1; } free(name); } /*}}}*/ /*{{{ alloc some bitmaps*/ { malloc_bitmap(&source, size.x, size.y); malloc_bitmap(¤t, size.x, size.y); malloc_bitmap(&scratch, size.x, size.y); malloc_bitmap(&mono_bitmap, size.x, size.y * 2); } /*}}}*/ /*{{{ solid mask?*/ if(solid_mask) { BITMAP temp; if(!no_mono) mono_planes++; malloc_bitmap(&temp, size.x, size.y * mono_planes); copy_area(&mono_source, &temp, GC_COPY, 0, 0, size.x, size.y * (mono_planes - 1), 0, size.y); fill_area(&temp, GC_COPY, 0, 0, size.x, size.y); memcpy(&temp.hot, &mono_source.hot, sizeof(COORD)); memcpy(&mono_source, &temp, sizeof(BITMAP)); } /*}}}*/ /*{{{ copy color?*/ if(color_copy) { BITMAP temp; color_planes++; malloc_bitmap(&temp, size.x, size.y * color_planes); copy_area(&color_bitmap, &temp, GC_COPY, 0, 0, size.x, size.y * (color_planes - 1), 0, size.y); copy_area(&mono_source, &temp, GC_COPY, 0, size.y, size.x, size.y, 0, 0); memcpy(&color_bitmap, &temp, sizeof(BITMAP)); } /*}}}*/ /*{{{ alloc a pile of bitmaps*/ { for(ix = 0; ix < MAX_COLORS; ix++) { malloc_bitmap(&bitmaps[ix], size.x, size.y); fill_area(&bitmaps[ix], GC_CLEAR, 0, 0, size.x, size.y); } for(ix = 0; ix < MAX_COLORS; ix++) { malloc_bitmap(&noswap_bitmaps[ix], size.x, size.y); fill_area(&noswap_bitmaps[ix], GC_CLEAR, 0, 0, size.x, size.y); } for(ix = 0; ix < MAX_COLORS; ix++) { malloc_bitmap(&swap_bitmaps[ix], size.x, size.y); fill_area(&swap_bitmaps[ix], GC_CLEAR, 0, 0, size.x, size.y); } } /*}}}*/ colors = !no_mono; if(!no_mono) { /*{{{ fiddle mono noswap*/ { copy_area(&mono_source, &source, GC_COPY, 0, (int)size.y, size.x, size.y, 0, 0); if(noswap_invert) fill_area(&source, GC_XOR, 0, 0, size.x, size.y); if(noswap_edge) { copy_area(&mono_source, ¤t, GC_COPY, 0, 0, size.x, size.y, 0, 0); copy_area(&mono_source, ¤t, GC_AND, 0, 0, size.x, size.y - 1, 0, 1); copy_area(&mono_source, ¤t, GC_AND, 0, 1, size.x, size.y - 1, 0, 0); copy_area(&mono_source, ¤t, GC_AND, 0, 0, size.x - 1, size.y, 1, 0); copy_area(&mono_source, ¤t, GC_AND, 1, 0, size.x - 1, size.y, 0, 0); draw_rectangle(¤t, GC_CLEAR, 0, 0, size.x - 1, size.y - 1); fill_area(¤t, GC_XOR, 0, 0, size.x, size.y); copy_area(¤t, &source, GC_OR, 0, 0, size.x, size.y, 0, 0); } copy_area(&mono_source, &source, GC_AND, 0, 0, size.x, size.y, 0, 0); copy_area(&source, &mono_bitmap, GC_COPY, 0, 0, size.x, size.y, 0, 0); } /*}}}*/ /*{{{ fiddle mono swap*/ { copy_area(&mono_source, &source, GC_COPY, 0, (int)(size.y * (mono_planes - 1)), size.x, size.y, 0, 0); if(swap_invert) fill_area(&source, GC_XOR, 0, 0, size.x, size.y); copy_area(&mono_source, &source, GC_AND, 0, 0, size.x, size.y, 0, 0); copy_area(&source, &mono_bitmap, GC_COPY, 0, 0, size.x, size.y, 0, (int)size.y); } /*}}}*/ } copy_area(&mono_source, &source, GC_COPY, 0, 0, size.x, size.y, 0, 0); make_color_pixmaps(noswap, noswap_bitmaps, "Noswap"); if(edge) { for(ix = 0; noswap[ix]; ix++) /*EMPTY*/; add_edge(ix, noswap_bitmaps); noswap[ix] = edge; } copy_area(&mono_source, &source, GC_COPY, 0, 0, size.x, size.y, 0, 0); make_color_pixmaps(swap, swap_bitmaps, "Swap"); compress_colors(noswap, noswap_bitmaps, "Noswap"); compress_colors(swap, swap_bitmaps, "Swap"); /*{{{ merge the noswap colors*/ { for(ix = 0; noswap[ix]; ix++) { copy_area(&noswap_bitmaps[ix], &bitmaps[ix + colors], GC_COPY, 0, 0, size.x, size.y, 0, 0); noswap_colors[ix + colors] = noswap[ix]; } colors = ix + colors; } /*}}}*/ /*{{{ merge the swap colors*/ for(ix = 0; swap[ix]; ix++) { unsigned j; for(j = 0; j != colors; j++) { if(is_blank(&swap_bitmaps[ix])) break; copy_area(&swap_bitmaps[ix], ¤t, GC_COPY, 0, 0, size.x, size.y, 0, 0); copy_area(&bitmaps[j], ¤t, GC_AND, 0, 0, size.x, size.y, 0, 0); if(!is_blank(¤t)) { swap_colors[j] = swap[ix]; copy_area(¤t, &scratch, GC_COPY, 0, 0, size.x, size.y, 0, 0); copy_area(&bitmaps[j], &scratch, GC_XOR, 0, 0, size.x, size.y, 0, 0); if(!is_blank(&scratch)) { copy_area(&bitmaps[j], &bitmaps[colors], GC_COPY, 0, 0, size.x, size.y, 0, 0); copy_area(¤t, &bitmaps[colors], GC_XOR, 0, 0, size.x, size.y, 0, 0); noswap_colors[colors] = noswap_colors[j]; copy_area(¤t, &bitmaps[j], GC_COPY, 0, 0, size.x, size.y, 0, 0); colors++; } copy_area(&bitmaps[j], &swap_bitmaps[ix], GC_XOR, 0, 0, size.x, size.y, 0, 0); } } } /*}}}*/ if(!no_mono) { /*{{{ merge the noswap mono*/ { copy_area(&mono_bitmap, &source, GC_COPY, 0, 0, size.x, size.y, 0, 0); merge_mono(); mono_noswap = mono_swap; mono_swap = 0; } /*}}}*/ /*{{{ merge the swap mono*/ { copy_area(&mono_bitmap, &source, GC_COPY, 0, (int)size.y, size.x, size.y, 0, 0); merge_mono(); } /*}}}*/ /*{{{ add mono color masks*/ { char st[20]; sprintf(st, "0x%lx", mono_noswap); noswap_colors[0] = strcpy(smalloc(strlen(st) + 1), st); sprintf(st, "0x%lx", mono_swap); swap_colors[0] = strcpy(smalloc(strlen(st) + 1), st); } /*}}}*/ } /*{{{ create the output bitmap*/ { unsigned mask; for(mask = 1, planes = 0; mask < colors; mask <<= 1) planes++; fprintf(stderr, "Creating %s.%s with %d colors on %d planes\n", filename, no_mono ? "packed" : "h", colors, planes); malloc_bitmap(&output_bitmap, size.x, size.y * planes); fill_area(&output_bitmap, GC_CLEAR, 0, 0, size.x, size.y * planes); for(ix = 0; ix != colors; ix++) { int bit; for(bit = 0; bit != planes; bit++) if(ix & (1 << bit)) copy_area(&bitmaps[ix], &output_bitmap, GC_OR, 0, 0, size.x, size.y, 0, (int)(bit * size.y)); } } /*}}}*/ /*{{{ write the file*/ { char *name; FILE *stream; char *ptr; unsigned x, y; unsigned count; unsigned ix; name = smalloc(strlen(filename) + 8); strcpy(name, filename); strcat(name, no_mono ? ".packed" : ".h"); ptr = strrchr(filename, '/'); if(!ptr) ptr = filename; else ptr++; stream = fopen(name, "w"); if(!stream) { fprintf(stderr, "Cannot write file\n"); return 1; } fprintf(stream, "#define %s_width %d\n", ptr, (int)size.x); fprintf(stream, "#define %s_height %d\n", ptr, (int)(size.y * planes)); if(mono_source.hot.x >= 0) { fprintf(stream, "#define %s_x_hot %d\n", ptr, mono_source.hot.x); fprintf(stream, "#define %s_y_hot %d\n", ptr, mono_source.hot.y); } if(!no_mono) fprintf(stream, "#define %s_depth %d\n", ptr, (int)planes); fprintf(stream, "static unsigned char %s_bits[] =\n{\n ", ptr); count = 10; for(y = 0; y < output_bitmap.size.y; y++) { for(x = 0; x < (output_bitmap.size.x + 7) / 8; x++) { if(!count--) { count = 9; fputs("\n ", stream); } fprintf(stream, " 0x%02x,", ((size.x - x * 8) > 7 ? 0xFF : 0xFF >> (8 - (size.x - x * 8))) & output_bitmap.bits[y * output_bitmap.scan + x]); } } fprintf(stream, "\n};\n"); if(no_mono) { fputs(" ", stdout); for(ix = 0; ix != colors; ix++) fprintf(stdout, "%s ", noswap_colors[ix]); fputs("+ \\\n", stdout); fputs(" ", stdout); for(ix = 0; ix != colors; ix++) fprintf(stdout, "%s ", swap_colors[ix]); fputs("+\n", stdout); } else { fprintf(stream, "static unsigned long %s_noswap[] =\n{\n", ptr); for(ix = 0; ix != colors; ix++) fprintf(stream, " %s,\n", noswap_colors[ix]); while(ix++ < 1 << planes) fprintf(stream, " ~(unsigned long)0,\n"); fprintf(stream, "};\n"); fprintf(stream, "static unsigned long %s_swap[] =\n{\n", ptr); for(ix = 0; ix != colors; ix++) fprintf(stream, " %s,\n", swap_colors[ix]); while(ix++ < 1 << planes) fprintf(stream, " ~(unsigned long)0,\n"); fprintf(stream, "};\n"); } if(ferror(stream)) { fprintf(stderr, "Error writing file"); error = 1; } fclose(stream); if(error) unlink(name); free(name); } /*}}}*/ return error; } /*}}}*/