//
//   Copyright 2014 DreamWorks Animation LLC.
//
//   Licensed under the terms set forth in the LICENSE.txt file available at
//   https://opensubdiv.org/license.
//
#include "../sdc/crease.h"
#include "../sdc/catmarkScheme.h"
#include "../sdc/bilinearScheme.h"
#include "../vtr/types.h"
#include "../vtr/level.h"
#include "../vtr/refinement.h"
#include "../vtr/fvarLevel.h"
#include "../vtr/fvarRefinement.h"
#include "../vtr/stackBuffer.h"

#include <cassert>
#include <cstdio>
#include <utility>


namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {

namespace Vtr {
namespace internal {

//
//  Simple constructor, destructor and basic initializers:
//
Refinement::Refinement(Level const & parentArg, Level & childArg, Sdc::Options const& options) :
    _parent(&parentArg),
    _child(&childArg),
    _options(options),
    _regFaceSize(-1),
    _uniform(false),
    _faceVertsFirst(false),
    _childFaceFromFaceCount(0),
    _childEdgeFromFaceCount(0),
    _childEdgeFromEdgeCount(0),
    _childVertFromFaceCount(0),
    _childVertFromEdgeCount(0),
    _childVertFromVertCount(0),
    _firstChildFaceFromFace(0),
    _firstChildEdgeFromFace(0),
    _firstChildEdgeFromEdge(0),
    _firstChildVertFromFace(0),
    _firstChildVertFromEdge(0),
    _firstChildVertFromVert(0) {

    assert((childArg.getDepth() == 0) && (childArg.getNumVertices() == 0));
    childArg._depth = 1 + parentArg.getDepth();
}

Refinement::~Refinement() {

    for (int i = 0; i < (int)_fvarChannels.size(); ++i) {
        delete _fvarChannels[i];
    }
}

void
Refinement::initializeChildComponentCounts() {

    //
    //  Assign the child's component counts/inventory based on the child components identified:
    //
    _child->_faceCount = _childFaceFromFaceCount;
    _child->_edgeCount = _childEdgeFromFaceCount + _childEdgeFromEdgeCount;
    _child->_vertCount = _childVertFromFaceCount + _childVertFromEdgeCount + _childVertFromVertCount;
}

void
Refinement::initializeSparseSelectionTags() {

    _parentFaceTag.resize(_parent->getNumFaces());
    _parentEdgeTag.resize(_parent->getNumEdges());
    _parentVertexTag.resize(_parent->getNumVertices());
}


//
//  The main refinement method -- provides a high-level overview of refinement:
//
//  The refinement process is as follows:
//      - determine a mapping from parent components to their potential child components
//          - for sparse refinement this mapping will be partial
//      - determine the reverse mapping from chosen child components back to their parents
//          - previously this was optional -- not strictly necessary and comes at added cost
//          - does simplify iteration of child components when refinement is sparse
//      - propagate/initialize component Tags from parents to their children
//          - knowing these Tags for a child component simplifies dealing with it later
//      - subdivide the topology, i.e. populate all topology relations for the child Level
//          - any subset of the 6 relations in a Level can be created
//          - using the minimum required in the last Level is very advantageous
//      - subdivide the sharpness values in the child Level
//      - subdivide face-varying channels in the child Level
//
void
Refinement::refine(Options refineOptions) {

    //  This will become redundant when/if assigned on construction:
    assert(_parent && _child);

    _uniform        = !refineOptions._sparse;
    _faceVertsFirst =  refineOptions._faceVertsFirst;

    //  We may soon have an option here to suppress refinement of FVar channels...
    bool refineOptions_ignoreFVarChannels = false;

    bool optionallyRefineFVar = (_parent->getNumFVarChannels() > 0) && !refineOptions_ignoreFVarChannels;

    //
    //  Initialize the parent-to-child and reverse child-to-parent mappings and propagate
    //  component tags to the new child components:
    //
    populateParentToChildMapping();

    initializeChildComponentCounts();

    populateChildToParentMapping();

    propagateComponentTags();

    //
    //  Subdivide the topology -- populating only those of the 6 relations specified
    //  (though we do require the vertex-face relation for refining FVar channels):
    //
    Relations relationsToPopulate;
    if (refineOptions._minimalTopology) {
        relationsToPopulate.setAll(false);
        relationsToPopulate._faceVertices = true;
    } else {
        relationsToPopulate.setAll(true);
    }
    if (optionallyRefineFVar) {
        relationsToPopulate._vertexFaces = true;
    }

    subdivideTopology(relationsToPopulate);

    //
    //  Subdivide the sharpness values and face-varying channels:
    //    - note there is some dependency of the vertex tag/Rule for semi-sharp vertices
    //
    subdivideSharpnessValues();

    if (optionallyRefineFVar) {
        subdivideFVarChannels();
    }

    //  Various debugging support:
    //
    //printf("Vertex refinement to level %d completed...\n", _child->getDepth());
    //_child->print();
    //printf("  validating refinement to level %d...\n", _child->getDepth());
    //_child->validateTopology();
    //assert(_child->validateTopology());
}


//
//  Methods to construct the parent-to-child mapping
//
void
Refinement::populateParentToChildMapping() {

    allocateParentChildIndices();

    //
    //  If sparse refinement, mark indices of any components in addition to those selected
    //  so that we have the full neighborhood for selected components:
    //
    if (!_uniform) {
        //  Make sure the selection was non-empty -- currently unsupported...
        if (_parentVertexTag.size() == 0) {
            assert("Unsupported empty sparse refinement detected in Refinement" == 0);
        }
        markSparseChildComponentIndices();
    }

    populateParentChildIndices();
}

namespace {
    inline bool isSparseIndexMarked(Index index)   { return index != 0; }

    inline int
    sequenceSparseIndexVector(IndexVector& indexVector, int baseValue = 0) {
        int validCount = 0;
        for (int i = 0; i < (int) indexVector.size(); ++i) {
            indexVector[i] = isSparseIndexMarked(indexVector[i])
                           ? (baseValue + validCount++) : INDEX_INVALID;
        }
        return validCount;
    }

    inline int
    sequenceFullIndexVector(IndexVector& indexVector, int baseValue = 0) {
        int indexCount = (int) indexVector.size();
        for (int i = 0; i < indexCount; ++i) {
            indexVector[i] = baseValue++;
        }
        return indexCount;
    }
}

void
Refinement::populateParentChildIndices() {

    //
    //  Two vertex orderings are currently supported -- ordering vertices refined
    //  from vertices first, or those refined from faces first.  It's possible this
    //  may be extended to more possibilities.  Once the ordering is defined here,
    //  other than analogous initialization in FVarRefinement, the treatment of
    //  vertices in blocks based on origin should make the rest of the code
    //  invariant to ordering changes.
    //
    //  These two blocks now differ only in the utility function that assigns the
    //  sequential values to the index vectors -- so parameterization/simplification
    //  is now possible...
    //
    if (_uniform) {
        //  child faces:
        _firstChildFaceFromFace = 0;
        _childFaceFromFaceCount = sequenceFullIndexVector(_faceChildFaceIndices, _firstChildFaceFromFace);

        //  child edges:
        _firstChildEdgeFromFace = 0;
        _childEdgeFromFaceCount = sequenceFullIndexVector(_faceChildEdgeIndices, _firstChildEdgeFromFace);

        _firstChildEdgeFromEdge = _childEdgeFromFaceCount;
        _childEdgeFromEdgeCount = sequenceFullIndexVector(_edgeChildEdgeIndices, _firstChildEdgeFromEdge);

        //  child vertices:
        if (_faceVertsFirst) {
            _firstChildVertFromFace = 0;
            _childVertFromFaceCount = sequenceFullIndexVector(_faceChildVertIndex, _firstChildVertFromFace);

            _firstChildVertFromEdge = _firstChildVertFromFace + _childVertFromFaceCount;
            _childVertFromEdgeCount = sequenceFullIndexVector(_edgeChildVertIndex, _firstChildVertFromEdge);

            _firstChildVertFromVert = _firstChildVertFromEdge + _childVertFromEdgeCount;
            _childVertFromVertCount = sequenceFullIndexVector(_vertChildVertIndex, _firstChildVertFromVert);
        } else {
            _firstChildVertFromVert = 0;
            _childVertFromVertCount = sequenceFullIndexVector(_vertChildVertIndex, _firstChildVertFromVert);

            _firstChildVertFromFace = _firstChildVertFromVert + _childVertFromVertCount;
            _childVertFromFaceCount = sequenceFullIndexVector(_faceChildVertIndex, _firstChildVertFromFace);

            _firstChildVertFromEdge = _firstChildVertFromFace + _childVertFromFaceCount;
            _childVertFromEdgeCount = sequenceFullIndexVector(_edgeChildVertIndex, _firstChildVertFromEdge);
        }
    } else {
        //  child faces:
        _firstChildFaceFromFace = 0;
        _childFaceFromFaceCount = sequenceSparseIndexVector(_faceChildFaceIndices, _firstChildFaceFromFace);

        //  child edges:
        _firstChildEdgeFromFace = 0;
        _childEdgeFromFaceCount = sequenceSparseIndexVector(_faceChildEdgeIndices, _firstChildEdgeFromFace);

        _firstChildEdgeFromEdge = _childEdgeFromFaceCount;
        _childEdgeFromEdgeCount = sequenceSparseIndexVector(_edgeChildEdgeIndices, _firstChildEdgeFromEdge);

        //  child vertices:
        if (_faceVertsFirst) {
            _firstChildVertFromFace = 0;
            _childVertFromFaceCount = sequenceSparseIndexVector(_faceChildVertIndex, _firstChildVertFromFace);

            _firstChildVertFromEdge = _firstChildVertFromFace + _childVertFromFaceCount;
            _childVertFromEdgeCount = sequenceSparseIndexVector(_edgeChildVertIndex, _firstChildVertFromEdge);

            _firstChildVertFromVert = _firstChildVertFromEdge + _childVertFromEdgeCount;
            _childVertFromVertCount = sequenceSparseIndexVector(_vertChildVertIndex, _firstChildVertFromVert);
        } else {
            _firstChildVertFromVert = 0;
            _childVertFromVertCount = sequenceSparseIndexVector(_vertChildVertIndex, _firstChildVertFromVert);

            _firstChildVertFromFace = _firstChildVertFromVert + _childVertFromVertCount;
            _childVertFromFaceCount = sequenceSparseIndexVector(_faceChildVertIndex, _firstChildVertFromFace);

            _firstChildVertFromEdge = _firstChildVertFromFace + _childVertFromFaceCount;
            _childVertFromEdgeCount = sequenceSparseIndexVector(_edgeChildVertIndex, _firstChildVertFromEdge);
        }
    }
}

void
Refinement::printParentToChildMapping() const {

    printf("Parent-to-child component mapping:\n");
    for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace) {
        printf("  Face %d:\n", pFace);
        printf("    Child vert:  %d\n", _faceChildVertIndex[pFace]);

        printf("    Child faces: ");
        ConstIndexArray childFaces = getFaceChildFaces(pFace);
        for (int i = 0; i < childFaces.size(); ++i) {
            printf(" %d", childFaces[i]);
        }
        printf("\n");

        printf("    Child edges: ");
        ConstIndexArray childEdges = getFaceChildEdges(pFace);
        for (int i = 0; i < childEdges.size(); ++i) {
            printf(" %d", childEdges[i]);
        }
        printf("\n");
    }
    for (Index pEdge = 0; pEdge < _parent->getNumEdges(); ++pEdge) {
        printf("  Edge %d:\n", pEdge);
        printf("    Child vert:  %d\n", _edgeChildVertIndex[pEdge]);

        ConstIndexArray childEdges = getEdgeChildEdges(pEdge);
        printf("    Child edges: %d %d\n", childEdges[0], childEdges[1]);
    }
    for (Index pVert = 0; pVert < _parent->getNumVertices(); ++pVert) {
        printf("  Vert %d:\n", pVert);
        printf("    Child vert:  %d\n", _vertChildVertIndex[pVert]);
    }
}


//
//  Methods to construct the child-to-parent mapping:
//
void
Refinement::populateChildToParentMapping() {

    ChildTag initialChildTags[2][4];
    for (int i = 0; i < 2; ++i) {
        for (int j = 0; j < 4; ++j) {
            ChildTag & tag = initialChildTags[i][j];

            tag._incomplete    = (unsigned char)i;
            tag._parentType    = 0;
            tag._indexInParent = (unsigned char)j;
        }
    }

    populateFaceParentVectors(initialChildTags);
    populateEdgeParentVectors(initialChildTags);
    populateVertexParentVectors(initialChildTags);
}

void
Refinement::populateFaceParentVectors(ChildTag const initialChildTags[2][4]) {

    _childFaceTag.resize(_child->getNumFaces());
    _childFaceParentIndex.resize(_child->getNumFaces());

    populateFaceParentFromParentFaces(initialChildTags);
}
void
Refinement::populateFaceParentFromParentFaces(ChildTag const initialChildTags[2][4]) {

    if (_uniform) {
        Index cFace = getFirstChildFaceFromFaces();
        for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace) {
            ConstIndexArray cFaces = getFaceChildFaces(pFace);
            if (cFaces.size() == 4) {
                _childFaceTag[cFace + 0] = initialChildTags[0][0];
                _childFaceTag[cFace + 1] = initialChildTags[0][1];
                _childFaceTag[cFace + 2] = initialChildTags[0][2];
                _childFaceTag[cFace + 3] = initialChildTags[0][3];

                _childFaceParentIndex[cFace + 0] = pFace;
                _childFaceParentIndex[cFace + 1] = pFace;
                _childFaceParentIndex[cFace + 2] = pFace;
                _childFaceParentIndex[cFace + 3] = pFace;

                cFace += 4;
            } else {
                bool childTooLarge = (cFaces.size() > 4);
                for (int i = 0; i < cFaces.size(); ++i, ++cFace) {
                    _childFaceTag[cFace] = initialChildTags[0][childTooLarge ? 0 : i];
                    _childFaceParentIndex[cFace] = pFace;
                }
            }
        }
    } else {
        //  Child faces of faces:
        for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace) {
            bool incomplete = !_parentFaceTag[pFace]._selected;

            IndexArray cFaces = getFaceChildFaces(pFace);
            if (!incomplete && (cFaces.size() == 4)) {
                _childFaceTag[cFaces[0]] = initialChildTags[0][0];
                _childFaceTag[cFaces[1]] = initialChildTags[0][1];
                _childFaceTag[cFaces[2]] = initialChildTags[0][2];
                _childFaceTag[cFaces[3]] = initialChildTags[0][3];

                _childFaceParentIndex[cFaces[0]] = pFace;
                _childFaceParentIndex[cFaces[1]] = pFace;
                _childFaceParentIndex[cFaces[2]] = pFace;
                _childFaceParentIndex[cFaces[3]] = pFace;
            } else {
                bool childTooLarge = (cFaces.size() > 4);
                for (int i = 0; i < cFaces.size(); ++i) {
                    if (IndexIsValid(cFaces[i])) {
                        _childFaceTag[cFaces[i]] = initialChildTags[incomplete][childTooLarge ? 0 : i];
                        _childFaceParentIndex[cFaces[i]] = pFace;
                    }
                }
            }
        }
    }
}

void
Refinement::populateEdgeParentVectors(ChildTag const initialChildTags[2][4]) {

    _childEdgeTag.resize(_child->getNumEdges());
    _childEdgeParentIndex.resize(_child->getNumEdges());

    populateEdgeParentFromParentFaces(initialChildTags);
    populateEdgeParentFromParentEdges(initialChildTags);
}
void
Refinement::populateEdgeParentFromParentFaces(ChildTag const initialChildTags[2][4]) {

    if (_uniform) {
        Index cEdge = getFirstChildEdgeFromFaces();
        for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace) {
            ConstIndexArray cEdges = getFaceChildEdges(pFace);
            if (cEdges.size() == 4) {
                _childEdgeTag[cEdge + 0] = initialChildTags[0][0];
                _childEdgeTag[cEdge + 1] = initialChildTags[0][1];
                _childEdgeTag[cEdge + 2] = initialChildTags[0][2];
                _childEdgeTag[cEdge + 3] = initialChildTags[0][3];

                _childEdgeParentIndex[cEdge + 0] = pFace;
                _childEdgeParentIndex[cEdge + 1] = pFace;
                _childEdgeParentIndex[cEdge + 2] = pFace;
                _childEdgeParentIndex[cEdge + 3] = pFace;

                cEdge += 4;
            } else {
                bool childTooLarge = (cEdges.size() > 4);
                for (int i = 0; i < cEdges.size(); ++i, ++cEdge) {
                    _childEdgeTag[cEdge] = initialChildTags[0][childTooLarge ? 0 : i];
                    _childEdgeParentIndex[cEdge] = pFace;
                }
            }
        }
    } else {
        for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace) {
            bool incomplete = !_parentFaceTag[pFace]._selected;

            IndexArray cEdges = getFaceChildEdges(pFace);
            if (!incomplete && (cEdges.size() == 4)) {
                _childEdgeTag[cEdges[0]] = initialChildTags[0][0];
                _childEdgeTag[cEdges[1]] = initialChildTags[0][1];
                _childEdgeTag[cEdges[2]] = initialChildTags[0][2];
                _childEdgeTag[cEdges[3]] = initialChildTags[0][3];

                _childEdgeParentIndex[cEdges[0]] = pFace;
                _childEdgeParentIndex[cEdges[1]] = pFace;
                _childEdgeParentIndex[cEdges[2]] = pFace;
                _childEdgeParentIndex[cEdges[3]] = pFace;
            } else {
                bool childTooLarge = (cEdges.size() > 4);
                for (int i = 0; i < cEdges.size(); ++i) {
                    if (IndexIsValid(cEdges[i])) {
                        _childEdgeTag[cEdges[i]] = initialChildTags[incomplete][childTooLarge ? 0 : i];
                        _childEdgeParentIndex[cEdges[i]] = pFace;
                    }
                }
            }
        }
    }
}
void
Refinement::populateEdgeParentFromParentEdges(ChildTag const initialChildTags[2][4]) {

    if (_uniform) {
        Index cEdge = getFirstChildEdgeFromEdges();
        for (Index pEdge = 0; pEdge < _parent->getNumEdges(); ++pEdge, cEdge += 2) {
            _childEdgeTag[cEdge + 0] = initialChildTags[0][0];
            _childEdgeTag[cEdge + 1] = initialChildTags[0][1];

            _childEdgeParentIndex[cEdge + 0] = pEdge;
            _childEdgeParentIndex[cEdge + 1] = pEdge;
        }
    } else {
        for (Index pEdge = 0; pEdge < _parent->getNumEdges(); ++pEdge) {
            bool incomplete = !_parentEdgeTag[pEdge]._selected;

            IndexArray cEdges = getEdgeChildEdges(pEdge);
            if (!incomplete) {
                _childEdgeTag[cEdges[0]] = initialChildTags[0][0];
                _childEdgeTag[cEdges[1]] = initialChildTags[0][1];

                _childEdgeParentIndex[cEdges[0]] = pEdge;
                _childEdgeParentIndex[cEdges[1]] = pEdge;
            } else {
                for (int i = 0; i < 2; ++i) {
                    if (IndexIsValid(cEdges[i])) {
                        _childEdgeTag[cEdges[i]] = initialChildTags[incomplete][i];
                        _childEdgeParentIndex[cEdges[i]] = pEdge;
                    }
                }
            }
        }
    }
}

void
Refinement::populateVertexParentVectors(ChildTag const initialChildTags[2][4]) {

    if (_uniform) {
        _childVertexTag.resize(_child->getNumVertices(), initialChildTags[0][0]);
    } else {
        _childVertexTag.resize(_child->getNumVertices(), initialChildTags[1][0]);
    }
    _childVertexParentIndex.resize(_child->getNumVertices());

    populateVertexParentFromParentFaces(initialChildTags);
    populateVertexParentFromParentEdges(initialChildTags);
    populateVertexParentFromParentVertices(initialChildTags);
}
void
Refinement::populateVertexParentFromParentFaces(ChildTag const initialChildTags[2][4]) {

    if (getNumChildVerticesFromFaces() == 0) return;

    if (_uniform) {
        Index cVert = getFirstChildVertexFromFaces();
        for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace, ++cVert) {
            //  Child tag was initialized as the complete and only child when allocated

            _childVertexParentIndex[cVert] = pFace;
        }
    } else {
        ChildTag const & completeChildTag = initialChildTags[0][0];

        for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace) {
            Index cVert = _faceChildVertIndex[pFace];
            if (IndexIsValid(cVert)) {
                //  Child tag was initialized as incomplete -- reset if complete:
                if (_parentFaceTag[pFace]._selected) {
                    _childVertexTag[cVert] = completeChildTag;
                }
                _childVertexParentIndex[cVert] = pFace;
            }
        }
    }
}
void
Refinement::populateVertexParentFromParentEdges(ChildTag const initialChildTags[2][4]) {

    if (_uniform) {
        Index cVert = getFirstChildVertexFromEdges();
        for (Index pEdge = 0; pEdge < _parent->getNumEdges(); ++pEdge, ++cVert) {
            //  Child tag was initialized as the complete and only child when allocated

            _childVertexParentIndex[cVert] = pEdge;
        }
    } else {
        ChildTag const & completeChildTag = initialChildTags[0][0];

        for (Index pEdge = 0; pEdge < _parent->getNumEdges(); ++pEdge) {
            Index cVert = _edgeChildVertIndex[pEdge];
            if (IndexIsValid(cVert)) {
                //  Child tag was initialized as incomplete -- reset if complete:
                if (_parentEdgeTag[pEdge]._selected) {
                    _childVertexTag[cVert] = completeChildTag;
                }
                _childVertexParentIndex[cVert] = pEdge;
            }
        }
    }
}
void
Refinement::populateVertexParentFromParentVertices(ChildTag const initialChildTags[2][4]) {

    if (_uniform) {
        Index cVert = getFirstChildVertexFromVertices();
        for (Index pVert = 0; pVert < _parent->getNumVertices(); ++pVert, ++cVert) {
            //  Child tag was initialized as the complete and only child when allocated

            _childVertexParentIndex[cVert] = pVert;
        }
    } else {
        ChildTag const & completeChildTag = initialChildTags[0][0];

        for (Index pVert = 0; pVert < _parent->getNumVertices(); ++pVert) {
            Index cVert = _vertChildVertIndex[pVert];
            if (IndexIsValid(cVert)) {
                //  Child tag was initialized as incomplete but these should be complete:
                if (_parentVertexTag[pVert]._selected) {
                    _childVertexTag[cVert] = completeChildTag;
                }
                _childVertexParentIndex[cVert] = pVert;
            }
        }
    }
}


//
//  Methods to propagate/initialize child component tags from their parent component:
//
void
Refinement::propagateComponentTags() {

    populateFaceTagVectors();
    populateEdgeTagVectors();
    populateVertexTagVectors();
}

void
Refinement::populateFaceTagVectors() {

    _child->_faceTags.resize(_child->getNumFaces());

    populateFaceTagsFromParentFaces();
}
void
Refinement::populateFaceTagsFromParentFaces() {

    //
    //  Tags for faces originating from faces are inherited from the parent face:
    //
    Index cFace    = getFirstChildFaceFromFaces();
    Index cFaceEnd = cFace + getNumChildFacesFromFaces();
    for ( ; cFace < cFaceEnd; ++cFace) {
        _child->_faceTags[cFace] = _parent->_faceTags[_childFaceParentIndex[cFace]];
    }
}

void
Refinement::populateEdgeTagVectors() {

    _child->_edgeTags.resize(_child->getNumEdges());

    populateEdgeTagsFromParentFaces();
    populateEdgeTagsFromParentEdges();
}
void
Refinement::populateEdgeTagsFromParentFaces() {

    //
    //  Tags for edges originating from faces are all constant:
    //
    Level::ETag eTag;
    eTag.clear();

    Index cEdge    = getFirstChildEdgeFromFaces();
    Index cEdgeEnd = cEdge + getNumChildEdgesFromFaces();
    for ( ; cEdge < cEdgeEnd; ++cEdge) {
        _child->_edgeTags[cEdge] = eTag;
    }
}
void
Refinement::populateEdgeTagsFromParentEdges() {

    //
    //  Tags for edges originating from edges are inherited from the parent edge:
    //
    Index cEdge    = getFirstChildEdgeFromEdges();
    Index cEdgeEnd = cEdge + getNumChildEdgesFromEdges();
    for ( ; cEdge < cEdgeEnd; ++cEdge) {
        _child->_edgeTags[cEdge] = _parent->_edgeTags[_childEdgeParentIndex[cEdge]];
    }
}

void
Refinement::populateVertexTagVectors() {

    _child->_vertTags.resize(_child->getNumVertices());

    populateVertexTagsFromParentFaces();
    populateVertexTagsFromParentEdges();
    populateVertexTagsFromParentVertices();

    if (!_uniform) {
        for (Index cVert = 0; cVert < _child->getNumVertices(); ++cVert) {
            if (_childVertexTag[cVert]._incomplete) {
                _child->_vertTags[cVert]._incomplete = true;
            }
        }
    }
}
void
Refinement::populateVertexTagsFromParentFaces() {

    //
    //  Similarly, tags for vertices originating from faces are all constant -- with the
    //  unfortunate exception of refining level 0, where the faces may be N-sided and so
    //  introduce new vertices that need to be tagged as extra-ordinary:
    //
    if (getNumChildVerticesFromFaces() == 0) return;

    Level::VTag vTag;
    vTag.clear();
    vTag._rule = Sdc::Crease::RULE_SMOOTH;

    Index cVert    = getFirstChildVertexFromFaces();
    Index cVertEnd = cVert + getNumChildVerticesFromFaces();

    if (_parent->_depth > 0) {
        for ( ; cVert < cVertEnd; ++cVert) {
            _child->_vertTags[cVert] = vTag;
        }
    } else {
        for ( ; cVert < cVertEnd; ++cVert) {
            _child->_vertTags[cVert] = vTag;

            if (_parent->getNumFaceVertices(_childVertexParentIndex[cVert]) != _regFaceSize) {
                _child->_vertTags[cVert]._xordinary = true;
            }
        }
    }
}
void
Refinement::populateVertexTagsFromParentEdges() {

    //
    //  Tags for vertices originating from edges are initialized according to the tags
    //  of the parent edge:
    //
    Level::VTag vTag;
    vTag.clear();

    for (Index pEdge = 0; pEdge < _parent->getNumEdges(); ++pEdge) {
        Index cVert = _edgeChildVertIndex[pEdge];
        if (!IndexIsValid(cVert)) continue;

        //  From the cleared local VTag, we just need to assign properties dependent
        //  on the parent edge:
        Level::ETag const& pEdgeTag = _parent->_edgeTags[pEdge];

        vTag._nonManifold    = pEdgeTag._nonManifold;
        vTag._boundary       = pEdgeTag._boundary;
        vTag._semiSharpEdges = pEdgeTag._semiSharp;
        vTag._infSharpEdges  = pEdgeTag._infSharp;
        vTag._infSharpCrease = pEdgeTag._infSharp;
        vTag._infIrregular   = pEdgeTag._infSharp && pEdgeTag._nonManifold;

        vTag._rule = (Level::VTag::VTagSize)((pEdgeTag._semiSharp || pEdgeTag._infSharp)
                       ? Sdc::Crease::RULE_CREASE : Sdc::Crease::RULE_SMOOTH);

        _child->_vertTags[cVert] = vTag;
    }
}
void
Refinement::populateVertexTagsFromParentVertices() {

    //
    //  Tags for vertices originating from vertices are inherited from the parent vertex:
    //
    Index cVert    = getFirstChildVertexFromVertices();
    Index cVertEnd = cVert + getNumChildVerticesFromVertices();
    for ( ; cVert < cVertEnd; ++cVert) {
        _child->_vertTags[cVert] = _parent->_vertTags[_childVertexParentIndex[cVert]];
        _child->_vertTags[cVert]._incidIrregFace = 0;
    }
}



//
//  Methods to subdivide the topology:
//
//  The main method to subdivide topology is fairly simple -- given a set of relations
//  to populate it simply tests and populates each relation separately.  The method for
//  each relation is responsible for appropriate allocation and initialization of all
//  data involved, and these are virtual -- provided by a quad- or tri-split subclass.
//
void
Refinement::subdivideTopology(Relations const& applyTo) {

    if (applyTo._faceVertices) {
        populateFaceVertexRelation();
    }
    if (applyTo._faceEdges) {
        populateFaceEdgeRelation();
    }
    if (applyTo._edgeVertices) {
        populateEdgeVertexRelation();
    }
    if (applyTo._edgeFaces) {
        populateEdgeFaceRelation();
    }
    if (applyTo._vertexFaces) {
        populateVertexFaceRelation();
    }
    if (applyTo._vertexEdges) {
        populateVertexEdgeRelation();
    }

    //
    //  Additional members of the child Level not specific to any relation...
    //      - note in the case of max-valence, the child's max-valence may be less
    //  than the parent if that maximal parent vertex was not included in the sparse
    //  refinement (possible when sparse refinement is more general).
    //      - it may also be more if the base level was fairly trivial, i.e. less
    //  than the regular valence, or contains non-manifold edges with many faces.
    //      - NOTE that when/if we support N-gons for tri-splitting, that the valence
    //  of edge-vertices introduced on the N-gon may be 7 rather than 6, while N may
    //  be less than both.
    //
    //  In general, we need a better way to deal with max-valence.  The fact that 
    //  each topology relation is independent/optional complicates the issue of 
    //  where to keep track of it...
    //
    if (_splitType == Sdc::SPLIT_TO_QUADS) {
        _child->_maxValence = std::max(_parent->_maxValence, 4);
        _child->_maxValence = std::max(_child->_maxValence, 2 + _parent->_maxEdgeFaces);
    } else {
        _child->_maxValence = std::max(_parent->_maxValence, 6);
        _child->_maxValence = std::max(_child->_maxValence, 2 + _parent->_maxEdgeFaces * 2);
    }
}


//
//  Methods to subdivide sharpness values:
//
void
Refinement::subdivideSharpnessValues() {

    //
    //  Subdividing edge and vertex sharpness values are independent, but in order
    //  to maintain proper classification/tagging of components as semi-sharp, both
    //  must be computed and the neighborhood inspected to properly update the
    //  status.
    //
    //  It is possible to clear the semi-sharp status when propagating the tags and
    //  to reset it (potentially multiple times) when updating the sharpness values.
    //  The vertex subdivision Rule is also affected by this, which complicates the
    //  process.  So for now we apply a post-process to explicitly handle all
    //  semi-sharp vertices.
    //

    //  These methods will update sharpness tags local to the edges and vertices:
    subdivideEdgeSharpness();
    subdivideVertexSharpness();

    //  This method uses local sharpness tags (set above) to update vertex tags that
    //  reflect the neighborhood of the vertex (e.g. its rule):
    reclassifySemisharpVertices();
}

void
Refinement::subdivideEdgeSharpness() {

    Sdc::Crease creasing(_options);

    _child->_edgeSharpness.clear();
    _child->_edgeSharpness.resize(_child->getNumEdges(), Sdc::Crease::SHARPNESS_SMOOTH);

    //
    //  Edge sharpness is passed to child-edges using the parent edge and the
    //  parent vertex for which the child corresponds.  Child-edges are created
    //  from both parent faces and parent edges, but those child-edges created
    //  from a parent face should be within the face's interior and so smooth
    //  (and so previously initialized).
    //
    //  The presence/validity of each parent edges child vert indicates one or
    //  more child edges.
    //
    //  NOTE -- It is also useful at this time to classify the child vert of
    //  this edge based on the creasing information here, particularly when a
    //  non-trivial creasing method like Chaikin is used.  This is not being
    //  done now but is worth considering...
    //
    internal::StackBuffer<float,16> pVertEdgeSharpness;
    if (!creasing.IsUniform()) {
        pVertEdgeSharpness.Reserve(_parent->getMaxValence());
    }

    Index cEdge    = getFirstChildEdgeFromEdges();
    Index cEdgeEnd = cEdge + getNumChildEdgesFromEdges();
    for ( ; cEdge < cEdgeEnd; ++cEdge) {
        float&       cSharpness = _child->_edgeSharpness[cEdge];
        Level::ETag& cEdgeTag   = _child->_edgeTags[cEdge];

        if (cEdgeTag._infSharp) {
            cSharpness = Sdc::Crease::SHARPNESS_INFINITE;
        } else if (cEdgeTag._semiSharp) {
            Index pEdge      = _childEdgeParentIndex[cEdge];
            float pSharpness = _parent->_edgeSharpness[pEdge];

            if (creasing.IsUniform()) {
                cSharpness = creasing.SubdivideUniformSharpness(pSharpness);
            } else {
                ConstIndexArray pEdgeVerts = _parent->getEdgeVertices(pEdge);
                Index           pVert      = pEdgeVerts[_childEdgeTag[cEdge]._indexInParent];
                ConstIndexArray pVertEdges = _parent->getVertexEdges(pVert);

                for (int i = 0; i < pVertEdges.size(); ++i) {
                    pVertEdgeSharpness[i] = _parent->_edgeSharpness[pVertEdges[i]];
                }
                cSharpness = creasing.SubdivideEdgeSharpnessAtVertex(pSharpness, pVertEdges.size(),
                                                                         pVertEdgeSharpness);
            }
            if (! Sdc::Crease::IsSharp(cSharpness)) {
                cEdgeTag._semiSharp = false;
            }
        }
    }
}

void
Refinement::subdivideVertexSharpness() {

    Sdc::Crease creasing(_options);

    _child->_vertSharpness.clear();
    _child->_vertSharpness.resize(_child->getNumVertices(), Sdc::Crease::SHARPNESS_SMOOTH);

    //
    //  All child-verts originating from faces or edges are initialized as smooth
    //  above.  Only those originating from vertices require "subdivided" values:
    //
    //  Only deal with the subrange of vertices originating from vertices:
    Index cVertBegin = getFirstChildVertexFromVertices();
    Index cVertEnd   = cVertBegin + getNumChildVerticesFromVertices();

    for (Index cVert = cVertBegin; cVert < cVertEnd; ++cVert) {
        float&       cSharpness = _child->_vertSharpness[cVert];
        Level::VTag& cVertTag   = _child->_vertTags[cVert];

        if (cVertTag._infSharp) {
            cSharpness = Sdc::Crease::SHARPNESS_INFINITE;
        } else if (cVertTag._semiSharp) {
            Index pVert      = _childVertexParentIndex[cVert];
            float pSharpness = _parent->_vertSharpness[pVert];

            cSharpness = creasing.SubdivideVertexSharpness(pSharpness);
            if (! Sdc::Crease::IsSharp(cSharpness)) {
                cVertTag._semiSharp = false;
            }
        }
    }
}

void
Refinement::reclassifySemisharpVertices() {

    typedef Level::VTag::VTagSize VTagSize;

    Sdc::Crease creasing(_options);

    //
    //  Inspect all vertices derived from edges -- for those whose parent edges were semisharp,
    //  reset the semisharp tag and the associated Rule according to the sharpness pair for the
    //  subdivided edges (note this may be better handled when the edge sharpness is computed):
    //
    Index vertFromEdgeBegin = getFirstChildVertexFromEdges();
    Index vertFromEdgeEnd   = vertFromEdgeBegin + getNumChildVerticesFromEdges();

    for (Index cVert = vertFromEdgeBegin; cVert < vertFromEdgeEnd; ++cVert) {
        Level::VTag& cVertTag = _child->_vertTags[cVert];
        if (!cVertTag._semiSharpEdges) continue;

        Index pEdge = _childVertexParentIndex[cVert];

        ConstIndexArray cEdges = getEdgeChildEdges(pEdge);

        if (_childVertexTag[cVert]._incomplete) {
            //  One child edge likely missing -- assume Crease if remaining edge semi-sharp:
            cVertTag._semiSharpEdges = (IndexIsValid(cEdges[0]) && _child->_edgeTags[cEdges[0]]._semiSharp) ||
                                       (IndexIsValid(cEdges[1]) && _child->_edgeTags[cEdges[1]]._semiSharp);
            cVertTag._rule = (VTagSize)(cVertTag._semiSharpEdges ? Sdc::Crease::RULE_CREASE : Sdc::Crease::RULE_SMOOTH);
        } else {
            int sharpEdgeCount = _child->_edgeTags[cEdges[0]]._semiSharp + _child->_edgeTags[cEdges[1]]._semiSharp;

            cVertTag._semiSharpEdges = (sharpEdgeCount > 0);
            cVertTag._rule = (VTagSize)(creasing.DetermineVertexVertexRule(0.0, sharpEdgeCount));
        }
    }

    //
    //  Inspect all vertices derived from vertices -- for those whose parent vertices were
    //  semisharp (inherited in the child vert's tag), inspect and reset the semisharp tag
    //  and the associated Rule (based on neighboring child edges around the child vertex).
    //
    //  We should never find such a vertex "incomplete" in a sparse refinement as a parent
    //  vertex is either selected or not, but never neighboring.  So the only complication
    //  here is whether the local topology of child edges exists -- it may have been pruned
    //  from the last level to reduce memory.  If so, we use the parent to identify the
    //  child edges.
    //
    //  In both cases, we count the number of sharp and semisharp child edges incident the
    //  child vertex and adjust the "semisharp" and "rule" tags accordingly.
    //
    Index vertFromVertBegin = getFirstChildVertexFromVertices();
    Index vertFromVertEnd   = vertFromVertBegin + getNumChildVerticesFromVertices();

    for (Index cVert = vertFromVertBegin; cVert < vertFromVertEnd; ++cVert) {
        Index pVert = _childVertexParentIndex[cVert];
        Level::VTag const& pVertTag = _parent->_vertTags[pVert];

        //  Skip if parent not semi-sharp:
        if (!pVertTag._semiSharp && !pVertTag._semiSharpEdges) continue;

        //
        //  We need to inspect the child neighborhood's sharpness when either semi-sharp
        //  edges were present around the parent vertex, or the parent vertex sharpness
        //  decayed:
        //
        Level::VTag& cVertTag = _child->_vertTags[cVert];

        bool sharpVertexDecayed = pVertTag._semiSharp && !cVertTag._semiSharp;

        if (pVertTag._semiSharpEdges || sharpVertexDecayed) {
            int infSharpEdgeCount = 0;
            int semiSharpEdgeCount = 0;

            bool cVertEdgesPresent = (_child->getNumVertexEdgesTotal() > 0);
            if (cVertEdgesPresent) {
                ConstIndexArray cEdges = _child->getVertexEdges(cVert);

                for (int i = 0; i < cEdges.size(); ++i) {
                    Level::ETag cEdgeTag = _child->_edgeTags[cEdges[i]];

                    infSharpEdgeCount  += cEdgeTag._infSharp;
                    semiSharpEdgeCount += cEdgeTag._semiSharp;
                }
            } else {
                ConstIndexArray      pEdges      = _parent->getVertexEdges(pVert);
                ConstLocalIndexArray pVertInEdge = _parent->getVertexEdgeLocalIndices(pVert);

                for (int i = 0; i < pEdges.size(); ++i) {
                    ConstIndexArray cEdgePair = getEdgeChildEdges(pEdges[i]);

                    Index       cEdge    = cEdgePair[pVertInEdge[i]];
                    Level::ETag cEdgeTag = _child->_edgeTags[cEdge];

                    infSharpEdgeCount  += cEdgeTag._infSharp;
                    semiSharpEdgeCount += cEdgeTag._semiSharp;
                }
            }
            cVertTag._semiSharpEdges = (semiSharpEdgeCount > 0);

            if (!cVertTag._semiSharp && !cVertTag._infSharp) {
                cVertTag._rule = (VTagSize)(creasing.DetermineVertexVertexRule(0.0,
                                        infSharpEdgeCount + semiSharpEdgeCount));
            }
        }
    }
}

//
//  Methods to subdivide face-varying channels:
//
void
Refinement::subdivideFVarChannels() {

    assert(_child->_fvarChannels.size() == 0);
    assert(this->_fvarChannels.size() == 0);

    int channelCount = _parent->getNumFVarChannels();

    for (int channel = 0; channel < channelCount; ++channel) {
        FVarLevel* parentFVar = _parent->_fvarChannels[channel];

        FVarLevel*      childFVar  = new FVarLevel(*_child);
        FVarRefinement* refineFVar = new FVarRefinement(*this, *parentFVar, *childFVar);

        refineFVar->applyRefinement();

        _child->_fvarChannels.push_back(childFVar);
        this->_fvarChannels.push_back(refineFVar);
    }
}

//
//  Marking of sparse child components -- including those selected and those neighboring...
//
//      For schemes requiring neighboring support, this is the equivalent of the "guarantee
//  neighbors" in Hbr -- it ensures that all components required to define the limit of
//  those "selected" are also generated in the refinement.
//
//  The difference with Hbr is that we do this in a single pass for all components once
//  "selection" of components of interest has been completed.
//
//  Considering two approaches:
//      1) By Vertex neighborhoods:
//          - for each base vertex
//              - for each incident face
//                  - test and mark components for its child face
//  or
//      2) By Edge and Face contents:
//          - for each base edge
//              - test and mark local components
//          - for each base face
//              - test and mark local components
//
//  Given a typical quad mesh with N verts, N faces and 2*N edges, determine which is more
//  efficient...
//
//  Going with (2) initially for simplicity -- certain aspects of (1) are awkward, i.e. the
//  identification of child-edges to be marked (trivial in (2).  We are also guaranteed with
//  (2) that we only visit each component once, i.e. each edge and each face.
//
//  Revising the above assessment... (2) has gotten WAY more complicated once the ability to
//  select child faces is provided.  Given that feature is important to Manuel for support
//  of the FarStencilTables we have to assume it will be needed.  So we'll try (1) out as it
//  will be simpler to get it correct -- we can work on improving performance later.
//
//  Complexity added by child component selection:
//      - the child vertex of the component can now be selected as part of a child face or
//  edge, and so the parent face or edge is not fully selected.  So we've had to add another
//  bit to the marking masks to indicate when a parent component is "fully selected".
//      - selecting a child face creates the situation where child edges of parent edges do
//  not have any selected vertex at their ends -- both can be neighboring.  This complicated
//  the marking of neighboring child edges, which was otherwise trivial -- if any end vertex
//  of a child edge (of a parent edge) was selected, the child edge was at least neighboring.
//
//  Final note on the marking technique:
//      There are currently two values to the marking of child components, which are no
//  longer that useful.  It is now sufficient, and not likely to be necessary, to distinguish
//  between what was selected or added to support it.  Ultimately that will be determined by
//  inspecting the selected flag on the parent component once the child-to-parent map is in
//  place.
//
namespace {
    Index const IndexSparseMaskNeighboring = (1 << 0);
    Index const IndexSparseMaskSelected    = (1 << 1);

    inline void markSparseIndexNeighbor(Index& index) { index = IndexSparseMaskNeighboring; }
    inline void markSparseIndexSelected(Index& index) { index = IndexSparseMaskSelected; }
}

void
Refinement::markSparseChildComponentIndices() {

    //
    //  There is an explicit ordering here as the work done for vertices is a subset
    //  of what is required for edges, which in turn is a subset of what is required
    //  for faces.  This ordering and their related implementations tries to avoid
    //  doing redundant work and accomplishing everything necessary in a single
    //  iteration through each component type.
    //
    markSparseVertexChildren();
    markSparseEdgeChildren();
    markSparseFaceChildren();
}


void
Refinement::markSparseVertexChildren() {

    assert(_parentVertexTag.size() > 0);

    //
    //  For each parent vertex:
    //      - mark the descending child vertex for each selected vertex
    //
    for (Index pVert = 0; pVert < parent().getNumVertices(); ++pVert) {
        if (_parentVertexTag[pVert]._selected) {
            markSparseIndexSelected(_vertChildVertIndex[pVert]);
        }
    }
}

void
Refinement::markSparseEdgeChildren() {

    assert(_parentEdgeTag.size() > 0);

    //
    //  For each parent edge:
    //      - mark the descending child edges and vertex for each selected edge
    //      - test each end vertex of unselected edges to see if selected:
    //          - mark both the child edge and the middle child vertex if so
    //      - set transitional bit for all edges based on selection of incident faces
    //
    //  Note that no edges have been marked "fully selected" -- only their vertices have
    //  been marked and marking of their child edges deferred to visiting each edge only
    //  once here.
    //
    for (Index pEdge = 0; pEdge < parent().getNumEdges(); ++pEdge) {
        IndexArray      eChildEdges = getEdgeChildEdges(pEdge);
        ConstIndexArray eVerts      = parent().getEdgeVertices(pEdge);

        SparseTag& pEdgeTag = _parentEdgeTag[pEdge];

        if (pEdgeTag._selected) {
            markSparseIndexSelected(eChildEdges[0]);
            markSparseIndexSelected(eChildEdges[1]);
            markSparseIndexSelected(_edgeChildVertIndex[pEdge]);
        } else {
            if (_parentVertexTag[eVerts[0]]._selected) {
                markSparseIndexNeighbor(eChildEdges[0]);
                markSparseIndexNeighbor(_edgeChildVertIndex[pEdge]);
            }
            if (_parentVertexTag[eVerts[1]]._selected) {
                markSparseIndexNeighbor(eChildEdges[1]);
                markSparseIndexNeighbor(_edgeChildVertIndex[pEdge]);
            }
        }

        //
        //  TAG the parent edges as "transitional" here if only one was selected (or in
        //  the more general non-manifold case, they are not all selected the same way).
        //  We use the transitional tags on the edges to TAG the parent face below.
        //
        //  Note -- this is best done now rather than as a post-process as we have more
        //  explicit information about the selected components.  Unless we also tag the
        //  parent faces as selected, we can't easily tell from the child-faces of the
        //  edge's incident faces which were generated by selection or neighboring...
        //
        ConstIndexArray eFaces = parent().getEdgeFaces(pEdge);
        if (eFaces.size() == 2) {
            pEdgeTag._transitional = (_parentFaceTag[eFaces[0]]._selected !=
                                      _parentFaceTag[eFaces[1]]._selected);
        } else if (eFaces.size() < 2) {
            pEdgeTag._transitional = false;
        } else {
            bool isFace0Selected = _parentFaceTag[eFaces[0]]._selected;

            pEdgeTag._transitional = false;
            for (int i = 1; i < eFaces.size(); ++i) {
                if (_parentFaceTag[eFaces[i]]._selected != isFace0Selected) {
                    pEdgeTag._transitional = true;
                    break;
                }
            }
        }
    }
}

} // end namespace internal
} // end namespace Vtr

} // end namespace OPENSUBDIV_VERSION
} // end namespace OpenSubdiv
