// Wild Magic Source Code
// David Eberly
// http://www.geometrictools.com
// Copyright (c) 1998-2007
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or (at
// your option) any later version.  The license is available for reading at
// either of the locations:
//     http://www.gnu.org/copyleft/lgpl.html
//     http://www.geometrictools.com/License/WildMagicLicense.pdf
//
// Version: 4.0.1 (2007/06/16)

#include "Wm4GraphicsPCH.h"
#include "Wm4Triangles.h"
using namespace Wm4;

WM4_IMPLEMENT_RTTI(Wm4,Triangles,Geometry);
WM4_IMPLEMENT_ABSTRACT_STREAM(Triangles);
WM4_IMPLEMENT_DEFAULT_STREAM(Triangles,Geometry);
WM4_IMPLEMENT_DEFAULT_NAME_ID(Triangles,Geometry);

//----------------------------------------------------------------------------
Triangles::Triangles ()
{
    // The Type value will be assigned by the derived class.
}
//----------------------------------------------------------------------------
Triangles::Triangles (VertexBuffer* pkVBuffer, IndexBuffer* pkIBuffer)
    :
    Geometry(pkVBuffer,pkIBuffer)
{
    // The Type value will be assigned by the derived class.
}
//----------------------------------------------------------------------------
Triangles::~Triangles ()
{
}
//----------------------------------------------------------------------------
bool Triangles::GetModelTriangle (int i, Triangle3f& rkMTri) const
{
    int iV0, iV1, iV2;
    if (GetTriangle(i,iV0,iV1,iV2))
    {
        rkMTri.V[0] = VBuffer->Position3(iV0);
        rkMTri.V[1] = VBuffer->Position3(iV1);
        rkMTri.V[2] = VBuffer->Position3(iV2);
        return true;
    }
    return false;
}
//----------------------------------------------------------------------------
bool Triangles::GetWorldTriangle (int i, Triangle3f& rkWTri) const
{
    int iV0, iV1, iV2;
    if (GetTriangle(i,iV0,iV1,iV2))
    {
        rkWTri.V[0] = World.ApplyForward(VBuffer->Position3(iV0));
        rkWTri.V[1] = World.ApplyForward(VBuffer->Position3(iV1));
        rkWTri.V[2] = World.ApplyForward(VBuffer->Position3(iV2));
        return true;
    }
    return false;
}
//----------------------------------------------------------------------------
void Triangles::GenerateNormals ()
{
    if (!VBuffer->GetAttributes().HasNormal())
    {
        Attributes kAttr = VBuffer->GetAttributes();
        kAttr.SetNormalChannels(3);
        VertexBuffer* pkVBufferPlusNormals = WM4_NEW VertexBuffer(kAttr,
            VBuffer->GetVertexQuantity());
        int iChannels;
        float* afData = pkVBufferPlusNormals->GetData();
        VBuffer->BuildCompatibleArray(kAttr,false,iChannels,afData);
        assert(iChannels == pkVBufferPlusNormals->GetChannelQuantity());
        VBuffer = pkVBufferPlusNormals;
    }

    UpdateModelNormals();
}
//----------------------------------------------------------------------------
void Triangles::UpdateModelNormals ()
{
    // Calculate normals from vertices by weighted averages of facet planes
    // that contain the vertices.
    if (!VBuffer->GetAttributes().HasNormal())
    {
        return;
    }

    int iVQuantity = VBuffer->GetVertexQuantity();
    int i;
    for (i = 0; i < iVQuantity; i++)
    {
        VBuffer->Normal3(i) = Vector3f::ZERO;
    }

    int iTQuantity = GetTriangleQuantity();
    for (i = 0; i < iTQuantity; i++)
    {
        // get vertex indices
        int iV0, iV1, iV2;
        if (!GetTriangle(i,iV0,iV1,iV2))
        {
            continue;
        }

        // get vertices
        Vector3f& rkV0 = VBuffer->Position3(iV0);
        Vector3f& rkV1 = VBuffer->Position3(iV1);
        Vector3f& rkV2 = VBuffer->Position3(iV2);

        // compute the normal (length provides the weighted sum)
        Vector3f kEdge1 = rkV1 - rkV0;
        Vector3f kEdge2 = rkV2 - rkV0;
        Vector3f kNormal = kEdge1.Cross(kEdge2);

        VBuffer->Normal3(iV0) += kNormal;
        VBuffer->Normal3(iV1) += kNormal;
        VBuffer->Normal3(iV2) += kNormal;
    }

    for (i = 0; i < iVQuantity; i++)
    {
        VBuffer->Normal3(i).Normalize();
    }
}
//----------------------------------------------------------------------------
