123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- /*
- * 3D Engine
- * mesh.c:
- * Based on pikuma.com 3D software renderer in C
- * Copyright (c) 2021 986-Studio. All rights reserved.
- *
- * 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>
- #define N_CUBE_VERTICES (8)
- extern vec3_t cubeVertices[N_CUBE_VERTICES];
- #define N_CUBE_FACES (6 * 2)
- extern face_t cubeFaces[N_CUBE_FACES];
- vec3_t cubeVertices[N_CUBE_VERTICES] =
- {
- [0] = { .x = -1, .y = -1, .z = -1},
- [1] = { .x = -1, .y = 1, .z = -1},
- [2] = { .x = 1, .y = 1, .z = -1},
- [3] = { .x = 1, .y = -1, .z = -1},
- [4] = { .x = 1, .y = 1, .z = 1},
- [5] = { .x = 1, .y = -1, .z = 1},
- [6] = { .x = -1, .y = 1, .z = 1},
- [7] = { .x = -1, .y = -1, .z = 1},
- };
- face_t cubeFaces[N_CUBE_FACES] =
- {
- /* Front */
- { .a = 1, .b = 2, .c = 3 },
- { .a = 1, .b = 3, .c = 4 },
- /* Right */
- { .a = 4, .b = 3, .c = 5 },
- { .a = 4, .b = 5, .c = 6 },
- /* Back */
- { .a = 6, .b = 5, .c = 7 },
- { .a = 6, .b = 7, .c = 8 },
- /* Left */
- { .a = 8, .b = 7, .c = 2 },
- { .a = 8, .b = 2, .c = 1 },
- /* Top */
- { .a = 2, .b = 7, .c = 5 },
- { .a = 2, .b = 5, .c = 3 },
- /* Bottom */
- { .a = 6, .b = 8, .c = 1 },
- { .a = 6, .b = 1, .c = 4 },
- };
- mesh_t mesh =
- {
- .vertices = NULL,
- .faces = NULL,
- .rotation = { 0, 0, 0 },
- };
- void loadCubeMeshData()
- {
- int i;
- meshFree();
- for(i = 0; i < N_CUBE_VERTICES; i++)
- {
- arrayAdd(mesh.vertices, cubeVertices[i]);
- }
- for(i = 0; i < N_CUBE_FACES; i++)
- {
- arrayAdd(mesh.faces, cubeFaces[i]);
- }
- mesh.rotation.x = 0;
- mesh.rotation.y = 0;
- mesh.rotation.z = 0;
- }
- 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;
- static uint32_t objFileLoaderLoadedVertices = 0;
- static uint32_t objFileLoaderLoadedVerticesNormal = 0;
- static uint32_t objFileLoaderLoadedVerticesTexture = 0;
- static uint32_t objFileLoaderLoadedFaces = 0;
- static uint32_t objFileLoaderTotalTri = 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;
- objFileLoaderLoadedVertices = 0;
- objFileLoaderLoadedVerticesNormal = 0;
- objFileLoaderLoadedVerticesTexture = 0;
- objFileLoaderLoadedFaces = 0;
- objFileLoaderTotalTri = 0;
- meshFree();
- if (objFileLoaderParser(fileBuff))
- {
- Log(TLOG_ERROR, "OBJLoader", "Errors occurred while opening the file '%s'.", filepath);
- }
- Log(TLOG_VERBOSE, "OBJLoader", "OBJ File '%s' loaded. Some stats:", filepath);
- Log(TLOG_VERBOSE, "OBJLoader", "Total ignored lines : %lu", objFileLoaderIgnoredLines);
- Log(TLOG_VERBOSE, "OBJLoader", "Number of vertices : %lu", objFileLoaderLoadedVertices);
- Log(TLOG_VERBOSE, "OBJLoader", "Number of normal vertices : %lu", objFileLoaderLoadedVerticesNormal);
- Log(TLOG_VERBOSE, "OBJLoader", "Number of texture vertices : %lu", objFileLoaderLoadedVerticesTexture);
- Log(TLOG_VERBOSE, "OBJLoader", "Number of faces in file : %lu", objFileLoaderLoadedFaces);
- Log(TLOG_VERBOSE, "OBJLoader", "Number of created triangles : %lu", objFileLoaderTotalTri);
- free(fileBuff);
- }
- else
- {
- Log(TLOG_ERROR, "OBJLoader", "Can't open/find the file '%s'.", 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!", currentLine);
- }
- else
- {
- vec3_t vertex = { atof(argv[1]), atof(argv[2]), atof(argv[3]) };
- arrayAdd(mesh.vertices, vertex);
- objFileLoaderLoadedVertices++;
- 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!", currentLine);
- }
- else
- {
- vec3_t vertex = { atof(argv[1]), atof(argv[2]), atof(argv[3]) };
- arrayAdd(mesh.normalVertices, vertex);
- objFileLoaderLoadedVerticesNormal++;
- ret = 0;
- }
- }
- else if (strncmp(argv[0], "vt", 3) == 0)
- {
- /* Vertice Normal entry */
- if ((argc < 3) || (argc > 4))
- {
- Log(TLOG_ERROR, "OBJLoader", "Malformed file at line %d: Vertices texture expect 2 or 3 parameters!", currentLine);
- }
- else
- {
- vec2_t vertex = { atof(argv[1]), atof(argv[2]) };
- arrayAdd(mesh.textureVertices, vertex);
- objFileLoaderLoadedVerticesTexture++;
- 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)
- {
- objFileLoaderTotalTri++;
- objFileLoaderLoadedFaces++;
- face_t face = { v[1], v[2], v[3] };
- arrayAdd(mesh.faces, face);
- ret = 0;
- }
- else if (argc > 4)
- {
- objFileLoaderLoadedFaces++;
- /* This is not a triangle, so we need to fan it */
- for(i = 2; i < (argc - 1); i++)
- {
- face_t face = { v[1], v[i], v[i + 1] };
- arrayAdd(mesh.faces, face);
- objFileLoaderTotalTri++;
- }
- ret = 0;
- }
- else
- {
- Log(TLOG_ERROR, "OBJLoader", "Malformed file at line %d: Too few/many parameters!", 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!", currentLine);
- }
- }
- #endif
- return ret;
- }
|