/// //Frees resuorces allocated by an Asset Buffer //Deletes data being held in buffer!! // //PArameters: // buffer: pointer to The buffer to free static void AssetManager_FreeBuffer(AssetBuffer* buffer) { for (int i = 0; i < buffer->meshMap->data->capacity; i++) { //Mesh_Free((Mesh*)buffer->meshMap->data[i]->data); Mesh* m = *(Mesh**)DynamicArray_Index(buffer->meshMap->data, i); if(m != NULL) { Mesh_Free(m); } } HashMap_Free(buffer->meshMap); //for (int i = 0; i < buffer->textureMap->size; i++) for (int i = 0; i < buffer->textureMap->data->capacity; i++) { //Texture_Free((Texture*)buffer->meshMap->data[i]->data); Texture* t = *(Texture**)DynamicArray_Index(buffer->textureMap->data, i); if(t != NULL) { Texture_Free(t); } } HashMap_Free(buffer->textureMap); }
/// //Frees resuorces allocated by an Asset Buffer //Deletes data being held in buffer!! // //PArameters: // buffer: pointer to The buffer to free static void AssetManager_FreeBuffer(AssetBuffer* buffer) { for (unsigned int i = 0; i < buffer->meshMap->data->capacity; i++) { struct HashMap_KeyValuePair* pair = *(struct HashMap_KeyValuePair**)DynamicArray_Index(buffer->meshMap->data, i); if(pair != NULL) { Mesh* m = (Mesh*)pair->data; Mesh_Free(m); //Following line will be done by HashMap_Free //HashMap_KeyValuePair_Free(pair); } } printf("Meshes freed\n"); HashMap_Free(buffer->meshMap); printf("MeshMap freed\n"); for (unsigned int i = 0; i < buffer->textureMap->data->capacity; i++) { struct HashMap_KeyValuePair* pair = *(struct HashMap_KeyValuePair**)DynamicArray_Index(buffer->textureMap->data, i); if(pair != NULL) { Texture* t = (Texture*)pair->data; Texture_Free(t); } } printf("Textures freed.\n"); HashMap_Free(buffer->textureMap); printf("Texture Map Freed.\n"); }
/// //Frees data allocated by an oct tree node // //Parameters: // tree: A pointer to the oct tree which the node being freed is apart of // node: A pointer to the oct tree node to free static void OctTree_Node_Free(OctTree* tree, struct OctTree_Node* node) { //If this node has children if(node->children != NULL) { for(int i = 0; i < 8; i++) { //Free the children! OctTree_Node_Free(tree, node->children + i); } //Free the children container... free(node->children); } else { //TODO: Figure out the proper way to deal with the freeing of the tree's hashmap. //Loop through the occupants of this list for(unsigned int i = 0; i < node->data->size; i++) { GObject* occupant = *(GObject**)DynamicArray_Index(node->data, i); //If the occupant still has a log in the hashmap if(HashMap_Contains(tree->map, &occupant, sizeof(GObject*))) { //Get the log of the occupant from the hashmap DynamicArray* log = (DynamicArray*)HashMap_LookUp(tree->map, &occupant, sizeof(GObject*))->data; //Find this node in the log struct OctTree_NodeStatus* status = NULL; for(unsigned int j = 0; j < log->size; j++) { status = (struct OctTree_NodeStatus*)DynamicArray_Index(log, j); if(status->node == node) { //When we find it, remove this node from the log. DynamicArray_RemoveAndReposition(log, j); //If there is no other nodes logged, delete the log. if(log->size == 0) { HashMap_Remove(tree->map, &occupant, sizeof(GObject*)); DynamicArray_Free(log); } //Stop looping break; } } } } } //Free the data contained within this tree DynamicArray_Free(node->data); //The parent node does the following, we must only free the root at the end. //Free this node //free(node); }
/// //Takes an existing key value pair and re-hashes and re-adds it to the hashmap //To be used when a hashmap is growing in size // //Parameters: // map: THe hashmap the existing pair is being added to // pair: THe pair to add static void HashMap_AddPair(HashMap* map, struct HashMap_KeyValuePair* pair) { unsigned int hash = map->Hash(pair->key, pair->keyLength); unsigned int index = hash % map->data->capacity; while(*(struct HashMap_KeyValuePair**)DynamicArray_Index(map->data, index) != NULL) { index = (index + 1) % map->data->capacity; } *(struct HashMap_KeyValuePair**)DynamicArray_Index(map->data, index) = pair; map->data->size++; }
/// //Checks if a key is contained within the hashmap // //Parameters: // map: The map to search // key: The key to search for // keyLength: The length of the key in bytes unsigned char HashMap_Contains(HashMap* map, void* key, unsigned int keyLength) { unsigned int index = (map->Hash(key, keyLength) % map->data->capacity); struct HashMap_KeyValuePair* pair = NULL; for(unsigned int i = 0; i < map->data->capacity; i++) { pair = *(struct HashMap_KeyValuePair**)DynamicArray_Index(map->data, (index + i) % map->data->capacity); if(pair == NULL) { //This cannot be assumed because what if there is a collision, then the object which initially caused the collision is removed //And we search for the object which was subject to the collision. //break; } else { if(keyLength == pair->keyLength) { if(memcmp(key, pair->key, pair->keyLength) == 0) return 1; } } } return 0; }
/// //Adds data to a hashmap // //Parameters: // map: Map to add to // key: Key to retrieve data later // data: pointer to The data being added // keyLength: The size of the key in bytes void HashMap_Add(HashMap* map, void* key, void* data, unsigned int keyLength) { struct HashMap_KeyValuePair* pair = HashMap_KeyValuePair_Allocate(); HashMap_KeyValuePair_Initialize(pair, key, data, keyLength); unsigned int index = map->Hash(key, keyLength) % map->data->capacity; while(*(struct HashMap_KeyValuePair**)DynamicArray_Index(map->data, index) != NULL) { index = (index + 1) % map->data->capacity; } *(struct HashMap_KeyValuePair**)DynamicArray_Index(map->data, index) = pair; map->data->size++; //If the array needs to grow if(map->data->size == map->data->capacity) { HashMap_Grow(map); } }
/// //Looks up a key and returns the related data // //Parameters: // map: The HashMap to lookup data in // key: The key related to the data // keyLength: The size of the key in bytes // //Returns: // Pointer to data struct HashMap_KeyValuePair* HashMap_LookUp(HashMap* map, void* key, unsigned int keyLength) { unsigned int index = (map->Hash(key, keyLength) % map->data->capacity); struct HashMap_KeyValuePair* pair = 0; for (unsigned int i = 0; i < map->data->capacity; i++) { pair = *(struct HashMap_KeyValuePair**)DynamicArray_Index(map->data, (index + i) % map->data->capacity); if (pair != NULL) if(keyLength == pair->keyLength) if (memcmp(key, pair->key, pair->keyLength) == 0) return pair; } return NULL; }
/// //Subdivides an oct tree node into 8 child nodes, re-adding all occupants to the oct tree //Also removes the corresponding log entry for the parent node from the occupants, //And adds the necessary child node log entries // //Parameters: // tree: A pointer to the oct tree inw hcihc this node lives // node: A pointer to the node being subdivided static void OctTree_Node_SubdivideAndLog(OctTree*tree, struct OctTree_Node* node) { //Allocate this nodes children node->children = OctTree_Node_AllocateChildren(); //Initialize this nodes children OctTree_Node_InitializeChildren(tree, node); unsigned int numOccupants = node->data->size; //Create a temporary list of occupants GObject** occupants = (GObject**)malloc(sizeof(GObject**) * numOccupants); //Copy occupants from node into temporary list memcpy(occupants, node->data->data, sizeof(GObject**) * numOccupants); //Clear the node's data DynamicArray_Clear(node->data); //re-add all contents to the node GObject* current; for(unsigned int i = 0; i < numOccupants; i++) { //Get the GObject* at index i current = occupants[i]; //Get this log of this object DynamicArray* log = (DynamicArray*)HashMap_LookUp(tree->map, ¤t, sizeof(GObject*))->data; //Find parent node in the log for(unsigned int j = 0; j < log->size; j++) { if(((struct OctTree_NodeStatus*)DynamicArray_Index(log, j))->node == node) { //And remove it DynamicArray_RemoveAndReposition(log, j); break; } } //Add the GObject* back into the node OctTree_Node_AddAndLog(tree, node, current); } //Free the temporary list of occupants free(occupants); }
/// //Frees a hashmap //Does not free data!! Delete prior to this! OR have other references!!! // //Parameters: // map: The Hashmap to free void HashMap_Free(HashMap* map) { //for (unsigned int i = 0; i < map->size; i++) for(unsigned int i = 0; i < map->data->capacity; i++) { HashMap_KeyValuePair* pair = NULL; if((pair = *(HashMap_KeyValuePair**)DynamicArray_Index(map->data, i)) != NULL) { HashMap_KeyValuePair_Free(pair); DynamicArray_Remove(map->data, i); } } //free(map->data); DynamicArray_Free(map->data); free(map); }
/// //Removes an entry from the hashmap //Does not delete data! // //Parameters: // map: Map to remove entry from // key: Key relating to data to be removed // keyLength: The size of the key in bytes void* HashMap_Remove(HashMap* map, void* key, unsigned int keyLength) { unsigned short found = 0; unsigned int index = (map->Hash(key, keyLength) % map->data->capacity); struct HashMap_KeyValuePair* pairToRemove = 0; //for (unsigned int i = 0; i < map->capacity; i++) for(unsigned int i = 0; i < map->data->capacity; i++) { pairToRemove = *(HashMap_KeyValuePair**)DynamicArray_Index(map->data, (index + i) % map->data->capacity); if(pairToRemove == NULL) { //printf("Pair NULL..\n"); } else if(keyLength == pairToRemove->keyLength) { if (memcmp(key, pairToRemove->key, pairToRemove->keyLength) == 0) { index = (index + i) % map->data->capacity; found = 1; break; } } } void* data = NULL; if (found == 1) { data = pairToRemove->data; HashMap_KeyValuePair_Free(pairToRemove); //DynamicArray_Remove(map->data, index); memset((char*)map->data->data + index * map->data->dataSize, 0, map->data->dataSize); map->data->size--; } return data; }
/// //adds a game object to a node of the oct tree and logs all nodes in which it is contained. // //Parameters: // tree: A pointer to the oct tree the object is being added to // node: A pointer to the node the object is being added to // obj: A pointer to the game object being added to the tree void OctTree_Node_AddAndLog(OctTree* tree, struct OctTree_Node* node, GObject* obj) { //If this node has children, determine which children the object collides with if(node->children != NULL) { for(int i = 0; i < 8; i++) { unsigned char collisionStatus = OctTree_Node_DoesObjectCollide(node->children + i, obj); //If the object is fully contained in this node if(collisionStatus == 2) { //Add the nobject to this node & stop looping OctTree_Node_AddAndLog(tree, node->children + i, obj); break; } //Else if the object is partially contained in this node else if(collisionStatus == 1) { //Add the object to this node & keep looping OctTree_Node_AddAndLog(tree, node->children + i, obj); } } } //If this node has no children else { //Can we hold another object? or are we too deep to subdivide? if(node->data->size <= tree->maxOccupancy || node->depth >= tree->maxDepth) { //Make sure we aren't already holding a pointer to the object... if(DynamicArray_ContainsWithin(node->data, &obj, node->data->size) == 0) { //Add the object! DynamicArray_Append(node->data, &obj); //Find the entry for this object in the treemap DynamicArray* log = NULL; //Is this object already contained in the map? if(HashMap_Contains(tree->map, &obj, sizeof(GObject*)) == 1) { log = (DynamicArray*)HashMap_LookUp(tree->map, &obj, sizeof(GObject*))->data; } else { //Add this object to the tree map log = DynamicArray_Allocate(); DynamicArray_Initialize(log, sizeof(struct OctTree_NodeStatus)); HashMap_Add(tree->map, &obj, log, sizeof(GObject*)); } //Add this node to the log of the object //Get the containment status! unsigned char status = OctTree_Node_DoesObjectCollide(node, obj); //create a Nodestatus struct struct OctTree_NodeStatus entry; entry.node = node; entry.collisionStatus = status; //Log the entry! DynamicArray_Append(log, &entry); } //Else, it is already contained else { //Check if the status of containment in this node has changed //Get the object's log DynamicArray* log = (DynamicArray*)HashMap_LookUp(tree->map, &obj, sizeof(GObject*))->data; //Find the entry of this node in the log struct OctTree_NodeStatus* entry = NULL; for(unsigned int i = 0; i < log->size; i++) { struct OctTree_NodeStatus* mightBeTheEntry = (struct OctTree_NodeStatus*)DynamicArray_Index(log, i); //If we find it if(mightBeTheEntry->node == node) { entry = mightBeTheEntry; break; } } //If this object is logged as being in this node if(entry != NULL) { //Compare the status of the entry to the current status unsigned char status = OctTree_Node_DoesObjectCollide(node, obj); if(entry->collisionStatus != status) { //Update the status entry->collisionStatus = status; } } //This object is not logged as being in this node else { //Create an entry //Get the containment status! unsigned char status = OctTree_Node_DoesObjectCollide(node, obj); //create a Nodestatus struct struct OctTree_NodeStatus entry; entry.node = node; entry.collisionStatus = status; //Log the entry! DynamicArray_Append(log, &entry); } } } //Else, we are out of room and can subdivide! else { OctTree_Node_SubdivideAndLog(tree, node); //Finally, recall this function to add the object to one of the children OctTree_Node_AddAndLog(tree, node, obj); } } }
/// //Updates the position of all gameobjects within the oct tree // //Parameters: // tree: A pointer to the oct tree to update // gameObjects: A linked list of all game objects currently in the simulation void OctTree_Update(OctTree* tree, LinkedList* gameObjects) { struct LinkedList_Node* current = gameObjects->head; while(current != NULL) { GObject* gameObj = (GObject*)current->data; //Find all gameObjects which have entries in the octtree (& treemap) if(gameObj->collider != NULL) { //Get the treemap entry DynamicArray* log = (DynamicArray*)HashMap_LookUp(tree->map, &gameObj, sizeof(GObject*))->data; if(log->size <= 0) { //printf("Not contained in any tree..\n"); //OctTree_AddAndLog(tree, gameObj); } //For each OctTree_Node the game object was in for(unsigned int i = 0; i < log->size; i++) { struct OctTree_NodeStatus* nodeStatus = (struct OctTree_NodeStatus*)DynamicArray_Index(log, i); //get it's current status for this node unsigned char currentStatus = OctTree_Node_DoesObjectCollide(nodeStatus->node, gameObj); //If the status has remained the same, continue to the next one if(nodeStatus->collisionStatus == currentStatus) continue; //If the current status says that the object is no longer in the node if(currentStatus == 0) { printf("Object left node\n"); //Remove the object from this node OctTree_Node_Remove(nodeStatus->node, gameObj); //Find where it moved struct OctTree_Node* containingNode = OctTree_SearchUp(nodeStatus->node, gameObj); //If it is still in a node if(containingNode != NULL) { //Add it to that node! OctTree_Node_AddAndLog(tree, containingNode, gameObj); } else { printf("No node found to relocate\n"); } //Remove the ith nodeStatus from the log DynamicArray_RemoveAndReposition(log, i); } //Object was fully contained, and now it is not else if(currentStatus == 1) { printf("Object leaving node\n"); //Update the status nodeStatus->collisionStatus = currentStatus; //Find where it moved struct OctTree_Node* containingNode = OctTree_SearchUp(nodeStatus->node, gameObj); //If it is even in a node anymore if(containingNode != NULL) { //Add it to that node! OctTree_Node_AddAndLog(tree, containingNode, gameObj); } else { printf("No node found to relocate\n"); } } //Object was partially contained and now it is fully contained! else { printf("Object entered node\n"); //Update the status nodeStatus->collisionStatus = currentStatus; } } } //Move to next object in linked list current = current->next; } }
/// //Loads and parses a .OBJ file constructing and returning //the Mesh it defines // //TODO: Put in code for parsing materials and groups // //Parameters: // fPath: The filepath of the .obj file to load // //Returns: // A pointer to a newly allocated Mesh following the specifications of the given .OBJ file Mesh* Loader_LoadOBJFile(const char* fPath) { //Open file in read mode FILE* fp = fopen(fPath, "r"); //MAke sure file is open if (fp == NULL) { printf("Error opening file %s.\n", fPath); return NULL; } //File opened correctly, begin parsing //Create struct to wrap 3 component attributes struct VertexAttr3 { GLfloat x, y, z; }; //Create struct to wrap 2 component attributes struct VertexAttr2 { GLfloat x, y; }; DynamicArray* vertices = DynamicArray_Allocate(); //Vertex coordinates DynamicArray* texCoords = DynamicArray_Allocate(); //Texture coordinates DynamicArray* normals = DynamicArray_Allocate(); //Normal Vectors DynamicArray* triangles = DynamicArray_Allocate(); //Complete Triangles DynamicArray_Initialize(vertices, sizeof(struct VertexAttr3)); DynamicArray_Initialize(texCoords, sizeof(struct VertexAttr2)); DynamicArray_Initialize(normals, sizeof(struct VertexAttr3)); DynamicArray_Initialize(triangles, sizeof(struct Triangle)); //Create a Cstring to hold each line of text char type[3]; //char line[100]; //Loop until we reach the end of the file while (!feof(fp)) { //Get first (max 3) letters indicating information we are parsing //if(fscanf_s(fp, "%s", type, 3) == EOF) break; //Break if we read past the end of the file (less than 3 characters were left) if(fscanf(fp, "%s", type) == EOF) break; //If we are reading Vertices, Texture Coordinates, or Normals if (type[0] == 'v') { //Normals if (type[1] == 'n') { struct VertexAttr3 vn; fscanf(fp, " %f %f %f", &vn.x, &vn.y, &vn.z); DynamicArray_Append(normals, &vn); } //Texture coordinates else if (type[1] == 't') { struct VertexAttr2 vt; fscanf(fp, " %f %f", &vt.x, &vt.y); DynamicArray_Append(texCoords, &vt); } //Vertices else { struct VertexAttr3 v; fscanf(fp, " %f %f %f", &v.x, &v.y, &v.z); DynamicArray_Append(vertices, &v); } } //Else if we are reading Face information else if (type[0] == 'f') { int indices[3]; struct Triangle t; struct Vertex v; struct VertexAttr3* vAtt3; struct VertexAttr2* vAtt2; //For each vertex in the triangle for (int i = 0; i < 3; i++) { //Get the face info & the amount of info given int infoCount = fscanf(fp, " %d/%d/%d", indices, indices + 1, indices + 2); switch (infoCount) { case 3: //Grabbing normals if present vAtt3 = (struct VertexAttr3*)DynamicArray_Index(normals, (indices[2] - 1)); v.nx = vAtt3->x; v.ny = vAtt3->y; v.nz = vAtt3->z; case 2: //Grabbing texture coords if present vAtt2 = (struct VertexAttr2*)DynamicArray_Index(texCoords, (indices[1] - 1)); v.tx = vAtt2->x; v.ty = vAtt2->y; case 1: //Grabbing vertex position vAtt3 = (struct VertexAttr3*)DynamicArray_Index(vertices, (indices[0] - 1)); v.x = vAtt3->x; v.y = vAtt3->y; v.z = vAtt3->z; } //Store vertex in triangle t *(&(t.a) + i) = v; } //And add to triangles array DynamicArray_Append(triangles, &t); } //Else if we are reading a comment else if (type[0] == '#') { //REad until you get to a new line char c = '0'; while (c != '\n' && c != '\r') { c = fgetc(fp); } } //Else if we don't know what we're reading else { //Read until the next line char c = '0'; while (c != '\n' && c != '\r') { c = fgetc(fp); } } }//End of file reached fclose(fp); //File parsed, creating mesh Mesh* parsed = Mesh_Allocate(); Mesh_Initialize(parsed, (struct Triangle*)triangles->data, triangles->size, GL_STATIC_DRAW); DynamicArray_Free(vertices); DynamicArray_Free(normals); DynamicArray_Free(texCoords); DynamicArray_Free(triangles); return parsed; }