|
@@ -6,8 +6,12 @@
|
|
*
|
|
*
|
|
* Created by Manoël Trapier on 04/03/2021.
|
|
* Created by Manoël Trapier on 04/03/2021.
|
|
*/
|
|
*/
|
|
|
|
+#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdlib.h>
|
|
|
|
+#include <stdint.h>
|
|
|
|
+#include <string.h>
|
|
|
|
|
|
|
|
+#include <log.h>
|
|
#include <array.h>
|
|
#include <array.h>
|
|
#include <mesh.h>
|
|
#include <mesh.h>
|
|
|
|
|
|
@@ -62,8 +66,7 @@ void loadCubeMeshData()
|
|
{
|
|
{
|
|
int i;
|
|
int i;
|
|
|
|
|
|
- arrayEmpty(mesh.vertices);
|
|
|
|
- arrayEmpty(mesh.faces);
|
|
|
|
|
|
+ meshFree();
|
|
|
|
|
|
for(i = 0; i < N_CUBE_VERTICES; i++)
|
|
for(i = 0; i < N_CUBE_VERTICES; i++)
|
|
{
|
|
{
|
|
@@ -81,6 +84,274 @@ void loadCubeMeshData()
|
|
|
|
|
|
void meshFree()
|
|
void meshFree()
|
|
{
|
|
{
|
|
|
|
+ arrayEmpty(mesh.normalVertices);
|
|
|
|
+ arrayEmpty(mesh.textureVertices);
|
|
arrayFree(mesh.faces);
|
|
arrayFree(mesh.faces);
|
|
arrayFree(mesh.vertices);
|
|
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;
|
|
|
|
+}
|