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

Revision 11032, 77.4 kB (checked in by robert, 5 years ago)

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

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

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

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