#include #include #include #include #include #include #include #define GLM_FORCE_RADIANS #include #include #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(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(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 _vertices; std::vector _texCoords; std::vector _normals; std::map, std::size_t > _vertex_tc_norm_map; std::vector > _vertex_tc_norm; std::vector > _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 buildVA() const { std::vector 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 buildIndices() const { std::vector 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 > readObject(std::string const& filename) { ObjectParser parser; parser.parse(filename); return std::tuple, std::vector >(parser.buildVA(), parser.buildIndices()); } #include #include "object.pb.h" using std::ios; void writeObjectPB(std::string const& filename, std::tuple, std::vector > 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 > readObjectPB(std::string const& filename) { return std::tuple, std::vector >(); }