//=============================================================================

#include <graphene/character/data_structure/Surface_mesh_skin.h>

//=============================================================================

namespace graphene {
namespace character {

//=============================================================================


Surface_mesh_skin::
Surface_mesh_skin() :
    Surface_mesh()
{
    visible_ = true;
    alpha_ = 1.0f;
    material_ = Vec4f(0.0f, 0.6f,0.0f,0.0f);
}


//-----------------------------------------------------------------------------


Surface_mesh_skin::Surface_mesh_skin(const Surface_mesh &mesh) :
    Surface_mesh(mesh)
{
    init_properties();
}

//-----------------------------------------------------------------------------


Surface_mesh_skin::Surface_mesh_skin(const Surface_mesh_skin &mesh) :
    Surface_mesh(mesh)
{
    init_properties();
}


//-----------------------------------------------------------------------------


Surface_mesh_skin::
~Surface_mesh_skin()
{

}


//-----------------------------------------------------------------------------


void
Surface_mesh_skin::
init_properties()
{
    vertices_ = get_vertex_property<Point>("v:point");
    if (vertices_)
    {
        unskinned_vertices_ = vertex_property<Point>("v:unskinned_point");
        for (auto v : vertices())
        {
            unskinned_vertices_[v] = vertices_[v];
        }
    }

    v_normals_ = get_vertex_property<Normal>("v:normal");
    if (!v_normals_)
    {
        update_vertex_normals();
        v_normals_ = get_vertex_property<Normal>("v:normal");
    }

    if (v_normals_)
    {
        v_unskinned_normals_ = vertex_property<Normal>("v:unskinned_normal");
        for (auto v : vertices())
        {
            v_unskinned_normals_[v] = v_normals_[v];
        }
    }

    v_colors_   = get_vertex_property<Color>("v:color");
    v_depends1_ = get_vertex_property<Vec4f>("v:skin_depend");
    v_weights1_ = get_vertex_property<Vec4f>("v:skin_weight");
    v_depends2_ = vertex_property<Vec4f>("v:skin_depend2", Vec4f(0.0f));
    v_weights2_ = vertex_property<Vec4f>("v:skin_weight2", Vec4f(0.0f));

    h_texcoords_ = get_halfedge_property<Texture_coordinate>("h:texcoord");
    h_normals_   = get_halfedge_property<Normal>("h:normal");
    if (h_normals_)
    {
        h_unskinned_normals_ = halfedge_property<Normal>("h:unskinned_normal");
        for (auto h : halfedges())
        {
            h_unskinned_normals_[h] = h_normals_[h];
        }
    }

    Surface_mesh::Mesh_property<Vec3f>       ambient_color;
    Surface_mesh::Mesh_property<Vec3f>       diffuse_color;
    Surface_mesh::Mesh_property<Vec4f>       specular_color;
    Surface_mesh::Mesh_property<float>       alpha;

    ambient_color  = get_mesh_property<Vec3f>("m:ambient_color");
    diffuse_color  = get_mesh_property<Vec3f>("m:diffuse_color");
    specular_color = get_mesh_property<Vec4f>("m:specular_color");
    alpha          = get_mesh_property<float>("m:alpha");

    if (ambient_color)
    {
        const Vec3f &v = ambient_color[0];
        const float avg = (v[0]+v[1]+v[2]) / 3.0f;
        material_[0] = avg;
    }

    if (diffuse_color)
    {
        const Vec3f &v = diffuse_color[0];
        const float avg = (v[0]+v[1]+v[2]) / 3.0f;
        material_[1] = avg;
    }

    if (specular_color)
    {
        const Vec4f &v = specular_color[0];
        const float avg = (v[0]+v[1]+v[2]) / 3.0f;
        material_[2] = avg;
        material_[3] = v[3];
    }

    if (alpha)
    {
        alpha_ = alpha[0];
    }
}

//-----------------------------------------------------------------------------

const geometry::Bounding_box
Surface_mesh_skin::
bbox()
{
    geometry::Bounding_box bbox;
    Vertex_iterator v_it;
    for (v_it=vertices_begin(); v_it != vertices_end(); ++v_it)
    {
        bbox += position(*v_it);
    }

    return bbox;
}


//-----------------------------------------------------------------------------


void
Surface_mesh_skin::
copy_unskinned_properties()
{
    vertices_ = get_vertex_property<Point>("v:point");
    unskinned_vertices_ = get_vertex_property<Point>("v:unskinned_point");

    v_normals_ = get_vertex_property<Normal>("v:normal");
    v_unskinned_normals_ = get_vertex_property<Normal>("v:unskinned_normal");

    h_normals_ = get_halfedge_property<Normal>("h:normal");
    h_unskinned_normals_ = get_halfedge_property<Normal>("h:unskinned_normal");

    if (!unskinned_vertices_)
    {
        std::cout << "[WARNING] update_unskinned_properties(): unskinned vertex property has not been set yet." << std::endl;
        unskinned_vertices_  = add_vertex_property<Point>("v:unskinned_point");
    }
    if (v_normals_&& !v_unskinned_normals_)
    {
        std::cout << "[WARNING] update_unskinned_properties(): unskinned normal property has not been set yet." << std::endl;
        v_unskinned_normals_ = add_vertex_property<Normal>("v:unskinned_normal");
    }
    if (h_normals_ && !h_unskinned_normals_)
    {
        std::cout << "[WARNING] update_unskinned_properties(): unskinned halfedge normal property has not been set yet." << std::endl;
        h_unskinned_normals_ = add_halfedge_property<Normal>("h:unskinned_normal");
    }

    unskinned_vertices_.vector() = vertices_.vector();

    if (v_normals_)
        v_unskinned_normals_.vector() = v_normals_.vector();

    if (h_normals_)
        h_unskinned_normals_.vector() = h_normals_.vector();
}

//=============================================================================
} // namespace character
} // namespace graphene
//=============================================================================
