/// //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); }
/// //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); }
/// //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; } }
/// //Looks up a texture from he asset manager's internal buffer // //Parameters // key: The name of the texture to lookup // //Returns: // Pointer to the requested texture, or NULL if the texture was not found Texture* AssetManager_LookupTexture(char* key) { return (Texture*)HashMap_LookUp(assetBuffer->textureMap, key, strlen(key))->data; }
/// //Looks up a mesh from the asset manager's internal buffer // //Parameters: // key: Name of the mesh to lookup // //Returns: // Pointer to the requested mesh, or NULL if mesh was not found Mesh* AssetManager_LookupMesh(char* key) { return (Mesh*)HashMap_LookUp(assetBuffer->meshMap, key, strlen(key))->data; }