<commit_before>// $Id$
//
//  Copyright (C) 2007-2008 Greg Landrum
//
//   @@ All Rights Reserved  @@
//
#include <RDBoost/Wrap.h>
#include <GraphMol/Atom.h>
#include <GraphMol/GraphMol.h>

#include <GraphMol/Descriptors/MolDescriptors.h>
#include <GraphMol/Descriptors/AtomPairs.h>
#include <GraphMol/Fingerprints/MorganFingerprints.h>

#include <vector>

namespace python = boost::python;

namespace {
  std::vector<unsigned int> atomPairTypes(RDKit::Descriptors::AtomPairs::atomNumberTypes,
					  RDKit::Descriptors::AtomPairs::atomNumberTypes+sizeof(RDKit::Descriptors::AtomPairs::atomNumberTypes)/sizeof(unsigned int));
  python::tuple computeASAContribs(const RDKit::ROMol &mol,bool includeHs=true,
				   bool force=false){
    std::vector<double> contribs(mol.getNumAtoms());
    double hContrib=0.0;
    RDKit::Descriptors::getLabuteAtomContribs(mol,contribs,hContrib,includeHs,force);
    python::tuple pycontribs(contribs);
    return python::make_tuple(contribs,hContrib);
  }
  python::list computeCrippenContribs(const RDKit::ROMol &mol,
				       bool force=false){
    std::vector<double> logpContribs(mol.getNumAtoms());
    std::vector<double> mrContribs(mol.getNumAtoms());

    RDKit::Descriptors::getCrippenAtomContribs(mol,logpContribs,mrContribs,force);
    python::list pycontribs;
    for(unsigned int i=0;i<mol.getNumAtoms();++i){
      pycontribs.append(python::make_tuple(logpContribs[i],mrContribs[i]));
    }
    return pycontribs;
  }
  python::tuple calcCrippenDescriptors(const RDKit::ROMol &mol,bool includeHs=true,
				       bool force=false){
    double logp,mr;
    RDKit::Descriptors::CalcCrippenDescriptors(mol,logp,mr,includeHs,force);
    return python::make_tuple(logp,mr);
  }

  RDKit::SparseIntVect<boost::int32_t> *GetAtomPairFingerprint(const RDKit::ROMol &mol,
                                                               unsigned int minLength,
                                                               unsigned int maxLength,
                                                               python::object fromAtoms){
    std::vector<boost::uint32_t> *vect=0;
    if(fromAtoms){
      vect = new std::vector<boost::uint32_t>;
      unsigned int nFrom=python::extract<unsigned int>(fromAtoms.attr("__len__")());
      for(unsigned int i=0;i<nFrom;++i){
        boost::uint32_t v=python::extract<boost::uint32_t>(fromAtoms[i]);
        if(v>=mol.getNumAtoms()){
          throw_value_error("atom index specified that is larger than the number of atoms");
        }
        vect->push_back(v);
      }
    }

    RDKit::SparseIntVect<boost::int32_t> *res;
    res = RDKit::Descriptors::AtomPairs::getAtomPairFingerprint(mol,minLength,maxLength,
                                                                vect);
    if(vect) delete vect;
    return res;
  }

  RDKit::SparseIntVect<boost::int64_t> *GetTopologicalTorsionFingerprint(const RDKit::ROMol &mol,
                                                                         unsigned int targetSize,
                                                                         python::object fromAtoms){
    std::vector<boost::uint32_t> *vect=0;
    if(fromAtoms){
      vect = new std::vector<boost::uint32_t>;
      unsigned int nFrom=python::extract<unsigned int>(fromAtoms.attr("__len__")());
      for(unsigned int i=0;i<nFrom;++i){
        boost::uint32_t v=python::extract<boost::uint32_t>(fromAtoms[i]);
        if(v>=mol.getNumAtoms()){
          throw_value_error("atom index specified that is larger than the number of atoms");
        }
        vect->push_back(v);
      }
    }

    if(targetSize*RDKit::Descriptors::AtomPairs::codeSize>64){
      std::ostringstream errout;
      errout << "Maximum supported topological torsion path length is " << 64/RDKit::Descriptors::AtomPairs::codeSize<<std::endl;
      throw_value_error(errout.str());
    }

    RDKit::SparseIntVect<boost::int64_t> *res;
    res = RDKit::Descriptors::AtomPairs::getTopologicalTorsionFingerprint(mol,targetSize,vect);
    if(vect) delete vect;
    return res;
  }

  RDKit::SparseIntVect<boost::int64_t> *GetHashedTopologicalTorsionFingerprint(const RDKit::ROMol &mol,
                                                                               unsigned int nBits,
                                                                         unsigned int targetSize,
                                                                         python::object fromAtoms){
    std::vector<boost::uint32_t> *vect=0;
    if(fromAtoms){
      vect = new std::vector<boost::uint32_t>;
      unsigned int nFrom=python::extract<unsigned int>(fromAtoms.attr("__len__")());
      for(unsigned int i=0;i<nFrom;++i){
        boost::uint32_t v=python::extract<boost::uint32_t>(fromAtoms[i]);
        if(v>=mol.getNumAtoms()){
          throw_value_error("atom index specified that is larger than the number of atoms");
        }
        vect->push_back(v);
      }
    }
    RDKit::SparseIntVect<boost::int64_t> *res;
    res = RDKit::Descriptors::AtomPairs::getHashedTopologicalTorsionFingerprint(mol,nBits,targetSize,vect);
    if(vect) delete vect;
    return res;
  }

  RDKit::SparseIntVect<boost::uint32_t> *GetMorganFingerprint(const RDKit::ROMol &mol,
                                                              int radius,
                                                              python::object invariants,
                                                              python::object fromAtoms){
    std::vector<boost::uint32_t> *invars=0;
    if(invariants){
      unsigned int nInvar=python::extract<unsigned int>(invariants.attr("__len__")());
      if(nInvar){
        if(nInvar!=mol.getNumAtoms()){
          throw_value_error("length of invariant vector != number of atoms");
        }
        invars = new std::vector<boost::uint32_t>(mol.getNumAtoms());
        for(unsigned int i=0;i<mol.getNumAtoms();++i){
          (*invars)[i] = python::extract<boost::uint32_t>(invariants[i]);
        }
      }
    }
    std::vector<boost::uint32_t> *froms=0;
    if(fromAtoms){
      unsigned int nFrom=python::extract<unsigned int>(fromAtoms.attr("__len__")());
      if(nFrom){
        froms = new std::vector<boost::uint32_t>();
        for(unsigned int i=0;i<nFrom;++i){
          froms->push_back(python::extract<boost::uint32_t>(fromAtoms[i]));
        }
      }
    }
    RDKit::SparseIntVect<boost::uint32_t> *res;
    res = RDKit::MorganFingerprints::getFingerprint(mol,
                                                    static_cast<unsigned int>(radius),
                                                    invars,froms);
    if(invars) delete invars;
    if(froms) delete froms;
    return res;
  }

}

BOOST_PYTHON_MODULE(rdMolDescriptors) {
  python::scope().attr("__doc__") =
    "Module containing functions to compute molecular descriptors"
    ;

  python::register_exception_translator<IndexErrorException>(&translate_index_error);
  python::register_exception_translator<ValueErrorException>(&translate_value_error);

  std::string docString = "";

  python::class_<python::object>("AtomPairsParameters")
    .def_readonly("version",
		  RDKit::Descriptors::AtomPairs::atomPairsVersion)
    .def_readonly("numTypeBits",
		  RDKit::Descriptors::AtomPairs::numTypeBits)
    .def_readonly("numPiBits",
		  RDKit::Descriptors::AtomPairs::numPiBits)
    .def_readonly("numBranchBits",
		  RDKit::Descriptors::AtomPairs::numBranchBits)
    .def_readonly("codeSize",
		  RDKit::Descriptors::AtomPairs::codeSize)
    .def_readonly("atomTypes",
		  atomPairTypes)
    .def_readonly("numPathBits",
		  RDKit::Descriptors::AtomPairs::numPathBits)
    .def_readonly("numAtomPairFingerprintBits",
		  RDKit::Descriptors::AtomPairs::numAtomPairFingerprintBits)
    ;
  docString="Returns the atom code (hash) for an atom";
  python::def("GetAtomPairAtomCode", RDKit::Descriptors::AtomPairs::getAtomCode,
              (python::arg("atom"), python::arg("branchSubtract")=0),
              docString.c_str());
  docString="Returns the atom-pair fingerprint for a molecule as an IntSparseIntVect";
  python::def("GetAtomPairFingerprint", GetAtomPairFingerprint,
              (python::arg("mol"),
               python::arg("minLength")=1,
               python::arg("maxLength")=RDKit::Descriptors::AtomPairs::maxPathLen-1,
               python::arg("fromAtoms")=python::list()),
              docString.c_str(),
              python::return_value_policy<python::manage_new_object>());

  python::def("GetHashedAtomPairFingerprint",
	      (RDKit::SparseIntVect<boost::int32_t> *(*)(const RDKit::ROMol&,unsigned int,unsigned int,unsigned int))RDKit::Descriptors::AtomPairs::getHashedAtomPairFingerprint,
	      (python::arg("mol"),
               python::arg("nBits")=2048,
               python::arg("minLength")=1,
               python::arg("maxLength")=RDKit::Descriptors::AtomPairs::maxPathLen-1),
              docString.c_str(),
	      python::return_value_policy<python::manage_new_object>());
  docString="Returns the topological-torsion fingerprint for a molecule as a LongIntSparseIntVect";
  python::def("GetTopologicalTorsionFingerprint",
	      GetTopologicalTorsionFingerprint,
	      (python::arg("mol"),python::arg("targetSize")=4,
               python::arg("fromAtoms")=0),
              docString.c_str(),
	      python::return_value_policy<python::manage_new_object>());
  python::def("GetHashedTopologicalTorsionFingerprint",
	      GetHashedTopologicalTorsionFingerprint,
	      (python::arg("mol"),
               python::arg("nBits")=2048,
               python::arg("targetSize")=4,
               python::arg("fromAtoms")=0),
              docString.c_str(),
	      python::return_value_policy<python::manage_new_object>());

  docString="Returns a Morgan fingerprint for a molecule";
  python::def("GetMorganFingerprint", GetMorganFingerprint,
              (python::arg("mol"),python::arg("radius"),
               python::arg("invariants")=python::list(),
               python::arg("fromAtoms")=python::list()),
              docString.c_str(),
              python::return_value_policy<python::manage_new_object>());
  python::scope().attr("__MorganFingerprint_version__")=
    RDKit::MorganFingerprints::morganFingerprintVersion;

  docString="returns (as a list of 2-tuples) the contributions of each atom to\n"
    "the Wildman-Cripppen logp and mr value";
  python::def("_CalcCrippenContribs",
	      computeCrippenContribs,
	      (python::arg("mol"),
	       python::arg("force")=false),
              docString.c_str());
  docString="returns a 2-tuple with the Wildman-Crippen logp,mr values";
  python::def("CalcCrippenDescriptors",
	      calcCrippenDescriptors,
	      (python::arg("mol"),python::arg("includeHs")=true,
	       python::arg("force")=false),
              docString.c_str());
  python::scope().attr("__CalcCrippenDescriptors_version__")=
    RDKit::Descriptors::crippenVersion;

  docString="returns the Labute ASA value for a molecule";
  python::def("CalcLabuteASA",
	      RDKit::Descriptors::calcLabuteASA,
	      (python::arg("mol"),python::arg("includeHs")=true,
	       python::arg("force")=false),
              docString.c_str());
  python::scope().attr("__CalcLabuteASA_version__")=RDKit::Descriptors::labuteASAVersion;

  docString="returns a list of atomic contributions to the Labute ASA";
  python::def("_CalcLabuteASAContribs",
	      computeASAContribs,
	      (python::arg("mol"),python::arg("includeHs")=true,
	       python::arg("force")=false),
              docString.c_str());

  docString="returns the molecule's molecular weight";
  python::def("_CalcMolWt",
	      RDKit::Descriptors::CalcAMW,
	      (python::arg("mol"),python::arg("onlyHeavy")=false),
              docString.c_str());
  python::scope().attr("__CalcMolWt_version__")="1.0.0";

}
<commit_msg>fix required for python2.6 with msvc-8.0<commit_after>// $Id$
//
//  Copyright (C) 2007-2008 Greg Landrum
//
//   @@ All Rights Reserved  @@
//
#include <RDBoost/Wrap.h>
#include <GraphMol/Atom.h>
#include <GraphMol/GraphMol.h>

#include <GraphMol/Descriptors/MolDescriptors.h>
#include <GraphMol/Descriptors/AtomPairs.h>
#include <GraphMol/Fingerprints/MorganFingerprints.h>

#include <vector>

namespace python = boost::python;

namespace {
  std::vector<unsigned int> atomPairTypes(RDKit::Descriptors::AtomPairs::atomNumberTypes,
					  RDKit::Descriptors::AtomPairs::atomNumberTypes+sizeof(RDKit::Descriptors::AtomPairs::atomNumberTypes)/sizeof(unsigned int));
  python::tuple computeASAContribs(const RDKit::ROMol &mol,bool includeHs=true,
				   bool force=false){
    std::vector<double> contribs(mol.getNumAtoms());
    double hContrib=0.0;
    RDKit::Descriptors::getLabuteAtomContribs(mol,contribs,hContrib,includeHs,force);
    python::tuple pycontribs(contribs);
    return python::make_tuple(contribs,hContrib);
  }
  python::list computeCrippenContribs(const RDKit::ROMol &mol,
				       bool force=false){
    std::vector<double> logpContribs(mol.getNumAtoms());
    std::vector<double> mrContribs(mol.getNumAtoms());

    RDKit::Descriptors::getCrippenAtomContribs(mol,logpContribs,mrContribs,force);
    python::list pycontribs;
    for(unsigned int i=0;i<mol.getNumAtoms();++i){
      pycontribs.append(python::make_tuple(logpContribs[i],mrContribs[i]));
    }
    return pycontribs;
  }
  python::tuple calcCrippenDescriptors(const RDKit::ROMol &mol,bool includeHs=true,
				       bool force=false){
    double logp,mr;
    RDKit::Descriptors::CalcCrippenDescriptors(mol,logp,mr,includeHs,force);
    return python::make_tuple(logp,mr);
  }

  RDKit::SparseIntVect<boost::int32_t> *GetAtomPairFingerprint(const RDKit::ROMol &mol,
                                                               unsigned int minLength,
                                                               unsigned int maxLength,
                                                               python::object fromAtoms){
    std::vector<boost::uint32_t> *vect=0;
    if(fromAtoms){
      vect = new std::vector<boost::uint32_t>;
      unsigned int nFrom=python::extract<unsigned int>(fromAtoms.attr("__len__")());
      for(unsigned int i=0;i<nFrom;++i){
        boost::uint32_t v=python::extract<boost::uint32_t>(fromAtoms[i]);
        if(v>=mol.getNumAtoms()){
          throw_value_error("atom index specified that is larger than the number of atoms");
        }
        vect->push_back(v);
      }
    }

    RDKit::SparseIntVect<boost::int32_t> *res;
    res = RDKit::Descriptors::AtomPairs::getAtomPairFingerprint(mol,minLength,maxLength,
                                                                vect);
    if(vect) delete vect;
    return res;
  }

  RDKit::SparseIntVect<boost::int64_t> *GetTopologicalTorsionFingerprint(const RDKit::ROMol &mol,
                                                                         unsigned int targetSize,
                                                                         python::object fromAtoms){
    std::vector<boost::uint32_t> *vect=0;
    if(fromAtoms){
      vect = new std::vector<boost::uint32_t>;
      unsigned int nFrom=python::extract<unsigned int>(fromAtoms.attr("__len__")());
      for(unsigned int i=0;i<nFrom;++i){
        boost::uint32_t v=python::extract<boost::uint32_t>(fromAtoms[i]);
        if(v>=mol.getNumAtoms()){
          throw_value_error("atom index specified that is larger than the number of atoms");
        }
        vect->push_back(v);
      }
    }

    if(targetSize*RDKit::Descriptors::AtomPairs::codeSize>64){
      std::ostringstream errout;
      errout << "Maximum supported topological torsion path length is " << 64/RDKit::Descriptors::AtomPairs::codeSize<<std::endl;
      throw_value_error(errout.str());
    }

    RDKit::SparseIntVect<boost::int64_t> *res;
    res = RDKit::Descriptors::AtomPairs::getTopologicalTorsionFingerprint(mol,targetSize,vect);
    if(vect) delete vect;
    return res;
  }

  RDKit::SparseIntVect<boost::int64_t> *GetHashedTopologicalTorsionFingerprint(const RDKit::ROMol &mol,
                                                                               unsigned int nBits,
                                                                         unsigned int targetSize,
                                                                         python::object fromAtoms){
    std::vector<boost::uint32_t> *vect=0;
    if(fromAtoms){
      vect = new std::vector<boost::uint32_t>;
      unsigned int nFrom=python::extract<unsigned int>(fromAtoms.attr("__len__")());
      for(unsigned int i=0;i<nFrom;++i){
        boost::uint32_t v=python::extract<boost::uint32_t>(fromAtoms[i]);
        if(v>=mol.getNumAtoms()){
          throw_value_error("atom index specified that is larger than the number of atoms");
        }
        vect->push_back(v);
      }
    }
    RDKit::SparseIntVect<boost::int64_t> *res;
    res = RDKit::Descriptors::AtomPairs::getHashedTopologicalTorsionFingerprint(mol,nBits,targetSize,vect);
    if(vect) delete vect;
    return res;
  }

  RDKit::SparseIntVect<boost::uint32_t> *GetMorganFingerprint(const RDKit::ROMol &mol,
                                                              int radius,
                                                              python::object invariants,
                                                              python::object fromAtoms){
    std::vector<boost::uint32_t> *invars=0;
    if(invariants){
      unsigned int nInvar=python::extract<unsigned int>(invariants.attr("__len__")());
      if(nInvar){
        if(nInvar!=mol.getNumAtoms()){
          throw_value_error("length of invariant vector != number of atoms");
        }
        invars = new std::vector<boost::uint32_t>(mol.getNumAtoms());
        for(unsigned int i=0;i<mol.getNumAtoms();++i){
          (*invars)[i] = python::extract<boost::uint32_t>(invariants[i]);
        }
      }
    }
    std::vector<boost::uint32_t> *froms=0;
    if(fromAtoms){
      unsigned int nFrom=python::extract<unsigned int>(fromAtoms.attr("__len__")());
      if(nFrom){
        froms = new std::vector<boost::uint32_t>();
        for(unsigned int i=0;i<nFrom;++i){
          froms->push_back(python::extract<boost::uint32_t>(fromAtoms[i]));
        }
      }
    }
    RDKit::SparseIntVect<boost::uint32_t> *res;
    res = RDKit::MorganFingerprints::getFingerprint(mol,
                                                    static_cast<unsigned int>(radius),
                                                    invars,froms);
    if(invars) delete invars;
    if(froms) delete froms;
    return res;
  }

}

BOOST_PYTHON_MODULE(rdMolDescriptors) {
  python::scope().attr("__doc__") =
    "Module containing functions to compute molecular descriptors"
    ;

  python::register_exception_translator<IndexErrorException>(&translate_index_error);
  python::register_exception_translator<ValueErrorException>(&translate_value_error);

  std::string docString = "";

  python::class_<python::object>("AtomPairsParameters")
    .setattr("version",
		  RDKit::Descriptors::AtomPairs::atomPairsVersion)
    .setattr("numTypeBits",
		  RDKit::Descriptors::AtomPairs::numTypeBits)
    .setattr("numPiBits",
		  RDKit::Descriptors::AtomPairs::numPiBits)
    .setattr("numBranchBits",
		  RDKit::Descriptors::AtomPairs::numBranchBits)
    .setattr("codeSize",
		  RDKit::Descriptors::AtomPairs::codeSize)
    .setattr("atomTypes",
		  atomPairTypes)
    .setattr("numPathBits",
		  RDKit::Descriptors::AtomPairs::numPathBits)
    .setattr("numAtomPairFingerprintBits",
		  RDKit::Descriptors::AtomPairs::numAtomPairFingerprintBits)
    ;
  docString="Returns the atom code (hash) for an atom";
  python::def("GetAtomPairAtomCode", RDKit::Descriptors::AtomPairs::getAtomCode,
              (python::arg("atom"), python::arg("branchSubtract")=0),
              docString.c_str());
  docString="Returns the atom-pair fingerprint for a molecule as an IntSparseIntVect";
  python::def("GetAtomPairFingerprint", GetAtomPairFingerprint,
              (python::arg("mol"),
               python::arg("minLength")=1,
               python::arg("maxLength")=RDKit::Descriptors::AtomPairs::maxPathLen-1,
               python::arg("fromAtoms")=python::list()),
              docString.c_str(),
              python::return_value_policy<python::manage_new_object>());

  python::def("GetHashedAtomPairFingerprint",
	      (RDKit::SparseIntVect<boost::int32_t> *(*)(const RDKit::ROMol&,unsigned int,unsigned int,unsigned int))RDKit::Descriptors::AtomPairs::getHashedAtomPairFingerprint,
	      (python::arg("mol"),
               python::arg("nBits")=2048,
               python::arg("minLength")=1,
               python::arg("maxLength")=RDKit::Descriptors::AtomPairs::maxPathLen-1),
              docString.c_str(),
	      python::return_value_policy<python::manage_new_object>());
  docString="Returns the topological-torsion fingerprint for a molecule as a LongIntSparseIntVect";
  python::def("GetTopologicalTorsionFingerprint",
	      GetTopologicalTorsionFingerprint,
	      (python::arg("mol"),python::arg("targetSize")=4,
               python::arg("fromAtoms")=0),
              docString.c_str(),
	      python::return_value_policy<python::manage_new_object>());
  python::def("GetHashedTopologicalTorsionFingerprint",
	      GetHashedTopologicalTorsionFingerprint,
	      (python::arg("mol"),
               python::arg("nBits")=2048,
               python::arg("targetSize")=4,
               python::arg("fromAtoms")=0),
              docString.c_str(),
	      python::return_value_policy<python::manage_new_object>());

  docString="Returns a Morgan fingerprint for a molecule";
  python::def("GetMorganFingerprint", GetMorganFingerprint,
              (python::arg("mol"),python::arg("radius"),
               python::arg("invariants")=python::list(),
               python::arg("fromAtoms")=python::list()),
              docString.c_str(),
              python::return_value_policy<python::manage_new_object>());
  python::scope().attr("__MorganFingerprint_version__")=
    RDKit::MorganFingerprints::morganFingerprintVersion;

  docString="returns (as a list of 2-tuples) the contributions of each atom to\n"
    "the Wildman-Cripppen logp and mr value";
  python::def("_CalcCrippenContribs",
	      computeCrippenContribs,
	      (python::arg("mol"),
	       python::arg("force")=false),
              docString.c_str());
  docString="returns a 2-tuple with the Wildman-Crippen logp,mr values";
  python::def("CalcCrippenDescriptors",
	      calcCrippenDescriptors,
	      (python::arg("mol"),python::arg("includeHs")=true,
	       python::arg("force")=false),
              docString.c_str());
  python::scope().attr("__CalcCrippenDescriptors_version__")=
    RDKit::Descriptors::crippenVersion;

  docString="returns the Labute ASA value for a molecule";
  python::def("CalcLabuteASA",
	      RDKit::Descriptors::calcLabuteASA,
	      (python::arg("mol"),python::arg("includeHs")=true,
	       python::arg("force")=false),
              docString.c_str());
  python::scope().attr("__CalcLabuteASA_version__")=RDKit::Descriptors::labuteASAVersion;

  docString="returns a list of atomic contributions to the Labute ASA";
  python::def("_CalcLabuteASAContribs",
	      computeASAContribs,
	      (python::arg("mol"),python::arg("includeHs")=true,
	       python::arg("force")=false),
              docString.c_str());

  docString="returns the molecule's molecular weight";
  python::def("_CalcMolWt",
	      RDKit::Descriptors::CalcAMW,
	      (python::arg("mol"),python::arg("onlyHeavy")=false),
              docString.c_str());
  python::scope().attr("__CalcMolWt_version__")="1.0.0";

}
<|endoftext|>


<commit_before>#include "mob.hpp"
#include "texture_manager.hpp"
#include "mesh_helpers.hpp"
#include <be/core/service_helpers.hpp>
#include <sstream>
#include <glm/gtc/matrix_transform.hpp>
#include <be/core/logging.hpp>
#include <be/util/service_xoroshiro_128_plus.hpp>
#include <random>

namespace o {

//////////////////////////////////////////////////////////////////////////////
Mob::Mob(MeshManager& mm) {
   auto& tm = service<TextureManager>();
   auto& tiles = tm.get(Id("tiles"));
   tiles_ = &tiles;

   avatar_mesh_ = mm.obtain(1);
   avatar_mesh_.texture_glid(tiles.glid());
   avatar_mesh_.size(4);
   avatar_mesh_.enabled(true);
   avatar_mesh_.layer(1);
   avatar_mesh_.transform(&avatar_transform_);

   direction_ = 'u';
   attack_time_remaining_ = 0;

   auto& rnd = service<util::xo128p>();
   std::uniform_int_distribution<int> dist('1', '4');

   variant_ = ( char ) dist(rnd);

   switch (variant_) {
      case '1':
         move_speed_ = 1.5f;
         hp_ = 2;
         break;
      case '2':
         move_speed_ = 3.f;
         hp_ = 1;
         break;
      case '3':
         move_speed_ = 0.25f;
         hp_ = 10;
         break;
      case '4':
         move_speed_ = 0.25f;
         hp_ = 5;
         break;
   }

   update_avatar_mesh_();
}

//////////////////////////////////////////////////////////////////////////////
void Mob::mobs_left(U32 count, U32 total) {
   if (variant_ == '4') {
      move_speed_ = 0.25f + (total - count) * 4.f / total;
   }
}

//////////////////////////////////////////////////////////////////////////////
void Mob::player_distance(F32 dst) {
   if (variant_ == '3') {
      move_speed_ = 0.25f + sqrt(dst / 2);
   }
}

//////////////////////////////////////////////////////////////////////////////
void Mob::pos(vec2 new_pos) {
   position_ = new_pos;
   avatar_transform_ = glm::translate(mat4(), vec3(position_, 0));
}

//////////////////////////////////////////////////////////////////////////////
void Mob::update(F64 dt) {
   bool dirty = false;

   if (hp_ <= 0) {
      if (avatar_mesh_) {
         avatar_mesh_ = Mesh();
      }
      return;
   }

   if (attack_time_remaining_ > 0) {
      attack_time_remaining_ -= ( F32 ) dt;
   }

   if (movement_intention_ != vec2()) {
      if (abs(movement_intention_.x) > abs(movement_intention_.y)) {
         if (movement_intention_.x < 0) {
            if (direction_ != 'l') {
               direction_ = 'l';
               dirty = true;
            }
         } else {
            if (direction_ != 'r') {
               direction_ = 'r';
               dirty = true;
            }
         }
      } else {
         if (movement_intention_.y < 0) {
            if (direction_ != 'u') {
               direction_ = 'u';
               dirty = true;
            }
         } else {
            if (direction_ != 'd') {
               direction_ = 'd';
               dirty = true;
            }
         }
      }

      position_ += move_speed_ * glm::normalize(movement_intention_) * ( F32 ) dt;
      avatar_transform_ = glm::translate(mat4(), vec3(position_, 0));
   }

   if (dirty) {
      be_verbose() << "Mob Mesh Change"
         & attr("movement_intention") << movement_intention_.x << ", " << movement_intention_.y
         & attr("position") << position_.x << ", " << position_.y
         & attr("attack_time") << attack_time_remaining_
         | default_log();

      update_avatar_mesh_();
   }
}

//////////////////////////////////////////////////////////////////////////////
void Mob::update_avatar_mesh_() {
   S name = "enemy";
   name.append(1, variant_);
   name.append(1, '-');
   name.append(1, direction_);
   TextureRegion region = tiles_->region(Id(name));

   update_verts(avatar_mesh_.verts(), region, vec2(), 1 / 16.f);
}

} // o
<commit_msg>swapping red/yellow mob variants<commit_after>#include "mob.hpp"
#include "texture_manager.hpp"
#include "mesh_helpers.hpp"
#include <be/core/service_helpers.hpp>
#include <sstream>
#include <glm/gtc/matrix_transform.hpp>
#include <be/core/logging.hpp>
#include <be/util/service_xoroshiro_128_plus.hpp>
#include <random>

namespace o {

//////////////////////////////////////////////////////////////////////////////
Mob::Mob(MeshManager& mm) {
   auto& tm = service<TextureManager>();
   auto& tiles = tm.get(Id("tiles"));
   tiles_ = &tiles;

   avatar_mesh_ = mm.obtain(1);
   avatar_mesh_.texture_glid(tiles.glid());
   avatar_mesh_.size(4);
   avatar_mesh_.enabled(true);
   avatar_mesh_.layer(1);
   avatar_mesh_.transform(&avatar_transform_);

   direction_ = 'u';
   attack_time_remaining_ = 0;

   auto& rnd = service<util::xo128p>();
   std::uniform_int_distribution<int> dist('1', '4');

   variant_ = ( char ) dist(rnd);

   switch (variant_) {
      case '4':
         move_speed_ = 1.5f;
         hp_ = 2;
         break;
      case '2':
         move_speed_ = 3.f;
         hp_ = 1;
         break;
      case '3':
         move_speed_ = 0.25f;
         hp_ = 10;
         break;
      case '1':
         move_speed_ = 0.25f;
         hp_ = 5;
         break;
   }

   update_avatar_mesh_();
}

//////////////////////////////////////////////////////////////////////////////
void Mob::mobs_left(U32 count, U32 total) {
   if (variant_ == '1') {
      move_speed_ = 0.25f + (total - count) * 4.f / total;
   }
}

//////////////////////////////////////////////////////////////////////////////
void Mob::player_distance(F32 dst) {
   if (variant_ == '3') {
      move_speed_ = 0.25f + sqrt(dst / 2);
   }
}

//////////////////////////////////////////////////////////////////////////////
void Mob::pos(vec2 new_pos) {
   position_ = new_pos;
   avatar_transform_ = glm::translate(mat4(), vec3(position_, 0));
}

//////////////////////////////////////////////////////////////////////////////
void Mob::update(F64 dt) {
   bool dirty = false;

   if (hp_ <= 0) {
      if (avatar_mesh_) {
         avatar_mesh_ = Mesh();
      }
      return;
   }

   if (attack_time_remaining_ > 0) {
      attack_time_remaining_ -= ( F32 ) dt;
   }

   if (movement_intention_ != vec2()) {
      if (abs(movement_intention_.x) > abs(movement_intention_.y)) {
         if (movement_intention_.x < 0) {
            if (direction_ != 'l') {
               direction_ = 'l';
               dirty = true;
            }
         } else {
            if (direction_ != 'r') {
               direction_ = 'r';
               dirty = true;
            }
         }
      } else {
         if (movement_intention_.y < 0) {
            if (direction_ != 'u') {
               direction_ = 'u';
               dirty = true;
            }
         } else {
            if (direction_ != 'd') {
               direction_ = 'd';
               dirty = true;
            }
         }
      }

      position_ += move_speed_ * glm::normalize(movement_intention_) * ( F32 ) dt;
      avatar_transform_ = glm::translate(mat4(), vec3(position_, 0));
   }

   if (dirty) {
      be_verbose() << "Mob Mesh Change"
         & attr("movement_intention") << movement_intention_.x << ", " << movement_intention_.y
         & attr("position") << position_.x << ", " << position_.y
         & attr("attack_time") << attack_time_remaining_
         | default_log();

      update_avatar_mesh_();
   }
}

//////////////////////////////////////////////////////////////////////////////
void Mob::update_avatar_mesh_() {
   S name = "enemy";
   name.append(1, variant_);
   name.append(1, '-');
   name.append(1, direction_);
   TextureRegion region = tiles_->region(Id(name));

   update_verts(avatar_mesh_.verts(), region, vec2(), 1 / 16.f);
}

} // o
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2016, Esteban Tovagliari. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "IECoreAppleseed/MeshAlgo.h"

#include "IECoreScene/MeshPrimitive.h"
#include "IECoreScene/TriangulateOp.h"

#include "IECore/Exception.h"
#include "IECore/MessageHandler.h"

using namespace IECore;
using namespace IECoreScene;
using namespace Imath;
using namespace std;

namespace asf = foundation;
namespace asr = renderer;

//////////////////////////////////////////////////////////////////////////
// Internal utilities
//////////////////////////////////////////////////////////////////////////

namespace
{

void setMeshKey( renderer::MeshObject *mesh, size_t keyIndex, const Object *object )
{
	const MeshPrimitive *m = static_cast<const MeshPrimitive*>( object );
	const V3fVectorData *p = m->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );

	if( !p )
	{
		throw Exception( "MeshPrimitive does not have \"P\" primitive variable of interpolation type Vertex." );
	}

	const std::vector<V3f> &points = p->readable();
	for( size_t j = 0, numVertices = p->readable().size() ; j < numVertices; ++j )
	{
		mesh->set_vertex_pose( j, keyIndex, asr::GVector3( points[j].x, points[j].y, points[j].z ) );
	}

	if( mesh->get_vertex_normal_count() != 0 )
	{
		PrimitiveVariableMap::const_iterator nIt = m->variables.find( "N" );
		if( nIt == m->variables.end() )
		{
			throw Exception( "MeshPrimitive missing normals in motion sample." );
		}

		const V3fVectorData *n = runTimeCast<const V3fVectorData>( nIt->second.data.get() );
		if( !n )
		{
			throw Exception( ( boost::format( "MeshPrimitive \"N\" primitive variable has unsupported type \"%s\" (expected V3fVectorData)." ) % nIt->second.data->typeName() ).str() );
		}

		const std::vector<V3f> &normals = n->readable();
		size_t numNormals = normals.size();
		if( numNormals != mesh->get_vertex_normal_count() )
		{
			throw Exception( "MeshPrimitive \"N\" primitive variable has different interpolation than first deformation sample." );
		}

		for( size_t j = 0 ; j < numNormals; ++j )
		{
			const asr::GVector3 n( normals[j].x, normals[j].y, normals[j].z );
			mesh->set_vertex_normal_pose( j, keyIndex, asf::normalize( n ) );
		}
	}

	if( mesh->get_vertex_tangent_count() != 0 )
	{
		PrimitiveVariableMap::const_iterator tIt = m->variables.find( "uTangent" );
		if( tIt == m->variables.end() )
		{
			throw Exception( "MeshPrimitive missing tangents in motion sample." );
		}

		const V3fVectorData *t = runTimeCast<const V3fVectorData>( tIt->second.data.get() );
		if( !t )
		{
			throw Exception( ( boost::format( "MeshPrimitive \"uTangent\" primitive variable has unsupported type \"%s\" (expected V3fVectorData)." ) % tIt->second.data->typeName() ).str() );
		}

		const std::vector<V3f> &tangents = t->readable();
		size_t numTangents = t->readable().size();
		if( numTangents != mesh->get_vertex_tangent_count() )
		{
			throw Exception( "MeshPrimitive \"uTangent\" primitive variable has different interpolation than first deformation sample." );
		}

		for( size_t j = 0 ; j < numTangents; ++j )
		{
			const asr::GVector3 t( tangents[j].x, tangents[j].y, tangents[j].z );
			mesh->set_vertex_tangent_pose( j, keyIndex, asf::normalize( t ) );
		}
	}
}

}

//////////////////////////////////////////////////////////////////////////
// Implementation of public API.
//////////////////////////////////////////////////////////////////////////

namespace IECoreAppleseed
{

namespace MeshAlgo
{

renderer::MeshObject *convert( const IECore::Object *primitive )
{
	assert( primitive->typeId() == IECore::MeshPrimitiveTypeId );
	const IECoreScene::MeshPrimitive *mesh = static_cast<const IECoreScene::MeshPrimitive *>( primitive );

	const V3fVectorData *p = mesh->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
	if( !p )
	{
		throw Exception( "MeshPrimitive does not have \"P\" primitive variable of interpolation type Vertex." );
	}

	asf::auto_release_ptr<asr::MeshObject> meshEntity( asr::MeshObjectFactory().create( "mesh", asr::ParamArray() ) );
	const size_t materialSlot = meshEntity->push_material_slot( "default" );

	// vertices
	{
		size_t numVertices = p->readable().size();
		meshEntity->reserve_vertices( numVertices );
		const std::vector<V3f> &points = p->readable();
		for( size_t i = 0; i < numVertices; ++i )
		{
			meshEntity->push_vertex( asr::GVector3( points[i].x, points[i].y, points[i].z ) );
		}
	}

	// triangulate primitive (this should be in appleseed at some point)
	MeshPrimitivePtr triangulatedMeshPrimPtr = mesh->copy();
	{
		TriangulateOpPtr op = new TriangulateOp();
		op->inputParameter()->setValue( triangulatedMeshPrimPtr );
		op->throwExceptionsParameter()->setTypedValue( false ); // it's better to see something than nothing
		op->copyParameter()->setTypedValue( false );
		op->operate();
	}

	// triangles
	size_t numTriangles = triangulatedMeshPrimPtr->numFaces();
	std::vector<asr::Triangle> triangles;
	triangles.reserve( numTriangles );
	const std::vector<int> &vidx = triangulatedMeshPrimPtr->vertexIds()->readable();
	for( size_t i = 0; i < vidx.size(); i += 3 )
	{
		triangles.push_back( asr::Triangle( vidx[i], vidx[i+1], vidx[i+2], materialSlot ) );
	}

	// texture coords
	{
		PrimitiveVariableMap::const_iterator uvIt = triangulatedMeshPrimPtr->variables.find( "uv" );
		if( uvIt != triangulatedMeshPrimPtr->variables.end() && uvIt->second.data->typeId() == V2fVectorDataTypeId )
		{
			if( uvIt->second.interpolation == PrimitiveVariable::Varying || uvIt->second.interpolation == PrimitiveVariable::Vertex || uvIt->second.interpolation == PrimitiveVariable::FaceVarying )
			{
				const std::vector<Imath::V2f> &uvs = runTimeCast<const V2fVectorData>( uvIt->second.data )->readable();
				size_t numUVs = uvs.size();

				meshEntity->reserve_tex_coords( numUVs );

				for( size_t i = 0; i < numUVs; ++i)
				{
					meshEntity->push_tex_coords( asr::GVector2( uvs[i] ) );
				}

				const vector<int> *indices = nullptr;
				if( uvIt->second.indices )
				{
					indices = &uvIt->second.indices->readable();
				}

				for( size_t i = 0; i < numTriangles; ++i )
				{
					asr::Triangle& tri = triangles[i];
					if( uvIt->second.interpolation == PrimitiveVariable::FaceVarying )
					{
						tri.m_a0 = i * 3;
						tri.m_a1 = i * 3 + 1;
						tri.m_a2 = i * 3 + 2;
					}
					else
					{
						tri.m_a0 = vidx[i * 3];
						tri.m_a1 = vidx[i * 3 + 1];
						tri.m_a2 = vidx[i * 3 + 2];
					}

					if( indices )
					{
						tri.m_a0 = (*indices)[tri.m_a0];
						tri.m_a1 = (*indices)[tri.m_a1];
						tri.m_a2 = (*indices)[tri.m_a2];
					}
				}
			}
			else
			{
				msg( Msg::Warning, "ToAppleseedMeshConverter::doConversion", "Variable \"uv\" has unsupported interpolation type - not generating uvs." );
			}
		}
	}

	// normals
	{
		PrimitiveVariableMap::const_iterator nIt = triangulatedMeshPrimPtr->variables.find( "N" );
		if( nIt != triangulatedMeshPrimPtr->variables.end() )
		{
			const V3fVectorData *n = runTimeCast<const V3fVectorData>( nIt->second.data.get() );
			if( n )
			{
				PrimitiveVariable::Interpolation nInterpolation = nIt->second.interpolation;
				if( nInterpolation == PrimitiveVariable::Varying || nInterpolation == PrimitiveVariable::Vertex || nInterpolation == PrimitiveVariable::FaceVarying )
				{
					size_t numNormals = n->readable().size();
					meshEntity->reserve_vertex_normals( numNormals );
					const std::vector<V3f> &normals = n->readable();
					for( size_t i = 0; i < numNormals; ++i)
					{
						asr::GVector3 n( normals[i].x, normals[i].y, normals[i].z );
						meshEntity->push_vertex_normal( asf::normalize( n ) );
					}

					if( nInterpolation == PrimitiveVariable::FaceVarying )
					{
						for( size_t i = 0, j = 0; i < numTriangles; ++i)
						{
							asr::Triangle& tri = triangles[i];
							tri.m_n0 = j++;
							tri.m_n1 = j++;
							tri.m_n2 = j++;
						}
					}
					else
					{
						for( size_t i = 0; i < vidx.size(); i += 3)
						{
							asr::Triangle& tri = triangles[i / 3];
							tri.m_n0 = vidx[i];
							tri.m_n1 = vidx[i+1];
							tri.m_n2 = vidx[i+2];
						}
					}
				}
				else
				{
					msg( Msg::Warning, "ToAppleseedMeshConverter::doConversion", "Variable \"N\" has unsupported interpolation type - not generating normals." );
				}
			}
			else
			{
				msg( Msg::Warning, "ToAppleseedMeshConverter::doConversion", boost::format( "Variable \"N\" has unsupported type \"%s\" (expected V3fVectorData)." ) % nIt->second.data->typeName() );
			}
		}
	}

	// tangents
	{
		PrimitiveVariableMap::const_iterator tIt = triangulatedMeshPrimPtr->variables.find( "uTangent" );
		if( tIt != triangulatedMeshPrimPtr->variables.end() )
		{
			const V3fVectorData *t = runTimeCast<const V3fVectorData>( tIt->second.data.get() );
			if( t )
			{
				PrimitiveVariable::Interpolation tInterpolation = tIt->second.interpolation;
				if( tInterpolation == PrimitiveVariable::Varying || tInterpolation == PrimitiveVariable::Vertex )
				{
					size_t numTangents = t->readable().size();
					meshEntity->reserve_vertex_tangents( numTangents );
					const std::vector<V3f> &tangents = t->readable();
					for( size_t i = 0; i < numTangents; ++i)
					{
						asr::GVector3 t( tangents[i].x, tangents[i].y, tangents[i].z );
						meshEntity->push_vertex_tangent( asf::normalize( t ) );
					}
				}
				else
				{
					msg( Msg::Warning, "ToAppleseedMeshConverter::doConversion", "Variable \"uTangent\" has unsupported interpolation type - not generating tangents." );
				}
			}
			else
			{
				msg( Msg::Warning, "ToAppleseedMeshConverter::doConversion", boost::format( "Variable \"uTangent\" has unsupported type \"%s\" (expected V3fVectorData)." ) % tIt->second.data->typeName() );
			}
		}
	}

	// copy triangles to mesh entity
	{
		meshEntity->reserve_triangles( numTriangles );

		for( size_t i = 0; i < triangles.size(); ++i)
		{
			meshEntity->push_triangle( triangles[i] );
		}
	}

	return meshEntity.release();
}

renderer::MeshObject *convert( const std::vector<const IECore::Object *> &samples )
{
	if( !asf::is_pow2( samples.size() ) )
	{
		throw Exception( "Number of motion samples must be a power of 2." );
	}

	// convert the first sample.
	renderer::MeshObject *mesh = convert( samples[0] );

	// set the point, normal and tangent positions for all other time samples.
	mesh->set_motion_segment_count( samples.size() - 1 );

	for( size_t i = 1, e = samples.size(); i < e; ++i )
	{
		setMeshKey( mesh, i - 1, samples[i] );
	}

	return mesh;
}

renderer::MeshObject *convert( const std::vector<IECore::ObjectPtr> &samples )
{
	if( !asf::is_pow2( samples.size() ) )
	{
		throw Exception( "Number of motion samples must be a power of 2." );
	}

	// convert the first sample.
	renderer::MeshObject *mesh = convert( samples[0].get() );

	// set the point, normal and tangent positions for all other time samples.
	mesh->set_motion_segment_count( samples.size() - 1 );
	for( size_t i = 1, e = samples.size(); i < e; ++i )
	{
		setMeshKey( mesh, i - 1, samples[i].get() );
	}

	return mesh;
}

} // namespace MeshAlgo

} // namespace IECoreAppleseed
<commit_msg>Appleseed MeshAlgo : Fix debug build<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2016, Esteban Tovagliari. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "IECoreAppleseed/MeshAlgo.h"

#include "IECoreScene/MeshPrimitive.h"
#include "IECoreScene/TriangulateOp.h"

#include "IECore/Exception.h"
#include "IECore/MessageHandler.h"

using namespace IECore;
using namespace IECoreScene;
using namespace Imath;
using namespace std;

namespace asf = foundation;
namespace asr = renderer;

//////////////////////////////////////////////////////////////////////////
// Internal utilities
//////////////////////////////////////////////////////////////////////////

namespace
{

void setMeshKey( renderer::MeshObject *mesh, size_t keyIndex, const Object *object )
{
	const MeshPrimitive *m = static_cast<const MeshPrimitive*>( object );
	const V3fVectorData *p = m->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );

	if( !p )
	{
		throw Exception( "MeshPrimitive does not have \"P\" primitive variable of interpolation type Vertex." );
	}

	const std::vector<V3f> &points = p->readable();
	for( size_t j = 0, numVertices = p->readable().size() ; j < numVertices; ++j )
	{
		mesh->set_vertex_pose( j, keyIndex, asr::GVector3( points[j].x, points[j].y, points[j].z ) );
	}

	if( mesh->get_vertex_normal_count() != 0 )
	{
		PrimitiveVariableMap::const_iterator nIt = m->variables.find( "N" );
		if( nIt == m->variables.end() )
		{
			throw Exception( "MeshPrimitive missing normals in motion sample." );
		}

		const V3fVectorData *n = runTimeCast<const V3fVectorData>( nIt->second.data.get() );
		if( !n )
		{
			throw Exception( ( boost::format( "MeshPrimitive \"N\" primitive variable has unsupported type \"%s\" (expected V3fVectorData)." ) % nIt->second.data->typeName() ).str() );
		}

		const std::vector<V3f> &normals = n->readable();
		size_t numNormals = normals.size();
		if( numNormals != mesh->get_vertex_normal_count() )
		{
			throw Exception( "MeshPrimitive \"N\" primitive variable has different interpolation than first deformation sample." );
		}

		for( size_t j = 0 ; j < numNormals; ++j )
		{
			const asr::GVector3 n( normals[j].x, normals[j].y, normals[j].z );
			mesh->set_vertex_normal_pose( j, keyIndex, asf::normalize( n ) );
		}
	}

	if( mesh->get_vertex_tangent_count() != 0 )
	{
		PrimitiveVariableMap::const_iterator tIt = m->variables.find( "uTangent" );
		if( tIt == m->variables.end() )
		{
			throw Exception( "MeshPrimitive missing tangents in motion sample." );
		}

		const V3fVectorData *t = runTimeCast<const V3fVectorData>( tIt->second.data.get() );
		if( !t )
		{
			throw Exception( ( boost::format( "MeshPrimitive \"uTangent\" primitive variable has unsupported type \"%s\" (expected V3fVectorData)." ) % tIt->second.data->typeName() ).str() );
		}

		const std::vector<V3f> &tangents = t->readable();
		size_t numTangents = t->readable().size();
		if( numTangents != mesh->get_vertex_tangent_count() )
		{
			throw Exception( "MeshPrimitive \"uTangent\" primitive variable has different interpolation than first deformation sample." );
		}

		for( size_t j = 0 ; j < numTangents; ++j )
		{
			const asr::GVector3 t( tangents[j].x, tangents[j].y, tangents[j].z );
			mesh->set_vertex_tangent_pose( j, keyIndex, asf::normalize( t ) );
		}
	}
}

}

//////////////////////////////////////////////////////////////////////////
// Implementation of public API.
//////////////////////////////////////////////////////////////////////////

namespace IECoreAppleseed
{

namespace MeshAlgo
{

renderer::MeshObject *convert( const IECore::Object *primitive )
{
	assert( primitive->typeId() == IECoreScene::MeshPrimitive::staticTypeId() );
	const IECoreScene::MeshPrimitive *mesh = static_cast<const IECoreScene::MeshPrimitive *>( primitive );

	const V3fVectorData *p = mesh->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
	if( !p )
	{
		throw Exception( "MeshPrimitive does not have \"P\" primitive variable of interpolation type Vertex." );
	}

	asf::auto_release_ptr<asr::MeshObject> meshEntity( asr::MeshObjectFactory().create( "mesh", asr::ParamArray() ) );
	const size_t materialSlot = meshEntity->push_material_slot( "default" );

	// vertices
	{
		size_t numVertices = p->readable().size();
		meshEntity->reserve_vertices( numVertices );
		const std::vector<V3f> &points = p->readable();
		for( size_t i = 0; i < numVertices; ++i )
		{
			meshEntity->push_vertex( asr::GVector3( points[i].x, points[i].y, points[i].z ) );
		}
	}

	// triangulate primitive (this should be in appleseed at some point)
	MeshPrimitivePtr triangulatedMeshPrimPtr = mesh->copy();
	{
		TriangulateOpPtr op = new TriangulateOp();
		op->inputParameter()->setValue( triangulatedMeshPrimPtr );
		op->throwExceptionsParameter()->setTypedValue( false ); // it's better to see something than nothing
		op->copyParameter()->setTypedValue( false );
		op->operate();
	}

	// triangles
	size_t numTriangles = triangulatedMeshPrimPtr->numFaces();
	std::vector<asr::Triangle> triangles;
	triangles.reserve( numTriangles );
	const std::vector<int> &vidx = triangulatedMeshPrimPtr->vertexIds()->readable();
	for( size_t i = 0; i < vidx.size(); i += 3 )
	{
		triangles.push_back( asr::Triangle( vidx[i], vidx[i+1], vidx[i+2], materialSlot ) );
	}

	// texture coords
	{
		PrimitiveVariableMap::const_iterator uvIt = triangulatedMeshPrimPtr->variables.find( "uv" );
		if( uvIt != triangulatedMeshPrimPtr->variables.end() && uvIt->second.data->typeId() == V2fVectorDataTypeId )
		{
			if( uvIt->second.interpolation == PrimitiveVariable::Varying || uvIt->second.interpolation == PrimitiveVariable::Vertex || uvIt->second.interpolation == PrimitiveVariable::FaceVarying )
			{
				const std::vector<Imath::V2f> &uvs = runTimeCast<const V2fVectorData>( uvIt->second.data )->readable();
				size_t numUVs = uvs.size();

				meshEntity->reserve_tex_coords( numUVs );

				for( size_t i = 0; i < numUVs; ++i)
				{
					meshEntity->push_tex_coords( asr::GVector2( uvs[i] ) );
				}

				const vector<int> *indices = nullptr;
				if( uvIt->second.indices )
				{
					indices = &uvIt->second.indices->readable();
				}

				for( size_t i = 0; i < numTriangles; ++i )
				{
					asr::Triangle& tri = triangles[i];
					if( uvIt->second.interpolation == PrimitiveVariable::FaceVarying )
					{
						tri.m_a0 = i * 3;
						tri.m_a1 = i * 3 + 1;
						tri.m_a2 = i * 3 + 2;
					}
					else
					{
						tri.m_a0 = vidx[i * 3];
						tri.m_a1 = vidx[i * 3 + 1];
						tri.m_a2 = vidx[i * 3 + 2];
					}

					if( indices )
					{
						tri.m_a0 = (*indices)[tri.m_a0];
						tri.m_a1 = (*indices)[tri.m_a1];
						tri.m_a2 = (*indices)[tri.m_a2];
					}
				}
			}
			else
			{
				msg( Msg::Warning, "ToAppleseedMeshConverter::doConversion", "Variable \"uv\" has unsupported interpolation type - not generating uvs." );
			}
		}
	}

	// normals
	{
		PrimitiveVariableMap::const_iterator nIt = triangulatedMeshPrimPtr->variables.find( "N" );
		if( nIt != triangulatedMeshPrimPtr->variables.end() )
		{
			const V3fVectorData *n = runTimeCast<const V3fVectorData>( nIt->second.data.get() );
			if( n )
			{
				PrimitiveVariable::Interpolation nInterpolation = nIt->second.interpolation;
				if( nInterpolation == PrimitiveVariable::Varying || nInterpolation == PrimitiveVariable::Vertex || nInterpolation == PrimitiveVariable::FaceVarying )
				{
					size_t numNormals = n->readable().size();
					meshEntity->reserve_vertex_normals( numNormals );
					const std::vector<V3f> &normals = n->readable();
					for( size_t i = 0; i < numNormals; ++i)
					{
						asr::GVector3 n( normals[i].x, normals[i].y, normals[i].z );
						meshEntity->push_vertex_normal( asf::normalize( n ) );
					}

					if( nInterpolation == PrimitiveVariable::FaceVarying )
					{
						for( size_t i = 0, j = 0; i < numTriangles; ++i)
						{
							asr::Triangle& tri = triangles[i];
							tri.m_n0 = j++;
							tri.m_n1 = j++;
							tri.m_n2 = j++;
						}
					}
					else
					{
						for( size_t i = 0; i < vidx.size(); i += 3)
						{
							asr::Triangle& tri = triangles[i / 3];
							tri.m_n0 = vidx[i];
							tri.m_n1 = vidx[i+1];
							tri.m_n2 = vidx[i+2];
						}
					}
				}
				else
				{
					msg( Msg::Warning, "ToAppleseedMeshConverter::doConversion", "Variable \"N\" has unsupported interpolation type - not generating normals." );
				}
			}
			else
			{
				msg( Msg::Warning, "ToAppleseedMeshConverter::doConversion", boost::format( "Variable \"N\" has unsupported type \"%s\" (expected V3fVectorData)." ) % nIt->second.data->typeName() );
			}
		}
	}

	// tangents
	{
		PrimitiveVariableMap::const_iterator tIt = triangulatedMeshPrimPtr->variables.find( "uTangent" );
		if( tIt != triangulatedMeshPrimPtr->variables.end() )
		{
			const V3fVectorData *t = runTimeCast<const V3fVectorData>( tIt->second.data.get() );
			if( t )
			{
				PrimitiveVariable::Interpolation tInterpolation = tIt->second.interpolation;
				if( tInterpolation == PrimitiveVariable::Varying || tInterpolation == PrimitiveVariable::Vertex )
				{
					size_t numTangents = t->readable().size();
					meshEntity->reserve_vertex_tangents( numTangents );
					const std::vector<V3f> &tangents = t->readable();
					for( size_t i = 0; i < numTangents; ++i)
					{
						asr::GVector3 t( tangents[i].x, tangents[i].y, tangents[i].z );
						meshEntity->push_vertex_tangent( asf::normalize( t ) );
					}
				}
				else
				{
					msg( Msg::Warning, "ToAppleseedMeshConverter::doConversion", "Variable \"uTangent\" has unsupported interpolation type - not generating tangents." );
				}
			}
			else
			{
				msg( Msg::Warning, "ToAppleseedMeshConverter::doConversion", boost::format( "Variable \"uTangent\" has unsupported type \"%s\" (expected V3fVectorData)." ) % tIt->second.data->typeName() );
			}
		}
	}

	// copy triangles to mesh entity
	{
		meshEntity->reserve_triangles( numTriangles );

		for( size_t i = 0; i < triangles.size(); ++i)
		{
			meshEntity->push_triangle( triangles[i] );
		}
	}

	return meshEntity.release();
}

renderer::MeshObject *convert( const std::vector<const IECore::Object *> &samples )
{
	if( !asf::is_pow2( samples.size() ) )
	{
		throw Exception( "Number of motion samples must be a power of 2." );
	}

	// convert the first sample.
	renderer::MeshObject *mesh = convert( samples[0] );

	// set the point, normal and tangent positions for all other time samples.
	mesh->set_motion_segment_count( samples.size() - 1 );

	for( size_t i = 1, e = samples.size(); i < e; ++i )
	{
		setMeshKey( mesh, i - 1, samples[i] );
	}

	return mesh;
}

renderer::MeshObject *convert( const std::vector<IECore::ObjectPtr> &samples )
{
	if( !asf::is_pow2( samples.size() ) )
	{
		throw Exception( "Number of motion samples must be a power of 2." );
	}

	// convert the first sample.
	renderer::MeshObject *mesh = convert( samples[0].get() );

	// set the point, normal and tangent positions for all other time samples.
	mesh->set_motion_segment_count( samples.size() - 1 );
	for( size_t i = 1, e = samples.size(); i < e; ++i )
	{
		setMeshKey( mesh, i - 1, samples[i].get() );
	}

	return mesh;
}

} // namespace MeshAlgo

} // namespace IECoreAppleseed
<|endoftext|>


<commit_before>/* implementations of byte-at-a-time virtual read/writes for long mode that
   never cause faults/exceptions and maybe do not affect TLB content */

#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR

    Bit8u BX_CPP_AttrRegparmN(2)
BX_CPU_C::read_virtual_byte_64_nofail(unsigned s, Bit64u offset, uint8_t *error)
{
    Bit8u data;
    Bit64u laddr = get_laddr64(s, offset); // this is safe

    if (! IsCanonical(laddr)) {
        *error = 1;
        return 0;
    }

    access_read_linear_nofail(laddr, 1, 0, BX_READ, (void *) &data, error);
    return data;
}

int BX_CPU_C::access_read_linear_nofail(bx_address laddr, unsigned len, unsigned curr_pl, unsigned xlate_rw, void *data, uint8_t *error)
{
    BX_ASSERT(xlate_rw == BX_READ || xlate_rw == BX_RW); // this is safe

    Bit32u pageOffset = PAGE_OFFSET(laddr); // this is safe

    bx_TLB_entry *tlbEntry = BX_TLB_ENTRY_OF(laddr); // this is safe

    /* next line DOES THE PAGE TABLE WALK */
    BX_CPU_THIS_PTR address_xlation.paddress1 = translate_linear_nofail(tlbEntry, laddr, (curr_pl == 3), xlate_rw);
    BX_CPU_THIS_PTR address_xlation.pages     = 1;
    access_read_physical(BX_CPU_THIS_PTR address_xlation.paddress1, len, data);
    /* previous line SHOULD BE SAFE */

    return 0;
}

bx_phy_address BX_CPU_C::translate_linear_nofail(bx_TLB_entry *tlbEntry, bx_address laddr, unsigned user, unsigned rw)
{
    Bit32u combined_access = 0x06;
    Bit32u lpf_mask = 0xfff; // 4K pages

    bx_phy_address paddress, ppf, poffset = PAGE_OFFSET(laddr);
    paddress = translate_linear_long_mode(laddr, lpf_mask, combined_access, user, rw);
    paddress = A20ADDR(paddress);
    return paddress;
}
<commit_msg>cut out translate_linear_nofail and just call the longmode shit<commit_after>/* implementations of byte-at-a-time virtual read/writes for long mode that
   never cause faults/exceptions and maybe do not affect TLB content */

#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR

    Bit8u BX_CPP_AttrRegparmN(2)
BX_CPU_C::read_virtual_byte_64_nofail(unsigned s, Bit64u offset, uint8_t *error)
{
    Bit8u data;
    Bit64u laddr = get_laddr64(s, offset); // this is safe

    if (! IsCanonical(laddr)) {
        *error = 1;
        return 0;
    }

    access_read_linear_nofail(laddr, 1, 0, BX_READ, (void *) &data, error);
    return data;
}

int BX_CPU_C::access_read_linear_nofail(bx_address laddr, unsigned len, unsigned curr_pl, unsigned xlate_rw, void *data, uint8_t *error)
{
    Bit32u combined_access = 0x06;
    Bit32u lpf_mask = 0xfff; // 4K pages
    bx_phy_address paddress, ppf, poffset = PAGE_OFFSET(laddr);

    paddress = translate_linear_long_mode_nofail(laddr, lpf_mask, combined_access, user, xlate_rw);
    paddress = A20ADDR(paddress);
    access_read_physical(paddress, len, data);

    return 0;
}

bx_phy_address BX_CPU_C::translate_linear_long_mode_nofail(bx_address laddr, Bit32u &lpf_mask, Bit32u &combined_access, unsigned user, unsigned rw)
{
  bx_phy_address entry_addr[4];
  bx_phy_address ppf = BX_CPU_THIS_PTR cr3 & BX_CR3_PAGING_MASK;
  Bit64u entry[4];
  bx_bool nx_fault = 0;
  int leaf;

  Bit64u offset_mask = BX_CONST64(0x0000ffffffffffff);
  lpf_mask = 0xfff;
  combined_access = 0x06;

  Bit64u reserved = PAGING_PAE_RESERVED_BITS;
  if (! BX_CPU_THIS_PTR efer.get_NXE())
    reserved |= PAGE_DIRECTORY_NX_BIT;

  for (leaf = BX_LEVEL_PML4;; --leaf) {
    entry_addr[leaf] = ppf + ((laddr >> (9 + 9*leaf)) & 0xff8);
#if BX_SUPPORT_VMX >= 2
    if (BX_CPU_THIS_PTR in_vmx_guest) {
      if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_EPT_ENABLE))
        entry_addr[leaf] = translate_guest_physical(entry_addr[leaf], laddr, 1, 1, BX_READ);
    }
#endif
#if BX_SUPPORT_SVM
    if (BX_CPU_THIS_PTR in_svm_guest && SVM_NESTED_PAGING_ENABLED) {
      entry_addr[leaf] = nested_walk(entry_addr[leaf], BX_RW, 1);
    }
#endif
    access_read_physical(entry_addr[leaf], 8, &entry[leaf]);
    BX_NOTIFY_PHY_MEMORY_ACCESS(entry_addr[leaf], 8, BX_READ, (BX_PTE_ACCESS + leaf), (Bit8u*)(&entry[leaf]));
    offset_mask >>= 9;

    Bit64u curr_entry = entry[leaf];
    int fault = check_entry_PAE(bx_paging_level[leaf], curr_entry, reserved, rw, &nx_fault);
    if (fault >= 0)
      page_fault(fault, laddr, user, rw);

    combined_access &= curr_entry; // U/S and R/W
    ppf = curr_entry & BX_CONST64(0x000ffffffffff000);

    if (leaf == BX_LEVEL_PTE) break;

    if (curr_entry & 0x80) {
      if (leaf > (BX_LEVEL_PDE + !!bx_cpuid_support_1g_paging())) {
        BX_DEBUG(("PAE %s: PS bit set !", bx_paging_level[leaf]));
        page_fault(ERROR_RESERVED | ERROR_PROTECTION, laddr, user, rw);
      }

      ppf &= BX_CONST64(0x000fffffffffe000);
      if (ppf & offset_mask) {
         BX_DEBUG(("PAE %s: reserved bit is set: 0x" FMT_ADDRX64, bx_paging_level[leaf], curr_entry));
         page_fault(ERROR_RESERVED | ERROR_PROTECTION, laddr, user, rw);
      }

      lpf_mask = (Bit32u) offset_mask;
      break;
    }
  }

  bx_bool isWrite = (rw & 1); // write or r-m-w

  unsigned priv_index = (BX_CPU_THIS_PTR cr0.get_WP() << 4) | // bit 4
                        (user<<3) |                           // bit 3
                        (combined_access | isWrite);          // bit 2,1,0

  if (!priv_check[priv_index] || nx_fault)
    page_fault(ERROR_PROTECTION, laddr, user, rw);

  if (BX_CPU_THIS_PTR cr4.get_SMEP() && rw == BX_EXECUTE && !user) {
    if (combined_access & 0x4) // User page
      page_fault(ERROR_PROTECTION, laddr, user, rw);
  }

  // SMAP protections are disabled if EFLAGS.AC=1
  if (BX_CPU_THIS_PTR cr4.get_SMAP() && ! BX_CPU_THIS_PTR get_AC() && rw != BX_EXECUTE && ! user) {
    if (combined_access & 0x4) // User page
      page_fault(ERROR_PROTECTION, laddr, user, rw);
  }

  if (BX_CPU_THIS_PTR cr4.get_PGE())
    combined_access |= (entry[leaf] & 0x100); // G

  // Update A/D bits if needed
  update_access_dirty_PAE(entry_addr, entry, BX_LEVEL_PML4, leaf, isWrite);

  return ppf | (laddr & offset_mask);
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2013-2014 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef CPP_UTILS_PARALLEL_HPP
#define CPP_UTILS_PARALLEL_HPP

#include<thread>
#include<future>
#include<vector>
#include<deque>
#include<functional>
#include<algorithm>

namespace cpp {

//Utilities

template<typename Lock, typename Functor>
void with_lock(Lock& lock, Functor&& fun){
    std::unique_lock<Lock> l(lock);
    fun();
}

//Normal parallel_foreach versions

template<typename Iterator, typename Functor>
void parallel_foreach(Iterator first, Iterator last, Functor&& fun){
    std::vector<std::future<void>> futures;
    futures.reserve(std::distance(first, last));

    for(; first != last; ++first){
        futures.push_back(std::move(std::async(std::launch::async, fun, *first)));
    }

    //No need to wait for the futures, the destructor will do it for us
}

template<typename Iterator, typename Functor>
void parallel_foreach_i(Iterator first, Iterator last, Functor&& fun){
    std::vector<std::future<void>> futures;
    futures.reserve(std::distance(first, last));

    for(; first != last; ++first){
        futures.push_back(std::move(std::async(std::launch::async, fun, *first, futures.size())));
    }

    //No need to wait for the futures, the destructor will do it for us
}

template<typename Container, typename Functor>
void parallel_foreach_i(const Container& container, Functor&& fun){
    std::vector<std::future<void>> futures;
    futures.reserve(container.size());

    for(std::size_t i = 0; i < container.size(); ++i){
        futures.push_back(std::move(std::async(std::launch::async, fun, container[i], i)));
    }

    //No need to wait for the futures, the destructor will do it for us
}

//parallel_foreach Thread pool versions

template<typename TP, typename Iterator, typename Functor>
void parallel_foreach(TP& thread_pool, Iterator first, Iterator last, Functor&& fun){
    for(; first != last; ++first){
        thread_pool.do_task(std::forward<Functor>(fun), *first);
    }

    thread_pool.wait();
}

template<typename TP, typename Iterator, typename Functor>
void parallel_foreach_i(TP& thread_pool, Iterator first, Iterator last, Functor&& fun){
    for(std::size_t i = 0; first != last; ++first, ++i){
        thread_pool.do_task(std::forward<Functor>(fun), *first, i);
    }

    thread_pool.wait();
}

template<typename TP, typename Container, typename Functor>
void parallel_foreach_i(TP& thread_pool, const Container& container, Functor&& fun){
    for(std::size_t i = 0; i < container.size(); ++i){
        thread_pool.do_task(std::forward<Functor>(fun), container[i], i);
    }

    thread_pool.wait();
}

template<template<typename...> class queue_t = std::deque>
struct default_thread_pool {
    enum class thread_status {
        WAITING,
        WORKING
    };

private:
    std::vector<std::thread> threads;
    std::vector<thread_status> status;
    queue_t<std::function<void()>> tasks;
    std::mutex main_lock;
    std::condition_variable condition;
    std::condition_variable wait_condition;
    volatile bool stop_flag = false;

public:
    default_thread_pool(std::size_t n) : status(n, thread_status::WAITING) {
        for(std::size_t t = 0; t < n; ++t){
            threads.emplace_back([this, t]{
                while(true){
                    std::function<void()> task;

                    {
                        std::unique_lock<std::mutex> ulock(main_lock);

                        status[t] = thread_status::WAITING;

                        wait_condition.notify_one();

                        condition.wait(ulock, [this]{ return stop_flag || !tasks.empty(); });

                        if(stop_flag && tasks.empty()){
                            return;
                        }

                        task = std::move(tasks.front());
                        tasks.pop_front();

                        status[t] = thread_status::WORKING;
                    }

                    task();
                }
            });
        }
    }

    default_thread_pool() : default_thread_pool(std::thread::hardware_concurrency()) {}

    ~default_thread_pool(){
        with_lock(main_lock, [this]{ stop_flag = true; });

        condition.notify_all();

        for(auto& thread : threads){
            thread.join();
        }
    }

    void wait(){
        while(true){
            std::unique_lock<std::mutex> ulock(main_lock);

            if(tasks.empty() && std::find(status.begin(), status.end(), thread_status::WORKING) == status.end()){
                return;
            }

            //At this point, there are still some threads working, we wait for
            //one of them to notify a change of status
            wait_condition.wait(ulock, [this]{ return tasks.empty(); });
        }
    }

    template<class Functor, typename... Args>
    void do_task(Functor&& fun, Args&&... args){
        with_lock(main_lock, [fun, &args..., this](){
            if(stop_flag){
                throw std::runtime_error("enqueue on stopped ThreadPool");
            }

            tasks.emplace_back([&fun, args...]{ fun(args...); });
        });

        condition.notify_one();
    }
};

} //end of the cpp namespace

#endif //CPP_UTILS_PARALLEL_HPP
<commit_msg>Fixes<commit_after>//=======================================================================
// Copyright (c) 2013-2014 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef CPP_UTILS_PARALLEL_HPP
#define CPP_UTILS_PARALLEL_HPP

#include<thread>
#include<future>
#include<vector>
#include<deque>
#include<functional>
#include<algorithm>

namespace cpp {

//Utilities

template<typename Lock, typename Functor>
void with_lock(Lock& lock, Functor&& fun){
    std::unique_lock<Lock> l(lock);
    fun();
}

//Normal parallel_foreach versions

template<typename Iterator, typename Functor>
void parallel_foreach(Iterator first, Iterator last, Functor&& fun){
    std::vector<std::future<void>> futures;
    futures.reserve(std::distance(first, last));

    for(; first != last; ++first){
        futures.push_back(std::move(std::async(std::launch::async, fun, *first)));
    }

    //No need to wait for the futures, the destructor will do it for us
}

template<typename Iterator, typename Functor>
void parallel_foreach_i(Iterator first, Iterator last, Functor&& fun){
    std::vector<std::future<void>> futures;
    futures.reserve(std::distance(first, last));

    for(; first != last; ++first){
        futures.push_back(std::move(std::async(std::launch::async, fun, *first, futures.size())));
    }

    //No need to wait for the futures, the destructor will do it for us
}

template<typename Container, typename Functor>
void parallel_foreach_i(const Container& container, Functor&& fun){
    std::vector<std::future<void>> futures;
    futures.reserve(container.size());

    for(std::size_t i = 0; i < container.size(); ++i){
        futures.push_back(std::move(std::async(std::launch::async, fun, container[i], i)));
    }

    //No need to wait for the futures, the destructor will do it for us
}

//parallel_foreach Thread pool versions

template<typename TP, typename Iterator, typename Functor>
void parallel_foreach(TP& thread_pool, Iterator first, Iterator last, Functor&& fun){
    for(; first != last; ++first){
        thread_pool.do_task(std::forward<Functor>(fun), *first);
    }

    thread_pool.wait();
}

template<typename TP, typename Iterator, typename Functor>
void parallel_foreach_i(TP& thread_pool, Iterator first, Iterator last, Functor&& fun){
    for(std::size_t i = 0; first != last; ++first, ++i){
        thread_pool.do_task(std::forward<Functor>(fun), *first, i);
    }

    thread_pool.wait();
}

template<typename TP, typename Container, typename Functor>
void parallel_foreach_i(TP& thread_pool, const Container& container, Functor&& fun){
    for(std::size_t i = 0; i < container.size(); ++i){
        thread_pool.do_task(std::forward<Functor>(fun), container[i], i);
    }

    thread_pool.wait();
}

template<template<typename...> class queue_t = std::deque>
struct default_thread_pool {
    enum class thread_status {
        WAITING,
        WORKING
    };

private:
    std::vector<std::thread> threads;
    std::vector<thread_status> status;
    queue_t<std::function<void()>> tasks;
    std::mutex main_lock;
    std::condition_variable condition;
    std::condition_variable wait_condition;
    volatile bool stop_flag = false;

public:
    default_thread_pool(std::size_t n) : status(n, thread_status::WAITING) {
        for(std::size_t t = 0; t < n; ++t){
            threads.emplace_back([this, t]{
                while(true){
                    std::function<void()> task;

                    {
                        std::unique_lock<std::mutex> ulock(main_lock);

                        status[t] = thread_status::WAITING;

                        wait_condition.notify_one();

                        condition.wait(ulock, [this]{ return stop_flag || !tasks.empty(); });

                        if(stop_flag && tasks.empty()){
                            return;
                        }

                        task = std::move(tasks.front());
                        tasks.pop_front();

                        status[t] = thread_status::WORKING;
                    }

                    task();
                }
            });
        }
    }

    default_thread_pool() : default_thread_pool(std::thread::hardware_concurrency()) {}

    ~default_thread_pool(){
        with_lock(main_lock, [this]{ stop_flag = true; });

        condition.notify_all();

        for(auto& thread : threads){
            thread.join();
        }
    }

    void wait(){
        while(true){
            std::unique_lock<std::mutex> ulock(main_lock);

            if(tasks.empty() && std::find(status.begin(), status.end(), thread_status::WORKING) == status.end()){
                return;
            }

            //At this point, there are still some threads working, we wait for
            //one of them to notify a change of status
            wait_condition.wait(ulock, [this]{ return tasks.empty(); });
        }
    }

    template<class Functor, typename... Args>
    void do_task(Functor fun, Args&&... args){
        with_lock(main_lock, [fun, &args..., this](){
            if(stop_flag){
                throw std::runtime_error("enqueue on stopped ThreadPool");
            }

            tasks.emplace_back([fun, args...]{ fun(args...); });
        });

        condition.notify_one();
    }
};

} //end of the cpp namespace

#endif //CPP_UTILS_PARALLEL_HPP
<|endoftext|>


<commit_before>#include "SqPack.h"

namespace xiv {
namespace dat {
   struct SqPackHeader
   {
      char magic[0x8];
      uint32_t zero;
      uint32_t size;
      uint32_t version;
      uint32_t type;
   };

   struct SqPackIndexHeader
   {
      uint32_t size;
      uint32_t type;
   };
}
}
namespace xiv {
namespace utils {
namespace bparse {
   template <>
   inline void reorder<xiv::dat::SqPackHeader>(xiv::dat::SqPackHeader& i_struct)
   {
      for (int32_t i = 0; i < 0x8; ++i)
      {
         xiv::utils::bparse::reorder(i_struct.magic[i]);
      }
      xiv::utils::bparse::reorder(i_struct.zero);
      xiv::utils::bparse::reorder(i_struct.size);
      xiv::utils::bparse::reorder(i_struct.version);
      xiv::utils::bparse::reorder(i_struct.type);
   }

   template <>
   inline void reorder<xiv::dat::SqPackIndexHeader>(xiv::dat::SqPackIndexHeader& i_struct)
   {
      xiv::utils::bparse::reorder(i_struct.size);
      xiv::utils::bparse::reorder(i_struct.type);
   }
}
}
};

using xiv::utils::bparse::extract;

namespace xiv
{
namespace dat
{

   SqPack::SqPack( const std::experimental::filesystem::path& path ) :
      // Open the file
      m_handle( path.string(), std::ios_base::in | std::ios_base::binary )
   {
      // Extract the header
      extract<SqPackHeader>( m_handle );

      // Skip until the IndexHeader the extract it
      m_handle.seekg( 0x400 );
      extract<SqPackIndexHeader>( m_handle );
   }

   SqPack::~SqPack()
   {
   }

   void SqPack::isBlockValid( uint32_t i_offset, uint32_t i_size, const SqPackBlockHash& i_block_hash )
   {
      // TODO
   }

}
}
<commit_msg>bit of cleanup and sqpack fix<commit_after>#include "SqPack.h"

namespace xiv::dat {
  enum PlatformId :
    uint8_t
  {
    Win32,
    PS3,
    PS4
  };

  struct SqPackHeader
  {
    char magic[0x8];
    PlatformId platformId;
    uint8_t padding0[3];
    uint32_t size;
    uint32_t version;
    uint32_t type;
  };

  struct SqPackIndexHeader
  {
    uint32_t size;
    uint32_t type;
  };
}

namespace xiv::utils:: bparse
{
  template<>
  inline void reorder< xiv::dat::SqPackHeader >( xiv::dat::SqPackHeader& i_struct )
  {
    for( int32_t i = 0; i < 0x8; ++i )
    {
      xiv::utils::bparse::reorder( i_struct.magic[ i ] );
    }
    xiv::utils::bparse::reorder( i_struct.platformId );
    xiv::utils::bparse::reorder( i_struct.size );
    xiv::utils::bparse::reorder( i_struct.version );
    xiv::utils::bparse::reorder( i_struct.type );
  }

  template<>
  inline void reorder< xiv::dat::SqPackIndexHeader >( xiv::dat::SqPackIndexHeader& i_struct )
  {
    xiv::utils::bparse::reorder( i_struct.size );
    xiv::utils::bparse::reorder( i_struct.type );
  }
}

using xiv::utils::bparse::extract;

namespace xiv::dat
{

  // Open the file
  SqPack::SqPack( const std::experimental::filesystem::path& path ) :
    m_handle( path.string(), std::ios_base::in | std::ios_base::binary )
  {
    // Extract the header
    extract< SqPackHeader >( m_handle );

    // Skip until the IndexHeader the extract it
    m_handle.seekg( 0x400 );
    extract< SqPackIndexHeader >( m_handle );
  }

  SqPack::~SqPack()
  {
  }

  void SqPack::isBlockValid( uint32_t i_offset, uint32_t i_size, const SqPackBlockHash& i_block_hash )
  {
    // TODO
  }

}
<|endoftext|>


<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/document/test/make_bucket_space.h>
#include <vespa/storage/distributor/maintenance/node_maintenance_stats_tracker.h>
#include <vespa/vdstestlib/cppunit/macros.h>
#include <vespa/document/bucket/fixed_bucket_spaces.h>

namespace storage::distributor {

using document::test::makeBucketSpace;
using document::BucketSpace;

class NodeMaintenanceStatsTrackerTest : public CppUnit::TestFixture
{
    CPPUNIT_TEST_SUITE(NodeMaintenanceStatsTrackerTest);
    CPPUNIT_TEST(emptyStatsInstancesAreEqual);
    CPPUNIT_TEST(statsFieldsAffectEqualityComparison);
    CPPUNIT_TEST(requestingNonExistingNodeGivesEmptyStats);
    CPPUNIT_TEST(statsAreTrackedPerNode);
    CPPUNIT_TEST(statsAreTrackedPerBucketSpace);
    CPPUNIT_TEST_SUITE_END();

    void emptyStatsInstancesAreEqual();
    void statsFieldsAffectEqualityComparison();
    void requestingNonExistingNodeGivesEmptyStats();
    void statsAreTrackedPerNode();
    void statsAreTrackedPerBucketSpace();
    void assertBucketStats(BucketSpace bucketSpace, const NodeMaintenanceStatsTracker& tracker);
    void assertBucketStats(uint64_t expMovingOut, uint64_t expSyncing, uint64_t expCopyingIn, uint64_t expCopyingOut,
                           BucketSpace bucketSpace, const NodeMaintenanceStatsTracker& tracker);
};

CPPUNIT_TEST_SUITE_REGISTRATION(NodeMaintenanceStatsTrackerTest);

void
NodeMaintenanceStatsTrackerTest::emptyStatsInstancesAreEqual()
{
    NodeMaintenanceStats a;
    NodeMaintenanceStats b;
    CPPUNIT_ASSERT_EQUAL(a, b);
}

void
NodeMaintenanceStatsTrackerTest::statsFieldsAffectEqualityComparison()
{
    NodeMaintenanceStats a;
    NodeMaintenanceStats b;

    a.movingOut = 1;
    CPPUNIT_ASSERT(!(a == b));
    b.movingOut = 1;
    CPPUNIT_ASSERT(a == b);

    a.syncing = 1;
    CPPUNIT_ASSERT(!(a == b));
    b.syncing = 1;
    CPPUNIT_ASSERT(a == b);

    a.copyingIn = 1;
    CPPUNIT_ASSERT(!(a == b));
    b.copyingIn = 1;
    CPPUNIT_ASSERT(a == b);

    a.copyingOut = 1;
    CPPUNIT_ASSERT(!(a == b));
    b.copyingOut = 1;
    CPPUNIT_ASSERT(a == b);
}

void
NodeMaintenanceStatsTrackerTest::requestingNonExistingNodeGivesEmptyStats()
{
    NodeMaintenanceStatsTracker tracker;
    NodeMaintenanceStats wanted;
    CPPUNIT_ASSERT_EQUAL(wanted, tracker.forNode(0, makeBucketSpace()));
}

void
NodeMaintenanceStatsTrackerTest::statsAreTrackedPerNode()
{
    NodeMaintenanceStatsTracker tracker;
    NodeMaintenanceStats wanted;
    BucketSpace space(1);

    tracker.incMovingOut(0, space);
    wanted.movingOut = 1;
    CPPUNIT_ASSERT_EQUAL(wanted, tracker.forNode(0, space));
    wanted.movingOut = 0;
    CPPUNIT_ASSERT_EQUAL(wanted, tracker.forNode(1, space));

    tracker.incMovingOut(0, space);
    wanted.movingOut = 2;
    CPPUNIT_ASSERT_EQUAL(wanted, tracker.forNode(0, space));

    tracker.incMovingOut(1, space);
    wanted.movingOut = 1;
    CPPUNIT_ASSERT_EQUAL(wanted, tracker.forNode(1, space));

    tracker.incSyncing(1, space);
    tracker.incCopyingIn(1, space);
    tracker.incCopyingOut(1, space);
    wanted.syncing = 1;
    wanted.copyingIn = 1;
    wanted.copyingOut = 1;
    CPPUNIT_ASSERT_EQUAL(wanted, tracker.forNode(1, space));
}

void
NodeMaintenanceStatsTrackerTest::statsAreTrackedPerBucketSpace()
{
    NodeMaintenanceStatsTracker tracker;
    BucketSpace fooSpace(3);
    BucketSpace barSpace(5);

    tracker.incMovingOut(0, fooSpace);
    assertBucketStats(1, 0, 0, 0, fooSpace, tracker);
    assertBucketStats(barSpace, tracker);

    tracker.incMovingOut(0, barSpace);
    assertBucketStats(1, 0, 0, 0, fooSpace, tracker);
    assertBucketStats(1, 0, 0, 0, barSpace, tracker);

    tracker.incSyncing(0, fooSpace);
    assertBucketStats(1, 1, 0, 0, fooSpace, tracker);
    assertBucketStats(1, 0, 0, 0, barSpace, tracker);

    tracker.incCopyingIn(0, fooSpace);
    assertBucketStats(1, 1, 1, 0, fooSpace, tracker);
    assertBucketStats(1, 0, 0, 0, barSpace, tracker);

    tracker.incCopyingOut(0, fooSpace);
    assertBucketStats(1, 1, 1, 1, fooSpace, tracker);
    assertBucketStats(1, 0, 0, 0, barSpace, tracker);
}

void
NodeMaintenanceStatsTrackerTest::assertBucketStats(BucketSpace bucketSpace,
                                                   const NodeMaintenanceStatsTracker& tracker)
{
    NodeMaintenanceStats expStats;
    CPPUNIT_ASSERT_EQUAL(expStats, tracker.forNode(0, bucketSpace));
}

void
NodeMaintenanceStatsTrackerTest::assertBucketStats(uint64_t expMovingOut,
                                                   uint64_t expSyncing,
                                                   uint64_t expCopyingIn,
                                                   uint64_t expCopyingOut,
                                                   BucketSpace bucketSpace,
                                                   const NodeMaintenanceStatsTracker& tracker)
{
    NodeMaintenanceStats expStats(expMovingOut, expSyncing, expCopyingIn, expCopyingOut);
    CPPUNIT_ASSERT_EQUAL(expStats, tracker.forNode(0, bucketSpace));
}

}

<commit_msg>Rename function for clarity.<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/document/test/make_bucket_space.h>
#include <vespa/storage/distributor/maintenance/node_maintenance_stats_tracker.h>
#include <vespa/vdstestlib/cppunit/macros.h>
#include <vespa/document/bucket/fixed_bucket_spaces.h>

namespace storage::distributor {

using document::test::makeBucketSpace;
using document::BucketSpace;

class NodeMaintenanceStatsTrackerTest : public CppUnit::TestFixture
{
    CPPUNIT_TEST_SUITE(NodeMaintenanceStatsTrackerTest);
    CPPUNIT_TEST(emptyStatsInstancesAreEqual);
    CPPUNIT_TEST(statsFieldsAffectEqualityComparison);
    CPPUNIT_TEST(requestingNonExistingNodeGivesEmptyStats);
    CPPUNIT_TEST(statsAreTrackedPerNode);
    CPPUNIT_TEST(statsAreTrackedPerBucketSpace);
    CPPUNIT_TEST_SUITE_END();

    void emptyStatsInstancesAreEqual();
    void statsFieldsAffectEqualityComparison();
    void requestingNonExistingNodeGivesEmptyStats();
    void statsAreTrackedPerNode();
    void statsAreTrackedPerBucketSpace();
    void assertEmptyBucketStats(BucketSpace bucketSpace, const NodeMaintenanceStatsTracker& tracker);
    void assertBucketStats(uint64_t expMovingOut, uint64_t expSyncing, uint64_t expCopyingIn, uint64_t expCopyingOut,
                           BucketSpace bucketSpace, const NodeMaintenanceStatsTracker& tracker);
};

CPPUNIT_TEST_SUITE_REGISTRATION(NodeMaintenanceStatsTrackerTest);

void
NodeMaintenanceStatsTrackerTest::emptyStatsInstancesAreEqual()
{
    NodeMaintenanceStats a;
    NodeMaintenanceStats b;
    CPPUNIT_ASSERT_EQUAL(a, b);
}

void
NodeMaintenanceStatsTrackerTest::statsFieldsAffectEqualityComparison()
{
    NodeMaintenanceStats a;
    NodeMaintenanceStats b;

    a.movingOut = 1;
    CPPUNIT_ASSERT(!(a == b));
    b.movingOut = 1;
    CPPUNIT_ASSERT(a == b);

    a.syncing = 1;
    CPPUNIT_ASSERT(!(a == b));
    b.syncing = 1;
    CPPUNIT_ASSERT(a == b);

    a.copyingIn = 1;
    CPPUNIT_ASSERT(!(a == b));
    b.copyingIn = 1;
    CPPUNIT_ASSERT(a == b);

    a.copyingOut = 1;
    CPPUNIT_ASSERT(!(a == b));
    b.copyingOut = 1;
    CPPUNIT_ASSERT(a == b);
}

void
NodeMaintenanceStatsTrackerTest::requestingNonExistingNodeGivesEmptyStats()
{
    NodeMaintenanceStatsTracker tracker;
    NodeMaintenanceStats wanted;
    CPPUNIT_ASSERT_EQUAL(wanted, tracker.forNode(0, makeBucketSpace()));
}

void
NodeMaintenanceStatsTrackerTest::statsAreTrackedPerNode()
{
    NodeMaintenanceStatsTracker tracker;
    NodeMaintenanceStats wanted;
    BucketSpace space(1);

    tracker.incMovingOut(0, space);
    wanted.movingOut = 1;
    CPPUNIT_ASSERT_EQUAL(wanted, tracker.forNode(0, space));
    wanted.movingOut = 0;
    CPPUNIT_ASSERT_EQUAL(wanted, tracker.forNode(1, space));

    tracker.incMovingOut(0, space);
    wanted.movingOut = 2;
    CPPUNIT_ASSERT_EQUAL(wanted, tracker.forNode(0, space));

    tracker.incMovingOut(1, space);
    wanted.movingOut = 1;
    CPPUNIT_ASSERT_EQUAL(wanted, tracker.forNode(1, space));

    tracker.incSyncing(1, space);
    tracker.incCopyingIn(1, space);
    tracker.incCopyingOut(1, space);
    wanted.syncing = 1;
    wanted.copyingIn = 1;
    wanted.copyingOut = 1;
    CPPUNIT_ASSERT_EQUAL(wanted, tracker.forNode(1, space));
}

void
NodeMaintenanceStatsTrackerTest::statsAreTrackedPerBucketSpace()
{
    NodeMaintenanceStatsTracker tracker;
    BucketSpace fooSpace(3);
    BucketSpace barSpace(5);

    tracker.incMovingOut(0, fooSpace);
    assertBucketStats(1, 0, 0, 0, fooSpace, tracker);
    assertEmptyBucketStats(barSpace, tracker);

    tracker.incMovingOut(0, barSpace);
    assertBucketStats(1, 0, 0, 0, fooSpace, tracker);
    assertBucketStats(1, 0, 0, 0, barSpace, tracker);

    tracker.incSyncing(0, fooSpace);
    assertBucketStats(1, 1, 0, 0, fooSpace, tracker);
    assertBucketStats(1, 0, 0, 0, barSpace, tracker);

    tracker.incCopyingIn(0, fooSpace);
    assertBucketStats(1, 1, 1, 0, fooSpace, tracker);
    assertBucketStats(1, 0, 0, 0, barSpace, tracker);

    tracker.incCopyingOut(0, fooSpace);
    assertBucketStats(1, 1, 1, 1, fooSpace, tracker);
    assertBucketStats(1, 0, 0, 0, barSpace, tracker);
}

void
NodeMaintenanceStatsTrackerTest::assertEmptyBucketStats(BucketSpace bucketSpace,
                                                        const NodeMaintenanceStatsTracker& tracker)
{
    NodeMaintenanceStats expStats;
    CPPUNIT_ASSERT_EQUAL(expStats, tracker.forNode(0, bucketSpace));
}

void
NodeMaintenanceStatsTrackerTest::assertBucketStats(uint64_t expMovingOut,
                                                   uint64_t expSyncing,
                                                   uint64_t expCopyingIn,
                                                   uint64_t expCopyingOut,
                                                   BucketSpace bucketSpace,
                                                   const NodeMaintenanceStatsTracker& tracker)
{
    NodeMaintenanceStats expStats(expMovingOut, expSyncing, expCopyingIn, expCopyingOut);
    CPPUNIT_ASSERT_EQUAL(expStats, tracker.forNode(0, bucketSpace));
}

}

<|endoftext|>