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