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