Browse Source

Started working on parsing OBJ Files.

Why string manipulation is so tedious in C/++ :(
Godzil 4 years ago
parent
commit
c17bfadc76

+ 1 - 1
source/canvas.cpp

@@ -107,7 +107,7 @@ Canvas::Canvas(const char *imgfile)
         }
         else
         {
-            printf("ERROR: Can't opening the file '%s'.\n", imgfile);
+            printf("ERROR: Can't open/find the file '%s'.\n", imgfile);
         }
     }
     else

+ 51 - 0
source/include/objfile.h

@@ -0,0 +1,51 @@
+/*
+ *  DoRayMe - a quick and dirty Raytracer
+ *  OBJ File header
+ *
+ *  Created by Manoël Trapier
+ *  Copyright (c) 2020 986-Studio.
+ *
+ */
+#ifndef DORAYME_OBJFILE_H
+#define DORAYME_OBJFILE_H
+
+#include <shape.h>
+#include <renderstat.h>
+
+class OBJFile : public Shape
+{
+private:
+    uint32_t allocatedFaceGroupCount;
+    Shape* *faceGroupList;
+    uint32_t faceGroupCount;
+
+    uint32_t allocatedVertexCount;
+    Tuple* *vertexList;
+    uint32_t vertexCount;
+
+
+private:
+    Intersect localIntersect(Ray r);
+    Tuple localNormalAt(Tuple point);
+
+public:
+    /* Some stats */
+    uint32_t ignoredLines;
+
+protected:
+    void addGroup(Shape *group);
+    void addVertex(Tuple *vertex);
+
+    BoundingBox bounds;
+
+public:
+    OBJFile();
+    OBJFile(const char *filepath);
+
+    int parseOBJFile(const char *content);
+
+    BoundingBox getLocalBounds();
+    bool haveFiniteBounds() { return true; };
+};
+
+#endif /* DORAYME_OBJFILE_H */

+ 6 - 3
source/include/renderstat.h

@@ -15,13 +15,14 @@ class RenderStats
 {
 private:
     uint64_t coneCount;                  /* Total number of cones    */
-    uint64_t cylinderCount;              /* Total number of cylinder    */
+    uint64_t cylinderCount;              /* Total number of cylinder */
     uint64_t cubeCount;                  /* Total number of cubes    */
     uint64_t groupCount;                 /* Total number of groups   */
     uint64_t lightCount;                 /* Total number of light    */
     uint64_t planeCount;                 /* Total number of plane    */
     uint64_t sphereCount;                /* Total number of sphere   */
-    uint64_t triangleCount;               /* Total number of triangle */
+    uint64_t triangleCount;              /* Total number of triangle */
+    uint64_t objfileCount;               /* Total number of OBJ File */
 
     uint64_t pixelCount;                 /* Total number of rendered pixels */
     uint64_t rayCount;                   /* Total number of rays */
@@ -40,7 +41,7 @@ public:
     RenderStats() : coneCount(0), cylinderCount(0), cubeCount(0), groupCount(0), lightCount(0), planeCount(0), sphereCount(0), triangleCount(0),
                     pixelCount(0), rayCount(0), lightRayEmitedCount(0), reflectionRayCount(0), refractedRayCount(0),
                     intersectCount(0), intersectionCount(0), reallocCallCount(0), mallocCallCount(0),
-                    discardedIntersectCount(0), maxDepthAttained(UINT64_MAX), maxIntersectOnARay(0) {};
+                    discardedIntersectCount(0), maxDepthAttained(UINT64_MAX), maxIntersectOnARay(0), objfileCount(0) {};
 #ifdef RENDER_STATS
     void addCone();
     void addCylinder();
@@ -49,6 +50,7 @@ public:
     void addLight();
     void addPlane();
     void addSphere();
+    void addOBJFile();
     void addTriangle();
     void printStats();
     void addPixel();
@@ -85,6 +87,7 @@ public:
     static void addMalloc() {};
     static void addRealloc() {};
     static void setMaxIntersect(uint32_t count) {};
+    static void void RenderStats::addOBJFile() {};
 #endif
 };
 

+ 1 - 1
source/include/shape.h

@@ -29,7 +29,7 @@ enum ShapeType
     SHAPE_CONE,
     SHAPE_GROUP,
     SHAPE_TRIANGLE,
-
+    SHAPE_OBJFILE,
 };
 
 /* Base class for all object that can be presented in the world */

+ 6 - 0
source/renderstat.cpp

@@ -61,6 +61,12 @@ void RenderStats::addTriangle()
     this->triangleCount++;
 };
 
+void RenderStats::addOBJFile()
+{
+#pragma omp atomic
+    this->objfileCount++;
+};
+
 void RenderStats::addPixel()
 {
 #pragma omp atomic

+ 145 - 0
source/shapes/objfile.cpp

@@ -0,0 +1,145 @@
+/*
+ *  DoRayMe - a quick and dirty Raytracer
+ *  OBJ File implementation
+ *
+ *  Created by Manoël Trapier
+ *  Copyright (c) 2020 986-Studio.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <tuple.h>
+#include <ray.h>
+#include <shape.h>
+#include <objfile.h>
+#include <math_helper.h>
+#include <group.h>
+
+#define MIN_ALLOC (2)
+#define DEFAULT_GROUP (0)
+
+OBJFile::OBJFile() : Shape(SHAPE_OBJFILE), ignoredLines(0)
+{
+    stats.addOBJFile();
+
+    this->allocatedFaceGroupCount = MIN_ALLOC;
+    this->faceGroupList = (Shape **)calloc(sizeof(Shape *), MIN_ALLOC);
+    this->faceGroupCount = 0;
+
+    this->allocatedVertexCount = MIN_ALLOC;
+    this->vertexList = (Tuple **)calloc(sizeof(Tuple *), MIN_ALLOC);
+    this->vertexCount = 0;
+
+    /* There is always a default group */
+    this->addGroup(new Group());
+};
+
+OBJFile::OBJFile(const char *filepath) : OBJFile()
+{
+    FILE *fp;
+    size_t fileSize;
+    char *fileBuff;
+    fp = fopen(filepath, "rt");
+    if (fp)
+    {
+        fseek(fp, 0, SEEK_END);
+        fileSize = ftell(fp);
+        fileBuff = (char *)calloc(fileSize, 1);
+        fseek(fp, 0, SEEK_SET);
+        fileSize = fread(fileBuff, 1, fileSize, fp);
+        fclose(fp);
+
+        this->parseOBJFile(fileBuff);
+
+        free(fileBuff);
+    }
+    else
+    {
+        printf("ERROR: Can't open/find the file '%s'.\n", filepath);
+    }
+}
+
+void OBJFile::addGroup(Shape *group)
+{
+    if ((this->faceGroupCount + 1) > this->allocatedFaceGroupCount)
+    {
+        this->allocatedFaceGroupCount *= 2;
+        this->faceGroupList = (Shape **)realloc(this->faceGroupList, sizeof(Shape **) * this->allocatedFaceGroupCount);
+    }
+
+    group->parent = this;
+    group->updateTransform();
+
+    this->faceGroupList[this->faceGroupCount++] = group;
+
+    this->bounds | group->getBounds();
+}
+
+void OBJFile::addVertex(Tuple *vertex)
+{
+    if ((this->vertexCount + 1) > this->allocatedVertexCount)
+    {
+        this->allocatedVertexCount *= 2;
+        this->vertexList = (Tuple **)realloc(this->vertexList, sizeof(Tuple **) * this->allocatedVertexCount);
+    }
+
+    this->vertexList[this->vertexCount++] = vertex;
+}
+
+Intersect OBJFile::localIntersect(Ray r)
+{
+
+}
+
+Tuple OBJFile::localNormalAt(Tuple point)
+{
+
+}
+
+BoundingBox OBJFile::getLocalBounds()
+{
+
+}
+
+#define MAX_LINE_LENGTH (512)
+/* Here start the fun! */
+int OBJFile::parseOBJFile(const char *content)
+{
+    /* I don't think we will handle lines of more than 512 characters... */
+    char lineBuff[MAX_LINE_LENGTH];
+    uint32_t currentLineNum = 1;
+
+    /* Need to process line by line */
+    const char *bufferPos = content;
+    const char *lineNewline;
+    while(*bufferPos != '\0')
+    {
+        uint32_t lineLength;
+        lineNewline = strchr(bufferPos, '\n');
+        if (lineNewline == nullptr)
+        {
+            /* We are on the last line */
+            lineLength = strlen(bufferPos);
+        }
+        else
+        {
+            lineLength = (lineNewline - bufferPos);
+        }
+        if (lineLength >= MAX_LINE_LENGTH)
+        {
+            printf("ERROR: Line %d is too long! (%d)\n", currentLineNum);
+        }
+        memset(lineBuff, 0, MAX_LINE_LENGTH);
+        strncpy(lineBuff, bufferPos, lineLength);
+
+        printf("line %d = %s\n", currentLineNum, lineBuff);
+
+        bufferPos += lineLength + 1;
+        currentLineNum++;
+    }
+
+
+
+}

+ 21 - 1
tests/CMakeLists.txt

@@ -10,7 +10,7 @@ link_libraries(rayonnement)
 set(TESTS_SRC math_test.cpp tuple_test.cpp colour_test.cpp canvas_test.cpp matrix_test.cpp transformation_test.cpp
         ray_test.cpp intersect_test.cpp sphere_test.cpp light_test.cpp material_test.cpp world_test.cpp camera_test.cpp
         shape_test.cpp plane_test.cpp pattern_test.cpp cube_test.cpp cylinder_test.cpp cone_test.cpp group_test.cpp
-        boundingbox_test.cpp triangle_test.cpp sequence_test.cpp)
+        boundingbox_test.cpp triangle_test.cpp sequence_test.cpp objfile_test.cpp)
 
 add_executable(testMyRays)
 target_include_directories(testMyRays PUBLIC ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
@@ -100,6 +100,25 @@ add_custom_command(
         TARGET uvmap_earth POST_BUILD
         COMMAND convert ${CMAKE_SOURCE_DIR}/external/earthmap1k.jpg  ${CMAKE_CURRENT_BINARY_DIR}/earthmap1k.png)
 
+add_executable(uvmap_skybox)
+target_sources(uvmap_skybox PRIVATE uvmap_skybox.cpp)
+file(DOWNLOAD
+        http://www.humus.name/Textures/LancellottiChapel.zip
+        ${CMAKE_SOURCE_DIR}/external/LancellottiChapel.zip
+        EXPECTED_HASH MD5=cd16610b00a4ace6baf1f0aff80f5685
+        )
+add_custom_command(
+        TARGET uvmap_skybox POST_BUILD
+        COMMAND unzip -o ${CMAKE_SOURCE_DIR}/external/LancellottiChapel.zip -d LancellottiChapel
+        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/external/
+)
+add_custom_command(
+        TARGET uvmap_skybox POST_BUILD
+        COMMAND ${CMAKE_COMMAND} -E copy
+        ${CMAKE_SOURCE_DIR}/external/LancellottiChapel/*.jpg
+        ${CMAKE_CURRENT_BINARY_DIR}/
+)
+
 add_test(NAME Chapter05_Test COMMAND $<TARGET_FILE:ch5_test>)
 add_test(NAME Chapter06_Test COMMAND $<TARGET_FILE:ch6_test>)
 add_test(NAME Chapter07_Test COMMAND $<TARGET_FILE:ch7_test>)
@@ -119,6 +138,7 @@ add_test(NAME UVMap_CheckeredCylinder COMMAND $<TARGET_FILE:uvmap_checkeredcylin
 add_test(NAME UVMap_AlignCheckPlane COMMAND $<TARGET_FILE:uvmap_aligncheckplane>)
 add_test(NAME UVMap_CheckeredCube COMMAND $<TARGET_FILE:uvmap_checkeredcube>)
 add_test(NAME UVMap_Earth COMMAND $<TARGET_FILE:uvmap_earth>)
+add_test(NAME UVMap_Skybox COMMAND $<TARGET_FILE:uvmap_skybox>)
 add_test(NAME Test_Rendering COMMAND $<TARGET_FILE:test_render>)
 add_test(NAME Triangle_RenderTest COMMAND $<TARGET_FILE:triangle_rendertest>)
 add_test(NAME ChristmasBall_Rendering COMMAND $<TARGET_FILE:christmasball_render>)

+ 25 - 0
tests/objfile_test.cpp

@@ -0,0 +1,25 @@
+/*
+ *  DoRayMe - a quick and dirty Raytracer
+ *  OBJ File unit tests
+ *
+ *  Created by Manoël Trapier
+ *  Copyright (c) 2020 986-Studio.
+ *
+ */
+#include <objfile.h>
+#include <math.h>
+#include <gtest/gtest.h>
+
+TEST(OBJFileTest, Ignoring_unrecognised_lines)
+{
+    const char gibberish[] = "There was a young lane named Bright\n"
+                             "who traveled much faster than light\n"
+                             "She set out one day\n"
+                             "in a relative way\n"
+                             "and came back the previous night.\n";
+
+    OBJFile parser = OBJFile();
+    parser.parseOBJFile(gibberish);
+
+    ASSERT_EQ(parser.ignoredLines, 5);
+}