From 15a861802a9667060851423368cee52294bddade Mon Sep 17 00:00:00 2001 From: Godzil Date: Mon, 9 Mar 2020 16:03:27 +0000 Subject: [PATCH] OBJFile now use group instead of it own list. Change the group function to find group by name, and now name group when needed, and change tests to use group name instead of number. Also now the default group is the base group, not a separate group. Bonus: Add a destructor to cleanup memory Added a function to get base group. OBJFile will still behave as a valid shape, but now we can skip it in the generated world by adding the base group instead. Code is now cleaner. --- source/include/objfile.h | 14 ++-- source/shapes/objfile.cpp | 131 +++++++++++++++++++------------------- tests/objfile_test.cpp | 15 +++-- 3 files changed, 86 insertions(+), 74 deletions(-) diff --git a/source/include/objfile.h b/source/include/objfile.h index 7cb3849..6d92988 100644 --- a/source/include/objfile.h +++ b/source/include/objfile.h @@ -18,9 +18,9 @@ class OBJFile : public Shape { private: - uint32_t allocatedFaceGroupCount; - Group* *faceGroupList; - uint32_t faceGroupCount; + Group *baseGroup; + + Group *currentGroup; uint32_t allocatedVertexCount; Point* *vertexList; @@ -51,16 +51,20 @@ public: OBJFile(); OBJFile(const char *filepath); + ~OBJFile(); + int parseOBJFile(const char *content); /* OBJ file expect the first vertice to be 1 and not 0 */ Point vertices(uint32_t i) { return *this->vertexList[i - 1]; }; Vector verticesNormal(uint32_t i) { return *this->vertexNormalList[i - 1]; }; - Group *groups(uint32_t i) { return this->faceGroupList[i]; }; + Group *groups(const char *groupName); Intersect intersect(Ray r); BoundingBox getLocalBounds(); BoundingBox getBounds(); + Shape *getBaseGroup() { return this->baseGroup; }; + bool includes(Shape *b); void updateBoundingBox(); @@ -69,4 +73,6 @@ public: void dumpMe(FILE * fp); }; +#define OBJ_DEFAULT_GROUP "_DefaultObjGroup_" + #endif /* DORAYME_OBJFILE_H */ diff --git a/source/shapes/objfile.cpp b/source/shapes/objfile.cpp index 6df1dac..976f7b3 100644 --- a/source/shapes/objfile.cpp +++ b/source/shapes/objfile.cpp @@ -26,23 +26,49 @@ OBJFile::OBJFile() : Shape(Shape::OBJFILE), ignoredLines(0) { stats.addOBJFile(); - this->allocatedFaceGroupCount = MIN_ALLOC; - this->faceGroupList = (Group **)calloc(sizeof(Group **), MIN_ALLOC); - this->faceGroupCount = 0; - this->allocatedVertexCount = MIN_ALLOC; this->vertexList = (Point **)calloc(sizeof(Point **), MIN_ALLOC); this->vertexCount = 0; - this->allocatedVertexNormalCount = MIN_ALLOC; this->vertexNormalList = (Vector **)calloc(sizeof(Vector **), MIN_ALLOC); this->vertexNormalCount = 0; - /* There is always a default group */ - this->addGroup(new Group()); + /* The base group */ + this->baseGroup = new Group(OBJ_DEFAULT_GROUP); + this->currentGroup = this->baseGroup; }; +OBJFile::~OBJFile() +{ + int i; + if (vertexCount > 0) + { + for(i = 0; i < vertexCount; i++) + { + delete this->vertexList[i]; + this->vertexList[i] = nullptr; + } + } + free(this->vertexList); + this->vertexList = nullptr; + + if (vertexNormalCount > 0) + { + for(i = 0; i < vertexNormalCount; i++) + { + delete this->vertexNormalList[i]; + this->vertexNormalList[i] = nullptr; + } + } + free(this->vertexNormalList); + this->vertexNormalList = nullptr; + + /* It is not our responsibility to clear the group object as this object may be destroyed before the + * render is done + */ +} + OBJFile::OBJFile(const char *filepath) : OBJFile() { FILE *fp; @@ -71,18 +97,13 @@ OBJFile::OBJFile(const char *filepath) : OBJFile() void OBJFile::addGroup(Group *group) { - if ((this->faceGroupCount + 1) > this->allocatedFaceGroupCount) - { - this->allocatedFaceGroupCount *= 2; - this->faceGroupList = (Group **)realloc(this->faceGroupList, sizeof(Group **) * this->allocatedFaceGroupCount); - } + this->baseGroup->addObject(group); group->parent = this; group->updateTransform(); - - this->faceGroupList[this->faceGroupCount++] = group; - this->bounds | group->getBounds(); + + this->currentGroup = group; } void OBJFile::addVertex(Point *vertex) @@ -107,44 +128,40 @@ void OBJFile::addVertexNormal(Vector *vertexNormal) this->vertexNormalList[this->vertexNormalCount++] = vertexNormal; } -Intersect OBJFile::intersect(Ray r) +Group *OBJFile::groups(const char *groupName) { - Intersect ret; - int i, j; - if (this->faceGroupCount > 0) + if (strncmp(groupName, this->baseGroup->getName(), strlen(groupName)) == 0) { - if (this->bounds.intesectMe(r)) + return this->baseGroup; + } + + int i; + for(i = 0; i < this->baseGroup->getObjectCount(); i++) + { + Shape *cur = (*this->baseGroup)[i]; + + if (cur->getType() == Shape::GROUP) { - for (i = 0 ; i < this->faceGroupCount ; i++) + Group *curGrp = (Group *)cur; + if (strncmp(groupName, curGrp->getName(), strlen(groupName)) == 0) { - Intersect xs = this->faceGroupList[i]->intersect(r); - if (xs.count() > 0) - { - for (j = 0 ; j < xs.count() ; j++) - { - ret.add(xs[j]); - } - } + return curGrp; } } } - return ret; + + /* Not found */ + return nullptr; +} + +Intersect OBJFile::intersect(Ray r) +{ + return this->baseGroup->intersect(r); } bool OBJFile::includes(Shape *b) { - int i; - if (this->faceGroupCount > 0) - { - for (i = 0 ; i < this->faceGroupCount ; i++) - { - if (this->faceGroupList[i] == b) - { - return true; - } - } - } - return false; + return this->baseGroup->includes(b); } Intersect OBJFile::localIntersect(Ray r) @@ -173,14 +190,7 @@ void OBJFile::updateBoundingBox() int i; this->bounds.reset(); - for(i = 0; i < this->faceGroupCount; i++) - { - if (this->faceGroupList[i]->haveFiniteBounds()) - { - BoundingBox objB = this->faceGroupList[i]->getBounds(); - this->bounds | objB; - } - } + this->bounds | this->baseGroup->getBounds(); } void OBJFile::updateTransform() @@ -188,10 +198,8 @@ void OBJFile::updateTransform() int i; Shape::updateTransform(); - for (i = 0 ; i < this->faceGroupCount ; i++) - { - this->faceGroupList[i]->updateTransform(); - } + + this->baseGroup->updateTransform(); /* Once the full stack being notified of the changes, let's update the * bounding box @@ -204,12 +212,7 @@ void OBJFile::dumpMe(FILE * fp) int i; fprintf(fp, "\"Type\": \"OBJFile\",\n"); fprintf(fp, "\"Objects\": {\n"); - for(i = 0; i < this->faceGroupCount; i++) - { - fprintf(fp, "\"%d\": {\n", i); - this->faceGroupList[i]->dumpMe(fp); - fprintf(fp, "},\n"); - } + this->baseGroup->dumpMe(fp); fprintf(fp, "},\n"); Shape::dumpMe(fp); @@ -399,7 +402,7 @@ int OBJFile::execLine(int argc, char *argv[], uint32_t currentLine) this->verticesNormal(vn[2]), this->verticesNormal(vn[3])); } - this->faceGroupList[this->faceGroupCount - 1]->addObject(t); + this->currentGroup->addObject(t); ret = 0; } else if (argc > 4) @@ -423,7 +426,7 @@ int OBJFile::execLine(int argc, char *argv[], uint32_t currentLine) this->verticesNormal(vn[i]), this->verticesNormal(vn[i + 1])); } - this->faceGroupList[this->faceGroupCount - 1]->addObject(t); + this->currentGroup->addObject(t); } ret = 0; } @@ -436,7 +439,7 @@ int OBJFile::execLine(int argc, char *argv[], uint32_t currentLine) { if (argc == 2) { - this->addGroup(new Group()); + this->addGroup(new Group(argv[1])); } else { @@ -444,4 +447,4 @@ int OBJFile::execLine(int argc, char *argv[], uint32_t currentLine) } } return ret; -} \ No newline at end of file +} diff --git a/tests/objfile_test.cpp b/tests/objfile_test.cpp index 49e2eef..ecae3cc 100644 --- a/tests/objfile_test.cpp +++ b/tests/objfile_test.cpp @@ -55,7 +55,7 @@ TEST(OBJFileTest, Parsing_triangle_faces) OBJFile parser = OBJFile(); parser.parseOBJFile(file); - Group *g0 = parser.groups(0); + Group *g0 = parser.groups(OBJ_DEFAULT_GROUP); Triangle *t1 = (Triangle *)(*g0)[0]; Triangle *t2 = (Triangle *)(*g0)[1]; @@ -82,7 +82,7 @@ TEST(OBJFileTest, Triangulating_polygons) OBJFile parser = OBJFile(); parser.parseOBJFile(file); - Group *g0 = parser.groups(0); + Group *g0 = parser.groups(OBJ_DEFAULT_GROUP); Triangle *t1 = (Triangle *)(*g0)[0]; Triangle *t2 = (Triangle *)(*g0)[1]; @@ -105,9 +105,12 @@ TEST(OBJFileTest, Triangle_in_groups) { OBJFile parser = OBJFile("triangles.obj"); - /* TODO: Add group name search/test */ - Group *g1 = parser.groups(1); - Group *g2 = parser.groups(2); + Group *g1 = parser.groups("FirstGroup"); + Group *g2 = parser.groups("SecondGroup"); + + /* The groups must exists */ + ASSERT_NE(g1, nullptr); + ASSERT_NE(g2, nullptr); Triangle *t1 = (Triangle *)(*g1)[0]; Triangle *t2 = (Triangle *)(*g2)[0]; @@ -151,7 +154,7 @@ TEST(OBJFileTest, Faces_with_normal) OBJFile parser = OBJFile(); parser.parseOBJFile(file); - Group *g0 = parser.groups(0); + Group *g0 = parser.groups(OBJ_DEFAULT_GROUP); SmoothTriangle *t1 = (SmoothTriangle *)(*g0)[0]; SmoothTriangle *t2 = (SmoothTriangle *)(*g0)[1];