Browse Source

Lesson 11.2

(Used my obj file parser from DoRayMe, modified to fit that project)
Godzil 3 years ago
parent
commit
b3b90b72c8
3 changed files with 283 additions and 7 deletions
  1. 7 3
      source/include/mesh.h
  2. 2 1
      source/main.c
  3. 274 3
      source/mesh.c

+ 7 - 3
source/include/mesh.h

@@ -18,10 +18,12 @@
  **********************************************************************************************************************/
 typedef struct mesh_t
 {
-    vec3_t *vertices;    /**< List of vertices */
-    face_t *faces;       /**< List of faces */
+    vec3_t *vertices;        /**< List of vertices */
+    vec3_t *normalVertices;  /**< List of normal vertices */
+    vec2_t *textureVertices; /**< List of texture vertices */
+    face_t *faces;           /**< List of faces */
 
-    vec3_t rotation;     /**< Rotation of the object */
+    vec3_t rotation;         /**< Rotation of the object */
 } mesh_t;
 
 
@@ -36,4 +38,6 @@ extern mesh_t mesh;
 void loadCubeMeshData();
 void meshFree();
 
+void loadOBJFile(const char *filepath);
+
 #endif /* THREEDENGINE_SOURCE_INCLUDE_MESH_H */

+ 2 - 1
source/main.c

@@ -51,7 +51,8 @@ void setup()
         goto exit;
     }
 
-    loadCubeMeshData();
+    //loadCubeMeshData();
+    loadOBJFile("assets/f22.obj");
 
 exit:
     return;

+ 274 - 3
source/mesh.c

@@ -6,8 +6,12 @@
  *
  * Created by Manoël Trapier on 04/03/2021.
  */
+#include <stdio.h>
 #include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
 
+#include <log.h>
 #include <array.h>
 #include <mesh.h>
 
@@ -62,8 +66,7 @@ void loadCubeMeshData()
 {
     int i;
 
-    arrayEmpty(mesh.vertices);
-    arrayEmpty(mesh.faces);
+    meshFree();
 
     for(i = 0; i < N_CUBE_VERTICES; i++)
     {
@@ -81,6 +84,274 @@ void loadCubeMeshData()
 
 void meshFree()
 {
+    arrayEmpty(mesh.normalVertices);
+    arrayEmpty(mesh.textureVertices);
     arrayFree(mesh.faces);
     arrayFree(mesh.vertices);
-}
+}
+
+/***********************************************************************************************************************
+ * OBJ File interpreter based on my project DoRayMe ( https://trac.godzil.net/Godzil/DoRayMe )
+ **********************************************************************************************************************/
+
+/* Function used to load OBJ files */
+static int objFileLoaderParser(const char *content);
+static void objFileLoaderLineParser(char *line, uint32_t currentLine);
+static int objFileLoaderExecuteLine(int argc, char *argv[], uint32_t currentLine);
+
+static uint32_t objFileLoaderIgnoredLines = 0;
+
+void loadOBJFile(const char *filepath)
+{
+    FILE *fp;
+    size_t fileSize;
+    char *fileBuff;
+    fp = fopen(filepath, "rt");
+    if (fp)
+    {
+        fseek(fp, 0, SEEK_END);
+        fileSize = ftell(fp);
+        /* Add one byte to the size to make sure it is null terminated */
+        fileBuff = (char *)calloc(fileSize + 1, 1);
+        fseek(fp, 0, SEEK_SET);
+        fileSize = fread(fileBuff, 1, fileSize, fp);
+        fclose(fp);
+
+        objFileLoaderIgnoredLines = 0;
+
+        meshFree();
+
+        if (objFileLoaderParser(fileBuff))
+        {
+            log(TLOG_ERROR, "OBJLoader", "Errors occurred while opening the file '%s'.\n", filepath);
+        }
+
+        free(fileBuff);
+    }
+    else
+    {
+        log(TLOG_ERROR, "OBJLoader", "Can't open/find the file '%s'.\n", filepath);
+    }
+}
+
+#define MAX_LINE_LENGTH (512)
+/* Here start the fun! */
+static int objFileLoaderParser(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;
+    uint32_t totalLength = strlen(content);
+    /* 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 == NULL)
+        {
+            /* We are on the last line */
+            lineLength = strlen(bufferPos);
+        }
+        else
+        {
+            lineLength = (lineNewline - bufferPos);
+        }
+        if (lineLength >= MAX_LINE_LENGTH)
+        {
+            log(TLOG_ERROR, "OBJLoader", "Line %d is too long! (%d)", currentLineNum, lineLength);
+            return -1;
+        }
+        memset(lineBuff, 0, MAX_LINE_LENGTH);
+        strncpy(lineBuff, bufferPos, lineLength);
+
+        objFileLoaderLineParser(lineBuff, currentLineNum);
+
+        bufferPos += lineLength + 1;
+
+        if ((bufferPos - content) >= totalLength)
+        {
+            /* We are past the length of the buffer, don't need to continue */
+            break;
+        }
+        currentLineNum++;
+    }
+    return 0;
+}
+
+#define MAX_ARGS (15)
+/* Parse the line into a couple ofr argc/argv using space as argument separator */
+static void objFileLoaderLineParser(char *line, uint32_t currentLine)
+{
+    char *argv[MAX_ARGS];
+    uint32_t argc = 0;
+
+    char *buffer = line;
+    uint32_t lineLength = strlen(line);
+    uint32_t linePos = 0;
+
+    /* First argument */
+    argv[argc++] = line;
+
+    while(linePos < lineLength)
+    {
+        char *next = strchr(buffer, ' ');
+        if (next != NULL)
+        {
+            *next = '\0';
+            linePos = next - line;
+            buffer = next + 1;
+            /* Skip empty strings as it mean multiple spaces */
+            if (strlen(buffer) > 0)
+            {
+                argv[argc++] = buffer;
+            }
+        }
+        else
+        {
+            linePos = lineLength;
+        }
+    }
+
+    if (objFileLoaderExecuteLine(argc, argv, currentLine))
+    {
+        objFileLoaderIgnoredLines++;
+    }
+}
+
+static int objFileLoaderParseFaceVertex(char *buf, uint32_t *v, uint32_t  *vt, uint32_t  *vn)
+{
+    uint32_t bufPos = 0;
+    uint32_t lineLength = strlen(buf);
+    *vt = INT32_MAX;
+    *vn = INT32_MAX;
+    int ret = 0;
+    int token = 0;
+
+    while (bufPos < lineLength)
+    {
+        char *next = strchr(buf, '/');
+        if (next != NULL)
+        {
+            *next = '\0';
+            bufPos = next - buf;
+        }
+        else
+        {
+            bufPos = lineLength;
+        }
+
+        if (strlen(buf) > 0)
+        {
+            switch (token)
+            {
+            case 0: *v = atol(buf); break;
+            case 1: *vt = atol(buf); break;
+            case 2: *vn = atol(buf); break;
+            default:
+                log(TLOG_ERROR, "OBJLoader", "Too many entry for a face vertex!");
+                ret = 1;
+                break;
+            }
+        }
+        buf = next + 1;
+        token++;
+    }
+
+    return ret;
+}
+
+/* Actually execute the line */
+int objFileLoaderExecuteLine(int argc, char *argv[], uint32_t currentLine)
+{
+    int ret = 1;
+    if (strncmp(argv[0], "v", 2) == 0)
+    {
+        /* Vertice entry */
+        if (argc != 4)
+        {
+            log(TLOG_ERROR, "OBJLoader", "Malformed file at line %d: Vertices expect 3 parameters!\n", currentLine);
+        }
+        else
+        {
+            vec3_t vertex = { atof(argv[1]), atof(argv[2]), atof(argv[3]) };
+            arrayAdd(mesh.vertices, vertex);
+            ret = 0;
+        }
+    }
+    else if (strncmp(argv[0], "vn", 3) == 0)
+    {
+        /* Vertice Normal entry */
+        if (argc != 4)
+        {
+            log(TLOG_ERROR, "OBJLoader", "Malformed file at line %d: Vertices normal expect 3 parameters!\n", currentLine);
+        }
+        else
+        {
+            vec3_t vertex = { atof(argv[1]), atof(argv[2]), atof(argv[3]) };
+            arrayAdd(mesh.normalVertices, vertex);
+            ret = 0;
+        }
+    }
+    else if (strncmp(argv[0], "vt", 3) == 0)
+    {
+        /* Vertice Normal entry */
+        if (argc != 3)
+        {
+            log(TLOG_ERROR, "OBJLoader", "Malformed file at line %d: Vertices normal expect 2 parameters!\n", currentLine);
+        }
+        else
+        {
+            vec2_t vertex = { atof(argv[1]), atof(argv[2]) };
+            arrayAdd(mesh.textureVertices, vertex);
+            ret = 0;
+        }
+    }
+    else if (strncmp(argv[0], "f", 2) == 0)
+    {
+        /* Faces entry */
+        int i;
+        uint32_t v[MAX_ARGS], vt[MAX_ARGS], vn[MAX_ARGS];
+        for(i = 1; i < argc; i++)
+        {
+            objFileLoaderParseFaceVertex(argv[i], &v[i], &vt[i], &vn[i]);
+        }
+
+        if (argc == 4)
+        {
+            face_t face = {v[1], v[2], v[3] };
+            arrayAdd(mesh.faces, face);
+            ret = 0;
+        }
+        else if (argc > 4)
+        {
+            /* This is not a triangle, so we need to fan it */
+            for(i = 2; i < (argc - 1); i++)
+            {
+                face_t face = {v[1], v[2], v[3] };
+                arrayAdd(mesh.faces, face);
+            }
+            ret = 0;
+        }
+        else
+        {
+            log(TLOG_ERROR, "OBJLoader", "Malformed file at line %d: Too few/many parameters!\n", currentLine);
+        }
+    }
+    /* We ignore groups for now, may use it later. */
+#if 0
+    else if (strncmp(argv[0], "g", 2) == 0)
+    {
+        if (argc == 2)
+        {
+            this->addGroup(new Group(argv[1]));
+        }
+        else
+        {
+            log(TLOG_ERROR, "OBJLoader", "Malformed file at line %d: Too few/many parameters!\n", currentLine);
+        }
+    }
+#endif
+    return ret;
+}