diff options
Diffstat (limited to 'libs/assimp/contrib/draco/src/draco/io/ply_reader.cc')
-rw-r--r-- | libs/assimp/contrib/draco/src/draco/io/ply_reader.cc | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/libs/assimp/contrib/draco/src/draco/io/ply_reader.cc b/libs/assimp/contrib/draco/src/draco/io/ply_reader.cc new file mode 100644 index 0000000..ea7f268 --- /dev/null +++ b/libs/assimp/contrib/draco/src/draco/io/ply_reader.cc @@ -0,0 +1,312 @@ +// 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/ply_reader.h" + +#include <array> +#include <regex> + +#include "draco/core/status.h" +#include "draco/io/parser_utils.h" +#include "draco/io/ply_property_writer.h" + +namespace draco { + +PlyProperty::PlyProperty(const std::string &name, DataType data_type, + DataType list_type) + : name_(name), data_type_(data_type), list_data_type_(list_type) { + data_type_num_bytes_ = DataTypeLength(data_type); + list_data_type_num_bytes_ = DataTypeLength(list_type); +} + +PlyElement::PlyElement(const std::string &name, int64_t num_entries) + : name_(name), num_entries_(num_entries) {} + +PlyReader::PlyReader() : format_(kLittleEndian) {} + +Status PlyReader::Read(DecoderBuffer *buffer) { + std::string value; + // The first line needs to by "ply". + if (!parser::ParseString(buffer, &value) || value != "ply") { + return Status(Status::INVALID_PARAMETER, "Not a valid ply file"); + } + parser::SkipLine(buffer); + + // The second line needs to be the format of the ply file. + parser::ParseLine(buffer, &value); + std::string format, version; + const std::vector<std::string> words = SplitWords(value); + if (words.size() >= 3 && words[0] == "format") { + format = words[1]; + version = words[2]; + } else { + return Status(Status::INVALID_PARAMETER, "Missing or wrong format line"); + } + if (version != "1.0") { + return Status(Status::UNSUPPORTED_VERSION, "Unsupported PLY version"); + } + if (format == "binary_big_endian") { + return Status(Status::UNSUPPORTED_VERSION, + "Unsupported format. Currently we support only ascii and" + " binary_little_endian format."); + } + if (format == "ascii") { + format_ = kAscii; + } else { + format_ = kLittleEndian; + } + DRACO_RETURN_IF_ERROR(ParseHeader(buffer)); + if (!ParsePropertiesData(buffer)) { + return Status(Status::INVALID_PARAMETER, "Couldn't parse properties"); + } + return OkStatus(); +} + +Status PlyReader::ParseHeader(DecoderBuffer *buffer) { + while (true) { + DRACO_ASSIGN_OR_RETURN(bool end, ParseEndHeader(buffer)); + if (end) { + break; + } + if (ParseElement(buffer)) { + continue; + } + DRACO_ASSIGN_OR_RETURN(bool property_parsed, ParseProperty(buffer)); + if (property_parsed) { + continue; + } + parser::SkipLine(buffer); + } + return OkStatus(); +} + +StatusOr<bool> PlyReader::ParseEndHeader(DecoderBuffer *buffer) { + parser::SkipWhitespace(buffer); + std::array<char, 10> c; + if (!buffer->Peek(&c)) { + return Status(Status::INVALID_PARAMETER, + "End of file reached before the end_header"); + } + if (std::memcmp(&c[0], "end_header", 10) != 0) { + return false; + } + parser::SkipLine(buffer); + return true; +} + +bool PlyReader::ParseElement(DecoderBuffer *buffer) { + DecoderBuffer line_buffer(*buffer); + std::string line; + parser::ParseLine(&line_buffer, &line); + + std::string element_name; + int64_t count; + const std::vector<std::string> words = SplitWords(line); + if (words.size() >= 3 && words[0] == "element") { + element_name = words[1]; + const std::string count_str = words[2]; + count = strtoll(count_str.c_str(), nullptr, 10); + } else { + return false; + } + element_index_[element_name] = static_cast<uint32_t>(elements_.size()); + elements_.emplace_back(PlyElement(element_name, count)); + *buffer = line_buffer; + return true; +} + +StatusOr<bool> PlyReader::ParseProperty(DecoderBuffer *buffer) { + if (elements_.empty()) { + return false; // Ignore properties if there is no active element. + } + DecoderBuffer line_buffer(*buffer); + std::string line; + parser::ParseLine(&line_buffer, &line); + + std::string data_type_str, list_type_str, property_name; + bool property_search = false; + const std::vector<std::string> words = SplitWords(line); + if (words.size() >= 3 && words[0] == "property" && words[1] != "list") { + property_search = true; + data_type_str = words[1]; + property_name = words[2]; + } + + bool property_list_search = false; + if (words.size() >= 5 && words[0] == "property" && words[1] == "list") { + property_list_search = true; + list_type_str = words[2]; + data_type_str = words[3]; + property_name = words[4]; + } + if (!property_search && !property_list_search) { + return false; + } + const DataType data_type = GetDataTypeFromString(data_type_str); + if (data_type == DT_INVALID) { + return Status(Status::INVALID_PARAMETER, "Wrong property data type"); + } + DataType list_type = DT_INVALID; + if (property_list_search) { + list_type = GetDataTypeFromString(list_type_str); + if (list_type == DT_INVALID) { + return Status(Status::INVALID_PARAMETER, "Wrong property list type"); + } + } + elements_.back().AddProperty( + PlyProperty(property_name, data_type, list_type)); + *buffer = line_buffer; + return true; +} + +bool PlyReader::ParsePropertiesData(DecoderBuffer *buffer) { + for (int i = 0; i < static_cast<int>(elements_.size()); ++i) { + if (format_ == kLittleEndian) { + if (!ParseElementData(buffer, i)) { + return false; + } + } else if (format_ == kAscii) { + if (!ParseElementDataAscii(buffer, i)) { + return false; + } + } + } + return true; +} + +bool PlyReader::ParseElementData(DecoderBuffer *buffer, int element_index) { + PlyElement &element = elements_[element_index]; + for (int entry = 0; entry < element.num_entries(); ++entry) { + for (int i = 0; i < element.num_properties(); ++i) { + PlyProperty &prop = element.property(i); + if (prop.is_list()) { + // Parse the number of entries for the list element. + int64_t num_entries = 0; + buffer->Decode(&num_entries, prop.list_data_type_num_bytes()); + // Store offset to the main data entry. + prop.list_data_.push_back(prop.data_.size() / + prop.data_type_num_bytes_); + // Store the number of entries. + prop.list_data_.push_back(num_entries); + // Read and store the actual property data + const int64_t num_bytes_to_read = + prop.data_type_num_bytes() * num_entries; + prop.data_.insert(prop.data_.end(), buffer->data_head(), + buffer->data_head() + num_bytes_to_read); + buffer->Advance(num_bytes_to_read); + } else { + // Non-list property + prop.data_.insert(prop.data_.end(), buffer->data_head(), + buffer->data_head() + prop.data_type_num_bytes()); + buffer->Advance(prop.data_type_num_bytes()); + } + } + } + return true; +} + +bool PlyReader::ParseElementDataAscii(DecoderBuffer *buffer, + int element_index) { + PlyElement &element = elements_[element_index]; + for (int entry = 0; entry < element.num_entries(); ++entry) { + for (int i = 0; i < element.num_properties(); ++i) { + PlyProperty &prop = element.property(i); + PlyPropertyWriter<double> prop_writer(&prop); + int32_t num_entries = 1; + if (prop.is_list()) { + parser::SkipWhitespace(buffer); + // Parse the number of entries for the list element. + if (!parser::ParseSignedInt(buffer, &num_entries)) { + return false; + } + + // Store offset to the main data entry. + prop.list_data_.push_back(prop.data_.size() / + prop.data_type_num_bytes_); + // Store the number of entries. + prop.list_data_.push_back(num_entries); + } + // Read and store the actual property data. + for (int v = 0; v < num_entries; ++v) { + parser::SkipWhitespace(buffer); + if (prop.data_type() == DT_FLOAT32 || prop.data_type() == DT_FLOAT64) { + float val; + if (!parser::ParseFloat(buffer, &val)) { + return false; + } + prop_writer.PushBackValue(val); + } else { + int32_t val; + if (!parser::ParseSignedInt(buffer, &val)) { + return false; + } + prop_writer.PushBackValue(val); + } + } + } + } + return true; +} + +std::vector<std::string> PlyReader::SplitWords(const std::string &line) { + std::vector<std::string> output; + std::string::size_type start = 0; + std::string::size_type end = 0; + + // Check for isspace chars. + while ((end = line.find_first_of(" \t\n\v\f\r", start)) != + std::string::npos) { + const std::string word(line.substr(start, end - start)); + if (!std::all_of(word.begin(), word.end(), isspace)) { + output.push_back(word); + } + start = end + 1; + } + + const std::string last_word(line.substr(start)); + if (!std::all_of(last_word.begin(), last_word.end(), isspace)) { + output.push_back(last_word); + } + return output; +} + +DataType PlyReader::GetDataTypeFromString(const std::string &name) const { + if (name == "char" || name == "int8") { + return DT_INT8; + } + if (name == "uchar" || name == "uint8") { + return DT_UINT8; + } + if (name == "short" || name == "int16") { + return DT_INT16; + } + if (name == "ushort" || name == "uint16") { + return DT_UINT16; + } + if (name == "int" || name == "int32") { + return DT_INT32; + } + if (name == "uint" || name == "uint32") { + return DT_UINT32; + } + if (name == "float" || name == "float32") { + return DT_FLOAT32; + } + if (name == "double" || name == "float64") { + return DT_FLOAT64; + } + return DT_INVALID; +} + +} // namespace draco |