@@ -27,12 +27,11 @@ function mesh(primitive::AbstractGeometry; pointtype=Point, facetype=GLTriangleF
2727        if  _f isa  AbstractVector{<:  MultiFace }
2828            if  facetype isa  MultiFace
2929                #  drop faces that facetype doesn't include
30-                 names =  propertynames (facetype)
31-                 _f =  map (f ->  MultiFace {names} (getproperty .((f,), names)), _f)
30+                 _f =  simplify_faces (facetype, _f)
3231            else 
3332                #  drop faces for vertex attributes that aren't given
3433                names =  (:position , keys (vertex_attributes)... )
35-                 _f2 =  map (f  ->   MultiFace { names} ( getproperty .((f,), names)) , _f)
34+                 _f2 =  simplify_faces ( names, _f)
3635
3736                #  and remap to a simple face type so that decompose can handle the rest
3837                _f, mappings =  merge_vertex_indices (_f2)
@@ -47,7 +46,6 @@ function mesh(primitive::AbstractGeometry; pointtype=Point, facetype=GLTriangleF
4746    return  Mesh (positions, f; vertex_attributes... )
4847end 
4948
50- 
5149const  SimpleMesh{N, T, FT} =  Mesh{N, T, FT, (:position ,), Tuple{Vector{Point{N, T}}}, Vector{FT}}
5250const  SimpleTriangleMesh{N} =  SimpleMesh{N, Float32, GLTriangleFace}
5351
@@ -123,41 +121,131 @@ function volume(mesh::Mesh)
123121    return  sum (volume, mesh)
124122end 
125123
124+ #  TODO : Is this ok as "public" function?
125+ #  MultiFace(f1, f2, f3) + (o1, o2, o3) = MultiFace(f1 + o1, f2 + o2, f3 + o3)
126+ function  Base.:+ (f:: MultiFace{N, T, FT, Names, M} , o:: NTuple{M, T} ) where  {N, T, FT, Names, M}
127+     return  MultiFace {Names} (ntuple (m ->  f[m] +  o[m], M))
128+ end 
129+ 
126130function  Base. merge (meshes:: AbstractVector{<:Mesh} )
127131    return  if  isempty (meshes)
128132        return  Mesh (Point3f[], GLTriangleFace[])
129133    elseif  length (meshes) ==  1 
130134        return  meshes[1 ]
131135    else 
132-         ps =  reduce (vcat, coordinates .(meshes))
133-         fs =  reduce (vcat, faces .(meshes))
134-         idx =  length (faces (meshes[1 ]))
135-         offset =  length (coordinates (meshes[1 ]))
136-         for  mesh in  Iterators. drop (meshes, 1 )
137-             N =  length (faces (mesh))
138-             for  i =  idx .+  (1 : N)
139-                 fs[i] =  fs[i] .+  offset
140-             end 
141-             idx +=  N
142-             offset +=  length (coordinates (mesh))
136+ 
137+         m1 =  meshes[1 ]
138+ 
139+         #  Check that all meshes use the same VertexAttributes
140+         #  Could also do this via typing the function, but maybe error is nice?
141+         names =  propertynames (m1. vertex_attributes)
142+         idx =  findfirst (m ->  propertynames (m. vertex_attributes) !=  names, meshes)
143+         if  idx != =  nothing 
144+             error (
145+                 " Cannot merge meshes with different vertex attributes. "   *  
146+                 " First missmatch between meshes[1] with $names  and "   *  
147+                 " meshes[$idx ] with $(propertynames (meshes[idx])) ." 
148+             )
143149        end 
144-         return  Mesh (ps, fs)
145-     end 
146- end 
147150
148- function  Base. merge (meshes:: AbstractVector{T} ) where  T <:  MetaMesh 
149-     isempty (meshes) &&  return  T (Point3f[], GLTriangleFace[])
150-     big_mesh =  merge (map (Mesh, meshes))
151-     big_meta =  deepcopy (meta (meshes[1 ]))
152-     for  mesh in  Iterators. drop (meshes, 1 )
153-         mm =  meta (mesh)
154-         for  (k, v) in  pairs (mm)
155-             append! (big_meta[k], v)
151+         #  We can't merge MultiFace with standard faces because MutliFace allows
152+         #  desynchronizes vertex indices that normal faces assume synchronized.
153+         is_multi =  facetype (m1) <:  MultiFace 
154+ 
155+         if  all (m ->  is_multi ==  (facetype (m) <:  MultiFace ), meshes)
156+ 
157+             #  All the same kind of face, can just merge
158+ 
159+             new_attribs =  NamedTuple {names} (map (names) do  name
160+                 return  mapreduce (m ->  getproperty (m, name), vcat, meshes)
161+             end )
162+             fs =  reduce (vcat, faces .(meshes))
163+ 
164+             #  TODO : is the type difference in offset bad?
165+             idx =  length (faces (m1))
166+             offset =  is_multi ?  length .(values (vertex_attributes (m1))) :  length (coordinates (m1))
167+             views =  isempty (m1. views) ?  [1 : idx] :  copy (m1. views)
168+             
169+             for  mesh in  Iterators. drop (meshes, 1 )
170+                 #  update face indices
171+                 N =  length (faces (mesh))
172+                 for  i =  idx .+  (1 : N)
173+                     fs[i] =  fs[i] +  offset
174+                 end 
175+ 
176+                 #  add views
177+                 if  isempty (mesh. views)
178+                     push! (views, idx+ 1  :  idx+ N)
179+                 else 
180+                     append! (views, (view +  idx for  view in  mesh. views))
181+                 end 
182+     
183+                 idx +=  N
184+                 if  is_multi
185+                     offset =  offset .+  length .(values (vertex_attributes (mesh)))
186+                 else 
187+                     offset +=  length (coordinates (mesh))
188+                 end 
189+             end 
190+ 
191+             return  Mesh (new_attribs, fs, views)
192+ 
193+         else 
194+ 
195+             #  TODO : find simplest face type to target
196+ 
197+             #  Varying ace types, need to convert MultiFace
198+             new_attribs =  NamedTuple {names} (similar .(values (vertex_attributes (m1)), 0 ))
199+             FT =  facetype (m1) <:  MultiFace  ?  eltype (facetype (m1)) :  facetype (m1)
200+             remapped_faces =  []
201+             new_views =  UnitRange{Int}[]
202+             vertex_index_counter =  eltype (FT)(1 )
203+ 
204+             for  mesh in  meshes
205+                 #  convert MultiFace mesh to normal faces, synchronizing vertex indices
206+                 attribs, fs, views =  merge_vertex_indices (
207+                     vertex_attributes (mesh), faces (mesh), mesh. views, vertex_index_counter)
208+                 
209+                 #  increment first vertex index used by faces of the next iteration
210+                 vertex_index_counter +=  length (attribs[1 ])
211+                 
212+                 #  update merged data
213+                 for  name in  names
214+                     append! (new_attribs[name], attribs[name])
215+                 end 
216+ 
217+                 push! (remapped_faces, fs)
218+ 
219+                 if  isempty (views)
220+                     push! (new_views, 1 : length (fs))
221+                 else  
222+                     append! (new_views, views)
223+                 end 
224+             end 
225+ 
226+             #  We did MultiFace -> normal face, now equalize normal face types
227+             new_faces =  reduce (vcat, remapped_faces)
228+ 
229+             return  Mesh (new_attribs, new_faces, new_views)
156230        end 
231+ 
157232    end 
158-     return  MetaMesh (big_mesh, big_meta)
159233end 
160234
235+ #  TODO : Probably not our problem
236+ #  function Base.merge(meshes::AbstractVector{T}) where T <: MetaMesh
237+ #      isempty(meshes) && return T(Point3f[], GLTriangleFace[])
238+ #      big_mesh = merge(map(Mesh, meshes))
239+ #      big_meta = deepcopy(meta(meshes[1]))
240+ #      for mesh in Iterators.drop(meshes, 1)
241+ #          mm = meta(mesh)
242+ #          for (k, v) in pairs(mm)
243+ #              append!(big_meta[k], v)
244+ #          end
245+ #      end
246+ #      return MetaMesh(big_mesh, big_meta)
247+ #  end
248+ 
161249#  TODO : naming
162250#  synchronize_vertex_attributes
163251#  merge_vertex_(attribute)_indices
@@ -170,10 +258,28 @@ function merge_vertex_indices(mesh)
170258    return  Mesh (attribs, fs, views)
171259end 
172260
261+ function  merge_vertex_indices (
262+         attribs:: NamedTuple{Names} , 
263+         faces:: AbstractVector{<: FT} ,
264+         views:: Vector{UnitRange{Int}} ,
265+         vertex_index_counter =  nothing 
266+     ) where  {Names, FT <:  AbstractFace }
267+ 
268+     if  FT <:  MultiFace 
269+         error (
270+             " Failed to call correct method. This likely happened because vertex "   * 
271+             " attributes names $Names  do not match face name $(propertynames (first (faces))) ." 
272+         )
273+     end 
274+ 
275+     return  attribs, faces, views
276+ end 
277+ 
173278function  merge_vertex_indices (
174279        attribs:: NamedTuple{Names} , 
175280        faces:: AbstractVector{<: MultiFace{N, T, FT, Names}} ,
176-         views:: Vector{UnitRange} 
281+         views:: Vector{UnitRange{Int}} ,
282+         vertex_index_counter =  T (1 ) #  TODO : test 0 vs 1 base
177283    ) where  {Names, N, T, FT}
178284
179285    #  Note: typing checks for matching Names
@@ -186,17 +292,16 @@ function merge_vertex_indices(
186292
187293    new_attribs =  NamedTuple ((Pair (k, similar (v, 0 )) for  (k, v) in  pairs (attribs)))
188294    new_faces =  similar (faces, FT, 0 )
189-     new_views =  UnitRange[]
295+     new_views =  UnitRange{Int} []
190296
297+     #  TODO : this depends on T in Face (1 based -> 1, 0 based -> 0)
191298    for  idxs in  views
192-         #  TODO : this depends on T in Face (1 based -> 1, 0 based -> 0)
193-         vertex_index_counter =  T (length (new_attribs[1 ]) +  1 )
194- 
195299        #  Generate new face from current view, with the first vertex_index 
196300        #  corresponding to the first vertex attribute added in this iteration
197301        face_view =  view (faces, idxs)
198302        new_faces_in_view, vertex_map =  merge_vertex_indices (face_view, vertex_index_counter)
199-         
303+         vertex_index_counter +=  length (vertex_map)
304+ 
200305        #  update vertex attributes
201306        for  (name, indices) in  pairs (vertex_map)
202307            append! (new_attribs[name], view (attribs[name], indices))
@@ -211,6 +316,17 @@ function merge_vertex_indices(
211316    return  new_attribs, new_faces, new_views
212317end 
213318
319+ function  merge_vertex_indices (
320+         faces:: AbstractVector{FT} ,
321+         vertex_index_counter =  T (1 )
322+     ) where  {N, T, FT <:  AbstractFace{N, T} }
323+ 
324+     @assert  ! (FT <:  MultiFace ) " Dispatch failed?" 
325+     
326+     N_vert =  mapreduce (f ->  max (f), max, faces)
327+     return  faces, (1 : N_vert) .+  vertex_index_counter
328+ end 
329+ 
214330function  merge_vertex_indices (
215331        faces:: AbstractVector{<: MultiFace{N, T, FT, Names, N_Attrib}} ,
216332        vertex_index_counter =  T (1 )
0 commit comments