/************************************************************************************/ /**
// Copyright (c) 2006-2024 Advanced Micro Devices, Inc. All rights reserved.
/// \author AMD Developer Tools Team
/// \file
****************************************************************************************/
#ifndef MESH_H
#define MESH_H

#include "soup.h"
#include "timer.h"
#include "error.h"

typedef std::vector<std::vector<UINT> > VTArray;

class Mesh : public Soup
{
public:
    Mesh(void)
    {
        ;
    }
    virtual ~Mesh()
    {
        ;
    }
    int ComputeVT(VTArray& vtOut);
    int ComputeAE(const VTArray& vt);
    int ComputeVV(void);

    // across-edge information
    std::vector<UINT>& ae(int i)
    {
        return ae_[i];
    }
    const std::vector<UINT>& ae(int i) const
    {
        return ae_[i];
    }
    std::vector<std::vector<UINT> >& ae(void)
    {
        return ae_;
    }
    const std::vector<std::vector<UINT> >& ae(void) const
    {
        return ae_;
    }

    // neighbor vertex information
    std::vector<UINT>& vv(int i)
    {
        return vv_[i];
    }
    const std::vector<UINT>& vv(int i) const
    {
        return vv_[i];
    }
    std::vector<std::vector<UINT> >& vv(void)
    {
        return vv_;
    }
    const std::vector<std::vector<UINT> >& vv(void) const
    {
        return vv_;
    }

protected:
    // across edge info (same as structure as a triangle)
    std::vector<std::vector<UINT> > ae_;
    // vertex neighboring vertices
    std::vector<std::vector<UINT> > vv_;

private:
    // prevent catastrophic copies
    Mesh(const Mesh&);
    Mesh& operator=(const Mesh&);
};

inline int Mesh::ComputeVV(void)
{
    Timer time;
    debugf(("Finding vertex neighbors"));

    vv().resize(v().size());

    for (int i = 0; i < static_cast<int>(t().size()); i++)
    {
        vv(t(i)[0]).push_back(t(i)[1]);
        vv(t(i)[1]).push_back(t(i)[0]);
        vv(t(i)[1]).push_back(t(i)[2]);
        vv(t(i)[2]).push_back(t(i)[1]);
        vv(t(i)[2]).push_back(t(i)[0]);
        vv(t(i)[0]).push_back(t(i)[2]);
    }

    debugf(("Done in %gs", time.GetElapsed()));
    return 1;
}

inline int Mesh::ComputeVT(VTArray& vtOut)
{
    Timer time;
    debugf(("Finding vertex faces"));

    // get all faces that use each vertex
    vtOut.resize(v().size());

    for (int f = 0; f < static_cast<int>(t().size()); f++)
    {
        Soup::Triangle& face = t(f);

        for (int i = 0; i < 3; i++)
        {
            vtOut[face[i]].push_back(f);
        }
    }

    debugf(("Done in %gs", time.GetElapsed()));
    return 1;
}

inline int Mesh::ComputeAE(const VTArray& vt)
{
    Timer time;
    debugf(("Finding across edge-info"));
    // clean across-edge info
    ae().resize(t().size());

    // find across-edge info
    for (int f = 0; f < static_cast<int>(t().size()); f++)
    {
        for (int i = 0; i < 3; i++)
        {
            int in = (i + 1) % 3;
            // get the vertices in edge
            int v  = t(f)[i];
            int vn = t(f)[in];

            // for each face that use v
            for (int j = 0; j < static_cast<int>(vt[v].size()); j++)
            {
                // check if face has vn too and is not f
                int af = vt[v][j];

                if (af != f)
                {
                    for (int k = 0; k < 3; k++)
                    {
                        if (t(af)[k] == vn)
                        {
                            ae(f).push_back(af);
                        }
                    }
                }
            }
        }
    }

    debugf(("Done in %gs", time.GetElapsed()));
    return 1;
}

#endif