1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 //      http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License.
12 //
13 #include "draco/maya/draco_maya_plugin.h"
14 
15 #ifdef DRACO_MAYA_PLUGIN
16 
17 namespace draco {
18 namespace maya {
19 
decode_faces(std::unique_ptr<draco::Mesh> & drc_mesh,Drc2PyMesh * out_mesh)20 static void decode_faces(std::unique_ptr<draco::Mesh> &drc_mesh,
21                          Drc2PyMesh *out_mesh) {
22   int num_faces = drc_mesh->num_faces();
23   out_mesh->faces = new int[num_faces * 3];
24   out_mesh->faces_num = num_faces;
25   for (int i = 0; i < num_faces; i++) {
26     const draco::Mesh::Face &face = drc_mesh->face(draco::FaceIndex(i));
27     out_mesh->faces[i * 3 + 0] = face[0].value();
28     out_mesh->faces[i * 3 + 1] = face[1].value();
29     out_mesh->faces[i * 3 + 2] = face[2].value();
30   }
31 }
decode_vertices(std::unique_ptr<draco::Mesh> & drc_mesh,Drc2PyMesh * out_mesh)32 static void decode_vertices(std::unique_ptr<draco::Mesh> &drc_mesh,
33                             Drc2PyMesh *out_mesh) {
34   const auto pos_att =
35       drc_mesh->GetNamedAttribute(draco::GeometryAttribute::POSITION);
36   if (pos_att == nullptr) {
37     out_mesh->vertices = new float[0];
38     out_mesh->vertices_num = 0;
39     return;
40   }
41 
42   int num_vertices = drc_mesh->num_points();
43   out_mesh->vertices = new float[num_vertices * 3];
44   out_mesh->vertices_num = num_vertices;
45   for (int i = 0; i < num_vertices; i++) {
46     draco::PointIndex pi(i);
47     const draco::AttributeValueIndex val_index = pos_att->mapped_index(pi);
48     float out_vertex[3];
49     bool is_ok = pos_att->ConvertValue<float, 3>(val_index, out_vertex);
50     if (!is_ok) return;
51     out_mesh->vertices[i * 3 + 0] = out_vertex[0];
52     out_mesh->vertices[i * 3 + 1] = out_vertex[1];
53     out_mesh->vertices[i * 3 + 2] = out_vertex[2];
54   }
55 }
decode_normals(std::unique_ptr<draco::Mesh> & drc_mesh,Drc2PyMesh * out_mesh)56 static void decode_normals(std::unique_ptr<draco::Mesh> &drc_mesh,
57                            Drc2PyMesh *out_mesh) {
58   const auto normal_att =
59       drc_mesh->GetNamedAttribute(draco::GeometryAttribute::NORMAL);
60   if (normal_att == nullptr) {
61     out_mesh->normals = new float[0];
62     out_mesh->normals_num = 0;
63     return;
64   }
65   int num_normals = drc_mesh->num_points();
66   out_mesh->normals = new float[num_normals * 3];
67   out_mesh->normals_num = num_normals;
68 
69   for (int i = 0; i < num_normals; i++) {
70     draco::PointIndex pi(i);
71     const draco::AttributeValueIndex val_index = normal_att->mapped_index(pi);
72     float out_normal[3];
73     bool is_ok = normal_att->ConvertValue<float, 3>(val_index, out_normal);
74     if (!is_ok) return;
75     out_mesh->normals[i * 3 + 0] = out_normal[0];
76     out_mesh->normals[i * 3 + 1] = out_normal[1];
77     out_mesh->normals[i * 3 + 2] = out_normal[2];
78   }
79 }
decode_uvs(std::unique_ptr<draco::Mesh> & drc_mesh,Drc2PyMesh * out_mesh)80 static void decode_uvs(std::unique_ptr<draco::Mesh> &drc_mesh,
81                        Drc2PyMesh *out_mesh) {
82   const auto uv_att =
83       drc_mesh->GetNamedAttribute(draco::GeometryAttribute::TEX_COORD);
84   if (uv_att == nullptr) {
85     out_mesh->uvs = new float[0];
86     out_mesh->uvs_num = 0;
87     out_mesh->uvs_real_num = 0;
88     return;
89   }
90   int num_uvs = drc_mesh->num_points();
91   out_mesh->uvs = new float[num_uvs * 2];
92   out_mesh->uvs_num = num_uvs;
93   out_mesh->uvs_real_num = uv_att->size();
94 
95   for (int i = 0; i < num_uvs; i++) {
96     draco::PointIndex pi(i);
97     const draco::AttributeValueIndex val_index = uv_att->mapped_index(pi);
98     float out_uv[2];
99     bool is_ok = uv_att->ConvertValue<float, 2>(val_index, out_uv);
100     if (!is_ok) return;
101     out_mesh->uvs[i * 2 + 0] = out_uv[0];
102     out_mesh->uvs[i * 2 + 1] = out_uv[1];
103   }
104 }
105 
drc2py_free(Drc2PyMesh ** mesh_ptr)106 void drc2py_free(Drc2PyMesh **mesh_ptr) {
107   Drc2PyMesh *mesh = *mesh_ptr;
108   if (!mesh) return;
109   if (mesh->faces) {
110     delete[] mesh->faces;
111     mesh->faces = nullptr;
112     mesh->faces_num = 0;
113   }
114   if (mesh->vertices) {
115     delete[] mesh->vertices;
116     mesh->vertices = nullptr;
117     mesh->vertices_num = 0;
118   }
119   if (mesh->normals) {
120     delete[] mesh->normals;
121     mesh->normals = nullptr;
122     mesh->normals_num = 0;
123   }
124   if (mesh->uvs) {
125     delete[] mesh->uvs;
126     mesh->uvs = nullptr;
127     mesh->uvs_num = 0;
128   }
129   delete mesh;
130   *mesh_ptr = nullptr;
131 }
132 
drc2py_decode(char * data,unsigned int length,Drc2PyMesh ** res_mesh)133 DecodeResult drc2py_decode(char *data, unsigned int length,
134                            Drc2PyMesh **res_mesh) {
135   draco::DecoderBuffer buffer;
136   buffer.Init(data, length);
137   auto type_statusor = draco::Decoder::GetEncodedGeometryType(&buffer);
138   if (!type_statusor.ok()) {
139     return DecodeResult::KO_GEOMETRY_TYPE_INVALID;
140   }
141   const draco::EncodedGeometryType geom_type = type_statusor.value();
142   if (geom_type != draco::TRIANGULAR_MESH) {
143     return DecodeResult::KO_TRIANGULAR_MESH_NOT_FOUND;
144   }
145 
146   draco::Decoder decoder;
147   auto statusor = decoder.DecodeMeshFromBuffer(&buffer);
148   if (!statusor.ok()) {
149     return DecodeResult::KO_MESH_DECODING;
150   }
151   std::unique_ptr<draco::Mesh> drc_mesh = std::move(statusor).value();
152 
153   *res_mesh = new Drc2PyMesh();
154   decode_faces(drc_mesh, *res_mesh);
155   decode_vertices(drc_mesh, *res_mesh);
156   decode_normals(drc_mesh, *res_mesh);
157   decode_uvs(drc_mesh, *res_mesh);
158   return DecodeResult::OK;
159 }
160 
161 // As encode references see https://github.com/google/draco/issues/116
drc2py_encode(Drc2PyMesh * in_mesh,char * file_path)162 EncodeResult drc2py_encode(Drc2PyMesh *in_mesh, char *file_path) {
163   if (in_mesh->faces_num == 0) return EncodeResult::KO_WRONG_INPUT;
164   if (in_mesh->vertices_num == 0) return EncodeResult::KO_WRONG_INPUT;
165   // TODO: Add check to protect against quad faces. At the moment only
166   // Triangular faces are supported
167 
168   std::unique_ptr<draco::Mesh> drc_mesh(new draco::Mesh());
169 
170   // Marshall Faces
171   int num_faces = in_mesh->faces_num;
172   drc_mesh->SetNumFaces(num_faces);
173   for (int i = 0; i < num_faces; ++i) {
174     Mesh::Face face;
175     face[0] = in_mesh->faces[i * 3 + 0];
176     face[1] = in_mesh->faces[i * 3 + 1];
177     face[2] = in_mesh->faces[i * 3 + 2];
178     drc_mesh->SetFace(FaceIndex(i), face);
179   }
180 
181   // Marshall Vertices
182   int num_points = in_mesh->vertices_num;
183   drc_mesh->set_num_points(num_points);
184   GeometryAttribute va;
185   va.Init(GeometryAttribute::POSITION, nullptr, 3, DT_FLOAT32, false,
186           sizeof(float) * 3, 0);
187   int pos_att_id = drc_mesh->AddAttribute(va, true, num_points);
188   float point[3];
189   for (int i = 0; i < num_points; ++i) {
190     point[0] = in_mesh->vertices[i * 3 + 0];
191     point[1] = in_mesh->vertices[i * 3 + 1];
192     point[2] = in_mesh->vertices[i * 3 + 2];
193     drc_mesh->attribute(pos_att_id)
194         ->SetAttributeValue(AttributeValueIndex(i), point);
195   }
196 
197   // Marshall Normals
198   int num_normals = in_mesh->normals_num;
199   int norm_att_id;
200   if (num_normals > 0) {
201     GeometryAttribute va;
202     va.Init(GeometryAttribute::NORMAL, nullptr, 3, DT_FLOAT32, false,
203             sizeof(float) * 3, 0);
204     norm_att_id = drc_mesh->AddAttribute(va, true, num_normals);
205 
206     float norm[3];
207     for (int i = 0; i < num_normals; ++i) {
208       norm[0] = in_mesh->normals[i * 3 + 0];
209       norm[1] = in_mesh->normals[i * 3 + 1];
210       norm[2] = in_mesh->normals[i * 3 + 2];
211       drc_mesh->attribute(norm_att_id)
212           ->SetAttributeValue(AttributeValueIndex(i), norm);
213     }
214   }
215 
216   // Marshall Uvs
217   int num_uvs = in_mesh->uvs_num;
218   int uv_att_id;
219   if (num_uvs > 0) {
220     GeometryAttribute va;
221     va.Init(GeometryAttribute::TEX_COORD, nullptr, 2, DT_FLOAT32, false,
222             sizeof(float) * 2, 0);
223     uv_att_id = drc_mesh->AddAttribute(va, true, num_uvs);
224     float uv[3];
225     for (int i = 0; i < num_uvs; ++i) {
226       uv[0] = in_mesh->uvs[i * 2 + 0];
227       uv[1] = in_mesh->uvs[i * 2 + 1];
228       drc_mesh->attribute(uv_att_id)->SetAttributeValue(AttributeValueIndex(i),
229                                                         uv);
230     }
231   }
232 
233 // Deduplicate Attributes and Points
234 #ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED
235   drc_mesh->DeduplicateAttributeValues();
236 #endif
237 #ifdef DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED
238   drc_mesh->DeduplicatePointIds();
239 #endif
240 
241   // Encode Mesh
242   draco::Encoder encoder;  // Use default encode settings (See draco_encoder.cc
243                            // Options struct)
244   draco::EncoderBuffer buffer;
245   const draco::Status status = encoder.EncodeMeshToBuffer(*drc_mesh, &buffer);
246   if (!status.ok()) {
247     // Use status.error_msg() to check the error
248     return EncodeResult::KO_MESH_ENCODING;
249   }
250 
251   // Save to file
252   std::string file = file_path;
253   std::ofstream out_file(file, std::ios::binary);
254   if (!out_file) {
255     return EncodeResult::KO_FILE_CREATION;
256   }
257   out_file.write(buffer.data(), buffer.size());
258   return EncodeResult::OK;
259 }
260 
261 }  // namespace maya
262 
263 }  // namespace draco
264 
265 #endif  // DRACO_MAYA_PLUGIN
266