<commit_before>// Copyright (C) 2013 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

#include <cmath>

#include "copasi.h"

#include "CLinkMatrix.h"

#include "CCopasiVector.h"

#include "blaswrap.h"
#include "clapackwrap.h"

#define DEBUG_MATRIX

CLinkMatrix::CLinkMatrix():
  CMatrix< C_FLOAT64 >(),
  mRowPivots(),
  mIndependent(0)
{}

CLinkMatrix::~CLinkMatrix()
{}

const CVector< size_t > & CLinkMatrix::getRowPivots() const
{
  return mRowPivots;
}

bool CLinkMatrix::build(const CMatrix< C_FLOAT64 > & matrix)
{
  bool success = true;

  CMatrix< C_FLOAT64 > M(matrix);

  C_INT NumCols = (C_INT) M.numCols();
  C_INT NumRows = (C_INT) M.numRows();
  C_INT LDA = std::max<C_INT>(1, NumCols);

  CVector< C_INT > JPVT(NumRows);
  JPVT = 0;

  C_INT32 Dim = std::min(NumCols, NumRows);

  if (Dim == 0)
    {
      C_INT32 i;
      mRowPivots.resize(NumRows);

      for (i = 0; i < NumRows; i++)
        mRowPivots[i] = i;

      resize(NumRows, 0);

      return success;
    }

  CVector< C_FLOAT64 > TAU(Dim);

  CVector< C_FLOAT64 > WORK(1);
  C_INT LWORK = -1;
  C_INT INFO;

  // QR factorization of the stoichiometry matrix
  /*
   *  -- LAPACK routine (version 3.0) --
   *     Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
   *     Courant Institute, Argonne National Lab, and Rice University
   *     June 30, 1999
   *
   *  Purpose
   *  =======
   *
   *  DGEQP3 computes a QR factorization with column pivoting of a
   *  matrix A:  A*P = Q*R  using Level 3 BLAS.
   *
   *  Arguments
   *  =========
   *
   *  M       (input) INTEGER
   *          The number of rows of the matrix A. M >= 0.
   *
   *  N       (input) INTEGER
   *          The number of columns of the matrix A.  N >= 0.
   *
   *  A       (input/output) DOUBLE PRECISION array, dimension (LDA,N)
   *          On entry, the M-by-N matrix A.
   *          On exit, the upper triangle of the array contains the
   *          min(M,N)-by-N upper trapezoidal matrix R; the elements below
   *          the diagonal, together with the array TAU, represent the
   *          orthogonal matrix Q as a product of min(M,N) elementary
   *          reflectors.
   *
   *  LDA     (input) INTEGER
   *          The leading dimension of the array A. LDA >= max(1,M).
   *
   *  JPVT    (input/output) INTEGER array, dimension (N)
   *          On entry, if JPVT(J).ne.0, the J-th column of A is permuted
   *          to the front of A*P (a leading column); if JPVT(J)=0,
   *          the J-th column of A is a free column.
   *          On exit, if JPVT(J)=K, then the J-th column of A*P was the
   *          the K-th column of A.
   *
   *  TAU     (output) DOUBLE PRECISION array, dimension (min(M,N))
   *          The scalar factors of the elementary reflectors.
   *
   *  WORK    (workspace/output) DOUBLE PRECISION array, dimension (LWORK)
   *          On exit, if INFO=0, WORK(1) returns the optimal LWORK.
   *
   *  LWORK   (input) INTEGER
   *          The dimension of the array WORK. LWORK >= 3*N+1.
   *          For optimal performance LWORK >= 2*N+(N+1)*NB, where NB
   *          is the optimal blocksize.
   *
   *          If LWORK = -1, then a workspace query is assumed; the routine
   *          only calculates the optimal size of the WORK array, returns
   *          this value as the first entry of the WORK array, and no error
   *          message related to LWORK is issued by XERBLA.
   *
   *  INFO    (output) INTEGER
   *          = 0: successful exit.
   *          < 0: if INFO = -i, the i-th argument had an illegal value.
   *
   *  Further Details
   *  ===============
   *
   *  The matrix Q is represented as a product of elementary reflectors
   *
   *     Q = H(1) H(2) . . . H(k), where k = min(m,n).
   *
   *  Each H(i) has the form
   *
   *     H(i) = I - tau * v * v'
   *
   *  where tau is a real/complex scalar, and v is a real/complex vector
   *  with v(1:i-1) = 0 and v(i) = 1; v(i+1:m) is stored on exit in
   *  A(i+1:m,i), and tau in TAU(i).
   *
   *  Based on contributions by
   *    G. Quintana-Orti, Depto. de Informatica, Universidad Jaime I, Spain
   *    X. Sun, Computer Science Dept., Duke University, USA
   *
   */

#ifdef DEBUG_MATRIX
  std::cout << CTransposeView< CMatrix< C_FLOAT64 > >(M) << std::endl;
#endif

  dgeqp3_(&NumCols, &NumRows, M.array(), &LDA,
          JPVT.array(), TAU.array(), WORK.array(), &LWORK, &INFO);

  if (INFO < 0) fatalError();

  LWORK = (C_INT) WORK[0];
  WORK.resize(LWORK);

  dgeqp3_(&NumCols, &NumRows, M.array(), &LDA,
          JPVT.array(), TAU.array(), WORK.array(), &LWORK, &INFO);

  if (INFO < 0) fatalError();

  C_INT32 i;
  mRowPivots.resize(NumRows);

  for (i = 0; i < NumRows; i++)
    mRowPivots[i] = JPVT[i] - 1;

#ifdef DEBUG_MATRIX
  std::cout << "QR Factorization:" << std::endl;
  std::cout << "Row permutation:\t" << mRowPivots << std::endl;
  std::cout << CTransposeView< CMatrix< C_FLOAT64 > >(M) << std::endl;
#endif

  C_INT independent = 0;

  while (independent < Dim &&
         fabs(M(independent, independent)) > 100.0 * std::numeric_limits< C_FLOAT64 >::epsilon()) independent++;

  mIndependent = independent;

  // Resize mL
  resize(NumRows - independent, independent);

  if (NumRows == independent || independent == 0)
    {
      return success;
    }

  /* to take care of differences between fortran's and c's memory  access,
       we need to take the transpose, i.e.,the upper triangular */
  char cL = 'U';
  char cU = 'N'; /* values in the diagonal of R */

  // Calculate Row Echelon form of R.
  // First invert R_1,1
  /* int dtrtri_(char *uplo,
   *             char *diag,
   *             integer *n,
   *             doublereal * A,
   *             integer *lda,
   *             integer *info);
   *  -- LAPACK routine (version 3.0) --
   *     Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
   *     Courant Institute, Argonne National Lab, and Rice University
   *     March 31, 1993
   *
   *  Purpose
   *  =======
   *
   *  DTRTRI computes the inverse of a real upper or lower triangular
   *  matrix A.
   *
   *  This is the Level 3 BLAS version of the algorithm.
   *
   *  Arguments
   *  =========
   *
   *  uplo    (input) CHARACTER*1
   *          = 'U':  A is upper triangular;
   *          = 'L':  A is lower triangular.
   *
   *  diag    (input) CHARACTER*1
   *          = 'N':  A is non-unit triangular;
   *          = 'U':  A is unit triangular.
   *
   *  n       (input) INTEGER
   *          The order of the matrix A.  n >= 0.
   *
   *  A       (input/output) DOUBLE PRECISION array, dimension (lda,n)
   *          On entry, the triangular matrix A.  If uplo = 'U', the
   *          leading n-by-n upper triangular part of the array A contains
   *          the upper triangular matrix, and the strictly lower
   *          triangular part of A is not referenced.  If uplo = 'L', the
   *          leading n-by-n lower triangular part of the array A contains
   *          the lower triangular matrix, and the strictly upper
   *          triangular part of A is not referenced.  If diag = 'U', the
   *          diagonal elements of A are also not referenced and are
   *          assumed to be 1.
   *          On exit, the (triangular) inverse of the original matrix, in
   *          the same storage format.
   *
   *  lda     (input) INTEGER
   *          The leading dimension of the array A.  lda >= max(1,n).
   *
   *  info    (output) INTEGER
   *          = 0: successful exit
   *          < 0: if info = -i, the i-th argument had an illegal value
   *          > 0: if info = i, A(i,i) is exactly zero.  The triangular
   *               matrix is singular and its inverse can not be computed.
   */
  dtrtri_(&cL, &cU, &independent, M.array(), &LDA, &INFO);

  if (INFO < 0) fatalError();

#ifdef DEBUG_MATRIX
  std::cout << "Invert R_1,1:" << std::endl;
  std::cout << CTransposeView< CMatrix< C_FLOAT64 > >(M) << std::endl;
#endif

  C_INT32 j, k;

  // Compute Link_0 = inverse(R_1,1) * R_1,2
  // :TODO: Use dgemm
  C_FLOAT64 * pTmp1 = array();
  C_FLOAT64 * pTmp2;
  C_FLOAT64 * pTmp3;

  for (j = 0; j < NumRows - independent; j++)
    for (i = 0; i < independent; i++, pTmp1++)
      {
        pTmp2 = &M(j + independent, i);
        pTmp3 = &M(i, i);

        // assert(&mL(j, i) == pTmp3);
        *pTmp1 = 0.0;

        for (k = i; k < independent; k++, pTmp2++, pTmp3 += NumCols)
          {
            // assert(&M(j + independent, k) == pTmp2);
            // assert(&M(k, i) == pTmp3);

            *pTmp1 += *pTmp3 * *pTmp2;
          }

        if (fabs(*pTmp1) < 100.0 * std::numeric_limits< C_FLOAT64 >::epsilon()) *pTmp1 = 0.0;
      }

#ifdef DEBUG_MATRIX
  std::cout << "Link Zero Matrix:" << std::endl;
  std::cout << *this << std::endl;
#endif // DEBUG_MATRIX

  return success;
}

const size_t & CLinkMatrix::getNumIndependent() const
{
  return mIndependent;
}

const size_t & CLinkMatrix::getNumDependent() const
{
  return numRows();
}

bool CLinkMatrix::applyRowPivot(CMatrix< C_FLOAT64 > & matrix) const
{
  if (matrix.numRows() < mRowPivots.size())
    {
      return false;
    }

  CVector< bool > Applied(mRowPivots.size());
  Applied = false;

  CVector< C_FLOAT64 > Tmp(matrix.numCols());

  size_t i, imax = mRowPivots.size();
  size_t to;
  size_t from;
  size_t numCols = matrix.numCols();

  for (i = 0; i < imax; i++)
    if (!Applied[i])
      {
        to = i;
        from = mRowPivots[to];

        if (from != i)
          {
            memcpy(Tmp.array(), matrix[to], sizeof(C_FLOAT64) * numCols);

            while (from != i)
              {
                memcpy(matrix[to], matrix[from], sizeof(C_FLOAT64) * numCols);
                Applied[to] = true;

                to = from;
                from = mRowPivots[to];
              }

            memcpy(matrix[to], Tmp.array(), sizeof(C_FLOAT64) * numCols);
          }

        Applied[to] = true;
      }

  return true;
}

//**********************************************************************
//                   CLinkMatrixView
//**********************************************************************

const C_FLOAT64 CLinkMatrixView::mZero = 0.0;
const C_FLOAT64 CLinkMatrixView::mUnit = 1.0;

CLinkMatrixView::CLinkMatrixView(const CLinkMatrix & A,
                                 const size_t & numIndependent):
  mpA(&A),
  mpNumIndependent(&numIndependent)
{CONSTRUCTOR_TRACE;}

CLinkMatrixView::~CLinkMatrixView()
{DESTRUCTOR_TRACE;}

CLinkMatrixView &
CLinkMatrixView::operator = (const CLinkMatrixView & rhs)
{
  mpA = rhs.mpA;
  mpNumIndependent = rhs.mpNumIndependent;

  return *this;
}

size_t CLinkMatrixView::numRows() const
{
  return *mpNumIndependent + mpA->numRows();
}

size_t CLinkMatrixView::numCols() const
{
  return mpA->numCols();
}

std::ostream &operator<<(std::ostream &os,
                         const CLinkMatrixView & A)
{
  size_t i, imax = A.numRows();
  size_t j, jmax = A.numCols();
  os << "Matrix(" << imax << "x" << jmax << ")" << std::endl;

  for (i = 0; i < imax; i++)
    {
      for (j = 0; j < jmax; j++)
        os << "\t" << A(i, j);

      os << std::endl;
    }

  return os;
}
<commit_msg>Disabled debug output.<commit_after>// Copyright (C) 2013 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

#include <cmath>

#include "copasi.h"

#include "CLinkMatrix.h"

#include "CCopasiVector.h"

#include "blaswrap.h"
#include "clapackwrap.h"

// Define to output debugging information
// #define DEBUG_MATRIX

CLinkMatrix::CLinkMatrix():
  CMatrix< C_FLOAT64 >(),
  mRowPivots(),
  mIndependent(0)
{}

CLinkMatrix::~CLinkMatrix()
{}

const CVector< size_t > & CLinkMatrix::getRowPivots() const
{
  return mRowPivots;
}

bool CLinkMatrix::build(const CMatrix< C_FLOAT64 > & matrix)
{
  bool success = true;

  CMatrix< C_FLOAT64 > M(matrix);

  C_INT NumCols = (C_INT) M.numCols();
  C_INT NumRows = (C_INT) M.numRows();
  C_INT LDA = std::max<C_INT>(1, NumCols);

  CVector< C_INT > JPVT(NumRows);
  JPVT = 0;

  C_INT32 Dim = std::min(NumCols, NumRows);

  if (Dim == 0)
    {
      C_INT32 i;
      mRowPivots.resize(NumRows);

      for (i = 0; i < NumRows; i++)
        mRowPivots[i] = i;

      resize(NumRows, 0);

      return success;
    }

  CVector< C_FLOAT64 > TAU(Dim);

  CVector< C_FLOAT64 > WORK(1);
  C_INT LWORK = -1;
  C_INT INFO;

  // QR factorization of the stoichiometry matrix
  /*
   *  -- LAPACK routine (version 3.0) --
   *     Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
   *     Courant Institute, Argonne National Lab, and Rice University
   *     June 30, 1999
   *
   *  Purpose
   *  =======
   *
   *  DGEQP3 computes a QR factorization with column pivoting of a
   *  matrix A:  A*P = Q*R  using Level 3 BLAS.
   *
   *  Arguments
   *  =========
   *
   *  M       (input) INTEGER
   *          The number of rows of the matrix A. M >= 0.
   *
   *  N       (input) INTEGER
   *          The number of columns of the matrix A.  N >= 0.
   *
   *  A       (input/output) DOUBLE PRECISION array, dimension (LDA,N)
   *          On entry, the M-by-N matrix A.
   *          On exit, the upper triangle of the array contains the
   *          min(M,N)-by-N upper trapezoidal matrix R; the elements below
   *          the diagonal, together with the array TAU, represent the
   *          orthogonal matrix Q as a product of min(M,N) elementary
   *          reflectors.
   *
   *  LDA     (input) INTEGER
   *          The leading dimension of the array A. LDA >= max(1,M).
   *
   *  JPVT    (input/output) INTEGER array, dimension (N)
   *          On entry, if JPVT(J).ne.0, the J-th column of A is permuted
   *          to the front of A*P (a leading column); if JPVT(J)=0,
   *          the J-th column of A is a free column.
   *          On exit, if JPVT(J)=K, then the J-th column of A*P was the
   *          the K-th column of A.
   *
   *  TAU     (output) DOUBLE PRECISION array, dimension (min(M,N))
   *          The scalar factors of the elementary reflectors.
   *
   *  WORK    (workspace/output) DOUBLE PRECISION array, dimension (LWORK)
   *          On exit, if INFO=0, WORK(1) returns the optimal LWORK.
   *
   *  LWORK   (input) INTEGER
   *          The dimension of the array WORK. LWORK >= 3*N+1.
   *          For optimal performance LWORK >= 2*N+(N+1)*NB, where NB
   *          is the optimal blocksize.
   *
   *          If LWORK = -1, then a workspace query is assumed; the routine
   *          only calculates the optimal size of the WORK array, returns
   *          this value as the first entry of the WORK array, and no error
   *          message related to LWORK is issued by XERBLA.
   *
   *  INFO    (output) INTEGER
   *          = 0: successful exit.
   *          < 0: if INFO = -i, the i-th argument had an illegal value.
   *
   *  Further Details
   *  ===============
   *
   *  The matrix Q is represented as a product of elementary reflectors
   *
   *     Q = H(1) H(2) . . . H(k), where k = min(m,n).
   *
   *  Each H(i) has the form
   *
   *     H(i) = I - tau * v * v'
   *
   *  where tau is a real/complex scalar, and v is a real/complex vector
   *  with v(1:i-1) = 0 and v(i) = 1; v(i+1:m) is stored on exit in
   *  A(i+1:m,i), and tau in TAU(i).
   *
   *  Based on contributions by
   *    G. Quintana-Orti, Depto. de Informatica, Universidad Jaime I, Spain
   *    X. Sun, Computer Science Dept., Duke University, USA
   *
   */

#ifdef DEBUG_MATRIX
  std::cout << CTransposeView< CMatrix< C_FLOAT64 > >(M) << std::endl;
#endif

  dgeqp3_(&NumCols, &NumRows, M.array(), &LDA,
          JPVT.array(), TAU.array(), WORK.array(), &LWORK, &INFO);

  if (INFO < 0) fatalError();

  LWORK = (C_INT) WORK[0];
  WORK.resize(LWORK);

  dgeqp3_(&NumCols, &NumRows, M.array(), &LDA,
          JPVT.array(), TAU.array(), WORK.array(), &LWORK, &INFO);

  if (INFO < 0) fatalError();

  C_INT32 i;
  mRowPivots.resize(NumRows);

  for (i = 0; i < NumRows; i++)
    mRowPivots[i] = JPVT[i] - 1;

#ifdef DEBUG_MATRIX
  std::cout << "QR Factorization:" << std::endl;
  std::cout << "Row permutation:\t" << mRowPivots << std::endl;
  std::cout << CTransposeView< CMatrix< C_FLOAT64 > >(M) << std::endl;
#endif

  C_INT independent = 0;

  while (independent < Dim &&
         fabs(M(independent, independent)) > 100.0 * std::numeric_limits< C_FLOAT64 >::epsilon()) independent++;

  mIndependent = independent;

  // Resize mL
  resize(NumRows - independent, independent);

  if (NumRows == independent || independent == 0)
    {
      return success;
    }

  /* to take care of differences between fortran's and c's memory  access,
       we need to take the transpose, i.e.,the upper triangular */
  char cL = 'U';
  char cU = 'N'; /* values in the diagonal of R */

  // Calculate Row Echelon form of R.
  // First invert R_1,1
  /* int dtrtri_(char *uplo,
   *             char *diag,
   *             integer *n,
   *             doublereal * A,
   *             integer *lda,
   *             integer *info);
   *  -- LAPACK routine (version 3.0) --
   *     Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
   *     Courant Institute, Argonne National Lab, and Rice University
   *     March 31, 1993
   *
   *  Purpose
   *  =======
   *
   *  DTRTRI computes the inverse of a real upper or lower triangular
   *  matrix A.
   *
   *  This is the Level 3 BLAS version of the algorithm.
   *
   *  Arguments
   *  =========
   *
   *  uplo    (input) CHARACTER*1
   *          = 'U':  A is upper triangular;
   *          = 'L':  A is lower triangular.
   *
   *  diag    (input) CHARACTER*1
   *          = 'N':  A is non-unit triangular;
   *          = 'U':  A is unit triangular.
   *
   *  n       (input) INTEGER
   *          The order of the matrix A.  n >= 0.
   *
   *  A       (input/output) DOUBLE PRECISION array, dimension (lda,n)
   *          On entry, the triangular matrix A.  If uplo = 'U', the
   *          leading n-by-n upper triangular part of the array A contains
   *          the upper triangular matrix, and the strictly lower
   *          triangular part of A is not referenced.  If uplo = 'L', the
   *          leading n-by-n lower triangular part of the array A contains
   *          the lower triangular matrix, and the strictly upper
   *          triangular part of A is not referenced.  If diag = 'U', the
   *          diagonal elements of A are also not referenced and are
   *          assumed to be 1.
   *          On exit, the (triangular) inverse of the original matrix, in
   *          the same storage format.
   *
   *  lda     (input) INTEGER
   *          The leading dimension of the array A.  lda >= max(1,n).
   *
   *  info    (output) INTEGER
   *          = 0: successful exit
   *          < 0: if info = -i, the i-th argument had an illegal value
   *          > 0: if info = i, A(i,i) is exactly zero.  The triangular
   *               matrix is singular and its inverse can not be computed.
   */
  dtrtri_(&cL, &cU, &independent, M.array(), &LDA, &INFO);

  if (INFO < 0) fatalError();

#ifdef DEBUG_MATRIX
  std::cout << "Invert R_1,1:" << std::endl;
  std::cout << CTransposeView< CMatrix< C_FLOAT64 > >(M) << std::endl;
#endif

  C_INT32 j, k;

  // Compute Link_0 = inverse(R_1,1) * R_1,2
  // :TODO: Use dgemm
  C_FLOAT64 * pTmp1 = array();
  C_FLOAT64 * pTmp2;
  C_FLOAT64 * pTmp3;

  for (j = 0; j < NumRows - independent; j++)
    for (i = 0; i < independent; i++, pTmp1++)
      {
        pTmp2 = &M(j + independent, i);
        pTmp3 = &M(i, i);

        // assert(&mL(j, i) == pTmp3);
        *pTmp1 = 0.0;

        for (k = i; k < independent; k++, pTmp2++, pTmp3 += NumCols)
          {
            // assert(&M(j + independent, k) == pTmp2);
            // assert(&M(k, i) == pTmp3);

            *pTmp1 += *pTmp3 * *pTmp2;
          }

        if (fabs(*pTmp1) < 100.0 * std::numeric_limits< C_FLOAT64 >::epsilon()) *pTmp1 = 0.0;
      }

#ifdef DEBUG_MATRIX
  std::cout << "Link Zero Matrix:" << std::endl;
  std::cout << *this << std::endl;
#endif // DEBUG_MATRIX

  return success;
}

const size_t & CLinkMatrix::getNumIndependent() const
{
  return mIndependent;
}

const size_t & CLinkMatrix::getNumDependent() const
{
  return numRows();
}

bool CLinkMatrix::applyRowPivot(CMatrix< C_FLOAT64 > & matrix) const
{
  if (matrix.numRows() < mRowPivots.size())
    {
      return false;
    }

  CVector< bool > Applied(mRowPivots.size());
  Applied = false;

  CVector< C_FLOAT64 > Tmp(matrix.numCols());

  size_t i, imax = mRowPivots.size();
  size_t to;
  size_t from;
  size_t numCols = matrix.numCols();

  for (i = 0; i < imax; i++)
    if (!Applied[i])
      {
        to = i;
        from = mRowPivots[to];

        if (from != i)
          {
            memcpy(Tmp.array(), matrix[to], sizeof(C_FLOAT64) * numCols);

            while (from != i)
              {
                memcpy(matrix[to], matrix[from], sizeof(C_FLOAT64) * numCols);
                Applied[to] = true;

                to = from;
                from = mRowPivots[to];
              }

            memcpy(matrix[to], Tmp.array(), sizeof(C_FLOAT64) * numCols);
          }

        Applied[to] = true;
      }

  return true;
}

//**********************************************************************
//                   CLinkMatrixView
//**********************************************************************

const C_FLOAT64 CLinkMatrixView::mZero = 0.0;
const C_FLOAT64 CLinkMatrixView::mUnit = 1.0;

CLinkMatrixView::CLinkMatrixView(const CLinkMatrix & A,
                                 const size_t & numIndependent):
  mpA(&A),
  mpNumIndependent(&numIndependent)
{CONSTRUCTOR_TRACE;}

CLinkMatrixView::~CLinkMatrixView()
{DESTRUCTOR_TRACE;}

CLinkMatrixView &
CLinkMatrixView::operator = (const CLinkMatrixView & rhs)
{
  mpA = rhs.mpA;
  mpNumIndependent = rhs.mpNumIndependent;

  return *this;
}

size_t CLinkMatrixView::numRows() const
{
  return *mpNumIndependent + mpA->numRows();
}

size_t CLinkMatrixView::numCols() const
{
  return mpA->numCols();
}

std::ostream &operator<<(std::ostream &os,
                         const CLinkMatrixView & A)
{
  size_t i, imax = A.numRows();
  size_t j, jmax = A.numCols();
  os << "Matrix(" << imax << "x" << jmax << ")" << std::endl;

  for (i = 0; i < imax; i++)
    {
      for (j = 0; j < jmax; j++)
        os << "\t" << A(i, j);

      os << std::endl;
    }

  return os;
}
<|endoftext|>


<commit_before>// Copyright (C) 2015 Elviss Strazdins
// This file is part of the Ouzel engine.

#include "Application.h"
#include <cmath>

using namespace std;

namespace ouzel
{
    Application::~Application()
    {
        Engine::getInstance()->getEventDispatcher()->removeEventHandler(_eventHandler);
    }

    Settings Application::getSettings()
    {
        Settings settings;
        settings.size = ouzel::Size2(800.0f, 600.0f);
        settings.resizable = true;

        return settings;
    }

    void Application::begin()
    {
        _eventHandler = make_shared<EventHandler>();

        _eventHandler->keyDownHandler = std::bind(&Application::handleKeyDown, this, std::placeholders::_1, std::placeholders::_2);
        _eventHandler->mouseMoveHandler = std::bind(&Application::handleMouseMove, this, std::placeholders::_1, std::placeholders::_2);
        _eventHandler->touchBeginHandler = std::bind(&Application::handleTouch, this, std::placeholders::_1, std::placeholders::_2);
        _eventHandler->touchMoveHandler = std::bind(&Application::handleTouch, this, std::placeholders::_1, std::placeholders::_2);
        _eventHandler->touchEndHandler = std::bind(&Application::handleTouch, this, std::placeholders::_1, std::placeholders::_2);
        _eventHandler->gamepadButtonChangeHandler = std::bind(&Application::handleGamepadButtonChange, this, std::placeholders::_1, std::placeholders::_2);

        Engine::getInstance()->getEventDispatcher()->addEventHandler(_eventHandler);

        Engine::getInstance()->getRenderer()->setClearColor(Color(64, 0, 0));
        Engine::getInstance()->getRenderer()->setTitle("Sample");

        ScenePtr scene = make_shared<Scene>();
        Engine::getInstance()->getSceneManager()->setScene(scene);

        _layer = make_shared<Layer>();
        scene->addLayer(_layer);

        _uiLayer = make_shared<Layer>();
        scene->addLayer(_uiLayer);

        DrawNodePtr drawNode = std::make_shared<DrawNode>();
        drawNode->rectangle(Rectangle(100.0f, 100.0f), Color(0, 128, 128, 255), true);
        drawNode->rectangle(Rectangle(100.0f, 100.0f), Color(255, 255, 255, 255), false);
        drawNode->line(Vector2(0.0f, 0.0f), Vector2(50.0f, 50.0f), Color(0, 255, 255, 255));
        drawNode->point(Vector2(75.0f, 75.0f), Color(255, 0, 0, 255));

        drawNode->circle(Vector2(75.0f, 75.0f), 20.0f, Color(0, 0, 255, 255));
        drawNode->circle(Vector2(25.0f, 75.0f), 20.0f, Color(0, 0, 255, 255), true);

        drawNode->setPosition(Vector2(-300, 0.0f));
        _layer->addChild(drawNode);

        _sprite = make_shared<Sprite>();
        _sprite->initFromFile("run.json");
        _sprite->play(true);
        _layer->addChild(_sprite);
        _sprite->setPosition(Vector2(-300.0f, 0.0f));

        std::vector<AnimatorPtr> sequence = {
            make_shared<MoveTo>(4.0f, Vector2(300.0f, 0.0f)),
            make_shared<FadeTo>(2.0f, 0.4f)
        };

        _sprite->animate(make_shared<Sequence>(sequence));

        SpritePtr fire = make_shared<Sprite>();
        fire->initFromFile("fire.json");
        fire->play(true);
        fire->setPosition(Vector2(-100.0f, -100.0f));
        _layer->addChild(fire);
        fire->animate(make_shared<FadeTo>(5.0f, 0.5f));

        _flame = make_shared<ParticleSystem>();
        _flame->initFromFile("flame.json");
        _layer->addChild(_flame);

        _witch = make_shared<Sprite>();
        _witch->initFromFile("witch.png");
        _witch->setPosition(Vector2(100.0f, 100.0f));
        _witch->setColor(Color(128, 0, 255, 255));
        _layer->addChild(_witch);
        _witch->animate(make_shared<Repeat>(make_shared<RotateTo>(1.0f, TAU), 3));

        LabelPtr label = make_shared<Label>("font.fnt", "testing fonts");
        _uiLayer->addChild(label);

        std::vector<AnimatorPtr> sequence2 = {
            make_shared<Animator>(1.0f), // delay
            make_shared<Ease>(make_shared<MoveTo>(2.0f, Vector2(0.0f, -240.0f)), Ease::Type::OUT, Ease::Func::BOUNCE)
        };

        label->animate(make_shared<Sequence>(sequence2));

        _button = make_shared<Button>();
        _button->init("button.png", "button.png", "button_down.png", "button_disabled.png", [this](VoidPtr sender) {
            _sprite->setVisible(!_sprite->isVisible());
        });
        _button->setPosition(Vector2(-200.0f, 200.0f));
        _uiLayer->addChild(_button);

        Engine::getInstance()->getInput()->startDiscovery();
    }

    bool Application::handleKeyDown(const KeyboardEvent& event, const VoidPtr& sender) const
    {
        Vector2 position = _layer->getCamera()->getPosition();

        switch (event.key)
        {
            case KeyboardKey::UP:
                position.y += 10.0f;
                break;
            case KeyboardKey::DOWN:
                position.y -= 10.0f;
                break;
            case KeyboardKey::LEFT:
                position.x -= 10.0f;
                break;
            case KeyboardKey::RIGHT:
                position.x += 10.0f;
                break;
            case KeyboardKey::SPACE:
                _witch->setVisible(!_witch->isVisible());
                break;
            case KeyboardKey::RETURN:
                Engine::getInstance()->getRenderer()->resize(Size2(640.0f, 480.0f));
                break;
            case KeyboardKey::TAB:
                _button->setEnabled(!_button->isEnabled());
                break;
            default:
                break;
        }

        _layer->getCamera()->setPosition(position);

        return true;
    }

    bool Application::handleMouseMove(const MouseEvent& event, const VoidPtr& sender) const
    {
        Vector2 worldLocation = _layer->screenToWorldLocation(event.position);
        _flame->setPosition(worldLocation);

        return true;
    }

    bool Application::handleTouch(const TouchEvent& event, const VoidPtr& sender) const
    {
        Vector2 worldLocation = _layer->screenToWorldLocation(event.position);
        _flame->setPosition(worldLocation);

        return true;
    }

    bool Application::handleGamepadButtonChange(const GamepadEvent& event, const VoidPtr& sender) const
    {
        Vector2 position = _layer->worldToScreenLocation(_flame->getPosition());

        switch (event.button)
        {
            case GamepadButton::DPAD_UP:
            case GamepadButton::LEFT_THUMB_UP:
            case GamepadButton::RIGHT_THUMB_UP:
                position.y = event.value;
                break;
            case GamepadButton::DPAD_DOWN:
            case GamepadButton::LEFT_THUMB_DOWN:
            case GamepadButton::RIGHT_THUMB_DOWN:
                position.y = -event.value;
                break;
            case GamepadButton::DPAD_LEFT:
            case GamepadButton::LEFT_THUMB_LEFT:
            case GamepadButton::RIGHT_THUMB_LEFT:
                position.x = -event.value;
                break;
            case GamepadButton::DPAD_RIGHT:
            case GamepadButton::LEFT_THUMB_RIGHT:
            case GamepadButton::RIGHT_THUMB_RIGHT:
                position.x = event.value;
                break;
            case GamepadButton::A:
                _witch->setVisible(!event.pressed);
                break;
            default:
                break;
        }

        Vector2 worldLocation = _layer->screenToWorldLocation(position);
        _flame->setPosition(worldLocation);

        return true;
    }
}
<commit_msg>Fix gamepad discovery code in the sample<commit_after>// Copyright (C) 2015 Elviss Strazdins
// This file is part of the Ouzel engine.

#include "Application.h"
#include <cmath>

using namespace std;

namespace ouzel
{
    Application::~Application()
    {
        Engine::getInstance()->getEventDispatcher()->removeEventHandler(_eventHandler);
    }

    Settings Application::getSettings()
    {
        Settings settings;
        settings.size = ouzel::Size2(800.0f, 600.0f);
        settings.resizable = true;

        return settings;
    }

    void Application::begin()
    {
        _eventHandler = make_shared<EventHandler>();

        _eventHandler->keyDownHandler = std::bind(&Application::handleKeyDown, this, std::placeholders::_1, std::placeholders::_2);
        _eventHandler->mouseMoveHandler = std::bind(&Application::handleMouseMove, this, std::placeholders::_1, std::placeholders::_2);
        _eventHandler->touchBeginHandler = std::bind(&Application::handleTouch, this, std::placeholders::_1, std::placeholders::_2);
        _eventHandler->touchMoveHandler = std::bind(&Application::handleTouch, this, std::placeholders::_1, std::placeholders::_2);
        _eventHandler->touchEndHandler = std::bind(&Application::handleTouch, this, std::placeholders::_1, std::placeholders::_2);
        _eventHandler->gamepadButtonChangeHandler = std::bind(&Application::handleGamepadButtonChange, this, std::placeholders::_1, std::placeholders::_2);

        Engine::getInstance()->getEventDispatcher()->addEventHandler(_eventHandler);

        Engine::getInstance()->getRenderer()->setClearColor(Color(64, 0, 0));
        Engine::getInstance()->getRenderer()->setTitle("Sample");

        ScenePtr scene = make_shared<Scene>();
        Engine::getInstance()->getSceneManager()->setScene(scene);

        _layer = make_shared<Layer>();
        scene->addLayer(_layer);

        _uiLayer = make_shared<Layer>();
        scene->addLayer(_uiLayer);

        DrawNodePtr drawNode = std::make_shared<DrawNode>();
        drawNode->rectangle(Rectangle(100.0f, 100.0f), Color(0, 128, 128, 255), true);
        drawNode->rectangle(Rectangle(100.0f, 100.0f), Color(255, 255, 255, 255), false);
        drawNode->line(Vector2(0.0f, 0.0f), Vector2(50.0f, 50.0f), Color(0, 255, 255, 255));
        drawNode->point(Vector2(75.0f, 75.0f), Color(255, 0, 0, 255));

        drawNode->circle(Vector2(75.0f, 75.0f), 20.0f, Color(0, 0, 255, 255));
        drawNode->circle(Vector2(25.0f, 75.0f), 20.0f, Color(0, 0, 255, 255), true);

        drawNode->setPosition(Vector2(-300, 0.0f));
        _layer->addChild(drawNode);

        _sprite = make_shared<Sprite>();
        _sprite->initFromFile("run.json");
        _sprite->play(true);
        _layer->addChild(_sprite);
        _sprite->setPosition(Vector2(-300.0f, 0.0f));

        std::vector<AnimatorPtr> sequence = {
            make_shared<MoveTo>(4.0f, Vector2(300.0f, 0.0f)),
            make_shared<FadeTo>(2.0f, 0.4f)
        };

        _sprite->animate(make_shared<Sequence>(sequence));

        SpritePtr fire = make_shared<Sprite>();
        fire->initFromFile("fire.json");
        fire->play(true);
        fire->setPosition(Vector2(-100.0f, -100.0f));
        _layer->addChild(fire);
        fire->animate(make_shared<FadeTo>(5.0f, 0.5f));

        _flame = make_shared<ParticleSystem>();
        _flame->initFromFile("flame.json");
        _layer->addChild(_flame);

        _witch = make_shared<Sprite>();
        _witch->initFromFile("witch.png");
        _witch->setPosition(Vector2(100.0f, 100.0f));
        _witch->setColor(Color(128, 0, 255, 255));
        _layer->addChild(_witch);
        _witch->animate(make_shared<Repeat>(make_shared<RotateTo>(1.0f, TAU), 3));

        LabelPtr label = make_shared<Label>("font.fnt", "testing fonts");
        _uiLayer->addChild(label);

        std::vector<AnimatorPtr> sequence2 = {
            make_shared<Animator>(1.0f), // delay
            make_shared<Ease>(make_shared<MoveTo>(2.0f, Vector2(0.0f, -240.0f)), Ease::Type::OUT, Ease::Func::BOUNCE)
        };

        label->animate(make_shared<Sequence>(sequence2));

        _button = make_shared<Button>();
        _button->init("button.png", "button.png", "button_down.png", "button_disabled.png", [this](VoidPtr sender) {
            _sprite->setVisible(!_sprite->isVisible());
        });
        _button->setPosition(Vector2(-200.0f, 200.0f));
        _uiLayer->addChild(_button);

        Engine::getInstance()->getInput()->startGamepadDiscovery();
    }

    bool Application::handleKeyDown(const KeyboardEvent& event, const VoidPtr& sender) const
    {
        Vector2 position = _layer->getCamera()->getPosition();

        switch (event.key)
        {
            case KeyboardKey::UP:
                position.y += 10.0f;
                break;
            case KeyboardKey::DOWN:
                position.y -= 10.0f;
                break;
            case KeyboardKey::LEFT:
                position.x -= 10.0f;
                break;
            case KeyboardKey::RIGHT:
                position.x += 10.0f;
                break;
            case KeyboardKey::SPACE:
                _witch->setVisible(!_witch->isVisible());
                break;
            case KeyboardKey::RETURN:
                Engine::getInstance()->getRenderer()->resize(Size2(640.0f, 480.0f));
                break;
            case KeyboardKey::TAB:
                _button->setEnabled(!_button->isEnabled());
                break;
            default:
                break;
        }

        _layer->getCamera()->setPosition(position);

        return true;
    }

    bool Application::handleMouseMove(const MouseEvent& event, const VoidPtr& sender) const
    {
        Vector2 worldLocation = _layer->screenToWorldLocation(event.position);
        _flame->setPosition(worldLocation);

        return true;
    }

    bool Application::handleTouch(const TouchEvent& event, const VoidPtr& sender) const
    {
        Vector2 worldLocation = _layer->screenToWorldLocation(event.position);
        _flame->setPosition(worldLocation);

        return true;
    }

    bool Application::handleGamepadButtonChange(const GamepadEvent& event, const VoidPtr& sender) const
    {
        Vector2 position = _layer->worldToScreenLocation(_flame->getPosition());

        switch (event.button)
        {
            case GamepadButton::DPAD_UP:
            case GamepadButton::LEFT_THUMB_UP:
            case GamepadButton::RIGHT_THUMB_UP:
                position.y = event.value;
                break;
            case GamepadButton::DPAD_DOWN:
            case GamepadButton::LEFT_THUMB_DOWN:
            case GamepadButton::RIGHT_THUMB_DOWN:
                position.y = -event.value;
                break;
            case GamepadButton::DPAD_LEFT:
            case GamepadButton::LEFT_THUMB_LEFT:
            case GamepadButton::RIGHT_THUMB_LEFT:
                position.x = -event.value;
                break;
            case GamepadButton::DPAD_RIGHT:
            case GamepadButton::LEFT_THUMB_RIGHT:
            case GamepadButton::RIGHT_THUMB_RIGHT:
                position.x = event.value;
                break;
            case GamepadButton::A:
                _witch->setVisible(!event.pressed);
                break;
            default:
                break;
        }

        Vector2 worldLocation = _layer->screenToWorldLocation(position);
        _flame->setPosition(worldLocation);

        return true;
    }
}
<|endoftext|>


<commit_before>/*

    Copyright Eli Dupree and Isaac Dupree, 2011, 2012

    This file is part of Lasercake.

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

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

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

*/

#include "specific_object_types.hpp"

// TODO HAAAAACK
#include "SDL/SDL.h"

struct beam_first_contact_finder : world_collision_detector::generalized_object_collection_handler {
  beam_first_contact_finder(world const& w, line_segment beam):w(w),beam(beam),best_intercept_point(false, 1){}
  world const& w;
  line_segment beam;
  std::pair<bool, boost::rational<int64_t>> best_intercept_point;
  unordered_set<object_or_tile_identifier> ignores;
  object_or_tile_identifier thing_hit;

  void handle_new_find(object_or_tile_identifier id) {
    if (ignores.find(id) != ignores.end()) return;

    // TODO : long beams, overflow?
    std::pair<bool, boost::rational<int64_t>> result = w.get_detail_shape_of_object_or_tile(id).first_intersection(beam);
    if (result.first) {
      if (!best_intercept_point.first || result.second < best_intercept_point.second) {
        best_intercept_point = result;
        thing_hit = id;
      }
    }
  }
  virtual bool should_be_considered__dynamic(bounding_box const& bb)const {
    std::pair<bool, boost::rational<int64_t>> result = shape(bb).first_intersection(beam);
    return result.first && (!best_intercept_point.first || result.second < best_intercept_point.second);
  }
  virtual bool bbox_ordering(bounding_box const& bb1, bounding_box const& bb2)const {
    // TODO do this in a more efficient way
    std::pair<bool, boost::rational<int64_t>> result1 = shape(bb1).first_intersection(beam);
    std::pair<bool, boost::rational<int64_t>> result2 = shape(bb2).first_intersection(beam);
    // Hack: This will never be relevant if the bools are false
    return (result1.second < result2.second);
  }
};

shape robot::get_initial_personal_space_shape()const {
  return shape(bounding_box(
    location - vector3<fine_scalar>(tile_width * 3 / 10, tile_width * 3 / 10, tile_width * 3 / 10),
    location + vector3<fine_scalar>(tile_width * 3 / 10, tile_width * 3 / 10, tile_width * 3 / 10)
  ));
}

shape robot::get_initial_detail_shape()const {
  return get_initial_personal_space_shape();
}

void robot::update(world &w, object_identifier my_id) {
  bounding_box shape_bounds = w.get_object_personal_space_shapes().find(my_id)->second.bounds();
  vector3<fine_scalar> bottom_middle(
    (shape_bounds.min.x + shape_bounds.max.x) / 2,
    (shape_bounds.min.y + shape_bounds.max.y) / 2,
    shape_bounds.min.z);
  const tile_location l = w.make_tile_location(get_containing_tile_coordinates(bottom_middle), CONTENTS_ONLY);
  const tile_location lminus = l.get_neighbor<zminus>(CONTENTS_ONLY);
  if (lminus.stuff_at().contents() != AIR) {
    // goal: decay towards levitating...
    fine_scalar target_height = (lower_bound_in_fine_units(l.coords().z, 2) + tile_height * 5 / 4);
    fine_scalar deficiency = target_height - shape_bounds.min.z;
    fine_scalar target_vel = gravity_acceleration_magnitude + deficiency * velocity_scale_factor / 8;
    if (velocity.z < target_vel) {
      velocity.z = std::min(velocity.z + gravity_acceleration_magnitude * 5, target_vel);
    }
  }

  // TODO HAAAAAACK
  Uint8 *keystate = SDL_GetKeyState(NULL);
  velocity.x -= velocity.x / 2;
  velocity.y -= velocity.y / 2;
  if (keystate[SDLK_UP]) {
    velocity.x = facing.x;
    velocity.y = facing.y;
  }
  if (keystate[SDLK_RIGHT]) {
    fine_scalar new_facing_x = facing.x + facing.y / 20;
    fine_scalar new_facing_y = facing.y - facing.x / 20;
    facing.x = new_facing_x; facing.y = new_facing_y;
  }
  if (keystate[SDLK_LEFT]) {
    fine_scalar new_facing_x = facing.x - facing.y / 20;
    fine_scalar new_facing_y = facing.y + facing.x / 20;
    facing.x = new_facing_x; facing.y = new_facing_y;
  }
  facing = facing * tile_width * velocity_scale_factor / 8 / facing.magnitude_within_32_bits();
}

shape laser_emitter::get_initial_personal_space_shape()const {
  return shape(bounding_box(
    location - vector3<fine_scalar>(tile_width * 4 / 10, tile_width * 4 / 10, tile_width * 4 / 10),
    location + vector3<fine_scalar>(tile_width * 4 / 10, tile_width * 4 / 10, tile_width * 4 / 10)
  ));
}

shape laser_emitter::get_initial_detail_shape()const {
  return get_initial_personal_space_shape();
}

void laser_emitter::update(world &w, object_identifier my_id) {
  bounding_box shape_bounds = w.get_object_personal_space_shapes().find(my_id)->second.bounds();
  vector3<fine_scalar> middle = (shape_bounds.min + shape_bounds.max) / 2;
  location = middle;
  do {
    facing.x = (rand()&2047) - 1024;
    facing.y = (rand()&2047) - 1024;
    facing.z = (rand()&2047) - 1024;
  } while (facing.magnitude_within_32_bits_is_greater_than(1023) || facing.magnitude_within_32_bits_is_less_than(512));
  facing = facing * tile_width * 2 / facing.magnitude_within_32_bits();

  beam_first_contact_finder finder(w, line_segment(location, location + facing * 50));
  finder.ignores.insert(my_id);
  w.get_things_exposed_to_collision().get_objects_generalized(&finder);

  if (finder.best_intercept_point.first) {
    // TODO do I have to worry about overflow?
    w.add_laser_sfx(location, facing * 50 * finder.best_intercept_point.second.numerator() / finder.best_intercept_point.second.denominator());
    if(tile_location const* locp = finder.thing_hit.get_tile_location()) {
      if (locp->stuff_at().contents() == ROCK) {
        w.replace_substance(*locp, ROCK, RUBBLE);
      }
    }
  }
  else {
    w.add_laser_sfx(location, facing * 50);
  }

  #if 0
  line_segment laser_line(location, location + facing);
  for (int i = 0; i < 50; ++i) {
    unordered_set<object_or_tile_identifier> possible_hits;
    w.collect_things_exposed_to_collision_intersecting(possible_hits, laser_line.bounds());
    std::pair<bool, boost::rational<int64_t> > best_inters(false, 0);
    object_or_tile_identifier best_id /*no default-constructor so pick something arbitrary*/ = my_id;
    for (object_or_tile_identifier const& id : possible_hits) {
      if (id != my_id) {
        shape other_shape = w.get_detail_shape_of_object_or_tile(id);
        std::pair<bool, boost::rational<int64_t> > inters = other_shape.first_intersection(laser_line);
        if (inters.first && (!best_inters.first || inters.second < best_inters.second)) {
          best_inters = inters;
          best_id = id;
        }
      }
    }

    if (best_inters.first) {
      // TODO do I have to worry about overflow?
      w.add_laser_sfx(location, facing * i + facing * best_inters.second.numerator() / best_inters.second.denominator());
      if(tile_location const* locp = best_id.get_tile_location()) {
        /*if(rand()%100 == 0) {
          w.replace_substance(*locp, locp->stuff_at().contents(), AIR);
        }*/
        if (locp->stuff_at().contents() == ROCK) {
          w.replace_substance(*locp, ROCK, RUBBLE);
        }
      }
      return;
    }
    laser_line.translate(facing);
  }
  w.add_laser_sfx(location, facing * 50);
  return;
  #endif

  /*struct laser_path_calculator {
    struct cross {
      fine_scalar dist_in_this_dimension;
      fine_scalar facing_in_this_dimension;
      int dimension;
      cross(fine_scalar d, fine_scalar f, int di):dist_in_this_dimension(d),facing_in_this_dimension(f),dimension(di){}
      bool operator<(cross const& other)const {
        return other.facing_in_this_dimension * dist_in_this_dimension < facing_in_this_dimension * other.dist_in_this_dimension;
      }
    };
    laser_path_calculator(laser_emitter *emi):emi(emi),current_laser_tile(get_containing_tile_coordinates(emi->location)){
      for (int i = 0; i < 3; ++i) {
        facing_signs[i] = sign(emi->facing[i]);
        facing_offs[i] = emi->facing[i] > 0;
        if (facing_signs[i] != 0) enter_next_cross(i);
      }
    }

    void enter_next_cross(int which_dimension) {
      coming_crosses.insert(cross(
        lower_bound_in_fine_units((current_laser_tile + facing_offs)[which_dimension], which_dimension) - emi->location[which_dimension],
        emi->facing[which_dimension],
        which_dimension
      ));
    }
    // returns which dimension we advanced
    int advance_to_next_location() {
      auto next_cross_iter = coming_crosses.begin();
      int which_dimension = next_cross_iter->dimension;
      coming_crosses.erase(next_cross_iter);
      current_laser_tile[which_dimension] += facing_signs[which_dimension];
      enter_next_cross(which_dimension);
      return which_dimension;
    }

    laser_emitter *emi;
    vector3<tile_coordinate> current_laser_tile;
    set<cross> coming_crosses;
    vector3<fine_scalar> facing_signs;
    vector3<tile_coordinate_signed_type> facing_offs;
  };

  laser_path_calculator calc(this);

  const vector3<fine_scalar> max_laser_delta = facing * 50;
  //const vector3<tile_coordinate> theoretical_end_tile = get_containing_tile_coordinates(location + max_laser_delta);

  int which_dimension_we_last_advanced = -1;
  while(true) {
    unordered_set<object_or_tile_identifier> possible_hits;
    w.collect_things_exposed_to_collision_intersecting(possible_hits, tile_bounding_box(calc.current_laser_tile));
    for (object_or_tile_identifier const& id : possible_hits) {
      if (id.get_tile_location()) {
        // it's the entire tile, of course we hit it!
        vector3<fine_scalar> laser_delta;
        if (which_dimension_we_last_advanced == -1) {
          laser_delta = vector3<fine_scalar>(0,0,0);
        }
        else {
          vector3<tile_coordinate> hitloc_finding_hack = calc.current_laser_tile;
          hitloc_finding_hack[which_dimension_we_last_advanced] += calc.facing_offs[which_dimension_we_last_advanced];
          const fine_scalar laser_delta_in_facing_direction = (lower_bound_in_fine_units(hitloc_finding_hack)[which_dimension_we_last_advanced] - location[which_dimension_we_last_advanced]);
          laser_delta = (facing * laser_delta_in_facing_direction) / facing[which_dimension_we_last_advanced];
        }
        w.add_laser_sfx(location, laser_delta);
        return; // TODO handle what happens if there are mobile objects and/or multiple objects and/or whatever
      }
      if (object_identifier const* oidp = id.get_object_identifier()) {
        shape const& their_shape = w.get_object_personal_space_shapes().find(*oidp)->second;
        if (their_shape)
      }
    }
    // TODO figure out a better end condition...
    if ((calc.current_laser_tile - get_containing_tile_coordinates(location)).magnitude_within_32_bits_is_greater_than(101)) {
      w.add_laser_sfx(location, max_laser_delta);
      return;
    }
    else which_dimension_we_last_advanced = calc.advance_to_next_location();
  }*/
}

<commit_msg>Allowed robots to look up and down. Controls now arrows to look, x to move.<commit_after>/*

    Copyright Eli Dupree and Isaac Dupree, 2011, 2012

    This file is part of Lasercake.

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

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

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

*/

#include "specific_object_types.hpp"

// TODO HAAAAACK
#include "SDL/SDL.h"

struct beam_first_contact_finder : world_collision_detector::generalized_object_collection_handler {
  beam_first_contact_finder(world const& w, line_segment beam):w(w),beam(beam),best_intercept_point(false, 1){}
  world const& w;
  line_segment beam;
  std::pair<bool, boost::rational<int64_t>> best_intercept_point;
  unordered_set<object_or_tile_identifier> ignores;
  object_or_tile_identifier thing_hit;

  void handle_new_find(object_or_tile_identifier id) {
    if (ignores.find(id) != ignores.end()) return;

    // TODO : long beams, overflow?
    std::pair<bool, boost::rational<int64_t>> result = w.get_detail_shape_of_object_or_tile(id).first_intersection(beam);
    if (result.first) {
      if (!best_intercept_point.first || result.second < best_intercept_point.second) {
        best_intercept_point = result;
        thing_hit = id;
      }
    }
  }
  virtual bool should_be_considered__dynamic(bounding_box const& bb)const {
    std::pair<bool, boost::rational<int64_t>> result = shape(bb).first_intersection(beam);
    return result.first && (!best_intercept_point.first || result.second < best_intercept_point.second);
  }
  virtual bool bbox_ordering(bounding_box const& bb1, bounding_box const& bb2)const {
    // TODO do this in a more efficient way
    std::pair<bool, boost::rational<int64_t>> result1 = shape(bb1).first_intersection(beam);
    std::pair<bool, boost::rational<int64_t>> result2 = shape(bb2).first_intersection(beam);
    // Hack: This will never be relevant if the bools are false
    return (result1.second < result2.second);
  }
};

shape robot::get_initial_personal_space_shape()const {
  return shape(bounding_box(
    location - vector3<fine_scalar>(tile_width * 3 / 10, tile_width * 3 / 10, tile_width * 3 / 10),
    location + vector3<fine_scalar>(tile_width * 3 / 10, tile_width * 3 / 10, tile_width * 3 / 10)
  ));
}

shape robot::get_initial_detail_shape()const {
  return get_initial_personal_space_shape();
}

void robot::update(world &w, object_identifier my_id) {
  bounding_box shape_bounds = w.get_object_personal_space_shapes().find(my_id)->second.bounds();
  vector3<fine_scalar> middle = (shape_bounds.min + shape_bounds.max) / 2;
  location = middle;
  vector3<fine_scalar> bottom_middle(middle.x, middle.y, shape_bounds.min.z);
  const tile_location l = w.make_tile_location(get_containing_tile_coordinates(bottom_middle), CONTENTS_ONLY);
  const tile_location lminus = l.get_neighbor<zminus>(CONTENTS_ONLY);
  if (lminus.stuff_at().contents() != AIR) {
    // goal: decay towards levitating...
    fine_scalar target_height = (lower_bound_in_fine_units(l.coords().z, 2) + tile_height * 5 / 4);
    fine_scalar deficiency = target_height - shape_bounds.min.z;
    fine_scalar target_vel = gravity_acceleration_magnitude + deficiency * velocity_scale_factor / 8;
    if (velocity.z < target_vel) {
      velocity.z = std::min(velocity.z + gravity_acceleration_magnitude * 5, target_vel);
    }
  }

  // TODO HAAAAAACK
  Uint8 *keystate = SDL_GetKeyState(NULL);
  velocity.x -= velocity.x / 2;
  velocity.y -= velocity.y / 2;
  const fine_scalar xymag = i64sqrt(facing.x*facing.x + facing.y*facing.y);
  if (keystate[SDLK_x]) {
    velocity.x = facing.x * tile_width * velocity_scale_factor / 8 / xymag;
    velocity.y = facing.y * tile_width * velocity_scale_factor / 8 / xymag;
  }
  if (keystate[SDLK_RIGHT]) {
    fine_scalar new_facing_x = facing.x + facing.y / 20;
    fine_scalar new_facing_y = facing.y - facing.x / 20;
    facing.x = new_facing_x; facing.y = new_facing_y;
  }
  if (keystate[SDLK_LEFT]) {
    fine_scalar new_facing_x = facing.x - facing.y / 20;
    fine_scalar new_facing_y = facing.y + facing.x / 20;
    facing.x = new_facing_x; facing.y = new_facing_y;
  }
  if (keystate[SDLK_UP] ^ keystate[SDLK_DOWN]) {
    const fine_scalar which_way = (keystate[SDLK_UP] ? 1 : -1);
    const fine_scalar new_xymag = xymag - (which_way * facing.z / 20);
    if (new_xymag > tile_width * velocity_scale_factor / 64) {
      facing.z += which_way * xymag / 20;
      facing.y = facing.y * new_xymag / xymag;
      facing.x = facing.x * new_xymag / xymag;
    }
  }
  facing = facing * tile_width * velocity_scale_factor / 8 / facing.magnitude_within_32_bits();
}

shape laser_emitter::get_initial_personal_space_shape()const {
  return shape(bounding_box(
    location - vector3<fine_scalar>(tile_width * 4 / 10, tile_width * 4 / 10, tile_width * 4 / 10),
    location + vector3<fine_scalar>(tile_width * 4 / 10, tile_width * 4 / 10, tile_width * 4 / 10)
  ));
}

shape laser_emitter::get_initial_detail_shape()const {
  return get_initial_personal_space_shape();
}

void laser_emitter::update(world &w, object_identifier my_id) {
  bounding_box shape_bounds = w.get_object_personal_space_shapes().find(my_id)->second.bounds();
  vector3<fine_scalar> middle = (shape_bounds.min + shape_bounds.max) / 2;
  location = middle;
  do {
    facing.x = (rand()&2047) - 1024;
    facing.y = (rand()&2047) - 1024;
    facing.z = (rand()&2047) - 1024;
  } while (facing.magnitude_within_32_bits_is_greater_than(1023) || facing.magnitude_within_32_bits_is_less_than(512));
  facing = facing * tile_width * 2 / facing.magnitude_within_32_bits();

  beam_first_contact_finder finder(w, line_segment(location, location + facing * 50));
  finder.ignores.insert(my_id);
  w.get_things_exposed_to_collision().get_objects_generalized(&finder);

  if (finder.best_intercept_point.first) {
    // TODO do I have to worry about overflow?
    w.add_laser_sfx(location, facing * 50 * finder.best_intercept_point.second.numerator() / finder.best_intercept_point.second.denominator());
    if(tile_location const* locp = finder.thing_hit.get_tile_location()) {
      if (locp->stuff_at().contents() == ROCK) {
        w.replace_substance(*locp, ROCK, RUBBLE);
      }
    }
  }
  else {
    w.add_laser_sfx(location, facing * 50);
  }

  #if 0
  line_segment laser_line(location, location + facing);
  for (int i = 0; i < 50; ++i) {
    unordered_set<object_or_tile_identifier> possible_hits;
    w.collect_things_exposed_to_collision_intersecting(possible_hits, laser_line.bounds());
    std::pair<bool, boost::rational<int64_t> > best_inters(false, 0);
    object_or_tile_identifier best_id /*no default-constructor so pick something arbitrary*/ = my_id;
    for (object_or_tile_identifier const& id : possible_hits) {
      if (id != my_id) {
        shape other_shape = w.get_detail_shape_of_object_or_tile(id);
        std::pair<bool, boost::rational<int64_t> > inters = other_shape.first_intersection(laser_line);
        if (inters.first && (!best_inters.first || inters.second < best_inters.second)) {
          best_inters = inters;
          best_id = id;
        }
      }
    }

    if (best_inters.first) {
      // TODO do I have to worry about overflow?
      w.add_laser_sfx(location, facing * i + facing * best_inters.second.numerator() / best_inters.second.denominator());
      if(tile_location const* locp = best_id.get_tile_location()) {
        /*if(rand()%100 == 0) {
          w.replace_substance(*locp, locp->stuff_at().contents(), AIR);
        }*/
        if (locp->stuff_at().contents() == ROCK) {
          w.replace_substance(*locp, ROCK, RUBBLE);
        }
      }
      return;
    }
    laser_line.translate(facing);
  }
  w.add_laser_sfx(location, facing * 50);
  return;
  #endif

  /*struct laser_path_calculator {
    struct cross {
      fine_scalar dist_in_this_dimension;
      fine_scalar facing_in_this_dimension;
      int dimension;
      cross(fine_scalar d, fine_scalar f, int di):dist_in_this_dimension(d),facing_in_this_dimension(f),dimension(di){}
      bool operator<(cross const& other)const {
        return other.facing_in_this_dimension * dist_in_this_dimension < facing_in_this_dimension * other.dist_in_this_dimension;
      }
    };
    laser_path_calculator(laser_emitter *emi):emi(emi),current_laser_tile(get_containing_tile_coordinates(emi->location)){
      for (int i = 0; i < 3; ++i) {
        facing_signs[i] = sign(emi->facing[i]);
        facing_offs[i] = emi->facing[i] > 0;
        if (facing_signs[i] != 0) enter_next_cross(i);
      }
    }

    void enter_next_cross(int which_dimension) {
      coming_crosses.insert(cross(
        lower_bound_in_fine_units((current_laser_tile + facing_offs)[which_dimension], which_dimension) - emi->location[which_dimension],
        emi->facing[which_dimension],
        which_dimension
      ));
    }
    // returns which dimension we advanced
    int advance_to_next_location() {
      auto next_cross_iter = coming_crosses.begin();
      int which_dimension = next_cross_iter->dimension;
      coming_crosses.erase(next_cross_iter);
      current_laser_tile[which_dimension] += facing_signs[which_dimension];
      enter_next_cross(which_dimension);
      return which_dimension;
    }

    laser_emitter *emi;
    vector3<tile_coordinate> current_laser_tile;
    set<cross> coming_crosses;
    vector3<fine_scalar> facing_signs;
    vector3<tile_coordinate_signed_type> facing_offs;
  };

  laser_path_calculator calc(this);

  const vector3<fine_scalar> max_laser_delta = facing * 50;
  //const vector3<tile_coordinate> theoretical_end_tile = get_containing_tile_coordinates(location + max_laser_delta);

  int which_dimension_we_last_advanced = -1;
  while(true) {
    unordered_set<object_or_tile_identifier> possible_hits;
    w.collect_things_exposed_to_collision_intersecting(possible_hits, tile_bounding_box(calc.current_laser_tile));
    for (object_or_tile_identifier const& id : possible_hits) {
      if (id.get_tile_location()) {
        // it's the entire tile, of course we hit it!
        vector3<fine_scalar> laser_delta;
        if (which_dimension_we_last_advanced == -1) {
          laser_delta = vector3<fine_scalar>(0,0,0);
        }
        else {
          vector3<tile_coordinate> hitloc_finding_hack = calc.current_laser_tile;
          hitloc_finding_hack[which_dimension_we_last_advanced] += calc.facing_offs[which_dimension_we_last_advanced];
          const fine_scalar laser_delta_in_facing_direction = (lower_bound_in_fine_units(hitloc_finding_hack)[which_dimension_we_last_advanced] - location[which_dimension_we_last_advanced]);
          laser_delta = (facing * laser_delta_in_facing_direction) / facing[which_dimension_we_last_advanced];
        }
        w.add_laser_sfx(location, laser_delta);
        return; // TODO handle what happens if there are mobile objects and/or multiple objects and/or whatever
      }
      if (object_identifier const* oidp = id.get_object_identifier()) {
        shape const& their_shape = w.get_object_personal_space_shapes().find(*oidp)->second;
        if (their_shape)
      }
    }
    // TODO figure out a better end condition...
    if ((calc.current_laser_tile - get_containing_tile_coordinates(location)).magnitude_within_32_bits_is_greater_than(101)) {
      w.add_laser_sfx(location, max_laser_delta);
      return;
    }
    else which_dimension_we_last_advanced = calc.advance_to_next_location();
  }*/
}

<|endoftext|>


<commit_before>#ifndef STATIC_LINK
#define IMPLEMENT_API
#endif

#if defined(HX_WINDOWS) || defined(HX_MACOS) || defined(HX_LINUX)
#define NEKO_COMPATIBLE
#endif

#include <hx/CFFI.h>
#include <hx/CFFIPrime.h>

#include "SamcodesChartboost.h"

using namespace samcodeschartboost;

#ifdef IPHONE

AutoGCRoot* chartboostEventHandle = 0;

void set_listener(value onEvent)
{
	if(chartboostEventHandle == 0) {
		chartboostEventHandle = new AutoGCRoot(onEvent);
	} else {
		chartboostEventHandle->set(onEvent);
	}
}
DEFINE_PRIME1v(samcodeschartboost_set_listener);

void show_interstitial(HxString location)
{
	showInterstitial(location.c_str());
}
DEFINE_PRIME1v(samcodeschartboost_show_interstitial);

void cache_interstitial(HxString location)
{
	cacheInterstitial(location.c_str());
}
DEFINE_PRIME1v(samcodeschartboost_cache_interstitial);

bool has_interstitial(HxString location)
{
	return hasInterstitial(location.c_str());
}
DEFINE_PRIME1(samcodeschartboost_has_interstitial);

void show_rewarded_video(HxString location)
{
	showRewardedVideo(location.c_str());
}
DEFINE_PRIME1v(samcodeschartboost_show_rewarded_video);

void cache_rewarded_video(HxString location)
{
	cacheRewardedVideo(location.c_str());
}
DEFINE_PRIME1v(samcodeschartboost_cache_rewarded_video);

bool has_rewarded_video(HxString location)
{
	return hasRewardedVideo(location.c_str());
}
DEFINE_PRIME1samcodeschartboost_(has_rewarded_video);

bool is_any_view_visible()
{
	return isAnyViewVisible();
}
DEFINE_PRIME0(samcodeschartboost_is_any_view_visible);

void set_custom_id(HxString id)
{
	setCustomId(id.c_str());
}
DEFINE_PRIME1v(samcodeschartboost_set_custom_id);

HxString get_custom_id()
{
	return HxString(getCustomId());
}
DEFINE_PRIME0(samcodeschartboost_get_custom_id);

void set_should_request_interstitials_in_first_session(bool shouldRequest)
{
	setShouldRequestInterstitialsInFirstSession(shouldRequest);
}
DEFINE_PRIME1v(samcodeschartboost_set_should_request_interstitials_in_first_session);

bool get_auto_cache_ads()
{
	return getAutoCacheAds();
}
DEFINE_PRIME0(samcodeschartboost_get_auto_cache_ads);

void set_auto_cache_ads(bool autoCache)
{
	setAutoCacheAds(autoCache);
}
DEFINE_PRIME1v(samcodeschartboost_set_auto_cache_ads);

void set_should_prefetch_video_content(bool shouldPrefetch)
{
	setShouldPrefetchVideoContent(shouldPrefetch);
}
DEFINE_PRIME1v(samcodeschartboost_set_should_prefetch_video_content);

HxString get_sdk_version()
{
	return HxString(getSDKVersion());
}
DEFINE_PRIME0(samcodeschartboost_get_sdk_version);

void set_status_bar_behavior(bool shouldHide)
{
	setStatusBarBehavior(shouldHide);
}
DEFINE_PRIME1v(samcodeschartboost_set_status_bar_behavior);

void set_muted(bool mute)
{
	setMuted(mute);
}
DEFINE_PRIME1v(samcodeschartboost_set_muted);

void restrict_data_collection(bool shouldRestrict)
{
	restrictDataCollection(shouldRestrict);
}
DEFINE_PRIME1v(samcodeschartboost_restrict_data_collection);

extern "C" void samcodeschartboost_main()
{
}
DEFINE_ENTRY_POINT(samcodeschartboost_main);

extern "C" int samcodeschartboost_register_prims()
{
	return 0;
}

extern "C" void sendChartboostEvent(const char* type, const char* location, const char* uri, int reward_coins, int error, bool status)
{
	if(chartboostEventHandle == 0)
	{
		return;
	}
	value o = alloc_empty_object();
	alloc_field(o, val_id("type"), alloc_string(type));
	alloc_field(o, val_id("location"), alloc_string(location));
	alloc_field(o, val_id("uri"), alloc_string(uri));
	alloc_field(o, val_id("reward_coins"), alloc_int(reward_coins));
	alloc_field(o, val_id("error"), alloc_int(error));
	alloc_field(o, val_id("status"), alloc_bool(status));
	val_call1(chartboostEventHandle->get(), o);
}

#endif
<commit_msg>More typos (about time I got a working mac)<commit_after>#ifndef STATIC_LINK
#define IMPLEMENT_API
#endif

#if defined(HX_WINDOWS) || defined(HX_MACOS) || defined(HX_LINUX)
#define NEKO_COMPATIBLE
#endif

#include <hx/CFFI.h>
#include <hx/CFFIPrime.h>

#include "SamcodesChartboost.h"

using namespace samcodeschartboost;

#ifdef IPHONE

AutoGCRoot* chartboostEventHandle = 0;

void samcodeschartboost_set_listener(value onEvent)
{
	if(chartboostEventHandle == 0) {
		chartboostEventHandle = new AutoGCRoot(onEvent);
	} else {
		chartboostEventHandle->set(onEvent);
	}
}
DEFINE_PRIME1v(samcodeschartboost_set_listener);

void samcodeschartboost_show_interstitial(HxString location)
{
	showInterstitial(location.c_str());
}
DEFINE_PRIME1v(samcodeschartboost_show_interstitial);

void samcodeschartboost_cache_interstitial(HxString location)
{
	cacheInterstitial(location.c_str());
}
DEFINE_PRIME1v(samcodeschartboost_cache_interstitial);

bool samcodeschartboost_has_interstitial(HxString location)
{
	return hasInterstitial(location.c_str());
}
DEFINE_PRIME1(samcodeschartboost_has_interstitial);

void samcodeschartboost_show_rewarded_video(HxString location)
{
	showRewardedVideo(location.c_str());
}
DEFINE_PRIME1v(samcodeschartboost_show_rewarded_video);

void samcodeschartboost_cache_rewarded_video(HxString location)
{
	cacheRewardedVideo(location.c_str());
}
DEFINE_PRIME1v(samcodeschartboost_cache_rewarded_video);

bool samcodeschartboost_has_rewarded_video(HxString location)
{
	return hasRewardedVideo(location.c_str());
}
DEFINE_PRIME1samcodeschartboost_(has_rewarded_video);

bool samcodeschartboost_is_any_view_visible()
{
	return isAnyViewVisible();
}
DEFINE_PRIME0(samcodeschartboost_is_any_view_visible);

void samcodeschartboost_set_custom_id(HxString id)
{
	setCustomId(id.c_str());
}
DEFINE_PRIME1v(samcodeschartboost_set_custom_id);

HxString samcodeschartboost_get_custom_id()
{
	return HxString(getCustomId());
}
DEFINE_PRIME0(samcodeschartboost_get_custom_id);

void samcodeschartboost_set_should_request_interstitials_in_first_session(bool shouldRequest)
{
	setShouldRequestInterstitialsInFirstSession(shouldRequest);
}
DEFINE_PRIME1v(samcodeschartboost_set_should_request_interstitials_in_first_session);

bool samcodeschartboost_get_auto_cache_ads()
{
	return getAutoCacheAds();
}
DEFINE_PRIME0(samcodeschartboost_get_auto_cache_ads);

void samcodeschartboost_set_auto_cache_ads(bool autoCache)
{
	setAutoCacheAds(autoCache);
}
DEFINE_PRIME1v(samcodeschartboost_set_auto_cache_ads);

void samcodeschartboost_set_should_prefetch_video_content(bool shouldPrefetch)
{
	setShouldPrefetchVideoContent(shouldPrefetch);
}
DEFINE_PRIME1v(samcodeschartboost_set_should_prefetch_video_content);

HxString samcodeschartboost_get_sdk_version()
{
	return HxString(getSDKVersion());
}
DEFINE_PRIME0(samcodeschartboost_get_sdk_version);

void samcodeschartboost_set_status_bar_behavior(bool shouldHide)
{
	setStatusBarBehavior(shouldHide);
}
DEFINE_PRIME1v(samcodeschartboost_set_status_bar_behavior);

void samcodeschartboost_set_muted(bool mute)
{
	setMuted(mute);
}
DEFINE_PRIME1v(samcodeschartboost_set_muted);

void restrict_data_collection(bool shouldRestrict)
{
	restrictDataCollection(shouldRestrict);
}
DEFINE_PRIME1v(samcodeschartboost_restrict_data_collection);

extern "C" void samcodeschartboost_main()
{
}
DEFINE_ENTRY_POINT(samcodeschartboost_main);

extern "C" int samcodeschartboost_register_prims()
{
	return 0;
}

extern "C" void sendChartboostEvent(const char* type, const char* location, const char* uri, int reward_coins, int error, bool status)
{
	if(chartboostEventHandle == 0)
	{
		return;
	}
	value o = alloc_empty_object();
	alloc_field(o, val_id("type"), alloc_string(type));
	alloc_field(o, val_id("location"), alloc_string(location));
	alloc_field(o, val_id("uri"), alloc_string(uri));
	alloc_field(o, val_id("reward_coins"), alloc_int(reward_coins));
	alloc_field(o, val_id("error"), alloc_int(error));
	alloc_field(o, val_id("status"), alloc_bool(status));
	val_call1(chartboostEventHandle->get(), o);
}

#endif
<|endoftext|>


<commit_before>// (c) 2015, dividiti
// BSD license

#ifndef CL_LAUNCHER_HPP
#define CL_LAUNCHER_HPP

#include <iostream>
#include <sstream>

#include <cstdlib>
#include <cassert>

#include <CL/cl.h>

#include <xopenme.h>

namespace gemmbench
{

class xopenme
{
private:
    static const int max_str_len = 1024;
    static const int max_tmr_count = 1;
    static const int max_var_count = 24;

public:

    char str[max_str_len];
    int  var_count;

    xopenme() : var_count(0)
    {
        xopenme_init(max_tmr_count, max_var_count);
    }

    ~xopenme()
    {
        xopenme_dump_state();
    }

    bool var_count_below_max()
    {
        return var_count < max_var_count;
    }
};

class arguments
{
public:
    std::string file;
    cl_uint platform_idx;
    cl_uint device_idx;

    arguments() : file(""), platform_idx(0), device_idx(0)
    { }

    void parse(int argc, char* argv[])
    {
        for (int i = 1; i < argc-1; ++i)
        {
            std::string this_arg(argv[i]);
            std::string next_arg(argv[++i]);

            if ("-f" == this_arg)
            {
                file = next_arg;
            }
            else if ("-p" == this_arg)
            {
                std::istringstream ss(next_arg); ss >> platform_idx;
            }
            else if ("-d" == this_arg)
            {
                std::istringstream ss(next_arg); ss >> device_idx;
            }
            else
            {
                std::cerr << "Unhandled argument: " << this_arg << std::endl;
                --i; // skip only one argument
            }
        } // END OF for each argument

    } // END OF parse()

}; // END OF class arguments

class state
{
private:
    arguments args;
    xopenme openme;

public:
    cl_platform_id platform;
    cl_device_id device;

    state() : platform(NULL), device(NULL)
    { }

    ~state()
    { }

    void parse_arguments(int argc, char* argv[])
    {
        args.parse(argc, argv);
    }

    void get_platform()
    {
        cl_uint err = CL_SUCCESS;

        cl_uint platform_idx = args.platform_idx;
        cl_uint num_entries = platform_idx+1;
        cl_platform_id * platforms = new cl_platform_id[num_entries];

        cl_uint num_platforms;
        err = clGetPlatformIDs(num_entries, platforms, &num_platforms);
        assert(CL_SUCCESS == err && "clGetPlatformIDs() failed.");
        assert(platform_idx < num_platforms && "No platform.");

        this->platform = platforms[platform_idx];
        delete [] platforms;

#if (1 == XOPENME)
        err = clGetPlatformInfo(platform, CL_PLATFORM_NAME,   sizeof(openme.str), &openme.str, NULL);
        assert(CL_SUCCESS == err && "clGetPlatformInfo() failed.");
        xopenme_add_var_s(openme.var_count++, (char*) "  \"CL_PLATFORM_NAME\":\"%s\"",    openme.str);
        assert(openme.var_count_below_max() && "xOpenME max var count reached.");

        err = clGetPlatformInfo(platform, CL_PLATFORM_VENDOR, sizeof(openme.str), &openme.str, NULL);
        assert(CL_SUCCESS == err && "clGetPlatformInfo() failed.");
        xopenme_add_var_s(openme.var_count++, (char*) "  \"CL_PLATFORM_VENDOR\":\"%s\"",  openme.str);
        assert(openme.var_count_below_max() && "xOpenME max var count reached.");

        err = clGetPlatformInfo(platform, CL_PLATFORM_VERSION, sizeof(openme.str), &openme.str, NULL);
        assert(CL_SUCCESS == err && "clGetPlatformInfo() failed.");
        xopenme_add_var_s(openme.var_count++, (char*) "  \"CL_PLATFORM_VERSION\":\"%s\"", openme.str);
        assert(openme.var_count_below_max() && "xOpenME max var count reached.");
#endif
    } // END OF get_platform()

    void get_device()
    {
        cl_uint err = CL_SUCCESS;

        cl_uint device_idx = args.device_idx;
        cl_uint num_entries = device_idx+1;
        cl_device_id * devices = new cl_device_id[num_entries];

        cl_uint num_devices;
        err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, num_entries, devices, &num_devices);
        assert(CL_SUCCESS == err && "clGetDeviceIDs() failed.");
        assert(device_idx < num_devices && "No device.");

        this->device = devices[device_idx];
        delete [] devices;

#if (1 == XOPENME)
        err = clGetDeviceInfo(device, CL_DEVICE_NAME, sizeof(openme.str),   &openme.str, NULL);
        assert(CL_SUCCESS == err && "clGetDeviceInfo() failed.");
        xopenme_add_var_s(openme.var_count++, (char*) "  \"CL_DEVICE_NAME\":\"%s\"",   openme.str);
        assert(openme.var_count_below_max() && "xOpenME max var count reached.");

        err = clGetDeviceInfo(device, CL_DEVICE_VENDOR, sizeof(openme.str), &openme.str, NULL);
        assert(CL_SUCCESS == err && "clGetDeviceInfo() failed.");
        xopenme_add_var_s(openme.var_count++, (char*) "  \"CL_DEVICE_VENDOR\":\"%s\"", openme.str);
        assert(openme.var_count_below_max() && "xOpenME max var count reached.");

        err = clGetDeviceInfo(device, CL_DEVICE_VERSION, sizeof(openme.str), &openme.str, NULL);
        assert(CL_SUCCESS == err && "clGetDeviceInfo() failed.");
        xopenme_add_var_s(openme.var_count++, (char*) "  \"CL_DEVICE_VERSION\":\"%s\"", openme.str);
        assert(openme.var_count_below_max() && "xOpenME max var count reached.");

        err = clGetDeviceInfo(device, CL_DRIVER_VERSION, sizeof(openme.str), &openme.str, NULL);
        assert(CL_SUCCESS == err && "clGetDeviceInfo() failed.");
        xopenme_add_var_s(openme.var_count++, (char*) "  \"CL_DRIVER_VERSION\":\"%s\"", openme.str);
        assert(openme.var_count_below_max() && "xOpenME max var count reached.");
#endif
    } // END OF get_device()

};

} // END OF namespace gemmbench

#endif // CL_LAUNCHER_HPP
<commit_msg>Device info parity with CLsmith launcher.<commit_after>// (c) 2015, dividiti
// BSD license

#ifndef CL_LAUNCHER_HPP
#define CL_LAUNCHER_HPP

#include <iostream>
#include <sstream>

#include <cstdlib>
#include <cassert>

#include <CL/cl.h>

#include <xopenme.h>

namespace gemmbench
{

class xopenme
{
private:
    static const int max_str_len = 1024;
    static const int max_tmr_count = 1;
    static const int max_var_count = 24;
    static const int max_work_dims = 3;

public:

    char str[max_str_len];
    int  var_count;

    cl_uint  tmp_uint;
    cl_ulong tmp_ulong;
    size_t   tmp_size_t;
    size_t   tmp_size_t_dims[max_work_dims];

    xopenme() :
        var_count(0),
        tmp_uint(0),
        tmp_ulong(0),
        tmp_size_t(0),
        tmp_size_t_dims() // C++11: {0, ..., 0}
    {
        assert(3 == max_work_dims);
        xopenme_init(max_tmr_count, max_var_count);
    }

    ~xopenme()
    {
        xopenme_dump_state();
    }

    bool var_count_below_max()
    {
        return var_count < max_var_count;
    }
};

class arguments
{
public:
    std::string file;
    cl_uint platform_idx;
    cl_uint device_idx;

    arguments() : file(""), platform_idx(0), device_idx(0)
    { }

    void parse(int argc, char* argv[])
    {
        for (int i = 1; i < argc-1; ++i)
        {
            std::string this_arg(argv[i]);
            std::string next_arg(argv[++i]);

            if ("-f" == this_arg)
            {
                file = next_arg;
            }
            else if ("-p" == this_arg)
            {
                std::istringstream ss(next_arg); ss >> platform_idx;
            }
            else if ("-d" == this_arg)
            {
                std::istringstream ss(next_arg); ss >> device_idx;
            }
            else
            {
                std::cerr << "Unhandled argument: " << this_arg << std::endl;
                --i; // skip only one argument
            }
        } // END OF for each argument

    } // END OF parse()

}; // END OF class arguments

class state
{
private:
    arguments args;
    xopenme openme;

public:
    cl_platform_id platform;
    cl_device_id device;

    state() : platform(NULL), device(NULL)
    { }

    ~state()
    { }

    void parse_arguments(int argc, char* argv[])
    {
        args.parse(argc, argv);
    }

    void get_platform()
    {
        cl_uint err = CL_SUCCESS;

        cl_uint platform_idx = args.platform_idx;
        cl_uint num_entries = platform_idx+1;
        cl_platform_id * platforms = new cl_platform_id[num_entries];

        cl_uint num_platforms;
        err = clGetPlatformIDs(num_entries, platforms, &num_platforms);
        assert(CL_SUCCESS == err && "clGetPlatformIDs() failed.");
        assert(platform_idx < num_platforms && "No platform.");

        this->platform = platforms[platform_idx];
        delete [] platforms;

#if (1 == XOPENME)
        err = clGetPlatformInfo(platform, CL_PLATFORM_NAME,   sizeof(openme.str), &openme.str, NULL);
        assert(CL_SUCCESS == err && "clGetPlatformInfo() failed.");
        xopenme_add_var_s(openme.var_count++, (char*) "  \"CL_PLATFORM_NAME\":\"%s\"",    openme.str);
        assert(openme.var_count_below_max() && "xOpenME max var count reached.");

        err = clGetPlatformInfo(platform, CL_PLATFORM_VENDOR, sizeof(openme.str), &openme.str, NULL);
        assert(CL_SUCCESS == err && "clGetPlatformInfo() failed.");
        xopenme_add_var_s(openme.var_count++, (char*) "  \"CL_PLATFORM_VENDOR\":\"%s\"",  openme.str);
        assert(openme.var_count_below_max() && "xOpenME max var count reached.");

        err = clGetPlatformInfo(platform, CL_PLATFORM_VERSION, sizeof(openme.str), &openme.str, NULL);
        assert(CL_SUCCESS == err && "clGetPlatformInfo() failed.");
        xopenme_add_var_s(openme.var_count++, (char*) "  \"CL_PLATFORM_VERSION\":\"%s\"", openme.str);
        assert(openme.var_count_below_max() && "xOpenME max var count reached.");
#endif
    } // END OF get_platform()

    void get_device()
    {
        cl_uint err = CL_SUCCESS;

        cl_uint device_idx = args.device_idx;
        cl_uint num_entries = device_idx+1;
        cl_device_id * devices = new cl_device_id[num_entries];

        cl_uint num_devices;
        err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, num_entries, devices, &num_devices);
        assert(CL_SUCCESS == err && "clGetDeviceIDs() failed.");
        assert(device_idx < num_devices && "No device.");

        this->device = devices[device_idx];
        delete [] devices;

#if (1 == XOPENME)
        err = clGetDeviceInfo(device, CL_DEVICE_NAME, sizeof(openme.str),   &openme.str, NULL);
        assert(CL_SUCCESS == err && "clGetDeviceInfo() failed.");
        xopenme_add_var_s(openme.var_count++, (char*) "  \"CL_DEVICE_NAME\":\"%s\"",   openme.str);
        assert(openme.var_count_below_max() && "xOpenME max var count reached.");

        err = clGetDeviceInfo(device, CL_DEVICE_VENDOR, sizeof(openme.str), &openme.str, NULL);
        assert(CL_SUCCESS == err && "clGetDeviceInfo() failed.");
        xopenme_add_var_s(openme.var_count++, (char*) "  \"CL_DEVICE_VENDOR\":\"%s\"", openme.str);
        assert(openme.var_count_below_max() && "xOpenME max var count reached.");

        err = clGetDeviceInfo(device, CL_DEVICE_VERSION, sizeof(openme.str), &openme.str, NULL);
        assert(CL_SUCCESS == err && "clGetDeviceInfo() failed.");
        xopenme_add_var_s(openme.var_count++, (char*) "  \"CL_DEVICE_VERSION\":\"%s\"", openme.str);
        assert(openme.var_count_below_max() && "xOpenME max var count reached.");

        err = clGetDeviceInfo(device, CL_DRIVER_VERSION, sizeof(openme.str), &openme.str, NULL);
        assert(CL_SUCCESS == err && "clGetDeviceInfo() failed.");
        xopenme_add_var_s(openme.var_count++, (char*) "  \"CL_DRIVER_VERSION\":\"%s\"", openme.str);
        assert(openme.var_count_below_max() && "xOpenME max var count reached.");

        err = clGetDeviceInfo(device, CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(cl_uint), &openme.tmp_uint, NULL);
        assert(CL_SUCCESS == err && "clGetDeviceInfo() failed.");
        xopenme_add_var_i(openme.var_count++, (char*) "  \"CL_DEVICE_MAX_COMPUTE_UNITS\":%u", openme.tmp_uint);
        assert(openme.var_count_below_max() && "xOpenME max var count reached.");

        err = clGetDeviceInfo(device, CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof(cl_uint), &openme.tmp_uint, NULL);
        assert(CL_SUCCESS == err && "clGetDeviceInfo() failed.");
        xopenme_add_var_i(openme.var_count++, (char*) "  \"CL_DEVICE_MAX_CLOCK_FREQUENCY\":%u", openme.tmp_uint);
        assert(openme.var_count_below_max() && "xOpenME max var count reached.");

        err = clGetDeviceInfo(device, CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(cl_ulong), &openme.tmp_ulong, NULL);
        assert(CL_SUCCESS == err && "clGetDeviceInfo() failed.");
        xopenme_add_var_i(openme.var_count++, (char*) "  \"CL_DEVICE_GLOBAL_MEM_SIZE\":%u", openme.tmp_ulong);
        assert(openme.var_count_below_max() && "xOpenME max var count reached.");

        err = clGetDeviceInfo(device, CL_DEVICE_LOCAL_MEM_SIZE, sizeof(cl_ulong), &openme.tmp_ulong, NULL);
        assert(CL_SUCCESS == err && "clGetDeviceInfo() failed.");
        xopenme_add_var_i(openme.var_count++, (char*) "  \"CL_DEVICE_LOCAL_MEM_SIZE\":%u", openme.tmp_ulong);
        assert(openme.var_count_below_max() && "xOpenME max var count reached.");

        err = clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(size_t), &openme.tmp_size_t, NULL);
        assert(CL_SUCCESS == err && "clGetDeviceInfo() failed.");
        xopenme_add_var_i(openme.var_count++, (char*) "  \"CL_DEVICE_MAX_WORK_GROUP_SIZE\":%u", openme.tmp_size_t);
        assert(openme.var_count_below_max() && "xOpenME max var count reached.");

        err = clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, sizeof(size_t), &openme.tmp_size_t, NULL);
        assert(CL_SUCCESS == err && "clGetDeviceInfo() failed.");
        xopenme_add_var_i(openme.var_count++, (char*) "  \"CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS\":%u", openme.tmp_size_t);
        assert(openme.tmp_size_t == 3 && "CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS != 3");
        assert(openme.var_count_below_max() && "xOpenME max var count reached.");

        err = clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(openme.tmp_size_t_dims), openme.tmp_size_t_dims, NULL);
        assert(CL_SUCCESS == err && "clGetDeviceInfo() failed.");
        xopenme_add_var_i(openme.var_count++, (char*) "  \"CL_DEVICE_MAX_WORK_ITEM_SIZES_0\":%u", openme.tmp_size_t_dims[0]);
        xopenme_add_var_i(openme.var_count++, (char*) "  \"CL_DEVICE_MAX_WORK_ITEM_SIZES_1\":%u", openme.tmp_size_t_dims[1]);
        xopenme_add_var_i(openme.var_count++, (char*) "  \"CL_DEVICE_MAX_WORK_ITEM_SIZES_2\":%u", openme.tmp_size_t_dims[2]);
#endif

    } // END OF get_device()

};

} // END OF namespace gemmbench

#endif // CL_LAUNCHER_HPP
<|endoftext|>