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