<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "cdbsymbolpathlisteditor.h"

#include <coreplugin/icore.h>

#include <utils/pathchooser.h>
#include <utils/checkablemessagebox.h>

#include <symbolpathsdialog.h>

#include <QCheckBox>
#include <QDir>
#include <QDebug>
#include <QAction>
#include <QFormLayout>
#include <QLabel>

namespace Debugger {
namespace Internal {

CacheDirectoryDialog::CacheDirectoryDialog(QWidget *parent) :
    QDialog(parent), m_chooser(new Utils::PathChooser),
    m_buttonBox(new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel))
{
    setWindowTitle(tr("Select Local Cache Folder"));
    setModal(true);
    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);

    QFormLayout *formLayout = new QFormLayout;
    m_chooser->setExpectedKind(Utils::PathChooser::ExistingDirectory);
    m_chooser->setMinimumWidth(400);
    formLayout->addRow(tr("Path:"), m_chooser);

    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addLayout(formLayout);
    mainLayout->addWidget(m_buttonBox);

    setLayout(mainLayout);

    connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
    connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
}

void CacheDirectoryDialog::setPath(const QString &p)
{
    m_chooser->setPath(p);
}

QString CacheDirectoryDialog::path() const
{
    return m_chooser->path();
}

void CacheDirectoryDialog::accept()
{
    QString cache = path();
    // if cache is empty a default is used by the cdb
    if (cache.isEmpty()) {
        QDialog::accept();
        return;
    }
    // Ensure path exists
    QFileInfo fi(cache);
    // Folder exists - all happy.
    if (fi.isDir()) {
        QDialog::accept();
        return;
    }
    // Does a file of the same name exist?
    if (fi.exists()) {
        QMessageBox::warning(this, tr("Already Exists"),
                             tr("A file named '%1' already exists.").arg(cache));
        return;
    }
    // Create
    QDir root(QDir::root());
    if (!root.mkpath(cache)) {
        QMessageBox::warning(this, tr("Cannot Create"),
                             tr("The folder '%1' could not be created.").arg(cache));
        return;
    }
    QDialog::accept();
}

// ---------------- CdbSymbolPathListEditor

const char *CdbSymbolPathListEditor::symbolServerPrefixC = "srv*";
const char *CdbSymbolPathListEditor::symbolServerPostfixC = "http://msdl.microsoft.com/download/symbols";
const char *CdbSymbolPathListEditor::symbolCachePrefixC = "cache*";

CdbSymbolPathListEditor::CdbSymbolPathListEditor(QWidget *parent) :
    Utils::PathListEditor(parent)
{
    //! Add Microsoft Symbol server connection
    QAction *action = insertAction(lastAddActionIndex() + 1, tr("Symbol Server..."), this, SLOT(addSymbolServer()));
    action->setToolTip(tr("Adds the Microsoft symbol server providing symbols for operating system libraries."
                      "Requires specifying a local cache directory."));
    action = insertAction(lastAddActionIndex() + 1, tr("Symbol Cache..."), this, SLOT(addSymbolCache()));
    action->setToolTip(tr("Uses a directory to cache symbols used by the debugger."));
}

bool CdbSymbolPathListEditor::promptCacheDirectory(QWidget *parent, QString *cacheDirectory)
{
    CacheDirectoryDialog dialog(parent);
    dialog.setPath(QDir::tempPath() + QDir::separator() + QLatin1String("symbolcache"));
    if (dialog.exec() != QDialog::Accepted)
        return false;
    *cacheDirectory = dialog.path();
    return true;
}

void CdbSymbolPathListEditor::addSymbolServer()
{
    addSymbolPath(SymbolServerPath);
}

void CdbSymbolPathListEditor::addSymbolCache()
{
    addSymbolPath(SymbolCachePath);
}

void CdbSymbolPathListEditor::addSymbolPath(CdbSymbolPathListEditor::SymbolPathMode mode)
{
    QString cacheDir;
    if (promptCacheDirectory(this, &cacheDir))
        insertPathAtCursor(CdbSymbolPathListEditor::symbolPath(cacheDir, mode));
}

QString CdbSymbolPathListEditor::symbolPath(const QString &cacheDir,
                                            CdbSymbolPathListEditor::SymbolPathMode mode)
{
    if (mode == SymbolCachePath)
        return QLatin1String(symbolCachePrefixC) + QDir::toNativeSeparators(cacheDir);
    QString s = QLatin1String(symbolServerPrefixC);
    if (!cacheDir.isEmpty())
        s += QDir::toNativeSeparators(cacheDir) + QLatin1String("*");
    s += QLatin1String(symbolServerPostfixC);
    return s;
}

bool CdbSymbolPathListEditor::isSymbolServerPath(const QString &path, QString *cacheDir /*  = 0 */)
{
    if (!path.startsWith(QLatin1String(symbolServerPrefixC)) || !path.endsWith(QLatin1String(symbolServerPostfixC)))
        return false;
    if (cacheDir) {
        static const unsigned prefixLength = qstrlen(symbolServerPrefixC);
        static const unsigned postfixLength = qstrlen(symbolServerPostfixC);
        if (path.length() == prefixLength + postfixLength)
            return true;
        // Split apart symbol server post/prefixes
        *cacheDir = path.mid(prefixLength, path.size() - prefixLength - qstrlen(symbolServerPostfixC) + 1);
    }
    return true;
}

bool CdbSymbolPathListEditor::isSymbolCachePath(const QString &path, QString *cacheDir)
{
    if (!path.startsWith(QLatin1String(symbolCachePrefixC)))
        return false;
    if (cacheDir) {
        static const unsigned prefixLength = qstrlen(symbolCachePrefixC);
        // Split apart symbol cach prefixes
        *cacheDir = path.mid(prefixLength);
    }
    return true;
}

int CdbSymbolPathListEditor::indexOfSymbolPath(const QStringList &paths,
                                               CdbSymbolPathListEditor::SymbolPathMode mode,
                                               QString *cacheDir /*  = 0 */)
{
    const int count = paths.size();
    for (int i = 0; i < count; i++) {
        if (mode == SymbolServerPath
                ? CdbSymbolPathListEditor::isSymbolServerPath(paths.at(i), cacheDir)
                : CdbSymbolPathListEditor::isSymbolCachePath(paths.at(i), cacheDir)) {
                return i;
        }
    }
    return -1;
}

bool CdbSymbolPathListEditor::promptToAddSymbolPaths(const QString &settingsGroup,
                                                     QStringList *symbolPaths)
{
    const int indexOfSymbolServer =
            CdbSymbolPathListEditor::indexOfSymbolPath(*symbolPaths, SymbolServerPath);
    const int indexOfSymbolCache =
            CdbSymbolPathListEditor::indexOfSymbolPath(*symbolPaths, SymbolCachePath);

    if (!qgetenv("_NT_SYMBOL_PATH").isEmpty()
            || (indexOfSymbolServer != -1 && indexOfSymbolCache != -1))
        return false;

    const QString nagSymbolServerKey = settingsGroup + QLatin1String("/NoPromptSymbolCache");
    bool noFurtherNagging = Core::ICore::settings()->value(nagSymbolServerKey, false).toBool();
    if (noFurtherNagging)
        return false;

    QString path;
    if (indexOfSymbolServer != -1)
        path = symbolPaths->at(indexOfSymbolServer);
    if (path.isEmpty() && indexOfSymbolCache != -1)
        path = symbolPaths->at(indexOfSymbolCache);
    if (path.isEmpty())
        path = QDir::tempPath() + QDir::separator() + QLatin1String("symbolcache");

    bool useSymbolServer = true;
    bool useSymbolCache = true;
    bool addSymbolPaths = SymbolPathsDialog::useCommonSymbolPaths(useSymbolCache,
                                                                  useSymbolServer,
                                                                  path, noFurtherNagging);
    Core::ICore::settings()->setValue(nagSymbolServerKey, noFurtherNagging);
    if (!addSymbolPaths)
        return false;

    // remove old entries
    if (indexOfSymbolServer > indexOfSymbolCache) {
        symbolPaths->removeAt(indexOfSymbolServer);
        if (indexOfSymbolCache != -1)
            symbolPaths->removeAt(indexOfSymbolCache);
    } else if (indexOfSymbolCache > indexOfSymbolServer) {
        symbolPaths->removeAt(indexOfSymbolCache);
        if (indexOfSymbolServer != -1)
            symbolPaths->removeAt(indexOfSymbolServer);
    }

    if (useSymbolCache) {
        symbolPaths->push_back(CdbSymbolPathListEditor::symbolPath(path, SymbolCachePath));
        if (useSymbolServer)
            symbolPaths->push_back(CdbSymbolPathListEditor::symbolPath(QString(), SymbolServerPath));
        return true;
    } else if (useSymbolServer) {
        symbolPaths->push_back(CdbSymbolPathListEditor::symbolPath(path, SymbolServerPath));
        return true;
    }
    return false;
}

} // namespace Internal
} // namespace Debugger
<commit_msg>Fix signedness warning in cdbsymbolpathlisteditor.cpp.<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "cdbsymbolpathlisteditor.h"

#include <coreplugin/icore.h>

#include <utils/pathchooser.h>
#include <utils/checkablemessagebox.h>

#include <symbolpathsdialog.h>

#include <QCheckBox>
#include <QDir>
#include <QDebug>
#include <QAction>
#include <QFormLayout>
#include <QLabel>

namespace Debugger {
namespace Internal {

CacheDirectoryDialog::CacheDirectoryDialog(QWidget *parent) :
    QDialog(parent), m_chooser(new Utils::PathChooser),
    m_buttonBox(new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel))
{
    setWindowTitle(tr("Select Local Cache Folder"));
    setModal(true);
    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);

    QFormLayout *formLayout = new QFormLayout;
    m_chooser->setExpectedKind(Utils::PathChooser::ExistingDirectory);
    m_chooser->setMinimumWidth(400);
    formLayout->addRow(tr("Path:"), m_chooser);

    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addLayout(formLayout);
    mainLayout->addWidget(m_buttonBox);

    setLayout(mainLayout);

    connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
    connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
}

void CacheDirectoryDialog::setPath(const QString &p)
{
    m_chooser->setPath(p);
}

QString CacheDirectoryDialog::path() const
{
    return m_chooser->path();
}

void CacheDirectoryDialog::accept()
{
    QString cache = path();
    // if cache is empty a default is used by the cdb
    if (cache.isEmpty()) {
        QDialog::accept();
        return;
    }
    // Ensure path exists
    QFileInfo fi(cache);
    // Folder exists - all happy.
    if (fi.isDir()) {
        QDialog::accept();
        return;
    }
    // Does a file of the same name exist?
    if (fi.exists()) {
        QMessageBox::warning(this, tr("Already Exists"),
                             tr("A file named '%1' already exists.").arg(cache));
        return;
    }
    // Create
    QDir root(QDir::root());
    if (!root.mkpath(cache)) {
        QMessageBox::warning(this, tr("Cannot Create"),
                             tr("The folder '%1' could not be created.").arg(cache));
        return;
    }
    QDialog::accept();
}

// ---------------- CdbSymbolPathListEditor

const char *CdbSymbolPathListEditor::symbolServerPrefixC = "srv*";
const char *CdbSymbolPathListEditor::symbolServerPostfixC = "http://msdl.microsoft.com/download/symbols";
const char *CdbSymbolPathListEditor::symbolCachePrefixC = "cache*";

CdbSymbolPathListEditor::CdbSymbolPathListEditor(QWidget *parent) :
    Utils::PathListEditor(parent)
{
    //! Add Microsoft Symbol server connection
    QAction *action = insertAction(lastAddActionIndex() + 1, tr("Symbol Server..."), this, SLOT(addSymbolServer()));
    action->setToolTip(tr("Adds the Microsoft symbol server providing symbols for operating system libraries."
                      "Requires specifying a local cache directory."));
    action = insertAction(lastAddActionIndex() + 1, tr("Symbol Cache..."), this, SLOT(addSymbolCache()));
    action->setToolTip(tr("Uses a directory to cache symbols used by the debugger."));
}

bool CdbSymbolPathListEditor::promptCacheDirectory(QWidget *parent, QString *cacheDirectory)
{
    CacheDirectoryDialog dialog(parent);
    dialog.setPath(QDir::tempPath() + QDir::separator() + QLatin1String("symbolcache"));
    if (dialog.exec() != QDialog::Accepted)
        return false;
    *cacheDirectory = dialog.path();
    return true;
}

void CdbSymbolPathListEditor::addSymbolServer()
{
    addSymbolPath(SymbolServerPath);
}

void CdbSymbolPathListEditor::addSymbolCache()
{
    addSymbolPath(SymbolCachePath);
}

void CdbSymbolPathListEditor::addSymbolPath(CdbSymbolPathListEditor::SymbolPathMode mode)
{
    QString cacheDir;
    if (promptCacheDirectory(this, &cacheDir))
        insertPathAtCursor(CdbSymbolPathListEditor::symbolPath(cacheDir, mode));
}

QString CdbSymbolPathListEditor::symbolPath(const QString &cacheDir,
                                            CdbSymbolPathListEditor::SymbolPathMode mode)
{
    if (mode == SymbolCachePath)
        return QLatin1String(symbolCachePrefixC) + QDir::toNativeSeparators(cacheDir);
    QString s = QLatin1String(symbolServerPrefixC);
    if (!cacheDir.isEmpty())
        s += QDir::toNativeSeparators(cacheDir) + QLatin1String("*");
    s += QLatin1String(symbolServerPostfixC);
    return s;
}

bool CdbSymbolPathListEditor::isSymbolServerPath(const QString &path, QString *cacheDir /*  = 0 */)
{
    if (!path.startsWith(QLatin1String(symbolServerPrefixC)) || !path.endsWith(QLatin1String(symbolServerPostfixC)))
        return false;
    if (cacheDir) {
        static const unsigned prefixLength = qstrlen(symbolServerPrefixC);
        static const unsigned postfixLength = qstrlen(symbolServerPostfixC);
        if (path.length() == int(prefixLength + postfixLength))
            return true;
        // Split apart symbol server post/prefixes
        *cacheDir = path.mid(prefixLength, path.size() - prefixLength - qstrlen(symbolServerPostfixC) + 1);
    }
    return true;
}

bool CdbSymbolPathListEditor::isSymbolCachePath(const QString &path, QString *cacheDir)
{
    if (!path.startsWith(QLatin1String(symbolCachePrefixC)))
        return false;
    if (cacheDir) {
        static const unsigned prefixLength = qstrlen(symbolCachePrefixC);
        // Split apart symbol cach prefixes
        *cacheDir = path.mid(prefixLength);
    }
    return true;
}

int CdbSymbolPathListEditor::indexOfSymbolPath(const QStringList &paths,
                                               CdbSymbolPathListEditor::SymbolPathMode mode,
                                               QString *cacheDir /*  = 0 */)
{
    const int count = paths.size();
    for (int i = 0; i < count; i++) {
        if (mode == SymbolServerPath
                ? CdbSymbolPathListEditor::isSymbolServerPath(paths.at(i), cacheDir)
                : CdbSymbolPathListEditor::isSymbolCachePath(paths.at(i), cacheDir)) {
                return i;
        }
    }
    return -1;
}

bool CdbSymbolPathListEditor::promptToAddSymbolPaths(const QString &settingsGroup,
                                                     QStringList *symbolPaths)
{
    const int indexOfSymbolServer =
            CdbSymbolPathListEditor::indexOfSymbolPath(*symbolPaths, SymbolServerPath);
    const int indexOfSymbolCache =
            CdbSymbolPathListEditor::indexOfSymbolPath(*symbolPaths, SymbolCachePath);

    if (!qgetenv("_NT_SYMBOL_PATH").isEmpty()
            || (indexOfSymbolServer != -1 && indexOfSymbolCache != -1))
        return false;

    const QString nagSymbolServerKey = settingsGroup + QLatin1String("/NoPromptSymbolCache");
    bool noFurtherNagging = Core::ICore::settings()->value(nagSymbolServerKey, false).toBool();
    if (noFurtherNagging)
        return false;

    QString path;
    if (indexOfSymbolServer != -1)
        path = symbolPaths->at(indexOfSymbolServer);
    if (path.isEmpty() && indexOfSymbolCache != -1)
        path = symbolPaths->at(indexOfSymbolCache);
    if (path.isEmpty())
        path = QDir::tempPath() + QDir::separator() + QLatin1String("symbolcache");

    bool useSymbolServer = true;
    bool useSymbolCache = true;
    bool addSymbolPaths = SymbolPathsDialog::useCommonSymbolPaths(useSymbolCache,
                                                                  useSymbolServer,
                                                                  path, noFurtherNagging);
    Core::ICore::settings()->setValue(nagSymbolServerKey, noFurtherNagging);
    if (!addSymbolPaths)
        return false;

    // remove old entries
    if (indexOfSymbolServer > indexOfSymbolCache) {
        symbolPaths->removeAt(indexOfSymbolServer);
        if (indexOfSymbolCache != -1)
            symbolPaths->removeAt(indexOfSymbolCache);
    } else if (indexOfSymbolCache > indexOfSymbolServer) {
        symbolPaths->removeAt(indexOfSymbolCache);
        if (indexOfSymbolServer != -1)
            symbolPaths->removeAt(indexOfSymbolServer);
    }

    if (useSymbolCache) {
        symbolPaths->push_back(CdbSymbolPathListEditor::symbolPath(path, SymbolCachePath));
        if (useSymbolServer)
            symbolPaths->push_back(CdbSymbolPathListEditor::symbolPath(QString(), SymbolServerPath));
        return true;
    } else if (useSymbolServer) {
        symbolPaths->push_back(CdbSymbolPathListEditor::symbolPath(path, SymbolServerPath));
        return true;
    }
    return false;
}

} // namespace Internal
} // namespace Debugger
<|endoftext|>


<commit_before>#ifndef INCLUDE_AL_MATH_RANDOM_HPP
#define INCLUDE_AL_MATH_RANDOM_HPP

/*	Allocore --
	Multimedia / virtual environment application class library

	Copyright (C) 2009. AlloSphere Research Group, Media Arts & Technology, UCSB.
	Copyright (C) 2012. The Regents of the University of California.
	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 the University of California 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 HOLDER OR CONTRIBUTORS BE
	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
	POSSIBILITY OF SUCH DAMAGE.

	File description:
	Various flavors of pseudo-random number generators nad distributions

	File author(s):
	Lance Putnam, 2006, putnam.lance@gmail.com
*/

#include <time.h>							/* req'd for time() */
#include <cmath>
#include "allocore/types/al_Conversion.hpp"	/* req'd for int to float conversion */
#include "allocore/math/al_Constants.hpp"
#include "allocore/math/al_Generators.hpp"

namespace al {

/// Random number generation utilities
namespace rnd{

class LinCon;
class MulLinCon;
class Tausworthe;
template<class RNG> class Random;

/// Get a random seed in interval [0, 4294967296)
inline static uint32_t seed(){
	static gen::RMulAdd<uint32_t> seedGen(1664525, 1013904223, time(NULL));
	return seedGen();
}

/// Random distribution generator
template <class RNG=al::rnd::Tausworthe>
class Random{
public:

	Random(){}

	Random(uint32_t seed): mRNG(seed){}

	/// Set seed
	Random& seed(uint32_t v){ mRNG.seed(v); return *this; }

	/// Returns uniform random in [0, 1)
	float uniform(){ return al::uintToUnit<float>(mRNG()); }

	/// Returns uniform random in [0, hi)
	template <class T>
	T uniform(const T& hi){ return hi*uniform(); }

	/// Returns uniform random in [lo, hi)
	template <class T>
	T uniform(const T& hi, const T& lo){ return T((hi-lo)*uniform()) + lo; }

	/// Returns uniform random in [-1, 1)
	float uniformS(){ return al::uintToUnitS<float>(mRNG()); }

	/// Returns uniform random in [-lim, lim)
	template <class T>
	T uniformS(const T& lim){ return lim*uniformS(); }

	/// Returns point within a unit ball

	/// To get a random point on a sphere, simply normalize the result.
	/// \tparam		N		dimensions of ball
	/// @param[in]	point	an array of size N
	template <int N, class T>
	void ball(T * point);

	/// Returns random Gaussian
	float gaussian(){ float r; gaussian(r,r); return r; }

	/// Returns two random Gaussians
	template <class T>
	void gaussian(T& y1, T& y2);

	/// Returns true with a probability of p.
	bool prob(float p=0.5f){ return uniform() < p; }

	/// Randomly shuffles elements in array.
	template <class T>
	void shuffle(T * arr, uint32_t len);

protected:
	RNG mRNG;
};

/// Linear congruential uniform pseudo-random number generator.

///	This generator is very fast requiring only a single integer multiply and add per
/// iteration.  However, the least significant bits of the numbers are less
/// random; the most extreme case being the LSB which at best flips between 0 and 1.
/// This generator also exhibits poor dimensional distribution, therefore it is
/// best to have a different generator for each dimension, rather than sharing one.
class LinCon : public gen::RMulAdd<uint32_t>{
public:

	LinCon(){ val=al::rnd::seed(); type(0); }

	/// @param[in] seed	Initial seed value
	LinCon(uint32_t seed): gen::RMulAdd<uint32_t>(1,0,seed){ type(0); }

	/// Set seed
	void seed(uint32_t v){ (*this)=v; }

	/// Change the type of equation used.

	/// 0 - Knuth, Numerical Recipes in C\n
	/// 1 - BCPL
	void type(int v){
		switch(v){
		case 1:	mul = 2147001325; add =  715136305; break; // BCPL
		default:mul =    1664525; add = 1013904223;        // Knuth, Numerical Recipes in C
		}
	}
};

/// Multiplicative linear congruential uniform pseudo-random number generator.

///	This generator is a faster LCG requiring only a single integer multiply.
///
class MulLinCon : public gen::RMul<uint32_t>{
public:

	MulLinCon(){ val=al::rnd::seed(); type(0); }

	/// @param[in] seed	Initial seed value
	MulLinCon(uint32_t seed): gen::RMul<uint32_t>(1,seed){ type(0); }

	/// Set seed
	void seed(uint32_t v){ (*this)=v; }

	/// Change the type of equation used.

	/// 0 - Marsaglia, Super-Duper\n
	///
	void type(int v){
		switch(v){
		default: mul = 69069;	// Super-duper
		}
	}
};

/// Combined Tausworthe uniform pseudo-random number generator.

/// This generator produces highly random numbers, but is more expensive than
/// than a linear congruential RNG.
/// It is based on the paper
/// P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe Generators",
/// Mathematics of Computation, 65, 213 (1996), 203--213.
/// http://www.iro.umontreal.ca/~lecuyer/papers.html
class Tausworthe{
public:

	Tausworthe();

	/// @param[in] seed		Initial seed value
	Tausworthe(uint32_t seed);

	uint32_t operator()();				///< Generates uniform random unsigned integer in [0, 2^32).

	void seed(uint32_t v);				///< Set seed
	void seed(uint32_t v1, uint32_t v2, uint32_t v3, uint32_t v4); ///< Set seed

private:
	uint32_t s1, s2, s3, s4;
	void iterate();
};

/// Get global random number generator
inline Random<>& global(){ static Random<> r; return r; }

/// Returns point within a unit ball

/// To get a random point on a sphere, simply normalize the result.
/// \tparam		N		dimensions of ball
/// @param[in]	point	an array of size N
template <int N, class T>
inline void ball(T * point){ global().ball<N>(point); }

/// Returns random Gaussian
inline float gaussian(){ return global().gaussian(); }

/// Returns true with probability p
inline bool prob(float p=0.5){ return global().prob(p); }

/// Returns uniform random in [0, 1)
inline float uniform(){ return global().uniform(); }

/// Returns uniform random in [0, hi)
template <class T>
inline T uniform(const T& hi){ return global().uniform(hi); }

/// Returns uniform random in [lo, hi)
template <class T>
inline T uniform(const T& hi, const T& lo){ return global().uniform(hi,lo); }

/// Returns signed uniform random in (-1, 1)
inline float uniformS(){ return global().uniformS(); }

/// Returns signed uniform random in (-lim, lim)
template <class T>
inline T uniformS(const T& lim){ return global().uniformS(lim); }

// Implementation_______________________________________________________________

//---- Tausworthe

inline Tausworthe::Tausworthe(){ seed(al::rnd::seed()); }
inline Tausworthe::Tausworthe(uint32_t sd){ seed(sd); }

inline uint32_t Tausworthe::operator()(){
	iterate();
	return s1 ^ s2 ^ s3 ^ s4;
}

inline void Tausworthe::seed(uint32_t v){
	al::rnd::LinCon g(v);
	g();
	seed(g(), g(), g(), g());
}

inline void Tausworthe::seed(uint32_t v1, uint32_t v2, uint32_t v3, uint32_t v4){
	//printf("%u %u %u %u\n", v1, v2, v3, v4);
	v1 & 0xffffffe ? s1 = v1 : s1 = ~v1;
	v2 & 0xffffff8 ? s2 = v2 : s2 = ~v2;
	v3 & 0xffffff0 ? s3 = v3 : s3 = ~v3;
	v4 & 0xfffff80 ? s4 = v4 : s4 = ~v4;
}

inline void Tausworthe::iterate(){
	s1 = ((s1 & 0xfffffffe) << 18) ^ (((s1 <<  6) ^ s1) >> 13);
	s2 = ((s2 & 0xfffffff8) <<  2) ^ (((s2 <<  2) ^ s2) >> 27);
	s3 = ((s3 & 0xfffffff0) <<  7) ^ (((s3 << 13) ^ s3) >> 21);
	s4 = ((s4 & 0xffffff80) << 13) ^ (((s4 <<  3) ^ s4) >> 12);
}

template <class RNG>
template <int N, class T>
void Random<RNG>::ball(T * point){
	T w;
	do{
		w = T(0);
		for(int i=0; i<N; ++i){
			float v = uniformS();
			point[i] = v;
			w += v*v;
		}
	} while(w >= T(1)); // if on or outside unit ball, try again
}

// Box-Muller transform
//		Box, G. and Muller, M. A note on the generation of normal deviates.
//		Ann. Math. Slat. 28, (1958).
//
// http://en.wikipedia.org/wiki/Box–Muller_transform
template <class RNG>
template <class T> void Random<RNG>::gaussian(T& y1, T& y2){
	float x1, x2, w;

	// Search for point within unit circle using sample-reject.
	// This will pass with probability π/4 = ~0.785.
	do{
		x1 = uniformS();
		x2 = uniformS();
		w = x1 * x1 + x2 * x2;
	} while(w >= 1.f);

	// perform inverse Gaussian function mapping
	w = std::sqrt((-2.f * std::log(w)) / w);
	y1 = T(x1 * w);
	y2 = T(x2 * w);
}

// Fisher-Yates shuffle
template <class RNG>
template <class T>
void Random<RNG>::shuffle(T * arr, uint32_t len){
	for(uint32_t i=len-1; i>0; --i){
		uint32_t j = uniform(i+1);
		T t = arr[i];
		arr[i] = arr[j];
		arr[j] = t;
	}
}

} // al::rnd::
} // al::

#endif
<commit_msg>remove dependency on al_Generators.hpp<commit_after>#ifndef INCLUDE_AL_MATH_RANDOM_HPP
#define INCLUDE_AL_MATH_RANDOM_HPP

/*	Allocore --
	Multimedia / virtual environment application class library

	Copyright (C) 2009. AlloSphere Research Group, Media Arts & Technology, UCSB.
	Copyright (C) 2012. The Regents of the University of California.
	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 the University of California 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 HOLDER OR CONTRIBUTORS BE
	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
	POSSIBILITY OF SUCH DAMAGE.

	File description:
	Various flavors of pseudo-random number generators and distributions

	File author(s):
	Lance Putnam, 2006, putnam.lance@gmail.com
*/

#include <time.h>							/* req'd for time() */
#include <cmath>
#include "allocore/types/al_Conversion.hpp"	/* req'd for int to float conversion */
#include "allocore/math/al_Constants.hpp"

namespace al {

/// Random number generation utilities
namespace rnd{

class LinCon;
class MulLinCon;
class Tausworthe;
template<class RNG> class Random;

/// Get a random seed in interval [0, 4294967296)
inline static uint32_t seed(){
	static uint32_t val = time(NULL);
	return val = val*1664525UL + 1013904223UL;
}

/// Random distribution generator
template <class RNG=al::rnd::Tausworthe>
class Random{
public:

	/// Default constructor uses a randomly generated seed
	Random(){}

	/// @param[in] seed		Initial seed value
	Random(uint32_t seed): mRNG(seed){}

	/// Set seed
	Random& seed(uint32_t v){ mRNG.seed(v); return *this; }

	/// Returns uniform random in [0, 1)
	float uniform(){ return al::uintToUnit<float>(mRNG()); }

	/// Returns uniform random in [0, hi)
	template <class T>
	T uniform(const T& hi){ return hi*uniform(); }

	/// Returns uniform random in [lo, hi)
	template <class T>
	T uniform(const T& hi, const T& lo){ return T((hi-lo)*uniform()) + lo; }

	/// Returns uniform random in [-1, 1)
	float uniformS(){ return al::uintToUnitS<float>(mRNG()); }

	/// Returns uniform random in [-lim, lim)
	template <class T>
	T uniformS(const T& lim){ return lim*uniformS(); }

	/// Returns point within a unit ball

	/// To get a random point on a sphere, simply normalize the result.
	/// \tparam		N		dimensions of ball
	/// @param[in]	point	an array of size N
	template <int N, class T>
	void ball(T * point);

	/// Returns random Gaussian
	float gaussian(){ float r; gaussian(r,r); return r; }

	/// Returns two random Gaussians
	template <class T>
	void gaussian(T& y1, T& y2);

	/// Returns true with a probability of p.
	bool prob(float p=0.5f){ return uniform() < p; }

	/// Randomly shuffles elements in array.
	template <class T>
	void shuffle(T * arr, uint32_t len);

protected:
	RNG mRNG;
};

/// Linear congruential uniform pseudo-random number generator.

///	This generator is very fast requiring only a single integer multiply and add
/// per iteration.  However, the least significant bits of the numbers are less
/// random; the most extreme case being the LSB which at best flips between
/// 0 and 1. This generator also exhibits poor dimensional distribution,
/// therefore it is best to have a different generator for each dimension,
/// rather than sharing one.
class LinCon {
public:
	/// Default constructor uses a randomly generated seed
	LinCon(){
		seed(al::rnd::seed());
		type(0);
	}

	/// @param[in] seed		Initial seed value
	LinCon(uint32_t seed)
	:	mVal(seed)
	{	type(0); }

	/// Generate next uniform random integer in [0, 2^32)
	uint32_t operator()(){
		return mVal = mVal*mMul + mAdd;
	}

	/// Set seed
	void seed(uint32_t v){ mVal=v; }

	/// Change the type of equation used.

	/// 0 - Knuth, Numerical Recipes in C\n
	/// 1 - BCPL
	void type(int v){
		switch(v){
		default:
		case 0: mMul =    1664525; mAdd = 1013904223; break;
		case 1:	mMul = 2147001325; mAdd =  715136305; break;
		}
	}

private:
	uint32_t mVal;
	uint32_t mMul, mAdd;
};

/// Multiplicative linear congruential uniform pseudo-random number generator.

///	This generator is faster than LinCon requiring only a single integer
/// multiply per iteration. However, the downside is that it produces lower
/// quality (less "random") results than LinCon. Because of this, it is really
/// not appropriate for simulations, but due to its speed it is very useful for
/// synthesizing noise for audio and graphics.
class MulLinCon{
public:
	/// Default constructor uses a randomly generated seed
	MulLinCon(){
		seed(al::rnd::seed());
		type(0);
	}

	/// @param[in] seed	Initial seed value
	MulLinCon(uint32_t seed)
	:	mVal(seed)
	{	type(0); }

	/// Generate next uniform random integer in [0, 2^32)
	uint32_t operator()(){
		return mVal *= mMul;
	}

	/// Set seed
	void seed(uint32_t v){ mVal=v; }

	/// Change the type of equation used.

	/// 0 - Marsaglia, Super-Duper\n
	///
	void type(int v){
		switch(v){
		default:
		case 0: mMul = 69069; break;
		}
	}

private:
	uint32_t mVal;
	uint32_t mMul;
};

/// Combined Tausworthe uniform pseudo-random number generator.

/// This generator produces highly random numbers, but is more expensive than
/// than a linear congruential RNG.
/// It is based on the paper
/// P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe Generators",
/// Mathematics of Computation, 65, 213 (1996), 203--213.
/// http://www.iro.umontreal.ca/~lecuyer/papers.html
class Tausworthe{
public:

	/// Default constructor uses a randomly generated seed
	Tausworthe();

	/// @param[in] seed		Initial seed value
	Tausworthe(uint32_t seed);

	/// Generate next uniform random integer in [0, 2^32)
	uint32_t operator()();

	/// Set seed
	void seed(uint32_t v);

	/// Set seed
	void seed(uint32_t v1, uint32_t v2, uint32_t v3, uint32_t v4);

private:
	uint32_t s1, s2, s3, s4;
	void iterate();
};

/// Get global random number generator
inline Random<>& global(){ static Random<> r; return r; }

/// Returns point within a unit ball

/// To get a random point on a sphere, simply normalize the result.
/// \tparam		N		dimensions of ball
/// @param[in]	point	an array of size N
template <int N, class T>
inline void ball(T * point){ global().ball<N>(point); }

/// Returns random Gaussian
inline float gaussian(){ return global().gaussian(); }

/// Returns true with probability p
inline bool prob(float p=0.5){ return global().prob(p); }

/// Returns uniform random in [0, 1)
inline float uniform(){ return global().uniform(); }

/// Returns uniform random in [0, hi)
template <class T>
inline T uniform(const T& hi){ return global().uniform(hi); }

/// Returns uniform random in [lo, hi)
template <class T>
inline T uniform(const T& hi, const T& lo){ return global().uniform(hi,lo); }

/// Returns signed uniform random in (-1, 1)
inline float uniformS(){ return global().uniformS(); }

/// Returns signed uniform random in (-lim, lim)
template <class T>
inline T uniformS(const T& lim){ return global().uniformS(lim); }

// Implementation_______________________________________________________________

inline Tausworthe::Tausworthe(){ seed(al::rnd::seed()); }
inline Tausworthe::Tausworthe(uint32_t sd){ seed(sd); }

inline uint32_t Tausworthe::operator()(){
	iterate();
	return s1 ^ s2 ^ s3 ^ s4;
}

inline void Tausworthe::seed(uint32_t v){
	al::rnd::LinCon g(v);
	g();
	seed(g(), g(), g(), g());
}

inline void Tausworthe::seed(uint32_t v1, uint32_t v2, uint32_t v3, uint32_t v4){
	//printf("%u %u %u %u\n", v1, v2, v3, v4);
	v1 & 0xffffffe ? s1 = v1 : s1 = ~v1;
	v2 & 0xffffff8 ? s2 = v2 : s2 = ~v2;
	v3 & 0xffffff0 ? s3 = v3 : s3 = ~v3;
	v4 & 0xfffff80 ? s4 = v4 : s4 = ~v4;
}

inline void Tausworthe::iterate(){
	s1 = ((s1 & 0xfffffffe) << 18) ^ (((s1 <<  6) ^ s1) >> 13);
	s2 = ((s2 & 0xfffffff8) <<  2) ^ (((s2 <<  2) ^ s2) >> 27);
	s3 = ((s3 & 0xfffffff0) <<  7) ^ (((s3 << 13) ^ s3) >> 21);
	s4 = ((s4 & 0xffffff80) << 13) ^ (((s4 <<  3) ^ s4) >> 12);
}

template <class RNG>
template <int N, class T>
void Random<RNG>::ball(T * point){
	T w;
	do{
		w = T(0);
		for(int i=0; i<N; ++i){
			float v = uniformS();
			point[i] = v;
			w += v*v;
		}
	} while(w >= T(1)); // if on or outside unit ball, try again
}

// Box-Muller transform
//		Box, G. and Muller, M. A note on the generation of normal deviates.
//		Ann. Math. Slat. 28, (1958).
//
// http://en.wikipedia.org/wiki/Box–Muller_transform
template <class RNG>
template <class T> void Random<RNG>::gaussian(T& y1, T& y2){
	float x1, x2, w;

	// Search for point within unit circle using sample-reject.
	// This will pass with probability π/4 = ~0.785.
	do{
		x1 = uniformS();
		x2 = uniformS();
		w = x1 * x1 + x2 * x2;
	} while(w >= 1.f);

	// perform inverse Gaussian function mapping
	w = std::sqrt((-2.f * std::log(w)) / w);
	y1 = T(x1 * w);
	y2 = T(x2 * w);
}

// Fisher-Yates shuffle
template <class RNG>
template <class T>
void Random<RNG>::shuffle(T * arr, uint32_t len){
	for(uint32_t i=len-1; i>0; --i){
		uint32_t j = uniform(i+1);
		T t = arr[i];
		arr[i] = arr[j];
		arr[j] = t;
	}
}

} // al::rnd::
} // al::
#endif

<|endoftext|>


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

#include <unistd.h>

using namespace v8;

static Handle<Value> OsPipe(const Arguments& args)
{
    HandleScope scope;
    int pipefd[2];

    int ok = pipe(pipefd);

    Local<Array> arr = Array::New();

    arr->Set(0,Number::New(pipefd[0]));
    arr->Set(1,Number::New(pipefd[1]));

    return scope.Close(arr);
}

//=========================

void init(Handle<Object> exports)
{
  exports->Set(String::NewSymbol("ospipe"),      FunctionTemplate::New(OsPipe)->GetFunction());
}

NODE_MODULE(ospipe, init)
<commit_msg>error checking<commit_after>
#include <node.h>
#include <v8.h>

#include <unistd.h>

using namespace v8;

static Handle<Value> OsPipe(const Arguments& args)
{
    HandleScope scope;
    int pipefd[2];

    int ok = pipe(pipefd);

    if (ok == -1) {
	ThrowException(Exception::Error(String::New("pipe(2) returned error")));
	return scope.Close(Undefined());
    }

    Local<Array> arr = Array::New();

    arr->Set(0,Number::New(pipefd[0]));
    arr->Set(1,Number::New(pipefd[1]));

    return scope.Close(arr);
}

//=========================

void init(Handle<Object> exports)
{
  exports->Set(String::NewSymbol("ospipe"),      FunctionTemplate::New(OsPipe)->GetFunction());
}

NODE_MODULE(ospipe, init)
<|endoftext|>


<commit_before>#include "minimap.h"

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

#include "asdf_multiplat/main/asdf_multiplat.h"
#include "asdf_multiplat/data/gl_vertex_spec.h"
#include "asdf_multiplat/data/gl_state.h"

#include "ui/hex_map.h"

using namespace std;
using namespace glm;

namespace asdf
{
namespace hexmap
{
namespace ui
{
    gl_vertex_spec_<vertex_attrib::position2_t
                  , vertex_attrib::color_t> minimap_vertex_t::vertex_spec;

    minimap_t::minimap_t(ui::hex_map_t& _rendered_map)
    : rendered_map(_rendered_map)
    , map_data(_rendered_map.map_data)
    , render_target(1024, 1024)
    {
        render_target.texture.name = "minimap";
        render_target.init();
    }

    void minimap_t::rebuild()
    {
        scoped_render_target_t scoped(this->render_target);  //MSVC is making me put a this->  why?

        glClearColor(0,0,0,0);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // use glBlendFuncSeparate to allow the minimap FBO to have a transparent background
        // instead of black
        //glEnable(GL_BLEND);
        //glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

        //snapshot the camera
        auto& camera = rendered_map.camera;
        auto prev_camera = camera;

        //set camera such that the entire map will fit within the fbo when rendered
        auto grid_size = map_data.hex_grid.size_units();
        auto grid_size_d2 = grid_size / 2.0f;
        auto grid_bbox = map_data.hex_grid.bounding_box_units();

        camera.position = vec3(grid_bbox.lower + grid_size_d2, 0.0f);
        camera.viewport = viewport_for_size_aspect(grid_size, camera.aspect_ratio);

        //render just the terrain (and grid outline for now)
        using flags_e = hex_map_t::render_flags_e;
        uint32_t flags = flags_e::terrain | flags_e::grid_outline;
        rendered_map.render(flags_e(flags));

        camera = prev_camera;

        ASSERT(!CheckGLError(), "GL Error building minimap");
    }

    void minimap_t::render()
    {
        //render texture to quad
        auto const& quad = app.renderer->quad;
        auto& shader = app.renderer->screen_shader;

        GL_State->bind(shader);

        float minimap_scale_px = 400.0f;

        //shader->world_matrix = scale(translate(mat4(), vec3(0, 0, 0)), vec3(minimap_scale_px));
        shader->world_matrix = mat4();
        shader->view_matrix = mat4();
        shader->projection_matrix = glm::ortho<float>(-0.5f, 0.5f, -0.5f, 0.5f, -1.0f, 1.0f);

        float const& halfwidth = render_target.texture.halfwidth;
        float const& halfheight = render_target.texture.halfheight;

        //project such that each unit is one pixel
        // shader->projection_matrix = ortho<float>(-halfwidth, halfwidth,
        //                     -halfheight, halfheight,
        //                     -1000, 1000);

        shader->update_wvp_uniform();

        glBindTexture(GL_TEXTURE_2D, render_target.texture.texture_id);
        quad.render();

        //TODO: render box-outline representing current viewport
        //      ie: how much of the map is on screen based on zoom/pan
    }
}
}
}
<commit_msg>minimap no longer renders hex outlines<commit_after>#include "minimap.h"

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

#include "asdf_multiplat/main/asdf_multiplat.h"
#include "asdf_multiplat/data/gl_vertex_spec.h"
#include "asdf_multiplat/data/gl_state.h"

#include "ui/hex_map.h"

using namespace std;
using namespace glm;

namespace asdf
{
namespace hexmap
{
namespace ui
{
    gl_vertex_spec_<vertex_attrib::position2_t
                  , vertex_attrib::color_t> minimap_vertex_t::vertex_spec;

    minimap_t::minimap_t(ui::hex_map_t& _rendered_map)
    : rendered_map(_rendered_map)
    , map_data(_rendered_map.map_data)
    , render_target(1024, 1024)
    {
        render_target.texture.name = "minimap";
        render_target.init();
    }

    void minimap_t::rebuild()
    {
        scoped_render_target_t scoped(this->render_target);  //MSVC is making me put a this->  why?

        glClearColor(0,0,0,0);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // use glBlendFuncSeparate to allow the minimap FBO to have a transparent background
        // instead of black
        //glEnable(GL_BLEND);
        //glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

        //snapshot the camera
        auto& camera = rendered_map.camera;
        auto prev_camera = camera;

        //set camera such that the entire map will fit within the fbo when rendered
        auto grid_size = map_data.hex_grid.size_units();
        auto grid_size_d2 = grid_size / 2.0f;
        auto grid_bbox = map_data.hex_grid.bounding_box_units();

        camera.position = vec3(grid_bbox.lower + grid_size_d2, 0.0f);
        camera.viewport = viewport_for_size_aspect(grid_size, camera.aspect_ratio);

        //render just the terrain (and grid outline for now)
        using flags_e = hex_map_t::render_flags_e;
        uint32_t flags = flags_e::terrain;
        rendered_map.render(flags_e(flags));

        camera = prev_camera;

        ASSERT(!CheckGLError(), "GL Error building minimap");
    }

    void minimap_t::render()
    {
        //render texture to quad
        auto const& quad = app.renderer->quad;
        auto& shader = app.renderer->screen_shader;

        GL_State->bind(shader);

        float minimap_scale_px = 400.0f;

        //shader->world_matrix = scale(translate(mat4(), vec3(0, 0, 0)), vec3(minimap_scale_px));
        shader->world_matrix = mat4();
        shader->view_matrix = mat4();
        shader->projection_matrix = glm::ortho<float>(-0.5f, 0.5f, -0.5f, 0.5f, -1.0f, 1.0f);

        float const& halfwidth = render_target.texture.halfwidth;
        float const& halfheight = render_target.texture.halfheight;

        //project such that each unit is one pixel
        // shader->projection_matrix = ortho<float>(-halfwidth, halfwidth,
        //                     -halfheight, halfheight,
        //                     -1000, 1000);

        shader->update_wvp_uniform();

        glBindTexture(GL_TEXTURE_2D, render_target.texture.texture_id);
        quad.render();

        //TODO: render box-outline representing current viewport
        //      ie: how much of the map is on screen based on zoom/pan
    }
}
}
}
<|endoftext|>


<commit_before>#include <modules/graph2d/processors/plot2d.h>

#include <modules/plotting/utils/axisutils.h>
#include <modules/opengl/texture/textureutils.h>
#include <inviwo/core/util/raiiutils.h>
#include <inviwo/core/algorithm/boundingbox.h>
#include <inviwo/core/rendering/meshdrawerfactory.h>

#include <modules/opengl/texture/textureutils.h>
#include <modules/opengl/shader/shaderutils.h>
#include <modules/opengl/openglutils.h>

#include <modules/opengl/openglutils.h>
#include <inviwo/core/datastructures/coordinatetransformer.h>
#include <modules/opengl/texture/textureutils.h>

namespace inviwo {

// The Class Identifier has to be globally unique. Use a reverse DNS naming scheme
const ProcessorInfo Plot2dProcessor::processorInfo_{
    "org.inviwo.Plot2D",    // Class identifier
    "Plot2D",                 // Display name
    "Plotting",               // Category
    CodeState::Stable,        // Code state
    "Plotting",           // Tags
};

const ProcessorInfo Plot2dProcessor::getProcessorInfo() const { return processorInfo_; }

Plot2dProcessor::Plot2dProcessor()
    : Processor()
    , inport_("inport")
    , imageInport_("imageInport")
    , outport_("outport")
    , xAxis_("xAxis", "X Axis")
    , yAxis_("yAxis", "Y Axis")
	, position_("position", "Position", vec3(0), vec3(-25), vec3(25), vec3(0.01))
	, size_("size", "Size", vec2(3), vec2(0.01), vec2(25), vec2(0.01))
    , camera_("camera", "Camera")
	, camera2d_{ InviwoApplication::getPtr()->getCameraFactory()->create("OrthographicCamera") }
    , trackball_(&camera_)
	, axisRenderers_({ {xAxis_, yAxis_} })
	, xAxisSelection_("xAxisSelection", "X Axis")
	, yAxisSelection_("yAxisSelection", "Y Axis")
	, toggle3d_("toggle3d", "Render in 3D space")
	, lineMesh_( std::make_shared<BasicMesh>() )
	, meshDrawer_( std::unique_ptr<MeshDrawer>() )
	, shader_("linerenderer.vert", "linerenderer.geom", "linerenderer.frag", false)
    {

	shader_.onReload([this]() { invalidate(InvalidationLevel::InvalidResources); });

	MeshDrawerFactory* factory = InviwoApplication::getPtr()->getMeshDrawerFactory();
	meshDrawer_ = std::move(factory->create(lineMesh_.get()));

	// Setup ports
    imageInport_.setOptional(true);
    addPort(inport_);
    addPort(imageInport_);
    addPort(outport_);

	// Add properties
	addProperty(toggle3d_);
	addProperty(position_);
	addProperty(size_);
	addProperties(xAxisSelection_, yAxisSelection_);
	addProperties(xAxis_, yAxis_);
	addProperty(camera_);
	addProperty(trackball_);

	// Set up property default values
	toggle3d_.set(false);
	camera_.setVisible(false);
	camera_.setCollapsed(true);
	trackball_.setVisible(false);
	trackball_.setCollapsed(true);

	// Initialize the 2d camera.
	camera2d_->setLookFrom(vec3(0, 0, 100));
	camera2d_->setLookTo(vec3(0, 0, 0));
	camera2d_->setLookUp(vec3(0, 1, 0));
	camera2d_->setFarPlaneDist(200);
	camera2d_->setNearPlaneDist(1);

	// Axis default values.
	xAxis_.setCaption("x");
	yAxis_.setCaption("y");
	yAxis_.orientation_.setSelectedDisplayName("Vertical");

	for (auto axis : { &xAxis_, &yAxis_ }) {
		axis->captionSettings_.offset_.set(0.7f);
		axis->captionSettings_.position_.set(0.5f);
		axis->labelSettings_.offset_.set(0.7f);

		axis->majorTicks_.tickLength_.set(0.3f);
		axis->majorTicks_.tickWidth_.set(1.5f);
		axis->majorTicks_.style_.set(plot::TickStyle::Outside);
		axis->majorTicks_.setCurrentStateAsDefault();

		axis->minorTicks_.tickLength_.set(0.15f);
		axis->minorTicks_.tickWidth_.set(1.3f);
		axis->minorTicks_.style_.set(plot::TickStyle::Outside);
		axis->minorTicks_.setCurrentStateAsDefault();

		axis->setCollapsed(true);
		axis->orientation_.setVisible(false);
		axis->placement_.setVisible(false);
		axis->flipped_.setVisible(false);
	}

	// Event callbacks
	toggle3d_.onChange([this] {
		position_.setVisible(toggle3d_.get());
		size_.setVisible(toggle3d_.get());
		camera_.setVisible(toggle3d_.get());
		trackball_.setVisible(toggle3d_.get());
		updateDimensions();
	});
	size_.onChange([this] { updateDimensions(); });
	position_.onChange([this] { updateDimensions(); });

	inport_.onChange([this] {
		reloadDatasets();
		updatePlotData(); });
	xAxisSelection_.onChange([this] { updatePlotData(); });
	yAxisSelection_.onChange([this] { updatePlotData(); });
	xAxis_.range_.onChange([this] { updatePlotData(); });
	yAxis_.range_.onChange([this] { updatePlotData(); });
	xAxis_.useDataRange_.onChange([this] { updatePlotData(); });
	yAxis_.useDataRange_.onChange([this] { updatePlotData(); });
}

void Plot2dProcessor::initializeResources() {
	LogInfo("Initializing resources plot2d");

	shader_[ShaderType::Geometry]->addShaderDefine("ENABLE_ADJACENCY", "0");
	//shader_[ShaderType::Fragment]->addShaderDefine("ENABLE_ROUND_DEPTH_PROFILE");

	// See createLineStripMesh()
	shader_[ShaderType::Vertex]->addInDeclaration("in_" + toString(BufferType::PositionAttrib),
		static_cast<int>(BufferType::PositionAttrib),
		"vec3");
	shader_[ShaderType::Vertex]->addInDeclaration("in_" + toString(BufferType::ColorAttrib),
		static_cast<int>(BufferType::ColorAttrib),
		"vec4");
	shader_[ShaderType::Vertex]->addInDeclaration("in_" + toString(BufferType::TexcoordAttrib),
		static_cast<int>(BufferType::TexcoordAttrib),
		"vec2");
	shader_.build();
	shader_.activate();
	shader_.setUniform("antialiasing", 0.0f);
	shader_.setUniform("miterLimit", 1.0f);
	shader_.deactivate();
}

void Plot2dProcessor::process() {
	LogInfo("Process start");
	if (imageInport_.isReady()) {
		utilgl::activateTargetAndCopySource(outport_, imageInport_, ImageType::ColorDepth);
	}
	else {
		utilgl::activateAndClearTarget(outport_, ImageType::ColorDepth);
	}
	const size2_t dims = outport_.getDimensions();
	if (!toggle3d_.get() && oldDims_ != dims) updateDimensions();

	// Save a pointer to the camera that will be used
	Camera* activeCamera;
	if (toggle3d_.get())
		activeCamera = &camera_.get();
	else
		activeCamera = camera2d_.get();

	vec3 xVector(1, 0, 0);
	vec3 yVector(0, 1, 0);

	if (toggle3d_.get()) {
		// Set the normal of the graph plane to point towards camera.
		yVector = glm::normalize( camera_.getLookUp() );
		xVector = glm::normalize( glm::cross(yVector, camera_.getLookFrom() - camera_.getLookTo()) );
		lineMesh_->setBasis(Matrix<3U, float>(
			xVector * graphDims_[0],
			yVector * graphDims_[1],
			vec3(0, 0, 1)));
	}

	// Render lines.
	shader_.activate();
	utilgl::setShaderUniforms(shader_, *meshDrawer_->getMesh(), "geometry");
	utilgl::setShaderUniforms(shader_, *activeCamera, "camera");
	shader_.setUniform("screenDim", vec2(outport_.getDimensions()));
	shader_.setUniform("lineWidth", 2);
	meshDrawer_->draw();
	shader_.deactivate();

	// Render x and y axis
	axisRenderers_[0].render(activeCamera, dims, origin_, origin_ + xVector * graphDims_[0], yVector);
	axisRenderers_[1].render(activeCamera, dims, origin_, origin_ + yVector * graphDims_[1], xVector);

	utilgl::deactivateCurrentTarget();
}

void Plot2dProcessor::reloadDatasets() {
	if (!inport_.hasData()) {
		xAxisSelection_.clearOptions();
		yAxisSelection_.clearOptions();
		return;
	}
	const std::shared_ptr<const DataFrame> dataframe = inport_.getData();
	// Update column selection properties
	std::vector<OptionPropertyStringOption> options;
	for (const auto& column : *dataframe) {
		options.emplace_back(column->getHeader(), column->getHeader(), column->getHeader());
	}

	xAxisSelection_.replaceOptions(options);
	yAxisSelection_.replaceOptions(options);
	xAxisSelection_.setCurrentStateAsDefault();
	yAxisSelection_.setCurrentStateAsDefault();
}

void Plot2dProcessor::updateDimensions() {
	if (toggle3d_.get()) {
		origin_ = position_.get();
		graphDims_ = size_.get();
	}
	else {
		const size2_t dims = outport_.getDimensions();
		const float aspect = (float)dims[0] / (float)dims[1];
		const float scale = (double)dims[0] / 512;
		const float width = 50 * scale;
		const float height = width / aspect;
		const float padding = 50 * width / (double)dims[0];

		oldDims_ = dims;
		origin_ = vec3(-width / 2 + padding, -height / 2 + padding, 0);
		graphDims_ = vec2(width - 2 * padding, height - 2 * padding);
		// Update 2d camera to fit new dimensions.
		static_cast<OrthographicCamera*>(camera2d_.get())->setFrustum({ -width / 2.0f, +width / 2.0f, -width / 2.0f / aspect, +width / 2.0f / aspect });
	}
	// Scale and offset line mesh to align with axises.
	lineMesh_->setBasis(Matrix<3U, float>(graphDims_[0], 0, 0, 0, graphDims_[1], 0, 0, 0, 1));
	lineMesh_->setOffset(origin_);
}

void Plot2dProcessor::updatePlotData() {
	// Reset line mesh
	lineMesh_ = std::make_shared<BasicMesh>();
	meshDrawer_ = std::move(InviwoApplication::getPtr()->getMeshDrawerFactory()->create(lineMesh_.get()));

	if (!inport_.hasData()) return;

	const std::shared_ptr<const DataFrame> dataframe = inport_.getData();
	const std::shared_ptr<const Column> xCol = dataframe->getColumn(xAxisSelection_.getSelectedIndex());
	const std::shared_ptr<const Column> yCol = dataframe->getColumn(yAxisSelection_.getSelectedIndex());
	size_t nValues = xCol->getSize();

	if (xCol->getSize() < 2 || yCol->getSize() < 2 || yCol->getSize() != xCol->getSize()) return;

	// Set ranges for x and y axis
	if (xAxis_.getUseDataRange()) {
		dvec2 xrange(xCol->getAsDouble(0), xCol->getAsDouble(0));
		for (size_t i = 1; i < nValues; ++i) {
			double v = xCol->getAsDouble(i);
			if (v < xrange[0]) xrange[0] = v;
			if (v > xrange[1]) xrange[1] = v;
		}
		xAxis_.range_.set(xrange);
	}

	if (yAxis_.getUseDataRange()) {
		dvec2 yrange(yCol->getAsDouble(0), yCol->getAsDouble(0));
		for (size_t i = 1; i < nValues; ++i) {
			if (xCol->getAsDouble(i) < xAxis_.getRange()[0] || xCol->getAsDouble(i) > xAxis_.getRange()[1]) {
				continue;
			}
			double v = yCol->getAsDouble(i);
			if (v < yrange[0]) yrange[0] = v;
			if (v > yrange[1]) yrange[1] = v;
		}
		if (yrange[0] == yrange[1]) yrange[1] += 1;
		yAxis_.range_.set(yrange);
	}

	const double offsetX = -xAxis_.getRange()[0];
	const double offsetY = -yAxis_.getRange()[0];
	const double scaleX = 1.0f / (xAxis_.getRange()[1] - xAxis_.getRange()[0]);
	const double scaleY = 1.0f / (yAxis_.getRange()[1] - yAxis_.getRange()[0]);

	std::shared_ptr<IndexBufferRAM> indices = lineMesh_->addIndexBuffer(DrawType::Lines, ConnectivityType::None);
	vec4 color(0.5, 0.3, 0.8, 1);

	auto getPoint = [xCol, yCol, offsetX, offsetY, scaleX, scaleY](const size_t index) {
		return vec3((xCol->getAsDouble(index) + offsetX)*scaleX, (yCol->getAsDouble(index) + offsetY)*scaleY, 0);
	};
	//// Add point from dataframe to line mesh
	for (size_t i = 0; i < nValues - 1; ++i) {
		const vec3 p1((xCol->getAsDouble(i) + offsetX)*scaleX, (yCol->getAsDouble(i) + offsetY)*scaleY, 0);
		const vec3 p2((xCol->getAsDouble(i+1) + offsetX)*scaleX, (yCol->getAsDouble(i+1) + offsetY)*scaleY, 0);
		if (p1.x < 0 || p1.x > 1) continue;
		if (p2.x < 0 || p2.x > 1) continue;
		indices->add(lineMesh_->addVertex(p1, p1, p1, color));
		indices->add(lineMesh_->addVertex(p2, p2, p2, color));
	}

	// Update the dimensions of the mesh.
	updateDimensions();

}

} // namespace<commit_msg>added point interpolation inside bounds<commit_after>#include <modules/graph2d/processors/plot2d.h>

#include <modules/plotting/utils/axisutils.h>
#include <modules/opengl/texture/textureutils.h>
#include <inviwo/core/util/raiiutils.h>
#include <inviwo/core/algorithm/boundingbox.h>
#include <inviwo/core/rendering/meshdrawerfactory.h>

#include <modules/opengl/texture/textureutils.h>
#include <modules/opengl/shader/shaderutils.h>
#include <modules/opengl/openglutils.h>

#include <modules/opengl/openglutils.h>
#include <inviwo/core/datastructures/coordinatetransformer.h>
#include <modules/opengl/texture/textureutils.h>

namespace inviwo {

// The Class Identifier has to be globally unique. Use a reverse DNS naming scheme
const ProcessorInfo Plot2dProcessor::processorInfo_{
    "org.inviwo.Plot2D",    // Class identifier
    "Plot2D",                 // Display name
    "Plotting",               // Category
    CodeState::Stable,        // Code state
    "Plotting",           // Tags
};

const ProcessorInfo Plot2dProcessor::getProcessorInfo() const { return processorInfo_; }

Plot2dProcessor::Plot2dProcessor()
    : Processor()
    , inport_("inport")
    , imageInport_("imageInport")
    , outport_("outport")
    , xAxis_("xAxis", "X Axis")
    , yAxis_("yAxis", "Y Axis")
	, position_("position", "Position", vec3(0), vec3(-25), vec3(25), vec3(0.01))
	, size_("size", "Size", vec2(3), vec2(0.01), vec2(25), vec2(0.01))
    , camera_("camera", "Camera")
	, camera2d_{ InviwoApplication::getPtr()->getCameraFactory()->create("OrthographicCamera") }
    , trackball_(&camera_)
	, axisRenderers_({ {xAxis_, yAxis_} })
	, xAxisSelection_("xAxisSelection", "X Axis")
	, yAxisSelection_("yAxisSelection", "Y Axis")
	, toggle3d_("toggle3d", "Render in 3D space")
	, lineMesh_( std::make_shared<BasicMesh>() )
	, meshDrawer_( std::unique_ptr<MeshDrawer>() )
	, shader_("linerenderer.vert", "linerenderer.geom", "linerenderer.frag", false)
    {

	shader_.onReload([this]() { invalidate(InvalidationLevel::InvalidResources); });

	MeshDrawerFactory* factory = InviwoApplication::getPtr()->getMeshDrawerFactory();
	meshDrawer_ = std::move(factory->create(lineMesh_.get()));

	// Setup ports
    imageInport_.setOptional(true);
    addPort(inport_);
    addPort(imageInport_);
    addPort(outport_);

	// Add properties
	addProperty(toggle3d_);
	addProperty(position_);
	addProperty(size_);
	addProperties(xAxisSelection_, yAxisSelection_);
	addProperties(xAxis_, yAxis_);
	addProperty(camera_);
	addProperty(trackball_);

	// Set up property default values
	toggle3d_.set(false);
	camera_.setVisible(false);
	camera_.setCollapsed(true);
	trackball_.setVisible(false);
	trackball_.setCollapsed(true);

	// Initialize the 2d camera.
	camera2d_->setLookFrom(vec3(0, 0, 100));
	camera2d_->setLookTo(vec3(0, 0, 0));
	camera2d_->setLookUp(vec3(0, 1, 0));
	camera2d_->setFarPlaneDist(200);
	camera2d_->setNearPlaneDist(1);

	// Axis default values.
	xAxis_.setCaption("x");
	yAxis_.setCaption("y");
	yAxis_.orientation_.setSelectedDisplayName("Vertical");

	for (auto axis : { &xAxis_, &yAxis_ }) {
		axis->captionSettings_.offset_.set(0.7f);
		axis->captionSettings_.position_.set(0.5f);
		axis->labelSettings_.offset_.set(0.7f);

		axis->majorTicks_.tickLength_.set(0.3f);
		axis->majorTicks_.tickWidth_.set(1.5f);
		axis->majorTicks_.style_.set(plot::TickStyle::Outside);
		axis->majorTicks_.setCurrentStateAsDefault();

		axis->minorTicks_.tickLength_.set(0.15f);
		axis->minorTicks_.tickWidth_.set(1.3f);
		axis->minorTicks_.style_.set(plot::TickStyle::Outside);
		axis->minorTicks_.setCurrentStateAsDefault();

		axis->setCollapsed(true);
		//axis->orientation_.setVisible(false);
		//axis->placement_.setVisible(false);
		//axis->flipped_.setVisible(false);
	}

	// Event callbacks
	toggle3d_.onChange([this] {
		position_.setVisible(toggle3d_.get());
		size_.setVisible(toggle3d_.get());
		camera_.setVisible(toggle3d_.get());
		trackball_.setVisible(toggle3d_.get());
		updateDimensions();
	});
	size_.onChange([this] { updateDimensions(); });
	position_.onChange([this] { updateDimensions(); });

	inport_.onChange([this] {
		reloadDatasets();
		updatePlotData(); });
	xAxisSelection_.onChange([this] { updatePlotData(); });
	yAxisSelection_.onChange([this] { updatePlotData(); });
	xAxis_.range_.onChange([this] { updatePlotData(); });
	yAxis_.range_.onChange([this] { updatePlotData(); });
	xAxis_.useDataRange_.onChange([this] { updatePlotData(); });
	yAxis_.useDataRange_.onChange([this] { updatePlotData(); });
}

void Plot2dProcessor::initializeResources() {
	LogInfo("Initializing resources plot2d");

	shader_[ShaderType::Geometry]->addShaderDefine("ENABLE_ADJACENCY", "0");
	//shader_[ShaderType::Fragment]->addShaderDefine("ENABLE_ROUND_DEPTH_PROFILE");

	// See createLineStripMesh()
	shader_[ShaderType::Vertex]->addInDeclaration("in_" + toString(BufferType::PositionAttrib),
		static_cast<int>(BufferType::PositionAttrib),
		"vec3");
	shader_[ShaderType::Vertex]->addInDeclaration("in_" + toString(BufferType::ColorAttrib),
		static_cast<int>(BufferType::ColorAttrib),
		"vec4");
	shader_[ShaderType::Vertex]->addInDeclaration("in_" + toString(BufferType::TexcoordAttrib),
		static_cast<int>(BufferType::TexcoordAttrib),
		"vec2");
	shader_.build();
	shader_.activate();
	shader_.setUniform("antialiasing", 0.0f);
	shader_.setUniform("miterLimit", 1.0f);
	shader_.deactivate();
}

void Plot2dProcessor::process() {
	LogInfo("Process start");
	if (imageInport_.isReady()) {
		utilgl::activateTargetAndCopySource(outport_, imageInport_, ImageType::ColorDepth);
	}
	else {
		utilgl::activateAndClearTarget(outport_, ImageType::ColorDepth);
	}
	const size2_t dims = outport_.getDimensions();
	if (!toggle3d_.get() && oldDims_ != dims) updateDimensions();

	// Save a pointer to the camera that will be used
	Camera* activeCamera;
	if (toggle3d_.get())
		activeCamera = &camera_.get();
	else
		activeCamera = camera2d_.get();

	vec3 xVector(1, 0, 0);
	vec3 yVector(0, 1, 0);

	if (toggle3d_.get()) {
		// Set the normal of the graph plane to point towards camera.
		yVector = glm::normalize( camera_.getLookUp() );
		xVector = glm::normalize( glm::cross(yVector, camera_.getLookFrom() - camera_.getLookTo()) );
		lineMesh_->setBasis(Matrix<3U, float>(
			xVector * graphDims_[0],
			yVector * graphDims_[1],
			vec3(0, 0, 1)));
	}

	// Render lines.
	shader_.activate();
	utilgl::setShaderUniforms(shader_, *meshDrawer_->getMesh(), "geometry");
	utilgl::setShaderUniforms(shader_, *activeCamera, "camera");
	shader_.setUniform("screenDim", vec2(outport_.getDimensions()));
	shader_.setUniform("lineWidth", 2);
	meshDrawer_->draw();
	shader_.deactivate();

	// Render x and y axis
	axisRenderers_[0].render(activeCamera, dims, origin_, origin_ + xVector * graphDims_[0], yVector);
	axisRenderers_[1].render(activeCamera, dims, origin_, origin_ + yVector * graphDims_[1], xVector);

	utilgl::deactivateCurrentTarget();
}

void Plot2dProcessor::reloadDatasets() {
	if (!inport_.hasData()) {
		xAxisSelection_.clearOptions();
		yAxisSelection_.clearOptions();
		return;
	}
	const std::shared_ptr<const DataFrame> dataframe = inport_.getData();
	// Update column selection properties
	std::vector<OptionPropertyStringOption> options;
	for (const auto& column : *dataframe) {
		options.emplace_back(column->getHeader(), column->getHeader(), column->getHeader());
	}

	xAxisSelection_.replaceOptions(options);
	yAxisSelection_.replaceOptions(options);
	xAxisSelection_.setCurrentStateAsDefault();
	yAxisSelection_.setCurrentStateAsDefault();
}

void Plot2dProcessor::updateDimensions() {
	if (toggle3d_.get()) {
		origin_ = position_.get();
		graphDims_ = size_.get();
	}
	else {
		const size2_t dims = outport_.getDimensions();
		const float aspect = (float)dims[0] / (float)dims[1];
		const float scale = (double)dims[0] / 512;
		const float width = 50 * scale;
		const float height = width / aspect;
		const float padding = 50 * width / (double)dims[0];

		oldDims_ = dims;
		origin_ = vec3(-width / 2 + padding, -height / 2 + padding, 0);
		graphDims_ = vec2(width - 2 * padding, height - 2 * padding);
		// Update 2d camera to fit new dimensions.
		static_cast<OrthographicCamera*>(camera2d_.get())->setFrustum({ -width / 2.0f, +width / 2.0f, -width / 2.0f / aspect, +width / 2.0f / aspect });
	}
	// Scale and offset line mesh to align with axises.
	lineMesh_->setBasis(Matrix<3U, float>(graphDims_[0], 0, 0, 0, graphDims_[1], 0, 0, 0, 1));
	lineMesh_->setOffset(origin_);
}

void Plot2dProcessor::updatePlotData() {
	// Reset line mesh
	lineMesh_ = std::make_shared<BasicMesh>();
	meshDrawer_ = std::move(InviwoApplication::getPtr()->getMeshDrawerFactory()->create(lineMesh_.get()));

	if (!inport_.hasData()) return;

	const std::shared_ptr<const DataFrame> dataframe = inport_.getData();
	const std::shared_ptr<const Column> xCol = dataframe->getColumn(xAxisSelection_.getSelectedIndex());
	const std::shared_ptr<const Column> yCol = dataframe->getColumn(yAxisSelection_.getSelectedIndex());
	size_t nValues = xCol->getSize();

	if (xCol->getSize() < 2 || yCol->getSize() < 2 || yCol->getSize() != xCol->getSize()) return;

	// Set ranges for x and y axis
	if (xAxis_.getUseDataRange()) {
		dvec2 xrange(xCol->getAsDouble(0), xCol->getAsDouble(0));
		for (size_t i = 1; i < nValues; ++i) {
			double v = xCol->getAsDouble(i);
			if (v < xrange[0]) xrange[0] = v;
			if (v > xrange[1]) xrange[1] = v;
		}
		xAxis_.range_.set(xrange);
	}

	if (yAxis_.getUseDataRange()) {
		dvec2 yrange(yCol->getAsDouble(0), yCol->getAsDouble(0));
		for (size_t i = 1; i < nValues; ++i) {
			if (xCol->getAsDouble(i) < xAxis_.getRange()[0] || xCol->getAsDouble(i) > xAxis_.getRange()[1]) {
				continue;
			}
			double v = yCol->getAsDouble(i);
			if (v < yrange[0]) yrange[0] = v;
			if (v > yrange[1]) yrange[1] = v;
		}
		if (yrange[0] == yrange[1]) yrange[1] += 1;
		yAxis_.range_.set(yrange);
	}

	const double offsetX = -xAxis_.getRange()[0];
	const double offsetY = -yAxis_.getRange()[0];
	const double scaleX = 1.0f / (xAxis_.getRange()[1] - xAxis_.getRange()[0]);
	const double scaleY = 1.0f / (yAxis_.getRange()[1] - yAxis_.getRange()[0]);

	std::shared_ptr<IndexBufferRAM> indices = lineMesh_->addIndexBuffer(DrawType::Lines, ConnectivityType::None);
	vec4 color(0.5, 0.3, 0.8, 1);

	auto inBounds = [](const vec3 p) {
		// Is point inside the bounds of the graph
		return (p.x >= 0 && p.x <= 1 && p.y >= 0 && p.y <= 1);
	};

	auto boundIntersection = [this](const vec3& p1, const vec3& p2) {
		// Return the point on the edge of the bounding rectangle of the graph
		// given the line segment p1->p2. p1 is inside the bounds.
		const vec3 v = p2 - p1;
		float t = 1;
		for (const float n : { -p1.x / v.x, (1 - p1.x) / v.x, -p1.y / v.y, (1 - p1.y) / v.y })
			if (n > 0 && n < t) t = n;
		if (t == 1) t = 0;
		LogInfo("Interpolation: "
			<< p1 << "\n"
			<< p2 << "\n"
			<< v << "\n"
			<< t);
		return p1 + t * v;
	};

	// Add point from dataframe to line mesh
	for (size_t i = 0; i < nValues - 1; ++i) {
		// Get points from columns and scale them to be in the value range [0,1]
		vec3 p1((xCol->getAsDouble(i) + offsetX)*scaleX, (yCol->getAsDouble(i) + offsetY)*scaleY, 0);
		vec3 p2((xCol->getAsDouble(i + 1) + offsetX)*scaleX, (yCol->getAsDouble(i + 1) + offsetY)*scaleY, 0);

		if ( !inBounds(p1) && !inBounds(p2) ) continue;
		// If one of the points inside bounds, interpolate the edge intersection point
		else if ( !inBounds(p2) ) p2 = boundIntersection(p1, p2);
		else if ( !inBounds(p1) ) p1 = boundIntersection(p2, p1);

		indices->add(lineMesh_->addVertex(p1, p1, p1, color));
		indices->add(lineMesh_->addVertex(p2, p2, p2, color));
	}

	// Update the dimensions of the mesh.
	updateDimensions();

}

} // namespace<|endoftext|>


<commit_before>#include "gtest/gtest.h"
#include "xigua/xigua.hpp"

using namespace xig;

TEST(Standard_Library_Function, Fn) {
  enviroment env = get_global_enviroment();
  evaluate(env, parser::from_string("[= add [fn (a b) [+ a b]]]"));

  EXPECT_EQ(evaluate(env, parser::from_string("[add 1 1]")), make_integer(2));

  evaluate(env, parser::from_string("[= multi [fn (a) [1] (a b) [2]]]"));

  EXPECT_EQ(evaluate(env, parser::from_string("[multi 1]")), make_integer(1));
  EXPECT_EQ(evaluate(env, parser::from_string("[multi 1 1]")), make_integer(2));
}

TEST(Standard_Library_Function, ConditionalArgs) {
  enviroment env = get_global_enviroment();
  evaluate(env, parser::from_string("[= equal [fn ([== a b]) [a]]]"));

  EXPECT_EQ(evaluate(env, parser::from_string("[equal 1 1]")), make_integer(1));

  evaluate(env, parser::from_string("[= abso [fn ([< i 0]) [- 0 i] (i) [i]]]"));

  EXPECT_EQ(evaluate(env, parser::from_string("[abso 10]")), make_integer(10));
  EXPECT_EQ(evaluate(env, parser::from_string("[abso -11]")), make_integer(11));

  evaluate(env, parser::from_string("[= maxi [fn ([> x y]) [x] (x y) [y]]]"));

  EXPECT_EQ(evaluate(env, parser::from_string("[maxi 10 11]")),
            make_integer(11));
  EXPECT_EQ(evaluate(env, parser::from_string("[maxi 20 2]")),
            make_integer(20));
  EXPECT_EQ(evaluate(env, parser::from_string("[maxi 20 20]")),
            make_integer(20));

  evaluate(env, parser::from_string("[= a [fn ([> x [+ x y]]) [x]]]"));

  EXPECT_EQ(evaluate(env, parser::from_string("[a 4 -2]")), make_integer(4));
}

TEST(Standard_Library_Function, EqualArgs) {
  enviroment env = get_global_enviroment();
  evaluate(env, parser::from_string("[= isOne [fn (1) [true] (x) [false]]]"));

  EXPECT_EQ(evaluate(env, parser::from_string("[isOne 1]")),
            make_boolean(true));

  EXPECT_EQ(evaluate(env, parser::from_string("[isOne :pipe]")),
            make_boolean(false));

  EXPECT_EQ(evaluate(env, parser::from_string("[isOne [- 2 1]]")),
            make_boolean(true));

  evaluate(env,
           parser::from_string(
               "[= isPipe [fn (:pipe) [true] (:pipes) [true] (x) [false]]]"));

  EXPECT_EQ(evaluate(env, parser::from_string("[isPipe :pipe]")),
            make_boolean(true));

  EXPECT_EQ(evaluate(env, parser::from_string("[isPipe :pipes]")),
            make_boolean(true));

  EXPECT_EQ(evaluate(env, parser::from_string("[isPipe 22]")),
            make_boolean(false));
}

TEST(Standard_Library_Function, Recursion) {
  enviroment env = get_global_enviroment();

  evaluate(env, parser::from_string(
                    "[= fac1 [fn (0) [1] (n) [* n [fac1 [- n 1]]]]]"));
  evaluate(env, parser::from_string(
                    "[= fac2 [fn (0) [1] (n) [* [fac2 [- n 1]] n]]]"));

  EXPECT_EQ(evaluate(env, parser::from_string("[fac1 5]")), make_integer(120));
  EXPECT_EQ(evaluate(env, parser::from_string("[fac2 5]")), make_integer(120));
}
<commit_msg>test conditional args for exception<commit_after>#include "gtest/gtest.h"
#include "xigua/xigua.hpp"

using namespace xig;

TEST(Standard_Library_Function, Fn) {
  enviroment env = get_global_enviroment();
  evaluate(env, parser::from_string("[= add [fn (a b) [+ a b]]]"));

  EXPECT_EQ(evaluate(env, parser::from_string("[add 1 1]")), make_integer(2));

  evaluate(env, parser::from_string("[= multi [fn (a) [1] (a b) [2]]]"));

  EXPECT_EQ(evaluate(env, parser::from_string("[multi 1]")), make_integer(1));
  EXPECT_EQ(evaluate(env, parser::from_string("[multi 1 1]")), make_integer(2));
}

TEST(Standard_Library_Function, ConditionalArgs) {
  enviroment env = get_global_enviroment();
  evaluate(env, parser::from_string("[= equal [fn ([== a b]) [a]]]"));

  EXPECT_EQ(evaluate(env, parser::from_string("[equal 1 1]")), make_integer(1));

  evaluate(env, parser::from_string("[= abso [fn ([< i 0]) [- 0 i] (i) [i]]]"));

  EXPECT_EQ(evaluate(env, parser::from_string("[abso 10]")), make_integer(10));
  EXPECT_EQ(evaluate(env, parser::from_string("[abso -11]")), make_integer(11));

  evaluate(env, parser::from_string("[= maxi [fn ([> x y]) [x] (x y) [y]]]"));

  EXPECT_EQ(evaluate(env, parser::from_string("[maxi 10 11]")),
            make_integer(11));
  EXPECT_EQ(evaluate(env, parser::from_string("[maxi 20 2]")),
            make_integer(20));
  EXPECT_EQ(evaluate(env, parser::from_string("[maxi 20 20]")),
            make_integer(20));

  evaluate(env, parser::from_string("[= a [fn ([> x [+ x y]]) [x]]]"));

  EXPECT_EQ(evaluate(env, parser::from_string("[a 4 -2]")), make_integer(4));

  evaluate(env,
           parser::from_string(
               "[= first-two? [fn ([== [first b] 2]) [true] (c) [false]]]"));
  EXPECT_EQ(evaluate(env, parser::from_string("[first-two? 4]")),
            make_boolean(false));
  EXPECT_EQ(evaluate(env, parser::from_string("[first-two? (2 3 5)]")),
            make_boolean(true));
}

TEST(Standard_Library_Function, EqualArgs) {
  enviroment env = get_global_enviroment();
  evaluate(env, parser::from_string("[= isOne [fn (1) [true] (x) [false]]]"));

  EXPECT_EQ(evaluate(env, parser::from_string("[isOne 1]")),
            make_boolean(true));

  EXPECT_EQ(evaluate(env, parser::from_string("[isOne :pipe]")),
            make_boolean(false));

  EXPECT_EQ(evaluate(env, parser::from_string("[isOne [- 2 1]]")),
            make_boolean(true));

  evaluate(env,
           parser::from_string(
               "[= isPipe [fn (:pipe) [true] (:pipes) [true] (x) [false]]]"));

  EXPECT_EQ(evaluate(env, parser::from_string("[isPipe :pipe]")),
            make_boolean(true));

  EXPECT_EQ(evaluate(env, parser::from_string("[isPipe :pipes]")),
            make_boolean(true));

  EXPECT_EQ(evaluate(env, parser::from_string("[isPipe 22]")),
            make_boolean(false));
}

TEST(Standard_Library_Function, Recursion) {
  enviroment env = get_global_enviroment();

  evaluate(env, parser::from_string(
                    "[= fac1 [fn (0) [1] (n) [* n [fac1 [- n 1]]]]]"));
  evaluate(env, parser::from_string(
                    "[= fac2 [fn (0) [1] (n) [* [fac2 [- n 1]] n]]]"));

  EXPECT_EQ(evaluate(env, parser::from_string("[fac1 5]")), make_integer(120));
  EXPECT_EQ(evaluate(env, parser::from_string("[fac2 5]")), make_integer(120));
}
<|endoftext|>


<commit_before>/*
 * Copyright 2016 C. Brett Witherspoon
 */

#include <algorithm>
#include <cmath>
#include <complex>
#include <iostream>
#include <stdexcept>

#include <boost/preprocessor/stringize.hpp>
#include <boost/program_options.hpp>
#include <boost/compute/core.hpp>

namespace compute = boost::compute;
namespace po = boost::program_options;

namespace
{
const char *source = BOOST_PP_STRINGIZE(

    __kernel void window(__global float4 *x, uint n)
    {
        uint i = get_global_id(0);

        // Hamming
        float4 w;
        w.xy = 0.54 - 0.46 * cos(2*M_PI_F*(2*i)/(n-1));
        w.zw = 0.54 - 0.46 * cos(2*M_PI_F*(2*i+1)/(n-1));

        x[i] = w * x[i];
    }

    __kernel void twiddle(__global float2 *x, uint n)
    {
        uint k = get_global_id(0);

        // e^{-j 2 \pi k/n)
        x[k] = cos((float2)(2*M_PI_F*k/n, 2*M_PI_F*k/n + M_PI_F/2));
    }

    __kernel void reorder(__global float2 *x, uint s)
    {
        uint i = get_global_id(0);

        // Reverse bits
        uint j = i;
        j = (j & 0xFFFF0000) >> 16 | (j & 0x0000FFFF) << 16;
        j = (j & 0xFF00FF00) >> 8  | (j & 0x00FF00FF) << 8;
        j = (j & 0xF0F0F0F0) >> 4  | (j & 0x0F0F0F0F) << 4;
        j = (j & 0xCCCCCCCC) >> 2  | (j & 0x33333333) << 2;
        j = (j & 0xAAAAAAAA) >> 1  | (j & 0x55555555) << 1;

        // Adjust number of bits for log2(length)
        j >>= 32 - s;

        // Swap items
        if (i < j)
        {
            float2 tmp = x[i];
            x[i] = x[j];
            x[j] = tmp;
        }
    }

    __kernel void stage1(__global float4 *v)
    {
        uint i = get_global_id(0);

        // Bufferfly
        float2 tmp = v[i].xy;
        v[i].xy = v[i].xy + v[i].zw;
        v[i].zw = tmp - v[i].zw;
    }

    __kernel void stagex(__global float2 *v, uint n, uint m, uint s)
    {
        // Indices
        uint i = get_global_id(0);
        uint j = 1 << (s - 1);

        // Twiddle
        uint mask = ~(0xFFFFFFFF << (s - 1));
        uint k = (i & mask) * (1 << (m - s));
        float2 w = cos((float2)(2*M_PI_F*k/n, 2*M_PI_F*k/n + M_PI_F/2));

        // Complex multiply
        float2 z = (float2)(v[i+j].x*w.x - v[i+j].y*w.y, v[i+j].x*w.y + v[i+j].y*w.x);

        // Butterfly
        v[i+j] = v[i] - z;
        v[i]   = v[i] + z;
    }
);

bool ispowertwo(unsigned int x)
{
    return (x != 0) && !(x & (x - 1));
}

} // end anonymous namespace

int main(int argc, char *argv[])
{
    size_t length;

    po::options_description desc("Supported options");
    desc.add_options()
        ("help,h", "print help message")
        ("length,l", po::value<size_t>(&length)->default_value(8), "set FFT length");
    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);
    po::notify(vm);

    if (vm.count("help"))
    {
        std::cerr << desc << std::endl;
        return 1;
    }

    if (!ispowertwo(length))
    {
        std::cerr << "FFT Length must be a power of two" << std::endl;
        return 1;
    }

    const size_t stages = static_cast<size_t>(log2(length));

    compute::device device = compute::system::default_device();
    compute::context context(device);
    compute::command_queue queue(context, device, compute::command_queue::enable_profiling);

    // Print some device information
    std::cout << device.platform().name() << ": " << device.name() << std::endl;
    std::cout << "Global memory size: " << device.global_memory_size() << std::endl;
    std::cout << "Local memory size: " << device.local_memory_size() << std::endl;
    std::cout << "Compute units: " << device.compute_units() << std::endl;
    std::cout << "Preferred vector width: " <<device.preferred_vector_width<float>() << std::endl;

    // Build program and create kernels
    auto program = compute::program::create_with_source(source, context);

    compute::kernel window_kernel;
    compute::kernel reorder_kernel;
    compute::kernel stage1_kernel;
    compute::kernel stagex_kernel;

    try
    {
        program.build();
        window_kernel = program.create_kernel("window");
        reorder_kernel = program.create_kernel("reorder");
        stage1_kernel = program.create_kernel("stage1");
        stagex_kernel = program.create_kernel("stagex");
    }
    catch (compute::opencl_error &error)
    {
        std::cerr << error.what() << ": " << std::endl << program.build_log();
        return 1;
    }

    // Allocate kernel buffers
    auto flags = compute::buffer::read_write | compute::buffer::alloc_host_ptr;
    auto size = length * sizeof(std::complex<float>);
    compute::buffer buffer(context, size, flags);

    // Set kernel arguments
    window_kernel.set_arg(0, buffer);
    window_kernel.set_arg(1, length);

    reorder_kernel.set_arg(0, buffer);
    reorder_kernel.set_arg(1, stages);

    stage1_kernel.set_arg(0, buffer);

    stagex_kernel.set_arg(0, buffer);
    stagex_kernel.set_arg(1, length);
    stagex_kernel.set_arg(2, stages);
    stagex_kernel.set_arg(3, 1);

    // Initialize input buffer
    auto ptr = queue.enqueue_map_buffer(buffer,
                                        compute::command_queue::map_write, 0,
                                        buffer.size());
    auto buf = static_cast<std::complex<float>*>(ptr);
    //std::generate(buf, buf + length, []() { return std::complex<float>(1,1); });
    std::iota(buf, buf + length, 0);
    queue.enqueue_unmap_buffer(buffer, ptr).wait();

    compute::wait_list events;

    // Enqueue kernels
    //auto window_event = queue.enqueue_1d_range_kernel(window_kernel, 0, length/2, 0);
    events.insert(queue.enqueue_1d_range_kernel(reorder_kernel, 0, length, 0));
    events.insert(queue.enqueue_1d_range_kernel(stage1_kernel, 0, length/2, 0, events[0]));

    for (size_t i = 2; i <= stages; ++i)
    {
        stagex_kernel.set_arg(3, i);

        auto groups = length >> i;
        auto items = 1 << i;

        for (size_t g = 0; g < groups; ++g)
        {
            events.insert(queue.enqueue_1d_range_kernel(stagex_kernel, g * items, items / 2, 0, events[i-1]));
        }
    }

    // Print output buffer
    ptr = queue.enqueue_map_buffer(buffer,
                                   compute::command_queue::map_read, 0,
                                   buffer.size(), events);
    buf = static_cast<std::complex<float>*>(ptr);
    for (size_t i = 0; i < length; ++i) std::cout << buf[i] << std::endl;
    queue.enqueue_unmap_buffer(buffer, ptr).wait();

    return 0;
}
<commit_msg>opencl: misc improvements to FFT example<commit_after>/*
 * Copyright 2016 C. Brett Witherspoon
 */

#include <algorithm>
#include <chrono>
#include <cmath>
#include <complex>
#include <iostream>
#include <stdexcept>

#include <boost/preprocessor/stringize.hpp>
#include <boost/program_options.hpp>
#include <boost/compute/core.hpp>

namespace compute = boost::compute;
namespace po = boost::program_options;

namespace
{
const char *source = BOOST_PP_STRINGIZE(

    __kernel void window(__global float4 *x, uint n)
    {
        uint i = get_global_id(0);

        // Hamming
        float4 w;
        w.xy = 0.54 - 0.46 * cos(2*M_PI_F*(2*i)/(n-1));
        w.zw = 0.54 - 0.46 * cos(2*M_PI_F*(2*i+1)/(n-1));

        x[i] = w * x[i];
    }

    __kernel void twiddle(__global float2 *x, uint n)
    {
        uint k = get_global_id(0);

        // e^{-j 2 \pi k/n)
        x[k] = cos((float2)(2*M_PI_F*k/n, 2*M_PI_F*k/n + M_PI_F/2));
    }

    __kernel void reorder(__global float2 *x, uint s)
    {
        uint i = get_global_id(0);

        // Reverse bits
        uint j = i;
        j = (j & 0xFFFF0000) >> 16 | (j & 0x0000FFFF) << 16;
        j = (j & 0xFF00FF00) >> 8  | (j & 0x00FF00FF) << 8;
        j = (j & 0xF0F0F0F0) >> 4  | (j & 0x0F0F0F0F) << 4;
        j = (j & 0xCCCCCCCC) >> 2  | (j & 0x33333333) << 2;
        j = (j & 0xAAAAAAAA) >> 1  | (j & 0x55555555) << 1;

        // Adjust number of bits for log2(length)
        j >>= 32 - s;

        // Swap items
        if (i < j)
        {
            float2 tmp = x[i];
            x[i] = x[j];
            x[j] = tmp;
        }
    }

    __kernel void stage1(__global float4 *v)
    {
        uint i = get_global_id(0);

        // Bufferfly
        float2 tmp = v[i].xy;
        v[i].xy = v[i].xy + v[i].zw;
        v[i].zw = tmp - v[i].zw;
    }

    __kernel void stagex(__global float2 *v, uint n, uint m, uint s)
    {
        // Indices
        uint i = get_global_id(0);
        uint j = 1 << (s - 1);

        // Twiddle
        uint mask = ~(0xFFFFFFFF << (s - 1));
        uint k = (i & mask) * (1 << (m - s));
        float2 w = cos((float2)(2*M_PI_F*k/n, 2*M_PI_F*k/n + M_PI_F/2));

        // Complex multiply
        float2 z = (float2)(v[i+j].x*w.x - v[i+j].y*w.y, v[i+j].x*w.y + v[i+j].y*w.x);

        // Butterfly
        v[i+j] = v[i] - z;
        v[i]   = v[i] + z;
    }
);

bool ispowertwo(unsigned int x)
{
    return !(x == 0 || (x & (x - 1)));
}

} // end anonymous namespace

int main(int argc, char *argv[])
{
    size_t length;

    po::options_description desc("Supported options");
    desc.add_options()
        ("help,h", "print help message")
        ("length,l", po::value<size_t>(&length)->default_value(8), "set FFT length");
    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);
    po::notify(vm);

    if (vm.count("help"))
    {
        std::cerr << desc << std::endl;
        return 1;
    }

    if (!ispowertwo(length))
    {
        std::cerr << "FFT Length must be a power of two" << std::endl;
        return 1;
    }

    const size_t stages = static_cast<size_t>(log2(length));

    compute::device device = compute::system::default_device();
    compute::context context(device);
    compute::command_queue queue(context, device, compute::command_queue::enable_profiling);

    // Print some device information
    std::cout << device.platform().name() << ": " << device.name() << std::endl;
    std::cout << "Global memory size: " << device.global_memory_size() << std::endl;
    std::cout << "Local memory size: " << device.local_memory_size() << std::endl;
    std::cout << "Compute units: " << device.compute_units() << std::endl;
    std::cout << "Preferred vector width: " <<device.preferred_vector_width<float>() << std::endl;

    // Build program and create kernels
    auto program = compute::program::create_with_source(source, context);

    compute::kernel window_kernel;
    compute::kernel reorder_kernel;
    compute::kernel stage1_kernel;
    compute::kernel stagex_kernel;

    try
    {
        program.build();
        window_kernel = program.create_kernel("window");
        reorder_kernel = program.create_kernel("reorder");
        stage1_kernel = program.create_kernel("stage1");
        stagex_kernel = program.create_kernel("stagex");
    }
    catch (compute::opencl_error &error)
    {
        std::cerr << error.what() << ": " << std::endl << program.build_log();
        return 1;
    }

    // Allocate kernel buffers
    auto flags = compute::buffer::read_write | compute::buffer::alloc_host_ptr;
    auto size = length * sizeof(std::complex<float>);
    compute::buffer buffer(context, size, flags);

    // Set kernel arguments
    window_kernel.set_arg(0, buffer);
    window_kernel.set_arg(1, length);

    reorder_kernel.set_arg(0, buffer);
    reorder_kernel.set_arg(1, stages);

    stage1_kernel.set_arg(0, buffer);

    stagex_kernel.set_arg(0, buffer);
    stagex_kernel.set_arg(1, length);
    stagex_kernel.set_arg(2, stages);
    stagex_kernel.set_arg(3, 1);

    // Initialize input buffer
    auto ptr = queue.enqueue_map_buffer(buffer,
                                        compute::command_queue::map_write, 0,
                                        buffer.size());
    auto buf = static_cast<std::complex<float>*>(ptr);

    std::default_random_engine eng;
    std::normal_distribution<> dist{0, 1};
    auto rand = std::bind(dist, eng);
    std::generate(buf, buf + length, rand);

    std::cout << "Input: " << std::endl;
    for (size_t i = 0; i < length; ++i) std::cout << buf[i] << std::endl;

    queue.enqueue_unmap_buffer(buffer, ptr).wait();

    compute::wait_list events;

    // Enqueue kernels
    //auto window_event = queue.enqueue_1d_range_kernel(window_kernel, 0, length/2, 0);
    events.insert(queue.enqueue_1d_range_kernel(reorder_kernel, 0, length, 0));
    events.insert(queue.enqueue_1d_range_kernel(stage1_kernel, 0, length/2, 0, events[0]));

    for (size_t i = 2; i <= stages; ++i)
    {
        stagex_kernel.set_arg(3, i);

        auto groups = length >> i;
        auto items = 1 << i;

        for (size_t g = 0; g < groups; ++g)
        {
            events.insert(queue.enqueue_1d_range_kernel(stagex_kernel, g * items, items / 2, 0, events[i-1]));
        }
    }

    events.wait();

    // Print profiling information
    std::chrono::nanoseconds time{0};
    for (const auto &event : events)
    {
        time += event.duration<std::chrono::nanoseconds>();
    }
    std::cout << "Execute time: " << time.count() << " ns" << std::endl;

    // Print output buffer
    ptr = queue.enqueue_map_buffer(buffer,
                                   compute::command_queue::map_read, 0,
                                   buffer.size());
    buf = static_cast<std::complex<float>*>(ptr);

    std::cout << "Output: " << std::endl;
    for (size_t i = 0; i < length; ++i) std::cout << buf[i] << std::endl;

    queue.enqueue_unmap_buffer(buffer, ptr).wait();

    return 0;
}
<|endoftext|>


<commit_before>#include <algorithm>
#include <vector>
#include <cmath>
#include <iostream>
using namespace std;

typedef pair<double, double> point;

bool cw(const point &a, const point &b, const point &c) {
    return (b.first - a.first) * (c.second - a.second) - (b.second - a.second) * (c.first - a.first) < 0;
}

vector<point> convexHull(vector<point> p) {
    int n = p.size();
    if (n <= 1)
        return p;
    int k = 0;
    sort(p.begin(), p.end());
    vector<point> q(n * 2);
    for (int i = 0; i < n; q[k++] = p[i++])
        for (; k >= 2 && !cw(q[k - 2], q[k - 1], p[i]); --k)
            ;
    for (int i = n - 2, t = k; i >= 0; q[k++] = p[i--])
        for (; k > t && !cw(q[k - 2], q[k - 1], p[i]); --k)
            ;
    q.resize(k - 1 - (q[0] == q[1]));
    return q;
}

double area(const point &a, const point &b, const point &c) {
    return abs((b.first - a.first) * (c.second - a.second) - (b.second - a.second) * (c.first - a.first));
}

double dist(const point &a, const point &b) {
    return hypot(a.first - b.first, a.second - b.second);
}

double diameter(const vector<point> &p) {
    vector<point> h = convexHull(p);
    int m = h.size();
    if (m == 1)
        return 0;
    if (m == 2)
        return dist(h[0], h[1]);
    int k = 1;
    while (area(h[m - 1], h[0], h[(k + 1) % m]) > area(h[m - 1], h[0], h[k]))
        ++k;
    double res = 0;
    for (int i = 0, j = k; i <= k && j < m; i++) {
        res = max(res, dist(h[i], h[j]));
        while (j < m && area(h[i], h[(i + 1) % m], h[(j + 1) % m]) > area(h[i], h[(i + 1) % m], h[j])) {
            res = max(res, dist(h[i], h[(j + 1) % m]));
            ++j;
        }
    }
    return res;
}

int main() {
    vector<point> points(4);
    points[0] = point(0, 0);
    points[1] = point(3, 0);
    points[2] = point(0, 3);
    points[3] = point(1, 1);
    double d = diameter(points);
    cout << d << endl;
}
<commit_msg>update<commit_after>#include <bits/stdc++.h>

using namespace std;

typedef pair<double, double> point;

bool cw(const point &a, const point &b, const point &c) {
    return (b.first - a.first) * (c.second - a.second) - (b.second - a.second) * (c.first - a.first) < 0;
}

vector<point> convexHull(vector<point> p) {
    int n = p.size();
    if (n <= 1)
        return p;
    int k = 0;
    sort(p.begin(), p.end());
    vector<point> q(n * 2);
    for (int i = 0; i < n; q[k++] = p[i++])
        for (; k >= 2 && !cw(q[k - 2], q[k - 1], p[i]); --k)
            ;
    for (int i = n - 2, t = k; i >= 0; q[k++] = p[i--])
        for (; k > t && !cw(q[k - 2], q[k - 1], p[i]); --k)
            ;
    q.resize(k - 1 - (q[0] == q[1]));
    return q;
}

double area(const point &a, const point &b, const point &c) {
    return abs((b.first - a.first) * (c.second - a.second) - (b.second - a.second) * (c.first - a.first));
}

double dist(const point &a, const point &b) {
    return hypot(a.first - b.first, a.second - b.second);
}

double diameter(const vector<point> &p) {
    vector<point> h = convexHull(p);
    int m = h.size();
    if (m == 1)
        return 0;
    if (m == 2)
        return dist(h[0], h[1]);
    int k = 1;
    while (area(h[m - 1], h[0], h[(k + 1) % m]) > area(h[m - 1], h[0], h[k]))
        ++k;
    double res = 0;
    for (int i = 0, j = k; i <= k && j < m; i++) {
        res = max(res, dist(h[i], h[j]));
        while (j < m && area(h[i], h[(i + 1) % m], h[(j + 1) % m]) > area(h[i], h[(i + 1) % m], h[j])) {
            res = max(res, dist(h[i], h[(j + 1) % m]));
            ++j;
        }
    }
    return res;
}

// usage example
int main() {
    double d = diameter({{0, 0},
                         {3, 0},
                         {0, 3},
                         {1, 1}});
    cout << d << endl;
}
<|endoftext|>