Node *
ColladaNode::createInstanceNode(ColladaInstInfo *colInstInfo, domNode *node)
{
    OSG_COLLADA_LOG(("ColladaNode::createInstanceNode id [%s]\n",
                     node->getId()));

    NodeLoaderState *state =
        getGlobal()->getLoaderStateAs<NodeLoaderState>(_loaderStateName);
    OSG_ASSERT(state != NULL);

    state->pushNodePath(node->getId() != NULL ? node->getId() : "");
    state->dumpNodePath();

    NodeUnrecPtr retVal = NULL;
    InstData     instData;

    instData._nodePath = state->getNodePath();
    const daeElementRefArray &contents = node->getContents();

    // read "transform" child elements in the order
    // they occur in the document
    for(UInt32 i = 0; i < contents.getCount(); ++i)
    {
        switch(contents[i]->getElementType())
        {
        case COLLADA_TYPE::LOOKAT:
            handleLookAt(daeSafeCast<domLookat>(contents[i]), instData);
            break;

        case COLLADA_TYPE::MATRIX:
            handleMatrix(daeSafeCast<domMatrix>(contents[i]), instData);
            break;

        case COLLADA_TYPE::ROTATE:
            handleRotate(daeSafeCast<domRotate>(contents[i]), instData);
            break;

        case COLLADA_TYPE::SCALE:
            handleScale(daeSafeCast<domScale>(contents[i]), instData);
            break;

        case COLLADA_TYPE::SKEW:
            handleSkew(daeSafeCast<domSkew>(contents[i]), instData);
            break;

        case COLLADA_TYPE::TRANSLATE:
            handleTranslate(daeSafeCast<domTranslate>(contents[i]), instData);
            break;
        }
    }

    // assert top and bottom are both set or both unset
    OSG_ASSERT((instData._topN != NULL && instData._bottomN != NULL) ||
               (instData._topN == NULL && instData._bottomN == NULL)   );

    // if no xforms were created make a group for this <node>
    if(instData._topN == NULL && instData._bottomN == NULL)
    {
        instData._topN    = makeCoredNode<Group>();
        instData._bottomN = instData._topN;

        if(getGlobal()->getOptions()->getCreateNameAttachments() == true &&
           node->getName()                                       != NULL   )
        {
            setName(instData._topN, node->getName());
        }
    }

    // update world matrix before we instantiate child nodes, etc.
    state->pushMatrix(instData._localMatrix);

    // add <node> child elements
    const domNode_Array &nodes = node->getNode_array();

    for(UInt32 i = 0; i < nodes.getCount(); ++i)
        handleNode(nodes[i], instData);

    // add <instance_node> child elements
    const domInstance_node_Array &instNodes =
        node->getInstance_node_array();

    for(UInt32 i = 0; i < instNodes.getCount(); ++i)
        handleInstanceNode(instNodes[i], instData);

    // add <instance_light> child elements
    const domInstance_light_Array &instLights =
        node->getInstance_light_array();

    for(UInt32 i = 0; i < instLights.getCount(); ++i)
        handleInstanceLight(instLights[i], instData);

    // add <instance_geometry> child elements
    const domInstance_geometry_Array &instGeos =
        node->getInstance_geometry_array();

    for(UInt32 i = 0; i < instGeos.getCount(); ++i)
        handleInstanceGeometry(instGeos[i], instData);

    // add <instance_controller> child elemnts
    const domInstance_controller_Array &instControllers =
        node->getInstance_controller_array();

    for(UInt32 i = 0; i < instControllers.getCount(); ++i)
        handleInstanceController(instControllers[i], instData);

    editInstStore().push_back(instData._topN);
    _instDataStore .push_back(instData      );
    retVal = instData._topN;

    state->popMatrix  ();
    state->popNodePath();

    return retVal;
}
Node *
ColladaNode::createInstanceJoint(ColladaInstInfo *colInstInfo, domNode *node)
{
    NodeUnrecPtr retVal    = NULL;
    bool         startSkel = false;

    // if there is a ColladaInstanceElement someone tried to use <instance_node>
    // with this joint as target - this is currently not supported
    if(colInstInfo->getColInst() != NULL)
    {
        SWARNING << "ColladaNode::createInstanceJoint: <instance_node> with "
                 << "target <node> of type JOINT not supported." << std::endl;
        return retVal;
    }

    NodeLoaderState *state =
        getGlobal()->getLoaderStateAs<NodeLoaderState>(_loaderStateName);
    OSG_ASSERT(state != NULL);

    state->pushNodePath(node->getId() != NULL ? node->getId() : "");
    state->dumpNodePath();

    InstData instData;
    instData._nodePath = state->getNodePath();
    instData._skel     = state->getSkeleton();

    if(instData._skel == NULL)
    {
        startSkel      = true;
        instData._skel = Skeleton::create();

        state->setSkeleton(instData._skel);
        state->setJointId (0             );

        OSG_COLLADA_LOG(("ColladaNode::createInstanceJoint: id [%s] "
                         "root joint\n", node->getId()));
    }
    else
    {
        state->setJointId(state->getJointId() + 1);

        OSG_COLLADA_LOG(("ColladaNode::createInstanceJoint: id [%s] "
                         "joint [%d]\n", node->getId(), state->getJointId()));
    }

    const daeElementRefArray &contents = node->getContents();

    for(UInt32 i = 0; i < contents.getCount(); ++i)
    {
        switch(contents[i]->getElementType())
        {
        case COLLADA_TYPE::LOOKAT:
            handleLookAt(daeSafeCast<domLookat>(contents[i]), instData);
            break;

        case COLLADA_TYPE::MATRIX:
            handleMatrix(daeSafeCast<domMatrix>(contents[i]), instData);
            break;

        case COLLADA_TYPE::ROTATE:
            handleRotate(daeSafeCast<domRotate>(contents[i]), instData);
            break;

        case COLLADA_TYPE::SCALE:
            handleScale(daeSafeCast<domScale>(contents[i]), instData);
            break;

        case COLLADA_TYPE::SKEW:
            handleSkew(daeSafeCast<domSkew>(contents[i]), instData);
            break;

        case COLLADA_TYPE::TRANSLATE:
            handleTranslate(daeSafeCast<domTranslate>(contents[i]), instData);
            break;
        }
    }

    // assert top and bottom are both set or both unset
    OSG_ASSERT((instData._topN != NULL && instData._bottomN != NULL) ||
               (instData._topN == NULL && instData._bottomN == NULL)   );

    if(instData._topN == NULL && instData._bottomN == NULL)
    {
        // no xforms were created, make a SkeletonJoint for this <node>

        SkeletonJointUnrecPtr joint = SkeletonJoint::create();

        joint->setJointId(state->getJointId());

        instData._topN    = makeNodeFor(joint);
        instData._bottomN = instData._topN;

        if(getGlobal()->getOptions()->getCreateNameAttachments() == true &&
           node->getName()                                       != NULL   )
        {
            setName(instData._topN, node->getName());
        }
    }
    else if(getGlobal()->getOptions()->getMergeTransforms() == false)
    {
        // when not merging transforms add SkeletonJoint core now

        SkeletonJointUnrecPtr joint  = SkeletonJoint::create();
        NodeUnrecPtr          jointN = makeNodeFor(joint);

        joint->setJointId(state->getJointId());

        instData._bottomN->addChild(jointN);
        instData._bottomN = jointN;
    }

    if(startSkel == true)
    {
        // add a transform for the world matrix up to this node to put
        // the Skeleton in the correct coordinate system

        TransformUnrecPtr xform  = Transform::create();
        NodeUnrecPtr      xformN = makeNodeFor(xform);

        xform->setMatrix(state->getWorldMatrix());

        xformN->addChild(instData._topN);
        instData._topN = xformN;

        if(getGlobal()->getOptions()->getCreateNameAttachments() == true)
            setName(xformN, "SkeletonWorldMatrix");
    }

    // update world matrix before we instantiate child nodes, etc.
    state->pushMatrix(instData._localMatrix);

    // add <node> child elements
    const domNode_Array &nodes = node->getNode_array();

    for(UInt32 i = 0; i < nodes.getCount(); ++i)
        handleNode(nodes[i], instData);

    // add <instance_node> child elements
    const domInstance_node_Array &instNodes =
        node->getInstance_node_array();

    for(UInt32 i = 0; i < instNodes.getCount(); ++i)
        handleInstanceNode(instNodes[i], instData);

    // we don't handle other <instance_*> tags here, it does not
    // make sense to have them inside a skeleton

    editInstStore().push_back(instData._topN);
    _instDataStore .push_back(instData      );
    retVal = instData._topN;

    if(startSkel == true)
    {
        instData._skel->pushToRoots(instData._topN);

        state->setSkeleton(NULL);
        state->setJointId (SkeletonJoint::INVALID_JOINT_ID);
    }

    state->popMatrix  ();
    state->popNodePath();

    return retVal;
}
void
ColladaNode::read(void)
{
    OSG_COLLADA_LOG(("ColladaNode::read\n"));

    domNodeRef                node     = getDOMElementAs<domNode>();
    const daeElementRefArray &contents = node->getContents();

    // handle "transform" child elements in the order
    // they occur in the document

    for(UInt32 i = 0; i < contents.getCount(); ++i)
    {
        switch(contents[i]->getElementType())
        {
        case COLLADA_TYPE::LOOKAT:
            handleLookAt(daeSafeCast<domLookat>(contents[i]));
            break;
            
        case COLLADA_TYPE::MATRIX:
            handleMatrix(daeSafeCast<domMatrix>(contents[i]));
        break;
        
        case COLLADA_TYPE::ROTATE:
            handleRotate(daeSafeCast<domRotate>(contents[i]));
        break;
        
        case COLLADA_TYPE::SCALE:
            handleScale(daeSafeCast<domScale>(contents[i]));
        break;
        
        case COLLADA_TYPE::SKEW:
            handleSkew(daeSafeCast<domSkew>(contents[i]));
        break;
        
        case COLLADA_TYPE::TRANSLATE:
            handleTranslate(daeSafeCast<domTranslate>(contents[i]));
        break;
        }
    }

    // handle <node> child elements
    const domNode_Array &nodes = node->getNode_array();
    
    for(UInt32 i = 0; i < nodes.getCount(); ++i)
    {
        handleNode(nodes[i]);
    }

    // handle <instance_node> child elements
    const domInstance_node_Array &instNodes = node->getInstance_node_array();
    
    for(UInt32 i = 0; i < instNodes.getCount(); ++i)
    {
        handleInstanceNode(instNodes[i]);
    }

    // handle <instance_light> child elements
    const domInstance_light_Array &instLights = node->getInstance_light_array();
    for(UInt32 i = 0; i < instLights.getCount(); ++i)
    {
        handleInstanceLight(instLights[i]);
    }

    // handle <instance_geometry> child elements
    const domInstance_geometry_Array &instGeos =
        node->getInstance_geometry_array();

    for(UInt32 i = 0; i < instGeos.getCount(); ++i)
    {
        handleInstanceGeometry(instGeos[i]);
    }

    // handle <instance_controller> child elemnts
    const domInstance_controller_Array &instControllers =
        node->getInstance_controller_array();

    for(UInt32 i = 0; i < instControllers.getCount(); ++i)
    {
        handleInstanceController(instControllers[i]);
    }

    // nothing created? build a dummy node
    if(_topN == NULL)
    {
        _topN = makeCoredNode<Group>();

        if(getGlobal()->getOptions()->getCreateNameAttachments() == true &&
           node->getName()                                       != NULL   )
        {
            setName(_topN, node->getName());
        }
    }

    if(_bottomN == NULL)
    {
        _bottomN = _topN;
    }
}