/* * Copyright (C) 2012 Open Source Robotics Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include #include #include #include "gazebo/math/Helpers.hh" #include "gazebo/common/Material.hh" #include "gazebo/common/Exception.hh" #include "gazebo/common/Console.hh" #include "gazebo/common/Mesh.hh" #include "gazebo/common/Skeleton.hh" #include "gazebo/gazebo_config.h" using namespace gazebo; using namespace common; ////////////////////////////////////////////////// Mesh::Mesh() { this->name = "unknown"; this->skeleton = NULL; } ////////////////////////////////////////////////// Mesh::~Mesh() { for (std::vector::iterator iter = this->submeshes.begin(); iter != this->submeshes.end(); ++iter) { delete *iter; } this->submeshes.clear(); for (std::vector::iterator iter = this->materials.begin(); iter != this->materials.end(); ++iter) { delete *iter; } this->materials.clear(); delete this->skeleton; } ////////////////////////////////////////////////// void Mesh::SetPath(const std::string &_path) { this->path = _path; } ////////////////////////////////////////////////// std::string Mesh::GetPath() const { return this->path; } ////////////////////////////////////////////////// void Mesh::SetName(const std::string &_n) { this->name = _n; } ////////////////////////////////////////////////// std::string Mesh::GetName() const { return this->name; } ////////////////////////////////////////////////// ignition::math::Vector3d Mesh::Max() const { ignition::math::Vector3d max; std::vector::const_iterator iter; max.X(-FLT_MAX); max.Y(-FLT_MAX); max.Z(-FLT_MAX); for (iter = this->submeshes.begin(); iter != this->submeshes.end(); ++iter) { if ((*iter)->GetVertexCount() <= 2) continue; ignition::math::Vector3d smax = (*iter)->Max(); max.X(std::max(max.X(), smax.X())); max.Y(std::max(max.Y(), smax.Y())); max.Z(std::max(max.Z(), smax.Z())); } return max; } ////////////////////////////////////////////////// ignition::math::Vector3d Mesh::Min() const { ignition::math::Vector3d min; std::vector::const_iterator iter; min.X(FLT_MAX); min.Y(FLT_MAX); min.Z(FLT_MAX); for (iter = this->submeshes.begin(); iter != this->submeshes.end(); ++iter) { if ((*iter)->GetVertexCount() <= 2) continue; ignition::math::Vector3d smin = (*iter)->Min(); min.X(std::min(min.X(), smin.X())); min.Y(std::min(min.Y(), smin.Y())); min.Z(std::min(min.Z(), smin.Z())); } return min; } ////////////////////////////////////////////////// unsigned int Mesh::GetVertexCount() const { unsigned int sum = 0; std::vector::const_iterator iter; for (iter = this->submeshes.begin(); iter != this->submeshes.end(); ++iter) { if ((*iter)->GetVertexCount() <= 2) continue; sum += (*iter)->GetVertexCount(); } return sum; } ////////////////////////////////////////////////// unsigned int Mesh::GetNormalCount() const { unsigned int sum = 0; std::vector::const_iterator iter; for (iter = this->submeshes.begin(); iter != this->submeshes.end(); ++iter) { if ((*iter)->GetVertexCount() <= 2) continue; sum += (*iter)->GetNormalCount(); } return sum; } ////////////////////////////////////////////////// unsigned int Mesh::GetIndexCount() const { unsigned int sum = 0; std::vector::const_iterator iter; for (iter = this->submeshes.begin(); iter != this->submeshes.end(); ++iter) { if ((*iter)->GetVertexCount() <= 2) continue; sum += (*iter)->GetIndexCount(); } return sum; } ////////////////////////////////////////////////// unsigned int Mesh::GetTexCoordCount() const { unsigned int sum = 0; std::vector::const_iterator iter; for (iter = this->submeshes.begin(); iter != this->submeshes.end(); ++iter) { if ((*iter)->GetVertexCount() <= 2) continue; sum += (*iter)->GetTexCoordCount(); } return sum; } ////////////////////////////////////////////////// void Mesh::AddSubMesh(SubMesh *_sub) { this->submeshes.push_back(_sub); } ////////////////////////////////////////////////// unsigned int Mesh::GetSubMeshCount() const { return this->submeshes.size(); } ////////////////////////////////////////////////// const SubMesh *Mesh::GetSubMesh(unsigned int i) const { if (i < this->submeshes.size()) return this->submeshes[i]; else gzthrow("Invalid index: " << i << " >= " << this->submeshes.size() << "\n"); } ////////////////////////////////////////////////// const SubMesh *Mesh::GetSubMesh(const std::string &_name) const { // Find the submesh with the provided name. for (std::vector::const_iterator iter = this->submeshes.begin(); iter != this->submeshes.end(); ++iter) { if ((*iter)->GetName() == _name) return *iter; } return NULL; } ////////////////////////////////////////////////// int Mesh::AddMaterial(Material *_mat) { int result = -1; if (_mat) { this->materials.push_back(_mat); result = this->materials.size()-1; } return result; } ////////////////////////////////////////////////// unsigned int Mesh::GetMaterialCount() const { return this->materials.size(); } ////////////////////////////////////////////////// const Material *Mesh::GetMaterial(int index) const { if (index >= 0 && index < static_cast(this->materials.size())) return this->materials[index]; return NULL; } ////////////////////////////////////////////////// int Mesh::GetMaterialIndex(const Material *_mat) const { for (unsigned int i = 0; i < this->materials.size(); ++i) { if (this->materials[i] == _mat) return i; } return -1; } ////////////////////////////////////////////////// void Mesh::FillArrays(float **_vertArr, int **_indArr) const { std::vector::const_iterator iter; unsigned int vertCount = 0; unsigned int indCount = 0; for (iter = this->submeshes.begin(); iter != this->submeshes.end(); ++iter) { if ((*iter)->GetVertexCount() <= 2) continue; vertCount += (*iter)->GetVertexCount(); indCount += (*iter)->GetIndexCount(); } if (*_vertArr) delete [] *_vertArr; if (*_indArr) delete [] *_indArr; *_vertArr = new float[vertCount * 3]; *_indArr = new int[indCount]; float *vPtr = *_vertArr; unsigned int index = 0; unsigned int offset = 0; for (iter = this->submeshes.begin(); iter != this->submeshes.end(); ++iter) { if ((*iter)->GetVertexCount() <= 2) continue; float *vertTmp = NULL; int *indTmp = NULL; (*iter)->FillArrays(&vertTmp, &indTmp); memcpy(vPtr, vertTmp, sizeof(vertTmp[0])*(*iter)->GetVertexCount()*3); for (unsigned int i = 0; i < (*iter)->GetIndexCount(); ++i) { (*_indArr)[index++] = (*iter)->GetIndex(i) + offset; } offset = offset + (*iter)->GetMaxIndex() + 1; vPtr += (*iter)->GetVertexCount()*3; delete [] vertTmp; delete [] indTmp; } } ////////////////////////////////////////////////// void Mesh::RecalculateNormals() { std::vector::iterator iter; for (iter = this->submeshes.begin(); iter != this->submeshes.end(); ++iter) (*iter)->RecalculateNormals(); } ////////////////////////////////////////////////// void Mesh::SetSkeleton(Skeleton* _skel) { this->skeleton = _skel; } ////////////////////////////////////////////////// Skeleton* Mesh::GetSkeleton() const { return this->skeleton; } ////////////////////////////////////////////////// bool Mesh::HasSkeleton() const { if (this->skeleton) return true; else return false; } ////////////////////////////////////////////////// void Mesh::Scale(double _factor) { std::vector::iterator iter; for (iter = this->submeshes.begin(); iter != this->submeshes.end(); ++iter) (*iter)->Scale(_factor); } ////////////////////////////////////////////////// void Mesh::SetScale(const ignition::math::Vector3d &_factor) { std::vector::iterator iter; for (iter = this->submeshes.begin(); iter != this->submeshes.end(); ++iter) (*iter)->SetScale(_factor); } ////////////////////////////////////////////////// void Mesh::GenSphericalTexCoord(const ignition::math::Vector3d &_center) { std::vector::iterator siter; for (siter = this->submeshes.begin(); siter != this->submeshes.end(); ++siter) (*siter)->GenSphericalTexCoord(_center); } ////////////////////////////////////////////////// void Mesh::Center(const ignition::math::Vector3d &_center) { ignition::math::Vector3d min, max, half; min = this->Min(); max = this->Max(); half = (max - min) * 0.5; this->Translate(_center - (min + half)); } ////////////////////////////////////////////////// void Mesh::Translate(const ignition::math::Vector3d &_vec) { std::vector::iterator iter; for (iter = this->submeshes.begin(); iter != this->submeshes.end(); ++iter) { if ((*iter)->GetVertexCount() <= 2) continue; (*iter)->Translate(_vec); } } ////////////////////////////////////////////////// ////////////////////////////////////////////////// ////////////////////////////////////////////////// SubMesh::SubMesh() { this->materialIndex = -1; this->primitiveType = TRIANGLES; } ////////////////////////////////////////////////// SubMesh::SubMesh(const SubMesh *_mesh) { if (!_mesh) { gzerr << "Submesh is NULL." << std::endl; return; } this->name = _mesh->name; this->materialIndex = _mesh->materialIndex; this->primitiveType = _mesh->primitiveType; std::copy(_mesh->nodeAssignments.begin(), _mesh->nodeAssignments.end(), std::back_inserter(this->nodeAssignments)); std::copy(_mesh->indices.begin(), _mesh->indices.end(), std::back_inserter(this->indices)); std::copy(_mesh->normals.begin(), _mesh->normals.end(), std::back_inserter(this->normals)); std::copy(_mesh->texCoords.begin(), _mesh->texCoords.end(), std::back_inserter(this->texCoords)); std::copy(_mesh->vertices.begin(), _mesh->vertices.end(), std::back_inserter(this->vertices)); } ////////////////////////////////////////////////// SubMesh::~SubMesh() { this->vertices.clear(); this->indices.clear(); this->nodeAssignments.clear(); } ////////////////////////////////////////////////// void SubMesh::SetPrimitiveType(PrimitiveType _type) { this->primitiveType = _type; } ////////////////////////////////////////////////// SubMesh::PrimitiveType SubMesh::GetPrimitiveType() const { return this->primitiveType; } ////////////////////////////////////////////////// void SubMesh::CopyVertices(const std::vector &_verts) { this->vertices.clear(); this->vertices.resize(_verts.size()); std::copy(_verts.begin(), _verts.end(), this->vertices.begin()); } ////////////////////////////////////////////////// void SubMesh::CopyNormals(const std::vector &_norms) { this->normals.clear(); this->normals.resize(_norms.size()); for (unsigned int i = 0; i < _norms.size(); ++i) { this->normals[i] = _norms[i]; this->normals[i].Normalize(); if (ignition::math::equal(this->normals[i].Length(), 0.0)) { this->normals[i].Set(0, 0, 1); } } } ////////////////////////////////////////////////// void SubMesh::SetVertexCount(unsigned int _count) { this->vertices.resize(_count); } ////////////////////////////////////////////////// void SubMesh::SetIndexCount(unsigned int _count) { this->indices.resize(_count); } ////////////////////////////////////////////////// void SubMesh::SetNormalCount(unsigned int _count) { this->normals.resize(_count); } ////////////////////////////////////////////////// void SubMesh::SetTexCoordCount(unsigned int _count) { this->texCoords.resize(_count); } ////////////////////////////////////////////////// void SubMesh::AddIndex(unsigned int _i) { this->indices.push_back(_i); } ////////////////////////////////////////////////// void SubMesh::AddVertex(const ignition::math::Vector3d &_v) { this->vertices.push_back(_v); } ////////////////////////////////////////////////// void SubMesh::AddVertex(double _x, double _y, double _z) { this->AddVertex(ignition::math::Vector3d(_x, _y, _z)); } ////////////////////////////////////////////////// void SubMesh::AddNormal(const ignition::math::Vector3d &_n) { this->normals.push_back(_n); } ////////////////////////////////////////////////// void SubMesh::AddNormal(double _x, double _y, double _z) { this->AddNormal(ignition::math::Vector3d(_x, _y, _z)); } ////////////////////////////////////////////////// void SubMesh::AddTexCoord(double _u, double _v) { this->texCoords.push_back(ignition::math::Vector2d(_u, _v)); } ////////////////////////////////////////////////// void SubMesh::AddNodeAssignment(unsigned int _vertex, unsigned int _node, float _weight) { NodeAssignment na; na.vertexIndex = _vertex; na.nodeIndex = _node; na.weight = _weight; this->nodeAssignments.push_back(na); } ////////////////////////////////////////////////// ignition::math::Vector3d SubMesh::Vertex(unsigned int _i) const { if (_i >= this->vertices.size()) gzthrow("Index too large"); return this->vertices[_i]; } ////////////////////////////////////////////////// void SubMesh::SetVertex(unsigned int _i, const ignition::math::Vector3d &_v) { if (_i >= this->vertices.size()) gzthrow("Index too large"); this->vertices[_i] = _v; } ////////////////////////////////////////////////// ignition::math::Vector3d SubMesh::Normal(unsigned int _i) const { if (_i >= this->normals.size()) gzthrow("Index too large"); return this->normals[_i]; } ////////////////////////////////////////////////// void SubMesh::SetNormal(unsigned int _i, const ignition::math::Vector3d &_n) { if (_i >= this->normals.size()) gzthrow("Index too large"); this->normals[_i] = _n; } ////////////////////////////////////////////////// ignition::math::Vector2d SubMesh::TexCoord(unsigned int _i) const { if (_i >= this->texCoords.size()) gzthrow("Index too large"); return this->texCoords[_i]; } ////////////////////////////////////////////////// NodeAssignment SubMesh::GetNodeAssignment(unsigned int _i) const { if (_i >= this->nodeAssignments.size()) gzthrow("Index too large"); return this->nodeAssignments[_i]; } ////////////////////////////////////////////////// void SubMesh::SetTexCoord(unsigned int _i, const ignition::math::Vector2d &_t) { if (_i >= this->texCoords.size()) gzthrow("Index too large"); this->texCoords[_i] = _t; } ////////////////////////////////////////////////// unsigned int SubMesh::GetIndex(unsigned int _i) const { if (_i > this->indices.size()) gzthrow("Index too large"); return this->indices[_i]; } ////////////////////////////////////////////////// ignition::math::Vector3d SubMesh::Max() const { ignition::math::Vector3d max; std::vector::const_iterator iter; max.X(-FLT_MAX); max.Y(-FLT_MAX); max.Z(-FLT_MAX); for (iter = this->vertices.begin(); iter != this->vertices.end(); ++iter) { max.X(std::max(max.X(), (*iter).X())); max.Y(std::max(max.Y(), (*iter).Y())); max.Z(std::max(max.Z(), (*iter).Z())); } return max; } ////////////////////////////////////////////////// ignition::math::Vector3d SubMesh::Min() const { ignition::math::Vector3d min; std::vector::const_iterator iter; min.X(FLT_MAX); min.Y(FLT_MAX); min.Z(FLT_MAX); for (iter = this->vertices.begin(); iter != this->vertices.end(); ++iter) { min.X(std::min(min.X(), (*iter).X())); min.Y(std::min(min.Y(), (*iter).Y())); min.Z(std::min(min.Z(), (*iter).Z())); } return min; } ////////////////////////////////////////////////// unsigned int SubMesh::GetVertexCount() const { return this->vertices.size(); } ////////////////////////////////////////////////// unsigned int SubMesh::GetNormalCount() const { return this->normals.size(); } ////////////////////////////////////////////////// unsigned int SubMesh::GetIndexCount() const { return this->indices.size(); } ////////////////////////////////////////////////// unsigned int SubMesh::GetTexCoordCount() const { return this->texCoords.size(); } ////////////////////////////////////////////////// unsigned int SubMesh::GetNodeAssignmentsCount() const { return this->nodeAssignments.size(); } ////////////////////////////////////////////////// unsigned int SubMesh::GetMaxIndex() const { std::vector::const_iterator maxIter; maxIter = std::max_element(this->indices.begin(), this->indices.end()); if (maxIter != this->indices.end()) return *maxIter; return 0; } ////////////////////////////////////////////////// void SubMesh::SetMaterialIndex(unsigned int _index) { this->materialIndex = _index; } ////////////////////////////////////////////////// unsigned int SubMesh::GetMaterialIndex() const { return this->materialIndex; } ////////////////////////////////////////////////// bool SubMesh::HasVertex(const ignition::math::Vector3d &_v) const { std::vector< ignition::math::Vector3d >::const_iterator iter; for (iter = this->vertices.begin(); iter != this->vertices.end(); ++iter) if (_v.Equal(*iter)) return true; return false; } ////////////////////////////////////////////////// unsigned int SubMesh::GetVertexIndex(const ignition::math::Vector3d &_v) const { std::vector< ignition::math::Vector3d >::const_iterator iter; for (iter = this->vertices.begin(); iter != this->vertices.end(); ++iter) if (_v.Equal(*iter)) return iter - this->vertices.begin(); return 0; } ////////////////////////////////////////////////// void SubMesh::FillArrays(float **_vertArr, int **_indArr) const { if (this->vertices.empty() || this->indices.empty()) gzerr << "No vertices or indices\n"; std::vector::const_iterator viter; std::vector::const_iterator iiter; unsigned int i; if (*_vertArr) delete [] *_vertArr; if (*_indArr) delete [] *_indArr; *_vertArr = new float[this->vertices.size() * 3]; *_indArr = new int[this->indices.size()]; for (viter = this->vertices.begin(), i = 0; viter != this->vertices.end(); ++viter) { (*_vertArr)[i++] = static_cast((*viter).X()); (*_vertArr)[i++] = static_cast((*viter).Y()); (*_vertArr)[i++] = static_cast((*viter).Z()); } for (iiter = this->indices.begin(), i = 0; iiter != this->indices.end(); ++iiter) { (*_indArr)[i++] = (*iiter); } } ////////////////////////////////////////////////// void SubMesh::RecalculateNormals() { unsigned int i; if (normals.size() < 3) return; // Reset all the normals for (i = 0; i < this->normals.size(); ++i) this->normals[i].Set(0, 0, 0); if (this->normals.size() != this->vertices.size()) this->normals.resize(this->vertices.size()); // For each face, which is defined by three indices, calculate the normals for (i = 0; i < this->indices.size(); i+= 3) { ignition::math::Vector3d v1 = this->vertices[this->indices[i]]; ignition::math::Vector3d v2 = this->vertices[this->indices[i+1]]; ignition::math::Vector3d v3 = this->vertices[this->indices[i+2]]; ignition::math::Vector3d n = ignition::math::Vector3d::Normal(v1, v2, v3); for (unsigned int j = 0; j< this->vertices.size(); ++j) { if (this->vertices[j] == v1 || this->vertices[j] == v2 || this->vertices[j] == v3) { this->normals[j] += n; } } } // Normalize the results for (i = 0; i < this->normals.size(); ++i) { this->normals[i].Normalize(); } } ////////////////////////////////////////////////// void Mesh::GetAABB(ignition::math::Vector3d &_center, ignition::math::Vector3d &_minXYZ, ignition::math::Vector3d &_maxXYZ) const { // find aabb center _minXYZ.X(1e15); _maxXYZ.X(-1e15); _minXYZ.Y(1e15); _maxXYZ.Y(-1e15); _minXYZ.Z(1e15); _maxXYZ.Z(-1e15); _center.X(0); _center.Y(0); _center.Z(0); std::vector::const_iterator siter; for (siter = this->submeshes.begin(); siter != this->submeshes.end(); ++siter) { ignition::math::Vector3d max = (*siter)->Max(); ignition::math::Vector3d min = (*siter)->Min(); _minXYZ.X(std::min(_minXYZ.X(), min.X())); _maxXYZ.X(std::max(_maxXYZ.X(), max.X())); _minXYZ.Y(std::min(_minXYZ.Y(), min.Y())); _maxXYZ.Y(std::max(_maxXYZ.Y(), max.Y())); _minXYZ.Z(std::min(_minXYZ.Z(), min.Z())); _maxXYZ.Z(std::max(_maxXYZ.Z(), max.Z())); } _center.X(0.5 * (_minXYZ.X() + _maxXYZ.X())); _center.Y(0.5 * (_minXYZ.Y() + _maxXYZ.Y())); _center.Z(0.5 * (_minXYZ.Z() + _maxXYZ.Z())); } ////////////////////////////////////////////////// void SubMesh::GenSphericalTexCoord(const ignition::math::Vector3d &_center) { std::vector::const_iterator viter; for (viter = this->vertices.begin(); viter != this->vertices.end(); ++viter) { // generate projected texture coordinates, projected from center // get x, y, z for computing texture coordinate projections double x = (*viter).X() - _center.X(); double y = (*viter).Y() - _center.Y(); double z = (*viter).Z() - _center.Z(); double r = std::max(0.000001, sqrt(x*x+y*y+z*z)); double s = std::min(1.0, std::max(-1.0, z/r)); double t = std::min(1.0, std::max(-1.0, y/r)); double u = acos(s) / M_PI; double v = acos(t) / M_PI; this->AddTexCoord(u, v); } } ////////////////////////////////////////////////// void SubMesh::Scale(double _factor) { for (auto &vert : this->vertices) vert *= _factor; } ////////////////////////////////////////////////// void SubMesh::SetScale(const ignition::math::Vector3d &_factor) { for (auto &vert : this->vertices) vert *= _factor; } ////////////////////////////////////////////////// void SubMesh::Center(const ignition::math::Vector3d &_center) { ignition::math::Vector3d min, max, half; min = this->Min(); max = this->Max(); half = (max - min) * 0.5; this->Translate(_center - (min + half)); } ////////////////////////////////////////////////// void SubMesh::Translate(const ignition::math::Vector3d &_vec) { for (auto &vert : this->vertices) vert += _vec; } ////////////////////////////////////////////////// void SubMesh::SetName(const std::string &_n) { this->name = _n; } ////////////////////////////////////////////////// std::string SubMesh::GetName() const { return this->name; } ////////////////////////////////////////////////// NodeAssignment::NodeAssignment() : vertexIndex(0), nodeIndex(0), weight(0.0) { }