<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2007 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <mapnik/libxml2_loader.hpp>

#include <mapnik/config_error.hpp>

#include <boost/utility.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/filesystem/operations.hpp>

#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/parserInternals.h>

#include <iostream>

using boost::property_tree::ptree;
using namespace std;

#define DEFAULT_OPTIONS (XML_PARSE_NOERROR | XML_PARSE_NOENT | XML_PARSE_NOBLANKS | XML_PARSE_DTDLOAD)

namespace mapnik
{
    class libxml2_loader : boost::noncopyable
    {
        public:
            libxml2_loader(const char *encoding = NULL, int options = DEFAULT_OPTIONS, const char *url = NULL) :
                ctx_( 0 ),
                encoding_( encoding ),
                options_( options ),
                url_( url )
            {
                LIBXML_TEST_VERSION;
                ctx_ = xmlNewParserCtxt();
                if ( ! ctx_ )
                {
                    throw std::runtime_error("Failed to create parser context.");
                }
            }

            ~libxml2_loader()
            {
                if (ctx_)
                {
                    xmlFreeParserCtxt(ctx_);
                }
            }

            void load( const std::string & filename, ptree & pt )
            {
                boost::filesystem::path path(filename);
                if ( ! boost::filesystem::exists( path ) ) {
                    throw config_error(string("Could not load map file '") +
                            filename + "': File does not exist");
                }

                xmlDocPtr doc = xmlCtxtReadFile(ctx_, filename.c_str(), encoding_, options_);

                if ( !doc )
                {
                    xmlError * error = xmlCtxtGetLastError( ctx_ );
                    std::ostringstream os;
                    os << "XML document not well formed";
                    if (error)
                    {
                        os << ": " << std::endl << error->message;
                        // remove CR
                        std::string msg = os.str().substr(0, os.str().size() - 1);
                        config_error ex( msg );

                        os.str("");
                        os << "in file '" << error->file << "' at line "
                            << error->line;

                        ex.append_context( os.str() );

                        throw ex;
                    }
                }

                /*
                   if ( ! ctx->valid )
                   {
                   std::clog << "### ERROR: Failed to validate DTD."
                   << std::endl;
                   }
                 */
                load(doc, pt);
            }

            void load( const int fd, ptree & pt )
            {
                xmlDocPtr doc = xmlCtxtReadFd(ctx_, fd, url_, encoding_, options_);
                load(doc, pt);
            }

            void load_string( const std::string & buffer, ptree & pt )
            {
                xmlDocPtr doc = xmlCtxtReadMemory(ctx_, buffer.data(), buffer.length(), url_, encoding_, options_);
                load(doc, pt);
            }

            void load( const xmlDocPtr doc, ptree & pt )
            {
                if ( !doc )
                {
                    xmlError * error = xmlCtxtGetLastError( ctx_ );
                    std::ostringstream os;
                    os << "XML document not well formed";
                    if (error)
                    {
                        os << ": " << std::endl << error->message;
                    }
                    throw config_error(os.str());
                }

                xmlNode * root = xmlDocGetRootElement( doc );
                if ( ! root ) {
                    throw config_error("XML document is empty.");
                }

                populate_tree( root, pt );
            }

        private:
            void append_attributes( xmlAttr * attributes, ptree & pt)
            {
                if (attributes)
                {
                    ptree::iterator it = pt.push_back( ptree::value_type( "<xmlattr>", ptree() ));
                    ptree & attr_list = it->second;
                    xmlAttr * cur_attr = attributes;
                    for (; cur_attr; cur_attr = cur_attr->next )
                    {
                        ptree::iterator it = attr_list.push_back(
                                ptree::value_type( (char*)cur_attr->name, ptree() ));
                        it->second.put_own( (char*) cur_attr->children->content );
                    }
                }
            }

            void populate_tree( xmlNode * node, ptree & pt )
            {
                xmlNode * cur_node = node;

                for (; cur_node; cur_node = cur_node->next )
                {
                    switch (cur_node->type)
                    {
                        case XML_ELEMENT_NODE:
                            {
                                ptree::iterator it = pt.push_back( ptree::value_type(
                                        (char*)cur_node->name, ptree() ));
                                append_attributes( cur_node->properties, it->second);
                                populate_tree( cur_node->children, it->second );
                            }
                            break;
                        case XML_TEXT_NODE:
                            pt.put_own( (char*) cur_node->content );
                            break;
                        case XML_COMMENT_NODE:
                            {
                                ptree::iterator it = pt.push_back(
                                        ptree::value_type( "<xmlcomment>", ptree() ));
                                it->second.put_own( (char*) cur_node->content );
                            }
                            break;
                        default:
                            break;

                    }
                }
            }

            xmlParserCtxtPtr ctx_;
            const char *encoding_;
            int options_;
            const char *url_;
    };

    void read_xml2( std::string const & filename, boost::property_tree::ptree & pt)
    {
        libxml2_loader loader;
        loader.load( filename, pt );
    }
    void read_xml2_string( std::string const & str, boost::property_tree::ptree & pt)
    {
        libxml2_loader loader;
        loader.load_string( str, pt );
    }

} // end of namespace mapnik
<commit_msg>improve formatting of error message during xml loading if document is not well formed<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2007 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <mapnik/libxml2_loader.hpp>

#include <mapnik/config_error.hpp>

#include <boost/utility.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/filesystem/operations.hpp>

#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/parserInternals.h>

#include <iostream>

using boost::property_tree::ptree;
using namespace std;

#define DEFAULT_OPTIONS (XML_PARSE_NOERROR | XML_PARSE_NOENT | XML_PARSE_NOBLANKS | XML_PARSE_DTDLOAD)

namespace mapnik
{
    class libxml2_loader : boost::noncopyable
    {
        public:
            libxml2_loader(const char *encoding = NULL, int options = DEFAULT_OPTIONS, const char *url = NULL) :
                ctx_( 0 ),
                encoding_( encoding ),
                options_( options ),
                url_( url )
            {
                LIBXML_TEST_VERSION;
                ctx_ = xmlNewParserCtxt();
                if ( ! ctx_ )
                {
                    throw std::runtime_error("Failed to create parser context.");
                }
            }

            ~libxml2_loader()
            {
                if (ctx_)
                {
                    xmlFreeParserCtxt(ctx_);
                }
            }

            void load( const std::string & filename, ptree & pt )
            {
                boost::filesystem::path path(filename);
                if ( ! boost::filesystem::exists( path ) ) {
                    throw config_error(string("Could not load map file '") +
                            filename + "': File does not exist");
                }

                xmlDocPtr doc = xmlCtxtReadFile(ctx_, filename.c_str(), encoding_, options_);

                if ( !doc )
                {
                    xmlError * error = xmlCtxtGetLastError( ctx_ );
                    std::ostringstream os;
                    os << "XML document not well formed";
                    if (error)
                    {
                        os << ": " << std::endl << error->message;
                        // remove CR
                        std::string msg = os.str().substr(0, os.str().size() - 1);
                        config_error ex( msg );

                        os.str("");
                        os << "(encountered in file '" << error->file << "' at line "
                            << error->line << ")";

                        ex.append_context( os.str() );

                        throw ex;
                    }
                }

                /*
                   if ( ! ctx->valid )
                   {
                   std::clog << "### ERROR: Failed to validate DTD."
                   << std::endl;
                   }
                 */
                load(doc, pt);
            }

            void load( const int fd, ptree & pt )
            {
                xmlDocPtr doc = xmlCtxtReadFd(ctx_, fd, url_, encoding_, options_);
                load(doc, pt);
            }

            void load_string( const std::string & buffer, ptree & pt )
            {
                xmlDocPtr doc = xmlCtxtReadMemory(ctx_, buffer.data(), buffer.length(), url_, encoding_, options_);
                load(doc, pt);
            }

            void load( const xmlDocPtr doc, ptree & pt )
            {
                if ( !doc )
                {
                    xmlError * error = xmlCtxtGetLastError( ctx_ );
                    std::ostringstream os;
                    os << "XML document not well formed";
                    if (error)
                    {
                        os << ": " << std::endl << error->message;
                    }
                    throw config_error(os.str());
                }

                xmlNode * root = xmlDocGetRootElement( doc );
                if ( ! root ) {
                    throw config_error("XML document is empty.");
                }

                populate_tree( root, pt );
            }

        private:
            void append_attributes( xmlAttr * attributes, ptree & pt)
            {
                if (attributes)
                {
                    ptree::iterator it = pt.push_back( ptree::value_type( "<xmlattr>", ptree() ));
                    ptree & attr_list = it->second;
                    xmlAttr * cur_attr = attributes;
                    for (; cur_attr; cur_attr = cur_attr->next )
                    {
                        ptree::iterator it = attr_list.push_back(
                                ptree::value_type( (char*)cur_attr->name, ptree() ));
                        it->second.put_own( (char*) cur_attr->children->content );
                    }
                }
            }

            void populate_tree( xmlNode * node, ptree & pt )
            {
                xmlNode * cur_node = node;

                for (; cur_node; cur_node = cur_node->next )
                {
                    switch (cur_node->type)
                    {
                        case XML_ELEMENT_NODE:
                            {
                                ptree::iterator it = pt.push_back( ptree::value_type(
                                        (char*)cur_node->name, ptree() ));
                                append_attributes( cur_node->properties, it->second);
                                populate_tree( cur_node->children, it->second );
                            }
                            break;
                        case XML_TEXT_NODE:
                            pt.put_own( (char*) cur_node->content );
                            break;
                        case XML_COMMENT_NODE:
                            {
                                ptree::iterator it = pt.push_back(
                                        ptree::value_type( "<xmlcomment>", ptree() ));
                                it->second.put_own( (char*) cur_node->content );
                            }
                            break;
                        default:
                            break;

                    }
                }
            }

            xmlParserCtxtPtr ctx_;
            const char *encoding_;
            int options_;
            const char *url_;
    };

    void read_xml2( std::string const & filename, boost::property_tree::ptree & pt)
    {
        libxml2_loader loader;
        loader.load( filename, pt );
    }
    void read_xml2_string( std::string const & str, boost::property_tree::ptree & pt)
    {
        libxml2_loader loader;
        loader.load_string( str, pt );
    }

} // end of namespace mapnik
<|endoftext|>


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

#include <cxxopts.hpp>
#include "cloginserver.h"
#include "config.h"
#include "logconsole.h"
#include "version.h"

namespace {
void DisplayTitle()
{
  auto console = Core::CLog::GetLogger(Core::log_type::GENERAL);
  if(auto log = console.lock())
  {
    log->notice( "--------------------------------" );
    log->notice( "        osIROSE 2 Alpha         " );
    log->notice( "  http://forum.dev-osrose.com/  " );
    log->notice( "--------------------------------" );
    log->notice( "Git Branch/Revision: {}/{}", GIT_BRANCH, GIT_COMMIT_HASH );
  }
}

void CheckUser()
{
#ifndef _WIN32
  auto console = Core::CLog::GetLogger(Core::log_type::GENERAL);
  if(auto log = console.lock())
  {
    if ((getuid() == 0) && (getgid() == 0)) {
      log->warn( "You are running as the root superuser." );
      log->warn( "It is unnecessary and unsafe to run with root privileges." );
    }
    std::this_thread::sleep_for(std::chrono::milliseconds(2000));
  }
#endif
}
}

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

  cxxopts::Options options("LoginServer", "OsIROSE Login Server");

  options.add_options()
  ("d,debug", "Enable extra debugging info")
  ("f,file",  "Config file path", cxxopts::value<std::string>(), "server.ini")
  ("l,level", "Logging level", cxxopts::value<int>())
  ("h,help",  "Print this help text")
  ;

  try {
  options.parse(argc, argv);

  if (options.count("help"))
  {
    std::cout << options.help({"", "Group"}) << std::endl;
    exit(0);
  }

  auto console = Core::CLog::GetLogger(Core::log_type::GENERAL);
  if(auto log = console.lock())
    log->notice( "Starting up server..." );

  Core::Config& config = Core::Config::getInstance();
  if( options.count("level") != 0 )
    Core::CLog::SetLevel((spdlog::level::level_enum)options["level"].as<int>());
  else
    Core::CLog::SetLevel((spdlog::level::level_enum)config.login_server().log_level());
  DisplayTitle();
  CheckUser();

  if(auto log = console.lock()) {
    if( options.count("level") != 0 )
      log->set_level((spdlog::level::level_enum)options["level"].as<int>());
    else
      log->set_level((spdlog::level::level_enum)config.login_server().log_level());
    log->trace("Trace logs are enabled.");
    log->debug("Debug logs are enabled.");
    log->info("Info logs are enabled.");
  }

  Core::NetworkThreadPool::GetInstance(config.serverdata().maxthreads());

  CLoginServer clientServer;
  CLoginServer iscServer(true);

  clientServer.Init(config.serverdata().ip(), config.login_server().clientport());
  clientServer.Listen();

  iscServer.Init(config.serverdata().ip(), config.login_server().iscport());
  iscServer.Listen();

  while (clientServer.IsActive()) {
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
  }

  if(auto log = console.lock())
    log->notice( "Server shutting down..." );
  Core::NetworkThreadPool::DeleteInstance();
  spdlog::drop_all();

  }
  catch (const cxxopts::option_not_exists_exception& ex) {
    std::cout << options.help({"", "Group"}) << std::endl;
    return 1;
  }
  catch (const spdlog::spdlog_ex& ex) {
     std::cout << "Log failed: " << ex.what() << std::endl;
  }
  return 0;
}
<commit_msg>Moved command line options into its own function. Added new command line options to override the config file<commit_after>// Copyright 2016 Chirstopher Torres (Raven), L3nn0x
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http ://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <cxxopts.hpp>
#include "cloginserver.h"
#include "config.h"
#include "logconsole.h"
#include "version.h"

namespace {
void DisplayTitle()
{
  auto console = Core::CLog::GetLogger(Core::log_type::GENERAL);
  if(auto log = console.lock())
  {
    log->notice( "--------------------------------" );
    log->notice( "        osIROSE 2 Alpha         " );
    log->notice( "  http://forum.dev-osrose.com/  " );
    log->notice( "--------------------------------" );
    log->notice( "Git Branch/Revision: {}/{}", GIT_BRANCH, GIT_COMMIT_HASH );
  }
}

void CheckUser()
{
#ifndef _WIN32
  auto console = Core::CLog::GetLogger(Core::log_type::GENERAL);
  if(auto log = console.lock())
  {
    if ((getuid() == 0) && (getgid() == 0)) {
      log->warn( "You are running as the root superuser." );
      log->warn( "It is unnecessary and unsafe to run with root privileges." );
    }
    std::this_thread::sleep_for(std::chrono::milliseconds(2000));
  }
#endif
}

void ParseCommandLine(int argc, char** argv)
{
  cxxopts::Options options(argv[0], "osIROSE login server");

  try {
    std::string config_file_path = "";
    options.add_options()
    ("f,file",  "Config file path", cxxopts::value<std::string>(config_file_path)
      ->default_value("server.ini"), "FILE_PATH")
    ("l,level", "Logging level (0-9)", cxxopts::value<int>()
      ->default_value("3"), "LEVEL")
    ("ip", "Client listen IP Address", cxxopts::value<std::string>()
      ->default_value("0.0.0.0"), "IP")
    ("port", "Client listen port", cxxopts::value<int>()
      ->default_value("29000"), "PORT")
    ("iscip", "ISC listen IP Address", cxxopts::value<std::string>()
      ->default_value("127.0.0.1"), "IP")
    ("iscport", "ISC listen port", cxxopts::value<int>()
      ->default_value("29010"), "PORT")
    ("t,maxthreads", "Max thread count", cxxopts::value<int>()
      ->default_value("512"), "COUNT")
    ("h,help",  "Print this help text")
    ;

    options.parse(argc, argv);

    // Check to see if the user wants to see the help text
    if (options.count("help"))
    {
      std::cout << options.help({"", "Group"}) << std::endl;
      exit(0);
    }

    Core::Config& config = Core::Config::getInstance(config_file_path);

    // We are using if checks here because we only want to override the config file if the option was supplied
    // Since this is a login server startup function we can get away with a little bit of overhead
    if( options.count("level") )
      config.mutable_login_server()->set_log_level( options["level"].as<int>() );

    if( options.count("ip") )
      config.mutable_serverdata()->set_ip( options["ip"].as<std::string>() );

    if( options.count("maxthreads") )
      config.mutable_serverdata()->set_maxthreads( options["maxthreads"].as<int>() );
  }
  catch (const cxxopts::OptionException& ex) {
    std::cout << ex.what() << std::endl;
    std::cout << options.help({"", "Group"}) << std::endl;
    exit(1);
  }
}
}

int main(int argc, char* argv[]) {
  try {
    ParseCommandLine(argc, argv);

    auto console = Core::CLog::GetLogger(Core::log_type::GENERAL);
    if(auto log = console.lock())
      log->notice( "Starting up server..." );

    Core::Config& config = Core::Config::getInstance();
    Core::CLog::SetLevel((spdlog::level::level_enum)config.login_server().log_level());
    DisplayTitle();
    CheckUser();

    if(auto log = console.lock()) {
      log->set_level((spdlog::level::level_enum)config.login_server().log_level());
      log->trace("Trace logs are enabled.");
      log->debug("Debug logs are enabled.");
      log->info("Info logs are enabled.");
    }

    Core::NetworkThreadPool::GetInstance(config.serverdata().maxthreads());

    CLoginServer clientServer;
    CLoginServer iscServer(true);

    clientServer.Init(config.serverdata().ip(), config.login_server().clientport());
    clientServer.Listen();

    iscServer.Init(config.serverdata().ip(), config.login_server().iscport());
    iscServer.Listen();

    while (clientServer.IsActive()) {
      std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }

    if(auto log = console.lock())
      log->notice( "Server shutting down..." );
    Core::NetworkThreadPool::DeleteInstance();
    spdlog::drop_all();

  }
  catch (const spdlog::spdlog_ex& ex) {
     std::cout << "Log failed: " << ex.what() << std::endl;
  }
  return 0;
}
<|endoftext|>


<commit_before>// SCOUT Navigation and Logic

#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>

// Pass data to USB serial via digital 3,2
SoftwareSerial mySerial(3, 2);

// Assign names to analog 0-3 for relay
int POS1 = A0;
int NEG1 = A1;
int POS2 = A2;
int NEG2 = A3;
int delayValue = 5000;

Adafruit_GPS GPS(&mySerial);

// Set GPSECHO to 'false' to turn off echoing the GPS data to the Serial console
// Set to 'true' if you want to debug and listen to the raw GPS sentences.
#define GPSECHO  true

// this keeps track of whether we're using the interrupt
// off by default!
boolean usingInterrupt = false;
void useInterrupt(boolean); // Func prototype keeps Arduino 0023 happy

void setup()
{

  // connect at 115200 baud to read GPS quickly
  // also spit it out
  Serial.begin(115200);
  Serial.println("GPS Initializing");

  // Initialize analog pins
  pinMode(POS1, OUTPUT);
  pinMode(NEG1, OUTPUT);
  pinMode(POS2, OUTPUT);
  pinMode(NEG2, OUTPUT);

  // With this relay, HIGH is OFF
  digitalWrite(POS1, HIGH);
  digitalWrite(NEG1, HIGH);
  digitalWrite(POS2, HIGH);
  digitalWrite(NEG2, HIGH);

  Serial.println("Initialized With High.");

  Serial.println("Turning Clockwise");
  digitalWrite(POS1, LOW);
  digitalWrite(NEG1, HIGH);
  digitalWrite(POS2, HIGH);
  digitalWrite(NEG2, LOW);

  delay(delayValue);

  Serial.println("Turning OFF");
  digitalWrite(POS1, HIGH);
  digitalWrite(NEG1, HIGH);
  digitalWrite(POS2, HIGH);
  digitalWrite(NEG2, HIGH);

  delay(delayValue);

  Serial.println("Turning Counter Clockwise");
  digitalWrite(POS1, HIGH);
  digitalWrite(NEG1, LOW);
  digitalWrite(POS2, LOW);
  digitalWrite(NEG2, HIGH);

  delay(delayValue);

  Serial.println("Turning OFF");
  digitalWrite(POS1, HIGH);
  digitalWrite(NEG1, HIGH);
  digitalWrite(POS2, HIGH);
  digitalWrite(NEG2, HIGH);

  delay(delayValue);

  // 9600 NMEA is the default baud rate for Adafruit MTK GPS's- some use 4800
  GPS.begin(9600);

  // uncomment this line to turn on RMC (recommended minimum) and GGA (fix data) including altitude
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);

  // Set the update rate
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);   // 1 Hz update rate

  // Request updates on antenna status, comment out to keep quiet
  GPS.sendCommand(PGCMD_ANTENNA);

  // 1 ms interrupt
  useInterrupt(true);

  delay(1000);
  // Ask for firmware version
  //mySerial.println(PMTK_Q_RELEASE);
}

// Interrupt is called once a millisecond, looks for any new GPS data, and stores it
SIGNAL(TIMER0_COMPA_vect) {
  char c = GPS.read();
  // if you want to debug, this is a good time to do it!
#ifdef UDR0
  if (GPSECHO)
    if (c) UDR0 = c;
    // writing direct to UDR0 is much much faster than Serial.print
    // but only one character can be written at a time.
#endif
}

void useInterrupt(boolean v) {
  if (v) {
    // Timer0 is already used for millis() - we'll just interrupt somewhere
    // in the middle and call the "Compare A" function above
    OCR0A = 0xAF;
    TIMSK0 |= _BV(OCIE0A);
    usingInterrupt = true;
  } else {
    // do not call the interrupt function COMPA anymore
    TIMSK0 &= ~_BV(OCIE0A);
    usingInterrupt = false;
  }
}

uint32_t timer = millis();
void loop()                     // run over and over again
{
  // in case you are not using the interrupt above, you'll

  if (! usingInterrupt) {
    // read data from the GPS in the 'main loop'
    char c = GPS.read();
    // if you want to debug, this is a good time to do it!

  }

  // if a sentence is received, we can check the checksum, parse it...
  if (GPS.newNMEAreceived()) {
    // a tricky thing here is if we print the NMEA sentence, or data
    // we end up not listening and catching other sentences!
    // so be very wary if using OUTPUT_ALLDATA and trytng to print out data
    //Serial.println(GPS.lastNMEA());   // this also sets the newNMEAreceived() flag to false

    if (!GPS.parse(GPS.lastNMEA()))   // this also sets the newNMEAreceived() flag to false
      return;  // we can fail to parse a sentence in which case we should just wait for another
  }

  // if millis() or timer wraps around, we'll just reset it
  if (timer > millis())  timer = millis();

  // approximately every 2 seconds or so, print out the current stats
  if (millis() - timer > 2000) {
    timer = millis(); // reset the timer

    Serial.print("Fix: "); Serial.print((int)GPS.fix);
    Serial.print(" quality: "); Serial.println((int)GPS.fixquality);
    if (GPS.fix) {
      Serial.print("Location: ");
      Serial.print(GPS.latitude, 4); Serial.print(GPS.lat);
      Serial.print(", ");
      Serial.print(GPS.longitude, 4); Serial.println(GPS.lon);
      Serial.print("Speed (knots): "); Serial.println(GPS.speed);
      Serial.print("Angle: "); Serial.println(GPS.angle);
      Serial.print("Altitude: "); Serial.println(GPS.altitude);
      Serial.print("Satellites: "); Serial.println((int)GPS.satellites);
    }
  }
}<commit_msg>Clean up instrument code<commit_after>// SCOUT Navigation and Logic

#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>

// Pass data to USB serial via digital 3,2
SoftwareSerial mySerial(3, 2);

// Assign names to analog 0-3 for relay
int POS1 = A0;
int NEG1 = A1;
int POS2 = A2;
int NEG2 = A3;
int delayValue = 5000;

Adafruit_GPS GPS(&mySerial);

// Set GPSECHO to 'false' to turn off echoing the GPS data to the Serial console
// Set to 'true' if you want to debug and listen to the raw GPS sentences.
#define GPSECHO  true

// this keeps track of whether we're using the interrupt
// off by default!
boolean usingInterrupt = false;
void useInterrupt(boolean); // Func prototype keeps Arduino 0023 happy

void setup()
{

  // connect at 115200 baud to read GPS quickly
  // also spit it out
  Serial.begin(115200);
  Serial.println("GPS Initializing");

  // Initialize analog pins
  pinMode(POS1, OUTPUT);
  pinMode(NEG1, OUTPUT);
  pinMode(POS2, OUTPUT);
  pinMode(NEG2, OUTPUT);

  // With this relay, HIGH is OFF
  digitalWrite(POS1, HIGH);
  digitalWrite(NEG1, HIGH);
  digitalWrite(POS2, HIGH);
  digitalWrite(NEG2, HIGH);

  Serial.println("Initialized With High.");

  Serial.println("Turning Clockwise");
  digitalWrite(POS1, LOW);
  digitalWrite(NEG1, HIGH);
  digitalWrite(POS2, HIGH);
  digitalWrite(NEG2, LOW);

  delay(delayValue);

  Serial.println("Turning OFF");
  digitalWrite(POS1, HIGH);
  digitalWrite(NEG1, HIGH);
  digitalWrite(POS2, HIGH);
  digitalWrite(NEG2, HIGH);

  delay(delayValue);

  Serial.println("Turning Counter Clockwise");
  digitalWrite(POS1, HIGH);
  digitalWrite(NEG1, LOW);
  digitalWrite(POS2, LOW);
  digitalWrite(NEG2, HIGH);

  delay(delayValue);

  Serial.println("Turning OFF");
  digitalWrite(POS1, HIGH);
  digitalWrite(NEG1, HIGH);
  digitalWrite(POS2, HIGH);
  digitalWrite(NEG2, HIGH);

  delay(delayValue);

  // 9600 NMEA is the default baud rate for Adafruit MTK GPS's- some use 4800
  GPS.begin(9600);

  // uncomment this line to turn on RMC (recommended minimum) and GGA (fix data) including altitude
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);

  // Set the update rate
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);   // 1 Hz update rate

  // Request updates on antenna status, comment out to keep quiet
  GPS.sendCommand(PGCMD_ANTENNA);

  // 1 ms interrupt
  useInterrupt(true);

  delay(1000);
  // Ask for firmware version
  //mySerial.println(PMTK_Q_RELEASE);
}

// Interrupt is called once a millisecond, looks for any new GPS data, and stores it
SIGNAL(TIMER0_COMPA_vect) {
  char c = GPS.read();
  // if you want to debug, this is a good time to do it!
#ifdef UDR0
  if (GPSECHO)
    if (c) UDR0 = c;
    // writing direct to UDR0
#endif
}

void useInterrupt(boolean v) {
  if (v) {
    // Timer0 is already used for millis() - we'll just interrupt somewhere
    // in the middle and call the "Compare A" function above
    OCR0A = 0xAF;
    TIMSK0 |= _BV(OCIE0A);
    usingInterrupt = true;
  } else {
    // do not call the interrupt function COMPA anymore
    TIMSK0 &= ~_BV(OCIE0A);
    usingInterrupt = false;
  }
}

uint32_t timer = millis();
void loop()
{

  if (! usingInterrupt) {
    // read data from the GPS in the 'main loop'
    char c = GPS.read();

  }

  // Determine if new statement received, if so, check the checksum, parse
  if (GPS.newNMEAreceived()) {

    if (!GPS.parse(GPS.lastNMEA()))   // this sets the newNMEAreceived() flag to false
      return;  // if miss statement, wait for
  }

  // if millis() or timer wraps around, reset it
  if (timer > millis())  timer = millis();

  //  Every 2 seconds, print out the current stats
  if (millis() - timer > 2000) {
    timer = millis(); // reset the timer

    Serial.print("Fix: "); Serial.print((int)GPS.fix);
    Serial.print(" quality: "); Serial.println((int)GPS.fixquality);
    if (GPS.fix) {
      Serial.print("Location: ");
      Serial.print(GPS.latitude, 4); Serial.print(GPS.lat);
      Serial.print(", ");
      Serial.print(GPS.longitude, 4); Serial.println(GPS.lon);
      Serial.print("Speed (knots): "); Serial.println(GPS.speed);
      Serial.print("Angle: "); Serial.println(GPS.angle);
      Serial.print("Altitude: "); Serial.println(GPS.altitude);
      Serial.print("Satellites: "); Serial.println((int)GPS.satellites);
    }
  }
}<|endoftext|>


<commit_before>//
// MessagePack for C++ static resolution routine
//
// Copyright (C) 2008-2009 FURUHASHI Sadayuki
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
//
#ifndef MSGPACK_TYPE_INT_HPP
#define MSGPACK_TYPE_INT_HPP

#include "msgpack/object.hpp"
#include <limits>

namespace msgpack {

namespace type {
namespace detail {
	template <typename T, bool Signed>
	struct convert_integer_sign;

	template <typename T>
	struct convert_integer_sign<T, true> {
		static inline T convert(object const& o) {
			if(o.type == type::POSITIVE_INTEGER) {
				if(o.via.u64 > (uint64_t)std::numeric_limits<T>::max())
					{ throw type_error(); }
				return (T)o.via.u64;
			} else if(o.type == type::NEGATIVE_INTEGER) {
				if(o.via.i64 < (int64_t)std::numeric_limits<T>::min())
					{ throw type_error(); }
				return (T)o.via.i64;
			}
			throw type_error();
		}
	};

	template <typename T>
	struct convert_integer_sign<T, false> {
		static inline T convert(object const& o) {
			if(o.type == type::POSITIVE_INTEGER) {
				if(o.via.u64 > (uint64_t)std::numeric_limits<T>::max())
					{ throw type_error(); }
				return (T)o.via.u64;
			}
			throw type_error();
		}
	};

	template <typename T>
	struct is_signed {
		static const bool value = std::numeric_limits<T>::is_signed;
	};

	template <typename T>
	static inline T convert_integer(object o)
	{
		return detail::convert_integer_sign<T, is_signed<T>::value>::convert(o);
	}

	template <bool Signed>
	struct pack_char_sign;

	template <>
	struct pack_char_sign<true> {
		template <typename Stream>
		static inline packer<Stream>& pack(packer<Stream>& o, char v) {
			o.pack_int8(v); return o;
		}
	};

	template <>
	struct pack_char_sign<false> {
		template <typename Stream>
		static inline packer<Stream>& pack(packer<Stream>& o, char v) {
			o.pack_uint8(v); return o;
		}
	};

	template <typename Stream>
	static inline packer<Stream>& pack_char(packer<Stream>& o, char v) {
		return pack_char_sign<is_signed<char>::value>::pack(o, v);
	}

	template <bool Signed>
	struct object_char_sign;

	template <>
	struct object_char_sign<true> {
		static inline void make(object& o, char v) {
			v < 0 ? o.type = type::NEGATIVE_INTEGER, o.via.i64 = v
				: o.type = type::POSITIVE_INTEGER, o.via.u64 = v;
		}
	};

	template <>
	struct object_char_sign<false> {
		static inline void make(object& o, char v) {
			o.type = type::POSITIVE_INTEGER, o.via.u64 = v;
		}
	};

	static inline void object_char(object& o, char v) {
		return object_char_sign<is_signed<char>::value>::make(o, v);
	}

}  // namespace detail
}  // namespace type

inline char& operator>> (object const& o, char& v)
	{ v = type::detail::convert_integer<char>(o); return v; }

inline signed char& operator>> (object const& o, signed char& v)
	{ v = type::detail::convert_integer<signed char>(o); return v; }

inline signed short& operator>> (object const& o, signed short& v)
	{ v = type::detail::convert_integer<signed short>(o); return v; }

inline signed int& operator>> (object const& o, signed int& v)
	{ v = type::detail::convert_integer<signed int>(o); return v; }

inline signed long& operator>> (object const& o, signed long& v)
	{ v = type::detail::convert_integer<signed long>(o); return v; }

inline signed long long& operator>> (object const& o, signed long long& v)
	{ v = type::detail::convert_integer<signed long long>(o); return v; }

inline unsigned char& operator>> (object const& o, unsigned char& v)
	{ v = type::detail::convert_integer<unsigned char>(o); return v; }

inline unsigned short& operator>> (object const& o, unsigned short& v)
	{ v = type::detail::convert_integer<unsigned short>(o); return v; }

inline unsigned int& operator>> (object const& o, unsigned int& v)
	{ v = type::detail::convert_integer<unsigned int>(o); return v; }

inline unsigned long& operator>> (object const& o, unsigned long& v)
	{ v = type::detail::convert_integer<unsigned long>(o); return v; }

inline unsigned long long& operator>> (object const& o, unsigned long long& v)
	{ v = type::detail::convert_integer<unsigned long long>(o); return v; }

template <typename Stream>
inline packer<Stream>& operator<< (packer<Stream>& o, char v)
	{ return type::detail::pack_char(o, v); }

template <typename Stream>
inline packer<Stream>& operator<< (packer<Stream>& o, signed char v)
	{ o.pack_int8(v); return o; }

template <typename Stream>
inline packer<Stream>& operator<< (packer<Stream>& o, signed short v)
	{ o.pack_short(v); return o; }

template <typename Stream>
inline packer<Stream>& operator<< (packer<Stream>& o, signed int v)
	{ o.pack_int(v); return o; }

template <typename Stream>
inline packer<Stream>& operator<< (packer<Stream>& o, signed long v)
	{ o.pack_long(v); return o; }

template <typename Stream>
inline packer<Stream>& operator<< (packer<Stream>& o, signed long long v)
	{ o.pack_long_long(v); return o; }

template <typename Stream>
inline packer<Stream>& operator<< (packer<Stream>& o, unsigned char v)
	{ o.pack_uint8(v); return o; }

template <typename Stream>
inline packer<Stream>& operator<< (packer<Stream>& o, unsigned short v)
	{ o.pack_unsigned_short(v); return o; }

template <typename Stream>
inline packer<Stream>& operator<< (packer<Stream>& o, unsigned int v)
	{ o.pack_unsigned_int(v); return o; }

template <typename Stream>
inline packer<Stream>& operator<< (packer<Stream>& o, unsigned long v)
	{ o.pack_unsigned_long(v); return o; }

template <typename Stream>
inline packer<Stream>& operator<< (packer<Stream>& o, unsigned long long v)
	{ o.pack_unsigned_long_long(v); return o; }

inline void operator<< (object& o, char v)
	{ type::detail::object_char(o, v); }

inline void operator<< (object& o, signed char v)
	{ v < 0 ? o.type = type::NEGATIVE_INTEGER, o.via.i64 = v : o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }

inline void operator<< (object& o, signed short v)
	{ v < 0 ? o.type = type::NEGATIVE_INTEGER, o.via.i64 = v : o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }

inline void operator<< (object& o, signed int v)
	{ v < 0 ? o.type = type::NEGATIVE_INTEGER, o.via.i64 = v : o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }

inline void operator<< (object& o, signed long v)
	{ v < 0 ? o.type = type::NEGATIVE_INTEGER, o.via.i64 = v : o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }

inline void operator<< (object& o, signed long long v)
	{ v < 0 ? o.type = type::NEGATIVE_INTEGER, o.via.i64 = v : o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }

inline void operator<< (object& o, unsigned char v)
	{ o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }

inline void operator<< (object& o, unsigned short v)
	{ o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }

inline void operator<< (object& o, unsigned int v)
	{ o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }

inline void operator<< (object& o, unsigned long v)
	{ o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }

inline void operator<< (object& o, unsigned long long v)
	{ o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }

inline void operator<< (object::with_zone& o, char v)
	{ static_cast<object&>(o) << v; }

inline void operator<< (object::with_zone& o, signed char v)
	{ static_cast<object&>(o) << v; }

inline void operator<< (object::with_zone& o, signed short v)
	{ static_cast<object&>(o) << v; }

inline void operator<< (object::with_zone& o, signed int v)
	{ static_cast<object&>(o) << v; }

inline void operator<< (object::with_zone& o, signed long v)
	{ static_cast<object&>(o) << v; }

inline void operator<< (object::with_zone& o, const signed long long& v)
	{ static_cast<object&>(o) << v; }

inline void operator<< (object::with_zone& o, unsigned char v)
	{ static_cast<object&>(o) << v; }

inline void operator<< (object::with_zone& o, unsigned short v)
	{ static_cast<object&>(o) << v; }

inline void operator<< (object::with_zone& o, unsigned int v)
	{ static_cast<object&>(o) << v; }

inline void operator<< (object::with_zone& o, unsigned long v)
	{ static_cast<object&>(o) << v; }

inline void operator<< (object::with_zone& o, const unsigned long long& v)
	{ static_cast<object&>(o) << v; }

}  // namespace msgpack

#endif /* msgpack/type/int.hpp */

<commit_msg>Supported 'plain' char. msgpack used to only support signed char and unsigned char.<commit_after>//
// MessagePack for C++ static resolution routine
//
// Copyright (C) 2008-2009 FURUHASHI Sadayuki
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
//
#ifndef MSGPACK_TYPE_INT_HPP
#define MSGPACK_TYPE_INT_HPP

#include "msgpack/object.hpp"
#include <limits>

namespace msgpack {

namespace type {
namespace detail {
	template <typename T, bool Signed>
	struct convert_integer_sign;

	template <typename T>
	struct convert_integer_sign<T, true> {
		static inline T convert(object const& o) {
			if(o.type == type::POSITIVE_INTEGER) {
				if(o.via.u64 > (uint64_t)std::numeric_limits<T>::max())
					{ throw type_error(); }
				return (T)o.via.u64;
			} else if(o.type == type::NEGATIVE_INTEGER) {
				if(o.via.i64 < (int64_t)std::numeric_limits<T>::min())
					{ throw type_error(); }
				return (T)o.via.i64;
			}
			throw type_error();
		}
	};

	template <typename T>
	struct convert_integer_sign<T, false> {
		static inline T convert(object const& o) {
			if(o.type == type::POSITIVE_INTEGER) {
				if(o.via.u64 > (uint64_t)std::numeric_limits<T>::max())
					{ throw type_error(); }
				return (T)o.via.u64;
			}
			throw type_error();
		}
	};

	template <typename T>
	struct is_signed {
		static const bool value = std::numeric_limits<T>::is_signed;
	};

	template <typename T>
	static inline T convert_integer(object const& o)
	{
		return detail::convert_integer_sign<T, is_signed<T>::value>::convert(o);
	}

	template <bool Signed>
	struct pack_char_sign;

	template <>
	struct pack_char_sign<true> {
		template <typename Stream>
		static inline packer<Stream>& pack(packer<Stream>& o, char v) {
			o.pack_int8(v); return o;
		}
	};

	template <>
	struct pack_char_sign<false> {
		template <typename Stream>
		static inline packer<Stream>& pack(packer<Stream>& o, char v) {
			o.pack_uint8(v); return o;
		}
	};

	template <typename Stream>
	static inline packer<Stream>& pack_char(packer<Stream>& o, char v) {
		return pack_char_sign<is_signed<char>::value>::pack(o, v);
	}

	template <bool Signed>
	struct object_char_sign;

	template <>
	struct object_char_sign<true> {
		static inline void make(object& o, char v) {
			v < 0 ? o.type = type::NEGATIVE_INTEGER, o.via.i64 = v
				  : o.type = type::POSITIVE_INTEGER, o.via.u64 = v;
		}
	};

	template <>
	struct object_char_sign<false> {
		static inline void make(object& o, char v) {
			o.type = type::POSITIVE_INTEGER, o.via.u64 = v;
		}
	};

	static inline void object_char(object& o, char v) {
		return object_char_sign<is_signed<char>::value>::make(o, v);
	}

}  // namespace detail
}  // namespace type

inline char& operator>> (object const& o, char& v)
	{ v = type::detail::convert_integer<char>(o); return v; }

inline signed char& operator>> (object const& o, signed char& v)
	{ v = type::detail::convert_integer<signed char>(o); return v; }

inline signed short& operator>> (object const& o, signed short& v)
	{ v = type::detail::convert_integer<signed short>(o); return v; }

inline signed int& operator>> (object const& o, signed int& v)
	{ v = type::detail::convert_integer<signed int>(o); return v; }

inline signed long& operator>> (object const& o, signed long& v)
	{ v = type::detail::convert_integer<signed long>(o); return v; }

inline signed long long& operator>> (object const& o, signed long long& v)
	{ v = type::detail::convert_integer<signed long long>(o); return v; }

inline unsigned char& operator>> (object const& o, unsigned char& v)
	{ v = type::detail::convert_integer<unsigned char>(o); return v; }

inline unsigned short& operator>> (object const& o, unsigned short& v)
	{ v = type::detail::convert_integer<unsigned short>(o); return v; }

inline unsigned int& operator>> (object const& o, unsigned int& v)
	{ v = type::detail::convert_integer<unsigned int>(o); return v; }

inline unsigned long& operator>> (object const& o, unsigned long& v)
	{ v = type::detail::convert_integer<unsigned long>(o); return v; }

inline unsigned long long& operator>> (object const& o, unsigned long long& v)
	{ v = type::detail::convert_integer<unsigned long long>(o); return v; }

template <typename Stream>
inline packer<Stream>& operator<< (packer<Stream>& o, char v)
	{ return type::detail::pack_char(o, v); }

template <typename Stream>
inline packer<Stream>& operator<< (packer<Stream>& o, signed char v)
	{ o.pack_int8(v); return o; }

template <typename Stream>
inline packer<Stream>& operator<< (packer<Stream>& o, signed short v)
	{ o.pack_short(v); return o; }

template <typename Stream>
inline packer<Stream>& operator<< (packer<Stream>& o, signed int v)
	{ o.pack_int(v); return o; }

template <typename Stream>
inline packer<Stream>& operator<< (packer<Stream>& o, signed long v)
	{ o.pack_long(v); return o; }

template <typename Stream>
inline packer<Stream>& operator<< (packer<Stream>& o, signed long long v)
	{ o.pack_long_long(v); return o; }

template <typename Stream>
inline packer<Stream>& operator<< (packer<Stream>& o, unsigned char v)
	{ o.pack_uint8(v); return o; }

template <typename Stream>
inline packer<Stream>& operator<< (packer<Stream>& o, unsigned short v)
	{ o.pack_unsigned_short(v); return o; }

template <typename Stream>
inline packer<Stream>& operator<< (packer<Stream>& o, unsigned int v)
	{ o.pack_unsigned_int(v); return o; }

template <typename Stream>
inline packer<Stream>& operator<< (packer<Stream>& o, unsigned long v)
	{ o.pack_unsigned_long(v); return o; }

template <typename Stream>
inline packer<Stream>& operator<< (packer<Stream>& o, unsigned long long v)
	{ o.pack_unsigned_long_long(v); return o; }

inline void operator<< (object& o, char v)
	{ type::detail::object_char(o, v); }

inline void operator<< (object& o, signed char v)
	{ v < 0 ? o.type = type::NEGATIVE_INTEGER, o.via.i64 = v : o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }

inline void operator<< (object& o, signed short v)
	{ v < 0 ? o.type = type::NEGATIVE_INTEGER, o.via.i64 = v : o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }

inline void operator<< (object& o, signed int v)
	{ v < 0 ? o.type = type::NEGATIVE_INTEGER, o.via.i64 = v : o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }

inline void operator<< (object& o, signed long v)
	{ v < 0 ? o.type = type::NEGATIVE_INTEGER, o.via.i64 = v : o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }

inline void operator<< (object& o, signed long long v)
	{ v < 0 ? o.type = type::NEGATIVE_INTEGER, o.via.i64 = v : o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }

inline void operator<< (object& o, unsigned char v)
	{ o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }

inline void operator<< (object& o, unsigned short v)
	{ o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }

inline void operator<< (object& o, unsigned int v)
	{ o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }

inline void operator<< (object& o, unsigned long v)
	{ o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }

inline void operator<< (object& o, unsigned long long v)
	{ o.type = type::POSITIVE_INTEGER, o.via.u64 = v; }

inline void operator<< (object::with_zone& o, char v)
	{ static_cast<object&>(o) << v; }

inline void operator<< (object::with_zone& o, signed char v)
	{ static_cast<object&>(o) << v; }

inline void operator<< (object::with_zone& o, signed short v)
	{ static_cast<object&>(o) << v; }

inline void operator<< (object::with_zone& o, signed int v)
	{ static_cast<object&>(o) << v; }

inline void operator<< (object::with_zone& o, signed long v)
	{ static_cast<object&>(o) << v; }

inline void operator<< (object::with_zone& o, const signed long long& v)
	{ static_cast<object&>(o) << v; }

inline void operator<< (object::with_zone& o, unsigned char v)
	{ static_cast<object&>(o) << v; }

inline void operator<< (object::with_zone& o, unsigned short v)
	{ static_cast<object&>(o) << v; }

inline void operator<< (object::with_zone& o, unsigned int v)
	{ static_cast<object&>(o) << v; }

inline void operator<< (object::with_zone& o, unsigned long v)
	{ static_cast<object&>(o) << v; }

inline void operator<< (object::with_zone& o, const unsigned long long& v)
	{ static_cast<object&>(o) << v; }

}  // namespace msgpack

#endif /* msgpack/type/int.hpp */

<|endoftext|>


<commit_before>#include "pd_host.h"
#include <foundation/array.h>
#include <foundation/string.h>

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

struct ServiceData {
    void* funcs;
    const char* identifer;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static ServiceData* s_serviceData;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Service_create() {
    array_clear(s_serviceData);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Service_destroy() {
    array_clear(s_serviceData);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Service_register(void* serviceFuncs, const char* ident) {
    ServiceData data = { serviceFuncs, ident };

    int count = array_size(s_serviceData);

    for (int i = 0; i < count; ++i) {
        if (string_equal(s_serviceData[i].identifer, ident))
            return;
    }

    array_push(s_serviceData, data);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void* Service_getService(const char* ident) {
    int count = array_size(s_serviceData);

    for (int i = 0; i < count; ++i) {
        if (string_equal(s_serviceData[i].identifer, ident))
            return s_serviceData[i].funcs;
    }

    return 0;
}

<commit_msg>Print error if service can't be found.<commit_after>#include "pd_host.h"
#include "log.h"
#include <foundation/array.h>
#include <foundation/string.h>

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

struct ServiceData {
    void* funcs;
    const char* identifer;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static ServiceData* s_serviceData;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Service_create() {
    array_clear(s_serviceData);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Service_destroy() {
    array_clear(s_serviceData);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Service_register(void* serviceFuncs, const char* ident) {
    ServiceData data = { serviceFuncs, ident };

    int count = array_size(s_serviceData);

    for (int i = 0; i < count; ++i) {
        if (string_equal(s_serviceData[i].identifer, ident))
            return;
    }

    array_push(s_serviceData, data);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void* Service_getService(const char* ident) {
    int count = array_size(s_serviceData);

    for (int i = 0; i < count; ++i) {
        if (string_equal(s_serviceData[i].identifer, ident))
            return s_serviceData[i].funcs;
    }

    pd_error("Unable to get service %s\n", ident);

    return 0;
}

<|endoftext|>


<commit_before>/* This file is part of the Pangolin Project.
 * http://github.com/stevenlovegrove/Pangolin
 *
 * Copyright (c) 2014 Steven Lovegrove
 *
 * 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 <pangolin/video/drivers/thread.h>

#ifdef DEBUGTHREAD
  #include <pangolin/utils/timer.h>
  #define TSTART() pangolin::basetime start,last,now; start = pangolin::TimeNow(); last = start;
  #define TGRABANDPRINT(...)  now = pangolin::TimeNow(); fprintf(stderr,"THREAD: "); fprintf(stderr, __VA_ARGS__); fprintf(stderr, " %fms.\n",1000*pangolin::TimeDiff_s(last, now)); last = now;
  #define DBGPRINT(...) fprintf(stderr,"THREAD: "); fprintf(stderr, __VA_ARGS__); fprintf(stderr,"\n");
#else
  #define TSTART()
  #define TGRABANDPRINT(...)
  #define DBGPRINT(...)
#endif

namespace pangolin
{

ThreadVideo::ThreadVideo(VideoInterface* src, unsigned int num_buffers): quit_grab_thread(true), num_buffers(num_buffers)
{
    if(!src) {
        throw VideoException("ThreadVideo: VideoInterface in must not be null");
    }
    videoin.push_back(src);
    // queue init allocates buffers.
    queue.init(num_buffers, videoin[0]->SizeBytes());
    Start();
}

ThreadVideo::~ThreadVideo()
{
    Stop();
    delete videoin[0];
    // queue destructor will take care of deallocating buffers.
}

//! Implement VideoInput::Start()
void ThreadVideo::Start()
{
    videoin[0]->Start();
    quit_grab_thread = false;
    grab_thread = boostd::thread(boostd::ref(*this));
}

//! Implement VideoInput::Stop()
void ThreadVideo::Stop()
{
    quit_grab_thread = true;
    if(grab_thread.joinable()) {
        grab_thread.join();
    }
    videoin[0]->Stop();
}

//! Implement VideoInput::SizeBytes()
size_t ThreadVideo::SizeBytes() const
{
    return videoin[0]->SizeBytes();
}

//! Implement VideoInput::Streams()
const std::vector<StreamInfo>& ThreadVideo::Streams() const
{
    return videoin[0]->Streams();
}

const json::value& ThreadVideo::DeviceProperties() const
{
    VideoPropertiesInterface* in_prop = dynamic_cast<VideoPropertiesInterface*>(videoin[0]);
    if(!in_prop)
        throw std::runtime_error("ThreadVideo: video in interface does not implement VideoPropertiesInterface.");
    else
        return in_prop->FrameProperties();
}

const json::value& ThreadVideo::FrameProperties() const
{
    VideoPropertiesInterface* in_prop = dynamic_cast<VideoPropertiesInterface*>(videoin[0]);
    if(!in_prop)
        throw std::runtime_error("ThreadVideo: video in interface does not implement VideoPropertiesInterface.");
    else
        return in_prop->FrameProperties();
}

unsigned int ThreadVideo::AvailableFrames() const
{
    return queue.AvailableFrames();
}

bool ThreadVideo::DropNFrames(uint32_t n)
{
    return queue.DropNFrames(n);
}

//! Implement VideoInput::GrabNext()
bool ThreadVideo::GrabNext( unsigned char* image, bool wait )
{

    if(queue.AvailableFrames() > 0) {
        // At least one valid frame in queue, return it.
        DBGPRINT("GrabNext at least one frame available.");
        unsigned char* i = queue.getNext();
        std::memcpy(image, i, queue.BufferSizeBytes());
        queue.returnUsedBuffer(i);
        return true;
    } else {
        if(wait) {
            // Must return a frame so block on notification from grab thread.
            std::unique_lock<std::mutex> lk(cvMtx);
            DBGPRINT("GrabNext no available frames wait for notification.");
            if(cv.wait_for(lk, boostd::chrono::seconds(5)) == boostd::cv_status::timeout)
                throw std::runtime_error("ThreadVideo: GrabNext blocking read for frames reached timeout.");
            DBGPRINT("GrabNext got notification.");
            unsigned char* i = queue.getNext();
            std::memcpy(image, i, queue.BufferSizeBytes());
            queue.returnUsedBuffer(i);
            return true;
        } else {
            DBGPRINT("GrabNext no available frames no wait.");
            // No frames available, no wait, simply return false.
            return false;
        }
    }
}

//! Implement VideoInput::GrabNewest()
bool ThreadVideo::GrabNewest( unsigned char* image, bool wait )
{
    if(queue.AvailableFrames() > 0) {
        // At least one valid frame in queue, call grabNewest to drop old frame and return the newest.
        DBGPRINT("GrabNewest at least one frame available.");
        unsigned char* i = queue.getNewest();
        std::memcpy(image, i, queue.BufferSizeBytes());
        queue.returnUsedBuffer(i);
        return true;
    } else {
        if(wait) {
            // Must return a frame so block on notification from grab thread.
            DBGPRINT("GrabNewest no available frames wait for notification.");
            std::unique_lock<std::mutex> lk(cvMtx);
            if(cv.wait_for(lk, boostd::chrono::seconds(5)) == boostd::cv_status::timeout)
                throw std::runtime_error("ThreadVideo: GrabNewest blocking read for frames reached timeout.");
            DBGPRINT("GrabNewest got notification.");
            unsigned char* i = queue.getNext();
            std::memcpy(image, i, queue.BufferSizeBytes());
            queue.returnUsedBuffer(i);
            return true;
        } else {
            DBGPRINT("GrabNewest no available frames no wait.");
            // No frames available, no wait, simply return false.
            return false;
        }
    }
}

void ThreadVideo::operator()()
{
    DBGPRINT("Grab thread Started.")
    // Spinning thread attempting to read from videoin[0] as fast as possible
    // relying on the videoin[0] blocking grab.
    while(!quit_grab_thread) {
        // Get a buffer from the queue;
        unsigned char* i = queue.getFreeBuffer();
        // Blocking grab (i.e. GrabNext with wait = true).
        if(videoin[0]->GrabNext(i, true)){
            queue.addValidBuffer(i);
            DBGPRINT("Grab thread got frame. valid:%d free:%d",queue.AvailableFrames(),queue.EmptyBuffers())
            // Let listening threads know we got a frame in case they are waiting.
            cv.notify_all();
        } else {
            // Grabbing frames failed, requeue the buffer.
            queue.returnUsedBuffer(i);
        }
        boostd::this_thread::yield();
    }
    DBGPRINT("Grab thread Stopped.")

    return;
}

}

#undef TSTART
#undef TGRABANDPRINT
#undef DBGPRINT
<commit_msg>Add time printout to thread debug info.<commit_after>/* This file is part of the Pangolin Project.
 * http://github.com/stevenlovegrove/Pangolin
 *
 * Copyright (c) 2014 Steven Lovegrove
 *
 * 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 <pangolin/video/drivers/thread.h>

#ifdef DEBUGTHREAD
  #include <pangolin/utils/timer.h>
  #define TSTART() pangolin::basetime start,last,now; start = pangolin::TimeNow(); last = start;
  #define TGRABANDPRINT(...)  now = pangolin::TimeNow(); fprintf(stderr,"THREAD: "); fprintf(stderr, __VA_ARGS__); fprintf(stderr, " %fms.\n",1000*pangolin::TimeDiff_s(last, now)); last = now;
  #define DBGPRINT(...) fprintf(stderr,"THREAD: "); fprintf(stderr, __VA_ARGS__); fprintf(stderr,"\n");
#else
  #define TSTART()
  #define TGRABANDPRINT(...)
  #define DBGPRINT(...)
#endif

namespace pangolin
{

ThreadVideo::ThreadVideo(VideoInterface* src, unsigned int num_buffers): quit_grab_thread(true), num_buffers(num_buffers)
{
    if(!src) {
        throw VideoException("ThreadVideo: VideoInterface in must not be null");
    }
    videoin.push_back(src);
    // queue init allocates buffers.
    queue.init(num_buffers, videoin[0]->SizeBytes());
    Start();
}

ThreadVideo::~ThreadVideo()
{
    Stop();
    delete videoin[0];
    // queue destructor will take care of deallocating buffers.
}

//! Implement VideoInput::Start()
void ThreadVideo::Start()
{
    videoin[0]->Start();
    quit_grab_thread = false;
    grab_thread = boostd::thread(boostd::ref(*this));
}

//! Implement VideoInput::Stop()
void ThreadVideo::Stop()
{
    quit_grab_thread = true;
    if(grab_thread.joinable()) {
        grab_thread.join();
    }
    videoin[0]->Stop();
}

//! Implement VideoInput::SizeBytes()
size_t ThreadVideo::SizeBytes() const
{
    return videoin[0]->SizeBytes();
}

//! Implement VideoInput::Streams()
const std::vector<StreamInfo>& ThreadVideo::Streams() const
{
    return videoin[0]->Streams();
}

const json::value& ThreadVideo::DeviceProperties() const
{
    VideoPropertiesInterface* in_prop = dynamic_cast<VideoPropertiesInterface*>(videoin[0]);
    if(!in_prop)
        throw std::runtime_error("ThreadVideo: video in interface does not implement VideoPropertiesInterface.");
    else
        return in_prop->FrameProperties();
}

const json::value& ThreadVideo::FrameProperties() const
{
    VideoPropertiesInterface* in_prop = dynamic_cast<VideoPropertiesInterface*>(videoin[0]);
    if(!in_prop)
        throw std::runtime_error("ThreadVideo: video in interface does not implement VideoPropertiesInterface.");
    else
        return in_prop->FrameProperties();
}

unsigned int ThreadVideo::AvailableFrames() const
{
    return queue.AvailableFrames();
}

bool ThreadVideo::DropNFrames(uint32_t n)
{
    return queue.DropNFrames(n);
}

//! Implement VideoInput::GrabNext()
bool ThreadVideo::GrabNext( unsigned char* image, bool wait )
{
    TSTART()
    if(queue.AvailableFrames() > 0) {
        // At least one valid frame in queue, return it.
        DBGPRINT("GrabNext at least one frame available.");
        unsigned char* i = queue.getNext();
        std::memcpy(image, i, queue.BufferSizeBytes());
        queue.returnUsedBuffer(i);
        TGRABANDPRINT("GrabNext memcpy of available frame took")
        return true;
    } else {
        if(wait) {
            // Must return a frame so block on notification from grab thread.
            std::unique_lock<std::mutex> lk(cvMtx);
            DBGPRINT("GrabNext no available frames wait for notification.");
            if(cv.wait_for(lk, boostd::chrono::seconds(5)) == boostd::cv_status::timeout)
                throw std::runtime_error("ThreadVideo: GrabNext blocking read for frames reached timeout.");
            DBGPRINT("GrabNext got notification.");
            unsigned char* i = queue.getNext();
            std::memcpy(image, i, queue.BufferSizeBytes());
            queue.returnUsedBuffer(i);
            TGRABANDPRINT("GrabNext wait for lock and memcpy of available frame took")
            return true;
        } else {
            DBGPRINT("GrabNext no available frames no wait.");
            // No frames available, no wait, simply return false.
            return false;
        }
    }
}

//! Implement VideoInput::GrabNewest()
bool ThreadVideo::GrabNewest( unsigned char* image, bool wait )
{
    TSTART()
    if(queue.AvailableFrames() > 0) {
        // At least one valid frame in queue, call grabNewest to drop old frame and return the newest.
        DBGPRINT("GrabNewest at least one frame available.");
        unsigned char* i = queue.getNewest();
        std::memcpy(image, i, queue.BufferSizeBytes());
        queue.returnUsedBuffer(i);
        TGRABANDPRINT("GrabNewest memcpy of available frame took")
        return true;
    } else {
        if(wait) {
            // Must return a frame so block on notification from grab thread.
            DBGPRINT("GrabNewest no available frames wait for notification.");
            std::unique_lock<std::mutex> lk(cvMtx);
            if(cv.wait_for(lk, boostd::chrono::seconds(5)) == boostd::cv_status::timeout)
                throw std::runtime_error("ThreadVideo: GrabNewest blocking read for frames reached timeout.");
            DBGPRINT("GrabNewest got notification.");
            unsigned char* i = queue.getNext();
            std::memcpy(image, i, queue.BufferSizeBytes());
            queue.returnUsedBuffer(i);
            TGRABANDPRINT("GrabNwest wait for lock and memcpy of available frame took")
            return true;
        } else {
            DBGPRINT("GrabNewest no available frames no wait.");
            // No frames available, no wait, simply return false.
            return false;
        }
    }
}

void ThreadVideo::operator()()
{
    DBGPRINT("Grab thread Started.")
    // Spinning thread attempting to read from videoin[0] as fast as possible
    // relying on the videoin[0] blocking grab.
    while(!quit_grab_thread) {
        // Get a buffer from the queue;
        unsigned char* i = queue.getFreeBuffer();
        // Blocking grab (i.e. GrabNext with wait = true).
        if(videoin[0]->GrabNext(i, true)){
            queue.addValidBuffer(i);
            DBGPRINT("Grab thread got frame. valid:%d free:%d",queue.AvailableFrames(),queue.EmptyBuffers())
            // Let listening threads know we got a frame in case they are waiting.
            cv.notify_all();
        } else {
            // Grabbing frames failed, requeue the buffer.
            queue.returnUsedBuffer(i);
        }
        boostd::this_thread::yield();
    }
    DBGPRINT("Grab thread Stopped.")

    return;
}

}

#undef TSTART
#undef TGRABANDPRINT
#undef DBGPRINT
<|endoftext|>


<commit_before>/*
    Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>

    This file is part of Magnum.

    Magnum is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License version 3
    only, as published by the Free Software Foundation.

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

#include <iostream>
#include <chrono>
#include <memory>
#include <unordered_map>

#include "PluginManager/PluginManager.h"
#include "Scene.h"
#include "Camera.h"
#include "Trade/AbstractImporter.h"
#include "Trade/MeshData.h"
#include "Trade/MeshObjectData.h"
#include "Trade/SceneData.h"
#include "MeshTools/Tipsify.h"
#include "MeshTools/Interleave.h"
#include "MeshTools/CompressIndices.h"
#include "Shaders/PhongShader.h"

#include "AbstractExample.h"
#include "ViewedObject.h"
#include "configure.h"

using namespace std;
using namespace Corrade::PluginManager;
using namespace Corrade::Utility;
using namespace Magnum;
using namespace Magnum::Shaders;
using namespace Magnum::Trade;
using namespace Magnum::Examples;

namespace Magnum { namespace Examples {

class ViewerExample: public AbstractExample {
    public:
        ViewerExample(int& argc, char** argv);

        ~ViewerExample() {
            for(auto i: meshes) delete i.second;
        }

    protected:
        inline void viewportEvent(const Math::Vector2<GLsizei>& size) {
            camera->setViewport(size);
        }

        void drawEvent() {
            if(fps) {
                chrono::high_resolution_clock::time_point now = chrono::high_resolution_clock::now();
                double duration = chrono::duration<double>(now-before).count();
                if(duration > 3.5) {
                    cout << frames << " frames in " << duration << " sec: "
                        << frames/duration << " FPS         \r";
                    cout.flush();
                    totalfps += frames/duration;
                    before = now;
                    frames = 0;
                    ++totalmeasurecount;
                }
            }
            camera->draw();
            swapBuffers();

            if(fps) {
                ++frames;
                redraw();
            }
        }

        void keyEvent(Key key, const Math::Vector2<int>& position) {
            switch(key) {
                case Key::Up:
                    o->rotate(deg(10.0f), Vector3::xAxis(-1));
                    break;
                case Key::Down:
                    o->rotate(deg(10.0f), Vector3::xAxis(1));
                    break;
                case Key::Left:
                    o->rotate(deg(10.0f), Vector3::yAxis(-1), false);
                    break;
                case Key::Right:
                    o->rotate(deg(10.0f), Vector3::yAxis(1), false);
                    break;
                case Key::PageUp:
                    camera->translate(Vector3::zAxis(-0.5), false);
                    break;
                case Key::PageDown:
                    camera->translate(Vector3::zAxis(0.5), false);
                    break;
                case Key::Home:
                    glPolygonMode(GL_FRONT_AND_BACK, wireframe ? GL_FILL : GL_LINE);
                    wireframe = !wireframe;
                    break;
                case Key::End:
                    if(fps) cout << "Average FPS on " << camera->viewport().x()
                        << 'x' << camera->viewport().y() << " from "
                        << totalmeasurecount << " measures: "
                        << totalfps/totalmeasurecount << "          " << endl;
                    else before = chrono::high_resolution_clock::now();

                    fps = !fps;
                    frames = totalmeasurecount = 0;
                    totalfps = 0;
                    break;
            }

            redraw();
        }

        void mouseEvent(MouseButton button, MouseState state, const Math::Vector2<int>& position) {
            switch(button) {
                case MouseButton::Left:
                    if(state == MouseState::Down) previousPosition = positionOnSphere(position);
                    else previousPosition = Vector3();
                    break;
                case MouseButton::WheelUp:
                case MouseButton::WheelDown: {
                    if(state == MouseState::Up) return;

                    /* Distance between origin and near camera clipping plane */
                    GLfloat distance = camera->transformation().at(3).z()-0-camera->near();

                    /* Move 15% of the distance back or forward */
                    if(button == MouseButton::WheelUp)
                        distance *= 1 - 1/0.85f;
                    else
                        distance *= 1 - 0.85f;
                    camera->translate(Vector3::zAxis(distance), false);

                    redraw();
                    break;
                }
                default: ;
            }
        }

        void mouseMoveEvent(const Math::Vector2<int>& position) {
            Vector3 currentPosition = positionOnSphere(position);

            Vector3 axis = Vector3::cross(previousPosition, currentPosition);

            if(previousPosition.length() < 0.001f || axis.length() < 0.001f) return;

            GLfloat angle = acos(previousPosition*currentPosition);
            o->rotate(angle, axis);

            previousPosition = currentPosition;

            redraw();
        }

    private:
        Vector3 positionOnSphere(const Math::Vector2<int>& _position) const {
            Math::Vector2<GLsizei> viewport = camera->viewport();
            Vector2 position(_position.x()*2.0f/viewport.x() - 1.0f,
                             _position.y()*2.0f/viewport.y() - 1.0f);

            GLfloat length = position.length();
            Vector3 result(length > 1.0f ? position : Vector3(position, 1.0f - length));
            result.setY(-result.y());
            return result.normalized();
        }

        void addObject(AbstractImporter* colladaImporter, Object* parent, unordered_map<size_t, PhongMaterialData*>& materials, size_t objectId);

        Scene scene;
        Camera* camera;
        PhongShader shader;
        Object* o;
        unordered_map<size_t, IndexedMesh*> meshes;
        chrono::high_resolution_clock::time_point before;
        bool wireframe, fps;
        size_t frames;
        double totalfps;
        size_t totalmeasurecount;
        Vector3 previousPosition;
};

ViewerExample::ViewerExample(int& argc, char** argv): AbstractExample(argc, argv, "Magnum Viewer"), wireframe(false), fps(false) {
    if(argc != 2) {
        cout << "Usage: " << argv[0] << " file.dae" << endl;
        exit(0);
    }

    /* Instance ColladaImporter plugin */
    PluginManager<AbstractImporter> manager(PLUGIN_IMPORTER_DIR);
    if(manager.load("ColladaImporter") != AbstractPluginManager::LoadOk) {
        Error() << "Could not load ColladaImporter plugin";
        exit(1);
    }
    unique_ptr<AbstractImporter> colladaImporter(manager.instance("ColladaImporter"));
    if(!colladaImporter) {
        Error() << "Could not instance ColladaImporter plugin";
        exit(2);
    }
    if(!(colladaImporter->features() & AbstractImporter::OpenFile)) {
        Error() << "ColladaImporter cannot open files";
        exit(3);
    }

    scene.setFeature(Scene::DepthTest, true);

    /* Every scene needs a camera */
    camera = new Camera(&scene);
    camera->setPerspective(deg(35.0f), 0.001f, 100);
    camera->translate(Vector3::zAxis(5));

    /* Load file */
    if(!colladaImporter->open(argv[1]))
        exit(4);

    if(colladaImporter->sceneCount() == 0)
        exit(5);

    /* Map with materials */
    unordered_map<size_t, PhongMaterialData*> materials;

    /* Default object, parent of all (for manipulation) */
    o = new Object(&scene);

    /* Load the scene */
    SceneData* scene = colladaImporter->scene(colladaImporter->defaultScene());

    /* Add all children */
    for(size_t objectId: scene->children())
        addObject(colladaImporter.get(), o, materials, objectId);

    /* Delete materials, as they are now unused */
    for(auto i: materials) delete i.second;

    colladaImporter->close();
    delete colladaImporter.release();
}

void ViewerExample::addObject(AbstractImporter* colladaImporter, Object* parent, unordered_map<size_t, PhongMaterialData*>& materials, size_t objectId) {
    ObjectData* object = colladaImporter->object(objectId);

    /* Only meshes for now */
    if(object->instanceType() == ObjectData::InstanceType::Mesh) {
        /* Use already processed mesh, if exists */
        IndexedMesh* mesh;
        auto found = meshes.find(object->instanceId());
        if(found != meshes.end()) mesh = found->second;

        /* Or create a new one */
        else {
            mesh = new IndexedMesh;
            meshes.insert(make_pair(object->instanceId(), mesh));

            MeshData* data = colladaImporter->mesh(object->instanceId());
            if(!data || !data->indices() || !data->vertexArrayCount() || !data->normalArrayCount())
                exit(6);

            /* Optimize vertices */
            Debug() << "Optimizing vertices of mesh" << object->instanceId() << "using Tipsify algorithm (cache size 24)...";
            MeshTools::tipsify(*data->indices(), data->vertices(0)->size(), 24);

            /* Interleave mesh data */
            Buffer* buffer = mesh->addBuffer(true);
            mesh->bindAttribute<PhongShader::Vertex>(buffer);
            mesh->bindAttribute<PhongShader::Normal>(buffer);
            MeshTools::interleave(mesh, buffer, Buffer::Usage::StaticDraw, *data->vertices(0), *data->normals(0));

            /* Compress indices */
            MeshTools::compressIndices(mesh, Buffer::Usage::StaticDraw, *data->indices());
        }

        /* Use already processed material, if exists */
        PhongMaterialData* material;
        auto materialFound = materials.find(static_cast<MeshObjectData*>(object)->material());
        if(materialFound != materials.end()) material = materialFound->second;

        /* Else get material or create default one */
        else {
            material = static_cast<PhongMaterialData*>(colladaImporter->material(static_cast<MeshObjectData*>(object)->material()));
            if(!material) material = new PhongMaterialData({0.0f, 0.0f, 0.0f}, {0.9f, 0.9f, 0.9f}, {1.0f, 1.0f, 1.0f}, 50.0f);
        }

        /* Add object */
        Object* o = new ViewedObject(mesh, material, &shader, parent);
        o->setTransformation(object->transformation());
    }

    /* Recursively add children */
    for(size_t id: object->children())
        addObject(colladaImporter, o, materials, id);
}

}}

MAGNUM_EXAMPLE_MAIN(Magnum::Examples::ViewerExample)
<commit_msg>Using Corrade::Debug instead of std::cout.<commit_after>/*
    Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>

    This file is part of Magnum.

    Magnum is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License version 3
    only, as published by the Free Software Foundation.

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

#include <iostream>
#include <chrono>
#include <memory>
#include <unordered_map>

#include "PluginManager/PluginManager.h"
#include "Scene.h"
#include "Camera.h"
#include "Trade/AbstractImporter.h"
#include "Trade/MeshData.h"
#include "Trade/MeshObjectData.h"
#include "Trade/SceneData.h"
#include "MeshTools/Tipsify.h"
#include "MeshTools/Interleave.h"
#include "MeshTools/CompressIndices.h"
#include "Shaders/PhongShader.h"

#include "AbstractExample.h"
#include "ViewedObject.h"
#include "configure.h"

using namespace std;
using namespace Corrade::PluginManager;
using namespace Corrade::Utility;
using namespace Magnum;
using namespace Magnum::Shaders;
using namespace Magnum::Trade;
using namespace Magnum::Examples;

namespace Magnum { namespace Examples {

class ViewerExample: public AbstractExample {
    public:
        ViewerExample(int& argc, char** argv);

        ~ViewerExample() {
            for(auto i: meshes) delete i.second;
        }

    protected:
        inline void viewportEvent(const Math::Vector2<GLsizei>& size) {
            camera->setViewport(size);
        }

        void drawEvent() {
            if(fps) {
                chrono::high_resolution_clock::time_point now = chrono::high_resolution_clock::now();
                double duration = chrono::duration<double>(now-before).count();
                if(duration > 3.5) {
                    cout << frames << " frames in " << duration << " sec: "
                        << frames/duration << " FPS         \r";
                    cout.flush();
                    totalfps += frames/duration;
                    before = now;
                    frames = 0;
                    ++totalmeasurecount;
                }
            }
            camera->draw();
            swapBuffers();

            if(fps) {
                ++frames;
                redraw();
            }
        }

        void keyEvent(Key key, const Math::Vector2<int>& position) {
            switch(key) {
                case Key::Up:
                    o->rotate(deg(10.0f), Vector3::xAxis(-1));
                    break;
                case Key::Down:
                    o->rotate(deg(10.0f), Vector3::xAxis(1));
                    break;
                case Key::Left:
                    o->rotate(deg(10.0f), Vector3::yAxis(-1), false);
                    break;
                case Key::Right:
                    o->rotate(deg(10.0f), Vector3::yAxis(1), false);
                    break;
                case Key::PageUp:
                    camera->translate(Vector3::zAxis(-0.5), false);
                    break;
                case Key::PageDown:
                    camera->translate(Vector3::zAxis(0.5), false);
                    break;
                case Key::Home:
                    glPolygonMode(GL_FRONT_AND_BACK, wireframe ? GL_FILL : GL_LINE);
                    wireframe = !wireframe;
                    break;
                case Key::End:
                    if(fps) cout << "Average FPS on " << camera->viewport().x()
                        << 'x' << camera->viewport().y() << " from "
                        << totalmeasurecount << " measures: "
                        << totalfps/totalmeasurecount << "          " << endl;
                    else before = chrono::high_resolution_clock::now();

                    fps = !fps;
                    frames = totalmeasurecount = 0;
                    totalfps = 0;
                    break;
            }

            redraw();
        }

        void mouseEvent(MouseButton button, MouseState state, const Math::Vector2<int>& position) {
            switch(button) {
                case MouseButton::Left:
                    if(state == MouseState::Down) previousPosition = positionOnSphere(position);
                    else previousPosition = Vector3();
                    break;
                case MouseButton::WheelUp:
                case MouseButton::WheelDown: {
                    if(state == MouseState::Up) return;

                    /* Distance between origin and near camera clipping plane */
                    GLfloat distance = camera->transformation().at(3).z()-0-camera->near();

                    /* Move 15% of the distance back or forward */
                    if(button == MouseButton::WheelUp)
                        distance *= 1 - 1/0.85f;
                    else
                        distance *= 1 - 0.85f;
                    camera->translate(Vector3::zAxis(distance), false);

                    redraw();
                    break;
                }
                default: ;
            }
        }

        void mouseMoveEvent(const Math::Vector2<int>& position) {
            Vector3 currentPosition = positionOnSphere(position);

            Vector3 axis = Vector3::cross(previousPosition, currentPosition);

            if(previousPosition.length() < 0.001f || axis.length() < 0.001f) return;

            GLfloat angle = acos(previousPosition*currentPosition);
            o->rotate(angle, axis);

            previousPosition = currentPosition;

            redraw();
        }

    private:
        Vector3 positionOnSphere(const Math::Vector2<int>& _position) const {
            Math::Vector2<GLsizei> viewport = camera->viewport();
            Vector2 position(_position.x()*2.0f/viewport.x() - 1.0f,
                             _position.y()*2.0f/viewport.y() - 1.0f);

            GLfloat length = position.length();
            Vector3 result(length > 1.0f ? position : Vector3(position, 1.0f - length));
            result.setY(-result.y());
            return result.normalized();
        }

        void addObject(AbstractImporter* colladaImporter, Object* parent, unordered_map<size_t, PhongMaterialData*>& materials, size_t objectId);

        Scene scene;
        Camera* camera;
        PhongShader shader;
        Object* o;
        unordered_map<size_t, IndexedMesh*> meshes;
        chrono::high_resolution_clock::time_point before;
        bool wireframe, fps;
        size_t frames;
        double totalfps;
        size_t totalmeasurecount;
        Vector3 previousPosition;
};

ViewerExample::ViewerExample(int& argc, char** argv): AbstractExample(argc, argv, "Magnum Viewer"), wireframe(false), fps(false) {
    if(argc != 2) {
        Debug() << "Usage:" << argv[0] << "file.dae";
        exit(0);
    }

    /* Instance ColladaImporter plugin */
    PluginManager<AbstractImporter> manager(PLUGIN_IMPORTER_DIR);
    if(manager.load("ColladaImporter") != AbstractPluginManager::LoadOk) {
        Error() << "Could not load ColladaImporter plugin";
        exit(1);
    }
    unique_ptr<AbstractImporter> colladaImporter(manager.instance("ColladaImporter"));
    if(!colladaImporter) {
        Error() << "Could not instance ColladaImporter plugin";
        exit(2);
    }
    if(!(colladaImporter->features() & AbstractImporter::OpenFile)) {
        Error() << "ColladaImporter cannot open files";
        exit(3);
    }

    scene.setFeature(Scene::DepthTest, true);

    /* Every scene needs a camera */
    camera = new Camera(&scene);
    camera->setPerspective(deg(35.0f), 0.001f, 100);
    camera->translate(Vector3::zAxis(5));

    /* Load file */
    if(!colladaImporter->open(argv[1]))
        exit(4);

    if(colladaImporter->sceneCount() == 0)
        exit(5);

    /* Map with materials */
    unordered_map<size_t, PhongMaterialData*> materials;

    /* Default object, parent of all (for manipulation) */
    o = new Object(&scene);

    /* Load the scene */
    SceneData* scene = colladaImporter->scene(colladaImporter->defaultScene());

    /* Add all children */
    for(size_t objectId: scene->children())
        addObject(colladaImporter.get(), o, materials, objectId);

    /* Delete materials, as they are now unused */
    for(auto i: materials) delete i.second;

    colladaImporter->close();
    delete colladaImporter.release();
}

void ViewerExample::addObject(AbstractImporter* colladaImporter, Object* parent, unordered_map<size_t, PhongMaterialData*>& materials, size_t objectId) {
    ObjectData* object = colladaImporter->object(objectId);

    /* Only meshes for now */
    if(object->instanceType() == ObjectData::InstanceType::Mesh) {
        /* Use already processed mesh, if exists */
        IndexedMesh* mesh;
        auto found = meshes.find(object->instanceId());
        if(found != meshes.end()) mesh = found->second;

        /* Or create a new one */
        else {
            mesh = new IndexedMesh;
            meshes.insert(make_pair(object->instanceId(), mesh));

            MeshData* data = colladaImporter->mesh(object->instanceId());
            if(!data || !data->indices() || !data->vertexArrayCount() || !data->normalArrayCount())
                exit(6);

            /* Optimize vertices */
            Debug() << "Optimizing vertices of mesh" << object->instanceId() << "using Tipsify algorithm (cache size 24)...";
            MeshTools::tipsify(*data->indices(), data->vertices(0)->size(), 24);

            /* Interleave mesh data */
            Buffer* buffer = mesh->addBuffer(true);
            mesh->bindAttribute<PhongShader::Vertex>(buffer);
            mesh->bindAttribute<PhongShader::Normal>(buffer);
            MeshTools::interleave(mesh, buffer, Buffer::Usage::StaticDraw, *data->vertices(0), *data->normals(0));

            /* Compress indices */
            MeshTools::compressIndices(mesh, Buffer::Usage::StaticDraw, *data->indices());
        }

        /* Use already processed material, if exists */
        PhongMaterialData* material;
        auto materialFound = materials.find(static_cast<MeshObjectData*>(object)->material());
        if(materialFound != materials.end()) material = materialFound->second;

        /* Else get material or create default one */
        else {
            material = static_cast<PhongMaterialData*>(colladaImporter->material(static_cast<MeshObjectData*>(object)->material()));
            if(!material) material = new PhongMaterialData({0.0f, 0.0f, 0.0f}, {0.9f, 0.9f, 0.9f}, {1.0f, 1.0f, 1.0f}, 50.0f);
        }

        /* Add object */
        Object* o = new ViewedObject(mesh, material, &shader, parent);
        o->setTransformation(object->transformation());
    }

    /* Recursively add children */
    for(size_t id: object->children())
        addObject(colladaImporter, o, materials, id);
}

}}

MAGNUM_EXAMPLE_MAIN(Magnum::Examples::ViewerExample)
<|endoftext|>