beginnings of binaryout
[henge/apc.git] / src / binaryout.c
diff --git a/src/binaryout.c b/src/binaryout.c
new file mode 100644 (file)
index 0000000..ee82c6f
--- /dev/null
@@ -0,0 +1,833 @@
+/* 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;
+}