Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/alembic/intern/abc_reader_curves.cc')
-rw-r--r--source/blender/alembic/intern/abc_reader_curves.cc354
1 files changed, 354 insertions, 0 deletions
diff --git a/source/blender/alembic/intern/abc_reader_curves.cc b/source/blender/alembic/intern/abc_reader_curves.cc
new file mode 100644
index 00000000000..1be164c7c94
--- /dev/null
+++ b/source/blender/alembic/intern/abc_reader_curves.cc
@@ -0,0 +1,354 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Kévin Dietrich.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup balembic
+ */
+
+#include "abc_reader_curves.h"
+#include "abc_reader_transform.h"
+#include "abc_util.h"
+
+#include <cstdio>
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "DNA_curve_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_listbase.h"
+
+#include "BKE_curve.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+}
+
+using Alembic::Abc::FloatArraySamplePtr;
+using Alembic::Abc::Int32ArraySamplePtr;
+using Alembic::Abc::P3fArraySamplePtr;
+using Alembic::Abc::PropertyHeader;
+using Alembic::Abc::UcharArraySamplePtr;
+
+using Alembic::AbcGeom::CurvePeriodicity;
+using Alembic::AbcGeom::ICompoundProperty;
+using Alembic::AbcGeom::ICurves;
+using Alembic::AbcGeom::ICurvesSchema;
+using Alembic::AbcGeom::IFloatGeomParam;
+using Alembic::AbcGeom::IInt16Property;
+using Alembic::AbcGeom::ISampleSelector;
+using Alembic::AbcGeom::kWrapExisting;
+
+AbcCurveReader::AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
+ : AbcObjectReader(object, settings)
+{
+ ICurves abc_curves(object, kWrapExisting);
+ m_curves_schema = abc_curves.getSchema();
+
+ get_min_max_time(m_iobject, m_curves_schema, m_min_time, m_max_time);
+}
+
+bool AbcCurveReader::valid() const
+{
+ return m_curves_schema.valid();
+}
+
+bool AbcCurveReader::accepts_object_type(
+ const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
+ const Object *const ob,
+ const char **err_str) const
+{
+ if (!Alembic::AbcGeom::ICurves::matches(alembic_header)) {
+ *err_str =
+ "Object type mismatch, Alembic object path pointed to Curves when importing, but not any "
+ "more.";
+ return false;
+ }
+
+ if (ob->type != OB_CURVE) {
+ *err_str = "Object type mismatch, Alembic object path points to Curves.";
+ return false;
+ }
+
+ return true;
+}
+
+void AbcCurveReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
+{
+ Curve *cu = BKE_curve_add(bmain, m_data_name.c_str(), OB_CURVE);
+
+ cu->flag |= CU_DEFORM_FILL | CU_3D;
+ cu->actvert = CU_ACT_NONE;
+ cu->resolu = 1;
+
+ ICompoundProperty user_props = m_curves_schema.getUserProperties();
+ if (user_props) {
+ const PropertyHeader *header = user_props.getPropertyHeader(ABC_CURVE_RESOLUTION_U_PROPNAME);
+ if (header != NULL && header->isScalar() && IInt16Property::matches(*header)) {
+ IInt16Property resolu(user_props, header->getName());
+ cu->resolu = resolu.getValue(sample_sel);
+ }
+ }
+
+ m_object = BKE_object_add_only_object(bmain, OB_CURVE, m_object_name.c_str());
+ m_object->data = cu;
+
+ read_curve_sample(cu, m_curves_schema, sample_sel);
+
+ if (has_animations(m_curves_schema, m_settings)) {
+ addCacheModifier();
+ }
+}
+
+void AbcCurveReader::read_curve_sample(Curve *cu,
+ const ICurvesSchema &schema,
+ const ISampleSelector &sample_sel)
+{
+ ICurvesSchema::Sample smp;
+ try {
+ smp = schema.getValue(sample_sel);
+ }
+ catch (Alembic::Util::Exception &ex) {
+ printf("Alembic: error reading curve sample for '%s/%s' at time %f: %s\n",
+ m_iobject.getFullName().c_str(),
+ schema.getName().c_str(),
+ sample_sel.getRequestedTime(),
+ ex.what());
+ return;
+ }
+
+ const Int32ArraySamplePtr num_vertices = smp.getCurvesNumVertices();
+ const P3fArraySamplePtr positions = smp.getPositions();
+ const FloatArraySamplePtr weights = smp.getPositionWeights();
+ const FloatArraySamplePtr knots = smp.getKnots();
+ const CurvePeriodicity periodicity = smp.getWrap();
+ const UcharArraySamplePtr orders = smp.getOrders();
+
+ const IFloatGeomParam widths_param = schema.getWidthsParam();
+ FloatArraySamplePtr radiuses;
+
+ if (widths_param.valid()) {
+ IFloatGeomParam::Sample wsample = widths_param.getExpandedValue(sample_sel);
+ radiuses = wsample.getVals();
+ }
+
+ int knot_offset = 0;
+
+ size_t idx = 0;
+ for (size_t i = 0; i < num_vertices->size(); i++) {
+ const int num_verts = (*num_vertices)[i];
+
+ Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), "abc_getnurb"));
+ nu->resolu = cu->resolu;
+ nu->resolv = cu->resolv;
+ nu->pntsu = num_verts;
+ nu->pntsv = 1;
+ nu->flag |= CU_SMOOTH;
+
+ switch (smp.getType()) {
+ case Alembic::AbcGeom::kCubic:
+ nu->orderu = 4;
+ break;
+ case Alembic::AbcGeom::kVariableOrder:
+ if (orders && orders->size() > i) {
+ nu->orderu = static_cast<short>((*orders)[i]);
+ break;
+ }
+ ATTR_FALLTHROUGH;
+ case Alembic::AbcGeom::kLinear:
+ default:
+ nu->orderu = 2;
+ }
+
+ if (periodicity == Alembic::AbcGeom::kNonPeriodic) {
+ nu->flagu |= CU_NURB_ENDPOINT;
+ }
+ else if (periodicity == Alembic::AbcGeom::kPeriodic) {
+ nu->flagu |= CU_NURB_CYCLIC;
+
+ /* Check the number of points which overlap, we don't have
+ * overlapping points in Blender, but other software do use them to
+ * indicate that a curve is actually cyclic. Usually the number of
+ * overlapping points is equal to the order/degree of the curve.
+ */
+
+ const int start = idx;
+ const int end = idx + num_verts;
+ int overlap = 0;
+
+ for (int j = start, k = end - nu->orderu; j < nu->orderu; j++, k++) {
+ const Imath::V3f &p1 = (*positions)[j];
+ const Imath::V3f &p2 = (*positions)[k];
+
+ if (p1 != p2) {
+ break;
+ }
+
+ overlap++;
+ }
+
+ /* TODO: Special case, need to figure out how it coincides with knots. */
+ if (overlap == 0 && num_verts > 2 && (*positions)[start] == (*positions)[end - 1]) {
+ overlap = 1;
+ }
+
+ /* There is no real cycles. */
+ if (overlap == 0) {
+ nu->flagu &= ~CU_NURB_CYCLIC;
+ nu->flagu |= CU_NURB_ENDPOINT;
+ }
+
+ nu->pntsu -= overlap;
+ }
+
+ const bool do_weights = (weights != NULL) && (weights->size() > 1);
+ float weight = 1.0f;
+
+ const bool do_radius = (radiuses != NULL) && (radiuses->size() > 1);
+ float radius = (radiuses && radiuses->size() == 1) ? (*radiuses)[0] : 1.0f;
+
+ nu->type = CU_NURBS;
+
+ nu->bp = static_cast<BPoint *>(MEM_callocN(sizeof(BPoint) * nu->pntsu, "abc_getnurb"));
+ BPoint *bp = nu->bp;
+
+ for (int j = 0; j < nu->pntsu; j++, bp++, idx++) {
+ const Imath::V3f &pos = (*positions)[idx];
+
+ if (do_radius) {
+ radius = (*radiuses)[idx];
+ }
+
+ if (do_weights) {
+ weight = (*weights)[idx];
+ }
+
+ copy_zup_from_yup(bp->vec, pos.getValue());
+ bp->vec[3] = weight;
+ bp->f1 = SELECT;
+ bp->radius = radius;
+ bp->weight = 1.0f;
+ }
+
+ if (knots && knots->size() != 0) {
+ nu->knotsu = static_cast<float *>(
+ MEM_callocN(KNOTSU(nu) * sizeof(float), "abc_setsplineknotsu"));
+
+ /* TODO: second check is temporary, for until the check for cycles is rock solid. */
+ if (periodicity == Alembic::AbcGeom::kPeriodic && (KNOTSU(nu) == knots->size() - 2)) {
+ /* Skip first and last knots. */
+ for (size_t i = 1; i < knots->size() - 1; i++) {
+ nu->knotsu[i - 1] = (*knots)[knot_offset + i];
+ }
+ }
+ else {
+ /* TODO: figure out how to use the knots array from other
+ * software in this case. */
+ BKE_nurb_knot_calc_u(nu);
+ }
+
+ knot_offset += knots->size();
+ }
+ else {
+ BKE_nurb_knot_calc_u(nu);
+ }
+
+ BLI_addtail(BKE_curve_nurbs_get(cu), nu);
+ }
+}
+
+/* NOTE: Alembic only stores data about control points, but the Mesh
+ * passed from the cache modifier contains the displist, which has more data
+ * than the control points, so to avoid corrupting the displist we modify the
+ * object directly and create a new Mesh from that. Also we might need to
+ * create new or delete existing NURBS in the curve.
+ */
+Mesh *AbcCurveReader::read_mesh(Mesh *existing_mesh,
+ const ISampleSelector &sample_sel,
+ int /*read_flag*/,
+ const char **err_str)
+{
+ ICurvesSchema::Sample sample;
+
+ try {
+ sample = m_curves_schema.getValue(sample_sel);
+ }
+ catch (Alembic::Util::Exception &ex) {
+ *err_str = "Error reading curve sample; more detail on the console";
+ printf("Alembic: error reading curve sample for '%s/%s' at time %f: %s\n",
+ m_iobject.getFullName().c_str(),
+ m_curves_schema.getName().c_str(),
+ sample_sel.getRequestedTime(),
+ ex.what());
+ return existing_mesh;
+ }
+
+ const P3fArraySamplePtr &positions = sample.getPositions();
+ const Int32ArraySamplePtr num_vertices = sample.getCurvesNumVertices();
+
+ int vertex_idx = 0;
+ int curve_idx;
+ Curve *curve = static_cast<Curve *>(m_object->data);
+
+ const int curve_count = BLI_listbase_count(&curve->nurb);
+ bool same_topology = curve_count == num_vertices->size();
+
+ if (same_topology) {
+ Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
+ for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
+ const int num_in_alembic = (*num_vertices)[curve_idx];
+ const int num_in_blender = nurbs->pntsu;
+
+ if (num_in_alembic != num_in_blender) {
+ same_topology = false;
+ break;
+ }
+ }
+ }
+
+ if (!same_topology) {
+ BKE_nurbList_free(&curve->nurb);
+ read_curve_sample(curve, m_curves_schema, sample_sel);
+ }
+ else {
+ Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
+ for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
+ const int totpoint = (*num_vertices)[curve_idx];
+
+ if (nurbs->bp) {
+ BPoint *point = nurbs->bp;
+
+ for (int i = 0; i < totpoint; i++, point++, vertex_idx++) {
+ const Imath::V3f &pos = (*positions)[vertex_idx];
+ copy_zup_from_yup(point->vec, pos.getValue());
+ }
+ }
+ else if (nurbs->bezt) {
+ BezTriple *bezier = nurbs->bezt;
+
+ for (int i = 0; i < totpoint; i++, bezier++, vertex_idx++) {
+ const Imath::V3f &pos = (*positions)[vertex_idx];
+ copy_zup_from_yup(bezier->vec[1], pos.getValue());
+ }
+ }
+ }
+ }
+
+ return BKE_mesh_new_nomain_from_curve(m_object);
+}