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

#include <bench/bench.h>
#include <chainparams.h>
#include <coins.h>
#include <consensus/merkle.h>
#include <consensus/validation.h>
#include <miner.h>
#include <policy/policy.h>
#include <scheduler.h>
#include <txdb.h>
#include <txmempool.h>
#include <utiltime.h>
#include <validation.h>
#include <validationinterface.h>

#include <boost/thread.hpp>

#include <list>
#include <vector>

static std::shared_ptr<CBlock> PrepareBlock(const CScript& coinbase_scriptPubKey)
{
    auto block = std::make_shared<CBlock>(
        BlockAssembler{Params()}
            .CreateNewBlock(coinbase_scriptPubKey, /* fMineWitnessTx */ true)
            ->block);

    block->nTime = ::chainActive.Tip()->GetMedianTimePast() + 1;
    block->hashMerkleRoot = BlockMerkleRoot(*block);

    return block;
}

static CTxIn MineBlock(const CScript& coinbase_scriptPubKey)
{
    auto block = PrepareBlock(coinbase_scriptPubKey);

    while (!CheckProofOfWork(block->GetHash(), block->nBits, Params().GetConsensus())) {
        assert(++block->nNonce);
    }

    bool processed{ProcessNewBlock(Params(), block, true, nullptr)};
    assert(processed);

    return CTxIn{block->vtx[0]->GetHash(), 0};
}

static void AssembleBlock(benchmark::State& state)
{
    const std::vector<unsigned char> op_true{OP_TRUE};
    CScriptWitness witness;
    witness.stack.push_back(op_true);

    uint256 witness_program;
    CSHA256().Write(&op_true[0], op_true.size()).Finalize(witness_program.begin());

    const CScript SCRIPT_PUB{CScript(OP_0) << std::vector<unsigned char>{witness_program.begin(), witness_program.end()}};

    // Switch to regtest so we can mine faster
    // Also segwit is active, so we can include witness transactions
    SelectParams(CBaseChainParams::REGTEST);

    InitScriptExecutionCache();

    boost::thread_group thread_group;
    CScheduler scheduler;
    {
        ::pblocktree.reset(new CBlockTreeDB(1 << 20, true));
        ::pcoinsdbview.reset(new CCoinsViewDB(1 << 23, true));
        ::pcoinsTip.reset(new CCoinsViewCache(pcoinsdbview.get()));

        const CChainParams& chainparams = Params();
        thread_group.create_thread(boost::bind(&CScheduler::serviceQueue, &scheduler));
        GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
        LoadGenesisBlock(chainparams);
        CValidationState state;
        ActivateBestChain(state, chainparams);
        assert(::chainActive.Tip() != nullptr);
        const bool witness_enabled{IsWitnessEnabled(::chainActive.Tip(), chainparams.GetConsensus())};
        assert(witness_enabled);
    }

    // Collect some loose transactions that spend the coinbases of our mined blocks
    constexpr size_t NUM_BLOCKS{200};
    std::array<CTransactionRef, NUM_BLOCKS - COINBASE_MATURITY + 1> txs;
    for (size_t b{0}; b < NUM_BLOCKS; ++b) {
        CMutableTransaction tx;
        tx.vin.push_back(MineBlock(SCRIPT_PUB));
        tx.vin.back().scriptWitness = witness;
        tx.vout.emplace_back(1337, SCRIPT_PUB);
        if (NUM_BLOCKS - b >= COINBASE_MATURITY)
            txs.at(b) = MakeTransactionRef(tx);
    }
    for (const auto& txr : txs) {
        CValidationState state;
        bool ret{::AcceptToMemoryPool(::mempool, state, txr, nullptr /* pfMissingInputs */, nullptr /* plTxnReplaced */, false /* bypass_limits */, /* nAbsurdFee */ 0)};
        assert(ret);
    }

    while (state.KeepRunning()) {
        PrepareBlock(SCRIPT_PUB);
    }

    thread_group.interrupt_all();
    thread_group.join_all();
    GetMainSignals().FlushBackgroundCallbacks();
    GetMainSignals().UnregisterBackgroundSignalScheduler();
}

BENCHMARK(AssembleBlock, 700);
<commit_msg>bench: Add missing pow.h header<commit_after>// Copyright (c) 2011-2017 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <bench/bench.h>
#include <chainparams.h>
#include <coins.h>
#include <consensus/merkle.h>
#include <consensus/validation.h>
#include <miner.h>
#include <policy/policy.h>
#include <pow.h>
#include <scheduler.h>
#include <txdb.h>
#include <txmempool.h>
#include <utiltime.h>
#include <validation.h>
#include <validationinterface.h>

#include <boost/thread.hpp>

#include <list>
#include <vector>

static std::shared_ptr<CBlock> PrepareBlock(const CScript& coinbase_scriptPubKey)
{
    auto block = std::make_shared<CBlock>(
        BlockAssembler{Params()}
            .CreateNewBlock(coinbase_scriptPubKey, /* fMineWitnessTx */ true)
            ->block);

    block->nTime = ::chainActive.Tip()->GetMedianTimePast() + 1;
    block->hashMerkleRoot = BlockMerkleRoot(*block);

    return block;
}

static CTxIn MineBlock(const CScript& coinbase_scriptPubKey)
{
    auto block = PrepareBlock(coinbase_scriptPubKey);

    while (!CheckProofOfWork(block->GetHash(), block->nBits, Params().GetConsensus())) {
        assert(++block->nNonce);
    }

    bool processed{ProcessNewBlock(Params(), block, true, nullptr)};
    assert(processed);

    return CTxIn{block->vtx[0]->GetHash(), 0};
}

static void AssembleBlock(benchmark::State& state)
{
    const std::vector<unsigned char> op_true{OP_TRUE};
    CScriptWitness witness;
    witness.stack.push_back(op_true);

    uint256 witness_program;
    CSHA256().Write(&op_true[0], op_true.size()).Finalize(witness_program.begin());

    const CScript SCRIPT_PUB{CScript(OP_0) << std::vector<unsigned char>{witness_program.begin(), witness_program.end()}};

    // Switch to regtest so we can mine faster
    // Also segwit is active, so we can include witness transactions
    SelectParams(CBaseChainParams::REGTEST);

    InitScriptExecutionCache();

    boost::thread_group thread_group;
    CScheduler scheduler;
    {
        ::pblocktree.reset(new CBlockTreeDB(1 << 20, true));
        ::pcoinsdbview.reset(new CCoinsViewDB(1 << 23, true));
        ::pcoinsTip.reset(new CCoinsViewCache(pcoinsdbview.get()));

        const CChainParams& chainparams = Params();
        thread_group.create_thread(boost::bind(&CScheduler::serviceQueue, &scheduler));
        GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
        LoadGenesisBlock(chainparams);
        CValidationState state;
        ActivateBestChain(state, chainparams);
        assert(::chainActive.Tip() != nullptr);
        const bool witness_enabled{IsWitnessEnabled(::chainActive.Tip(), chainparams.GetConsensus())};
        assert(witness_enabled);
    }

    // Collect some loose transactions that spend the coinbases of our mined blocks
    constexpr size_t NUM_BLOCKS{200};
    std::array<CTransactionRef, NUM_BLOCKS - COINBASE_MATURITY + 1> txs;
    for (size_t b{0}; b < NUM_BLOCKS; ++b) {
        CMutableTransaction tx;
        tx.vin.push_back(MineBlock(SCRIPT_PUB));
        tx.vin.back().scriptWitness = witness;
        tx.vout.emplace_back(1337, SCRIPT_PUB);
        if (NUM_BLOCKS - b >= COINBASE_MATURITY)
            txs.at(b) = MakeTransactionRef(tx);
    }
    for (const auto& txr : txs) {
        CValidationState state;
        bool ret{::AcceptToMemoryPool(::mempool, state, txr, nullptr /* pfMissingInputs */, nullptr /* plTxnReplaced */, false /* bypass_limits */, /* nAbsurdFee */ 0)};
        assert(ret);
    }

    while (state.KeepRunning()) {
        PrepareBlock(SCRIPT_PUB);
    }

    thread_group.interrupt_all();
    thread_group.join_all();
    GetMainSignals().FlushBackgroundCallbacks();
    GetMainSignals().UnregisterBackgroundSignalScheduler();
}

BENCHMARK(AssembleBlock, 700);
<|endoftext|>


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

#include "intro.h"
#include "ui_intro.h"

#include "util.h"

#include <boost/filesystem.hpp>
#include <QFileDialog>
#include <QSettings>
#include <QMessageBox>

/* Minimum free space (in bytes) needed for data directory */
static const uint64_t GB_BYTES = 1000000000LL;
static const uint64_t BLOCK_CHAIN_SIZE = 10LL * GB_BYTES;

/* Check free space asynchronously to prevent hanging the UI thread.

   Up to one request to check a path is in flight to this thread; when the check()
   function runs, the current path is requested from the associated Intro object.
   The reply is sent back through a signal.

   This ensures that no queue of checking requests is built up while the user is
   still entering the path, and that always the most recently entered path is checked as
   soon as the thread becomes available.
*/
class FreespaceChecker : public QObject
{
    Q_OBJECT

public:
    FreespaceChecker(Intro *intro);

    enum Status {
        ST_OK,
        ST_ERROR
    };

public slots:
    void check();

signals:
    void reply(int status, const QString &message, quint64 available);

private:
    Intro *intro;
};

#include "intro.moc"

FreespaceChecker::FreespaceChecker(Intro *intro)
{
    this->intro = intro;
}

void FreespaceChecker::check()
{
    namespace fs = boost::filesystem;
    QString dataDirStr = intro->getPathToCheck();
    fs::path dataDir = fs::path(dataDirStr.toStdString());
    uint64_t freeBytesAvailable = 0;
    int replyStatus = ST_OK;
    QString replyMessage = tr("A new data directory will be created.");

    /* Find first parent that exists, so that fs::space does not fail */
    fs::path parentDir = dataDir;
    fs::path parentDirOld = fs::path();
    while(parentDir.has_parent_path() && !fs::exists(parentDir))
    {
        parentDir = parentDir.parent_path();

        /* Check if we make any progress, break if not to prevent an infinite loop here */
        if (parentDirOld == parentDir)
            break;

        parentDirOld = parentDir;
    }

    try {
        freeBytesAvailable = fs::space(parentDir).available;
        if(fs::exists(dataDir))
        {
            if(fs::is_directory(dataDir))
            {
                QString separator = "" + QDir::toNativeSeparators("/") + tr("name") + "";
                replyStatus = ST_OK;
                replyMessage = tr("Directory already exists. Add %1 if you intend to create a new directory here.").arg(separator);
            } else {
                replyStatus = ST_ERROR;
                replyMessage = tr("Path already exists, and is not a directory.");
            }
        }
    } catch(fs::filesystem_error &e)
    {
        /* Parent directory does not exist or is not accessible */
        replyStatus = ST_ERROR;
        replyMessage = tr("Cannot create data directory here.");
    }
    emit reply(replyStatus, replyMessage, freeBytesAvailable);
}

Intro::Intro(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Intro),
    thread(0),
    signalled(false)
{
    ui->setupUi(this);
    ui->sizeWarningLabel->setText(ui->sizeWarningLabel->text().arg(BLOCK_CHAIN_SIZE/GB_BYTES));
    startThread();
}

Intro::~Intro()
{
    delete ui;
    /* Ensure thread is finished before it is deleted */
    emit stopThread();
    thread->wait();
}

QString Intro::getDataDirectory()
{
    return ui->dataDirectory->text();
}

void Intro::setDataDirectory(const QString &dataDir)
{
    ui->dataDirectory->setText(dataDir);
    if(dataDir == getDefaultDataDirectory())
    {
        ui->dataDirDefault->setChecked(true);
        ui->dataDirectory->setEnabled(false);
        ui->ellipsisButton->setEnabled(false);
    } else {
        ui->dataDirCustom->setChecked(true);
        ui->dataDirectory->setEnabled(true);
        ui->ellipsisButton->setEnabled(true);
    }
}

QString Intro::getDefaultDataDirectory()
{
    return QString::fromStdString(GetDefaultDataDir().string());
}

void Intro::pickDataDirectory(bool fIsTestnet)
{
    namespace fs = boost::filesystem;
    QSettings settings;
    /* If data directory provided on command line, no need to look at settings
       or show a picking dialog */
    if(!GetArg("-datadir", "").empty())
        return;
    /* 1) Default data directory for operating system */
    QString dataDir = getDefaultDataDirectory();
    /* 2) Allow QSettings to override default dir */
    dataDir = settings.value("strDataDir", dataDir).toString();

    if(!fs::exists(dataDir.toStdString()) || GetBoolArg("-choosedatadir", false))
    {
        /* If current default data directory does not exist, let the user choose one */
        Intro intro;
        intro.setDataDirectory(dataDir);
        if (!fIsTestnet)
            intro.setWindowIcon(QIcon(":icons/bitcoin"));
        else
            intro.setWindowIcon(QIcon(":icons/bitcoin_testnet"));

        while(true)
        {
            if(!intro.exec())
            {
                /* Cancel clicked */
                exit(0);
            }
            dataDir = intro.getDataDirectory();
            try {
                fs::create_directory(dataDir.toStdString());
                break;
            } catch(fs::filesystem_error &e) {
                QMessageBox::critical(0, tr("Bitcoin"),
                    tr("Error: Specified data directory \"%1\" can not be created.").arg(dataDir));
                /* fall through, back to choosing screen */
            }
        }

        settings.setValue("strDataDir", dataDir);
    }
    SoftSetArg("-datadir", dataDir.toStdString());
}

void Intro::setStatus(int status, const QString &message, quint64 bytesAvailable)
{
    switch(status)
    {
    case FreespaceChecker::ST_OK:
        ui->errorMessage->setText(message);
        ui->errorMessage->setStyleSheet("");
        break;
    case FreespaceChecker::ST_ERROR:
        ui->errorMessage->setText(tr("Error") + ": " + message);
        ui->errorMessage->setStyleSheet("QLabel { color: #800000 }");
        break;
    }
    /* Indicate number of bytes available */
    if(status == FreespaceChecker::ST_ERROR)
    {
        ui->freeSpace->setText("");
    } else {
        QString freeString = QString::number(bytesAvailable/GB_BYTES) + tr("GB of free space available");
        if(bytesAvailable < BLOCK_CHAIN_SIZE)
        {
            freeString += " " + tr("(of %1GB needed)").arg(BLOCK_CHAIN_SIZE/GB_BYTES);
            ui->freeSpace->setStyleSheet("QLabel { color: #800000 }");
        } else {
            ui->freeSpace->setStyleSheet("");
        }
        ui->freeSpace->setText(freeString + ".");
    }
    /* Don't allow confirm in ERROR state */
    ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(status != FreespaceChecker::ST_ERROR);
}

void Intro::on_dataDirectory_textChanged(const QString &dataDirStr)
{
    /* Disable OK button until check result comes in */
    ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
    checkPath(dataDirStr);
}

void Intro::on_ellipsisButton_clicked()
{
    QString dir = QFileDialog::getExistingDirectory(0, "Choose data directory", ui->dataDirectory->text());
    if(!dir.isEmpty())
        ui->dataDirectory->setText(dir);
}

void Intro::on_dataDirDefault_clicked()
{
    setDataDirectory(getDefaultDataDirectory());
}

void Intro::on_dataDirCustom_clicked()
{
    ui->dataDirectory->setEnabled(true);
    ui->ellipsisButton->setEnabled(true);
}

void Intro::startThread()
{
    thread = new QThread(this);
    FreespaceChecker *executor = new FreespaceChecker(this);
    executor->moveToThread(thread);

    connect(executor, SIGNAL(reply(int,QString,quint64)), this, SLOT(setStatus(int,QString,quint64)));
    connect(this, SIGNAL(requestCheck()), executor, SLOT(check()));
    /*  make sure executor object is deleted in its own thread */
    connect(this, SIGNAL(stopThread()), executor, SLOT(deleteLater()));
    connect(this, SIGNAL(stopThread()), thread, SLOT(quit()));

    thread->start();
}

void Intro::checkPath(const QString &dataDir)
{
    mutex.lock();
    pathToCheck = dataDir;
    if(!signalled)
    {
        signalled = true;
        emit requestCheck();
    }
    mutex.unlock();
}

QString Intro::getPathToCheck()
{
    QString retval;
    mutex.lock();
    retval = pathToCheck;
    signalled = false; /* new request can be queued now */
    mutex.unlock();
    return retval;
}
<commit_msg>[Qt] display native dir separators in select dadatir dialog<commit_after>// Copyright (c) 2011-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "intro.h"
#include "ui_intro.h"

#include "util.h"

#include <boost/filesystem.hpp>
#include <QFileDialog>
#include <QSettings>
#include <QMessageBox>

/* Minimum free space (in bytes) needed for data directory */
static const uint64_t GB_BYTES = 1000000000LL;
static const uint64_t BLOCK_CHAIN_SIZE = 10LL * GB_BYTES;

/* Check free space asynchronously to prevent hanging the UI thread.

   Up to one request to check a path is in flight to this thread; when the check()
   function runs, the current path is requested from the associated Intro object.
   The reply is sent back through a signal.

   This ensures that no queue of checking requests is built up while the user is
   still entering the path, and that always the most recently entered path is checked as
   soon as the thread becomes available.
*/
class FreespaceChecker : public QObject
{
    Q_OBJECT

public:
    FreespaceChecker(Intro *intro);

    enum Status {
        ST_OK,
        ST_ERROR
    };

public slots:
    void check();

signals:
    void reply(int status, const QString &message, quint64 available);

private:
    Intro *intro;
};

#include "intro.moc"

FreespaceChecker::FreespaceChecker(Intro *intro)
{
    this->intro = intro;
}

void FreespaceChecker::check()
{
    namespace fs = boost::filesystem;
    QString dataDirStr = intro->getPathToCheck();
    fs::path dataDir = fs::path(dataDirStr.toStdString());
    uint64_t freeBytesAvailable = 0;
    int replyStatus = ST_OK;
    QString replyMessage = tr("A new data directory will be created.");

    /* Find first parent that exists, so that fs::space does not fail */
    fs::path parentDir = dataDir;
    fs::path parentDirOld = fs::path();
    while(parentDir.has_parent_path() && !fs::exists(parentDir))
    {
        parentDir = parentDir.parent_path();

        /* Check if we make any progress, break if not to prevent an infinite loop here */
        if (parentDirOld == parentDir)
            break;

        parentDirOld = parentDir;
    }

    try {
        freeBytesAvailable = fs::space(parentDir).available;
        if(fs::exists(dataDir))
        {
            if(fs::is_directory(dataDir))
            {
                QString separator = "" + QDir::toNativeSeparators("/") + tr("name") + "";
                replyStatus = ST_OK;
                replyMessage = tr("Directory already exists. Add %1 if you intend to create a new directory here.").arg(separator);
            } else {
                replyStatus = ST_ERROR;
                replyMessage = tr("Path already exists, and is not a directory.");
            }
        }
    } catch(fs::filesystem_error &e)
    {
        /* Parent directory does not exist or is not accessible */
        replyStatus = ST_ERROR;
        replyMessage = tr("Cannot create data directory here.");
    }
    emit reply(replyStatus, replyMessage, freeBytesAvailable);
}

Intro::Intro(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Intro),
    thread(0),
    signalled(false)
{
    ui->setupUi(this);
    ui->sizeWarningLabel->setText(ui->sizeWarningLabel->text().arg(BLOCK_CHAIN_SIZE/GB_BYTES));
    startThread();
}

Intro::~Intro()
{
    delete ui;
    /* Ensure thread is finished before it is deleted */
    emit stopThread();
    thread->wait();
}

QString Intro::getDataDirectory()
{
    return ui->dataDirectory->text();
}

void Intro::setDataDirectory(const QString &dataDir)
{
    ui->dataDirectory->setText(dataDir);
    if(dataDir == getDefaultDataDirectory())
    {
        ui->dataDirDefault->setChecked(true);
        ui->dataDirectory->setEnabled(false);
        ui->ellipsisButton->setEnabled(false);
    } else {
        ui->dataDirCustom->setChecked(true);
        ui->dataDirectory->setEnabled(true);
        ui->ellipsisButton->setEnabled(true);
    }
}

QString Intro::getDefaultDataDirectory()
{
    return QString::fromStdString(GetDefaultDataDir().string());
}

void Intro::pickDataDirectory(bool fIsTestnet)
{
    namespace fs = boost::filesystem;
    QSettings settings;
    /* If data directory provided on command line, no need to look at settings
       or show a picking dialog */
    if(!GetArg("-datadir", "").empty())
        return;
    /* 1) Default data directory for operating system */
    QString dataDir = getDefaultDataDirectory();
    /* 2) Allow QSettings to override default dir */
    dataDir = settings.value("strDataDir", dataDir).toString();

    if(!fs::exists(dataDir.toStdString()) || GetBoolArg("-choosedatadir", false))
    {
        /* If current default data directory does not exist, let the user choose one */
        Intro intro;
        intro.setDataDirectory(dataDir);
        if (!fIsTestnet)
            intro.setWindowIcon(QIcon(":icons/bitcoin"));
        else
            intro.setWindowIcon(QIcon(":icons/bitcoin_testnet"));

        while(true)
        {
            if(!intro.exec())
            {
                /* Cancel clicked */
                exit(0);
            }
            dataDir = intro.getDataDirectory();
            try {
                fs::create_directory(dataDir.toStdString());
                break;
            } catch(fs::filesystem_error &e) {
                QMessageBox::critical(0, tr("Bitcoin"),
                    tr("Error: Specified data directory \"%1\" can not be created.").arg(dataDir));
                /* fall through, back to choosing screen */
            }
        }

        settings.setValue("strDataDir", dataDir);
    }
    SoftSetArg("-datadir", dataDir.toStdString());
}

void Intro::setStatus(int status, const QString &message, quint64 bytesAvailable)
{
    switch(status)
    {
    case FreespaceChecker::ST_OK:
        ui->errorMessage->setText(message);
        ui->errorMessage->setStyleSheet("");
        break;
    case FreespaceChecker::ST_ERROR:
        ui->errorMessage->setText(tr("Error") + ": " + message);
        ui->errorMessage->setStyleSheet("QLabel { color: #800000 }");
        break;
    }
    /* Indicate number of bytes available */
    if(status == FreespaceChecker::ST_ERROR)
    {
        ui->freeSpace->setText("");
    } else {
        QString freeString = QString::number(bytesAvailable/GB_BYTES) + tr("GB of free space available");
        if(bytesAvailable < BLOCK_CHAIN_SIZE)
        {
            freeString += " " + tr("(of %1GB needed)").arg(BLOCK_CHAIN_SIZE/GB_BYTES);
            ui->freeSpace->setStyleSheet("QLabel { color: #800000 }");
        } else {
            ui->freeSpace->setStyleSheet("");
        }
        ui->freeSpace->setText(freeString + ".");
    }
    /* Don't allow confirm in ERROR state */
    ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(status != FreespaceChecker::ST_ERROR);
}

void Intro::on_dataDirectory_textChanged(const QString &dataDirStr)
{
    /* Disable OK button until check result comes in */
    ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
    checkPath(dataDirStr);
}

void Intro::on_ellipsisButton_clicked()
{
    QString dir = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(0, "Choose data directory", ui->dataDirectory->text()));
    if(!dir.isEmpty())
        ui->dataDirectory->setText(dir);
}

void Intro::on_dataDirDefault_clicked()
{
    setDataDirectory(getDefaultDataDirectory());
}

void Intro::on_dataDirCustom_clicked()
{
    ui->dataDirectory->setEnabled(true);
    ui->ellipsisButton->setEnabled(true);
}

void Intro::startThread()
{
    thread = new QThread(this);
    FreespaceChecker *executor = new FreespaceChecker(this);
    executor->moveToThread(thread);

    connect(executor, SIGNAL(reply(int,QString,quint64)), this, SLOT(setStatus(int,QString,quint64)));
    connect(this, SIGNAL(requestCheck()), executor, SLOT(check()));
    /*  make sure executor object is deleted in its own thread */
    connect(this, SIGNAL(stopThread()), executor, SLOT(deleteLater()));
    connect(this, SIGNAL(stopThread()), thread, SLOT(quit()));

    thread->start();
}

void Intro::checkPath(const QString &dataDir)
{
    mutex.lock();
    pathToCheck = dataDir;
    if(!signalled)
    {
        signalled = true;
        emit requestCheck();
    }
    mutex.unlock();
}

QString Intro::getPathToCheck()
{
    QString retval;
    mutex.lock();
    retval = pathToCheck;
    signalled = false; /* new request can be queued now */
    mutex.unlock();
    return retval;
}
<|endoftext|>


<commit_before>#include "precompiled.h"
//
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

// InputLayoutCache.cpp: Defines InputLayoutCache, a class that builds and caches
// D3D11 input layouts.

#include "libGLESv2/renderer/d3d11/InputLayoutCache.h"
#include "libGLESv2/renderer/d3d11/VertexBuffer11.h"
#include "libGLESv2/renderer/d3d11/BufferStorage11.h"
#include "libGLESv2/renderer/d3d11/ShaderExecutable11.h"
#include "libGLESv2/ProgramBinary.h"
#include "libGLESv2/VertexAttribute.h"
#include "libGLESv2/renderer/VertexDataManager.h"
#include "libGLESv2/renderer/d3d11/formatutils11.h"

#include "third_party/murmurhash/MurmurHash3.h"

namespace rx
{

static void GetInputLayout(const TranslatedAttribute translatedAttributes[gl::MAX_VERTEX_ATTRIBS],
                           gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS])
{
    for (unsigned int attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++)
    {
        const TranslatedAttribute &translatedAttribute = translatedAttributes[attributeIndex];

        if (translatedAttributes[attributeIndex].active)
        {
            inputLayout[attributeIndex] = gl::VertexFormat(*translatedAttribute.attribute,
                                                           translatedAttribute.currentValueType);
        }
    }
}

const unsigned int InputLayoutCache::kMaxInputLayouts = 1024;

InputLayoutCache::InputLayoutCache() : mInputLayoutMap(kMaxInputLayouts, hashInputLayout, compareInputLayouts)
{
    mCounter = 0;
    mDevice = NULL;
    mDeviceContext = NULL;
    mCurrentIL = NULL;
    for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
    {
        mCurrentBuffers[i] = NULL;
        mCurrentVertexStrides[i] = -1;
        mCurrentVertexOffsets[i] = -1;
    }
}

InputLayoutCache::~InputLayoutCache()
{
    clear();
}

void InputLayoutCache::initialize(ID3D11Device *device, ID3D11DeviceContext *context)
{
    clear();
    mDevice = device;
    mDeviceContext = context;
}

void InputLayoutCache::clear()
{
    for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++)
    {
        SafeRelease(i->second.inputLayout);
    }
    mInputLayoutMap.clear();
    markDirty();
}

void InputLayoutCache::markDirty()
{
    mCurrentIL = NULL;
    for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
    {
        mCurrentBuffers[i] = NULL;
        mCurrentVertexStrides[i] = -1;
        mCurrentVertexOffsets[i] = -1;
    }
}

GLenum InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS],
                                            gl::ProgramBinary *programBinary)
{
    int sortedSemanticIndices[gl::MAX_VERTEX_ATTRIBS];
    programBinary->sortAttributesByLayout(attributes, sortedSemanticIndices);

    if (!mDevice || !mDeviceContext)
    {
        ERR("InputLayoutCache is not initialized.");
        return GL_INVALID_OPERATION;
    }

    InputLayoutKey ilKey = { 0 };

    ID3D11Buffer *vertexBuffers[gl::MAX_VERTEX_ATTRIBS] = { NULL };
    UINT vertexStrides[gl::MAX_VERTEX_ATTRIBS] = { 0 };
    UINT vertexOffsets[gl::MAX_VERTEX_ATTRIBS] = { 0 };

    static const char* semanticName = "TEXCOORD";

    for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
    {
        if (attributes[i].active)
        {
            VertexBuffer11 *vertexBuffer = VertexBuffer11::makeVertexBuffer11(attributes[i].vertexBuffer);
            BufferStorage11 *bufferStorage = attributes[i].storage ? BufferStorage11::makeBufferStorage11(attributes[i].storage) : NULL;

            D3D11_INPUT_CLASSIFICATION inputClass = attributes[i].divisor > 0 ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA;

            gl::VertexFormat vertexFormat(*attributes[i].attribute, attributes[i].currentValueType);
            DXGI_FORMAT dxgiFormat = gl_d3d11::GetNativeVertexFormat(vertexFormat);

            // Record the type of the associated vertex shader vector in our key
            // This will prevent mismatched vertex shaders from using the same input layout
            GLint attributeSize;
            programBinary->getActiveAttribute(ilKey.elementCount, 0, NULL, &attributeSize, &ilKey.elements[ilKey.elementCount].glslElementType, NULL);

            ilKey.elements[ilKey.elementCount].desc.SemanticName = semanticName;
            ilKey.elements[ilKey.elementCount].desc.SemanticIndex = sortedSemanticIndices[i];
            ilKey.elements[ilKey.elementCount].desc.Format = dxgiFormat;
            ilKey.elements[ilKey.elementCount].desc.InputSlot = i;
            ilKey.elements[ilKey.elementCount].desc.AlignedByteOffset = 0;
            ilKey.elements[ilKey.elementCount].desc.InputSlotClass = inputClass;
            ilKey.elements[ilKey.elementCount].desc.InstanceDataStepRate = attributes[i].divisor;
            ilKey.elementCount++;

            vertexBuffers[i] = bufferStorage ? bufferStorage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK)
                                             : vertexBuffer->getBuffer();
            vertexStrides[i] = attributes[i].stride;
            vertexOffsets[i] = attributes[i].offset;
        }
    }

    ID3D11InputLayout *inputLayout = NULL;

    InputLayoutMap::iterator keyIter = mInputLayoutMap.find(ilKey);
    if (keyIter != mInputLayoutMap.end())
    {
        inputLayout = keyIter->second.inputLayout;
        keyIter->second.lastUsedTime = mCounter++;
    }
    else
    {
        gl::VertexFormat shaderInputLayout[gl::MAX_VERTEX_ATTRIBS];
        GetInputLayout(attributes, shaderInputLayout);
        ShaderExecutable11 *shader = ShaderExecutable11::makeShaderExecutable11(programBinary->getVertexExecutableForInputLayout(shaderInputLayout));

        D3D11_INPUT_ELEMENT_DESC descs[gl::MAX_VERTEX_ATTRIBS];
        for (unsigned int j = 0; j < ilKey.elementCount; ++j)
        {
            descs[j] = ilKey.elements[j].desc;
        }

        HRESULT result = mDevice->CreateInputLayout(descs, ilKey.elementCount, shader->getFunction(), shader->getLength(), &inputLayout);
        if (FAILED(result))
        {
            ERR("Failed to crate input layout, result: 0x%08x", result);
            return GL_INVALID_OPERATION;
        }

        if (mInputLayoutMap.size() >= kMaxInputLayouts)
        {
            TRACE("Overflowed the limit of %u input layouts, removing the least recently used "
                  "to make room.", kMaxInputLayouts);

            InputLayoutMap::iterator leastRecentlyUsed = mInputLayoutMap.begin();
            for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++)
            {
                if (i->second.lastUsedTime < leastRecentlyUsed->second.lastUsedTime)
                {
                    leastRecentlyUsed = i;
                }
            }
            SafeRelease(leastRecentlyUsed->second.inputLayout);
            mInputLayoutMap.erase(leastRecentlyUsed);
        }

        InputLayoutCounterPair inputCounterPair;
        inputCounterPair.inputLayout = inputLayout;
        inputCounterPair.lastUsedTime = mCounter++;

        mInputLayoutMap.insert(std::make_pair(ilKey, inputCounterPair));
    }

    if (inputLayout != mCurrentIL)
    {
        mDeviceContext->IASetInputLayout(inputLayout);
        mCurrentIL = inputLayout;
    }

    for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
    {
        if (vertexBuffers[i] != mCurrentBuffers[i] || vertexStrides[i] != mCurrentVertexStrides[i] ||
            vertexOffsets[i] != mCurrentVertexOffsets[i])
        {
            mDeviceContext->IASetVertexBuffers(i, 1, &vertexBuffers[i], &vertexStrides[i], &vertexOffsets[i]);
            mCurrentBuffers[i] = vertexBuffers[i];
            mCurrentVertexStrides[i] = vertexStrides[i];
            mCurrentVertexOffsets[i] = vertexOffsets[i];
        }
    }

    return GL_NO_ERROR;
}

std::size_t InputLayoutCache::hashInputLayout(const InputLayoutKey &inputLayout)
{
    static const unsigned int seed = 0xDEADBEEF;

    std::size_t hash = 0;
    MurmurHash3_x86_32(inputLayout.begin(), inputLayout.end() - inputLayout.begin(), seed, &hash);
    return hash;
}

bool InputLayoutCache::compareInputLayouts(const InputLayoutKey &a, const InputLayoutKey &b)
{
    if (a.elementCount != b.elementCount)
    {
        return false;
    }

    return std::equal(a.begin(), a.end(), b.begin());
}

}
<commit_msg>Refactor setting the input layout and vertex buffers separately.<commit_after>#include "precompiled.h"
//
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

// InputLayoutCache.cpp: Defines InputLayoutCache, a class that builds and caches
// D3D11 input layouts.

#include "libGLESv2/renderer/d3d11/InputLayoutCache.h"
#include "libGLESv2/renderer/d3d11/VertexBuffer11.h"
#include "libGLESv2/renderer/d3d11/BufferStorage11.h"
#include "libGLESv2/renderer/d3d11/ShaderExecutable11.h"
#include "libGLESv2/ProgramBinary.h"
#include "libGLESv2/VertexAttribute.h"
#include "libGLESv2/renderer/VertexDataManager.h"
#include "libGLESv2/renderer/d3d11/formatutils11.h"

#include "third_party/murmurhash/MurmurHash3.h"

namespace rx
{

static void GetInputLayout(const TranslatedAttribute translatedAttributes[gl::MAX_VERTEX_ATTRIBS],
                           gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS])
{
    for (unsigned int attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++)
    {
        const TranslatedAttribute &translatedAttribute = translatedAttributes[attributeIndex];

        if (translatedAttributes[attributeIndex].active)
        {
            inputLayout[attributeIndex] = gl::VertexFormat(*translatedAttribute.attribute,
                                                           translatedAttribute.currentValueType);
        }
    }
}

const unsigned int InputLayoutCache::kMaxInputLayouts = 1024;

InputLayoutCache::InputLayoutCache() : mInputLayoutMap(kMaxInputLayouts, hashInputLayout, compareInputLayouts)
{
    mCounter = 0;
    mDevice = NULL;
    mDeviceContext = NULL;
    mCurrentIL = NULL;
    for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
    {
        mCurrentBuffers[i] = NULL;
        mCurrentVertexStrides[i] = -1;
        mCurrentVertexOffsets[i] = -1;
    }
}

InputLayoutCache::~InputLayoutCache()
{
    clear();
}

void InputLayoutCache::initialize(ID3D11Device *device, ID3D11DeviceContext *context)
{
    clear();
    mDevice = device;
    mDeviceContext = context;
}

void InputLayoutCache::clear()
{
    for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++)
    {
        SafeRelease(i->second.inputLayout);
    }
    mInputLayoutMap.clear();
    markDirty();
}

void InputLayoutCache::markDirty()
{
    mCurrentIL = NULL;
    for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
    {
        mCurrentBuffers[i] = NULL;
        mCurrentVertexStrides[i] = -1;
        mCurrentVertexOffsets[i] = -1;
    }
}

GLenum InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS],
                                            gl::ProgramBinary *programBinary)
{
    int sortedSemanticIndices[gl::MAX_VERTEX_ATTRIBS];
    programBinary->sortAttributesByLayout(attributes, sortedSemanticIndices);

    if (!mDevice || !mDeviceContext)
    {
        ERR("InputLayoutCache is not initialized.");
        return GL_INVALID_OPERATION;
    }

    InputLayoutKey ilKey = { 0 };

    static const char* semanticName = "TEXCOORD";

    for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
    {
        if (attributes[i].active)
        {
            D3D11_INPUT_CLASSIFICATION inputClass = attributes[i].divisor > 0 ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA;

            gl::VertexFormat vertexFormat(*attributes[i].attribute, attributes[i].currentValueType);
            DXGI_FORMAT dxgiFormat = gl_d3d11::GetNativeVertexFormat(vertexFormat);

            // Record the type of the associated vertex shader vector in our key
            // This will prevent mismatched vertex shaders from using the same input layout
            GLint attributeSize;
            programBinary->getActiveAttribute(ilKey.elementCount, 0, NULL, &attributeSize, &ilKey.elements[ilKey.elementCount].glslElementType, NULL);

            ilKey.elements[ilKey.elementCount].desc.SemanticName = semanticName;
            ilKey.elements[ilKey.elementCount].desc.SemanticIndex = sortedSemanticIndices[i];
            ilKey.elements[ilKey.elementCount].desc.Format = dxgiFormat;
            ilKey.elements[ilKey.elementCount].desc.InputSlot = i;
            ilKey.elements[ilKey.elementCount].desc.AlignedByteOffset = 0;
            ilKey.elements[ilKey.elementCount].desc.InputSlotClass = inputClass;
            ilKey.elements[ilKey.elementCount].desc.InstanceDataStepRate = attributes[i].divisor;
            ilKey.elementCount++;
        }
    }

    ID3D11InputLayout *inputLayout = NULL;

    InputLayoutMap::iterator keyIter = mInputLayoutMap.find(ilKey);
    if (keyIter != mInputLayoutMap.end())
    {
        inputLayout = keyIter->second.inputLayout;
        keyIter->second.lastUsedTime = mCounter++;
    }
    else
    {
        gl::VertexFormat shaderInputLayout[gl::MAX_VERTEX_ATTRIBS];
        GetInputLayout(attributes, shaderInputLayout);
        ShaderExecutable11 *shader = ShaderExecutable11::makeShaderExecutable11(programBinary->getVertexExecutableForInputLayout(shaderInputLayout));

        D3D11_INPUT_ELEMENT_DESC descs[gl::MAX_VERTEX_ATTRIBS];
        for (unsigned int j = 0; j < ilKey.elementCount; ++j)
        {
            descs[j] = ilKey.elements[j].desc;
        }

        HRESULT result = mDevice->CreateInputLayout(descs, ilKey.elementCount, shader->getFunction(), shader->getLength(), &inputLayout);
        if (FAILED(result))
        {
            ERR("Failed to crate input layout, result: 0x%08x", result);
            return GL_INVALID_OPERATION;
        }

        if (mInputLayoutMap.size() >= kMaxInputLayouts)
        {
            TRACE("Overflowed the limit of %u input layouts, removing the least recently used "
                  "to make room.", kMaxInputLayouts);

            InputLayoutMap::iterator leastRecentlyUsed = mInputLayoutMap.begin();
            for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++)
            {
                if (i->second.lastUsedTime < leastRecentlyUsed->second.lastUsedTime)
                {
                    leastRecentlyUsed = i;
                }
            }
            SafeRelease(leastRecentlyUsed->second.inputLayout);
            mInputLayoutMap.erase(leastRecentlyUsed);
        }

        InputLayoutCounterPair inputCounterPair;
        inputCounterPair.inputLayout = inputLayout;
        inputCounterPair.lastUsedTime = mCounter++;

        mInputLayoutMap.insert(std::make_pair(ilKey, inputCounterPair));
    }

    if (inputLayout != mCurrentIL)
    {
        mDeviceContext->IASetInputLayout(inputLayout);
        mCurrentIL = inputLayout;
    }

    for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
    {
        ID3D11Buffer *buffer = NULL;

        if (attributes[i].active)
        {
            VertexBuffer11 *vertexBuffer = VertexBuffer11::makeVertexBuffer11(attributes[i].vertexBuffer);
            BufferStorage11 *bufferStorage = attributes[i].storage ? BufferStorage11::makeBufferStorage11(attributes[i].storage) : NULL;

            buffer = bufferStorage ? bufferStorage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK)
                                   : vertexBuffer->getBuffer();
        }

        UINT vertexStride = attributes[i].stride;
        UINT vertexOffset = attributes[i].offset;

        if (buffer != mCurrentBuffers[i] || vertexStride != mCurrentVertexStrides[i] ||
            vertexOffset != mCurrentVertexOffsets[i])
        {
            mDeviceContext->IASetVertexBuffers(i, 1, &buffer, &vertexStride, &vertexOffset);
            mCurrentBuffers[i] = buffer;
            mCurrentVertexStrides[i] = vertexStride;
            mCurrentVertexOffsets[i] = vertexOffset;
        }
    }

    return GL_NO_ERROR;
}

std::size_t InputLayoutCache::hashInputLayout(const InputLayoutKey &inputLayout)
{
    static const unsigned int seed = 0xDEADBEEF;

    std::size_t hash = 0;
    MurmurHash3_x86_32(inputLayout.begin(), inputLayout.end() - inputLayout.begin(), seed, &hash);
    return hash;
}

bool InputLayoutCache::compareInputLayouts(const InputLayoutKey &a, const InputLayoutKey &b)
{
    if (a.elementCount != b.elementCount)
    {
        return false;
    }

    return std::equal(a.begin(), a.end(), b.begin());
}

}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Emilian Cioca
#include "Jewel3D/Precompiled.h"
#include "Quaternion.h"
#include "Math.h"
#include "Matrix.h"
#include "Vector.h"
#include "Jewel3D/Application/Logging.h"

namespace Jwl
{
	const quat quat::Identity = quat();

	quat::quat(float X, float Y, float Z, float W)
		: x(X), y(Y), z(Z), w(W)
	{
	}

	quat::quat(const vec3& right, const vec3& up, const vec3& forward)
	{
		*this = quat(mat3(right, up, forward));
	}

	quat::quat(const mat3& rotation)
	{
		float trace = rotation.data[0] + rotation.data[4] + rotation.data[8];

		if (trace > 0.0f)
		{
			float S = sqrtf(trace + 1.0f) * 2.0f;
			x = (rotation.data[5] - rotation.data[7]) / S;
			y = (rotation.data[6] - rotation.data[2]) / S;
			z = (rotation.data[1] - rotation.data[3]) / S;
			w = 0.25f * S;
		}
		else if ((rotation.data[0] > rotation.data[4]) && (rotation.data[0] > rotation.data[8]))
		{
			float S = sqrtf(1.0f + rotation.data[0] - rotation.data[4] - rotation.data[8]) * 2.0f;
			x = 0.25f * S;
			y = (rotation.data[3] + rotation.data[1]) / S;
			z = (rotation.data[6] + rotation.data[2]) / S;
			w = (rotation.data[5] - rotation.data[7]) / S;
		}
		else if (rotation.data[4] > rotation.data[8])
		{
			float S = sqrtf(1.0f + rotation.data[4] - rotation.data[0] - rotation.data[8]) * 2.0f;
			x = (rotation.data[3] + rotation.data[1]) / S;
			y = 0.25f * S;
			z = (rotation.data[7] + rotation.data[5]) / S;
			w = (rotation.data[6] - rotation.data[2]) / S;
		}
		else
		{
			float S = sqrtf(1.0f + rotation.data[8] - rotation.data[0] - rotation.data[4]) * 2.0f;
			x = (rotation.data[6] + rotation.data[2]) / S;
			y = (rotation.data[7] + rotation.data[5]) / S;
			z = 0.25f * S;
			w = (rotation.data[1] - rotation.data[3]) / S;
		}

		Normalize();
	}

	bool quat::operator==(const quat& other) const
	{
		return
			Equals(x, other.x) &&
			Equals(y, other.y) &&
			Equals(z, other.z) &&
			Equals(w, other.w);
	}

	bool quat::operator!=(const quat& other) const
	{
		return
			!Equals(x, other.x) ||
			!Equals(y, other.y) ||
			!Equals(z, other.z) ||
			!Equals(w, other.w);
	}

	quat quat::operator*(const quat& other) const
	{
		return quat(
			w * other.x + x * other.w + y * other.z - z * other.y,
			w * other.y - x * other.z + y * other.w + z * other.x,
			w * other.z + x * other.y - y * other.x + z * other.w,
			w * other.w - x * other.x - y * other.y - z * other.z);
	}

	vec3 quat::operator*(const vec3& v) const
	{
		vec3 q = vec3(x, y, z);

		return 2.0f * Dot(q, v) * q
			+ (w * w - Dot(q, q)) * v
			+ 2.0f * w * Cross(q, v);
	}

	quat& quat::operator*=(const quat& other)
	{
		*this = (*this) * other;

		return *this;
	}

	float quat::operator[](unsigned index) const
	{
		return *(&x + index);
	}

	float& quat::operator[](unsigned index)
	{
		return *(&x + index);
	}

	void quat::SetIdentity()
	{
		x = 0.0f;
		y = 0.0f;
		z = 0.0f;
		w = 1.0f;
	}

	void quat::Conjugate()
	{
		x *= -1.0f;
		y *= -1.0f;
		z *= -1.0f;
	}

	quat quat::GetConjugate() const
	{
		return quat(-z, -y, -z, w);
	}

	void quat::Normalize()
	{
		float invLength = 1.0f / sqrt(x * x + y * y + z * z + w * w);

		ASSERT(!std::isinf(invLength), "Zero length quaternion cannot be normalized.");

		x *= invLength;
		y *= invLength;
		z *= invLength;
		w *= invLength;
	}

	quat quat::GetNormalized() const
	{
		float invLength = 1.0f / sqrt(x * x + y * y + z * z + w * w);

		ASSERT(!std::isinf(invLength), "Zero length quaternion cannot be normalized.");

		return quat(x * invLength, y * invLength, z * invLength, w * invLength);
	}

	vec3 quat::GetRight() const
	{
		return *this * vec3::Right;
	}

	vec3 quat::GetUp() const
	{
		return *this * vec3::Up;
	}

	vec3 quat::GetForward() const
	{
		return *this * vec3::Forward;
	}

	void quat::Rotate(const vec3& axis, float degrees)
	{
		float radians = ToRadian(degrees) / 2.0f;
		vec3 temp = axis * sin(radians);

		*this = quat(temp.x, temp.y, temp.z, cos(radians)) * (*this);
	}

	void quat::Rotate(float X, float Y, float Z, float degrees)
	{
		float radians = ToRadian(degrees) / 2.0f;

		float sRadians = sin(radians);
		*this = quat(X * sRadians, Y * sRadians, Z * sRadians, cos(radians)) * (*this);
	}

	void quat::RotateX(float degrees)
	{
		float radians = ToRadian(degrees) / 2.0f;

		*this = quat(sin(radians), 0.0f, 0.0f, cos(radians)) * (*this);
	}

	void quat::RotateY(float degrees)
	{
		float radians = ToRadian(degrees) / 2.0f;

		*this = quat(0.0f, sin(radians), 0.0f, cos(radians)) * (*this);
	}

	void quat::RotateZ(float degrees)
	{
		float radians = ToRadian(degrees) / 2.0f;

		*this = quat(0.0f, 0.0f, sin(radians), cos(radians)) * (*this);
	}

	float Dot(const quat& p0, const quat& p1)
	{
		return p0.x * p1.x + p0.y * p1.y + p0.z * p1.z + p0.w * p1.w;
	}

	quat Slerp(const quat& p0, const quat& p1, float percent)
	{
		float dot = Abs(Dot(p0, p1));
		if (dot == 1.0f)
		{
			// Quaternions are the same.
			return p0;
		}

		float angle = acos(dot);
		float sAngle = sin(angle);
		float coef1 = sin((1.0f - percent) * angle) / sAngle;
		float coef2 = sin(percent * angle) / sAngle;

		return quat(
			coef1 * p0.x + coef2 * p1.x,
			coef1 * p0.y + coef2 * p1.y,
			coef1 * p0.z + coef2 * p1.z,
			coef1 * p0.w + coef2 * p1.w).GetNormalized();
	}
}
<commit_msg>Fixed calculation error in quat::GetConjugate()<commit_after>// Copyright (c) 2017 Emilian Cioca
#include "Jewel3D/Precompiled.h"
#include "Quaternion.h"
#include "Math.h"
#include "Matrix.h"
#include "Vector.h"
#include "Jewel3D/Application/Logging.h"

namespace Jwl
{
	const quat quat::Identity = quat();

	quat::quat(float X, float Y, float Z, float W)
		: x(X), y(Y), z(Z), w(W)
	{
	}

	quat::quat(const vec3& right, const vec3& up, const vec3& forward)
	{
		*this = quat(mat3(right, up, forward));
	}

	quat::quat(const mat3& rotation)
	{
		float trace = rotation.data[0] + rotation.data[4] + rotation.data[8];

		if (trace > 0.0f)
		{
			float S = sqrtf(trace + 1.0f) * 2.0f;
			x = (rotation.data[5] - rotation.data[7]) / S;
			y = (rotation.data[6] - rotation.data[2]) / S;
			z = (rotation.data[1] - rotation.data[3]) / S;
			w = 0.25f * S;
		}
		else if ((rotation.data[0] > rotation.data[4]) && (rotation.data[0] > rotation.data[8]))
		{
			float S = sqrtf(1.0f + rotation.data[0] - rotation.data[4] - rotation.data[8]) * 2.0f;
			x = 0.25f * S;
			y = (rotation.data[3] + rotation.data[1]) / S;
			z = (rotation.data[6] + rotation.data[2]) / S;
			w = (rotation.data[5] - rotation.data[7]) / S;
		}
		else if (rotation.data[4] > rotation.data[8])
		{
			float S = sqrtf(1.0f + rotation.data[4] - rotation.data[0] - rotation.data[8]) * 2.0f;
			x = (rotation.data[3] + rotation.data[1]) / S;
			y = 0.25f * S;
			z = (rotation.data[7] + rotation.data[5]) / S;
			w = (rotation.data[6] - rotation.data[2]) / S;
		}
		else
		{
			float S = sqrtf(1.0f + rotation.data[8] - rotation.data[0] - rotation.data[4]) * 2.0f;
			x = (rotation.data[6] + rotation.data[2]) / S;
			y = (rotation.data[7] + rotation.data[5]) / S;
			z = 0.25f * S;
			w = (rotation.data[1] - rotation.data[3]) / S;
		}

		Normalize();
	}

	bool quat::operator==(const quat& other) const
	{
		return
			Equals(x, other.x) &&
			Equals(y, other.y) &&
			Equals(z, other.z) &&
			Equals(w, other.w);
	}

	bool quat::operator!=(const quat& other) const
	{
		return
			!Equals(x, other.x) ||
			!Equals(y, other.y) ||
			!Equals(z, other.z) ||
			!Equals(w, other.w);
	}

	quat quat::operator*(const quat& other) const
	{
		return quat(
			w * other.x + x * other.w + y * other.z - z * other.y,
			w * other.y - x * other.z + y * other.w + z * other.x,
			w * other.z + x * other.y - y * other.x + z * other.w,
			w * other.w - x * other.x - y * other.y - z * other.z);
	}

	vec3 quat::operator*(const vec3& v) const
	{
		vec3 q = vec3(x, y, z);

		return 2.0f * Dot(q, v) * q
			+ (w * w - Dot(q, q)) * v
			+ 2.0f * w * Cross(q, v);
	}

	quat& quat::operator*=(const quat& other)
	{
		*this = (*this) * other;

		return *this;
	}

	float quat::operator[](unsigned index) const
	{
		return *(&x + index);
	}

	float& quat::operator[](unsigned index)
	{
		return *(&x + index);
	}

	void quat::SetIdentity()
	{
		x = 0.0f;
		y = 0.0f;
		z = 0.0f;
		w = 1.0f;
	}

	void quat::Conjugate()
	{
		x *= -1.0f;
		y *= -1.0f;
		z *= -1.0f;
	}

	quat quat::GetConjugate() const
	{
		return quat(-x, -y, -z, w);
	}

	void quat::Normalize()
	{
		float invLength = 1.0f / sqrt(x * x + y * y + z * z + w * w);

		ASSERT(!std::isinf(invLength), "Zero length quaternion cannot be normalized.");

		x *= invLength;
		y *= invLength;
		z *= invLength;
		w *= invLength;
	}

	quat quat::GetNormalized() const
	{
		float invLength = 1.0f / sqrt(x * x + y * y + z * z + w * w);

		ASSERT(!std::isinf(invLength), "Zero length quaternion cannot be normalized.");

		return quat(x * invLength, y * invLength, z * invLength, w * invLength);
	}

	vec3 quat::GetRight() const
	{
		return *this * vec3::Right;
	}

	vec3 quat::GetUp() const
	{
		return *this * vec3::Up;
	}

	vec3 quat::GetForward() const
	{
		return *this * vec3::Forward;
	}

	void quat::Rotate(const vec3& axis, float degrees)
	{
		float radians = ToRadian(degrees) / 2.0f;
		vec3 temp = axis * sin(radians);

		*this = quat(temp.x, temp.y, temp.z, cos(radians)) * (*this);
	}

	void quat::Rotate(float X, float Y, float Z, float degrees)
	{
		float radians = ToRadian(degrees) / 2.0f;

		float sRadians = sin(radians);
		*this = quat(X * sRadians, Y * sRadians, Z * sRadians, cos(radians)) * (*this);
	}

	void quat::RotateX(float degrees)
	{
		float radians = ToRadian(degrees) / 2.0f;

		*this = quat(sin(radians), 0.0f, 0.0f, cos(radians)) * (*this);
	}

	void quat::RotateY(float degrees)
	{
		float radians = ToRadian(degrees) / 2.0f;

		*this = quat(0.0f, sin(radians), 0.0f, cos(radians)) * (*this);
	}

	void quat::RotateZ(float degrees)
	{
		float radians = ToRadian(degrees) / 2.0f;

		*this = quat(0.0f, 0.0f, sin(radians), cos(radians)) * (*this);
	}

	float Dot(const quat& p0, const quat& p1)
	{
		return p0.x * p1.x + p0.y * p1.y + p0.z * p1.z + p0.w * p1.w;
	}

	quat Slerp(const quat& p0, const quat& p1, float percent)
	{
		float dot = Abs(Dot(p0, p1));
		if (dot == 1.0f)
		{
			// Quaternions are the same.
			return p0;
		}

		float angle = acos(dot);
		float sAngle = sin(angle);
		float coef1 = sin((1.0f - percent) * angle) / sAngle;
		float coef2 = sin(percent * angle) / sAngle;

		return quat(
			coef1 * p0.x + coef2 * p1.x,
			coef1 * p0.y + coef2 * p1.y,
			coef1 * p0.z + coef2 * p1.z,
			coef1 * p0.w + coef2 * p1.w).GetNormalized();
	}
}
<|endoftext|>


<commit_before>#include "InventoryTransitions.h"

#include <sstream>

#include "ExtendedInventoryScreen.h"

#include "com/mojang/minecraftpe/client/gui/screen/Screen.h"
#include "com/mojang/minecraftpe/client/gui/screen/InventoryScreen.h"
#include "com/mojang/minecraftpe/client/gui/screen/ScreenChooser.h"
#include "com/mojang/minecraftpe/client/gui/Gui.h"
#include "com/mojang/minecraftpe/client/MinecraftClient.h"

std::shared_ptr<Touch::TButton> InventoryTransitions::forwardButton = NULL;
std::shared_ptr<Touch::TButton> InventoryTransitions::backButton = NULL;

int InventoryTransitions::currentPage = 1;

std::vector<std::shared_ptr<Screen>> InventoryTransitions::pages;

bool InventoryTransitions::canPress = true;

void InventoryTransitions::init(Screen* self)
{
	if(!forwardButton)
	{
		forwardButton = std::make_shared<Touch::TButton>(0, ">", self->mcClient, false, 0x7FFFFFFF);
		forwardButton->init(self->mcClient);
	}

	if(!backButton)
	{
		backButton = std::make_shared<Touch::TButton>(1, "<", self->mcClient, false, 0x7FFFFFFF);
		backButton->init(self->mcClient);
	}

	if(pages.empty())
	{
		pages.emplace_back(std::make_shared<ExtendedInventoryScreen>(*(self->mcClient)));
		pages.emplace_back(std::make_shared<ExtendedInventoryScreen>(*(self->mcClient)));
		pages.emplace_back(std::make_shared<ExtendedInventoryScreen>(*(self->mcClient)));
		pages.emplace_back(std::make_shared<ExtendedInventoryScreen>(*(self->mcClient)));
		pages.emplace_back(std::make_shared<ExtendedInventoryScreen>(*(self->mcClient)));
	}

	self->buttonList.emplace_back(forwardButton);
	self->buttonList.emplace_back(backButton);
}

void InventoryTransitions::setupPositions(Screen* self)
{
	forwardButton->xPosition = self->width - 25;
	forwardButton->yPosition = self->height - 20;
	forwardButton->width = 20;
	forwardButton->height = 20;

	backButton->xPosition = self->width - 50;
	backButton->yPosition = self->height - 20;
	backButton->width = 20;
	backButton->height = 20;
}

void InventoryTransitions::render(Screen* self, int i1, int i2, float f1)
{
	std::ostringstream pageNum;
	pageNum << currentPage << " / " << pages.size() + 1;
	self->drawString(self->font, pageNum.str(), 5, self->height - 15, Color::WHITE);

	if(!canPress)
		canPress = true;

	if(currentPage == 1)
		backButton->enabled = false;
}

void InventoryTransitions::_buttonClicked(Screen* self, Button& button)
{
	if(canPress)
	{
		if(button.id == forwardButton->id)
			pushNextScreen(self);

		if(button.id == backButton->id)
			pushPreviousScreen(self);
	}
}

void InventoryTransitions::pushNextScreen(Screen* self)
{
	if(currentPage <= pages.size()) // if the currentPage is not the last page, push the next page
	{
		self->mcClient->getScreenChooser()->_pushScreen(pages[currentPage - 1], false);
		currentPage++; // increase the current page by 1
		canPress = false;
	}

	if(currentPage == pages.size() + 1)
		forwardButton->enabled = false;

	if(currentPage >= 2)
		backButton->enabled = true;
}

void InventoryTransitions::pushPreviousScreen(Screen* self)
{
	if(currentPage > 1) // if greater than the first page, pop the currentPage and push the previous page
	{
		self->mcClient->getScreenChooser()->popScreen(*self, 1);
		currentPage--; // reduce the currentPage by 1
		canPress = false;
	}

	if(currentPage <= pages.size())
		forwardButton->enabled = true;

	if(currentPage == 1)
		backButton->enabled = false;
}
<commit_msg>Fixed a bug<commit_after>#include "InventoryTransitions.h"

#include <sstream>

#include "ExtendedInventoryScreen.h"

#include "com/mojang/minecraftpe/client/gui/screen/Screen.h"
#include "com/mojang/minecraftpe/client/gui/screen/InventoryScreen.h"
#include "com/mojang/minecraftpe/client/gui/screen/ScreenChooser.h"
#include "com/mojang/minecraftpe/client/gui/Gui.h"
#include "com/mojang/minecraftpe/client/MinecraftClient.h"

std::shared_ptr<Touch::TButton> InventoryTransitions::forwardButton = NULL;
std::shared_ptr<Touch::TButton> InventoryTransitions::backButton = NULL;

int InventoryTransitions::currentPage = 1;

std::vector<std::shared_ptr<Screen>> InventoryTransitions::pages;

bool InventoryTransitions::canPress = true;

void InventoryTransitions::init(Screen* self)
{
	if(!forwardButton)
	{
		forwardButton = std::make_shared<Touch::TButton>(0, ">", self->mcClient, false, 0x7FFFFFFF);
		forwardButton->init(self->mcClient);
	}

	if(!backButton)
	{
		backButton = std::make_shared<Touch::TButton>(1, "<", self->mcClient, false, 0x7FFFFFFF);
		backButton->init(self->mcClient);
	}

	if(pages.empty())
	{
		pages.emplace_back(std::make_shared<ExtendedInventoryScreen>(*(self->mcClient)));
		pages.emplace_back(std::make_shared<ExtendedInventoryScreen>(*(self->mcClient)));
		pages.emplace_back(std::make_shared<ExtendedInventoryScreen>(*(self->mcClient)));
		pages.emplace_back(std::make_shared<ExtendedInventoryScreen>(*(self->mcClient)));
		pages.emplace_back(std::make_shared<ExtendedInventoryScreen>(*(self->mcClient)));
	}

	self->buttonList.emplace_back(forwardButton);
	self->buttonList.emplace_back(backButton);
}

void InventoryTransitions::setupPositions(Screen* self)
{
	forwardButton->xPosition = self->width - 25;
	forwardButton->yPosition = self->height - 20;
	forwardButton->width = 20;
	forwardButton->height = 20;

	backButton->xPosition = self->width - 50;
	backButton->yPosition = self->height - 20;
	backButton->width = 20;
	backButton->height = 20;
}

void InventoryTransitions::render(Screen* self, int i1, int i2, float f1)
{
	std::ostringstream pageNum;
	pageNum << currentPage << " / " << pages.size() + 1;
	self->drawString(self->font, pageNum.str(), 5, self->height - 15, Color::WHITE);

	if(!canPress)
		canPress = true;

	if(currentPage == 1)
	{
		backButton->enabled = false;
		forwardButton->enabled = true;
	}
}

void InventoryTransitions::_buttonClicked(Screen* self, Button& button)
{
	if(canPress)
	{
		if(button.id == forwardButton->id)
			pushNextScreen(self);

		if(button.id == backButton->id)
			pushPreviousScreen(self);
	}
}

void InventoryTransitions::pushNextScreen(Screen* self)
{
	if(currentPage <= pages.size()) // if the currentPage is not the last page, push the next page
	{
		self->mcClient->getScreenChooser()->_pushScreen(pages[currentPage - 1], false);
		currentPage++; // increase the current page by 1
		canPress = false;
	}

	if(currentPage == pages.size() + 1)
		forwardButton->enabled = false;

	if(currentPage >= 2)
		backButton->enabled = true;
}

void InventoryTransitions::pushPreviousScreen(Screen* self)
{
	if(currentPage > 1) // if greater than the first page, pop the currentPage and push the previous page
	{
		self->mcClient->getScreenChooser()->popScreen(*self, 1);
		currentPage--; // reduce the currentPage by 1
		canPress = false;
	}

	if(currentPage <= pages.size())
		forwardButton->enabled = true;

	if(currentPage == 1)
		backButton->enabled = false;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2011, Tim Branyen @tbranyen <tim@tabdeveloper.com>
 * @author Michael Robinson @codeofinterest <mike@pagesofinterest.net>
 *
 * Dual licensed under the MIT and GPL licenses.
 */

#include <v8.h>
#include <node.h>
#include <string>

#include "../vendor/libgit2/include/git2.h"

#include "../include/repo.h"
#include "../include/reference.h"
#include "../include/oid.h"
#include "../include/error.h"

#include "../include/functions/string.h"
#include "../include/functions/utilities.h"

using namespace v8;
using namespace node;

void GitReference::Initialize(Handle<Object> target) {
  HandleScope scope;

  Local<FunctionTemplate> tpl = FunctionTemplate::New(New);

  tpl->InstanceTemplate()->SetInternalFieldCount(1);
  tpl->SetClassName(String::NewSymbol("Reference"));

  NODE_SET_PROTOTYPE_METHOD(tpl, "oid", Oid);
  NODE_SET_PROTOTYPE_METHOD(tpl, "lookup", Lookup);

  constructor_template = Persistent<Function>::New(tpl->GetFunction());
  target->Set(String::NewSymbol("Reference"), constructor_template);
}

git_reference* GitReference::GetValue() {
  return this->ref;
}
void GitReference::SetValue(git_reference *ref) {
  this->ref = ref;
}

Handle<Value> GitReference::New(const Arguments& args) {
  HandleScope scope;

  GitReference *ref = new GitReference();

  ref->Wrap(args.This());

  return args.This();
}

Handle<Value> GitReference::Oid(const Arguments& args) {
  HandleScope scope;

  if(args.Length() == 0 || !args[0]->IsFunction()) {
    return ThrowException(Exception::Error(String::New("Callback is required and must be a Function.")));
  }

  OidBaton *baton = new OidBaton;
  baton->request.data = baton;
  baton->error = NULL;
  baton->rawOid = NULL;
  baton->rawRef = ObjectWrap::Unwrap<GitReference>(args.This())->GetValue();
  baton->callback = Persistent<Function>::New(Local<Function>::Cast(args[0]));

  uv_queue_work(uv_default_loop(), &baton->request, OidWork, (uv_after_work_cb)OidAfterWork);

  return Undefined();
}
void GitReference::OidWork(uv_work_t* req) {
  OidBaton *baton = static_cast<OidBaton *>(req->data);

  git_ref_t referenceType = git_reference_type(baton->rawRef);

  if (referenceType == GIT_REF_INVALID) {
    giterr_set_str(GITERR_INVALID, "Invalid reference type");
    baton->error = giterr_last();
    return;
  }

  if (referenceType == GIT_REF_SYMBOLIC) {
    int returnCode = git_reference_resolve(&baton->rawRef, baton->rawRef);
    if (returnCode != GIT_OK) {
      baton->error = giterr_last();
      return;
    }
  }
}
void GitReference::OidAfterWork(uv_work_t* req) {
  HandleScope scope;
  OidBaton *baton = static_cast<OidBaton *>(req->data);

  if (success(baton->error, baton->callback)) {
    Handle<Object> oid = GitOid::constructor_template->NewInstance();
    GitOid *oidInstance = ObjectWrap::Unwrap<GitOid>(oid);
    oidInstance->SetValue(*const_cast<git_oid *>(baton->rawOid));

    Handle<Value> argv[2] = {
      Local<Value>::New(Null()),
      oid
    };

    TryCatch try_catch;
    baton->callback->Call(Context::GetCurrent()->Global(), 2, argv);
    if (try_catch.HasCaught()) {
      node::FatalException(try_catch);
    }
  }

  delete req;
}

Handle<Value> GitReference::Lookup(const Arguments& args) {
  HandleScope scope;

  if(args.Length() == 0 || !args[0]->IsObject()) {
    return ThrowException(Exception::Error(String::New("Repo is required and must be a Object.")));
  }

  if(args.Length() == 1 || !args[1]->IsString()) {
    return ThrowException(Exception::Error(String::New("Name is required and must be a String.")));
  }

  if(args.Length() == 2 || !args[2]->IsFunction()) {
    return ThrowException(Exception::Error(String::New("Callback is required and must be a Function.")));
  }

  LookupBaton *baton = new LookupBaton;
  baton->request.data = baton;
  baton->ref = ObjectWrap::Unwrap<GitReference>(args.This());
  baton->ref->Ref();
  baton->error = NULL;
  baton->rawRepo = ObjectWrap::Unwrap<GitRepo>(args[0]->ToObject())->GetValue();
  baton->name = stringArgToString(args[1]->ToString());
  baton->callback = Persistent<Function>::New(Local<Function>::Cast(args[2]));

  uv_queue_work(uv_default_loop(), &baton->request, LookupWork, (uv_after_work_cb)LookupAfterWork);

  return Undefined();
}

void GitReference::LookupWork(uv_work_t *req) {
  LookupBaton *baton = static_cast<LookupBaton *>(req->data);

  baton->rawRef = NULL;
  int returnCode = git_reference_lookup(&baton->rawRef, baton->rawRepo, baton->name.c_str());
  if (returnCode != GIT_OK) {
    baton->error = giterr_last();
  }
}

void GitReference::LookupAfterWork(uv_work_t *req) {
  HandleScope scope;
  LookupBaton *baton = static_cast<LookupBaton *>(req->data);

  if (baton->error) {
    Local<Value> argv[1] = {
      GitError::WrapError(baton->error)
    };

    TryCatch try_catch;
    baton->callback->Call(Context::GetCurrent()->Global(), 1, argv);
    if (try_catch.HasCaught()) {
      node::FatalException(try_catch);
    }
  } else {

    baton->ref->SetValue(baton->rawRef);

    Handle<Value> argv[2] = {
      Local<Value>::New(Null()),
      baton->ref->handle_
    };

    TryCatch try_catch;
    baton->callback->Call(Context::GetCurrent()->Global(), 2, argv);
    if (try_catch.HasCaught()) {
      node::FatalException(try_catch);
    }
  }

  baton->ref->Unref();
  delete req;
}

Persistent<Function> GitReference::constructor_template;
<commit_msg>Updated reference.cc<commit_after>/*
 * Copyright 2011, Tim Branyen @tbranyen <tim@tabdeveloper.com>
 * @author Michael Robinson @codeofinterest <mike@pagesofinterest.net>
 *
 * Dual licensed under the MIT and GPL licenses.
 */

#include <v8.h>
#include <node.h>
#include <string>

#include "../vendor/libgit2/include/git2.h"

#include "../include/repo.h"
#include "../include/reference.h"
#include "../include/oid.h"
#include "../include/error.h"

#include "../include/functions/string.h"
#include "../include/functions/utilities.h"

using namespace v8;
using namespace node;

void GitReference::Initialize(Handle<Object> target) {
  HandleScope scope;

  Local<FunctionTemplate> tpl = FunctionTemplate::New(New);

  tpl->InstanceTemplate()->SetInternalFieldCount(1);
  tpl->SetClassName(String::NewSymbol("Reference"));

  NODE_SET_PROTOTYPE_METHOD(tpl, "oid", Oid);
  NODE_SET_PROTOTYPE_METHOD(tpl, "lookup", Lookup);

  constructor_template = Persistent<Function>::New(tpl->GetFunction());
  target->Set(String::NewSymbol("Reference"), constructor_template);
}

git_reference* GitReference::GetValue() {
  return this->ref;
}
void GitReference::SetValue(git_reference *ref) {
  this->ref = ref;
}

Handle<Value> GitReference::New(const Arguments& args) {
  HandleScope scope;

  GitReference *ref = new GitReference();

  ref->Wrap(args.This());

  return args.This();
}

Handle<Value> GitReference::Oid(const Arguments& args) {
  HandleScope scope;

  if(args.Length() == 0 || !args[0]->IsFunction()) {
    return ThrowException(Exception::Error(String::New("Callback is required and must be a Function.")));
  }

  OidBaton *baton = new OidBaton;
  baton->request.data = baton;
  baton->error = NULL;
  baton->rawOid = NULL;
  baton->rawRef = ObjectWrap::Unwrap<GitReference>(args.This())->GetValue();
  baton->callback = Persistent<Function>::New(Local<Function>::Cast(args[0]));

  uv_queue_work(uv_default_loop(), &baton->request, OidWork, (uv_after_work_cb)OidAfterWork);

  return Undefined();
}
void GitReference::OidWork(uv_work_t* req) {
  OidBaton *baton = static_cast<OidBaton *>(req->data);

  git_ref_t referenceType = git_reference_type(baton->rawRef);

  if (referenceType == GIT_REF_INVALID) {
    giterr_set_str(GITERR_INVALID, "Invalid reference type");
    baton->error = giterr_last();
    return;
  }

  if (referenceType == GIT_REF_SYMBOLIC) {
    int returnCode = git_reference_resolve(&baton->rawRef, baton->rawRef);
    if (returnCode != GIT_OK) {
      baton->error = giterr_last();
      return;
    }
  }
}
void GitReference::OidAfterWork(uv_work_t* req) {
  HandleScope scope;
  OidBaton *baton = static_cast<OidBaton *>(req->data);

  if (success(baton->error, baton->callback)) {
    Handle<Object> oid = GitOid::constructor_template->NewInstance();
    GitOid *oidInstance = ObjectWrap::Unwrap<GitOid>(oid);
    oidInstance->SetValue(*const_cast<git_oid *>(baton->rawOid));

    Handle<Value> argv[2] = {
      Local<Value>::New(Null()),
      oid
    };

    TryCatch try_catch;
    baton->callback->Call(Context::GetCurrent()->Global(), 2, argv);
    if (try_catch.HasCaught()) {
      node::FatalException(try_catch);
    }
  }

  delete req;
}

Handle<Value> GitReference::Lookup(const Arguments& args) {
  HandleScope scope;

  if(args.Length() == 0 || !args[0]->IsObject()) {
    return ThrowException(Exception::Error(String::New("Repo is required and must be a Object.")));
  }

  if(args.Length() == 1 || !args[1]->IsString()) {
    return ThrowException(Exception::Error(String::New("Name is required and must be a String.")));
  }

  if(args.Length() == 2 || !args[2]->IsFunction()) {
    return ThrowException(Exception::Error(String::New("Callback is required and must be a Function.")));
  }

  LookupBaton *baton = new LookupBaton;
  baton->request.data = baton;
  baton->ref = ObjectWrap::Unwrap<GitReference>(args.This());
  baton->ref->Ref();
  baton->error = NULL;
  baton->rawRepo = ObjectWrap::Unwrap<GitRepo>(args[0]->ToObject())->GetValue();
  baton->name = stringArgToString(args[1]->ToString());
  baton->callback = Persistent<Function>::New(Local<Function>::Cast(args[2]));

  uv_queue_work(uv_default_loop(), &baton->request, LookupWork, (uv_after_work_cb)LookupAfterWork);

  return Undefined();
}
void GitReference::LookupWork(uv_work_t *req) {
  LookupBaton *baton = static_cast<LookupBaton *>(req->data);

  baton->rawRef = NULL;
  int returnCode = git_reference_lookup(&baton->rawRef, baton->rawRepo, baton->name.c_str());
  if (returnCode != GIT_OK) {
    baton->error = giterr_last();
  }
}
void GitReference::LookupAfterWork(uv_work_t *req) {
  HandleScope scope;
  LookupBaton *baton = static_cast<LookupBaton *>(req->data);

  if (success(baton->error, baton->callback)) {
    baton->ref->SetValue(baton->rawRef);

    Handle<Value> argv[2] = {
      Local<Value>::New(Null()),
      baton->ref->handle_
    };

    TryCatch try_catch;
    baton->callback->Call(Context::GetCurrent()->Global(), 2, argv);
    if (try_catch.HasCaught()) {
      node::FatalException(try_catch);
    }
  }

  baton->ref->Unref();
  delete req;
}

Persistent<Function> GitReference::constructor_template;
<|endoftext|>


<commit_before>#include "util/misc.h"

#include "caffe2/core/db.h"
#include "caffe2/core/init.h"
#include "caffe2/core/operator_gradient.h"
#include "caffe2/utils/proto_utils.h"
#include "caffe2/zoo/keeper.h"

#include "res/imagenet_classes.h"

CAFFE2_DEFINE_string(model, "", "Name of one of the pre-trained models.");
CAFFE2_DEFINE_string(folder, "", "Folder with subfolders with images");

CAFFE2_DEFINE_string(db_type, "leveldb", "The database type.");
CAFFE2_DEFINE_int(size_to_fit, 224, "The image file.");
CAFFE2_DEFINE_int(train_runs, 1000, "The of training runs.");
CAFFE2_DEFINE_int(test_runs, 50, "The of training runs.");
CAFFE2_DEFINE_int(batch_size, 64, "Training batch size.");
CAFFE2_DEFINE_double(learning_rate, 1e-4, "Learning rate.");

CAFFE2_DEFINE_bool(zero_one, false, "Show zero-one for batch.");
CAFFE2_DEFINE_bool(show_worst, false,
                   "Show worst correct and incorrect classification.");

#include "util/cmd.h"

namespace caffe2 {

void run() {
  if (!cmd_init("Full Train Example")) {
    return;
  }

  if (!FLAGS_model.size()) {
    std::cerr << "specify a model name using --model <name>" << std::endl;
    for (auto const &pair : keeper_model_lookup) {
      std::cerr << "  " << pair.first << std::endl;
    }
    return;
  }

  if (!FLAGS_folder.size()) {
    std::cerr << "specify a image folder using --folder <name>" << std::endl;
    return;
  }

  std::cout << "model: " << FLAGS_model << std::endl;
  std::cout << "image_dir: " << FLAGS_folder << std::endl;
  std::cout << "db_type: " << FLAGS_db_type << std::endl;
  std::cout << "size_to_fit: " << FLAGS_size_to_fit << std::endl;
  std::cout << "train_runs: " << FLAGS_train_runs << std::endl;
  std::cout << "test_runs: " << FLAGS_test_runs << std::endl;
  std::cout << "batch_size: " << FLAGS_batch_size << std::endl;
  std::cout << "learning_rate: " << FLAGS_learning_rate << std::endl;
  std::cout << "zero_one: " << (FLAGS_zero_one ? "true" : "false") << std::endl;
  std::cout << "show_worst: " << (FLAGS_show_worst ? "true" : "false")
            << std::endl;

  auto path_prefix = FLAGS_folder + '/' + '_' + FLAGS_model + '_';
  std::string db_paths[kRunNum];
  for (int i = 0; i < kRunNum; i++) {
    db_paths[i] = path_prefix + name_for_run[i] + ".db";
  }

  std::cout << std::endl;

  auto load_time = -clock();
  std::vector<std::string> class_labels;
  std::vector<std::pair<std::string, int>> image_files;
  load_labels(FLAGS_folder, path_prefix, class_labels, image_files);

  std::cout << "load model.." << std::endl;
  NetDef full_init_model, full_predict_model;
  Keeper(FLAGS_model).AddModel(full_init_model, full_predict_model, false);

  if (FLAGS_device == "cudnn") {
    NetUtil(full_init_model).SetEngineOps("CUDNN");
    NetUtil(full_predict_model).SetEngineOps("CUDNN");
  }

  if (FLAGS_dump_model) {
    std::cout << NetUtil(full_init_model).Short();
    std::cout << NetUtil(full_predict_model).Short();
  }

  NetDef init_model[kRunNum];
  NetDef predict_model[kRunNum];
  for (int i = 0; i < kRunNum; i++) {
    init_model[i].set_name(name_for_run[i] + "_init_model");
    predict_model[i].set_name(name_for_run[i] + "_predict_model");
  }

  pre_process(image_files, db_paths, FLAGS_db_type, FLAGS_size_to_fit);
  load_time += clock();

  for (int i = 0; i < kRunNum; i++) {
    ModelUtil(init_model[i], predict_model[i])
        .AddDatabaseOps(name_for_run[i], full_predict_model.external_input(0),
                        db_paths[i], FLAGS_db_type, FLAGS_batch_size);
  }
  add_train_model(full_init_model, full_predict_model,
                  full_predict_model.external_input(0), class_labels.size(),
                  init_model[kRunTrain], predict_model[kRunTrain],
                  FLAGS_learning_rate, FLAGS_optimizer);
  add_test_model(full_predict_model, predict_model[kRunValidate]);
  add_test_model(full_predict_model, predict_model[kRunTest]);
  if (FLAGS_zero_one) {
    NetUtil(predict_model[kRunValidate])
        .AddZeroOneOp(full_predict_model.external_output(0), "label");
  }
  if (FLAGS_show_worst) {
    NetUtil(predict_model[kRunValidate])
        .AddShowWorstOp(full_predict_model.external_output(0), "label",
                        full_predict_model.external_input(0));
  }

  if (FLAGS_device != "cpu") {
    for (int i = 0; i < kRunNum; i++) {
      NetUtil(init_model[i]).SetDeviceCUDA();
      NetUtil(predict_model[i]).SetDeviceCUDA();
    }
  }

  std::cout << std::endl;

  Workspace workspace("tmp");
  unique_ptr<caffe2::NetBase> predict_net[kRunNum];
  for (int i = 0; i < kRunNum; i++) {
    auto init_net = CreateNet(init_model[i], &workspace);
    init_net->Run();
    predict_net[i] = CreateNet(predict_model[i], &workspace);
  }

  clock_t train_time = 0;
  clock_t validate_time = 0;
  clock_t test_time = 0;

  auto last_time = clock();
  auto last_i = 0;

  std::cout << "training.." << std::endl;
  for (auto i = 1; i <= FLAGS_train_runs; i++) {
    train_time -= clock();
    predict_net[kRunTrain]->Run();
    train_time += clock();

    auto steps_time = (float)(clock() - last_time) / CLOCKS_PER_SEC;
    if (steps_time > 5 || i == FLAGS_train_runs) {
      auto iter = BlobUtil(*workspace.GetBlob("iter")).Get().data<int64_t>()[0];
      auto lr = BlobUtil(*workspace.GetBlob("lr")).Get().data<float>()[0];
      auto train_accuracy =
          BlobUtil(*workspace.GetBlob("accuracy")).Get().data<float>()[0];
      auto train_loss =
          BlobUtil(*workspace.GetBlob("loss")).Get().data<float>()[0];
      validate_time -= clock();
      predict_net[kRunValidate]->Run();
      validate_time += clock();
      auto validate_accuracy =
          BlobUtil(*workspace.GetBlob("accuracy")).Get().data<float>()[0];
      std::cout << "step: " << iter << "  rate: " << lr
                << "  loss: " << train_loss << "  accuracy: " << train_accuracy
                << " | " << validate_accuracy
                << "  step_time: " << std::setprecision(3)
                << steps_time / (i - last_i) << "s" << std::endl;
      last_i = i;
      last_time = clock();
    }
  }

  std::cout << std::endl;

  std::cout << "testing.." << std::endl;
  for (auto i = 1; i <= FLAGS_test_runs; i++) {
    test_time -= clock();
    predict_net[kRunTest]->Run();
    test_time += clock();

    if (i % 10 == 0) {
      auto accuracy =
          BlobUtil(*workspace.GetBlob("accuracy")).Get().data<float>()[0];
      auto loss = BlobUtil(*workspace.GetBlob("loss")).Get().data<float>()[0];
      std::cout << "step: " << i << " loss: " << loss
                << " accuracy: " << accuracy << std::endl;
    }
  }

  NetDef deploy_init_model;  // the final initialization model
  deploy_init_model.set_name("train_" + full_init_model.name());
  for (const auto &op : full_init_model.op()) {
    auto &output = op.output(0);
    auto blob = workspace.GetBlob(output);
    if (blob) {
      auto tensor = BlobUtil(*blob).Get();
      auto init_op = deploy_init_model.add_op();
      init_op->set_type("GivenTensorFill");
      auto arg1 = init_op->add_arg();
      arg1->set_name("shape");
      for (auto dim : tensor.dims()) {
        arg1->add_ints(dim);
      }
      auto arg2 = init_op->add_arg();
      arg2->set_name("values");
      const auto &data = tensor.data<float>();
      for (auto i = 0; i < tensor.size(); ++i) {
        arg2->add_floats(data[i]);
      }
      init_op->add_output(output);
    } else {
      deploy_init_model.add_op()->CopyFrom(op);
    }
  }

  WriteProtoToBinaryFile(deploy_init_model, path_prefix + "init_net.pb");
  WriteProtoToBinaryFile(full_predict_model, path_prefix + "predict_net.pb");
  auto init_size = std::ifstream(path_prefix + "init_net.pb",
                                 std::ifstream::ate | std::ifstream::binary)
                       .tellg();
  auto predict_size = std::ifstream(path_prefix + "predict_net.pb",
                                    std::ifstream::ate | std::ifstream::binary)
                          .tellg();
  auto model_size = init_size + predict_size;

  std::cout << std::endl;

  std::cout << std::setprecision(3)
            << "load: " << ((float)load_time / CLOCKS_PER_SEC)
            << "s  train: " << ((float)train_time / CLOCKS_PER_SEC)
            << "s  validate: " << ((float)validate_time / CLOCKS_PER_SEC)
            << "s  test: " << ((float)test_time / CLOCKS_PER_SEC)
            << "s  model: " << ((float)model_size / 1000000) << "MB"
            << std::endl;
}

}  // namespace caffe2

int main(int argc, char **argv) {
  caffe2::GlobalInit(&argc, &argv);
  caffe2::run();
  google::protobuf::ShutdownProtobufLibrary();
  return 0;
}
<commit_msg>remove model from train files<commit_after>#include "util/misc.h"

#include "caffe2/core/db.h"
#include "caffe2/core/init.h"
#include "caffe2/core/operator_gradient.h"
#include "caffe2/utils/proto_utils.h"
#include "caffe2/zoo/keeper.h"

#include "res/imagenet_classes.h"

CAFFE2_DEFINE_string(model, "", "Name of one of the pre-trained models.");
CAFFE2_DEFINE_string(folder, "", "Folder with subfolders with images");

CAFFE2_DEFINE_string(db_type, "leveldb", "The database type.");
CAFFE2_DEFINE_int(size_to_fit, 224, "The image file.");
CAFFE2_DEFINE_int(train_runs, 1000, "The of training runs.");
CAFFE2_DEFINE_int(test_runs, 50, "The of training runs.");
CAFFE2_DEFINE_int(batch_size, 64, "Training batch size.");
CAFFE2_DEFINE_double(learning_rate, 1e-4, "Learning rate.");

CAFFE2_DEFINE_bool(zero_one, false, "Show zero-one for batch.");
CAFFE2_DEFINE_bool(show_worst, false,
                   "Show worst correct and incorrect classification.");

#include "util/cmd.h"

namespace caffe2 {

void run() {
  if (!cmd_init("Full Train Example")) {
    return;
  }

  if (!FLAGS_model.size()) {
    std::cerr << "specify a model name using --model <name>" << std::endl;
    for (auto const &pair : keeper_model_lookup) {
      std::cerr << "  " << pair.first << std::endl;
    }
    return;
  }

  if (!FLAGS_folder.size()) {
    std::cerr << "specify a image folder using --folder <name>" << std::endl;
    return;
  }

  std::cout << "model: " << FLAGS_model << std::endl;
  std::cout << "image_dir: " << FLAGS_folder << std::endl;
  std::cout << "db_type: " << FLAGS_db_type << std::endl;
  std::cout << "size_to_fit: " << FLAGS_size_to_fit << std::endl;
  std::cout << "train_runs: " << FLAGS_train_runs << std::endl;
  std::cout << "test_runs: " << FLAGS_test_runs << std::endl;
  std::cout << "batch_size: " << FLAGS_batch_size << std::endl;
  std::cout << "learning_rate: " << FLAGS_learning_rate << std::endl;
  std::cout << "zero_one: " << (FLAGS_zero_one ? "true" : "false") << std::endl;
  std::cout << "show_worst: " << (FLAGS_show_worst ? "true" : "false")
            << std::endl;

  auto path_prefix = FLAGS_folder + '/' + '_';
  std::string db_paths[kRunNum];
  for (int i = 0; i < kRunNum; i++) {
    db_paths[i] = path_prefix + name_for_run[i] + ".db";
  }

  std::cout << std::endl;

  auto load_time = -clock();
  std::vector<std::string> class_labels;
  std::vector<std::pair<std::string, int>> image_files;
  load_labels(FLAGS_folder, path_prefix, class_labels, image_files);

  std::cout << "load model.." << std::endl;
  NetDef full_init_model, full_predict_model;
  Keeper(FLAGS_model).AddModel(full_init_model, full_predict_model, false);

  if (FLAGS_device == "cudnn") {
    NetUtil(full_init_model).SetEngineOps("CUDNN");
    NetUtil(full_predict_model).SetEngineOps("CUDNN");
  }

  if (FLAGS_dump_model) {
    std::cout << NetUtil(full_init_model).Short();
    std::cout << NetUtil(full_predict_model).Short();
  }

  NetDef init_model[kRunNum];
  NetDef predict_model[kRunNum];
  for (int i = 0; i < kRunNum; i++) {
    init_model[i].set_name(name_for_run[i] + "_init_model");
    predict_model[i].set_name(name_for_run[i] + "_predict_model");
  }

  pre_process(image_files, db_paths, FLAGS_db_type, FLAGS_size_to_fit);
  load_time += clock();

  for (int i = 0; i < kRunNum; i++) {
    ModelUtil(init_model[i], predict_model[i])
        .AddDatabaseOps(name_for_run[i], full_predict_model.external_input(0),
                        db_paths[i], FLAGS_db_type, FLAGS_batch_size);
  }
  add_train_model(full_init_model, full_predict_model,
                  full_predict_model.external_input(0), class_labels.size(),
                  init_model[kRunTrain], predict_model[kRunTrain],
                  FLAGS_learning_rate, FLAGS_optimizer);
  add_test_model(full_predict_model, predict_model[kRunValidate]);
  add_test_model(full_predict_model, predict_model[kRunTest]);
  if (FLAGS_zero_one) {
    NetUtil(predict_model[kRunValidate])
        .AddZeroOneOp(full_predict_model.external_output(0), "label");
  }
  if (FLAGS_show_worst) {
    NetUtil(predict_model[kRunValidate])
        .AddShowWorstOp(full_predict_model.external_output(0), "label",
                        full_predict_model.external_input(0));
  }

  if (FLAGS_device != "cpu") {
    for (int i = 0; i < kRunNum; i++) {
      NetUtil(init_model[i]).SetDeviceCUDA();
      NetUtil(predict_model[i]).SetDeviceCUDA();
    }
  }

  std::cout << std::endl;

  Workspace workspace("tmp");
  unique_ptr<caffe2::NetBase> predict_net[kRunNum];
  for (int i = 0; i < kRunNum; i++) {
    auto init_net = CreateNet(init_model[i], &workspace);
    init_net->Run();
    predict_net[i] = CreateNet(predict_model[i], &workspace);
  }

  clock_t train_time = 0;
  clock_t validate_time = 0;
  clock_t test_time = 0;

  auto last_time = clock();
  auto last_i = 0;

  std::cout << "training.." << std::endl;
  for (auto i = 1; i <= FLAGS_train_runs; i++) {
    train_time -= clock();
    predict_net[kRunTrain]->Run();
    train_time += clock();

    auto steps_time = (float)(clock() - last_time) / CLOCKS_PER_SEC;
    if (steps_time > 5 || i == FLAGS_train_runs) {
      auto iter = BlobUtil(*workspace.GetBlob("iter")).Get().data<int64_t>()[0];
      auto lr = BlobUtil(*workspace.GetBlob("lr")).Get().data<float>()[0];
      auto train_accuracy =
          BlobUtil(*workspace.GetBlob("accuracy")).Get().data<float>()[0];
      auto train_loss =
          BlobUtil(*workspace.GetBlob("loss")).Get().data<float>()[0];
      validate_time -= clock();
      predict_net[kRunValidate]->Run();
      validate_time += clock();
      auto validate_accuracy =
          BlobUtil(*workspace.GetBlob("accuracy")).Get().data<float>()[0];
      std::cout << "step: " << iter << "  rate: " << lr
                << "  loss: " << train_loss << "  accuracy: " << train_accuracy
                << " | " << validate_accuracy
                << "  step_time: " << std::setprecision(3)
                << steps_time / (i - last_i) << "s" << std::endl;
      last_i = i;
      last_time = clock();
    }
  }

  std::cout << std::endl;

  std::cout << "testing.." << std::endl;
  for (auto i = 1; i <= FLAGS_test_runs; i++) {
    test_time -= clock();
    predict_net[kRunTest]->Run();
    test_time += clock();

    if (i % 10 == 0) {
      auto accuracy =
          BlobUtil(*workspace.GetBlob("accuracy")).Get().data<float>()[0];
      auto loss = BlobUtil(*workspace.GetBlob("loss")).Get().data<float>()[0];
      std::cout << "step: " << i << " loss: " << loss
                << " accuracy: " << accuracy << std::endl;
    }
  }

  NetDef deploy_init_model;  // the final initialization model
  deploy_init_model.set_name("train_" + full_init_model.name());
  for (const auto &op : full_init_model.op()) {
    auto &output = op.output(0);
    auto blob = workspace.GetBlob(output);
    if (blob) {
      auto tensor = BlobUtil(*blob).Get();
      auto init_op = deploy_init_model.add_op();
      init_op->set_type("GivenTensorFill");
      auto arg1 = init_op->add_arg();
      arg1->set_name("shape");
      for (auto dim : tensor.dims()) {
        arg1->add_ints(dim);
      }
      auto arg2 = init_op->add_arg();
      arg2->set_name("values");
      const auto &data = tensor.data<float>();
      for (auto i = 0; i < tensor.size(); ++i) {
        arg2->add_floats(data[i]);
      }
      init_op->add_output(output);
    } else {
      deploy_init_model.add_op()->CopyFrom(op);
    }
  }

  auto init_path = path_prefix + FLAGS_model + "_init_net.pb";
  auto predict_path = path_prefix + FLAGS_model + "_predict_net.pb";
  WriteProtoToBinaryFile(deploy_init_model, init_path);
  WriteProtoToBinaryFile(full_predict_model, predict_path);
  auto init_size =
      std::ifstream(init_path, std::ifstream::ate | std::ifstream::binary)
          .tellg();
  auto predict_size =
      std::ifstream(predict_path, std::ifstream::ate | std::ifstream::binary)
          .tellg();
  auto model_size = init_size + predict_size;

  std::cout << std::endl;

  std::cout << std::setprecision(3)
            << "load: " << ((float)load_time / CLOCKS_PER_SEC)
            << "s  train: " << ((float)train_time / CLOCKS_PER_SEC)
            << "s  validate: " << ((float)validate_time / CLOCKS_PER_SEC)
            << "s  test: " << ((float)test_time / CLOCKS_PER_SEC)
            << "s  model: " << ((float)model_size / 1000000) << "MB"
            << std::endl;
}

}  // namespace caffe2

int main(int argc, char **argv) {
  caffe2::GlobalInit(&argc, &argv);
  caffe2::run();
  google::protobuf::ShutdownProtobufLibrary();
  return 0;
}
<|endoftext|>


<commit_before>#include "font.hpp"

//////////////
// Includes //
#include <iostream>

//////////
// Code //

FT_Library* FontLib::ft = nullptr;

// Getting an instance of the FT_Library.
FT_Library FontLib::instance() {
   if (FontLib::ft == nullptr) {
        ft = new FT_Library;
        FT_Init_FreeType(ft);
   }

   return *ft;
}

// Cleaning up this font.
void Font::destroy() {
    if (this->original)
        return;
}

// Constructing a font from a location.
Font::Font(std::string path, int pnt) {
    if (FT_New_Face(FontLib::instance(), path.c_str(), 0, &this->fontFace)) {
        std::cout << "Failed to load font '" << path << "'!" << std::endl;
        return;
    }

    FT_Set_Pixel_Sizes(this->fontFace, 0, pnt);

    this->original = true;
    this->pnt      = pnt;
}

// Copy constructor.
Font::Font(const Font& font) {
    this->fontFace = font.fontFace;
    this->original = false;
    this->pnt      = font.pnt;
}

// Assignment operator.
Font& Font::operator=(const Font& font) {
    this->destroy();

    this->fontFace = font.fontFace;
    this->original = false;
    this->pnt      = font.pnt;

    return *this;
}

// Destroying this fontFace.
Font::~Font() { this->destroy(); }

// Finding the display width of a string.
float Font::displayWidth(std::string str) const {
    float x = 0;
    const char* ptr;
    for (ptr = str.c_str(); *ptr; ptr++) {
        if (FT_Load_Char(this->fontFace, *ptr, FT_LOAD_RENDER))
            continue;
        x += (this->fontFace->glyph->advance.x >> 6);
    }

    return x;
}

// Finding the display height of a string.
float Font::displayHeight(std::string) const {
    return this->pnt;
}

// Drawing text 'n' stuff.
void Font::drawText(GLFWwindow* window, Shader shader, const char* str,
                    float x, float y) const {
    const char* ptr;

    glUseProgram(shader.getID());

    // Getting the window size.
    int width, height;
    glfwGetWindowSize(window, &width, &height);
    glUniform2f(glGetUniformLocation(shader.getID(), "in_size"), width, height);

    // Setting the text color.
    glUniform4f(glGetUniformLocation(shader.getID(), "in_color"), 1, 1, 1, 1);

    // Loading up the texture.
    GLuint tex;
    glGenTextures(1, &tex);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, tex);
    glUniform1i(glGetUniformLocation(shader.getID(), "in_tex"), 0);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    // Loading up the VBO.
    GLuint vbo;
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);

    // Loading up the EBO.
    GLuint ebo;
    glGenBuffers(1, &ebo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);

    GLuint order[] = {
        0, 1, 2,
        2, 3, 0
    };

    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(order), order, GL_STATIC_DRAW);

    // Setting the vertex coordinate.
    GLint posAttrib = glGetAttribLocation(shader.getID(), "in_coords");
    glEnableVertexAttribArray(posAttrib);
    glVertexAttribPointer(posAttrib, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);

    FT_GlyphSlot g = this->fontFace->glyph;
    for (ptr = str; *ptr; ptr++) {
        if (FT_Load_Char(this->fontFace, *ptr, FT_LOAD_RENDER))
            continue;

        glTexImage2D(
            GL_TEXTURE_2D,
            0,
            GL_RED,
            g->bitmap.width,
            g->bitmap.rows,
            0,
            GL_RED,
            GL_UNSIGNED_BYTE,
            g->bitmap.buffer
        );

        float w = g->bitmap.width,
              h = g->bitmap.rows ;

        GLfloat box[] = {
            x    , y    , 0, 1,
            x + w, y    , 1, 1,
            x + w, y + h, 1, 0,
            x    , y + h, 0, 0
        };

        glBufferData(GL_ARRAY_BUFFER, sizeof(box), box, GL_DYNAMIC_DRAW);
        glDrawElements(GL_TRIANGLES, sizeof(order), GL_UNSIGNED_INT, 0);

        x += g->advance.x >> 6;
        y += g->advance.y >> 6;
    }

    glDeleteBuffers(1, &vbo);
    glDeleteTextures(1, &tex);
}
<commit_msg>Fixed issue #1 by deleting the EBO with text rendering.<commit_after>#include "font.hpp"

//////////////
// Includes //
#include <iostream>

//////////
// Code //

FT_Library* FontLib::ft = nullptr;

// Getting an instance of the FT_Library.
FT_Library FontLib::instance() {
   if (FontLib::ft == nullptr) {
        ft = new FT_Library;
        FT_Init_FreeType(ft);
   }

   return *ft;
}

// Cleaning up this font.
void Font::destroy() {
    if (this->original)
        return;
}

// Constructing a font from a location.
Font::Font(std::string path, int pnt) {
    if (FT_New_Face(FontLib::instance(), path.c_str(), 0, &this->fontFace)) {
        std::cout << "Failed to load font '" << path << "'!" << std::endl;
        return;
    }

    FT_Set_Pixel_Sizes(this->fontFace, 0, pnt);

    this->original = true;
    this->pnt      = pnt;
}

// Copy constructor.
Font::Font(const Font& font) {
    this->fontFace = font.fontFace;
    this->original = false;
    this->pnt      = font.pnt;
}

// Assignment operator.
Font& Font::operator=(const Font& font) {
    this->destroy();

    this->fontFace = font.fontFace;
    this->original = false;
    this->pnt      = font.pnt;

    return *this;
}

// Destroying this fontFace.
Font::~Font() { this->destroy(); }

// Finding the display width of a string.
float Font::displayWidth(std::string str) const {
    float x = 0;
    const char* ptr;
    for (ptr = str.c_str(); *ptr; ptr++) {
        if (FT_Load_Char(this->fontFace, *ptr, FT_LOAD_RENDER))
            continue;
        x += (this->fontFace->glyph->advance.x >> 6);
    }

    return x;
}

// Finding the display height of a string.
float Font::displayHeight(std::string) const {
    return this->pnt;
}

// Drawing text 'n' stuff.
void Font::drawText(GLFWwindow* window, Shader shader, const char* str,
                    float x, float y) const {
    const char* ptr;

    glUseProgram(shader.getID());

    // Getting the window size.
    int width, height;
    glfwGetWindowSize(window, &width, &height);
    glUniform2f(glGetUniformLocation(shader.getID(), "in_size"), width, height);

    // Setting the text color.
    glUniform4f(glGetUniformLocation(shader.getID(), "in_color"), 1, 1, 1, 1);

    // Loading up the texture.
    GLuint tex;
    glGenTextures(1, &tex);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, tex);
    glUniform1i(glGetUniformLocation(shader.getID(), "in_tex"), 0);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    // Loading up the VBO.
    GLuint vbo;
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);

    // Loading up the EBO.
    GLuint ebo;
    glGenBuffers(1, &ebo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);

    GLuint order[] = {
        0, 1, 2,
        2, 3, 0
    };

    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(order), order, GL_STATIC_DRAW);

    // Setting the vertex coordinate.
    GLint posAttrib = glGetAttribLocation(shader.getID(), "in_coords");
    glEnableVertexAttribArray(posAttrib);
    glVertexAttribPointer(posAttrib, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);

    FT_GlyphSlot g = this->fontFace->glyph;
    for (ptr = str; *ptr; ptr++) {
        if (FT_Load_Char(this->fontFace, *ptr, FT_LOAD_RENDER))
            continue;

        glTexImage2D(
            GL_TEXTURE_2D,
            0,
            GL_RED,
            g->bitmap.width,
            g->bitmap.rows,
            0,
            GL_RED,
            GL_UNSIGNED_BYTE,
            g->bitmap.buffer
        );

        float w = g->bitmap.width,
              h = g->bitmap.rows ;

        GLfloat box[] = {
            x    , y    , 0, 1,
            x + w, y    , 1, 1,
            x + w, y + h, 1, 0,
            x    , y + h, 0, 0
        };

        glBufferData(GL_ARRAY_BUFFER, sizeof(box), box, GL_DYNAMIC_DRAW);
        glDrawElements(GL_TRIANGLES, sizeof(order), GL_UNSIGNED_INT, 0);

        x += g->advance.x >> 6;
        y += g->advance.y >> 6;
    }

    glDeleteBuffers(1, &vbo);
    glDeleteBuffers(1, &ebo);
    glDeleteTextures(1, &tex);
}
<|endoftext|>