Depsgraph: remove EvaluationContext, pass Depsgraph instead.
[blender.git] / source / blender / alembic / intern / abc_hair.cc
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 #include "abc_hair.h"
24
25 #include <cstdio>
26
27 #include "abc_transform.h"
28 #include "abc_util.h"
29
30 extern "C" {
31 #include "MEM_guardedalloc.h"
32
33 #include "DNA_modifier_types.h"
34
35 #include "BLI_listbase.h"
36 #include "BLI_math_geom.h"
37
38 #include "BKE_DerivedMesh.h"
39 #include "BKE_object.h"
40 #include "BKE_particle.h"
41 }
42
43 using Alembic::Abc::P3fArraySamplePtr;
44
45 using Alembic::AbcGeom::OCurves;
46 using Alembic::AbcGeom::OCurvesSchema;
47 using Alembic::AbcGeom::ON3fGeomParam;
48 using Alembic::AbcGeom::OV2fGeomParam;
49
50 /* ************************************************************************** */
51
52 AbcHairWriter::AbcHairWriter(Depsgraph *depsgraph,
53                              Scene *scene,
54                              Object *ob,
55                              AbcTransformWriter *parent,
56                              uint32_t time_sampling,
57                              ExportSettings &settings,
58                              ParticleSystem *psys)
59     : AbcObjectWriter(depsgraph, scene, ob, time_sampling, settings, parent)
60     , m_uv_warning_shown(false)
61 {
62         m_psys = psys;
63
64         OCurves curves(parent->alembicXform(), psys->name, m_time_sampling);
65         m_schema = curves.getSchema();
66 }
67
68 void AbcHairWriter::do_write()
69 {
70         if (!m_psys) {
71                 return;
72         }
73
74         ParticleSystemModifierData *psmd = psys_get_modifier(m_object, m_psys);
75
76         if (!psmd->dm_final) {
77                 return;
78         }
79
80         DerivedMesh *dm = mesh_create_derived_render(m_depsgraph, m_scene, m_object, CD_MASK_MESH);
81         DM_ensure_tessface(dm);
82
83         std::vector<Imath::V3f> verts;
84         std::vector<int32_t> hvertices;
85         std::vector<Imath::V2f> uv_values;
86         std::vector<Imath::V3f> norm_values;
87
88         if (m_psys->pathcache) {
89                 ParticleSettings *part = m_psys->part;
90
91                 write_hair_sample(dm, part, verts, norm_values, uv_values, hvertices);
92
93                 if (m_settings.export_child_hairs && m_psys->childcache) {
94                         write_hair_child_sample(dm, part, verts, norm_values, uv_values, hvertices);
95                 }
96         }
97
98         dm->release(dm);
99
100         Alembic::Abc::P3fArraySample iPos(verts);
101         m_sample = OCurvesSchema::Sample(iPos, hvertices);
102         m_sample.setBasis(Alembic::AbcGeom::kNoBasis);
103         m_sample.setType(Alembic::AbcGeom::kLinear);
104         m_sample.setWrap(Alembic::AbcGeom::kNonPeriodic);
105
106         if (!uv_values.empty()) {
107                 OV2fGeomParam::Sample uv_smp;
108                 uv_smp.setVals(uv_values);
109                 m_sample.setUVs(uv_smp);
110         }
111
112         if (!norm_values.empty()) {
113                 ON3fGeomParam::Sample norm_smp;
114                 norm_smp.setVals(norm_values);
115                 m_sample.setNormals(norm_smp);
116         }
117
118         m_sample.setSelfBounds(bounds());
119         m_schema.set(m_sample);
120 }
121
122 void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
123                                       ParticleSettings *part,
124                                       std::vector<Imath::V3f> &verts,
125                                       std::vector<Imath::V3f> &norm_values,
126                                       std::vector<Imath::V2f> &uv_values,
127                                       std::vector<int32_t> &hvertices)
128 {
129         /* Get untransformed vertices, there's a xform under the hair. */
130         float inv_mat[4][4];
131         invert_m4_m4_safe(inv_mat, m_object->obmat);
132
133         MTFace *mtface = static_cast<MTFace *>(CustomData_get_layer(&dm->faceData, CD_MTFACE));
134         MFace *mface = dm->getTessFaceArray(dm);
135         MVert *mverts = dm->getVertArray(dm);
136
137         if ((!mtface || !mface) && !m_uv_warning_shown) {
138                 std::fprintf(stderr, "Warning, no UV set found for underlying geometry of %s.\n",
139                              m_object->id.name + 2);
140                 m_uv_warning_shown = true;
141         }
142
143         ParticleData * pa = m_psys->particles;
144         int k;
145
146         ParticleCacheKey **cache = m_psys->pathcache;
147         ParticleCacheKey *path;
148         float normal[3];
149         Imath::V3f tmp_nor;
150
151         for (int p = 0; p < m_psys->totpart; ++p, ++pa) {
152                 /* underlying info for faces-only emission */
153                 path = cache[p];
154
155                 if (part->from == PART_FROM_FACE && mtface) {
156                         const int num = pa->num_dmcache >= 0 ? pa->num_dmcache : pa->num;
157
158                         if (num < dm->getNumTessFaces(dm)) {
159                                 MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, num, CD_MFACE));
160                                 MTFace *tface = mtface + num;
161
162                                 if (mface) {
163                                         float r_uv[2], mapfw[4], vec[3];
164
165                                         psys_interpolate_uvs(tface, face->v4, pa->fuv, r_uv);
166                                         uv_values.push_back(Imath::V2f(r_uv[0], r_uv[1]));
167
168                                         psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, normal, NULL, NULL, NULL, NULL);
169
170                                         copy_yup_from_zup(tmp_nor.getValue(), normal);
171                                         norm_values.push_back(tmp_nor);
172                                 }
173                         }
174                         else {
175                                 std::fprintf(stderr, "Particle to faces overflow (%d/%d)\n", num, dm->getNumTessFaces(dm));
176                         }
177                 }
178                 else if (part->from == PART_FROM_VERT && mtface) {
179                         /* vertex id */
180                         const int num = (pa->num_dmcache >= 0) ? pa->num_dmcache : pa->num;
181
182                         /* iterate over all faces to find a corresponding underlying UV */
183                         for (int n = 0; n < dm->getNumTessFaces(dm); ++n) {
184                                 MFace *face  = static_cast<MFace *>(dm->getTessFaceData(dm, n, CD_MFACE));
185                                 MTFace *tface = mtface + n;
186                                 unsigned int vtx[4];
187                                 vtx[0] = face->v1;
188                                 vtx[1] = face->v2;
189                                 vtx[2] = face->v3;
190                                 vtx[3] = face->v4;
191                                 bool found = false;
192
193                                 for (int o = 0; o < 4; ++o) {
194                                         if (o > 2 && vtx[o] == 0) {
195                                                 break;
196                                         }
197
198                                         if (vtx[o] == num) {
199                                                 uv_values.push_back(Imath::V2f(tface->uv[o][0], tface->uv[o][1]));
200
201                                                 MVert *mv = mverts + vtx[o];
202
203                                                 normal_short_to_float_v3(normal, mv->no);
204                                                 copy_yup_from_zup(tmp_nor.getValue(), normal);
205                                                 norm_values.push_back(tmp_nor);
206                                                 found = true;
207                                                 break;
208                                         }
209                                 }
210
211                                 if (found) {
212                                         break;
213                                 }
214                         }
215                 }
216
217                 int steps = path->segments + 1;
218                 hvertices.push_back(steps);
219
220                 for (k = 0; k < steps; ++k) {
221                         float vert[3];
222                         copy_v3_v3(vert, path->co);
223                         mul_m4_v3(inv_mat, vert);
224
225                         /* Convert Z-up to Y-up. */
226                         verts.push_back(Imath::V3f(vert[0], vert[2], -vert[1]));
227
228                         ++path;
229                 }
230         }
231 }
232
233 void AbcHairWriter::write_hair_child_sample(DerivedMesh *dm,
234                                             ParticleSettings *part,
235                                             std::vector<Imath::V3f> &verts,
236                                             std::vector<Imath::V3f> &norm_values,
237                                             std::vector<Imath::V2f> &uv_values,
238                                             std::vector<int32_t> &hvertices)
239 {
240         /* Get untransformed vertices, there's a xform under the hair. */
241         float inv_mat[4][4];
242         invert_m4_m4_safe(inv_mat, m_object->obmat);
243
244         MTFace *mtface = static_cast<MTFace *>(CustomData_get_layer(&dm->faceData, CD_MTFACE));
245         MVert *mverts = dm->getVertArray(dm);
246
247         ParticleCacheKey **cache = m_psys->childcache;
248         ParticleCacheKey *path;
249
250         ChildParticle *pc = m_psys->child;
251
252         for (int p = 0; p < m_psys->totchild; ++p, ++pc) {
253                 path = cache[p];
254
255                 if (part->from == PART_FROM_FACE &&
256                     part->childtype != PART_CHILD_PARTICLES &&
257                     mtface)
258                 {
259                         const int num = pc->num;
260                         if (num < 0) {
261                                 ABC_LOG(m_settings.logger)
262                                         << "Warning, child particle of hair system " << m_psys->name
263                                         << " has unknown face index of geometry of "<< (m_object->id.name + 2)
264                                         << ", skipping child hair." << std::endl;
265                                 continue;
266                         }
267
268                         MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, num, CD_MFACE));
269                         MTFace *tface = mtface + num;
270
271                         float r_uv[2], tmpnor[3], mapfw[4], vec[3];
272
273                         psys_interpolate_uvs(tface, face->v4, pc->fuv, r_uv);
274                         uv_values.push_back(Imath::V2f(r_uv[0], r_uv[1]));
275
276                         psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, tmpnor, NULL, NULL, NULL, NULL);
277
278                         /* Convert Z-up to Y-up. */
279                         norm_values.push_back(Imath::V3f(tmpnor[0], tmpnor[2], -tmpnor[1]));
280                 }
281                 else {
282                         if (uv_values.size()) {
283                                 uv_values.push_back(uv_values[pc->parent]);
284                         }
285                         if (norm_values.size()) {
286                                 norm_values.push_back(norm_values[pc->parent]);
287                         }
288                 }
289
290                 int steps = path->segments + 1;
291                 hvertices.push_back(steps);
292
293                 for (int k = 0; k < steps; ++k) {
294                         float vert[3];
295                         copy_v3_v3(vert, path->co);
296                         mul_m4_v3(inv_mat, vert);
297
298                         /* Convert Z-up to Y-up. */
299                         verts.push_back(Imath::V3f(vert[0], vert[2], -vert[1]));
300
301                         ++path;
302                 }
303         }
304 }