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

Revision 11032, 70.8 kB (checked in by robert, 4 years ago)

From Jan Peciva, "I am sending improved version of Inventor plugin. Attaching just
modified files, while GroupSoLOD.h and .cpp was deleted. Please, delete
it from repository, it is not used any longer and I doubt if it is
probably not used for anything meaningful for a while. In the new code,
there is no GroupSoLOD. Please, delete it.

I am using new plugin version for about 1.5 month so I consider it
stable by myself.

List of changes:
- rewritten Inventor state stack
- shaders support
- light attenuation support
- support for reading from stream (readNode(std::istream& fin, options))
- improved grouping node handling (SoSeparator?, SoGroup?,...)
- fixed transformation bug when two SoShapes/Drawables? with different transformations are placed bellow one grouping node
- introduced preprocessing to handle more advanced usage schemes of SoLOD and SoSwitch? nodes
- unused code clean up
- improved notify messages
- animation callbacks fixes
- FindInventor?.cmake improved finding routines, support for Coin3 and Coin4"

  • 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)
283    ivStateStack.push(IvStateItem(ivRootNode, osgRootNode));
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)
514        osg::Group *stateRoot = ivState.osgStateRoot;
515        osg::ref_ptr<osg::Group> r = stateRoot;
516/*    assert(strcmp(stateRoot->className(), "Group") == 0 &&
517           "IvStateStack osg graph is expected to be "
518           "headed by osg::Group");
519        if (stateRoot->getNumChildren() == 1) {
520            r = stateRoot->getChild(0)->asGroup();
521            osg::notify(osg::FATAL) << stateRoot->className() << std::endl;
522            osg::notify(osg::FATAL) << stateRoot->getChild(0)->className() << std::endl;
523            exit(0);
524            assert(r != NULL && "Node must be group.");
525        }*/
526
527        // Pop state
528        ivStateStack.pop();
529
530        // Update state from already popped values
531        if ((ivState.flags & (IvStateItem::UPDATE_STATE |
532            IvStateItem::UPDATE_STATE_EXCEPT_TRANSFORM)) != 0) {
533            IvStateItem &newTop = ivStateStack.top();
534            newTop.currentTexture = ivState.currentTexture;
535            newTop.currentLights = ivState.currentLights;
536            newTop.currentGLProgram = ivState.currentGLProgram;
537        }
538
539        // APPEND_AT_PUSH
540        if (!(ivState.flags & IvStateItem::APPEND_AT_PUSH))
541            appendNode(r, action);
542
543    } while (multipop);
544
545}
546///////////////////////////////////////////////////////////////////
547SoCallbackAction::Response
548ConvertFromInventor::preNode(void* data, SoCallbackAction* action,
549                             const SoNode* node)
550{
551#ifdef DEBUG_IV_PLUGIN
552    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "preNode()    "
553              << node->getTypeId().getName().getString() << std::endl;
554#endif
555
556    if (nodePreservesState(node)) {
557
558        // push state
559        ConvertFromInventor *thisPtr = (ConvertFromInventor *) data;
560        thisPtr->ivPushState(action, node);
561#ifdef DEBUG_IV_PLUGIN
562        if (osg::isNotifyEnabled(osg::DEBUG_INFO)) {
563            osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "push state, saved values: " << std::endl;
564            notifyAboutMatrixContent(osg::DEBUG_INFO, action->getModelMatrix());
565        }
566#endif
567    }
568
569    return SoCallbackAction::CONTINUE;
570}
571////////////////////////////////////////////////////////////////////
572SoCallbackAction::Response
573ConvertFromInventor::postNode(void* data, SoCallbackAction* action,
[2225]574                              const SoNode* node)
575{
576#ifdef DEBUG_IV_PLUGIN
[11032]577    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "postNode()   "
[2225]578              << node->getTypeId().getName().getString() << std::endl;
579#endif
580
[11032]581    if (nodePreservesState(node)) {
582
583        // pop state
584        ConvertFromInventor *thisPtr = (ConvertFromInventor *) data;
585        assert(thisPtr->ivStateStack.size() > 0 && "ivStackState underflow");
586        thisPtr->ivPopState(action, node);
587
588#ifdef DEBUG_IV_PLUGIN
589        if (osg::isNotifyEnabled(osg::DEBUG_INFO)) {
590            osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER <<
591                      "pop state, restored transformation: " << std::endl;
592            notifyAboutMatrixContent(osg::DEBUG_INFO, action->getModelMatrix());
593        }
594#endif
595    }
596
597    return SoCallbackAction::CONTINUE;
598}
599///////////////////////////////////////////////////////////////////
600SoCallbackAction::Response
601ConvertFromInventor::preTransformSeparator(void* data, SoCallbackAction* action,
602                             const SoNode* node)
603{
604#ifdef DEBUG_IV_PLUGIN
605    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "preTransformSeparator()    "
606              << node->getTypeId().getName().getString() << std::endl;
607#endif
608
609    // push state
610    ConvertFromInventor *thisPtr = (ConvertFromInventor *) data;
611    thisPtr->ivPushState(action, node, IvStateItem::UPDATE_STATE_EXCEPT_TRANSFORM,
612                         new osg::Group());
613
614    return SoCallbackAction::CONTINUE;
615}
616////////////////////////////////////////////////////////////////////
617SoCallbackAction::Response
618ConvertFromInventor::postTransformSeparator(void* data, SoCallbackAction* action,
619                              const SoNode* node)
620{
621#ifdef DEBUG_IV_PLUGIN
622    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "postTransformSeparator()   "
623              << node->getTypeId().getName().getString() << std::endl;
624#endif
625
626    // pop state
627    ConvertFromInventor *thisPtr = (ConvertFromInventor *) data;
628    assert(thisPtr->ivStateStack.size() > 0 && "ivStackState underflow");
629    thisPtr->ivPopState(action, node);
630
631    return SoCallbackAction::CONTINUE;
632}
633///////////////////////////////////////////////////////////////////
634SoCallbackAction::Response
635ConvertFromInventor::preLOD(void* data, SoCallbackAction* action,
636                            const SoNode* node)
637{
638#ifdef DEBUG_IV_PLUGIN
639    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "preLOD()   "
640              << node->getTypeId().getName().getString() << std::endl;
641#endif
642
643    // init values
644    ConvertFromInventor* thisPtr = (ConvertFromInventor*)data;
645
646    // SoLOD
647    // Note: It is not possible to convert SoLOD to osg:LOD
648    // in any non-complex algorithm, because SoLOD does not preserves
649    // traversal state (like SoSeparator). Thus, following example
650    // can not be easily converted:
651    //
652    // SoLOD {
653    //   range [...]
654    //   Complexity { value 0.1 }
655    //   Complexity { value 0.2 }
656    //   Complexity { value 0.3 }
657    // }
658    // Sphere {}
659    //
660    // It was decided that it is necessary to preprocess scene
661    // in a way to avoid any state to come out of SoLOD. For example:
662    //
663    // SoLOD {
664    //   range [...]
665    //   Separator {
666    //     Complexity { value 0.1 }
667    //     DEF mySphere Sphere {}
668    //   }
669    //   Separator {
670    //     Complexity { value 0.2 }
671    //     USE mySphere
672    //   }
673    //   Separator {
674    //     Complexity { value 0.3 }
675    //     USE mySphere
676    //   }
677    // }
678    //
679    // Such scene can be converted easily to OSG.
680    if (node->isOfType(SoLOD::getClassTypeId())) {
681
682        thisPtr->ivPushState(action, node, IvStateItem::KEEP_CHILDREN_ORDER,
683                             new osg::LOD);
684        thisPtr->ivStateStack.top().keepChildrenOrderParent = node;
685
686        return SoCallbackAction::CONTINUE;
687    }
688
689    return SoCallbackAction::CONTINUE;
690}
691//////////////////////////////////////////////////////////////
692SoCallbackAction::Response
693ConvertFromInventor::postLOD(void* data, SoCallbackAction* action,
694                             const SoNode* node)
695{
696#ifdef DEBUG_IV_PLUGIN
697    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "postLOD()  "
698              << node->getTypeId().getName().getString() << std::endl;
699#endif
700
701    // SoGroup -> do nothing
702    if (node->getTypeId() == SoGroup::getClassTypeId())
703        return SoCallbackAction::CONTINUE;
704
705    // init values
706    ConvertFromInventor* thisPtr = (ConvertFromInventor*)data;
707    IvStateItem &ivState = thisPtr->ivStateStack.top();
708
709    // SoLOD
710    if (node->isOfType(SoLOD::getClassTypeId())) {
711
712        osg::LOD *lod = dynamic_cast<osg::LOD*>(ivState.osgStateRoot.get());
713        SoLOD *ivLOD = (SoLOD*)node;
714
715        // LOD center
716        SbVec3f ivCenter = ivLOD->center.getValue();
717        lod->setCenter(osg::Vec3(ivCenter[0], ivCenter[1], ivCenter[2]));
718
719        // Verify the number of children and range values
720        int num = lod->getNumChildren();
721        if (ivLOD->range.getNum()+1 != num &&
722            !(num == 0 && ivLOD->range.getNum() == 0)) {
723            osg::notify(osg::WARN) << NOTIFY_HEADER <<
724                      "Warning: SoLOD does not contain "
725                      "correct data in range field." << std::endl;
726            if (ivLOD->range.getNum()+1 < num) {
727                lod->removeChildren(ivLOD->range.getNum() + 1,
728                                    num - ivLOD->range.getNum() - 1);
729                num = ivLOD->range.getNum() + 1;
730            }
731        }
732
733        // Get the ranges and set it
734        if (num > 0) {
735            if (num == 1)
736                lod->setRange(0, 0.0, FLT_MAX);
737            else {
738                lod->setRange(0, 0.0, ivLOD->range[0]);
739                for (int i = 1; i < num-1; i++)
740                    lod->setRange(i, ivLOD->range[i-1], ivLOD->range[i]);
741                lod->setRange(num-1, ivLOD->range[num-2], FLT_MAX);
742            }
743        }
744
745#ifdef DEBUG_IV_PLUGIN
746        osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER <<
747                  "Appending osg::LOD with " << num << " children." << std::endl;
748#endif
749
750        assert(ivState.keepChildrenOrderParent == node &&
751               "Current node is not the root of keepChildrenOrder graph.");
752        thisPtr->ivPopState(action, node);
753
754        return SoCallbackAction::CONTINUE;
755    }
756
757    return SoCallbackAction::CONTINUE;
758}
759///////////////////////////////////////////////////////////////////
760SoCallbackAction::Response
761ConvertFromInventor::preShape(void* data, SoCallbackAction* action,
762                              const SoNode* node)
763{
764#ifdef DEBUG_IV_PLUGIN
765    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "preShape()   "
766              << node->getTypeId().getName().getString() << std::endl;
767#endif
768
[2225]769    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
770
771    // Normal and color binding map from Inventor to OSG
[11032]772    static std::map<SoNormalBinding::Binding, osg::Geometry::AttributeBinding>
[2225]773        normBindingMap;
774    static std::map<SoMaterialBinding::Binding, osg::Geometry::AttributeBinding>
775        colBindingMap;
776    static bool firstTime = true;
777    if (firstTime)
778    {
[11032]779        normBindingMap[SoNormalBinding::OVERALL]
[2225]780                                        = osg::Geometry::BIND_OVERALL;
[11032]781        normBindingMap[SoNormalBinding::PER_PART]
[2225]782                                        = osg::Geometry::BIND_PER_PRIMITIVE;
[11032]783        normBindingMap[SoNormalBinding::PER_PART_INDEXED]
[2225]784                                        = osg::Geometry::BIND_PER_PRIMITIVE;
[11032]785        normBindingMap[SoNormalBinding::PER_FACE]
[2225]786                                        = osg::Geometry::BIND_PER_PRIMITIVE;
[11032]787        normBindingMap[SoNormalBinding::PER_FACE_INDEXED]
[2225]788                                        = osg::Geometry::BIND_PER_PRIMITIVE;
[11032]789        normBindingMap[SoNormalBinding::PER_VERTEX]
[2225]790                                        = osg::Geometry::BIND_PER_VERTEX;
[11032]791        normBindingMap[SoNormalBinding::PER_VERTEX_INDEXED]
[2225]792                                        = osg::Geometry::BIND_PER_VERTEX;
793
[11032]794        colBindingMap[SoMaterialBinding::OVERALL]
[2225]795                                        = osg::Geometry::BIND_OVERALL;
796        colBindingMap[SoMaterialBinding::PER_PART]
797                                        = osg::Geometry::BIND_PER_PRIMITIVE;
[11032]798        colBindingMap[SoMaterialBinding::PER_PART_INDEXED]
[2225]799                                        = osg::Geometry::BIND_PER_PRIMITIVE;
800        colBindingMap[SoMaterialBinding::PER_FACE]
801                                        = osg::Geometry::BIND_PER_PRIMITIVE;
[11032]802        colBindingMap[SoMaterialBinding::PER_FACE_INDEXED]
[2225]803                                        = osg::Geometry::BIND_PER_PRIMITIVE;
[11032]804        colBindingMap[SoMaterialBinding::PER_VERTEX]
[2225]805                                        = osg::Geometry::BIND_PER_VERTEX;
[11032]806        colBindingMap[SoMaterialBinding::PER_VERTEX_INDEXED]
[2225]807                                        = osg::Geometry::BIND_PER_VERTEX;
808
809        firstTime = false;
810    }
811
812    // Get normal and color binding
813    if (node->isOfType(SoVertexShape::getClassTypeId()))
814    {
815        thisPtr->normalBinding = normBindingMap[action->getNormalBinding()];
816        thisPtr->colorBinding = colBindingMap[action->getMaterialBinding()];
817    }
818    else
819    {
820        thisPtr->normalBinding = osg::Geometry::BIND_PER_VERTEX;
821        thisPtr->colorBinding = osg::Geometry::BIND_PER_VERTEX;
822    }
823
824    // Check vertex ordering
825    if (action->getVertexOrdering() == SoShapeHints::CLOCKWISE)
826        thisPtr->vertexOrder = CLOCKWISE;
827    else
828        thisPtr->vertexOrder = COUNTER_CLOCKWISE;
829
830    // Clear the data from the previous shape callback
831    thisPtr->numPrimitives = 0;
832    thisPtr->vertices.clear();
833    thisPtr->normals.clear();
834    thisPtr->colors.clear();
835    thisPtr->textureCoords.clear();
[11032]836
[2225]837    return SoCallbackAction::CONTINUE;
838}
[5802]839///////////////////////////////////////////////////////////
840// OSG doesn't seem to have a transpose function         //
841//for matrices                                           //
842///////////////////////////////////////////////////////////
[11032]843void
844ConvertFromInventor::transposeMatrix(osg::Matrix& mat)
[2225]845{
846    float tmp;
[11032]847    for (int j = 0; j < 4; j++)
[2225]848    {
[11032]849        for (int i = j + 1; i < 4; i++)
[2225]850        {
851            tmp = mat.operator()(j,i);
852            mat.operator()(j,i) = mat.operator()(i,j);
853            mat.operator()(i,j) = tmp;
854        }
855    }
856
857}
[5802]858////////////////////////////////////////////////////////////////////
[11032]859SoCallbackAction::Response
860ConvertFromInventor::postShape(void* data, SoCallbackAction* action,
[3920]861                               const SoNode* node)
[2225]862{
863#ifdef DEBUG_IV_PLUGIN
[11032]864    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "postShape()  "
[2225]865              << node->getTypeId().getName().getString() << std::endl;
866#endif
867
868    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
869
[3920]870
871    // Create a new Geometry
[5802]872    osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
[3920]873
[2225]874
[5802]875    osg::ref_ptr<osg::Vec3Array> coords = new osg::Vec3Array(thisPtr->vertices.size());
[2225]876    for (unsigned int i = 0; i < thisPtr->vertices.size(); i++)
[9053]877        (*coords)[i] = thisPtr->vertices[i];
[5802]878    geometry->setVertexArray(coords.get());
[3920]879
[5802]880    osg::ref_ptr<osg::Vec3Array> norms = NULL;
[2225]881    if (thisPtr->normalBinding == osg::Geometry::BIND_OVERALL)
882    {
883        norms = new osg::Vec3Array(1);
884        const SbVec3f &norm = action->getNormal(0);
885        (*norms)[0].set(norm[0], norm[1], norm[2]);
886    }
887    else
888    {
889        norms = new osg::Vec3Array(thisPtr->normals.size());
890        for (unsigned int i = 0; i < thisPtr->normals.size(); i++)
891        {
[9053]892            (*norms)[i] = thisPtr->normals[i];
[2225]893        }
894    }
[5802]895    geometry->setNormalArray(norms.get());
[3920]896    geometry->setNormalBinding(thisPtr->normalBinding);
[2225]897
898    // Set the colors
[5802]899    osg::ref_ptr<osg::Vec4Array> cols;
[2225]900    if (thisPtr->colorBinding == osg::Geometry::BIND_OVERALL)
901    {
902        cols = new osg::Vec4Array(1);
903        SbColor ambient, diffuse, specular, emission;
904        float transparency, shininess;
[11032]905        action->getMaterial(ambient, diffuse, specular, emission, shininess,
[2225]906                            transparency, 0);
907        (*cols)[0].set(diffuse[0], diffuse[1], diffuse[2], 1.0 - transparency);
908    }
909    else
910    {
911        cols = new osg::Vec4Array(thisPtr->colors.size());
912        for (unsigned int i = 0; i < thisPtr->colors.size(); i++)
913            (*cols)[i] = thisPtr->colors[i];
914    }
[5802]915    geometry->setColorArray(cols.get());
[3920]916    geometry->setColorBinding(thisPtr->colorBinding);
[2225]917
918
[5802]919    if (thisPtr->textureCoords.empty())
[11032]920        osg::notify(osg::DEBUG_INFO)<<"tex coords not found"<<std::endl;
[5802]921    else {
[11032]922
[5802]923        // report texture coordinate conditions
924        if (action->getNumTextureCoordinates()>0)
[11032]925            osg::notify(osg::DEBUG_INFO)<<"tex coords found"<<std::endl;
[5802]926        else
[11032]927           osg::notify(osg::DEBUG_INFO)<<"tex coords generated"<<std::endl;
[5802]928
[3920]929        // Get the texture transformation matrix
930        osg::Matrix textureMat;
931        textureMat.set((float *) action->getTextureMatrix().getValue());
932
933        // Transform texture coordinates if texture matrix is not an identity mat
[5802]934        osg::Matrix identityMat;
935        identityMat.makeIdentity();
[11032]936        osg::ref_ptr<osg::Vec2Array> texCoords
[3920]937            = new osg::Vec2Array(thisPtr->textureCoords.size());
[5802]938        if (textureMat == identityMat)
[2225]939        {
[3920]940            // Set the texture coordinates
941            for (unsigned int i = 0; i < thisPtr->textureCoords.size(); i++)
942                (*texCoords)[i] = thisPtr->textureCoords[i];
[2225]943        }
[3920]944        else
945        {
946            // Transform and set the texture coordinates
947            for (unsigned int i = 0; i < thisPtr->textureCoords.size(); i++)
948            {
949                osg::Vec3 transVec = textureMat.preMult(
[11032]950                        osg::Vec3(thisPtr->textureCoords[i][0],
[3920]951                                  thisPtr->textureCoords[i][1],
952                                  0.0));
953                (*texCoords)[i].set(transVec.x(), transVec.y());
954            }
955        }
956
[5802]957        geometry->setTexCoordArray(0, texCoords.get());
[2225]958    }
[11032]959
[2225]960    // Set the parameters for the geometry
961
962    geometry->addPrimitiveSet(new osg::DrawArrays(thisPtr->primitiveType,0,
963                                                  coords->size()));
964    // Get the StateSet for the geoset
[5802]965    osg::ref_ptr<osg::StateSet> stateSet = thisPtr->getStateSet(action);
966    geometry->setStateSet(stateSet.get());
[11032]967
[2225]968    // Add the geoset to a geode
[5802]969    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
970    geode->addDrawable(geometry.get());
[2225]971
[9053]972    // copy name
973    std::string name = stateSet->getName();
974    if (name != "") {
975        geode->setName(name);
976    }
[2225]977
[11032]978    // Transformation and scene graph building
979    thisPtr->appendNode(geode.get(), action);
980
[2225]981    return SoCallbackAction::CONTINUE;
982}
[5802]983///////////////////////////////////////////////////////////////
[11032]984SoCallbackAction::Response
985ConvertFromInventor::postTexture(void* data, SoCallbackAction *,
986                                 const SoNode* node)
[2225]987{
988#ifdef DEBUG_IV_PLUGIN
[11032]989    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "postTexture()  "
990              << node->getTypeId().getName().getString();
991    if (node->isOfType(SoTexture2::getClassTypeId())) {
992        SoTexture2 *t = (SoTexture2*)node;
993        if (t->filename.getValue().getLength())
994            osg::notify(osg::DEBUG_INFO) << "  "  << t->filename.getValue().getString();
995    }
996    osg::notify(osg::DEBUG_INFO) << std::endl;
[2225]997#endif
[11032]998
[2225]999    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
[11032]1000    bool texturingEnabled = false;
[9053]1001
[11032]1002    // Texture2
1003    if (node->isOfType(SoTexture2::getClassTypeId())) {
1004
1005        // Check whether texturing was enabled by the texture node
1006        SoTexture2 *t = (SoTexture2*)node;
1007        SbVec2s size;
1008        int nc;
1009        const unsigned char *data = t->image.getValue(size, nc);
1010        texturingEnabled = t->filename.getValue().getLength() ||
1011                           (data && size != SbVec2s(0,0));
1012    }
1013
[9053]1014#ifdef __COIN__
1015
[11032]1016    // SoVRMLImageTexture
1017    if (node->isOfType(SoVRMLImageTexture::getClassTypeId())) {
1018
1019        // Check whether texturing was enabled by the texture node
1020        SoVRMLImageTexture *t = (SoVRMLImageTexture*)node;
1021        texturingEnabled = t->url.getNum() > 1 || (t->url.getNum() == 1 && t->url[0].getLength() > 0);
[9053]1022    }
[11032]1023
1024    // SoVRMLAppearance
1025    if (node->isOfType(SoVRMLAppearance::getClassTypeId())) {
1026
1027        // If SoVRMLAppearance is present and there is no texture
1028        // inside, disable texturing
1029        // FIXME: should SoVRMLAppearance really disable texturing
1030        // when not containing SoVRMLImageTexture? Coin is not doing that,
1031        // but it can be Coin bug.
1032        SoVRMLAppearance *a = (SoVRMLAppearance*)node;
1033        if (a->texture.getValue() == NULL)
1034            thisPtr->ivStateStack.top().currentTexture = NULL;
1035
1036        // Do not try to "optimize" this code by removing the return
1037    // and use the one at the end of the function.
1038    // It would break the case when there is texture inside
1039    // the appearance node.
1040        return SoCallbackAction::CONTINUE;
[9053]1041    }
1042
[11032]1043#endif /* __COIN__ */
[6543]1044
[11032]1045    // Set current texture
1046    if (texturingEnabled)
1047        thisPtr->ivStateStack.top().currentTexture = node;
1048    else
1049        thisPtr->ivStateStack.top().currentTexture = NULL;
[6543]1050
1051    return SoCallbackAction::CONTINUE;
1052}
[5802]1053//////////////////////////////////////////////////////////////////
[11032]1054void ConvertFromInventor::transformLight(SoCallbackAction* action,
1055                                         const SbVec3f& vec,
[2225]1056                                         osg::Vec3& transVec)
1057{
1058    osg::Matrix modelMat;
1059    modelMat.set((float *)action->getModelMatrix().getValue());
1060
1061    transVec.set(vec[0], vec[1], vec[2]);
1062    transVec = modelMat.preMult(transVec);
1063}
[5802]1064///////////////////////////////////////////////////////////////////
[11032]1065SoCallbackAction::Response
1066ConvertFromInventor::preLight(void* data, SoCallbackAction* action,
[2225]1067                              const SoNode* node)
1068{
1069#ifdef DEBUG_IV_PLUGIN
[11032]1070    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "preLight()   "
[2225]1071              << node->getTypeId().getName().getString() << std::endl;
1072#endif
1073
1074    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
[11032]1075
[2225]1076    // Return if the light is not on
1077    const SoLight* ivLight = (const SoLight*) node;
1078    if (!ivLight->on.getValue())
1079        return SoCallbackAction::CONTINUE;
1080
[11032]1081    // Create new OSG light
1082    IvStateItem &ivState = thisPtr->ivStateStack.top();
[5802]1083    osg::ref_ptr<osg::Light> osgLight = new osg::Light;
[9053]1084
[11032]1085    // Light name
[9053]1086    const char* name = ivLight->getName().getString();
1087    osgLight->setName(name);
[11032]1088
[2225]1089    // Get color and intensity
1090    SbVec3f lightColor = ivLight->color.getValue();
1091    float intensity = ivLight->intensity.getValue();
1092
1093    // Set color and intensity
[11032]1094    osgLight->setAmbient(osg::Vec4(0.f, 0.f, 0.f, 1.f));
[2225]1095    osgLight->setDiffuse(osg::Vec4(lightColor[0] * intensity,
1096                                   lightColor[1] * intensity,
1097                                   lightColor[2] * intensity, 1));
[11032]1098    osgLight->setSpecular(osg::Vec4(lightColor[0] * intensity,
1099                                    lightColor[1] * intensity,
1100                                    lightColor[2] * intensity, 1));
[2225]1101
[11032]1102    // Light type
[2225]1103    if (node->isOfType(SoDirectionalLight::getClassTypeId()))
1104    {
1105        SoDirectionalLight *dirLight = (SoDirectionalLight *) node;
[11032]1106
1107#if 1 // Let's place the light to its place in scene graph instead of
1108      // old approach of global light group.
1109        SbVec3f l(dirLight->direction.getValue());
1110        osgLight->setPosition(osg::Vec4(l[0], l[1], l[2] , 0.));
1111#else
[2225]1112        osg::Vec3 transVec;
1113        thisPtr->transformLight(action, dirLight->direction.getValue(), transVec);
[11032]1114        osgLight->setPosition(osg::Vec4(transVec.x(), transVec.y(),
1115                                        transVec.z(), 0.));
1116#endif
[2225]1117    }
1118    else if (node->isOfType(SoPointLight::getClassTypeId()))
1119    {
1120        SoPointLight* ptLight = (SoPointLight *) node;
1121
[11032]1122#if 1 // Let's place the light to its place in scene graph instead of
1123      // old approach of global light group.
1124        SbVec3f l(ptLight->location.getValue());
1125        osgLight->setPosition(osg::Vec4(l[0], l[1], l[2] , 1.));
1126#else
[2225]1127        osg::Vec3 transVec;
1128        thisPtr->transformLight(action, ptLight->location.getValue(), transVec);
[11032]1129        osgLight->setPosition(osg::Vec4(transVec.x(), transVec.y(),
1130                                        transVec.z(), 1.));
1131#endif
[2225]1132    }
1133    else if (node->isOfType(SoSpotLight::getClassTypeId()))
1134    {
1135        SoSpotLight* spotLight = (SoSpotLight *) node;
1136
1137        osgLight->setSpotExponent(spotLight->dropOffRate.getValue() * 128.0);
[2915]1138        osgLight->setSpotCutoff(spotLight->cutOffAngle.getValue()*180.0/osg::PI);
[2225]1139
[11032]1140#if 1 // Let's place the light to its place in scene graph instead of
1141      // old approach of global light group.
1142        SbVec3f l(spotLight->location.getValue());
1143        osgLight->setPosition(osg::Vec4(l[0], l[1], l[2] , 1.));
1144        l = spotLight->direction.getValue();
1145        osgLight->setDirection(osg::Vec3(l[0], l[1], l[2]));
1146#else
[2225]1147        osg::Vec3 transVec;
1148        thisPtr->transformLight(action, spotLight->location.getValue(), transVec);
[11032]1149        osgLight->setPosition(osg::Vec4(transVec.x(), transVec.y(),
1150                                        transVec.z(), 1.));
[2225]1151
1152        thisPtr->transformLight(action, spotLight->direction.getValue(),transVec);
[11032]1153        osgLight->setDirection(osg::Vec3(transVec.x(), transVec.y(),
[2225]1154                                         transVec.z()));
[11032]1155#endif
[2225]1156    }
[11032]1157
1158    // Attenuation
1159    if (!node->isOfType(SoDirectionalLight::getClassTypeId())) {
1160        SbVec3f att = action->getLightAttenuation();
1161        osgLight->setConstantAttenuation(att[2]);
1162        osgLight->setLinearAttenuation(att[1]);
1163        osgLight->setQuadraticAttenuation(att[0]);
1164    } else {
1165        // keep default light settings for directional light, e.g.
1166        // no attenuation
[2225]1167    }
1168
[11032]1169    // Append the light into the scene and onto the state stack
1170    osgLight->setLightNum(ivState.currentLights.size());
1171    ivState.currentLights.push_back(osgLight);
1172
[9053]1173    osg::ref_ptr<osg::LightSource> ls = new osg::LightSource();
1174    ls->setLight(osgLight.get());
1175    ls->setName(ivLight->getName().getString());
[11032]1176#if 1 // Let's place the light to its place in scene graph instead of
1177      // old approach of global light group.
1178    thisPtr->ivPushState(action, node,
1179              IvStateItem::MULTI_POP | IvStateItem::UPDATE_STATE |
1180              IvStateItem::APPEND_AT_PUSH, ls.get());
1181#else
1182    if (!(thisPtr->lightGroup.get()))
1183        thisPtr->lightGroup = new osg::Group();
1184    thisPtr->lightGroup->addChild(ls);
1185#endif
1186
1187    return SoCallbackAction::CONTINUE;
1188}
1189///////////////////////////////////////////////////////////////////
1190SoCallbackAction::Response
1191ConvertFromInventor::preEnvironment(void* data, SoCallbackAction* action,
1192                                    const SoNode* node)
1193{
1194#ifdef DEBUG_IV_PLUGIN
1195    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "preLight()   "
1196              << node->getTypeId().getName().getString() << std::endl;
1197#endif
1198
1199    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
1200    IvStateItem &ivState = thisPtr->ivStateStack.top();
1201
1202    ivState.currentAmbientLight = ((SoEnvironment*)node)->ambientColor.getValue() *
1203                                  ((SoEnvironment*)node)->ambientIntensity.getValue();
1204
1205    return SoCallbackAction::CONTINUE;
1206}
1207///////////////////////////////////////////////////////////////////
1208#ifdef INVENTOR_SHADERS_AVAILABLE
1209static bool
1210convertShader(osg::Shader::Type osgShaderType,
1211              const SoShaderObject *ivShader,
1212              osg::Program *osgProgram)
1213{
1214    // NULL shader is not converted while returning success
1215    if (ivShader == NULL)
1216        return true;
1217
1218    // Create shader
1219    osg::ref_ptr<osg::Shader> osgShader = new osg::Shader(osgShaderType);
1220    if (ivShader->sourceType.getValue() == SoShaderObject::FILENAME)
1221        osgShader->loadShaderSourceFromFile(ivShader->sourceProgram.getValue().getString());
1222    else
1223    if (ivShader->sourceType.getValue() == SoShaderObject::GLSL_PROGRAM)
1224        osgShader->setShaderSource(ivShader->sourceProgram.getValue().getString());
1225    else {
1226        osg::notify(osg::WARN) << NOTIFY_HEADER << "Can not convert "
1227                  << "shader. Unsupported shader language." << std::endl;
1228        return false;
[9053]1229    }
1230
[11032]1231    return osgProgram->addShader(osgShader);
1232}
1233#endif // INVENTOR_SHADERS_AVAILABLE
1234///////////////////////////////////////////////////////////////////
1235SoCallbackAction::Response
1236ConvertFromInventor::preShaderProgram(void* data, SoCallbackAction* action,
1237                              const SoNode* node)
1238{
1239#ifdef DEBUG_IV_PLUGIN
1240    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "preShaderProgram()  "
1241              << node->getTypeId().getName().getString() << std::endl;
1242#endif
1243
1244#ifdef INVENTOR_SHADERS_AVAILABLE
1245
1246    ConvertFromInventor *thisPtr = (ConvertFromInventor*)data;
1247    IvStateItem &ivState = thisPtr->ivStateStack.top();
1248
1249    // Get Inventor nodes
1250    // Note: Shaders are available since Coin 2.5 (including
1251    // geometry shader)
1252    const SoShaderProgram *ivProgram = (const SoShaderProgram*)node;
1253    const SoVertexShader *ivVertexShader = NULL;
1254    const SoGeometryShader *ivGeometryShader = NULL;
1255    const SoFragmentShader *ivFragmentShader = NULL;
1256
1257    for (int i=0, c=ivProgram->shaderObject.getNum(); i<c; i++) {
1258
1259        const SoShaderObject *shader = (const SoShaderObject*)ivProgram->shaderObject[i];
1260        if (!shader->isOfType(SoShaderObject::getClassTypeId()))
1261            continue;
1262        if (shader->isActive.getValue() == FALSE)
1263            continue;
1264
1265        if (shader->isOfType(SoVertexShader::getClassTypeId()))
1266            ivVertexShader = (const SoVertexShader*)shader;
1267        if (shader->isOfType(SoGeometryShader::getClassTypeId()))
1268            ivGeometryShader = (const SoGeometryShader*)shader;
1269        if (shader->isOfType(SoFragmentShader::getClassTypeId()))
1270            ivFragmentShader = (const SoFragmentShader*)shader;
1271    }
1272
1273    // Create OSG shader
1274    osg::Program *osgProgram = new osg::Program();
1275    if (!convertShader(osg::Shader::VERTEX, ivVertexShader, osgProgram))
1276        osg::notify(osg::WARN) << NOTIFY_HEADER
1277                  << "Failed to add vertex shader." << std::endl;
1278    if (!convertShader(osg::Shader::GEOMETRY, ivGeometryShader, osgProgram))
1279        osg::notify(osg::WARN) << NOTIFY_HEADER
1280                  << "Failed to add geometry shader." << std::endl;
1281    if (!convertShader(osg::Shader::FRAGMENT, ivFragmentShader, osgProgram))
1282        osg::notify(osg::WARN) << NOTIFY_HEADER
1283                  << "Failed to add fragment shader." << std::endl;
1284
1285    // Put shader to the state stack
1286    ivState.currentGLProgram = osgProgram;
1287
1288#else
1289
1290    osg::notify(osg::WARN) << NOTIFY_HEADER << "Warning: The model "
1291              "contains shaders while your Inventor does not support "
1292              "them." << std::endl;
1293#endif
1294
[2225]1295    return SoCallbackAction::CONTINUE;
1296}
[5802]1297///////////////////////////////////////////////////////////////////////////////////////
[6543]1298osg::ref_ptr<osg::StateSet>
1299ConvertFromInventor::getStateSet(SoCallbackAction* action)
[2225]1300{
[5802]1301    osg::ref_ptr<osg::StateSet> stateSet = new osg::StateSet;
[11032]1302
[2225]1303    // Inherit modes from the global state
[3480]1304    stateSet->clear();
[2225]1305
[11032]1306    // Inventor State Stack
1307    IvStateItem &ivState = ivStateStack.top();
1308
[7348]1309    // Convert the IV texture to OSG texture if any
1310    osg::ref_ptr<osg::Texture2D> texture;
[11032]1311    const SoNode *ivTexture = ivState.currentTexture;
[7348]1312    if (ivTexture)
1313    {
1314        // Found a corresponding OSG texture object
1315        if (ivToOsgTexMap[ivTexture])
1316            texture = ivToOsgTexMap[ivTexture];
1317        else
1318        {
1319            // Create a new osg texture
1320            texture = convertIVTexToOSGTex(ivTexture, action);
1321
1322            // Add the new texture to the database
1323            ivToOsgTexMap[ivTexture] = texture.get();
1324        }
[11032]1325
[7348]1326        stateSet->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::ON);
[11032]1327
[9053]1328        // propogate name
[9451]1329        if(texture.valid())
1330        {
1331            std::string name = texture->getName();
1332            if (name != "")
1333                stateSet->setName(name);
1334        }
[7348]1335        // Set the texture environment
1336        osg::ref_ptr<osg::TexEnv> texEnv = new osg::TexEnv;
1337        switch (action->getTextureModel())
1338        {
1339            case SoTexture2::MODULATE:
1340                texEnv->setMode(osg::TexEnv::MODULATE);
1341                break;
1342            case SoTexture2::DECAL:
1343                texEnv->setMode(osg::TexEnv::DECAL);
1344                break;
[11032]1345            case SoTexture2::BLEND: {
[7348]1346                texEnv->setMode(osg::TexEnv::BLEND);
[11032]1347                SbColor c(action->getTextureBlendColor());
1348                texEnv->setColor(osg::Vec4(c[0], c[1], c[2], 1.f));
[7348]1349                break;
[11032]1350            }
[7348]1351            // SGI's Inventor does not have REPLACE mode, but the Coin 3D library does.
1352            // Coin supports REPLACE since 2.2 release, TGS Inventor from 4.0.
1353            // Let's convert to the TexEnv anyway.
[11032]1354            case 0x1E01: //SoTexture2::REPLACE:
[7348]1355                texEnv->setMode(osg::TexEnv::REPLACE);
1356                break;
[9585]1357            default:
[11032]1358                osg::notify(osg::WARN) << "Unsupported TexEnv mode." << std::endl;
[9585]1359                break;
1360
[7348]1361        }
1362        stateSet->setTextureAttributeAndModes(0,texEnv.get(),osg::StateAttribute::ON);
1363    }
1364
[2225]1365    SbColor ambient, diffuse, specular, emission;
1366    float shininess, transparency;
1367
1368    // Get the material colors
1369    action->getMaterial(ambient, diffuse, specular, emission,
[2485]1370                shininess, transparency, 0);
[11032]1371
[2225]1372    // Set transparency
[7348]1373    SbBool hasTextureTransparency = FALSE;
1374    if (ivTexture) {
1375      SbVec2s tmp;
[11032]1376      int bpp = 0;
[7348]1377      if (ivTexture->isOfType(SoTexture2::getClassTypeId()))
1378        ((SoTexture2*)ivTexture)->image.getValue(tmp, bpp);
1379#ifdef __COIN__
1380      else
1381      if (ivTexture->isOfType(SoVRMLImageTexture::getClassTypeId())) {
1382        const SbImage *img = ((SoVRMLImageTexture*)ivTexture)->getImage();
1383        if (img) img->getValue(tmp, bpp);
1384      }
1385#endif
1386      hasTextureTransparency = bpp==4 || bpp==2;
1387    }
1388
1389    if (transparency > 0 || hasTextureTransparency)
[2225]1390    {
[5802]1391        osg::ref_ptr<osg::BlendFunc> transparency = new osg::BlendFunc;
[11032]1392        stateSet->setAttributeAndModes(transparency.get(),
[2225]1393                                       osg::StateAttribute::ON);
[11032]1394
[2225]1395        // Enable depth sorting for transparent objects
1396        stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
1397    }
[11032]1398
[2225]1399    // Set linewidth
1400    if (action->getLineWidth())
1401    {
[5802]1402        osg::ref_ptr<osg::LineWidth> lineWidth = new osg::LineWidth;
[2225]1403        lineWidth->setWidth(action->getLineWidth());
[5802]1404        stateSet->setAttributeAndModes(lineWidth.get(), osg::StateAttribute::ON);
[2225]1405    }
1406
1407    // Set pointsize
1408    if (action->getPointSize())
1409    {
[5802]1410        osg::ref_ptr<osg::Point> point = new osg::Point;
[2225]1411        point->setSize(action->getPointSize());
[5802]1412        stateSet->setAttributeAndModes(point.get(), osg::StateAttribute::ON);
[2225]1413    }
[11032]1414
1415    // Set draw mode
[2225]1416    switch (action->getDrawStyle())
1417    {
1418        case SoDrawStyle::FILLED:
[3920]1419        {
1420#if 0
1421// OSG defaults to filled draw style, so no need to set redundent state.
1422            osg::PolygonMode *polygonMode = new osg::PolygonMode;
[11032]1423            polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
[2225]1424                                 osg::PolygonMode::FILL);
[3920]1425            stateSet->setAttributeAndModes(polygonMode, osg::StateAttribute::ON);
1426#endif
[2225]1427            break;
[3920]1428        }
[2225]1429        case SoDrawStyle::LINES:
[3920]1430        {
[5802]1431            osg::ref_ptr<osg::PolygonMode> polygonMode = new osg::PolygonMode;
[11032]1432            polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
[2225]1433                                 osg::PolygonMode::LINE);
[5802]1434            stateSet->setAttributeAndModes(polygonMode.get(), osg::StateAttribute::ON);
[2225]1435            break;
[3920]1436        }
[2225]1437        case SoDrawStyle::POINTS:
[3920]1438        {
[5802]1439            osg::ref_ptr<osg::PolygonMode> polygonMode = new osg::PolygonMode;
[11032]1440            polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
[2225]1441                                 osg::PolygonMode::POINT);
[5802]1442            stateSet->setAttributeAndModes(polygonMode.get(), osg::StateAttribute::ON);
[2225]1443            break;
[3920]1444        }
[2225]1445        case SoDrawStyle::INVISIBLE:
1446            // check how to handle this in osg.
1447            break;
1448    }
1449
1450    // Set back face culling
1451    if (action->getShapeType() == SoShapeHints::SOLID)
1452    {
[5802]1453        osg::ref_ptr<osg::CullFace> cullFace = new osg::CullFace;
[2225]1454        cullFace->setMode(osg::CullFace::BACK);
[5802]1455        stateSet->setAttributeAndModes(cullFace.get(), osg::StateAttribute::ON);
[11032]1456    }
[2225]1457
1458    // Set lighting
1459    if (action->getLightModel() == SoLightModel::BASE_COLOR)
1460        stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
1461    else
1462    {
1463        // Set the material
[5802]1464        osg::ref_ptr<osg::Material> material = new osg::Material;
[2225]1465
[11032]1466        material->setAmbient(osg::Material::FRONT_AND_BACK,
1467                             osg::Vec4(ambient[0], ambient[1], ambient[2],
[2225]1468                                       1.0 - transparency));
[11032]1469        material->setDiffuse(osg::Material::FRONT_AND_BACK,
1470                             osg::Vec4(diffuse[0], diffuse[1], diffuse[2],
[2225]1471                                       1.0 - transparency));
[11032]1472        material->setSpecular(osg::Material::FRONT_AND_BACK,
1473                              osg::Vec4(specular[0], specular[1], specular[2],
[2225]1474                                        1.0 - transparency));
[11032]1475        material->setEmission(osg::Material::FRONT_AND_BACK,
1476                              osg::Vec4(emission[0], emission[1], emission[2],
[2225]1477                                        1.0 - transparency));
1478        material->setTransparency(osg::Material::FRONT_AND_BACK, transparency);
1479        if (specular[0] || specular[1] || specular[2])
[11032]1480            material->setShininess(osg::Material::FRONT_AND_BACK,
[2225]1481                                   shininess*128.0);
1482        else
1483            material->setShininess(osg::Material::FRONT_AND_BACK, 0.0);
1484
1485        material->setColorMode(osg::Material::DIFFUSE);
1486
[5802]1487        stateSet->setAttributeAndModes(material.get(), osg::StateAttribute::ON);
[9053]1488        stateSet->setName(appearanceName.getString());
[2225]1489        stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
1490
[11032]1491        // Set global ambient light
1492        // note on osg::LightModel default values:
1493        //   colorControl: SINGLE_COLOR, localViewer: false, twoSided: false
1494        osg::LightModel *lightModel = new osg::LightModel();
1495        const SbColor &c = ivState.currentAmbientLight;
1496        lightModel->setAmbientIntensity(osg::Vec4(c[0], c[1], c[2], 1.0));
[3920]1497#if 0
1498// disable as two sided lighting causes problem under NVidia, and the above osg::Material settings are single sided anway..
[11032]1499update: The mentioned bug is probably just for very old NVidia drivers (commit time of the comment is 2005-03-18).
1500        The proper solution should be to set two sided lighting based on SoShapeHints node. Need to be developed. PCJohn-2010-01-20
[2225]1501        // Set two sided lighting
1502        lightModel->setTwoSided(true);
[11032]1503#endif
[2225]1504        stateSet->setAttributeAndModes(lightModel, osg::StateAttribute::ON);
[11032]1505
[2225]1506        // Set lights
[11032]1507        for (unsigned int i = 0; i < ivState.currentLights.size(); i++)
1508            stateSet->setAttributeAndModes(ivState.currentLights[i].get(),
[2225]1509                                           osg::StateAttribute::ON);
[11032]1510
[2225]1511    }
[11032]1512
1513    // Shader program setup
1514    if (ivState.currentGLProgram.get() != NULL) {
1515        stateSet->setAttributeAndModes(ivState.currentGLProgram.get(),
1516                                       osg::StateAttribute::ON);
1517    }
1518
1519    // Shader program uniforms
1520    if (ivState.currentGLProgram.get() != NULL) {
1521        for (int i=0, c=ivState.currentGLProgram->getNumShaders(); i<c; i++) {
1522             const std::string &shaderCode = ivState.currentGLProgram->getShader(i)->getShaderSource();
1523             if (shaderCode.find("coin_texunit0_model") != std::string::npos) {
1524                 int mode = (ivTexture!=NULL) ? action->getTextureModel() : 0;
1525                 stateSet->addUniform(new osg::Uniform("coin_texunit0_model", mode));
1526                 break;
1527             }
1528        }
1529    }
1530
[2225]1531    return stateSet;
1532}
[5802]1533////////////////////////////////////////////////////////////////////
[6543]1534osg::Texture2D*
1535ConvertFromInventor::convertIVTexToOSGTex(const SoNode* soNode,
[2225]1536                                          SoCallbackAction* action)
1537{
[11032]1538#ifdef DEBUG_IV_PLUGIN
1539    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER
1540              << "convertIVTexToOSGTex ("
1541              << soNode->getTypeId().getName().getString()
1542              << ")" << std::endl;
1543#endif
[3920]1544
[6543]1545    SbVec2s soSize;
1546    int soNC;
1547
[2225]1548    // Get the texture size and components
[6543]1549    const unsigned char* soImageData = action->getTextureImage(soSize, soNC);
1550    if (!soImageData) {
[11032]1551        osg::notify(osg::WARN) << NOTIFY_HEADER
1552                  << "Warning: Error while loading texture data." << std::endl;
[2225]1553        return NULL;
[6543]1554    }
1555
[2225]1556    // Allocate memory for image data
[6543]1557    unsigned char* osgImageData = new unsigned char[soSize[0] * soSize[1] * soNC];
1558
[2225]1559    // Copy the texture image data from the inventor texture
[6543]1560    memcpy(osgImageData, soImageData, soSize[0] * soSize[1] * soNC);
[2225]1561
[9053]1562    // Copy the name
1563    std::string name = soNode->getName().getString();
1564
[6543]1565    // File name
1566    std::string fileName;
1567    if (soNode->isOfType(SoTexture2::getClassTypeId()))
1568        fileName = ((SoTexture2*)soNode)->filename.getValue().getString();
[7348]1569#ifdef __COIN__
[6543]1570    else
1571    if (soNode->isOfType(SoVRMLImageTexture::getClassTypeId()))
[11032]1572        fileName = ((SoVRMLImageTexture*)soNode)->url.getNum() >= 1 ?
[6543]1573                   ((SoVRMLImageTexture*)soNode)->url.getValues(0)[0].getString() : "";
[6544]1574#endif
[6543]1575    else
[11032]1576      osg::notify(osg::WARN) << NOTIFY_HEADER
1577                << " Warning: Unsupported texture type: "
1578                << soNode->getTypeId().getName().getString() << std::endl;
[6543]1579
[11032]1580#ifdef DEBUG_IV_PLUGIN
1581    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER
1582              << "  Converting file name: " << fileName << " -> ";
1583#endif
[6543]1584    if (fileName[0]=='\"') fileName.erase(fileName.begin());
[11032]1585    if (fileName.size() > 0 && fileName[fileName.size()-1]=='\"')
[6543]1586        fileName.erase(fileName.begin()+fileName.size()-1);
[11032]1587#ifdef DEBUG_IV_PLUGIN
1588    osg::notify(osg::DEBUG_INFO) << fileName << std::endl;
1589#endif
[6543]1590
[11032]1591    // Create the osg::Image
[6543]1592    osg::ref_ptr<osg::Image> osgImage = new osg::Image;
1593    osgImage->setFileName(fileName);
[2225]1594    GLenum formats[] = {GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA};
[6543]1595    osgImage->setImage(soSize[0], soSize[1], 0, soNC, formats[soNC-1],
1596                       GL_UNSIGNED_BYTE, osgImageData, osg::Image::USE_NEW_DELETE);
[2225]1597
[6543]1598    // Create the osg::Texture2D
1599    osg::Texture2D *osgTex = new osg::Texture2D;
1600    osgTex->setImage(osgImage.get());
[9053]1601    if (name != "") {
1602        osgTex->setName(name);
1603    }
[2225]1604
1605    static std::map<SoTexture2::Wrap, osg::Texture2D::WrapMode> texWrapMap;
1606    static bool firstTime = true;
1607    if (firstTime)
1608    {
1609        texWrapMap[SoTexture2::CLAMP] = osg::Texture2D::CLAMP;
1610        texWrapMap[SoTexture2::REPEAT] = osg::Texture2D::REPEAT;
1611        firstTime = false;
1612    }
[11032]1613
[2225]1614    // Set texture wrap mode
[7348]1615#ifdef __COIN__
[6543]1616    if (soNode->isOfType(SoVRMLImageTexture::getClassTypeId())) {
1617        // It looks like there is a high probability of bug in Coin (investigated on version 2.4.6).
1618        // action->getTextureWrap() returns correct value on SoTexture2 (SoTexture2::CLAMP = 0x2900,
1619        // and REPEAT = 0x2901), but SoVRMLImageTexture returns incorrect value of
1620        // SoGLImage::REPEAT = 0, CLAMP = 1, CLAMP_TO_EDGE = 2).
1621        // So, let's not use action and try to get correct value directly from texture node.
1622        // PCJohn-2007-04-22
1623        osgTex->setWrap(osg::Texture2D::WRAP_S, ((SoVRMLImageTexture*)soNode)->repeatS.getValue() ?
1624            osg::Texture2D::REPEAT : osg::Texture2D::CLAMP_TO_EDGE);
1625        osgTex->setWrap(osg::Texture2D::WRAP_T, ((SoVRMLImageTexture*)soNode)->repeatT.getValue() ?
1626            osg::Texture2D::REPEAT : osg::Texture2D::CLAMP_TO_EDGE);
[6544]1627    }
1628    else
1629#endif
1630    {
[6543]1631        // Proper way to determine wrap mode
1632        osgTex->setWrap(osg::Texture2D::WRAP_S, texWrapMap[action->getTextureWrapS()]);
1633        osgTex->setWrap(osg::Texture2D::WRAP_T, texWrapMap[action->getTextureWrapT()]);
1634    }
[2225]1635
[11032]1636    return osgTex;
[2225]1637}
[5802]1638///////////////////////////////////////////////////////////////////
[11032]1639SoCallbackAction::Response
1640ConvertFromInventor::preInfo(void* data, SoCallbackAction* action,
1641                             const SoNode* node)
[2225]1642{
1643#ifdef DEBUG_IV_PLUGIN
[11032]1644    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "preInfo()    "
[9053]1645              << node->getTypeId().getName().getString() << std::endl;
1646#endif
1647    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
1648    SoInfo* info = (SoInfo*)node;
1649    thisPtr->transformInfoName = info->string.getValue();
1650
1651    return SoCallbackAction::CONTINUE;
1652}
[5802]1653/////////////////////////////////////////////////////////////
[11032]1654SoCallbackAction::Response
1655ConvertFromInventor::preRotor(void *data, SoCallbackAction *action,
1656                              const SoNode *node)
[2225]1657{
1658#ifdef DEBUG_IV_PLUGIN
[11032]1659    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "preRotor()  "
[2225]1660              << node->getTypeId().getName().getString() << std::endl;
1661#endif
1662
1663    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
1664
1665    // Get the parameters for the inventor Rotor
1666    SoRotor *ivRotor = (SoRotor *) node;
1667    SbVec3f ivAxis;
1668    float angle;
1669    ivRotor->rotation.getValue(ivAxis, angle);
1670
1671    // Create a new osg::MatrixTransform
[5802]1672    osg::ref_ptr<osg::MatrixTransform> rotorTransform = new osg::MatrixTransform;
[11032]1673
[2225]1674    // Create a Rotor Callback equivalent to the inventor Rotor
1675    osg::Vec3 pivot(0, 0, 0);
1676    osg::Vec3 axis(ivAxis[0], ivAxis[1], ivAxis[2]);
[11032]1677    osg::ref_ptr<osgUtil::TransformCallback> rotorCallback
1678        = new osgUtil::TransformCallback(pivot, axis,
[2915]1679                                         2 * osg::PI * ivRotor->speed.getValue());
[2225]1680
1681    // Set the app callback
[5802]1682    rotorTransform->setUpdateCallback(rotorCallback.get());
[2225]1683
[11032]1684    // Push the rotor onto the state stack
1685    thisPtr->ivPushState(action, node,
1686              IvStateItem::MULTI_POP | IvStateItem::UPDATE_STATE |
1687              IvStateItem::APPEND_AT_PUSH, rotorTransform.get());
1688
1689    // Append initial rotation to the model matrix
1690    if (!ivRotor->rotation.isIgnored()) {
1691        SoModelMatrixElement::rotateBy(action->getState(), ivRotor,
1692                                       ivRotor->rotation.getValue());
1693    }
1694
1695    // Don't do the traversal of the SoShuttle
1696    // since it was seen on Coin that is does not append just
1697    // initial shuttle position, but some interpolated one,
1698    // resulting in incorrect animation.
1699    return SoCallbackAction::PRUNE;
[2225]1700}
[5802]1701////////////////////////////////////////////////////////////////
[11032]1702SoCallbackAction::Response
1703ConvertFromInventor::prePendulum(void* data, SoCallbackAction *action,
[2225]1704                                 const SoNode* node)
1705{
1706#ifdef DEBUG_IV_PLUGIN
[11032]1707    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "prePendulum()  "
[2225]1708              << node->getTypeId().getName().getString() << std::endl;
1709#endif
1710
1711    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
1712
1713    // Get the parameters for the inventor Pendulum
1714    SoPendulum *ivPendulum = (SoPendulum *) node;
1715    SbVec3f ivAxis0, ivAxis1;
1716    float startAngle, endAngle;
1717    ivPendulum->rotation0.getValue(ivAxis0, startAngle);
1718    ivPendulum->rotation1.getValue(ivAxis1, endAngle);
[11032]1719    ivAxis0.normalize();
1720    ivAxis1.normalize();
[2225]1721
[11032]1722    // Reverse axis and direction if required
1723    // Actually, this will produce correct results only when axis is
1724    // opposite to each other, and approximate results when nearly
1725    // opposite and garbage otherwise.
1726    if ((ivAxis0+ivAxis1).length() < 0.5 ) {
1727        ivAxis1 = -ivAxis1;
1728        endAngle = -endAngle;
1729    }
1730
[2225]1731    // Create a new osg::MatrixTransform
[5802]1732    osg::ref_ptr<osg::MatrixTransform> pendulumTransform = new osg::MatrixTransform;
[11032]1733
[2225]1734    // Create a Pendulum Callback equivalent to the inventor Rotor
[11032]1735    // Use axis from of the bigger angle (to avoid lost axis when
1736    // angle is zero - see SbRotation and quaternion theory).
1737    osg::Vec3 axis;
1738    if (fabs(startAngle) > fabs(endAngle))
1739        axis = osg::Vec3(ivAxis0[0], ivAxis0[1], ivAxis0[2]);
1740    else
1741        axis = osg::Vec3(ivAxis1[0], ivAxis1[1], ivAxis1[2]);
1742    PendulumCallback* pendulumCallback
[2225]1743        = new PendulumCallback(axis, startAngle, endAngle,
1744                               ivPendulum->speed.getValue());
1745
1746    // Set the app callback
1747    pendulumTransform->setUpdateCallback(pendulumCallback);
1748
[11032]1749    // Push the pendulum onto the state stack
1750    thisPtr->ivPushState(action, node,
1751              IvStateItem::MULTI_POP | IvStateItem::UPDATE_STATE |
1752              IvStateItem::APPEND_AT_PUSH, pendulumTransform.get());
1753
1754    // Don't do the traversal of the SoShuttle
1755    // since it was seen on Coin that is does not append just
1756    // initial shuttle position, but some interpolated one,
1757    // resulting in incorrect animation.
1758    return SoCallbackAction::PRUNE;
[2225]1759}
[5802]1760////////////////////////////////////////////////////////////////
[11032]1761SoCallbackAction::Response
1762ConvertFromInventor::preShuttle(void* data, SoCallbackAction *action,
[2225]1763                                const SoNode* node)
1764{
1765#ifdef DEBUG_IV_PLUGIN
[11032]1766    osg::notify(osg::DEBUG_INFO) << NOTIFY_HEADER << "preShuttle()  "
[2225]1767              << node->getTypeId().getName().getString() << std::endl;
1768#endif
1769
1770    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
1771
1772    // Get the parameters for the inventor Shuttle
1773    SoShuttle *ivShuttle = (SoShuttle *) node;
1774    SbVec3f ivStartPos, ivEndPos;
1775    ivStartPos = ivShuttle->translation0.getValue();
1776    ivEndPos = ivShuttle->translation1.getValue();
1777
1778    // Create a new osg::MatrixTransform
[5802]1779    osg::ref_ptr<osg::MatrixTransform> shuttleTransform = new osg::MatrixTransform;
[11032]1780
[2225]1781    // Create a shuttle Callback equivalent to the inventor Rotor
1782    osg::Vec3 startPos(ivStartPos[0], ivStartPos[1], ivStartPos[2]);
1783    osg::Vec3 endPos(ivEndPos[0], ivEndPos[1], ivEndPos[2]);
[11032]1784    ShuttleCallback* shuttleCallback
[2225]1785        = new ShuttleCallback(startPos, endPos, ivShuttle->speed.getValue());
1786
1787    // Set the app callback
1788    shuttleTransform->setUpdateCallback(shuttleCallback);
1789
[11032]1790    // Push the shuttle onto the state stack
1791    thisPtr->ivPushState(action, node,
1792              IvStateItem::MULTI_POP | IvStateItem::UPDATE_STATE |
1793              IvStateItem::APPEND_AT_PUSH, shuttleTransform.get());
1794
1795    // Don't do the traversal of the SoShuttle
1796    // since it was seen on Coin that is does not append just
1797    // initial shuttle position, but some interpolated one,
1798    // resulting in incorrect animation.
1799    return SoCallbackAction::PRUNE;
[2225]1800}
[5802]1801////////////////////////////////////////////////////////////
[2225]1802void ConvertFromInventor::addVertex(SoCallbackAction* action,
[11032]1803                                    const SoPrimitiveVertex *v,
[5802]1804                                    int index)
[2225]1805{
1806    // Get the coordinates of the vertex
1807    SbVec3f pt = v->getPoint();
1808    vertices.push_back(osg::Vec3(pt[0], pt[1], pt[2]));
1809
1810    // Get the normal of the vertex
1811    SbVec3f norm = v->getNormal();
1812
1813    if ((normalBinding == osg::Geometry::BIND_PER_VERTEX) ||
1814        (normalBinding == osg::Geometry::BIND_PER_PRIMITIVE && index == 0))
1815    {
[11032]1816        // What is this? Why to invert normals at CLOCKWISE vertex ordering?
1817        // PCJohn 2009-12-13
1818        //if (vertexOrder == CLOCKWISE)
1819        //    normals.push_back(osg::Vec3(-norm[0], -norm[1], -norm[2]));
1820        //else
[2225]1821            normals.push_back(osg::Vec3(norm[0], norm[1], norm[2]));
1822    }
1823
1824    if (colorBinding == osg::Geometry::BIND_PER_VERTEX ||
1825            colorBinding == osg::Geometry::BIND_PER_PRIMITIVE)
1826    {
[11032]1827        // Get the material/color
[2225]1828        SbColor ambient, diffuse, specular, emission;
1829        float transparency, shininess;
[11032]1830        action->getMaterial(ambient, diffuse, specular, emission, shininess,
[2225]1831                            transparency, v->getMaterialIndex());
1832        if (colorBinding == osg::Geometry::BIND_PER_VERTEX)
1833            colors.push_back(osg::Vec4(diffuse[0], diffuse[1], diffuse[2],
1834                                       1.0 - transparency));
1835        else if (colorBinding == osg::Geometry::BIND_PER_PRIMITIVE && index == 0)
1836            colors.push_back(osg::Vec4(diffuse[0], diffuse[1], diffuse[2],
1837                                       1.0 - transparency));
1838    }
1839
1840    // Get the texture coordinates
1841    SbVec4f texCoord = v->getTextureCoords();
1842    textureCoords.push_back(osg::Vec2(texCoord[0], texCoord[1]));
1843}
[5802]1844////////////////////////////////////////////////////////////////////////////
[2225]1845void ConvertFromInventor::addTriangleCB(void* data, SoCallbackAction* action,
[5802]1846                                        const SoPrimitiveVertex* v0,
[2225]1847                                        const SoPrimitiveVertex* v1,
1848                                        const SoPrimitiveVertex* v2)
1849{
1850    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
[11032]1851
[2225]1852    switch (thisPtr->vertexOrder)
1853    {
1854        case CLOCKWISE:
1855            thisPtr->addVertex(action, v0, 0);
1856            thisPtr->addVertex(action, v2, 1);
1857            thisPtr->addVertex(action, v1, 2);
1858            break;
1859        case COUNTER_CLOCKWISE:
1860            thisPtr->addVertex(action, v0, 0);
1861            thisPtr->addVertex(action, v1, 1);
1862            thisPtr->addVertex(action, v2, 2);
1863            break;
1864    }
1865
1866    thisPtr->numPrimitives++;
1867    thisPtr->primitiveType = osg::PrimitiveSet::TRIANGLES;
1868}
[5802]1869////////////////////////////////////////////////////////////////////////////////
[2225]1870void ConvertFromInventor::addLineSegmentCB(void* data, SoCallbackAction* action,
1871                                           const SoPrimitiveVertex* v0,
1872                                           const SoPrimitiveVertex* v1)
1873{
1874    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
1875
1876    thisPtr->addVertex(action, v0, 0);
1877    thisPtr->addVertex(action, v1, 1);
1878
1879    thisPtr->numPrimitives++;
1880    thisPtr->primitiveType = osg::PrimitiveSet::LINES;
1881}
[5802]1882//////////////////////////////////////////////////////////////////////////
[2225]1883void ConvertFromInventor::addPointCB(void* data, SoCallbackAction* action,
1884                                     const SoPrimitiveVertex* v0)
1885{
1886    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
1887
1888    thisPtr->addVertex(action, v0, 0);
1889
1890    thisPtr->numPrimitives++;
1891    thisPtr->primitiveType = osg::PrimitiveSet::POINTS;
1892}
Note: See TracBrowser for help on using the browser.