Changeset View
Changeset View
Standalone View
Standalone View
source/blender/datatoc/datatoc_icon.c
| Show First 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| static void endian_switch_uint32(unsigned int *val) | static void endian_switch_uint32(unsigned int *val) | ||||
| { | { | ||||
| unsigned int tval = *val; | unsigned int tval = *val; | ||||
| *val = ((tval >> 24)) | ((tval << 8) & 0x00ff0000) | ((tval >> 8) & 0x0000ff00) | ((tval << 24)); | *val = ((tval >> 24)) | ((tval << 8) & 0x00ff0000) | ((tval >> 8) & 0x0000ff00) | ((tval << 24)); | ||||
| } | } | ||||
| static const char *path_slash_rfind(const char *string) | |||||
| { | |||||
| const char *const lfslash = strrchr(string, '/'); | |||||
| const char *const lbslash = strrchr(string, '\\'); | |||||
| if (!lfslash) { | |||||
| return lbslash; | |||||
| } | |||||
| if (!lbslash) { | |||||
| return lfslash; | |||||
| } | |||||
| return (lfslash > lbslash) ? lfslash : lbslash; | |||||
| } | |||||
| static const char *path_basename(const char *path) | |||||
| { | |||||
| const char *const filename = path_slash_rfind(path); | |||||
| return filename ? filename + 1 : path; | |||||
| } | |||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /* Write a PNG from RGBA pixels */ | /* Write a PNG from RGBA pixels */ | ||||
| static bool write_png(const char *name, | static bool write_png(const char *name, | ||||
| const unsigned int *pixels, | const unsigned int *pixels, | ||||
| const int width, | const int width, | ||||
| const int height) | const int height) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 95 Lines • ▼ Show 20 Lines | |||||
| /* Merge icon-data from files */ | /* Merge icon-data from files */ | ||||
| struct IconHead { | struct IconHead { | ||||
| unsigned int icon_w, icon_h; | unsigned int icon_w, icon_h; | ||||
| unsigned int orig_x, orig_y; | unsigned int orig_x, orig_y; | ||||
| unsigned int canvas_w, canvas_h; | unsigned int canvas_w, canvas_h; | ||||
| }; | }; | ||||
| struct IconInfo { | |||||
| struct IconHead head; | |||||
| char *file_name; | |||||
| }; | |||||
| struct IconMergeContext { | |||||
| /* Information about all icons read from disk. | |||||
| * Is used for sanity checks like prevention of two files defining icon for | |||||
| * the same position on canvas. */ | |||||
| int num_read_icons; | |||||
| struct IconInfo *read_icons; | |||||
| }; | |||||
| static void icon_merge_context_init(struct IconMergeContext *context) | |||||
| { | |||||
| context->num_read_icons = 0; | |||||
| context->read_icons = NULL; | |||||
| } | |||||
| /* Get icon information from the context which matches given icon head. | |||||
| * Is used to check whether icon is re-defined, and to provide useful information about which | |||||
| * files are conflicting. */ | |||||
| static struct IconInfo *icon_merge_context_info_for_icon_head(struct IconMergeContext *context, | |||||
| struct IconHead *icon_head) | |||||
| { | |||||
| if (context->read_icons == NULL) { | |||||
| return NULL; | |||||
| } | |||||
| for (int i = 0; i < context->num_read_icons; i++) { | |||||
| struct IconInfo *read_icon_info = &context->read_icons[i]; | |||||
| const struct IconHead *read_icon_head = &read_icon_info->head; | |||||
| if (read_icon_head->orig_x == icon_head->orig_x && | |||||
| read_icon_head->orig_y == icon_head->orig_y) { | |||||
| return read_icon_info; | |||||
| } | |||||
| } | |||||
| return NULL; | |||||
| } | |||||
| static void icon_merge_context_register_icon(struct IconMergeContext *context, | |||||
| const char *file_name, | |||||
| struct IconHead *icon_head) | |||||
| { | |||||
| context->read_icons = realloc(context->read_icons, | |||||
| sizeof(struct IconInfo) * (context->num_read_icons + 1)); | |||||
| struct IconInfo *icon_info = &context->read_icons[context->num_read_icons]; | |||||
| icon_info->head = *icon_head; | |||||
| icon_info->file_name = strdup(path_basename(file_name)); | |||||
| context->num_read_icons++; | |||||
| } | |||||
| static void icon_merge_context_free(struct IconMergeContext *context) | |||||
| { | |||||
| if (context->read_icons != NULL) { | |||||
| for (int i = 0; i < context->num_read_icons; i++) { | |||||
| free(context->read_icons[i].file_name); | |||||
| } | |||||
| free(context->read_icons); | |||||
| } | |||||
| } | |||||
| static bool icon_decode_head(FILE *f_src, struct IconHead *r_head) | static bool icon_decode_head(FILE *f_src, struct IconHead *r_head) | ||||
| { | { | ||||
| if (fread(r_head, 1, sizeof(*r_head), f_src) == sizeof(*r_head)) { | if (fread(r_head, 1, sizeof(*r_head), f_src) == sizeof(*r_head)) { | ||||
| #ifndef __LITTLE_ENDIAN__ | #ifndef __LITTLE_ENDIAN__ | ||||
| endian_switch_uint32(&r_head->icon_w); | endian_switch_uint32(&r_head->icon_w); | ||||
| endian_switch_uint32(&r_head->icon_h); | endian_switch_uint32(&r_head->icon_h); | ||||
| endian_switch_uint32(&r_head->orig_x); | endian_switch_uint32(&r_head->orig_x); | ||||
| endian_switch_uint32(&r_head->orig_y); | endian_switch_uint32(&r_head->orig_y); | ||||
| ▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | static bool icon_read(const char *file_src, struct IconHead *r_head, unsigned int **r_pixels) | ||||
| } | } | ||||
| success = icon_decode(f_src, r_head, r_pixels); | success = icon_decode(f_src, r_head, r_pixels); | ||||
| fclose(f_src); | fclose(f_src); | ||||
| return success; | return success; | ||||
| } | } | ||||
| static bool icon_merge(const char *file_src, | static bool icon_merge(struct IconMergeContext *context, | ||||
| const char *file_src, | |||||
| unsigned int **r_pixels_canvas, | unsigned int **r_pixels_canvas, | ||||
| unsigned int *r_canvas_w, | unsigned int *r_canvas_w, | ||||
| unsigned int *r_canvas_h) | unsigned int *r_canvas_h) | ||||
| { | { | ||||
| struct IconHead head; | struct IconHead head; | ||||
| unsigned int *pixels; | unsigned int *pixels; | ||||
| unsigned int x, y; | unsigned int x, y; | ||||
| /* canvas */ | /* canvas */ | ||||
| unsigned int *pixels_canvas; | unsigned int *pixels_canvas; | ||||
| unsigned int canvas_w, canvas_h; | unsigned int canvas_w, canvas_h; | ||||
| if (!icon_read(file_src, &head, &pixels)) { | if (!icon_read(file_src, &head, &pixels)) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| struct IconInfo *read_icon_info = icon_merge_context_info_for_icon_head(context, &head); | |||||
| if (read_icon_info != NULL) { | |||||
| printf( | |||||
| "Conflicting icon files %s and %s\n", path_basename(file_src), read_icon_info->file_name); | |||||
| free(pixels); | |||||
| return false; | |||||
| } | |||||
| icon_merge_context_register_icon(context, file_src, &head); | |||||
| if (*r_canvas_w == 0) { | if (*r_canvas_w == 0) { | ||||
| /* init once */ | /* init once */ | ||||
| *r_canvas_w = head.canvas_w; | *r_canvas_w = head.canvas_w; | ||||
| *r_canvas_h = head.canvas_h; | *r_canvas_h = head.canvas_h; | ||||
| *r_pixels_canvas = calloc(1, (head.canvas_w * head.canvas_h) * sizeof(const unsigned char[4])); | *r_pixels_canvas = calloc(1, (head.canvas_w * head.canvas_h) * sizeof(const unsigned char[4])); | ||||
| } | } | ||||
| canvas_w = *r_canvas_w; | canvas_w = *r_canvas_w; | ||||
| Show All 34 Lines | static bool icondir_to_png(const char *path_src, const char *file_dst) | ||||
| /* Takes a path full of 'dat' files and writes out */ | /* Takes a path full of 'dat' files and writes out */ | ||||
| DIR *dir; | DIR *dir; | ||||
| const struct dirent *fname; | const struct dirent *fname; | ||||
| char filepath[1024]; | char filepath[1024]; | ||||
| char *filename; | char *filename; | ||||
| int path_str_len; | int path_str_len; | ||||
| int found = 0, fail = 0; | int found = 0, fail = 0; | ||||
| struct IconMergeContext context; | |||||
| unsigned int *pixels_canvas = NULL; | unsigned int *pixels_canvas = NULL; | ||||
| unsigned int canvas_w = 0, canvas_h = 0; | unsigned int canvas_w = 0, canvas_h = 0; | ||||
| icon_merge_context_init(&context); | |||||
| errno = 0; | errno = 0; | ||||
| dir = opendir(path_src); | dir = opendir(path_src); | ||||
| if (dir == NULL) { | if (dir == NULL) { | ||||
| printf( | printf( | ||||
| "%s: failed to dir '%s', (%s)\n", __func__, path_src, errno ? strerror(errno) : "unknown"); | "%s: failed to dir '%s', (%s)\n", __func__, path_src, errno ? strerror(errno) : "unknown"); | ||||
| return false; | return false; | ||||
| } | } | ||||
| strcpy(filepath, path_src); | strcpy(filepath, path_src); | ||||
| path_str_len = path_ensure_slash(filepath); | path_str_len = path_ensure_slash(filepath); | ||||
| filename = &filepath[path_str_len]; | filename = &filepath[path_str_len]; | ||||
| while ((fname = readdir(dir)) != NULL) { | while ((fname = readdir(dir)) != NULL) { | ||||
| if (path_test_extension(fname->d_name, ".dat")) { | if (path_test_extension(fname->d_name, ".dat")) { | ||||
| strcpy(filename, fname->d_name); | strcpy(filename, fname->d_name); | ||||
| if (icon_merge(filepath, &pixels_canvas, &canvas_w, &canvas_h)) { | if (icon_merge(&context, filepath, &pixels_canvas, &canvas_w, &canvas_h)) { | ||||
| found++; | found++; | ||||
| } | } | ||||
| else { | else { | ||||
| fail++; | fail++; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| icon_merge_context_free(&context); | |||||
| closedir(dir); | closedir(dir); | ||||
| if (found == 0) { | if (found == 0) { | ||||
| printf("%s: dir '%s' has no icons\n", __func__, path_src); | printf("%s: dir '%s' has no icons\n", __func__, path_src); | ||||
| } | } | ||||
| if (fail != 0) { | if (fail != 0) { | ||||
| printf("%s: dir '%s' failed %d icons\n", __func__, path_src, fail); | printf("%s: dir '%s' failed %d icons\n", __func__, path_src, fail); | ||||
| } | } | ||||
| /* write pixels */ | /* write pixels */ | ||||
| write_png(file_dst, pixels_canvas, canvas_w, canvas_h); | write_png(file_dst, pixels_canvas, canvas_w, canvas_h); | ||||
| free(pixels_canvas); | free(pixels_canvas); | ||||
| return true; | return (fail == 0); | ||||
| } | } | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /* Main and parse args */ | /* Main and parse args */ | ||||
| int main(int argc, char **argv) | int main(int argc, char **argv) | ||||
| { | { | ||||
| const char *path_src; | const char *path_src; | ||||
| Show All 12 Lines | |||||