diff options
Diffstat (limited to 'libs/assimp/contrib/draco/src/draco/io/obj_decoder.cc')
-rw-r--r-- | libs/assimp/contrib/draco/src/draco/io/obj_decoder.cc | 708 |
1 files changed, 0 insertions, 708 deletions
diff --git a/libs/assimp/contrib/draco/src/draco/io/obj_decoder.cc b/libs/assimp/contrib/draco/src/draco/io/obj_decoder.cc deleted file mode 100644 index 9b4eab6..0000000 --- a/libs/assimp/contrib/draco/src/draco/io/obj_decoder.cc +++ /dev/null @@ -1,708 +0,0 @@ -// Copyright 2016 The Draco Authors. -// -// 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 "draco/io/obj_decoder.h" - -#include <cctype> -#include <cmath> - -#include "draco/io/file_utils.h" -#include "draco/io/parser_utils.h" -#include "draco/metadata/geometry_metadata.h" - -namespace draco { - -ObjDecoder::ObjDecoder() - : counting_mode_(true), - num_obj_faces_(0), - num_positions_(0), - num_tex_coords_(0), - num_normals_(0), - num_materials_(0), - last_sub_obj_id_(0), - pos_att_id_(-1), - tex_att_id_(-1), - norm_att_id_(-1), - material_att_id_(-1), - sub_obj_att_id_(-1), - deduplicate_input_values_(true), - last_material_id_(0), - use_metadata_(false), - out_mesh_(nullptr), - out_point_cloud_(nullptr) {} - -Status ObjDecoder::DecodeFromFile(const std::string &file_name, - Mesh *out_mesh) { - out_mesh_ = out_mesh; - return DecodeFromFile(file_name, static_cast<PointCloud *>(out_mesh)); -} - -Status ObjDecoder::DecodeFromFile(const std::string &file_name, - PointCloud *out_point_cloud) { - std::vector<char> buffer; - if (!ReadFileToBuffer(file_name, &buffer)) { - return Status(Status::DRACO_ERROR, "Unable to read input file."); - } - buffer_.Init(buffer.data(), buffer.size()); - - out_point_cloud_ = out_point_cloud; - input_file_name_ = file_name; - return DecodeInternal(); -} - -Status ObjDecoder::DecodeFromBuffer(DecoderBuffer *buffer, Mesh *out_mesh) { - out_mesh_ = out_mesh; - return DecodeFromBuffer(buffer, static_cast<PointCloud *>(out_mesh)); -} - -Status ObjDecoder::DecodeFromBuffer(DecoderBuffer *buffer, - PointCloud *out_point_cloud) { - out_point_cloud_ = out_point_cloud; - buffer_.Init(buffer->data_head(), buffer->remaining_size()); - return DecodeInternal(); -} - -Status ObjDecoder::DecodeInternal() { - // In the first pass, count the number of different elements in the geometry. - // In case the desired output is just a point cloud (i.e., when - // out_mesh_ == nullptr) the decoder will ignore all information about the - // connectivity that may be included in the source data. - counting_mode_ = true; - ResetCounters(); - material_name_to_id_.clear(); - last_sub_obj_id_ = 0; - // Parse all lines. - Status status(Status::OK); - while (ParseDefinition(&status) && status.ok()) { - } - if (!status.ok()) { - return status; - } - - bool use_identity_mapping = false; - if (num_obj_faces_ == 0) { - // Mesh has no faces. In this case we try to read the geometry as a point - // cloud where every attribute entry is a point. - - // Ensure the number of all entries is same for all attributes. - if (num_positions_ == 0) { - return Status(Status::DRACO_ERROR, "No position attribute"); - } - if (num_tex_coords_ > 0 && num_tex_coords_ != num_positions_) { - return Status(Status::DRACO_ERROR, - "Invalid number of texture coordinates for a point cloud"); - } - if (num_normals_ > 0 && num_normals_ != num_positions_) { - return Status(Status::DRACO_ERROR, - "Invalid number of normals for a point cloud"); - } - - out_mesh_ = nullptr; // Treat the output geometry as a point cloud. - use_identity_mapping = true; - } - - // Initialize point cloud and mesh properties. - if (out_mesh_) { - // Start decoding a mesh with the given number of faces. For point clouds we - // silently ignore all data about the mesh connectivity. - out_mesh_->SetNumFaces(num_obj_faces_); - } - if (num_obj_faces_ > 0) { - out_point_cloud_->set_num_points(3 * num_obj_faces_); - } else { - out_point_cloud_->set_num_points(num_positions_); - } - - // Add attributes if they are present in the input data. - if (num_positions_ > 0) { - GeometryAttribute va; - va.Init(GeometryAttribute::POSITION, nullptr, 3, DT_FLOAT32, false, - sizeof(float) * 3, 0); - pos_att_id_ = out_point_cloud_->AddAttribute(va, use_identity_mapping, - num_positions_); - } - if (num_tex_coords_ > 0) { - GeometryAttribute va; - va.Init(GeometryAttribute::TEX_COORD, nullptr, 2, DT_FLOAT32, false, - sizeof(float) * 2, 0); - tex_att_id_ = out_point_cloud_->AddAttribute(va, use_identity_mapping, - num_tex_coords_); - } - if (num_normals_ > 0) { - GeometryAttribute va; - va.Init(GeometryAttribute::NORMAL, nullptr, 3, DT_FLOAT32, false, - sizeof(float) * 3, 0); - norm_att_id_ = - out_point_cloud_->AddAttribute(va, use_identity_mapping, num_normals_); - } - if (num_materials_ > 0 && num_obj_faces_ > 0) { - GeometryAttribute va; - const auto geometry_attribute_type = GeometryAttribute::GENERIC; - if (num_materials_ < 256) { - va.Init(geometry_attribute_type, nullptr, 1, DT_UINT8, false, 1, 0); - } else if (num_materials_ < (1 << 16)) { - va.Init(geometry_attribute_type, nullptr, 1, DT_UINT16, false, 2, 0); - } else { - va.Init(geometry_attribute_type, nullptr, 1, DT_UINT32, false, 4, 0); - } - material_att_id_ = - out_point_cloud_->AddAttribute(va, false, num_materials_); - - // Fill the material entries. - for (int i = 0; i < num_materials_; ++i) { - const AttributeValueIndex avi(i); - out_point_cloud_->attribute(material_att_id_)->SetAttributeValue(avi, &i); - } - - if (use_metadata_) { - // Use metadata to store the name of materials. - std::unique_ptr<AttributeMetadata> material_metadata = - std::unique_ptr<AttributeMetadata>(new AttributeMetadata()); - material_metadata->AddEntryString("name", "material"); - // Add all material names. - for (const auto &itr : material_name_to_id_) { - material_metadata->AddEntryInt(itr.first, itr.second); - } - if (!material_file_name_.empty()) { - material_metadata->AddEntryString("file_name", material_file_name_); - } - - out_point_cloud_->AddAttributeMetadata(material_att_id_, - std::move(material_metadata)); - } - } - if (!obj_name_to_id_.empty() && num_obj_faces_ > 0) { - GeometryAttribute va; - if (obj_name_to_id_.size() < 256) { - va.Init(GeometryAttribute::GENERIC, nullptr, 1, DT_UINT8, false, 1, 0); - } else if (obj_name_to_id_.size() < (1 << 16)) { - va.Init(GeometryAttribute::GENERIC, nullptr, 1, DT_UINT16, false, 2, 0); - } else { - va.Init(GeometryAttribute::GENERIC, nullptr, 1, DT_UINT32, false, 4, 0); - } - sub_obj_att_id_ = out_point_cloud_->AddAttribute( - va, false, static_cast<uint32_t>(obj_name_to_id_.size())); - // Fill the sub object id entries. - for (const auto &itr : obj_name_to_id_) { - const AttributeValueIndex i(itr.second); - out_point_cloud_->attribute(sub_obj_att_id_)->SetAttributeValue(i, &i); - } - if (use_metadata_) { - // Use metadata to store the name of materials. - std::unique_ptr<AttributeMetadata> sub_obj_metadata = - std::unique_ptr<AttributeMetadata>(new AttributeMetadata()); - sub_obj_metadata->AddEntryString("name", "sub_obj"); - // Add all sub object names. - for (const auto &itr : obj_name_to_id_) { - const AttributeValueIndex i(itr.second); - sub_obj_metadata->AddEntryInt(itr.first, itr.second); - } - out_point_cloud_->AddAttributeMetadata(sub_obj_att_id_, - std::move(sub_obj_metadata)); - } - } - - // Perform a second iteration of parsing and fill all the data. - counting_mode_ = false; - ResetCounters(); - // Start parsing from the beginning of the buffer again. - buffer()->StartDecodingFrom(0); - while (ParseDefinition(&status) && status.ok()) { - } - if (!status.ok()) { - return status; - } - if (out_mesh_) { - // Add faces with identity mapping between vertex and corner indices. - // Duplicate vertices will get removed later. - Mesh::Face face; - for (FaceIndex i(0); i < num_obj_faces_; ++i) { - for (int c = 0; c < 3; ++c) { - face[c] = 3 * i.value() + c; - } - out_mesh_->SetFace(i, face); - } - } - -#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED - if (deduplicate_input_values_) { - out_point_cloud_->DeduplicateAttributeValues(); - } -#endif -#ifdef DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED - out_point_cloud_->DeduplicatePointIds(); -#endif - return status; -} - -void ObjDecoder::ResetCounters() { - num_obj_faces_ = 0; - num_positions_ = 0; - num_tex_coords_ = 0; - num_normals_ = 0; - last_material_id_ = 0; - last_sub_obj_id_ = 0; -} - -bool ObjDecoder::ParseDefinition(Status *status) { - char c; - parser::SkipWhitespace(buffer()); - if (!buffer()->Peek(&c)) { - // End of file reached?. - return false; - } - if (c == '#') { - // Comment, ignore the line. - parser::SkipLine(buffer()); - return true; - } - if (ParseVertexPosition(status)) { - return true; - } - if (ParseNormal(status)) { - return true; - } - if (ParseTexCoord(status)) { - return true; - } - if (ParseFace(status)) { - return true; - } - if (ParseMaterial(status)) { - return true; - } - if (ParseMaterialLib(status)) { - return true; - } - if (ParseObject(status)) { - return true; - } - // No known definition was found. Ignore the line. - parser::SkipLine(buffer()); - return true; -} - -bool ObjDecoder::ParseVertexPosition(Status *status) { - std::array<char, 2> c; - if (!buffer()->Peek(&c)) { - return false; - } - if (c[0] != 'v' || c[1] != ' ') { - return false; - } - // Vertex definition found! - buffer()->Advance(2); - if (!counting_mode_) { - // Parse three float numbers for vertex position coordinates. - float val[3]; - for (int i = 0; i < 3; ++i) { - parser::SkipWhitespace(buffer()); - if (!parser::ParseFloat(buffer(), val + i)) { - *status = Status(Status::DRACO_ERROR, "Failed to parse a float number"); - // The definition is processed so return true. - return true; - } - } - out_point_cloud_->attribute(pos_att_id_) - ->SetAttributeValue(AttributeValueIndex(num_positions_), val); - } - ++num_positions_; - parser::SkipLine(buffer()); - return true; -} - -bool ObjDecoder::ParseNormal(Status *status) { - std::array<char, 2> c; - if (!buffer()->Peek(&c)) { - return false; - } - if (c[0] != 'v' || c[1] != 'n') { - return false; - } - // Normal definition found! - buffer()->Advance(2); - if (!counting_mode_) { - // Parse three float numbers for the normal vector. - float val[3]; - for (int i = 0; i < 3; ++i) { - parser::SkipWhitespace(buffer()); - if (!parser::ParseFloat(buffer(), val + i)) { - *status = Status(Status::DRACO_ERROR, "Failed to parse a float number"); - // The definition is processed so return true. - return true; - } - } - out_point_cloud_->attribute(norm_att_id_) - ->SetAttributeValue(AttributeValueIndex(num_normals_), val); - } - ++num_normals_; - parser::SkipLine(buffer()); - return true; -} - -bool ObjDecoder::ParseTexCoord(Status *status) { - std::array<char, 2> c; - if (!buffer()->Peek(&c)) { - return false; - } - if (c[0] != 'v' || c[1] != 't') { - return false; - } - // Texture coord definition found! - buffer()->Advance(2); - if (!counting_mode_) { - // Parse two float numbers for the texture coordinate. - float val[2]; - for (int i = 0; i < 2; ++i) { - parser::SkipWhitespace(buffer()); - if (!parser::ParseFloat(buffer(), val + i)) { - *status = Status(Status::DRACO_ERROR, "Failed to parse a float number"); - // The definition is processed so return true. - return true; - } - } - out_point_cloud_->attribute(tex_att_id_) - ->SetAttributeValue(AttributeValueIndex(num_tex_coords_), val); - } - ++num_tex_coords_; - parser::SkipLine(buffer()); - return true; -} - -bool ObjDecoder::ParseFace(Status *status) { - char c; - if (!buffer()->Peek(&c)) { - return false; - } - if (c != 'f') { - return false; - } - // Face definition found! - buffer()->Advance(1); - if (!counting_mode_) { - std::array<int32_t, 3> indices[4]; - // Parse face indices (we try to look for up to four to support quads). - int num_valid_indices = 0; - for (int i = 0; i < 4; ++i) { - if (!ParseVertexIndices(&indices[i])) { - if (i == 3) { - break; // It's OK if there is no fourth vertex index. - } - *status = Status(Status::DRACO_ERROR, "Failed to parse vertex indices"); - return true; - } - ++num_valid_indices; - } - // Process the first face. - for (int i = 0; i < 3; ++i) { - const PointIndex vert_id(3 * num_obj_faces_ + i); - MapPointToVertexIndices(vert_id, indices[i]); - } - ++num_obj_faces_; - if (num_valid_indices == 4) { - // Add an additional triangle for the quad. - // - // 3----2 - // | / | - // | / | - // 0----1 - // - const PointIndex vert_id(3 * num_obj_faces_); - MapPointToVertexIndices(vert_id, indices[0]); - MapPointToVertexIndices(vert_id + 1, indices[2]); - MapPointToVertexIndices(vert_id + 2, indices[3]); - ++num_obj_faces_; - } - } else { - // We are in the counting mode. - // We need to determine how many triangles are in the obj face. - // Go over the line and check how many gaps there are between non-empty - // sub-strings. - parser::SkipWhitespace(buffer()); - int num_indices = 0; - bool is_end = false; - while (buffer()->Peek(&c) && c != '\n') { - if (parser::PeekWhitespace(buffer(), &is_end)) { - buffer()->Advance(1); - } else { - // Non-whitespace reached.. assume it's index declaration, skip it. - num_indices++; - while (!parser::PeekWhitespace(buffer(), &is_end) && !is_end) { - buffer()->Advance(1); - } - } - } - if (num_indices < 3 || num_indices > 4) { - *status = - Status(Status::DRACO_ERROR, "Invalid number of indices on a face"); - return false; - } - // Either one or two new triangles. - num_obj_faces_ += num_indices - 2; - } - parser::SkipLine(buffer()); - return true; -} - -bool ObjDecoder::ParseMaterialLib(Status *status) { - // Allow only one material library per file for now. - if (!material_name_to_id_.empty()) { - return false; - } - std::array<char, 6> c; - if (!buffer()->Peek(&c)) { - return false; - } - if (std::memcmp(&c[0], "mtllib", 6) != 0) { - return false; - } - buffer()->Advance(6); - DecoderBuffer line_buffer = parser::ParseLineIntoDecoderBuffer(buffer()); - parser::SkipWhitespace(&line_buffer); - material_file_name_.clear(); - if (!parser::ParseString(&line_buffer, &material_file_name_)) { - *status = Status(Status::DRACO_ERROR, "Failed to parse material file name"); - return true; - } - parser::SkipLine(&line_buffer); - - if (!material_file_name_.empty()) { - if (!ParseMaterialFile(material_file_name_, status)) { - // Silently ignore problems with material files for now. - return true; - } - } - return true; -} - -bool ObjDecoder::ParseMaterial(Status * /* status */) { - // In second pass, skip when we don't use materials. - if (!counting_mode_ && material_att_id_ < 0) { - return false; - } - std::array<char, 6> c; - if (!buffer()->Peek(&c)) { - return false; - } - if (std::memcmp(&c[0], "usemtl", 6) != 0) { - return false; - } - buffer()->Advance(6); - DecoderBuffer line_buffer = parser::ParseLineIntoDecoderBuffer(buffer()); - parser::SkipWhitespace(&line_buffer); - std::string mat_name; - parser::ParseLine(&line_buffer, &mat_name); - if (mat_name.length() == 0) { - return false; - } - auto it = material_name_to_id_.find(mat_name); - if (it == material_name_to_id_.end()) { - // In first pass, materials found in obj that's not in the .mtl file - // will be added to the list. - last_material_id_ = num_materials_; - material_name_to_id_[mat_name] = num_materials_++; - - return true; - } - last_material_id_ = it->second; - return true; -} - -bool ObjDecoder::ParseObject(Status *status) { - std::array<char, 2> c; - if (!buffer()->Peek(&c)) { - return false; - } - if (std::memcmp(&c[0], "o ", 2) != 0) { - return false; - } - buffer()->Advance(1); - DecoderBuffer line_buffer = parser::ParseLineIntoDecoderBuffer(buffer()); - parser::SkipWhitespace(&line_buffer); - std::string obj_name; - if (!parser::ParseString(&line_buffer, &obj_name)) { - return false; - } - if (obj_name.length() == 0) { - return true; // Ignore empty name entries. - } - auto it = obj_name_to_id_.find(obj_name); - if (it == obj_name_to_id_.end()) { - const int num_obj = static_cast<int>(obj_name_to_id_.size()); - obj_name_to_id_[obj_name] = num_obj; - last_sub_obj_id_ = num_obj; - } else { - last_sub_obj_id_ = it->second; - } - return true; -} - -bool ObjDecoder::ParseVertexIndices(std::array<int32_t, 3> *out_indices) { - // Parsed attribute indices can be in format: - // 1. POS_INDEX - // 2. POS_INDEX/TEX_COORD_INDEX - // 3. POS_INDEX/TEX_COORD_INDEX/NORMAL_INDEX - // 4. POS_INDEX//NORMAL_INDEX - parser::SkipCharacters(buffer(), " \t"); - if (!parser::ParseSignedInt(buffer(), &(*out_indices)[0]) || - (*out_indices)[0] == 0) { - return false; // Position index must be present and valid. - } - (*out_indices)[1] = (*out_indices)[2] = 0; - char ch; - if (!buffer()->Peek(&ch)) { - return true; // It may be OK if we cannot read any more characters. - } - if (ch != '/') { - return true; - } - buffer()->Advance(1); - // Check if we should skip texture index or not. - if (!buffer()->Peek(&ch)) { - return false; // Here, we should be always able to read the next char. - } - if (ch != '/') { - // Must be texture coord index. - if (!parser::ParseSignedInt(buffer(), &(*out_indices)[1]) || - (*out_indices)[1] == 0) { - return false; // Texture index must be present and valid. - } - } - if (!buffer()->Peek(&ch)) { - return true; - } - if (ch == '/') { - buffer()->Advance(1); - // Read normal index. - if (!parser::ParseSignedInt(buffer(), &(*out_indices)[2]) || - (*out_indices)[2] == 0) { - return false; // Normal index must be present and valid. - } - } - return true; -} - -void ObjDecoder::MapPointToVertexIndices( - PointIndex vert_id, const std::array<int32_t, 3> &indices) { - // Use face entries to store mapping between vertex and attribute indices - // (positions, texture coordinates and normal indices). - // Any given index is used when indices[x] != 0. For positive values, the - // point is mapped directly to the specified attribute index. Negative input - // indices indicate addressing from the last element (e.g. -1 is the last - // attribute value of a given type, -2 the second last, etc.). - if (indices[0] > 0) { - out_point_cloud_->attribute(pos_att_id_) - ->SetPointMapEntry(vert_id, AttributeValueIndex(indices[0] - 1)); - } else if (indices[0] < 0) { - out_point_cloud_->attribute(pos_att_id_) - ->SetPointMapEntry(vert_id, - AttributeValueIndex(num_positions_ + indices[0])); - } - - if (tex_att_id_ >= 0) { - if (indices[1] > 0) { - out_point_cloud_->attribute(tex_att_id_) - ->SetPointMapEntry(vert_id, AttributeValueIndex(indices[1] - 1)); - } else if (indices[1] < 0) { - out_point_cloud_->attribute(tex_att_id_) - ->SetPointMapEntry(vert_id, - AttributeValueIndex(num_tex_coords_ + indices[1])); - } else { - // Texture index not provided but expected. Insert 0 entry as the - // default value. - out_point_cloud_->attribute(tex_att_id_) - ->SetPointMapEntry(vert_id, AttributeValueIndex(0)); - } - } - - if (norm_att_id_ >= 0) { - if (indices[2] > 0) { - out_point_cloud_->attribute(norm_att_id_) - ->SetPointMapEntry(vert_id, AttributeValueIndex(indices[2] - 1)); - } else if (indices[2] < 0) { - out_point_cloud_->attribute(norm_att_id_) - ->SetPointMapEntry(vert_id, - AttributeValueIndex(num_normals_ + indices[2])); - } else { - // Normal index not provided but expected. Insert 0 entry as the default - // value. - out_point_cloud_->attribute(norm_att_id_) - ->SetPointMapEntry(vert_id, AttributeValueIndex(0)); - } - } - - // Assign material index to the point if it is available. - if (material_att_id_ >= 0) { - out_point_cloud_->attribute(material_att_id_) - ->SetPointMapEntry(vert_id, AttributeValueIndex(last_material_id_)); - } - - // Assign sub-object index to the point if it is available. - if (sub_obj_att_id_ >= 0) { - out_point_cloud_->attribute(sub_obj_att_id_) - ->SetPointMapEntry(vert_id, AttributeValueIndex(last_sub_obj_id_)); - } -} - -bool ObjDecoder::ParseMaterialFile(const std::string &file_name, - Status *status) { - const std::string full_path = GetFullPath(file_name, input_file_name_); - std::vector<char> buffer; - if (!ReadFileToBuffer(full_path, &buffer)) { - return false; - } - - // Backup the original decoder buffer. - DecoderBuffer old_buffer = buffer_; - - buffer_.Init(buffer.data(), buffer.size()); - - num_materials_ = 0; - while (ParseMaterialFileDefinition(status)) { - } - - // Restore the original buffer. - buffer_ = old_buffer; - return true; -} - -bool ObjDecoder::ParseMaterialFileDefinition(Status * /* status */) { - char c; - parser::SkipWhitespace(buffer()); - if (!buffer()->Peek(&c)) { - // End of file reached?. - return false; - } - if (c == '#') { - // Comment, ignore the line. - parser::SkipLine(buffer()); - return true; - } - std::string str; - if (!parser::ParseString(buffer(), &str)) { - return false; - } - if (str == "newmtl") { - parser::SkipWhitespace(buffer()); - parser::ParseLine(buffer(), &str); - if (str.empty()) { - return false; - } - // Add new material to our map. - material_name_to_id_[str] = num_materials_++; - } - return true; -} - -} // namespace draco |