LCOV - code coverage report
Current view: top level - src/obj - objmesh.jl (source / functions) Hit Total Coverage
Test: on branch nothing Lines: 62 93 66.7 %
Date: 2025-07-10 13:29:30 Functions: 0 0 -

          Line data    Source code
       1             : """
       2             :     mesh = createmesh(::OBJ[; real_type=Float64, dimx=Val(3), dimu=Val(2)])
       3             : 
       4             : Create an empty mesh with all attributes that may be read from an
       5             : OBJ file: position, normal, and texture coordinates:
       6             : 
       7             : - vertex attributes `:x`, `:n`, `:u`, `:c`
       8             : - face attributes: `:n`
       9             : - half-edge attributes `:n`, `:u`
      10             : 
      11             : The latter stores texture coordinates and normals that are defined for
      12             : each vertex of a face.
      13             : 
      14             : !!! note
      15             :     This method uses default attribute names `:x`, `:n`, `:u`, `:c`!
      16             : """
      17           4 : function PMesh.createmesh(::OBJ; real_type::Type{T}=Float64,
      18             :                           dimx::Val{Nx}=Val(3),
      19             :                           dimu::Val{Nu}=Val(2)) where {T<:Real, Nx, Nu}
      20           2 :     _createobjmesh(real_type, dimx, dimu)
      21             : end
      22             : 
      23             : 
      24           2 : function _createobjmesh(real_type::Type{T}, ::Val{Nx}, ::Val{Nu}) where {T, Nx, Nu}
      25           2 :     PMesh.createmesh((:x => SVector{Nx, real_type},
      26             :                       :u => SVector{Nu, real_type},
      27             :                       :n => SVector{3, real_type},
      28             :                       :c => RGBA),
      29             :                      (:n => SVector{3, real_type}),
      30             :                      (:u => SVector{Nu, real_type},
      31             :                       :n => SVector{3, real_type}),
      32             :                      ())
      33             : end
      34             : 
      35           0 : function _createobjmesh(real_type::Type{T}, ::Val{Nx}, ::Val{1}) where {T, Nx}
      36           0 :     PMesh.createmesh((:x => SVector{Nx, real_type},
      37             :                       :u => real_type,
      38             :                       :n => SVector{3, real_type},
      39             :                       :c => RGBA),
      40             :                      (:n => SVector{3, real_type}),
      41             :                      (:u => real_type,
      42             :                       :n => SVector{3, real_type}),
      43             :                      ())
      44             : end
      45             : 
      46             : 
      47             : """
      48             : Enable of disable attributes provided by `mesh` depending on what is
      49             : provided by  [`OBJBuffer`](@ref).
      50             : 
      51             : See also [`createmesh`](@ref)
      52             : """
      53           3 : function toggleattributes!(mesh::Mesh, obj::OBJBuffer)
      54           3 :     PMesh.hasvattr(mesh, :u) && setenabled!(vattr(mesh, :u), hasvt(obj))
      55           3 :     PMesh.hasvattr(mesh, :n) && setenabled!(vattr(mesh, :n), hasvn(obj))
      56           3 :     PMesh.hasvattr(mesh, :c) &&
      57             :         setenabled!(vattr(mesh, :c), hasvertexcolor(obj))
      58             : 
      59           3 :     PMesh.hasfattr(mesh, :n) && setenabled!(fattr(mesh, :n), nn(obj) > 0)
      60             : 
      61           3 :     PMesh.hashattr(mesh, :u) && setenabled!(hattr(mesh, :u), hasht(obj))
      62           3 :     PMesh.hashattr(mesh, :n) && setenabled!(hattr(mesh, :n), hashn(obj))
      63             : 
      64           3 :     mesh
      65             : end
      66             : 
      67             : """
      68             :     mesh = createmesh(obj::OBJBuffer;
      69             :                       template::Mesh=createmesh(; real_type=T),
      70             :                       position=Val(:x),
      71             :                       normal=Val(:n),
      72             :                       texcoord=Val(:u))
      73             : 
      74             : Create mesh from `obj` that was read by [`readobj`](@ref) using
      75             : `template` and the specified attribute names.
      76             : 
      77             : - Attributes which are not defined in `obj` will be *disabled*!
      78             : - Attributes which are not defined in `template` are not copied from `obj`.
      79             : 
      80             : !!! note
      81             :     The given attribute names are uses equally for vertex attributes
      82             :     and for half-edge attributes.
      83             : 
      84             : See also [`OBJBuffer`](@ref), [`toggleattributes!](@ref)
      85             : """
      86           6 : function PMesh.createmesh(obj::OBJBuffer{T, I};
      87             :                           template::Mesh=createmesh(OBJ(); real_type=T),
      88             :                           position=Val(:x),
      89             :                           normal=Val(:n), texcoord=Val(:u),
      90             :                           color=Val(:c)) where {T, I}
      91             : 
      92          12 :     to_Val(x::Val) = x
      93           0 :     to_Val(x::Symbol) = Val(x)
      94           3 :     to_Val(::Nothing) = Val(:_nothing_)
      95             : 
      96           3 :     mesh = similar(template)
      97           3 :     mesh = toggleattributes!(mesh, obj)
      98             : 
      99           3 :     copy!(mesh, obj,
     100             :           Val(positiondim(obj)), Val(texcoorddim(obj)),
     101             :           to_Val(position), to_Val(normal), to_Val(texcoord),
     102             :           to_Val(color))
     103             : 
     104           3 :     mesh
     105             : end
     106             : 
     107             : """
     108             :     copy!(mesh, obj,
     109             :           Val(NX), Val(NU),
     110             :           Val(:x), Val(:n), Val(:u), Val(:c))
     111             : 
     112             : Helper that copies contents of [`OBJBuffer`])@ref) `obj` to `mesh` using
     113             : dimensions `NX` and `NU` and the provided attributes for position, normal,
     114             : texture coordinates, and color.
     115             : 
     116             : See also [`OBJBuffer`](@ref), [`createmesh`](@ref)
     117             : """
     118           3 : function copy!(mesh::Mesh,
     119             :                obj::OBJBuffer{T},
     120             :                nx::Val{Nx}, nu::Val{Nu},
     121             :                ax::Val, an::Val{Sn}, au::Val{St},
     122             :                ac::Val{C}) where {T, Nx, Nu, Sn, St, C}
     123             : 
     124           3 :     sizehint!(mesh, nv(obj), nf(obj))
     125             : 
     126           3 :     x = vattr(mesh, ax)
     127             : 
     128           3 :     for p in position(obj, nx)
     129       11351 :         v = addvertex!(mesh)
     130       11351 :         x[v] = convert_to(p, x[v])
     131       11351 :     end
     132             : 
     133           3 :     faces = FHnd[] # Note: Faces may be invalid! (But we need the indexing!)
     134             : 
     135           3 :     f = 0
     136           3 :     for d in obj.fdegree
     137       87728 :         vs = map(i -> VHnd(obj.vidx[i]), (f+1):(f+d))
     138       21815 :         fh = addface!(mesh, vs)
     139       21815 :         (fh == NoF) && @warn "cannot add face $(Int.(vs))"
     140       21815 :         push!(faces, fh) # even if NoF
     141       21815 :         f += d
     142       21815 :     end
     143           3 :     @assert length(faces) == length(obj.fdegree)
     144             : 
     145           3 :     if hasvertexcolor(obj) && PMesh.hasvattr(mesh, C) && isenabled(vattr(mesh, ac))
     146           1 :         c = vattr(mesh, ac)
     147             : 
     148           2 :         for (i, v) in enumerate(vertices(mesh))
     149        9222 :             c[v] = obj.vcolor[i] # TODO: convert colors to SVector in case
     150       18443 :         end
     151             :     end
     152             : 
     153             :     # TODO: simplify, avoid redundant code
     154             : 
     155           3 :     if hasnormal(obj)
     156           2 :         if hasvn(obj)
     157           0 :             if PMesh.hasvattr(mesh, Sn) && isenabled(vattr(mesh, an))
     158           0 :                 n = vattr(mesh, an)
     159           0 :                 nrm = normal(obj, Val(3))
     160             : 
     161           0 :                 for (i, v) in enumerate(vertices(mesh))
     162           0 :                     n[v] = convert_to(nrm[i], n[v])
     163           0 :                 end
     164             :             else
     165           0 :                 @warn "Drop vertex normals"
     166             :             end
     167             :         else
     168           2 :             if PMesh.hashattr(mesh, Sn) && isenabled(hattr(mesh, an))
     169           0 :                 n = hattr(mesh, an)
     170           0 :                 nrm = normal(obj, Val(3))
     171             : 
     172           0 :                 fanchor = 0
     173           0 :                 for (f, d) in enumerate(obj.fdegree)
     174           0 :                     if faces[f] != NoF
     175           0 :                         @assert Int(faces[f]) <= f
     176           0 :                         for (i, h) in enumerate(halfedges(mesh, faces[f]))
     177           0 :                             fi = fanchor + i
     178           0 :                             @assert destination(mesh, h) == VHnd(obj.vidx[fi])
     179           0 :                             n[h] = convert_to(nrm[obj.nidx[fi]], n[h])
     180           0 :                         end
     181             :                     end
     182           0 :                     fanchor += d
     183           0 :                 end
     184             :             else
     185           2 :                 @warn "Drop per face vertex normals"
     186             :             end
     187             :         end
     188             :     end
     189             : 
     190           3 :     if hastexcoord(obj)
     191           1 :         if hasvt(obj)
     192           0 :             if PMesh.hasvattr(mesh, St) && isenabled(vattr(mesh, au))
     193           0 :                 u = vattr(mesh, au)
     194           0 :                 t = texcoord(obj, nu)
     195             : 
     196           0 :                 for (i, v) in enumerate(vertices(mesh))
     197           0 :                     u[v] = convert_to(t[i], u[v])
     198           0 :                 end
     199             :             else
     200           0 :                 @warn "Drop texture coordinates"
     201             :             end
     202             :         else
     203           1 :             if PMesh.hashattr(mesh, St)  && isenabled(hattr(mesh, au))
     204           1 :                 u = hattr(mesh, au)
     205           1 :                 t = texcoord(obj, nu)
     206             : 
     207           1 :                 fanchor = 0
     208           1 :                 for (f, d) in enumerate(obj.fdegree)
     209        3192 :                     if faces[f] != NoF
     210        3091 :                         @assert Int(faces[f]) <= f
     211        3091 :                         for (i, h) in enumerate(halfedges(mesh, faces[f]))
     212        9273 :                             fi = fanchor + i
     213        9273 :                             @assert destination(mesh, h) == VHnd(obj.vidx[fi])
     214        9273 :                             u[h] = convert_to(t[obj.tidx[fi]], u[h])
     215       15455 :                         end
     216             :                     end
     217        3192 :                     fanchor += d
     218        3192 :                 end
     219             :             else
     220           0 :                 @warn "Drop per face texture coordinates"
     221             :             end
     222             :         end
     223             :     end
     224             : 
     225           3 :     mesh
     226             : end

Generated by: LCOV version 1.16