ported the University CGI demo from WINDOWS + GLUT + GLEW + GLU + OpenGL 4 to LINUX WAYLAND + EGL + GLES 2 with minimal cuts

This commit is contained in:
beno
2025-07-03 01:26:25 +02:00
commit 6c125fb35e
85 changed files with 91688 additions and 0 deletions

203
GL_STUFF/SOURCES/SCENE/Camera.cpp Executable file
View File

@@ -0,0 +1,203 @@
#define GLM_ENABLE_EXPERIMENTAL
#include "../../HEADERS/SCENE/Camera.hpp"
/* REPLACED
#include <GL/freeglut.h>
*/
extern "C" {
#include <glut.h>
}
#include <glm/gtc/matrix_transform.hpp>
#include <string>
#include <iostream>
#include <glm/gtx/transform.hpp>
#include <glm/gtx/norm.hpp>
/* don't know how it worked before */
#include <glm/gtx/quaternion.hpp>
/* aarch64-linux-gnu/include/math.h already defines it */
#ifndef M_PI
#define M_PI 3.14159265358979323846264338327950288
#endif
using namespace glm;
Camera::Camera() {
this->cameraPos = vec3();
this->cameraFront = vec3(0.0f, 0.0f, -1.0f);
this->cameraUp = vec3(0.0f, 1.0f, 0.0f);
}
Camera::Camera(vec3 position, vec3 front, vec3 up) {
if (! glm::length(front))
throw std::invalid_argument("Camera : front vector has no length");
if (! glm::length(up))
throw std::invalid_argument("Camera : up vector has no length");
this->cameraPos = position;
this->cameraFront = front;
this->cameraUp = up;
}
glm::mat4 Camera::getViewMat() {
return lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
}
glm::vec3 Camera::getPosition() {
return cameraPos;
}
void Camera::setPosition(glm::vec3 pos) {
cameraPos = pos;
}
void Camera::alignTo(glm::vec3 direction) {
glm::vec3 localZ;
direction = glm::normalize(direction);
localZ = cameraFront;
glm::quat a = glm::rotation(localZ, direction);
cameraFront = glm::toMat4(a) * glm::vec4(cameraFront, 0.0f);
cameraUp = glm::toMat4(a) * glm::vec4(cameraUp, 0.0f); //temp
// ++++++++++++++++++++++++++ //
glm::vec3 right = glm::normalize(cross(cameraFront, cameraUp));
right.y = 0;
glm::vec3 stabilizedR = glm::normalize(right);
cameraUp = glm::cross(stabilizedR, cameraFront);
}
CameraController::CameraController(Camera *cam) {
lastX = 0;
lastY = 0;
windowHeight = 0;
windowWidth = 0;
windowTop = 0;
windowLeft = 0;
this->camera = cam;
}
Camera* CameraController::getCamera() {
return camera;
}
void CameraController::setWindowData(int left, int width, int top, int height) {
windowLeft = left;
windowWidth = width;
windowTop = top;
windowHeight = height;
lastX = left + width / 2;
lastY = top + height / 2;
}
void CameraController::mouseMotion(int cursorX, int cursorY) {
//return;
float alfa = 0.05; //serve ridimensionare l'offset tra due posizioni successive del mouse
//il mouse è appena entrato nella finestra
if (mouseUnlocked)
{
lastX = windowLeft + windowWidth / 2;
lastY = windowTop + windowHeight / 2;
mouseUnlocked = false;
}
//di quanto ci siamo mossi
float xoffset = (cursorX - lastX);
float yoffset = (lastY - cursorY);
glutWarpPointer(windowLeft + windowWidth / 2, windowTop + windowHeight / 2);
lastX = windowLeft + windowWidth / 2;
lastY = windowTop + windowHeight / 2;
xoffset *= alfa;
yoffset *= alfa;
PHI += yoffset;
THETA += xoffset;
//if (PHI >= 179.0)
// PHI = 179;
vec3 direction;
direction.x = cos(radians(PHI)) * cos(radians(THETA));
direction.y = sin(radians(PHI));
direction.z = cos(radians(PHI)) * sin(radians(THETA));
getCamera()->cameraFront = normalize(direction);
}
void CameraController::keyPress(unsigned char key) {
Camera *c = getCamera();
vec3 dir;
switch (key)
{
case 'a':
//Calcolo la direzione perpendicolare alla direzione della camera e l'alto della camera
dir = normalize(cross(getCamera()->cameraFront, getCamera()->cameraUp));
//Mi sposto a sinistra lungo la direzione perpendicolare alla direzione della camera e l'alto della camera
c->cameraPos = c->cameraPos - dir * cameraSpeed;
break;
case 'A':
//Calcolo la direzione perpendicolare alla direzione della camera e l'alto della camera
dir = normalize(cross(c->cameraFront, c->cameraUp));
//Mi sposto a sinistra lungo la direzione perpendicolare alla direzione della camera e l'alto della camera
c->cameraPos = c->cameraPos - dir * (cameraSpeed * 10);
break;
case 'd':
//Calcolo la irezione perpendicolare alla direzione della camera e l'alto della camera
dir = normalize(cross(c->cameraFront, c->cameraUp));//Mi sposto a destra lungo la direzione perpendicolare alla direzione della camera e l'alto della camera
c->cameraPos = c->cameraPos + dir * cameraSpeed;
break;
case 'D':
//Calcolo la irezione perpendicolare alla direzione della camera e l'alto della camera
dir = normalize(cross(c->cameraFront, c->cameraUp));//Mi sposto a destra lungo la direzione perpendicolare alla direzione della camera e l'alto della camera
c->cameraPos = c->cameraPos + dir * (cameraSpeed * 10);
break;
case 's':
//Mi sposto indietro lungo la direzione della camera
c->cameraPos = c->cameraPos - cameraSpeed * c->cameraFront;
break;
case 'S':
//Mi sposto indietro lungo la direzione della camera
c->cameraPos = c->cameraPos - (cameraSpeed * 10) * c->cameraFront;
break;
case 'w':
//Mi sposto avanti lungo la direzione perpendicolare alla direzione della camera e l'alto della camera
c->cameraPos = c->cameraPos + cameraSpeed * c->cameraFront;
break;
case 'W':
//Mi sposto avanti lungo la direzione perpendicolare alla direzione della camera e l'alto della camera
c->cameraPos = c->cameraPos + (cameraSpeed * 10) * c->cameraFront;
break;
case 'r':
//Mi sposto avanti lungo la direzione perpendicolare alla direzione della camera e l'alto della camera
c->cameraPos = c->cameraPos + cameraSpeed * c->cameraUp;
break;
case 'R':
//Mi sposto avanti lungo la direzione perpendicolare alla direzione della camera e l'alto della camera
c->cameraPos = c->cameraPos + (cameraSpeed * 10) * c->cameraUp;
break;
case 'f':
//Mi sposto avanti lungo la direzione perpendicolare alla direzione della camera e l'alto della camera
c->cameraPos = c->cameraPos - cameraSpeed * c->cameraUp;
break;
case 'F':
//Mi sposto avanti lungo la direzione perpendicolare alla direzione della camera e l'alto della camera
c->cameraPos = c->cameraPos - (cameraSpeed * 10) * c->cameraUp;
break;
default:
break;
}
}

View File

@@ -0,0 +1,21 @@
#include "../../HEADERS/SCENE/Instance3D.h"
Instance3D::Instance3D(Model3D* mesh, vec3 position) : WorldInstanceable{ position } {
this->mesh = mesh;
}
Instance3D::Instance3D(Model3D* mesh, vec3 position, vec3 scale) : WorldInstanceable{ position , scale } {
this->mesh = mesh;
}
Instance3D::Instance3D(Model3D* mesh, vec3 position, vec3 axis, float angle) : WorldInstanceable{ position, axis, angle } {
this->mesh = mesh;
}
Instance3D::Instance3D(Model3D* mesh, vec3 position, vec3 scale, vec3 axis, float angle) : WorldInstanceable { position, scale, axis, angle } {
this->mesh = mesh;
}
Model3D* Instance3D::getModel() {
return this->mesh;
}

View File

@@ -0,0 +1,85 @@
#include <regex>
#include <iostream>
#include <sstream>
#include "../../HEADERS/SCENE/InstancesLoader.h"
char lineHeader[128];
char* res;
FILE* file;
std::smatch pieces;
Instance3D* parseInstanceData(Model3D* model, string str) {
vector<float> vecComponents = vector<float>();
std::regex regex("-?\\d+.\\d+");
std::regex_search(str, pieces, regex);
float x = stof(pieces[0], NULL); //potevi evitare la regex
str = pieces.suffix().str();
std::regex_search(str, pieces, regex);
float y = stof(pieces[0], NULL); //potevi evitare la regex
str = pieces.suffix().str();
std::regex_search(str, pieces, regex);
float z = stof(pieces[0], NULL); //potevi evitare la regex
str = pieces.suffix().str();
std::regex_search(str, pieces, regex);
float rotx = stof(pieces[0], NULL); //potevi evitare la regex
str = pieces.suffix().str();
std::regex_search(str, pieces, regex);
float roty = stof(pieces[0], NULL); //potevi evitare la regex
str = pieces.suffix().str();
std::regex_search(str, pieces, regex);
float rotz = stof(pieces[0], NULL); //potevi evitare la regex
Instance3D* inst = new Instance3D(model, vec3(x, y, z), vec3(1));
inst->rotate(vec3(1, 0, 0), rotx);
inst->rotate(vec3(0, 1, 0), roty);
inst->rotate(vec3(0, 0, 1), rotz);
return inst;
}
/* TOFIX: broken */
bool loadInstances(std::string path, vector<Instance3D*>& instances, bool smoothNormals) {
bool modelLoaded = false;
std::stringstream fileName;
Model3D* currentModel = NULL;
/*on windows was last of \\ */
string root = path.substr(0, path.find_last_of("/") + 1);
file = fopen(&path[0], "r");
if (file == NULL) {
printf("Impossible to open the scene file ! Are you in the right path ?\n");
getchar();
return false;
}
while (1) {
res = fgets(lineHeader, 128, file); // read the first word of the line
// EOF = End Of File. Store pending curve and quit the loop.
if (res == NULL) {
break;
}
string str = lineHeader;
std::regex regex("\\w+\\n");
//inizia una serie di istanze(la prima o una nuova)
if (std::regex_match(str, pieces, regex)) {
std::regex regex("\\w+");
std::regex_search(str, pieces, regex);
fileName.str(std::string()); //clear
fileName << root << pieces[0].str() << ".obj";
string mdl = fileName.str();
currentModel = new Model3D(&mdl[0], smoothNormals);
modelLoaded = true;
}
//devono essere i dati di trasformazione di un istanza
else {
std::regex regex("\\s*(-?\\d+.\\d+)(( , -?\\d+.\\d+)+)\\s*(\\n)?");
//sono dati di un vertice
if (std::regex_match(str, pieces, regex) && modelLoaded) {
instances.push_back(parseInstanceData(currentModel, str));
}
else {
std::cout << "unrecognized scene line : " << str << std::endl;
}
}
}
std::cout << "trovati " << instances.size() << std::endl;
return true;
}

View File

@@ -0,0 +1,159 @@
#include "../../HEADERS/SCENE/Model3D.hpp"
extern "C" {
#include "../../GLES_3_1_compatibility.h"
}
#include "../../HEADERS/UTILS/OnlyOnce.hpp"
#include "../../HEADERS/UTILS/ShaderMaker.h"
#include "../../HEADERS/SCENE/objloader.hpp"
#include "../../HEADERS/UTILS/ResourceCache.h"
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
/* the gl**OES functions are calls which are not in the original OpenGL ES 2
OpenGL ES 3 would have supported them, ES 2 offers them as extensions
*/
Model3D::Model3D(const char* modelPath, bool smoothNormals) {
vector<vec3> points = loadVertexData(modelPath, smoothNormals);
computeBoundingBox(points);
}
void Model3D::computeBoundingBox(vector<vec3> points) {
boundingBoxLBN = points[0];
boundingBoxRTF = points[0];
for (const vec3& point : points) {
boundingBoxLBN.x = glm::min(boundingBoxLBN.x, point.x);
boundingBoxLBN.y = glm::min(boundingBoxLBN.y, point.y);
boundingBoxLBN.z = glm::max(boundingBoxLBN.z, point.z);
boundingBoxRTF.x = glm::max(boundingBoxRTF.x, point.x);
boundingBoxRTF.y = glm::max(boundingBoxRTF.y, point.y);
boundingBoxRTF.z = glm::min(boundingBoxRTF.z, point.z);
}
}
vector<vec3> Model3D::loadVertexData(const char* modelPath, bool smoothNormals) {
unsigned int vbo, vboUv, vboNor, vboTangent, vboBitangent;
vector<vec3> vertices;
vector<int> verticesIndex;
vector<vec2> verticesUv;
vector<vec3> verticesNor;
vector<vec3> verticesTangent;
vector<vec3> verticesBitangent;
loadOBJ(modelPath, vertices, verticesUv, verticesNor, smoothNormals);
/* the windows version was happy even with %d */
printf("Vertici : %ld\tUVcoord : %ld\tNormali : %ld\n", vertices.size(), verticesUv.size(), verticesNor.size() );
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// VBO vertici
{
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(vec3), &vertices[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0/* 3 * sizeof(float)*/, 0);
Model3D::nVertices = vertices.size();
}
// VBO coordinate UV
{
glGenBuffers(1, &vboUv);
glBindBuffer(GL_ARRAY_BUFFER, vboUv);
glBufferData(GL_ARRAY_BUFFER, verticesUv.size() * sizeof(vec2), &verticesUv[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE,0 /*2 * sizeof(float)*/, 0);
}
// VBO normali
{
glGenBuffers(1, &vboNor);
glBindBuffer(GL_ARRAY_BUFFER, vboNor);
glBufferData(GL_ARRAY_BUFFER, verticesNor.size() * sizeof(vec3), &verticesNor[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0/* 3 * sizeof(float)*/,0);
}
// VBO tangenti e VBO bitangenti
{
for (int i = 0; i < vertices.size(); i += 3) {
//erano del tipo vec2& =
// Shortcuts for vertices
vec3 v0 = vertices[i + 0];
vec3 v1 = vertices[i + 1];
vec3 v2 = vertices[i + 2];
// Shortcuts for UVs
vec2 uv0 = verticesUv[i + 0];
vec2 uv1 = verticesUv[i + 1];
vec2 uv2 = verticesUv[i + 2];
// Edges of the triangle : position delta
vec3 deltaPos1 = v1 - v0;
vec3 deltaPos2 = v2 - v0;
// UV delta
vec2 deltaUV1 = uv1 - uv0;
vec2 deltaUV2 = uv2 - uv0;
float r = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV1.y * deltaUV2.x);
vec3 tangent = (deltaPos1 * deltaUV2.y - deltaPos2 * deltaUV1.y) * r;
vec3 bitangent = (deltaPos2 * deltaUV1.x - deltaPos1 * deltaUV2.x) * r;
// Set the same tangent for all three vertices of the triangle.
verticesTangent.push_back(tangent);
verticesTangent.push_back(tangent);
verticesTangent.push_back(tangent);
// Same thing for bitangents
verticesBitangent.push_back(bitangent);
verticesBitangent.push_back(bitangent);
verticesBitangent.push_back(bitangent);
}
glGenBuffers(1, &vboTangent);
glBindBuffer(GL_ARRAY_BUFFER, vboTangent);
glBufferData(GL_ARRAY_BUFFER, verticesTangent.size() * sizeof(vec3), &verticesTangent[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, 0);
glGenBuffers(1, &vboBitangent);
glBindBuffer(GL_ARRAY_BUFFER, vboBitangent);
glBufferData(GL_ARRAY_BUFFER, verticesBitangent.size() * sizeof(vec3), &verticesBitangent[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 0, 0);
}
return vertices;
}
void Model3D::draw() {
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, nVertices);
glBindVertexArray(0);
}
GLuint Model3D::getVAO() {
return this->vao;
}
int Model3D::getTrisCount() {
return this->nVertices;
}
vec3 Model3D::getLBN() {
return boundingBoxLBN;
}
vec3 Model3D::getRTF() {
return boundingBoxRTF;
}

View File

@@ -0,0 +1,103 @@
#include "../../HEADERS/SCENE/ObjectInstance.hpp"
#include <glm/gtc/matrix_transform.hpp>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/transform.hpp>
#include <glm/gtx/norm.hpp>
#include <iostream>
/*was glm/gtc/before */
#include <glm/gtx/quaternion.hpp>
/* aarch64-linux-gnu/include/math.h already defines it */
#ifndef M_PI
#define M_PI 3.14159265358979323846264338327950288
#endif
glm::mat4 WorldInstanceable::getLocalTransform() {
glm::mat4 transform = glm::mat4(1.0);
transform *= scaleMat;
transform *= rotation;
return transform;
}
glm::mat4 WorldInstanceable::getGlobalTransform() {
glm::mat4 transform = getLocalTransform();
//transform = glm::translate(glm::mat4(transform), position);
return glm::translate(glm::mat4(1.0), position) * transform;
}
void WorldInstanceable::alignTo(glm::vec3 direction) {
glm::vec3 localZ;
direction = glm::normalize(direction);
localZ = localFront;
glm::quat a = glm::rotation(localZ, direction);
localFront = glm::toMat4(a) * glm::vec4(localFront, 0.0f);
glm::quat b = glm::rotation(localZ, direction);
localUp = glm::toMat4(b) * glm::vec4(localUp, 0.0f);
//++++++++++++++++++++++++++
//glm::vec3 right = glm::normalize(cross(localFront, localUp));
glm::vec3 right = glm::normalize(cross(localUp, localFront));
right.y = 0;
glm::vec3 stabilizedR = glm::normalize(right);
glm::quat c = glm::rotation(right, stabilizedR);
localUp = glm::toMat4(c) * glm::vec4(localUp, 0);
localUp = -glm::cross(stabilizedR, localFront);
rotation = glm::mat4(glm::mat3(stabilizedR, localUp, localFront));
}
void WorldInstanceable::setPosition(glm::vec3 position) {
this->position = position;
}
void WorldInstanceable::rotate(glm::vec3 axis, float angle) {
rotation *= glm::rotate(glm::radians(angle), axis);
}
void WorldInstanceable::scale(float factor) {
scaleMat *= glm::scale(glm::mat4(1.0), glm::vec3(factor));
}
void WorldInstanceable::scale(glm::vec3 factors) {
scaleMat *= glm::scale(glm::mat4(1.0), factors);
}
void WorldInstanceable::setup(glm::vec3 position) {
this->position = position;
localFront = glm::vec3( 0, 0, 1);
localUp = glm::vec3( 0, 1, 0);
rotation = glm::mat4(1.0f);
scaleMat = glm::mat4(1.0f);
}
WorldInstanceable::WorldInstanceable(glm::vec3 position) {
setup(position);
}
WorldInstanceable::WorldInstanceable(glm::vec3 position, glm::vec3 scale) {
setup(position);
this->scale(scale);
}
WorldInstanceable::WorldInstanceable(glm::vec3 position, glm::vec3 axis, float angle) {
setup(position);
this->rotate(axis, angle);
}
WorldInstanceable::WorldInstanceable(glm::vec3 position, glm::vec3 scale, glm::vec3 axis, float angle) {
setup(position);
this->scale(scale);
this->rotate(axis, angle);
}

View File

@@ -0,0 +1,40 @@
#include "../../HEADERS/SCENE/ShadingHelper.h"
#include <glm/gtc/type_ptr.hpp>
ShadingHelper::ShadingHelper(GLuint program) {
this->program = program;
}
void ShadingHelper::useProgram() {
glUseProgram(program);
}
GLuint ShadingHelper::getProgram() {
return program;
}
void ShadingHelper::bindTexture2D(GLuint texUnitIndex, GLuint texture, std::string uniform) {
glActiveTexture(GL_TEXTURE0 + texUnitIndex);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(glGetUniformLocation(program, &uniform[0]), texUnitIndex);
}
void ShadingHelper::bindViewUniforms(glm::mat4 projection, glm::mat4 view) {
GLint projectionUniform = glGetUniformLocation(program, "Projection");
glUniformMatrix4fv(projectionUniform, 1, GL_FALSE, value_ptr(projection));
GLint viewUniform = glGetUniformLocation(program, "View");
glUniformMatrix4fv(viewUniform, 1, GL_FALSE, value_ptr(view));
}
void ShadingHelper::bindLightUniforms(glm::vec3 lightPos, glm::vec3 lightCol, glm::vec3 eyePos) {
glUniform3f(glGetUniformLocation(program, "lightPos"), lightPos.x, lightPos.y, lightPos.z);
glUniform3f(glGetUniformLocation(program, "lightCol"), lightCol.x, lightCol.y, lightCol.z);
glUniform3f(glGetUniformLocation(program, "eyePos"), eyePos.x, eyePos.y, eyePos.z);
}
void ShadingHelper::bindModelUniforms(glm::mat4 locRotScl, glm::mat4 rotScl) {
GLint localTransformUniform = glGetUniformLocation(program, "Model");
glUniformMatrix4fv(localTransformUniform, 1, GL_FALSE, value_ptr(locRotScl));
GLint onlyRotationUniform = glGetUniformLocation(program, "ModelRot");
glUniformMatrix4fv(onlyRotationUniform, 1, GL_FALSE, value_ptr(rotScl));
}

View File

@@ -0,0 +1,134 @@
#include <vector>
#include <stdio.h>
#include <string>
#include <cstring>
#include <glm/glm.hpp>
#include "../../HEADERS/SCENE/objloader.hpp"
// Very, VERY simple OBJ loader.
// Here is a short list of features a real function would provide :
// - Binary files. Reading a model should be just a few memcpy's away, not parsing a file at runtime. In short : OBJ is not very great.
// - Animations & bones (includes bones weights)
// - Multiple UVs
// - All attributes should be optional, not "forced"
// - More stable. Change a line in the OBJ file and it crashes.
// - More secure. Change another line and you can inject code.
// - Loading from memory, stream, etc
bool loadOBJ(
const char* path,
std::vector<glm::vec3>& out_vertices,
std::vector<glm::vec2>& out_uvs,
std::vector<glm::vec3>& out_normals,
bool smoothNormals
) {
printf("Loading OBJ file %s...\n", path);
std::vector<unsigned int> vertexIndices, uvIndices, normalIndices;
std::vector<glm::vec3> temp_vertices;
std::vector<glm::vec2> temp_uvs;
std::vector<glm::vec3> temp_normals;
FILE* file = fopen(path, "r");
if (file == NULL) {
printf("Impossible to open the file ! Are you in the right path ? See Tutorial 1 for details\n");
getchar();
return false;
}
while (1) {
char lineHeader[128];
// read the first word of the line
int res = fscanf(file, "%s", lineHeader);
if (res == EOF)
break; // EOF = End Of File. Quit the loop.
// else : parse lineHeader
if (strcmp(lineHeader, "v") == 0) {
glm::vec3 vertex;
fscanf(file, "%f %f %f\n", &vertex.x, &vertex.y, &vertex.z);
temp_vertices.push_back(vertex);
}
else if (strcmp(lineHeader, "vt") == 0) {
glm::vec2 uv;
fscanf(file, "%f %f\n", &uv.x, &uv.y);
uv.y = -uv.y; // Invert V coordinate since we will only use DDS texture, which are inverted. Remove if you want to use TGA or BMP loaders.
temp_uvs.push_back(uv);
}
else if (strcmp(lineHeader, "vn") == 0) {
glm::vec3 normal;
fscanf(file, "%f %f %f\n", &normal.x, &normal.y, &normal.z);
temp_normals.push_back(normal);
}
else if (strcmp(lineHeader, "f") == 0) {
std::string vertex1, vertex2, vertex3;
unsigned int vertexIndex[3], uvIndex[3], normalIndex[3];
/* the Windows version accepted even the %d specifier, here is more strict */
int matches = fscanf(file, "%u/%u/%u %u/%u/%u %u/%u/%u\n", &vertexIndex[0], &uvIndex[0], &normalIndex[0], &vertexIndex[1], &uvIndex[1], &normalIndex[1], &vertexIndex[2], &uvIndex[2], &normalIndex[2]);
if (matches != 9) {
printf("File can't be read by our simple parser :-( Try exporting with other options\n");
fclose(file);
return false;
}
vertexIndices.push_back(vertexIndex[0]);
vertexIndices.push_back(vertexIndex[1]);
vertexIndices.push_back(vertexIndex[2]);
uvIndices.push_back(uvIndex[0]);
uvIndices.push_back(uvIndex[1]);
uvIndices.push_back(uvIndex[2]);
normalIndices.push_back(normalIndex[0]);
normalIndices.push_back(normalIndex[1]);
normalIndices.push_back(normalIndex[2]);
}
else {
// Probably a comment, eat up the rest of the line
char stupidBuffer[1000];
fgets(stupidBuffer, 1000, file);
}
}
// For each vertex of each triangle
for (unsigned int i = 0; i < vertexIndices.size(); i++) {
// Get the indices of its attributes
unsigned int vertexIndex = vertexIndices[i];
unsigned int uvIndex = uvIndices[i];
unsigned int normalIndex = normalIndices[i];
// Get the attributes thanks to the index
glm::vec3 vertex = temp_vertices[vertexIndex - 1];
glm::vec2 uv = temp_uvs[uvIndex - 1];
glm::vec3 normal;
if (smoothNormals) {
normal = glm::vec3();
unsigned int count = 0;
for (int j = 0; j < vertexIndices.size(); j++) {
if (vertexIndices[i] == vertexIndices[j]) {
normal += temp_normals[normalIndices[j] - 1];
count++;
}
}
printf("averaging %d normals\n", count);
normal /= count; //count is always greater than 0
}
else {
normal = temp_normals[normalIndex - 1];
}
// Put the attributes in buffers
out_vertices.push_back(vertex);
out_uvs.push_back(uv);
out_normals.push_back(normal);
}
fclose(file);
return true;
}