root/OpenSceneGraph/trunk/src/osgPlugins/Inventor/ConvertToInventor.cpp @ 13557

Revision 13557, 76.6 kB (checked in by robert, 41 hours ago)

From Alberto Luaces,"the current code uses the preprocessor for generating the plugin path in
a way that when CMAKE_INSTALL_PREFIX contains something along the lines
of

/usr/x86_64-linux-gnu/

it gets substituted as

/usr/x86_64-1-gnu/

that is, the string is preprocessed again, thereby making changes to
anything that matches any defined symbol, as "linux" in this example
(https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=763816).

Quoting that path directly in CMake scripts solves that problem.
"

  • Property svn:eol-style set to native
Line 
1//
2//  ConvertToInventor converts OSG scene graph to Inventor or VRML 1 scene graph
3//
4//  It requires OSG and Inventor compatible library, such as Coin,
5//  SGI Inventor , or TGS Inventor.
6//
7//
8//  Autor: PCJohn (peciva _at fit.vutbr.cz)
9//
10//  License: public domain
11//
12//
13//  THIS SOFTWARE IS NOT COPYRIGHTED
14//
15//  This source code is offered for use in the public domain.
16//  You may use, modify or distribute it freely.
17//
18//  This source code is distributed in the hope that it will be useful but
19//  WITHOUT ANY WARRANTY.  ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
20//  DISCLAIMED.  This includes but is not limited to warranties of
21//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22//
23//  If you find the source code useful, authors will kindly welcome
24//  if you give them credit and keep their names with their source code,
25//  but you are not forced to do so.
26//
27
28#include <osg/BlendFunc>
29#include <osg/Billboard>
30#include <osg/Geode>
31#include <osg/Geometry>
32#include <osg/Group>
33#include <osg/LightModel>
34#include <osg/LOD>
35#include <osg/Material>
36#include <osg/MatrixTransform>
37#include <osg/Node>
38#include <osg/NodeVisitor>
39#include <osg/PositionAttitudeTransform>
40#include <osg/PrimitiveSet>
41#include <osg/ShapeDrawable>
42#include <osg/TexEnv>
43#include <osg/TexGen>
44#include <Inventor/nodes/SoBaseColor.h>
45#include <Inventor/nodes/SoCoordinate3.h>
46#include <Inventor/nodes/SoCoordinate4.h>
47#include <Inventor/nodes/SoCube.h>
48#include <Inventor/nodes/SoCone.h>
49#include <Inventor/nodes/SoCylinder.h>
50#include <Inventor/nodes/SoFaceSet.h>
51#include <Inventor/nodes/SoIndexedFaceSet.h>
52#include <Inventor/nodes/SoIndexedLineSet.h>
53#include <Inventor/nodes/SoIndexedTriangleStripSet.h>
54#include <Inventor/nodes/SoLightModel.h>
55#include <Inventor/nodes/SoLineSet.h>
56#include <Inventor/nodes/SoLOD.h>
57#include <Inventor/nodes/SoLevelOfDetail.h>
58#include <Inventor/nodes/SoMaterial.h>
59#include <Inventor/nodes/SoMatrixTransform.h>
60#include <Inventor/nodes/SoNode.h>
61#include <Inventor/nodes/SoNormal.h>
62#include <Inventor/nodes/SoNormalBinding.h>
63#include <Inventor/nodes/SoPointSet.h>
64#include <Inventor/nodes/SoSeparator.h>
65#include <Inventor/nodes/SoShapeHints.h>
66#include <Inventor/nodes/SoSphere.h>
67#include <Inventor/nodes/SoTexture2.h>
68#include <Inventor/nodes/SoTextureCoordinate2.h>
69#include <Inventor/nodes/SoTextureCoordinateEnvironment.h>
70#include <Inventor/nodes/SoTransform.h>
71#include <Inventor/nodes/SoTranslation.h>
72#include <Inventor/nodes/SoTriangleStripSet.h>
73#include <Inventor/fields/SoFields.h>
74#ifdef __COIN__
75#include <Inventor/nodes/SoTextureCoordinate3.h>
76#include <Inventor/nodes/SoTransparencyType.h>
77#include <Inventor/VRMLnodes/SoVRMLBillboard.h>
78#endif
79#include "ConvertToInventor.h"
80
81#include <assert.h>
82
83
84#define DEBUG_IV_WRITER 1
85
86
87// Considerations for VRML1 support:
88//
89// SoSeparator:                supported (only renderCulling field)
90// SoCoordinate3:              supported
91// SoCoordinate4:              no -> conversion to Coordinate3 required <---- missing
92// SoTextureCoordinate2:       supported
93// SoTextureCoordinate3:       no - 3D textures not supported by VRML1
94// SoTextureCoordinateEnvironment no <- should texturing be disabled in this case?
95// SoTextureCoordinateBinding: no -> indexing is probably mandatory
96// SoNormal:                   supported
97// SoNormalBinding:            supported (all modes supported, including non-indexed modes)
98// SoMaterial:                 supported
99// SoMaterialBinding:          supported (all modes supported, including non-indexed modes)
100// SoBaseColor:                no -> using SoMaterial instead
101// SoPointSet:                 supported
102// SoLineSet:                  no -> using SoIndexedListSet instead
103// SoIndexedLineSet:           supported
104// SoIndexedTriangleStripSet:  no -> using SoIndexedFaceSet instead
105// SoTriangleStripSet:         no -> using SoIndexedFaceSet instead
106// SoMatrixTransform:          supported
107// SoTransform:                supported
108// SoTransparencyType:         no   <---- missing
109// SoShapeHints:               supported
110// SoCone,SoCube,SoCylinder,SoSphere supported
111// SoTranslation               supported
112// SoLightModel:               ?
113// SoLOD:                      supported
114// SoLevelOfDetail:            no
115
116
117// Node list from VRML1 documentation:
118// shape nodes: AsciiText, Cone, Cube, Cylinder, IndexedFaceSet, IndexedLineSet, PointSet, Sphere
119// properties nodes: Coordinate3, FontStyle, Info, Material, MaterialBinding, Normal, NormalBinding,
120//                   Texture2, Texture2Transform, TextureCoordinate2, ShapeHints
121// transformantion nodes: MatrixTransform, Rotation, Scale, Transform, Translation
122// group nodes: Separator, Switch, WWWAnchor, LOD
123// cameras: OrthographicCamera, PerspectiveCamera
124// lights: DirectionalLight, PointLight, SpotLight
125// others: WWWInline
126
127
128
129ConvertToInventor::ConvertToInventor() : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
130{
131  // Enable/disable using of some extensions introduced by TGS and Coin.
132  //
133  // For instance, GL_REPLACE texturing mode is extension
134  // and it will not be used if extensions are not enabled.
135#ifdef __COIN__
136  useIvExtensions = true;
137#else
138  useIvExtensions = false;
139#endif
140  vrml1Conversion = false;
141  uniqueIdGenerator = 1;
142
143  // Scene root
144  ivRoot = new SoSeparator;
145  ivRoot->ref();
146
147  // OSG -> Inventor coordinate system conversion
148  SoMatrixTransform *mt = new SoMatrixTransform;
149  mt->matrix.setValue(1.f, 0.f,  0.f, 0.f,
150                      0.f, 0.f, -1.f, 0.f,
151                      0.f, 1.f,  0.f, 0.f,
152                      0.f, 0.f,  0.f, 1.f);
153  ivRoot->addChild(mt);
154
155#if 0 // Setting everything to defaults may not be correct option
156      // because the user may want to have model whose material,etc.
157      // will be specified up in the scene graph and he may, for instance,
158      // reuse the model with different materials.
159      // However, I am not sure anyway. PCJohn-2007-08-27
160
161  //              OSG defaults to:    Inventor defaults to:
162  // GL_LIGHTING   enabled             enabled
163  SoLightModel *lm = new SoLightModel;
164  lm->model = SoLightModel::PHONG;
165  ivRoot->addChild(lm);
166
167  //              OSG defaults to:    Inventor defaults to:
168  // lighting:     one side            one side lighting
169  // frontFace:    COUNTER_CLOCKWISE   COUNTER_CLOCKWISE
170  // culling:      DISABLED            DISABLED
171  // faceCulling:  GL_BACK             GL_BACK
172  SoShapeHints *sh = new SoShapeHints;
173  sh->vertexOrdering = SoShapeHints::UNKNOWN_ORDERING;
174  ivRoot->addChild(sh);
175
176  // Make sure texturing is OFF
177  ivRoot->addChild(new SoTexture2D);
178
179  // Put default material
180  ivRoot->addChild(new SoMaterial);
181#endif
182
183  // initialize Inventor state stack
184  ivStack.push(InventorState::createTopLevelState(ivRoot));
185}
186
187
188ConvertToInventor::~ConvertToInventor()
189{
190  assert(ivStack.size() == 1 && "Not all InventorStates were popped from ivStack.");
191  if (ivRoot)  ivRoot->unref();
192}
193
194
195SoNode* ConvertToInventor::getIvSceneGraph() const
196{
197  return ivRoot;
198}
199
200
201void ConvertToInventor::apply(osg::Node &node)
202{
203#ifdef DEBUG_IV_WRITER
204  OSG_INFO << "IvWriter: node traversed" << std::endl;
205#endif
206
207  traverse(node);
208}
209
210
211template<typename fieldClass, typename ivType, typename osgType>
212void osgArray2ivMField_template(const osg::Array *array, fieldClass &field, int startIndex = 0, int stopIndex = 0, int numItemsUntilMinusOne = 0)
213{
214  int i,num = array->getNumElements();
215  if (startIndex!=0 || stopIndex!=0) {
216    num = stopIndex - startIndex;
217    assert(stopIndex >= startIndex);
218    assert(startIndex >= 0 && stopIndex >= 0);
219    assert(stopIndex <= int(array->getNumElements()));
220  }
221
222  // update num if numItemsUntilMinusOne > 0
223  if (numItemsUntilMinusOne > 0 && num >= 1)
224    num += (num-1) / numItemsUntilMinusOne;
225
226  field.setNum(num);
227  ivType *a = field.startEditing();
228
229  osgType *ptr = (osgType*)array->getDataPointer() + startIndex;
230
231  if (numItemsUntilMinusOne <= 0)
232    for (i=0; i<num; i++, ptr++)
233      a[i] = ivType(*ptr);
234  else {
235    int z;
236    for (i=0, z=0; i<num; i++)
237      if (z == numItemsUntilMinusOne) {
238        a[i] = ivType(-1);
239        z = 0;
240      } else {
241        a[i] = ivType(*ptr);
242        ptr++;
243        z++;
244      }
245  }
246
247  field.finishEditing();
248}
249
250
251template<typename ivType, typename osgType, int shift>
252void osgArray2ivMField_composite_template_worker(ivType *dest, osgType *src, int num, int numItemsUntilMinusOne = 0)
253{
254  for (int i=0; i<num; i++, src+=shift)
255    dest[i] = ivType(src);
256}
257
258
259template<>
260void osgArray2ivMField_composite_template_worker<SbColor, GLubyte, 4>(SbColor *dest, GLubyte *src, int num, int numItemsUntilMinusOne)
261{
262  for (int i=0; i<num; i++, src+=4)
263    dest[i].setValue(src[0]/255.f, src[1]/255.f, src[2]/255.f);
264}
265
266
267template<>
268void osgArray2ivMField_composite_template_worker<SbVec3f, float, 2>(SbVec3f *dest, float *src, int num, int numItemsUntilMinusOne)
269{
270  for (int i=0; i<num; i++, src+=2)
271    dest[i].setValue(src[0], src[1], 0.f);
272}
273
274
275template<typename fieldClass, typename ivType, typename osgType, int shift>
276void osgArray2ivMField_composite_template(const osg::Array *array, fieldClass &field, int startIndex = 0, int stopIndex = 0, int numItemsUntilMinusOne = 0)
277{
278  int num = array->getNumElements();
279  if (startIndex!=0 || stopIndex!=0) {
280    num = stopIndex - startIndex;
281    assert(stopIndex >= startIndex);
282    assert(startIndex >= 0 && stopIndex >= 0);
283    assert(stopIndex <= int(array->getNumElements()));
284  }
285  assert(numItemsUntilMinusOne <= 0 && "Composite template must have numItemsUntilMinusOne set to 0.");
286  field.setNum(num);
287  ivType *a = field.startEditing();
288
289  osgType *ptr = (osgType*)array->getDataPointer() + startIndex;
290  osgArray2ivMField_composite_template_worker<ivType, osgType, shift>(a, ptr, num, 0);
291
292  field.finishEditing();
293}
294
295
296template<typename fieldClass, typename ivType, typename osgType, int numComponents>
297void osgArray2ivMField_pack_template(const osg::Array *array, fieldClass &field,
298                                            osgType mul, osgType max, osgType min,
299                                            int startIndex = 0, int stopIndex = 0, int numItemsUntilMinusOne = 0)
300{
301  int i,num = array->getNumElements();
302  if (startIndex!=0 || stopIndex!=0) {
303    num = stopIndex - startIndex;
304    assert(stopIndex >= startIndex);
305    assert(startIndex >= 0 && stopIndex >= 0);
306    assert(stopIndex <= int(array->getNumElements()));
307  }
308  assert(numItemsUntilMinusOne <= 0 && "Pack template must have numItemsUntilMinusOne set to 0.");
309  field.setNum(num);
310  ivType *a = field.startEditing();
311
312  osgType *ptr = (osgType*)array->getDataPointer() + startIndex;
313  for (i=0; i<num; i++, ptr++) {
314    a[i] = ivType(0);
315    for (int j=0; j<numComponents; j++) {
316      osgType tmp = ptr[j]*mul;
317      if (tmp > max)  tmp = max;
318      if (tmp < min)  tmp = min;
319      a[i] |= ivType(tmp) << (((numComponents-1)*8)-(j*8));
320    }
321  }
322
323  field.finishEditing();
324}
325
326
327template<typename fieldClass, typename fieldItemType>
328bool ivApplicateIntType(const osg::Array *array, fieldClass &field, int startIndex, int stopIndex, int numItemsUntilMinusOne)
329{
330  if (field.isOfType(fieldClass::getClassTypeId()))
331  {
332    switch (array->getType())
333    {
334      case osg::Array::ByteArrayType:   osgArray2ivMField_template<fieldClass, fieldItemType, int8_t>
335                                          (array, field, startIndex, stopIndex, numItemsUntilMinusOne); return true;
336      case osg::Array::UByteArrayType:  osgArray2ivMField_template<fieldClass, fieldItemType, uint8_t>
337                                          (array, field, startIndex, stopIndex, numItemsUntilMinusOne); return true;
338      case osg::Array::ShortArrayType:  osgArray2ivMField_template<fieldClass, fieldItemType, int16_t>
339                                          (array, field, startIndex, stopIndex, numItemsUntilMinusOne); return true;
340      case osg::Array::UShortArrayType: osgArray2ivMField_template<fieldClass, fieldItemType, uint16_t>
341                                          (array, field, startIndex, stopIndex, numItemsUntilMinusOne); return true;
342      case osg::Array::IntArrayType:    osgArray2ivMField_template<fieldClass, fieldItemType, int32_t>
343                                          (array, field, startIndex, stopIndex, numItemsUntilMinusOne); return true;
344      case osg::Array::UIntArrayType:   osgArray2ivMField_template<fieldClass, fieldItemType, uint32_t>
345                                          (array, field, startIndex, stopIndex, numItemsUntilMinusOne); return true;
346      case osg::Array::FloatArrayType:  osgArray2ivMField_template<fieldClass, fieldItemType, float>
347                                          (array, field, startIndex, stopIndex, numItemsUntilMinusOne); return true;
348      case osg::Array::Vec4bArrayType:  // FIXME: should signed values be handled differently? Like -128..127?
349      case osg::Array::Vec4ubArrayType: osgArray2ivMField_pack_template<fieldClass, fieldItemType, GLubyte, 4>
350                                          (array, field, 1, 255, 0, startIndex, stopIndex, numItemsUntilMinusOne); return true;
351      case osg::Array::Vec4ArrayType:   osgArray2ivMField_pack_template<fieldClass, fieldItemType, float, 4>
352                                          (array, field, 255.f, 255.f, 0.f, startIndex, stopIndex, numItemsUntilMinusOne); return true;
353      default: break;
354    }
355  }
356  return false;
357}
358
359
360static void osgArray2ivMField(const osg::Array *array, SoMField &field, int startIndex = 0, int stopIndex = 0, int numItemsUntilMinusOne = 0)
361{
362  if (field.isOfType(SoMFFloat::getClassTypeId()))
363  {
364    switch (array->getType())
365    {
366      case osg::Array::FloatArrayType:  osgArray2ivMField_template<SoMFFloat, float, float>
367                                          (array, (SoMFFloat&)field, startIndex, stopIndex, numItemsUntilMinusOne); return;
368      default: break;
369    }
370  }
371  else if (ivApplicateIntType<SoMFInt32,  int32_t>(array, (SoMFInt32&) field, startIndex, stopIndex, numItemsUntilMinusOne)) return;
372  else if (ivApplicateIntType<SoMFUInt32,uint32_t>(array, (SoMFUInt32&)field, startIndex, stopIndex, numItemsUntilMinusOne)) return;
373  else if (ivApplicateIntType<SoMFShort,  int16_t>(array, (SoMFShort&) field, startIndex, stopIndex, numItemsUntilMinusOne)) return;
374  else if (ivApplicateIntType<SoMFUShort,uint16_t>(array, (SoMFUShort&)field, startIndex, stopIndex, numItemsUntilMinusOne)) return;
375  else if (field.isOfType(SoMFVec2f::getClassTypeId()))
376  {
377    switch (array->getType())
378    {
379      case osg::Array::Vec2ArrayType:   osgArray2ivMField_composite_template<SoMFVec2f, SbVec2f, float, 2>
380                                          (array, (SoMFVec2f&)field, startIndex, stopIndex, numItemsUntilMinusOne); return;
381      default: break;
382    }
383  }
384  else if (field.isOfType(SoMFVec3f::getClassTypeId()))
385  {
386    switch (array->getType())
387    {
388      case osg::Array::Vec3ArrayType:   osgArray2ivMField_composite_template<SoMFVec3f, SbVec3f, float, 3>
389                                          (array, (SoMFVec3f&)field, startIndex, stopIndex, numItemsUntilMinusOne); return;
390      case osg::Array::Vec2ArrayType:   osgArray2ivMField_composite_template<SoMFVec3f, SbVec3f, float, 2>
391                                          (array, (SoMFVec3f&)field, startIndex, stopIndex, numItemsUntilMinusOne); return;
392      default: break;
393    }
394  }
395  else if (field.isOfType(SoMFVec4f::getClassTypeId()))
396  {
397    switch (array->getType()) {
398      case osg::Array::Vec4ArrayType:   osgArray2ivMField_composite_template<SoMFVec4f, SbVec4f, float, 4>
399                                          (array, (SoMFVec4f&)field, startIndex, stopIndex, numItemsUntilMinusOne); return;
400      default: break;
401    }
402  }
403  else if (field.isOfType(SoMFColor::getClassTypeId()))
404  {
405    switch (array->getType())
406    {
407      case osg::Array::Vec3ArrayType:   osgArray2ivMField_composite_template<SoMFColor, SbColor, float, 3>
408                                          (array, (SoMFColor&)field, startIndex, stopIndex, numItemsUntilMinusOne); return;
409      case osg::Array::Vec4ArrayType:   osgArray2ivMField_composite_template<SoMFColor, SbColor, float, 4>
410                                          (array, (SoMFColor&)field, startIndex, stopIndex, numItemsUntilMinusOne); return;
411      case osg::Array::Vec4ubArrayType: osgArray2ivMField_composite_template<SoMFColor, SbColor, GLubyte, 4>
412                                          (array, (SoMFColor&)field, startIndex, stopIndex, numItemsUntilMinusOne); return;
413      default: break;
414    }
415  };
416
417  OSG_WARN << "IvWriter: No direct conversion for array. "
418    << "The file may be broken." << std::endl;
419}
420
421
422template<typename variableType, typename indexType>
423bool ivDeindex(variableType *dest, const variableType *src, const int srcNum,
424                    const indexType *indices, const int numToProcess)
425{
426  for (int i=0; i<numToProcess; i++) {
427    int index = indices[i];
428    if (index<0 || index>=srcNum)  return false;
429    dest[i] = src[index];
430  }
431  return true;
432}
433
434
435template<typename variableType>
436bool ivDeindex(variableType *dest, const variableType *src, const int srcNum,
437                    const osg::Array *indices, const int numToProcess)
438{
439  if (int(indices->getNumElements()) < numToProcess) {
440    assert(0 && "Something is wrong: indices array is shorter than numToProcess.");
441    return false;
442  }
443
444  switch (indices->getType()) {
445  case osg::Array::ByteArrayType:
446  case osg::Array::UByteArrayType:
447      return ivDeindex<variableType, GLbyte>(dest, src, srcNum,
448                                           (GLbyte*)indices->getDataPointer(), numToProcess);
449      break;
450  case osg::Array::ShortArrayType:
451  case osg::Array::UShortArrayType:
452      return ivDeindex<variableType, GLshort>(dest, src, srcNum,
453                                            (GLshort*)indices->getDataPointer(), numToProcess);
454      break;
455  case osg::Array::IntArrayType:
456  case osg::Array::UIntArrayType:
457      return ivDeindex<variableType, GLint>(dest, src, srcNum,
458                                          (GLint*)indices->getDataPointer(), numToProcess);
459      break;
460  default:
461      assert(0 && "Index of strange type.");
462      return false;
463  }
464}
465
466
467template<typename variableType, typename fieldType>
468bool ivProcessArray(const osg::Array *drawElemIndices,
469                         fieldType *destField, const fieldType *srcField,
470                         int startIndex, int numToProcess)
471{
472  bool ok = true;
473
474  if (drawElemIndices) {
475
476    // "deindex" original data
477    ok = ivDeindex<variableType>(destField->startEditing(),
478                                srcField->getValues(startIndex),
479                                srcField->getNum(), drawElemIndices, numToProcess);
480
481    destField->finishEditing();
482    if (!ok)
483      OSG_WARN << "IvWriter: Can not deindex - bug in model: index out of range." << std::endl;
484
485  } else {
486
487    // copy required part of original data
488    const variableType *src = srcField->getValues(startIndex);
489    assert(startIndex+numToProcess <= srcField->getNum() && "Index out of bounds.");
490    variableType *dest = destField->startEditing();
491    for (int i=0; i<numToProcess; i++)
492      *(dest++) = *(src++);
493    destField->finishEditing();
494  }
495
496  return ok;
497}
498
499
500static void processIndices(const osg::Array *drawElemIndices,
501                           SoMFInt32 &ivIndices,
502                           int startIndex, int stopIndex, int numItemsUntilMinusOne)
503{
504  if (drawElemIndices) {
505
506      osgArray2ivMField(drawElemIndices, ivIndices, startIndex, stopIndex, numItemsUntilMinusOne);
507
508  } else {
509
510    int num = stopIndex-startIndex;
511    if (numItemsUntilMinusOne != 0 && num >= 1)
512      num += (num-1)/numItemsUntilMinusOne;
513    ivIndices.setNum(num);
514    int32_t *a = ivIndices.startEditing();
515    if (numItemsUntilMinusOne <= 0)
516      for (int i=0,j=startIndex; j<stopIndex; i++,j++)
517        a[i] = j;
518    else
519      for (int i=0,j=startIndex,k=0; j<stopIndex; i++)
520        if (k==numItemsUntilMinusOne) {
521          a[i]=-1;
522          k=0;
523        } else {
524          a[i] = j;
525          j++;
526          k++;
527        }
528    ivIndices.finishEditing();
529  }
530}
531
532
533static void postProcessDrawArrayLengths(const osg::DrawArrayLengths *drawArrayLengths, SoMFInt32 *field)
534{
535  int origNum = field->getNum();
536  int newNum = origNum + drawArrayLengths->size()-1;
537  field->setNum(newNum);
538  int32_t *a = field->startEditing();
539  int32_t *src = a + origNum;
540  int32_t *dst = a + newNum;
541  for (osg::DrawArrayLengths::const_reverse_iterator primItr = drawArrayLengths->rbegin();
542      primItr!=drawArrayLengths->rend()-1;
543      ++primItr) {
544    int c = *primItr;
545    src -= c;
546    dst -= c;
547    memmove(dst, src, sizeof(int32_t)*c);
548    dst--;
549    *dst = -1;
550  }
551  field->finishEditing();
552}
553
554
555static void postProcessField(const SbIntList &runLengths, osg::PrimitiveSet::Mode primType,
556                             SoMFInt32 *field, deprecated_osg::Geometry::AttributeBinding binding)
557{
558  if (binding==deprecated_osg::Geometry::BIND_OFF || binding==deprecated_osg::Geometry::BIND_OVERALL ||
559      binding==deprecated_osg::Geometry::BIND_PER_PRIMITIVE_SET)
560    return;
561
562  // make copy of array
563  const int32_t *fieldArray = field->getValues(0);
564  int origNum = field->getNum();
565  int32_t *tmpArray = new int32_t[origNum];
566  memcpy(tmpArray, fieldArray, origNum*sizeof(int32_t));
567
568  // compute new number of indices
569  int newNum = origNum;
570  const int l = runLengths.getLength();
571  switch (binding) {
572    case deprecated_osg::Geometry::BIND_PER_VERTEX:
573      for (int i=0; i<l; i++)
574        newNum += (runLengths[i]-3)*3;
575      break;
576    case deprecated_osg::Geometry::BIND_PER_PRIMITIVE:
577      for (int i=0; i<l; i++)
578        newNum += runLengths[i]-3;
579      break;
580    default:
581      assert(0);
582  }
583
584  // process indices
585  field->setNum(newNum);
586  int32_t *src = tmpArray;
587  int32_t *dst = field->startEditing();
588  // int32_t *dst2 = dst;
589  switch (binding) {
590    case deprecated_osg::Geometry::BIND_PER_VERTEX:
591      for (int i=0; i<l; i++) {
592        int c = runLengths[i];
593        *(dst++) = *(src++);
594        *(dst++) = *(src++);
595        *(dst++) = *(src++);
596        bool even = true;
597        int32_t first = *(src-3);
598        for (int j=3; j<c; j++) {
599          *(dst++) = -1;
600          if (primType==osg::PrimitiveSet::TRIANGLE_STRIP) {
601            if (even) {
602              *(dst++) = *(src-1);
603              *(dst++) = *(src-2);
604            } else {
605              *(dst++) = *(src-2);
606              *(dst++) = *(src-1);
607            }
608            even = !even;
609          } else
610          if (primType==osg::PrimitiveSet::TRIANGLE_FAN) {
611            *(dst++) = first;
612            *(dst++) = *(src-1);
613          } // FIXME: are QUADS, QUAD_STRIP, and POLYGON requiring some handling here as well? PCJohn-2007-08-25
614          else {
615            *(dst++) = *(src-2);
616            *(dst++) = *(src-1);
617          }
618          *(dst++) = *(src++);
619        }
620        src++; // skip -1
621        if (i != l-1)
622          *(dst++) = -1;
623      }
624      break;
625
626    case deprecated_osg::Geometry::BIND_PER_PRIMITIVE:
627      for (int i=0; i<l; i++,src++) {
628        int c = runLengths[i];
629        *(dst++) = *(src);
630        for (int j=3; j<c; j++)
631          *(dst++) = *(src);
632      }
633      break;
634
635    default:
636      assert(0);
637  }
638  field->finishEditing();
639
640  // free resources
641  delete [] tmpArray;
642}
643
644
645static void postProcessTriangleSeparation(SoIndexedShape *shape, osg::PrimitiveSet::Mode primType,
646                                          deprecated_osg::Geometry::AttributeBinding normalBinding,
647                                          deprecated_osg::Geometry::AttributeBinding colorBinding)
648{
649  // compute runLengths
650  SbIntList runLengths;
651  const int32_t *a = shape->coordIndex.getValues(0);
652  int origNum = shape->coordIndex.getNum();
653  int l = 0;
654  for (int i=0; i<origNum; i++,a++) {
655    if (*a == -1) {
656      runLengths.append(l);
657      l = 0;
658    } else
659      l++;
660  }
661  if (l != 0) // append final l if field is not finished by -1
662    runLengths.append(l);
663
664  postProcessField(runLengths, primType, &shape->coordIndex,        deprecated_osg::Geometry::BIND_PER_VERTEX);
665  postProcessField(runLengths, primType, &shape->normalIndex,       normalBinding);
666  postProcessField(runLengths, primType, &shape->materialIndex,     colorBinding);
667  bool notUseTexCoords = shape->textureCoordIndex.getNum()==0 ||
668                         (shape->textureCoordIndex.getNum()==1 && shape->textureCoordIndex[0] == -1);
669  if (!notUseTexCoords)
670    postProcessField(runLengths, primType, &shape->textureCoordIndex, deprecated_osg::Geometry::BIND_PER_VERTEX);
671
672}
673
674
675static SoMaterialBinding* createMaterialBinding(const deprecated_osg::Geometry *g, bool isMaterialIndexed)
676{
677  SoMaterialBinding *materialBinding = new SoMaterialBinding;
678  switch (g->getColorBinding()) {
679  case deprecated_osg::Geometry::BIND_OFF: // OFF means use material from state set (if any) for whole geometry
680  case deprecated_osg::Geometry::BIND_OVERALL:
681  case deprecated_osg::Geometry::BIND_PER_PRIMITIVE_SET: materialBinding->value = SoMaterialBinding::OVERALL; break;
682  case deprecated_osg::Geometry::BIND_PER_PRIMITIVE:     materialBinding->value = (isMaterialIndexed) ? SoMaterialBinding::PER_PART_INDEXED   : SoMaterialBinding::PER_PART; break;
683  case deprecated_osg::Geometry::BIND_PER_VERTEX:        materialBinding->value = (isMaterialIndexed) ? SoMaterialBinding::PER_VERTEX_INDEXED : SoMaterialBinding::PER_VERTEX; break;
684  default: assert(0);
685  }
686  return materialBinding;
687}
688
689
690static SoNormalBinding* createNormalBinding(const deprecated_osg::Geometry *g, bool areNormalsIndexed)
691{
692  // Convert normal binding
693  SoNormalBinding *normalBinding = new SoNormalBinding;
694  switch (g->getNormalBinding()) {
695  case deprecated_osg::Geometry::BIND_OFF: // FIXME: what to do with BIND_OFF value?
696  case deprecated_osg::Geometry::BIND_OVERALL:
697  case deprecated_osg::Geometry::BIND_PER_PRIMITIVE_SET: normalBinding->value = SoNormalBinding::OVERALL; break;
698  case deprecated_osg::Geometry::BIND_PER_PRIMITIVE:     normalBinding->value = (areNormalsIndexed) ? SoNormalBinding::PER_PART_INDEXED   : SoNormalBinding::PER_PART; break;
699  case deprecated_osg::Geometry::BIND_PER_VERTEX:        normalBinding->value = (areNormalsIndexed) ? SoNormalBinding::PER_VERTEX_INDEXED : SoNormalBinding::PER_VERTEX; break;
700  default: assert(0);
701  }
702  return normalBinding;
703}
704
705
706static SoTextureCoordinateBinding* createTexCoordBinding(SbBool useIndexing)
707{
708  SoTextureCoordinateBinding *b = new SoTextureCoordinateBinding;
709  b->value.setValue(useIndexing ? SoTextureCoordinateBinding::PER_VERTEX_INDEXED :
710                    SoTextureCoordinateBinding::PER_VERTEX);
711  return b;
712}
713
714
715static SoTexture2::Model convertTexEnvMode(osg::TexEnv::Mode osgMode, bool useIvExtensions)
716{
717  switch (osgMode) {
718  case GL_MODULATE: return SoTexture2::MODULATE;
719  case GL_REPLACEreturn (SoTexture2::Model)(useIvExtensions ? GL_REPLACE : GL_MODULATE);
720  case GL_BLEND:    return SoTexture2::BLEND;
721  case GL_DECAL:    return SoTexture2::DECAL;
722  default: assert(0); return SoTexture2::MODULATE;
723  }
724}
725
726
727
728static SoTexture2::Wrap convertTextureWrap(osg::Texture::WrapMode osgWrap)
729{
730  // notes on support of CLAMP_TO_BORDER, CLAMP_TO_EDGE, and MIRRORED_REPEAT:
731  // original SGI Inventor: no
732  // Coin: no (until current version Coin 2.5.0b3)
733  // TGS Inventor: introduced in TGS Inventor 5.0 (available in SoTexture class)
734
735  // note: Coin (since 2.0) uses CLAMP_TO_EDGE for rendering if SoTexture2::CLAMP is specified.
736
737  switch (osgWrap) {
738    case osg::Texture::CLAMP:
739    case osg::Texture::CLAMP_TO_BORDER:
740    case osg::Texture::CLAMP_TO_EDGE: return SoTexture2::CLAMP;
741    case osg::Texture::REPEAT:
742    case osg::Texture::MIRROR: return SoTexture2::REPEAT;
743    default: assert(0); return SoTexture2::REPEAT;
744  }
745}
746
747
748static void setSoTransform(SoTransform *tr, const osg::Vec3 &translation, const osg::Quat &rotation,
749                           const osg::Vec3 &scale = osg::Vec3(1.,1.,1.))
750{
751  tr->translation.setValue(translation.ptr());
752  tr->rotation.setValue(rotation.x(), rotation.y(), rotation.z(), rotation.w());
753  tr->scaleFactor.setValue(scale.ptr());
754  //tr->scaleCenter.setValue(osg::Vec3f(node.getPivotPoint())); <- testing required on this line
755}
756
757
758static bool updateMode(bool &flag, const osg::StateAttribute::GLModeValue value)
759{
760  if (value & osg::StateAttribute::INHERIT)  return flag;
761  else  return (flag = (value & osg::StateAttribute::ON));
762}
763
764
765ConvertToInventor::InventorState* ConvertToInventor::createInventorState(const osg::StateSet *ss)
766{
767  // Push on stack
768  const InventorState *ivPrevState = &ivStack.top();
769  ivStack.push(*ivPrevState);
770  InventorState *ivState = &ivStack.top();
771
772  // Inventor graph
773  ivState->ivHead = new SoSeparator;
774  ivPrevState->ivHead->addChild(ivState->ivHead);
775
776  if (ss) {
777
778    //
779    // Lighting
780    //
781
782    // enable/disable lighting
783    updateMode(ivState->osgLighting, ss->getMode(GL_LIGHTING));
784    if (ivState->osgLighting != ivPrevState->osgLighting) {
785      SoLightModel *lm = new SoLightModel;
786      lm->model = (ivState->osgLighting) ? SoLightModel::PHONG : SoLightModel::BASE_COLOR;
787      ivState->ivHead->addChild(lm);
788    }
789
790    // two-sided lighting
791    const osg::LightModel *osgLM = dynamic_cast<const osg::LightModel*>(ss->getAttribute(osg::StateAttribute::LIGHTMODEL));
792    if (osgLM)
793      ivState->osgTwoSided = osgLM->getTwoSided();
794
795    // front face
796    const osg::FrontFace *osgFF = dynamic_cast<const osg::FrontFace*>(ss->getAttribute(osg::StateAttribute::FRONTFACE));
797    if (osgFF)
798      ivState->osgFrontFace = osgFF->getMode();
799
800    // face culling
801    updateMode(ivState->osgCullFaceEnabled, ss->getMode(GL_CULL_FACE));
802    const osg::CullFace *osgCF = dynamic_cast<const osg::CullFace*>(ss->getAttribute(osg::StateAttribute::CULLFACE));
803    if (osgCF)
804      ivState->osgCullFace = osgCF->getMode();
805
806    // detect state change
807    if (ivState->osgTwoSided != ivPrevState->osgTwoSided ||
808        ivState->osgFrontFace != ivPrevState->osgFrontFace ||
809        ivState->osgCullFaceEnabled != ivPrevState->osgCullFaceEnabled ||
810        ivState->osgCullFace != ivPrevState->osgCullFace) {
811
812      // new SoShapeHints
813      SoShapeHints *sh = new SoShapeHints;
814      if (ivState->osgTwoSided) {
815        // warn if face culling is on
816        if (ivState->osgCullFaceEnabled)
817          OSG_WARN << "IvWriter: Using face culling and two-sided lighting together! "
818                                    "Ignoring face culling." << std::endl;
819
820        // set two-sided lighting and backface culling off
821        sh->vertexOrdering = ivState->osgFrontFace==osg::FrontFace::COUNTER_CLOCKWISE ?
822                             SoShapeHints::COUNTERCLOCKWISE : SoShapeHints::CLOCKWISE;
823        sh->shapeType = SoShapeHints::UNKNOWN_SHAPE_TYPE;
824      }
825      else {
826        // set one-sided lighting and backface optionally
827        if (ivState->osgCullFaceEnabled) {
828
829          // determine vertex ordering
830          bool ccw = ivState->osgFrontFace==osg::FrontFace::COUNTER_CLOCKWISE;
831          if (ivState->osgCullFace != osg::CullFace::BACK)  ccw = !ccw;
832
833          if (ccw)
834            // Warn if culling the lit faces while rendering unlit faces.
835            // Inventor does not support this setup and it lits the unculled faces only.
836            OSG_WARN << "IvWriter: Culling was set in a way that one-sided lighting will lit the culled sides of faces. "
837                                      "Using lighting on correct faces." << std::endl;
838
839          // face culling on
840          sh->vertexOrdering = ccw ? SoShapeHints::COUNTERCLOCKWISE : SoShapeHints::CLOCKWISE;
841          sh->shapeType = SoShapeHints::SOLID;
842        }
843        else
844          // no face culling
845          sh->shapeType = SoShapeHints::UNKNOWN_SHAPE_TYPE;
846      }
847      ivState->ivHead->addChild(sh);
848    }
849
850    //
851    // Texturing
852    //
853    // FIXME: handle 1D and 3D textures
854
855    // get OSG state
856    ivState->osgTexture = dynamic_cast<const osg::Texture*>(ss->getTextureAttribute(0, osg::StateAttribute::TEXTURE));
857    ivState->osgTexEnv = dynamic_cast<const osg::TexEnv*>(ss->getTextureAttribute(0, osg::StateAttribute::TEXENV));
858    updateMode(ivState->osgTexture2Enabled, ss->getTextureMode(0, GL_TEXTURE_2D));
859
860    // detect state changes
861    if (ivState->osgTexture2Enabled != ivPrevState->osgTexture2Enabled ||
862        ivState->osgTexture != ivPrevState->osgTexture ||
863        ivState->osgTexEnv != ivPrevState->osgTexEnv) {
864
865      if (!ivState->osgTexture2Enabled ||
866          ivState->osgTexture==NULL || ivState->osgTexture->getImage(0)==NULL)
867
868        // empty texture disables texturing
869        ivState->ivTexture = new SoTexture2;
870
871      else {
872
873        // reuse texture if possible
874        ivState->ivTexture = ivTexturesMap[ivState->osgTexture][ivState->osgTexEnv];
875
876        // if nothing for reusing, create new
877        if (!ivState->ivTexture) {
878
879          // create texture
880          ivState->ivTexture = new SoTexture2;
881          ivTexturesMap[ivState->osgTexture][ivState->osgTexEnv] = ivState->ivTexture;
882
883          // texture file name
884          const std::string &textureName = ivState->osgTexture->getImage(0)->getFileName();
885          ivState->ivTexture->filename.setValue(textureName.c_str()); // FIXME: handle inlined texture data in the files
886
887          // wrap
888          ivState->ivTexture->wrapS.setValue(convertTextureWrap(
889                                             ivState->osgTexture->getWrap(osg::Texture::WRAP_S)));
890          ivState->ivTexture->wrapT.setValue(convertTextureWrap(
891                                             ivState->osgTexture->getWrap(osg::Texture::WRAP_T)));
892
893          // texture environment
894          if (ivState->osgTexEnv) {
895            ivState->ivTexture->model.setValue(convertTexEnvMode(
896                                               ivState->osgTexEnv->getMode(), useIvExtensions));
897            osg::Vec4 color = ivState->osgTexEnv->getColor();
898            ivState->ivTexture->blendColor.setValue(color.r(), color.g(), color.b());
899          }
900
901          // notes on support of borderColor and borderWidth:
902          // original SGI Inventor: no
903          // Coin: no (until current version 2.5.0b3)
904          // TGS Inventor: introduced in version 5.0 (as SoTexture::borderColor)
905
906          // FIXME: implement support for texture filtering
907        }
908      }
909    }
910
911    // Texture coordinate generation
912    updateMode(ivState->osgTexGenS, ss->getTextureMode(0, GL_TEXTURE_GEN_S));
913    updateMode(ivState->osgTexGenT, ss->getTextureMode(0, GL_TEXTURE_GEN_T));
914    ivState->osgTexGen = dynamic_cast<const osg::TexGen*>(ss->getTextureAttribute(0, osg::StateAttribute::TEXGEN));
915
916    // Material parameters
917    const osg::Material *osgMaterial = dynamic_cast<const osg::Material*>(ss->getAttribute(osg::StateAttribute::MATERIAL));
918    if (osgMaterial)
919      ivState->osgMaterial = osgMaterial;
920
921    if (ivState->osgMaterial != ivPrevState->osgMaterial) {
922
923      ivState->ivMaterial = new SoMaterial;
924      assert(ivState->osgMaterial);
925
926      // Warn if using two side materials
927      // FIXME: The geometry can be probably doubled, or some estimation can be made
928      // whether only front or back faces are used.
929      if (ivState->osgMaterial->getAmbientFrontAndBack() == false ||
930          ivState->osgMaterial->getDiffuseFrontAndBack() == false ||
931          ivState->osgMaterial->getSpecularFrontAndBack() == false ||
932          ivState->osgMaterial->getEmissionFrontAndBack() == false ||
933          ivState->osgMaterial->getShininessFrontAndBack() == false)
934      {
935        OSG_WARN << "IvWriter: Model contains different materials for front and "
936                                  "back faces. This is not handled properly. Using front material only." << std::endl;
937      }
938
939      // Convert colors
940      // OSG represents colors by: Vec3, Vec4,Vec4ub
941      // Inventor by: uint32 (RGBA, by SoPackedColor), SbColor (Vec3f, by SoMaterial and SoBaseColor)
942      // note: Inventor can use DIFFUSE component inside a shape only. Material is set for whole shape.
943      // Although SoMaterial is used only, SoPackedColor may bring some possibilities on per-vertex
944      // alpha and SoBaseColor may be useful on pre-lit scene.
945      if (ivState->osgMaterial->getColorMode() != osg::Material::DIFFUSE &&
946          ivState->osgMaterial->getColorMode() != osg::Material::OFF)
947      {
948
949        if (ivState->osgMaterial->getColorMode() == osg::Material::AMBIENT_AND_DIFFUSE)
950        {
951            OSG_WARN << "IvWriter: The model is using AMBIENT_AND_DIFFUSE material "
952                                    "mode while Inventor supports DIFFUSE mode only. "
953                                    "The model colors may not much exactly." << std::endl;
954        }
955        else
956        {
957            OSG_WARN << "IvWriter: The model is not using DIFFUSE material mode and "
958                                    "Inventor supports DIFFUSE mode only. "
959                                    "The model colors may not be correct." << std::endl;
960        }
961      }
962
963      // Convert material components
964      // FIXME: Transparency can be specified for each component in OSG
965      // and just globally in Inventor.
966      // Solutions? It can be averaged or just diffuse can be used.
967      ((SoMaterial*)ivState->ivMaterial)->ambientColor.setValue(osgMaterial->getAmbient(
968        osgMaterial->getAmbientFrontAndBack()   ? osg::Material::FRONT_AND_BACK : osg::Material::FRONT).ptr());
969      ((SoMaterial*)ivState->ivMaterial)->diffuseColor.setValue(osgMaterial->getDiffuse(
970        osgMaterial->getDiffuseFrontAndBack()   ? osg::Material::FRONT_AND_BACK : osg::Material::FRONT).ptr());
971      ((SoMaterial*)ivState->ivMaterial)->specularColor.setValue(osgMaterial->getSpecular(
972        osgMaterial->getSpecularFrontAndBack()  ? osg::Material::FRONT_AND_BACK : osg::Material::FRONT).ptr());
973      ((SoMaterial*)ivState->ivMaterial)->emissiveColor.setValue(osgMaterial->getEmission(
974        osgMaterial->getEmissionFrontAndBack()  ? osg::Material::FRONT_AND_BACK : osg::Material::FRONT).ptr());
975      ((SoMaterial*)ivState->ivMaterial)->shininess.setValue(osgMaterial->getShininess(
976        osgMaterial->getShininessFrontAndBack() ? osg::Material::FRONT_AND_BACK : osg::Material::FRONT));
977      ((SoMaterial*)ivState->ivMaterial)->transparency.setValue(1.f - osgMaterial->getDiffuse(
978        osgMaterial->getDiffuseFrontAndBack()   ? osg::Material::FRONT_AND_BACK : osg::Material::FRONT).a());
979    }
980
981    // note on "headlight":
982    // OSG is using HEADLIGHT or SKY_LIGHT. In both cases it sets these defaults:
983    // osg::LightModel::ambientIntensity(0.1, 0.1, 0.1, 1.0);
984    // osg::Light::num(0)
985    // osg::Light::ambient(0,0,0,1)
986    // osg::Light::diffuse(0.8,0.8,0.8, 1)
987    // osg::Light::specular(1,1,1,1)
988    //
989    // Inventor uses different settings:
990    // SoEnvironment::ambientIntensity(0.2)
991    // SoEnvironment::ambientColor(1,1,1)
992    // SoDirectionalLight::intensity(1)
993    // SoDirectionalLight::color(1,1,1)
994    //
995    // note on Inventor light handling:
996    // ambient is set to 0,0,0,1
997    // diffuse to color*intensity
998    // specular to color*intensity
999
1000
1001  #ifdef __COIN__
1002    //
1003    // Handle transparency
1004    //
1005    // OSG supports GL_BLEND and GL_ALPHA_TEST
1006    // Related classes: BlendFunc, BlendEquation, BlendColor, AlphaFunc
1007    //
1008    // Inventor is more difficult and not so robust. According to Inventor 2.1 standard,
1009    // just SoMaterial::transparency, SoTexture2 with alpha channel carry transparency information
1010    // that is controlled by SoGLRenderAction::transparency type that is set to SCREEN_DOOR by default
1011    // (dither pattern). So, if the user does not select better transparency type, there is no
1012    // possiblity to control transparency type from file format.
1013    //
1014    // However, SoTransparencyType node was introduced to overcome this historical limitation
1015    // because transparency was performance expensive long time ago.
1016    // Support by different Inventor branches:
1017    //
1018    // SGI Inventor: no
1019    // Coin: since 2.0
1020    // TGS Inventor: since 5.0
1021    //
1022    // Alpha test was introduced in TGS 4.0, but as SoGLRenderArea::setAlphaTest. So, no direct
1023    // control in the file format.
1024    //
1025    // Conclusion:
1026    // - Alpha test is not supported and all pixels will be drawn
1027    // - Blending - current strategy is following:
1028    //     ADD x BLEND - ADD is used if destination-blending-factor is GL_ONE
1029    //     DELAYED rendering is used if transparency bin is used by OSG
1030    //     SORTED_OBJECT is used if ...
1031    //
1032
1033    updateMode(ivState->osgBlendEnabled, ss->getMode(GL_BLEND));
1034    ivState->osgBlendFunc = dynamic_cast<const osg::BlendFunc*>(ss->getAttribute(osg::StateAttribute::BLENDFUNC));
1035
1036    if (useIvExtensions)
1037      if (ivState->osgBlendEnabled != ivPrevState->osgBlendEnabled ||
1038          ivState->osgBlendFunc != ivPrevState->osgBlendFunc ||
1039          (ivState->osgBlendFunc && ivPrevState->osgBlendFunc &&
1040          ivState->osgBlendFunc->getDestinationRGB() != ivPrevState->osgBlendFunc->getDestinationRGB())) {
1041
1042        const SoTransparencyType::Type transparencyTable[8] = {
1043          SoTransparencyType::BLEND,         SoTransparencyType::ADD,
1044          SoTransparencyType::DELAYED_BLEND, SoTransparencyType::DELAYED_ADD,
1045          // FIXME: add sorted modes and test previous four
1046        };
1047
1048        int index = 0;
1049        if (!ivState->osgBlendFunc)  index |= 0;
1050        else  index = (ivState->osgBlendFunc->getDestinationRGB() == osg::BlendFunc::ONE) ? 1 : 0;
1051        index |= (ss->getRenderingHint() == osg::StateSet::TRANSPARENT_BIN) ? 2 : 0;
1052
1053        SoTransparencyType *ivTransparencyType = new SoTransparencyType;
1054        ivTransparencyType->value = transparencyTable[index];
1055        ivState->ivHead->addChild(ivTransparencyType);
1056      }
1057  #endif
1058
1059  }
1060
1061  // ref Inventor nodes that are required when processing Drawables
1062  if (ivState->ivTexture)
1063    ivState->ivTexture->ref();
1064  if (ivState->ivMaterial)
1065    ivState->ivMaterial->ref();
1066
1067  return ivState;
1068}
1069
1070
1071void ConvertToInventor::popInventorState()
1072{
1073  InventorState *ivState = &ivStack.top();
1074
1075  // unref Inventor nodes
1076  if (ivState->ivTexture)
1077    ivState->ivTexture->unref();
1078  if (ivState->ivMaterial)
1079    ivState->ivMaterial->unref();
1080
1081  ivStack.pop();
1082}
1083
1084
1085static bool processPrimitiveSet(const deprecated_osg::Geometry *g, const osg::PrimitiveSet *pset,
1086                                osg::UIntArray *drawElemIndices, bool needSeparateTriangles,
1087                                int elementsCount, int primSize, const int startIndex, int stopIndex,
1088                                int &normalIndex, int &colorIndex,
1089                                SoNode *ivCoords, SoNormal *ivNormals, SoNode *ivMaterial,
1090                                SoNode *ivTexCoords, SoNode *ivTexture, SoShape *shape,
1091                                SoSeparator *&indexedRoot, SoSeparator *&nonIndexedRoot)
1092{
1093  bool ok = true;
1094  const osg::DrawArrayLengths *drawArrayLengths =
1095    (elementsCount == -1) ? dynamic_cast<const osg::DrawArrayLengths*>(pset) : NULL;
1096
1097  int drawArrayLengthsElems = 0;
1098
1099  if (drawArrayLengths) {
1100
1101    // compute elementsCount
1102    elementsCount = 0;
1103    drawArrayLengthsElems = 0;
1104    for (osg::DrawArrayLengths::const_iterator primItr=drawArrayLengths->begin();
1105        primItr!=drawArrayLengths->end();
1106        ++primItr, drawArrayLengthsElems++)
1107      elementsCount += *primItr;
1108
1109    // update stopIndex
1110    stopIndex = startIndex + elementsCount;
1111  }
1112
1113  // NonIndexed data for nonIndexed shapes
1114  SoNode *nonIndexedCoords = NULL;
1115  SoNode *nonIndexedTexCoords = NULL;
1116  SoNormal *nonIndexedNormals = NULL;
1117  SoNode *nonIndexedMaterial = NULL;
1118
1119  // Normal indexing
1120  int normalStart = (g->getNormalBinding() == deprecated_osg::Geometry::BIND_PER_VERTEX) ? startIndex : normalIndex;
1121  int numNormalsUsed = 0;
1122  switch (g->getNormalBinding()) {
1123  case deprecated_osg::Geometry::BIND_OFF: // FIXME: what is meaning of OFF value?
1124  case deprecated_osg::Geometry::BIND_OVERALL:           numNormalsUsed = 0; break;
1125  case deprecated_osg::Geometry::BIND_PER_PRIMITIVE_SET: numNormalsUsed = 1; break;
1126  case deprecated_osg::Geometry::BIND_PER_PRIMITIVE:     numNormalsUsed = primSize!=0 ? (stopIndex-startIndex)/primSize :
1127                                                (drawArrayLengths ? drawArrayLengths->size() : 1); break;
1128  case deprecated_osg::Geometry::BIND_PER_VERTEX:        numNormalsUsed = stopIndex-startIndex; break;
1129  }
1130  normalIndex += numNormalsUsed;
1131
1132  // Color indexing
1133  int colorStart = g->getColorBinding() == deprecated_osg::Geometry::BIND_PER_VERTEX ? startIndex : colorIndex;
1134  int numColorsUsed = 0;
1135  switch (g->getColorBinding()) {
1136  case deprecated_osg::Geometry::BIND_OFF:
1137  case deprecated_osg::Geometry::BIND_OVERALL:           numColorsUsed = 0; break;
1138  case deprecated_osg::Geometry::BIND_PER_PRIMITIVE_SET: numColorsUsed = 1; break;
1139  case deprecated_osg::Geometry::BIND_PER_PRIMITIVE:     numColorsUsed = primSize!=0 ? (stopIndex-startIndex)/primSize :
1140                                                (drawArrayLengths ? drawArrayLengths->size() : 1); break;
1141  case deprecated_osg::Geometry::BIND_PER_VERTEX:        numColorsUsed = stopIndex-startIndex; break;
1142  }
1143  colorIndex += numColorsUsed;
1144
1145  if (shape->isOfType(SoIndexedShape::getClassTypeId())) {
1146
1147    // Convert to SoIndexedShape
1148    processIndices(drawElemIndices, ((SoIndexedShape*)shape)->coordIndex,
1149                   startIndex, stopIndex, primSize);
1150
1151    if (ivNormals)
1152      processIndices(drawElemIndices, ((SoIndexedShape*)shape)->normalIndex,
1153                     normalStart, normalStart+(numNormalsUsed==0 ? 1 : numNormalsUsed),
1154                     g->getNormalBinding()==deprecated_osg::Geometry::BIND_PER_VERTEX ? primSize : 0);
1155
1156    if (ivMaterial)
1157      processIndices(drawElemIndices, ((SoIndexedShape*)shape)->materialIndex,
1158                     colorStart, colorStart+(numColorsUsed==0 ? 1 : numColorsUsed),
1159                     g->getColorBinding()==deprecated_osg::Geometry::BIND_PER_VERTEX ? primSize : 0);
1160
1161    if (ivTexCoords && !ivTexCoords->isOfType(SoTextureCoordinateFunction::getClassTypeId()))
1162      processIndices(drawElemIndices, ((SoIndexedShape*)shape)->textureCoordIndex,
1163                     startIndex, stopIndex, primSize);
1164
1165    // Post-processing for DrawArrayLengths
1166    if (drawArrayLengths && primSize==0 && drawArrayLengths->size()>=2) {
1167
1168      postProcessDrawArrayLengths(drawArrayLengths, &((SoIndexedShape*)shape)->coordIndex);
1169
1170      if (ivNormals && g->getNormalBinding()==deprecated_osg::Geometry::BIND_PER_VERTEX)
1171        postProcessDrawArrayLengths(drawArrayLengths, &((SoIndexedShape*)shape)->normalIndex);
1172
1173      if (ivMaterial && g->getColorBinding()==deprecated_osg::Geometry::BIND_PER_VERTEX)
1174        postProcessDrawArrayLengths(drawArrayLengths, &((SoIndexedShape*)shape)->materialIndex);
1175
1176      if (ivTexCoords && !ivTexCoords->isOfType(SoTextureCoordinateFunction::getClassTypeId()))
1177        postProcessDrawArrayLengths(drawArrayLengths, &((SoIndexedShape*)shape)->textureCoordIndex);
1178    }
1179
1180    if (needSeparateTriangles)
1181      postProcessTriangleSeparation((SoIndexedShape*)shape, (osg::PrimitiveSet::Mode)pset->getMode(),
1182                                    g->getNormalBinding(), g->getColorBinding());
1183
1184  } else {
1185
1186    // Convert to SoNonIndexedShape
1187
1188    assert(shape->isOfType(SoNonIndexedShape::getClassTypeId()) && "Shape must be non-indexed.");
1189
1190    int i,n = stopIndex-startIndex;
1191
1192    // create alternate coordinates
1193    if (ivCoords->isOfType(SoCoordinate4::getClassTypeId()))
1194    {
1195      nonIndexedCoords = new SoCoordinate4;
1196      if (ok) {
1197        ((SoCoordinate4*)nonIndexedCoords)->point.setNum(n);
1198        ok = ivProcessArray<SbVec4f,SoMFVec4f>(drawElemIndices,
1199                                             &((SoCoordinate4*)nonIndexedCoords)->point,
1200                                             &((SoCoordinate4*)ivCoords)->point,
1201                                             startIndex, n);
1202      }
1203    } else {
1204      nonIndexedCoords = new SoCoordinate3;
1205      if (ok) {
1206        ((SoCoordinate3*)nonIndexedCoords)->point.setNum(n);
1207        ok = ivProcessArray<SbVec3f,SoMFVec3f>(drawElemIndices,
1208                                             &((SoCoordinate3*)nonIndexedCoords)->point,
1209                                             &((SoCoordinate3*)ivCoords)->point,
1210                                             startIndex, n);
1211      }
1212    }
1213
1214    // create alternate texture coordinates
1215    if (ivTexCoords)
1216    {
1217      if (ivTexCoords->isOfType(SoTextureCoordinate2::getClassTypeId()))
1218      {
1219        nonIndexedTexCoords = new SoTextureCoordinate2;
1220        if (ok)
1221        {
1222          ((SoTextureCoordinate2*)nonIndexedTexCoords)->point.setNum(n);
1223          ok = ivProcessArray<SbVec2f,SoMFVec2f>(drawElemIndices,
1224                                               &((SoTextureCoordinate2*)nonIndexedTexCoords)->point,
1225                                               &((SoTextureCoordinate2*)ivTexCoords)->point,
1226                                               startIndex, n);
1227        }
1228      } else
1229#ifdef __COIN__
1230      if (ivTexCoords->isOfType(SoTextureCoordinate3::getClassTypeId()))
1231      {
1232        nonIndexedTexCoords = new SoTextureCoordinate3;
1233        if (ok)
1234        {
1235          ((SoTextureCoordinate3*)nonIndexedTexCoords)->point.setNum(n);
1236          ok = ivProcessArray<SbVec3f,SoMFVec3f>(drawElemIndices,
1237                                               &((SoTextureCoordinate3*)nonIndexedTexCoords)->point,
1238                                               &((SoTextureCoordinate3*)ivCoords)->point,
1239                                               startIndex, n);
1240        }
1241      }
1242      else
1243#endif  // __COIN__
1244        nonIndexedTexCoords = ivTexCoords;
1245    }
1246
1247    // create alternate normals
1248    if (ivNormals) {
1249      nonIndexedNormals = new SoNormal;
1250      if (ok) {
1251        nonIndexedNormals->vector.setNum(numNormalsUsed==0 ? 1 : numNormalsUsed);
1252        ok = ivProcessArray<SbVec3f,SoMFVec3f>(g->getNormalBinding()==deprecated_osg::Geometry::BIND_PER_VERTEX ? drawElemIndices : NULL,
1253                                             &nonIndexedNormals->vector, &ivNormals->vector,
1254                                             normalStart, numNormalsUsed==0 ? 1 : numNormalsUsed);
1255      }
1256    }
1257
1258    // create alternate material
1259    if (ivMaterial) {
1260      SoMFColor *dstColorField;
1261      if (ivMaterial->isOfType(SoMaterial::getClassTypeId())) {
1262        nonIndexedMaterial = new SoMaterial;
1263        dstColorField = &((SoMaterial*)nonIndexedMaterial)->diffuseColor;
1264      } else {
1265        nonIndexedMaterial = new SoBaseColor;
1266        dstColorField = &((SoBaseColor*)nonIndexedMaterial)->rgb;
1267      }
1268      if (ok) {
1269        // FIXME: diffuse only?
1270        SoMFColor *srcColorField = (ivMaterial->isOfType(SoMaterial::getClassTypeId())) ?
1271                                   &((SoMaterial*)ivMaterial)->diffuseColor :
1272                                   &((SoBaseColor*)ivMaterial)->rgb;
1273        dstColorField->setNum(numColorsUsed==0 ? 1 : numColorsUsed);
1274        ok = ivProcessArray<SbColor,SoMFColor>(g->getColorBinding()==deprecated_osg::Geometry::BIND_PER_VERTEX ? drawElemIndices : NULL,
1275                                            dstColorField, srcColorField,
1276                                            colorStart, numColorsUsed==0 ? 1 : numColorsUsed);
1277      }
1278    }
1279
1280    if (shape->isOfType(SoPointSet::getClassTypeId()))
1281      ((SoPointSet*)shape)->numPoints.setValue(elementsCount); else
1282
1283    if (shape->isOfType(SoLineSet::getClassTypeId())) {
1284      switch (pset->getMode()) {
1285      case GL_LINES:
1286          assert(elementsCount % 2 == 0 && "elementsCount is not multiple of 2.");
1287          n = elementsCount/2;
1288          ((SoLineSet*)shape)->numVertices.setNum(n);
1289          for (i=0; i<n; i++)
1290            ((SoLineSet*)shape)->numVertices.set1Value(i, 2);
1291          break;
1292      case GL_LINE_STRIP:
1293          if (drawArrayLengths) {
1294            ((SoLineSet*)shape)->numVertices.setNum(drawArrayLengthsElems);
1295            int i=0;
1296            for (osg::DrawArrayLengths::const_iterator primItr=drawArrayLengths->begin();
1297                primItr!=drawArrayLengths->end();
1298                ++primItr, i++)
1299              ((SoLineSet*)shape)->numVertices.set1Value(i, *primItr);
1300          } else {
1301            ((SoLineSet*)shape)->numVertices.setNum(1);
1302            ((SoLineSet*)shape)->numVertices.set1Value(0, elementsCount);
1303          }
1304          break;
1305      default:
1306          OSG_WARN << "IvWriter: NOT IMPLEMENTED" << std::endl;
1307          assert(0);
1308      }
1309    } else
1310
1311    if (shape->isOfType(SoTriangleStripSet::getClassTypeId())) {
1312      switch (pset->getMode()) {
1313      case GL_TRIANGLES:
1314          n = elementsCount/3;
1315          assert(n*3 == elementsCount && "elementsCount is not multiple of 3.");
1316          ((SoTriangleStripSet*)shape)->numVertices.setNum(n);
1317          for (i=0; i<n; i++)
1318            ((SoTriangleStripSet*)shape)->numVertices.set1Value(i, 3);
1319          break;
1320      case GL_TRIANGLE_STRIP:
1321          if (drawArrayLengths) {
1322            ((SoTriangleStripSet*)shape)->numVertices.setNum(drawArrayLengthsElems);
1323            int i=0;
1324            for (osg::DrawArrayLengths::const_iterator primItr=drawArrayLengths->begin();
1325                primItr!=drawArrayLengths->end();
1326                ++primItr, i++)
1327              ((SoTriangleStripSet*)shape)->numVertices.set1Value(i, *primItr);
1328          } else {
1329            ((SoTriangleStripSet*)shape)->numVertices.setNum(1);
1330            ((SoTriangleStripSet*)shape)->numVertices.set1Value(0, elementsCount);
1331          }
1332          break;
1333      case GL_TRIANGLE_FAN:
1334          OSG_WARN << "IvWriter: GL_TRIANGLE_FAN NOT IMPLEMENTED" << std::endl;
1335          ((SoTriangleStripSet*)shape)->numVertices.setNum(1);
1336          ((SoTriangleStripSet*)shape)->numVertices.set1Value(0, elementsCount);
1337          break;
1338      case GL_QUAD_STRIP:
1339          assert(elementsCount % 2 == 0 && "elementsCount is not multiple of 2.");
1340          if (drawArrayLengths) {
1341            ((SoTriangleStripSet*)shape)->numVertices.setNum(drawArrayLengthsElems);
1342            int i=0;
1343            for (osg::DrawArrayLengths::const_iterator primItr=drawArrayLengths->begin();
1344                primItr!=drawArrayLengths->end();
1345                ++primItr, i++)
1346              ((SoTriangleStripSet*)shape)->numVertices.set1Value(i, *primItr);
1347          } else {
1348            ((SoTriangleStripSet*)shape)->numVertices.setNum(1);
1349            ((SoTriangleStripSet*)shape)->numVertices.set1Value(0, elementsCount);
1350          }
1351          break;
1352      default:
1353          OSG_WARN << "IvWriter: NOT IMPLEMENTED" << std::endl;
1354          assert(0);
1355      }
1356    } else
1357
1358    if (shape->isOfType(SoFaceSet::getClassTypeId())) {
1359      switch (pset->getMode()) {
1360      case GL_QUADS:
1361          n = elementsCount/4;
1362          assert(n*4 == elementsCount && "elementsCount is not multiple of 4.");
1363          ((SoFaceSet*)shape)->numVertices.setNum(n);
1364          for (i=0; i<n; i++)
1365            ((SoFaceSet*)shape)->numVertices.set1Value(i, 4);
1366          break;
1367      case GL_POLYGON:
1368          if (drawArrayLengths) {
1369            ((SoFaceSet*)shape)->numVertices.setNum(drawArrayLengthsElems);
1370            int i=0;
1371            for (osg::DrawArrayLengths::const_iterator primItr=drawArrayLengths->begin();
1372                primItr!=drawArrayLengths->end();
1373                ++primItr, i++)
1374              ((SoFaceSet*)shape)->numVertices.set1Value(i, *primItr);
1375          } else {
1376            ((SoFaceSet*)shape)->numVertices.setNum(1);
1377            ((SoFaceSet*)shape)->numVertices.set1Value(0, elementsCount);
1378          }
1379          break;
1380      default:
1381          OSG_WARN << "IvWriter: NOT IMPLEMENTED" << std::endl;
1382          assert(0);
1383      }
1384    } else {
1385      OSG_WARN << "IvWriter: NOT IMPLEMENTED" << std::endl;
1386      assert(0 && "Unknown non-indexed shape type.");
1387    }
1388  }
1389
1390  // Construct graph
1391
1392  // Each osg::Drawable will have its own SoSeparator (render caching, culling, etc.)
1393  SoSeparator *sep = new SoSeparator;
1394  if (nonIndexedCoords) {
1395    assert(shape->isOfType(SoNonIndexedShape::getClassTypeId()) && "Not nonIndexed shape.");
1396
1397    if (!ok) {
1398
1399      // handle errors
1400      nonIndexedCoords->ref();
1401      nonIndexedCoords->unref();
1402      if (nonIndexedTexCoords) { nonIndexedTexCoords->ref(); nonIndexedTexCoords->unref(); }
1403      if (nonIndexedNormals) { nonIndexedNormals->ref(); nonIndexedNormals->unref(); }
1404      nonIndexedMaterial->ref();
1405      nonIndexedMaterial->unref();
1406      shape->ref();
1407      shape->unref();
1408      sep->ref();
1409      sep->unref();
1410    } else {
1411
1412      // make scene graph
1413      if (nonIndexedRoot == NULL) {
1414        nonIndexedRoot = new SoSeparator;
1415        if (ivTexture)  nonIndexedRoot->addChild(ivTexture);
1416        if (ivTexture)  nonIndexedRoot->addChild(createTexCoordBinding(FALSE));
1417        nonIndexedRoot->addChild(createMaterialBinding(g, FALSE));
1418        if (ivNormals)  nonIndexedRoot->addChild(createNormalBinding(g, FALSE));
1419      }
1420      if (nonIndexedMaterial)  sep->addChild(nonIndexedMaterial);
1421      sep->addChild(nonIndexedCoords);
1422      if (nonIndexedNormals)  sep->addChild(nonIndexedNormals);
1423      if (nonIndexedTexCoords)  sep->addChild(nonIndexedTexCoords);
1424      sep->addChild(shape);
1425      nonIndexedRoot->addChild(sep);
1426    }
1427  } else {
1428    assert(shape->isOfType(SoIndexedShape::getClassTypeId()) && "Not indexed shape.");
1429    assert(nonIndexedCoords==NULL && nonIndexedNormals==NULL && nonIndexedMaterial==NULL);
1430    if (indexedRoot == NULL) {
1431      indexedRoot = new SoSeparator;
1432      if (ivTexture)  indexedRoot->addChild(ivTexture);
1433      if (ivTexture)  indexedRoot->addChild(createTexCoordBinding(TRUE));
1434      if (ivMaterial)  indexedRoot->addChild(ivMaterial);
1435      indexedRoot->addChild(createMaterialBinding(g, TRUE));
1436      indexedRoot->addChild(ivCoords);
1437      if (ivNormals)  indexedRoot->addChild(ivNormals);
1438      if (ivNormals)  indexedRoot->addChild(createNormalBinding(g, TRUE));
1439      if (ivTexCoords)  indexedRoot->addChild(ivTexCoords);
1440    }
1441    sep->addChild(shape);
1442    indexedRoot->addChild(sep);
1443  }
1444
1445  return ok;
1446}
1447
1448
1449void ConvertToInventor::processGeometry(const deprecated_osg::Geometry *g, InventorState *ivState)
1450{
1451  int normalIndex = 0;
1452  int colorIndex = 0;
1453
1454  // Inventor scene graph roots
1455  SoSeparator *indexedRoot = NULL;
1456  SoSeparator *nonIndexedRoot = NULL;
1457
1458  // Active material
1459  SoMaterial *ivStateMaterial = ivState->ivMaterial;
1460  SoNode *ivMaterial = NULL;
1461  if (ivState->osgLighting || vrml1Conversion)
1462    // SoMaterial
1463    if (g->getColorArray())
1464      if (ivStateMaterial)  ivMaterial = ivStateMaterial->copy();
1465      else  ivMaterial = new SoMaterial; // FIXME: check default values of SoMaterial and OSG lighting
1466    else
1467      if (ivStateMaterial)  ivMaterial = ivStateMaterial;
1468      else  ivMaterial = NULL;
1469  else
1470    // SoBaseColor
1471    if (g->getColorArray())
1472      if (ivStateMaterial) {
1473        ivMaterial = new SoBaseColor;
1474        ((SoBaseColor*)ivMaterial)->rgb.setValue(ivStateMaterial->diffuseColor[0]); // copy first value
1475      } else
1476        ivMaterial = new SoBaseColor; // FIXME: check default values of SoBaseColor and OSG pre-lit scene
1477    else
1478      if (ivStateMaterial) {
1479        ivMaterial = new SoBaseColor;
1480        ((SoBaseColor*)ivMaterial)->rgb.setValue(ivStateMaterial->diffuseColor[0]); // copy first value
1481      } else
1482        ivMaterial = NULL;
1483
1484  // Convert color array into the SoMaterial
1485  if (g->getColorArray()) {
1486    assert(ivMaterial);
1487
1488    // Choose correct color field
1489    SoMFColor *colorField;
1490    if (ivMaterial->isOfType(SoMaterial::getClassTypeId())) {
1491      if (vrml1Conversion && ivState->osgLighting==false) {
1492
1493        // special case of pre-lit VRML1 scene
1494        ((SoMaterial*)ivMaterial)->ambientColor.setValue(0.f,0.f,0.f);
1495        ((SoMaterial*)ivMaterial)->diffuseColor.setValue(0.f,0.f,0.f);
1496        ((SoMaterial*)ivMaterial)->specularColor.setValue(0.f,0.f,0.f);
1497        colorField = &((SoMaterial*)ivMaterial)->emissiveColor;
1498      } else
1499        // regular diffuse color
1500        colorField = &((SoMaterial*)ivMaterial)->diffuseColor;
1501    } else
1502      // Using of SoBaseColor
1503      colorField = &((SoBaseColor*)ivMaterial)->rgb;
1504
1505
1506    // Color array with material
1507    if (ivState->osgMaterial == NULL ||
1508        ivState->osgMaterial->getColorMode() == osg::Material::DIFFUSE ||
1509        ivState->osgMaterial->getColorMode() == osg::Material::AMBIENT_AND_DIFFUSE)
1510      osgArray2ivMField(g->getColorArray(), *colorField);
1511    else; // FIXME: implement some workaround for non-diffuse cases?
1512          // note: Warning was already shown in createInventorState().
1513          // note2: There is no effect to convert SoMaterial::[ambient|specular|emissive]color
1514          // here because Inventor does not set them per-vertex (performance reasons). See
1515          // Inventor documentation for more details.
1516  }
1517
1518
1519  // Convert coordinates
1520  // OSG represents coordinates by: Vec2, Vec3, Vec4
1521  // Inventor by: SbVec3f, SbVec4f
1522  SoNode *coords;
1523  if (g->getVertexArray()->getDataSize() == 4) {
1524    coords = new SoCoordinate4;
1525    osgArray2ivMField(g->getVertexArray(), ((SoCoordinate4*)coords)->point);
1526  } else {
1527    coords = new SoCoordinate3;
1528    osgArray2ivMField(g->getVertexArray(), ((SoCoordinate3*)coords)->point);
1529  }
1530  coords->ref();
1531
1532  // Convert texture coordinates
1533  SoNode *texCoords = NULL;
1534  if (ivState->ivTexture) {
1535    if (ivState->osgTexGenS && ivState->osgTexGenT &&
1536        ivState->osgTexGen && ivState->osgTexGen->getMode()==osg::TexGen::SPHERE_MAP)
1537      texCoords = new SoTextureCoordinateEnvironment;
1538    else
1539    if (g->getTexCoordArray(0)) {
1540      if (g->getTexCoordArray(0)->getDataSize() <= 2) {
1541        texCoords = new SoTextureCoordinate2;
1542        osgArray2ivMField(g->getTexCoordArray(0), ((SoTextureCoordinate2*)texCoords)->point);
1543      }
1544#ifdef __COIN__
1545      else {
1546        texCoords = new SoTextureCoordinate3;
1547        osgArray2ivMField(g->getTexCoordArray(0), ((SoTextureCoordinate3*)texCoords)->point);
1548      }
1549#endif   // __COIN__
1550    }
1551    if (texCoords)
1552      texCoords->ref();
1553  }
1554
1555  // Convert normals
1556  // OSG represents normals by: Vec3,Vec3s,Vec3b
1557  // and can handle: Vec4s,Vec4b by truncating them to three components
1558  // Inventor by: SbVec3f
1559  SoNormal *normals = NULL;
1560  if (g->getNormalArray()) {
1561    normals = new SoNormal;
1562    osgArray2ivMField(g->getNormalArray(), normals->vector);
1563    normals->ref();
1564  }
1565
1566  // Convert osg::PrimitiveSets to Inventor's SoShapes
1567  int psetIndex,numPsets = g->getNumPrimitiveSets();
1568  for (psetIndex=0; psetIndex<numPsets; psetIndex++) {
1569
1570    // Get PrimitiveSet
1571    const osg::PrimitiveSet *pset = g->getPrimitiveSet(psetIndex);
1572    osg::PrimitiveSet::Type type = pset->getType();
1573    GLenum mode = pset->getMode();
1574
1575    // Create appropriate SoShape
1576    bool useIndices = vrml1Conversion;
1577    bool needSeparateTriangles = false;
1578    SoVertexShape *shape = NULL;
1579    switch (mode) {
1580      case GL_POINTS:         shape = new SoPointSet; break;
1581      case GL_LINES:
1582      case GL_LINE_STRIP:
1583      case GL_LINE_LOOP:      if (useIndices) shape = new SoIndexedLineSet;
1584                              else shape = new SoLineSet;
1585                              break;
1586      case GL_TRIANGLES:
1587      case GL_TRIANGLE_STRIP:
1588      case GL_QUAD_STRIP:     if (useIndices)
1589                                if (vrml1Conversion) {
1590                                  shape = new SoIndexedFaceSet;
1591                                  needSeparateTriangles = true;
1592                                } else
1593                                  shape = new SoIndexedTriangleStripSet;
1594                              else
1595                                shape = new SoTriangleStripSet;
1596                              break;
1597      case GL_TRIANGLE_FAN:   needSeparateTriangles = true;
1598                              shape = (vrml1Conversion) ? (SoVertexShape*)new SoIndexedFaceSet :
1599                                                          new SoIndexedTriangleStripSet;
1600                              break;
1601      case GL_QUADS:
1602      case GL_POLYGON:        if (useIndices) shape = new SoIndexedFaceSet;
1603                              else shape = new SoFaceSet;
1604                              break;
1605      default: assert(0);
1606    }
1607
1608    // Size of single geometric primitive
1609    int primSize;
1610    switch (mode) {
1611    case GL_LINES:          primSize = 2; break;
1612    case GL_TRIANGLES:      primSize = 3; break;
1613    case GL_QUADS:          primSize = 4; break;
1614    default: primSize = 0;
1615    };
1616
1617
1618    bool ok = true;
1619
1620    switch (type) {
1621
1622      case osg::PrimitiveSet::DrawArraysPrimitiveType:
1623      {
1624        const osg::DrawArrays *drawArrays = dynamic_cast<const osg::DrawArrays*>(pset);
1625
1626        int startIndex = drawArrays->getFirst();
1627        int stopIndex = startIndex + drawArrays->getCount();
1628
1629        // FIXME: Am I using startIndex for all bundles that are PER_VERTEX?
1630        ok = processPrimitiveSet(g, pset, NULL, needSeparateTriangles,
1631                                  drawArrays->getCount(), primSize,
1632                                  startIndex, stopIndex, normalIndex, colorIndex,
1633                                  coords, normals, ivMaterial, texCoords,
1634                                  ivState->ivTexture, shape, indexedRoot, nonIndexedRoot);
1635        if (!ok)
1636        {
1637            OSG_WARN<<"Inventor plugin, ConvertToInventor processPrimitiveSet() failed."<<std::endl;
1638        }
1639        break;
1640      }
1641
1642      case osg::PrimitiveSet::DrawArrayLengthsPrimitiveType:
1643      {
1644        const osg::DrawArrayLengths *drawArrayLengths =
1645          dynamic_cast<const osg::DrawArrayLengths*>(pset);
1646
1647        int startIndex = drawArrayLengths->getFirst();
1648
1649        ok = processPrimitiveSet(g, pset, NULL, needSeparateTriangles,
1650                                  -1, primSize, startIndex, -1, normalIndex, colorIndex,
1651                                  coords, normals, ivMaterial, texCoords,
1652                                  ivState->ivTexture, shape, indexedRoot, nonIndexedRoot);
1653        if (!ok)
1654        {
1655            OSG_WARN<<"Inventor plugin, ConvertToInventor processPrimitiveSet() failed."<<std::endl;
1656        }
1657
1658        break;
1659      }
1660
1661      case osg::PrimitiveSet::DrawElementsUBytePrimitiveType:
1662      case osg::PrimitiveSet::DrawElementsUShortPrimitiveType:
1663      case osg::PrimitiveSet::DrawElementsUIntPrimitiveType:
1664      {
1665        osg::ref_ptr<osg::UIntArray> drawElemIndices = new osg::UIntArray;
1666
1667        switch (type) {
1668        case osg::PrimitiveSet::DrawElementsUBytePrimitiveType:
1669          {
1670            const osg::DrawElementsUByte *drawElements =
1671              dynamic_cast<const osg::DrawElementsUByte*>(pset);
1672            for(osg::DrawElementsUByte::const_iterator primItr = drawElements->begin();
1673                primItr!=drawElements->end();
1674                ++primItr)
1675              drawElemIndices->push_back(*primItr);
1676            break;
1677          }
1678        case osg::PrimitiveSet::DrawElementsUShortPrimitiveType:
1679          {
1680            const osg::DrawElementsUShort *drawElements =
1681              dynamic_cast<const osg::DrawElementsUShort*>(pset);
1682            for(osg::DrawElementsUShort::const_iterator primItr = drawElements->begin();
1683                primItr!=drawElements->end();
1684                ++primItr)
1685              drawElemIndices->push_back(*primItr);
1686            break;
1687          }
1688        case osg::PrimitiveSet::DrawElementsUIntPrimitiveType:
1689          {
1690            const osg::DrawElementsUInt *drawElements =
1691              dynamic_cast<const osg::DrawElementsUInt*>(pset);
1692            for(osg::DrawElementsUInt::const_iterator primItr = drawElements->begin();
1693                primItr!=drawElements->end();
1694                ++primItr)
1695              drawElemIndices->push_back(*primItr);
1696            break;
1697          }
1698        default: assert(0);
1699        }
1700
1701        ok = processPrimitiveSet(g, pset, drawElemIndices.get(), needSeparateTriangles,
1702                                  drawElemIndices->getNumElements(), primSize,
1703                                  0, drawElemIndices->getNumElements(), normalIndex, colorIndex,
1704                                  coords, normals, ivMaterial, texCoords,
1705                                  ivState->ivTexture, shape, indexedRoot, nonIndexedRoot);
1706        if (!ok)
1707        {
1708            OSG_WARN<<"Inventor plugin, ConvertToInventor processPrimitiveSet() failed."<<std::endl;
1709        }
1710        break;
1711      }
1712
1713      default:
1714        OSG_WARN << "IvWriter: NOT IMPLEMENTED" << std::endl;
1715    }
1716  }
1717
1718  if (indexedRoot)  ivState->ivHead->addChild(indexedRoot);
1719  if (nonIndexedRoot)  ivState->ivHead->addChild(nonIndexedRoot);
1720
1721  coords->unref();
1722  if (texCoords)  texCoords->unref();
1723  if (normals)  normals->unref();
1724}
1725
1726
1727void ConvertToInventor::processShapeDrawable(const osg::ShapeDrawable *d, InventorState *ivState)
1728{
1729  // visitor for converting ShapeDrawables
1730  class MyShapeVisitor : public osg::ConstShapeVisitor {
1731  public:
1732    void processNode(SoNode *ivNode, const osg::Vec3& center, osg::Quat rotation,
1733                      SoGroup *root) {
1734      // convert rotation
1735      rotation = osg::Quat(-M_PI_2, osg::Vec3(0.,1.,0.)) * osg::Quat(M_PI_2, osg::Vec3(1.,0.,0.)) * rotation;
1736
1737      if (center.length2()==0. && rotation.zeroRotation() && ivState->ivTexture==NULL)
1738
1739        // optimized handling of single node
1740        root->addChild(ivNode);
1741
1742      else {
1743        SoSeparator *root2 = new SoSeparator;
1744
1745        // handle transformation
1746        if (center.length2()!=0. || !rotation.zeroRotation()) {
1747          SoTransform *ivTransform = new SoTransform;
1748          setSoTransform(ivTransform, center, rotation);
1749          root2->addChild(ivTransform);
1750        }
1751
1752        // handle texture
1753        if (ivState->ivTexture)
1754          root2->addChild(ivState->ivTexture);
1755
1756        // build graph
1757        root2->addChild(ivNode);
1758        root->addChild(root2);
1759      }
1760    }
1761
1762    virtual void apply(const osg::Sphere &s) {
1763      SoSphere *ivSphere = new SoSphere;
1764      ivSphere->radius.setValue(s.getRadius());
1765      processNode(ivSphere, s.getCenter(), osg::Quat(0., osg::Vec3(1.,0.,0.)), ivState->ivHead);
1766    }
1767    virtual void apply(const osg::Box &b) {
1768      SoCube *ivCube = new SoCube;
1769      ivCube->width  = 2 * b.getHalfLengths().y();
1770      ivCube->height = 2 * b.getHalfLengths().z();
1771      ivCube->depth  = 2 * b.getHalfLengths().x();
1772      processNode(ivCube, b.getCenter(), b.getRotation(), ivState->ivHead);
1773    }
1774    virtual void apply(const osg::Cone &c) {
1775      SoCone *ivCone = new SoCone;
1776      ivCone->bottomRadius = c.getRadius();
1777      ivCone->height = c.getHeight();
1778      osg::Vec3 newCenter(c.getCenter());
1779      newCenter.ptr()[2] -= c.getBaseOffset();
1780      processNode(ivCone, newCenter, c.getRotation(), ivState->ivHead);
1781    }
1782    virtual void apply(const osg::Cylinder &c) {
1783      SoCylinder *ivCylinder = new SoCylinder;
1784      ivCylinder->radius = c.getRadius();
1785      ivCylinder->height = c.getHeight();
1786      processNode(ivCylinder, c.getCenter(), c.getRotation(), ivState->ivHead);
1787    }
1788
1789    void warnNonSupported() {
1790      OSG_WARN << "IvWriter: Not supported ShapeDrawable found. Skipping it." << std::endl;
1791    }
1792    virtual void apply(const osg::Capsule&)        { warnNonSupported(); }
1793    virtual void apply(const osg::InfinitePlane&)  { warnNonSupported(); }
1794    virtual void apply(const osg::TriangleMesh&)   { warnNonSupported(); }
1795    virtual void apply(const osg::ConvexHull&)     { warnNonSupported(); }
1796    virtual void apply(const osg::HeightField&)    { warnNonSupported(); }
1797    virtual void apply(const osg::CompositeShape&) { warnNonSupported(); }
1798
1799    InventorState *ivState;
1800    MyShapeVisitor(InventorState *ivState) { this->ivState = ivState; }
1801  } shapeVisitor(ivState);
1802
1803  // convert ShapeDrawable
1804  const osg::Shape *shape = d->getShape();
1805  if (shape)
1806    shape->accept(shapeVisitor);
1807}
1808
1809
1810void ConvertToInventor::processDrawable(osg::Drawable *d)
1811{
1812  deprecated_osg::Geometry *g = dynamic_cast<deprecated_osg::Geometry*>(d); // FIXME: other drawables have to be handled also
1813  osg::ShapeDrawable *sd = 0;
1814
1815  // Create SoSeparator and convert StateSet for Drawable
1816  InventorState *ivDrawableState = createInventorState(d->getStateSet());
1817
1818  if (g != NULL)
1819    processGeometry(g, ivDrawableState);
1820  else
1821
1822  if ((sd = dynamic_cast<osg::ShapeDrawable*>(d)) != NULL) {
1823    processShapeDrawable(sd, ivDrawableState);
1824  }
1825  else
1826    OSG_WARN << "IvWriter: Unsupported drawable found: \"" << d->className() <<
1827                              "\". Skipping it." << std::endl;
1828
1829  // Restore state
1830  popInventorState();
1831}
1832
1833
1834void ConvertToInventor::apply(osg::Geode &node)
1835{
1836#ifdef DEBUG_IV_WRITER
1837  OSG_INFO << "IvWriter: Geode traversed" << std::endl;
1838#endif
1839
1840  // Create SoSeparator and convert StateSet for Geode
1841  /*InventorState *ivGeodeState = */createInventorState(node.getStateSet());
1842
1843  // Convert drawables
1844  const int numDrawables = node.getNumDrawables();
1845  for (int i=0; i<numDrawables; i++)
1846    processDrawable(node.getDrawable(i));
1847
1848  traverse(node);
1849
1850  // Restore state
1851  popInventorState();
1852}
1853
1854
1855void ConvertToInventor::apply(osg::Group &node)
1856{
1857#ifdef DEBUG_IV_WRITER
1858  OSG_INFO << "IvWriter: Group traversed" << std::endl;
1859#endif
1860
1861  // Create SoSeparator and convert StateSet
1862  /*InventorState *ivState = */createInventorState(node.getStateSet());
1863
1864  traverse(node);
1865
1866  popInventorState();
1867}
1868
1869
1870void ConvertToInventor::apply(osg::Billboard& node)
1871{
1872#ifdef DEBUG_IV_WRITER
1873  OSG_INFO << "IvWriter: Billboard traversed" << std::endl;
1874#endif
1875
1876#ifdef __COIN__
1877
1878  if (useIvExtensions) {
1879
1880    // Create SoSeparator and convert StateSet
1881    InventorState *ivState = createInventorState(node.getStateSet());
1882    SoGroup *root = ivState->ivHead;
1883
1884    // Process drawables
1885    const int numDrawables = node.getNumDrawables();
1886    for (int i=0; i<numDrawables; i++) {
1887
1888      SoVRMLBillboard *billboard = new SoVRMLBillboard;
1889
1890      // SoVRMLBillboard is VRML 2.0 node supported by Coin (?since 2.0?)
1891      // However, I am seeing bug in my Coin 2.4.5 so that if
1892      // SoVRMLBillboard::axisOfRotation is not 0,0,0, the billboard behaviour is strange.
1893      // As long as it is set to 0,0,0, POINT_ROT_EYE-style billboard works perfectly.
1894      // AXIAL_ROT seems not possible with the bug. And POINT_ROT_WORLD was not
1895      // investigated by me until now.
1896      // There is also billboard culling bug in Coin, so the billboards may not be
1897      // rendered properly from time to time. PCJohn-2007-09-08
1898    #if 0
1899      SbVec3f axis;
1900      switch (node.getMode()) {
1901        case osg::Billboard::POINT_ROT_EYE:   axis = SbVec3f(0.f,0.f,0.f); break;
1902        case osg::Billboard::POINT_ROT_WORLD: axis = SbVec3f(0.f,0.f,0.f); break;
1903        case osg::Billboard::AXIAL_ROT:       axis = node.getAxis().ptr(); break;
1904        default:
1905          axis = SbVec3f(0.f,0.f,0.f);
1906      };
1907      billboard->axisOfRotation.setValue(axis);
1908    #else
1909
1910      billboard->axisOfRotation.setValue(SbVec3f(0.f,0.f,0.f));
1911
1912    #endif
1913
1914      SoTranslation *translation = new SoTranslation;
1915      translation->translation.setValue(node.getPosition(i).ptr());
1916
1917      // Rotate billboard correctly (OSG->IV conversion)
1918      // Note: use SoTransform instead of SoRotation because SoRotation is not supported by VRML1.
1919      SoTransform *transform = new SoTransform;
1920      transform->rotation = SbRotation(SbVec3f(1.f,0.f,0.f), float(-M_PI_2));
1921
1922      SoSeparator *separator = new SoSeparator;
1923      separator->addChild(translation);
1924      separator->addChild(billboard);
1925      billboard->addChild(transform);
1926
1927      root->addChild(separator);
1928      ivState->ivHead = billboard;
1929
1930      processDrawable(node.getDrawable(i));
1931
1932      traverse((osg::Node&)node);
1933    }
1934
1935    popInventorState();
1936
1937  } else
1938    apply((osg::Geode&)node);
1939
1940#else
1941
1942  apply((osg::Geode&)node);
1943
1944#endif
1945}
1946
1947
1948void ConvertToInventor::apply(osg::MatrixTransform& node)
1949{
1950#ifdef DEBUG_IV_WRITER
1951  OSG_INFO << "IvWriter: MatrixTransform traversed" << std::endl;
1952#endif
1953
1954  // Convert matrix
1955  SoMatrixTransform *ivTransform = new SoMatrixTransform;
1956  SbMatrix ivMatrix;
1957  const osg::Matrix::value_type *src = node.getMatrix().ptr();
1958  float *dest = ivMatrix[0];
1959  for (int i=0; i<16; i++,dest++,src++)
1960    *dest = *src;
1961  ivTransform->matrix.setValue(ivMatrix);
1962
1963  // Create SoSeparator and convert StateSet
1964  InventorState *ivState = createInventorState(node.getStateSet());
1965  ivState->ivHead->addChild(ivTransform);
1966
1967  traverse((osg::Node&)node);
1968
1969  popInventorState();
1970}
1971
1972
1973void ConvertToInventor::apply(osg::PositionAttitudeTransform& node)
1974{
1975#ifdef DEBUG_IV_WRITER
1976  OSG_INFO << "IvWriter: PositionAttitudeTransform traversed" << std::endl;
1977#endif
1978
1979  // Convert matrix
1980  SoTransform *ivTransform = new SoTransform;
1981  setSoTransform(ivTransform, node.getPosition(), node.getAttitude(), node.getScale());
1982
1983  // Create SoSeparator and convert StateSet
1984  InventorState *ivState = createInventorState(node.getStateSet());
1985  ivState->ivHead->addChild(ivTransform);
1986
1987  traverse((osg::Node&)node);
1988
1989  popInventorState();
1990}
1991
1992
1993void ConvertToInventor::apply(osg::LOD& node)
1994{
1995#ifdef DEBUG_IV_WRITER
1996  OSG_INFO << "IvWriter: LOD traversed" << std::endl;
1997#endif
1998
1999  // Convert LOD
2000  SoGroup *ivLOD = NULL;
2001  osg::LOD::RangeMode rangeMode = node.getRangeMode();
2002  if (rangeMode == osg::LOD::DISTANCE_FROM_EYE_POINT) {
2003
2004    // use SoLOD for DISTANCE_FROM_EYE_POINT
2005    SoLOD *lod = new SoLOD;
2006
2007    // copy ranges
2008    int i,c=node.getNumRanges();
2009    for (i=0; i<c; i++)
2010       lod->range.set1Value(i, node.getMaxRange(i));
2011
2012    // set center
2013    osg::Vec3f center(node.getCenter());
2014    lod->center.setValue(center.ptr());
2015
2016    ivLOD = lod;
2017
2018  } else
2019  if (rangeMode == osg::LOD::PIXEL_SIZE_ON_SCREEN) {
2020
2021    // use SoLevelOfDetail for PIXEL_SIZE_ON_SCREEN
2022    SoLevelOfDetail *lod = new SoLevelOfDetail;
2023
2024    // copy ranges
2025    int i,c=node.getNumRanges();
2026    for (i=0; i<c; i++)
2027       lod->screenArea.set1Value(i, node.getMaxRange(i));
2028
2029    ivLOD = lod;
2030
2031  } else {
2032
2033    // undefined mode -> put warning
2034    OSG_WARN << "IvWriter: Undefined LOD::RangeMode value." << std::endl;
2035    ivLOD = new SoGroup;
2036  }
2037
2038  // Create SoSeparator and convert StateSet
2039  InventorState *ivState = createInventorState(node.getStateSet());
2040  ivState->ivHead->addChild(ivLOD);
2041  ivState->ivHead = ivLOD;
2042
2043  traverse((osg::Node&)node);
2044
2045  popInventorState();
2046}
Note: See TracBrowser for help on using the browser.