/* 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 */ #define eprintf_callback(...) exit(EXIT_FAILURE) #include "print.h" #include "apc.h" #include "ir.h" #include "pagenode.h" #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, plinkpages; 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_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 iter; count = 0; for (iter = ir_set_framebox(set); 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; } typedef RGBA_t uint32_t; 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 long /* 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(); return entry_pos; } /* | 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 | |------------------| | num dlinks | |------------------| | dlink len | |------------------| | dlink string | |------------------| | variant ht | |------------------| | 1st variant data | -- variant == framebox |------------------| | 2nd variant data | |------------------| | etc. | */ void bin_insert_links(struct bin_processed_lists_t*, 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); int bin_process_dlinks(struct bin_processed_lists_t*); /* 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; struct bin_processed_links_t* processed_links_root; long varht_start, varht_size, sdat_start; int num_entries, num_links; sdat_start = ftell(binaryout); /* Alloc position for sdat_header */ fseek(binaryout, sizeof(struct bin_setdata_header_t), SEEK_CUR); /* set up root for processed_links */ processed_links_root = stack_alloc(&plinkpages, bin_processed_links_t); processed_links_root_val->mlink_len = processed_links_root->vlink_len = 0; processed_links_root = bin_process_links(set, processed_links_root); num_links = processed_links_root->mlink_len + processed_links_root->vlink_len; 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); /* Process dlinks */ bin_process_dlinks(processed_links_root); /* 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); /* insert the links that were processed into the variant hash table */ bin_insert_links(processed_links_root, &ht_header, attachment_list.filepos); /* 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 */ /* free plinkpages and datapages */ return sdat_start; } static inline void bin_process_dlinks ( struct bin_processed_links_t* processed_links ) { struct bin_linklist_t* olink_iter; ir_set trg_set; for( dlink_iter = processed_links->dlink_list; dlink_iter != NULL; dlink_iter = dlink_iter->next) { /* Construct its fully qualified name based on ?*/ /* Output an int for its length, and then output the name */ } } static inline struct bin_linklist_t* bin_linklist_head ( struct bin_linklist_t* root ) { struct bin_linklist_t* head; head = root; while(head->next) head = head->next; return head; } /* We dont know src_pos at this point because this is still in the control flow of bin_process_links, which determines the number of links, which determines the hash table. */ void #define PUSH_LINK(_LINK) (*(linkdata*) stack_alloc(&linkpages, sizeof(linkdata)) = _LINK) bin_process_vlink ( linkdata vlink, struct bin_processed_links_t* processed_links) { struct bin_processed_links_t* plp; struct bin_linklist_t* vlink_list_head; linkdata new_vlink; ir_setdata fiter; ir_set trg_set; uint8_t* link_name; vlink_list_head = bin_linklist_head(processed_links->vlink_list); link_name = ir_setdata_name(vlink); if (link_name) { plp = struct_alloc(bin_processed_links_t); plp->linkdata = vlink; vlink_list_head->next = plp; processed_links->vlink_len++; PUSH_LINK(vlink); } else // linking a variant hash table { trg_set = ir_linkdata_set(vlink); for (fiter = ir_set_framebox(trg_set); fiter != NULL; fiter = ir_setdata_nextsib(fiter)) { plp = struct_alloc(bin_processed_links_t); new_vlink = struct_alloc(linkdata); ir_linkdata_assign_name(new_vlink,ir_setdata_name(fiter)); ir_linkdata_assign_set(new_vlink,trg_set); ir_linkdata_assign_type(new_vlink,VLINK); plp->linkdata = vlink; vlink_list_head->next = plp; processed_links->vlink_len++; PUSH_LINK(vlink); } } return processed_links; } /* Adds an mlink to the stack_alloc, to be processed later */ void bin_process_mlink ( linkdata mlink, bin_processed_links_t* processed_links ) { uint8_t* mlink_name; struct bin_processed_links_t* mlink_list_head; mlink_list_head = bin_listlist_head(processed_links->mlink_list); mlink_name = ir_setdata_name(mlink); plp = stack_alloc(&linkpages, bin_linklist_t); plp->header.filepos = 0; //TBD after resolving the childlist | TODO: attach_pos? if(mlink_name) plp->name = mlink_name;// TODO: What does a mlink with a name mean? specifying the framebox mapsheet to use? plp->trg_set = ir_linkdata_set(mlink); mlink_list_head->next = plp; processed_links->mlink_len++; return processed_links; } /* 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 ( linkdata olink, struct bin_processed_links_t* processed_links ) { struct bin_linklist_t* iter; ir_set olink_set; olink_set = ir_linkdata_set(olink); for( iter = processed_links->olink_list; iter != NULL; iter = iter->next) if(iter == olink_set) return 1; return 0; } /* if olink, process target sets frameboxes(turn into vlinks) and its attachment_list (turn into mlink), else its a dlink so just add it to the processed_links list*/ static inline void bin_process_olink ( linkdata olink, struct bin_processed_links_t* processed_links_root, ir_set trg_set ) { struct bin_linklist_t* link_list_head; if(trg_set)) //add olink to list so we can check for cycles { bin_set_frameboxes_vlinks(trg_set, processed_links_root); //TODO: implement bin_set_attachmentlist_mlink(trg_set, processed_links_root); //TODO: implement link_list_head = bin_linklist_head(processed_links_root->olink_list); link_list_head->next = struct_alloc(bin_linklist_t); link_list_head->next->linkdata = olink; } else // olink is actually a dynamic link { link_list_head = bin_linklist_head(processed_links_root->dlink_list); link_list_head->next = struct_alloc(bin_linklist_t); link_list_head->next->linkdata = olink; } } struct bin_linklist_t; struct bin_linklist_t { struct bin_linklist_t* next; linkdata linkdata; }; struct bin_processed_links_t { struct bin_linklist_t* vlink_list; int vlink_len; struct bin_linklist_t* mlink_list; int mlink_len; struct bin_linklist_t* olink_list; //keep track of olink cycles int olink_len; struct bin_linklist_t* dlink_list; int dlink_len; }; /* 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. */ struct bin_processed_links_t* bin_process_links ( ir_set src_set, struct bin_processed_links_t* processed_links_root; ) { struct bin_processed_links_t* returned_val; linkdata linkdata; ir_set trg_set; for(linkdata = ir_set_link(src_set); linkdata != NULL; linkdata = (linkdata) ir_setdata_nextsib((ir_setdata) linkdata)) { switch (ir_linkdata_type(linkdata)) { case OLINK: if (olink_cycle(linkdata, processed_links_root)) return processed_links_root; //TODO: what return value? trg_set = ir_linkdata_set(linkdata); bin_process_olink(trg_set, linkdata, processed_links_root); bin_process_links(trg_set, processed_links_root); break; case VLINK: bin_process_vlink(linkdata, processed_links_root); break; case MLINK: bin_process_mlink(linkdata, processed_links_root); break; case ALINK: //TODO: ? break; } } return processed_links_root; } /* 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 PUSH_PLINK(_LINK) (*(struct **) stack_alloc(&linkpages, sizeof (_LINK)) = _LINK ) void bin_insert_links ( struct bin_processed_links_t* links, struct bin_ht_header_t* ht, long attach_pos ) { struct bin_plink_t* plp; struct bin_ht_entry_t ht_entry; struct link_list_t* vlinkiter, mlinkiter; long entry_pos; /* Insert vlinks into hash table, put v/mlinks on link stack to be processed later */ for ( vlinkiter = links->vlink_root; vlinkiter != NULL; vlinkiter = vlinkiter->next;) { ht_entry.key = NAMEHASH(ir_setdata_name(vlinkiter->linkdata), ht->entries << 1); ht_entry.value = 0; entry_pos = bin_insert_ht_entry(ht->start, ht->entries * sizeof(ht_entry), &ht_entry, 0); ir_setdata_assign_fpos(vlinkiter->linkdata, entry_pos); PUSH_PLINK(vlinkiter->linkdata); } for ( mlinkiter = links->mlink_root; mlinkiter != NULL; mlinkiter = mlinkiter->next) { >trg_set = plp->trg_set; plp->src_pos = attach_pos; PUSH_PLINK(plp); } /* Process dlinks here */ } 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; RGBA_t* 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 = (RGBA_t*) stbi_load(GENERATE_FILENAME(ir_setdata_name((ir_setdata) ir_framebox_mapsheet(framebox,SFACE))), &mapsheet_info.width, &mapsheet_info.width, &num_framechannels , 0); framedata = (RGBA_t*) 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; } /* 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, RBGA_t* 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++ ) { if (*data) { pixel_node = struct_alloc(bin_pixel_node_t); /* get ref from 4 bytes of data */ pixel_node->data.ref = (*data) >> 8; /* bitshift by ? to get Z */ pixel_node->data.z = (*data & 0xFF); /* set x and y */ pixel_node->data.x = x + init_width; pixel_node->data.y = y + init_width; pixel_list = bin_insert_node_into_list(pixel_list, pixel_node); } data++; } 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; RGBA_t* 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 = (RGBA_t*) 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; }