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