Blender  V2.93
abc_writer_nurbs.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
21 #include "abc_writer_nurbs.h"
23 
24 #include "DNA_curve_types.h"
25 #include "DNA_object_types.h"
26 
27 #include "BLI_listbase.h"
28 
29 #include "BKE_curve.h"
30 
31 #include "CLG_log.h"
32 static CLG_LogRef LOG = {"io.alembic"};
33 
34 namespace blender::io::alembic {
35 
36 using Alembic::Abc::OObject;
37 using Alembic::AbcGeom::FloatArraySample;
38 using Alembic::AbcGeom::OBoolProperty;
39 using Alembic::AbcGeom::OCompoundProperty;
40 using Alembic::AbcGeom::ONuPatch;
41 using Alembic::AbcGeom::ONuPatchSchema;
42 
44 {
45 }
46 
48 {
49  Curve *curve = static_cast<Curve *>(context->object->data);
50  size_t num_nurbs = BLI_listbase_count(&curve->nurb);
51  OObject abc_parent = args_.abc_parent;
52  const char *abc_parent_path = abc_parent.getFullName().c_str();
53 
54  for (size_t i = 0; i < num_nurbs; i++) {
55  std::stringstream patch_name_stream;
56  patch_name_stream << args_.abc_name << '_' << i;
57 
58  while (abc_parent.getChildHeader(patch_name_stream.str())) {
59  patch_name_stream << "_";
60  }
61 
62  std::string patch_name = patch_name_stream.str();
63  CLOG_INFO(&LOG, 2, "exporting %s/%s", abc_parent_path, patch_name.c_str());
64 
65  ONuPatch nurbs(abc_parent, patch_name, timesample_index_);
66  abc_nurbs_.push_back(nurbs);
67  abc_nurbs_schemas_.push_back(nurbs.getSchema());
68  }
69 }
70 
72 {
73  if (abc_nurbs_.empty()) {
74  return OObject();
75  }
76  /* For parenting purposes within the Alembic file, all NURBS patches are equal, so just use the
77  * first one. */
78  return abc_nurbs_[0];
79 }
80 
81 Alembic::Abc::OCompoundProperty ABCNurbsWriter::abc_prop_for_custom_props()
82 {
83  if (abc_nurbs_.empty()) {
84  return Alembic::Abc::OCompoundProperty();
85  }
86 
87  /* A single NURBS object in Blender is expanded to multiple curves in Alembic.
88  * Just store the custom properties on the first one for simplicity. */
89  return abc_schema_prop_for_custom_props(abc_nurbs_schemas_[0]);
90 }
91 
93 {
94  /* Check if object has shape keys. */
95  Curve *cu = static_cast<Curve *>(context.object->data);
96  return (cu->key != nullptr);
97 }
98 
100 {
101  return ELEM(context->object->type, OB_SURF, OB_CURVE);
102 }
103 
104 static void get_knots(std::vector<float> &knots, const int num_knots, float *nu_knots)
105 {
106  if (num_knots <= 1) {
107  return;
108  }
109 
110  /* Add an extra knot at the beginning and end of the array since most apps
111  * require/expect them. */
112  knots.reserve(num_knots + 2);
113 
114  knots.push_back(0.0f);
115 
116  for (int i = 0; i < num_knots; i++) {
117  knots.push_back(nu_knots[i]);
118  }
119 
120  knots[0] = 2.0f * knots[1] - knots[2];
121  knots.push_back(2.0f * knots[num_knots] - knots[num_knots - 1]);
122 }
123 
125 {
126  Curve *curve = static_cast<Curve *>(context.object->data);
127  ListBase *nulb;
128 
129  if (context.object->runtime.curve_cache->deformed_nurbs.first != nullptr) {
130  nulb = &context.object->runtime.curve_cache->deformed_nurbs;
131  }
132  else {
133  nulb = BKE_curve_nurbs_get(curve);
134  }
135 
136  size_t count = 0;
137  for (Nurb *nu = static_cast<Nurb *>(nulb->first); nu; nu = nu->next, count++) {
138  std::vector<float> knotsU;
139  get_knots(knotsU, KNOTSU(nu), nu->knotsu);
140 
141  std::vector<float> knotsV;
142  get_knots(knotsV, KNOTSV(nu), nu->knotsv);
143 
144  const int size = nu->pntsu * nu->pntsv;
145  std::vector<Imath::V3f> positions(size);
146  std::vector<float> weights(size);
147 
148  const BPoint *bp = nu->bp;
149 
150  for (int i = 0; i < size; i++, bp++) {
151  copy_yup_from_zup(positions[i].getValue(), bp->vec);
152  weights[i] = bp->vec[3];
153  }
154 
155  ONuPatchSchema::Sample sample;
156  sample.setUOrder(nu->orderu + 1);
157  sample.setVOrder(nu->orderv + 1);
158  sample.setPositions(positions);
159  sample.setPositionWeights(weights);
160  sample.setUKnot(FloatArraySample(knotsU));
161  sample.setVKnot(FloatArraySample(knotsV));
162  sample.setNu(nu->pntsu);
163  sample.setNv(nu->pntsv);
164 
165  /* TODO(kevin): to accommodate other software we should duplicate control
166  * points to indicate that a NURBS is cyclic. */
167  OCompoundProperty user_props = abc_nurbs_schemas_[count].getUserProperties();
168 
169  if ((nu->flagu & CU_NURB_ENDPOINT) != 0) {
170  OBoolProperty prop(user_props, "endpoint_u");
171  prop.set(true);
172  }
173 
174  if ((nu->flagv & CU_NURB_ENDPOINT) != 0) {
175  OBoolProperty prop(user_props, "endpoint_v");
176  prop.set(true);
177  }
178 
179  if ((nu->flagu & CU_NURB_CYCLIC) != 0) {
180  OBoolProperty prop(user_props, "cyclic_u");
181  prop.set(true);
182  }
183 
184  if ((nu->flagv & CU_NURB_CYCLIC) != 0) {
185  OBoolProperty prop(user_props, "cyclic_v");
186  prop.set(true);
187  }
188 
189  abc_nurbs_schemas_[count].set(sample);
190  }
191 }
192 
193 } // namespace blender::io::alembic
#define KNOTSU(nu)
Definition: BKE_curve.h:68
#define KNOTSV(nu)
Definition: BKE_curve.h:70
ListBase * BKE_curve_nurbs_get(struct Curve *cu)
Definition: curve.c:5079
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define ELEM(...)
#define CLOG_INFO(clg_ref, level,...)
Definition: CLG_log.h:201
@ CU_NURB_CYCLIC
@ CU_NURB_ENDPOINT
Object is a sort of wrapper for general info.
@ OB_SURF
@ OB_CURVE
static CLG_LogRef LOG
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
Alembic::Abc::OCompoundProperty abc_schema_prop_for_custom_props(T abc_schema)
const ABCWriterConstructorArgs args_
virtual bool check_is_animated(const HierarchyContext &context) const override
virtual bool is_supported(const HierarchyContext *context) const override
virtual void create_alembic_objects(const HierarchyContext *context) override
ABCNurbsWriter(const ABCWriterConstructorArgs &args)
virtual void do_write(HierarchyContext &context) override
virtual Alembic::Abc::OObject get_alembic_object() const override
Alembic::Abc::OCompoundProperty abc_prop_for_custom_props() override
Curve curve
int count
static void sample(SocketReader *reader, int x, int y, float color[4])
static void get_knots(std::vector< float > &knots, const int num_knots, float *nu_knots)
BLI_INLINE void copy_yup_from_zup(float yup[3], const float zup[3])
struct SELECTID_Context context
Definition: select_engine.c:47
float vec[4]
struct Key * key
ListBase nurb
void * first
Definition: DNA_listBase.h:47
struct Nurb * next