root/OpenSceneGraph/trunk/src/osgPlugins/Inventor/ConvertFromInventor.cpp @ 11034

Revision 11034, 70.3 kB (checked in by robert, 5 years ago)

Build fixes for build without ref_ptr<> automatic type conversion

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
RevLine 
[2225]1#include "ConvertFromInventor.h"
[6419]2
[2225]3#include "PendulumCallback.h"
4#include "ShuttleCallback.h"
5
6// OSG headers
7#include <osg/MatrixTransform>
[5802]8#include <osg/Node>
[2225]9#include <osg/Geode>
10#include <osg/Notify>
11#include <osg/LineWidth>
12#include <osg/Point>
13#include <osg/TexEnv>
14#include <osg/Texture2D>
15#include <osg/PolygonMode>
16#include <osg/BlendFunc>
17#include <osg/Material>
18#include <osg/CullFace>
19#include <osg/LightModel>
[9053]20#include <osg/LightSource>
[5802]21#include <osg/ShadeModel>
[2225]22#include <osg/LOD>
23#include <osgUtil/TransformCallback>
24
25// Inventor headers
26#include <Inventor/SoDB.h>
27#include <Inventor/SoInteraction.h>
28#include <Inventor/nodes/SoSeparator.h>
[11032]29#include <Inventor/nodes/SoTransformSeparator.h>
[2225]30#include <Inventor/nodes/SoShape.h>
31#include <Inventor/nodes/SoVertexShape.h>
32#include <Inventor/nodes/SoLight.h>
33#include <Inventor/nodes/SoDirectionalLight.h>
34#include <Inventor/nodes/SoSpotLight.h>
35#include <Inventor/nodes/SoPointLight.h>
36#include <Inventor/nodes/SoRotor.h>
37#include <Inventor/nodes/SoPendulum.h>
38#include <Inventor/nodes/SoShuttle.h>
39#include <Inventor/nodes/SoLOD.h>
[6543]40#include <Inventor/nodes/SoTexture2.h>
[11032]41#include <Inventor/nodes/SoEnvironment.h>
[2225]42#include <Inventor/misc/SoChildList.h>
43#include <Inventor/SoPrimitiveVertex.h>
44#include <Inventor/SbLinear.h>
[9053]45#include <Inventor/nodes/SoTransform.h>
46#include <Inventor/nodes/SoInfo.h>
[11032]47#include <Inventor/actions/SoWriteAction.h>
48#include <Inventor/elements/SoModelMatrixElement.h>
[2225]49
[7348]50#ifdef __COIN__
[6544]51#include <Inventor/VRMLnodes/SoVRMLImageTexture.h>
[9053]52#include <Inventor/VRMLnodes/SoVRMLTransform.h>
53#include <Inventor/VRMLnodes/SoVRMLAppearance.h>
54#include <Inventor/VRMLnodes/SoVRMLMaterial.h>
[6544]55#endif
56
[11032]57#if defined(__COIN__) && (COIN_MAJOR_VERSION >= 3 || \
58    (COIN_MAJOR_VERSION == 2 && COIN_MINOR_VERSION>=5))
59#define INVENTOR_SHADERS_AVAILABLE
60#endif
[2225]61
[11032]62#ifdef INVENTOR_SHADERS_AVAILABLE
63#include <Inventor/nodes/SoShaderProgram.h>
64#include <Inventor/nodes/SoVertexShader.h>
65#include <Inventor/nodes/SoGeometryShader.h>
66#include <Inventor/nodes/SoFragmentShader.h>
67#endif
68
[2225]69#include <map>
[6544]70#include <assert.h>
[2225]71#include <math.h>
[9053]72#include <string.h>
[2225]73#ifdef __linux
74#include <values.h>
75#endif
76#ifdef __APPLE__
77#include <float.h>
78#endif
79
[3920]80#define DEBUG_IV_PLUGIN
[11032]81#define NOTIFY_HEADER "Inventor Plugin (reader): "
82
[5802]83///////////////////////////////////////////
[2225]84ConvertFromInventor::ConvertFromInventor()
85{
86    numPrimitives = 0;
[9053]87    transformInfoName = "";
88    appearanceName = "";
[2225]89}
[5802]90///////////////////////////////////////////
[2225]91ConvertFromInventor::~ConvertFromInventor()
92{
93}
[11032]94///////////////////////////////////////////////////////////////////
95static bool
96nodePreservesState(const SoNode *node)
97{
98    return node->isOfType(SoSeparator::getClassTypeId()) ||
99           (node->getChildren() != NULL && node->affectsState() == FALSE);
100}
101////////////////////////////////////////////////////////////////////
102SoCallbackAction::Response
103ConvertFromInventor::restructure(void* data, SoCallbackAction* action,
104                                 const SoNode* node)
105{
106#ifdef DEBUG_IV_PLUGIN
107    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "restructure() "
108              << node->getTypeId().getName().getString();
109#endif
110
111    int childrenTotal = 0;
112    int numModifiedChildren = 0;
113    int numRemovedNodes = 0;
114    std::vector<std::vector<int> > &stack = *((std::vector<std::vector<int> >*)data);
115
116    if (node->isOfType(SoGroup::getClassTypeId())) {
117
118        SoGroup *group = (SoGroup*)node;
119        SoGroup *affectedScene = NULL;
120        childrenTotal = group->getNumChildren();
121
122        for (int i=0, c=group->getNumChildren(); i<c; i++) {
123            SoNode *child = group->getChild(i);
124            if (!child->isOfType(SoSeparator::getClassTypeId()) &&
125                child->affectsState()) {
126
127                // Put the node bellow separator
128                SoSeparator *s = new SoSeparator;
129                s->addChild(group->getChild(i));
130                group->replaceChild(i, s);
131                numModifiedChildren++;
132
133                // Create the scene that may be affected by the node
134                if (!affectedScene) {
135
136                    // Create the graph of nodes that may be influenced
137                    // by the node
138                    const SoFullPath *path = (const SoFullPath*)action->getCurPath();
139                    assert(path->getLength() == 0 ||
140                           path->getNode(path->getLength()-1) == group &&
141                           "Group being restructured is not at the end of the path.");
142                    int stackLevel = stack.size()-2;
143                    for (int j=path->getLength()-2; j>=0; j--, stackLevel--) {
144
145                        // Get the appropriate stack level of nodesToRemove
146                        assert(stackLevel >=0);
147                        std::vector<int> &nodesToRemove = stack[stackLevel];
148
149                        // Get parent and index of the current group
150                        SoNode *parent = path->getNode(j);
151                        int childIndex = path->getIndex(j+1);
152                        const SoChildList *chl = parent->getChildren();
153                        assert(chl->operator[](childIndex) == path->getNode(j+1) &&
154                               "Wrong indexing.");
155
156                        // Create affected scene graph
157                        if (!affectedScene)
158                            affectedScene = new SoGroup;
159
160                        // Copy nodes to the graph
161                        for (int k=childIndex+1, n=chl->getLength(); k<n; k++) {
162                            affectedScene->addChild(chl->operator[](k));
163                            nodesToRemove.push_back(k);
164                            numRemovedNodes++;
165                        }
166
167                        // Stop recursion if we reached separator
168                        // or other state-preserving node.
169                        if (nodePreservesState(parent))
170                            break;
171                    }
172                }
173
174                // Append the affected graph to the separator
175                s->addChild(affectedScene);
176            }
177        }
178    }
179
180#ifdef DEBUG_IV_PLUGIN
181    if (numModifiedChildren == 0)
182        osg::notify(osg::DEBUG_INFO) << ": no changes necessary" << std::endl;
183    else
184        osg::notify(osg::DEBUG_INFO) << ": " << numModifiedChildren <<
185                  " nodes of " << childrenTotal << " restruc., " <<
186                  numRemovedNodes << " removed" << std::endl;
187#endif
188
189    return SoCallbackAction::CONTINUE;
190}
[5802]191///////////////////////////////////////////////////////////
[11032]192SoCallbackAction::Response
193ConvertFromInventor::restructurePreNode(void* data, SoCallbackAction* action,
194                             const SoNode* node)
195{
196    std::vector<std::vector<int> > &stack = *((std::vector<std::vector<int> >*)data);
197
198    stack.push_back(std::vector<int>());
199
200    return SoCallbackAction::CONTINUE;
201}
202////////////////////////////////////////////////////////////////////
203SoCallbackAction::Response
204ConvertFromInventor::restructurePostNode(void* data, SoCallbackAction* action,
205                              const SoNode* node)
206{
207    std::vector<std::vector<int> > &stack = *((std::vector<std::vector<int> >*)data);
208
209    assert(stack.size() > 0 && "Stack is empty");
210    std::vector<int> &nodesToRemove = stack.back();
211
212    if (nodesToRemove.size() > 0) {
213
214#ifdef DEBUG_IV_PLUGIN
215        osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "postNode()   "
216                  << node->getTypeId().getName().getString()
217                  << " (level " << stack.size() << ") removed "
218                  << nodesToRemove.size() << " node(s)" << std::endl;
219#endif
220
221        assert(node->getChildren());
222        for (int i=nodesToRemove.size()-1; i>=0; i--) {
223            assert(i==0 || nodesToRemove[i-1] < nodesToRemove[i] &&
224                   "Children to remove are not in order.");
225            node->getChildren()->remove(nodesToRemove[i]);
226        }
227    }
228
229    stack.pop_back();
230
231    return SoCallbackAction::CONTINUE;
232}
233///////////////////////////////////////////////////////////////////
234void
235ConvertFromInventor::preprocess(SoNode* root)
236{
237#ifdef DEBUG_IV_PLUGIN
238    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "Preprocessing..." << std::endl;
239#endif
240
241    SoCallbackAction action;
242    std::vector<std::vector<int> > stackOfNodesToRemove;
243
244    // Callbacks for troublesome nodes
245    action.addPreCallback(SoNode::getClassTypeId(),
246                          restructurePreNode, &stackOfNodesToRemove);
247    action.addPostCallback(SoLOD::getClassTypeId(),
248                           restructure, &stackOfNodesToRemove);
249    action.addPostCallback(SoNode::getClassTypeId(),
250                           restructurePostNode, &stackOfNodesToRemove);
251
252    // Traverse the scene
253    action.apply(root);
254
255#if 0 // For debugging purposes: Write preprocessed scene to the file
256    SoOutput out;
257    out.openFile("preprocess.iv");
258    SoWriteAction wa(&out);
259    wa.apply(root);
260#endif
261}
262///////////////////////////////////////////////////////////
263osg::Node*
264ConvertFromInventor::convert(SoNode* ivRootNode)
265{
266#ifdef DEBUG_IV_PLUGIN
267    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "Converting..." << std::endl;
268#endif
269
270    // Transformation matrix for converting Inventor coordinate system to OSG
[2225]271    // coordinate system
[6543]272    osg::Matrix ivToOSGMat(osg::Matrix(1.0, 0.0, 0.0, 0.0,
[2225]273                                       0.0, 0.0, 1.0, 0.0,
274                                       0.0,-1.0, 0.0, 0.0,
275                                       0.0, 0.0, 0.0, 1.0));
276
[11032]277    // Root of the scene
278    osg::ref_ptr<osg::Group> osgRootNode = new osg::MatrixTransform(ivToOSGMat);
[2225]279
[11032]280    // Initialize Inventor state stack
281    // (ivStateStack is used to track the state that is not accessible by
282    // SoCallbackAction functions)
[11034]283    ivStateStack.push(IvStateItem(ivRootNode, osgRootNode.get()));
[11032]284
285    // Create callback actions for the inventor nodes
[2225]286    // These callback functions perform the conversion
[6543]287    // note: if one class is derived from the other and both callbacks
288    // are registered, both functions will be called
[2225]289    SoCallbackAction cbAction;
[11032]290
291    // Node callbacks are used for detecting which node
292    // preserves state (like SoSeparator) and which not.
293    // There are few nodes that behave like SoSeparator although they
294    // are not derived from it.
295    // Note: postNode callback is moved down, because it must be
296    // called as the last callback.
297    cbAction.addPreCallback(SoNode::getClassTypeId(), preNode, this);
298
299    // SoTransformSeparator callbacks. Special handling of transformations.
300    cbAction.addPreCallback(SoTransformSeparator::getClassTypeId(), preTransformSeparator, this);
301    cbAction.addPostCallback(SoTransformSeparator::getClassTypeId(), postTransformSeparator, this);
302
303    // LOD (Level of Detail) callbacks. Handles SoLOD nodes.
304    // FIXME: SoLevelOfDetail needs to be implemented and tested.
305    cbAction.addPreCallback(SoLOD::getClassTypeId(), preLOD, this);
306    cbAction.addPostCallback(SoLOD::getClassTypeId(), postLOD, this);
307
308    // Shape callbacks collects all triangles and all the geometry data.
309    // Moreover, they handle transformations, ...
[2225]310    cbAction.addPreCallback(SoShape::getClassTypeId(), preShape, this);
311    cbAction.addPostCallback(SoShape::getClassTypeId(), postShape, this);
[11032]312
313    // Handling of textures
314    cbAction.addPostCallback(SoTexture2::getClassTypeId(),
315                            postTexture, this);
[7348]316#ifdef __COIN__
[11032]317    cbAction.addPostCallback(SoVRMLImageTexture::getClassTypeId(),
318                            postTexture, this);
319    cbAction.addPostCallback(SoVRMLAppearance::getClassTypeId(),
320                            postTexture, this);
321#endif
322
323#ifdef __COIN__
[9053]324    cbAction.addPreCallback(SoInfo::getClassTypeId(), preInfo, this);
[6544]325#endif
[11032]326
327    // Lights
[2225]328    cbAction.addPreCallback(SoLight::getClassTypeId(), preLight, this);
[11032]329
330    // Environment (ambient light,...)
331    cbAction.addPreCallback(SoEnvironment::getClassTypeId(), preEnvironment, this);
332
333    // Shaders
334#ifdef INVENTOR_SHADERS_AVAILABLE
335    cbAction.addPreCallback(SoShaderProgram::getClassTypeId(), preShaderProgram, this);
336#endif
337
338    // Motion callbacks
[2225]339    cbAction.addPreCallback(SoRotor::getClassTypeId(), preRotor, this);
340    cbAction.addPreCallback(SoPendulum::getClassTypeId(), prePendulum, this);
341    cbAction.addPreCallback(SoShuttle::getClassTypeId(), preShuttle, this);
[11032]342
343    // Geometry callbacks
[2225]344    cbAction.addTriangleCallback(SoShape::getClassTypeId(), addTriangleCB, this);
345    cbAction.addLineSegmentCallback(SoShape::getClassTypeId(), addLineSegmentCB,
346                                    this);
347    cbAction.addPointCallback(SoShape::getClassTypeId(), addPointCB, this);
[6543]348
[11032]349    // Post node callback
350    cbAction.addPostCallback(SoNode::getClassTypeId(), postNode, this);
351
[2225]352    // Traverse the inventor scene graph
[11032]353    cbAction.apply(ivRootNode);
[2225]354
[11032]355    // Remove superfluous group
356    if (osgRootNode->getNumChildren() == 1) {
357        osg::ref_ptr<osg::Group> toRemove = osgRootNode->getChild(0)->asGroup();
358        assert(toRemove.get() &&
359               strcmp(toRemove->className(), "Group") == 0 &&
360               "IvStateStack osg graph is expected to be "
361               "headed by osg::Group");
362        osgRootNode->removeChild(0u);
363        for (int i=0, c=toRemove->getNumChildren(); i<c; i++)
364            osgRootNode->addChild(toRemove->getChild(i));
[6543]365    }
[2225]366
[11032]367    return osgRootNode.get();
368}
369///////////////////////////////////////////////////////////////////
370static void
371notifyAboutMatrixContent(const osg::NotifySeverity level, const SbMatrix &m)
372{
373    SbVec3f t,s;
374    SbRotation r,so;
375    m.getTransform(t, r, s, so);
376    SbVec3f axis;
377    float angle;
378    r.getValue(axis, angle);
379    osg::notify(level) << NOTIFY_HEADER << "  Translation: " <<
380              t[0] << "," << t[1] << "," << t[2] << std::endl;
381    osg::notify(level) << NOTIFY_HEADER << "  Rotation: (" <<
382              axis[0] << "," << axis[1] << "," << axis[2] << ")," << angle << std::endl;
383}
384///////////////////////////////////////////////////////////////////
385void
386ConvertFromInventor::appendNode(osg::Node *n, const SoCallbackAction *action)
387{
388    IvStateItem &ivState = ivStateStack.top();
389    SbMatrix currentMatrix = action->getModelMatrix();
390    SbMatrix inheritedMatrix = ivState.inheritedTransformation;
[6543]391
[11032]392    // Keep children order - this must be done for some nodes like
393    // SoSwitch, SoLOD,...
394    // We will append dummy nodes if the child is expected to be on
395    // higher index.
396    if (ivState.flags & IvStateItem::KEEP_CHILDREN_ORDER) {
[2225]397
[11032]398        // Determine child index
399        int childIndex = -1;
400        const SoFullPath *path = (const SoFullPath*)(((SoCallbackAction*)action)->getCurPath());
401        for (int i=path->getLength()-2; i>=0; i--)
402            if (path->getNode(i) == ivState.keepChildrenOrderParent) {
403                childIndex = path->getIndex(i+1);
404                assert(ivState.keepChildrenOrderParent->getChildren());
405                assert((ivState.keepChildrenOrderParent->getChildren()->operator[](childIndex) == path->getNode(i+1)) && "Indexing is wrong.");
406                break;
407            }
408        assert(childIndex != -1 && "Node did not found.");
409
410        // Append dummy nodes to keep children order
411        assert(int(ivState.osgStateRoot->getNumChildren()) <= childIndex &&
412               "Number of children in ivState.osgStateRoot is too big.");
413        while (int(ivState.osgStateRoot->getNumChildren()) < childIndex)
414            ivState.osgStateRoot->addChild(new osg::Node);
415    }
416
417#ifdef DEBUG_IV_PLUGIN
418    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "appendNode: "
419              << n->className();
420#endif
421
422    if (currentMatrix == inheritedMatrix) {
423
424        // just append node to the current group in osg scene graph
425        ivState.osgStateRoot->addChild(n);
426        ivState.lastUsedTransformation = inheritedMatrix;
427
428#ifdef DEBUG_IV_PLUGIN
429        if (osg::isNotifyEnabled(osg::DEBUG_INFO))
430            osg::notify(osg::DEBUG_INFO) <<
431                      " uses parent transformation" << std::endl;
432#endif
433
434    } else {
435
436        if (!(ivState.flags & IvStateItem::KEEP_CHILDREN_ORDER) &&
437            currentMatrix == ivState.lastUsedTransformation) {
438
439            // Previous node has the same transformation. Let's use it.
440            assert(ivState.osgStateRoot->getNumChildren() != 0 &&
441                   "This should never happen - there is no item on "
442                   "osgShapeGraphs list while want to use last one.");
443            osg::Transform *t = ivState.osgStateRoot->getChild(ivState.osgStateRoot->getNumChildren()-1)->asTransform();
444            assert(t && "This should never happen - want to use "
445                        "transformation of previous scene geometry "
446                        "and it does not have Transform node.");
447            t->addChild(n);
448
449#ifdef DEBUG_IV_PLUGIN
450            if (osg::isNotifyEnabled(osg::DEBUG_INFO))
451                osg::notify(osg::DEBUG_INFO) <<
452                          " reuses previous transformation" << std::endl;
453#endif
454
455        } else {
456
457            // We need a new transformation node
458            osg::Matrix m(osg::Matrix(currentMatrix.operator float*()));
459            osg::Matrix m2;
460            m2.invert(osg::Matrix(inheritedMatrix.operator float*()));
461            m.postMult(m2);
462            osg::MatrixTransform *mt = new osg::MatrixTransform(m);
463            mt->addChild(n);
464
465            ivState.osgStateRoot->addChild(mt);
466            ivState.lastUsedTransformation = currentMatrix;
467
468#ifdef DEBUG_IV_PLUGIN
469            if (osg::isNotifyEnabled(osg::DEBUG_INFO)) {
470                osg::notify(osg::DEBUG_INFO) <<
471                          " uses local transformation:" << std::endl;
472                notifyAboutMatrixContent(osg::DEBUG_INFO,
473                          SbMatrix((SbMat&)(*osg::Matrixf(m).ptr())));
474            }
475#endif
476        }
477    }
[2225]478}
[5802]479///////////////////////////////////////////////////////////////////
[11032]480void
481ConvertFromInventor::ivPushState(const SoCallbackAction *action,
482                                 const SoNode *initiator, const int flags,
483                                 osg::Group *root)
484{
485    assert(ivStateStack.size() >= 1 && "There must be at least one "
486           "value in the ivStateStack to use ivPushState function.");
487
488    // APPEND_AT_PUSH
489    if (flags & IvStateItem::APPEND_AT_PUSH)
490        appendNode(root, action);
491
492    // Push state
493    ivStateStack.push(IvStateItem(ivStateStack.top(), action, initiator, flags, root));
494
495}
496///////////////////////////////////////////////////////////////////
497void
498ConvertFromInventor::ivPopState(const SoCallbackAction *action,
499                                const SoNode *initiator)
500{
501    bool multipop;
502    do {
503        assert(ivStateStack.size() >= 2 && "There must be at least two "
504               "values in the ivStateStack to use ivPopState function.");
505
506        // Get multipop value
507        IvStateItem ivState = ivStateStack.top();
508        multipop = ivState.flags & IvStateItem::MULTI_POP;
509        assert(multipop ||
510               ivState.pushInitiator == initiator &&
511               "ivStateStack push was initiated by different node.");
512
513        // Get osgStateRoot (note: we HAVE TO reference it)
[11034]514        osg::ref_ptr<osg::Group> r = ivState.osgStateRoot;
[11032]515
516        // Pop state
517        ivStateStack.pop();
518
519        // Update state from already popped values
520        if ((ivState.flags & (IvStateItem::UPDATE_STATE |
521            IvStateItem::UPDATE_STATE_EXCEPT_TRANSFORM)) != 0) {
522            IvStateItem &newTop = ivStateStack.top();
523            newTop.currentTexture = ivState.currentTexture;
524            newTop.currentLights = ivState.currentLights;
525            newTop.currentGLProgram = ivState.currentGLProgram;
526        }
527
528        // APPEND_AT_PUSH
529        if (!(ivState.flags & IvStateItem::APPEND_AT_PUSH))
[11034]530            appendNode(r.get(), action);
[11032]531
532    } while (multipop);
533
534}
535///////////////////////////////////////////////////////////////////
536SoCallbackAction::Response
537ConvertFromInventor::preNode(void* data, SoCallbackAction* action,
538                             const SoNode* node)
539{
540#ifdef DEBUG_IV_PLUGIN
541    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "preNode()    "
542              << node->getTypeId().getName().getString() << std::endl;
543#endif
544
545    if (nodePreservesState(node)) {
546
547        // push state
548        ConvertFromInventor *thisPtr = (ConvertFromInventor *) data;
549        thisPtr->ivPushState(action, node);
550#ifdef DEBUG_IV_PLUGIN
551        if (osg::isNotifyEnabled(osg::DEBUG_INFO)) {
552            osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "push state, saved values: " << std::endl;
553            notifyAboutMatrixContent(osg::DEBUG_INFO, action->getModelMatrix());
554        }
555#endif
556    }
557
558    return SoCallbackAction::CONTINUE;
559}
560////////////////////////////////////////////////////////////////////
561SoCallbackAction::Response
562ConvertFromInventor::postNode(void* data, SoCallbackAction* action,
[2225]563                              const SoNode* node)
564{
565#ifdef DEBUG_IV_PLUGIN
[11032]566    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "postNode()   "
[2225]567              << node->getTypeId().getName().getString() << std::endl;
568#endif
569
[11032]570    if (nodePreservesState(node)) {
571
572        // pop state
573        ConvertFromInventor *thisPtr = (ConvertFromInventor *) data;
574        assert(thisPtr->ivStateStack.size() > 0 && "ivStackState underflow");
575        thisPtr->ivPopState(action, node);
576
577#ifdef DEBUG_IV_PLUGIN
578        if (osg::isNotifyEnabled(osg::DEBUG_INFO)) {
579            osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER <<
580                      "pop state, restored transformation: " << std::endl;
581            notifyAboutMatrixContent(osg::DEBUG_INFO, action->getModelMatrix());
582        }
583#endif
584    }
585
586    return SoCallbackAction::CONTINUE;
587}
588///////////////////////////////////////////////////////////////////
589SoCallbackAction::Response
590ConvertFromInventor::preTransformSeparator(void* data, SoCallbackAction* action,
591                             const SoNode* node)
592{
593#ifdef DEBUG_IV_PLUGIN
594    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "preTransformSeparator()    "
595              << node->getTypeId().getName().getString() << std::endl;
596#endif
597
598    // push state
599    ConvertFromInventor *thisPtr = (ConvertFromInventor *) data;
600    thisPtr->ivPushState(action, node, IvStateItem::UPDATE_STATE_EXCEPT_TRANSFORM,
601                         new osg::Group());
602
603    return SoCallbackAction::CONTINUE;
604}
605////////////////////////////////////////////////////////////////////
606SoCallbackAction::Response
607ConvertFromInventor::postTransformSeparator(void* data, SoCallbackAction* action,
608                              const SoNode* node)
609{
610#ifdef DEBUG_IV_PLUGIN
611    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "postTransformSeparator()   "
612              << node->getTypeId().getName().getString() << std::endl;
613#endif
614
615    // pop state
616    ConvertFromInventor *thisPtr = (ConvertFromInventor *) data;
617    assert(thisPtr->ivStateStack.size() > 0 && "ivStackState underflow");
618    thisPtr->ivPopState(action, node);
619
620    return SoCallbackAction::CONTINUE;
621}
622///////////////////////////////////////////////////////////////////
623SoCallbackAction::Response
624ConvertFromInventor::preLOD(void* data, SoCallbackAction* action,
625                            const SoNode* node)
626{
627#ifdef DEBUG_IV_PLUGIN
628    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "preLOD()   "
629              << node->getTypeId().getName().getString() << std::endl;
630#endif
631
632    // init values
633    ConvertFromInventor* thisPtr = (ConvertFromInventor*)data;
634
635    // SoLOD
636    // Note: It is not possible to convert SoLOD to osg:LOD
637    // in any non-complex algorithm, because SoLOD does not preserves
638    // traversal state (like SoSeparator). Thus, following example
639    // can not be easily converted:
640    //
641    // SoLOD {
642    //   range [...]
643    //   Complexity { value 0.1 }
644    //   Complexity { value 0.2 }
645    //   Complexity { value 0.3 }
646    // }
647    // Sphere {}
648    //
649    // It was decided that it is necessary to preprocess scene
650    // in a way to avoid any state to come out of SoLOD. For example:
651    //
652    // SoLOD {
653    //   range [...]
654    //   Separator {
655    //     Complexity { value 0.1 }
656    //     DEF mySphere Sphere {}
657    //   }
658    //   Separator {
659    //     Complexity { value 0.2 }
660    //     USE mySphere
661    //   }
662    //   Separator {
663    //     Complexity { value 0.3 }
664    //     USE mySphere
665    //   }
666    // }
667    //
668    // Such scene can be converted easily to OSG.
669    if (node->isOfType(SoLOD::getClassTypeId())) {
670
671        thisPtr->ivPushState(action, node, IvStateItem::KEEP_CHILDREN_ORDER,
672                             new osg::LOD);
673        thisPtr->ivStateStack.top().keepChildrenOrderParent = node;
674
675        return SoCallbackAction::CONTINUE;
676    }
677
678    return SoCallbackAction::CONTINUE;
679}
680//////////////////////////////////////////////////////////////
681SoCallbackAction::Response
682ConvertFromInventor::postLOD(void* data, SoCallbackAction* action,
683                             const SoNode* node)
684{
685#ifdef DEBUG_IV_PLUGIN
686    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "postLOD()  "
687              << node->getTypeId().getName().getString() << std::endl;
688#endif
689
690    // SoGroup -> do nothing
691    if (node->getTypeId() == SoGroup::getClassTypeId())
692        return SoCallbackAction::CONTINUE;
693
694    // init values
695    ConvertFromInventor* thisPtr = (ConvertFromInventor*)data;
696    IvStateItem &ivState = thisPtr->ivStateStack.top();
697
698    // SoLOD
699    if (node->isOfType(SoLOD::getClassTypeId())) {
700
701        osg::LOD *lod = dynamic_cast<osg::LOD*>(ivState.osgStateRoot.get());
702        SoLOD *ivLOD = (SoLOD*)node;
703
704        // LOD center
705        SbVec3f ivCenter = ivLOD->center.getValue();
706        lod->setCenter(osg::Vec3(ivCenter[0], ivCenter[1], ivCenter[2]));
707
708        // Verify the number of children and range values
709        int num = lod->getNumChildren();
710        if (ivLOD->range.getNum()+1 != num &&
711            !(num == 0 && ivLOD->range.getNum() == 0)) {
712            osg::notify(osg::WARN) << NOTIFY_HEADER <<
713                      "Warning: SoLOD does not contain "
714                      "correct data in range field." << std::endl;
715            if (ivLOD->range.getNum()+1 < num) {
716                lod->removeChildren(ivLOD->range.getNum() + 1,
717                                    num - ivLOD->range.getNum() - 1);
718                num = ivLOD->range.getNum() + 1;
719            }
720        }
721
722        // Get the ranges and set it
723        if (num > 0) {
724            if (num == 1)
725                lod->setRange(0, 0.0, FLT_MAX);
726            else {
727                lod->setRange(0, 0.0, ivLOD->range[0]);
728                for (int i = 1; i < num-1; i++)
729                    lod->setRange(i, ivLOD->range[i-1], ivLOD->range[i]);
730                lod->setRange(num-1, ivLOD->range[num-2], FLT_MAX);
731            }
732        }
733
734#ifdef DEBUG_IV_PLUGIN
735        osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER <<
736                  "Appending osg::LOD with " << num << " children." << std::endl;
737#endif
738
739        assert(ivState.keepChildrenOrderParent == node &&
740               "Current node is not the root of keepChildrenOrder graph.");
741        thisPtr->ivPopState(action, node);
742
743        return SoCallbackAction::CONTINUE;
744    }
745
746    return SoCallbackAction::CONTINUE;
747}
748///////////////////////////////////////////////////////////////////
749SoCallbackAction::Response
750ConvertFromInventor::preShape(void* data, SoCallbackAction* action,
751                              const SoNode* node)
752{
753#ifdef DEBUG_IV_PLUGIN
754    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "preShape()   "
755              << node->getTypeId().getName().getString() << std::endl;
756#endif
757
[2225]758    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
759
760    // Normal and color binding map from Inventor to OSG
[11032]761    static std::map<SoNormalBinding::Binding, osg::Geometry::AttributeBinding>
[2225]762        normBindingMap;
763    static std::map<SoMaterialBinding::Binding, osg::Geometry::AttributeBinding>
764        colBindingMap;
765    static bool firstTime = true;
766    if (firstTime)
767    {
[11032]768        normBindingMap[SoNormalBinding::OVERALL]
[2225]769                                        = osg::Geometry::BIND_OVERALL;
[11032]770        normBindingMap[SoNormalBinding::PER_PART]
[2225]771                                        = osg::Geometry::BIND_PER_PRIMITIVE;
[11032]772        normBindingMap[SoNormalBinding::PER_PART_INDEXED]
[2225]773                                        = osg::Geometry::BIND_PER_PRIMITIVE;
[11032]774        normBindingMap[SoNormalBinding::PER_FACE]
[2225]775                                        = osg::Geometry::BIND_PER_PRIMITIVE;
[11032]776        normBindingMap[SoNormalBinding::PER_FACE_INDEXED]
[2225]777                                        = osg::Geometry::BIND_PER_PRIMITIVE;
[11032]778        normBindingMap[SoNormalBinding::PER_VERTEX]
[2225]779                                        = osg::Geometry::BIND_PER_VERTEX;
[11032]780        normBindingMap[SoNormalBinding::PER_VERTEX_INDEXED]
[2225]781                                        = osg::Geometry::BIND_PER_VERTEX;
782
[11032]783        colBindingMap[SoMaterialBinding::OVERALL]
[2225]784                                        = osg::Geometry::BIND_OVERALL;
785        colBindingMap[SoMaterialBinding::PER_PART]
786                                        = osg::Geometry::BIND_PER_PRIMITIVE;
[11032]787        colBindingMap[SoMaterialBinding::PER_PART_INDEXED]
[2225]788                                        = osg::Geometry::BIND_PER_PRIMITIVE;
789        colBindingMap[SoMaterialBinding::PER_FACE]
790                                        = osg::Geometry::BIND_PER_PRIMITIVE;
[11032]791        colBindingMap[SoMaterialBinding::PER_FACE_INDEXED]
[2225]792                                        = osg::Geometry::BIND_PER_PRIMITIVE;
[11032]793        colBindingMap[SoMaterialBinding::PER_VERTEX]
[2225]794                                        = osg::Geometry::BIND_PER_VERTEX;
[11032]795        colBindingMap[SoMaterialBinding::PER_VERTEX_INDEXED]
[2225]796                                        = osg::Geometry::BIND_PER_VERTEX;
797
798        firstTime = false;
799    }
800
801    // Get normal and color binding
802    if (node->isOfType(SoVertexShape::getClassTypeId()))
803    {
804        thisPtr->normalBinding = normBindingMap[action->getNormalBinding()];
805        thisPtr->colorBinding = colBindingMap[action->getMaterialBinding()];
806    }
807    else
808    {
809        thisPtr->normalBinding = osg::Geometry::BIND_PER_VERTEX;
810        thisPtr->colorBinding = osg::Geometry::BIND_PER_VERTEX;
811    }
812
813    // Check vertex ordering
814    if (action->getVertexOrdering() == SoShapeHints::CLOCKWISE)
815        thisPtr->vertexOrder = CLOCKWISE;
816    else
817        thisPtr->vertexOrder = COUNTER_CLOCKWISE;
818
819    // Clear the data from the previous shape callback
820    thisPtr->numPrimitives = 0;
821    thisPtr->vertices.clear();
822    thisPtr->normals.clear();
823    thisPtr->colors.clear();
824    thisPtr->textureCoords.clear();
[11032]825
[2225]826    return SoCallbackAction::CONTINUE;
827}
[5802]828///////////////////////////////////////////////////////////
829// OSG doesn't seem to have a transpose function         //
830//for matrices                                           //
831///////////////////////////////////////////////////////////
[11032]832void
833ConvertFromInventor::transposeMatrix(osg::Matrix& mat)
[2225]834{
835    float tmp;
[11032]836    for (int j = 0; j < 4; j++)
[2225]837    {
[11032]838        for (int i = j + 1; i < 4; i++)
[2225]839        {
840            tmp = mat.operator()(j,i);
841            mat.operator()(j,i) = mat.operator()(i,j);
842            mat.operator()(i,j) = tmp;
843        }
844    }
845
846}
[5802]847////////////////////////////////////////////////////////////////////
[11032]848SoCallbackAction::Response
849ConvertFromInventor::postShape(void* data, SoCallbackAction* action,
[3920]850                               const SoNode* node)
[2225]851{
852#ifdef DEBUG_IV_PLUGIN
[11032]853    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "postShape()  "
[2225]854              << node->getTypeId().getName().getString() << std::endl;
855#endif
856
857    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
858
[3920]859
860    // Create a new Geometry
[5802]861    osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
[3920]862
[2225]863
[5802]864    osg::ref_ptr<osg::Vec3Array> coords = new osg::Vec3Array(thisPtr->vertices.size());
[2225]865    for (unsigned int i = 0; i < thisPtr->vertices.size(); i++)
[9053]866        (*coords)[i] = thisPtr->vertices[i];
[5802]867    geometry->setVertexArray(coords.get());
[3920]868
[5802]869    osg::ref_ptr<osg::Vec3Array> norms = NULL;
[2225]870    if (thisPtr->normalBinding == osg::Geometry::BIND_OVERALL)
871    {
872        norms = new osg::Vec3Array(1);
873        const SbVec3f &norm = action->getNormal(0);
874        (*norms)[0].set(norm[0], norm[1], norm[2]);
875    }
876    else
877    {
878        norms = new osg::Vec3Array(thisPtr->normals.size());
879        for (unsigned int i = 0; i < thisPtr->normals.size(); i++)
880        {
[9053]881            (*norms)[i] = thisPtr->normals[i];
[2225]882        }
883    }
[5802]884    geometry->setNormalArray(norms.get());
[3920]885    geometry->setNormalBinding(thisPtr->normalBinding);
[2225]886
887    // Set the colors
[5802]888    osg::ref_ptr<osg::Vec4Array> cols;
[2225]889    if (thisPtr->colorBinding == osg::Geometry::BIND_OVERALL)
890    {
891        cols = new osg::Vec4Array(1);
892        SbColor ambient, diffuse, specular, emission;
893        float transparency, shininess;
[11032]894        action->getMaterial(ambient, diffuse, specular, emission, shininess,
[2225]895                            transparency, 0);
896        (*cols)[0].set(diffuse[0], diffuse[1], diffuse[2], 1.0 - transparency);
897    }
898    else
899    {
900        cols = new osg::Vec4Array(thisPtr->colors.size());
901        for (unsigned int i = 0; i < thisPtr->colors.size(); i++)
902            (*cols)[i] = thisPtr->colors[i];
903    }
[5802]904    geometry->setColorArray(cols.get());
[3920]905    geometry->setColorBinding(thisPtr->colorBinding);
[2225]906
907
[5802]908    if (thisPtr->textureCoords.empty())
[11032]909        osg::notify(osg::DEBUG_INFO)<<"tex coords not found"<<std::endl;
[5802]910    else {
[11032]911
[5802]912        // report texture coordinate conditions
913        if (action->getNumTextureCoordinates()>0)
[11032]914            osg::notify(osg::DEBUG_INFO)<<"tex coords found"<<std::endl;
[5802]915        else
[11032]916           osg::notify(osg::DEBUG_INFO)<<"tex coords generated"<<std::endl;
[5802]917
[3920]918        // Get the texture transformation matrix
919        osg::Matrix textureMat;
920        textureMat.set((float *) action->getTextureMatrix().getValue());
921
922        // Transform texture coordinates if texture matrix is not an identity mat
[5802]923        osg::Matrix identityMat;
924        identityMat.makeIdentity();
[11032]925        osg::ref_ptr<osg::Vec2Array> texCoords
[3920]926            = new osg::Vec2Array(thisPtr->textureCoords.size());
[5802]927        if (textureMat == identityMat)
[2225]928        {
[3920]929            // Set the texture coordinates
930            for (unsigned int i = 0; i < thisPtr->textureCoords.size(); i++)
931                (*texCoords)[i] = thisPtr->textureCoords[i];
[2225]932        }
[3920]933        else
934        {
935            // Transform and set the texture coordinates
936            for (unsigned int i = 0; i < thisPtr->textureCoords.size(); i++)
937            {
938                osg::Vec3 transVec = textureMat.preMult(
[11032]939                        osg::Vec3(thisPtr->textureCoords[i][0],
[3920]940                                  thisPtr->textureCoords[i][1],
941                                  0.0));
942                (*texCoords)[i].set(transVec.x(), transVec.y());
943            }
944        }
945
[5802]946        geometry->setTexCoordArray(0, texCoords.get());
[2225]947    }
[11032]948
[2225]949    // Set the parameters for the geometry
950
951    geometry->addPrimitiveSet(new osg::DrawArrays(thisPtr->primitiveType,0,
952                                                  coords->size()));
953    // Get the StateSet for the geoset
[5802]954    osg::ref_ptr<osg::StateSet> stateSet = thisPtr->getStateSet(action);
955    geometry->setStateSet(stateSet.get());
[11032]956
[2225]957    // Add the geoset to a geode
[5802]958    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
959    geode->addDrawable(geometry.get());
[2225]960
[9053]961    // copy name
962    std::string name = stateSet->getName();
963    if (name != "") {
964        geode->setName(name);
965    }
[2225]966
[11032]967    // Transformation and scene graph building
968    thisPtr->appendNode(geode.get(), action);
969
[2225]970    return SoCallbackAction::CONTINUE;
971}
[5802]972///////////////////////////////////////////////////////////////
[11032]973SoCallbackAction::Response
974ConvertFromInventor::postTexture(void* data, SoCallbackAction *,
975                                 const SoNode* node)
[2225]976{
977#ifdef DEBUG_IV_PLUGIN
[11032]978    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "postTexture()  "
979              << node->getTypeId().getName().getString();
980    if (node->isOfType(SoTexture2::getClassTypeId())) {
981        SoTexture2 *t = (SoTexture2*)node;
982        if (t->filename.getValue().getLength())
983            osg::notify(osg::DEBUG_INFO) << "  "  << t->filename.getValue().getString();
984    }
985    osg::notify(osg::DEBUG_INFO) << std::endl;
[2225]986#endif
[11032]987
[2225]988    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
[11032]989    bool texturingEnabled = false;
[9053]990
[11032]991    // Texture2
992    if (node->isOfType(SoTexture2::getClassTypeId())) {
993
994        // Check whether texturing was enabled by the texture node
995        SoTexture2 *t = (SoTexture2*)node;
996        SbVec2s size;
997        int nc;
998        const unsigned char *data = t->image.getValue(size, nc);
999        texturingEnabled = t->filename.getValue().getLength() ||
1000                           (data && size != SbVec2s(0,0));
1001    }
1002
[9053]1003#ifdef __COIN__
1004
[11032]1005    // SoVRMLImageTexture
1006    if (node->isOfType(SoVRMLImageTexture::getClassTypeId())) {
1007
1008        // Check whether texturing was enabled by the texture node
1009        SoVRMLImageTexture *t = (SoVRMLImageTexture*)node;
1010        texturingEnabled = t->url.getNum() > 1 || (t->url.getNum() == 1 && t->url[0].getLength() > 0);
[9053]1011    }
[11032]1012
1013    // SoVRMLAppearance
1014    if (node->isOfType(SoVRMLAppearance::getClassTypeId())) {
1015
1016        // If SoVRMLAppearance is present and there is no texture
1017        // inside, disable texturing
1018        // FIXME: should SoVRMLAppearance really disable texturing
1019        // when not containing SoVRMLImageTexture? Coin is not doing that,
1020        // but it can be Coin bug.
1021        SoVRMLAppearance *a = (SoVRMLAppearance*)node;
1022        if (a->texture.getValue() == NULL)
1023            thisPtr->ivStateStack.top().currentTexture = NULL;
1024
1025        // Do not try to "optimize" this code by removing the return
1026    // and use the one at the end of the function.
1027    // It would break the case when there is texture inside
1028    // the appearance node.
1029        return SoCallbackAction::CONTINUE;
[9053]1030    }
1031
[11032]1032#endif /* __COIN__ */
[6543]1033
[11032]1034    // Set current texture
1035    if (texturingEnabled)
1036        thisPtr->ivStateStack.top().currentTexture = node;
1037    else
1038        thisPtr->ivStateStack.top().currentTexture = NULL;
[6543]1039
1040    return SoCallbackAction::CONTINUE;
1041}
[5802]1042//////////////////////////////////////////////////////////////////
[11032]1043void ConvertFromInventor::transformLight(SoCallbackAction* action,
1044                                         const SbVec3f& vec,
[2225]1045                                         osg::Vec3& transVec)
1046{
1047    osg::Matrix modelMat;
1048    modelMat.set((float *)action->getModelMatrix().getValue());
1049
1050    transVec.set(vec[0], vec[1], vec[2]);
1051    transVec = modelMat.preMult(transVec);
1052}
[5802]1053///////////////////////////////////////////////////////////////////
[11032]1054SoCallbackAction::Response
1055ConvertFromInventor::preLight(void* data, SoCallbackAction* action,
[2225]1056                              const SoNode* node)
1057{
1058#ifdef DEBUG_IV_PLUGIN
[11032]1059    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "preLight()   "
[2225]1060              << node->getTypeId().getName().getString() << std::endl;
1061#endif
1062
1063    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
[11032]1064
[2225]1065    // Return if the light is not on
1066    const SoLight* ivLight = (const SoLight*) node;
1067    if (!ivLight->on.getValue())
1068        return SoCallbackAction::CONTINUE;
1069
[11032]1070    // Create new OSG light
1071    IvStateItem &ivState = thisPtr->ivStateStack.top();
[5802]1072    osg::ref_ptr<osg::Light> osgLight = new osg::Light;
[9053]1073
[11032]1074    // Light name
[9053]1075    const char* name = ivLight->getName().getString();
1076    osgLight->setName(name);
[11032]1077
[2225]1078    // Get color and intensity
1079    SbVec3f lightColor = ivLight->color.getValue();
1080    float intensity = ivLight->intensity.getValue();
1081
1082    // Set color and intensity
[11032]1083    osgLight->setAmbient(osg::Vec4(0.f, 0.f, 0.f, 1.f));
[2225]1084    osgLight->setDiffuse(osg::Vec4(lightColor[0] * intensity,
1085                                   lightColor[1] * intensity,
1086                                   lightColor[2] * intensity, 1));
[11032]1087    osgLight->setSpecular(osg::Vec4(lightColor[0] * intensity,
1088                                    lightColor[1] * intensity,
1089                                    lightColor[2] * intensity, 1));
[2225]1090
[11032]1091    // Light type
[2225]1092    if (node->isOfType(SoDirectionalLight::getClassTypeId()))
1093    {
1094        SoDirectionalLight *dirLight = (SoDirectionalLight *) node;
[11032]1095
1096#if 1 // Let's place the light to its place in scene graph instead of
1097      // old approach of global light group.
1098        SbVec3f l(dirLight->direction.getValue());
1099        osgLight->setPosition(osg::Vec4(l[0], l[1], l[2] , 0.));
1100#else
[2225]1101        osg::Vec3 transVec;
1102        thisPtr->transformLight(action, dirLight->direction.getValue(), transVec);
[11032]1103        osgLight->setPosition(osg::Vec4(transVec.x(), transVec.y(),
1104                                        transVec.z(), 0.));
1105#endif
[2225]1106    }
1107    else if (node->isOfType(SoPointLight::getClassTypeId()))
1108    {
1109        SoPointLight* ptLight = (SoPointLight *) node;
1110
[11032]1111#if 1 // Let's place the light to its place in scene graph instead of
1112      // old approach of global light group.
1113        SbVec3f l(ptLight->location.getValue());
1114        osgLight->setPosition(osg::Vec4(l[0], l[1], l[2] , 1.));
1115#else
[2225]1116        osg::Vec3 transVec;
1117        thisPtr->transformLight(action, ptLight->location.getValue(), transVec);
[11032]1118        osgLight->setPosition(osg::Vec4(transVec.x(), transVec.y(),
1119                                        transVec.z(), 1.));
1120#endif
[2225]1121    }
1122    else if (node->isOfType(SoSpotLight::getClassTypeId()))
1123    {
1124        SoSpotLight* spotLight = (SoSpotLight *) node;
1125
1126        osgLight->setSpotExponent(spotLight->dropOffRate.getValue() * 128.0);
[2915]1127        osgLight->setSpotCutoff(spotLight->cutOffAngle.getValue()*180.0/osg::PI);
[2225]1128
[11032]1129#if 1 // Let's place the light to its place in scene graph instead of
1130      // old approach of global light group.
1131        SbVec3f l(spotLight->location.getValue());
1132        osgLight->setPosition(osg::Vec4(l[0], l[1], l[2] , 1.));
1133        l = spotLight->direction.getValue();
1134        osgLight->setDirection(osg::Vec3(l[0], l[1], l[2]));
1135#else
[2225]1136        osg::Vec3 transVec;
1137        thisPtr->transformLight(action, spotLight->location.getValue(), transVec);
[11032]1138        osgLight->setPosition(osg::Vec4(transVec.x(), transVec.y(),
1139                                        transVec.z(), 1.));
[2225]1140
1141        thisPtr->transformLight(action, spotLight->direction.getValue(),transVec);
[11032]1142        osgLight->setDirection(osg::Vec3(transVec.x(), transVec.y(),
[2225]1143                                         transVec.z()));
[11032]1144#endif
[2225]1145    }
[11032]1146
1147    // Attenuation
1148    if (!node->isOfType(SoDirectionalLight::getClassTypeId())) {
1149        SbVec3f att = action->getLightAttenuation();
1150        osgLight->setConstantAttenuation(att[2]);
1151        osgLight->setLinearAttenuation(att[1]);
1152        osgLight->setQuadraticAttenuation(att[0]);
1153    } else {
1154        // keep default light settings for directional light, e.g.
1155        // no attenuation
[2225]1156    }
1157
[11032]1158    // Append the light into the scene and onto the state stack
1159    osgLight->setLightNum(ivState.currentLights.size());
1160    ivState.currentLights.push_back(osgLight);
1161
[9053]1162    osg::ref_ptr<osg::LightSource> ls = new osg::LightSource();
1163    ls->setLight(osgLight.get());
1164    ls->setName(ivLight->getName().getString());
[11032]1165#if 1 // Let's place the light to its place in scene graph instead of
1166      // old approach of global light group.
1167    thisPtr->ivPushState(action, node,
1168              IvStateItem::MULTI_POP | IvStateItem::UPDATE_STATE |
1169              IvStateItem::APPEND_AT_PUSH, ls.get());
1170#else
1171    if (!(thisPtr->lightGroup.get()))
1172        thisPtr->lightGroup = new osg::Group();
1173    thisPtr->lightGroup->addChild(ls);
1174#endif
1175
1176    return SoCallbackAction::CONTINUE;
1177}
1178///////////////////////////////////////////////////////////////////
1179SoCallbackAction::Response
1180ConvertFromInventor::preEnvironment(void* data, SoCallbackAction* action,
1181                                    const SoNode* node)
1182{
1183#ifdef DEBUG_IV_PLUGIN
1184    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "preLight()   "
1185              << node->getTypeId().getName().getString() << std::endl;
1186#endif
1187
1188    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
1189    IvStateItem &ivState = thisPtr->ivStateStack.top();
1190
1191    ivState.currentAmbientLight = ((SoEnvironment*)node)->ambientColor.getValue() *
1192                                  ((SoEnvironment*)node)->ambientIntensity.getValue();
1193
1194    return SoCallbackAction::CONTINUE;
1195}
1196///////////////////////////////////////////////////////////////////
1197#ifdef INVENTOR_SHADERS_AVAILABLE
1198static bool
1199convertShader(osg::Shader::Type osgShaderType,
1200              const SoShaderObject *ivShader,
1201              osg::Program *osgProgram)
1202{
1203    // NULL shader is not converted while returning success
1204    if (ivShader == NULL)
1205        return true;
1206
1207    // Create shader
1208    osg::ref_ptr<osg::Shader> osgShader = new osg::Shader(osgShaderType);
1209    if (ivShader->sourceType.getValue() == SoShaderObject::FILENAME)
1210        osgShader->loadShaderSourceFromFile(ivShader->sourceProgram.getValue().getString());
1211    else
1212    if (ivShader->sourceType.getValue() == SoShaderObject::GLSL_PROGRAM)
1213        osgShader->setShaderSource(ivShader->sourceProgram.getValue().getString());
1214    else {
1215        osg::notify(osg::WARN) << NOTIFY_HEADER << "Can not convert "
1216                  << "shader. Unsupported shader language." << std::endl;
1217        return false;
[9053]1218    }
1219
[11034]1220    return osgProgram->addShader(osgShader.get());
[11032]1221}
1222#endif // INVENTOR_SHADERS_AVAILABLE
1223///////////////////////////////////////////////////////////////////
1224SoCallbackAction::Response
1225ConvertFromInventor::preShaderProgram(void* data, SoCallbackAction* action,
1226                              const SoNode* node)
1227{
1228#ifdef DEBUG_IV_PLUGIN
1229    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "preShaderProgram()  "
1230              << node->getTypeId().getName().getString() << std::endl;
1231#endif
1232
1233#ifdef INVENTOR_SHADERS_AVAILABLE
1234
1235    ConvertFromInventor *thisPtr = (ConvertFromInventor*)data;
1236    IvStateItem &ivState = thisPtr->ivStateStack.top();
1237
1238    // Get Inventor nodes
1239    // Note: Shaders are available since Coin 2.5 (including
1240    // geometry shader)
1241    const SoShaderProgram *ivProgram = (const SoShaderProgram*)node;
1242    const SoVertexShader *ivVertexShader = NULL;
1243    const SoGeometryShader *ivGeometryShader = NULL;
1244    const SoFragmentShader *ivFragmentShader = NULL;
1245
1246    for (int i=0, c=ivProgram->shaderObject.getNum(); i<c; i++) {
1247
1248        const SoShaderObject *shader = (const SoShaderObject*)ivProgram->shaderObject[i];
1249        if (!shader->isOfType(SoShaderObject::getClassTypeId()))
1250            continue;
1251        if (shader->isActive.getValue() == FALSE)
1252            continue;
1253
1254        if (shader->isOfType(SoVertexShader::getClassTypeId()))
1255            ivVertexShader = (const SoVertexShader*)shader;
1256        if (shader->isOfType(SoGeometryShader::getClassTypeId()))
1257            ivGeometryShader = (const SoGeometryShader*)shader;
1258        if (shader->isOfType(SoFragmentShader::getClassTypeId()))
1259            ivFragmentShader = (const SoFragmentShader*)shader;
1260    }
1261
1262    // Create OSG shader
1263    osg::Program *osgProgram = new osg::Program();
1264    if (!convertShader(osg::Shader::VERTEX, ivVertexShader, osgProgram))
1265        osg::notify(osg::WARN) << NOTIFY_HEADER
1266                  << "Failed to add vertex shader." << std::endl;
1267    if (!convertShader(osg::Shader::GEOMETRY, ivGeometryShader, osgProgram))
1268        osg::notify(osg::WARN) << NOTIFY_HEADER
1269                  << "Failed to add geometry shader." << std::endl;
1270    if (!convertShader(osg::Shader::FRAGMENT, ivFragmentShader, osgProgram))
1271        osg::notify(osg::WARN) << NOTIFY_HEADER
1272                  << "Failed to add fragment shader." << std::endl;
1273
1274    // Put shader to the state stack
1275    ivState.currentGLProgram = osgProgram;
1276
1277#else
1278
1279    osg::notify(osg::WARN) << NOTIFY_HEADER << "Warning: The model "
1280              "contains shaders while your Inventor does not support "
1281              "them." << std::endl;
1282#endif
1283
[2225]1284    return SoCallbackAction::CONTINUE;
1285}
[5802]1286///////////////////////////////////////////////////////////////////////////////////////
[6543]1287osg::ref_ptr<osg::StateSet>
1288ConvertFromInventor::getStateSet(SoCallbackAction* action)
[2225]1289{
[5802]1290    osg::ref_ptr<osg::StateSet> stateSet = new osg::StateSet;
[11032]1291
[2225]1292    // Inherit modes from the global state
[3480]1293    stateSet->clear();
[2225]1294
[11032]1295    // Inventor State Stack
1296    IvStateItem &ivState = ivStateStack.top();
1297
[7348]1298    // Convert the IV texture to OSG texture if any
1299    osg::ref_ptr<osg::Texture2D> texture;
[11032]1300    const SoNode *ivTexture = ivState.currentTexture;
[7348]1301    if (ivTexture)
1302    {
1303        // Found a corresponding OSG texture object
1304        if (ivToOsgTexMap[ivTexture])
1305            texture = ivToOsgTexMap[ivTexture];
1306        else
1307        {
1308            // Create a new osg texture
1309            texture = convertIVTexToOSGTex(ivTexture, action);
1310
1311            // Add the new texture to the database
1312            ivToOsgTexMap[ivTexture] = texture.get();
1313        }
[11032]1314
[7348]1315        stateSet->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::ON);
[11032]1316
[9053]1317        // propogate name
[9451]1318        if(texture.valid())
1319        {
1320            std::string name = texture->getName();
1321            if (name != "")
1322                stateSet->setName(name);
1323        }
[7348]1324        // Set the texture environment
1325        osg::ref_ptr<osg::TexEnv> texEnv = new osg::TexEnv;
1326        switch (action->getTextureModel())
1327        {
1328            case SoTexture2::MODULATE:
1329                texEnv->setMode(osg::TexEnv::MODULATE);
1330                break;
1331            case SoTexture2::DECAL:
1332                texEnv->setMode(osg::TexEnv::DECAL);
1333                break;
[11032]1334            case SoTexture2::BLEND: {
[7348]1335                texEnv->setMode(osg::TexEnv::BLEND);
[11032]1336                SbColor c(action->getTextureBlendColor());
1337                texEnv->setColor(osg::Vec4(c[0], c[1], c[2], 1.f));
[7348]1338                break;
[11032]1339            }
[7348]1340            // SGI's Inventor does not have REPLACE mode, but the Coin 3D library does.
1341            // Coin supports REPLACE since 2.2 release, TGS Inventor from 4.0.
1342            // Let's convert to the TexEnv anyway.
[11032]1343            case 0x1E01: //SoTexture2::REPLACE:
[7348]1344                texEnv->setMode(osg::TexEnv::REPLACE);
1345                break;
[9585]1346            default:
[11032]1347                osg::notify(osg::WARN) << "Unsupported TexEnv mode." << std::endl;
[9585]1348                break;
1349
[7348]1350        }
1351        stateSet->setTextureAttributeAndModes(0,texEnv.get(),osg::StateAttribute::ON);
1352    }
1353
[2225]1354    SbColor ambient, diffuse, specular, emission;
1355    float shininess, transparency;
1356
1357    // Get the material colors
1358    action->getMaterial(ambient, diffuse, specular, emission,
[2485]1359                shininess, transparency, 0);
[11032]1360
[2225]1361    // Set transparency
[7348]1362    SbBool hasTextureTransparency = FALSE;
1363    if (ivTexture) {
1364      SbVec2s tmp;
[11032]1365      int bpp = 0;
[7348]1366      if (ivTexture->isOfType(SoTexture2::getClassTypeId()))
1367        ((SoTexture2*)ivTexture)->image.getValue(tmp, bpp);
1368#ifdef __COIN__
1369      else
1370      if (ivTexture->isOfType(SoVRMLImageTexture::getClassTypeId())) {
1371        const SbImage *img = ((SoVRMLImageTexture*)ivTexture)->getImage();
1372        if (img) img->getValue(tmp, bpp);
1373      }
1374#endif
1375      hasTextureTransparency = bpp==4 || bpp==2;
1376    }
1377
1378    if (transparency > 0 || hasTextureTransparency)
[2225]1379    {
[5802]1380        osg::ref_ptr<osg::BlendFunc> transparency = new osg::BlendFunc;
[11032]1381        stateSet->setAttributeAndModes(transparency.get(),
[2225]1382                                       osg::StateAttribute::ON);
[11032]1383
[2225]1384        // Enable depth sorting for transparent objects
1385        stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
1386    }
[11032]1387
[2225]1388    // Set linewidth
1389    if (action->getLineWidth())
1390    {
[5802]1391        osg::ref_ptr<osg::LineWidth> lineWidth = new osg::LineWidth;
[2225]1392        lineWidth->setWidth(action->getLineWidth());
[5802]1393        stateSet->setAttributeAndModes(lineWidth.get(), osg::StateAttribute::ON);
[2225]1394    }
1395
1396    // Set pointsize
1397    if (action->getPointSize())
1398    {
[5802]1399        osg::ref_ptr<osg::Point> point = new osg::Point;
[2225]1400        point->setSize(action->getPointSize());
[5802]1401        stateSet->setAttributeAndModes(point.get(), osg::StateAttribute::ON);
[2225]1402    }
[11032]1403
1404    // Set draw mode
[2225]1405    switch (action->getDrawStyle())
1406    {
1407        case SoDrawStyle::FILLED:
[3920]1408        {
1409#if 0
1410// OSG defaults to filled draw style, so no need to set redundent state.
1411            osg::PolygonMode *polygonMode = new osg::PolygonMode;
[11032]1412            polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
[2225]1413                                 osg::PolygonMode::FILL);
[3920]1414            stateSet->setAttributeAndModes(polygonMode, osg::StateAttribute::ON);
1415#endif
[2225]1416            break;
[3920]1417        }
[2225]1418        case SoDrawStyle::LINES:
[3920]1419        {
[5802]1420            osg::ref_ptr<osg::PolygonMode> polygonMode = new osg::PolygonMode;
[11032]1421            polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
[2225]1422                                 osg::PolygonMode::LINE);
[5802]1423            stateSet->setAttributeAndModes(polygonMode.get(), osg::StateAttribute::ON);
[2225]1424            break;
[3920]1425        }
[2225]1426        case SoDrawStyle::POINTS:
[3920]1427        {
[5802]1428            osg::ref_ptr<osg::PolygonMode> polygonMode = new osg::PolygonMode;
[11032]1429            polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
[2225]1430                                 osg::PolygonMode::POINT);
[5802]1431            stateSet->setAttributeAndModes(polygonMode.get(), osg::StateAttribute::ON);
[2225]1432            break;
[3920]1433        }
[2225]1434        case SoDrawStyle::INVISIBLE:
1435            // check how to handle this in osg.
1436            break;
1437    }
1438
1439    // Set back face culling
1440    if (action->getShapeType() == SoShapeHints::SOLID)
1441    {
[5802]1442        osg::ref_ptr<osg::CullFace> cullFace = new osg::CullFace;
[2225]1443        cullFace->setMode(osg::CullFace::BACK);
[5802]1444        stateSet->setAttributeAndModes(cullFace.get(), osg::StateAttribute::ON);
[11032]1445    }
[2225]1446
1447    // Set lighting
1448    if (action->getLightModel() == SoLightModel::BASE_COLOR)
1449        stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
1450    else
1451    {
1452        // Set the material
[5802]1453        osg::ref_ptr<osg::Material> material = new osg::Material;
[2225]1454
[11032]1455        material->setAmbient(osg::Material::FRONT_AND_BACK,
1456                             osg::Vec4(ambient[0], ambient[1], ambient[2],
[2225]1457                                       1.0 - transparency));
[11032]1458        material->setDiffuse(osg::Material::FRONT_AND_BACK,
1459                             osg::Vec4(diffuse[0], diffuse[1], diffuse[2],
[2225]1460                                       1.0 - transparency));
[11032]1461        material->setSpecular(osg::Material::FRONT_AND_BACK,
1462                              osg::Vec4(specular[0], specular[1], specular[2],
[2225]1463                                        1.0 - transparency));
[11032]1464        material->setEmission(osg::Material::FRONT_AND_BACK,
1465                              osg::Vec4(emission[0], emission[1], emission[2],
[2225]1466                                        1.0 - transparency));
1467        material->setTransparency(osg::Material::FRONT_AND_BACK, transparency);
1468        if (specular[0] || specular[1] || specular[2])
[11032]1469            material->setShininess(osg::Material::FRONT_AND_BACK,
[2225]1470                                   shininess*128.0);
1471        else
1472            material->setShininess(osg::Material::FRONT_AND_BACK, 0.0);
1473
1474        material->setColorMode(osg::Material::DIFFUSE);
1475
[5802]1476        stateSet->setAttributeAndModes(material.get(), osg::StateAttribute::ON);
[9053]1477        stateSet->setName(appearanceName.getString());
[2225]1478        stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
1479
[11032]1480        // Set global ambient light
1481        // note on osg::LightModel default values:
1482        //   colorControl: SINGLE_COLOR, localViewer: false, twoSided: false
1483        osg::LightModel *lightModel = new osg::LightModel();
1484        const SbColor &c = ivState.currentAmbientLight;
1485        lightModel->setAmbientIntensity(osg::Vec4(c[0], c[1], c[2], 1.0));
[3920]1486#if 0
1487// disable as two sided lighting causes problem under NVidia, and the above osg::Material settings are single sided anway..
[11032]1488update: The mentioned bug is probably just for very old NVidia drivers (commit time of the comment is 2005-03-18).
1489        The proper solution should be to set two sided lighting based on SoShapeHints node. Need to be developed. PCJohn-2010-01-20
[2225]1490        // Set two sided lighting
1491        lightModel->setTwoSided(true);
[11032]1492#endif
[2225]1493        stateSet->setAttributeAndModes(lightModel, osg::StateAttribute::ON);
[11032]1494
[2225]1495        // Set lights
[11032]1496        for (unsigned int i = 0; i < ivState.currentLights.size(); i++)
1497            stateSet->setAttributeAndModes(ivState.currentLights[i].get(),
[2225]1498                                           osg::StateAttribute::ON);
[11032]1499
[2225]1500    }
[11032]1501
1502    // Shader program setup
1503    if (ivState.currentGLProgram.get() != NULL) {
1504        stateSet->setAttributeAndModes(ivState.currentGLProgram.get(),
1505                                       osg::StateAttribute::ON);
1506    }
1507
1508    // Shader program uniforms
1509    if (ivState.currentGLProgram.get() != NULL) {
1510        for (int i=0, c=ivState.currentGLProgram->getNumShaders(); i<c; i++) {
1511             const std::string &shaderCode = ivState.currentGLProgram->getShader(i)->getShaderSource();
1512             if (shaderCode.find("coin_texunit0_model") != std::string::npos) {
1513                 int mode = (ivTexture!=NULL) ? action->getTextureModel() : 0;
1514                 stateSet->addUniform(new osg::Uniform("coin_texunit0_model", mode));
1515                 break;
1516             }
1517        }
1518    }
1519
[2225]1520    return stateSet;
1521}
[5802]1522////////////////////////////////////////////////////////////////////
[6543]1523osg::Texture2D*
1524ConvertFromInventor::convertIVTexToOSGTex(const SoNode* soNode,
[2225]1525                                          SoCallbackAction* action)
1526{
[11032]1527#ifdef DEBUG_IV_PLUGIN
1528    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER
1529              << "convertIVTexToOSGTex ("
1530              << soNode->getTypeId().getName().getString()
1531              << ")" << std::endl;
1532#endif
[3920]1533
[6543]1534    SbVec2s soSize;
1535    int soNC;
1536
[2225]1537    // Get the texture size and components
[6543]1538    const unsigned char* soImageData = action->getTextureImage(soSize, soNC);
1539    if (!soImageData) {
[11032]1540        osg::notify(osg::WARN) << NOTIFY_HEADER
1541                  << "Warning: Error while loading texture data." << std::endl;
[2225]1542        return NULL;
[6543]1543    }
1544
[2225]1545    // Allocate memory for image data
[6543]1546    unsigned char* osgImageData = new unsigned char[soSize[0] * soSize[1] * soNC];
1547
[2225]1548    // Copy the texture image data from the inventor texture
[6543]1549    memcpy(osgImageData, soImageData, soSize[0] * soSize[1] * soNC);
[2225]1550
[9053]1551    // Copy the name
1552    std::string name = soNode->getName().getString();
1553
[6543]1554    // File name
1555    std::string fileName;
1556    if (soNode->isOfType(SoTexture2::getClassTypeId()))
1557        fileName = ((SoTexture2*)soNode)->filename.getValue().getString();
[7348]1558#ifdef __COIN__
[6543]1559    else
1560    if (soNode->isOfType(SoVRMLImageTexture::getClassTypeId()))
[11032]1561        fileName = ((SoVRMLImageTexture*)soNode)->url.getNum() >= 1 ?
[6543]1562                   ((SoVRMLImageTexture*)soNode)->url.getValues(0)[0].getString() : "";
[6544]1563#endif
[6543]1564    else
[11032]1565      osg::notify(osg::WARN) << NOTIFY_HEADER
1566                << " Warning: Unsupported texture type: "
1567                << soNode->getTypeId().getName().getString() << std::endl;
[6543]1568
[11032]1569#ifdef DEBUG_IV_PLUGIN
1570    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER
1571              << "  Converting file name: " << fileName << " -> ";
1572#endif
[6543]1573    if (fileName[0]=='\"') fileName.erase(fileName.begin());
[11032]1574    if (fileName.size() > 0 && fileName[fileName.size()-1]=='\"')
[6543]1575        fileName.erase(fileName.begin()+fileName.size()-1);
[11032]1576#ifdef DEBUG_IV_PLUGIN
1577    osg::notify(osg::DEBUG_INFO) << fileName << std::endl;
1578#endif
[6543]1579
[11032]1580    // Create the osg::Image
[6543]1581    osg::ref_ptr<osg::Image> osgImage = new osg::Image;
1582    osgImage->setFileName(fileName);
[2225]1583    GLenum formats[] = {GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA};
[6543]1584    osgImage->setImage(soSize[0], soSize[1], 0, soNC, formats[soNC-1],
1585                       GL_UNSIGNED_BYTE, osgImageData, osg::Image::USE_NEW_DELETE);
[2225]1586
[6543]1587    // Create the osg::Texture2D
1588    osg::Texture2D *osgTex = new osg::Texture2D;
1589    osgTex->setImage(osgImage.get());
[9053]1590    if (name != "") {
1591        osgTex->setName(name);
1592    }
[2225]1593
1594    static std::map<SoTexture2::Wrap, osg::Texture2D::WrapMode> texWrapMap;
1595    static bool firstTime = true;
1596    if (firstTime)
1597    {
1598        texWrapMap[SoTexture2::CLAMP] = osg::Texture2D::CLAMP;
1599        texWrapMap[SoTexture2::REPEAT] = osg::Texture2D::REPEAT;
1600        firstTime = false;
1601    }
[11032]1602
[2225]1603    // Set texture wrap mode
[7348]1604#ifdef __COIN__
[6543]1605    if (soNode->isOfType(SoVRMLImageTexture::getClassTypeId())) {
1606        // It looks like there is a high probability of bug in Coin (investigated on version 2.4.6).
1607        // action->getTextureWrap() returns correct value on SoTexture2 (SoTexture2::CLAMP = 0x2900,
1608        // and REPEAT = 0x2901), but SoVRMLImageTexture returns incorrect value of
1609        // SoGLImage::REPEAT = 0, CLAMP = 1, CLAMP_TO_EDGE = 2).
1610        // So, let's not use action and try to get correct value directly from texture node.
1611        // PCJohn-2007-04-22
1612        osgTex->setWrap(osg::Texture2D::WRAP_S, ((SoVRMLImageTexture*)soNode)->repeatS.getValue() ?
1613            osg::Texture2D::REPEAT : osg::Texture2D::CLAMP_TO_EDGE);
1614        osgTex->setWrap(osg::Texture2D::WRAP_T, ((SoVRMLImageTexture*)soNode)->repeatT.getValue() ?
1615            osg::Texture2D::REPEAT : osg::Texture2D::CLAMP_TO_EDGE);
[6544]1616    }
1617    else
1618#endif
1619    {
[6543]1620        // Proper way to determine wrap mode
1621        osgTex->setWrap(osg::Texture2D::WRAP_S, texWrapMap[action->getTextureWrapS()]);
1622        osgTex->setWrap(osg::Texture2D::WRAP_T, texWrapMap[action->getTextureWrapT()]);
1623    }
[2225]1624
[11032]1625    return osgTex;
[2225]1626}
[5802]1627///////////////////////////////////////////////////////////////////
[11032]1628SoCallbackAction::Response
1629ConvertFromInventor::preInfo(void* data, SoCallbackAction* action,
1630                             const SoNode* node)
[2225]1631{
1632#ifdef DEBUG_IV_PLUGIN
[11032]1633    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "preInfo()    "
[9053]1634              << node->getTypeId().getName().getString() << std::endl;
1635#endif
1636    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
1637    SoInfo* info = (SoInfo*)node;
1638    thisPtr->transformInfoName = info->string.getValue();
1639
1640    return SoCallbackAction::CONTINUE;
1641}
[5802]1642/////////////////////////////////////////////////////////////
[11032]1643SoCallbackAction::Response
1644ConvertFromInventor::preRotor(void *data, SoCallbackAction *action,
1645                              const SoNode *node)
[2225]1646{
1647#ifdef DEBUG_IV_PLUGIN
[11032]1648    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "preRotor()  "
[2225]1649              << node->getTypeId().getName().getString() << std::endl;
1650#endif
1651
1652    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
1653
1654    // Get the parameters for the inventor Rotor
1655    SoRotor *ivRotor = (SoRotor *) node;
1656    SbVec3f ivAxis;
1657    float angle;
1658    ivRotor->rotation.getValue(ivAxis, angle);
1659
1660    // Create a new osg::MatrixTransform
[5802]1661    osg::ref_ptr<osg::MatrixTransform> rotorTransform = new osg::MatrixTransform;
[11032]1662
[2225]1663    // Create a Rotor Callback equivalent to the inventor Rotor
1664    osg::Vec3 pivot(0, 0, 0);
1665    osg::Vec3 axis(ivAxis[0], ivAxis[1], ivAxis[2]);
[11032]1666    osg::ref_ptr<osgUtil::TransformCallback> rotorCallback
1667        = new osgUtil::TransformCallback(pivot, axis,
[2915]1668                                         2 * osg::PI * ivRotor->speed.getValue());
[2225]1669
1670    // Set the app callback
[5802]1671    rotorTransform->setUpdateCallback(rotorCallback.get());
[2225]1672
[11032]1673    // Push the rotor onto the state stack
1674    thisPtr->ivPushState(action, node,
1675              IvStateItem::MULTI_POP | IvStateItem::UPDATE_STATE |
1676              IvStateItem::APPEND_AT_PUSH, rotorTransform.get());
1677
1678    // Append initial rotation to the model matrix
1679    if (!ivRotor->rotation.isIgnored()) {
1680        SoModelMatrixElement::rotateBy(action->getState(), ivRotor,
1681                                       ivRotor->rotation.getValue());
1682    }
1683
1684    // Don't do the traversal of the SoShuttle
1685    // since it was seen on Coin that is does not append just
1686    // initial shuttle position, but some interpolated one,
1687    // resulting in incorrect animation.
1688    return SoCallbackAction::PRUNE;
[2225]1689}
[5802]1690////////////////////////////////////////////////////////////////
[11032]1691SoCallbackAction::Response
1692ConvertFromInventor::prePendulum(void* data, SoCallbackAction *action,
[2225]1693                                 const SoNode* node)
1694{
1695#ifdef DEBUG_IV_PLUGIN
[11032]1696    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "prePendulum()  "
[2225]1697              << node->getTypeId().getName().getString() << std::endl;
1698#endif
1699
1700    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
1701
1702    // Get the parameters for the inventor Pendulum
1703    SoPendulum *ivPendulum = (SoPendulum *) node;
1704    SbVec3f ivAxis0, ivAxis1;
1705    float startAngle, endAngle;
1706    ivPendulum->rotation0.getValue(ivAxis0, startAngle);
1707    ivPendulum->rotation1.getValue(ivAxis1, endAngle);
[11032]1708    ivAxis0.normalize();
1709    ivAxis1.normalize();
[2225]1710
[11032]1711    // Reverse axis and direction if required
1712    // Actually, this will produce correct results only when axis is
1713    // opposite to each other, and approximate results when nearly
1714    // opposite and garbage otherwise.
1715    if ((ivAxis0+ivAxis1).length() < 0.5 ) {
1716        ivAxis1 = -ivAxis1;
1717        endAngle = -endAngle;
1718    }
1719
[2225]1720    // Create a new osg::MatrixTransform
[5802]1721    osg::ref_ptr<osg::MatrixTransform> pendulumTransform = new osg::MatrixTransform;
[11032]1722
[2225]1723    // Create a Pendulum Callback equivalent to the inventor Rotor
[11032]1724    // Use axis from of the bigger angle (to avoid lost axis when
1725    // angle is zero - see SbRotation and quaternion theory).
1726    osg::Vec3 axis;
1727    if (fabs(startAngle) > fabs(endAngle))
1728        axis = osg::Vec3(ivAxis0[0], ivAxis0[1], ivAxis0[2]);
1729    else
1730        axis = osg::Vec3(ivAxis1[0], ivAxis1[1], ivAxis1[2]);
1731    PendulumCallback* pendulumCallback
[2225]1732        = new PendulumCallback(axis, startAngle, endAngle,
1733                               ivPendulum->speed.getValue());
1734
1735    // Set the app callback
1736    pendulumTransform->setUpdateCallback(pendulumCallback);
1737
[11032]1738    // Push the pendulum onto the state stack
1739    thisPtr->ivPushState(action, node,
1740              IvStateItem::MULTI_POP | IvStateItem::UPDATE_STATE |
1741              IvStateItem::APPEND_AT_PUSH, pendulumTransform.get());
1742
1743    // Don't do the traversal of the SoShuttle
1744    // since it was seen on Coin that is does not append just
1745    // initial shuttle position, but some interpolated one,
1746    // resulting in incorrect animation.
1747    return SoCallbackAction::PRUNE;
[2225]1748}
[5802]1749////////////////////////////////////////////////////////////////
[11032]1750SoCallbackAction::Response
1751ConvertFromInventor::preShuttle(void* data, SoCallbackAction *action,
[2225]1752                                const SoNode* node)
1753{
1754#ifdef DEBUG_IV_PLUGIN
[11032]1755    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "preShuttle()  "
[2225]1756              << node->getTypeId().getName().getString() << std::endl;
1757#endif
1758
1759    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
1760
1761    // Get the parameters for the inventor Shuttle
1762    SoShuttle *ivShuttle = (SoShuttle *) node;
1763    SbVec3f ivStartPos, ivEndPos;
1764    ivStartPos = ivShuttle->translation0.getValue();
1765    ivEndPos = ivShuttle->translation1.getValue();
1766
1767    // Create a new osg::MatrixTransform
[5802]1768    osg::ref_ptr<osg::MatrixTransform> shuttleTransform = new osg::MatrixTransform;
[11032]1769
[2225]1770    // Create a shuttle Callback equivalent to the inventor Rotor
1771    osg::Vec3 startPos(ivStartPos[0], ivStartPos[1], ivStartPos[2]);
1772    osg::Vec3 endPos(ivEndPos[0], ivEndPos[1], ivEndPos[2]);
[11032]1773    ShuttleCallback* shuttleCallback
[2225]1774        = new ShuttleCallback(startPos, endPos, ivShuttle->speed.getValue());
1775
1776    // Set the app callback
1777    shuttleTransform->setUpdateCallback(shuttleCallback);
1778
[11032]1779    // Push the shuttle onto the state stack
1780    thisPtr->ivPushState(action, node,
1781              IvStateItem::MULTI_POP | IvStateItem::UPDATE_STATE |
1782              IvStateItem::APPEND_AT_PUSH, shuttleTransform.get());
1783
1784    // Don't do the traversal of the SoShuttle
1785    // since it was seen on Coin that is does not append just
1786    // initial shuttle position, but some interpolated one,
1787    // resulting in incorrect animation.
1788    return SoCallbackAction::PRUNE;
[2225]1789}
[5802]1790////////////////////////////////////////////////////////////
[2225]1791void ConvertFromInventor::addVertex(SoCallbackAction* action,
[11032]1792                                    const SoPrimitiveVertex *v,
[5802]1793                                    int index)
[2225]1794{
1795    // Get the coordinates of the vertex
1796    SbVec3f pt = v->getPoint();
1797    vertices.push_back(osg::Vec3(pt[0], pt[1], pt[2]));
1798
1799    // Get the normal of the vertex
1800    SbVec3f norm = v->getNormal();
1801
1802    if ((normalBinding == osg::Geometry::BIND_PER_VERTEX) ||
1803        (normalBinding == osg::Geometry::BIND_PER_PRIMITIVE && index == 0))
1804    {
[11032]1805        // What is this? Why to invert normals at CLOCKWISE vertex ordering?
1806        // PCJohn 2009-12-13
1807        //if (vertexOrder == CLOCKWISE)
1808        //    normals.push_back(osg::Vec3(-norm[0], -norm[1], -norm[2]));
1809        //else
[2225]1810            normals.push_back(osg::Vec3(norm[0], norm[1], norm[2]));
1811    }
1812
1813    if (colorBinding == osg::Geometry::BIND_PER_VERTEX ||
1814            colorBinding == osg::Geometry::BIND_PER_PRIMITIVE)
1815    {
[11032]1816        // Get the material/color
[2225]1817        SbColor ambient, diffuse, specular, emission;
1818        float transparency, shininess;
[11032]1819        action->getMaterial(ambient, diffuse, specular, emission, shininess,
[2225]1820                            transparency, v->getMaterialIndex());
1821        if (colorBinding == osg::Geometry::BIND_PER_VERTEX)
1822            colors.push_back(osg::Vec4(diffuse[0], diffuse[1], diffuse[2],
1823                                       1.0 - transparency));
1824        else if (colorBinding == osg::Geometry::BIND_PER_PRIMITIVE && index == 0)
1825            colors.push_back(osg::Vec4(diffuse[0], diffuse[1], diffuse[2],
1826                                       1.0 - transparency));
1827    }
1828
1829    // Get the texture coordinates
1830    SbVec4f texCoord = v->getTextureCoords();
1831    textureCoords.push_back(osg::Vec2(texCoord[0], texCoord[1]));
1832}
[5802]1833////////////////////////////////////////////////////////////////////////////
[2225]1834void ConvertFromInventor::addTriangleCB(void* data, SoCallbackAction* action,
[5802]1835                                        const SoPrimitiveVertex* v0,
[2225]1836                                        const SoPrimitiveVertex* v1,
1837                                        const SoPrimitiveVertex* v2)
1838{
1839    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
[11032]1840
[2225]1841    switch (thisPtr->vertexOrder)
1842    {
1843        case CLOCKWISE:
1844            thisPtr->addVertex(action, v0, 0);
1845            thisPtr->addVertex(action, v2, 1);
1846            thisPtr->addVertex(action, v1, 2);
1847            break;
1848        case COUNTER_CLOCKWISE:
1849            thisPtr->addVertex(action, v0, 0);
1850            thisPtr->addVertex(action, v1, 1);
1851            thisPtr->addVertex(action, v2, 2);
1852            break;
1853    }
1854
1855    thisPtr->numPrimitives++;
1856    thisPtr->primitiveType = osg::PrimitiveSet::TRIANGLES;
1857}
[5802]1858////////////////////////////////////////////////////////////////////////////////
[2225]1859void ConvertFromInventor::addLineSegmentCB(void* data, SoCallbackAction* action,
1860                                           const SoPrimitiveVertex* v0,
1861                                           const SoPrimitiveVertex* v1)
1862{
1863    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
1864
1865    thisPtr->addVertex(action, v0, 0);
1866    thisPtr->addVertex(action, v1, 1);
1867
1868    thisPtr->numPrimitives++;
1869    thisPtr->primitiveType = osg::PrimitiveSet::LINES;
1870}
[5802]1871//////////////////////////////////////////////////////////////////////////
[2225]1872void ConvertFromInventor::addPointCB(void* data, SoCallbackAction* action,
1873                                     const SoPrimitiveVertex* v0)
1874{
1875    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
1876
1877    thisPtr->addVertex(action, v0, 0);
1878
1879    thisPtr->numPrimitives++;
1880    thisPtr->primitiveType = osg::PrimitiveSet::POINTS;
1881}
Note: See TracBrowser for help on using the browser.