more binaryout
[henge/apc.git] / src / binaryout.c
1 /* Standard */
2 #include <stdlib.h> //exit, malloc
3 #include <stdio.h> //print
4 #include <stdarg.h> //va_args
5 #include <string.h> //memset, str*
6 #include <errno.h>
7 /* Unicode */
8 #include <unistd.h> //u8_* functions
9 #include <unitypes.h> //uint8_t as a char
10 #include <unistr.h> //u32_cpy
11 #include <unistdio.h> //ulc_fprintf
12 /* Local */
13 #include "print.h"
14 #include "apc.h"
15 #include "ir.h"
16 #include "pagenode.h"
17 #undef do_error
18 #define do_error(...) exit(-1)
19 #define XXH_PRIVATE_API
20 #include "../xxHash/xxhash.h"
21 #define STB_IMAGE_IMPLEMENTATION
22 #include "../stb/stb_image.h"
23 #define STB_IMAGE_WRITE_IMPLEMENTATION
24 #include "../stb/stb_image_write.h"
25
26 /* Public */
27 void ir_binout_init(struct ir_class_t*);
28
29 /* Memory Allocation */
30 #define struct_alloc(_T) ((struct _T*) stack_alloc(&datapages, sizeof(struct _T)))
31 static
32 struct pagelist_t linkpages, datapages, plinkpages;
33
34 enum model_type { SS };
35 /* Binaryout out structure definitions */
36 struct bin_img_info_t {
37 int height;
38 int width;
39 int fwidth; //map and frame width
40 int fheight; //map and frame height
41 int unaligned_width;
42 int unaligned_height;
43 };
44 struct bin_ht_header_t {
45 long start;
46 int entries;
47 int size;
48 };
49 struct bin_default_ht_entry_t {
50 uint32_t key;
51 long value;
52 };
53 struct bin_var_ht_entry_t {
54 uint32_t key;
55 long vvalue;
56 long mvalue;
57 };
58 struct bin_class_header_t {
59 struct bin_ht_header_t child_ht;
60 struct bin_ht_header_t rootset_ht;
61 int namelen;
62 };
63 struct bin_set_header_t {
64 struct bin_ht_header_t child_ht;
65 long sdat_start; //points to setdata_header
66 int namelen;
67 };
68 struct bin_setdata_header_t {
69 struct bin_ht_header_t variant_ht;
70 long attach_pos;
71 };
72 struct bin_model_header_t { //one for each framebox, currently
73 long facing_array_start;
74 enum model_type type;
75 };
76 struct bin_frame_header_t {
77 int width;
78 int height;
79 int frames;
80 long op_start;
81 };
82
83 struct bin_pixel_t {
84 int x, y, z;
85 uint32_t ref;
86 int attach_idx;
87 };
88 struct bin_pixel_node_t {
89 struct bin_pixel_node_t* next;
90 struct bin_pixel_t data;
91 };
92 struct bin_attachment_header_t {
93 int num_attachment_lists;
94 int num_attachments;
95 };
96 struct bin_attachment_t {
97 int x, y, z, idx;
98 ir_set set;
99 };
100 /* Read out of the als, after first ir pass, resolves the
101 attach_pos of the src-set that created the attachment_list
102 to the header that describes the attachment_list */
103 struct bin_attachment_list_t {
104 int num_attachments;
105 struct bin_attachment_t** attachments;
106 long filepos;
107 };
108 struct bin_linklist_t;
109 struct bin_linklist_t
110 { struct bin_linklist_t* next;
111 linkdata linkdata;
112 };
113
114 struct bin_processed_links_t
115 { struct bin_linklist_t* vlink_list;
116 int vlink_len;
117 struct bin_linklist_t* mlink_list;
118 int mlink_len;
119 struct bin_linklist_t* olink_list; //keep track of olink cycles
120 int olink_len;
121 struct bin_linklist_t* dlink_list;
122 int dlink_len;
123 };
124 struct bin_pixel_ht_entry_t
125 { uint16_t key;
126 uint16_t value;
127 };
128
129 struct bin_pixel_ht_t
130 { struct bin_pixel_ht_t* next;
131 struct bin_pixel_ht_entry_t[] hash_entries;
132 };
133
134 struct bin_attachment_list_t **attachment_stack, **asp; //attachment_stack, attachment_stack_pointer
135 FILE* binaryout;
136
137
138 #define NAMEHASH(name, domain) (XXH32(name, u8_strlen(name), 0XCEED ) & domain)
139 #define REFHASH(ref, domain) (XXH32(&ref, sizeof(uint32_t), 0xCEED) & domain)
140 static inline
141 int bin_set_varcount
142 ( ir_set set )
143 { int count;
144 framebox iter;
145 count = 0;
146 for (iter = ir_set_framebox(set); iter != NULL; iter = ir_setdata_nextsib(iter))
147 count++;
148 return count;
149 }
150
151 static inline
152 int bin_class_sibcount
153 ( ir_class class )
154 { int count;
155 ir_class iter;
156 count = 0;
157 for (iter = class; iter != NULL; iter = ir_class_nextsib(iter))
158 count++;
159 return count;
160 }
161
162 static inline
163 int bin_set_sibcount
164 ( ir_set set )
165 { int count;
166 ir_set iter;
167 count = 0;
168 for (iter = set; iter != NULL; iter = ir_set_nextsib(iter))
169 count++;
170 return count;
171 }
172
173 /* Given a position and a size, checks if the bytes are null and returns
174 the file position to where it started. 1 if not null, 0 if null*/
175 /* TODO: Determine why fseeking file past end sets bytes to -1, and not 0 */
176 static inline
177 int bytes_null( int len, int pos )
178 { while(len--)
179 { if(fgetc(binaryout) > 0)
180 { fseek(binaryout, pos, SEEK_SET);
181 return 1;
182 }
183 }
184 fseek(binaryout, pos, SEEK_SET);
185 return 0;
186 }
187 /* Checks if the key at entrypos is the same as the parameter key. Returns
188 1 if so, 0 if not. */
189 static inline
190 int bin_keys_identical
191 ( long entry_pos,
192 uint32_t key
193 )
194 { uint32_t curr_key;
195 fseek(binaryout, entry_pos, SEEK_SET);
196 fscanf(binaryout, "%u", &curr_key);
197 if( curr_key == key)
198 return 1;
199 return 0;
200 }
201
202
203 typedef uint32_t RGBA_t;
204
205 long bin_traverse_class(ir_class);
206 /* Takes root class and begins processing */
207 void
208 ir_binout_init(ir_class root_class)
209 { binaryout = fopen("binaryout", "w+");
210 asp = attachment_stack;
211 pagelist_init(datapages, (size_t) SYS_PAGESIZE);
212 pagelist_init(linkpages, (size_t) SYS_PAGESIZE);
213 pagelist_init(plinkpages, (size_t) SYS_PAGESIZE);
214 bin_traverse_class(root_class);
215 }
216
217
218 /* Returns the key position where the hash table entry was inserted. */
219 #define ENTRY_OCCUPIED() (bytes_null(uint32_t), entry_pos))
220 #define LOOP_ENTRY(_HTSTART) (entry_pos = _HTSTART)
221 #define WRITE_DEF_ENTRY() do { \
222 if(fseek(binaryout, entry_pos, SEEK_SET) == -1) wprintf("fseek failed with %s", strerror(errno)); \
223 fwrite(&def_ht_entry, sizeof def_ht_entry, 1, binaryout); \
224 } while (0)
225 #define INC_DEF_ENTRY() do { \
226 entry_pos += sizeof(def_ht_entry); \
227 if(fseek(binaryout, entry_pos, SEEK_SET) == -1) eprintf("fseek failed with %s", strerror(errno)); \
228 } while (0)
229 #define HT_END(_HTEND) (entry_pos >= _HTEND) //just in case at last entry
230 long
231 bin_insert_default_ht_entry
232 ( long ht_start,
233 int ht_size,
234 struct bin_def_ht_entry_t* def_ht_entry,
235 int overwrite
236 )
237 { long entry_pos, ht_end;
238
239 ht_end = ht_start + ht_size;
240 entry_pos = ht_start + sizeof(ht_entry) * ht_entry->key;
241 fseek(binaryout, entry_pos, SEEK_SET);
242
243 if (!ENTRY_OCCUPIED())
244 { uprintf("key not occupied\n");
245 WRITE_DEF_ENTRY();
246 }
247 while( ENTRY_OCCUPIED() )
248 { if(overwrite)
249 { if(bin_keys_identical(entry_pos, ht_entry->key))
250 break;
251 else
252 { eprintf("error in hashtable insertion, keys are identical");
253 }
254 }
255 if (HT_END(ht_end))
256 LOOP_ENTRY(ht_start);
257 else
258 INC_DEF_ENTRY();
259 }
260 WRITE_DEF_ENTRY();
261
262 return entry_pos;
263
264 }
265 long
266 #define WRITE_VAR_ENTRY() do { \
267 if(fseek(binaryout, entry_pos, SEEK_SET) == -1) wprintf("fseek failed with %s", strerror(errno)); \
268 fwrite(&var_ht_entry, sizeof var_ht_entry, 1, binaryout); \
269 } while (0)
270 #define INC_VAR_ENTRY() do { \
271 entry_pos += sizeof(var_ht_entry); \
272 if(fseek(binaryout, entry_pos, SEEK_SET) == -1) eprintf("fseek failed with %s", strerror(errno)); \
273 } while (0)
274 bin_insert_var_ht_entry
275 ( long ht_start,
276 int ht_size,
277 struct bin_var_ht_entry_t* var_ht_entry,
278 int overwrite
279 )
280 { long entry_pos, ht_end;
281
282 ht_end = ht_start + ht_size;
283 entry_pos = ht_start + sizeof(var_ht_entry) * ht_entry->key;
284 fseek(binaryout, entry_pos, SEEK_SET);
285
286 if (!ENTRY_OCCUPIED())
287 { uprintf("key not occupied\n");
288 WRITE_VAR_ENTRY();
289 }
290 while( ENTRY_OCCUPIED() )
291 { if(overwrite)
292 { if(bin_keys_identical(entry_pos, ht_entry->key))
293 break;
294 else
295 { eprintf("error in hashtable insertion, keys are identical");
296 }
297 }
298 if (HT_END(ht_end))
299 LOOP_ENTRY(ht_start);
300 else
301 INC_VAR_ENTRY();
302 }
303 WRITE_VAR_ENTRY();
304
305 return entry_pos;
306
307 /** @see http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 */
308 static inline
309 int bin_calculate_ht_entries
310 ( int entries )
311 { entries = (entries << 1) - 1;
312 entries |= entries >> 1;
313 entries |= entries >> 2;
314 entries |= entries >> 4;
315 entries |= entries >> 8;
316 entries |= entries >> 16;
317 return ++entries;
318 }
319
320 /* | class header |
321 |--------------------|
322 | rootset ht |
323 |--------------------|
324 | rootsets data |
325 |--------------------|
326 | classchild ht |
327 |--------------------|
328 | classchild header |
329 | ... |
330 */
331
332 long bin_traverse_set(ir_set);
333 long
334 #define DEF_HT_INIT(_START, _SIZE, _INIT_ENTRIES) do { \
335 _SIZE = _ENTRIES * sizeof(var_ht_entry); \
336 _START = ftell(binaryout); \
337 fseek(binaryout, _SIZE, SEEK_CUR); \
338 } while (0)
339 #define VAR_HT_INIT(_START, _SIZE, _ENTRIES) do { \
340 _SIZE = _ENTRIES * sizeof(var_ht_entry); \
341 _START = ftell(binaryout); \
342 fseek(binaryout, _SIZE, SEEK_CUR); \
343 } while (0)
344 bin_traverse_class
345 ( ir_class class)
346 { ir_class citer;
347 ir_set siter;
348 struct bin_class_header_t class_header;
349 struct bin_def_ht_entry_t ht_entry;
350 long class_start, classht_start, classht_size, rootsetht_start, rootsetht_size;
351 int num_class_entries, num_rootset_entries;
352 uint8_t* class_name;
353
354 class_start = ftell(binaryout);
355 class_name = ir_class_name(class);
356
357 num_class_entries = bin_calculate_ht_entries(bin_class_sibcount(class));
358 num_rootset_entries = bin_calculate_ht_entries(ir_class_rootset(class));
359
360 /* alloc space (before hash tables) for class header */
361 class_header.namelen = u8_strlen(class_name);
362 fseek(binaryout, class_start + sizeof(class_header) + class_header.namelen ,SEEK_SET);
363
364 DEF_HT_INIT(classht_start, classht_size, num_class_entries);
365 DEF_HT_INIT(rootsetht_start, rootsetht_size, num_rootset_entries);
366
367 /* TODO: Figure out generic way to output headers */
368 /* populate class header */
369 class_header.child_ht.entries = num_class_entries;
370 class_header.child_ht.start = classht_start;
371 class_header.child_ht.size = classht_size;
372 class_header.rootset_ht.entries = num_rootset_entries;
373 class_header.rootset_ht.start = rootsetht_start;
374 class_header.rootset_ht.size = rootsetht_size;
375 fseek(binaryout, class_start, SEEK_SET); //seek back to where we allocated header
376 fwrite(&class_header, sizeof(class_header), 1, binaryout);
377 fwrite(class_name, class_header.namelen, 1, binaryout);
378
379 /* Start populating root_set hash table */
380 for ( siter = ir_class_rootset(class); siter != NULL; siter = ir_set_nextsib(siter))
381 { fseek(binaryout, 0, SEEK_END);
382 ht_entry.key = NAMEHASH(ir_set_name(siter), num_rootset_entries);
383 ht_entry.value = bin_traverse_set(siter);
384 bin_insert_def_ht_entry(rootsetht_start, rootsetht_size, &ht_entry, 0);
385 }
386
387 /* Start populating class child hash table */
388 for ( citer = ir_class_nextchild(class); citer != NULL; citer = ir_class_nextsib(citer))
389 { if(chdir((char*) class_name))
390 eprintf("CHDIR %U from %s\n",(char*) class_name,getcwd(NULL,255));
391 fseek(binaryout, 0, SEEK_END);
392 ht_entry.key = NAMEHASH(ir_class_name(citer), num_class_entries);
393 ht_entry.value = bin_traverse_class(citer);
394 bin_insert_def_ht_entry(classht_start, classht_size, &ht_entry, 0);
395 if (chdir(".."))
396 eprintf("CHDIR ..\n");
397 }
398
399 return class_start;
400 }
401
402 long bin_process_sdat( ir_set);
403
404 /* | set header |--|
405 |-----------------| |
406 | set data |<-|
407 |-----------------| |
408 ---| setchild ht |<--
409 | |-----------------|
410 |->| setchild header |
411 |->| ... |
412 */
413
414 long
415 bin_traverse_set
416 ( ir_set set )
417 { ir_set iter;
418 struct bin_set_header_t header;
419 struct bin_def_ht_entry_t ht_entry;
420 int num_entries, setname_len;
421 long childht_start, childht_size, set_start;
422 uint8_t* set_name;
423
424 set_start = ftell(binaryout);
425 set_name = ir_set_name(set);
426
427 /* alloc space for set header */
428 setname_len = u8_strlen(set_name);
429 fseek(binaryout, sizeof(struct bin_set_header_t) + setname_len , SEEK_CUR);
430
431 /* process the set data */
432 header.sdat_start = bin_process_sdat(set);
433
434 /* Setup child hash table for current sets children */
435 num_entries = bin_calculate_ht_entries(bin_set_sibcount(ir_set_nextchild(set)));
436
437 DEF_HT_INIT(childht_start, childht_size, num_child);
438
439 /* populate header, write to file */
440 header.child_ht.entries = num_entries;
441 header.child_ht.start = childht_start;
442 header.child_ht.size = childht_size;
443 fseek(binaryout, set_start, SEEK_SET);
444 fwrite(&header, sizeof(struct bin_set_header_t), 1, binaryout);
445 fwrite(set_name, setname_len, 1, binaryout);
446
447 for(iter = ir_set_nextchild(set); iter != NULL; iter = ir_set_nextsib(iter))
448 { fseek(binaryout, 0, SEEK_END);
449 ht_entry.key = NAMEHASH(ir_set_name(iter), num_entries);
450 ht_entry.value = bin_traverse_set(iter);
451 bin_insert_def_ht_entry(childht_start, childht_size, &ht_entry, 0);
452 }
453
454
455 ir_set_assign_fpos(set, set_start);
456 return set_start;
457
458 }
459 /* | sdat header |
460 |------------------|
461 | num dlinks |
462 |------------------|
463 | dlink len |
464 |------------------|
465 | dlink string |
466 |------------------|
467 | variant ht |
468 |------------------|
469 | 1st variant data | -- variant == framebox
470 |------------------|
471 | 2nd variant data |
472 |------------------|
473 | etc. |
474
475 */
476
477 static inline void bin_insert_links(struct bin_processed_links_t*, struct bin_ht_header_t*, long);
478 static inline struct bin_pixel_node_t* bin_find_default_pixel_list(ir_set);
479 static inline void bin_process_frameboxes(ir_set, struct bin_ht_header_t*, struct bin_pixel_node_t*);
480 static inline struct bin_processed_links_t* bin_process_links(ir_set, struct bin_processed_links_t*);
481 static inline void bin_process_dlinks(struct bin_processed_links_t*);
482
483 /* Init the variant hash table for the set, process the sets links and add them to link_stack
484 and variant hash table, and then output the actual framedata */
485 long
486 bin_process_sdat
487 ( ir_set set )
488 { struct bin_setdata_header_t header;
489 struct bin_attachment_list_t attachment_list;
490 struct bin_pixel_node_t *default_pixel_list;
491 struct bin_ht_header_t ht_header;
492 struct bin_processed_links_t* processed_links_root;
493 long varht_start, varht_size, sdat_start;
494 int num_entries, num_links;
495
496 sdat_start = ftell(binaryout);
497
498 /* Alloc position for sdat_header */
499 fseek(binaryout, sizeof(struct bin_setdata_header_t), SEEK_CUR);
500
501 /* set up root for processed_links */
502 processed_links_root = stack_alloc(&plinkpages, sizeof(struct bin_processed_links_t));
503 processed_links_root->mlink_len = processed_links_root->vlink_len = processed_links_root->dlink_len = processed_links_root->olinks_len = 0;
504 processed_links_root = bin_process_links(set, processed_links_root);
505
506 num_links = processed_links_root->mlink_len + processed_links_root->vlink_len;
507
508 num_entries = bin_calculate_ht_entries(bin_set_varcount(set) + num_links);
509
510 VAR_HT_INIT(varht_start, varht_size, num_entries);
511
512 /* Populate the sdat_header */
513 fseek(binaryout, 0, sdat_start);
514 header.variant_ht.start = varht_start;
515 header.variant_ht.entries = num_entries;
516 header.variant_ht.size = varht_size;
517 attachment_list.filepos = header.attach_pos = ftell(binaryout) + sizeof(varht_start) + sizeof(num_entries);
518 fwrite(&header, sizeof(header), 1, binaryout);
519 fseek(binaryout, 0, SEEK_ENDhttps://en.wikipedia.org/wiki/Generic_programming);
520
521 /* Process dlinks */
522 bin_process_dlinks(processed_links_root);
523
524 /* Determine the default pixel list for all of the frameboxes */
525 default_pixel_list = bin_find_default_pixel_list(set);
526 /* Output each framebox, and insert it into the variant hash table */
527 bin_process_frameboxes(set, &ht_header, default_pixel_list);
528
529 /* insert the links that were processed into the variant hash table */
530 bin_insert_links(processed_links_root, &ht_header, attachment_list.filepos);
531
532 /* TODO: Convert the default pixel list to an attachment_list and then push the */
533 /* sdats attachment_list onto the attachment_stack so it can be procesed */
534
535
536
537
538 return sdat_start;
539 }
540 static inline
541 void bin_process_dlinks
542 ( struct bin_processed_links_t* processed_links )
543 { struct bin_linklist_t* dlink_iter;
544 for( dlink_iter = processed_links->dlink_list; dlink_iter != NULL; dlink_iter = dlink_iter->next)
545 { /* TODO: Construct its fully qualified name based on its linkdata*/
546
547 /* Output an int for its length, and then output the name */
548
549
550 }
551 }
552
553 static inline
554 struct bin_linklist_t* bin_linklist_head
555 ( struct bin_linklist_t* root )
556 { struct bin_linklist_t* head;
557 head = root;
558 while(head->next)
559 head = head->next;
560 return head;
561 }
562
563 /* We dont know src_pos at this point because this is still in the control flow
564 of bin_process_links, which determines the number of links, which determines
565 the hash table. */
566 void
567 #define PUSH_LINK(_LINK) (*(linkdata*) stack_alloc(&linkpages, sizeof(linkdata)) = _LINK)
568 bin_process_vlink
569 ( linkdata vlink,
570 struct bin_processed_links_t* processed_links)
571 { struct bin_linklist_t* llp;
572 struct bin_linklist_t* vlink_list_head;
573 linkdata new_vlink;
574 ir_setdata fiter;
575 ir_set trg_set;
576 uint8_t* link_name;
577
578 vlink_list_head = bin_linklist_head(processed_links->vlink_list);
579 link_name = ir_setdata_name(vlink);
580 if (link_name)
581 { llp = stack_alloc(&plinkpages, sizeof(bin_linklist_t));
582 llp->linkdata = vlink;
583 vlink_list_head->next = llp;
584 processed_links->vlink_len++;
585 }
586 else // linking a variant hash table
587 { trg_set = ir_linkdata_set(vlink);
588 for (fiter = ir_set_framebox(trg_set); fiter != NULL; fiter = ir_setdata_nextsib(fiter))
589 { llp = stack_alloc(&plinkpages, sizeof(bin_linklist_t));
590 new_vlink = stack_alloc(&plinkpages, sizeof(linkdata));
591 ir_data_assign_path(new_vlink,ir_setdata_name(fiter));
592 ir_linkdata_assign_set(new_vlink,trg_set);
593 ir_linkdata_assign_type(new_vlink,VLINK);
594 llp->linkdata = vlink;
595 vlink_list_head->next = llp;
596 processed_links->vlink_len++;
597 }
598 }
599
600
601 }
602
603 /* Adds an mlink to the stack_alloc, to be processed later */
604 /* TODO: redo */
605 void
606 bin_process_mlink
607 ( linkdata mlink,
608 struct bin_processed_links_t* processed_links
609 )
610 { uint8_t* mlink_name;
611 struct bin_linklist_t* llp;
612 struct bin_linklist_t* mlink_list_head;
613 linkdata new_mlink;
614 ir_setdata fiter;
615 ir_set trg_set;
616
617
618 mlink_list_head = bin_linklist_head(processed_links->mlink_list);
619 mlink_name = ir_setdata_name(mlink);
620
621 if(mlink_name)
622 { llp = stack_alloc(&plinkpages, sizeof(bin_linklist_t));
623 llp->linkdata = mlink;
624 mlink_list_head->next = llp;
625 processed_links->mlink_len++;
626 }
627 else
628 { trg_set = ir_linkdata_set(mlink);
629 for (fiter = ir_set_framebox(trg_set); fiter != NULL; fiter = ir_setdata_nextsib(fiter))
630 { //TODO: check here if illegal mlink(linking to a opsheet of a vdat not in src_set domain)?
631 llp = stack_alloc(&plinkpages, sizeof(bin_linklist_t));
632 new_mlink = stack_alloc(&plinkpages, sizeof(linkdata));
633 ir_data_assign_path(new_mlink,ir_setdata_name(fiter));//TODO: assign name
634 ir_linkdata_assign_set(new_vlink,trg_set);
635 ir_linkdata_assign_type(new_vlink,VLINK);
636 llp->linkdata = vlink;
637 vlink_list_head->next = llp;
638 processed_links->vlink_len++;
639 }
640 }
641
642
643
644 return processed_links;
645 }
646
647 /* Determine if olink is already part of the olink_list.
648 if it is, theres a cycle, return 1. Else return 0. */
649 static inline
650 int olink_cycle
651 ( linkdata olink,
652 struct bin_processed_links_t* processed_links
653 )
654 { struct bin_linklist_t* iter;
655 ir_set olink_set;
656 olink_set = ir_linkdata_set(olink);
657 for( iter = processed_links->olink_list; iter != NULL; iter = iter->next)
658 if(ir_linkdata_set(iter->linkdata) == olink_set)
659 return 1;
660
661 return 0;
662 }
663 /* if olink, process target sets frameboxes(turn into vlinks) and its attachment_list (turn into mlink),
664 else its a dlink so just add it to the processed_links list*/
665 static inline
666 void bin_process_olink
667 ( ir_set trg_set,
668 linkdata olink,
669 struct bin_processed_links_t* processed_links_root
670 )
671 { struct bin_linklist_t* link_list_head;
672 struct bin_linklist_t* new_link;
673
674 new_link = stack_alloc(&plinkpages, sizeof(bin_linklist_t));
675 if(trg_set) //add olink to list so we can check for cycles
676 { bin_set_frameboxes_vlinks(trg_set, processed_links_root); //TODO:
677 bin_set_attachmentlist_mlink(trg_set, processed_links_root); //TODO:
678 link_list_head = bin_linklist_head(processed_links_root->olink_list);
679 new_link->linkdata = olink;
680 link_list_head->next = new_link;
681 }
682 else // olink is actually a dynamic link
683 { link_list_head = bin_linklist_head(processed_links_root->dlink_list);
684 new_link->linkdata = olink;
685 link_list_head->next = new_link;
686 }
687
688 }
689
690
691 /* Given a set, determine the number of links it has and process each link and
692 then add them to stack_alloc, where they will be popped off and further processed. */
693 struct bin_processed_links_t* bin_process_links
694 ( ir_set src_set,
695 struct bin_processed_links_t* processed_links_root
696 )
697 { linkdata linkdata;
698 ir_set trg_set;
699 for(linkdata = ir_set_link(src_set); linkdata != NULL; linkdata = ir_setdata_nextsib((ir_setdata) linkdata))
700 { switch (ir_linkdata_type(linkdata)) {
701 case OLINK:
702 if (olink_cycle(linkdata, processed_links_root))
703 return processed_links_root; //TODO: what return value?
704 trg_set = ir_linkdata_set(linkdata);
705 bin_process_olink(trg_set, linkdata, processed_links_root);
706 bin_process_links(trg_set, processed_links_root);
707 break;
708 case VLINK:
709 bin_process_vlink(linkdata, processed_links_root);
710 break;
711 case MLINK:
712 bin_process_mlink(linkdata, processed_links_root);
713 break;
714 case ALINK: //TODO: ?
715 break;
716 }
717 }
718 return processed_links_root;
719 }
720
721 /* Insert both mlinks and vlinks into the link stack, after determining their src_pos. Vlinks
722 have an additional requirement of being added into the variant hash table */
723 #define FRAME_POS() (entry_pos + sizeof(long))
724 #define MAP_POS() (entry_pos + sizeof(long)*2)
725 #define PUSH_PLINK(_LINK) (*(linkdata*) stack_alloc(&linkpages, sizeof (_LINK)) = _LINK )
726 void
727 bin_insert_links
728 ( struct bin_processed_links_t* links,
729 struct bin_ht_header_t* ht,
730 long attach_pos
731 )
732 { struct bin_plink_t* plp;
733 struct bin_var_ht_entry_t ht_entry;
734 struct bin_linklist_t* vlinkiter, *mlinkiter;
735 long entry_pos;
736
737
738 /* Insert vlinks and mlinks into hash table, put v/mlinks on link stack to be processed later */
739 for ( vlinkiter = links->vlink_list; vlinkiter != NULL; vlinkiter = vlinkiter->next)
740 { ht_entry.key = NAMEHASH(ir_setdata_name(vlinkiter->linkdata), ht->entries);
741 ht_entry.fvalue = 0;
742 entry_pos = bin_insert_var_ht_entry(ht->start, ht->size, &ht_entry, 0);
743 ir_setdata_assign_fpos(vlinkiter->linkdata, FRAME_POS());
744 PUSH_PLINK(vlinkiter->linkdata);
745 }
746 /* TODO: If name exists in src_set, overwrite. if it dont, print a warning */
747 for ( mlinkiter = links->mlink_list; mlinkiter != NULL; mlinkiter = mlinkiter->next)
748 { ht_entry.key = NAMEHASH(ir_setdata_name(mlinkiter->linkdata), ht->size);
749 ht_entry.mvalue = 0;
750 entrypos = bin_insert_var_ht_entry(ht->start, ht->size, &ht_entry, 0);
751 ir_setdata_assign_fpos(mlinkiter->linkdata, MAP_POS());
752 PUSH_PLINK(mlinkiter->linkdata);
753 }
754 /* free all the processed links */
755 pagelist_free(plinkpages);
756
757
758 }
759
760 long bin_process_facing(ir_setdata, apc_facing, struct bin_pixel_node_t*);
761 /* |-------------------|
762 | framebox header |
763 |-------------------|
764 | SFACE framesheet |
765 |-------------------|
766 | SWFACE framesheet |
767 |-------------------|
768 | etc. |
769 */
770 long
771 bin_process_framebox
772 ( ir_set set,
773 ir_setdata framebox,
774 struct bin_pixel_node_t* default_pixel_list
775 )
776 { struct bin_model_header_t header;
777 long framebox_start, index_pos;
778 int i;
779
780 framebox_start = ftell(binaryout);
781
782 /* insert model header */
783 header.type = SS;
784 header.facing_array_start = framebox_start + sizeof(header);
785 fwrite(&header, sizeof(header), 1, binaryout);
786
787 /* Create the index array for framesheet of each direction */
788 for ( i = SFACE; i < FACING_MAX; i++)
789 { fseek(binaryout, 0, SEEK_END);
790 index_pos = bin_process_facing(framebox, i, default_pixel_list); //TODO: finish process_direction
791 fseek(binaryout, header.facing_array_start + i * sizeof(long), SEEK_SET);
792 fwrite(&index_pos, sizeof(long), 1, binaryout);
793 }
794
795 return framebox_start;
796 }
797 static inline
798 struct bin_pixel_ht_t* bin_pixel_ht_alloc
799 ()
800 { struct bin_pixel_ht_t* htp;
801 if(!(htp = (struct bin_pixel_ht_t*) malloc(sizeof(bin_pixel_ht_t) + )))
802 eprintf("error mallocing pixel_ht\n");
803
804 return htp;
805 }
806 int bin_insert_pixel_ht_entry
807 ( struct bin_pixel_ht_t* ht,
808 struct bin_pixel_ht_entry_t* ht_entry
809 )
810 {
811
812 }
813
814 void
815 bin_process_frameboxes
816 ( ir_set set,
817 struct bin_ht_header_t* ht,
818 struct bin_pixel_node_t* default_pixel_list
819 )
820 { struct bin_ht_entry_t ht_entry;
821 struct bin_pixel_ht_t* ht;
822 struct bin_pixel_node_t* pixeliter;
823 ir_setdata fiter;
824
825 /* create the default ht */
826 ht = bin_ht_alloc();
827 for(pixeliter = default_pixel_list; pixeliter != NULL; pixeliter = pixeliter->next)
828 { ht_entry.val = 1;
829 ht_entry.key = pixel_iter->data.ref;
830 bin_insert_pixel_ht_entry(&ht, ;
831 }
832
833
834
835
836 /* Insert variants into hash table to overwrite olink insertions*/
837 for ( fiter = ir_set_framebox(set); fiter != NULL; fiter = ir_setdata_nextsib(fiter))
838 { fseek(binaryout, 0, SEEK_END);
839 ht_entry.key = NAMEHASH(ir_setdata_name(fiter), ht->entries);
840 /* create the copy, pass the copy */
841 ht_entry.value = bin_process_framebox(set, fiter, default_pixel_list);
842 bin_insert_var_ht_entry(ht->start, ht->entries * sizeof(ht_entry), &ht_entry, 1);
843 }
844
845 }
846 /* Determine clipping based on image height/width and frame height/width */
847 static inline
848 void bin_set_img_info
849 ( struct bin_img_info_t* img_info,
850 ir_setdata frame_data
851 )
852 { ir_frameinfo frameinfo;
853 frameinfo = ir_framedata_frameinfo(frame_data);
854 img_info->fwidth = frameinfo->w;
855 img_info->fheight = frameinfo->h;
856 img_info->unaligned_height = img_info->height % img_info->fheight;
857 img_info->unaligned_width = img_info->width % img_info->fwidth;
858
859 }
860 /* |-----------------------------|
861 | frame header |
862 |-----------------------------|
863 | pixel data for frame1 - n |
864 |-----------------------------|
865 | op data for frame1 - n |
866 |-----------------------------| */
867
868 long
869 //TODO: THIS SHOULD THE SET SPEC, NOT THE FRAMEBOX NAME
870 #define GENERATE_FILENAME(_N) ((char*) u8_strcat(_N, png_suffix))
871 bin_process_facing
872 ( ir_setdata framebox,
873 apc_facing facing,
874 struct bin_pixel_node_t* default_pixel_list
875 )
876 { struct bin_img_info_t mapsheet_info, framesheet_info;
877 int num_mapchannels, num_framechannels, x;
878 struct bin_frame_header_t header;
879 long facing_start;
880 RGBA_t* mapdata, * framedata;
881 uint8_t* png_suffix = ".png";
882 struct bin_pixel_node_t* map_pixel_list;
883
884 facing_start = ftell(binaryout);
885
886
887 /* Set up data pointers to mapsheet and framesheet, as well as their image infos */
888 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);
889 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);
890 bin_set_img_info(&framesheet_info, ir_framebox_framesheet(framebox, SFACE));
891 bin_set_img_info(&mapsheet_info, ir_framebox_mapsheet(framebox, SFACE));
892
893 /* Allocate space for header */
894 fseek(binaryout, sizeof(header), SEEK_CUR);
895
896
897 /* Output framesheet */
898 if(!stbi_write_png(binaryout, framesheet_info.width, framesheet_info.height, 4, mapdata, framesheet_info.fwidth))
899 eprintf("error writing out framesheet\n");
900
901 /* Output framesheet header */
902 header.width = framesheet_info.fwidth;
903 header.height = framesheet_info.fheight;
904 header.frames = framesheet_info.width / framesheet_info.fwidth; //TODO: division is bad
905 header.op_start = ftell(binaryout);
906 fseek(binaryout, facing_start, SEEK_SET);
907 fwrite(&header, sizeof(header), 1, binaryout);
908 fseek(binaryout, 0, SEEK_END);
909
910
911
912
913 /* Assuming that fheight = image height */
914 /* For each mapframe in mapsheet */
915 for ( x = 0; x < header.frames; x++)
916 { map_pixel_list = bin_mapframe_to_pixel_list(mapsheet_info, 0, x * mapsheet_info.fwidth, mapdata);
917 if(!bin_process_map_pixel_list(default_pixel_list, map_pixel_list))
918 eprintf("error processing map pixel list\n");
919 bin_output_pixel_list(map_pixel_list);
920 mapdata = mapsheet_info.fwidth * x; //do we do this in mapframe to pixellist?
921
922 }
923
924
925
926 return facing_start;
927
928 }
929
930 /* pixel_list == ops, output up to fwidth amount of them */
931 void
932 bin_output_pixel_list(struct bin_pixel_node_t* map_pixel_list);
933
934 /* TODO: Please rename all the functions jhc*/
935 static inline
936 void bin_number_pixel_list
937 ( struct bin_pixel_node_t* pixel_list )
938 { int num = 0;
939 struct bin_pixel_node_t* iter;
940 while (iter)
941 { iter->data.attach_idx = num++;
942 iter = iter->next;
943 }
944 }
945
946 /* Assuming at this point that map_pixel_list is valid */
947 static inline
948 int bin_set_map_pixel_list_attach_idxs
949 ( struct bin_pixel_node_t* default_pixel_list,
950 struct bin_pixel_node_t* map_pixel_list
951 )
952 { struct bin_pixel_node_t* mapiter, defaultiter;
953 mapiter = map_pixel_list;
954 defaultiter = default_pixel_list;
955 while (mapiter && defaultiter)
956 { /* if mapiter.data.ref == defaultiter.data.ref, assign mapiter index_idx to defaultiter */
957 if (mapiter.data.ref == defauliter.data.ref)
958 { defaultiter.data.attach_idx = mapiter.data.attach_idx;
959 mapiter = mapiter->next;
960 defaultiter = defaultiter->next;
961 }
962 else
963 defaultiter = defaultiter->next;
964 }
965 }
966 int bin_ref_in_pixel_list
967 ( struct bin_pixel_node_t* pixel_list,
968 uint32_t ref
969 )
970 { struct bin_pixel_node_t* iter;
971 for(iter = pixel_list; iter != NULL; iter = iter->next)
972 { if(ref == iter.data.ref)
973 return 1;
974 }
975 return 0;
976 }
977
978 struct bin_pixel_ht_t*
979 #define PIXEL_HT_SIZE() (sizeof(bin_pixel_ht_entry_t) * SYS_PAGESIZE + sizeof(bin_pixel_ht_t*))
980 bin_pixel_ht_alloc
981 ( void )
982 { struct bin_pixel_ht_t* ht;
983
984 if(!(ht = (struct bin_pixel_ht_t*) malloc( PIXEL_HT_SIZE())))
985 eprintf("Memory allocation error in bin_pixel_ht_alloc\n");
986 memset(ht, 0, PIXEL_HT_SIZE());
987
988 return ht;
989 }
990
991 void
992 bin_insert_pixel_ht_entry
993 ( struct bin_pixel_ht_t** ht,
994 struct bin_pixel_ht_entry_t* ht_entry
995 )
996 { if(*ht == NULL)
997 *ht = bin_pixel_ht_alloc();
998
999 }
1000
1001 /* Determines if the multiset map_pixel is a subset of the multiset default pixel list.
1002 0 if invalid, 1 if valid */
1003 static inline
1004 int bin_valid_map_pixel_list
1005 ( struct bin_pixel_ht_t* default_ht,
1006 struct bin_pixel_node_t* map_pixel_list
1007 )
1008 { struct bin_pixel_node_t* mapiter, *defaultiter, *tmpdefault, tmpmap;
1009 int i;
1010 defaultiter = default_pixel_list;
1011 mapiter = map_pixel_list;
1012
1013 while(mapiter != NULL)
1014 { /* hash the ref*/
1015 /* compare against the default ht */
1016 /* decrement the value of the found ht_entry */
1017 /* if(value == 0) */
1018 /* return 0 */
1019
1020
1021 }
1022
1023
1024 return 1;
1025
1026 }
1027 static inline
1028 int bin_process_map_pixel_list
1029 ( struct bin_pixel_node_t* default_pixel_list,
1030 struct bin_pixel_node_t* map_pixel_list
1031 )
1032 { /* Determine if pixel_list is valid */
1033 if(!bin_valid_map_pixel_list(default_pixel_list, map_pixel_list))
1034 return 0;
1035
1036 /* Determine attach_idx of each pixel, as compared to default pixel list */
1037
1038
1039 }
1040
1041 void
1042 bin_assign_pixel_idxs
1043 ( struct bin_pixel_node_t* pixel_list )
1044 {
1045 }
1046
1047 /* Insert pixel(s) into the list, z sorted */
1048 /* number the pixels as you insert them */
1049 struct bin_pixel_node_t*
1050 bin_insert_node_into_list
1051 ( struct bin_pixel_node_t** pixel_list_root,
1052 struct bin_pixel_node_t* pixel_node
1053 )
1054 { struct bin_pixel_node_t** head_node;
1055
1056 head_node = pixel_list_root;
1057
1058 while(*head_node != NULL && head_node->data.ref < pixel_node->data.ref)
1059 head_node = &((*head_node)->next);
1060
1061 pixel_node->next = *head_node;
1062 *head_node = pixel_node;
1063
1064 return pixel_list_root;
1065
1066
1067 }
1068
1069 /* Returns the non null pixels of a single mapframe (unaligned or not)
1070 given any height and width */
1071 struct bin_pixel_node_t*
1072 bin_mapframe_to_pixel_list
1073 ( struct bin_img_info_t* img_info,
1074 int init_height,
1075 int init_width,
1076 RBGA_t* data
1077 )
1078 { int j, i, fheight, fwidth, fhsize, fwsize;
1079 RGBA_t* p;
1080 struct bin_pixel_node_t* pixel_list,* pixel_node;
1081
1082 pixel_list = NULL;
1083
1084 /* if frame clips, process unclippign frames */
1085
1086 fwsize = img_info->unaligned_width ? img_info->unaligned_width : img_info->fwidth;
1087 fhsize = img_info->unaligned_height ? img_info->unaligned_height : img_info->fwidth;
1088
1089
1090 fwidth = img_info->fwidth;
1091 fheight = img_info->fheight;
1092
1093
1094 /* Process the map*/
1095 for (i = init_height; i < fhsize; i++)
1096 { for ( j = init_width; j < fwsize; j++ )
1097 { if (p = data[i*img_info->width+j])
1098 { pixel_node = struct_alloc(bin_pixel_node_t);
1099 /* get ref from 4 bytes of data */
1100 pixel_node->data.ref = (*p) >> 8;
1101 /* bitshift by ? to get Z */
1102 pixel_node->data.z = (*p & 0xFF);
1103 /* set x and y */
1104 pixel_node->data.x = j;
1105 pixel_node->data.y = i;
1106 pixel_node->data.num = 0;
1107 pixel_list = bin_insert_node_into_list(&pixel_list, pixel_node);
1108 }
1109 }
1110 }
1111
1112 return pixel_list;
1113 }
1114
1115 static inline
1116 int bin_pixel_list_len
1117 ( struct bin_pixel_node_t* pl )
1118 { struct bin_pixel_node_t* plp;
1119 int count;
1120 count = 0;
1121 plp = pl;
1122 while(plp)
1123 { count++;
1124 plp = plp->next;
1125 }
1126 return count;
1127 }
1128 /* TODO: what are the qualifications for the default pixel list? len and __? */
1129 struct bin_pixel_node_t*
1130 bin_cmp_default_pixel_lists
1131 ( struct bin_pixel_node_t* pl1,
1132 struct bin_pixel_node_t* pl2
1133 )
1134 { struct bin_pixel_node_t* pl1p, * pl2p;
1135 int i, pl1_len, pl2_len;
1136
1137 pl1p = pl1;
1138 pl2p = pl2;
1139 pl1_len = bin_pixel_list_len(pl1);
1140 pl2_len = bin_pixel_list_len(pl2);
1141
1142 if (pl1_len > pl2_len)
1143 return pl1;
1144 else if (pl1_len < pl2_len)
1145 return pl2;
1146 /* pl1 == pl2, make sure that all refs are the same */
1147 /* TODO: what type of warning/error handling should occur here? */
1148 for (i = 0; i < pl1_len; i++)
1149 { if (pl1p->data.ref != pl2p->data.ref)
1150 eprintf("Error in determining default pixel list\n");
1151 pl1p = pl1p->next;
1152 pl2p = pl2p->next;
1153 }
1154 return pl1; //doesnt matter which one you return
1155 }
1156
1157 /* Find default framebox, based on the framebox with the most attachments*/
1158 /* Search through first frame of S of each framebox */
1159 struct bin_pixel_node_t*
1160 bin_find_default_pixel_list
1161 ( ir_set set)
1162 { ir_setdata fiter;
1163 struct bin_pixel_node_t* default_pixel_list, * curr_pixel_list;
1164 RGBA_t* data;
1165 int num_channels;
1166 struct bin_img_info_t img_info;
1167
1168 for (fiter = ir_set_framebox(set); fiter != NULL; fiter = ir_setdata_nextsib(fiter))
1169 { /* TODO: Stringify the frame name with .png? */
1170 /* TODO: Add directory changing */
1171 data = (RGBA_t*) stbi_load(ir_setdata_name((ir_setdata) ir_framebox_mapsheet(fiter,SFACE) ), &img_info.width, &img_info.width, &num_channels, 0);
1172 bin_set_img_info(&img_info, ir_framebox_mapsheet(fiter, SFACE));
1173 curr_pixel_list = bin_mapframe_to_pixel_list(&img_info, 0, 0, data);
1174 default_pixel_list = bin_cmp_default_pixel_lists(curr_pixel_list, default_pixel_list);
1175
1176 free(data);
1177 }
1178
1179 return default_pixel_list;
1180 }