+/* Standard */
+#include <stdlib.h> //exit, malloc
+#include <stdio.h> //print
+#include <stdarg.h> //va_args
+#include <string.h> //memset, str*
+#include <errno.h>
+/* Unicode */
+#include <unistd.h> //u8_* functions
+#include <unitypes.h> //uint8_t as a char
+#include <unistr.h> //u32_cpy
+#include <unistdio.h> //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_image.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;
+};
+struct bin_pixel_node_t {
+ struct bin_pixel_node_t* next;
+ struct bin_pixel_t data;
+};
+struct bin_op_t {
+ int x;
+ int y;
+ int attach_idx;
+};
+struct bin_attachment_header_t {
+ int num_attachment_lists;
+ int num_attachments;
+};
+struct bin_attachment_t {
+ int 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)
+
+/* 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 = get_class_name(class);
+
+ num_csibs = get_class_sibcount(class);
+ num_ssibs = get_set_sibcount(get_class_root_set(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 = get_class_root_set(class); siter != NULL; siter = get_set_nextsib(siter))
+ { fseek(binaryout, 0, SEEK_END);
+ ht_entry.key = NAMEHASH(get_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 = get_class_nextchild(class); citer != NULL; citer = get_class_nextsib(citer))
+ { fseek(binaryout, 0, SEEK_END);
+ ht_entry.key = NAMEHASH(get_class_name(citer), num_csibs << 1);
+ ht_entry.value = bin_traverse_class(citer);
+ bin_insert_ht_entry(classht_start, classht_size, &ht_entry, 0);
+ }
+
+ 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 = get_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 = get_set_sibcount(get_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 = get_set_nextchild(set); iter != NULL; iter = get_set_nextsib(iter))
+ { fseek(binaryout, 0, SEEK_END);
+ ht_entry.key = NAMEHASH(get_set_name(iter), num_child << 1);
+ ht_entry.value = bin_traverse_set(iter);
+ bin_insert_ht_entry(childht_start, childht_size, &ht_entry, 0);
+ }
+
+
+ set_set_filepos(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 = get_set_variants(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 = get_link_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 = get_set_frameboxes(trg_set); fiter != NULL; fiter = get_framebox_nextsib(fiter))
+ { plp = struct_alloc(bin_plink_t);
+ plp->src_pos = 0; // TBD @ process_setdata
+ plp->name = get_framebox_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 = get_link_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;
+ ir_setdata liter; //link iter
+ ir_set trg_set;
+
+ num_links = 0;
+
+ for(liter = get_set_links(src_set); liter != NULL; liter = get_link_nextsib(liter))
+ { trg_set = get_set_from_ref(get_link_ref(liter));
+ switch (get_link_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 = get_set_frameboxes(set); fiter != NULL; fiter = get_framebox_nextsib(fiter))
+ { fseek(binaryout, 0, SEEK_END);
+ ht_entry.key = NAMEHASH(get_framebox_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 framedata
+)
+{ img_info->fwidth = get_framedata_width(framedata);
+ img_info->fheight = get_framedata_height(framedata);
+ img_info->unaligned_height = img_info->height % img_info->fheight;
+ img_info->unaligned_width = img_info->width % img_info->fwidth;
+
+}
+
+/* TODO: Implement this */
+long
+bin_process_frame
+ ()
+{}
+
+
+
+/* Combine the framesheet and mapsheet to create
+ the output sheet */
+/* |-------------------------|
+ | outputsheet header |
+ |-------------------------|
+ | pixel data for frame1 |
+ |-------------------------|
+ | op data for frame1 |
+ |-------------------------|
+ | etc. | */
+//TODO: processing direction sounds dumb, but cant call it process_framesheet because
+// its actually the mapsheet and the framesheet. rename to output sheet?
+/* THIS FUNCTION IS NOT DONE */
+long
+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;
+ long facing_start;
+ unsigned char* mapdata, * framedata;
+
+ facing_start = ftell(binaryout);
+
+
+ /* Set up data pointers to mapsheet and framesheet, as well as their image infos */
+ mapdata = stbi_load(get_framedata_name(get_framebox_facing_mapdata(framebox,SFACE)), &mapsheet_info.width, &mapsheet_info.width, &num_framechannels , 0);
+ framedata = stbi_load(get_framedata_name(get_framebox_facing_framedata(framebox,SFACE)), &framesheet_info.width, &framesheet_info.height, &num_mapchannels, 0);
+ bin_set_img_info(&framesheet_info, get_framebox_facing_framedata(framebox, SFACE));
+ bin_set_img_info(&mapsheet_info, get_framebox_facing_mapdata(framebox, SFACE));
+
+ /* TODO: output framesheet/direction header */
+
+
+ /* For each frame and map i in framesheet + mapsheet */
+ /* output frame data */
+ /* output op space for frames */
+ /* determine ops in map */
+ /* check if ops are acceptable */
+ /* output ops */
+
+
+ return facing_start;
+
+}
+
+
+
+
+
+/* Insert pixel(s) into the list, z sorted */
+void
+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;
+ int node_z;
+
+ head_node = pixel_list_root->next;
+ node_z = pixel_node->data.z;
+
+ if(head_node == NULL)
+ { head_node = pixel_node;
+ }
+ prev_node = pixel_list_root;
+ while(head_node != NULL)
+ { if(node_z > head_node->data.z)
+ { prev_node = head_node;
+ head_node = head_node->next;
+ }
+ else if (node_z < head_node->data.z || node_z == head_node->data.z)
+ { prev_node->next = pixel_node;
+ pixel_node->next = head_node;
+ break;
+ }
+ }
+
+
+}
+
+/* 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 ordering */
+
+ /* 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 frame */
+/* TODO: Finish this */
+struct bin_pixel_node_t*
+bin_map_to_pixel_list
+( struct bin_img_info_t* img_info,
+ int init_height,
+ int init_width,
+ unsigned char* data
+)
+{ int x, y;
+ struct bin_pixel_node_t* pixel_list, * pixel_node;
+
+ pixel_list = NULL;
+
+ /* Check if frame clips */
+ if( img_info->unaligned_width )
+ ;
+ if (img_info->unaligned_height )
+ ;
+
+ /* Process the map*/
+ for (y = 0; y < img_info->fheight; y++)
+ { for ( x = 0; x < img_info->fwidth; x++ )
+ { pixel_node = bin_process_pixel(data, x, y, init_height, init_width);
+ bin_insert_node_into_list(pixel_list, pixel_node);
+ }
+ }
+
+ return pixel_node;
+}
+
+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 = get_set_frameboxes(set); fiter != NULL; fiter = get_framebox_nextsib(fiter))
+ { /* TODO: Stringify the frame name with .png? */
+ /* TODO: Add directory changing */
+ data = stbi_load(get_framedata_name(get_framebox_facing_mapdata(fiter, SFACE)), &img_info.width, &img_info.width, &num_channels, 0);
+ bin_set_img_info(&img_info, get_framebox_facing_mapdata(fiter, SFACE));
+ curr_pixel_list = bin_map_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;
+}