void convertOpenCOLLADAMesh(COLLADAFW::Mesh* openCOLLADAMesh,
                             MeshVector &meshes)
 {
     shared_ptr <GLTF::GLTFMesh> cvtMesh(new GLTF::GLTFMesh());
     
     cvtMesh->setID(openCOLLADAMesh->getOriginalId());
     cvtMesh->setName(openCOLLADAMesh->getName());
     
     const COLLADAFW::MeshPrimitiveArray& primitives =  openCOLLADAMesh->getMeshPrimitives();
     size_t primitiveCount = primitives.getCount();
     
     std::vector< shared_ptr<IndicesVector> > allPrimitiveIndicesVectors;
     
     // get all primitives
     for (size_t i = 0 ; i < primitiveCount ; i++) {
         const COLLADAFW::MeshPrimitive::PrimitiveType primitiveType = primitives[i]->getPrimitiveType();
         if ((primitiveType != COLLADAFW::MeshPrimitive::TRIANGLES) &&
             (primitiveType != COLLADAFW::MeshPrimitive::TRIANGLE_STRIPS) &&
             (primitiveType != COLLADAFW::MeshPrimitive::POLYLIST) &&
             (primitiveType != COLLADAFW::MeshPrimitive::POLYGONS))
             continue;
         
         shared_ptr <GLTF::IndicesVector> primitiveIndicesVector(new GLTF::IndicesVector());
         allPrimitiveIndicesVectors.push_back(primitiveIndicesVector);
         
         shared_ptr <GLTF::GLTFPrimitive> primitive = ConvertOpenCOLLADAMeshPrimitive(primitives[i],*primitiveIndicesVector);
         cvtMesh->appendPrimitive(primitive);
         
         VertexAttributeVector vertexAttributes = primitive->getVertexAttributes();
         primitiveIndicesVector = allPrimitiveIndicesVectors[i];
         
         // once we got a primitive, keep track of its meshAttributes
         std::vector< shared_ptr<GLTF::GLTFIndices> > allIndices = *primitiveIndicesVector;
         for (size_t k = 0 ; k < allIndices.size() ; k++) {
             shared_ptr<GLTF::GLTFIndices> indices = allIndices[k];
             GLTF::Semantic semantic = vertexAttributes[k]->getSemantic();
             GLTF::IndexSetToMeshAttributeHashmap& meshAttributes = cvtMesh->getMeshAttributesForSemantic(semantic);
             
             switch (semantic) {
                 case GLTF::POSITION:
                     ConvertOpenCOLLADAMeshVertexDataToGLTFMeshAttributes(openCOLLADAMesh->getPositions(), meshAttributes);
                     break;
                     
                 case GLTF::NORMAL:
                     ConvertOpenCOLLADAMeshVertexDataToGLTFMeshAttributes(openCOLLADAMesh->getNormals(), meshAttributes);
                     break;
                     
                 case GLTF::TEXCOORD:
                     ConvertOpenCOLLADAMeshVertexDataToGLTFMeshAttributes(openCOLLADAMesh->getUVCoords(), meshAttributes);
                     break;
                     
                 case GLTF::COLOR:
                     ConvertOpenCOLLADAMeshVertexDataToGLTFMeshAttributes(openCOLLADAMesh->getColors(), meshAttributes);
                     break;
                     
                 default:
                     break;
             }
             
             cvtMesh->setMeshAttributesForSemantic(semantic, meshAttributes);
         }
     }
     
     //https://github.com/KhronosGroup/collada2json/issues/41
     //Goes through all texcoord and invert V
     GLTF::IndexSetToMeshAttributeHashmap& texcoordMeshAttributes = cvtMesh->getMeshAttributesForSemantic(GLTF::TEXCOORD);
     GLTF::IndexSetToMeshAttributeHashmap::const_iterator meshAttributeIterator;
     
     //FIXME: consider turn this search into a method for mesh
     for (meshAttributeIterator = texcoordMeshAttributes.begin() ; meshAttributeIterator != texcoordMeshAttributes.end() ; meshAttributeIterator++) {
         //(*it).first;             // the key value (of type Key)
         //(*it).second;            // the mapped value (of type T)
         shared_ptr <GLTF::GLTFMeshAttribute> meshAttribute = (*meshAttributeIterator).second;
         
         meshAttribute->apply(__InvertV, NULL);
     }
     
     if (cvtMesh->getPrimitives().size() > 0) {
         //After this point cvtMesh should be referenced anymore and will be deallocated
         shared_ptr <GLTF::GLTFMesh> unifiedMesh = createUnifiedIndexesMeshFromMesh(cvtMesh.get(), allPrimitiveIndicesVectors);
         if  (createMeshesWithMaximumIndicesCountFromMeshIfNeeded(unifiedMesh.get(), 65535, meshes) == false) {
             meshes.push_back(unifiedMesh);
         }
     }
 }
Exemple #2
0
bool createMeshesWithMaximumIndicesCountFromMeshIfNeeded(GLTFMesh *sourceMesh, unsigned int maxiumIndicesCount, MeshVector &meshes)
{
    bool splitNeeded = false;

    //First, check every primitive indices count to figure out if we really need to split anything at all.
    //TODO: what about making a sanity check, to ensure we don't have points not referenced by any primitive. (I wonder if that's would be considered compliant with the SPEC. need to check.
    PrimitiveVector primitives = sourceMesh->getPrimitives();

    for (size_t i = 0 ; i < primitives.size() ; i++) {
        if (primitives[i]->getIndices()->getCount() >= maxiumIndicesCount) {
            splitNeeded = true;
            break;
        }
    }

    if (!splitNeeded)
        return false;

    SubMeshContext *subMesh = NULL;

    bool stillHavePrimitivesElementsToBeProcessed = false;
    bool primitiveCompleted = false;

    int *allNextPrimitiveIndices = (int*)calloc(primitives.size(), sizeof(int));
    unsigned int meshIndex = 0;
    for (size_t i = 0 ; i < primitives.size() ; i++) {
        if (allNextPrimitiveIndices[i] == -1)
            continue;

        if (subMesh == 0) {
            subMesh = __CreateSubMeshContext();
            meshes.push_back(subMesh->targetMesh);
            std::string meshID = "";
            std::string meshName = "";

            meshID += sourceMesh->getID();
            meshName += sourceMesh->getName();
            if (meshIndex) {
                meshID += "-"+ GLTFUtils::toString(meshIndex);
                meshName += "-"+ GLTFUtils::toString(meshIndex);
            }
            subMesh->targetMesh->setID(meshID);
            subMesh->targetMesh->setName(meshName);

            stillHavePrimitivesElementsToBeProcessed = false;
            meshIndex++;
        }

        shared_ptr <GLTFPrimitive> targetPrimitive;
        //when we are done with a primitive we mark its nextIndice with a -1

        targetPrimitive = shared_ptr <GLTFPrimitive> (new GLTFPrimitive((*primitives[i])));

        unsigned int nextPrimitiveIndex = (unsigned int)allNextPrimitiveIndices[i];

        shared_ptr<GLTFPrimitive> &primitive = primitives[i];
        shared_ptr<GLTFIndices> indices = primitive->getIndices();

        unsigned int* indicesPtr = (unsigned int*)indices->getBufferView()->getBufferDataByApplyingOffset();
        unsigned int* targetIndicesPtr = (unsigned int*)malloc(indices->getBufferView()->getBuffer()->getByteLength());

        //sub meshes are built this way [ and it is not optimal yet (*)]:
        //each primitive is iterated through all its triangles/lines/...
        //When the indices count in indexToRemappedIndex is >= maxiumIndicesCount then we try the next primitive.
        /*
            we could continue walking through a primitive even if the of maximum indices has been reached, because, for instance the next say, triangles could be within the already remapped indices. That said, not doing so should produce meshes that have more chances to have adjacent triangles. Need more experimentation about this. Having 2 modes would ideal.
         */


        //Different iterators type will be needed for these types
        /*
         type = "TRIANGLES";
         type = "LINES";
         type = "LINE_STRIP";
         type = "TRIANGLES";
         type = "TRIANGLE_FANS";
         type = "TRIANGLE_STRIPS";
         type = "POINTS";
         */
        size_t j = 0;
        unsigned int primitiveCount = 0;
        unsigned int targetIndicesCount = 0;
        if (primitive->getType() == "TRIANGLES") {
            unsigned int indicesPerElementCount = 3;
            primitiveCount = indices->getCount() / indicesPerElementCount;
            for (j = nextPrimitiveIndex ; j < primitiveCount ; j++) {
                unsigned int *indicesPtrAtPrimitiveIndex = indicesPtr + (j * indicesPerElementCount);
                //will we still have room to store coming indices from this mesh ?
                //note: this is tied to the policy described above in (*)
                size_t currentSize = subMesh->indexToRemappedIndex.size();
                if ((currentSize + indicesPerElementCount) < maxiumIndicesCount) {
                    __PushAndRemapIndicesInSubMesh(subMesh, indicesPtrAtPrimitiveIndex, indicesPerElementCount);

                    //build the indices for the primitive to be added to the subMesh
                    targetIndicesPtr[targetIndicesCount] = subMesh->indexToRemappedIndex[indicesPtrAtPrimitiveIndex[0]];
                    targetIndicesPtr[targetIndicesCount + 1] = subMesh->indexToRemappedIndex[indicesPtrAtPrimitiveIndex[1]];
                    targetIndicesPtr[targetIndicesCount + 2] = subMesh->indexToRemappedIndex[indicesPtrAtPrimitiveIndex[2]];

                    targetIndicesCount += indicesPerElementCount;

                    nextPrimitiveIndex++;
                } else {
                    allNextPrimitiveIndices[i] = -1;
                    primitiveCompleted = true;
                    break;
                }
            }
        }

        allNextPrimitiveIndices[i] = nextPrimitiveIndex;

        if (targetIndicesCount > 0) {
            //FIXME: here targetIndices takes too much memory
            //To avoid this we would need to make a smaller copy.
            //In our case not sure if that's really a problem since this buffer won't be around for too long, as each buffer is deallocated once the callback from OpenCOLLADA to handle geomery has completed.

            shared_ptr <GLTFBufferView> targetBufferView = createBufferViewWithAllocatedBuffer(targetIndicesPtr, 0,targetIndicesCount * sizeof(unsigned int), true);

            shared_ptr <GLTFIndices> indices(new GLTFIndices(targetBufferView, targetIndicesCount));
            targetPrimitive->setIndices(indices);

            subMesh->targetMesh->appendPrimitive(targetPrimitive);
        } else {
            if (targetIndicesPtr)
                free(targetIndicesPtr);
        }

        if (j < primitiveCount)
            stillHavePrimitivesElementsToBeProcessed = true;

        //did we process the last primitive ?
        if (primitiveCompleted || (((i + 1) == primitives.size()))) {
            __RemapSubMesh(subMesh, sourceMesh);
            if (stillHavePrimitivesElementsToBeProcessed) {
                //loop again and build new mesh
                i = -1;
                delete subMesh;
                subMesh = 0;
            }
        }
    }

    free(allNextPrimitiveIndices);

    return true;
}