<commit_before>// FIXME Lock for _read() method - listen()/_read() may start even when object is already reading. this has to be disabled!
// FIXME close() only if FIFO is open.
// FIXME maybe split close() to close() and _kill() - _kill() into destructor -- kill MUST NEVER throw/fail.
// FIXME catch references
// LICENSE/*{{{*/
/*
  sxc - Simple Xmpp Client
  Copyright (C) 2008 Dennis Felsing, Andreas Waidler

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/*}}}*/

/* $Id$ */

#ifndef FILE_INPUTBASE_HXX
#define FILE_INPUTBASE_HXX

// INCLUDES/*{{{*/

#include <string>
#include <fstream>
#include <pthread.h>

/*}}}*/

namespace File
{
    /**
     * @author Andreas Waidler
     * @brief Abstract Base Class handling input (FIFOs).
     *
     * Handles creation and checking of, listening (non-blocking) on and reading
     * (blocking) off FIFOs.
     * Contains pure virtual methods that will define the location of the FIFO
     * and how the input is handled.
     */
    class InputBase
    {
        public:
            // InputBase();/*{{{*/

            /// Constructor, initializes private variables with default values.
            InputBase();

/*}}}*/
            // virtual ~InputBase();/*{{{*/

            /**
             * @brief Destructor, frees resources and cleans up.
             *
             * Takes care of a clean termination of the thread if running.
             * Closes the FIFO if open.
             */
            virtual ~InputBase();

/*}}}*/
            // void initialize();/*{{{*/

            /**
             * @brief Initializes the object.
             *
             * Calls @ref _createPath() to set @ref _path. Tries to create
             * the FIFO or checks its permissions by calling @ref _tryCreate()
             * or @ref validateFile().
             *
             * @note This method has to be called before any other method can
             *       be used! You may want to call it in the constructor of
             *       the childs.
             *
             * @warning Do not override this method!
             */
            void initialize();

/*}}}*/
            // void listen(bool blocking = false);/*{{{*/

            /**
             * @brief Initiates listening on the FIFO.
             *
             * If @a blocking is set to @c true this method will read blocking,
             * i.e. it will finish when @ref close() is run. Per default, @a
             * blocking is @c false.
             *
             * This method creates a thread that executes @ref _listen()
             * which will run in the background. If @a blocking is true @c
             * pthread_join() is called which causes this method to wait until
             * the thread terminates.
             *
             * @warning Do not override this method!
             *
             * @param blocking Specifies whether this method should listen
             * blocking or non-blocking.
             */
            void listen(bool blocking = false);

/*}}}*/

        protected:
            // void create();/*{{{*/

            /** Creates the FIFO.
             *
             * @exception Exception::FileInputException When the file could not
             *            be created. @c Exception::Type is the result of
             *            @ref Exception::errnoToType().
             */
            void create();

/*}}}*/
            // void open(bool createIfMissing = false);/*{{{*/

            /**
             * @brief Opens the FIFO.
             *
             * Wraps around @ref validateFile(), @ref create() and @c
             * fstream::open().
             *
             * If @a createIfMissing is set to @c true, this method calls
             * @ref create() instead of throwing an @ref FileInputException with
             * the @ref Type of @ref Exception::FileMissing.
             *
             * @param createIfMissing Whether FIFO should be created or not.
             * @exception FileInputException If @ref validateFile() fails.
             * @see InputBase::validateFile()
             * @see InputBase::create()
             */
            void open(bool createIfMissing = false);

/*}}}*/
            // void close();/*{{{*/

            /**
             * @brief Closes the FIFO.
             *
             * Closes the FIFO and cancles the thread, if running.
             *
             * @warning Do not override this method!
             */
            void close();

/*}}}*/
            // void validateFile();/*{{{*/

            /**
             * @brief Checks the FIFO for validity and throws an exception if
             *        something is not like expected.
             *
             * The FIFOs owner-uid has to be the one who runs this program.
             * Additionally, the FIFO must @b not be readable or writable for
             * other users. (chmod 600).
             *
             * Normally, the FIFO should exist with the right permissions,
             * except sxc has not been run before (in this directory) or someone
             * tampered with the directory structure.
             *
             * @exception Exception::FileInputException When file is invalid.
             */

            void validateFile();

/*}}}*/

        private:
            /// The path including file name where the FIFO is located.
            std::string _path;
            /// The FIFO from which will be read.
            std::fstream _fifo;
            /// Indicates whether @ref _fifo is valid.
            bool _isFifoValid;
            /// The thread running @ref _listen
            pthread_t _thread;
            /// Indicates whether @ref _thread is running.
            bool _isThreadRunning;
            /// Indicates whether @ref _read() or @ref listen() are active.
            bool _isLocked;
            // virtual const std::string &_createPath() const = 0;/*{{{*/

            /**
             * @brief Returns the path and file name of the FIFO.
             *
             * Called by @ref initialize() which stores the result in @ref _path
             * which is used throughout the class in the other methods.
             *
             * @note Pure virtual.
             *
             * @return Path and file name where the FIFO should be placed.
             */
            virtual const std::string &_createPath() const = 0;

/*}}}*/
            // virtual void _handleInput(std::string input) = 0;/*{{{*/

            /**
             * @brief Handles input that has been written into the FIFO.
             *
             * @note Pure virtual.
             *
             * @param input Something that has been written into the FIFO.
             */
            virtual void _handleInput(std::string input) = 0;

/*}}}*/
            // void _read();/*{{{*/

            /**
             * @brief Reads the FIFO blocking until the other end is closed.
             *
             * Input is handled by calling @ref _handleInput().
             *
             * @warning Do not override this method!
             */
            void _read();

/*}}}*/
            // static void *_listen(void *fifo);/*{{{*/

            /**
             * @brief Listens blocking on the passed FIFO.
             *
             * Runs an infinite loop on @ref _read() of the object @a fifo.
             *
             * @warning Should only be called by a pthread created in @ref
             *          listen. This method will never stop by itsself, thus
             *          its thread has to be canceled.
             * @warning The parameter @a fifo should not be anything other than
             *          a this-pointer.
             *
             * @param fifo Pointer to object of class InputBase.
             * @return NULL
             * @see InputBase::listen()
             * @see InputBase::close()
             * @see InputBase::_read()
             */
            static void *_listen(void *fifo);

/*}}}*/
    };
}

#endif // FILE_INPUTBASE_HXX

// Use no tabs at all; four spaces indentation; max. eighty chars per line.
// vim: et ts=4 sw=4 tw=80 fo+=c fdm=marker
<commit_msg>Removed obsolete FIXME markers<commit_after>// FIXME catch references
// LICENSE/*{{{*/
/*
  sxc - Simple Xmpp Client
  Copyright (C) 2008 Dennis Felsing, Andreas Waidler

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/*}}}*/

/* $Id$ */

#ifndef FILE_INPUTBASE_HXX
#define FILE_INPUTBASE_HXX

// INCLUDES/*{{{*/

#include <string>
#include <fstream>
#include <pthread.h>

/*}}}*/

namespace File
{
    /**
     * @author Andreas Waidler
     * @brief Abstract Base Class handling input (FIFOs).
     *
     * Handles creation and checking of, listening (non-blocking) on and reading
     * (blocking) off FIFOs.
     * Contains pure virtual methods that will define the location of the FIFO
     * and how the input is handled.
     */
    class InputBase
    {
        public:
            // InputBase();/*{{{*/

            /// Constructor, initializes private variables with default values.
            InputBase();

/*}}}*/
            // virtual ~InputBase();/*{{{*/

            /**
             * @brief Destructor, frees resources and cleans up.
             *
             * Takes care of a clean termination of the thread if running.
             * Closes the FIFO if open.
             */
            virtual ~InputBase();

/*}}}*/
            // void initialize();/*{{{*/

            /**
             * @brief Initializes the object.
             *
             * Calls @ref _createPath() to set @ref _path. Tries to create
             * the FIFO or checks its permissions by calling @ref _tryCreate()
             * or @ref validateFile().
             *
             * @note This method has to be called before any other method can
             *       be used! You may want to call it in the constructor of
             *       the childs.
             *
             * @warning Do not override this method!
             */
            void initialize();

/*}}}*/
            // void listen(bool blocking = false);/*{{{*/

            /**
             * @brief Initiates listening on the FIFO.
             *
             * If @a blocking is set to @c true this method will read blocking,
             * i.e. it will finish when @ref close() is run. Per default, @a
             * blocking is @c false.
             *
             * This method creates a thread that executes @ref _listen()
             * which will run in the background. If @a blocking is true @c
             * pthread_join() is called which causes this method to wait until
             * the thread terminates.
             *
             * @warning Do not override this method!
             *
             * @param blocking Specifies whether this method should listen
             * blocking or non-blocking.
             */
            void listen(bool blocking = false);

/*}}}*/

        protected:
            // void create();/*{{{*/

            /** Creates the FIFO.
             *
             * @exception Exception::FileInputException When the file could not
             *            be created. @c Exception::Type is the result of
             *            @ref Exception::errnoToType().
             */
            void create();

/*}}}*/
            // void open(bool createIfMissing = false);/*{{{*/

            /**
             * @brief Opens the FIFO.
             *
             * Wraps around @ref validateFile(), @ref create() and @c
             * fstream::open().
             *
             * If @a createIfMissing is set to @c true, this method calls
             * @ref create() instead of throwing an @ref FileInputException with
             * the @ref Type of @ref Exception::FileMissing.
             *
             * @param createIfMissing Whether FIFO should be created or not.
             * @exception FileInputException If @ref validateFile() fails.
             * @see InputBase::validateFile()
             * @see InputBase::create()
             */
            void open(bool createIfMissing = false);

/*}}}*/
            // void close();/*{{{*/

            /**
             * @brief Closes the FIFO.
             *
             * Closes the FIFO and cancles the thread, if running.
             *
             * @warning Do not override this method!
             */
            void close();

/*}}}*/
            // void validateFile();/*{{{*/

            /**
             * @brief Checks the FIFO for validity and throws an exception if
             *        something is not like expected.
             *
             * The FIFOs owner-uid has to be the one who runs this program.
             * Additionally, the FIFO must @b not be readable or writable for
             * other users. (chmod 600).
             *
             * Normally, the FIFO should exist with the right permissions,
             * except sxc has not been run before (in this directory) or someone
             * tampered with the directory structure.
             *
             * @exception Exception::FileInputException When file is invalid.
             */

            void validateFile();

/*}}}*/

        private:
            /// The path including file name where the FIFO is located.
            std::string _path;
            /// The FIFO from which will be read.
            std::fstream _fifo;
            /// Indicates whether @ref _fifo is valid.
            bool _isFifoValid;
            /// The thread running @ref _listen
            pthread_t _thread;
            /// Indicates whether @ref _thread is running.
            bool _isThreadRunning;
            /// Indicates whether @ref _read() or @ref listen() are active.
            bool _isLocked;
            // virtual const std::string &_createPath() const = 0;/*{{{*/

            /**
             * @brief Returns the path and file name of the FIFO.
             *
             * Called by @ref initialize() which stores the result in @ref _path
             * which is used throughout the class in the other methods.
             *
             * @note Pure virtual.
             *
             * @return Path and file name where the FIFO should be placed.
             */
            virtual const std::string &_createPath() const = 0;

/*}}}*/
            // virtual void _handleInput(std::string input) = 0;/*{{{*/

            /**
             * @brief Handles input that has been written into the FIFO.
             *
             * @note Pure virtual.
             *
             * @param input Something that has been written into the FIFO.
             */
            virtual void _handleInput(std::string input) = 0;

/*}}}*/
            // void _read();/*{{{*/

            /**
             * @brief Reads the FIFO blocking until the other end is closed.
             *
             * Input is handled by calling @ref _handleInput().
             *
             * @warning Do not override this method!
             */
            void _read();

/*}}}*/
            // static void *_listen(void *fifo);/*{{{*/

            /**
             * @brief Listens blocking on the passed FIFO.
             *
             * Runs an infinite loop on @ref _read() of the object @a fifo.
             *
             * @warning Should only be called by a pthread created in @ref
             *          listen. This method will never stop by itsself, thus
             *          its thread has to be canceled.
             * @warning The parameter @a fifo should not be anything other than
             *          a this-pointer.
             *
             * @param fifo Pointer to object of class InputBase.
             * @return NULL
             * @see InputBase::listen()
             * @see InputBase::close()
             * @see InputBase::_read()
             */
            static void *_listen(void *fifo);

/*}}}*/
    };
}

#endif // FILE_INPUTBASE_HXX

// Use no tabs at all; four spaces indentation; max. eighty chars per line.
// vim: et ts=4 sw=4 tw=80 fo+=c fdm=marker
<|endoftext|>


<commit_before>/*
 * DesktopNetworkReply.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * This program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "DesktopNetworkReply.hpp"

#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/asio/io_service.hpp>

#include <core/Error.hpp>
#include <core/Log.hpp>

#include <core/http/Response.hpp>
#include <core/http/LocalStreamAsyncClient.hpp>

#include <QTimer>

#include "DesktopNetworkIOService.hpp"

using namespace core;

namespace desktop {

struct NetworkReply::Impl
{
   Impl(const FilePath& streamFilePath)
      : pClient(new http::LocalStreamAsyncClient(ioService(),
                                                 streamFilePath)),
        replyReadOffset(0)
   {
   }
   boost::shared_ptr<http::LocalStreamAsyncClient> pClient;
   QByteArray replyData;
   qint64 replyReadOffset;
};

NetworkReply::NetworkReply(const FilePath& streamFilePath,
                           QNetworkAccessManager::Operation op,
                           const QNetworkRequest& req,
                           QIODevice* outgoingData,
                           QObject *parent)
   : QNetworkReply(parent), pImpl_(new Impl(streamFilePath))
{
   // set our attributes
   setOperation(op);
   setRequest(req);
   setUrl(req.url());

   // build http request
   http::Request request;
   switch(op)
   {
   case QNetworkAccessManager::HeadOperation:
      request.setMethod("HEAD");
      break;
   case QNetworkAccessManager::GetOperation:
      request.setMethod("GET");
      break;
   case QNetworkAccessManager::PutOperation:
      request.setMethod("PUT");
      break;
   case QNetworkAccessManager::PostOperation:
      request.setMethod("POST");
      break;
   case QNetworkAccessManager::DeleteOperation:
      request.setMethod("DELETE");
      break;
   case QNetworkAccessManager::CustomOperation:
      {
      QVariant custom = req.attribute(QNetworkRequest::CustomVerbAttribute);
      if (!custom.isNull())
         request.setMethod(custom.toString().toStdString());
      break;
      }
    case QNetworkAccessManager::UnknownOperation:
      LOG_WARNING_MESSAGE("Unknown operation passed to createRequest");
      break;
   }

   // uri
   std::string uri = req.url().path().toStdString();
   if (req.url().hasQuery())
   {
      uri.append("?");
      QByteArray queryString = req.url().encodedQuery();
      uri.append(queryString.begin(), queryString.end());
   }
   if (req.url().hasFragment())
   {
      uri.append("#");
      uri.append(req.url().fragment().toStdString());
   }
   request.setUri(uri);

   // headers
   QList<QByteArray> headers = req.rawHeaderList();
   BOOST_FOREACH(QByteArray header, headers)
   {
      request.setHeaderLine(std::string(header.begin(), header.end()));
   }

   // body
   if (outgoingData != NULL)
   {
      QByteArray postData = outgoingData->readAll();
      request.setBody(std::string(postData.begin(), postData.end()));
   }

   // set the request
   pImpl_->pClient->request().assign(request);

   // set the retry profile
   pImpl_->pClient->setConnectionRetryProfile(
       http::ConnectionRetryProfile(boost::posix_time::seconds(10),
                                    boost::posix_time::milliseconds(50)));

   // execute and bind to response handlers
   pImpl_->pClient->execute(boost::bind(&NetworkReply::onResponse, this, _1),
                            boost::bind(&NetworkReply::onError, _1));
}

NetworkReply::~NetworkReply()
{
   try
   {
      pImpl_->pClient->close();
   }
   catch(...)
   {
   }
}

qint64 NetworkReply::bytesAvailable() const
{
   // check for bytes available
   qint64 avail = pImpl_->replyData.size() - pImpl_->replyReadOffset;
   return avail;
}

bool NetworkReply::isSequential() const
{
   return true;
}

void NetworkReply::abort()
{
}

qint64 NetworkReply::readData(char *data, qint64 maxSize)
{
   if (pImpl_->replyReadOffset >= pImpl_->replyData.size())
      return -1;

   qint64 bytesToRead = qMin(maxSize, pImpl_->replyData.size() -
                                      pImpl_->replyReadOffset);

   ::memcpy(data,
            pImpl_->replyData.constData() + pImpl_->replyReadOffset,
            bytesToRead);

   pImpl_->replyReadOffset += bytesToRead;

   if (pImpl_->replyReadOffset >= pImpl_->replyData.size())
      QTimer::singleShot(0, this, SIGNAL(finished()));
   else
      QTimer::singleShot(0, this, SIGNAL(readyRead()));

   return bytesToRead;
}

void NetworkReply::onResponse(const http::Response& response)
{
   // call open on the QIODevice
   open(ReadOnly | Unbuffered);

   // set http status and reason codes
   setAttribute(QNetworkRequest::HttpStatusCodeAttribute,
                response.statusCode());
   setAttribute(QNetworkRequest::HttpReasonPhraseAttribute,
                QString::fromStdString(response.statusMessage()));

   // set headers
   BOOST_FOREACH(const http::Header& header, response.headers())
   {
      QByteArray name = QByteArray(header.name.c_str());
      QByteArray value = QByteArray(header.value.c_str());
      setRawHeader(name, value);
   }

   // set body / content-length
   const std::string& body = response.body();
   if (!body.empty())
   {
      setHeader(QNetworkRequest::ContentLengthHeader, (uint)body.length());
      pImpl_->replyData.append(body.data(), body.length());
      pImpl_->replyReadOffset = 0;
   }

   // notify listeners that data is ready
   QTimer::singleShot(0, this, SIGNAL(readyRead()));
}

void NetworkReply::onError(const Error& error)
{
   if (error.code() != boost::asio::error::operation_aborted)
   {
      LOG_ERROR(error);
   }
}

} // namespace desktop
<commit_msg>don't include fragments when forwarding urls to local peer<commit_after>/*
 * DesktopNetworkReply.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * This program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "DesktopNetworkReply.hpp"

#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/asio/io_service.hpp>

#include <core/Error.hpp>
#include <core/Log.hpp>

#include <core/http/Response.hpp>
#include <core/http/LocalStreamAsyncClient.hpp>

#include <QTimer>

#include "DesktopNetworkIOService.hpp"

using namespace core;

namespace desktop {

struct NetworkReply::Impl
{
   Impl(const FilePath& streamFilePath)
      : pClient(new http::LocalStreamAsyncClient(ioService(),
                                                 streamFilePath)),
        replyReadOffset(0)
   {
   }
   boost::shared_ptr<http::LocalStreamAsyncClient> pClient;
   QByteArray replyData;
   qint64 replyReadOffset;
};

NetworkReply::NetworkReply(const FilePath& streamFilePath,
                           QNetworkAccessManager::Operation op,
                           const QNetworkRequest& req,
                           QIODevice* outgoingData,
                           QObject *parent)
   : QNetworkReply(parent), pImpl_(new Impl(streamFilePath))
{
   // set our attributes
   setOperation(op);
   setRequest(req);
   setUrl(req.url());

   // build http request
   http::Request request;
   switch(op)
   {
   case QNetworkAccessManager::HeadOperation:
      request.setMethod("HEAD");
      break;
   case QNetworkAccessManager::GetOperation:
      request.setMethod("GET");
      break;
   case QNetworkAccessManager::PutOperation:
      request.setMethod("PUT");
      break;
   case QNetworkAccessManager::PostOperation:
      request.setMethod("POST");
      break;
   case QNetworkAccessManager::DeleteOperation:
      request.setMethod("DELETE");
      break;
   case QNetworkAccessManager::CustomOperation:
      {
      QVariant custom = req.attribute(QNetworkRequest::CustomVerbAttribute);
      if (!custom.isNull())
         request.setMethod(custom.toString().toStdString());
      break;
      }
    case QNetworkAccessManager::UnknownOperation:
      LOG_WARNING_MESSAGE("Unknown operation passed to createRequest");
      break;
   }

   // uri
   std::string uri = req.url().path().toStdString();
   if (req.url().hasQuery())
   {
      uri.append("?");
      QByteArray queryString = req.url().encodedQuery();
      uri.append(queryString.begin(), queryString.end());
   }
   request.setUri(uri);

   // headers
   QList<QByteArray> headers = req.rawHeaderList();
   BOOST_FOREACH(QByteArray header, headers)
   {
      request.setHeaderLine(std::string(header.begin(), header.end()));
   }

   // body
   if (outgoingData != NULL)
   {
      QByteArray postData = outgoingData->readAll();
      request.setBody(std::string(postData.begin(), postData.end()));
   }

   // set the request
   pImpl_->pClient->request().assign(request);

   // set the retry profile
   pImpl_->pClient->setConnectionRetryProfile(
       http::ConnectionRetryProfile(boost::posix_time::seconds(10),
                                    boost::posix_time::milliseconds(50)));

   // execute and bind to response handlers
   pImpl_->pClient->execute(boost::bind(&NetworkReply::onResponse, this, _1),
                            boost::bind(&NetworkReply::onError, _1));
}

NetworkReply::~NetworkReply()
{
   try
   {
      pImpl_->pClient->close();
   }
   catch(...)
   {
   }
}

qint64 NetworkReply::bytesAvailable() const
{
   // check for bytes available
   qint64 avail = pImpl_->replyData.size() - pImpl_->replyReadOffset;
   return avail;
}

bool NetworkReply::isSequential() const
{
   return true;
}

void NetworkReply::abort()
{
}

qint64 NetworkReply::readData(char *data, qint64 maxSize)
{
   if (pImpl_->replyReadOffset >= pImpl_->replyData.size())
      return -1;

   qint64 bytesToRead = qMin(maxSize, pImpl_->replyData.size() -
                                      pImpl_->replyReadOffset);

   ::memcpy(data,
            pImpl_->replyData.constData() + pImpl_->replyReadOffset,
            bytesToRead);

   pImpl_->replyReadOffset += bytesToRead;

   if (pImpl_->replyReadOffset >= pImpl_->replyData.size())
      QTimer::singleShot(0, this, SIGNAL(finished()));
   else
      QTimer::singleShot(0, this, SIGNAL(readyRead()));

   return bytesToRead;
}

void NetworkReply::onResponse(const http::Response& response)
{
   // call open on the QIODevice
   open(ReadOnly | Unbuffered);

   // set http status and reason codes
   setAttribute(QNetworkRequest::HttpStatusCodeAttribute,
                response.statusCode());
   setAttribute(QNetworkRequest::HttpReasonPhraseAttribute,
                QString::fromStdString(response.statusMessage()));

   // set headers
   BOOST_FOREACH(const http::Header& header, response.headers())
   {
      QByteArray name = QByteArray(header.name.c_str());
      QByteArray value = QByteArray(header.value.c_str());
      setRawHeader(name, value);
   }

   // set body / content-length
   const std::string& body = response.body();
   if (!body.empty())
   {
      setHeader(QNetworkRequest::ContentLengthHeader, (uint)body.length());
      pImpl_->replyData.append(body.data(), body.length());
      pImpl_->replyReadOffset = 0;
   }

   // notify listeners that data is ready
   QTimer::singleShot(0, this, SIGNAL(readyRead()));
}

void NetworkReply::onError(const Error& error)
{
   if (error.code() != boost::asio::error::operation_aborted)
   {
      LOG_ERROR(error);
   }
}

} // namespace desktop
<|endoftext|>


<commit_before>/*************************************************************************
 * Copyright (c) 2014 eProsima. All rights reserved.
 *
 * This copy of eProsima Fast RTPS is licensed to you under the terms described in the
 * FASTRTPS_LIBRARY_LICENSE file included in this distribution.
 *
 *************************************************************************/

/*
 * @file StatelessReader.cpp
 *
 */

#include <fastrtps/rtps/reader/StatelessReader.h>
#include <fastrtps/rtps/history/ReaderHistory.h>
#include <fastrtps/rtps/reader/ReaderListener.h>
#include <fastrtps/utils/RTPSLog.h>
#include <fastrtps/rtps/common/CacheChange.h>
#include "../participant/RTPSParticipantImpl.h"
#include "FragmentedChangePitStop.h"

#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/lock_guard.hpp>
#include <boost/thread.hpp>

#include <cassert>

#define IDSTRING "(ID:"<< boost::this_thread::get_id() <<") "<<

using namespace eprosima::fastrtps::rtps;

static const char* const CLASS_NAME = "StatelessReader";

StatelessReader::~StatelessReader()
{
	const char* const METHOD_NAME = "~StatelessReader";
	logInfo(RTPS_READER,"Removing reader "<<this->getGuid());
}

StatelessReader::StatelessReader(RTPSParticipantImpl* pimpl,GUID_t& guid,
		ReaderAttributes& att,ReaderHistory* hist,ReaderListener* listen):
						RTPSReader(pimpl,guid,att,hist, listen)
{

}

bool StatelessReader::matched_writer_add(RemoteWriterAttributes& wdata)
{
	const char* const METHOD_NAME = "matched_writer_add";
	boost::lock_guard<boost::recursive_mutex> guard(*mp_mutex);
	for(auto it = m_matched_writers.begin();it!=m_matched_writers.end();++it)
	{
		if((*it).guid == wdata.guid)
			return false;
	}
	logInfo(RTPS_READER,"Writer " << wdata.guid << " added to "<<m_guid.entityId);
	m_matched_writers.push_back(wdata);
	m_acceptMessagesFromUnkownWriters = false;
	return true;
}
bool StatelessReader::matched_writer_remove(RemoteWriterAttributes& wdata)
{
	const char* const METHOD_NAME = "matched_writer_remove";
	boost::lock_guard<boost::recursive_mutex> guard(*mp_mutex);
	for(auto it = m_matched_writers.begin();it!=m_matched_writers.end();++it)
	{
		if((*it).guid == wdata.guid)
		{
			logInfo(RTPS_READER,"Writer " <<wdata.guid<< " removed from "<<m_guid.entityId);
			m_matched_writers.erase(it);
			return true;
		}
	}
	return false;
}

bool StatelessReader::matched_writer_is_matched(RemoteWriterAttributes& wdata)
{
	boost::lock_guard<boost::recursive_mutex> guard(*mp_mutex);
	for(auto it = m_matched_writers.begin();it!=m_matched_writers.end();++it)
	{
		if((*it).guid == wdata.guid)
		{
			return true;
		}
	}
	return false;
}

bool StatelessReader::change_received(CacheChange_t* change)
{
    // Only make visible the change if there is not other with bigger sequence number.
    // TODO Revisar si no hay que incluirlo.
    if(!mp_history->thereIsUpperRecordOf(change->writerGUID, change->sequenceNumber))
    {
        if(mp_history->received_change(change, 0))
        {
            boost::unique_lock<boost::recursive_mutex> lock(*mp_mutex);

            if(getListener() != nullptr)
            {
                lock.unlock();
                getListener()->onNewCacheChangeAdded((RTPSReader*)this,change);
                lock.lock();
            }

            mp_history->postSemaphore();
            return true;
        }
    }

	return false;
}

bool StatelessReader::nextUntakenCache(CacheChange_t** change,WriterProxy** /*wpout*/)
{
	//const char* const METHOD_NAME = "nextUntakenCache";
	boost::lock_guard<boost::recursive_mutex> guard(*mp_mutex);
	return mp_history->get_min_change(change);
}

bool StatelessReader::nextUnreadCache(CacheChange_t** change,WriterProxy** /*wpout*/)
{
	const char* const METHOD_NAME = "nextUnreadCache";
	boost::lock_guard<boost::recursive_mutex> guard(*mp_mutex);
	//m_reader_cache.sortCacheChangesBySeqNum();
	bool found = false;
	std::vector<CacheChange_t*>::iterator it;
	//TODO PROTEGER ACCESO A HISTORIA AQUI??? YO CREO QUE NO, YA ESTA EL READER PROTEGIDO
	for(it = mp_history->changesBegin();
			it!=mp_history->changesEnd();++it)
	{
		if(!(*it)->isRead)
		{
			found = true;
			break;
		}
	}
	if(found)
	{
		*change = *it;
		return true;
	}
	logInfo(RTPS_READER,"No Unread elements left");
	return false;
}

bool StatelessReader::change_removed_by_history(CacheChange_t* /*ch*/, WriterProxy* /*prox*/)
{
	return true;
}

bool StatelessReader::processDataMsg(CacheChange_t *change)
{
    const char* const METHOD_NAME = "processDataMsg";

    assert(change);

	boost::unique_lock<boost::recursive_mutex> lock(*mp_mutex);

    if(acceptMsgFrom(change->writerGUID))
    {
        logInfo(RTPS_MSG_IN,IDSTRING"Trying to add change " << change->sequenceNumber <<" TO reader: "<< getGuid().entityId,C_BLUE);

        CacheChange_t* change_to_add;

        if(reserveCache(&change_to_add)) //Reserve a new cache from the corresponding cache pool
        {
            if (!change_to_add->copy(change))
            {
                logWarning(RTPS_MSG_IN,IDSTRING"Problem copying CacheChange, received data is: " << change->serializedPayload.length
                        << " bytes and max size in reader " << getGuid().entityId << " is " << change_to_add->serializedPayload.max_size, C_BLUE);
                releaseCache(change_to_add);
                return false;
            }
        }
        else
        {
            logError(RTPS_MSG_IN,IDSTRING"Problem reserving CacheChange in reader: " << getGuid().entityId, C_BLUE);
            return false;
        }

        //lock.unlock(); // Next function has its own lock.
        if(!change_received(change_to_add))
        {
            logInfo(RTPS_MSG_IN,IDSTRING"MessageReceiver not add change "
                    <<change_to_add->sequenceNumber, C_BLUE);
            releaseCache(change_to_add);

            if(getGuid().entityId == c_EntityId_SPDPReader)
            {
                mp_RTPSParticipant->assertRemoteRTPSParticipantLiveliness(change->writerGUID.guidPrefix);
            }
        }
    }

    return true;
}

bool StatelessReader::processDataFragMsg(CacheChange_t *incomingChange, uint32_t sampleSize, uint32_t fragmentStartingNum)
{
	const char* const METHOD_NAME = "processDataFragMsg";

	assert(incomingChange);

	boost::unique_lock<boost::recursive_mutex> lock(*mp_mutex);

	if (acceptMsgFrom(incomingChange->writerGUID))
	{
        // Check if CacheChange was received.
        if(!getHistory()->thereIsRecordOf(incomingChange->writerGUID, incomingChange->sequenceNumber))
        {
            logInfo(RTPS_MSG_IN, IDSTRING"Trying to add fragment " << incomingChange->sequenceNumber.to64long() << " TO reader: " << getGuid().entityId, C_BLUE);

            // Fragments manager has to process incomming fragments.
            // If CacheChange_t is completed, it will be returned;
            CacheChange_t* change_completed = fragmentedChangePitStop_->process(incomingChange, sampleSize, fragmentStartingNum);

            // If the change was completed, process it.
            if(change_completed != nullptr)
            {
                lock.unlock(); // Next function has its own lock.

                if (!change_received(change_completed))
                {
                    logInfo(RTPS_MSG_IN, IDSTRING"MessageReceiver not add change " << change_completed->sequenceNumber.to64long(), C_BLUE);

                    // Assert liveliness because if it is a participant discovery info.
                    if (getGuid().entityId == c_EntityId_SPDPReader)
                    {
                        mp_RTPSParticipant->assertRemoteRTPSParticipantLiveliness(incomingChange->writerGUID.guidPrefix);
                    }

                    // Release CacheChange_t.
                    releaseCache(change_completed);
                }
            }
		}
	}

	return true;
}

bool StatelessReader::processHeartbeatMsg(GUID_t& /*writerGUID*/, uint32_t /*hbCount*/, SequenceNumber_t& /*firstSN*/,
        SequenceNumber_t& /*lastSN*/, bool /*finalFlag*/, bool /*livelinessFlag*/)
{
    return true;
}

bool StatelessReader::processGapMsg(GUID_t& /*writerGUID*/, SequenceNumber_t& /*gapStart*/, SequenceNumberSet_t& /*gapList*/)
{
    return true;
}

bool StatelessReader::acceptMsgFrom(GUID_t& writerId)
{
	if(this->m_acceptMessagesFromUnkownWriters)
	{
		return true;
	}
	else
	{
		if(writerId.entityId == this->m_trustedWriterEntityId)
			return true;

		for(auto it = m_matched_writers.begin();it!=m_matched_writers.end();++it)
		{
			if((*it).guid == writerId)
			{
				return true;
			}
		}
	}

	return false;
}
<commit_msg>Restored mutex<commit_after>/*************************************************************************
 * Copyright (c) 2014 eProsima. All rights reserved.
 *
 * This copy of eProsima Fast RTPS is licensed to you under the terms described in the
 * FASTRTPS_LIBRARY_LICENSE file included in this distribution.
 *
 *************************************************************************/

/*
 * @file StatelessReader.cpp
 *
 */

#include <fastrtps/rtps/reader/StatelessReader.h>
#include <fastrtps/rtps/history/ReaderHistory.h>
#include <fastrtps/rtps/reader/ReaderListener.h>
#include <fastrtps/utils/RTPSLog.h>
#include <fastrtps/rtps/common/CacheChange.h>
#include "../participant/RTPSParticipantImpl.h"
#include "FragmentedChangePitStop.h"

#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/lock_guard.hpp>
#include <boost/thread.hpp>

#include <cassert>

#define IDSTRING "(ID:"<< boost::this_thread::get_id() <<") "<<

using namespace eprosima::fastrtps::rtps;

static const char* const CLASS_NAME = "StatelessReader";

StatelessReader::~StatelessReader()
{
	const char* const METHOD_NAME = "~StatelessReader";
	logInfo(RTPS_READER,"Removing reader "<<this->getGuid());
}

StatelessReader::StatelessReader(RTPSParticipantImpl* pimpl,GUID_t& guid,
		ReaderAttributes& att,ReaderHistory* hist,ReaderListener* listen):
						RTPSReader(pimpl,guid,att,hist, listen)
{

}

bool StatelessReader::matched_writer_add(RemoteWriterAttributes& wdata)
{
	const char* const METHOD_NAME = "matched_writer_add";
	boost::lock_guard<boost::recursive_mutex> guard(*mp_mutex);
	for(auto it = m_matched_writers.begin();it!=m_matched_writers.end();++it)
	{
		if((*it).guid == wdata.guid)
			return false;
	}
	logInfo(RTPS_READER,"Writer " << wdata.guid << " added to "<<m_guid.entityId);
	m_matched_writers.push_back(wdata);
	m_acceptMessagesFromUnkownWriters = false;
	return true;
}
bool StatelessReader::matched_writer_remove(RemoteWriterAttributes& wdata)
{
	const char* const METHOD_NAME = "matched_writer_remove";
	boost::lock_guard<boost::recursive_mutex> guard(*mp_mutex);
	for(auto it = m_matched_writers.begin();it!=m_matched_writers.end();++it)
	{
		if((*it).guid == wdata.guid)
		{
			logInfo(RTPS_READER,"Writer " <<wdata.guid<< " removed from "<<m_guid.entityId);
			m_matched_writers.erase(it);
			return true;
		}
	}
	return false;
}

bool StatelessReader::matched_writer_is_matched(RemoteWriterAttributes& wdata)
{
	boost::lock_guard<boost::recursive_mutex> guard(*mp_mutex);
	for(auto it = m_matched_writers.begin();it!=m_matched_writers.end();++it)
	{
		if((*it).guid == wdata.guid)
		{
			return true;
		}
	}
	return false;
}

bool StatelessReader::change_received(CacheChange_t* change)
{
    // Only make visible the change if there is not other with bigger sequence number.
    // TODO Revisar si no hay que incluirlo.
    if(!mp_history->thereIsUpperRecordOf(change->writerGUID, change->sequenceNumber))
    {
        if(mp_history->received_change(change, 0))
        {
            boost::unique_lock<boost::recursive_mutex> lock(*mp_mutex);

            if(getListener() != nullptr)
            {
                lock.unlock();
                getListener()->onNewCacheChangeAdded((RTPSReader*)this,change);
                lock.lock();
            }

            mp_history->postSemaphore();
            return true;
        }
    }

	return false;
}

bool StatelessReader::nextUntakenCache(CacheChange_t** change,WriterProxy** /*wpout*/)
{
	//const char* const METHOD_NAME = "nextUntakenCache";
	boost::lock_guard<boost::recursive_mutex> guard(*mp_mutex);
	return mp_history->get_min_change(change);
}

bool StatelessReader::nextUnreadCache(CacheChange_t** change,WriterProxy** /*wpout*/)
{
	const char* const METHOD_NAME = "nextUnreadCache";
	boost::lock_guard<boost::recursive_mutex> guard(*mp_mutex);
	//m_reader_cache.sortCacheChangesBySeqNum();
	bool found = false;
	std::vector<CacheChange_t*>::iterator it;
	//TODO PROTEGER ACCESO A HISTORIA AQUI??? YO CREO QUE NO, YA ESTA EL READER PROTEGIDO
	for(it = mp_history->changesBegin();
			it!=mp_history->changesEnd();++it)
	{
		if(!(*it)->isRead)
		{
			found = true;
			break;
		}
	}
	if(found)
	{
		*change = *it;
		return true;
	}
	logInfo(RTPS_READER,"No Unread elements left");
	return false;
}

bool StatelessReader::change_removed_by_history(CacheChange_t* /*ch*/, WriterProxy* /*prox*/)
{
	return true;
}

bool StatelessReader::processDataMsg(CacheChange_t *change)
{
    const char* const METHOD_NAME = "processDataMsg";

    assert(change);

	boost::unique_lock<boost::recursive_mutex> lock(*mp_mutex);

    if(acceptMsgFrom(change->writerGUID))
    {
        logInfo(RTPS_MSG_IN,IDSTRING"Trying to add change " << change->sequenceNumber <<" TO reader: "<< getGuid().entityId,C_BLUE);

        CacheChange_t* change_to_add;

        if(reserveCache(&change_to_add)) //Reserve a new cache from the corresponding cache pool
        {
            if (!change_to_add->copy(change))
            {
                logWarning(RTPS_MSG_IN,IDSTRING"Problem copying CacheChange, received data is: " << change->serializedPayload.length
                        << " bytes and max size in reader " << getGuid().entityId << " is " << change_to_add->serializedPayload.max_size, C_BLUE);
                releaseCache(change_to_add);
                return false;
            }
        }
        else
        {
            logError(RTPS_MSG_IN,IDSTRING"Problem reserving CacheChange in reader: " << getGuid().entityId, C_BLUE);
            return false;
        }

        lock.unlock(); // Next function has its own lock.
        if(!change_received(change_to_add))
        {
            logInfo(RTPS_MSG_IN,IDSTRING"MessageReceiver not add change "
                    <<change_to_add->sequenceNumber, C_BLUE);
            releaseCache(change_to_add);

            if(getGuid().entityId == c_EntityId_SPDPReader)
            {
                mp_RTPSParticipant->assertRemoteRTPSParticipantLiveliness(change->writerGUID.guidPrefix);
            }
        }
    }

    return true;
}

bool StatelessReader::processDataFragMsg(CacheChange_t *incomingChange, uint32_t sampleSize, uint32_t fragmentStartingNum)
{
	const char* const METHOD_NAME = "processDataFragMsg";

	assert(incomingChange);

	boost::unique_lock<boost::recursive_mutex> lock(*mp_mutex);

	if (acceptMsgFrom(incomingChange->writerGUID))
	{
        // Check if CacheChange was received.
        if(!getHistory()->thereIsRecordOf(incomingChange->writerGUID, incomingChange->sequenceNumber))
        {
            logInfo(RTPS_MSG_IN, IDSTRING"Trying to add fragment " << incomingChange->sequenceNumber.to64long() << " TO reader: " << getGuid().entityId, C_BLUE);

            // Fragments manager has to process incomming fragments.
            // If CacheChange_t is completed, it will be returned;
            CacheChange_t* change_completed = fragmentedChangePitStop_->process(incomingChange, sampleSize, fragmentStartingNum);

            // If the change was completed, process it.
            if(change_completed != nullptr)
            {
                lock.unlock(); // Next function has its own lock.

                if (!change_received(change_completed))
                {
                    logInfo(RTPS_MSG_IN, IDSTRING"MessageReceiver not add change " << change_completed->sequenceNumber.to64long(), C_BLUE);

                    // Assert liveliness because if it is a participant discovery info.
                    if (getGuid().entityId == c_EntityId_SPDPReader)
                    {
                        mp_RTPSParticipant->assertRemoteRTPSParticipantLiveliness(incomingChange->writerGUID.guidPrefix);
                    }

                    // Release CacheChange_t.
                    releaseCache(change_completed);
                }
            }
		}
	}

	return true;
}

bool StatelessReader::processHeartbeatMsg(GUID_t& /*writerGUID*/, uint32_t /*hbCount*/, SequenceNumber_t& /*firstSN*/,
        SequenceNumber_t& /*lastSN*/, bool /*finalFlag*/, bool /*livelinessFlag*/)
{
    return true;
}

bool StatelessReader::processGapMsg(GUID_t& /*writerGUID*/, SequenceNumber_t& /*gapStart*/, SequenceNumberSet_t& /*gapList*/)
{
    return true;
}

bool StatelessReader::acceptMsgFrom(GUID_t& writerId)
{
	if(this->m_acceptMessagesFromUnkownWriters)
	{
		return true;
	}
	else
	{
		if(writerId.entityId == this->m_trustedWriterEntityId)
			return true;

		for(auto it = m_matched_writers.begin();it!=m_matched_writers.end();++it)
		{
			if((*it).guid == writerId)
			{
				return true;
			}
		}
	}

	return false;
}
<|endoftext|>


<commit_before>
#include <display/VROffAxisProjectionNode.h>

namespace MinVR {

	VROffAxisProjectionNode::VROffAxisProjectionNode(const std::string &name, VRPoint3 topLeft, VRPoint3 botLeft, VRPoint3 topRight, VRPoint3 botRight, float nearClip, float farClip) :
	VRDisplayNode(name), _topLeft(topLeft), _botLeft(botLeft), _topRight(topRight), _botRight(botRight),  _nearClip(nearClip), _farClip(farClip)
{
  // in:
  _valuesAdded.push_back("CameraMatrix");
  // out:
  _valuesAdded.push_back("ProjectionMatrix");
  _valuesAdded.push_back("ViewMatrix");
}

VROffAxisProjectionNode::~VROffAxisProjectionNode()
{
}

void
VROffAxisProjectionNode::render(VRDataIndex *renderState, VRRenderHandler *renderHandler)
{
	renderState->pushState();

	// This projection code follows the math described in this paper:
	// http://csc.lsu.edu/~kooima/pdfs/gen-perspective.pdf

	VRPoint3 pa = _botLeft;
	VRPoint3 pb = _botRight;
	VRPoint3 pc = _topLeft;
    VRMatrix4 cameraMatrix = renderState->getValue("CameraMatrix");
    VRPoint3 pe = VRPoint3(0,0,0) + cameraMatrix.getColumn(3);

	// Compute an orthonormal basis for the screen
	VRVector3 vr = (pb - pa).normalize();
	VRVector3 vu = (pc - pa).normalize();
	VRVector3 vn = vr.cross(vu).normalize();

	// Compute the screen corner vectors
	VRVector3 va = pa - pe;
	VRVector3 vb = pb - pe;
	VRVector3 vc = pc - pe;

	// Find the distance from the eye to screen plane
	float d = -va.dot(vn);

	// Find the extent of the perpendicular projection
	float l = vr.dot(va) * _nearClip / d;
	float r = vr.dot(vb) * _nearClip / d;
	float b = vu.dot(va) * _nearClip / d;
	float t = vu.dot(vc) * _nearClip / d;

	VRMatrix4 projMat = VRMatrix4::projection(l, r, b, t, _nearClip, _farClip);

	renderState->addData("ProjectionMatrix", projMat);

	// Rotate the projection to be non-perpendicular
    VRMatrix4 Mrot = VRMatrix4::fromRowMajorElements(vr[0], vr[1], vr[2], 0.0,
                                                     vu[0], vu[1], vu[2], 0.0,
                                                     vn[0], vn[1], vn[2], 0.0,
                                                     0.0, 0.0, 0.0, 1.0);

	// Move the apex of the frustum to the origin
	VRMatrix4 Mtrans = VRMatrix4::translation(VRPoint3(0, 0, 0) - pe);

	VRMatrix4 viewMat = Mrot * Mtrans;

	renderState->addData("ViewMatrix", viewMat);

	VRDisplayNode::render(renderState, renderHandler);

	renderState->popState();
}

VRDisplayNode*
VROffAxisProjectionNode::create(VRMainInterface *vrMain, VRDataIndex *config, const std::string &nameSpace) {
	std::string nodeNameSpace = nameSpace;

	VRPoint3 topLeft = config->getValue("TopLeft", nameSpace);
	VRPoint3 botLeft = config->getValue("BottomLeft", nameSpace);
	VRPoint3 topRight = config->getValue("TopRight", nameSpace);
	VRPoint3 botRight = config->getValue("BottomRight", nameSpace);
	float nearClip = config->getValue("NearClip", nameSpace);
	float farClip = config->getValue("FarClip", nameSpace);

	VROffAxisProjectionNode *node = new VROffAxisProjectionNode(nameSpace, topLeft, botLeft, topRight, botRight, nearClip, farClip);

	return node;
}

} // end namespace

<commit_msg>audit information fixed<commit_after>
#include <display/VROffAxisProjectionNode.h>

namespace MinVR {

	VROffAxisProjectionNode::VROffAxisProjectionNode(const std::string &name, VRPoint3 topLeft, VRPoint3 botLeft, VRPoint3 topRight, VRPoint3 botRight, float nearClip, float farClip) :
	VRDisplayNode(name), _topLeft(topLeft), _botLeft(botLeft), _topRight(topRight), _botRight(botRight),  _nearClip(nearClip), _farClip(farClip)
{
  // in:
  _valuesNeeded.push_back("CameraMatrix");
  // out:
  _valuesAdded.push_back("ProjectionMatrix");
  _valuesAdded.push_back("ViewMatrix");
}

VROffAxisProjectionNode::~VROffAxisProjectionNode()
{
}

void
VROffAxisProjectionNode::render(VRDataIndex *renderState, VRRenderHandler *renderHandler)
{
	renderState->pushState();

	// This projection code follows the math described in this paper:
	// http://csc.lsu.edu/~kooima/pdfs/gen-perspective.pdf

	VRPoint3 pa = _botLeft;
	VRPoint3 pb = _botRight;
	VRPoint3 pc = _topLeft;
    VRMatrix4 cameraMatrix = renderState->getValue("CameraMatrix");
    VRPoint3 pe = VRPoint3(0,0,0) + cameraMatrix.getColumn(3);

	// Compute an orthonormal basis for the screen
	VRVector3 vr = (pb - pa).normalize();
	VRVector3 vu = (pc - pa).normalize();
	VRVector3 vn = vr.cross(vu).normalize();

	// Compute the screen corner vectors
	VRVector3 va = pa - pe;
	VRVector3 vb = pb - pe;
	VRVector3 vc = pc - pe;

	// Find the distance from the eye to screen plane
	float d = -va.dot(vn);

	// Find the extent of the perpendicular projection
	float l = vr.dot(va) * _nearClip / d;
	float r = vr.dot(vb) * _nearClip / d;
	float b = vu.dot(va) * _nearClip / d;
	float t = vu.dot(vc) * _nearClip / d;

	VRMatrix4 projMat = VRMatrix4::projection(l, r, b, t, _nearClip, _farClip);

	renderState->addData("ProjectionMatrix", projMat);

	// Rotate the projection to be non-perpendicular
    VRMatrix4 Mrot = VRMatrix4::fromRowMajorElements(vr[0], vr[1], vr[2], 0.0,
                                                     vu[0], vu[1], vu[2], 0.0,
                                                     vn[0], vn[1], vn[2], 0.0,
                                                     0.0, 0.0, 0.0, 1.0);

	// Move the apex of the frustum to the origin
	VRMatrix4 Mtrans = VRMatrix4::translation(VRPoint3(0, 0, 0) - pe);

	VRMatrix4 viewMat = Mrot * Mtrans;

	renderState->addData("ViewMatrix", viewMat);

	VRDisplayNode::render(renderState, renderHandler);

	renderState->popState();
}

VRDisplayNode*
VROffAxisProjectionNode::create(VRMainInterface *vrMain, VRDataIndex *config, const std::string &nameSpace) {
	std::string nodeNameSpace = nameSpace;

	VRPoint3 topLeft = config->getValue("TopLeft", nameSpace);
	VRPoint3 botLeft = config->getValue("BottomLeft", nameSpace);
	VRPoint3 topRight = config->getValue("TopRight", nameSpace);
	VRPoint3 botRight = config->getValue("BottomRight", nameSpace);
	float nearClip = config->getValue("NearClip", nameSpace);
	float farClip = config->getValue("FarClip", nameSpace);

	VROffAxisProjectionNode *node = new VROffAxisProjectionNode(nameSpace, topLeft, botLeft, topRight, botRight, nearClip, farClip);

	return node;
}

} // end namespace

<|endoftext|>


<commit_before>#include <iostream>
#include <thread>
#include <random>
#include <chrono>

#include <mpi.h>

#include <multiverso/multiverso.h>
#include <multiverso/net.h>
#include <multiverso/util/log.h>
#include <multiverso/util/net_util.h>

#include <multiverso/table/smooth_array_table.h>
#include <multiverso/table/array_table.h>
#include <multiverso/table/kv_table.h>
#include <MPIWrapper.h>
using namespace multiverso;

void TestKV(int argc, char* argv[]) {
  Log::Info("Test KV map \n");
  // ----------------------------------------------------------------------- //
  // this is a demo of distributed hash table to show how to use the multiverso
  // ----------------------------------------------------------------------- //

  // 1. Start the Multiverso engine ---------------------------------------- //
  MV_Init(&argc, argv);

  // 2. To create the shared table ----------------------------------------- //

  // TODO(feiga): This table must be create at both worker and server endpoint
  // simultaneously, since they should share same type and same created order
  // (same order means same table id). So it's better to create them with some
  // specific creator, instead of current way

  // TODO(feiga): should add some if statesment
  // if the node is worker, then create a worker cache table
  KVWorkerTable<int, int>* dht = new KVWorkerTable<int, int>();
  // if the node is server, then create a server storage table
  KVServerTable<int, int>* server_dht = new KVServerTable<int, int>();

  MV_Barrier();

  // 3. User program ------------------------------------------------------- //

  // all this interface is related with the KVWorkerTable
  // the data structure and the interface can be both defined by users
  // We also provides several common implementations
  // For specific program, user-defined table may provides better performance

  // access the local cache
  std::unordered_map<int, int>& kv = dht->raw();

  // The Get/Add are sync operation, when the function call returns, we already
  // Get from server, or the server has Added the update

  // Get from the server
  dht->Get(0);
  // Check the result. Since no one added, this should be 0
  Log::Info("Get 0 from kv server: result = %d\n", kv[0]);

  // Add 1 to the server
  dht->Add(0, 1);

  // Check the result. Since just added one, this should be 1
  dht->Get(0);

  Log::Info("Get 0 from kv server after add 1: result = %d\n", kv[0]);

  // 4. Shutdown the Multiverso engine. ------------------------------------ //
  MV_ShutDown();
}

void TestArray(int argc, char* argv[]) {
  Log::Info("Test Array \n");

  MV_Init(&argc, argv);

  ArrayWorker<float>* shared_array = new ArrayWorker<float>(1000000);
  ArrayServer<float>* server_array = new ArrayServer<float>(1000000);

  MV_Barrier();
  Log::Info("Create tables OK\n");

  int iter = 1000;
  if (argc == 3) iter = atoi(argv[2]);

  for (int i = 0; i < iter; ++i) {
  // std::vector<float>& vec = shared_array->raw();

  // shared_array->Get();
    float* data = new float[1000000];

    std::vector<float> delta(1000000);
    for (int i = 0; i < 1000000; ++i)
      delta[i] = static_cast<float>(i);

    shared_array->Add(delta.data(), 1000000);

    Log::Info("Rank %d Add OK\n", MV_Rank());

    shared_array->Get(data, 1000000);
    Log::Info("Rank %d Get OK\n", MV_Rank());
    for (int i = 0; i < 10; ++i)
      std::cout << data[i] << " "; std::cout << std::endl;
    MV_Barrier();

  }
  MV_ShutDown();
}

void TestMomentum(int argc, char* argv[]) {
	Log::Info("Test smooth_gradient table \n");

	Log::ResetLogLevel(LogLevel::Debug);
	MV_Init();

	SmoothArrayWorker<float>* shared_array = new SmoothArrayWorker<float>(10);
	SmoothArrayServer<float>* server_array = new SmoothArrayServer<float>(10);

	MV_Barrier();
	Log::Info("Create tables OK\n");

	while (true){
		// std::vector<float>& vec = shared_array->raw();

		// shared_array->Get();
		float data[10];

		std::vector<float> delta(10);
		for (int i = 0; i < 10; ++i)
			delta[i] = static_cast<float>(i+1);

		shared_array->Add(delta.data(), 10, 0.5f);

		Log::Info("Rank %d Add OK\n", MV_Rank());

		shared_array->Get(data, 10);
		Log::Info("Rank %d Get OK\n", MV_Rank());
		for (int i = 0; i < 10; ++i)
			std::cout << data[i] << " "; std::cout << std::endl;
		MV_Barrier();

	}
	MV_ShutDown();
}

#define ARRAY_SIZE 4683776
void TestMultipleThread(int argc, char* argv[])
{
	Microsoft::MSR::CNTK::MPIWrapper *g_mpi = new Microsoft::MSR::CNTK::MPIWrapper();
	Log::Info("Test Multiple threads \n");
	std::mt19937_64 eng{ std::random_device{}() };
	std::uniform_int_distribution<> dist{ 5, 10000 };
	std::this_thread::sleep_for(std::chrono::milliseconds{ dist(eng) });
	//Log::ResetLogLevel(LogLevel::Debug);
	MV_Init(&argc, argv);

	ArrayWorker<float>* shared_array = new ArrayWorker<float>(ARRAY_SIZE);
	ArrayServer<float>* server_array = new ArrayServer<float>(ARRAY_SIZE);
	std::thread* m_prefetchThread = nullptr;
	MV_Barrier();
	Log::Info("Create tables OK\n");

	std::vector<float> delta(ARRAY_SIZE);
	while (true){
		if (m_prefetchThread != nullptr && m_prefetchThread->joinable())
		{
			m_prefetchThread->join();
			delete m_prefetchThread;
			m_prefetchThread = nullptr;
		}

		std::fill(delta.begin(), delta.end(), 0);
		for (int i = 0; i < ARRAY_SIZE; ++i)
		{
		std::mt19937_64 eng{ std::random_device{}() };
			std::uniform_real_distribution<float> dist{ -1, 1 };
			delta[i] = dist(eng);
		}
		m_prefetchThread = new std::thread([&](){

			//std::mt19937_64 eng{ std::random_device{}() };
			//std::uniform_int_distribution<> dist{ 50, 500 };
			//std::this_thread::sleep_for(std::chrono::milliseconds{ dist(eng) });
			shared_array->Add(delta.data(), ARRAY_SIZE);
			shared_array->Get(delta.data(), ARRAY_SIZE);
			Log::Info("Rank %d Get OK\n", MV_Rank());
			for (int i = 0; i < 10; ++i)
				std::cout << delta[i] << " "; std::cout << std::endl;
		});

		//shared_array->Get(data, 10);
		MV_Barrier();

	}
	MV_ShutDown();
}

void TestNet(int argc, char* argv[]) {
  NetInterface* net = NetInterface::Get();
  net->Init(&argc, argv);

  const char* chi1 = std::string("hello, world").c_str();
  const char* chi2 = std::string("hello, c++").c_str();
  const char* chi3 = std::string("hello, multiverso").c_str();
  char* hi1 = new char[14];
  strcpy(hi1, chi1);
  char* hi2 = new char[12];
  strcpy(hi2, chi2);
  char* hi3 = new char[19];
  strcpy(hi3, chi3);
  if (net->rank() == 0) {
    for (int rank = 1; rank < net->size(); ++rank) {
    MessagePtr msg(new Message());// = std::make_unique<Message>();
    msg->set_src(0);
    msg->set_dst(rank);
    msg->Push(Blob(hi1, 13));
    msg->Push(Blob(hi2, 11));
    msg->Push(Blob(hi3, 18));
    net->Send(msg);
    Log::Info("rank 0 send\n");
    }

    for (int i = 1; i < net->size(); ++i) {
      MessagePtr msg(new Message());
      msg.reset(new Message());
      while (net->Recv(&msg) == 0) {
        // Log::Info("recv return 0\n");
      }
      Log::Info("rank 0 recv\n");
      // CHECK(strcmp(msg->data()[0].data(), hi) == 0);
      std::vector<Blob> recv_data = msg->data();
      CHECK(recv_data.size() == 3);
      for (int i = 0; i < msg->size(); ++i) {
        Log::Info("recv from srv %d: %s\n", msg->src(), recv_data[i].data());
      };
    }
  } else {// other rank
    MessagePtr msg(new Message());// = std::make_unique<Message>();
    while (net->Recv(&msg) == 0) {
      // Log::Info("recv return 0\n");
    }
    Log::Info("rank %d recv\n", net->rank());
    // CHECK(strcmp(msg->data()[0].data(), hi) == 0);
    std::vector<Blob>& recv_data = msg->data();
    CHECK(recv_data.size() == 3);
    for (int i = 0; i < msg->size(); ++i) {
      Log::Info("%s\n", recv_data[i].data());
    }

    msg.reset(new Message());
    msg->set_src(net->rank());
    msg->set_dst(0);
    msg->Push(Blob(hi1, 13));
    msg->Push(Blob(hi2, 11));
    msg->Push(Blob(hi3, 18));
    net->Send(msg);
    Log::Info("rank %d send\n", net->rank());
  }
  // while (!net->Test()) {
  //  // wait all message process finished
  // }

  net->Finalize();
}

void TestIP() {
  std::unordered_set<std::string> ip_list;
  // net::GetLocalIPAddress(&ip_list);
  for (auto ip : ip_list) Log::Info("%s\n", ip.c_str());
}

void TestNoNet(int argc, char* argv[]) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided);

  MPI_Barrier(MPI_COMM_WORLD);
  MV_Init(&argc, argv);

  ArrayWorker<float>* shared_array = new ArrayWorker<float>(ARRAY_SIZE);
  ArrayServer<float>* server_array = new ArrayServer<float>(ARRAY_SIZE);
  std::thread* m_prefetchThread = nullptr;
  MV_Barrier();
  Log::Info("Create tables OK\n");

  std::vector<float> delta(ARRAY_SIZE);
  while (true){
    if (m_prefetchThread != nullptr && m_prefetchThread->joinable())
    {
      m_prefetchThread->join();
      delete m_prefetchThread;
      m_prefetchThread = nullptr;
    }

    std::fill(delta.begin(), delta.end(), 0);
    for (int i = 0; i < ARRAY_SIZE; ++i)
    {
      std::mt19937_64 eng{ std::random_device{}() };
      std::uniform_real_distribution<float> dist{ -1, 1 };
      delta[i] = dist(eng);
    }
    m_prefetchThread = new std::thread([&](){

      //std::mt19937_64 eng{ std::random_device{}() };
      //std::uniform_int_distribution<> dist{ 50, 500 };
      //std::this_thread::sleep_for(std::chrono::milliseconds{ dist(eng) });
      shared_array->Add(delta.data(), ARRAY_SIZE);
      shared_array->Get(delta.data(), ARRAY_SIZE);
      Log::Info("Rank %d Get OK\n", MV_Rank());
      for (int i = 0; i < 10; ++i)
        std::cout << delta[i] << " "; std::cout << std::endl;
    });

    //shared_array->Get(data, 10);
    MV_Barrier();

  }
  MV_ShutDown();
}

void TestComm(int argc, char* argv[]) {

}

int main(int argc, char* argv[]) {
  Log::ResetLogLevel(LogLevel::Debug);
  if (argc == 2) {
    if (strcmp(argv[1], "kv") == 0) TestKV(argc, argv);
    else if (strcmp(argv[1], "array") == 0) TestArray(argc, argv);
    else if (strcmp(argv[1], "net") == 0) TestNet(argc, argv);
    else if (strcmp(argv[1], "ip") == 0) TestIP();
	else if (strcmp(argv[1], "momentum") == 0) TestMomentum(argc, argv);
	else if (strcmp(argv[1], "threads") == 0) TestMultipleThread(argc, argv);
  else if (strcmp(argv[1], "nonet") == 0) TestNoNet(argc, argv);
    else CHECK(false);
  }
  // argc == 4 is for zeromq test, with two extra arguments: machinefile, port
  else if (argc == 4) {
    if (strcmp(argv[3], "kv") == 0) TestKV(argc, argv);
    else if (strcmp(argv[3], "array") == 0) TestArray(argc, argv);
    else if (strcmp(argv[3], "net") == 0) TestNet(argc, argv);
    else if (strcmp(argv[3], "ip") == 0) TestIP();
  } else {
    TestArray(argc, argv);
  }
  return 0;
}
<commit_msg>to make the test net works. little tricky calling of the async send<commit_after>#include <iostream>
#include <thread>
#include <random>
#include <chrono>

#include <mpi.h>

#include <multiverso/multiverso.h>
#include <multiverso/net.h>
#include <multiverso/util/log.h>
#include <multiverso/util/net_util.h>

#include <multiverso/table/smooth_array_table.h>
#include <multiverso/table/array_table.h>
#include <multiverso/table/kv_table.h>
#include <MPIWrapper.h>
using namespace multiverso;

void TestKV(int argc, char* argv[]) {
  Log::Info("Test KV map \n");
  // ----------------------------------------------------------------------- //
  // this is a demo of distributed hash table to show how to use the multiverso
  // ----------------------------------------------------------------------- //

  // 1. Start the Multiverso engine ---------------------------------------- //
  MV_Init(&argc, argv);

  // 2. To create the shared table ----------------------------------------- //

  // TODO(feiga): This table must be create at both worker and server endpoint
  // simultaneously, since they should share same type and same created order
  // (same order means same table id). So it's better to create them with some
  // specific creator, instead of current way

  // TODO(feiga): should add some if statesment
  // if the node is worker, then create a worker cache table
  KVWorkerTable<int, int>* dht = new KVWorkerTable<int, int>();
  // if the node is server, then create a server storage table
  KVServerTable<int, int>* server_dht = new KVServerTable<int, int>();

  MV_Barrier();

  // 3. User program ------------------------------------------------------- //

  // all this interface is related with the KVWorkerTable
  // the data structure and the interface can be both defined by users
  // We also provides several common implementations
  // For specific program, user-defined table may provides better performance

  // access the local cache
  std::unordered_map<int, int>& kv = dht->raw();

  // The Get/Add are sync operation, when the function call returns, we already
  // Get from server, or the server has Added the update

  // Get from the server
  dht->Get(0);
  // Check the result. Since no one added, this should be 0
  Log::Info("Get 0 from kv server: result = %d\n", kv[0]);

  // Add 1 to the server
  dht->Add(0, 1);

  // Check the result. Since just added one, this should be 1
  dht->Get(0);

  Log::Info("Get 0 from kv server after add 1: result = %d\n", kv[0]);

  // 4. Shutdown the Multiverso engine. ------------------------------------ //
  MV_ShutDown();
}

void TestArray(int argc, char* argv[]) {
  Log::Info("Test Array \n");

  MV_Init(&argc, argv);

  ArrayWorker<float>* shared_array = new ArrayWorker<float>(1000000);
  ArrayServer<float>* server_array = new ArrayServer<float>(1000000);

  MV_Barrier();
  Log::Info("Create tables OK\n");

  int iter = 1000;
  if (argc == 3) iter = atoi(argv[2]);

  for (int i = 0; i < iter; ++i) {
  // std::vector<float>& vec = shared_array->raw();

  // shared_array->Get();
    float* data = new float[1000000];

    std::vector<float> delta(1000000);
    for (int i = 0; i < 1000000; ++i)
      delta[i] = static_cast<float>(i);

    shared_array->Add(delta.data(), 1000000);

    Log::Info("Rank %d Add OK\n", MV_Rank());

    shared_array->Get(data, 1000000);
    Log::Info("Rank %d Get OK\n", MV_Rank());
    for (int i = 0; i < 10; ++i)
      std::cout << data[i] << " "; std::cout << std::endl;
    MV_Barrier();

  }
  MV_ShutDown();
}

void TestMomentum(int argc, char* argv[]) {
	Log::Info("Test smooth_gradient table \n");

	Log::ResetLogLevel(LogLevel::Debug);
	MV_Init();

	SmoothArrayWorker<float>* shared_array = new SmoothArrayWorker<float>(10);
	SmoothArrayServer<float>* server_array = new SmoothArrayServer<float>(10);

	MV_Barrier();
	Log::Info("Create tables OK\n");

	while (true){
		// std::vector<float>& vec = shared_array->raw();

		// shared_array->Get();
		float data[10];

		std::vector<float> delta(10);
		for (int i = 0; i < 10; ++i)
			delta[i] = static_cast<float>(i+1);

		shared_array->Add(delta.data(), 10, 0.5f);

		Log::Info("Rank %d Add OK\n", MV_Rank());

		shared_array->Get(data, 10);
		Log::Info("Rank %d Get OK\n", MV_Rank());
		for (int i = 0; i < 10; ++i)
			std::cout << data[i] << " "; std::cout << std::endl;
		MV_Barrier();

	}
	MV_ShutDown();
}

#define ARRAY_SIZE 4683776
void TestMultipleThread(int argc, char* argv[])
{
	Microsoft::MSR::CNTK::MPIWrapper *g_mpi = new Microsoft::MSR::CNTK::MPIWrapper();
	Log::Info("Test Multiple threads \n");
	std::mt19937_64 eng{ std::random_device{}() };
	std::uniform_int_distribution<> dist{ 5, 10000 };
	std::this_thread::sleep_for(std::chrono::milliseconds{ dist(eng) });
	//Log::ResetLogLevel(LogLevel::Debug);
	MV_Init(&argc, argv);

	ArrayWorker<float>* shared_array = new ArrayWorker<float>(ARRAY_SIZE);
	ArrayServer<float>* server_array = new ArrayServer<float>(ARRAY_SIZE);
	std::thread* m_prefetchThread = nullptr;
	MV_Barrier();
	Log::Info("Create tables OK\n");

	std::vector<float> delta(ARRAY_SIZE);
	while (true){
		if (m_prefetchThread != nullptr && m_prefetchThread->joinable())
		{
			m_prefetchThread->join();
			delete m_prefetchThread;
			m_prefetchThread = nullptr;
		}

		std::fill(delta.begin(), delta.end(), 0);
		for (int i = 0; i < ARRAY_SIZE; ++i)
		{
		std::mt19937_64 eng{ std::random_device{}() };
			std::uniform_real_distribution<float> dist{ -1, 1 };
			delta[i] = dist(eng);
		}
		m_prefetchThread = new std::thread([&](){

			//std::mt19937_64 eng{ std::random_device{}() };
			//std::uniform_int_distribution<> dist{ 50, 500 };
			//std::this_thread::sleep_for(std::chrono::milliseconds{ dist(eng) });
			shared_array->Add(delta.data(), ARRAY_SIZE);
			shared_array->Get(delta.data(), ARRAY_SIZE);
			Log::Info("Rank %d Get OK\n", MV_Rank());
			for (int i = 0; i < 10; ++i)
				std::cout << delta[i] << " "; std::cout << std::endl;
		});

		//shared_array->Get(data, 10);
		MV_Barrier();

	}
	MV_ShutDown();
}

void TestNet(int argc, char* argv[]) {
  NetInterface* net = NetInterface::Get();
  net->Init(&argc, argv);

  const char* chi1 = std::string("hello, world").c_str();
  const char* chi2 = std::string("hello, c++").c_str();
  const char* chi3 = std::string("hello, multiverso").c_str();
  char* hi1 = new char[14];
  strcpy(hi1, chi1);
  char* hi2 = new char[12];
  strcpy(hi2, chi2);
  char* hi3 = new char[19];
  strcpy(hi3, chi3);
  if (net->rank() == 0) {
    for (int rank = 1; rank < net->size(); ++rank) {
      MessagePtr msg(new Message());// = std::make_unique<Message>();
      msg->set_src(0);
      msg->set_dst(rank);
      msg->Push(Blob(hi1, 13));
      msg->Push(Blob(hi2, 11));
      msg->Push(Blob(hi3, 18));
      while (net->Send(msg) == 0) ;
      Log::Info("rank 0 send\n");
    }

    for (int i = 1; i < net->size(); ++i) {
      MessagePtr msg(new Message());
      msg.reset(new Message());
      while (net->Recv(&msg) == 0) {
        // Log::Info("recv return 0\n");
      }
      Log::Info("rank 0 recv\n");
      // CHECK(strcmp(msg->data()[0].data(), hi) == 0);
      std::vector<Blob> recv_data = msg->data();
      CHECK(recv_data.size() == 3);
      for (int i = 0; i < msg->size(); ++i) {
        Log::Info("recv from srv %d: %s\n", msg->src(), recv_data[i].data());
      };
    }
  } else {// other rank
    MessagePtr msg(new Message());// = std::make_unique<Message>();
    while (net->Recv(&msg) == 0) {
      // Log::Info("recv return 0\n");
    }
    Log::Info("rank %d recv\n", net->rank());
    // CHECK(strcmp(msg->data()[0].data(), hi) == 0);
    std::vector<Blob>& recv_data = msg->data();
    CHECK(recv_data.size() == 3);
    for (int i = 0; i < msg->size(); ++i) {
      Log::Info("%s\n", recv_data[i].data());
    }

    msg.reset(new Message());
    msg->set_src(net->rank());
    msg->set_dst(0);
    msg->Push(Blob(hi1, 13));
    msg->Push(Blob(hi2, 11));
    msg->Push(Blob(hi3, 18));
    while (net->Send(msg) == 0) ;
    Log::Info("rank %d send\n", net->rank());
  }
  // while (!net->Test()) {
  //  // wait all message process finished
  // }

  net->Finalize();
}

void TestIP() {
  std::unordered_set<std::string> ip_list;
  // net::GetLocalIPAddress(&ip_list);
  for (auto ip : ip_list) Log::Info("%s\n", ip.c_str());
}

void TestNoNet(int argc, char* argv[]) {
  int provided;
  MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided);

  MPI_Barrier(MPI_COMM_WORLD);
  MV_Init(&argc, argv);

  ArrayWorker<float>* shared_array = new ArrayWorker<float>(ARRAY_SIZE);
  ArrayServer<float>* server_array = new ArrayServer<float>(ARRAY_SIZE);
  std::thread* m_prefetchThread = nullptr;
  MV_Barrier();
  Log::Info("Create tables OK\n");

  std::vector<float> delta(ARRAY_SIZE);
  while (true){
    if (m_prefetchThread != nullptr && m_prefetchThread->joinable())
    {
      m_prefetchThread->join();
      delete m_prefetchThread;
      m_prefetchThread = nullptr;
    }

    std::fill(delta.begin(), delta.end(), 0);
    for (int i = 0; i < ARRAY_SIZE; ++i)
    {
      std::mt19937_64 eng{ std::random_device{}() };
      std::uniform_real_distribution<float> dist{ -1, 1 };
      delta[i] = dist(eng);
    }
    m_prefetchThread = new std::thread([&](){

      //std::mt19937_64 eng{ std::random_device{}() };
      //std::uniform_int_distribution<> dist{ 50, 500 };
      //std::this_thread::sleep_for(std::chrono::milliseconds{ dist(eng) });
      shared_array->Add(delta.data(), ARRAY_SIZE);
      shared_array->Get(delta.data(), ARRAY_SIZE);
      Log::Info("Rank %d Get OK\n", MV_Rank());
      for (int i = 0; i < 10; ++i)
        std::cout << delta[i] << " "; std::cout << std::endl;
    });

    //shared_array->Get(data, 10);
    MV_Barrier();

  }
  MV_ShutDown();
}

void TestComm(int argc, char* argv[]) {

}

int main(int argc, char* argv[]) {
  Log::ResetLogLevel(LogLevel::Debug);
  if (argc == 2) {
    if (strcmp(argv[1], "kv") == 0) TestKV(argc, argv);
    else if (strcmp(argv[1], "array") == 0) TestArray(argc, argv);
    else if (strcmp(argv[1], "net") == 0) TestNet(argc, argv);
    else if (strcmp(argv[1], "ip") == 0) TestIP();
	else if (strcmp(argv[1], "momentum") == 0) TestMomentum(argc, argv);
	else if (strcmp(argv[1], "threads") == 0) TestMultipleThread(argc, argv);
  else if (strcmp(argv[1], "nonet") == 0) TestNoNet(argc, argv);
    else CHECK(false);
  }
  // argc == 4 is for zeromq test, with two extra arguments: machinefile, port
  else if (argc == 4) {
    if (strcmp(argv[3], "kv") == 0) TestKV(argc, argv);
    else if (strcmp(argv[3], "array") == 0) TestArray(argc, argv);
    else if (strcmp(argv[3], "net") == 0) TestNet(argc, argv);
    else if (strcmp(argv[3], "ip") == 0) TestIP();
  } else {
    TestArray(argc, argv);
  }
  return 0;
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

#include <iostream>
#include <cstdlib>

#include "RtMidi.h"

#include "ctlra.h"

static volatile uint32_t done;
static struct ctlra_dev_t* dev;

void demo_feedback_func(struct ctlra_dev_t *dev, void *d)
{
	/* feedback like LEDs and Screen drawing based on application
	 * state goes here. No events should be sent to the application
	 * from this function - one-way App->Ctlra updates only */
}

void demo_event_func(struct ctlra_dev_t* dev,
                     uint32_t num_events,
                     struct ctlra_event_t** events,
                     void *userdata)
{
	/* Events from the Ctlra device are handled here. They should be
	 * decoded, and events sent to the application. Note that this
	 * function must *NOT* send feedback to the device. Instead, the
	 * feedback_func() above should be used to send feedback */

	/* See below, a RtMidiOut instance is passed as the device's
	 * userdata pointer when registering the event_func */
	RtMidiOut *midiout = (RtMidiOut *)userdata;

	std::vector<unsigned char> message(3);

	for(uint32_t i = 0; i < num_events; i++) {
		const char *pressed = 0;
		struct ctlra_event_t *e = events[i];
		const char *name = 0;
		switch(e->type) {
		case CTLRA_EVENT_BUTTON:
			name = ctlra_dev_control_get_name(dev, CTLRA_EVENT_BUTTON, e->button.id);
			printf("[%s] button %s (%d)\n",
			       e->button.pressed ? " X " : "   ",
			       name, e->button.id);
			message[0] = e->button.pressed ? 0x90 : 0x80;
			message[1] = 60 + e->button.id;
			message[2] = e->button.pressed ? 0x70 : 0;
			midiout->sendMessage( &message );
			break;

		case CTLRA_EVENT_ENCODER:
			name = ctlra_dev_control_get_name(dev, CTLRA_EVENT_ENCODER,  e->button.id);
			printf("[%s] encoder %s (%d)\n",
			       e->encoder.delta > 0 ? " ->" : "<- ",
			       name, e->button.id);
			break;

		case CTLRA_EVENT_SLIDER:
			name = ctlra_dev_control_get_name(dev, CTLRA_EVENT_SLIDER, e->button.id);
			printf("[%03d] slider %s (%d)\n",
			       (int)(e->slider.value * 100.f),
			       name, e->slider.id);
			message[0] = 0xb0;
			message[1] = e->slider.id;
			message[2] = int(e->slider.value * 127.f);
			midiout->sendMessage( &message );
			break;

		case CTLRA_EVENT_GRID:
			static const char* grid_pressed[] = { " X ", "   " };
			name = ctlra_dev_control_get_name(dev, CTLRA_EVENT_GRID,
			                                  e->button.id);
			if(e->grid.flags & CTLRA_EVENT_GRID_FLAG_BUTTON) {
				pressed = grid_pressed[e->grid.pressed];
			} else {
				pressed = "---";
			}
			printf("[%s] grid %d", pressed, e->grid.pos);
			if(e->grid.flags & CTLRA_EVENT_GRID_FLAG_PRESSURE)
				printf(", pressure %1.3f", e->grid.pressure);
			printf("\n");
			message[0] = e->grid.pressed ? 0x90 : 0x80;
			message[1] = e->grid.pos + 36; /* default GM drum
							  mapping */
			message[2] = e->grid.pressed ? 0x70 : 0;
			midiout->sendMessage( &message );
			break;
		default:
			break;
		};
	}

	ctlra_dev_light_flush(dev, 0);
}

void sighndlr(int signal)
{
	done = 1;
	printf("\n");
}

void remove_dev_func(struct ctlra_dev_t *dev, int unexpected_removal,
		     void *userdata)
{
	RtMidiOut *midiout = (RtMidiOut *)userdata;
	delete midiout;
}

int accept_dev_func(const struct ctlra_dev_info_t *info,
                    ctlra_event_func *event_func,
                    ctlra_feedback_func *feedback_func,
                    ctlra_remove_dev_func *remove_func,
                    void **userdata_for_event_func,
                    void *userdata)
{
	printf("daemon: accepting %s %s\n", info->vendor, info->device);

	*event_func = demo_event_func;
	*feedback_func = demo_feedback_func;
	*remove_func = remove_dev_func;

	/* MIDI output */
	RtMidiOut *midiout = new RtMidiOut(RtMidi::UNSPECIFIED, "Ctlra");
	unsigned int nPorts = midiout->getPortCount();
	if ( nPorts == 0 ) {
		std::cout << "No ports available!\n";
		return 0;
	}

	try {
		midiout->openVirtualPort(info->device);
	} catch (...) {
		printf("CtlrError: failed to open virtual midi port\n");
		return -1;
	}
	*userdata_for_event_func = midiout;

	return 1;
}

int main()
{
	signal(SIGINT, sighndlr);

	struct ctlra_t *ctlra = ctlra_create(NULL);
	int num_devs = ctlra_probe(ctlra, accept_dev_func, 0x0);

	while(!done) {
		ctlra_idle_iter(ctlra);
		usleep(10 * 1000);
	}

	ctlra_exit(ctlra);

	return 0;
}
<commit_msg>daemon: remove prints<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

#include <iostream>
#include <cstdlib>

#include "RtMidi.h"

#include "ctlra.h"

static volatile uint32_t done;
static struct ctlra_dev_t* dev;

void demo_feedback_func(struct ctlra_dev_t *dev, void *d)
{
	/* feedback like LEDs and Screen drawing based on application
	 * state goes here. No events should be sent to the application
	 * from this function - one-way App->Ctlra updates only */
}

void demo_event_func(struct ctlra_dev_t* dev,
                     uint32_t num_events,
                     struct ctlra_event_t** events,
                     void *userdata)
{
	/* Events from the Ctlra device are handled here. They should be
	 * decoded, and events sent to the application. Note that this
	 * function must *NOT* send feedback to the device. Instead, the
	 * feedback_func() above should be used to send feedback */

	/* See below, a RtMidiOut instance is passed as the device's
	 * userdata pointer when registering the event_func */
	RtMidiOut *midiout = (RtMidiOut *)userdata;

	std::vector<unsigned char> message(3);

	for(uint32_t i = 0; i < num_events; i++) {
		const char *pressed = 0;
		struct ctlra_event_t *e = events[i];
		switch(e->type) {
		case CTLRA_EVENT_BUTTON:
			message[0] = e->button.pressed ? 0x90 : 0x80;
			message[1] = 60 + e->button.id;
			message[2] = e->button.pressed ? 0x70 : 0;
			midiout->sendMessage( &message );
			break;

		case CTLRA_EVENT_ENCODER:
			break;

		case CTLRA_EVENT_SLIDER:
			message[0] = 0xb0;
			message[1] = e->slider.id;
			message[2] = int(e->slider.value * 127.f);
			midiout->sendMessage( &message );
			break;

		case CTLRA_EVENT_GRID:
			message[0] = e->grid.pressed ? 0x90 : 0x80;
			message[1] = e->grid.pos + 36; /* GM drum mapping
							  kick drum note */
			message[2] = e->grid.pressed ? 0x70 : 0;
			midiout->sendMessage( &message );
			break;
		default:
			break;
		};
	}

	ctlra_dev_light_flush(dev, 0);
}

void sighndlr(int signal)
{
	done = 1;
	printf("\n");
}

void remove_dev_func(struct ctlra_dev_t *dev, int unexpected_removal,
		     void *userdata)
{
	RtMidiOut *midiout = (RtMidiOut *)userdata;
	delete midiout;
}

int accept_dev_func(const struct ctlra_dev_info_t *info,
                    ctlra_event_func *event_func,
                    ctlra_feedback_func *feedback_func,
                    ctlra_remove_dev_func *remove_func,
                    void **userdata_for_event_func,
                    void *userdata)
{
	printf("daemon: accepting %s %s\n", info->vendor, info->device);

	*event_func = demo_event_func;
	*feedback_func = demo_feedback_func;
	*remove_func = remove_dev_func;

	/* MIDI output */
	RtMidiOut *midiout = new RtMidiOut(RtMidi::UNSPECIFIED, "Ctlra");
	unsigned int nPorts = midiout->getPortCount();
	if ( nPorts == 0 ) {
		std::cout << "No ports available!\n";
		return 0;
	}

	try {
		midiout->openVirtualPort(info->device);
	} catch (...) {
		printf("CtlrError: failed to open virtual midi port\n");
		return -1;
	}
	*userdata_for_event_func = midiout;

	return 1;
}

int main()
{
	signal(SIGINT, sighndlr);

	struct ctlra_t *ctlra = ctlra_create(NULL);
	int num_devs = ctlra_probe(ctlra, accept_dev_func, 0x0);

	while(!done) {
		ctlra_idle_iter(ctlra);
		usleep(10 * 1000);
	}

	ctlra_exit(ctlra);

	return 0;
}
<|endoftext|>


<commit_before>/**************************************************************************

 The MIT License (MIT)

 Copyright (c) 2015 Dmitry Sovetov

 https://github.com/dmsovetov

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

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

#include "Loaders.h"

DC_BEGIN_DREEMCHEST

namespace Scene {

// ------------------------------------------ ImageLoaderRAW ------------------------------------------ //

// ** ImageLoaderRAW::loadFromStream
bool ImageLoaderRAW::loadFromStream( AssetBundleWPtr assets, AssetWPtr asset, const Io::StreamPtr& stream )
{
	// Call the base loadFromStream to init the asset pointer
	if( !GenericAssetLoader::loadFromStream( assets, asset, stream ) ) {
		return false;
	}

	u16 width, height;
	u8  channels;

	// Read image info
	stream->read( &width, 2 );
	stream->read( &height, 2 );
	stream->read( &channels, 1 );

	// Read image pixels
	ByteArray pixels;
	pixels.resize( width * height * channels );
	stream->read( &pixels[0], pixels.size() );

	// Setup image asset
	m_asset->setWidth( width );
	m_asset->setHeight( height );
	m_asset->setBytesPerPixel( channels );
	m_asset->setMipLevelCount( 1 );
	m_asset->setMipLevel( 0, pixels );

	return true;
}

// ------------------------------------------ MeshLoaderRAW ------------------------------------------ //

// ** MeshLoaderRAW::loadFromStream
bool MeshLoaderRAW::loadFromStream( AssetBundleWPtr assets, AssetWPtr asset, const Io::StreamPtr& stream )
{
	// Call the base loadFromStream to init the asset pointer
	if( !GenericAssetLoader::loadFromStream( assets, asset, stream ) ) {
		return false;
	}

	// Read the total number of mesh chunks
	u32 chunkCount;
	stream->read( &chunkCount, 4 );

	// Set the total number of mesh chunks
	m_asset->setChunkCount( chunkCount );

	for( u32 i = 0; i < chunkCount; i++ ) {
		// Read the total number of vertices & indices
		u32 vertexCount, indexCount;
		stream->read( &vertexCount, 4 );
		stream->read( &indexCount, 4 );

		// Read vertex buffer
		Mesh::VertexBuffer vertices;
		vertices.resize( vertexCount );

		for( u32 j = 0; j < vertexCount; j++ ) {
			Mesh::Vertex* v = &vertices[i];

			stream->read( &v->position.x, sizeof( v->position ) );
			stream->read( &v->normal.x, sizeof( v->normal ) );
			stream->read( &v->uv[0].x, sizeof( v->uv[0] ) );
			stream->read( &v->uv[1].x, sizeof( v->uv[1] ) );
		}

		// Set chunk vertex buffer.
		m_asset->setVertexBuffer( i, vertices );

		// Read index buffer
		Mesh::IndexBuffer indices;
		indices.resize( indexCount );
		stream->read( &indices[0], indices.size() );

		// Set chunk index buffer
		m_asset->setIndexBuffer( i, indices );
	}

	// Update node bounds
	m_asset->updateBounds();

	return true;
}

// --------------------------------------- MaterialLoader --------------------------------------- //

// ** MaterialLoader::loadFromStream
bool MaterialLoader::loadFromStream( AssetBundleWPtr assets, AssetWPtr asset, const Io::StreamPtr& stream )
{
	// Call the base loadFromStream to init the asset pointer
	if( !GenericAssetLoader::loadFromStream( assets, asset, stream ) ) {
		return false;
	}

#ifdef HAVE_JSON
	String json;
	json.resize( stream->length() );
	stream->read( &json[0], stream->length() );

	Json::Reader reader;
	Json::Value root;

	if( !reader.parse( json, root ) ) {
		return false;
	}

	String      shader		   = root["shader"].asString();
	Json::Value diffuseColor   = root["colors"]["tint"] != Json::nullValue ? root["colors"]["tint"] : root["colors"]["diffuse"];
	Json::Value diffuseTexture = root["textures"]["diffuse"];
	Json::Value parameters = root["parameters"];

	if( shader.find( "cutout" ) != String::npos ) {
		m_asset->setRenderingMode( RenderCutout );
	}
	else if( shader.find( "transparent" ) != String::npos ) {
		m_asset->setRenderingMode( RenderTranslucent );
	}
	else if( shader.find( "additive" ) != String::npos ) {
		m_asset->setRenderingMode( RenderAdditive );
	}
	else {
		m_asset->setRenderingMode( RenderOpaque );
	}

	m_asset->setModel( Material::Phong );
	m_asset->setColor( Material::Diffuse, Rgba( diffuseColor[0].asFloat(), diffuseColor[1].asFloat(), diffuseColor[2].asFloat(), diffuseColor[3].asFloat() ) );
	m_asset->setTexture( Material::Diffuse, assets->find<Image>( diffuseTexture["asset"].asString() ) );

	return true;
#else
	return false;
#endif	/*	HAVE_JSON	*/
}

} // namespace Scene

DC_END_DREEMCHEST<commit_msg>Fixed raw mesh loader<commit_after>/**************************************************************************

 The MIT License (MIT)

 Copyright (c) 2015 Dmitry Sovetov

 https://github.com/dmsovetov

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

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

#include "Loaders.h"

DC_BEGIN_DREEMCHEST

namespace Scene {

// ------------------------------------------ ImageLoaderRAW ------------------------------------------ //

// ** ImageLoaderRAW::loadFromStream
bool ImageLoaderRAW::loadFromStream( AssetBundleWPtr assets, AssetWPtr asset, const Io::StreamPtr& stream )
{
	// Call the base loadFromStream to init the asset pointer
	if( !GenericAssetLoader::loadFromStream( assets, asset, stream ) ) {
		return false;
	}

	u16 width, height;
	u8  channels;

	// Read image info
	stream->read( &width, 2 );
	stream->read( &height, 2 );
	stream->read( &channels, 1 );

	// Read image pixels
	ByteArray pixels;
	pixels.resize( width * height * channels );
	stream->read( &pixels[0], pixels.size() );

	// Setup image asset
	m_asset->setWidth( width );
	m_asset->setHeight( height );
	m_asset->setBytesPerPixel( channels );
	m_asset->setMipLevelCount( 1 );
	m_asset->setMipLevel( 0, pixels );

	return true;
}

// ------------------------------------------ MeshLoaderRAW ------------------------------------------ //

// ** MeshLoaderRAW::loadFromStream
bool MeshLoaderRAW::loadFromStream( AssetBundleWPtr assets, AssetWPtr asset, const Io::StreamPtr& stream )
{
	// Call the base loadFromStream to init the asset pointer
	if( !GenericAssetLoader::loadFromStream( assets, asset, stream ) ) {
		return false;
	}

	// Read the total number of mesh chunks
	u32 chunkCount;
	stream->read( &chunkCount, 4 );

	// Set the total number of mesh chunks
	m_asset->setChunkCount( chunkCount );

	for( u32 i = 0; i < chunkCount; i++ ) {
		// Read the total number of vertices & indices
		u32 vertexCount, indexCount;
		stream->read( &vertexCount, 4 );
		stream->read( &indexCount, 4 );

		// Read vertex buffer
		Mesh::VertexBuffer vertices;
		vertices.resize( vertexCount );

		for( u32 j = 0; j < vertexCount; j++ ) {
			Mesh::Vertex* v = &vertices[j];

			stream->read( &v->position.x, sizeof( v->position ) );
			stream->read( &v->normal.x, sizeof( v->normal ) );
			stream->read( &v->uv[0].x, sizeof( v->uv[0] ) );
			stream->read( &v->uv[1].x, sizeof( v->uv[1] ) );
		}

		// Set chunk vertex buffer.
		m_asset->setVertexBuffer( i, vertices );

		// Read index buffer
		Mesh::IndexBuffer indices;
		indices.resize( indexCount );
		stream->read( &indices[0], indices.size() * sizeof( u16 ) );

		// Set chunk index buffer
		m_asset->setIndexBuffer( i, indices );
	}

	// Update node bounds
	m_asset->updateBounds();

	return true;
}

// --------------------------------------- MaterialLoader --------------------------------------- //

// ** MaterialLoader::loadFromStream
bool MaterialLoader::loadFromStream( AssetBundleWPtr assets, AssetWPtr asset, const Io::StreamPtr& stream )
{
	// Call the base loadFromStream to init the asset pointer
	if( !GenericAssetLoader::loadFromStream( assets, asset, stream ) ) {
		return false;
	}

#ifdef HAVE_JSON
	String json;
	json.resize( stream->length() );
	stream->read( &json[0], stream->length() );

	Json::Reader reader;
	Json::Value root;

	if( !reader.parse( json, root ) ) {
		return false;
	}

	String      shader		   = root["shader"].asString();
	Json::Value diffuseColor   = root["colors"]["tint"] != Json::nullValue ? root["colors"]["tint"] : root["colors"]["diffuse"];
	Json::Value diffuseTexture = root["textures"]["diffuse"];
	Json::Value parameters = root["parameters"];

	if( shader.find( "cutout" ) != String::npos ) {
		m_asset->setRenderingMode( RenderCutout );
	}
	else if( shader.find( "transparent" ) != String::npos ) {
		m_asset->setRenderingMode( RenderTranslucent );
	}
	else if( shader.find( "additive" ) != String::npos ) {
		m_asset->setRenderingMode( RenderAdditive );
	}
	else {
		m_asset->setRenderingMode( RenderOpaque );
	}

	m_asset->setModel( Material::Phong );
	m_asset->setColor( Material::Diffuse, Rgba( diffuseColor[0].asFloat(), diffuseColor[1].asFloat(), diffuseColor[2].asFloat(), diffuseColor[3].asFloat() ) );
	m_asset->setTexture( Material::Diffuse, assets->find<Image>( diffuseTexture["asset"].asString() ) );

	return true;
#else
	return false;
#endif	/*	HAVE_JSON	*/
}

} // namespace Scene

DC_END_DREEMCHEST<|endoftext|>


<commit_before>/*
 * lines.cpp
 *
 *  Created on: Oct 22, 2014
 *      Author: Carsten Uphoff (uphoff@mytum.de)
 */

#include <cmath>

#include <Canvas.hpp>
#include <Drawable.hpp>
#include <Color.hpp>
#include <Geometry.hpp>
#include <HorizontalLayout.hpp>
#include <VerticalLayout.hpp>
#include <GridLayout.hpp>
#include <Contour.hpp>
#include <ColorTable.hpp>
#include <OGLPlotter.hpp>
#include <FileBrowser.hpp>

#define NUM_POINTS 200

int main()
{
    double x[NUM_POINTS];
    double y[NUM_POINTS];
    double z[NUM_POINTS];
    double m[NUM_POINTS * NUM_POINTS];

    for (int i = 0; i < NUM_POINTS; ++i) {
        x[i] = i / static_cast<double>(NUM_POINTS);
        y[i] = sin(10.0 * x[i]);
        z[i] = cos(20.0 * x[i]);
    }
    for (int i = 0; i < NUM_POINTS; ++i) {
        for (int j = 0; j < NUM_POINTS; ++j) {
            m[i*NUM_POINTS+j] = sin(10.0 * x[i]) * cos(20.0 * x[j]);
        }
    }

    //! @todo should not stay here, only for testing
    hpl::FileBrowser fb;
    fb.addSearchPath("../fonts/");
    std::string fontPath = fb.getFontPath("inconsolata");
    std::cout << "Font: " << fontPath << std::endl;

    hpl::Canvas canvas/*("../fonts/inconsolata.font")*/;

    hpl::OGLPlotter plotter;
    canvas.connectToPlotter(&plotter);
    plotter.setBackgroundColor(hpl::Color(0.9f, 0.9f, 0.9f));

    hpl::HorizontalLayout& layout1 = canvas.addLayout<hpl::HorizontalLayout>();
    hpl::VerticalLayout& layout2 = canvas.addLayout<hpl::VerticalLayout>();

    hpl::CoordinateSystem& cs1 = canvas.addCoordinateSystem<hpl::CoordinateSystem>();
    cs1.setColor(hpl::Color(0.6f, 0.6f, 0.6f));
    hpl::Lines& plot1 = cs1.addPlot<hpl::Lines>(NUM_POINTS, x, y);
    plot1.setColor(hpl::Color(1.0f, 0.0f, 0.0f));

    hpl::CoordinateSystem& cs2 = canvas.addCoordinateSystem<hpl::CoordinateSystem>();
    hpl::Contour& plot2 = cs2.addPlot<hpl::Contour>(NUM_POINTS, x, x, m);

    hpl::CoordinateSystem& cs3 = canvas.addCoordinateSystem<hpl::CoordinateSystem>();
    hpl::Points& plot3 = cs3.addPlot<hpl::Points>(NUM_POINTS, x, z);
    plot3.setColor(hpl::Color(0.0f, 0.0f, 1.0f));
    hpl::Lines& plot4 = cs3.addPlot<hpl::Lines>(NUM_POINTS, x, y);
    plot4.setColor(hpl::Color(0.0f, 0.0f, 0.0f));

    canvas.addCoordinateSystemToLayout(cs1.id(), layout1.id());
    canvas.addLayoutToLayout(layout2.id(), layout1.id());
    canvas.addCoordinateSystemToLayout(cs2.id(), layout2.id());
    canvas.addCoordinateSystemToLayout(cs3.id(), layout2.id());

    hpl::sleep(1e6);

    plot2.setColorTable<hpl::ColorTable::BlueRed>(256);

    hpl::sleep(1e6);

    layout2.changeOrientation(hpl::VerticalLayout::BottomToTop);

    hpl::sleep(1e6);

    layout1.changeOrientation(hpl::HorizontalLayout::RightToLeft);
    plot2.setColorTable<hpl::ColorTable::RainbowBlack>(256);

    //canvas.saveToFile("testoutput");
    plotter.wait();

    return 0;
}

<commit_msg>Forgot to clean up<commit_after>/*
 * lines.cpp
 *
 *  Created on: Oct 22, 2014
 *      Author: Carsten Uphoff (uphoff@mytum.de)
 */

#include <cmath>

#include <Canvas.hpp>
#include <Drawable.hpp>
#include <Color.hpp>
#include <Geometry.hpp>
#include <HorizontalLayout.hpp>
#include <VerticalLayout.hpp>
#include <GridLayout.hpp>
#include <Contour.hpp>
#include <ColorTable.hpp>
#include <OGLPlotter.hpp>
#include <FileBrowser.hpp>

#define NUM_POINTS 200

int main()
{
    double x[NUM_POINTS];
    double y[NUM_POINTS];
    double z[NUM_POINTS];
    double m[NUM_POINTS * NUM_POINTS];

    for (int i = 0; i < NUM_POINTS; ++i) {
        x[i] = i / static_cast<double>(NUM_POINTS);
        y[i] = sin(10.0 * x[i]);
        z[i] = cos(20.0 * x[i]);
    }
    for (int i = 0; i < NUM_POINTS; ++i) {
        for (int j = 0; j < NUM_POINTS; ++j) {
            m[i*NUM_POINTS+j] = sin(10.0 * x[i]) * cos(20.0 * x[j]);
        }
    }

    //! @todo should not stay here, only for testing
    hpl::FileBrowser fb;
    fb.addSearchPath("../fonts/");
    std::string fontPath = fb.getFontPath("inconsolata");

    hpl::Canvas canvas/*("../fonts/inconsolata.font")*/;

    hpl::OGLPlotter plotter;
    canvas.connectToPlotter(&plotter);
    plotter.setBackgroundColor(hpl::Color(0.9f, 0.9f, 0.9f));

    hpl::HorizontalLayout& layout1 = canvas.addLayout<hpl::HorizontalLayout>();
    hpl::VerticalLayout& layout2 = canvas.addLayout<hpl::VerticalLayout>();

    hpl::CoordinateSystem& cs1 = canvas.addCoordinateSystem<hpl::CoordinateSystem>();
    cs1.setColor(hpl::Color(0.6f, 0.6f, 0.6f));
    hpl::Lines& plot1 = cs1.addPlot<hpl::Lines>(NUM_POINTS, x, y);
    plot1.setColor(hpl::Color(1.0f, 0.0f, 0.0f));

    hpl::CoordinateSystem& cs2 = canvas.addCoordinateSystem<hpl::CoordinateSystem>();
    hpl::Contour& plot2 = cs2.addPlot<hpl::Contour>(NUM_POINTS, x, x, m);

    hpl::CoordinateSystem& cs3 = canvas.addCoordinateSystem<hpl::CoordinateSystem>();
    hpl::Points& plot3 = cs3.addPlot<hpl::Points>(NUM_POINTS, x, z);
    plot3.setColor(hpl::Color(0.0f, 0.0f, 1.0f));
    hpl::Lines& plot4 = cs3.addPlot<hpl::Lines>(NUM_POINTS, x, y);
    plot4.setColor(hpl::Color(0.0f, 0.0f, 0.0f));

    canvas.addCoordinateSystemToLayout(cs1.id(), layout1.id());
    canvas.addLayoutToLayout(layout2.id(), layout1.id());
    canvas.addCoordinateSystemToLayout(cs2.id(), layout2.id());
    canvas.addCoordinateSystemToLayout(cs3.id(), layout2.id());

    hpl::sleep(1e6);

    plot2.setColorTable<hpl::ColorTable::BlueRed>(256);

    hpl::sleep(1e6);

    layout2.changeOrientation(hpl::VerticalLayout::BottomToTop);

    hpl::sleep(1e6);

    layout1.changeOrientation(hpl::HorizontalLayout::RightToLeft);
    plot2.setColorTable<hpl::ColorTable::RainbowBlack>(256);

    //canvas.saveToFile("testoutput");
    plotter.wait();

    return 0;
}

<|endoftext|>