1
#include "ConvertFromInventor.h"
3
#include "PendulumCallback.h"
4
#include "ShuttleCallback.h"
7
#include <osg/MatrixTransform>
11
#include <osg/LineWidth>
14
#include <osg/Texture2D>
15
#include <osg/PolygonMode>
16
#include <osg/BlendFunc>
17
#include <osg/Material>
18
#include <osg/CullFace>
20
#include <osg/LightModel>
21
#include <osg/LightSource>
22
#include <osg/ShadeModel>
24
#include <osgDB/ReadFile>
25
#include <osgUtil/TransformCallback>
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>
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>
60
#if defined(__COIN__) && (COIN_MAJOR_VERSION >= 3 || \
61
(COIN_MAJOR_VERSION == 2 && COIN_MINOR_VERSION>=5))
62
#define INVENTOR_SHADERS_AVAILABLE
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>
83
#define DEBUG_IV_PLUGIN
84
#define NOTIFY_HEADER "Inventor Plugin (reader): "
86
///////////////////////////////////////////
87
ConvertFromInventor::ConvertFromInventor()
91
///////////////////////////////////////////
92
ConvertFromInventor::~ConvertFromInventor()
95
///////////////////////////////////////////////////////////////////
97
nodePreservesState(const SoNode *node)
99
return node->isOfType(SoSeparator::getClassTypeId()) ||
100
(node->getChildren() != NULL && node->affectsState() == FALSE);
102
////////////////////////////////////////////////////////////////////
103
SoCallbackAction::Response
104
ConvertFromInventor::restructure(void* data, SoCallbackAction* action,
107
#ifdef DEBUG_IV_PLUGIN
108
OSG_DEBUG << NOTIFY_HEADER << "restructure() "
109
<< node->getTypeId().getName().getString();
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);
117
if (node->isOfType(SoGroup::getClassTypeId())) {
119
SoGroup *group = (SoGroup*)node;
120
SoGroup *affectedScene = NULL;
121
childrenTotal = group->getNumChildren();
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()) {
128
// Put the node bellow separator
129
SoSeparator *s = new SoSeparator;
130
s->addChild(group->getChild(i));
131
group->replaceChild(i, s);
132
numModifiedChildren++;
134
// Create the scene that may be affected by the node
135
if (!affectedScene) {
137
// Create the graph of nodes that may be influenced
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--) {
146
// Get the appropriate stack level of nodesToRemove
147
assert(stackLevel >=0);
148
std::vector<int> &nodesToRemove = stack[stackLevel];
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) &&
157
// Create affected scene graph
159
affectedScene = new SoGroup;
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);
168
// Stop recursion if we reached separator
169
// or other state-preserving node.
170
if (nodePreservesState(parent))
175
// Append the affected graph to the separator
176
s->addChild(affectedScene);
181
#ifdef DEBUG_IV_PLUGIN
182
if (numModifiedChildren == 0)
184
OSG_DEBUG << ": no changes necessary" << std::endl;
188
OSG_DEBUG << ": " << numModifiedChildren <<
189
" nodes of " << childrenTotal << " restruc., " <<
190
numRemovedNodes << " removed" << std::endl;
194
return SoCallbackAction::CONTINUE;
196
///////////////////////////////////////////////////////////
197
SoCallbackAction::Response
198
ConvertFromInventor::restructurePreNode(void* data, SoCallbackAction* action,
201
std::vector<std::vector<int> > &stack = *((std::vector<std::vector<int> >*)data);
203
stack.push_back(std::vector<int>());
205
return SoCallbackAction::CONTINUE;
207
////////////////////////////////////////////////////////////////////
208
SoCallbackAction::Response
209
ConvertFromInventor::restructurePostNode(void* data, SoCallbackAction* action,
212
std::vector<std::vector<int> > &stack = *((std::vector<std::vector<int> >*)data);
214
assert(stack.size() > 0 && "Stack is empty");
215
std::vector<int> &nodesToRemove = stack.back();
217
if (nodesToRemove.size() > 0) {
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;
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]);
236
return SoCallbackAction::CONTINUE;
238
///////////////////////////////////////////////////////////////////
240
ConvertFromInventor::preprocess(SoNode* root)
242
#ifdef DEBUG_IV_PLUGIN
243
OSG_DEBUG << NOTIFY_HEADER << "Preprocessing..." << std::endl;
246
SoCallbackAction action;
247
std::vector<std::vector<int> > stackOfNodesToRemove;
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);
257
// Traverse the scene
260
#if 0 // For debugging purposes: Write preprocessed scene to the file
262
out.openFile("preprocess.iv");
263
SoWriteAction wa(&out);
267
///////////////////////////////////////////////////////////
269
ConvertFromInventor::convert(SoNode* ivRootNode)
271
#ifdef DEBUG_IV_PLUGIN
272
OSG_DEBUG << NOTIFY_HEADER << "Converting..." << std::endl;
275
// Transformation matrix for converting Inventor coordinate system to OSG
277
osg::Matrix ivToOSGMat(osg::Matrix(1.0, 0.0, 0.0, 0.0,
280
0.0, 0.0, 0.0, 1.0));
283
osg::ref_ptr<osg::Group> osgRootNode = new osg::MatrixTransform(ivToOSGMat);
285
// Propagate node name
286
osgRootNode->setName(ivRootNode->getName().getString());
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()));
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;
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);
307
// SoTransformSeparator callbacks. Special handling of transformations.
308
cbAction.addPreCallback(SoTransformSeparator::getClassTypeId(), preTransformSeparator, this);
309
cbAction.addPostCallback(SoTransformSeparator::getClassTypeId(), postTransformSeparator, this);
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);
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);
321
// Handling of textures
322
cbAction.addPostCallback(SoTexture2::getClassTypeId(),
325
cbAction.addPostCallback(SoVRMLImageTexture::getClassTypeId(),
327
cbAction.addPostCallback(SoVRMLAppearance::getClassTypeId(),
332
cbAction.addPreCallback(SoInfo::getClassTypeId(), preInfo, this);
336
cbAction.addPreCallback(SoLight::getClassTypeId(), preLight, this);
338
// Environment (ambient light,...)
339
cbAction.addPreCallback(SoEnvironment::getClassTypeId(), preEnvironment, this);
342
#ifdef INVENTOR_SHADERS_AVAILABLE
343
cbAction.addPreCallback(SoShaderProgram::getClassTypeId(), preShaderProgram, this);
347
cbAction.addPreCallback(SoRotor::getClassTypeId(), preRotor, this);
348
cbAction.addPreCallback(SoPendulum::getClassTypeId(), prePendulum, this);
349
cbAction.addPreCallback(SoShuttle::getClassTypeId(), preShuttle, this);
351
// Geometry callbacks
352
cbAction.addTriangleCallback(SoShape::getClassTypeId(), addTriangleCB, this);
353
cbAction.addLineSegmentCallback(SoShape::getClassTypeId(), addLineSegmentCB,
355
cbAction.addPointCallback(SoShape::getClassTypeId(), addPointCB, this);
357
// Post node callback
358
cbAction.addPostCallback(SoNode::getClassTypeId(), postNode, this);
360
// Traverse the inventor scene graph
361
cbAction.apply(ivRootNode);
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));
375
return osgRootNode.get();
377
///////////////////////////////////////////////////////////////////
379
notifyAboutMatrixContent(const osg::NotifySeverity level, const SbMatrix &m)
383
m.getTransform(t, r, s, so);
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;
392
///////////////////////////////////////////////////////////////////
394
ConvertFromInventor::appendNode(osg::Node *n, const SoCallbackAction *action)
396
IvStateItem &ivState = ivStateStack.top();
397
SbMatrix currentMatrix = action->getModelMatrix();
398
SbMatrix inheritedMatrix = ivState.inheritedTransformation;
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
404
if (ivState.flags & IvStateItem::KEEP_CHILDREN_ORDER) {
406
// Determine child index
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.");
416
assert(childIndex != -1 && "Node did not found.");
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);
425
#ifdef DEBUG_IV_PLUGIN
426
OSG_DEBUG << NOTIFY_HEADER << "appendNode: "
430
if (currentMatrix == inheritedMatrix) {
432
// just append node to the current group in osg scene graph
433
ivState.osgStateRoot->addChild(n);
434
ivState.lastUsedTransformation = inheritedMatrix;
436
#ifdef DEBUG_IV_PLUGIN
437
if (osg::isNotifyEnabled(osg::DEBUG_INFO))
439
" uses parent transformation" << std::endl;
444
if (!(ivState.flags & IvStateItem::KEEP_CHILDREN_ORDER) &&
445
currentMatrix == ivState.lastUsedTransformation) {
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.");
457
#ifdef DEBUG_IV_PLUGIN
458
if (osg::isNotifyEnabled(osg::DEBUG_INFO))
460
" reuses previous transformation" << std::endl;
465
// We need a new transformation node
466
osg::Matrix m(osg::Matrix(currentMatrix.operator float*()));
468
m2.invert(osg::Matrix(inheritedMatrix.operator float*()));
470
osg::MatrixTransform *mt = new osg::MatrixTransform(m);
473
ivState.osgStateRoot->addChild(mt);
474
ivState.lastUsedTransformation = currentMatrix;
476
#ifdef DEBUG_IV_PLUGIN
477
if (osg::isNotifyEnabled(osg::DEBUG_INFO)) {
479
" uses local transformation:" << std::endl;
480
notifyAboutMatrixContent(osg::DEBUG_INFO,
481
SbMatrix((SbMat&)(*osg::Matrixf(m).ptr())));
487
///////////////////////////////////////////////////////////////////
489
ConvertFromInventor::ivPushState(const SoCallbackAction *action,
490
const SoNode *initiator, const int flags,
493
assert(ivStateStack.size() >= 1 && "There must be at least one "
494
"value in the ivStateStack to use ivPushState function.");
496
// Propagate node name
497
root->setName(initiator->getName().getString());
500
if (flags & IvStateItem::APPEND_AT_PUSH)
501
appendNode(root, action);
504
ivStateStack.push(IvStateItem(ivStateStack.top(), action, initiator, flags, root));
507
///////////////////////////////////////////////////////////////////
509
ConvertFromInventor::ivPopState(const SoCallbackAction *action,
510
const SoNode *initiator)
514
assert(ivStateStack.size() >= 2 && "There must be at least two "
515
"values in the ivStateStack to use ivPopState function.");
517
// Get multipop value
518
IvStateItem ivState = ivStateStack.top();
519
multipop = ivState.flags & IvStateItem::MULTI_POP;
521
// ivState.pushInitiator == initiator &&
522
// "ivStateStack push was initiated by different node.");
524
// Get osgStateRoot (note: we HAVE TO reference it)
525
osg::ref_ptr<osg::Group> r = ivState.osgStateRoot;
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;
540
if (!(ivState.flags & IvStateItem::APPEND_AT_PUSH))
541
appendNode(r.get(), action);
546
///////////////////////////////////////////////////////////////////
547
SoCallbackAction::Response
548
ConvertFromInventor::preNode(void* data, SoCallbackAction* action,
551
#ifdef DEBUG_IV_PLUGIN
552
OSG_DEBUG << NOTIFY_HEADER << "preNode() "
553
<< node->getTypeId().getName().getString() << std::endl;
556
if (nodePreservesState(node)) {
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());
569
return SoCallbackAction::CONTINUE;
571
////////////////////////////////////////////////////////////////////
572
SoCallbackAction::Response
573
ConvertFromInventor::postNode(void* data, SoCallbackAction* action,
576
#ifdef DEBUG_IV_PLUGIN
577
OSG_DEBUG << NOTIFY_HEADER << "postNode() "
578
<< node->getTypeId().getName().getString() << std::endl;
581
if (nodePreservesState(node)) {
584
ConvertFromInventor *thisPtr = (ConvertFromInventor *) data;
585
assert(thisPtr->ivStateStack.size() > 0 && "ivStackState underflow");
586
thisPtr->ivPopState(action, node);
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());
597
return SoCallbackAction::CONTINUE;
599
///////////////////////////////////////////////////////////////////
600
SoCallbackAction::Response
601
ConvertFromInventor::preTransformSeparator(void* data, SoCallbackAction* action,
604
#ifdef DEBUG_IV_PLUGIN
605
OSG_DEBUG << NOTIFY_HEADER << "preTransformSeparator() "
606
<< node->getTypeId().getName().getString() << std::endl;
610
ConvertFromInventor *thisPtr = (ConvertFromInventor *) data;
611
thisPtr->ivPushState(action, node, IvStateItem::UPDATE_STATE_EXCEPT_TRANSFORM,
614
return SoCallbackAction::CONTINUE;
616
////////////////////////////////////////////////////////////////////
617
SoCallbackAction::Response
618
ConvertFromInventor::postTransformSeparator(void* data, SoCallbackAction* action,
621
#ifdef DEBUG_IV_PLUGIN
622
OSG_DEBUG << NOTIFY_HEADER << "postTransformSeparator() "
623
<< node->getTypeId().getName().getString() << std::endl;
627
ConvertFromInventor *thisPtr = (ConvertFromInventor *) data;
628
assert(thisPtr->ivStateStack.size() > 0 && "ivStackState underflow");
629
thisPtr->ivPopState(action, node);
631
return SoCallbackAction::CONTINUE;
633
///////////////////////////////////////////////////////////////////
634
SoCallbackAction::Response
635
ConvertFromInventor::preLOD(void* data, SoCallbackAction* action,
638
#ifdef DEBUG_IV_PLUGIN
639
OSG_DEBUG << NOTIFY_HEADER << "preLOD() "
640
<< node->getTypeId().getName().getString() << std::endl;
644
ConvertFromInventor* thisPtr = (ConvertFromInventor*)data;
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:
654
// Complexity { value 0.1 }
655
// Complexity { value 0.2 }
656
// Complexity { value 0.3 }
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:
666
// Complexity { value 0.1 }
667
// DEF mySphere Sphere {}
670
// Complexity { value 0.2 }
674
// Complexity { value 0.3 }
679
// Such scene can be converted easily to OSG.
680
if (node->isOfType(SoLOD::getClassTypeId())) {
682
thisPtr->ivPushState(action, node, IvStateItem::KEEP_CHILDREN_ORDER,
684
thisPtr->ivStateStack.top().keepChildrenOrderParent = node;
686
return SoCallbackAction::CONTINUE;
689
return SoCallbackAction::CONTINUE;
691
//////////////////////////////////////////////////////////////
692
SoCallbackAction::Response
693
ConvertFromInventor::postLOD(void* data, SoCallbackAction* action,
696
#ifdef DEBUG_IV_PLUGIN
697
OSG_DEBUG << NOTIFY_HEADER << "postLOD() "
698
<< node->getTypeId().getName().getString() << std::endl;
701
// SoGroup -> do nothing
702
if (node->getTypeId() == SoGroup::getClassTypeId())
703
return SoCallbackAction::CONTINUE;
706
ConvertFromInventor* thisPtr = (ConvertFromInventor*)data;
707
IvStateItem &ivState = thisPtr->ivStateStack.top();
710
if (node->isOfType(SoLOD::getClassTypeId())) {
712
osg::LOD *lod = dynamic_cast<osg::LOD*>(ivState.osgStateRoot.get());
713
SoLOD *ivLOD = (SoLOD*)node;
716
SbVec3f ivCenter = ivLOD->center.getValue();
717
lod->setCenter(osg::Vec3(ivCenter[0], ivCenter[1], ivCenter[2]));
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;
733
// Get the ranges and set it
736
lod->setRange(0, 0.0, FLT_MAX);
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);
745
#ifdef DEBUG_IV_PLUGIN
746
OSG_DEBUG << NOTIFY_HEADER <<
747
"Appending osg::LOD with " << num << " children." << std::endl;
750
assert(ivState.keepChildrenOrderParent == node &&
751
"Current node is not the root of keepChildrenOrder graph.");
752
thisPtr->ivPopState(action, node);
754
return SoCallbackAction::CONTINUE;
757
return SoCallbackAction::CONTINUE;
759
///////////////////////////////////////////////////////////////////
760
SoCallbackAction::Response
761
ConvertFromInventor::preShape(void* data, SoCallbackAction* action,
764
#ifdef DEBUG_IV_PLUGIN
765
OSG_DEBUG << NOTIFY_HEADER << "preShape() "
766
<< node->getTypeId().getName().getString() << std::endl;
769
ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
771
// Normal and color binding map from Inventor to OSG
772
static std::map<SoNormalBinding::Binding, deprecated_osg::Geometry::AttributeBinding>
774
static std::map<SoMaterialBinding::Binding, deprecated_osg::Geometry::AttributeBinding>
776
static bool firstTime = true;
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;
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;
812
// Get normal and color binding
813
if (node->isOfType(SoVertexShape::getClassTypeId()))
815
thisPtr->normalBinding = normBindingMap[action->getNormalBinding()];
816
thisPtr->colorBinding = colBindingMap[action->getMaterialBinding()];
820
thisPtr->normalBinding = deprecated_osg::Geometry::BIND_PER_VERTEX;
821
thisPtr->colorBinding = deprecated_osg::Geometry::BIND_PER_VERTEX;
824
// Check vertex ordering
825
if (action->getVertexOrdering() == SoShapeHints::CLOCKWISE)
826
thisPtr->vertexOrder = CLOCKWISE;
828
thisPtr->vertexOrder = COUNTER_CLOCKWISE;
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();
837
return SoCallbackAction::CONTINUE;
839
///////////////////////////////////////////////////////////
840
// OSG doesn't seem to have a transpose function //
842
///////////////////////////////////////////////////////////
844
ConvertFromInventor::transposeMatrix(osg::Matrix& mat)
847
for (int j = 0; j < 4; j++)
849
for (int i = j + 1; i < 4; i++)
851
tmp = mat.operator()(j,i);
852
mat.operator()(j,i) = mat.operator()(i,j);
853
mat.operator()(i,j) = tmp;
858
////////////////////////////////////////////////////////////////////
859
SoCallbackAction::Response
860
ConvertFromInventor::postShape(void* data, SoCallbackAction* action,
863
#ifdef DEBUG_IV_PLUGIN
864
OSG_DEBUG << NOTIFY_HEADER << "postShape() "
865
<< node->getTypeId().getName().getString() << std::endl;
868
ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
871
// Create a new Geometry
872
osg::ref_ptr<deprecated_osg::Geometry> geometry = new deprecated_osg::Geometry;
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());
880
osg::ref_ptr<osg::Vec3Array> norms = NULL;
881
if (thisPtr->normalBinding == deprecated_osg::Geometry::BIND_OVERALL)
883
norms = new osg::Vec3Array(1);
884
const SbVec3f &norm = action->getNormal(0);
885
(*norms)[0].set(norm[0], norm[1], norm[2]);
889
norms = new osg::Vec3Array(thisPtr->normals.size());
890
for (unsigned int i = 0; i < thisPtr->normals.size(); i++)
892
(*norms)[i] = thisPtr->normals[i];
895
geometry->setNormalArray(norms.get());
896
geometry->setNormalBinding(thisPtr->normalBinding);
899
osg::ref_ptr<osg::Vec4Array> cols;
900
if (thisPtr->colorBinding == deprecated_osg::Geometry::BIND_OVERALL)
902
cols = new osg::Vec4Array(1);
903
SbColor ambient, diffuse, specular, emission;
904
float transparency, shininess;
905
action->getMaterial(ambient, diffuse, specular, emission, shininess,
907
(*cols)[0].set(diffuse[0], diffuse[1], diffuse[2], 1.0 - transparency);
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];
915
geometry->setColorArray(cols.get());
916
geometry->setColorBinding(thisPtr->colorBinding);
919
if (thisPtr->textureCoords.empty())
921
OSG_DEBUG<<"tex coords not found"<<std::endl;
926
// report texture coordinate conditions
927
if (action->getNumTextureCoordinates()>0)
929
OSG_DEBUG<<"tex coords found"<<std::endl;
933
OSG_DEBUG<<"tex coords generated"<<std::endl;
936
// Get the texture transformation matrix
937
osg::Matrix textureMat;
938
textureMat.set((float *) action->getTextureMatrix().getValue());
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)
947
// Set the texture coordinates
948
for (unsigned int i = 0; i < thisPtr->textureCoords.size(); i++)
949
(*texCoords)[i] = thisPtr->textureCoords[i];
953
// Transform and set the texture coordinates
954
for (unsigned int i = 0; i < thisPtr->textureCoords.size(); i++)
956
osg::Vec3 transVec = textureMat.preMult(
957
osg::Vec3(thisPtr->textureCoords[i][0],
958
thisPtr->textureCoords[i][1],
960
(*texCoords)[i].set(transVec.x(), transVec.y());
964
geometry->setTexCoordArray(0, texCoords.get());
967
// Set the parameters for the geometry
969
geometry->addPrimitiveSet(new osg::DrawArrays(thisPtr->primitiveType,0,
971
// Get the StateSet for the geoset
972
osg::ref_ptr<osg::StateSet> stateSet = thisPtr->getStateSet(action);
973
geometry->setStateSet(stateSet.get());
975
// Add the geoset to a geode
976
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
977
geode->addDrawable(geometry.get());
980
const char* name = node->getName().getString();
981
geometry->setName(name);
982
geode->setName(strlen(name)>0 ? name : stateSet->getName());
984
// Transformation and scene graph building
985
thisPtr->appendNode(geode.get(), action);
987
return SoCallbackAction::CONTINUE;
989
///////////////////////////////////////////////////////////////
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.
999
// Classes that are loading textures: SoTexture2, SoTexture3 (since Coin 2.0),
1000
// SoVRMLImageTexture (since Coin 2.0), SoVRMLMovieTexture (not yet implemented in Coin)
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.
1007
#include <Inventor/nodes/SoTexture2.h>
1008
#include <Inventor/nodes/SoTexture3.h>
1009
#include <Inventor/VRMLnodes/SoVRMLImageTexture.h>
1012
// This macro gives the common API for all overriding classes.
1013
#define OVERRIDE_HEADER(_class_,_parent_) \
1016
static void overrideClass() \
1018
if (overrideCounter == 0) { \
1019
SoType t = _parent_::getClassTypeId(); \
1020
oldMethod = t.getInstantiationMethod(); \
1021
SoType::overrideType(t, _class_::createInstance); \
1023
overrideCounter++; \
1026
static SbBool cancelOverrideClass() \
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."); \
1034
overrideCounter--; \
1035
if (overrideCounter == 0) \
1036
SoType::overrideType(_parent_::getClassTypeId(), oldMethod); \
1038
return overrideCounter==0; \
1043
static int overrideCounter; \
1045
static SoType::instantiationMethod oldMethod; \
1047
static void* createInstance() \
1049
return new _class_; \
1052
#define OVERRIDE_SRC(_class_) \
1054
int _class_::overrideCounter = 0; \
1055
SoType::instantiationMethod _class_::oldMethod
1058
class SoTexture2Osg : public SoTexture2 {
1059
OVERRIDE_HEADER(SoTexture2Osg, SoTexture2);
1061
virtual SbBool readInstance(SoInput *in, unsigned short flags);
1065
class SoTexture3Osg : public SoTexture3 {
1066
OVERRIDE_HEADER(SoTexture3Osg, SoTexture3);
1068
virtual SbBool readInstance(SoInput *in, unsigned short flags);
1072
class SoVRMLImageTextureOsg : public SoVRMLImageTexture {
1073
OVERRIDE_HEADER(SoVRMLImageTextureOsg, SoVRMLImageTexture);
1075
virtual SbBool readInstance(SoInput *in, unsigned short flags);
1078
OVERRIDE_SRC(SoTexture2Osg);
1079
OVERRIDE_SRC(SoTexture3Osg);
1080
OVERRIDE_SRC(SoVRMLImageTextureOsg);
1082
static osgDB::ReaderWriter::Options* createOptions()
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());
1094
static osg::Image* loadImage(const char *fileName, osgDB::ReaderWriter::Options *options)
1096
osg::ref_ptr<osg::Image> osgImage = osgDB::readImageFile(fileName, options);
1100
OSG_WARN << NOTIFY_HEADER << "Could not read texture file '" << fileName << "'.";
1104
if (!osgImage->isDataContiguous())
1106
OSG_WARN << NOTIFY_HEADER << "Inventor cannot handle non contiguous image data found in texture file '" << fileName << "'.";
1110
return osgImage.release();
1113
SbBool SoTexture2Osg::readInstance(SoInput *in, unsigned short flags)
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);
1120
// if file name given
1121
if (readOK && !filename.isDefault() && filename.getValue() != "")
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);
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();
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.
1144
// image loading failed -> set readOK
1146
this->setReadStatus(FALSE);
1149
// write filename, not image
1150
this->image.setDefault(TRUE);
1153
filename.enableNotify(oldNotify);
1157
SbBool SoTexture3Osg::readInstance(SoInput *in, unsigned short flags)
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);
1164
// if file name given
1165
int numImages = filenames.getNum();
1166
if (readOK && !filenames.isDefault() && numImages > 0)
1168
// Fail on empty filenames
1169
SbBool sizeError = FALSE;
1170
SbBool retval = FALSE;
1171
SbVec3s volumeSize(0,0,0);
1174
for (i=0; i<numImages; i++)
1175
if (this->filenames[i].getLength()==0) break;
1180
osgDB::ReaderWriter::Options *options = createOptions();
1182
for (int n=0; n<numImages && !sizeError; n++)
1185
osg::ref_ptr<osg::Image> image = loadImage(filenames[n].getString(), options);
1189
OSG_WARN << NOTIFY_HEADER << "Could not read texture file #" << n << ": "
1190
<< filenames[n].getString() << "\n";
1195
// get image dimensions and data
1196
int nc = osg::Image::computeNumComponents(image->getPixelFormat());
1197
SbVec3s size(image->s(), image->t(), image->r());
1200
unsigned char *imgbytes = image->data();
1202
if (this->images.isDefault()) { // First time => allocate memory
1203
volumeSize.setValue(size[0],
1207
this->images.setValue(volumeSize, nc, NULL);
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) ||
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";
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,
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.
1248
// if image loading failed, set read status,
1249
// but not set readOK to false (according to Coin source code)
1250
this->setReadStatus(FALSE);
1253
// write filename, not image
1254
this->images.setDefault(TRUE);
1257
filenames.enableNotify(oldNotify);
1261
SbBool SoVRMLImageTextureOsg::readInstance(SoInput *in, unsigned short flags)
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);
1270
// create options and read the file
1271
osgDB::ReaderWriter::Options *options = createOptions();
1273
if (url.getNum() && url[0].getLength())
1275
osg::ref_ptr<osg::Image> image = loadImage(url[0].getString(), options);
1276
if (!image->valid())
1278
OSG_WARN << "Could not read texture file: " << url[0].getString() << std::endl;
1279
this->setReadStatus(FALSE);
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();
1288
SbImage ivImage(bytes, size, nc);
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.
1301
url.enableNotify(oldNotify);
1305
#endif /* __COIN__ */
1307
///////////////////////////////////////////////////////////////
1308
SoCallbackAction::Response
1309
ConvertFromInventor::postTexture(void* data, SoCallbackAction *,
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();
1320
OSG_DEBUG << std::endl;
1323
ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
1324
bool texturingEnabled = false;
1327
if (node->isOfType(SoTexture2::getClassTypeId())) {
1329
// Check whether texturing was enabled by the texture node
1330
SoTexture2 *t = (SoTexture2*)node;
1333
const unsigned char *data = t->image.getValue(size, nc);
1334
texturingEnabled = t->filename.getValue().getLength() ||
1335
(data && size != SbVec2s(0,0));
1340
// SoVRMLImageTexture
1341
if (node->isOfType(SoVRMLImageTexture::getClassTypeId())) {
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);
1349
if (node->isOfType(SoVRMLAppearance::getClassTypeId())) {
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;
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;
1367
#endif /* __COIN__ */
1369
// Set current texture
1370
if (texturingEnabled)
1371
thisPtr->ivStateStack.top().currentTexture = node;
1373
thisPtr->ivStateStack.top().currentTexture = NULL;
1375
return SoCallbackAction::CONTINUE;
1377
//////////////////////////////////////////////////////////////////
1378
void ConvertFromInventor::transformLight(SoCallbackAction* action,
1380
osg::Vec3& transVec)
1382
osg::Matrix modelMat;
1383
modelMat.set((float *)action->getModelMatrix().getValue());
1385
transVec.set(vec[0], vec[1], vec[2]);
1386
transVec = modelMat.preMult(transVec);
1388
///////////////////////////////////////////////////////////////////
1389
SoCallbackAction::Response
1390
ConvertFromInventor::preLight(void* data, SoCallbackAction* action,
1393
#ifdef DEBUG_IV_PLUGIN
1394
OSG_DEBUG << NOTIFY_HEADER << "preLight() "
1395
<< node->getTypeId().getName().getString() << std::endl;
1398
ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
1400
// Return if the light is not on
1401
const SoLight* ivLight = (const SoLight*) node;
1402
if (!ivLight->on.getValue())
1403
return SoCallbackAction::CONTINUE;
1405
// Create new OSG light
1406
IvStateItem &ivState = thisPtr->ivStateStack.top();
1407
osg::ref_ptr<osg::Light> osgLight = new osg::Light;
1409
// Get color and intensity
1410
SbVec3f lightColor = ivLight->color.getValue();
1411
float intensity = ivLight->intensity.getValue();
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));
1423
if (node->isOfType(SoDirectionalLight::getClassTypeId()))
1425
SoDirectionalLight *dirLight = (SoDirectionalLight *) node;
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.));
1433
thisPtr->transformLight(action, dirLight->direction.getValue(), transVec);
1434
osgLight->setPosition(osg::Vec4(transVec.x(), transVec.y(),
1438
else if (node->isOfType(SoPointLight::getClassTypeId()))
1440
SoPointLight* ptLight = (SoPointLight *) node;
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.));
1448
thisPtr->transformLight(action, ptLight->location.getValue(), transVec);
1449
osgLight->setPosition(osg::Vec4(transVec.x(), transVec.y(),
1453
else if (node->isOfType(SoSpotLight::getClassTypeId()))
1455
SoSpotLight* spotLight = (SoSpotLight *) node;
1457
osgLight->setSpotExponent(spotLight->dropOffRate.getValue() * 128.0);
1458
osgLight->setSpotCutoff(spotLight->cutOffAngle.getValue()*180.0/osg::PI);
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]));
1468
thisPtr->transformLight(action, spotLight->location.getValue(), transVec);
1469
osgLight->setPosition(osg::Vec4(transVec.x(), transVec.y(),
1472
thisPtr->transformLight(action, spotLight->direction.getValue(),transVec);
1473
osgLight->setDirection(osg::Vec3(transVec.x(), transVec.y(),
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]);
1485
// keep default light settings for directional light, e.g.
1489
// Append the light into the scene and onto the state stack
1490
osgLight->setLightNum(ivState.currentLights.size());
1491
ivState.currentLights.push_back(osgLight);
1493
// Create LightSource
1494
osg::ref_ptr<osg::LightSource> ls = new osg::LightSource();
1495
ls->setLight(osgLight.get());
1498
const char* name = ivLight->getName().getString();
1499
osgLight->setName(name);
1500
//ls->setName(name); -> this will be handled bellow in ivPushState
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());
1508
if (!(thisPtr->lightGroup.get()))
1509
thisPtr->lightGroup = new osg::Group();
1510
thisPtr->lightGroup->addChild(ls);
1513
return SoCallbackAction::CONTINUE;
1515
///////////////////////////////////////////////////////////////////
1516
SoCallbackAction::Response
1517
ConvertFromInventor::preEnvironment(void* data, SoCallbackAction* action,
1520
#ifdef DEBUG_IV_PLUGIN
1521
OSG_DEBUG << NOTIFY_HEADER << "preEnvironment() "
1522
<< node->getTypeId().getName().getString() << std::endl;
1525
ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
1526
IvStateItem &ivState = thisPtr->ivStateStack.top();
1528
ivState.currentAmbientLight = ((SoEnvironment*)node)->ambientColor.getValue() *
1529
((SoEnvironment*)node)->ambientIntensity.getValue();
1531
return SoCallbackAction::CONTINUE;
1533
///////////////////////////////////////////////////////////////////
1534
#ifdef INVENTOR_SHADERS_AVAILABLE
1536
convertShader(osg::Shader::Type osgShaderType,
1537
const SoShaderObject *ivShader,
1538
osg::Program *osgProgram)
1540
// NULL shader is not converted while returning success
1541
if (ivShader == NULL)
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());
1549
if (ivShader->sourceType.getValue() == SoShaderObject::GLSL_PROGRAM)
1550
osgShader->setShaderSource(ivShader->sourceProgram.getValue().getString());
1552
OSG_WARN << NOTIFY_HEADER << "Can not convert "
1553
<< "shader. Unsupported shader language." << std::endl;
1558
osgShader->setName(ivShader->getName().getString());
1560
return osgProgram->addShader(osgShader.get());
1562
#endif // INVENTOR_SHADERS_AVAILABLE
1563
///////////////////////////////////////////////////////////////////
1564
SoCallbackAction::Response
1565
ConvertFromInventor::preShaderProgram(void* data, SoCallbackAction* action,
1568
#ifdef DEBUG_IV_PLUGIN
1569
OSG_DEBUG << NOTIFY_HEADER << "preShaderProgram() "
1570
<< node->getTypeId().getName().getString() << std::endl;
1573
#ifdef INVENTOR_SHADERS_AVAILABLE
1575
ConvertFromInventor *thisPtr = (ConvertFromInventor*)data;
1576
IvStateItem &ivState = thisPtr->ivStateStack.top();
1578
// Get Inventor nodes
1579
// Note: Shaders are available since Coin 2.5 (including
1581
const SoShaderProgram *ivProgram = (const SoShaderProgram*)node;
1582
const SoVertexShader *ivVertexShader = NULL;
1583
const SoGeometryShader *ivGeometryShader = NULL;
1584
const SoFragmentShader *ivFragmentShader = NULL;
1586
for (int i=0, c=ivProgram->shaderObject.getNum(); i<c; i++) {
1588
const SoShaderObject *shader = (const SoShaderObject*)ivProgram->shaderObject[i];
1589
if (!shader->isOfType(SoShaderObject::getClassTypeId()))
1591
if (shader->isActive.getValue() == FALSE)
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;
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;
1615
osgProgram->setName(ivProgram->getName().getString());
1617
// Put shader to the state stack
1618
ivState.currentGLProgram = osgProgram;
1622
OSG_WARN << NOTIFY_HEADER << "Warning: The model "
1623
"contains shaders while your Inventor does not support "
1624
"them." << std::endl;
1627
return SoCallbackAction::CONTINUE;
1629
///////////////////////////////////////////////////////////////////////////////////////
1630
osg::ref_ptr<osg::StateSet>
1631
ConvertFromInventor::getStateSet(SoCallbackAction* action)
1633
osg::ref_ptr<osg::StateSet> stateSet = new osg::StateSet;
1635
// Inherit modes from the global state
1638
// Inventor State Stack
1639
IvStateItem &ivState = ivStateStack.top();
1641
// Convert the IV texture to OSG texture if any
1642
osg::ref_ptr<osg::Texture2D> texture;
1643
const SoNode *ivTexture = ivState.currentTexture;
1646
// Found a corresponding OSG texture object
1647
if (ivToOsgTexMap[ivTexture])
1648
texture = ivToOsgTexMap[ivTexture];
1651
// Create a new osg texture
1652
texture = convertIVTexToOSGTex(ivTexture, action);
1654
// Add the new texture to the database
1655
ivToOsgTexMap[ivTexture] = texture.get();
1658
stateSet->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::ON);
1663
std::string name = texture->getName();
1665
stateSet->setName(name);
1667
// Set the texture environment
1668
osg::ref_ptr<osg::TexEnv> texEnv = new osg::TexEnv;
1669
switch (action->getTextureModel())
1671
case SoTexture2::MODULATE:
1672
texEnv->setMode(osg::TexEnv::MODULATE);
1674
case SoTexture2::DECAL:
1675
texEnv->setMode(osg::TexEnv::DECAL);
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));
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);
1690
OSG_WARN << "Unsupported TexEnv mode." << std::endl;
1694
stateSet->setTextureAttributeAndModes(0,texEnv.get(),osg::StateAttribute::ON);
1697
SbColor ambient, diffuse, specular, emission;
1698
float shininess, transparency;
1700
// Get the material colors
1701
action->getMaterial(ambient, diffuse, specular, emission,
1702
shininess, transparency, 0);
1705
SbBool hasTextureTransparency = FALSE;
1709
const unsigned char *data = NULL;
1710
if (ivTexture->isOfType(SoTexture2::getClassTypeId()))
1711
data = ((SoTexture2*)ivTexture)->image.getValue(size, bpp);
1714
if (ivTexture->isOfType(SoVRMLImageTexture::getClassTypeId())) {
1715
const SbImage *img = ((SoVRMLImageTexture*)ivTexture)->getImage();
1717
data = img->getValue(size, bpp);
1721
// look whether texture really contains transparency
1722
if ((bpp==4 || bpp==2) && data) {
1724
for (int y=0; y<size[1]; y++)
1725
for (int x=0; x<size[0]; x++, data += bpp)
1727
hasTextureTransparency = TRUE;
1734
if (transparency > 0 || hasTextureTransparency)
1736
// Blending to SRC_APLHA and ONE_MINUS_SRC_ALPHA
1737
stateSet->setAttributeAndModes(new osg::BlendFunc);
1739
// Disable depth writes
1740
stateSet->setAttributeAndModes(new osg::Depth(osg::Depth::LEQUAL, 0., 1., false));
1742
// Enable depth sorting for transparent objects
1743
stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
1744
stateSet->setNestRenderBins(false);
1748
if (action->getLineWidth())
1750
osg::ref_ptr<osg::LineWidth> lineWidth = new osg::LineWidth;
1751
lineWidth->setWidth(action->getLineWidth());
1752
stateSet->setAttributeAndModes(lineWidth.get(), osg::StateAttribute::ON);
1756
if (action->getPointSize())
1758
osg::ref_ptr<osg::Point> point = new osg::Point;
1759
point->setSize(action->getPointSize());
1760
stateSet->setAttributeAndModes(point.get(), osg::StateAttribute::ON);
1764
switch (action->getDrawStyle())
1766
case SoDrawStyle::FILLED:
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);
1777
case SoDrawStyle::LINES:
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);
1785
case SoDrawStyle::POINTS:
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);
1793
case SoDrawStyle::INVISIBLE:
1794
// check how to handle this in osg.
1798
// Set back face culling
1799
if (action->getShapeType() == SoShapeHints::SOLID)
1801
osg::ref_ptr<osg::CullFace> cullFace = new osg::CullFace;
1802
cullFace->setMode(osg::CullFace::BACK);
1803
stateSet->setAttributeAndModes(cullFace.get(), osg::StateAttribute::ON);
1807
if (action->getLightModel() == SoLightModel::BASE_COLOR)
1808
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
1812
osg::ref_ptr<osg::Material> material = new osg::Material;
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,
1831
material->setShininess(osg::Material::FRONT_AND_BACK, 0.0);
1833
material->setColorMode(osg::Material::DIFFUSE);
1835
stateSet->setAttributeAndModes(material.get(), osg::StateAttribute::ON);
1836
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
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));
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);
1851
stateSet->setAttributeAndModes(lightModel, osg::StateAttribute::ON);
1854
for (unsigned int i = 0; i < ivState.currentLights.size(); i++)
1855
stateSet->setAttributeAndModes(ivState.currentLights[i].get(),
1856
osg::StateAttribute::ON);
1860
// Shader program setup
1861
if (ivState.currentGLProgram.get() != NULL) {
1862
stateSet->setAttributeAndModes(ivState.currentGLProgram.get(),
1863
osg::StateAttribute::ON);
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));
1880
////////////////////////////////////////////////////////////////////
1882
ConvertFromInventor::convertIVTexToOSGTex(const SoNode* soNode,
1883
SoCallbackAction* action)
1885
#ifdef DEBUG_IV_PLUGIN
1886
OSG_DEBUG << NOTIFY_HEADER
1887
<< "convertIVTexToOSGTex ("
1888
<< soNode->getTypeId().getName().getString()
1889
<< ")" << std::endl;
1895
// Get the texture size and components
1896
const unsigned char* soImageData = action->getTextureImage(soSize, soNC);
1898
OSG_WARN << NOTIFY_HEADER
1899
<< "Warning: Error while loading texture data." << std::endl;
1903
// Allocate memory for image data
1904
unsigned char* osgImageData = new unsigned char[soSize[0] * soSize[1] * soNC];
1906
// Copy the texture image data from the inventor texture
1907
memcpy(osgImageData, soImageData, soSize[0] * soSize[1] * soNC);
1910
std::string fileName;
1911
if (soNode->isOfType(SoTexture2::getClassTypeId()))
1912
fileName = ((SoTexture2*)soNode)->filename.getValue().getString();
1915
if (soNode->isOfType(SoVRMLImageTexture::getClassTypeId()))
1916
fileName = ((SoVRMLImageTexture*)soNode)->url.getNum() >= 1 ?
1917
((SoVRMLImageTexture*)soNode)->url.getValues(0)[0].getString() : "";
1920
OSG_WARN << NOTIFY_HEADER
1921
<< " Warning: Unsupported texture type: "
1922
<< soNode->getTypeId().getName().getString() << std::endl;
1924
#ifdef DEBUG_IV_PLUGIN
1925
OSG_DEBUG << NOTIFY_HEADER
1926
<< " Converting file name: " << fileName << " -> ";
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;
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);
1942
// Create the osg::Texture2D
1943
osg::Texture2D *osgTex = new osg::Texture2D;
1944
osgTex->setImage(osgImage.get());
1947
osgTex->setName(soNode->getName().getString());
1949
static std::map<SoTexture2::Wrap, osg::Texture2D::WrapMode> texWrapMap;
1950
static bool firstTime = true;
1953
texWrapMap[SoTexture2::CLAMP] = osg::Texture2D::CLAMP;
1954
texWrapMap[SoTexture2::REPEAT] = osg::Texture2D::REPEAT;
1958
// Set texture wrap mode
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);
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()]);
1982
///////////////////////////////////////////////////////////////////
1983
SoCallbackAction::Response
1984
ConvertFromInventor::preInfo(void* data, SoCallbackAction* action,
1987
#ifdef DEBUG_IV_PLUGIN
1988
OSG_DEBUG << NOTIFY_HEADER << "preInfo() "
1989
<< node->getTypeId().getName().getString() << std::endl;
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;
1998
return SoCallbackAction::CONTINUE;
2000
/////////////////////////////////////////////////////////////
2001
SoCallbackAction::Response
2002
ConvertFromInventor::preRotor(void *data, SoCallbackAction *action,
2005
#ifdef DEBUG_IV_PLUGIN
2006
OSG_DEBUG << NOTIFY_HEADER << "preRotor() "
2007
<< node->getTypeId().getName().getString() << std::endl;
2010
ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
2012
// Get the parameters for the inventor Rotor
2013
SoRotor *ivRotor = (SoRotor *) node;
2016
ivRotor->rotation.getValue(ivAxis, angle);
2018
// Create a new osg::MatrixTransform
2019
osg::ref_ptr<osg::MatrixTransform> rotorTransform = new osg::MatrixTransform;
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());
2028
// Set the app callback
2029
rotorTransform->setUpdateCallback(rotorCallback.get());
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());
2036
// Append initial rotation to the model matrix
2037
if (!ivRotor->rotation.isIgnored()) {
2038
SoModelMatrixElement::rotateBy(action->getState(), ivRotor,
2039
ivRotor->rotation.getValue());
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;
2048
////////////////////////////////////////////////////////////////
2049
SoCallbackAction::Response
2050
ConvertFromInventor::prePendulum(void* data, SoCallbackAction *action,
2053
#ifdef DEBUG_IV_PLUGIN
2054
OSG_DEBUG << NOTIFY_HEADER << "prePendulum() "
2055
<< node->getTypeId().getName().getString() << std::endl;
2058
ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
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();
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 ) {
2075
endAngle = -endAngle;
2078
// Create a new osg::MatrixTransform
2079
osg::ref_ptr<osg::MatrixTransform> pendulumTransform = new osg::MatrixTransform;
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).
2085
if (fabs(startAngle) > fabs(endAngle))
2086
axis = osg::Vec3(ivAxis0[0], ivAxis0[1], ivAxis0[2]);
2088
axis = osg::Vec3(ivAxis1[0], ivAxis1[1], ivAxis1[2]);
2089
PendulumCallback* pendulumCallback
2090
= new PendulumCallback(axis, startAngle, endAngle,
2091
ivPendulum->speed.getValue());
2093
// Set the app callback
2094
pendulumTransform->setUpdateCallback(pendulumCallback);
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());
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;
2107
////////////////////////////////////////////////////////////////
2108
SoCallbackAction::Response
2109
ConvertFromInventor::preShuttle(void* data, SoCallbackAction *action,
2112
#ifdef DEBUG_IV_PLUGIN
2113
OSG_DEBUG << NOTIFY_HEADER << "preShuttle() "
2114
<< node->getTypeId().getName().getString() << std::endl;
2117
ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
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();
2125
// Create a new osg::MatrixTransform
2126
osg::ref_ptr<osg::MatrixTransform> shuttleTransform = new osg::MatrixTransform;
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());
2134
// Set the app callback
2135
shuttleTransform->setUpdateCallback(shuttleCallback);
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());
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;
2148
////////////////////////////////////////////////////////////
2149
void ConvertFromInventor::addVertex(SoCallbackAction* action,
2150
const SoPrimitiveVertex *v,
2153
// Get the coordinates of the vertex
2154
SbVec3f pt = v->getPoint();
2155
vertices.push_back(osg::Vec3(pt[0], pt[1], pt[2]));
2157
// Get the normal of the vertex
2158
SbVec3f norm = v->getNormal();
2160
if ((normalBinding == deprecated_osg::Geometry::BIND_PER_VERTEX) ||
2161
(normalBinding == deprecated_osg::Geometry::BIND_PER_PRIMITIVE && index == 0))
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]));
2168
normals.push_back(osg::Vec3(norm[0], norm[1], norm[2]));
2171
if (colorBinding == deprecated_osg::Geometry::BIND_PER_VERTEX ||
2172
colorBinding == deprecated_osg::Geometry::BIND_PER_PRIMITIVE)
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));
2187
// Get the texture coordinates
2188
SbVec4f texCoord = v->getTextureCoords();
2189
textureCoords.push_back(osg::Vec2(texCoord[0], texCoord[1]));
2191
////////////////////////////////////////////////////////////////////////////
2192
void ConvertFromInventor::addTriangleCB(void* data, SoCallbackAction* action,
2193
const SoPrimitiveVertex* v0,
2194
const SoPrimitiveVertex* v1,
2195
const SoPrimitiveVertex* v2)
2197
ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
2199
switch (thisPtr->vertexOrder)
2202
thisPtr->addVertex(action, v0, 0);
2203
thisPtr->addVertex(action, v2, 1);
2204
thisPtr->addVertex(action, v1, 2);
2206
case COUNTER_CLOCKWISE:
2207
thisPtr->addVertex(action, v0, 0);
2208
thisPtr->addVertex(action, v1, 1);
2209
thisPtr->addVertex(action, v2, 2);
2213
thisPtr->numPrimitives++;
2214
thisPtr->primitiveType = osg::PrimitiveSet::TRIANGLES;
2216
////////////////////////////////////////////////////////////////////////////////
2217
void ConvertFromInventor::addLineSegmentCB(void* data, SoCallbackAction* action,
2218
const SoPrimitiveVertex* v0,
2219
const SoPrimitiveVertex* v1)
2221
ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
2223
thisPtr->addVertex(action, v0, 0);
2224
thisPtr->addVertex(action, v1, 1);
2226
thisPtr->numPrimitives++;
2227
thisPtr->primitiveType = osg::PrimitiveSet::LINES;
2229
//////////////////////////////////////////////////////////////////////////
2230
void ConvertFromInventor::addPointCB(void* data, SoCallbackAction* action,
2231
const SoPrimitiveVertex* v0)
2233
ConvertFromInventor* thisPtr = (ConvertFromInventor *) (data);
2235
thisPtr->addVertex(action, v0, 0);
2237
thisPtr->numPrimitives++;
2238
thisPtr->primitiveType = osg::PrimitiveSet::POINTS;
2240
//////////////////////////////////////////////////////////////////////////
2241
void ConvertFromInventor::init()
2244
SoTexture2Osg::overrideClass();
2245
SoTexture3Osg::overrideClass();
2246
SoVRMLImageTextureOsg::overrideClass();