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

Revision 9414, 77.4 kB (checked in by robert, 6 years ago)

Fixed compile error during debug build

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) {
239        a[i] = -1;
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;
1923      transform->rotation = SbRotation(SbVec3f(1.f,0.f,0.f), -M_PI_2);
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.