fc84759b1d9b931133b79952e534f77197de7f20
[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(Scene *scene,
62                                  Object *ob,
63                                      AbcTransformWriter *parent,
64                                      uint32_t time_sampling,
65                                      ExportSettings &settings,
66                                      ParticleSystem *psys)
67     : AbcObjectWriter(scene, ob, time_sampling, settings, parent)
68 {
69         m_psys = psys;
70
71         OPoints points(parent->alembicXform(), psys->name, m_time_sampling);
72         m_schema = points.getSchema();
73 }
74
75 void AbcPointsWriter::do_write()
76 {
77         if (!m_psys) {
78                 return;
79         }
80
81         std::vector<Imath::V3f> points;
82         std::vector<Imath::V3f> velocities;
83         std::vector<float> widths;
84         std::vector<uint64_t> ids;
85
86         ParticleKey state;
87
88         ParticleSimulationData sim;
89         sim.scene = m_scene;
90         sim.ob = m_object;
91         sim.psys = m_psys;
92
93         m_psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
94
95         uint64_t index = 0;
96         for (int p = 0; p < m_psys->totpart; p++) {
97                 float pos[3], vel[3];
98
99                 if (m_psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST)) {
100                         continue;
101                 }
102
103                 state.time = BKE_scene_frame_get(m_scene);
104
105                 if (psys_get_particle_state(&sim, p, &state, 0) == 0) {
106                         continue;
107                 }
108
109                 /* location */
110                 mul_v3_m4v3(pos, m_object->imat, state.co);
111
112                 /* velocity */
113                 sub_v3_v3v3(vel, state.co, m_psys->particles[p].prev_state.co);
114
115                 /* Convert Z-up to Y-up. */
116                 points.push_back(Imath::V3f(pos[0], pos[2], -pos[1]));
117                 velocities.push_back(Imath::V3f(vel[0], vel[2], -vel[1]));
118                 widths.push_back(m_psys->particles[p].size);
119                 ids.push_back(index++);
120         }
121
122         if (m_psys->lattice_deform_data) {
123                 end_latt_deform(m_psys->lattice_deform_data);
124                 m_psys->lattice_deform_data = NULL;
125         }
126
127         Alembic::Abc::P3fArraySample psample(points);
128         Alembic::Abc::UInt64ArraySample idsample(ids);
129         Alembic::Abc::V3fArraySample vsample(velocities);
130         Alembic::Abc::FloatArraySample wsample_array(widths);
131         Alembic::AbcGeom::OFloatGeomParam::Sample wsample(wsample_array, kVertexScope);
132
133         m_sample = OPointsSchema::Sample(psample, idsample, vsample, wsample);
134         m_sample.setSelfBounds(bounds());
135
136         m_schema.set(m_sample);
137 }
138
139 /* ************************************************************************** */
140
141 AbcPointsReader::AbcPointsReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
142     : AbcObjectReader(object, settings)
143 {
144         IPoints ipoints(m_iobject, kWrapExisting);
145         m_schema = ipoints.getSchema();
146         get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time);
147 }
148
149 bool AbcPointsReader::valid() const
150 {
151         return m_schema.valid();
152 }
153
154 void AbcPointsReader::readObjectData(Main *bmain, float time)
155 {
156         Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
157
158         DerivedMesh *dm = CDDM_from_mesh(mesh);
159         DerivedMesh *ndm = this->read_derivedmesh(dm, time, 0, NULL);
160
161         if (ndm != dm) {
162                 dm->release(dm);
163         }
164
165         DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true);
166
167         if (m_settings->validate_meshes) {
168                 BKE_mesh_validate(mesh, false, false);
169         }
170
171         m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
172         m_object->data = mesh;
173
174         if (has_animations(m_schema, m_settings)) {
175                 addCacheModifier();
176         }
177 }
178
179 void read_points_sample(const IPointsSchema &schema,
180                         const ISampleSelector &selector,
181                         CDStreamConfig &config,
182                         float time)
183 {
184         Alembic::AbcGeom::IPointsSchema::Sample sample = schema.getValue(selector);
185
186         const P3fArraySamplePtr &positions = sample.getPositions();
187
188         ICompoundProperty prop = schema.getArbGeomParams();
189         N3fArraySamplePtr vnormals;
190
191         if (has_property(prop, "N")) {
192                 const Alembic::Util::uint32_t itime = static_cast<Alembic::Util::uint32_t>(time);
193                 const IN3fArrayProperty &normals_prop = IN3fArrayProperty(prop, "N", itime);
194
195                 if (normals_prop) {
196                         vnormals = normals_prop.getValue(selector);
197                 }
198         }
199
200         read_mverts(config.mvert, positions, vnormals);
201 }
202
203 DerivedMesh *AbcPointsReader::read_derivedmesh(DerivedMesh *dm, const float time, int /*read_flag*/, const char ** /*err_str*/)
204 {
205         ISampleSelector sample_sel(time);
206         const IPointsSchema::Sample sample = m_schema.getValue(sample_sel);
207
208         const P3fArraySamplePtr &positions = sample.getPositions();
209
210         DerivedMesh *new_dm = NULL;
211
212         if (dm->getNumVerts(dm) != positions->size()) {
213                 new_dm = CDDM_new(positions->size(), 0, 0, 0, 0);
214         }
215
216         CDStreamConfig config = get_config(new_dm ? new_dm : dm);
217         read_points_sample(m_schema, sample_sel, config, time);
218
219         return new_dm ? new_dm : dm;
220 }