@@ -146,6 +146,107 @@ function Base.merge(meshes::AbstractVector{T}) where T <: MetaMesh
146146 return MetaMesh (big_mesh, big_meta)
147147end
148148
149+ # TODO : naming
150+ # synchronize_vertex_attributes
151+ # merge_vertex_(attribute)_indices
152+ # convert(Face, MultiFace)
153+ # ...
154+ function merge_vertex_indices (mesh)
155+ attribs, fs, views = merge_vertex_indices (
156+ vertex_attributes (mesh), faces (mesh), mesh. views)
157+
158+ return Mesh (attribs, fs, views)
159+ end
160+
161+ function merge_vertex_indices (
162+ attribs:: NamedTuple{Names} ,
163+ faces:: AbstractVector{<: MultiFace{N, T, FT, Names}} ,
164+ views:: Vector{UnitRange}
165+ ) where {Names, N, T, FT}
166+
167+ # Note: typing checks for matching Names
168+
169+ if isempty (views)
170+ new_faces, vertex_map = merge_vertex_indices (faces)
171+ new_attribs = ntuple (n -> attribs[n][vertex_map[n]], length (Names))
172+ return NamedTuple {Names} (new_attribs), new_faces, views
173+ end
174+
175+ new_attribs = NamedTuple ((Pair (k, similar (v, 0 )) for (k, v) in pairs (attribs)))
176+ new_faces = similar (faces, FT, 0 )
177+ new_views = UnitRange[]
178+
179+ for idxs in views
180+ # TODO : this depends on T in Face (1 based -> 1, 0 based -> 0)
181+ vertex_index_counter = T (length (new_attribs[1 ]) + 1 )
182+
183+ # Generate new face from current view, with the first vertex_index
184+ # corresponding to the first vertex attribute added in this iteration
185+ face_view = view (faces, idxs)
186+ new_faces_in_view, vertex_map = merge_vertex_indices (face_view, vertex_index_counter)
187+
188+ # update vertex attributes
189+ for (name, indices) in pairs (vertex_map)
190+ append! (new_attribs[name], view (attribs[name], indices))
191+ end
192+
193+ # add new faces and new view
194+ start = length (new_faces) + 1
195+ append! (new_faces, new_faces_in_view)
196+ append! (new_views, start: length (new_faces))
197+ end
198+
199+ return new_attribs, new_faces, new_views
200+ end
201+
202+ function merge_vertex_indices (
203+ faces:: AbstractVector{<: MultiFace{N, T, FT, Names, N_Attrib}} ,
204+ vertex_index_counter = T (1 )
205+ ) where {N, T, FT <: AbstractFace{N, T} , Names, N_Attrib}
206+
207+ N_faces = length (faces)
208+
209+ # maps a combination of old indices in MultiFace to a new vertex_index
210+ vertex_index_map = Dict {NTuple{N_Attrib, T}, T} ()
211+
212+ # Faces after conversion
213+ new_faces = sizehint! (FT[], N_faces)
214+
215+ # indices that remap attributes
216+ attribute_indices = ntuple (n -> sizehint! (UInt32[], N_faces), N_Attrib)
217+
218+ # keep track of the remmaped indices for one vertex so we don't have to
219+ # query the dict twice
220+ temp = zeros (N)
221+
222+ for multi_face in faces
223+
224+ for i in 1 : N
225+ # get the i-th set of vertex indices from multi_face, i.e.
226+ # (multi_face.position_index[i], multi_face.normal_index[i], ...)
227+ vertex = ntuple (n -> multi_face. faces[n][i], N_Attrib)
228+
229+ # if the vertex exists, get it's index
230+ # otherwise register it with the next available vertex index
231+ temp[i] = get! (vertex_index_map, vertex) do
232+ vertex_index_counter += 1
233+ push! .(attribute_indices, vertex)
234+ return vertex_index_counter - 1
235+ end
236+ end
237+
238+ # generate new face
239+ push! (new_faces, FT (temp))
240+ end
241+
242+ # in case we are reserving more than needed
243+ sizehint! (new_faces, length (new_faces))
244+
245+ return new_faces, attribute_indices
246+ end
247+
248+
249+
149250
150251function map_coordinates (f, mesh:: Mesh )
151252 result = copy (mesh)
0 commit comments