455 lines
16 KiB
C++
455 lines
16 KiB
C++
#include <iostream>
|
|
#include <cassert>
|
|
#include <vector>
|
|
#include <tuple>
|
|
#include <map>
|
|
#include <tr1/functional>
|
|
#include <obj.hpp>
|
|
#define GLM_FORCE_RADIANS
|
|
#include <glm/glm.hpp>
|
|
#include <glm/gtc/packing.hpp>
|
|
|
|
#include "objectParser.hh"
|
|
|
|
using namespace obj;
|
|
|
|
using std::tr1::placeholders::_1;
|
|
using std::tr1::placeholders::_2;
|
|
using std::tr1::placeholders::_3;
|
|
using std::tr1::placeholders::_4;
|
|
|
|
|
|
class ObjectParser {
|
|
private:
|
|
void texture_vertex_callback(obj::float_type u, obj::float_type v)
|
|
{
|
|
assert(!_addedGenerated);
|
|
if ((u > 1.0f) || (u < 0.0f))
|
|
std::cout << "Warning: Clamping texture coordinate U to [0.0, 1.0]" << std::endl;
|
|
uint16_t c_u = glm::packUnorm1x16(u);
|
|
if ((v > 1.0f) || (v < 0.0f))
|
|
std::cout << "Warning: Clamping texture coordinate V to [0.0, 1.0]" << std::endl;
|
|
uint16_t c_v = glm::packUnorm1x16(v);
|
|
_texCoords.emplace_back(glm::u16vec2(c_u, c_v));
|
|
//std::cout << "vt " << c_u << " " << c_v << "\n";
|
|
}
|
|
|
|
void geometric_vertex_callback(obj::float_type x, obj::float_type y, obj::float_type z)
|
|
{
|
|
_vertices.emplace_back(glm::vec3(x, y, z));
|
|
//std::cout << "v " << x << " " << y << " " << z << "\n";
|
|
}
|
|
|
|
void vertex_normal_callback(obj::float_type x, obj::float_type y, obj::float_type z)
|
|
{
|
|
assert(!_addedGenerated);
|
|
union {
|
|
struct {
|
|
signed x:10;
|
|
signed y:10;
|
|
signed z:10;
|
|
// signed :2;
|
|
// signed z:10;
|
|
// signed y:10;
|
|
// signed x:10;
|
|
} bits;
|
|
uint32_t all;
|
|
} pack_10;
|
|
if ((x > 1.0f) || (x < -1.0f))
|
|
std::cout << "Warning: Clamping normal X to [-1.0, 1.0]" << std::endl;
|
|
if ((y > 1.0f) || (y < -1.0f))
|
|
std::cout << "Warning: Clamping normal Y to [-1.0, 1.0]" << std::endl;
|
|
if ((z > 1.0f) || (z < -1.0f))
|
|
std::cout << "Warning: Clamping normal Z to [-1.0, 1.0]" << std::endl;
|
|
pack_10.all = glm::packSnorm3x10_1x2(glm::vec4(x, y, z, 0.0f));
|
|
_normals.push_back(pack_10.all);
|
|
// std::cout << "vn " << pack_10.bits.x << " " << pack_10.bits.y << " " << pack_10.bits.z << "\n";
|
|
}
|
|
|
|
size_t _find_vertex_tc_norm(size_t vert, size_t tc, size_t norm)
|
|
{
|
|
auto pair_it = _vertex_tc_norm_map.find(std::tuple<std::size_t, std::size_t, std::size_t>(vert, tc, norm));
|
|
size_t pair_pos;
|
|
if (pair_it != _vertex_tc_norm_map.end())
|
|
pair_pos = pair_it->second;
|
|
else {
|
|
_vertex_tc_norm.emplace_back(_vertices[vert],
|
|
_texCoords[tc],
|
|
_normals[norm]);
|
|
pair_pos = _vertex_tc_norm.size()-1;
|
|
_vertex_tc_norm_map.emplace(std::tuple<std::size_t, std::size_t, std::size_t>(vert, tc, norm),
|
|
pair_pos);
|
|
}
|
|
return pair_pos;
|
|
}
|
|
|
|
glm::vec3 _calculateNormal(glm::vec3 const& a, glm::vec3 const& b, glm::vec3 const& c)
|
|
{
|
|
return glm::normalize(glm::cross(b-a, c-a));
|
|
}
|
|
|
|
size_t _generateNormal(glm::vec3 const& a, glm::vec3 const& b, glm::vec3 const& c)
|
|
{
|
|
glm::vec3 normal = _calculateNormal(a, b, c);
|
|
uint32_t norm32 = glm::packSnorm3x10_1x2(glm::vec4(normal, 0.0f));
|
|
|
|
size_t pos = 0;
|
|
for(auto& ent : _normals) {
|
|
if (ent == norm32)
|
|
return pos;
|
|
++pos;
|
|
}
|
|
|
|
_addedGenerated = true;
|
|
_normals.push_back(norm32);
|
|
return _normals.size()-1;
|
|
}
|
|
|
|
size_t _generateTC()
|
|
{
|
|
glm::u16vec2 tc(0, 0);
|
|
|
|
size_t pos = 0;
|
|
for(auto& ent : _texCoords) {
|
|
if (ent == tc)
|
|
return pos;
|
|
++pos;
|
|
}
|
|
|
|
_addedGenerated = true;
|
|
_texCoords.push_back(tc);
|
|
return _texCoords.size()-1;
|
|
}
|
|
|
|
|
|
void triangular_face_geometric_vertices_callback(index_type a, index_type b, index_type c)
|
|
{
|
|
if ((_vertices.size() < a) ||
|
|
(_vertices.size() < b) ||
|
|
(_vertices.size() < c))
|
|
throw ParseException("Vertex Index out of range");
|
|
|
|
size_t norm = _generateNormal(_vertices[a-1],
|
|
_vertices[b-1],
|
|
_vertices[c-1]);
|
|
size_t tc = _generateTC();
|
|
|
|
//std::cout << "f (" << a << ", " << tc << ", " << norm << ")" <<
|
|
// " (" << b << ", " << tc << ", " << norm << ")" <<
|
|
// " (" << c << ", " << tc << ", " << norm << ")\n";
|
|
|
|
size_t a_pos = _find_vertex_tc_norm(a-1,
|
|
tc,
|
|
norm);
|
|
size_t b_pos = _find_vertex_tc_norm(b-1,
|
|
tc,
|
|
norm);
|
|
size_t c_pos = _find_vertex_tc_norm(c-1,
|
|
tc,
|
|
norm);
|
|
_faces.emplace_back(a_pos, b_pos, c_pos);
|
|
|
|
//std::cout << "\t [" << a_pos << ", " << b_pos << ", " << c_pos << "]\n";
|
|
}
|
|
|
|
void triangular_face_geometric_vertices_texture_vertices_callback(index_2_tuple_type a, index_2_tuple_type b, index_2_tuple_type c)
|
|
{
|
|
if ((_vertices.size() < std::tr1::get<0>(a)) ||
|
|
(_vertices.size() < std::tr1::get<0>(b)) ||
|
|
(_vertices.size() < std::tr1::get<0>(c)))
|
|
throw ParseException("Vertex Index out of range");
|
|
if ((_texCoords.size() < std::tr1::get<1>(a)) ||
|
|
(_texCoords.size() < std::tr1::get<1>(b)) ||
|
|
(_texCoords.size() < std::tr1::get<1>(c)))
|
|
throw ParseException("Texture Coordinate Index out of range");
|
|
|
|
size_t norm = _generateNormal(_vertices[std::tr1::get<0>(a)-1],
|
|
_vertices[std::tr1::get<0>(b)-1],
|
|
_vertices[std::tr1::get<0>(c)-1]);
|
|
|
|
//std::cout << "f (" << std::tr1::get<0>(a) << ", " << std::tr1::get<1>(a) << ", " << norm << ")" <<
|
|
// " (" << std::tr1::get<0>(b) << ", " << std::tr1::get<1>(b) << ", " << norm << ")" <<
|
|
// " (" << std::tr1::get<0>(c) << ", " << std::tr1::get<1>(c) << ", " << norm << ")\n";
|
|
|
|
size_t a_pos = _find_vertex_tc_norm(std::tr1::get<0>(a)-1,
|
|
std::tr1::get<1>(a)-1,
|
|
norm);
|
|
size_t b_pos = _find_vertex_tc_norm(std::tr1::get<0>(b)-1,
|
|
std::tr1::get<1>(b)-1,
|
|
norm);
|
|
size_t c_pos = _find_vertex_tc_norm(std::tr1::get<0>(c)-1,
|
|
std::tr1::get<1>(c)-1,
|
|
norm);
|
|
_faces.emplace_back(a_pos, b_pos, c_pos);
|
|
|
|
//std::cout << "\t [" << a_pos << ", " << b_pos << ", " << c_pos << "]\n";
|
|
}
|
|
|
|
void triangular_face_geometric_vertices_vertex_normals_callback(index_2_tuple_type a, index_2_tuple_type b, index_2_tuple_type c)
|
|
{
|
|
if ((_vertices.size() < std::tr1::get<0>(a)) ||
|
|
(_vertices.size() < std::tr1::get<0>(b)) ||
|
|
(_vertices.size() < std::tr1::get<0>(c)))
|
|
throw ParseException("Vertex Index out of range");
|
|
if ((_normals.size() < std::tr1::get<1>(a)) ||
|
|
(_normals.size() < std::tr1::get<1>(b)) ||
|
|
(_normals.size() < std::tr1::get<1>(c)))
|
|
throw ParseException("Normal Index out of range");
|
|
|
|
size_t tc = _generateTC();
|
|
|
|
//std::cout << "f (" << std::tr1::get<0>(a) << ", " << tc << ", " << std::tr1::get<1>(a) << ")" <<
|
|
// " (" << std::tr1::get<0>(b) << ", " << tc << "," << std::tr1::get<1>(b) << ")" <<
|
|
// " (" << std::tr1::get<0>(c) << ", " << tc << ", " << std::tr1::get<1>(c) << ")\n";
|
|
|
|
size_t a_pos = _find_vertex_tc_norm(std::tr1::get<0>(a)-1,
|
|
tc,
|
|
std::tr1::get<1>(a)-1);
|
|
size_t b_pos = _find_vertex_tc_norm(std::tr1::get<0>(b)-1,
|
|
tc,
|
|
std::tr1::get<1>(b)-1);
|
|
size_t c_pos = _find_vertex_tc_norm(std::tr1::get<0>(c)-1,
|
|
tc,
|
|
std::tr1::get<1>(c)-1);
|
|
_faces.emplace_back(a_pos, b_pos, c_pos);
|
|
|
|
//std::cout << "\t [" << a_pos << ", " << b_pos << ", " << c_pos << "]\n";
|
|
}
|
|
|
|
void triangular_face_geometric_vertices_texture_vertices_vertex_normals_callback(index_3_tuple_type a, index_3_tuple_type b,
|
|
index_3_tuple_type c)
|
|
{
|
|
if ((_vertices.size() < std::tr1::get<0>(a)) ||
|
|
(_vertices.size() < std::tr1::get<0>(b)) ||
|
|
(_vertices.size() < std::tr1::get<0>(c)))
|
|
throw ParseException("Vertex Index out of range");
|
|
if ((_texCoords.size() < std::tr1::get<1>(a)) ||
|
|
(_texCoords.size() < std::tr1::get<1>(b)) ||
|
|
(_texCoords.size() < std::tr1::get<1>(c)))
|
|
throw ParseException("Texture Coordinate Index out of range");
|
|
if ((_normals.size() < std::tr1::get<2>(a)) ||
|
|
(_normals.size() < std::tr1::get<2>(b)) ||
|
|
(_normals.size() < std::tr1::get<2>(c)))
|
|
throw ParseException("Normal Index out of range");
|
|
|
|
//std::cout << "f (" << std::tr1::get<0>(a) << ", " << std::tr1::get<1>(a) << ", " << std::tr1::get<2>(a) << ")" <<
|
|
// " (" << std::tr1::get<0>(b) << ", " << std::tr1::get<1>(b) << ", " << std::tr1::get<2>(b) << ")" <<
|
|
// " (" << std::tr1::get<0>(c) << ", " << std::tr1::get<1>(c) << ", " << std::tr1::get<2>(c) << ")\n";
|
|
|
|
size_t a_pos = _find_vertex_tc_norm(std::tr1::get<0>(a)-1,
|
|
std::tr1::get<1>(a)-1,
|
|
std::tr1::get<2>(a)-1);
|
|
size_t b_pos = _find_vertex_tc_norm(std::tr1::get<0>(b)-1,
|
|
std::tr1::get<1>(b)-1,
|
|
std::tr1::get<2>(b)-1);
|
|
size_t c_pos = _find_vertex_tc_norm(std::tr1::get<0>(c)-1,
|
|
std::tr1::get<1>(c)-1,
|
|
std::tr1::get<2>(c)-1);
|
|
_faces.emplace_back(a_pos, b_pos, c_pos);
|
|
|
|
//std::cout << "\t [" << a_pos << ", " << b_pos << ", " << c_pos << "]\n";
|
|
}
|
|
|
|
void quadrilateral_face_geometric_vertices_callback(index_type a, index_type b, index_type c, index_type d)
|
|
{
|
|
assert(false);
|
|
}
|
|
|
|
void quadrilateral_face_geometric_vertices_texture_vertices_callback(index_2_tuple_type a, index_2_tuple_type b,
|
|
index_2_tuple_type c, index_2_tuple_type d)
|
|
{
|
|
assert(false);
|
|
}
|
|
|
|
void quadrilateral_face_geometric_vertices_vertex_normals_callback(index_2_tuple_type a, index_2_tuple_type b,
|
|
index_2_tuple_type c, index_2_tuple_type d)
|
|
{
|
|
assert(false);
|
|
}
|
|
|
|
void quadrilateral_face_geometric_vertices_texture_vertices_vertex_normals_callback(index_3_tuple_type a, index_3_tuple_type b,
|
|
index_3_tuple_type c, index_3_tuple_type d)
|
|
{
|
|
assert(false);
|
|
}
|
|
|
|
void polygonal_face_geometric_vertices_begin_callback(index_type a, index_type b, index_type c)
|
|
{
|
|
assert(false);
|
|
}
|
|
|
|
void polygonal_face_geometric_vertices_vertex_callback(index_type a)
|
|
{
|
|
assert(false);
|
|
}
|
|
|
|
void polygonal_face_geometric_vertices_end_callback()
|
|
{
|
|
assert(false);
|
|
}
|
|
|
|
void polygonal_face_geometric_vertices_texture_vertices_begin_callback(index_2_tuple_type a, index_2_tuple_type b,
|
|
index_2_tuple_type c)
|
|
{
|
|
assert(false);
|
|
}
|
|
|
|
void polygonal_face_geometric_vertices_texture_vertices_vertex_callback(index_2_tuple_type a)
|
|
{
|
|
assert(false);
|
|
}
|
|
|
|
void polygonal_face_geometric_vertices_texture_vertices_end_callback()
|
|
{
|
|
assert(false);
|
|
}
|
|
|
|
void polygonal_face_geometric_vertices_vertex_normals_begin_callback(index_2_tuple_type a, index_2_tuple_type b,
|
|
index_2_tuple_type c)
|
|
{
|
|
assert(false);
|
|
}
|
|
|
|
void polygonal_face_geometric_vertices_vertex_normals_vertex_callback(index_2_tuple_type a)
|
|
{
|
|
assert(false);
|
|
}
|
|
|
|
void polygonal_face_geometric_vertices_vertex_normals_end_callback()
|
|
{
|
|
assert(false);
|
|
}
|
|
|
|
void polygonal_face_geometric_vertices_texture_vertices_vertex_normals_begin_callback(index_3_tuple_type a, index_3_tuple_type b,
|
|
index_3_tuple_type c)
|
|
{
|
|
assert(false);
|
|
}
|
|
|
|
void polygonal_face_geometric_vertices_texture_vertices_vertex_normals_vertex_callback(index_3_tuple_type a)
|
|
{
|
|
assert(false);
|
|
}
|
|
|
|
void polygonal_face_geometric_vertices_texture_vertices_vertex_normals_end_callback()
|
|
{
|
|
assert(false);
|
|
}
|
|
|
|
bool _addedGenerated;
|
|
|
|
std::vector<glm::vec3> _vertices;
|
|
std::vector<glm::u16vec2> _texCoords;
|
|
std::vector<uint32_t> _normals;
|
|
|
|
std::map<std::tuple<std::size_t, std::size_t, std::size_t>, std::size_t > _vertex_tc_norm_map;
|
|
std::vector<std::tuple<glm::vec3, glm::u16vec2, glm::uint32_t> > _vertex_tc_norm;
|
|
|
|
std::vector<std::tuple<std::size_t, std::size_t, std::size_t> > _faces;
|
|
|
|
public:
|
|
ObjectParser() : _addedGenerated(false) {
|
|
}
|
|
|
|
~ObjectParser() {
|
|
}
|
|
|
|
void parse(std::string const& filename)
|
|
{
|
|
obj::obj_parser obj_parser(obj::obj_parser::triangulate_faces | obj::obj_parser::translate_negative_indices);
|
|
obj_parser.geometric_vertex_callback(std::tr1::bind(&ObjectParser::geometric_vertex_callback, this, _1, _2, _3));
|
|
obj_parser.texture_vertex_callback(std::tr1::bind(&ObjectParser::texture_vertex_callback, this, _1, _2));
|
|
obj_parser.vertex_normal_callback(std::tr1::bind(&ObjectParser::vertex_normal_callback, this, _1, _2, _3));
|
|
obj_parser.face_callbacks
|
|
(std::tr1::bind(&ObjectParser::triangular_face_geometric_vertices_callback, this, _1, _2, _3),
|
|
std::tr1::bind(&ObjectParser::triangular_face_geometric_vertices_texture_vertices_callback, this, _1, _2, _3),
|
|
std::tr1::bind(&ObjectParser::triangular_face_geometric_vertices_vertex_normals_callback, this, _1, _2, _3),
|
|
std::tr1::bind(&ObjectParser::triangular_face_geometric_vertices_texture_vertices_vertex_normals_callback, this, _1, _2, _3),
|
|
std::tr1::bind(&ObjectParser::quadrilateral_face_geometric_vertices_callback, this, _1, _2, _3, _4),
|
|
std::tr1::bind(&ObjectParser::quadrilateral_face_geometric_vertices_texture_vertices_callback, this, _1, _2, _3, _4),
|
|
std::tr1::bind(&ObjectParser::quadrilateral_face_geometric_vertices_vertex_normals_callback, this, _1, _2, _3, _4),
|
|
std::tr1::bind(&ObjectParser::quadrilateral_face_geometric_vertices_texture_vertices_vertex_normals_callback, this, _1, _2, _3, _4),
|
|
std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_begin_callback, this, _1, _2, _3),
|
|
std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_vertex_callback, this, _1),
|
|
std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_end_callback, this),
|
|
std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_texture_vertices_begin_callback, this, _1, _2, _3),
|
|
std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_texture_vertices_vertex_callback, this, _1),
|
|
std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_texture_vertices_end_callback, this),
|
|
std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_vertex_normals_begin_callback, this, _1, _2, _3),
|
|
std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_vertex_normals_vertex_callback, this, _1),
|
|
std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_vertex_normals_end_callback, this),
|
|
std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_texture_vertices_vertex_normals_begin_callback, this, _1, _2, _3),
|
|
std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_texture_vertices_vertex_normals_vertex_callback, this, _1),
|
|
std::tr1::bind(&ObjectParser::polygonal_face_geometric_vertices_texture_vertices_vertex_normals_end_callback, this));
|
|
obj_parser.parse(filename);
|
|
}
|
|
|
|
std::vector<objVertexAttribs> buildVA() const
|
|
{
|
|
std::vector<objVertexAttribs> ret;
|
|
for (auto const& ent : _vertex_tc_norm) {
|
|
objVertexAttribs tmp;
|
|
tmp.vertex[0] = std::get<0>(ent).x;
|
|
tmp.vertex[1] = std::get<0>(ent).y;
|
|
tmp.vertex[2] = std::get<0>(ent).z;
|
|
tmp.texCoords[0] = std::get<1>(ent).x;
|
|
tmp.texCoords[1] = std::get<1>(ent).y;
|
|
tmp.normal = std::get<2>(ent);
|
|
ret.push_back(tmp);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
std::vector<uint16_t> buildIndices() const
|
|
{
|
|
std::vector<uint16_t> ret;
|
|
for (auto const& ent : _faces) {
|
|
ret.push_back(std::get<0>(ent));
|
|
ret.push_back(std::get<1>(ent));
|
|
ret.push_back(std::get<2>(ent));
|
|
}
|
|
return ret;
|
|
}
|
|
};
|
|
|
|
std::tuple<std::vector<objVertexAttribs>, std::vector<uint16_t> > readObject(std::string const& filename)
|
|
{
|
|
ObjectParser parser;
|
|
parser.parse(filename);
|
|
return std::tuple<std::vector<objVertexAttribs>, std::vector<uint16_t> >(parser.buildVA(), parser.buildIndices());
|
|
}
|
|
|
|
|
|
#include <fstream>
|
|
|
|
#include "object.pb.h"
|
|
|
|
using std::ios;
|
|
|
|
void writeObjectPB(std::string const& filename, std::tuple<std::vector<objVertexAttribs>, std::vector<uint16_t> > obj)
|
|
{
|
|
std::fstream output(filename, ios::out | ios::binary);
|
|
|
|
pb::Object pbObj;
|
|
for (auto const& ind : std::get<1>(obj)) {
|
|
pbObj.add_indices(ind);
|
|
}
|
|
|
|
for (auto const& attr : std::get<0>(obj)) {
|
|
auto a = pbObj.add_attribs();
|
|
for(int i = 0;i < 3;++i)
|
|
a->add_vertex(attr.vertex[i]);
|
|
for(int i = 0;i < 2;++i)
|
|
a->add_texcoords(attr.texCoords[i]);
|
|
a->set_normal(attr.normal);
|
|
}
|
|
|
|
pbObj.SerializeToOstream(&output);
|
|
}
|
|
|
|
std::tuple<std::vector<objVertexAttribs>, std::vector<uint16_t> > readObjectPB(std::string const& filename)
|
|
{
|
|
return std::tuple<std::vector<objVertexAttribs>, std::vector<uint16_t> >();
|
|
}
|
|
|