<commit_before>#include <iostream>
#include <string>
#include <sstream>
#include <cstdlib>
#include <vector>
#include <fstream>
#include <ctime>
#include "Map.h"
#include "Zombie.h"
#include "Player.h"
#include "Plant.h"

using namespace std;

bool allZombiesDie(const Zombie * zombie);
bool enoughMoney(const vector<Plant*> & plant, const Player * player);
void printInfor(const Map & map, const Player & player, const Zombie * zombie);
int main()
{
    //game start
    cout << " -----------------------------" << endl
         << "|     Plants v.s Zombies      |" << endl
         << " -----------------------------" << endl;
    constexpr int LAND_DEFAULT=8;
    constexpr int LAND_MAX=10;
    constexpr int LAND_MIN=1;
    constexpr int ZOMBIE_DEFAULT=3;
    constexpr int ZOMBIE_MAX=10;
    constexpr int ZOMBIE_MIN=1;

    string input;
    //initialize game setting
    cout << "Number of lands on the map (" << LAND_MIN << "-" << LAND_MAX << ", default: " << LAND_DEFAULT <<")...>";
    int value = LAND_DEFAULT;
    getline(cin, input);
    if(!input.empty())
    {
        istringstream stream( input );
        stream >> value;
        if(value > LAND_MAX) value = LAND_MAX;
        if(value < LAND_MIN) value = LAND_MIN;
    }
    const int LANDS=value;

    cout << "Number of zombies on the map (" << ZOMBIE_MIN << "-" << ZOMBIE_MAX << ", default: "<< ZOMBIE_DEFAULT <<")...>";
    value=ZOMBIE_DEFAULT;
    getline(cin, input);
    if(!input.empty())
    {
        istringstream stream( input );
        stream >> value;
        if(value > ZOMBIE_MAX) value = ZOMBIE_MAX;
        if(value < ZOMBIE_MIN) value = ZOMBIE_MIN;
    }
    const int ZOMBIES=value;

    //game rules
    cout << "=============================================================================" << endl
         << "Plants vs. Zombies Rule:" << endl
         << endl
         << "How to win:" << endl
         << "  (1) All zombies are dead." << endl
         << "  (2) At least one plant is live." << endl
         << "  (3) The number of dead bomb plants cannot exceed the number of zombies." << endl
         << endl
         << "How to lose:" << endl
         << "  All plants are dead." << endl
         << "=============================================================================" << endl;
    system("pause");
    system("cls");

    //construct
    srand(time(0));     // random number seed
    Player *player = new Player;
    Zombie *zombie = new Zombie[ZOMBIES];
    Zombie::TotalNum = ZOMBIES;
    Map *map = new Map(LANDS);
    vector<Plant*> plant;
    fstream fin("plants.txt", fstream::in);
    string str;
    if(fin)
    {
        while(fin >> str)
        {
            Plant *tmp = nullptr;
            switch(str[0])
            {
            case 'C':
            {
                tmp = new CoinPlant(fin);
                break;
            }
            case 'S':
            {
                tmp = new HornPlant(fin);
                break;
            }
            case 'B':
            {
                tmp = new BombPlant(fin);
                break;
            }
            case 'H':
            {
                tmp = new HealPlant(fin);
                break;
            }
            default:
                continue;
            }
            if(tmp)
            {
                plant.push_back(tmp);
            }
        }
    }

    player->Move(rand()%LANDS);
    for (int i=0; i<ZOMBIES; ++i)
        zombie[i].Move(rand()%LANDS);
    int choice = plant.size();
    while(true)
    {
        int position;
        printInfor(*map, *player, zombie);
        do
        {
            position = player->Pos();
            Land * land = map->GetLand(position);
            if(!land->IsEmpty())
            {
                Plant *p = land->GetPlant();
                int visit = p->Visit(*player);
                if(visit < 0)
                {
                    map->Healing(p->HpBack());
                    cout << "All your plants have recovered "<< p->HpBack() << " HP!" << endl;
                    break;
                }
                else if (visit)
                {
                    cout << "You have earned $" << visit << "! Now you have $" << player->Money();
                    break;
                }
                else break;
            }
            else
            {
                if (!enoughMoney(plant, player))
                {
                    cout << "You don't have enough money to plant anything" << endl;
                    break;
                }
                else
                {
                    for(size_t i=0; i<plant.size(); ++i)
                    {
                        cout << "[" << i << "] " ;
                        plant[i]->Print();
                        cout << endl;
                    }
                    cout << endl << "Player $" << player->Money() ;
                    cout << ":\tEnter your choice (" << plant.size() << " to give up, default: " << choice << ")...>";
                    getline(cin, input);
                    if(!input.empty())
                    {
                        istringstream stream( input );
                        stream >> choice;
                        if(choice > plant.size() || choice < 0) choice = plant.size();
                    }
                    if(choice != plant.size())
                    {
                        map->GetLand(player->Pos())->Planting(*player, *plant[choice]);
                        cout << "You have planted " << plant[choice]->Name() << " at land " << player->Pos() << " !" << endl;
                    }
                    break;
                }
                if(choice != plant.size() && plant[choice]->Price() > player->Money())
                {
                    cout << "Not enough money! Please input again!" << endl;
                    system("pause");
                }
            }
        }
        while (true);
        system("pause");
        system("cls");
        for (int i=0; i<ZOMBIES; ++i)
        {
            if (zombie[i].isAlive())
            {
                printInfor(*map, *player, zombie);
                position = rand()%LANDS;
                zombie[i].Move(position);
                cout << "Zombie [" << i << "] moves to land " << position << "." << endl;
                Land * land = map->GetLand(position);
                if(!land->IsEmpty())
                {
                    Plant *p = land->GetPlant();
                    p->Visit(zombie[i]);
                    if(p->Attack())
                    {
                        cout << p->Name() << " gives " << p->Attack() << " damage to the zombie!" << endl;
                    }
                    cout << "Zombie eats plant " << p->Name() << " and cause damage " << zombie[i].Attack() << endl;
                    if(!zombie[i].isAlive())
                        cout << "Zombie is killed!" << endl;
                    if(!p->isAlive())
                    {
                        land->Dead();
                        cout << "Plant " << p->Name() << " is dead!" << endl;
                    }
                }
                system("pause");
                system("cls");
            }
        }
        position = rand()%LANDS;
        player->Move(position);

        // end game condition
        if (map->IsNonPlant())
        {
            cout << "Oh no... You have no plant on the map ...." << endl;
        }
        else if (BombPlant::deadNum >= ZOMBIES/2)
        {
            cout << "You lose the game since you cannot use that many bomb plants!" << endl;
        }
        else if (allZombiesDie(zombie))
        {
            cout << "Congratulations! You have killed all zombies!" << endl;
        }
        system("cls");
        //break;
    }

    // destruct
    while(!plant.empty())
    {
        delete plant.back();
        plant.pop_back();
    }
    delete player;
    delete map;
    delete [] zombie;

    return 0;
}

bool allZombiesDie(const Zombie * zombie)
{
    for(int i=0; i<Zombie::TotalNum && !zombie[i].isAlive(); ++i)
        return (i==Zombie::TotalNum-1);
}

bool enoughMoney(const vector<Plant*> & plant, const Player * player)
{
    for (Plant* p : plant)
        if (p->Price() <= player->Money()) return true;
    return false;
}

void printInfor(const Map & map, const Player & player, const Zombie * zombie)
{
    map.Display(player, zombie);
    cout << "------------------------------------------------" << endl;
    cout << "Zombie information:" << endl;
    for(int i=0; i<Zombie::TotalNum; ++i)
    {
        if(zombie[i].isAlive())
            cout << '[' << i << "] " << zombie[i];
    }
    cout << "================================================" << endl;
}
<commit_msg>add endGame function<commit_after>#include <iostream>
#include <string>
#include <sstream>
#include <cstdlib>
#include <vector>
#include <fstream>
#include <ctime>
#include "Map.h"
#include "Zombie.h"
#include "Player.h"
#include "Plant.h"

using namespace std;

bool endGame(const Map & map, const Zombie * zombie);
bool allZombiesDie(const Zombie * zombie);
bool enoughMoney(const vector<Plant*> & plant, const Player * player);
void printInfor(const Map & map, const Player & player, const Zombie * zombie);
int main()
{
    //game start
    cout << " -----------------------------" << endl
         << "|     Plants v.s Zombies      |" << endl
         << " -----------------------------" << endl;
    constexpr int LAND_DEFAULT=8;
    constexpr int LAND_MAX=10;
    constexpr int LAND_MIN=1;
    constexpr int ZOMBIE_DEFAULT=3;
    constexpr int ZOMBIE_MAX=10;
    constexpr int ZOMBIE_MIN=1;

    string input;
    //initialize game setting
    cout << "Number of lands on the map (" << LAND_MIN << "-" << LAND_MAX << ", default: " << LAND_DEFAULT <<")...>";
    int value = LAND_DEFAULT;
    getline(cin, input);
    if(!input.empty())
    {
        istringstream stream( input );
        stream >> value;
        if(value > LAND_MAX) value = LAND_MAX;
        if(value < LAND_MIN) value = LAND_MIN;
    }
    const int LANDS=value;

    cout << "Number of zombies on the map (" << ZOMBIE_MIN << "-" << ZOMBIE_MAX << ", default: "<< ZOMBIE_DEFAULT <<")...>";
    value=ZOMBIE_DEFAULT;
    getline(cin, input);
    if(!input.empty())
    {
        istringstream stream( input );
        stream >> value;
        if(value > ZOMBIE_MAX) value = ZOMBIE_MAX;
        if(value < ZOMBIE_MIN) value = ZOMBIE_MIN;
    }
    const int ZOMBIES=value;

    //game rules
    cout << "=============================================================================" << endl
         << "Plants vs. Zombies Rule:" << endl
         << endl
         << "How to win:" << endl
         << "  (1) All zombies are dead." << endl
         << "  (2) At least one plant is live." << endl
         << "  (3) The number of dead bomb plants cannot exceed the number of zombies." << endl
         << endl
         << "How to lose:" << endl
         << "  All plants are dead." << endl
         << "=============================================================================" << endl;
    system("pause");
    system("cls");

    //construct
    srand(time(0));     // random number seed
    Player *player = new Player;
    Zombie *zombie = new Zombie[ZOMBIES];
    Zombie::TotalNum = ZOMBIES;
    Map *map = new Map(LANDS);
    vector<Plant*> plant;
    fstream fin("plants.txt", fstream::in);
    string str;
    if(fin)
    {
        while(fin >> str)
        {
            Plant *tmp = nullptr;
            switch(str[0])
            {
            case 'C':
            {
                tmp = new CoinPlant(fin);
                break;
            }
            case 'S':
            {
                tmp = new HornPlant(fin);
                break;
            }
            case 'B':
            {
                tmp = new BombPlant(fin);
                break;
            }
            case 'H':
            {
                tmp = new HealPlant(fin);
                break;
            }
            default:
                continue;
            }
            if(tmp)
            {
                plant.push_back(tmp);
            }
        }
    }

    player->Move(rand()%LANDS);
    for (int i=0; i<ZOMBIES; ++i)
        zombie[i].Move(rand()%LANDS);
    int choice = plant.size();
    while(true)
    {
        int position;
        printInfor(*map, *player, zombie);
        do
        {
            position = player->Pos();
            Land * land = map->GetLand(position);
            if(!land->IsEmpty())
            {
                Plant *p = land->GetPlant();
                int visit = p->Visit(*player);
                if(visit < 0)
                {
                    map->Healing(p->HpBack());
                    cout << "All your plants have recovered "<< p->HpBack() << " HP!" << endl;
                    break;
                }
                else if (visit)
                {
                    cout << "You have earned $" << visit << "! Now you have $" << player->Money();
                    break;
                }
                else break;
            }
            else
            {
                if (!enoughMoney(plant, player))
                {
                    cout << "You don't have enough money to plant anything" << endl;
                    break;
                }
                else
                {
                    for(size_t i=0; i<plant.size(); ++i)
                    {
                        cout << "[" << i << "] " ;
                        plant[i]->Print();
                        cout << endl;
                    }
                    cout << endl << "Player $" << player->Money() ;
                    cout << ":\tEnter your choice (" << plant.size() << " to give up, default: " << choice << ")...>";
                    getline(cin, input);
                    if(!input.empty())
                    {
                        istringstream stream( input );
                        stream >> choice;
                        if(choice > plant.size() || choice < 0) choice = plant.size();
                    }
                    if(choice != plant.size())
                    {
                        map->GetLand(player->Pos())->Planting(*player, *plant[choice]);
                        cout << "You have planted " << plant[choice]->Name() << " at land " << player->Pos() << " !" << endl;
                    }
                    break;
                }
                if(choice != plant.size() && plant[choice]->Price() > player->Money())
                {
                    cout << "Not enough money! Please input again!" << endl;
                    system("pause");
                }
            }
        }
        while (true);
        system("pause");
        system("cls");
        for (int i=0; i<ZOMBIES; ++i)
        {
            if (zombie[i].isAlive())
            {
                printInfor(*map, *player, zombie);
                position = rand()%LANDS;
                zombie[i].Move(position);
                cout << "Zombie [" << i << "] moves to land " << position << "." << endl;
                Land * land = map->GetLand(position);
                if(!land->IsEmpty())
                {
                    Plant *p = land->GetPlant();
                    p->Visit(zombie[i]);
                    if(p->Attack())
                    {
                        cout << p->Name() << " gives " << p->Attack() << " damage to the zombie!" << endl;
                    }
                    cout << "Zombie eats plant " << p->Name() << " and cause damage " << zombie[i].Attack() << endl;
                    if(!zombie[i].isAlive())
                        cout << "Zombie is killed!" << endl;
                    if(!p->isAlive())
                    {
                        land->Dead();
                        cout << "Plant " << p->Name() << " is dead!" << endl;
                    }
                }
                system("pause");
                system("cls");
            }
        }
        position = rand()%LANDS;
        player->Move(position);

        // end game condition

        system("cls");
        //break;
    }

    // destruct
    while(!plant.empty())
    {
        delete plant.back();
        plant.pop_back();
    }
    delete player;
    delete map;
    delete [] zombie;

    return 0;
}

bool endGame(const Map & map, const Zombie * zombie)
{
    if (map.IsNonPlant())
    {
        cout << "Oh no... You have no plant on the map ...." << endl;
    }
    else if (BombPlant::deadNum >= ZOMBIES/2)
    {
        cout << "You lose the game since you cannot use that many bomb plants!" << endl;
    }
    else if (allZombiesDie(zombie))
    {
        cout << "Congratulations! You have killed all zombies!" << endl;
    }
}

bool allZombiesDie(const Zombie * zombie)
{
    for(int i=0; i<Zombie::TotalNum && !zombie[i].isAlive(); ++i)
        return (i==Zombie::TotalNum-1);
}

bool enoughMoney(const vector<Plant*> & plant, const Player * player)
{
    for (Plant* p : plant)
        if (p->Price() <= player->Money()) return true;
    return false;
}

void printInfor(const Map & map, const Player & player, const Zombie * zombie)
{
    map.Display(player, zombie);
    cout << "------------------------------------------------" << endl;
    cout << "Zombie information:" << endl;
    for(int i=0; i<Zombie::TotalNum; ++i)
    {
        if(zombie[i].isAlive())
            cout << '[' << i << "] " << zombie[i];
    }
    cout << "================================================" << endl;
}
<|endoftext|>


<commit_before>/******************************************************************************
axelwrap
First commit 06 Apr 2016 by Mike Seery

https://github.com/roleohibachi/axlewrap

An Intel Edison motion tracking tool, intended for sports coaching. Uses Sparkfun 9DOF and gnuplot-iostream.

Development environment specifics:
  Uses i2c only, as it uses Sparkfun's library for comms.
  Code developed in vim, by rubbing two sticks together.
  This code requires the Intel mraa library to function; for more
  information see https://github.com/intel-iot-devkit/mraa

This code is protected by an Apache v2.0 license. See LICENSE for more information.
Distributed as-is; no warranty is given. Which is probably good, because I'm a rank amateur coder. If you can do better, please offer your help to the project!

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

#include "mraa.hpp"
#include <vector>
#include <iostream>
#include <unistd.h>
#include "SFE_LSM9DS0.h"
#include <fstream>

//#define GNUPLOT_ENABLE_PTY //not working?
#include "gnuplot-iostream.h"

using namespace std;

int buffSize = 100;
std::vector<float> x_pts(buffSize, 0.0);
LSM9DS0 *imu;
bool newAccelData = false;
const uint16_t chipID = 0x49d4;

void getData(int howMany){

  bool overflow = false;
    // Of course, we may care if an overflow occurred; we can check that
    //  easily enough from an internal register on the part. There are functions
    //  to check for overflow per device.
    overflow = imu->xDataOverflow();

  if (overflow)
  {
    cerr<<"WARNING: Data overflow has occurred."<<endl;
  }

  cout << "DEBUG: getting " << howMany << " datapoints.\n";

  for(int i=0;i<howMany;i++){
    while ((newAccelData) != true){
      if (newAccelData != true)
      {
        newAccelData = imu->newXData();
      }
    }
    newAccelData = false;

    cout << "." << flush;//DEBUG

    // Calling these functions causes the data to be read from the IMU into
    //  10 16-bit signed integer public variables, as seen below. There is no
    //  automated check on whether the data is new; you need to do that
    //  manually as above. Also, there's no check on overflow, so you may miss
    //  a sample and not know it.

    // cout << "DEBUG: Pulling the hot data...\n";
    imu->readAccel();
    // cout << "DEBUG: Pulled the hot data.\n";

    // cout << "DEBUG: Storing the new data...\n";
    x_pts.push_back(imu->calcAccel(imu->ax));
    // cout << "DEBUG: Stored the new data (" <<x_pts.back() << ").\n";

    // cout << "DEBUG: Resizing the vector...\n";
    x_pts.erase(x_pts.begin());
    // cout << "DEBUG: Resized the vector.\n";
  }
  cout << endl;
}

int main()
{
  //Gnuplot gp(stdout);
  //Gnuplot gp;
  //Gnuplot gp("tee out.gp | gnuplot -persist");

  //gp << "set terminal png"<<endl;
  //gp << "set output out.png"<<endl;
  //cout << "DEBUG: gp configured\n";

  imu = new LSM9DS0(0x6B, 0x1D); //the pinout addresses of the gyro and xm, respectively
  imu -> setAccelScale(imu -> A_SCALE_2G);
  imu -> setAccelODR(imu -> A_ODR_800); // 800 Hz (0x9)
  //cout << "DEBUG: IMU configured.\n";

  uint16_t imuResult = imu->begin();
  //cout<<hex<<"Chip ID: 0x"<<imuResult<<dec<<" (should be 0x49d4)"<<endl;
//TODO fix this test to exit if the chip is bad
  if(imuResult != chipID){
    cout << "The chip is enabled.\n";
  }else{
    cout << "The chip reported ID " << imuResult << endl;
  }

  //cout << "DEBUG: filling buffer...\n";
  getData(buffSize); //fill with data, be patient.
  //cout << "DEBUG: Buffer full!\n";

  // Loop and report data
  while (1)
  {
    getData(10);
    //cout << "DEBUG: Plotting data...\n";
    //gp << "plot '-' using (column(0)):1 with lines"<<endl;
    //gp.send1d(x_pts);
    //cout << "DEBUG: latest is " << x_pts.back() << endl;

    //cout<<"Accel y: "<<imu->calcAccel(imu->ay)<<" g"<<endl;
    //cout<<"Accel z: "<<imu->calcAccel(imu->az)<<" g"<<endl;
    //sleep(1);
  }

	return MRAA_SUCCESS;
}

<commit_msg>first working prototype<commit_after>/******************************************************************************
axelwrap
First commit 06 Apr 2016 by Mike Seery

https://github.com/roleohibachi/axlewrap

An Intel Edison motion tracking tool, intended for sports coaching. Uses Sparkfun 9DOF and gnuplot-iostream.

Development environment specifics:
  Uses i2c only, as it uses Sparkfun's library for comms.
  Code developed in vim, by rubbing two sticks together.
  This code requires the Intel mraa library to function; for more
  information see https://github.com/intel-iot-devkit/mraa

This code is protected by an Apache v2.0 license. See LICENSE for more information.
Distributed as-is; no warranty is given. Which is probably good, because I'm a rank amateur coder. If you can do better, please offer your help to the project!

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

#include "mraa.hpp"
#include <vector>
#include <iostream>
#include <unistd.h>
#include "SFE_LSM9DS0.h"
#include <fstream>

#include "gnuplot-iostream.h"

using namespace std;

int buffSize = 100;
std::vector<float> x_pts(buffSize, 0.0);
LSM9DS0 *imu;
bool newAccelData = false;
const uint16_t chipID = 0x49d4;

void getData(int howMany){

  bool overflow = false;
    // Of course, we may care if an overflow occurred; we can check that
    //  easily enough from an internal register on the part. There are functions
    //  to check for overflow per device.
    overflow = imu->xDataOverflow();

  if (overflow)
  {
    cerr<<"WARNING: Data overflow has occurred."<<endl;
  }

  cout << "DEBUG: getting " << howMany << " datapoints.\n";

  for(int i=0;i<howMany;i++){
    while ((newAccelData) != true){
      if (newAccelData != true)
      {
        newAccelData = imu->newXData();
      }
    }
    newAccelData = false;

    cout << "." << flush;//DEBUG

    // Calling these functions causes the data to be read from the IMU into
    //  10 16-bit signed integer public variables, as seen below. There is no
    //  automated check on whether the data is new; you need to do that
    //  manually as above. Also, there's no check on overflow, so you may miss
    //  a sample and not know it.

    // cout << "DEBUG: Pulling the hot data...\n";
    imu->readAccel();
    // cout << "DEBUG: Pulled the hot data.\n";

    // cout << "DEBUG: Storing the new data...\n";
    x_pts.push_back(imu->calcAccel(imu->ax));
    // cout << "DEBUG: Stored the new data (" <<x_pts.back() << ").\n";

    // cout << "DEBUG: Resizing the vector...\n";
    x_pts.erase(x_pts.begin());
    // cout << "DEBUG: Resized the vector.\n";
  }
  cout << endl;
}

int main()
{
  //Gnuplot gp(stdout);
  //Gnuplot gp;
  //Gnuplot gp(fopen("script.gp", "w"));
  Gnuplot gp("tee out.gp | gnuplot");

  gp << "set terminal png\n";

  cout << "DEBUG: gp configured\n";

  imu = new LSM9DS0(0x6B, 0x1D); //the pinout addresses of the gyro and xm, respectively
  imu -> setAccelScale(imu -> A_SCALE_2G);
  imu -> setAccelODR(imu -> A_ODR_800); // 800 Hz (0x9)
  //cout << "DEBUG: IMU configured.\n";

  uint16_t imuResult = imu->begin();
  //cout<<hex<<"Chip ID: 0x"<<imuResult<<dec<<" (should be 0x49d4)"<<endl;
//TODO fix this test to exit if the chip is bad
  if(imuResult != chipID){
    cout << "The chip is enabled.\n";
  }else{
    cout << "The chip reported ID " << imuResult << endl;
  }

  //cout << "DEBUG: filling buffer...\n";
  getData(buffSize); //fill with data, be patient.
  //cout << "DEBUG: Buffer full!\n";

  // Loop and report data
  while (1)
  {
    getData(10);
    //cout << "DEBUG: Plotting data...\n";
    rename("/var/www/stage.png","/var/www/out.png");
    gp << "set output \"/var/www/stage.png\"\n";
    gp << "plot '-' using (column(0)):1 with lines\n";
    gp.send1d(x_pts);
    //gp << "plot" << gp.file1d(x_pts, "in.dat") << "with lines\n";

    //cout << "DEBUG: plotted up through datapoint " << x_pts.back() << endl;

    //cout<<"Accel y: "<<imu->calcAccel(imu->ay)<<" g"<<endl;
    //cout<<"Accel z: "<<imu->calcAccel(imu->az)<<" g"<<endl;
    //sleep(1);
  }

	return MRAA_SUCCESS;
}

<|endoftext|>


<commit_before>#include "qtcamera.h"
#include "qtcamscanner.h"
#include "qtcamconfig.h"
#include "qtcamdevice.h"
#include <gst/gst.h>

class QtCameraPrivate {
public:
  QtCamConfig *conf;
  QtCamScanner *scanner;
};

QtCamera::QtCamera(QObject *parent) :
  QObject(parent), d_ptr(new QtCameraPrivate) {

  gst_init(0, 0);

  d_ptr->conf = new QtCamConfig(this);
  d_ptr->scanner = new QtCamScanner(d_ptr->conf, this);

  refreshDevices();
}

QtCamera::QtCamera(const QString& configPath, QObject *parent) :
  QObject(parent), d_ptr(new QtCameraPrivate) {

  gst_init(0, 0);

  d_ptr->conf = new QtCamConfig(configPath, this);
  d_ptr->scanner = new QtCamScanner(d_ptr->conf, this);

  refreshDevices();
}

QtCamera::QtCamera(QtCamConfig *config, QObject *parent) :
  QObject(parent), d_ptr(new QtCameraPrivate) {

  gst_init(0, 0);

  d_ptr->conf = config;
  d_ptr->scanner = new QtCamScanner(d_ptr->conf, this);

  refreshDevices();
}

QtCamera::~QtCamera() {
  delete d_ptr; d_ptr = 0;

  gst_deinit();
}

void QtCamera::refreshDevices() {
  d_ptr->scanner->refresh();
}

QList<QPair<QString, QVariant> > QtCamera::devices() const {
  return d_ptr->scanner->devices();
}

QtCamDevice *QtCamera::device(const QVariant& id, QObject *parent) {
  QList<QPair<QString, QVariant> > devs = devices();

  // G++ barfs with foreach and class templates.
  typedef QPair<QString, QVariant> Dev;
  foreach (const Dev& dev, devs) {
    if (dev.second == id) {
      return new QtCamDevice(d_ptr->conf, dev.first, dev.second, parent ? parent : this);
    }
  }

  return 0;
}

QtCamConfig *QtCamera::config() const {
  return d_ptr->conf;
}
<commit_msg>Removed extra new line<commit_after>#include "qtcamera.h"
#include "qtcamscanner.h"
#include "qtcamconfig.h"
#include "qtcamdevice.h"
#include <gst/gst.h>

class QtCameraPrivate {
public:
  QtCamConfig *conf;
  QtCamScanner *scanner;
};

QtCamera::QtCamera(QObject *parent) :
  QObject(parent), d_ptr(new QtCameraPrivate) {

  gst_init(0, 0);

  d_ptr->conf = new QtCamConfig(this);
  d_ptr->scanner = new QtCamScanner(d_ptr->conf, this);

  refreshDevices();
}

QtCamera::QtCamera(const QString& configPath, QObject *parent) :
  QObject(parent), d_ptr(new QtCameraPrivate) {

  gst_init(0, 0);

  d_ptr->conf = new QtCamConfig(configPath, this);
  d_ptr->scanner = new QtCamScanner(d_ptr->conf, this);

  refreshDevices();
}

QtCamera::QtCamera(QtCamConfig *config, QObject *parent) :
  QObject(parent), d_ptr(new QtCameraPrivate) {

  gst_init(0, 0);

  d_ptr->conf = config;
  d_ptr->scanner = new QtCamScanner(d_ptr->conf, this);

  refreshDevices();
}

QtCamera::~QtCamera() {
  delete d_ptr; d_ptr = 0;

  gst_deinit();
}

void QtCamera::refreshDevices() {
  d_ptr->scanner->refresh();
}

QList<QPair<QString, QVariant> > QtCamera::devices() const {
  return d_ptr->scanner->devices();
}

QtCamDevice *QtCamera::device(const QVariant& id, QObject *parent) {
  QList<QPair<QString, QVariant> > devs = devices();

  // G++ barfs with foreach and class templates.
  typedef QPair<QString, QVariant> Dev;
  foreach (const Dev& dev, devs) {
    if (dev.second == id) {
      return new QtCamDevice(d_ptr->conf, dev.first, dev.second, parent ? parent : this);
    }
  }

  return 0;
}

QtCamConfig *QtCamera::config() const {
  return d_ptr->conf;
}
<|endoftext|>


<commit_before>9bd04e82-ad5c-11e7-80c1-ac87a332f658<commit_msg>having coffee<commit_after>9c6440d9-ad5c-11e7-bdd9-ac87a332f658<|endoftext|>


<commit_before>/*
 * events.cpp
 *
 *  Created on: 26 mars 2013
 *      Author: dom
 */

#include <iostream>
#include <sstream>
#include "events.h"
#include "scheduler.h"
#include "blockCode.h"

int Event::nextId = 0;
unsigned int Event::nbLivingEvents = 0;

using namespace std;
using namespace BaseSimulator;

//===========================================================================================================
//
//          Event  (class)
//
//===========================================================================================================

Event::Event(Time t) {
	id = nextId;
	nextId++;
	nbLivingEvents++;
	date = t;
	eventType = EVENT_GENERIC;
	randomNumber = 0;
	EVENT_CONSTRUCTOR_INFO();
}

Event::Event(Event *ev) {
	id = nextId;
	nextId++;
	nbLivingEvents++;
	date = ev->date;
	eventType = ev->eventType;
	randomNumber = 0;
	EVENT_CONSTRUCTOR_INFO();
}

Event::~Event() {
	EVENT_DESTRUCTOR_INFO();
	nbLivingEvents--;
}

const string Event::getEventName() {
	return("Generic Event");
}

unsigned int Event::getNextId() {
	return(nextId);
}

unsigned int Event::getNbLivingEvents() {
	return(nbLivingEvents);
}

//===========================================================================================================
//
//          BlockEvent  (class)
//
//===========================================================================================================

BlockEvent::BlockEvent(Time t, BaseSimulator::BuildingBlock *conBlock) : Event(t) {
	EVENT_CONSTRUCTOR_INFO();
	concernedBlock = conBlock;
	eventType = BLOCKEVENT_GENERIC;
}

BlockEvent::BlockEvent(BlockEvent *ev) : Event(ev) {
	EVENT_CONSTRUCTOR_INFO();
	concernedBlock = ev->concernedBlock;
}

BlockEvent::~BlockEvent() {
	EVENT_DESTRUCTOR_INFO();
}

const string BlockEvent::getEventName() {
	return("Generic BlockEvent");
}

//===========================================================================================================
//
//          CodeStartEvent  (class)
//
//===========================================================================================================

CodeStartEvent::CodeStartEvent(Time t, BaseSimulator::BuildingBlock *conBlock): BlockEvent(t, conBlock) {
	EVENT_CONSTRUCTOR_INFO();
	eventType = EVENT_CODE_START;
}
CodeStartEvent::~CodeStartEvent() {
	EVENT_DESTRUCTOR_INFO();
}

void CodeStartEvent::consumeBlockEvent() {
	EVENT_CONSUME_INFO();
	concernedBlock->blockCode->startup();
}

const string CodeStartEvent::getEventName() {
	return("CodeStart Event");
}

//===========================================================================================================
//
//          CodeEndSimulationEvent  (class)
//
//===========================================================================================================

CodeEndSimulationEvent::CodeEndSimulationEvent(Time t): Event(t) {
	eventType = EVENT_END_SIMULATION;
	EVENT_CONSTRUCTOR_INFO();
}

CodeEndSimulationEvent::~CodeEndSimulationEvent() {
	EVENT_DESTRUCTOR_INFO();
}

void CodeEndSimulationEvent::consume() {
	EVENT_CONSUME_INFO();
	BaseSimulator::getScheduler()->setState(BaseSimulator::Scheduler::ENDED);
}

const string CodeEndSimulationEvent::getEventName() {
	return("CodeEndSimulation Event");
}

//===========================================================================================================
//
//          ProcessLocalEvent  (class)
//
//===========================================================================================================

ProcessLocalEvent::ProcessLocalEvent(Time t, BaseSimulator::BuildingBlock *conBlock): BlockEvent(t, conBlock) {
	EVENT_CONSTRUCTOR_INFO();
	eventType = EVENT_PROCESS_LOCAL_EVENT;
}
ProcessLocalEvent::~ProcessLocalEvent() {
	EVENT_DESTRUCTOR_INFO();
}

void ProcessLocalEvent::consumeBlockEvent() {
	EVENT_CONSUME_INFO();
	concernedBlock->processLocalEvent();
}

const string ProcessLocalEvent::getEventName() {
	return("ProcessLocal Event");
}

//===========================================================================================================
//
//          NetworkInterfaceStartTransmittingEvent  (class)
//
//===========================================================================================================

NetworkInterfaceStartTransmittingEvent::NetworkInterfaceStartTransmittingEvent(Time t, P2PNetworkInterface *ni):Event(t) {
	eventType = EVENT_NI_START_TRANSMITTING;
	interface = ni;
	EVENT_CONSTRUCTOR_INFO();
}
NetworkInterfaceStartTransmittingEvent::~NetworkInterfaceStartTransmittingEvent() {
	EVENT_DESTRUCTOR_INFO();
}

void NetworkInterfaceStartTransmittingEvent::consume() {
	EVENT_CONSUME_INFO();
	interface->send();
}

const string NetworkInterfaceStartTransmittingEvent::getEventName() {
	return("NetworkInterfaceStartTransmitting Event");
}

//===========================================================================================================
//
//          NetworkInterfaceStopTransmittingEvent  (class)
//
//===========================================================================================================

NetworkInterfaceStopTransmittingEvent::NetworkInterfaceStopTransmittingEvent(Time t, P2PNetworkInterface *ni):Event(t) {
	eventType = EVENT_NI_STOP_TRANSMITTING;
	interface = ni;
	EVENT_CONSTRUCTOR_INFO();
}
NetworkInterfaceStopTransmittingEvent::~NetworkInterfaceStopTransmittingEvent() {
	EVENT_DESTRUCTOR_INFO();
}

void NetworkInterfaceStopTransmittingEvent::consume() {
	EVENT_CONSUME_INFO();
	if (!interface->connectedInterface) {
	  cerr << "Warning: connection loss, untransmitted message!" << endl;
	} else {
	  interface->connectedInterface->hostBlock->scheduleLocalEvent(EventPtr(new NetworkInterfaceReceiveEvent(BaseSimulator::getScheduler()->now(), interface->connectedInterface, interface->messageBeingTransmitted)));
	}

	interface->messageBeingTransmitted.reset();
	interface->availabilityDate = BaseSimulator::getScheduler()->now();

	if (interface->outgoingQueue.size() > 0) {
		//cout << "one more to send !!" << endl;
		interface->send();
	}
}

const string NetworkInterfaceStopTransmittingEvent::getEventName() {
	return("NetworkInterfaceStopTransmitting Event");
}

//===========================================================================================================
//
//          NetworkInterfaceReceiveEvent  (class)
//
//===========================================================================================================

NetworkInterfaceReceiveEvent::NetworkInterfaceReceiveEvent(Time t, P2PNetworkInterface *ni, MessagePtr mes):Event(t) {
	eventType = EVENT_NI_RECEIVE;
	interface = ni;
	message = mes;
	EVENT_CONSTRUCTOR_INFO();
}

NetworkInterfaceReceiveEvent::~NetworkInterfaceReceiveEvent() {
	message.reset();
	EVENT_DESTRUCTOR_INFO();
}

void NetworkInterfaceReceiveEvent::consume() {
	EVENT_CONSUME_INFO();
}

const string NetworkInterfaceReceiveEvent::getEventName() {
	return("NetworkInterfaceReceiveEvent Event");
}

//===========================================================================================================
//
//          NetworkInterfaceEnqueueOutgoingEvent  (class)
//
//===========================================================================================================

NetworkInterfaceEnqueueOutgoingEvent::NetworkInterfaceEnqueueOutgoingEvent(Time t, Message *mes, P2PNetworkInterface *ni):Event(t) {
	eventType = EVENT_NI_ENQUEUE_OUTGOING_MESSAGE;
	message = MessagePtr(mes);
	sourceInterface = ni;
	EVENT_CONSTRUCTOR_INFO();
}

NetworkInterfaceEnqueueOutgoingEvent::NetworkInterfaceEnqueueOutgoingEvent(Time t, MessagePtr mes, P2PNetworkInterface *ni):Event(t) {
	eventType = EVENT_NI_ENQUEUE_OUTGOING_MESSAGE;
	message = mes;
	sourceInterface = ni;
	EVENT_CONSTRUCTOR_INFO();
}

NetworkInterfaceEnqueueOutgoingEvent::~NetworkInterfaceEnqueueOutgoingEvent() {
	message.reset();
	EVENT_DESTRUCTOR_INFO();
}

void NetworkInterfaceEnqueueOutgoingEvent::consume() {
	EVENT_CONSUME_INFO();
	sourceInterface->addToOutgoingBuffer(message);
}

const string NetworkInterfaceEnqueueOutgoingEvent::getEventName() {
	return("NetworkInterfaceEnqueueOutgoingEvent Event");
}

//===========================================================================================================
//
//          SetColorEvent  (class)
//
//===========================================================================================================

SetColorEvent::SetColorEvent(Time t, BuildingBlock *conBlock, float r, float g, float b, float a): BlockEvent(t, conBlock) {
	EVENT_CONSTRUCTOR_INFO();
	eventType = EVENT_SET_COLOR;
	randomNumber = conBlock->getNextRandomNumber();
	color = Color(r, g, b, a);
}

SetColorEvent::SetColorEvent(Time t, BuildingBlock *conBlock, Color &c): BlockEvent(t, conBlock) {
	EVENT_CONSTRUCTOR_INFO();
	eventType = EVENT_SET_COLOR;
	randomNumber = conBlock->getNextRandomNumber();
	color = c;
}

SetColorEvent::SetColorEvent(SetColorEvent *ev) : BlockEvent(ev) {
	EVENT_CONSTRUCTOR_INFO();
	color = ev->color;
	//randomNumber = ev->randomNumber;
}

SetColorEvent::~SetColorEvent() {
	EVENT_DESTRUCTOR_INFO();
}

void SetColorEvent::consumeBlockEvent() {
	EVENT_CONSUME_INFO();
	concernedBlock->scheduleLocalEvent(EventPtr(new SetColorEvent(this)));
}

const string SetColorEvent::getEventName() {
	return("SetColor Event");
}

//===========================================================================================================
//
//          AddNeighborEvent  (class)
//
//===========================================================================================================

AddNeighborEvent::AddNeighborEvent(Time t, BuildingBlock *conBlock, uint64_t f, uint64_t ta): BlockEvent(t, conBlock) {
	EVENT_CONSTRUCTOR_INFO();
	eventType = EVENT_ADD_NEIGHBOR;
	face = f;
	target = ta;
}

AddNeighborEvent::AddNeighborEvent(AddNeighborEvent *ev) : BlockEvent(ev) {
	EVENT_CONSTRUCTOR_INFO();
	face = ev->face;
	target = ev->target;
}

AddNeighborEvent::~AddNeighborEvent() {
	EVENT_DESTRUCTOR_INFO();
}

void AddNeighborEvent::consumeBlockEvent() {
	EVENT_CONSUME_INFO();
	concernedBlock->scheduleLocalEvent(EventPtr(new AddNeighborEvent(this)));
}

const string AddNeighborEvent::getEventName() {
	return("AddNeighbor Event");
}

//===========================================================================================================
//
//          RemoveNeighborEvent  (class)
//
//===========================================================================================================

RemoveNeighborEvent::RemoveNeighborEvent(Time t, BuildingBlock *conBlock, uint64_t f): BlockEvent(t, conBlock) {
	EVENT_CONSTRUCTOR_INFO();
	eventType = EVENT_REMOVE_NEIGHBOR;
	face = f;
}

RemoveNeighborEvent::RemoveNeighborEvent(RemoveNeighborEvent *ev) : BlockEvent(ev) {
	EVENT_CONSTRUCTOR_INFO();
	face = ev->face;
}

RemoveNeighborEvent::~RemoveNeighborEvent() {
	EVENT_DESTRUCTOR_INFO();
}

void RemoveNeighborEvent::consumeBlockEvent() {
	EVENT_CONSUME_INFO();
	concernedBlock->scheduleLocalEvent(EventPtr(new RemoveNeighborEvent(this)));
}

const string RemoveNeighborEvent::getEventName() {
	return("RemoveNeighbor Event");
}

//===========================================================================================================
//
//          TapEvent  (class)
//
//===========================================================================================================

TapEvent::TapEvent(Time t, BuildingBlock *conBlock, const int face):
	BlockEvent(t, conBlock), tappedFace(face) {
	EVENT_CONSTRUCTOR_INFO();
	eventType = EVENT_TAP;
}

TapEvent::TapEvent(TapEvent *ev) : BlockEvent(ev), tappedFace(ev->tappedFace) {
	EVENT_CONSTRUCTOR_INFO();
}

TapEvent::~TapEvent() {
	EVENT_DESTRUCTOR_INFO();
}

void TapEvent::consumeBlockEvent() {
	EVENT_CONSUME_INFO();
	concernedBlock->scheduleLocalEvent(EventPtr(new TapEvent(this)));
}

const string TapEvent::getEventName() {
	return("Tap Event");
}

//===========================================================================================================
//
//          AccelEvent  (class)
//
//===========================================================================================================

AccelEvent::AccelEvent(Time t, BuildingBlock *conBlock, uint64_t xx, uint64_t yy, uint64_t zz): BlockEvent(t, conBlock) {
	EVENT_CONSTRUCTOR_INFO();
	eventType = EVENT_ACCEL;
	x = xx;
	y = yy;
	z = zz;
}

AccelEvent::AccelEvent(AccelEvent *ev) : BlockEvent(ev) {
	EVENT_CONSTRUCTOR_INFO();
	x = ev->x;
	y = ev->y;
	z = ev->z;
}

AccelEvent::~AccelEvent() {
	EVENT_DESTRUCTOR_INFO();
}

void AccelEvent::consumeBlockEvent() {
	EVENT_CONSUME_INFO();
	concernedBlock->scheduleLocalEvent(EventPtr(new AccelEvent(this)));
}

const string AccelEvent::getEventName() {
	return("Accel Event");
}

//===========================================================================================================
//
//          ShakeEvent  (class)
//
//===========================================================================================================

ShakeEvent::ShakeEvent(Time t, BuildingBlock *conBlock, uint64_t f): BlockEvent(t, conBlock) {
	EVENT_CONSTRUCTOR_INFO();
	eventType = EVENT_SHAKE;
	force = f;
}

ShakeEvent::ShakeEvent(ShakeEvent *ev) : BlockEvent(ev) {
	EVENT_CONSTRUCTOR_INFO();
	force = ev->force;
}

ShakeEvent::~ShakeEvent() {
	EVENT_DESTRUCTOR_INFO();
}

void ShakeEvent::consumeBlockEvent() {
	EVENT_CONSUME_INFO();
	concernedBlock->scheduleLocalEvent(EventPtr(new ShakeEvent(this)));
}

const string ShakeEvent::getEventName() {
	return("Shake Event");
}
<commit_msg>Warning for message loss due to disconnection is now printed in the simulation log file.<commit_after>/*
 * events.cpp
 *
 *  Created on: 26 mars 2013
 *      Author: dom
 */

#include <iostream>
#include <sstream>
#include "events.h"
#include "scheduler.h"
#include "blockCode.h"

int Event::nextId = 0;
unsigned int Event::nbLivingEvents = 0;

using namespace std;
using namespace BaseSimulator;

//===========================================================================================================
//
//          Event  (class)
//
//===========================================================================================================

Event::Event(Time t) {
	id = nextId;
	nextId++;
	nbLivingEvents++;
	date = t;
	eventType = EVENT_GENERIC;
	randomNumber = 0;
	EVENT_CONSTRUCTOR_INFO();
}

Event::Event(Event *ev) {
	id = nextId;
	nextId++;
	nbLivingEvents++;
	date = ev->date;
	eventType = ev->eventType;
	randomNumber = 0;
	EVENT_CONSTRUCTOR_INFO();
}

Event::~Event() {
	EVENT_DESTRUCTOR_INFO();
	nbLivingEvents--;
}

const string Event::getEventName() {
	return("Generic Event");
}

unsigned int Event::getNextId() {
	return(nextId);
}

unsigned int Event::getNbLivingEvents() {
	return(nbLivingEvents);
}

//===========================================================================================================
//
//          BlockEvent  (class)
//
//===========================================================================================================

BlockEvent::BlockEvent(Time t, BaseSimulator::BuildingBlock *conBlock) : Event(t) {
	EVENT_CONSTRUCTOR_INFO();
	concernedBlock = conBlock;
	eventType = BLOCKEVENT_GENERIC;
}

BlockEvent::BlockEvent(BlockEvent *ev) : Event(ev) {
	EVENT_CONSTRUCTOR_INFO();
	concernedBlock = ev->concernedBlock;
}

BlockEvent::~BlockEvent() {
	EVENT_DESTRUCTOR_INFO();
}

const string BlockEvent::getEventName() {
	return("Generic BlockEvent");
}

//===========================================================================================================
//
//          CodeStartEvent  (class)
//
//===========================================================================================================

CodeStartEvent::CodeStartEvent(Time t, BaseSimulator::BuildingBlock *conBlock): BlockEvent(t, conBlock) {
	EVENT_CONSTRUCTOR_INFO();
	eventType = EVENT_CODE_START;
}
CodeStartEvent::~CodeStartEvent() {
	EVENT_DESTRUCTOR_INFO();
}

void CodeStartEvent::consumeBlockEvent() {
	EVENT_CONSUME_INFO();
	concernedBlock->blockCode->startup();
}

const string CodeStartEvent::getEventName() {
	return("CodeStart Event");
}

//===========================================================================================================
//
//          CodeEndSimulationEvent  (class)
//
//===========================================================================================================

CodeEndSimulationEvent::CodeEndSimulationEvent(Time t): Event(t) {
	eventType = EVENT_END_SIMULATION;
	EVENT_CONSTRUCTOR_INFO();
}

CodeEndSimulationEvent::~CodeEndSimulationEvent() {
	EVENT_DESTRUCTOR_INFO();
}

void CodeEndSimulationEvent::consume() {
	EVENT_CONSUME_INFO();
	BaseSimulator::getScheduler()->setState(BaseSimulator::Scheduler::ENDED);
}

const string CodeEndSimulationEvent::getEventName() {
	return("CodeEndSimulation Event");
}

//===========================================================================================================
//
//          ProcessLocalEvent  (class)
//
//===========================================================================================================

ProcessLocalEvent::ProcessLocalEvent(Time t, BaseSimulator::BuildingBlock *conBlock): BlockEvent(t, conBlock) {
	EVENT_CONSTRUCTOR_INFO();
	eventType = EVENT_PROCESS_LOCAL_EVENT;
}
ProcessLocalEvent::~ProcessLocalEvent() {
	EVENT_DESTRUCTOR_INFO();
}

void ProcessLocalEvent::consumeBlockEvent() {
	EVENT_CONSUME_INFO();
	concernedBlock->processLocalEvent();
}

const string ProcessLocalEvent::getEventName() {
	return("ProcessLocal Event");
}

//===========================================================================================================
//
//          NetworkInterfaceStartTransmittingEvent  (class)
//
//===========================================================================================================

NetworkInterfaceStartTransmittingEvent::NetworkInterfaceStartTransmittingEvent(Time t, P2PNetworkInterface *ni):Event(t) {
	eventType = EVENT_NI_START_TRANSMITTING;
	interface = ni;
	EVENT_CONSTRUCTOR_INFO();
}
NetworkInterfaceStartTransmittingEvent::~NetworkInterfaceStartTransmittingEvent() {
	EVENT_DESTRUCTOR_INFO();
}

void NetworkInterfaceStartTransmittingEvent::consume() {
	EVENT_CONSUME_INFO();
	interface->send();
}

const string NetworkInterfaceStartTransmittingEvent::getEventName() {
	return("NetworkInterfaceStartTransmitting Event");
}

//===========================================================================================================
//
//          NetworkInterfaceStopTransmittingEvent  (class)
//
//===========================================================================================================

NetworkInterfaceStopTransmittingEvent::NetworkInterfaceStopTransmittingEvent(Time t, P2PNetworkInterface *ni):Event(t) {
	eventType = EVENT_NI_STOP_TRANSMITTING;
	interface = ni;
	EVENT_CONSTRUCTOR_INFO();
}
NetworkInterfaceStopTransmittingEvent::~NetworkInterfaceStopTransmittingEvent() {
	EVENT_DESTRUCTOR_INFO();
}

void NetworkInterfaceStopTransmittingEvent::consume() {
	EVENT_CONSUME_INFO();
	if (!interface->connectedInterface) {
	  ERRPUT << "Warning: connection loss, untransmitted message!" << endl;
	} else {
	  interface->connectedInterface->hostBlock->scheduleLocalEvent(EventPtr(new NetworkInterfaceReceiveEvent(BaseSimulator::getScheduler()->now(), interface->connectedInterface, interface->messageBeingTransmitted)));
	}

	interface->messageBeingTransmitted.reset();
	interface->availabilityDate = BaseSimulator::getScheduler()->now();

	if (interface->outgoingQueue.size() > 0) {
		//cout << "one more to send !!" << endl;
		interface->send();
	}
}

const string NetworkInterfaceStopTransmittingEvent::getEventName() {
	return("NetworkInterfaceStopTransmitting Event");
}

//===========================================================================================================
//
//          NetworkInterfaceReceiveEvent  (class)
//
//===========================================================================================================

NetworkInterfaceReceiveEvent::NetworkInterfaceReceiveEvent(Time t, P2PNetworkInterface *ni, MessagePtr mes):Event(t) {
	eventType = EVENT_NI_RECEIVE;
	interface = ni;
	message = mes;
	EVENT_CONSTRUCTOR_INFO();
}

NetworkInterfaceReceiveEvent::~NetworkInterfaceReceiveEvent() {
	message.reset();
	EVENT_DESTRUCTOR_INFO();
}

void NetworkInterfaceReceiveEvent::consume() {
	EVENT_CONSUME_INFO();
}

const string NetworkInterfaceReceiveEvent::getEventName() {
	return("NetworkInterfaceReceiveEvent Event");
}

//===========================================================================================================
//
//          NetworkInterfaceEnqueueOutgoingEvent  (class)
//
//===========================================================================================================

NetworkInterfaceEnqueueOutgoingEvent::NetworkInterfaceEnqueueOutgoingEvent(Time t, Message *mes, P2PNetworkInterface *ni):Event(t) {
	eventType = EVENT_NI_ENQUEUE_OUTGOING_MESSAGE;
	message = MessagePtr(mes);
	sourceInterface = ni;
	EVENT_CONSTRUCTOR_INFO();
}

NetworkInterfaceEnqueueOutgoingEvent::NetworkInterfaceEnqueueOutgoingEvent(Time t, MessagePtr mes, P2PNetworkInterface *ni):Event(t) {
	eventType = EVENT_NI_ENQUEUE_OUTGOING_MESSAGE;
	message = mes;
	sourceInterface = ni;
	EVENT_CONSTRUCTOR_INFO();
}

NetworkInterfaceEnqueueOutgoingEvent::~NetworkInterfaceEnqueueOutgoingEvent() {
	message.reset();
	EVENT_DESTRUCTOR_INFO();
}

void NetworkInterfaceEnqueueOutgoingEvent::consume() {
	EVENT_CONSUME_INFO();
	sourceInterface->addToOutgoingBuffer(message);
}

const string NetworkInterfaceEnqueueOutgoingEvent::getEventName() {
	return("NetworkInterfaceEnqueueOutgoingEvent Event");
}

//===========================================================================================================
//
//          SetColorEvent  (class)
//
//===========================================================================================================

SetColorEvent::SetColorEvent(Time t, BuildingBlock *conBlock, float r, float g, float b, float a): BlockEvent(t, conBlock) {
	EVENT_CONSTRUCTOR_INFO();
	eventType = EVENT_SET_COLOR;
	randomNumber = conBlock->getNextRandomNumber();
	color = Color(r, g, b, a);
}

SetColorEvent::SetColorEvent(Time t, BuildingBlock *conBlock, Color &c): BlockEvent(t, conBlock) {
	EVENT_CONSTRUCTOR_INFO();
	eventType = EVENT_SET_COLOR;
	randomNumber = conBlock->getNextRandomNumber();
	color = c;
}

SetColorEvent::SetColorEvent(SetColorEvent *ev) : BlockEvent(ev) {
	EVENT_CONSTRUCTOR_INFO();
	color = ev->color;
	//randomNumber = ev->randomNumber;
}

SetColorEvent::~SetColorEvent() {
	EVENT_DESTRUCTOR_INFO();
}

void SetColorEvent::consumeBlockEvent() {
	EVENT_CONSUME_INFO();
	concernedBlock->scheduleLocalEvent(EventPtr(new SetColorEvent(this)));
}

const string SetColorEvent::getEventName() {
	return("SetColor Event");
}

//===========================================================================================================
//
//          AddNeighborEvent  (class)
//
//===========================================================================================================

AddNeighborEvent::AddNeighborEvent(Time t, BuildingBlock *conBlock, uint64_t f, uint64_t ta): BlockEvent(t, conBlock) {
	EVENT_CONSTRUCTOR_INFO();
	eventType = EVENT_ADD_NEIGHBOR;
	face = f;
	target = ta;
}

AddNeighborEvent::AddNeighborEvent(AddNeighborEvent *ev) : BlockEvent(ev) {
	EVENT_CONSTRUCTOR_INFO();
	face = ev->face;
	target = ev->target;
}

AddNeighborEvent::~AddNeighborEvent() {
	EVENT_DESTRUCTOR_INFO();
}

void AddNeighborEvent::consumeBlockEvent() {
	EVENT_CONSUME_INFO();
	concernedBlock->scheduleLocalEvent(EventPtr(new AddNeighborEvent(this)));
}

const string AddNeighborEvent::getEventName() {
	return("AddNeighbor Event");
}

//===========================================================================================================
//
//          RemoveNeighborEvent  (class)
//
//===========================================================================================================

RemoveNeighborEvent::RemoveNeighborEvent(Time t, BuildingBlock *conBlock, uint64_t f): BlockEvent(t, conBlock) {
	EVENT_CONSTRUCTOR_INFO();
	eventType = EVENT_REMOVE_NEIGHBOR;
	face = f;
}

RemoveNeighborEvent::RemoveNeighborEvent(RemoveNeighborEvent *ev) : BlockEvent(ev) {
	EVENT_CONSTRUCTOR_INFO();
	face = ev->face;
}

RemoveNeighborEvent::~RemoveNeighborEvent() {
	EVENT_DESTRUCTOR_INFO();
}

void RemoveNeighborEvent::consumeBlockEvent() {
	EVENT_CONSUME_INFO();
	concernedBlock->scheduleLocalEvent(EventPtr(new RemoveNeighborEvent(this)));
}

const string RemoveNeighborEvent::getEventName() {
	return("RemoveNeighbor Event");
}

//===========================================================================================================
//
//          TapEvent  (class)
//
//===========================================================================================================

TapEvent::TapEvent(Time t, BuildingBlock *conBlock, const int face):
	BlockEvent(t, conBlock), tappedFace(face) {
	EVENT_CONSTRUCTOR_INFO();
	eventType = EVENT_TAP;
}

TapEvent::TapEvent(TapEvent *ev) : BlockEvent(ev), tappedFace(ev->tappedFace) {
	EVENT_CONSTRUCTOR_INFO();
}

TapEvent::~TapEvent() {
	EVENT_DESTRUCTOR_INFO();
}

void TapEvent::consumeBlockEvent() {
	EVENT_CONSUME_INFO();
	concernedBlock->scheduleLocalEvent(EventPtr(new TapEvent(this)));
}

const string TapEvent::getEventName() {
	return("Tap Event");
}

//===========================================================================================================
//
//          AccelEvent  (class)
//
//===========================================================================================================

AccelEvent::AccelEvent(Time t, BuildingBlock *conBlock, uint64_t xx, uint64_t yy, uint64_t zz): BlockEvent(t, conBlock) {
	EVENT_CONSTRUCTOR_INFO();
	eventType = EVENT_ACCEL;
	x = xx;
	y = yy;
	z = zz;
}

AccelEvent::AccelEvent(AccelEvent *ev) : BlockEvent(ev) {
	EVENT_CONSTRUCTOR_INFO();
	x = ev->x;
	y = ev->y;
	z = ev->z;
}

AccelEvent::~AccelEvent() {
	EVENT_DESTRUCTOR_INFO();
}

void AccelEvent::consumeBlockEvent() {
	EVENT_CONSUME_INFO();
	concernedBlock->scheduleLocalEvent(EventPtr(new AccelEvent(this)));
}

const string AccelEvent::getEventName() {
	return("Accel Event");
}

//===========================================================================================================
//
//          ShakeEvent  (class)
//
//===========================================================================================================

ShakeEvent::ShakeEvent(Time t, BuildingBlock *conBlock, uint64_t f): BlockEvent(t, conBlock) {
	EVENT_CONSTRUCTOR_INFO();
	eventType = EVENT_SHAKE;
	force = f;
}

ShakeEvent::ShakeEvent(ShakeEvent *ev) : BlockEvent(ev) {
	EVENT_CONSTRUCTOR_INFO();
	force = ev->force;
}

ShakeEvent::~ShakeEvent() {
	EVENT_DESTRUCTOR_INFO();
}

void ShakeEvent::consumeBlockEvent() {
	EVENT_CONSUME_INFO();
	concernedBlock->scheduleLocalEvent(EventPtr(new ShakeEvent(this)));
}

const string ShakeEvent::getEventName() {
	return("Shake Event");
}
<|endoftext|>


<commit_before><commit_msg>fix double-delete<commit_after><|endoftext|>


<commit_before><commit_msg>Set default cycle time to 0<commit_after><|endoftext|>


<commit_before>#include <assert.h>
#include <stdio.h>
#include <atomic>
#include <new>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <pthread.h>
#include <signal.h>
#include <setjmp.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include "mtrace.h"
#include "fstest.h"
#include "libutil.h"
#include "spinbarrier.hh"

extern char _end[];
__thread sigjmp_buf pf_jmpbuf;
__thread int pf_active;

class double_barrier {
  spin_barrier enter_;
  spin_barrier exit_;

public:
  double_barrier() : enter_(2), exit_(2) {}
  void sync() { enter(); exit(); }
  void enter() { enter_.join(); }
  void exit() { exit_.join(); }
};

struct testproc {
  double_barrier setup;
  std::atomic<void (*)(void)> setupf;

  testproc(void (*s)(void)) : setupf(s) {}
  void run() {
    setup.enter();
    setupf();
    setup.exit();
  }
};

struct testfunc {
  double_barrier start;
  double_barrier stop;

  std::atomic<int (*)(void)> func;
  std::atomic<int> retval;

  testfunc(int (*f)(void)) : func(f) {}
  void run() {
    start.sync();
    retval = func();
    stop.sync();
  }
};

static void*
testfunc_thread(void* arg)
{
  madvise(0, (size_t) _end, MADV_WILLNEED);
  testfunc* f = (testfunc*) arg;
  f->run();
  return nullptr;
}

static void
run_test(testproc* tp, testfunc* tf, fstest* t, int first_func, bool do_pin)
{
  assert(first_func == 0 || first_func == 1);
  if (do_pin)
    setaffinity(2);

  for (int i = 0; i < 2; i++)
    new (&tp[i]) testproc(t->proc[i].setup_proc);
  for (int i = 0; i < 2; i++)
    new (&tf[i]) testfunc(t->func[i].call);

  pid_t pids[2] = { 0, 0 };
  for (int p = 0; p < 2; p++) {
    int nfunc = 0;
    for (int f = 0; f < 2; f++)
      if (t->func[f].callproc == p)
        nfunc++;
    if (nfunc == 0)
      continue;

    pids[p] = fork();
    assert(pids[p] >= 0);

    if (pids[p] == 0) {
      madvise(0, (size_t) _end, MADV_WILLNEED);
      tp[p].run();

      int ndone = 0;
      pthread_t tid[2];
      for (int f = 0; f < 2; f++) {
        if (t->func[f].callproc == p) {
          if (do_pin)
            setaffinity(f);
          ndone++;
          if (ndone == nfunc)
            testfunc_thread(&tf[f]);
          else
            pthread_create(&tid[f], 0, testfunc_thread, (void*) &tf[f]);
        }
      }

      if (nfunc == 2)
        pthread_join(tid[0], nullptr);
      exit(0);
    }
  }

  t->setup_common();
  for (int p = 0; p < 2; p++) if (pids[p]) tp[p].setup.sync();
  t->setup_final();

  for (int i = 0; i < 2; i++) tf[i].start.enter();

  char mtname[64];
  snprintf(mtname, sizeof(mtname), "%s", t->testname);
  mtenable_type(mtrace_record_ascope, mtname);

  for (int i = 0; i < 2; i++) {
    tf[first_func ^ i].start.exit();
    tf[first_func ^ i].stop.enter();
  }

  mtdisable(mtname);

  for (int i = 0; i < 2; i++) tf[i].stop.exit();

  for (int p = 0; p < 2; p++)
    if (pids[p])
      assert(waitpid(pids[p], nullptr, 0) >= 0);

  t->cleanup();
}

static void
pf_handler(int signo)
{
  if (pf_active)
    siglongjmp(pf_jmpbuf, signo);
  // Let the error happen
  signal(signo, SIG_DFL);
}

static bool verbose = false;
static bool check_commutativity = false;
static bool run_threads = false;

static void
usage(const char* prog)
{
  fprintf(stderr, "Usage: %s [-v] [-c] [-t] [-n NPARTS] [-p THISPART] [min[-max]]\n", prog);
}

int
main(int ac, char** av)
{
  uint32_t min = 0;
  uint32_t max = UINT_MAX;
  int nparts = -1;
  int thispart = -1;

  uint32_t ntests = 0;
  for (ntests = min; fstests[ntests].testname; ntests++)
    ;

  for (;;) {
    int opt = getopt(ac, av, "vctp:n:");
    if (opt == -1)
      break;

    switch (opt) {
    case 'v':
      verbose = true;
      break;

    case 'c':
      check_commutativity = true;
      break;

    case 't':
      run_threads = true;
      break;

    case 'n':
      nparts = atoi(optarg);
      break;

    case 'p':
      thispart = atoi(optarg);
      break;

    default:
      usage(av[0]);
      return -1;
    }
  }

  if (optind < ac) {
    char* dash = strchr(av[optind], '-');
    if (!dash) {
      min = max = atoi(av[optind]);
    } else {
      *dash = '\0';
      min = atoi(av[optind]);
      max = atoi(dash + 1);
    }
  } else if (nparts >= 0 || thispart >= 0) {
    if (nparts < 0 || thispart < 0) {
      usage(av[0]);
      return -1;
    }

    uint32_t partsize = (ntests + nparts - 1) /nparts;
    min = partsize * thispart;
    max = partsize * (thispart + 1) - 1;
  }

  if (!check_commutativity && !run_threads) {
    fprintf(stderr, "Must specify one of -c or -t\n");
    usage(av[0]);
    return -1;
  }

  printf("fstest:");
  if (verbose)
    printf(" verbose");
  if (check_commutativity)
    printf(" check");
  if (run_threads)
    printf(" threads");
  if (min == 0 && max == UINT_MAX)
    printf(" all");
  else if (min == max)
    printf(" %d", min);
  else
    printf(" %d-%d", min, max);
  printf("\n");

  testproc* tp = (testproc*) mmap(nullptr, 4096, PROT_READ | PROT_WRITE,
                                  MAP_SHARED | MAP_ANONYMOUS, -1, 0);
  assert(tp != MAP_FAILED);
  assert(2*sizeof(*tp) <= 4096);

  testfunc* tf = (testfunc*) mmap(nullptr, 4096, PROT_READ | PROT_WRITE,
                                  MAP_SHARED | MAP_ANONYMOUS, -1, 0);
  assert(tf != MAP_FAILED);
  assert(2*sizeof(*tf) <= 4096);

  madvise(0, (size_t) _end, MADV_WILLNEED);

  signal(SIGBUS, pf_handler);
  signal(SIGSEGV, pf_handler);

  for (uint32_t t = min; t <= max && t < ntests; t++) {
    if (check_commutativity) {
      run_test(tp, tf, &fstests[t], 0, false);
      int ra0 = tf[0].retval;
      int ra1 = tf[1].retval;

      run_test(tp, tf, &fstests[t], 1, false);
      int rb0 = tf[0].retval;
      int rb1 = tf[1].retval;

      if (ra0 == rb0 && ra1 == rb1) {
        if (verbose)
          printf("%s: commutes: %s->%d %s->%d\n",
                 fstests[t].testname,
                 fstests[t].func[0].callname, ra0, fstests[t].func[1].callname, ra1);
      } else {
        printf("%s: diverges: %s->%d %s->%d vs %s->%d %s->%d\n",
               fstests[t].testname,
               fstests[t].func[0].callname, ra0, fstests[t].func[1].callname, ra1,
               fstests[t].func[1].callname, rb1, fstests[t].func[0].callname, rb0);
      }
    }

    if (run_threads) {
      run_test(tp, tf, &fstests[t], 0, true);
      printf("%s: threads done\n", fstests[t].testname);
    }
  }
}
<commit_msg>fstest: Flush stdout before forking<commit_after>#include <assert.h>
#include <stdio.h>
#include <atomic>
#include <new>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <pthread.h>
#include <signal.h>
#include <setjmp.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include "mtrace.h"
#include "fstest.h"
#include "libutil.h"
#include "spinbarrier.hh"

extern char _end[];
__thread sigjmp_buf pf_jmpbuf;
__thread int pf_active;

class double_barrier {
  spin_barrier enter_;
  spin_barrier exit_;

public:
  double_barrier() : enter_(2), exit_(2) {}
  void sync() { enter(); exit(); }
  void enter() { enter_.join(); }
  void exit() { exit_.join(); }
};

struct testproc {
  double_barrier setup;
  std::atomic<void (*)(void)> setupf;

  testproc(void (*s)(void)) : setupf(s) {}
  void run() {
    setup.enter();
    setupf();
    setup.exit();
  }
};

struct testfunc {
  double_barrier start;
  double_barrier stop;

  std::atomic<int (*)(void)> func;
  std::atomic<int> retval;

  testfunc(int (*f)(void)) : func(f) {}
  void run() {
    start.sync();
    retval = func();
    stop.sync();
  }
};

static void*
testfunc_thread(void* arg)
{
  madvise(0, (size_t) _end, MADV_WILLNEED);
  testfunc* f = (testfunc*) arg;
  f->run();
  return nullptr;
}

static void
run_test(testproc* tp, testfunc* tf, fstest* t, int first_func, bool do_pin)
{
  assert(first_func == 0 || first_func == 1);
  if (do_pin)
    setaffinity(2);

  for (int i = 0; i < 2; i++)
    new (&tp[i]) testproc(t->proc[i].setup_proc);
  for (int i = 0; i < 2; i++)
    new (&tf[i]) testfunc(t->func[i].call);

  pid_t pids[2] = { 0, 0 };
  for (int p = 0; p < 2; p++) {
    int nfunc = 0;
    for (int f = 0; f < 2; f++)
      if (t->func[f].callproc == p)
        nfunc++;
    if (nfunc == 0)
      continue;

    fflush(stdout);
    pids[p] = fork();
    assert(pids[p] >= 0);

    if (pids[p] == 0) {
      madvise(0, (size_t) _end, MADV_WILLNEED);
      tp[p].run();

      int ndone = 0;
      pthread_t tid[2];
      for (int f = 0; f < 2; f++) {
        if (t->func[f].callproc == p) {
          if (do_pin)
            setaffinity(f);
          ndone++;
          if (ndone == nfunc)
            testfunc_thread(&tf[f]);
          else
            pthread_create(&tid[f], 0, testfunc_thread, (void*) &tf[f]);
        }
      }

      if (nfunc == 2)
        pthread_join(tid[0], nullptr);
      exit(0);
    }
  }

  t->setup_common();
  for (int p = 0; p < 2; p++) if (pids[p]) tp[p].setup.sync();
  t->setup_final();

  for (int i = 0; i < 2; i++) tf[i].start.enter();

  char mtname[64];
  snprintf(mtname, sizeof(mtname), "%s", t->testname);
  mtenable_type(mtrace_record_ascope, mtname);

  for (int i = 0; i < 2; i++) {
    tf[first_func ^ i].start.exit();
    tf[first_func ^ i].stop.enter();
  }

  mtdisable(mtname);

  for (int i = 0; i < 2; i++) tf[i].stop.exit();

  for (int p = 0; p < 2; p++)
    if (pids[p])
      assert(waitpid(pids[p], nullptr, 0) >= 0);

  t->cleanup();
}

static void
pf_handler(int signo)
{
  if (pf_active)
    siglongjmp(pf_jmpbuf, signo);
  // Let the error happen
  signal(signo, SIG_DFL);
}

static bool verbose = false;
static bool check_commutativity = false;
static bool run_threads = false;

static void
usage(const char* prog)
{
  fprintf(stderr, "Usage: %s [-v] [-c] [-t] [-n NPARTS] [-p THISPART] [min[-max]]\n", prog);
}

int
main(int ac, char** av)
{
  uint32_t min = 0;
  uint32_t max = UINT_MAX;
  int nparts = -1;
  int thispart = -1;

  uint32_t ntests = 0;
  for (ntests = min; fstests[ntests].testname; ntests++)
    ;

  for (;;) {
    int opt = getopt(ac, av, "vctp:n:");
    if (opt == -1)
      break;

    switch (opt) {
    case 'v':
      verbose = true;
      break;

    case 'c':
      check_commutativity = true;
      break;

    case 't':
      run_threads = true;
      break;

    case 'n':
      nparts = atoi(optarg);
      break;

    case 'p':
      thispart = atoi(optarg);
      break;

    default:
      usage(av[0]);
      return -1;
    }
  }

  if (optind < ac) {
    char* dash = strchr(av[optind], '-');
    if (!dash) {
      min = max = atoi(av[optind]);
    } else {
      *dash = '\0';
      min = atoi(av[optind]);
      max = atoi(dash + 1);
    }
  } else if (nparts >= 0 || thispart >= 0) {
    if (nparts < 0 || thispart < 0) {
      usage(av[0]);
      return -1;
    }

    uint32_t partsize = (ntests + nparts - 1) /nparts;
    min = partsize * thispart;
    max = partsize * (thispart + 1) - 1;
  }

  if (!check_commutativity && !run_threads) {
    fprintf(stderr, "Must specify one of -c or -t\n");
    usage(av[0]);
    return -1;
  }

  printf("fstest:");
  if (verbose)
    printf(" verbose");
  if (check_commutativity)
    printf(" check");
  if (run_threads)
    printf(" threads");
  if (min == 0 && max == UINT_MAX)
    printf(" all");
  else if (min == max)
    printf(" %d", min);
  else
    printf(" %d-%d", min, max);
  printf("\n");

  testproc* tp = (testproc*) mmap(nullptr, 4096, PROT_READ | PROT_WRITE,
                                  MAP_SHARED | MAP_ANONYMOUS, -1, 0);
  assert(tp != MAP_FAILED);
  assert(2*sizeof(*tp) <= 4096);

  testfunc* tf = (testfunc*) mmap(nullptr, 4096, PROT_READ | PROT_WRITE,
                                  MAP_SHARED | MAP_ANONYMOUS, -1, 0);
  assert(tf != MAP_FAILED);
  assert(2*sizeof(*tf) <= 4096);

  madvise(0, (size_t) _end, MADV_WILLNEED);

  signal(SIGBUS, pf_handler);
  signal(SIGSEGV, pf_handler);

  for (uint32_t t = min; t <= max && t < ntests; t++) {
    if (check_commutativity) {
      run_test(tp, tf, &fstests[t], 0, false);
      int ra0 = tf[0].retval;
      int ra1 = tf[1].retval;

      run_test(tp, tf, &fstests[t], 1, false);
      int rb0 = tf[0].retval;
      int rb1 = tf[1].retval;

      if (ra0 == rb0 && ra1 == rb1) {
        if (verbose)
          printf("%s: commutes: %s->%d %s->%d\n",
                 fstests[t].testname,
                 fstests[t].func[0].callname, ra0, fstests[t].func[1].callname, ra1);
      } else {
        printf("%s: diverges: %s->%d %s->%d vs %s->%d %s->%d\n",
               fstests[t].testname,
               fstests[t].func[0].callname, ra0, fstests[t].func[1].callname, ra1,
               fstests[t].func[1].callname, rb1, fstests[t].func[0].callname, rb0);
      }
    }

    if (run_threads) {
      run_test(tp, tf, &fstests[t], 0, true);
      printf("%s: threads done\n", fstests[t].testname);
    }
  }
}
<|endoftext|>


<commit_before>/**
 *   Copyright 2016, Quickstep Research Group, Computer Sciences Department,
 *   University of Wisconsin—Madison.
 *
 *   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 QUICKSTEP_UTILITY_TEMPLATE_UTIL_HPP_
#define QUICKSTEP_UTILITY_TEMPLATE_UTIL_HPP_

#include <tuple>
#include <utility>

namespace quickstep {

/** \addtogroup Utility
 *  @{
 */

/**
 * @brief Represents a compile-time sequence of integers.
 *
 * Seq is defined here for C++11 compatibility. For C++14 and above,
 * std::integer_sequence can be used to achieve the same functionality.
 */
template<std::size_t ...>
struct Seq {};

/**
 * @brief The helper class for creating Seq. GenSeq<N>::type is equivalent to
 *        Seq<1,2,...,N>.
 *
 * GenSeq is defined here for C++11 compatibility. For C++14 and above,
 * std::make_interger_sequence can be used to achieve the same functionality.
 */
template<std::size_t N, std::size_t ...S>
struct GenSeq : GenSeq<N-1, N-1, S...> {};

template<std::size_t ...S>
struct GenSeq<0, S...> {
  typedef Seq<S...> type;
};

/**
 * @brief Final step of CreateBoolInstantiatedInstance. Now all bool_values are
 *        ready. Instantiate the template and create (i.e. new) an instance.
 */
template <template <bool ...> class T, class ReturnT,
          bool ...bool_values, std::size_t ...i,
          typename Tuple>
inline ReturnT* CreateBoolInstantiatedInstanceInner(Tuple&& args, Seq<i...>&& indices) {
  return new T<bool_values...>(std::get<i>(std::forward<Tuple>(args))...);
}

/**
 * @brief Edge case of the recursive CreateBoolInstantiatedInstance function
 *        when all bool variables have been branched and replaced with compile-time
 *        bool constants.
 */
template <template <bool ...> class T, class ReturnT,
          bool ...bool_values,
          typename Tuple>
inline ReturnT* CreateBoolInstantiatedInstance(Tuple&& args) {
  // Note that the constructor arguments have been forwarded as a tuple (args).
  // Here we generate a compile-time index sequence (i.e. typename GenSeq<n_args>::type())
  // for the tuple, so that the tuple can be unpacked as a sequence of constructor
  // parameters in CreateBoolInstantiatedInstanceInner.
  constexpr std::size_t n_args = std::tuple_size<Tuple>::value;
  return CreateBoolInstantiatedInstanceInner<T, ReturnT, bool_values...>(
      std::forward<Tuple>(args), typename GenSeq<n_args>::type());
}

/**
 * @brief A helper function for creating bool branched templates.
 *
 * The scenario for using this helper function is that, suppose we have a class
 * where all template parameters are bools:
 * --
 * template <bool c1, bool c2, bool c3>
 * class SomeClass : BaseClass {
 *   // This simple function will be invoked in computationally-intensive loops.
 *   inline SomeType someSimpleFunction(...) {
 *     if (c1) {
 *       doSomeThing1();
 *     }
 *     if (c2) {
 *       doSomeThing2();
 *     }
 *     if (c3) {
 *       doSomeThing3();
 *     }
 *   }
 * };
 * --
 * Typically, this bool-paramterized template is for performance consideration.
 * That is, we would like to make a copy of code for each configuration of bool
 * values, so that there will be no branchings in someSimpleFunction().
 *
 * The problem is that, to conditionally instantiate the template, given bool
 * variables c1, c2, c3, we have to do something like this:
 * --
 * if (c1) {
 *   if (c2) {
 *     if (c3) {
 *       return new SomeClass<true, true, true>(some_args...);
 *     } else {
 *       return new SomeClass<true, true, false>(some_args...);
 *     }
 *   } else {
 *     if (c3) {
 *       return new SomeClass<true, false, true>(some_args...);
 *     } else {
 *       return new SomeClass<true, false, false>(some_args...);
 *     }
 * } else {
 *   ...
 * }
 * --
 * Then there will be power(2,N) branches if the template has N bool parameters,
 * making it tedious to do the instantiating.
 *
 * Now, this helper function can achieve the branched instantiation in one
 * statement as:
 * --
 * return CreateBoolInstantiatedInstance<SomeClass,BaseClass>(
 *     std::forward_as_tuple(some_args...), c1, c2, c3);
 * --
 */
template <template <bool ...> class T, class ReturnT,
          bool ...bool_values, typename ...Bools,
          typename Tuple>
inline ReturnT* CreateBoolInstantiatedInstance(Tuple&& args, bool tparam, Bools ...rest_tparams) {
  if (tparam) {
    return CreateBoolInstantiatedInstance<T, ReturnT, bool_values..., true>(
        std::forward<Tuple>(args), rest_tparams...);
  } else {
    return CreateBoolInstantiatedInstance<T, ReturnT, bool_values..., false>(
        std::forward<Tuple>(args), rest_tparams...);
  }
}

/** @} */

}  // namespace quickstep

#endif  // QUICKSTEP_UTILITY_TEMPLATE_UTIL_HPP_
<commit_msg>Update TemplateUtil.hpp<commit_after>/**
 *   Copyright 2016, Quickstep Research Group, Computer Sciences Department,
 *   University of Wisconsin—Madison.
 *
 *   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 QUICKSTEP_UTILITY_TEMPLATE_UTIL_HPP_
#define QUICKSTEP_UTILITY_TEMPLATE_UTIL_HPP_

#include <tuple>
#include <utility>

namespace quickstep {

/** \addtogroup Utility
 *  @{
 */

/**
 * @brief Represents a compile-time sequence of integers.
 *
 * Seq is defined here for C++11 compatibility. For C++14 and above,
 * std::integer_sequence can be used to achieve the same functionality.
 */
template<std::size_t ...>
struct Seq {};

/**
 * @brief The helper class for creating Seq. GenSeq<N>::type is equivalent to
 *        Seq<1,2,...,N>.
 *
 * GenSeq is defined here for C++11 compatibility. For C++14 and above,
 * std::make_integer_sequence can be used to achieve the same functionality.
 */
template<std::size_t N, std::size_t ...S>
struct GenSeq : GenSeq<N-1, N-1, S...> {};

template<std::size_t ...S>
struct GenSeq<0, S...> {
  typedef Seq<S...> type;
};

/**
 * @brief Final step of CreateBoolInstantiatedInstance. Now all bool_values are
 *        ready. Instantiate the template and create (i.e. new) an instance.
 */
template <template <bool ...> class T, class ReturnT,
          bool ...bool_values, std::size_t ...i,
          typename Tuple>
inline ReturnT* CreateBoolInstantiatedInstanceInner(Tuple&& args, Seq<i...>&& indices) {
  return new T<bool_values...>(std::get<i>(std::forward<Tuple>(args))...);
}

/**
 * @brief Edge case of the recursive CreateBoolInstantiatedInstance function
 *        when all bool variables have been branched and replaced with compile-time
 *        bool constants.
 */
template <template <bool ...> class T, class ReturnT,
          bool ...bool_values,
          typename Tuple>
inline ReturnT* CreateBoolInstantiatedInstance(Tuple&& args) {
  // Note that the constructor arguments have been forwarded as a tuple (args).
  // Here we generate a compile-time index sequence (i.e. typename GenSeq<n_args>::type())
  // for the tuple, so that the tuple can be unpacked as a sequence of constructor
  // parameters in CreateBoolInstantiatedInstanceInner.
  constexpr std::size_t n_args = std::tuple_size<Tuple>::value;
  return CreateBoolInstantiatedInstanceInner<T, ReturnT, bool_values...>(
      std::forward<Tuple>(args), typename GenSeq<n_args>::type());
}

/**
 * @brief A helper function for creating bool branched templates.
 *
 * The scenario for using this helper function is that, suppose we have a class
 * where all template parameters are bools:
 * --
 * template <bool c1, bool c2, bool c3>
 * class SomeClass : BaseClass {
 *   // This simple function will be invoked in computationally-intensive loops.
 *   inline SomeType someSimpleFunction(...) {
 *     if (c1) {
 *       doSomeThing1();
 *     }
 *     if (c2) {
 *       doSomeThing2();
 *     }
 *     if (c3) {
 *       doSomeThing3();
 *     }
 *   }
 * };
 * --
 * Typically, this bool-paramterized template is for performance consideration.
 * That is, we would like to make a copy of code for each configuration of bool
 * values, so that there will be no branchings in someSimpleFunction().
 *
 * The problem is that, to conditionally instantiate the template, given bool
 * variables c1, c2, c3, we have to do something like this:
 * --
 * if (c1) {
 *   if (c2) {
 *     if (c3) {
 *       return new SomeClass<true, true, true>(some_args...);
 *     } else {
 *       return new SomeClass<true, true, false>(some_args...);
 *     }
 *   } else {
 *     if (c3) {
 *       return new SomeClass<true, false, true>(some_args...);
 *     } else {
 *       return new SomeClass<true, false, false>(some_args...);
 *     }
 * } else {
 *   ...
 * }
 * --
 * Then there will be power(2,N) branches if the template has N bool parameters,
 * making it tedious to do the instantiating.
 *
 * Now, this helper function can achieve the branched instantiation in one
 * statement as:
 * --
 * return CreateBoolInstantiatedInstance<SomeClass,BaseClass>(
 *     std::forward_as_tuple(some_args...), c1, c2, c3);
 * --
 */
template <template <bool ...> class T, class ReturnT,
          bool ...bool_values, typename ...Bools,
          typename Tuple>
inline ReturnT* CreateBoolInstantiatedInstance(Tuple&& args, bool tparam, Bools ...rest_tparams) {
  if (tparam) {
    return CreateBoolInstantiatedInstance<T, ReturnT, bool_values..., true>(
        std::forward<Tuple>(args), rest_tparams...);
  } else {
    return CreateBoolInstantiatedInstance<T, ReturnT, bool_values..., false>(
        std::forward<Tuple>(args), rest_tparams...);
  }
}

/** @} */

}  // namespace quickstep

#endif  // QUICKSTEP_UTILITY_TEMPLATE_UTIL_HPP_
<|endoftext|>


<commit_before>#include "editingcamera.h"
#include <Urho3D/Graphics/Renderer.h>
#include <Urho3D/Graphics/Graphics.h>
#include <Urho3D/UI/UI.h>
#include <Urho3D/Input/Input.h>
#include <Urho3D/Graphics/Drawable.h>
#include <Urho3D/Graphics/OctreeQuery.h>
#include <Urho3D/Graphics/Octree.h>
#include <Urho3D/IO/Log.h>

#include "../terraincontext.h"

EditingCamera::EditingCamera(Context *context) : LogicComponent(context),
	pitch_(30), yaw_(180),
	follow_(10), minfollow_(0), maxfollow_(20), curfollow_(10), followvel_(0), zoomspeed_(1000.0f),
	offset_(2), clipdistance_(600), scrollspeed_(64.0f),
	allowpitch_(true), allowspin_(true), allowzoom_(true),
	clipsolid_(false), tracksurface_(true),
	anglenode_(nullptr), cameranode_(nullptr),
	terrainContext_(nullptr),
	camera_(nullptr)
{
	SetUpdateEventMask(USE_UPDATE);
}

void EditingCamera::DelayedStart()
{
	anglenode_ = node_->CreateChild("AngleNode");
	cameranode_ = anglenode_->CreateChild("CameraNode");
	camera_ = cameranode_->CreateComponent<Camera>();
	viewport_ = new Viewport(context_, node_->GetScene(), camera_);
	GetSubsystem<Renderer>()->SetViewport(0, viewport_);

	node_->SetRotation(Quaternion(yaw_, Vector3(0,1,0)));
	cameranode_->SetPosition(Vector3(0,0,-follow_));
	anglenode_->SetRotation(Quaternion(pitch_, Vector3(1,0,0)));
	node_->SetPosition(Vector3(0,0,0));
}

Ray EditingCamera::GetScreenRay(const IntVector2 &mousepos)
{
	auto graphics=GetSubsystem<Graphics>();

	if(!camera_) return Ray();
	return camera_->GetScreenRay((float)mousepos.x_ / (float)graphics->GetWidth(), (float)mousepos.y_/(float)graphics->GetHeight());
}

Ray EditingCamera::GetMouseRay()
{
	if(!camera_) return Ray();
	auto input=GetSubsystem<Input>();
	auto ui=GetSubsystem<UI>();

	if(input->IsMouseVisible()) return GetScreenRay(input->GetMousePosition());
	else return GetScreenRay(ui->GetCursor()->GetPosition());
}

bool EditingCamera::GetScreenGround(Vector3 &out, const IntVector2 &mousepos)
{
	if(!camera_) return false;
	Ray ray=GetScreenRay(mousepos);
	float hitdist=ray.HitDistance(Plane(Vector3(0,1,0), Vector3(0,0,0)));
	if(hitdist==M_INFINITY) return false;
	out=ray.origin_ + ray.direction_*hitdist;
	return true;
}

bool EditingCamera::GetMouseGround(Vector3 &out)
{
	if(!camera_) return false;
	auto input=GetSubsystem<Input>();
	auto ui=GetSubsystem<UI>();

	if(input->IsMouseVisible()) return GetScreenGround(out, input->GetMousePosition());
	else return GetScreenGround(out, ui->GetCursorPosition());
}

bool EditingCamera::PickGround(Vector3 &ground, const IntVector2 &mousepos, float maxdistance)
{
	auto ui=GetSubsystem<UI>();
	auto input=GetSubsystem<Input>();

	Scene *scene=node_->GetScene();
	Octree *octree=node_->GetScene()->GetComponent<Octree>();

	float hitpos=0;
	Drawable *hitdrawable=nullptr;
	//if(ui->GetCursor() && ui->GetCursor()->IsVisible()==false && input->IsMouseVisible()==false) return false;

	Ray ray=GetScreenRay(mousepos);
	static ea::vector<RayQueryResult> result;
	result.clear();
	RayOctreeQuery query(result, ray, RAY_TRIANGLE, maxdistance, DRAWABLE_GEOMETRY);
	octree->Raycast(query);
	if(result.size()==0) return false;

	for(unsigned int i=0; i<result.size(); ++i)
	{
		if(result[i].distance_>=0)
		{
			ground=ray.origin_+ray.direction_*result[i].distance_;
			return true;
		}
	}

	return false;
}

void EditingCamera::Update(float dt)
{
	if(!camera_) return;
	auto ui=GetSubsystem<UI>();
	auto input=GetSubsystem<Input>();
	auto graphics=GetSubsystem<Graphics>();

	IntVector2 mousepos;
	if(ui->GetCursor()) mousepos=ui->GetCursor()->GetPosition();
	else mousepos=input->GetMousePosition();

	if(allowzoom_ && !ui->GetElementAt(mousepos))
	{
		float wheel=input->GetMouseMoveWheel();
		follow_=follow_-wheel*dt*zoomspeed_;
		follow_=std::max(minfollow_, std::min(maxfollow_, follow_));
	}

	if(input->GetMouseButtonDown(MOUSEB_MIDDLE) && (allowspin_ || allowpitch_))
	{
		if(ui->GetCursor()) ui->GetCursor()->SetVisible(false);
		else input->SetMouseVisible(false);

		if(allowpitch_)
		{
			float mmovey=(float)input->GetMouseMoveY() / (float)graphics->GetHeight();
			pitch_+=mmovey*600.0f;
			pitch_=std::max(-89.0f, std::min(89.0f, pitch_));
		}
		if(allowspin_)
		{
			float mmovex=(float)input->GetMouseMoveX() / (float)graphics->GetWidth();
			yaw_+=mmovex*800.0f;
			while(yaw_<0.0f) yaw_+=360.0f;
			while(yaw_>=360.0f) yaw_-=360.0f;
		}
	}
	else
	{
		if(ui->GetCursor()) ui->GetCursor()->SetVisible(true);
		else input->SetMouseVisible(true);
	}

	Vector3 trans(0,0,0);

	if(input->GetMouseButtonPress(MOUSEB_RIGHT))
	{
		lastmouse_=mousepos;
	}

	if(input->GetMouseButtonDown(MOUSEB_RIGHT))
	{
		trans=Vector3(0,0,0);
		Vector3 oldground;
		bool s=GetScreenGround(oldground, lastmouse_);
		if(s)
		{
			Vector3 newground;
			bool t=GetScreenGround(newground, mousepos);
			if(t)
			{
				trans=oldground-newground;
				lastmouse_=mousepos;
			}
		}
	}
	else
	{
		Quaternion quat(yaw_,Vector3(0,1,0));
		if(input->GetKeyDown(KEY_W)) trans.z_+=1.0f;
		if(input->GetKeyDown(KEY_S)) trans.z_-=1.0f;
		if(input->GetKeyDown(KEY_A)) trans.x_-=1.0f;
		if(input->GetKeyDown(KEY_D)) trans.x_+=1.0f;

		trans=quat*trans*dt*scrollspeed_;
	}

	Vector3 mypos=node_->GetPosition();
	Vector3 np=mypos+trans;
	np.x_=std::max(minbounds_.x_, std::min(maxbounds_.x_, np.x_));
	np.z_=std::max(minbounds_.y_, std::min(maxbounds_.y_, np.z_));

	if(tracksurface_ && terrainContext_)
	{
		float ht=terrainContext_->GetHeight(np);
		np.y_=ht+offset_;
	}

	node_->SetPosition(np);
	SpringFollow(dt);

	if(clipsolid_)
	{
		Ray ray=camera_->GetScreenRay(0.5f, 0.5f);
		Ray revray=Ray(node_->GetPosition(), ray.direction_*Vector3(-1,-1,-1));
		curfollow_=CameraClipPick(revray, curfollow_);
	}

	node_->SetRotation(Quaternion(yaw_, Vector3(0,1,0)));
	cameranode_->SetPosition(Vector3(0,0,-curfollow_));
	anglenode_->SetRotation(Quaternion(pitch_, Vector3(1,0,0)));
	camera_->SetFarClip(clipdistance_);
}

float EditingCamera::CameraClipPick(const Ray &ray, float followdist)
{
	Scene *scene=node_->GetScene();
	Octree *octree=scene->GetComponent<Octree>();

	static ea::vector<RayQueryResult> result;
	result.clear();
	RayOctreeQuery query(result, ray, RAY_TRIANGLE, followdist, DRAWABLE_GEOMETRY);
	octree->Raycast(query);
	if(result.size()==0) return followdist;

	for(unsigned int i=0; i<result.size(); ++i)
	{
		Node *n=TopLevelNodeFromDrawable(result[i].drawable_, scene);
		return std::min(result[i].distance_-0.0f, followdist);
	}

	return followdist;
}

void EditingCamera::SpringFollow(float dt)
{
	float df=follow_-curfollow_;
	float af=9.0f*df-6.0f*followvel_;
	followvel_+=dt*af;
	curfollow_+=dt*followvel_;
}

void EditingCamera::SetGroundHeight(float e)
{
	Vector3 pos=node_->GetPosition();
	pos.y_=e+offset_;
	node_->SetPosition(pos);
}

Node *EditingCamera::TopLevelNodeFromDrawable(Drawable *d, Scene *s)
{
	Node *n=d->GetNode();
	if(!n) return nullptr;
	while(n->GetParent() != s)
	{
		if(n->GetParent()==nullptr) return n;
		n=n->GetParent();
	}
	return n;
}
<commit_msg>Raise camera offset from ground a bit.<commit_after>#include "editingcamera.h"
#include <Urho3D/Graphics/Renderer.h>
#include <Urho3D/Graphics/Graphics.h>
#include <Urho3D/UI/UI.h>
#include <Urho3D/Input/Input.h>
#include <Urho3D/Graphics/Drawable.h>
#include <Urho3D/Graphics/OctreeQuery.h>
#include <Urho3D/Graphics/Octree.h>
#include <Urho3D/IO/Log.h>

#include "../terraincontext.h"

EditingCamera::EditingCamera(Context *context) : LogicComponent(context),
	pitch_(30), yaw_(180),
	follow_(10), minfollow_(0), maxfollow_(20), curfollow_(10), followvel_(0), zoomspeed_(1000.0f),
	offset_(6.0f), clipdistance_(600), scrollspeed_(64.0f),
	allowpitch_(true), allowspin_(true), allowzoom_(true),
	clipsolid_(false), tracksurface_(true),
	anglenode_(nullptr), cameranode_(nullptr),
	terrainContext_(nullptr),
	camera_(nullptr)
{
	SetUpdateEventMask(USE_UPDATE);
}

void EditingCamera::DelayedStart()
{
	anglenode_ = node_->CreateChild("AngleNode");
	cameranode_ = anglenode_->CreateChild("CameraNode");
	camera_ = cameranode_->CreateComponent<Camera>();
	viewport_ = new Viewport(context_, node_->GetScene(), camera_);
	GetSubsystem<Renderer>()->SetViewport(0, viewport_);

	node_->SetRotation(Quaternion(yaw_, Vector3(0,1,0)));
	cameranode_->SetPosition(Vector3(0,0,-follow_));
	anglenode_->SetRotation(Quaternion(pitch_, Vector3(1,0,0)));
	node_->SetPosition(Vector3(0,0,0));
}

Ray EditingCamera::GetScreenRay(const IntVector2 &mousepos)
{
	auto graphics=GetSubsystem<Graphics>();

	if(!camera_) return Ray();
	return camera_->GetScreenRay((float)mousepos.x_ / (float)graphics->GetWidth(), (float)mousepos.y_/(float)graphics->GetHeight());
}

Ray EditingCamera::GetMouseRay()
{
	if(!camera_) return Ray();
	auto input=GetSubsystem<Input>();
	auto ui=GetSubsystem<UI>();

	if(input->IsMouseVisible()) return GetScreenRay(input->GetMousePosition());
	else return GetScreenRay(ui->GetCursor()->GetPosition());
}

bool EditingCamera::GetScreenGround(Vector3 &out, const IntVector2 &mousepos)
{
	if(!camera_) return false;
	Ray ray=GetScreenRay(mousepos);
	float hitdist=ray.HitDistance(Plane(Vector3(0,1,0), Vector3(0,0,0)));
	if(hitdist==M_INFINITY) return false;
	out=ray.origin_ + ray.direction_*hitdist;
	return true;
}

bool EditingCamera::GetMouseGround(Vector3 &out)
{
	if(!camera_) return false;
	auto input=GetSubsystem<Input>();
	auto ui=GetSubsystem<UI>();

	if(input->IsMouseVisible()) return GetScreenGround(out, input->GetMousePosition());
	else return GetScreenGround(out, ui->GetCursorPosition());
}

bool EditingCamera::PickGround(Vector3 &ground, const IntVector2 &mousepos, float maxdistance)
{
	auto ui=GetSubsystem<UI>();
	auto input=GetSubsystem<Input>();

	Scene *scene=node_->GetScene();
	Octree *octree=node_->GetScene()->GetComponent<Octree>();

	float hitpos=0;
	Drawable *hitdrawable=nullptr;
	//if(ui->GetCursor() && ui->GetCursor()->IsVisible()==false && input->IsMouseVisible()==false) return false;

	Ray ray=GetScreenRay(mousepos);
	static ea::vector<RayQueryResult> result;
	result.clear();
	RayOctreeQuery query(result, ray, RAY_TRIANGLE, maxdistance, DRAWABLE_GEOMETRY);
	octree->Raycast(query);
	if(result.size()==0) return false;

	for(unsigned int i=0; i<result.size(); ++i)
	{
		if(result[i].distance_>=0)
		{
			ground=ray.origin_+ray.direction_*result[i].distance_;
			return true;
		}
	}

	return false;
}

void EditingCamera::Update(float dt)
{
	if(!camera_) return;
	auto ui=GetSubsystem<UI>();
	auto input=GetSubsystem<Input>();
	auto graphics=GetSubsystem<Graphics>();

	IntVector2 mousepos;
	if(ui->GetCursor()) mousepos=ui->GetCursor()->GetPosition();
	else mousepos=input->GetMousePosition();

	if(allowzoom_ && !ui->GetElementAt(mousepos))
	{
		float wheel=input->GetMouseMoveWheel();
		follow_=follow_-wheel*dt*zoomspeed_;
		follow_=std::max(minfollow_, std::min(maxfollow_, follow_));
	}

	if(input->GetMouseButtonDown(MOUSEB_MIDDLE) && (allowspin_ || allowpitch_))
	{
		if(ui->GetCursor()) ui->GetCursor()->SetVisible(false);
		else input->SetMouseVisible(false);

		if(allowpitch_)
		{
			float mmovey=(float)input->GetMouseMoveY() / (float)graphics->GetHeight();
			pitch_+=mmovey*600.0f;
			pitch_=std::max(-89.0f, std::min(89.0f, pitch_));
		}
		if(allowspin_)
		{
			float mmovex=(float)input->GetMouseMoveX() / (float)graphics->GetWidth();
			yaw_+=mmovex*800.0f;
			while(yaw_<0.0f) yaw_+=360.0f;
			while(yaw_>=360.0f) yaw_-=360.0f;
		}
	}
	else
	{
		if(ui->GetCursor()) ui->GetCursor()->SetVisible(true);
		else input->SetMouseVisible(true);
	}

	Vector3 trans(0,0,0);

	if(input->GetMouseButtonPress(MOUSEB_RIGHT))
	{
		lastmouse_=mousepos;
	}

	if(input->GetMouseButtonDown(MOUSEB_RIGHT))
	{
		trans=Vector3(0,0,0);
		Vector3 oldground;
		bool s=GetScreenGround(oldground, lastmouse_);
		if(s)
		{
			Vector3 newground;
			bool t=GetScreenGround(newground, mousepos);
			if(t)
			{
				trans=oldground-newground;
				lastmouse_=mousepos;
			}
		}
	}
	else
	{
		Quaternion quat(yaw_,Vector3(0,1,0));
		if(input->GetKeyDown(KEY_W)) trans.z_+=1.0f;
		if(input->GetKeyDown(KEY_S)) trans.z_-=1.0f;
		if(input->GetKeyDown(KEY_A)) trans.x_-=1.0f;
		if(input->GetKeyDown(KEY_D)) trans.x_+=1.0f;

		trans=quat*trans*dt*scrollspeed_;
	}

	Vector3 mypos=node_->GetPosition();
	Vector3 np=mypos+trans;
	np.x_=std::max(minbounds_.x_, std::min(maxbounds_.x_, np.x_));
	np.z_=std::max(minbounds_.y_, std::min(maxbounds_.y_, np.z_));

	if(tracksurface_ && terrainContext_)
	{
		float ht=terrainContext_->GetHeight(np);
		np.y_=ht+offset_;
	}

	node_->SetPosition(np);
	SpringFollow(dt);

	if(clipsolid_)
	{
		Ray ray=camera_->GetScreenRay(0.5f, 0.5f);
		Ray revray=Ray(node_->GetPosition(), ray.direction_*Vector3(-1,-1,-1));
		curfollow_=CameraClipPick(revray, curfollow_);
	}

	node_->SetRotation(Quaternion(yaw_, Vector3(0,1,0)));
	cameranode_->SetPosition(Vector3(0,0,-curfollow_));
	anglenode_->SetRotation(Quaternion(pitch_, Vector3(1,0,0)));
	camera_->SetFarClip(clipdistance_);
}

float EditingCamera::CameraClipPick(const Ray &ray, float followdist)
{
	Scene *scene=node_->GetScene();
	Octree *octree=scene->GetComponent<Octree>();

	static ea::vector<RayQueryResult> result;
	result.clear();
	RayOctreeQuery query(result, ray, RAY_TRIANGLE, followdist, DRAWABLE_GEOMETRY);
	octree->Raycast(query);
	if(result.size()==0) return followdist;

	for(unsigned int i=0; i<result.size(); ++i)
	{
		Node *n=TopLevelNodeFromDrawable(result[i].drawable_, scene);
		return std::min(result[i].distance_-0.0f, followdist);
	}

	return followdist;
}

void EditingCamera::SpringFollow(float dt)
{
	float df=follow_-curfollow_;
	float af=9.0f*df-6.0f*followvel_;
	followvel_+=dt*af;
	curfollow_+=dt*followvel_;
}

void EditingCamera::SetGroundHeight(float e)
{
	Vector3 pos=node_->GetPosition();
	pos.y_=e+offset_;
	node_->SetPosition(pos);
}

Node *EditingCamera::TopLevelNodeFromDrawable(Drawable *d, Scene *s)
{
	Node *n=d->GetNode();
	if(!n) return nullptr;
	while(n->GetParent() != s)
	{
		if(n->GetParent()==nullptr) return n;
		n=n->GetParent();
	}
	return n;
}
<|endoftext|>