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