void	btStridingMeshInterface::InternalProcessAllTriangles(btInternalTriangleIndexCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const
{
	(void)aabbMin;
	(void)aabbMax;
	int numtotalphysicsverts = 0;
	int part,graphicssubparts = getNumSubParts();
	const unsigned char * vertexbase;
	const unsigned char * indexbase;
	int indexstride;
	PHY_ScalarType type;
	PHY_ScalarType gfxindextype;
	int stride,numverts,numtriangles;
	int gfxindex;
	btVector3 triangle[3];

	btVector3 meshScaling = getScaling();

	///if the number of parts is big, the performance might drop due to the innerloop switch on indextype
	for (part=0;part<graphicssubparts ;part++)
	{
		getLockedReadOnlyVertexIndexBase(&vertexbase,numverts,type,stride,&indexbase,indexstride,numtriangles,gfxindextype,part);
		numtotalphysicsverts+=numtriangles*3; //upper bound

		///unlike that developers want to pass in double-precision meshes in single-precision Bullet build
		///so disable this feature by default
		///see patch http://code.google.com/p/bullet/issues/detail?id=213

		switch (type)
		{
		case PHY_FLOAT:
		 {

			 float* graphicsbase;

			 switch (gfxindextype)
			 {
			 case PHY_INTEGER:
				 {
					 for (gfxindex=0;gfxindex<numtriangles;gfxindex++)
					 {
						 unsigned int* tri_indices= (unsigned int*)(indexbase+gfxindex*indexstride);
						 graphicsbase = (float*)(vertexbase+tri_indices[0]*stride);
						 triangle[0].setValue(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),graphicsbase[2]*meshScaling.getZ());
						 graphicsbase = (float*)(vertexbase+tri_indices[1]*stride);
						 triangle[1].setValue(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),	graphicsbase[2]*meshScaling.getZ());
						 graphicsbase = (float*)(vertexbase+tri_indices[2]*stride);
						 triangle[2].setValue(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),	graphicsbase[2]*meshScaling.getZ());
						 callback->internalProcessTriangleIndex(triangle,part,gfxindex);
					 }
					 break;
				 }
			 case PHY_SHORT:
				 {
					 for (gfxindex=0;gfxindex<numtriangles;gfxindex++)
					 {
						 unsigned short int* tri_indices= (unsigned short int*)(indexbase+gfxindex*indexstride);
						 graphicsbase = (float*)(vertexbase+tri_indices[0]*stride);
						 triangle[0].setValue(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),graphicsbase[2]*meshScaling.getZ());
						 graphicsbase = (float*)(vertexbase+tri_indices[1]*stride);
						 triangle[1].setValue(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),	graphicsbase[2]*meshScaling.getZ());
						 graphicsbase = (float*)(vertexbase+tri_indices[2]*stride);
						 triangle[2].setValue(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),	graphicsbase[2]*meshScaling.getZ());
						 callback->internalProcessTriangleIndex(triangle,part,gfxindex);
					 }
					 break;
				 }
			case PHY_UCHAR:
				 {
					 for (gfxindex=0;gfxindex<numtriangles;gfxindex++)
					 {
						 unsigned char* tri_indices= (unsigned char*)(indexbase+gfxindex*indexstride);
						 graphicsbase = (float*)(vertexbase+tri_indices[0]*stride);
						 triangle[0].setValue(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),graphicsbase[2]*meshScaling.getZ());
						 graphicsbase = (float*)(vertexbase+tri_indices[1]*stride);
						 triangle[1].setValue(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),	graphicsbase[2]*meshScaling.getZ());
						 graphicsbase = (float*)(vertexbase+tri_indices[2]*stride);
						 triangle[2].setValue(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),	graphicsbase[2]*meshScaling.getZ());
						 callback->internalProcessTriangleIndex(triangle,part,gfxindex);
					 }
					 break;
				 }
			 default:
				 btAssert((gfxindextype == PHY_INTEGER) || (gfxindextype == PHY_SHORT));
			 }
			 break;
		 }

		case PHY_DOUBLE:
			{
				double* graphicsbase;

				switch (gfxindextype)
				{
				case PHY_INTEGER:
					{
						for (gfxindex=0;gfxindex<numtriangles;gfxindex++)
						{
							unsigned int* tri_indices= (unsigned int*)(indexbase+gfxindex*indexstride);
							graphicsbase = (double*)(vertexbase+tri_indices[0]*stride);
							triangle[0].setValue((btScalar)graphicsbase[0]*meshScaling.getX(),(btScalar)graphicsbase[1]*meshScaling.getY(),(btScalar)graphicsbase[2]*meshScaling.getZ());
							graphicsbase = (double*)(vertexbase+tri_indices[1]*stride);
							triangle[1].setValue((btScalar)graphicsbase[0]*meshScaling.getX(),(btScalar)graphicsbase[1]*meshScaling.getY(),  (btScalar)graphicsbase[2]*meshScaling.getZ());
							graphicsbase = (double*)(vertexbase+tri_indices[2]*stride);
							triangle[2].setValue((btScalar)graphicsbase[0]*meshScaling.getX(),(btScalar)graphicsbase[1]*meshScaling.getY(),  (btScalar)graphicsbase[2]*meshScaling.getZ());
							callback->internalProcessTriangleIndex(triangle,part,gfxindex);
						}
						break;
					}
				case PHY_SHORT:
					{
						for (gfxindex=0;gfxindex<numtriangles;gfxindex++)
						{
							unsigned short int* tri_indices= (unsigned short int*)(indexbase+gfxindex*indexstride);
							graphicsbase = (double*)(vertexbase+tri_indices[0]*stride);
							triangle[0].setValue((btScalar)graphicsbase[0]*meshScaling.getX(),(btScalar)graphicsbase[1]*meshScaling.getY(),(btScalar)graphicsbase[2]*meshScaling.getZ());
							graphicsbase = (double*)(vertexbase+tri_indices[1]*stride);
							triangle[1].setValue((btScalar)graphicsbase[0]*meshScaling.getX(),(btScalar)graphicsbase[1]*meshScaling.getY(),  (btScalar)graphicsbase[2]*meshScaling.getZ());
							graphicsbase = (double*)(vertexbase+tri_indices[2]*stride);
							triangle[2].setValue((btScalar)graphicsbase[0]*meshScaling.getX(),(btScalar)graphicsbase[1]*meshScaling.getY(),  (btScalar)graphicsbase[2]*meshScaling.getZ());
							callback->internalProcessTriangleIndex(triangle,part,gfxindex);
						}
						break;
					}
				case PHY_UCHAR:
					{
						for (gfxindex=0;gfxindex<numtriangles;gfxindex++)
						{
							unsigned char* tri_indices= (unsigned char*)(indexbase+gfxindex*indexstride);
							graphicsbase = (double*)(vertexbase+tri_indices[0]*stride);
							triangle[0].setValue((btScalar)graphicsbase[0]*meshScaling.getX(),(btScalar)graphicsbase[1]*meshScaling.getY(),(btScalar)graphicsbase[2]*meshScaling.getZ());
							graphicsbase = (double*)(vertexbase+tri_indices[1]*stride);
							triangle[1].setValue((btScalar)graphicsbase[0]*meshScaling.getX(),(btScalar)graphicsbase[1]*meshScaling.getY(),  (btScalar)graphicsbase[2]*meshScaling.getZ());
							graphicsbase = (double*)(vertexbase+tri_indices[2]*stride);
							triangle[2].setValue((btScalar)graphicsbase[0]*meshScaling.getX(),(btScalar)graphicsbase[1]*meshScaling.getY(),  (btScalar)graphicsbase[2]*meshScaling.getZ());
							callback->internalProcessTriangleIndex(triangle,part,gfxindex);
						}
						break;
					}
				default:
					btAssert((gfxindextype == PHY_INTEGER) || (gfxindextype == PHY_SHORT));
				}
				break;
			}
		default:
			btAssert((type == PHY_FLOAT) || (type == PHY_DOUBLE));
		}

		unLockReadOnlyVertexBase(part);
	}
}
Example #2
0
 void scale     (const T x, const T y) { this->operator *=(getScaling(x, y)); }
Example #3
0
void AbsoluteLayout::updateLayout(const MFUnrecChildComponentPtr* Components,
                                  const Component* ParentComponent) const
{
    Pnt2f ParentInsetsTopLeft, ParentInsetBottomRight;
    dynamic_cast<const ComponentContainer*>(ParentComponent)->getInsideInsetsBounds(ParentInsetsTopLeft, ParentInsetBottomRight);
	Vec2f borderSize(ParentInsetBottomRight-ParentInsetsTopLeft);

    Vec2f ComponentSize;
    Pnt2f ComponentPosition;
    for(UInt32 i = 0 ; i<Components->size(); ++i)
    {
        //Calculate the Components Size
        if((*Components)[i]->getConstraints() != NULL)
        {
            ComponentPosition = dynamic_cast<AbsoluteLayoutConstraints*>((*Components)[i]->getConstraints())->getPosition();
        }
        else
        {
            ComponentPosition.setValues(0.0f,0.0f);
        }
        ComponentSize = (*Components)[i]->getPreferredSize();

        
        if(getScaling())
        {
            Vec2f DifferenceRatio(borderSize.x() / getOriginalDimensions().x(), borderSize.y() / getOriginalDimensions().y());

            ComponentPosition.setValues(ComponentPosition.x() * DifferenceRatio.x(), ComponentPosition.y() * DifferenceRatio.y());
            ComponentSize.setValues(ComponentSize.x() * DifferenceRatio.x(), ComponentSize.y() * DifferenceRatio.y());
        }
        else
        {
            if(ComponentPosition.x() <= 1.0f)
            {
                ComponentPosition[0] = ComponentPosition.x() * borderSize.x();
            }
            if(ComponentPosition.y() <= 1.0f)
            {
                ComponentPosition[1] = ComponentPosition.y() * borderSize.y();
            }

            if(ComponentSize.x() <= 1.0f)
            {
                ComponentSize[0] = ComponentSize.x() * borderSize.x();
            }
            if(ComponentSize.y() <= 1.0f)
            {
                ComponentSize[1] = ComponentSize.y() * borderSize.y();
            }
        }

        ComponentPosition = ParentInsetsTopLeft + ComponentPosition.subZero();
        if((*Components)[i]->getPosition() != ComponentPosition)
        {
            (*Components)[i]->setPosition(ComponentPosition);
        }
        if((*Components)[i]->getSize() != ComponentSize)
        {
            (*Components)[i]->setSize(ComponentSize);
        }
    }
}
///fills the dataBuffer and returns the struct name (and 0 on failure)
const char*	btStridingMeshInterface::serialize(void* dataBuffer, btSerializer* serializer) const
{
	btStridingMeshInterfaceData* trimeshData = (btStridingMeshInterfaceData*) dataBuffer;

	trimeshData->m_numMeshParts = getNumSubParts();

	//void* uniquePtr = 0;

	trimeshData->m_meshPartsPtr = 0;

	if (trimeshData->m_numMeshParts)
	{
		btChunk* chunk = serializer->allocate(sizeof(btMeshPartData),trimeshData->m_numMeshParts);
		btMeshPartData* memPtr = (btMeshPartData*)chunk->m_oldPtr;
		trimeshData->m_meshPartsPtr = (btMeshPartData *)serializer->getUniquePointer(memPtr);


	//	int numtotalphysicsverts = 0;
		int part,graphicssubparts = getNumSubParts();
		const unsigned char * vertexbase;
		const unsigned char * indexbase;
		int indexstride;
		PHY_ScalarType type;
		PHY_ScalarType gfxindextype;
		int stride,numverts,numtriangles;
		int gfxindex;
	//	btVector3 triangle[3];

		btVector3 meshScaling = getScaling();

		///if the number of parts is big, the performance might drop due to the innerloop switch on indextype
		for (part=0;part<graphicssubparts ;part++,memPtr++)
		{
			getLockedReadOnlyVertexIndexBase(&vertexbase,numverts,type,stride,&indexbase,indexstride,numtriangles,gfxindextype,part);
			memPtr->m_numTriangles = numtriangles;//indices = 3*numtriangles
			memPtr->m_numVertices = numverts;
			memPtr->m_indices16 = 0;
			memPtr->m_indices32 = 0;
			memPtr->m_3indices16 = 0;
			memPtr->m_3indices8 = 0;
			memPtr->m_vertices3f = 0;
			memPtr->m_vertices3d = 0;


			switch (gfxindextype)
			{
			case PHY_INTEGER:
				{
					int numindices = numtriangles*3;
				
					if (numindices)
					{
						btChunk* chunk = serializer->allocate(sizeof(btIntIndexData),numindices);
						btIntIndexData* tmpIndices = (btIntIndexData*)chunk->m_oldPtr;
						memPtr->m_indices32 = (btIntIndexData*)serializer->getUniquePointer(tmpIndices);
						for (gfxindex=0;gfxindex<numtriangles;gfxindex++)
						{
							unsigned int* tri_indices= (unsigned int*)(indexbase+gfxindex*indexstride);
							tmpIndices[gfxindex*3].m_value = tri_indices[0];
							tmpIndices[gfxindex*3+1].m_value = tri_indices[1];
							tmpIndices[gfxindex*3+2].m_value = tri_indices[2];
						}
						serializer->finalizeChunk(chunk,"btIntIndexData",BT_ARRAY_CODE,(void*)chunk->m_oldPtr);
					}
					break;
				}
			case PHY_SHORT:
				{
					if (numtriangles)
					{
						btChunk* chunk = serializer->allocate(sizeof(btShortIntIndexTripletData),numtriangles);
						btShortIntIndexTripletData* tmpIndices = (btShortIntIndexTripletData*)chunk->m_oldPtr;
						memPtr->m_3indices16 = (btShortIntIndexTripletData*) serializer->getUniquePointer(tmpIndices);
						for (gfxindex=0;gfxindex<numtriangles;gfxindex++)
						{
							unsigned short int* tri_indices= (unsigned short int*)(indexbase+gfxindex*indexstride);
							tmpIndices[gfxindex].m_values[0] = tri_indices[0];
							tmpIndices[gfxindex].m_values[1] = tri_indices[1];
							tmpIndices[gfxindex].m_values[2] = tri_indices[2];
						}
						serializer->finalizeChunk(chunk,"btShortIntIndexTripletData",BT_ARRAY_CODE,(void*)chunk->m_oldPtr);
					}
					break;
				}
				case PHY_UCHAR:
				{
					if (numtriangles)
					{
						btChunk* chunk = serializer->allocate(sizeof(btCharIndexTripletData),numtriangles);
						btCharIndexTripletData* tmpIndices = (btCharIndexTripletData*)chunk->m_oldPtr;
						memPtr->m_3indices8 = (btCharIndexTripletData*) serializer->getUniquePointer(tmpIndices);
						for (gfxindex=0;gfxindex<numtriangles;gfxindex++)
						{
							unsigned char* tri_indices= (unsigned char*)(indexbase+gfxindex*indexstride);
							tmpIndices[gfxindex].m_values[0] = tri_indices[0];
							tmpIndices[gfxindex].m_values[1] = tri_indices[1];
							tmpIndices[gfxindex].m_values[2] = tri_indices[2];
						}
						serializer->finalizeChunk(chunk,"btCharIndexTripletData",BT_ARRAY_CODE,(void*)chunk->m_oldPtr);
					}
					break;
				}
			default:
				{
					btAssert(0);
					//unknown index type
				}
			}

			switch (type)
			{
			case PHY_FLOAT:
			 {
				 float* graphicsbase;

				 if (numverts)
				 {
					 btChunk* chunk = serializer->allocate(sizeof(btVector3FloatData),numverts);
					 btVector3FloatData* tmpVertices = (btVector3FloatData*) chunk->m_oldPtr;
					 memPtr->m_vertices3f = (btVector3FloatData *)serializer->getUniquePointer(tmpVertices);
					 for (int i=0;i<numverts;i++)
					 {
						 graphicsbase = (float*)(vertexbase+i*stride);
						 tmpVertices[i].m_floats[0] = graphicsbase[0];
						 tmpVertices[i].m_floats[1] = graphicsbase[1];
						 tmpVertices[i].m_floats[2] = graphicsbase[2];
					 }
					 serializer->finalizeChunk(chunk,"btVector3FloatData",BT_ARRAY_CODE,(void*)chunk->m_oldPtr);
				 }
				 break;
				}

			case PHY_DOUBLE:
				{
					if (numverts)
					{
						btChunk* chunk = serializer->allocate(sizeof(btVector3DoubleData),numverts);
						btVector3DoubleData* tmpVertices = (btVector3DoubleData*) chunk->m_oldPtr;
						memPtr->m_vertices3d = (btVector3DoubleData *) serializer->getUniquePointer(tmpVertices);
						for (int i=0;i<numverts;i++)
					 {
						 double* graphicsbase = (double*)(vertexbase+i*stride);//for now convert to float, might leave it at double
						 tmpVertices[i].m_floats[0] = graphicsbase[0];
						 tmpVertices[i].m_floats[1] = graphicsbase[1];
						 tmpVertices[i].m_floats[2] = graphicsbase[2];
					 }
						serializer->finalizeChunk(chunk,"btVector3DoubleData",BT_ARRAY_CODE,(void*)chunk->m_oldPtr);
					}
					break;
				}

			default:
				btAssert((type == PHY_FLOAT) || (type == PHY_DOUBLE));
			}

			unLockReadOnlyVertexBase(part);
		}

		serializer->finalizeChunk(chunk,"btMeshPartData",BT_ARRAY_CODE,chunk->m_oldPtr);
	}


	m_scaling.serializeFloat(trimeshData->m_scaling);
	return "btStridingMeshInterfaceData";
}
/*!
SLAssimpImporter::loadAnimation loads the scene graph node tree recursively.
*/
SLAnimation* SLAssimpImporter::loadAnimation(aiAnimation* anim)
{
    int animCount = 0;
    if (_skeleton) animCount = _skeleton->numAnimations();
    ostringstream oss;
    oss << "unnamed_anim_" << animCount;
    SLstring animName = oss.str();
    SLfloat animTicksPerSec = (anim->mTicksPerSecond == 0) ? 30.0f : (SLfloat)anim->mTicksPerSecond;
    SLfloat animDuration = (SLfloat)anim->mDuration / animTicksPerSec;

    if (anim->mName.length > 0)
        animName = anim->mName.C_Str();

    // log
    logMessage(LV_minimal, "\nLoading animation %s\n", animName.c_str());
    logMessage(LV_normal, " Duration(seconds): %f \n", animDuration);
    logMessage(LV_normal, " Duration(ticks): %f \n", anim->mDuration);
    logMessage(LV_normal, " Ticks per second: %f \n", animTicksPerSec);
    logMessage(LV_normal, " Num channels: %d\n", anim->mNumChannels);
                
    // exit if we didn't load a skeleton but have animations for one
    if (_skinnedMeshes.size() > 0)
        assert(_skeleton != nullptr && "The skeleton wasn't impoted correctly."); 
    
    // create the animation
    SLAnimation* result;
    if (_skeleton)
        result = _skeleton->createAnimation(animName, animDuration);
    else
    {
        result = SLScene::current->animManager().createNodeAnimation(animName, animDuration);
        _nodeAnimations.push_back(result);
    }


    SLbool isSkeletonAnim = false;
    for (SLuint i = 0; i < anim->mNumChannels; i++)
    {
        aiNodeAnim* channel = anim->mChannels[i];

        // find the node that is animated by this channel
        SLstring nodeName = channel->mNodeName.C_Str();
        SLNode* affectedNode = _sceneRoot->find<SLNode>(nodeName);
        SLuint id = 0;
        SLbool isJointNode = (affectedNode == nullptr);

        // @todo: this is currently a work around but it can happen that we receive normal node animationtracks and joint animationtracks
        //        we don't allow node animation tracks in a skeleton animation, so we should split an animation in two seperate 
        //        animations if this happens. for now we just ignore node animation tracks if we already have joint tracks
        //        ofc this will crash if the first track is a node anim but its just temporary
        if (!isJointNode && isSkeletonAnim)
            continue;

        // is there a skeleton and is this animation channel not affecting a normal node?
        if (_skeletonRoot && !affectedNode)
        {
            isSkeletonAnim = true;
            SLJoint* affectedJoint = _skeleton->getJoint(nodeName);
            if (affectedJoint == nullptr)
                break;

            id = affectedJoint->id();
            // @todo warn if we find an animation with some node channels and some joint channels
            //       this shouldn't happen!

            /// @todo [high priority!] Address the problem of some bones not containing an animation channel
            ///         when importing. Current workaround is to set their reset position to their bind pose.
            ///         This will however fail if we have multiple animations affecting a single model and fading
            ///         some of them out or in. This will require us to provide animations that have a channel
            ///         for all bones even if they're just positional.
            // What does this next line do?
            //   
            //   The testimportfile we used (Astroboy.dae) has the following properties:
            //      > It has joints in the skeleton that aren't animated by any channel.
            //      > The joints need a reset position of (0, 0, 0) to work properly 
            //          because the joint position is contained in a single keyframe for every joint
            //
            //      Since some of the joints don't have a channel that animates them, they also lack
            //      the joint position that the other joints get from their animation channel.
            //      So we need to set the initial state for all joints that have a channel
            //      to identity.
            //      All joints that arent in a channel will receive their local joint bind pose as
            //      reset position.
            //
            //      The problem stems from the design desicion to reset a whole skeleton before applying 
            //      animations to it. If we were to reset each joint just before applying a channel to it
            //      we wouldn't have this problem. But we coulnd't blend animations as easily.
            //
            SLMat4f prevOM = affectedJoint->om();
            affectedJoint->om(SLMat4f());
            affectedJoint->setInitialState();
            affectedJoint->om(prevOM);
        }
                            
        // log
        logMessage(LV_normal, "\n  Channel %d %s", i, (isJointNode) ? "(joint animation)\n" : "\n");
        logMessage(LV_normal, "   Affected node: %s\n", channel->mNodeName.C_Str());
        logMessage(LV_detailed, "   Num position keys: %d\n", channel->mNumPositionKeys);
        logMessage(LV_detailed, "   Num rotation keys: %d\n", channel->mNumRotationKeys);
        logMessage(LV_detailed, "   Num scaling keys: %d\n", channel->mNumScalingKeys);

        
        // joint animation channels should receive the correct node id, normal node animations just get 0
        SLNodeAnimTrack* track = result->createNodeAnimationTrack(id);

        
        // this is a node animation only, so we add a reference to the affected node to the track
        if (affectedNode && !isSkeletonAnim) {
            track->animatedNode(affectedNode);
        }

        KeyframeMap keyframes;

        // add position keys
        for (SLuint i = 0; i < channel->mNumPositionKeys; i++)
        {
            SLfloat time = (SLfloat)channel->mPositionKeys[i].mTime; 
            keyframes[time] = SLImportKeyframe(&channel->mPositionKeys[i], nullptr, nullptr);
        }
        
        // add rotation keys
        for (SLuint i = 0; i < channel->mNumRotationKeys; i++)
        {
            SLfloat time = (SLfloat)channel->mRotationKeys[i].mTime;

            if (keyframes.find(time) == keyframes.end())
                keyframes[time] = SLImportKeyframe(nullptr, &channel->mRotationKeys[i], nullptr);
            else
            {
                // @todo this shouldn't abort but just throw an exception
                assert(keyframes[time].rotation == nullptr && "There were two rotation keys assigned to the same timestamp.");
                keyframes[time].rotation = &channel->mRotationKeys[i];
            }
        }
        
        // add scaleing keys
        for (SLuint i = 0; i < channel->mNumScalingKeys; i++)
        {
            SLfloat time = (SLfloat)channel->mScalingKeys[i].mTime; 

            if (keyframes.find(time) == keyframes.end())
                keyframes[time] = SLImportKeyframe(nullptr, nullptr, &channel->mScalingKeys[i]);
            else
            {
                // @todo this shouldn't abort but just throw an exception
                assert(keyframes[time].scaling == nullptr && "There were two scaling keys assigned to the same timestamp.");
                keyframes[time].scaling = &channel->mScalingKeys[i];
            }
        }

        logMessage(LV_normal, "   Found %d distinct keyframe timestamp(s).\n", 
                              keyframes.size());

        for (auto it : keyframes)
        {   SLTransformKeyframe* kf = track->createNodeKeyframe(it.first);         
            kf->translation(getTranslation(it.first, keyframes));
            kf->rotation(getRotation(it.first, keyframes));
            kf->scale(getScaling(it.first, keyframes));

            // log
            logMessage(LV_detailed, "\n   Generating keyframe at time '%.2f'\n", 
                       it.first);
            logMessage(LV_detailed, "    Translation: (%.2f, %.2f, %.2f) %s\n", 
                       kf->translation().x, 
                       kf->translation().y, 
                       kf->translation().z, 
                       (it.second.translation != nullptr) ? "imported" : "generated");
            logMessage(LV_detailed, "    Rotation: (%.2f, %.2f, %.2f, %.2f) %s\n", 
                       kf->rotation().x(), 
                       kf->rotation().y(), 
                       kf->rotation().z(), 
                       kf->rotation().w(), 
                       (it.second.rotation != nullptr) ? "imported" : "generated");
            logMessage(LV_detailed, "    Scale: (%.2f, %.2f, %.2f) %s\n", 
                       kf->scale().x, 
                       kf->scale().y, 
                       kf->scale().z, 
                       (it.second.scaling != nullptr) ? "imported" : "generated");
        }
    }
    
    return result;
}
void	btStridingMeshInterface::InternalProcessAllTriangles(btInternalTriangleIndexCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const
{
	(void)aabbMin;
	(void)aabbMax;
	int numtotalphysicsverts = 0;
	int part,graphicssubparts = getNumSubParts();
	const unsigned char * vertexbase;
	const unsigned char * indexbase;
	int indexstride;
	PHY_ScalarType type;
	PHY_ScalarType gfxindextype;
	int stride,numverts,numtriangles;
	int gfxindex;
	btVector3 triangle[3];
	btScalar* graphicsbase;

	btVector3 meshScaling = getScaling();

	///if the number of parts is big, the performance might drop due to the innerloop switch on indextype
	for (part=0;part<graphicssubparts ;part++)
	{
		getLockedReadOnlyVertexIndexBase(&vertexbase,numverts,type,stride,&indexbase,indexstride,numtriangles,gfxindextype,part);
		numtotalphysicsverts+=numtriangles*3; //upper bound

		switch (gfxindextype)
		{
		case PHY_INTEGER:
			{
				for (gfxindex=0;gfxindex<numtriangles;gfxindex++)
				{
					int* tri_indices= (int*)(indexbase+gfxindex*indexstride);
					graphicsbase = (btScalar*)(vertexbase+tri_indices[0]*stride);
					triangle[0].setValue(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),graphicsbase[2]*meshScaling.getZ());
					graphicsbase = (btScalar*)(vertexbase+tri_indices[1]*stride);
					triangle[1].setValue(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),	graphicsbase[2]*meshScaling.getZ());
					graphicsbase = (btScalar*)(vertexbase+tri_indices[2]*stride);
					triangle[2].setValue(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),	graphicsbase[2]*meshScaling.getZ());
					callback->internalProcessTriangleIndex(triangle,part,gfxindex);
				}
				break;
			}
		case PHY_SHORT:
			{
				for (gfxindex=0;gfxindex<numtriangles;gfxindex++)
				{
					short int* tri_indices= (short int*)(indexbase+gfxindex*indexstride);
					graphicsbase = (btScalar*)(vertexbase+tri_indices[0]*stride);
					triangle[0].setValue(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),graphicsbase[2]*meshScaling.getZ());
					graphicsbase = (btScalar*)(vertexbase+tri_indices[1]*stride);
					triangle[1].setValue(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),	graphicsbase[2]*meshScaling.getZ());
					graphicsbase = (btScalar*)(vertexbase+tri_indices[2]*stride);
					triangle[2].setValue(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),	graphicsbase[2]*meshScaling.getZ());
					callback->internalProcessTriangleIndex(triangle,part,gfxindex);
				}
				break;
			}
		default:
			btAssert((gfxindextype == PHY_INTEGER) || (gfxindextype == PHY_SHORT));
		}

		unLockReadOnlyVertexBase(part);
	}
}