<commit_before>#include "coincontroltreewidget.h"
#include "coincontroldialog.h"

CoinControlTreeWidget::CoinControlTreeWidget(QWidget *parent) :
    QTreeWidget(parent)
{

}

void CoinControlTreeWidget::keyPressEvent(QKeyEvent *event)
{
    if (event->key() == Qt::Key_Space) // press spacebar -> select checkbox
    {
        event->ignore();
        int COLUMN_CHECKBOX = 0;
        this->currentItem()->setCheckState(COLUMN_CHECKBOX, ((this->currentItem()->checkState(COLUMN_CHECKBOX) == Qt::Checked) ? Qt::Unchecked : Qt::Checked));
    }
    else if (event->key() == Qt::Key_Escape) // press esc -> close dialog
    {
        event->ignore();
        CoinControlDialog *coinControlDialog = (CoinControlDialog*)this->parentWidget();
        coinControlDialog->done(QDialog::Accepted);
    }
    else
    {
        this->QTreeWidget::keyPressEvent(event);
    }
}<commit_msg>Исправление падения при нажатии пробела в CC<commit_after>#include "coincontroltreewidget.h"
#include "coincontroldialog.h"

CoinControlTreeWidget::CoinControlTreeWidget(QWidget *parent) :
    QTreeWidget(parent)
{

}

void CoinControlTreeWidget::keyPressEvent(QKeyEvent *event)
{
    if (event->key() == Qt::Key_Space) // press spacebar -> select checkbox
    {
        event->ignore();
        int COLUMN_CHECKBOX = 0;
        if(this->currentItem())
            this->currentItem()->setCheckState(COLUMN_CHECKBOX, ((this->currentItem()->checkState(COLUMN_CHECKBOX) == Qt::Checked) ? Qt::Unchecked : Qt::Checked));
    }
    else if (event->key() == Qt::Key_Escape) // press esc -> close dialog
    {
        event->ignore();
        CoinControlDialog *coinControlDialog = (CoinControlDialog*)this->parentWidget();
        coinControlDialog->done(QDialog::Accepted);
    }
    else
    {
        this->QTreeWidget::keyPressEvent(event);
    }
}
<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2013-2019 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <inviwo/qt/editor/settingswidget.h>
#include <modules/qtwidgets/properties/propertywidgetqt.h>
#include <modules/qtwidgets/propertylistwidget.h>
#include <modules/qtwidgets/properties/collapsiblegroupboxwidgetqt.h>
#include <inviwo/core/properties/propertywidgetfactory.h>
#include <inviwo/core/common/inviwoapplication.h>
#include <inviwo/core/util/settings/settings.h>
#include <inviwo/qt/editor/inviwomainwindow.h>

#include <warn/push>
#include <warn/ignore/all>
#include <QVBoxLayout>
#include <QString>
#include <QScrollArea>
#include <QLayout>
#include <QFrame>
#include <warn/pop>

namespace inviwo {

SettingsWidget::SettingsWidget(const QString& title, InviwoMainWindow* mainwindow)
    : InviwoDockWidget(title, mainwindow, "SettingsWidget"), mainwindow_(mainwindow) {

    setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
    resize(utilqt::emToPx(this, QSizeF(60, 60)));  // default size

    scrollArea_ = new QScrollArea();
    scrollArea_->setWidgetResizable(true);
    scrollArea_->setMinimumWidth(utilqt::emToPx(this, 35));
    scrollArea_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    scrollArea_->setFrameShape(QFrame::NoFrame);
    scrollArea_->setContentsMargins(0, 0, 0, 0);

    mainWidget_ = new QWidget();
    layout_ = new QVBoxLayout(mainWidget_);
    layout_->setAlignment(Qt::AlignTop);
    const auto space = utilqt::refSpacePx(this);
    layout_->setContentsMargins(0, space, 0, space);
    layout_->setSpacing(space);
    scrollArea_->setWidget(mainWidget_);

    setWidget(scrollArea_);

    onModulesDidRegister_ =
        mainwindow->getInviwoApplication()->getModuleManager().onModulesDidRegister(
            [&]() { updateSettingsWidget(); });
    onModulesWillUnregister_ =
        mainwindow->getInviwoApplication()->getModuleManager().onModulesWillUnregister([&]() {
            while (auto item = layout_->takeAt(0)) {
                delete item;
            }
        });
}

SettingsWidget::SettingsWidget(InviwoMainWindow* mainwindow)
    : SettingsWidget(tr("Settings"), mainwindow) {}

SettingsWidget::~SettingsWidget() = default;

void SettingsWidget::updateSettingsWidget() {
    auto settings = mainwindow_->getInviwoApplication()->getModuleSettings();

    for (auto setting : settings) {
        auto settingsGroup = new CollapsibleGroupBoxWidgetQt(setting);
        layout_->addWidget(settingsGroup);
        settingsGroup->initState();

        for (auto prop : setting->getProperties()) {
            settingsGroup->addProperty(prop);
        }

        if (!settingsGroup->isCollapsed()) {
            settingsGroup->toggleCollapsed();
        }
    }
    layout_->addStretch();
}

}  // namespace inviwo<commit_msg>Qt: adds missing includes<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2013-2019 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <inviwo/qt/editor/settingswidget.h>
#include <modules/qtwidgets/properties/propertywidgetqt.h>
#include <modules/qtwidgets/propertylistwidget.h>
#include <modules/qtwidgets/properties/collapsiblegroupboxwidgetqt.h>
#include <inviwo/core/properties/propertywidgetfactory.h>
#include <inviwo/core/common/inviwoapplication.h>
#include <inviwo/core/util/settings/settings.h>
#include <inviwo/qt/editor/inviwomainwindow.h>
#include <modules/qtwidgets/inviwoqtutils.h>

#include <warn/push>
#include <warn/ignore/all>
#include <QVBoxLayout>
#include <QString>
#include <QScrollArea>
#include <QLayout>
#include <QFrame>
#include <warn/pop>

namespace inviwo {

SettingsWidget::SettingsWidget(const QString& title, InviwoMainWindow* mainwindow)
    : InviwoDockWidget(title, mainwindow, "SettingsWidget"), mainwindow_(mainwindow) {

    setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
    resize(utilqt::emToPx(this, QSizeF(60, 60)));  // default size

    scrollArea_ = new QScrollArea();
    scrollArea_->setWidgetResizable(true);
    scrollArea_->setMinimumWidth(utilqt::emToPx(this, 30));
    scrollArea_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    scrollArea_->setFrameShape(QFrame::NoFrame);
    scrollArea_->setContentsMargins(0, 0, 0, 0);

    mainWidget_ = new QWidget();
    layout_ = new QVBoxLayout(mainWidget_);
    layout_->setAlignment(Qt::AlignTop);
    const auto space = utilqt::refSpacePx(this);
    layout_->setContentsMargins(0, space, 0, space);
    layout_->setSpacing(space);
    scrollArea_->setWidget(mainWidget_);

    setWidget(scrollArea_);

    onModulesDidRegister_ =
        mainwindow->getInviwoApplication()->getModuleManager().onModulesDidRegister(
            [&]() { updateSettingsWidget(); });
    onModulesWillUnregister_ =
        mainwindow->getInviwoApplication()->getModuleManager().onModulesWillUnregister([&]() {
            while (auto item = layout_->takeAt(0)) {
                delete item;
            }
        });
}

SettingsWidget::SettingsWidget(InviwoMainWindow* mainwindow)
    : SettingsWidget(tr("Settings"), mainwindow) {}

SettingsWidget::~SettingsWidget() = default;

void SettingsWidget::updateSettingsWidget() {
    auto settings = mainwindow_->getInviwoApplication()->getModuleSettings();

    for (auto setting : settings) {
        auto settingsGroup = new CollapsibleGroupBoxWidgetQt(setting);
        layout_->addWidget(settingsGroup);
        settingsGroup->initState();

        for (auto prop : setting->getProperties()) {
            settingsGroup->addProperty(prop);
        }

        if (!settingsGroup->isCollapsed()) {
            settingsGroup->toggleCollapsed();
        }
    }
    layout_->addStretch();
}

}  // namespace inviwo<|endoftext|>


<commit_before>/*
 * This file is part of the telepathy-nonsense connection manager.
 * Copyright (C) 2015 Niels Ole Salscheider <niels_ole@salscheider-online.de>
 * Copyright (C) 2014 Alexandr Akulich <akulichalexander@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, see <http://www.gnu.org/licenses/>
 */

#include "textchannel.hh"
#include "common.hh"
#include "connection.hh"

TextChannel::TextChannel(Connection *connection, Tp::BaseChannel *baseChannel)
    : Tp::BaseChannelTextType(baseChannel),
      m_connection(connection),
      m_targetHandle(baseChannel->targetHandle()),
      m_targetJid(baseChannel->targetID())
{
    DBG;
    QStringList supportedContentTypes = QStringList() << QLatin1String("text/plain");
    Tp::UIntList messageTypes = Tp::UIntList() << Tp::ChannelTextMessageTypeNormal
                                               << Tp::ChannelTextMessageTypeDeliveryReport;

    uint messagePartSupportFlags = Tp::MessageSendingFlagReportDelivery | Tp::MessageSendingFlagReportRead;
    uint deliveryReportingSupport = Tp::DeliveryReportingSupportFlagReceiveSuccesses | Tp::DeliveryReportingSupportFlagReceiveRead;

    setMessageAcknowledgedCallback(Tp::memFun(this, &TextChannel::messageAcknowledged));

    m_messagesIface = Tp::BaseChannelMessagesInterface::create(this,
                                                               supportedContentTypes,
                                                               messageTypes,
                                                               messagePartSupportFlags,
                                                               deliveryReportingSupport);

    baseChannel->plugInterface(Tp::AbstractChannelInterfacePtr::dynamicCast(m_messagesIface));
    m_messagesIface->setSendMessageCallback(Tp::memFun(this, &TextChannel::sendMessage));

    m_chatStateIface = Tp::BaseChannelChatStateInterface::create();
    m_chatStateIface->setSetChatStateCallback(Tp::memFun(this, &TextChannel::setChatState));
    baseChannel->plugInterface(Tp::AbstractChannelInterfacePtr::dynamicCast(m_chatStateIface));
}

TextChannelPtr TextChannel::create(Connection *connection, Tp::BaseChannel *baseChannel)
{
    return TextChannelPtr(new TextChannel(connection, baseChannel));
}

QString TextChannel::sendMessage(const Tp::MessagePartList &messageParts, uint flags, Tp::DBusError *error)
{
    QUuid messageToken = QUuid::createUuid();
    QXmppMessage message;
    message.setTo(targetJid());
    message.setFrom(selfJid());
    message.setId(messageToken.toString());

    if (flags & (Tp::MessageSendingFlagReportDelivery | Tp::MessageSendingFlagReportRead)) {
        message.setReceiptRequested(true);
        message.setMarkable(true);
    }

    QString content;
    for (auto &part : messageParts) {
        // TODO handle other parts?
        if(part.count(QLatin1String("content-type")) && part.value(QLatin1String("content-type")).variant().toString() == QLatin1String("text/plain") && part.count(QLatin1String("content"))) {
            content = part.value(QLatin1String("content")).variant().toString();
            break;
        }
    }
    message.setBody(content);

    sendQXmppMessage(message);
    return messageToken.toString();
}

void TextChannel::onMessageReceived(const QXmppMessage &message)
{
    processReceivedMessage(message, m_targetHandle, m_targetJid);
}

void TextChannel::processReceivedMessage(const QXmppMessage &message, uint senderHandle, const QString &senderID)
{
    Tp::MessagePart header;
    header[QLatin1String("message-token")] = QDBusVariant(message.id());
    if (message.stamp().isValid()) {
        header[QLatin1String("message-sent")]  = QDBusVariant(message.stamp().toMSecsSinceEpoch() / 1000);
    }
    header[QLatin1String("message-received")]  = QDBusVariant(QDateTime::currentMSecsSinceEpoch() / 1000);
    header[QLatin1String("message-sender")]    = QDBusVariant(senderHandle);
    header[QLatin1String("message-sender-id")] = QDBusVariant(senderID);

    /* Handle chat states */
    if (message.state() != QXmppMessage::None) {
        Tp::ChannelChatState state = Tp::ChannelChatStateActive;
        switch(message.state()) {
        case QXmppMessage::Active:
            state = Tp::ChannelChatStateActive;
            break;
        case QXmppMessage::Composing:
            state = Tp::ChannelChatStateComposing;
            break;
        case QXmppMessage::Gone:
            state = Tp::ChannelChatStateGone;
            break;
        case QXmppMessage::Inactive:
            state = Tp::ChannelChatStateInactive;
            break;
        case QXmppMessage::Paused:
            state = Tp::ChannelChatStatePaused;
            break;
        default:
            Q_ASSERT(0);
        }
        m_chatStateIface->chatStateChanged(senderHandle, state);
    }

    /* Handle chat markers */
    if (message.marker() != QXmppMessage::NoMarker) {
        Tp::MessagePartList partList;
        header[QLatin1String("message-type")]  = QDBusVariant(Tp::ChannelTextMessageTypeDeliveryReport);

        switch (message.marker()) {
        case QXmppMessage::Acknowledged:
            header[QLatin1String("delivery-status")] = QDBusVariant(Tp::DeliveryStatusRead);
            break;
        case QXmppMessage::Displayed:
        case QXmppMessage::Received:
            header[QLatin1String("delivery-status")] = QDBusVariant(Tp::DeliveryStatusDelivered);
            break;
        default:
            Q_ASSERT(0);
        }
        partList << header;
        addReceivedMessage(partList);
    }

    /* Send receipt */
    if (message.isReceiptRequested()) {
        QUuid outMessageToken = QUuid::createUuid();
        QXmppMessage outMessage;
        outMessage.setMarker(QXmppMessage::Received);
        outMessage.setTo(message.from());
        outMessage.setFrom(selfJid());
        outMessage.setMarkerId(message.id());
        outMessage.setId(outMessageToken.toString());

        sendQXmppMessage(outMessage);
    }

    /* Text message */
    if (!message.body().isEmpty()) {
        Tp::MessagePartList body;
        Tp::MessagePart text;
        text[QLatin1String("content-type")] = QDBusVariant(QLatin1String("text/plain"));
        text[QLatin1String("content")]      = QDBusVariant(message.body());
        body << text;

        Tp::MessagePartList partList;
        header[QLatin1String("message-type")]  = QDBusVariant(Tp::ChannelTextMessageTypeNormal);
        partList << header << body;
        addReceivedMessage(partList);
    }
}

bool TextChannel::sendQXmppMessage(QXmppMessage &message)
{
    return m_connection->qxmppClient()->sendPacket(message);
}

QString TextChannel::targetJid() const
{
    return m_targetJid + m_connection->lastResourceForJid(m_targetJid);
}

QString TextChannel::selfJid() const
{
    return m_connection->qxmppClient()->configuration().jid();
}

void TextChannel::messageAcknowledged(const QString &messageId)
{
    QUuid messageToken = QUuid::createUuid();
    QXmppMessage message;
    message.setMarker(QXmppMessage::Displayed);
    message.setTo(targetJid()); //TODO: Should we make sure that we send the "displayed" ack to the same resource as the "received" ack?
    message.setFrom(selfJid());
    message.setId(messageToken.toString());
    message.setMarkerId(messageId);

    sendQXmppMessage(message);
}

void TextChannel::setChatState(uint state, Tp::DBusError *error)
{
    Q_UNUSED(error);

    QUuid messageToken = QUuid::createUuid();
    QXmppMessage message;
    switch (state) {
    case Tp::ChannelChatStateActive:
        message.setState(QXmppMessage::Active);
        break;
    case Tp::ChannelChatStateComposing:
        message.setState(QXmppMessage::Composing);
        break;
    case Tp::ChannelChatStateGone:
        message.setState(QXmppMessage::Gone);
        break;
    case Tp::ChannelChatStateInactive:
        message.setState(QXmppMessage::Inactive);
        break;
    case Tp::ChannelChatStatePaused:
        message.setState(QXmppMessage::Paused);
        break;
    default:
        Q_ASSERT(0);
    }
    message.setTo(targetJid());
    message.setFrom(selfJid());
    message.setId(messageToken.toString());

    sendQXmppMessage(message);
}
<commit_msg>TextChannel: Implemented error message processing.<commit_after>/*
 * This file is part of the telepathy-nonsense connection manager.
 * Copyright (C) 2015 Niels Ole Salscheider <niels_ole@salscheider-online.de>
 * Copyright (C) 2014 Alexandr Akulich <akulichalexander@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, see <http://www.gnu.org/licenses/>
 */

#include "textchannel.hh"
#include "common.hh"
#include "connection.hh"

QString xmppConditionToStr(QXmppStanza::Error::Condition condition)
{
    switch (condition) {
    case QXmppStanza::Error::BadRequest:
        return QLatin1String("Bad request");
    case QXmppStanza::Error::Conflict:
        return QLatin1String("Conflict");
    case QXmppStanza::Error::FeatureNotImplemented:
        return QLatin1String("Feature is not implemented");
    case QXmppStanza::Error::Forbidden:
        return QLatin1String("Forbidden");
    case QXmppStanza::Error::Gone:
        return QLatin1String("Gone");
    case QXmppStanza::Error::InternalServerError:
        return QLatin1String("Internal server error");
    case QXmppStanza::Error::ItemNotFound:
        return QLatin1String("Item not found");
    case QXmppStanza::Error::JidMalformed:
        return QLatin1String("Jid is malformed");
    case QXmppStanza::Error::NotAcceptable:
        return QLatin1String("Not acceptable");
    case QXmppStanza::Error::NotAllowed:
        return QLatin1String("Not allowed");
    case QXmppStanza::Error::NotAuthorized:
        return QLatin1String("Not authorized");
    case QXmppStanza::Error::PaymentRequired:
        return QLatin1String("Payment required");
    case QXmppStanza::Error::RecipientUnavailable:
        return QLatin1String("Recipient unavailable");
    case QXmppStanza::Error::Redirect:
        return QLatin1String("Redirect");
    case QXmppStanza::Error::RegistrationRequired:
        return QLatin1String("Registration required");
    case QXmppStanza::Error::RemoteServerNotFound:
        return QLatin1String("Remote server not found");
    case QXmppStanza::Error::RemoteServerTimeout:
        return QLatin1String("Remote server timeout");
    case QXmppStanza::Error::ResourceConstraint:
        return QLatin1String("Resource constraint");
    case QXmppStanza::Error::ServiceUnavailable:
        return QLatin1String("Service unavailable");
    case QXmppStanza::Error::SubscriptionRequired:
        return QLatin1String("Subscription required");
    case QXmppStanza::Error::UndefinedCondition:
        return QLatin1String("Undefined condition");
    case QXmppStanza::Error::UnexpectedRequest:
        return QLatin1String("Unexpected request");
    default:
        return QLatin1String("Unknown error");
    }
}

TextChannel::TextChannel(Connection *connection, Tp::BaseChannel *baseChannel)
    : Tp::BaseChannelTextType(baseChannel),
      m_connection(connection),
      m_targetHandle(baseChannel->targetHandle()),
      m_targetJid(baseChannel->targetID())
{
    DBG;
    QStringList supportedContentTypes = QStringList() << QLatin1String("text/plain");
    Tp::UIntList messageTypes = Tp::UIntList() << Tp::ChannelTextMessageTypeNormal
                                               << Tp::ChannelTextMessageTypeDeliveryReport;

    uint messagePartSupportFlags = Tp::MessageSendingFlagReportDelivery | Tp::MessageSendingFlagReportRead;
    uint deliveryReportingSupport = Tp::DeliveryReportingSupportFlagReceiveSuccesses | Tp::DeliveryReportingSupportFlagReceiveRead;

    setMessageAcknowledgedCallback(Tp::memFun(this, &TextChannel::messageAcknowledged));

    m_messagesIface = Tp::BaseChannelMessagesInterface::create(this,
                                                               supportedContentTypes,
                                                               messageTypes,
                                                               messagePartSupportFlags,
                                                               deliveryReportingSupport);

    baseChannel->plugInterface(Tp::AbstractChannelInterfacePtr::dynamicCast(m_messagesIface));
    m_messagesIface->setSendMessageCallback(Tp::memFun(this, &TextChannel::sendMessage));

    m_chatStateIface = Tp::BaseChannelChatStateInterface::create();
    m_chatStateIface->setSetChatStateCallback(Tp::memFun(this, &TextChannel::setChatState));
    baseChannel->plugInterface(Tp::AbstractChannelInterfacePtr::dynamicCast(m_chatStateIface));
}

TextChannelPtr TextChannel::create(Connection *connection, Tp::BaseChannel *baseChannel)
{
    return TextChannelPtr(new TextChannel(connection, baseChannel));
}

QString TextChannel::sendMessage(const Tp::MessagePartList &messageParts, uint flags, Tp::DBusError *error)
{
    QUuid messageToken = QUuid::createUuid();
    QXmppMessage message;
    message.setTo(targetJid());
    message.setFrom(selfJid());
    message.setId(messageToken.toString());

    if (flags & (Tp::MessageSendingFlagReportDelivery | Tp::MessageSendingFlagReportRead)) {
        message.setReceiptRequested(true);
        message.setMarkable(true);
    }

    QString content;
    for (auto &part : messageParts) {
        // TODO handle other parts?
        if(part.count(QLatin1String("content-type")) && part.value(QLatin1String("content-type")).variant().toString() == QLatin1String("text/plain") && part.count(QLatin1String("content"))) {
            content = part.value(QLatin1String("content")).variant().toString();
            break;
        }
    }
    message.setBody(content);

    sendQXmppMessage(message);
    return messageToken.toString();
}

void TextChannel::onMessageReceived(const QXmppMessage &message)
{
    processReceivedMessage(message, m_targetHandle, m_targetJid);
}

void TextChannel::processReceivedMessage(const QXmppMessage &message, uint senderHandle, const QString &senderID)
{
    Tp::MessagePart header;
    header[QLatin1String("message-token")] = QDBusVariant(message.id());
    if (message.stamp().isValid()) {
        header[QLatin1String("message-sent")]  = QDBusVariant(message.stamp().toMSecsSinceEpoch() / 1000);
    }
    header[QLatin1String("message-received")]  = QDBusVariant(QDateTime::currentMSecsSinceEpoch() / 1000);
    header[QLatin1String("message-sender")]    = QDBusVariant(senderHandle);
    header[QLatin1String("message-sender-id")] = QDBusVariant(senderID);

    /* Handle chat states */
    if (message.state() != QXmppMessage::None) {
        Tp::ChannelChatState state = Tp::ChannelChatStateActive;
        switch(message.state()) {
        case QXmppMessage::Active:
            state = Tp::ChannelChatStateActive;
            break;
        case QXmppMessage::Composing:
            state = Tp::ChannelChatStateComposing;
            break;
        case QXmppMessage::Gone:
            state = Tp::ChannelChatStateGone;
            break;
        case QXmppMessage::Inactive:
            state = Tp::ChannelChatStateInactive;
            break;
        case QXmppMessage::Paused:
            state = Tp::ChannelChatStatePaused;
            break;
        default:
            Q_ASSERT(0);
        }
        m_chatStateIface->chatStateChanged(senderHandle, state);
    }

    if (message.type() == QXmppMessage::Error) {
        Tp::MessagePartList partList;
        header[QLatin1String("message-type")]  = QDBusVariant(Tp::ChannelTextMessageTypeDeliveryReport);

        switch (message.error().type()) {
        // It seems that there is no "continue" error type in the spec
        case QXmppStanza::Error::Cancel:
        case QXmppStanza::Error::Modify:
        case QXmppStanza::Error::Auth:
            header[QLatin1String("delivery-status")] = QDBusVariant(Tp::DeliveryStatusPermanentlyFailed);
            break;
        case QXmppStanza::Error::Wait:
            header[QLatin1String("delivery-status")] = QDBusVariant(Tp::DeliveryStatusTemporarilyFailed);
            break;
        default:
            break;
        }

        QString errorMessage = xmppConditionToStr(message.error().condition());

        if (message.error().code() != 0) {
            errorMessage.append(QString(QLatin1String(" (code %1)")).arg(message.error().code()));
        }

        header[QLatin1String("delivery-error-message")] = QDBusVariant(errorMessage);

        partList << header;
        addReceivedMessage(partList);
        return;
    }

    /* Handle chat markers */
    if (message.marker() != QXmppMessage::NoMarker) {
        Tp::MessagePartList partList;
        header[QLatin1String("message-type")]  = QDBusVariant(Tp::ChannelTextMessageTypeDeliveryReport);

        switch (message.marker()) {
        case QXmppMessage::Acknowledged:
            header[QLatin1String("delivery-status")] = QDBusVariant(Tp::DeliveryStatusRead);
            break;
        case QXmppMessage::Displayed:
        case QXmppMessage::Received:
            header[QLatin1String("delivery-status")] = QDBusVariant(Tp::DeliveryStatusDelivered);
            break;
        default:
            Q_ASSERT(0);
        }
        partList << header;
        addReceivedMessage(partList);
    }

    /* Send receipt */
    if (message.isReceiptRequested()) {
        QUuid outMessageToken = QUuid::createUuid();
        QXmppMessage outMessage;
        outMessage.setMarker(QXmppMessage::Received);
        outMessage.setTo(message.from());
        outMessage.setFrom(selfJid());
        outMessage.setMarkerId(message.id());
        outMessage.setId(outMessageToken.toString());

        sendQXmppMessage(outMessage);
    }

    /* Text message */
    if (!message.body().isEmpty()) {
        Tp::MessagePartList body;
        Tp::MessagePart text;
        text[QLatin1String("content-type")] = QDBusVariant(QLatin1String("text/plain"));
        text[QLatin1String("content")]      = QDBusVariant(message.body());
        body << text;

        Tp::MessagePartList partList;
        header[QLatin1String("message-type")]  = QDBusVariant(Tp::ChannelTextMessageTypeNormal);
        partList << header << body;
        addReceivedMessage(partList);
    }
}

bool TextChannel::sendQXmppMessage(QXmppMessage &message)
{
    return m_connection->qxmppClient()->sendPacket(message);
}

QString TextChannel::targetJid() const
{
    return m_targetJid + m_connection->lastResourceForJid(m_targetJid);
}

QString TextChannel::selfJid() const
{
    return m_connection->qxmppClient()->configuration().jid();
}

void TextChannel::messageAcknowledged(const QString &messageId)
{
    QUuid messageToken = QUuid::createUuid();
    QXmppMessage message;
    message.setMarker(QXmppMessage::Displayed);
    message.setTo(targetJid()); //TODO: Should we make sure that we send the "displayed" ack to the same resource as the "received" ack?
    message.setFrom(selfJid());
    message.setId(messageToken.toString());
    message.setMarkerId(messageId);

    sendQXmppMessage(message);
}

void TextChannel::setChatState(uint state, Tp::DBusError *error)
{
    Q_UNUSED(error);

    QUuid messageToken = QUuid::createUuid();
    QXmppMessage message;
    switch (state) {
    case Tp::ChannelChatStateActive:
        message.setState(QXmppMessage::Active);
        break;
    case Tp::ChannelChatStateComposing:
        message.setState(QXmppMessage::Composing);
        break;
    case Tp::ChannelChatStateGone:
        message.setState(QXmppMessage::Gone);
        break;
    case Tp::ChannelChatStateInactive:
        message.setState(QXmppMessage::Inactive);
        break;
    case Tp::ChannelChatStatePaused:
        message.setState(QXmppMessage::Paused);
        break;
    default:
        Q_ASSERT(0);
    }
    message.setTo(targetJid());
    message.setFrom(selfJid());
    message.setId(messageToken.toString());

    sendQXmppMessage(message);
}
<|endoftext|>


<commit_before>//
//  refract/RenderJSONVisitor.cc
//  librefract
//
//  Created by Pavan Kumar Sunkara on 17/06/15.
//  Copyright (c) 2015 Apiary Inc. All rights reserved.
//

#include "Element.h"
#include "Visitors.h"
#include "sosJSON.h"
#include <sstream>

namespace refract
{

    RenderJSONVisitor::RenderJSONVisitor(const sos::Base::Type& type_)
    : type(type_), isExtend(false) {}

    RenderJSONVisitor::RenderJSONVisitor()
    : type(sos::Base::UndefinedType), isExtend(false) {}

    void RenderJSONVisitor::assign(sos::Base value) {
        if (isExtend) {
            extend(value);
        }
        else if (type == sos::Base::ArrayType) {
            pArr.push(value);
        }
        else if (type == sos::Base::UndefinedType) {
            result = value;
        }
    }

    void RenderJSONVisitor::assign(std::string key, sos::Base value) {
        if (!key.empty() && type == sos::Base::ObjectType) {
            pObj.set(key, value);
        }
    }

    void RenderJSONVisitor::extend(sos::Base value) {
        if (type == sos::Base::ObjectType) {

            for (sos::KeyValues::iterator it = value.object().begin();
                 it != value.object().end();
                 ++it) {

                pObj.set(it->first, it->second);
            }
        }
        else if (type == sos::Base::ArrayType) {

            for (sos::Bases::iterator it = value.array().begin();
                 it != value.array().end();
                 ++it) {

                pArr.push(*it);
            }
        }
    }

    void RenderJSONVisitor::visit(const IElement& e) {
        e.content(*this);
    }

    void RenderJSONVisitor::visit(const MemberElement& e) {
        RenderJSONVisitor renderer;
        if (e.value.second) {
            renderer.visit(*e.value.second);
        }

        if (StringElement* str = TypeQueryVisitor::as<StringElement>(e.value.first)) {
            assign(str->value, renderer.get());
        }
        else {
            throw std::logic_error("A property's key in the object is not of type string");
        }
    }

    void RenderJSONVisitor::visit(const ObjectElement& e) {
        // If the element is a mixin reference
        if (e.element() == "ref") {
            IElement::MemberElementCollection::const_iterator resolved = e.attributes.find("resolved");

            if (resolved == e.attributes.end()) {
                return;
            }

            RenderJSONVisitor renderer;
            if ((*resolved)->value.second) {
                renderer.visit(*(*resolved)->value.second);
            }

            // Imitate an extend object
            isExtend = true;
            assign(renderer.get());
            isExtend = false;

            return;
        }

        RenderJSONVisitor renderer(sos::Base::ObjectType);
        std::vector<refract::IElement*>::const_iterator it;

        if (e.element() == "extend") {
            renderer.isExtend = true;
        }

        for (it = e.value.begin(); it != e.value.end(); ++it) {
            if (*it) {
                renderer.visit(*(*it));
            }
        }

        assign(renderer.get());
    }

    void RenderJSONVisitor::visit(const ArrayElement& e) {
        RenderJSONVisitor renderer(sos::Base::ArrayType);
        std::vector<refract::IElement*>::const_iterator it;

        if (e.element() == "extend") {
            renderer.isExtend = true;
        }

        for (it = e.value.begin(); it != e.value.end(); ++it) {
            if (*it) {
                renderer.visit(*(*it));
            }
        }

        assign(renderer.get());
    }

    void RenderJSONVisitor::visit(const NullElement& e) {}

    void RenderJSONVisitor::visit(const StringElement& e) {
        assign(sos::String(e.value));
    }

    void RenderJSONVisitor::visit(const NumberElement& e) {
        assign(sos::Number(e.value));
    }

    void RenderJSONVisitor::visit(const BooleanElement& e) {
        assign(sos::Boolean(e.value));
    }

    sos::Base RenderJSONVisitor::get() const {
        if (type == sos::Base::ArrayType) {
            return pArr;
        }
        else if (type == sos::Base::ObjectType) {
            return pObj;
        }

        return result;
    }

    std::string RenderJSONVisitor::getString() const {
        sos::SerializeJSON serializer;
        std::stringstream ss;

        serializer.process(get(), ss);
        return ss.str();
    }
}
<commit_msg>Boutique - render JSON from "samples" and "default"<commit_after>//
//  refract/RenderJSONVisitor.cc
//  librefract
//
//  Created by Pavan Kumar Sunkara on 17/06/15.
//  Copyright (c) 2015 Apiary Inc. All rights reserved.
//

#include "Element.h"
#include "Visitors.h"
#include "sosJSON.h"
#include <sstream>

namespace refract
{

    RenderJSONVisitor::RenderJSONVisitor(const sos::Base::Type& type_)
    : type(type_), isExtend(false) {}

    RenderJSONVisitor::RenderJSONVisitor()
    : type(sos::Base::UndefinedType), isExtend(false) {}

    void RenderJSONVisitor::assign(sos::Base value) {
        if (isExtend) {
            extend(value);
        }
        else if (type == sos::Base::ArrayType) {
            pArr.push(value);
        }
        else if (type == sos::Base::UndefinedType) {
            result = value;
        }
    }

    void RenderJSONVisitor::assign(std::string key, sos::Base value) {
        if (!key.empty() && type == sos::Base::ObjectType) {
            pObj.set(key, value);
        }
    }

    void RenderJSONVisitor::extend(sos::Base value) {
        if (type == sos::Base::ObjectType) {

            for (sos::KeyValues::iterator it = value.object().begin();
                 it != value.object().end();
                 ++it) {

                pObj.set(it->first, it->second);
            }
        }
        else if (type == sos::Base::ArrayType) {

            for (sos::Bases::iterator it = value.array().begin();
                 it != value.array().end();
                 ++it) {

                pArr.push(*it);
            }
        }
    }

    void RenderJSONVisitor::visit(const IElement& e) {
        e.content(*this);
    }

    void RenderJSONVisitor::visit(const MemberElement& e) {
        RenderJSONVisitor renderer;

        if (e.value.second) {
            renderer.visit(*e.value.second);
        }

        if (StringElement* str = TypeQueryVisitor::as<StringElement>(e.value.first)) {
            assign(str->value, renderer.get());
        }
        else {
            throw std::logic_error("A property's key in the object is not of type string");
        }
    }

    template<typename T>
    const T* getDefault(const T& e) {
        IElement::MemberElementCollection::const_iterator i = e.attributes.find("default");

        if (i == e.attributes.end()) {
            return NULL;
        }

        return TypeQueryVisitor::as<T>((*i)->value.second);
    }

    template<typename T>
    const T* getSample(const T& e) {
        IElement::MemberElementCollection::const_iterator i = e.attributes.find("samples");

        if (i == e.attributes.end()) {
            return NULL;
        }

        ArrayElement* a = TypeQueryVisitor::as<ArrayElement>((*i)->value.second);

        if (!a || a->value.empty()) {
            return NULL;
        }

        return TypeQueryVisitor::as<T>(*(a->value.begin()));
    }

    template<typename T, typename R = typename T::ValueType>
    struct getValue {
        const T& element;

        getValue(const T& e) : element(e) {}

        operator const R*() {
            if (const T* d = getDefault(element)) {
                return &d->value;
            }

            if (const T* s = getSample(element)) {
                return &s->value;
            }

            return &element.value;
        }
    };

    void RenderJSONVisitor::visit(const ObjectElement& e) {
        // If the element is a mixin reference
        if (e.element() == "ref") {
            IElement::MemberElementCollection::const_iterator resolved = e.attributes.find("resolved");

            if (resolved == e.attributes.end()) {
                return;
            }

            RenderJSONVisitor renderer;
            if ((*resolved)->value.second) {
                renderer.visit(*(*resolved)->value.second);
            }

            // Imitate an extend object
            isExtend = true;
            assign(renderer.get());
            isExtend = false;

            return;
        }

        RenderJSONVisitor renderer(sos::Base::ObjectType);

        const ObjectElement::ValueType* val = getValue<ObjectElement>(e);

        if (!val) {
            return;
        }

        if (e.element() == "extend") {
            renderer.isExtend = true;
        }

        for (std::vector<refract::IElement*>::const_iterator it = val->begin();
             it != val->end();
             ++it) {

            if (*it) {
                renderer.visit(*(*it));
            }
        }

        assign(renderer.get());
    }

    void RenderJSONVisitor::visit(const ArrayElement& e) {
        RenderJSONVisitor renderer(sos::Base::ArrayType);

        const ArrayElement::ValueType* val = getValue<ArrayElement>(e);

        if (!val) {
            return;
        }

        if (e.element() == "extend") {
            renderer.isExtend = true;
        }

        for (ArrayElement::ValueType::const_iterator it = val->begin();
             it != val->end();
             ++it) {

            if (*it) {
                renderer.visit(*(*it));
            }
        }

        assign(renderer.get());
    }

    void RenderJSONVisitor::visit(const NullElement& e) {}

    void RenderJSONVisitor::visit(const StringElement& e) {
        const StringElement::ValueType* v = getValue<StringElement>(e);

        if (v) {
            assign(sos::String(*v));
        }
    }

    void RenderJSONVisitor::visit(const NumberElement& e) {
        const NumberElement::ValueType* v = getValue<NumberElement>(e);

        if (v) {
            assign(sos::Number(*v));
        }
    }

    void RenderJSONVisitor::visit(const BooleanElement& e) {
        const BooleanElement::ValueType* v = getValue<BooleanElement>(e);

        if (v) {
            assign(sos::Boolean(*v));
        }
    }

    sos::Base RenderJSONVisitor::get() const {
        if (type == sos::Base::ArrayType) {
            return pArr;
        }
        else if (type == sos::Base::ObjectType) {
            return pObj;
        }

        return result;
    }

    std::string RenderJSONVisitor::getString() const {
        sos::SerializeJSON serializer;
        std::stringstream ss;

        serializer.process(get(), ss);
        return ss.str();
    }
}
<|endoftext|>


<commit_before>#include "log_impl.h"

#include <cerrno>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <sstream>
#include <string>
#include <vector>
#include <boost/asio/ip/host_name.hpp>
#include <dlfcn.h>
#include <stdlib.h>

#include "proto/zlog.pb.h"
#include "include/zlog/log.h"
#include "include/zlog/backend.h"
#include "include/zlog/cache.h"

#include "striper.h"

namespace zlog {

LogImpl::LogImpl(std::shared_ptr<Backend> backend,
    const std::string& name,
    const std::string& hoid,
    const std::string& prefix,
    const std::string& secret,
    const Options& opts) :
  shutdown(false),
  backend(backend),
  name(name),
  hoid(hoid),
  prefix(prefix),
  striper(this, secret),
  options(opts)
{
  assert(!name.empty());
  assert(!hoid.empty());
  assert(!prefix.empty());

  for (int i = 0; i < options.finisher_threads; i++) {
    finishers_.push_back(std::thread(&LogImpl::finisher_entry_, this));
  }
}

LogImpl::~LogImpl()
{
  {
    std::lock_guard<std::mutex> l(lock);
    shutdown = true;
  }

  finishers_cond_.notify_all();
  for (auto& finisher : finishers_) {
    finisher.join();
  }

  striper.shutdown();
}

int TailOp::run()
{
  while (true) {
    const auto view = log_->striper.view();
    if (view->seq) {
      position_ = view->seq->check_tail(increment_);
      return 0;
    } else {
      int ret = log_->striper.propose_sequencer();
      if (ret) {
        return ret;
      }
      continue;
    }
  }
}

int LogImpl::tailAsync(bool increment, std::function<void(int, uint64_t)> cb)
{
  auto op = std::unique_ptr<LogOp>(new TailOp(this, increment, cb));
  queue_op(std::move(op));
  return 0;
}

int LogImpl::CheckTail(uint64_t *position_out)
{
  struct {
    int ret;
    bool done = false;
    uint64_t position;
    std::mutex lock;
    std::condition_variable cond;
  } ctx;

  int ret = tailAsync([&](int ret, uint64_t position) {
    {
      std::lock_guard<std::mutex> lk(ctx.lock);
      ctx.ret = ret;
      ctx.done = true;
      if (!ctx.ret) {
        ctx.position = position;
      }
    }
    ctx.cond.notify_one();
  });

  if (ret) {
    return ret;
  }

  std::unique_lock<std::mutex> lk(ctx.lock);
  ctx.cond.wait(lk, [&] { return ctx.done; });

  if (!ctx.ret) {
    *position_out = ctx.position;
  }

  return ctx.ret;
}

int ReadOp::run()
{
  while (true) {
    const auto view = log_->striper.view();
    const auto oid = view->object_map.map(position_);
    if (!oid) {
      int ret = log_->striper.try_expand_view(position_);
      if (ret) {
        return ret;
      }
      continue;
    }

    int ret = log_->backend->Read(*oid, view->epoch(), position_, &data_);

    if (ret == -ESPIPE) {
      log_->striper.update_current_view(view->epoch());
      continue;
    }

    if (ret == -ERANGE) {
      return -ENOENT;
    }

    // the position is mapped, but the target object doesn't exist / hasn't been
    // initialized. in this case we _could_ choose to not initialize it and
    // report that the position hasn't been written. initializing here means we
    // can avoid explaining how the behavior is correct, and unifies handling
    // with the other operations which will make future restructing of the async
    // handling easier. in the end, this is unlikely to be an optimization that
    // matters at all since newly created stripes are initialized in the
    // background (future work).
    if (ret == -ENOENT) {
      int ret = log_->backend->Seal(*oid, view->epoch());
      if (ret && ret != -ESPIPE) {
        return ret;
      }
      continue;
    }

    return ret;
  }
}

int LogImpl::Read(const uint64_t position, std::string *data_out)
{
  struct {
    int ret;
    bool done = false;
    std::string data;
    std::mutex lock;
    std::condition_variable cond;
  } ctx;

  int ret = readAsync(position, [&](int ret, std::string& data) {
    {
      std::lock_guard<std::mutex> lk(ctx.lock);
      ctx.ret = ret;
      ctx.done = true;
      if (!ctx.ret) {
        ctx.data.assign(std::move(data));
      }
    }
    ctx.cond.notify_one();
  });

  if (ret) {
    return ret;
  }

  std::unique_lock<std::mutex> lk(ctx.lock);
  ctx.cond.wait(lk, [&] { return ctx.done; });

  if (!ctx.ret) {
    data_out->assign(std::move(ctx.data));
  }

  return ctx.ret;
}

int LogImpl::readAsync(uint64_t position,
    std::function<void(int, std::string&)> cb)
{
  auto op = std::unique_ptr<LogOp>(new ReadOp(this, position, cb));
  queue_op(std::move(op));
  return 0;
}

int AppendOp::run()
{
  while (true) {
    const auto view = log_->striper.view();

    if (view->seq) {
      if (!position_epoch_ || (*position_epoch_ != view->seq->epoch())) {
        position_ = view->seq->check_tail(true);
        position_epoch_ = view->seq->epoch();
      }
      assert(position_epoch_);
      assert(*position_epoch_ > 0);
      assert(*position_epoch_ == view->seq->epoch());
    } else {
      int ret = log_->striper.propose_sequencer();
      if (ret) {
        return ret;
      }
      continue;
    }

    const auto oid = view->object_map.map(position_);
    if (!oid) {
      int ret = log_->striper.try_expand_view(position_);
      if (ret) {
        return ret;
      }
      continue;
    }

    while (true) {
      int ret = log_->backend->Write(*oid, data_, view->epoch(), position_);
      if (!ret) {
        return ret;
      } else if (ret == -ENOENT) {
        // this can happen if a new stripe has been created but not initialized,
        // either because we are racing with initialization, or due to a fault in
        // the process performing the initialization.
        int ret = log_->backend->Seal(*oid, view->epoch());
        if (!ret) {
          // try the append again. the view and the position are still
          // consistent, and there is no reason to think they are out-of-date.
          continue;
        } else if (ret != -ESPIPE) {
          return ret;
        }
        assert(ret == -ESPIPE);
        // unlike other backend interfaces, seal will return -ESPIPE if the
        // epoch is less than _or equal_ to the stored epoch. if the write
        // returned -ENOENT at epoch 100 because it was racing with
        // initialization (also at epoch 100), then seal at epoch 100 will
        // return -ESPIPE. the point is that when -ESPIPE is returned from seal
        // we shouldn't refresh the striper and wait on a newer epoch. if there
        // actually is a newer view, then that will be caught by the write
        // interface. XXX: this would be a fantastic scenario to test for in a
        // model, by incorrectly refreshing here causing a deadlock, or perhaps
        // changing the epoch <= test in the backend.
        break;
      } else if (ret == -ESPIPE) {
        log_->striper.update_current_view(view->epoch());
        break;
      } else if (ret == -EROFS) {
        position_epoch_.reset(); // make sure to get a new position
        break;
      } else {
        return ret;
      }
    }
  }
}

int LogImpl::Append(const std::string& data, uint64_t *pposition)
{
  struct {
    int ret;
    bool done = false;
    uint64_t position;
    std::mutex lock;
    std::condition_variable cond;
  } ctx;

  int ret = appendAsync(data, [&](int ret, uint64_t position) {
    {
      std::lock_guard<std::mutex> lk(ctx.lock);
      ctx.ret = ret;
      ctx.done = true;
      if (!ctx.ret) {
        ctx.position = position;
      }
    }
    ctx.cond.notify_one();
  });

  if (ret) {
    return ret;
  }

  std::unique_lock<std::mutex> lk(ctx.lock);
  ctx.cond.wait(lk, [&] { return ctx.done; });

  if (!ctx.ret && pposition) {
    *pposition = ctx.position;
  }

  return ctx.ret;
}

int LogImpl::appendAsync(const std::string& data,
    std::function<void(int, uint64_t)> cb)
{
  auto op = std::unique_ptr<LogOp>(new AppendOp(this, data, cb));
  queue_op(std::move(op));
  return 0;
}

int FillOp::run()
{
  while (true) {
    const auto view = log_->striper.view();
    const auto oid = view->object_map.map(position_);
    if (!oid) {
      int ret = log_->striper.try_expand_view(position_);
      if (ret) {
        return ret;
      }
      continue;
    }

    int ret = log_->backend->Fill(*oid, view->epoch(), position_);

    if (ret == -ESPIPE) {
      log_->striper.update_current_view(view->epoch());
      continue;
    }

    if (ret == -ENOENT) {
      int ret = log_->backend->Seal(*oid, view->epoch());
      if (ret && ret != -ESPIPE) {
        return ret;
      }
      continue;
    }

    return ret;
  }
}

int LogImpl::Fill(const uint64_t position)
{
  struct {
    int ret;
    bool done = false;
    std::mutex lock;
    std::condition_variable cond;
  } ctx;

  int ret = fillAsync(position, [&](int ret) {
    {
      std::lock_guard<std::mutex> lk(ctx.lock);
      ctx.ret = ret;
      ctx.done = true;
    }
    ctx.cond.notify_one();
  });

  if (ret) {
    return ret;
  }

  std::unique_lock<std::mutex> lk(ctx.lock);
  ctx.cond.wait(lk, [&] { return ctx.done; });

  return ctx.ret;
}

int LogImpl::fillAsync(uint64_t position, std::function<void(int)> cb)
{
  auto op = std::unique_ptr<LogOp>(new FillOp(this, position, cb));
  queue_op(std::move(op));
  return 0;
}

int TrimOp::run()
{
  while (true) {
    const auto view = log_->striper.view();
    const auto oid = view->object_map.map(position_);
    if (!oid) {
      int ret = log_->striper.try_expand_view(position_);
      if (ret) {
        return ret;
      }
      continue;
    }

    int ret = log_->backend->Trim(*oid, view->epoch(), position_);

    if (ret == -ESPIPE) {
      log_->striper.update_current_view(view->epoch());
      continue;
    }

    if (ret == -ENOENT) {
      int ret = log_->backend->Seal(*oid, view->epoch());
      if (ret && ret != -ESPIPE) {
        return ret;
      }
      continue;
    }

    return ret;
  }
}

int LogImpl::Trim(const uint64_t position)
{
  struct {
    int ret;
    bool done = false;
    std::mutex lock;
    std::condition_variable cond;
  } ctx;

  int ret = trimAsync(position, [&](int ret) {
    {
      std::lock_guard<std::mutex> lk(ctx.lock);
      ctx.ret = ret;
      ctx.done = true;
    }
    ctx.cond.notify_one();
  });

  if (ret) {
    return ret;
  }

  std::unique_lock<std::mutex> lk(ctx.lock);
  ctx.cond.wait(lk, [&] { return ctx.done; });

  return ctx.ret;
}

int LogImpl::trimAsync(uint64_t position, std::function<void(int)> cb)
{
  auto op = std::unique_ptr<LogOp>(new TrimOp(this, position, cb));
  queue_op(std::move(op));
  return 0;
}

void LogImpl::queue_op(std::unique_ptr<LogOp> op)
{
  std::lock_guard<std::mutex> lk(lock);
  pending_ops_.emplace_back(std::move(op));
  finishers_cond_.notify_all();
}

void LogImpl::finisher_entry_()
{
  while (true) {
    bool do_shutdown = false;
    std::unique_ptr<LogOp> op;
    {
      std::unique_lock<std::mutex> lk(lock);
      finishers_cond_.wait(lk, [&] {
        return !pending_ops_.empty() || shutdown;
      });

      if (shutdown) {
        if (pending_ops_.empty()) {
          break;
        }
        do_shutdown = true;
      }

      assert(!pending_ops_.empty());
      op = std::move(pending_ops_.front());
      pending_ops_.pop_front();
    }

    if (do_shutdown) {
      op->callback(-ESHUTDOWN);
    } else {
      int ret = op->run();
      op->callback(ret);
    }
  }
}

}
<commit_msg>log: add note about reusing seq pos<commit_after>#include "log_impl.h"

#include <cerrno>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <sstream>
#include <string>
#include <vector>
#include <boost/asio/ip/host_name.hpp>
#include <dlfcn.h>
#include <stdlib.h>

#include "proto/zlog.pb.h"
#include "include/zlog/log.h"
#include "include/zlog/backend.h"
#include "include/zlog/cache.h"

#include "striper.h"

namespace zlog {

LogImpl::LogImpl(std::shared_ptr<Backend> backend,
    const std::string& name,
    const std::string& hoid,
    const std::string& prefix,
    const std::string& secret,
    const Options& opts) :
  shutdown(false),
  backend(backend),
  name(name),
  hoid(hoid),
  prefix(prefix),
  striper(this, secret),
  options(opts)
{
  assert(!name.empty());
  assert(!hoid.empty());
  assert(!prefix.empty());

  for (int i = 0; i < options.finisher_threads; i++) {
    finishers_.push_back(std::thread(&LogImpl::finisher_entry_, this));
  }
}

LogImpl::~LogImpl()
{
  {
    std::lock_guard<std::mutex> l(lock);
    shutdown = true;
  }

  finishers_cond_.notify_all();
  for (auto& finisher : finishers_) {
    finisher.join();
  }

  striper.shutdown();
}

int TailOp::run()
{
  while (true) {
    const auto view = log_->striper.view();
    if (view->seq) {
      position_ = view->seq->check_tail(increment_);
      return 0;
    } else {
      int ret = log_->striper.propose_sequencer();
      if (ret) {
        return ret;
      }
      continue;
    }
  }
}

int LogImpl::tailAsync(bool increment, std::function<void(int, uint64_t)> cb)
{
  auto op = std::unique_ptr<LogOp>(new TailOp(this, increment, cb));
  queue_op(std::move(op));
  return 0;
}

int LogImpl::CheckTail(uint64_t *position_out)
{
  struct {
    int ret;
    bool done = false;
    uint64_t position;
    std::mutex lock;
    std::condition_variable cond;
  } ctx;

  int ret = tailAsync([&](int ret, uint64_t position) {
    {
      std::lock_guard<std::mutex> lk(ctx.lock);
      ctx.ret = ret;
      ctx.done = true;
      if (!ctx.ret) {
        ctx.position = position;
      }
    }
    ctx.cond.notify_one();
  });

  if (ret) {
    return ret;
  }

  std::unique_lock<std::mutex> lk(ctx.lock);
  ctx.cond.wait(lk, [&] { return ctx.done; });

  if (!ctx.ret) {
    *position_out = ctx.position;
  }

  return ctx.ret;
}

int ReadOp::run()
{
  while (true) {
    const auto view = log_->striper.view();
    const auto oid = view->object_map.map(position_);
    if (!oid) {
      int ret = log_->striper.try_expand_view(position_);
      if (ret) {
        return ret;
      }
      continue;
    }

    int ret = log_->backend->Read(*oid, view->epoch(), position_, &data_);

    if (ret == -ESPIPE) {
      log_->striper.update_current_view(view->epoch());
      continue;
    }

    if (ret == -ERANGE) {
      return -ENOENT;
    }

    // the position is mapped, but the target object doesn't exist / hasn't been
    // initialized. in this case we _could_ choose to not initialize it and
    // report that the position hasn't been written. initializing here means we
    // can avoid explaining how the behavior is correct, and unifies handling
    // with the other operations which will make future restructing of the async
    // handling easier. in the end, this is unlikely to be an optimization that
    // matters at all since newly created stripes are initialized in the
    // background (future work).
    if (ret == -ENOENT) {
      int ret = log_->backend->Seal(*oid, view->epoch());
      if (ret && ret != -ESPIPE) {
        return ret;
      }
      continue;
    }

    return ret;
  }
}

int LogImpl::Read(const uint64_t position, std::string *data_out)
{
  struct {
    int ret;
    bool done = false;
    std::string data;
    std::mutex lock;
    std::condition_variable cond;
  } ctx;

  int ret = readAsync(position, [&](int ret, std::string& data) {
    {
      std::lock_guard<std::mutex> lk(ctx.lock);
      ctx.ret = ret;
      ctx.done = true;
      if (!ctx.ret) {
        ctx.data.assign(std::move(data));
      }
    }
    ctx.cond.notify_one();
  });

  if (ret) {
    return ret;
  }

  std::unique_lock<std::mutex> lk(ctx.lock);
  ctx.cond.wait(lk, [&] { return ctx.done; });

  if (!ctx.ret) {
    data_out->assign(std::move(ctx.data));
  }

  return ctx.ret;
}

int LogImpl::readAsync(uint64_t position,
    std::function<void(int, std::string&)> cb)
{
  auto op = std::unique_ptr<LogOp>(new ReadOp(this, position, cb));
  queue_op(std::move(op));
  return 0;
}

int AppendOp::run()
{
  while (true) {
    const auto view = log_->striper.view();

    if (view->seq) {
      // avoid obtaining a new append position when the view has been updated
      // (e.g. because the mapping was extended), but the sequencer did not
      // change. this is generally a minor optimization. but for completeness,
      // it also handles the edge case in which stripes are configured to hold
      // exactly one log entry. in this case a loop will be created by which the
      // new position doesn't map, the map is extended, and then a new unmapped
      // position is obtained.
      if (!position_epoch_ || (*position_epoch_ != view->seq->epoch())) {
        position_ = view->seq->check_tail(true);
        position_epoch_ = view->seq->epoch();
      }
      assert(position_epoch_);
      assert(*position_epoch_ > 0);
      assert(*position_epoch_ == view->seq->epoch());
    } else {
      int ret = log_->striper.propose_sequencer();
      if (ret) {
        return ret;
      }
      continue;
    }

    const auto oid = view->object_map.map(position_);
    if (!oid) {
      int ret = log_->striper.try_expand_view(position_);
      if (ret) {
        return ret;
      }
      continue;
    }

    while (true) {
      int ret = log_->backend->Write(*oid, data_, view->epoch(), position_);
      if (!ret) {
        return ret;
      } else if (ret == -ENOENT) {
        // this can happen if a new stripe has been created but not initialized,
        // either because we are racing with initialization, or due to a fault in
        // the process performing the initialization.
        int ret = log_->backend->Seal(*oid, view->epoch());
        if (!ret) {
          // try the append again. the view and the position are still
          // consistent, and there is no reason to think they are out-of-date.
          continue;
        } else if (ret != -ESPIPE) {
          return ret;
        }
        assert(ret == -ESPIPE);
        // unlike other backend interfaces, seal will return -ESPIPE if the
        // epoch is less than _or equal_ to the stored epoch. if the write
        // returned -ENOENT at epoch 100 because it was racing with
        // initialization (also at epoch 100), then seal at epoch 100 will
        // return -ESPIPE. the point is that when -ESPIPE is returned from seal
        // we shouldn't refresh the striper and wait on a newer epoch. if there
        // actually is a newer view, then that will be caught by the write
        // interface. XXX: this would be a fantastic scenario to test for in a
        // model, by incorrectly refreshing here causing a deadlock, or perhaps
        // changing the epoch <= test in the backend.
        break;
      } else if (ret == -ESPIPE) {
        log_->striper.update_current_view(view->epoch());
        break;
      } else if (ret == -EROFS) {
        position_epoch_.reset(); // make sure to get a new position
        break;
      } else {
        return ret;
      }
    }
  }
}

int LogImpl::Append(const std::string& data, uint64_t *pposition)
{
  struct {
    int ret;
    bool done = false;
    uint64_t position;
    std::mutex lock;
    std::condition_variable cond;
  } ctx;

  int ret = appendAsync(data, [&](int ret, uint64_t position) {
    {
      std::lock_guard<std::mutex> lk(ctx.lock);
      ctx.ret = ret;
      ctx.done = true;
      if (!ctx.ret) {
        ctx.position = position;
      }
    }
    ctx.cond.notify_one();
  });

  if (ret) {
    return ret;
  }

  std::unique_lock<std::mutex> lk(ctx.lock);
  ctx.cond.wait(lk, [&] { return ctx.done; });

  if (!ctx.ret && pposition) {
    *pposition = ctx.position;
  }

  return ctx.ret;
}

int LogImpl::appendAsync(const std::string& data,
    std::function<void(int, uint64_t)> cb)
{
  auto op = std::unique_ptr<LogOp>(new AppendOp(this, data, cb));
  queue_op(std::move(op));
  return 0;
}

int FillOp::run()
{
  while (true) {
    const auto view = log_->striper.view();
    const auto oid = view->object_map.map(position_);
    if (!oid) {
      int ret = log_->striper.try_expand_view(position_);
      if (ret) {
        return ret;
      }
      continue;
    }

    int ret = log_->backend->Fill(*oid, view->epoch(), position_);

    if (ret == -ESPIPE) {
      log_->striper.update_current_view(view->epoch());
      continue;
    }

    if (ret == -ENOENT) {
      int ret = log_->backend->Seal(*oid, view->epoch());
      if (ret && ret != -ESPIPE) {
        return ret;
      }
      continue;
    }

    return ret;
  }
}

int LogImpl::Fill(const uint64_t position)
{
  struct {
    int ret;
    bool done = false;
    std::mutex lock;
    std::condition_variable cond;
  } ctx;

  int ret = fillAsync(position, [&](int ret) {
    {
      std::lock_guard<std::mutex> lk(ctx.lock);
      ctx.ret = ret;
      ctx.done = true;
    }
    ctx.cond.notify_one();
  });

  if (ret) {
    return ret;
  }

  std::unique_lock<std::mutex> lk(ctx.lock);
  ctx.cond.wait(lk, [&] { return ctx.done; });

  return ctx.ret;
}

int LogImpl::fillAsync(uint64_t position, std::function<void(int)> cb)
{
  auto op = std::unique_ptr<LogOp>(new FillOp(this, position, cb));
  queue_op(std::move(op));
  return 0;
}

int TrimOp::run()
{
  while (true) {
    const auto view = log_->striper.view();
    const auto oid = view->object_map.map(position_);
    if (!oid) {
      int ret = log_->striper.try_expand_view(position_);
      if (ret) {
        return ret;
      }
      continue;
    }

    int ret = log_->backend->Trim(*oid, view->epoch(), position_);

    if (ret == -ESPIPE) {
      log_->striper.update_current_view(view->epoch());
      continue;
    }

    if (ret == -ENOENT) {
      int ret = log_->backend->Seal(*oid, view->epoch());
      if (ret && ret != -ESPIPE) {
        return ret;
      }
      continue;
    }

    return ret;
  }
}

int LogImpl::Trim(const uint64_t position)
{
  struct {
    int ret;
    bool done = false;
    std::mutex lock;
    std::condition_variable cond;
  } ctx;

  int ret = trimAsync(position, [&](int ret) {
    {
      std::lock_guard<std::mutex> lk(ctx.lock);
      ctx.ret = ret;
      ctx.done = true;
    }
    ctx.cond.notify_one();
  });

  if (ret) {
    return ret;
  }

  std::unique_lock<std::mutex> lk(ctx.lock);
  ctx.cond.wait(lk, [&] { return ctx.done; });

  return ctx.ret;
}

int LogImpl::trimAsync(uint64_t position, std::function<void(int)> cb)
{
  auto op = std::unique_ptr<LogOp>(new TrimOp(this, position, cb));
  queue_op(std::move(op));
  return 0;
}

void LogImpl::queue_op(std::unique_ptr<LogOp> op)
{
  std::lock_guard<std::mutex> lk(lock);
  pending_ops_.emplace_back(std::move(op));
  finishers_cond_.notify_all();
}

void LogImpl::finisher_entry_()
{
  while (true) {
    bool do_shutdown = false;
    std::unique_ptr<LogOp> op;
    {
      std::unique_lock<std::mutex> lk(lock);
      finishers_cond_.wait(lk, [&] {
        return !pending_ops_.empty() || shutdown;
      });

      if (shutdown) {
        if (pending_ops_.empty()) {
          break;
        }
        do_shutdown = true;
      }

      assert(!pending_ops_.empty());
      op = std::move(pending_ops_.front());
      pending_ops_.pop_front();
    }

    if (do_shutdown) {
      op->callback(-ESHUTDOWN);
    } else {
      int ret = op->run();
      op->callback(ret);
    }
  }
}

}
<|endoftext|>


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

#include "deferredShading.h"
#include "console/consoleInternal.h"
#include "graphics/shaders.h"
#include "graphics/dgl.h"
#include "scene/scene.h"
#include "rendering/renderCamera.h"

#include <bgfx/bgfx.h>
#include <bx/fpumath.h>
#include <bx/timer.h>

namespace Rendering
{
   DeferredShading::DeferredShading(RenderCamera* camera)
   {
      mCamera        = camera;
      mInitialized   = false;

      mGBufferTextures[0].idx = bgfx::invalidHandle;
      mGBufferTextures[1].idx = bgfx::invalidHandle;
      mGBufferTextures[2].idx = bgfx::invalidHandle;
      mGBufferTextures[3].idx = bgfx::invalidHandle;
      mGBuffer.idx            = bgfx::invalidHandle;
      mDecalBuffer.idx        = bgfx::invalidHandle;
      mLightBuffer.idx        = bgfx::invalidHandle;
      mAmbientBuffer.idx      = bgfx::invalidHandle;
      mFinalBuffer.idx        = bgfx::invalidHandle;

      mCombineShader          = NULL;
      mDefaultShader          = NULL;
      mDeferredGeometryView   = NULL;
      mDeferredDecalView      = NULL;
      mDeferredLightView      = NULL;
      mDeferredAmbientView    = NULL;
      mDeferredFinalView      = NULL;
   }

   DeferredShading::~DeferredShading()
   {
      destroy();
   }

   void DeferredShading::init()
   {
      destroy();

      mCombineShader = Graphics::getDefaultShader("rendering/combine_vs.tsh", "rendering/combine_fs.tsh");
      mDefaultShader = Graphics::getDefaultShader("rendering/default_deferred_vs.tsh", "rendering/default_deferred_fs.tsh");

      // Get Views
      mDeferredGeometryView   = Graphics::getView("DeferredGeometry", 1000);
      mDeferredDecalView      = Graphics::getView("DeferredDecal", 1250);
      mDeferredLightView      = Graphics::getView("DeferredLight", 1500);
      mDeferredAmbientView    = Graphics::getView("DeferredAmbient", 1600);
      mDeferredFinalView      = Graphics::getView("DeferredFinal", 1750);

      const uint32_t samplerFlags = 0
         | BGFX_TEXTURE_RT
         | BGFX_TEXTURE_MIN_POINT
         | BGFX_TEXTURE_MAG_POINT
         | BGFX_TEXTURE_MIP_POINT
         | BGFX_TEXTURE_U_CLAMP
         | BGFX_TEXTURE_V_CLAMP
         ;

      // G-Buffer
      mGBufferTextures[0]  = bgfx::createTexture2D(bgfx::BackbufferRatio::Equal, 1, bgfx::TextureFormat::BGRA8, samplerFlags);
      mGBufferTextures[1]  = Rendering::getNormalTexture();
      mGBufferTextures[2]  = Rendering::getMatInfoTexture();
      mGBufferTextures[3]  = Rendering::getDepthTexture();
      mGBuffer             = bgfx::createFrameBuffer(BX_COUNTOF(mGBufferTextures), mGBufferTextures, false);

      // Decal Buffer
      bgfx::TextureHandle decalBufferTextures[] =
      {
         mGBufferTextures[0],
         Rendering::getDepthTexture()
      };
      mDecalBuffer = bgfx::createFrameBuffer(BX_COUNTOF(decalBufferTextures), decalBufferTextures);

      // Light Buffer
      mLightBuffer = bgfx::createFrameBuffer(bgfx::BackbufferRatio::Equal, bgfx::TextureFormat::RGBA16, samplerFlags);

      // Ambient Buffer
      mAmbientBuffer = bgfx::createFrameBuffer(bgfx::BackbufferRatio::Equal, bgfx::TextureFormat::BGRA8, samplerFlags);

      // Final Buffer
      bgfx::TextureHandle finalBufferTextures[] =
      {
         Rendering::getColorTexture(),
         bgfx::createTexture2D(bgfx::BackbufferRatio::Equal, 1, bgfx::TextureFormat::D16, BGFX_TEXTURE_RT_BUFFER_ONLY)
      };
      mFinalBuffer = bgfx::createFrameBuffer(BX_COUNTOF(finalBufferTextures), finalBufferTextures);

      mInitialized = true;
   }

   void DeferredShading::destroy()
   {
      // Destroy Frame Buffers
      if ( bgfx::isValid(mGBuffer) )
         bgfx::destroyFrameBuffer(mGBuffer);
      if ( bgfx::isValid(mLightBuffer) )
         bgfx::destroyFrameBuffer(mLightBuffer);
      if (bgfx::isValid(mAmbientBuffer))
         bgfx::destroyFrameBuffer(mAmbientBuffer);

      // Destroy G-Buffer Color/Lighting Textures
      if ( bgfx::isValid(mGBufferTextures[0]) )
         bgfx::destroyTexture(mGBufferTextures[0]);
   }

   void DeferredShading::preRender()
   {
      if (!mInitialized)
         init();

      // G-Buffer
      bgfx::setPaletteColor(0, UINT32_C(0x00000000));

      // Geometry Buffer
      bgfx::setViewClear(mDeferredGeometryView->id
         , BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH
         , 1.0f
         , 0
         , 0
         , 0
         , 0
         );
      bgfx::setViewRect(mDeferredGeometryView->id, 0, 0, canvasWidth, canvasHeight);
      bgfx::setViewFrameBuffer(mDeferredGeometryView->id, mGBuffer);
      bgfx::setViewTransform(mDeferredGeometryView->id, mCamera->viewMatrix, mCamera->projectionMatrix);
      bgfx::touch(mDeferredGeometryView->id);

      // Decal Buffer
      bgfx::setViewRect(mDeferredDecalView->id, 0, 0, canvasWidth, canvasHeight);
      bgfx::setViewFrameBuffer(mDeferredDecalView->id, mDecalBuffer);
      bgfx::setViewTransform(mDeferredDecalView->id, mCamera->viewMatrix, mCamera->projectionMatrix);
      bgfx::touch(mDeferredDecalView->id);

      // Light Buffer
      bgfx::setViewClear(mDeferredLightView->id
         , BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH
         , 1.0f
         , 0
         , 0
         );
      bgfx::setViewRect(mDeferredLightView->id, 0, 0, canvasWidth, canvasHeight);
      bgfx::setViewFrameBuffer(mDeferredLightView->id, mLightBuffer);
      bgfx::setViewTransform(mDeferredLightView->id, mCamera->viewMatrix, mCamera->projectionMatrix);
      bgfx::touch(mDeferredLightView->id);

      // Ambient Buffer
      bgfx::setViewClear(mDeferredAmbientView->id
         , BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH
         , 1.0f
         , 0
         , 0
         );
      bgfx::setViewRect(mDeferredAmbientView->id, 0, 0, canvasWidth, canvasHeight);
      bgfx::setViewFrameBuffer(mDeferredAmbientView->id, mAmbientBuffer);
      bgfx::setViewTransform(mDeferredAmbientView->id, mCamera->viewMatrix, mCamera->projectionMatrix);
      bgfx::touch(mDeferredAmbientView->id);

      // Final Buffer
      bgfx::setViewFrameBuffer(mDeferredFinalView->id, mFinalBuffer);
      bgfx::setViewRect(mDeferredFinalView->id, 0, 0, canvasWidth, canvasHeight);
      bgfx::setViewTransform(mDeferredFinalView->id, mCamera->viewMatrix, mCamera->projectionMatrix);

      // Temp hack.
      bgfx::blit(mDeferredDecalView->id, Rendering::getDepthTextureRead(), 0, 0, Rendering::getDepthTexture());
   }

   void DeferredShading::render()
   {
      // Render everything in the render list.
      Rendering::RenderData* item = Rendering::getRenderDataList();
      for (U32 n = 0; n < Rendering::getRenderDataCount(); ++n, ++item)
      {
         if (item->flags & RenderData::Deleted || item->flags & RenderData::Hidden)
            continue;

         // Transform Table.
         bgfx::setTransform(item->transformTable, item->transformCount);

         // Instancing Data
         if (item->instances && item->instances->size() > 0)
         {
            U16 stride = sizeof(Rendering::InstanceData);
            const bgfx::InstanceDataBuffer* idb = bgfx::allocInstanceDataBuffer(item->instances->size(), stride);

            for (S32 i = 0; i < item->instances->size(); ++i)
               dMemcpy(&idb->data[i * stride], &item->instances->at(i), stride);

            bgfx::setInstanceDataBuffer(idb);
         }

         // Vertex/Index Buffers (Optionally Dynamic)
         if (item->flags & RenderData::IsDynamic)
         {
            bgfx::setVertexBuffer(item->dynamicVertexBuffer);
            bgfx::setIndexBuffer(item->dynamicIndexBuffer);
         }
         else {
            bgfx::setVertexBuffer(item->vertexBuffer);
            bgfx::setIndexBuffer(item->indexBuffer);
         }

         // Setup Textures
         if (item->textures)
         {
            for (S32 i = 0; i < item->textures->size(); ++i)
            {
               if (item->textures->at(i).isDepthTexture)
                  bgfx::setTexture(i, item->textures->at(i).uniform, Rendering::getDepthTexture());
               else if (item->textures->at(i).isNormalTexture)
                  bgfx::setTexture(i, item->textures->at(i).uniform, Rendering::getNormalTexture());
               else
                  bgfx::setTexture(i, item->textures->at(i).uniform, item->textures->at(i).handle);
            }
         }

         // Setup Uniforms
         if (!item->uniforms.isEmpty())
         {
            for (S32 i = 0; i < item->uniforms.uniforms->size(); ++i)
            {
               UniformData* uniform = &item->uniforms.uniforms->at(i);
               bgfx::setUniform(uniform->uniform, uniform->_dataPtr, uniform->count);
            }
         }

         // Set render states.
         bgfx::setState(item->state, item->stateRGBA);

         // Submit primitive
         bgfx::submit(item->view->id, item->shader);
      }
   }

   void DeferredShading::postRender()
   {
      // This projection matrix is used because its a full screen quad.
      F32 proj[16];
      bx::mtxOrtho(proj, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 100.0f);
      bgfx::setViewTransform(mDeferredFinalView->id, NULL, proj);
      bgfx::setViewRect(mDeferredFinalView->id, 0, 0, canvasWidth, canvasHeight);

      // Combine Color + Direct Light
      bgfx::setTexture(0, Graphics::Shader::getTextureUniform(0), mGBuffer, 0);                    // Albedo
      bgfx::setTexture(1, Graphics::Shader::getTextureUniform(1), Rendering::getNormalTexture());  // Normals
      bgfx::setTexture(2, Graphics::Shader::getTextureUniform(2), mGBuffer, 2);                    // Material Info
      bgfx::setTexture(3, Graphics::Shader::getTextureUniform(3), Rendering::getDepthTexture());   // Depth Buffer
      bgfx::setTexture(4, Graphics::Shader::getTextureUniform(4), mLightBuffer, 0);                // Light Buffer
      bgfx::setTexture(5, Graphics::Shader::getTextureUniform(5), mAmbientBuffer, 0);              // Ambient Buffer

      bgfx::setState(0
         | BGFX_STATE_RGB_WRITE
         | BGFX_STATE_ALPHA_WRITE
         );

      fullScreenQuad((F32)canvasWidth, (F32)canvasHeight);

      bgfx::submit(mDeferredFinalView->id, mCombineShader->mProgram);
   }

   void DeferredShading::resize()
   {

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

#include "deferredShading.h"
#include "console/consoleInternal.h"
#include "graphics/shaders.h"
#include "graphics/dgl.h"
#include "scene/scene.h"
#include "rendering/renderCamera.h"

#include <bgfx/bgfx.h>
#include <bx/fpumath.h>
#include <bx/timer.h>

namespace Rendering
{
   DeferredShading::DeferredShading(RenderCamera* camera)
   {
      mCamera        = camera;
      mInitialized   = false;

      mGBufferTextures[0].idx = bgfx::invalidHandle;
      mGBufferTextures[1].idx = bgfx::invalidHandle;
      mGBufferTextures[2].idx = bgfx::invalidHandle;
      mGBufferTextures[3].idx = bgfx::invalidHandle;
      mGBuffer.idx            = bgfx::invalidHandle;
      mDecalBuffer.idx        = bgfx::invalidHandle;
      mLightBuffer.idx        = bgfx::invalidHandle;
      mAmbientBuffer.idx      = bgfx::invalidHandle;
      mFinalBuffer.idx        = bgfx::invalidHandle;

      mCombineShader          = NULL;
      mDefaultShader          = NULL;
      mDeferredGeometryView   = NULL;
      mDeferredDecalView      = NULL;
      mDeferredLightView      = NULL;
      mDeferredAmbientView    = NULL;
      mDeferredFinalView      = NULL;
   }

   DeferredShading::~DeferredShading()
   {
      destroy();
   }

   void DeferredShading::init()
   {
      destroy();

      mCombineShader = Graphics::getDefaultShader("rendering/combine_vs.tsh", "rendering/combine_fs.tsh");
      mDefaultShader = Graphics::getDefaultShader("rendering/default_deferred_vs.tsh", "rendering/default_deferred_fs.tsh");

      // Get Views
      mDeferredGeometryView   = Graphics::getView("DeferredGeometry", 1000);
      mDeferredDecalView      = Graphics::getView("DeferredDecal", 1250);
      mDeferredLightView      = Graphics::getView("DeferredLight", 1500);
      mDeferredAmbientView    = Graphics::getView("DeferredAmbient", 1600);
      mDeferredFinalView      = Graphics::getView("DeferredFinal", 1750);

      const uint32_t samplerFlags = 0
         | BGFX_TEXTURE_RT
         | BGFX_TEXTURE_MIN_POINT
         | BGFX_TEXTURE_MAG_POINT
         | BGFX_TEXTURE_MIP_POINT
         | BGFX_TEXTURE_U_CLAMP
         | BGFX_TEXTURE_V_CLAMP
         ;

      // G-Buffer
      mGBufferTextures[0]  = bgfx::createTexture2D(bgfx::BackbufferRatio::Equal, 1, bgfx::TextureFormat::BGRA8, samplerFlags);
      mGBufferTextures[1]  = Rendering::getNormalTexture();
      mGBufferTextures[2]  = Rendering::getMatInfoTexture();
      mGBufferTextures[3]  = Rendering::getDepthTexture();
      mGBuffer             = bgfx::createFrameBuffer(BX_COUNTOF(mGBufferTextures), mGBufferTextures, false);

      // Decal Buffer
      bgfx::TextureHandle decalBufferTextures[] =
      {
         mGBufferTextures[0],
         Rendering::getDepthTexture()
      };
      mDecalBuffer = bgfx::createFrameBuffer(BX_COUNTOF(decalBufferTextures), decalBufferTextures);

      // Light Buffer
      mLightBuffer = bgfx::createFrameBuffer(bgfx::BackbufferRatio::Equal, bgfx::TextureFormat::RGBA16, samplerFlags);

      // Ambient Buffer
      mAmbientBuffer = bgfx::createFrameBuffer(bgfx::BackbufferRatio::Equal, bgfx::TextureFormat::BGRA8, samplerFlags);

      // Final Buffer
      bgfx::TextureHandle finalBufferTextures[] =
      {
         Rendering::getColorTexture(),
         bgfx::createTexture2D(bgfx::BackbufferRatio::Equal, 1, bgfx::TextureFormat::D16, BGFX_TEXTURE_RT_WRITE_ONLY)
      };
      mFinalBuffer = bgfx::createFrameBuffer(BX_COUNTOF(finalBufferTextures), finalBufferTextures);

      mInitialized = true;
   }

   void DeferredShading::destroy()
   {
      // Destroy Frame Buffers
      if ( bgfx::isValid(mGBuffer) )
         bgfx::destroyFrameBuffer(mGBuffer);
      if ( bgfx::isValid(mLightBuffer) )
         bgfx::destroyFrameBuffer(mLightBuffer);
      if (bgfx::isValid(mAmbientBuffer))
         bgfx::destroyFrameBuffer(mAmbientBuffer);

      // Destroy G-Buffer Color/Lighting Textures
      if ( bgfx::isValid(mGBufferTextures[0]) )
         bgfx::destroyTexture(mGBufferTextures[0]);
   }

   void DeferredShading::preRender()
   {
      if (!mInitialized)
         init();

      // G-Buffer
      bgfx::setPaletteColor(0, UINT32_C(0x00000000));

      // Geometry Buffer
      bgfx::setViewClear(mDeferredGeometryView->id
         , BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH
         , 1.0f
         , 0
         , 0
         , 0
         , 0
         );
      bgfx::setViewRect(mDeferredGeometryView->id, 0, 0, canvasWidth, canvasHeight);
      bgfx::setViewFrameBuffer(mDeferredGeometryView->id, mGBuffer);
      bgfx::setViewTransform(mDeferredGeometryView->id, mCamera->viewMatrix, mCamera->projectionMatrix);
      bgfx::touch(mDeferredGeometryView->id);

      // Decal Buffer
      bgfx::setViewRect(mDeferredDecalView->id, 0, 0, canvasWidth, canvasHeight);
      bgfx::setViewFrameBuffer(mDeferredDecalView->id, mDecalBuffer);
      bgfx::setViewTransform(mDeferredDecalView->id, mCamera->viewMatrix, mCamera->projectionMatrix);
      bgfx::touch(mDeferredDecalView->id);

      // Light Buffer
      bgfx::setViewClear(mDeferredLightView->id
         , BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH
         , 1.0f
         , 0
         , 0
         );
      bgfx::setViewRect(mDeferredLightView->id, 0, 0, canvasWidth, canvasHeight);
      bgfx::setViewFrameBuffer(mDeferredLightView->id, mLightBuffer);
      bgfx::setViewTransform(mDeferredLightView->id, mCamera->viewMatrix, mCamera->projectionMatrix);
      bgfx::touch(mDeferredLightView->id);

      // Ambient Buffer
      bgfx::setViewClear(mDeferredAmbientView->id
         , BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH
         , 1.0f
         , 0
         , 0
         );
      bgfx::setViewRect(mDeferredAmbientView->id, 0, 0, canvasWidth, canvasHeight);
      bgfx::setViewFrameBuffer(mDeferredAmbientView->id, mAmbientBuffer);
      bgfx::setViewTransform(mDeferredAmbientView->id, mCamera->viewMatrix, mCamera->projectionMatrix);
      bgfx::touch(mDeferredAmbientView->id);

      // Final Buffer
      bgfx::setViewFrameBuffer(mDeferredFinalView->id, mFinalBuffer);
      bgfx::setViewRect(mDeferredFinalView->id, 0, 0, canvasWidth, canvasHeight);
      bgfx::setViewTransform(mDeferredFinalView->id, mCamera->viewMatrix, mCamera->projectionMatrix);

      // Temp hack.
      bgfx::blit(mDeferredDecalView->id, Rendering::getDepthTextureRead(), 0, 0, Rendering::getDepthTexture());
   }

   void DeferredShading::render()
   {
      // Render everything in the render list.
      Rendering::RenderData* item = Rendering::getRenderDataList();
      for (U32 n = 0; n < Rendering::getRenderDataCount(); ++n, ++item)
      {
         if (item->flags & RenderData::Deleted || item->flags & RenderData::Hidden)
            continue;

         // Transform Table.
         bgfx::setTransform(item->transformTable, item->transformCount);

         // Instancing Data
         if (item->instances && item->instances->size() > 0)
         {
            U16 stride = sizeof(Rendering::InstanceData);
            const bgfx::InstanceDataBuffer* idb = bgfx::allocInstanceDataBuffer(item->instances->size(), stride);

            for (S32 i = 0; i < item->instances->size(); ++i)
               dMemcpy(&idb->data[i * stride], &item->instances->at(i), stride);

            bgfx::setInstanceDataBuffer(idb);
         }

         // Vertex/Index Buffers (Optionally Dynamic)
         if (item->flags & RenderData::IsDynamic)
         {
            bgfx::setVertexBuffer(item->dynamicVertexBuffer);
            bgfx::setIndexBuffer(item->dynamicIndexBuffer);
         }
         else {
            bgfx::setVertexBuffer(item->vertexBuffer);
            bgfx::setIndexBuffer(item->indexBuffer);
         }

         // Setup Textures
         if (item->textures)
         {
            for (S32 i = 0; i < item->textures->size(); ++i)
            {
               if (item->textures->at(i).isDepthTexture)
                  bgfx::setTexture(i, item->textures->at(i).uniform, Rendering::getDepthTexture());
               else if (item->textures->at(i).isNormalTexture)
                  bgfx::setTexture(i, item->textures->at(i).uniform, Rendering::getNormalTexture());
               else
                  bgfx::setTexture(i, item->textures->at(i).uniform, item->textures->at(i).handle);
            }
         }

         // Setup Uniforms
         if (!item->uniforms.isEmpty())
         {
            for (S32 i = 0; i < item->uniforms.uniforms->size(); ++i)
            {
               UniformData* uniform = &item->uniforms.uniforms->at(i);
               bgfx::setUniform(uniform->uniform, uniform->_dataPtr, uniform->count);
            }
         }

         // Set render states.
         bgfx::setState(item->state, item->stateRGBA);

         // Submit primitive
         bgfx::submit(item->view->id, item->shader);
      }
   }

   void DeferredShading::postRender()
   {
      // This projection matrix is used because its a full screen quad.
      F32 proj[16];
      bx::mtxOrtho(proj, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 100.0f);
      bgfx::setViewTransform(mDeferredFinalView->id, NULL, proj);
      bgfx::setViewRect(mDeferredFinalView->id, 0, 0, canvasWidth, canvasHeight);

      // Combine Color + Direct Light
      bgfx::setTexture(0, Graphics::Shader::getTextureUniform(0), mGBuffer, 0);                    // Albedo
      bgfx::setTexture(1, Graphics::Shader::getTextureUniform(1), Rendering::getNormalTexture());  // Normals
      bgfx::setTexture(2, Graphics::Shader::getTextureUniform(2), mGBuffer, 2);                    // Material Info
      bgfx::setTexture(3, Graphics::Shader::getTextureUniform(3), Rendering::getDepthTexture());   // Depth Buffer
      bgfx::setTexture(4, Graphics::Shader::getTextureUniform(4), mLightBuffer, 0);                // Light Buffer
      bgfx::setTexture(5, Graphics::Shader::getTextureUniform(5), mAmbientBuffer, 0);              // Ambient Buffer

      bgfx::setState(0
         | BGFX_STATE_RGB_WRITE
         | BGFX_STATE_ALPHA_WRITE
         );

      fullScreenQuad((F32)canvasWidth, (F32)canvasHeight);

      bgfx::submit(mDeferredFinalView->id, mCombineShader->mProgram);
   }

   void DeferredShading::resize()
   {

   }
}
<|endoftext|>