Alembic import: port DerivedMesh → Mesh
[blender.git] / source / blender / alembic / intern / abc_points.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  * The Original Code is Copyright (C) 2016 Kévin Dietrich.
19  * All rights reserved.
20  *
21  * ***** END GPL LICENSE BLOCK *****
22  *
23  */
24
25 #include "abc_points.h"
26
27 #include "abc_mesh.h"
28 #include "abc_transform.h"
29 #include "abc_util.h"
30
31 extern "C" {
32 #include "DNA_mesh_types.h"
33 #include "DNA_object_types.h"
34
35 #include "BKE_cdderivedmesh.h"
36 #include "BKE_lattice.h"
37 #include "BKE_mesh.h"
38 #include "BKE_object.h"
39 #include "BKE_particle.h"
40 #include "BKE_scene.h"
41
42 #include "BLI_math.h"
43 }
44
45 using Alembic::AbcGeom::kVertexScope;
46 using Alembic::AbcGeom::kWrapExisting;
47 using Alembic::AbcGeom::P3fArraySamplePtr;
48 using Alembic::AbcGeom::N3fArraySamplePtr;
49
50 using Alembic::AbcGeom::ICompoundProperty;
51 using Alembic::AbcGeom::IN3fArrayProperty;
52 using Alembic::AbcGeom::IPoints;
53 using Alembic::AbcGeom::IPointsSchema;
54 using Alembic::AbcGeom::ISampleSelector;
55
56 using Alembic::AbcGeom::OPoints;
57 using Alembic::AbcGeom::OPointsSchema;
58
59 /* ************************************************************************** */
60
61 AbcPointsWriter::AbcPointsWriter(Depsgraph *depsgraph,
62                                  Scene *scene,
63                                  Object *ob,
64                                      AbcTransformWriter *parent,
65                                      uint32_t time_sampling,
66                                      ExportSettings &settings,
67                                      ParticleSystem *psys)
68     : AbcObjectWriter(depsgraph, scene, ob, time_sampling, settings, parent)
69 {
70         m_psys = psys;
71
72         OPoints points(parent->alembicXform(), psys->name, m_time_sampling);
73         m_schema = points.getSchema();
74 }
75
76 void AbcPointsWriter::do_write()
77 {
78         if (!m_psys) {
79                 return;
80         }
81
82         std::vector<Imath::V3f> points;
83         std::vector<Imath::V3f> velocities;
84         std::vector<float> widths;
85         std::vector<uint64_t> ids;
86
87         ParticleKey state;
88
89         ParticleSimulationData sim;
90         sim.depsgraph = m_depsgraph;
91         sim.scene = m_scene;
92         sim.ob = m_object;
93         sim.psys = m_psys;
94
95         m_psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
96
97         uint64_t index = 0;
98         for (int p = 0; p < m_psys->totpart; p++) {
99                 float pos[3], vel[3];
100
101                 if (m_psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST)) {
102                         continue;
103                 }
104
105                 state.time = BKE_scene_frame_get(m_scene);
106
107                 if (psys_get_particle_state(&sim, p, &state, 0) == 0) {
108                         continue;
109                 }
110
111                 /* location */
112                 mul_v3_m4v3(pos, m_object->imat, state.co);
113
114                 /* velocity */
115                 sub_v3_v3v3(vel, state.co, m_psys->particles[p].prev_state.co);
116
117                 /* Convert Z-up to Y-up. */
118                 points.push_back(Imath::V3f(pos[0], pos[2], -pos[1]));
119                 velocities.push_back(Imath::V3f(vel[0], vel[2], -vel[1]));
120                 widths.push_back(m_psys->particles[p].size);
121                 ids.push_back(index++);
122         }
123
124         if (m_psys->lattice_deform_data) {
125                 end_latt_deform(m_psys->lattice_deform_data);
126                 m_psys->lattice_deform_data = NULL;
127         }
128
129         Alembic::Abc::P3fArraySample psample(points);
130         Alembic::Abc::UInt64ArraySample idsample(ids);
131         Alembic::Abc::V3fArraySample vsample(velocities);
132         Alembic::Abc::FloatArraySample wsample_array(widths);
133         Alembic::AbcGeom::OFloatGeomParam::Sample wsample(wsample_array, kVertexScope);
134
135         m_sample = OPointsSchema::Sample(psample, idsample, vsample, wsample);
136         m_sample.setSelfBounds(bounds());
137
138         m_schema.set(m_sample);
139 }
140
141 /* ************************************************************************** */
142
143 AbcPointsReader::AbcPointsReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
144     : AbcObjectReader(object, settings)
145 {
146         IPoints ipoints(m_iobject, kWrapExisting);
147         m_schema = ipoints.getSchema();
148         get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time);
149 }
150
151 bool AbcPointsReader::valid() const
152 {
153         return m_schema.valid();
154 }
155
156 bool AbcPointsReader::accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
157                                           const Object *const ob,
158                                           const char **err_str) const
159 {
160         if (!Alembic::AbcGeom::IPoints::matches(alembic_header)) {
161                 *err_str = "Object type mismatch, Alembic object path pointed to Points when importing, but not any more.";
162                 return false;
163         }
164
165         if (ob->type != OB_MESH) {
166                 *err_str = "Object type mismatch, Alembic object path points to Points.";
167                 return false;
168         }
169
170         return true;
171 }
172
173 void AbcPointsReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
174 {
175         Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
176         Mesh *read_mesh = this->read_mesh(mesh, sample_sel, 0, NULL);
177
178         BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, CD_MASK_MESH, true);
179
180         if (m_settings->validate_meshes) {
181                 BKE_mesh_validate(mesh, false, false);
182         }
183
184         m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
185         m_object->data = mesh;
186
187         if (has_animations(m_schema, m_settings)) {
188                 addCacheModifier();
189         }
190 }
191
192 void read_points_sample(const IPointsSchema &schema,
193                         const ISampleSelector &selector,
194                         CDStreamConfig &config)
195 {
196         Alembic::AbcGeom::IPointsSchema::Sample sample = schema.getValue(selector);
197
198         const P3fArraySamplePtr &positions = sample.getPositions();
199
200         ICompoundProperty prop = schema.getArbGeomParams();
201         N3fArraySamplePtr vnormals;
202
203         if (has_property(prop, "N")) {
204                 const Alembic::Util::uint32_t itime = static_cast<Alembic::Util::uint32_t>(selector.getRequestedTime());
205                 const IN3fArrayProperty &normals_prop = IN3fArrayProperty(prop, "N", itime);
206
207                 if (normals_prop) {
208                         vnormals = normals_prop.getValue(selector);
209                 }
210         }
211
212         read_mverts(config.mvert, positions, vnormals);
213 }
214
215 struct Mesh *AbcPointsReader::read_mesh(struct Mesh *existing_mesh,
216                                         const ISampleSelector &sample_sel,
217                                         int /*read_flag*/,
218                                         const char ** /*err_str*/)
219 {
220         const IPointsSchema::Sample sample = m_schema.getValue(sample_sel);
221
222         const P3fArraySamplePtr &positions = sample.getPositions();
223
224         Mesh *new_mesh = NULL;
225
226         if (existing_mesh->totvert != positions->size()) {
227                 new_mesh = BKE_mesh_new_nomain(positions->size(), 0, 0, 0, 0);
228         }
229
230         CDStreamConfig config = get_config(new_mesh ? new_mesh : existing_mesh);
231         read_points_sample(m_schema, sample_sel, config);
232
233         return new_mesh ? new_mesh : existing_mesh;
234 }