Hi Michael,

I managed to write the code, but I need testing. Moreover I can't update the 
FBX plugin because of the regression I told you in another thread, concerning 
images.
Can you, please:
- Merge changes to your working copy, and
- Make a few tests with your models?

Also feel free to commit if everything seems okay.
Attached file is against rev. 11322 of the trunk.

Many thanks.

For info, my implemtation looks like:
- Add points of the triangles
- Detect how to split quads (02 or 13), and add points for the two triangles
- Save polygons in a temporary array
- Add a primitive set for all triangles (DrawArray)
- Add polygons points AFTER the points of the triangles
- Add primitive sets for polygons
- Tessellate

Sukender
PVLE - Lightweight cross-platform game engine - http://pvle.sourceforge.net/

----- "Sukender" <[email protected]> a écrit :

> Alright. I started working on it.
> 
> Sukender
> PVLE - Lightweight cross-platform game engine -
> http://pvle.sourceforge.net/
> 
> ----- "Sukender" <[email protected]> a écrit :
> 
> > Oh, right, sorry I didn't spot this. Thanks.
> >
> > Sukender
> > PVLE - Lightweight cross-platform game engine -
> > http://pvle.sourceforge.net/
> >
> > ----- "Michael Platings" <[email protected]> a écrit :
> >
> > > I was referring to that by "For quads I imagine it would be
> possible
> > > to write some fast specialised code to see if they should be split
> > > across vertices (0,2) or (1,3) so that loading times remain
> > bearable."
> > >
> > >
> > > On 6 July 2010 09:02, Sukender < [email protected] > wrote:
> > >
> > >
> > > Oh... What about concave "quads" (I mean 4 points polygons)?
> > >
> > >
> > > Sukender
> > > PVLE - Lightweight cross-platform game engine -
> > > http://pvle.sourceforge.net/
> > >
> > > ----- "Sukender" < [email protected] > a écrit :
> > >
> > >
> > >
> > >
> > > > OK. If you got time for this before I do... :)
> > > >
> > > > Sukender
> > > > PVLE - Lightweight cross-platform game engine -
> > > > http://pvle.sourceforge.net/
> > > >
> > > > ----- "Michael Platings" < [email protected] > a écrit :
> > > >
> > > > > Waht you could do is leave all the triangles and quads in one
> > > > > PrimitiveSet (like it is already), but put each polygon with
> >=5
> > > > > vertices in it's own PrimitiveSet with Mode=POLYGON. Then run
> > the
> > > > > Tesselator on the Geometry which should tesselate the polygons
> > > > > automagically.
> > > > >
> > > > >
> > > > > On 5 July 2010 13:49, Sukender < [email protected] > wrote:
> > > > >
> > > > >
> > > > > Hi Michael,
> > > > >
> > > > > Yes, sorry about OpenGL interpretation of polygons, I forgot
> > that.
> > > > >
> > > > > Well actually, I guess the reader has to handle most (all?)
> > cases.
> > > > So
> > > > > I suggest to have something like:
> > > > > - If number of points <= 4, use current code.
> > > > > - Else call GLU tesselation.
> > > > >
> > > > > Do you agree?
> > > > > The problem I have is that osgUtil::Tessellator is intended to
> > > > operate
> > > > > on osg's structures. Any idea on how to make it work easily in
> > the
> > > > > reader plugin?
> > > > >
> > > > >
> > > > > Sukender
> > > > > PVLE - Lightweight cross-platform game engine -
> > > > > http://pvle.sourceforge.net/
> > > > >
> > > > > ----- "Michael Platings" < [email protected] > a écrit :
> > > > >
> > > > >
> > > > >
> > > > >
> > > > > > No, 1 to 1 mapping of primitives isn't possible because
> OpenGL
> > > > > doesn't
> > > > > > render concave polygons correctly (in practice GL_POLYGON is
> > the
> > > > > same
> > > > > > as GL_TRIANGLE_FAN).
> > > > > > Tesselation is possible via GLU but very slow so we need to
> be
> > > > > careful
> > > > > > about how we use that. Most models I've come across have
> many
> > > > > > triangles and quads but few polygons >=5 vertices. If we
> apply
> > > > > > triangulation to those few polygons then most models will be
> > > > > > unaffected. For quads I imagine it would be possible to
> write
> > > some
> > > > > > fast specialised code to see if they should be split across
> > > > vertices
> > > > > > (0,2) or (1,3) so that loading times remain bearable.
> > > > > > However, if your content provider could just produce models
> > that
> > > > are
> > > > > > already suitable for real-time rendering that would be best
> ;)
> > > > > >
> > > > > >
> > > > > > On 5 July 2010 09:09, Sukender < [email protected] > wrote:
> > > > > >
> > > > > >
> > > > > > Hi all,
> > > > > >
> > > > > > The FBX reader seems to interpret FBX polygons as triangles.
> > > Well
> > > > I
> > > > > > guess this should not be, as 1-to-1 mapping of primitives is
> > > > > possible
> > > > > > (as far as I know), but this is not really an issue. What is
> > an
> > > > > issue
> > > > > > is that concave polygons are not intepreted the right way. I
> > > think
> > > > > > about two solutions:
> > > > > > 1. Use tessellation code to get correct "splitting"
> > > > > > 2. Do the 1-to-1 mapping of primitives
> > > > > >
> > > > > > Am I right ?
> > > > > > Other ideas?
> > > > > > Anyone having time for this?
> > > > > >
> > > > > > Thanks folks!
> > > > > >
> > > > > > Cheers,
> > > > > >
> > > > > > Sukender
> > > > > > PVLE - Lightweight cross-platform game engine -
> > > > > > http://pvle.sourceforge.net/
> > > > > > _______________________________________________
> > > > > > osg-users mailing list
> > > > > > [email protected]
> > > > > >
> > > > >
> > > >
> > >
> >
> http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
> > > > > >
> > > > > >
> > > > > > _______________________________________________
> > > > > > osg-users mailing list
> > > > > > [email protected]
> > > > > >
> > > > >
> > > >
> > >
> >
> http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
> > > > > _______________________________________________
> > > > > osg-users mailing list
> > > > > [email protected]
> > > > >
> > > >
> > >
> >
> http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
> > > > >
> > > > >
> > > > > _______________________________________________
> > > > > osg-users mailing list
> > > > > [email protected]
> > > > >
> > > >
> > >
> >
> http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
> > > > _______________________________________________
> > > > osg-users mailing list
> > > > [email protected]
> > > >
> > >
> >
> http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
> > > _______________________________________________
> > > osg-users mailing list
> > > [email protected]
> > >
> >
> http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
> > >
> > >
> > > _______________________________________________
> > > osg-users mailing list
> > > [email protected]
> > >
> >
> http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
> > _______________________________________________
> > osg-users mailing list
> > [email protected]
> >
> http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
> _______________________________________________
> osg-users mailing list
> [email protected]
> http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
#include <cassert>
#include <sstream>

#include <osg/BlendFunc>
#include <osg/Geode>
#include <osg/Image>
#include <osg/MatrixTransform>

#include <osgUtil/TriStripVisitor>
#include <osgUtil/Tessellator>

#include <osgDB/ReadFile>

#include <osgAnimation/RigGeometry>
#include <osgAnimation/MorphGeometry>
#include <osgAnimation/BasicAnimationManager>

#if defined(_MSC_VER)
#pragma warning( disable : 4505 )
#endif
#include <fbxsdk.h>

#include "fbxRMesh.h"
#include "fbxRNode.h"

enum GeometryType
{
    GEOMETRY_STATIC,
    GEOMETRY_RIG,
    GEOMETRY_MORPH
};

osg::Vec3d convertVec3(const KFbxVector4& v)
{
    return osg::Vec3d(
        v[0],
        v[1],
        v[2]);
}

template <typename T>
bool layerElementValid(const KFbxLayerElementTemplate<T>* pLayerElement)
{
    if (!pLayerElement)
        return false;

    switch (pLayerElement->GetMappingMode())
    {
    case KFbxLayerElement::eBY_CONTROL_POINT:
    case KFbxLayerElement::eBY_POLYGON_VERTEX:
    case KFbxLayerElement::eBY_POLYGON:
        break;
    default:
        return false;
    }

    switch (pLayerElement->GetReferenceMode())
    {
    case KFbxLayerElement::eDIRECT:
    case KFbxLayerElement::eINDEX_TO_DIRECT:
        return true;
    }

    return false;
}

template <typename T>
int getVertexIndex(const KFbxLayerElementTemplate<T>* pLayerElement,
    const KFbxMesh* fbxMesh,
    int nPolygon, int nPolyVertex, int nMeshVertex)
{
    int index = 0;

    switch (pLayerElement->GetMappingMode())
    {
    case KFbxLayerElement::eBY_CONTROL_POINT:
        index = fbxMesh->GetPolygonVertex(nPolygon, nPolyVertex);
        break;
    case KFbxLayerElement::eBY_POLYGON_VERTEX:
        index = nMeshVertex;
        break;
    case KFbxLayerElement::eBY_POLYGON:
        index = nPolygon;
        break;
    }

    if (pLayerElement->GetReferenceMode() == KFbxLayerElement::eDIRECT)
    {
        return index;
    }

    return pLayerElement->GetIndexArray().GetAt(index);
}

template <typename T>
int getPolygonIndex(const KFbxLayerElementTemplate<T>* pLayerElement, int 
nPolygon)
{
    if (pLayerElement &&
        pLayerElement->GetMappingMode() == KFbxLayerElement::eBY_POLYGON)
    {
        switch (pLayerElement->GetReferenceMode())
        {
        case KFbxLayerElement::eDIRECT:
            return nPolygon;
        case KFbxLayerElement::eINDEX_TO_DIRECT:
            return pLayerElement->GetIndexArray().GetAt(nPolygon);
        }
    }

    return 0;
}

template <typename FbxT>
FbxT getElement(const KFbxLayerElementTemplate<FbxT>* pLayerElement,
    const KFbxMesh* fbxMesh,
    int nPolygon, int nPolyVertex, int nMeshVertex)
{
    return pLayerElement->GetDirectArray().GetAt(getVertexIndex(
        pLayerElement, fbxMesh, nPolygon, nPolyVertex, nMeshVertex));
}

typedef std::map<unsigned, osg::ref_ptr<osg::Geometry> > GeometryMap;

osg::Array* createVec2Array(bool doublePrecision)
{
    if  (doublePrecision) return new osg::Vec2dArray;
    else return new osg::Vec2Array;
}
osg::Array* createVec3Array(bool doublePrecision)
{
    if  (doublePrecision) return new osg::Vec3dArray;
    else return new osg::Vec3Array;
}
osg::Array* createVec4Array(bool doublePrecision)
{
    if  (doublePrecision) return new osg::Vec4dArray;
    else return new osg::Vec4Array;
}

osg::Geometry* getGeometry(osg::Geode* pGeode, GeometryMap& geometryMap,
    std::vector<StateSetContent>& stateSetList,
    GeometryType gt, unsigned int mti, bool bNormal, bool bTexCoord, bool 
bColor, const osgDB::Options& options)
{
    GeometryMap::iterator it = geometryMap.find(mti);

    if (it != geometryMap.end())
    {
        return it->second.get();
    }

    osg::ref_ptr<osg::Geometry> pGeometry;
    if (gt == GEOMETRY_MORPH)
    {
        pGeometry = new osgAnimation::MorphGeometry;
    }
    else
    {
        pGeometry = new osg::Geometry;
    }

    osgDB::Options::PrecisionHint precision = options.getPrecisionHint();

    
pGeometry->setVertexData(osg::Geometry::ArrayData(createVec3Array((precision & 
osgDB::Options::DOUBLE_PRECISION_VERTEX) != 0), 
osg::Geometry::BIND_PER_VERTEX));
    if (bNormal) 
pGeometry->setNormalData(osg::Geometry::ArrayData(createVec3Array((precision & 
osgDB::Options::DOUBLE_PRECISION_NORMAL) != 0), 
osg::Geometry::BIND_PER_VERTEX));
    if (bTexCoord) pGeometry->setTexCoordData(0, 
osg::Geometry::ArrayData(createVec2Array((precision & 
osgDB::Options::DOUBLE_PRECISION_TEX_COORD) != 0), 
osg::Geometry::BIND_PER_VERTEX));
    if (bColor) 
pGeometry->setColorData(osg::Geometry::ArrayData(createVec4Array((precision & 
osgDB::Options::DOUBLE_PRECISION_COLOR) != 0), osg::Geometry::BIND_PER_VERTEX));

    if (mti < stateSetList.size())
    {
        bool transparent = false;
        const StateSetContent& ss = stateSetList[mti];
        if (osg::Material* pMaterial = ss.first)
        {
            pGeometry->getOrCreateStateSet()->setAttributeAndModes(pMaterial);
            transparent = pMaterial->getDiffuse(osg::Material::FRONT).w() < 
1.0f;
        }
        if (osg::Texture2D* pTexture = ss.second)
        {
            pGeometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, 
pTexture);
            if (!transparent && pTexture->getImage())
            {
                transparent = pTexture->getImage()->isImageTranslucent();
            }
        }

        if (transparent)
        {
            pGeometry->getOrCreateStateSet()->setAttributeAndModes(new 
osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
        }
    }

    geometryMap.insert(std::pair<unsigned, osg::ref_ptr<osg::Geometry> >(mti, 
pGeometry));
    pGeode->addDrawable(pGeometry.get());

    return pGeometry.get();
}

osgAnimation::VertexInfluence& getVertexInfluence(
    osgAnimation::VertexInfluenceMap& vim, const std::string& name)
{
    osgAnimation::VertexInfluenceMap::iterator it = vim.lower_bound(name);
    if (it == vim.end() || name != it->first)
    {
        it = vim.insert(it, osgAnimation::VertexInfluenceMap::value_type(
            name, osgAnimation::VertexInfluence()));
        it->second.setName(name);
    }
    return it->second;
}

void addChannel(
    osgAnimation::Channel* pChannel,
    osg::ref_ptr<osgAnimation::AnimationManagerBase>& pAnimManager,
    const char* pTakeName)
{
    if (!pChannel)
    {
        return;
    }

    if (!pAnimManager) pAnimManager = new osgAnimation::BasicAnimationManager;

    osgAnimation::Animation* pAnimation = 0;
    const osgAnimation::AnimationList& anims = pAnimManager->getAnimationList();
    for (size_t i = 0; i < anims.size(); ++i)
    {
        if (anims[i]->getName() == pTakeName)
        {
            pAnimation = anims[i].get();
        }
    }

    if (!pAnimation)
    {
        pAnimation = new osgAnimation::Animation;
        pAnimation->setName(pTakeName);
        pAnimManager->registerAnimation(pAnimation);
    }

    pAnimation->addChannel(pChannel);
}

void readAnimation(KFbxNode* pNode, const std::string& targetName,
    osg::ref_ptr<osgAnimation::AnimationManagerBase>& pAnimationManager,
    KFbxMesh* pMesh, int nShape)
{
    for (int i = 1; i < pNode->GetTakeNodeCount(); ++i)
    {
        const char* pTakeName = pNode->GetTakeNodeName(i);

        KFCurve* pCurve = pMesh->GetShapeChannel(nShape, false, pTakeName);
        if (!pCurve)
        {
            continue;
        }

        int nKeys = pCurve->KeyGetCount();
        if (!nKeys)
        {
            continue;
        }

        osgAnimation::FloatLinearChannel* pChannel = new 
osgAnimation::FloatLinearChannel;
        std::vector<osgAnimation::TemplateKeyframe<float> >& keyFrameCntr = 
*pChannel->getOrCreateSampler()->getOrCreateKeyframeContainer();

        for (int k = 0; k < nKeys; ++k)
        {
            KFCurveKey key = pCurve->KeyGet(k);
            double fTime = key.GetTime().GetSecondDouble();
            float fValue = static_cast<float>(key.GetValue() * 0.01);
            keyFrameCntr.push_back(osgAnimation::FloatKeyframe(fTime,fValue));
        }

        pChannel->setTargetName(targetName);
        std::stringstream ss;
        ss << nShape;
        pChannel->setName(ss.str());
        addChannel(pChannel, pAnimationManager, pTakeName);
    }
}

void addBindMatrix(
    BindMatrixMap& boneBindMatrices,
    KFbxNode* pBone,
    const osg::Matrix& bindMatrix,
    osgAnimation::RigGeometry* pRigGeometry)
{
    boneBindMatrices.insert(BindMatrixMap::value_type(
        BindMatrixMap::key_type(pBone, pRigGeometry), bindMatrix));
}

void addVec2ArrayElement(osg::Array& a, const KFbxVector2& v)
{
    if (a.getType() == osg::Array::Vec2dArrayType)
    {
        static_cast<osg::Vec2dArray&>(a).push_back(osg::Vec2d(v[0], v[1]));
    }
    else
    {
        static_cast<osg::Vec2Array&>(a).push_back(osg::Vec2(
            static_cast<float>(v[0]),
            static_cast<float>(v[1])));
    }
}

void addVec3ArrayElement(osg::Array& a, const KFbxVector4& v)
{
    if (a.getType() == osg::Array::Vec3dArrayType)
    {
        static_cast<osg::Vec3dArray&>(a).push_back(osg::Vec3d(v[0], v[1], 
v[2]));
    }
    else
    {
        static_cast<osg::Vec3Array&>(a).push_back(osg::Vec3(
            static_cast<float>(v[0]),
            static_cast<float>(v[1]),
            static_cast<float>(v[2])));
    }
}

void addColorArrayElement(osg::Array& a, const KFbxColor& c)
{
    if (a.getType() == osg::Array::Vec4dArrayType)
    {
        static_cast<osg::Vec4dArray&>(a).push_back(osg::Vec4d(c.mRed, c.mGreen, 
c.mBlue, c.mAlpha));
    }
    else
    {
        static_cast<osg::Vec4Array&>(a).push_back(osg::Vec4(
            static_cast<float>(c.mRed),
            static_cast<float>(c.mGreen),
            static_cast<float>(c.mBlue),
            static_cast<float>(c.mAlpha)));
    }
}

typedef std::pair<osg::Geometry*, int> GIPair;
typedef std::multimap<int, GIPair> FbxToOsgVertexMap;
typedef std::map<GIPair, int> OsgToFbxNormalMap;

void readMeshTriangle(const KFbxMesh * fbxMesh, int i /*polygonIndex*/,
                                          int posInPoly0, int posInPoly1, int 
posInPoly2,
                                          int meshVertex0, int meshVertex1, int 
meshVertex2,
                                          FbxToOsgVertexMap & fbxToOsgVertMap, 
OsgToFbxNormalMap & osgToFbxNormMap,
                                          const KFbxVector4* pFbxVertices, 
const KFbxLayerElementNormal* pFbxNormals, const KFbxLayerElementUV* pFbxUVs, 
const KFbxLayerElementVertexColor* pFbxColors, //const 
KFbxLayerElementMaterial* pFbxMaterials,
                                          osg::Geometry * pGeometry,
                                          osg::Array * pVertices, osg::Array * 
pNormals, osg::Array * pTexCoords, osg::Array * pColors)
{
    int v0 = fbxMesh->GetPolygonVertex(i, posInPoly0),
        v1 = fbxMesh->GetPolygonVertex(i, posInPoly1),
        v2 = fbxMesh->GetPolygonVertex(i, posInPoly2);

    fbxToOsgVertMap.insert(FbxToOsgVertexMap::value_type(v0, GIPair(pGeometry, 
pVertices->getNumElements())));
    fbxToOsgVertMap.insert(FbxToOsgVertexMap::value_type(v1, GIPair(pGeometry, 
pVertices->getNumElements() + 1)));
    fbxToOsgVertMap.insert(FbxToOsgVertexMap::value_type(v2, GIPair(pGeometry, 
pVertices->getNumElements() + 2)));

    addVec3ArrayElement(*pVertices, pFbxVertices[v0]);
    addVec3ArrayElement(*pVertices, pFbxVertices[v1]);
    addVec3ArrayElement(*pVertices, pFbxVertices[v2]);

    if (pNormals)
    {
        int n0 = getVertexIndex(pFbxNormals, fbxMesh, i, posInPoly0, 
meshVertex0);
        int n1 = getVertexIndex(pFbxNormals, fbxMesh, i, posInPoly1, 
meshVertex1);
        int n2 = getVertexIndex(pFbxNormals, fbxMesh, i, posInPoly2, 
meshVertex2);

        osgToFbxNormMap.insert(OsgToFbxNormalMap::value_type(GIPair(pGeometry, 
pNormals->getNumElements()), n0));
        osgToFbxNormMap.insert(OsgToFbxNormalMap::value_type(GIPair(pGeometry, 
pNormals->getNumElements() + 1), n1));
        osgToFbxNormMap.insert(OsgToFbxNormalMap::value_type(GIPair(pGeometry, 
pNormals->getNumElements() + 2), n2));

        addVec3ArrayElement(*pNormals, pFbxNormals->GetDirectArray().GetAt(n0));
        addVec3ArrayElement(*pNormals, pFbxNormals->GetDirectArray().GetAt(n1));
        addVec3ArrayElement(*pNormals, pFbxNormals->GetDirectArray().GetAt(n2));
    }

    if (pTexCoords)
    {
        addVec2ArrayElement(*pTexCoords, getElement(pFbxUVs, fbxMesh, i, 
posInPoly0, meshVertex0));
        addVec2ArrayElement(*pTexCoords, getElement(pFbxUVs, fbxMesh, i, 
posInPoly1, meshVertex1));
        addVec2ArrayElement(*pTexCoords, getElement(pFbxUVs, fbxMesh, i, 
posInPoly2, meshVertex2));
    }

    if (pColors)
    {
        addColorArrayElement(*pColors, getElement(pFbxColors, fbxMesh, i, 
posInPoly0, meshVertex0));
        addColorArrayElement(*pColors, getElement(pFbxColors, fbxMesh, i, 
posInPoly1, meshVertex1));
        addColorArrayElement(*pColors, getElement(pFbxColors, fbxMesh, i, 
posInPoly2, meshVertex2));
    }
}

/// Says if a quad should be split using vertices 02 (or else 13)
bool quadSplit02(const KFbxMesh * fbxMesh, int i /*polygonIndex*/,
                                          int posInPoly0, int posInPoly1, int 
posInPoly2, int posInPoly3,
                                          const KFbxVector4* pFbxVertices)
{
        // Algorithm may be a bit dumb. If you got a faster one, feel free to 
change.
        // Here we test each of the 4 triangles and see if there is one in the 
opposite direction.
        //              Triangles: 012, 023, 013, 123
        // For this, we do a cross product to get normals. We say here the 
first triangle is the reference, and do a dot product to see the direction.
        //              Normals: na (= (p1-p0)^(p2-p1)), nb, na, nd
        //              Dot products: rb (na.nb), rc, rd
        // Results:
        //              if r*>0 => convex (02 and 13 are ok, so choose 02)
        //              if rb only <0, or r*<0 => concave, split on 13
        //              if rc only <0, or rd<0 => concave, split on 02
        //              else unhandled (crossed polygon?) => choose 02
        //      In short:
        //              if rb only <0, or r*<0 => return false
        //              else return true

    int v0 = fbxMesh->GetPolygonVertex(i, posInPoly0);
        int v1 = fbxMesh->GetPolygonVertex(i, posInPoly1);
        int v2 = fbxMesh->GetPolygonVertex(i, posInPoly2);
        int v3 = fbxMesh->GetPolygonVertex(i, posInPoly3);

        osg::Vec3d p0(pFbxVertices[v0][0],  pFbxVertices[v0][1],  
pFbxVertices[v0][2]);
        osg::Vec3d p1(pFbxVertices[v1][0],  pFbxVertices[v1][1],  
pFbxVertices[v1][2]);
        osg::Vec3d p2(pFbxVertices[v2][0],  pFbxVertices[v2][1],  
pFbxVertices[v2][2]);
        osg::Vec3d p3(pFbxVertices[v3][0],  pFbxVertices[v3][1],  
pFbxVertices[v3][2]);

        osg::Vec3d na( (p1-p0)^(p2-p1) );
        osg::Vec3d nb( (p2-p0)^(p3-p2) );
        //osg::Vec3d nc( (p1-p0)^(p3-p1) );
        //osg::Vec3d nd( (p2-p1)^(p3-p2) );

        double rb( na*nb );
        //double rc( na*nc );
        //double rd( na*nd );
        if (rb>=0) return true;         // Split at 02

        osg::Vec3d nc( (p1-p0)^(p3-p1) );
        osg::Vec3d nd( (p2-p1)^(p3-p2) );
        double rc( na*nc );
        double rd( na*nd );
        return (rc>=0 || rd>=0);
}

osgDB::ReaderWriter::ReadResult readMesh(KFbxSdkManager& pSdkManager,
    KFbxNode* pNode, KFbxMesh* fbxMesh,
    osg::ref_ptr<osgAnimation::AnimationManagerBase>& pAnimationManager,
    std::vector<StateSetContent>& stateSetList,
    const char* szName,
    BindMatrixMap& boneBindMatrices,
    const std::set<const KFbxNode*>& fbxSkeletons,
    std::map<KFbxNode*, osgAnimation::Skeleton*>& skeletonMap,
    const osgDB::Options& options)
{
    GeometryMap geometryMap;

    osg::Geode* pGeode = new osg::Geode;
    pGeode->setName(szName);

    const KFbxLayer* pFbxLayer = fbxMesh->GetLayer(0);
    const KFbxLayerElementNormal* pFbxNormals = 0;
    const KFbxLayerElementUV* pFbxUVs = 0;
    const KFbxLayerElementVertexColor* pFbxColors = 0;
    const KFbxLayerElementMaterial* pFbxMaterials = 0;

    const KFbxVector4* pFbxVertices = fbxMesh->GetControlPoints();

    if (pFbxLayer)
    {
        pFbxNormals = pFbxLayer->GetNormals();
        pFbxColors = pFbxLayer->GetVertexColors();
        pFbxUVs = pFbxLayer->GetUVs();
        pFbxMaterials = pFbxLayer->GetMaterials();

        if (!layerElementValid(pFbxNormals)) pFbxNormals = 0;
        if (!layerElementValid(pFbxColors)) pFbxColors = 0;
        if (!layerElementValid(pFbxUVs)) pFbxUVs = 0;
    }

    int nPolys = fbxMesh->GetPolygonCount();

    int nDeformerCount = fbxMesh->GetDeformerCount(KFbxDeformer::eSKIN);
    int nMorphShapeCount = 0;

    GeometryType geomType = GEOMETRY_STATIC;

    //determine the type of geometry
    if (nDeformerCount)
    {
        geomType = GEOMETRY_RIG;
    }
    else if (nMorphShapeCount = fbxMesh->GetShapeCount())
    {
        geomType = GEOMETRY_MORPH;
    }

    FbxToOsgVertexMap fbxToOsgVertMap;
    OsgToFbxNormalMap osgToFbxNormMap;

        // First add only triangles and quads (easy to split into triangles 
without more processing)
        // This is the reason we store polygons references:
        struct PolygonRef {
                PolygonRef(osg::Geometry* pGeometry, int numPoly, int nVertex) 
: pGeometry(pGeometry), numPoly(numPoly), nVertex(nVertex) {}
                osg::Geometry* pGeometry;
                int numPoly;
                int nVertex;
        };
        typedef std::vector<PolygonRef> PolygonRefList;
        PolygonRefList polygonRefList;

    for (int i = 0, nVertex = 0; i < nPolys; ++i)
    {
        int lPolygonSize = fbxMesh->GetPolygonSize(i);

        int materialIndex = getPolygonIndex(pFbxMaterials, i);

        osg::Geometry* pGeometry = getGeometry(pGeode, geometryMap,
            stateSetList, geomType, materialIndex,
            pFbxNormals != 0, pFbxUVs != 0, pFbxColors != 0, options);

        osg::Array* pVertices = pGeometry->getVertexArray();
        osg::Array* pNormals = pGeometry->getNormalArray();
        osg::Array* pTexCoords = pGeometry->getTexCoordArray(0);
        osg::Array* pColors = pGeometry->getColorArray();

                if (lPolygonSize == 3) {
                        // Triangle
                        readMeshTriangle(fbxMesh, i,
                                0, 1, 2,
                                nVertex, nVertex+1, nVertex+2,
                                fbxToOsgVertMap, osgToFbxNormMap,
                                pFbxVertices, pFbxNormals, pFbxUVs, pFbxColors,
                                pGeometry,
                                pVertices, pNormals, pTexCoords, pColors);
                        nVertex += 3;
                } else if (lPolygonSize == 4) {
                        // Quad - Convert to triangles
                        // Use some fast specialized code to see how the should 
be decomposed
                        // Two cases : Split at '02' (012 and 023), or split at 
'13 (013 and 123)
                        bool split02 = quadSplit02(fbxMesh, i, 0, 1, 2, 3, 
pFbxVertices);
                        int p02 = split02 ? 2 : 3;              // Triangle 0, 
point 2
                        int p10 = split02 ? 0 : 1;              // Triangle 1, 
point 0
                        readMeshTriangle(fbxMesh, i,
                                0, 1, p02,
                                nVertex, nVertex+1, nVertex+p02,
                                fbxToOsgVertMap, osgToFbxNormMap,
                                pFbxVertices, pFbxNormals, pFbxUVs, pFbxColors,
                                pGeometry,
                                pVertices, pNormals, pTexCoords, pColors);
                        readMeshTriangle(fbxMesh, i,
                                p10, 2, 3,
                                nVertex+p10, nVertex+2, nVertex+3,
                                fbxToOsgVertMap, osgToFbxNormMap,
                                pFbxVertices, pFbxNormals, pFbxUVs, pFbxColors,
                                pGeometry,
                                pVertices, pNormals, pTexCoords, pColors);
                        nVertex += 4;
                } else {
                        // Polygons - Store to add after triangles
                        polygonRefList.push_back(PolygonRef(pGeometry, i, 
nVertex));
                        nVertex += lPolygonSize;
                }
    }

    for (int i = 0; i < pGeode->getNumDrawables(); ++i)
    {
        osg::Geometry* pGeometry = pGeode->getDrawable(i)->asGeometry();
        osg::DrawArrays* pDrawArrays = new osg::DrawArrays(
            GL_TRIANGLES, 0, pGeometry->getVertexArray()->getNumElements());
        pGeometry->addPrimitiveSet(pDrawArrays);
    }

        // Now add polygons - Convert to triangles
        // We put vertices in their own PrimitiveSet with Mode=POLYGON; then 
run the Tesselator on the Geometry which should tesselate the polygons 
automagically.
        for(PolygonRefList::iterator it=polygonRefList.begin(), 
itEnd=polygonRefList.end(); it!=itEnd; ++it)
        {
                int i = it->numPoly;
        int lPolygonSize = fbxMesh->GetPolygonSize(i);
        //int materialIndex = getPolygonIndex(pFbxMaterials, i);
        osg::Geometry* pGeometry = it->pGeometry;

        osg::Array* pVertices = pGeometry->getVertexArray();
        osg::Array* pNormals = pGeometry->getNormalArray();
        osg::Array* pTexCoords = pGeometry->getTexCoordArray(0);
        osg::Array* pColors = pGeometry->getColorArray();
                int osgVertex0 = pVertices->getNumElements();           // 
Index of the 1st vertex of the polygon in the geometry

                for(int j=0, nVertex = it->nVertex; j<lPolygonSize; ++j, 
++nVertex) {
                        int v0 = fbxMesh->GetPolygonVertex(i, j);
                        
fbxToOsgVertMap.insert(FbxToOsgVertexMap::value_type(v0, GIPair(pGeometry, 
pVertices->getNumElements())));
                        addVec3ArrayElement(*pVertices, pFbxVertices[v0]);
                        if (pNormals)
                        {
                                int n0 = getVertexIndex(pFbxNormals, fbxMesh, 
i, j, nVertex);
                                
osgToFbxNormMap.insert(OsgToFbxNormalMap::value_type(GIPair(pGeometry, 
pNormals->getNumElements()), n0));
                                addVec3ArrayElement(*pNormals, 
pFbxNormals->GetDirectArray().GetAt(n0));
                        }
                        if (pTexCoords)
                        {
                                addVec2ArrayElement(*pTexCoords, 
getElement(pFbxUVs, fbxMesh, i, j, nVertex));
                        }
                        if (pColors)
                        {
                                addColorArrayElement(*pColors, 
getElement(pFbxColors, fbxMesh, i, j, nVertex));
                        }
                }
        osg::DrawArrays* pDrawArrays = new osg::DrawArrays(
                        GL_POLYGON, osgVertex0, 
pGeometry->getVertexArray()->getNumElements()-osgVertex0);
        pGeometry->addPrimitiveSet(pDrawArrays);
        }

        for (int i = 0; i < pGeode->getNumDrawables(); ++i)
    {
        osg::Geometry* pGeometry = pGeode->getDrawable(i)->asGeometry();

                // Now split polygons if necessary
                osgUtil::Tessellator tessellator;
                tessellator.retessellatePolygons(*pGeometry);

                if (pGeode->getNumDrawables() > 1)
        {
            std::stringstream ss;
            ss << pGeode->getName() << " " << i + 1;
            pGeometry->setName(ss.str());
        }
        else
        {
            pGeometry->setName(pGeode->getName());
        }
    }

    if (geomType == GEOMETRY_RIG)
    {
        typedef std::map<osg::ref_ptr<osg::Geometry>,
            osg::ref_ptr<osgAnimation::RigGeometry> > GeometryRigGeometryMap;
        GeometryRigGeometryMap old2newGeometryMap;

        for (int i = 0; i < pGeode->getNumDrawables(); ++i)
        {
            osg::Geometry* pGeometry = pGeode->getDrawable(i)->asGeometry();

            osgAnimation::RigGeometry* pRig = new osgAnimation::RigGeometry;
            pRig->setSourceGeometry(pGeometry);
            pRig->copyFrom(*pGeometry);
            old2newGeometryMap.insert(GeometryRigGeometryMap::value_type(
                pGeometry, pRig));
            pRig->setDataVariance(osg::Object::DYNAMIC);
            pRig->setUseDisplayList( false );
            pGeode->setDrawable(i, pRig);

            pRig->setInfluenceMap(new osgAnimation::VertexInfluenceMap);
            pGeometry = pRig;
        }

        for (int i = 0; i < nDeformerCount; ++i)
        {
            KFbxSkin* pSkin = (KFbxSkin*)fbxMesh->GetDeformer(i, 
KFbxDeformer::eSKIN);
            int nClusters = pSkin->GetClusterCount();
            for (int j = 0; j < nClusters; ++j)
            {
                KFbxCluster* pCluster = (KFbxCluster*)pSkin->GetCluster(j);
                //assert(KFbxCluster::eNORMALIZE == pCluster->GetLinkMode());
                KFbxNode* pBone = pCluster->GetLink();

                KFbxXMatrix transformLink;
                pCluster->GetTransformLinkMatrix(transformLink);
                KFbxXMatrix transformLinkInverse = transformLink.Inverse();
                const double* pTransformLinkInverse = transformLinkInverse;
                osg::Matrix bindMatrix(pTransformLinkInverse);

                int nIndices = pCluster->GetControlPointIndicesCount();
                int* pIndices = pCluster->GetControlPointIndices();
                double* pWeights = pCluster->GetControlPointWeights();

                for (int k = 0; k < nIndices; ++k)
                {
                    int fbxIndex = pIndices[k];
                    float weight = static_cast<float>(pWeights[k]);

                    for (FbxToOsgVertexMap::const_iterator it =
                        fbxToOsgVertMap.find(fbxIndex);
                        it != fbxToOsgVertMap.end() &&
                        it->first == fbxIndex; ++it)
                    {
                        GIPair gi = it->second;
                        osgAnimation::RigGeometry& rig =
                            dynamic_cast<osgAnimation::RigGeometry&>(
                            *old2newGeometryMap[gi.first]);
                        addBindMatrix(boneBindMatrices, pBone, bindMatrix, 
&rig);
                        osgAnimation::VertexInfluenceMap& vim =
                            *rig.getInfluenceMap();
                        osgAnimation::VertexInfluence& vi =
                            getVertexInfluence(vim, pBone->GetName());
                        vi.push_back(osgAnimation::VertexIndexWeight(
                            gi.second, weight));
                    }
                }
            }
        }
    }
    else if (geomType == GEOMETRY_MORPH)
    {
        for (int i = 0; i < pGeode->getNumDrawables(); ++i)
        {
            osg::Geometry* pGeometry = pGeode->getDrawable(i)->asGeometry();

            osgAnimation::MorphGeometry& morph = 
dynamic_cast<osgAnimation::MorphGeometry&>(*pGeometry);

            pGeode->addUpdateCallback(new 
osgAnimation::UpdateMorph(morph.getName()));

            //read morph geometry
            for (int j = 0; j < nMorphShapeCount; ++j)
            {
                const KFbxGeometryBase* pMorphShape = fbxMesh->GetShape(i);

                const KFbxLayerElementNormal* pFbxShapeNormals = 0;
                if (const KFbxLayer* pFbxShapeLayer = pMorphShape->GetLayer(0))
                {
                    pFbxShapeNormals = pFbxShapeLayer->GetNormals();
                    if (!layerElementValid(pFbxShapeNormals)) pFbxShapeNormals 
= 0;
                }

                osg::Geometry* pMorphTarget = new osg::Geometry(morph);
                pMorphTarget->setVertexArray(static_cast<osg::Array*>(
                    
pMorphTarget->getVertexArray()->clone(osg::CopyOp::DEEP_COPY_ARRAYS)));
                if (pFbxShapeNormals)
                {
                    if (osg::Array* pNormals = pMorphTarget->getNormalArray())
                    {
                        pMorphTarget->setNormalArray(static_cast<osg::Array*>(
                            pNormals->clone(osg::CopyOp::DEEP_COPY_ARRAYS)));
                    }
                }
                pMorphTarget->setName(fbxMesh->GetShapeName(j));
                morph.addMorphTarget(pMorphTarget, 0.0f);

                readAnimation(pNode, morph.getName(), pAnimationManager, 
fbxMesh, j);
            }
        }

        for (int i = 0; i < nMorphShapeCount; ++i)
        {
            const KFbxGeometryBase* pMorphShape = fbxMesh->GetShape(i);

            const KFbxLayerElementNormal* pFbxShapeNormals = 0;
            if (const KFbxLayer* pFbxShapeLayer = pMorphShape->GetLayer(0))
            {
                pFbxShapeNormals = pFbxShapeLayer->GetNormals();
                if (!layerElementValid(pFbxShapeNormals)) pFbxShapeNormals = 0;
            }

            const KFbxVector4* pControlPoints = pMorphShape->GetControlPoints();
            int nControlPoints = pMorphShape->GetControlPointsCount();
            for (int fbxIndex = 0; fbxIndex < nControlPoints; ++fbxIndex)
            {
                osg::Vec3d vPos = convertVec3(pControlPoints[fbxIndex]);
                for (FbxToOsgVertexMap::const_iterator it =
                    fbxToOsgVertMap.find(fbxIndex);
                    it != fbxToOsgVertMap.end() &&
                    it->first == fbxIndex; ++it)
                {
                    GIPair gi = it->second;
                    osgAnimation::MorphGeometry& morphGeom =
                        dynamic_cast<osgAnimation::MorphGeometry&>(*gi.first);
                    osg::Geometry* pGeometry = 
morphGeom.getMorphTarget(i).getGeometry();

                    if (pGeometry->getVertexArray()->getType() == 
osg::Array::Vec3dArrayType)
                    {
                        osg::Vec3dArray* pVertices = 
static_cast<osg::Vec3dArray*>(pGeometry->getVertexArray());
                        (*pVertices)[gi.second] = vPos;
                    }
                    else
                    {
                        osg::Vec3Array* pVertices = 
static_cast<osg::Vec3Array*>(pGeometry->getVertexArray());
                        (*pVertices)[gi.second] = vPos;
                    }

                    if (pFbxShapeNormals && pGeometry->getNormalArray())
                    {
                        if (pGeometry->getNormalArray()->getType() == 
osg::Array::Vec3dArrayType)
                        {
                            osg::Vec3dArray* pNormals = 
static_cast<osg::Vec3dArray*>(pGeometry->getNormalArray());
                            (*pNormals)[gi.second] = convertVec3(
                                
pFbxShapeNormals->GetDirectArray().GetAt(osgToFbxNormMap[gi]));
                        }
                        else
                        {
                            osg::Vec3Array* pNormals = 
static_cast<osg::Vec3Array*>(pGeometry->getNormalArray());
                            (*pNormals)[gi.second] = convertVec3(
                                
pFbxShapeNormals->GetDirectArray().GetAt(osgToFbxNormMap[gi]));
                        }
                    }
                }
            }
        }
    }

    KFbxXMatrix fbxGeometricTransform;
    fbxGeometricTransform.SetTRS(
        pNode->GeometricTranslation.Get(),
        pNode->GeometricRotation.Get(),
        pNode->GeometricScaling.Get());
    const double* pGeometricMat = fbxGeometricTransform;
    osg::Matrix osgGeometricTransform(pGeometricMat);

    if (geomType == GEOMETRY_RIG)
    {
        KFbxSkin* pSkin = (KFbxSkin*)fbxMesh->GetDeformer(0, 
KFbxDeformer::eSKIN);
        if (pSkin->GetClusterCount())
        {
            KFbxXMatrix fbxTransformMatrix;
            pSkin->GetCluster(0)->GetTransformMatrix(fbxTransformMatrix);
            const double* pTransformMatrix = fbxTransformMatrix;
            osgGeometricTransform.postMult(osg::Matrix(pTransformMatrix));
        }
    }

    osg::Node* pResult = pGeode;

    if (!osgGeometricTransform.isIdentity())
    {
        osg::MatrixTransform* pMatTrans = new 
osg::MatrixTransform(osgGeometricTransform);
        pMatTrans->addChild(pGeode);
        pResult = pMatTrans;
    }

    if (geomType == GEOMETRY_RIG)
    {
        //Add the geometry to the skeleton ancestor of one of the bones.
        KFbxSkin* pSkin = (KFbxSkin*)fbxMesh->GetDeformer(0, 
KFbxDeformer::eSKIN);
        if (pSkin->GetClusterCount())
        {
            osgAnimation::Skeleton* pSkeleton = getSkeleton(
                pSkin->GetCluster(0)->GetLink(), fbxSkeletons, skeletonMap);
            pSkeleton->addChild(pResult);
            return osgDB::ReaderWriter::ReadResult::FILE_LOADED;
        }
    }

    return osgDB::ReaderWriter::ReadResult(pResult);
}

osgDB::ReaderWriter::ReadResult readFbxMesh(KFbxSdkManager& pSdkManager,
    KFbxNode* pNode,
    osg::ref_ptr<osgAnimation::AnimationManagerBase>& pAnimationManager,
    std::vector<StateSetContent>& stateSetList,
    BindMatrixMap& boneBindMatrices,
    const std::set<const KFbxNode*>& fbxSkeletons,
    std::map<KFbxNode*, osgAnimation::Skeleton*>& skeletonMap,
    const osgDB::Options& options)
{
    KFbxMesh* lMesh = dynamic_cast<KFbxMesh*>(pNode->GetNodeAttribute());

    if (!lMesh)
    {
        return osgDB::ReaderWriter::ReadResult::ERROR_IN_READING_FILE;
    }

    return readMesh(pSdkManager, pNode, lMesh, pAnimationManager, stateSetList,
        pNode->GetName(), boneBindMatrices, fbxSkeletons, skeletonMap, options);
}
_______________________________________________
osg-users mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org

Reply via email to