Beispiel #1
0
 /*
  Convert an OpenCOLLADA's FloatOrDoubleArray type to a GLTFBufferView
  Note: the resulting GLTFBufferView is not typed, it's the call responsability to keep track of the type if needed.
  */
 shared_ptr <GLTFBufferView> convertFloatOrDoubleArrayToGLTFBufferView(const COLLADAFW::FloatOrDoubleArray &floatOrDoubleArray) {
     unsigned char* sourceData = 0;
     size_t sourceSize = 0;
     
     switch (floatOrDoubleArray.getType()) {
         case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT: {
             const COLLADAFW::FloatArray* array = floatOrDoubleArray.getFloatValues();
             
             sourceData = (unsigned char*)array->getData();
             sourceSize = array->getCount() * sizeof(float);
         }
             break;
         case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE: {
             const COLLADAFW::DoubleArray* array = floatOrDoubleArray.getDoubleValues();
             
             sourceData = (unsigned char*)array->getData();
             sourceSize = array->getCount() * sizeof(double);
         }
             break;
         default:
         case COLLADAFW::MeshVertexData::DATA_TYPE_UNKNOWN:
             //FIXME report error
             break;
     }
     unsigned char* copiedData = (unsigned char*)malloc(sourceSize);
     memcpy(copiedData, sourceData, sourceSize);
     
     shared_ptr <GLTF::GLTFBufferView> bufferView = createBufferViewWithAllocatedBuffer(copiedData, 0, sourceSize, true);
     
     return bufferView;
 }
Beispiel #2
0
 //FIXME: these 3 functions up there could use some refactoring
 shared_ptr <GLTFBufferView> convertIntArrayToGLTFBufferView(const COLLADAFW::IntValuesArray &array) {
     unsigned char* sourceData = (unsigned char*)array.getData();
     size_t sourceSize = array.getCount() * sizeof(int);
     unsigned char* copiedData = (unsigned char*)malloc(sourceSize);
     memcpy(copiedData, sourceData, sourceSize);
     shared_ptr <GLTF::GLTFBufferView> bufferView = createBufferViewWithAllocatedBuffer(copiedData, 0, sourceSize, true);
     
     return bufferView;
 }
Beispiel #3
0
shared_ptr<GLTF::GLTFPrimitiveRemapInfos> __BuildPrimitiveUniqueIndexes(shared_ptr<GLTF::GLTFPrimitive> primitive,
        std::vector< shared_ptr<GLTF::GLTFIndices> > allIndices,
        RemappedMeshIndexesHashmap& remappedMeshIndexesMap,
        unsigned int* indicesInRemapping,
        size_t startIndex,
        unsigned int meshAttributesCount,
        size_t &endIndex)
{
    unsigned int generatedIndicesCount = 0;

    size_t allIndicesSize = allIndices.size();
    size_t vertexIndicesCount = allIndices[0]->getCount();
    size_t sizeOfRemappedIndex = (meshAttributesCount + 1) * sizeof(unsigned int);

    unsigned int* originalCountAndIndexes = (unsigned int*)calloc( vertexIndicesCount, sizeOfRemappedIndex);
    //this is useful for debugging.

    unsigned int *uniqueIndexes = (unsigned int*)calloc( vertexIndicesCount , sizeof(unsigned int));
    unsigned int *generatedIndices = (unsigned int*) calloc (vertexIndicesCount , sizeof(unsigned int)); //owned by PrimitiveRemapInfos
    unsigned int currentIndex = startIndex;

    for (size_t k = 0 ; k < vertexIndicesCount ; k++) {
        unsigned int* remappedIndex = &originalCountAndIndexes[k * (meshAttributesCount + 1)];

        remappedIndex[0] = meshAttributesCount;
        for (unsigned int i = 0 ; i < allIndicesSize ; i++) {
            unsigned int idx = indicesInRemapping[i];
            unsigned int* indicesPtr = (unsigned int*)allIndices[i]->getBufferView()->getBufferDataByApplyingOffset();
            remappedIndex[1 + idx] = indicesPtr[k];
        }

        unsigned int index;
        if (remappedMeshIndexesMap.count(remappedIndex) == 0) {
            index = currentIndex++;
            generatedIndices[generatedIndicesCount++] = (unsigned int)k;
            remappedMeshIndexesMap[remappedIndex] = index;
        } else {
            index = remappedMeshIndexesMap[remappedIndex];
        }
        uniqueIndexes[k] = index;
    }

    endIndex = currentIndex;
    shared_ptr <GLTF::GLTFPrimitiveRemapInfos> primitiveRemapInfos(new GLTF::GLTFPrimitiveRemapInfos(generatedIndices, generatedIndicesCount, originalCountAndIndexes));
    shared_ptr <GLTF::GLTFBufferView> indicesBufferView = createBufferViewWithAllocatedBuffer(uniqueIndexes, 0, vertexIndicesCount * sizeof(unsigned int), true);

    shared_ptr <GLTF::GLTFIndices> indices = shared_ptr <GLTF::GLTFIndices> (new GLTF::GLTFIndices(indicesBufferView, vertexIndicesCount));

    primitive->setIndices(indices);

    return primitiveRemapInfos;
}
Beispiel #4
0
 static void __HandleIndexList(unsigned int idx,
                               COLLADAFW::IndexList *indexList,
                               Semantic semantic,
                               bool shouldTriangulate,
                               unsigned int count,
                               unsigned int vcount,
                               unsigned int *verticesCountArray,
                               shared_ptr <GLTF::GLTFPrimitive> cvtPrimitive,
                               IndicesVector &primitiveIndicesVector
                               )
 {
     unsigned int triangulatedIndicesCount = 0;
     bool ownData = false;
     unsigned int *indices = indexList->getIndices().getData();
     
     if (shouldTriangulate) {
         indices = createTrianglesFromPolylist(verticesCountArray, indices, vcount, &triangulatedIndicesCount);
         count = triangulatedIndicesCount;
         ownData = true;
     }
     
     //Why is OpenCOLLADA doing this ? why adding an offset the indices ??
     //We need to offset it backward here.
     unsigned int initialIndex = indexList->getInitialIndex();
     if (initialIndex != 0) {
         unsigned int *bufferDestination = 0;
         if (!ownData) {
             bufferDestination = (unsigned int*)malloc(sizeof(unsigned int) * count);
             ownData = true;
         } else {
             bufferDestination = indices;
         }
         for (size_t idx = 0 ; idx < count ; idx++) {
             bufferDestination[idx] = indices[idx] - initialIndex;
         }
         indices = bufferDestination;
     }
     
     shared_ptr <GLTF::GLTFBufferView> uvBuffer = createBufferViewWithAllocatedBuffer(indices, 0, count * sizeof(unsigned int), ownData);
     
     //FIXME: Looks like for texcoord indexSet begin at 1, this is out of the sync with the index used in ConvertOpenCOLLADAMeshVertexDataToGLTFMeshAttributes that begins at 0
     //for now forced to 0, to be fixed for multi texturing.
     
     //unsigned int idx = (unsigned int)indexList->getSetIndex();
     
     shared_ptr <GLTFIndices> jsonIndices(new GLTFIndices(uvBuffer, count));
     __AppendIndices(cvtPrimitive, primitiveIndicesVector, jsonIndices, semantic, idx);
 }
Beispiel #5
0
    static void __HandleIndexList(unsigned int idx,
                                  COLLADAFW::IndexList *indexList,
                                  Semantic semantic,
                                  bool shouldTriangulate,
                                  unsigned int count,
                                  unsigned int vcount,
                                  unsigned int *verticesCountArray,
                                  shared_ptr <GLTF::GLTFPrimitive> cvtPrimitive,
                                  IndicesVector &primitiveIndicesVector,
                                  shared_ptr<GLTFProfile> profile)
    {
        unsigned int triangulatedIndicesCount = 0;
        bool ownData = false;
        unsigned int *indices = indexList->getIndices().getData();
        
        if (shouldTriangulate) {
            indices = createTrianglesFromPolylist(verticesCountArray, indices, vcount, &triangulatedIndicesCount);
            count = triangulatedIndicesCount;
            ownData = true;
        }
        
        //Why is OpenCOLLADA doing this ? why adding an offset the indices ??
        //We need to offset it backward here.
		unsigned int initialIndex = (unsigned int)indexList->getInitialIndex();
        if (initialIndex != 0) {
            unsigned int *bufferDestination = 0;
            if (!ownData) {
                bufferDestination = (unsigned int*)malloc(sizeof(unsigned int) * count);
                ownData = true;
            } else {
                bufferDestination = indices;
            }
            for (size_t idx = 0 ; idx < count ; idx++) {
                bufferDestination[idx] = indices[idx] - initialIndex;
            }
            indices = bufferDestination;
        }
        
        shared_ptr <GLTF::GLTFBufferView> uvBuffer = createBufferViewWithAllocatedBuffer(indices, 0, count * sizeof(unsigned int), ownData);
        shared_ptr <GLTFAccessor> accessor(new GLTFAccessor(profile, profile->getGLenumForString("UNSIGNED_SHORT")));
        
        accessor->setBufferView(uvBuffer);
        accessor->setCount(count);
        
        __AppendIndices(cvtPrimitive, primitiveIndicesVector, accessor, semantic, idx);
    }
Beispiel #6
0
 /*
     Since GLTF does not have the same granularity as COLLADA, we need in some situations to duplicate a few datas.
     For instance a target path like position.x is not supported by glTF, just the 3 components (x,y,z) can be animated.
     This function create a buffer that will allow to handle a target path supported by GLTF.
  */
 static shared_ptr<GLTFBufferView> __CreateBufferViewByReplicatingArrayAndReplacingValueAtIndex(shared_ptr<GLTFBufferView> bufferView,
                                                                                                shared_ptr<JSONArray> array,
                                                                                                size_t index,
                                                                                                std::string type,
                                                                                                size_t keyCount) {
     
     char *destinationBuffer = 0;
     char *sourceBuffer = (char*)bufferView->getBufferDataByApplyingOffset();
     size_t elementSize = 0;
     size_t offset = 0;
     //TODO handle other types
     if (type == "FLOAT") {
         elementSize = sizeof(float);
         offset = (elementSize * array->values().size());
     }
     
     size_t destinationBufferLength = offset * keyCount;
     
     if (elementSize != 0) {
         //FIXME: should not assume FLOAT here
         size_t count = array->values().size();
         float *values = (float*)malloc(elementSize * count);
         for (size_t i = 0 ; i < count ; i++) {
             shared_ptr <JSONNumber> nb = static_pointer_cast<JSONNumber>(array->values()[i]);
             values[i] = (float)nb->getDouble();
         }
         
         destinationBuffer = (char*)malloc(destinationBufferLength);
         for (size_t i = 0 ; i < keyCount ; i++) {
             memcpy(destinationBuffer + (offset * i), values, offset);
             memcpy(destinationBuffer + (offset * i) + (index * elementSize) ,
                    sourceBuffer + (i * elementSize) ,
                    elementSize);
         }
         
         free(values);
         
     } else {
         //TODO:..
         printf("WARNING attempt to use __CreateBufferViewByReplicatingArrayAndReplacingValueAtIndex without using floats\n");
     }
     
     return  createBufferViewWithAllocatedBuffer(destinationBuffer, 0, destinationBufferLength, true);
 }
Beispiel #7
0
//FIXME: add suport for interleaved arrays
void __RemapSubMesh(SubMeshContext *subMesh, GLTFMesh *sourceMesh)
{
    //remap the subMesh using the original mesh
    //we walk through all meshAttributes
    vector <GLTF::Semantic> allSemantics = sourceMesh->allSemantics();
    std::map<string, unsigned int> semanticAndSetToIndex;

    for (unsigned int i = 0 ; i < allSemantics.size() ; i++) {
        IndexSetToMeshAttributeHashmap& indexSetToMeshAttribute = sourceMesh->getMeshAttributesForSemantic(allSemantics[i]);
        IndexSetToMeshAttributeHashmap& targetIndexSetToMeshAttribute = subMesh->targetMesh->getMeshAttributesForSemantic(allSemantics[i]);
        IndexSetToMeshAttributeHashmap::const_iterator meshAttributeIterator;
        for (meshAttributeIterator = indexSetToMeshAttribute.begin() ; meshAttributeIterator != indexSetToMeshAttribute.end() ; meshAttributeIterator++) {
            //(*it).first;             // the key value (of type Key)
            //(*it).second;            // the mapped value (of type T)
            shared_ptr <GLTFMeshAttribute> selectedMeshAttribute = (*meshAttributeIterator).second;
            unsigned int indexSet = (*meshAttributeIterator).first;

            shared_ptr <GLTFBufferView> referenceBufferView = selectedMeshAttribute->getBufferView();

            unsigned int vertexAttributeCount = subMesh->indexToRemappedIndex.size();

            //FIXME: this won't work with interleaved
            unsigned int *targetBufferPtr = (unsigned int*)malloc(selectedMeshAttribute->getVertexAttributeByteLength() * vertexAttributeCount);

            void *context[2];
            context[0] = targetBufferPtr;
            context[1] = subMesh;
            selectedMeshAttribute->apply(__RemapMeshAttribute, (void*)context);

            shared_ptr <GLTFBufferView> remappedBufferView =
                createBufferViewWithAllocatedBuffer(referenceBufferView->getID(), targetBufferPtr, 0, selectedMeshAttribute->getVertexAttributeByteLength() * vertexAttributeCount, true);

            shared_ptr <GLTFMeshAttribute> remappedMeshAttribute(new GLTF::GLTFMeshAttribute(selectedMeshAttribute.get()));
            remappedMeshAttribute->setBufferView(remappedBufferView);
            remappedMeshAttribute->setCount(vertexAttributeCount);

            targetIndexSetToMeshAttribute[indexSet] = remappedMeshAttribute;
        }
    }
}
Beispiel #8
0
 static shared_ptr <GLTF::GLTFPrimitive> ConvertOpenCOLLADAMeshPrimitive(
                                                                         COLLADAFW::MeshPrimitive *openCOLLADAMeshPrimitive,
                                                                         IndicesVector &primitiveIndicesVector)
 {
     shared_ptr <GLTF::GLTFPrimitive> cvtPrimitive(new GLTF::GLTFPrimitive());
     
     // We want to match OpenGL/ES mode , as WebGL spec points to OpenGL/ES spec...
     // "Symbolic constants GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, and GL_TRIANGLES are accepted."
     std::string type;
     bool shouldTriangulate = false;
     
     switch(openCOLLADAMeshPrimitive->getPrimitiveType()) {
             //these 2 requires transforms
         case COLLADAFW::MeshPrimitive::POLYLIST:
         case COLLADAFW::MeshPrimitive::POLYGONS:
             // FIXME: perform conversion, but until not done report error
             //these mode are supported by WebGL
             shouldTriangulate = true;
             //force triangles
             type = "TRIANGLES";
             break;
         case  COLLADAFW::MeshPrimitive::LINES:
             type = "LINES";
             break;
         case  COLLADAFW::MeshPrimitive::LINE_STRIPS:
             type = "LINE_STRIP";
             break;
             
         case  COLLADAFW::MeshPrimitive::TRIANGLES:
             type = "TRIANGLES";
             break;
             
         case  COLLADAFW::MeshPrimitive::TRIANGLE_FANS:
             type = "TRIANGLE_FANS";
             break;
             
         case  COLLADAFW::MeshPrimitive::TRIANGLE_STRIPS:
             type = "TRIANGLE_STRIPS";
             break;
             
         case  COLLADAFW::MeshPrimitive::POINTS:
             type = "POINTS";
             break;
         default:
             break;
     }
     
     cvtPrimitive->setMaterialObjectID((unsigned int)openCOLLADAMeshPrimitive->getMaterialId());
     cvtPrimitive->setType(type);
     
     //count of indices , it must be the same for all kind of indices
     size_t count = openCOLLADAMeshPrimitive->getPositionIndices().getCount();
     
     //vertex
     //IndexList &positionIndexList = openCOLLADAMeshPrimitive->getPositionIndices();
     unsigned int *indices = openCOLLADAMeshPrimitive->getPositionIndices().getData();
     unsigned int *verticesCountArray = 0;
     unsigned int vcount = 0;   //count of elements in the array containing the count of indices per polygon & polylist.
     
     if (shouldTriangulate) {
         unsigned int triangulatedIndicesCount = 0;
         //We have to upcast to polygon to retrieve the array of vertexCount
         //OpenCOLLADA use polylist as polygon.
         COLLADAFW::Polygons *polygon = (COLLADAFW::Polygons*)openCOLLADAMeshPrimitive;
         const COLLADAFW::Polygons::VertexCountArray& vertexCountArray = polygon->getGroupedVerticesVertexCountArray();
         vcount = (unsigned int)vertexCountArray.getCount();
         verticesCountArray = (unsigned int*)malloc(sizeof(unsigned int) * vcount);
         for (size_t i = 0; i < vcount; i++) {
             verticesCountArray[i] = polygon->getGroupedVerticesVertexCount(i);;
         }
         indices = createTrianglesFromPolylist(verticesCountArray, indices, vcount, &triangulatedIndicesCount);
         count = triangulatedIndicesCount;
     }
     
     shared_ptr <GLTFBufferView> positionBuffer = createBufferViewWithAllocatedBuffer(indices, 0, count * sizeof(unsigned int), shouldTriangulate ? true : false);
     
     shared_ptr <GLTF::GLTFIndices> positionIndices(new GLTF::GLTFIndices(positionBuffer,count));
     
     __AppendIndices(cvtPrimitive, primitiveIndicesVector, positionIndices, POSITION, 0);
     
     if (openCOLLADAMeshPrimitive->hasNormalIndices()) {
         unsigned int triangulatedIndicesCount = 0;
         indices = openCOLLADAMeshPrimitive->getNormalIndices().getData();
         if (shouldTriangulate) {
             indices = createTrianglesFromPolylist(verticesCountArray, indices, vcount, &triangulatedIndicesCount);
             count = triangulatedIndicesCount;
         }
         
         shared_ptr <GLTF::GLTFBufferView> normalBuffer = createBufferViewWithAllocatedBuffer(indices, 0, count * sizeof(unsigned int), shouldTriangulate ? true : false);
         shared_ptr <GLTF::GLTFIndices> normalIndices(new GLTF::GLTFIndices(normalBuffer,
                                                                            count));
         __AppendIndices(cvtPrimitive, primitiveIndicesVector, normalIndices, NORMAL, 0);
     }
     
     if (openCOLLADAMeshPrimitive->hasColorIndices()) {
         COLLADAFW::IndexListArray& colorListArray = openCOLLADAMeshPrimitive->getColorIndicesArray();
         for (size_t i = 0 ; i < colorListArray.getCount() ; i++) {
             COLLADAFW::IndexList* indexList = openCOLLADAMeshPrimitive->getColorIndices(i);
             __HandleIndexList(i,
                               indexList,
                               GLTF::COLOR,
                               shouldTriangulate,
                               count,
                               vcount,
                               verticesCountArray,
                               cvtPrimitive,
                               primitiveIndicesVector);
         }
     }
     
     if (openCOLLADAMeshPrimitive->hasUVCoordIndices()) {
         COLLADAFW::IndexListArray& uvListArray = openCOLLADAMeshPrimitive->getUVCoordIndicesArray();
         for (size_t i = 0 ; i < uvListArray.getCount() ; i++) {
             COLLADAFW::IndexList* indexList = openCOLLADAMeshPrimitive->getUVCoordIndices(i);
             __HandleIndexList(i,
                               indexList,
                               GLTF::TEXCOORD,
                               shouldTriangulate,
                               count,
                               vcount,
                               verticesCountArray,
                               cvtPrimitive,
                               primitiveIndicesVector);
         }
     }
     
     if (verticesCountArray) {
         free(verticesCountArray);
     }
     
     return cvtPrimitive;
 }
Beispiel #9
0
 static unsigned int ConvertOpenCOLLADAMeshVertexDataToGLTFMeshAttributes(const COLLADAFW::MeshVertexData &vertexData, GLTF::IndexSetToMeshAttributeHashmap &meshAttributes)
 {
     // The following are OpenCOLLADA fmk issues preventing doing a totally generic processing of sources
     //1. "set"(s) other than texCoord don't have valid input infos
     //2. not the original id in the source
     
     std::string name;
     size_t length, elementsCount;
     size_t stride = 0;
     size_t size = 0;
     size_t byteOffset = 0;
     size_t inputLength = 0;
     
     size_t setCount = vertexData.getNumInputInfos();
     bool unpatchedOpenCOLLADA = (setCount == 0); // reliable heuristic to know if the input have not been set
     
     if (unpatchedOpenCOLLADA)
         setCount = 1;
     
     for (size_t indexOfSet = 0 ; indexOfSet < setCount ; indexOfSet++) {
         
         if (!unpatchedOpenCOLLADA) {
             name = vertexData.getName(indexOfSet);
             size = vertexData.getStride(indexOfSet);
             inputLength = vertexData.getLength(indexOfSet);
         } else {
             // for unpatched version of OpenCOLLADA we need this work-around.
             name = GLTF::GLTFUtils::generateIDForType("buffer").c_str();
             size = 3; //only normal and positions should reach this code
             inputLength = vertexData.getLength(0);
         }
         
         //name is the id
         length = inputLength ? inputLength : vertexData.getValuesCount();
         elementsCount = length / size;
         unsigned char *sourceData = 0;
         size_t sourceSize = 0;
         
         GLTF::ComponentType componentType = GLTF::NOT_AN_ELEMENT_TYPE;
         switch (vertexData.getType()) {
             case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT: {
                 componentType = GLTF::FLOAT;
                 stride = sizeof(float) * size;
                 const COLLADAFW::FloatArray* array = vertexData.getFloatValues();
                 
                 sourceData = (unsigned char*)array->getData() + byteOffset;
                 
                 sourceSize = length * sizeof(float);
                 byteOffset += sourceSize; //Doh! - OpenCOLLADA store all sets contiguously in the same array
             }
                 break;
             case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE: {
                 /*
                  sourceType = DOUBLE;
                  
                  const DoubleArray& array = vertexData.getDoubleValues()[indexOfSet];
                  const size_t count = array.getCount();
                  sourceData = (void*)array.getData();
                  sourceSize = count * sizeof(double);
                  */
                 // Warning if can't make "safe" conversion
             }
                 
                 break;
             default:
             case COLLADAFW::MeshVertexData::DATA_TYPE_UNKNOWN:
                 //FIXME report error
                 break;
         }
         
         // FIXME: the source could be shared, store / retrieve it here
         shared_ptr <GLTFBufferView> cvtBufferView = createBufferViewWithAllocatedBuffer(name, sourceData, 0, sourceSize, false);
         shared_ptr <GLTFMeshAttribute> cvtMeshAttribute(new GLTFMeshAttribute());
         
         cvtMeshAttribute->setBufferView(cvtBufferView);
         cvtMeshAttribute->setComponentsPerAttribute(size);
         cvtMeshAttribute->setByteStride(stride);
         cvtMeshAttribute->setComponentType(componentType);
         cvtMeshAttribute->setCount(elementsCount);
         
         meshAttributes[(unsigned int)indexOfSet] = cvtMeshAttribute;
     }
     
     return (unsigned int)setCount;
 }
Beispiel #10
0
    static unsigned int __ConvertOpenCOLLADAMeshVertexDataToGLTFAccessors(const COLLADAFW::MeshVertexData &vertexData,
                                                                          GLTFMesh* mesh,
                                                                          GLTF::Semantic semantic,
                                                                          size_t allowedComponentsPerAttribute,
                                                                          shared_ptr<GLTFProfile> profile)
    {
        // The following are OpenCOLLADA fmk issues preventing doing a totally generic processing of sources
        //1. "set"(s) other than texCoord don't have valid input infos
        //2. not the original id in the source
        
        std::string id;
        size_t length, elementsCount;
        size_t stride = 0;
        size_t componentsPerElement = 0;
        size_t byteOffset = 0;
        size_t inputLength = 0;
        
        size_t setCount = vertexData.getNumInputInfos();
        bool unpatchedOpenCOLLADA = (setCount == 0); // reliable heuristic to know if the input have not been set
        
        if (unpatchedOpenCOLLADA)
            setCount = 1;
        
        for (size_t indexOfSet = 0 ; indexOfSet < setCount ; indexOfSet++) {
            bool meshAttributeOwnsBuffer = false;

            if (!unpatchedOpenCOLLADA) {
                id = vertexData.getName(indexOfSet);
                componentsPerElement = vertexData.getStride(indexOfSet);
                inputLength = vertexData.getLength(indexOfSet);
            } else {
                // for unpatched version of OpenCOLLADA we need this work-around.
                id = GLTF::GLTFUtils::generateIDForType("buffer").c_str();
                componentsPerElement = 3; //only normal and positions should reach this code
                inputLength = vertexData.getLength(0);
            }
            
            length = inputLength ? inputLength : vertexData.getValuesCount();
            elementsCount = length / componentsPerElement;
            unsigned char *sourceData = 0;
            size_t sourceSize = 0;
            
            GLTF::ComponentType componentType = GLTF::NOT_AN_ELEMENT_TYPE;
            switch (vertexData.getType()) {
                case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT: {
                    componentType = GLTF::FLOAT;
                    stride = sizeof(float) * componentsPerElement;
                    const COLLADAFW::FloatArray* array = vertexData.getFloatValues();
                    
                    sourceData = (unsigned char*)array->getData() + byteOffset;
                    sourceSize = length * sizeof(float);

                     byteOffset += sourceSize; //Doh! - OpenCOLLADA store all sets contiguously in the same array
                }
                    break;
                case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE: {
                    //FIXME: handle this
                    /*
                     sourceType = DOUBLE;
                     
                     const DoubleArray& array = vertexData.getDoubleValues()[indexOfSet];
                     const size_t count = array.getCount();
                     sourceData = (void*)array.getData();
                     sourceSize = length * sizeof(double);
                     */
                    // Warning if can't make "safe" conversion
                }
                    
                    break;
                default:
                case COLLADAFW::MeshVertexData::DATA_TYPE_UNKNOWN:
                    //FIXME report error
                    break;
            }
            
            //FIXME: this is assuming float
            if (allowedComponentsPerAttribute != componentsPerElement) {
                sourceSize = elementsCount * sizeof(float) * allowedComponentsPerAttribute;
                
                float *adjustedSource = (float*)malloc(sourceSize);
                float *originalSource = (float*)sourceData;
                size_t adjustedStride = sizeof(float) * allowedComponentsPerAttribute;
                
                if (allowedComponentsPerAttribute < componentsPerElement) {
                    for (size_t i = 0 ; i < elementsCount ; i++) {
                        for (size_t j= 0 ; j < allowedComponentsPerAttribute ; j++) {
                            adjustedSource[(i*allowedComponentsPerAttribute) + j] = originalSource[(i*componentsPerElement) + j];
                        }
                    }
                } else {
                    //FIXME: unlikely but should be taken care of
                }

                //Free source before replacing it
                if (meshAttributeOwnsBuffer) {
                    free(sourceData);
                }
                
                componentsPerElement = allowedComponentsPerAttribute;
                meshAttributeOwnsBuffer = true;
                sourceData = (unsigned char*)adjustedSource;
                stride = adjustedStride;
            }
            
            // FIXME: the source could be shared, store / retrieve it here
            shared_ptr <GLTFBufferView> cvtBufferView = createBufferViewWithAllocatedBuffer(id, sourceData, 0, sourceSize, meshAttributeOwnsBuffer);
            shared_ptr <GLTFAccessor> cvtMeshAttribute(new GLTFAccessor(profile, profile->getGLTypeForComponentType(componentType, componentsPerElement)));
            
            cvtMeshAttribute->setBufferView(cvtBufferView);
            cvtMeshAttribute->setByteStride(stride);
            cvtMeshAttribute->setCount(elementsCount);
            
            mesh->setMeshAttribute(semantic, indexOfSet, cvtMeshAttribute);
        }
        
        return (unsigned int)setCount;
    }
Beispiel #11
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;
}
Beispiel #12
0
shared_ptr <GLTFMesh> createUnifiedIndexesMeshFromMesh(GLTFMesh *sourceMesh, std::vector< shared_ptr<IndicesVector> > &vectorOfIndicesVector)
{
    MeshAttributeVector originalMeshAttributes;
    MeshAttributeVector remappedMeshAttributes;
    shared_ptr <GLTFMesh> targetMesh(new GLTFMesh(*sourceMesh));

    PrimitiveVector sourcePrimitives = sourceMesh->getPrimitives();
    PrimitiveVector targetPrimitives = targetMesh->getPrimitives();

    size_t startIndex = 0;
    size_t endIndex = 0;
    size_t primitiveCount = sourcePrimitives.size();
    unsigned int maxVertexAttributes = 0;

    if (primitiveCount == 0) {
        // FIXME: report error
        //return 0;
    }

    //in originalMeshAttributes we'll get the flattened list of all the meshAttributes as a vector.
    //fill semanticAndSetToIndex with key: (semantic, indexSet) value: index in originalMeshAttributes vector.
    vector <GLTF::Semantic> allSemantics = sourceMesh->allSemantics();
    std::map<string, unsigned int> semanticAndSetToIndex;

    for (unsigned int i = 0 ; i < allSemantics.size() ; i++) {
        IndexSetToMeshAttributeHashmap& indexSetToMeshAttribute = sourceMesh->getMeshAttributesForSemantic(allSemantics[i]);
        IndexSetToMeshAttributeHashmap::const_iterator meshAttributeIterator;
        for (meshAttributeIterator = indexSetToMeshAttribute.begin() ; meshAttributeIterator != indexSetToMeshAttribute.end() ; meshAttributeIterator++) {
            //(*it).first;             // the key value (of type Key)
            //(*it).second;            // the mapped value (of type T)
            shared_ptr <GLTF::GLTFMeshAttribute> selectedMeshAttribute = (*meshAttributeIterator).second;
            unsigned int indexSet = (*meshAttributeIterator).first;
            GLTF::Semantic semantic = allSemantics[i];
            std::string semanticIndexSetKey = keyWithSemanticAndSet(semantic, indexSet);
            unsigned int size = (unsigned int)originalMeshAttributes.size();
            semanticAndSetToIndex[semanticIndexSetKey] = size;

            originalMeshAttributes.push_back(selectedMeshAttribute);
        }
    }

    maxVertexAttributes = (unsigned int)originalMeshAttributes.size();

    vector <shared_ptr<GLTF::GLTFPrimitiveRemapInfos> > allPrimitiveRemapInfos;

    //build a array that maps the meshAttributes that the indices points to with the index of the indice.
    GLTF::RemappedMeshIndexesHashmap remappedMeshIndexesMap;
    for (unsigned int i = 0 ; i < primitiveCount ; i++) {
        shared_ptr<IndicesVector>  allIndicesSharedPtr = vectorOfIndicesVector[i];
        IndicesVector *allIndices = allIndicesSharedPtr.get();
        unsigned int* indicesInRemapping = (unsigned int*)malloc(sizeof(unsigned int) * allIndices->size());


        VertexAttributeVector vertexAttributes = sourcePrimitives[i]->getVertexAttributes();
        for (unsigned int k = 0 ; k < allIndices->size() ; k++) {
            GLTF::Semantic semantic = vertexAttributes[k]->getSemantic();
            unsigned int indexSet = vertexAttributes[k]->getIndexOfSet();
            std::string semanticIndexSetKey = keyWithSemanticAndSet(semantic, indexSet);
            unsigned int idx = semanticAndSetToIndex[semanticIndexSetKey];
            indicesInRemapping[k] = idx;
        }

        shared_ptr<GLTF::GLTFPrimitiveRemapInfos> primitiveRemapInfos = __BuildPrimitiveUniqueIndexes(targetPrimitives[i], *allIndices, remappedMeshIndexesMap, indicesInRemapping, startIndex, maxVertexAttributes, endIndex);

        free(indicesInRemapping);

        if (primitiveRemapInfos.get()) {
            startIndex = endIndex;
            allPrimitiveRemapInfos.push_back(primitiveRemapInfos);
        } else {
            // FIXME: report error
            //return NULL;
        }
    }

    // now we got not only the uniqueIndexes but also the number of different indexes, i.e the number of vertex attributes count
    // we can allocate the buffer to hold vertex attributes
    unsigned int vertexCount = endIndex;
    //just allocate it now, will be filled later
    unsigned int* remapTableForPositions = (unsigned int*)malloc(sizeof(unsigned int) * vertexCount);
    targetMesh->setRemapTableForPositions(remapTableForPositions);

    for (unsigned int i = 0 ; i < allSemantics.size() ; i++) {
        Semantic semantic = allSemantics[i];
        IndexSetToMeshAttributeHashmap& indexSetToMeshAttribute = sourceMesh->getMeshAttributesForSemantic(semantic);
        IndexSetToMeshAttributeHashmap& destinationIndexSetToMeshAttribute = targetMesh->getMeshAttributesForSemantic(semantic);
        IndexSetToMeshAttributeHashmap::const_iterator meshAttributeIterator;

        //FIXME: consider turn this search into a method for mesh
        for (meshAttributeIterator = indexSetToMeshAttribute.begin() ; meshAttributeIterator != indexSetToMeshAttribute.end() ; meshAttributeIterator++) {
            //(*it).first;             // the key value (of type Key)
            //(*it).second;            // the mapped value (of type T)
            shared_ptr <GLTF::GLTFMeshAttribute> selectedMeshAttribute = (*meshAttributeIterator).second;

            size_t sourceSize = vertexCount * selectedMeshAttribute->getVertexAttributeByteLength();
            void* sourceData = malloc(sourceSize);

            shared_ptr <GLTFBufferView> referenceBufferView = selectedMeshAttribute->getBufferView();
            shared_ptr <GLTFBufferView> remappedBufferView = createBufferViewWithAllocatedBuffer(referenceBufferView->getID(), sourceData, 0, sourceSize, true);

            shared_ptr <GLTFMeshAttribute> remappedMeshAttribute(new GLTFMeshAttribute(selectedMeshAttribute.get()));
            remappedMeshAttribute->setBufferView(remappedBufferView);
            remappedMeshAttribute->setCount(vertexCount);

            destinationIndexSetToMeshAttribute[(*meshAttributeIterator).first] = remappedMeshAttribute;

            remappedMeshAttributes.push_back(remappedMeshAttribute);
        }
    }

    /*
     if (_allOriginalMeshAttributes.size() != allIndices.size()) {
     // FIXME: report error
     return false;
     }
     */

    for (unsigned int i = 0 ; i < primitiveCount ; i++) {
        shared_ptr<IndicesVector>  allIndicesSharedPtr = vectorOfIndicesVector[i];
        IndicesVector *allIndices = allIndicesSharedPtr.get();
        unsigned int* indicesInRemapping = (unsigned int*)calloc(sizeof(unsigned int) * (*allIndices).size(), 1);
        VertexAttributeVector vertexAttributes = sourcePrimitives[i]->getVertexAttributes();

        for (unsigned int k = 0 ; k < (*allIndices).size() ; k++) {
            GLTF::Semantic semantic = vertexAttributes[k]->getSemantic();
            unsigned int indexSet = vertexAttributes[k]->getIndexOfSet();
            std::string semanticIndexSetKey = keyWithSemanticAndSet(semantic, indexSet);
            unsigned int idx = semanticAndSetToIndex[semanticIndexSetKey];
            indicesInRemapping[k] = idx;
        }

        bool status = __RemapPrimitiveVertices(targetPrimitives[i],
                                               (*allIndices),
                                               originalMeshAttributes ,
                                               remappedMeshAttributes,
                                               indicesInRemapping,
                                               allPrimitiveRemapInfos[i],
                                               remapTableForPositions);
        free(indicesInRemapping);

        if (!status) {
            // FIXME: report error
            //return NULL;
        }
    }

    return targetMesh;
}
Beispiel #13
0
 static void __DecomposeMatrices(float *matrices, size_t count,
                                 std::vector< shared_ptr <GLTFBufferView> > &TRSBufferViews) {
     
     size_t translationBufferSize = sizeof(float) * 3 * count;
     size_t rotationBufferSize = sizeof(float) * 4 * count;
     size_t scaleBufferSize = sizeof(float) * 3 * count;
     
     float *translationData = (float*)malloc(translationBufferSize);
     float *rotationData = (float*)malloc(rotationBufferSize);
     float *scaleData = (float*)malloc(scaleBufferSize);
     
     shared_ptr <GLTF::GLTFBufferView> translationBufferView = createBufferViewWithAllocatedBuffer(translationData, 0, translationBufferSize, true);
     shared_ptr <GLTF::GLTFBufferView> rotationBufferView = createBufferViewWithAllocatedBuffer(rotationData, 0, rotationBufferSize, true);
     shared_ptr <GLTF::GLTFBufferView> scaleBufferView = createBufferViewWithAllocatedBuffer(scaleData, 0, scaleBufferSize, true);
     
     float *previousRotation = 0;
     
     for (size_t i = 0 ; i < count ; i++) {
         
         float *m = matrices;
         COLLADABU::Math::Matrix4 mat;
         mat.setAllElements(m[0], m[1], m[2], m[3],
                            m[4], m[5], m[6], m[7],
                            m[8], m[9], m[10], m[11],
                            m[12], m[13], m[14], m[15] );
         
         decomposeMatrix(mat, translationData, rotationData, scaleData);
         
         //make sure we export the short path from orientations
         if (0 != previousRotation) {
             COLLADABU::Math::Vector3 axis1(previousRotation[0], previousRotation[1], previousRotation[2]);
             COLLADABU::Math::Vector3 axis2(rotationData[0], rotationData[1], rotationData[2]);
             
             COLLADABU::Math::Quaternion key1;
             COLLADABU::Math::Quaternion key2;
             
             key1.fromAngleAxis(previousRotation[3], axis1);
             key2.fromAngleAxis(rotationData[3], axis2);
             
             COLLADABU::Math::Real cosHalfTheta = key1.dot(key2);
             if (cosHalfTheta < 0) {
                 key2.x = -key2.x;
                 key2.y = -key2.y;
                 key2.z = -key2.z;
                 key2.w = -key2.w;
                 
                 COLLADABU::Math::Real angle;
                 key2.toAngleAxis(angle, axis2);
                 rotationData[3] = (float)angle;
                 rotationData[0] = (float)axis2.x;
                 rotationData[1] = (float)axis2.y;
                 rotationData[2] = (float)axis2.z;
                 
                 key2.fromAngleAxis(rotationData[3], axis2);
                 
                 //FIXME: this needs to be refined, we ensure continuity here, but assume in clockwise order
                 cosHalfTheta = key1.dot(key2);
                 if (cosHalfTheta < 0) {
                     rotationData[3] += (float)(2. * 3.14159265359);
                     key2.fromAngleAxis(rotationData[3], axis2);
                 }
             }
             
         }
         
         previousRotation = rotationData;
         translationData += 3;
         rotationData += 4;
         scaleData += 3;
         matrices += 16;
     }
     /*
      rotationData = (float*)rotationBufferView->getBufferDataByApplyingOffset();
      for (size_t i = 0 ; i < count ; i++) {
      printf("rotation at:%d %f %f %f %f\n",  i,
      rotationData[0],rotationData[1],rotationData[2],rotationData[3]);
      
      rotationData += 4;
      }
      */
     TRSBufferViews.push_back(translationBufferView);
     TRSBufferViews.push_back(rotationBufferView);
     TRSBufferViews.push_back(scaleBufferView);
 }