/* Standard */ #include //exit, malloc #include //print #include //va_args #include //memset, str* #include /* Unicode */ #include //u8_* functions #include //uint8_t as a char #include //u32_cpy #include //ulc_fprintf /* Local */ #include "print.h" #include "apc.h" #include "ir.h" #include "pagenode.h" #undef do_error #define do_error(...) exit(-1) #define XXH_PRIVATE_API #include "../xxHash/xxhash.h" #define STB_IMAGE_IMPLEMENTATION #include "../stb/stb_image.h" #define STB_IMAGE_WRITE_IMPLEMENTATION #include "../stb/stb_image_write.h" /* Public */ void ir_binout_init(struct ir_class_t*); /* Memory Allocation */ #define struct_alloc(_T) ((struct _T*) stack_alloc(&datapages, sizeof(struct _T))) static struct pagelist_t linkpages, datapages; enum model_type { SS }; /* Binaryout out structure definitions */ struct bin_img_info_t { int height; int width; int fwidth; //map and frame width int fheight; //map and frame height int unaligned_width; int unaligned_height; }; struct bin_ht_header_t { long start; int entries; }; struct bin_ht_entry_t { uint32_t key; long value; }; struct bin_class_header_t { struct bin_ht_header_t child_ht; struct bin_ht_header_t rootset_ht; int namelen; }; struct bin_set_header_t { struct bin_ht_header_t child_ht; long sdat_start; //points to setdata_header int namelen; }; struct bin_setdata_header_t { struct bin_ht_header_t variant_ht; long attach_pos; }; struct bin_model_header_t { //one for each framebox, currently long facing_array_start; enum model_type type; }; struct bin_frame_header_t { int width; int height; int frames; long op_start; }; struct bin_plink_t { enum ltype type; ir_set trg_set; uint8_t* name; long src_pos; }; struct bin_pixel_t { int x, y, z; uint32_t ref; int attach_idx; }; struct bin_pixel_node_t { struct bin_pixel_node_t* next; struct bin_pixel_t data; }; struct bin_attachment_header_t { int num_attachment_lists; int num_attachments; }; struct bin_attachment_t { int x, y, z, idx; ir_set set; }; /* Read out of the als, after first ir pass, resolves the attach_pos of the src-set that created the attachment_list to the header that describes the attachment_list */ struct bin_attachment_list_t { int num_attachments; struct bin_attachment_t** attachments; long filepos; }; struct bin_attachment_list_t **attachment_stack, **asp; //attachment_stack, attachment_stack_pointer FILE* binaryout; #define NAMEHASH(name, domain) (XXH32(name, u8_strlen(name), 0XCEED ) & domain) static inline int bin_set_varcount ( ir_set set ) { int count; framebox set_fb; framebox iter; set_fb = ir_set_framebox(set); count = 0; for (iter = set_fb; iter != NULL; iter = ir_setdata_nextsib(iter)) count++; return count; } static inline int bin_class_sibcount ( ir_class class ) { int count; ir_class iter; count = 0; for (iter = class; iter != NULL; iter = ir_class_nextsib(iter)) count++; return count; } static inline int bin_set_sibcount ( ir_set set ) { int count; ir_set iter; count = 0; for (iter = set; iter != NULL; iter = ir_set_nextsib(iter)) count++; return count; } /* Given a position and a size, checks if the bytes are null and returns the file position to where it started. 1 if not null, 0 if null*/ /* TODO: Determine why fseeking file past end sets bytes to -1, and not 0 */ static inline int bytes_null( int len, int pos ) { while(len--) { if(fgetc(binaryout) > 0) { fseek(binaryout, pos, SEEK_SET); return 1; } } fseek(binaryout, pos, SEEK_SET); return 0; } /* Checks if the key at entrypos is the same as the parameter key. Returns 1 if so, 0 if not. */ static inline int bin_keys_identical ( long entry_pos, uint32_t key ) { uint32_t curr_key; fseek(binaryout, entry_pos, SEEK_SET); fscanf(binaryout, "%u", &curr_key); if( curr_key == key) return 1; return 0; } long bin_traverse_class(ir_class); /* Takes root class and begins processing */ void ir_binout_init(ir_class root_class) { binaryout = fopen("binaryout", "w+"); asp = attachment_stack; pagelist_init(datapages, (size_t) SYS_PAGESIZE); pagelist_init(linkpages, (size_t) SYS_PAGESIZE); bin_traverse_class(root_class); } #define ENTRY_OCCUPIED() (bytes_null(sizeof(ht_entry->key), entry_pos)) #define WRITE_ENTRY() do { \ if(fseek(binaryout, entry_pos, SEEK_SET) == -1) wprintf("fseek failed with %s", strerror(errno)); \ fwrite(&ht_entry, sizeof ht_entry, 1, binaryout); \ } while (0) #define LOOP_ENTRY(_HTSTART) (entry_pos = _HTSTART) #define INC_ENTRY() do { \ entry_pos += sizeof(ht_entry); \ if(fseek(binaryout, entry_pos, SEEK_SET) == -1) eprintf("fseek failed with %s", strerror(errno)); \ } while (0) #define HT_END(_HTEND) (entry_pos >= _HTEND) //just in case at last entry void /* TODO: Should overwrite be a default? */ bin_insert_ht_entry ( long ht_start, long ht_size, struct bin_ht_entry_t* ht_entry, int overwrite ) { long entry_pos, ht_end; ht_end = ht_start + ht_size; entry_pos = ht_start + sizeof(ht_entry) * ht_entry->key; fseek(binaryout, entry_pos, SEEK_SET); if (!ENTRY_OCCUPIED()) { uprintf("key not occupied\n"); WRITE_ENTRY(); } while( ENTRY_OCCUPIED() ) { if(overwrite) { if(bin_keys_identical(entry_pos, ht_entry->key)) break; else { eprintf("error in hashtable insertion, keys are identical"); } } if (HT_END(ht_end)) LOOP_ENTRY(ht_start); else INC_ENTRY(); } WRITE_ENTRY(); } /* | class header | |--------------------| | rootset ht | |--------------------| | rootsets data | |--------------------| | classchild ht | |--------------------| | classchild header | | ... | */ long bin_traverse_set(ir_set); long #define HT_INIT(_START, _SIZE, _INIT_ENTRIES) do { \ _SIZE = _INIT_ENTRIES ? (_INIT_ENTRIES * (sizeof(struct bin_ht_entry_t) << 1)): 0; \ _START = ftell(binaryout); \ fseek(binaryout, _SIZE, SEEK_CUR); \ } while (0) bin_traverse_class ( ir_class class) { ir_class citer; ir_set siter; struct bin_class_header_t class_header; struct bin_ht_entry_t ht_entry; long class_start, classht_start, classht_size, rootsetht_start, rootsetht_size; int num_csibs, num_ssibs; uint8_t* class_name; class_start = ftell(binaryout); class_name = ir_class_name(class); num_csibs = bin_class_sibcount(class); num_ssibs = bin_set_sibcount(ir_class_rootset(class)); /* alloc space (before hash tables) for class header */ class_header.namelen = u8_strlen(class_name); fseek(binaryout, class_start + sizeof(class_header) + class_header.namelen ,SEEK_SET); HT_INIT(classht_start, classht_size, num_csibs); HT_INIT(rootsetht_start, rootsetht_size, num_ssibs); /* TODO: Figure out generic way to output headers */ /* populate class header */ class_header.child_ht.entries = num_csibs; class_header.child_ht.start = classht_start; class_header.rootset_ht.entries = num_ssibs; class_header.rootset_ht.start = rootsetht_start; fseek(binaryout, class_start, SEEK_SET); //seek back to where we allocated header fwrite(&class_header, sizeof(class_header), 1, binaryout); fwrite(class_name, class_header.namelen, 1, binaryout); /* Start populating root_set hash table */ for ( siter = ir_class_rootset(class); siter != NULL; siter = ir_set_nextsib(siter)) { fseek(binaryout, 0, SEEK_END); ht_entry.key = NAMEHASH(ir_set_name(siter), num_ssibs << 1); ht_entry.value = bin_traverse_set(siter); bin_insert_ht_entry(rootsetht_start, rootsetht_size, &ht_entry, 0); } /* Start populating class child hash table */ for ( citer = ir_class_nextchild(class); citer != NULL; citer = ir_class_nextsib(citer)) { if(chdir((char*) class_name)) eprintf("CHDIR %U from %s\n",(char*) class_name,getcwd(NULL,255)); fseek(binaryout, 0, SEEK_END); ht_entry.key = NAMEHASH(ir_class_name(citer), num_csibs << 1); ht_entry.value = bin_traverse_class(citer); bin_insert_ht_entry(classht_start, classht_size, &ht_entry, 0); if (chdir("..")) eprintf("CHDIR ..\n"); } return class_start; } long bin_process_sdat( ir_set); /* | set header |--| |-----------------| | | set data |<-| |-----------------| | ---| setchild ht |<-- | |-----------------| |->| setchild header | |->| ... | */ long bin_traverse_set ( ir_set set ) { ir_set iter; struct bin_set_header_t header; struct bin_ht_entry_t ht_entry; int num_child, setname_len; long childht_start, childht_size, set_start; uint8_t* set_name; set_start = ftell(binaryout); set_name = ir_set_name(set); /* alloc space for set header */ setname_len = u8_strlen(set_name); fseek(binaryout, sizeof(struct bin_set_header_t) + setname_len , SEEK_CUR); /* process the set data */ header.sdat_start = bin_process_sdat(set); /* Setup child hash table for current sets children */ num_child = bin_set_sibcount(ir_set_nextchild(set)); HT_INIT(childht_start, childht_size, num_child); /* populate header, write to file */ header.child_ht.entries = num_child; header.child_ht.start = childht_start; fseek(binaryout, set_start, SEEK_SET); fwrite(&header, sizeof(struct bin_set_header_t), 1, binaryout); fwrite(set_name, setname_len, 1, binaryout); for(iter = ir_set_nextchild(set); iter != NULL; iter = ir_set_nextsib(iter)) { fseek(binaryout, 0, SEEK_END); ht_entry.key = NAMEHASH(ir_set_name(iter), num_child << 1); ht_entry.value = bin_traverse_set(iter); bin_insert_ht_entry(childht_start, childht_size, &ht_entry, 0); } ir_set_assign_fpos(set, set_start); return set_start; } /* | sdat header | |------------------| | variant ht | |------------------| | 1st variant data | -- variant == framebox |------------------| | 2nd variant data | |------------------| | etc. | */ void bin_insert_links(int, struct bin_ht_header_t*, long); struct bin_pixel_node_t* bin_find_default_pixel_list(ir_set); void bin_process_frameboxes(ir_set, struct bin_ht_header_t*, struct bin_pixel_node_t*); int bin_process_links(ir_set, ir_setdata); /* Init the variant hash table for the set, process the sets links and add them to link_stack and variant hash table, and then output the actual framedata */ long bin_process_sdat ( ir_set set ) { struct bin_setdata_header_t header; struct bin_attachment_list_t attachment_list; struct bin_pixel_node_t *default_pixel_list; struct bin_ht_header_t ht_header; long varht_start, varht_size, sdat_start; int num_entries, num_links; ir_setdata olink_head; sdat_start = ftell(binaryout); /* Alloc position for sdat_header */ fseek(binaryout, sizeof(struct bin_setdata_header_t), SEEK_CUR); num_links = bin_process_links(set, olink_head); num_entries = bin_set_varcount(set) + num_links; HT_INIT(varht_start, varht_size, num_entries); /* Populate the sdat_header */ fseek(binaryout, 0, sdat_start); header.variant_ht.start = ht_header.start = varht_start; header.variant_ht.entries = ht_header.entries = num_entries; attachment_list.filepos = header.attach_pos = ftell(binaryout) + sizeof(varht_start) + sizeof(num_entries); fwrite(&header, sizeof(header), 1, binaryout); fseek(binaryout, 0, SEEK_END); /* insert the links that were processed into the variant hash table */ bin_insert_links(num_links, &ht_header, attachment_list.filepos); /* Determine the default pixel list for all of the frameboxes */ default_pixel_list = bin_find_default_pixel_list(set); /* Output each framebox, and insert it into the variant hash table */ bin_process_frameboxes(set, &ht_header, default_pixel_list); /* TODO: Convert the default pixel list to an attachment_list and then push the */ /* sdats attachment_list onto the attachment_stack so it can be procesed */ return sdat_start; } /* Adds a vlink onto the stack_alloc to be popped during the processing of the sets variant hash table. If the vlink has a name, its a vlink to a single variant. if the vlink doesnt have a name, its the vlink to an entire variant hash table, and each variant (framebox) needs to be added */ int bin_process_vlink ( ir_setdata vlink, ir_set trg_set ) { struct bin_plink_t* plp; ir_setdata fiter; uint8_t* link_name; int num_links; num_links = 0; /* TODO: Macroize? or not worth? */ link_name = ir_setdata_name(vlink); if (link_name) { plp = struct_alloc(bin_plink_t); plp->src_pos = 0; // TBD @ process_setdata plp->name = link_name; plp->trg_set = trg_set; plp->type = VLINK; num_links++; } else // linking a variant hash table for (fiter = ir_set_framebox(trg_set); fiter != NULL; fiter = ir_setdata_nextsib(fiter)) { plp = struct_alloc(bin_plink_t); plp->src_pos = 0; // TBD @ process_setdata plp->name = ir_setdata_name(fiter); plp->trg_set = trg_set; plp->type = VLINK; num_links++; } return num_links; } /* Adds an mlink to the stack_alloc, to be processed later */ int bin_process_mlink ( ir_setdata mlink, ir_set trg_set ) { struct bin_plink_t* plp; uint8_t* mlink_name; mlink_name = ir_setdata_name(mlink); plp = struct_alloc(bin_plink_t); plp->src_pos = 0; //TBD after resolving the childlist | TODO: attach_pos? if(mlink_name) plp->name = mlink_name; plp->trg_set = trg_set; plp->type = MLINK; return 1; } /* TODO: implement this */ /* Determine if olink is already part of the olink_list. if it is, theres a cycle, return 1. Else return 0. */ static inline int olink_cycle ( ir_setdata olink, ir_setdata olink_head ) { ir_setdata iter; return 0; } /* Given a set, determine the number of links it has and process each link and then add them to stack_alloc, where they will be popped off and further processed. */ int bin_process_links ( ir_set src_set, ir_setdata olink_head ) { int num_links; linkdata liter; //link iter ir_set trg_set; num_links = 0; for(liter = ir_set_link(src_set); liter != NULL; liter = ir_setdata_nextsib((ir_setdata) liter)) { trg_set = ir_set_from_ref(ir_linkdata_ref(liter)); switch (ir_linkdata_type(liter)) { case OLINK: if (olink_cycle(liter, olink_head)) //TODO: stack of olinks to iterate and check for cycles? return num_links; num_links += bin_process_vlink(liter, trg_set); num_links += bin_process_mlink(liter, trg_set); num_links += bin_process_links(trg_set, liter); break; case VLINK: num_links += bin_process_vlink(liter, trg_set); break; case MLINK: num_links += bin_process_mlink(liter, trg_set); break; case ALINK: //TODO: ? break; } } return num_links; } /* Insert both mlinks and vlinks into the link stack, after determining their src_pos. Vlinks have an additional requirement of being added into the variant hash table */ #define pop_linkp() (*(struct bin_plink_t**) pagelist_pop(&datapages, sizeof(struct bin_plink_t*))) #define PUSH_PLINK(_LINK) (*(struct bin_plink_t**) stack_alloc(&linkpages, sizeof (_LINK)) = _LINK ) void bin_insert_links ( int num_links, struct bin_ht_header_t* ht, long attach_pos ) { struct bin_plink_t* plp; struct bin_ht_entry_t ht_entry; int i; /* Insert vlinks into hash table, put v/mlinks on link stack to be processed later */ for ( i = 0; i < num_links; i++) { plp = pop_linkp(); switch (plp->type) { case MLINK: plp->trg_set = plp->trg_set; plp->src_pos = attach_pos; PUSH_PLINK(plp); break; case VLINK: ht_entry.key = NAMEHASH(plp->name, ht->entries << 1); ht_entry.value = 0; bin_insert_ht_entry(ht->start, ht->entries * sizeof(ht_entry), &ht_entry, 0); plp->src_pos = ht_entry.key + sizeof(ht_entry.key); PUSH_PLINK(plp); break; case OLINK: break; //shouldnt exist case ALINK: break; //TBD } } } long bin_process_facing(ir_setdata, apc_facing, struct bin_pixel_node_t*); /* |-------------------| | framebox header | |-------------------| | SFACE framesheet | |-------------------| | SWFACE framesheet | |-------------------| | etc. | */ long bin_process_framebox ( ir_set set, ir_setdata framebox, struct bin_pixel_node_t* default_pixel_list ) { struct bin_model_header_t header; long framebox_start, index_pos; int i; framebox_start = ftell(binaryout); /* insert model header */ header.type = SS; header.facing_array_start = framebox_start + sizeof(header); fwrite(&header, sizeof(header), 1, binaryout); /* Create the index array for framesheet of each direction */ for ( i = SFACE; i < FACING_MAX; i++) { fseek(binaryout, 0, SEEK_END); index_pos = bin_process_facing(framebox, i, default_pixel_list); //TODO: finish process_direction fseek(binaryout, header.facing_array_start + i * sizeof(long), SEEK_SET); fwrite(&index_pos, sizeof(long), 1, binaryout); } return framebox_start; } void bin_process_frameboxes ( ir_set set, struct bin_ht_header_t* ht, struct bin_pixel_node_t* default_pixel_list ) { struct bin_ht_entry_t ht_entry; ir_setdata fiter; /* Insert variants into hash table to overwrite olink insertions*/ for ( fiter = ir_set_framebox(set); fiter != NULL; fiter = ir_setdata_nextsib(fiter)) { fseek(binaryout, 0, SEEK_END); ht_entry.key = NAMEHASH(ir_setdata_name(fiter), ht->entries << 1); ht_entry.value = bin_process_framebox(set, fiter, default_pixel_list); bin_insert_ht_entry(ht->start, ht->entries * sizeof(ht_entry), &ht_entry, 1); } } /* Determine clipping based on image height/width and frame height/width */ static inline void bin_set_img_info ( struct bin_img_info_t* img_info, ir_setdata frame_data ) { ir_frameinfo frameinfo; frameinfo = ir_framedata_frameinfo(frame_data); img_info->fwidth = frameinfo->w; img_info->fheight = frameinfo->h; img_info->unaligned_height = img_info->height % img_info->fheight; img_info->unaligned_width = img_info->width % img_info->fwidth; } /* |-----------------------------| | frame header | |-----------------------------| | pixel data for frame1 - n | |-----------------------------| | op data for frame1 - n | |-----------------------------| */ long #define GENERATE_FILENAME(_N) ((char*) u8_strcat(_N, png_suffix)) bin_process_facing ( ir_setdata framebox, apc_facing facing, struct bin_pixel_node_t* default_pixel_list ) { struct bin_img_info_t mapsheet_info, framesheet_info; int num_mapchannels, num_framechannels, x; struct bin_frame_header_t header; long facing_start; unsigned char* mapdata, * framedata; uint8_t* png_suffix = ".png"; struct bin_pixel_node_t* map_pixel_list; facing_start = ftell(binaryout); /* Set up data pointers to mapsheet and framesheet, as well as their image infos */ mapdata = stbi_load(GENERATE_FILENAME(ir_setdata_name((ir_setdata) ir_framebox_mapsheet(framebox,SFACE))), &mapsheet_info.width, &mapsheet_info.width, &num_framechannels , 0); framedata = stbi_load(GENERATE_FILENAME(ir_setdata_name((ir_setdata) ir_framebox_framesheet(framebox,SFACE))), &framesheet_info.width, &framesheet_info.height, &num_mapchannels, 0); bin_set_img_info(&framesheet_info, ir_framebox_framesheet(framebox, SFACE)); bin_set_img_info(&mapsheet_info, ir_framebox_mapsheet(framebox, SFACE)); /* Allocate space for header */ fseek(binaryout, sizeof(header), SEEK_CUR); /* Output framesheet */ if(!stbi_write_png(binaryout, framesheet_info.width, framesheet_info.height, 4, mapdata, framesheet_info.fwidth)) eprintf("error writing out framesheet\n"); /* Output framesheet header */ header.width = framesheet_info.fwidth; header.height = framesheet_info.fheight; header.frames = framesheet_info.width / framesheet_info.fwidth; //TODO: division is bad header.op_start = ftell(binaryout); fseek(binaryout, facing_start, SEEK_SET); fwrite(&header, sizeof(header), 1, binaryout); fseek(binaryout, 0, SEEK_END); /* Assuming that fheight = image height */ /* For each mapframe in mapsheet */ for ( x = 0; x < header.frames; x++) { map_pixel_list = bin_map_to_pixel_list(mapsheet_info, 0, x * mapsheet_info.fwidth, data); if(!bin_process_map_pixel_list(default_pixel_list, map_pixel_list)) eprintf("error processing map pixel list\n"); bin_output_pixel_list(map_pixel_list); data += mapsheet_info.fwidth; } /* Determine pixel_list */ /* Output pixel_list */ return facing_start; } /* TODO: Please rename all the functions jhc*/ static inline void bin_number_pixel_list ( struct bin_pixel_node_t* pixel_list ) { int num = 0; struct bin_pixel_node_t* iter; while (iter) { iter.data.attach_idx = num++; iter = iter->next; } } /* Assuming at this point that map_pixel_list is valid */ static inline int bin_set_map_pixel_list_attach_idxs ( struct bin_pixel_node_t* default_pixel_list, struct bin_pixel_node_t* map_pixel_list ) { struct bin_pixel_node_t* mapiter, defaultiter; mapiter = map_pixel_list; defaultiter = default_pixel_list; while (mapiter && defaultiter) { /* if mapiter.data.ref == defaultiter.data.ref, assign mapiter index_idx to defaultiter */ if (mapiter.data.ref == defauliter.data.ref) { defaultiter.data.attach_idx = mapiter.data.attach_idx; mapiter = mapiter->next; defaultiter = defaultiter->next; } else defaultiter = defaultiter->next; } } /* map_pixel_list cannot have more pixels. for all of its pixels, the refs must be represented in default pixel list. 0 if invalid, 1 if valid */ static inline int bin_valid_map_pixel_list ( struct bin_pixel_node_t* default_pixel_list, struct bin_pixel_node_t* map_pixel_list ) { struct bin_pixel_node_t* mapiter, defaultiter; defaultiter = default_pixel_list; /* check length of each to make sure default < max */ /* for each pixel node in default and map */ while(defaultiter) { for( mapiter = map_pixel_list; mapiter != NULL; mapiter = mapiter->next) { } } if(!mapiter && defaultiter) //defaultiter is longer so error! return 0; } static inline int bin_process_map_pixel_list ( struct bin_pixel_node_t* default_pixel_list, struct bin_pixel_node_t* map_pixel_list ) { /* Determine if pixel_list is valid */ /* Determine attach_idx of each pixel, as compared to default pixel list */ } void bin_assign_pixel_idxs ( struct bin_pixel_node_t* pixel_list ) { } /* Insert pixel(s) into the list, z sorted */ /* number the pixels as you insert them */ struct bin_pixel_node_t* bin_insert_node_into_list ( struct bin_pixel_node_t* pixel_list_root, struct bin_pixel_node_t* pixel_node ) { struct bin_pixel_node_t* head_node, * prev_node; if(pixel_list_root == NULL) { pixel_list_root = pixel_node; } prev_node = head_node = pixel_list_root; while(head_node != NULL) { if(pixel_node->data.z > head_node->data.z) { if(head_node->next) { prev_node = head_node; head_node = head_node->next; } else { head_node->next = pixel_node; break; } } else if (pixel_node->data.z < head_node->data.z || pixel_node->data.z == head_node->data.z) { prev_node->next = pixel_node; pixel_node->next = head_node; break; } } return pixel_list_root; } /* TODO: Finish this */ struct bin_pixel_node_t* bin_process_pixel ( unsigned char* data, int x, int y, int init_height, int init_width ) { struct bin_pixel_node_t* pixel_node; pixel_node = struct_alloc(bin_pixel_node_t); if(data) { /* get ref from 4 bytes of data */ pixel_node->data.ref = (int) data; /* bitshift by ? to get Z */ pixel_node->data.z = ((int) data << 24); /* set x and y */ pixel_node->data.x = x + init_width ; pixel_node->data.y = y + init_width; data += 4; } else { data += 4; //TODO: does this correctly increment past 0x00000000? return NULL; } return pixel_node; } /* Returns the non null pixels of a single map */ /* TODO: Finish this */ struct bin_pixel_node_t* bin_mapframe_to_pixel_list ( struct bin_img_info_t* img_info, int init_height, int init_width, unsigned char* data ) { int x, y, fheight, fwidth; struct bin_pixel_node_t* pixel_list, * pixel_node; pixel_list = NULL; /* if frame clips, process unclippign frames */ if( img_info->unaligned_width ) { if(img_info->height < img_info->fheight) fheight = img_info->height; else fheight = img_info->fheight; } else fheight = img_info->fheight; if (img_info->unaligned_height ) { if(img_info->width < img_info->fwidth) fwidth = img_info->width; else fwidth = img_info->fwidth; } else fwidth = img_info->fwidth; /* Process the map*/ for (y = 0; y < fheight; y++) { for ( x = 0; x < fwidth; x++ ) { pixel_node = bin_process_pixel(data, x, y, init_height, init_width); pixel_list = bin_insert_node_into_list(pixel_list, pixel_node); data += img_info->width - img_info->fwidth; //stride } } return pixel_list; } static inline int bin_pixel_list_len ( struct bin_pixel_node_t* pl ) { struct bin_pixel_node_t* plp; int count; count = 0; plp = pl; while(plp) { count++; plp = plp->next; } return count; } struct bin_pixel_node_t* bin_cmp_default_pixel_lists ( struct bin_pixel_node_t* pl1, struct bin_pixel_node_t* pl2 ) { struct bin_pixel_node_t* pl1p, * pl2p; int i, pl1_len, pl2_len; pl1p = pl1; pl2p = pl2; pl1_len = bin_pixel_list_len(pl1); pl2_len = bin_pixel_list_len(pl2); if (pl1_len > pl2_len) return pl1; else if (pl1_len < pl2_len) return pl2; /* pl1 == pl2, make sure that all refs are the same */ /* TODO: what type of warning/error handling should occur here? */ for (i = 0; i < pl1_len; i++) { if (pl1p->data.ref != pl2p->data.ref) eprintf("Error in determining default pixel list\n"); pl1p = pl1p->next; pl2p = pl2p->next; } return pl1; //doesnt matter which one you return } /* Find default framebox, based on the framebox with the most attachments*/ /* Search through first frame of S of each framebox */ struct bin_pixel_node_t* bin_find_default_pixel_list ( ir_set set) { ir_setdata fiter; struct bin_pixel_node_t* default_pixel_list, * curr_pixel_list; unsigned char* data; int num_channels; struct bin_img_info_t img_info; for (fiter = ir_set_framebox(set); fiter != NULL; fiter = ir_setdata_nextsib(fiter)) { /* TODO: Stringify the frame name with .png? */ /* TODO: Add directory changing */ data = stbi_load(ir_setdata_name((ir_setdata) ir_framebox_mapsheet(fiter,SFACE) ), &img_info.width, &img_info.width, &num_channels, 0); bin_set_img_info(&img_info, ir_framebox_mapsheet(fiter, SFACE)); curr_pixel_list = bin_mapframe_to_pixel_list(&img_info, 0, 0, data); default_pixel_list = bin_cmp_default_pixel_lists(curr_pixel_list, default_pixel_list); free(data); } return default_pixel_list; }