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