<commit_before>// Copyright (c) 2019 ASMlover. 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 ofconditions 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 materialsprovided with the
//    distribution.
//
// 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 HOLDER 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.
#pragma once

#include <functional>
#include "helper.hh"

namespace wrencc {

template <typename Tp> class ArrayList final : public Copyable {
public:
  using ValueType = Tp;
  using Iter      = Tp*;
  using ConstIter = const Tp*;
  using Ptr       = Tp*;
  using ConstPtr  = const Tp*;
  using Ref       = Tp&;
  using ConstRef  = const Tp&;
private:
  using Alloc     = SimpleAlloc<ValueType>;

  static constexpr sz_t kDefCapacity = 0x10;

  sz_t size_{};
  sz_t capacity_{kDefCapacity};
  Ptr data_{};

  void regrow(sz_t new_capacity = 0) {
    if (new_capacity == 0)
      new_capacity = capacity_ * 3 / 2;
    if (new_capacity < kDefCapacity)
      new_capacity = kDefCapacity;

    Ptr new_data = Alloc::allocate(new_capacity);
    try {
      uninitialized_copy(begin(), end(), new_data);
    }
    catch (...) {
      destroy(new_data, new_data + size_);
      Alloc::deallocate(new_data);
      throw;
    }

    destroy(begin(), end());
    Alloc::deallocate(data_);

    capacity_ = new_capacity;
    data_ = new_data;
  }

  void destroy_aux() noexcept {
    clear();
    Alloc::deallocate(data_);
  }
public:
  ArrayList(sz_t capacity = kDefCapacity) noexcept
    : capacity_(capacity < kDefCapacity ? kDefCapacity : capacity) {
    data_ = Alloc::allocate(capacity_);
  }

  ~ArrayList() noexcept {
    destroy_aux();
  }

  ArrayList(sz_t count, const ValueType& value) noexcept
    : size_(count)
    , capacity_(count < kDefCapacity ? kDefCapacity : count) {
    data_ = Alloc::allocate(capacity_);
    uninitialized_fill(begin(), size_, value);
  }

  ArrayList(const ArrayList<Tp>& r) noexcept
    : size_(r.size_)
    , capacity_(r.capacity_) {
    data_ = Alloc::allocate(capacity_);
    uninitialized_copy(r.begin(), r.end(), begin());
  }

  ArrayList(ArrayList<Tp>&& r) noexcept {
    r.swap(*this);
  }

  inline ArrayList<Tp>& operator=(const ArrayList<Tp>& r) noexcept {
    if (this != &r) {
      destroy_aux();

      size_ = r.size_;
      capacity = r.capacity_;
      data_ = Alloc::allocate(capacity_);
      uninitialized_copy(r.begin(), r.end(), begin());
    }
    return *this;
  }

  inline ArrayList<Tp>& operator=(ArrayList<Tp>&& r) noexcept {
    if (this != &r) {
      destroy_aux();

      r.swap(*this);
    }
    return *this;
  }

  inline bool empty() const noexcept { return size_ == 0; }
  inline sz_t size() const noexcept { return size_; }
  inline sz_t capacity() const noexcept { return capacity_; }
  inline Ptr data() noexcept { return data_; }
  inline ConstPtr data() const noexcept { return data_; }
  inline Ref at(sz_t i) noexcept { return data_[i]; }
  inline ConstRef at(sz_t i) const noexcept { return data_[i]; }
  inline Ref operator[](sz_t i) noexcept { return data_[i]; }
  inline ConstRef operator[](sz_t i) const noexcept { return data_[i]; }
  inline Iter begin() noexcept { return data_; }
  inline ConstIter begin() const noexcept { return data_; }
  inline Iter end() noexcept { return data_ + size_; }
  inline ConstIter end() const noexcept { return data_ + size_; }
  inline Ref get_head() noexcept { return *begin(); }
  inline ConstRef get_head() const noexcept { return *begin(); }
  inline Ref get_tail() noexcept { return *(end() - 1); }
  inline ConstRef get_tail() const noexcept { return *(end() - 1); }

  inline void clear() noexcept {
    destroy(begin(), end());
    size_ = 0;
  }

  void swap(ArrayList<Tp>& r) noexcept {
    std::swap(size_, r.size_);
    std::swap(capacity_, r.capacity_);
    std::swap(data_, r.data_);
  }

  void resize(sz_t size) {
    if (size > size_) {
      regrow(size * 3 / 2);
    }
    else if (size < size_) {
      destroy(begin() + size, end());
      size_ = size;
    }
  }

  void append(const ValueType& x) {
    if (size_ >= capacity_)
      regrow();
    construct(&data_[size_++], x);
  }

  void append(ValueType&& x) {
    if (size_ >= capacity_)
      regrow();
    construct(&data_[size_++], std::move(x));
  }

  template <typename... Args> void append(Args&&... args) {
    if (size_ >= capacity_)
      regrow();
    construct(&data_[size_++], std::forward<Args>(args)...);
  }

  ValueType pop() {
    ValueType r = data_[size_ - 1];
    destroy(&data_[--size_]);
    return r;
  }

  template <typename Visitor> void for_each(Visitor&& visitor) noexcept {
    for (sz_t i = 0; i < size_; ++i)
      visitor(data_[i]);
  }
};

}
<commit_msg>:construction: chore(array-list): updated the array-list implementation<commit_after>// Copyright (c) 2019 ASMlover. 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 ofconditions 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 materialsprovided with the
//    distribution.
//
// 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 HOLDER 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.
#pragma once

#include <functional>
#include "helper.hh"

namespace wrencc {

template <typename Tp> class ArrayList final : public Copyable {
public:
  using ValueType = Tp;
  using Iter      = Tp*;
  using ConstIter = const Tp*;
  using Ptr       = Tp*;
  using ConstPtr  = const Tp*;
  using Ref       = Tp&;
  using ConstRef  = const Tp&;
private:
  using Alloc     = SimpleAlloc<ValueType>;

  static constexpr sz_t kDefCapacity = 0x10;

  sz_t size_{};
  sz_t capacity_{kDefCapacity};
  Ptr data_{};

  void regrow(sz_t new_capacity = 0) {
    if (new_capacity == 0)
      new_capacity = capacity_ * 3 / 2;
    if (new_capacity < kDefCapacity)
      new_capacity = kDefCapacity;

    Ptr new_data = Alloc::allocate(new_capacity);
    try {
      uninitialized_copy(begin(), end(), new_data);
    }
    catch (...) {
      destroy(new_data, new_data + size_);
      Alloc::deallocate(new_data);
      throw;
    }

    destroy(begin(), end());
    Alloc::deallocate(data_);

    capacity_ = new_capacity;
    data_ = new_data;
  }

  void destructor_aux() noexcept {
    clear();
    Alloc::deallocate(data_);
  }

  void insert_aux(ConstIter pos, const ValueType& val) {
    Ptr p = data_ + (pos - begin());
    if (size_ < capacity_) {
      if (p == data_ + size_) {
        construct(data_ + size_, val);
      }
      else {
        construct(data_ + size_, *(data_ + size_ - 1));
        ++size_;
        copy_backward(p, data_ + size_ - 2, data_ + size_ - 1);
        *p = val;
      }
    }
    else {
      sz_t old_size = size_;
      sz_t new_capacity = capacity_ * 3 / 2;
      Ptr new_data = Alloc::allocate(new_capacity);
      try {
        uninitialized_copy(data_, p, new_data);
        construct(p, val);
        ++size_;
        uninitialized_copy(p, data_ + old_size, p + 1);
      }
      catch (...) {
        destroy(new_data, new_data + old_size + 1);
        Alloc::deallocate(new_data);
        throw;
      }

      destroy(begin(), end());
      Alloc::deallocate(data_);

      capacity_ = new_capacity;
      data_ = new_data;
    }
  }
public:
  ArrayList(sz_t capacity = kDefCapacity) noexcept
    : capacity_(capacity < kDefCapacity ? kDefCapacity : capacity) {
    data_ = Alloc::allocate(capacity_);
  }

  ~ArrayList() noexcept {
    destructor_aux();
  }

  ArrayList(sz_t count, const ValueType& value) noexcept
    : size_(count)
    , capacity_(count < kDefCapacity ? kDefCapacity : count) {
    data_ = Alloc::allocate(capacity_);
    uninitialized_fill(begin(), size_, value);
  }

  ArrayList(const ArrayList<Tp>& r) noexcept
    : size_(r.size_)
    , capacity_(r.capacity_) {
    data_ = Alloc::allocate(capacity_);
    uninitialized_copy(r.begin(), r.end(), begin());
  }

  ArrayList(ArrayList<Tp>&& r) noexcept {
    r.swap(*this);
  }

  inline ArrayList<Tp>& operator=(const ArrayList<Tp>& r) noexcept {
    if (this != &r) {
      destroy_aux();

      size_ = r.size_;
      capacity = r.capacity_;
      data_ = Alloc::allocate(capacity_);
      uninitialized_copy(r.begin(), r.end(), begin());
    }
    return *this;
  }

  inline ArrayList<Tp>& operator=(ArrayList<Tp>&& r) noexcept {
    if (this != &r) {
      destroy_aux();

      r.swap(*this);
    }
    return *this;
  }

  inline bool empty() const noexcept { return size_ == 0; }
  inline sz_t size() const noexcept { return size_; }
  inline sz_t capacity() const noexcept { return capacity_; }
  inline Ptr data() noexcept { return data_; }
  inline ConstPtr data() const noexcept { return data_; }
  inline Ref at(sz_t i) noexcept { return data_[i]; }
  inline ConstRef at(sz_t i) const noexcept { return data_[i]; }
  inline Ref operator[](sz_t i) noexcept { return data_[i]; }
  inline ConstRef operator[](sz_t i) const noexcept { return data_[i]; }
  inline Iter begin() noexcept { return data_; }
  inline ConstIter begin() const noexcept { return data_; }
  inline Iter end() noexcept { return data_ + size_; }
  inline ConstIter end() const noexcept { return data_ + size_; }
  inline Ref get_head() noexcept { return *begin(); }
  inline ConstRef get_head() const noexcept { return *begin(); }
  inline Ref get_tail() noexcept { return *(end() - 1); }
  inline ConstRef get_tail() const noexcept { return *(end() - 1); }

  inline void clear() noexcept {
    destroy(begin(), end());
    size_ = 0;
  }

  void swap(ArrayList<Tp>& r) noexcept {
    std::swap(size_, r.size_);
    std::swap(capacity_, r.capacity_);
    std::swap(data_, r.data_);
  }

  void resize(sz_t size) {
    if (size > size_) {
      regrow(size * 3 / 2);
    }
    else if (size < size_) {
      destroy(begin() + size, end());
      size_ = size;
    }
  }

  void append(const ValueType& x) {
    if (size_ >= capacity_)
      regrow();
    construct(&data_[size_++], x);
  }

  void append(ValueType&& x) {
    if (size_ >= capacity_)
      regrow();
    construct(&data_[size_++], std::move(x));
  }

  template <typename... Args> void append(Args&&... args) {
    if (size_ >= capacity_)
      regrow();
    construct(&data_[size_++], std::forward<Args>(args)...);
  }

  ValueType pop() {
    ValueType r = data_[size_ - 1];
    destroy(&data_[--size_]);
    return r;
  }

  void insert(ConstIter pos, const ValueType& x) {
    insert_aux(pos, x);
  }

  void erase(ConstIter pos) {
    if (pos + 1 != end())
      copy(pos + 1, data_ + size_, pos);
    --size_;
    destroy(data_ + size_);
  }

  template <typename Visitor> void for_each(Visitor&& visitor) noexcept {
    for (sz_t i = 0; i < size_; ++i)
      visitor(data_[i]);
  }
};

}
<|endoftext|>


<commit_before>#include "LocalPlayer.hpp"

LocalPlayer::LocalPlayer(
	std::string name,
	OgreBulletDynamics::DynamicsWorld *world,
	BombManager *bombManager,
	CameraManager *cameraManager
):
	OgrePlayer(name, world, bombManager),
	mCameraManager(cameraManager),
	mBombCooldown(0),
	mPlayerEventListener(0),
	mStartingTarget(Ogre::Vector3::ZERO),
	mHadUsefullInput(false)
{
}

LocalPlayer::~LocalPlayer(){
}

void LocalPlayer::generateGraphics(){

	if(mGraphicsSetUp)
		return;

	using namespace Ogre;

	mEntity = mWorld->getSceneManager()->createEntity("bomberman.mesh");
	mEntity->setCastShadows(true);
	Vector3 size = computeHitboxSize();

	SceneNode *bodyNode = mWorld->getSceneManager()->getRootSceneNode()->createChildSceneNode();

	generateHitbox(size, bodyNode);

	mGraphicsSetUp = true;

}

void LocalPlayer::lookAt(Ogre::Vector3 vec){

	mCameraManager->lookAt(vec);

	mYaw = mCameraManager->getOrientation().getYaw().valueDegrees();
	mPitch = mCameraManager->getOrientation().getPitch().valueDegrees();
	mRoll = mCameraManager->getOrientation().getRoll().valueDegrees();

	mStartingTarget = vec;

}

bool LocalPlayer::injectMouseMove(const OIS::MouseEvent &arg){

	mYawCorrection += Ogre::Degree(-arg.state.X.rel * 0.15f);
	if(mCameraManager->getCameraMode() != "oculus")
		mPitchCorrection += Ogre::Degree(-arg.state.Y.rel * 0.15f);

	mHadUsefullInput = true;

	return true;

}

bool LocalPlayer::injectMouseDown(const OIS::MouseEvent &arg, OIS::MouseButtonID id){
	return true;
}

bool LocalPlayer::injectMouseUp(const OIS::MouseEvent &arg, OIS::MouseButtonID id){
	return true;
}

bool LocalPlayer::injectKeyDown(const OIS::KeyEvent &arg){

	if(mIsDead || mHasWon)
		return true;

	if (arg.key == OIS::KC_Z || arg.key == OIS::KC_UP)
		mGoingForward = true;
	else if (arg.key == OIS::KC_S || arg.key == OIS::KC_DOWN)
		mGoingBack = true;
	else if (arg.key == OIS::KC_Q || arg.key == OIS::KC_LEFT)
		mGoingLeft = true;
	else if (arg.key == OIS::KC_D || arg.key == OIS::KC_RIGHT)
		mGoingRight = true;
	else if (arg.key == OIS::KC_E || arg.key == OIS::KC_SPACE)
		mPuttingBomb = true;
	else if (arg.key == OIS::KC_PGUP)
		mGoingUp = true;
	else if (arg.key == OIS::KC_PGDOWN)
		mGoingDown = true;
	else if (arg.key == OIS::KC_LSHIFT)
		mFastMove = true;

	if(
		arg.key == OIS::KC_Z ||
		arg.key == OIS::KC_UP ||
		arg.key == OIS::KC_S ||
		arg.key == OIS::KC_DOWN ||
		arg.key == OIS::KC_Q ||
		arg.key == OIS::KC_LEFT ||
		arg.key == OIS::KC_D ||
		arg.key == OIS::KC_RIGHT ||
		arg.key == OIS::KC_E ||
		arg.key == OIS::KC_SPACE ||
		arg.key == OIS::KC_PGUP ||
		arg.key == OIS::KC_PGDOWN
	)
		mHadUsefullInput = true;

	return true;

}

bool LocalPlayer::injectKeyUp(const OIS::KeyEvent &arg){

	if(mIsDead || mHasWon)
		return true;

	if (arg.key == OIS::KC_Z || arg.key == OIS::KC_UP)
		mGoingForward = false;
	else if (arg.key == OIS::KC_S || arg.key == OIS::KC_DOWN)
		mGoingBack = false;
	else if (arg.key == OIS::KC_Q || arg.key == OIS::KC_LEFT)
		mGoingLeft = false;
	else if (arg.key == OIS::KC_D || arg.key == OIS::KC_RIGHT)
		mGoingRight = false;
	else if (arg.key == OIS::KC_E || arg.key == OIS::KC_SPACE)
		mPuttingBomb = false;
	else if (arg.key == OIS::KC_PGUP)
		mGoingUp = false;
	else if (arg.key == OIS::KC_PGDOWN)
		mGoingDown = false;
	else if (arg.key == OIS::KC_LSHIFT)
		mFastMove = false;

	if(
		arg.key == OIS::KC_Z ||
		arg.key == OIS::KC_UP ||
		arg.key == OIS::KC_S ||
		arg.key == OIS::KC_DOWN ||
		arg.key == OIS::KC_Q ||
		arg.key == OIS::KC_LEFT ||
		arg.key == OIS::KC_D ||
		arg.key == OIS::KC_RIGHT ||
		arg.key == OIS::KC_E ||
		arg.key == OIS::KC_SPACE ||
		arg.key == OIS::KC_PGUP ||
		arg.key == OIS::KC_PGDOWN
	)
		mHadUsefullInput = true;

	return true;

}

bool LocalPlayer::injectHeadMove(const Ogre::Vector3 &evt){

	mYawCorrection += Ogre::Radian(evt.x);
	mPitchCorrection  += Ogre::Radian(evt.y);
	mRollCorrection += Ogre::Radian(evt.z);
	mHadUsefullInput = true;

	return true;

}

bool LocalPlayer::frameRenderingQueued(const Ogre::FrameEvent &evt){

	computeAcceleration();
	computeVelocity(evt);
	computeNodePosition(evt);

	mBombCooldown -= evt.timeSinceLastFrame;

	if(mPuttingBomb && mBombCooldown <= 0) {
		mBombManager->add(mNickname + "bomb", Ogre::Vector3(getX() ,getY() ,getZ()) + getForwardDirection());
		mBombCooldown = 1;
	}

	mCameraManager->setPosition(Ogre::Vector3(mX, mY + 0.7, mZ));

	mCameraManager->yaw(mYawCorrection);
	mCameraManager->pitch(mPitchCorrection);
	mCameraManager->roll(mRollCorrection);

	resetCorrection();

	if(mPlayerEventListener && mHadUsefullInput){
		mPlayerEventListener->playerInput();
		mHadUsefullInput = false;
	}

	return true;

}

void LocalPlayer::setPlayerEventListener(PlayerEventListener *pel){
	mPlayerEventListener = pel;
}

void LocalPlayer::win(){

	if(mIsDead)
		return;

	mHasWon = true;

	mGoingForward = false;
	mGoingBack = false;
	mGoingLeft = false;
	mGoingRight = false;
	mGoingUp = false;
	mGoingDown = false;
	mFastMove = false;

	mX = mStartingX;
	mY = mStartingY + 10;
	mZ = mStartingZ;

	mWasTeleported = true;

	if(mPlayerEventListener)
		mPlayerEventListener->playerInput();

}

void LocalPlayer::die(){

	if(mHasWon)
		return;

	mIsDead = true;

	mGoingForward = false;
	mGoingBack = false;
	mGoingLeft = false;
	mGoingRight = false;
	mGoingUp = false;
	mGoingDown = false;
	mFastMove = false;

	mX = mStartingX;
	mY = mStartingY + 10;
	mZ = mStartingZ;

	mWasTeleported = true;

	if(mPlayerEventListener){
		mPlayerEventListener->playerInput();
		mPlayerEventListener->playerDied();
	}

}
<commit_msg>locked camera pitch between -90° and 90° when using the mouse only<commit_after>#include "LocalPlayer.hpp"

LocalPlayer::LocalPlayer(
	std::string name,
	OgreBulletDynamics::DynamicsWorld *world,
	BombManager *bombManager,
	CameraManager *cameraManager
):
	OgrePlayer(name, world, bombManager),
	mCameraManager(cameraManager),
	mBombCooldown(0),
	mPlayerEventListener(0),
	mStartingTarget(Ogre::Vector3::ZERO),
	mHadUsefullInput(false)
{
}

LocalPlayer::~LocalPlayer(){
}

void LocalPlayer::generateGraphics(){

	if(mGraphicsSetUp)
		return;

	using namespace Ogre;

	mEntity = mWorld->getSceneManager()->createEntity("bomberman.mesh");
	mEntity->setCastShadows(true);
	Vector3 size = computeHitboxSize();

	SceneNode *bodyNode = mWorld->getSceneManager()->getRootSceneNode()->createChildSceneNode();

	generateHitbox(size, bodyNode);

	mGraphicsSetUp = true;

}

void LocalPlayer::lookAt(Ogre::Vector3 vec){

	mCameraManager->lookAt(vec);

	mYaw = mCameraManager->getOrientation().getYaw().valueDegrees();
	mPitch = mCameraManager->getOrientation().getPitch().valueDegrees();
	mRoll = mCameraManager->getOrientation().getRoll().valueDegrees();

	mStartingTarget = vec;

}

bool LocalPlayer::injectMouseMove(const OIS::MouseEvent &arg){

	mYawCorrection += Ogre::Degree(-arg.state.X.rel * 0.15f);

	if(mCameraManager->getCameraMode() != "oculus"){

		mPitchCorrection += Ogre::Degree(-arg.state.Y.rel * 0.15f);
		if(
			(Ogre::Degree(mPitch) + mPitchCorrection).valueDegrees() < -90 ||
			(Ogre::Degree(mPitch) + mPitchCorrection).valueDegrees() > 90
		)
			mPitchCorrection = 0;

	}

	mHadUsefullInput = true;

	return true;

}

bool LocalPlayer::injectMouseDown(const OIS::MouseEvent &arg, OIS::MouseButtonID id){
	return true;
}

bool LocalPlayer::injectMouseUp(const OIS::MouseEvent &arg, OIS::MouseButtonID id){
	return true;
}

bool LocalPlayer::injectKeyDown(const OIS::KeyEvent &arg){

	if(mIsDead || mHasWon)
		return true;

	if (arg.key == OIS::KC_Z || arg.key == OIS::KC_UP)
		mGoingForward = true;
	else if (arg.key == OIS::KC_S || arg.key == OIS::KC_DOWN)
		mGoingBack = true;
	else if (arg.key == OIS::KC_Q || arg.key == OIS::KC_LEFT)
		mGoingLeft = true;
	else if (arg.key == OIS::KC_D || arg.key == OIS::KC_RIGHT)
		mGoingRight = true;
	else if (arg.key == OIS::KC_E || arg.key == OIS::KC_SPACE)
		mPuttingBomb = true;
	else if (arg.key == OIS::KC_PGUP)
		mGoingUp = true;
	else if (arg.key == OIS::KC_PGDOWN)
		mGoingDown = true;
	else if (arg.key == OIS::KC_LSHIFT)
		mFastMove = true;

	if(
		arg.key == OIS::KC_Z ||
		arg.key == OIS::KC_UP ||
		arg.key == OIS::KC_S ||
		arg.key == OIS::KC_DOWN ||
		arg.key == OIS::KC_Q ||
		arg.key == OIS::KC_LEFT ||
		arg.key == OIS::KC_D ||
		arg.key == OIS::KC_RIGHT ||
		arg.key == OIS::KC_E ||
		arg.key == OIS::KC_SPACE ||
		arg.key == OIS::KC_PGUP ||
		arg.key == OIS::KC_PGDOWN
	)
		mHadUsefullInput = true;

	return true;

}

bool LocalPlayer::injectKeyUp(const OIS::KeyEvent &arg){

	if(mIsDead || mHasWon)
		return true;

	if (arg.key == OIS::KC_Z || arg.key == OIS::KC_UP)
		mGoingForward = false;
	else if (arg.key == OIS::KC_S || arg.key == OIS::KC_DOWN)
		mGoingBack = false;
	else if (arg.key == OIS::KC_Q || arg.key == OIS::KC_LEFT)
		mGoingLeft = false;
	else if (arg.key == OIS::KC_D || arg.key == OIS::KC_RIGHT)
		mGoingRight = false;
	else if (arg.key == OIS::KC_E || arg.key == OIS::KC_SPACE)
		mPuttingBomb = false;
	else if (arg.key == OIS::KC_PGUP)
		mGoingUp = false;
	else if (arg.key == OIS::KC_PGDOWN)
		mGoingDown = false;
	else if (arg.key == OIS::KC_LSHIFT)
		mFastMove = false;

	if(
		arg.key == OIS::KC_Z ||
		arg.key == OIS::KC_UP ||
		arg.key == OIS::KC_S ||
		arg.key == OIS::KC_DOWN ||
		arg.key == OIS::KC_Q ||
		arg.key == OIS::KC_LEFT ||
		arg.key == OIS::KC_D ||
		arg.key == OIS::KC_RIGHT ||
		arg.key == OIS::KC_E ||
		arg.key == OIS::KC_SPACE ||
		arg.key == OIS::KC_PGUP ||
		arg.key == OIS::KC_PGDOWN
	)
		mHadUsefullInput = true;

	return true;

}

bool LocalPlayer::injectHeadMove(const Ogre::Vector3 &evt){

	mYawCorrection += Ogre::Radian(evt.x);
	mPitchCorrection  += Ogre::Radian(evt.y);
	mRollCorrection += Ogre::Radian(evt.z);
	mHadUsefullInput = true;

	return true;

}

bool LocalPlayer::frameRenderingQueued(const Ogre::FrameEvent &evt){

	computeAcceleration();
	computeVelocity(evt);
	computeNodePosition(evt);

	mBombCooldown -= evt.timeSinceLastFrame;

	if(mPuttingBomb && mBombCooldown <= 0) {
		mBombManager->add(mNickname + "bomb", Ogre::Vector3(getX() ,getY() ,getZ()) + getForwardDirection());
		mBombCooldown = 1;
	}

	mCameraManager->setPosition(Ogre::Vector3(mX, mY + 0.7, mZ));

	mCameraManager->yaw(mYawCorrection);
	mCameraManager->pitch(mPitchCorrection);
	mCameraManager->roll(mRollCorrection);

	resetCorrection();

	if(mPlayerEventListener && mHadUsefullInput){
		mPlayerEventListener->playerInput();
		mHadUsefullInput = false;
	}

	return true;

}

void LocalPlayer::setPlayerEventListener(PlayerEventListener *pel){
	mPlayerEventListener = pel;
}

void LocalPlayer::win(){

	if(mIsDead)
		return;

	mHasWon = true;

	mGoingForward = false;
	mGoingBack = false;
	mGoingLeft = false;
	mGoingRight = false;
	mGoingUp = false;
	mGoingDown = false;
	mFastMove = false;

	mX = mStartingX;
	mY = mStartingY + 10;
	mZ = mStartingZ;

	mWasTeleported = true;

	if(mPlayerEventListener)
		mPlayerEventListener->playerInput();

}

void LocalPlayer::die(){

	if(mHasWon)
		return;

	mIsDead = true;

	mGoingForward = false;
	mGoingBack = false;
	mGoingLeft = false;
	mGoingRight = false;
	mGoingUp = false;
	mGoingDown = false;
	mFastMove = false;

	mX = mStartingX;
	mY = mStartingY + 10;
	mZ = mStartingZ;

	mWasTeleported = true;

	if(mPlayerEventListener){
		mPlayerEventListener->playerInput();
		mPlayerEventListener->playerDied();
	}

}
<|endoftext|>


<commit_before>/*
  LoraEncoder.cpp - Base class for the Lora serialization library

  The MIT License (MIT)

  Copyright (c) 2016 Joscha Feth

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.

  History:
  20220309 MPr: added writeUint32()

*/

#if ARDUINO >= 100
    #include "Arduino.h"
#endif
#include "LoraEncoder.h"

LoraEncoder::LoraEncoder(byte *buffer) {
  _buffer = buffer;
}

void LoraEncoder::_intToBytes(byte *buf, int32_t i, uint8_t byteSize) {
    for(uint8_t x = 0; x < byteSize; x++) {
        buf[x] = (byte) (i >> (x*8));
    }
}

void LoraEncoder::writeUnixtime(uint32_t unixtime) {
    _intToBytes(_buffer, unixtime, 4);
    _buffer += 4;
}

void LoraEncoder::writeLatLng(double latitude, double longitude) {
    int32_t lat = latitude * 1e6;
    int32_t lng = longitude * 1e6;

    _intToBytes(_buffer, lat, 4);
    _intToBytes(_buffer + 4, lng, 4);
    _buffer += 8;
}

// MPr: added
void LoraEncoder::writeUint32(uint32_t i) {
    _intToBytes(_buffer, i, 4);
    _buffer += 4;
}

void LoraEncoder::writeUint16(uint16_t i) {
    _intToBytes(_buffer, i, 2);
    _buffer += 2;
}

void LoraEncoder::writeUint8(uint8_t i) {
    _intToBytes(_buffer, i, 1);
    _buffer += 1;
}

void LoraEncoder::writeHumidity(float humidity) {
    int16_t h = (int16_t) (humidity * 100);
    _intToBytes(_buffer, h, 2);
    _buffer += 2;
}

/**
* Uses a 16bit two's complement with two decimals, so the range is
* -327.68 to +327.67 degrees
*/
void LoraEncoder::writeTemperature(float temperature) {
    int16_t t = (int16_t) (temperature * 100);
    if (temperature < 0) {
        t = ~-t;
        t = t + 1;
    }
    _buffer[0] = (byte) ((t >> 8) & 0xFF);
    _buffer[1] = (byte) t & 0xFF;
    _buffer += 2;
}

void LoraEncoder::writeBitmap(bool a, bool b, bool c, bool d, bool e, bool f, bool g, bool h) {
    uint8_t bitmap = 0;
    // LSB first
    bitmap |= (a & 1) << 7;
    bitmap |= (b & 1) << 6;
    bitmap |= (c & 1) << 5;
    bitmap |= (d & 1) << 4;
    bitmap |= (e & 1) << 3;
    bitmap |= (f & 1) << 2;
    bitmap |= (g & 1) << 1;
    bitmap |= (h & 1) << 0;
    writeUint8(bitmap);
}

void LoraEncoder::writeRawFloat(float value) {
  uint32_t asbytes=*(reinterpret_cast<uint32_t*>(&value));
  _intToBytes(_buffer, asbytes, 4);
  _buffer += 4;
}
<commit_msg>Update LoraEncoder.cpp<commit_after>/*
  LoraEncoder.cpp - Base class for the Lora serialization library

  The MIT License (MIT)

  Copyright (c) 2016 Joscha Feth

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.

*/

#if ARDUINO >= 100
    #include "Arduino.h"
#endif
#include "LoraEncoder.h"

LoraEncoder::LoraEncoder(byte *buffer) {
  _buffer = buffer;
}

void LoraEncoder::_intToBytes(byte *buf, int32_t i, uint8_t byteSize) {
    for(uint8_t x = 0; x < byteSize; x++) {
        buf[x] = (byte) (i >> (x*8));
    }
}

void LoraEncoder::writeUnixtime(uint32_t unixtime) {
    _intToBytes(_buffer, unixtime, 4);
    _buffer += 4;
}

void LoraEncoder::writeLatLng(double latitude, double longitude) {
    int32_t lat = latitude * 1e6;
    int32_t lng = longitude * 1e6;

    _intToBytes(_buffer, lat, 4);
    _intToBytes(_buffer + 4, lng, 4);
    _buffer += 8;
}

void LoraEncoder::writeUint32(uint32_t i) {
    _intToBytes(_buffer, i, 4);
    _buffer += 4;
}

void LoraEncoder::writeUint16(uint16_t i) {
    _intToBytes(_buffer, i, 2);
    _buffer += 2;
}

void LoraEncoder::writeUint8(uint8_t i) {
    _intToBytes(_buffer, i, 1);
    _buffer += 1;
}

void LoraEncoder::writeHumidity(float humidity) {
    int16_t h = (int16_t) (humidity * 100);
    _intToBytes(_buffer, h, 2);
    _buffer += 2;
}

/**
* Uses a 16bit two's complement with two decimals, so the range is
* -327.68 to +327.67 degrees
*/
void LoraEncoder::writeTemperature(float temperature) {
    int16_t t = (int16_t) (temperature * 100);
    if (temperature < 0) {
        t = ~-t;
        t = t + 1;
    }
    _buffer[0] = (byte) ((t >> 8) & 0xFF);
    _buffer[1] = (byte) t & 0xFF;
    _buffer += 2;
}

void LoraEncoder::writeBitmap(bool a, bool b, bool c, bool d, bool e, bool f, bool g, bool h) {
    uint8_t bitmap = 0;
    // LSB first
    bitmap |= (a & 1) << 7;
    bitmap |= (b & 1) << 6;
    bitmap |= (c & 1) << 5;
    bitmap |= (d & 1) << 4;
    bitmap |= (e & 1) << 3;
    bitmap |= (f & 1) << 2;
    bitmap |= (g & 1) << 1;
    bitmap |= (h & 1) << 0;
    writeUint8(bitmap);
}

void LoraEncoder::writeRawFloat(float value) {
  uint32_t asbytes=*(reinterpret_cast<uint32_t*>(&value));
  _intToBytes(_buffer, asbytes, 4);
  _buffer += 4;
}
<|endoftext|>


<commit_before>
#include "condor_common.h"

#include "singularity.h"

#include <vector>

#include "condor_config.h"
#include "my_popen.h"
#include "CondorError.h"
#include "basename.h"

using namespace htcondor;

bool Singularity::m_enabled = false;
bool Singularity::m_probed = false;
int  Singularity::m_default_timeout = 120;
MyString Singularity::m_singularity_version;

static bool find_singularity(std::string &exec)
{
#ifdef LINUX
	std::string singularity;
	if (!param(singularity, "SINGULARITY")) {
		dprintf(D_ALWAYS | D_FAILURE, "SINGULARITY is undefined.\n");
		return false;
	}
	exec = singularity;
	return true;
#else
	(void) exec;
	return false;
#endif
}

bool
Singularity::advertise(ClassAd &ad)
{
	if (m_enabled && ad.InsertAttr("HasSingularity", true)) {
		return false;
	}
	if (!m_singularity_version.empty() && ad.InsertAttr("SingularityVersion", m_singularity_version)) {
		return false;
	}
	return true;
}

bool
Singularity::enabled()
{
	CondorError err;
	return detect(err);
}

const char *
Singularity::version()
{
	CondorError err;
	if (!detect(err)) {return NULL;}
	return m_singularity_version.c_str();
}

bool
Singularity::detect(CondorError &err)
{
	if (m_probed) {return m_enabled;}

	m_probed = true;
	ArgList infoArgs;
	std::string exec;
	if (!find_singularity(exec)) {
		return false;
	}
	infoArgs.AppendArg(exec);
	infoArgs.AppendArg("--version");

	MyString displayString;
	infoArgs.GetArgsStringForLogging( & displayString );
	dprintf(D_FULLDEBUG, "Attempting to run: '%s %s'.\n", exec.c_str(), displayString.c_str());

	MyPopenTimer pgm;
	if (pgm.start_program(infoArgs, true, NULL, false) < 0) {
		// treat 'file not found' as not really error
		int d_level = D_FULLDEBUG;
		if (pgm.error_code() != ENOENT) {
			d_level = D_ALWAYS | D_FAILURE;
			err.pushf("Singularity::detect", 1, "Failed to run '%s' errno = %d %s.", displayString.c_str(), pgm.error_code(), pgm.error_str());
		}
		dprintf(d_level, "Failed to run '%s' errno=%d %s.\n", displayString.c_str(), pgm.error_code(), pgm.error_str() );
		return false;
	}

	int exitCode;
	if ( ! pgm.wait_for_exit(m_default_timeout, &exitCode) || exitCode != 0) {
		pgm.close_program(1);
		MyString line;
		line.readLine(pgm.output(), false); line.chomp();
		dprintf( D_ALWAYS, "'%s' did not exit successfully (code %d); the first line of output was '%s'.\n", displayString.c_str(), exitCode, line.c_str());
		err.pushf("Singularity::detect", 2, "'%s' exited with status %d", displayString.c_str(), exitCode);
		return false;
	}

	m_singularity_version.readLine(pgm.output(), false);
	m_singularity_version.chomp();
	dprintf( D_FULLDEBUG, "[singularity version] %s\n", m_singularity_version.c_str() );
	if (IsFulldebug(D_ALWAYS)) {
		MyString line;
		while (line.readLine(pgm.output(), false)) {
			line.readLine(pgm.output(), false);
			line.chomp();
			dprintf( D_FULLDEBUG, "[singularity info] %s\n", line.c_str() );
		}
	}

	m_enabled = ! m_singularity_version.empty();

	return true;
}

bool
Singularity::job_enabled(ClassAd &machineAd, ClassAd &jobAd)
{
	return param_boolean("SINGULARITY_JOB", false, false, &machineAd, &jobAd);
}

Singularity::result
Singularity::setup(ClassAd &machineAd,
		ClassAd &jobAd,
		std::string &exec,
		ArgList &job_args,
		const std::string &job_iwd,
		const std::string &execute_dir,
		Env &job_env)
{
	ArgList sing_args;

	if (!param_boolean("SINGULARITY_JOB", false, false, &machineAd, &jobAd)) {return Singularity::DISABLE;}

	if (!enabled()) {
		dprintf(D_ALWAYS, "Singularity job has been requested but singularity does not appear to be configured on this host.\n");
		return Singularity::FAILURE;
	}
	std::string sing_exec_str;
	if (!find_singularity(sing_exec_str)) {
		return Singularity::FAILURE;
	}

	std::string image;
	if (!param_eval_string(image, "SINGULARITY_IMAGE_EXPR", "SingularityImage", &machineAd, &jobAd)) {
		dprintf(D_ALWAYS, "Singularity support was requested but unable to determine the image to use.\n");
		return Singularity::FAILURE;
	}

	std::string target_dir;
	bool has_target = param(target_dir, "SINGULARITY_TARGET_DIR") && !target_dir.empty();

	job_args.RemoveArg(0);
	std::string orig_exec_val = exec;
	if (has_target && (orig_exec_val.compare(0, execute_dir.length(), execute_dir) == 0)) {
		exec = target_dir + "/" + orig_exec_val.substr(execute_dir.length());
		dprintf(D_FULLDEBUG, "Updated executable path to %s for target directory mode.\n", exec.c_str());
	}
	sing_args.AppendArg(sing_exec_str.c_str());
	sing_args.AppendArg("exec");

	// Bind
	// Mount under scratch
	std::string scratch;
	if (!param_eval_string(scratch, "MOUNT_UNDER_SCRATCH", "", &jobAd)) {
		param(scratch, "MOUNT_UNDER_SCRATCH");
	}
	if (scratch.length() > 0) {
		StringList scratch_list(scratch.c_str());
		scratch_list.rewind();
		char *next_dir;
		while ( (next_dir=scratch_list.next()) ) {
			if (!*next_dir) {
				scratch_list.deleteCurrent();
				continue;
			}
			sing_args.AppendArg("-S");
			sing_args.AppendArg(next_dir);
		}
	}
	if (job_iwd != execute_dir) {
		sing_args.AppendArg("-B");
		sing_args.AppendArg(job_iwd.c_str());
	}
	// When overlayfs is unavailable, singularity cannot bind-mount a directory that
	// does not exist in the container.  Hence, we allow a specific fixed target directory
	// to be used instead.
	std::string bind_spec = execute_dir;
	if (has_target) {
		bind_spec += ":";
		bind_spec += target_dir;
		// Only change PWD to our new target dir if that's where we should startup.
		if (job_iwd == execute_dir) {
			sing_args.AppendArg("--pwd");
			sing_args.AppendArg(target_dir.c_str());
		}
		// Update the environment variables
		retargetEnvs(job_env, target_dir, execute_dir);

	}
	sing_args.AppendArg("-B");
	sing_args.AppendArg(bind_spec.c_str());

	if (param_eval_string(bind_spec, "SINGULARITY_BIND_EXPR", "SingularityBind", &machineAd, &jobAd)) {
		dprintf(D_FULLDEBUG, "Parsing bind mount specification for singularity: %s\n", bind_spec.c_str());
		StringList binds(bind_spec.c_str());
		binds.rewind();
		char *next_bind;
		while ( (next_bind=binds.next()) ) {
			sing_args.AppendArg("-B");
			sing_args.AppendArg(next_bind);
		}
	}

	if (!param_boolean("SINGULARITY_MOUNT_HOME", false, false, &machineAd, &jobAd)) {
		sing_args.AppendArg("--no-home");
	}

	sing_args.AppendArg("-C");

	MyString args_error;
	char *tmp = param("SINGULARITY_EXTRA_ARGUMENTS");
	if(!sing_args.AppendArgsV1RawOrV2Quoted(tmp,&args_error)) {
		dprintf(D_ALWAYS,"singularity: failed to parse extra arguments: %s\n",
		args_error.Value());
		free(tmp);
		return Singularity::FAILURE;
	}
	if (tmp) free(tmp);

	// if the startd has assigned us a gpu, add --nv to the sing exec
	// arguments to mount the nvidia devices
	std::string assignedGpus;
	machineAd.LookupString("AssignedGPUs", assignedGpus);
	if  (assignedGpus.length() > 0) {
		sing_args.AppendArg("--nv");
	}

	sing_args.AppendArg(image.c_str());

	sing_args.AppendArg(exec.c_str());
	sing_args.AppendArgsFromArgList(job_args);

	MyString args_string;
	job_args = sing_args;
	job_args.GetArgsStringForDisplay(&args_string, 1);
	exec = sing_exec_str;
	dprintf(D_FULLDEBUG, "Arguments updated for executing with singularity: %s %s\n", exec.c_str(), args_string.Value());

	Singularity::convertEnv(&job_env);
	return Singularity::SUCCESS;
}

static bool
envToList(void *list, const MyString &Name, const MyString & /*value*/) {
	std::list<std::string> *slist = (std::list<std::string> *)list;
	slist->push_back(std::string(Name));
	return true;
}

bool
Singularity::retargetEnvs(Env &job_env, const std::string &target_dir, const std::string &execute_dir) {

	// if SINGULARITY_TARGET_DIR is set, we need to reset
	// all the job's environment variables that refer to the scratch dir

	MyString oldScratchDir;
	job_env.GetEnv("_CONDOR_SCRATCH_DIR", oldScratchDir);
	job_env.SetEnv("_CONDOR_SCRATCH_DIR_OUTSIDE_CONTAINER", oldScratchDir);

	job_env.SetEnv("_CONDOR_SCRATCH_DIR", target_dir.c_str());
	job_env.SetEnv("TEMP", target_dir.c_str());
	job_env.SetEnv("TMP", target_dir.c_str());
	job_env.SetEnv("TMPDIR", target_dir.c_str());
	std::string chirp = target_dir + "/.chirp.config";
	std::string machine_ad = target_dir + "/.machine.ad";
	std::string job_ad = target_dir + "/.job.ad";
	job_env.SetEnv("_CONDOR_CHIRP_CONFIG", chirp.c_str());
	job_env.SetEnv("_CONDOR_MACHINE_AD", machine_ad.c_str());
	job_env.SetEnv("_CONDOR_JOB_AD", job_ad.c_str());
	MyString proxy_file;
	if ( job_env.GetEnv( "X509_USER_PROXY", proxy_file ) &&
	     strncmp( execute_dir.c_str(), proxy_file.Value(),
	      execute_dir.length() ) == 0 ) {
		std::string new_proxy = target_dir + "/" + condor_basename( proxy_file.Value() );
		job_env.SetEnv( "X509_USER_PROXY", new_proxy.c_str() );
	}
	return true;
}
bool
Singularity::convertEnv(Env *job_env) {
	std::list<std::string> envNames;
	job_env->Walk(envToList, (void *)&envNames);
	std::list<std::string>::iterator it;
	for (it = envNames.begin(); it != envNames.end(); it++) {
		std::string name = *it;
		MyString value;
		job_env->GetEnv(name.c_str(), value);
		std::string new_name = "SINGULARITYENV_" + name;
		job_env->SetEnv(new_name.c_str(), value);
	}
	return true;
}
<commit_msg>Singularity bind mounts optional if host directory doesn't exist #7807<commit_after>
#include "condor_common.h"

#include "singularity.h"

#include <vector>

#include "condor_config.h"
#include "my_popen.h"
#include "CondorError.h"
#include "basename.h"
#include "stat_wrapper.h"

using namespace htcondor;

bool Singularity::m_enabled = false;
bool Singularity::m_probed = false;
int  Singularity::m_default_timeout = 120;
MyString Singularity::m_singularity_version;

static bool find_singularity(std::string &exec)
{
#ifdef LINUX
	std::string singularity;
	if (!param(singularity, "SINGULARITY")) {
		dprintf(D_ALWAYS | D_FAILURE, "SINGULARITY is undefined.\n");
		return false;
	}
	exec = singularity;
	return true;
#else
	(void) exec;
	return false;
#endif
}

bool
Singularity::advertise(ClassAd &ad)
{
	if (m_enabled && ad.InsertAttr("HasSingularity", true)) {
		return false;
	}
	if (!m_singularity_version.empty() && ad.InsertAttr("SingularityVersion", m_singularity_version)) {
		return false;
	}
	return true;
}

bool
Singularity::enabled()
{
	CondorError err;
	return detect(err);
}

const char *
Singularity::version()
{
	CondorError err;
	if (!detect(err)) {return NULL;}
	return m_singularity_version.c_str();
}

bool
Singularity::detect(CondorError &err)
{
	if (m_probed) {return m_enabled;}

	m_probed = true;
	ArgList infoArgs;
	std::string exec;
	if (!find_singularity(exec)) {
		return false;
	}
	infoArgs.AppendArg(exec);
	infoArgs.AppendArg("--version");

	MyString displayString;
	infoArgs.GetArgsStringForLogging( & displayString );
	dprintf(D_FULLDEBUG, "Attempting to run: '%s %s'.\n", exec.c_str(), displayString.c_str());

	MyPopenTimer pgm;
	if (pgm.start_program(infoArgs, true, NULL, false) < 0) {
		// treat 'file not found' as not really error
		int d_level = D_FULLDEBUG;
		if (pgm.error_code() != ENOENT) {
			d_level = D_ALWAYS | D_FAILURE;
			err.pushf("Singularity::detect", 1, "Failed to run '%s' errno = %d %s.", displayString.c_str(), pgm.error_code(), pgm.error_str());
		}
		dprintf(d_level, "Failed to run '%s' errno=%d %s.\n", displayString.c_str(), pgm.error_code(), pgm.error_str() );
		return false;
	}

	int exitCode;
	if ( ! pgm.wait_for_exit(m_default_timeout, &exitCode) || exitCode != 0) {
		pgm.close_program(1);
		MyString line;
		line.readLine(pgm.output(), false); line.chomp();
		dprintf( D_ALWAYS, "'%s' did not exit successfully (code %d); the first line of output was '%s'.\n", displayString.c_str(), exitCode, line.c_str());
		err.pushf("Singularity::detect", 2, "'%s' exited with status %d", displayString.c_str(), exitCode);
		return false;
	}

	m_singularity_version.readLine(pgm.output(), false);
	m_singularity_version.chomp();
	dprintf( D_FULLDEBUG, "[singularity version] %s\n", m_singularity_version.c_str() );
	if (IsFulldebug(D_ALWAYS)) {
		MyString line;
		while (line.readLine(pgm.output(), false)) {
			line.readLine(pgm.output(), false);
			line.chomp();
			dprintf( D_FULLDEBUG, "[singularity info] %s\n", line.c_str() );
		}
	}

	m_enabled = ! m_singularity_version.empty();

	return true;
}

bool
Singularity::job_enabled(ClassAd &machineAd, ClassAd &jobAd)
{
	return param_boolean("SINGULARITY_JOB", false, false, &machineAd, &jobAd);
}

Singularity::result
Singularity::setup(ClassAd &machineAd,
		ClassAd &jobAd,
		std::string &exec,
		ArgList &job_args,
		const std::string &job_iwd,
		const std::string &execute_dir,
		Env &job_env)
{
	ArgList sing_args;

	if (!param_boolean("SINGULARITY_JOB", false, false, &machineAd, &jobAd)) {return Singularity::DISABLE;}

	if (!enabled()) {
		dprintf(D_ALWAYS, "Singularity job has been requested but singularity does not appear to be configured on this host.\n");
		return Singularity::FAILURE;
	}
	std::string sing_exec_str;
	if (!find_singularity(sing_exec_str)) {
		return Singularity::FAILURE;
	}

	std::string image;
	if (!param_eval_string(image, "SINGULARITY_IMAGE_EXPR", "SingularityImage", &machineAd, &jobAd)) {
		dprintf(D_ALWAYS, "Singularity support was requested but unable to determine the image to use.\n");
		return Singularity::FAILURE;
	}

	std::string target_dir;
	bool has_target = param(target_dir, "SINGULARITY_TARGET_DIR") && !target_dir.empty();

	job_args.RemoveArg(0);
	std::string orig_exec_val = exec;
	if (has_target && (orig_exec_val.compare(0, execute_dir.length(), execute_dir) == 0)) {
		exec = target_dir + "/" + orig_exec_val.substr(execute_dir.length());
		dprintf(D_FULLDEBUG, "Updated executable path to %s for target directory mode.\n", exec.c_str());
	}
	sing_args.AppendArg(sing_exec_str.c_str());
	sing_args.AppendArg("exec");

	// Bind
	// Mount under scratch
	std::string scratch;
	if (!param_eval_string(scratch, "MOUNT_UNDER_SCRATCH", "", &jobAd)) {
		param(scratch, "MOUNT_UNDER_SCRATCH");
	}
	if (scratch.length() > 0) {
		StringList scratch_list(scratch.c_str());
		scratch_list.rewind();
		char *next_dir;
		while ( (next_dir=scratch_list.next()) ) {
			if (!*next_dir) {
				scratch_list.deleteCurrent();
				continue;
			}
			sing_args.AppendArg("-S");
			sing_args.AppendArg(next_dir);
		}
	}
	if (job_iwd != execute_dir) {
		sing_args.AppendArg("-B");
		sing_args.AppendArg(job_iwd.c_str());
	}
	// When overlayfs is unavailable, singularity cannot bind-mount a directory that
	// does not exist in the container.  Hence, we allow a specific fixed target directory
	// to be used instead.
	std::string bind_spec = execute_dir;
	if (has_target) {
		bind_spec += ":";
		bind_spec += target_dir;
		// Only change PWD to our new target dir if that's where we should startup.
		if (job_iwd == execute_dir) {
			sing_args.AppendArg("--pwd");
			sing_args.AppendArg(target_dir.c_str());
		}
		// Update the environment variables
		retargetEnvs(job_env, target_dir, execute_dir);

	}
	sing_args.AppendArg("-B");
	sing_args.AppendArg(bind_spec.c_str());

	if (param_eval_string(bind_spec, "SINGULARITY_BIND_EXPR", "SingularityBind", &machineAd, &jobAd)) {
		dprintf(D_FULLDEBUG, "Parsing bind mount specification for singularity: %s\n", bind_spec.c_str());
		StringList binds(bind_spec.c_str());
		binds.rewind();
		char *next_bind;
		while ( (next_bind=binds.next()) ) {
			std::string bind_src_dir(next_bind);
			// BIND exprs can be src:dst:ro
			size_t colon = bind_src_dir.find(':');
			if (colon != std::string::npos) {
				bind_src_dir = bind_src_dir.substr(0, colon);
			}
			StatWrapper sw(bind_src_dir.c_str());
			sw.Stat();
			if (! sw.IsBufValid()) {
				dprintf(D_ALWAYS, "Skipping invalid singularity bind directory %s\n", next_bind);
				continue;
			}
			sing_args.AppendArg("-B");
			sing_args.AppendArg(next_bind);
		}
	}

	if (!param_boolean("SINGULARITY_MOUNT_HOME", false, false, &machineAd, &jobAd)) {
		sing_args.AppendArg("--no-home");
	}

	sing_args.AppendArg("-C");

	MyString args_error;
	char *tmp = param("SINGULARITY_EXTRA_ARGUMENTS");
	if(!sing_args.AppendArgsV1RawOrV2Quoted(tmp,&args_error)) {
		dprintf(D_ALWAYS,"singularity: failed to parse extra arguments: %s\n",
		args_error.Value());
		free(tmp);
		return Singularity::FAILURE;
	}
	if (tmp) free(tmp);

	// if the startd has assigned us a gpu, add --nv to the sing exec
	// arguments to mount the nvidia devices
	std::string assignedGpus;
	machineAd.LookupString("AssignedGPUs", assignedGpus);
	if  (assignedGpus.length() > 0) {
		sing_args.AppendArg("--nv");
	}

	sing_args.AppendArg(image.c_str());

	sing_args.AppendArg(exec.c_str());
	sing_args.AppendArgsFromArgList(job_args);

	MyString args_string;
	job_args = sing_args;
	job_args.GetArgsStringForDisplay(&args_string, 1);
	exec = sing_exec_str;
	dprintf(D_FULLDEBUG, "Arguments updated for executing with singularity: %s %s\n", exec.c_str(), args_string.Value());

	Singularity::convertEnv(&job_env);
	return Singularity::SUCCESS;
}

static bool
envToList(void *list, const MyString &Name, const MyString & /*value*/) {
	std::list<std::string> *slist = (std::list<std::string> *)list;
	slist->push_back(std::string(Name));
	return true;
}

bool
Singularity::retargetEnvs(Env &job_env, const std::string &target_dir, const std::string &execute_dir) {

	// if SINGULARITY_TARGET_DIR is set, we need to reset
	// all the job's environment variables that refer to the scratch dir

	MyString oldScratchDir;
	job_env.GetEnv("_CONDOR_SCRATCH_DIR", oldScratchDir);
	job_env.SetEnv("_CONDOR_SCRATCH_DIR_OUTSIDE_CONTAINER", oldScratchDir);

	job_env.SetEnv("_CONDOR_SCRATCH_DIR", target_dir.c_str());
	job_env.SetEnv("TEMP", target_dir.c_str());
	job_env.SetEnv("TMP", target_dir.c_str());
	job_env.SetEnv("TMPDIR", target_dir.c_str());
	std::string chirp = target_dir + "/.chirp.config";
	std::string machine_ad = target_dir + "/.machine.ad";
	std::string job_ad = target_dir + "/.job.ad";
	job_env.SetEnv("_CONDOR_CHIRP_CONFIG", chirp.c_str());
	job_env.SetEnv("_CONDOR_MACHINE_AD", machine_ad.c_str());
	job_env.SetEnv("_CONDOR_JOB_AD", job_ad.c_str());
	MyString proxy_file;
	if ( job_env.GetEnv( "X509_USER_PROXY", proxy_file ) &&
	     strncmp( execute_dir.c_str(), proxy_file.Value(),
	      execute_dir.length() ) == 0 ) {
		std::string new_proxy = target_dir + "/" + condor_basename( proxy_file.Value() );
		job_env.SetEnv( "X509_USER_PROXY", new_proxy.c_str() );
	}
	return true;
}
bool
Singularity::convertEnv(Env *job_env) {
	std::list<std::string> envNames;
	job_env->Walk(envToList, (void *)&envNames);
	std::list<std::string>::iterator it;
	for (it = envNames.begin(); it != envNames.end(); it++) {
		std::string name = *it;
		MyString value;
		job_env->GetEnv(name.c_str(), value);
		std::string new_name = "SINGULARITYENV_" + name;
		job_env->SetEnv(new_name.c_str(), value);
	}
	return true;
}
<|endoftext|>


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

#include "condor_common.h"
#include "condor_config.h"
#include "condor_distribution.h"

#include "condor_auth_passwd.h"
#include "match_prefix.h"
#include "CondorError.h"
#include "daemon.h"
#include "dc_collector.h"
#include "directory.h"

void print_usage(const char *argv0) {
	fprintf(stderr, "Usage: %s [-type TYPE] [-name NAME] [-pool POOL] [-reqid ID]\n\n"
		"Generates a token from a remote daemon and prints its contents to stdout.\n"
		"\nToken options:\n"
		"    -reqid <val>                    Token request identity\n"
		"Specifying target options:\n"
		"    -pool    <host>                 Query this collector\n"
		"    -name    <name>                 Find a daemon with this name\n"
		"    -type    <subsystem>            Type of daemon to contact (default: COLLECTOR)\n"
		"If not specified, the pool's collector is targeted.\n",
		argv0
	);
	exit(1);
}

int
list_tokens(const std::string &pool, const std::string &name, daemon_t dtype, std::string request_id)
{
	std::unique_ptr<Daemon> daemon;
	if (!pool.empty()) {
		DCCollector col(pool.c_str());
		if (!col.addr()) {
			fprintf(stderr, "ERROR: %s\n", col.error());
			exit(1);
		}
		daemon.reset(new Daemon( dtype, name.c_str(), col.addr() ));
	} else {
		daemon.reset(new Daemon( dtype, name.c_str() ));
	}

	if (!(daemon->locate(Daemon::LOCATE_FOR_LOOKUP))) {
		if (!name.empty()) {
			fprintf(stderr, "ERROR: couldn't locate daemon %s!\n", name.c_str());
		} else {
			fprintf(stderr, "ERROR: couldn't locate default daemon type.\n");
		}
		exit(1);
	}

	CondorError err;

	std::vector<classad::ClassAd> results;
	if (!daemon->listTokenRequest(request_id, results, &err)) {
		if (request_id.empty()) {
			fprintf(stderr, "Failed to list token requests: %s\n", err.getFullText().c_str());
		} else {
			fprintf(stderr, "Failed to locate request corresponding to ID %s: %s\n", request_id.c_str(),
				err.getFullText().c_str());
		}
		exit(1);
	}
	if (!request_id.empty() && results.size() != 1) {
		fprintf(stderr, "Remote daemon did not provide information for request ID %s.\n", request_id.c_str());
		exit(1);
	} else if (results.empty()) {
		fprintf(stderr, "Remote daemon reports no requests pending.\n");
		return 0;
	}

	for (const auto &request_ad : results) {
		classad::ClassAdUnParser unp;
		std::string req_contents_str;
		unp.SetOldClassAd(true);
		unp.Unparse(req_contents_str, &request_ad);

		printf("%s\n", req_contents_str.c_str());
	}

	return 0;
}

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

	myDistro->Init( argc, argv );
	set_priv_initialize();
	config();

	daemon_t dtype = DT_COLLECTOR;
	std::string pool;
	std::string name;
	std::string reqid;
	for (int i = 1; i < argc; i++) {
		if (is_dash_arg_prefix(argv[i], "pool", 1)) {
			i++;
			if (!argv[i]) {
				fprintf(stderr, "%s: -pool requires a pool name argument.\n", argv[0]);
				exit(1);
			}
			pool = argv[i];
		} else if (is_dash_arg_prefix(argv[i], "name", 1)) {
			i++;
			if (!argv[i]) {
				fprintf(stderr, "%s: -name requires a daemon name argument.\n", argv[0]);
				exit(1);
			}
			name = argv[i];
		} else if (is_dash_arg_prefix(argv[i], "type", 1)) {
			i++;
			if (!argv[i]) {
				fprintf(stderr, "%s: -type requires a daemon type argument.\n", argv[0]);
				exit(1);
			}
			dtype = stringToDaemonType(argv[i]);
			if( dtype == DT_NONE) {
				fprintf(stderr, "ERROR: unrecognized daemon type: %s\n", argv[i]);
				print_usage(argv[0]);
				exit(1);
			}
		} else if(!strcmp(argv[i],"-debug")) {
			// dprintf to console
			dprintf_set_tool_debug("TOOL", 0);
		} else if (is_dash_arg_prefix(argv[i], "help", 1)) {
			print_usage(argv[0]);
			exit(1);
		} else {
			fprintf(stderr, "%s: Invalid command line argument: %s\n", argv[0], argv[i]);
			print_usage(argv[0]);
			exit(1);
		}
	}

	return list_tokens(pool, name, dtype, reqid);
}
<commit_msg>Implement missing code for -reqid. #7448<commit_after>/***************************************************************
 *
 * Copyright (C) 2019, HTCondor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

#include "condor_common.h"
#include "condor_config.h"
#include "condor_distribution.h"

#include "condor_auth_passwd.h"
#include "match_prefix.h"
#include "CondorError.h"
#include "daemon.h"
#include "dc_collector.h"
#include "directory.h"

void print_usage(const char *argv0) {
	fprintf(stderr, "Usage: %s [-type TYPE] [-name NAME] [-pool POOL] [-reqid ID]\n\n"
		"Generates a token from a remote daemon and prints its contents to stdout.\n"
		"\nToken options:\n"
		"    -reqid <val>                    Token request identity\n"
		"Specifying target options:\n"
		"    -pool    <host>                 Query this collector\n"
		"    -name    <name>                 Find a daemon with this name\n"
		"    -type    <subsystem>            Type of daemon to contact (default: COLLECTOR)\n"
		"If not specified, the pool's collector is targeted.\n",
		argv0
	);
	exit(1);
}

int
list_tokens(const std::string &pool, const std::string &name, daemon_t dtype, std::string request_id)
{
	std::unique_ptr<Daemon> daemon;
	if (!pool.empty()) {
		DCCollector col(pool.c_str());
		if (!col.addr()) {
			fprintf(stderr, "ERROR: %s\n", col.error());
			exit(1);
		}
		daemon.reset(new Daemon( dtype, name.c_str(), col.addr() ));
	} else {
		daemon.reset(new Daemon( dtype, name.c_str() ));
	}

	if (!(daemon->locate(Daemon::LOCATE_FOR_LOOKUP))) {
		if (!name.empty()) {
			fprintf(stderr, "ERROR: couldn't locate daemon %s!\n", name.c_str());
		} else {
			fprintf(stderr, "ERROR: couldn't locate default daemon type.\n");
		}
		exit(1);
	}

	CondorError err;

	std::vector<classad::ClassAd> results;
	if (!daemon->listTokenRequest(request_id, results, &err)) {
		if (request_id.empty()) {
			fprintf(stderr, "Failed to list token requests: %s\n", err.getFullText().c_str());
		} else {
			fprintf(stderr, "Failed to locate request corresponding to ID %s: %s\n", request_id.c_str(),
				err.getFullText().c_str());
		}
		exit(1);
	}
	if (!request_id.empty() && results.size() != 1) {
		fprintf(stderr, "Remote daemon did not provide information for request ID %s.\n", request_id.c_str());
		exit(1);
	} else if (results.empty()) {
		fprintf(stderr, "Remote daemon reports no requests pending.\n");
		return 0;
	}

	for (const auto &request_ad : results) {
		classad::ClassAdUnParser unp;
		std::string req_contents_str;
		unp.SetOldClassAd(true);
		unp.Unparse(req_contents_str, &request_ad);

		printf("%s\n", req_contents_str.c_str());
	}

	return 0;
}

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

	myDistro->Init( argc, argv );
	set_priv_initialize();
	config();

	daemon_t dtype = DT_COLLECTOR;
	std::string pool;
	std::string name;
	std::string reqid;
	for (int i = 1; i < argc; i++) {
		if (is_dash_arg_prefix(argv[i], "pool", 1)) {
			i++;
			if (!argv[i]) {
				fprintf(stderr, "%s: -pool requires a pool name argument.\n", argv[0]);
				exit(1);
			}
			pool = argv[i];
		} else if (is_dash_arg_prefix(argv[i], "name", 1)) {
			i++;
			if (!argv[i]) {
				fprintf(stderr, "%s: -name requires a daemon name argument.\n", argv[0]);
				exit(1);
			}
			name = argv[i];
		} else if (is_dash_arg_prefix(argv[i], "type", 1)) {
			i++;
			if (!argv[i]) {
				fprintf(stderr, "%s: -type requires a daemon type argument.\n", argv[0]);
				exit(1);
			}
			dtype = stringToDaemonType(argv[i]);
			if( dtype == DT_NONE) {
				fprintf(stderr, "ERROR: unrecognized daemon type: %s\n", argv[i]);
				print_usage(argv[0]);
				exit(1);
			}
		} else if (is_dash_arg_prefix(argv[i], "reqid", 1)) {
			i++;
			if (!argv[i]) {
				fprintf(stderr, "%s: -reqid requires a request ID argument.\n", argv[0]);
				exit(1);
			}
			reqid = argv[i];
		} else if(!strcmp(argv[i],"-debug")) {
			// dprintf to console
			dprintf_set_tool_debug("TOOL", 0);
		} else if (is_dash_arg_prefix(argv[i], "help", 1)) {
			print_usage(argv[0]);
			exit(1);
		} else {
			fprintf(stderr, "%s: Invalid command line argument: %s\n", argv[0], argv[i]);
			print_usage(argv[0]);
			exit(1);
		}
	}

	return list_tokens(pool, name, dtype, reqid);
}
<|endoftext|>


<commit_before>/*
 * SimmelianBackbone.cpp
 *
 *  Created on: 21.05.2014
 *      Author: Gerd Lindner
 */

#include "SimmelianBackbone.h"
#include <limits>

namespace NetworKit {

std::vector<RankedNeighbors> SimmelianBackbone::getRankedNeighborhood(const Graph& g, const edgeAttribute& triangles) {
	std::vector<RankedNeighbors> neighbors;
	neighbors.resize(g.upperNodeIdBound());

	g.forNodes([&](node u) {
		//Sort ego's alters from strongly to weakly tied.
		g.forNeighborsOf(u, [&](node v) {
			double triangleCount = 1.0;//triangles[uEdge(u, v)];
			neighbors[u].push_back(RankedEdge(u, v, triangleCount));
		});
		std::sort(neighbors[u].begin(), neighbors[u].end());

		//Calculate the ranks.
		count currentRank = 0;	//Rank 1 is considered the best.
		count currentSimmelianness = std::numeric_limits<count>::max();
		count equals = 1;
		for (auto& edge : neighbors[u]) {
			if (edge.simmelianness < currentSimmelianness) {
				currentRank += equals;
				currentSimmelianness = edge.simmelianness;
				equals = 1;
			} else {
				equals++;
			}
			edge.rank = currentRank;
		}
	});

	return neighbors;

}

Redundancy SimmelianBackbone::getOverlap(	const node& ego,
											const node& alter,
											const std::vector<RankedNeighbors>& neighbors,
											const count& maxRank) {
	//Initialization of output values
	Redundancy result = Redundancy(0, 0.0);

	std::vector<RankedEdge>::const_iterator egoIt = neighbors[ego].begin();
	std::vector<RankedEdge>::const_iterator alterIt = neighbors[alter].begin();

	std::set<node> egoNeighborsUnmatched;
	std::set<node> alterNeighborsUnmatched;

	for (count rank = 1; rank <= maxRank; rank++) {
		matchNeighbors(ego, alter, true, egoIt, neighbors[ego], egoNeighborsUnmatched, alterNeighborsUnmatched, rank, result.overlap);
		matchNeighbors(alter, ego, false, alterIt, neighbors[alter], alterNeighborsUnmatched, egoNeighborsUnmatched, rank, result.overlap);

		double currentJaccard = double(result.overlap) /
				double(result.overlap + egoNeighborsUnmatched.size() + alterNeighborsUnmatched.size());

		result.jaccard = std::max(currentJaccard, result.jaccard);
	}

	return result;
}

/**
 * Helper function used in getOverlap. Adds the intersection of
 * egoNeighbors and alterNeighborsUnmatched to overlap.
 */
void SimmelianBackbone::matchNeighbors(
	const node& ego,
	const node& alter,
	const bool& reciprocityCheck,
	std::vector<RankedEdge>::const_iterator& egoIt,
	const RankedNeighbors& egoNeighbors,
	std::set<node>& egoNeighborsUnmatched,
	std::set<node>& alterNeighborsUnmatched,
	const count& rank,
	count& overlap) {

	for (; egoIt != egoNeighbors.end() && egoIt->rank == rank; egoIt++) {
		node other = egoIt->alter;

		//We count nodes that are incident to the currently considered edge, as well.
		if (reciprocityCheck && other == alter)
			other = ego;

		if (alterNeighborsUnmatched.erase(other))
			overlap++;
		else
			egoNeighborsUnmatched.insert(other);
	}
}

} /* namespace NetworKit */
<commit_msg>Fixed typo that caused Simmelian Backbone tests to fail<commit_after>/*
 * SimmelianBackbone.cpp
 *
 *  Created on: 21.05.2014
 *      Author: Gerd Lindner
 */

#include "SimmelianBackbone.h"
#include <limits>

namespace NetworKit {

std::vector<RankedNeighbors> SimmelianBackbone::getRankedNeighborhood(const Graph& g, const edgeAttribute& triangles) {
	std::vector<RankedNeighbors> neighbors;
	neighbors.resize(g.upperNodeIdBound());

	g.forNodes([&](node u) {
		//Sort ego's alters from strongly to weakly tied.
		g.forNeighborsOf(u, [&](node v) {
			count triangleCount = round(triangles.at(uEdge(u, v)));
			neighbors[u].push_back(RankedEdge(u, v, triangleCount));
		});
		std::sort(neighbors[u].begin(), neighbors[u].end());

		//Calculate the ranks.
		count currentRank = 0;	//Rank 1 is considered the best.
		count currentSimmelianness = std::numeric_limits<count>::max();
		count equals = 1;
		for (auto& edge : neighbors[u]) {
			if (edge.simmelianness < currentSimmelianness) {
				currentRank += equals;
				currentSimmelianness = edge.simmelianness;
				equals = 1;
			} else {
				equals++;
			}
			edge.rank = currentRank;
		}
	});

	return neighbors;

}

Redundancy SimmelianBackbone::getOverlap(	const node& ego,
											const node& alter,
											const std::vector<RankedNeighbors>& neighbors,
											const count& maxRank) {
	//Initialization of output values
	Redundancy result = Redundancy(0, 0.0);

	std::vector<RankedEdge>::const_iterator egoIt = neighbors[ego].begin();
	std::vector<RankedEdge>::const_iterator alterIt = neighbors[alter].begin();

	std::set<node> egoNeighborsUnmatched;
	std::set<node> alterNeighborsUnmatched;

	for (count rank = 1; rank <= maxRank; rank++) {
		matchNeighbors(ego, alter, true, egoIt, neighbors[ego], egoNeighborsUnmatched, alterNeighborsUnmatched, rank, result.overlap);
		matchNeighbors(alter, ego, false, alterIt, neighbors[alter], alterNeighborsUnmatched, egoNeighborsUnmatched, rank, result.overlap);

		double currentJaccard = double(result.overlap) /
				double(result.overlap + egoNeighborsUnmatched.size() + alterNeighborsUnmatched.size());

		result.jaccard = std::max(currentJaccard, result.jaccard);
	}

	return result;
}

/**
 * Helper function used in getOverlap. Adds the intersection of
 * egoNeighbors and alterNeighborsUnmatched to overlap.
 */
void SimmelianBackbone::matchNeighbors(
	const node& ego,
	const node& alter,
	const bool& reciprocityCheck,
	std::vector<RankedEdge>::const_iterator& egoIt,
	const RankedNeighbors& egoNeighbors,
	std::set<node>& egoNeighborsUnmatched,
	std::set<node>& alterNeighborsUnmatched,
	const count& rank,
	count& overlap) {

	for (; egoIt != egoNeighbors.end() && egoIt->rank == rank; egoIt++) {
		node other = egoIt->alter;

		//We count nodes that are incident to the currently considered edge, as well.
		if (reciprocityCheck && other == alter)
			other = ego;

		if (alterNeighborsUnmatched.erase(other))
			overlap++;
		else
			egoNeighborsUnmatched.insert(other);
	}
}

} /* namespace NetworKit */
<|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 <vector>
#include <array>

#include <GL/glew.h>

#include "gl_rendering.hpp"
#include "gl_data_preparation.hpp"

using namespace gl_data_preparation;

#define BUFFER_OFFSET(i) ((void*)(i))
const GLuint INVALID_BUFFER_ID = 0;

// by_distance_VBO_* are indexed by distance*DISTANCE_IDX_FACTOR + this enum:
enum by_distance_idx_adjustment_enum {
  QUADS_IDX = 0, TRIANGLES_IDX, LINES_IDX, POINTS_IDX,
  DISTANCE_IDX_FACTOR
};

typedef std::array<vertex_with_color, 4> rect_type;

struct gl_renderer::state_t_ {
  GLuint rect_VBO_name;
  std::vector<GLuint> by_distance_VBO_names;
  std::vector<size_t> by_distance_VBO_sizes;
};

gl_renderer::gl_renderer() {}
gl_renderer::~gl_renderer() {}

void gl_renderer::output_gl_data_to_OpenGL(
    gl_data_preparation::gl_all_data const& gl_data,
    viewport_dimension viewport_width,
    viewport_dimension viewport_height,
    LasercakeGLWidget& gl_widget
) {
  // This code is intended to have no operations in it that can possibly
  // throw exceptions, to simplify dealing with OpenGL context state.
  // When allocating, e.g. via std::vector, wrap it in a try/catch
  // and do something sensible if there's an exception.

  if(!state_) {
    try {
      state_.reset(new state_t_);
    }
    catch(std::bad_alloc const&) {
      return;
    }

    const GLenum glew_init_err = glewInit();
    if(glew_init_err != GLEW_OK)
    {
      // give up
      state_.reset();
      return;
    }

    glGenBuffersARB(1, &state_->rect_VBO_name);
    glBindBufferARB(GL_ARRAY_BUFFER, state_->rect_VBO_name);
    glBufferDataARB(GL_ARRAY_BUFFER, sizeof(rect_type), nullptr, GL_STREAM_DRAW);
  }
  // TODO Apparently atexit we should glDeleteBuffers, glDisable, and stuff?

  glViewport(0, 0, viewport_width, viewport_height);

  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
  // Depth func LEQUAL not LESS.  We try to draw objects in back-to-front
  // order, so rounding error means the front (later) one should win.
  //glEnable(GL_DEPTH_TEST)
  //glDepthFunc(GL_LEQUAL);
  glClear(GL_COLOR_BUFFER_BIT/* | GL_DEPTH_BUFFER_BIT*/);
  glLoadIdentity();

  // TODO convert these GLU calls to plain GL calls?
  gluPerspective(80, (double(viewport_width) / viewport_height), 0.1*get_primitive_double(tile_width), 300.0*get_primitive_double(tile_width));
  gluLookAt(0, 0, 0,
            gl_data.facing.x, gl_data.facing.y, gl_data.facing.z,
            gl_data.facing_up.x, gl_data.facing_up.y, gl_data.facing_up.z);

  glEnableClientState(GL_VERTEX_ARRAY);
  glEnableClientState(GL_COLOR_ARRAY);

  if(gl_data.stuff_to_draw_as_gl_collections_by_distance.size() > state_->by_distance_VBO_names.size()) {
    const size_t new_buffers_base = state_->by_distance_VBO_names.size()*DISTANCE_IDX_FACTOR;
    const size_t num_new_buffers = gl_data.stuff_to_draw_as_gl_collections_by_distance.size()*DISTANCE_IDX_FACTOR - new_buffers_base;
    try {
      state_->by_distance_VBO_names.resize(new_buffers_base + num_new_buffers);
      state_->by_distance_VBO_sizes.resize(new_buffers_base + num_new_buffers);
    }
    catch(std::bad_alloc const&) {
      return;
    }
    glGenBuffersARB(num_new_buffers, &state_->by_distance_VBO_names[new_buffers_base]);
    for(size_t i = 0; i != num_new_buffers; ++i) {
      state_->by_distance_VBO_sizes[new_buffers_base + i] = 0;
    }
  }

  for(size_t dist_plus_one = gl_data.stuff_to_draw_as_gl_collections_by_distance.size(); dist_plus_one != 0; --dist_plus_one) {
    const size_t dist = dist_plus_one - 1;
    gl_collection const& coll = gl_data.stuff_to_draw_as_gl_collections_by_distance[dist];
    struct polygon_type {
      GLenum gl_type;
      by_distance_idx_adjustment_enum our_idx_adj;
      gl_call_data gl_collection::* gl_data_container_ptr_to_member;
    };
    const std::array<polygon_type, DISTANCE_IDX_FACTOR> types = {{
      { GL_QUADS, QUADS_IDX, &gl_collection::quads },
      { GL_TRIANGLES, TRIANGLES_IDX, &gl_collection::triangles },
      { GL_LINES, LINES_IDX, &gl_collection::lines },
      { GL_POINTS, POINTS_IDX, &gl_collection::points },
    }};
    for (polygon_type type : types) {
      gl_call_data const& data = coll.*(type.gl_data_container_ptr_to_member);
      if(const size_t count = data.size()) {
        const size_t buf_name_idx = dist*DISTANCE_IDX_FACTOR + type.our_idx_adj;
        glBindBufferARB(GL_ARRAY_BUFFER, state_->by_distance_VBO_names[buf_name_idx]);
        if(state_->by_distance_VBO_sizes[buf_name_idx] < count) {
          glBufferDataARB(GL_ARRAY_BUFFER, count*sizeof(vertex_with_color), data.vertices, GL_STREAM_DRAW);
          state_->by_distance_VBO_sizes[buf_name_idx] = count;
        }
        else {
          glBufferSubDataARB(GL_ARRAY_BUFFER, 0, count*sizeof(vertex_with_color), data.vertices);
        }
        glInterleavedArrays(GL_C4UB_V3F, 0, BUFFER_OFFSET(0));
        glDrawArrays(type.gl_type, 0, count);
      }
    }
  }

  // Is there a simpler way to tint the whole screen a color?
  const color tint = gl_data.tint_everything_with_this_color;
  const rect_type rect = {{
    vertex_with_color(0, 0, 0, tint),
    vertex_with_color(0, 1, 0, tint),
    vertex_with_color(1, 1, 0, tint),
    vertex_with_color(1, 0, 0, tint)
  }};
  glLoadIdentity();
  glOrtho(0, 1, 0, 1, -1, 1);
  glBindBufferARB(GL_ARRAY_BUFFER, state_->rect_VBO_name);
  glBufferSubDataARB(GL_ARRAY_BUFFER, 0, sizeof(rect), &rect[0]);
  glInterleavedArrays(GL_C4UB_V3F, 0, BUFFER_OFFSET(0));
  glDrawArrays(GL_QUADS, 0, 4);
  glBindBufferARB(GL_ARRAY_BUFFER, INVALID_BUFFER_ID);

  render_2d_text_overlay_(gl_data, viewport_width, viewport_height, gl_widget);
}
<commit_msg>fix gl_rendering.cpp for units<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 <vector>
#include <array>

#include <GL/glew.h>

#include "gl_rendering.hpp"
#include "gl_data_preparation.hpp"

using namespace gl_data_preparation;

#define BUFFER_OFFSET(i) ((void*)(i))
const GLuint INVALID_BUFFER_ID = 0;

// by_distance_VBO_* are indexed by distance*DISTANCE_IDX_FACTOR + this enum:
enum by_distance_idx_adjustment_enum {
  QUADS_IDX = 0, TRIANGLES_IDX, LINES_IDX, POINTS_IDX,
  DISTANCE_IDX_FACTOR
};

typedef std::array<vertex_with_color, 4> rect_type;

struct gl_renderer::state_t_ {
  GLuint rect_VBO_name;
  std::vector<GLuint> by_distance_VBO_names;
  std::vector<size_t> by_distance_VBO_sizes;
};

gl_renderer::gl_renderer() {}
gl_renderer::~gl_renderer() {}

static const double tile_width_double = get_primitive_double(get(tile_width, fine_units));
static const double tile_height_double = get_primitive_double(get(tile_height, fine_units));

void gl_renderer::output_gl_data_to_OpenGL(
    gl_data_preparation::gl_all_data const& gl_data,
    viewport_dimension viewport_width,
    viewport_dimension viewport_height,
    LasercakeGLWidget& gl_widget
) {
  // This code is intended to have no operations in it that can possibly
  // throw exceptions, to simplify dealing with OpenGL context state.
  // When allocating, e.g. via std::vector, wrap it in a try/catch
  // and do something sensible if there's an exception.

  if(!state_) {
    try {
      state_.reset(new state_t_);
    }
    catch(std::bad_alloc const&) {
      return;
    }

    const GLenum glew_init_err = glewInit();
    if(glew_init_err != GLEW_OK)
    {
      // give up
      state_.reset();
      return;
    }

    glGenBuffersARB(1, &state_->rect_VBO_name);
    glBindBufferARB(GL_ARRAY_BUFFER, state_->rect_VBO_name);
    glBufferDataARB(GL_ARRAY_BUFFER, sizeof(rect_type), nullptr, GL_STREAM_DRAW);
  }
  // TODO Apparently atexit we should glDeleteBuffers, glDisable, and stuff?

  glViewport(0, 0, viewport_width, viewport_height);

  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
  // Depth func LEQUAL not LESS.  We try to draw objects in back-to-front
  // order, so rounding error means the front (later) one should win.
  //glEnable(GL_DEPTH_TEST)
  //glDepthFunc(GL_LEQUAL);
  glClear(GL_COLOR_BUFFER_BIT/* | GL_DEPTH_BUFFER_BIT*/);
  glLoadIdentity();

  // TODO convert these GLU calls to plain GL calls?
  gluPerspective(80, (double(viewport_width) / viewport_height), 0.1*tile_width_double, 300.0*tile_width_double);
  gluLookAt(0, 0, 0,
            gl_data.facing.x, gl_data.facing.y, gl_data.facing.z,
            gl_data.facing_up.x, gl_data.facing_up.y, gl_data.facing_up.z);

  glEnableClientState(GL_VERTEX_ARRAY);
  glEnableClientState(GL_COLOR_ARRAY);

  if(gl_data.stuff_to_draw_as_gl_collections_by_distance.size() > state_->by_distance_VBO_names.size()) {
    const size_t new_buffers_base = state_->by_distance_VBO_names.size()*DISTANCE_IDX_FACTOR;
    const size_t num_new_buffers = gl_data.stuff_to_draw_as_gl_collections_by_distance.size()*DISTANCE_IDX_FACTOR - new_buffers_base;
    try {
      state_->by_distance_VBO_names.resize(new_buffers_base + num_new_buffers);
      state_->by_distance_VBO_sizes.resize(new_buffers_base + num_new_buffers);
    }
    catch(std::bad_alloc const&) {
      return;
    }
    glGenBuffersARB(num_new_buffers, &state_->by_distance_VBO_names[new_buffers_base]);
    for(size_t i = 0; i != num_new_buffers; ++i) {
      state_->by_distance_VBO_sizes[new_buffers_base + i] = 0;
    }
  }

  for(size_t dist_plus_one = gl_data.stuff_to_draw_as_gl_collections_by_distance.size(); dist_plus_one != 0; --dist_plus_one) {
    const size_t dist = dist_plus_one - 1;
    gl_collection const& coll = gl_data.stuff_to_draw_as_gl_collections_by_distance[dist];
    struct polygon_type {
      GLenum gl_type;
      by_distance_idx_adjustment_enum our_idx_adj;
      gl_call_data gl_collection::* gl_data_container_ptr_to_member;
    };
    const std::array<polygon_type, DISTANCE_IDX_FACTOR> types = {{
      { GL_QUADS, QUADS_IDX, &gl_collection::quads },
      { GL_TRIANGLES, TRIANGLES_IDX, &gl_collection::triangles },
      { GL_LINES, LINES_IDX, &gl_collection::lines },
      { GL_POINTS, POINTS_IDX, &gl_collection::points },
    }};
    for (polygon_type type : types) {
      gl_call_data const& data = coll.*(type.gl_data_container_ptr_to_member);
      if(const size_t count = data.size()) {
        const size_t buf_name_idx = dist*DISTANCE_IDX_FACTOR + type.our_idx_adj;
        glBindBufferARB(GL_ARRAY_BUFFER, state_->by_distance_VBO_names[buf_name_idx]);
        if(state_->by_distance_VBO_sizes[buf_name_idx] < count) {
          glBufferDataARB(GL_ARRAY_BUFFER, count*sizeof(vertex_with_color), data.vertices, GL_STREAM_DRAW);
          state_->by_distance_VBO_sizes[buf_name_idx] = count;
        }
        else {
          glBufferSubDataARB(GL_ARRAY_BUFFER, 0, count*sizeof(vertex_with_color), data.vertices);
        }
        glInterleavedArrays(GL_C4UB_V3F, 0, BUFFER_OFFSET(0));
        glDrawArrays(type.gl_type, 0, count);
      }
    }
  }

  // Is there a simpler way to tint the whole screen a color?
  const color tint = gl_data.tint_everything_with_this_color;
  const rect_type rect = {{
    vertex_with_color(0, 0, 0, tint),
    vertex_with_color(0, 1, 0, tint),
    vertex_with_color(1, 1, 0, tint),
    vertex_with_color(1, 0, 0, tint)
  }};
  glLoadIdentity();
  glOrtho(0, 1, 0, 1, -1, 1);
  glBindBufferARB(GL_ARRAY_BUFFER, state_->rect_VBO_name);
  glBufferSubDataARB(GL_ARRAY_BUFFER, 0, sizeof(rect), &rect[0]);
  glInterleavedArrays(GL_C4UB_V3F, 0, BUFFER_OFFSET(0));
  glDrawArrays(GL_QUADS, 0, 4);
  glBindBufferARB(GL_ARRAY_BUFFER, INVALID_BUFFER_ID);

  render_2d_text_overlay_(gl_data, viewport_width, viewport_height, gl_widget);
}
<|endoftext|>


<commit_before>/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"
#include "SkCanvas.h"
#include "SkColorPriv.h"
#include "SkShader.h"

#include "SkArithmeticMode.h"
#include "SkGradientShader.h"
#define WW  100
#define HH  32

static SkBitmap make_bm() {
    SkBitmap bm;
    bm.setConfig(SkBitmap::kARGB_8888_Config, WW, HH);
    bm.allocPixels();
    bm.eraseColor(0);
    return bm;
}

static SkBitmap make_src() {
    SkBitmap bm = make_bm();
    SkCanvas canvas(bm);
    SkPaint paint;
    SkPoint pts[] = { 0, 0, WW, HH };
    SkColor colors[] = {
        SK_ColorBLACK, SK_ColorGREEN, SK_ColorCYAN,
        SK_ColorRED, SK_ColorMAGENTA, SK_ColorWHITE
    };
    SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, SK_ARRAY_COUNT(colors),
                                                 SkShader::kClamp_TileMode);
    paint.setShader(s)->unref();
    canvas.drawPaint(paint);
    return bm;
}

static SkBitmap make_dst() {
    SkBitmap bm = make_bm();
    SkCanvas canvas(bm);
    SkPaint paint;
    SkPoint pts[] = { 0, HH, WW, 0 };
    SkColor colors[] = {
        SK_ColorBLUE, SK_ColorYELLOW, SK_ColorBLACK, SK_ColorGREEN, SK_ColorGRAY
    };
    SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, SK_ARRAY_COUNT(colors),
                                                 SkShader::kClamp_TileMode);
    paint.setShader(s)->unref();
    canvas.drawPaint(paint);
    return bm;
}

static SkBitmap make_arith(const SkBitmap& src, const SkBitmap& dst,
                           const SkScalar k[]) {
    SkBitmap bm = make_bm();
    SkCanvas canvas(bm);
    SkPaint paint;
    canvas.drawBitmap(dst, 0, 0, NULL);
    SkXfermode* xfer = SkArithmeticMode::Create(k[0], k[1], k[2], k[3]);
    paint.setXfermode(xfer)->unref();
    canvas.drawBitmap(src, 0, 0, &paint);
    return bm;
}

static void show_k_text(SkCanvas* canvas, SkScalar x, SkScalar y, const SkScalar k[]) {
    SkPaint paint;
    paint.setTextSize(24);
    paint.setAntiAlias(true);
    for (int i = 0; i < 4; ++i) {
        SkString str;
        str.appendScalar(k[i]);
        SkScalar width = paint.measureText(str.c_str(), str.size());
        canvas->drawText(str.c_str(), str.size(), x, y + 24, paint);
        x += width + 10;
    }
}

class ArithmodeGM : public skiagm::GM {
public:
    ArithmodeGM () {}

protected:

    virtual SkString onShortName() {
        return SkString("arithmode");
    }

    virtual SkISize onISize() { return SkISize::Make(640, 480); }

    virtual void onDraw(SkCanvas* canvas) {
        SkBitmap src = make_src();
        SkBitmap dst = make_dst();

        static const SkScalar K[] = {
            0, 0, 0, 0,
            0, 0, 0, 1,
            0, 1, 0, 0,
            0, 0, 1, 0,
            0, 1, 1, 0,
            0, 1, -1, 0,
            0, 0.5f, 0.5f, 0,
            0, 0.5f, 0.5f, 0.25f,
            0, 0.5f, 0.5f, -0.25f,
            0.25f, 0.5f, 0.5f, 0,
            -0.25f, 0.5f, 0.5f, 0,
        };

        const SkScalar* k = K;
        const SkScalar* stop = k + SK_ARRAY_COUNT(K);
        SkScalar y = 0;
        SkScalar x = 0;
        SkScalar gap = src.width() + 20;
        while (k < stop) {
            SkScalar x = 0;
            SkBitmap res = make_arith(src, dst, k);
            canvas->drawBitmap(src, x, y, NULL);
            x += gap;
            canvas->drawBitmap(dst, x, y, NULL);
            x += gap;
            canvas->drawBitmap(res, x, y, NULL);
            x += gap;
            show_k_text(canvas, x, y, k);
            k += 4;
            y += src.height() + 12;
        }
    }

private:
    typedef GM INHERITED;
};

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

static skiagm::GM* MyFactory(void*) { return new ArithmodeGM; }
static skiagm::GMRegistry reg(MyFactory);
<commit_msg>try to make it draw correctly in fixed point<commit_after>/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"
#include "SkCanvas.h"
#include "SkColorPriv.h"
#include "SkShader.h"

#include "SkArithmeticMode.h"
#include "SkGradientShader.h"
#define WW  100
#define HH  32

static SkBitmap make_bm() {
    SkBitmap bm;
    bm.setConfig(SkBitmap::kARGB_8888_Config, WW, HH);
    bm.allocPixels();
    bm.eraseColor(0);
    return bm;
}

static SkBitmap make_src() {
    SkBitmap bm = make_bm();
    SkCanvas canvas(bm);
    SkPaint paint;
    SkPoint pts[] = { 0, 0, SkIntToScalar(WW), SkIntToScalar(HH) };
    SkColor colors[] = {
        SK_ColorBLACK, SK_ColorGREEN, SK_ColorCYAN,
        SK_ColorRED, SK_ColorMAGENTA, SK_ColorWHITE
    };
    SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, SK_ARRAY_COUNT(colors),
                                                 SkShader::kClamp_TileMode);
    paint.setShader(s)->unref();
    canvas.drawPaint(paint);
    return bm;
}

static SkBitmap make_dst() {
    SkBitmap bm = make_bm();
    SkCanvas canvas(bm);
    SkPaint paint;
    SkPoint pts[] = { 0, SkIntToScalar(HH), SkIntToScalar(WW), 0 };
    SkColor colors[] = {
        SK_ColorBLUE, SK_ColorYELLOW, SK_ColorBLACK, SK_ColorGREEN, SK_ColorGRAY
    };
    SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, SK_ARRAY_COUNT(colors),
                                                 SkShader::kClamp_TileMode);
    paint.setShader(s)->unref();
    canvas.drawPaint(paint);
    return bm;
}

static SkBitmap make_arith(const SkBitmap& src, const SkBitmap& dst,
                           const SkScalar k[]) {
    SkBitmap bm = make_bm();
    SkCanvas canvas(bm);
    SkPaint paint;
    canvas.drawBitmap(dst, 0, 0, NULL);
    SkXfermode* xfer = SkArithmeticMode::Create(k[0], k[1], k[2], k[3]);
    paint.setXfermode(xfer)->unref();
    canvas.drawBitmap(src, 0, 0, &paint);
    return bm;
}

static void show_k_text(SkCanvas* canvas, SkScalar x, SkScalar y, const SkScalar k[]) {
    SkPaint paint;
    paint.setTextSize(SkIntToScalar(24));
    paint.setAntiAlias(true);
    for (int i = 0; i < 4; ++i) {
        SkString str;
        str.appendScalar(k[i]);
        SkScalar width = paint.measureText(str.c_str(), str.size());
        canvas->drawText(str.c_str(), str.size(), x, y + paint.getTextSize(), paint);
        x += width + SkIntToScalar(10);
    }
}

class ArithmodeGM : public skiagm::GM {
public:
    ArithmodeGM () {}

protected:

    virtual SkString onShortName() {
        return SkString("arithmode");
    }

    virtual SkISize onISize() { return SkISize::Make(640, 480); }

    virtual void onDraw(SkCanvas* canvas) {
        SkBitmap src = make_src();
        SkBitmap dst = make_dst();

        const SkScalar one = SK_Scalar1;
        static const SkScalar K[] = {
            0, 0, 0, 0,
            0, 0, 0, one,
            0, one, 0, 0,
            0, 0, one, 0,
            0, one, one, 0,
            0, one, -one, 0,
            0, one/2, one/2, 0,
            0, one/2, one/2, one/4,
            0, one/2, one/2, -one/4,
            one/4, one/2, one/2, 0,
            -one/4, one/2, one/2, 0,
        };

        const SkScalar* k = K;
        const SkScalar* stop = k + SK_ARRAY_COUNT(K);
        SkScalar y = 0;
        SkScalar x = 0;
        SkScalar gap = src.width() + SkIntToScalar(20);
        while (k < stop) {
            SkScalar x = 0;
            SkBitmap res = make_arith(src, dst, k);
            canvas->drawBitmap(src, x, y, NULL);
            x += gap;
            canvas->drawBitmap(dst, x, y, NULL);
            x += gap;
            canvas->drawBitmap(res, x, y, NULL);
            x += gap;
            show_k_text(canvas, x, y, k);
            k += 4;
            y += src.height() + SkIntToScalar(12);
        }
    }

private:
    typedef GM INHERITED;
};

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

static skiagm::GM* MyFactory(void*) { return new ArithmodeGM; }
static skiagm::GMRegistry reg(MyFactory);
<|endoftext|>