{
    return (a == b) || (b.isPrefixOf(a));
}

/**
 *
 */

#include "mongo/db/update_index_data.h"
#include "mongo/bson/util/builder.h"

namespace mongo {

namespace {
enum class NumericPathComponentResult {
    kNumericOrDollar,
    kConsecutiveNumbers,
    kNonNumericOrDollar
};

NumericPathComponentResult checkNumericOrDollarPathComponent(const FieldRef& path,
                                                             size_t pathIdx,
                                                             const StringData& pathComponent) {
    if (pathComponent == "$"_sd) {
        return NumericPathComponentResult::kNumericOrDollar;
    }

    if (FieldRef::isNumericPathComponentLenient(pathComponent)) {
        // Peek ahead to see if the next component is also all digits. This implies that the
        // update is attempting to create a numeric field name which would violate the
        // "ambiguous field name in array" constraint for multi-key indexes. Break early in this
        // case and conservatively return that this path affects the prefix of the consecutive
        // numerical path components. For instance, an input such as 'a.0.1.b.c' would return
        // the canonical index path of 'a'.
        if ((pathIdx + 1) < path.numParts() &&
            FieldRef::isNumericPathComponentLenient(path.getPart(pathIdx + 1))) {
            return NumericPathComponentResult::kConsecutiveNumbers;
        }
        return NumericPathComponentResult::kNumericOrDollar;
    }

    return NumericPathComponentResult::kNonNumericOrDollar;
}

/**
 * Checks whether a given Document path overlaps with an indexed path
 */
bool pathOverlaps(const FieldRef& path, const FieldRef& indexedPath) {
    size_t pathIdx = 0;
    size_t indexedPathIdx = 0;

    while (pathIdx < path.numParts() && indexedPathIdx < indexedPath.numParts()) {
        auto pathComponent = path.getPart(pathIdx);

        // The first part of the path must always be a valid field name, since it's not possible to
        // store a top-level array or '$' field name in a document.
        if (pathIdx > 0) {
            NumericPathComponentResult res =
                checkNumericOrDollarPathComponent(path, pathIdx, pathComponent);
            if (res == NumericPathComponentResult::kNumericOrDollar) {
                ++pathIdx;
                continue;
            }
            if (res == NumericPathComponentResult::kConsecutiveNumbers) {
                // This case implies that the update is attempting to create a numeric field name
                // which would violate the "ambiguous field name in array" constraint for multi-key
                // indexes. Break early in this case and conservatively return that this path
                // affects the prefix of the consecutive numerical path components. For instance, an
                // input path such as 'a.0.1.b.c' would match indexed path of 'a.d'.
                return true;
            }
        }

        StringData indexedPathComponent = indexedPath.getPart(indexedPathIdx);
        if (pathComponent != indexedPathComponent) {
            return false;
        }

        ++pathIdx;
        ++indexedPathIdx;
    }

    return true;
}
}  // namespace

UpdateIndexData::UpdateIndexData() : _allPathsIndexed(false) {}

void UpdateIndexData::addPath(const FieldRef& path) {
    _canonicalPaths.insert(getCanonicalIndexField(path));
}

void UpdateIndexData::addPathComponent(StringData pathComponent) {
    _pathComponents.insert(pathComponent.toString());
}

void UpdateIndexData::allPathsIndexed() {
    _allPathsIndexed = true;
}

void UpdateIndexData::clear() {
    _canonicalPaths.clear();
    _pathComponents.clear();
    _allPathsIndexed = false;
}

bool UpdateIndexData::mightBeIndexed(const FieldRef& path) const {
    if (_allPathsIndexed) {
        return true;
    }

    for (const auto& indexedPath : _canonicalPaths) {
        if (pathOverlaps(path, indexedPath)) {
            return true;
        }
    }

    for (const auto& pathComponent : _pathComponents) {
        for (size_t partIdx = 0; partIdx < path.numParts(); ++partIdx) {
            if (pathComponent == path.getPart(partIdx)) {
                return true;
            }
        }
    }

    return false;
}

bool UpdateIndexData::_startsWith(const FieldRef& a, const FieldRef& b) const

FieldRef UpdateIndexData::getCanonicalIndexField(const FieldRef& path) {
    if (path.numParts() <= 1)
        return path;

    // The first part of the path must always be a valid field name, since it's not possible to
    // store a top-level array or '$' field name in a document.
    FieldRef buf(path.getPart(0));
    for (size_t i = 1; i < path.numParts(); ++i) {
        auto pathComponent = path.getPart(i);

        NumericPathComponentResult res = checkNumericOrDollarPathComponent(path, i, pathComponent);
        if (res == NumericPathComponentResult::kNumericOrDollar) {
            continue;
        }
        if (res == NumericPathComponentResult::kConsecutiveNumbers) {
            break;
        }

        buf.appendPart(pathComponent);
    }

    return buf;
}

bool UpdateIndexData::isComponentPartOfCanonicalizedIndexPath(StringData pathComponent) {
    return pathComponent != "$"_sd && !FieldRef::isNumericPathComponentLenient(pathComponent);
}
}  // namespace mongo


{
    if (_allPathsIndexed) {
        return true;
    }

/**
 *
 */

#include "mongo/db/update_index_data.h"
#include "mongo/bson/util/builder.h"

namespace mongo {

namespace {
enum class NumericPathComponentResult {
    kNumericOrDollar,
    kConsecutiveNumbers,
    kNonNumericOrDollar
};

NumericPathComponentResult checkNumericOrDollarPathComponent(const FieldRef& path,
                                                             size_t pathIdx,
                                                             const StringData& pathComponent) {
    if (pathComponent == "$"_sd) {
        return NumericPathComponentResult::kNumericOrDollar;
    }

    if (FieldRef::isNumericPathComponentLenient(pathComponent)) {
        // Peek ahead to see if the next component is also all digits. This implies that the
        // update is attempting to create a numeric field name which would violate the
        // "ambiguous field name in array" constraint for multi-key indexes. Break early in this
        // case and conservatively return that this path affects the prefix of the consecutive
        // numerical path components. For instance, an input such as 'a.0.1.b.c' would return
        // the canonical index path of 'a'.
        if ((pathIdx + 1) < path.numParts() &&
            FieldRef::isNumericPathComponentLenient(path.getPart(pathIdx + 1))) {
            return NumericPathComponentResult::kConsecutiveNumbers;
        }
        return NumericPathComponentResult::kNumericOrDollar;
    }

    return NumericPathComponentResult::kNonNumericOrDollar;
}

/**
 * Checks whether a given Document path overlaps with an indexed path
 */
bool pathOverlaps(const FieldRef& path, const FieldRef& indexedPath) {
    size_t pathIdx = 0;
    size_t indexedPathIdx = 0;

    while (pathIdx < path.numParts() && indexedPathIdx < indexedPath.numParts()) {
        auto pathComponent = path.getPart(pathIdx);

        // The first part of the path must always be a valid field name, since it's not possible to
        // store a top-level array or '$' field name in a document.
        if (pathIdx > 0) {
            NumericPathComponentResult res =
                checkNumericOrDollarPathComponent(path, pathIdx, pathComponent);
            if (res == NumericPathComponentResult::kNumericOrDollar) {
                ++pathIdx;
                continue;
            }
            if (res == NumericPathComponentResult::kConsecutiveNumbers) {
                // This case implies that the update is attempting to create a numeric field name
                // which would violate the "ambiguous field name in array" constraint for multi-key
                // indexes. Break early in this case and conservatively return that this path
                // affects the prefix of the consecutive numerical path components. For instance, an
                // input path such as 'a.0.1.b.c' would match indexed path of 'a.d'.
                return true;
            }
        }

        StringData indexedPathComponent = indexedPath.getPart(indexedPathIdx);
        if (pathComponent != indexedPathComponent) {
            return false;
        }

        ++pathIdx;
        ++indexedPathIdx;
    }

    return true;
}
}  // namespace

UpdateIndexData::UpdateIndexData() : _allPathsIndexed(false) {}

void UpdateIndexData::addPath(const FieldRef& path) {
    _canonicalPaths.insert(getCanonicalIndexField(path));
}

void UpdateIndexData::addPathComponent(StringData pathComponent) {
    _pathComponents.insert(pathComponent.toString());
}

void UpdateIndexData::allPathsIndexed() {
    _allPathsIndexed = true;
}

void UpdateIndexData::clear() {
    _canonicalPaths.clear();
    _pathComponents.clear();
    _allPathsIndexed = false;
}

bool UpdateIndexData::mightBeIndexed(const FieldRef& path) const

    for (const auto& indexedPath : _canonicalPaths) {
        if (pathOverlaps(path, indexedPath)) {
            return true;
        }
    }

    for (const auto& pathComponent : _pathComponents) {
        for (size_t partIdx = 0; partIdx < path.numParts(); ++partIdx) {
            if (pathComponent == path.getPart(partIdx)) {
                return true;
            }
        }
    }

    return false;
}

bool UpdateIndexData::_startsWith(const FieldRef& a, const FieldRef& b) const {
    return (a == b) || (b.isPrefixOf(a));
}

FieldRef UpdateIndexData::getCanonicalIndexField(const FieldRef& path) {
    if (path.numParts() <= 1)
        return path;

    // The first part of the path must always be a valid field name, since it's not possible to
    // store a top-level array or '$' field name in a document.
    FieldRef buf(path.getPart(0));
    for (size_t i = 1; i < path.numParts(); ++i) {
        auto pathComponent = path.getPart(i);

        NumericPathComponentResult res = checkNumericOrDollarPathComponent(path, i, pathComponent);
        if (res == NumericPathComponentResult::kNumericOrDollar) {
            continue;
        }
        if (res == NumericPathComponentResult::kConsecutiveNumbers) {
            break;
        }

        buf.appendPart(pathComponent);
    }

    return buf;
}

bool UpdateIndexData::isComponentPartOfCanonicalizedIndexPath(StringData pathComponent) {
    return pathComponent != "$"_sd && !FieldRef::isNumericPathComponentLenient(pathComponent);
}
}  // namespace mongo


for (const auto& indexedPath : _canonicalPaths) {
        if (pathOverlaps(path, indexedPath)) {
            return true;
        }
    }

    for (const auto& pathComponent : _pathComponents) {
        for (size_t partIdx = 0; partIdx < path.numParts(); ++partIdx) {
            if (pathComponent == path.getPart(partIdx)) {
                return true;
            }
        }
    }

/**
 *
 */

#include "mongo/db/update_index_data.h"
#include "mongo/bson/util/builder.h"

namespace mongo {

namespace {
enum class NumericPathComponentResult {
    kNumericOrDollar,
    kConsecutiveNumbers,
    kNonNumericOrDollar
};

NumericPathComponentResult checkNumericOrDollarPathComponent(const FieldRef& path,
                                                             size_t pathIdx,
                                                             const StringData& pathComponent) {
    if (pathComponent == "$"_sd) {
        return NumericPathComponentResult::kNumericOrDollar;
    }

    if (FieldRef::isNumericPathComponentLenient(pathComponent)) {
        // Peek ahead to see if the next component is also all digits. This implies that the
        // update is attempting to create a numeric field name which would violate the
        // "ambiguous field name in array" constraint for multi-key indexes. Break early in this
        // case and conservatively return that this path affects the prefix of the consecutive
        // numerical path components. For instance, an input such as 'a.0.1.b.c' would return
        // the canonical index path of 'a'.
        if ((pathIdx + 1) < path.numParts() &&
            FieldRef::isNumericPathComponentLenient(path.getPart(pathIdx + 1))) {
            return NumericPathComponentResult::kConsecutiveNumbers;
        }
        return NumericPathComponentResult::kNumericOrDollar;
    }

    return NumericPathComponentResult::kNonNumericOrDollar;
}

/**
 * Checks whether a given Document path overlaps with an indexed path
 */
bool pathOverlaps(const FieldRef& path, const FieldRef& indexedPath) {
    size_t pathIdx = 0;
    size_t indexedPathIdx = 0;

    while (pathIdx < path.numParts() && indexedPathIdx < indexedPath.numParts()) {
        auto pathComponent = path.getPart(pathIdx);

        // The first part of the path must always be a valid field name, since it's not possible to
        // store a top-level array or '$' field name in a document.
        if (pathIdx > 0) {
            NumericPathComponentResult res =
                checkNumericOrDollarPathComponent(path, pathIdx, pathComponent);
            if (res == NumericPathComponentResult::kNumericOrDollar) {
                ++pathIdx;
                continue;
            }
            if (res == NumericPathComponentResult::kConsecutiveNumbers) {
                // This case implies that the update is attempting to create a numeric field name
                // which would violate the "ambiguous field name in array" constraint for multi-key
                // indexes. Break early in this case and conservatively return that this path
                // affects the prefix of the consecutive numerical path components. For instance, an
                // input path such as 'a.0.1.b.c' would match indexed path of 'a.d'.
                return true;
            }
        }

        StringData indexedPathComponent = indexedPath.getPart(indexedPathIdx);
        if (pathComponent != indexedPathComponent) {
            return false;
        }

        ++pathIdx;
        ++indexedPathIdx;
    }

    return true;
}
}  // namespace

UpdateIndexData::UpdateIndexData() : _allPathsIndexed(false) {}

void UpdateIndexData::addPath(const FieldRef& path) {
    _canonicalPaths.insert(getCanonicalIndexField(path));
}

void UpdateIndexData::addPathComponent(StringData pathComponent) {
    _pathComponents.insert(pathComponent.toString());
}

void UpdateIndexData::allPathsIndexed() {
    _allPathsIndexed = true;
}

void UpdateIndexData::clear() {
    _canonicalPaths.clear();
    _pathComponents.clear();
    _allPathsIndexed = false;
}

bool UpdateIndexData::mightBeIndexed(const FieldRef& path) const {
    if (_allPathsIndexed) {
        return true;
    }

    return false;
}

bool UpdateIndexData::_startsWith(const FieldRef& a, const FieldRef& b) const {
    return (a == b) || (b.isPrefixOf(a));
}

FieldRef UpdateIndexData::getCanonicalIndexField(const FieldRef& path) {
    if (path.numParts() <= 1)
        return path;

    // The first part of the path must always be a valid field name, since it's not possible to
    // store a top-level array or '$' field name in a document.
    FieldRef buf(path.getPart(0));
    for (size_t i = 1; i < path.numParts(); ++i) {
        auto pathComponent = path.getPart(i);

        NumericPathComponentResult res = checkNumericOrDollarPathComponent(path, i, pathComponent);
        if (res == NumericPathComponentResult::kNumericOrDollar) {
            continue;
        }
        if (res == NumericPathComponentResult::kConsecutiveNumbers) {
            break;
        }

        buf.appendPart(pathComponent);
    }

    return buf;
}

bool UpdateIndexData::isComponentPartOfCanonicalizedIndexPath(StringData pathComponent) {
    return pathComponent != "$"_sd && !FieldRef::isNumericPathComponentLenient(pathComponent);
}
}  // namespace mongo


/**
 *
 */

#include "mongo/db/update_index_data.h"
#include "mongo/bson/util/builder.h"

namespace mongo {

namespace {
enum class NumericPathComponentResult {
    kNumericOrDollar,
    kConsecutiveNumbers,
    kNonNumericOrDollar
};

NumericPathComponentResult checkNumericOrDollarPathComponent(const FieldRef& path,
                                                             size_t pathIdx,
                                                             const StringData& pathComponent) {
    if (pathComponent == "$"_sd) {
        return NumericPathComponentResult::kNumericOrDollar;
    }

    if (FieldRef::isNumericPathComponentLenient(pathComponent)) {
        // Peek ahead to see if the next component is also all digits. This implies that the
        // update is attempting to create a numeric field name which would violate the
        // "ambiguous field name in array" constraint for multi-key indexes. Break early in this
        // case and conservatively return that this path affects the prefix of the consecutive
        // numerical path components. For instance, an input such as 'a.0.1.b.c' would return
        // the canonical index path of 'a'.
        if ((pathIdx + 1) < path.numParts() &&
            FieldRef::isNumericPathComponentLenient(path.getPart(pathIdx + 1))) {
            return NumericPathComponentResult::kConsecutiveNumbers;
        }
        return NumericPathComponentResult::kNumericOrDollar;
    }

    return NumericPathComponentResult::kNonNumericOrDollar;
}

/**
 * Checks whether a given Document path overlaps with an indexed path
 */
bool pathOverlaps(const FieldRef& path, const FieldRef& indexedPath) {
    size_t pathIdx = 0;
    size_t indexedPathIdx = 0;

    while (pathIdx < path.numParts() && indexedPathIdx < indexedPath.numParts()) {
        auto pathComponent = path.getPart(pathIdx);

        // The first part of the path must always be a valid field name, since it's not possible to
        // store a top-level array or '$' field name in a document.
        if (pathIdx > 0) {
            NumericPathComponentResult res =
                checkNumericOrDollarPathComponent(path, pathIdx, pathComponent);
            if (res == NumericPathComponentResult::kNumericOrDollar) {
                ++pathIdx;
                continue;
            }
            if (res == NumericPathComponentResult::kConsecutiveNumbers) {
                // This case implies that the update is attempting to create a numeric field name
                // which would violate the "ambiguous field name in array" constraint for multi-key
                // indexes. Break early in this case and conservatively return that this path
                // affects the prefix of the consecutive numerical path components. For instance, an
                // input path such as 'a.0.1.b.c' would match indexed path of 'a.d'.
                return true;
            }
        }

        StringData indexedPathComponent = indexedPath.getPart(indexedPathIdx);
        if (pathComponent != indexedPathComponent) {
            return false;
        }

        ++pathIdx;
        ++indexedPathIdx;
    }

    return true;
}
}  // namespace

UpdateIndexData::UpdateIndexData() : _allPathsIndexed(false) {}

void UpdateIndexData::addPath(const FieldRef& path) {
    _canonicalPaths.insert(getCanonicalIndexField(path));
}

void UpdateIndexData::addPathComponent(StringData pathComponent) {
    _pathComponents.insert(pathComponent.toString());
}

void UpdateIndexData::allPathsIndexed() {
    _allPathsIndexed = true;
}

void UpdateIndexData::clear() {
    _canonicalPaths.clear();
    _pathComponents.clear();
    _allPathsIndexed = false;
}

bool UpdateIndexData::mightBeIndexed(const FieldRef& path) const {
    if (_allPathsIndexed) {
        return true;
    }

    for (const auto& indexedPath : _canonicalPaths) {
        if (pathOverlaps(path, indexedPath)) {
            return true;
        }
    }

    for (const auto& pathComponent : _pathComponents) {
        for (size_t partIdx = 0; partIdx < path.numParts(); ++partIdx) {
            if (pathComponent == path.getPart(partIdx)) {
                return true;
            }
        }
    }

bool UpdateIndexData::_startsWith(const FieldRef& a, const FieldRef& b) const {
    return (a == b) || (b.isPrefixOf(a));
}

FieldRef UpdateIndexData::getCanonicalIndexField(const FieldRef& path) {
    if (path.numParts() <= 1)
        return path;

    // The first part of the path must always be a valid field name, since it's not possible to
    // store a top-level array or '$' field name in a document.
    FieldRef buf(path.getPart(0));
    for (size_t i = 1; i < path.numParts(); ++i) {
        auto pathComponent = path.getPart(i);

        NumericPathComponentResult res = checkNumericOrDollarPathComponent(path, i, pathComponent);
        if (res == NumericPathComponentResult::kNumericOrDollar) {
            continue;
        }
        if (res == NumericPathComponentResult::kConsecutiveNumbers) {
            break;
        }

        buf.appendPart(pathComponent);
    }

    return buf;
}

bool UpdateIndexData::isComponentPartOfCanonicalizedIndexPath(StringData pathComponent) {
    return pathComponent != "$"_sd && !FieldRef::isNumericPathComponentLenient(pathComponent);
}
}  // namespace mongo


/**
 *
 */

#include "mongo/db/update_index_data.h"
#include "mongo/bson/util/builder.h"

namespace mongo {

namespace {
enum class NumericPathComponentResult {
    kNumericOrDollar,
    kConsecutiveNumbers,
    kNonNumericOrDollar
};

NumericPathComponentResult checkNumericOrDollarPathComponent(const FieldRef& path,
                                                             size_t pathIdx,
                                                             const StringData& pathComponent) {
    if (pathComponent == "$"_sd) {
        return NumericPathComponentResult::kNumericOrDollar;
    }

    if (FieldRef::isNumericPathComponentLenient(pathComponent)) {
        // Peek ahead to see if the next component is also all digits. This implies that the
        // update is attempting to create a numeric field name which would violate the
        // "ambiguous field name in array" constraint for multi-key indexes. Break early in this
        // case and conservatively return that this path affects the prefix of the consecutive
        // numerical path components. For instance, an input such as 'a.0.1.b.c' would return
        // the canonical index path of 'a'.
        if ((pathIdx + 1) < path.numParts() &&
            FieldRef::isNumericPathComponentLenient(path.getPart(pathIdx + 1))) {
            return NumericPathComponentResult::kConsecutiveNumbers;
        }
        return NumericPathComponentResult::kNumericOrDollar;
    }

    return NumericPathComponentResult::kNonNumericOrDollar;
}

/**
 * Checks whether a given Document path overlaps with an indexed path
 */
bool pathOverlaps(const FieldRef& path, const FieldRef& indexedPath) {
    size_t pathIdx = 0;
    size_t indexedPathIdx = 0;

    while (pathIdx < path.numParts() && indexedPathIdx < indexedPath.numParts()) {
        auto pathComponent = path.getPart(pathIdx);

        // The first part of the path must always be a valid field name, since it's not possible to
        // store a top-level array or '$' field name in a document.
        if (pathIdx > 0) {
            NumericPathComponentResult res =
                checkNumericOrDollarPathComponent(path, pathIdx, pathComponent);
            if (res == NumericPathComponentResult::kNumericOrDollar) {
                ++pathIdx;
                continue;
            }
            if (res == NumericPathComponentResult::kConsecutiveNumbers) {
                // This case implies that the update is attempting to create a numeric field name
                // which would violate the "ambiguous field name in array" constraint for multi-key
                // indexes. Break early in this case and conservatively return that this path
                // affects the prefix of the consecutive numerical path components. For instance, an
                // input path such as 'a.0.1.b.c' would match indexed path of 'a.d'.
                return true;
            }
        }

        StringData indexedPathComponent = indexedPath.getPart(indexedPathIdx);
        if (pathComponent != indexedPathComponent) {
            return false;
        }

        ++pathIdx;
        ++indexedPathIdx;
    }

    return true;
}
}  // namespace

UpdateIndexData::UpdateIndexData() : _allPathsIndexed(false) {}

void UpdateIndexData::addPath(const FieldRef& path) {
    _canonicalPaths.insert(getCanonicalIndexField(path));
}

void UpdateIndexData::addPathComponent(StringData pathComponent) {
    _pathComponents.insert(pathComponent.toString());
}

void UpdateIndexData::allPathsIndexed() {
    _allPathsIndexed = true;
}

void UpdateIndexData::clear() {
    _canonicalPaths.clear();
    _pathComponents.clear();
    _allPathsIndexed = false;
}

bool UpdateIndexData::mightBeIndexed(const FieldRef& path) const {
    if (_allPathsIndexed) {
        return true;
    }

    for (const auto& indexedPath : _canonicalPaths) {
        if (pathOverlaps(path, indexedPath)) {
            return true;
        }
    }

    for (const auto& pathComponent : _pathComponents) {
        for (size_t partIdx = 0; partIdx < path.numParts(); ++partIdx) {
            if (pathComponent == path.getPart(partIdx)) {
                return true;
            }
        }
    }

    return false;
}

bool UpdateIndexData::_startsWith(const FieldRef& a, const FieldRef& b) const {
    return (a == b) || (b.isPrefixOf(a));
}

FieldRef UpdateIndexData::getCanonicalIndexField(const FieldRef& path) {
    if (path.numParts() <= 1)
        return path;

    // The first part of the path must always be a valid field name, since it's not possible to
    // store a top-level array or '$' field name in a document.
    FieldRef buf(pat

    for (size_t i = 1; i < path.numParts(); ++i) {
        auto pathComponent = path.getPart(i);

        NumericPathComponentResult res = checkNumericOrDollarPathComponent(path, i, pathComponent);
        if (res == NumericPathComponentResult::kNumericOrDollar) {
            continue;
        }
        if (res == NumericPathComponentResult::kConsecutiveNumbers) {
            break;
        }

        buf.appendPart(pathComponent);
    }

    return buf;
}

bool UpdateIndexData::isComponentPartOfCanonicalizedIndexPath(StringData pathComponent) {
    return pathComponent != "$"_sd && !FieldRef::isNumericPathComponentLenient(pathComponent);
}
}  // namespace mongo


UpdateIndexData::UpdateIndexData() : _allPathsIndexed(false) {}

/**
 *
 */

#include "mongo/db/update_index_data.h"
#include "mongo/bson/util/builder.h"

namespace mongo {

namespace {
enum class NumericPathComponentResult {
    kNumericOrDollar,
    kConsecutiveNumbers,
    kNonNumericOrDollar
};

NumericPathComponentResult checkNumericOrDollarPathComponent(const FieldRef& path,
                                                             size_t pathIdx,
                                                             const StringData& pathComponent) {
    if (pathComponent == "$"_sd) {
        return NumericPathComponentResult::kNumericOrDollar;
    }

    if (FieldRef::isNumericPathComponentLenient(pathComponent)) {
        // Peek ahead to see if the next component is also all digits. This implies that the
        // update is attempting to create a numeric field name which would violate the
        // "ambiguous field name in array" constraint for multi-key indexes. Break early in this
        // case and conservatively return that this path affects the prefix of the consecutive
        // numerical path components. For instance, an input such as 'a.0.1.b.c' would return
        // the canonical index path of 'a'.
        if ((pathIdx + 1) < path.numParts() &&
            FieldRef::isNumericPathComponentLenient(path.getPart(pathIdx + 1))) {
            return NumericPathComponentResult::kConsecutiveNumbers;
        }
        return NumericPathComponentResult::kNumericOrDollar;
    }

    return NumericPathComponentResult::kNonNumericOrDollar;
}

/**
 * Checks whether a given Document path overlaps with an indexed path
 */
bool pathOverlaps(const FieldRef& path, const FieldRef& indexedPath) {
    size_t pathIdx = 0;
    size_t indexedPathIdx = 0;

    while (pathIdx < path.numParts() && indexedPathIdx < indexedPath.numParts()) {
        auto pathComponent = path.getPart(pathIdx);

        // The first part of the path must always be a valid field name, since it's not possible to
        // store a top-level array or '$' field name in a document.
        if (pathIdx > 0) {
            NumericPathComponentResult res =
                checkNumericOrDollarPathComponent(path, pathIdx, pathComponent);
            if (res == NumericPathComponentResult::kNumericOrDollar) {
                ++pathIdx;
                continue;
            }
            if (res == NumericPathComponentResult::kConsecutiveNumbers) {
                // This case implies that the update is attempting to create a numeric field name
                // which would violate the "ambiguous field name in array" constraint for multi-key
                // indexes. Break early in this case and conservatively return that this path
                // affects the prefix of the consecutive numerical path components. For instance, an
                // input path such as 'a.0.1.b.c' would match indexed path of 'a.d'.
                return true;
            }
        }

        StringData indexedPathComponent = indexedPath.getPart(indexedPathIdx);
        if (pathComponent != indexedPathComponent) {
            return false;
        }

        ++pathIdx;
        ++indexedPathIdx;
    }

    return true;
}
}  // namespace

void UpdateIndexData::addPath(const FieldRef& path) {
    _canonicalPaths.insert(getCanonicalIndexField(path));
}

void UpdateIndexData::addPathComponent(StringData pathComponent) {
    _pathComponents.insert(pathComponent.toString());
}

void UpdateIndexData::allPathsIndexed() {
    _allPathsIndexed = true;
}

void UpdateIndexData::clear() {
    _canonicalPaths.clear();
    _pathComponents.clear();
    _allPathsIndexed = false;
}

bool UpdateIndexData::mightBeIndexed(const FieldRef& path) const {
    if (_allPathsIndexed) {
        return true;
    }

    for (const auto& indexedPath : _canonicalPaths) {
        if (pathOverlaps(path, indexedPath)) {
            return true;
        }
    }

    for (const auto& pathComponent : _pathComponents) {
        for (size_t partIdx = 0; partIdx < path.numParts(); ++partIdx) {
            if (pathComponent == path.getPart(partIdx)) {
                return true;
            }
        }
    }

    return false;
}

bool UpdateIndexData::_startsWith(const FieldRef& a, const FieldRef& b) const {
    return (a == b) || (b.isPrefixOf(a));
}

FieldRef UpdateIndexData::getCanonicalIndexField(const FieldRef& path) {
    if (path.numParts() <= 1)
        return path;

    // The first part of the path must always be a valid field name, since it's not possible to
    // store a top-level array or '$' field name in a document.
    FieldRef buf(path.getPart(0));
    for (size_t i = 1; i < path.numParts(); ++i) {
        auto pathComponent = path.getPart(i);

        NumericPathComponentResult res = checkNumericOrDollarPathComponent(path, i, pathComponent);
        if (res == NumericPathComponentResult::kNumericOrDollar) {
            continue;
        }
        if (res == NumericPathComponentResult::kConsecutiveNumbers) {
            break;
        }

        buf.appendPart(pathComponent);
    }

    return buf;
}

bool UpdateIndexData::isComponentPartOfCanonicalizedIndexPath(StringData pathComponent) {
    return pathComponent != "$"_sd && !FieldRef::isNumericPathComponentLenient(pathComponent);
}
}  // namespace mongo


if (_allPathsIndexed) {
        return true;
    }

/**
 *
 */

#include "mongo/db/update_index_data.h"
#include "mongo/bson/util/builder.h"

namespace mongo {

namespace {
enum class NumericPathComponentResult {
    kNumericOrDollar,
    kConsecutiveNumbers,
    kNonNumericOrDollar
};

NumericPathComponentResult checkNumericOrDollarPathComponent(const FieldRef& path,
                                                             size_t pathIdx,
                                                             const StringData& pathComponent) {
    if (pathComponent == "$"_sd) {
        return NumericPathComponentResult::kNumericOrDollar;
    }

    if (FieldRef::isNumericPathComponentLenient(pathComponent)) {
        // Peek ahead to see if the next component is also all digits. This implies that the
        // update is attempting to create a numeric field name which would violate the
        // "ambiguous field name in array" constraint for multi-key indexes. Break early in this
        // case and conservatively return that this path affects the prefix of the consecutive
        // numerical path components. For instance, an input such as 'a.0.1.b.c' would return
        // the canonical index path of 'a'.
        if ((pathIdx + 1) < path.numParts() &&
            FieldRef::isNumericPathComponentLenient(path.getPart(pathIdx + 1))) {
            return NumericPathComponentResult::kConsecutiveNumbers;
        }
        return NumericPathComponentResult::kNumericOrDollar;
    }

    return NumericPathComponentResult::kNonNumericOrDollar;
}

/**
 * Checks whether a given Document path overlaps with an indexed path
 */
bool pathOverlaps(const FieldRef& path, const FieldRef& indexedPath) {
    size_t pathIdx = 0;
    size_t indexedPathIdx = 0;

    while (pathIdx < path.numParts() && indexedPathIdx < indexedPath.numParts()) {
        auto pathComponent = path.getPart(pathIdx);

        // The first part of the path must always be a valid field name, since it's not possible to
        // store a top-level array or '$' field name in a document.
        if (pathIdx > 0) {
            NumericPathComponentResult res =
                checkNumericOrDollarPathComponent(path, pathIdx, pathComponent);
            if (res == NumericPathComponentResult::kNumericOrDollar) {
                ++pathIdx;
                continue;
            }
            if (res == NumericPathComponentResult::kConsecutiveNumbers) {
                // This case implies that the update is attempting to create a numeric field name
                // which would violate the "ambiguous field name in array" constraint for multi-key
                // indexes. Break early in this case and conservatively return that this path
                // affects the prefix of the consecutive numerical path components. For instance, an
                // input path such as 'a.0.1.b.c' would match indexed path of 'a.d'.
                return true;
            }
        }

        StringData indexedPathComponent = indexedPath.getPart(indexedPathIdx);
        if (pathComponent != indexedPathComponent) {
            return false;
        }

        ++pathIdx;
        ++indexedPathIdx;
    }

    return true;
}
}  // namespace

UpdateIndexData::UpdateIndexData() : _allPathsIndexed(false) {}

void UpdateIndexData::addPath(const FieldRef& path) {
    _canonicalPaths.insert(getCanonicalIndexField(path));
}

void UpdateIndexData::addPathComponent(StringData pathComponent) {
    _pathComponents.insert(pathComponent.toString());
}

void UpdateIndexData::allPathsIndexed() {
    _allPathsIndexed = true;
}

void UpdateIndexData::clear() {
    _canonicalPaths.clear();
    _pathComponents.clear();
    _allPathsIndexed = false;
}

bool UpdateIndexData::mightBeIndexed(const FieldRef& path) const {


for (size_t i = 1; i < path.numParts(); ++i) {
        auto pathComponent = path.getPart(i);

        NumericPathComponentResult res = checkNumericOrDollarPathComponent(path, i, pathComponent);
        if (res == NumericPathComponentResult::kNumericOrDollar) {
            continue;
        }
        if (res == NumericPathComponentResult::kConsecutiveNumbers) {
            break;
        }

        buf.appendPart(pathComponent);
    }

/**
 *
 */

#include "mongo/db/update_index_data.h"
#include "mongo/bson/util/builder.h"

namespace mongo {

namespace {
enum class NumericPathComponentResult {
    kNumericOrDollar,
    kConsecutiveNumbers,
    kNonNumericOrDollar
};

NumericPathComponentResult checkNumericOrDollarPathComponent(const FieldRef& path,
                                                             size_t pathIdx,
                                                             const StringData& pathComponent) {
    if (pathComponent == "$"_sd) {
        return NumericPathComponentResult::kNumericOrDollar;
    }

    if (FieldRef::isNumericPathComponentLenient(pathComponent)) {
        // Peek ahead to see if the next component is also all digits. This implies that the
        // update is attempting to create a numeric field name which would violate the
        // "ambiguous field name in array" constraint for multi-key indexes. Break early in this
        // case and conservatively return that this path affects the prefix of the consecutive
        // numerical path components. For instance, an input such as 'a.0.1.b.c' would return
        // the canonical index path of 'a'.
        if ((pathIdx + 1) < path.numParts() &&
            FieldRef::isNumericPathComponentLenient(path.getPart(pathIdx + 1))) {
            return NumericPathComponentResult::kConsecutiveNumbers;
        }
        return NumericPathComponentResult::kNumericOrDollar;
    }

    return NumericPathComponentResult::kNonNumericOrDollar;
}

/**
 * Checks whether a given Document path overlaps with an indexed path
 */
bool pathOverlaps(const FieldRef& path, const FieldRef& indexedPath) {
    size_t pathIdx = 0;
    size_t indexedPathIdx = 0;

    while (pathIdx < path.numParts() && indexedPathIdx < indexedPath.numParts()) {
        auto pathComponent = path.getPart(pathIdx);

        // The first part of the path must always be a valid field name, since it's not possible to
        // store a top-level array or '$' field name in a document.
        if (pathIdx > 0) {
            NumericPathComponentResult res =
                checkNumericOrDollarPathComponent(path, pathIdx, pathComponent);
            if (res == NumericPathComponentResult::kNumericOrDollar) {
                ++pathIdx;
                continue;
            }
            if (res == NumericPathComponentResult::kConsecutiveNumbers) {
                // This case implies that the update is attempting to create a numeric field name
                // which would violate the "ambiguous field name in array" constraint for multi-key
                // indexes. Break early in this case and conservatively return that this path
                // affects the prefix of the consecutive numerical path components. For instance, an
                // input path such as 'a.0.1.b.c' would match indexed path of 'a.d'.
                return true;
            }
        }

        StringData indexedPathComponent = indexedPath.getPart(indexedPathIdx);
        if (pathComponent != indexedPathComponent) {
            return false;
        }

        ++pathIdx;
        ++indexedPathIdx;
    }

    return true;
}
}  // namespace

UpdateIndexData::UpdateIndexData() : _allPathsIndexed(false) {}

void UpdateIndexData::addPath(const FieldRef& path) {
    _canonicalPaths.insert(getCanonicalIndexField(path));
}

void UpdateIndexData::addPathComponent(StringData pathComponent) {
    _pathComponents.insert(pathComponent.toString());
}

void UpdateIndexData::allPathsIndexed() {
    _allPathsIndexed = true;
}

void UpdateIndexData::clear() {
    _canonicalPaths.clear();
    _pathComponents.clear();
    _allPathsIndexed = false;
}

bool UpdateIndexData::mightBeIndexed(const FieldRef& path) const {
    if (_allPathsIndexed) {
        return true;
    }

    for (const auto& indexedPath : _canonicalPaths) {
        if (pathOverlaps(path, indexedPath)) {
            return true;
        }
    }

    for (const auto& pathComponent : _pathComponents) {
        for (size_t partIdx = 0; partIdx < path.numParts(); ++partIdx) {
            if (pathComponent == path.getPart(partIdx)) {
                return true;
            }
        }
    }

    return false;
}

bool UpdateIndexData::_startsWith(const FieldRef& a, const FieldRef& b) const {
    return (a == b) || (b.isPrefixOf(a));
}

FieldRef UpdateIndexData::getCanonicalIndexField(const FieldRef& path) {
    if (path.numParts() <= 1)
        return path;

    // The first part of the path must always be a valid field name, since it's not possible to
    // store a top-level array or '$' field name in a document.
    FieldRef buf(path.getPart(0));

    return buf;
}

bool UpdateIndexData::isComponentPartOfCanonicalizedIndexPath(StringData pathComponent) {
    return pathComponent != "$"_sd && !FieldRef::isNumericPathComponentLenient(pathComponent);
}
}  // namespace mongo


/**
 *
 */

#include "mongo/db/update_index_data.h"
#include "mongo/bson/util/builder.h"

namespace mongo {

namespace {
enum class NumericPathComponentResult {
    kNumericOrDollar,
    kConsecutiveNumbers,
    kNonNumericOrDollar
};

NumericPathComponentResult checkNumericOrDollarPathComponent(const FieldRef& path,
                                                             size_t pathIdx,
                                                             const StringData& pathComponent) {
    if (pathComponent == "$"_sd) {
        return NumericPathComponentResult::kNumericOrDollar;
    }

    if (FieldRef::isNumericPathComponentLenient(pathComponent)) {
        // Peek ahead to see if the next component is also all digits. This implies that the
        // update is attempting to create a numeric field name which would violate the
        // "ambiguous field name in array" constraint for multi-key indexes. Break early in this
        // case and conservatively return that this path affects the prefix of the consecutive
        // numerical path components. For instance, an input such as 'a.0.1.b.c' would return
        // the canonical index path of 'a'.
        if ((pathIdx + 1) < path.numParts() &&
            FieldRef::isNumericPathComponentLenient(path.getPart(pathIdx + 1))) {
            return NumericPathComponentResult::kConsecutiveNumbers;
        }
        return NumericPathComponentResult::kNumericOrDollar;
    }

    return NumericPathComponentResult::kNonNumericOrDollar;
}

/**
 * Checks whether a given Document path overlaps with an indexed path
 */
bool pathOverlaps(const FieldRef& path, const FieldRef& indexedPath) {
    size_t pathIdx = 0;
    size_t indexedPathIdx = 0;

    while (pathIdx < path.numParts() && indexedPathIdx < indexedPath.numParts()) {
        auto pathComponent = pa

th.getPart(pathIdx);

        // The first part of the path must always be a valid field name, since it's not possible to
        // store a top-level array or '$' field name in a document.
        if (pathIdx > 0) {
            NumericPathComponentResult res =
                checkNumericOrDollarPathComponent(path, pathIdx, pathComponent);
            if (res == NumericPathComponentResult::kNumericOrDollar) {
                ++pathIdx;
                continue;
            }
            if (res == NumericPathComponentResult::kConsecutiveNumbers) {
                // This case implies that the update is attempting to create a numeric field name
                // which would violate the "ambiguous field name in array" constraint for multi-key
                // indexes. Break early in this case and conservatively return that this path
                // affects the prefix of the consecutive numerical path components. For instance, an
                // input path such as 'a.0.1.b.c' would match indexed path of 'a.d'.
                return true;
            }
        }

        StringData indexedPathComponent = indexedPath.getPart(indexedPathIdx);
        if (pathComponent != indexedPathComponent) {
            return false;
        }

        ++pathIdx;
        ++indexedPathIdx;
    }

    return true;
}
}  // namespace

UpdateIndexData::UpdateIndexData() : _allPathsIndexed(false) {}

void UpdateIndexData::addPath(const FieldRef& path) {
    _canonicalPaths.insert(getCanonicalIndexField(path));
}

void UpdateIndexData::addPathComponent(StringData pathComponent) {
    _pathComponents.insert(pathComponent.toString());
}

void UpdateIndexData::allPathsIndexed() {
    _allPathsIndexed = true;
}

void UpdateIndexData::clear() {
    _canonicalPaths.clear();
    _pathComponents.clear();
    _allPathsIndexed = false;
}

bool UpdateIndexData::mightBeIndexed(const FieldRef& path) const {
    if (_allPathsIndexed) {
        return true;
    }

    for (const auto& indexedPath : _canonicalPaths) {
        if (pathOverlaps(path, indexedPath)) {
            return true;
        }
    }

    for (const auto& pathComponent : _pathComponents) {
        for (size_t partIdx = 0; partIdx < path.numParts(); ++partIdx) {
            if (pathComponent == path.getPart(partIdx)) {
                return true;
            }
        }
    }

    return false;
}

bool UpdateIndexData::_startsWith(const FieldRef& a, const FieldRef& b) const {
    return (a == b) || (b.isPrefixOf(a));
}

FieldRef UpdateIndexData::getCanonicalIndexField(const FieldRef& path) {
    if (path.numParts() <= 1)
        return path;

    // The first part of the path must always be a valid field name, since it's not possible to
    // store a top-level array or '$' field name in a document.
    FieldRef buf(path.getPart(0));
    for (size_t i = 1; i < path.numParts(); ++i) {
        auto pathComponent = path.getPart(i);

        NumericPathComponentResult res = checkNumericOrDollarPathComponent(path, i, pathComponent);
        if (res == NumericPathComponentResult::kNumericOrDollar) {
            continue;
        }
        if (res == NumericPathComponentResult::kConsecutiveNumbers) {
            break;
        }

        buf.appendPart(pathComponent);
    }

    return buf;
}

bool UpdateIndexData::isComponentPartOfCanonicalizedIndexPath(StringData pathComponent) {
    return pathComponent != "$"_sd && !FieldRef::isNumericPathComponentLenient(pathComponent);
}
}  // namespace mongo


// stdafx.cpp : source file that includes just the standard includes
// MMXSwarm.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
// Also includes utility functions that rarely change.
// This is a part of the Microsoft Foundation Classes C++ library.
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>

// Note: See the CPUID sample for a more complete
// implentation

const DWORD _MMX_FEATURE_BIT = 0x00800000;
const DWORD _SSE2_FEATURE_BIT = 0x04000000;

static bool _IsFeature(DWORD nFeature);

bool IsMMX()
{
	static bool bMMX = _IsFeature(_MMX_FEATURE_BIT);
	return(bMMX);
}

{
	static bool bSSE2 = _IsFeature(_SSE2_FEATURE_BIT);
	return(bSSE2);
}

static bool _IsFeature(DWORD dwRequestFeature)
{
	// This	bit	flag can get set on	calling	cpuid
	// with	register eax set to	1
	DWORD dwFeature	= 0;
	__try {
			_asm {
				mov	eax,1
				cpuid
				mov	dwFeature,edx
			}
	} __except ( EXCEPTION_EXECUTE_HANDLER)	{
			return false;
	}
	if ((dwRequestFeature == _MMX_FEATURE_BIT) &&
		(dwFeature & _MMX_FEATURE_BIT)) {
		__try {
			__asm {
				pxor mm0, mm0
				emms
			}
		} __except (EXCEPTION_EXECUTE_HANDLER) {
			return (0);
		}
		return(true);
	}
	else if ((dwRequestFeature == _SSE2_FEATURE_BIT) &&
		(dwFeature & _SSE2_FEATURE_BIT)) {
		__try {
			__asm {
				xorpd xmm0, xmm0
			}
		} __except (EXCEPTION_EXECUTE_HANDLER) {
			return (0);
		}
		return(true);
	}

	return false;
}


// stdafx.cpp : source file that includes just the standard includes
// MMXSwarm.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
// Also includes utility functions that rarely change.
// This is a part of the Microsoft Foundation Classes C++ library.
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>

// Note: See the CPUID sample for a more complete
// implentation

const DWORD _MMX_FEATURE_BIT = 0x00800000;
const DWORD _SSE2_FEATURE_BIT = 0x04000000;

static bool _IsFeature(DWORD nFeature);

bool IsMMX()
{
	static bool bMMX = _IsFeature(_MMX_FEATURE_BIT);
	return(bMMX);
}

bool IsSSE2()
{
	static bool bSSE2 = _IsFeature(_SSE2_FEATURE_BIT);
	return(bSSE2);
}

static bool _IsFeature(DWORD dwRequestFeature)
{
	// This	bit	flag can get set on	calling	cpuid
	// with	register eax set to	1
	DWORD dwFeature	= 0;
	__try {
			_asm {
				mov	eax,1
				cpuid
				mov	dwFeature,edx
			}
	} __except ( EXCEPTION_EXECUTE_HANDLER)	{
			return false;
	}
	if ((dwRequestFeature == _MMX_FEATURE_BIT) &&
		(dwFeature & _MMX_FEATURE_BIT)) {
		__try {
			__asm {
				pxor mm0, mm0
				emms
			}
		} __except (EXCEPTION_EXECUTE_HANDLER) {
			return (0);
		}
		return(true);
	}
	else if ((dwRequestFeature == _SSE2_FEATURE_BIT) &&
		(dwFeature & _SSE2_FEATURE_BIT)) {
		__try {
			__asm {
				xorpd xmm0, xmm0
			}
		} __except (EXCEPTION_EXECUTE_HANDLER)


{
	// This	bit	flag can get set on	calling	cpuid
	// with	register eax set to	1

// stdafx.cpp : source file that includes just the standard includes
// MMXSwarm.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
// Also includes utility functions that rarely change.
// This is a part of the Microsoft Foundation Classes C++ library.
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>

// Note: See the CPUID sample for a more complete
// implentation

const DWORD _MMX_FEATURE_BIT = 0x00800000;
const DWORD _SSE2_FEATURE_BIT = 0x04000000;

static bool _IsFeature(DWORD nFeature);

bool IsMMX()
{
	static bool bMMX = _IsFeature(_MMX_FEATURE_BIT);
	return(bMMX);
}

bool IsSSE2()
{
	static bool bSSE2 = _IsFeature(_SSE2_FEATURE_BIT);
	return(bSSE2);
}

static bool _IsFeature(DWORD dwRequestFeature)

	DWORD dwFeature	= 0;
	__try {
			_asm {
				mov	eax,1
				cpuid
				mov	dwFeature,edx
			}
	} __except ( EXCEPTION_EXECUTE_HANDLER)	{
			return false;
	}
	if ((dwRequestFeature == _MMX_FEATURE_BIT) &&
		(dwFeature & _MMX_FEATURE_BIT)) {
		__try {
			__asm {
				pxor mm0, mm0
				emms
			}
		} __except (EXCEPTION_EXECUTE_HANDLER) {
			return (0);
		}
		return(true);
	}
	else if ((dwRequestFeature == _SSE2_FEATURE_BIT) &&
		(dwFeature & _SSE2_FEATURE_BIT)) {
		__try {
			__asm {
				xorpd xmm0, xmm0
			}
		} __except (EXCEPTION_EXECUTE_HANDLER) {
			return (0);
		}
		return(true);
	}

	return false;
}


DWORD dwFeature	= 0;
	__try {
			_asm {
				mov	eax,1
				cpuid
				mov	dwFeature,edx
			}
	} __except ( EXCEPTION_EXECUTE_HANDLER)	{
			return false;
	}

// stdafx.cpp : source file that includes just the standard includes
// MMXSwarm.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
// Also includes utility functions that rarely change.
// This is a part of the Microsoft Foundation Classes C++ library.
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>

// Note: See the CPUID sample for a more complete
// implentation

const DWORD _MMX_FEATURE_BIT = 0x00800000;
const DWORD _SSE2_FEATURE_BIT = 0x04000000;

static bool _IsFeature(DWORD nFeature);

bool IsMMX()
{
	static bool bMMX = _IsFeature(_MMX_FEATURE_BIT);
	return(bMMX);
}

bool IsSSE2()
{
	static bool bSSE2 = _IsFeature(_SSE2_FEATURE_BIT);
	return(bSSE2);
}

static bool _IsFeature(DWORD dwRequestFeature)
{
	// This	bit	flag can get set on	calling	cpuid
	// with	register eax set to	1

	if ((dwRequestFeature == _MMX_FEATURE_BIT) &&
		(dwFeature & _MMX_FEATURE_BIT)) {
		__try {
			__asm {
				pxor mm0, mm0
				emms
			}
		} __except (EXCEPTION_EXECUTE_HANDLER) {
			return (0);
		}
		return(true);
	}
	else if ((dwRequestFeature == _SSE2_FEATURE_BIT) &&
		(dwFeature & _SSE2_FEATURE_BIT)) {
		__try {
			__asm {
				xorpd xmm0, xmm0
			}
		} __except (EXCEPTION_EXECUTE_HANDLER) {
			return (0);
		}
		return(true);
	}

	return false;
}


if ((dwRequestFeature == _MMX_FEATURE_BIT) &&
		(dwFeature & _MMX_FEATURE_BIT)) {
		__try {
			__asm {
				pxor mm0, mm0
				emms
			}
		} __except (EXCEPTION_EXECUTE_HANDLER) {
			return (0);
		}
		return(true);
	}
	else if ((dwRequestFeature == _SSE2_FEATURE_BIT) &&
		(dwFeature & _SSE2_FEATURE_BIT)) {
		__try {
			__asm {
				xorpd xmm0, xmm0
			}
		} __except (EXCEPTION_EXECUTE_HANDLER) {
			return (0);
		}
		return(true);
	}

	return false;
}

// stdafx.cpp : source file that includes just the standard includes
// MMXSwarm.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
// Also includes utility functions that rarely change.
// This is a part of the Microsoft Foundation Classes C++ library.
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>

// Note: See the CPUID sample for a more complete
// implentation

const DWORD _MMX_FEATURE_BIT = 0x00800000;
const DWORD _SSE2_FEATURE_BIT = 0x04000000;

static bool _IsFeature(DWORD nFeature);

bool IsMMX()
{
	static bool bMMX = _IsFeature(_MMX_FEATURE_BIT);
	return(bMMX);
}

bool IsSSE2()
{
	static bool bSSE2 = _IsFeature(_SSE2_FEATURE_BIT);
	return(bSSE2);
}

static bool _IsFeature(DWORD dwRequestFeature)
{
	// This	bit	flag can get set on	calling	cpuid
	// with	register eax set to	1
	DWORD dwFeature	= 0;
	__try {
			_asm {
				mov	eax,1
				cpuid
				mov	dwFeature,edx
			}
	} __except ( EXCEPTION_EXECUTE_HANDLER)	{
			return false;
	}


// stdafx.cpp : source file that includes just the standard includes
// MMXSwarm.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
// Also includes utility functions that rarely change.
// This is a part of the Microsoft Foundation Classes C++ library.
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>

// Note: See the CPUID sample for a more complete
// implentation

const DWORD _MMX_FEATURE_BIT = 0x00800000;
const DWORD _SSE2_FEATURE_BIT = 0x04000000;

static bool _IsFeature(DWORD nFeature);

bool IsMMX()
{
	static bool bMMX = _IsFeature(_MMX_FEATURE_BIT);
	return(bMMX);
}

bool IsSSE2()
{
	static bool bSSE2 = _IsFeature(_SSE2_FEATURE_BIT);
	return(bSSE2);
}

static bool _IsFeature(DWORD dwRequestFeature)
{
	// This	bit	flag can get set on	calling	cpuid
	// with	register eax set to	1
	DWORD dwFeature	= 0;
	__try {
			_asm {
				mov	eax,1
				cpuid
				mov	dwFeature,edx
			}
	} __except ( EXCEPTION_EXECUTE_HANDLER)	{
			return false;
	}
	if ((dwRequestFeature == _MMX_FEATURE_BIT) &&
		(dwFeature & _MMX_FEATURE_BIT)) {
		__try {
			__asm {
				pxor mm0, mm0
				emms
			}
		} __except (EXCEPTION_EXECUTE_HANDLER) {
			re

		}
		return(true);
	}
	else if ((dwRequestFeature == _SSE2_FEATURE_BIT) &&
		(dwFeature & _SSE2_FEATURE_BIT)) {
		__try {
			__asm {
				xorpd xmm0, xmm0
			}
		} __except (EXCEPTION_EXECUTE_HANDLER) {
			return (0);
		}
		return(true);
	}

	return false;
}


if ((dwRequestFeature == _MMX_FEATURE_BIT) &&
		(dwFeature & _MMX_FEATURE_BIT)) {
		__try {
			__asm {
				pxor mm0, mm0
				emms
			}
		} __except (EXCEPTION_EXECUTE_HANDLER) {
			return (0);
		}
		return(true);
	}
	else if ((dwRequestFeature == _SSE2_FEATURE_BIT) &&
		(dwFeature & _SSE2_FEATURE_BIT)) {
		__try {
			__asm {
				xorpd xmm0, xmm0
			}
		} __except (EXCEPTION_EXECUTE_HANDLER) {
			return (0);
		}
		return(true);
	}


// stdafx.cpp : source file that includes just the standard includes
// MMXSwarm.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
// Also includes utility functions that rarely change.
// This is a part of the Microsoft Foundation Classes C++ library.
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>

// Note: See the CPUID sample for a more complete
// implentation

const

DWORD _MMX_FEATURE_BIT = 0x00800000;
const DWORD _SSE2_FEATURE_BIT = 0x04000000;

static bool _IsFeature(DWORD nFeature);

bool IsMMX()
{
	static bool bMMX = _IsFeature(_MMX_FEATURE_BIT);
	return(bMMX);
}

bool IsSSE2()
{
	static bool bSSE2 = _IsFeature(_SSE2_FEATURE_BIT);
	return(bSSE2);
}

static bool _IsFeature(DWORD dwRequestFeature)
{
	// This	bit	flag can get set on	calling	cpuid
	// with	register eax set to	1
	DWORD dwFeature	= 0;
	__try {
			_asm {
				mov	eax,1
				cpuid
				mov	dwFeature,edx
			}
	} __except ( EXCEPTION_EXECUTE_HANDLER)	{
			return false;
	}
	if ((dwRequestFeature == _MMX_FEATURE_BIT) &&
		(dwFeature & _MMX_FEATURE_BIT)) {
		__try {
			__asm {
				pxor mm0, mm0
				emms
			}
		} __except (EXCEPTION_EXECUTE_HANDLER) {
			return (0);
		}
		return(true);
	}
	else if ((dwRequestFeature == _SSE2_FEATURE_BIT) &&
		(dwFeature & _SSE2_FEATURE_BIT)) {
		__try {
			__asm {
				xorpd xmm0, xmm0
			}
		} __except (EXCEPTION_EXECUTE_HANDLER) {
			return (0);
		}
		return(true);
	}

	return false;
}


/* -*-c++-*- OpenSceneGraph Cookbook
 * Chapter 6 Recipe 1
 * Author: Wang Rui <wangray84 at gmail dot com>
*/

#include <osg/Program>
#include <osg/Texture2D>
#include <osg/ShapeDrawable>
#include <osg/Geode>
#include <osgDB/ReadFile>
#include <osgUtil/TangentSpaceGenerator>
#include <osgViewer/Viewer>

#include "CommonFunctions"

static const char* vertSource = {
    "attribute vec3 tangent;\n"
    "attribute vec3 binormal;\n"
    "varying vec3 lightDir;\n"
    "void main()\n"
    "{\n"
    "    vec3 normal = normalize(gl_NormalMatrix * gl_Normal);\n"
    "    mat3 rotation = mat3(tangent, binormal, normal);\n"
    "    vec4 vertexInEye = gl_ModelViewMatrix * gl_Vertex;\n"
    "    lightDir = vec3(gl_LightSource[0].position.xyz - vertexInEye.xyz);\n"
    "    lightDir = normalize(rotation * normalize(lightDir));\n"
    "    gl_Position = ftransform();\n"
    "    gl_TexCoord[0] = gl_MultiTexCoord0;\n"
    "}\n"
};

static const char* fragSource = {
    "uniform sampler2D colorTex;\n"
    "uniform sampler2D normalTex;\n"
    "varying vec3 lightDir;\n"
    "void main (void)\n"
    "{\n"
    "    vec4 base = texture2D(colorTex, gl_TexCoord[0].xy);\n"
    "    vec3 bump = texture2D(normalTex, gl_TexCoord[0].xy).xyz;\n"
    "    bump = normalize(bump * 2.0 - 1.0);\n"

    "    float lambert = max(dot(bump, lightDir), 0.0);\n"
    "    if (lambert > 0.0)\n"
    "    {\n"
    "        gl_FragColor = base * gl_LightSource[0].diffuse * lambert;\n"
    "        gl_FragColor += gl_LightSource[0].specular * pow(lambert, 2.0);\n"
    "    }\n"
    "    gl_FragColor += gl_LightSource[0].ambient;\n"
    "}\n"
};

class ComputeTangentVisitor : public osg::NodeVisitor
{
public:
    void apply( osg::Node& node ) { traverse(node); }

    void apply( osg::Geode& node )
    {
        for ( unsigned int i=0; i<node.getNumDrawables(); ++i )
        {
            osg::Geometry* geom = dynamic_cast<osg::Geometry*>( node.getDrawable(i) );
            if ( geom ) generateTangentArray( geom );
        }
        traverse( node );
    }

    void generateTangentArray( osg::Geometry* geom )
    {
        osg::ref_ptr<osgUtil::TangentSpaceGenerator> tsg = new osgUtil::TangentSpaceGenerator;
        tsg->generate( geom );
        geom->setVertexAttribArray( 6, tsg->getTangentArray() );
        geom->setVertexAttribBinding( 6, osg::Geometry::BIND_PER_VERTEX );
        geom->setVertexAttribArray( 7, tsg->getBinormalArray() );
        geom->setVertexAttribBinding( 7, osg::Geometry::BIND_PER_VERTEX );
    }
};

{
    osg::ArgumentParser arguments( &argc, argv );
    osg::ref_ptr<osg::Node> scene = osgDB::readNodeFiles( arguments );
    if ( !scene ) scene = osgDB::readNodeFile("skydome.osgt");

    ComputeTangentVisitor ctv;
    ctv.setTraversalMode( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN );
    scene->accept( ctv );

    osg::ref_ptr<osg::Program> program = new osg::Program;
    program->addShader( new osg::Shader(osg::Shader::VERTEX, vertSource) );
    program->addShader( new osg::Shader(osg::Shader::FRAGMENT, fragSource) );
    program->addBindAttribLocation( "tangent", 6 );
    program->addBindAttribLocation( "binormal", 7 );

    osg::ref_ptr<osg::Texture2D> colorTex = new osg::Texture2D;
    colorTex->setImage( osgDB::readImageFile("Images/whitemetal_diffuse.jpg") );

    osg::ref_ptr<osg::Texture2D> normalTex = new osg::Texture2D;
    normalTex->setImage( osgDB::readImageFile("Images/whitemetal_normal.jpg") );

    osg::StateSet* stateset = scene->getOrCreateStateSet();
    stateset->addUniform( new osg::Uniform("colorTex", 0) );
    stateset->addUniform( new osg::Uniform("normalTex", 1) );
    stateset->setAttributeAndModes( program.get() );

    osg::StateAttribute::GLModeValue value = osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE;
    stateset->setTextureAttributeAndModes( 0, colorTex.get(), value );
    stateset->setTextureAttributeAndModes( 1, normalTex.get(), value );

    osgViewer::Viewer viewer;
    viewer.setSceneData( scene.get() );
    return viewer.run();
}


{
        for ( unsigned int i=0; i<node.getNumDrawables(); ++i )
        {
            osg::Geometry* geom = dynamic_cast<osg::Geometry*>( node.getDrawable(i) );
            if ( geom ) generateTangentArray( geom );
        }
        traverse( node );
    }

/* -*-c++-*- OpenSceneGraph Cookbook
 * Chapter 6 Recipe 1
 * Author: Wang Rui <wangray84 at gmail dot com>
*/

#include <osg/Program>
#include <osg/Texture2D>
#include <osg/ShapeDrawable>
#include <osg/Geode>
#include <osgDB/ReadFile>
#include <osgUtil/TangentSpaceGenerator>
#include <osgViewer/Viewer>

#include "CommonFunctions"

static const char* vertSource = {
    "attribute vec3 tangent;\n"
    "attribute vec3 binormal;\n"
    "varying vec3 lightDir;\n"
    "void main()\n"
    "{\n"
    "    vec3 normal = normalize(gl_NormalMatrix * gl_Normal);\n"
    "    mat3 rotation = mat3(tangent, binormal, normal);\n"
    "    vec4 vertexInEye = gl_ModelViewMatrix * gl_Vertex;\n"
    "    lightDir = vec3(gl_LightSource[0].position.xyz - vertexInEye.xyz);\n"
    "    lightDir = normalize(rotation * normalize(lightDir));\n"
    "    gl_Position = ftransform();\n"
    "    gl_TexCoord[0] = gl_MultiTexCoord0;\n"
    "}\n"
};

static const char* fragSource = {
    "uniform sampler2D colorTex;\n"
    "uniform sampler2D normalTex;\n"
    "varying vec3 lightDir;\n"
    "void main (void)\n"
    "{\n"
    "    vec4 base = texture2D(colorTex, gl_TexCoord[0].xy);\n"
    "    vec3 bump = texture2D(normalTex, gl_TexCoord[0].xy).xyz;\n"
    "    bump = normalize(bump * 2.0 - 1.0);\n"

    "    float lambert = max(dot(bump, lightDir), 0.0);\n"
    "    if (lambert > 0.0)\n"
    "    {\n"
    "        gl_FragColor = base * gl_LightSource[0].diffuse * lambert;\n"
    "        gl_FragColor += gl_LightSource[0].specular * pow(lambert, 2.0);\n"
    "    }\n"
    "    gl_FragColor += gl_LightSource[0].ambient;\n"
    "}\n"
};

class ComputeTangentVisitor : public osg::NodeVisitor
{
public:
    void apply( osg::Node& node ) { traverse(node); }

    void apply( osg::Geode& node )

    void generateTangentArray( osg::Geometry* geom )
    {
        osg::ref_ptr<osgUtil::TangentSpaceGenerator> tsg = new osgUtil::TangentSpaceGenerator;
        tsg->generate( geom );
        geom->setVertexAttribArray( 6, tsg->getTangentArray() );
        geom->setVertexAttribBinding( 6, osg::Geometry::BIND_PER_VERTEX );
        geom->setVertexAttribArray( 7, tsg->getBinormalArray() );
        geom->setVertexAttribBinding( 7, osg::Geometry::BIND_PER_VERTEX );
    }
};

int main( int argc, char** argv )
{
    osg::ArgumentParser arguments( &argc, argv );
    osg::ref_ptr<osg::Node> scene = osgDB::readNodeFiles( arguments );
    if ( !scene ) scene = osgDB::readNodeFile("skydome.osgt");

    ComputeTangentVisitor ctv;
    ctv.setTraversalMode( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN );
    scene->accept( ctv );

    osg::ref_ptr<osg::Program> program = new osg::Program;
    program->addShader( new osg::Shader(osg::Shader::VERTEX, vertSource) );
    program->addShader( new osg::Shader(osg::Shader::FRAGMENT, fragSource) );
    program->addBindAttribLocation( "tangent", 6 );
    program->addBindAttribLocation( "binormal", 7 );

    osg::ref_ptr<osg::Texture2D> colorTex = new osg::Texture2D;
    colorTex->setImage( osgDB::readImageFile("Images/whitemetal_diffuse.jpg") );

    osg::ref_ptr<osg::Texture2D> normalTex = new osg::Texture2D;
    normalTex->setImage( osgDB::readImageFile("Images/whitemetal_normal.jpg") );

    osg::StateSet* stateset = scene->getOrCreateStateSet();
    stateset->addUniform( new osg::Uniform("colorTex", 0) );
    stateset->addUniform( new osg::Uniform("normalTex", 1) );
    stateset->setAttributeAndModes( program.get() );

    osg::StateAttribute::GLModeValue value = osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE;
    stateset->setTextureAttributeAndModes( 0, colorTex.get(), value );
    stateset->setTextureAttributeAndModes( 1, normalTex.get(), value );

    osgViewer::Viewer viewer;
    viewer.setSceneData( scene.get() );
    return viewer.run();
}


{
        for ( unsigned int i=0; i<node.getNumDrawables(); ++i )
        {
            osg::Geometry* geom = dynamic_cast<osg::Geometry*>( node.getDrawable(i) );
            if ( geom ) generateTangentArray( geom );
        }

        traverse( node );
    }

    void generateTangentArray( osg::Geometry* geom )
    {
        osg::ref_ptr<osgUtil::TangentSpaceGenerator> tsg = new osgUtil::TangentSpaceGenerator;
        tsg->generate( geom );
        geom->setVertexAttribArray( 6, tsg->getTangentArray() );
        geom->setVertexAttribBinding( 6, osg::Geometry::BIND_PER_VERTEX );
        geom->setVertexAttribArray( 7, tsg->getBinormalArray() );
        geom->setVertexAttribBinding( 7, osg::Geometry::BIND_PER_VERTEX );
    }
};

int main( int argc, char** argv )
{
    osg::ArgumentParser arguments( &argc, argv );
    osg::ref_ptr<osg::Node> scene = osgDB::readNodeFiles( arguments );
    if ( !scene ) scene = osgDB::readNodeFile("skydome.osgt");

    ComputeTangentVisitor ctv;
    ctv.setTraversalMode( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN );
    scene->accept( ctv );

    osg::ref_ptr<osg::Program> program = new osg::Program;
    program->addShader( new osg::Shader(osg::Shader::VERTEX, vertSource) );
    program->addShader( new osg::Shader(osg::Shader::FRAGMENT, fragSource) );
    program->addBindAttribLocation( "tangent", 6 );
    program->addBindAttribLocation( "binormal", 7 );

    osg::ref_ptr<osg::Texture2D> colorTex = new osg::Texture2D;
    colorTex->setImage( osgDB::readImageFile("Images/whitemetal_diffuse.jpg") );

    osg::ref_ptr<osg::Texture2D> normalTex = new osg::Texture2D;
    normalTex->setImage( osgDB::readImageFile("Images/whitemetal_normal.jpg") );

    osg::StateSet* stateset = scene->getOrCreateStateSet();
    stateset->addUniform( new osg::Uniform("colorTex", 0) );
    stateset->addUniform( new osg::Uniform("normalTex", 1) );
    stateset->setAttributeAndModes( program.get() );

    osg::StateAttribute::GLModeValue value = osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE;
    stateset->setTextureAttributeAndModes( 0, colorTex.get(), value );
    stateset->setTextureAttributeAndModes( 1, normalTex.get(), value );

    osgViewer::Viewer viewer;
    viewer.setSceneData( scene.get() );
    return viewer.run();
}


/* -*-c++-*- OpenSceneGraph Cookbook
 * Chapter 6 Recipe 1
 * Author: Wang Rui <wangray84 at gmail dot com>
*/

#include <osg/Program>
#include <osg/Texture2D>
#include <osg/ShapeDrawable>
#include <osg/Geode>
#include <osgDB/ReadFile>
#include <osgUtil/TangentSpaceGenerator>
#include <osgViewer/Viewer>

#include "CommonFunctions"

static const char* vertSource = {
    "attribute vec3 tangent;\n"
    "attribute vec3 binormal;\n"
    "varying vec3 lightDir;\n"
    "void main()\n"
    "{\n"
    "    vec3 normal = normalize(gl_NormalMatrix * gl_Normal);\n"
    "    mat3 rotation = mat3(tangent, binormal, normal);\n"
    "    vec4 vertexInEye = gl_ModelViewMatrix * gl_Vertex;\n"
    "    lightDir = vec3(gl_LightSource[0].position.xyz - vertexInEye.xyz);\n"
    "    lightDir = normalize(rotation * normalize(lightDir));\n"
    "    gl_Position = ftransform();\n"
    "    gl_TexCoord[0] = gl_MultiTexCoord0;\n"
    "}\n"
};

static const char* fragSource = {
    "uniform sampler2D colorTex;\n"
    "uniform sampler2D normalTex;\n"
    "varying vec3 lightDir;\n"
    "void main (void)\n"
    "{\n"
    "    vec4 base = texture2D(colorTex, gl_TexCoord[0].xy);\n"
    "    vec3 bump = texture2D(normalTex, gl_TexCoord[0].xy).xyz;\n"
    "    bump = normalize(bump * 2.0 - 1.0);\n"

    "    float lambert = max(dot(bump, lightDir), 0.0);\n"
    "    if (lambert > 0.0)\n"
    "    {\n"
    "        gl_FragColor = base * gl_LightSource[0].diffuse * lambert;\n"
    "        gl_FragColor += gl_LightSource[0].specular * pow(lambert, 2.0);\n"
    "    }\n"
    "    gl_FragColor += gl_LightSource[0].ambient;\n"
    "}\n"
};

class ComputeTangentVisitor : public osg::NodeVisitor
{
public:
    void apply( osg::Node& node ) { traverse(node); }

    void apply( osg::Geode& node )
    {
        for ( unsigned int i=0; i<node.getNumDrawables(); ++i )
        {
            osg::Geometry* geom = dynamic_cast<osg::Geometry*>( node.getDrawable(i) );
            if ( geom ) generateTangentArray( geom );
        }

    }

    void generateTangentArray( osg::Geometry* geom )
    {
        osg::ref_ptr<osgUtil::TangentSpaceGenerator> tsg = new osgUtil::TangentSpaceGenerator;
        tsg->generate( geom );
        geom->setVertexAttribArray( 6, tsg->getTangentArray() );
        geom->setVertexAttribBinding( 6, osg::Geometry::BIND_PER_VERTEX );
        geom->setVertexAttribArray( 7, tsg->getBinormalArray() );
        geom->setVertexAttribBinding( 7, osg::Geometry::BIND_PER_VERTEX );
    }
};

int main( int argc, char** argv )
{
    osg::ArgumentParser arguments( &argc, argv );
    osg::ref_ptr<osg::Node> scene = osgDB::readNodeFiles( arguments );
    if ( !scene ) scene = osgDB::readNodeFile("skydome.osgt");

    ComputeTangentVisitor ctv;
    ctv.setTraversalMode( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN );
    scene->accept( ctv );

    osg::ref_ptr<osg::Program> program = new osg::Program;
    program->addShader( new osg::Shader(osg::Shader::VERTEX, vertSource) );
    program->addShader( new osg::Shader(osg::Shader::FRAGMENT, fragSource) );
    program->addBindAttribLocation( "tangent", 6 );
    program->addBindAttribLocation( "binormal", 7 );

    osg::ref_ptr<osg::Texture2D> colorTex = new osg::Texture2D;
    colorTex->setImage( osgDB::readImageFile("Images/whitemetal_diffuse.jpg") );

    osg::ref_ptr<osg::Texture2D> normalTex = new osg::Texture2D;
    normalTex->setImage( osgDB::readImageFile("Images/whitemetal_normal.jpg") );

    osg::StateSet* stateset = scene->getOrCreateStateSet();
    stateset->addUniform( new osg::Uniform("colorTex", 0) );
    stateset->addUniform( new osg::Uniform("normalTex", 1) );
    stateset->setAttributeAndModes( program.get() );

    osg::StateAttribute::GLModeValue value = osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE;
    stateset->setTextureAttributeAndModes( 0, colorTex.get(), value );
    stateset->setTextureAttributeAndModes( 1, normalTex.get(), value );

    osgViewer::Viewer viewer;
    viewer.setSceneData( scene.get() );
    return viewer.run();
}


/* -*-c++-*- OpenSceneGraph Cookbook
 * Chapter 6 Recipe 1
 * Author: Wang Rui <wangray84 at gmail dot com>
*/

#include <osg/Program>
#include <osg/Texture2D>
#include <osg/ShapeDrawable>
#include <osg/Geode>
#include <osgDB/ReadFile>
#include <osgUtil/TangentSpaceGenerator>
#include <osgViewer/Viewer>

#include "CommonFunctions"

static const char* vertSource = {
    "attribute vec3 tangent;\n"
    "attribute vec3 binormal;\n"
    "varying vec3 lightDir;\n"
    "void main()\n"
    "{\n"
    "    vec3 normal = normalize(gl_NormalMatrix * gl_Normal);\n"
    "    mat3 rotation = mat3(tangent, binormal, normal);\n"
    "    vec4 vertexInEye = gl_ModelViewMatrix * gl_Vertex;\n"
    "    lightDir = vec3(gl_LightSource[0].position.xyz - vertexInEye.xyz);\n"
    "    lightDir = normalize(rotation * normalize(lightDir));\n"
    "    gl_Position = ftransform();\n"
    "    gl_TexCoord[0] = gl_MultiTexCoord0;\n"
    "}\n"
};

static const char* fragSource = {
    "uniform sampler2D colorTex;\n"
    "uniform sampler2D normalTex;\n"
    "varying vec3 lightDir;\n"
    "void main (void)\n"
    "{\n"
    "    vec4 base = texture2D(colorTex, gl_TexCoord[0].xy);\n"
    "    vec3 bump = texture2D(normalTex, gl_TexCoord[0].xy).xyz;\n"
    "    bump = normalize(bump * 2.0 - 1.0);\n"

    "    float lambert = max(dot(bump, lightDir), 0.0);\n"
    "    if (lambert > 0.0)\n"
    "    {\n"
    "        gl_FragColor = base * gl_LightSource[0].diffuse * lambert;\n"
    "        gl_FragColor += gl_LightSource[0].specular * pow(lambert, 2.0);\n"
    "    }\n"
    "    gl_FragColor += gl_LightSource[0].ambient;\n"
    "}\n"
};

class ComputeTangentVisitor : public osg::NodeVisitor
{
public:
    void apply( osg::Node& node ) { traverse(node); }

    void apply( osg::Geode& node )
    {
        for ( unsigned int i=0; i<node.getNumDrawables(); ++i )
        {
            osg::Geometry* geom = dynamic_cast<osg::Geometry*>( node.getDrawable(i) );
            if ( geom ) generateTangentArray( geom );
        }
        traverse( node );


/* -*-c++-*- OpenSceneGraph Cookbook
 * Chapter 6 Recipe 1
 * Author: Wang Rui <wangray84 at gmail dot com>
*/

#include <osg/Program>
#include <osg/Texture2D>
#include <osg/ShapeDrawable>
#include <osg/Geode>
#include <osgDB/ReadFile>
#include <osgUtil/TangentSpaceGenerator>
#include <osgViewer/Viewer>

#include "CommonFunctions"

static const char* vertSource = {
    "attribute vec3 tangent;\n"
    "attribute vec3 binormal;\n"
    "varying vec3 lightDir;\n"
    "void main()\n"
    "{\n"
    "    vec3 normal = normalize(gl_NormalMatrix * gl_Normal);\n"
    "    mat3 rotation = mat3(tangent, binormal, normal);\n"
    "    vec4 vertexInEye = gl_ModelViewMatrix * gl_Vertex;\n"
    "    lightDir = vec3(gl_LightSource[0].position.xyz - vertexInEye.xyz);\n"
    "    lightDir = normalize(rotation * normalize(lightDir));\n"
    "    gl_Position = ftransform();\n"
    "    gl_TexCoord[0] = gl_MultiTexCoord0;\n"
    "}\n"
};

static const char* fragSource = {
    "uniform sampler2D colorTex;\n"
    "uniform sampler2D normalTex;\n"
    "varying vec3 lightDir;\n"
    "void main (void)\n"
    "{\n"
    "    vec4 base = texture2D(colorTex, gl_TexCoord[0].xy);\n"
    "    vec3 bump = texture2D(normalTex, gl_TexCoord[0].xy).xyz;\n"
    "    bump = normalize(bump * 2.0 - 1.0);\n"

    "    float lambert = max(dot(bump, lightDir), 0.0);\n"
    "    if (lambert > 0.0)\n"
    "    {\n"
    "        gl_FragColor = base * gl_LightSource[0].diffuse * lambert;\n"
    "        gl_FragColor += gl_LightSource[0].specular * pow(lambert, 2.0);\n"
    "    }\n"
    "    gl_FragColor += gl_LightSource[0].ambient;\n"
    "}\n"
};

class ComputeTangentVisitor : public osg::NodeVisitor
{
public:
    void apply( osg::Node& node ) { traverse(node); }

    void apply( osg::Geode& node )
    {
        for ( unsigned int i=0; i<node.getNumDrawables(); ++i )
        {
            osg::Geometry* geom = dynamic_cast<osg::Geometry*>( node.getDrawable(i) );
            if ( geom ) generateTangentArray( geom );
        }
        traverse( node );
    }

    void generateTangentArray( osg::Geometry* geom )
    {
        osg::ref_ptr<osgUtil::TangentSpaceGenerator> tsg = new osgUtil::TangentSpaceGenerator;
        tsg->generate( geom );
        geom->setVertexAttribArray( 6, tsg->getTangentArray() );
        geom->setVertexAttribBinding( 6, osg::Geometry::BIND_PER_VERTEX );
        geom->setVertexAttribArray( 7, tsg->getBinorm

        geom->setVertexAttribBinding( 7, osg::Geometry::BIND_PER_VERTEX );
    }
};

int main( int argc, char** argv )
{
    osg::ArgumentParser arguments( &argc, argv );
    osg::ref_ptr<osg::Node> scene = osgDB::readNodeFiles( arguments );
    if ( !scene ) scene = osgDB::readNodeFile("skydome.osgt");

    ComputeTangentVisitor ctv;
    ctv.setTraversalMode( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN );
    scene->accept( ctv );

    osg::ref_ptr<osg::Program> program = new osg::Program;
    program->addShader( new osg::Shader(osg::Shader::VERTEX, vertSource) );
    program->addShader( new osg::Shader(osg::Shader::FRAGMENT, fragSource) );
    program->addBindAttribLocation( "tangent", 6 );
    program->addBindAttribLocation( "binormal", 7 );

    osg::ref_ptr<osg::Texture2D> colorTex = new osg::Texture2D;
    colorTex->setImage( osgDB::readImageFile("Images/whitemetal_diffuse.jpg") );

    osg::ref_ptr<osg::Texture2D> normalTex = new osg::Texture2D;
    normalTex->setImage( osgDB::readImageFile("Images/whitemetal_normal.jpg") );

    osg::StateSet* stateset = scene->getOrCreateStateSet();
    stateset->addUniform( new osg::Uniform("colorTex", 0) );
    stateset->addUniform( new osg::Uniform("normalTex", 1) );
    stateset->setAttributeAndModes( program.get() );

    osg::StateAttribute::GLModeValue value = osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE;
    stateset->setTextureAttributeAndModes( 0, colorTex.get(), value );
    stateset->setTextureAttributeAndModes( 1, normalTex.get(), value );

    osgViewer::Viewer viewer;
    viewer.setSceneData( scene.get() );
    return viewer.run();
}


if ( !scene ) scene = osgDB::readNodeFile("skydome.osgt");

/* -*-c++-*- OpenSceneGraph Cookbook
 * Chapter 6 Recipe 1
 * Author: Wang Rui <wangray84 at gmail dot com>
*/

#include <osg/Program>
#include <osg/Texture2D>
#include <osg/ShapeDrawable>
#include <osg/Geode>
#include <osgDB/ReadFile>
#include <osgUtil/TangentSpaceGenerator>
#include <osgViewer/Viewer>

#include "CommonFunctions"

static const char* vertSource = {
    "attribute vec3 tangent;\n"
    "attribute vec3 binormal;\n"
    "varying vec3 lightDir;\n"
    "void main()\n"
    "{\n"
    "    vec3 normal = normalize(gl_NormalMatrix * gl_Normal);\n"
    "    mat3 rotation = mat3(tangent, binormal, normal);\n"
    "    vec4 vertexInEye = gl_ModelViewMatrix * gl_Vertex;\n"
    "    lightDir = vec3(gl_LightSource[0].position.xyz - vertexInEye.xyz);\n"
    "    lightDir = normalize(rotation * normalize(lightDir));\n"
    "    gl_Position = ftransform();\n"
    "    gl_TexCoord[0] = gl_MultiTexCoord0;\n"
    "}\n"
};

static const char* fragSource = {
    "uniform sampler2D colorTex;\n"
    "uniform sampler2D normalTex;\n"
    "varying vec3 lightDir;\n"
    "void main (void)\n"
    "{\n"
    "    vec4 base = texture2D(colorTex, gl_TexCoord[0].xy);\n"
    "    vec3 bump = texture2D(normalTex, gl_TexCoord[0].xy).xyz;\n"
    "    bump = normalize(bump * 2.0 - 1.0);\n"

    "    float lambert = max(dot(bump, lightDir), 0.0);\n"
    "    if (lambert > 0.0)\n"
    "    {\n"
    "        gl_FragColor = base * gl_LightSource[0].diffuse * lambert;\n"
    "        gl_FragColor += gl_LightSource[0].specular * pow(lambert, 2.0);\n"
    "    }\n"
    "    gl_FragColor += gl_LightSource[0].ambient;\n"
    "}\n"
};

class ComputeTangentVisitor : public osg::NodeVisitor
{
public:
    void apply( osg::Node& node ) { traverse(node); }

    void apply( osg::Geode& node )
    {
        for ( unsigned int i=0; i<node.getNumDrawables(); ++i )
        {
            osg::Geometry* geom = dynamic_cast<osg::Geometry*>( node.getDrawable(i) );
            if ( geom ) generateTangentArray( geom );
        }
        traverse( node );
    }

    void generateTangentArray( osg::Geometry* geom )
    {
        osg::ref_ptr<osgUtil::TangentSpaceGenerator> tsg = new osgUtil::TangentSpaceGenerator;
        tsg->generate( geom );
        geom->setVertexAttribArray( 6, tsg->getTangentArray() );
        geom->setVertexAttribBinding( 6, osg::Geometry::BIND_PER_VERTEX );
        geom->setVertexAttribArray( 7, tsg->getBinormalArray() );
        geom->setVertexAttribBinding( 7, osg::Geometry::BIND_PER_VERTEX );
    }
};

int main( int argc, char** argv )
{
    osg::ArgumentParser arguments( &argc, argv );
    osg::ref_ptr<osg::Node> scene = osgDB::readNodeFiles( arguments );

    ComputeTangentVisitor ctv;
    ctv.setTraversalMode( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN );
    scene->accept( ctv );

    osg::ref_ptr<osg::Program> program = new osg::Program;
    program->addShader( new osg::Shader(osg::Shader::VERTEX, vertSource) );
    program->addShader( new osg::Shader(osg::Shader::FRAGMENT, fragSource) );
    program->addBindAttribLocation( "tangent", 6 );
    program->addBindAttribLocation( "binormal", 7 );

    osg::ref_ptr<osg::Texture2D> colorTex = new osg::Texture2D;
    colorTex->setImage( osgDB::readImageFile("Images/whitemetal_diffuse.jpg") );

    osg::ref_ptr<osg::Texture2D> normalTex = new osg::Texture2D;
    normalTex->setImage( osgDB::readImageFile("Images/whitemetal_normal.jpg") );

    osg::StateSet* stateset = scene->getOrCreateStateSet();
    stateset->addUniform( new osg::Uniform("colorTex", 0) );
    stateset->addUniform( new osg::Uniform("normalTex", 1) );
    stateset->setAttributeAndModes( program.get() );

    osg::StateAttribute::GLModeValue value = osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE;
    stateset->setTextureAttributeAndModes( 0, colorTex.get(), value );
    stateset->setTextureAttributeAndModes( 1, normalTex.get(), value );

    osgViewer::Viewer viewer;
    viewer.setSceneData( scene.get() );
    return viewer.run();
}


for ( unsigned int i=0; i<node.getNumDrawables(); ++i )
        {
            osg::Geometry* geom = dynamic_cast<osg::Geometry*>( node.getDrawable(i) );
            if ( geom ) generateTangentArray( geom );
        }

/* -*-c++-*- OpenSceneGraph Cookbook
 * Chapter 6 Recipe 1
 * Author: Wang Rui <wangray84 at gmail dot com>
*/

#include <osg/Program>
#include <osg/Texture2D>
#include <osg/ShapeDrawable>
#include <osg/Geode>
#include <osgDB/ReadFile>
#include <osgUtil/TangentSpaceGenerator>
#include <osgViewer/Viewer>

#include "CommonFunctions"

static const char* vertSource = {
    "attribute vec3 tangent;\n"
    "attribute vec3 binormal;\n"
    "varying vec3 lightDir;\n"
    "void main()\n"
    "{\n"
    "    vec3 normal = normalize(gl_NormalMatrix * gl_Normal);\n"
    "    mat3 rotation = mat3(tangent, binormal, normal);\n"
    "    vec4 vertexInEye = gl_ModelViewMatrix * gl_Vertex;\n"
    "    lightDir = vec3(gl_LightSource[0].position.xyz - vertexInEye.xyz);\n"
    "    lightDir = normalize(rotation * normalize(lightDir));\n"
    "    gl_Position = ftransform();\n"
    "    gl_TexCoord[0] = gl_MultiTexCoord0;\n"
    "}\n"
};

static const char* fragSource = {
    "uniform sampler2D colorTex;\n"
    "uniform sampler2D normalTex;\n"
    "varying vec3 lightDir;\n"
    "void main (void)\n"
    "{\n"
    "    vec4 base = texture2D(colorTex, gl_TexCoord[0].xy);\n"
    "    vec3 bump = texture2D(normalTex, gl_TexCoord[0].xy).xyz;\n"
    "    bump = normalize(bump * 2.0 - 1.0);\n"

    "    float lambert = max(dot(bump, lightDir), 0.0);\n"
    "    if (lambert > 0.0)\n"
    "    {\n"
    "        gl_FragColor = base * gl_LightSource[0].diffuse * lambert;\n"
    "        gl_FragColor += gl_LightSource[0].specular * pow(lambert, 2.0);\n"
    "    }\n"
    "    gl_FragColor += gl_LightSource[0].ambient;\n"
    "}\n"
};

class ComputeTangentVisitor : public osg::NodeVisitor
{
public:
    void apply( osg::Node& node ) { traverse(node); }

    void apply( osg::Geode& node )
    {


/* -*-c++-*- OpenSceneGraph Cookbook
 * Chapter 6 Recipe 1
 * Author: Wang Rui <wangray84 at gmail dot com>
*/

#include <osg/Program>
#include <osg/Texture2D>
#include <osg/ShapeDrawable>
#include <osg/Geode>
#include <osgDB/ReadFile>
#include <osgUtil/TangentSpaceGenerator>
#include <osgViewer/Viewer>

#include "CommonFunctions"

static const char* vertSource = {
    "attribute vec3 tangent;\n"
    "attribute vec3 binormal;\n"
    "varying vec3 lightDir;\n"
    "void main()\n"
    "{\n"
    "    vec3 normal = normalize(gl_NormalMatrix * gl_Normal);\n"
    "    mat3 rotation = mat3(tangent, binormal, normal);\n"
    "    vec4 vertexInEye = gl_ModelViewMatrix * gl_Vertex;\n"
    "    lightDir = vec3(gl_LightSource[0].position.xyz - vertexInEye.xyz);\n"
    "    lightDir = normalize(rotation * normalize(lightDir));\n"
    "    gl_Position = ftransform();\n"
    "    gl_TexCoord[0] = gl_MultiTexCoord0;\n"
    "}\n"
};

static const char* fragSource = {
    "uniform sampler2D colorTex;\n"
    "uniform sampler2D normalTex;\n"
    "varying vec3 lightDir;\n"
    "void main (void)\n"
    "{\n"
    "    vec4 base = texture2D(colorTex, gl_TexCoord[0].xy);\n"
    "    vec3 bump = texture2D(normalTex, gl_TexCoord[0].xy).xyz;\n"
    "    bump = normalize(bump * 2.0 - 1.0);\n"

    "    float lambert = max(dot(bump, lightDir), 0.0);\n"
    "    if (lambert > 0.0)\n"
    "    {\n"
    "        gl_FragColor = base * gl_LightSource[0].diffuse * lambert;\n"
    "        gl_FragColor += gl_LightSource[0].specular * pow(lambert, 2.0);\n"
    "    }\n"
    "    gl_FragColor += gl_LightSource[0].ambient;\n"
    "}\n"
};

class ComputeTangentVisitor : public osg::NodeVisitor
{
public:
    void apply( osg::Node& node ) { traverse(node); }

    void apply( osg::Geode& node )
    {
        for ( unsigned int i=0; i<node.getNumDrawables(); ++i )
        {
            osg::Geometry* geom = dynamic_cast<osg::Geometry*>( node.getDrawable(i) );
            if ( geom ) generateTangent

Array( geom );
        }
        traverse( node );
    }

    void generateTangentArray( osg::Geometry* geom )
    {
        osg::ref_ptr<osgUtil::TangentSpaceGenerator> tsg = new osgUtil::TangentSpaceGenerator;
        tsg->generate( geom );
        geom->setVertexAttribArray( 6, tsg->getTangentArray() );
        geom->setVertexAttribBinding( 6, osg::Geometry::BIND_PER_VERTEX );
        geom->setVertexAttribArray( 7, tsg->getBinormalArray() );
        geom->setVertexAttribBinding( 7, osg::Geometry::BIND_PER_VERTEX );
    }
};

int main( int argc, char** argv )
{
    osg::ArgumentParser arguments( &argc, argv );
    osg::ref_ptr<osg::Node> scene = osgDB::readNodeFiles( arguments );
    if ( !scene ) scene = osgDB::readNodeFile("skydome.osgt");

    ComputeTangentVisitor ctv;
    ctv.setTraversalMode( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN );
    scene->accept( ctv );

    osg::ref_ptr<osg::Program> program = new osg::Program;
    program->addShader( new osg::Shader(osg::Shader::VERTEX, vertSource) );
    program->addShader( new osg::Shader(osg::Shader::FRAGMENT, fragSource) );
    program->addBindAttribLocation( "tangent", 6 );
    program->addBindAttribLocation( "binormal", 7 );

    osg::ref_ptr<osg::Texture2D> colorTex = new osg::Texture2D;
    colorTex->setImage( osgDB::readImageFile("Images/whitemetal_diffuse.jpg") );

    osg::ref_ptr<osg::Texture2D> normalTex = new osg::Texture2D;
    normalTex->setImage( osgDB::readImageFile("Images/whitemetal_normal.jpg") );

    osg::StateSet* stateset = scene->getOrCreateStateSet();
    stateset->addUniform( new osg::Uniform("colorTex", 0) );
    stateset->addUniform( new osg::Uniform("normalTex", 1) );
    stateset->setAttributeAndModes( program.get() );

    osg::StateAttribute::GLModeValue value = osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE;
    stateset->setTextureAttributeAndModes( 0, colorTex.get(), value );
    stateset->setTextureAttributeAndModes( 1, normalTex.get(), value );

    osgViewer::Viewer viewer;
    viewer.setSceneData( scene.get() );
    return viewer.run();
}