@@ -69,12 +69,20 @@ Status PlyDecoder::DecodeFromBuffer(DecoderBuffer *buffer,
6969Status PlyDecoder::DecodeInternal () {
7070 PlyReader ply_reader;
7171 DRACO_RETURN_IF_ERROR (ply_reader.Read (buffer ()));
72+
73+ const PlyElement *vertex_element = ply_reader.GetElementByName (" vertex" );
74+ if (vertex_element == nullptr ) {
75+ return Status (Status::DRACO_ERROR, " no vertex element" );
76+ }
77+
7278 // First, decode the connectivity data.
73- if (out_mesh_)
74- DRACO_RETURN_IF_ERROR (DecodeFaceData (ply_reader.GetElementByName (" face" )));
79+ if (out_mesh_) {
80+ const int num_vertices = vertex_element->num_entries ();
81+ DRACO_RETURN_IF_ERROR (DecodeFaceData (ply_reader.GetElementByName (" face" ),
82+ num_vertices));
83+ }
7584 // Decode all attributes.
76- DRACO_RETURN_IF_ERROR (
77- DecodeVertexData (ply_reader.GetElementByName (" vertex" )));
85+ DRACO_RETURN_IF_ERROR (DecodeVertexData (vertex_element));
7886 // In case there are no faces this is just a point cloud which does
7987 // not require deduplication.
8088 if (out_mesh_ && out_mesh_->num_faces () != 0 ) {
@@ -91,7 +99,7 @@ Status PlyDecoder::DecodeInternal() {
9199 return OkStatus ();
92100}
93101
94- Status PlyDecoder::DecodeFaceData (const PlyElement *face_element) {
102+ Status PlyDecoder::DecodeFaceData (const PlyElement *face_element, const int num_vertices ) {
95103 // We accept point clouds now.
96104 if (face_element == nullptr ) {
97105 return Status (Status::INVALID_PARAMETER, " face_element is null" );
@@ -133,6 +141,65 @@ Status PlyDecoder::DecodeFaceData(const PlyElement *face_element) {
133141 }
134142 }
135143 out_mesh_->SetNumFaces (face_index.value ());
144+
145+ DecodeFaceTexCoordData (face_element, vertex_indices, num_vertices);
146+
147+ return OkStatus ();
148+ }
149+
150+ // Decodes per-face texture coordinate data into the TEX_COORD attribute.
151+ // When texture coordinates are stored on faces, the same vertex may have
152+ // multiple sets of texture coordinates from different faces. This function
153+ // rewrites the texture coordinates every time the same vertex is encountered
154+ // on a new face, effectively choosing the last coordinate pair encountered
155+ // for each vertex.
156+ Status PlyDecoder::DecodeFaceTexCoordData (
157+ const PlyElement *face_element,
158+ const PlyProperty *vertex_indices,
159+ const int num_vertices) {
160+ if (face_element == nullptr ) {
161+ return Status (Status::INVALID_PARAMETER, " face_element is null" );
162+ }
163+ if (vertex_indices == nullptr ) {
164+ return Status (Status::INVALID_PARAMETER, " vertex_indices is null" );
165+ }
166+
167+ const PlyProperty *texture_coordinates =
168+ face_element->GetPropertyByName (" texcoord" );
169+ if (!texture_coordinates) {
170+ return OkStatus (); // No texture coordinates to decode.
171+ }
172+
173+ // Allocate attribute for texture coordinates.
174+ GeometryAttribute uv_attr;
175+ uv_attr.Init (GeometryAttribute::TEX_COORD, nullptr , 2 , DT_FLOAT32, false , sizeof (float ) * 2 , 0 );
176+ const int uv_att_id = out_point_cloud_->AddAttribute (uv_attr, true , num_vertices);
177+
178+ const int64_t num_polygons = face_element->num_entries ();
179+ PlyPropertyReader<float > uv_reader (texture_coordinates);
180+ PlyPropertyReader<PointIndex::ValueType> vertex_index_reader (vertex_indices);
181+
182+ for (int64_t face_index = 0 ; face_index < num_polygons; ++face_index) {
183+ const int64_t vertex_list_offset = vertex_indices->GetListEntryOffset (face_index);
184+ const int64_t vertex_list_size = vertex_indices->GetListEntryNumValues (face_index);
185+
186+ const int64_t uv_list_offset = texture_coordinates->GetListEntryOffset (face_index);
187+ const int64_t uv_list_size = texture_coordinates->GetListEntryNumValues (face_index);
188+
189+ if (uv_list_size < 2 * vertex_list_size) {
190+ continue ; // Skip invalid uv list. Must have two texture coords per vertex.
191+ }
192+
193+ for (int64_t i = 0 ; i < vertex_list_size; ++i) {
194+ uint32_t vertex_index = vertex_index_reader.ReadValue (static_cast <int >(vertex_list_offset + i));
195+ float uv_value[2 ];
196+ uv_value[0 ] = uv_reader.ReadValue (static_cast <int >(uv_list_offset + i * 2 ));
197+ uv_value[1 ] = uv_reader.ReadValue (static_cast <int >(uv_list_offset + i * 2 + 1 ));
198+ out_point_cloud_->attribute (uv_att_id)->SetAttributeValue (
199+ AttributeValueIndex (vertex_index), uv_value);
200+ }
201+ }
202+
136203 return OkStatus ();
137204}
138205
0 commit comments