<commit_before>//=============================================================================================================
/**
* @file     ecddatatreeitem.cpp
* @author   Lorenz Esch <Lorenz.Esch@tu-ilmenau.de>;
*           Matti Hamalainen <msh@nmr.mgh.harvard.edu>
* @version  1.0
* @date     November, 2015
*
* @section  LICENSE
*
* Copyright (C) 2015, Lorenz Esch and Matti Hamalainen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that
* the following conditions are met:
*     * Redistributions of source code must retain the above copyright notice, this list of conditions and the
*       following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
*       the following disclaimer in the documentation and/or other materials provided with the distribution.
*     * Neither the name of MNE-CPP authors nor the names of its contributors may be used
*       to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*
* @brief    EcdDataTreeItem class definition.
*
*/

//*************************************************************************************************************
//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include "ecddatatreeitem.h"
#include "../common/metatreeitem.h"
#include "../../3dhelpers/renderable3Dentity.h"

#include <inverse/dipoleFit/ecd_set.h>

//*************************************************************************************************************
//=============================================================================================================
// Qt INCLUDES
//=============================================================================================================

#include <QList>
#include <QVariant>
#include <QStringList>
#include <QColor>
#include <QVector3D>
#include <QStandardItem>
#include <QStandardItemModel>
#include <Qt3DRender/qshaderprogram.h>
#include <Qt3DExtras/QSphereMesh>
#include <Qt3DExtras/QPhongMaterial>
#include <Qt3DCore/QTransform>
#include <QQuaternion>
#include <Qt3DExtras/QConeMesh>

//*************************************************************************************************************
//=============================================================================================================
// Eigen INCLUDES
//=============================================================================================================

#include <Eigen/Core>

//*************************************************************************************************************
//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace Eigen;
using namespace INVERSELIB;
using namespace DISP3DLIB;

//*************************************************************************************************************
//=============================================================================================================
// DEFINE MEMBER METHODS
//=============================================================================================================

EcdDataTreeItem::EcdDataTreeItem(int iType, const QString &text)
: AbstractTreeItem(iType, text)
, m_bIsInit(false)
, m_pRenderable3DEntity(new Renderable3DEntity())
{
    this->setEditable(false);
    this->setCheckable(true);
    this->setCheckState(Qt::Checked);
    this->setToolTip("Dipole fit data");
}

//*************************************************************************************************************

EcdDataTreeItem::~EcdDataTreeItem()
{
    //Schedule deletion/Decouple of all entities so that the SceneGraph is NOT plotting them anymore.
    for(int i = 0; i < m_lDipoles.size(); ++i) {
        m_lDipoles.at(i)->deleteLater();
    }

    if(!m_pRenderable3DEntity.isNull()) {
        m_pRenderable3DEntity->deleteLater();
    }
}

//*************************************************************************************************************

QVariant EcdDataTreeItem::data(int role) const
{
    return AbstractTreeItem::data(role);
}

//*************************************************************************************************************

void EcdDataTreeItem::setData(const QVariant& value, int role)
{
    AbstractTreeItem::setData(value, role);
}

//*************************************************************************************************************

bool EcdDataTreeItem::init(Qt3DCore::QEntity* parent)
{
    //Create renderable 3D entity
    m_pRenderable3DEntity->setParent(parent);

    //Add meta information as item children
    QList<QStandardItem*> list;
    QVariant data;

    m_bIsInit = true;

    return true;
}

//*************************************************************************************************************

bool EcdDataTreeItem::addData(ECDSet::SPtr pECDSet)
{
    if(!m_bIsInit) {
        qDebug() << "EcdDataTreeItem::addData - EcdDataTreeItem has not been initialized yet!";
        return false;
    }

    //Add further infos as children
    QList<QStandardItem*> list;
    MetaTreeItem *pItemNumDipoles = new MetaTreeItem(MetaTreeItemTypes::NumberDipoles, QString::number(pECDSet->size()));
    pItemNumDipoles->setEditable(false);
    list.clear();
    list << pItemNumDipoles;
    list << new QStandardItem(pItemNumDipoles->toolTip());
    this->appendRow(list);

    //Add data which is held by this NetworkTreeItem
    QVariant data;

    data.setValue(pECDSet);
    this->setData(data, Data3DTreeModelItemRoles::ECDSetData);

    //Plot dipole moment
    plotDipoles(pECDSet);

    return true;
}

//*************************************************************************************************************

void EcdDataTreeItem::onCheckStateChanged(const Qt::CheckState& checkState)
{
    this->setVisible(checkState == Qt::Unchecked ? false : true);
}

//*************************************************************************************************************

void EcdDataTreeItem::setVisible(bool state)
{
    for(int i = 0; i < m_lDipoles.size(); ++i) {
        m_lDipoles.at(i)->setEnabled(state);
    }

    m_pRenderable3DEntity->setEnabled(state);
}

//*************************************************************************************************************

void EcdDataTreeItem::plotDipoles(QSharedPointer<ECDSet> pECDSet)
{
    //Plot dipoles
    QVector3D pos,to,from;

    for(int i = 0; i < pECDSet->size(); ++i) {
        pos.setX((*pECDSet)[i].rd(0));
        pos.setY((*pECDSet)[i].rd(1));
        pos.setZ((*pECDSet)[i].rd(2));

        to.setX((*pECDSet)[i].Q(0));
        to.setY((*pECDSet)[i].Q(1));
        to.setZ((*pECDSet)[i].Q(2));
        //to.normalize();

        qDebug()<<"EcdDataTreeItem::plotDipoles - from" << from;
        qDebug()<<"EcdDataTreeItem::plotDipoles - to" << to;

        //The Qt3D default cone orientation and the top of the cone lies in line with the positive y-axis.
        from = QVector3D(0.0, 1.0, 0.0);
        QQuaternion final = QQuaternion::rotationTo(from, to);

        Renderable3DEntity* dipoleEntity = new Renderable3DEntity(m_pRenderable3DEntity);

        Qt3DExtras::QConeMesh* dipoleCone = new Qt3DExtras::QConeMesh();
        dipoleCone->setBottomRadius(0.001f);
        dipoleCone->setLength(0.003f);

        dipoleEntity->addComponent(dipoleCone);

        //Set dipole position and orientation
        Qt3DCore::QTransform* transform = new Qt3DCore::QTransform();
        QMatrix4x4 m;
        m.translate(pos);
        m.rotate(final);
        transform->setMatrix(m);
        dipoleEntity->addComponent(transform);

        Qt3DExtras::QPhongMaterial* material = new Qt3DExtras::QPhongMaterial();
        material->setAmbient(QColor(rand()%255, rand()%255, rand()%255));
        dipoleEntity->addComponent(material);

        m_lDipoles.append(dipoleEntity);
    }
}

<commit_msg>[LIB-161] Start working on dipole orientation issue<commit_after>//=============================================================================================================
/**
* @file     ecddatatreeitem.cpp
* @author   Lorenz Esch <Lorenz.Esch@tu-ilmenau.de>;
*           Matti Hamalainen <msh@nmr.mgh.harvard.edu>
* @version  1.0
* @date     November, 2015
*
* @section  LICENSE
*
* Copyright (C) 2015, Lorenz Esch and Matti Hamalainen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that
* the following conditions are met:
*     * Redistributions of source code must retain the above copyright notice, this list of conditions and the
*       following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
*       the following disclaimer in the documentation and/or other materials provided with the distribution.
*     * Neither the name of MNE-CPP authors nor the names of its contributors may be used
*       to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*
* @brief    EcdDataTreeItem class definition.
*
*/

//*************************************************************************************************************
//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include "ecddatatreeitem.h"
#include "../common/metatreeitem.h"
#include "../../3dhelpers/renderable3Dentity.h"

#include <inverse/dipoleFit/ecd_set.h>

//*************************************************************************************************************
//=============================================================================================================
// Qt INCLUDES
//=============================================================================================================

#include <QList>
#include <QVariant>
#include <QStringList>
#include <QColor>
#include <QVector3D>
#include <QStandardItem>
#include <QStandardItemModel>
#include <Qt3DRender/qshaderprogram.h>
#include <Qt3DExtras/QSphereMesh>
#include <Qt3DExtras/QPhongMaterial>
#include <Qt3DCore/QTransform>
#include <QQuaternion>
#include <Qt3DExtras/QConeMesh>

//*************************************************************************************************************
//=============================================================================================================
// Eigen INCLUDES
//=============================================================================================================

#include <Eigen/Core>

//*************************************************************************************************************
//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace Eigen;
using namespace INVERSELIB;
using namespace DISP3DLIB;

//*************************************************************************************************************
//=============================================================================================================
// DEFINE MEMBER METHODS
//=============================================================================================================

EcdDataTreeItem::EcdDataTreeItem(int iType, const QString &text)
: AbstractTreeItem(iType, text)
, m_bIsInit(false)
, m_pRenderable3DEntity(new Renderable3DEntity())
{
    this->setEditable(false);
    this->setCheckable(true);
    this->setCheckState(Qt::Checked);
    this->setToolTip("Dipole fit data");
}

//*************************************************************************************************************

EcdDataTreeItem::~EcdDataTreeItem()
{
    //Schedule deletion/Decouple of all entities so that the SceneGraph is NOT plotting them anymore.
    for(int i = 0; i < m_lDipoles.size(); ++i) {
        m_lDipoles.at(i)->deleteLater();
    }

    if(!m_pRenderable3DEntity.isNull()) {
        m_pRenderable3DEntity->deleteLater();
    }
}

//*************************************************************************************************************

QVariant EcdDataTreeItem::data(int role) const
{
    return AbstractTreeItem::data(role);
}

//*************************************************************************************************************

void EcdDataTreeItem::setData(const QVariant& value, int role)
{
    AbstractTreeItem::setData(value, role);
}

//*************************************************************************************************************

bool EcdDataTreeItem::init(Qt3DCore::QEntity* parent)
{
    //Create renderable 3D entity
    m_pRenderable3DEntity->setParent(parent);

    //Add meta information as item children
    QList<QStandardItem*> list;
    QVariant data;

    m_bIsInit = true;

    return true;
}

//*************************************************************************************************************

bool EcdDataTreeItem::addData(ECDSet::SPtr pECDSet)
{
    if(!m_bIsInit) {
        qDebug() << "EcdDataTreeItem::addData - EcdDataTreeItem has not been initialized yet!";
        return false;
    }

    //Add further infos as children
    QList<QStandardItem*> list;
    MetaTreeItem *pItemNumDipoles = new MetaTreeItem(MetaTreeItemTypes::NumberDipoles, QString::number(pECDSet->size()));
    pItemNumDipoles->setEditable(false);
    list.clear();
    list << pItemNumDipoles;
    list << new QStandardItem(pItemNumDipoles->toolTip());
    this->appendRow(list);

    //Add data which is held by this NetworkTreeItem
    QVariant data;

    data.setValue(pECDSet);
    this->setData(data, Data3DTreeModelItemRoles::ECDSetData);

    //Plot dipole moment
    plotDipoles(pECDSet);

    return true;
}

//*************************************************************************************************************

void EcdDataTreeItem::onCheckStateChanged(const Qt::CheckState& checkState)
{
    this->setVisible(checkState == Qt::Unchecked ? false : true);
}

//*************************************************************************************************************

void EcdDataTreeItem::setVisible(bool state)
{
    for(int i = 0; i < m_lDipoles.size(); ++i) {
        m_lDipoles.at(i)->setEnabled(state);
    }

    m_pRenderable3DEntity->setEnabled(state);
}

//*************************************************************************************************************

void EcdDataTreeItem::plotDipoles(QSharedPointer<ECDSet> pECDSet)
{
    //Plot dipoles
    QVector3D pos, to, from;

    for(int i = 0; i < pECDSet->size(); ++i) {
        pos.setX((*pECDSet)[i].rd(0));
        pos.setY((*pECDSet)[i].rd(1));
        pos.setZ((*pECDSet)[i].rd(2));

        to.setX((*pECDSet)[i].Q(0));
        to.setY((*pECDSet)[i].Q(1));
        to.setZ((*pECDSet)[i].Q(2));
        //to.normalize();

        //The Qt3D default cone orientation and the top of the cone lies in line with the positive y-axis.
        from = QVector3D(0.0, 1.0, 0.0);
        qDebug()<<"EcdDataTreeItem::plotDipoles - from" << from;
        qDebug()<<"EcdDataTreeItem::plotDipoles - to" << to;

        QQuaternion final = QQuaternion::rotationTo(from, to);

        Renderable3DEntity* dipoleEntity = new Renderable3DEntity(m_pRenderable3DEntity);

        Qt3DExtras::QConeMesh* dipoleCone = new Qt3DExtras::QConeMesh();
        dipoleCone->setBottomRadius(0.001f);
        dipoleCone->setLength(0.003f);

        dipoleEntity->addComponent(dipoleCone);

        //Set dipole position and orientation
        Qt3DCore::QTransform* transform = new Qt3DCore::QTransform();
        QMatrix4x4 m;
        m.translate(pos);
        m.rotate(final);
        transform->setMatrix(m);
        dipoleEntity->addComponent(transform);

        Qt3DExtras::QPhongMaterial* material = new Qt3DExtras::QPhongMaterial();
        material->setAmbient(QColor(rand()%255, rand()%255, rand()%255));
        dipoleEntity->addComponent(material);

        m_lDipoles.append(dipoleEntity);
    }
}

<|endoftext|>


<commit_before>#include <cstdio>
#include <iostream>
#include "Vcpu.h"

using namespace std;

#define MEMSIZE 65536

void tick(Vcpu *cpu);
void print_stats(Vcpu *cpu, int time);

int main(int argc, char **argv) {

	Verilated::commandArgs(argc, argv);

    if (argc < 2) {
        cerr << "usage: " << argv[0] << " <6502 executable>" << endl;
        return 1;
    }

    Vcpu *cpu = new Vcpu;
    char memory[MEMSIZE];
    memset((char *)memory, 9, sizeof(memory));
    int time = 0;
    uint16_t addr = 0;
    uint8_t input;

    /* Read assembled binary into simulated memory */
    char *filename = argv[1];
    FILE *binary = fopen(filename, "r");
    if (binary == NULL) {
        perror(filename);
        return 2;
    }
    size_t len = fread(memory, 1, MEMSIZE, binary);

	while (1) {
		if (Verilated::gotFinish()) { break; }

		addr = cpu->addr;

		if (addr == (len+1)) { break; }

		if (cpu->write) { memory[cpu->addr] = cpu->d_out; }

		tick(cpu);

		input = memory[addr];
		cpu->d_in = input;

        print_stats(cpu, time);
		time++;
	}
	cpu->final();

	delete cpu;
	return 0;
}

void tick(Vcpu *cpu) {
    cpu->clk = 0;
    cpu->eval();
    cpu->clk = 1;
    cpu->eval();
}

void print_stats(Vcpu *cpu, int time) {
    static int first = 1;
    if (first) {
        printf("%5s %2s %3s %4s\n",
               "Cycle", "Op", "out", "addr");
        first = 0;
    }

    if (cpu->sync) {
        printf("%5d %.2x %.3x %.4x\n",
               time, cpu->d_in, cpu->d_out, cpu->addr);
    }
}
<commit_msg>CPU simulator and testbench print same stuff<commit_after>#include <cstdio>
#include <iostream>
#include "Vcpu.h"

using namespace std;

#define MEMSIZE 65536

void tick(Vcpu *cpu);
void print_stats(Vcpu *cpu, int time);

int main(int argc, char **argv) {

	Verilated::commandArgs(argc, argv);

    if (argc < 2) {
        cerr << "usage: " << argv[0] << " <6502 executable>" << endl;
        return 1;
    }

    Vcpu *cpu = new Vcpu;
    char memory[MEMSIZE];
    memset((char *)memory, 9, sizeof(memory));
    int time = 0;
    uint16_t addr = 0;
    uint8_t input;

    /* Read assembled binary into simulated memory */
    char *filename = argv[1];
    FILE *binary = fopen(filename, "r");
    if (binary == NULL) {
        perror(filename);
        return 2;
    }
    size_t len = fread(memory, 1, MEMSIZE, binary);

	while (1) {
		if (Verilated::gotFinish()) { break; }

		addr = cpu->addr;

		if (addr == (len+1)) { break; }

		if (cpu->write) { memory[cpu->addr] = cpu->d_out; }

		tick(cpu);

		input = memory[addr];
		cpu->d_in = input;

        print_stats(cpu, time);
		time++;
	}
	cpu->final();

	delete cpu;
	return 0;
}

void tick(Vcpu *cpu) {
    cpu->clk = 0;
    cpu->eval();
    cpu->clk = 1;
    cpu->eval();
}

void print_stats(Vcpu *cpu, int time) {
    static int first = 1;
    if (first) {
        printf("Cycle Op  A  X  Y  P\n");
        first = 0;
    }

    if (cpu->sync) {
        printf("%5d %.2x %.2x %.2x %.2x %.2x\n",
               time,
               cpu->v__DOT__IR,
               cpu->v__DOT__A,
               cpu->v__DOT__X,
               cpu->v__DOT__Y,
               cpu->v__DOT__P);
    }
}
<|endoftext|>


<commit_before>#line 2 "togo/utility.hpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file utility.hpp
@brief Utilities.
@ingroup utility
*/

#pragma once

#include <togo/config.hpp>
#include <togo/types.hpp>
#include <togo/traits.hpp>
#include <togo/debug_constraints.hpp>

#include <type_traits>

namespace togo {

/**
	@addtogroup utility
	@{
*/

/** @name Type utilities */ /// @{

/// Cast unsigned integral to signed integral.
template<class T>
inline constexpr typename std::make_signed<T>::type
signed_cast(T const value) noexcept {
	return static_cast<typename std::make_signed<T>::type>(value);
}

/// Cast signed integral to unsigned integral.
template<class T>
inline constexpr typename std::make_unsigned<T>::type
unsigned_cast(T const value) noexcept {
	return static_cast<typename std::make_unsigned<T>::type>(value);
}

/// Get number of elements in bounded array.
template<class T, unsigned N>
inline constexpr unsigned
array_extent(T const (&)[N]) noexcept {
	return N;
}

/// Get number of elements in bounded array.
template<class T, class U, unsigned N>
inline constexpr unsigned
array_extent(T const (U::* const)[N]) noexcept {
	return N;
}

/// Get sizeof type or 0 if the type is empty.
template<class T>
inline constexpr unsigned
sizeof_empty() noexcept {
	return std::is_empty<T>::value ? 0 : sizeof(T);
}

/// @}

/** @name Misc utilities */ /// @{

/// Swap the values of two references.
template<class T>
inline void swap(T& x, T& y) {
	T temp = x;
	x = y;
	y = temp;
}

/// Less-than comparison operator wrapper.
template<class T>
inline bool less(T const& x, T const& y) {
	return x < y;
}

/// Greater-than comparison operator wrapper.
template<class T>
inline bool greater(T const& x, T const& y) {
	return x > y;
}

/// @}

/** @name Arithmetic utilities */ /// @{

/// Get the smallest of two values.
template<class T>
inline T min(T const x, T const y) noexcept {
	TOGO_CONSTRAIN_COMPARABLE(T);
	return x < y ? x : y;
}

/// Get the largest of two values.
template<class T>
inline T max(T const x, T const y) noexcept {
	TOGO_CONSTRAIN_COMPARABLE(T);
	return x > y ? x : y;
}

/// Clamp a value between a minimum and maximum.
template<class T>
inline T clamp(T const x, T const minimum, T const maximum) noexcept {
	TOGO_CONSTRAIN_COMPARABLE(T);
	return
		  x < minimum
		? minimum
		: x > maximum
		? maximum
		: x
	;
}

/// @}

/** @name Memory utilities */ /// @{

/// Advance pointer by bytes.
/// @warning This advances by bytes, not sizeof(T).
template<class T>
inline T* pointer_add(T* p, u32 const bytes) noexcept {
	return reinterpret_cast<T*>(reinterpret_cast<char*>(p) + bytes);
}

/// Aligns a pointer by moving it forward.
template<class T>
inline T* pointer_align(T* p, u32 const align) noexcept {
	u32 const m = reinterpret_cast<std::uintptr_t>(p) % align;
	if (m) {
		p = pointer_add(p, align - m);
	}
	return p;
}

/// @}

/** @name Enum utilities */ /// @{

/** @cond INTERNAL */
template<class FlagT, class = enable_if<enable_enum_bitwise_ops<FlagT>::value>>
inline constexpr FlagT operator|(FlagT const& x, FlagT const& y) noexcept {
	return static_cast<FlagT>(
		static_cast<unsigned>(x) | static_cast<unsigned>(y)
	);
}

template<class FlagT, class = enable_if<enable_enum_bitwise_ops<FlagT>::value>>
inline constexpr FlagT operator&(FlagT const& x, FlagT const& y) noexcept {
	return static_cast<FlagT>(
		static_cast<unsigned>(x) & static_cast<unsigned>(y)
	);
}

template<class FlagT, class = enable_if<enable_enum_bitwise_ops<FlagT>::value>>
inline constexpr FlagT& operator|=(FlagT& x, FlagT const& y) noexcept {
	return x = static_cast<FlagT>(
		static_cast<unsigned>(x) | static_cast<unsigned>(y)
	);
}

template<class FlagT, class = enable_if<enable_enum_bitwise_ops<FlagT>::value>>
inline constexpr FlagT& operator&=(FlagT& x, FlagT const& y) noexcept {
	return x = static_cast<FlagT>(
		static_cast<unsigned>(x) & static_cast<unsigned>(y)
	);
}
/** @endcond */ // INTERNAL

/// @}

/** @} */ // end of doc-group utility

} // namespace togo
<commit_msg>utility: added enum_bool().<commit_after>#line 2 "togo/utility.hpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file utility.hpp
@brief Utilities.
@ingroup utility
*/

#pragma once

#include <togo/config.hpp>
#include <togo/types.hpp>
#include <togo/traits.hpp>
#include <togo/debug_constraints.hpp>

#include <type_traits>

namespace togo {

/**
	@addtogroup utility
	@{
*/

/** @name Type utilities */ /// @{

/// Cast unsigned integral to signed integral.
template<class T>
inline constexpr typename std::make_signed<T>::type
signed_cast(T const value) noexcept {
	return static_cast<typename std::make_signed<T>::type>(value);
}

/// Cast signed integral to unsigned integral.
template<class T>
inline constexpr typename std::make_unsigned<T>::type
unsigned_cast(T const value) noexcept {
	return static_cast<typename std::make_unsigned<T>::type>(value);
}

/// Get number of elements in bounded array.
template<class T, unsigned N>
inline constexpr unsigned
array_extent(T const (&)[N]) noexcept {
	return N;
}

/// Get number of elements in bounded array.
template<class T, class U, unsigned N>
inline constexpr unsigned
array_extent(T const (U::* const)[N]) noexcept {
	return N;
}

/// Get sizeof type or 0 if the type is empty.
template<class T>
inline constexpr unsigned
sizeof_empty() noexcept {
	return std::is_empty<T>::value ? 0 : sizeof(T);
}

/// @}

/** @name Misc utilities */ /// @{

/// Swap the values of two references.
template<class T>
inline void swap(T& x, T& y) {
	T temp = x;
	x = y;
	y = temp;
}

/// Less-than comparison operator wrapper.
template<class T>
inline bool less(T const& x, T const& y) {
	return x < y;
}

/// Greater-than comparison operator wrapper.
template<class T>
inline bool greater(T const& x, T const& y) {
	return x > y;
}

/// @}

/** @name Arithmetic utilities */ /// @{

/// Get the smallest of two values.
template<class T>
inline T min(T const x, T const y) noexcept {
	TOGO_CONSTRAIN_COMPARABLE(T);
	return x < y ? x : y;
}

/// Get the largest of two values.
template<class T>
inline T max(T const x, T const y) noexcept {
	TOGO_CONSTRAIN_COMPARABLE(T);
	return x > y ? x : y;
}

/// Clamp a value between a minimum and maximum.
template<class T>
inline T clamp(T const x, T const minimum, T const maximum) noexcept {
	TOGO_CONSTRAIN_COMPARABLE(T);
	return
		  x < minimum
		? minimum
		: x > maximum
		? maximum
		: x
	;
}

/// @}

/** @name Memory utilities */ /// @{

/// Advance pointer by bytes.
/// @warning This advances by bytes, not sizeof(T).
template<class T>
inline T* pointer_add(T* p, u32 const bytes) noexcept {
	return reinterpret_cast<T*>(reinterpret_cast<char*>(p) + bytes);
}

/// Aligns a pointer by moving it forward.
template<class T>
inline T* pointer_align(T* p, u32 const align) noexcept {
	u32 const m = reinterpret_cast<std::uintptr_t>(p) % align;
	if (m) {
		p = pointer_add(p, align - m);
	}
	return p;
}

/// @}

/** @name Enum utilities */ /// @{

/// Return true whether an enum value is non-zero.
template<class T>
inline constexpr bool enum_bool(T const value) {
	static_assert(
		std::is_enum<T>::value,
		"T must be an enum"
	);
	return static_cast<typename std::underlying_type<T>::type>(value);
}

/** @cond INTERNAL */
template<class FlagT, class = enable_if<enable_enum_bitwise_ops<FlagT>::value>>
inline constexpr FlagT operator|(FlagT const& x, FlagT const& y) noexcept {
	return static_cast<FlagT>(
		static_cast<unsigned>(x) | static_cast<unsigned>(y)
	);
}

template<class FlagT, class = enable_if<enable_enum_bitwise_ops<FlagT>::value>>
inline constexpr FlagT operator&(FlagT const& x, FlagT const& y) noexcept {
	return static_cast<FlagT>(
		static_cast<unsigned>(x) & static_cast<unsigned>(y)
	);
}

template<class FlagT, class = enable_if<enable_enum_bitwise_ops<FlagT>::value>>
inline constexpr FlagT& operator|=(FlagT& x, FlagT const& y) noexcept {
	return x = static_cast<FlagT>(
		static_cast<unsigned>(x) | static_cast<unsigned>(y)
	);
}

template<class FlagT, class = enable_if<enable_enum_bitwise_ops<FlagT>::value>>
inline constexpr FlagT& operator&=(FlagT& x, FlagT const& y) noexcept {
	return x = static_cast<FlagT>(
		static_cast<unsigned>(x) & static_cast<unsigned>(y)
	);
}
/** @endcond */ // INTERNAL

/// @}

/** @} */ // end of doc-group utility

} // namespace togo
<|endoftext|>


<commit_before>/* GNE - Game Networking Engine, a portable multithreaded networking library.
 * Copyright (C) 2001 Jason Winnebeck (gillius@webzone.net)
 * Project website: http://www.rit.edu/~jpw9607/
 *
 * 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/**
 * exhello
 * Everyone knows the "Hello World" program.  Perhaps it's been coded
 * too many times.  However, the GNE coders just plain don't care ;).
 * This is an example to show the minimum code needed to connect and send
 * data, in this case, "Hello Server (or Client)!" to the other end of the
 * connection.
 * Well... perhaps not the minimum.  Lots of errors can happen over network
 * connections that we have to handle for this program to properly execute
 * when conditions aren't perfectly ideal, like when we can't reach the
 * server.
 */

#include "../../src/gnelib.h"
#include <iostream>
#include <cstring>

using namespace std;
using namespace GNE;
using namespace GNE::Console;

void errorExit(const char* error);
int getPort(const char* prompt);
void displayAddress();
string getAddressString(NLaddress& addr);
void doServer(int outRate, int inRate, int port);
void doClient(int outRate, int inRate, int port);

class OurClient : public ClientConnection {
public:
  OurClient(int outRate, int inRate)
    : ClientConnection(outRate, inRate) {}

  void onConnect() {
    mprintf("Connection to server successful.\n");
  }

  void onConnectFailure(FailureType errorType) {
    mprintf("Connection to server failed.\n");
  }

  virtual ~OurClient() {}
private:
};

class OurServer : public ServerConnection {
public:
  OurServer(int outRate, int inRate, NLsocket rsocket2)
    : ServerConnection(outRate, inRate, rsocket2) {}

  virtual ~OurServer() {}

  void onNewConn() {
    mprintf("Connection received.\n");
    detach(true);
  }

  void onConnFailure(FailureType errorType) {
    mprintf("Connection failure.\n");
    detach(true);
  }
private:
};

class OurCreator : public ServerConnectionCreator {
public:
  OurCreator() {}
  virtual ~OurCreator() {}

  ServerConnection* create(int outRate, int inRate, NLsocket rsocket2) {
    return new OurServer(outRate, inRate, rsocket2);
  }
};

class OurListener : public ServerConnectionListener {
public:
  OurListener(int outRate, int inRate)
    : ServerConnectionListener(outRate, inRate, new OurCreator()) {
  }

  virtual ~OurListener() {}

private:
};

int main(int argc, char* argv[]) {
  initGNE(NL_IP, atexit);
  setUserVersion(1); //sets our user protocol version number, used in
                     //the connection process by GNE to version check.
  initConsole(atexit);
  setTitle("GNE Basic Connections Example");

  //It's okay to use iostreams instead of the Console functions when we are
  //only accessing the console from one thread.
  displayAddress();
  cout << "Should we act as the server, or the client?" << endl;
  cout << "Type 1 for client, 2 for server: ";
  int type;
  cin >> type;

  int port;
  if (type == 2) {
    setTitle("GNE Basic Connections Example -- Server");
    cout << "Reminder: ports <= 1024 on UNIX can only be used by the superuser." << endl;
    port = getPort("listen on");
    doServer(3000, 3000, port);
  } else {
    setTitle("GNE Basic Connections Example -- Client");
    port = getPort("connect to");
    doClient(3000, 3000, port);
  }

  return 0;
}

void errorExit(const char* error) {
  cout << "Error: " << error << endl;
  exit(1);
}

int getPort(const char* prompt) {
  int port;
  cout << "Which port should we " << prompt << ": ";
  cin >> port;
  while ((port < 1) || (port > 65535)) {
    cout << "Ports range from 1 to 65535, please select one in this range: ";
    cin >> port;
  }
  return port;
}

void displayAddress() {
  NLaddress ourAddr = getLocalAddress();
  char buf[NL_MAX_STRING_LENGTH];
  nlAddrToString(&ourAddr, (NLbyte*)buf);
  char* temp = strchr(buf, ':');
  if (temp)
    *temp = '\0';
  cout << "Local address: " << buf << endl;
}

string getAddressString(NLaddress& addr) {
  char buf[NL_MAX_STRING_LENGTH];
  nlAddrToString(&addr, (NLbyte*)buf);
  return string(buf);
}

void doServer(int outRate, int inRate, int port) {
  OurListener server(outRate, inRate);
  if (server.open(port))
    errorExit("Cannot open server socket.");
  if (server.listen())
    errorExit("Cannot listen on server socket.");

  cout << "Server is listening on: " << getAddressString(server.getLocalAddress()) << endl;
  cout << "Press a key to shutdown server." << endl;
  getch();
  //When the server class is destructed, it will stop listening and shutdown.
}

void doClient(int outRate, int inRate, int port) {
  string host;
  cout << "Enter hostname or IP address: ";
  cin >> host;

  NLaddress addr;
  nlGetAddrFromName((NLbyte*)host.c_str(), &addr);
  nlSetAddrPort(&addr, (NLushort)port);

  cout << "Connecting to: " << getAddressString(addr) << endl;
  OurClient client(outRate, inRate);
  client.open(addr); //let port take 0 default, for any local port.
  client.connect();
  client.join();     //join on the connection thread
  //if we did not call join, we would have called client.detach(false)
  //instead for true async connections.
}<commit_msg>Changes made so it compiles in Mingw.<commit_after>/* GNE - Game Networking Engine, a portable multithreaded networking library.
 * Copyright (C) 2001 Jason Winnebeck (gillius@webzone.net)
 * Project website: http://www.rit.edu/~jpw9607/
 *
 * 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/**
 * exhello
 * Everyone knows the "Hello World" program.  Perhaps it's been coded
 * too many times.  However, the GNE coders just plain don't care ;).
 * This is an example to show the minimum code needed to connect and send
 * data, in this case, "Hello Server (or Client)!" to the other end of the
 * connection.
 * Well... perhaps not the minimum.  Lots of errors can happen over network
 * connections that we have to handle for this program to properly execute
 * when conditions aren't perfectly ideal, like when we can't reach the
 * server.
 */

#include "../../src/gnelib.h"
#include <iostream>
#include <cstring>

using namespace std;
using namespace GNE;
using namespace GNE::Console;

void errorExit(const char* error);
int getPort(const char* prompt);
void displayAddress();
string getAddressString(NLaddress addr);
void doServer(int outRate, int inRate, int port);
void doClient(int outRate, int inRate, int port);

class OurClient : public ClientConnection {
public:
  OurClient(int outRate, int inRate)
    : ClientConnection(outRate, inRate) {}

  void onConnect() {
    mprintf("Connection to server successful.\n");
  }

  void onConnectFailure(FailureType errorType) {
    mprintf("Connection to server failed.\n");
  }

  virtual ~OurClient() {}
private:
};

class OurServer : public ServerConnection {
public:
  OurServer(int outRate, int inRate, NLsocket rsocket2)
    : ServerConnection(outRate, inRate, rsocket2) {}

  virtual ~OurServer() {}

  void onNewConn() {
    mprintf("Connection received.\n");
    detach(true);
  }

  void onConnFailure(FailureType errorType) {
    mprintf("Connection failure.\n");
    detach(true);
  }
private:
};

class OurCreator : public ServerConnectionCreator {
public:
  OurCreator() {}
  virtual ~OurCreator() {}

  ServerConnection* create(int outRate, int inRate, NLsocket rsocket2) {
    return new OurServer(outRate, inRate, rsocket2);
  }
};

class OurListener : public ServerConnectionListener {
public:
  OurListener(int outRate, int inRate)
    : ServerConnectionListener(outRate, inRate, new OurCreator()) {
  }

  virtual ~OurListener() {}

private:
};

int main(int argc, char* argv[]) {
  initGNE(NL_IP, atexit);
  setUserVersion(1); //sets our user protocol version number, used in
                     //the connection process by GNE to version check.
  initConsole(atexit);
  setTitle("GNE Basic Connections Example");

  //It's okay to use iostreams instead of the Console functions when we are
  //only accessing the console from one thread.
  displayAddress();
  cout << "Should we act as the server, or the client?" << endl;
  cout << "Type 1 for client, 2 for server: ";
  int type;
  cin >> type;

  int port;
  if (type == 2) {
    setTitle("GNE Basic Connections Example -- Server");
    cout << "Reminder: ports <= 1024 on UNIX can only be used by the superuser." << endl;
    port = getPort("listen on");
    doServer(3000, 3000, port);
  } else {
    setTitle("GNE Basic Connections Example -- Client");
    port = getPort("connect to");
    doClient(3000, 3000, port);
  }

  return 0;
}

void errorExit(const char* error) {
  cout << "Error: " << error << endl;
  exit(1);
}

int getPort(const char* prompt) {
  int port;
  cout << "Which port should we " << prompt << ": ";
  cin >> port;
  while ((port < 1) || (port > 65535)) {
    cout << "Ports range from 1 to 65535, please select one in this range: ";
    cin >> port;
  }
  return port;
}

void displayAddress() {
  NLaddress ourAddr = getLocalAddress();
  char buf[NL_MAX_STRING_LENGTH];
  nlAddrToString(&ourAddr, (NLbyte*)buf);
  char* temp = strchr(buf, ':');
  if (temp)
    *temp = '\0';
  cout << "Local address: " << buf << endl;
}

string getAddressString(NLaddress addr) {
  char buf[NL_MAX_STRING_LENGTH];
  nlAddrToString(&addr, (NLbyte*)buf);
  return string(buf);
}

void doServer(int outRate, int inRate, int port) {
  OurListener server(outRate, inRate);
  if (server.open(port))
    errorExit("Cannot open server socket.");
  if (server.listen())
    errorExit("Cannot listen on server socket.");

  cout << "Server is listening on: " << getAddressString(server.getLocalAddress()) << endl;
  cout << "Press a key to shutdown server." << endl;
  getch();
  //When the server class is destructed, it will stop listening and shutdown.
}

void doClient(int outRate, int inRate, int port) {
  string host;
  cout << "Enter hostname or IP address: ";
  cin >> host;

  NLaddress addr;
  nlGetAddrFromName((NLbyte*)host.c_str(), &addr);
  nlSetAddrPort(&addr, (NLushort)port);

  cout << "Connecting to: " << getAddressString(addr) << endl;
  OurClient client(outRate, inRate);
  client.open(addr); //let port take 0 default, for any local port.
  client.connect();
  client.join();     //join on the connection thread
  //if we did not call join, we would have called client.detach(false)
  //instead for true async connections.
}<|endoftext|>


<commit_before>/*
 *  Copyright (C) 2010 - 2015 Leonid Kostrykin
 *
 *  Chair of Medical Engineering (mediTEC)
 *  RWTH Aachen University
 *  Pauwelsstr. 20
 *  52074 Aachen
 *  Germany
 *
 */

#include <Carna/presets/OrthogonalControl.h>
#include <Carna/base/math.h>

namespace Carna
{

namespace presets
{

// ----------------------------------------------------------------------------------
// OrthogonalControl :: Details
// ----------------------------------------------------------------------------------

struct OrthogonalControl::Details
{
    Details( base::CameraControl* cc );
    const std::unique_ptr< base::CameraControl > cc;

    float weightedAxialPosition;
    float zoomStrength;
    float zoomFactor() const;
};

OrthogonalControl::Details::Details( base::CameraControl* cc )
    : cc( cc )
    , weightedAxialPosition( 0 )
    , zoomStrength( DEFAULT_ZOOM_STRENGTH )
{
}

float OrthogonalControl::Details::zoomFactor() const
{
    if( weightedAxialPosition >= 0 )
    {
        return 1 + weightedAxialPosition;
    }
    else
    {
        return 1 / ( 1 - weightedAxialPosition );
    }
}

// ----------------------------------------------------------------------------------
// OrthogonalControl
// ----------------------------------------------------------------------------------

const float OrthogonalControl::DEFAULT_ZOOM_STRENGTH = 1e-1f;

OrthogonalControl::OrthogonalControl( base::CameraControl* cc )
    : pimpl( new Details( cc ) )
{
    CARNA_ASSERT( cc != nullptr );
}

OrthogonalControl::~OrthogonalControl()
{
}

void OrthogonalControl::setZoomStrength( float zoomStrength )
{
    CARNA_ASSERT( zoomStrength > 0 );
    if( !base::math::isEqual( pimpl->zoomStrength, zoomStrength ) )
    {
        pimpl->zoomStrength = zoomStrength;
        invalidateProjection();
    }
}

float OrthogonalControl::zoomStrength() const
{
    return pimpl->zoomStrength;
}

void OrthogonalControl::updateProjection( base::math::Matrix4f& projection ) const
{
    const float shortSideLength = std::min( viewportWidth(), viewportHeight() );
    const float halfZoomFactor = pimpl->zoomFactor() / 2;

    const float left   = viewportWidth () * ( -halfZoomFactor );
    const float right  = viewportWidth () * ( +halfZoomFactor );
    const float bottom = viewportHeight() * ( -halfZoomFactor );
    const float top    = viewportHeight() * ( +halfZoomFactor );
    const float zMin = minimumVisibleDistance();
    const float zMax = maximumVisibleDistance();
    projection = base::math::ortho4f( left, right, bottom, top, zMin, zMax );
    setProjectionValidated();
}

void OrthogonalControl::moveAxially( float units )
{
    if( !base::math::isEqual( units, 0.f ) )
    {
        pimpl->weightedAxialPosition += pimpl->zoomStrength * units;
        invalidateProjection();
    }
}

void OrthogonalControl::setCamera( base::Spatial& cam )
{
    pimpl->cc->setCamera( cam );
}

void OrthogonalControl::rotateHorizontally( float radians )
{
    pimpl->cc->rotateHorizontally( radians );
}

void OrthogonalControl::rotateVertically( float radians )
{
    pimpl->cc->rotateVertically( radians );
}

void OrthogonalControl::moveLaterally( float unitsX, float unitsY )
{
    pimpl->cc->moveLaterally( unitsX, unitsY );
}

}  // namespace Carna :: presets

}  // namespace Carna

<commit_msg>OrthogonalControl::moveLaterally now pays attention to current zoom level.<commit_after>/*
 *  Copyright (C) 2010 - 2015 Leonid Kostrykin
 *
 *  Chair of Medical Engineering (mediTEC)
 *  RWTH Aachen University
 *  Pauwelsstr. 20
 *  52074 Aachen
 *  Germany
 *
 */

#include <Carna/presets/OrthogonalControl.h>
#include <Carna/base/math.h>

namespace Carna
{

namespace presets
{

// ----------------------------------------------------------------------------------
// OrthogonalControl :: Details
// ----------------------------------------------------------------------------------

struct OrthogonalControl::Details
{
    Details( base::CameraControl* cc );
    const std::unique_ptr< base::CameraControl > cc;

    float weightedAxialPosition;
    float zoomStrength;
    float zoomFactor() const;
};

OrthogonalControl::Details::Details( base::CameraControl* cc )
    : cc( cc )
    , weightedAxialPosition( 0 )
    , zoomStrength( DEFAULT_ZOOM_STRENGTH )
{
}

float OrthogonalControl::Details::zoomFactor() const
{
    if( weightedAxialPosition >= 0 )
    {
        return 1 + weightedAxialPosition;
    }
    else
    {
        return 1 / ( 1 - weightedAxialPosition );
    }
}

// ----------------------------------------------------------------------------------
// OrthogonalControl
// ----------------------------------------------------------------------------------

const float OrthogonalControl::DEFAULT_ZOOM_STRENGTH = 1e-1f;

OrthogonalControl::OrthogonalControl( base::CameraControl* cc )
    : pimpl( new Details( cc ) )
{
    CARNA_ASSERT( cc != nullptr );
}

OrthogonalControl::~OrthogonalControl()
{
}

void OrthogonalControl::setZoomStrength( float zoomStrength )
{
    CARNA_ASSERT( zoomStrength > 0 );
    if( !base::math::isEqual( pimpl->zoomStrength, zoomStrength ) )
    {
        pimpl->zoomStrength = zoomStrength;
        invalidateProjection();
    }
}

float OrthogonalControl::zoomStrength() const
{
    return pimpl->zoomStrength;
}

void OrthogonalControl::updateProjection( base::math::Matrix4f& projection ) const
{
    const float shortSideLength = std::min( viewportWidth(), viewportHeight() );
    const float halfZoomFactor = pimpl->zoomFactor() / 2;

    const float left   = viewportWidth () * ( -halfZoomFactor );
    const float right  = viewportWidth () * ( +halfZoomFactor );
    const float bottom = viewportHeight() * ( -halfZoomFactor );
    const float top    = viewportHeight() * ( +halfZoomFactor );
    const float zMin = minimumVisibleDistance();
    const float zMax = maximumVisibleDistance();
    projection = base::math::ortho4f( left, right, bottom, top, zMin, zMax );
    setProjectionValidated();
}

void OrthogonalControl::moveAxially( float units )
{
    if( !base::math::isEqual( units, 0.f ) )
    {
        pimpl->weightedAxialPosition += pimpl->zoomStrength * units;
        invalidateProjection();
    }
}

void OrthogonalControl::setCamera( base::Spatial& cam )
{
    pimpl->cc->setCamera( cam );
}

void OrthogonalControl::rotateHorizontally( float radians )
{
    pimpl->cc->rotateHorizontally( radians );
}

void OrthogonalControl::rotateVertically( float radians )
{
    pimpl->cc->rotateVertically( radians );
}

void OrthogonalControl::moveLaterally( float unitsX, float unitsY )
{
    const float zoomFactor = pimpl->zoomFactor();
    pimpl->cc->moveLaterally( zoomFactor * unitsX, zoomFactor * unitsY );
}

}  // namespace Carna :: presets

}  // namespace Carna

<|endoftext|>


<commit_before>/*
 * Copyright 2015 Aldebaran
 *
 * 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.
 *
*/

#ifndef BASE_PUBLISHER_HPP
#define BASE_PUBLISHER_HPP

#include <algorithm>
#include <iostream>
#include <string>

#include <alvalue/alvalue.h>
#include <qi/session.hpp>

#include <alrosbridge/tools.hpp>

namespace alros
{
namespace publisher
{

// CRTP
template<class T>
class BasePublisher
{

public:
  BasePublisher( const std::string& name, const std::string& topic, float frequency, qi::SessionPtr session ):
    name_( name ),
    topic_( topic ),
    frequency_( frequency ),
    is_initialized_( false ),
    robot_( UNIDENTIFIED ),
    session_(session)
  {}

  virtual ~BasePublisher() {};

  inline std::string name() const
  {
    return name_;
  }

  inline std::string topic() const
  {
    return topic_;
  }

  inline float frequency() const
  {
    return frequency_;
  }

  inline bool isInitialized() const
  {
    return is_initialized_;
  }

  /** Function that returns the type of a robot
   */
  inline Robot robot() const
  {
    if (robot_ != UNIDENTIFIED)
      return robot_;

    qi::AnyObject p_memory = session_->service("ALMemory");
    std::string robot = p_memory.call<AL::ALValue>("getData", "RobotConfig/Body/Type" );
    std::transform(robot.begin(), robot.end(), robot.begin(), ::tolower);

    if (std::string(robot) == "nao")
      robot_ = NAO;
    else if (std::string(robot) == "pepper")
      robot_ = PEPPER;
    else
      robot_ = UNIDENTIFIED;
    return robot_;
  }

  virtual bool isSubscribed() const = 0;

protected:
  std::string name_, topic_;

  bool is_initialized_;

  /** Frequency at which the publisher should publish. This is informative */
  float frequency_;
  /** The type of the robot */
  mutable Robot robot_;

  /** Pointer to a session from which we can create proxies */
  qi::SessionPtr session_;
}; // class

} //publisher
} // alros

#endif
<commit_msg>quickfix: return correct robot string<commit_after>/*
 * Copyright 2015 Aldebaran
 *
 * 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.
 *
*/

#ifndef BASE_PUBLISHER_HPP
#define BASE_PUBLISHER_HPP

#include <algorithm>
#include <iostream>
#include <string>

#include <alvalue/alvalue.h>
#include <qi/session.hpp>

#include <alrosbridge/tools.hpp>

namespace alros
{
namespace publisher
{

// CRTP
template<class T>
class BasePublisher
{

public:
  BasePublisher( const std::string& name, const std::string& topic, float frequency, qi::SessionPtr session ):
    name_( name ),
    topic_( topic ),
    frequency_( frequency ),
    is_initialized_( false ),
    robot_( UNIDENTIFIED ),
    session_(session)
  {}

  virtual ~BasePublisher() {};

  inline std::string name() const
  {
    return name_;
  }

  inline std::string topic() const
  {
    return topic_;
  }

  inline float frequency() const
  {
    return frequency_;
  }

  inline bool isInitialized() const
  {
    return is_initialized_;
  }

  /** Function that returns the type of a robot
   */
  inline Robot robot() const
  {
    if (robot_ != UNIDENTIFIED)
      return robot_;

    qi::AnyObject p_memory = session_->service("ALMemory");
    std::string robot = p_memory.call<AL::ALValue>("getData", "RobotConfig/Body/Type" );
    std::transform(robot.begin(), robot.end(), robot.begin(), ::tolower);

    if (std::string(robot) == "nao")
    {
      robot_ = NAO;
      return robot_;
    }
    else if (std::string(robot) == "pepper")
    {
      robot_ = PEPPER;
      return robot_;
    }
    else
    {
      robot_ = UNIDENTIFIED;
      return robot_;
    }
  }

  virtual bool isSubscribed() const = 0;

protected:
  std::string name_, topic_;

  bool is_initialized_;

  /** Frequency at which the publisher should publish. This is informative */
  float frequency_;
  /** The type of the robot */
  mutable Robot robot_;

  /** Pointer to a session from which we can create proxies */
  qi::SessionPtr session_;
}; // class

} //publisher
} // alros

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
 */

#include "query.h"

// for sorting and set operations
bool query_result_unit_t::operator<(const query_result_unit_t& rhs) const
{
#if 0
    if (timestamp == rhs.timestamp)
    {
        GenDb::DbDataValueVec::iterator it = info.begin();
        GenDb::DbDataValueVec::iterator jt = rhs.info.begin();
        for (; it != info.end(), jt != rhs.info.end(); it++, jt++) {
            if (*it < *jt) {
                return true;
            } else if (*it > *jt) {
                return false;
            }
        }
        return false;
    }
#endif

    return (timestamp < rhs.timestamp);
}

void SetOperationUnit::or_operation()
{
    if (sub_queries.size() == 0)
    {
        QE_TRACE(DEBUG, "Empty where sub-clause");
        return;
    }

    // with one query no need to do any operation
    query_result = sub_queries[0]->query_result;

    for (unsigned int i = 1; i < sub_queries.size(); i++)
    {
        std::vector<query_result_unit_t> tmp_query_result;

        QE_TRACE(DEBUG, "UNION between tables of sizes " <<
                query_result.size() << " and " <<
                sub_queries[i]->query_result.size());
        set_union(query_result.begin(), query_result.end(),
                sub_queries[i]->query_result.begin(),
                sub_queries[i]->query_result.end(),
                std::back_inserter(tmp_query_result));

        query_result = tmp_query_result;    // keep the result in output var
        QE_TRACE(DEBUG, "Resulting size of set " << query_result.size());
    }
}

void SetOperationUnit::and_operation()
{
    if (sub_queries.size() == 0)
    {
        QE_TRACE(DEBUG, "Empty where sub-clause");
        return;
    }

    // with one query no need to do any operation
    query_result = sub_queries[0]->query_result;

    for (unsigned int i = 1; i < sub_queries.size(); i++)
    {
        std::vector<query_result_unit_t> tmp_query_result;

        QE_TRACE(DEBUG, "INT between tables of sizes " <<
                query_result.size() << " and " <<
                sub_queries[i]->query_result.size());
        set_intersection(query_result.begin(), query_result.end(),
                sub_queries[i]->query_result.begin(),
                sub_queries[i]->query_result.end(),
                std::back_inserter(tmp_query_result));

        query_result = tmp_query_result;    // keep the result in output var
        QE_TRACE(DEBUG, "Resulting size of set " << query_result.size());
    }
}

query_status_t SetOperationUnit::process_query()
{
    if (status_details != 0)
    {
        QE_TRACE(DEBUG,
             "No need to process query, as there were errors previously");
        return QUERY_FAILURE;
    }

    QE_TRACE(DEBUG,
             " No of subset queries:"  << sub_queries.size());
    // invoke processing of all the sub queries
    // TBD: Handle ASYNC processing
    for (unsigned int i = 0; i < sub_queries.size(); i++)
    {
        query_status_t query_status = sub_queries[i]->process_query();

        if (query_status == QUERY_FAILURE)
        {
            status_details = sub_queries[i]->status_details;
            return QUERY_FAILURE;
        }
    }

    QE_TRACE(DEBUG, "Set operation between " << sub_queries.size()
            << " tables");

    // Do the SET operation
    switch (set_operation)
    {
        case UNION_OP:
            QE_TRACE(DEBUG, "Now do UNION set operation");
            or_operation();
            break;

        case INTERSECTION_OP:
            QE_TRACE(DEBUG, "Now do INTERSECTION set operation");
            and_operation();
            break;

        default:
            // Dont know what to do
            if (sub_queries.size() != 0)
                query_result = sub_queries[0]->query_result;
            break;
    }

    // Have the result ready and processing is done
    status_details = 0;
    parent_query->subquery_processed(this);
    return QUERY_SUCCESS;
}

<commit_msg>fix set operation and/or issue<commit_after>/*
 * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
 */

#include "query.h"

// for sorting and set operations
bool query_result_unit_t::operator<(const query_result_unit_t& rhs) const
{
    if (timestamp == rhs.timestamp)
    {
        GenDb::DbDataValueVec::const_iterator it = info.begin();
        GenDb::DbDataValueVec::const_iterator jt = rhs.info.begin();
        for (; it != info.end(), jt != rhs.info.end(); it++, jt++) {
            if (*it < *jt) {
                return true;
            } else if (*jt < *it) {
                return false;
            }
        }
        return false;
    }

    return (timestamp < rhs.timestamp);
}

void SetOperationUnit::or_operation()
{
    if (sub_queries.size() == 0)
    {
        QE_TRACE(DEBUG, "Empty where sub-clause");
        return;
    }

    // with one query no need to do any operation
    query_result = sub_queries[0]->query_result;

    for (unsigned int i = 1; i < sub_queries.size(); i++)
    {
        std::vector<query_result_unit_t> tmp_query_result;

        QE_TRACE(DEBUG, "UNION between tables of sizes " <<
                query_result.size() << " and " <<
                sub_queries[i]->query_result.size());
        set_union(query_result.begin(), query_result.end(),
                sub_queries[i]->query_result.begin(),
                sub_queries[i]->query_result.end(),
                std::back_inserter(tmp_query_result));

        query_result = tmp_query_result;    // keep the result in output var
        QE_TRACE(DEBUG, "Resulting size of set " << query_result.size());
    }
}

void SetOperationUnit::and_operation()
{
    if (sub_queries.size() == 0)
    {
        QE_TRACE(DEBUG, "Empty where sub-clause");
        return;
    }

    // with one query no need to do any operation
    query_result = sub_queries[0]->query_result;

    for (unsigned int i = 1; i < sub_queries.size(); i++)
    {
        std::vector<query_result_unit_t> tmp_query_result;

        QE_TRACE(DEBUG, "INT between tables of sizes " <<
                query_result.size() << " and " <<
                sub_queries[i]->query_result.size());
        set_intersection(query_result.begin(), query_result.end(),
                sub_queries[i]->query_result.begin(),
                sub_queries[i]->query_result.end(),
                std::back_inserter(tmp_query_result));

        query_result = tmp_query_result;    // keep the result in output var
        QE_TRACE(DEBUG, "Resulting size of set " << query_result.size());
    }
}

query_status_t SetOperationUnit::process_query()
{
    if (status_details != 0)
    {
        QE_TRACE(DEBUG,
             "No need to process query, as there were errors previously");
        return QUERY_FAILURE;
    }

    QE_TRACE(DEBUG,
             " No of subset queries:"  << sub_queries.size());
    // invoke processing of all the sub queries
    // TBD: Handle ASYNC processing
    for (unsigned int i = 0; i < sub_queries.size(); i++)
    {
        query_status_t query_status = sub_queries[i]->process_query();

        if (query_status == QUERY_FAILURE)
        {
            status_details = sub_queries[i]->status_details;
            return QUERY_FAILURE;
        }
    }

    QE_TRACE(DEBUG, "Set operation between " << sub_queries.size()
            << " tables");

    // Do the SET operation
    switch (set_operation)
    {
        case UNION_OP:
            QE_TRACE(DEBUG, "Now do UNION set operation");
            or_operation();
            break;

        case INTERSECTION_OP:
            QE_TRACE(DEBUG, "Now do INTERSECTION set operation");
            and_operation();
            break;

        default:
            // Dont know what to do
            if (sub_queries.size() != 0)
                query_result = sub_queries[0]->query_result;
            break;
    }

    // Have the result ready and processing is done
    status_details = 0;
    parent_query->subquery_processed(this);
    return QUERY_SUCCESS;
}

<|endoftext|>


<commit_before>#include "nova_renderer/frontend/pipeline_storage.hpp"

#include "nova_renderer/nova_renderer.hpp"
#include "nova_renderer/rhi/render_engine.hpp"

#include "spirv_glsl.hpp"

using namespace spirv_cross;

namespace nova::renderer {
    using namespace mem;
    using namespace ntl;
    using namespace shaderpack;

    PipelineStorage::PipelineStorage(NovaRenderer& renderer, AllocatorHandle<>& allocator)
        : renderer(renderer), device(renderer.get_engine()), allocator(allocator) {}

    std::optional<renderer::Pipeline> PipelineStorage::get_pipeline(const std::string& pipeline_name) const {
        if(const auto itr = pipelines.find(pipeline_name); itr != pipelines.end()) {
            return std::make_optional(itr->second);

        } else {
            return {};
        }
    }

    bool PipelineStorage::create_pipeline(const PipelineCreateInfo& create_info) {
        const auto rp_create = renderer.get_renderpass_metadata(create_info.pass);
        if(!rp_create) {
            NOVA_LOG(ERROR) << "Pipeline " << create_info.name << " wants to be rendered by renderpass " << create_info.pass
                            << ", but that renderpass doesn't have any metadata";
            return false;
        }

        Result<rhi::PipelineInterface*> pipeline_interface = create_pipeline_interface(create_info,
                                                                                rp_create->texture_outputs,
                                                                                rp_create->depth_texture);
        if(!pipeline_interface) {
            NOVA_LOG(ERROR) << "Pipeline " << create_info.name << " has an invalid interface: " << pipeline_interface.error.to_string();
            return false;
        }

        Result<PipelineReturn> pipeline_result = create_graphics_pipeline(*pipeline_interface, create_info);
        if(pipeline_result) {
            auto [pipeline, pipeline_metadata] = *pipeline_result;

            pipelines.emplace(create_info.name, pipeline);
            pipeline_metadatas.emplace(create_info.name, pipeline_metadata);

            return true;
        } else {
            NOVA_LOG(ERROR) << "Could not create pipeline " << create_info.name << ": " << pipeline_result.error.to_string();

            return false;
        }
    }

    Result<PipelineReturn> PipelineStorage::create_graphics_pipeline(rhi::PipelineInterface* pipeline_interface,
                                                                     const PipelineCreateInfo& pipeline_create_info) const {
        renderer::Pipeline pipeline;
        PipelineMetadata metadata;

        metadata.data = pipeline_create_info;

        Result<rhi::Pipeline*> rhi_pipeline = device->create_pipeline(pipeline_interface, pipeline_create_info, allocator);
        if(rhi_pipeline) {
            pipeline.pipeline = *rhi_pipeline;
            pipeline.pipeline_interface = pipeline_interface;

        } else {
            NovaError error = NovaError(format(fmt("Could not create pipeline {:s}"), pipeline_create_info.name.c_str()).c_str(),
                                        std::move(rhi_pipeline.error));
            return ntl::Result<PipelineReturn>(std::move(error));
        }

        return Result(PipelineReturn{pipeline, metadata});
    }

    Result<rhi::PipelineInterface*> PipelineStorage::create_pipeline_interface(
        const PipelineCreateInfo& pipeline_create_info,
        const std::pmr::vector<TextureAttachmentInfo>& color_attachments,
        const std::optional<TextureAttachmentInfo>& depth_texture) const {
        std::unordered_map<std::string, rhi::ResourceBindingDescription> bindings;
        bindings.reserve(32); // Probably a good estimate

        get_shader_module_descriptors(pipeline_create_info.vertex_shader.source, rhi::ShaderStage::Vertex, bindings);

        if(pipeline_create_info.tessellation_control_shader) {
            get_shader_module_descriptors(pipeline_create_info.tessellation_control_shader->source,
                                          rhi::ShaderStage::TessellationControl,
                                          bindings);
        }
        if(pipeline_create_info.tessellation_evaluation_shader) {
            get_shader_module_descriptors(pipeline_create_info.tessellation_evaluation_shader->source,
                                          rhi::ShaderStage::TessellationEvaluation,
                                          bindings);
        }
        if(pipeline_create_info.geometry_shader) {
            get_shader_module_descriptors(pipeline_create_info.geometry_shader->source, rhi::ShaderStage::Geometry, bindings);
        }
        if(pipeline_create_info.fragment_shader) {
            get_shader_module_descriptors(pipeline_create_info.fragment_shader->source, rhi::ShaderStage::Fragment, bindings);
        }

        const auto vertex_attributes = get_vertex_fields(pipeline_create_info.vertex_shader);

        return device->create_pipeline_interface(bindings, color_attachments, depth_texture, allocator);
    }

    rhi::VertexFieldFormat to_rhi_vertex_format(const SPIRType& spirv_type) {
        switch(spirv_type.basetype) {
            case SPIRType::UInt:
                return rhi::VertexFieldFormat::Uint;

            case SPIRType::Float: {
                switch(spirv_type.vecsize) {
                    case 2:
                        return rhi::VertexFieldFormat::Float2;

                    case 3:
                        return rhi::VertexFieldFormat::Float3;

                    case 4:
                        return rhi::VertexFieldFormat::Float4;

                    default:
                        NOVA_LOG(ERROR) << "Nova does not support float fields with " << spirv_type.vecsize << " vector elements";
                }
            };

            case SPIRType::Unknown:
                [[fallthrough]];
            case SPIRType::Void:
                [[fallthrough]];
            case SPIRType::Boolean:
                [[fallthrough]];
            case SPIRType::SByte:
                [[fallthrough]];
            case SPIRType::UByte:
                [[fallthrough]];
            case SPIRType::Short:
                [[fallthrough]];
            case SPIRType::UShort:
                [[fallthrough]];
            case SPIRType::Int:
                [[fallthrough]];
            case SPIRType::Int64:
                [[fallthrough]];
            case SPIRType::UInt64:
                [[fallthrough]];
            case SPIRType::AtomicCounter:
                [[fallthrough]];
            case SPIRType::Half:
                [[fallthrough]];
            case SPIRType::Double:
                [[fallthrough]];
            case SPIRType::Struct:
                [[fallthrough]];
            case SPIRType::Image:
                [[fallthrough]];
            case SPIRType::SampledImage:
                [[fallthrough]];
            case SPIRType::Sampler:
                [[fallthrough]];
            case SPIRType::AccelerationStructureNV:
                [[fallthrough]];
            case SPIRType::ControlPointArray:
                [[fallthrough]];
            case SPIRType::Char:
                [[fallthrough]];
            default:
                NOVA_LOG(ERROR) << "Nova does not support vertex fields of type " << spirv_type.basetype;
        }

        return {};
    }

    std::pmr::vector<rhi::VertexField> PipelineStorage::get_vertex_fields(const ShaderSource& vertex_shader) const {
        const CompilerGLSL shader_compiler(vertex_shader.source.data(), vertex_shader.source.size());

        const auto& shader_vertex_fields = shader_compiler.get_shader_resources().stage_inputs;

        std::pmr::vector<rhi::VertexField> vertex_fields(shader_vertex_fields.size());

        std::transform(shader_vertex_fields.begin(),
                       shader_vertex_fields.end(),
                       std::back_insert_iterator(vertex_fields),
                       [&](const auto& spirv_field) {
                           const auto& spirv_type = shader_compiler.get_type(spirv_field.base_type_id);
                           const auto format = to_rhi_vertex_format(spirv_type);

                           return rhi::VertexField{spirv_field.name, format};
                       });

        return vertex_fields;
    }

    void PipelineStorage::get_shader_module_descriptors(const std::pmr::vector<uint32_t>& spirv,
                                                        const rhi::ShaderStage shader_stage,
                                                        std::unordered_map<std::string, rhi::ResourceBindingDescription>& bindings) {
        const CompilerGLSL shader_compiler(spirv.data(), spirv.size());
        const ShaderResources resources = shader_compiler.get_shader_resources();

        for(const auto& resource : resources.separate_images) {
            NOVA_LOG(TRACE) << "Found a image named " << resource.name;
            add_resource_to_bindings(bindings, shader_stage, shader_compiler, resource, rhi::DescriptorType::Texture);
        }

        for(const auto& resource : resources.separate_samplers) {
            NOVA_LOG(TRACE) << "Found a sampler named " << resource.name;
            add_resource_to_bindings(bindings, shader_stage, shader_compiler, resource, rhi::DescriptorType::Sampler);
        }

        for(const auto& resource : resources.sampled_images) {
            NOVA_LOG(TRACE) << "Found a sampled image resource named " << resource.name;
            add_resource_to_bindings(bindings, shader_stage, shader_compiler, resource, rhi::DescriptorType::CombinedImageSampler);
        }

        for(const auto& resource : resources.uniform_buffers) {
            NOVA_LOG(TRACE) << "Found a UBO resource named " << resource.name;
            add_resource_to_bindings(bindings, shader_stage, shader_compiler, resource, rhi::DescriptorType::UniformBuffer);
        }

        for(const auto& resource : resources.storage_buffers) {
            NOVA_LOG(TRACE) << "Found a SSBO resource named " << resource.name;
            add_resource_to_bindings(bindings, shader_stage, shader_compiler, resource, rhi::DescriptorType::StorageBuffer);
        }
    }

    void PipelineStorage::add_resource_to_bindings(std::unordered_map<std::string, rhi::ResourceBindingDescription>& bindings,
                                                   const rhi::ShaderStage shader_stage,
                                                   const CompilerGLSL& shader_compiler,
                                                   const spirv_cross::Resource& resource,
                                                   const rhi::DescriptorType type) {
        const uint32_t set = shader_compiler.get_decoration(resource.id, spv::DecorationDescriptorSet);
        const uint32_t binding = shader_compiler.get_decoration(resource.id, spv::DecorationBinding);

        rhi::ResourceBindingDescription new_binding = {};
        new_binding.set = set;
        new_binding.binding = binding;
        new_binding.type = type;
        new_binding.count = 1;
        new_binding.stages = shader_stage;

        const SPIRType& type_information = shader_compiler.get_type(resource.type_id);
        if(!type_information.array.empty()) {
            new_binding.count = type_information.array[0];
            // All arrays are unbounded until I figure out how to use SPIRV-Cross to detect unbounded arrays
            new_binding.is_unbounded = true;
        }

        const std::string& resource_name = resource.name;

        if(const auto itr = bindings.find(resource_name); itr != bindings.end()) {
            // Existing binding. Is it the same as our binding?
            rhi::ResourceBindingDescription& existing_binding = itr->second;
            if(existing_binding != new_binding) {
                // They have two different bindings with the same name. Not allowed
                NOVA_LOG(ERROR) << "You have two different uniforms named " << resource.name
                                << " in different shader stages. This is not allowed. Use unique names";

            } else {
                // Same binding, probably at different stages - let's fix that
                existing_binding.stages |= shader_stage;
            }

        } else {
            // Totally new binding!
            bindings[resource_name] = new_binding;
        }
    }
} // namespace nova::renderer
<commit_msg>[pipelines] Actually save the vertex field information<commit_after>#include "nova_renderer/frontend/pipeline_storage.hpp"

#include "nova_renderer/nova_renderer.hpp"
#include "nova_renderer/rhi/render_engine.hpp"

#include "spirv_glsl.hpp"

using namespace spirv_cross;

namespace nova::renderer {
    using namespace mem;
    using namespace ntl;
    using namespace shaderpack;

    PipelineStorage::PipelineStorage(NovaRenderer& renderer, AllocatorHandle<>& allocator)
        : renderer(renderer), device(renderer.get_engine()), allocator(allocator) {}

    std::optional<renderer::Pipeline> PipelineStorage::get_pipeline(const std::string& pipeline_name) const {
        if(const auto itr = pipelines.find(pipeline_name); itr != pipelines.end()) {
            return std::make_optional(itr->second);

        } else {
            return {};
        }
    }

    bool PipelineStorage::create_pipeline(const PipelineCreateInfo& create_info) {
        const auto rp_create = renderer.get_renderpass_metadata(create_info.pass);
        if(!rp_create) {
            NOVA_LOG(ERROR) << "Pipeline " << create_info.name << " wants to be rendered by renderpass " << create_info.pass
                            << ", but that renderpass doesn't have any metadata";
            return false;
        }

        Result<rhi::PipelineInterface*> pipeline_interface = create_pipeline_interface(create_info,
                                                                                rp_create->texture_outputs,
                                                                                rp_create->depth_texture);
        if(!pipeline_interface) {
            NOVA_LOG(ERROR) << "Pipeline " << create_info.name << " has an invalid interface: " << pipeline_interface.error.to_string();
            return false;
        }

        Result<PipelineReturn> pipeline_result = create_graphics_pipeline(*pipeline_interface, create_info);
        if(pipeline_result) {
            auto [pipeline, pipeline_metadata] = *pipeline_result;

            pipelines.emplace(create_info.name, pipeline);
            pipeline_metadatas.emplace(create_info.name, pipeline_metadata);

            return true;
        } else {
            NOVA_LOG(ERROR) << "Could not create pipeline " << create_info.name << ": " << pipeline_result.error.to_string();

            return false;
        }
    }

    Result<PipelineReturn> PipelineStorage::create_graphics_pipeline(rhi::PipelineInterface* pipeline_interface,
                                                                     const PipelineCreateInfo& pipeline_create_info) const {
        renderer::Pipeline pipeline;
        PipelineMetadata metadata;

        metadata.data = pipeline_create_info;

        Result<rhi::Pipeline*> rhi_pipeline = device->create_pipeline(pipeline_interface, pipeline_create_info, allocator);
        if(rhi_pipeline) {
            pipeline.pipeline = *rhi_pipeline;
            pipeline.pipeline_interface = pipeline_interface;

        } else {
            NovaError error = NovaError(format(fmt("Could not create pipeline {:s}"), pipeline_create_info.name.c_str()).c_str(),
                                        std::move(rhi_pipeline.error));
            return ntl::Result<PipelineReturn>(std::move(error));
        }

        return Result(PipelineReturn{pipeline, metadata});
    }

    Result<rhi::PipelineInterface*> PipelineStorage::create_pipeline_interface(
        const PipelineCreateInfo& pipeline_create_info,
        const std::pmr::vector<TextureAttachmentInfo>& color_attachments,
        const std::optional<TextureAttachmentInfo>& depth_texture) const {
        std::unordered_map<std::string, rhi::ResourceBindingDescription> bindings;
        bindings.reserve(32); // Probably a good estimate

        get_shader_module_descriptors(pipeline_create_info.vertex_shader.source, rhi::ShaderStage::Vertex, bindings);

        if(pipeline_create_info.tessellation_control_shader) {
            get_shader_module_descriptors(pipeline_create_info.tessellation_control_shader->source,
                                          rhi::ShaderStage::TessellationControl,
                                          bindings);
        }
        if(pipeline_create_info.tessellation_evaluation_shader) {
            get_shader_module_descriptors(pipeline_create_info.tessellation_evaluation_shader->source,
                                          rhi::ShaderStage::TessellationEvaluation,
                                          bindings);
        }
        if(pipeline_create_info.geometry_shader) {
            get_shader_module_descriptors(pipeline_create_info.geometry_shader->source, rhi::ShaderStage::Geometry, bindings);
        }
        if(pipeline_create_info.fragment_shader) {
            get_shader_module_descriptors(pipeline_create_info.fragment_shader->source, rhi::ShaderStage::Fragment, bindings);
        }

        return device->create_pipeline_interface(bindings, color_attachments, depth_texture, allocator)
            .map([&](rhi::PipelineInterface* pipeline_interface) {
                pipeline_interface->vertex_fields = get_vertex_fields(pipeline_create_info.vertex_shader);
                return pipeline_interface;
            });
    }

    rhi::VertexFieldFormat to_rhi_vertex_format(const SPIRType& spirv_type) {
        switch(spirv_type.basetype) {
            case SPIRType::UInt:
                return rhi::VertexFieldFormat::Uint;

            case SPIRType::Float: {
                switch(spirv_type.vecsize) {
                    case 2:
                        return rhi::VertexFieldFormat::Float2;

                    case 3:
                        return rhi::VertexFieldFormat::Float3;

                    case 4:
                        return rhi::VertexFieldFormat::Float4;

                    default:
                        NOVA_LOG(ERROR) << "Nova does not support float fields with " << spirv_type.vecsize << " vector elements";
                }
            };

            case SPIRType::Unknown:
                [[fallthrough]];
            case SPIRType::Void:
                [[fallthrough]];
            case SPIRType::Boolean:
                [[fallthrough]];
            case SPIRType::SByte:
                [[fallthrough]];
            case SPIRType::UByte:
                [[fallthrough]];
            case SPIRType::Short:
                [[fallthrough]];
            case SPIRType::UShort:
                [[fallthrough]];
            case SPIRType::Int:
                [[fallthrough]];
            case SPIRType::Int64:
                [[fallthrough]];
            case SPIRType::UInt64:
                [[fallthrough]];
            case SPIRType::AtomicCounter:
                [[fallthrough]];
            case SPIRType::Half:
                [[fallthrough]];
            case SPIRType::Double:
                [[fallthrough]];
            case SPIRType::Struct:
                [[fallthrough]];
            case SPIRType::Image:
                [[fallthrough]];
            case SPIRType::SampledImage:
                [[fallthrough]];
            case SPIRType::Sampler:
                [[fallthrough]];
            case SPIRType::AccelerationStructureNV:
                [[fallthrough]];
            case SPIRType::ControlPointArray:
                [[fallthrough]];
            case SPIRType::Char:
                [[fallthrough]];
            default:
                NOVA_LOG(ERROR) << "Nova does not support vertex fields of type " << spirv_type.basetype;
        }

        return {};
    }

    std::pmr::vector<rhi::VertexField> PipelineStorage::get_vertex_fields(const ShaderSource& vertex_shader) const {
        const CompilerGLSL shader_compiler(vertex_shader.source.data(), vertex_shader.source.size());

        const auto& shader_vertex_fields = shader_compiler.get_shader_resources().stage_inputs;

        std::pmr::vector<rhi::VertexField> vertex_fields(shader_vertex_fields.size());

        std::transform(shader_vertex_fields.begin(),
                       shader_vertex_fields.end(),
                       std::back_insert_iterator(vertex_fields),
                       [&](const auto& spirv_field) {
                           const auto& spirv_type = shader_compiler.get_type(spirv_field.base_type_id);
                           const auto format = to_rhi_vertex_format(spirv_type);

                           return rhi::VertexField{spirv_field.name, format};
                       });

        return vertex_fields;
    }

    void PipelineStorage::get_shader_module_descriptors(const std::pmr::vector<uint32_t>& spirv,
                                                        const rhi::ShaderStage shader_stage,
                                                        std::unordered_map<std::string, rhi::ResourceBindingDescription>& bindings) {
        const CompilerGLSL shader_compiler(spirv.data(), spirv.size());
        const ShaderResources resources = shader_compiler.get_shader_resources();

        for(const auto& resource : resources.separate_images) {
            NOVA_LOG(TRACE) << "Found a image named " << resource.name;
            add_resource_to_bindings(bindings, shader_stage, shader_compiler, resource, rhi::DescriptorType::Texture);
        }

        for(const auto& resource : resources.separate_samplers) {
            NOVA_LOG(TRACE) << "Found a sampler named " << resource.name;
            add_resource_to_bindings(bindings, shader_stage, shader_compiler, resource, rhi::DescriptorType::Sampler);
        }

        for(const auto& resource : resources.sampled_images) {
            NOVA_LOG(TRACE) << "Found a sampled image resource named " << resource.name;
            add_resource_to_bindings(bindings, shader_stage, shader_compiler, resource, rhi::DescriptorType::CombinedImageSampler);
        }

        for(const auto& resource : resources.uniform_buffers) {
            NOVA_LOG(TRACE) << "Found a UBO resource named " << resource.name;
            add_resource_to_bindings(bindings, shader_stage, shader_compiler, resource, rhi::DescriptorType::UniformBuffer);
        }

        for(const auto& resource : resources.storage_buffers) {
            NOVA_LOG(TRACE) << "Found a SSBO resource named " << resource.name;
            add_resource_to_bindings(bindings, shader_stage, shader_compiler, resource, rhi::DescriptorType::StorageBuffer);
        }
    }

    void PipelineStorage::add_resource_to_bindings(std::unordered_map<std::string, rhi::ResourceBindingDescription>& bindings,
                                                   const rhi::ShaderStage shader_stage,
                                                   const CompilerGLSL& shader_compiler,
                                                   const spirv_cross::Resource& resource,
                                                   const rhi::DescriptorType type) {
        const uint32_t set = shader_compiler.get_decoration(resource.id, spv::DecorationDescriptorSet);
        const uint32_t binding = shader_compiler.get_decoration(resource.id, spv::DecorationBinding);

        rhi::ResourceBindingDescription new_binding = {};
        new_binding.set = set;
        new_binding.binding = binding;
        new_binding.type = type;
        new_binding.count = 1;
        new_binding.stages = shader_stage;

        const SPIRType& type_information = shader_compiler.get_type(resource.type_id);
        if(!type_information.array.empty()) {
            new_binding.count = type_information.array[0];
            // All arrays are unbounded until I figure out how to use SPIRV-Cross to detect unbounded arrays
            new_binding.is_unbounded = true;
        }

        const std::string& resource_name = resource.name;

        if(const auto itr = bindings.find(resource_name); itr != bindings.end()) {
            // Existing binding. Is it the same as our binding?
            rhi::ResourceBindingDescription& existing_binding = itr->second;
            if(existing_binding != new_binding) {
                // They have two different bindings with the same name. Not allowed
                NOVA_LOG(ERROR) << "You have two different uniforms named " << resource.name
                                << " in different shader stages. This is not allowed. Use unique names";

            } else {
                // Same binding, probably at different stages - let's fix that
                existing_binding.stages |= shader_stage;
            }

        } else {
            // Totally new binding!
            bindings[resource_name] = new_binding;
        }
    }
} // namespace nova::renderer
<|endoftext|>


<commit_before>///
/// C++14 Streams サンプル
///
/// g++ -std=c++14 -I "Stream.h のあるパス" sample.cpp

#include <iostream>
#include <string>
#include <sstream>

namespace patch
{
    template < typename T > std::string to_string( const T& n )
    {
        std::ostringstream stm ;
        stm << n ;
        return stm.str() ;
    }
}

#include "Stream.h"

using namespace stream;
using namespace stream::op;

#include <sstream>

template <typename T>
void Dump(T &seq)
{
  seq | print_to(std::cout);
  std::cout << std::endl;
}

int main()
{
  MakeStream::from({1, 3, 8, 4, 7})
      | map_([](auto x) { return x * 2; })
      | print_to(std::cout);

  std::cout << std::endl;

  auto seq = MakeStream::from({1, 3, 8, 4, 7})
             | map_([](auto x) { return x * x; });
  Dump(seq);

  auto str = MakeStream::from({1, 3, 8, 4, 7})
             | map_([](auto x) { return patch::to_string(x); })
             | reduce([](auto result, auto elem) { return result + "," + elem; });
  std::cout << str << std::endl;

  return 0;
}
<commit_msg>Adds Samples<commit_after>///
/// C++14 Streams サンプル
///
/// g++ -std=c++14 -I "Stream.h のあるパス" sample.cpp

#include <iostream>
#include <string>
#include <sstream>

namespace patch
{
    template < typename T > std::string to_string( const T& n )
    {
        std::ostringstream stm ;
        stm << n ;
        return stm.str() ;
    }
}

#include "Stream.h"

using namespace stream;
using namespace stream::op;

#include <sstream>

template <typename T>
void DumpStream(T &seq)
{
  seq | print_to(std::cout);
  std::cout << std::endl;
}

template <typename T>
void Dump(const T &val)
{
  std::cout << val << std::endl;
}

int main()
{
  MakeStream::from({1, 3, 8, 4, 7})
      | map_([](auto x) { return x * 2; })
      | print_to(std::cout);

  std::cout << std::endl;

  auto seq = MakeStream::from({1, 3, 8, 4, 7})
             | map_([](auto x) { return x * x; });
  DumpStream(seq);

  auto str = MakeStream::from({1, 3, 8, 4, 7})
             | map_([](auto x) { return patch::to_string(x); })
             | reduce([](auto result, auto elem) { return result + "," + elem; });
  Dump(str);

  // map
  auto mapseq =
      MakeStream::from({3, 2, 9, 6})
      | map_([](auto elem) { return elem * 2; });  // 6 4 18 12
  DumpStream(mapseq);

  // filter
  auto filterseq =
      MakeStream::from({3, 2, 9, 6})
      | filter([](auto elem) { return elem % 2 == 1; });  // 3 9
  DumpStream(filterseq);

  std::vector<int> src = {3, 2, 9, 6};
  Dump(MakeStream::from(src) | reduce([](auto sum, auto elem) { return sum + elem; })); // 20
  Dump(MakeStream::from(src) | reduce([](auto max, auto elem) { return (max < elem) ? elem : max; })); // 9
  Dump(MakeStream::from(src) | identity_reduce(0, [](auto count, auto elem) { return count + 1; })); // 4

  // {3, 2, 9, 6}
  // (3, 2) => 3 + 2
  //                 (5, 9) => 5 + 9
  //                                 (14, 6) => 14 + 6
  //                                                   20

  // count
  Dump(MakeStream::from({3, 2, 9, 6}) | count());  // 4

  // limit
  auto limitseq =
      MakeStream::from({3, 2, 9, 6}) | limit(2);
  DumpStream(limitseq);  // 3 2

  // max
  Dump(MakeStream::from({3, 2, 9, 6}) | max());  // 9
  // min
  Dump(MakeStream::from({3, 2, 9, 6}) | min());  // 2

  std::cout << std::boolalpha;
  Dump(MakeStream::from({3, 2, 9, 6}) | all([](auto elem) { return (elem % 3) == 0;}));  // false
  Dump(MakeStream::from({3, 2, 9, 6}) | any([](auto elem) { return (elem % 3) == 0;}));  // true

  // 四則演算
  auto divseq = MakeStream::from({3, 2, 9, 6}) / 3.0;
  DumpStream(divseq);  // 1 0.666667 3 2

  auto mulseq = 5 * MakeStream::from({3, 2, 9, 6});
  DumpStream(mulseq);  // 15 10 45 30

  auto modseq = MakeStream::from({3, 2, 9, 6}) % 3;
  DumpStream(modseq);  // 0 2 0 0

  auto dot_prod = MakeStream::from({3, 2, 9}) * MakeStream::from({1, 2, 3});
  DumpStream(dot_prod);  // 3 4 27

  // sort
  auto sortseq =
      MakeStream::from({3, 2, 9, 6}) | sort();
  DumpStream(sortseq);  // 2 3 6 9

  std::cout << std::endl;
  auto conseq =
      MakeStream::from({3, 2, 9, 6})
      | peek([](auto elem) { std::cout << "[in]  : " << elem << std::endl; })
      | filter([](auto elem) { return elem % 3 == 0; })
      | peek([](auto elem) { std::cout << " - filter : " << elem << std::endl; })
      | map_([](auto elem)  { return elem * 2; })
      | peek([](auto elem) { std::cout << " - map    : " << elem << std::endl; });

  for (auto &elem : conseq) {
    std::cout << "[out] : " << elem << std::endl;
  }

  std::cout << std::endl;
  auto conseq2 =
      MakeStream::from({3, 2, 9, 6})
      | peek([](auto elem) { std::cout << "[in]  : " << elem << std::endl; })
      | filter([](auto elem) { return elem % 3 == 0; })
      | peek([](auto elem) { std::cout << " - filter : " << elem << std::endl; })
      | sort()
      | peek([](auto elem) { std::cout << " - sort : " << elem << std::endl; })
      | map_([](auto elem)  { return elem * 2; })
      | peek([](auto elem) { std::cout << " - map    : " << elem << std::endl; });

  for (auto &elem : conseq2) {
    std::cout << "[out] : " << elem << std::endl;
  }

  return 0;
}
<|endoftext|>