7acc6b67ba0a7ef80393d25c2edcec9616a30cd8
2 \brief IR Memory Implementation
3 \details Intermediary memory management
6 ----------------------------------------------------------------------------*/
9 #include <stdint.h> //uint64_t
10 #include <string.h> //memmove
11 #include <stdlib.h> //malloc
14 #define CURR_CDAT (*cdat_stackp)
15 #define CURR_SET set_list[CURR_CDAT->num_sets]
16 #define CURR_ELE ele_list[CURR_CDAT->CURR_SET.num_ele]
17 #define PREV_REF (ref_buf[num_refs-1])
18 #define CURR_REF (ref_buf[num_refs])
19 #define PREV_ODAT (odat_buf[num_odats-1])
20 #define CURR_ODAT (odat_buf[num_odats])
21 #define CURR_VDAT (vdat_buf[num_vdats])
22 #define PREV_VDAT (vdat_buf[num_vdats-1])
23 #define CURR_MODEL model_list[CURR_VDAT->num_models]
24 #define CURR_LINK (link_buf[num_links])
25 #define CURR_POST (post_buf[num_posts])
42 /* General: All information from the directory structure is stored in */
43 /* five buffers that comprise the IR: cdat_buf, odat_buf, vdat_buf, ref_buf */
44 /* and link_buf. Each buf corresponds to the data structure that it stores. */
45 /* The storage techique for all bufs (except cdat) is the same. Each bufs member first */
46 /* populates its struct and then allocates the space for the next member */
47 /* and increments the buf index. This means that we have to allocate the */
48 /* very first member of each buf at ir_init(), so that we don't segfault */
49 /* as the first member attempts to access memory that its previous member */
50 /* didn't allocate (because it doesnt exist). We access the buf members */
51 /* through standard array indexing but conceal the tediousness of array */
52 /* indexing with macros. E.g. without macros, acessing an elements name */
53 /* member would look like (split up to not go over line char limit): */
54 /* (*cdat_stackp)->set_list[(*cdat_stackp)->num_sets] */
55 /* .ele_list[(*cdat_stackp)->set_list[(*cdat_stackp->num_sets)].num_ele].name */
57 /* For cdats in cdat_buf, we allocate the memory for a cdat once a cdat
58 is recognized in the grammar. Cdat_buf is different from the other bufs
59 because cdats have a root cdat that all cdats are a subclass of. This root
60 cdat can have a set_list like other cdats. */
62 /* Elements: Ele stands for element and has two representations in the IR. */
63 /* In the cdat_buf eles store their name, cdat_idx (their classes index in */
64 /* the cdat_buf) and the ref_id (refer to ref ). In the odat_buf, eles store */
65 /* their object data (odat). At output time, the ref_id is dereferenced to */
66 /* determine the elements odat which is the data that the engine expects */
67 /* from an element. */
70 /* All bufs are of pointers to their respective structs. When a buf is full */
71 /* (number of data structs pointers >= max number of data struct pointers), */
72 /* we need to allocate a more pointers for that buf. Allocate these */
73 /* pointers a page at a time (1024 = Page bytes (4096)/bytes per pointer(4)) */
81 /* Sets: The set is similar to the ele, but it contains a list of its */
82 /* elements. The set is populated at parse time AFTER the elements are */
83 /* populated, due to the nature of bottom up parsing. */
90 struct ele ele_list
[MAX_ELES
];
93 /* Cdats: A cdat is a class data structure. Cdats serve as the central */
94 /* data types of the IR. At output, the cdat_buf is iterated through and */
95 /* each is written to the output file. For each cdat, sets and element */
96 /* ref_ids must be dereferenced to determine the odat information. Cdats */
97 /* contain pointers to their subclasses so that the relationship between */
98 /* classes can be determined, but the subclasses are not represented inside */
99 /* of the cdat itself but rather in the subsequent cdats in cdat_buf. We */
100 /* can determine the number of subclasses (the last index into cdat_buf */
101 /* that represents a subclass of some arbitrary cdat) each cdat has by */
102 /* incrementing num_classes during parse time. */
103 /* TODO: Should classes point to their parent class? */
110 struct cdat
* class_list
[MAX_CLASSES
];
111 struct set set_list
[MAX_SETS
];
114 /* There are an unknown amount of cdats at compile time, so we maintain */
115 /* a cdat_buf of cdat pointers that can be expanded as needed. */
116 struct cdat
* cdat_buf
[PTRS_IN_PAGE
];
118 /* The cdat_stack is a stack pointers to cdat pointers, the top of which is
119 the cdat that is currently being parsed. Whenever a new cdat is recognized
120 by the grammar (CLOPEN), a cdat is pushed onto the cdat_stack, and we refer
121 to this cdat through the macro CURR_CDAT. By keeping a cdat_stack, we have
122 access to the current cdat so that the elements and sets can populate themselves
123 in the cdat accordingly. */
125 struct cdat
* cdat_stack
[PTRS_IN_PAGE
];
126 struct cdat
** cdat_stackp
;
128 int curr_max_cdats
= PTRS_IN_PAGE
;
130 /* Refs: Each set/ele has a reference to its object data (odat) through a ref_id.
131 Ref_ids are unsigned 64 byte integers that map to the hex values RGBA. During
132 the construction of the directory structure, users can choose a RGBA value for
133 each object that any other object can refer to via links (see link). If a user
134 does not choose an RGBA value, then the object is given one from the system space.
135 We maintain a doubly linked list of refs in the ref_buf at parse time so that
136 links can be resolved after the parsing of the directory structure is complete.
137 For every 16th ref, we create a post so that we can reduce on the search time for
145 uint64_t ref_id
; //0xFFFFFF->digit
149 /* Like the cdat_buf, ref_buf stores pointers to refs and can
151 struct ref
* ref_buf
[PTRS_IN_PAGE
];
153 int curr_max_refs
= PTRS_IN_PAGE
;
154 uint64_t ss_ref_id
= 0x00FFFFFF; /* system space for ref_ids */
156 /* posts for ref_buf */
157 struct ref
* post_buf
[PTRS_IN_PAGE
];
159 int curr_max_posts
= PTRS_IN_PAGE
;
161 /* Links: At parse time, a set/ele can include a link in their
162 grammar representation instead of the actual data and this signifies
163 to the APC that that set/ele wishes to use the data of another
164 set/ele, either its video data (vdat) or object data (odat). The link
165 itself contains the type of link it is, the ref_id OR name, and
166 which set/ele created the link. During parse time, links can be made
167 to o/vdats that have yet to be parsed. In order to accomodate for this,
168 we resolve all links AFTER parse time by iterating through the link_buf,
169 finding the ref_id that was stored for some object (if the ref_id exists),
170 and creating a relative pointer from the original object to the data that
173 /* Svlinks stand for short vlink, which is a link to a vdat
174 TODO: diff btwn vlink*/
180 /* A vlink is what it sounds like, a link to a vdat
187 /* Olinks are links to odats */
195 struct svlink svlink
;
199 int type
; //1 = olink, 2 = vlink, 3 = svlink
206 /* link_buf contains all the links that
207 we encountered during parse time that need
208 to be resolved to an offset at output time.
209 This does not include quad refs, because
210 those are already known to need to be resolved */
211 struct link
* link_buf
[PTRS_IN_PAGE
];
213 int curr_max_links
= PTRS_IN_PAGE
;
216 /* Odats: Odats consist of the object data necessary for
217 each object. Odats are sometimes referred to as archetypes
218 at compile-time, in order to distinguish the difference from
219 a runtime object and a compile-time object.
220 TODO: Need more info about objects at runtime, to described
221 the reasoning behind odat structure at compile-time*/
223 /* Each set has a quad_list or a list of quads. The quad_list
227 uint64_t ref_id
; //rgba
240 struct ref
* refp
; /* pointer to it's ref on ref_list */
242 struct quad quad_list
[MAX_QUADS
];
244 struct odat
* odat_buf
[PTRS_IN_PAGE
];
246 int curr_max_odats
= PTRS_IN_PAGE
;
248 /* A framesheet is a grouping of animation frames in
249 a single direction (N,W,S,E) */
254 void* frames
[MAX_FRAMES
];
257 /* A model is a collection of framesheets for every
258 direction (N,W,S,E,NW,NE,SW,SE)*/
259 /* NAMED spritesheet */
262 struct framesheet spritesheet
[8]; //one for each
265 /* Vdat: Vdats are the video data of each object. They can not be
266 created as a stand alone object (because they consist solely
267 of animation information and not the skeleton on which the
268 animation manipulates). Vdats have a list of models for every
269 animation that the vdats odat can do for that vdat*/
271 struct odat
* creator
; //pointer to odat that made this vdat
273 struct model model_list
[MAX_MODELS
];
276 struct vdat
* vdat_buf
[PTRS_IN_PAGE
];
278 int curr_max_vdats
= PTRS_IN_PAGE
;
281 /* The initalization function of the IR. Mallocs the
282 first c/v/odat and the first links and refs and
283 inits the cdat_stack */
288 /* Init root cdat and stack */
289 char root
[4] = "root";
291 cdat_buf
[num_cdats
] = (struct cdat
*) malloc(sizeof(struct cdat
) );
292 cdat_buf
[num_cdats
]->idx
= 0;
293 memmove(cdat_buf
[num_cdats
]->name
, root
, 4);
295 cdat_stackp
= cdat_stack
;
296 *cdat_stackp
= cdat_buf
[num_cdats
++];
298 /* Init first odat */
299 if( (CURR_ODAT
= (struct odat
*) malloc(sizeof(struct odat
))) == NULL
)
300 perror("malloc first odat failed");
303 if( (CURR_VDAT
= (struct vdat
*) malloc(sizeof(struct vdat
))) == NULL
)
304 perror("malloc first vdat failed");
307 if( (CURR_REF
= (struct ref
*) malloc(sizeof(struct ref
))) == NULL
)
308 perror("malloc first ref failed");
310 /* Init first link */
311 if( (CURR_LINK
= (struct link
*) malloc(sizeof(struct link
))) == NULL
)
312 perror("malloc first link failed");
314 /* Init first post */
315 if( (CURR_POST
= (struct ref
*) malloc(sizeof(struct ref
))) == NULL
)
316 perror("malloc first post failed");
324 if(curr_max_cdats
<= num_cdats
)
326 if( (realloc((void*) cdat_buf
, PTRS_IN_PAGE
* 4)) == NULL
)
327 perror("realloc cdat_buf failed");
328 curr_max_cdats
+= PTRS_IN_PAGE
;
329 if( (realloc( (void*) cdat_stack
, PTRS_IN_PAGE
* 4)) == NULL
) //increase cdat_stack also
330 perror("realloc cdat_stack failed");
332 if( (cdat_buf
[num_cdats
] = (struct cdat
*) malloc(sizeof (struct cdat
)) ) == NULL
)
333 perror("malloc cdat failed");
338 /* Dynamically allocate memory for a class data structure,
339 or cdat, after a class has been identified in a grammar.
340 We also create a stack of class pointers so that
341 we can access the cdat during processing of that
342 cdats sets and elements, a requirement because the
343 nature of recursive classes prevents us from accessing
344 the cdat based on the previous index into cdat_buf,
345 which is a list of all allocated cdats*/
347 push_cdat(char* name
)
352 memmove(cdat_buf
[num_cdats
]->name
, name
, 32);
353 cdat_buf
[num_cdats
]->idx
= num_cdats
;
355 /* Set the cdat as a class of the previous cdat */
356 (*cdat_stackp
)->class_list
[(*cdat_stackp
)->num_classes
++] = cdat_buf
[num_cdats
];
358 /* Push the cdat onto the cdat_stack */
359 *++cdat_stackp
= cdat_buf
[num_cdats
++];
374 if(num_posts
>= curr_max_posts
)
376 if( (realloc((void*) post_buf
, PTRS_IN_PAGE
* 4)) == NULL
)
377 perror("realloc post_buf failed");
378 curr_max_posts
+= PTRS_IN_PAGE
;
380 if( (CURR_POST
= (struct ref
*) malloc(sizeof (struct ref
))) == NULL
)
382 perror("malloc post failed");
390 if(num_odats
>= curr_max_odats
)
392 if( (realloc((void*) odat_buf
, PTRS_IN_PAGE
* 4)) == NULL
)
393 perror("realloc odat_buf failed");
394 curr_max_odats
+= PTRS_IN_PAGE
;
396 if( (CURR_ODAT
= (struct odat
*) malloc(sizeof (struct odat
))) == NULL
)
398 perror("malloc odat failed");
407 if(num_vdats
>= curr_max_vdats
)
409 if( (realloc((void*) vdat_buf
, PTRS_IN_PAGE
* 4)) == NULL
)
410 perror("realloc vdat_buf failed");
411 curr_max_vdats
+= PTRS_IN_PAGE
;
413 if((CURR_VDAT
= (struct vdat
*) malloc(sizeof (struct vdat
))) == NULL
)
415 perror("malloc vdat failed");
424 if(num_links
>= curr_max_links
)
426 if( (realloc((void*) link_buf
, PTRS_IN_PAGE
* 4)) == NULL
)
427 perror("realloc vdat_buf failed");
428 curr_max_links
+= PTRS_IN_PAGE
;
430 if((CURR_LINK
= (struct link
*) malloc(sizeof (struct link
))) == NULL
)
432 perror("malloc link failed");
440 if(num_refs
% 16 == 0)
442 CURR_POST
= CURR_REF
;
447 if(num_refs
>= curr_max_refs
)
449 if( (realloc((void*) ref_buf
, PTRS_IN_PAGE
* 4)) == NULL
)
450 perror("realloc ref_buf failed");
451 curr_max_refs
+= PTRS_IN_PAGE
;
453 if((CURR_REF
= (struct ref
*) malloc(sizeof (struct ref
))) == NULL
)
454 perror("malloc ref failed");
456 /* Called in the reduction of a set. While both odats (eles and sets)
457 have identical label terminals, we are unable to give a single grammatical rule
458 for both due to how we allocate odats in the odat buf. Due to the
459 nature of bottom up parsing, all the elements will be inserted into the
460 odat_buf first, and then the set that contains these element is inserted. Since
461 the sets label comes before the element list in the grammar, we would be giving an element
462 a set label in its respective odat, which would then be replaced by the
463 elements label. Instead, we store the label in the sets representation inside
464 CURR_CDAT and after we are done parsing the element_list and know that the CURR_ODAT
465 is the set, we populate the sets label members in CURR_ODAT with the values we stored
466 previously in CURR_CDAT. */
469 insert_set_label(char* name
, uint64_t ref_id
)
471 memmove(CURR_CDAT
->CURR_SET
.name
,name
,32);
472 memmove(&CURR_CDAT
->CURR_SET
.ref_id
,&ref_id
,64);
476 insert_set_olink(uint64_t ref_id
)
478 CURR_CDAT
->CURR_SET
.cdat_idx
= CURR_CDAT
->idx
;
479 CURR_CDAT
->CURR_SET
.ref_id
= ref_id
; /* Will be resolved to offset
480 when link is processed */
482 CURR_LINK
->link_t
.olink
.ref_id
= ref_id
;
483 CURR_LINK
->cdat_idx
= CURR_CDAT
->idx
;
484 CURR_LINK
->set_idx
= CURR_CDAT
->num_sets
++;
485 CURR_LINK
->ele_idx
= -1;
491 insert_set_vlink(uint64_t ref_id
, char* anim_name
)
493 /* Insert vlink into link_stack so that it gets processed at
495 CURR_LINK
->cdat_idx
= CURR_CDAT
->idx
;
496 CURR_LINK
->set_idx
= CURR_CDAT
->num_sets
;
498 CURR_LINK
->link_t
.vlink
.ref_id
= ref_id
;
499 memmove(CURR_LINK
->link_t
.vlink
.anim_name
, anim_name
, 32);
505 insert_set_svlink(uint64_t ref_id
)
508 /* Insert vlink into link_stack so that it gets processed at
510 CURR_LINK
->cdat_idx
= CURR_CDAT
->idx
;
511 CURR_LINK
->set_idx
= CURR_CDAT
->num_sets
;
513 CURR_LINK
->link_t
.svlink
.ref_id
= ref_id
;
517 /* At the point of reducing to a set, most of the
518 sets odat information has already been populated
519 during the reduction of its right hand side
520 non terminals (hitbox, root, quad_list). */
526 ref_id
= CURR_CDAT
->CURR_SET
.ref_id
;
528 CURR_CDAT
->CURR_SET
.cdat_idx
= CURR_CDAT
->idx
;
529 memmove(CURR_ODAT
->name
, CURR_CDAT
->CURR_SET
.name
, 32);
530 CURR_CDAT
->num_sets
++;
532 CURR_ODAT
->cdat_idx
= CURR_CDAT
->idx
;
533 CURR_ODAT
->refp
= CURR_REF
;
536 CURR_REF
->lastref
= PREV_REF
;
537 PREV_REF
->nextref
= CURR_REF
;
538 CURR_REF
->odatp
= CURR_ODAT
;
541 if(ref_id
== -1) /* user did not define a ref_id so */
542 { /* use a ref_id from system_space */
547 CURR_REF
->ref_id
= ref_id
;
554 /* Created as a seperate function, instead of setting the ODATS vdat_id and
555 calling inc_vdat() inside of insert_set(), to account for the set reduction
556 where a vdat is not created (o/v/svlinks). Because insert_set/ele is always
557 called before insert_vdat, and thus increments the CURR_ODAT to be the next
558 ODAT to be populated, insert_vdat() targets the last ODAT that was populated,
564 PREV_ODAT
->vdat_id
= num_vdats
; //NULL for vlink, svlink
568 /* Populates both the odat name and ref_id
571 insert_ele_label(char* name
, uint64_t ref_id
)
573 memmove(CURR_CDAT
->CURR_SET
.CURR_ELE
.name
, name
, 32);
574 memmove(&CURR_CDAT
->CURR_SET
.ele_list
[CURR_CDAT
->CURR_SET
.ref_id
].ref_id
, &ref_id
, 64);
578 insert_ele_olink(uint64_t ref_id
)
580 CURR_CDAT
->CURR_SET
.CURR_ELE
.cdat_idx
= CURR_CDAT
->idx
;
581 CURR_CDAT
->CURR_SET
.CURR_ELE
.ref_id
= ref_id
; /* Will be resolved to offset
582 when link is processed */
584 CURR_LINK
->link_t
.olink
.ref_id
= ref_id
;
585 CURR_LINK
->cdat_idx
= CURR_CDAT
->idx
;
586 CURR_LINK
->set_idx
= CURR_CDAT
->num_sets
++;
587 CURR_LINK
->ele_idx
= CURR_CDAT
->CURR_SET
.num_ele
++;
591 insert_ele_vlink(uint64_t ref_id
, char* anim_name
)
594 /* Insert vlink into link_stack so that it gets processed at
596 CURR_LINK
->cdat_idx
= CURR_CDAT
->idx
;
598 CURR_LINK
->set_idx
= CURR_CDAT
->num_sets
;
599 CURR_LINK
->ele_idx
= CURR_CDAT
->CURR_SET
.num_ele
;
600 CURR_LINK
->link_t
.vlink
.ref_id
= ref_id
;
601 memmove(CURR_LINK
->link_t
.vlink
.anim_name
, anim_name
, 32);
606 insert_ele_svlink(uint64_t ref_id
)
609 CURR_LINK
->cdat_idx
= CURR_CDAT
->idx
;
611 CURR_LINK
->set_idx
= CURR_CDAT
->num_sets
;
612 CURR_LINK
->ele_idx
= CURR_CDAT
->CURR_SET
.num_ele
;
613 CURR_LINK
->link_t
.svlink
.ref_id
= ref_id
;
617 //Insert element into odat_buf and cdatpages
624 ref_id
= CURR_CDAT
->CURR_SET
.CURR_ELE
.ref_id
;
626 CURR_CDAT
->CURR_SET
.CURR_ELE
.cdat_idx
= CURR_CDAT
->idx
;
627 memmove(CURR_ODAT
->name
,CURR_CDAT
->CURR_SET
.CURR_ELE
.name
, 32);
628 CURR_CDAT
->CURR_SET
.num_ele
++;
630 CURR_ODAT
->cdat_idx
= CURR_CDAT
->idx
;
631 CURR_ODAT
->refp
= CURR_REF
;
633 if(ref_id
== -1) /* user did not define a ref_id so */
634 { /* use a ref_id from system_space */
639 CURR_REF
->ref_id
= ref_id
;
647 insert_framesheet(char direction
, char* name
, uint64_t ref_id
, int height
, int width
, int num_frames
)
649 CURR_VDAT
->CURR_MODEL
.spritesheet
[(int)direction
].height
= height
;
650 CURR_VDAT
->CURR_MODEL
.spritesheet
[(int)direction
].width
= width
;
651 CURR_VDAT
->CURR_MODEL
.spritesheet
[(int)direction
].num_frames
= num_frames
;
652 CURR_VDAT
->num_models
++;
655 #define CURR_QUAD (CURR_ODAT->quad_list[CURR_ODAT->num_quads])
657 insert_quad(int x
, int y
, int z
, uint64_t ref_id
)
662 CURR_QUAD
.ref_id
= ref_id
;
663 CURR_ODAT
->num_quads
++;
666 /* Inserting the hitbox into the set
667 odat. Elements that don't have
668 a hitbox will use the sets root. */
670 insert_hitbox(int hitbox
)
672 CURR_ODAT
->hitbox
= hitbox
;
675 /* Inserting the root into the set
676 odat. Elements that don't have
677 a root will use the sets root. */
679 insert_root(int x
, int y
, int z
)
682 CURR_ODAT
->root
.x
= x
;
683 CURR_ODAT
->root
.y
= y
;
684 CURR_ODAT
->root
.z
= z
;
688 insert_frame_pointer(char direction
, void* frame
)
690 CURR_VDAT
->CURR_MODEL
.spritesheet
[(int)direction
].frames
[CURR_VDAT
->CURR_MODEL
.spritesheet
[(int)direction
].num_frames
++] = frame
;