// // Created by Иван Ильин on 13.01.2021. // #include #include #include #include #include "Mesh.h" #include "utils/Log.h" using namespace std; Mesh Mesh::operator*(const Matrix4x4 &matrix4X4) const { return Mesh(*this) *= matrix4X4; } Mesh &Mesh::operator*=(const Matrix4x4 &matrix4X4) { for (auto& t : tris) t *= matrix4X4; return *this; } Mesh &Mesh::loadObj(const std::string& filename, const std::string &materials, const Point4D& scale) { auto objects = Mesh::LoadObjects(filename, materials, scale); for(auto& obj : objects) { for (auto &tri : obj->triangles()) { tris.push_back(tri); } } return *this; } Mesh::Mesh(const std::string& filename, const std::string &materials, const Point4D& scale){ loadObj(filename, materials, scale); } Mesh::Mesh(const vector &tries){ tris = tries; } Mesh::Mesh(const Mesh& mesh) : Animatable(mesh) { *this = mesh; } Mesh Mesh::Obj(const std::string& filename) { return Mesh(filename); } Mesh Mesh::Cube(double size) { Mesh cube{}; cube.tris = { { Point4D{0.0, 0.0, 0.0, 1.0}, Point4D{0.0, 1.0, 0.0, 1.0}, Point4D{1.0, 1.0, 0.0, 1.0} }, { Point4D{0.0, 0.0, 0.0, 1.0}, Point4D{1.0, 1.0, 0.0, 1.0}, Point4D{1.0, 0.0, 0.0, 1.0} }, { Point4D{1.0, 0.0, 0.0, 1.0}, Point4D{1.0, 1.0, 0.0, 1.0}, Point4D{1.0, 1.0, 1.0, 1.0} }, { Point4D{1.0, 0.0, 0.0, 1.0}, Point4D{1.0, 1.0, 1.0, 1.0}, Point4D{1.0, 0.0, 1.0, 1.0} }, { Point4D{1.0, 0.0, 1.0, 1.0}, Point4D{1.0, 1.0, 1.0, 1.0}, Point4D{0.0, 1.0, 1.0, 1.0} }, { Point4D{1.0, 0.0, 1.0, 1.0}, Point4D{0.0, 1.0, 1.0, 1.0}, Point4D{0.0, 0.0, 1.0, 1.0} }, { Point4D{0.0, 0.0, 1.0, 1.0}, Point4D{0.0, 1.0, 1.0, 1.0}, Point4D{0.0, 1.0, 0.0, 1.0} }, { Point4D{0.0, 0.0, 1.0, 1.0}, Point4D{0.0, 1.0, 0.0, 1.0}, Point4D{0.0, 0.0, 0.0, 1.0} }, { Point4D{0.0, 1.0, 0.0, 1.0}, Point4D{0.0, 1.0, 1.0, 1.0}, Point4D{1.0, 1.0, 1.0, 1.0} }, { Point4D{0.0, 1.0, 0.0, 1.0}, Point4D{1.0, 1.0, 1.0, 1.0}, Point4D{1.0, 1.0, 0.0, 1.0} }, { Point4D{1.0, 0.0, 1.0, 1.0}, Point4D{0.0, 0.0, 1.0, 1.0}, Point4D{0.0, 0.0, 0.0, 1.0} }, { Point4D{1.0, 0.0, 1.0, 1.0}, Point4D{0.0, 0.0, 0.0, 1.0}, Point4D{1.0, 0.0, 0.0, 1.0} }, }; return cube *= Matrix4x4::Scale(size, size, size); } void Mesh::translate(double dx, double dy, double dz) { p_position += Point4D(dx, dy, dz); if(v_attached.empty()) return; for(auto attached : v_attached) attached->translate(Point4D{dx, dy, dz}); } void Mesh::rotate(double rx, double ry, double rz) { p_angle += Point4D{rx, ry, rz}; *this *= Matrix4x4::Rotation(rx, ry, rz); } void Mesh::rotate(const Point4D &r) { p_angle += r; *this *= Matrix4x4::Rotation(r); if(v_attached.empty()) return; for(auto attached : v_attached) attached->rotateRelativePoint(position(), r); } void Mesh::rotate(const Point4D &v, double r) { *this *= Matrix4x4::Rotation(v, r); if(v_attached.empty()) return; for(auto attached : v_attached) attached->rotateRelativePoint(position(), v, r); } void Mesh::scale(double sx, double sy, double sz) { *this *= Matrix4x4::Scale(sx, sy, sz); } void Mesh::scale(const Point4D &s) { *this *= Matrix4x4::Scale(s.x(), s.y(), s.z()); } void Mesh::translate(const Point4D &t) { translate(t.x(), t.y(), t.z()); } Mesh &Mesh::operator=(const Mesh &mesh) { tris = mesh.tris; p_position = mesh.p_position; c_color = mesh.c_color; return *this; } void Mesh::rotateRelativePoint(const Point4D &s, double rx, double ry, double rz) { p_angle += Point4D{rx, ry, rz}; // Translate XYZ by vector r1 Point4D r1 = p_position - s; *this *= Matrix4x4::Translation(r1); // In translated coordinate system we rotate mesh and position Matrix4x4 rotationMatrix = Matrix4x4::Rotation(rx, ry, rz); Point4D r2 = rotationMatrix*r1; *this *= rotationMatrix; // After rotation we translate XYZ by vector -r2 and recalculate position *this *= Matrix4x4::Translation(-r2); p_position = s + r2; if(v_attached.empty()) return; for(auto attached : v_attached) attached->rotateRelativePoint(s, Point4D{rx, ry, rz}); } void Mesh::rotateRelativePoint(const Point4D &s, const Point4D &r) { p_angle += r; rotateRelativePoint(s, r.x(), r.y(), r.z()); } void Mesh::rotateRelativePoint(const Point4D &s, const Point4D &v, double r) { // Translate XYZ by vector r1 Point4D r1 = p_position - s; *this *= Matrix4x4::Translation(r1); // In translated coordinate system we rotate mesh and position Matrix4x4 rotationMatrix = Matrix4x4::Rotation(v, r); Point4D r2 = rotationMatrix*r1; *this *= rotationMatrix; // After rotation we translate XYZ by vector -r2 and recalculate position *this *= Matrix4x4::Translation(-r2); p_position = s + r2; if(v_attached.empty()) return; for(auto attached : v_attached) attached->rotateRelativePoint(s, v, r); } void Mesh::translateToPoint(const Point4D &point) { translate(point - p_position); } void Mesh::setColor(sf::Color c) { c_color = c; for (auto& t : tris) t.color = c_color; } std::vector> Mesh::LoadObjects(const string &filename, const string &materials, const Point4D &scale) { std::vector> objects; map maters; ifstream file(filename); if (!file.is_open()) { Log::log("Mesh::LoadObjects(): cannot load file from " + filename); return objects; } if(!materials.empty()) { ifstream mat(materials); if (!mat.is_open()) { Log::log("Mesh::LoadObjects(): cannot load mat from " + materials); return objects; } else { while (!mat.eof()) { char line[128]; mat.getline(line, 128); stringstream s; s << line; int color[4]; string matName; s >> matName >> color[0] >> color[1] >> color[2] >> color[3]; maters.insert({matName, sf::Color(color[0],color[1],color[2], color[3])}); } mat.close(); } } vector verts; std::vector tris; sf::Color currentColor = sf::Color(255, 245, 194, 255); while (!file.eof()) { char line[128]; file.getline(line, 128); stringstream s; s << line; char junk; if(line[0] == 'o') { if(!tris.empty()) { objects.push_back(make_shared(tris)); objects.back()->scale(scale); } tris.clear(); } if (line[0] == 'v') { double x, y, z; s >> junk >> x >> y >> z; verts.emplace_back(x, y, z, 1); } if(line[0] == 'g') { string matInfo; s >> junk >> matInfo; string colorName = matInfo.substr(matInfo.size()-3, 3); currentColor = maters[matInfo.substr(matInfo.size()-3, 3)]; } if (line[0] == 'f') { int f[3]; s >> junk >> f[0] >> f[1] >> f[2]; tris.emplace_back(verts[f[0] - 1], verts[f[1] - 1], verts[f[2] - 1] ); tris.back().color = currentColor; } } if(!tris.empty()) { objects.push_back(make_shared(tris)); objects.back()->scale(scale); } file.close(); return objects; } Mesh Mesh::LineTo(const Point4D& from, const Point4D& to, double line_width, sf::Color color) { Mesh line; Point4D v1 = (to - from).normalized(); Point4D v2 = from.cross3D(from + Point4D{1, 0, 0}).normalized(); Point4D v3 = v1.cross3D(v2).normalized(); // from plane Point4D p1 = from - v2 * line_width/2.0 - v3 * line_width/2.0; Point4D p2 = from - v2 * line_width/2.0 + v3 * line_width/2.0; Point4D p3 = from + v2 * line_width/2.0 + v3 * line_width/2.0; Point4D p4 = from + v2 * line_width/2.0 - v3 * line_width/2.0; // to plane Point4D p5 = to - v2 * line_width/2.0 - v3 * line_width/2.0; Point4D p6 = to - v2 * line_width/2.0 + v3 * line_width/2.0; Point4D p7 = to + v2 * line_width/2.0 + v3 * line_width/2.0; Point4D p8 = to + v2 * line_width/2.0 - v3 * line_width/2.0; line.tris = { { p2, p4, p1 }, { p2, p3, p4 }, { p1, p6, p2 }, { p1, p5, p6 }, { p2, p6, p7 }, { p2, p7, p3 }, { p6, p5, p8 }, { p6, p8, p7 }, { p4, p3, p7 }, { p4, p7, p8 }, { p1, p8, p5 }, { p1, p4, p8 } }; line.setColor(color); return line; }