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