Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Schmithüsen <UX3D-schmithuesen>2019-04-11 12:26:23 +0300
committerBrecht Van Lommel <brechtvanlommel@gmail.com>2019-04-11 13:04:53 +0300
commit4bad4bfc6ae5a81c44038cb1259f44befbb3afe0 (patch)
tree9b196d3ed0466406ba85441ea2314bedaeaea783 /extern/draco/dracoenc/src/draco/io/obj_encoder.cc
parenta9d6356fee28d3567e956415a8eb08ab0bb7a0ab (diff)
glTF: add Draco shared library for mesh compression.
Draco is added as a library under extern/ and builds a shared library that is installed into the Python site-packages. This is then loaded by the glTF add-on to do mesh compression. Differential Revision: https://developer.blender.org/D4501
Diffstat (limited to 'extern/draco/dracoenc/src/draco/io/obj_encoder.cc')
-rw-r--r--extern/draco/dracoenc/src/draco/io/obj_encoder.cc314
1 files changed, 314 insertions, 0 deletions
diff --git a/extern/draco/dracoenc/src/draco/io/obj_encoder.cc b/extern/draco/dracoenc/src/draco/io/obj_encoder.cc
new file mode 100644
index 00000000000..807506e3536
--- /dev/null
+++ b/extern/draco/dracoenc/src/draco/io/obj_encoder.cc
@@ -0,0 +1,314 @@
+// 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_encoder.h"
+
+#include <fstream>
+
+#include "draco/metadata/geometry_metadata.h"
+
+namespace draco {
+
+ObjEncoder::ObjEncoder()
+ : pos_att_(nullptr),
+ tex_coord_att_(nullptr),
+ normal_att_(nullptr),
+ material_att_(nullptr),
+ sub_obj_att_(nullptr),
+ out_buffer_(nullptr),
+ in_point_cloud_(nullptr),
+ in_mesh_(nullptr),
+ current_sub_obj_id_(-1),
+ current_material_id_(-1) {}
+
+bool ObjEncoder::EncodeToFile(const PointCloud &pc,
+ const std::string &file_name) {
+ std::ofstream file(file_name);
+ if (!file)
+ return false; // File could not be opened.
+ file_name_ = file_name;
+ // Encode the mesh into a buffer.
+ EncoderBuffer buffer;
+ if (!EncodeToBuffer(pc, &buffer))
+ return false;
+ // Write the buffer into the file.
+ file.write(buffer.data(), buffer.size());
+ return true;
+}
+
+bool ObjEncoder::EncodeToFile(const Mesh &mesh, const std::string &file_name) {
+ in_mesh_ = &mesh;
+ return EncodeToFile(static_cast<const PointCloud &>(mesh), file_name);
+}
+
+bool ObjEncoder::EncodeToBuffer(const PointCloud &pc,
+ EncoderBuffer *out_buffer) {
+ in_point_cloud_ = &pc;
+ out_buffer_ = out_buffer;
+ if (!EncodeInternal())
+ return ExitAndCleanup(false);
+ return ExitAndCleanup(true);
+}
+
+bool ObjEncoder::EncodeToBuffer(const Mesh &mesh, EncoderBuffer *out_buffer) {
+ in_mesh_ = &mesh;
+ return EncodeToBuffer(static_cast<const PointCloud &>(mesh), out_buffer);
+}
+
+bool ObjEncoder::EncodeInternal() {
+ pos_att_ = nullptr;
+ tex_coord_att_ = nullptr;
+ normal_att_ = nullptr;
+ material_att_ = nullptr;
+ sub_obj_att_ = nullptr;
+ current_sub_obj_id_ = -1;
+ current_material_id_ = -1;
+ if (!GetSubObjects())
+ return false;
+ if (!EncodeMaterialFileName())
+ return false;
+ if (!EncodePositions())
+ return false;
+ if (!EncodeTextureCoordinates())
+ return false;
+ if (!EncodeNormals())
+ return false;
+ if (in_mesh_ && !EncodeFaces())
+ return false;
+ return true;
+}
+
+bool ObjEncoder::ExitAndCleanup(bool return_value) {
+ in_mesh_ = nullptr;
+ in_point_cloud_ = nullptr;
+ out_buffer_ = nullptr;
+ pos_att_ = nullptr;
+ tex_coord_att_ = nullptr;
+ normal_att_ = nullptr;
+ material_att_ = nullptr;
+ sub_obj_att_ = nullptr;
+ current_sub_obj_id_ = -1;
+ current_material_id_ = -1;
+ file_name_.clear();
+ return return_value;
+}
+
+bool ObjEncoder::GetSubObjects() {
+ const GeometryMetadata *pc_metadata = in_point_cloud_->GetMetadata();
+ if (!pc_metadata)
+ return true;
+ const AttributeMetadata *sub_obj_metadata =
+ pc_metadata->GetAttributeMetadataByStringEntry("name", "sub_obj");
+ if (!sub_obj_metadata)
+ return true;
+ sub_obj_id_to_name_.clear();
+ for (const auto &entry : sub_obj_metadata->entries()) {
+ // Sub-object id must be int.
+ int value = 0;
+ if (!entry.second.GetValue(&value))
+ continue;
+ sub_obj_id_to_name_[value] = entry.first;
+ }
+ sub_obj_att_ = in_point_cloud_->GetAttributeByUniqueId(
+ sub_obj_metadata->att_unique_id());
+ if (sub_obj_att_ == nullptr || sub_obj_att_->size() == 0)
+ return false;
+ return true;
+}
+
+bool ObjEncoder::EncodeMaterialFileName() {
+ const GeometryMetadata *pc_metadata = in_point_cloud_->GetMetadata();
+ const AttributeMetadata *material_metadata = nullptr;
+ if (pc_metadata) {
+ material_metadata =
+ pc_metadata->GetAttributeMetadataByStringEntry("name", "material");
+ }
+ std::string material_file_name;
+ std::string material_full_path;
+ if (!material_metadata)
+ return true;
+ if (!material_metadata->GetEntryString("file_name", &material_file_name))
+ return false;
+ buffer()->Encode("mtllib ", 7);
+ buffer()->Encode(material_file_name.c_str(), material_file_name.size());
+ buffer()->Encode("\n", 1);
+ material_id_to_name_.clear();
+ for (const auto &entry : material_metadata->entries()) {
+ // Material id must be int.
+ int value = 0;
+ // Found entry that are not material id, e.g. file name as a string.
+ if (!entry.second.GetValue(&value))
+ continue;
+ material_id_to_name_[value] = entry.first;
+ }
+ material_att_ = in_point_cloud_->GetAttributeByUniqueId(
+ material_metadata->att_unique_id());
+ if (material_att_ == nullptr || material_att_->size() == 0)
+ return false;
+ return true;
+}
+
+bool ObjEncoder::EncodePositions() {
+ const PointAttribute *const att =
+ in_point_cloud_->GetNamedAttribute(GeometryAttribute::POSITION);
+ if (att == nullptr || att->size() == 0)
+ return false; // Position attribute must be valid.
+ std::array<float, 3> value;
+ for (AttributeValueIndex i(0); i < static_cast<uint32_t>(att->size()); ++i) {
+ if (!att->ConvertValue<float, 3>(i, &value[0]))
+ return false;
+ buffer()->Encode("v ", 2);
+ EncodeFloatList(&value[0], 3);
+ buffer()->Encode("\n", 1);
+ }
+ pos_att_ = att;
+ return true;
+}
+
+bool ObjEncoder::EncodeTextureCoordinates() {
+ const PointAttribute *const att =
+ in_point_cloud_->GetNamedAttribute(GeometryAttribute::TEX_COORD);
+ if (att == nullptr || att->size() == 0)
+ return true; // It's OK if we don't have texture coordinates.
+ std::array<float, 2> value;
+ for (AttributeValueIndex i(0); i < static_cast<uint32_t>(att->size()); ++i) {
+ if (!att->ConvertValue<float, 2>(i, &value[0]))
+ return false;
+ buffer()->Encode("vt ", 3);
+ EncodeFloatList(&value[0], 2);
+ buffer()->Encode("\n", 1);
+ }
+ tex_coord_att_ = att;
+ return true;
+}
+
+bool ObjEncoder::EncodeNormals() {
+ const PointAttribute *const att =
+ in_point_cloud_->GetNamedAttribute(GeometryAttribute::NORMAL);
+ if (att == nullptr || att->size() == 0)
+ return true; // It's OK if we don't have normals.
+ std::array<float, 3> value;
+ for (AttributeValueIndex i(0); i < static_cast<uint32_t>(att->size()); ++i) {
+ if (!att->ConvertValue<float, 3>(i, &value[0]))
+ return false;
+ buffer()->Encode("vn ", 3);
+ EncodeFloatList(&value[0], 3);
+ buffer()->Encode("\n", 1);
+ }
+ normal_att_ = att;
+ return true;
+}
+
+bool ObjEncoder::EncodeFaces() {
+ for (FaceIndex i(0); i < in_mesh_->num_faces(); ++i) {
+ if (sub_obj_att_)
+ if (!EncodeSubObject(i))
+ return false;
+ if (material_att_)
+ if (!EncodeMaterial(i))
+ return false;
+ buffer()->Encode('f');
+ for (int j = 0; j < 3; ++j) {
+ if (!EncodeFaceCorner(i, j))
+ return false;
+ }
+ buffer()->Encode("\n", 1);
+ }
+ return true;
+}
+
+bool ObjEncoder::EncodeMaterial(FaceIndex face_id) {
+ int material_id = 0;
+ // Pick the first corner, all corners of a face should have same id.
+ const PointIndex vert_index = in_mesh_->face(face_id)[0];
+ const AttributeValueIndex index_id(material_att_->mapped_index(vert_index));
+ if (!material_att_->ConvertValue<int>(index_id, &material_id)) {
+ return false;
+ }
+
+ if (material_id != current_material_id_) {
+ // Update material information.
+ buffer()->Encode("usemtl ", 7);
+ const auto mat_ptr = material_id_to_name_.find(material_id);
+ // If the material id is not found.
+ if (mat_ptr == material_id_to_name_.end())
+ return false;
+ buffer()->Encode(mat_ptr->second.c_str(), mat_ptr->second.size());
+ buffer()->Encode("\n", 1);
+ current_material_id_ = material_id;
+ }
+ return true;
+}
+
+bool ObjEncoder::EncodeSubObject(FaceIndex face_id) {
+ int sub_obj_id = 0;
+ // Pick the first corner, all corners of a face should have same id.
+ const PointIndex vert_index = in_mesh_->face(face_id)[0];
+ const AttributeValueIndex index_id(sub_obj_att_->mapped_index(vert_index));
+ if (!sub_obj_att_->ConvertValue<int>(index_id, &sub_obj_id)) {
+ return false;
+ }
+ if (sub_obj_id != current_sub_obj_id_) {
+ buffer()->Encode("o ", 2);
+ const auto sub_obj_ptr = sub_obj_id_to_name_.find(sub_obj_id);
+ if (sub_obj_ptr == sub_obj_id_to_name_.end())
+ return false;
+ buffer()->Encode(sub_obj_ptr->second.c_str(), sub_obj_ptr->second.size());
+ buffer()->Encode("\n", 1);
+ current_sub_obj_id_ = sub_obj_id;
+ }
+ return true;
+}
+
+bool ObjEncoder::EncodeFaceCorner(FaceIndex face_id, int local_corner_id) {
+ buffer()->Encode(' ');
+ const PointIndex vert_index = in_mesh_->face(face_id)[local_corner_id];
+ // Note that in the OBJ format, all indices are encoded starting from index 1.
+ // Encode position index.
+ EncodeInt(pos_att_->mapped_index(vert_index).value() + 1);
+ if (tex_coord_att_ || normal_att_) {
+ // Encoding format is pos_index/tex_coord_index/normal_index.
+ // If tex_coords are not present, we must encode pos_index//normal_index.
+ buffer()->Encode('/');
+ if (tex_coord_att_) {
+ EncodeInt(tex_coord_att_->mapped_index(vert_index).value() + 1);
+ }
+ if (normal_att_) {
+ buffer()->Encode('/');
+ EncodeInt(normal_att_->mapped_index(vert_index).value() + 1);
+ }
+ }
+ return true;
+}
+
+void ObjEncoder::EncodeFloat(float val) {
+ snprintf(num_buffer_, sizeof(num_buffer_), "%f", val);
+ buffer()->Encode(num_buffer_, strlen(num_buffer_));
+}
+
+void ObjEncoder::EncodeFloatList(float *vals, int num_vals) {
+ for (int i = 0; i < num_vals; ++i) {
+ if (i > 0) {
+ buffer()->Encode(' ');
+ }
+ EncodeFloat(vals[i]);
+ }
+}
+
+void ObjEncoder::EncodeInt(int32_t val) {
+ snprintf(num_buffer_, sizeof(num_buffer_), "%d", val);
+ buffer()->Encode(num_buffer_, strlen(num_buffer_));
+}
+
+} // namespace draco