<commit_before>// Copyright (C) 2010 and 2011 Marcin Arkadiusz Skrobiranda.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. 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.
// 3. Neither the name of the project nor the names of its contributors
//    may be used to endorse or promote products derived from this software
//    without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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 <GameServer/Achievement/Managers/AchievementManager.hpp>

using namespace GameServer::Epoch;
using namespace GameServer::Human;
using namespace GameServer::Land;
using namespace GameServer::Persistence;
using namespace GameServer::User;
using namespace GameServer::World;

namespace GameServer
{
namespace Achievement
{

AchievementManager::AchievementManager(
    IAchievementPersistenceFacadeShrPtr a_achievement_persistence_facade,
    IEpochPersistenceFacadeShrPtr       a_epoch_persistence_facade,
    IHumanPersistenceFacadeShrPtr       a_human_persistence_facade,
    ILandPersistenceFacadeShrPtr        a_land_persistence_facade,
    IUserPersistenceFacadeShrPtr        a_user_persistence_facade,
    IWorldPersistenceFacadeShrPtr       a_world_persistence_facade
)
    : m_achievement_persistence_facade(a_achievement_persistence_facade),
      m_epoch_persistence_facade(a_epoch_persistence_facade),
      m_human_persistence_facade(a_human_persistence_facade),
      m_land_persistence_facade(a_land_persistence_facade),
      m_user_persistence_facade(a_user_persistence_facade),
      m_world_persistence_facade(a_world_persistence_facade)
{
}

bool AchievementManager::grantAchievements(
    ITransactionShrPtr       a_transaction,
    IWorldShrPtr       const a_world
) const
{
    try
    {
        // Get the epoch of the world.
        IEpochShrPtr epoch = m_epoch_persistence_facade->getEpoch(a_transaction, a_world->getWorldName());

        if (!epoch)
        {
            return false;
        }

        // Get the lands of the world.
        ILandMap lands = m_land_persistence_facade->getLands(a_transaction, a_world);

        // Grant achievements to every land.
        for (ILandMap::const_iterator it = lands.begin(); it != lands.end(); ++it)
        {
            bool const result = grantAchievements(a_transaction, epoch, it->second);

            if (!result)
            {
                return false;
            }
        }

        return true;
    }
    catch (...)
    {
        return false;
    }
}

bool AchievementManager::grantAchievements(
    Persistence::ITransactionShrPtr       a_transaction,
    Epoch::IEpochShrPtr             const a_epoch,
    Land::ILandShrPtr               const a_land
) const
{
    int const turns = a_land->getTurns();

    if (turns == 88 or turns == 44 or turns == 22)
    {
        IUserShrPtr user = m_user_persistence_facade->getUser(a_transaction, a_land->getLogin());

        if (!user)
        {
            return false;
        }

        switch (turns)
        {
            case 88:
                return m_achievement_persistence_facade->grantAchievement(a_transaction, a_epoch, user, "survived88");
            case 44:
                return m_achievement_persistence_facade->grantAchievement(a_transaction, a_epoch, user, "survived44");
            case 22:
                return m_achievement_persistence_facade->grantAchievement(a_transaction, a_epoch, user, "survived22");
            default:
                BOOST_ASSERT(false);
        }
    }

    return true;
}

} // namespace Achievement
} // namespace GameServer
<commit_msg>Achievements granted only if there are more than 500 humans in the land.<commit_after>// Copyright (C) 2010 and 2011 Marcin Arkadiusz Skrobiranda.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. 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.
// 3. Neither the name of the project nor the names of its contributors
//    may be used to endorse or promote products derived from this software
//    without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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 <GameServer/Achievement/Managers/AchievementManager.hpp>

using namespace GameServer::Epoch;
using namespace GameServer::Human;
using namespace GameServer::Land;
using namespace GameServer::Persistence;
using namespace GameServer::User;
using namespace GameServer::World;

namespace GameServer
{
namespace Achievement
{

AchievementManager::AchievementManager(
    IAchievementPersistenceFacadeShrPtr a_achievement_persistence_facade,
    IEpochPersistenceFacadeShrPtr       a_epoch_persistence_facade,
    IHumanPersistenceFacadeShrPtr       a_human_persistence_facade,
    ILandPersistenceFacadeShrPtr        a_land_persistence_facade,
    IUserPersistenceFacadeShrPtr        a_user_persistence_facade,
    IWorldPersistenceFacadeShrPtr       a_world_persistence_facade
)
    : m_achievement_persistence_facade(a_achievement_persistence_facade),
      m_epoch_persistence_facade(a_epoch_persistence_facade),
      m_human_persistence_facade(a_human_persistence_facade),
      m_land_persistence_facade(a_land_persistence_facade),
      m_user_persistence_facade(a_user_persistence_facade),
      m_world_persistence_facade(a_world_persistence_facade)
{
}

bool AchievementManager::grantAchievements(
    ITransactionShrPtr       a_transaction,
    IWorldShrPtr       const a_world
) const
{
    try
    {
        // Get the epoch of the world.
        IEpochShrPtr epoch = m_epoch_persistence_facade->getEpoch(a_transaction, a_world->getWorldName());

        if (!epoch)
        {
            return false;
        }

        // Get the lands of the world.
        ILandMap lands = m_land_persistence_facade->getLands(a_transaction, a_world);

        // Grant achievements to every land.
        for (ILandMap::const_iterator it = lands.begin(); it != lands.end(); ++it)
        {
            bool const result = grantAchievements(a_transaction, epoch, it->second);

            if (!result)
            {
                return false;
            }
        }

        return true;
    }
    catch (...)
    {
        return false;
    }
}

bool AchievementManager::grantAchievements(
    Persistence::ITransactionShrPtr       a_transaction,
    Epoch::IEpochShrPtr             const a_epoch,
    Land::ILandShrPtr               const a_land
) const
{
    int const turns = a_land->getTurns();

    if (turns == 88 or turns == 44 or turns == 22)
    {
    	// TODO: Hardcoded human number.
        if (m_human_persistence_facade->countHumans(a_transaction, a_land->getLandName()) > 500)
        {
            IUserShrPtr user = m_user_persistence_facade->getUser(a_transaction, a_land->getLogin());

            if (!user)
            {
                return false;
            }

            switch (turns)
            {
                case 88:
                    return m_achievement_persistence_facade->grantAchievement(a_transaction, a_epoch, user, "survived88");
                case 44:
                    return m_achievement_persistence_facade->grantAchievement(a_transaction, a_epoch, user, "survived44");
                case 22:
                    return m_achievement_persistence_facade->grantAchievement(a_transaction, a_epoch, user, "survived22");
                default:
                    BOOST_ASSERT(false);
            }
        }
    }

    return true;
}

} // namespace Achievement
} // namespace GameServer
<|endoftext|>


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

#include "hphp/runtime/ext/extension.h"
#include "hphp/runtime/vm/native-data.h"

#include "../../../mongodb.h"
#include "../../../utils.h"

#include "ObjectID.h"

namespace HPHP {

const StaticString s_MongoBsonObjectID_className("MongoDB\\BSON\\ObjectID");
Class* MongoDBBsonObjectIDData::s_class = nullptr;
const StaticString MongoDBBsonObjectIDData::s_className("MongoDBBsonObjectID");
IMPLEMENT_GET_CLASS(MongoDBBsonObjectIDData);

void HHVM_METHOD(MongoDBBsonObjectID, __construct, const Variant &objectId)
{
	MongoDBBsonObjectIDData* data = Native::data<MongoDBBsonObjectIDData>(this_);
	const String& str_objectId = objectId.isNull() ? null_string : objectId.toString();

	if (!objectId.isNull()) {
		if (bson_oid_is_valid(str_objectId.c_str(), str_objectId.length())) {
			bson_oid_init_from_string(&data->m_oid, str_objectId.c_str());
		} else {
			throw MongoDriver::Utils::throwInvalidArgumentException("Invalid BSON ID provided");
		}
	} else {
		bson_oid_init(&data->m_oid, NULL);
	}
}

static String oidAsString(MongoDBBsonObjectIDData* data)
{
	String s;
	char *data_s;

	s = String(24, ReserveString);
	data_s = s.bufferSlice().data();
	bson_oid_to_string(&data->m_oid, data_s);
	s.setSize(24);

	return s;
}

String HHVM_METHOD(MongoDBBsonObjectID, __toString)
{
	MongoDBBsonObjectIDData* data = Native::data<MongoDBBsonObjectIDData>(this_);

	return oidAsString(data);
}

const StaticString s_oid("oid");

Array HHVM_METHOD(MongoDBBsonObjectID, __debugInfo)
{
	Array retval = Array::Create();
	MongoDBBsonObjectIDData* data = Native::data<MongoDBBsonObjectIDData>(this_);

	retval.set(s_oid, oidAsString(data));

	return retval;
}

}
<commit_msg>Fixed HHVM-188: ObjectID only supports lower case hexadecimal letters<commit_after>/**
 *  Copyright 2014-2015 MongoDB, Inc.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include "hphp/runtime/ext/extension.h"
#include "hphp/runtime/vm/native-data.h"
#include "hphp/runtime/ext/string/ext_string.h"

#include "../../../mongodb.h"
#include "../../../utils.h"

#include "ObjectID.h"

namespace HPHP {

const StaticString s_MongoBsonObjectID_className("MongoDB\\BSON\\ObjectID");
Class* MongoDBBsonObjectIDData::s_class = nullptr;
const StaticString MongoDBBsonObjectIDData::s_className("MongoDBBsonObjectID");
IMPLEMENT_GET_CLASS(MongoDBBsonObjectIDData);

void HHVM_METHOD(MongoDBBsonObjectID, __construct, const Variant &objectId)
{
	MongoDBBsonObjectIDData* data = Native::data<MongoDBBsonObjectIDData>(this_);
	const String& str_objectId = objectId.isNull() ? null_string : objectId.toString();

	if (!objectId.isNull()) {
		if (bson_oid_is_valid((HHVM_FN(strtolower)(str_objectId)).c_str(), str_objectId.length())) {
			bson_oid_init_from_string(&data->m_oid, (HHVM_FN(strtolower)(str_objectId)).c_str());
		} else {
			throw MongoDriver::Utils::throwInvalidArgumentException("Invalid BSON ID provided");
		}
	} else {
		bson_oid_init(&data->m_oid, NULL);
	}
}

static String oidAsString(MongoDBBsonObjectIDData* data)
{
	String s;
	char *data_s;

	s = String(24, ReserveString);
	data_s = s.bufferSlice().data();
	bson_oid_to_string(&data->m_oid, data_s);
	s.setSize(24);

	return s;
}

String HHVM_METHOD(MongoDBBsonObjectID, __toString)
{
	MongoDBBsonObjectIDData* data = Native::data<MongoDBBsonObjectIDData>(this_);

	return oidAsString(data);
}

const StaticString s_oid("oid");

Array HHVM_METHOD(MongoDBBsonObjectID, __debugInfo)
{
	Array retval = Array::Create();
	MongoDBBsonObjectIDData* data = Native::data<MongoDBBsonObjectIDData>(this_);

	retval.set(s_oid, oidAsString(data));

	return retval;
}

}
<|endoftext|>


<commit_before>#ifndef ITER_ACCUMULATE_H_
#define ITER_ACCUMULATE_H_

#include "internal/iterbase.hpp"

#include <utility>
#include <iterator>
#include <initializer_list>
#include <functional>
#include <type_traits>
#include <memory>

namespace iter {
  namespace impl {
    template <typename Container, typename AccumulateFunc>
    class Accumulator;
  }

  template <typename Container, typename AccumulateFunc>
  impl::Accumulator<Container, AccumulateFunc> accumulate(
      Container&&, AccumulateFunc);

  template <typename T, typename AccumulateFunc>
  impl::Accumulator<std::initializer_list<T>, AccumulateFunc> accumulate(
      std::initializer_list<T>, AccumulateFunc);
}

template <typename Container, typename AccumulateFunc>
class iter::impl::Accumulator {
 private:
  Container container;
  AccumulateFunc accumulate_func;

  friend Accumulator iter::accumulate<Container, AccumulateFunc>(
      Container&&, AccumulateFunc);

  template <typename T, typename AF>
  friend Accumulator<std::initializer_list<T>, AF> iter::accumulate(
      std::initializer_list<T>, AF);

  // AccumVal must be default constructible
  using AccumVal =
      typename std::remove_reference<typename std::result_of<AccumulateFunc(
          iterator_deref<Container>, iterator_deref<Container>)>::type>::type;

  Accumulator(Container&& in_container, AccumulateFunc in_accumulate_func)
      : container(std::forward<Container>(in_container)),
        accumulate_func(in_accumulate_func) {}

 public:
  class Iterator : public std::iterator<std::input_iterator_tag, AccumVal> {
   private:
    iterator_type<Container> sub_iter;
    iterator_type<Container> sub_end;
    AccumulateFunc* accumulate_func;
    std::unique_ptr<AccumVal> acc_val;

   public:
    Iterator(iterator_type<Container>&& iter, iterator_type<Container>&& end,
        AccumulateFunc in_accumulate_func)
        : sub_iter{std::move(iter)},
          sub_end{std::move(end)},
          accumulate_func(&in_accumulate_func),
          // only get first value if not an end iterator
          acc_val{!(iter != end) ? nullptr : new AccumVal(*iter)} {}

    Iterator(const Iterator& other)
        : sub_iter{other.sub_iter},
          sub_end{other.sub_end},
          accumulate_func{other.accumulate_func},
          acc_val{other.acc_val ? new AccumVal(*other.acc_val) : nullptr} {}

    Iterator& operator=(const Iterator& other) {
      if (this == &other) return *this;
      this->sub_iter = other.sub_iter;
      this->sub_end = other.sub_end;
      this->accumulate_func = other.accumulate_func;
      this->acc_val.reset(
          other.acc_val ? new AccumVal(*other.acc_val) : nullptr);
      return *this;
    }

    Iterator(Iterator&&) = default;
    Iterator& operator=(Iterator&&) = default;

    const AccumVal& operator*() const {
      return *this->acc_val;
    }

    const AccumVal* operator->() const {
      return this->acc_val.get();
    }

    Iterator& operator++() {
      ++this->sub_iter;
      if (this->sub_iter != this->sub_end) {
        *this->acc_val = (*accumulate_func)(*this->acc_val, *this->sub_iter);
      }
      return *this;
    }

    Iterator operator++(int) {
      auto ret = *this;
      ++*this;
      return ret;
    }

    bool operator!=(const Iterator& other) const {
      return this->sub_iter != other.sub_iter;
    }

    bool operator==(const Iterator& other) const {
      return !(*this != other);
    }
  };

  Iterator begin() {
    return {std::begin(this->container), std::end(this->container),
        this->accumulate_func};
  }

  Iterator end() {
    return {std::end(this->container), std::end(this->container),
        this->accumulate_func};
  }
};

template <typename Container, typename AccumulateFunc>
iter::impl::Accumulator<Container, AccumulateFunc> iter::accumulate(
    Container&& container, AccumulateFunc accumulate_func) {
  return {std::forward<Container>(container), accumulate_func};
}

template <typename T, typename AccumulateFunc>
iter::impl::Accumulator<std::initializer_list<T>, AccumulateFunc>
iter::accumulate(std::initializer_list<T> il, AccumulateFunc accumulate_func) {
  return {std::move(il), accumulate_func};
}

namespace iter {
  template <typename Container>
  auto accumulate(Container&& container) -> decltype(accumulate(
      std::forward<Container>(container),
      std::plus<typename std::
              remove_reference<impl::iterator_deref<Container>>::type>{})) {
    return accumulate(
        std::forward<Container>(container),
        std::plus<typename std::
                remove_reference<impl::iterator_deref<Container>>::type>{});
  }

  template <typename T>
  auto accumulate(std::initializer_list<T> il)
      -> decltype(accumulate(std::move(il), std::plus<T>{})) {
    return accumulate(std::move(il), std::plus<T>{});
  }
}

#endif
<commit_msg>makes accumulate implementation class move-only<commit_after>#ifndef ITER_ACCUMULATE_H_
#define ITER_ACCUMULATE_H_

#include "internal/iterbase.hpp"

#include <utility>
#include <iterator>
#include <initializer_list>
#include <functional>
#include <type_traits>
#include <memory>

namespace iter {
  namespace impl {
    template <typename Container, typename AccumulateFunc>
    class Accumulator;
  }

  template <typename Container, typename AccumulateFunc>
  impl::Accumulator<Container, AccumulateFunc> accumulate(
      Container&&, AccumulateFunc);

  template <typename T, typename AccumulateFunc>
  impl::Accumulator<std::initializer_list<T>, AccumulateFunc> accumulate(
      std::initializer_list<T>, AccumulateFunc);
}

template <typename Container, typename AccumulateFunc>
class iter::impl::Accumulator {
 private:
  Container container;
  AccumulateFunc accumulate_func;

  friend Accumulator iter::accumulate<Container, AccumulateFunc>(
      Container&&, AccumulateFunc);

  template <typename T, typename AF>
  friend Accumulator<std::initializer_list<T>, AF> iter::accumulate(
      std::initializer_list<T>, AF);

  // AccumVal must be default constructible
  using AccumVal =
      typename std::remove_reference<typename std::result_of<AccumulateFunc(
          iterator_deref<Container>, iterator_deref<Container>)>::type>::type;

  Accumulator(Container&& in_container, AccumulateFunc in_accumulate_func)
      : container(std::forward<Container>(in_container)),
        accumulate_func(in_accumulate_func) {}

 public:
  Accumulator(Accumulator&&) = default;

  class Iterator : public std::iterator<std::input_iterator_tag, AccumVal> {
   private:
    iterator_type<Container> sub_iter;
    iterator_type<Container> sub_end;
    AccumulateFunc* accumulate_func;
    std::unique_ptr<AccumVal> acc_val;

   public:
    Iterator(iterator_type<Container>&& iter, iterator_type<Container>&& end,
        AccumulateFunc in_accumulate_fun)
        : sub_iter{std::move(iter)},
          sub_end{std::move(end)},
          accumulate_func(&in_accumulate_func),
          // only get first value if not an end iterator
          acc_val{!(iter != end) ? nullptr : new AccumVal(*iter)} {}

    Iterator(const Iterator& other)
        : sub_iter{other.sub_iter},
          sub_end{other.sub_end},
          accumulate_func{other.accumulate_func},
          acc_val{other.acc_val ? new AccumVal(*other.acc_val) : nullptr} {}

    Iterator& operator=(const Iterator& other) {
      if (this == &other) return *this;
      this->sub_iter = other.sub_iter;
      this->sub_end = other.sub_end;
      this->accumulate_func = other.accumulate_func;
      this->acc_val.reset(
          other.acc_val ? new AccumVal(*other.acc_val) : nullptr);
      return *this;
    }

    Iterator(Iterator&&) = default;
    Iterator& operator=(Iterator&&) = default;

    const AccumVal& operator*() const {
      return *this->acc_val;
    }

    const AccumVal* operator->() const {
      return this->acc_val.get();
    }

    Iterator& operator++() {
      ++this->sub_iter;
      if (this->sub_iter != this->sub_end) {
        *this->acc_val = (*accumulate_func)(*this->acc_val, *this->sub_iter);
      }
      return *this;
    }

    Iterator operator++(int) {
      auto ret = *this;
      ++*this;
      return ret;
    }

    bool operator!=(const Iterator& other) const {
      return this->sub_iter != other.sub_iter;
    }

    bool operator==(const Iterator& other) const {
      return !(*this != other);
    }
  };

  Iterator begin() {
    return {std::begin(this->container), std::end(this->container),
        this->accumulate_func};
  }

  Iterator end() {
    return {std::end(this->container), std::end(this->container),
        this->accumulate_func};
  }
};

template <typename Container, typename AccumulateFunc>
iter::impl::Accumulator<Container, AccumulateFunc> iter::accumulate(
    Container&& container, AccumulateFunc accumulate_func) {
  return {std::forward<Container>(container), accumulate_func};
}

template <typename T, typename AccumulateFunc>
iter::impl::Accumulator<std::initializer_list<T>, AccumulateFunc>
iter::accumulate(std::initializer_list<T> il, AccumulateFunc accumulate_func) {
  return {std::move(il), accumulate_func};
}

namespace iter {
  template <typename Container>
  auto accumulate(Container&& container) -> decltype(accumulate(
      std::forward<Container>(container),
      std::plus<typename std::
              remove_reference<impl::iterator_deref<Container>>::type>{})) {
    return accumulate(
        std::forward<Container>(container),
        std::plus<typename std::
                remove_reference<impl::iterator_deref<Container>>::type>{});
  }

  template <typename T>
  auto accumulate(std::initializer_list<T> il)
      -> decltype(accumulate(std::move(il), std::plus<T>{})) {
    return accumulate(std::move(il), std::plus<T>{});
  }
}

#endif
<|endoftext|>


<commit_before>/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.
*/

#include <Onsang/Log.hpp>
#include <Onsang/System/Session.hpp>

#include <Hord/Cmd/Defs.hpp>
#include <Hord/Cmd/Unit.hpp>

#include <iomanip>

#include <Onsang/detail/gr_core.hpp>

namespace Onsang {
namespace System {

#define ONSANG_SCOPE_CLASS System::Session

#define ONSANG_SCOPE_FUNC notify_exception_impl
void
Session::notify_exception_impl(
	Hord::Cmd::UnitBase const& /*command*/,
	Hord::Cmd::type_info const& type_info,
	std::exception_ptr eptr
) noexcept {
	Log::acquire(Log::error)
		<< "exception caught in " << type_info.name << ": \n"
	;
	Log::report_error_ptr(std::move(eptr));
}
#undef ONSANG_SCOPE_FUNC

#define ONSANG_SCOPE_FUNC notify_complete_impl
void
Session::notify_complete_impl(
	Hord::Cmd::UnitBase const& command,
	Hord::Cmd::type_info const& type_info
) noexcept {
	// TODO: Dispatch to observers
	Log::acquire(Log::debug)
		<< "notify_complete: "
		<< std::hex << type_info.id
		<< ' ' << type_info.name
		<< " ok? " << std::boolalpha << command.ok()
		<< " message: \"" << command.get_message() << '\"'
		<< '\n'
	;
}
#undef ONSANG_SCOPE_FUNC

#define ONSANG_SCOPE_FUNC open
void
Session::open() {
	get_datastore().open(m_auto_create);
}
#undef ONSANG_SCOPE_FUNC

#define ONSANG_SCOPE_FUNC close
void
Session::close() {
	get_datastore().close();
}
#undef ONSANG_SCOPE_FUNC

#define ONSANG_SCOPE_FUNC process
void
Session::process() {
	// TODO: Update views
}
#undef ONSANG_SCOPE_FUNC

#undef ONSANG_SCOPE_CLASS

} // namespace System
} // namespace Onsang

<commit_msg>System::Session: output tidy.<commit_after>/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.
*/

#include <Onsang/Log.hpp>
#include <Onsang/System/Session.hpp>

#include <Hord/Cmd/Defs.hpp>
#include <Hord/Cmd/Unit.hpp>

#include <iomanip>

#include <Onsang/detail/gr_core.hpp>

namespace Onsang {
namespace System {

#define ONSANG_SCOPE_CLASS System::Session

#define ONSANG_SCOPE_FUNC notify_exception_impl
void
Session::notify_exception_impl(
	Hord::Cmd::UnitBase const& /*command*/,
	Hord::Cmd::type_info const& type_info,
	std::exception_ptr eptr
) noexcept {
	Log::acquire(Log::error)
		<< "exception caught in " << type_info.name << ": \n"
	;
	Log::report_error_ptr(std::move(eptr));
}
#undef ONSANG_SCOPE_FUNC

#define ONSANG_SCOPE_FUNC notify_complete_impl
void
Session::notify_complete_impl(
	Hord::Cmd::UnitBase const& command,
	Hord::Cmd::type_info const& type_info
) noexcept {
	// TODO: Dispatch to observers
	Log::acquire(Log::debug)
		<< "notify_complete: "
		<< std::hex << type_info.id
		<< ' ' << type_info.name
		<< ", ok: " << (command.ok() ? "yes" : "no")
		<< ", message: \"" << command.get_message() << '\"'
		<< '\n'
	;
}
#undef ONSANG_SCOPE_FUNC

#define ONSANG_SCOPE_FUNC open
void
Session::open() {
	get_datastore().open(m_auto_create);
}
#undef ONSANG_SCOPE_FUNC

#define ONSANG_SCOPE_FUNC close
void
Session::close() {
	get_datastore().close();
}
#undef ONSANG_SCOPE_FUNC

#define ONSANG_SCOPE_FUNC process
void
Session::process() {
	// TODO: Update views
}
#undef ONSANG_SCOPE_FUNC

#undef ONSANG_SCOPE_CLASS

} // namespace System
} // namespace Onsang

<|endoftext|>


<commit_before>#include <iostream>

class MyClass
{
	int m_iID = -1;

public:
	MyClass(int iID) : m_iID(iID)
	{
		std::cout << "Built and instance with ID: " << m_iID << std::endl;
	}

	MyClass() : MyClass(42)
	{
		std::cout << "Delegated construction" << m_iID << std::endl;
	}
};

int main(int argc, char* argv[])
{
	MyClass myInstance;
}

<commit_msg>Added member and destructor<commit_after>#include <iostream>

class MyClass
{
private:

	int m_iID = -1;

public:
	MyClass(int iID) : m_iID(iID)
	{
		std::cout << "Built and instance with ID: " << m_iID << std::endl;
	}

	MyClass() : MyClass(42)
	{
		std::cout << "Delegated construction" << m_iID << std::endl;
	}

	~MyClass()
	{
	}

};

int main(int argc, char* argv[])
{
	MyClass myInstance;
}

<|endoftext|>


<commit_before>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date: 2009-05-12 19:56:03 +0200 (Di, 12 Mai 2009) $
Version:   $Revision: 17179 $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mitkSurfaceToSurfaceFilter.h"
#include "mitkSurface.h"

mitk::SurfaceToSurfaceFilter::SurfaceToSurfaceFilter()
: SurfaceSource()
{
}

mitk::SurfaceToSurfaceFilter::~SurfaceToSurfaceFilter()
{
}

void mitk::SurfaceToSurfaceFilter::SetInput( const mitk::Surface* surface )
{
  this->SetInput( 0, const_cast<mitk::Surface*>( surface ) );
}

void mitk::SurfaceToSurfaceFilter::SetInput( unsigned int idx, const mitk::Surface* surface )
{
  if ( this->GetInput(idx) != surface )
  {
    this->SetNthInput( idx, const_cast<mitk::Surface*>( surface ) );
    this->CreateOutputsForAllInputs(idx);
    this->Modified();
  }
}

const mitk::Surface* mitk::SurfaceToSurfaceFilter::GetInput()
{
  if (this->GetNumberOfInputs() < 1)
    return NULL;

  return static_cast<const mitk::Surface*>(this->ProcessObject::GetInput(0));
}

const mitk::Surface* mitk::SurfaceToSurfaceFilter::GetInput( unsigned int idx)
{
  if (this->GetNumberOfInputs() < 1)
    return NULL;

  return static_cast<const mitk::Surface*>(this->ProcessObject::GetInput(idx));
}

void mitk::SurfaceToSurfaceFilter::CreateOutputsForAllInputs(unsigned int  /*idx*/)
{
  this->SetNumberOfOutputs( this->GetNumberOfInputs() );
  for (unsigned int idx = 0; idx < this->GetNumberOfOutputs(); ++idx)
    if (this->GetOutput(idx) == NULL)
    {
      DataObjectPointer newOutput = this->MakeOutput(idx);
      this->SetNthOutput(idx, newOutput);
    }
  this->Modified();
}

void mitk::SurfaceToSurfaceFilter::RemoveInputs(mitk::Surface* input)
{
  this->RemoveInput(input);
}<commit_msg>FIX (#3189): now grafting each input into its corresponding output -> output-surfaces are initialized correctly<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date: 2009-05-12 19:56:03 +0200 (Di, 12 Mai 2009) $
Version:   $Revision: 17179 $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mitkSurfaceToSurfaceFilter.h"
#include "mitkSurface.h"

mitk::SurfaceToSurfaceFilter::SurfaceToSurfaceFilter()
: SurfaceSource()
{
}

mitk::SurfaceToSurfaceFilter::~SurfaceToSurfaceFilter()
{
}

void mitk::SurfaceToSurfaceFilter::SetInput( const mitk::Surface* surface )
{
  this->SetInput( 0, const_cast<mitk::Surface*>( surface ) );
}

void mitk::SurfaceToSurfaceFilter::SetInput( unsigned int idx, const mitk::Surface* surface )
{
  if ( this->GetInput(idx) != surface )
  {
    this->SetNthInput( idx, const_cast<mitk::Surface*>( surface ) );
    this->CreateOutputsForAllInputs(idx);
    this->Modified();
  }
}

const mitk::Surface* mitk::SurfaceToSurfaceFilter::GetInput()
{
  if (this->GetNumberOfInputs() < 1)
    return NULL;

  return static_cast<const mitk::Surface*>(this->ProcessObject::GetInput(0));
}

const mitk::Surface* mitk::SurfaceToSurfaceFilter::GetInput( unsigned int idx)
{
  if (this->GetNumberOfInputs() < 1)
    return NULL;

  return static_cast<const mitk::Surface*>(this->ProcessObject::GetInput(idx));
}

void mitk::SurfaceToSurfaceFilter::CreateOutputsForAllInputs(unsigned int  /*idx*/)
{
  this->SetNumberOfOutputs( this->GetNumberOfInputs() );
  for (unsigned int idx = 0; idx < this->GetNumberOfOutputs(); ++idx)
  {
    if (this->GetOutput(idx) == NULL)
    {
      DataObjectPointer newOutput = this->MakeOutput(idx);
      this->SetNthOutput(idx, newOutput);
    }
    this->GetOutput( idx )->Graft( this->GetInput( idx) );
  }
  this->Modified();
}

void mitk::SurfaceToSurfaceFilter::RemoveInputs(mitk::Surface* input)
{
  this->RemoveInput(input);
}<|endoftext|>


<commit_before>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "mitkLevelWindowManager.h"
#include <itkCommand.h>
#include "mitkDataStorage.h"
#include "mitkNodePredicateBase.h"
#include "mitkNodePredicateProperty.h"
#include "mitkNodePredicateDataType.h"
#include "mitkNodePredicateAnd.h"
#include "mitkNodePredicateOr.h"
#include "mitkNodePredicateNot.h"
#include "mitkProperties.h"
#include "mitkMessage.h"

mitk::LevelWindowManager::LevelWindowManager()
: m_DataStorage(NULL)
, m_LevelWindowProperty(NULL)
, m_AutoTopMost(true)
, m_IsObserverTagSet(false)
, m_CurrentImage(NULL)
, m_IsPropertyModifiedTagSet(false)
{
}

mitk::LevelWindowManager::~LevelWindowManager()
{
  if (m_DataStorage.IsNotNull())
  {
    m_DataStorage->AddNodeEvent.RemoveListener(
        MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageAddedNode ));
    m_DataStorage->RemoveNodeEvent.RemoveListener(
        MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageRemovedNode ));
    m_DataStorage = NULL;
  }

  if (m_IsPropertyModifiedTagSet && m_LevelWindowProperty.IsNotNull())
  {
    m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag);
    m_IsPropertyModifiedTagSet = false;
  }

  //clear both observer maps
  this->ClearPropObserverLists();
}

void mitk::LevelWindowManager::SetDataStorage( mitk::DataStorage* ds )
{
  if (ds == NULL) return;

  /* remove listeners of old DataStorage */
  if (m_DataStorage.IsNotNull())
  {
    m_DataStorage->AddNodeEvent.RemoveListener(
        MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageAddedNode ));
    m_DataStorage->RemoveNodeEvent.RemoveListener(
        MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageRemovedNode ));
  }

  /* register listener for new DataStorage */
  m_DataStorage = ds;  // register
  m_DataStorage->AddNodeEvent.AddListener(
      MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageAddedNode ));
  m_DataStorage->RemoveNodeEvent.AddListener(
      MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageRemovedNode ));

  this->DataStorageAddedNode(); // update us with new DataStorage
}

void mitk::LevelWindowManager::OnPropertyModified(const itk::EventObject& )
{
  Modified();
}

void mitk::LevelWindowManager::SetAutoTopMostImage(bool autoTopMost, const mitk::DataNode* removedNode)
{
  m_AutoTopMost = autoTopMost;
  if (m_AutoTopMost == false)
    return;

  if (m_IsPropertyModifiedTagSet && m_LevelWindowProperty.IsNotNull())
  {
    m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag);
    m_IsPropertyModifiedTagSet = false;
  }

  /* search topmost image */
  if (m_DataStorage.IsNull())
  {
    itkExceptionMacro("DataStorage not set");
  }

  int maxLayer = itk::NumericTraits<int>::min();
  m_LevelWindowProperty = NULL;

  mitk::DataNode::Pointer topLevelNode;

  mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes();
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it)
  {
    mitk::DataNode::Pointer node = it->Value();
    if (node.IsNull() || (removedNode != NULL && node == removedNode))
      continue;

    node->SetBoolProperty( "imageForLevelWindow", false );

    if (node->IsVisible(NULL) == false)
      continue;

    int layer = 0;
    node->GetIntProperty("layer", layer);
    if ( layer < maxLayer )
      continue;

    mitk::LevelWindowProperty::Pointer levelWindowProperty = dynamic_cast<mitk::LevelWindowProperty*>(node->GetProperty("levelwindow"));
    if (levelWindowProperty.IsNull())
      continue;

    m_LevelWindowProperty = levelWindowProperty;
    m_CurrentImage = dynamic_cast<mitk::Image*>(node->GetData());
    topLevelNode = node;

    maxLayer = layer;
  }

  if (topLevelNode.IsNotNull())
  {
    topLevelNode->SetBoolProperty( "imageForLevelWindow", true );
  }

  this->SetLevelWindowProperty( m_LevelWindowProperty );

  if ( m_LevelWindowProperty.IsNull() )
  {
    Modified();
  }
  // else SetLevelWindowProperty will call Modified();
}

// sets an specific LevelWindowProperty, all changes will affect the image belonging to this property.
void mitk::LevelWindowManager::SetLevelWindowProperty(LevelWindowProperty::Pointer levelWindowProperty)
{
  if (levelWindowProperty.IsNull())
    return;

  if (m_IsPropertyModifiedTagSet)  // remove listener for old property
  {
    m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag);
    m_IsPropertyModifiedTagSet = false;
  }

  m_LevelWindowProperty = levelWindowProperty;

  itk::ReceptorMemberCommand<LevelWindowManager>::Pointer command = itk::ReceptorMemberCommand<LevelWindowManager>::New();  // register listener for new property
  command->SetCallbackFunction(this, &LevelWindowManager::OnPropertyModified);
  m_PropertyModifiedTag = m_LevelWindowProperty->AddObserver( itk::ModifiedEvent(), command );
  m_IsPropertyModifiedTagSet = true;

  /* search image than belongs to the property */
  mitk::NodePredicateProperty::Pointer p = mitk::NodePredicateProperty::New("levelwindow", m_LevelWindowProperty);
  mitk::DataNode* n = m_DataStorage->GetNode(p);
  if (n == NULL)
  {
    mitkThrow() << "No Image in DataStorage that belongs to LevelWindow property" << m_LevelWindowProperty;
  }

  m_CurrentImage = dynamic_cast<mitk::Image*>(n->GetData());
  n->SetBoolProperty( "imageForLevelWindow", true );
  this->Modified();
}

// returns the current mitkLevelWindowProperty object from the image that is affected by changes
mitk::LevelWindowProperty::Pointer mitk::LevelWindowManager::GetLevelWindowProperty()
{
  return m_LevelWindowProperty;
}

// returns Level/Window values for the current image
const mitk::LevelWindow& mitk::LevelWindowManager::GetLevelWindow()
{
  if (m_LevelWindowProperty.IsNotNull())
  {
    return m_LevelWindowProperty->GetLevelWindow();
  }
  else
  {
    itkExceptionMacro("No LevelWindow available!");
  }
}

// sets new Level/Window values and informs all listeners about changes
void mitk::LevelWindowManager::SetLevelWindow(const mitk::LevelWindow& levelWindow)
{
  if (m_LevelWindowProperty.IsNotNull())
  {
    m_LevelWindowProperty->SetLevelWindow(levelWindow);
  }
  this->Modified();
}

void mitk::LevelWindowManager::DataStorageAddedNode( const mitk::DataNode* )
{
  //update observers with new data storage
  UpdateObservers();

  //check if everything is still ok
  if ((m_PropObserverToNode.size() != m_PropObserverToNode2.size()) || (m_PropObserverToNode2.size() != this->GetRelevantNodes()->size()))
     {mitkThrow() << "Wrong number of observers in Level Window Manager!";}
}

void mitk::LevelWindowManager::DataStorageRemovedNode( const mitk::DataNode* removedNode )
{
  //remember node which will be removed
  m_NodeMarkedToDelete = removedNode;

  //update observers
  UpdateObservers();

  /* search image than belongs to the property */
  if (m_LevelWindowProperty.IsNull())
  {
    SetAutoTopMostImage(true, removedNode);
  }
  else
  {
    mitk::NodePredicateProperty::Pointer p2 = mitk::NodePredicateProperty::New("levelwindow", m_LevelWindowProperty);
    mitk::DataNode* n = m_DataStorage->GetNode(p2);
    if (n == NULL || m_AutoTopMost) // if node was deleted, change our behaviour to AutoTopMost, if AutoTopMost is true change level window to topmost node
    {
      SetAutoTopMostImage(true, removedNode);
    }
  }

  //reset variable
  m_NodeMarkedToDelete = NULL;

  //check if everything is still ok
  if ((m_PropObserverToNode.size() != m_PropObserverToNode2.size()) || (m_PropObserverToNode2.size() != (this->GetRelevantNodes()->size()-1)))
     {mitkThrow() << "Wrong number of observers in Level Window Manager!";}
}

void mitk::LevelWindowManager::UpdateObservers()
{
  this->ClearPropObserverLists(); //remove old observers
  CreatePropObserverLists(); //create new observer lists

}

int mitk::LevelWindowManager::GetNumberOfObservers()
{
  return m_PropObserverToNode.size();
}

mitk::DataStorage* mitk::LevelWindowManager::GetDataStorage()
{
  return m_DataStorage.GetPointer();
}

// true if changes on slider or line-edits will affect always the topmost layer image
bool mitk::LevelWindowManager::isAutoTopMost()
{
  return m_AutoTopMost;
}

void mitk::LevelWindowManager::Update(const itk::EventObject&)  // visible property of a image has changed
{
  if (m_AutoTopMost)
  {
    SetAutoTopMostImage(true);
    return;
  }
  mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes();
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin();
       it != all->End();
       ++it)
  {
    mitk::DataNode::Pointer node = it->Value();
    if (node.IsNull())
      continue;

    node->SetBoolProperty( "imageForLevelWindow", false );

    if (node->IsVisible(NULL) == false)
      continue;

    mitk::LevelWindowProperty::Pointer levelWindowProperty = dynamic_cast<mitk::LevelWindowProperty*>(node->GetProperty("levelwindow"));
    if (levelWindowProperty.IsNull())
      continue;

    m_LevelWindowProperty = levelWindowProperty;
    m_CurrentImage = dynamic_cast<mitk::Image*>(node->GetData());
    node->SetBoolProperty( "imageForLevelWindow", true );
    if (m_LevelWindowProperty.IsNull() && m_LevelWindowProperty.GetPointer() == levelWindowProperty) // we found our m_LevelWindowProperty
    {
      return;
    }
  }
  Modified();
}

mitk::DataStorage::SetOfObjects::ConstPointer mitk::LevelWindowManager::GetRelevantNodes()
{
  if (m_DataStorage.IsNull())
    return mitk::DataStorage::SetOfObjects::ConstPointer(mitk::DataStorage::SetOfObjects::New());  // return empty set

  mitk::BoolProperty::Pointer trueProp = mitk::BoolProperty::New(true);
  mitk::NodePredicateProperty::Pointer notBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(false));
  mitk::NodePredicateProperty::Pointer hasLevelWindow = mitk::NodePredicateProperty::New("levelwindow", NULL);

  mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image");
  mitk::NodePredicateDataType::Pointer isDImage = mitk::NodePredicateDataType::New("DiffusionImage");
  mitk::NodePredicateDataType::Pointer isTImage = mitk::NodePredicateDataType::New("TensorImage");
  mitk::NodePredicateDataType::Pointer isQImage = mitk::NodePredicateDataType::New("QBallImage");
  mitk::NodePredicateOr::Pointer predicateTypes = mitk::NodePredicateOr::New();
  predicateTypes->AddPredicate(isImage);
  predicateTypes->AddPredicate(isDImage);
  predicateTypes->AddPredicate(isTImage);
  predicateTypes->AddPredicate(isQImage);

  mitk::NodePredicateAnd::Pointer predicate = mitk::NodePredicateAnd::New();
  predicate->AddPredicate(notBinary);
  predicate->AddPredicate(hasLevelWindow);
  predicate->AddPredicate(predicateTypes);

  mitk::DataStorage::SetOfObjects::ConstPointer relevantNodes = m_DataStorage->GetSubset( predicate );

  return relevantNodes;
}

mitk::Image* mitk::LevelWindowManager::GetCurrentImage()
{
  return m_CurrentImage;
}

void mitk::LevelWindowManager::ClearPropObserverLists()
{
for( ObserverToPropertyMap::iterator iter = m_PropObserverToNode.begin();
       iter != m_PropObserverToNode.end();
       ++iter )
  {
    (*iter).second->RemoveObserver((*iter).first.first);
    (*iter).second = 0;
  }
  m_PropObserverToNode.clear();

  for( ObserverToPropertyMap::iterator iter = m_PropObserverToNode2.begin();
       iter != m_PropObserverToNode2.end();
       ++iter )
  {
    (*iter).second->RemoveObserver((*iter).first.first);
    (*iter).second = 0;
  }
  m_PropObserverToNode2.clear();
}

void mitk::LevelWindowManager::CreatePropObserverLists()
{
  if (m_DataStorage.IsNull())     //check if data storage is set
    {itkExceptionMacro("DataStorage not set");}

  /* add observers for all relevant nodes */
  mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes();
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin();
       it != all->End();
       ++it)
  {
    if ((it->Value().IsNull()) || (it->Value() == m_NodeMarkedToDelete))
      {continue;}

    /* register listener for changes in visible property */
    itk::ReceptorMemberCommand<LevelWindowManager>::Pointer command = itk::ReceptorMemberCommand<LevelWindowManager>::New();
    command->SetCallbackFunction(this, &LevelWindowManager::Update);
    unsigned long idx = it->Value()->GetProperty("visible")->AddObserver( itk::ModifiedEvent(), command );
    m_PropObserverToNode[PropDataPair(idx, it->Value())] = it->Value()->GetProperty("visible");
  }

  /* add observers for all layer properties*/
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin();
       it != all->End();
       ++it)
  {
    if ((it->Value().IsNull()) || (it->Value() == m_NodeMarkedToDelete))
      {continue;}
    /* register listener for changes in layer property */
    itk::ReceptorMemberCommand<LevelWindowManager>::Pointer command2 = itk::ReceptorMemberCommand<LevelWindowManager>::New();
    command2->SetCallbackFunction(this, &LevelWindowManager::Update);
    unsigned long idx = it->Value()->GetProperty("layer")->AddObserver( itk::ModifiedEvent(), command2 );
    m_PropObserverToNode2[PropDataPair(idx, it->Value())] = it->Value()->GetProperty("layer");
  }

}
<commit_msg>added a check if the removed node is relevant<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "mitkLevelWindowManager.h"
#include <itkCommand.h>
#include "mitkDataStorage.h"
#include "mitkNodePredicateBase.h"
#include "mitkNodePredicateProperty.h"
#include "mitkNodePredicateDataType.h"
#include "mitkNodePredicateAnd.h"
#include "mitkNodePredicateOr.h"
#include "mitkNodePredicateNot.h"
#include "mitkProperties.h"
#include "mitkMessage.h"

mitk::LevelWindowManager::LevelWindowManager()
: m_DataStorage(NULL)
, m_LevelWindowProperty(NULL)
, m_AutoTopMost(true)
, m_IsObserverTagSet(false)
, m_CurrentImage(NULL)
, m_IsPropertyModifiedTagSet(false)
{
}

mitk::LevelWindowManager::~LevelWindowManager()
{
  if (m_DataStorage.IsNotNull())
  {
    m_DataStorage->AddNodeEvent.RemoveListener(
        MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageAddedNode ));
    m_DataStorage->RemoveNodeEvent.RemoveListener(
        MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageRemovedNode ));
    m_DataStorage = NULL;
  }

  if (m_IsPropertyModifiedTagSet && m_LevelWindowProperty.IsNotNull())
  {
    m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag);
    m_IsPropertyModifiedTagSet = false;
  }

  //clear both observer maps
  this->ClearPropObserverLists();
}

void mitk::LevelWindowManager::SetDataStorage( mitk::DataStorage* ds )
{
  if (ds == NULL) return;

  /* remove listeners of old DataStorage */
  if (m_DataStorage.IsNotNull())
  {
    m_DataStorage->AddNodeEvent.RemoveListener(
        MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageAddedNode ));
    m_DataStorage->RemoveNodeEvent.RemoveListener(
        MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageRemovedNode ));
  }

  /* register listener for new DataStorage */
  m_DataStorage = ds;  // register
  m_DataStorage->AddNodeEvent.AddListener(
      MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageAddedNode ));
  m_DataStorage->RemoveNodeEvent.AddListener(
      MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageRemovedNode ));

  this->DataStorageAddedNode(); // update us with new DataStorage
}

void mitk::LevelWindowManager::OnPropertyModified(const itk::EventObject& )
{
  Modified();
}

void mitk::LevelWindowManager::SetAutoTopMostImage(bool autoTopMost, const mitk::DataNode* removedNode)
{
  m_AutoTopMost = autoTopMost;
  if (m_AutoTopMost == false)
    return;

  if (m_IsPropertyModifiedTagSet && m_LevelWindowProperty.IsNotNull())
  {
    m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag);
    m_IsPropertyModifiedTagSet = false;
  }

  /* search topmost image */
  if (m_DataStorage.IsNull())
  {
    itkExceptionMacro("DataStorage not set");
  }

  int maxLayer = itk::NumericTraits<int>::min();
  m_LevelWindowProperty = NULL;

  mitk::DataNode::Pointer topLevelNode;

  mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes();
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it)
  {
    mitk::DataNode::Pointer node = it->Value();
    if (node.IsNull() || (removedNode != NULL && node == removedNode))
      continue;

    node->SetBoolProperty( "imageForLevelWindow", false );

    if (node->IsVisible(NULL) == false)
      continue;

    int layer = 0;
    node->GetIntProperty("layer", layer);
    if ( layer < maxLayer )
      continue;

    mitk::LevelWindowProperty::Pointer levelWindowProperty = dynamic_cast<mitk::LevelWindowProperty*>(node->GetProperty("levelwindow"));
    if (levelWindowProperty.IsNull())
      continue;

    m_LevelWindowProperty = levelWindowProperty;
    m_CurrentImage = dynamic_cast<mitk::Image*>(node->GetData());
    topLevelNode = node;

    maxLayer = layer;
  }

  if (topLevelNode.IsNotNull())
  {
    topLevelNode->SetBoolProperty( "imageForLevelWindow", true );
  }

  this->SetLevelWindowProperty( m_LevelWindowProperty );

  if ( m_LevelWindowProperty.IsNull() )
  {
    Modified();
  }
  // else SetLevelWindowProperty will call Modified();
}

// sets an specific LevelWindowProperty, all changes will affect the image belonging to this property.
void mitk::LevelWindowManager::SetLevelWindowProperty(LevelWindowProperty::Pointer levelWindowProperty)
{
  if (levelWindowProperty.IsNull())
    return;

  if (m_IsPropertyModifiedTagSet)  // remove listener for old property
  {
    m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag);
    m_IsPropertyModifiedTagSet = false;
  }

  m_LevelWindowProperty = levelWindowProperty;

  itk::ReceptorMemberCommand<LevelWindowManager>::Pointer command = itk::ReceptorMemberCommand<LevelWindowManager>::New();  // register listener for new property
  command->SetCallbackFunction(this, &LevelWindowManager::OnPropertyModified);
  m_PropertyModifiedTag = m_LevelWindowProperty->AddObserver( itk::ModifiedEvent(), command );
  m_IsPropertyModifiedTagSet = true;

  /* search image than belongs to the property */
  mitk::NodePredicateProperty::Pointer p = mitk::NodePredicateProperty::New("levelwindow", m_LevelWindowProperty);
  mitk::DataNode* n = m_DataStorage->GetNode(p);
  if (n == NULL)
  {
    mitkThrow() << "No Image in DataStorage that belongs to LevelWindow property" << m_LevelWindowProperty;
  }

  m_CurrentImage = dynamic_cast<mitk::Image*>(n->GetData());
  n->SetBoolProperty( "imageForLevelWindow", true );
  this->Modified();
}

// returns the current mitkLevelWindowProperty object from the image that is affected by changes
mitk::LevelWindowProperty::Pointer mitk::LevelWindowManager::GetLevelWindowProperty()
{
  return m_LevelWindowProperty;
}

// returns Level/Window values for the current image
const mitk::LevelWindow& mitk::LevelWindowManager::GetLevelWindow()
{
  if (m_LevelWindowProperty.IsNotNull())
  {
    return m_LevelWindowProperty->GetLevelWindow();
  }
  else
  {
    itkExceptionMacro("No LevelWindow available!");
  }
}

// sets new Level/Window values and informs all listeners about changes
void mitk::LevelWindowManager::SetLevelWindow(const mitk::LevelWindow& levelWindow)
{
  if (m_LevelWindowProperty.IsNotNull())
  {
    m_LevelWindowProperty->SetLevelWindow(levelWindow);
  }
  this->Modified();
}

void mitk::LevelWindowManager::DataStorageAddedNode( const mitk::DataNode* )
{
  //update observers with new data storage
  UpdateObservers();

  //check if everything is still ok
  if ((m_PropObserverToNode.size() != m_PropObserverToNode2.size()) || (m_PropObserverToNode2.size() != this->GetRelevantNodes()->size()))
     {mitkThrow() << "Wrong number of observers in Level Window Manager!";}
}

void mitk::LevelWindowManager::DataStorageRemovedNode( const mitk::DataNode* removedNode )
{
  //first: check if deleted node is part of relevant nodes. If not, abort method because there is no need change anything.
  if ((this->GetRelevantNodes()->size() == 0)) return;
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = this->GetRelevantNodes()->Begin();
       it != this->GetRelevantNodes()->End();
       ++it)
  {if (it->Value() == removedNode) {return;}}

  //remember node which will be removed
  m_NodeMarkedToDelete = removedNode;

  //update observers
  UpdateObservers();

  /* search image than belongs to the property */
  if (m_LevelWindowProperty.IsNull())
  {
    SetAutoTopMostImage(true, removedNode);
  }
  else
  {
    mitk::NodePredicateProperty::Pointer p2 = mitk::NodePredicateProperty::New("levelwindow", m_LevelWindowProperty);
    mitk::DataNode* n = m_DataStorage->GetNode(p2);
    if (n == NULL || m_AutoTopMost) // if node was deleted, change our behaviour to AutoTopMost, if AutoTopMost is true change level window to topmost node
    {
      SetAutoTopMostImage(true, removedNode);
    }
  }

  //reset variable
  m_NodeMarkedToDelete = NULL;

  //check if everything is still ok
  MITK_INFO << "Size Observers 1: " << m_PropObserverToNode.size();
  MITK_INFO << "Size Observers 2: " << m_PropObserverToNode2.size();
  MITK_INFO << "Size Observers Relevant Nodes: " << GetRelevantNodes()->size();
  if ((m_PropObserverToNode.size() != m_PropObserverToNode2.size()) || (m_PropObserverToNode2.size() != (this->GetRelevantNodes()->size()-1)))
     {
     MITK_ERROR << "Wrong number of observers in Level Window Manager!";
     mitkThrow() << "Wrong number of observers in Level Window Manager!";
     }

}

void mitk::LevelWindowManager::UpdateObservers()
{
  this->ClearPropObserverLists(); //remove old observers
  CreatePropObserverLists(); //create new observer lists

}

int mitk::LevelWindowManager::GetNumberOfObservers()
{
  return m_PropObserverToNode.size();
}

mitk::DataStorage* mitk::LevelWindowManager::GetDataStorage()
{
  return m_DataStorage.GetPointer();
}

// true if changes on slider or line-edits will affect always the topmost layer image
bool mitk::LevelWindowManager::isAutoTopMost()
{
  return m_AutoTopMost;
}

void mitk::LevelWindowManager::Update(const itk::EventObject&)  // visible property of a image has changed
{
  if (m_AutoTopMost)
  {
    SetAutoTopMostImage(true);
    return;
  }
  mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes();
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin();
       it != all->End();
       ++it)
  {
    mitk::DataNode::Pointer node = it->Value();
    if (node.IsNull())
      continue;

    node->SetBoolProperty( "imageForLevelWindow", false );

    if (node->IsVisible(NULL) == false)
      continue;

    mitk::LevelWindowProperty::Pointer levelWindowProperty = dynamic_cast<mitk::LevelWindowProperty*>(node->GetProperty("levelwindow"));
    if (levelWindowProperty.IsNull())
      continue;

    m_LevelWindowProperty = levelWindowProperty;
    m_CurrentImage = dynamic_cast<mitk::Image*>(node->GetData());
    node->SetBoolProperty( "imageForLevelWindow", true );
    if (m_LevelWindowProperty.IsNull() && m_LevelWindowProperty.GetPointer() == levelWindowProperty) // we found our m_LevelWindowProperty
    {
      return;
    }
  }
  Modified();
}

mitk::DataStorage::SetOfObjects::ConstPointer mitk::LevelWindowManager::GetRelevantNodes()
{
  if (m_DataStorage.IsNull())
    return mitk::DataStorage::SetOfObjects::ConstPointer(mitk::DataStorage::SetOfObjects::New());  // return empty set

  mitk::BoolProperty::Pointer trueProp = mitk::BoolProperty::New(true);
  mitk::NodePredicateProperty::Pointer notBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(false));
  mitk::NodePredicateProperty::Pointer hasLevelWindow = mitk::NodePredicateProperty::New("levelwindow", NULL);

  mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image");
  mitk::NodePredicateDataType::Pointer isDImage = mitk::NodePredicateDataType::New("DiffusionImage");
  mitk::NodePredicateDataType::Pointer isTImage = mitk::NodePredicateDataType::New("TensorImage");
  mitk::NodePredicateDataType::Pointer isQImage = mitk::NodePredicateDataType::New("QBallImage");
  mitk::NodePredicateOr::Pointer predicateTypes = mitk::NodePredicateOr::New();
  predicateTypes->AddPredicate(isImage);
  predicateTypes->AddPredicate(isDImage);
  predicateTypes->AddPredicate(isTImage);
  predicateTypes->AddPredicate(isQImage);

  mitk::NodePredicateAnd::Pointer predicate = mitk::NodePredicateAnd::New();
  predicate->AddPredicate(notBinary);
  predicate->AddPredicate(hasLevelWindow);
  predicate->AddPredicate(predicateTypes);

  mitk::DataStorage::SetOfObjects::ConstPointer relevantNodes = m_DataStorage->GetSubset( predicate );

  return relevantNodes;
}

mitk::Image* mitk::LevelWindowManager::GetCurrentImage()
{
  return m_CurrentImage;
}

void mitk::LevelWindowManager::ClearPropObserverLists()
{
for( ObserverToPropertyMap::iterator iter = m_PropObserverToNode.begin();
       iter != m_PropObserverToNode.end();
       ++iter )
  {
    (*iter).second->RemoveObserver((*iter).first.first);
    (*iter).second = 0;
  }
  m_PropObserverToNode.clear();

  for( ObserverToPropertyMap::iterator iter = m_PropObserverToNode2.begin();
       iter != m_PropObserverToNode2.end();
       ++iter )
  {
    (*iter).second->RemoveObserver((*iter).first.first);
    (*iter).second = 0;
  }
  m_PropObserverToNode2.clear();
}

void mitk::LevelWindowManager::CreatePropObserverLists()
{
  if (m_DataStorage.IsNull())     //check if data storage is set
    {itkExceptionMacro("DataStorage not set");}

  /* add observers for all relevant nodes */
  mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes();
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin();
       it != all->End();
       ++it)
  {
    if ((it->Value().IsNull()) || (it->Value() == m_NodeMarkedToDelete))
      {continue;}

    /* register listener for changes in visible property */
    itk::ReceptorMemberCommand<LevelWindowManager>::Pointer command = itk::ReceptorMemberCommand<LevelWindowManager>::New();
    command->SetCallbackFunction(this, &LevelWindowManager::Update);
    unsigned long idx = it->Value()->GetProperty("visible")->AddObserver( itk::ModifiedEvent(), command );
    m_PropObserverToNode[PropDataPair(idx, it->Value())] = it->Value()->GetProperty("visible");
  }

  /* add observers for all layer properties*/
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin();
       it != all->End();
       ++it)
  {
    if ((it->Value().IsNull()) || (it->Value() == m_NodeMarkedToDelete))
      {continue;}
    /* register listener for changes in layer property */
    itk::ReceptorMemberCommand<LevelWindowManager>::Pointer command2 = itk::ReceptorMemberCommand<LevelWindowManager>::New();
    command2->SetCallbackFunction(this, &LevelWindowManager::Update);
    unsigned long idx = it->Value()->GetProperty("layer")->AddObserver( itk::ModifiedEvent(), command2 );
    m_PropObserverToNode2[PropDataPair(idx, it->Value())] = it->Value()->GetProperty("layer");
  }

}
<|endoftext|>


<commit_before>/*-----------------------------------------------------------------------------------------------
The MIT License (MIT)

Copyright (c) 2015 OSRE ( Open Source Render Engine ) by Kim Kulling

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.
-----------------------------------------------------------------------------------------------*/
#include <osre/Scene/GeometryBuilder.h>

#include <GL/glew.h>
#include <GL/gl.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/string_cast.hpp>

#include <vector>

namespace OSRE {
namespace Scene {

using namespace ::OSRE::RenderBackend;

const String VsSrc =
    "#version 400 core\n"
    "\n"
    "layout(location = 0) in vec3 position;	      // object space vertex position\n"
    "layout(location = 1) in vec3 normal;	            // object space vertex normal\n"
    "layout(location = 2) in vec3 color0;  // per-vertex colour\n"
    "\n"
    "// output from the vertex shader\n"
    "smooth out vec4 vSmoothColor;		//smooth colour to fragment shader\n"
    "\n"
    "// uniform\n"
    "uniform mat4 MVP;	//combined modelview projection matrix\n"
    "\n"
    "void main()\n"
    "{\n"
    "    //assign the per-vertex color to vSmoothColor varying\n"
    "    vSmoothColor = vec4(color0,1);\n"
    "\n"
    "    //get the clip space position by multiplying the combined MVP matrix with the object space\n"
    "    //vertex position\n"
    "    gl_Position = MVP*vec4(position,1);\n"
    "}\n";

const String FsSrc =
    "#version 400 core\n"
    "\n"
    "layout(location=0) out vec4 vFragColor; //fragment shader output\n"
    "\n"
    "//input form the vertex shader\n"
    "smooth in vec4 vSmoothColor;		//interpolated colour to fragment shader\n"
    "\n"
    "void main()\n"
    "{\n"
    "    //set the interpolated color as the shader output\n"
    "    vFragColor = vSmoothColor;\n"
    "}\n";

static const String TextVsSrc =
	"layout(location = 0) in vec3 position;	      // object space vertex position\n"
	"layout(location = 1) in vec3 normal;	            // object space vertex normal\n"
	"layout(location = 2) in vec2 texcoord0;	        // texture coordinate\n"
	"out vec2 vUV;\n"
	"\n"
	"void main() {\n"
	"    vec3 vertexPosition_homoneneousspace = position;\n"
	"    gl_Position = vec4(position, 1 );\n"
	"    // UV of the vertex. No special space for this one.\n"
	"    UV = texcoord0;\n"
	"};\n";

static const String TextFsSrc =
	"in vec2 vUV;\n"
	"// Output data\n"
	"out vec4 vFragColor;\n"
	"uniform sampler2D tex0;\n"

	"void main() {\n"
	"    vFragColor = texture( tex0, vUV );\n"
	"};\n";

//-------------------------------------------------------------------------------------------------
GeometryBuilder::GeometryBuilder() {
    // empty
}

//-------------------------------------------------------------------------------------------------
GeometryBuilder::~GeometryBuilder() {
    // empty
}

//-------------------------------------------------------------------------------------------------
RenderBackend::Geometry *GeometryBuilder::createEmptyGeometry( RenderBackend::VertexType type ) {
    Geometry *geo = new Geometry;
    geo->m_vertextype = type;
    geo->m_indextype = UnsignedShort;

    return geo;
}

//-------------------------------------------------------------------------------------------------
RenderBackend::Geometry *GeometryBuilder::createTriangle() {
    Geometry *geo = new Geometry;
    geo->m_vertextype = ColorVertex;
    geo->m_indextype = UnsignedShort;

    // setup triangle vertices
    static const ui32 NumVert = 3;
    ColorVert vertices[ NumVert ];
    vertices[ 0 ].color = glm::vec3( 1, 0, 0 );
    vertices[ 1 ].color = glm::vec3( 0, 1, 0 );
    vertices[ 2 ].color = glm::vec3( 0, 0, 1 );

    vertices[ 0 ].position = glm::vec3( -1, -1, 0 );
    vertices[ 1 ].position = glm::vec3( 0, 1, 0 );
    vertices[ 2 ].position = glm::vec3( 1, -1, 0 );

    ui32 size( sizeof( ColorVert ) * NumVert );
    geo->m_vb = BufferData::alloc( VertexBuffer, size, ReadOnly );
    ::memcpy( geo->m_vb->m_pData, vertices, size );

    // setup triangle indices
    static const ui32 NumIndices = 3;
    GLushort  indices[ NumIndices ];
    indices[ 0 ] = 0;
    indices[ 1 ] = 1;
    indices[ 2 ] = 2;

    size = sizeof( GLushort ) * NumIndices;
    geo->m_ib = BufferData::alloc( IndexBuffer, size, ReadOnly );
    ::memcpy( geo->m_ib->m_pData, indices, size );

	// setup primitives
    geo->m_numPrimGroups = 1;
    geo->m_pPrimGroups   = new PrimitiveGroup[ geo->m_numPrimGroups ];
    geo->m_pPrimGroups[ 0 ].m_indexType     = UnsignedShort;
    geo->m_pPrimGroups[ 0 ].m_numPrimitives = 3 * geo->m_numPrimGroups;
    geo->m_pPrimGroups[ 0 ].m_primitive     = TriangleList;
    geo->m_pPrimGroups[ 0 ].m_startIndex    = 0;

	// setup material
    geo->m_material = new Material;
    geo->m_material->m_numTextures = 0;
    geo->m_material->m_type = ShaderMaterial;
    geo->m_material->m_pShader = new Shader;
    geo->m_material->m_pShader->m_src[ SH_VertexShaderType ] = VsSrc;
    geo->m_material->m_pShader->m_src[ SH_FragmentShaderType ] = FsSrc;

	// setup shader attributes and variables
    if( nullptr != geo->m_material->m_pShader ) {
        ui32 numAttribs( ColorVert::getNumAttributes() );
        const String *attribs( ColorVert::getAttributes() );
        geo->m_material->m_pShader->m_attributes.add(attribs, numAttribs);
        geo->m_material->m_pShader->m_parameters.add( "MVP" );
    }

    return geo;
}

//-------------------------------------------------------------------------------------------------
RenderBackend::Geometry *GeometryBuilder::createBox( f32 w, f32 h, f32 d ) {
    Geometry *pGeometry = new Geometry;
    pGeometry->m_vertextype = ColorVertex;
    pGeometry->m_indextype  = UnsignedShort;

    static const ui32 NumVert = 8;

    ColorVert vertices[ NumVert ];
    f32 x(0.0f), y(0.0f), z( 0.0f );
    vertices[ 0 ].position = glm::vec3( x,     y,     z );
    vertices[ 1 ].position = glm::vec3( x + w, y,     z );
    vertices[ 2 ].position = glm::vec3( x + w, y + h, z );
    vertices[ 3 ].position = glm::vec3( x,     y + h, z );

    vertices[ 4 ].position = glm::vec3( x,     y,     z + d );
    vertices[ 5 ].position = glm::vec3( x + w, y,     z + d );
    vertices[ 6 ].position = glm::vec3( x + w, y + h, z + d );
    vertices[ 7 ].position = glm::vec3( x,     y + h, z + d );

    ui32 size( sizeof( ColorVert ) * NumVert );
    pGeometry->m_vb = BufferData::alloc( VertexBuffer, size, ReadOnly );
    ::memcpy( pGeometry->m_vb->m_pData, vertices, size );

    static const ui32 NumIndices = 36;
    GLushort  indices[ NumIndices ];
    indices[ 0 ] = 0;
    indices[ 1 ] = 1;
    indices[ 2 ] = 2;
    indices[ 3 ] = 0+3;
    indices[ 4 ] = 1+3;
    indices[ 5 ] = 2+3;

    indices[ 6 ] = 0+6;
    indices[ 7 ] = 1+6;
    indices[ 8 ] = 2+6;
    indices[ 9 ] = 0+9;
    indices[ 10 ] = 1+9;
    indices[ 11 ] = 2+9;

    indices[ 12 ] = 0+12;
    indices[ 13 ] = 1+12;
    indices[ 14 ] = 2+12;
    indices[ 15 ] = 0+15;
    indices[ 16 ] = 1+15;
    indices[ 17 ] = 2+15;

    indices[ 18 ] = 0+18;
    indices[ 19 ] = 1 + 18;
    indices[ 20 ] = 2 + 18;
    indices[ 21 ] = 0+21;
    indices[ 22 ] = 1 + 21;
    indices[ 23 ] = 2 + 21;

    indices[ 24 ] = 0+24;
    indices[ 25 ] = 1 + 24;
    indices[ 26 ] = 2 + 24;
    indices[ 27 ] = 0+27;
    indices[ 28 ] = 1 + 27;
    indices[ 29 ] = 2 + 27;

    indices[ 30 ] = 0+30;
    indices[ 31 ] = 1 + 30;
    indices[ 32 ] = 2 + 30;
    indices[ 33 ] = 0+33;
    indices[ 34 ] = 1 + 33;
    indices[ 35 ] = 2 + 33;
    size = sizeof( GLushort ) * NumIndices;
    pGeometry->m_ib = BufferData::alloc( IndexBuffer, size, ReadOnly );
    ::memcpy( pGeometry->m_ib->m_pData, indices, size );

    return pGeometry;
}

//-------------------------------------------------------------------------------------------------
RenderBackend::Geometry *GeometryBuilder::createTextBox( f32 x, f32 y, f32 size, const String &text ) {
	if ( text.empty() ) {
		return nullptr;
	}

	Geometry *geo = new Geometry;
	std::vector<RenderVert> vertices;
	std::vector<GLushort> indices;
	for (ui32 i = 0; i <text.size(); i++) {
		RenderVert vert[ 4 ];
		vert[ 0 ].position = glm::vec3( x + i*size, y + size, 0 );
		vert[ 1 ].position = glm::vec3( x + i*size + size, y + size, 0 );
		vert[ 2 ].position = glm::vec3( x + i*size + size, y, 0 );
		vert[ 3 ].position = glm::vec3( x + i*size, y, 0 );

		char character = text[ i ];
		float uv_x = ( character % 16 ) / 16.0f;
		float uv_y = ( character / 16 ) / 16.0f;
		vert[ 0 ].tex0 = glm::vec2( uv_x, 1.0f - uv_y );
		vert[ 1 ].tex0 = glm::vec2( uv_x + 1.0f / 16.0f, 1.0f - uv_y );
		vert[ 2 ].tex0 = glm::vec2( uv_x + 1.0f / 16.0f, 1.0f - ( uv_y + 1.0f / 16.0f ) );
		vert[ 3 ].tex0 = glm::vec2( uv_x, 1.0f - ( uv_y + 1.0f / 16.0f ) );

		for (ui32 j = 0; j < 4; j++) {
			vertices.push_back( vert[ j ] );
		}

		// setup indices
		static const ui32 NumIndices = 6;
		GLushort  quad[ NumIndices ];
		quad[ 0 ] = 0;
		quad[ 1 ] = 1;
		quad[ 2 ] = 2;

		quad[ 0 ] = 2;
		quad[ 1 ] = 3;
		quad[ 2 ] = 1;

		for (ui32 j = 0; j < 6; ++j) {
			indices.push_back( quad[ i ] + (i*4) );
		}
	}

	const ui32 vertSize( vertices.size() * sizeof( RenderVert ) );
	BufferData *bufferData = BufferData::alloc( VertexBuffer, vertSize, ReadWrite );
	::memcpy( bufferData->m_pData, &vertices[ 0 ], vertSize );
	geo->m_vb = bufferData;

	size = sizeof( GLushort ) * text.size() * 6;
	geo->m_ib = BufferData::alloc( IndexBuffer, size, ReadOnly );
	::memcpy( geo->m_ib->m_pData, &indices[ 0 ], size );

	geo->m_numPrimGroups = 1;
	geo->m_pPrimGroups = new PrimitiveGroup[ geo->m_numPrimGroups ];
	geo->m_pPrimGroups[ 0 ].m_indexType = UnsignedShort;
	geo->m_pPrimGroups[ 0 ].m_numPrimitives = text.size()*2;
	geo->m_pPrimGroups[ 0 ].m_primitive = TriangleList;
	geo->m_pPrimGroups[ 0 ].m_startIndex = 0;

	// setup material
	geo->m_material = new Material;
	geo->m_material->m_numTextures = 0;
	geo->m_material->m_type = ShaderMaterial;
	geo->m_material->m_pShader = new Shader;
	geo->m_material->m_pShader->m_src[ SH_VertexShaderType ] = VsSrc;
	geo->m_material->m_pShader->m_src[ SH_FragmentShaderType ] = FsSrc;

	// setup shader attributes and variables
	if (nullptr != geo->m_material->m_pShader) {
		ui32 numAttribs( ColorVert::getNumAttributes() );
		const String *attribs( ColorVert::getAttributes() );
		geo->m_material->m_pShader->m_attributes.add( attribs, numAttribs );
		geo->m_material->m_pShader->m_parameters.add( "MVP" );
	}

	return geo;
}

//-------------------------------------------------------------------------------------------------

} // Namespace Scene
} // namespace OSRE
<commit_msg>RenderBackend: add missing cpp-file OGLCommon.cpp<commit_after>/*-----------------------------------------------------------------------------------------------
The MIT License (MIT)

Copyright (c) 2015 OSRE ( Open Source Render Engine ) by Kim Kulling

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.
-----------------------------------------------------------------------------------------------*/
#include <osre/Scene/GeometryBuilder.h>

#include <GL/glew.h>
#include <GL/gl.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/string_cast.hpp>

#include <vector>

namespace OSRE {
namespace Scene {

using namespace ::OSRE::RenderBackend;

const String VsSrc =
    "#version 400 core\n"
    "\n"
    "layout(location = 0) in vec3 position;	      // object space vertex position\n"
    "layout(location = 1) in vec3 normal;	            // object space vertex normal\n"
    "layout(location = 2) in vec3 color0;  // per-vertex colour\n"
    "\n"
    "// output from the vertex shader\n"
    "smooth out vec4 vSmoothColor;		//smooth colour to fragment shader\n"
    "\n"
    "// uniform\n"
    "uniform mat4 MVP;	//combined modelview projection matrix\n"
    "\n"
    "void main()\n"
    "{\n"
    "    //assign the per-vertex color to vSmoothColor varying\n"
    "    vSmoothColor = vec4(color0,1);\n"
    "\n"
    "    //get the clip space position by multiplying the combined MVP matrix with the object space\n"
    "    //vertex position\n"
    "    gl_Position = MVP*vec4(position,1);\n"
    "}\n";

const String FsSrc =
    "#version 400 core\n"
    "\n"
    "layout(location=0) out vec4 vFragColor; //fragment shader output\n"
    "\n"
    "//input form the vertex shader\n"
    "smooth in vec4 vSmoothColor;		//interpolated colour to fragment shader\n"
    "\n"
    "void main()\n"
    "{\n"
    "    //set the interpolated color as the shader output\n"
    "    vFragColor = vSmoothColor;\n"
    "}\n";

static const String TextVsSrc =
	"layout(location = 0) in vec3 position;	      // object space vertex position\n"
	"layout(location = 1) in vec3 normal;	            // object space vertex normal\n"
	"layout(location = 2) in vec2 texcoord0;	        // texture coordinate\n"
	"out vec2 vUV;\n"
	"\n"
	"void main() {\n"
	"    vec3 vertexPosition_homoneneousspace = position;\n"
	"    gl_Position = vec4(position, 1 );\n"
	"    // UV of the vertex. No special space for this one.\n"
	"    UV = texcoord0;\n"
	"};\n";

static const String TextFsSrc =
	"in vec2 vUV;\n"
	"// Output data\n"
	"out vec4 vFragColor;\n"
	"uniform sampler2D tex0;\n"

	"void main() {\n"
	"    vFragColor = texture( tex0, vUV );\n"
	"};\n";

//-------------------------------------------------------------------------------------------------
GeometryBuilder::GeometryBuilder() {
    // empty
}

//-------------------------------------------------------------------------------------------------
GeometryBuilder::~GeometryBuilder() {
    // empty
}

//-------------------------------------------------------------------------------------------------
RenderBackend::Geometry *GeometryBuilder::createEmptyGeometry( RenderBackend::VertexType type ) {
    Geometry *geo = new Geometry;
    geo->m_vertextype = type;
    geo->m_indextype = UnsignedShort;

    return geo;
}

//-------------------------------------------------------------------------------------------------
RenderBackend::Geometry *GeometryBuilder::createTriangle() {
    Geometry *geo = new Geometry;
    geo->m_vertextype = ColorVertex;
    geo->m_indextype = UnsignedShort;

    // setup triangle vertices
    static const ui32 NumVert = 3;
    ColorVert vertices[ NumVert ];
    vertices[ 0 ].color = glm::vec3( 1, 0, 0 );
    vertices[ 1 ].color = glm::vec3( 0, 1, 0 );
    vertices[ 2 ].color = glm::vec3( 0, 0, 1 );

    vertices[ 0 ].position = glm::vec3( -1, -1, 0 );
    vertices[ 1 ].position = glm::vec3( 0, 1, 0 );
    vertices[ 2 ].position = glm::vec3( 1, -1, 0 );

    ui32 size( sizeof( ColorVert ) * NumVert );
    geo->m_vb = BufferData::alloc( VertexBuffer, size, ReadOnly );
    ::memcpy( geo->m_vb->m_pData, vertices, size );

    // setup triangle indices
    static const ui32 NumIndices = 3;
    GLushort  indices[ NumIndices ];
    indices[ 0 ] = 0;
    indices[ 1 ] = 1;
    indices[ 2 ] = 2;

    size = sizeof( GLushort ) * NumIndices;
    geo->m_ib = BufferData::alloc( IndexBuffer, size, ReadOnly );
    ::memcpy( geo->m_ib->m_pData, indices, size );

	// setup primitives
    geo->m_numPrimGroups = 1;
    geo->m_pPrimGroups   = new PrimitiveGroup[ geo->m_numPrimGroups ];
    geo->m_pPrimGroups[ 0 ].m_indexType     = UnsignedShort;
    geo->m_pPrimGroups[ 0 ].m_numPrimitives = 3 * geo->m_numPrimGroups;
    geo->m_pPrimGroups[ 0 ].m_primitive     = TriangleList;
    geo->m_pPrimGroups[ 0 ].m_startIndex    = 0;

	// setup material
    geo->m_material = new Material;
    geo->m_material->m_numTextures = 0;
    geo->m_material->m_type = ShaderMaterial;
    geo->m_material->m_pShader = new Shader;
    geo->m_material->m_pShader->m_src[ SH_VertexShaderType ] = VsSrc;
    geo->m_material->m_pShader->m_src[ SH_FragmentShaderType ] = FsSrc;

	// setup shader attributes and variables
    if( nullptr != geo->m_material->m_pShader ) {
        ui32 numAttribs( ColorVert::getNumAttributes() );
        const String *attribs( ColorVert::getAttributes() );
        geo->m_material->m_pShader->m_attributes.add(attribs, numAttribs);
        geo->m_material->m_pShader->m_parameters.add( "MVP" );
    }

    return geo;
}

//-------------------------------------------------------------------------------------------------
RenderBackend::Geometry *GeometryBuilder::createBox( f32 w, f32 h, f32 d ) {
    Geometry *pGeometry = new Geometry;
    pGeometry->m_vertextype = ColorVertex;
    pGeometry->m_indextype  = UnsignedShort;

    static const ui32 NumVert = 8;

    ColorVert vertices[ NumVert ];
    f32 x(0.0f), y(0.0f), z( 0.0f );
    vertices[ 0 ].position = glm::vec3( x,     y,     z );
    vertices[ 1 ].position = glm::vec3( x + w, y,     z );
    vertices[ 2 ].position = glm::vec3( x + w, y + h, z );
    vertices[ 3 ].position = glm::vec3( x,     y + h, z );

    vertices[ 4 ].position = glm::vec3( x,     y,     z + d );
    vertices[ 5 ].position = glm::vec3( x + w, y,     z + d );
    vertices[ 6 ].position = glm::vec3( x + w, y + h, z + d );
    vertices[ 7 ].position = glm::vec3( x,     y + h, z + d );

    ui32 size( sizeof( ColorVert ) * NumVert );
    pGeometry->m_vb = BufferData::alloc( VertexBuffer, size, ReadOnly );
    ::memcpy( pGeometry->m_vb->m_pData, vertices, size );

    static const ui32 NumIndices = 36;
    GLushort  indices[ NumIndices ];
    indices[ 0 ] = 0;
    indices[ 1 ] = 1;
    indices[ 2 ] = 2;
    indices[ 3 ] = 0+3;
    indices[ 4 ] = 1+3;
    indices[ 5 ] = 2+3;

    indices[ 6 ] = 0+6;
    indices[ 7 ] = 1+6;
    indices[ 8 ] = 2+6;
    indices[ 9 ] = 0+9;
    indices[ 10 ] = 1+9;
    indices[ 11 ] = 2+9;

    indices[ 12 ] = 0+12;
    indices[ 13 ] = 1+12;
    indices[ 14 ] = 2+12;
    indices[ 15 ] = 0+15;
    indices[ 16 ] = 1+15;
    indices[ 17 ] = 2+15;

    indices[ 18 ] = 0+18;
    indices[ 19 ] = 1 + 18;
    indices[ 20 ] = 2 + 18;
    indices[ 21 ] = 0+21;
    indices[ 22 ] = 1 + 21;
    indices[ 23 ] = 2 + 21;

    indices[ 24 ] = 0+24;
    indices[ 25 ] = 1 + 24;
    indices[ 26 ] = 2 + 24;
    indices[ 27 ] = 0+27;
    indices[ 28 ] = 1 + 27;
    indices[ 29 ] = 2 + 27;

    indices[ 30 ] = 0+30;
    indices[ 31 ] = 1 + 30;
    indices[ 32 ] = 2 + 30;
    indices[ 33 ] = 0+33;
    indices[ 34 ] = 1 + 33;
    indices[ 35 ] = 2 + 33;
    size = sizeof( GLushort ) * NumIndices;
    pGeometry->m_ib = BufferData::alloc( IndexBuffer, size, ReadOnly );
    ::memcpy( pGeometry->m_ib->m_pData, indices, size );

    return pGeometry;
}

//-------------------------------------------------------------------------------------------------
RenderBackend::Geometry *GeometryBuilder::createTextBox( f32 x, f32 y, f32 size, const String &text ) {
	if ( text.empty() ) {
		return nullptr;
	}

	Geometry *geo = new Geometry;
	std::vector<RenderVert> vertices;
	std::vector<GLushort> indices;

    static const ui32 NumIndices = 6;
    GLushort  quad[ NumIndices ];
    quad[ 0 ] = 0;
    quad[ 1 ] = 1;
    quad[ 2 ] = 2;

    quad[ 0 ] = 2;
    quad[ 1 ] = 3;
    quad[ 2 ] = 1;

	for (ui32 i = 0; i <text.size(); i++) {
		RenderVert vert[ 4 ];
		vert[ 0 ].position = glm::vec3( x + i*size, y + size, 0 );
		vert[ 1 ].position = glm::vec3( x + i*size + size, y + size, 0 );
		vert[ 2 ].position = glm::vec3( x + i*size + size, y, 0 );
		vert[ 3 ].position = glm::vec3( x + i*size, y, 0 );

		char character = text[ i ];
		float uv_x = ( character % 16 ) / 16.0f;
		float uv_y = ( character / 16 ) / 16.0f;
		vert[ 0 ].tex0 = glm::vec2( uv_x, 1.0f - uv_y );
		vert[ 1 ].tex0 = glm::vec2( uv_x + 1.0f / 16.0f, 1.0f - uv_y );
		vert[ 2 ].tex0 = glm::vec2( uv_x + 1.0f / 16.0f, 1.0f - ( uv_y + 1.0f / 16.0f ) );
		vert[ 3 ].tex0 = glm::vec2( uv_x, 1.0f - ( uv_y + 1.0f / 16.0f ) );

		for (ui32 j = 0; j < 4; j++) {
			vertices.push_back( vert[ j ] );
		}

		// setup indices
		for (ui32 j = 0; j < 6; ++j) {
			indices.push_back( quad[ i ] + (i*4) );
		}
	}

	const ui32 vertSize( vertices.size() * sizeof( RenderVert ) );
	BufferData *bufferData = BufferData::alloc( VertexBuffer, vertSize, ReadWrite );
	::memcpy( bufferData->m_pData, &vertices[ 0 ], vertSize );
	geo->m_vb = bufferData;

	size = sizeof( GLushort ) * text.size() * 6;
	geo->m_ib = BufferData::alloc( IndexBuffer, size, ReadOnly );
	::memcpy( geo->m_ib->m_pData, &indices[ 0 ], size );

	geo->m_numPrimGroups = 1;
	geo->m_pPrimGroups = new PrimitiveGroup[ geo->m_numPrimGroups ];
	geo->m_pPrimGroups[ 0 ].m_indexType = UnsignedShort;
	geo->m_pPrimGroups[ 0 ].m_numPrimitives = text.size()*2;
	geo->m_pPrimGroups[ 0 ].m_primitive = TriangleList;
	geo->m_pPrimGroups[ 0 ].m_startIndex = 0;

	// setup material
	geo->m_material = new Material;
	geo->m_material->m_numTextures = 0;
	geo->m_material->m_type = ShaderMaterial;
	geo->m_material->m_pShader = new Shader;
	geo->m_material->m_pShader->m_src[ SH_VertexShaderType ] = VsSrc;
	geo->m_material->m_pShader->m_src[ SH_FragmentShaderType ] = FsSrc;

	// setup shader attributes and variables
	if ( nullptr != geo->m_material->m_pShader) {
		ui32 numAttribs( ColorVert::getNumAttributes() );
		const String *attribs( ColorVert::getAttributes() );
		geo->m_material->m_pShader->m_attributes.add( attribs, numAttribs );
		geo->m_material->m_pShader->m_parameters.add( "MVP" );
	}

	return geo;
}

//-------------------------------------------------------------------------------------------------

} // Namespace Scene
} // namespace OSRE
<|endoftext|>


<commit_before>#pragma XOD evaluate_on_pin disable
#pragma XOD evaluate_on_pin enable input_UPD

/*
 *  Datasheet can be found at
 *  https://cdn-shop.adafruit.com/datasheets/DS18B20.pdf
 *
 *  Most code comments are quotes from that datasheet
 */

enum {
    CMD_CONVERT = 0x44,
    CMD_READ_SCRATCHPAD = 0xBE,
    CMD_SKIP_ROM = 0xCC
};

void writeByte(uint8_t pin, uint8_t data) {
    pinMode(pin, OUTPUT);

    // There are two types of write time slots: “Write 1” time slots and “Write
    // 0” time slots. The bus master uses a Write 1 time slot to write a logic
    // 1 to the DS18B20 and a Write 0 time slot to write a logic 0 to the
    // DS18B20. All write time slots must be a minimum of 60µs in duration with
    // a minimum of a 1µs recovery time between individual write slots. Both
    // types of write time slots are initiated by the master pulling the 1-Wire
    // bus low

    for (uint8_t i = 8; i--; data >>= 1) {
        bool bit = data & 0x01;

        // To generate a Write 1 time slot, after pulling the 1-Wire bus low,
        // the bus master must release the 1-Wire bus within 15µs. When the bus
        // is released, the 5kΩ pullup resistor will pull the bus high. To
        // generate a Write 0 time slot, after pulling the 1-Wire bus low, the
        // bus master must continue to hold the bus low for the duration of the
        // time slot (at least 60µs)

        digitalWrite(pin, LOW);
        delayMicroseconds(bit ? 10 : 50);
        digitalWrite(pin, HIGH);
        delayMicroseconds(bit ? 50 : 10);

    }

    pinMode(pin, INPUT); // release the bus
}

uint8_t readByte(uint8_t pin) {
    uint8_t r = 0;
    for (uint8_t i = 0; i < 8; ++i) {
        // All read time slots must be a minimum of 60µs in duration with a
        // minimum of a 1µs recovery time between slots. A read time slot is
        // initiated by the master device pulling the 1-Wire bus low for a
        // minimum of 1µs and then releasing the bus.
        pinMode(pin, OUTPUT);
        digitalWrite(pin, LOW);
        delayMicroseconds(1);
        pinMode(pin, INPUT);

        // Output data from the DS18B20 is valid for 15µs after the falling
        // edge that initiated the read time slot.  Therefore, the master must
        // release the bus and then sample the bus state within 15µs from the
        // start of the slot.
        delayMicroseconds(5);

        // After the master initiates the read time slot, the DS18B20 will
        // begin transmitting a 1 or 0 on bus. The DS18B20 transmits a 1 by
        // leaving the bus high and transmits a 0 by pulling the bus low. When
        // transmitting a 0, the DS18B20 will release the bus by the end of the
        // time slot, and the bus will be pulled back to its high idle state by
        // the pullup resister.
        r |= digitalRead(pin) << i;

        delayMicroseconds(54); // complete the cycle
    }

    return r;
}

bool init(uint8_t pin) {
    // All communication with the DS18B20 begins with an initialization
    // sequence that consists of a reset pulse from the master followed by a
    // presence pulse from the DS18B20...

    // During the initialization sequence the bus master transmits (TX) the
    // reset pulse by pulling the 1-Wire bus low for a minimum of 480µs. The
    // bus master then releases the bus and goes into receive mode (RX).
    pinMode(pin, OUTPUT);
    digitalWrite(pin, LOW);
    delayMicroseconds(480);
    pinMode(pin, INPUT);

    // When the bus is released, the 5kΩ pullup resistor pulls the 1-Wire bus
    // high. When the DS18B20 detects this rising edge, it waits 15µs to 60µs
    // and then transmits a presence pulse by pulling the 1-Wire bus low for
    // 60µs to 240µs.
    delayMicroseconds(60);
    if (digitalRead(pin))
        return false; // no presence

    delayMicroseconds(420); // complete initialization procedure

    return true;
}

bool readTemperature(uint8_t pin, Number* out) {
    if (!init(pin))
        return false;

    writeByte(pin, CMD_SKIP_ROM);
    writeByte(pin, CMD_CONVERT);

    if (!init(pin))
        return false;

    writeByte(pin, CMD_SKIP_ROM);
    writeByte(pin, CMD_READ_SCRATCHPAD);

    int16_t hi = readByte(pin);
    int16_t lo = readByte(pin);
    *out = (Number)(hi | lo << 8) / 16.0;
    return true;
}

struct State {
};

{{ GENERATED_CODE }}

void evaluate(Context ctx) {
    static_assert(isValidDigitalPort(constant_input_PORT), "must be a valid digital port");

    if (!isInputDirty<input_UPD>(ctx))
        return;

    Number tc;
    bool success = readTemperature(port, &tc);
    if (!success) {
        raiseError(ctx); // Initialization sequence error
        return;
    }

    emitValue<output_Tc>(ctx, tc);
    emitValue<output_DONE>(ctx, 1);
}
<commit_msg>fix(stdlib): fix typo in implementation of xod/common-hardware/ds18b20-thermometer<commit_after>#pragma XOD evaluate_on_pin disable
#pragma XOD evaluate_on_pin enable input_UPD

/*
 *  Datasheet can be found at
 *  https://cdn-shop.adafruit.com/datasheets/DS18B20.pdf
 *
 *  Most code comments are quotes from that datasheet
 */

enum {
    CMD_CONVERT = 0x44,
    CMD_READ_SCRATCHPAD = 0xBE,
    CMD_SKIP_ROM = 0xCC
};

void writeByte(uint8_t pin, uint8_t data) {
    pinMode(pin, OUTPUT);

    // There are two types of write time slots: “Write 1” time slots and “Write
    // 0” time slots. The bus master uses a Write 1 time slot to write a logic
    // 1 to the DS18B20 and a Write 0 time slot to write a logic 0 to the
    // DS18B20. All write time slots must be a minimum of 60µs in duration with
    // a minimum of a 1µs recovery time between individual write slots. Both
    // types of write time slots are initiated by the master pulling the 1-Wire
    // bus low

    for (uint8_t i = 8; i--; data >>= 1) {
        bool bit = data & 0x01;

        // To generate a Write 1 time slot, after pulling the 1-Wire bus low,
        // the bus master must release the 1-Wire bus within 15µs. When the bus
        // is released, the 5kΩ pullup resistor will pull the bus high. To
        // generate a Write 0 time slot, after pulling the 1-Wire bus low, the
        // bus master must continue to hold the bus low for the duration of the
        // time slot (at least 60µs)

        digitalWrite(pin, LOW);
        delayMicroseconds(bit ? 10 : 50);
        digitalWrite(pin, HIGH);
        delayMicroseconds(bit ? 50 : 10);

    }

    pinMode(pin, INPUT); // release the bus
}

uint8_t readByte(uint8_t pin) {
    uint8_t r = 0;
    for (uint8_t i = 0; i < 8; ++i) {
        // All read time slots must be a minimum of 60µs in duration with a
        // minimum of a 1µs recovery time between slots. A read time slot is
        // initiated by the master device pulling the 1-Wire bus low for a
        // minimum of 1µs and then releasing the bus.
        pinMode(pin, OUTPUT);
        digitalWrite(pin, LOW);
        delayMicroseconds(1);
        pinMode(pin, INPUT);

        // Output data from the DS18B20 is valid for 15µs after the falling
        // edge that initiated the read time slot.  Therefore, the master must
        // release the bus and then sample the bus state within 15µs from the
        // start of the slot.
        delayMicroseconds(5);

        // After the master initiates the read time slot, the DS18B20 will
        // begin transmitting a 1 or 0 on bus. The DS18B20 transmits a 1 by
        // leaving the bus high and transmits a 0 by pulling the bus low. When
        // transmitting a 0, the DS18B20 will release the bus by the end of the
        // time slot, and the bus will be pulled back to its high idle state by
        // the pullup resister.
        r |= digitalRead(pin) << i;

        delayMicroseconds(54); // complete the cycle
    }

    return r;
}

bool init(uint8_t pin) {
    // All communication with the DS18B20 begins with an initialization
    // sequence that consists of a reset pulse from the master followed by a
    // presence pulse from the DS18B20...

    // During the initialization sequence the bus master transmits (TX) the
    // reset pulse by pulling the 1-Wire bus low for a minimum of 480µs. The
    // bus master then releases the bus and goes into receive mode (RX).
    pinMode(pin, OUTPUT);
    digitalWrite(pin, LOW);
    delayMicroseconds(480);
    pinMode(pin, INPUT);

    // When the bus is released, the 5kΩ pullup resistor pulls the 1-Wire bus
    // high. When the DS18B20 detects this rising edge, it waits 15µs to 60µs
    // and then transmits a presence pulse by pulling the 1-Wire bus low for
    // 60µs to 240µs.
    delayMicroseconds(60);
    if (digitalRead(pin))
        return false; // no presence

    delayMicroseconds(420); // complete initialization procedure

    return true;
}

bool readTemperature(uint8_t pin, Number* out) {
    if (!init(pin))
        return false;

    writeByte(pin, CMD_SKIP_ROM);
    writeByte(pin, CMD_CONVERT);

    if (!init(pin))
        return false;

    writeByte(pin, CMD_SKIP_ROM);
    writeByte(pin, CMD_READ_SCRATCHPAD);

    int16_t hi = readByte(pin);
    int16_t lo = readByte(pin);
    *out = (Number)(hi | lo << 8) / 16.0;
    return true;
}

struct State {
};

{{ GENERATED_CODE }}

void evaluate(Context ctx) {
    static_assert(isValidDigitalPort(constant_input_PORT), "must be a valid digital port");

    if (!isInputDirty<input_UPD>(ctx))
        return;

    Number tc;
    bool success = readTemperature(constant_input_PORT, &tc);
    if (!success) {
        raiseError(ctx); // Initialization sequence error
        return;
    }

    emitValue<output_Tc>(ctx, tc);
    emitValue<output_DONE>(ctx, 1);
}
<|endoftext|>