<commit_before>/*
 * Copyright (C) 2004, 2006-2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

/// \brief Sample demonstration of URBI capabilities.
/*
 * This is a port to URBI of the Sony OPEN-R balltrackinghead example.
 * The algorithms used are as close as possible to the original version.
 */
#include <libport/cmath>

#include <vector>

#include <urbi/uclient.hh>
#include <urbi/uconversion.hh>

#ifndef LIBURBI_OPENR
# include "monitor.h"
Monitor* mon = NULL;
#endif

//inline double fabs(double a) {return  a>0?a:(a*-1);}
inline double fsgn (double a)
{
  return a>0?1:-1;
}

struct PositionData
{
  int frame;
  double value;
  bool operator == (int f) {return f==frame;}
};

class BallTrackingHead
{
 public:
  BallTrackingHead(const char * robotName);

  //callback functions
  urbi::UCallbackAction getHead(bool pan, const urbi::UMessage &msg);
  urbi::UCallbackAction getImage(const urbi::UMessage &msg);

 private:
  /// Client for image reception.
  urbi::UClient robotI;
  /// Client for command sending.
  urbi::UClient robotC;
  /// Client for command reception.
  /// urbi::UClient robotG;

  //joint value for the last few frames
  std::vector<PositionData> current_x, current_y;
  // base of current_x, current_y (currentx[i] = frame_base - i)
  int baseframeX, baseframeY;
  unsigned char  image[500000];  //uncompressed image
  double target_x, target_y;  //command to center the ball
  double expect_x, expect_y;  //values in last command, that should be reached

  void doSendCommand(double current_x, double current_y);

  static const int VSIZE = 10; //size of the joint position list.
  static const int ball_treshold = 50;
  static const double factor_x; //x field of view
  static const double factor_y;  //y field of view
  static const double maxcommand_x;
  static const double maxcommand_y;
};

const double BallTrackingHead::factor_x = 0.9 * 56.9;
const double BallTrackingHead::factor_y = 0.9 * 45.2;
const double BallTrackingHead::maxcommand_x = 150.0;
const double BallTrackingHead::maxcommand_y = 150.0;

int format=1;

void BallTrackingHead::doSendCommand(double current_x, double current_y)
{
  static int sframe=0;
  static unsigned int stime=0;
  double command_x=-1, command_y=-1;
  robotC.send("headPan.val = headPan.val + %lf"
              " & headTilt.val = headTilt.val + %lf,",
              target_x, target_y);
  if (! (sframe % 1000))
    {
      if (stime)
	robotC.printf("!! csps %f\n",
		       1000000.0/(float)(robotC.getCurrentTime()-stime));
      stime=robotC.getCurrentTime();
    }
  ++sframe;
  return;
  if (fabs(current_x-expect_x)< 100)
    {
      if (fabs(target_x - current_x) > maxcommand_x)
	command_x = current_x + maxcommand_x*fsgn(target_x - current_x);
      else
	command_x = target_x;
      if (fabs(command_x-current_x) > 0.0)
      {
	robotC.send("headPan.val = %lf,",command_x);
	expect_x = command_x;
      }
      else
	command_x = -1;
    }
  if (fabs(current_y-expect_y)< 100)
    {
      if (fabs(target_y - current_y) > maxcommand_y)
	command_y = current_y + maxcommand_y*fsgn(target_y - current_y);
      else
	command_y = target_y;
      if (fabs(command_y-current_y) > 0.0)
      {
	robotC.send("headTilt.val = %lf,",command_y);
	expect_y = command_y;
      }
      else
	command_y = -1;
    }

  if (command_x!=-1 || command_y!=-1)
    {
      if (! (sframe % 1000))
	{
	  if (stime)
	    robotC.printf("!! csps %f\n",
			  1000000.0/(float)(robotC.getCurrentTime()-stime));
	  stime=robotC.getCurrentTime();
	}
      ++sframe;
    }
}

urbi::UCallbackAction
BallTrackingHead::getHead(bool pan, const urbi::UMessage &msg)
{
  if (msg.type != urbi::MESSAGE_DATA
      || msg.value->type != urbi::DATA_DOUBLE)
    return urbi::URBI_CONTINUE;

  PositionData pd;
  pd.frame = msg.timestamp/32;
  pd.value = msg.value->val;
  if (pan)
    {
      current_x.insert(current_x.begin(), pd);
      current_x.resize(VSIZE);
    }
  else
    {
      current_y.insert(current_y.begin(), pd);
      current_y.resize(VSIZE);
    }

  return urbi::URBI_CONTINUE;
}

urbi::UCallbackAction
BallTrackingHead::getImage(const urbi::UMessage &msg)
{
  static int framenum=0;
  static float interframe=0;
  static int frametime=0;

  if (msg.type != urbi::MESSAGE_DATA
      || msg.value->type != urbi::DATA_BINARY
      || msg.value->binary->type != urbi::BINARY_IMAGE)
    return urbi::URBI_CONTINUE;

  urbi::UImage& img = msg.value->binary->image;
  double cx=0, cy=0;
  /*
    std::vector<PositionData>::iterator it =
      find(current_x.begin(), current_x.end(), msg.timestamp/32);
    if (it==current_x.end())
    {
    return URBI_CONTINUE;
    }
    double cx = it->value;
    it = find(current_y.begin(), current_y.end(), msg.timestamp/32);
    if (it==current_y.end())
    {
    return URBI_CONTINUE;
    }
    double cy = it->value;
  */
  if ((framenum % 50)==0)
    {
      if (!frametime)
	frametime=robotC.getCurrentTime();
      else
	{
	  int dt=robotC.getCurrentTime()-frametime;
	  frametime=robotC.getCurrentTime();
	  if (interframe == 0)
	    interframe=((float)dt)/50.0;
	  else
	    interframe=interframe*0.5 +  0.5*((float)dt)/50.0;
	  robotC.printf("## %f fps\n",1000.0/interframe);
	}
    }
  ++framenum;
  size_t imgsize = 500000;
  if (img.imageFormat == urbi::IMAGE_JPEG)
  {
    size_t w, h;
    urbi::convertJPEGtoYCrCb((const urbi::byte *) img.data,
			     img.size, &image, imgsize, w, h);
  }
  else
    memcpy(image, img.data, img.width * img.height * 3);

  //get ball centroid
  int xsum=0, ysum=0;
  int nummatch=0;
  int w = img.width;
  int h = img.height;
  for (unsigned i=0;i<img.width; ++i)
    for (unsigned j=0;j<img.height; ++j)
      {
	unsigned char cb = image[(i+j*w)*3+1];
	unsigned char cr = image[(i+j*w)*3+2];;
	if (150 <= cr && cr<=230
	    && 120 <= cb && cb<=190)
	  {
	    ++nummatch;
	    xsum+=i;
	    ysum+=j;
	  }
      }
  if (nummatch >= ball_treshold)
    {
      double bx= (double)xsum / (double)nummatch;
      double by= (double)ysum / (double)nummatch;
      double dbx = bx - (double)w / 2.0;
      double dby = by - (double)h / 2.0;

      double dx = (-1.0) * (factor_x / (double)w) * dbx;
      double dy = (-1.0) * (factor_y / (double)h) * dby;

#ifndef LIBURBI_OPENR
      for (int j=0;j<h; ++j)
	image[(((int)bx)+w*j)*3]=255;
      for (int j=0;j<w; ++j)
	image[(((int)by)*w+j)*3]=255;
#endif

      target_x = cx+dx;
      target_y = cy+dy;
      if (target_x > 90.0)
	target_x = 90.0;
      if (target_x < -90.0)
	target_x = -90.0;
      if (target_y > 60.0)
	target_y = 60.0;
      if (target_y < -30.0)
	target_y = -30.0;
      doSendCommand(cx, cy);

    }

#ifndef LIBURBI_OPENR
  urbi::convertYCrCbtoRGB(image, w*h*3, image);
  if (!mon)
    mon = new Monitor(w, h, "Image");
  mon->setImage((bits8*)image, img.width*img.height*3);
#endif

  return urbi::URBI_CONTINUE;
}

BallTrackingHead::BallTrackingHead(const char * robotname)
  : robotI (robotname),
    robotC (robotname)
    //, robotG (robotname)
{
  robotI.start();
  if (robotI.error())
    urbi::exit(1);
  robotC.start();
  if (robotC.error())
    urbi::exit(1);

  robotC.send("motoron;");
  robotC.send("camera.format = 1;");
#ifdef LIBURBI_OPENR
  robotC.send("camera.resolution = 1;");
#else
  robotC.send("camera.resolution = 0;");
#endif
  robotC.send("camera.jpegfactor = 75;");
  robotC.setCallback(*this, &BallTrackingHead::getImage,"cam");

  robotC.send("loop cam << camera.val, ");
  //robotG.send("loop {pan << headPan.val& tilt << headTilt.val},");
}

int
main(int argc, char * argv[])
{
  const char* host = urbi::UClient::default_host();
  if (argc != 2)
    printf("usage: %s robotname\n", argv[0]);
  else
    host = argv[1];
  BallTrackingHead bt(host);
  // Help GCC understand we really want this variable to be "used".
  (void) bt;
  urbi::execute();
}
<commit_msg>Update call to convertJPEG*.<commit_after>/*
 * Copyright (C) 2004, 2006-2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

/// \brief Sample demonstration of URBI capabilities.
/*
 * This is a port to URBI of the Sony OPEN-R balltrackinghead example.
 * The algorithms used are as close as possible to the original version.
 */
#include <libport/cmath>

#include <vector>

#include <urbi/uclient.hh>
#include <urbi/uconversion.hh>

#ifndef LIBURBI_OPENR
# include "monitor.h"
Monitor* mon = NULL;
#endif

//inline double fabs(double a) {return  a>0?a:(a*-1);}
inline double fsgn (double a)
{
  return a>0?1:-1;
}

struct PositionData
{
  int frame;
  double value;
  bool operator == (int f) {return f==frame;}
};

class BallTrackingHead
{
 public:
  BallTrackingHead(const char * robotName);

  //callback functions
  urbi::UCallbackAction getHead(bool pan, const urbi::UMessage &msg);
  urbi::UCallbackAction getImage(const urbi::UMessage &msg);

 private:
  /// Client for image reception.
  urbi::UClient robotI;
  /// Client for command sending.
  urbi::UClient robotC;
  /// Client for command reception.
  /// urbi::UClient robotG;

  //joint value for the last few frames
  std::vector<PositionData> current_x, current_y;
  // base of current_x, current_y (currentx[i] = frame_base - i)
  int baseframeX, baseframeY;
  unsigned char  image[500000];  //uncompressed image
  double target_x, target_y;  //command to center the ball
  double expect_x, expect_y;  //values in last command, that should be reached

  void doSendCommand(double current_x, double current_y);

  static const int VSIZE = 10; //size of the joint position list.
  static const int ball_treshold = 50;
  static const double factor_x; //x field of view
  static const double factor_y;  //y field of view
  static const double maxcommand_x;
  static const double maxcommand_y;
};

const double BallTrackingHead::factor_x = 0.9 * 56.9;
const double BallTrackingHead::factor_y = 0.9 * 45.2;
const double BallTrackingHead::maxcommand_x = 150.0;
const double BallTrackingHead::maxcommand_y = 150.0;

int format=1;

void BallTrackingHead::doSendCommand(double current_x, double current_y)
{
  static int sframe=0;
  static unsigned int stime=0;
  double command_x=-1, command_y=-1;
  robotC.send("headPan.val = headPan.val + %lf"
              " & headTilt.val = headTilt.val + %lf,",
              target_x, target_y);
  if (! (sframe % 1000))
    {
      if (stime)
	robotC.printf("!! csps %f\n",
		       1000000.0/(float)(robotC.getCurrentTime()-stime));
      stime=robotC.getCurrentTime();
    }
  ++sframe;
  return;
  if (fabs(current_x-expect_x)< 100)
    {
      if (fabs(target_x - current_x) > maxcommand_x)
	command_x = current_x + maxcommand_x*fsgn(target_x - current_x);
      else
	command_x = target_x;
      if (fabs(command_x-current_x) > 0.0)
      {
	robotC.send("headPan.val = %lf,",command_x);
	expect_x = command_x;
      }
      else
	command_x = -1;
    }
  if (fabs(current_y-expect_y)< 100)
    {
      if (fabs(target_y - current_y) > maxcommand_y)
	command_y = current_y + maxcommand_y*fsgn(target_y - current_y);
      else
	command_y = target_y;
      if (fabs(command_y-current_y) > 0.0)
      {
	robotC.send("headTilt.val = %lf,",command_y);
	expect_y = command_y;
      }
      else
	command_y = -1;
    }

  if (command_x!=-1 || command_y!=-1)
    {
      if (! (sframe % 1000))
	{
	  if (stime)
	    robotC.printf("!! csps %f\n",
			  1000000.0/(float)(robotC.getCurrentTime()-stime));
	  stime=robotC.getCurrentTime();
	}
      ++sframe;
    }
}

urbi::UCallbackAction
BallTrackingHead::getHead(bool pan, const urbi::UMessage &msg)
{
  if (msg.type != urbi::MESSAGE_DATA
      || msg.value->type != urbi::DATA_DOUBLE)
    return urbi::URBI_CONTINUE;

  PositionData pd;
  pd.frame = msg.timestamp/32;
  pd.value = msg.value->val;
  if (pan)
    {
      current_x.insert(current_x.begin(), pd);
      current_x.resize(VSIZE);
    }
  else
    {
      current_y.insert(current_y.begin(), pd);
      current_y.resize(VSIZE);
    }

  return urbi::URBI_CONTINUE;
}

urbi::UCallbackAction
BallTrackingHead::getImage(const urbi::UMessage &msg)
{
  static int framenum=0;
  static float interframe=0;
  static int frametime=0;

  if (msg.type != urbi::MESSAGE_DATA
      || msg.value->type != urbi::DATA_BINARY
      || msg.value->binary->type != urbi::BINARY_IMAGE)
    return urbi::URBI_CONTINUE;

  urbi::UImage& img = msg.value->binary->image;
  double cx=0, cy=0;
  /*
    std::vector<PositionData>::iterator it =
      find(current_x.begin(), current_x.end(), msg.timestamp/32);
    if (it==current_x.end())
    {
    return URBI_CONTINUE;
    }
    double cx = it->value;
    it = find(current_y.begin(), current_y.end(), msg.timestamp/32);
    if (it==current_y.end())
    {
    return URBI_CONTINUE;
    }
    double cy = it->value;
  */
  if ((framenum % 50)==0)
    {
      if (!frametime)
	frametime=robotC.getCurrentTime();
      else
	{
	  int dt=robotC.getCurrentTime()-frametime;
	  frametime=robotC.getCurrentTime();
	  if (interframe == 0)
	    interframe=((float)dt)/50.0;
	  else
	    interframe=interframe*0.5 +  0.5*((float)dt)/50.0;
	  robotC.printf("## %f fps\n",1000.0/interframe);
	}
    }
  ++framenum;
  size_t imgsize = 500000;
  if (img.imageFormat == urbi::IMAGE_JPEG)
  {
    size_t w, h;
    urbi::convertJPEGtoYCrCb((const urbi::byte *) img.data, img.size,
                             (urbi::byte **) &image, imgsize
                             , w, h);
  }
  else
    memcpy(image, img.data, img.width * img.height * 3);

  //get ball centroid
  int xsum=0, ysum=0;
  int nummatch=0;
  int w = img.width;
  int h = img.height;
  for (unsigned i=0;i<img.width; ++i)
    for (unsigned j=0;j<img.height; ++j)
      {
	unsigned char cb = image[(i+j*w)*3+1];
	unsigned char cr = image[(i+j*w)*3+2];;
	if (150 <= cr && cr<=230
	    && 120 <= cb && cb<=190)
	  {
	    ++nummatch;
	    xsum+=i;
	    ysum+=j;
	  }
      }
  if (nummatch >= ball_treshold)
    {
      double bx= (double)xsum / (double)nummatch;
      double by= (double)ysum / (double)nummatch;
      double dbx = bx - (double)w / 2.0;
      double dby = by - (double)h / 2.0;

      double dx = (-1.0) * (factor_x / (double)w) * dbx;
      double dy = (-1.0) * (factor_y / (double)h) * dby;

#ifndef LIBURBI_OPENR
      for (int j=0;j<h; ++j)
	image[(((int)bx)+w*j)*3]=255;
      for (int j=0;j<w; ++j)
	image[(((int)by)*w+j)*3]=255;
#endif

      target_x = cx+dx;
      target_y = cy+dy;
      if (target_x > 90.0)
	target_x = 90.0;
      if (target_x < -90.0)
	target_x = -90.0;
      if (target_y > 60.0)
	target_y = 60.0;
      if (target_y < -30.0)
	target_y = -30.0;
      doSendCommand(cx, cy);

    }

#ifndef LIBURBI_OPENR
  urbi::convertYCrCbtoRGB(image, w*h*3, image);
  if (!mon)
    mon = new Monitor(w, h, "Image");
  mon->setImage((bits8*)image, img.width*img.height*3);
#endif

  return urbi::URBI_CONTINUE;
}

BallTrackingHead::BallTrackingHead(const char * robotname)
  : robotI (robotname),
    robotC (robotname)
    //, robotG (robotname)
{
  robotI.start();
  if (robotI.error())
    urbi::exit(1);
  robotC.start();
  if (robotC.error())
    urbi::exit(1);

  robotC.send("motoron;");
  robotC.send("camera.format = 1;");
#ifdef LIBURBI_OPENR
  robotC.send("camera.resolution = 1;");
#else
  robotC.send("camera.resolution = 0;");
#endif
  robotC.send("camera.jpegfactor = 75;");
  robotC.setCallback(*this, &BallTrackingHead::getImage,"cam");

  robotC.send("loop cam << camera.val, ");
  //robotG.send("loop {pan << headPan.val& tilt << headTilt.val},");
}

int
main(int argc, char * argv[])
{
  const char* host = urbi::UClient::default_host();
  if (argc != 2)
    printf("usage: %s robotname\n", argv[0]);
  else
    host = argv[1];
  BallTrackingHead bt(host);
  // Help GCC understand we really want this variable to be "used".
  (void) bt;
  urbi::execute();
}
<|endoftext|>


<commit_before>/* Copyright (c) 2011-2013, AOYAMA Kazuharu
 * All rights reserved.
 *
 * This software may be used and distributed according to the terms of
 * the New BSD License, which is incorporated herein by reference.
 */

#include <QtCore>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <signal.h>
#include "processinfo.h"

namespace TreeFrog {

bool ProcessInfo::exists() const
{
    return allConcurrentPids().contains(processId);
}

QString ProcessInfo::processName() const
{
    QString ret;
    struct kinfo_proc kp;
    size_t bufSize = sizeof(struct kinfo_proc);
    int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, processId };

    if (sysctl(mib, 4, &kp, &bufSize, NULL, 0) == 0) {
        ret.append(kp.kp_proc.p_comm);
    }
    return ret;
}

QList<qint64> ProcessInfo::allConcurrentPids()
{
    QList<qint64> ret;
    struct kinfo_proc *kp;
    size_t bufSize = 0;
    int mib[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };

    if (sysctl(mib, 3, NULL, &bufSize, NULL, 0) == 0) {
        kp = (struct kinfo_proc *) new char[bufSize];
        if (sysctl(mib, 3, kp, &bufSize, NULL, 0) == 0) {
            for (size_t i = 0; i < (bufSize / sizeof(struct kinfo_proc)); ++i) {
                qint64 pid = kp[i].kp_proc.p_pid;
                if (pid > 0)
                    ret.prepend(pid);
            }
        }
        delete[] kp;
    }

    qSort(ret.begin(), ret.end());  // Sorts the items
    return ret;
}

void ProcessInfo::terminate()
{
    if (processId > 0) {
        ::kill(processId, SIGTERM);
    }
}

void ProcessInfo::kill()
{
    if (processId > 0) {
        ::kill(processId, SIGKILL);
    }
    processId = -1;
}

void ProcessInfo::restart()
{
    if (processId > 0) {
        ::kill(processId, SIGHUP);
    }
}

} // namespace TreeFrog
<commit_msg>added get-ppid function for OS X.<commit_after>/* Copyright (c) 2011-2013, AOYAMA Kazuharu
 * All rights reserved.
 *
 * This software may be used and distributed according to the terms of
 * the New BSD License, which is incorporated herein by reference.
 */

#include <QtCore>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <signal.h>
#include "processinfo.h"

namespace TreeFrog {

bool ProcessInfo::exists() const
{
    return allConcurrentPids().contains(processId);
}

qint64 ProcessInfo::ppid() const
{
    qint64 ppid = 0;
    struct kinfo_proc kp;
    size_t bufSize = sizeof(struct kinfo_proc);
    int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, processId };

    if (sysctl(mib, 4, &kp, &bufSize, NULL, 0) == 0) {
        ppid = kp.kp_eproc.e_ppid;
    }
    return ppid;
}

QString ProcessInfo::processName() const
{
    QString ret;
    struct kinfo_proc kp;
    size_t bufSize = sizeof(struct kinfo_proc);
    int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, processId };

    if (sysctl(mib, 4, &kp, &bufSize, NULL, 0) == 0) {
        ret.append(kp.kp_proc.p_comm);
    }
    return ret;
}

QList<qint64> ProcessInfo::allConcurrentPids()
{
    QList<qint64> ret;
    struct kinfo_proc *kp;
    size_t bufSize = 0;
    int mib[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };

    if (sysctl(mib, 3, NULL, &bufSize, NULL, 0) == 0) {
        kp = (struct kinfo_proc *) new char[bufSize];
        if (sysctl(mib, 3, kp, &bufSize, NULL, 0) == 0) {
            for (size_t i = 0; i < (bufSize / sizeof(struct kinfo_proc)); ++i) {
                qint64 pid = kp[i].kp_proc.p_pid;
                if (pid > 0)
                    ret.prepend(pid);
            }
        }
        delete[] kp;
    }

    qSort(ret.begin(), ret.end());  // Sorts the items
    return ret;
}

void ProcessInfo::terminate()
{
    if (processId > 0) {
        ::kill(processId, SIGTERM);
    }
}

void ProcessInfo::kill()
{
    if (processId > 0) {
        ::kill(processId, SIGKILL);
    }
    processId = -1;
}

void ProcessInfo::restart()
{
    if (processId > 0) {
        ::kill(processId, SIGHUP);
    }
}

} // namespace TreeFrog
<|endoftext|>


<commit_before>#ifndef ALEPH_PERSISTENT_HOMOLOGY_PHI_PERSISTENCE_HH__
#define ALEPH_PERSISTENT_HOMOLOGY_PHI_PERSISTENCE_HH__

#include <aleph/persistenceDiagrams/PersistenceDiagram.hh>

#include <aleph/persistentHomology/Calculation.hh>

#include <aleph/topology/Conversions.hh>
#include <aleph/topology/Intersections.hh>
#include <aleph/topology/SimplicialComplex.hh>

#include <initializer_list>
#include <map>
#include <stdexcept>
#include <utility>
#include <vector>

namespace aleph
{

/**
  Partitions a simplicial complex according to its $\phi$-persistence
  values. This follows the persistent intersection homology algorithm
  in:

    Persistent Intersection Homology
    Paul Bendich and John Harer

  The function expects a simplicial complex $K$ and a function $\phi$
  that determines whether a simplex is proper or not. The function is
  going to create a new simplicial complex. This complex contains all
  proper simplices (in their original order) followed by all improper
  ones.
*/

template <class Simplex, class Function> std::pair<topology::SimplicialComplex<Simplex>, std::size_t> partition( const topology::SimplicialComplex<Simplex>& K, Function phi )
{
  topology::SimplicialComplex<Simplex> L;

  for( auto&& simplex : K )
  {
    if( phi(simplex) )
      L.push_back( simplex );
  }

  auto s = L.size();

  for( auto&& simplex : K )
  {
    if( !phi(simplex) )
      L.push_back( simplex );
  }

  return std::make_pair( L, s );
}

/**
  @class Perversity
  @brief Perversity model in the sense of intersection homology

  Models a perversity in the sense of intersection homology. The class
  ensures that all values satisfy

  \f
    -1 \leq p_k \leq k-1
  \f
*/

class Perversity
{
public:

  /**
    Creates a new perversity from a range of values. The values must be
    at least implicitly convertible to integers.
  */

  template <class InputIterator> Perversity( InputIterator begin, InputIterator end )
    : _values( begin, end )
  {
    for( std::size_t k = 0; k < _values.size(); k++ )
    {
      if( _values[k] < -1 )
        _values[k] = -1;
      // There is an index shift going on here: since $k$ runs from $0$
      // to $d-1$, there is no need to shift the upper bound.
      else if( _values[k] > static_cast<int>( k ) )
        _values[k] = static_cast<int>( k );
    }
  }

  /** Creates a new perversity from an initializer list of values */
  Perversity( std::initializer_list<int> values )
    : Perversity( values.begin(), values.end() )
  {
  }

  /**
    Queries the perversity value in a given dimension $d$. Invalid
    dimension values only cause the function to return a zero.
  */

  int operator()( std::size_t d ) const noexcept
  {
    if( d < _values.size() + 1 )
      return _values[ static_cast<std::size_t>( d-1 ) ];
    else
      return 0;
  }

private:
  std::vector<int> _values;
};

template <class Simplex> auto calculateIntersectionHomology( const aleph::topology::SimplicialComplex<Simplex>& K,
                                                             const std::vector< aleph::topology::SimplicialComplex<Simplex> >& X,
                                                             const Perversity& p ) -> std::vector< PersistenceDiagram<typename Simplex::DataType> >
{
  // 0. Check consistency of strata
  // 1. Create allowability function based on the dimensionality of the
  //    intersection of simplices with individual strata.
  // 2. Calculate $phi$-persistence
  // 3. Convert the result into a persistence diagram.

  // Check consistency of filtration -----------------------------------
  //
  // The maximum dimension of each complex in the filtration has to
  // match the dimension of the simplicial complex.

  {
    std::size_t minDimension = K.dimension();
    std::size_t maxDimension = 0;

    for( auto&& x : X )
    {
      minDimension = std::min( minDimension, x.dimension() );
      maxDimension = std::max( maxDimension, x.dimension() );
    }

    if( maxDimension != K.dimension() )
      throw std::runtime_error( "Invalid filtration" );
  }

  // Check whether simplex is allowable --------------------------------

  std::map<Simplex, bool> phi;

  {
    auto d = K.dimension();

    for( auto&& s : K )
    {
      bool admissible = true;

      for( std::size_t k = 1; k <= d; k++ )
      {
        // The notation follows Bendich and Harer, so $i$ is actually
        // referring to a dimension instead of an index. Beware!
        auto i            = s.dimension();
        auto intersection = aleph::topology::intersect( X.at( d - k ), s );
        auto dimension    = intersection.empty() ? -1 : static_cast<long>( intersection.rbegin()->dimension() );
        admissible        = admissible && intersection.empty() ? true : static_cast<long>( dimension ) <= ( long(i) - long(k) + long( p(k) ) );
      }

      phi[s] = admissible;
    }
  }

  // Partition according to allowable simplices ------------------------

  aleph::topology::SimplicialComplex<Simplex> L;
  std::size_t s = 0;

  std::tie( L, s ) =
    aleph::partition( K, [&phi] ( const Simplex& s )
                         {
                           return phi.at(s);
                         } );

  // Calculate persistent intersection homology ------------------------

  auto boundaryMatrix             = aleph::topology::makeBoundaryMatrix( L, s );
  using IndexType                 = typename decltype(boundaryMatrix)::Index;
  bool includeAllUnpairedCreators = true;
  auto pairing                    = aleph::calculatePersistencePairing( boundaryMatrix, includeAllUnpairedCreators, static_cast<IndexType>(s) );
  auto persistenceDiagrams        = aleph::makePersistenceDiagrams( pairing, L );

  return persistenceDiagrams;
}

} // namespace aleph

#endif
<commit_msg>Output operator for perversities<commit_after>#ifndef ALEPH_PERSISTENT_HOMOLOGY_PHI_PERSISTENCE_HH__
#define ALEPH_PERSISTENT_HOMOLOGY_PHI_PERSISTENCE_HH__

#include <aleph/persistenceDiagrams/PersistenceDiagram.hh>

#include <aleph/persistentHomology/Calculation.hh>

#include <aleph/topology/Conversions.hh>
#include <aleph/topology/Intersections.hh>
#include <aleph/topology/SimplicialComplex.hh>

#include <initializer_list>
#include <map>
#include <ostream>
#include <stdexcept>
#include <utility>
#include <vector>

namespace aleph
{

/**
  Partitions a simplicial complex according to its $\phi$-persistence
  values. This follows the persistent intersection homology algorithm
  in:

    Persistent Intersection Homology
    Paul Bendich and John Harer

  The function expects a simplicial complex $K$ and a function $\phi$
  that determines whether a simplex is proper or not. The function is
  going to create a new simplicial complex. This complex contains all
  proper simplices (in their original order) followed by all improper
  ones.
*/

template <class Simplex, class Function> std::pair<topology::SimplicialComplex<Simplex>, std::size_t> partition( const topology::SimplicialComplex<Simplex>& K, Function phi )
{
  topology::SimplicialComplex<Simplex> L;

  for( auto&& simplex : K )
  {
    if( phi(simplex) )
      L.push_back( simplex );
  }

  auto s = L.size();

  for( auto&& simplex : K )
  {
    if( !phi(simplex) )
      L.push_back( simplex );
  }

  return std::make_pair( L, s );
}

/**
  @class Perversity
  @brief Perversity model in the sense of intersection homology

  Models a perversity in the sense of intersection homology. The class
  ensures that all values satisfy

  \f
    -1 \leq p_k \leq k-1
  \f
*/

class Perversity
{
public:

  /**
    Creates a new perversity from a range of values. The values must be
    at least implicitly convertible to integers.
  */

  template <class InputIterator> Perversity( InputIterator begin, InputIterator end )
    : _values( begin, end )
  {
    for( std::size_t k = 0; k < _values.size(); k++ )
    {
      if( _values[k] < -1 )
        _values[k] = -1;
      // There is an index shift going on here: since $k$ runs from $0$
      // to $d-1$, there is no need to shift the upper bound.
      else if( _values[k] > static_cast<int>( k ) )
        _values[k] = static_cast<int>( k );
    }
  }

  /** Creates a new perversity from an initializer list of values */
  Perversity( std::initializer_list<int> values )
    : Perversity( values.begin(), values.end() )
  {
  }

  /**
    Queries the perversity value in a given dimension $d$. Invalid
    dimension values only cause the function to return a zero.
  */

  int operator()( std::size_t d ) const noexcept
  {
    if( d < _values.size() + 1 )
      return _values[ static_cast<std::size_t>( d-1 ) ];
    else
      return 0;
  }

  using const_iterator = typename std::vector<int>::const_iterator;

  const_iterator begin() const noexcept { return _values.begin(); }
  const_iterator end()   const noexcept { return _values.end();   }

private:
  std::vector<int> _values;
};

std::ostream& operator<<( std::ostream& o, const Perversity p )
{
  o << "[";

  for( auto it = p.begin(); it != p.end(); ++it )
  {
    if( it != p.begin() )
      o << ",";

    o << *it;
  }

  o << "]";

  return o;
}

template <class Simplex> auto calculateIntersectionHomology( const aleph::topology::SimplicialComplex<Simplex>& K,
                                                             const std::vector< aleph::topology::SimplicialComplex<Simplex> >& X,
                                                             const Perversity& p ) -> std::vector< PersistenceDiagram<typename Simplex::DataType> >
{
  // 0. Check consistency of strata
  // 1. Create allowability function based on the dimensionality of the
  //    intersection of simplices with individual strata.
  // 2. Calculate $phi$-persistence
  // 3. Convert the result into a persistence diagram.

  // Check consistency of filtration -----------------------------------
  //
  // The maximum dimension of each complex in the filtration has to
  // match the dimension of the simplicial complex.

  {
    std::size_t minDimension = K.dimension();
    std::size_t maxDimension = 0;

    for( auto&& x : X )
    {
      minDimension = std::min( minDimension, x.dimension() );
      maxDimension = std::max( maxDimension, x.dimension() );
    }

    if( maxDimension != K.dimension() )
      throw std::runtime_error( "Invalid filtration" );
  }

  // Check whether simplex is allowable --------------------------------

  std::map<Simplex, bool> phi;

  {
    auto d = K.dimension();

    for( auto&& s : K )
    {
      bool admissible = true;

      for( std::size_t k = 1; k <= d; k++ )
      {
        // The notation follows Bendich and Harer, so $i$ is actually
        // referring to a dimension instead of an index. Beware!
        auto i            = s.dimension();
        auto intersection = aleph::topology::intersect( X.at( d - k ), s );
        auto dimension    = intersection.empty() ? -1 : static_cast<long>( intersection.rbegin()->dimension() );
        admissible        = admissible && intersection.empty() ? true : static_cast<long>( dimension ) <= ( long(i) - long(k) + long( p(k) ) );
      }

      phi[s] = admissible;
    }
  }

  // Partition according to allowable simplices ------------------------

  aleph::topology::SimplicialComplex<Simplex> L;
  std::size_t s = 0;

  std::tie( L, s ) =
    aleph::partition( K, [&phi] ( const Simplex& s )
                         {
                           return phi.at(s);
                         } );

  // Calculate persistent intersection homology ------------------------

  auto boundaryMatrix             = aleph::topology::makeBoundaryMatrix( L, s );
  using IndexType                 = typename decltype(boundaryMatrix)::Index;
  bool includeAllUnpairedCreators = true;
  auto pairing                    = aleph::calculatePersistencePairing( boundaryMatrix, includeAllUnpairedCreators, static_cast<IndexType>(s) );
  auto persistenceDiagrams        = aleph::makePersistenceDiagrams( pairing, L );

  return persistenceDiagrams;
}

} // namespace aleph

#endif
<|endoftext|>


<commit_before>// Copyright 2008 Google Inc. All Rights Reserved.
// Author: manzagop@google.com (Pierre-Antoine Manzagol)

#include <sstream>
#include "base/google.h"
#include "file/base/file.h"
#include "third_party/Torch3/Allocator.h"
#include "third_party/Torch3/ClassFormatDataSet.h"
#include "third_party/Torch3/OneHotClassFormat.h"
#include "third_party/Torch3/Measurer.h"
#include "third_party/Torch3/MSEMeasurer.h"
#include "third_party/Torch3/ClassMeasurer.h"
#include "third_party/Torch3/ClassNLLMeasurer.h"
#include "experimental/torch3google/GoogleMatDataSet.h"
#include "experimental/torch3google/GoogleDiskXFile.h"

#include "experimental/popnnet/mains/helpers.h"

DEFINE_string(model_filename, "", "the model filename");
DEFINE_string(test_data_file, "/home/manzagop/data/mnist/mnist_test.txt", "name of the test file");
DEFINE_string(expdir, "reload", "location where to write the expdir folder");
// --- Task ---
DEFINE_string(task, "mnist", "name of the task");
DEFINE_int32(n_inputs, 784, "number of inputs");
DEFINE_int32(n_classes, 10, "number of targets");
// --- Stuff ---
DEFINE_int32(max_load, -1, "max number of examples to load for train");
DEFINE_bool(binary_mode, false, "binary mode for files");

using namespace Torch;

// ************
// *** MAIN ***
// ************
int main(int argc, char **argv)
{
  InitGoogle(argv[0], &argc, &argv, true);
  File::Init();
  Allocator *allocator = new Allocator;

  CHECK(File::RecursivelyCreateDir(FLAGS_expdir.c_str(), mode_t(0755)));

  // data
  GoogleMatDataSet test_matdata(FLAGS_test_data_file.c_str(), FLAGS_n_inputs,1,false,
                                FLAGS_max_load, FLAGS_binary_mode);
  ClassFormatDataSet test_data(&test_matdata,FLAGS_n_classes);
  OneHotClassFormat class_format(&test_data);   // Not sure about this... what if not all classes were in the test set?

  // model
  CommunicatingStackedAutoencoder *csae = LoadCSAE(allocator, FLAGS_model_filename);

  // measurers
  MeasurerList measurers;

  string measurer_filename;
  measurer_filename = FLAGS_expdir + "/nll.txt";
  GoogleDiskXFile *file_nll = new(allocator) GoogleDiskXFile(measurer_filename.c_str(),"w");
  ClassNLLMeasurer *measurer_nll = new(allocator) ClassNLLMeasurer(csae->outputs, &test_data,
                                                                             &class_format, file_nll);
  measurers.addNode(measurer_nll);

  measurer_filename = FLAGS_expdir + "/class.txt";
  GoogleDiskXFile *file_class = new(allocator) GoogleDiskXFile(measurer_filename.c_str(),"w");
  ClassMeasurer *measurer_class = new(allocator) ClassMeasurer(csae->outputs, &test_data,
                                                                         &class_format, file_class);
  measurers.addNode(measurer_class);

  // trainer
  StochasticGradient trainer(csae, NULL);
  trainer.test(&measurers);

  delete allocator;
  return(0);

}
<commit_msg>Modifications to use Torch style arguments / options.<commit_after>// Copyright 2008 Google Inc.
//
// 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.
//
const char *help = "\
sae_load\n\
\n\
This program will load a model and test it on a dataset.\n\
\n";

#include <string>
#include <sstream>

#include "CmdLine.h"
#include "Allocator.h"
#include "ClassFormatDataSet.h"
#include "OneHotClassFormat.h"
#include "Measurer.h"
#include "MSEMeasurer.h"
#include "ClassMeasurer.h"
#include "ClassNLLMeasurer.h"
#include "MatDataSet.h"
#include "DiskXFile.h"
#include "helpers.h"

using namespace Torch;

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

  // === The command-line ===

  int flag_n_inputs;
  int flag_n_classes;
  char *flag_model_filename;
  char *flag_testdata_filename;

  char *flag_expdir;
  char *flag_task;
  int flag_max_load;
  bool flag_binary_mode;

  // Construct the command line
  CmdLine cmd;

  // Put the help line at the beginning
  cmd.info(help);

  cmd.addText("\nArguments:");

  cmd.addICmdArg("-n_inputs", &flag_n_inputs, "number of inputs");
  cmd.addICmdArg("-n_classes", &flag_n_classes, "number of targets");
  cmd.addSCmdArg("-model_filename", &flag_model_filename, "the model filename");
  cmd.addSCmdArg("-testdata_filename", &flag_testdata_filename, "name of the test file");

  cmd.addText("\nOptions:");
  cmd.addSCmdOption("-expdir", &flag_expdir, "./", "Location where to write the expdir folder.", true);
  cmd.addSCmdOption("-task", &flag_task, "", "name of the task", true);
  cmd.addICmdOption("max_load", &flag_max_load, -1, "max number of examples to load for train", true);
  cmd.addBCmdOption("binary_mode", &flag_binary_mode, false, "binary mode for files", true);

  // Read the command line
  cmd.read(argc, argv);

  Allocator *allocator = new Allocator;

  std::string str_expdir = flag_expdir;
  if(str_expdir != "./")   {
    warning("Calling non portable mkdir!");
    std::stringstream command;
    command << "mkdir " << flag_expdir;
    system(command.str().c_str());
  }

  // data
  MatDataSet test_matdata(flag_testdata_filename, flag_n_inputs,1,false,
                                flag_max_load, flag_binary_mode);
  ClassFormatDataSet test_data(&test_matdata,flag_n_classes);
  OneHotClassFormat class_format(&test_data);   // Not sure about this... what if not all classes were in the test set?

  // model
  CommunicatingStackedAutoencoder *csae = LoadCSAE(allocator, flag_model_filename);

  // measurers
  MeasurerList measurers;

  std::stringstream measurer_filename;
  measurer_filename << flag_expdir << "/nll.txt";
  DiskXFile *file_nll = new(allocator) DiskXFile(measurer_filename.str().c_str(),"w");
  ClassNLLMeasurer *measurer_nll = new(allocator) ClassNLLMeasurer(csae->outputs, &test_data,
                                                                             &class_format, file_nll);
  measurers.addNode(measurer_nll);

  measurer_filename.str("");
  measurer_filename.clear();

  measurer_filename << flag_expdir << "/class.txt";
  DiskXFile *file_class = new(allocator) DiskXFile(measurer_filename.str().c_str(),"w");
  ClassMeasurer *measurer_class = new(allocator) ClassMeasurer(csae->outputs, &test_data,
                                                                         &class_format, file_class);
  measurers.addNode(measurer_class);

  // trainer
  StochasticGradient trainer(csae, NULL);
  trainer.test(&measurers);

  delete allocator;
  return(0);

}
<|endoftext|>


<commit_before>//
// Copyright (c) 2013-2014 Christoph Malek
// See LICENSE for more information.
//

#ifndef RJ_CORE_MAIN_MENU_LEVEL_SQUARES_HPP
#define RJ_CORE_MAIN_MENU_LEVEL_SQUARES_HPP

#include "basic_component.hpp"
#include "level_square.hpp"
#include <rectojump/core/render.hpp>
#include <rectojump/shared/level_manager/level_manager.hpp>

#include <mlk/signals_slots/slot.h>

namespace rj
{
	enum class scroll_dir : char
	{up, down, none};

	template<typename Main_Menu>
	class level_squares : public basic_component
	{
		Main_Menu& m_mainmenu;

		const vec2f m_square_size{100, 100};
		std::vector<level_square<Main_Menu>> m_squares;
		std::size_t m_current_index{0};

		scroll_dir m_sdir{scroll_dir::none};
		float m_scrollstep{1.5f};

	public:
		mlk::slot<const level_id&> on_level_load;

		level_squares(Main_Menu& mm) :
			basic_component{mm.get_gamehandler().get_game(), mm.get_font(), mm.get_center()},
			m_mainmenu{mm}
		{this->init();}

		void update(dur duration)
		{
			if(m_squares[m_current_index].get_position().y > m_center.y + 5.f) // 5: add some 'space'
				this->scroll(scroll_dir::down);
			else if(m_squares[m_current_index].get_position().y < m_center.y - 5.f)
				this->scroll(scroll_dir::up);
			else
				this->scroll_stop();

			for(auto& a : m_squares)
			{
				a.update(duration);
				a.deactivate();

				if(m_sdir == scroll_dir::down) a.move({0.f, -m_scrollstep});
				else if(m_sdir == scroll_dir::up) a.move({0.f, m_scrollstep});
			}

			m_squares[m_current_index].activate();
		}

		void render()
		{
			for(auto& a : m_squares)
				a.render();
		}

		void scroll(scroll_dir dir) noexcept
		{m_sdir = dir;}

		void scroll_stop() noexcept
		{m_sdir = scroll_dir::none;}

		void on_key_up() noexcept
		{
			if(m_current_index <= 0)
				m_current_index = this->max_index();
			else
				--m_current_index;
		}

		void on_key_down() noexcept
		{
			if(m_current_index >= this->max_index())
				m_current_index = 0;
			else
				++m_current_index;
		}

		void call_current_event() override
		{on_level_load("");}

	private:
		void init()
		{
			auto pos_y(0.f);

			for(auto& a : m_mainmenu.get_gamehandler().get_levelmgr().get_levels())
			{
				auto& lv(a.second);
				auto& inf(lv.info);

				m_squares.emplace_back(m_mainmenu, vec2f{m_center.x, pos_y}, m_square_size,
									   "Name", mlk::stl_string::str_format("Creator: %%\nDate: %%", inf.creator_name, inf.creation_date));
				pos_y += m_squares.back().get_height();
			}
		}

		std::size_t num_items() const noexcept
		{return m_squares.size();}

		std::size_t max_index() const noexcept
		{return this->num_items() - 1;}
	};
}

#endif // RJ_CORE_MAIN_MENU_LEVEL_SQUARES_HPP
<commit_msg>level_sqaures: loading current selected level<commit_after>//
// Copyright (c) 2013-2014 Christoph Malek
// See LICENSE for more information.
//

#ifndef RJ_CORE_MAIN_MENU_LEVEL_SQUARES_HPP
#define RJ_CORE_MAIN_MENU_LEVEL_SQUARES_HPP

#include "basic_component.hpp"
#include "level_square.hpp"
#include <rectojump/core/render.hpp>
#include <rectojump/shared/level_manager/level_manager.hpp>

#include <mlk/signals_slots/slot.h>

namespace rj
{
	enum class scroll_dir : char
	{up, down, none};

	template<typename Main_Menu>
	class level_squares : public basic_component
	{
		Main_Menu& m_mainmenu;

		const vec2f m_square_size{100, 100};
		std::vector<level_square<Main_Menu>> m_squares;
		std::size_t m_current_index{0};

		scroll_dir m_sdir{scroll_dir::none};
		float m_scrollstep{1.5f};

	public:
		mlk::slot<const level_id&> on_level_load;

		level_squares(Main_Menu& mm) :
			basic_component{mm.get_gamehandler().get_game(), mm.get_font(), mm.get_center()},
			m_mainmenu{mm}
		{this->init();}

		void update(dur duration)
		{
			if(m_squares[m_current_index].get_position().y > m_center.y + 5.f) // 5: add some 'space'
				this->scroll(scroll_dir::down);
			else if(m_squares[m_current_index].get_position().y < m_center.y - 5.f)
				this->scroll(scroll_dir::up);
			else
				this->scroll_stop();

			for(auto& a : m_squares)
			{
				a.update(duration);
				a.deactivate();

				if(m_sdir == scroll_dir::down) a.move({0.f, -m_scrollstep});
				else if(m_sdir == scroll_dir::up) a.move({0.f, m_scrollstep});
			}

			m_squares[m_current_index].activate();
		}

		void render()
		{
			for(auto& a : m_squares)
				a.render();
		}

		void scroll(scroll_dir dir) noexcept
		{m_sdir = dir;}

		void scroll_stop() noexcept
		{m_sdir = scroll_dir::none;}

		void on_key_up() noexcept
		{
			if(m_current_index <= 0)
				m_current_index = this->max_index();
			else
				--m_current_index;
		}

		void on_key_down() noexcept
		{
			if(m_current_index >= this->max_index())
				m_current_index = 0;
			else
				++m_current_index;
		}

		void call_current_event() override
		{on_level_load(m_squares[m_current_index].get_id());}

	private:
		void init()
		{
			auto pos_y(0.f);

			for(auto& a : m_mainmenu.get_gamehandler().get_levelmgr().get_levels())
			{
				auto& id(a.first);
				auto& lv(a.second);
				auto& inf(lv.info);

				m_squares.emplace_back(m_mainmenu, vec2f{m_center.x, pos_y}, m_square_size,
									   "Name", mlk::stl_string::str_format("Creator: %%\nDate: %%", inf.creator_name, inf.creation_date), id);
				pos_y += m_squares.back().get_height();
			}
		}

		std::size_t num_items() const noexcept
		{return m_squares.size();}

		std::size_t max_index() const noexcept
		{return this->num_items() - 1;}
	};
}

#endif // RJ_CORE_MAIN_MENU_LEVEL_SQUARES_HPP
<|endoftext|>


<commit_before>// Filename: ppInstance.cxx
// Created by:  drose (19Jun09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University.  All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license.  You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////

#include "ppInstance.h"
#include "startup.h"
#include "p3d_plugin_config.h"

////////////////////////////////////////////////////////////////////
//     Function: PPInstance::Constructor
//       Access: Public
//  Description: Creates a new instance of a Panda3D plugin window.
//               The create_data structure is supplied from NPAPI, and
//               defines the initial parameters specified in the HTML
//               document.
////////////////////////////////////////////////////////////////////
PPInstance::
PPInstance(NPMIMEType pluginType, NPP instance, uint16 mode,
           int16 argc, char *argn[], char *argv[], NPSavedData *saved) {
  logfile << "constructing " << this << "\n" << flush;
  _p3d_inst = NULL;

  _npp_instance = instance;
  _npp_mode = mode;

  // Copy the tokens and save them within this object.
  _tokens.reserve(argc);
  for (int i = 0; i < argc; ++i) {
    P3D_token token;
    token._keyword = strdup(argn[i]);
    token._value = strdup(argv[i]);
    logfile
      << " " << i << ": " << token._keyword << " = " << token._value << "\n";
    _tokens.push_back(token);
  }

  _started_instance_data = false;
  _got_instance_data = false;
  _got_window = false;

  if (!is_plugin_loaded()) {
    // Start the plugin DLL downloading.
    string url = P3D_PLUGIN_DOWNLOAD;
    url += P3D_PLUGIN_PLATFORM;
    url += "/";
    url += get_plugin_basename();

    PPDownloadRequest *req = new PPDownloadRequest(PPDownloadRequest::RT_core_dll);
    browser->geturlnotify(_npp_instance, url.c_str(), NULL, req);
  }
}

////////////////////////////////////////////////////////////////////
//     Function: PPInstance::Destructor
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
PPInstance::
~PPInstance() {
  logfile
    << "destructing " << this << ", " << _p3d_inst << "\n" << flush;

  if (_p3d_inst != NULL) {
    P3D_instance_finish(_p3d_inst);
    _p3d_inst = NULL;
  }

  // Free the tokens we allocated.
  Tokens::iterator ti;
  for (ti = _tokens.begin(); ti != _tokens.end(); ++ti) {
    free((char *)(*ti)._keyword);
    free((char *)(*ti)._value);
  }
  _tokens.clear();
}

////////////////////////////////////////////////////////////////////
//     Function: PPInstance::set_window
//       Access: Public
//  Description: Stores or updates the window parameters.
////////////////////////////////////////////////////////////////////
void PPInstance::
set_window(NPWindow *window) {
  if (window->x == _window.x &&
      window->y == _window.y &&
      window->width == _window.width &&
      window->height == _window.height) {
    // No changes.
    return;
  }

  _window = *window;
  _got_window = true;

  if (_p3d_inst == NULL) {
    create_instance();
  } else {
    send_window();
  }
}

////////////////////////////////////////////////////////////////////
//     Function: PPInstance::new_stream
//       Access: Public
//  Description: Receives notification of a new stream object, e.g. a
//               url request.
////////////////////////////////////////////////////////////////////
NPError PPInstance::
new_stream(NPMIMEType type, NPStream *stream, bool seekable, uint16 *stype) {
  if (stream->notifyData == NULL) {
    // This is an unsolicited stream.  Assume the first unsolicited
    // stream we receive is the instance data; any other unsolicited
    // stream is an error.
    if (!_started_instance_data) {
      stream->notifyData = new PPDownloadRequest(PPDownloadRequest::RT_instance_data);
      *stype = NP_ASFILEONLY;
      _started_instance_data = true;
      return NPERR_NO_ERROR;
    }

    // This is an unexpected unsolicited stream.  (Firefox seems to
    // give us the instance data twice for some reason.)
    return NPERR_GENERIC_ERROR;
  }

  PPDownloadRequest *req = (PPDownloadRequest *)(stream->notifyData);
  switch (req->_rtype) {
  case PPDownloadRequest::RT_core_dll:
    // This is the core API DLL (or dylib or whatever).  We want to
    // download this to file so we can run it directly.
    *stype = NP_ASFILEONLY;
    return NPERR_NO_ERROR;

  case PPDownloadRequest::RT_user:
    // This is a request from the plugin.  We'll receive this as a
    // stream.
    *stype = NP_NORMAL;
    return NPERR_NO_ERROR;

  default:
    // Don't know what this is.
    logfile << "Unexpected request " << (int)req->_rtype << "\n";
  }

  return NPERR_GENERIC_ERROR;
}

////////////////////////////////////////////////////////////////////
//     Function: PPInstance::write_stream
//       Access: Public
//  Description: Called by the browser to feed data read from a URL or
//               whatever.
////////////////////////////////////////////////////////////////////
int PPInstance::
write_stream(NPStream *stream, int offset, int len, void *buffer) {
  if (stream->notifyData == NULL) {
    logfile << "Unexpected write_stream on " << stream->url << "\n";
    return 0;
  }

  PPDownloadRequest *req = (PPDownloadRequest *)(stream->notifyData);
  switch (req->_rtype) {
  case PPDownloadRequest::RT_user:
    P3D_instance_feed_url_stream(_p3d_inst, req->_user_id,
                                 P3D_RC_in_progress, 0,
                                 stream->end, buffer, len);
    return len;

  default:
    logfile << "Unexpected write_stream on " << stream->url << "\n";
    break;
  }

  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: PPInstance::destroy_stream
//       Access: Public
//  Description: Called by the browser to mark the end of a stream;
//               the file has either been successfully downloaded or
//               failed.
////////////////////////////////////////////////////////////////////
NPError PPInstance::
destroy_stream(NPStream *stream, NPReason reason) {
  if (stream->notifyData == NULL) {
    logfile << "Unexpected destroy_stream on " << stream->url << "\n";
    return NPERR_GENERIC_ERROR;
  }

  PPDownloadRequest *req = (PPDownloadRequest *)(stream->notifyData);
  switch (req->_rtype) {
  case PPDownloadRequest::RT_user:
    {
      P3D_result_code result_code = P3D_RC_done;
      if (reason != NPRES_DONE) {
        result_code = P3D_RC_generic_error;
      }
      assert(!req->_notified_done);
      P3D_instance_feed_url_stream(_p3d_inst, req->_user_id,
                                   result_code, 0, stream->end, NULL, 0);
      req->_notified_done = true;
    }
    break;

  default:
    break;
  }

  return NPERR_NO_ERROR;
}

////////////////////////////////////////////////////////////////////
//     Function: PPInstance::url_notify
//       Access: Public
//  Description: Called by the browser to announce the end of a
//               stream.  This normally follows destroy_stream(),
//               unless the stream was never created in the first
//               place.
////////////////////////////////////////////////////////////////////
void PPInstance::
url_notify(const char *url, NPReason reason, void *notifyData) {
  if (notifyData == NULL) {
    return;
  }

  PPDownloadRequest *req = (PPDownloadRequest *)notifyData;
  switch (req->_rtype) {
  case PPDownloadRequest::RT_user:
    if (!req->_notified_done) {
      // We shouldn't have gotten here without notifying the stream
      // unless the stream never got started (and hence we never
      // called destroy_stream().
      logfile << "Failure starting stream\n" << flush;
      assert(reason != NPRES_DONE);

      P3D_instance_feed_url_stream(_p3d_inst, req->_user_id,
                                   P3D_RC_generic_error, 0, 0, NULL, 0);
      req->_notified_done = true;
    }
    break;

  default:
    break;
  }

  delete req;
}

////////////////////////////////////////////////////////////////////
//     Function: PPInstance::stream_as_file
//       Access: Public
//  Description: Called by the browser to report the filename that
//               contains the fully-downloaded stream contents.
////////////////////////////////////////////////////////////////////
void PPInstance::
stream_as_file(NPStream *stream, const char *fname) {
  if (stream->notifyData == NULL) {
    logfile << "Unexpected stream_as_file on " << stream->url << "\n";
    return;
  }

  string filename = fname;
#ifdef __APPLE__
  // Safari seems to want to report the filename in the old-style form
  // "Macintosh HD:blah:blah:blah" instead of the new-style form
  // "/blah/blah/blah".  How annoying.

  // TODO: Is "Macintosh HD:" the only possible prefix?
  if (filename.substr(0, 13) == "Macintosh HD:") {
    string fname2;
    for (size_t p = 12; p < filename.size(); ++p) {
      if (filename[p] == ':') {
        fname2 += '/';
      } else {
        fname2 += filename[p];
      }
    }
    filename = fname2;
    logfile << "converted filename to " << filename << "\n";
  }

#endif  // __APPLE__

  PPDownloadRequest *req = (PPDownloadRequest *)(stream->notifyData);
  switch (req->_rtype) {
  case PPDownloadRequest::RT_core_dll:
    {
      // This is the core API DLL (or dylib or whatever).  Now that
      // we've downloaded it, we can load it.
      string override_filename = P3D_PLUGIN_P3D_PLUGIN;
      if (!override_filename.empty()) {
        filename = override_filename;
      }
      logfile << "got plugin " << filename << "\n" << flush;
      if (!load_plugin(filename)) {
        logfile << "Unable to launch core API.\n";
        break;
      }
      logfile << "loaded core API\n";
      create_instance();
    }
    break;

  case PPDownloadRequest::RT_instance_data:
    // This is the instance data, e.g. the p3d filename.  Now we can
    // launch the instance.
    _got_instance_data = true;
    _p3d_filename = filename;
    create_instance();
    break;

  default:
    // Don't know what this is.
    logfile << "Unexpected stream_as_file, type " << (int)req->_rtype << "\n";
  }
}

////////////////////////////////////////////////////////////////////
//     Function: PPInstance::handle_request
//       Access: Public
//  Description: Handles a request from the plugin, forwarding
//               it to the browser as appropriate.
////////////////////////////////////////////////////////////////////
void PPInstance::
handle_request(P3D_request *request) {
  logfile << "handle_request: " << request << ", " << request->_instance
          << " within " << this << ", " << _p3d_inst << "\n" << flush;
  assert(request->_instance == _p3d_inst);

  bool handled = false;

  switch (request->_request_type) {
  case P3D_RT_stop:
    logfile << "Got P3D_RT_stop\n";
    if (_p3d_inst != NULL) {
      P3D_instance_finish(_p3d_inst);
      _p3d_inst = NULL;
    }
    // Guess the browser doesn't really care.
    handled = true;
    break;

  case P3D_RT_get_url:
    {
      logfile << "Got P3D_RT_get_url: " << request->_request._get_url._url
              << "\n";

      PPDownloadRequest *req =
        new PPDownloadRequest(PPDownloadRequest::RT_user,
                              request->_request._get_url._unique_id);
      browser->geturlnotify(_npp_instance, request->_request._get_url._url,
                            NULL, req);
    }

    break;

  default:
    // Some request types are not handled.
    logfile << "Unhandled request: " << request->_request_type << "\n";
    break;
  };

  P3D_request_finish(request, handled);
}

////////////////////////////////////////////////////////////////////
//     Function: PPInstance::create_instance
//       Access: Private
//  Description: Actually creates the internal P3D_instance object, if
//               possible and needed.
////////////////////////////////////////////////////////////////////
void PPInstance::
create_instance() {
  if (_p3d_inst != NULL) {
    // Already created.
    return;
  }

  if (!is_plugin_loaded()) {
    // Plugin is not loaded yet.
    return;
  }

  if (!_got_instance_data) {
    // No instance data yet.
    return;
  }

  if (!_got_window) {
    // No window yet.
    return;
  }

  logfile << "within " << this << ", creating new instance\n" << flush;
  _p3d_inst = P3D_new_instance(request_ready, this);
  logfile << "within " << this << ", created new instance " << _p3d_inst
          << "\n" << flush;

  if (_p3d_inst != NULL) {
    const P3D_token *tokens = NULL;
    if (!_tokens.empty()) {
      tokens = &_tokens[0];
    }
    P3D_instance_start(_p3d_inst, _p3d_filename.c_str(), tokens, _tokens.size());
    send_window();
  }
}

////////////////////////////////////////////////////////////////////
//     Function: PPInstance::send_window
//       Access: Private
//  Description: Actually issues the window parameters to the internal
//               P3D_instance object.
////////////////////////////////////////////////////////////////////
void PPInstance::
send_window() {
  assert(_p3d_inst != NULL);

  P3D_window_handle parent_window;
#ifdef _WIN32
  parent_window._hwnd = (HWND)(_window.window);
#endif

  // Actually, we set up the window starting at (0, 0), instead of
  // whatever Mozilla tells us, because the window handle we get is a
  // specially created window that is already aligned to where we want
  // our window to be.
  P3D_instance_setup_window
    (_p3d_inst, P3D_WT_embedded,
     0, 0, _window.width, _window.height,
     parent_window);
}
<commit_msg>minor cleanup<commit_after>// Filename: ppInstance.cxx
// Created by:  drose (19Jun09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University.  All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license.  You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////

#include "ppInstance.h"
#include "startup.h"
#include "p3d_plugin_config.h"

////////////////////////////////////////////////////////////////////
//     Function: PPInstance::Constructor
//       Access: Public
//  Description: Creates a new instance of a Panda3D plugin window.
//               The create_data structure is supplied from NPAPI, and
//               defines the initial parameters specified in the HTML
//               document.
////////////////////////////////////////////////////////////////////
PPInstance::
PPInstance(NPMIMEType pluginType, NPP instance, uint16 mode,
           int16 argc, char *argn[], char *argv[], NPSavedData *saved) {
  logfile << "constructing " << this << "\n" << flush;
  _p3d_inst = NULL;

  _npp_instance = instance;
  _npp_mode = mode;

  // Copy the tokens and save them within this object.
  _tokens.reserve(argc);
  for (int i = 0; i < argc; ++i) {
    P3D_token token;
    token._keyword = strdup(argn[i]);
    token._value = strdup(argv[i]);
    logfile
      << " " << i << ": " << token._keyword << " = " << token._value << "\n";
    _tokens.push_back(token);
  }

  _started_instance_data = false;
  _got_instance_data = false;
  _got_window = false;

  if (!is_plugin_loaded()) {
    // Start the plugin DLL downloading.
    string url = P3D_PLUGIN_DOWNLOAD;
    url += P3D_PLUGIN_PLATFORM;
    url += "/";
    url += get_plugin_basename();

    PPDownloadRequest *req = new PPDownloadRequest(PPDownloadRequest::RT_core_dll);
    browser->geturlnotify(_npp_instance, url.c_str(), NULL, req);
  }
}

////////////////////////////////////////////////////////////////////
//     Function: PPInstance::Destructor
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
PPInstance::
~PPInstance() {
  logfile
    << "destructing " << this << ", " << _p3d_inst << "\n" << flush;

  if (_p3d_inst != NULL) {
    P3D_instance_finish(_p3d_inst);
    _p3d_inst = NULL;
  }

  // Free the tokens we allocated.
  Tokens::iterator ti;
  for (ti = _tokens.begin(); ti != _tokens.end(); ++ti) {
    free((char *)(*ti)._keyword);
    free((char *)(*ti)._value);
  }
  _tokens.clear();
}

////////////////////////////////////////////////////////////////////
//     Function: PPInstance::set_window
//       Access: Public
//  Description: Stores or updates the window parameters.
////////////////////////////////////////////////////////////////////
void PPInstance::
set_window(NPWindow *window) {
  if (window->x == _window.x &&
      window->y == _window.y &&
      window->width == _window.width &&
      window->height == _window.height) {
    // No changes.
    return;
  }

  _window = *window;
  _got_window = true;

  if (_p3d_inst == NULL) {
    create_instance();
  } else {
    send_window();
  }
}

////////////////////////////////////////////////////////////////////
//     Function: PPInstance::new_stream
//       Access: Public
//  Description: Receives notification of a new stream object, e.g. a
//               url request.
////////////////////////////////////////////////////////////////////
NPError PPInstance::
new_stream(NPMIMEType type, NPStream *stream, bool seekable, uint16 *stype) {
  if (stream->notifyData == NULL) {
    // This is an unsolicited stream.  Assume the first unsolicited
    // stream we receive is the instance data; any other unsolicited
    // stream is an error.
    if (!_started_instance_data) {
      stream->notifyData = new PPDownloadRequest(PPDownloadRequest::RT_instance_data);
      *stype = NP_ASFILEONLY;
      _started_instance_data = true;
      return NPERR_NO_ERROR;
    }

    // This is an unexpected unsolicited stream.  (Firefox seems to
    // give us the instance data twice for some reason.)
    return NPERR_GENERIC_ERROR;
  }

  PPDownloadRequest *req = (PPDownloadRequest *)(stream->notifyData);
  switch (req->_rtype) {
  case PPDownloadRequest::RT_core_dll:
    // This is the core API DLL (or dylib or whatever).  We want to
    // download this to file so we can run it directly.
    *stype = NP_ASFILEONLY;
    return NPERR_NO_ERROR;

  case PPDownloadRequest::RT_user:
    // This is a request from the plugin.  We'll receive this as a
    // stream.
    *stype = NP_NORMAL;
    return NPERR_NO_ERROR;

  default:
    // Don't know what this is.
    logfile << "Unexpected request " << (int)req->_rtype << "\n";
  }

  return NPERR_GENERIC_ERROR;
}

////////////////////////////////////////////////////////////////////
//     Function: PPInstance::write_stream
//       Access: Public
//  Description: Called by the browser to feed data read from a URL or
//               whatever.
////////////////////////////////////////////////////////////////////
int PPInstance::
write_stream(NPStream *stream, int offset, int len, void *buffer) {
  if (stream->notifyData == NULL) {
    logfile << "Unexpected write_stream on " << stream->url << "\n";
    return 0;
  }

  PPDownloadRequest *req = (PPDownloadRequest *)(stream->notifyData);
  switch (req->_rtype) {
  case PPDownloadRequest::RT_user:
    P3D_instance_feed_url_stream(_p3d_inst, req->_user_id,
                                 P3D_RC_in_progress, 0,
                                 stream->end, buffer, len);
    return len;

  default:
    logfile << "Unexpected write_stream on " << stream->url << "\n";
    break;
  }

  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: PPInstance::destroy_stream
//       Access: Public
//  Description: Called by the browser to mark the end of a stream;
//               the file has either been successfully downloaded or
//               failed.
////////////////////////////////////////////////////////////////////
NPError PPInstance::
destroy_stream(NPStream *stream, NPReason reason) {
  if (stream->notifyData == NULL) {
    logfile << "Unexpected destroy_stream on " << stream->url << "\n";
    return NPERR_GENERIC_ERROR;
  }

  PPDownloadRequest *req = (PPDownloadRequest *)(stream->notifyData);
  switch (req->_rtype) {
  case PPDownloadRequest::RT_user:
    {
      P3D_result_code result_code = P3D_RC_done;
      if (reason != NPRES_DONE) {
        result_code = P3D_RC_generic_error;
      }
      assert(!req->_notified_done);
      P3D_instance_feed_url_stream(_p3d_inst, req->_user_id,
                                   result_code, 0, stream->end, NULL, 0);
      req->_notified_done = true;
    }
    break;

  default:
    break;
  }

  return NPERR_NO_ERROR;
}

////////////////////////////////////////////////////////////////////
//     Function: PPInstance::url_notify
//       Access: Public
//  Description: Called by the browser to announce the end of a
//               stream.  This normally follows destroy_stream(),
//               unless the stream was never created in the first
//               place.
////////////////////////////////////////////////////////////////////
void PPInstance::
url_notify(const char *url, NPReason reason, void *notifyData) {
  if (notifyData == NULL) {
    return;
  }

  PPDownloadRequest *req = (PPDownloadRequest *)notifyData;
  switch (req->_rtype) {
  case PPDownloadRequest::RT_user:
    if (!req->_notified_done) {
      // We shouldn't have gotten here without notifying the stream
      // unless the stream never got started (and hence we never
      // called destroy_stream().
      logfile << "Failure starting stream\n" << flush;
      assert(reason != NPRES_DONE);

      P3D_instance_feed_url_stream(_p3d_inst, req->_user_id,
                                   P3D_RC_generic_error, 0, 0, NULL, 0);
      req->_notified_done = true;
    }
    break;

  default:
    break;
  }

  delete req;
}

////////////////////////////////////////////////////////////////////
//     Function: PPInstance::stream_as_file
//       Access: Public
//  Description: Called by the browser to report the filename that
//               contains the fully-downloaded stream contents.
////////////////////////////////////////////////////////////////////
void PPInstance::
stream_as_file(NPStream *stream, const char *fname) {
  if (stream->notifyData == NULL) {
    logfile << "Unexpected stream_as_file on " << stream->url << "\n";
    return;
  }

  string filename = fname;
#ifdef __APPLE__
  // Safari seems to want to report the filename in the old-style form
  // "Macintosh HD:blah:blah:blah" instead of the new-style form
  // "/blah/blah/blah".  How annoying.

  // TODO: Is "Macintosh HD:" the only possible prefix?
  if (filename.substr(0, 13) == "Macintosh HD:") {
    string fname2;
    for (size_t p = 12; p < filename.size(); ++p) {
      if (filename[p] == ':') {
        fname2 += '/';
      } else {
        fname2 += filename[p];
      }
    }
    filename = fname2;
    logfile << "converted filename to " << filename << "\n";
  }

#endif  // __APPLE__

  PPDownloadRequest *req = (PPDownloadRequest *)(stream->notifyData);
  switch (req->_rtype) {
  case PPDownloadRequest::RT_core_dll:
    {
      // This is the core API DLL (or dylib or whatever).  Now that
      // we've downloaded it, we can load it.
      string override_filename = P3D_PLUGIN_P3D_PLUGIN;
      if (!override_filename.empty()) {
        filename = override_filename;
      }
      logfile << "got plugin " << filename << "\n" << flush;
      if (!load_plugin(filename)) {
        logfile << "Unable to launch core API.\n";
        break;
      }
      logfile << "loaded core API\n";
      create_instance();
    }
    break;

  case PPDownloadRequest::RT_instance_data:
    // This is the instance data, e.g. the p3d filename.  Now we can
    // launch the instance.
    _got_instance_data = true;
    _p3d_filename = filename;
    create_instance();
    break;

  default:
    // Don't know what this is.
    logfile << "Unexpected stream_as_file, type " << (int)req->_rtype << "\n";
  }
}

////////////////////////////////////////////////////////////////////
//     Function: PPInstance::handle_request
//       Access: Public
//  Description: Handles a request from the plugin, forwarding
//               it to the browser as appropriate.
////////////////////////////////////////////////////////////////////
void PPInstance::
handle_request(P3D_request *request) {
  logfile << "handle_request: " << request << ", " << request->_instance
          << " within " << this << ", " << _p3d_inst << "\n" << flush;
  assert(request->_instance == _p3d_inst);

  bool handled = false;

  switch (request->_request_type) {
  case P3D_RT_stop:
    logfile << "Got P3D_RT_stop\n";
    if (_p3d_inst != NULL) {
      P3D_instance_finish(_p3d_inst);
      _p3d_inst = NULL;
    }
    // Guess the browser doesn't really care.
    handled = true;
    break;

  case P3D_RT_get_url:
    {
      logfile << "Got P3D_RT_get_url: " << request->_request._get_url._url
              << "\n";

      PPDownloadRequest *req =
        new PPDownloadRequest(PPDownloadRequest::RT_user,
                              request->_request._get_url._unique_id);
      browser->geturlnotify(_npp_instance, request->_request._get_url._url,
                            NULL, req);
    }

    break;

  default:
    // Some request types are not handled.
    logfile << "Unhandled request: " << request->_request_type << "\n";
    break;
  };

  P3D_request_finish(request, handled);
}

////////////////////////////////////////////////////////////////////
//     Function: PPInstance::create_instance
//       Access: Private
//  Description: Actually creates the internal P3D_instance object, if
//               possible and needed.
////////////////////////////////////////////////////////////////////
void PPInstance::
create_instance() {
  if (_p3d_inst != NULL) {
    // Already created.
    return;
  }

  if (!is_plugin_loaded()) {
    // Plugin is not loaded yet.
    return;
  }

  if (!_got_instance_data) {
    // No instance data yet.
    return;
  }

  if (!_got_window) {
    // No window yet.
    return;
  }

  _p3d_inst = P3D_new_instance(request_ready, this);

  if (_p3d_inst != NULL) {
    const P3D_token *tokens = NULL;
    if (!_tokens.empty()) {
      tokens = &_tokens[0];
    }
    P3D_instance_start(_p3d_inst, _p3d_filename.c_str(), tokens, _tokens.size());
    send_window();
  }
}

////////////////////////////////////////////////////////////////////
//     Function: PPInstance::send_window
//       Access: Private
//  Description: Actually issues the window parameters to the internal
//               P3D_instance object.
////////////////////////////////////////////////////////////////////
void PPInstance::
send_window() {
  assert(_p3d_inst != NULL);

  P3D_window_handle parent_window;
#ifdef _WIN32
  parent_window._hwnd = (HWND)(_window.window);
#endif

  // Actually, we set up the window starting at (0, 0), instead of
  // whatever Mozilla tells us, because the window handle we get is a
  // specially created window that is already aligned to where we want
  // our window to be.
  P3D_instance_setup_window
    (_p3d_inst, P3D_WT_embedded,
     0, 0, _window.width, _window.height,
     parent_window);
}
<|endoftext|>


<commit_before>//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "ClingPragmas.h"

#include "cling/Interpreter/Interpreter.h"
#include "cling/Utils/Output.h"
#include "cling/Utils/Paths.h"

#include "clang/AST/ASTContext.h"
#include "clang/Basic/TokenKinds.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/Token.h"
#include "clang/Parse/Parser.h"

using namespace cling;
using namespace clang;

namespace {
  typedef std::pair<bool, std::string> ParseResult_t;

  static ParseResult_t HandlePragmaHelper(Preprocessor &PP,
                                          const std::string &pragmaInst) {
    struct SkipToEOD_t {
      Preprocessor& m_PP;
      SkipToEOD_t(Preprocessor& PParg): m_PP(PParg) {}
      ~SkipToEOD_t() { m_PP.DiscardUntilEndOfDirective(); }
    } SkipToEOD(PP);

    Token Tok;
    PP.Lex(Tok);
    if (Tok.isNot(tok::l_paren)) {
      cling::errs() << "cling:HandlePragmaHelper : expect '(' after #"
                    << pragmaInst;
      return ParseResult_t{false, ""};
    }
    std::string Literal;
    if (!PP.LexStringLiteral(Tok, Literal, pragmaInst.c_str(),
                             false /*allowMacroExpansion*/)) {
      // already diagnosed.
      return ParseResult_t {false, ""};
    }
    utils::ExpandEnvVars(Literal);

    return ParseResult_t {true, Literal};
  }

  class PHLoad: public PragmaHandler {
    Interpreter& m_Interp;

  public:
    PHLoad(Interpreter& interp):
      PragmaHandler("load"), m_Interp(interp) {}

    void HandlePragma(Preprocessor &PP,
                      PragmaIntroducerKind Introducer,
                      Token &FirstToken) override {
      // TODO: use Diagnostics!
      ParseResult_t Result = HandlePragmaHelper(PP, "pragma cling load");

      if (!Result.first)
        return;
      if (Result.second.empty()) {
        cling::errs() << "Cannot load unnamed files.\n" ;
        return;
      }
      clang::Parser& P = m_Interp.getParser();
      Parser::ParserCurTokRestoreRAII savedCurToken(P);
      // After we have saved the token reset the current one to something which
      // is safe (semi colon usually means empty decl)
      Token& CurTok = const_cast<Token&>(P.getCurToken());
      CurTok.setKind(tok::semi);

      if (!m_Interp.isInSyntaxOnlyMode()) {
        // No need to load libraries if we're not executing anything.

        Preprocessor::CleanupAndRestoreCacheRAII cleanupRAII(PP);
        // We can't PushDeclContext, because we go up and the routine that pops
        // the DeclContext assumes that we drill down always.
        // We have to be on the global context. At that point we are in a
        // wrapper function so the parent context must be the global.
        TranslationUnitDecl* TU =
          m_Interp.getCI()->getASTContext().getTranslationUnitDecl();
        Sema::ContextAndScopeRAII pushedDCAndS(m_Interp.getSema(),
                                               TU, m_Interp.getSema().TUScope);
        Interpreter::PushTransactionRAII pushedT(&m_Interp);

        m_Interp.loadFile(Result.second, true /*allowSharedLib*/);
      }
    }
  };

  class PHAddIncPath: public PragmaHandler {
    Interpreter& m_Interp;

  public:
    PHAddIncPath(Interpreter& interp):
      PragmaHandler("add_include_path"), m_Interp(interp) {}

    void HandlePragma(Preprocessor &PP,
                      PragmaIntroducerKind Introducer,
                      Token &FirstToken) override {
      // TODO: use Diagnostics!
      ParseResult_t Result = HandlePragmaHelper(PP,
                                           "pragma cling add_include_path");
      //if the function HandlePragmaHelper returned false,
      if (!Result.first)
        return;
      if (!Result.second.empty())
        m_Interp.AddIncludePath(Result.second);
    }
  };

  class PHAddLibraryPath: public PragmaHandler {
    Interpreter& m_Interp;

  public:
    PHAddLibraryPath(Interpreter& interp):
      PragmaHandler("add_library_path"), m_Interp(interp) {}

    void HandlePragma(Preprocessor &PP,
                      PragmaIntroducerKind Introducer,
                      Token &FirstToken) override {
      // TODO: use Diagnostics!
      ParseResult_t Result = HandlePragmaHelper(PP,
                                         "pragma cling add_library_path");
      //if the function HandlePragmaHelper returned false,
      if (!Result.first)
        return;
      if (!Result.second.empty()) {
      // if HandlePragmaHelper returned success, this means that
      //it also returned the path to be included
        InvocationOptions& Opts = m_Interp.getOptions();
        Opts.LibSearchPath.push_back(Result.second);
      }
    }
  };
}

void cling::addClingPragmas(Interpreter& interp) {
  Preprocessor& PP = interp.getCI()->getPreprocessor();
  // PragmaNamespace / PP takes ownership of sub-handlers.
  PP.AddPragmaHandler("cling", new PHLoad(interp));
  PP.AddPragmaHandler("cling", new PHAddIncPath(interp));
  PP.AddPragmaHandler("cling", new PHAddLibraryPath(interp));
}
<commit_msg>Teach the pragma parser to parse non-string literals.<commit_after>//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "ClingPragmas.h"

#include "cling/Interpreter/Interpreter.h"
#include "cling/Utils/Output.h"
#include "cling/Utils/Paths.h"

#include "clang/AST/ASTContext.h"
#include "clang/Basic/TokenKinds.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/Token.h"
#include "clang/Parse/Parser.h"

#include <cstdlib>

using namespace cling;
using namespace clang;

namespace {
  typedef std::pair<bool, std::string> ParseResult_t;

  static ParseResult_t HandlePragmaHelper(Preprocessor &PP,
                                          const std::string &pragmaInst,
                                          bool stringLiteralArg = true) {
    struct SkipToEOD_t {
      Preprocessor& m_PP;
      SkipToEOD_t(Preprocessor& PParg): m_PP(PParg) {}
      ~SkipToEOD_t() { m_PP.DiscardUntilEndOfDirective(); }
    } SkipToEOD(PP);

    Token Tok;
    PP.Lex(Tok);
    if (Tok.isNot(tok::l_paren)) {
      cling::errs() << "cling::HandlePragmaHelper: expect '(' after #"
                    << pragmaInst << '\n';
      return ParseResult_t{false, ""};
    }
    std::string Literal;
    if (stringLiteralArg) {
      if (!PP.LexStringLiteral(Tok, Literal, pragmaInst.c_str(),
                               false /*allowMacroExpansion*/)) {
        // already diagnosed.
        return ParseResult_t {false, ""};
      }
      utils::ExpandEnvVars(Literal);
    } else {
      // integer literal
      PP.Lex(Tok);
      if (!Tok.isLiteral()) {
        cling::errs()
          << "cling::HandlePragmaHelper: expect integer literal after #"
          << pragmaInst << '\n';
        return ParseResult_t {false, ""};
      }
      Literal = std::string(Tok.getLiteralData(), Tok.getLength());
    }

    return ParseResult_t {true, Literal};
  }

  class PHLoad: public PragmaHandler {
    Interpreter& m_Interp;

  public:
    PHLoad(Interpreter& interp):
      PragmaHandler("load"), m_Interp(interp) {}

    void HandlePragma(Preprocessor &PP,
                      PragmaIntroducerKind Introducer,
                      Token &FirstToken) override {
      // TODO: use Diagnostics!
      ParseResult_t Result = HandlePragmaHelper(PP, "pragma cling load");

      if (!Result.first)
        return;
      if (Result.second.empty()) {
        cling::errs() << "Cannot load unnamed files.\n" ;
        return;
      }
      clang::Parser& P = m_Interp.getParser();
      Parser::ParserCurTokRestoreRAII savedCurToken(P);
      // After we have saved the token reset the current one to something which
      // is safe (semi colon usually means empty decl)
      Token& CurTok = const_cast<Token&>(P.getCurToken());
      CurTok.setKind(tok::semi);

      if (!m_Interp.isInSyntaxOnlyMode()) {
        // No need to load libraries if we're not executing anything.

        Preprocessor::CleanupAndRestoreCacheRAII cleanupRAII(PP);
        // We can't PushDeclContext, because we go up and the routine that pops
        // the DeclContext assumes that we drill down always.
        // We have to be on the global context. At that point we are in a
        // wrapper function so the parent context must be the global.
        TranslationUnitDecl* TU =
          m_Interp.getCI()->getASTContext().getTranslationUnitDecl();
        Sema::ContextAndScopeRAII pushedDCAndS(m_Interp.getSema(),
                                               TU, m_Interp.getSema().TUScope);
        Interpreter::PushTransactionRAII pushedT(&m_Interp);

        m_Interp.loadFile(Result.second, true /*allowSharedLib*/);
      }
    }
  };

  class PHAddIncPath: public PragmaHandler {
    Interpreter& m_Interp;

  public:
    PHAddIncPath(Interpreter& interp):
      PragmaHandler("add_include_path"), m_Interp(interp) {}

    void HandlePragma(Preprocessor &PP,
                      PragmaIntroducerKind Introducer,
                      Token &FirstToken) override {
      // TODO: use Diagnostics!
      ParseResult_t Result = HandlePragmaHelper(PP,
                                           "pragma cling add_include_path");
      //if the function HandlePragmaHelper returned false,
      if (!Result.first)
        return;
      if (!Result.second.empty())
        m_Interp.AddIncludePath(Result.second);
    }
  };

  class PHAddLibraryPath: public PragmaHandler {
    Interpreter& m_Interp;

  public:
    PHAddLibraryPath(Interpreter& interp):
      PragmaHandler("add_library_path"), m_Interp(interp) {}

    void HandlePragma(Preprocessor &PP,
                      PragmaIntroducerKind Introducer,
                      Token &FirstToken) override {
      // TODO: use Diagnostics!
      ParseResult_t Result = HandlePragmaHelper(PP,
                                         "pragma cling add_library_path");
      //if the function HandlePragmaHelper returned false,
      if (!Result.first)
        return;
      if (!Result.second.empty()) {
      // if HandlePragmaHelper returned success, this means that
      //it also returned the path to be included
        InvocationOptions& Opts = m_Interp.getOptions();
        Opts.LibSearchPath.push_back(Result.second);
      }
    }
  };
}

void cling::addClingPragmas(Interpreter& interp) {
  Preprocessor& PP = interp.getCI()->getPreprocessor();
  // PragmaNamespace / PP takes ownership of sub-handlers.
  PP.AddPragmaHandler("cling", new PHLoad(interp));
  PP.AddPragmaHandler("cling", new PHAddIncPath(interp));
  PP.AddPragmaHandler("cling", new PHAddLibraryPath(interp));
}
<|endoftext|>