1 /*
2  * Scene.cpp
3  *
4  * Copyright (C) 1999 Stephen F. White
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 /***************************************************************************
23  * Scene::Download() based on ftpget example of Curl library
24  *
25  * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
26  *
27  * This software is licensed as described in the file COPYING, which
28  * you should have received as part of this distribution. The terms
29  * are also available at https://curl.haxx.se/docs/copyright.html.
30  *
31  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
32  * copies of the Software, and permit persons to whom the Software is
33  * furnished to do so, under the terms of the COPYING file.
34  *
35  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
36  * KIND, either express or implied.
37  *
38  ***************************************************************************/
39 
40 #include <stdio.h>
41 #include <string.h>
42 #include <stdarg.h>
43 #include <stdlib.h>
44 #include <limits.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <ctype.h>
48 #include "stdafx.h"
49 #ifndef _WIN32
50 # include <unistd.h>
51 # include <fcntl.h>
52 #endif
53 #include "Util.h"
54 #include "resource.h"
55 
56 #ifdef HAVE_LIBZ
57 extern "C" {
58 # include "zlib.h"
59 }
60 #endif
61 
62 #ifdef HAVE_LIBCURL
63 # include <curl/curl.h>
64 #endif
65 
66 #include "swt.h"
67 
68 #include "Scene.h"
69 #include "SceneProtoMap.h"
70 #include "SceneView.h"
71 #include "WonderlandModuleExport.h"
72 #include "Matrix.h"
73 #include "FieldValue.h"
74 #include "FieldCommand.h"
75 #include "MFieldCommand.h"
76 #include "CommandList.h"
77 #include "RouteCommand.h"
78 #include "UnRouteCommand.h"
79 #include "MoveCommand.h"
80 #include "Node.h"
81 #include "DynamicFieldsNode.h"
82 #include "SFNode.h"
83 #include "SFRotation.h"
84 #include "SFTime.h"
85 #include "MFNode.h"
86 #include "Proto.h"
87 #include "parser.h"
88 #include "Path.h"
89 #include "Field.h"
90 #include "EventIn.h"
91 #include "EventOut.h"
92 #include "ExposedField.h"
93 #include "URL.h"
94 #include "FontInfo.h"
95 #include "DuneApp.h"
96 #include "WriteFlags.h"
97 #include "RenderState.h"
98 #include "Interpolator.h"
99 #include "NextCommand.h"
100 #include "FaceData.h"
101 
102 #include "NodeTimeSensor.h"
103 #include "NodeVrmlCut.h"
104 #include "NodeVrmlScene.h"
105 #include "NodeNavigationInfo.h"
106 #include "NodeViewpoint.h"
107 #include "NodeOrthoViewpoint.h"
108 #include "NodeGeoViewpoint.h"
109 #include "NodeBackground.h"
110 #include "NodeCurveAnimation.h"
111 #include "NodeFog.h"
112 #include "NodeInline.h"
113 #include "NodeGroup.h"
114 #include "NodeShape.h"
115 #include "NodeIndexedFaceSet.h"
116 #include "NodeIndexedLineSet.h"
117 #include "NodeIndexedTriangleSet.h"
118 #include "NodeTriangleSet.h"
119 #include "NodeNurbsCurve.h"
120 #include "NodeNurbsSurface.h"
121 #include "NodeCattExportRec.h"
122 #include "NodeLdrawDatExport.h"
123 #include "NodeViewport.h"
124 #include "NodeTransform.h"
125 
126 #define ARRAY_SIZE(v)  ((int) (sizeof(v) / sizeof(v[0])))
127 
128 #define PICK_BUFFER_SIZE 65536
129 #define PICK_REGION_SIZE 2.5
130 
131 #define MAX_JAVA_CALLS 8000
132 
133 enum {
134     PICKED_NODE,
135     PICKED_HANDLE,
136     PICKED_RIGID_BODY_HANDLE,
137     PICKED_3DCURSOR
138 };
139 
Scene()140 Scene::Scene()
141 {
142     m_writeFlags = 0;
143 
144     m_numSymbols = 0;
145 
146     m_headlight = true;
147     m_numLights = 0;
148     m_numClipPlanes = 0;
149     m_selection = NULL;
150     m_selectedHandles.resize(0);
151     m_selectionMode = TheApp->GetIntPreference("SelectionMode",
152                                                SELECTION_MODE_VERTICES);
153     m_lastSelectedHandle = -1;
154     m_isNewSelectedHandle = false;
155     m_singleSelectedHandle = true;
156     m_transformMode = new TransformMode(
157           (TMode) TheApp->GetIntPreference("TransformMode",TM_HOVER),
158           (TDimension) TheApp->GetIntPreference("TransformDimension",TM_3D),
159           (T2axes) TheApp->GetIntPreference("Transform2Axes",TM_NEAR_FAR));
160     if (TheApp->getMaxNumberAxesInputDevices()<=4)
161         if ((m_transformMode->tmode == TM_6D) || (m_transformMode->tmode == TM_6D))
162             m_transformMode->tmode = TM_HOVER;
163     if (TheApp->getMaxNumberAxesInputDevices()<3)
164         if (m_transformMode->tmode == TM_ROCKET)
165             m_transformMode->tmode = TM_HOVER;
166     if (TheApp->getMaxNumberAxesInputDevices()<2)
167         if (m_transformMode->tmode >= TM_6D)
168             m_transformMode->tmode = TM_TRANSLATE;
169 
170     m_root = NULL;
171     m_unmodified = NULL;
172     resetWriteFlags(0);
173     m_extraModifiedFlag = false;
174 
175     m_x3dVersion = -1;
176 
177     m_unitLength = 1;
178     m_unitAngle = 1;
179 
180     SceneProtoMap::createProtoMap(&m_protos, this);
181 
182     StringArray *allNodeNames = getAllNodeNames();
183     m_numberBuildinProtos = allNodeNames->size();
184     delete allNodeNames;
185 
186     m_root = createNode("Group");
187     m_root->ref();
188     m_rootField = ((NodeGroup *) m_root)->children_Field();
189     m_running = false;
190     m_recording = false;
191 
192     m_setViewpoint = false;
193 
194     m_defaultViewpoint = NULL;
195     m_currentViewpoint = NULL;
196     updateViewpoint();
197 
198     m_setNavigationInfo = false;
199     m_defaultNavigationInfo = (NodeNavigationInfo *)
200                              createNode("NavigationInfo");
201     m_defaultNavigationInfo->ref();
202 
203     m_currentNavigationInfo = m_defaultNavigationInfo;
204     m_currentNavigationInfo->ref();
205 
206     m_currentFog = NULL;
207     m_currentBackground = NULL;
208 
209     m_numProtoNames = 0;
210     m_numProtoDefinitions = 0;
211 
212     m_navigationMouseMode = true;
213     m_navigationInputDeviceMode = true;
214 
215     m_routeList.Init();
216 
217     m_selectlevel = 1;
218     m_hasFocus = false;
219 
220     m_viewOfLastSelection = NULL;
221     m_selection_is_in_scene = false;
222     m_URL = "";
223     m_newURL = "";
224     m_errorLineNumber = -1;
225 
226     m_obj3dCursor = gluNewQuadric();
227 
228     m_backupCommandList = NULL;
229 
230     m_use3dCursor = false;
231 
232     m_nodesWithExternProto.append("Contour2D");
233     m_nodesWithExternProto.append("CoordinateDeformer");
234     m_nodesWithExternProto.append("InlineLoadControl");
235     m_nodesWithExternProto.append("LoadSensor");
236 
237     m_nodesWithExternProto.append("NurbsCurve");
238     m_nodesWithExternProto.append("NurbsCurve2D");
239     m_nodesWithExternProto.append("NurbsGroup");
240     m_nodesWithExternProto.append("NurbsPositionInterpolator");
241     m_nodesWithExternProto.append("NurbsSurface");
242     m_nodesWithExternProto.append("NurbsTextureSurface");
243     m_nodesWithExternProto.append("TrimmedSurface");
244 
245     m_nodesWithExternProto.append("Arc2D");
246     m_nodesWithExternProto.append("ArcClose2D");
247     m_nodesWithExternProto.append("BooleanFilter");
248     m_nodesWithExternProto.append("BooleanSequencer");
249     m_nodesWithExternProto.append("BooleanToggle");
250     m_nodesWithExternProto.append("BooleanTrigger");
251     m_nodesWithExternProto.append("Circle2D");
252     m_nodesWithExternProto.append("ColorRGBA");
253     m_nodesWithExternProto.append("CoordinateInterpolator2D");
254     m_nodesWithExternProto.append("Disk2D");
255     m_nodesWithExternProto.append("FillProperties");
256     m_nodesWithExternProto.append("IntegerSequencer");
257     m_nodesWithExternProto.append("IntegerTrigger");
258     m_nodesWithExternProto.append("KeySensor");
259     m_nodesWithExternProto.append("LineProperties");
260     m_nodesWithExternProto.append("Metadata");
261     m_nodesWithExternProto.append("MetadataBoolean");
262     m_nodesWithExternProto.append("MetadataDouble");
263     m_nodesWithExternProto.append("MetadataFloat");
264     m_nodesWithExternProto.append("MetadataInteger");
265     m_nodesWithExternProto.append("MetadataSet");
266     m_nodesWithExternProto.append("MetadataString");
267     m_nodesWithExternProto.append("MultiTexture");
268     m_nodesWithExternProto.append("Polyline2D");
269     m_nodesWithExternProto.append("Polypoint2D");
270     m_nodesWithExternProto.append("PositionInterpolator2D");
271     m_nodesWithExternProto.append("Rectangle2D");
272     m_nodesWithExternProto.append("StringSensor");
273     m_nodesWithExternProto.append("TimeTrigger");
274     m_nodesWithExternProto.append("TriangleSet2D");
275 
276     m_nodesWithExternProto.append("SuperEllipsoid");
277     m_nodesWithExternProto.append("SuperExtrusion");
278     m_nodesWithExternProto.append("SuperShape");
279     m_nodesWithExternProto.append("SuperRevolver");
280 
281     m_nodesWithExternProto.append("CattExportRec");
282     m_nodesWithExternProto.append("CattExportSrc");
283 
284     m_nodesWithExternProto.append("LdrawDatExport");
285     m_nodesWithExternProto.append("WonderlandImportJava");
286 
287     m_nodesWithExternProto.append("VrmlCut");
288     m_nodesForceExternProtoWrite.append("VrmlCut");
289     m_nodesWithExternProto.append("VrmlScene");
290     m_nodesForceExternProtoWrite.append("VrmlScene");
291 
292     m_nodesWithExternProto.append("CurveAnimation");
293 
294     m_nodesWithExternProto.append("ARSensor");
295     m_nodesWithExternProto.append("COVER");
296     m_nodesWithExternProto.append("CubeTexture");
297     m_nodesWithExternProto.append("JoystickSensor");
298     m_nodesWithExternProto.append("LabView");
299     m_nodesWithExternProto.append("SpaceSensor");
300     m_nodesWithExternProto.append("Sky");
301     m_nodesWithExternProto.append("SteeringWheel");
302     m_nodesWithExternProto.append("TUIButton");
303     m_nodesWithExternProto.append("TUIComboBox");
304     m_nodesWithExternProto.append("TUIFloatSlider");
305     m_nodesWithExternProto.append("TUIFrame");
306     m_nodesWithExternProto.append("TUILabel");
307     m_nodesWithExternProto.append("TUIListBox");
308     m_nodesWithExternProto.append("TUIMap");
309     m_nodesWithExternProto.append("TUIProgressBar");
310     m_nodesWithExternProto.append("TUISlider");
311     m_nodesWithExternProto.append("TUISplitter");
312     m_nodesWithExternProto.append("TUITab");
313     m_nodesWithExternProto.append("TUITabFolder");
314     m_nodesWithExternProto.append("TUIToggleButton");
315     m_nodesWithExternProto.append("Vehicle");
316     m_nodesWithExternProto.append("VirtualAcoustics");
317     m_nodesWithExternProto.append("VirtualSoundSource");
318     m_nodesWithExternProto.append("Wave");
319 
320     m_nodesWithExternProto.append("BlendMode");
321     m_nodesWithExternProto.append("ColorSetInterpolator");
322     m_nodesWithExternProto.append("CubicBezier2DOrientationInterpolator");
323     m_nodesWithExternProto.append("CubicBezierPositionInterpolator");
324     m_nodesWithExternProto.append("GeneratedShadowMap");
325     m_nodesWithExternProto.append("MatrixTransform");
326     m_nodesWithExternProto.append("KambiAppearance");
327     m_nodesWithExternProto.append("KambiHeadLight");
328     m_nodesWithExternProto.append("KambiInline");
329     m_nodesWithExternProto.append("KambiNavigationInfo");
330     m_nodesWithExternProto.append("KambiTriangulation");
331     m_nodesWithExternProto.append("OctreeProperties");
332     m_nodesWithExternProto.append("ProjectedTextureCoordinate");
333     m_nodesWithExternProto.append("RenderedTexture");
334     m_nodesWithExternProto.append("Teapot");
335     m_nodesWithExternProto.append("Text3D");
336     m_nodesWithExternProto.append("KambiTriangulation");
337     m_nodesWithExternProto.append("VectorInterpolator");
338 
339     m_externProtoWarning = true;
340     TheApp->readProtoLibrary(this);
341     m_isParsing = false;
342     m_hasJoints = false;
343     m_showJoints = false;
344     m_headlightIsSet = false;
345     m_xrayRendering = false;
346     m_defNode = NULL;
347     buildInteractiveProtos();
348     m_importIntoVrmlScene = false;
349     m_rigidBodyHandleNode = NULL;
350     m_writeKanimNow = false;
351     m_ac3dEmptyMaterial = 0;
352     m_canUpdateViewsSelection = true;
353     m_variableCounter = 0;
354     m_deselect = false;
355     zeroNumDataClasses();
356     zeroNumDataFunctions();
357     m_startNumDataFunctions = 0;
358     m_numDataFunctionsPerClass = 0;
359     m_numDraw = 0;
360     m_lastSelectedHAnimJoint = NULL;
361     m_downloaded = false;
362     m_path = "";
363     m_pathIntern = "";
364     m_firstSelectionRangeHandle = -1;
365     m_saved_vrml = true;
366     m_saved_x3dv = true;
367     m_saved_x3dxml = true;
368     setSelection(getRoot());
369     setViewPorts();
370     m_oldTime = swGetCurrentTime();
371     updateTime();
372     m_viewpointUpdated = false;
373     m_drawViewPorts = true;
374     m_width = 1024;
375     m_height = 768;
376     m_hasParticleSystem = false;
377     m_hasMovieTexture = false;
378     m_infoHandles = false;
379     m_glName = 0;
380     m_vertexModifier = NULL;
381     m_storeAsHtml = false;
382     m_similarNameFlag = true;
383     m_convexHullCounter = 0;
384 }
385 
386 void
updateViewpoint(void)387 Scene::updateViewpoint(void)
388 {
389     if (m_defaultViewpoint)
390         m_defaultViewpoint->unref();
391     m_defaultViewpoint = (NodeViewpoint *) createNode("Viewpoint");
392     m_defaultViewpoint->ref();
393 
394     if (m_currentViewpoint)
395         m_currentViewpoint->unref();
396     m_currentViewpoint = m_defaultViewpoint;
397     m_currentViewpoint->ref();
398 
399     m_viewpointUpdated = true;
400 }
401 
~Scene()402 Scene::~Scene()
403 {
404     TheApp->SetIntPreference("TransformMode",m_transformMode->tmode);
405     TheApp->SetIntPreference("TransformDimension",m_transformMode->tdimension);
406     TheApp->SetIntPreference("Transform2Axes",m_transformMode->t2axes);
407 
408     TheApp->SetIntPreference("SelectionMode", m_selectionMode);
409 /*
410     while (!m_undoStack.empty()) delete m_undoStack.pop();
411 
412     while (!m_redoStack.empty()) delete m_redoStack.pop();
413 */
414 
415     m_defaultViewpoint->unref();
416     m_currentViewpoint->unref();
417 
418     delete m_selection;
419     m_selection = NULL;
420 
421     m_root->unref();
422 
423     ProtoMap::Chain::Iterator *j;
424 
425     for (int i = 0; i < m_protos.width(); i++) {
426         for (j = m_protos.chain(i).first(); j != NULL; j = j->next()) {
427             delete j->item()->getData();
428         }
429     }
430     for (long i = 0; i < m_fonts.size(); i++) {
431         delete m_fonts[i];
432     }
433     gluDeleteQuadric(m_obj3dCursor);
434 }
435 
updateSceneMap(void)436 void Scene::updateSceneMap(void)
437 {
438     SceneProtoMap::updateProtoMap(&m_protos, this);
439 }
440 
def(const char * nodeName,Node * value)441 void Scene::def(const char *nodeName, Node *value)
442 {
443     if (value && nodeName && (strlen(nodeName) > 0)) {
444         value->setName(nodeName);
445         m_nodeMap[nodeName] = value;
446         Proto *proto = value->getProto();
447         if (proto && (proto->isDynamicProto()))
448             proto->buildExportNames(nodeName);
449     }
450 }
451 
undef(MyString nodeName)452 void Scene::undef(MyString nodeName)
453 {
454     if (nodeName && nodeName.length() > 0) {
455        m_defNode = m_nodeMap[nodeName];
456        if (m_defNode && m_defNode->getRefs() > 1)
457            m_nodeMap.remove(nodeName);
458     }
459 }
460 
use(const char * nodeName)461 Node *Scene::use(const char *nodeName)
462 {
463     return m_nodeMap[nodeName];
464 }
465 
unuse(const char * nodeName)466 void Scene::unuse(const char *nodeName)
467 {
468     NodeMap::Chain::Iterator *nodeIterator;
469     NodeMap::Chain::Iterator *j;
470     for (int i = 0; i < m_nodeMap.width(); i++) {
471         for (j = m_nodeMap.chain(i).first(); j != NULL; j = j->next())
472             nodeIterator = j;
473     }
474     if (nodeIterator) {
475         Node *node = nodeIterator->item()->getData();
476         if (node->hasParent()) {
477             Node *parent = node->getParent();
478             int parentField = node->getParentField();
479             MFNode *mfnode = (MFNode *)parent->getField(parentField);
480             int index = 0;
481             for (int i = 0; i < mfnode->getSize(); i++) {
482                  if (mfnode->getValue(i) == node)
483                      index = i;
484             }
485             Node *selection = node->getScene()->getSelection()->getNode();
486             MoveCommand command(node, parent, parentField, NULL, -1, index,
487                                 true);
488             command.execute();
489             selection->getScene()->UpdateViews(NULL, UPDATE_ALL, NULL);
490             selection->getScene()->setSelection(selection);
491             selection->getScene()->UpdateViews(NULL, UPDATE_SELECTION, NULL);
492         }
493     }
494 }
495 
canUse(Node * parentNode,int parentField)496 bool Scene::canUse(Node *parentNode, int parentField)
497 {
498     if (m_defNode == NULL)
499         return false;
500     // avoid to create recursive scenegraphs
501     if (m_defNode == parentNode)
502         return false;
503     return getDestField(m_defNode, parentNode, parentField) >= 0;
504 }
505 
use(Node * parentNode,int parentField)506 bool Scene::use(Node *parentNode, int parentField)
507 {
508     // avoid to create recursive scenegraphs
509     Node *testRecursive = parentNode;
510     while (testRecursive->hasParent()) {
511        if (testRecursive == m_defNode)
512            return false;
513        testRecursive = testRecursive->getParent();
514     }
515 
516     int destField = getDestField(m_defNode, parentNode, parentField);
517     if (destField >= 0)
518         execute(new MoveCommand(m_defNode, NULL, -1, parentNode, destField));
519 
520     return true;
521 }
522 
getDestField(Node * src,Node * dest,int destField)523 int Scene::getDestField(Node* src, Node *dest, int destField)
524 {
525     int field = destField;
526     if (field == -1)
527         field = dest->findValidField(src);
528     if (dest->validChildType(field, src->getNodeClass()) ||
529         dest->validChildType(field, src->getType())) {
530         if (src->isInvalidChildNode()) {
531             if (dest->getType() == VRML_NURBS_GROUP)
532                 return field;
533             if (dest->getProto()->getField(field)->getNodeType() & CHILD_NODE)
534                 return -1;
535         }
536         return field;
537     }
538     return -1;
539 }
540 
541 int
addSymbol(MyString s)542 Scene::addSymbol(MyString s)
543 {
544     int &id = m_symbols[s];
545 
546     if (id == 0) {
547         id = m_numSymbols++;
548         m_symbolList[id] = s;
549     }
550     return id;
551 }
552 
553 const MyString &
getSymbol(int id) const554 Scene::getSymbol(int id) const
555 {
556     return m_symbolList[id];
557 }
558 
559 void
setNodes(NodeList * nodes)560 Scene::setNodes(NodeList *nodes)
561 {
562     ((NodeGroup *)m_root)->children(new MFNode(nodes));
563 }
564 
searchViewPortOrParticles(Node * node,void * data)565 static bool searchViewPortOrParticles(Node *node, void *data)
566 {
567     Scene *scene = (Scene *)data;
568     if (node->getType() == X3D_VIEWPORT) {
569         scene->addViewPort(node);
570     } else if (node->getType() == X3D_LAYOUT_GROUP) {
571         scene->addViewPort(node);
572     } else if (node->getType() == X3D_LAYOUT_LAYER) {
573         scene->addViewPort(node);
574     } else if (node->getType() == X3D_PARTICLE_SYSTEM) {
575         scene->setParticleSystem(true);
576     }
577     return true;
578 }
579 
searchMovieTexture(Node * node,void * data)580 static bool searchMovieTexture(Node *node, void *data)
581 {
582     Scene *scene = (Scene *)data;
583     if (node->getType() == VRML_MOVIE_TEXTURE) {
584         scene->setMovieTexture(true);
585     }
586     return true;
587 }
588 
589 void
setViewPorts(void)590 Scene::setViewPorts(void)
591 {
592     m_viewports.resize(0);
593     m_hasParticleSystem = false;
594     m_hasMovieTexture = false;
595     m_root->doWithBranch(searchViewPortOrParticles, this);
596     m_root->doWithBranch(searchMovieTexture, this);
597 }
598 
599 void
addNodes(Node * targetNode,int targetField,NodeList * nodes,int scanFor)600 Scene::addNodes(Node *targetNode, int targetField, NodeList *nodes, int scanFor)
601 {
602     if (targetNode == NULL)
603         m_root->addFieldNodeList(m_rootField, nodes);
604     else if (targetField == -1)
605         targetNode->addFieldNodeList(m_rootField, nodes);
606     else if (targetNode->getField(targetField) &&
607              targetNode->getField(targetField)->getType() == MFNODE) {
608         targetNode->setField(targetField, new MFNode(nodes));
609     } else if (targetNode->getField(targetField) &&
610                targetNode->getField(targetField)->getType() == SFNODE) {
611         SFNode *oldSFNode = (SFNode *)targetNode->getField(targetField);
612         MoveCommand *removeCommand = new MoveCommand(oldSFNode->getValue(),
613                                                      targetNode, targetField,
614                                                      NULL, -1);
615         removeCommand->execute();
616         if (nodes->size() > 0) {
617             Node *lastNode = nodes->get(nodes->size() - 1);
618             MoveCommand *addCommand = new MoveCommand(lastNode, NULL, -1,
619                                                       targetNode, targetField);
620            addCommand->execute();
621        }
622     } else if (targetNode->getField(targetField)) {
623         // wrong targetField
624         assert(0);
625     }
626     if ((scanFor == SCAN_FOR_BOTH) || (scanFor == SCAN_FOR_EXTERN_PROTO))
627         scanForExternProtos(nodes);
628     if ((scanFor == SCAN_FOR_BOTH) || (scanFor == SCAN_FOR_INLINE))
629         scanForInlines(nodes);
630     scanForMultimedia(nodes);
631     nodes->clearFlag(NODE_FLAG_TOUCHED);
632     for (long i = 0; i < nodes->size(); i++)
633         if (nodes->get(i))
634             nodes->get(i)->doWithBranch(searchViewPortOrParticles, this,
635                                         false);
636 }
637 
loadInline(Node * node,void * data)638 static bool loadInline(Node *node, void *data)
639 {
640     if ((node->getType() == VRML_INLINE) ||
641         (node->getType() == VRML_INLINE_LOAD_CONTROL))
642         if (TheApp->loadNewInline()) {
643             NodeInline *nodeInline =(NodeInline *)node;
644             node->getScene()->readInline(nodeInline);
645             if (node->getLoadedNodes() != NULL)
646                 for (long j = 0; j < node->getLoadedNodes()->size(); j++) {
647                     Node *inlinedNode = node->getLoadedNodes()->get(j);
648                     inlinedNode->doWithBranch(loadInline, NULL);
649                 }
650         }
651     return true;
652 }
653 
readInlines(Node * node,void * data)654 static bool readInlines(Node *node, void *data)
655 {
656     if ((node->getType() == VRML_INLINE) ||
657         (node->getType() == VRML_INLINE_LOAD_CONTROL))
658         loadInline(node, NULL);
659     return true;
660 }
661 
662 void
scanForInlines(NodeList * nodes)663 Scene::scanForInlines(NodeList *nodes)
664 {
665      nodes->doWithBranch(readInlines, NULL, false, true, false, true, false);
666 }
667 
loadMultimedia(Node * node,void * data)668 static bool loadMultimedia(Node *node, void *data)
669 {
670     if ((node->getType() == VRML_IMAGE_TEXTURE) ||
671         (node->getType() == VRML_AUDIO_CLIP) ||
672         (node->getType() == VRML_MOVIE_TEXTURE) ||
673         (node->getType() == VRML_GEO_LOD) ||
674         (node->getType() == X3DOM_BINARY_GEOMETRY) ||
675         (node->getType() == X3DOM_EXTERNAL_GEOMETRY) ||
676         (node->getType() == X3DOM_POP_GEOMETRY_LEVEL) ||
677         (node->getType() == X3DOM_MULTI_PART) ||
678         (node->getType() == X3D_IMAGE_TEXTURE_3D) ||
679         (node->getType() == X3D_DIS_ENTITY_TYPE_MAPPING))
680         node->load();
681     return true;
682 }
683 
684 
685 void
scanForMultimedia(NodeList * nodes)686 Scene::scanForMultimedia(NodeList *nodes)
687 {
688      nodes->doWithBranch(loadMultimedia, NULL, false, true, false, true, false);
689 }
690 
691 
recreateNodePROTO(Node * node,void * data)692 static bool recreateNodePROTO(Node *node, void *data)
693 {
694     if (node->isPROTO() && (node->getProto()->isLoaded())) {
695         NodePROTO *protoNode = (NodePROTO *)node;
696         if (!(protoNode->isLoaded())) {
697             protoNode->handleIs();
698             protoNode->createPROTO();
699             protoNode->reInit();
700         }
701     }
702     return true;
703 }
704 
705 void
scanForExternProtos(NodeList * nodes)706 Scene::scanForExternProtos(NodeList *nodes)
707 {
708     ProtoMap::Chain::Iterator *j;
709     for (int i = 0; i < m_protos.width(); i++) {
710         for (j = m_protos.chain(i).first(); j != NULL; j = j->next()) {
711             Proto *proto = j->item()->getData();
712             if (proto == NULL)
713                 continue;
714             if (belongsToNodeWithExternProto(proto->getName(isX3d())))
715                 continue;
716             if (proto->isCoverProto() ||
717                 proto->isKambiProto() ||
718                 proto->isX3domProto())
719                 continue;
720             if (proto->isX3dInternalProto())
721                 continue;
722             if (proto == NULL)
723                 continue;
724             if (proto->isLoaded())
725                 continue;
726             if (proto->isLoading())
727                 continue;
728 #ifdef NURBS_CURVE_ANIMATION_COMPATIBILTY
729             if (strcmp(proto->getName(true), "NurbsCurveAnimation") == 0) {
730                 readExternProto(proto);
731                 continue;
732             }
733 #endif
734             if ((proto->getUrls() != NULL) && (!proto->isInternUrl())) {
735                 if (!readExternProto(proto)) {
736                     MFString *urls = (MFString *)proto->getUrls();
737                     MyString files = "";
738                     for (int i = 0; i < urls->getSize(); i++) {
739                          files += urls->getValue(i);
740                          static MyString path = urls->getValue(i);
741                          if (Download((const char*)getURL(), &path))
742                              break;
743                          files += " ";
744                          if (i == urls->getSize() -1)
745                             TheApp->MessageBox(IDS_EXTERNPROTO_FILE_FAILED,
746                                                proto->getName(isX3d()), files);
747                     }
748                 }
749             }
750         }
751     }
752     nodes->doWithBranch(recreateNodePROTO, NULL, false, true, false, true,
753                                                  false);
754 }
755 
756 void
addToNodeList(Node * node)757 Scene::addToNodeList(Node *node)
758 {
759     m_nodeList.append(node);
760 }
761 
checkNodeType(Node * node,void * data)762 static bool checkNodeType(Node *node, void *data)
763 {
764     int *nodeType = (int *) data;
765     if (node->getType() == *nodeType)
766         node->getScene()->addToNodeList(node);
767     return true;
768 }
769 
770 NodeList *
searchNodeType(int nodeType)771 Scene::searchNodeType(int nodeType)
772 {
773     m_nodeList.resize(0);
774     m_root->doWithBranch(checkNodeType, &nodeType);
775     NodeList *nodeList = new NodeList();
776     for (long i = 0; i < m_nodeList.size(); i++)
777         nodeList->append(m_nodeList[i]);
778         // delete returned NodeList after usage
779     return nodeList;
780 }
781 
782 void
readInline(NodeInline * node)783 Scene::readInline(NodeInline *node)
784 {
785     if (node->alreadyLoaded()) {
786         return;
787     }
788     MyString oldDir = "";
789     oldDir += TheApp->getImportURL();
790     MFString *urls = node->url();
791     if (urls == NULL)
792         return;
793     for (int j = 0; j < urls->getSize(); j++) {
794         if (urls->getValue(j).length() == 0)
795             continue;
796         URL url(oldDir, urls->getValue(j));
797         MyString path;
798         if (Download(url, &path)) {
799             TheApp->setImportURL(url.GetPath());
800             struct stat fileStat;
801             MyString filename = "";
802             filename += path;
803             if (stat(filename, &fileStat) == 0) {
804                 if (S_ISREG(fileStat.st_mode)) {
805                     bool oldX3d = isX3d();
806                     FILE *file = fopen(filename, "rb");
807                     if (file == NULL) {
808                         TheApp->MessageBoxPerror(IDS_INLINE_FILE_FAILED,
809                                                  filename);
810                         continue;
811                     }
812                     double oldUnitLength = getUnitLength();
813                     pushUnitLength();
814                     TheApp->setImportFile(filename);
815                     parse(file, node, -1, SCAN_FOR_BOTH);
816                     TheApp->setSkipChecks(false);
817                     node->setUnitLength(oldUnitLength / getUnitLength());
818                     popUnitLength();
819                     fclose(file);
820                     if (oldX3d && (!isX3d()))
821                         setX3d();
822                     else if ((!oldX3d) && isX3d())
823                         setVrml();
824                     break;
825                 }
826             }
827         }
828     }
829     TheApp->setImportURL(oldDir);
830 }
831 
832 bool
readExternProto(Proto * proto)833 Scene::readExternProto(Proto *proto)
834 {
835     if (proto->isInternUrl())
836         return true;
837     if (proto->isDefined() && proto->isLoaded())
838         return true;
839     MyString oldDir = "";
840     oldDir += TheApp->getImportURL();
841     FILE* file = NULL;
842     bool oldX3d = isX3d();
843     MFString *urls = (MFString *)proto->getUrls();
844     if (urls == NULL)
845         return false;
846     for (int j = 0; j < urls->getSize(); j++) {
847         if (urls->getValue(j).length() == 0)
848             continue;
849         URL url(oldDir, urls->getValue(j));
850         url.TrimTopic();
851         MyString path;
852         if (Download(url, &path)) {
853             struct stat fileStat;
854             const char *filename = path;
855             if (stat(filename, &fileStat) == 0) {
856                 if (S_ISREG(fileStat.st_mode)) {
857                     file = fopen(filename, "rb");
858                     if (file == NULL)
859                         continue;
860                     Node *oldTargetNode = targetNode;
861                     int oldTargetField = targetField;
862                     // fake root node, will be ignored later
863                     NodeGroup *node = (NodeGroup *)createNode("Group");
864                     if (proto->isLoading()) {
865                         fclose(file);
866                         return true;
867                     }
868                     proto->setLoading(true);
869                     double oldUnitLength = getUnitLength();
870                     pushUnitLength();
871                     pushUnitAngle();
872                     TheApp->setImportURL(oldDir);
873                     TheApp->setImportFile(filename);
874                     parse(file, node, node->children_Field(),
875                           SCAN_FOR_EXTERN_PROTO);
876                     proto->setLoaded(true);
877                     proto->setUnitLength(oldUnitLength / getUnitLength());
878                     proto->setUnitAngle(getUnitAngle());
879                     popUnitAngle();
880                     popUnitLength();
881                     proto->setLoading(false);
882                     targetNode = oldTargetNode;
883                     targetField = oldTargetField;
884                     fclose(file);
885                     if (oldX3d && (!isX3d()))
886                         setX3d();
887                     else if ((!oldX3d) && isX3d())
888                         setVrml();
889                     updateNodePROTOs(proto);
890                     break;
891                 }
892             }
893         }
894     }
895     if (file == NULL)
896         return false;
897     return true;
898 }
899 
900 
getProfileCallback(Node * node,void * data)901 static bool getProfileCallback(Node *node, void *data)
902 {
903     int *currentProfile = (int *)data;
904     if (node->getProfile() > *currentProfile)
905         *currentProfile = node->getProfile();
906     return true;
907 }
908 
909 
910 int
writeRouteStrings(int filedes,int indent,bool end)911 Scene::writeRouteStrings(int filedes, int indent, bool end)
912 {
913     static bool alreadyIn = false;
914     // avoid recursive call of writeRouteStrings via Node::write
915     if (alreadyIn)
916         return 0;
917     alreadyIn = true;
918     // write tempory nodes first
919     for (long i = 0; i < m_delayedWriteNodes.size(); i++) {
920         int ret = 0;
921         if (isX3dXml())
922             ret = m_delayedWriteNodes[i]->writeXml(filedes, indent);
923         else
924             ret = m_delayedWriteNodes[i]->write(filedes, indent);
925         if (ret < 0) {
926             alreadyIn = false;
927             return ret;
928         }
929         removeNode(m_delayedWriteNodes[i]);
930     }
931     if (m_delayedWriteNodes.size() > 0)
932         m_delayedWriteNodes.resize(0);
933     alreadyIn = false;
934 
935     // sort out multiple ROUTEs
936     if (m_routeList.size() != 0)
937        for (List<MyString>::Iterator* routepointer = m_routeList.first();
938             routepointer != NULL; routepointer = routepointer->next() )
939             for (List<MyString>::Iterator* routepointer2 = m_routeList.first();
940                 routepointer2 != NULL; routepointer2 = routepointer2->next() )
941           if (routepointer2 != routepointer)
942               if (strcmp((const char*) routepointer->item(),
943                          (const char*) routepointer2->item()) == 0)
944                   m_routeList.remove(routepointer2);
945 
946     if (m_routeList.size() != 0) {
947        for (List<MyString>::Iterator* routepointer = m_routeList.first();
948             routepointer != NULL; routepointer = routepointer->next() )
949           {
950           RET_ONERROR( indentf(filedes, indent) )
951           RET_ONERROR( mywritestr(filedes, (const char*) routepointer->item()) )
952           RET_ONERROR( mywritestr(filedes, "\n") )
953           TheApp->incSelectionLinenumber();
954           }
955        RET_ONERROR( mywritestr(filedes, "\n") )
956        TheApp->incSelectionLinenumber();
957        m_routeList.removeAll();
958     }
959 
960     // sort out multiple ROUTEs
961     if (end && m_endRouteList.size() != 0)
962        for (List<MyString>::Iterator* routepointer = m_endRouteList.first();
963             routepointer != NULL; routepointer = routepointer->next() )
964             for (List<MyString>::Iterator* routepointer2 = m_endRouteList.first();
965                 routepointer2 != NULL; routepointer2 = routepointer2->next() )
966           if (routepointer2 != routepointer)
967               if (strcmp((const char*) routepointer->item(),
968                          (const char*) routepointer2->item()) == 0)
969                   m_endRouteList.remove(routepointer2);
970 
971     if (end && m_endRouteList.size() != 0) {
972        for (List<MyString>::Iterator* routepointer = m_endRouteList.first();
973             routepointer != NULL; routepointer = routepointer->next() )
974           {
975           RET_ONERROR( indentf(filedes, indent) )
976           RET_ONERROR( mywritestr(filedes, (const char*) routepointer->item()) )
977           RET_ONERROR( mywritestr(filedes, "\n") )
978           TheApp->incSelectionLinenumber();
979           }
980        RET_ONERROR( mywritestr(filedes, "\n") )
981        TheApp->incSelectionLinenumber();
982        m_endRouteList.removeAll();
983     }
984     return 0;
985 }
986 
writeExternProto(int f,const char * protoName)987 int Scene::writeExternProto(int f, const char* protoName)
988 {
989     // search if EXTERNPROTO already exist
990     bool foundProto = false;
991     for (int i = 0; i < m_numProtoNames; i++)
992         if (strcmp((const char*)m_protoNames[i], protoName)==0) {
993             foundProto = true;
994             // force writing of some nodes despite EXTERNPROTO already exist
995             for (long j = 0; j < m_nodesForceExternProtoWrite.size(); j++)
996                 if (strcmp(m_nodesForceExternProtoWrite[j], protoName) == 0)
997                     foundProto = false;
998         }
999 
1000     if (!foundProto) {
1001         // write EXTERNPROTO
1002         const NodeList *nodes = getNodes();
1003         for (long i = 0; i < nodes->size(); i++) {
1004             Node *node = nodes->get(i);
1005             if (node->isInScene(this)) {
1006                 const char *nodeName = node->getProto()->getName(isX3d());
1007                 if (strcmp(nodeName, protoName)==0) {
1008                     RET_ONERROR( node->writeProto(f) )
1009                     RET_ONERROR( mywritestr(f ,"\n\n") )
1010                     TheApp->incSelectionLinenumber(2);
1011                     break;
1012                 }
1013             }
1014         }
1015     }
1016     return 0;
1017 }
1018 
1019 
avoidProtoOnPureVrml(MyString name)1020 static bool avoidProtoOnPureVrml(MyString name)
1021 {
1022     if (strcmp(name, "SuperEllipsoid") == 0)
1023         return true;
1024     if (strcmp(name, "SuperExtrusion") == 0)
1025         return true;
1026     if (strcmp(name, "SuperRevolver") == 0)
1027         return true;
1028     if (strcmp(name, "SuperShape") == 0)
1029         return true;
1030     if (strcmp(name, "CurveAnimation") == 0)
1031         return true;
1032     if (strcmp(name, "NurbsCurve") == 0)
1033         return true;
1034     if (strcmp(name, "NurbsCurve2D") == 0)
1035         return true;
1036     if (strcmp(name, "NurbsGroup") == 0)
1037         return true;
1038     if (strcmp(name, "NurbsOrientationInterpolator") == 0)
1039         return true;
1040     if (strcmp(name, "NurbsPositionInterpolator") == 0)
1041         return true;
1042     if (strcmp(name, "NurbsSet") == 0)
1043         return true;
1044     if (strcmp(name, "NurbsSurface") == 0)
1045         return true;
1046     if (strcmp(name, "NurbsSurfaceInterpolator") == 0)
1047         return true;
1048     if (strcmp(name, "NurbsSweptSurface") == 0)
1049         return true;
1050     if (strcmp(name, "NurbsSwungSurface") == 0)
1051         return true;
1052     if (strcmp(name, "NurbsTextureCoordinate") == 0)
1053         return true;
1054     if (strcmp(name, "NurbsTextureSurface") == 0)
1055         return true;
1056     if (strcmp(name, "NurbsTrimmedSurface") == 0)
1057         return true;
1058     if (strcmp(name, "Contour2D") == 0)
1059         return true;
1060     if (strcmp(name, "CoordinateDeformer") == 0)
1061         return true;
1062     if (strcmp(name, "Polyline2D") == 0)
1063         return true;
1064     if (strcmp(name, "TrimmedSurface") == 0)
1065         return true;
1066     if (strcmp(name, "KambiAppearance") == 0)
1067         return true;
1068     if (strcmp(name, "KambiHeadLight") == 0)
1069         return true;
1070     if (strcmp(name, "KambiInline") == 0)
1071         return true;
1072     if (strcmp(name, "KambiNavigationInfo") == 0)
1073         return true;
1074     if (strcmp(name, "KambiOctreeProperties") == 0)
1075         return true;
1076     if (strcmp(name, "KambiTriangulation") == 0)
1077         return true;
1078     if (strcmp(name, "Text3D") == 0)
1079         return true;
1080 
1081     return false;
1082 }
1083 
avoidProtoOnX3dom(MyString name)1084 static bool avoidProtoOnX3dom(MyString name)
1085 {
1086     return avoidProtoOnPureVrml(name);
1087 }
1088 
avoidProtoOnX3d(MyString name)1089 static bool avoidProtoOnX3d(MyString name)
1090 {
1091     if (strcmp(name, "NurbsCurve") == 0)
1092         return true;
1093     if (strcmp(name, "NurbsCurve2D") == 0)
1094         return true;
1095     if (strcmp(name, "NurbsGroup") == 0)
1096         return true;
1097     if (strcmp(name, "NurbsOrientationInterpolator") == 0)
1098         return true;
1099     if (strcmp(name, "NurbsPositionInterpolator") == 0)
1100         return true;
1101     if (strcmp(name, "NurbsSet") == 0)
1102         return true;
1103     if (strcmp(name, "NurbsSurface") == 0)
1104         return true;
1105     if (strcmp(name, "NurbsSurfaceInterpolator") == 0)
1106         return true;
1107     if (strcmp(name, "NurbsTextureSurface") == 0)
1108         return true;
1109     if (strcmp(name, "NurbsSweptSurface") == 0)
1110         return true;
1111     if (strcmp(name, "NurbsSwungSurface") == 0)
1112         return true;
1113     if (strcmp(name, "MultiTexture") == 0)
1114         return true;
1115     if (strcmp(name, "MultiTextureCoordinate") == 0)
1116         return true;
1117     if (strcmp(name, "MultiTextureTransform") == 0)
1118         return true;
1119     if (strcmp(name, "Contour2D") == 0)
1120         return true;
1121     if (strcmp(name, "LoadSensor") == 0)
1122         return true;
1123     if (strcmp(name, "Arc2D") == 0)
1124         return true;
1125     if (strcmp(name, "ArcClose2D") == 0)
1126         return true;
1127     if (strcmp(name, "BooleanFilter") == 0)
1128         return true;
1129     if (strcmp(name, "BooleanToggle") == 0)
1130         return true;
1131     if (strcmp(name, "BooleanTrigger") == 0)
1132         return true;
1133     if (strcmp(name, "Circle2D") == 0)
1134         return true;
1135     if (strcmp(name, "ColorRGBA") == 0)
1136         return true;
1137     if (strcmp(name, "ContourPolyline2D") == 0)
1138         return true;
1139     if (strcmp(name, "CoordinateInterpolator2D") == 0)
1140         return true;
1141     if (strcmp(name, "Disk2D") == 0)
1142         return true;
1143     if (strcmp(name, "FillProperties") == 0)
1144         return true;
1145     if (strcmp(name, "IntegerSequencer") == 0)
1146         return true;
1147     if (strcmp(name, "IntegerTrigger") == 0)
1148         return true;
1149     if (strcmp(name, "KeySensor") == 0)
1150         return true;
1151     if (strcmp(name, "LineProperties") == 0)
1152         return true;
1153     if (strcmp(name, "Polypoint2D") == 0)
1154         return true;
1155     if (strcmp(name, "Polyline2D") == 0)
1156         return true;
1157     if (strcmp(name, "PositionInterpolator2D") == 0)
1158         return true;
1159     if (strcmp(name, "Rectangle2D") == 0)
1160         return true;
1161     if (strcmp(name, "StringSensor") == 0)
1162         return true;
1163     if (strcmp(name, "TimeTrigger") == 0)
1164         return true;
1165     if (strcmp(name, "TriangleSet2D") == 0)
1166         return true;
1167     if (strcmp(name, "InlineLoadControl") == 0)
1168         return true;
1169     return false;
1170 }
1171 
avoidComponentOnPureX3dv(MyString name)1172 static bool avoidComponentOnPureX3dv(MyString name)
1173 {
1174     if (strcmp(name, "NURBS") == 0)
1175         return true;
1176     return false;
1177 }
1178 
getComponents(Node * node,void * data)1179 static bool getComponents(Node *node, void *data)
1180 {
1181     StringMap *components = (StringMap *) data;
1182     if (node->isPROTO())
1183         ((NodePROTO *)node)->getComponentsInBranch(getComponents, data);
1184     else {
1185         int level = node->getComponentLevel();
1186         if (level != -1) {
1187             const char* name = node->getComponentName();
1188             StringMap::Chain::Iterator *j;
1189             bool hasAlreadyName = false;
1190             for (int i = 0; i < components->width(); i++)
1191                 for (j = components->chain(i).first(); j != NULL; j = j->next())
1192                     if (strcmp(name, j->item()->getKey()) == 0)
1193                         hasAlreadyName = true;
1194             bool x3d = node->getScene()->isX3d();
1195             if (node->getScene()->isPureX3dv() &&
1196                 avoidComponentOnPureX3dv(node->getProto()->getName(x3d)))
1197                 return true;
1198             if (!hasAlreadyName)
1199                 (*components)[name] = level;
1200             else if (level > (*components)[name])
1201                 (*components)[name] = level;
1202         }
1203     }
1204     return true;
1205 }
1206 
1207 int
writeComponents(int f)1208 Scene::writeComponents(int f)
1209 {
1210     StringMap components;
1211     m_root->doWithBranch(getComponents, &components);
1212 
1213     if (components.width() == 0)
1214         return 0;
1215 
1216     StringMap::Chain::Iterator *j;
1217     for (int i = 0; i < components.width(); i++)
1218         for (j = components.chain(i).first(); j != NULL; j = j->next())
1219             if (j->item()->getData() != -1) {
1220                 if (isX3dv())
1221                     RET_ONERROR( mywritestr(f, "COMPONENT ") )
1222                 else if (isX3dXml()) {
1223                     RET_ONERROR( indentf(f, TheApp->GetIndent()) )
1224                     RET_ONERROR( mywritestr(f, "<component name='") )
1225                 }
1226                 RET_ONERROR( mywritestr(f, (const char *) j->item()->getKey()) )
1227                 if (isX3dv())
1228                     RET_ONERROR( mywritestr(f, ":") )
1229                 else if (isX3dXml())
1230                     RET_ONERROR( mywritestr(f, "' level='") )
1231                 RET_ONERROR( mywritef(f, "%d", j->item()->getData()) )
1232                 if (isX3dXml())
1233                     RET_ONERROR( mywritestr(f, "'/>") )
1234                 RET_ONERROR( mywritestr(f, "\n") )
1235                 TheApp->incSelectionLinenumber();
1236             }
1237 
1238     return 0;
1239 }
1240 
1241 #define RET_RESET_FLAGS_ONERROR(x) RET_AND_RESET_ONERROR(x, \
1242 {    \
1243     TheApp->disableEFloatWriteFormat(m_writeFlags); \
1244     if (m_writeFlags & TEMP_EXPORT) \
1245         m_writeFlags = oldWriteFlags; \
1246 })
1247 
1248 
getVariableNames(Node * node,void * data)1249 static bool getVariableNames(Node *node, void *data)
1250 {
1251     if (node != NULL) {
1252         node->getVariableName();
1253         if (node->isPROTO()) {
1254             NodePROTO *protoNode = (NodePROTO *)node;
1255             for (int i = 0; i < protoNode->getNumProtoNodes(); i++)
1256                 protoNode->getProtoNode(i)->doWithBranch(getVariableNames,
1257                                                          data);
1258             }
1259     }
1260     return true;
1261 }
1262 
generateConvertedNodes(Node * node,void * data)1263 static bool generateConvertedNodes(Node *node, void *data)
1264 {
1265     int *writeFlags = (int *)data;
1266     if (node != NULL) {
1267         node->addToConvertedNodes(*writeFlags);
1268     }
1269     return true;
1270 }
1271 
convertBackAndDeleteConvertedNodes(Node * node,void * data)1272 static bool convertBackAndDeleteConvertedNodes(Node *node, void *data)
1273 {
1274     Scene *scene = (Scene *)data;
1275     node->deleteConvertedNodes();
1276     if ((node->getType() != VRML_NURBS_GROUP) && !scene->isX3d())
1277         node->convert2Vrml();
1278     return true;
1279 }
1280 
markUsedProto(Node * node,void * data)1281 static bool markUsedProto(Node *node, void *data)
1282 {
1283     Scene *scene = (Scene *)data;
1284     if (node == NULL)
1285         return true;
1286     Proto *proto = scene->getProto(node->getProto()->getName(false));
1287     if (proto == NULL)
1288         return true;
1289     proto->setInUse(true);
1290     proto->setIsInScene(true);
1291     if ((node->getType() == VRML_INLINE) ||
1292         (node->getType() == VRML_INLINE_LOAD_CONTROL)) {
1293         NodeList *nodelist = node->getLoadedNodes();
1294         if (nodelist != NULL)
1295             for (long i = 0; i < nodelist->size(); i++)
1296                 nodelist->get(i)->doWithBranch(markUsedProto, data);
1297     }
1298 
1299     return true;
1300 }
1301 
1302 static NodeVrmlCut *vrmlCut = NULL;
1303 
searchVrmlCut(Node * node,void * data)1304 static bool searchVrmlCut(Node *node, void *data)
1305 {
1306     if (node == NULL)
1307         return true;
1308     if (node->getType() == DUNE_VRML_CUT)
1309         vrmlCut = (NodeVrmlCut *)node;
1310 
1311     return true;
1312 }
1313 
1314 static NodeVrmlScene *vrmlScene = NULL;
1315 
searchVrmlScene(Node * node,void * data)1316 static bool searchVrmlScene(Node *node, void *data)
1317 {
1318     if (node == NULL)
1319         return true;
1320     if (node->getType() == DUNE_VRML_SCENE) {
1321         vrmlScene = (NodeVrmlScene *)node;;
1322         return false;
1323     }
1324     return true;
1325 }
1326 
write(int f,const char * url,int writeFlags,char * wrlFile)1327 int Scene::write(int f, const char *url, int writeFlags, char *wrlFile)
1328 {
1329     if (!(writeFlags & SKIP_SAVED_TEST)) {
1330         if (writeFlags & X3DV)
1331             if (m_saved_x3dv == true)
1332                 return 0;
1333         if (writeFlags & X3D_XML)
1334             if (m_saved_x3dxml == true)
1335                 return 0;
1336     }
1337 
1338     if (getStoreAsHtml())
1339         writeFlags |= (X3DOM | X3D_XML);
1340 
1341     TheApp->setWriteUrl(url);
1342     ProtoMap::Chain::Iterator *j;
1343     for (int i = 0; i < m_protos.width(); i++)
1344         for (j = m_protos.chain(i).first(); j != NULL; j = j->next())
1345             if (j->item()->getData() != NULL)
1346                 j->item()->getData()->setInUse(false);
1347     m_root->doWithBranch(markUsedProto, this);
1348 
1349     int oldWriteFlags = m_writeFlags;
1350     m_writeFlags = writeFlags;
1351     bool done = false;
1352     int ret = 0;
1353     bool x3dv = ::isX3dv(writeFlags);
1354 //    if (writeFlags & (TRIANGULATE | (C_SOURCE | CC_SOURCE | JAVA_SOURCE))) {
1355     if (writeFlags & (TRIANGULATE | (C_SOURCE | CC_SOURCE))) {
1356         m_root->doWithBranch(generateConvertedNodes, &writeFlags);
1357     }
1358     if (writeFlags & (C_SOURCE | CC_SOURCE | JAVA_SOURCE))
1359         if (isX3d())
1360             x3dv = true;
1361     writeFlags = writeFlags & (~(TRIANGULATE));
1362     bool oldXml = isX3dXml();
1363     if (x3dv)
1364         setX3dv();
1365     else if (::isX3dXml(writeFlags))
1366         setX3dXml();
1367     else
1368         setVrml();
1369 /*
1370     if (writeFlags & (C_SOURCE | CC_SOURCE | JAVA_SOURCE)) {
1371         m_root->doWithBranch(getVariableNames, &writeFlags);
1372     }
1373 */
1374     if (writeFlags & OFF) {
1375         ret = writeOff(f);
1376         done = true;
1377     } else if (writeFlags & AC3D) {
1378         ret = writeAc3d(f, writeFlags & AC3D_4_RAVEN);
1379         done = true;
1380     } else if (writeFlags & RIB) {
1381         ret = writeRib(f, url);
1382         done = true;
1383     } else if (writeFlags & POVRAY) {
1384         ret = writePovray(f, url);
1385         done = true;
1386     } else if (writeFlags & KANIM) {
1387         ret = writeKanim(f, url);
1388         done = true;
1389     } else if (writeFlags & LDRAW_DAT) {
1390         ret = writeLdrawDat(f, url);
1391         done = true;
1392     } else if (writeFlags & C_SOURCE) {
1393         ret = writeC(f, writeFlags);
1394         done = true;
1395     } else if (writeFlags & CC_SOURCE) {
1396         ret = writeC(f, writeFlags);
1397         done = true;
1398     } else if (writeFlags & JAVA_SOURCE) {
1399         ret = writeC(f, writeFlags);
1400         done = true;
1401     }
1402     if (done) {
1403         m_writeFlags = oldWriteFlags;
1404         m_root->doWithBranch(convertBackAndDeleteConvertedNodes, this);
1405         return ret;
1406     }
1407     TheApp->disableEFloatWriteFormat(writeFlags);
1408     m_newURL = url;
1409 
1410     bool convertFromXml = false;
1411     if (oldXml && !::isX3dXml(writeFlags))
1412         convertFromXml=true;
1413     bool convertToXml = false;
1414     if (!oldXml && ::isX3dXml(writeFlags))
1415         convertToXml=true;
1416     m_writeFlags = writeFlags;
1417     if (convertToXml)
1418         m_writeFlags |= CONVERT_TO_XML;
1419     if (convertFromXml)
1420         m_writeFlags |= CONVERT_FROM_XML;
1421 
1422     getNodes()->clearFlag(NODE_FLAG_DEFED);
1423     getNodes()->clearFlag(NODE_FLAG_TOUCHED);
1424 
1425     // remove multiple identical ProtoDefinitions smuggled in by Inline nodes
1426     for (int i = 0;i < m_numProtoDefinitions;i++) {
1427         for (int j = 0;j < m_numProtoDefinitions;j++)
1428            if (i != j)
1429                if (strcmp((const char*)m_protoDefinitions[i],
1430                          (const char*)m_protoDefinitions[j]) == 0)
1431                    m_protoDefinitions[j] = "";
1432     }
1433 
1434     int indent = 0;
1435     if (writeFlags & X3DOM) {
1436         RET_RESET_FLAGS_ONERROR( mywritestr(f,"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n") )
1437         RET_RESET_FLAGS_ONERROR( mywritestr(f,"  \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n") )
1438         RET_RESET_FLAGS_ONERROR( mywritestr(f,"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n") )
1439         RET_RESET_FLAGS_ONERROR( mywritestr(f,"  <head>\n") )
1440         RET_RESET_FLAGS_ONERROR( mywritestr(f,"    <title></title>\n") )
1441         RET_RESET_FLAGS_ONERROR( mywritef(f,
1442                                           "    <link rel=\"stylesheet\" type=\"text/css\" href=\"%sx3dom.css\" />\n",
1443                                           TheApp->GetX3domPath()) )
1444         RET_RESET_FLAGS_ONERROR( mywritef(f,
1445                                           "    <script type=\"text/javascript\" src=\"%sx3dom-full.js\"></script>\n",
1446                                           TheApp->GetX3domPath()) )
1447         RET_RESET_FLAGS_ONERROR( writeHead(f, writeFlags) )
1448         RET_RESET_FLAGS_ONERROR( mywritestr(f,"  </head>\n") )
1449         RET_RESET_FLAGS_ONERROR( mywritestr(f,"  <body>\n") )
1450         vrmlCut = NULL;
1451         getRoot()->doWithBranch(searchVrmlCut, NULL, false);
1452         if (vrmlCut)
1453             RET_ONERROR( vrmlCut->writeX3domScript(f, 4) )
1454         for (int i = 0; i < m_htmlFirstPart.size(); i++)
1455             if (m_htmlFirstPart[i]) {
1456                 RET_RESET_FLAGS_ONERROR( mywritef(f,"%s",
1457                                                   (const char *)m_htmlBegin[i])
1458                                        )
1459                 RET_RESET_FLAGS_ONERROR( mywritef(f,"%s",
1460                                                   (const char *)m_htmlData[i]) )
1461                 RET_RESET_FLAGS_ONERROR( mywritef(f,"%s\n",
1462                                                   (const char *)m_htmlEnd[i]) )
1463             }
1464         RET_RESET_FLAGS_ONERROR( mywritef(f,"    <x3d %s>\n",
1465                                               TheApp->GetX3domParameter()) )
1466         RET_RESET_FLAGS_ONERROR( mywritestr(f ,"      <Scene>\n") )
1467         indent = 2 * TheApp->GetIndent();
1468     } else if (writeFlags & XITE) {
1469         RET_RESET_FLAGS_ONERROR( mywritestr(f,"<!DOCTYPE html>\n") )
1470         RET_RESET_FLAGS_ONERROR( mywritestr(f,"<html>\n") )
1471         RET_RESET_FLAGS_ONERROR( mywritestr(f,"  <head>\n") )
1472         RET_RESET_FLAGS_ONERROR( mywritestr(f,"    <title></title>\n") )
1473         RET_RESET_FLAGS_ONERROR( mywritef(f,
1474                                           "    <link rel=\"stylesheet\" type=\"text/css\" href=\"%sx_ite.css\" />\n",
1475                                           TheApp->GetXitePath()) )
1476         RET_RESET_FLAGS_ONERROR( mywritef(f,
1477                                           "    <script type=\"text/javascript\" src=\"%sx_ite.min.js\"></script>\n",
1478                                           TheApp->GetXitePath()) )
1479         RET_RESET_FLAGS_ONERROR( mywritestr(f,"  <style>\n") )
1480         RET_RESET_FLAGS_ONERROR( mywritestr(f,"X3DCanvas {\n") )
1481         RET_RESET_FLAGS_ONERROR( mywritestr(f,"  width: 100%;\n") )
1482         RET_RESET_FLAGS_ONERROR( mywritestr(f,"  height: 432px;\n") )
1483         RET_RESET_FLAGS_ONERROR( mywritestr(f,"}\n") )
1484         RET_RESET_FLAGS_ONERROR( mywritestr(f,"  </style>\n") )
1485         RET_RESET_FLAGS_ONERROR( mywritestr(f,"  \n") )
1486         RET_RESET_FLAGS_ONERROR( mywritestr(f,"  </head>\n") )
1487         RET_RESET_FLAGS_ONERROR( mywritestr(f,"  <body>\n") )
1488         RET_RESET_FLAGS_ONERROR( mywritestr(f,"  <p margin: 1px 0;>") )
1489         RET_RESET_FLAGS_ONERROR( mywritef(f,"<X3DCanvas url='\"%s\"'/></p>\n",
1490                                           wrlFile ? wrlFile : url) )
1491         RET_RESET_FLAGS_ONERROR( mywritestr(f,"  </body>\n") )
1492         RET_RESET_FLAGS_ONERROR( mywritestr(f ,"</html>\n") )
1493         return 0;
1494     } else if (::isX3d(writeFlags)) {
1495         if (::isX3dXml(writeFlags)) {
1496             RET_RESET_FLAGS_ONERROR( mywritestr(f,
1497                   "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") )
1498             TheApp->incSelectionLinenumber();
1499             RET_RESET_FLAGS_ONERROR( mywritestr(f,"<!DOCTYPE X3D PUBLIC ") )
1500             RET_RESET_FLAGS_ONERROR( mywritestr(f,"\"ISO//Web3D//DTD ") )
1501             RET_RESET_FLAGS_ONERROR( mywritef(f,"X3D 3.%d//EN\" ",
1502                                               getX3dVersion() ) )
1503             RET_RESET_FLAGS_ONERROR( mywritef(f,
1504                   "\"http://www.web3d.org/specifications/x3d-3.%d.dtd\">\n",
1505                   getX3dVersion()) )
1506             TheApp->incSelectionLinenumber();
1507             RET_RESET_FLAGS_ONERROR( mywritestr(f ,"<X3D profile='") )
1508         } else {
1509             RET_RESET_FLAGS_ONERROR( mywritef(f ,"#X3D V3.%d utf8\n",
1510                                               getX3dVersion()) )
1511             TheApp->incSelectionLinenumber();
1512             RET_RESET_FLAGS_ONERROR( mywritestr(f ,"PROFILE ") )
1513         }
1514         int profile = PROFILE_CORE;
1515         getRoot()->doWithBranch(getProfileCallback, &profile);
1516         switch (profile) {
1517           case PROFILE_CORE:
1518             RET_RESET_FLAGS_ONERROR( mywritestr(f ,"Core") )
1519             break;
1520           case PROFILE_INTERCHANGE:
1521             RET_RESET_FLAGS_ONERROR( mywritestr(f ,"Interchange") )
1522             break;
1523           case PROFILE_INTERACTIVE:
1524             RET_RESET_FLAGS_ONERROR( mywritestr(f ,"Interactive") )
1525             break;
1526           case PROFILE_MPEG4_INTERACTIVE:
1527             RET_RESET_FLAGS_ONERROR( mywritestr(f ,"MPEG-4 interactive") )
1528             break;
1529           case PROFILE_IMMERSIVE:
1530             RET_RESET_FLAGS_ONERROR( mywritestr(f ,"Immersive") )
1531             break;
1532           default:  //  PROFILE_FULL
1533             RET_RESET_FLAGS_ONERROR( mywritestr(f ,"Full") )
1534             break;
1535         }
1536         if (::isX3dXml(writeFlags)) {
1537             RET_RESET_FLAGS_ONERROR( mywritef(f ,"' Version='3.%d>",
1538                                               getX3dVersion()) )
1539             RET_RESET_FLAGS_ONERROR( mywritestr(f ,"'>") )
1540         }
1541         RET_RESET_FLAGS_ONERROR( mywritestr(f ,"\n") )
1542         TheApp->incSelectionLinenumber();
1543 
1544         if (::isX3dXml(writeFlags)) {
1545             RET_ONERROR( mywritestr(f, "<head>\n") )
1546             TheApp->incSelectionLinenumber();
1547         }
1548         RET_RESET_FLAGS_ONERROR( writeComponents(f) )
1549         TheApp->incSelectionLinenumber();
1550         RET_RESET_FLAGS_ONERROR( mywritestr(f ,"\n") )
1551         TheApp->incSelectionLinenumber();
1552 
1553         RET_RESET_FLAGS_ONERROR( writeHead(f, writeFlags) )
1554 
1555         if (::isX3dXml(writeFlags)) {
1556             RET_ONERROR( mywritestr(f, "</head>\n") )
1557             TheApp->incSelectionLinenumber();
1558         }
1559     } else {
1560         RET_RESET_FLAGS_ONERROR( mywritestr(f ,"#VRML V2.0 utf8\n\n") )
1561         TheApp->incSelectionLinenumber(2);
1562     }
1563     if (isX3dXml()) {
1564     }
1565     if (::isX3dXml(m_writeFlags) && !(writeFlags & X3DOM)) {
1566         RET_RESET_FLAGS_ONERROR( mywritestr(f ,"<Scene>\n") )
1567         TheApp->incSelectionLinenumber();
1568     }
1569     if (writeFlags & (PURE_VRML97 | PURE_X3DV | X3DOM)) {
1570         if (TheApp->getCoverMode())
1571             writeExtensionProtos(f, FF_COVER_ONLY);
1572         if (TheApp->getKambiMode())
1573             writeExtensionProtos(f, FF_KAMBI_ONLY);
1574     }
1575     for (int i = 0;i < m_numProtoNames;i++) {
1576         MyString protoName = m_protoNames[i];
1577         if ((isPureVRML() && avoidProtoOnPureVrml(protoName)) ||
1578             (isX3d() && avoidProtoOnX3d(protoName)) ||
1579             ((writeFlags & X3DOM) && avoidProtoOnX3dom(protoName))) {
1580             if (belongsToNodeWithExternProto(protoName))
1581                 continue;
1582         }
1583         bool writeProto = true;
1584         // avoid writing of Protos, which are forced written via ExternProto
1585         for (long j = 0; j < m_nodesForceExternProtoWrite.size(); j++)
1586             if (strcmp(m_nodesForceExternProtoWrite[j], protoName) == 0)
1587                 writeProto = false;
1588         if (!writeProto)
1589             continue;
1590 
1591         if (TheApp->getPrefix() != NULL) {
1592             MyString prefix = TheApp->getPrefix();
1593             bool isPrefixProto = false;
1594             for (int j = 0; j < m_numProtoNames; j++) {
1595                 if (strncmp(m_protoNames[j], prefix, prefix.length()) == 0)
1596                     if (strcmp(m_protoNames[j], protoName) == 0)
1597                         isPrefixProto = true;
1598             }
1599             if (!isPrefixProto) {
1600                 for (int j = 0; j < m_numProtoNames; j++) {
1601                     if (strncmp(m_protoNames[j], prefix, prefix.length()) == 0)
1602                         m_protoDefinitions[i].gsubOnce(
1603                               m_protoNames[j] + prefix.length(),
1604                               m_protoNames[j]);
1605                 }
1606             }
1607         }
1608         // avoid PROTOs from Proto Library, which are not used
1609         if (m_protos[protoName] != NULL)
1610             if (m_protos[protoName]->fromProtoLibrary() &&
1611                 !m_protos[protoName]->isInUse())
1612                 continue;
1613         if (m_isNestedProto[i]) {
1614             if (isX3dXml()) {
1615                 static char format[256];
1616                 swLoadString(IDS_X3D_NESTED_PROTO_NOT_SUPPORTED, format, 255);
1617                 errorf(format, (const char *)protoName);
1618             }
1619             RET_RESET_FLAGS_ONERROR( m_protos[protoName]->write(f, 0,
1620                                                                 writeFlags) )
1621             // count end of line characters in protodefinitions
1622             const char* string = m_protoDefinitions[i];
1623             while ((string = strchr(string, '\n')) !=NULL) {
1624                 TheApp->incSelectionLinenumber();
1625                 string++;
1626             }
1627             RET_RESET_FLAGS_ONERROR( mywritestr(f ,"\n\n") )
1628             TheApp->incSelectionLinenumber(2);
1629         } else if (strlen(m_protoNames[i]) > 0)  {
1630             RET_RESET_FLAGS_ONERROR( m_protos[protoName]->write(f, indent,
1631                                                                 m_writeFlags) )
1632         }
1633     }
1634 
1635     for (long k = 0; k < m_nodesWithExternProto.size(); k++) {
1636         // do not write EXTERN PROTOs for some (e.g. Nurbs Nodes) when using
1637         // pureVRML97 cause this nodes are written converted to pure VRML97
1638         bool doWriteExternProto = true;
1639         if (isPureVRML() && avoidProtoOnPureVrml(m_nodesWithExternProto[k]))
1640             doWriteExternProto = false;
1641         if (isX3d() && avoidProtoOnX3d(m_nodesWithExternProto[k]))
1642             doWriteExternProto = false;
1643         if (doWriteExternProto)
1644             RET_RESET_FLAGS_ONERROR(
1645                 writeExternProto(f, m_nodesWithExternProto[k])
1646             )
1647     }
1648 
1649     vrmlScene = NULL;
1650     getRoot()->doWithBranch(searchVrmlScene, NULL, false);
1651     if (vrmlScene)
1652         vrmlScene->writeProto(f);
1653 
1654     getNodes()->clearFlag(NODE_FLAG_TOUCHED);
1655 
1656     if (!TheApp->getX3dv() && ::isX3d(m_writeFlags)) {
1657         NodeList *childList = ((NodeGroup *)getRoot())->children()->getValues();
1658         if (childList)
1659             for (long i = 0; i < childList->size(); i++)
1660                 childList->get(i)->convert2X3d();
1661     }
1662 
1663     NodeList *childList = ((NodeGroup *)getRoot())->children()->getValues();
1664     if (childList)
1665         for (long i = 0; i < childList->size(); i++) {
1666             if (::isX3dXml(m_writeFlags)) {
1667                 int rootIndent = indent + TheApp->GetIndent();
1668                 RET_RESET_FLAGS_ONERROR( childList->get(i)->
1669                                              writeXml(f, rootIndent))
1670             } else
1671                  RET_RESET_FLAGS_ONERROR( childList->get(i)->write(f, 0) )
1672         }
1673 
1674     if ((!isTempSave()) && (!isPureVRML())) {
1675         m_unmodified = m_undoStack.empty() ? (Command *) NULL : m_undoStack.peek();
1676         m_extraModifiedFlag = false;
1677         MyString newURL = "";
1678         newURL += url;
1679         TheApp->setImportURL(newURL);
1680         m_URL = newURL;
1681     }
1682 
1683     RET_RESET_FLAGS_ONERROR( writeRouteStrings(f, indent + TheApp->GetIndent(),
1684                                                true) )
1685 
1686     if (::isX3dXml(m_writeFlags)) {
1687         RET_RESET_FLAGS_ONERROR( indentf(f, indent) )
1688         RET_RESET_FLAGS_ONERROR( mywritestr(f ,"</Scene>\n") )
1689         TheApp->incSelectionLinenumber();
1690         RET_RESET_FLAGS_ONERROR( indentf(f, indent) )
1691         if (writeFlags & X3DOM)
1692             RET_RESET_FLAGS_ONERROR( mywritestr(f ,"</x3d>\n") )
1693         else
1694             RET_RESET_FLAGS_ONERROR( mywritestr(f ,"</X3D>\n") )
1695         TheApp->incSelectionLinenumber();
1696     }
1697     if (writeFlags & X3DOM) {
1698         RET_RESET_FLAGS_ONERROR( indentf(f, indent > 0 ? 2 : 0) )
1699         TheApp->incSelectionLinenumber();
1700         for (int i = 0; i < m_htmlFirstPart.size(); i++)
1701             if (!(m_htmlFirstPart[i])) {
1702                 RET_RESET_FLAGS_ONERROR( mywritef(f,"%s",
1703                                                   (const char *)m_htmlBegin[i])
1704                                         )
1705                 RET_RESET_FLAGS_ONERROR( mywritef(f,"%s",
1706                                                   (const char *)m_htmlData[i]) )
1707                 RET_RESET_FLAGS_ONERROR( mywritef(f,"%s\n",
1708                                                   (const char *)m_htmlEnd[i]) )
1709                 TheApp->incSelectionLinenumber();
1710             }
1711         RET_RESET_FLAGS_ONERROR( mywritestr(f ,"</body>\n") )
1712         TheApp->incSelectionLinenumber();
1713         RET_RESET_FLAGS_ONERROR( mywritestr(f ,"</html>\n") )
1714         TheApp->incSelectionLinenumber();
1715     }
1716 
1717     if (writeFlags & (PURE_VRML97 | PURE_X3DV | X3DOM))
1718         if (TheApp->getCoverMode())
1719             deleteExtensionProtos();
1720     TheApp->enableEFloatWriteFormat(writeFlags);
1721     if ((oldWriteFlags & (TEMP_EXPORT | TEMP_SAVE)) ||
1722         (writeFlags & (TEMP_EXPORT | TEMP_SAVE))) {
1723         resetWriteFlags(oldWriteFlags);
1724     }
1725 
1726     if (writeFlags & X3DV)
1727         m_saved_x3dv = true;
1728     else if (writeFlags & X3D_XML)
1729         m_saved_x3dxml = true;
1730 
1731     return 0;
1732 }
1733 
writeHead(int f,int writeFlags)1734 int Scene::writeHead(int f, int writeFlags)
1735 {
1736     int oldWriteFlags = m_writeFlags;
1737     long maxMetas = m_metaKeys.size();
1738     if (m_metaValues.size() < maxMetas)
1739         maxMetas = m_metaValues.size();
1740     if (::isX3dXml(writeFlags))
1741         for (long i = 0; i < maxMetas; i++) {
1742             RET_RESET_FLAGS_ONERROR( indentf(f, TheApp->GetIndent()) )
1743             RET_RESET_FLAGS_ONERROR( mywritestr(f , "<meta name='") )
1744             RET_RESET_FLAGS_ONERROR( mywritestr(f , m_metaKeys[i]) )
1745             RET_RESET_FLAGS_ONERROR( mywritestr(f , "' content='") )
1746             RET_RESET_FLAGS_ONERROR( mywritestr(f , m_metaValues[i]) )
1747             RET_RESET_FLAGS_ONERROR( mywritestr(f , "' />\n") )
1748             TheApp->incSelectionLinenumber();
1749         }
1750     else
1751         for (long i = 0; i < maxMetas; i++) {
1752             RET_RESET_FLAGS_ONERROR( mywritestr(f , "META \"") )
1753             RET_RESET_FLAGS_ONERROR( mywritestr(f , m_metaKeys[i]) )
1754             RET_RESET_FLAGS_ONERROR( mywritestr(f , "\" \"") )
1755             RET_RESET_FLAGS_ONERROR( mywritestr(f , m_metaValues[i]) )
1756             RET_RESET_FLAGS_ONERROR( mywritestr(f , "\"\n") )
1757             TheApp->incSelectionLinenumber();
1758         }
1759     if (maxMetas > 0) {
1760         RET_RESET_FLAGS_ONERROR( mywritestr(f , "\n") )
1761         TheApp->incSelectionLinenumber(2);
1762     }
1763     long maxUnits = m_unitCategory.size();
1764     if (m_unitName.size() < maxUnits)
1765         maxUnits = m_unitName.size();
1766     if (m_unitConversionFactor.size() < maxUnits)
1767         maxUnits = m_unitConversionFactor.size();
1768     if (::isX3dXml(writeFlags))
1769         for (long i = 0; i < maxUnits; i++) {
1770             RET_RESET_FLAGS_ONERROR( indentf(f, TheApp->GetIndent()) )
1771             RET_RESET_FLAGS_ONERROR( mywritestr(f , "<unit category='") )
1772             RET_RESET_FLAGS_ONERROR( mywritestr(f , m_unitCategory[i]) )
1773             RET_RESET_FLAGS_ONERROR( mywritestr(f , "' name='") )
1774             RET_RESET_FLAGS_ONERROR( mywritestr(f , m_unitName[i]) )
1775             RET_RESET_FLAGS_ONERROR( mywritestr(f , "' conversionFactor='") )
1776             if (strcmp(m_unitCategory[i], "length") == 0)
1777                 RET_RESET_FLAGS_ONERROR( mywritef(f , "%f", m_unitLength) )
1778             else if (strcmp(m_unitCategory[i], "angle") == 0)
1779                 RET_RESET_FLAGS_ONERROR( mywritef(f , "%f", m_unitAngle) )
1780             else
1781                 RET_RESET_FLAGS_ONERROR( mywritef(f , "%f",
1782                                                   m_unitConversionFactor[i]) )
1783             RET_RESET_FLAGS_ONERROR( mywritestr(f , "' />\n") )
1784             TheApp->incSelectionLinenumber();
1785         }
1786     else
1787         for (long i = 0; i < maxUnits; i++) {
1788             RET_RESET_FLAGS_ONERROR( mywritestr(f , "UNIT ") )
1789             RET_RESET_FLAGS_ONERROR( mywritestr(f , m_unitCategory[i]) )
1790             RET_RESET_FLAGS_ONERROR( mywritestr(f , " ") )
1791             RET_RESET_FLAGS_ONERROR( mywritestr(f , m_unitName[i]) )
1792             RET_RESET_FLAGS_ONERROR( mywritestr(f , " ") )
1793             if (strcmp(m_unitCategory[i], "length") == 0)
1794                 RET_RESET_FLAGS_ONERROR( mywritef(f , "%f", m_unitLength) )
1795             else if (strcmp(m_unitCategory[i], "angle") == 0)
1796                 RET_RESET_FLAGS_ONERROR( mywritef(f , "%f", m_unitAngle) )
1797             else
1798                 RET_RESET_FLAGS_ONERROR( mywritef(f , "%f",
1799                                                   m_unitConversionFactor[i]) )
1800             RET_RESET_FLAGS_ONERROR( mywritestr(f , "\n") )
1801             TheApp->incSelectionLinenumber();
1802         }
1803     if (maxUnits > 0) {
1804         RET_RESET_FLAGS_ONERROR( mywritestr(f , "\n") )
1805         TheApp->incSelectionLinenumber(2);
1806     }
1807     return 0;
1808 }
1809 
1810 bool
belongsToNodeWithExternProto(const char * protoName)1811 Scene::belongsToNodeWithExternProto(const char *protoName)
1812 {
1813     bool found = false;
1814     for (long i = 0; i < m_nodesWithExternProto.size(); i++)
1815         if (strcmp(protoName, m_nodesWithExternProto[i]) == 0) {
1816             found = true;
1817             break;
1818         }
1819     return found;
1820 }
1821 
1822 #define KANIM_RET_ONERROR(x) RET_AND_RESET_ONERROR(x, delete [] name;m_writeKanimNow = false)
1823 
1824 int
writeKanim(int f,const char * url)1825 Scene::writeKanim(int f, const char *url)
1826 {
1827     m_writeKanimNow = true;
1828     char* name = new char[strlen(url) + 1 + strlen(".wrl") + 1 + LEN_DEZIMAL_INT_MAX + 1];
1829     strcpy(name, url);
1830     char *nameBaseEnd = strrchr(name, '.');
1831     if (nameBaseEnd == NULL)
1832         nameBaseEnd = name + strlen(url);
1833     FloatArray keyTimes;
1834     bool allInterpolatorsLoop = true;
1835     for (long i = 0; i < m_timeSensors.size(); i++) {
1836         NodeTimeSensor *timer = (NodeTimeSensor *)m_timeSensors[i];
1837         if (!timer->loop()->getValue())
1838             allInterpolatorsLoop = false;
1839         int frac = timer->fraction_changed_Field();
1840         float interval = timer->cycleInterval()->getValue();
1841         for (SocketList::Iterator *j = timer->getOutput(frac).first();
1842                j != NULL; j = j->next()) {
1843             Interpolator *interpolator = (Interpolator *)(j->item().getNode());
1844             MFFloat *keys = interpolator->key();
1845             for (int k = 0; k < keys->getSize(); k++) {
1846                 float time = keys->getValue(k) * interval;
1847                 if (keyTimes.size() == 0)
1848                     keyTimes.append(time);
1849                 else if (time > keyTimes[keyTimes.size() - 1])
1850                     keyTimes.append(time);
1851                 else for (long l = 0 ; l < keyTimes.size(); l++) {
1852                     if (time == keyTimes[l])
1853                         break;
1854                     if (time < keyTimes[l]) {
1855                         keyTimes.insert(time, l);
1856                         break;
1857                     }
1858                 }
1859             }
1860         }
1861     }
1862     KANIM_RET_ONERROR( mywritestr(f ,"<?xml version=\"1.0\"?>\n") )
1863     KANIM_RET_ONERROR( mywritestr(f ,"<animation ") )
1864     if (allInterpolatorsLoop)
1865         KANIM_RET_ONERROR( mywritestr(f ,"loop=\"true\"") )
1866     else
1867         KANIM_RET_ONERROR( mywritestr(f ,"loop=\"false\"") )
1868     KANIM_RET_ONERROR( mywritestr(f ,">\n") )
1869     double t = swGetCurrentTime();
1870     m_timeStart = t;
1871     for (long i = 0; i < m_timeSensors.size(); i++)
1872         ((NodeTimeSensor *) m_timeSensors[i])->start(t);
1873     for (long i = 0; i < keyTimes.size(); i++) {
1874         updateTimeAt(t + keyTimes[i]);
1875 #ifdef WIN32
1876         sprintf(nameBaseEnd, "_%zu.wrl", i);
1877 #else
1878         sprintf(nameBaseEnd, "_%lu.wrl", i);
1879 #endif
1880         int filedes = open(name, O_WRONLY | O_CREAT,00666);
1881         if (filedes == -1) {
1882             delete [] name;
1883             m_writeKanimNow = false;
1884             return -1;
1885         }
1886         KANIM_RET_ONERROR( write(filedes, name, PURE_VRML97) )
1887         if (swTruncateClose(filedes)) {
1888             delete [] name;
1889             m_writeKanimNow = false;
1890             return -1;
1891         }
1892         KANIM_RET_ONERROR( mywritestr(f ,"    <frame file_name=\"") )
1893         URL fileUrl(name);
1894         MyString filename = fileUrl.GetFileName();
1895         if (filename.length() == 0)
1896             filename = name;
1897         KANIM_RET_ONERROR( mywritestr(f, (const char *)filename) )
1898         KANIM_RET_ONERROR( mywritestr(f ,"\" time=\"") )
1899         KANIM_RET_ONERROR( mywritef(f ,"%f", keyTimes[i]) )
1900         KANIM_RET_ONERROR( mywritestr(f ,"\"/>\n") )
1901     }
1902     KANIM_RET_ONERROR( mywritestr(f ,"</animation>\n") )
1903     delete [] name;
1904     if (swTruncateClose(f)) {
1905         m_writeKanimNow = false;
1906         return -1;
1907     }
1908     updateTime();
1909     m_writeKanimNow = false;
1910     return 0;
1911 }
1912 
hasEmptyMaterialCallback(Node * node,void * data)1913 static bool hasEmptyMaterialCallback(Node *node, void *data)
1914 {
1915     bool *emptyMaterial = (bool *) data;
1916     if (node->getType() == VRML_SHAPE)
1917         if (((NodeShape *)node)->appearance()->getValue() == NULL)
1918             *emptyMaterial = true;
1919     if (node->getType() == VRML_APPEARANCE)
1920         if (((NodeAppearance *)node)->material()->getValue() == NULL)
1921             *emptyMaterial = true;
1922     return true;
1923 }
1924 
hasEmptyMaterial()1925 bool Scene::hasEmptyMaterial()
1926 {
1927     bool emptyMaterial = false;
1928     getRoot()->doWithBranch(hasEmptyMaterialCallback, &emptyMaterial);
1929     return emptyMaterial;
1930 }
1931 
1932 void
collectAc3dMaterialInfo(char * name,Node * node)1933 Scene::collectAc3dMaterialInfo(char *name, Node *node)
1934 {
1935     m_ac3dMaterialNameArray.append(name);
1936     m_ac3dMaterialNodeArray.append(node);
1937     int materialIndex = m_ac3dMaterialNodeArray.size() - 1;
1938 
1939     StringMap::Chain::Iterator *j;
1940     bool alreadyInMap = false;
1941     for (int i = 0; i < m_ac3dMaterialIndexMap.width(); i++)
1942         for (j = m_ac3dMaterialIndexMap.chain(i).first(); j != NULL; j = j->next())
1943             if (strcmp(name, j->item()->getKey()) == 0)
1944                 alreadyInMap = true;
1945     if (alreadyInMap)
1946         TheApp->PrintMessageWindowsString(IDS_AC3D_EXPORT_COLOR_IGNORED, name);
1947     else
1948         m_ac3dMaterialIndexMap[name] = materialIndex;
1949 }
1950 
handleMaterial(Scene * scene,char * name,Node * node)1951 static void handleMaterial(Scene *scene, char *name, Node *node)
1952 {
1953     if (name != NULL) {
1954         scene->collectAc3dMaterialInfo(name, node);
1955         //free(name);? later !
1956     }
1957 }
1958 
1959 int
writeAc3d(int f,bool raven)1960 Scene::writeAc3d(int f, bool raven)
1961 {
1962     RET_ONERROR( mywritestr(f, "AC3Db\n") )
1963 
1964     m_ac3dMaterialNameArray.resize(0);
1965     m_ac3dMaterialNodeArray.resize(0);
1966     m_ac3dMaterialIndexMap.removeAll();
1967 
1968     NodeList *childList = ((NodeGroup *)getRoot())->children()->getValues();
1969 
1970     for (long i = 0; i < childList->size(); i++)
1971         childList->get(i)->handleAc3dMaterial(handleMaterial ,this);
1972 
1973     if (raven) {
1974         int materialIndex = 0;
1975         StringMap::Chain::Iterator *j;
1976         for (int i = 0; i < m_ac3dMaterialIndexMap.width(); i++) {
1977             for (j = m_ac3dMaterialIndexMap.chain(i).first(); j != NULL;
1978                  j = j->next()) {
1979                 const char *materialName = j->item()->getKey();
1980                 Node *materialNode = NULL;
1981                 for (long k = 0; k < m_ac3dMaterialNameArray.size(); k++) {
1982                      if (strcmp(materialName, m_ac3dMaterialNameArray[k]) == 0) {
1983                          materialNode = m_ac3dMaterialNodeArray[k];
1984                          materialNode->setAc3dMaterialIndex(materialIndex);
1985                      }
1986                 }
1987                 if (materialNode != NULL) {
1988                     materialNode->writeAc3dMaterial(f, 0, materialName);
1989                     materialIndex += materialNode->getIncAc3dMaterialIndex();
1990                 }
1991             }
1992         }
1993         m_ac3dEmptyMaterial = materialIndex;
1994     } else {
1995         int materialIndex = 0;
1996         for (long i = 0; i < m_ac3dMaterialNameArray.size(); i++) {
1997             const char *materialName = m_ac3dMaterialNameArray[i];
1998             Node *materialNode = m_ac3dMaterialNodeArray[i];
1999             materialNode->setAc3dMaterialIndex(materialIndex);
2000             materialNode->writeAc3dMaterial(f, 0, materialName);
2001             materialIndex += materialNode->getIncAc3dMaterialIndex();
2002         }
2003         m_ac3dEmptyMaterial = materialIndex;
2004     }
2005 
2006     // write ac3d equivalent of empty material
2007     RET_ONERROR( mywritestr(f, "MATERIAL \"") )
2008     if (raven)
2009         RET_ONERROR( mywritestr(f, "__") )
2010     RET_ONERROR( mywritestr(f, TheApp->GetDefaultAc3dMaterialName()) )
2011     RET_ONERROR( mywritestr(f, "\" ") )
2012     RET_ONERROR( mywritestr(f, "rgb 1 1 1  amb 0.2 0.2 0.2  emis 0 0 0  ") )
2013     RET_ONERROR( mywritestr(f, "spec 0 0 0  shi 2  trans 0\n") )
2014 
2015     int kids = 0;
2016     for (long i = 0; i < childList->size(); i++)
2017         if (childList->get(i)->canWriteAc3d())
2018             kids++;
2019     RET_ONERROR( mywritef(f, "OBJECT world\nkids %d\n", kids) )
2020     for (long i = 0; i < childList->size(); i++)
2021         RET_ONERROR( childList->get(i)->writeAc3d(f, 0) )
2022     return(0);
2023 }
2024 
getAllNodes(Node * node,void * data)2025 static bool getAllNodes(Node *node, void *data)
2026 {
2027     NodeArray *nodeArray = (NodeArray *) data;
2028     nodeArray->append(node);
2029     return true;
2030 }
2031 
2032 struct FaceSetAndNode  {
2033 public:
2034     NodeIndexedFaceSet *faceSet;
2035     Node *node;
2036 };
2037 
2038 int
writeOff(int f)2039 Scene::writeOff(int f)
2040 {
2041     int sumVerticesPerFace = 0;
2042     int numFaces = 0;
2043     int sumVertices = 0;
2044 
2045     Node *selection = getSelection()->getNode();
2046     NodeArray childList;
2047     MyArray<FaceSetAndNode> faces;
2048     getRoot()->doWithBranch(getAllNodes, &childList, false);
2049     for (long i = 0; i < childList.size(); i++) {
2050         Node *node = childList.get(i);
2051         if (node->isMeshBasedNode()) {
2052             MeshBasedNode *mBasedNode = (MeshBasedNode *)node;
2053             NodeIndexedFaceSet *face = (NodeIndexedFaceSet *)
2054                                        mBasedNode->toIndexedFaceSet();
2055             FaceSetAndNode faceAndNode;
2056             faceAndNode.faceSet = face;
2057             faceAndNode.node = node->getParent();
2058             faces.append(faceAndNode);
2059             face->ref();
2060             face->setFlag(NODE_FLAG_CONVERTED);
2061             MoveCommand *command = new MoveCommand(face, NULL, -1,
2062                                                    getRoot(), getRootField());
2063             command->execute();
2064             face->writeOffInit();
2065         }
2066     }
2067     bool hasColor = false;
2068     for (int i = 0; i < faces.size(); i++) {
2069         NodeIndexedFaceSet *face = faces[i].faceSet;
2070         if (face->colorPerVertex()->getValue())
2071             if (face->color()->getValue())
2072                 hasColor = true;
2073     }
2074     if (hasColor)
2075         RET_ONERROR( mywritestr(f, "C") )
2076     RET_ONERROR( mywritestr(f, "OFF\n") )
2077     for (int i = 0; i < faces.size(); i++) {
2078         NodeIndexedFaceSet *face = faces[i].faceSet;
2079         face->accountOffData(f);
2080         sumVerticesPerFace += face->getSumVerticesPerFaces();
2081         sumVertices += face->getSumVertices();
2082         numFaces += face->getMesh()->getNumFaces();
2083     }
2084     mywritef(f, "%d %d %d\n", sumVertices, numFaces, sumVerticesPerFace);
2085     for (int i = 0; i < faces.size(); i++) {
2086         NodeIndexedFaceSet *face = faces[i].faceSet;
2087         face->writeOffVerticesAndColors(f, faces[i].node);
2088     }
2089     int numIndices = 0;
2090     for (int i = 0; i < faces.size(); i++) {
2091         NodeIndexedFaceSet *face = faces[i].faceSet;
2092         face->writeOffIndicesAndColors(f, numIndices, childList.get(i));
2093         numIndices += face->getMesh()->getNumFaces();
2094     }
2095     for (int i = 0; i < faces.size(); i++) {
2096         NodeIndexedFaceSet *face = faces[i].faceSet;
2097         face->writeOffNormals(f, faces[i].node);
2098     }
2099     for (int i = 0; i < faces.size(); i++) {
2100          MoveCommand *command = new MoveCommand(faces[i].faceSet,
2101                                                 getRoot(), getRootField(),
2102                                                 NULL, -1);
2103          command->execute();
2104     }
2105     UpdateViews(NULL, UPDATE_ALL, NULL);
2106     setSelection(selection);
2107     UpdateViews(NULL, UPDATE_SELECTION);
2108     return(0);
2109 }
2110 
searchLongestTime(Node * node,void * data)2111 static bool searchLongestTime(Node *node, void *data)
2112 {
2113     double *time = (double *)data;
2114     if (node->getType() == VRML_TIME_SENSOR) {
2115         NodeTimeSensor *sensor = (NodeTimeSensor *)node;
2116         node->getScene()->addTimeSensor(sensor);
2117         if (sensor->cycleInterval()->getValue() > *time)
2118             *time = sensor->cycleInterval()->getValue();
2119     }
2120     if (node->getType() == DUNE_VRML_CUT) {
2121         NodeVrmlCut *cut = (NodeVrmlCut *)node;
2122         float sceneLength = 0;
2123         MFTime *lengths = cut->sceneLengths();
2124         for (int i = 0; i < lengths->getSize(); i++)
2125             sceneLength += lengths->getValue(i);
2126         if (sceneLength > *time)
2127             *time = sceneLength;
2128     }
2129     return true;
2130 }
2131 
2132 #define FRAME_RATE 24
2133 
2134 int
writeRib(int filedes,const char * file)2135 Scene::writeRib(int filedes, const char *file)
2136 {
2137     const char *url = file;
2138     int f = filedes;
2139 
2140     m_ribTexureFiles.removeAll();
2141 
2142     double longestTime = 0;
2143     getRoot()->doWithBranch(searchLongestTime, &longestTime);
2144 
2145     m_viewpoints.resize(0);
2146 
2147     findBindableNodes();
2148 
2149     int frames = longestTime * FRAME_RATE;
2150     if (longestTime == 0)
2151         frames = 1;
2152 
2153     bool running = isRunning();
2154     start();
2155     m_currentTime = 0;
2156 
2157     int framesPerFile = frames / TheApp->getNumExportFiles();
2158     if (framesPerFile == 0) {
2159         fprintf(stderr, "Warning: only %d frames, not all files are written\n",
2160                frames);
2161         framesPerFile = 1;
2162     }
2163 
2164     char filename[4096];
2165     snprintf(filename, 4095, "%s", url);
2166     int numFramesPerFile = 0;
2167     int currentfile = 0;
2168     for (int j = 0; j < frames; j++) {
2169         if (((numFramesPerFile >= framesPerFile) && (framesPerFile > 0)) ||
2170             (((currentfile == 0) && (frames > 1)) &&
2171              (TheApp->getNumExportFiles() > 1)))  {
2172             URL file(url);
2173             snprintf(filename, 4095, "%s%d.rib",
2174                      file.GetFileNameWithoutExtension(), ++currentfile);
2175             if ((TheApp->getNumExportFiles() > 1) ||
2176                 ((TheApp->getNumExportFiles() == 1) && (f != 1))) {
2177                 swTruncateClose(f);
2178                 f = open(filename, O_WRONLY | O_CREAT,00666);
2179             }
2180 
2181             RET_ONERROR( mywritestr(f, "##RenderMan RIB-Structure 1.0\n") )
2182             RET_ONERROR( mywritestr(f, "version 3.03\n\n") )
2183             numFramesPerFile = 0;
2184         }
2185         if (frames == 1) {
2186             f = open(file, O_WRONLY | O_CREAT,00666);
2187 
2188             RET_ONERROR( mywritestr(f, "##RenderMan RIB-Structure 1.0\n") )
2189             RET_ONERROR( mywritestr(f, "version 3.03\n\n") )
2190         }
2191         RET_ONERROR( writeRibNextFrame(f, file, j) )
2192         numFramesPerFile++;
2193     }
2194 
2195     swTruncateClose(f);
2196 
2197     if (!running)
2198         stop();
2199     updateTime();
2200 
2201     return(0);
2202 }
2203 
2204 int
writeRibNextFrame(int f,const char * url,int frame)2205 Scene::writeRibNextFrame(int f, const char *url, int frame)
2206 {
2207     glMatrixMode(GL_MODELVIEW);
2208     glLoadIdentity();
2209 
2210     updateTimeAt(m_currentTime);
2211 
2212     RET_ONERROR( mywritef(f, "FrameBegin %d\n", frame) )
2213     URL file(url);
2214     RET_ONERROR( mywritef(f, "Display \"%s%06d.tif\" \"file\" \"rgba\"\n",
2215                           file.GetFileNameWithoutExtension(), frame + 1) )
2216                                                 // png2yuv begins to count at 1
2217 
2218     float fov = 30;
2219     if (m_currentViewpoint)
2220         fov = m_currentViewpoint->fov()->getValue() * 360.0 / (2 * M_PI);
2221 
2222     RET_ONERROR( mywritestr(f, "ShadingRate 1\n") )
2223     RET_ONERROR( mywritef(f, "Projection \"perspective\" \"fov\" [%f]\n",
2224                              fov) )
2225     RET_ONERROR( mywritestr(f, "Identity\n") )
2226 
2227     if (m_currentNavigationInfo &&
2228         m_currentNavigationInfo->headlight()->getValue()) {
2229         RET_ONERROR( mywritestr(f, "LightSource \"distantlight\" 1 ") )
2230         RET_ONERROR( mywritestr(f, "\"intensity\" [1] ") )
2231         RET_ONERROR( mywritestr(f, "\"from\" [200 300 100] ") ) //light 0,0,10?
2232         RET_ONERROR( mywritestr(f, "\"to\" [0 0 0]\n") )
2233     }
2234 
2235     RET_ONERROR( mywritef(f, "Rotate 0 0 1 0\n") )
2236     RET_ONERROR( mywritef(f ,"Translate 0 0 0\n") )
2237 
2238     RET_ONERROR( mywritef(f, "\n") )
2239 
2240     RET_ONERROR( mywritestr(f, "WorldBegin\n\n") )
2241     RET_ONERROR( mywritestr(f, "Identity\n\n") )
2242 
2243     NodeList *childList = ((NodeGroup *)getRoot())->children()->getValues();
2244 
2245     for (long i = 0; i < childList->size(); i++)
2246         RET_ONERROR( childList->get(i)->writeRib(f, 0) )
2247 
2248     RET_ONERROR( mywritestr(f, "WorldEnd\n\n") )
2249 
2250     RET_ONERROR( mywritestr(f, "FrameEnd\n") )
2251 
2252     m_currentTime = (double)frame / FRAME_RATE;
2253 
2254     return(0);
2255 }
2256 
2257 
2258 int
writePovray(int filedes,const char * file)2259 Scene::writePovray(int filedes, const char *file)
2260 {
2261     const char *url = file;
2262     int f = filedes;
2263 
2264     m_povrayTexureFiles.removeAll();
2265 
2266     double longestTime = 0;
2267     getRoot()->doWithBranch(searchLongestTime, &longestTime);
2268 
2269     m_viewpoints.resize(0);
2270 
2271     findBindableNodes();
2272 
2273     int frames = longestTime * FRAME_RATE;
2274     if (longestTime == 0)
2275         frames = 1;
2276 
2277     bool running = isRunning();
2278     start();
2279     m_currentTime = 0;
2280 
2281     int framesPerFile = frames / TheApp->getNumExportFiles();
2282     if (framesPerFile == 0) {
2283         fprintf(stderr, "Warning: only %d frames, not all files are written\n",
2284                frames);
2285         framesPerFile = 1;
2286     }
2287 
2288     char filename[4096];
2289     snprintf(filename, 4095, "%s", url);
2290     int numFramesPerFile = 0;
2291     int currentfile = 0;
2292     for (int j = 0; j < frames; j++) {
2293         if (((numFramesPerFile >= framesPerFile) && (framesPerFile > 0)) ||
2294             (((currentfile == 0) && (frames > 1)) &&
2295              (TheApp->getNumExportFiles() > 1)))  {
2296             URL file(url);
2297             snprintf(filename, 4095, "%s%d.pov",
2298                      file.GetFileNameWithoutExtension(), ++currentfile);
2299             if ((TheApp->getNumExportFiles() > 1) ||
2300                 ((TheApp->getNumExportFiles() == 1) && (f != 1))) {
2301                 swTruncateClose(f);
2302                 f = open(filename, O_WRONLY | O_CREAT,00666);
2303             }
2304             numFramesPerFile = 0;
2305         }
2306         if (numFramesPerFile == 0) {
2307             RET_ONERROR( mywritestr(f, "// Povray output of white_dune\n") )
2308             RET_ONERROR( mywritestr(f, "#version 3.7;\n\n") )
2309             RET_ONERROR( mywritef(f, "// number_of_frames %d\n\n", frames) )
2310             RET_ONERROR( mywritestr(f,
2311                              "global_settings { assumed_gamma 1.0}\n\n") )
2312             RET_ONERROR( mywritef(f, "light_source{ <0, 0, -10>  %s",
2313                                      "color rgb<1,1,1> }\n\n") )
2314         }
2315         RET_ONERROR( writePovrayNextFrame(f, file, j) )
2316         numFramesPerFile++;
2317     }
2318 
2319     swTruncateClose(f);
2320 
2321     if (!running)
2322         stop();
2323     updateTime();
2324 
2325     return(0);
2326 }
2327 
2328 int
writePovrayNextFrame(int f,const char * url,int frame)2329 Scene::writePovrayNextFrame(int f, const char *url, int frame)
2330 {
2331     RET_ONERROR( mywritef(f, "#if(frame_number=%d)\n", frame) )
2332 
2333     m_currentTime = (double)frame / FRAME_RATE;
2334 
2335     updateTimeAt(m_currentTime);
2336 
2337     NodeList *childList = ((NodeGroup *)getRoot())->children()->getValues();
2338 
2339     for (long i = 0; i < childList->size(); i++)
2340         RET_ONERROR( childList->get(i)->writePovray(f, 0) )
2341 
2342     RET_ONERROR( mywritef(f, "#end\n") )
2343     return(0);
2344 }
2345 
collectCattExportRecNodes(Node * node,void * data)2346 static bool collectCattExportRecNodes(Node *node, void *data)
2347 {
2348     if (node->getType() == DUNE_CATT_EXPORT_REC) {
2349         NodeArray *array = (NodeArray *)data;
2350         array->append(node);
2351     }
2352     return true;
2353 }
2354 
2355 int
writeCattGeo(void)2356 Scene::writeCattGeo(void)
2357 {
2358     m_cattGeoFileCounter = 0;
2359     m_cattGeoCornerCounter = 1;
2360     m_cattGeoPlaneCounter = 1;
2361     m_cattRecIsWritten = false;
2362     m_cattSrcIsWritten = false;
2363 
2364     MyArray<NodeCattExportRec *> cattExportRecNodes;
2365     getRoot()->doWithBranch(collectCattExportRecNodes, &cattExportRecNodes);
2366 
2367     for (long i = 0; i < cattExportRecNodes.size(); i++)
2368         for (long j = 0; j < i; j++)
2369            if (cattExportRecNodes[i]->id()->getValue() ==
2370                cattExportRecNodes[j]->id()->getValue()) {
2371                char message[1024];
2372                mysnprintf(message, 1023, "Warning: id %d is used %s\n",
2373                           cattExportRecNodes[i]->id()->getValue(),
2374                           "in more than one CattExportRec nodes\n");
2375                if (TheApp->mainWnd() == NULL)
2376                    swDebugf(message);
2377                else {
2378                    TheApp->MessageBox(message);
2379                    setSelection(cattExportRecNodes[j]);
2380                    UpdateViews(NULL, UPDATE_SELECTION);
2381                }
2382                break;
2383            }
2384     if (m_root->writeCattGeo(0,0))
2385         return -1;
2386 
2387     return(0);
2388 }
2389 
2390 bool
validateLdrawExport()2391 Scene::validateLdrawExport()
2392 {
2393     NodeList *list = searchNodeType(DUNE_LDRAW_DAT_EXPORT);
2394     if (list->size() == 0) {
2395         TheApp->MessageBoxId(IDS_LDRAW_DAT_EXPORT_NODE_CREATED, SW_MB_WARNING);
2396         Node *node = createNode("LdrawDatExport");
2397         execute(new MoveCommand(node, NULL, -1, m_root, m_rootField));
2398         UpdateViews(NULL, UPDATE_SELECTION);
2399         return false;
2400     }
2401     if (list->size() > 1) {
2402         TheApp->MessageBoxId(IDS_TO_MUCH_LDRAW_DAT_EXPORT_NODES);
2403         return false;
2404     }
2405     NodeLdrawDatExport *node = (NodeLdrawDatExport *)list->get(0);
2406     return node->validate();
2407 }
2408 
2409 int
writeLdrawDat(int filedes,const char * path)2410 Scene::writeLdrawDat(int filedes, const char *path)
2411 {
2412     m_currentLdrawColor = -1;
2413     NodeList *list = searchNodeType(DUNE_LDRAW_DAT_EXPORT);
2414     const char *filename = strrchr(path, swGetPathSeperator());
2415     if (filename == NULL)
2416         filename = path;
2417     else
2418         filename++;
2419     if (list->size() == 1) {
2420         NodeLdrawDatExport *node = (NodeLdrawDatExport *)list->get(0);
2421         if (node->writeLdrawDatHeader(filedes, filename) != 0)
2422             return 0;
2423     };
2424     m_root->writeLdrawDat(filedes, 0);
2425     return 0;
2426 }
2427 
writeCDynamicNodeDeclaration(Node * node,void * data)2428 static bool writeCDynamicNodeDeclaration(Node *node, void *data)
2429 {
2430     WriteCDynamicNodeData *parameters = (WriteCDynamicNodeData *)data;
2431     Proto *proto = node->getProto();
2432     if (proto->isDynamicProto())
2433         parameters->result = proto->writeCDeclaration(parameters->filedes,
2434                                  parameters->languageFlag);
2435     if (parameters->result != 0)
2436         return false;
2437 
2438     return true;
2439 }
2440 
2441 int
writeCDeclaration(int f,int languageFlag)2442 Scene::writeCDeclaration(int f, int languageFlag)
2443 {
2444     ProtoMap::Chain::Iterator *j;
2445     for (int i = 0; i < m_protos.width(); i++)
2446         for (j = m_protos.chain(i).first(); j != NULL; j = j->next()) {
2447             Proto *proto = j->item()->getData();
2448             if (proto == NULL)
2449                 continue;
2450             proto->setIsInScene(false);
2451             proto->setWriteCDeclarationWritten(false);
2452             proto->setInUse(false);
2453             if (proto->getType() == VRML_POSITION_INTERPOLATOR)
2454                 proto->setInUse(true);
2455             if (proto->getType() == VRML_ORIENTATION_INTERPOLATOR)
2456                 proto->setInUse(true);
2457             if (proto->isDeclaredInRwd_h())
2458                 proto->setInUse(true);
2459     }
2460     m_root->doWithBranch(markUsedProto, this);
2461     for (int i = 0; i < m_protos.width(); i++)
2462         for (j = m_protos.chain(i).first(); j != NULL; j = j->next()) {
2463             Proto *proto = j->item()->getData();
2464             if (proto == NULL)
2465                 continue;
2466             if (proto->getType() == VRML_COMMENT)
2467                 continue;
2468             if (proto->isMesh() && !proto->isExportTargetMesh())
2469                 continue;
2470             if (proto->isMismatchingProto())
2471                 continue;
2472             if (proto->isInUse())
2473                 if (proto->writeCDeclaration(f, languageFlag) != 0)
2474                     return -1;
2475         }
2476     WriteCDynamicNodeData parameters;
2477     parameters.result = 0;
2478     parameters.filedes = f;
2479     parameters.languageFlag = languageFlag;
2480     m_root->doWithBranch(writeCDynamicNodeDeclaration, &parameters);
2481     return parameters.result;
2482 }
2483 
2484 int
writeCDataFunctionsCalls(int f,int languageFlag)2485 Scene::writeCDataFunctionsCalls(int f, int languageFlag)
2486 {
2487     if (languageFlag & MANY_JAVA_CLASSES) {
2488         RET_ONERROR( mywritef(f, "    }\n") )
2489         RET_ONERROR( mywritef(f, "}\n") )
2490         RET_ONERROR( mywritef(f, "class Data%sFunctionClass_%d {\n",
2491                               TheApp->getCPrefix(), getNumDataClasses()) )
2492     }
2493     RET_ONERROR( mywritef(f,
2494         "    public static void data%sFunction%d() {\n",
2495         TheApp->getCPrefix(), getNumDataClasses()) )
2496     increaseNumDataClasses();
2497 
2498     return(0);
2499 }
2500 
2501 struct WriteCStruct {
2502     int filedes;
2503     int ret;
2504     int languageFlag;
2505     bool outsideJavaClass;
2506     bool writeBracket;
2507 };
2508 
2509 bool writeCVariableNameLine(Node *node, const char *variableName,
2510                             struct WriteCStruct *cWrite, bool extraJavaClass);
2511 
writeCSetWrittenFalse(Node * node,void * data)2512 bool writeCSetWrittenFalse(Node *node, void *data)
2513 {
2514     if (node == NULL)
2515         return true;
2516 
2517     node->setWritten(false);
2518 
2519     return true;
2520 }
2521 
2522 class WriteData {
2523 public:
2524     int languageFlag;
2525     int filedes;
2526 };
2527 
writeCCoordinateFirst(Node * node,void * data)2528 bool writeCCoordinateFirst(Node *node, void *data)
2529 {
2530     if (node == NULL)
2531         return true;
2532 
2533     WriteData *wdata = (WriteData *)data;
2534     if (node->getType() == VRML_COORDINATE) {
2535         node->writeCDataFunction(wdata->filedes, wdata->languageFlag,
2536                                  true, true);
2537     }
2538     return true;
2539 }
2540 
writeCIndexedFaceSetFirst(Node * node,void * data)2541 bool writeCIndexedFaceSetFirst(Node *node, void *data)
2542 {
2543     if (node == NULL)
2544         return true;
2545 
2546     WriteData *wdata = (WriteData *)data;
2547     if (node->getType() == VRML_INDEXED_FACE_SET) {
2548         node->writeCDataFunction(wdata->filedes, wdata->languageFlag,
2549                                  true, true);
2550     }
2551     return true;
2552 }
2553 
writeCShapeFirst(Node * node,void * data)2554 bool writeCShapeFirst(Node *node, void *data)
2555 {
2556     if (node == NULL)
2557         return true;
2558 
2559     WriteData *wdata = (WriteData *)data;
2560     if (node->getType() == VRML_SHAPE) {
2561         node->writeCDataFunction(wdata->filedes, wdata->languageFlag,
2562                                  true, true);
2563     }
2564     return true;
2565 }
2566 
writeCHAnimJointFirst(Node * node,void * data)2567 bool writeCHAnimJointFirst(Node *node, void *data)
2568 {
2569     if (node == NULL)
2570         return true;
2571 
2572     WriteData *wdata = (WriteData *)data;
2573     if (node->getType() == X3D_HANIM_JOINT) {
2574         node->writeCDataFunction(wdata->filedes, wdata->languageFlag,
2575                                  true, true);
2576     }
2577     return true;
2578 }
2579 
2580 static MyArray<const char *> variableNames;
2581 
writeCNodeData(Node * node,void * data)2582 bool writeCNodeData(Node *node, void *data)
2583 {
2584     if (node == NULL)
2585         return true;
2586 
2587     struct WriteCStruct *cWrite = (struct WriteCStruct *)data;
2588 
2589     bool writeBracket = cWrite->writeBracket;
2590 
2591     node->addToConvertedNodes(node->getScene()->getWriteFlags());
2592 
2593     if (node->getNumConvertedNodes() > 0) {
2594         for (int i = 0; i < node->getNumConvertedNodes(); i++) {
2595             node->getConvertedNode(i)->doWithBranch(writeCNodeData, data,
2596                                                     false);
2597         }
2598         writeBracket = false;
2599     }
2600 
2601     if (!node->isCWriteable())
2602         return true;
2603 
2604     Proto *proto = node->getProto();
2605     if (proto->getType() == VRML_COMMENT)
2606         return true;
2607     if (proto->isMismatchingProto())
2608         return true;
2609 
2610     // do not write multiple declarations for USE'd nodes
2611     if (node->getFlag(NODE_FLAG_TOUCHED))
2612         return true;
2613     node->setFlag(NODE_FLAG_TOUCHED);
2614 
2615     if (node->hasProtoNodes()) {
2616        NodePROTO *protoNode = (NodePROTO *)node;
2617        for (int i = 0; i < protoNode->getNumProtoNodes(); i++)
2618            protoNode->getProtoNode(i)->doWithBranch(writeCNodeData, data);
2619         if (cWrite->ret == -1)
2620             return false;
2621     }
2622 
2623     bool extraJavaClass = false;
2624     if (node->needExtraJavaClass())
2625         extraJavaClass = true;
2626 
2627     if (cWrite->languageFlag & MANY_JAVA_CLASSES) {
2628         if (cWrite->outsideJavaClass) {
2629             if (!extraJavaClass)
2630                 return true;
2631         } else {
2632             if (extraJavaClass)
2633                 return true;
2634         }
2635     }
2636     bool writeName = true;
2637     if (node->getType() != DUNE_CURVE_ANIMATION) {
2638         for (int i = 0; i < variableNames.size(); i++)
2639             if (strcmp(variableNames[i], node->getVariableName()) == 0) {
2640                 writeName = false;
2641                 break;
2642             }
2643         if (writeName) {
2644             writeCVariableNameLine(node, node->getVariableName(), cWrite,
2645                                    extraJavaClass);
2646             if (cWrite->ret != 0)
2647                 return false;
2648             variableNames.append(node->getVariableName());
2649         }
2650     } else {
2651         NodeCurveAnimation *curve = (NodeCurveAnimation *)node;
2652         Node *inter = curve->getPositionInterpolator();
2653         const char *variableName = inter->getVariableName();
2654         bool writeName = true;
2655         for (int i = 0; i < variableNames.size(); i++)
2656             if (strcmp(variableNames[i], variableName) == 0) {
2657                 writeName = false;
2658                 break;
2659             }
2660         if (writeName) {
2661             writeCVariableNameLine(inter, variableName, cWrite, extraJavaClass);
2662             if (cWrite->ret != 0)
2663                 return false;
2664             variableNames.append(variableName);
2665         }
2666         inter = curve->getOrientationInterpolator();
2667         variableName = inter->getVariableName();
2668         writeName = true;
2669         for (int i = 0; i < variableNames.size(); i++)
2670             if (strcmp(variableNames[i], node->getVariableName()) == 0) {
2671                 writeName = false;
2672                 break;
2673             }
2674         if (writeName) {
2675             writeCVariableNameLine(inter, variableName, cWrite, extraJavaClass);
2676             if (cWrite->ret != 0)
2677                return false;
2678             variableNames.append(variableName);
2679         }
2680     }
2681 
2682     if (node->isMeshBasedNode())
2683         if (node->getType() != VRML_INDEXED_FACE_SET)
2684             if (writeName)
2685                 writeBracket = true;
2686 
2687     int f = cWrite->filedes;
2688     if (cWrite->languageFlag & MANY_JAVA_CLASSES)
2689         if (extraJavaClass && writeBracket) {
2690             RET_ONERROR( mywritestr(f, "}\n") )
2691         }
2692 
2693     return true;
2694 }
2695 
writeCVariableNameLine(Node * node,const char * variableName,struct WriteCStruct * cWrite,bool extraJavaClass)2696 bool writeCVariableNameLine(Node *node, const char *variableName,
2697                            struct WriteCStruct *cWrite, bool extraJavaClass)
2698 {
2699     int f = cWrite->filedes;
2700     int error = 0;
2701     if (!(extraJavaClass && (cWrite->languageFlag & MANY_JAVA_CLASSES)))
2702         if (mywritestr(f, "    ") != 0) {
2703             cWrite->ret = -1;
2704             return false;
2705         }
2706     if (cWrite->languageFlag & C_SOURCE)
2707         if (mywritestr(f, "struct ") != 0) {
2708             cWrite->ret = -1;
2709             return false;
2710         }
2711 
2712     if (cWrite->languageFlag & MANY_JAVA_CLASSES) {
2713         if (extraJavaClass)
2714             RET_ONERROR( mywritef(f, "class %s%s {\n    ",
2715                                   TheApp->getCPrefix(),
2716                                   node->getVariableName()) )
2717         RET_ONERROR( mywritestr(f, "public static ") )
2718     }
2719 
2720     bool written = false;
2721     if (node->isDynamicFieldsNode() && !node->isPROTO()) {
2722         if (mywritestr(f, (const char *)node->getClassName()) != 0)
2723             error = -1;
2724         else
2725             written = true;
2726     } else if ((cWrite->languageFlag & C_SOURCE) && node->isPROTO() &&
2727                (!written)) {
2728         if (mywritef(f, "%s%s_%s", TheApp->getCPrefix(), (const char *)
2729                                    node->getProto()->getName(true),
2730                                    variableName) != 0)
2731             error = -1;
2732         else
2733             written = true;
2734     } if ((!written) && mywritef(f, "%s%s", TheApp->getCPrefix(), (const char *)
2735                                     node->getProto()->getName(true)) != 0)
2736         error = -1;
2737     if (mywritestr(f, " ") != 0)
2738         error = -1;
2739     else if (mywritestr(f, variableName) != 0)
2740         error = -1;
2741     else if (mywritestr(f, ";\n") != 0)
2742         error = -1;
2743     if (error != 0) {
2744         cWrite->ret = -1;
2745     }
2746     return true;
2747 }
2748 
writeCDynamicNodeCallback(Node * node,void * data)2749 static bool writeCDynamicNodeCallback(Node *node, void *data)
2750 {
2751     WriteCDynamicNodeData *parameters = (WriteCDynamicNodeData *)data;
2752     Proto *proto = node->getProto();
2753     if (proto->isDynamicProto())
2754         parameters->result = node->writeCDynamicNodeCallback(
2755                                  parameters->filedes, parameters->languageFlag);
2756     if (parameters->result != 0)
2757         return false;
2758     return true;
2759 }
2760 
writeCParentCallback(Node * node,void * data)2761 static bool writeCParentCallback(Node *node, void *data)
2762 {
2763     WriteCDynamicNodeData *parameters = (WriteCDynamicNodeData *)data;
2764     if (!node->isCWriteable())
2765         return true;
2766     parameters->result = node->writeCGetParent(parameters->filedes, parameters->languageFlag);
2767     if (parameters->result != 0)
2768         return false;
2769     return true;
2770 }
2771 
writeCInstallDynamicNodeCallback(Node * node,void * data)2772 static bool writeCInstallDynamicNodeCallback(Node *node, void *data)
2773 {
2774     WriteCDynamicNodeData *parameters = (WriteCDynamicNodeData *)data;
2775     Proto *proto = node->getProto();
2776     if (proto->isDynamicProto() && !node->isPROTO())
2777         parameters->result = node->writeCInstallDynamicNodeCallback(
2778                                    parameters->filedes,
2779                                    parameters->languageFlag, node->getProto());
2780     if (parameters->result != 0)
2781         return false;
2782     return true;
2783 }
2784 
writeCRemoveAlreadyWrittenEventOuts(Node * node,void * data)2785 static bool writeCRemoveAlreadyWrittenEventOuts(Node *node, void *data)
2786 {
2787     node->removeAlreadyWrittenEventOuts();
2788     return true;
2789 }
2790 
2791 int
writeC(int f,int languageFlag)2792 Scene::writeC(int f, int languageFlag)
2793 {
2794     dynamicNodeCallbackRemove();
2795     m_root->doWithBranch(writeCRemoveAlreadyWrittenEventOuts, NULL);
2796     m_scriptTypeWritten = false;
2797     if (languageFlag & C_SOURCE)
2798         RET_ONERROR( mywritestr(f, "/*") )
2799     else
2800         RET_ONERROR( mywritestr(f, "//") )
2801     RET_ONERROR( mywritestr(f, " VRML97/X3D file \"") )
2802     URL *url = new URL(getURL());
2803     RET_ONERROR( mywritestr(f, url->GetFileName()) )
2804     delete url;
2805     RET_ONERROR( mywritestr(f, "\" converted to ") )
2806     if (languageFlag & C_SOURCE)
2807         RET_ONERROR( mywritestr(f, "C") )
2808     else if (languageFlag & CC_SOURCE)
2809         RET_ONERROR( mywritestr(f, "C++") )
2810     else if (languageFlag & JAVA_SOURCE)
2811         RET_ONERROR( mywritestr(f, "java") )
2812     RET_ONERROR( mywritestr(f, " with white_dune") )
2813     if (languageFlag & C_SOURCE)
2814         RET_ONERROR( mywritestr(f, "*/") )
2815     RET_ONERROR( mywritestr(f, "\n\n") )
2816     if (languageFlag & C_SOURCE) {
2817         RET_ONERROR( mywritestr(f, "#ifndef NULL\n") )
2818         RET_ONERROR( mywritestr(f, "# define NULL (void *)0\n") )
2819         RET_ONERROR( mywritestr(f, "#endif\n") )
2820         RET_ONERROR( mywritestr(f, "\n") )
2821         RET_ONERROR( mywritestr(f, "struct ") )
2822         RET_ONERROR( mywritestr(f, TheApp->getCSceneGraphName()) )
2823         RET_ONERROR( mywritestr(f, ";\n") )
2824         RET_ONERROR( mywritestr(f, "\n") )
2825         RET_ONERROR( mywritestr(f, "typedef void ") )
2826         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
2827         RET_ONERROR( mywritestr(f, ";\n") )
2828         RET_ONERROR( mywritestr(f, "\n") )
2829         RET_ONERROR( mywritestr(f, "struct ") )
2830         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
2831         RET_ONERROR( mywritestr(f, "Struct;\n") )
2832         RET_ONERROR( mywritestr(f, "\n") )
2833         RET_ONERROR( mywritestr(f, "typedef void (*") )
2834         RET_ONERROR( mywritestr(f, TheApp->getCPrefix()) )
2835         RET_ONERROR( mywritestr(f, "Callback)") )
2836         RET_ONERROR( mywritestr(f, "(") )
2837         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
2838         RET_ONERROR( mywritestr(f, " *node, void *data);\n") )
2839         RET_ONERROR( mywritestr(f, "\n") )
2840         RET_ONERROR( mywritestr(f, "void ") )
2841         RET_ONERROR( mywritestr(f, TheApp->getCPrefix()) )
2842         RET_ONERROR( mywritestr(f, "TreeRenderCallback(struct ") )
2843         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
2844         RET_ONERROR( mywritestr(f, "Struct *node, void *data);\n") )
2845         RET_ONERROR( mywritestr(f, "void ") )
2846         RET_ONERROR( mywritestr(f, TheApp->getCPrefix()) )
2847         RET_ONERROR( mywritestr(f, "TreeDoWithDataCallback(struct ") )
2848         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
2849         RET_ONERROR( mywritestr(f, "Struct *node, void *data);\n") )
2850         RET_ONERROR( mywritestr(f, "typedef int (*") )
2851         RET_ONERROR( mywritestr(f, TheApp->getCPrefix()) )
2852         RET_ONERROR( mywritestr(f, "ProcessEventCallback)") )
2853         RET_ONERROR( mywritestr(f, "(") )
2854         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
2855         RET_ONERROR( mywritestr(f, " *node, const char *event, ") )
2856         RET_ONERROR( mywritestr(f, "void *data);\n") )
2857         RET_ONERROR( mywritestr(f, "\n") )
2858         RET_ONERROR( mywritestr(f, "\n\n") )
2859      }
2860      if (languageFlag & CC_SOURCE) {
2861         RET_ONERROR( mywritestr(f, "#include <stddef.h> // for NULL\n") )
2862         RET_ONERROR( mywritestr(f, "\n") )
2863         RET_ONERROR( mywritestr(f, "class ") )
2864         RET_ONERROR( mywritestr(f, TheApp->getCSceneGraphName()) )
2865         RET_ONERROR( mywritestr(f, ";\n") )
2866         RET_ONERROR( mywritestr(f, "\n") )
2867         RET_ONERROR( mywritestr(f, "class ") )
2868         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
2869         RET_ONERROR( mywritestr(f, " {\n") )
2870         RET_ONERROR( mywritestr(f, "public:\n") )
2871         RET_ONERROR( mywritestr(f, "    ") )
2872         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
2873         RET_ONERROR( mywritestr(f, "() {\n") )
2874         RET_ONERROR( mywritestr(f, "        m_parent = NULL;\n") )
2875         RET_ONERROR( mywritestr(f, "        m_protoRoot = NULL;\n") )
2876         RET_ONERROR( mywritestr(f, "        m_data = NULL;\n") )
2877         RET_ONERROR( mywritestr(f, "    }\n") )
2878         RET_ONERROR( mywritestr(f, "    virtual void treeRender(") )
2879         RET_ONERROR( mywritestr(f, "void *dataptr) {\n") )
2880         RET_ONERROR( mywritestr(f, "        if (m_protoRoot != NULL)\n") )
2881         RET_ONERROR( mywritestr(f, "            m_protoRoot->") )
2882         RET_ONERROR( mywritestr(f, "treeRender(dataptr);\n") )
2883         RET_ONERROR( mywritestr(f, "    }\n") )
2884         RET_ONERROR( mywritestr(f, "    virtual void treeDoWithData(") )
2885         RET_ONERROR( mywritestr(f, "void *dataptr) {\n") )
2886         RET_ONERROR( mywritestr(f, "        if (m_protoRoot != NULL)\n") )
2887         RET_ONERROR( mywritestr(f, "            m_protoRoot->") )
2888         RET_ONERROR( mywritestr(f, "treeDoWithData(dataptr);\n") )
2889         RET_ONERROR( mywritestr(f, "    }\n") )
2890         RET_ONERROR( mywritestr(f, "    ") )
2891         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
2892         RET_ONERROR( mywritestr(f, " *m_parent;\n") )
2893         RET_ONERROR( mywritestr(f, "    ") )
2894         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
2895         RET_ONERROR( mywritestr(f, " *m_protoRoot;\n") )
2896         RET_ONERROR( mywritestr(f, "    void *m_data;\n") )
2897         RET_ONERROR( mywritestr(f, "    virtual int getType() const = 0;\n") )
2898         RET_ONERROR( mywritestr(f, "};\n") )
2899         RET_ONERROR( mywritestr(f, "\n") )
2900         RET_ONERROR( mywritestr(f, "typedef void (*") )
2901         RET_ONERROR( mywritestr(f, TheApp->getCPrefix()) )
2902         RET_ONERROR( mywritestr(f, "Callback)") )
2903         RET_ONERROR( mywritestr(f, "(") )
2904         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
2905         RET_ONERROR( mywritestr(f, " *node, void *dataptr);\n") )
2906         RET_ONERROR( mywritestr(f, "typedef bool (*") )
2907         RET_ONERROR( mywritestr(f, TheApp->getCPrefix()) )
2908         RET_ONERROR( mywritestr(f, "ProcessEventCallback)") )
2909         RET_ONERROR( mywritestr(f, "(") )
2910         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
2911         RET_ONERROR( mywritestr(f, " *node, const char *event, ") )
2912         RET_ONERROR( mywritestr(f, "void *dataptr);\n") )
2913         RET_ONERROR( mywritestr(f, "\n\n") )
2914      }
2915      if (languageFlag & JAVA_SOURCE) {
2916         RET_ONERROR( mywritestr(f, "abstract class ") )
2917         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
2918         RET_ONERROR( mywritestr(f, " {\n") )
2919         RET_ONERROR( mywritestr(f, "    void treeRender(") )
2920         RET_ONERROR( mywritestr(f, TheApp->getCPrefix()) )
2921         RET_ONERROR( mywritestr(f, "Node dataptr, Object object) {\n") )
2922         RET_ONERROR( mywritestr(f, "        if (m_protoRoot != null)\n") )
2923         RET_ONERROR( mywritestr(f, "            m_protoRoot.") )
2924         RET_ONERROR( mywritestr(f, "treeRender(dataptr, object);\n") )
2925         RET_ONERROR( mywritestr(f, "    }\n") )
2926         RET_ONERROR( mywritestr(f, "    void treeDoWithData(") )
2927         RET_ONERROR( mywritestr(f, TheApp->getCPrefix()) )
2928         RET_ONERROR( mywritestr(f, "Node dataptr) {\n") )
2929         RET_ONERROR( mywritestr(f, "        if (m_protoRoot != null)\n") )
2930         RET_ONERROR( mywritestr(f, "            m_protoRoot.") )
2931         RET_ONERROR( mywritestr(f, "treeDoWithData(dataptr);\n") )
2932         RET_ONERROR( mywritestr(f, "    }\n") )
2933         RET_ONERROR( mywritestr(f, "    ") )
2934         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
2935         RET_ONERROR( mywritestr(f, " m_parent;\n") )
2936         RET_ONERROR( mywritestr(f, "    Object m_data;\n") )
2937         RET_ONERROR( mywritestr(f, "    ") )
2938         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
2939         RET_ONERROR( mywritestr(f, " m_protoRoot;\n") )
2940         RET_ONERROR( mywritestr(f, "    abstract int getType();\n") )
2941         RET_ONERROR( mywritestr(f, "};\n") )
2942         RET_ONERROR( mywritestr(f, "\n") )
2943 
2944         RET_ONERROR( mywritestr(f, "class ") )
2945         RET_ONERROR( mywritestr(f, TheApp->getCPrefix()) )
2946         RET_ONERROR( mywritestr(f, "RenderCallback {\n") )
2947         RET_ONERROR( mywritestr(f, "   public void render(") )
2948         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
2949         RET_ONERROR( mywritestr(f, " node, Object object) {}\n") )
2950         RET_ONERROR( mywritestr(f, "}\n") )
2951 
2952         RET_ONERROR( mywritestr(f, "class ") )
2953         RET_ONERROR( mywritestr(f, TheApp->getCPrefix()) )
2954         RET_ONERROR( mywritestr(f, "TreeRenderCallback {\n") )
2955         RET_ONERROR( mywritestr(f, "   public void treeRender(") )
2956         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
2957         RET_ONERROR( mywritestr(f, " node, Object object) {}\n") )
2958         RET_ONERROR( mywritestr(f, "}\n") )
2959         RET_ONERROR( mywritestr(f, "\n") )
2960 
2961         RET_ONERROR( mywritestr(f, "class ") )
2962         RET_ONERROR( mywritestr(f, TheApp->getCPrefix()) )
2963         RET_ONERROR( mywritestr(f, "DoWithDataCallback {\n") )
2964         RET_ONERROR( mywritestr(f, "   public void doWithData(") )
2965         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
2966         RET_ONERROR( mywritestr(f, " node) ") )
2967         RET_ONERROR( mywritestr(f, "{}\n") )
2968         RET_ONERROR( mywritestr(f, "   public void update(") )
2969         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
2970         RET_ONERROR( mywritestr(f, " node) ") )
2971         RET_ONERROR( mywritestr(f, "{}\n") )
2972         RET_ONERROR( mywritestr(f, "   public Object getNullOrObject(") )
2973         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
2974         RET_ONERROR( mywritestr(f, " node) ") )
2975         RET_ONERROR( mywritestr(f, "{ return null; }\n") )
2976         RET_ONERROR( mywritestr(f, "}\n") )
2977 
2978         RET_ONERROR( mywritestr(f, "class ") )
2979         RET_ONERROR( mywritestr(f, TheApp->getCPrefix()) )
2980         RET_ONERROR( mywritestr(f, "TreeDoWithDataCallback {\n") )
2981         RET_ONERROR( mywritestr(f, "   public void treeDoWithData(") )
2982         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
2983         RET_ONERROR( mywritestr(f, " node) ") )
2984         RET_ONERROR( mywritestr(f, "{}\n") )
2985         RET_ONERROR( mywritestr(f, "}\n") )
2986         RET_ONERROR( mywritestr(f, "\n") )
2987 
2988         RET_ONERROR( mywritestr(f, "class ") )
2989         RET_ONERROR( mywritestr(f, TheApp->getCPrefix()) )
2990         RET_ONERROR( mywritestr(f, "CreateNormalsCallback {\n") )
2991         RET_ONERROR( mywritestr(f, "   public void createNormals(") )
2992         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
2993         RET_ONERROR( mywritestr(f, " node, Object data) {}\n") )
2994         RET_ONERROR( mywritestr(f, "}\n") )
2995 
2996         RET_ONERROR( mywritestr(f, "class ") )
2997         RET_ONERROR( mywritestr(f, TheApp->getCPrefix()) )
2998         RET_ONERROR( mywritestr(f, "ProcessEventCallback {\n") )
2999         RET_ONERROR( mywritestr(f, "   public boolean processEvent(") )
3000         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
3001         RET_ONERROR( mywritestr(f, " node, ") )
3002         RET_ONERROR( mywritestr(f, "String") )
3003         RET_ONERROR( mywritestr(f, " event) ") )
3004         RET_ONERROR( mywritestr(f, "{ return false;}\n") )
3005         RET_ONERROR( mywritestr(f, "}\n") )
3006 
3007         RET_ONERROR( mywritestr(f, "\n\n") )
3008     }
3009     RET_ONERROR( writeCDeclaration(f, languageFlag) )
3010     RET_ONERROR( mywritestr(f, "\n") )
3011 
3012     int numDataFunctions = 0;
3013     MyArray<int> startFunctions;
3014     MyArray<int> numFunctionsPerClass;
3015 
3016     zeroNumDataFunctions();
3017     setStartNumDataFunctions(0);
3018 
3019     WriteData data;
3020     data.filedes = f;
3021     data.languageFlag = languageFlag;
3022 
3023     if (languageFlag & MANY_JAVA_CLASSES) {
3024         struct WriteCStruct cWrite;
3025         cWrite.filedes = f;
3026         cWrite.ret = 0;
3027         cWrite.languageFlag = languageFlag;
3028         cWrite.outsideJavaClass = true;
3029         cWrite.writeBracket = true;
3030 
3031         getNodes()->clearFlag(NODE_FLAG_TOUCHED); // to handle DEF/USE
3032         m_root->doWithBranch(writeCNodeData, &cWrite);
3033         if (cWrite.ret !=0)
3034             return -1;
3035         RET_ONERROR( mywritestr(f, "\n") )
3036 
3037         if (m_root->writeC(f, languageFlag | OUTSIDE_JAVA_CLASS))
3038             return -1;
3039 
3040         getNodes()->clearFlag(NODE_FLAG_TOUCHED); // to handle DEF/USE
3041 
3042         if (m_root->writeCDataAsFunctions(f, languageFlag))
3043             return -1;
3044 
3045         if (languageFlag & MANY_JAVA_CLASSES) {
3046             RET_ONERROR( mywritef(f, "class %sScenegraphFunctions%d {\n",
3047                                   TheApp->getCPrefix(), getNumDataClasses()) )
3048             RET_ONERROR( mywritef(f, "    static void data%sFunction0() {",
3049                                   TheApp->getCPrefix()) )
3050         }
3051 
3052         m_root->doWithBranch(writeCSetWrittenFalse, NULL);
3053 
3054         m_root->doWithBranch(writeCCoordinateFirst, &data,
3055                              true, false, false, true, false, true);
3056         numFunctionsPerClass.append(getNumDataFunctions());
3057         setNumDataFunctionsPerClass(getNumDataFunctions());
3058         setStartNumDataFunctions(numDataFunctions);
3059         startFunctions.append(numDataFunctions);
3060         numDataFunctions += getNumDataFunctions();
3061         RET_ONERROR( writeCDataFunctionsCalls(f, languageFlag) )
3062         RET_ONERROR( mywritestr(f, "\n") )
3063 
3064         m_root->doWithBranch(writeCIndexedFaceSetFirst, &data,
3065                              true, false, false, true, false, true);
3066         numFunctionsPerClass.append(getNumDataFunctions());
3067         setNumDataFunctionsPerClass(getNumDataFunctions());
3068         startFunctions.append(numDataFunctions);
3069         setStartNumDataFunctions(numDataFunctions);
3070         numDataFunctions += getNumDataFunctions();
3071         RET_ONERROR( writeCDataFunctionsCalls(f, languageFlag) )
3072         RET_ONERROR( mywritestr(f, "\n") )
3073         m_root->doWithBranch(writeCShapeFirst, &data);
3074         numFunctionsPerClass.append(getNumDataFunctions());
3075 
3076         setStartNumDataFunctions(getNumDataFunctions());
3077         setNumDataFunctionsPerClass(getNumDataFunctions());
3078         startFunctions.append(numDataFunctions);
3079         setStartNumDataFunctions(numDataFunctions);
3080         numDataFunctions += getNumDataFunctions();
3081         RET_ONERROR( writeCDataFunctionsCalls(f, languageFlag) )
3082         RET_ONERROR( mywritestr(f, "\n") )
3083 
3084         m_root->doWithBranch(writeCHAnimJointFirst, &data,
3085                              true, false, false, true, false, true);
3086         numFunctionsPerClass.append(getNumDataFunctions());
3087         setNumDataFunctionsPerClass(getNumDataFunctions());
3088         setStartNumDataFunctions(numDataFunctions);
3089         startFunctions.append(numDataFunctions);
3090         numDataFunctions += getNumDataFunctions();
3091         RET_ONERROR( writeCDataFunctionsCalls(f, languageFlag) )
3092         RET_ONERROR( mywritestr(f, "    }\n") )
3093         RET_ONERROR( mywritestr(f, "}\n") )
3094         RET_ONERROR( mywritestr(f, "\n") )
3095     }
3096 
3097     WriteCDynamicNodeData parameters;
3098     parameters.result = 0;
3099     parameters.filedes = f;
3100     parameters.languageFlag = languageFlag;
3101     m_root->doWithBranch(writeCDynamicNodeCallback, &parameters);
3102     if (parameters.result != 0)
3103         return -1;
3104 
3105     if (languageFlag & C_SOURCE)
3106         RET_ONERROR( mywritestr(f, "struct ") )
3107     else
3108         RET_ONERROR( mywritestr(f, "class ") )
3109     RET_ONERROR( mywritestr(f, TheApp->getCSceneGraphName()) )
3110     RET_ONERROR( mywritestr(f, " {\n") )
3111     if (languageFlag & CC_SOURCE)
3112         RET_ONERROR( mywritestr(f, "public:\n") )
3113     struct WriteCStruct cWrite;
3114     cWrite.filedes = f;
3115     cWrite.ret = 0;
3116     cWrite.languageFlag = languageFlag;
3117     cWrite.outsideJavaClass = false;
3118     cWrite.writeBracket = true;
3119     getNodes()->clearFlag(NODE_FLAG_TOUCHED); // to handle DEF/USE
3120     variableNames.resize(0);;
3121     m_root->doWithBranch(writeCNodeData, &cWrite);
3122     if (cWrite.ret !=0)
3123         return -1;
3124 
3125     if (languageFlag & C_SOURCE) {
3126         RET_ONERROR( mywritestr(f, "};\n\n") )
3127 
3128         RET_ONERROR( mywritestr(f, "struct ") )
3129         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
3130         RET_ONERROR( mywritestr(f, "Struct {\n") )
3131         RET_ONERROR( mywritestr(f, "    ") )
3132         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
3133         RET_ONERROR( mywritestr(f, " *m_parent;\n") )
3134         RET_ONERROR( mywritestr(f, "    ") )
3135         RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
3136         RET_ONERROR( mywritestr(f, " *m_protoRoot;\n") )
3137         RET_ONERROR( mywritestr(f, "    int m_type;\n") )
3138         RET_ONERROR( mywritestr(f, "    void *m_data;\n") )
3139         RET_ONERROR( mywritestr(f, "};\n\n") )
3140 
3141         RET_ONERROR( mywritestr(f, "void ") )
3142         RET_ONERROR( mywritestr(f, TheApp->getCSceneGraphName()) )
3143         RET_ONERROR( mywritestr(f, "Init(") )
3144         RET_ONERROR( mywritestr(f, "struct ") )
3145         RET_ONERROR( mywritestr(f, TheApp->getCSceneGraphName()) )
3146         RET_ONERROR( mywritestr(f, " *self) {\n") )
3147         if (m_root->writeC(f, languageFlag))
3148             return -1;
3149         parameters.result = 0;
3150         parameters.filedes = f;
3151         parameters.languageFlag = languageFlag;
3152         m_root->doWithBranch(writeCInstallDynamicNodeCallback, &parameters);
3153         if (parameters.result != 0)
3154             return -1;
3155         RET_ONERROR( mywritestr(f, "    }\n\n") )
3156         RET_ONERROR( mywritestr(f, "}\n\n") )
3157         RET_ONERROR( writeCTreeCallback(f, "Render") )
3158         RET_ONERROR( mywritestr(f, "\n") )
3159         RET_ONERROR( writeCTreeCallback(f, "DoWithData") )
3160         RET_ONERROR( mywritestr(f, "\n") )
3161 
3162         RET_ONERROR( mywritef(f, "%s%s *", TheApp->getCPrefix(), "Node") )
3163         RET_ONERROR( mywritef(f, "%sGetNodeFromGlName(", TheApp->getCPrefix()) )
3164         RET_ONERROR( mywritef(f, "struct %sSceneGraph *self, int glName) {\n",
3165                               TheApp->getCPrefix()) )
3166         RET_ONERROR( mywritestr(f, "    switch (glName) {\n") )
3167         for (long i = 0; i < m_glNameData.size(); i++) {
3168             RET_ONERROR( mywritef(f, "       case %d:\n",
3169                                  m_glNameData[i].glName) )
3170             RET_ONERROR( mywritestr(f, "         return ") )
3171             RET_ONERROR( mywritef(f, "&self->%s;\n", (const char *)
3172                                                m_glNameData[i].nodeName) )
3173         }
3174         RET_ONERROR( mywritestr(f, "    }\n") )
3175         RET_ONERROR( mywritestr(f, "    return NULL;\n") )
3176         RET_ONERROR( mywritestr(f, "}\n") )
3177 
3178         for (int i = 0; i < LAST_TYPE; i++) {
3179             FieldValue *value = typeDefaultValue(i);
3180             value->writeCSendEventFunction(f, languageFlag);
3181         }
3182     }
3183     getNodes()->clearFlag(NODE_FLAG_TOUCHED); // to handle DEF/USE
3184     if (languageFlag & CC_SOURCE) {
3185         RET_ONERROR( mywritestr(f, "public:\n") )
3186         RET_ONERROR( mywritestr(f, "    ") )
3187         RET_ONERROR( mywritestr(f, TheApp->getCSceneGraphName()) )
3188         RET_ONERROR( mywritestr(f, "();\n") )
3189 
3190         RET_ONERROR( mywritestr(f, "    ") )
3191         RET_ONERROR( mywritestr(f, "void render(void *data) ") )
3192         RET_ONERROR( mywritestr(f, "{ root.treeRender(data); }\n") )
3193 
3194         RET_ONERROR( mywritestr(f, "    ") )
3195         RET_ONERROR( mywritestr(f, "void doWithData(void *data) ") )
3196         RET_ONERROR( mywritestr(f, "{ root.treeDoWithData(data); }\n") )
3197 
3198         RET_ONERROR( mywritestr(f, "    ") )
3199         RET_ONERROR( mywritef(f, "%sNode *", TheApp->getCPrefix()) )
3200         RET_ONERROR( mywritestr(f, "getNodeFromGlName(int glName);\n") )
3201         RET_ONERROR( mywritestr(f, "};\n\n") )
3202 
3203         RET_ONERROR( mywritestr(f, TheApp->getCSceneGraphName()) )
3204         RET_ONERROR( mywritestr(f, "::") )
3205         RET_ONERROR( mywritestr(f, TheApp->getCSceneGraphName()) )
3206         RET_ONERROR( mywritestr(f, "() {\n") )
3207         if (m_root->writeC(f, languageFlag))
3208             return -1;
3209         parameters.result = 0;
3210         parameters.filedes = f;
3211         parameters.languageFlag = languageFlag;
3212         m_root->doWithBranch(writeCInstallDynamicNodeCallback, &parameters);
3213         if (parameters.result != 0)
3214             return -1;
3215 
3216         RET_ONERROR( mywritestr(f, "}\n") )
3217 
3218         RET_ONERROR( mywritef(f, "%s%s *", TheApp->getCPrefix(), "Node") )
3219         RET_ONERROR( mywritef(f, "%s::",TheApp->getCSceneGraphName()) )
3220         RET_ONERROR( mywritef(f, "getNodeFromGlName(int glName) {\n") )
3221         RET_ONERROR( mywritestr(f, "    switch (glName) {\n") )
3222         for (long i = 0; i < m_glNameData.size(); i++) {
3223             RET_ONERROR( mywritef(f, "       case %d:\n",
3224                                   m_glNameData[i].glName) )
3225             RET_ONERROR( mywritestr(f, "         return ") )
3226             RET_ONERROR( mywritef(f, "&%s;\n", (const char *)
3227                                                m_glNameData[i].nodeName) )
3228         }
3229         RET_ONERROR( mywritestr(f, "    }\n") )
3230         RET_ONERROR( mywritestr(f, "    return NULL;\n") )
3231         RET_ONERROR( mywritestr(f, "}\n") )
3232 
3233         for (int i = 0; i < LAST_TYPE; i++) {
3234             FieldValue *value = typeDefaultValue(i);
3235             value->writeCSendEventFunction(f, languageFlag);
3236         }
3237     } else if (languageFlag & JAVA_SOURCE) {
3238         if (!(languageFlag & MANY_JAVA_CLASSES)) {
3239 
3240             if (m_root->writeCDataAsFunctions(f, languageFlag, true))
3241                 return -1;
3242 
3243             numFunctionsPerClass.append(getNumDataFunctions());
3244             setNumDataFunctionsPerClass(getNumDataFunctions());
3245             setStartNumDataFunctions(numDataFunctions);
3246             startFunctions.append(numDataFunctions);
3247             numDataFunctions += getNumDataFunctions();
3248 
3249             RET_ONERROR(writeCDataFunctionsCalls(f, languageFlag) )
3250 
3251             RET_ONERROR( mywritestr(f, "    }\n") )
3252         }
3253 
3254         RET_ONERROR( mywritestr(f, "    ") )
3255         RET_ONERROR( mywritestr(f, "public static boolean initThings = true;\n"))
3256         RET_ONERROR( mywritestr(f, "    ") )
3257         RET_ONERROR( mywritestr(f, TheApp->getCSceneGraphName()) )
3258         RET_ONERROR( mywritestr(f, "() {\n") )
3259 
3260         if (m_root->writeC(f, languageFlag))
3261             return -1;
3262         for (int j = 0; j < getNumDataClasses(); j++) {
3263             for (int i = 0; i < 1; i++) {
3264                 if (j == getNumDataClasses() - 1) {
3265                     RET_ONERROR( mywritestr(f, "        if (initThings)\n") )
3266                     RET_ONERROR( mywritestr(f, "    ") )
3267                     RET_ONERROR( mywritestr(f, "        ") )
3268                     if (languageFlag & MANY_JAVA_CLASSES)
3269                         RET_ONERROR( mywritef(f, "%sScenegraphFunctions%d.",
3270                                           TheApp->getCPrefix(), 0) )
3271                     RET_ONERROR( mywritef(f, "data%sFunction%d();\n",
3272                                           TheApp->getCPrefix(), 0) )
3273                 }
3274                 if (j == 2) {
3275                     RET_ONERROR( mywritestr(f, "        if (initThings)\n") )
3276                     RET_ONERROR( mywritestr(f, "    ") )
3277                 }
3278 
3279                 RET_ONERROR( mywritestr(f, "        ") )
3280                 if (languageFlag & MANY_JAVA_CLASSES)
3281                     RET_ONERROR( mywritef(f, "Data%sFunctionClass_%d.",
3282                                           TheApp->getCPrefix(), j) )
3283                 RET_ONERROR( mywritef(f, "data%sFunction%d();\n",
3284                                           TheApp->getCPrefix(), j) )
3285 
3286                 if (j == getNumDataClasses() - 1)
3287                     if (languageFlag & MANY_JAVA_CLASSES) {
3288                         RET_ONERROR(m_root->writeCDataFunction(f, languageFlag,
3289                                     true, true) )
3290                     }
3291             }
3292         }
3293         RET_ONERROR( mywritestr(f, "        setParents();\n") )
3294 
3295         RET_ONERROR( mywritestr(f , "    }\n") )
3296 
3297         parameters.result = 0;
3298         parameters.filedes = f;
3299         parameters.languageFlag = languageFlag;
3300         m_root->doWithBranch(writeCInstallDynamicNodeCallback, &parameters);
3301         if (parameters.result != 0)
3302             return -1;
3303 
3304         RET_ONERROR( mywritestr(f, "    ") )
3305         if (languageFlag & MANY_JAVA_CLASSES)
3306             RET_ONERROR( mywritestr(f, "static ") )
3307         RET_ONERROR( mywritestr(f, "void render() ") )
3308         RET_ONERROR( mywritestr(f, "{ root.treeRender(null, null); }\n") )
3309         RET_ONERROR( mywritestr(f, "    ") )
3310         if (languageFlag & MANY_JAVA_CLASSES)
3311             RET_ONERROR( mywritestr(f, "static ") )
3312         RET_ONERROR( mywritestr(f, "void doWithData() ") )
3313         RET_ONERROR( mywritestr(f, "{ root.treeDoWithData(null); }\n") )
3314 
3315         RET_ONERROR( mywritef(f, "    static %s%s ",
3316                                  TheApp->getCPrefix(), "Node") )
3317         RET_ONERROR( mywritef(f, "getNodeFromGlName(") )
3318         RET_ONERROR( mywritef(f, "int glName) {\n") )
3319         RET_ONERROR( mywritestr(f, "        switch (glName) {\n") )
3320         for (long i = 0; i < m_glNameData.size(); i++) {
3321             RET_ONERROR( mywritef(f, "           case %d:\n",
3322                                   m_glNameData[i].glName) )
3323             RET_ONERROR( mywritestr(f, "             return ") )
3324             MyString className = "";
3325 /*
3326             if (m_glNameData[i].node->hasName())
3327                 className += TheApp->getCSceneGraphName();
3328             else {
3329 */
3330                 className += TheApp->getCPrefix();
3331                 className += m_glNameData[i].nodeName;
3332 //            }
3333             RET_ONERROR( mywritef(f, "%s.%s;\n",
3334                                      (const char *)className,
3335                                      (const char *)m_glNameData[i].nodeName
3336                                  ) )
3337         }
3338         RET_ONERROR( mywritef(f, "        }\n") )
3339         RET_ONERROR( mywritef(f, "    return null;\n") )
3340         RET_ONERROR( mywritef(f, "    }\n") )
3341 
3342         RET_ONERROR( mywritestr(f, "    public void setParents() {\n") )
3343         parameters.result = 0;
3344         parameters.filedes = f;
3345         parameters.languageFlag = languageFlag;
3346         m_root->doWithBranch(writeCParentCallback, &parameters);
3347         if (parameters.result != 0)
3348             return -1;
3349         RET_ONERROR( mywritestr(f, "    }\n") )
3350 
3351         for (int i = 0; i < LAST_TYPE; i++) {
3352             FieldValue *value = typeDefaultValue(i);
3353             value->writeCSendEventFunction(f, languageFlag);
3354         }
3355     }
3356 
3357     if (languageFlag & JAVA_SOURCE) {
3358         RET_ONERROR( mywritestr(f, "\n") )
3359         RET_ONERROR( mywritestr(f, "    void ") )
3360         RET_ONERROR( mywritestr(f, TheApp->getCPrefix()) )
3361         RET_ONERROR( mywritestr(f, "ShowError(Exception e) {\n") )
3362         RET_ONERROR( mywritestr(f, "        StackTraceElement stack[] = e.getStackTrace();\n") )
3363         RET_ONERROR( mywritestr(f, "        ") )
3364         if (TheApp->isWonderlandModuleExport()) {
3365             RET_ONERROR( mywritestr(f, TheApp->getCPrefix()) )
3366             RET_ONERROR( mywritestr(f, "_Util.logger.warning") )
3367         } else
3368             RET_ONERROR( mywritestr(f, "java.lang.System.err.print") )
3369         RET_ONERROR( mywritestr(f, "(\"\\n\" + e.getMessage() + \"\\n\");\n") )
3370         RET_ONERROR( mywritestr(f, "        for (int i = 0; i < stack.length; i++)\n") )
3371         RET_ONERROR( mywritestr(f, "            ") )
3372         if (TheApp->isWonderlandModuleExport()) {
3373             RET_ONERROR( mywritestr(f, TheApp->getCPrefix()) )
3374             RET_ONERROR( mywritestr(f, "_Util.logger.warning") )
3375         } else
3376             RET_ONERROR( mywritestr(f, "java.lang.System.err.print") )
3377         RET_ONERROR( mywritestr(f, "(stack[i].toString() + \"\\n\");\n") )
3378         RET_ONERROR( mywritestr(f, "    }\n") )
3379     }
3380     RET_ONERROR( writeCRoutes(f, languageFlag) )
3381     if (languageFlag & JAVA_SOURCE)
3382         RET_ONERROR( mywritestr(f, "};\n\n") )
3383     return(0);
3384 }
3385 
3386 int
writeCTreeCallback(int f,const char * functionName,bool callTreeCallback)3387 Scene::writeCTreeCallback(int f, const char *functionName,
3388                           bool callTreeCallback)
3389 {
3390     RET_ONERROR( mywritestr(f, "void ") )
3391     RET_ONERROR( mywritestr(f, TheApp->getCPrefix()) )
3392     RET_ONERROR( mywritestr(f, "Tree") )
3393     RET_ONERROR( mywritestr(f, functionName) )
3394     if (callTreeCallback)
3395         RET_ONERROR( mywritestr(f, "Callback") )
3396     RET_ONERROR( mywritestr(f, "(struct ") )
3397     RET_ONERROR( mywritestr(f, TheApp->getCNodeName()) )
3398     RET_ONERROR( mywritestr(f, "Struct *node,") )
3399     RET_ONERROR( mywritestr(f, " void *data) {\n") )
3400     RET_ONERROR( mywritestr(f, "    switch(node->") )
3401     RET_ONERROR( mywritestr(f, "m_type) {\n") )
3402     ProtoMap::Chain::Iterator *j;
3403     for (int i = 0; i < m_protos.width(); i++)
3404         for (j = m_protos.chain(i).first(); j != NULL; j = j->next()) {
3405             Proto *proto = j->item()->getData();
3406             if (proto == NULL)
3407                 continue;
3408             if ((proto->getType() != VRML_INDEXED_FACE_SET) &&
3409                 (!(proto->isInScene())))
3410                 continue;
3411             if (proto->getType() == VRML_COMMENT)
3412                 continue;
3413             if (proto->isMesh() &&
3414                 !(proto->isExportTargetMesh()))
3415                 continue;
3416             if (proto->isMismatchingProto())
3417                 continue;
3418             RET_ONERROR( mywritestr(f, "      case ") )
3419             if (proto->getNumNodes() > 0)
3420                 RET_ONERROR( mywritef(f, "%d", getProtoType(proto)) )
3421             else
3422                 RET_ONERROR( mywritef(f, "%d", proto->getType()) )
3423             RET_ONERROR( mywritestr(f, ":\n") )
3424             if (callTreeCallback) {
3425                 RET_ONERROR( mywritestr(f, "        if (") )
3426                 RET_ONERROR( mywritestr(f, proto->getClassName()) )
3427                 RET_ONERROR( mywritestr(f, "Tree") )
3428                 RET_ONERROR( mywritestr(f, functionName) )
3429                 RET_ONERROR( mywritestr(f, "Callback)\n") )
3430                 RET_ONERROR( mywritestr(f, "            ") )
3431                 RET_ONERROR( mywritestr(f, proto->getClassName()) )
3432                 RET_ONERROR( mywritestr(f, "Tree") )
3433                 RET_ONERROR( mywritestr(f, functionName) )
3434                 RET_ONERROR( mywritestr(f, "Callback(node, data);\n") )
3435                 RET_ONERROR( mywritestr(f, "        else\n") )
3436                 RET_ONERROR( mywritestr(f, "    ") )
3437             }
3438             RET_ONERROR( mywritestr(f, "        ") )
3439             RET_ONERROR( mywritestr(f, proto->getClassName()) )
3440             RET_ONERROR( mywritestr(f, "Tree") )
3441             RET_ONERROR( mywritestr(f, functionName) )
3442             RET_ONERROR( mywritestr(f, "(node, data);\n") )
3443             RET_ONERROR( mywritestr(f, "        break;\n") )
3444         }
3445     RET_ONERROR( mywritestr(f, "    }\n") )
3446     RET_ONERROR( mywritestr(f, "}\n") )
3447     return 0;
3448 }
3449 
3450 class WriteCFunctionCallData {
3451 public:
3452     int filedes;
3453     int languageFlag;
3454     int returnValue;
3455 };
3456 
searchNodesOnlyOutputAndWriteCRoutes(Node * node,void * data)3457 static bool searchNodesOnlyOutputAndWriteCRoutes(Node *node, void *data)
3458 {
3459     WriteCFunctionCallData *cdata = (WriteCFunctionCallData *)data;
3460     if (node->hasOutputs() && !(node->hasInputs())) {
3461         if (node->writeCAndFollowRoutes(cdata->filedes, 0, cdata->languageFlag,
3462                                         false, "") != 0) {
3463             cdata->returnValue = -1;
3464             return false;
3465         }
3466     }
3467     return true;
3468 }
3469 
3470 int
writeCRoutes(int filedes,int languageFlag)3471 Scene::writeCRoutes(int filedes, int languageFlag)
3472 {
3473     static bool alreadyIn = false;
3474     if (alreadyIn)
3475         return 0;
3476     alreadyIn = true;
3477     // write tempory nodes first
3478     for (long i = 0; i < m_delayedWriteNodes.size(); i++) {
3479         int ret = m_delayedWriteNodes[i]->writeC(filedes, languageFlag);
3480         if (ret < 0) {
3481             alreadyIn = false;
3482             return ret;
3483         }
3484         removeNode(m_delayedWriteNodes[i]);
3485     }
3486     if (m_delayedWriteNodes.size() > 0)
3487         m_delayedWriteNodes.resize(0);
3488     alreadyIn = false;
3489 
3490     if (languageFlag & JAVA_SOURCE)
3491         RET_ONERROR( mywritestr(filedes, "    ") )
3492     RET_ONERROR( mywritestr(filedes, "void ") )
3493     RET_ONERROR( mywritestr(filedes, TheApp->getCProcessEventsName()) )
3494     RET_ONERROR( mywritestr(filedes, "(") )
3495     if (languageFlag & C_SOURCE)
3496         RET_ONERROR( mywritestr(filedes, "struct ") )
3497     if (languageFlag & (C_SOURCE | CC_SOURCE)) {
3498         RET_ONERROR( mywritestr(filedes, TheApp->getCSceneGraphName()) )
3499         RET_ONERROR( mywritestr(filedes, " *self, void *data") )
3500     }
3501 
3502     RET_ONERROR( mywritestr(filedes, ") {\n") )
3503 
3504     if (languageFlag & JAVA_SOURCE) {
3505         RET_ONERROR( indentf(filedes, 8) )
3506         RET_ONERROR( mywritestr(filedes, "boolean nextEvent = false;\n") )
3507     } else {
3508         RET_ONERROR( indentf(filedes, 4) )
3509         RET_ONERROR( mywritestr(filedes, "int nextEvent = 0;\n") )
3510     }
3511 
3512     WriteCFunctionCallData cdata;
3513     cdata.filedes = filedes;
3514     cdata.languageFlag = languageFlag;
3515     cdata.returnValue = 0;
3516     m_root->doWithBranch(searchNodesOnlyOutputAndWriteCRoutes, &cdata);
3517     for (long i = 0; i < m_sensorNodes.size(); i++) {
3518         if (languageFlag & JAVA_SOURCE)
3519             RET_ONERROR( mywritestr(filedes, "    ") )
3520         RET_ONERROR( mywritestr(filedes, "    ") )
3521         MyString className = "";
3522         if (languageFlag & JAVA_SOURCE) {
3523             if (m_sensorNodes[i]->hasName())
3524                 className += TheApp->getCSceneGraphName();
3525             else {
3526                 className += TheApp->getCPrefix();
3527                 className += m_sensorNodes[i]->getVariableName();
3528             }
3529             RET_ONERROR( mywritestr(filedes, "Extra.") )
3530         }
3531         RET_ONERROR( mywritestr(filedes, "reInitSensor(") )
3532         if (languageFlag & JAVA_SOURCE) {
3533             RET_ONERROR( mywritef(filedes, "X3d%s.",
3534                                   m_sensorNodes[i]->getVariableName()) )
3535         } else
3536             RET_ONERROR( mywritestr(filedes, "&(self->") )
3537         RET_ONERROR( mywritestr(filedes, m_sensorNodes[i]->getVariableName()) )
3538         if (!(languageFlag & JAVA_SOURCE))
3539             RET_ONERROR( mywritestr(filedes, ")") )
3540         RET_ONERROR( mywritestr(filedes, ");\n") )
3541     }
3542     removeSensorNodes();
3543     if (languageFlag & JAVA_SOURCE)
3544         RET_ONERROR( mywritestr(filedes, "    ") )
3545     RET_ONERROR( mywritestr(filedes, "}\n") )
3546     return cdata.returnValue;
3547 
3548     return 0;
3549 }
3550 
searchExtensionProto(int extension,Node * node,void * data)3551 static bool searchExtensionProto(int extension, Node *node, void *data)
3552 {
3553     MyArray<Proto *> *protoArrayPtr = (MyArray<Proto *> *) data;
3554     if (!node->hasDefault(extension) /* && !node->hasRoute(extension)*/) {
3555         for (long i = 0; i < (*protoArrayPtr).size(); i++)
3556             if ((*protoArrayPtr)[i] == node->getProto())
3557                 return true;
3558         (*protoArrayPtr).append(node->getProto());
3559     }
3560     // Todo: also check if Route to extension event
3561     return true;
3562 }
3563 
searchCoverExtensionProto(Node * node,void * data)3564 static bool searchCoverExtensionProto(Node *node, void *data)
3565 {
3566     return searchExtensionProto(FF_COVER_ONLY, node, data);
3567 }
3568 
searchKambiExtensionProto(Node * node,void * data)3569 static bool searchKambiExtensionProto(Node *node, void *data)
3570 {
3571     return searchExtensionProto(FF_KAMBI_ONLY, node, data);
3572 }
3573 
3574 int
writeExtensionProtos(int f,int flag)3575 Scene::writeExtensionProtos(int f, int flag)
3576 {
3577     int x3d = false;
3578     if (flag == FF_X3D_ONLY)
3579         x3d = true;
3580     MyArray<Proto *> protoArray;
3581     NodeList *nodes = ((NodeGroup *)getRoot())->children()->getValues();
3582     for (long i = 0; i < nodes->size(); i++) {
3583         if (flag == FF_COVER_ONLY)
3584             nodes->get(i)->doWithBranch(searchCoverExtensionProto,
3585                                         &protoArray, false);
3586         if (flag == FF_KAMBI_ONLY)
3587             nodes->get(i)->doWithBranch(searchKambiExtensionProto,
3588                                         &protoArray, false);
3589     }
3590     for (long i = 0; i < protoArray.size(); i++) {
3591         addProtoName(protoArray[i]->getName(false));
3592         Proto *newProto = new Proto(this, protoArray[i], flag);
3593         if (newProto->write(f, 0, x3d) != 0) {
3594             deleteExtensionProtos();
3595             return -1;
3596         }
3597         if (mywritestr(f, "\n") != 0) {
3598             deleteExtensionProtos();
3599             return -1;
3600         }
3601 
3602         m_writtenExtensionProtos.append(newProto);
3603     }
3604     return 0;
3605 }
3606 
3607 void
deleteExtensionProtos(void)3608 Scene::deleteExtensionProtos(void)
3609 {
3610     for (long i = 0; i < m_writtenExtensionProtos.size(); i++) {
3611         deleteProtoName(m_writtenExtensionProtos[i]->getName(false));
3612         deleteProto(m_writtenExtensionProtos[i]->getName(false));
3613         delete(m_writtenExtensionProtos[i]);
3614     }
3615     m_writtenExtensionProtos.resize(0);
3616 }
3617 
3618 Proto *
getExtensionProto(Proto * proto)3619 Scene::getExtensionProto(Proto *proto)
3620 {
3621     for (long i = 0; i < m_writtenExtensionProtos.size(); i++)
3622         if (m_writtenExtensionProtos[i]->getNode(0)->getProto() == proto)
3623             return m_writtenExtensionProtos[i];
3624     return NULL;
3625 }
3626 
3627 
3628 void
addProto(MyString name,Proto * value)3629 Scene::addProto(MyString name, Proto *value)
3630 {
3631     if (belongsToNodeWithExternProto(name))
3632        return;
3633     Proto *proto = m_protos[name];
3634     if (proto && proto->isX3dInternalProto())
3635         return;
3636     m_protos[name] = value;
3637 }
3638 
deleteProto(MyString name)3639 void Scene::deleteProto(MyString name)
3640 {
3641     if (m_protos.hasKey(name)) {
3642         m_protos.remove(name);
3643         deleteProtoName(name);
3644     }
3645 }
3646 
3647 Proto *
getProto(MyString name)3648 Scene::getProto(MyString name)
3649 {
3650     return m_protos[name];
3651 }
3652 
3653 Proto *
getExtensionProto(MyString name)3654 Scene::getExtensionProto(MyString name)
3655 {
3656     Proto *proto = NULL;
3657     MyString protoName = name;
3658     // TODO: handle X3D node names like the following in a better way
3659     if ((strcmp(protoName, "NurbsPatchSurface") == 0) ||
3660         (getStoreAsHtml() &&
3661         (strcasecmp(protoName, "NurbsPatchSurface") == 0))) {
3662         protoName = "";
3663         protoName += "NurbsSurface";
3664     }
3665     if (m_protos.hasKey(protoName))
3666         proto = m_protos[protoName];
3667     else if (getStoreAsHtml()) {
3668         // X3DOM users tend to use low case namenames
3669         ProtoMap::Chain::Iterator *j;
3670         for (int i = 0; i < m_protos.width(); i++)
3671             for (j = m_protos.chain(i).first(); j != NULL; j = j->next())
3672                 if (strcasecmp(j->item()->getKey(), protoName) == 0) {
3673                     proto =  m_protos[j->item()->getKey()];
3674                     break;
3675                 }
3676         if (proto == NULL)
3677             return NULL;
3678     } else
3679         return NULL;
3680     if (TheApp->getCoverMode() && proto->isExtensionProto(FF_COVER_ONLY)) {
3681         proto = proto->getNode(0)->getProto();
3682         proto->setScene(this);
3683     }
3684     if (TheApp->getKambiMode() && proto->isExtensionProto(FF_KAMBI_ONLY)) {
3685         proto = proto->getNode(0)->getProto();
3686         proto->setScene(this);
3687     }
3688     if (TheApp->getX3domMode() && proto->isExtensionProto(FF_X3DOM_ONLY)) {
3689         proto = proto->getNode(0)->getProto();
3690         proto->setScene(this);
3691     }
3692     return proto;
3693 }
3694 
3695 bool
validRoute(Node * src,int eventOut,Node * dst,int eventIn)3696 Scene::validRoute(Node *src, int eventOut, Node *dst, int eventIn)
3697 {
3698     if ((src == NULL) || (dst == NULL))
3699         return false;
3700 
3701     bool onlyOneConnectAnything = false;
3702     // "connect anything" route of Script/ShaderNode (eventOut will be created)
3703     if (src->isNodeWithAdditionalEvents())
3704         if (eventOut == src->getProto()->getNumEventOuts())
3705             onlyOneConnectAnything = true;
3706 
3707     // "connect anything" route of Script/ShaderNode (eventIn will be created)
3708     if (dst->isNodeWithAdditionalEvents())
3709         if (eventIn == dst->getProto()->getNumEventIns()) {
3710             if (onlyOneConnectAnything)
3711                 onlyOneConnectAnything = false;
3712             else
3713                 onlyOneConnectAnything = true;
3714         }
3715 
3716     if (onlyOneConnectAnything)
3717         return true;
3718 
3719     if (eventOut < 0 || eventOut >= src->getProto()->getNumEventOuts())
3720         return false;
3721 
3722     if (eventIn < 0 || eventIn >= dst->getProto()->getNumEventIns())
3723         return false;
3724 
3725     if (src->getProto()->getEventOut(eventOut)->getType() !=
3726         dst->getProto()->getEventIn(eventIn)->getType())
3727         return false;
3728 
3729     return true;
3730 }
3731 
3732 bool
addRoute(Node * src,int eventOut,Node * dst,int eventIn,SceneView * sender)3733 Scene::addRoute(Node *src, int eventOut, Node *dst, int eventIn,
3734                 SceneView *sender)
3735 {
3736     if (eventIn == -1)
3737         return true;
3738     bool x3d = isX3d();
3739 
3740     RouteUpdate hint(src, eventOut, dst, eventIn);
3741 
3742     src->addOutput(eventOut, dst, eventIn);
3743     dst->addInput(eventIn, src, eventOut);
3744 
3745     bool ret = true;
3746     if (!validRoute(src, eventOut, dst, eventIn))
3747         ret = false;
3748     Proto *srcProto = src->getProto();
3749     if ((eventOut != srcProto->getNumEventOuts()) &&
3750         (isInvalidElement(srcProto->getEventOut(eventOut))))
3751         ret = false;
3752     Proto *dstProto = dst->getProto();
3753     if (isInvalidElement(dstProto->getEventIn(eventIn)))
3754         ret = false;
3755     if (!ret) {
3756         swDebugf("invalid ROUTE %s.%s To %s.%s\n",
3757                  (const char *)src->getProto()->getName(x3d),
3758                  (const char *)src->getProto()->getEventOut(eventOut)->getName(x3d),
3759                  (const char *)dst->getProto()->getName(x3d),
3760                  (const char *)dst->getProto()->getEventIn(eventIn)->getName(x3d));
3761         return false;
3762     }
3763 
3764     // try to copy a exposedField value or field of a eventIn
3765     // to the first value of a Interpolator
3766 
3767     int field = -1;
3768     bool isFlag = false;
3769 
3770     // is this dst field an ExposedField?
3771     ExposedField *e = dst->getProto()->getEventIn(eventIn)->getExposedField();
3772     if (e) {
3773         field = e->getFieldIndex();
3774         isFlag = e->getFlags() & FF_IS;
3775     } else {
3776         // is this dst field an EventIn connected to a Field ?
3777         field = dst->getProto()->getEventIn(eventIn)->getField();
3778         isFlag = dst->getProto()->getEventIn(eventIn)->getFlags() & FF_IS;
3779     }
3780     if ((field != -1) && (!isFlag)) {
3781         Interpolator *interp = findUpstreamInterpolator(dst, field);
3782         if (interp && !((Node *)interp)->isPROTO()) {
3783             bool setValue = false;
3784             if (interp->getNumKeys() == 0)
3785                 setValue = true;
3786             if (interp->getNumKeys() == 1)
3787                 if (interp->getKey(0) == 0.0f)
3788                     setValue = true;
3789             if (setValue) {
3790                 FieldValue *value = dst->getField(field);
3791                 if (value)
3792                     interp->recordKey(value, true);
3793             }
3794         }
3795     }
3796     UpdateViews(sender, UPDATE_ADD_ROUTE, (Hint *) &hint);
3797 
3798     return true;
3799 }
3800 
3801 void
deleteRoute(Node * src,int eventOut,Node * dst,int eventIn)3802 Scene::deleteRoute(Node *src, int eventOut, Node *dst, int eventIn)
3803 {
3804     if (eventOut < 0 || eventOut >= src->getProto()->getNumEventOuts())
3805         return;
3806 
3807     if (eventIn < 0 || eventIn >= dst->getProto()->getNumEventIns())
3808         return;
3809 
3810     RouteUpdate hint(src, eventOut, dst, eventIn);
3811 
3812     src->removeOutput(eventOut, dst, eventIn);
3813     dst->removeInput(eventIn, src, eventOut);
3814     UpdateViews(NULL, UPDATE_DELETE_ROUTE, (Hint *) &hint);
3815 }
3816 
3817 void
errorf(const char * fmt,...)3818 Scene::errorf(const char *fmt, ...)
3819 {
3820     va_list ap;
3821     char buf[1024], buf2[1024];
3822     const char *url = "";
3823 
3824     va_start(ap, fmt);
3825     myvsnprintf(buf, 1024, fmt, ap);
3826     if (TheApp->getImportFile() != NULL)
3827         url = TheApp->getImportFile();
3828     mysnprintf(buf2, 1024, "%s %d: %s", url, lineno, buf);
3829 #ifndef _WIN32
3830     fprintf(stderr, "%s", buf2);
3831     fflush(stderr);
3832 #endif
3833     m_errors += buf2;
3834 }
3835 
3836 void
invalidNode(const char * name)3837 Scene::invalidNode(const char *name)
3838 {
3839     errorf("invalid DEF name \"%s\"\n", name);
3840 }
3841 
3842 void
invalidField(const char * node,const char * field)3843 Scene::invalidField(const char *node, const char *field)
3844 {
3845     errorf("node \"%s\" has no field \"%s\"\n", node, field);
3846 }
3847 
3848 #ifdef NURBS_CURVE_ANIMATION_COMPATIBILTY
replaceNurbsCurveAnimation(Node * node,void * data)3849 static bool replaceNurbsCurveAnimation(Node *node, void *data)
3850 {
3851     if (node == NULL)
3852         return true;
3853     Proto *proto = node->getProto();
3854     if (proto == NULL)
3855         return true;
3856     Scene *scene = node->getScene();
3857     if (scene == NULL)
3858         return true;
3859     bool x3d = scene->isX3d();
3860     int nurbsCurveField;
3861     if (strcmp(proto->getName(x3d), "NurbsCurveAnimation") == 0) {
3862         if ((proto->lookupField("rotationAxesInterpolator", x3d) != -1) &&
3863             (proto->lookupField("timeWarpScalarInterpolator", x3d) != -1) &&
3864             (nurbsCurveField = proto->lookupField("nurbsCurve", x3d) != -1)) {
3865             FieldValue *value = node->getField(nurbsCurveField);
3866             if (value == NULL)
3867                 return true;
3868             NodeNurbsCurve *curve = (NodeNurbsCurve *)
3869                                      ((SFNode *)value)->getValue();
3870             if (curve == NULL)
3871                 return true;
3872             Node *curveAnimation = curve->toCurveAnimation();
3873             if (curveAnimation != NULL) {
3874                 Node *fromNode = node;
3875                 Node *toNode = curveAnimation;
3876                 Proto *fromProto = fromNode->getProto();
3877                 Proto *toProto = toNode->getProto();
3878                 int fromFractionEvent = fromProto->lookupEventIn("set_fraction",
3879                                                                  x3d);
3880                 int toFractionEvent = toProto->lookupEventIn("set_fraction",
3881                                                              x3d);
3882                 if ((fromFractionEvent == -1) || (toFractionEvent == -1))
3883                     return true;
3884                 SocketList::Iterator *i = NULL;
3885                 CommandList *list = NULL;
3886 
3887                 for (i = fromNode->getInput(fromFractionEvent).first();
3888                      i != NULL; i = i->next()) {
3889                     if (list == NULL)
3890                         list = new CommandList();
3891                     list->append(new RouteCommand(i->item().getNode(),
3892                                  i->item().getField(), toNode,
3893                                  toFractionEvent));
3894                 }
3895 
3896                 int fromPosEvent = fromProto->lookupEventOut("position_changed",
3897                                                             x3d);
3898                 int toPosEvent = toProto->lookupEventOut("position_changed",
3899                                                         x3d);
3900                 if ((fromPosEvent == -1) || (toPosEvent == -1))
3901                     return true;
3902                 for (i = fromNode->getOutput(fromPosEvent).first(); i != NULL;
3903                      i = i->next()) {
3904                     if (list == NULL)
3905                         list = new CommandList();
3906                     list->append(new RouteCommand(toNode, toPosEvent,
3907                                                   i->item().getNode(),
3908                                                   i->item().getField()));
3909                 }
3910 
3911                 int fromOriEvent = fromProto->lookupEventOut("orientation_changed",
3912                                                              x3d);
3913                 int toOriEvent = toProto->lookupEventOut("orientation_changed",
3914                                                          x3d);
3915                 if ((fromOriEvent == -1) || (toOriEvent == -1))
3916                     return true;
3917                 for (i = fromNode->getOutput(fromOriEvent).first(); i != NULL;
3918                      i = i->next()) {
3919                     if (list == NULL)
3920                         list = new CommandList();
3921                     list->append(new RouteCommand(toNode, toOriEvent,
3922                                                   i->item().getNode(),
3923                                                   i->item().getField()));
3924                 }
3925 
3926                 if (list) scene->execute(list);
3927 
3928                 MyString oldName = node->getName();
3929                 if (oldName.length() > 0) {
3930                     scene->undef(oldName);
3931                     scene->def(oldName, curveAnimation);
3932                 }
3933                 Node *parent = node->getParent();
3934                 int parentField = node->getParentField();
3935                 MoveCommand *command;
3936                 command = new MoveCommand(node, parent, parentField, NULL, -1);
3937                 command->execute();
3938                 command = new MoveCommand(curveAnimation, NULL, -1,
3939                                           parent, parentField);
3940                 command->execute();
3941             }
3942         }
3943     }
3944     return true;
3945 }
3946 #endif
3947 
3948 const char *
parse(FILE * f,Node * target,int field,int scan)3949 Scene::parse(FILE *f, Node* target, int field, int scan)
3950 {
3951     bool canRewind = true;
3952     if (isatty(fileno(f)))
3953         canRewind = false;
3954 #ifdef HAVE_LIBZ
3955     inputFile = gzdopen(fileno(f),"rb");
3956 #else
3957     inputFile = f;
3958 #endif
3959     scene = this;
3960     targetNode = target;
3961     targetField = field;
3962     scanFor = scan;
3963     lineno = 1;
3964     m_errors = "";
3965     m_isParsing = true;
3966     m_writeFlags = m_writeFlags & ~(X3DV | X3D_XML);
3967     bool isXml = false;
3968     bool isOther = false;
3969     if (canRewind) {
3970         int firstChar = -1;
3971         int end;
3972         do {
3973 #ifdef HAVE_LIBZ
3974            end = -1;
3975            firstChar = gzgetc(inputFile);
3976 #else
3977            end = EOF;
3978            firstChar = getc(inputFile);
3979 #endif
3980            if (firstChar == '<')
3981                isXml = true;
3982            else if (!isspace(firstChar))
3983                isOther = true;
3984         } while (isspace(firstChar) && (firstChar != end));
3985 #ifdef HAVE_LIBZ
3986         gzrewind(inputFile);
3987 #else
3988         rewind(inputFile);
3989 #endif
3990     } else {
3991         // no rewind possible, check current mode
3992         isXml = isX3dXml();
3993         isOther = !isXml;
3994     }
3995 #ifdef HAVE_LIBEXPAT
3996     if (isXml)
3997         parseX3d();
3998     if (isOther)
3999 #endif
4000         yyparse();
4001 #ifdef NURBS_CURVE_ANIMATION_COMPATIBILTY
4002     if (targetNode)
4003         targetNode->doWithBranch(replaceNurbsCurveAnimation, NULL);
4004     else if (getRoot())
4005         getRoot()->doWithBranch(replaceNurbsCurveAnimation, NULL);
4006 #endif
4007     m_isParsing = false;
4008     updateViewpoint();
4009     return m_errors;
4010 }
4011 
4012 void
add(Command * cmd)4013 Scene::add(Command *cmd)
4014 {
4015     m_undoStack.push(cmd);
4016 
4017     while (!m_redoStack.empty()) {
4018         delete m_redoStack.pop();
4019     }
4020 }
4021 
4022 
4023 void
addNextCommand(void)4024 Scene::addNextCommand(void)
4025 {
4026     m_undoStack.push(new NextCommand());
4027 }
4028 
4029 void
execute(Command * cmd,SceneView * sender)4030 Scene::execute(Command *cmd, SceneView *sender)
4031 {
4032     cmd->execute(sender);
4033     add(cmd);
4034 }
4035 
4036 void
backupFieldsStart(void)4037 Scene::backupFieldsStart(void)
4038 {
4039     // check for forbidden recursive usage or not missing backupFieldsDone()
4040     assert(m_backupCommandList == NULL);
4041     m_backupCommandList = new CommandList();
4042 }
4043 
4044 void
backupFieldsAppend(Node * node,int field)4045 Scene::backupFieldsAppend(Node *node, int field)
4046 {
4047     if (isRecording()) {
4048         Interpolator *interp = findUpstreamInterpolator(node, field);
4049 
4050         if (interp) {
4051             interp->backup(m_backupCommandList);
4052         }
4053     }
4054     m_backupCommandList->append(new FieldCommand(node, field));
4055 }
4056 
4057 void
backupFieldsDone(void)4058 Scene::backupFieldsDone(void)
4059 {
4060     add(m_backupCommandList);
4061     m_backupCommandList = NULL;
4062 }
4063 
4064 void
backupField(Node * node,int field)4065 Scene::backupField(Node *node, int field)
4066 {
4067     backupFieldsStart();
4068     backupFieldsAppend(node, field);
4069     backupFieldsDone();
4070 }
4071 
4072 Interpolator *
findUpstreamInterpolator(const Node * node,int field) const4073 Scene::findUpstreamInterpolator(const Node *node, int field) const
4074 {
4075     // is this field an ExposedField?
4076     int eventIn = -1;
4077     Field *f = node->getProto()->getField(field);
4078     ExposedField *e = f->getExposedField();
4079     if (e)
4080         eventIn = e->getEventIn();
4081     else if (f->getEventIn() != -1)
4082         eventIn = f->getEventIn();
4083     if (eventIn != -1) {
4084         const SocketList::Iterator *i;
4085 
4086         // check for interpolator routed to the corresponding EventIn;
4087 
4088         for (i = node->getInput(eventIn).first(); i != NULL; i = i->next()) {
4089             if ((i->item().getNode()->getMaskedNodeClass() ==
4090                  INTERPOLATOR_NODE) && i->item().getNode()->isInterpolator())
4091                 return ((Interpolator *)i->item().getNode());
4092         }
4093     }
4094     return NULL;
4095 
4096 }
4097 
4098 void
setField(Node * node,int field,FieldValue * value)4099 Scene::setField(Node *node, int field, FieldValue *value)
4100 {
4101     if (isRecording()) {
4102         Interpolator *interp = findUpstreamInterpolator(node, field);
4103 
4104         if (interp) {
4105             interp->recordKey(value, isRunning());
4106         }
4107     }
4108     node->setField(field, value);
4109     if (TheApp->is4Catt()) {
4110         if ((field != -1) && (node->getSolidField() == field)) {
4111             node->generateTreeLabel();
4112             NodeUpdate *hint= new NodeUpdate(node, NULL, 0);
4113             UpdateViews(NULL, UPDATE_SOLID_CHANGED, (Hint*) hint);
4114         }
4115     }
4116     if (node->getType() == VRML_TIME_SENSOR) {
4117        NodeTimeSensor *nodeTimeSensor = (NodeTimeSensor *) node;
4118        nodeTimeSensor->updateStart(field, value, m_currentTime);
4119     }
4120     if (!TheApp->getDrawAvoided())
4121         OnFieldChange(node, field);
4122 }
4123 
4124 void
deleteLastNextCommand(void)4125 Scene::deleteLastNextCommand(void)
4126 {
4127     if (m_undoStack.empty())
4128         return;
4129     Command *command = m_undoStack.peek();
4130     if (command->getType() == NEXT_COMMAND)
4131         command = m_undoStack.pop();
4132 }
4133 
4134 int
canUndo() const4135 Scene::canUndo() const
4136 {
4137     if (m_undoStack.empty())
4138         return 0;
4139     int top = m_undoStack.getTop();
4140     Command *command = m_undoStack.peek(top);
4141     if (command->getType() == NEXT_COMMAND)
4142         return (top > 1);
4143     return (top > 1);
4144 }
4145 
4146 int
canRedo() const4147 Scene::canRedo() const
4148 {
4149     if (m_redoStack.empty())
4150         return 0;
4151     int top = m_redoStack.getTop();
4152     Command *command = m_redoStack.peek(top);
4153     if (command->getType() == NEXT_COMMAND)
4154         return (top > 1);
4155     return (top > 1);
4156 }
4157 
4158 void
undo()4159 Scene::undo()
4160 {
4161     if (m_undoStack.empty()) {
4162         assert(0);
4163         return;
4164     }
4165 
4166     Command *change = m_undoStack.pop();
4167     if (change->getType() != NEXT_COMMAND) {
4168         change->undo();
4169         m_redoStack.push(change);
4170     } else if (m_undoStack.peek()->getType() == NEXT_COMMAND) {
4171         // ignore second NEXT_COMMAND
4172         change = m_undoStack.pop();
4173         m_redoStack.push(change);
4174     }
4175     while (!m_undoStack.empty()) {
4176         change = m_undoStack.pop();
4177         if (change->getType() == NEXT_COMMAND) {
4178             m_redoStack.push(change);
4179             break;
4180         } else {
4181             change->undo();
4182             m_redoStack.push(change);
4183         }
4184     }
4185 }
4186 
4187 void
redo()4188 Scene::redo()
4189 {
4190     if (m_redoStack.empty()) {
4191         assert(0);
4192         return;
4193     }
4194 
4195     Command *change = m_redoStack.pop();
4196     if (change->getType() != NEXT_COMMAND) {
4197         change->execute();
4198         m_undoStack.push(change);
4199     } else if (m_redoStack.peek()->getType() == NEXT_COMMAND) {
4200         // ignore second NEXT_COMMAND
4201         change = m_redoStack.pop();
4202         m_undoStack.push(change);
4203     }
4204 
4205     while (!m_redoStack.empty()) {
4206         change = m_redoStack.pop();
4207         if (change->getType() == NEXT_COMMAND) {
4208             m_undoStack.push(change);
4209             break;
4210         } else {
4211             change->execute();
4212             m_undoStack.push(change);
4213         }
4214     }
4215 }
4216 
4217 void
drawScene(bool pick,int x,int y,double width,double height,Node * root,bool useUpdate,float scaleX,float scaleY)4218 Scene::drawScene(bool pick, int x, int y, double width, double height,
4219                  Node *root, bool useUpdate, float scaleX, float scaleY)
4220 {
4221     m_width = width;
4222     m_height = height;
4223 
4224     m_drawViewPorts = (root != getRoot());
4225     if (root == NULL) {
4226         root = getRoot();
4227         m_drawViewPorts = false;
4228     }
4229     GLint v[4];
4230     float aspect;
4231 
4232     glGetIntegerv(GL_VIEWPORT, v);
4233 
4234     if (v[3])
4235         aspect = (GLfloat)v[2]/v[3];
4236     else  // don't divide by zero, not that we should ever run into that...
4237         aspect = 1.0f;
4238 
4239     m_numLights = 0;
4240     m_numClipPlanes = 0;
4241     m_headlight = true;
4242 
4243     glMatrixMode(GL_PROJECTION);
4244     glLoadIdentity();
4245     if (pick)
4246         gluPickMatrix(x, y, width, height, v);
4247     float fieldOfView = getCamera()->fov() ?
4248                         RAD2DEG(getCamera()->fov()->getValue() *
4249                         getUnitAngle()) : TheApp->getFixFieldOfView();
4250     if (TheApp->hasFixFieldOfView())
4251         fieldOfView = TheApp->getFixFieldOfView();
4252     gluPerspective(fieldOfView, aspect, TheApp->GetNearClippingPlaneDist(),
4253                                         TheApp->GetFarClippingPlaneDist());
4254 
4255     if (getSelection()->getNode() &&
4256         getSelection()->getNode()->getType() == X3D_ORTHO_VIEWPOINT) {
4257         glMatrixMode(GL_PROJECTION);
4258         glLoadIdentity();
4259         float dim = 4; // ???
4260         glOrtho(-dim * aspect, dim * aspect, -dim, dim,
4261                 TheApp->GetNearClippingPlaneDist(),
4262                 TheApp->GetFarClippingPlaneDist());
4263     }
4264 
4265     glMatrixMode(GL_MODELVIEW);
4266     glLoadIdentity();
4267 
4268     if (!m_drawViewPorts) {
4269         glClearColor(0.0F, 0.0F, 0.0F, 1.0F);
4270         glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
4271     }
4272 
4273     glEnable(GL_LIGHTING);
4274     glEnable(GL_NORMALIZE);
4275     glEnable(GL_DEPTH_TEST);
4276     glDepthFunc(GL_LEQUAL);
4277     if (TheApp->getRenderFaster()) {
4278         glHint(GL_LINE_SMOOTH_HINT, GL_FASTEST);
4279         glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST);
4280         glHint(GL_POLYGON_SMOOTH_HINT, GL_FASTEST);
4281     } else {
4282         glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
4283         glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
4284         glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
4285     }
4286 
4287     // no scene ambient light, please
4288     GLint zero[4] = { 0, 0, 0, 0 };
4289     glLightModeliv(GL_LIGHT_MODEL_AMBIENT, zero);
4290 
4291     double scale = getUnitLength();
4292     if (scale > 0)
4293         glScaled(1 / scale, 1 / scale, 1 / scale);
4294 
4295     glScalef(scaleX, scaleY, 1.0f);
4296 
4297     // first pass:  pre-draw traversal
4298     // enable PointLights and SpotLights; pick up ViewPoints, Fogs.
4299     // Backgrounds and TimeSensors
4300 
4301     glPushMatrix();
4302 
4303     bool viewpointFlag = getViewpointUpdated();
4304 
4305     applyCamera();
4306 
4307     m_viewpointUpdated = viewpointFlag;
4308 
4309     glPopMatrix();
4310 
4311     m_timeSensors.resize(0);
4312 
4313     m_headlightIsSet = false;
4314     m_defaultViewpoint->preDraw();
4315     root->preDraw();
4316 
4317     if (m_currentFog)
4318         m_currentFog->apply();
4319 
4320     if (useUpdate)
4321         updateTime();
4322 
4323     // second pass:  main drawing traversal
4324 
4325     glPushMatrix();
4326     if (m_headlight)
4327         enableHeadlight();
4328     glPushName(PICKED_NODE);
4329     if (m_backgrounds.size() > 0) {
4330 //        glPushName(NO_HANDLE);    // FIXME:  can't pick backgrounds, yet
4331         if (m_currentBackground)
4332             ((NodeBackground *) m_currentBackground)->apply();
4333 //        glPopName();
4334     }
4335     applyCamera();
4336     if (m_xrayRendering)
4337         glDepthMask(GL_FALSE);
4338     else
4339         glDepthMask(GL_TRUE);
4340     glDepthFunc(GL_LESS);
4341     root->draw(RENDER_PASS_NON_TRANSPARENT);
4342     glEnable(GL_BLEND);
4343     glDepthFunc(GL_LEQUAL);
4344     root->draw(RENDER_PASS_TRANSPARENT);
4345 
4346     for (int i = 0; i < m_numLights; i++) {
4347         glDisable((GLenum) (GL_LIGHT0 + i));
4348     }
4349     m_numLights = 0;
4350 
4351     for (int i = 0; i < m_numClipPlanes; i++) {
4352         glDisable((GLenum) (GL_CLIP_PLANE0 + i));
4353     }
4354     m_numClipPlanes = 0;
4355 
4356     glDisable(GL_FOG);
4357     glPopMatrix();
4358 
4359     // post-draw phase
4360     // draw handles
4361 
4362     if (m_headlight)
4363         enableHeadlight();
4364 
4365     if (getSelection()->getNode() &&
4366         getSelection()->getNode()->getType() != X3D_ORTHO_VIEWPOINT) {
4367         glPushMatrix();
4368         applyCamera();
4369         glLoadName(PICKED_RIGID_BODY_HANDLE);
4370         drawHandles(root, true);
4371         glPopMatrix();
4372 
4373         glPushMatrix();
4374         applyCamera();
4375         glLoadName(PICKED_HANDLE);
4376         drawHandles(root, false);
4377         glPopMatrix();
4378     }
4379     glDisable(GL_LIGHT0);
4380     glPopName();
4381     TheApp->printRenderErrors();
4382 
4383     m_numDraw++;
4384 }
4385 
4386 void
resetPerspective(void)4387 Scene::resetPerspective(void)
4388 {
4389     GLint v[4];
4390     float aspect;
4391 
4392     glGetIntegerv(GL_VIEWPORT, v);
4393 
4394     if (v[3])
4395         aspect = (GLfloat)v[2]/v[3];
4396     else  // don't divide by zero, not that we should ever run into that...
4397         aspect = 1.0f;
4398 
4399     glMatrixMode(GL_PROJECTION);
4400     glLoadIdentity();
4401     float fieldOfView = RAD2DEG(getCamera()->fov()->getValue() *
4402                                 getUnitAngle());
4403     if (TheApp->hasFixFieldOfView())
4404         fieldOfView = TheApp->getFixFieldOfView();
4405     gluPerspective(fieldOfView, aspect, TheApp->GetNearClippingPlaneDist(),
4406                                         TheApp->GetFarClippingPlaneDist());
4407 }
4408 
4409 void
draw3dCursor(int x,int y)4410 Scene::draw3dCursor(int x, int y)
4411 {
4412     if (!use3dCursor())
4413          return;
4414 
4415     float objX;
4416     float objY;
4417     float objZ;
4418 
4419     float eyeposition=0;
4420     float eyeangle=0;
4421     float nearPlane=TheApp->GetNearClippingPlaneDist();
4422 
4423     glPushMatrix();
4424 
4425     if (TheApp->useStereo())
4426        {
4427        // inexact "toe in" stereo method
4428        if (TheApp->getEyeMode()==EM_RIGHT)
4429           {
4430           eyeposition= - TheApp->getEyeHalfDist();
4431           eyeangle= - TheApp->getEyeAngle();
4432           }
4433        else if (TheApp->getEyeMode()==EM_LEFT)
4434           {
4435           eyeposition= + TheApp->getEyeHalfDist();
4436           eyeangle= + TheApp->getEyeAngle();
4437           }
4438        }
4439     glTranslatef(eyeposition, 0, 0);
4440     glRotatef(eyeangle, 0,1,0);
4441 
4442     GLint viewport[4];
4443     glGetIntegerv(GL_VIEWPORT, viewport);
4444 
4445     float xSize = (viewport[2] - viewport[0]) * TheApp->GetEyeAngleFactor() *
4446                   (viewport[3] - viewport[1]) / (viewport[2] - viewport[0]);
4447 
4448     unProjectPoint(x - eyeposition * xSize, y, nearPlane, &objX, &objY, &objZ);
4449 
4450     glPushAttrib(GL_ENABLE_BIT);
4451     glDisable(GL_LIGHTING);
4452     glDisable(GL_TEXTURE_2D);
4453     glEnable(GL_LINE_SMOOTH);
4454     glDisable(GL_BLEND);
4455     glLineWidth(TheApp->Get3dCursorWidth());
4456 
4457     if (TheApp->isAnaglyphStereo())
4458         Util::myGlColor3f(1, 1, 1);
4459     else
4460         Util::myGlColor3f(0, 1, 0);
4461     glBegin(GL_LINE_STRIP);
4462     glVertex3f(objX + TheApp->Get3dCursorLength(), -objY, objZ);
4463     glVertex3f(objX - TheApp->Get3dCursorLength(), -objY, objZ);
4464     glEnd();
4465     glBegin(GL_LINE_STRIP);
4466     glVertex3f(objX, -objY + TheApp->Get3dCursorLength(), objZ);
4467     glVertex3f(objX, -objY - TheApp->Get3dCursorLength(), objZ);
4468     glEnd();
4469     glEnable(GL_LIGHTING);
4470     glLineWidth(1);
4471     glPopAttrib();
4472 
4473     glPopMatrix();
4474 }
4475 
4476 bool
isVerticesOrNurbs(void)4477 Scene::isVerticesOrNurbs(void)
4478 {
4479     Node *selection = NULL;
4480     if (getSelection())
4481         selection = getSelection()->getNode();
4482     bool isNurbs = selection && ((selection->getType() == VRML_NURBS_SURFACE) ||
4483                                  (selection->getType() == VRML_NURBS_CURVE) ||
4484                                  (selection->getType() == VRML_NURBS_CURVE_2D) ||
4485                                  (selection->getType() == DUNE_CURVE_ANIMATION));
4486     if ((getSelectionMode() == SELECTION_MODE_VERTICES) || isNurbs)
4487         return true;
4488     return false;
4489 }
4490 
4491 void
draw3dBoundingBox(int xfrom,int yfrom,int xto,int yto)4492 Scene::draw3dBoundingBox(int xfrom, int yfrom, int xto, int yto)
4493 {
4494     float objXfrom;
4495     float objYfrom;
4496     float objZfrom;
4497 
4498     float objXto;
4499     float objYto;
4500     float objZto;
4501 
4502     float eyeposition = 0;
4503     float eyeangle = 0;
4504     float nearPlane=TheApp->GetNearClippingPlaneDist();
4505 
4506     glPushMatrix();
4507 
4508     if (TheApp->useStereo()) {
4509        // inexact "toe in" stereo method
4510        if (TheApp->getEyeMode()==EM_RIGHT)
4511           {
4512           eyeposition= - TheApp->getEyeHalfDist();
4513           eyeangle= - TheApp->getEyeAngle();
4514           }
4515        else if (TheApp->getEyeMode()==EM_LEFT)
4516           {
4517           eyeposition= + TheApp->getEyeHalfDist();
4518           eyeangle= + TheApp->getEyeAngle();
4519           }
4520        }
4521     glTranslatef(eyeposition, 0, 0);
4522     glRotatef(eyeangle, 0,1,0);
4523 
4524     GLint viewport[4];
4525     glGetIntegerv(GL_VIEWPORT, viewport);
4526 
4527     float xSize = (viewport[2] - viewport[0]) * TheApp->GetEyeAngleFactor() *
4528                   (viewport[3] - viewport[1]) / (viewport[2] - viewport[0]);
4529 
4530     unProjectPoint(xfrom - eyeposition * xSize, yfrom, nearPlane,
4531                    &objXfrom, &objYfrom, &objZfrom);
4532     unProjectPoint(xto - eyeposition * xSize, yto, nearPlane,
4533                    &objXto, &objYto, &objZto);
4534 
4535     glPushAttrib(GL_ENABLE_BIT);
4536     glDisable(GL_LIGHTING);
4537     glDisable(GL_TEXTURE_2D);
4538     glEnable(GL_LINE_SMOOTH);
4539     glDisable(GL_BLEND);
4540     glLineWidth(TheApp->Get3dCursorWidth());
4541 
4542     if (TheApp->isAnaglyphStereo())
4543         Util::myGlColor3f(1, 1, 1);
4544     else
4545         Util::myGlColor3f(0, 1, 0);
4546 
4547     glBegin(GL_LINE_STRIP);
4548     glVertex3f(objXfrom, -objYfrom, objZfrom);
4549     glVertex3f(objXto, -objYfrom, objZfrom);
4550     glEnd();
4551     glBegin(GL_LINE_STRIP);
4552     glVertex3f(objXto, -objYfrom, objZfrom);
4553     glVertex3f(objXto, -objYto, objZfrom);
4554     glEnd();
4555     glBegin(GL_LINE_STRIP);
4556     glVertex3f(objXto, -objYto, objZfrom);
4557     glVertex3f(objXfrom, -objYto, objZfrom);
4558     glEnd();
4559     glBegin(GL_LINE_STRIP);
4560     glVertex3f(objXfrom, -objYto, objZfrom);
4561     glVertex3f(objXfrom, -objYfrom, objZfrom);
4562     glEnd();
4563 
4564     glEnable(GL_LIGHTING);
4565     glLineWidth(1);
4566     glPopAttrib();
4567 
4568     glPopMatrix();
4569 }
4570 
4571 Path *
pick(int x,int y,float width,float height)4572 Scene::pick(int x, int y, float width, float height)
4573 {
4574     float xwidth = PICK_REGION_SIZE * TheApp->GetHandleSize();
4575     if (width != 0)
4576         xwidth = width;
4577     float yheight = PICK_REGION_SIZE * TheApp->GetHandleSize();
4578     if (height != 0)
4579         yheight = height;
4580     GLuint pickBuffer[PICK_BUFFER_SIZE];
4581 #ifdef DEBUG
4582     for (GLuint i = 0; i < PICK_BUFFER_SIZE; i++)
4583         pickBuffer[i] = 0;
4584 #endif
4585     glSelectBuffer(PICK_BUFFER_SIZE, pickBuffer);
4586     glRenderMode(GL_SELECT);
4587     glInitNames();
4588 
4589     TheApp->setEyeMode(EM_NONE);
4590     drawScene(true, x, y, xwidth, yheight);
4591 
4592     GLint hits = glRenderMode(GL_RENDER);
4593     Path *path = NULL;
4594     if (hits < 0) // overflow flag has been set, ignore
4595         hits = - hits;
4596     if (hits)
4597         path = processHits(hits, pickBuffer, (width != 0) && (height != 0));
4598     if (path != NULL) {
4599         return path;
4600     } else {
4601         return new Path(NULL, 0, this);
4602     }
4603 }
4604 
4605 Path *
processHits(GLint hits,GLuint * pickBuffer,bool selectMultipleHandles)4606 Scene::processHits(GLint hits, GLuint *pickBuffer, bool selectMultipleHandles)
4607 {
4608     GLuint *glPath = NULL;
4609     int glPathLen = 0;
4610     unsigned depth = UINT_MAX;
4611     unsigned handleDepth = 0;
4612     bool pickedNode = false;
4613     int handle = -1;
4614 
4615     for (int i = 0; i < hits; i++) {
4616         unsigned numNames = *pickBuffer++;
4617 /*      unsigned minDepth = * */ pickBuffer++;
4618         unsigned maxDepth = *pickBuffer++;
4619         if (*pickBuffer == PICKED_NODE) {
4620             if (depth >= maxDepth) {
4621                 pickedNode = true;
4622                 glPath = pickBuffer + 1;
4623                 glPathLen = numNames - 1;
4624                 depth = maxDepth;
4625             }
4626         } else if (*pickBuffer == PICKED_RIGID_BODY_HANDLE) {
4627             if (m_rigidBodyHandleNode == NULL)
4628                 return NULL;
4629             handle = pickBuffer[numNames - 1];
4630             return m_rigidBodyHandleNode->getPath();
4631         } else if (*pickBuffer == PICKED_HANDLE) {
4632             bool isCoord = COORDINATE_NODE ==
4633                   getSelection()->getNode()->getProto()->getNodeClass();
4634 
4635             bool isVertices = getSelectionMode() == SELECTION_MODE_VERTICES ||
4636                               getSelectionMode() ==
4637                               SELECTION_HANIM_JOINT_WEIGHT;
4638             if ((!isCoord) || isVertices || (handleDepth <= maxDepth)) {
4639                 if (pickBuffer[numNames - 1] != NO_HANDLE) {
4640                     pickedNode = false;
4641                     glPath = pickBuffer + 1;
4642                     glPathLen = numNames - 2;
4643                     handle = pickBuffer[numNames - 1];
4644                     handleDepth = maxDepth;
4645                 }
4646                 if (selectMultipleHandles) {
4647                     if (m_deselect)
4648                         removeSelectedHandle(handle);
4649                     else
4650                         addSelectedHandle(handle);
4651                 }
4652                 depth = maxDepth;
4653             }
4654         } else if (*pickBuffer == PICKED_3DCURSOR) {
4655             return NULL;
4656         } else {
4657             return NULL;
4658         }
4659         pickBuffer += numNames;
4660     }
4661     if (pickedNode)
4662         m_lastSelectedHandle = -1;
4663     else if (handle != -1)
4664         if (!selectMultipleHandles) {
4665             if (m_deselect)
4666                 removeSelectedHandle(handle);
4667             else
4668                 setSelectedHandle(handle);
4669         }
4670 
4671     if (glPath == NULL)
4672         return NULL;
4673 
4674     bool insideProto = false;
4675     Path *path = new Path((int *) glPath, glPathLen, this, true,
4676                           true);
4677     if (path->getNode()->isDeepInsideProto()) {
4678         insideProto = true;
4679         delete path;
4680     }
4681     return new Path((int *) glPath, glPathLen, this, insideProto);
4682 }
4683 
4684 void
transform(const Path * path)4685 Scene::transform(const Path *path)
4686 {
4687     assert(path != NULL);
4688     applyCamera();
4689     const NodeList *nodes = path->getNodes();
4690     for (long i = 0; i < nodes->size() - 1; i++) {
4691         nodes->get(i)->transform();
4692     }
4693 }
4694 
searchTransform(void)4695 Path* Scene::searchTransform(void)
4696 {
4697     Path* transform = new Path(*m_selection);
4698     Node *trans = transform->getNode();
4699     while (trans->getType() != VRML_TRANSFORM && trans->hasParent()) {
4700            trans = trans->getParent();
4701            if (trans == getRoot())
4702                return NULL;
4703     }
4704     return searchTransform(trans->getPath());
4705 }
4706 
4707 // search for a Transform node in a path
4708 // return new path to Transform node or NULL if not found
4709 
searchTransform(Path * transform)4710 Path* Scene::searchTransform(Path *transform)
4711 {
4712     if (transform != NULL) {
4713         if (transform->getNode()->getType() == VRML_TRANSFORM)
4714             return transform;
4715         while (transform->getNode() != m_root &&
4716                transform->getNode()->hasParent()) {
4717             transform = new Path(*(transform->getNode()->getParent()->getPath()));
4718             if (transform->getNode()->getType() == VRML_TRANSFORM)
4719                 break;
4720             // delete old_transform; // bug: deleting a path cause a crash
4721         }
4722         if (transform->getNode()==m_root)
4723             transform = NULL;
4724     }
4725     return transform;
4726 }
4727 
checkHandleParentsForRigidBody(Node * node,void * data)4728 static bool checkHandleParentsForRigidBody(Node *node, void *data) {
4729     Scene *scene = (Scene *)data;
4730     if (node == NULL)
4731         return true;
4732     if (node->getType() == X3D_RIGID_BODY)
4733         if (node->isInScene(scene))
4734             scene->setRigidBodyHandleNode(node);
4735     return true;
4736 }
4737 
4738 void
finishDrawHandles(void)4739 Scene::finishDrawHandles(void)
4740 {
4741     int glPushCount = 0;
4742     glGetIntegerv(GL_NAME_STACK_DEPTH, &glPushCount);
4743     glPushCount--;
4744     for (int i = 0; i < glPushCount; i++)
4745         glPopName();
4746 }
4747 
4748 void
drawHandles(Node * root,bool drawRigidBodyHandles)4749 Scene::drawHandles(Node *root, bool drawRigidBodyHandles)
4750 {
4751     if (root != getRoot())
4752         return;
4753     glDisable(GL_DEPTH_TEST);
4754     switch (TheApp->GetHandleMode()) {
4755       case HM_NONE:
4756         break;
4757       case HM_TREE:
4758         // draw handles for all nodes in the current selection path
4759         if ((m_selection != NULL) && (!drawRigidBodyHandles)) {
4760             glPushMatrix();
4761             int len = m_selection->getPathLen();
4762             const int *path = m_selection->getPath();
4763             Node *node = root;
4764             for (int i = 0; i < len;) {
4765                 int field = path[i++];
4766                 if (i >= len)
4767                     break;
4768                 node = m_selection->getNextNode(node, field, i);
4769                 if (node == NULL)
4770                     break;
4771                 glPushName(field);
4772                 glPushName(path[i++]);
4773                 node->drawHandles();
4774                 node->transform();
4775             }
4776             glPopMatrix();
4777         }
4778         break;
4779       case HM_SELECTED:
4780         if (m_selection != NULL) {
4781             glPushMatrix();
4782             int len = m_selection->getPathLen();
4783             const int *path = m_selection->getPath();
4784             Node *node = root;
4785             Node *handlenode = root;
4786             Node *lastnode = root;
4787             m_rigidBodyHandleNode = NULL;
4788             for (int i = 0; i < len;) {
4789                 int field = path[i++];
4790                 if (i >= len) {
4791                     break;
4792                 }
4793                 Node *newNode = m_selection->getNextNode(node, field, i++);
4794                 if (newNode == NULL) {
4795                     finishDrawHandles();
4796                     break;
4797                 } else
4798                     node = newNode;
4799                 /* search last transform node in path */
4800                 if (node->getType() == VRML_TRANSFORM)
4801                    handlenode = node;
4802                 // search for a RigidBody node in the Parents of a
4803                 // X3DNBodyCollidableNode
4804                 if (node->matchNodeClass(BODY_COLLIDABLE_NODE)) {
4805                     m_rigidBodyHandleNode = NULL;
4806                     node->doWithParents(checkHandleParentsForRigidBody, this);
4807                     if (m_rigidBodyHandleNode != NULL)
4808                         handlenode = node;
4809                 }
4810             }
4811             lastnode = node;
4812             node = root;
4813             for (int i = 0; i < len;) {
4814                 int field = path[i++];
4815                 if (i >= len)
4816                     break;
4817                 node = m_selection->getNextNode(node, field, i);
4818                 if (node == NULL) {
4819                     finishDrawHandles();
4820                     break;
4821                 }
4822                 glPushName(field);
4823                 glPushName(path[i++]);
4824                 /* display last transform node in path */
4825                 if ((node == handlenode) || (node == lastnode)) {
4826                      if ((node == handlenode) &&
4827                          (m_rigidBodyHandleNode != NULL)) {
4828                          if (drawRigidBodyHandles)
4829                              m_rigidBodyHandleNode->drawHandles();
4830                      } else {
4831                          if (!drawRigidBodyHandles)
4832                              node->drawHandles();
4833                      }
4834                 }
4835                 if (node->getType() != X3D_RIGID_BODY)
4836                     if (node->getType() != X3D_HANIM_JOINT)
4837                         node->transform();
4838             }
4839             glPopMatrix();
4840         }
4841         break;
4842       case HM_ALL:
4843         if (!drawRigidBodyHandles)
4844             drawHandlesRec(root);
4845         break;
4846     }
4847     finishDrawHandles();
4848 }
4849 
4850 void
drawHandlesRec(Node * node,bool drawOnlyJoints) const4851 Scene::drawHandlesRec(Node *node, bool drawOnlyJoints) const
4852 {
4853     int numFields = node->getProto()->getNumFields();
4854 
4855     glPushMatrix();
4856     bool draw = true;
4857     if (drawOnlyJoints)
4858         if (!node->isJoint())
4859             draw = false;
4860     if (draw)
4861         if (node->isJoint() && !node->isFirstUSE())
4862             draw = false;
4863     if (draw)
4864         node->drawHandles();
4865     node->transform();
4866     for (int i = 0; i < numFields; i++) {
4867         FieldValue *value = node->getField(i);
4868         if (value->getType() == SFNODE) {
4869             Node *child = ((SFNode *) value)->getValue();
4870             if (child) {
4871                 glPushName(i);
4872                 glPushName(0);
4873                 drawHandlesRec(child, drawOnlyJoints);
4874                 glPopName();
4875                 glPopName();
4876             }
4877         } else if (value->getType() == MFNODE) {
4878             glPushName(i);
4879             glPushName(0);
4880             MFNode  *v = (MFNode *) value;
4881             int n = v->getSize();
4882             for (int j = 0; j < n; j++) {
4883                 glLoadName(j);
4884                 drawHandlesRec(v->getValue(j), drawOnlyJoints);
4885             }
4886             glPopName();
4887             glPopName();
4888         }
4889     }
4890     glPopMatrix();
4891 }
4892 
4893 void
enableHeadlight()4894 Scene::enableHeadlight()
4895 {
4896     GLenum light = (GLenum) allocateLight();
4897     static float pos[4] = {0.0f, 0.0f, 1.0f, 0.0f};
4898     static float ambientColor[4] = {0.0f, 0.0f, 0.0f, 1.0f};
4899     static float diffuseColor[4] = {1.0f, 1.0f, 1.0f, 1.0f};
4900 
4901     glLightfv(light, GL_AMBIENT, ambientColor);
4902     glLightfv(light, GL_DIFFUSE, diffuseColor);
4903     glLightfv(light, GL_POSITION, pos);
4904     glLightfv(light, GL_SPECULAR, diffuseColor);
4905     glLightf(light, GL_SPOT_CUTOFF, 180.0f);
4906     glLightf(light, GL_SPOT_EXPONENT, 0.0f);
4907     glLightf(light, GL_CONSTANT_ATTENUATION, 1.0f);
4908     glLightf(light, GL_LINEAR_ATTENUATION, 0.0f);
4909     glLightf(light, GL_QUADRATIC_ATTENUATION, 0.0f);
4910     glEnable(light);
4911 }
4912 
4913 // allocateLight()
4914 //
4915 // reserve an openGL light
4916 
4917 int
allocateLight()4918 Scene::allocateLight()
4919 {
4920     GLint maxLights;
4921     glGetIntegerv(GL_MAX_LIGHTS, &maxLights);
4922 
4923     if (m_numLights >= maxLights) {
4924         errorf("too many lights!\n");
4925         return GL_LIGHT0;
4926     }
4927 
4928     return (GL_LIGHT0 + m_numLights++);
4929 }
4930 
4931 int
freeLight()4932 Scene::freeLight()
4933 {
4934     return GL_LIGHT0 + --m_numLights;
4935 }
4936 
4937 int
allocateClipPlane()4938 Scene::allocateClipPlane()
4939 {
4940     GLint maxClipPlanes;
4941     glGetIntegerv(GL_MAX_CLIP_PLANES, &maxClipPlanes);
4942 
4943     if (m_numClipPlanes >= maxClipPlanes) {
4944         errorf("too many ClipPlanes!\n");
4945         return GL_CLIP_PLANE0;
4946     }
4947 
4948     return (GL_CLIP_PLANE0 + m_numClipPlanes++);
4949 }
4950 
4951 int
freeClipPlane()4952 Scene::freeClipPlane()
4953 {
4954     return GL_CLIP_PLANE0 + --m_numClipPlanes;
4955 }
4956 
4957 void
projectPoint(float x,float y,float z,float * wx,float * wy,float * wz)4958 Scene::projectPoint(float x, float y, float z, float *wx, float *wy, float *wz)
4959 {
4960     GLdouble mmat[16], pmat[16];
4961     GLdouble winx, winy, winz;
4962     GLint viewport[4];
4963 
4964     glGetDoublev(GL_MODELVIEW_MATRIX, mmat);
4965     glGetDoublev(GL_PROJECTION_MATRIX, pmat);
4966     glGetIntegerv(GL_VIEWPORT, viewport);
4967 
4968     gluProject(x, y, z, mmat, pmat, viewport, &winx, &winy, &winz);
4969 
4970     *wx = (float) winx;
4971     *wy = (float) winy;
4972     *wz = (float) winz;
4973 }
4974 
4975 void
unProjectPoint(float wx,float wy,float wz,float * x,float * y,float * z)4976 Scene::unProjectPoint(float wx, float wy, float wz, float *x, float *y, float *z)
4977 {
4978     GLdouble mmat[16], pmat[16];
4979     GLdouble objx, objy, objz;
4980     GLint viewport[4];
4981 
4982     glGetDoublev(GL_MODELVIEW_MATRIX, mmat);
4983     glGetDoublev(GL_PROJECTION_MATRIX, pmat);
4984     glGetIntegerv(GL_VIEWPORT, viewport);
4985 
4986     gluUnProject(wx, wy, wz, mmat, pmat, viewport, &objx, &objy, &objz);
4987 
4988     *x = (float) objx;
4989     *y = (float) objy;
4990     *z = (float) objz;
4991 }
4992 
4993 void
addViewpoint(Node * viewpoint)4994 Scene::addViewpoint(Node *viewpoint)
4995 {
4996     m_viewpoints.append(viewpoint);
4997 }
4998 
4999 void
addNavigationInfo(Node * navigationInfo)5000 Scene::addNavigationInfo(Node *navigationInfo)
5001 {
5002     m_navigationinfos.append(navigationInfo);
5003 }
5004 
5005 void
addFog(Node * fog)5006 Scene::addFog(Node *fog)
5007 {
5008     m_fogs.append(fog);
5009     setFog(fog);
5010 }
5011 
5012 void
setFog(Node * fog)5013 Scene::setFog(Node *fog)
5014 {
5015     m_currentFog = (NodeFog *)fog;
5016 }
5017 
5018 void
addBackground(Node * background)5019 Scene::addBackground(Node *background)
5020 {
5021     m_backgrounds.append(background);
5022     setBackground(background);
5023 }
5024 
5025 void
setBackground(Node * background)5026 Scene::setBackground(Node *background)
5027 {
5028     m_currentBackground = (NodeBackground *)background;
5029 }
5030 
5031 void
addTimeSensor(Node * timeSensor)5032 Scene::addTimeSensor(Node *timeSensor)
5033 {
5034     for (long i = 0; i < m_timeSensors.size(); i++)
5035         if (m_timeSensors[i] == timeSensor)
5036             return;
5037     m_timeSensors.append(timeSensor);
5038 }
5039 
5040 void
startWalking()5041 Scene::startWalking()
5042 {
5043     m_oldWalkTime = swGetCurrentTime();
5044 }
5045 
5046 void
walkCamera(Vec3f walk,bool forward)5047 Scene::walkCamera(Vec3f walk, bool forward)
5048 {
5049     Vec3d pos(m_currentViewpoint->getPosition());
5050     Quaternion rot(m_currentViewpoint->getOrientation());
5051     float fspeed = m_currentNavigationInfo->speed()->getValue();
5052     double dt = swGetCurrentTime() - m_oldWalkTime;
5053 
5054     if (forward || dt > 0) {
5055         Quaternion around(Vec3f(0.0f, 1.0f, 0.0f), -DEG2RAD(walk.x * 2.0f));
5056         Quaternion newRot(around * rot);
5057         newRot.normalize();
5058         rot.normalize();
5059         m_currentViewpoint->setOrientation(newRot);
5060         float z = dt * walk.z * 2.0f;
5061         m_currentViewpoint->setPosition(pos + rot * fspeed * Vec3d(0, 0, z));
5062         UpdateViews(NULL, UPDATE_REDRAW_3D);
5063     } else {
5064          Vec3f vec(dt * fspeed * walk.x * 2.0f, dt * fspeed * walk.y * 2.0f, 0);
5065          m_currentViewpoint->setPosition(pos + rot * vec);
5066     }
5067     m_viewpointUpdated = true;
5068 }
5069 
5070 void
changeTurnPointDistance(float factor)5071 Scene::changeTurnPointDistance(float factor)
5072 {
5073     if (m_currentNavigationInfo) {
5074         MFFloat *mfAvatarSize = m_currentNavigationInfo->avatarSize();
5075         float fdist = m_currentNavigationInfo->speed()->getValue() * 10;
5076         if (mfAvatarSize->getSize() > 3)
5077             fdist = mfAvatarSize->getValue(3) * factor;
5078         MFFloat *newAvatarSize = new MFFloat();
5079         for (int i = 0; i < mfAvatarSize->getSize(); i++)
5080             newAvatarSize->setValue(i, mfAvatarSize->getValue(i));
5081         float values[] = { 0.25f, 1.6f, 0.75f };
5082         if (newAvatarSize->getSize() < 3)
5083             for (int i = newAvatarSize->getSize() - 1; i < 3; i++)
5084                  newAvatarSize->setValue(i, values[i]);
5085         newAvatarSize->setValue(3, fdist);
5086         setField(m_currentNavigationInfo,
5087                  m_currentNavigationInfo->avatarSize_Field(), newAvatarSize);
5088         TheApp->PrintMessageWindowsFloat(IDS_TURN_POINT_DISTANCE, fdist);
5089     }
5090 }
5091 
5092 void
moveCamera(float dx,float dy,float dz)5093 Scene::moveCamera(float dx, float dy, float dz)
5094 {
5095     Vec3d pos = m_currentViewpoint->getPosition();
5096     Quaternion rot = m_currentViewpoint->getOrientation();
5097 
5098     float fspeed = m_currentNavigationInfo->speed()->getValue();
5099     m_currentViewpoint->setPosition(pos + rot * fspeed * Vec3f(dx, dy, dz));
5100 
5101     m_viewpointUpdated = true;
5102 }
5103 
5104 void
turnCamera(float x,float y,float z,float ang)5105 Scene::turnCamera(float x, float y, float z, float ang)
5106 {
5107     Quaternion rot = m_currentViewpoint->getOrientation();
5108     Quaternion r(Vec3f(x, y, z), ang);
5109 
5110     m_currentViewpoint->setOrientation(r * rot);
5111 
5112     m_viewpointUpdated = true;
5113 }
5114 
5115 Quaternion oldRot;
5116 
5117 void
setTurnPoint(void)5118 Scene::setTurnPoint(void)
5119 {
5120     m_turnPointPos = m_currentViewpoint->getPosition();
5121     m_turnPointRot = m_currentViewpoint->getOrientation();
5122 }
5123 
5124 void
orbitCamera(float dtheta,float dphi)5125 Scene::orbitCamera(float dtheta, float dphi)
5126 {
5127     Vec3d pos(m_currentViewpoint->getPosition());
5128     Quaternion rot(m_currentViewpoint->getOrientation());
5129     Quaternion up(Vec3f(0.0f, 1.0f, 0.0f), dtheta);
5130     Quaternion around(Vec3f(1.0f, 0.0f, 0.0f), dphi);
5131     Quaternion newRot(up * around * rot);
5132 
5133     Vec3f zAxis(0, 0, 10);
5134     Vec3f dist(m_turnPointRot * zAxis);
5135     dist.normalize();
5136     float fdist = 10;
5137     MFFloat *mfAvatarSize = m_currentNavigationInfo->avatarSize();
5138     if (mfAvatarSize->getSize() > 3)
5139         fdist = mfAvatarSize->getValue(3);
5140     else
5141         fdist =  m_currentNavigationInfo->speed()->getValue() * 10;
5142 
5143     dist = dist * fdist;
5144 
5145     Vec3d newPos = m_turnPointPos - dist + dist * m_turnPointRot.conj() *
5146                                                   newRot;
5147     if (TheApp->GetMouseMode() == MOUSE_EXAMINE)
5148         m_currentViewpoint->setPosition(newPos);
5149 
5150     m_currentViewpoint->setOrientation(newRot);
5151 
5152     m_viewpointUpdated = true;
5153 }
5154 
5155 void
rollCamera(float dtheta)5156 Scene::rollCamera(float dtheta)
5157 {
5158     Vec3d pos(m_currentViewpoint->getPosition());
5159     Quaternion rot(m_currentViewpoint->getOrientation());
5160     Quaternion roll(Vec3f(0.0f, 0.0f, -1.0f), dtheta);
5161     Quaternion newRot(roll * rot);
5162     newRot.normalize();
5163     rot.normalize();
5164 
5165     Vec3d newPos(rot.conj() * pos * newRot);
5166 
5167     if (TheApp->GetMouseMode() == MOUSE_EXAMINE) {
5168         m_currentViewpoint->setPosition(newPos);
5169     }
5170     m_currentViewpoint->setOrientation(newRot);
5171     applyCamera();
5172 
5173     m_viewpointUpdated = true;
5174 }
5175 
5176 void
standUpCamera(void)5177 Scene::standUpCamera(void)
5178 {
5179     Quaternion rot(m_currentViewpoint->getOrientation());
5180     rot.x = 0;
5181     rot.z = 0;
5182     m_currentViewpoint->setOrientation(rot);
5183     UpdateViews(NULL, UPDATE_PREVIEW);
5184 
5185     m_viewpointUpdated = true;
5186 }
5187 
5188 Node *
createNode(const char * nodeType,int flags)5189 Scene::createNode(const char *nodeType, int flags)
5190 {
5191     Proto *def = NULL;
5192     if (isX3d() && strcmp(nodeType, "NurbsPatchSurface") == 0)
5193         def = m_protos["NurbsSurface"];
5194     else
5195         def = m_protos[nodeType];
5196 
5197     Node *node = def ? def->create(this) : (Node *) NULL;
5198     if (node != NULL)
5199         node->setFlag(flags);
5200     return node;
5201 }
5202 
5203 Node *
createNode(int nodeType)5204 Scene::createNode(int nodeType)
5205 {
5206     ProtoMap::Chain::Iterator *j;
5207     // search for proto with correct nodeType
5208     for (int i = 0; i < m_protos.width(); i++) {
5209         for ( j = m_protos.chain(i).first(); j != NULL; j = j->next()) {
5210             if (j->item()->getData()->getType() == nodeType)
5211                 return createNode(j->item()->getKey());
5212         }
5213     }
5214     return (Node *) NULL;
5215 }
5216 
5217 DynamicFieldsNode *
createDynamicFieldsNode(const char * nodeType,int flags)5218 Scene::createDynamicFieldsNode(const char *nodeType, int flags)
5219 {
5220     Proto *def = NULL;
5221     if (isX3d() && strcmp(nodeType, "NurbsPatchSurface") == 0)
5222         def = m_protos["NurbsSurface"];
5223     else
5224         def = m_protos[nodeType];
5225 
5226     DynamicFieldsNode *node = def ? (DynamicFieldsNode *)def->create(this) :
5227                               (DynamicFieldsNode *) NULL;
5228     if (node != NULL)
5229         node->setFlag(flags);
5230     return node;
5231 }
5232 
5233 void
addNode(Node * node)5234 Scene::addNode(Node *node)
5235 {
5236     m_nodes.append(node);
5237 
5238 }
5239 
5240 MyString
getUniqueNodeName(const char * name)5241 Scene::getUniqueNodeName(const char *name)
5242 {
5243     static char buf[512];
5244     for (int i = 1; ; i++) {
5245         mysnprintf(buf, 512, "%s%d", name, i);
5246         if (!hasAlreadyName(buf)) break;
5247     }
5248     MyString ret = "";
5249     ret += buf;
5250     return ret;
5251 }
5252 
5253 MyString
getUniqueNodeName(Node * node)5254 Scene::getUniqueNodeName(Node *node)
5255 {
5256     const char *name = node->getProto()->getName(isX3d());
5257 
5258     return getUniqueNodeName(name);
5259 }
5260 
5261 
5262 MyString
generateUniqueNodeName(Node * node,const char * name)5263 Scene::generateUniqueNodeName(Node *node, const char *name)
5264 {
5265     int i;
5266     static char buf[512];
5267 
5268     mysnprintf(buf, 512, "%s%d", name, 1);
5269     for (i = 1; hasAlreadyName(buf); i++) {
5270         mysnprintf(buf, 512, "%s%d", name, i);
5271     }
5272     MyString ret = "";
5273     ret += buf;
5274     def(ret, node);
5275     return ret;
5276 }
5277 
5278 MyString
generateUniqueNodeName(Node * node)5279 Scene::generateUniqueNodeName(Node *node)
5280 {
5281     MyString name = mystrdup(getUniqueNodeName(node));
5282     def(name, node);
5283     return name;
5284 }
5285 
generateVariableName(Node * node)5286 MyString Scene::generateVariableName(Node *node)
5287 {
5288      MyString ret = "";
5289      ret += node->getProto()->getName(isX3d());
5290      m_variableCounter++;
5291      char number[1024];
5292      mysnprintf(number, 1023, "%d", m_variableCounter);
5293      ret += "_";
5294      ret += number;
5295      return ret;
5296 }
5297 
5298 void
removeNode(Node * node)5299 Scene::removeNode(Node *node)
5300 {
5301     long index = m_nodes.findBackward(node);
5302     if ((index >= 0) && (index < (long)m_nodes.size()))
5303         m_nodes.remove(index);
5304 }
5305 
5306 void
setSelection(Path * path)5307 Scene::setSelection(Path *path)
5308 {
5309     m_selection_is_in_scene = true;
5310     m_viewOfLastSelection = NULL;
5311     if (m_selection != path) {
5312         if (m_selection)
5313             m_oldSelection = m_selection->getNode();
5314         else
5315             m_oldSelection = NULL;
5316         delete m_selection;
5317         m_selection = path;
5318         Node *node = m_selection->getNode();
5319         if (node == NULL) {
5320             return;
5321         }
5322         if (node->getType() == VRML_VIEWPOINT) {
5323             m_currentViewpoint = (NodeViewpoint *)node;
5324             applyCamera();
5325         }
5326         if (node->getType() == VRML_GEO_VIEWPOINT) {
5327             m_currentViewpoint = (NodeGeoViewpoint *)node;
5328             applyCamera();
5329         }
5330         if (node->getType() == VRML_NAVIGATION_INFO) {
5331             m_currentNavigationInfo = (NodeNavigationInfo *)node;
5332             applyNavigationInfo();
5333         }
5334         if (node->getType() == X3D_HANIM_JOINT) {
5335             m_lastSelectedHAnimJoint = node;
5336         }
5337         if (node->getType() == X3D_HANIM_HUMANOID) {
5338             m_lastSelectedHAnimJoint = NULL;
5339         }
5340         if (node == getRoot()) {
5341             m_lastSelectedHAnimJoint = NULL;
5342             m_firstSelectionRangeHandle = -1;
5343             removeSelectedHandles();
5344         }
5345         MFNode *children = ((NodeGroup *)getRoot())->children();
5346         for (int i = 0; i < children->getSize(); i++)
5347             if (children->getValue(i)->getType() == DUNE_VRML_CUT) {
5348                 NodeVrmlCut *cut = (NodeVrmlCut *)children->getValue(i);
5349                 cut->updateSelection();
5350                 break;
5351             }
5352     }
5353 }
5354 
5355 void
getProtoList(MyArray<int> * protoList,const Node * node)5356 Scene::getProtoList(MyArray<int> *protoList, const Node *node)
5357 {
5358     if (node != getRoot())
5359         for (int i = 0; (i < getNumProtos()) && (protoList->size() == 0); i++) {
5360             Proto *proto = getProto(i);
5361             for (int j = 0; j < proto->getNumNodes(); j++)
5362                 if ((proto->getNode(j)->isEqualCopy((Node *)node)) ||
5363                     (proto->getNode(j)->isEqual((Node *)node))) {
5364                     protoList->append(-i - 1);
5365                     protoList->append(j);
5366                     break;
5367                 }
5368         }
5369 }
5370 
5371 Path*
newPath(Node * node)5372 Scene::newPath(Node *node)
5373 {
5374     Path* ret;
5375     int len = 0;
5376     Node *n;
5377 
5378     for (n = node; n->hasParent() ; n = n->getParent()) {
5379         len += 2;
5380     }
5381 
5382     MyArray<int> protoList;
5383     getProtoList(&protoList, n);
5384     if (protoList.size() > 0)
5385         len += 4;
5386 
5387     if (len > 0) {
5388         int *list = new int[len];
5389 
5390         int i = len-1;
5391 
5392         for (n = node; n->hasParentOrProtoParent();
5393              n = n->getParentOrProtoParent()) {
5394             Node *parent = n->getParent();
5395 
5396             int field = n->getParentFieldOrProtoParentField();
5397             list[i--] = parent->findChild(n, field);
5398             list[i--] = field;
5399         }
5400         if (protoList.size() > 0) {
5401             list[i--] = 0;
5402             list[i--] = 0;
5403             list[i--] = protoList[1];
5404             list[i--] = protoList[0];
5405         }
5406         ret=new Path(list, len, this);
5407         delete [] list;
5408     } else {
5409         // select root node
5410         ret=new Path(NULL, 0, this);
5411     }
5412     return ret;
5413 }
5414 
5415 void
setSelection(Node * node)5416 Scene::setSelection(Node *node)
5417 {
5418     if (node != NULL)
5419         setSelection(node->getPath());
5420 }
5421 
5422 void
setSelection(Proto * proto)5423 Scene::setSelection(Proto *proto)
5424 {
5425     Path* path = NULL;
5426     int len = 3;
5427     if (len > 0) {
5428         int *list = new int[len];
5429         for (int i = 0; i < getNumProtos(); i++) {
5430              if (proto == getProto(i)) {
5431                 list[0] = -i - 1;
5432                 list[1] = -1;
5433                 list[2] = 0;
5434                 path = new Path(list, len, this);
5435                 delete [] list;
5436                 setSelection(path);
5437                 break;
5438             }
5439         }
5440     }
5441 }
5442 
5443 bool
isModified() const5444 Scene::isModified() const
5445 {
5446     if (!canUndo()) {
5447         if (m_unmodified != NULL)
5448             return TRUE;
5449         else
5450             return m_extraModifiedFlag;
5451     } else {
5452         return m_unmodified != m_undoStack.peek();
5453     }
5454 }
5455 
5456 void
applyCamera()5457 Scene::applyCamera()
5458 {
5459     if (getSelection()->getNode() &&
5460         getSelection()->getNode()->getType() == X3D_ORTHO_VIEWPOINT)
5461         ((NodeOrthoViewpoint *)getSelection()->getNode())->apply();
5462     else if (m_currentViewpoint->getType() == VRML_GEO_VIEWPOINT)
5463         ((NodeGeoViewpoint *)m_currentViewpoint)->apply();
5464     else if (m_currentViewpoint->getType() == VRML_VIEWPOINT) {
5465         glPushMatrix();
5466         glMatrixMode(GL_MODELVIEW);
5467         glLoadIdentity();
5468         Matrix matrix = Matrix::identity();;
5469         Path *trans = searchTransform(m_currentViewpoint->getPath());
5470         if (trans)
5471             ((NodeTransform *)trans->getNode())->getMatrix(matrix);
5472         glLoadMatrixf(matrix);
5473         ((NodeViewpoint *)m_currentViewpoint)->preDraw();
5474         glPopMatrix();
5475 
5476         ((NodeViewpoint *)m_currentViewpoint)->apply(TheApp->useStereo(),
5477                                                      Vec3d(), SFRotation());
5478     }
5479     m_viewpointUpdated = false;
5480 }
5481 
5482 void
setCamera(Node * camera)5483 Scene::setCamera(Node *camera)
5484 {
5485     m_currentViewpoint = camera;
5486 
5487     m_viewpointUpdated = true;
5488 }
5489 
5490 void
applyNavigationInfo(void)5491 Scene::applyNavigationInfo(void)
5492 {
5493     m_currentNavigationInfo->apply();
5494 }
5495 
5496 void
setFirstNavigationInfo(void)5497 Scene::setFirstNavigationInfo(void)
5498 {
5499     if (!m_setNavigationInfo) {
5500         m_setNavigationInfo = true;
5501         if (m_navigationinfos.size() > 0) {
5502             m_currentNavigationInfo = (NodeNavigationInfo *) m_navigationinfos[0];
5503         } else {
5504             m_currentNavigationInfo = m_defaultNavigationInfo;
5505         }
5506     }
5507     applyNavigationInfo();
5508 }
5509 
5510 void
start()5511 Scene::start()
5512 {
5513     m_running = true;
5514     if (!m_setViewpoint) {
5515         m_setViewpoint = true;
5516        if (m_viewpoints.size() > 0) {
5517            m_currentViewpoint = (NodeViewpoint *) m_viewpoints[0];
5518        } else {
5519             m_currentViewpoint = m_defaultViewpoint;
5520        }
5521     }
5522 
5523     double t = swGetCurrentTime();
5524     updateTimeAt(t);
5525 }
5526 
5527 void
stop()5528 Scene::stop()
5529 {
5530     m_running = false;
5531 }
5532 
5533 double
timeSinceStart(void)5534 Scene::timeSinceStart(void)
5535 {
5536     return m_currentTime - m_timeStart;
5537 }
5538 
5539 void
updateTimeAt(double t)5540 Scene::updateTimeAt(double t)
5541 {
5542     for (long i = 0; i < m_timeSensors.size(); i++)
5543         ((NodeTimeSensor *) m_timeSensors[i])->setTime(t);
5544 }
5545 
timeUpdateNodePROTO(Node * node,void * data)5546 static bool timeUpdateNodePROTO(Node *node, void *data)
5547 {
5548 #ifdef HAVE_PROTO_INITIALIZATION_OPTIMIZATION
5549     if (node->isPROTO()) {
5550         NodePROTO *protoNode = (NodePROTO *)node;
5551         if (protoNode->getProto()->hasTimeSensor() ||
5552             protoNode->getProto()->specialInit())  {
5553             protoNode->handleIs();
5554             protoNode->createPROTO();
5555             protoNode->reInit();
5556         }
5557     }
5558 #else
5559     if (node->isPROTO()) {
5560         NodePROTO *protoNode = (NodePROTO *)node;
5561         protoNode->handleIs();
5562         protoNode->createPROTO();
5563         protoNode->reInit();
5564     }
5565 #endif
5566     return true;
5567 }
5568 
5569 class TimeStep {
5570 public:
5571     double currentTime;
5572     double oldTime;
5573 };
5574 
timeUpdateInterpolator(Node * node,void * data)5575 static bool timeUpdateInterpolator(Node *node, void *data)
5576 {
5577     TimeStep *step = (TimeStep *)data;
5578     if (node->isInterpolator()) {
5579         ((Interpolator *)node)->removeOldKeys(step->currentTime, step->oldTime);
5580     }
5581     return true;
5582 }
5583 
5584 void
updateTime()5585 Scene::updateTime()
5586 {
5587     m_oldTime = m_currentTime;
5588     m_currentTime = swGetCurrentTime();
5589     updateTimeAt(m_currentTime);
5590     getRoot()->doWithBranch(timeUpdateNodePROTO, NULL,
5591                             false, false, false, true, false);
5592     if (isRunning() && isRecording()) {
5593         TimeStep timeStep;
5594         timeStep.currentTime = m_currentTime;
5595         timeStep.oldTime = m_oldTime;
5596         getRoot()->doWithBranch(timeUpdateInterpolator, &timeStep,
5597                                 false, false, false, true, false);
5598     }
5599     UpdateViews(NULL, UPDATE_TIME);
5600     UpdateViews(NULL, UPDATE_TOOLBARS);
5601 }
5602 
5603 Node *
getCamera() const5604 Scene::getCamera() const
5605 {
5606     return m_currentViewpoint;
5607 }
5608 
5609 NodeNavigationInfo *
getNavigationInfoNode() const5610 Scene::getNavigationInfoNode() const
5611 {
5612     return m_currentNavigationInfo;
5613 }
5614 
5615 void
AddView(SceneView * view)5616 Scene::AddView(SceneView *view)
5617 {
5618     m_views.append(view);
5619 }
5620 
5621 void
RemoveView(SceneView * view)5622 Scene::RemoveView(SceneView *view)
5623 {
5624     m_views.remove(m_views.find(view));
5625 }
5626 
updateNodePROTO(Node * node,void * data)5627 static bool updateNodePROTO(Node *node, void *data)
5628 {
5629     Proto *proto = (Proto *)data;
5630     if (node->getProto() == proto) {
5631         ((NodePROTO *)node)->handleIs();
5632         ((NodePROTO *)node)->createPROTO();
5633         ((NodePROTO *)node)->reInit();
5634     }
5635     return true;
5636 }
5637 
updateNodePROTOs(Proto * protoToUpdate)5638 void Scene::updateNodePROTOs(Proto *protoToUpdate)
5639 {
5640     if (protoToUpdate != NULL) {
5641         getRoot()->doWithBranch(updateNodePROTO, protoToUpdate,
5642                                 false, false, false, true, false);
5643         UpdateViews(NULL, UPDATE_REDRAW_3D);
5644     }
5645 }
5646 
5647 void
OnFieldChange(Node * node,int field,int index)5648 Scene::OnFieldChange(Node *node, int field, int index)
5649 {
5650     static double time = 0;
5651     if ((node->getType() == VRML_VIEWPOINT) ||
5652         (node->getType() == VRML_GEO_VIEWPOINT))
5653         if (node != getSelection()->getNode())
5654             return;
5655 
5656     time = m_currentTime;
5657 
5658     FieldUpdate hint(node, field, index);
5659     UpdateViews(NULL, UPDATE_FIELD, (Hint *) &hint);
5660 }
5661 
5662 void
OnAddNode(Node * node,Node * dest,int field)5663 Scene::OnAddNode(Node *node, Node *dest, int field)
5664 {
5665     if (node->getOutsideProto() != NULL) {
5666         Proto *protoToUpdate = node->getOutsideProto();
5667         protoToUpdate->setIsNodeIndex();
5668         getRoot()->doWithBranch(updateNodePROTO, protoToUpdate);
5669     }
5670 
5671     NodeUpdate hint(node, dest, field);
5672 
5673     UpdateViews(NULL, UPDATE_ADD_NODE, (Hint *) &hint);
5674 }
5675 
5676 void
OnAddNodeSceneGraph(Node * node,Node * dest,int field)5677 Scene::OnAddNodeSceneGraph(Node *node, Node *dest, int field)
5678 {
5679     NodeUpdate hint(node, dest, field);
5680 
5681     UpdateViews(NULL, UPDATE_ADD_NODE_SCENE_GRAPH_VIEW, (Hint *) &hint);
5682 }
5683 
5684 void
OnRemoveNode(Node * node,Node * src,int field)5685 Scene::OnRemoveNode(Node *node, Node *src, int field)
5686 {
5687     NodeUpdate hint(node, src, field);
5688     // a deleted DEF'ed node can not be USE'd
5689     if (node == m_defNode)
5690         m_defNode = NULL;
5691     UpdateViews(NULL, UPDATE_REMOVE_NODE, (Hint *) &hint);
5692 }
5693 
5694 void
UpdateViews(SceneView * sender,int type,Hint * hint)5695 Scene::UpdateViews(SceneView *sender, int type, Hint *hint)
5696 {
5697     static bool alreadyInUpdate = false;
5698     if (alreadyInUpdate) // forbid recursive update chains
5699         return;
5700     alreadyInUpdate = true;
5701     UpdateViewsNow(sender, type, hint);
5702     alreadyInUpdate = false;
5703 }
5704 
5705 
5706 void
UpdateViewsNow(SceneView * sender,int type,Hint * hint)5707 Scene::UpdateViewsNow(SceneView *sender, int type, Hint *hint)
5708 {
5709     if (!m_canUpdateViewsSelection)
5710         if (type == UPDATE_SELECTION)
5711             return;
5712     for (List<SceneView *>::Iterator *i = m_views.first(); i != NULL;
5713          i = i->next()) {
5714         SceneView *view = i->item();
5715         if (view != sender && (!swIsHidden(TheApp->mainWnd())))
5716             view->OnUpdate(sender, type, hint);
5717     }
5718 }
5719 
5720 void
BackupRoutesRec(Node * node,CommandList * list)5721 BackupRoutesRec(Node *node, CommandList *list)
5722 {
5723     int                         i;
5724     SocketList::Iterator       *j;
5725 
5726     if (!node) return;
5727 
5728     if (node->getNumParents() > 1) return;
5729 
5730     for (i = 0; i < node->getProto()->getNumEventIns(); i++) {
5731         for (j = node->getInput(i).first(); j != NULL; j = j->next()) {
5732             const RouteSocket &s = j->item();
5733             list->append(new UnRouteCommand(s.getNode(), s.getField(),
5734                                             node, i));
5735         }
5736     }
5737     for (i = 0; i < node->getProto()->getNumEventOuts(); i++) {
5738         for (j = node->getOutput(i).first(); j != NULL; j = j->next()) {
5739             const RouteSocket &s = j->item();
5740             list->append(new UnRouteCommand(node, i,
5741                                             s.getNode(), s.getField()));
5742         }
5743     }
5744 
5745     for (i = 0; i < node->getProto()->getNumFields(); i++) {
5746         FieldValue  *v = node->getField(i);
5747         if (v->getType() == SFNODE) {
5748             BackupRoutesRec(((SFNode *) v)->getValue(), list);
5749         } else if (v->getType() == MFNODE) {
5750             int size = ((MFNode *) v)->getSize();
5751             for (int k = 0; k < size; k++) {
5752                 BackupRoutesRec(((MFNode *) v)->getValue(k), list);
5753             }
5754         }
5755     }
5756 }
5757 
5758 void
selectNext()5759 Scene::selectNext()
5760 {
5761     Node *node = m_selection->getNode();
5762     int newIndex = node->getNextSiblingIndex();
5763     if (newIndex == -1)
5764         newIndex = node->getPrevSiblingIndex();
5765     Node *parent = m_selection->getParent();
5766     Node *newSelection = parent;
5767     if (parent == NULL)
5768         newSelection = m_root;
5769     else {
5770         int parentField = m_selection->getParentField();
5771         newSelection = parent;
5772         if (newIndex != -1) {
5773             MFNode *mfnode = (MFNode *)parent->getField(parentField);
5774             if (newIndex < mfnode->getSize())
5775                 newSelection = mfnode->getValue(newIndex);
5776         }
5777     }
5778     setSelection(newSelection);
5779 }
5780 
5781 void
deleteSelected()5782 Scene::deleteSelected()
5783 {
5784     Proto *proto = m_selection->getProto(this);
5785     Node *node = m_selection->getNode();
5786     if (node->getIsUse())
5787         return;
5788     if (proto != NULL) {
5789         for (int i = 0; i < proto->getNumNodes(); i++)
5790             if (node->isEqual(proto->getNode(i))) {
5791                 proto->removeNode(i);
5792                 proto->setIsNodeIndex();
5793                 updateNodePROTOs(proto);
5794                 UpdateViews(NULL, UPDATE_ALL);
5795                 if (i > 0)
5796                     setSelection(newPath(proto->getNode(i - 1)));
5797                 else
5798                     setSelection(getRoot());
5799                 UpdateViews(NULL, UPDATE_SELECTION);
5800                 return;
5801             }
5802     }
5803     Node *parent = m_selection->getParent();
5804     int parentField = m_selection->getParentField();
5805     if ((parent != NULL) && (parentField != -1)) {
5806         CommandList *list = new CommandList();
5807         deleteSelectedAppend(list);
5808         execute(list);
5809     }
5810 }
5811 
5812 void
deleteAll()5813 Scene::deleteAll()
5814 {
5815     NodeGroup *parent = (NodeGroup *)getRoot();
5816     int parentField = parent->children_Field();
5817 
5818     CommandList *list = new CommandList();
5819     if ((parent != NULL) && (parentField != -1)) {
5820         for (int i = parent->children()->getSize() - 1; i >= 0; i--) {
5821             Node *node = parent->children()->getValue(i);
5822             BackupRoutesRec(node, list);
5823             list->append(new MoveCommand(node, parent, parentField, NULL, -1));
5824             execute(list);
5825         }
5826     }
5827     UpdateViews(NULL, UPDATE_ALL);
5828 }
5829 
5830 void
deleteSelectedAppend(CommandList * list)5831 Scene::deleteSelectedAppend(CommandList* list)
5832 {
5833     if (m_selection && (m_selection->getNode() != m_root)) {
5834         if (m_selection->getNode() == m_currentViewpoint) {
5835             m_defaultViewpoint = (NodeViewpoint *)m_currentViewpoint->copy();
5836             m_currentViewpoint = m_defaultViewpoint;
5837         }
5838         if (m_selection->getNode() &&
5839             m_selection->getNode()->getType() == X3D_VIEWPORT) {
5840             m_viewports.remove(m_viewports.find((NodeViewport *)
5841                                                 m_selection->getNode()));
5842         }
5843         Node *node = m_selection->getNode();
5844         Node *parent = m_selection->getParent();
5845         int parentField = m_selection->getParentField();
5846 
5847         if ((parent != NULL) && (parentField != -1)) {
5848             if (node->getNumParents() == 1) {
5849                 BackupRoutesRec(node, list);
5850             }
5851             list->append(new MoveCommand(node, parent, parentField, NULL, -1));
5852         }
5853     }
5854 }
5855 
5856 int
OnDragOver(Node * src,Node * srcParent,int src_field,Node * dest,int dest_field,int modifiers)5857 Scene::OnDragOver(Node *src, Node *srcParent, int src_field,
5858                   Node *dest, int dest_field, int modifiers)
5859 {
5860     int rc = 0;
5861 
5862     if (src && dest) {
5863         int destField = getDestField(src, dest, dest_field);
5864         if (destField >= 0) {
5865             if ((modifiers & SW_CONTROL) && (modifiers & SW_SHIFT)
5866                 && dest != src && !dest->hasAncestor(src)) {
5867                 rc = SW_DRAG_LINK;
5868             } else if (modifiers & SW_CONTROL) {
5869                 rc = SW_DRAG_COPY;
5870             } else if (dest != src
5871                    && !dest->hasAncestor(src)
5872                    && dest->findChild(src, destField) == -1) {
5873                 rc = SW_DRAG_MOVE;
5874             }
5875         }
5876     }
5877     return rc;
5878 }
5879 
5880 int
OnDrop(Node * src,Node * srcParent,int srcField,Node * dest,int destField,int modifiers)5881 Scene::OnDrop(Node *src, Node *srcParent, int srcField,
5882               Node *dest, int destField, int modifiers)
5883 {
5884     int effect = OnDragOver(src, srcParent, srcField, dest, destField, modifiers);
5885     NodeUpdate *hint = NULL;
5886     if (src && dest) {
5887         if (destField == -1) destField = dest->findValidField(src);
5888         switch(effect) {
5889           case SW_DRAG_COPY:
5890             execute(new MoveCommand(src->copy(), NULL, -1, dest, destField));
5891             src->reInit();
5892             break;
5893           case SW_DRAG_MOVE:
5894             execute(new MoveCommand(src, srcParent, srcField, dest, destField));
5895             break;
5896           case SW_DRAG_LINK:
5897             execute(new MoveCommand(src, NULL, -1, dest, destField));
5898             hint = new NodeUpdate(src, NULL, 0);
5899             UpdateViews(NULL, UPDATE_NODE_NAME, (Hint*) hint);
5900             break;
5901         }
5902         return 1;
5903     } else {
5904         return 0;
5905     }
5906 }
5907 
5908 struct HttpFile {
5909   const char *filename;
5910   FILE *stream;
5911 };
5912 
my_fwrite(void * buffer,long size,long nmemb,void * stream)5913 static long my_fwrite(void *buffer, long size, long nmemb, void *stream)
5914 {
5915   struct HttpFile *out = (struct HttpFile *)stream;
5916   if(out && !out->stream) {
5917     /* open file for writing */
5918     out->stream = fopen(out->filename, "wb");
5919     if(!out->stream)
5920       return -1; /* failure, can't open file to write */
5921   }
5922   return fwrite(buffer, size, nmemb, out->stream);
5923 }
5924 
5925 class DownloadPathData {
5926 public:
5927     MyString string;
5928     bool isRemote;
5929 };
5930 
5931 MyString
downloadPath(const URL & url)5932 Scene::downloadPath(const URL &url)
5933 {
5934      DownloadPathData data = downloadPathIntern(url);
5935      return data.string;
5936 }
5937 
5938 DownloadPathData
downloadPathIntern(const URL & url)5939 Scene::downloadPathIntern(const URL &url)
5940 {
5941     DownloadPathData ret;
5942     ret.string = "";
5943     ret.isRemote = false;
5944     if ((strcasecmp(url.getScheme(), "https") == 0) ||
5945         (strcasecmp(url.getScheme(), "http") == 0) ||
5946         (strcasecmp(url.getScheme(), "ftp") == 0)) {
5947         ret.isRemote = true;
5948 
5949         const char *myPath = TheApp->getDownloadDirectory();
5950         myPath = replaceHome(myPath);
5951         ret.string += myPath;
5952         free((void *)myPath);
5953         ret.string += swGetPathSeperator();
5954         ret.string += url.getHostname();
5955         ret.string += swGetPathSeperator();
5956         ret.string += '/';
5957         ret.string += url.ToPath();
5958         if (TheApp->getVerbose())
5959             swDebugf("%s\n", (const char *)ret.string);
5960         mkdir_parents4file(ret.string);
5961         setPathIntern(ret.string);
5962         return ret;
5963     } else if (strcasecmp(url.getScheme(), "file") == 0) {
5964         ret.string += url.ToPath();
5965         return ret;
5966     }
5967     ret.string += url.ToPath();
5968     return ret;
5969 }
5970 
5971 bool
Download(const URL & url,MyString * path)5972 Scene::Download(const URL &url, MyString *path)
5973 {
5974 #ifdef HAVE_LIBCURL
5975     DownloadPathData data = downloadPathIntern(url);
5976 
5977     if (data.isRemote) {
5978         MyString filename = "";
5979         filename += data.string;
5980         CURL *curl;
5981         CURLcode res;
5982         struct HttpFile httpfile = {
5983           filename, /* name to store the file as if successful */
5984           NULL
5985         };
5986 
5987         curl_global_init(CURL_GLOBAL_DEFAULT);
5988 
5989         curl = curl_easy_init();
5990         if (curl) {
5991             curl_easy_setopt(curl, CURLOPT_URL, (const char *)url);
5992             // Define our callback to get called when there's data to be written
5993             curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
5994             // Set a pointer to our struct to pass to the callback
5995             curl_easy_setopt(curl, CURLOPT_WRITEDATA, &httpfile);
5996             // disable decompession
5997             curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "identity");
5998             curl_easy_setopt(curl, CURLOPT_FAILONERROR, true);
5999 
6000     #ifdef DEBUG
6001             /* Switch on full protocol/debug output */
6002             curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
6003     #endif
6004 
6005             res = curl_easy_perform(curl);
6006 
6007             /* always cleanup */
6008             curl_easy_cleanup(curl);
6009 
6010             if (CURLE_OK != res) {
6011                 /* we failed */
6012                 fprintf(stderr, "curl: %s\n",  curl_easy_strerror(res));
6013             } else
6014                 m_downloaded = true;
6015         } else {
6016             swDebugf("failed download %s\n", (const char *)url);
6017             return false;
6018         }
6019 
6020         if (httpfile.stream)
6021             fclose(httpfile.stream); /* close the local file */
6022 
6023         curl_global_cleanup();
6024 
6025         *path = filename;
6026     } else
6027         *path = data.string;
6028 #endif
6029 
6030     return true;
6031 }
6032 
6033 FontInfo *
LoadGLFont(const char * fontName,const char * style)6034 Scene::LoadGLFont(const char *fontName, const char *style)
6035 {
6036     int styleId;
6037 
6038     // handle "special" font names
6039     if (!strcmp(fontName, "SERIF")) {
6040         fontName = "Times New Roman";
6041     } else if (!strcmp(fontName, "SANS")) {
6042         fontName = "Arial";
6043     } else if (!strcmp(fontName, "TYPEWRITER")) {
6044         fontName = "Courier New";
6045     }
6046 
6047     if (!strcmp(style, "BOLD")) {
6048         styleId = SW_BOLD;
6049     } else if (!strcmp(style, "ITALIC")) {
6050         styleId = SW_ITALIC;
6051     } else if (!strcmp(style, "BOLDITALIC")) {
6052         styleId = SW_BOLD | SW_ITALIC;
6053     } else {
6054         styleId = SW_PLAIN;
6055     }
6056 
6057     // look for font in cache
6058 
6059     for (long i = 0; i < m_fonts.size(); i++) {
6060         if (!strcmp(m_fonts[i]->name, fontName) && m_fonts[i]->style == styleId) {
6061             return m_fonts[i];
6062         }
6063     }
6064 
6065     // create some font outlines
6066 
6067     FontInfo *info = new FontInfo();
6068 
6069     info->displayListBase =
6070           swLoadGLFont(fontName, styleId, info->kernX, info->kernY);
6071 
6072     if (info->displayListBase == 0) {
6073         delete info;
6074         return NULL;
6075     } else {
6076         info->name = fontName;
6077         info->style = styleId;
6078         m_fonts.append(info);
6079         return info;
6080     }
6081 }
6082 
6083 bool
addProtoName(MyString name)6084 Scene::addProtoName(MyString name)
6085 {
6086    if (belongsToNodeWithExternProto(name))
6087        return true;
6088    for (int i = 0; i < m_numProtoNames; i++)
6089        if (m_protos[m_protoNames[i]] && name == m_protoNames[i]) {
6090            if (m_protos[m_protoNames[i]]->isExternProto())
6091                return true;
6092            return false;
6093        }
6094    m_protoNames[m_numProtoNames++] = name;
6095    return true;
6096 }
6097 
6098 void
deleteProtoName(MyString name)6099 Scene::deleteProtoName(MyString name)
6100 {
6101    for (int i = 0; i < m_numProtoNames; i++)
6102        if (name == m_protoNames[i]) {
6103            m_protoNames.remove(i);
6104            m_numProtoNames--;
6105        }
6106 }
6107 
6108 void
addProtoDefinition(void)6109 Scene::addProtoDefinition(void)
6110 {
6111    m_protoDefinitions[m_numProtoDefinitions++] = "";
6112    m_isNestedProto[m_numProtoDefinitions - 1] = false;
6113 }
6114 
6115 void
addToProtoDefinition(const char * string)6116 Scene::addToProtoDefinition(const char* string)
6117 {
6118     if (m_numProtoDefinitions > 0)
6119         m_protoDefinitions[m_numProtoDefinitions - 1] += string;
6120 }
6121 
6122 bool
isNestedProto(const char * protoName)6123 Scene::isNestedProto(const char *protoName)
6124 {
6125     for (int i = 0; i < m_numProtoDefinitions; i++)
6126         if (i < getNumProtos())
6127             if (strcmp(m_protoNames[i], protoName) == 0)
6128                 if (m_isNestedProto[i])
6129                     return true;
6130     return false;
6131 }
6132 
6133 void
setNestedProto(void)6134 Scene::setNestedProto(void)
6135 {
6136     if (m_numProtoDefinitions > 0)
6137         m_isNestedProto[m_numProtoDefinitions - 1] = true;
6138 }
6139 
6140 MyString
createRouteString(const char * fromNodeName,const char * fromFieldName,const char * toNodeName,const char * toFieldName)6141 Scene::createRouteString(const char *fromNodeName, const char *fromFieldName,
6142                          const char *toNodeName, const char *toFieldName)
6143 {
6144     MyString route = "";
6145     if (::isX3dXml(m_writeFlags)) {
6146         route += "<ROUTE fromNode='";
6147         route += fromNodeName;
6148         route += "' fromField='";
6149         route += fromFieldName;
6150         route += "' toNode='";
6151         route += toNodeName;
6152         route += "' toField='";
6153         route += toFieldName;
6154         route += "'";
6155         if (m_writeFlags & X3DOM) {
6156             // X3DOM do not support <ROUTE />
6157             route += ">";
6158             route += "</ROUTE>";
6159         } else
6160            route += "/>";
6161     } else {
6162         route += "ROUTE ";
6163         route += fromNodeName;
6164         route += ".";
6165         route += fromFieldName;
6166         route += " TO ";
6167         route += toNodeName;
6168         route += ".";
6169         route += toFieldName;
6170     }
6171     return route;
6172 }
6173 
6174 
6175 void
addRouteString(MyString string)6176 Scene::addRouteString(MyString string)
6177 {
6178    // do not store double route strings
6179    for (List<MyString>::Iterator* routepointer = m_routeList.first();
6180         routepointer != NULL; routepointer = routepointer->next() )
6181        if (strcmp(routepointer->item(),string) == 0)
6182            return;
6183 
6184    m_routeList.append(string);
6185 }
6186 
6187 void
addEndRouteString(MyString string)6188 Scene::addEndRouteString(MyString string)
6189 {
6190    m_endRouteList.append(string);
6191 }
6192 
6193 void
setViewOfLastSelection(SceneView * view)6194 Scene::setViewOfLastSelection(SceneView* view)
6195 {
6196    m_viewOfLastSelection = view;
6197    m_selection_is_in_scene = false;
6198 }
6199 
getViewOfLastSelection(void)6200 SceneView* Scene::getViewOfLastSelection(void)
6201 {
6202    return m_viewOfLastSelection;
6203 }
6204 
copyLastSelection(void)6205 void Scene::copyLastSelection(void)
6206 {
6207    if (!m_selection_is_in_scene) {
6208       // do copy in View
6209       SceneView* view = getViewOfLastSelection();
6210       if (view != NULL)
6211           view->CopyLastSelection();
6212    }
6213 }
6214 
pasteLastSelection(void)6215 void Scene::pasteLastSelection(void)
6216 {
6217    if (!m_selection_is_in_scene) {
6218       // do paste in View
6219       SceneView* view = getViewOfLastSelection();
6220       if (view != NULL)
6221           view->PasteLastSelection();
6222    }
6223 }
6224 
pasteSymetricLastSelection(int direction)6225 void Scene::pasteSymetricLastSelection(int direction)
6226 {
6227    if (!m_selection_is_in_scene) {
6228       // do paste in View
6229       SceneView* view = getViewOfLastSelection();
6230       if (view != NULL)
6231           view->PasteSymetricLastSelection(direction);
6232    }
6233 }
6234 
deleteLastSelection(void)6235 void Scene::deleteLastSelection(void)
6236 {
6237    if (m_selection_is_in_scene) {
6238       // do delete in scene
6239       deleteSelected();
6240    } else {
6241       // do delete in View
6242       SceneView* view = getViewOfLastSelection();
6243       if (view != NULL)
6244           view->DeleteLastSelection();
6245    }
6246 }
6247 
saveProtoStatus(void)6248 void Scene::saveProtoStatus(void)
6249 {
6250    m_statusNumProtoNames=m_numProtoNames;
6251    m_statusNumProtoDefinitions=m_numProtoDefinitions;
6252 }
6253 
restoreProtoStatus(void)6254 void Scene::restoreProtoStatus(void)
6255 {
6256    for (int i = m_statusNumProtoNames + 1; i < m_numProtoNames; i++)
6257        m_protoNames.remove(i);
6258    m_numProtoNames=m_statusNumProtoNames;
6259    for (int i = m_statusNumProtoDefinitions + 1; i < m_numProtoDefinitions; i++)
6260        m_protoDefinitions.remove(i);
6261    m_numProtoDefinitions=m_statusNumProtoDefinitions;
6262 }
6263 
6264 StringArray *
getAllNodeNames(void)6265 Scene::getAllNodeNames(void)
6266 {
6267     StringArray *ret = new StringArray();
6268     ProtoMap::Chain::Iterator *j;
6269     for (int i = 0; i < m_protos.width(); i++) {
6270         for ( j = m_protos.chain(i).first(); j != NULL; j = j->next()) {
6271             ret->append(j->item()->getKey());
6272         }
6273     }
6274     return ret;
6275 }
6276 
6277 bool
use3dCursor(void)6278 Scene::use3dCursor(void)
6279 {
6280     switch (TheApp->Get3dCursorMode()) {
6281       case CM_3DCURSOR_ALWAYS:
6282          return m_use3dCursor;
6283       case CM_3DCURSOR_RECORDING:
6284         if (isRecording())
6285             return m_use3dCursor;
6286         break;
6287       case CM_3DCURSOR_NOT_RUN:
6288         if (!isRunning())
6289             return m_use3dCursor;
6290         break;
6291       case CM_3DCURSOR_NONE:
6292           return false;
6293     }
6294     return false;
6295 }
6296 
6297 // the proto PREFIX is also needed for the illegal2vrml program
6298 // undefined nodes named "something" are renamed to "PREFIXsomething"
6299 // when the proto "PREFIXsomething" is defined
6300 
6301 bool
setPrefix(char * prefix)6302 Scene::setPrefix(char* prefix)
6303 {
6304     if (prefix != NULL)
6305        TheApp->setPrefix(prefix);
6306     else {
6307        // compare all protonames to find out a common prefix
6308        bool prefixFound = false;
6309        if (getNumProtoNames() > 1) {
6310            MyString prefix = "";
6311            for (int numChar = 0; numChar < m_protoNames[0].length();
6312                numChar++) {
6313                char character = m_protoNames[0][numChar];
6314                bool sameCharacter = true;
6315                for (int i = 1; i < getNumProtoNames(); i++) {
6316                    if ((numChar >= m_protoNames[i].length()) ||
6317                        (m_protoNames[i][numChar] != character)) {
6318                        sameCharacter = false;
6319                        break;
6320                    }
6321                }
6322                if (sameCharacter) {
6323                    prefixFound = true;
6324                    prefix += character;
6325                } else
6326                    break;
6327            }
6328            if (prefixFound)
6329                TheApp->setPrefix(mystrdup(prefix));
6330        }
6331        if (!prefixFound) {
6332            errorf("can not find out prefix from only one node\n");
6333            errorf("prefix missing, use \"-prefix\" in commandline\n");
6334            return false;
6335        }
6336     }
6337     return true;
6338 }
6339 
6340 MyString
getNodeWithPrefix(const MyString & nodeType)6341 Scene::getNodeWithPrefix(const MyString &nodeType)
6342 {
6343     MyString newNodeType = "";
6344     newNodeType += TheApp->getPrefix();
6345     newNodeType += nodeType;
6346     return newNodeType;
6347 }
6348 
6349 void
setPathAllURL(const char * path)6350 Scene::setPathAllURL(const char *path)
6351 {
6352     const NodeList *nodes = getNodes();
6353     for (long i = 0; i < nodes->size(); i++) {
6354         Node *node = nodes->get(i);
6355         if (node->isInScene(this))
6356             for (int j = 0; j < node->getProto()->getNumFields(); j++) {
6357                 Field *field = node->getProto()->getField(j);
6358                 if ((field->getType() == MFSTRING) &&
6359                     ((field->getFlags() & FF_URL) != 0)) {
6360                     MFString* urls = (MFString *)node->getField(j);
6361                     for (int k = 0; k < urls->getSize(); k++) {
6362                         const char *urlk = urls->getValue(k);
6363                         if (!isSortOfEcmascript(urlk) && notURN(urlk)) {
6364                             URL url(getURL(), urlk);
6365                             MyString *newURL = new MyString("");
6366                             if (strlen(path) != 0) {
6367                                 *newURL += path;
6368                                 *newURL += "/";
6369                             }
6370                             *newURL += url.GetFileName();
6371                             urls->setValue(k, *newURL);
6372                         }
6373                     }
6374                 }
6375             }
6376     }
6377 }
6378 
6379 Node *
replaceNode(Node * oldNode,Node * newNode)6380 Scene::replaceNode(Node *oldNode, Node* newNode)
6381 {
6382     if (newNode == NULL)
6383         return NULL;
6384     if (oldNode->getParent() == NULL)
6385         return NULL;
6386     int numParents = oldNode->getNumParents();
6387     for (int i = 0; i <= numParents; i++) {
6388         Node *parent = oldNode->getParent(i);
6389         int field = oldNode->getParentField(i);
6390         if ((parent != NULL) && (field != -1)) {
6391             execute(new MoveCommand(oldNode, parent, field, NULL, -1));
6392             execute(new MoveCommand(newNode, NULL, -1, parent, field));
6393         }
6394     }
6395     if (numParents == 0)
6396         return NULL;
6397     return newNode;
6398 }
6399 
6400 Node *
convertToIndexedFaceSet(Node * node)6401 Scene::convertToIndexedFaceSet(Node* node)
6402 {
6403     if (!node->canConvertToIndexedFaceSet())
6404         return NULL;
6405 
6406     NodeIndexedFaceSet *meshNode = (NodeIndexedFaceSet *)
6407                                    node->toIndexedFaceSet();
6408 
6409     return replaceNode(node, meshNode);
6410 }
6411 
6412 int
writeIndexedFaceSet(int f,Node * node)6413 Scene::writeIndexedFaceSet(int f, Node* node)
6414 {
6415     NodeIndexedFaceSet *meshNode = (NodeIndexedFaceSet *)
6416                                    node->toIndexedFaceSet();
6417 
6418     meshNode->setVariableName(strdup(node->getVariableName()));
6419     int ret = meshNode->write(f, m_writeFlags);
6420     meshNode->unref();
6421     return ret;
6422 }
6423 
6424 Node *
convertToIndexedLineSet(Node * node)6425 Scene::convertToIndexedLineSet(Node* node)
6426 {
6427     if (!node->canConvertToIndexedLineSet())
6428         return NULL;
6429 
6430     NodeIndexedLineSet *chainNode = (NodeIndexedLineSet *)
6431                                     node->toIndexedLineSet();
6432     return replaceNode(node, chainNode);
6433 }
6434 
6435 void
recalibrate(void)6436 Scene::recalibrate(void)
6437 {
6438     TheApp->calibrateInputDevices();
6439     if (m_viewpoints.size() > 0) {
6440         m_currentViewpoint = (NodeViewpoint *) m_viewpoints[0];
6441     } else {
6442         m_currentViewpoint = m_defaultViewpoint;
6443     }
6444     applyCamera();
6445     UpdateViews(NULL, UPDATE_TIME);
6446 }
6447 
6448 void
makeSimilarName(Node * node,const char * name)6449 Scene::makeSimilarName(Node *node, const char *name)
6450 {
6451     if (!m_similarNameFlag)
6452         return;
6453     char* reducedName = mystrdup(name);
6454     int i;
6455     // strip _ number (e.g. _0 or _12) constructs at end
6456     for (i = strlen(name) - 1; i > 0; i--)
6457         if ((name[i] == '_') || ((name[i] >= '0') && (name[i] <= '9'))) {
6458             if (name[i] == '_')
6459                 reducedName[i] = 0;
6460         } else
6461             break;
6462     int len = strlen(name) + 512;
6463     char* buf = (char*) malloc(len);
6464     while (true) {
6465         mysnprintf(buf, len, "%s_%d", reducedName, i++);
6466         if (!hasAlreadyName(buf)) {
6467             MyString* newName = new MyString(buf);
6468             def(*newName, node);
6469             break;
6470         }
6471     }
6472     free(buf);
6473     free(reducedName);
6474 }
6475 
6476 ProtoArray *
getInteractiveProtos(int type)6477 Scene::getInteractiveProtos(int type)
6478 {
6479     switch(type)
6480       {
6481         case SFBOOL:
6482           return &m_interactiveSFBoolProtos;
6483         case SFROTATION:
6484           return &m_interactiveSFRotationProtos;
6485         case SFTIME:
6486           return &m_interactiveSFTimeProtos;
6487         case SFVEC3F:
6488           return &m_interactiveSFVec3fProtos;
6489       }
6490     return &m_emptyProtoArray;
6491 }
6492 
6493 void
buildInteractiveProtos(void)6494 Scene::buildInteractiveProtos(void)
6495 {
6496     int i = 0;
6497     m_interactiveSFBoolProtos[i++] = m_protos["CylinderSensor"];
6498     m_interactiveSFBoolProtos[i++] = m_protos["PlaneSensor"];
6499     m_interactiveSFBoolProtos[i++] = m_protos["ProximitySensor"];
6500     m_interactiveSFBoolProtos[i++] = m_protos["SphereSensor"];
6501     m_interactiveSFBoolProtos[i++] = m_protos["TouchSensor"];
6502     m_interactiveSFBoolProtos[i++] = m_protos["VisibilitySensor"];
6503     i = 0;
6504     m_interactiveSFRotationProtos[i++] = m_protos["CylinderSensor"];
6505     m_interactiveSFRotationProtos[i++] = m_protos["ProximitySensor"];
6506     m_interactiveSFRotationProtos[i++] = m_protos["SphereSensor"];
6507     if (TheApp->getCoverMode()) {
6508         m_interactiveSFRotationProtos[i++] = m_protos["COVER"];
6509         m_interactiveSFRotationProtos[i++] = m_protos["SpaceSensor"];
6510         m_interactiveSFRotationProtos[i++] = m_protos["ARSensor"];
6511     }
6512     i = 0;
6513     m_interactiveSFTimeProtos[i++] = m_protos["Collision"];
6514     m_interactiveSFTimeProtos[i++] = m_protos["ProximitySensor"];
6515     m_interactiveSFTimeProtos[i++] = m_protos["TouchSensor"];
6516     m_interactiveSFTimeProtos[i++] = m_protos["VisibilitySensor"];
6517     i = 0;
6518     m_interactiveSFVec3fProtos[i++] = m_protos["CylinderSensor"];
6519     m_interactiveSFVec3fProtos[i++] = m_protos["PlaneSensor"];
6520     m_interactiveSFVec3fProtos[i++] = m_protos["ProximitySensor"];
6521     m_interactiveSFVec3fProtos[i++] = m_protos["SphereSensor"];
6522     m_interactiveSFVec3fProtos[i++] = m_protos["TouchSensor"];
6523     if (TheApp->getCoverMode()) {
6524         m_interactiveSFVec3fProtos[i++] = m_protos["COVER"];
6525         m_interactiveSFVec3fProtos[i++] = m_protos["SpaceSensor"];
6526         m_interactiveSFVec3fProtos[i++] = m_protos["ARSensor"];
6527     }
6528 }
6529 
6530 void
setHeadlight(int headlight)6531 Scene::setHeadlight(int headlight)
6532 {
6533     // only use headlight of first NavigationInfo
6534     if (m_headlightIsSet == false) {
6535         m_headlight = headlight;
6536         m_headlightIsSet = true;
6537     }
6538 }
6539 
6540 int
getConstrain(void)6541 Scene::getConstrain(void)
6542 {
6543     int ret = CONSTRAIN_NONE;
6544     if (!m_xOnly && !m_yOnly && !m_zOnly)
6545         ret = CONSTRAIN_NONE;
6546     else if (m_xOnly && !m_yOnly && !m_zOnly)
6547         ret = CONSTRAIN_X;
6548     else if (!m_xOnly && m_yOnly && !m_zOnly)
6549         ret = CONSTRAIN_Y;
6550     else if (!m_xOnly && !m_yOnly && m_zOnly)
6551         ret = CONSTRAIN_Z;
6552     else if (m_xOnly && m_yOnly && !m_zOnly)
6553         ret = CONSTRAIN_XY;
6554     else if (m_xOnly && !m_yOnly && m_zOnly)
6555         ret = CONSTRAIN_ZX;
6556     else if (!m_xOnly && m_yOnly && m_zOnly)
6557         ret = CONSTRAIN_YZ;
6558     return ret;
6559 }
6560 
6561 Vec3f
constrainVec(Vec3f vec)6562 Scene::constrainVec(Vec3f vec)
6563 {
6564     Vec3f v(vec);
6565     if ((!m_xOnly) && (m_yOnly || m_zOnly))
6566         v.x = 0;
6567     if ((!m_yOnly) && (m_xOnly || m_zOnly))
6568         v.y=0;
6569     if ((!m_zOnly) && (m_xOnly || m_yOnly))
6570         v.z=0;
6571     return v;
6572 }
6573 
6574 void
setX3d(void)6575 Scene::setX3d(void)
6576 {
6577     m_writeFlags = m_writeFlags & ~(CONVERT2VRML);
6578     if ((!::isX3d(m_writeFlags)) && (m_root != NULL)) {
6579         getNodes()->clearFlag(NODE_FLAG_CONVERTED);
6580         m_writeFlags |= CONVERT2X3D;
6581         for (int i = 0; i < getNumProtos(); i++)
6582             for (int j = 0; j < getProto(i)->getNumNodes(); j++)
6583                 getProto(i)->getNode(j)->convert2X3d();
6584         m_root->convert2X3d();
6585     }
6586 }
6587 
6588 void
setX3dv(void)6589 Scene::setX3dv(void)
6590 {
6591     setX3d();
6592     if (!(m_writeFlags & PURE_X3DV))
6593         m_writeFlags |= X3DV;
6594 }
6595 
6596 void
setX3dXml(void)6597 Scene::setX3dXml(void)
6598 {
6599     setX3d();
6600     if (!(m_writeFlags & X3D_XML)) {
6601         m_writeFlags |= X3D_XML;
6602     }
6603 }
6604 
6605 void
setVrml(void)6606 Scene::setVrml(void)
6607 {
6608     m_writeFlags = m_writeFlags & ~(CONVERT2X3D);
6609     if (::isX3d(m_writeFlags) && (m_root != NULL)) {
6610         getNodes()->clearFlag(NODE_FLAG_CONVERTED);
6611         m_writeFlags |= CONVERT2VRML;
6612         m_writeFlags = m_writeFlags & ~(X3DV | X3D_XML);
6613         for (int i = 0; i < getNumProtos(); i++)
6614             for (int j = 0; j < getProto(i)->getNumNodes(); j++)
6615                 getProto(i)->getNode(j)->convert2Vrml();
6616         m_root->convert2Vrml();
6617     }
6618     m_writeFlags = m_writeFlags & ~(X3DV | X3D_XML);
6619 }
6620 
6621 void
convertProtos2X3d(void)6622 Scene::convertProtos2X3d(void) {
6623     ProtoMap::Chain::Iterator *j;
6624     for (int i = 0; i < m_protos.width(); i++)
6625         for (j = m_protos.chain(i).first(); j != NULL; j = j->next())
6626             j->item()->getData()->convert2X3d();
6627 }
6628 
6629 void
convertProtos2Vrml(void)6630 Scene::convertProtos2Vrml(void) {
6631     ProtoMap::Chain::Iterator *j;
6632     for (int i = 0; i < m_protos.width(); i++)
6633         for (j = m_protos.chain(i).first(); j != NULL; j = j->next())
6634             j->item()->getData()->convert2Vrml();
6635 }
6636 
6637 bool
isInvalidElement(Element * element)6638 Scene::isInvalidElement(Element *element)
6639 {
6640     bool x3d = isX3d();
6641     return !isValidElement(element, x3d);
6642 }
6643 
6644 bool
isValidElement(Element * element,bool x3d)6645 Scene::isValidElement(Element *element, bool x3d)
6646 {
6647     if (element == NULL)
6648         return false;
6649     int flags = element->getFlags();
6650     if (flags & FF_ALWAYS)
6651         return true;
6652     bool invalidX3d = (flags & FF_X3D_ONLY) && (!x3d);
6653     bool invalidKambi = (flags & FF_KAMBI_ONLY) && (!TheApp->getKambiMode());
6654     bool invalidX3dom = (flags & FF_X3DOM_ONLY) && (!TheApp->getX3domMode());
6655     bool invalidX3dKambi = (flags & (FF_X3D_ONLY | FF_KAMBI_ONLY)) &&
6656                            ((!x3d) && (!TheApp->getKambiMode()));
6657     if (
6658         (flags & FF_NEVER) ||
6659         invalidX3d || invalidKambi || invalidX3dKambi || invalidX3dom ||
6660         ((flags & FF_VRML_ONLY) && x3d) ||
6661         ((flags & FF_COVER_ONLY) && (!TheApp->getCoverMode())) ||
6662         ((flags & FF_ROOT_ONLY) && (getSelection()->getNode() != getRoot()))
6663        )
6664         return false;
6665     return true;
6666 }
6667 
6668 
6669 void
resetWriteFlags(int flags)6670 Scene::resetWriteFlags(int flags)
6671 {
6672     if (::isX3d(m_writeFlags) && (!::isX3d(flags)) && (m_root != NULL)) {
6673         m_writeFlags = flags & ~(CONVERT2X3D);
6674         m_writeFlags |= CONVERT2VRML;
6675         m_root->clearFlagRec(NODE_FLAG_CONVERTED);
6676         m_root->convert2Vrml();
6677     }
6678     if ((!::isX3d(m_writeFlags)) && ::isX3d(flags) && (m_root != NULL)) {
6679         m_writeFlags = flags & ~(CONVERT2VRML);
6680         m_writeFlags |= CONVERT2X3D;
6681         m_root->clearFlagRec(NODE_FLAG_CONVERTED);
6682         m_root->convert2X3d();
6683     }
6684     m_writeFlags = flags & ~(CONVERT2VRML | CONVERT2X3D);
6685 }
6686 
6687 void
changeRoutes(Node * toNode,int toField,Node * fromNode,int fromField)6688 Scene::changeRoutes(Node *toNode, int toField,
6689                     Node *fromNode, int fromField)
6690 {
6691     changeRoutes(toNode, toField, 0, fromNode, fromField, 0);
6692 }
6693 
6694 void
changeRoutes(Node * toNode,int toField,int toOffset,Node * fromNode,int fromField,int fromOffset)6695 Scene::changeRoutes(Node *toNode, int toField, int toOffset,
6696                     Node *fromNode, int fromField, int fromOffset)
6697 {
6698     SocketList::Iterator *i = NULL;
6699     CommandList *list = NULL;
6700 
6701     bool fromX3d = false;
6702     bool toX3d = false;
6703 
6704     Proto *fProto = fromNode->getProto();
6705     Field *fField = fProto->getField(fromField);
6706     int fEventIn = fProto->lookupEventIn(fField->getName(fromX3d), fromX3d);
6707     int fEventOut = fProto->lookupEventOut(fField->getName(fromX3d), fromX3d);
6708 
6709     Proto *tProto = toNode->getProto();
6710     Field *tField = tProto->getField(toField);
6711     int tEventIn = tProto->lookupEventIn(tField->getName(toX3d), toX3d);
6712     int tEventOut = tProto->lookupEventOut(tField->getName(toX3d), toX3d);
6713 
6714     if (fEventIn != -1)
6715         for (i = fromNode->getInput(fEventIn).first(); i != NULL;
6716              i = i->next()) {
6717             if (list == NULL)
6718                 list = new CommandList();
6719             list->append(new UnRouteCommand(i->item().getNode(),
6720                                             i->item().getField(),
6721                                             fromNode,
6722                                             fEventIn + fromOffset));
6723             list->append(new RouteCommand(i->item().getNode(),
6724                                           i->item().getField(),
6725                                           toNode, tEventIn + toOffset));
6726         }
6727     if (fEventOut != -1)
6728         for (i = fromNode->getOutput(fEventOut).first(); i != NULL;
6729              i = i->next()) {
6730             if (list == NULL)
6731                 list = new CommandList();
6732             list->append(new UnRouteCommand(fromNode, fEventOut + fromOffset,
6733                                             i->item().getNode(),
6734                                             i->item().getField()));
6735 
6736             list->append(new RouteCommand(toNode, tEventOut + toOffset,
6737                                           i->item().getNode(),
6738                                           i->item().getField()));
6739         }
6740     if (list) execute(list);
6741 }
6742 
6743 void
copyRoutes(Node * toNode,Node * fromNode)6744 Scene::copyRoutes(Node *toNode, Node *fromNode)
6745 {
6746     int j = -1;
6747     SocketList::Iterator *i = NULL;
6748     SocketList::Iterator *last = NULL;
6749     CommandList *list = NULL;
6750 
6751     Proto *fromProto = fromNode->getProto();
6752 
6753     for (j = 0; j < fromProto->getNumEventIns(); j++) {
6754         last = fromNode->getInput(j).last();
6755         for (i = fromNode->getInput(j).first(); i != NULL;
6756              i = i->next()) {
6757             if (list == NULL)
6758                 list = new CommandList();
6759             list->append(new RouteCommand(i->item().getNode(),
6760                                           i->item().getField(),
6761                                           toNode, j));
6762             if (i == last)
6763                break;
6764         }
6765    }
6766 
6767     for (j = 0; j < fromProto->getNumEventOuts(); j++) {
6768         last = fromNode->getInput(j).last();
6769         for (i = fromNode->getOutput(j).first(); i != NULL;
6770              i = i->next()) {
6771             if (list == NULL)
6772                 list = new CommandList();
6773             list->append(new RouteCommand(toNode, j,
6774                                           i->item().getNode(),
6775                                           i->item().getField()));
6776             if (i == last)
6777                break;
6778         }
6779     }
6780     if (list)
6781         execute(list);
6782 }
6783 
6784 void
copyRoutesToScene(Node * node)6785 Scene::copyRoutesToScene(Node *node) {
6786     int j = -1;
6787     SocketList::Iterator *i = NULL;
6788     CommandList *list = NULL;
6789 
6790     Proto *fromProto = node->getProto();
6791 
6792     for (j = 0; j < fromProto->getNumEventIns(); j++)
6793         for (i = node->getInput(j).first(); i != NULL;
6794              i = i->next()) {
6795             if (list == NULL)
6796                 list = new CommandList();
6797             list->append(new RouteCommand(i->item().getNode(),
6798                                           i->item().getField(),
6799                                           node, j));
6800         }
6801     for (j = 0; j < fromProto->getNumEventOuts(); j++)
6802         for (i = node->getOutput(j).first(); i != NULL;
6803              i = i->next()) {
6804             if (list == NULL)
6805                 list = new CommandList();
6806             list->append(new RouteCommand(node, j, i->item().getNode(),
6807                                                    i->item().getField()));
6808         }
6809     if (list)
6810         execute(list);
6811 
6812 }
6813 
6814 
searchBindableNodes(Node * node,void * data)6815 static bool searchBindableNodes(Node *node, void *data)
6816 {
6817     Scene *scene = (Scene *)data;
6818     if (node->getType() == VRML_VIEWPOINT)
6819         scene->addViewpoint(node);
6820     if (node->getType() == VRML_GEO_VIEWPOINT)
6821         scene->addViewpoint(node);
6822     else if (node->getType() == X3D_ORTHO_VIEWPOINT)
6823         scene->addViewpoint(node);
6824     else if (node->getType() == VRML_NAVIGATION_INFO)
6825         scene->addNavigationInfo(node);
6826     else if (node->getType() == VRML_BACKGROUND)
6827         scene->addBackground(node);
6828     else if (node->getType() == VRML_FOG)
6829         scene->addFog(node);
6830     return true;
6831 }
6832 
6833 void
findBindableNodes(void)6834 Scene::findBindableNodes(void)
6835 {
6836     if (m_root != NULL)
6837         m_root->doWithBranch(searchBindableNodes, this);
6838     setFirstNavigationInfo();
6839 }
6840 
convertToTriangleSet(Node * node,void * data)6841 static bool convertToTriangleSet(Node *node, void *data)
6842 {
6843     Scene *scene = (Scene *)data;
6844     if (node->canConvertToTriangleSet())
6845         scene->convertToTriangleSet(node);
6846     return true;
6847 }
6848 
6849 Node *
convertToTriangleSet(Node * node)6850 Scene::convertToTriangleSet(Node* node)
6851 {
6852     if (!node->canConvertToTriangleSet())
6853         return NULL;
6854 
6855     NodeTriangleSet *triangleNode = (NodeTriangleSet *)node->toTriangleSet();
6856 
6857     return replaceNode(node, triangleNode);
6858 }
6859 
branchConvertToTriangleSet(Node * node)6860 void Scene::branchConvertToTriangleSet(Node *node)
6861 {
6862     node->doWithBranch(::convertToTriangleSet, this);
6863 }
6864 
6865 Node *
convertToIndexedTriangleSet(Node * node)6866 Scene::convertToIndexedTriangleSet(Node* node)
6867 {
6868     if (!node->canConvertToIndexedTriangleSet())
6869         return NULL;
6870 
6871     NodeIndexedTriangleSet *meshNode = (NodeIndexedTriangleSet *)
6872                                        node->toIndexedTriangleSet();
6873 
6874     return replaceNode(node, meshNode);
6875 }
6876 
convertToIndexedTriangleSet(Node * node,void * data)6877 static bool convertToIndexedTriangleSet(Node *node, void *data)
6878 {
6879     Scene *scene = (Scene *)data;
6880     if (node->canConvertToIndexedTriangleSet())
6881         scene->convertToIndexedTriangleSet(node);
6882     return true;
6883 }
6884 
branchConvertToIndexedTriangleSet(Node * node)6885 void Scene::branchConvertToIndexedTriangleSet(Node *node)
6886 {
6887     node->doWithBranch(::convertToIndexedTriangleSet, this);
6888 }
6889 
convertToIndexedFaceSet(Node * node,void * data)6890 static bool convertToIndexedFaceSet(Node *node, void *data)
6891 {
6892     Scene *scene = (Scene *)data;
6893     if (node->canConvertToIndexedFaceSet())
6894         scene->convertToIndexedFaceSet(node);
6895     return true;
6896 }
6897 
branchConvertToIndexedFaceSet(Node * node)6898 void Scene::branchConvertToIndexedFaceSet(Node *node)
6899 {
6900     node->doWithBranch(::convertToIndexedFaceSet, this);
6901 }
6902 
createNormals(Node * node,void * data)6903 static bool createNormals(Node *node, void *data)
6904 {
6905     int normalField = node->getNormalField();
6906     if (normalField == -1)
6907         return true;
6908     // ignore Nodes with already set normal field
6909     if (((SFNode *)node->getField(normalField))->getValue() == NULL) {
6910         Node *nnormal = node->getScene()->createNode("Normal");
6911         if (nnormal != NULL) {
6912             MoveCommand *command = new MoveCommand(nnormal, NULL, -1,
6913                                                    node, normalField);
6914             command->execute();
6915             node->setNormalFromMesh(nnormal);
6916         }
6917     }
6918     return true;
6919 }
6920 
branchCreateNormals(Node * node)6921 void Scene::branchCreateNormals(Node *node)
6922 {
6923     node->doWithBranch(createNormals, NULL);
6924 }
6925 
createNormal(Node * node)6926 void Scene::createNormal(Node *node)
6927 {
6928     ::createNormals(node, NULL);
6929 }
6930 
createTextureCoordinates(Node * node,void * data)6931 static bool createTextureCoordinates(Node *node, void *data)
6932 {
6933     int texCoordField = node->getTexCoordField();
6934     if (texCoordField == -1)
6935         return true;
6936     // ignore Nodes with already set texCoord field
6937     if (((SFNode *)node->getField(texCoordField))->getValue() == NULL) {
6938         Node *ntexCoord = node->getScene()->createNode("TextureCoordinate");
6939         if (ntexCoord != NULL) {
6940             MoveCommand *command = new MoveCommand(ntexCoord, NULL, -1,
6941                                                    node, texCoordField);
6942             command->execute();
6943             node->setTexCoordFromMesh(ntexCoord);
6944         }
6945     }
6946     return true;
6947 }
6948 
6949 void
branchCreateTextureCoordinates(Node * node)6950 Scene::branchCreateTextureCoordinates(Node *node)
6951 {
6952     node->doWithBranch(createTextureCoordinates, NULL);
6953 }
6954 
6955 void
createTextureCoordinate(Node * node)6956 Scene::createTextureCoordinate(Node *node)
6957 {
6958     ::createTextureCoordinates(node, NULL);
6959 }
6960 
6961 bool
checkXSymetricOrSameHandle(int handle,MFVec3f * points)6962 Scene::checkXSymetricOrSameHandle(int handle, MFVec3f *points)
6963 {
6964     if ((handle >= points->getSFSize()) || (handle < 0))
6965         return true;
6966     Vec3f vIndex = points->getValue(handle);
6967     float epsilon = TheApp->GetHandleEpsilon();
6968     for (int i = 0; i < getSelectedHandlesSize(); i++) {
6969         int checkedHandle = getSelectedHandle(i);
6970         if ((checkedHandle >= points->getSFSize()) || (checkedHandle < 0))
6971             continue;
6972         if (checkedHandle != handle) {
6973             Vec3f vPoint = points->getValue(checkedHandle);
6974             if (   (fabs(vPoint.z - vIndex.z) < epsilon)
6975                 && (fabs(vPoint.y - vIndex.y) < epsilon)) {
6976                 if (fabs(vPoint.x - vIndex.x) < epsilon) {
6977                     if (isSingleSelectedHandle())
6978                         return true;
6979                 } else
6980                     if (fabs(vPoint.x + vIndex.x) < epsilon)
6981                         return true;
6982             }
6983         }
6984     }
6985     return false;
6986 }
6987 
6988 void
addMeta(const char * metaKey,const char * metaValue)6989 Scene::addMeta(const char *metaKey, const char* metaValue)
6990 {
6991     m_metaKeys.append(metaKey);
6992     m_metaValues.append(metaValue);
6993 }
6994 
6995 void
addUnit(const char * category,const char * name,double conversionFactor)6996 Scene::addUnit(const char *category, const char *name,
6997                double conversionFactor)
6998 {
6999     int found = -1;
7000     for (long i = 0; i < m_unitCategory.size(); i++)
7001         if (strcmp(m_unitCategory[i], category) == 0) {
7002             found = i;
7003             break;
7004         }
7005     if (found > -1) {
7006         m_unitName[found] = name;
7007         m_unitConversionFactor[found] = conversionFactor;
7008     } else {
7009         m_unitCategory.append(category);
7010         m_unitName.append(name);
7011         m_unitConversionFactor.append(conversionFactor);
7012     }
7013     setUnitLengthInit();
7014     setUnitAngleInit();
7015     SceneProtoMap::updateProtoMap(&m_protos, this);
7016 }
7017 
7018 void
setUnitLength(double f)7019 Scene::setUnitLength(double f)
7020 {
7021     m_unitLength = f;
7022 }
7023 
7024 void
setUnitLengthInit(void)7025 Scene::setUnitLengthInit(void)
7026 {
7027     for (long i = 0; i < m_unitCategory.size(); i++)
7028         if (strcmp(m_unitCategory[i], "length") == 0)
7029             m_unitLength = m_unitConversionFactor[i];
7030 }
7031 
7032 void
setUnitAngleInit(void)7033 Scene::setUnitAngleInit(void)
7034 {
7035     for (long i = 0; i < m_unitCategory.size(); i++)
7036         if (strcmp(m_unitCategory[i], "angle") == 0)
7037             m_unitAngle = m_unitConversionFactor[i];
7038 }
7039 
7040 void
setUnitAngle(double f)7041 Scene::setUnitAngle(double f)
7042 {
7043     m_unitAngle = f;
7044 }
7045 
7046 void
pushUnitLength(void)7047 Scene::pushUnitLength(void)
7048 {
7049    m_unitLengthStack.push(getUnitLength());
7050 }
7051 
7052 void
popUnitLength(void)7053 Scene::popUnitLength(void)
7054 {
7055    if (m_unitLengthStack.empty())
7056        setUnitLength(1);
7057    else
7058        setUnitLength(m_unitLengthStack.pop());
7059 }
7060 
7061 void
pushUnitAngle(void)7062 Scene::pushUnitAngle(void)
7063 {
7064    m_unitAngleStack.push(getUnitAngle());
7065 }
7066 
7067 void
popUnitAngle(void)7068 Scene::popUnitAngle(void)
7069 {
7070    if (m_unitAngleStack.empty())
7071        setUnitAngle(1);
7072    else
7073        setUnitAngle(m_unitAngleStack.pop());
7074 }
7075 
7076 void
addToSensorNodes(Node * node)7077 Scene::addToSensorNodes(Node *node)
7078 {
7079     for (long i = 0; i < m_sensorNodes.size(); i++)
7080         if (m_sensorNodes.get(i) == node)
7081             return;
7082     m_sensorNodes.append(node);
7083 }
7084 
7085 void
restoreSelectedHandles(void)7086 Scene::restoreSelectedHandles(void)
7087 {
7088     m_selectedHandles.resize(0);
7089     if (m_oldSelectedHandles.size() > 0) {
7090         for (long i = 0; i < m_oldSelectedHandles.size(); i++)
7091             m_selectedHandles.append(m_oldSelectedHandles[i]);
7092         m_lastSelectedHandle = m_oldLastSelectedHandle;
7093         m_singleSelectedHandle = m_selectedHandles.size() <= 1;
7094     } else {
7095         m_lastSelectedHandle = -1;
7096         m_singleSelectedHandle = true;
7097     }
7098     m_isNewSelectedHandle = false;
7099     setSelection(m_oldSelection->getPath());
7100     UpdateViews(NULL, UPDATE_SELECTION);
7101 }
7102 
7103 int
getX3dVersion(void)7104 Scene::getX3dVersion(void)
7105 {
7106     int ret = m_x3dVersion;
7107     const NodeList *nodes = getNodes();
7108     for (long i = 0; i < nodes->size(); i++) {
7109          Node *node = nodes->get(i);
7110          if (node->getX3dVersion() > ret)
7111              ret = node->getX3dVersion();
7112     }
7113 
7114     if (scene != NULL) {
7115         scene->setParsedX3dVersion(ret);
7116         scene->updateSceneMap();
7117     }
7118 
7119     return ret;
7120 }
7121 
7122 static Node *returnNode;
7123 
searchNodeById(Node * node,void * data)7124 static bool searchNodeById(Node *node, void *data)
7125 {
7126     int *id = (int *)data;
7127     if ((node != NULL) && (node->getId() == (*id))) {
7128         returnNode = node;
7129         return false;
7130     }
7131     return true;
7132 }
7133 
7134 
7135 Node *
searchProtoNodeIdInNode(Node * node,long id)7136 Scene::searchProtoNodeIdInNode(Node *node, long id)
7137 {
7138     returnNode = NULL;
7139     if (node->isPROTO()) {
7140         NodePROTO *nodePROTO = (NodePROTO *)node;
7141         for (int i = 0; i < nodePROTO->getNumIndexedNodes(); i++)
7142              if (nodePROTO->getIndexedNode(i)->getId() == id)
7143                  returnNode = nodePROTO->getIndexedNode(i);
7144     }
7145     return returnNode;
7146 }
7147 
7148 Node *
searchProtoNodeId(long id)7149 Scene::searchProtoNodeId(long id)
7150 {
7151     returnNode = NULL;
7152     for (long i = 0; i < m_nodes.size(); i++)
7153         if (m_nodes.get(i)->isPROTO()) {
7154             NodePROTO *protoNode = (NodePROTO *)m_nodes.get(i);
7155             for (int j = 0; j < protoNode->getNumProtoNodes(); j++) {
7156                 Node *rootNode = protoNode->getProtoNode(j);
7157                 rootNode->doWithBranch(searchNodeById, &id);
7158             }
7159         }
7160     return returnNode;
7161 }
7162 
7163 int
getProtoType(Proto * proto)7164 Scene::getProtoType(Proto *proto)
7165 {
7166     int lastNodeType = LAST_NODE;
7167     ProtoMap::Chain::Iterator *j;
7168     for (j = m_protos.getExtraData(); j != NULL; j = j->next()) {
7169         Proto *jproto = j->item()->getData();
7170         lastNodeType++;
7171         if (jproto == proto) {
7172             return lastNodeType;
7173         }
7174     }
7175     return -1;
7176 }
7177 
7178 void
setSelectionMode(int mode)7179 Scene::setSelectionMode(int mode)
7180 {
7181     int oldMode = getSelectionMode();
7182     m_selectionMode = mode;
7183     if (oldMode != mode) {
7184         Node *node = getSelection()->getNode();
7185         NodeIndexedFaceSet *faceSet = NULL;
7186         MyMesh *mesh = NULL;
7187         MFInt32 *ci = NULL;
7188         if (node->hasParent())
7189             if (node->getParent()->getType() == VRML_INDEXED_FACE_SET) {
7190                 faceSet = (NodeIndexedFaceSet *)node->getParent();
7191                 mesh = faceSet->getMesh();
7192                 ci = mesh->getCoordIndex();
7193             }
7194         if (faceSet == NULL)
7195             return;
7196         MyArray<int> oldSelection;
7197         for (int i = 0; i < getSelectedHandlesSize(); i++)
7198              oldSelection.append(getSelectedHandle(i));
7199         removeSelectedHandles();
7200 
7201         if ((oldMode == SELECTION_MODE_FACES) &&
7202             (mode == SELECTION_MODE_VERTICES)) {
7203             for (long i = 0; i < oldSelection.size(); i++) {
7204                 int handle = oldSelection[i];
7205                 for (int j = 0; j < mesh->getNumFaces(); j++) {
7206                     FaceData *face = mesh->getFace(j);
7207                     if (handle == j) {
7208                         int offset = face->getOffset();
7209                         for (int n = offset; n < offset +
7210                                                  face->getNumVertices(); n++)
7211                             addSelectedHandle(ci->getValue(n));
7212                     }
7213 
7214                 }
7215             }
7216             UpdateViews(NULL, UPDATE_REDRAW_3D, NULL);
7217         } else if ((oldMode == SELECTION_MODE_VERTICES) &&
7218                    (mode == SELECTION_MODE_FACES)) {
7219             for (int j = 0; j < mesh->getNumFaces(); j++) {
7220                 FaceData *face = mesh->getFace(j);
7221                 int offset = face->getOffset();
7222                 int vertexCount = 0;
7223                 for (int n = offset; n < offset + face->getNumVertices(); n++) {
7224                     for (long i = 0; i < oldSelection.size(); i++) {
7225                         int handle = oldSelection[i];
7226                         int meshVertex = ci->getValue(n);
7227                         if (meshVertex == handle)
7228                             vertexCount++;
7229                     }
7230                 }
7231                 if (vertexCount >= face->getNumVertices())
7232                     addSelectedHandle(j);
7233             }
7234             UpdateViews(NULL, UPDATE_REDRAW_3D, NULL);
7235         }
7236     }
7237 }
7238 
7239 
7240 void
addSelectionRange(int firstRangeHandle,int secondRangeHandle)7241 Scene::addSelectionRange(int firstRangeHandle, int secondRangeHandle)
7242 {
7243      if ((firstRangeHandle > -1) && (m_selection)) {
7244          Node *node = m_selection->getNode();
7245          if (node == NULL)
7246              return;
7247          Vec3f first = node->getVertex(firstRangeHandle);
7248          Vec3f second = node->getVertex(secondRangeHandle);
7249          float len = (second - first).length();
7250          bool addedHandle = false;
7251          for (int i = 0; i < node->getNumVertex(); i++) {
7252              if (i == firstRangeHandle)
7253                  continue;
7254              if (i == secondRangeHandle)
7255                  continue;
7256              if (node->validHandle(i) &&
7257                  (node->getVertex(i) - first).length() - len <=
7258                  TheApp->GetHandleEpsilon()) {
7259                  if (addSelectedHandle(i))
7260                      addedHandle = true;
7261              }
7262          }
7263          if (addedHandle) {
7264              UpdateViews(NULL, UPDATE_REDRAW_3D);
7265              m_firstSelectionRangeHandle = -1;
7266              m_isNewSelectedHandle = false;
7267          }
7268     }
7269 }
7270 
7271 void
hideSelectedVertices(void)7272 Scene::hideSelectedVertices(void)
7273 {
7274      float epsilon = TheApp->GetHandleEpsilon();
7275      Node *node = getSelection()->getNode();
7276      for (int i = 0; i < getSelectedHandlesSize(); i++) {
7277          if (getXSymetricMode() && node->validHandle(getSelectedHandle(i))) {
7278              Vec3f vertex = node->getVertex(getSelectedHandle(i));
7279              for (int j = 0; j < node->getNumVertex(); j++) {
7280                  Vec3f vec = node->getVertex(j);
7281                  if ((fabsf(vertex.x + vec.x) < epsilon) &&
7282                      (fabsf(vertex.y - vec.y) < epsilon) &&
7283                      (fabsf(vertex.z - vec.z) < epsilon))
7284                      m_hiddenVertices.append(j);
7285             }
7286          }
7287          if (node->validHandle(getSelectedHandle(i))) {
7288              Vec3f vertex = node->getVertex(getSelectedHandle(i));
7289              for (int j = 0; j < node->getNumVertex(); j++) {
7290                  Vec3f vec = node->getVertex(j);
7291                  if ((fabsf(vertex.x - vec.x) < epsilon) &&
7292                      (fabsf(vertex.y - vec.y) < epsilon) &&
7293                      (fabsf(vertex.z - vec.z) < epsilon))
7294                      m_hiddenVertices.append(j);
7295             }
7296          }
7297          m_hiddenVertices.append(getSelectedHandle(i));
7298      }
7299 }
7300 
7301 void
showOnlySelectedVertices(void)7302 Scene::showOnlySelectedVertices(void)
7303 {
7304      float epsilon = TheApp->GetHandleEpsilon();
7305      Node *node = getSelection()->getNode();
7306      IntArray notHiddenVertices;
7307      for (int i = 0; i < getSelectedHandlesSize(); i++) {
7308          if (getXSymetricMode() && node->validHandle(getSelectedHandle(i))) {
7309              Vec3f vertex = node->getVertex(getSelectedHandle(i));
7310              for (int j = 0; j < node->getNumVertex(); j++) {
7311                  Vec3f vec = node->getVertex(j);
7312                  if ((fabsf(vertex.x + vec.x) < epsilon) &&
7313                      (fabsf(vertex.y - vec.y) < epsilon) &&
7314                      (fabsf(vertex.z - vec.z) < epsilon))
7315                      notHiddenVertices.append(j);
7316             }
7317          }
7318          if (node->validHandle(getSelectedHandle(i))) {
7319              Vec3f vertex = node->getVertex(getSelectedHandle(i));
7320              for (int j = 0; j < node->getNumVertex(); j++) {
7321                  Vec3f vec = node->getVertex(j);
7322                  if ((fabsf(vertex.x - vec.x) < epsilon) &&
7323                      (fabsf(vertex.y - vec.y) < epsilon) &&
7324                      (fabsf(vertex.z - vec.z) < epsilon))
7325                      notHiddenVertices.append(j);
7326             }
7327          }
7328          notHiddenVertices.append(getSelectedHandle(i));
7329      }
7330      for (int i = 0; i < node->getNumVertex(); i++) {
7331          bool skip = false;
7332          for (long j = 0; j < notHiddenVertices.size(); j++)
7333              if (i == notHiddenVertices[j]) {
7334                  skip = true;
7335                  break;
7336              }
7337          if (!skip)
7338              m_hiddenVertices.append(i);
7339      }
7340 }
7341 
7342 void
warning(const char * string)7343 Scene::warning(const char* string)
7344 {
7345     int newIndex = m_warnings.size();
7346     m_warnings[newIndex] = "";
7347     m_warnings[newIndex] += string;
7348     swDebugf("%s\n", string);
7349 }
7350 
7351 MyArray<Node *> *
getViewPorts()7352 Scene::getViewPorts()
7353 {
7354     return &m_viewports;
7355 }
7356 
7357 
7358 void
warning(int id)7359 Scene::warning(int id)
7360 {
7361     char message[256];
7362     swLoadString(id, message, 255);
7363     warning(message);
7364 }
7365 
7366 void
warning(int id,const char * string)7367 Scene::warning(int id, const char *string)
7368 {
7369     char idText[256];
7370     static char text[256];
7371     swLoadString(id, idText, 255);
7372     mysnprintf(text, 255, idText, string);
7373     warning(text);
7374 }
7375 
7376 void
addToStore4ConvexHull(void)7377 Scene::addToStore4ConvexHull(void)
7378 {
7379     if (getSelectionMode() != SELECTION_MODE_VERTICES)
7380         return;
7381     Node *node = getSelection()->getNode();
7382     if (!node->getValidVertex())
7383         return;
7384 
7385     static Matrix transformMatrix;
7386     Path *trans = searchTransform();
7387     Node *transform = NULL;
7388     if (trans)
7389         transform = trans->getNode();
7390     if (transform) {
7391         transform->transform();
7392         transform->getMatrix(transformMatrix);
7393     }
7394     bool changed = false;
7395     float eps = TheApp->GetHandleEpsilon();
7396     for (int i = 0; i < getSelectedHandlesSize(); i++) {
7397          int handle = getSelectedHandle(i);
7398          if (handle >= NO_HANDLE)
7399              continue;
7400          Vec3f vertex = node->getVertex(handle);
7401          // also collect symetric handles
7402          if (getXSymetricMode())
7403              for (int j = 0; j < node->getNumVertex(); j++) {
7404                  if (j == handle)
7405                      continue;
7406                  Vec3f vec = node->getVertex(j);
7407                  if (vec.x != 0) {
7408                      if ((fabs(vertex.x + vec.x) < eps) &&
7409                          (fabs(vertex.y - vec.y) < eps) &&
7410                          (fabs(vertex.x - vec.z) < eps)) {
7411                          m_store4ConvexHull.append(transformMatrix * vec);
7412                          if ((m_convexHullCounter % 2) == 1)
7413                              m_store4Extrusion1ConvexHull.append(
7414                                  transformMatrix * vec);
7415                          else
7416                              m_store4Extrusion2ConvexHull.append(
7417                                  transformMatrix * vec);
7418                          break;
7419                      }
7420                  }
7421              }
7422          m_store4ConvexHull.append(transformMatrix * vertex);
7423          if ((m_convexHullCounter % 2) == 1)
7424              m_store4Extrusion1ConvexHull.append(transformMatrix * vertex);
7425          else
7426              m_store4Extrusion2ConvexHull.append(transformMatrix * vertex);
7427          changed = true;
7428     }
7429     if (changed)
7430         m_convexHullCounter++;
7431 
7432 }
7433 
7434 void
storeHtmlData(const char * data)7435 Scene::storeHtmlData(const char *data)
7436 {
7437     if (data)
7438         if (m_htmlData.size() > 0)
7439             m_htmlData[m_htmlData.size() - 1] += data;
7440 }
7441 
7442 void
storeHtmlElementAndAttributes(const char * element,const char ** attributes,int numAttributes,bool htmlFirstPart)7443 Scene::storeHtmlElementAndAttributes(const char *element,
7444                                      const char **attributes,
7445                                      int numAttributes, bool htmlFirstPart)
7446 {
7447     MyString begin = "";
7448     MyString end = "";
7449     if (strlen(element) > 0) {
7450         begin += "<";
7451         begin += element;
7452         for (int i = 0; i < numAttributes; i += 2) {
7453             begin += " ";
7454             begin += attributes[i];
7455             begin += "=";
7456             begin += "'";
7457             if (i + 1 < numAttributes)
7458                 begin += attributes[i + 1];
7459             begin += "'";
7460         }
7461         begin += ">";
7462 
7463         end += "</";
7464         end += element;
7465         end += ">";
7466     }
7467     m_htmlBegin.append(begin);
7468     m_htmlData.append("");
7469     m_htmlEnd.append(end);
7470     m_htmlFirstPart.append(htmlFirstPart);
7471 }
7472 
searchPROTO(Node * node,void * data)7473 static bool searchPROTO(Node *node, void *data)
7474 {
7475     bool *result = (bool *)data;
7476     if (node->isPROTO())
7477         *result = true;
7478     return true;
7479 }
7480 
7481 
7482 bool
hasPROTONodes(void)7483 Scene::hasPROTONodes(void)
7484 {
7485     bool result = false;
7486     m_root->doWithBranch(searchPROTO, &result, true, false, false, true, false);
7487     return result;
7488 }
7489 
setBoundingBox(Node * node,void * data)7490 static bool setBoundingBox(Node *node, void *data)
7491 {
7492     if (node != NULL)
7493         node->setBoundingBox();
7494     return true;
7495 }
7496 
7497 void
branchSetBbox(void)7498 Scene::branchSetBbox(void)
7499 {
7500     m_root->doWithBranch(setBoundingBox, NULL, false);
7501 }
7502 
7503 
7504 MyArray<Node *>*
searchInterpolators(void)7505 Scene::searchInterpolators(void)
7506 {
7507     MyArray<Node *> *targets;
7508     Node *node = getSelection()->getNode();
7509     for (int i = 0; i < node->getProto()->getNumEventIns(); i++) {
7510         for (SocketList::Iterator *j = node->getInput(i).first();
7511              j != NULL; j = j->next()) {
7512             Node *inputNode = j->item().getNode();
7513             if (!inputNode->isInterpolator())
7514                 continue;
7515             bool targetIsNew = true;
7516             for (long n = 0; n < targets->size(); n++)
7517                 if (inputNode == targets->get(n))
7518                     targetIsNew = false;
7519             if (targetIsNew)
7520                 targets->append(inputNode);
7521         }
7522     }
7523     return targets;
7524 }
7525 
7526 NodeList
searchTimeSensorInInterpolator(Node * interpolator)7527 Scene::searchTimeSensorInInterpolator(Node *interpolator)
7528 {
7529     NodeList targets;
7530     for (int k = 0; k < interpolator->getProto()->getNumEventIns(); k++) {
7531         for (SocketList::Iterator *l = interpolator->getInput(k).first();
7532              l != NULL; l = l->next()) {
7533             Node *targetNode = l->item().getNode();
7534             if (targetNode->getType() != VRML_TIME_SENSOR)
7535                 continue;
7536             bool targetIsNew = true;
7537             for (long n = 0; n < targets.size(); n++)
7538                 if (targetNode == targets[n])
7539                     targetIsNew = false;
7540             if (targetIsNew)
7541                 targets.append(targetNode);
7542         }
7543     }
7544     return targets;
7545 }
7546 
7547 MyArray<Node *> *
searchTimeSensors(void)7548 Scene::searchTimeSensors(void)
7549 {
7550     MyArray<Node *> *targets;
7551     Node *node = getSelection()->getNode();
7552     if (node->isInterpolator())
7553         targets = searchTimeSensorInInterpolator(node).copy();
7554     else {
7555         if (!node->hasInputs())
7556             return targets;
7557         for (int i = 0; i < node->getProto()->getNumEventIns(); i++) {
7558             for (SocketList::Iterator *j = node->getInput(i).first(); j != NULL;
7559                  j = j->next()) {
7560                 Node *inputNode = j->item().getNode();
7561                 if (!inputNode->isInterpolator())
7562                     continue;
7563                 NodeList interpolatorTargets;
7564                     searchTimeSensorInInterpolator(inputNode).copy();
7565                 for (int i = 0; i < interpolatorTargets.size(); i++)
7566                      targets->append(interpolatorTargets[i]);
7567            }
7568         }
7569     }
7570     return targets;
7571 }
7572 
7573 void
removeUse(Node * node)7574 Scene::removeUse(Node *node)
7575 {
7576     unuse(node->getName());
7577     UpdateViews(NULL, UPDATE_ALL, NULL);
7578 }
7579 
7580 void
makeEmpty(void)7581 Scene::makeEmpty(void)
7582 {
7583      NodeGroup *root = (NodeGroup *)getRoot();
7584      for (int i = 0; i < root->getChildren()->getSize(); i++) {
7585          MoveCommand command(root, root->getChildren()->getValue(i), i,
7586                              NULL, -1);
7587          command.execute();
7588      }
7589 }
7590 
FieldUpdate(Node * n,int f,int i)7591 FieldUpdate::FieldUpdate(Node *n, int f, int i)
7592 {
7593     node = n;
7594     field = f;
7595     index = i;
7596 }
7597 
7598 #include "MainWindow.h"
7599 
CreateDC(SWND canvas)7600 SDC CreateDC(SWND canvas)
7601 {
7602     if (swFromPtr(canvas) == 0) {
7603         return swCreateDC(TheApp->getCurrentMainWindow()->getParentWindow());
7604     }
7605     return swCreateDC(canvas);
7606 }
7607