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