// Bounding Sphere Tests
TEST_F(BBoxTest, BoundingSphereWorks) {
    BBox b (Point (0, 0, 0), Point (1, 1, 1));

    Point center;
    float radius;

    b.BoundingSphere (&center, &radius);

    EXPECT_EQ (.5, center.x);
    EXPECT_EQ (.5, center.y);
    EXPECT_EQ (.5, center.z);

    EXPECT_EQ (sqrtf(.75), radius);
}
TEST_F(BBoxTest, BoundingSphereDegenerateWorks) {
    BBox b (Point (0, 0, 0), Point (0, 0, 0));

    Point center;
    float radius;

    b.BoundingSphere (&center, &radius);

    EXPECT_EQ (0, center.x);
    EXPECT_EQ (0, center.y);
    EXPECT_EQ (0, center.z);

    EXPECT_EQ (0, radius);
}
//--------------------------------------------------------------------------------------
//
// ProcessVertices
//
// After all of the vertices have been loaded ProcessVertices is called to create the
// associated data with the hair vertices, which includes attributes like tangents,strand
// length, and transformations. Also the hair type is stored with each vertex which
// allows different simulation parameters for different sections of the hair.
//
//--------------------------------------------------------------------------------------
void TressFXAssetLoader::ProcessVertices()
{
    // construct local and global transforms for each hair strand.
    ConstructTransforms();

    // compute tangent vectors
    ComputeStrandTangent();

    // compute distances to root vertices
    ComputeDistanceToRoot();

    m_HairAsset.m_pVertices = new XMFLOAT4[m_HairAsset.m_NumTotalHairVertices];
    m_HairAsset.m_pHairStrandType = new int[m_HairAsset.m_NumTotalHairStrands];

    if (m_usingPerStrandTexCoords)
    {
        m_HairAsset.m_pStrandTexCoords = new XMFLOAT2[m_HairAsset.m_NumTotalHairStrands];
    }
    else
    {
        m_HairAsset.m_pStrandTexCoords = NULL;
    }

    m_HairAsset.m_pTangents = new XMFLOAT4[m_HairAsset.m_NumTotalHairVertices];

    // Initialize the hair strands and compute tangents
    for ( int i = 0; i < m_HairAsset.m_NumTotalHairVertices; i++ )
    {
        m_HairAsset.m_pTangents[i].x = m_Vertices[i].tangent.x;
        m_HairAsset.m_pTangents[i].y = m_Vertices[i].tangent.y;
        m_HairAsset.m_pTangents[i].z = m_Vertices[i].tangent.z;
    }

    m_HairAsset.m_pRestLengths = new float[m_HairAsset.m_NumTotalHairVertices];
    int index = 0;

    // Calculate rest lengths
    for ( int i = 0; i < m_HairAsset.m_NumTotalHairStrands; i++ )
    {
        int indexRootVert = i * m_HairAsset.m_NumOfVerticesInStrand;

        for ( int j = 0; j < m_HairAsset.m_NumOfVerticesInStrand - 1; j++ )
        {
            m_HairAsset.m_pRestLengths[index++] = (m_Vertices[indexRootVert + j].position - m_Vertices[indexRootVert + j + 1].position).Length();
        }

        // Since number of edges are one less than number of vertices in hair strand, below line acts as a placeholder.
        m_HairAsset.m_pRestLengths[index++] = 0;
    }

    assert(index == m_HairAsset.m_NumTotalHairVertices);

    m_HairAsset.m_pRefVectors = new XMFLOAT4[m_HairAsset.m_NumTotalHairVertices];
    m_HairAsset.m_pGlobalRotations = new XMFLOAT4[m_HairAsset.m_NumTotalHairVertices];
    m_HairAsset.m_pLocalRotations = new XMFLOAT4[m_HairAsset.m_NumTotalHairVertices];
    m_HairAsset.m_pTriangleVertices = new StrandVertex[m_HairAsset.m_NumTotalHairVertices];
    m_HairAsset.m_pThicknessCoeffs = new float[m_HairAsset.m_NumTotalHairVertices];
    m_HairAsset.m_pFollowRootOffset = new XMFLOAT4[m_HairAsset.m_NumTotalHairStrands];
    m_HairAsset.m_LineIndices.reserve(m_HairAsset.m_NumTotalHairVertices * 2);
    m_HairAsset.m_TriangleIndices.reserve(m_HairAsset.m_NumTotalHairVertices * 6);
    int id=0;
    index = 0;

    TressFXStrand* pGuideHair = NULL;
    int indexGuideHairStrand = -1;

    // initialize the rest of the hair data
    for ( int i = 0; i < m_HairAsset.m_NumTotalHairStrands; i++ )
    {
        int indexRootVert = i * m_HairAsset.m_NumOfVerticesInStrand;

        for ( int j = 0; j < m_HairAsset.m_NumOfVerticesInStrand - 1; j++ )
        {
            // line indices
            m_HairAsset.m_LineIndices.push_back(id);
            m_HairAsset.m_LineIndices.push_back(id + 1);

            // triangle indices
            m_HairAsset.m_TriangleIndices.push_back(2 * id);
            m_HairAsset.m_TriangleIndices.push_back(2 * id + 1);
            m_HairAsset.m_TriangleIndices.push_back(2 * id + 2);
            m_HairAsset.m_TriangleIndices.push_back(2 * id + 2);
            m_HairAsset.m_TriangleIndices.push_back(2 * id + 1);
            m_HairAsset.m_TriangleIndices.push_back(2 * id + 3);
            id++;
        }

        id++;

        TressFXHairVertex* vertices = &m_Vertices[indexRootVert];

        for ( int j = 0; j < m_HairAsset.m_NumOfVerticesInStrand; j++ )
        {
            // triangle vertices
            StrandVertex strandVertex;
            strandVertex.position = XMFLOAT3(vertices[j].position.x, vertices[j].position.y, vertices[j].position.z);
            strandVertex.tangent = XMFLOAT3(vertices[j].tangent.x, vertices[j].tangent.y, vertices[j].tangent.z);
            strandVertex.texcoord = XMFLOAT4(vertices[j].texcoord.x, vertices[j].texcoord.y, vertices[j].texcoord.z, 0);
            m_HairAsset.m_pTriangleVertices[index] = strandVertex;

            float tVal = m_HairAsset.m_pTriangleVertices[index].texcoord.z;
            m_HairAsset.m_pThicknessCoeffs[index] = sqrt(1.f - tVal * tVal);

            XMFLOAT4 v;

            // temp vertices
            v.x = vertices[j].position.x;
            v.y = vertices[j].position.y;
            v.z = vertices[j].position.z;
            v.w = vertices[j].invMass;
            m_HairAsset.m_pVertices[index] = v;

            // global rotations
            v.x = vertices[j].globalTransform.GetRotation().x;
            v.y = vertices[j].globalTransform.GetRotation().y;
            v.z = vertices[j].globalTransform.GetRotation().z;
            v.w = vertices[j].globalTransform.GetRotation().w;
            m_HairAsset.m_pGlobalRotations[index] = v;

            // local rotations
            v.x = vertices[j].localTransform.GetRotation().x;
            v.y = vertices[j].localTransform.GetRotation().y;
            v.z = vertices[j].localTransform.GetRotation().z;
            v.w = vertices[j].localTransform.GetRotation().w;
            m_HairAsset.m_pLocalRotations[index] = v;

            // ref vectors
            v.x = vertices[j].referenceVector.x;
            v.y = vertices[j].referenceVector.y;
            v.z = vertices[j].referenceVector.z;
            m_HairAsset.m_pRefVectors[index].x = v.x;
            m_HairAsset.m_pRefVectors[index].y = v.y;
            m_HairAsset.m_pRefVectors[index].z = v.z;

            index++;
        }

        int groupId = m_HairStrands[i].m_GroupID;
        m_HairAsset.m_pHairStrandType[i] = groupId;

        if ( m_usingPerStrandTexCoords )
        {
            m_HairAsset.m_pStrandTexCoords[i] = m_HairStrands[i].m_texCoord;
        }

        if ( m_HairStrands[i].m_bGuideHair )
        {
            indexGuideHairStrand = i;
            pGuideHair = &m_HairStrands[i];
            m_HairAsset.m_pFollowRootOffset[i] = XMFLOAT4(0, 0, 0, (float)indexGuideHairStrand); // forth component is an index to the guide hair strand. For guide hair, it points itself.
        }
        else
        {
            assert(pGuideHair);
            tressfx_vec3& offset = m_SlaveOffset[i];
            m_HairAsset.m_pFollowRootOffset[i] = XMFLOAT4(offset.x, offset.y, offset.z, (float)indexGuideHairStrand);
        }
    }

    // Find the bounding sphere
    BBox bBox;

    for ( int i = 0; i < (int)m_Vertices.size(); ++i )
    {
        const TressFXHairVertex& vertex = m_Vertices[i];
        bBox = Union(bBox, Float3(vertex.position.x, vertex.position.y, vertex.position.z));
    }

    Float3 c; float radius;
    bBox.BoundingSphere(&c, &radius);
    m_HairAsset.m_bSphere.center = XMFLOAT3(c.x, c.y, c.z);
    m_HairAsset.m_bSphere.radius = radius;
}