From 98197290ac44b0c9960ba2edd60a9ec5515aa181 Mon Sep 17 00:00:00 2001 From: "jordan@hack_attack" Date: Thu, 29 Sep 2016 09:15:34 -0700 Subject: [PATCH] addin irmem.c --- src/apc/irmem.c | 723 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 723 insertions(+) create mode 100644 src/apc/irmem.c diff --git a/src/apc/irmem.c b/src/apc/irmem.c new file mode 100644 index 0000000..3b62201 --- /dev/null +++ b/src/apc/irmem.c @@ -0,0 +1,723 @@ +/*!@file + \brief IR Memory Implementation + \details Intermediary memory management + \author Jordan Lavatai + \date Aug 2016 + ----------------------------------------------------------------------------*/ +#include +#include +#include //uint64_t +#include //memmove +#include //malloc +#include + +#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]) + +void +inc_odat(void); +void +inc_vdat(void); +void +inc_link(void); +void +inc_ref(void); +void +ir_init(void); +void +malloc_cdat(void); + + + +/* 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; + + +/* The initalization function of the IR. Mallocs the + first c/v/odat and the first links and refs and + inits the cdat_stack */ +void +ir_init() +{ + + /* Init root cdat and stack */ + char root[4] = "root"; + + cdat_buf[num_cdats] = (struct cdat*) malloc(sizeof(struct cdat) ); + cdat_buf[num_cdats]->idx = 0; + memmove(cdat_buf[num_cdats]->name, root, 4); + + cdat_stackp = cdat_stack; + *cdat_stackp = cdat_buf[num_cdats++]; + + /* Init first odat */ + if( (CURR_ODAT = (struct odat*) malloc(sizeof(struct odat))) == NULL) + perror("malloc first odat failed"); + + /* init first vdat*/ + if( (CURR_VDAT = (struct vdat*) malloc(sizeof(struct vdat))) == NULL) + perror("malloc first vdat failed"); + + /* Init first ref */ + if( (CURR_REF = (struct ref*) malloc(sizeof(struct ref))) == NULL) + perror("malloc first ref failed"); + + /* Init first link */ + if( (CURR_LINK = (struct link*) malloc(sizeof(struct link))) == NULL) + perror("malloc first link failed"); + + /* Init first post */ + if( (CURR_POST = (struct ref*) malloc(sizeof(struct ref))) == NULL) + perror("malloc first post failed"); +} + +//TODO: FREE MEMORY! +void +malloc_cdat() +{ + if(curr_max_cdats <= num_cdats) + { if( (realloc((void*) cdat_buf, PTRS_IN_PAGE * 4)) == NULL) + perror("realloc cdat_buf failed"); + curr_max_cdats += PTRS_IN_PAGE; + if( (realloc( (void*) cdat_stack, PTRS_IN_PAGE * 4)) == NULL) //increase cdat_stack also + perror("realloc cdat_stack failed"); + } + if( (cdat_buf[num_cdats] = (struct cdat*) malloc(sizeof (struct cdat)) ) == NULL ) + perror("malloc cdat failed"); + + +} + +/* Dynamically allocate memory for a class data structure, + or cdat, after a class has been identified in a grammar. + We also create a stack of class pointers so that + we can access the cdat during processing of that + cdats sets and elements, a requirement because the + nature of recursive classes prevents us from accessing + the cdat based on the previous index into cdat_buf, + which is a list of all allocated cdats*/ +void +push_cdat +( char* name +) +{ + malloc_cdat(); + + memmove(cdat_buf[num_cdats]->name, name, 32); + cdat_buf[num_cdats]->idx = num_cdats; + + /* Set the cdat as a class of the previous cdat */ + (*cdat_stackp)->class_list[(*cdat_stackp)->num_classes++] = cdat_buf[num_cdats]; + + /* Push the cdat onto the cdat_stack */ + *++cdat_stackp = cdat_buf[num_cdats++]; + +} + +void +pop_cdat +() +{ + *cdat_stackp = NULL; + cdat_stackp--; +} + +void +inc_posts +() +{ + num_posts++; + if(num_posts >= curr_max_posts) + { if( (realloc((void*) post_buf, PTRS_IN_PAGE * 4)) == NULL) + perror("realloc post_buf failed"); + curr_max_posts += PTRS_IN_PAGE; + } + if( (CURR_POST = (struct ref*) malloc(sizeof (struct ref))) == NULL) + perror("malloc post failed"); + +} +void +inc_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"); + +} + +void +inc_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"); + +} + +void +inc_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"); +} + +void +inc_ref +() +{ + + if(num_refs % 16 == 0) + { CURR_POST = CURR_REF; + inc_posts(); + } + + num_refs++; + 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"); +} +/* Called in the reduction of a set. While both odats (eles and sets) + have identical label terminals, we are unable to give a single grammatical rule + for both due to how we allocate odats in the odat buf. Due to the + nature of bottom up parsing, all the elements will be inserted into the + odat_buf first, and then the set that contains these element is inserted. Since + the sets label comes before the element list in the grammar, we would be giving an element + a set label in its respective odat, which would then be replaced by the + elements label. Instead, we store the label in the sets representation inside + CURR_CDAT and after we are done parsing the element_list and know that the CURR_ODAT + is the set, we populate the sets label members in CURR_ODAT with the values we stored + previously in CURR_CDAT. */ + +void +insert_set_label +( char* name, + uint64_t ref_id +) +{ + memmove(CURR_CDAT->CURR_SET.name,name,32); + memmove(&CURR_CDAT->CURR_SET.ref_id,&ref_id,64); + +} +void +insert_set_olink +( uint64_t ref_id +) +{ + CURR_CDAT->CURR_SET.cdat_idx = CURR_CDAT->idx; + CURR_CDAT->CURR_SET.ref_id = ref_id; /* Will be resolved to offset + when link is processed */ + CURR_LINK->type = 1; + CURR_LINK->link_t.olink.ref_id = ref_id; + CURR_LINK->cdat_idx = CURR_CDAT->idx; + CURR_LINK->set_idx = CURR_CDAT->num_sets++; + CURR_LINK->ele_idx = -1; + + inc_link(); +} + +void +insert_set_vlink +( uint64_t ref_id, + char* anim_name +) +{ + /* Insert vlink into link_stack so that it gets processed at + output time */ + CURR_LINK->cdat_idx = CURR_CDAT->idx; + CURR_LINK->set_idx = CURR_CDAT->num_sets; + CURR_LINK->type = 2; + CURR_LINK->link_t.vlink.ref_id = ref_id; + memmove(CURR_LINK->link_t.vlink.anim_name, anim_name, 32); + + +} + +void +insert_set_svlink +( uint64_t ref_id +) +{ + + /* Insert vlink into link_stack so that it gets processed at + output time */ + CURR_LINK->cdat_idx = CURR_CDAT->idx; + CURR_LINK->set_idx = CURR_CDAT->num_sets; + CURR_LINK->type = 3; + CURR_LINK->link_t.svlink.ref_id = ref_id; + +} + +/* At the point of reducing to a set, most of the + sets odat information has already been populated + during the reduction of its right hand side + non terminals (hitbox, root, quad_list). */ +void +insert_set +() +{ + uint64_t ref_id; + + ref_id = CURR_CDAT->CURR_SET.ref_id; + + CURR_CDAT->CURR_SET.cdat_idx = CURR_CDAT->idx; + memmove(CURR_ODAT->name, CURR_CDAT->CURR_SET.name, 32); + CURR_CDAT->num_sets++; + + CURR_ODAT->cdat_idx = CURR_CDAT->idx; + CURR_ODAT->refp = CURR_REF; + + + CURR_REF->lastref = PREV_REF; + PREV_REF->nextref = CURR_REF; + CURR_REF->odatp = CURR_ODAT; + + + if(ref_id == -1) /* user did not define a ref_id so */ + { ref_id = ss_ref_id; + ss_ref_id++; + } + + CURR_REF->ref_id = ref_id; + + inc_ref(); + inc_odat(); +} +/* Created as a seperate function, instead of setting the ODATS vdat_id and + calling inc_vdat() inside of insert_set(), to account for the set reduction + where a vdat is not created (o/v/svlinks). Because insert_set/ele is always + called before insert_vdat, and thus increments the CURR_ODAT to be the next + ODAT to be populated, insert_vdat() targets the last ODAT that was populated, + via PREV_ODAT. */ + +void +insert_vdat +() +{ + PREV_ODAT->vdat_id = num_vdats; //NULL for vlink, svlink + inc_vdat(); +} + +/* Populates both the odat name and ref_id + for element. */ +void +insert_ele_label +( char* name, + uint64_t ref_id +) +{ + memmove(CURR_CDAT->CURR_SET.CURR_ELE.name, name, 32); + memmove(&CURR_CDAT->CURR_SET.ele_list[CURR_CDAT->CURR_SET.ref_id].ref_id, &ref_id, 64); +} + +void +insert_ele_olink +( uint64_t ref_id +) +{ + CURR_CDAT->CURR_SET.CURR_ELE.cdat_idx = CURR_CDAT->idx; + CURR_CDAT->CURR_SET.CURR_ELE.ref_id = ref_id; /* Will be resolved to offset + when link is processed */ + CURR_LINK->type = 1; + CURR_LINK->link_t.olink.ref_id = ref_id; + CURR_LINK->cdat_idx = CURR_CDAT->idx; + CURR_LINK->set_idx = CURR_CDAT->num_sets++; + CURR_LINK->ele_idx = CURR_CDAT->CURR_SET.num_ele++; + +} + +void +insert_ele_vlink +( uint64_t ref_id, + char* anim_name +) +{ + + /* Insert vlink into link_stack so that it gets processed at + output time */ + CURR_LINK->cdat_idx = CURR_CDAT->idx; + CURR_LINK->type = 2; + CURR_LINK->set_idx = CURR_CDAT->num_sets; + CURR_LINK->ele_idx = CURR_CDAT->CURR_SET.num_ele; + CURR_LINK->link_t.vlink.ref_id = ref_id; + memmove(CURR_LINK->link_t.vlink.anim_name, anim_name, 32); + +} + +void +insert_ele_svlink +( uint64_t ref_id +) +{ + + CURR_LINK->cdat_idx = CURR_CDAT->idx; + CURR_LINK->type = 3; + CURR_LINK->set_idx = CURR_CDAT->num_sets; + CURR_LINK->ele_idx = CURR_CDAT->CURR_SET.num_ele; + CURR_LINK->link_t.svlink.ref_id = ref_id; + + +} + +//Insert element into odat_buf and cdatpages +void +insert_ele() +{ + uint64_t ref_id; + + ref_id = CURR_CDAT->CURR_SET.CURR_ELE.ref_id; + + CURR_CDAT->CURR_SET.CURR_ELE.cdat_idx = CURR_CDAT->idx; + memmove(CURR_ODAT->name,CURR_CDAT->CURR_SET.CURR_ELE.name, 32); + CURR_CDAT->CURR_SET.num_ele++; + + CURR_ODAT->cdat_idx = CURR_CDAT->idx; + CURR_ODAT->refp = CURR_REF; + + if(ref_id == -1) /* user did not define a ref_id so */ + { ref_id = ss_ref_id; + ss_ref_id++; + } + + CURR_REF->ref_id = ref_id; + + inc_odat(); + inc_ref(); + +} + +void +insert_framesheet +( char direction, + char* name, + uint64_t ref_id, + int height , + int width, + int num_frames +) +{ + CURR_VDAT->CURR_MODEL.spritesheet[(int)direction].height = height; + CURR_VDAT->CURR_MODEL.spritesheet[(int)direction].width = width; + CURR_VDAT->CURR_MODEL.spritesheet[(int)direction].num_frames = num_frames; + CURR_VDAT->num_models++; +} + +void +insert_quad +( int x, + int y, + int z, + uint64_t ref_id +) +#define CURR_QUAD (CURR_ODAT->quad_list[CURR_ODAT->num_quads]) +{ + CURR_QUAD.x = x; + CURR_QUAD.y = y; + CURR_QUAD.z = z; + CURR_QUAD.ref_id = ref_id; + CURR_ODAT->num_quads++; +} + +/* Inserting the hitbox into the set + odat. Elements that don't have + a hitbox will use the sets root. */ +void +insert_hitbox +( int hitbox +) +{ + CURR_ODAT->hitbox = hitbox; +} + +/* Inserting the root into the set + odat. Elements that don't have + a root will use the sets root. */ +void +insert_root +( int x, + int y, + int z +) +{ + + CURR_ODAT->root.x = x; + CURR_ODAT->root.y = y; + CURR_ODAT->root.z = z; +} + +void +insert_frame_pointer +( char direction, + void* frame +) +{ + CURR_VDAT->CURR_MODEL.spritesheet[(int)direction].frames[CURR_VDAT->CURR_MODEL.spritesheet[(int)direction].num_frames++] = frame; +} + -- 2.18.0