/// //Initializes an oct tree node to the given specifications // //Parameters: // node: A pointer to the oct tree node to initialize // tree: A pointer to the oct tree this node is part of // parent: A pointer to the parent node of this oct tree node // depth: The depth from the root node of this node in the oct tree // leftBound: The left bound of the octtree // rightBound: The right bound of the octtree // bottomBound: The bottom bound of the octtree // topBound: The top bound of the octtree // backBound: The back bound of the octtree // frontBound: The front bound of the octtree static void OctTree_Node_Initialize(struct OctTree_Node* node, OctTree* tree, struct OctTree_Node* parent, unsigned int depth, float leftBound, float rightBound, float bottomBound, float topBound, float backBound, float frontBound) { //Set relative nodes node->children = NULL; node->parent = parent; //Create data array node->data = DynamicArray_Allocate(); //Set a max capacity of the dynamic array to the max occupancy of the oct tree node->data->capacity = tree->maxOccupancy; DynamicArray_Initialize(node->data, sizeof(GObject*)); //Set depth node->depth = depth; //Set bounds node->left = leftBound; node->right = rightBound; node->bottom = bottomBound; node->top = topBound; node->back = backBound; node->front = frontBound; }
/// //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); } } }
/// //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; }
/// //Initializes a HashMap // //Parameters: // map: Hashmap to initialize void HashMap_Initialize(HashMap* map, unsigned int capacity) { map->data = DynamicArray_Allocate(); DynamicArray_Initialize(map->data, sizeof(struct HashMap_KeyValuePair*)); map->Hash = Hash_SDBM; }