<commit_before>/*************************************
** Tsunagari Tile Engine            **
** window.cpp                       **
** Copyright 2016-2019 Paul Merrill **
*************************************/

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

#include "av/sdl2/window.h"

#include "av/sdl2/error.h"
#include "av/sdl2/sdl2.h"
#include "core/client-conf.h"
#include "core/display-list.h"
#include "core/log.h"
#include "core/measure.h"
#include "core/world.h"
#include "util/noexcept.h"
#include "util/optional.h"

SDL_Renderer* SDL2GameWindow::renderer = nullptr;
rvec2 SDL2GameWindow::translation = {0.0, 0.0};
rvec2 SDL2GameWindow::scaling = {0.0, 0.0};

static TimePoint start = SteadyClock::nowMS();

static SDL_Window* window = nullptr;
static Transform transform = Transform::identity();

static int
getRefreshRate(SDL_Window* window) noexcept {
    // SDL_GetWindowDisplayIndex computes which display the window is on each
    // time.
    int display = SDL_GetWindowDisplayIndex(window);
    SDL_DisplayMode mode;
    SDL_GetCurrentDisplayMode(display, &mode);
    return mode.refresh_rate;
}

static void
handleEvent(const SDL_Event& event) noexcept {
    KeyboardKey key;

    switch (event.type) {
    case SDL_KEYUP:
    case SDL_KEYDOWN:
        switch (event.key.keysym.sym) {
        case SDLK_ESCAPE:
            key = KBEscape;
            break;
        case SDLK_LCTRL:
            key = KBLeftControl;
            break;
        case SDLK_RCTRL:
            key = KBRightControl;
            break;
        case SDLK_LSHIFT:
            key = KBLeftShift;
            break;
        case SDLK_RSHIFT:
            key = KBRightShift;
            break;
        case SDLK_SPACE:
            key = KBSpace;
            break;
        case SDLK_LEFT:
            key = KBLeftArrow;
            break;
        case SDLK_RIGHT:
            key = KBRightArrow;
            break;
        case SDLK_UP:
            key = KBUpArrow;
            break;
        case SDLK_DOWN:
            key = KBDownArrow;
            break;
        default:
            return;
        }
        if (event.type == SDL_KEYUP) {
            GameWindow::emitKeyUp(key);
        }
        else if (event.type == SDL_KEYDOWN) {
            GameWindow::emitKeyDown(key);
        }
        break;

    case SDL_QUIT:
        SDL_DestroyWindow(window);
        exit(0);
        return;

    default:
        return;
    }
}

static void
handleEvents() noexcept {
    SDL_Event event;

    while (SDL_PollEvent(&event)) {
        handleEvent(event);
    }
}

static void
updateTransform() noexcept {
    int w, h;

    SDL_GetWindowSize(window, &w, &h);

    float xScale = transform[0];
    float yScale = transform[5];
    float x = transform[12];
    float y = transform[13];

    SDL2GameWindow::translation = {x / xScale, y / yScale};
    SDL2GameWindow::scaling = {xScale, yScale};
}

time_t
GameWindow::time() noexcept {
    return SteadyClock::nowMS() - start;
}

void
GameWindow::create() noexcept {
    {
        TimeMeasure m("Initialized the SDL2 video subsystem");
        if (SDL_Init(SDL_INIT_VIDEO) < 0) {
            sdlDie("SDL2GameWindow", "SDL_Init(SDL_INIT_VIDEO)");
        }
    }

    {
        TimeMeasure m("Created SDL2 window");

        int width = Conf::windowSize.x;
        int height = Conf::windowSize.y;

        uint32_t flags = SDL_WINDOW_HIDDEN;
        if (Conf::fullscreen) {
            flags |= SDL_WINDOW_FULLSCREEN;
        }

        window = SDL_CreateWindow("Tsunagari",
                                  SDL_WINDOWPOS_UNDEFINED,
                                  SDL_WINDOWPOS_UNDEFINED,
                                  width,
                                  height,
                                  flags);

        if (window == nullptr) {
            sdlDie("SDL2GameWindow", "SDL_CreateWindow");
        }
    }

    {
        TimeMeasure m("Created SDL2 renderer");

        SDL2GameWindow::renderer = SDL_CreateRenderer(
                window,
                -1,
                SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

        if (SDL2GameWindow::renderer == nullptr) {
            sdlDie("SDL2GameWindow", "SDL_CreateRenderer");
        }

        SDL_RendererInfo info;

        if (SDL_GetRendererInfo(SDL2GameWindow::renderer, &info) < 0) {
            sdlDie("SDL2GameWindow", "SDL_GetRendererInfo");
        }

        StringView name = info.name;
        bool vsync = info.flags & SDL_RENDERER_PRESENTVSYNC;

        Log::info("SDL2GameWindow",
                  String("Rendering will be done with ")
                          << name
                          << (vsync ? " with vsync" : " without vsync"));
    }

    SDL_SetRenderDrawColor(SDL2GameWindow::renderer, 0x00, 0x00, 0x00, 0xFF);
}

unsigned
GameWindow::width() noexcept {
    int w, h;
    SDL_GetWindowSize(window, &w, &h);
    return static_cast<unsigned>(w);
}

unsigned
GameWindow::height() noexcept {
    int w, h;
    SDL_GetWindowSize(window, &w, &h);
    return static_cast<unsigned>(h);
}

void
GameWindow::setCaption(StringView caption) noexcept {
    SDL_SetWindowTitle(window, String(caption).null());
}

void
GameWindow::mainLoop() noexcept {
    SDL_ShowWindow(window);

    DisplayList display;

    int refreshRate = getRefreshRate(window);
    const Duration idealFrameTime = s_to_ns(1) / refreshRate;

    // Block until the start of a frame.
    SDL_SetRenderDrawColor(SDL2GameWindow::renderer, 0, 0, 0, 0xFF);
    SDL_RenderClear(SDL2GameWindow::renderer);
    SDL_RenderPresent(SDL2GameWindow::renderer);

    TimePoint frameStart = SteadyClock::now();
    TimePoint previousFrameStart =
            frameStart - idealFrameTime;  // Bogus initial value.

    TimePoint nextFrameStart = frameStart + idealFrameTime;

    while (window != nullptr) {
        handleEvents();

        //
        // Simulate world and draw frame.
        //
        time_t dt = ns_to_ms(frameStart - previousFrameStart);

        assert_(dt >= 0);

        if (dt > 0) {
            World::tick(dt);
        } else {
            Log::info("SDL2GameWindow", "dt == 0");
        }

        bool drew = false;
        if (World::needsRedraw()) {
            drew = true;

            World::draw(&display);

            SDL_SetRenderDrawColor(SDL2GameWindow::renderer, 0, 0, 0, 0xFF);
            SDL_RenderClear(SDL2GameWindow::renderer);
            displayListPresent(&display);
            SDL_RenderPresent(SDL2GameWindow::renderer);

            display.items.clear();
        }

        TimePoint frameEnd = SteadyClock::now();
        Duration timeTaken = frameEnd - frameStart;

        //
        // Sleep until next frame.
        //
        Duration sleepDuration = nextFrameStart - frameEnd;
        if (sleepDuration < 0) {
            sleepDuration = 0;
        }

        if (!drew && sleepDuration) {
            SleepFor(sleepDuration);
        }

        previousFrameStart = frameStart;
        frameStart = SteadyClock::now();
        nextFrameStart += idealFrameTime;

        if (frameStart > nextFrameStart) {
            int framesDropped = 0;
            while (frameStart > nextFrameStart) {
                nextFrameStart += idealFrameTime;
                framesDropped += 1;
            }
            Log::info("GameWindow",
                      String() << "Dropped " << framesDropped << " frames");
        }
    }
}

void
GameWindow::drawRect(float x1,
                     float x2,
                     float y1,
                     float y2,
                     uint32_t argb) noexcept {
    auto a = static_cast<uint8_t>((argb >> 24) & 0xFF);
    auto r = static_cast<uint8_t>((argb >> 16) & 0xFF);
    auto g = static_cast<uint8_t>((argb >> 8) & 0xFF);
    auto b = static_cast<uint8_t>((argb >> 0) & 0xFF);

    SDL_Rect rect{static_cast<int>(x1),
                  static_cast<int>(y1),
                  static_cast<int>(x2 - x1),
                  static_cast<int>(y2 - y1)};

    SDL_SetRenderDrawColor(SDL2GameWindow::renderer, r, g, b, a);
    SDL_SetRenderDrawBlendMode(SDL2GameWindow::renderer, SDL_BLENDMODE_BLEND);
    SDL_RenderFillRect(SDL2GameWindow::renderer, &rect);
}

void
GameWindow::scale(float x, float y, Function<void()> op) noexcept {
    assert_(x == y);

    Transform prev = transform;

    auto factor = static_cast<float>(x);

    transform = Transform::scale(factor) * transform;
    updateTransform();

    op();

    transform = prev;
    updateTransform();
}

void
GameWindow::translate(float x, float y, Function<void()> op) noexcept {
    Transform prev = transform;

    transform =
            Transform::translate(static_cast<float>(x), static_cast<float>(y)) *
            transform;
    updateTransform();

    op();

    transform = prev;
    updateTransform();
}

void
GameWindow::clip(float x,
                 float y,
                 float width,
                 float height,
                 Function<void()> op) noexcept {
    op();
}

void
GameWindow::close() noexcept {
    SDL_DestroyWindow(window);
    window = nullptr;
}
<commit_msg>av/sdl2/window: Narrow a TimeMeasure window<commit_after>/*************************************
** Tsunagari Tile Engine            **
** window.cpp                       **
** Copyright 2016-2019 Paul Merrill **
*************************************/

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

#include "av/sdl2/window.h"

#include "av/sdl2/error.h"
#include "av/sdl2/sdl2.h"
#include "core/client-conf.h"
#include "core/display-list.h"
#include "core/log.h"
#include "core/measure.h"
#include "core/world.h"
#include "util/noexcept.h"
#include "util/optional.h"

SDL_Renderer* SDL2GameWindow::renderer = nullptr;
rvec2 SDL2GameWindow::translation = {0.0, 0.0};
rvec2 SDL2GameWindow::scaling = {0.0, 0.0};

static TimePoint start = SteadyClock::nowMS();

static SDL_Window* window = nullptr;
static Transform transform = Transform::identity();

static int
getRefreshRate(SDL_Window* window) noexcept {
    // SDL_GetWindowDisplayIndex computes which display the window is on each
    // time.
    int display = SDL_GetWindowDisplayIndex(window);
    SDL_DisplayMode mode;
    SDL_GetCurrentDisplayMode(display, &mode);
    return mode.refresh_rate;
}

static void
handleEvent(const SDL_Event& event) noexcept {
    KeyboardKey key;

    switch (event.type) {
    case SDL_KEYUP:
    case SDL_KEYDOWN:
        switch (event.key.keysym.sym) {
        case SDLK_ESCAPE:
            key = KBEscape;
            break;
        case SDLK_LCTRL:
            key = KBLeftControl;
            break;
        case SDLK_RCTRL:
            key = KBRightControl;
            break;
        case SDLK_LSHIFT:
            key = KBLeftShift;
            break;
        case SDLK_RSHIFT:
            key = KBRightShift;
            break;
        case SDLK_SPACE:
            key = KBSpace;
            break;
        case SDLK_LEFT:
            key = KBLeftArrow;
            break;
        case SDLK_RIGHT:
            key = KBRightArrow;
            break;
        case SDLK_UP:
            key = KBUpArrow;
            break;
        case SDLK_DOWN:
            key = KBDownArrow;
            break;
        default:
            return;
        }
        if (event.type == SDL_KEYUP) {
            GameWindow::emitKeyUp(key);
        }
        else if (event.type == SDL_KEYDOWN) {
            GameWindow::emitKeyDown(key);
        }
        break;

    case SDL_QUIT:
        SDL_DestroyWindow(window);
        exit(0);
        return;

    default:
        return;
    }
}

static void
handleEvents() noexcept {
    SDL_Event event;

    while (SDL_PollEvent(&event)) {
        handleEvent(event);
    }
}

static void
updateTransform() noexcept {
    int w, h;

    SDL_GetWindowSize(window, &w, &h);

    float xScale = transform[0];
    float yScale = transform[5];
    float x = transform[12];
    float y = transform[13];

    SDL2GameWindow::translation = {x / xScale, y / yScale};
    SDL2GameWindow::scaling = {xScale, yScale};
}

time_t
GameWindow::time() noexcept {
    return SteadyClock::nowMS() - start;
}

void
GameWindow::create() noexcept {
    {
        TimeMeasure m("Initialized the SDL2 video subsystem");
        if (SDL_Init(SDL_INIT_VIDEO) < 0) {
            sdlDie("SDL2GameWindow", "SDL_Init(SDL_INIT_VIDEO)");
        }
    }

    {
        TimeMeasure m("Created SDL2 window");

        int width = Conf::windowSize.x;
        int height = Conf::windowSize.y;

        uint32_t flags = SDL_WINDOW_HIDDEN;
        if (Conf::fullscreen) {
            flags |= SDL_WINDOW_FULLSCREEN;
        }

        window = SDL_CreateWindow("Tsunagari",
                                  SDL_WINDOWPOS_UNDEFINED,
                                  SDL_WINDOWPOS_UNDEFINED,
                                  width,
                                  height,
                                  flags);

        if (window == nullptr) {
            sdlDie("SDL2GameWindow", "SDL_CreateWindow");
        }
    }

    {
        TimeMeasure m("Created SDL2 renderer");

        SDL2GameWindow::renderer = SDL_CreateRenderer(
                window,
                -1,
                SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

        if (SDL2GameWindow::renderer == nullptr) {
            sdlDie("SDL2GameWindow", "SDL_CreateRenderer");
        }
    }

    SDL_RendererInfo info;

    if (SDL_GetRendererInfo(SDL2GameWindow::renderer, &info) < 0) {
        sdlDie("SDL2GameWindow", "SDL_GetRendererInfo");
    }

    StringView name = info.name;
    bool vsync = info.flags & SDL_RENDERER_PRESENTVSYNC;

    Log::info("SDL2GameWindow",
              String("Rendering will be done with ")
                      << name
                      << (vsync ? " with vsync" : " without vsync"));

    SDL_SetRenderDrawColor(SDL2GameWindow::renderer, 0x00, 0x00, 0x00, 0xFF);
}

unsigned
GameWindow::width() noexcept {
    int w, h;
    SDL_GetWindowSize(window, &w, &h);
    return static_cast<unsigned>(w);
}

unsigned
GameWindow::height() noexcept {
    int w, h;
    SDL_GetWindowSize(window, &w, &h);
    return static_cast<unsigned>(h);
}

void
GameWindow::setCaption(StringView caption) noexcept {
    SDL_SetWindowTitle(window, String(caption).null());
}

void
GameWindow::mainLoop() noexcept {
    SDL_ShowWindow(window);

    DisplayList display;

    int refreshRate = getRefreshRate(window);
    const Duration idealFrameTime = s_to_ns(1) / refreshRate;

    // Block until the start of a frame.
    SDL_SetRenderDrawColor(SDL2GameWindow::renderer, 0, 0, 0, 0xFF);
    SDL_RenderClear(SDL2GameWindow::renderer);
    SDL_RenderPresent(SDL2GameWindow::renderer);

    TimePoint frameStart = SteadyClock::now();
    TimePoint previousFrameStart =
            frameStart - idealFrameTime;  // Bogus initial value.

    TimePoint nextFrameStart = frameStart + idealFrameTime;

    while (window != nullptr) {
        handleEvents();

        //
        // Simulate world and draw frame.
        //
        time_t dt = ns_to_ms(frameStart - previousFrameStart);

        assert_(dt >= 0);

        if (dt > 0) {
            World::tick(dt);
        } else {
            Log::info("SDL2GameWindow", "dt == 0");
        }

        bool drew = false;
        if (World::needsRedraw()) {
            drew = true;

            World::draw(&display);

            SDL_SetRenderDrawColor(SDL2GameWindow::renderer, 0, 0, 0, 0xFF);
            SDL_RenderClear(SDL2GameWindow::renderer);
            displayListPresent(&display);
            SDL_RenderPresent(SDL2GameWindow::renderer);

            display.items.clear();
        }

        TimePoint frameEnd = SteadyClock::now();
        Duration timeTaken = frameEnd - frameStart;

        //
        // Sleep until next frame.
        //
        Duration sleepDuration = nextFrameStart - frameEnd;
        if (sleepDuration < 0) {
            sleepDuration = 0;
        }

        if (!drew && sleepDuration) {
            SleepFor(sleepDuration);
        }

        previousFrameStart = frameStart;
        frameStart = SteadyClock::now();
        nextFrameStart += idealFrameTime;

        if (frameStart > nextFrameStart) {
            int framesDropped = 0;
            while (frameStart > nextFrameStart) {
                nextFrameStart += idealFrameTime;
                framesDropped += 1;
            }
            Log::info("GameWindow",
                      String() << "Dropped " << framesDropped << " frames");
        }
    }
}

void
GameWindow::drawRect(float x1,
                     float x2,
                     float y1,
                     float y2,
                     uint32_t argb) noexcept {
    auto a = static_cast<uint8_t>((argb >> 24) & 0xFF);
    auto r = static_cast<uint8_t>((argb >> 16) & 0xFF);
    auto g = static_cast<uint8_t>((argb >> 8) & 0xFF);
    auto b = static_cast<uint8_t>((argb >> 0) & 0xFF);

    SDL_Rect rect{static_cast<int>(x1),
                  static_cast<int>(y1),
                  static_cast<int>(x2 - x1),
                  static_cast<int>(y2 - y1)};

    SDL_SetRenderDrawColor(SDL2GameWindow::renderer, r, g, b, a);
    SDL_SetRenderDrawBlendMode(SDL2GameWindow::renderer, SDL_BLENDMODE_BLEND);
    SDL_RenderFillRect(SDL2GameWindow::renderer, &rect);
}

void
GameWindow::scale(float x, float y, Function<void()> op) noexcept {
    assert_(x == y);

    Transform prev = transform;

    auto factor = static_cast<float>(x);

    transform = Transform::scale(factor) * transform;
    updateTransform();

    op();

    transform = prev;
    updateTransform();
}

void
GameWindow::translate(float x, float y, Function<void()> op) noexcept {
    Transform prev = transform;

    transform =
            Transform::translate(static_cast<float>(x), static_cast<float>(y)) *
            transform;
    updateTransform();

    op();

    transform = prev;
    updateTransform();
}

void
GameWindow::clip(float x,
                 float y,
                 float width,
                 float height,
                 Function<void()> op) noexcept {
    op();
}

void
GameWindow::close() noexcept {
    SDL_DestroyWindow(window);
    window = nullptr;
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2019 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "blocksignature.h"
#include "main.h"
#include "zpivchain.h"

bool SignBlockWithKey(CBlock& block, const CKey& key)
{
    if (!key.Sign(block.GetHash(), block.vchBlockSig))
        return error("%s: failed to sign block hash with key", __func__);

    return true;
}

bool GetKeyIDFromUTXO(const CTxOut& txout, CKeyID& keyID)
{
    std::vector<valtype> vSolutions;
    txnouttype whichType;
    if (!Solver(txout.scriptPubKey, whichType, vSolutions))
        return false;
    if (whichType == TX_PUBKEY) {
        keyID = CPubKey(vSolutions[0]).GetID();
    } else if (whichType == TX_PUBKEYHASH) {
        keyID = CKeyID(uint160(vSolutions[0]));
    }

    return true;
}

bool SignBlock(CBlock& block, const CKeyStore& keystore)
{
    CKeyID keyID;
    if (block.IsProofOfWork()) {
        bool fFoundID = false;
        for (const CTxOut& txout :block.vtx[0].vout) {
            if (!GetKeyIDFromUTXO(txout, keyID))
                continue;
            fFoundID = true;
            break;
        }
        if (!fFoundID)
            return error("%s: failed to find key for PoW", __func__);
    } else {
        if (!GetKeyIDFromUTXO(block.vtx[1].vout[1], keyID))
            return error("%s: failed to find key for PoS", __func__);
    }

    CKey key;
    if (!keystore.GetKey(keyID, key))
        return error("%s: failed to get key from keystore", __func__);

    return SignBlockWithKey(block, key);
}

bool CheckBlockSignature(const CBlock& block)
{
    if (block.IsProofOfWork())
        return block.vchBlockSig.empty();

    if (block.vchBlockSig.empty())
        return error("%s: vchBlockSig is empty!", __func__);

    /** Each block is signed by the private key of the input that is staked. This can be either zPIV or normal UTXO
     *  zPIV: Each zPIV has a keypair associated with it. The serial number is a hash of the public key.
     *  UTXO: The public key that signs must match the public key associated with the first utxo of the coinstake tx.
     */
    CPubKey pubkey;
    bool fzPIVStake = block.vtx[1].vin[0].IsZerocoinSpend();
    if (fzPIVStake) {
        libzerocoin::CoinSpend spend = TxInToZerocoinSpend(block.vtx[1].vin[0]);
        pubkey = spend.getPubKey();
    } else {
        txnouttype whichType;
        std::vector<valtype> vSolutions;
        const CTxOut& txout = block.vtx[1].vout[1];
        if (!Solver(txout.scriptPubKey, whichType, vSolutions))
            return false;
        if (whichType == TX_PUBKEY || whichType == TX_PUBKEYHASH) {
            valtype& vchPubKey = vSolutions[0];
            pubkey = CPubKey(vchPubKey);
        }
    }

    if (!pubkey.IsValid())
        return error("%s: invalid pubkey %s", __func__, HexStr(pubkey));

    return pubkey.Verify(block.GetHash(), block.vchBlockSig);
}
<commit_msg>[Core] Sign block with staking key if coinstake is 'cold' stake<commit_after>// Copyright (c) 2017-2019 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "blocksignature.h"
#include "main.h"
#include "zpivchain.h"

bool SignBlockWithKey(CBlock& block, const CKey& key)
{
    if (!key.Sign(block.GetHash(), block.vchBlockSig))
        return error("%s: failed to sign block hash with key", __func__);

    return true;
}

bool GetKeyIDFromUTXO(const CTxOut& txout, CKeyID& keyID)
{
    std::vector<valtype> vSolutions;
    txnouttype whichType;
    if (!Solver(txout.scriptPubKey, whichType, vSolutions))
        return false;
    if (whichType == TX_PUBKEY) {
        keyID = CPubKey(vSolutions[0]).GetID();
    } else if (whichType == TX_PUBKEYHASH || whichType == TX_COLDSTAKE) {
        keyID = CKeyID(uint160(vSolutions[0]));
    } else {
        return false;
    }

    return true;
}

bool SignBlock(CBlock& block, const CKeyStore& keystore)
{
    CKeyID keyID;
    if (block.IsProofOfWork()) {
        bool fFoundID = false;
        for (const CTxOut& txout :block.vtx[0].vout) {
            if (!GetKeyIDFromUTXO(txout, keyID))
                continue;
            fFoundID = true;
            break;
        }
        if (!fFoundID)
            return error("%s: failed to find key for PoW", __func__);
    } else {
        if (!GetKeyIDFromUTXO(block.vtx[1].vout[1], keyID))
            return error("%s: failed to find key for PoS", __func__);
    }

    CKey key;
    if (!keystore.GetKey(keyID, key))
        return error("%s: failed to get key from keystore", __func__);

    return SignBlockWithKey(block, key);
}

bool CheckBlockSignature(const CBlock& block)
{
    if (block.IsProofOfWork())
        return block.vchBlockSig.empty();

    if (block.vchBlockSig.empty())
        return error("%s: vchBlockSig is empty!", __func__);

    /** Each block is signed by the private key of the input that is staked. This can be either zPIV or normal UTXO
     *  zPIV: Each zPIV has a keypair associated with it. The serial number is a hash of the public key.
     *  UTXO: The public key that signs must match the public key associated with the first utxo of the coinstake tx.
     */
    CPubKey pubkey;
    bool fzPIVStake = block.vtx[1].vin[0].IsZerocoinSpend();
    if (fzPIVStake) {
        libzerocoin::CoinSpend spend = TxInToZerocoinSpend(block.vtx[1].vin[0]);
        pubkey = spend.getPubKey();
    } else {
        txnouttype whichType;
        std::vector<valtype> vSolutions;
        const CTxOut& txout = block.vtx[1].vout[1];
        if (!Solver(txout.scriptPubKey, whichType, vSolutions))
            return false;
        if (whichType == TX_PUBKEY || whichType == TX_PUBKEYHASH) {
            valtype& vchPubKey = vSolutions[0];
            pubkey = CPubKey(vchPubKey);
        } else if (whichType == TX_COLDSTAKE) {
            // pick the public key from the P2CS input
            const CTxIn& txin = block.vtx[1].vin[0];
            int start = 1 + (int) *txin.scriptSig.begin(); // skip sig
            start += 1 + (int) *(txin.scriptSig.begin()+start); // skip flag
            pubkey = CPubKey(txin.scriptSig.begin()+start+1, txin.scriptSig.end());
        }
    }

    if (!pubkey.IsValid())
        return error("%s: invalid pubkey %s", __func__, HexStr(pubkey));

    return pubkey.Verify(block.GetHash(), block.vchBlockSig);
}
<|endoftext|>


<commit_before>// CZone Delta Correlation Prefetcher
// Computer Acvhitecture NTNU 2017
// Anders Liland and Adrian Ribe

#include <iostream>
#include <algorithm>
#include <iterator>
#include <list>
#include <map>
#include <stdint.h>
#include <string.h>
#include <vector>
#include <array>

#include "interface.hh"

#define BLOCK_SIZE 64 // Size of cache blocks (cache lines) in bytes.
#define MAX_QUEUE_SIZE 100 // Maximum number of pending prefetch requests.
#define MAX_PHYS_MEM_ADDR ((uint64_t)(256*1024*1024) - 1) // 268 435 455

using std::cout;
using std::endl;
using std::vector;

//const int DELTA_CORRELATION_SEQUENCE_LENGTH = 2;
//const int CZONE_SIZE = 64; // number of bytes in CZone
const int PREFETCH_DEGREE = 3;
const int GHB_LENGTH_MAX = 10;
const int CZoneMask = 3; // number of digits to mask away

static int Timestep = 0;

enum State{CZone,pushGHB, traverse, prefetch };

struct GHBEntry{
    GHBEntry();
    GHBEntry(Addr mem_addr, int delta);
    Addr mem_addr, pc;
    int delta, key_first, key_second;
    GHBEntry *next, *prev; // pointers used to make a linked list inside each CZone
};
GHBEntry::GHBEntry() : mem_addr(0), pc(0), delta(0), next(NULL), prev(NULL){}
GHBEntry::GHBEntry(Addr mem_addr, int delta) : mem_addr(mem_addr), pc(0),delta(delta), next(NULL), prev(NULL){}

class GHBTable{
    public:
        std::vector<int> calculatePrefetchAddr(Addr mem_addr);
        Addr maskCZoneAddr(Addr mem_addr);
        State state;

    private:
        std::map<Addr, GHBEntry*> indexTable;
        std::map<Addr, GHBEntry*>::iterator indexTableIterator;
        std::list<GHBEntry> ghb_list;

        std::array<int, 2> key_register;
        std::array<int, 2> compare_register;

        std::vector<int> delta_buffer;
};

static GHBTable * table;

// Mask the 'CZoneMask' MSB of mem_addr
Addr GHBTable::maskCZoneAddr(Addr mem_addr){
    // mem_addr is 28 bit
    // return mem_addr >> (ADDR_BITWIDTH - CZoneMask)
    return mem_addr/(10*CZoneMask);
}

std::vector<int> GHBTable::calculatePrefetchAddr(Addr mem_addr){
    Addr CZoneTag;
    GHBEntry *CZoneHead = NULL;
    GHBEntry *entry = new GHBEntry();
    delta_buffer.clear(); // remove all values from previous calulation
    ghb_list.clear();
    while(true){
    switch (state) {

        // Check IndexTable for ZCone tag, and add to list if not pressent.
        case CZone:
            Timestep++;
            cout << "\n\n" << endl;
            cout << "TIMESTEP\t" << Timestep << endl;
            CZoneTag = maskCZoneAddr(mem_addr); // mask CZone tag
            indexTableIterator = indexTable.find(CZoneTag);
            if (indexTableIterator != indexTable.end()){ // CZone tag found in Index Table
                    //CZoneTag = indexTableIterator->first;
                    CZoneHead = indexTableIterator->second; // ptr to newest element in same CZone in GHB
                    //cout << "Found CZoneTag: " << CZoneTag << " *CZoneHead: " << CZoneHead << " CZoneHead->mem_addr: " << CZoneHead->mem_addr << endl;
            }else{ // tag not found
                CZoneHead = entry;
                CZoneHead->mem_addr = mem_addr;
                indexTable.insert(std::pair<Addr, GHBEntry*>(CZoneTag, CZoneHead));
                //cout << "CZoneTag not found, add new: " << "CZoneTag: " << CZoneTag << " *CZoneHead: " << CZoneHead << " CZoneHead->mem_addr: " << CZoneHead->mem_addr << endl;
            }
            state = pushGHB;
        break;

        // Add miss addr to GHB list, calculate delta and add miss addr to Correlation Key Register
        case pushGHB:
            entry->mem_addr = mem_addr;
            entry->delta = mem_addr - CZoneHead->mem_addr;
            entry->next = CZoneHead;
            entry->prev = NULL;
            cout << "Addr: " <<  entry->mem_addr << " Delta: " << entry->delta<< endl;
            //cout << "mem_addr: " << entry->mem_addr << " Delta: " << entry->delta << " struct addr: " << entry << endl;
            key_register[1] = key_register[0];
            key_register[0] = entry->delta;
            cout << "key_register[0] = " << key_register[0] << endl;
            cout << "key_register[1] = " << key_register[1] << endl;
            //update value in Index prt Table
            CZoneHead->prev = entry;
            CZoneHead = entry; // make new entry top of its CZone
            indexTableIterator->second = entry; // update ptr in map to point to newest emelent in CZone
            //cout << "Update Index Table: CZoneTag " << CZoneTag << " *CZoneHead: " << CZoneHead << " CZoneHead->mem_addr: " << CZoneHead->mem_addr << endl;
            indexTable.insert(std::pair<Addr, GHBEntry*>(CZoneTag, CZoneHead));
            ghb_list.push_front(*entry);

            // TODO: figure out why ghb_list is poped every time?
            cout << "GHB size " << ghb_list.size() << endl;
            if (ghb_list.size() >= GHB_LENGTH_MAX){ // ghb_list is a FIFO. Pop end when list is too long.
                //cout << "popGHB: " << ghb_list.back().mem_addr << endl;
                //ghb_list.pop_back();
            }
            state = traverse;
        break;
        case traverse:
        {
            // Print GHB list
            cout << "GHB:" << endl;
            for (std::list<GHBEntry>::const_iterator iterator = ghb_list.begin(), end = ghb_list.end(); iterator != end; ++iterator) {
                cout << "Mem_addr: " << iterator->mem_addr << " Delta: " << iterator->delta  << " CZoneTag: " <<  endl;
            }

            //traverse GHB and add deltas to Comparison Register
            std::list<GHBEntry>::iterator i = ghb_list.begin();
            std::advance(i,1); // advance itterator two elements from head of list

            // Traverse GHB backward, add deltas to Comparison register.
            for(std::list<GHBEntry>::iterator it = i; it != ghb_list.end(); it++){
                compare_register[1] = compare_register[0];
                compare_register[0] = it->delta;

                if(compare_register[0] == key_register[0] && compare_register[1] == key_register[1] && it->mem_addr != mem_addr ){ //correlation hits
                    state = prefetch;
                }
            }

            auto index = delta_buffer.begin();
            delta_buffer.insert(index, compare_register[1]);

            if( state == prefetch){ // continue to prefetch case
                cout << "Correlation Hit " << endl;
                break;
            }else{ // not prefetch for this miss address
                state = CZone;
                delta_buffer.clear();
                return delta_buffer; // return vector without any elements
            }

        }
        case prefetch:
            cout << "prefetch " << endl;
            state = CZone;
            return delta_buffer;
    } // switch
} // while
}

// --------- PREFETCH SIMULATED FUNCTIONS ------------------------
void prefetch_init(void){
    std::cout << "prefetch_init" << std::endl;
    table = new GHBTable;
    GHBEntry *entry2 = new GHBEntry();
    std::list<GHBEntry> ghb_list;
    ghb_list.clear();
    cout << "init ghb size " << ghb_list.size() << endl;
    ghb_list.push_front(*entry2);
    cout << "init ghb size " << ghb_list.size() << endl;

}

void prefetch_access(AccessStat stat){
    Addr pf_addr = 0, mem_addr = stat.mem_addr;
    std::vector<int> temp_delta_buffer;
    if(stat.miss){ //calculate prefetch address only on miss

        temp_delta_buffer = table->calculatePrefetchAddr(stat.mem_addr);
        if ( temp_delta_buffer.empty() ) {
            cout << "Delta buffer is empty. No delta correlation found for miss addr: " << stat.mem_addr << endl;
        } else {
            //temp_delta_buffer.erase(temp_delta_buffer.begin(),temp_delta_buffer.begin()+2); // remove two first deltas, according to algorithm
            int delta_buffer_size = temp_delta_buffer.size();
            cout << "Delta buffer size " << delta_buffer_size << endl;

            // DEBUG: print all deltas in vector
            int j = 0;
            for(auto val: temp_delta_buffer){
                cout << "temp_delta_buffer[" << j << "]: " << temp_delta_buffer[j] << endl;
                j++;
            }

            for(int i = 0; i < (PREFETCH_DEGREE && delta_buffer_size); i++){
                pf_addr = mem_addr + temp_delta_buffer[i];
                if(pf_addr < MAX_PHYS_MEM_ADDR){
                    cout << "Issue prefetch for address: " << pf_addr << endl;
                    //issue_prefetch( pf_addr );
                }else{
                    cout << "Not issuing prefetch" << endl;
                }
                mem_addr = pf_addr; // The prefetch addresses are cumulative
            }
        }

    }
}

void prefetch_complete(Addr addr){
    cout << "prefetch_complete" << endl;
}

int main( ) {
    AccessStat stat;
    prefetch_init();

    int pc[7] = {1,2,3,4,5,6,7};
    int miss_addresses[7] = {1147,1149,1154,1156,1158,1163,1165};
    for (int i = 0; i < 7; i++ ){
        stat.pc = pc[i];
        stat.mem_addr = miss_addresses[i];
        stat.time = 1;
        stat.miss = 1;
        prefetch_access(stat);
    }

    prefetch_complete(stat.mem_addr);
    return 0;
}
<commit_msg>presumably working prefetcher<commit_after>// CZone Delta Correlation Prefetcher
// Computer Acvhitecture NTNU 2017
// Anders Liland and Adrian Ribe

#include <iostream>
#include <algorithm>
#include <iterator>
#include <list>
#include <map>
#include <stdint.h>
#include <string.h>
#include <vector>
#include <array>

#include "interface.hh"

#define BLOCK_SIZE 64 // Size of cache blocks (cache lines) in bytes.
#define MAX_QUEUE_SIZE 100 // Maximum number of pending prefetch requests.
#define MAX_PHYS_MEM_ADDR ((uint64_t)(256*1024*1024) - 1) // 268 435 455

using std::cout;
using std::endl;
using std::vector;

//const int DELTA_CORRELATION_SEQUENCE_LENGTH = 2;
//const int CZONE_SIZE = 64; // number of bytes in CZone
const int PREFETCH_DEGREE = 5;
const int GHB_LENGTH_MAX = 20;
const int CZoneMask = 3; // number of digits to mask away

static int Timestep = 0;

enum State{CZone,pushGHB, traverse, prefetch };

struct GHBEntry{
    GHBEntry();
    GHBEntry(Addr mem_addr, int delta);
    Addr mem_addr, pc;
    int delta, key_first, key_second;
    GHBEntry *next, *prev; // pointers used to make a linked list inside each CZone
};
GHBEntry::GHBEntry() : mem_addr(0), pc(0), delta(0), next(NULL), prev(NULL){}
GHBEntry::GHBEntry(Addr mem_addr, int delta) : mem_addr(mem_addr), pc(0),delta(delta), next(NULL), prev(NULL){}

class GHBTable{
    public:
        std::vector<int> calculatePrefetchAddr(Addr mem_addr);
        Addr maskCZoneAddr(Addr mem_addr);
        State state;

    private:

        static int GHBNumberOfEntries;
        std::map<Addr, GHBEntry*> indexTable;
        std::map<Addr, GHBEntry*>::iterator indexTableIterator;

        std::list<GHBEntry> ghb_list;

        std::array<int, 2> key_register;
        std::array<int, 2> compare_register;

        std::vector<int> delta_buffer;
};

int GHBTable::GHBNumberOfEntries = 0;

static GHBTable * table;

// Mask the 'CZoneMask' MSB of mem_addr
Addr GHBTable::maskCZoneAddr(Addr mem_addr){
    // mem_addr is 28 bit
    // return mem_addr >> (ADDR_BITWIDTH - CZoneMask)
    return mem_addr/(10*CZoneMask);
}

std::vector<int> GHBTable::calculatePrefetchAddr(Addr mem_addr){
    Addr CZoneTag;
    GHBEntry *CZoneHead = NULL;
    GHBEntry *entry = new GHBEntry();
    delta_buffer.clear();

    while(true){
    switch (state) {

        // Check IndexTable for ZCone tag, and add to list if not pressent.
        case CZone:
            Timestep++;
            cout << "\n\n" << endl;
            cout << "TIMESTEP\t" << Timestep << endl;
            CZoneTag = maskCZoneAddr(mem_addr); // mask CZone tag
            indexTableIterator = indexTable.find(CZoneTag);
            if (indexTableIterator != indexTable.end()){ // CZone tag found in Index Table
                    //CZoneTag = indexTableIterator->first;
                    CZoneHead = indexTableIterator->second; // ptr to newest element in same CZone in GHB
                    //cout << "Found CZoneTag: " << CZoneTag << " *CZoneHead: " << CZoneHead << " CZoneHead->mem_addr: " << CZoneHead->mem_addr << endl;
            }else{ // tag not found
                CZoneHead = entry;
                CZoneHead->mem_addr = mem_addr;
                indexTable.insert(std::pair<Addr, GHBEntry*>(CZoneTag, CZoneHead));
                //cout << "CZoneTag not found, add new: " << "CZoneTag: " << CZoneTag << " *CZoneHead: " << CZoneHead << " CZoneHead->mem_addr: " << CZoneHead->mem_addr << endl;
            }
            state = pushGHB;
        break;

        // Add miss addr to GHB list, calculate delta and add miss addr to Correlation Key Register
        case pushGHB:
            entry->mem_addr = mem_addr;
            entry->delta = mem_addr - CZoneHead->mem_addr;
            entry->next = CZoneHead;
            entry->prev = NULL;
            cout << "Addr: " <<  entry->mem_addr << " Delta: " << entry->delta<< endl;
            //cout << "mem_addr: " << entry->mem_addr << " Delta: " << entry->delta << " struct addr: " << entry << endl;
            key_register[1] = key_register[0];
            key_register[0] = entry->delta;
            cout << "key_register[0] = " << key_register[0] << endl;
            cout << "key_register[1] = " << key_register[1] << endl;
            //update value in Index prt Table
            CZoneHead->prev = entry;
            CZoneHead = entry; // make new entry top of its CZone
            indexTableIterator->second = entry; // update ptr in map to point to newest emelent in CZone
            //cout << "Update Index Table: CZoneTag " << CZoneTag << " *CZoneHead: " << CZoneHead << " CZoneHead->mem_addr: " << CZoneHead->mem_addr << endl;
            indexTable.insert(std::pair<Addr, GHBEntry*>(CZoneTag, CZoneHead));
            ghb_list.push_front(*entry);
            GHBNumberOfEntries++;

            if (GHBNumberOfEntries > GHB_LENGTH_MAX){ // ghb_list is a FIFO. Pop end when list is too long.
                ghb_list.pop_back();
            }
            state = traverse;
        break;
        case traverse:
        {
            // Print GHB list
            cout << "GHB:" << endl;
            for (std::list<GHBEntry>::const_iterator iterator = ghb_list.begin(), end = ghb_list.end(); iterator != end; ++iterator) {
                cout << "Mem_addr: " << iterator->mem_addr << " Delta: " << iterator->delta <<  endl;
            }

            //traverse GHB and add deltas to Comparison Register
            std::list<GHBEntry>::iterator i = ghb_list.begin();
            std::advance(i,1); // advance itterator two elements from head of list

            // Traverse GHB from head to tail (new to old), add deltas to Comparison register.
            for(std::list<GHBEntry>::iterator it = i; it != ghb_list.end(); it++){
                compare_register[1] = compare_register[0];
                compare_register[0] = it->delta;
                auto index = delta_buffer.begin();
                delta_buffer.insert(index, compare_register[1]);

                if(compare_register[0] == key_register[0] && compare_register[1] == key_register[1] && it->mem_addr != mem_addr ){ //correlation hits
                    state = prefetch;
                }
            }

            if( state == prefetch){ // continue to prefetch case
                cout << "Correlation Hit " << endl;
                break;
            }else{ // not prefetch for this miss address
                state = CZone;
                delta_buffer.clear();
                return delta_buffer; // return vector without any elements
            }

        }
        case prefetch:
            cout << "prefetch " << endl;
            state = CZone;
            return delta_buffer;
    } // switch
} // while
}

// --------- PREFETCH SIMULATED FUNCTIONS ------------------------
void prefetch_init(void){
    std::cout << "prefetch_init" << std::endl;
    table = new GHBTable;

}

void prefetch_access(AccessStat stat){
    Addr pf_addr = 0, mem_addr = stat.mem_addr;
    std::vector<int> temp_delta_buffer;
    if(stat.miss){ //calculate prefetch address only on miss

        temp_delta_buffer = table->calculatePrefetchAddr(stat.mem_addr);
        if ( temp_delta_buffer.empty() ) {
            cout << "Delta buffer is empty. No delta correlation found for miss addr: " << stat.mem_addr << endl;
        } else {
            //temp_delta_buffer.erase(temp_delta_buffer.begin(),temp_delta_buffer.begin()+2); // remove two first deltas, according to algorithm
            int delta_buffer_size = temp_delta_buffer.size();
            cout << "Delta buffer size " << delta_buffer_size << endl;

            // DEBUG: print all deltas in vector
            int j = 0;
            for(auto val: temp_delta_buffer){
                cout << "temp_delta_buffer[" << j << "]: " << temp_delta_buffer[j] << endl;
                j++;
            }
            for(int i = 0; i < PREFETCH_DEGREE; i++){
                pf_addr = mem_addr + temp_delta_buffer[i];
                if(pf_addr < MAX_PHYS_MEM_ADDR){
                    cout << "Issue prefetch for address: " << pf_addr << endl;
                    //issue_prefetch( pf_addr );
                }else{
                    cout << "Not issuing prefetch" << endl;
                }
                mem_addr = pf_addr; // The prefetch addresses are cumulative
            }
        }

    }
}

void prefetch_complete(Addr addr){
    cout << "prefetch_complete" << endl;
}

int main( ) {
    AccessStat stat;
    prefetch_init();

    int pc[7] = {1,2,3,4,5,6,7};
    int miss_addresses[7] = {1147,1149,1154,1156,1158,1163,1165};
    for (int i = 0; i < 7; i++ ){
        stat.pc = pc[i];
        stat.mem_addr = miss_addresses[i];
        stat.time = 1;
        stat.miss = 1;
        prefetch_access(stat);
    }

    prefetch_complete(stat.mem_addr);
    return 0;
}
<|endoftext|>


<commit_before>/*
 Copyright (c) 2010, The Barbarian Group
 All rights reserved.

 Redistribution and use in source and binary forms, with or without modification, are permitted provided that
 the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this list of conditions and
	the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
	the following disclaimer in the documentation and/or other materials provided with the distribution.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
*/

#include "cinder/Cinder.h"
#include "cinder/Capture.h"
#if defined( CINDER_MAC ) || defined( CINDER_COCOA_TOUCH_DEVICE )
	#import "cinder/CaptureImplAvFoundation.h"
	typedef CaptureImplAvFoundation	CapturePlatformImpl;
#elif defined( CINDER_COCOA_TOUCH_SIMULATOR )
	#include "cinder/CaptureImplCocoaDummy.h"
	typedef CaptureImplCocoaDummy	CapturePlatformImpl;
#elif defined( CINDER_MSW )
	#include "cinder/CaptureImplDirectShow.h"
	typedef cinder::CaptureImplDirectShow	CapturePlatformImpl;
#endif

#include <set>
using namespace std;

namespace cinder {

const vector<Capture::DeviceRef>& Capture::getDevices( bool forceRefresh )
{
#if defined( CINDER_COCOA )
	return [CapturePlatformImpl getDevices:forceRefresh];
#else
	return CapturePlatformImpl::getDevices( forceRefresh );
#endif
}

Capture::DeviceRef Capture::findDeviceByName( const string &name )
{
	const vector<DeviceRef> &devices = getDevices();
	for( vector<DeviceRef>::const_iterator deviceIt = devices.begin(); deviceIt != devices.end(); ++deviceIt ) {
		if( (*deviceIt)->getName() == name )
			return *deviceIt;
	}

	return DeviceRef(); // failed - return "null" device
}

Capture::DeviceRef Capture::findDeviceByNameContains( const string &nameFragment )
{
	const vector<DeviceRef> &devices = getDevices();
	for( vector<DeviceRef>::const_iterator deviceIt = devices.begin(); deviceIt != devices.end(); ++deviceIt ) {
		if( (*deviceIt)->getName().find( nameFragment ) != std::string::npos )
			return *deviceIt;
	}

	return DeviceRef();
}

Capture::Capture( int32_t width, int32_t height, const DeviceRef device )
{
#if defined( CINDER_COCOA )
	mImpl = [[::CapturePlatformImpl alloc] initWithDevice:device width:width height:height];
#else
	mImpl = new CapturePlatformImpl( width, height, device );
#endif
}

Capture::~Capture()
{
#if defined( CINDER_COCOA )
	[((::CapturePlatformImpl*)mImpl) release];
#else
	delete mImpl;
#endif
}

void Capture::start()
{
#if defined( CINDER_COCOA )
	[mImpl startCapture];
#else
	mImpl->start();
#endif
}

void Capture::stop()
{
#if defined( CINDER_COCOA )
	[mImpl stopCapture];
#else
	mImpl->stop();
#endif
}

bool Capture::isCapturing()
{
#if defined( CINDER_COCOA )
	return [mImpl isCapturing];
#else
	return mImpl->isCapturing();
#endif
}

bool Capture::checkNewFrame() const
{
#if defined( CINDER_COCOA )
	return [mImpl checkNewFrame];
#else
	return mImpl->checkNewFrame();
#endif
}

Surface8uRef Capture::getSurface() const
{
#if defined( CINDER_COCOA )
	return [mImpl getCurrentFrame];
#else
	return mImpl->getSurface();
#endif
}

int32_t	Capture::getWidth() const {
#if defined( CINDER_COCOA )
	return [mImpl getWidth];
#else
	return mImpl->getWidth();
#endif
}

int32_t	Capture::getHeight() const {
#if defined( CINDER_COCOA )
	return [mImpl getHeight];
#else
	return mImpl->getHeight();
#endif
}

const Capture::DeviceRef Capture::getDevice() const {
#if defined( CINDER_COCOA )
	return [mImpl getDevice];
#else
	return mImpl->getDevice();
#endif
}

} //namespace cinder
<commit_msg>use range based for on getDevices() iteration<commit_after>/*
 Copyright (c) 2010, The Barbarian Group
 All rights reserved.

 Redistribution and use in source and binary forms, with or without modification, are permitted provided that
 the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this list of conditions and
	the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
	the following disclaimer in the documentation and/or other materials provided with the distribution.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
*/

#include "cinder/Cinder.h"
#include "cinder/Capture.h"
#if defined( CINDER_MAC ) || defined( CINDER_COCOA_TOUCH_DEVICE )
	#import "cinder/CaptureImplAvFoundation.h"
	typedef CaptureImplAvFoundation	CapturePlatformImpl;
#elif defined( CINDER_COCOA_TOUCH_SIMULATOR )
	#include "cinder/CaptureImplCocoaDummy.h"
	typedef CaptureImplCocoaDummy	CapturePlatformImpl;
#elif defined( CINDER_MSW )
	#include "cinder/CaptureImplDirectShow.h"
	typedef cinder::CaptureImplDirectShow	CapturePlatformImpl;
#endif

#include <set>
using namespace std;

namespace cinder {

const vector<Capture::DeviceRef>& Capture::getDevices( bool forceRefresh )
{
#if defined( CINDER_COCOA )
	return [CapturePlatformImpl getDevices:forceRefresh];
#else
	return CapturePlatformImpl::getDevices( forceRefresh );
#endif
}

Capture::DeviceRef Capture::findDeviceByName( const string &name )
{
	for( const auto &dev : getDevices() ) {
		if( dev->getName() == name )
			return dev;
	}

	return DeviceRef(); // failed - return "null" device
}

Capture::DeviceRef Capture::findDeviceByNameContains( const string &nameFragment )
{
	for( const auto &dev : getDevices() ) {
		if( dev->getName().find( nameFragment ) != std::string::npos )
			return dev;
	}

	return DeviceRef();
}

Capture::Capture( int32_t width, int32_t height, const DeviceRef device )
{
#if defined( CINDER_COCOA )
	mImpl = [[::CapturePlatformImpl alloc] initWithDevice:device width:width height:height];
#else
	mImpl = new CapturePlatformImpl( width, height, device );
#endif
}

Capture::~Capture()
{
#if defined( CINDER_COCOA )
	[((::CapturePlatformImpl*)mImpl) release];
#else
	delete mImpl;
#endif
}

void Capture::start()
{
#if defined( CINDER_COCOA )
	[mImpl startCapture];
#else
	mImpl->start();
#endif
}

void Capture::stop()
{
#if defined( CINDER_COCOA )
	[mImpl stopCapture];
#else
	mImpl->stop();
#endif
}

bool Capture::isCapturing()
{
#if defined( CINDER_COCOA )
	return [mImpl isCapturing];
#else
	return mImpl->isCapturing();
#endif
}

bool Capture::checkNewFrame() const
{
#if defined( CINDER_COCOA )
	return [mImpl checkNewFrame];
#else
	return mImpl->checkNewFrame();
#endif
}

Surface8uRef Capture::getSurface() const
{
#if defined( CINDER_COCOA )
	return [mImpl getCurrentFrame];
#else
	return mImpl->getSurface();
#endif
}

int32_t	Capture::getWidth() const {
#if defined( CINDER_COCOA )
	return [mImpl getWidth];
#else
	return mImpl->getWidth();
#endif
}

int32_t	Capture::getHeight() const {
#if defined( CINDER_COCOA )
	return [mImpl getHeight];
#else
	return mImpl->getHeight();
#endif
}

const Capture::DeviceRef Capture::getDevice() const {
#if defined( CINDER_COCOA )
	return [mImpl getDevice];
#else
	return mImpl->getDevice();
#endif
}

} //namespace cinder
<|endoftext|>


<commit_before><commit_msg>update<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// This code glues the RLZ library DLL with Chrome. It allows Chrome to work
// with or without the DLL being present. If the DLL is not present the
// functions do nothing and just return false.

#include "chrome/browser/rlz/rlz.h"

#include <algorithm>

#include <windows.h>
#include <process.h>

#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/task.h"
#include "base/thread.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/env_vars.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#include "chrome/installer/util/google_update_settings.h"

namespace {

// The maximum length of an access points RLZ in wide chars.
const DWORD kMaxRlzLength = 64;

// The RLZ is a DLL that might not be present in the system. We load it
// as needed but never unload it.
volatile HMODULE rlz_dll = NULL;

enum {
  ACCESS_VALUES_STALE,      // Possibly new values available.
  ACCESS_VALUES_FRESH       // The cached values are current.
};

// Tracks if we have tried and succeeded sending the ping. This helps us
// decide if we need to refresh the some cached strings.
volatile int access_values_state = ACCESS_VALUES_STALE;

extern "C" {
typedef bool (*RecordProductEventFn)(RLZTracker::Product product,
                                     RLZTracker::AccessPoint point,
                                     RLZTracker::Event event_id,
                                     void* reserved);

typedef bool (*GetAccessPointRlzFn)(RLZTracker::AccessPoint point,
                                    wchar_t* rlz,
                                    DWORD rlz_size,
                                    void* reserved);

typedef bool (*ClearAllProductEventsFn)(RLZTracker::Product product,
                                        void* reserved);

typedef bool (*SendFinancialPingFn)(RLZTracker::Product product,
                                    RLZTracker::AccessPoint* access_points,
                                    const WCHAR* product_signature,
                                    const WCHAR* product_brand,
                                    const WCHAR* product_id,
                                    const WCHAR* product_lang,
                                    bool exclude_id,
                                    void* reserved);
}  // extern "C".

RecordProductEventFn record_event = NULL;
GetAccessPointRlzFn get_access_point = NULL;
ClearAllProductEventsFn clear_all_events = NULL;
SendFinancialPingFn send_ping = NULL;

template <typename FuncT>
FuncT WireExport(HMODULE module, const char* export_name) {
  if (!module)
    return NULL;
  void* entry_point = ::GetProcAddress(module, export_name);
  return reinterpret_cast<FuncT>(entry_point);
}

HMODULE LoadRLZLibraryInternal(int directory_key) {
  FilePath rlz_path;
  if (!PathService::Get(directory_key, &rlz_path))
    return NULL;
  rlz_path = rlz_path.AppendASCII("rlz.dll");
  return ::LoadLibraryW(rlz_path.value().c_str());
}

bool LoadRLZLibrary(int directory_key) {
  rlz_dll = LoadRLZLibraryInternal(directory_key);
  if (!rlz_dll) {
    // As a last resort we can try the EXE directory.
    if (directory_key != base::DIR_EXE)
      rlz_dll = LoadRLZLibraryInternal(base::DIR_EXE);
  }
  if (rlz_dll) {
    record_event =
        WireExport<RecordProductEventFn>(rlz_dll, "RecordProductEvent");
    get_access_point =
        WireExport<GetAccessPointRlzFn>(rlz_dll, "GetAccessPointRlz");
    clear_all_events =
        WireExport<ClearAllProductEventsFn>(rlz_dll, "ClearAllProductEvents");
    send_ping =
        WireExport<SendFinancialPingFn>(rlz_dll, "SendFinancialPing");
    return (record_event && get_access_point && clear_all_events && send_ping);
  }
  return false;
}

bool SendFinancialPing(const wchar_t* brand, const wchar_t* lang,
                       const wchar_t* referral, bool exclude_id) {
  RLZTracker::AccessPoint points[] = {RLZTracker::CHROME_OMNIBOX,
                                      RLZTracker::CHROME_HOME_PAGE,
                                      RLZTracker::NO_ACCESS_POINT};
  if (!send_ping)
    return false;
  return send_ping(RLZTracker::CHROME, points, L"chrome", brand, referral, lang,
                   exclude_id, NULL);
}

// This class leverages the AutocompleteEditModel notification to know when
// the user first interacted with the omnibox and set a global accordingly.
class OmniBoxUsageObserver : public NotificationObserver {
 public:
  OmniBoxUsageObserver() {
    registrar_.Add(this, NotificationType::OMNIBOX_OPENED_URL,
                   NotificationService::AllSources());
    omnibox_used_ = false;
    DCHECK(!instance_);
    instance_ = this;
  }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    // Try to record event now, else set the flag to try later when we
    // attempt the ping.
    if (!RLZTracker::RecordProductEvent(RLZTracker::CHROME,
                                        RLZTracker::CHROME_OMNIBOX,
                                        RLZTracker::FIRST_SEARCH))
      omnibox_used_ = true;
    delete this;
  }

  static bool used() {
    return omnibox_used_;
  }

  // Deletes the single instance of OmniBoxUsageObserver.
  static void DeleteInstance() {
    delete instance_;
  }

 private:
  // Dtor is private so the object cannot be created on the stack.
  ~OmniBoxUsageObserver() {
    instance_ = NULL;
  }

  static bool omnibox_used_;

  // There should only be one instance created at a time, and instance_ points
  // to that instance.
  // NOTE: this is only non-null for the amount of time it is needed. Once the
  // instance_ is no longer needed (or Chrome is exiting), this is null.
  static OmniBoxUsageObserver* instance_;

  NotificationRegistrar registrar_;
};

bool OmniBoxUsageObserver::omnibox_used_ = false;
OmniBoxUsageObserver* OmniBoxUsageObserver::instance_ = NULL;

// This task is run in the file thread, so to not block it for a long time
// we use a throwaway thread to do the blocking url request.
class DailyPingTask : public Task {
 public:
  virtual ~DailyPingTask() {
  }
  virtual void Run() {
    // We use a transient thread because we have no guarantees about
    // how long the RLZ lib can block us.
    _beginthread(PingNow, 0, NULL);
  }

 private:
  // Causes a ping to the server using WinInet. There is logic inside RLZ dll
  // that throttles it to a maximum of one ping per day.
  static void _cdecl PingNow(void*) {
    std::wstring lang;
    GoogleUpdateSettings::GetLanguage(&lang);
    if (lang.empty())
      lang = L"en";
    std::wstring brand;
    GoogleUpdateSettings::GetBrand(&brand);
    std::wstring referral;
    GoogleUpdateSettings::GetReferral(&referral);
    if (SendFinancialPing(brand.c_str(), lang.c_str(), referral.c_str(),
                          is_organic(brand))) {
      access_values_state = ACCESS_VALUES_STALE;
      GoogleUpdateSettings::ClearReferral();
    }
  }

  // Organic brands all start with GG, such as GGCM.
  static bool is_organic(const std::wstring& brand) {
    return (brand.size() < 2) ? false : (brand.substr(0,2) == L"GG");
  }

};

// Performs late RLZ initialization and RLZ event recording for chrome.
// This task needs to run on the UI thread.
class DelayedInitTask : public Task {
 public:
  explicit DelayedInitTask(int directory_key, bool first_run)
      : directory_key_(directory_key), first_run_(first_run) {
  }
  virtual ~DelayedInitTask() {
  }
  virtual void Run() {
    // For non-interactive tests we don't do the rest of the initialization
    // because sometimes the very act of loading the dll causes QEMU to crash.
    if (::GetEnvironmentVariableW(env_vars::kHeadless, NULL, 0))
      return;
    // For organic brandcodes do not use rlz at all. Empty brandcode usually
    // means a chromium install. This is ok.
    std::wstring brand;
    GoogleUpdateSettings::GetBrand(&brand);
    if (is_strict_organic(brand))
      return;

    if (!LoadRLZLibrary(directory_key_))
      return;
    // Do the initial event recording if is the first run or if we have an
    // empty rlz which means we haven't got a chance to do it.
    std::wstring omnibox_rlz;
    RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &omnibox_rlz);

    if (first_run_ || omnibox_rlz.empty()) {
      // Record the installation of chrome.
      RLZTracker::RecordProductEvent(RLZTracker::CHROME,
                                     RLZTracker::CHROME_OMNIBOX,
                                     RLZTracker::INSTALL);
      RLZTracker::RecordProductEvent(RLZTracker::CHROME,
                                     RLZTracker::CHROME_HOME_PAGE,
                                     RLZTracker::INSTALL);
      // Record if google is the initial search provider.
      if (IsGoogleDefaultSearch()) {
        RLZTracker::RecordProductEvent(RLZTracker::CHROME,
                                       RLZTracker::CHROME_OMNIBOX,
                                       RLZTracker::SET_TO_GOOGLE);
      }
      // Record first user interaction with the omnibox.
      if (OmniBoxUsageObserver::used()) {
        RLZTracker::RecordProductEvent(RLZTracker::CHROME,
                                       RLZTracker::CHROME_OMNIBOX,
                                       RLZTracker::FIRST_SEARCH);
      }
    }
    // Schedule the daily RLZ ping.
    base::Thread* thread = g_browser_process->file_thread();
    if (thread)
      thread->message_loop()->PostTask(FROM_HERE, new DailyPingTask());
  }

 private:
  bool IsGoogleDefaultSearch() {
    if (!g_browser_process)
      return false;
    FilePath user_data_dir;
    if (!PathService::Get(chrome::DIR_USER_DATA, &user_data_dir))
      return false;
    ProfileManager* profile_manager = g_browser_process->profile_manager();
    Profile* profile = profile_manager->GetDefaultProfile(user_data_dir);
    if (!profile)
      return false;
    const TemplateURL* url_template =
        profile->GetTemplateURLModel()->GetDefaultSearchProvider();
    if (!url_template)
      return false;
    const TemplateURLRef* urlref = url_template->url();
    if (!urlref)
      return false;
    return urlref->HasGoogleBaseURLs();
  }

  static bool is_strict_organic(const std::wstring& brand) {
    static const wchar_t* kBrands[] = {
        L"CHFO", L"CHFT", L"CHMA", L"CHMB", L"CHME", L"CHMF", L"CHMG", L"CHMH",
        L"CHMI", L"CHMQ", L"CHMV", L"CHNB", L"CHNC", L"CHNG", L"CHNH", L"CHNI",
        L"CHOA", L"CHOB", L"CHOC", L"CHON", L"CHOO", L"CHOP", L"CHOQ", L"CHOR",
        L"CHOS", L"CHOT", L"CHOU", L"CHOX", L"CHOY", L"CHOZ", L"CHPD", L"CHPE",
        L"CHPF", L"CHPG", L"EUBB", L"EUBC", L"GGLA", L"GGLS" };
    const wchar_t** end = &kBrands[arraysize(kBrands)];
    const wchar_t** found = std::find(&kBrands[0], end, brand);
    if (found != end)
      return true;
    if (StartsWith(brand, L"EUB", true) || StartsWith(brand, L"EUC", true))
      return true;
    return false;
  }

  int directory_key_;
  bool first_run_;
  DISALLOW_IMPLICIT_CONSTRUCTORS(DelayedInitTask);
};

}  // namespace

bool RLZTracker::InitRlz(int directory_key) {
  return LoadRLZLibrary(directory_key);
}

bool RLZTracker::InitRlzDelayed(int directory_key, bool first_run, int delay) {
  // Maximum and minimum delay we would allow to be set through master
  // preferences. Somewhat arbitrary, may need to be adjusted in future.
  const int kMaxDelay = 200 * 1000;
  const int kMinDelay = 20 * 1000;

  delay *= 1000;
  delay = (delay < kMinDelay) ? kMinDelay : delay;
  delay = (delay > kMaxDelay) ? kMaxDelay : delay;

  if (!OmniBoxUsageObserver::used())
    new OmniBoxUsageObserver();

  // Schedule the delayed init items.
  MessageLoop::current()->PostDelayedTask(FROM_HERE,
      new DelayedInitTask(directory_key, first_run), delay);
  return true;
}

bool RLZTracker::RecordProductEvent(Product product, AccessPoint point,
                                    Event event) {
  return (record_event) ? record_event(product, point, event, NULL) : false;
}

bool RLZTracker::ClearAllProductEvents(Product product) {
  return (clear_all_events) ? clear_all_events(product, NULL) : false;
}

// We implement caching of the answer of get_access_point() if the request
// is for CHROME_OMNIBOX. If we had a successful ping, then we update the
// cached value.

bool RLZTracker::GetAccessPointRlz(AccessPoint point, std::wstring* rlz) {
  static std::wstring cached_ommibox_rlz;
  if (!get_access_point)
    return false;
  if ((CHROME_OMNIBOX == point) &&
      (access_values_state == ACCESS_VALUES_FRESH)) {
    *rlz = cached_ommibox_rlz;
    return true;
  }
  wchar_t str_rlz[kMaxRlzLength];
  if (!get_access_point(point, str_rlz, kMaxRlzLength, NULL))
    return false;
  if (CHROME_OMNIBOX == point) {
    access_values_state = ACCESS_VALUES_FRESH;
    cached_ommibox_rlz.assign(str_rlz);
  }
  *rlz = str_rlz;
  return true;
}

// static
void RLZTracker::CleanupRlz() {
  OmniBoxUsageObserver::DeleteInstance();
}
<commit_msg>Have rlz record first search event in a corner case<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// This code glues the RLZ library DLL with Chrome. It allows Chrome to work
// with or without the DLL being present. If the DLL is not present the
// functions do nothing and just return false.

#include "chrome/browser/rlz/rlz.h"

#include <algorithm>

#include <windows.h>
#include <process.h>

#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/task.h"
#include "base/thread.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/env_vars.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#include "chrome/installer/util/google_update_settings.h"

namespace {

// The maximum length of an access points RLZ in wide chars.
const DWORD kMaxRlzLength = 64;

// The RLZ is a DLL that might not be present in the system. We load it
// as needed but never unload it.
volatile HMODULE rlz_dll = NULL;

enum {
  ACCESS_VALUES_STALE,      // Possibly new values available.
  ACCESS_VALUES_FRESH       // The cached values are current.
};

// Tracks if we have tried and succeeded sending the ping. This helps us
// decide if we need to refresh the some cached strings.
volatile int access_values_state = ACCESS_VALUES_STALE;

extern "C" {
typedef bool (*RecordProductEventFn)(RLZTracker::Product product,
                                     RLZTracker::AccessPoint point,
                                     RLZTracker::Event event_id,
                                     void* reserved);

typedef bool (*GetAccessPointRlzFn)(RLZTracker::AccessPoint point,
                                    wchar_t* rlz,
                                    DWORD rlz_size,
                                    void* reserved);

typedef bool (*ClearAllProductEventsFn)(RLZTracker::Product product,
                                        void* reserved);

typedef bool (*SendFinancialPingFn)(RLZTracker::Product product,
                                    RLZTracker::AccessPoint* access_points,
                                    const WCHAR* product_signature,
                                    const WCHAR* product_brand,
                                    const WCHAR* product_id,
                                    const WCHAR* product_lang,
                                    bool exclude_id,
                                    void* reserved);
}  // extern "C".

RecordProductEventFn record_event = NULL;
GetAccessPointRlzFn get_access_point = NULL;
ClearAllProductEventsFn clear_all_events = NULL;
SendFinancialPingFn send_ping = NULL;

template <typename FuncT>
FuncT WireExport(HMODULE module, const char* export_name) {
  if (!module)
    return NULL;
  void* entry_point = ::GetProcAddress(module, export_name);
  return reinterpret_cast<FuncT>(entry_point);
}

HMODULE LoadRLZLibraryInternal(int directory_key) {
  FilePath rlz_path;
  if (!PathService::Get(directory_key, &rlz_path))
    return NULL;
  rlz_path = rlz_path.AppendASCII("rlz.dll");
  return ::LoadLibraryW(rlz_path.value().c_str());
}

bool LoadRLZLibrary(int directory_key) {
  rlz_dll = LoadRLZLibraryInternal(directory_key);
  if (!rlz_dll) {
    // As a last resort we can try the EXE directory.
    if (directory_key != base::DIR_EXE)
      rlz_dll = LoadRLZLibraryInternal(base::DIR_EXE);
  }
  if (rlz_dll) {
    record_event =
        WireExport<RecordProductEventFn>(rlz_dll, "RecordProductEvent");
    get_access_point =
        WireExport<GetAccessPointRlzFn>(rlz_dll, "GetAccessPointRlz");
    clear_all_events =
        WireExport<ClearAllProductEventsFn>(rlz_dll, "ClearAllProductEvents");
    send_ping =
        WireExport<SendFinancialPingFn>(rlz_dll, "SendFinancialPing");
    return (record_event && get_access_point && clear_all_events && send_ping);
  }
  return false;
}

bool SendFinancialPing(const wchar_t* brand, const wchar_t* lang,
                       const wchar_t* referral, bool exclude_id) {
  RLZTracker::AccessPoint points[] = {RLZTracker::CHROME_OMNIBOX,
                                      RLZTracker::CHROME_HOME_PAGE,
                                      RLZTracker::NO_ACCESS_POINT};
  if (!send_ping)
    return false;
  return send_ping(RLZTracker::CHROME, points, L"chrome", brand, referral, lang,
                   exclude_id, NULL);
}

// This class leverages the AutocompleteEditModel notification to know when
// the user first interacted with the omnibox and set a global accordingly.
class OmniBoxUsageObserver : public NotificationObserver {
 public:
  OmniBoxUsageObserver() {
    registrar_.Add(this, NotificationType::OMNIBOX_OPENED_URL,
                   NotificationService::AllSources());
    omnibox_used_ = false;
    DCHECK(!instance_);
    instance_ = this;
  }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    // Try to record event now, else set the flag to try later when we
    // attempt the ping.
    if (!RLZTracker::RecordProductEvent(RLZTracker::CHROME,
                                        RLZTracker::CHROME_OMNIBOX,
                                        RLZTracker::FIRST_SEARCH))
      omnibox_used_ = true;
    delete this;
  }

  static bool used() {
    return omnibox_used_;
  }

  // Deletes the single instance of OmniBoxUsageObserver.
  static void DeleteInstance() {
    delete instance_;
  }

 private:
  // Dtor is private so the object cannot be created on the stack.
  ~OmniBoxUsageObserver() {
    instance_ = NULL;
  }

  static bool omnibox_used_;

  // There should only be one instance created at a time, and instance_ points
  // to that instance.
  // NOTE: this is only non-null for the amount of time it is needed. Once the
  // instance_ is no longer needed (or Chrome is exiting), this is null.
  static OmniBoxUsageObserver* instance_;

  NotificationRegistrar registrar_;
};

bool OmniBoxUsageObserver::omnibox_used_ = false;
OmniBoxUsageObserver* OmniBoxUsageObserver::instance_ = NULL;

// This task is run in the file thread, so to not block it for a long time
// we use a throwaway thread to do the blocking url request.
class DailyPingTask : public Task {
 public:
  virtual ~DailyPingTask() {
  }
  virtual void Run() {
    // We use a transient thread because we have no guarantees about
    // how long the RLZ lib can block us.
    _beginthread(PingNow, 0, NULL);
  }

 private:
  // Causes a ping to the server using WinInet. There is logic inside RLZ dll
  // that throttles it to a maximum of one ping per day.
  static void _cdecl PingNow(void*) {
    std::wstring lang;
    GoogleUpdateSettings::GetLanguage(&lang);
    if (lang.empty())
      lang = L"en";
    std::wstring brand;
    GoogleUpdateSettings::GetBrand(&brand);
    std::wstring referral;
    GoogleUpdateSettings::GetReferral(&referral);
    if (SendFinancialPing(brand.c_str(), lang.c_str(), referral.c_str(),
                          is_organic(brand))) {
      access_values_state = ACCESS_VALUES_STALE;
      GoogleUpdateSettings::ClearReferral();
    }
  }

  // Organic brands all start with GG, such as GGCM.
  static bool is_organic(const std::wstring& brand) {
    return (brand.size() < 2) ? false : (brand.substr(0,2) == L"GG");
  }

};

// Performs late RLZ initialization and RLZ event recording for chrome.
// This task needs to run on the UI thread.
class DelayedInitTask : public Task {
 public:
  explicit DelayedInitTask(int directory_key, bool first_run)
      : directory_key_(directory_key), first_run_(first_run) {
  }
  virtual ~DelayedInitTask() {
  }
  virtual void Run() {
    // For non-interactive tests we don't do the rest of the initialization
    // because sometimes the very act of loading the dll causes QEMU to crash.
    if (::GetEnvironmentVariableW(env_vars::kHeadless, NULL, 0))
      return;
    // For organic brandcodes do not use rlz at all. Empty brandcode usually
    // means a chromium install. This is ok.
    std::wstring brand;
    GoogleUpdateSettings::GetBrand(&brand);
    if (is_strict_organic(brand))
      return;

    if (!LoadRLZLibrary(directory_key_))
      return;
    // Do the initial event recording if is the first run or if we have an
    // empty rlz which means we haven't got a chance to do it.
    std::wstring omnibox_rlz;
    RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &omnibox_rlz);

    if (first_run_ || omnibox_rlz.empty()) {
      // Record the installation of chrome.
      RLZTracker::RecordProductEvent(RLZTracker::CHROME,
                                     RLZTracker::CHROME_OMNIBOX,
                                     RLZTracker::INSTALL);
      RLZTracker::RecordProductEvent(RLZTracker::CHROME,
                                     RLZTracker::CHROME_HOME_PAGE,
                                     RLZTracker::INSTALL);
      // Record if google is the initial search provider.
      if (IsGoogleDefaultSearch()) {
        RLZTracker::RecordProductEvent(RLZTracker::CHROME,
                                       RLZTracker::CHROME_OMNIBOX,
                                       RLZTracker::SET_TO_GOOGLE);
      }
    }
    // Record first user interaction with the omnibox. We call this all the
    // time but the rlz lib should ingore all but the first one.
    if (OmniBoxUsageObserver::used()) {
      RLZTracker::RecordProductEvent(RLZTracker::CHROME,
                                     RLZTracker::CHROME_OMNIBOX,
                                     RLZTracker::FIRST_SEARCH);
    }
    // Schedule the daily RLZ ping.
    base::Thread* thread = g_browser_process->file_thread();
    if (thread)
      thread->message_loop()->PostTask(FROM_HERE, new DailyPingTask());
  }

 private:
  bool IsGoogleDefaultSearch() {
    if (!g_browser_process)
      return false;
    FilePath user_data_dir;
    if (!PathService::Get(chrome::DIR_USER_DATA, &user_data_dir))
      return false;
    ProfileManager* profile_manager = g_browser_process->profile_manager();
    Profile* profile = profile_manager->GetDefaultProfile(user_data_dir);
    if (!profile)
      return false;
    const TemplateURL* url_template =
        profile->GetTemplateURLModel()->GetDefaultSearchProvider();
    if (!url_template)
      return false;
    const TemplateURLRef* urlref = url_template->url();
    if (!urlref)
      return false;
    return urlref->HasGoogleBaseURLs();
  }

  static bool is_strict_organic(const std::wstring& brand) {
    static const wchar_t* kBrands[] = {
        L"CHFO", L"CHFT", L"CHMA", L"CHMB", L"CHME", L"CHMF", L"CHMG", L"CHMH",
        L"CHMI", L"CHMQ", L"CHMV", L"CHNB", L"CHNC", L"CHNG", L"CHNH", L"CHNI",
        L"CHOA", L"CHOB", L"CHOC", L"CHON", L"CHOO", L"CHOP", L"CHOQ", L"CHOR",
        L"CHOS", L"CHOT", L"CHOU", L"CHOX", L"CHOY", L"CHOZ", L"CHPD", L"CHPE",
        L"CHPF", L"CHPG", L"EUBB", L"EUBC", L"GGLA", L"GGLS" };
    const wchar_t** end = &kBrands[arraysize(kBrands)];
    const wchar_t** found = std::find(&kBrands[0], end, brand);
    if (found != end)
      return true;
    if (StartsWith(brand, L"EUB", true) || StartsWith(brand, L"EUC", true))
      return true;
    return false;
  }

  int directory_key_;
  bool first_run_;
  DISALLOW_IMPLICIT_CONSTRUCTORS(DelayedInitTask);
};

}  // namespace

bool RLZTracker::InitRlz(int directory_key) {
  return LoadRLZLibrary(directory_key);
}

bool RLZTracker::InitRlzDelayed(int directory_key, bool first_run, int delay) {
  // Maximum and minimum delay we would allow to be set through master
  // preferences. Somewhat arbitrary, may need to be adjusted in future.
  const int kMaxDelay = 200 * 1000;
  const int kMinDelay = 20 * 1000;

  delay *= 1000;
  delay = (delay < kMinDelay) ? kMinDelay : delay;
  delay = (delay > kMaxDelay) ? kMaxDelay : delay;

  if (!OmniBoxUsageObserver::used())
    new OmniBoxUsageObserver();

  // Schedule the delayed init items.
  MessageLoop::current()->PostDelayedTask(FROM_HERE,
      new DelayedInitTask(directory_key, first_run), delay);
  return true;
}

bool RLZTracker::RecordProductEvent(Product product, AccessPoint point,
                                    Event event) {
  return (record_event) ? record_event(product, point, event, NULL) : false;
}

bool RLZTracker::ClearAllProductEvents(Product product) {
  return (clear_all_events) ? clear_all_events(product, NULL) : false;
}

// We implement caching of the answer of get_access_point() if the request
// is for CHROME_OMNIBOX. If we had a successful ping, then we update the
// cached value.

bool RLZTracker::GetAccessPointRlz(AccessPoint point, std::wstring* rlz) {
  static std::wstring cached_ommibox_rlz;
  if (!get_access_point)
    return false;
  if ((CHROME_OMNIBOX == point) &&
      (access_values_state == ACCESS_VALUES_FRESH)) {
    *rlz = cached_ommibox_rlz;
    return true;
  }
  wchar_t str_rlz[kMaxRlzLength];
  if (!get_access_point(point, str_rlz, kMaxRlzLength, NULL))
    return false;
  if (CHROME_OMNIBOX == point) {
    access_values_state = ACCESS_VALUES_FRESH;
    cached_ommibox_rlz.assign(str_rlz);
  }
  *rlz = str_rlz;
  return true;
}

// static
void RLZTracker::CleanupRlz() {
  OmniBoxUsageObserver::DeleteInstance();
}
<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2011, Alexandru-Eugen Ichim
 *                      Willow Garage, Inc
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 */

#ifndef PCL_KEYPOINTS_IMPL_SMOOTHEDSURFACESKEYPOINT_H_
#define PCL_KEYPOINTS_IMPL_SMOOTHEDSURFACESKEYPOINT_H_

#include "pcl/keypoints/smoothed_surfaces_keypoint.h"
#include <pcl/kdtree/kdtree_flann.h>

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointT, typename PointNT> void
pcl::SmoothedSurfacesKeypoint<PointT, PointNT>::addSmoothedPointCloud (SmoothedSurfacesKeypoint<PointT, PointNT>::PointCloudTConstPtr &cloud,
                                                                       SmoothedSurfacesKeypoint<PointT, PointNT>::PointCloudNTConstPtr &normals,
                                                                       SmoothedSurfacesKeypoint<PointT, PointNT>::KdTreePtr &kdtree,
                                                                       float &scale)
{
  clouds_.push_back (cloud);
  cloud_normals_.push_back (normals);
  cloud_trees_.push_back (kdtree);
  scales_.push_back (std::pair<float, size_t> (scale, scales_.size ()));
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointT, typename PointNT> void
pcl::SmoothedSurfacesKeypoint<PointT, PointNT>::resetClouds ()
{
  clouds_.clear ();
  cloud_normals_.clear ();
  scales_.clear ();
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointT, typename PointNT> void
pcl::SmoothedSurfacesKeypoint<PointT, PointNT>::detectKeypoints (pcl::SmoothedSurfacesKeypoint<PointT, PointNT>::PointCloudT &output)
{
  // Calculate differences for each cloud
  std::vector<std::vector<float> > diffs (scales_.size ());

  // The cloud with the smallest scale has no differences
  std::vector<float> aux_diffs (input_->points.size (), 0.0f);
  diffs[scales_[0].second] = aux_diffs;

  for (size_t scale_i = 1; scale_i < clouds_.size (); ++scale_i)
  {
    diffs[scale_i].resize (input_->points.size ());
    size_t cloud_i = scales_[scale_i].second,
        cloud_i_minus_one = scales_[scale_i - 1].second;
    for (size_t point_i = 0; point_i < input_->points.size (); ++point_i)
      diffs[cloud_i][point_i] = cloud_normals_[cloud_i]->points[point_i].getNormalVector3fMap ().dot (
          clouds_[cloud_i]->points[point_i].getVector3fMap () - clouds_[cloud_i_minus_one]->points[point_i].getVector3fMap ());

    // Setup kdtree for this cloud
    cloud_trees_[cloud_i]->setInputCloud (clouds_[cloud_i]);
  }

  // Find minima and maxima in differences inside the input cloud
  tree_->setInputCloud (input_);
  for (int point_i = 0; point_i < input_->points.size (); ++point_i)
  {
    std::vector<int> nn_indices;
    std::vector<float> nn_distances;
    tree_->radiusSearch (point_i, input_scale_ * neighborhood_constant_, nn_indices, nn_distances);

    bool is_min = true, is_max = true;
    for (std::vector<int>::iterator nn_it = nn_indices.begin (); nn_it != nn_indices.end (); ++nn_it)
      if (*nn_it != point_i)
      {
        if (diffs[input_index_][point_i] < diffs[input_index_][*nn_it])
          is_max = false;
        else
          is_min = false;
      }

    // If the point is a local minimum/maximum, check if it so over all the scales
    if (is_min || is_max)
    {
      bool passed = true;
      for (size_t scale_i = 0; scale_i < scales_.size (); ++scale_i)
      {
        size_t cloud_i = scales_[scale_i].second;
        // skip input cloud
        if (cloud_i == clouds_.size ())
          continue;

        nn_indices.clear (); nn_distances.clear ();
        cloud_trees_[cloud_i]->radiusSearch (point_i, scales_[scale_i].first * neighborhood_constant_, nn_indices, nn_distances);

        bool is_min_other_scale = true, is_max_other_scale = true;
        for (std::vector<int>::iterator nn_it = nn_indices.begin (); nn_it != nn_indices.end (); ++nn_it)
          if (*nn_it != point_i)
          {
            if (diffs[input_index_][point_i] < diffs[cloud_i][*nn_it])
              is_max_other_scale = false;
            else
              is_min_other_scale = false;
          }

        if ( (is_min == true && is_min_other_scale == false) || (is_max == true && is_max_other_scale == false) )
        {
          passed = false;
          break;
        }
      }

      // check if point was minimum/maximum over all the scales
      if (passed)
        output.points.push_back (input_->points[point_i]);
    }
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointT, typename PointNT> bool
pcl::SmoothedSurfacesKeypoint<PointT, PointNT>::initCompute ()
{
  if ( !PCLBase<PointT>::initCompute ())
  {
    PCL_ERROR ("[pcl::SmoothedSurfacesKeypoints::initCompute] PCLBase::initCompute failed\n");
    return false;
  }

  if (!normals_)
  {
    PCL_ERROR ("[pcl::SmoothedSurfacesKeypoints::initCompute] Input normals were not set\n");
    return false;
  }
  if (clouds_.size () == 0)
  {
    PCL_ERROR ("[pcl::SmoothedSurfacesKeypoints::initCompute] No other clouds were set apart from the input\n");
    return false;
  }

  if (input_->points.size () != normals_->points.size ())
  {
    PCL_ERROR ("[pcl::SmoothedSurfacesKeypoints::initCompute] The input cloud and the input normals differ in size\n");
    return false;
  }

  for (size_t cloud_i = 0; cloud_i < clouds_.size (); ++cloud_i)
  {
    if (clouds_[cloud_i]->points.size () != input_->points.size ())
    {
      PCL_ERROR ("[pcl::SmoothedSurfacesKeypoints::initCompute] Cloud %d does not have the same number of points as the input cloud\n", cloud_i);
      return false;
    }

    if (cloud_normals_[cloud_i]->points.size () != input_->points.size ())
    {
      PCL_ERROR ("[pcl::SmoothedSurfacesKeypoints::initCompute] Normals for cloud %d do not have the same number of points as the input cloud\n", cloud_i);
      return false;
    }
  }

  // Add the input cloud as the last index
  scales_.push_back (std::pair<float, size_t> (input_scale_, scales_.size ()));
  clouds_.push_back (input_);
  cloud_normals_.push_back (normals_);
  // Sort the clouds by their scales
  sort (scales_.begin (), scales_.end (), compareScalesFunction);

  // Find the index of the input after sorting
  for (size_t i = 0; i < scales_.size (); ++i)
    if (scales_[i].second == scales_.size () - 1)
    {
      input_index_ = i;
      break;
    }

  return true;
}

#define PCL_INSTANTIATE_SmoothedSurfacesKeypoint(T,NT) template class PCL_EXPORTS pcl::SmoothedSurfacesKeypoint<T,NT>;

#endif /* PCL_KEYPOINTS_IMPL_SMOOTHEDSURFACESKEYPOINT_H_ */
<commit_msg>fixing msvc build issue<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2011, Alexandru-Eugen Ichim
 *                      Willow Garage, Inc
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 */

#ifndef PCL_KEYPOINTS_IMPL_SMOOTHEDSURFACESKEYPOINT_H_
#define PCL_KEYPOINTS_IMPL_SMOOTHEDSURFACESKEYPOINT_H_

#include "pcl/keypoints/smoothed_surfaces_keypoint.h"
#include <pcl/kdtree/kdtree_flann.h>

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointT, typename PointNT> void
pcl::SmoothedSurfacesKeypoint<PointT, PointNT>::addSmoothedPointCloud (PointCloudTConstPtr &cloud,
                                                                       PointCloudNTConstPtr &normals,
                                                                       KdTreePtr &kdtree,
                                                                       float &scale)
{
  clouds_.push_back (cloud);
  cloud_normals_.push_back (normals);
  cloud_trees_.push_back (kdtree);
  scales_.push_back (std::pair<float, size_t> (scale, scales_.size ()));
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointT, typename PointNT> void
pcl::SmoothedSurfacesKeypoint<PointT, PointNT>::resetClouds ()
{
  clouds_.clear ();
  cloud_normals_.clear ();
  scales_.clear ();
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointT, typename PointNT> void
pcl::SmoothedSurfacesKeypoint<PointT, PointNT>::detectKeypoints (PointCloudT &output)
{
  // Calculate differences for each cloud
  std::vector<std::vector<float> > diffs (scales_.size ());

  // The cloud with the smallest scale has no differences
  std::vector<float> aux_diffs (input_->points.size (), 0.0f);
  diffs[scales_[0].second] = aux_diffs;

  for (size_t scale_i = 1; scale_i < clouds_.size (); ++scale_i)
  {
    diffs[scale_i].resize (input_->points.size ());
    size_t cloud_i = scales_[scale_i].second,
        cloud_i_minus_one = scales_[scale_i - 1].second;
    for (size_t point_i = 0; point_i < input_->points.size (); ++point_i)
      diffs[cloud_i][point_i] = cloud_normals_[cloud_i]->points[point_i].getNormalVector3fMap ().dot (
          clouds_[cloud_i]->points[point_i].getVector3fMap () - clouds_[cloud_i_minus_one]->points[point_i].getVector3fMap ());

    // Setup kdtree for this cloud
    cloud_trees_[cloud_i]->setInputCloud (clouds_[cloud_i]);
  }

  // Find minima and maxima in differences inside the input cloud
  tree_->setInputCloud (input_);
  for (int point_i = 0; point_i < input_->points.size (); ++point_i)
  {
    std::vector<int> nn_indices;
    std::vector<float> nn_distances;
    tree_->radiusSearch (point_i, input_scale_ * neighborhood_constant_, nn_indices, nn_distances);

    bool is_min = true, is_max = true;
    for (std::vector<int>::iterator nn_it = nn_indices.begin (); nn_it != nn_indices.end (); ++nn_it)
      if (*nn_it != point_i)
      {
        if (diffs[input_index_][point_i] < diffs[input_index_][*nn_it])
          is_max = false;
        else
          is_min = false;
      }

    // If the point is a local minimum/maximum, check if it so over all the scales
    if (is_min || is_max)
    {
      bool passed = true;
      for (size_t scale_i = 0; scale_i < scales_.size (); ++scale_i)
      {
        size_t cloud_i = scales_[scale_i].second;
        // skip input cloud
        if (cloud_i == clouds_.size ())
          continue;

        nn_indices.clear (); nn_distances.clear ();
        cloud_trees_[cloud_i]->radiusSearch (point_i, scales_[scale_i].first * neighborhood_constant_, nn_indices, nn_distances);

        bool is_min_other_scale = true, is_max_other_scale = true;
        for (std::vector<int>::iterator nn_it = nn_indices.begin (); nn_it != nn_indices.end (); ++nn_it)
          if (*nn_it != point_i)
          {
            if (diffs[input_index_][point_i] < diffs[cloud_i][*nn_it])
              is_max_other_scale = false;
            else
              is_min_other_scale = false;
          }

        if ( (is_min == true && is_min_other_scale == false) || (is_max == true && is_max_other_scale == false) )
        {
          passed = false;
          break;
        }
      }

      // check if point was minimum/maximum over all the scales
      if (passed)
        output.points.push_back (input_->points[point_i]);
    }
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointT, typename PointNT> bool
pcl::SmoothedSurfacesKeypoint<PointT, PointNT>::initCompute ()
{
  if ( !PCLBase<PointT>::initCompute ())
  {
    PCL_ERROR ("[pcl::SmoothedSurfacesKeypoints::initCompute] PCLBase::initCompute failed\n");
    return false;
  }

  if (!normals_)
  {
    PCL_ERROR ("[pcl::SmoothedSurfacesKeypoints::initCompute] Input normals were not set\n");
    return false;
  }
  if (clouds_.size () == 0)
  {
    PCL_ERROR ("[pcl::SmoothedSurfacesKeypoints::initCompute] No other clouds were set apart from the input\n");
    return false;
  }

  if (input_->points.size () != normals_->points.size ())
  {
    PCL_ERROR ("[pcl::SmoothedSurfacesKeypoints::initCompute] The input cloud and the input normals differ in size\n");
    return false;
  }

  for (size_t cloud_i = 0; cloud_i < clouds_.size (); ++cloud_i)
  {
    if (clouds_[cloud_i]->points.size () != input_->points.size ())
    {
      PCL_ERROR ("[pcl::SmoothedSurfacesKeypoints::initCompute] Cloud %d does not have the same number of points as the input cloud\n", cloud_i);
      return false;
    }

    if (cloud_normals_[cloud_i]->points.size () != input_->points.size ())
    {
      PCL_ERROR ("[pcl::SmoothedSurfacesKeypoints::initCompute] Normals for cloud %d do not have the same number of points as the input cloud\n", cloud_i);
      return false;
    }
  }

  // Add the input cloud as the last index
  scales_.push_back (std::pair<float, size_t> (input_scale_, scales_.size ()));
  clouds_.push_back (input_);
  cloud_normals_.push_back (normals_);
  // Sort the clouds by their scales
  sort (scales_.begin (), scales_.end (), compareScalesFunction);

  // Find the index of the input after sorting
  for (size_t i = 0; i < scales_.size (); ++i)
    if (scales_[i].second == scales_.size () - 1)
    {
      input_index_ = i;
      break;
    }

  return true;
}

#define PCL_INSTANTIATE_SmoothedSurfacesKeypoint(T,NT) template class PCL_EXPORTS pcl::SmoothedSurfacesKeypoint<T,NT>;

#endif /* PCL_KEYPOINTS_IMPL_SMOOTHEDSURFACESKEYPOINT_H_ */
<|endoftext|>