
/*
 * -----------------------------------------------------------------------------
 * This source file is part of OGRE-Next
 * (Object-oriented Graphics Rendering Engine)
 * For the latest info, see http://www.ogre3d.org/
 *
 * Copyright (c) 2000-2014 Torus Knot Software Ltd
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 * -----------------------------------------------------------------------------
 */

#ifndef _LodCollapser_H__
#define _LodCollapser_H__

#include "OgreLodPrerequisites.h"

#include "OgreLodData.h"

namespace Ogre
{
    class _OgreLodExport LodCollapser
    {
    public:
        virtual ~LodCollapser() {}
        /// Reduces vertices until vertexCountLimit or collapseCostLimit is reached.
        virtual void collapse( LodData *data, LodCollapseCost *cost, LodOutputProvider *output,
                               int vertexCountLimit, Real collapseCostLimit );

        /**
         * @brief Returns the last reduced vertex.
         *
         * You should call this function after generateLodLevels!
         *
         * @param data This parameter is not used, but this will guarantee that data is alive.
         * @param outVec The vector receiving the position of the vertex.
         * @return Whether the outVec was changed. If the mesh is reduced at least 1 vertex, then it
         * returns true.
         */
        bool _getLastVertexPos( LodData *data, Vector3 &outVec );

        /**
         * @brief Returns the destination of the edge, which was last reduced.
         *
         * You should call this function after generateLodLevels!
         *
         * @param data This parameter is not used, but this will guarantee that data is alive.
         * @param outVec The vector receiving the CollapseTo position.
         * @return Whether the outVec was changed. If the mesh is reduced at least 1 vertex, then it
         * returns true.
         */
        bool _getLastVertexCollapseTo( LodData *data, Vector3 &outVec );

    protected:
        struct CollapsedEdge
        {
            unsigned int srcID;
            unsigned int dstID;
            unsigned int submeshID;
        };

        typedef vector<CollapsedEdge>::type CollapsedEdges;

        /// tmp variable, to overcome allocation on every collapse.
        CollapsedEdges tmpCollapsedEdges;

        /// Last reduced vertex. Can be used for debugging purposes. For example the Mesh Lod Editor uses
        /// it to select edge.
        LodData::Vertex *mLastReducedVertex;

        /// Collapses a single vertex.
        void collapseVertex( LodData *data, LodCollapseCost *cost, LodOutputProvider *output,
                             LodData::Vertex *src );
        void assertOutdatedCollapseCost( LodData *data, LodCollapseCost *cost,
                                         LodData::VertexI vertexi );
        void assertValidMesh( LodData *data );
        void assertValidVertex( LodData *data, LodData::VertexI vi );
        bool hasSrcID( unsigned int srcID, unsigned submeshID );
        void removeTriangleFromEdges( LodData *data, LodData::Triangle *triangle,
                                      LodData::VertexI skipi );

        size_t findDstID( unsigned int srcID, unsigned submeshID );
        void   replaceVertexID( LodData *data, LodData::Triangle *triangle, unsigned int oldID,
                                unsigned int newID, LodData::Vertex *dst );
    };

}  // namespace Ogre
#endif
