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
|