nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@5: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #ifndef WIN32 nuclear@0: #include nuclear@0: #else nuclear@0: #include nuclear@0: #endif nuclear@0: #include nuclear@0: nuclear@0: struct palentry { nuclear@0: float r, g, b; nuclear@0: struct palentry *next; nuclear@0: }; nuclear@0: nuclear@5: void print_usage(const char *argv0); nuclear@0: int load_palette(const char *fname); nuclear@5: int save_palette(const char *fname); nuclear@0: int proc_tile(const char *fname); nuclear@0: float find_nearest(float r, float g, float b); nuclear@0: nuclear@0: struct palentry *palette; nuclear@0: int palsize; nuclear@5: float colscale[10] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; nuclear@5: int scale_count = 0; nuclear@5: int key = -1; nuclear@0: nuclear@0: int main(int argc, char **argv) nuclear@0: { nuclear@0: int i; nuclear@5: const char *outpalname = 0; nuclear@0: nuclear@0: for(i=1; i= pairs\n"); nuclear@5: return 1; nuclear@5: } nuclear@5: if(idx < 0 || idx >= 10) { nuclear@5: fprintf(stderr, "-f expects a z value from 0 to 9\n"); nuclear@5: return 1; nuclear@5: } nuclear@5: colscale[idx] = (float)maxcol / 255.0; nuclear@5: if(idx >= scale_count) scale_count = idx + 1; nuclear@5: } nuclear@5: break; nuclear@5: nuclear@5: case 'k': nuclear@5: { nuclear@5: char *endp; nuclear@5: long x = strtol(argv[++i], &endp, 10); nuclear@5: if(endp == argv[i]) { nuclear@5: fprintf(stderr, "-k must be followed by a palette index\n"); nuclear@5: return 1; nuclear@5: } nuclear@5: key = x; nuclear@5: } nuclear@5: break; nuclear@5: nuclear@5: case 'h': nuclear@5: print_usage(argv[0]); nuclear@5: return 0; nuclear@5: nuclear@0: default: nuclear@0: fprintf(stderr, "invalid option: %s\n", argv[i]); nuclear@5: print_usage(argv[0]); nuclear@0: return 1; nuclear@0: } nuclear@0: } else { nuclear@0: if(proc_tile(argv[i]) == -1) { nuclear@0: return 1; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@5: nuclear@5: if(outpalname) { nuclear@5: if(save_palette(outpalname) == -1) { nuclear@5: fprintf(stderr, "failed to write extended palette: %s\n", outpalname); nuclear@5: return 1; nuclear@5: } nuclear@5: } nuclear@5: nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@5: void print_usage(const char *argv0) nuclear@5: { nuclear@5: printf("Usage: %s [img1 img2 img3 ... imgN]\n", argv0); nuclear@5: printf("Options:\n"); nuclear@5: printf(" -p use palette from file\n"); nuclear@5: printf(" -f = darken the image (max brightness 'b') based on the digit (z) in its filename\n"); nuclear@5: printf(" -k colorkey index (preserve this color regardless of depth cues)\n"); nuclear@5: printf(" -h print usage and exit\n"); nuclear@5: } nuclear@5: nuclear@0: int load_palette(const char *fname) nuclear@0: { nuclear@0: FILE *fp; nuclear@0: char buf[128]; nuclear@0: struct palentry *newpal; nuclear@0: struct palentry *head = 0, *tail; nuclear@0: int nent = 0; nuclear@0: nuclear@0: if(!(fp = fopen(fname, "r"))) { nuclear@0: fprintf(stderr, "failed to open palette file: %s: %s\n", fname, strerror(errno)); nuclear@0: return -1; nuclear@0: } nuclear@0: nuclear@0: while(fgets(buf, sizeof buf, fp)) { nuclear@0: struct palentry *pent; nuclear@0: char *endp, *line = buf; nuclear@0: int r, g, b; nuclear@0: nuclear@0: if(!line || !*line) continue; nuclear@0: nuclear@0: if(*line == '#') { /* hex html-like values */ nuclear@0: unsigned int val = strtol(line + 1, &endp, 16); nuclear@0: if(endp == line) { nuclear@0: fprintf(stderr, "unrecognized line \"%s\" in palette file: %s\n", line, fname); nuclear@0: goto fail; nuclear@0: } nuclear@0: nuclear@0: r = (val >> 16) & 0xff; nuclear@0: g = (val >> 8) & 0xff; nuclear@0: b = val & 0xff; nuclear@0: } else { nuclear@0: fprintf(stderr, "unrecognized line \"%s\" in palette file: %s\n", line, fname); nuclear@0: goto fail; nuclear@0: } nuclear@0: nuclear@0: if(!(pent = malloc(sizeof *pent))) { nuclear@0: perror("failed to allocate palette entry"); nuclear@0: goto fail; nuclear@0: } nuclear@0: pent->r = (float)r / 255.0; nuclear@0: pent->g = (float)g / 255.0; nuclear@0: pent->b = (float)b / 255.0; nuclear@0: pent->next = 0; nuclear@0: nuclear@0: if(head) { nuclear@0: tail->next = pent; nuclear@0: tail = pent; nuclear@0: } else { nuclear@0: head = tail = pent; nuclear@0: } nuclear@0: nent++; nuclear@0: } nuclear@0: nuclear@0: /* flatten */ nuclear@0: if(!(newpal = malloc(nent * sizeof *newpal))) { nuclear@0: fprintf(stderr, "failed to allocate %d palette entries: %s\n", nent, strerror(errno)); nuclear@0: goto fail; nuclear@0: } nuclear@0: palette = newpal; nuclear@0: palsize = nent; nuclear@0: nuclear@0: while(head) { nuclear@0: struct palentry *ent = head; nuclear@0: head = head->next; nuclear@0: nuclear@0: *newpal++ = *ent; nuclear@0: free(ent); nuclear@0: } nuclear@0: nuclear@0: printf("loaded palette: %s (%d colors)\n", fname, nent); nuclear@0: nuclear@0: fclose(fp); nuclear@0: return 0; nuclear@0: nuclear@0: fail: nuclear@0: fclose(fp); nuclear@0: while(head) { nuclear@0: void *tmp = head; nuclear@0: head = head->next; nuclear@0: free(tmp); nuclear@0: } nuclear@0: return -1; nuclear@0: } nuclear@0: nuclear@5: int save_palette(const char *fname) nuclear@5: { nuclear@5: FILE *fp; nuclear@5: int i, j; nuclear@5: int extsize = palsize * scale_count; nuclear@5: nuclear@5: printf("saving extended palette: %s\n", fname); nuclear@5: nuclear@5: if(!(fp = fopen(fname, "w"))) { nuclear@5: fprintf(stderr, "failed to save extended palette: %s: %s\n", fname, strerror(errno)); nuclear@5: return -1; nuclear@5: } nuclear@5: nuclear@5: if(extsize > 256) { nuclear@5: fprintf(stderr, "warning: extended palette size too large (%d)\n", extsize); nuclear@5: } nuclear@5: nuclear@5: for(i=0; i 255) r = 255; nuclear@5: if(g > 255) g = 255; nuclear@5: if(b > 255) b = 255; nuclear@5: nuclear@5: fprintf(fp, "#%02x%02x%02x\n", r, g, b); nuclear@5: } nuclear@5: } nuclear@5: fclose(fp); nuclear@5: return 0; nuclear@5: } nuclear@5: nuclear@0: int proc_tile(const char *fname) nuclear@0: { nuclear@0: int i; nuclear@0: int xsz, ysz; nuclear@0: unsigned char *pixels, *pptr; nuclear@0: char *outfname, *cptr; nuclear@0: FILE *fp; nuclear@0: const char *magic = "TILEIMAG"; nuclear@5: int zidx = -1; nuclear@0: nuclear@0: outfname = alloca(strlen(fname) + 4); nuclear@0: strcpy(outfname, fname); nuclear@0: if((cptr = strrchr(outfname, '.'))) { nuclear@0: *cptr = 0; nuclear@0: } nuclear@0: strcat(outfname, ".til"); nuclear@0: nuclear@5: cptr = outfname + strlen(outfname) - 1; nuclear@5: while(cptr >= outfname && !isdigit(*cptr)) --cptr; nuclear@5: if(cptr >= outfname) { nuclear@5: zidx = *cptr - '0'; nuclear@5: } nuclear@5: nuclear@0: printf("processing tile: %s -> %s\n", fname, outfname); nuclear@0: nuclear@0: if(!(pixels = img_load_pixels(fname, &xsz, &ysz, IMG_FMT_RGB24))) { nuclear@0: fprintf(stderr, "failed to load source tile image: %s\n", fname); nuclear@0: return -1; nuclear@0: } nuclear@0: if(!(fp = fopen(outfname, "wb"))) { nuclear@0: fprintf(stderr, "failed to open output tile image for writing: %s: %s\n", outfname, strerror(errno)); nuclear@0: img_free_pixels(pixels); nuclear@0: return -1; nuclear@0: } nuclear@0: /* write header */ nuclear@0: fwrite(magic, 1, 8, fp); nuclear@0: fwrite(&xsz, sizeof xsz, 1, fp); nuclear@0: fwrite(&ysz, sizeof ysz, 1, fp); nuclear@0: nuclear@0: pptr = pixels; nuclear@0: for(i=0; i 0 && idx != key) { nuclear@5: /* shift the indices to the appropriate copy of the palette */ nuclear@5: idx += zidx * palsize; nuclear@5: } nuclear@5: nuclear@0: fputc(idx, fp); nuclear@0: pptr += 3; nuclear@0: } nuclear@0: img_free_pixels(pixels); nuclear@0: fclose(fp); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: float find_nearest(float r, float g, float b) nuclear@0: { nuclear@0: int i, res; nuclear@0: float mindist = FLT_MAX; nuclear@0: nuclear@0: for(i=0; i