mirror of
https://github.com/TheRedShip/RT_GPU.git
synced 2025-09-27 18:48:36 +02:00
250 lines
6.9 KiB
C++
250 lines
6.9 KiB
C++
/* ************************************************************************** */
|
|
/* */
|
|
/* ::: :::::::: */
|
|
/* ObjParser.cpp :+: :+: :+: */
|
|
/* +:+ +:+ +:+ */
|
|
/* By: tomoron <tomoron@student.42angouleme.fr> +#+ +:+ +#+ */
|
|
/* +#+#+#+#+#+ +#+ */
|
|
/* Created: 2025/01/16 15:00:33 by tomoron #+# #+# */
|
|
/* Updated: 2025/01/17 19:31:52 by tomoron ### ########.fr */
|
|
/* */
|
|
/* ************************************************************************** */
|
|
|
|
#include "RT.hpp"
|
|
|
|
ObjParser::ObjParser(std::string &filename)
|
|
{
|
|
_mat = 0;
|
|
_file.open(filename);
|
|
if(!_file.is_open())
|
|
throw std::runtime_error("OBJ : could not open object file");
|
|
}
|
|
|
|
ObjParser::~ObjParser()
|
|
{
|
|
_file.close();
|
|
}
|
|
|
|
glm::vec3 ObjParser::getVertex(std::stringstream &line)
|
|
{
|
|
glm::vec3 res;
|
|
|
|
if(!(line >> res.x >> res.y >> res.z))
|
|
throw std::runtime_error("syntax error in obj file while parsing vertex");
|
|
return(res);
|
|
}
|
|
|
|
glm::vec2 ObjParser::getUV(std::stringstream &line)
|
|
{
|
|
glm::vec2 res;
|
|
|
|
if(!(line >> res.x) || (!(line >> res.y) && !line.eof()))
|
|
throw std::runtime_error("syntax error in obj file while parsing texture vertex");
|
|
return(res);
|
|
}
|
|
|
|
long int ObjParser::checkVertexIndex(int index, size_t size)
|
|
{
|
|
if((size_t)index > size || index == 0 || (index < 0 && (size_t)(-index) > size))
|
|
throw std::runtime_error("obj file error, invalid vertex index");
|
|
if(index < 0)
|
|
index = size - index;
|
|
return(index - 1);
|
|
}
|
|
|
|
int ObjParser::pointInTriangle(glm::vec3 pts[3], std::vector<glm::vec3> vertices, size_t cur)
|
|
{
|
|
glm::vec3 v0, v1, v2;
|
|
float d00, d01, d11, d20, d21;
|
|
float den;
|
|
float u, v;
|
|
|
|
for(size_t i = 0; i < vertices.size(); i++)
|
|
{
|
|
if(i == ((cur - 1) % vertices.size()) || i == cur || i == ((cur + 1) % vertices.size()))
|
|
continue;
|
|
v0 = pts[2] - pts[0];
|
|
v1 = pts[1] - pts[0];
|
|
v2 = vertices[i] - pts[0];
|
|
|
|
d00 = glm::dot(v0, v0);
|
|
d01 = glm::dot(v0, v1);
|
|
d11 = glm::dot(v1, v1);
|
|
d20 = glm::dot(v2, v0);
|
|
d21 = glm::dot(v2, v1);
|
|
den = glm::dot(d00, d11) - glm::dot(d01, d01);
|
|
|
|
u = (glm::dot(d11, d20) - glm::dot(d01, d21)) / den;
|
|
v = (glm::dot(d00, d21) - glm::dot(d01, d20)) / den;
|
|
if(u >= 0 && v >= 0 && (u + v) <= 1)
|
|
return(1);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
bool ObjParser::addTriangleFromPolygon(std::vector<glm::vec3> &vertices, Scene &scene, int inv)
|
|
{
|
|
glm::vec3 v1, v2 ,v3;
|
|
float dot;
|
|
|
|
for (size_t i = 0; i < vertices.size(); i++)
|
|
{
|
|
if(!i)
|
|
v1 = vertices.back();
|
|
else
|
|
v1 = vertices[i - 1];
|
|
v2 = vertices[i];
|
|
v3 = vertices[(i + 1) % vertices.size()];
|
|
|
|
std::cout << glm::to_string(v1) << std::endl;
|
|
std::cout << glm::to_string(v2) << std::endl;
|
|
std::cout << glm::to_string(v3) << std::endl;
|
|
if (inv)
|
|
dot = glm::cross(v2 - v1, v2 - v3).z;
|
|
else
|
|
dot = glm::cross(v2 - v3, v2 - v1).z;
|
|
if(dot <= 0)
|
|
continue;
|
|
glm::vec3 triangleVertices[3] = {v1, v2, v3};
|
|
if(pointInTriangle(triangleVertices, vertices, i))
|
|
continue;
|
|
vertices.erase(vertices.begin() + i);
|
|
addTriangle(v1, v2 ,v3 , scene);
|
|
return(1);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
void ObjParser::addFace(std::stringstream &line, Scene &scene)
|
|
{
|
|
int vert_index;
|
|
std::vector<glm::vec3> face_vertices;
|
|
std::string el;
|
|
|
|
while((line >> vert_index))
|
|
face_vertices.push_back(_vertices[checkVertexIndex(vert_index, _vertices.size())]);
|
|
if(face_vertices.size() < 3)
|
|
throw std::runtime_error("OBJ : face does not have enough vertices");
|
|
|
|
while(face_vertices.size() > 3)
|
|
if (!addTriangleFromPolygon(face_vertices, scene, 0))
|
|
addTriangleFromPolygon(face_vertices, scene, 1);
|
|
|
|
if(!line.eof())
|
|
throw std::runtime_error("OBJ: an error occured while parsing face");
|
|
addTriangle(face_vertices[0], face_vertices[1], face_vertices[2], scene);
|
|
}
|
|
|
|
void ObjParser::addTriangle(glm::vec3 v1, glm::vec3 v2, glm::vec3 v3, Scene &scene)
|
|
{
|
|
scene.addObject(new Triangle(v1, v2, v3, _mat));
|
|
}
|
|
|
|
void ObjParser::parseMtl(std::stringstream &input_line, Scene &scene)
|
|
{
|
|
std::string filename;
|
|
std::ifstream file;
|
|
std::string matName;
|
|
std::string identifier;
|
|
std::string line;
|
|
Material *mat;
|
|
|
|
input_line >> filename;
|
|
file.open(filename);
|
|
mat = 0;
|
|
if(!file.is_open())
|
|
throw std::runtime_error("OBJ : could not open material file");
|
|
while(getline(file, line))
|
|
{
|
|
if (line.empty() || line[0] == '#')
|
|
continue;
|
|
std::stringstream lineStream(line);
|
|
lineStream >> identifier;
|
|
if(identifier == "newmtl")
|
|
{
|
|
if(mat)
|
|
{
|
|
scene.addMaterial(mat);
|
|
_matNames[matName] = scene.getMaterialData().size() - 1;
|
|
}
|
|
lineStream >> matName;
|
|
if(matName.empty())
|
|
throw std::runtime_error("OBJ: syntax error in material file, missing material name");
|
|
mat = new Material;
|
|
memset(mat, 0, sizeof(Material));
|
|
mat->metallic = 1.0f;
|
|
continue;
|
|
}
|
|
if(!mat)
|
|
throw std::runtime_error("OBJ: error in material file, material name not defined");
|
|
if(identifier == "Kd")
|
|
{
|
|
if(!(lineStream >> mat->color.x >> mat->color.y >> mat->color.z))
|
|
throw std::runtime_error("OBJ: syntax error while getting material color");
|
|
}
|
|
else if(identifier == "Ns")
|
|
{
|
|
if(!(lineStream >> mat->roughness) || mat->roughness > 1000 || mat->roughness < 0)
|
|
throw std::runtime_error("OBJ: syntax error while getting material softness");
|
|
mat->roughness /= 1000;
|
|
}
|
|
else if(identifier == "Ke")
|
|
{
|
|
float x, y, z;
|
|
if(!(lineStream >> x >> y >> z))
|
|
throw std::runtime_error("OBJ: syntax error while getting material emission");
|
|
mat->emission = (x + y + z) / 3;
|
|
}
|
|
else if(identifier == "Ni")
|
|
{
|
|
if(!(lineStream >> mat->refraction))
|
|
throw std::runtime_error("OBJ: syntax error while getting material refraction");
|
|
}
|
|
else
|
|
std::cerr << "unsupported material setting : " << identifier << std::endl;
|
|
}
|
|
if(mat)
|
|
{
|
|
scene.addMaterial(mat);
|
|
_matNames[matName] = scene.getMaterialData().size() - 1;
|
|
}
|
|
file.close();
|
|
}
|
|
|
|
void ObjParser::parse(Scene &scene)
|
|
{
|
|
std::string line;
|
|
std::string identifier;
|
|
|
|
while (getline(_file, line))
|
|
{
|
|
try{
|
|
if(line[0] == '#' || line.empty())
|
|
continue;
|
|
std::stringstream lineStream(line);
|
|
identifier = "";
|
|
lineStream >> identifier;
|
|
if(identifier == "v")
|
|
_vertices.push_back(getVertex(lineStream));
|
|
else if (identifier == "vt")
|
|
_textureVertices.push_back(getUV(lineStream));
|
|
else if (identifier == "f")
|
|
addFace(lineStream, scene);
|
|
else if (identifier == "mtllib")
|
|
parseMtl(lineStream, scene);
|
|
else if (identifier == "usemtl")
|
|
{
|
|
lineStream >> identifier;
|
|
if(_matNames.find(identifier) == _matNames.end())
|
|
throw std::runtime_error("OBJ: invalid material name");
|
|
_mat = _matNames[identifier];
|
|
}
|
|
} catch (std::exception &e)
|
|
{
|
|
std::cerr << line << std::endl;
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
|