1 /*
2 * NodeNurbsPositionInterpolator.cpp
3 *
4 * Copyright (C) 1999 Stephen F. White, 2004 J. "MUFTI" Scheurich
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file "COPYING" for details); if
18 * not, write to the Free Software Foundation, Inc., 675 Mass Ave,
19 * Cambridge, MA 02139, USA.
20 */
21
22 #include <stdio.h>
23 #include "stdafx.h"
24
25 #include "NodeNurbsPositionInterpolator.h"
26 #include "NodeNurbsCurve.h"
27 #include "NodeCoordinate.h"
28 #include "Proto.h"
29 #include "DuneApp.h"
30 #include "Scene.h"
31 #include "FieldValue.h"
32 #include "Field.h"
33 #include "SFFloat.h"
34 #include "SFInt32.h"
35 #include "SFBool.h"
36 #include "Vec2f.h"
37 #include "MoveCommand.h"
38 #include "RenderState.h"
39 #include "Util.h"
40
ProtoNurbsPositionInterpolator(Scene * scene)41 ProtoNurbsPositionInterpolator::ProtoNurbsPositionInterpolator(Scene *scene)
42 : Proto(scene, "NurbsPositionInterpolator")
43 {
44 dimension.set(
45 addExposedField(SFINT32, "dimension", new SFInt32(0)));
46 setFieldFlags(dimension, FF_VRML_ONLY);
47 controlPoint.set(
48 addExposedField(SFNODE, "controlPoint", new SFNode(NULL),
49 COORDINATE_NODE));
50 setFieldFlags(controlPoint, FF_X3D_ONLY);
51 weight.set(
52 addExposedField(MFDOUBLE, "keyWeight", new MFFloat(),
53 new MFDouble(0.0f), NULL, "weight"));
54 knot.set(
55 addField(MFDOUBLE, "knot", new MFDouble()));
56 order.set(
57 addField(SFINT32, "order", new SFInt32(4), new SFInt32(2)));
58 getField(order)->addX3dDefault(new SFInt32(3));
59 addEventIn(SFFLOAT, "set_fraction", EIF_RECOMMENDED);
60 addEventOut(SFVEC3F, "value_changed", EOF_RECOMMENDED);
61
62 addURLs(URL_VRML97_AMENDMENT1);
63 }
64
65 Node *
create(Scene * scene)66 ProtoNurbsPositionInterpolator::create(Scene *scene)
67 {
68 return new NodeNurbsPositionInterpolator(scene, this);
69 }
70
71 void
setField(int fieldIndex,FieldValue * value,int cf)72 NodeNurbsPositionInterpolator::setField(int fieldIndex, FieldValue *value,
73 int cf)
74 {
75 m_nurbsCurveDirty = true;
76 Node::setField(fieldIndex, value, cf);
77 }
78
NodeNurbsPositionInterpolator(Scene * scene,Proto * def)79 NodeNurbsPositionInterpolator::NodeNurbsPositionInterpolator(Scene *scene, Proto *def)
80 : Node(scene, def)
81 {
82 m_nurbsCurveDirty = true;
83 m_nurbsCurve = (NodeNurbsCurve *) scene->createNode("NurbsCurve");
84 m_nurbsCurve->setInternal(true);
85 m_set_fractionField.set(getProto()->lookupEventIn("set_fraction"));
86 m_value_changedField.set(getProto()->lookupEventOut("value_changed"));
87 }
88
~NodeNurbsPositionInterpolator()89 NodeNurbsPositionInterpolator::~NodeNurbsPositionInterpolator()
90 {
91 delete m_nurbsCurve;
92 }
93
94 MFVec3f *
getControlPoints(void)95 NodeNurbsPositionInterpolator::getControlPoints(void)
96 {
97 Node *pointNode = controlPoint()->getValue();
98 if (pointNode)
99 return ((NodeCoordinate *)pointNode)->point();
100 return NULL;
101 }
102
103 void
setControlPoints(const MFVec3f * points)104 NodeNurbsPositionInterpolator::setControlPoints(const MFVec3f *points)
105 {
106 NodeCoordinate *coord = (NodeCoordinate *)controlPoint()->getValue();
107 if (!coord)
108 coord = (NodeCoordinate *) m_scene->createNode("Coordinate");
109 if (coord != NULL) {
110 controlPoint(new SFNode(coord));
111 coord->setField(coord->point_Field(), new MFVec3f(points));
112 }
113 }
114
115 void
createNurbsCurve()116 NodeNurbsPositionInterpolator::createNurbsCurve()
117 {
118 float *points = new float[getControlPoints()->getSize()];
119 for (int i = 0; i < getControlPoints()->getSize(); i++)
120 points[i] = getControlPoints()->getValues()[i];
121 m_nurbsCurve->setControlPoints(new MFVec3f(points,
122 getControlPoints()->getSize()));
123 float *weights = new float[weight()->getSize()];
124 for (int i = 0; i < weight()->getSize(); i++)
125 weights[i] = weight()->getValues()[i];
126 m_nurbsCurve->weight(new MFFloat(weights, weight()->getSize()));
127 float *knots = new float[knot()->getSize()];
128 for (int i = 0; i < knot()->getSize(); i++)
129 knots[i] = knot()->getValues()[i];
130 m_nurbsCurve->knot(new MFFloat(knots, knot()->getSize()));
131 m_nurbsCurve->order(new SFInt32(order()->getValue()));
132 const Vec3f *chain = m_nurbsCurve->getChain();
133 int chainLength = m_nurbsCurve->getChainLength();
134 m_chainLength = 0;
135 float *fchain = new float[chainLength * 3];
136 for (int i = 0; i < chainLength; i++) {
137 fchain[i * 3 ] = chain[i].x;
138 fchain[i * 3 + 1] = chain[i].y;
139 fchain[i * 3 + 2] = chain[i].z;
140 if (i > 0)
141 m_chainLength += (chain[i] - chain[i - 1]).length();
142 }
143 m_nurbsCurveDirty = false;
144 }
145
146 int
writeProto(int f)147 NodeNurbsPositionInterpolator::writeProto(int f)
148 {
149 if (m_scene->isX3dXml())
150 return writeX3dProto(f);
151
152 RET_ONERROR( mywritestr(f ,"EXTERNPROTO NurbsPositionInterpolator[\n") )
153 TheApp->incSelectionLinenumber();
154 RET_ONERROR( writeProtoArguments(f) );
155 RET_ONERROR( mywritestr(f ," ]\n") )
156 TheApp->incSelectionLinenumber();
157 RET_ONERROR( mywritestr(f ,"[\n") )
158 TheApp->incSelectionLinenumber();
159 RET_ONERROR( mywritestr(f ," \"urn:web3d:vrml97:node:NurbsPositionInterpolator\",\n") )
160 TheApp->incSelectionLinenumber();
161 RET_ONERROR( mywritestr(f ," \"urn:inet:blaxxun.com:node:NurbsPositionInterpolator\",\n") )
162 TheApp->incSelectionLinenumber();
163 RET_ONERROR( mywritestr(f ," \"urn:ParaGraph:NurbsPositionInterpolator\",\n") )
164 TheApp->incSelectionLinenumber();
165 #ifdef HAVE_VRML97_AMENDMENT1_PROTO_URL
166 RET_ONERROR( mywritestr(f ," \"") )
167 RET_ONERROR( mywritestr(f ,HAVE_VRML97_AMENDMENT1_PROTO_URL) )
168 RET_ONERROR( mywritestr(f ,"/NurbsPositionInterpolatorPROTO.wrl") )
169 RET_ONERROR( mywritestr(f ,"\"\n") )
170 TheApp->incSelectionLinenumber();
171 #else
172 RET_ONERROR( mywritestr(f ," \"NurbsPositionInterpolatorPROTO.wrl\",\n") )
173 TheApp->incSelectionLinenumber();
174 #endif
175 RET_ONERROR( mywritestr(f ," \"http://wdune.ourproject.org/docs/vrml97Amendment1/NurbsPositionInterpolatorPROTO.wrl\"\n") )
176 TheApp->incSelectionLinenumber();
177 RET_ONERROR( mywritestr(f ,"]\n") )
178 TheApp->incSelectionLinenumber();
179 return 0;
180 }
181
182 int
write(int filedes,int indent,bool avoidUse)183 NodeNurbsPositionInterpolator::write(int filedes, int indent, bool avoidUse)
184 {
185 if (m_scene->isPureVRML()) {
186 Node *node = m_nurbsCurve->toPositionInterpolator();
187 if (node == NULL)
188 return 1;
189
190 // fixme: read Route connects of node and
191 // build routes to new node instead
192
193 RET_ONERROR( node->write(filedes, indent, avoidUse) )
194 node->unref();
195 } else
196 RET_ONERROR( Node::write(filedes, indent, avoidUse) )
197 return 0;
198 }
199
200 void
draw()201 NodeNurbsPositionInterpolator::draw()
202 {
203 if (m_nurbsCurveDirty) {
204 createNurbsCurve();
205 m_nurbsCurve->createChain();
206 m_nurbsCurveDirty = false;
207 }
208
209 if (!m_nurbsCurve) return;
210
211 float c[3] = { 1.0f, 1.0f, 1.0f };
212 Util::myGlMaterial3fv(GL_FRONT, GL_EMISSION, c);
213 m_nurbsCurve->draw();
214 }
215
216 void
drawHandles()217 NodeNurbsPositionInterpolator::drawHandles()
218 {
219 if (getControlPoints() == NULL)
220 return;
221 int iDimension = getControlPoints()->getSize() / 3;
222 RenderState state;
223
224 if (weight()->getSize() != iDimension) {
225 return;
226 }
227
228 glPushName(0);
229 glDisable(GL_LIGHTING);
230 Util::myGlColor3f(1.0f, 1.0f, 1.0f);
231
232 glLoadName(NO_HANDLE);
233 glBegin(GL_LINE_STRIP);
234 for (int i = 0; i < iDimension; i++) {
235 const float *v = getControlPoints()->getValue(i);
236 float w = weight()->getValue(i);
237 glVertex3f(v[0] / w, v[1] / w, v[2] / w);
238 }
239 glEnd();
240
241 state.startDrawHandles();
242 for (int ci = 0; ci < iDimension; ci++) {
243 state.setHandleColor(m_scene, ci);
244 glLoadName(ci);
245 state.drawHandle(Vec3f(getControlPoints()->getValue(ci)) /
246 weight()->getValue(ci));
247 }
248 state.endDrawHandles();
249 draw();
250 glPopName();
251 glEnable(GL_LIGHTING);
252 }
253
254 Vec3f
getHandle(int handle,int * constraint,int * field)255 NodeNurbsPositionInterpolator::getHandle(int handle, int *constraint,
256 int *field)
257 {
258 *field = controlPoint_Field() ;
259
260 if (handle >= 0 && handle < getControlPoints()->getSize() / 3) {
261 Vec3f ret((Vec3f)getControlPoints()->getValue(handle) /
262 weight()->getValue(handle));
263 return ret;
264 } else {
265 return Vec3f(0.0f, 0.0f, 0.0f);
266 }
267 }
268
269 void
setHandle(int handle,const Vec3f & v)270 NodeNurbsPositionInterpolator::setHandle(int handle, const Vec3f &v)
271 {
272 MFVec3f *oldValue = getControlPoints();
273 MFVec3f *newValue = (MFVec3f *)oldValue->copy();
274
275 if (handle >= 0 && handle < oldValue->getSize() / 3) {
276 Vec3f v2 = v * weight()->getValue(handle);
277 m_nurbsCurveDirty = true;
278 newValue->setValue(handle * 3, v2.x);
279 newValue->setValue(handle * 3+1, v2.y);
280 newValue->setValue(handle * 3+2, v2.z);
281 setControlPoints(newValue);
282 }
283 }
284
285 void
flip(int index)286 NodeNurbsPositionInterpolator::flip(int index)
287 {
288 if (getControlPoints())
289 getControlPoints()->flip(index);
290 m_nurbsCurveDirty = true;
291 }
292
293 void
swap(int fromTo)294 NodeNurbsPositionInterpolator::swap(int fromTo)
295 {
296 if (getControlPoints())
297 getControlPoints()->swap(fromTo);
298 m_nurbsCurveDirty = true;
299 }
300
301 Node *
toNurbsCurve(void)302 NodeNurbsPositionInterpolator::toNurbsCurve(void)
303 {
304 NodeNurbsCurve *node = (NodeNurbsCurve *) m_scene->createNode("NurbsCurve");
305
306 float *tmpControlPoints = new float[getControlPoints()->getSize()];
307 float *tmpWeights = new float[weight()->getSize()];
308 float *tmpKnots = new float[knot()->getSize()];
309 int tmpOrder = order()->getValue();
310
311 for(int i=0; i<getControlPoints()->getSize(); i++){
312 tmpControlPoints[i] = getControlPoints()->getValues()[i];
313 }
314
315 for(int i=0; i<(weight()->getSFSize()); i++){
316 tmpWeights[i] = weight()->getValue(i);
317 }
318
319 for(int i=0; i<(knot()->getSFSize()); i++){
320 tmpKnots[i] = knot()->getValue(i);
321 }
322
323 node->knot(new MFFloat(tmpKnots, knot()->getSFSize()));
324 node->setField(node->order_Field(), new SFInt32(tmpOrder));
325 node->setControlPoints(new MFVec3f(tmpControlPoints,
326 getControlPoints()->getSize()));
327 node->weight(new MFFloat(tmpWeights, weight()->getSFSize()));
328
329 return node;
330 }
331
332 void
receiveEvent(int eventIn,double timestamp,FieldValue * value)333 NodeNurbsPositionInterpolator::receiveEvent(int eventIn, double timestamp,
334 FieldValue *value)
335 {
336 if (m_nurbsCurveDirty) {
337 createNurbsCurve();
338 m_nurbsCurve->createChain();
339 m_nurbsCurveDirty = false;
340 }
341
342 if (!m_nurbsCurve) return;
343
344 if (eventIn == m_set_fractionField) {
345 float fraction = ((SFFloat *) value)->getValue();
346 float posChain = fraction * m_chainLength;
347 float pos = 0;
348 float oldPos = pos;
349 const Vec3f *chain = m_nurbsCurve->getChain();
350 int chainLength = m_nurbsCurve->getChainLength();
351 for (int i = 0; i < chainLength; i++) {
352 if (pos >= posChain) {
353 if (i == 0) {
354 sendEvent(m_value_changedField, timestamp,
355 new SFVec3f(chain[0].x, chain[0].y, chain[0].z));
356 break;
357 } else {
358 Vec3f vec = chain[i - 1] + ((chain[i] - chain[i - 1]) *
359 (pos - oldPos));
360 sendEvent(m_value_changedField, timestamp,
361 new SFVec3f(vec.x, vec.y, vec.z));
362 break;
363 }
364 }
365 if (i > 0)
366 pos += (chain[i] - chain[i - 1]).length();
367 oldPos = pos;
368 }
369 } else
370 Node::receiveEvent(eventIn, timestamp, value);
371 }
372
373