1 /*---------------------------------------------------------------------------*\
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
32 * 2002/10/16: added transparency path. Thanks to Franck Sourdin *
33 * (sourdin@ai.cluny.ensam.fr) for it! *
38 \*---------------------------------------------------------------------------*/
40 //-------------------------------
42 //-------------------------------
47 #include "OSGConfig.h"
58 #include "OSGGeometry.h"
59 #include "OSGTypedGeoVectorProperty.h"
60 #include "OSGTypedGeoIntegralProperty.h"
61 #include "OSGGeoFunctions.h"
62 #include "OSGSimpleTexturedMaterial.h"
63 #include "OSGImageFileHandler.h"
64 #include "OSGPathHandler.h"
66 #include "OSGSceneFileHandler.h"
67 #include "OSGTriangleIterator.h"
69 #include "OSGOBJSceneFileType.h"
74 /*! \class OSG::OBJSceneFileType
75 \ingroup GrpSystemFileIO
79 #if defined(OSG_WIN32_ICL) && !defined(OSG_CHECK_FIELDSETARG)
80 #pragma warning (disable : 383)
83 /*****************************
85 *****************************/
86 // Static Class Varible implementations:
87 const Char8
*OBJSceneFileType::_suffixA
[] = { "obj" };
89 OBJSceneFileType
OBJSceneFileType::_the(_suffixA
,
93 (SceneFileType::OSG_READ_SUPPORTED
|
94 SceneFileType::OSG_WRITE_SUPPORTED
));
96 /*****************************
98 *****************************/
101 /********************************
103 *******************************/
106 /*******************************
108 *******************************/
110 //----------------------------
111 // Function name: read
112 //----------------------------
115 //p: Scene &image, const char *fileName
125 //d: read the image from the given file
129 //------------------------------
130 NodeTransitPtr
OBJSceneFileType::read( std::istream
&is
,
134 NodeUnrecPtr rootPtr
, nodePtr
;
136 std::map
<std::string
, DataElem
>::const_iterator elemI
;
141 GeoPnt3fPropertyUnrecPtr coordPtr
= GeoPnt3fProperty::create();
142 GeoVec2fPropertyUnrecPtr texCoordPtr
= GeoVec2fProperty::create();
143 GeoVec3fPropertyUnrecPtr normalPtr
= GeoVec3fProperty::create();
144 GeometryUnrecPtr geoPtr
;
145 GeoIntegralPropertyUnrecPtr posIndexPtr
, texIndexPtr
, normalIndexPtr
;
146 GeoIntegralPropertyUnrecPtr lensPtr
;
147 GeoIntegralPropertyUnrecPtr typePtr
;
149 DataElem lastDataElem
;
150 Char8 strBuf
[8192], *token
, *nextToken
;
151 Int32 strBufSize
= sizeof(strBuf
)/sizeof(Char8
);
152 Int32 index
, posIndex
= 0, indexType
;
153 Int32 i
,j
,n
,primCount
[3];
154 std::list
<Mesh
> meshList
;
155 std::map
<std::string
, SimpleTexturedMaterialUnrecPtr
> mtlMap
;
156 std::map
<std::string
, SimpleTexturedMaterialUnrecPtr
>::iterator mtlI
;
160 Int32 indexMask
, meshIndexMask
;
161 std::list
<Face
>::iterator faceI
;
162 std::list
<Mesh
>::iterator meshI
;
165 // create the first mesh entry
166 meshList
.push_back(emptyMesh
);
167 meshI
= meshList
.begin();
175 for(is
>> elem
; is
.eof() == false; is
>> elem
)
177 if(elem
[0] == '#' || elem
[0] == '$')
179 is
.ignore(INT_MAX
, '\n');
183 SceneFileHandler::the()->updateReadProgress();
185 elemI
= _dataElemMap
.find(elem
);
186 dataElem
= ((elemI
== _dataElemMap
.end()) ?
187 UNKNOWN_DE
: elemI
->second
);
192 case SMOOTHING_GROUP_DE
:
193 is
.ignore(INT_MAX
, '\n');
198 pnt3r
.setValues(x
,y
,z
);
199 coordPtr
->addValue(pnt3r
);
201 case VERTEX_TEXTURECOORD_DE
:
204 vec2r
.setValues(x
,y
);
205 texCoordPtr
->addValue(vec2r
);
207 case VERTEX_NORMAL_DE
:
210 vec3r
.setValues(x
,y
,z
);
211 normalPtr
->addValue(vec3r
);
215 readMTL ( elem
.c_str(), mtlMap
);
216 is
.ignore(INT_MAX
, '\n');
220 if (meshI
->faceList
.empty() == false)
222 meshList
.push_front(emptyMesh
);
223 meshI
= meshList
.begin();
225 mtlI
= mtlMap
.find(elem
);
226 if (mtlI
== mtlMap
.end())
228 FFATAL (("Unkown mtl %s\n", elem
.c_str()));
232 meshI
->mtlPtr
= mtlI
->second
;
236 meshI
->faceList
.push_front(emptyFace
);
237 faceI
= meshI
->faceList
.begin();
238 is
.get(strBuf
,strBufSize
);
241 while(token
&& *token
)
243 // some tools use line continuation for long
244 // face definitions - these use a \ at the line
249 is
.get(strBuf
,strBufSize
);
254 for (; *token
== '/'; token
++)
256 for (; isspace(*token
); token
++)
258 index
= strtol(token
, &nextToken
, 10);
259 if (token
== nextToken
)
262 faceI
->tieVec
.push_back(emptyTie
);
266 index
= primCount
[indexType
] + index
;
267 faceI
->tieVec
.back().index
[indexType
] = index
;
274 // don't warn about 3rd tex coord
275 if(lastDataElem
!= VERTEX_TEXTURECOORD_DE
)
277 FWARNING (( "Unkown obj data elem: %s\n",
280 is
.ignore(INT_MAX
, '\n');
284 lastDataElem
= dataElem
;
289 std::cerr
<< "------------------------------------------------" << std::endl
;
291 for (meshI
= meshList
.begin(); meshI
!= meshList
.end(); meshI
++)
293 std::cerr
<< "Mesh " << i
<< " faceCount :"
294 << meshI
->faceList
.size() << std::endl
;
296 for ( faceI
= meshI
->faceList
.begin(); faceI
!= meshI
->faceList
.end();
298 std::cerr
<< "MESH " << i
<< "face: " << j
++ << "tie num: "
299 << faceI
->tieVec
.size() << std::endl
;
302 std::cerr
<< "------------------------------------------------" << std::endl
;
305 // create Geometry objects
306 for (meshI
= meshList
.begin(); meshI
!= meshList
.end(); meshI
++)
308 geoPtr
= Geometry::create();
311 normalIndexPtr
= NULL
;
312 lensPtr
= GeoUInt32Property::create();
313 typePtr
= GeoUInt8Property ::create();
315 // create and check mesh index mask
317 isSingleIndex
= true;
318 if ( meshI
->faceList
.empty() == false)
320 for ( faceI
= meshI
->faceList
.begin();
321 faceI
!= meshI
->faceList
.end(); faceI
++)
324 n
= UInt32(faceI
->tieVec
.size());
325 for (i
= 0; i
< n
; i
++)
327 for (j
= 0; j
< 3; j
++)
329 if ((index
= (faceI
->tieVec
[i
].index
[j
])) >= 0)
331 indexMask
|= (1 << j
);
333 isSingleIndex
&= (posIndex
== index
);
339 if (meshIndexMask
== 0)
341 meshIndexMask
= indexMask
;
343 else if (meshIndexMask
!= indexMask
)
345 // consider this real-world example:
347 // f 1603//1747 1679//1744 1678//1743
349 // f 9/1/10 5/2/9 1680/3/1748 1681/4/174
351 // Some faces contain texture coords and others do not.
352 // The old version did just skip this geometry.
353 // This version should continue if there's at least
355 // I've seen the change in the maskIndex only after a smooth group,
356 // so it's perhaps smarter to not ignore the smooth group further up in this code
357 if( !(indexMask
& 1) )
359 // if there are vertex indices there's no reason to get in here
360 FFATAL (( "IndexMask unmatch, can not create geo\n"));
366 // consider the minimum similarities of mesh masks
367 meshIndexMask
&= indexMask
;
374 FWARNING (("Mesh with empty faceList\n"));
377 // fill the geo properties
380 geoPtr
->setPositions ( coordPtr
);
381 posIndexPtr
= GeoUInt32Property::create();
383 geoPtr
->setIndex(posIndexPtr
, Geometry::PositionsIndex
);
384 geoPtr
->setLengths ( lensPtr
);
385 geoPtr
->setTypes ( typePtr
);
387 if ( (meshIndexMask
& 2) && texCoordPtr
->size() > 0 )
389 geoPtr
->setTexCoords ( texCoordPtr
);
390 texIndexPtr
= GeoUInt32Property::create();
392 geoPtr
->setIndex(texIndexPtr
, Geometry::TexCoordsIndex
);
396 geoPtr
->setTexCoords ( NULL
);
399 if ( (meshIndexMask
& 4) && normalPtr
->size() > 0 )
401 geoPtr
->setNormals ( normalPtr
);
402 normalIndexPtr
= GeoUInt32Property::create();
404 geoPtr
->setIndex(normalIndexPtr
, Geometry::NormalsIndex
);
408 geoPtr
->setNormals ( NULL
);
411 if (meshI
->mtlPtr
== NULL
)
413 meshI
->mtlPtr
= SimpleTexturedMaterial::create();
414 meshI
->mtlPtr
->setDiffuse( Color3f( .8f
, .8f
, .8f
) );
415 meshI
->mtlPtr
->setSpecular( Color3f( 1.f
, 1.f
, 1.f
) );
416 meshI
->mtlPtr
->setShininess( 20.f
);
418 geoPtr
->setMaterial ( meshI
->mtlPtr
);
420 for ( faceI
= meshI
->faceList
.begin();
421 faceI
!= meshI
->faceList
.end(); faceI
++)
423 n
= UInt32(faceI
->tieVec
.size());
425 // add the lens entry
426 lensPtr
->push_back(n
);
428 // add the type entry
429 typePtr
->push_back(GL_POLYGON
);
431 // create the index values
432 for (i
= 0; i
< n
; i
++)
436 posIndexPtr
->push_back(faceI
->tieVec
[i
].index
[0]);
440 posIndexPtr
->push_back(faceI
->tieVec
[i
].index
[0]);
441 if(texIndexPtr
!= NULL
)
442 texIndexPtr
->push_back(faceI
->tieVec
[i
].index
[1]);
443 if(normalIndexPtr
!= NULL
)
444 normalIndexPtr
->push_back(faceI
->tieVec
[i
].index
[2]);
451 geoPtr
->setIndex(posIndexPtr
, Geometry::PositionsIndex
);
452 geoPtr
->setIndex(posIndexPtr
, Geometry::NormalsIndex
);
453 geoPtr
->setIndex(posIndexPtr
, Geometry::TexCoordsIndex
);
456 // need to port the geometry functions ...
457 createSharedIndex( geoPtr
);
459 // check if we have normals
460 // need to port the geometry functions ...
462 if(geoPtr
->getNormals() == NULL
)
463 calcVertexNormals(geoPtr
);
465 // create and link the node
466 nodePtr
= Node::create();
467 nodePtr
->setCore( geoPtr
);
469 if (meshList
.size() > 1)
473 rootPtr
= Node::create();
475 GroupUnrecPtr tmpPtr
= Group::create();
477 rootPtr
->setCore ( tmpPtr
);
478 rootPtr
->addChild(nodePtr
);
482 rootPtr
->addChild(nodePtr
);
493 SceneFileHandler::the()->updateReadProgress(100);
497 return NodeTransitPtr(rootPtr
);
500 void OBJSceneFileType::write(Node
* const node
,
504 UInt32
&tIndex
) const
506 UInt32 i
,pCount
=0,nCount
=0,tCount
=0;
507 Geometry
*g
= dynamic_cast<Geometry
*>(node
->getCore());
510 // HACK separate it in several geometry nodes.
511 os
<< "g Geometry" << std::endl
;
512 os
<< "usemtl Geometry" << std::endl
;
513 Matrix mat
= node
->getToWorld();
515 if(g
->getPositions())
517 pCount
= g
->getPositions()->size32();
518 for(i
=0 ; i
< pCount
; ++i
)
521 g
->getPositions()->getValue(v
, i
);
523 os
<< "v " << v
[0] << " " << v
[1] << " " << v
[2] << std::endl
;
529 nCount
= g
->getNormals()->size32();
530 for(i
=0 ; i
< nCount
; ++i
)
533 g
->getNormals()->getValue(v
, i
);
535 os
<< "vn " << v
[0] << " " << v
[1] << " " << v
[2] << std::endl
;
539 if(g
->getTexCoords())
541 tCount
= g
->getTexCoords()->size32();
542 for(i
=0 ; i
< tCount
; ++i
)
545 g
->getTexCoords()->getValue(v
, i
);
546 os
<< "vt " << v
[0] << " " << v
[1] << std::endl
;
551 for(f
=g
->beginTriangles() ; f
!=g
->endTriangles() ; ++f
)
556 os
<< " " << f
.getPositionIndex(i
) + pIndex
;
561 os
<< f
.getTexCoordsIndex(i
) + tIndex
;
563 os
<< "/" << f
.getNormalIndex(i
) + nIndex
;
572 for(MFUnrecChildNodePtr::const_iterator nI
=node
->getMFChildren()->begin();
573 nI
!=node
->getMFChildren()->end();
576 write((*nI
),os
,pIndex
,nIndex
,tIndex
);
580 bool OBJSceneFileType::write(Node
* const node
, std::ostream
&os
,
581 const Char8
*fileNameOrExtension
) const
587 write(node
,os
,pIndex
,tIndex
,nIndex
);
592 /******************************
594 ******************************/
597 /******************************
599 ******************************/
602 /***************************
604 ***************************/
607 /***************************
609 ***************************/
612 /**constructors & destructors**/
615 //----------------------------
616 // Function name: OBJSceneFileType
617 //----------------------------
620 //p: const char *suffixArray[], UInit16 suffixByteCount
630 //d: Default Constructor
634 //------------------------------
636 OBJSceneFileType::OBJSceneFileType(const Char8
*suffixArray
[],
637 UInt16 suffixByteCount
,
639 UInt32 overridePriority
,
641 SceneFileType(suffixArray
,
653 //----------------------------
654 // Function name: OBJSceneFileType
655 //----------------------------
658 //p: const OBJSceneFileType &obj
668 //d: Copy Constructor
672 //------------------------------
674 OBJSceneFileType::OBJSceneFileType(const OBJSceneFileType
&obj
) :
682 //----------------------------
683 // Function name: ~OBJSceneFileType
684 //----------------------------
701 //------------------------------
703 OBJSceneFileType
&OBJSceneFileType::the(void)
708 OBJSceneFileType::~OBJSceneFileType(void)
713 const Char8
*OBJSceneFileType::getName(void) const
715 return "Wavefront Geometry";
719 /*------------access----------------*/
721 /*------------properies-------------*/
723 /*------------your Category---------*/
725 /*------------Operators-------------*/
729 /****************************
731 ****************************/
734 /****************************
736 ****************************/
739 void OBJSceneFileType::initElemMap(void)
741 if (_dataElemMap
.empty())
743 _dataElemMap
[""] = UNKNOWN_DE
;
745 _dataElemMap
["v"] = VERTEX_DE
;
746 _dataElemMap
["vt"] = VERTEX_TEXTURECOORD_DE
;
747 _dataElemMap
["vn"] = VERTEX_NORMAL_DE
;
748 _dataElemMap
["f"] = FACE_DE
;
749 _dataElemMap
["fo"] = FACE_DE
;
750 _dataElemMap
["mtllib"] = LIB_MTL_DE
;
751 _dataElemMap
["usemtl"] = USE_MTL_DE
;
752 _dataElemMap
["g"] = GROUP_DE
;
753 _dataElemMap
["s"] = SMOOTHING_GROUP_DE
;
754 _dataElemMap
["o"] = OBJECT_DE
;
757 if (_mtlElemMap
.empty())
759 _mtlElemMap
[""] = UNKNOWN_ME
;
761 _mtlElemMap
["newmtl"] = NEW_MTL_ME
;
762 _mtlElemMap
["Kd"] = MTL_DIFFUSE_ME
;
763 _mtlElemMap
["Ka"] = MTL_AMBIENT_ME
;
764 _mtlElemMap
["Ks"] = MTL_SPECULAR_ME
;
765 _mtlElemMap
["Ns"] = MTL_SHININESS_ME
;
766 _mtlElemMap
["Tr"] = MTL_TRANSPARENCY_ME
;
767 _mtlElemMap
["d"] = MTL_DISSOLVE_ME
;
768 _mtlElemMap
["map_Kd"] = MTL_MAP_KD_ME
;
769 _mtlElemMap
["map_Ka"] = MTL_MAP_KA_ME
;
770 _mtlElemMap
["map_Ks"] = MTL_MAP_KS_ME
;
771 _mtlElemMap
["illum"] = MTL_ILLUM_ME
;
772 _mtlElemMap
["refl"] = MTL_REFL_ME
;
776 Int32
OBJSceneFileType::readMTL ( const Char8
*fileName
,
777 std::map
<std::string
,
778 SimpleTexturedMaterialUnrecPtr
> & mtlMap
)
781 if(fileName
== NULL
|| strlen(fileName
) == 0)
786 PathHandler
*pathHandler
= SceneFileHandler::the()->getPathHandler();
787 std::string fullFilePath
;
789 if(pathHandler
!= NULL
)
790 fullFilePath
= pathHandler
->findFile(fileName
);
792 fullFilePath
= fileName
;
794 if(fullFilePath
.empty())
796 FWARNING (("Couldn't open '%s'!\n", fileName
));
800 std::ifstream
in(fullFilePath
.c_str());
801 SimpleTexturedMaterialUnrecPtr mtlPtr
= NULL
;
804 std::map
<std::string
, MaterialElem
>::const_iterator elemI
;
805 MaterialElem mtlElem
;
806 std::map
<std::string
, OSG::ImageUnrecPtr
> imageMap
;
807 std::map
<std::string
, OSG::ImageUnrecPtr
>::iterator iI
;
808 ImageUnrecPtr image
= NULL
;
809 bool constDiffuse
= false, constAmbient
= false, constSpecular
= false;
813 for (in
>> elem
; in
.eof() == false; in
>> elem
)
815 if (elem
[0] == '#' || elem
[0] == '$' )
817 in
.ignore(INT_MAX
, '\n');
821 elemI
= _mtlElemMap
.find(elem
);
822 mtlElem
= ((elemI
== _mtlElemMap
.end()) ?
823 UNKNOWN_ME
: elemI
->second
);
824 if (mtlElem
== NEW_MTL_ME
)
827 mtlPtr
= SimpleTexturedMaterial::create();
828 mtlPtr
->setColorMaterial(GL_NONE
);
829 mtlPtr
->setEnvMode(GL_MODULATE
);
830 mtlMap
[elem
] = mtlPtr
;
832 constDiffuse
= false;
833 constAmbient
= false;
834 constSpecular
= false;
840 FFATAL (( "Invalid Mtl token: %s, newmtl expected in %s\n",
841 elem
.c_str(), fileName
));
842 in
.ignore(INT_MAX
, '\n');
851 mtlPtr
->setDiffuse( Color3f( a
,b
,c
));
856 mtlPtr
->setAmbient( Color3f( a
,b
,c
));
858 case MTL_SPECULAR_ME
:
861 mtlPtr
->setSpecular( Color3f( a
,b
,c
));
863 case MTL_SHININESS_ME
:
865 mtlPtr
->setShininess(a
);
868 ; // TODO: What to do with illum ?!?
870 // FFATAL (("obj mtl illum not handled yet\n"));
873 mtlPtr
->setEnvMap(true);
875 case MTL_TRANSPARENCY_ME
:
877 mtlPtr
->setTransparency(a
);
879 case MTL_DISSOLVE_ME
:
881 mtlPtr
->setTransparency(1.f
- a
);
888 iI
= imageMap
.find(elem
);
889 if (iI
== imageMap
.end())
891 std::string fullElemPath
;
892 if(pathHandler
!= NULL
)
893 fullElemPath
= pathHandler
->findFile(elem
.c_str());
895 fullElemPath
= elem
.c_str();
896 image
= OSG::ImageFileHandler::the()->read(fullElemPath
.c_str());
900 image
->setForceAlphaBinary(
901 image
->calcIsAlphaBinary());
903 imageMap
[elem
] = image
;
912 mtlPtr
->setImage(image
);
917 mtlPtr
->setDiffuse ( Color3f( 1.f
, 1.f
, 1.f
) );
921 mtlPtr
->setAmbient ( Color3f( 1.f
, 1.f
, 1.f
) );
924 constSpecular
= true;
925 mtlPtr
->setSpecular ( Color3f( 1.f
, 1.f
, 1.f
) );
933 FFATAL (( "Can not find %s texture file in mtl %s \n",
934 elem
.c_str(), fileName
));
938 FWARNING (( "Invalid %s entry in %s\n",
939 elem
.c_str(), fileName
));
940 in
.ignore(INT_MAX
, '\n');