aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjvech <jmvalenciae@unal.edu.co>2022-10-03 11:38:07 -0500
committerjvech <jmvalenciae@unal.edu.co>2022-10-03 11:38:07 -0500
commit8fad4fc153d162598e432ca5740c5ec401b46696 (patch)
tree32cdf567cb433397db9594202c7b15358e002eb2
parentfc8d7fed3ccdf0998a7b9809aa825f2d14876b29 (diff)
feat: obj file reading and rendering implemented
-rw-r--r--.gitignore2
-rw-r--r--Makefile6
-rw-r--r--TODO11
-rw-r--r--shaders/dummy.fsh7
-rw-r--r--shaders/dummy.vsh20
-rw-r--r--src/main.c287
-rw-r--r--src/obj.c293
-rw-r--r--src/obj.h26
-rw-r--r--src/shader.c4
9 files changed, 443 insertions, 213 deletions
diff --git a/.gitignore b/.gitignore
index 5b43945..53be119 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
objs/
mverse
tags
+models
+textures
diff --git a/Makefile b/Makefile
index f50f361..3895e4d 100644
--- a/Makefile
+++ b/Makefile
@@ -4,10 +4,10 @@ DLIBS := -lm $(shell pkg-config --libs glfw3 opengl glew)
INCLUDE := $(addprefix -I,./include)
OBJDIR = objs
SRCDIR = src
-OBJS = $(addprefix objs/,main.o shader.o linear.o)
+OBJS = $(addprefix objs/,main.o shader.o linear.o obj.o)
BIN = mverse
-all: build run
+all: build
$(OBJS): | $(OBJDIR)
@@ -15,7 +15,7 @@ $(OBJDIR):
mkdir ${OBJDIR}
$(OBJDIR)/%.o: $(SRCDIR)/%.c
- ${CC} -c $< -o $@ ${CFLAGS} ${INCLUDE}
+ ${CC} -g -c $< -o $@ ${CFLAGS} ${INCLUDE}
build: $(OBJS)
${CC} $^ -o ${BIN} ${DLIBS}
diff --git a/TODO b/TODO
index 192e084..b302590 100644
--- a/TODO
+++ b/TODO
@@ -3,12 +3,13 @@ General
? Try to implement it without external libraries
- Make a PNG image reader
-- Add 3D objects
- - define a format for 3D objects
- - Implement a function to load objects from a file
- - Render a set of vertices loaded from a file
+Obj
+- Load obj files
+ * Vertex coordinates, normals and textures
+ - read faces with more than 4 vertices
+- Render a set of vertices loaded from a file
+ - Add normal Support
-* Implement Camera movement
Linear
- Implement the Inverse function of mat4
diff --git a/shaders/dummy.fsh b/shaders/dummy.fsh
new file mode 100644
index 0000000..7d94f22
--- /dev/null
+++ b/shaders/dummy.fsh
@@ -0,0 +1,7 @@
+#version 330 core
+out vec4 FragColor;
+
+void main()
+{
+ FragColor = vec4(0.0f);
+}
diff --git a/shaders/dummy.vsh b/shaders/dummy.vsh
new file mode 100644
index 0000000..ab57a50
--- /dev/null
+++ b/shaders/dummy.vsh
@@ -0,0 +1,20 @@
+# version 330 core
+
+layout (location = 0) in vec3 aPos;
+layout (location = 1) in vec3 aNormal;
+layout (location = 2) in vec2 aTexCoords;
+
+uniform mat4 model, view, proj;
+uniform mat4 rotNormals;
+
+out vec3 FragPos;
+out vec3 Normal;
+out vec2 TexCoords;
+
+void main()
+{
+ gl_Position = proj * view * model * vec4(aPos, 1.0f);
+ //FragPos = vec3(model * vec4(aPos, 1.0));
+ //Normal = vec3(rotNormals * vec4(aNormal, 1.0));
+ //TexCoords = aTexCoords;
+}
diff --git a/src/main.c b/src/main.c
index 531a1df..01ac661 100644
--- a/src/main.c
+++ b/src/main.c
@@ -10,11 +10,12 @@
#include <GLFW/glfw3.h>
#define STB_IMAGE_IMPLEMENTATION
-#include <stb_image.h>
+#include "../include/stb_image.h"
#include "main.h"
#include "linear.h"
#include "shader.h"
+#include "obj.h"
struct Camera {
Vec3 position;
@@ -22,55 +23,15 @@ struct Camera {
Vec3 up;
};
-float vertices[] = {
- -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
- 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
- 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
- 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
- -0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
- -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-
- -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
- 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
- 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
- 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
- -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
- -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
-
- -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
- -0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
- -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
- -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
- -0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
- -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-
- 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
- 0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
- 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
- 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
- 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
- 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-
- -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
- 0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f,
- 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
- 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
- -0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
- -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
-
- -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
- 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
- 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
- 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
- -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
- -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f
-};
-
static void userError(const char *msg, const char *detail);
static void glfw_size_callback(GLFWwindow *window, int width, int height);
static void processInput(GLFWwindow *window);
static Mat4 processCameraInput(GLFWwindow *window, struct Camera *cameraObj, float deltaTime);
static unsigned int loadTexture(char const *path);
+static void meshSetUp(Mesh *mesh);
+static void meshDraw(unsigned int shader, Mesh mesh);
+
+static float cameraSpeed = 2.0;
void
userError(const char *msg, const char *detail)
@@ -107,7 +68,11 @@ processCameraInput(GLFWwindow *window, struct Camera *camObj, float deltaTime)
* Keyboard Input
*/
Vec3 tmp;
- float speed = 2.0f * deltaTime;
+ float speed = cameraSpeed * deltaTime;
+
+ if (glfwGetKey(window, GLFW_KEY_K)) cameraSpeed += 0.2;
+ if (glfwGetKey(window, GLFW_KEY_J)) cameraSpeed -= 0.2;
+
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {
// pos = pos + front * speed
tmp = linearVec3ScalarMulp(camObj->front, speed);
@@ -213,11 +178,57 @@ loadTexture(char const *path)
return textureID;
}
-int main()
+
+void
+meshSetUp(Mesh *mesh)
{
+ glGenVertexArrays(1, &(mesh->VAO));
+ glGenBuffers(1, &(mesh->VBO));
+ glGenBuffers(1, &(mesh->EBO));
+
+ glBindVertexArray(mesh->VAO);
+
+ glBindBuffer(GL_ARRAY_BUFFER, mesh->VBO);
+ glBufferData(GL_ARRAY_BUFFER, mesh->vertexSize * sizeof(Vertex), mesh->vertices, GL_STATIC_DRAW);
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->EBO);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, mesh->indexSize * sizeof(int), mesh->indices, GL_STATIC_DRAW);
+
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)0);
+
+ glEnableVertexAttribArray(1);
+ glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)offsetof(Vertex, normal));
+
+ glEnableVertexAttribArray(2);
+ glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)offsetof(Vertex, texCoords));
+
+ glBindVertexArray(0);
+}
+
+void
+meshDraw(unsigned int shader, Mesh mesh)
+{
+ glBindVertexArray(mesh.VAO);
+ glDrawElements(GL_TRIANGLES, mesh.indexSize, GL_UNSIGNED_INT, 0);
+ glBindVertexArray(0);
+}
+
+int main(int argc, char *argv[])
+{
+ Mesh *mesh;
GLFWwindow *window;
const char *glfwErrno;
+ if (argc == 2) mesh = objCreateMesh(argv[1]);
+ else if (argc == 1) mesh = objCreateMesh("-");
+ else return 1;
+
+ if (mesh == NULL) {
+ glfwTerminate();
+ userError("objCreateMesh Error", "NULL mesh returned");
+ }
+
if (!glfwInit()) {
glfwGetError(&glfwErrno);
glfwTerminate();
@@ -227,7 +238,7 @@ int main()
window = glfwCreateWindow(640, 480, "Mverse", NULL, NULL);
if (!window) {
glfwTerminate();
- userError("glfwCreateWindow() failed", "Can't create window");
+ userError("glfwCreateWindow() Error", "Can't create window");
}
glfwSetFramebufferSizeCallback(window, glfw_size_callback);
@@ -237,189 +248,59 @@ int main()
GLubyte glewErrno = glewInit();
if (glewErrno != GLEW_OK) {
glfwTerminate();
- userError("glewInit() failed", (const char *)glewGetErrorString(glewErrno));
+ userError("glewInit Error", (const char *)glewGetErrorString(glewErrno));
}
- glEnable(GL_DEPTH_TEST);
- stbi_set_flip_vertically_on_load(1);
-
- unsigned int programColor = shaderCreateProgram("shaders/color.vsh",
- "shaders/color.fsh");
- unsigned int programLight = shaderCreateProgram("shaders/lightsource.vsh",
- "shaders/lightsource.fsh");
- unsigned int VBO, VAO, lightVAO;
- int vertexSize = 8;
-
- glGenVertexArrays(1, &VAO);
- glGenBuffers(1, &VBO);
-
- glBindBuffer(GL_ARRAY_BUFFER, VBO);
- glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
-
- glBindVertexArray(VAO);
-
- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, vertexSize * sizeof(float), (void *)0);
- glEnableVertexAttribArray(0);
-
- glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, vertexSize * sizeof(float), (void *)(3 * sizeof(float)));
- glEnableVertexAttribArray(1);
-
- glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, vertexSize * sizeof(float), (void *)(6 * sizeof(float)));
- glEnableVertexAttribArray(2);
-
- glBindVertexArray(lightVAO);
-
- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, vertexSize * sizeof(float), (void *)0);
- glEnableVertexAttribArray(0);
-
- unsigned int diffuseMap = loadTexture("textures/container2.png");
- unsigned int specularMap = loadTexture("textures/container2_specular.png");
-
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindVertexArray(0);
+ unsigned int shader = shaderCreateProgram("shaders/dummy.vsh", "shaders/dummy.fsh");
- /*============ Initializations ===============*/
-
- Vec3 cubePositions[] = {
- linearVec3( 0.5f, 0.0f, 0.0f),
- linearVec3( 2.0f, 5.0f, -15.0f),
- linearVec3(-1.5f, -2.2f, -2.5f),
- linearVec3(-3.8f, -2.0f, -12.3f),
- linearVec3( 2.4f, -0.4f, -3.5f),
- linearVec3(-1.7f, 3.0f, -7.5f),
- linearVec3( 1.3f, -2.0f, -2.5f),
- linearVec3( 1.5f, 2.0f, -2.5f),
- linearVec3( 1.5f, 0.2f, -1.5f),
- linearVec3(-1.3f, 1.0f, -1.5f)
- };
-
- Vec3 pointLightsPos[4] = {
- linearVec3(0.7f, 0.2f, 2.0f),
- linearVec3(2.3f, -3.3f, -4.0f),
- linearVec3(-4.0f, 2.0f, -12.0f),
- linearVec3(0.0f, 0.0f, -3.0f),
- };
+ meshSetUp(mesh);
struct Camera mainCamera;
- mainCamera.position = linearVec3(0.0, 0.0, 3.0);
+ mainCamera.position = linearVec3(0.0, 0.0, 10.0);
mainCamera.front = linearVec3(0.0, 0.0, -1.0);
mainCamera.up = linearVec3(0.0, 1.0, 0.0);
Mat4 model, view, proj;
Mat4 T, S, R;
-
- Vec3 dirLight = linearVec3(-0.2, -1.0, 0.3);
- Vec3 ambient = linearVec3(0.0, 0.0, 0.0);
- Vec3 diffuse = linearVec3(0.5, 0.5, 0.5);
- Vec3 specular = linearVec3(1.0, 1.0, 1.0);
- float dt, t, t0;
+ float t, t0, dt;
int width, height;
t0 = 0;
+
+ glEnable(GL_DEPTH_TEST);
while (!glfwWindowShouldClose(window)) {
processInput(window);
-
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glfwGetWindowSize(window, &width, &height);
- /* -------------------
- * frame calculations
- * ------------------*/
t = (float)glfwGetTime();
dt = t - t0;
t0 = t;
-
view = processCameraInput(window, &mainCamera, dt);
- glfwGetWindowSize(window, &width, &height);
proj = linearPerspective(35, (float)width / height, 0.1, 100);
+ T = linearTranslate(0.0, 0.0, 0.0);
+ R = linearRotate(0, 1.0, 0.0, 0.0);
+ S = linearScale(0.6, 0.6, 0.6);
+ model = linearMat4Muln(3, T, R, S);
- glUseProgram(programColor);
-
- float constant = 1.0;
- float linear = 0.09;
- float quadratic = 0.032f;
-
- shaderSetfv(programColor, "dirLight.direction", dirLight.vector, glUniform3fv);
- shaderSetfv(programColor, "dirLight.ambient", ambient.vector, glUniform3fv);
- shaderSetfv(programColor, "dirLight.diffuse", diffuse.vector, glUniform3fv);
- shaderSetfv(programColor, "dirLight.specular", vec3(1.0, 1.0, 1.0), glUniform3fv);
-
- char varNames[7][50];
- for (int i = 0; i < 4; i++) {
- sprintf(varNames[0], "pointLight[%d].position", i);
- sprintf(varNames[1], "pointLight[%d].ambient", i);
- sprintf(varNames[2], "pointLight[%d].diffuse", i);
- sprintf(varNames[3], "pointLight[%d].specular", i);
- sprintf(varNames[4], "pointLight[%d].constant", i);
- sprintf(varNames[5], "pointLight[%d].linear", i);
- sprintf(varNames[6], "pointLight[%d].quadratic", i);
-
- shaderSetfv(programColor, varNames[0], pointLightsPos[i].vector, glUniform3fv);
- shaderSetfv(programColor, varNames[1], ambient.vector, glUniform3fv);
- shaderSetfv(programColor, varNames[2], diffuse.vector, glUniform3fv);
- shaderSetfv(programColor, varNames[3], specular.vector, glUniform3fv);
- shaderSet1f(programColor, varNames[4], constant);
- shaderSet1f(programColor, varNames[5], linear);
- shaderSet1f(programColor, varNames[6], quadratic);
- }
-
- shaderSetfv(programColor, "flashLight.position", mainCamera.position.vector, glUniform3fv);
- shaderSetfv(programColor, "flashLight.direction", mainCamera.front.vector, glUniform3fv);
- shaderSetfv(programColor, "flashLight.ambient", ambient.vector, glUniform3fv);
- shaderSetfv(programColor, "flashLight.diffuse", vec3(0.8, 0.5, 0.5), glUniform3fv);
- shaderSetfv(programColor, "flashLight.specular", vec3(1.0, 0.0, 0.0), glUniform3fv);
- shaderSet1f(programColor, "flashLight.constant", constant);
- shaderSet1f(programColor, "flashLight.linear", linear);
- shaderSet1f(programColor, "flashLight.quadratic", quadratic);
- shaderSet1f(programColor, "flashLight.cutOff", cosf(12.5f * M_PI / 180));
- shaderSet1f(programColor, "flashLight.outerCutOff", cosf(17.5f * M_PI / 180));
-
- shaderSetfv(programColor, "viewPos", mainCamera.position.vector, glUniform3fv);
- shaderSetfv(programColor, "material.specular", vec3(0.5, 0.5, 0.5), glUniform3fv);
- shaderSet1f(programColor, "material.shininess", 64.0f);
- shaderSet1i(programColor, "material.diffuse", 0);
- shaderSet1i(programColor, "material.specular", 1);
-
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, diffuseMap);
- glActiveTexture(GL_TEXTURE1);
- glBindTexture(GL_TEXTURE_2D, specularMap);
-
- shaderSetMatrixfv(programColor, "view", view.matrix[0], glUniformMatrix4fv);
- shaderSetMatrixfv(programColor, "proj", proj.matrix[0], glUniformMatrix4fv);
- for (int i = 0; i < 10; i++) {
- // World Transformation
- // --------------------
- T = linearTranslatev(cubePositions[i]);
- R = linearRotate(180 * i / M_PI, 1.0, 0.3, 0.5);
- S = linearScale(1.0, 1.0, 1.0);
- model = linearMat4Muln(3, T, R, S);
- shaderSetMatrixfv(programColor, "model", model.matrix[0], glUniformMatrix4fv);
- shaderSetMatrixfv(programColor, "rotNormals", R.matrix[0], glUniformMatrix4fv);
-
- glBindVertexArray(VAO);
- glDrawArrays(GL_TRIANGLES, 0, sizeof(vertices) / sizeof(float));
- }
-
- /* -----------------
- * Light Source
- * -----------------*/
- for (int i = 0; i < 4; i++) {
- model = linearMat4Mul(linearTranslatev(pointLightsPos[i]),
- linearScale(0.2, 0.2, 0.2));
- glUseProgram(programLight);
- glBindVertexArray(lightVAO);
-
- shaderSetMatrixfv(programColor, "model", model.matrix[0], glUniformMatrix4fv);
- shaderSetMatrixfv(programColor, "view", view.matrix[0], glUniformMatrix4fv);
- shaderSetMatrixfv(programColor, "proj", proj.matrix[0], glUniformMatrix4fv);
- glDrawArrays(GL_TRIANGLES, 0, sizeof(vertices) / sizeof(float));
- }
+ glUseProgram(shader);
+
+ shaderSetMatrixfv(shader, "model", model.matrix[0], glUniformMatrix4fv);
+ shaderSetMatrixfv(shader, "proj", proj.matrix[0], glUniformMatrix4fv);
+ shaderSetMatrixfv(shader, "view", view.matrix[0], glUniformMatrix4fv);
+ shaderSetMatrixfv(shader, "rotNormals", R.matrix[0], glUniformMatrix4fv);
+
+ meshDraw(shader, mesh[0]);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
+
+ free(mesh->vertices);
+ free(mesh->indices);
+ free(mesh);
return 0;
}
diff --git a/src/obj.c b/src/obj.c
new file mode 100644
index 0000000..0f13fb4
--- /dev/null
+++ b/src/obj.c
@@ -0,0 +1,293 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "obj.h"
+
+enum ObjVertexType {
+ OBJ_V,
+ OBJ_VN,
+ OBJ_VT,
+ OBJ_F,
+ OBJ_OTHER
+};
+
+struct Setv3 {
+ float data[3];
+};
+
+struct Setv2 {
+ float data[2];
+};
+
+struct Seti {
+ int v, vn, vt;
+};
+
+static void readV3(char *line, struct Setv3 **v, int vIndex);
+static void readV2(char *line, struct Setv2 **vn, int vtIndex);
+static void readF(char *line, Mesh *mesh, struct Setv3 *v, struct Setv2 *vt, struct Setv3 *vn);
+static void vertexCount(FILE *, int *vSize, int *vtSize, int *vnSize);
+
+// ----------------------------------------------------------------------------
+static int readIndices(char *line, struct Seti *f);
+static Vertex createVertex(struct Seti f, struct Setv3 *v, struct Setv2 *vt, struct Setv3 *vn);
+static int vertexInVertices(Vertex vertex, Vertex *vertices, int nVertices);
+static void vertexAdd(Mesh *mesh, Vertex vertex);
+static int vertexGetIndex(Vertex *vertices, Vertex vertex, int nVertices);
+static void indexAdd(Mesh *mesh, int index);
+
+Mesh *
+objCreateMesh(const char *filename)
+{
+ Mesh *mesh;
+ char lineBuffer[OBJ_LINE_MAX_SIZE];
+ FILE *fi;
+
+ struct Setv3 *v, *vn;
+ struct Setv2 *vt;
+ int vSize, vtSize, vnSize;
+ vSize = vtSize = vnSize = 0;
+
+ fi = (!strcmp(filename, "-")) ? stdin : fopen(filename, "r");
+ mesh = (Mesh *)calloc(1, sizeof(Mesh));
+
+ // On error return NULL
+ if (fi == NULL || mesh == NULL) {
+ fprintf(stderr, "objCreateMesh() Error: %s\n", strerror(errno));
+ fclose(fi);
+ return NULL;
+ }
+
+ //vertexCount(fi, &vSize, &vtSize, &vnSize);
+ v = (struct Setv3 *)calloc(1, vSize * sizeof(struct Setv3));
+ vt = (struct Setv2 *)calloc(1, vtSize * sizeof(struct Setv2));
+ vn = (struct Setv3 *)calloc(1, vnSize * sizeof(struct Setv3));
+
+ /*
+ if (vSize == 0) {
+ fprintf(stderr, "objCreateMesh() Error: v components not found\n");
+ exit(1);
+ } else if (v == NULL) {
+ fprintf(stderr, "objCreateMesh() Error: %s\n", strerror(errno));
+ exit(1);
+ }
+ */
+
+ int vIndex, vtIndex, vnIndex;
+ vIndex = vtIndex = vnIndex = 0;
+ while (fgets(lineBuffer, OBJ_LINE_MAX_SIZE, fi)) {
+ if (!strncmp("f", lineBuffer, 1)) readF (lineBuffer + 1, mesh, v, vt, vn);
+ else if (!strncmp("vt", lineBuffer, 2)) readV2(lineBuffer + 2, &vt, vtIndex++);
+ else if (!strncmp("vn", lineBuffer, 2)) readV3(lineBuffer + 2, &vn, vnIndex++);
+ else if (!strncmp("v", lineBuffer, 1)) readV3(lineBuffer + 1, &v, vIndex++);
+
+ /*
+ if (vIndex > vSize) {
+ fprintf(stderr, "objCreateMesh() Error: v components exceeded the expected size\n");
+ exit(1);
+ } else if (vtIndex > vtSize) {
+ fprintf(stderr, "objCreateMesh() Error: vt components exceeded the expected size\n");
+ exit(1);
+ } else if (vtIndex > vnSize) {
+ fprintf(stderr, "objCreateMesh() Error: vn components exceeded the expected size\n");
+ exit(1);
+ }
+ */
+ }
+
+ free(v);
+ free(vt);
+ free(vn);
+ fclose(fi);
+
+ return mesh;
+}
+
+void
+vertexCount(FILE *fi, int *vSize, int *vtSize, int *vnSize)
+{
+ char line[OBJ_LINE_MAX_SIZE];
+ while (fgets(line, OBJ_LINE_MAX_SIZE, fi)) {
+ if (!strncmp("vt", line, 2)) (*vtSize)++;
+ else if (!strncmp("vn", line, 2)) (*vnSize)++;
+ else if (!strncmp("v", line, 1)) (*vSize)++;
+ }
+ fseek(fi, 0L, SEEK_SET);
+}
+
+void
+readF(char *line, Mesh *mesh, struct Setv3 *v, struct Setv2 *vt, struct Setv3 *vn)
+{
+ Vertex vertexBuffer;
+ struct Seti f[6];
+ int i, nIndices, vi;
+ nIndices = readIndices(line, f);
+
+ for (i = 0; i < nIndices; i++) {
+ vertexBuffer = createVertex(f[i], v, vt, vn);
+ if (!vertexInVertices(vertexBuffer, mesh->vertices, mesh->vertexSize))
+ vertexAdd(mesh, vertexBuffer);
+ vi = vertexGetIndex(mesh->vertices, vertexBuffer, mesh->vertexSize);
+ indexAdd(mesh, vi);
+ }
+}
+
+void
+readV3(char *line, struct Setv3 **v, int vIndex)
+{
+ int i, n;
+ char *ptr;
+ struct Setv3 *vptr;
+
+ if (vIndex > 0)
+ *v = (struct Setv3 *)realloc(*v, (vIndex + 1) * sizeof(struct Setv3));
+
+ vptr = *v;
+ for (i = 0, ptr = line, n = 0; i < 3; i++, ptr += n)
+ sscanf(ptr, " %f%n", vptr[vIndex].data + i, &n);
+}
+
+void
+readV2(char *line, struct Setv2 **v, int vIndex)
+{
+ int i, n;
+ char *ptr;
+ struct Setv2 *vptr;
+
+ if (vIndex > 0)
+ *v = (struct Setv2 *)realloc(*v, (vIndex + 1) * sizeof(struct Setv2));
+
+ vptr = *v;
+ for (i = 0, ptr = line, n = 0; i < 2; i++, ptr += n)
+ sscanf(line, " %f%n", vptr[vIndex].data + i, &n);
+}
+
+int
+readIndices(char *line, struct Seti *f)
+{
+ int i, n, fSize;
+ char *ptr;
+
+ for (ptr = line, i = n = fSize = 0; *ptr != '\n'; fSize++, ptr += n, i++) {
+ f[i].v = f[i].vt = f[i].vn = -1;
+ if ((sscanf(ptr, " %d/%d/%d%n", &f[i].v, &f[i].vn, &f[i].vt, &n) >= 3)) continue;
+
+ f[i].v = f[i].vt = f[i].vn = -1;
+ if ((sscanf(ptr, " %d//%d%n", &f[i].v, &f[i].vn, &n) >= 2)) continue;
+
+ f[i].v = f[i].vt = f[i].vn = -1;
+ if ((sscanf(ptr, " %d/%d%n", &f[i].v, &f[i].vt, &n) >= 2)) continue;
+
+ f[i].v = f[i].vt = f[i].vn = -1;
+ if ((sscanf(ptr, " %d%n", &f[i].v, &n) >= 1)) continue;
+
+ fprintf(stderr, "readIndices() Error: bad format on line '%s'\n", line - 1);
+ exit(1);
+ }
+
+ for (i = 0; i < fSize; i++) {
+ if (f[i].v > 0) f[i].v--;
+ if (f[i].vn > 0) f[i].vn--;
+ if (f[i].vt > 0 && i < 2) f[i].vt--;
+ }
+
+ if (fSize == 4) {
+ f[4].v = f[2].v;
+ f[4].vt = f[2].vt;
+ f[4].vn = f[2].vn;
+
+ f[5].v = f[0].v;
+ f[5].vt = f[0].vt;
+ f[5].vn = f[0].vn;
+ fSize += 2;
+ }
+ return fSize;
+}
+
+Vertex
+createVertex(struct Seti f, struct Setv3 *v, struct Setv2 *vt, struct Setv3 *vn)
+{
+ int i;
+ Vertex out = {.position = {0, 0, 0}, .normal = {0, 0, 0}, .texCoords = {0, 0}};
+ for (i = 0; i < 3; i++) {
+ if (f.v != -1) out.position[i] = v[f.v].data[i];
+ if (f.vn != -1) out.normal[i] = vn[f.vn].data[i];
+ if (f.vt != -1 && i < 2) out.texCoords[i] = vt[f.vt].data[i];
+ }
+ return out;
+}
+
+int
+vertexInVertices(Vertex vertex, Vertex *vertices, int nVertices)
+{
+ return vertexGetIndex(vertices, vertex, nVertices) + 1;
+}
+
+int
+vertexGetIndex(Vertex *vertices, Vertex vertex, int nVertices) {
+ int i, j, n;
+ for (i = 0; i < nVertices; i++) {
+ n = 0;
+ for (j = 0; j < 3; j++) {
+ if (vertices[i].position[j] == vertex.position[j]) n++;
+ if (vertices[i].normal[j] == vertex.normal[j]) n++;
+ }
+ for (j = 0; j < 2; j++) {
+ if (vertices[i].texCoords[j] == vertex.texCoords[j]) n++;
+ }
+
+ if (n == 8) return i;
+ }
+ return -1;
+}
+
+void
+vertexAdd(Mesh *mesh, Vertex vertex)
+{
+ Vertex *v;
+ int i;
+ unsigned int vSize;
+
+ v = mesh->vertices;
+ vSize = mesh->vertexSize;
+
+ if (!vSize) v = (Vertex *)calloc(1, sizeof(Vertex));
+ else v = (Vertex *)realloc(v, (vSize + 1) * sizeof(Vertex));
+
+ if (v == NULL) {
+ fprintf(stderr, "vertexAdd() Error: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ for (i = 0; i < 3; i++) {
+ v[vSize].position[i] = vertex.position[i];
+ v[vSize].normal[i] = vertex.normal[i];
+ if (i < 2)
+ v[vSize].texCoords[i] = vertex.texCoords[i];
+ }
+ mesh->vertices = v;
+ mesh->vertexSize++;
+}
+
+void
+indexAdd(Mesh *mesh, int index)
+{
+ unsigned int *iv, iSize;
+
+ iv = mesh->indices;
+ iSize = mesh->indexSize;
+
+ if (!iSize) iv = (unsigned int *)calloc(1, sizeof(int));
+ else iv = (unsigned int *)realloc(iv, (iSize + 1) * sizeof(int));
+
+ if (iv == NULL) {
+ fprintf(stderr, "vertexAdd() Error: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ iv[iSize] = index;
+ mesh->indices = iv;
+ mesh->indexSize++;
+}
diff --git a/src/obj.h b/src/obj.h
new file mode 100644
index 0000000..864910f
--- /dev/null
+++ b/src/obj.h
@@ -0,0 +1,26 @@
+# ifndef __OBJ__
+#define __OBJ__
+
+#define OBJ_LINE_MAX_SIZE 1024
+
+typedef struct {
+ float position[3];
+ float normal[3];
+ float texCoords[2];
+} Vertex;
+
+typedef struct {
+ unsigned int id;
+ char type[50];
+} Texture;
+
+typedef struct {
+ Vertex *vertices;
+ Texture *textures;
+ unsigned int *indices;
+ unsigned int indexSize, vertexSize;
+ unsigned int VAO, EBO, VBO;
+} Mesh;
+
+Mesh * objCreateMesh(const char *filename);
+# endif
diff --git a/src/shader.c b/src/shader.c
index efc4844..2156490 100644
--- a/src/shader.c
+++ b/src/shader.c
@@ -7,8 +7,8 @@ static char *getShaderSource(const char *shaderPath);
static void checkShaderCompile(unsigned int shader, const char *shaderPath);
static void checkProgramLink(unsigned int shader);
-char
-*getShaderSource(const char *shaderPath)
+char *
+getShaderSource(const char *shaderPath)
{
long fileSize;
char *shaderSource;
Feel free to download, copy and edit any repo