Index: /OpenSceneGraph/trunk/src/osgPlugins/3ds/WriterNodeVisitor.cpp
===================================================================
--- /OpenSceneGraph/trunk/src/osgPlugins/3ds/WriterNodeVisitor.cpp (revision 11123)
+++ /OpenSceneGraph/trunk/src/osgPlugins/3ds/WriterNodeVisitor.cpp (revision 11194)
@@ -16,4 +16,5 @@
 #include <osg/io_utils>
 #include <osg/CullFace>
+#include <osg/Billboard>
 #include <osgDB/WriteFile>
 
@@ -659,5 +660,5 @@
 
 /** 
-*  Add a vertice to the index and link him with the Triangle index and the drawable.
+*  Add a vertice to the index and link it with the Triangle index and the drawable.
 *  \param index_vert is the map where the vertice are stored.
 *  \param index is the indice of the vertice's position in the vec3.
@@ -681,8 +682,9 @@
 
 void 
-WriterNodeVisitor::buildMesh(osg::Geode                  &    geo,
-                             MapIndices                  &    index_vert,
-                             bool                        texcoords,
-                             Lib3dsMesh                  *    mesh)
+WriterNodeVisitor::buildMesh(osg::Geode        & geo,
+                             const osg::Matrix & mat,
+                             MapIndices        & index_vert,
+                             bool                texcoords,
+                             Lib3dsMesh        * mesh)
 {
     osg::notify(osg::DEBUG_INFO) << "Building Mesh" << std::endl;
@@ -690,6 +692,7 @@
     if (!mesh) throw "Allocation error";        // TODO
 
+    // Write points
+    assert(index_vert.size() <= MAX_VERTICES);
     lib3ds_mesh_resize_vertices(mesh, index_vert.size(), texcoords ? 1 : 0, 0);
-    // Write points
 
     for(MapIndices::iterator it = index_vert.begin(); it != index_vert.end();++it)
@@ -700,5 +703,5 @@
             throw "Vertex array is not Vec3. Not implemented";        // TODO
         const osg::Vec3Array & vecs= *static_cast<osg::Vec3Array *>(g->getVertexArray());
-        copyOsgVectorToLib3dsVector(mesh->vertices[it->second], vecs[it->first.first]);
+        copyOsgVectorToLib3dsVector(mesh->vertices[it->second], vecs[it->first.first]*mat);
     }
 
@@ -745,42 +748,51 @@
 
 void
-WriterNodeVisitor::buildFaces(osg::Geode     &    geo,
-                              ListTriangle   &    listTriangles,
+WriterNodeVisitor::buildFaces(osg::Geode        & geo,
+                              const osg::Matrix & mat,
+                              ListTriangle      & listTriangles,
                               bool                texcoords)
 {
     MapIndices index_vert;
-    unsigned int nbFace = 0;
     Lib3dsMesh *mesh = lib3ds_mesh_new( getUniqueName(geo.getName().empty() ? geo.className() : geo.getName(), "geo").c_str() );
-    unsigned int nbTriangles = listTriangles.size();
-
-    lib3ds_mesh_resize_faces(mesh, nbTriangles);
-
-    unsigned int nbVertices = calcVertices(geo);
-    if (listTriangles.size() >= MAX_FACES-2 ||
-       ((nbVertices) >= MAX_VERTICES-2))
+    if (!mesh) throw "Allocation error";
+
+    unsigned int nbTrianglesRemaining = listTriangles.size();
+    unsigned int nbVerticesRemaining  = calcVertices(geo);
+
+    lib3ds_mesh_resize_faces   (mesh, osg::minimum(nbTrianglesRemaining, MAX_FACES));
+    lib3ds_mesh_resize_vertices(mesh, osg::minimum(nbVerticesRemaining,  MAX_VERTICES), texcoords ? 0 : 1, 0);        // Not mandatory but will allocate once a big block
+
+    // Test if the mesh will be split and needs sorting
+    if (nbVerticesRemaining >= MAX_VERTICES || nbTrianglesRemaining >= MAX_FACES)
     {
         osg::notify(osg::INFO) << "Sorting elements..." << std::endl;
-        WriterCompareTriangle cmp(geo, nbVertices);
+        WriterCompareTriangle cmp(geo, nbVerticesRemaining);
         std::sort(listTriangles.begin(), listTriangles.end(), cmp);
     }
 
+    unsigned int numFace = 0;        // Current face index
     for (ListTriangle::iterator it = listTriangles.begin(); it != listTriangles.end(); ++it) //Go through the triangle list to define meshs
     {
-        // Using -2 due to the fact that we treat 3 faces in one time (=the algorithm may overrun the limit by 2).
-        if ((index_vert.size() >= MAX_VERTICES-2 ||        // If mesh is full
-            nbFace >= MAX_FACES-2))
-        {
-            // Finnishing mesh
-            lib3ds_mesh_resize_faces(mesh, nbFace);
-            buildMesh(geo, index_vert, texcoords, mesh);
-
-            // Creating a new mesh
+        // Test if the mesh will be full after adding a face
+        if (index_vert.size()+3 >= MAX_VERTICES || numFace+1 >= MAX_FACES)
+        {
+            // Finnish mesh
+            lib3ds_mesh_resize_faces   (mesh, numFace);
+            //lib3ds_mesh_resize_vertices() will be called in buildMesh()
+            buildMesh(geo, mat, index_vert, texcoords, mesh);
+
+            // "Reset" values and start over a new mesh
             index_vert.clear();
+            nbTrianglesRemaining -= numFace;
+            numFace = 0;
+            // We can't call a thing like "nbVerticesRemaining -= ...;" because points may be used multiple times.
+            // [Sukender: An optimisation here would take too much time I think.]
+
             mesh = lib3ds_mesh_new( getUniqueName(geo.getName().empty() ? geo.className() : geo.getName(), "geo").c_str());
-            nbTriangles -= nbFace;
-            nbFace = 0;
-            lib3ds_mesh_resize_faces(mesh, nbTriangles);
-        }
-        Lib3dsFace & face = mesh->faces[nbFace++];
+            if (!mesh) throw "Allocation error";
+            lib3ds_mesh_resize_faces   (mesh, osg::minimum(nbTrianglesRemaining, MAX_FACES));
+            lib3ds_mesh_resize_vertices(mesh, osg::minimum(nbVerticesRemaining,  MAX_VERTICES), texcoords ? 0 : 1, 0);        // Not mandatory but will allocate once a big block
+        }
+        Lib3dsFace & face = mesh->faces[numFace++];
         face.index[0] = getMeshIndexForGeometryIndex(index_vert, it->first.t1, it->second);
         face.index[1] = getMeshIndexForGeometryIndex(index_vert, it->first.t2, it->second);
@@ -788,5 +800,5 @@
         face.material = it->first.material;
     }
-    buildMesh(geo, index_vert, texcoords, mesh); //When a Mesh is completed without restriction of vertices number
+    buildMesh(geo, mat, index_vert, texcoords, mesh); //When a Mesh is completed without restriction of vertices number
 }
 
@@ -841,9 +853,7 @@
 }
 
-void WriterNodeVisitor::apply( osg::Geode &node )
-{
+void WriterNodeVisitor::apply( osg::Geode &node ) {
     pushStateSet(node.getStateSet());
     //_nameStack.push_back(node.getName());
-    //osg::Matrix m = osg::computeLocalToWorld(getNodePath());
     unsigned int count = node.getNumDrawables();
     ListTriangle listTriangles;
@@ -861,5 +871,6 @@
     if (count > 0)
     {
-        buildFaces(node, listTriangles, texcoords);
+        osg::Matrix mat( osg::computeLocalToWorld(getNodePath()) );
+        buildFaces(node, mat, listTriangles, texcoords);
     }
     popStateSet(node.getStateSet());
@@ -869,21 +880,69 @@
 }
 
-void WriterNodeVisitor::apply(osg::Group &node)
-{
+void WriterNodeVisitor::apply( osg::Billboard &node ) {
+    // TODO Does not handle Billboards' points yet
+
+    pushStateSet(node.getStateSet());
     Lib3dsMeshInstanceNode * parent = _cur3dsNode;
-    Lib3dsMeshInstanceNode * node3ds = lib3ds_node_new_mesh_instance(NULL, getUniqueName(node.getName().empty() ? node.className() : getFileName(node.getName()), "grp").c_str(), NULL, NULL, NULL);
-    lib3ds_file_append_node(file3ds, reinterpret_cast<Lib3dsNode*>(node3ds), reinterpret_cast<Lib3dsNode*>(parent));
-    _cur3dsNode = node3ds;
+
+    unsigned int count = node.getNumDrawables();
+    ListTriangle listTriangles;
+    bool texcoords = false;
+    osg::notify(osg::NOTICE) << "Warning: 3DS writer is incomplete for Billboards (rotation not implemented)." << std::endl;
+    osg::Matrix m( osg::computeLocalToWorld(getNodePath()) );
+    for ( unsigned int i = 0; i < count; i++ )
+    {
+        osg::Geometry *g = node.getDrawable( i )->asGeometry();
+        if ( g != NULL )
+        {
+            listTriangles.clear();
+            _cur3dsNode = parent;
+
+            pushStateSet(g->getStateSet());
+            createListTriangle(g, listTriangles, texcoords, i);
+            popStateSet(g->getStateSet());
+
+            osg::Matrix currentBillBoardMat(osg::Matrix::translate(node.getPosition(i)) * m);        // TODO handle rotation
+            apply3DSMatrixNode(node, currentBillBoardMat, "bil");        // Add a 3DS matrix node
+            buildFaces(node, currentBillBoardMat, listTriangles, texcoords);
+        }
+    }
+
     if (suceedLastApply())
         traverse(node);
     _cur3dsNode = parent;
+    popStateSet(node.getStateSet());
+}
+
+
+
+void WriterNodeVisitor::apply(osg::Group &node)
+{
+    pushStateSet(node.getStateSet());
+    Lib3dsMeshInstanceNode * parent = _cur3dsNode;
+    apply3DSMatrixNode(node, osg::computeLocalToWorld(getNodePath()), "grp");
+    if (suceedLastApply())
+        traverse(node);
+    _cur3dsNode = parent;
+    popStateSet(node.getStateSet());
 }
 
 void WriterNodeVisitor::apply(osg::MatrixTransform &node)
 {
+    pushStateSet(node.getStateSet());
     Lib3dsMeshInstanceNode * parent = _cur3dsNode;
-
-    const osg::Matrix & m = node.getMatrix();
-    //const osg::Matrix m( osg::computeWorldToLocal(getNodePath()) );        // [NEEDS TESTING!] 3DS matrices always contain world to local transformation (not local transform; ie. from parent)
+    apply3DSMatrixNode(node, osg::computeLocalToWorld(getNodePath()), "mtx");
+    if (suceedLastApply())
+        traverse(node);
+    _cur3dsNode = parent;
+    popStateSet(node.getStateSet());
+}
+
+void WriterNodeVisitor::apply3DSMatrixNode(osg::Node &node, const osg::Matrix & m, const char * const prefix)
+{
+    Lib3dsMeshInstanceNode * parent = _cur3dsNode;
+
+    //const osg::Matrix & m = node.getMatrix();
+    //const osg::Matrix m( osg::computeLocalToWorld(nodePath) );        // [NEEDS TESTING!] 3DS matrices always contain world to local transformation (not local transform; ie. from parent)
 
     // Transform data used to be given to lib3ds_node_new_mesh_instance(), but it seems buggy (pivot problem? bug in conversion?).
@@ -898,5 +957,5 @@
     copyOsgQuatToLib3dsQuat(rot, osgRot);
     Lib3dsMeshInstanceNode * node3ds = lib3ds_node_new_mesh_instance
-        (NULL, getUniqueName(node.getName().empty() ? node.className() : node.getName(), "mtx").c_str(), pos, scl, rot);
+        (NULL, getUniqueName(node.getName().empty() ? node.className() : node.getName(), prefix).c_str(), pos, scl, rot);
 
     //// Create a mesh instance with no transform and then copy the matrix (doesn't work)
@@ -907,6 +966,3 @@
     lib3ds_file_append_node(file3ds, reinterpret_cast<Lib3dsNode*>(node3ds), reinterpret_cast<Lib3dsNode*>(parent));
     _cur3dsNode = node3ds;
-    if (suceedLastApply())
-        traverse(node);
-    _cur3dsNode = parent;
-}
+}
Index: /OpenSceneGraph/trunk/src/osgPlugins/3ds/WriterNodeVisitor.h
===================================================================
--- /OpenSceneGraph/trunk/src/osgPlugins/3ds/WriterNodeVisitor.h (revision 11056)
+++ /OpenSceneGraph/trunk/src/osgPlugins/3ds/WriterNodeVisitor.h (revision 11194)
@@ -62,4 +62,5 @@
         void        failedApply();
         virtual void apply(osg::Geode &node);
+        virtual void apply(osg::Billboard &node);
 
         virtual void apply(osg::Group &node);
@@ -135,8 +136,9 @@
         *  Fill the faces field of the mesh and call buildMesh().
         *  \param geo is the geode who contain vertice and faces.
+        *  \param mat Local to world matrix applied to the geode
         *  \param listTriangles contain all the meshs faces.
         *  \param texcoords tell us if we have to treat texture coord.
         */
-        void buildFaces(osg::Geode & geo, ListTriangle & listTriangles, bool texcoords);
+        void buildFaces(osg::Geode & geo, const osg::Matrix & mat, ListTriangle & listTriangles, bool texcoords);
 
         /** 
@@ -150,14 +152,15 @@
         *  Build a mesh
         *  \param geo is the geode who contain vertice and faces
+        *  \param mat Local to world matrix applied to the geode
         *  \param index_vert is the index used to build the new mesh
         *  \param texcoords tell us if we have to treat texture coord
         *  \param mesh is the mesh with faces filled
-        *  \return the place of the box in the vector.
         *  \sa See cutScene() about the definition of the boxes for faces sorting.
         */
         void
-        buildMesh(osg::Geode        &    geo, 
-                  MapIndices        &    index_vert, 
-                  bool                   texcoords,        
+        buildMesh(osg::Geode        &    geo,
+                  const osg::Matrix &    mat,
+                  MapIndices        &    index_vert,
+                  bool                   texcoords,       
                   Lib3dsMesh             *mesh);
 
@@ -193,4 +196,5 @@
         typedef std::map< osg::ref_ptr<osg::StateSet>, Material, CompareStateSet> MaterialMap;
 
+        void apply3DSMatrixNode(osg::Node &node, const osg::Matrix & m, const char * const prefix);
 
         bool                                _suceedLastApply;
Index: /OpenSceneGraph/trunk/src/osgPlugins/3ds/ReaderWriter3DS.cpp
===================================================================
--- /OpenSceneGraph/trunk/src/osgPlugins/3ds/ReaderWriter3DS.cpp (revision 11180)
+++ /OpenSceneGraph/trunk/src/osgPlugins/3ds/ReaderWriter3DS.cpp (revision 11194)
@@ -903,5 +903,5 @@
     if (texture && *(texture->name))
     {
-        osg::notify(osg::NOTICE)<<"texture->name="<<texture->name<<", _directory="<<_directory<<std::endl;
+        osg::notify(osg::INFO)<<"texture->name="<<texture->name<<", _directory="<<_directory<<std::endl;
 
         std::string fileName = osgDB::findFileInDirectory(texture->name,_directory,osgDB::CASE_INSENSITIVE);
@@ -910,5 +910,5 @@
             // file not found in .3ds file's directory, so we'll look in the datafile path list.
             fileName = osgDB::findDataFile(texture->name,options, osgDB::CASE_INSENSITIVE);
-            osg::notify(osg::NOTICE)<<"texture->name="<<texture->name<<", _directory="<<_directory<<std::endl;
+            osg::notify(osg::INFO)<<"texture->name="<<texture->name<<", _directory="<<_directory<<std::endl;
         }
 
Index: /OpenSceneGraph/trunk/src/osgPlugins/3ds/WriterCompareTriangle.cpp
===================================================================
--- /OpenSceneGraph/trunk/src/osgPlugins/3ds/WriterCompareTriangle.cpp (revision 11056)
+++ /OpenSceneGraph/trunk/src/osgPlugins/3ds/WriterCompareTriangle.cpp (revision 11194)
@@ -49,11 +49,12 @@
     unsigned int nbVerticesZ = static_cast<unsigned int>( (nbVertices * k) / (length.x() * length.y()) );
 
-    setMaxMin (nbVerticesX, nbVerticesY, nbVerticesZ); // This function prevent from cut scene in too many blocs
+    setMaxMin (nbVerticesX, nbVerticesY, nbVerticesZ); // This function prevent from cutting the scene in too many blocs
 
-    osg::notify(osg::ALWAYS) << "Cutting x by " << nbVerticesX << std::endl
+    osg::notify(osg::INFO)
+        << "Cutting x by " << nbVerticesX << std::endl
         << "Cutting y by " << nbVerticesY << std::endl
         << "Cutting z by " << nbVerticesZ << std::endl;
 
-    osg::BoundingBox::value_type blocX = length.x() / nbVerticesX; //This 3 lines set the size of a bloc in x, y and z
+    osg::BoundingBox::value_type blocX = length.x() / nbVerticesX;    // These 3 lines set the size of a bloc in x, y and z
     osg::BoundingBox::value_type blocY = length.y() / nbVerticesY;
     osg::BoundingBox::value_type blocZ = length.z() / nbVerticesZ;
