<commit_before>// Copyright (c) 2011-2019 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 <qt/walletview.h>

#include <qt/addressbookpage.h>
#include <qt/askpassphrasedialog.h>
#include <qt/clientmodel.h>
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
#include <qt/overviewpage.h>
#include <qt/platformstyle.h>
#include <qt/receivecoinsdialog.h>
#include <qt/sendcoinsdialog.h>
#include <qt/signverifymessagedialog.h>
#include <qt/transactiontablemodel.h>
#include <qt/transactionview.h>
#include <qt/walletmodel.h>

#include <interfaces/node.h>
#include <ui_interface.h>

#include <qt/mintingview.h>
#include <wallet/wallet.h>

#include <QAction>
#include <QActionGroup>
#include <QFileDialog>
#include <QHBoxLayout>
#include <QProgressDialog>
#include <QPushButton>
#include <QVBoxLayout>

WalletView::WalletView(const PlatformStyle *_platformStyle, QWidget *parent):
    QStackedWidget(parent),
    clientModel(nullptr),
    walletModel(nullptr),
    platformStyle(_platformStyle)
{
    // Create tabs
    overviewPage = new OverviewPage(platformStyle);

    transactionsPage = new QWidget(this);
    QVBoxLayout *vbox = new QVBoxLayout();
    QHBoxLayout *hbox_buttons = new QHBoxLayout();
    transactionView = new TransactionView(platformStyle, this);
    vbox->addWidget(transactionView);
    QPushButton *exportButton = new QPushButton(tr("&Export"), this);
    exportButton->setToolTip(tr("Export the data in the current tab to a file"));
    if (platformStyle->getImagesOnButtons()) {
        exportButton->setIcon(QIcon(":/icons/export"));
    }
    hbox_buttons->addStretch();
    hbox_buttons->addWidget(exportButton);
    vbox->addLayout(hbox_buttons);
    transactionsPage->setLayout(vbox);

    mintingPage = new QWidget(this);
    QVBoxLayout *vboxMinting = new QVBoxLayout();
    mintingView = new MintingView(this);
    vboxMinting->addWidget(mintingView);
    mintingPage->setLayout(vboxMinting);

    receiveCoinsPage = new ReceiveCoinsDialog(platformStyle);
    sendCoinsPage = new SendCoinsDialog(platformStyle);

    usedSendingAddressesPage = new AddressBookPage(platformStyle, AddressBookPage::ForEditing, AddressBookPage::SendingTab, this);
    usedReceivingAddressesPage = new AddressBookPage(platformStyle, AddressBookPage::ForEditing, AddressBookPage::ReceivingTab, this);

    addWidget(overviewPage);
    addWidget(transactionsPage);
    addWidget(mintingPage);
    addWidget(receiveCoinsPage);
    addWidget(sendCoinsPage);

    connect(overviewPage, &OverviewPage::transactionClicked, this, &WalletView::transactionClicked);
    // Clicking on a transaction on the overview pre-selects the transaction on the transaction history page
    connect(overviewPage, &OverviewPage::transactionClicked, transactionView, static_cast<void (TransactionView::*)(const QModelIndex&)>(&TransactionView::focusTransaction));

    connect(overviewPage, &OverviewPage::outOfSyncWarningClicked, this, &WalletView::requestedSyncWarningInfo);

    connect(sendCoinsPage, &SendCoinsDialog::coinsSent, this, &WalletView::coinsSent);
    // Highlight transaction after send
    connect(sendCoinsPage, &SendCoinsDialog::coinsSent, transactionView, static_cast<void (TransactionView::*)(const uint256&)>(&TransactionView::focusTransaction));

    // Clicking on "Export" allows to export the transaction list
    connect(exportButton, &QPushButton::clicked, transactionView, &TransactionView::exportClicked);

    // Pass through messages from sendCoinsPage
    connect(sendCoinsPage, &SendCoinsDialog::message, this, &WalletView::message);
    // Pass through messages from transactionView
    connect(transactionView, &TransactionView::message, this, &WalletView::message);
}

WalletView::~WalletView()
{
}

void WalletView::setClientModel(ClientModel *_clientModel)
{
    this->clientModel = _clientModel;

    overviewPage->setClientModel(_clientModel);
    sendCoinsPage->setClientModel(_clientModel);
}

void WalletView::setWalletModel(WalletModel *_walletModel)
{
    this->walletModel = _walletModel;

    // Put transaction list in tabs
    transactionView->setModel(_walletModel);
    mintingView->setModel(_walletModel);
    overviewPage->setWalletModel(_walletModel);
    receiveCoinsPage->setModel(_walletModel);
    sendCoinsPage->setModel(_walletModel);
    usedReceivingAddressesPage->setModel(_walletModel ? _walletModel->getAddressTableModel() : nullptr);
    usedSendingAddressesPage->setModel(_walletModel ? _walletModel->getAddressTableModel() : nullptr);

    if (_walletModel)
    {
        // Receive and pass through messages from wallet model
        connect(_walletModel, &WalletModel::message, this, &WalletView::message);

        // Handle changes in encryption status
        connect(_walletModel, &WalletModel::encryptionStatusChanged, this, &WalletView::encryptionStatusChanged);
        updateEncryptionStatus();

        // update HD status
        Q_EMIT hdEnabledStatusChanged();

        // Balloon pop-up for new transaction
        connect(_walletModel->getTransactionTableModel(), &TransactionTableModel::rowsInserted, this, &WalletView::processNewTransaction);

        // Ask for passphrase if needed
        connect(_walletModel, &WalletModel::requireUnlock, this, &WalletView::unlockWallet);

        // Show progress dialog
        connect(_walletModel, &WalletModel::showProgress, this, &WalletView::showProgress);

        this->unlockWallet();
    }
}

void WalletView::processNewTransaction(const QModelIndex& parent, int start, int /*end*/)
{
    // Prevent balloon-spam when initial block download is in progress
    if (!walletModel || !clientModel || clientModel->node().isInitialBlockDownload())
        return;

    TransactionTableModel *ttm = walletModel->getTransactionTableModel();
    if (!ttm || ttm->processingQueuedTransactions())
        return;

    QString date = ttm->index(start, TransactionTableModel::Date, parent).data().toString();
    qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent).data(Qt::EditRole).toULongLong();
    QString type = ttm->index(start, TransactionTableModel::Type, parent).data().toString();
    QModelIndex index = ttm->index(start, 0, parent);
    QString address = ttm->data(index, TransactionTableModel::AddressRole).toString();
    QString label = GUIUtil::HtmlEscape(ttm->data(index, TransactionTableModel::LabelRole).toString());

    Q_EMIT incomingTransaction(date, walletModel->getOptionsModel()->getDisplayUnit(), amount, type, address, label, GUIUtil::HtmlEscape(walletModel->getWalletName()));
}

void WalletView::gotoOverviewPage()
{
    setCurrentWidget(overviewPage);
}

void WalletView::gotoHistoryPage()
{
    setCurrentWidget(transactionsPage);
}

void WalletView::gotoMintingPage()
{
    setCurrentWidget(mintingPage);
}

void WalletView::gotoReceiveCoinsPage()
{
    setCurrentWidget(receiveCoinsPage);
}

void WalletView::gotoSendCoinsPage(QString addr)
{
    setCurrentWidget(sendCoinsPage);

    if (!addr.isEmpty())
        sendCoinsPage->setAddress(addr);
}

void WalletView::gotoSignMessageTab(QString addr)
{
    // calls show() in showTab_SM()
    SignVerifyMessageDialog *signVerifyMessageDialog = new SignVerifyMessageDialog(platformStyle, this);
    signVerifyMessageDialog->setAttribute(Qt::WA_DeleteOnClose);
    signVerifyMessageDialog->setModel(walletModel);
    signVerifyMessageDialog->showTab_SM(true);

    if (!addr.isEmpty())
        signVerifyMessageDialog->setAddress_SM(addr);
}

void WalletView::gotoVerifyMessageTab(QString addr)
{
    // calls show() in showTab_VM()
    SignVerifyMessageDialog *signVerifyMessageDialog = new SignVerifyMessageDialog(platformStyle, this);
    signVerifyMessageDialog->setAttribute(Qt::WA_DeleteOnClose);
    signVerifyMessageDialog->setModel(walletModel);
    signVerifyMessageDialog->showTab_VM(true);

    if (!addr.isEmpty())
        signVerifyMessageDialog->setAddress_VM(addr);
}

bool WalletView::handlePaymentRequest(const SendCoinsRecipient& recipient)
{
    return sendCoinsPage->handlePaymentRequest(recipient);
}

void WalletView::showOutOfSyncWarning(bool fShow)
{
    overviewPage->showOutOfSyncWarning(fShow);
}

void WalletView::updateEncryptionStatus()
{
    Q_EMIT encryptionStatusChanged();
}

void WalletView::encryptWallet(bool status)
{
    if(!walletModel)
        return;
    AskPassphraseDialog dlg(status ? AskPassphraseDialog::Encrypt : AskPassphraseDialog::Decrypt, this);
    dlg.setModel(walletModel);
    dlg.exec();

    updateEncryptionStatus();
}

void WalletView::decryptForMinting(bool status)
{
    if(!walletModel)
        return;

    if (status)
    {
        if(walletModel->getEncryptionStatus() != WalletModel::Locked)
            return;

        AskPassphraseDialog dlg(AskPassphraseDialog::Unlock, this);
        dlg.setModel(walletModel);
        dlg.exec();

        if(walletModel->getEncryptionStatus() != WalletModel::Unlocked)
            return;

        fWalletUnlockMintOnly = true;
    }
    else
    {
        if(walletModel->getEncryptionStatus() != WalletModel::Unlocked)
            return;

        if (!fWalletUnlockMintOnly)
            return;

        walletModel->setWalletLocked(true);
        fWalletUnlockMintOnly = false;
    }
}
void WalletView::backupWallet()
{
    QString filename = GUIUtil::getSaveFileName(this,
        tr("Backup Wallet"), QString(),
        tr("Wallet Data (*.dat)"), nullptr);

    if (filename.isEmpty())
        return;

    if (!walletModel->wallet().backupWallet(filename.toLocal8Bit().data())) {
        Q_EMIT message(tr("Backup Failed"), tr("There was an error trying to save the wallet data to %1.").arg(filename),
            CClientUIInterface::MSG_ERROR);
        }
    else {
        Q_EMIT message(tr("Backup Successful"), tr("The wallet data was successfully saved to %1.").arg(filename),
            CClientUIInterface::MSG_INFORMATION);
    }
}

void WalletView::changePassphrase()
{
    AskPassphraseDialog dlg(AskPassphraseDialog::ChangePass, this);
    dlg.setModel(walletModel);
    dlg.exec();
}

void WalletView::unlockWallet()
{
    if(!walletModel)
        return;
    // Unlock wallet when requested by wallet model
    if (walletModel->getEncryptionStatus() == WalletModel::Locked)
    {
        AskPassphraseDialog dlg(AskPassphraseDialog::Unlock, this);
        dlg.setModel(walletModel);
        dlg.exec();
    }
}

void WalletView::usedSendingAddresses()
{
    if(!walletModel)
        return;

    GUIUtil::bringToFront(usedSendingAddressesPage);
}

void WalletView::usedReceivingAddresses()
{
    if(!walletModel)
        return;

    GUIUtil::bringToFront(usedReceivingAddressesPage);
}

void WalletView::showProgress(const QString &title, int nProgress)
{
    if (nProgress == 0) {
        progressDialog = new QProgressDialog(title, tr("Cancel"), 0, 100);
        GUIUtil::PolishProgressDialog(progressDialog);
        progressDialog->setWindowModality(Qt::ApplicationModal);
        progressDialog->setMinimumDuration(0);
        progressDialog->setAutoClose(false);
        progressDialog->setValue(0);
    } else if (nProgress == 100) {
        if (progressDialog) {
            progressDialog->close();
            progressDialog->deleteLater();
            progressDialog = nullptr;
        }
    } else if (progressDialog) {
        if (progressDialog->wasCanceled()) {
            getWalletModel()->wallet().abortRescan();
        } else {
            progressDialog->setValue(nProgress);
        }
    }
}

void WalletView::requestedSyncWarningInfo()
{
    Q_EMIT outOfSyncWarningClicked();
}
<commit_msg>Instead of the initial pop-up unlocking the wallet, decrypt it for minting only.<commit_after>// Copyright (c) 2011-2019 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 <qt/walletview.h>

#include <qt/addressbookpage.h>
#include <qt/askpassphrasedialog.h>
#include <qt/clientmodel.h>
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
#include <qt/overviewpage.h>
#include <qt/platformstyle.h>
#include <qt/receivecoinsdialog.h>
#include <qt/sendcoinsdialog.h>
#include <qt/signverifymessagedialog.h>
#include <qt/transactiontablemodel.h>
#include <qt/transactionview.h>
#include <qt/walletmodel.h>

#include <interfaces/node.h>
#include <ui_interface.h>

#include <qt/mintingview.h>
#include <wallet/wallet.h>

#include <QAction>
#include <QActionGroup>
#include <QFileDialog>
#include <QHBoxLayout>
#include <QProgressDialog>
#include <QPushButton>
#include <QVBoxLayout>

WalletView::WalletView(const PlatformStyle *_platformStyle, QWidget *parent):
    QStackedWidget(parent),
    clientModel(nullptr),
    walletModel(nullptr),
    platformStyle(_platformStyle)
{
    // Create tabs
    overviewPage = new OverviewPage(platformStyle);

    transactionsPage = new QWidget(this);
    QVBoxLayout *vbox = new QVBoxLayout();
    QHBoxLayout *hbox_buttons = new QHBoxLayout();
    transactionView = new TransactionView(platformStyle, this);
    vbox->addWidget(transactionView);
    QPushButton *exportButton = new QPushButton(tr("&Export"), this);
    exportButton->setToolTip(tr("Export the data in the current tab to a file"));
    if (platformStyle->getImagesOnButtons()) {
        exportButton->setIcon(QIcon(":/icons/export"));
    }
    hbox_buttons->addStretch();
    hbox_buttons->addWidget(exportButton);
    vbox->addLayout(hbox_buttons);
    transactionsPage->setLayout(vbox);

    mintingPage = new QWidget(this);
    QVBoxLayout *vboxMinting = new QVBoxLayout();
    mintingView = new MintingView(this);
    vboxMinting->addWidget(mintingView);
    mintingPage->setLayout(vboxMinting);

    receiveCoinsPage = new ReceiveCoinsDialog(platformStyle);
    sendCoinsPage = new SendCoinsDialog(platformStyle);

    usedSendingAddressesPage = new AddressBookPage(platformStyle, AddressBookPage::ForEditing, AddressBookPage::SendingTab, this);
    usedReceivingAddressesPage = new AddressBookPage(platformStyle, AddressBookPage::ForEditing, AddressBookPage::ReceivingTab, this);

    addWidget(overviewPage);
    addWidget(transactionsPage);
    addWidget(mintingPage);
    addWidget(receiveCoinsPage);
    addWidget(sendCoinsPage);

    connect(overviewPage, &OverviewPage::transactionClicked, this, &WalletView::transactionClicked);
    // Clicking on a transaction on the overview pre-selects the transaction on the transaction history page
    connect(overviewPage, &OverviewPage::transactionClicked, transactionView, static_cast<void (TransactionView::*)(const QModelIndex&)>(&TransactionView::focusTransaction));

    connect(overviewPage, &OverviewPage::outOfSyncWarningClicked, this, &WalletView::requestedSyncWarningInfo);

    connect(sendCoinsPage, &SendCoinsDialog::coinsSent, this, &WalletView::coinsSent);
    // Highlight transaction after send
    connect(sendCoinsPage, &SendCoinsDialog::coinsSent, transactionView, static_cast<void (TransactionView::*)(const uint256&)>(&TransactionView::focusTransaction));

    // Clicking on "Export" allows to export the transaction list
    connect(exportButton, &QPushButton::clicked, transactionView, &TransactionView::exportClicked);

    // Pass through messages from sendCoinsPage
    connect(sendCoinsPage, &SendCoinsDialog::message, this, &WalletView::message);
    // Pass through messages from transactionView
    connect(transactionView, &TransactionView::message, this, &WalletView::message);
}

WalletView::~WalletView()
{
}

void WalletView::setClientModel(ClientModel *_clientModel)
{
    this->clientModel = _clientModel;

    overviewPage->setClientModel(_clientModel);
    sendCoinsPage->setClientModel(_clientModel);
}

void WalletView::setWalletModel(WalletModel *_walletModel)
{
    this->walletModel = _walletModel;

    // Put transaction list in tabs
    transactionView->setModel(_walletModel);
    mintingView->setModel(_walletModel);
    overviewPage->setWalletModel(_walletModel);
    receiveCoinsPage->setModel(_walletModel);
    sendCoinsPage->setModel(_walletModel);
    usedReceivingAddressesPage->setModel(_walletModel ? _walletModel->getAddressTableModel() : nullptr);
    usedSendingAddressesPage->setModel(_walletModel ? _walletModel->getAddressTableModel() : nullptr);

    if (_walletModel)
    {
        // Receive and pass through messages from wallet model
        connect(_walletModel, &WalletModel::message, this, &WalletView::message);

        // Handle changes in encryption status
        connect(_walletModel, &WalletModel::encryptionStatusChanged, this, &WalletView::encryptionStatusChanged);
        updateEncryptionStatus();

        // update HD status
        Q_EMIT hdEnabledStatusChanged();

        // Balloon pop-up for new transaction
        connect(_walletModel->getTransactionTableModel(), &TransactionTableModel::rowsInserted, this, &WalletView::processNewTransaction);

        // Ask for passphrase if needed
        connect(_walletModel, &WalletModel::requireUnlock, this, &WalletView::unlockWallet);

        // Show progress dialog
        connect(_walletModel, &WalletModel::showProgress, this, &WalletView::showProgress);

        this->decryptForMinting(true);
    }
}

void WalletView::processNewTransaction(const QModelIndex& parent, int start, int /*end*/)
{
    // Prevent balloon-spam when initial block download is in progress
    if (!walletModel || !clientModel || clientModel->node().isInitialBlockDownload())
        return;

    TransactionTableModel *ttm = walletModel->getTransactionTableModel();
    if (!ttm || ttm->processingQueuedTransactions())
        return;

    QString date = ttm->index(start, TransactionTableModel::Date, parent).data().toString();
    qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent).data(Qt::EditRole).toULongLong();
    QString type = ttm->index(start, TransactionTableModel::Type, parent).data().toString();
    QModelIndex index = ttm->index(start, 0, parent);
    QString address = ttm->data(index, TransactionTableModel::AddressRole).toString();
    QString label = GUIUtil::HtmlEscape(ttm->data(index, TransactionTableModel::LabelRole).toString());

    Q_EMIT incomingTransaction(date, walletModel->getOptionsModel()->getDisplayUnit(), amount, type, address, label, GUIUtil::HtmlEscape(walletModel->getWalletName()));
}

void WalletView::gotoOverviewPage()
{
    setCurrentWidget(overviewPage);
}

void WalletView::gotoHistoryPage()
{
    setCurrentWidget(transactionsPage);
}

void WalletView::gotoMintingPage()
{
    setCurrentWidget(mintingPage);
}

void WalletView::gotoReceiveCoinsPage()
{
    setCurrentWidget(receiveCoinsPage);
}

void WalletView::gotoSendCoinsPage(QString addr)
{
    setCurrentWidget(sendCoinsPage);

    if (!addr.isEmpty())
        sendCoinsPage->setAddress(addr);
}

void WalletView::gotoSignMessageTab(QString addr)
{
    // calls show() in showTab_SM()
    SignVerifyMessageDialog *signVerifyMessageDialog = new SignVerifyMessageDialog(platformStyle, this);
    signVerifyMessageDialog->setAttribute(Qt::WA_DeleteOnClose);
    signVerifyMessageDialog->setModel(walletModel);
    signVerifyMessageDialog->showTab_SM(true);

    if (!addr.isEmpty())
        signVerifyMessageDialog->setAddress_SM(addr);
}

void WalletView::gotoVerifyMessageTab(QString addr)
{
    // calls show() in showTab_VM()
    SignVerifyMessageDialog *signVerifyMessageDialog = new SignVerifyMessageDialog(platformStyle, this);
    signVerifyMessageDialog->setAttribute(Qt::WA_DeleteOnClose);
    signVerifyMessageDialog->setModel(walletModel);
    signVerifyMessageDialog->showTab_VM(true);

    if (!addr.isEmpty())
        signVerifyMessageDialog->setAddress_VM(addr);
}

bool WalletView::handlePaymentRequest(const SendCoinsRecipient& recipient)
{
    return sendCoinsPage->handlePaymentRequest(recipient);
}

void WalletView::showOutOfSyncWarning(bool fShow)
{
    overviewPage->showOutOfSyncWarning(fShow);
}

void WalletView::updateEncryptionStatus()
{
    Q_EMIT encryptionStatusChanged();
}

void WalletView::encryptWallet(bool status)
{
    if(!walletModel)
        return;
    AskPassphraseDialog dlg(status ? AskPassphraseDialog::Encrypt : AskPassphraseDialog::Decrypt, this);
    dlg.setModel(walletModel);
    dlg.exec();

    updateEncryptionStatus();
}

void WalletView::decryptForMinting(bool status)
{
    if(!walletModel)
        return;

    if (status)
    {
        if(walletModel->getEncryptionStatus() != WalletModel::Locked)
            return;

        AskPassphraseDialog dlg(AskPassphraseDialog::Unlock, this);
        dlg.setModel(walletModel);
        dlg.exec();

        if(walletModel->getEncryptionStatus() != WalletModel::Unlocked)
            return;

        fWalletUnlockMintOnly = true;
    }
    else
    {
        if(walletModel->getEncryptionStatus() != WalletModel::Unlocked)
            return;

        if (!fWalletUnlockMintOnly)
            return;

        walletModel->setWalletLocked(true);
        fWalletUnlockMintOnly = false;
    }
}
void WalletView::backupWallet()
{
    QString filename = GUIUtil::getSaveFileName(this,
        tr("Backup Wallet"), QString(),
        tr("Wallet Data (*.dat)"), nullptr);

    if (filename.isEmpty())
        return;

    if (!walletModel->wallet().backupWallet(filename.toLocal8Bit().data())) {
        Q_EMIT message(tr("Backup Failed"), tr("There was an error trying to save the wallet data to %1.").arg(filename),
            CClientUIInterface::MSG_ERROR);
        }
    else {
        Q_EMIT message(tr("Backup Successful"), tr("The wallet data was successfully saved to %1.").arg(filename),
            CClientUIInterface::MSG_INFORMATION);
    }
}

void WalletView::changePassphrase()
{
    AskPassphraseDialog dlg(AskPassphraseDialog::ChangePass, this);
    dlg.setModel(walletModel);
    dlg.exec();
}

void WalletView::unlockWallet()
{
    if(!walletModel)
        return;
    // Unlock wallet when requested by wallet model
    if (walletModel->getEncryptionStatus() == WalletModel::Locked)
    {
        AskPassphraseDialog dlg(AskPassphraseDialog::Unlock, this);
        dlg.setModel(walletModel);
        dlg.exec();
    }
}

void WalletView::usedSendingAddresses()
{
    if(!walletModel)
        return;

    GUIUtil::bringToFront(usedSendingAddressesPage);
}

void WalletView::usedReceivingAddresses()
{
    if(!walletModel)
        return;

    GUIUtil::bringToFront(usedReceivingAddressesPage);
}

void WalletView::showProgress(const QString &title, int nProgress)
{
    if (nProgress == 0) {
        progressDialog = new QProgressDialog(title, tr("Cancel"), 0, 100);
        GUIUtil::PolishProgressDialog(progressDialog);
        progressDialog->setWindowModality(Qt::ApplicationModal);
        progressDialog->setMinimumDuration(0);
        progressDialog->setAutoClose(false);
        progressDialog->setValue(0);
    } else if (nProgress == 100) {
        if (progressDialog) {
            progressDialog->close();
            progressDialog->deleteLater();
            progressDialog = nullptr;
        }
    } else if (progressDialog) {
        if (progressDialog->wasCanceled()) {
            getWalletModel()->wallet().abortRescan();
        } else {
            progressDialog->setValue(nProgress);
        }
    }
}

void WalletView::requestedSyncWarningInfo()
{
    Q_EMIT outOfSyncWarningClicked();
}
<|endoftext|>


<commit_before>/*
 * This file is part of liblcf. Copyright (c) 2017 liblcf authors.
 * https://github.com/EasyRPG/liblcf - https://easyrpg.org
 *
 * liblcf is Free/Libre Open Source Software, released under the MIT License.
 * For the full copyright and license information, please view the COPYING
 * file that was distributed with this source code.
 */

#include <cstring>
#include <iostream>
#include <iomanip>
#include <type_traits>
#include "ldb_reader.h"
#include "lmt_reader.h"
#include "lmu_reader.h"
#include "lsd_reader.h"
#include "reader_struct.h"
#include "rpg_save.h"

// Read/Write Struct

template <class S>
void Struct<S>::MakeFieldMap() {
	if (!field_map.empty())
		return;
	for (int i = 0; fields[i] != NULL; i++)
		field_map[fields[i]->id] = fields[i];
}

template <class S>
void Struct<S>::MakeTagMap() {
	if (!tag_map.empty())
		return;
	for (int i = 0; fields[i] != NULL; i++)
		tag_map[fields[i]->name] = fields[i];
}

template <typename T>
struct StructDefault {
	static T make() {
		return T();
	}
};

template <>
struct StructDefault<RPG::Actor> {
	static RPG::Actor make() {
		auto actor = RPG::Actor();
		actor.Setup();
		return actor;
	}
};

template <class S>
void Struct<S>::ReadLcf(S& obj, LcfReader& stream) {
	MakeFieldMap();

	LcfReader::Chunk chunk_info;

	while (!stream.Eof()) {
		chunk_info.ID = stream.ReadInt();
		if (chunk_info.ID == 0)
			break;

		chunk_info.length = stream.ReadInt();
		if (chunk_info.length == 0)
			continue;

		typename field_map_type::const_iterator it = field_map.find(chunk_info.ID);
		if (it != field_map.end()) {
#ifdef LCF_DEBUG_TRACE
			printf("0x%02x (size: %d, pos: 0x%x): %s\n", chunk_info.ID, chunk_info.length, stream.Tell(), it->second->name);
#endif
			it->second->ReadLcf(obj, stream, chunk_info.length);
		}
		else
			stream.Skip(chunk_info);
	}
}

template<typename T>
typename std::enable_if<std::is_same<T, RPG::Save>::value ||
		std::is_same<T, RPG::Database>::value>::type
conditional_zero_writer(LcfWriter&) {
	// no-op
}

template<typename T>
typename std::enable_if<!std::is_same<T, RPG::Save>::value &&
		!std::is_same<T, RPG::Database>::value>::type
conditional_zero_writer(LcfWriter& stream) {
	stream.WriteInt(0);
}

template <class S>
void Struct<S>::WriteLcf(const S& obj, LcfWriter& stream) {
	auto ref = StructDefault<S>::make();
	int last = -1;
	for (int i = 0; fields[i] != NULL; i++) {
		const Field<S>* field = fields[i];
		if (field->id < last)
			std::cerr << "field order mismatch: " << field->id
					  << " after " << last
					  << " in struct " << name
					  << std::endl;
		if (field->IsDefault(obj, ref)) {
			continue;
		}
		stream.WriteInt(field->id);
		stream.WriteInt(field->LcfSize(obj, stream));
		field->WriteLcf(obj, stream);
	}
	// Writing a 0-byte after RPG::Database or RPG::Save breaks the parser in RPG_RT
	conditional_zero_writer<S>(stream);
}

template <class S>
int Struct<S>::LcfSize(const S& obj, LcfWriter& stream) {
	int result = 0;
	auto ref = StructDefault<S>::make();
	for (int i = 0; fields[i] != NULL; i++) {
		const Field<S>* field = fields[i];
		//printf("%s\n", field->name);
		if (field->IsDefault(obj, ref))
			continue;
		result += LcfReader::IntSize(field->id);
		int size = field->LcfSize(obj, stream);
		result += LcfReader::IntSize(size);
		result += size;
	}
	result += LcfReader::IntSize(0);
	return result;
}

template <class S>
void Struct<S>::WriteXml(const S& obj, XmlWriter& stream) {
	IDReader::WriteXmlTag(obj, name, stream);
	for (int i = 0; fields[i] != NULL; i++) {
		const Field<S>* field = fields[i];
		field->WriteXml(obj, stream);
	}
	stream.EndElement(name);
}

template <class S>
class StructXmlHandler : public XmlHandler {
public:
	StructXmlHandler(S& ref) : ref(ref), field(NULL) {
		Struct<S>::MakeTagMap();
	}

	void StartElement(XmlReader& stream, const char* name, const char** /* atts */) {
		field = Struct<S>::tag_map[name];
		field->BeginXml(ref, stream);
	}

	void EndElement(XmlReader& /* stream */, const char* /* name */) {
		field = NULL;
	}

	void CharacterData(XmlReader& /* stream */, const std::string& data) {
		if (field != NULL)
			field->ParseXml(ref, data);
	}
private:
	S& ref;
	const Field<S>* field;
};

template <class S>
class StructFieldXmlHandler : public XmlHandler {
public:
	StructFieldXmlHandler(S& ref) : ref(ref) {}

	void StartElement(XmlReader& stream, const char* name, const char** atts) {
		if (strcmp(name, Struct<S>::name) != 0)
			stream.Error("Expecting %s but got %s", Struct<S>::name, name);
		Struct<S>::IDReader::ReadIDXml(ref, atts);
		stream.SetHandler(new StructXmlHandler<S>(ref));
	}
private:
	S& ref;
};

template <class S>
void Struct<S>::BeginXml(S& obj, XmlReader& stream) {
	stream.SetHandler(new StructFieldXmlHandler<S>(obj));
}

// Read/Write std::vector<Struct>

template <class S>
void Struct<S>::ReadLcf(std::vector<S>& vec, LcfReader& stream) {
	int count = stream.ReadInt();
	vec.resize(count);
	for (int i = 0; i < count; i++) {
		IDReader::ReadID(vec[i], stream);
		TypeReader<S>::ReadLcf(vec[i], stream, 0);
	}
}

template <class S>
void Struct<S>::WriteLcf(const std::vector<S>& vec, LcfWriter& stream) {
	int count = vec.size();
	stream.WriteInt(count);
	for (int i = 0; i < count; i++) {
		IDReader::WriteID(vec[i], stream);
		TypeReader<S>::WriteLcf(vec[i], stream);
	}
}

template <class S>
int Struct<S>::LcfSize(const std::vector<S>& vec, LcfWriter& stream) {
	int result = 0;
	int count = vec.size();
	result += LcfReader::IntSize(count);
	for (int i = 0; i < count; i++) {
		result += IDReader::IDSize(vec[i]);
		result += TypeReader<S>::LcfSize(vec[i], stream);
	}
	return result;
}

template <class S>
void Struct<S>::WriteXml(const std::vector<S>& vec, XmlWriter& stream) {
	int count = vec.size();
	for (int i = 0; i < count; i++)
		TypeReader<S>::WriteXml(vec[i], stream);
}

template <class S>
class StructVectorXmlHandler : public XmlHandler {
public:
	StructVectorXmlHandler(std::vector<S>& ref) : ref(ref) {}

	void StartElement(XmlReader& stream, const char* name, const char** atts) {
		if (strcmp(name, Struct<S>::name) != 0)
			stream.Error("Expecting %s but got %s", Struct<S>::name, name);
		ref.resize(ref.size() + 1);
		S& obj = ref.back();
		Struct<S>::IDReader::ReadIDXml(obj, atts);
		stream.SetHandler(new StructXmlHandler<S>(obj));
	}
private:
	std::vector<S>& ref;
};

template <class S>
void Struct<S>::BeginXml(std::vector<S>& obj, XmlReader& stream) {
	stream.SetHandler(new StructVectorXmlHandler<S>(obj));
}

// Instantiate templates
#ifdef _MSC_VER
#pragma warning (disable : 4661)
#endif

template class Struct<RPG::Actor>;
template class Struct<RPG::Animation>;
template class Struct<RPG::AnimationCellData>;
template class Struct<RPG::AnimationFrame>;
template class Struct<RPG::AnimationTiming>;
template class Struct<RPG::Attribute>;
template class Struct<RPG::BattleCommand>;
template class Struct<RPG::BattleCommands>;
template class Struct<RPG::BattlerAnimation>;
template class Struct<RPG::BattlerAnimationData>;
template class Struct<RPG::BattlerAnimationExtension>;
template class Struct<RPG::Chipset>;
template class Struct<RPG::Class>;
template class Struct<RPG::CommonEvent>;
template class Struct<RPG::Database>;
template class Struct<RPG::Encounter>;
template class Struct<RPG::Enemy>;
template class Struct<RPG::EnemyAction>;
template class Struct<RPG::Event>;
template class Struct<RPG::EventPage>;
template class Struct<RPG::EventPageCondition>;
template class Struct<RPG::Item>;
template class Struct<RPG::ItemAnimation>;
template class Struct<RPG::Learning>;
template class Struct<RPG::Map>;
template class Struct<RPG::MapInfo>;
template class Struct<RPG::MoveRoute>;
template class Struct<RPG::Music>;
template class Struct<RPG::Save>;
template class Struct<RPG::SaveActor>;
template class Struct<RPG::SaveCommonEvent>;
template class Struct<RPG::SaveEventCommands>;
template class Struct<RPG::SaveEventData>;
template class Struct<RPG::SaveInventory>;
template class Struct<RPG::SaveMapEvent>;
template class Struct<RPG::SaveMapInfo>;
template class Struct<RPG::SavePartyLocation>;
template class Struct<RPG::SavePicture>;
template class Struct<RPG::SaveScreen>;
template class Struct<RPG::SaveSystem>;
template class Struct<RPG::SaveTarget>;
template class Struct<RPG::SaveTitle>;
template class Struct<RPG::SaveVehicleLocation>;
template class Struct<RPG::Skill>;
template class Struct<RPG::Sound>;
template class Struct<RPG::Start>;
template class Struct<RPG::State>;
template class Struct<RPG::Switch>;
template class Struct<RPG::System>;
template class Struct<RPG::Terms>;
template class Struct<RPG::Terrain>;
template class Struct<RPG::TestBattler>;
template class Struct<RPG::Troop>;
template class Struct<RPG::TroopMember>;
template class Struct<RPG::TroopPage>;
template class Struct<RPG::TroopPageCondition>;
template class Struct<RPG::Variable>;
<commit_msg>Don't write 2k3 fields to 2k database<commit_after>/*
 * This file is part of liblcf. Copyright (c) 2017 liblcf authors.
 * https://github.com/EasyRPG/liblcf - https://easyrpg.org
 *
 * liblcf is Free/Libre Open Source Software, released under the MIT License.
 * For the full copyright and license information, please view the COPYING
 * file that was distributed with this source code.
 */

#include <cstring>
#include <iostream>
#include <iomanip>
#include <type_traits>
#include "ldb_reader.h"
#include "lmt_reader.h"
#include "lmu_reader.h"
#include "lsd_reader.h"
#include "reader_struct.h"
#include "rpg_save.h"
#include "data.h"

// Read/Write Struct

template <class S>
void Struct<S>::MakeFieldMap() {
	if (!field_map.empty())
		return;
	for (int i = 0; fields[i] != NULL; i++)
		field_map[fields[i]->id] = fields[i];
}

template <class S>
void Struct<S>::MakeTagMap() {
	if (!tag_map.empty())
		return;
	for (int i = 0; fields[i] != NULL; i++)
		tag_map[fields[i]->name] = fields[i];
}

template <typename T>
struct StructDefault {
	static T make() {
		return T();
	}
};

template <>
struct StructDefault<RPG::Actor> {
	static RPG::Actor make() {
		auto actor = RPG::Actor();
		actor.Setup();
		return actor;
	}
};

template <class S>
void Struct<S>::ReadLcf(S& obj, LcfReader& stream) {
	MakeFieldMap();

	LcfReader::Chunk chunk_info;

	while (!stream.Eof()) {
		chunk_info.ID = stream.ReadInt();
		if (chunk_info.ID == 0)
			break;

		chunk_info.length = stream.ReadInt();
		if (chunk_info.length == 0)
			continue;

		typename field_map_type::const_iterator it = field_map.find(chunk_info.ID);
		if (it != field_map.end()) {
#ifdef LCF_DEBUG_TRACE
			printf("0x%02x (size: %d, pos: 0x%x): %s\n", chunk_info.ID, chunk_info.length, stream.Tell(), it->second->name);
#endif
			it->second->ReadLcf(obj, stream, chunk_info.length);
		}
		else
			stream.Skip(chunk_info);
	}
}

template<typename T>
typename std::enable_if<std::is_same<T, RPG::Save>::value ||
		std::is_same<T, RPG::Database>::value>::type
conditional_zero_writer(LcfWriter&) {
	// no-op
}

template<typename T>
typename std::enable_if<!std::is_same<T, RPG::Save>::value &&
		!std::is_same<T, RPG::Database>::value>::type
conditional_zero_writer(LcfWriter& stream) {
	stream.WriteInt(0);
}

template <class S>
void Struct<S>::WriteLcf(const S& obj, LcfWriter& stream) {
	const bool db_is2k3 = (Data::system.ldb_id == 2003);

	auto ref = StructDefault<S>::make();
	int last = -1;
	for (int i = 0; fields[i] != NULL; i++) {
		const Field<S>* field = fields[i];
		if (!db_is2k3 && field->is2k3) {
			continue;
		}
		if (field->id < last)
			std::cerr << "field order mismatch: " << field->id
					  << " after " << last
					  << " in struct " << name
					  << std::endl;
		if (field->IsDefault(obj, ref)) {
			continue;
		}
		stream.WriteInt(field->id);
		stream.WriteInt(field->LcfSize(obj, stream));
		field->WriteLcf(obj, stream);
	}
	// Writing a 0-byte after RPG::Database or RPG::Save breaks the parser in RPG_RT
	conditional_zero_writer<S>(stream);
}

template <class S>
int Struct<S>::LcfSize(const S& obj, LcfWriter& stream) {
	const bool db_is2k3 = (Data::system.ldb_id == 2003);
	int result = 0;
	auto ref = StructDefault<S>::make();
	for (int i = 0; fields[i] != NULL; i++) {
		const Field<S>* field = fields[i];
		if (!db_is2k3 && field->is2k3) {
			continue;
		}
		//printf("%s\n", field->name);
		if (field->IsDefault(obj, ref))
			continue;
		result += LcfReader::IntSize(field->id);
		int size = field->LcfSize(obj, stream);
		result += LcfReader::IntSize(size);
		result += size;
	}
	result += LcfReader::IntSize(0);
	return result;
}

template <class S>
void Struct<S>::WriteXml(const S& obj, XmlWriter& stream) {
	IDReader::WriteXmlTag(obj, name, stream);
	for (int i = 0; fields[i] != NULL; i++) {
		const Field<S>* field = fields[i];
		field->WriteXml(obj, stream);
	}
	stream.EndElement(name);
}

template <class S>
class StructXmlHandler : public XmlHandler {
public:
	StructXmlHandler(S& ref) : ref(ref), field(NULL) {
		Struct<S>::MakeTagMap();
	}

	void StartElement(XmlReader& stream, const char* name, const char** /* atts */) {
		field = Struct<S>::tag_map[name];
		field->BeginXml(ref, stream);
	}

	void EndElement(XmlReader& /* stream */, const char* /* name */) {
		field = NULL;
	}

	void CharacterData(XmlReader& /* stream */, const std::string& data) {
		if (field != NULL)
			field->ParseXml(ref, data);
	}
private:
	S& ref;
	const Field<S>* field;
};

template <class S>
class StructFieldXmlHandler : public XmlHandler {
public:
	StructFieldXmlHandler(S& ref) : ref(ref) {}

	void StartElement(XmlReader& stream, const char* name, const char** atts) {
		if (strcmp(name, Struct<S>::name) != 0)
			stream.Error("Expecting %s but got %s", Struct<S>::name, name);
		Struct<S>::IDReader::ReadIDXml(ref, atts);
		stream.SetHandler(new StructXmlHandler<S>(ref));
	}
private:
	S& ref;
};

template <class S>
void Struct<S>::BeginXml(S& obj, XmlReader& stream) {
	stream.SetHandler(new StructFieldXmlHandler<S>(obj));
}

// Read/Write std::vector<Struct>

template <class S>
void Struct<S>::ReadLcf(std::vector<S>& vec, LcfReader& stream) {
	int count = stream.ReadInt();
	vec.resize(count);
	for (int i = 0; i < count; i++) {
		IDReader::ReadID(vec[i], stream);
		TypeReader<S>::ReadLcf(vec[i], stream, 0);
	}
}

template <class S>
void Struct<S>::WriteLcf(const std::vector<S>& vec, LcfWriter& stream) {
	int count = vec.size();
	stream.WriteInt(count);
	for (int i = 0; i < count; i++) {
		IDReader::WriteID(vec[i], stream);
		TypeReader<S>::WriteLcf(vec[i], stream);
	}
}

template <class S>
int Struct<S>::LcfSize(const std::vector<S>& vec, LcfWriter& stream) {
	int result = 0;
	int count = vec.size();
	result += LcfReader::IntSize(count);
	for (int i = 0; i < count; i++) {
		result += IDReader::IDSize(vec[i]);
		result += TypeReader<S>::LcfSize(vec[i], stream);
	}
	return result;
}

template <class S>
void Struct<S>::WriteXml(const std::vector<S>& vec, XmlWriter& stream) {
	int count = vec.size();
	for (int i = 0; i < count; i++)
		TypeReader<S>::WriteXml(vec[i], stream);
}

template <class S>
class StructVectorXmlHandler : public XmlHandler {
public:
	StructVectorXmlHandler(std::vector<S>& ref) : ref(ref) {}

	void StartElement(XmlReader& stream, const char* name, const char** atts) {
		if (strcmp(name, Struct<S>::name) != 0)
			stream.Error("Expecting %s but got %s", Struct<S>::name, name);
		ref.resize(ref.size() + 1);
		S& obj = ref.back();
		Struct<S>::IDReader::ReadIDXml(obj, atts);
		stream.SetHandler(new StructXmlHandler<S>(obj));
	}
private:
	std::vector<S>& ref;
};

template <class S>
void Struct<S>::BeginXml(std::vector<S>& obj, XmlReader& stream) {
	stream.SetHandler(new StructVectorXmlHandler<S>(obj));
}

// Instantiate templates
#ifdef _MSC_VER
#pragma warning (disable : 4661)
#endif

template class Struct<RPG::Actor>;
template class Struct<RPG::Animation>;
template class Struct<RPG::AnimationCellData>;
template class Struct<RPG::AnimationFrame>;
template class Struct<RPG::AnimationTiming>;
template class Struct<RPG::Attribute>;
template class Struct<RPG::BattleCommand>;
template class Struct<RPG::BattleCommands>;
template class Struct<RPG::BattlerAnimation>;
template class Struct<RPG::BattlerAnimationData>;
template class Struct<RPG::BattlerAnimationExtension>;
template class Struct<RPG::Chipset>;
template class Struct<RPG::Class>;
template class Struct<RPG::CommonEvent>;
template class Struct<RPG::Database>;
template class Struct<RPG::Encounter>;
template class Struct<RPG::Enemy>;
template class Struct<RPG::EnemyAction>;
template class Struct<RPG::Event>;
template class Struct<RPG::EventPage>;
template class Struct<RPG::EventPageCondition>;
template class Struct<RPG::Item>;
template class Struct<RPG::ItemAnimation>;
template class Struct<RPG::Learning>;
template class Struct<RPG::Map>;
template class Struct<RPG::MapInfo>;
template class Struct<RPG::MoveRoute>;
template class Struct<RPG::Music>;
template class Struct<RPG::Save>;
template class Struct<RPG::SaveActor>;
template class Struct<RPG::SaveCommonEvent>;
template class Struct<RPG::SaveEventCommands>;
template class Struct<RPG::SaveEventData>;
template class Struct<RPG::SaveInventory>;
template class Struct<RPG::SaveMapEvent>;
template class Struct<RPG::SaveMapInfo>;
template class Struct<RPG::SavePartyLocation>;
template class Struct<RPG::SavePicture>;
template class Struct<RPG::SaveScreen>;
template class Struct<RPG::SaveSystem>;
template class Struct<RPG::SaveTarget>;
template class Struct<RPG::SaveTitle>;
template class Struct<RPG::SaveVehicleLocation>;
template class Struct<RPG::Skill>;
template class Struct<RPG::Sound>;
template class Struct<RPG::Start>;
template class Struct<RPG::State>;
template class Struct<RPG::Switch>;
template class Struct<RPG::System>;
template class Struct<RPG::Terms>;
template class Struct<RPG::Terrain>;
template class Struct<RPG::TestBattler>;
template class Struct<RPG::Troop>;
template class Struct<RPG::TroopMember>;
template class Struct<RPG::TroopPage>;
template class Struct<RPG::TroopPageCondition>;
template class Struct<RPG::Variable>;
<|endoftext|>


<commit_before>#include "Model.hpp"

#include "Scenes/Scenes.hpp"
#include "Resources/Resources.hpp"

namespace acid
{
std::shared_ptr<Model> Model::Create(const Metadata &metadata)
{
	return Scenes::Get()->GetModelRegister().Create(metadata);
}

std::shared_ptr<Model> Model::Create(const std::filesystem::path &filename)
{
	return Scenes::Get()->GetModelRegister().Create(filename);
}

Model::Model()
{
}

bool Model::CmdRender(const CommandBuffer &commandBuffer, const uint32_t &instances) const
{
	if (m_vertexBuffer != nullptr && m_indexBuffer != nullptr)
	{
		VkBuffer vertexBuffers[]{m_vertexBuffer->GetBuffer()};
		VkDeviceSize offsets[]{0};
		vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
		vkCmdBindIndexBuffer(commandBuffer, m_indexBuffer->GetBuffer(), 0, GetIndexType());
		vkCmdDrawIndexed(commandBuffer, m_indexCount, instances, 0, 0, 0);
	}
	else if (m_vertexBuffer != nullptr && m_indexBuffer == nullptr)
	{
		VkBuffer vertexBuffers[]{m_vertexBuffer->GetBuffer()};
		VkDeviceSize offsets[]{0};
		vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
		vkCmdDraw(commandBuffer, m_vertexCount, instances, 0, 0);
	}
	else
	{
		//throw std::runtime_error("Model with no buffers cannot be rendered");
		return false;
	}

	return true;
}

std::vector<uint32_t> Model::GetIndices(const std::size_t &offset) const
{
	Buffer indexStaging{m_indexBuffer->GetSize(), VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
		VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT};

	CommandBuffer commandBuffer;

	VkBufferCopy copyRegion{};
	copyRegion.size = indexStaging.GetSize();
	vkCmdCopyBuffer(commandBuffer, m_indexBuffer->GetBuffer(), indexStaging.GetBuffer(), 1, &copyRegion);

	commandBuffer.SubmitIdle();

	void *indicesMemory;
	indexStaging.MapMemory(&indicesMemory);
	std::vector<uint32_t> indices(m_indexCount);

	auto sizeOfSrcT{indexStaging.GetSize() / m_indexCount};

	for (uint32_t i{}; i < m_indexCount; i++)
	{
		std::memcpy(&indices[i], static_cast<char *>(indicesMemory) + (i * sizeOfSrcT) + offset, sizeof(uint32_t));
	}

	indexStaging.UnmapMemory();
	return indices;
}

void Model::SetIndices(const std::vector<uint32_t> &indices)
{
	m_indexBuffer = nullptr;
	m_indexCount = static_cast<uint32_t>(indices.size());

	if (!indices.empty())
	{
		Buffer indexStaging{sizeof(uint32_t) * indices.size(), VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
			VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, indices.data()};
		m_indexBuffer = std::make_unique<Buffer>(indexStaging.GetSize(), VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
			VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);

		CommandBuffer commandBuffer;

		VkBufferCopy copyRegion{};
		copyRegion.size = indexStaging.GetSize();
		vkCmdCopyBuffer(commandBuffer, indexStaging.GetBuffer(), m_indexBuffer->GetBuffer(), 1, &copyRegion);

		commandBuffer.SubmitIdle();
	}
}

std::vector<float> Model::GetPointCloud() const
{
	if (m_vertexBuffer == nullptr)
	{
		return {};
	}

	// This assumes a Vector3f attribute is the first vertex attribute.
	auto indices{GetIndices()};
	auto vertices{GetVertices<Vector3f>()};

	std::vector<float> pointCloud;
	pointCloud.reserve(indices.size());

	for (const auto &index : indices)
	{
		auto vertex{vertices[index]};
		pointCloud.emplace_back(vertex.m_x);
		pointCloud.emplace_back(vertex.m_y);
		pointCloud.emplace_back(vertex.m_z);
	}

	return pointCloud;
}

const Metadata &operator>>(const Metadata &metadata, Model &model)
{
	// TODO: Virtual?
	return metadata;
}

Metadata &operator<<(Metadata &metadata, const Model &model)
{
	// TODO: Virtual?
	return metadata;
}
}
<commit_msg>Fixed model index memory property.<commit_after>#include "Model.hpp"

#include "Scenes/Scenes.hpp"
#include "Resources/Resources.hpp"

namespace acid
{
std::shared_ptr<Model> Model::Create(const Metadata &metadata)
{
	return Scenes::Get()->GetModelRegister().Create(metadata);
}

std::shared_ptr<Model> Model::Create(const std::filesystem::path &filename)
{
	return Scenes::Get()->GetModelRegister().Create(filename);
}

Model::Model()
{
}

bool Model::CmdRender(const CommandBuffer &commandBuffer, const uint32_t &instances) const
{
	if (m_vertexBuffer != nullptr && m_indexBuffer != nullptr)
	{
		VkBuffer vertexBuffers[]{m_vertexBuffer->GetBuffer()};
		VkDeviceSize offsets[]{0};
		vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
		vkCmdBindIndexBuffer(commandBuffer, m_indexBuffer->GetBuffer(), 0, GetIndexType());
		vkCmdDrawIndexed(commandBuffer, m_indexCount, instances, 0, 0, 0);
	}
	else if (m_vertexBuffer != nullptr && m_indexBuffer == nullptr)
	{
		VkBuffer vertexBuffers[]{m_vertexBuffer->GetBuffer()};
		VkDeviceSize offsets[]{0};
		vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
		vkCmdDraw(commandBuffer, m_vertexCount, instances, 0, 0);
	}
	else
	{
		//throw std::runtime_error("Model with no buffers cannot be rendered");
		return false;
	}

	return true;
}

std::vector<uint32_t> Model::GetIndices(const std::size_t &offset) const
{
	Buffer indexStaging{m_indexBuffer->GetSize(), VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
		VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT};

	CommandBuffer commandBuffer;

	VkBufferCopy copyRegion{};
	copyRegion.size = indexStaging.GetSize();
	vkCmdCopyBuffer(commandBuffer, m_indexBuffer->GetBuffer(), indexStaging.GetBuffer(), 1, &copyRegion);

	commandBuffer.SubmitIdle();

	void *indicesMemory;
	indexStaging.MapMemory(&indicesMemory);
	std::vector<uint32_t> indices(m_indexCount);

	auto sizeOfSrcT{indexStaging.GetSize() / m_indexCount};

	for (uint32_t i{}; i < m_indexCount; i++)
	{
		std::memcpy(&indices[i], static_cast<char *>(indicesMemory) + (i * sizeOfSrcT) + offset, sizeof(uint32_t));
	}

	indexStaging.UnmapMemory();
	return indices;
}

void Model::SetIndices(const std::vector<uint32_t> &indices)
{
	m_indexBuffer = nullptr;
	m_indexCount = static_cast<uint32_t>(indices.size());

	if (!indices.empty())
	{
		Buffer indexStaging{sizeof(uint32_t) * indices.size(), VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
			VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, indices.data()};
		m_indexBuffer = std::make_unique<Buffer>(indexStaging.GetSize(), VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
			VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);

		CommandBuffer commandBuffer;

		VkBufferCopy copyRegion{};
		copyRegion.size = indexStaging.GetSize();
		vkCmdCopyBuffer(commandBuffer, indexStaging.GetBuffer(), m_indexBuffer->GetBuffer(), 1, &copyRegion);

		commandBuffer.SubmitIdle();
	}
}

std::vector<float> Model::GetPointCloud() const
{
	if (m_vertexBuffer == nullptr)
	{
		return {};
	}

	// This assumes a Vector3f attribute is the first vertex attribute.
	auto indices{GetIndices()};
	auto vertices{GetVertices<Vector3f>()};

	std::vector<float> pointCloud;
	pointCloud.reserve(indices.size());

	for (const auto &index : indices)
	{
		auto vertex{vertices[index]};
		pointCloud.emplace_back(vertex.m_x);
		pointCloud.emplace_back(vertex.m_y);
		pointCloud.emplace_back(vertex.m_z);
	}

	return pointCloud;
}

const Metadata &operator>>(const Metadata &metadata, Model &model)
{
	// TODO: Virtual?
	return metadata;
}

Metadata &operator<<(Metadata &metadata, const Model &model)
{
	// TODO: Virtual?
	return metadata;
}
}
<|endoftext|>


<commit_before>/**
 *
 * FaZend.com, Fully Automated Zend Framework
 * RQDQL.com, Requirements Definition and Query Language
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are PROHIBITED without prior written
 * permission from the author. This product may NOT be used
 * anywhere and on any computer except the server platform of
 * FaZend.com. located at www.fazend.com. If you received this
 * code occasionally and without intent to use it, please report
 * this incident to the author by email: team@rqdql.com
 *
 * @author Yegor Bugayenko <egor@tpc2.com>
 * @copyright Copyright (c) rqdql.com, 2010
 * @version $Id: rqdql.cpp 1746 2010-05-04 11:47:08Z yegor256@yahoo.com $
 */

#include <stdarg.h>
#include <unistd.h>
#include <iostream>
#include "rqdql.h"
#include "Scanner.h"
#include "Logger.h"
#include "Front.h"

rqdql::LogLevel rqdql::level = L_ERROR;

/**
 * Main method in the product
 */
int main(int argc, char** argv) {
    using namespace std;

    char c;
    while ((c = getopt(argc, argv, "v?")) != -1) {
        switch (c) {
            case 'v':
                cout << RQDQL_VERSION << endl;
                return 0;
            case '?':
                cout <<
                "usage: rqdql [-?v] [reports...]" << endl <<
                "Options:" << endl <<
                "  -?\tShows this help message" << endl <<
                "  -v\tReturns current version of the product" << endl <<
                "This program built for " << __VERSION__ << endl <<
                "Report bugs to <bugs@rqdql.com>" << endl
                ;
                return 0;
        }
    }

    string text;
    while (!cin.eof()) {
        string s;
        getline(cin, s);
        text = text + s + "\n";
    }

    try {
        rqdql::Scanner::getInstance().scan(text);
        proxy::Proxy::getInstance().inject();
        for (int i = 1; i < argc; ++i) {
            if (argv[i][0] != '-') {
                front::Front::getInstance().require(argv[i]);
            }
        }
        cout << front::Front::getInstance().asXml() << endl;
    } catch (char* e) {
        cerr << "Internal error: \"" << e << "\"" << endl;
        return -1;
    } catch (...) {
        cerr << "Unknown internal error, email us your text to <team@rqdql.com>" << endl;
        return -1;
    }
    return 0;
}

<commit_msg>nicer format of errors<commit_after>/**
 *
 * FaZend.com, Fully Automated Zend Framework
 * RQDQL.com, Requirements Definition and Query Language
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are PROHIBITED without prior written
 * permission from the author. This product may NOT be used
 * anywhere and on any computer except the server platform of
 * FaZend.com. located at www.fazend.com. If you received this
 * code occasionally and without intent to use it, please report
 * this incident to the author by email: team@rqdql.com
 *
 * @author Yegor Bugayenko <egor@tpc2.com>
 * @copyright Copyright (c) rqdql.com, 2010
 * @version $Id: rqdql.cpp 1746 2010-05-04 11:47:08Z yegor256@yahoo.com $
 */

#include <stdarg.h>
#include <unistd.h>
#include <iostream>
#include "rqdql.h"
#include "Scanner.h"
#include "Logger.h"
#include "Front.h"

rqdql::LogLevel rqdql::level = L_ERROR;

/**
 * Main method in the product
 */
int main(int argc, char** argv) {
    using namespace std;

    char c;
    while ((c = getopt(argc, argv, "v?")) != -1) {
        switch (c) {
            case 'v':
                cout << RQDQL_VERSION << endl;
                return 0;
            case '?':
                cout <<
                "usage: rqdql [-?v] [reports...]" << endl <<
                "Options:" << endl <<
                "  -?\tShows this help message" << endl <<
                "  -v\tReturns current version of the product" << endl <<
                "This program built for " << __VERSION__ << endl <<
                "Report bugs to <bugs@rqdql.com>" << endl
                ;
                return 0;
        }
    }

    string text;
    while (!cin.eof()) {
        string s;
        getline(cin, s);
        text = text + s + "\n";
    }

    try {
        rqdql::Scanner::getInstance().scan(text);
        proxy::Proxy::getInstance().inject();
        for (int i = 1; i < argc; ++i) {
            if (argv[i][0] != '-') {
                front::Front::getInstance().require(argv[i]);
            }
        }
        cout << front::Front::getInstance().asXml() << endl;
    } catch (char* e) {
        cerr << "Internal error: \"" << e << "\"" << endl;
        return -1;
    } catch (...) {
        cerr << "Unknown internal error, please email your text to <bugs@rqdql.com>" << endl;
        return -1;
    }
    return 0;
}

<|endoftext|>


<commit_before>
#include "config.h"
#include "linalg.hpp"
#include "logger.hpp"

#include <math.h>

#define POLY0(x, c0) (c0)
#define POLY1(x, c0, c1) (x * POLY0(x, c1) + c0)
#define POLY2(x, c0, c1, c2) (x * POLY1(x, c1, c2) + c0)
#define POLY3(x, c0, c1, c2, c3) (x * POLY2(x, c1, c2, c3) + c0)
#define POLY4(x, c0, c1, c2, c3, c4) (x * POLY3(x, c1, c2, c3, c4) + c0)
#define POLY5(x, c0, c1, c2, c3, c4, c5) (x * POLY4(x, c1, c2, c3, c4, c5) + c0)

static float fastlog2(float x_)
{
    if (x_ <= 0.0f) return -INFINITY;

    union {
        float   f;
        int32_t i;
    } x, y, one;

    one.f = 1.0f;
    x.f = x_;

    float e = (float) ((x.i >> 23) - 127);

    y.i = (x.i & 0x007FFFFF) | one.i;
    float m = y.f;

    float p = POLY5(m, 3.1157899f, -3.3241990f, 2.5988452f, -1.2315303f,  3.1821337e-1f, -3.4436006e-2f);

    p *= m - 1.0;

    return p + e;
}

/* AVX versions */
#if defined(HAVE_AVX) && defined(HAVE_IMMINTRIN_H) && defined(__AVX__)

#include <immintrin.h>

float* vector_alloc(size_t n)
{
    float* xs = reinterpret_cast<float*>(
                    _mm_malloc(n * sizeof(float), 16));
    if (xs == NULL) {
        Logger::abort("Can't allocate an array of size %ul.",
                      (unsigned long) (n * sizeof(float)));
    }
    return xs;
}

void vector_free(float* xs)
{
    _mm_free(xs);
}

typedef union {
    __m256i a;
    __m128i b[2];
} m256i_m128i_t;

typedef union {
    __m256 a;
    __m128 b[2];
} m256_m128_t;

/* Macros for evaluating ploynomials. */
#define AVX_POLY0(x, c0) _mm256_set1_ps(c0)
#define AVX_POLY1(x, c0, c1) \
    _mm256_add_ps(_mm256_mul_ps(AVX_POLY0(x, c1), x), _mm256_set1_ps(c0))
#define AVX_POLY2(x, c0, c1, c2) \
    _mm256_add_ps(_mm256_mul_ps(AVX_POLY1(x, c1, c2), x), _mm256_set1_ps(c0))
#define AVX_POLY3(x, c0, c1, c2, c3) \
    _mm256_add_ps(_mm256_mul_ps(AVX_POLY2(x, c1, c2, c3), x), _mm256_set1_ps(c0))
#define AVX_POLY4(x, c0, c1, c2, c3, c4) \
    _mm256_add_ps(_mm256_mul_ps(AVX_POLY3(x, c1, c2, c3, c4), x), _mm256_set1_ps(c0))
#define AVX_POLY5(x, c0, c1, c2, c3, c4, c5) \
    _mm256_add_ps(_mm256_mul_ps(AVX_POLY4(x, c1, c2, c3, c4, c5), x), _mm256_set1_ps(c0))

/* Comptue log2 over an avx single vector. */
static __m256 avx_log2(__m256 x)
{
    /* TODO: this can be written using avx2 instructions, without resorting to
     * SSE for integer operations, but I won't bother until I actually have an
     * cpu I can test that on.
     * */

    /* extract the exponent */
    const __m128 c127 = _mm_set1_epi32(127);
    m256i_m128i_t i;
    m256_m128_t e;
    i.a = _mm256_castps_si256(x);
    e.b[0] = _mm_sub_epi32(_mm_srli_epi32(i.b[0], 23), c127);
    e.b[1] = _mm_sub_epi32(_mm_srli_epi32(i.b[1], 23), c127);
    e.a = _mm256_cvtepi32_ps(e.a);

    /* extract the mantissa */
    m256_m128_t m;
    const __m256 c1 = _mm256_set1_ps(1.0f);
    const __m128i mant_mask = _mm_set1_epi32(0x007FFFFF);
    m.b[0] = _mm_castsi128_ps(_mm_and_si128(i.b[0], mant_mask));
    m.b[1] = _mm_castsi128_ps(_mm_and_si128(i.b[1], mant_mask));
    m.a = _mm256_or_ps(m.a, c1);

    /* polynomial approximation on the mantissa */
    __m256 p = AVX_POLY5(m.a, 3.1157899f,
                             -3.3241990f,
                              2.5988452f,
                             -1.2315303f,
                              3.1821337e-1f,
                             -3.4436006e-2f);

    p = _mm256_add_ps(_mm256_mul_ps(p, _mm256_sub_ps(m.a, c1)), e.a);

    /* Handle the log(x) = -INFINITY, for x <= 0 cases. */
    p = _mm256_blendv_ps(p, _mm256_set1_ps(-INFINITY),
                         _mm256_cmp_ps(x, _mm256_setzero_ps(), _CMP_LE_OQ));

    return p;
}

float dotlog(const float* xs, const float* ys, const size_t n)
{
    union {
        __m256 v;
        float f[8];
    } ans;
    ans.v = _mm256_setzero_ps();

    __m256 xv, yv;
    size_t i;
    for (i = 0; i < n / 8; ++i) {
        xv = _mm256_load_ps(xs + 8 * i);
        yv = _mm256_load_ps(ys + 8 * i);
        ans.v = _mm256_add_ps(ans.v, _mm256_mul_ps(xv, avx_log2(yv)));
    }

    float fans = ans.f[0] + ans.f[1] + ans.f[2] + ans.f[3] +
                 ans.f[4] + ans.f[5] + ans.f[6] + ans.f[7];

    /* handle any overhang */
    i *= 8;
    switch (n % 8) {
        case 7: fans += xs[i] * fastlog2(ys[i]); ++i;
        case 6: fans += xs[i] * fastlog2(ys[i]); ++i;
        case 5: fans += xs[i] * fastlog2(ys[i]); ++i;
        case 4: fans += xs[i] * fastlog2(ys[i]); ++i;
        case 3: fans += xs[i] * fastlog2(ys[i]); ++i;
        case 2: fans += xs[i] * fastlog2(ys[i]); ++i;
        case 1: fans += xs[i] * fastlog2(ys[i]); ++i;
    }

    return fans;
}

void asxpy(float* xs, const float* ys, const float c,
            const unsigned int* idx, const size_t n)
{
    __m256 yv;
    __m256 cv = _mm256_set1_ps(c);
    union {
        __m256 v;
        float f[8];
    } x;

    size_t i;
    for (i = 0; i < 8 * (n / 8); ++i) {
        yv = _mm256_mul_ps(cv, _mm256_load_ps(ys + i));

        /* load from xs */
        x.f[0] = xs[idx[i]];
        x.f[1] = xs[idx[i+1]];
        x.f[2] = xs[idx[i+2]];
        x.f[3] = xs[idx[i+3]];
        x.f[4] = xs[idx[i+4]];
        x.f[5] = xs[idx[i+5]];
        x.f[6] = xs[idx[i+6]];
        x.f[7] = xs[idx[i+7]];

        x.v = _mm256_add_ps(x.v, yv);

        /* store in xs */
        xs[idx[i]]   = x.f[0];
        xs[idx[i+1]] = x.f[1];
        xs[idx[i+2]] = x.f[2];
        xs[idx[i+3]] = x.f[3];
        xs[idx[i+4]] = x.f[4];
        xs[idx[i+5]] = x.f[5];
        xs[idx[i+6]] = x.f[6];
        xs[idx[i+7]] = x.f[7];
    }

    /* handle overhang */
    i = 8 * (n / 8);
    switch (n % 8) {
        case 8: xs[idx[i]] += c * ys[i]; ++i;
        case 7: xs[idx[i]] += c * ys[i]; ++i;
        case 6: xs[idx[i]] += c * ys[i]; ++i;
        case 5: xs[idx[i]] += c * ys[i]; ++i;
        case 4: xs[idx[i]] += c * ys[i]; ++i;
        case 3: xs[idx[i]] += c * ys[i]; ++i;
        case 2: xs[idx[i]] += c * ys[i]; ++i;
        case 1: xs[idx[i]] += c * ys[i]; ++i;
    }
}

/* Vanilla versions */
#else

float* vector_alloc(size_t n)
{
    float* xs = malloc(n * sizeof(float));
    if (xs == NULL) {
        Logger::abort("Can't allocate an array of size %ul.",
                      (unsigned long) (n * sizeof(float)));
    }
    return xs;
}

void vector_free(float* xs)
{
    free(xs);
}

float dotlog(const float* xs, const float* ys, const size_t n)
{
    float ans = 0.0;
    size_t i;
    for (i = 0; i < n; ++i) {
        ans += xs[i] * fastlog2(ys[i]);
    }
    return ans;
}

void asxpy(float* xs, const float* ys, const float c,
            const unsigned int* idx, const size_t n)
{
    size_t i;
    for (i = 0; i < n; ++i) {
        xs[idx[i]] += c * ys[i];
    }
}

#endif
<commit_msg>SSE versions of the linalg functions.<commit_after>
#include "config.h"
#include "linalg.hpp"
#include "logger.hpp"

#include <math.h>

#define POLY0(x, c0) (c0)
#define POLY1(x, c0, c1) (x * POLY0(x, c1) + c0)
#define POLY2(x, c0, c1, c2) (x * POLY1(x, c1, c2) + c0)
#define POLY3(x, c0, c1, c2, c3) (x * POLY2(x, c1, c2, c3) + c0)
#define POLY4(x, c0, c1, c2, c3, c4) (x * POLY3(x, c1, c2, c3, c4) + c0)
#define POLY5(x, c0, c1, c2, c3, c4, c5) (x * POLY4(x, c1, c2, c3, c4, c5) + c0)

static float fastlog2(float x_)
{
    if (x_ <= 0.0f) return -INFINITY;

    union {
        float   f;
        int32_t i;
    } x, y, one;

    one.f = 1.0f;
    x.f = x_;

    float e = (float) ((x.i >> 23) - 127);

    y.i = (x.i & 0x007FFFFF) | one.i;
    float m = y.f;

    float p = POLY5(m, 3.1157899f, -3.3241990f, 2.5988452f, -1.2315303f,  3.1821337e-1f, -3.4436006e-2f);

    p *= m - 1.0;

    return p + e;
}

/* AVX versions */
#if defined(HAVE_AVX) && defined(HAVE_IMMINTRIN_H) && defined(__AVX__)

#include <immintrin.h>

float* vector_alloc(size_t n)
{
    float* xs = reinterpret_cast<float*>(
                    _mm_malloc(n * sizeof(float), 16));
    if (xs == NULL) {
        Logger::abort("Can't allocate an array of size %ul.",
                      (unsigned long) (n * sizeof(float)));
    }
    return xs;
}

void vector_free(float* xs)
{
    _mm_free(xs);
}

typedef union {
    __m256i a;
    __m128i b[2];
} m256i_m128i_t;

typedef union {
    __m256 a;
    __m128 b[2];
} m256_m128_t;

/* Macros for evaluating ploynomials. */
#define AVX_POLY0(x, c0) _mm256_set1_ps(c0)
#define AVX_POLY1(x, c0, c1) \
    _mm256_add_ps(_mm256_mul_ps(AVX_POLY0(x, c1), x), _mm256_set1_ps(c0))
#define AVX_POLY2(x, c0, c1, c2) \
    _mm256_add_ps(_mm256_mul_ps(AVX_POLY1(x, c1, c2), x), _mm256_set1_ps(c0))
#define AVX_POLY3(x, c0, c1, c2, c3) \
    _mm256_add_ps(_mm256_mul_ps(AVX_POLY2(x, c1, c2, c3), x), _mm256_set1_ps(c0))
#define AVX_POLY4(x, c0, c1, c2, c3, c4) \
    _mm256_add_ps(_mm256_mul_ps(AVX_POLY3(x, c1, c2, c3, c4), x), _mm256_set1_ps(c0))
#define AVX_POLY5(x, c0, c1, c2, c3, c4, c5) \
    _mm256_add_ps(_mm256_mul_ps(AVX_POLY4(x, c1, c2, c3, c4, c5), x), _mm256_set1_ps(c0))

/* Comptue log2 over an avx single vector. */
static __m256 avx_log2(__m256 x)
{
    /* TODO: this can be written using avx2 instructions, without resorting to
     * SSE for integer operations, but I won't bother until I actually have an
     * cpu I can test that on.
     * */

    /* extract the exponent */
    const __m128 c127 = _mm_set1_epi32(127);
    m256i_m128i_t i;
    m256_m128_t e;
    i.a = _mm256_castps_si256(x);
    e.b[0] = _mm_sub_epi32(_mm_srli_epi32(i.b[0], 23), c127);
    e.b[1] = _mm_sub_epi32(_mm_srli_epi32(i.b[1], 23), c127);
    e.a = _mm256_cvtepi32_ps(e.a);

    /* extract the mantissa */
    m256_m128_t m;
    const __m256 c1 = _mm256_set1_ps(1.0f);
    const __m128i mant_mask = _mm_set1_epi32(0x007FFFFF);
    m.b[0] = _mm_castsi128_ps(_mm_and_si128(i.b[0], mant_mask));
    m.b[1] = _mm_castsi128_ps(_mm_and_si128(i.b[1], mant_mask));
    m.a = _mm256_or_ps(m.a, c1);

    /* polynomial approximation on the mantissa */
    __m256 p = AVX_POLY5(m.a, 3.1157899f,
                             -3.3241990f,
                              2.5988452f,
                             -1.2315303f,
                              3.1821337e-1f,
                             -3.4436006e-2f);

    p = _mm256_add_ps(_mm256_mul_ps(p, _mm256_sub_ps(m.a, c1)), e.a);

    /* Handle the log(x) = -INFINITY, for x <= 0 cases. */
    p = _mm256_blendv_ps(p, _mm256_set1_ps(-INFINITY),
                         _mm256_cmp_ps(x, _mm256_setzero_ps(), _CMP_LE_OQ));

    return p;
}

float dotlog(const float* xs, const float* ys, const size_t n)
{
    union {
        __m256 v;
        float f[8];
    } ans;
    ans.v = _mm256_setzero_ps();

    __m256 xv, yv;
    size_t i;
    for (i = 0; i < n / 8; ++i) {
        xv = _mm256_load_ps(xs + 8 * i);
        yv = _mm256_load_ps(ys + 8 * i);
        ans.v = _mm256_add_ps(ans.v, _mm256_mul_ps(xv, avx_log2(yv)));
    }

    float fans = ans.f[0] + ans.f[1] + ans.f[2] + ans.f[3] +
                 ans.f[4] + ans.f[5] + ans.f[6] + ans.f[7];

    /* handle any overhang */
    i *= 8;
    switch (n % 8) {
        case 7: fans += xs[i] * fastlog2(ys[i]); ++i;
        case 6: fans += xs[i] * fastlog2(ys[i]); ++i;
        case 5: fans += xs[i] * fastlog2(ys[i]); ++i;
        case 4: fans += xs[i] * fastlog2(ys[i]); ++i;
        case 3: fans += xs[i] * fastlog2(ys[i]); ++i;
        case 2: fans += xs[i] * fastlog2(ys[i]); ++i;
        case 1: fans += xs[i] * fastlog2(ys[i]); ++i;
    }

    return fans;
}

void asxpy(float* xs, const float* ys, const float c,
            const unsigned int* idx, const size_t n)
{
    __m256 yv;
    __m256 cv = _mm256_set1_ps(c);
    union {
        __m256 v;
        float f[8];
    } x;

    size_t i;
    for (i = 0; i < 8 * (n / 8); ++i) {
        yv = _mm256_mul_ps(cv, _mm256_load_ps(ys + i));

        /* load from xs */
        x.f[0] = xs[idx[i]];
        x.f[1] = xs[idx[i+1]];
        x.f[2] = xs[idx[i+2]];
        x.f[3] = xs[idx[i+3]];
        x.f[4] = xs[idx[i+4]];
        x.f[5] = xs[idx[i+5]];
        x.f[6] = xs[idx[i+6]];
        x.f[7] = xs[idx[i+7]];

        x.v = _mm256_add_ps(x.v, yv);

        /* store in xs */
        xs[idx[i]]   = x.f[0];
        xs[idx[i+1]] = x.f[1];
        xs[idx[i+2]] = x.f[2];
        xs[idx[i+3]] = x.f[3];
        xs[idx[i+4]] = x.f[4];
        xs[idx[i+5]] = x.f[5];
        xs[idx[i+6]] = x.f[6];
        xs[idx[i+7]] = x.f[7];
    }

    /* handle overhang */
    i = 8 * (n / 8);
    switch (n % 8) {
        case 7: xs[idx[i]] += c * ys[i]; ++i;
        case 6: xs[idx[i]] += c * ys[i]; ++i;
        case 5: xs[idx[i]] += c * ys[i]; ++i;
        case 4: xs[idx[i]] += c * ys[i]; ++i;
        case 3: xs[idx[i]] += c * ys[i]; ++i;
        case 2: xs[idx[i]] += c * ys[i]; ++i;
        case 1: xs[idx[i]] += c * ys[i]; ++i;
    }
}

/* SSE2 versions */
#elif defined(HAVE_IMMINTRIN_H) && defined(HAVE_SSE2) && defined(__SSE2__)

#include <immintrin.h>

float* vector_alloc(size_t n)
{
    float* xs = reinterpret_cast<float*>(
                    _mm_malloc(n * sizeof(float), 16));
    if (xs == NULL) {
        Logger::abort("Can't allocate an array of size %ul.",
                      (unsigned long) (n * sizeof(float)));
    }
    return xs;
}

void vector_free(float* xs)
{
    _mm_free(xs);
}

/* Macros for evaluating ploynomials. */
#define SSE_POLY0(x, c0) _mm_set1_ps(c0)
#define SSE_POLY1(x, c0, c1) \
    _mm_add_ps(_mm_mul_ps(SSE_POLY0(x, c1), x), _mm_set1_ps(c0))
#define SSE_POLY2(x, c0, c1, c2) \
    _mm_add_ps(_mm_mul_ps(SSE_POLY1(x, c1, c2), x), _mm_set1_ps(c0))
#define SSE_POLY3(x, c0, c1, c2, c3) \
    _mm_add_ps(_mm_mul_ps(SSE_POLY2(x, c1, c2, c3), x), _mm_set1_ps(c0))
#define SSE_POLY4(x, c0, c1, c2, c3, c4) \
    _mm_add_ps(_mm_mul_ps(SSE_POLY3(x, c1, c2, c3, c4), x), _mm_set1_ps(c0))
#define SSE_POLY5(x, c0, c1, c2, c3, c4, c5) \
    _mm_add_ps(_mm_mul_ps(SSE_POLY4(x, c1, c2, c3, c4, c5), x), _mm_set1_ps(c0))

/* Comptue log2 over an sse single vector. */
static __m128 sse_log2(__m128 x)
{

    /* extract exponent */
    const __m128i i = _mm_castps_si128(x);
    __m128 e = _mm_cvtepi32_ps(
                 _mm_sub_epi32(
                   _mm_srli_epi32(i, 23),
                   _mm_set1_epi32(127)));

    /* extract mantissa */
    const __m128i mant_mask = _mm_set1_epi32(0x007FFFFF);
    const __m128 one = _mm_set1_ps(1.0f);
    __m128 m = _mm_or_ps(_mm_castsi128_ps(_mm_and_si128(i, mant_mask)), one);

    /* polynomial approximation on the mantissa */
    __m128 p = SSE_POLY5(m,
                         3.1157899f,
                        -3.3241990f,
                         2.5988452f,
                        -1.2315303f,
                         3.1821337e-1f,
                        -3.4436006e-2f);

    p = _mm_add_ps(_mm_mul_ps(p, _mm_sub_ps(m, one)), e);

    /* handle the case with x= < 0.0 */
#if (defined(HAVE_SSE41) && defined(__SSE41__)) || (defined(HAVE_SSE42) && defined(__SSE42__))
    p = _mm_blendv_ps(p, _mm_set1_ps(-INFINITY), _mm_cmple_ps(x, _mm_setzero_ps()));
#else
    // TODO: test this
    __m128 mask = _mm_cmpgt_ps(x, _mm_setzero_ps());
    p = _mm_or_ps(_mm_and_ps(mask, p), _mm_andnot_ps(mask, _mm_set1_ps(-INFINITY)));
#endif

    return p;
}

float dotlog(const float* xs, const float* ys, const size_t n)
{
    __m128 xv, yv;
    union ans_t
    {
        __m128  v;
        float   f[4];
    } ans;
    ans.v = _mm_setzero_ps();

    size_t i;
    for (i = 0; i < n / 4; ++i) {
        xv = _mm_load_ps(xs + 4 * i);
        yv = _mm_load_ps(ys + 4 * i);
        ans.v = _mm_add_ps(ans.v, _mm_mul_ps(xv, sse_log2(yv)));
    }

    float fans = ans.f[0] + ans.f[1] + ans.f[2] + ans.f[3];

    /* handle any overhang */
    i *= 4;
    switch (n % 4) {
        case 3: fans += xs[i] * fastlog2(ys[i]); ++i;
        case 2: fans += xs[i] * fastlog2(ys[i]); ++i;
        case 1: fans += xs[i] * fastlog2(ys[i]); ++i;
    }

    return fans;
}

void asxpy(float* xs, const float* ys, const float c,
            const unsigned int* idx, const size_t n)
{
    __m128 yv;
    __m128 cv = _mm_set1_ps(c);
    union {
        __m128 v;
        float f[8];
    } x;

    size_t i;
    for (i = 0; i < 4 * (n / 4); ++i) {
        yv = _mm_mul_ps(cv, _mm_load_ps(ys + i));

        /* load from xs */
        x.f[0] = xs[idx[i]];
        x.f[1] = xs[idx[i+1]];
        x.f[2] = xs[idx[i+2]];
        x.f[3] = xs[idx[i+3]];

        x.v = _mm_add_ps(x.v, yv);

        /* store in xs */
        xs[idx[i]]   = x.f[0];
        xs[idx[i+1]] = x.f[1];
        xs[idx[i+2]] = x.f[2];
        xs[idx[i+3]] = x.f[3];
    }

    /* handle overhang */
    i = 4 * (n / 4);
    switch (n % 4) {
        case 3: xs[idx[i]] += c * ys[i]; ++i;
        case 2: xs[idx[i]] += c * ys[i]; ++i;
        case 1: xs[idx[i]] += c * ys[i]; ++i;
    }
}

/* Vanilla versions */
#else

float* vector_alloc(size_t n)
{
    float* xs = malloc(n * sizeof(float));
    if (xs == NULL) {
        Logger::abort("Can't allocate an array of size %ul.",
                      (unsigned long) (n * sizeof(float)));
    }
    return xs;
}

void vector_free(float* xs)
{
    free(xs);
}

float dotlog(const float* xs, const float* ys, const size_t n)
{
    float ans = 0.0;
    size_t i;
    for (i = 0; i < n; ++i) {
        ans += xs[i] * fastlog2(ys[i]);
    }
    return ans;
}

void asxpy(float* xs, const float* ys, const float c,
            const unsigned int* idx, const size_t n)
{
    size_t i;
    for (i = 0; i < n; ++i) {
        xs[idx[i]] += c * ys[i];
    }
}

#endif
<|endoftext|>


<commit_before>#include "logging.h"

#include <boost/log/utility/setup/console.hpp>

namespace logging = boost::log;
using boost::log::trivial::severity_level;

severity_level gLoggingThreshold;

long get_curlopt_verbose() { return gLoggingThreshold <= boost::log::trivial::debug ? 1L : 0L; }

void logger_init() {
  gLoggingThreshold = boost::log::trivial::info;
  logging::add_console_log(std::cout, boost::log::keywords::format = "%Message%");
  boost::log::core::get()->set_filter(boost::log::trivial::severity >= gLoggingThreshold);
  std::cout << std::unitbuf;  // Ensure that log messages are flushed to the journal
}

void logger_set_threshold(severity_level threshold) {
  gLoggingThreshold = threshold;
  boost::log::core::get()->set_filter(boost::log::trivial::severity >= gLoggingThreshold);
}

int loggerGetSeverity() { return (int)gLoggingThreshold; }

// vim: set tabstop=2 shiftwidth=2 expandtab:
<commit_msg>Add a better fix to flush the log messages<commit_after>#include "logging.h"

#include <boost/log/utility/setup/console.hpp>

namespace logging = boost::log;
using boost::log::trivial::severity_level;

severity_level gLoggingThreshold;

long get_curlopt_verbose() { return gLoggingThreshold <= boost::log::trivial::debug ? 1L : 0L; }

void logger_init() {
  gLoggingThreshold = boost::log::trivial::info;
  logging::add_console_log(std::cout, boost::log::keywords::format = "%Message%",
                           boost::log::keywords::auto_flush = true);
  boost::log::core::get()->set_filter(boost::log::trivial::severity >= gLoggingThreshold);
}

void logger_set_threshold(severity_level threshold) {
  gLoggingThreshold = threshold;
  boost::log::core::get()->set_filter(boost::log::trivial::severity >= gLoggingThreshold);
}

int loggerGetSeverity() { return (int)gLoggingThreshold; }

// vim: set tabstop=2 shiftwidth=2 expandtab:
<|endoftext|>


<commit_before>// -*- coding: us-ascii-unix -*-
// Copyright 2013 Lukas Kemmer
//
// Licensed under the Apache License, Version 2.0 (the "License"); you
// may not use this file except in compliance with the License. You
// may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.

#include <sstream>
#include "app/app-context.hh"
#include "app/canvas.hh"
#include "app/frame.hh"
#include "commands/frame-cmd.hh"
#include "commands/put-pixel-cmd.hh"
#include "text/formatting.hh"
#include "util/command-util.hh"
#include "util/image.hh"
#include "util/object-util.hh"
#include "util/setting-util.hh"
#include "python/py-include.hh"
#include "python/py-canvas.hh"
#include "python/py-common.hh"
#include "python/py-frame.hh"
#include "python/py-less-common.hh"
#include "python/py-tri.hh"
#include "python/py-ugly-forward.hh"
#include "python/py-util.hh"
#include "python/python-context.hh"

namespace faint{

bool expired(frameObject* self){
  if (canvas_ok(self->canvasId, *self->ctx) && self->canvas->Has(self->frameId)){
    return false;
  }
  PyErr_SetString(PyExc_ValueError,
    "That frame is removed."); // Fixme: really do this?
  return true;
}

template<>
struct MappedType<const Frame&>{
  using PYTHON_TYPE = frameObject;

  static Frame GetCppObject(frameObject* self){
    return Frame(*self->ctx,
      *self->canvas,
      self->canvas->GetFrame(self->frameId));
  }

  static bool Expired(frameObject* self){
    return expired(self);
  }

  static void ShowError(frameObject*){
    PyErr_SetString(PyExc_ValueError, "That frame is removed.");
  }
};

static PyObject* frame_new(PyTypeObject* type, PyObject*, PyObject*){
  frameObject* self;
  self = (frameObject*)type->tp_alloc(type, 0);
  return (PyObject*)self;
}

static PyObject* frame_repr(frameObject* self){
  std::stringstream ss;
  if (canvas_ok(self->canvasId, *self->ctx)){
    ss << "Frame of canvas #" << self->canvasId.Raw();
  }
  else{
    ss << "Frame of retired Canvas #" << self->canvasId.Raw();
  }
  return Py_BuildValue("s", ss.str().c_str());
}

static void frame_init(frameObject&){
  throw TypeError("Frame can not be instantiated. "
    "Use image.get_frame or frames[index]");
}

/* method: "__copy__() Not implemented."
name: "__copy__" */
static void frame_copy(const Frame&){
  throw NotImplementedError("Frame can not be copied.");
}

// Fixme: Consider return bitmap even if ColorSpan?
/* method: "get_bitmap()->bmp?\n
Returns a copy of the pixel data as a Bitmap." */
static const Optional<Bitmap>& frame_get_bitmap(const Frame& frame){
  return frame.image.GetBackground().Get<Bitmap>();
}

/* method: "get_delay()->s/100\n
Returns the duration, in hundredths of a second, that this frame will
be shown when saved as a gif." */
static Delay frame_get_delay(const Frame& frame){
  return frame.GetImage().GetDelay();
}

/* method: "get_hotspot()-> x,y\n
Returns the hotspot for the frame. This is the anchor point for
cursors (.cur)." */
static IntPoint frame_get_hotspot(const Frame& frame){
  return frame.GetImage().GetHotSpot();
}

/* method: "get_size() -> w,h\n
Returns the size of the frame (in pixels)." */
static IntSize frame_get_size(const Frame& frame){
  return frame.image.GetSize();
}

/* method: "get_objects() -> objects\n
Returns a list of the objects in the frame, sorted from rear-most to
front-most." */
static BoundObjects frame_get_objects(const Frame& frame){
  return bind_objects(frame.ctx,
    frame.canvas,
    frame.image.GetObjects(),
    frame.frameId);
}

/* method: "get_calibration() -> ((x0,y0,x1,y1), length, unit)\n
Returns a line, its specified length and the unit this refers to - or
None if the image is not calibrated." */
static Optional<Calibration> frame_get_calibration(const Frame& frame){
  return frame.image.GetCalibration();
}

/* method: "get_selected() -> objects\n
Returns a list of the selected objects in the frame, sorted from rear-most to
front-most." */
static BoundObjects frame_get_selected(const Frame& frame){
  return bind_objects(frame.ctx,
    frame.canvas,
    frame.image.GetObjectSelection(),
    frame.frameId);
}

/* method: "set_delay(s/100)\n
Sets the duration, in hundredths of a second, that this frame will be
shown when saved as a gif." */
static void frame_set_delay(const Frame& frame, const Delay& delay){
  if (delay.Get().count() < 0){
    // Fixme: -1 should probably mean 'forever' for gifs.
    throw ValueError("Negative delay");
  }

  auto oldDelay(Old(frame.GetImage().GetDelay()));
  auto newDelay(New(delay));

  frame.ctx.RunCommand(frame,
    set_frame_delay_command(frame.GetFrameIndex(),
      newDelay, oldDelay));
}

/* method: "set_hotspot(x,y)\n
Sets the hotspot to x,y. This is the anchor point for cursors
(.cur)." */
static void frame_set_hotspot(const Frame& frame, const HotSpot& pos){
  auto oldHotSpot(frame.GetImage().GetHotSpot());

  frame.ctx.RunCommand(frame,
    set_frame_hotspot_command(frame.GetFrameIndex(),
      New(pos), Old(oldHotSpot)));
}

/* method: "set_pixel((x,y),(r,g,b[,a]))\n
Sets the pixel at x,y to the specified color." */
static void frame_set_pixel(const Frame& frame,
  const IntPoint& pos,
  const Color& color)
{
  frame.image.GetBackground().Visit(
    [&](const Bitmap& bmp){
      if (invalid_pixel_pos(pos, bmp)){
        throw ValueError("Invalid pixel position");
      }
      frame.ctx.RunCommand(frame, put_pixel_command(pos, color));
    },
    [&](const ColorSpan& span){
      if (invalid_pixel_pos(pos, span)){
        throw ValueError("Invalid pixel position");
      }
      frame.ctx.RunCommand(frame, put_pixel_command(pos, color));
    });
}

using common_type = const Frame&;

void py_common_run_command(const Frame& frame, CommandPtr cmd){
  frame.ctx.RunCommand(frame, std::move(cmd));
}

/* extra_include: "generated/python/method-def/py-common-method-def.hh" */
/* extra_include: "generated/python/method-def/py-less-common-method-def.hh" */

#include "generated/python/method-def/py-frame-method-def.hh"

PyTypeObject FrameType = {
  PyVarObject_HEAD_INIT(nullptr, 0)
  "Frame", //tp_name
  sizeof(frameObject), // tp_basicsize
  0, // tp_itemsize
  nullptr, // tp_dealloc
  nullptr, // tp_print
  nullptr, // tp_getattr
  nullptr, // tp_setattr
  nullptr,  // tp_compare
  (reprfunc)frame_repr, // tp_repr
  nullptr, // tp_as_number
  nullptr, // tp_as_sequence
  nullptr, // tp_as_mapping
  nullptr, // tp_hash
  nullptr, // tp_call
  nullptr, // tp_str
  nullptr, // tp_getattro
  nullptr, // tp_setattro
  nullptr, // tp_as_buffer
  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
  "An frame in a Faint image.", // tp_doc
  nullptr, // tp_traverse
  nullptr, // tp_clear
  nullptr, // tp_richcompare
  0, // tp_weaklistoffset
  nullptr, // tp_iter
  nullptr, // tp_iternext
  frame_methods, // tp_methods
  nullptr, // tp_members
  nullptr, // tp_getset
  nullptr, // tp_base
  nullptr, // tp_dict
  nullptr, // tp_descr_get
  nullptr, // tp_descr_set
  0, // tp_dictoffset
  INIT_FORWARDER(frame_init), // tp_init
  nullptr, // tp_alloc
  frame_new, // tp_new
  nullptr, // tp_free
  nullptr, // tp_is_gc
  nullptr, // tp_bases
  nullptr, // tp_mro
  nullptr, // tp_cache
  nullptr, // tp_subclasses
  nullptr, // tp_weaklist
  nullptr, // tp_del
  0, // tp_version_tag
  nullptr  // tp_finalize
};

} // namespace
<commit_msg>Renamed frame.get_bitmap to get_background.<commit_after>// -*- coding: us-ascii-unix -*-
// Copyright 2013 Lukas Kemmer
//
// Licensed under the Apache License, Version 2.0 (the "License"); you
// may not use this file except in compliance with the License. You
// may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.

#include <sstream>
#include "app/app-context.hh"
#include "app/canvas.hh"
#include "app/frame.hh"
#include "commands/frame-cmd.hh"
#include "commands/put-pixel-cmd.hh"
#include "text/formatting.hh"
#include "util/command-util.hh"
#include "util/image.hh"
#include "util/object-util.hh"
#include "util/setting-util.hh"
#include "python/py-include.hh"
#include "python/py-canvas.hh"
#include "python/py-common.hh"
#include "python/py-frame.hh"
#include "python/py-less-common.hh"
#include "python/py-tri.hh"
#include "python/py-ugly-forward.hh"
#include "python/py-util.hh"
#include "python/python-context.hh"

namespace faint{

bool expired(frameObject* self){
  if (canvas_ok(self->canvasId, *self->ctx) && self->canvas->Has(self->frameId)){
    return false;
  }
  PyErr_SetString(PyExc_ValueError,
    "That frame is removed."); // Fixme: really do this?
  return true;
}

template<>
struct MappedType<const Frame&>{
  using PYTHON_TYPE = frameObject;

  static Frame GetCppObject(frameObject* self){
    return Frame(*self->ctx,
      *self->canvas,
      self->canvas->GetFrame(self->frameId));
  }

  static bool Expired(frameObject* self){
    return expired(self);
  }

  static void ShowError(frameObject*){
    PyErr_SetString(PyExc_ValueError, "That frame is removed.");
  }
};

static PyObject* frame_new(PyTypeObject* type, PyObject*, PyObject*){
  frameObject* self;
  self = (frameObject*)type->tp_alloc(type, 0);
  return (PyObject*)self;
}

static PyObject* frame_repr(frameObject* self){
  std::stringstream ss;
  if (canvas_ok(self->canvasId, *self->ctx)){
    ss << "Frame of canvas #" << self->canvasId.Raw();
  }
  else{
    ss << "Frame of retired Canvas #" << self->canvasId.Raw();
  }
  return Py_BuildValue("s", ss.str().c_str());
}

static void frame_init(frameObject&){
  throw TypeError("Frame can not be instantiated. "
    "Use image.get_frame or frames[index]");
}

/* method: "__copy__() Not implemented."
name: "__copy__" */
static void frame_copy(const Frame&){
  throw NotImplementedError("Frame can not be copied.");
}

// Fixme: Consider return bitmap even if ColorSpan?
/* method: "get_background()->bmp?\n
Returns a copy of the pixel data as a Bitmap." */
static const Optional<Bitmap>& frame_get_background(const Frame& frame){
  return frame.image.GetBackground().Get<Bitmap>();
}

/* method: "get_delay()->s/100\n
Returns the duration, in hundredths of a second, that this frame will
be shown when saved as a gif." */
static Delay frame_get_delay(const Frame& frame){
  return frame.GetImage().GetDelay();
}

/* method: "get_hotspot()-> x,y\n
Returns the hotspot for the frame. This is the anchor point for
cursors (.cur)." */
static IntPoint frame_get_hotspot(const Frame& frame){
  return frame.GetImage().GetHotSpot();
}

/* method: "get_size() -> w,h\n
Returns the size of the frame (in pixels)." */
static IntSize frame_get_size(const Frame& frame){
  return frame.image.GetSize();
}

/* method: "get_objects() -> objects\n
Returns a list of the objects in the frame, sorted from rear-most to
front-most." */
static BoundObjects frame_get_objects(const Frame& frame){
  return bind_objects(frame.ctx,
    frame.canvas,
    frame.image.GetObjects(),
    frame.frameId);
}

/* method: "get_calibration() -> ((x0,y0,x1,y1), length, unit)\n
Returns a line, its specified length and the unit this refers to - or
None if the image is not calibrated." */
static Optional<Calibration> frame_get_calibration(const Frame& frame){
  return frame.image.GetCalibration();
}

/* method: "get_selected() -> objects\n
Returns a list of the selected objects in the frame, sorted from rear-most to
front-most." */
static BoundObjects frame_get_selected(const Frame& frame){
  return bind_objects(frame.ctx,
    frame.canvas,
    frame.image.GetObjectSelection(),
    frame.frameId);
}

/* method: "set_delay(s/100)\n
Sets the duration, in hundredths of a second, that this frame will be
shown when saved as a gif." */
static void frame_set_delay(const Frame& frame, const Delay& delay){
  if (delay.Get().count() < 0){
    // Fixme: -1 should probably mean 'forever' for gifs.
    throw ValueError("Negative delay");
  }

  auto oldDelay(Old(frame.GetImage().GetDelay()));
  auto newDelay(New(delay));

  frame.ctx.RunCommand(frame,
    set_frame_delay_command(frame.GetFrameIndex(),
      newDelay, oldDelay));
}

/* method: "set_hotspot(x,y)\n
Sets the hotspot to x,y. This is the anchor point for cursors
(.cur)." */
static void frame_set_hotspot(const Frame& frame, const HotSpot& pos){
  auto oldHotSpot(frame.GetImage().GetHotSpot());

  frame.ctx.RunCommand(frame,
    set_frame_hotspot_command(frame.GetFrameIndex(),
      New(pos), Old(oldHotSpot)));
}

/* method: "set_pixel((x,y),(r,g,b[,a]))\n
Sets the pixel at x,y to the specified color." */
static void frame_set_pixel(const Frame& frame,
  const IntPoint& pos,
  const Color& color)
{
  frame.image.GetBackground().Visit(
    [&](const Bitmap& bmp){
      if (invalid_pixel_pos(pos, bmp)){
        throw ValueError("Invalid pixel position");
      }
      frame.ctx.RunCommand(frame, put_pixel_command(pos, color));
    },
    [&](const ColorSpan& span){
      if (invalid_pixel_pos(pos, span)){
        throw ValueError("Invalid pixel position");
      }
      frame.ctx.RunCommand(frame, put_pixel_command(pos, color));
    });
}

using common_type = const Frame&;

void py_common_run_command(const Frame& frame, CommandPtr cmd){
  frame.ctx.RunCommand(frame, std::move(cmd));
}

/* extra_include: "generated/python/method-def/py-common-method-def.hh" */
/* extra_include: "generated/python/method-def/py-less-common-method-def.hh" */

#include "generated/python/method-def/py-frame-method-def.hh"

PyTypeObject FrameType = {
  PyVarObject_HEAD_INIT(nullptr, 0)
  "Frame", //tp_name
  sizeof(frameObject), // tp_basicsize
  0, // tp_itemsize
  nullptr, // tp_dealloc
  nullptr, // tp_print
  nullptr, // tp_getattr
  nullptr, // tp_setattr
  nullptr,  // tp_compare
  (reprfunc)frame_repr, // tp_repr
  nullptr, // tp_as_number
  nullptr, // tp_as_sequence
  nullptr, // tp_as_mapping
  nullptr, // tp_hash
  nullptr, // tp_call
  nullptr, // tp_str
  nullptr, // tp_getattro
  nullptr, // tp_setattro
  nullptr, // tp_as_buffer
  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
  "An frame in a Faint image.", // tp_doc
  nullptr, // tp_traverse
  nullptr, // tp_clear
  nullptr, // tp_richcompare
  0, // tp_weaklistoffset
  nullptr, // tp_iter
  nullptr, // tp_iternext
  frame_methods, // tp_methods
  nullptr, // tp_members
  nullptr, // tp_getset
  nullptr, // tp_base
  nullptr, // tp_dict
  nullptr, // tp_descr_get
  nullptr, // tp_descr_set
  0, // tp_dictoffset
  INIT_FORWARDER(frame_init), // tp_init
  nullptr, // tp_alloc
  frame_new, // tp_new
  nullptr, // tp_free
  nullptr, // tp_is_gc
  nullptr, // tp_bases
  nullptr, // tp_mro
  nullptr, // tp_cache
  nullptr, // tp_subclasses
  nullptr, // tp_weaklist
  nullptr, // tp_del
  0, // tp_version_tag
  nullptr  // tp_finalize
};

} // namespace
<|endoftext|>