#include #include #include #include #include #include #include struct odat* alloc_odat(void); void alloc_vdat(void); struct ref* alloc_link(void); struct ref* alloc_ref(void); struct cdat* curr_cdat(void); struct odat* curr_odat(void); struct ele* curr_ele(void); struct set* curr_set(void); struct ref* prev_ref(void); #define CURR_CDAT (*cdat_stackp) #define CURR_SET set_list[CURR_CDAT->num_sets] #define CURR_ELE ele_list[CURR_CDAT->CURR_SET.num_ele] #define PREV_REF (ref_buf[num_refs-1]) #define CURR_REF (ref_buf[num_refs]) #define PREV_ODAT (odat_buf[num_odats-1]) #define CURR_ODAT (odat_buf[num_odats]) #define CURR_VDAT (vdat_buf[num_vdats]) #define PREV_VDAT (vdat_buf[num_vdats-1]) #define CURR_MODEL model_list[CURR_VDAT->num_models] #define CURR_LINK (link_buf[num_links]) #define CURR_POST (post_buf[num_posts]) /* General: All information from the directory structure is stored in */ /* five buffers that comprise the IR: cdat_buf, odat_buf, vdat_buf, ref_buf */ /* and link_buf. Each buf corresponds to the data structure that it stores. */ /* The storage techique for all bufs (except cdat) is the same. Each bufs member first */ /* populates its struct and then allocates the space for the next member */ /* and increments the buf index. This means that we have to allocate the */ /* very first member of each buf at ir_init(), so that we don't segfault */ /* as the first member attempts to access memory that its previous member */ /* didn't allocate (because it doesnt exist). We access the buf members */ /* through standard array indexing but conceal the tediousness of array */ /* indexing with macros. E.g. without macros, acessing an elements name */ /* member would look like (split up to not go over line char limit): */ /* (*cdat_stackp)->set_list[(*cdat_stackp)->num_sets] */ /* .ele_list[(*cdat_stackp)->set_list[(*cdat_stackp->num_sets)].num_ele].name */ /* For cdats in cdat_buf, we allocate the memory for a cdat once a cdat is recognized in the grammar. Cdat_buf is different from the other bufs because cdats have a root cdat that all cdats are a subclass of. This root cdat can have a set_list like other cdats. */ /* Elements: Ele stands for element and has two representations in the IR. */ /* In the cdat_buf eles store their name, cdat_idx (their classes index in */ /* the cdat_buf) and the ref_id (refer to ref ). In the odat_buf, eles store */ /* their object data (odat). At output time, the ref_id is dereferenced to */ /* determine the elements odat which is the data that the engine expects */ /* from an element. */ /* All bufs are of pointers to their respective structs. When a buf is full */ /* (number of data structs pointers >= max number of data struct pointers), */ /* we need to allocate a more pointers for that buf. Allocate these */ /* pointers a page at a time (1024 = Page bytes (4096)/bytes per pointer(4)) */ struct ele { char name[32]; uint64_t ref_id; int cdat_idx; }; /* Sets: The set is similar to the ele, but it contains a list of its */ /* elements. The set is populated at parse time AFTER the elements are */ /* populated, due to the nature of bottom up parsing. */ struct set { char name[32]; uint64_t ref_id; int cdat_idx; int num_ele; struct ele ele_list[MAX_ELES]; }; /* Cdats: A cdat is a class data structure. Cdats serve as the central */ /* data types of the IR. At output, the cdat_buf is iterated through and */ /* each is written to the output file. For each cdat, sets and element */ /* ref_ids must be dereferenced to determine the odat information. Cdats */ /* contain pointers to their subclasses so that the relationship between */ /* classes can be determined, but the subclasses are not represented inside */ /* of the cdat itself but rather in the subsequent cdats in cdat_buf. We */ /* can determine the number of subclasses (the last index into cdat_buf */ /* that represents a subclass of some arbitrary cdat) each cdat has by */ /* incrementing num_classes during parse time. */ /* TODO: Should classes point to their parent class? */ struct cdat { char name[32]; int idx; int num_classes; int num_sets; struct cdat* class_list[MAX_CLASSES]; struct set set_list[MAX_SETS]; }; /* There are an unknown amount of cdats at compile time, so we maintain */ /* a cdat_buf of cdat pointers that can be expanded as needed. */ struct cdat* cdat_buf[PTRS_IN_PAGE]; /* The cdat_stack is a stack pointers to cdat pointers, the top of which is the cdat that is currently being parsed. Whenever a new cdat is recognized by the grammar (CLOPEN), a cdat is pushed onto the cdat_stack, and we refer to this cdat through the macro CURR_CDAT. By keeping a cdat_stack, we have access to the current cdat so that the elements and sets can populate themselves in the cdat accordingly. */ struct cdat* cdat_stack[PTRS_IN_PAGE]; struct cdat** cdat_stackp; int num_cdats = 0; int curr_max_cdats = PTRS_IN_PAGE; /* Refs: Each set/ele has a reference to its object data (odat) through a ref_id. Ref_ids are unsigned 64 byte integers that map to the hex values RGBA. During the construction of the directory structure, users can choose a RGBA value for each object that any other object can refer to via links (see link). If a user does not choose an RGBA value, then the object is given one from the system space. We maintain a doubly linked list of refs in the ref_buf at parse time so that links can be resolved after the parsing of the directory structure is complete. For every 16th ref, we create a post so that we can reduce on the search time for a random access. */ struct ref { int type; struct ref* nextref; struct ref* lastref; struct odat* odatp; uint64_t ref_id; //0xFFFFFF->digit }; /* Like the cdat_buf, ref_buf stores pointers to refs and can increase in size */ struct ref* ref_buf[PTRS_IN_PAGE]; int num_refs = 0; int curr_max_refs = PTRS_IN_PAGE; uint64_t ss_ref_id = 0x00FFFFFF; /* system space for ref_ids */ /* posts for ref_buf */ struct ref* post_buf[PTRS_IN_PAGE]; int num_posts = 0; int curr_max_posts = PTRS_IN_PAGE; /* Links: At parse time, a set/ele can include a link in their grammar representation instead of the actual data and this signifies to the APC that that set/ele wishes to use the data of another set/ele, either its video data (vdat) or object data (odat). The link itself contains the type of link it is, the ref_id OR name, and which set/ele created the link. During parse time, links can be made to o/vdats that have yet to be parsed. In order to accomodate for this, we resolve all links AFTER parse time by iterating through the link_buf, finding the ref_id that was stored for some object (if the ref_id exists), and creating a relative pointer from the original object to the data that was linked */ /* Svlinks stand for short vlink, which is a link to a vdat TODO: diff btwn vlink*/ struct svlink { uint64_t ref_id; }; /* A vlink is what it sounds like, a link to a vdat TODO: model link? */ struct vlink { uint64_t ref_id; char anim_name[32]; }; /* Olinks are links to odats */ struct olink { uint64_t ref_id; }; union link_t { struct olink olink; struct vlink vlink; struct svlink svlink; }; struct link { int type; //1 = olink, 2 = vlink, 3 = svlink union link_t link_t; int cdat_idx; int set_idx; int ele_idx; }; /* link_buf contains all the links that we encountered during parse time that need to be resolved to an offset at output time. This does not include quad refs, because those are already known to need to be resolved */ struct link* link_buf[PTRS_IN_PAGE]; int num_links = 0; int curr_max_links = PTRS_IN_PAGE; /* Odats: Odats consist of the object data necessary for each object. Odats are sometimes referred to as archetypes at compile-time, in order to distinguish the difference from a runtime object and a compile-time object. TODO: Need more info about objects at runtime, to described the reasoning behind odat structure at compile-time*/ /* Each set has a quad_list or a list of quads. The quad_list is the ? */ struct quad { int x, y, z; uint64_t ref_id; //rgba }; struct root { int x, y, z; }; struct odat { char name[32]; int vdat_id; int cdat_idx; int hitbox; struct root root; struct ref* refp; /* pointer to it's ref on ref_list */ int num_quads; struct quad quad_list[MAX_QUADS]; }; struct odat* odat_buf[PTRS_IN_PAGE]; int num_odats = 0; int curr_max_odats = PTRS_IN_PAGE; /* A framesheet is a grouping of animation frames in a single direction (N,W,S,E) */ struct framesheet { int width; int height; int num_frames; void* frames[MAX_FRAMES]; }; /* A model is a collection of framesheets for every direction (N,W,S,E,NW,NE,SW,SE)*/ /* NAMED spritesheet */ struct model { char name[32]; struct framesheet spritesheet[8]; //one for each }; /* Vdat: Vdats are the video data of each object. They can not be created as a stand alone object (because they consist solely of animation information and not the skeleton on which the animation manipulates). Vdats have a list of models for every animation that the vdats odat can do for that vdat*/ struct vdat { struct odat* creator; //pointer to odat that made this vdat int num_models; struct model model_list[MAX_MODELS]; }; struct vdat* vdat_buf[PTRS_IN_PAGE]; int num_vdats = 0; int curr_max_vdats = PTRS_IN_PAGE; struct odat* alloc_odat () { num_odats++; if(num_odats >= curr_max_odats) { if( (realloc((void*) odat_buf, PTRS_IN_PAGE * 4)) == NULL) perror("realloc odat_buf failed"); curr_max_odats += PTRS_IN_PAGE; } if( (CURR_ODAT = (struct odat*) malloc(sizeof (struct odat))) == NULL) perror("malloc odat failed"); return CURR_ODAT; } void alloc_vdat () { num_vdats++; if(num_vdats >= curr_max_vdats) { if( (realloc((void*) vdat_buf, PTRS_IN_PAGE * 4)) == NULL) perror("realloc vdat_buf failed"); curr_max_vdats += PTRS_IN_PAGE; } if((CURR_VDAT = (struct vdat*) malloc(sizeof (struct vdat))) == NULL) perror("malloc vdat failed"); return CURR_VDAT; } struct link* alloc_link () { num_links++; if(num_links >= curr_max_links) { if( (realloc((void*) link_buf, PTRS_IN_PAGE * 4)) == NULL) perror("realloc vdat_buf failed"); curr_max_links += PTRS_IN_PAGE; } if((CURR_LINK = (struct link*) malloc(sizeof (struct link))) == NULL) perror("malloc link failed"); return CURR_LINK; } struct ref* alloc_ref () { num_refs++; if(num_refs % 16 == 0) { CURR_POST = CURR_REF; inc_posts(); } if(num_refs >= curr_max_refs) { if( (realloc((void*) ref_buf, PTRS_IN_PAGE * 4)) == NULL) perror("realloc ref_buf failed"); curr_max_refs += PTRS_IN_PAGE; } if((CURR_REF = (struct ref*) malloc(sizeof (struct ref))) == NULL) perror("malloc ref failed"); return CURR_REF; } struct cdat* curr_cdat () { return CURR_CDAT; } struct odat* curr_odat () { return CURR_ODAT; } struct set* curr_set () { return CURR_CDAT->CURR_SET; } struct ele* curr_ele () { return CURR_CDAT->CURR_SET->CURR_ELE; } struct ref* prev_ref () { return PREV_REF; }