~ubuntu-branches/ubuntu/trusty/openscenegraph/trusty-proposed

« back to all changes in this revision

Viewing changes to .pc/fix_for_multithreaded_vrml_loading/OpenSceneGraph/src/osgPlugins/Inventor/ConvertFromInventor.cpp

  • Committer: Package Import Robot
  • Author(s): Alberto Luaces Fernández
  • Date: 2014-02-17 23:36:07 UTC
  • mfrom: (31.1.7 trusty)
  • Revision ID: package-import@ubuntu.com-20140217233607-v2j7s7y6sozcyh41
Tags: 3.2.0~rc1-4
* Added patch for fixing a multithreading initialization bug in the
  inventor plugin (LP: #1211993).
* Closing bug about conflicting files in 3.2.0-rc1 and 3.2.0 since next
  version to be packaged is 3.2.1 (Closes: #722674).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "ConvertFromInventor.h"
 
2
 
 
3
#include "PendulumCallback.h"
 
4
#include "ShuttleCallback.h"
 
5
 
 
6
// OSG headers
 
7
#include <osg/MatrixTransform>
 
8
#include <osg/Node>
 
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/Depth>
 
20
#include <osg/LightModel>
 
21
#include <osg/LightSource>
 
22
#include <osg/ShadeModel>
 
23
#include <osg/LOD>
 
24
#include <osgDB/ReadFile>
 
25
#include <osgUtil/TransformCallback>
 
26
 
 
27
// Inventor headers
 
28
#include <Inventor/SoDB.h>
 
29
#include <Inventor/SoInteraction.h>
 
30
#include <Inventor/nodes/SoSeparator.h>
 
31
#include <Inventor/nodes/SoTransformSeparator.h>
 
32
#include <Inventor/nodes/SoShape.h>
 
33
#include <Inventor/nodes/SoVertexShape.h>
 
34
#include <Inventor/nodes/SoLight.h>
 
35
#include <Inventor/nodes/SoDirectionalLight.h>
 
36
#include <Inventor/nodes/SoSpotLight.h>
 
37
#include <Inventor/nodes/SoPointLight.h>
 
38
#include <Inventor/nodes/SoRotor.h>
 
39
#include <Inventor/nodes/SoPendulum.h>
 
40
#include <Inventor/nodes/SoShuttle.h>
 
41
#include <Inventor/nodes/SoLOD.h>
 
42
#include <Inventor/nodes/SoTexture2.h>
 
43
#include <Inventor/nodes/SoEnvironment.h>
 
44
#include <Inventor/misc/SoChildList.h>
 
45
#include <Inventor/SoPrimitiveVertex.h>
 
46
#include <Inventor/SbLinear.h>
 
47
#include <Inventor/nodes/SoTransform.h>
 
48
#include <Inventor/nodes/SoInfo.h>
 
49
#include <Inventor/actions/SoWriteAction.h>
 
50
#include <Inventor/elements/SoModelMatrixElement.h>
 
51
 
 
52
#ifdef __COIN__
 
53
#include <Inventor/VRMLnodes/SoVRMLImageTexture.h>
 
54
#include <Inventor/VRMLnodes/SoVRMLTransform.h>
 
55
#include <Inventor/VRMLnodes/SoVRMLAppearance.h>
 
56
#include <Inventor/VRMLnodes/SoVRMLMaterial.h>
 
57
#include <Inventor/lists/SbStringList.h>
 
58
#endif
 
59
 
 
60
#if defined(__COIN__) && (COIN_MAJOR_VERSION >= 3 || \
 
61
    (COIN_MAJOR_VERSION == 2 && COIN_MINOR_VERSION>=5))
 
62
#define INVENTOR_SHADERS_AVAILABLE
 
63
#endif
 
64
 
 
65
#ifdef INVENTOR_SHADERS_AVAILABLE
 
66
#include <Inventor/nodes/SoShaderProgram.h>
 
67
#include <Inventor/nodes/SoVertexShader.h>
 
68
#include <Inventor/nodes/SoGeometryShader.h>
 
69
#include <Inventor/nodes/SoFragmentShader.h>
 
70
#endif
 
71
 
 
72
#include <map>
 
73
#include <assert.h>
 
74
#include <math.h>
 
75
#include <string.h>
 
76
#ifdef __linux
 
77
#include <values.h>
 
78
#endif
 
79
#ifdef __APPLE__
 
80
#include <float.h>
 
81
#endif
 
82
 
 
83
#define DEBUG_IV_PLUGIN
 
84
#define NOTIFY_HEADER "Inventor Plugin (reader): "
 
85
 
 
86
///////////////////////////////////////////
 
87
ConvertFromInventor::ConvertFromInventor()
 
88
{
 
89
    numPrimitives = 0;
 
90
}
 
91
///////////////////////////////////////////
 
92
ConvertFromInventor::~ConvertFromInventor()
 
93
{
 
94
}
 
95
///////////////////////////////////////////////////////////////////
 
96
static bool
 
97
nodePreservesState(const SoNode *node)
 
98
{
 
99
    return node->isOfType(SoSeparator::getClassTypeId()) ||
 
100
           (node->getChildren() != NULL && node->affectsState() == FALSE);
 
101
}
 
102
////////////////////////////////////////////////////////////////////
 
103
SoCallbackAction::Response
 
104
ConvertFromInventor::restructure(void* data, SoCallbackAction* action,
 
105
                                 const SoNode* node)
 
106
{
 
107
#ifdef DEBUG_IV_PLUGIN
 
108
    OSG_DEBUG << NOTIFY_HEADER << "restructure() "
 
109
              << node->getTypeId().getName().getString();
 
110
#endif
 
111
 
 
112
    int childrenTotal = 0;
 
113
    int numModifiedChildren = 0;
 
114
    int numRemovedNodes = 0;
 
115
    std::vector<std::vector<int> > &stack = *((std::vector<std::vector<int> >*)data);
 
116
 
 
117
    if (node->isOfType(SoGroup::getClassTypeId())) {
 
118
 
 
119
        SoGroup *group = (SoGroup*)node;
 
120
        SoGroup *affectedScene = NULL;
 
121
        childrenTotal = group->getNumChildren();
 
122
 
 
123
        for (int i=0, c=group->getNumChildren(); i<c; i++) {
 
124
            SoNode *child = group->getChild(i);
 
125
            if (!child->isOfType(SoSeparator::getClassTypeId()) &&
 
126
                child->affectsState()) {
 
127
 
 
128
                // Put the node bellow separator
 
129
                SoSeparator *s = new SoSeparator;
 
130
                s->addChild(group->getChild(i));
 
131
                group->replaceChild(i, s);
 
132
                numModifiedChildren++;
 
133
 
 
134
                // Create the scene that may be affected by the node
 
135
                if (!affectedScene) {
 
136
 
 
137
                    // Create the graph of nodes that may be influenced
 
138
                    // by the node
 
139
                    const SoFullPath *path = (const SoFullPath*)action->getCurPath();
 
140
                    //assert(path->getLength() == 0 ||
 
141
                    //       path->getNode(path->getLength()-1) == group &&
 
142
                    //       "Group being restructured is not at the end of the path.");
 
143
                    int stackLevel = stack.size()-2;
 
144
                    for (int j=path->getLength()-2; j>=0; j--, stackLevel--) {
 
145
 
 
146
                        // Get the appropriate stack level of nodesToRemove
 
147
                        assert(stackLevel >=0);
 
148
                        std::vector<int> &nodesToRemove = stack[stackLevel];
 
149
 
 
150
                        // Get parent and index of the current group
 
151
                        SoNode *parent = path->getNode(j);
 
152
                        int childIndex = path->getIndex(j+1);
 
153
                        const SoChildList *chl = parent->getChildren();
 
154
                        assert(chl->operator[](childIndex) == path->getNode(j+1) &&
 
155
                               "Wrong indexing.");
 
156
 
 
157
                        // Create affected scene graph
 
158
                        if (!affectedScene)
 
159
                            affectedScene = new SoGroup;
 
160
 
 
161
                        // Copy nodes to the graph
 
162
                        for (int k=childIndex+1, n=chl->getLength(); k<n; k++) {
 
163
                            affectedScene->addChild(chl->operator[](k));
 
164
                            nodesToRemove.push_back(k);
 
165
                            numRemovedNodes++;
 
166
                        }
 
167
 
 
168
                        // Stop recursion if we reached separator
 
169
                        // or other state-preserving node.
 
170
                        if (nodePreservesState(parent))
 
171
                            break;
 
172
                    }
 
173
                }
 
174
 
 
175
                // Append the affected graph to the separator
 
176
                s->addChild(affectedScene);
 
177
            }
 
178
        }
 
179
    }
 
180
 
 
181
#ifdef DEBUG_IV_PLUGIN
 
182
    if (numModifiedChildren == 0)
 
183
    {
 
184
        OSG_DEBUG << ": no changes necessary" << std::endl;
 
185
    }
 
186
    else
 
187
    {
 
188
        OSG_DEBUG << ": " << numModifiedChildren <<
 
189
                  " nodes of " << childrenTotal << " restruc., " <<
 
190
                  numRemovedNodes << " removed" << std::endl;
 
191
    }
 
192
#endif
 
193
 
 
194
    return SoCallbackAction::CONTINUE;
 
195
}
 
196
///////////////////////////////////////////////////////////
 
197
SoCallbackAction::Response
 
198
ConvertFromInventor::restructurePreNode(void* data, SoCallbackAction* action,
 
199
                             const SoNode* node)
 
200
{
 
201
    std::vector<std::vector<int> > &stack = *((std::vector<std::vector<int> >*)data);
 
202
 
 
203
    stack.push_back(std::vector<int>());
 
204
 
 
205
    return SoCallbackAction::CONTINUE;
 
206
}
 
207
////////////////////////////////////////////////////////////////////
 
208
SoCallbackAction::Response
 
209
ConvertFromInventor::restructurePostNode(void* data, SoCallbackAction* action,
 
210
                              const SoNode* node)
 
211
{
 
212
    std::vector<std::vector<int> > &stack = *((std::vector<std::vector<int> >*)data);
 
213
 
 
214
    assert(stack.size() > 0 && "Stack is empty");
 
215
    std::vector<int> &nodesToRemove = stack.back();
 
216
 
 
217
    if (nodesToRemove.size() > 0) {
 
218
 
 
219
#ifdef DEBUG_IV_PLUGIN
 
220
        OSG_DEBUG << NOTIFY_HEADER << "postNode()   "
 
221
                  << node->getTypeId().getName().getString()
 
222
                  << " (level " << stack.size() << ") removed "
 
223
                  << nodesToRemove.size() << " node(s)" << std::endl;
 
224
#endif
 
225
 
 
226
        assert(node->getChildren());
 
227
        for (int i=nodesToRemove.size()-1; i>=0; i--) {
 
228
            //assert(i==0 || nodesToRemove[i-1] < nodesToRemove[i] &&
 
229
            //       "Children to remove are not in order.");
 
230
            node->getChildren()->remove(nodesToRemove[i]);
 
231
        }
 
232
    }
 
233
 
 
234
    stack.pop_back();
 
235
 
 
236
    return SoCallbackAction::CONTINUE;
 
237
}
 
238
///////////////////////////////////////////////////////////////////
 
239
void
 
240
ConvertFromInventor::preprocess(SoNode* root)
 
241
{
 
242
#ifdef DEBUG_IV_PLUGIN
 
243
    OSG_DEBUG << NOTIFY_HEADER << "Preprocessing..." << std::endl;
 
244
#endif
 
245
 
 
246
    SoCallbackAction action;
 
247
    std::vector<std::vector<int> > stackOfNodesToRemove;
 
248
 
 
249
    // Callbacks for troublesome nodes
 
250
    action.addPreCallback(SoNode::getClassTypeId(),
 
251
                          restructurePreNode, &stackOfNodesToRemove);
 
252
    action.addPostCallback(SoLOD::getClassTypeId(),
 
253
                           restructure, &stackOfNodesToRemove);
 
254
    action.addPostCallback(SoNode::getClassTypeId(),
 
255
                           restructurePostNode, &stackOfNodesToRemove);
 
256
 
 
257
    // Traverse the scene
 
258
    action.apply(root);
 
259
 
 
260
#if 0 // For debugging purposes: Write preprocessed scene to the file
 
261
    SoOutput out;
 
262
    out.openFile("preprocess.iv");
 
263
    SoWriteAction wa(&out);
 
264
    wa.apply(root);
 
265
#endif
 
266
}
 
267
///////////////////////////////////////////////////////////
 
268
osg::Node*
 
269
ConvertFromInventor::convert(SoNode* ivRootNode)
 
270
{
 
271
#ifdef DEBUG_IV_PLUGIN
 
272
    OSG_DEBUG << NOTIFY_HEADER << "Converting..." << std::endl;
 
273
#endif
 
274
 
 
275
    // Transformation matrix for converting Inventor coordinate system to OSG
 
276
    // coordinate system
 
277
    osg::Matrix ivToOSGMat(osg::Matrix(1.0, 0.0, 0.0, 0.0,
 
278
                                       0.0, 0.0, 1.0, 0.0,
 
279
                                       0.0,-1.0, 0.0, 0.0,
 
280
                                       0.0, 0.0, 0.0, 1.0));
 
281
 
 
282
    // Root of the scene
 
283
    osg::ref_ptr<osg::Group> osgRootNode = new osg::MatrixTransform(ivToOSGMat);
 
284
 
 
285
    // Propagate node name
 
286
    osgRootNode->setName(ivRootNode->getName().getString());
 
287
 
 
288
    // Initialize Inventor state stack
 
289
    // (ivStateStack is used to track the state that is not accessible by
 
290
    // SoCallbackAction functions)
 
291
    ivStateStack.push(IvStateItem(ivRootNode, osgRootNode.get()));
 
292
 
 
293
    // Create callback actions for the inventor nodes
 
294
    // These callback functions perform the conversion
 
295
    // note: if one class is derived from the other and both callbacks
 
296
    // are registered, both functions will be called
 
297
    SoCallbackAction cbAction;
 
298
 
 
299
    // Node callbacks are used for detecting which node
 
300
    // preserves state (like SoSeparator) and which not.
 
301
    // There are few nodes that behave like SoSeparator although they
 
302
    // are not derived from it.
 
303
    // Note: postNode callback is moved down, because it must be
 
304
    // called as the last callback.
 
305
    cbAction.addPreCallback(SoNode::getClassTypeId(), preNode, this);
 
306
 
 
307
    // SoTransformSeparator callbacks. Special handling of transformations.
 
308
    cbAction.addPreCallback(SoTransformSeparator::getClassTypeId(), preTransformSeparator, this);
 
309
    cbAction.addPostCallback(SoTransformSeparator::getClassTypeId(), postTransformSeparator, this);
 
310
 
 
311
    // LOD (Level of Detail) callbacks. Handles SoLOD nodes.
 
312
    // FIXME: SoLevelOfDetail needs to be implemented and tested.
 
313
    cbAction.addPreCallback(SoLOD::getClassTypeId(), preLOD, this);
 
314
    cbAction.addPostCallback(SoLOD::getClassTypeId(), postLOD, this);
 
315
 
 
316
    // Shape callbacks collects all triangles and all the geometry data.
 
317
    // Moreover, they handle transformations, ...
 
318
    cbAction.addPreCallback(SoShape::getClassTypeId(), preShape, this);
 
319
    cbAction.addPostCallback(SoShape::getClassTypeId(), postShape, this);
 
320
 
 
321
    // Handling of textures
 
322
    cbAction.addPostCallback(SoTexture2::getClassTypeId(),
 
323
                            postTexture, this);
 
324
#ifdef __COIN__
 
325
    cbAction.addPostCallback(SoVRMLImageTexture::getClassTypeId(),
 
326
                            postTexture, this);
 
327
    cbAction.addPostCallback(SoVRMLAppearance::getClassTypeId(),
 
328
                            postTexture, this);
 
329
#endif
 
330
 
 
331
#ifdef __COIN__
 
332
    cbAction.addPreCallback(SoInfo::getClassTypeId(), preInfo, this);
 
333
#endif
 
334
 
 
335
    // Lights
 
336
    cbAction.addPreCallback(SoLight::getClassTypeId(), preLight, this);
 
337
 
 
338
    // Environment (ambient light,...)
 
339
    cbAction.addPreCallback(SoEnvironment::getClassTypeId(), preEnvironment, this);
 
340
 
 
341
    // Shaders
 
342
#ifdef INVENTOR_SHADERS_AVAILABLE
 
343
    cbAction.addPreCallback(SoShaderProgram::getClassTypeId(), preShaderProgram, this);
 
344
#endif
 
345
 
 
346
    // Motion callbacks
 
347
    cbAction.addPreCallback(SoRotor::getClassTypeId(), preRotor, this);
 
348
    cbAction.addPreCallback(SoPendulum::getClassTypeId(), prePendulum, this);
 
349
    cbAction.addPreCallback(SoShuttle::getClassTypeId(), preShuttle, this);
 
350
 
 
351
    // Geometry callbacks
 
352
    cbAction.addTriangleCallback(SoShape::getClassTypeId(), addTriangleCB, this);
 
353
    cbAction.addLineSegmentCallback(SoShape::getClassTypeId(), addLineSegmentCB,
 
354
                                    this);
 
355
    cbAction.addPointCallback(SoShape::getClassTypeId(), addPointCB, this);
 
356
 
 
357
    // Post node callback
 
358
    cbAction.addPostCallback(SoNode::getClassTypeId(), postNode, this);
 
359
 
 
360
    // Traverse the inventor scene graph
 
361
    cbAction.apply(ivRootNode);
 
362
 
 
363
    // Remove superfluous group
 
364
    if (osgRootNode->getNumChildren() == 1) {
 
365
        osg::ref_ptr<osg::Group> toRemove = osgRootNode->getChild(0)->asGroup();
 
366
        assert(toRemove.get() &&
 
367
               strcmp(toRemove->className(), "Group") == 0 &&
 
368
               "IvStateStack osg graph is expected to be "
 
369
               "headed by osg::Group");
 
370
        osgRootNode->removeChild(0u);
 
371
        for (int i=0, c=toRemove->getNumChildren(); i<c; i++)
 
372
            osgRootNode->addChild(toRemove->getChild(i));
 
373
    }
 
374
 
 
375
    return osgRootNode.get();
 
376
}
 
377
///////////////////////////////////////////////////////////////////
 
378
static void
 
379
notifyAboutMatrixContent(const osg::NotifySeverity level, const SbMatrix &m)
 
380
{
 
381
    SbVec3f t,s;
 
382
    SbRotation r,so;
 
383
    m.getTransform(t, r, s, so);
 
384
    SbVec3f axis;
 
385
    float angle;
 
386
    r.getValue(axis, angle);
 
387
    OSG_NOTIFY(level) << NOTIFY_HEADER << "  Translation: " <<
 
388
              t[0] << "," << t[1] << "," << t[2] << std::endl;
 
389
    OSG_NOTIFY(level) << NOTIFY_HEADER << "  Rotation: (" <<
 
390
              axis[0] << "," << axis[1] << "," << axis[2] << ")," << angle << std::endl;
 
391
}
 
392
///////////////////////////////////////////////////////////////////
 
393
void
 
394
ConvertFromInventor::appendNode(osg::Node *n, const SoCallbackAction *action)
 
395
{
 
396
    IvStateItem &ivState = ivStateStack.top();
 
397
    SbMatrix currentMatrix = action->getModelMatrix();
 
398
    SbMatrix inheritedMatrix = ivState.inheritedTransformation;
 
399
 
 
400
    // Keep children order - this must be done for some nodes like
 
401
    // SoSwitch, SoLOD,...
 
402
    // We will append dummy nodes if the child is expected to be on
 
403
    // higher index.
 
404
    if (ivState.flags & IvStateItem::KEEP_CHILDREN_ORDER) {
 
405
 
 
406
        // Determine child index
 
407
        int childIndex = -1;
 
408
        const SoFullPath *path = (const SoFullPath*)(((SoCallbackAction*)action)->getCurPath());
 
409
        for (int i=path->getLength()-2; i>=0; i--)
 
410
            if (path->getNode(i) == ivState.keepChildrenOrderParent) {
 
411
                childIndex = path->getIndex(i+1);
 
412
                assert(ivState.keepChildrenOrderParent->getChildren());
 
413
                assert((ivState.keepChildrenOrderParent->getChildren()->operator[](childIndex) == path->getNode(i+1)) && "Indexing is wrong.");
 
414
                break;
 
415
            }
 
416
        assert(childIndex != -1 && "Node did not found.");
 
417
 
 
418
        // Append dummy nodes to keep children order
 
419
        assert(int(ivState.osgStateRoot->getNumChildren()) <= childIndex &&
 
420
               "Number of children in ivState.osgStateRoot is too big.");
 
421
        while (int(ivState.osgStateRoot->getNumChildren()) < childIndex)
 
422
            ivState.osgStateRoot->addChild(new osg::Node);
 
423
    }
 
424
 
 
425
#ifdef DEBUG_IV_PLUGIN
 
426
    OSG_DEBUG << NOTIFY_HEADER << "appendNode: "
 
427
              << n->className();
 
428
#endif
 
429
 
 
430
    if (currentMatrix == inheritedMatrix) {
 
431
 
 
432
        // just append node to the current group in osg scene graph
 
433
        ivState.osgStateRoot->addChild(n);
 
434
        ivState.lastUsedTransformation = inheritedMatrix;
 
435
 
 
436
#ifdef DEBUG_IV_PLUGIN
 
437
        if (osg::isNotifyEnabled(osg::DEBUG_INFO))
 
438
            OSG_DEBUG <<
 
439
                      " uses parent transformation" << std::endl;
 
440
#endif
 
441
 
 
442
    } else {
 
443
 
 
444
        if (!(ivState.flags & IvStateItem::KEEP_CHILDREN_ORDER) &&
 
445
            currentMatrix == ivState.lastUsedTransformation) {
 
446
 
 
447
            // Previous node has the same transformation. Let's use it.
 
448
            assert(ivState.osgStateRoot->getNumChildren() != 0 &&
 
449
                   "This should never happen - there is no item on "
 
450
                   "osgShapeGraphs list while want to use last one.");
 
451
            osg::Transform *t = ivState.osgStateRoot->getChild(ivState.osgStateRoot->getNumChildren()-1)->asTransform();
 
452
            assert(t && "This should never happen - want to use "
 
453
                        "transformation of previous scene geometry "
 
454
                        "and it does not have Transform node.");
 
455
            t->addChild(n);
 
456
 
 
457
#ifdef DEBUG_IV_PLUGIN
 
458
            if (osg::isNotifyEnabled(osg::DEBUG_INFO))
 
459
                OSG_DEBUG <<
 
460
                          " reuses previous transformation" << std::endl;
 
461
#endif
 
462
 
 
463
        } else {
 
464
 
 
465
            // We need a new transformation node
 
466
            osg::Matrix m(osg::Matrix(currentMatrix.operator float*()));
 
467
            osg::Matrix m2;
 
468
            m2.invert(osg::Matrix(inheritedMatrix.operator float*()));
 
469
            m.postMult(m2);
 
470
            osg::MatrixTransform *mt = new osg::MatrixTransform(m);
 
471
            mt->addChild(n);
 
472
 
 
473
            ivState.osgStateRoot->addChild(mt);
 
474
            ivState.lastUsedTransformation = currentMatrix;
 
475
 
 
476
#ifdef DEBUG_IV_PLUGIN
 
477
            if (osg::isNotifyEnabled(osg::DEBUG_INFO)) {
 
478
                OSG_DEBUG <<
 
479
                          " uses local transformation:" << std::endl;
 
480
                notifyAboutMatrixContent(osg::DEBUG_INFO,
 
481
                          SbMatrix((SbMat&)(*osg::Matrixf(m).ptr())));
 
482
            }
 
483
#endif
 
484
        }
 
485
    }
 
486
}
 
487
///////////////////////////////////////////////////////////////////
 
488
void
 
489
ConvertFromInventor::ivPushState(const SoCallbackAction *action,
 
490
                                 const SoNode *initiator, const int flags,
 
491
                                 osg::Group *root)
 
492
{
 
493
    assert(ivStateStack.size() >= 1 && "There must be at least one "
 
494
           "value in the ivStateStack to use ivPushState function.");
 
495
 
 
496
    // Propagate node name
 
497
    root->setName(initiator->getName().getString());
 
498
 
 
499
    // APPEND_AT_PUSH
 
500
    if (flags & IvStateItem::APPEND_AT_PUSH)
 
501
        appendNode(root, action);
 
502
 
 
503
    // Push state
 
504
    ivStateStack.push(IvStateItem(ivStateStack.top(), action, initiator, flags, root));
 
505
 
 
506
}
 
507
///////////////////////////////////////////////////////////////////
 
508
void
 
509
ConvertFromInventor::ivPopState(const SoCallbackAction *action,
 
510
                                const SoNode *initiator)
 
511
{
 
512
    bool multipop;
 
513
    do {
 
514
        assert(ivStateStack.size() >= 2 && "There must be at least two "
 
515
               "values in the ivStateStack to use ivPopState function.");
 
516
 
 
517
        // Get multipop value
 
518
        IvStateItem ivState = ivStateStack.top();
 
519
        multipop = ivState.flags & IvStateItem::MULTI_POP;
 
520
        //assert(multipop ||
 
521
        //       ivState.pushInitiator == initiator &&
 
522
        //       "ivStateStack push was initiated by different node.");
 
523
 
 
524
        // Get osgStateRoot (note: we HAVE TO reference it)
 
525
        osg::ref_ptr<osg::Group> r = ivState.osgStateRoot;
 
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.get(), action);
 
542
 
 
543
    } while (multipop);
 
544
 
 
545
}
 
546
///////////////////////////////////////////////////////////////////
 
547
SoCallbackAction::Response
 
548
ConvertFromInventor::preNode(void* data, SoCallbackAction* action,
 
549
                             const SoNode* node)
 
550
{
 
551
#ifdef DEBUG_IV_PLUGIN
 
552
    OSG_DEBUG << 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_DEBUG << 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
////////////////////////////////////////////////////////////////////
 
572
SoCallbackAction::Response
 
573
ConvertFromInventor::postNode(void* data, SoCallbackAction* action,
 
574
                              const SoNode* node)
 
575
{
 
576
#ifdef DEBUG_IV_PLUGIN
 
577
    OSG_DEBUG << NOTIFY_HEADER << "postNode()   "
 
578
              << node->getTypeId().getName().getString() << std::endl;
 
579
#endif
 
580
 
 
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_DEBUG << 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
///////////////////////////////////////////////////////////////////
 
600
SoCallbackAction::Response
 
601
ConvertFromInventor::preTransformSeparator(void* data, SoCallbackAction* action,
 
602
                             const SoNode* node)
 
603
{
 
604
#ifdef DEBUG_IV_PLUGIN
 
605
    OSG_DEBUG << 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
////////////////////////////////////////////////////////////////////
 
617
SoCallbackAction::Response
 
618
ConvertFromInventor::postTransformSeparator(void* data, SoCallbackAction* action,
 
619
                              const SoNode* node)
 
620
{
 
621
#ifdef DEBUG_IV_PLUGIN
 
622
    OSG_DEBUG << 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
///////////////////////////////////////////////////////////////////
 
634
SoCallbackAction::Response
 
635
ConvertFromInventor::preLOD(void* data, SoCallbackAction* action,
 
636
                            const SoNode* node)
 
637
{
 
638
#ifdef DEBUG_IV_PLUGIN
 
639
    OSG_DEBUG << 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
//////////////////////////////////////////////////////////////
 
692
SoCallbackAction::Response
 
693
ConvertFromInventor::postLOD(void* data, SoCallbackAction* action,
 
694
                             const SoNode* node)
 
695
{
 
696
#ifdef DEBUG_IV_PLUGIN
 
697
    OSG_DEBUG << 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_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_DEBUG << 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
///////////////////////////////////////////////////////////////////
 
760
SoCallbackAction::Response
 
761
ConvertFromInventor::preShape(void* data, SoCallbackAction* action,
 
762
                              const SoNode* node)
 
763
{
 
764
#ifdef DEBUG_IV_PLUGIN
 
765
    OSG_DEBUG << NOTIFY_HEADER << "preShape()   "
 
766
              << node->getTypeId().getName().getString() << std::endl;
 
767
#endif
 
768
 
 
769
    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
 
770
 
 
771
    // Normal and color binding map from Inventor to OSG
 
772
    static std::map<SoNormalBinding::Binding, deprecated_osg::Geometry::AttributeBinding>
 
773
        normBindingMap;
 
774
    static std::map<SoMaterialBinding::Binding, deprecated_osg::Geometry::AttributeBinding>
 
775
        colBindingMap;
 
776
    static bool firstTime = true;
 
777
    if (firstTime)
 
778
    {
 
779
        normBindingMap[SoNormalBinding::OVERALL]
 
780
                                        = deprecated_osg::Geometry::BIND_OVERALL;
 
781
        normBindingMap[SoNormalBinding::PER_PART]
 
782
                                        = deprecated_osg::Geometry::BIND_PER_PRIMITIVE;
 
783
        normBindingMap[SoNormalBinding::PER_PART_INDEXED]
 
784
                                        = deprecated_osg::Geometry::BIND_PER_PRIMITIVE;
 
785
        normBindingMap[SoNormalBinding::PER_FACE]
 
786
                                        = deprecated_osg::Geometry::BIND_PER_PRIMITIVE;
 
787
        normBindingMap[SoNormalBinding::PER_FACE_INDEXED]
 
788
                                        = deprecated_osg::Geometry::BIND_PER_PRIMITIVE;
 
789
        normBindingMap[SoNormalBinding::PER_VERTEX]
 
790
                                        = deprecated_osg::Geometry::BIND_PER_VERTEX;
 
791
        normBindingMap[SoNormalBinding::PER_VERTEX_INDEXED]
 
792
                                        = deprecated_osg::Geometry::BIND_PER_VERTEX;
 
793
 
 
794
        colBindingMap[SoMaterialBinding::OVERALL]
 
795
                                        = deprecated_osg::Geometry::BIND_OVERALL;
 
796
        colBindingMap[SoMaterialBinding::PER_PART]
 
797
                                        = deprecated_osg::Geometry::BIND_PER_PRIMITIVE;
 
798
        colBindingMap[SoMaterialBinding::PER_PART_INDEXED]
 
799
                                        = deprecated_osg::Geometry::BIND_PER_PRIMITIVE;
 
800
        colBindingMap[SoMaterialBinding::PER_FACE]
 
801
                                        = deprecated_osg::Geometry::BIND_PER_PRIMITIVE;
 
802
        colBindingMap[SoMaterialBinding::PER_FACE_INDEXED]
 
803
                                        = deprecated_osg::Geometry::BIND_PER_PRIMITIVE;
 
804
        colBindingMap[SoMaterialBinding::PER_VERTEX]
 
805
                                        = deprecated_osg::Geometry::BIND_PER_VERTEX;
 
806
        colBindingMap[SoMaterialBinding::PER_VERTEX_INDEXED]
 
807
                                        = deprecated_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 = deprecated_osg::Geometry::BIND_PER_VERTEX;
 
821
        thisPtr->colorBinding = deprecated_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();
 
836
 
 
837
    return SoCallbackAction::CONTINUE;
 
838
}
 
839
///////////////////////////////////////////////////////////
 
840
// OSG doesn't seem to have a transpose function         //
 
841
//for matrices                                           //
 
842
///////////////////////////////////////////////////////////
 
843
void
 
844
ConvertFromInventor::transposeMatrix(osg::Matrix& mat)
 
845
{
 
846
    float tmp;
 
847
    for (int j = 0; j < 4; j++)
 
848
    {
 
849
        for (int i = j + 1; i < 4; i++)
 
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
}
 
858
////////////////////////////////////////////////////////////////////
 
859
SoCallbackAction::Response
 
860
ConvertFromInventor::postShape(void* data, SoCallbackAction* action,
 
861
                               const SoNode* node)
 
862
{
 
863
#ifdef DEBUG_IV_PLUGIN
 
864
    OSG_DEBUG << NOTIFY_HEADER << "postShape()  "
 
865
              << node->getTypeId().getName().getString() << std::endl;
 
866
#endif
 
867
 
 
868
    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
 
869
 
 
870
 
 
871
    // Create a new Geometry
 
872
    osg::ref_ptr<deprecated_osg::Geometry> geometry = new deprecated_osg::Geometry;
 
873
 
 
874
 
 
875
    osg::ref_ptr<osg::Vec3Array> coords = new osg::Vec3Array(thisPtr->vertices.size());
 
876
    for (unsigned int i = 0; i < thisPtr->vertices.size(); i++)
 
877
        (*coords)[i] = thisPtr->vertices[i];
 
878
    geometry->setVertexArray(coords.get());
 
879
 
 
880
    osg::ref_ptr<osg::Vec3Array> norms = NULL;
 
881
    if (thisPtr->normalBinding == deprecated_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
        {
 
892
            (*norms)[i] = thisPtr->normals[i];
 
893
        }
 
894
    }
 
895
    geometry->setNormalArray(norms.get());
 
896
    geometry->setNormalBinding(thisPtr->normalBinding);
 
897
 
 
898
    // Set the colors
 
899
    osg::ref_ptr<osg::Vec4Array> cols;
 
900
    if (thisPtr->colorBinding == deprecated_osg::Geometry::BIND_OVERALL)
 
901
    {
 
902
        cols = new osg::Vec4Array(1);
 
903
        SbColor ambient, diffuse, specular, emission;
 
904
        float transparency, shininess;
 
905
        action->getMaterial(ambient, diffuse, specular, emission, shininess,
 
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
    }
 
915
    geometry->setColorArray(cols.get());
 
916
    geometry->setColorBinding(thisPtr->colorBinding);
 
917
 
 
918
 
 
919
    if (thisPtr->textureCoords.empty())
 
920
    {
 
921
        OSG_DEBUG<<"tex coords not found"<<std::endl;
 
922
    }
 
923
    else
 
924
    {
 
925
 
 
926
        // report texture coordinate conditions
 
927
        if (action->getNumTextureCoordinates()>0)
 
928
        {
 
929
            OSG_DEBUG<<"tex coords found"<<std::endl;
 
930
        }
 
931
        else
 
932
        {
 
933
           OSG_DEBUG<<"tex coords generated"<<std::endl;
 
934
        }
 
935
 
 
936
        // Get the texture transformation matrix
 
937
        osg::Matrix textureMat;
 
938
        textureMat.set((float *) action->getTextureMatrix().getValue());
 
939
 
 
940
        // Transform texture coordinates if texture matrix is not an identity mat
 
941
        osg::Matrix identityMat;
 
942
        identityMat.makeIdentity();
 
943
        osg::ref_ptr<osg::Vec2Array> texCoords
 
944
            = new osg::Vec2Array(thisPtr->textureCoords.size());
 
945
        if (textureMat == identityMat)
 
946
        {
 
947
            // Set the texture coordinates
 
948
            for (unsigned int i = 0; i < thisPtr->textureCoords.size(); i++)
 
949
                (*texCoords)[i] = thisPtr->textureCoords[i];
 
950
        }
 
951
        else
 
952
        {
 
953
            // Transform and set the texture coordinates
 
954
            for (unsigned int i = 0; i < thisPtr->textureCoords.size(); i++)
 
955
            {
 
956
                osg::Vec3 transVec = textureMat.preMult(
 
957
                        osg::Vec3(thisPtr->textureCoords[i][0],
 
958
                                  thisPtr->textureCoords[i][1],
 
959
                                  0.0));
 
960
                (*texCoords)[i].set(transVec.x(), transVec.y());
 
961
            }
 
962
        }
 
963
 
 
964
        geometry->setTexCoordArray(0, texCoords.get());
 
965
    }
 
966
 
 
967
    // Set the parameters for the geometry
 
968
 
 
969
    geometry->addPrimitiveSet(new osg::DrawArrays(thisPtr->primitiveType,0,
 
970
                                                  coords->size()));
 
971
    // Get the StateSet for the geoset
 
972
    osg::ref_ptr<osg::StateSet> stateSet = thisPtr->getStateSet(action);
 
973
    geometry->setStateSet(stateSet.get());
 
974
 
 
975
    // Add the geoset to a geode
 
976
    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
 
977
    geode->addDrawable(geometry.get());
 
978
 
 
979
    // Set object names
 
980
    const char* name = node->getName().getString();
 
981
    geometry->setName(name);
 
982
    geode->setName(strlen(name)>0 ? name : stateSet->getName());
 
983
 
 
984
    // Transformation and scene graph building
 
985
    thisPtr->appendNode(geode.get(), action);
 
986
 
 
987
    return SoCallbackAction::CONTINUE;
 
988
}
 
989
///////////////////////////////////////////////////////////////
 
990
 
 
991
#ifdef __COIN__
 
992
 
 
993
//
 
994
//  Following classes can be used for redirecting texture loading from Coin routines
 
995
//  that use simage library to native OSG routines. This removes the dependency
 
996
//  on simage and using the same routines by OSG and Coin may provide some
 
997
//  advantages to programmer as well.
 
998
//
 
999
//  Classes that are loading textures: SoTexture2, SoTexture3 (since Coin 2.0),
 
1000
//  SoVRMLImageTexture (since Coin 2.0), SoVRMLMovieTexture (not yet implemented in Coin)
 
1001
//
 
1002
//  Principle: SoType::overrideType() can be used for changing
 
1003
//  of the class instantiation method. So let's change it and create our own
 
1004
//  API compatible class that will just not load texture from file.
 
1005
//
 
1006
 
 
1007
#include <Inventor/nodes/SoTexture2.h>
 
1008
#include <Inventor/nodes/SoTexture3.h>
 
1009
#include <Inventor/VRMLnodes/SoVRMLImageTexture.h>
 
1010
 
 
1011
 
 
1012
// This macro gives the common API for all overriding classes.
 
1013
#define OVERRIDE_HEADER(_class_,_parent_) \
 
1014
public: \
 
1015
\
 
1016
    static void overrideClass() \
 
1017
    { \
 
1018
        if (overrideCounter == 0) { \
 
1019
            SoType t = _parent_::getClassTypeId(); \
 
1020
            oldMethod = t.getInstantiationMethod(); \
 
1021
            SoType::overrideType(t, _class_::createInstance); \
 
1022
        } \
 
1023
        overrideCounter++; \
 
1024
    } \
 
1025
\
 
1026
    static SbBool cancelOverrideClass() \
 
1027
    { \
 
1028
        assert(overrideCounter > 0 && #_class_ "::cancelOverride called more times\n" \
 
1029
               "than " #_class_ "::override"); \
 
1030
        assert(_parent_::getClassTypeId().getInstantiationMethod() == _class_::createInstance && \
 
1031
               "Somebody changed " #_parent_ " instantiation method\n" \
 
1032
               "(probably through SoType::overrideType) and did not restored it."); \
 
1033
\
 
1034
        overrideCounter--; \
 
1035
        if (overrideCounter == 0) \
 
1036
            SoType::overrideType(_parent_::getClassTypeId(), oldMethod); \
 
1037
\
 
1038
        return overrideCounter==0; \
 
1039
    } \
 
1040
\
 
1041
private: \
 
1042
\
 
1043
    static int overrideCounter; \
 
1044
\
 
1045
    static SoType::instantiationMethod oldMethod; \
 
1046
\
 
1047
    static void* createInstance() \
 
1048
    { \
 
1049
        return new _class_; \
 
1050
    }
 
1051
 
 
1052
#define OVERRIDE_SRC(_class_) \
 
1053
\
 
1054
int _class_::overrideCounter = 0; \
 
1055
SoType::instantiationMethod _class_::oldMethod
 
1056
 
 
1057
 
 
1058
class SoTexture2Osg : public SoTexture2 {
 
1059
    OVERRIDE_HEADER(SoTexture2Osg, SoTexture2);
 
1060
protected:
 
1061
    virtual SbBool readInstance(SoInput *in, unsigned short flags);
 
1062
};
 
1063
 
 
1064
 
 
1065
class SoTexture3Osg : public SoTexture3 {
 
1066
    OVERRIDE_HEADER(SoTexture3Osg, SoTexture3);
 
1067
protected:
 
1068
    virtual SbBool readInstance(SoInput *in, unsigned short flags);
 
1069
};
 
1070
 
 
1071
 
 
1072
class SoVRMLImageTextureOsg : public SoVRMLImageTexture {
 
1073
    OVERRIDE_HEADER(SoVRMLImageTextureOsg, SoVRMLImageTexture);
 
1074
protected:
 
1075
    virtual SbBool readInstance(SoInput *in, unsigned short flags);
 
1076
};
 
1077
 
 
1078
OVERRIDE_SRC(SoTexture2Osg);
 
1079
OVERRIDE_SRC(SoTexture3Osg);
 
1080
OVERRIDE_SRC(SoVRMLImageTextureOsg);
 
1081
 
 
1082
static osgDB::ReaderWriter::Options* createOptions()
 
1083
{
 
1084
    const SbStringList &soInputDirectories = SoInput::getDirectories();
 
1085
    osgDB::ReaderWriter::Options *options = new osgDB::ReaderWriter::Options;
 
1086
    osgDB::FilePathList &pathList = options->getDatabasePathList();
 
1087
    int c = soInputDirectories.getLength();
 
1088
    for (int i=0; i<c; i++)
 
1089
        pathList.push_back(soInputDirectories[i]->getString());
 
1090
 
 
1091
    return options;
 
1092
}
 
1093
 
 
1094
static osg::Image* loadImage(const char *fileName, osgDB::ReaderWriter::Options *options)
 
1095
{
 
1096
    osg::ref_ptr<osg::Image> osgImage = osgDB::readImageFile(fileName, options);
 
1097
 
 
1098
    if (!osgImage)
 
1099
    {
 
1100
        OSG_WARN << NOTIFY_HEADER << "Could not read texture file '" << fileName << "'.";
 
1101
        return 0;
 
1102
    }
 
1103
 
 
1104
    if (!osgImage->isDataContiguous())
 
1105
    {
 
1106
        OSG_WARN << NOTIFY_HEADER << "Inventor cannot handle non contiguous image data found in texture file '" << fileName << "'.";
 
1107
        return 0;
 
1108
    }
 
1109
 
 
1110
    return osgImage.release();
 
1111
}
 
1112
 
 
1113
SbBool SoTexture2Osg::readInstance(SoInput *in, unsigned short flags)
 
1114
{
 
1115
    // disable notification and read inherited fields
 
1116
    SbBool oldNotify = filename.enableNotify(FALSE);
 
1117
    SbBool readOK = SoNode::readInstance(in, flags);
 
1118
    this->setReadStatus((int) readOK);
 
1119
 
 
1120
    // if file name given
 
1121
    if (readOK && !filename.isDefault() && filename.getValue() != "")
 
1122
    {
 
1123
        // create options and read the file
 
1124
        osgDB::ReaderWriter::Options *options = createOptions();
 
1125
        osg::ref_ptr<osg::Image> image = loadImage(filename.getValue().getString(), options);
 
1126
 
 
1127
        if (image.valid())
 
1128
        {
 
1129
            // get image dimensions and data
 
1130
            int nc = osg::Image::computeNumComponents(image->getPixelFormat());
 
1131
            SbVec2s size(image->s(), image->t());
 
1132
            unsigned char *bytes = image->data();
 
1133
 
 
1134
            // disable notification on image while setting data from filename
 
1135
            // as a notify will cause a filename.setDefault(TRUE)
 
1136
            SbBool oldnotify = this->image.enableNotify(FALSE);
 
1137
            this->image.setValue(size, nc, bytes);
 
1138
            this->image.enableNotify(oldnotify);
 
1139
            // PRIVATE(this)->glimagevalid = FALSE; -> recreate GL image in next GLRender()
 
1140
            // We can safely ignore this as we are not going to render the scene graph.
 
1141
        }
 
1142
        else
 
1143
        {
 
1144
            // image loading failed -> set readOK
 
1145
            readOK = FALSE;
 
1146
            this->setReadStatus(FALSE);
 
1147
        }
 
1148
 
 
1149
        // write filename, not image
 
1150
        this->image.setDefault(TRUE);
 
1151
    }
 
1152
 
 
1153
    filename.enableNotify(oldNotify);
 
1154
    return readOK;
 
1155
}
 
1156
 
 
1157
SbBool SoTexture3Osg::readInstance(SoInput *in, unsigned short flags)
 
1158
{
 
1159
    // disable notification and read inherited fields
 
1160
    SbBool oldNotify = filenames.enableNotify(FALSE);
 
1161
    SbBool readOK = SoNode::readInstance(in, flags);
 
1162
    this->setReadStatus((int) readOK);
 
1163
 
 
1164
    // if file name given
 
1165
    int numImages = filenames.getNum();
 
1166
    if (readOK && !filenames.isDefault() && numImages > 0)
 
1167
    {
 
1168
        // Fail on empty filenames
 
1169
        SbBool sizeError = FALSE;
 
1170
        SbBool retval = FALSE;
 
1171
        SbVec3s volumeSize(0,0,0);
 
1172
        int volumenc = -1;
 
1173
        int i;
 
1174
        for (i=0; i<numImages; i++)
 
1175
            if (this->filenames[i].getLength()==0) break;
 
1176
 
 
1177
        if (i==numImages)
 
1178
        {
 
1179
            // create options
 
1180
            osgDB::ReaderWriter::Options *options = createOptions();
 
1181
 
 
1182
            for (int n=0; n<numImages && !sizeError; n++)
 
1183
            {
 
1184
                // read the file
 
1185
                osg::ref_ptr<osg::Image> image = loadImage(filenames[n].getString(), options);
 
1186
 
 
1187
                if (!image.valid())
 
1188
                {
 
1189
                    OSG_WARN << NOTIFY_HEADER << "Could not read texture file #" << n << ": "
 
1190
                             << filenames[n].getString() << "\n";
 
1191
                    retval = FALSE;
 
1192
                }
 
1193
                else
 
1194
                {
 
1195
                    // get image dimensions and data
 
1196
                    int nc = osg::Image::computeNumComponents(image->getPixelFormat());
 
1197
                    SbVec3s size(image->s(), image->t(), image->r());
 
1198
                    if (size[2]==0)
 
1199
                        size[2]=1;
 
1200
                    unsigned char *imgbytes = image->data();
 
1201
 
 
1202
                    if (this->images.isDefault()) { // First time => allocate memory
 
1203
                        volumeSize.setValue(size[0],
 
1204
                                            size[1],
 
1205
                                            size[2]*numImages);
 
1206
                        volumenc = nc;
 
1207
                        this->images.setValue(volumeSize, nc, NULL);
 
1208
                    }
 
1209
                    else { // Verify size & components
 
1210
                        if (size[0] != volumeSize[0] ||
 
1211
                            size[1] != volumeSize[1] ||
 
1212
                            //FIXME: always 1 or what? (kintel 20020110)
 
1213
                            size[2] != (volumeSize[2]/numImages) ||
 
1214
                            nc != volumenc)
 
1215
                        {
 
1216
                            sizeError = TRUE;
 
1217
                            retval = FALSE;
 
1218
 
 
1219
                            OSG_WARN << NOTIFY_HEADER << "Texture file #" << n << " ("
 
1220
                                     << filenames[n].getString() << ") has wrong size: "
 
1221
                                     << "Expected (" << volumeSize[0] << "," << volumeSize[1] << ","
 
1222
                                     << volumeSize[2] << "," << volumenc << ") got ("
 
1223
                                     << size[0] << "," << size[1] << "," << size[2] << "," << nc << ")\n";
 
1224
                        }
 
1225
                    }
 
1226
 
 
1227
                    if (!sizeError)
 
1228
                    {
 
1229
                        // disable notification on images while setting data from the
 
1230
                        // filenames as a notify will cause a filenames.setDefault(TRUE).
 
1231
                        SbBool oldnotify = this->images.enableNotify(FALSE);
 
1232
                        unsigned char *volbytes = this->images.startEditing(volumeSize,
 
1233
                                                                            volumenc);
 
1234
                        memcpy(volbytes+int(size[0])*int(size[1])*int(size[2])*nc*n,
 
1235
                               imgbytes, int(size[0])*int(size[1])*int(size[2])*nc);
 
1236
                        this->images.finishEditing();
 
1237
                        this->images.enableNotify(oldnotify);
 
1238
                        // PRIVATE(this)->glimagevalid = FALSE; -> recreate GL image in next GLRender()
 
1239
                        // We can safely ignore this as we are not going to render the scene graph.
 
1240
                        retval = TRUE;
 
1241
                    }
 
1242
                }
 
1243
            }
 
1244
        }
 
1245
 
 
1246
        if (!retval)
 
1247
        {
 
1248
            // if image loading failed, set read status,
 
1249
            // but not set readOK to false (according to Coin source code)
 
1250
            this->setReadStatus(FALSE);
 
1251
        }
 
1252
 
 
1253
        // write filename, not image
 
1254
        this->images.setDefault(TRUE);
 
1255
    }
 
1256
 
 
1257
    filenames.enableNotify(oldNotify);
 
1258
    return readOK;
 
1259
}
 
1260
 
 
1261
SbBool SoVRMLImageTextureOsg::readInstance(SoInput *in, unsigned short flags)
 
1262
{
 
1263
    // disable notification and read inherited fields
 
1264
    SbBool oldNotify = url.enableNotify(FALSE);
 
1265
    SbBool readOK = SoNode::readInstance(in, flags);
 
1266
    this->setReadStatus((int) readOK);
 
1267
 
 
1268
    if (readOK) {
 
1269
 
 
1270
        // create options and read the file
 
1271
        osgDB::ReaderWriter::Options *options = createOptions();
 
1272
 
 
1273
        if (url.getNum() && url[0].getLength())
 
1274
        {
 
1275
            osg::ref_ptr<osg::Image> image = loadImage(url[0].getString(), options);
 
1276
            if (!image->valid())
 
1277
            {
 
1278
                OSG_WARN << "Could not read texture file: " << url[0].getString() << std::endl;
 
1279
                this->setReadStatus(FALSE);
 
1280
            }
 
1281
            else
 
1282
            {
 
1283
                // get image dimensions and data
 
1284
                int nc = osg::Image::computeNumComponents(image->getPixelFormat());
 
1285
                SbVec2s size(image->s(), image->t());
 
1286
                unsigned char *bytes = image->data();
 
1287
 
 
1288
                SbImage ivImage(bytes, size, nc);
 
1289
 
 
1290
                // disable notification on image while setting data from filename
 
1291
                // as a notify will cause a filename.setDefault(TRUE)
 
1292
                //SbBool oldnotify = this->image.enableNotify(FALSE); <- difficult to implement for SoVRMLImageTexture
 
1293
                this->setImage(ivImage);
 
1294
                //this->image.enableNotify(oldnotify); <- difficult to implement for SoVRMLImageTexture
 
1295
                // PRIVATE(this)->glimagevalid = FALSE; -> recreate GL image in next GLRender()
 
1296
                // We can safely ignore this as we are not going to render the scene graph.
 
1297
            }
 
1298
        }
 
1299
    }
 
1300
 
 
1301
    url.enableNotify(oldNotify);
 
1302
    return readOK;
 
1303
}
 
1304
 
 
1305
#endif /* __COIN__ */
 
1306
 
 
1307
///////////////////////////////////////////////////////////////
 
1308
SoCallbackAction::Response
 
1309
ConvertFromInventor::postTexture(void* data, SoCallbackAction *,
 
1310
                                 const SoNode* node)
 
1311
{
 
1312
#ifdef DEBUG_IV_PLUGIN
 
1313
    OSG_DEBUG << NOTIFY_HEADER << "postTexture()  "
 
1314
              << node->getTypeId().getName().getString();
 
1315
    if (node->isOfType(SoTexture2::getClassTypeId())) {
 
1316
        SoTexture2 *t = (SoTexture2*)node;
 
1317
        if (t->filename.getValue().getLength())
 
1318
            OSG_DEBUG << "  "  << t->filename.getValue().getString();
 
1319
    }
 
1320
    OSG_DEBUG << std::endl;
 
1321
#endif
 
1322
 
 
1323
    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
 
1324
    bool texturingEnabled = false;
 
1325
 
 
1326
    // Texture2
 
1327
    if (node->isOfType(SoTexture2::getClassTypeId())) {
 
1328
 
 
1329
        // Check whether texturing was enabled by the texture node
 
1330
        SoTexture2 *t = (SoTexture2*)node;
 
1331
        SbVec2s size;
 
1332
        int nc;
 
1333
        const unsigned char *data = t->image.getValue(size, nc);
 
1334
        texturingEnabled = t->filename.getValue().getLength() ||
 
1335
                           (data && size != SbVec2s(0,0));
 
1336
    }
 
1337
 
 
1338
#ifdef __COIN__
 
1339
 
 
1340
    // SoVRMLImageTexture
 
1341
    if (node->isOfType(SoVRMLImageTexture::getClassTypeId())) {
 
1342
 
 
1343
        // Check whether texturing was enabled by the texture node
 
1344
        SoVRMLImageTexture *t = (SoVRMLImageTexture*)node;
 
1345
        texturingEnabled = t->url.getNum() > 1 || (t->url.getNum() == 1 && t->url[0].getLength() > 0);
 
1346
    }
 
1347
 
 
1348
    // SoVRMLAppearance
 
1349
    if (node->isOfType(SoVRMLAppearance::getClassTypeId())) {
 
1350
 
 
1351
        // If SoVRMLAppearance is present and there is no texture
 
1352
        // inside, disable texturing
 
1353
        // FIXME: should SoVRMLAppearance really disable texturing
 
1354
        // when not containing SoVRMLImageTexture? Coin is not doing that,
 
1355
        // but it can be Coin bug.
 
1356
        SoVRMLAppearance *a = (SoVRMLAppearance*)node;
 
1357
        if (a->texture.getValue() == NULL)
 
1358
            thisPtr->ivStateStack.top().currentTexture = NULL;
 
1359
 
 
1360
        // Do not try to "optimize" this code by removing the return
 
1361
    // and use the one at the end of the function.
 
1362
    // It would break the case when there is texture inside
 
1363
    // the appearance node.
 
1364
        return SoCallbackAction::CONTINUE;
 
1365
    }
 
1366
 
 
1367
#endif /* __COIN__ */
 
1368
 
 
1369
    // Set current texture
 
1370
    if (texturingEnabled)
 
1371
        thisPtr->ivStateStack.top().currentTexture = node;
 
1372
    else
 
1373
        thisPtr->ivStateStack.top().currentTexture = NULL;
 
1374
 
 
1375
    return SoCallbackAction::CONTINUE;
 
1376
}
 
1377
//////////////////////////////////////////////////////////////////
 
1378
void ConvertFromInventor::transformLight(SoCallbackAction* action,
 
1379
                                         const SbVec3f& vec,
 
1380
                                         osg::Vec3& transVec)
 
1381
{
 
1382
    osg::Matrix modelMat;
 
1383
    modelMat.set((float *)action->getModelMatrix().getValue());
 
1384
 
 
1385
    transVec.set(vec[0], vec[1], vec[2]);
 
1386
    transVec = modelMat.preMult(transVec);
 
1387
}
 
1388
///////////////////////////////////////////////////////////////////
 
1389
SoCallbackAction::Response
 
1390
ConvertFromInventor::preLight(void* data, SoCallbackAction* action,
 
1391
                              const SoNode* node)
 
1392
{
 
1393
#ifdef DEBUG_IV_PLUGIN
 
1394
    OSG_DEBUG << NOTIFY_HEADER << "preLight()   "
 
1395
              << node->getTypeId().getName().getString() << std::endl;
 
1396
#endif
 
1397
 
 
1398
    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
 
1399
 
 
1400
    // Return if the light is not on
 
1401
    const SoLight* ivLight = (const SoLight*) node;
 
1402
    if (!ivLight->on.getValue())
 
1403
        return SoCallbackAction::CONTINUE;
 
1404
 
 
1405
    // Create new OSG light
 
1406
    IvStateItem &ivState = thisPtr->ivStateStack.top();
 
1407
    osg::ref_ptr<osg::Light> osgLight = new osg::Light;
 
1408
 
 
1409
    // Get color and intensity
 
1410
    SbVec3f lightColor = ivLight->color.getValue();
 
1411
    float intensity = ivLight->intensity.getValue();
 
1412
 
 
1413
    // Set color and intensity
 
1414
    osgLight->setAmbient(osg::Vec4(0.f, 0.f, 0.f, 1.f));
 
1415
    osgLight->setDiffuse(osg::Vec4(lightColor[0] * intensity,
 
1416
                                   lightColor[1] * intensity,
 
1417
                                   lightColor[2] * intensity, 1));
 
1418
    osgLight->setSpecular(osg::Vec4(lightColor[0] * intensity,
 
1419
                                    lightColor[1] * intensity,
 
1420
                                    lightColor[2] * intensity, 1));
 
1421
 
 
1422
    // Light type
 
1423
    if (node->isOfType(SoDirectionalLight::getClassTypeId()))
 
1424
    {
 
1425
        SoDirectionalLight *dirLight = (SoDirectionalLight *) node;
 
1426
 
 
1427
#if 1 // Let's place the light to its place in scene graph instead of
 
1428
      // old approach of global light group.
 
1429
        SbVec3f l(dirLight->direction.getValue());
 
1430
        osgLight->setPosition(osg::Vec4(-l[0], -l[1], -l[2] , 0.));
 
1431
#else
 
1432
        osg::Vec3 transVec;
 
1433
        thisPtr->transformLight(action, dirLight->direction.getValue(), transVec);
 
1434
        osgLight->setPosition(osg::Vec4(transVec.x(), transVec.y(),
 
1435
                                        transVec.z(), 0.));
 
1436
#endif
 
1437
    }
 
1438
    else if (node->isOfType(SoPointLight::getClassTypeId()))
 
1439
    {
 
1440
        SoPointLight* ptLight = (SoPointLight *) node;
 
1441
 
 
1442
#if 1 // Let's place the light to its place in scene graph instead of
 
1443
      // old approach of global light group.
 
1444
        SbVec3f l(ptLight->location.getValue());
 
1445
        osgLight->setPosition(osg::Vec4(l[0], l[1], l[2] , 1.));
 
1446
#else
 
1447
        osg::Vec3 transVec;
 
1448
        thisPtr->transformLight(action, ptLight->location.getValue(), transVec);
 
1449
        osgLight->setPosition(osg::Vec4(transVec.x(), transVec.y(),
 
1450
                                        transVec.z(), 1.));
 
1451
#endif
 
1452
    }
 
1453
    else if (node->isOfType(SoSpotLight::getClassTypeId()))
 
1454
    {
 
1455
        SoSpotLight* spotLight = (SoSpotLight *) node;
 
1456
 
 
1457
        osgLight->setSpotExponent(spotLight->dropOffRate.getValue() * 128.0);
 
1458
        osgLight->setSpotCutoff(spotLight->cutOffAngle.getValue()*180.0/osg::PI);
 
1459
 
 
1460
#if 1 // Let's place the light to its place in scene graph instead of
 
1461
      // old approach of global light group.
 
1462
        SbVec3f l(spotLight->location.getValue());
 
1463
        osgLight->setPosition(osg::Vec4(l[0], l[1], l[2] , 1.));
 
1464
        l = spotLight->direction.getValue();
 
1465
        osgLight->setDirection(osg::Vec3(l[0], l[1], l[2]));
 
1466
#else
 
1467
        osg::Vec3 transVec;
 
1468
        thisPtr->transformLight(action, spotLight->location.getValue(), transVec);
 
1469
        osgLight->setPosition(osg::Vec4(transVec.x(), transVec.y(),
 
1470
                                        transVec.z(), 1.));
 
1471
 
 
1472
        thisPtr->transformLight(action, spotLight->direction.getValue(),transVec);
 
1473
        osgLight->setDirection(osg::Vec3(transVec.x(), transVec.y(),
 
1474
                                         transVec.z()));
 
1475
#endif
 
1476
    }
 
1477
 
 
1478
    // Attenuation
 
1479
    if (!node->isOfType(SoDirectionalLight::getClassTypeId())) {
 
1480
        SbVec3f att = action->getLightAttenuation();
 
1481
        osgLight->setConstantAttenuation(att[2]);
 
1482
        osgLight->setLinearAttenuation(att[1]);
 
1483
        osgLight->setQuadraticAttenuation(att[0]);
 
1484
    } else {
 
1485
        // keep default light settings for directional light, e.g.
 
1486
        // no attenuation
 
1487
    }
 
1488
 
 
1489
    // Append the light into the scene and onto the state stack
 
1490
    osgLight->setLightNum(ivState.currentLights.size());
 
1491
    ivState.currentLights.push_back(osgLight);
 
1492
 
 
1493
    // Create LightSource
 
1494
    osg::ref_ptr<osg::LightSource> ls = new osg::LightSource();
 
1495
    ls->setLight(osgLight.get());
 
1496
 
 
1497
    // Set object names
 
1498
    const char* name = ivLight->getName().getString();
 
1499
    osgLight->setName(name);
 
1500
    //ls->setName(name); -> this will be handled bellow in ivPushState
 
1501
 
 
1502
#if 1 // Let's place the light to its place in scene graph instead of
 
1503
      // old approach of global light group.
 
1504
    thisPtr->ivPushState(action, node,
 
1505
              IvStateItem::MULTI_POP | IvStateItem::UPDATE_STATE |
 
1506
              IvStateItem::APPEND_AT_PUSH, ls.get());
 
1507
#else
 
1508
    if (!(thisPtr->lightGroup.get()))
 
1509
        thisPtr->lightGroup = new osg::Group();
 
1510
    thisPtr->lightGroup->addChild(ls);
 
1511
#endif
 
1512
 
 
1513
    return SoCallbackAction::CONTINUE;
 
1514
}
 
1515
///////////////////////////////////////////////////////////////////
 
1516
SoCallbackAction::Response
 
1517
ConvertFromInventor::preEnvironment(void* data, SoCallbackAction* action,
 
1518
                                    const SoNode* node)
 
1519
{
 
1520
#ifdef DEBUG_IV_PLUGIN
 
1521
    OSG_DEBUG << NOTIFY_HEADER << "preEnvironment()   "
 
1522
              << node->getTypeId().getName().getString() << std::endl;
 
1523
#endif
 
1524
 
 
1525
    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
 
1526
    IvStateItem &ivState = thisPtr->ivStateStack.top();
 
1527
 
 
1528
    ivState.currentAmbientLight = ((SoEnvironment*)node)->ambientColor.getValue() *
 
1529
                                  ((SoEnvironment*)node)->ambientIntensity.getValue();
 
1530
 
 
1531
    return SoCallbackAction::CONTINUE;
 
1532
}
 
1533
///////////////////////////////////////////////////////////////////
 
1534
#ifdef INVENTOR_SHADERS_AVAILABLE
 
1535
static bool
 
1536
convertShader(osg::Shader::Type osgShaderType,
 
1537
              const SoShaderObject *ivShader,
 
1538
              osg::Program *osgProgram)
 
1539
{
 
1540
    // NULL shader is not converted while returning success
 
1541
    if (ivShader == NULL)
 
1542
        return true;
 
1543
 
 
1544
    // Create shader
 
1545
    osg::ref_ptr<osg::Shader> osgShader = new osg::Shader(osgShaderType);
 
1546
    if (ivShader->sourceType.getValue() == SoShaderObject::FILENAME)
 
1547
        osgShader->loadShaderSourceFromFile(ivShader->sourceProgram.getValue().getString());
 
1548
    else
 
1549
    if (ivShader->sourceType.getValue() == SoShaderObject::GLSL_PROGRAM)
 
1550
        osgShader->setShaderSource(ivShader->sourceProgram.getValue().getString());
 
1551
    else {
 
1552
        OSG_WARN << NOTIFY_HEADER << "Can not convert "
 
1553
                  << "shader. Unsupported shader language." << std::endl;
 
1554
        return false;
 
1555
    }
 
1556
 
 
1557
    // Set shader name
 
1558
    osgShader->setName(ivShader->getName().getString());
 
1559
 
 
1560
    return osgProgram->addShader(osgShader.get());
 
1561
}
 
1562
#endif // INVENTOR_SHADERS_AVAILABLE
 
1563
///////////////////////////////////////////////////////////////////
 
1564
SoCallbackAction::Response
 
1565
ConvertFromInventor::preShaderProgram(void* data, SoCallbackAction* action,
 
1566
                              const SoNode* node)
 
1567
{
 
1568
#ifdef DEBUG_IV_PLUGIN
 
1569
    OSG_DEBUG << NOTIFY_HEADER << "preShaderProgram()  "
 
1570
              << node->getTypeId().getName().getString() << std::endl;
 
1571
#endif
 
1572
 
 
1573
#ifdef INVENTOR_SHADERS_AVAILABLE
 
1574
 
 
1575
    ConvertFromInventor *thisPtr = (ConvertFromInventor*)data;
 
1576
    IvStateItem &ivState = thisPtr->ivStateStack.top();
 
1577
 
 
1578
    // Get Inventor nodes
 
1579
    // Note: Shaders are available since Coin 2.5 (including
 
1580
    // geometry shader)
 
1581
    const SoShaderProgram *ivProgram = (const SoShaderProgram*)node;
 
1582
    const SoVertexShader *ivVertexShader = NULL;
 
1583
    const SoGeometryShader *ivGeometryShader = NULL;
 
1584
    const SoFragmentShader *ivFragmentShader = NULL;
 
1585
 
 
1586
    for (int i=0, c=ivProgram->shaderObject.getNum(); i<c; i++) {
 
1587
 
 
1588
        const SoShaderObject *shader = (const SoShaderObject*)ivProgram->shaderObject[i];
 
1589
        if (!shader->isOfType(SoShaderObject::getClassTypeId()))
 
1590
            continue;
 
1591
        if (shader->isActive.getValue() == FALSE)
 
1592
            continue;
 
1593
 
 
1594
        if (shader->isOfType(SoVertexShader::getClassTypeId()))
 
1595
            ivVertexShader = (const SoVertexShader*)shader;
 
1596
        if (shader->isOfType(SoGeometryShader::getClassTypeId()))
 
1597
            ivGeometryShader = (const SoGeometryShader*)shader;
 
1598
        if (shader->isOfType(SoFragmentShader::getClassTypeId()))
 
1599
            ivFragmentShader = (const SoFragmentShader*)shader;
 
1600
    }
 
1601
 
 
1602
    // Create OSG shader program
 
1603
    osg::Program *osgProgram = new osg::Program();
 
1604
    if (!convertShader(osg::Shader::VERTEX, ivVertexShader, osgProgram))
 
1605
        OSG_WARN << NOTIFY_HEADER
 
1606
                  << "Failed to add vertex shader." << std::endl;
 
1607
    if (!convertShader(osg::Shader::GEOMETRY, ivGeometryShader, osgProgram))
 
1608
        OSG_WARN << NOTIFY_HEADER
 
1609
                  << "Failed to add geometry shader." << std::endl;
 
1610
    if (!convertShader(osg::Shader::FRAGMENT, ivFragmentShader, osgProgram))
 
1611
        OSG_WARN << NOTIFY_HEADER
 
1612
                  << "Failed to add fragment shader." << std::endl;
 
1613
 
 
1614
    // Set program name
 
1615
    osgProgram->setName(ivProgram->getName().getString());
 
1616
 
 
1617
    // Put shader to the state stack
 
1618
    ivState.currentGLProgram = osgProgram;
 
1619
 
 
1620
#else
 
1621
 
 
1622
    OSG_WARN << NOTIFY_HEADER << "Warning: The model "
 
1623
              "contains shaders while your Inventor does not support "
 
1624
              "them." << std::endl;
 
1625
#endif
 
1626
 
 
1627
    return SoCallbackAction::CONTINUE;
 
1628
}
 
1629
///////////////////////////////////////////////////////////////////////////////////////
 
1630
osg::ref_ptr<osg::StateSet>
 
1631
ConvertFromInventor::getStateSet(SoCallbackAction* action)
 
1632
{
 
1633
    osg::ref_ptr<osg::StateSet> stateSet = new osg::StateSet;
 
1634
 
 
1635
    // Inherit modes from the global state
 
1636
    stateSet->clear();
 
1637
 
 
1638
    // Inventor State Stack
 
1639
    IvStateItem &ivState = ivStateStack.top();
 
1640
 
 
1641
    // Convert the IV texture to OSG texture if any
 
1642
    osg::ref_ptr<osg::Texture2D> texture;
 
1643
    const SoNode *ivTexture = ivState.currentTexture;
 
1644
    if (ivTexture)
 
1645
    {
 
1646
        // Found a corresponding OSG texture object
 
1647
        if (ivToOsgTexMap[ivTexture])
 
1648
            texture = ivToOsgTexMap[ivTexture];
 
1649
        else
 
1650
        {
 
1651
            // Create a new osg texture
 
1652
            texture = convertIVTexToOSGTex(ivTexture, action);
 
1653
 
 
1654
            // Add the new texture to the database
 
1655
            ivToOsgTexMap[ivTexture] = texture.get();
 
1656
        }
 
1657
 
 
1658
        stateSet->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::ON);
 
1659
 
 
1660
        // propogate name
 
1661
        if(texture.valid())
 
1662
        {
 
1663
            std::string name = texture->getName();
 
1664
            if (name != "")
 
1665
                stateSet->setName(name);
 
1666
        }
 
1667
        // Set the texture environment
 
1668
        osg::ref_ptr<osg::TexEnv> texEnv = new osg::TexEnv;
 
1669
        switch (action->getTextureModel())
 
1670
        {
 
1671
            case SoTexture2::MODULATE:
 
1672
                texEnv->setMode(osg::TexEnv::MODULATE);
 
1673
                break;
 
1674
            case SoTexture2::DECAL:
 
1675
                texEnv->setMode(osg::TexEnv::DECAL);
 
1676
                break;
 
1677
            case SoTexture2::BLEND: {
 
1678
                texEnv->setMode(osg::TexEnv::BLEND);
 
1679
                SbColor c(action->getTextureBlendColor());
 
1680
                texEnv->setColor(osg::Vec4(c[0], c[1], c[2], 1.f));
 
1681
                break;
 
1682
            }
 
1683
            // SGI's Inventor does not have REPLACE mode, but the Coin 3D library does.
 
1684
            // Coin supports REPLACE since 2.2 release, TGS Inventor from 4.0.
 
1685
            // Let's convert to the TexEnv anyway.
 
1686
            case 0x1E01: //SoTexture2::REPLACE:
 
1687
                texEnv->setMode(osg::TexEnv::REPLACE);
 
1688
                break;
 
1689
            default:
 
1690
                OSG_WARN << "Unsupported TexEnv mode." << std::endl;
 
1691
                break;
 
1692
 
 
1693
        }
 
1694
        stateSet->setTextureAttributeAndModes(0,texEnv.get(),osg::StateAttribute::ON);
 
1695
    }
 
1696
 
 
1697
    SbColor ambient, diffuse, specular, emission;
 
1698
    float shininess, transparency;
 
1699
 
 
1700
    // Get the material colors
 
1701
    action->getMaterial(ambient, diffuse, specular, emission,
 
1702
                shininess, transparency, 0);
 
1703
 
 
1704
    // Set transparency
 
1705
    SbBool hasTextureTransparency = FALSE;
 
1706
    if (ivTexture) {
 
1707
      SbVec2s size(0, 0);
 
1708
      int bpp = 0;
 
1709
      const unsigned char *data = NULL;
 
1710
      if (ivTexture->isOfType(SoTexture2::getClassTypeId()))
 
1711
        data = ((SoTexture2*)ivTexture)->image.getValue(size, bpp);
 
1712
#ifdef __COIN__
 
1713
      else
 
1714
      if (ivTexture->isOfType(SoVRMLImageTexture::getClassTypeId())) {
 
1715
        const SbImage *img = ((SoVRMLImageTexture*)ivTexture)->getImage();
 
1716
        if (img)
 
1717
          data = img->getValue(size, bpp);
 
1718
      }
 
1719
#endif
 
1720
 
 
1721
      // look whether texture really contains transparency
 
1722
      if ((bpp==4 || bpp==2) && data) {
 
1723
        data += bpp - 1;
 
1724
        for (int y=0; y<size[1]; y++)
 
1725
          for (int x=0; x<size[0]; x++, data += bpp)
 
1726
            if (*data != 255) {
 
1727
              hasTextureTransparency = TRUE;
 
1728
              goto finished;
 
1729
            }
 
1730
      finished:;
 
1731
      }
 
1732
    }
 
1733
 
 
1734
    if (transparency > 0 || hasTextureTransparency)
 
1735
    {
 
1736
        // Blending to SRC_APLHA and ONE_MINUS_SRC_ALPHA
 
1737
        stateSet->setAttributeAndModes(new osg::BlendFunc);
 
1738
 
 
1739
        // Disable depth writes
 
1740
        stateSet->setAttributeAndModes(new osg::Depth(osg::Depth::LEQUAL, 0., 1., false));
 
1741
 
 
1742
        // Enable depth sorting for transparent objects
 
1743
        stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
 
1744
        stateSet->setNestRenderBins(false);
 
1745
    }
 
1746
 
 
1747
    // Set linewidth
 
1748
    if (action->getLineWidth())
 
1749
    {
 
1750
        osg::ref_ptr<osg::LineWidth> lineWidth = new osg::LineWidth;
 
1751
        lineWidth->setWidth(action->getLineWidth());
 
1752
        stateSet->setAttributeAndModes(lineWidth.get(), osg::StateAttribute::ON);
 
1753
    }
 
1754
 
 
1755
    // Set pointsize
 
1756
    if (action->getPointSize())
 
1757
    {
 
1758
        osg::ref_ptr<osg::Point> point = new osg::Point;
 
1759
        point->setSize(action->getPointSize());
 
1760
        stateSet->setAttributeAndModes(point.get(), osg::StateAttribute::ON);
 
1761
    }
 
1762
 
 
1763
    // Set draw mode
 
1764
    switch (action->getDrawStyle())
 
1765
    {
 
1766
        case SoDrawStyle::FILLED:
 
1767
        {
 
1768
#if 0
 
1769
// OSG defaults to filled draw style, so no need to set redundent state.
 
1770
            osg::PolygonMode *polygonMode = new osg::PolygonMode;
 
1771
            polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
 
1772
                                 osg::PolygonMode::FILL);
 
1773
            stateSet->setAttributeAndModes(polygonMode, osg::StateAttribute::ON);
 
1774
#endif
 
1775
            break;
 
1776
        }
 
1777
        case SoDrawStyle::LINES:
 
1778
        {
 
1779
            osg::ref_ptr<osg::PolygonMode> polygonMode = new osg::PolygonMode;
 
1780
            polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
 
1781
                                 osg::PolygonMode::LINE);
 
1782
            stateSet->setAttributeAndModes(polygonMode.get(), osg::StateAttribute::ON);
 
1783
            break;
 
1784
        }
 
1785
        case SoDrawStyle::POINTS:
 
1786
        {
 
1787
            osg::ref_ptr<osg::PolygonMode> polygonMode = new osg::PolygonMode;
 
1788
            polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
 
1789
                                 osg::PolygonMode::POINT);
 
1790
            stateSet->setAttributeAndModes(polygonMode.get(), osg::StateAttribute::ON);
 
1791
            break;
 
1792
        }
 
1793
        case SoDrawStyle::INVISIBLE:
 
1794
            // check how to handle this in osg.
 
1795
            break;
 
1796
    }
 
1797
 
 
1798
    // Set back face culling
 
1799
    if (action->getShapeType() == SoShapeHints::SOLID)
 
1800
    {
 
1801
        osg::ref_ptr<osg::CullFace> cullFace = new osg::CullFace;
 
1802
        cullFace->setMode(osg::CullFace::BACK);
 
1803
        stateSet->setAttributeAndModes(cullFace.get(), osg::StateAttribute::ON);
 
1804
    }
 
1805
 
 
1806
    // Set lighting
 
1807
    if (action->getLightModel() == SoLightModel::BASE_COLOR)
 
1808
        stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
 
1809
    else
 
1810
    {
 
1811
        // Set the material
 
1812
        osg::ref_ptr<osg::Material> material = new osg::Material;
 
1813
 
 
1814
        material->setAmbient(osg::Material::FRONT_AND_BACK,
 
1815
                             osg::Vec4(ambient[0], ambient[1], ambient[2],
 
1816
                                       1.0 - transparency));
 
1817
        material->setDiffuse(osg::Material::FRONT_AND_BACK,
 
1818
                             osg::Vec4(diffuse[0], diffuse[1], diffuse[2],
 
1819
                                       1.0 - transparency));
 
1820
        material->setSpecular(osg::Material::FRONT_AND_BACK,
 
1821
                              osg::Vec4(specular[0], specular[1], specular[2],
 
1822
                                        1.0 - transparency));
 
1823
        material->setEmission(osg::Material::FRONT_AND_BACK,
 
1824
                              osg::Vec4(emission[0], emission[1], emission[2],
 
1825
                                        1.0 - transparency));
 
1826
        material->setTransparency(osg::Material::FRONT_AND_BACK, transparency);
 
1827
        if (specular[0] || specular[1] || specular[2])
 
1828
            material->setShininess(osg::Material::FRONT_AND_BACK,
 
1829
                                   shininess*128.0);
 
1830
        else
 
1831
            material->setShininess(osg::Material::FRONT_AND_BACK, 0.0);
 
1832
 
 
1833
        material->setColorMode(osg::Material::DIFFUSE);
 
1834
 
 
1835
        stateSet->setAttributeAndModes(material.get(), osg::StateAttribute::ON);
 
1836
        stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
 
1837
 
 
1838
        // Set global ambient light
 
1839
        // note on osg::LightModel default values:
 
1840
        //   colorControl: SINGLE_COLOR, localViewer: false, twoSided: false
 
1841
        osg::LightModel *lightModel = new osg::LightModel();
 
1842
        const SbColor &c = ivState.currentAmbientLight;
 
1843
        lightModel->setAmbientIntensity(osg::Vec4(c[0], c[1], c[2], 1.0));
 
1844
#if 0
 
1845
// disable as two sided lighting causes problem under NVidia, and the above osg::Material settings are single sided anway..
 
1846
update: The mentioned bug is probably just for very old NVidia drivers (commit time of the comment is 2005-03-18).
 
1847
        The proper solution should be to set two sided lighting based on SoShapeHints node. Need to be developed. PCJohn-2010-01-20
 
1848
        // Set two sided lighting
 
1849
        lightModel->setTwoSided(true);
 
1850
#endif
 
1851
        stateSet->setAttributeAndModes(lightModel, osg::StateAttribute::ON);
 
1852
 
 
1853
        // Set lights
 
1854
        for (unsigned int i = 0; i < ivState.currentLights.size(); i++)
 
1855
            stateSet->setAttributeAndModes(ivState.currentLights[i].get(),
 
1856
                                           osg::StateAttribute::ON);
 
1857
 
 
1858
    }
 
1859
 
 
1860
    // Shader program setup
 
1861
    if (ivState.currentGLProgram.get() != NULL) {
 
1862
        stateSet->setAttributeAndModes(ivState.currentGLProgram.get(),
 
1863
                                       osg::StateAttribute::ON);
 
1864
    }
 
1865
 
 
1866
    // Shader program uniforms
 
1867
    if (ivState.currentGLProgram.get() != NULL) {
 
1868
        for (int i=0, c=ivState.currentGLProgram->getNumShaders(); i<c; i++) {
 
1869
             const std::string &shaderCode = ivState.currentGLProgram->getShader(i)->getShaderSource();
 
1870
             if (shaderCode.find("coin_texunit0_model") != std::string::npos) {
 
1871
                 int mode = (ivTexture!=NULL) ? action->getTextureModel() : 0;
 
1872
                 stateSet->addUniform(new osg::Uniform("coin_texunit0_model", mode));
 
1873
                 break;
 
1874
             }
 
1875
        }
 
1876
    }
 
1877
 
 
1878
    return stateSet;
 
1879
}
 
1880
////////////////////////////////////////////////////////////////////
 
1881
osg::Texture2D*
 
1882
ConvertFromInventor::convertIVTexToOSGTex(const SoNode* soNode,
 
1883
                                          SoCallbackAction* action)
 
1884
{
 
1885
#ifdef DEBUG_IV_PLUGIN
 
1886
    OSG_DEBUG << NOTIFY_HEADER
 
1887
              << "convertIVTexToOSGTex ("
 
1888
              << soNode->getTypeId().getName().getString()
 
1889
              << ")" << std::endl;
 
1890
#endif
 
1891
 
 
1892
    SbVec2s soSize;
 
1893
    int soNC;
 
1894
 
 
1895
    // Get the texture size and components
 
1896
    const unsigned char* soImageData = action->getTextureImage(soSize, soNC);
 
1897
    if (!soImageData) {
 
1898
        OSG_WARN << NOTIFY_HEADER
 
1899
                  << "Warning: Error while loading texture data." << std::endl;
 
1900
        return NULL;
 
1901
    }
 
1902
 
 
1903
    // Allocate memory for image data
 
1904
    unsigned char* osgImageData = new unsigned char[soSize[0] * soSize[1] * soNC];
 
1905
 
 
1906
    // Copy the texture image data from the inventor texture
 
1907
    memcpy(osgImageData, soImageData, soSize[0] * soSize[1] * soNC);
 
1908
 
 
1909
    // File name
 
1910
    std::string fileName;
 
1911
    if (soNode->isOfType(SoTexture2::getClassTypeId()))
 
1912
        fileName = ((SoTexture2*)soNode)->filename.getValue().getString();
 
1913
#ifdef __COIN__
 
1914
    else
 
1915
    if (soNode->isOfType(SoVRMLImageTexture::getClassTypeId()))
 
1916
        fileName = ((SoVRMLImageTexture*)soNode)->url.getNum() >= 1 ?
 
1917
                   ((SoVRMLImageTexture*)soNode)->url.getValues(0)[0].getString() : "";
 
1918
#endif
 
1919
    else
 
1920
      OSG_WARN << NOTIFY_HEADER
 
1921
                << " Warning: Unsupported texture type: "
 
1922
                << soNode->getTypeId().getName().getString() << std::endl;
 
1923
 
 
1924
#ifdef DEBUG_IV_PLUGIN
 
1925
    OSG_DEBUG << NOTIFY_HEADER
 
1926
              << "  Converting file name: " << fileName << " -> ";
 
1927
#endif
 
1928
    if (fileName[0]=='\"') fileName.erase(fileName.begin());
 
1929
    if (fileName.size() > 0 && fileName[fileName.size()-1]=='\"')
 
1930
        fileName.erase(fileName.begin()+fileName.size()-1);
 
1931
#ifdef DEBUG_IV_PLUGIN
 
1932
    OSG_DEBUG << fileName << std::endl;
 
1933
#endif
 
1934
 
 
1935
    // Create the osg::Image
 
1936
    osg::ref_ptr<osg::Image> osgImage = new osg::Image;
 
1937
    osgImage->setFileName(fileName);
 
1938
    GLenum formats[] = {GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA};
 
1939
    osgImage->setImage(soSize[0], soSize[1], 1, soNC, formats[soNC-1],
 
1940
                       GL_UNSIGNED_BYTE, osgImageData, osg::Image::USE_NEW_DELETE);
 
1941
 
 
1942
    // Create the osg::Texture2D
 
1943
    osg::Texture2D *osgTex = new osg::Texture2D;
 
1944
    osgTex->setImage(osgImage.get());
 
1945
 
 
1946
    // Set name
 
1947
    osgTex->setName(soNode->getName().getString());
 
1948
 
 
1949
    static std::map<SoTexture2::Wrap, osg::Texture2D::WrapMode> texWrapMap;
 
1950
    static bool firstTime = true;
 
1951
    if (firstTime)
 
1952
    {
 
1953
        texWrapMap[SoTexture2::CLAMP] = osg::Texture2D::CLAMP;
 
1954
        texWrapMap[SoTexture2::REPEAT] = osg::Texture2D::REPEAT;
 
1955
        firstTime = false;
 
1956
    }
 
1957
 
 
1958
    // Set texture wrap mode
 
1959
#ifdef __COIN__
 
1960
    if (soNode->isOfType(SoVRMLImageTexture::getClassTypeId())) {
 
1961
        // It looks like there is a high probability of bug in Coin (investigated on version 2.4.6).
 
1962
        // action->getTextureWrap() returns correct value on SoTexture2 (SoTexture2::CLAMP = 0x2900,
 
1963
        // and REPEAT = 0x2901), but SoVRMLImageTexture returns incorrect value of
 
1964
        // SoGLImage::REPEAT = 0, CLAMP = 1, CLAMP_TO_EDGE = 2).
 
1965
        // So, let's not use action and try to get correct value directly from texture node.
 
1966
        // PCJohn-2007-04-22
 
1967
        osgTex->setWrap(osg::Texture2D::WRAP_S, ((SoVRMLImageTexture*)soNode)->repeatS.getValue() ?
 
1968
            osg::Texture2D::REPEAT : osg::Texture2D::CLAMP_TO_EDGE);
 
1969
        osgTex->setWrap(osg::Texture2D::WRAP_T, ((SoVRMLImageTexture*)soNode)->repeatT.getValue() ?
 
1970
            osg::Texture2D::REPEAT : osg::Texture2D::CLAMP_TO_EDGE);
 
1971
    }
 
1972
    else
 
1973
#endif
 
1974
    {
 
1975
        // Proper way to determine wrap mode
 
1976
        osgTex->setWrap(osg::Texture2D::WRAP_S, texWrapMap[action->getTextureWrapS()]);
 
1977
        osgTex->setWrap(osg::Texture2D::WRAP_T, texWrapMap[action->getTextureWrapT()]);
 
1978
    }
 
1979
 
 
1980
    return osgTex;
 
1981
}
 
1982
///////////////////////////////////////////////////////////////////
 
1983
SoCallbackAction::Response
 
1984
ConvertFromInventor::preInfo(void* data, SoCallbackAction* action,
 
1985
                             const SoNode* node)
 
1986
{
 
1987
#ifdef DEBUG_IV_PLUGIN
 
1988
    OSG_DEBUG << NOTIFY_HEADER << "preInfo()    "
 
1989
              << node->getTypeId().getName().getString() << std::endl;
 
1990
#endif
 
1991
 
 
1992
#if 0 // FIXME: Not handled properly yet. There is no Info node in OSG.
 
1993
      // Append probably empty Node and set its name to info->string.getValue();
 
1994
    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
 
1995
    SoInfo* info = (SoInfo*)node;
 
1996
#endif
 
1997
 
 
1998
    return SoCallbackAction::CONTINUE;
 
1999
}
 
2000
/////////////////////////////////////////////////////////////
 
2001
SoCallbackAction::Response
 
2002
ConvertFromInventor::preRotor(void *data, SoCallbackAction *action,
 
2003
                              const SoNode *node)
 
2004
{
 
2005
#ifdef DEBUG_IV_PLUGIN
 
2006
    OSG_DEBUG << NOTIFY_HEADER << "preRotor()  "
 
2007
              << node->getTypeId().getName().getString() << std::endl;
 
2008
#endif
 
2009
 
 
2010
    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
 
2011
 
 
2012
    // Get the parameters for the inventor Rotor
 
2013
    SoRotor *ivRotor = (SoRotor *) node;
 
2014
    SbVec3f ivAxis;
 
2015
    float angle;
 
2016
    ivRotor->rotation.getValue(ivAxis, angle);
 
2017
 
 
2018
    // Create a new osg::MatrixTransform
 
2019
    osg::ref_ptr<osg::MatrixTransform> rotorTransform = new osg::MatrixTransform;
 
2020
 
 
2021
    // Create a Rotor Callback equivalent to the inventor Rotor
 
2022
    osg::Vec3 pivot(0, 0, 0);
 
2023
    osg::Vec3 axis(ivAxis[0], ivAxis[1], ivAxis[2]);
 
2024
    osg::ref_ptr<osgUtil::TransformCallback> rotorCallback
 
2025
        = new osgUtil::TransformCallback(pivot, axis,
 
2026
                                         2 * osg::PI * ivRotor->speed.getValue());
 
2027
 
 
2028
    // Set the app callback
 
2029
    rotorTransform->setUpdateCallback(rotorCallback.get());
 
2030
 
 
2031
    // Push the rotor onto the state stack
 
2032
    thisPtr->ivPushState(action, node,
 
2033
              IvStateItem::MULTI_POP | IvStateItem::UPDATE_STATE |
 
2034
              IvStateItem::APPEND_AT_PUSH, rotorTransform.get());
 
2035
 
 
2036
    // Append initial rotation to the model matrix
 
2037
    if (!ivRotor->rotation.isIgnored()) {
 
2038
        SoModelMatrixElement::rotateBy(action->getState(), ivRotor,
 
2039
                                       ivRotor->rotation.getValue());
 
2040
    }
 
2041
 
 
2042
    // Don't do the traversal of the SoShuttle
 
2043
    // since it was seen on Coin that is does not append just
 
2044
    // initial shuttle position, but some interpolated one,
 
2045
    // resulting in incorrect animation.
 
2046
    return SoCallbackAction::PRUNE;
 
2047
}
 
2048
////////////////////////////////////////////////////////////////
 
2049
SoCallbackAction::Response
 
2050
ConvertFromInventor::prePendulum(void* data, SoCallbackAction *action,
 
2051
                                 const SoNode* node)
 
2052
{
 
2053
#ifdef DEBUG_IV_PLUGIN
 
2054
    OSG_DEBUG << NOTIFY_HEADER << "prePendulum()  "
 
2055
              << node->getTypeId().getName().getString() << std::endl;
 
2056
#endif
 
2057
 
 
2058
    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
 
2059
 
 
2060
    // Get the parameters for the inventor Pendulum
 
2061
    SoPendulum *ivPendulum = (SoPendulum *) node;
 
2062
    SbVec3f ivAxis0, ivAxis1;
 
2063
    float startAngle, endAngle;
 
2064
    ivPendulum->rotation0.getValue(ivAxis0, startAngle);
 
2065
    ivPendulum->rotation1.getValue(ivAxis1, endAngle);
 
2066
    ivAxis0.normalize();
 
2067
    ivAxis1.normalize();
 
2068
 
 
2069
    // Reverse axis and direction if required
 
2070
    // Actually, this will produce correct results only when axis is
 
2071
    // opposite to each other, and approximate results when nearly
 
2072
    // opposite and garbage otherwise.
 
2073
    if ((ivAxis0+ivAxis1).length() < 0.5 ) {
 
2074
        ivAxis1 = -ivAxis1;
 
2075
        endAngle = -endAngle;
 
2076
    }
 
2077
 
 
2078
    // Create a new osg::MatrixTransform
 
2079
    osg::ref_ptr<osg::MatrixTransform> pendulumTransform = new osg::MatrixTransform;
 
2080
 
 
2081
    // Create a Pendulum Callback equivalent to the inventor Rotor
 
2082
    // Use axis from of the bigger angle (to avoid lost axis when
 
2083
    // angle is zero - see SbRotation and quaternion theory).
 
2084
    osg::Vec3 axis;
 
2085
    if (fabs(startAngle) > fabs(endAngle))
 
2086
        axis = osg::Vec3(ivAxis0[0], ivAxis0[1], ivAxis0[2]);
 
2087
    else
 
2088
        axis = osg::Vec3(ivAxis1[0], ivAxis1[1], ivAxis1[2]);
 
2089
    PendulumCallback* pendulumCallback
 
2090
        = new PendulumCallback(axis, startAngle, endAngle,
 
2091
                               ivPendulum->speed.getValue());
 
2092
 
 
2093
    // Set the app callback
 
2094
    pendulumTransform->setUpdateCallback(pendulumCallback);
 
2095
 
 
2096
    // Push the pendulum onto the state stack
 
2097
    thisPtr->ivPushState(action, node,
 
2098
              IvStateItem::MULTI_POP | IvStateItem::UPDATE_STATE |
 
2099
              IvStateItem::APPEND_AT_PUSH, pendulumTransform.get());
 
2100
 
 
2101
    // Don't do the traversal of the SoShuttle
 
2102
    // since it was seen on Coin that is does not append just
 
2103
    // initial shuttle position, but some interpolated one,
 
2104
    // resulting in incorrect animation.
 
2105
    return SoCallbackAction::PRUNE;
 
2106
}
 
2107
////////////////////////////////////////////////////////////////
 
2108
SoCallbackAction::Response
 
2109
ConvertFromInventor::preShuttle(void* data, SoCallbackAction *action,
 
2110
                                const SoNode* node)
 
2111
{
 
2112
#ifdef DEBUG_IV_PLUGIN
 
2113
    OSG_DEBUG << NOTIFY_HEADER << "preShuttle()  "
 
2114
              << node->getTypeId().getName().getString() << std::endl;
 
2115
#endif
 
2116
 
 
2117
    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
 
2118
 
 
2119
    // Get the parameters for the inventor Shuttle
 
2120
    SoShuttle *ivShuttle = (SoShuttle *) node;
 
2121
    SbVec3f ivStartPos, ivEndPos;
 
2122
    ivStartPos = ivShuttle->translation0.getValue();
 
2123
    ivEndPos = ivShuttle->translation1.getValue();
 
2124
 
 
2125
    // Create a new osg::MatrixTransform
 
2126
    osg::ref_ptr<osg::MatrixTransform> shuttleTransform = new osg::MatrixTransform;
 
2127
 
 
2128
    // Create a shuttle Callback equivalent to the inventor Rotor
 
2129
    osg::Vec3 startPos(ivStartPos[0], ivStartPos[1], ivStartPos[2]);
 
2130
    osg::Vec3 endPos(ivEndPos[0], ivEndPos[1], ivEndPos[2]);
 
2131
    ShuttleCallback* shuttleCallback
 
2132
        = new ShuttleCallback(startPos, endPos, ivShuttle->speed.getValue());
 
2133
 
 
2134
    // Set the app callback
 
2135
    shuttleTransform->setUpdateCallback(shuttleCallback);
 
2136
 
 
2137
    // Push the shuttle onto the state stack
 
2138
    thisPtr->ivPushState(action, node,
 
2139
              IvStateItem::MULTI_POP | IvStateItem::UPDATE_STATE |
 
2140
              IvStateItem::APPEND_AT_PUSH, shuttleTransform.get());
 
2141
 
 
2142
    // Don't do the traversal of the SoShuttle
 
2143
    // since it was seen on Coin that is does not append just
 
2144
    // initial shuttle position, but some interpolated one,
 
2145
    // resulting in incorrect animation.
 
2146
    return SoCallbackAction::PRUNE;
 
2147
}
 
2148
////////////////////////////////////////////////////////////
 
2149
void ConvertFromInventor::addVertex(SoCallbackAction* action,
 
2150
                                    const SoPrimitiveVertex *v,
 
2151
                                    int index)
 
2152
{
 
2153
    // Get the coordinates of the vertex
 
2154
    SbVec3f pt = v->getPoint();
 
2155
    vertices.push_back(osg::Vec3(pt[0], pt[1], pt[2]));
 
2156
 
 
2157
    // Get the normal of the vertex
 
2158
    SbVec3f norm = v->getNormal();
 
2159
 
 
2160
    if ((normalBinding == deprecated_osg::Geometry::BIND_PER_VERTEX) ||
 
2161
        (normalBinding == deprecated_osg::Geometry::BIND_PER_PRIMITIVE && index == 0))
 
2162
    {
 
2163
        // What is this? Why to invert normals at CLOCKWISE vertex ordering?
 
2164
        // PCJohn 2009-12-13
 
2165
        //if (vertexOrder == CLOCKWISE)
 
2166
        //    normals.push_back(osg::Vec3(-norm[0], -norm[1], -norm[2]));
 
2167
        //else
 
2168
            normals.push_back(osg::Vec3(norm[0], norm[1], norm[2]));
 
2169
    }
 
2170
 
 
2171
    if (colorBinding == deprecated_osg::Geometry::BIND_PER_VERTEX ||
 
2172
            colorBinding == deprecated_osg::Geometry::BIND_PER_PRIMITIVE)
 
2173
    {
 
2174
        // Get the material/color
 
2175
        SbColor ambient, diffuse, specular, emission;
 
2176
        float transparency, shininess;
 
2177
        action->getMaterial(ambient, diffuse, specular, emission, shininess,
 
2178
                            transparency, v->getMaterialIndex());
 
2179
        if (colorBinding == deprecated_osg::Geometry::BIND_PER_VERTEX)
 
2180
            colors.push_back(osg::Vec4(diffuse[0], diffuse[1], diffuse[2],
 
2181
                                       1.0 - transparency));
 
2182
        else if (colorBinding == deprecated_osg::Geometry::BIND_PER_PRIMITIVE && index == 0)
 
2183
            colors.push_back(osg::Vec4(diffuse[0], diffuse[1], diffuse[2],
 
2184
                                       1.0 - transparency));
 
2185
    }
 
2186
 
 
2187
    // Get the texture coordinates
 
2188
    SbVec4f texCoord = v->getTextureCoords();
 
2189
    textureCoords.push_back(osg::Vec2(texCoord[0], texCoord[1]));
 
2190
}
 
2191
////////////////////////////////////////////////////////////////////////////
 
2192
void ConvertFromInventor::addTriangleCB(void* data, SoCallbackAction* action,
 
2193
                                        const SoPrimitiveVertex* v0,
 
2194
                                        const SoPrimitiveVertex* v1,
 
2195
                                        const SoPrimitiveVertex* v2)
 
2196
{
 
2197
    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
 
2198
 
 
2199
    switch (thisPtr->vertexOrder)
 
2200
    {
 
2201
        case CLOCKWISE:
 
2202
            thisPtr->addVertex(action, v0, 0);
 
2203
            thisPtr->addVertex(action, v2, 1);
 
2204
            thisPtr->addVertex(action, v1, 2);
 
2205
            break;
 
2206
        case COUNTER_CLOCKWISE:
 
2207
            thisPtr->addVertex(action, v0, 0);
 
2208
            thisPtr->addVertex(action, v1, 1);
 
2209
            thisPtr->addVertex(action, v2, 2);
 
2210
            break;
 
2211
    }
 
2212
 
 
2213
    thisPtr->numPrimitives++;
 
2214
    thisPtr->primitiveType = osg::PrimitiveSet::TRIANGLES;
 
2215
}
 
2216
////////////////////////////////////////////////////////////////////////////////
 
2217
void ConvertFromInventor::addLineSegmentCB(void* data, SoCallbackAction* action,
 
2218
                                           const SoPrimitiveVertex* v0,
 
2219
                                           const SoPrimitiveVertex* v1)
 
2220
{
 
2221
    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
 
2222
 
 
2223
    thisPtr->addVertex(action, v0, 0);
 
2224
    thisPtr->addVertex(action, v1, 1);
 
2225
 
 
2226
    thisPtr->numPrimitives++;
 
2227
    thisPtr->primitiveType = osg::PrimitiveSet::LINES;
 
2228
}
 
2229
//////////////////////////////////////////////////////////////////////////
 
2230
void ConvertFromInventor::addPointCB(void* data, SoCallbackAction* action,
 
2231
                                     const SoPrimitiveVertex* v0)
 
2232
{
 
2233
    ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
 
2234
 
 
2235
    thisPtr->addVertex(action, v0, 0);
 
2236
 
 
2237
    thisPtr->numPrimitives++;
 
2238
    thisPtr->primitiveType = osg::PrimitiveSet::POINTS;
 
2239
}
 
2240
//////////////////////////////////////////////////////////////////////////
 
2241
void ConvertFromInventor::init()
 
2242
{
 
2243
#ifdef __COIN__
 
2244
    SoTexture2Osg::overrideClass();
 
2245
    SoTexture3Osg::overrideClass();
 
2246
    SoVRMLImageTextureOsg::overrideClass();
 
2247
#endif
 
2248
}