<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2021.  All rights reserved
 */
#ifndef _Stroika_Foundation_Containers_Private_IteratorImplHelper_inl_
#define _Stroika_Foundation_Containers_Private_IteratorImplHelper_inl_ 1

#include <random>

#include "../../Debug/Assertions.h"
#include "../../Debug/Cast.h"

namespace Stroika::Foundation::Containers::Private {

    /*
     ********************************************************************************
     *************************** ContainerDebugChangeCounts_ ************************
     ********************************************************************************
     */
#if qDebug
    inline ContainerDebugChangeCounts_::ChangeCountType ContainerDebugChangeCounts_::mkInitial_ ()
    {
        // use random number so when we assign new object we are more likely to detect bad iterators (dangling)
        random_device                             rd;
        mt19937                                   gen{rd ()};
        uniform_int_distribution<ChangeCountType> distrib{1, 1000};
        return distrib (gen);
    }
#endif
    inline ContainerDebugChangeCounts_::ContainerDebugChangeCounts_ ()
#if qDebug
        // clang-format off
        : fChangeCount{mkInitial_ ()}
    // clang-format on
#endif
    {
    }
    inline ContainerDebugChangeCounts_::ContainerDebugChangeCounts_ ([[maybe_unused]] const ContainerDebugChangeCounts_& src)
#if qDebug
        // clang-format off
        : fDeleted{src.fDeleted}
        , fChangeCount{src.fChangeCount.load ()}
    // clang-format on
#endif
    {
    }
    inline ContainerDebugChangeCounts_::~ContainerDebugChangeCounts_ ()
    {
#if qDebug
        fDeleted = true;
#endif
    }
    inline void ContainerDebugChangeCounts_::PerformedChange ()
    {
#if qDebug
        ++fChangeCount;
#endif
    }

    /*
     ********************************************************************************
     *IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR,DATASTRUCTURE_CONTAINER_VALUE> *
     ********************************************************************************
     */
#if qCompilerAndStdLib_template_default_arguments_then_paramPack_Buggy
    template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
    template <typename... ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS>
    inline IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR, DATASTRUCTURE_CONTAINER_VALUE>::IteratorImplHelper_ (const DATASTRUCTURE_CONTAINER* data, [[maybe_unused]] const ContainerDebugChangeCounts_* changeCounter, ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS&&... args)
        // clang-format off
        : fIterator{data, forward<ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS> (args)...}
#if qDebug
        , fChangeCounter{changeCounter}
        , fLastCapturedChangeCount { (changeCounter == nullptr) ? 0 : changeCounter->fChangeCount.load () }
#endif
    // clang-format on
    {
        RequireNotNull (data);
    }
    template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
    inline IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR, DATASTRUCTURE_CONTAINER_VALUE>::IteratorImplHelper_ (const DATASTRUCTURE_CONTAINER* data)
        : IteratorImplHelper_{data, nullptr}
    {
    }
#else
    template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
    template <typename... ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS>
    inline IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR, DATASTRUCTURE_CONTAINER_VALUE>::IteratorImplHelper_ (const DATASTRUCTURE_CONTAINER* data, [[maybe_unused]] const ContainerDebugChangeCounts_* changeCounter, ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS&&... args)
        // clang-format off
        : fIterator{data, forward<ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS> (args)...}
#if qDebug
        , fChangeCounter{changeCounter}
        , fLastCapturedChangeCount { (changeCounter == nullptr) ? 0 : changeCounter->fChangeCount.load () }
#endif
    // clang-format on
    {
        RequireNotNull (data);
    }
#endif
    template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
    typename Iterator<T>::RepSmartPtr IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR, DATASTRUCTURE_CONTAINER_VALUE>::Clone () const
    {
        ValidateChangeCount ();
        return Iterator<T>::template MakeSmartPtr<IteratorImplHelper_> (*this);
    }
    template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
    void IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR, DATASTRUCTURE_CONTAINER_VALUE>::More (optional<T>* result, bool advance)
    {
        RequireNotNull (result); // API says result ptr required
        ValidateChangeCount ();
        // Typically calls have advance = true
        if (advance) [[LIKELY_ATTR]] {
            Require (not fIterator.Done ()); // new requirement since Stroika 2.1b14
            ++fIterator;
        }
        if (fIterator.Done ()) [[UNLIKELY_ATTR]] {
            *result = nullopt;
        }
        else {
            *result = fIterator.Current ();
        }
    }
    template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
    bool IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR, DATASTRUCTURE_CONTAINER_VALUE>::Equals (const typename Iterator<T>::IRep* rhs) const
    {
        RequireNotNull (rhs);
        using ActualIterImplType_ = IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR, DATASTRUCTURE_CONTAINER_VALUE>;
        const ActualIterImplType_* rrhs = Debug::UncheckedDynamicCast<const ActualIterImplType_*> (rhs);
        return fIterator.Equals (rrhs->fIterator);
    }
#if qDebug
    template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
    void IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR, DATASTRUCTURE_CONTAINER_VALUE>::Invariant () const
    {
        ValidateChangeCount ();
    }
#endif
    template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
    inline void IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR, DATASTRUCTURE_CONTAINER_VALUE>::UpdateChangeCount ()
    {
#if qDebug
        if (fChangeCounter != nullptr) {
            fLastCapturedChangeCount = fChangeCounter->fChangeCount;
        }
#endif
    }
    template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
    inline void IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR, DATASTRUCTURE_CONTAINER_VALUE>::ValidateChangeCount () const
    {
#if qDebug
        if (fChangeCounter != nullptr) {
            Require (not fChangeCounter->fDeleted);                             // if this is triggered, it means the container changed so drastically that its rep was deleted
            Require (fChangeCounter->fChangeCount == fLastCapturedChangeCount); // if this fails, it almost certainly means you are using a stale iterator
        }
#endif
    }

}

#endif /* _Stroika_Foundation_Containers_Private_IteratorImplHelper_inl_ */
<commit_msg>cosmetic<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2021.  All rights reserved
 */
#ifndef _Stroika_Foundation_Containers_Private_IteratorImplHelper_inl_
#define _Stroika_Foundation_Containers_Private_IteratorImplHelper_inl_ 1

#include <random>

#include "../../Debug/Assertions.h"
#include "../../Debug/Cast.h"

namespace Stroika::Foundation::Containers::Private {

    /*
     ********************************************************************************
     *************************** ContainerDebugChangeCounts_ ************************
     ********************************************************************************
     */
#if qDebug
    inline ContainerDebugChangeCounts_::ChangeCountType ContainerDebugChangeCounts_::mkInitial_ ()
    {
        // use random number so when we assign new object we are more likely to detect bad iterators (dangling)
        random_device                             rd;
        mt19937                                   gen{rd ()};
        uniform_int_distribution<ChangeCountType> distrib{1, 1000};
        return distrib (gen);
    }
#endif
    inline ContainerDebugChangeCounts_::ContainerDebugChangeCounts_ ()
#if qDebug
        // clang-format off
        : fChangeCount{mkInitial_ ()}
    // clang-format on
#endif
    {
    }
    inline ContainerDebugChangeCounts_::ContainerDebugChangeCounts_ ([[maybe_unused]] const ContainerDebugChangeCounts_& src)
#if qDebug
        // clang-format off
        : fDeleted{src.fDeleted}
        , fChangeCount{src.fChangeCount.load ()}
    // clang-format on
#endif
    {
    }
    inline ContainerDebugChangeCounts_::~ContainerDebugChangeCounts_ ()
    {
#if qDebug
        fDeleted = true;
#endif
    }
    inline void ContainerDebugChangeCounts_::PerformedChange ()
    {
#if qDebug
        ++fChangeCount;
#endif
    }

    /*
     ********************************************************************************
     *IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR,DATASTRUCTURE_CONTAINER_VALUE> *
     ********************************************************************************
     */
#if qCompilerAndStdLib_template_default_arguments_then_paramPack_Buggy
    template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
    template <typename... ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS>
    inline IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR, DATASTRUCTURE_CONTAINER_VALUE>::IteratorImplHelper_ (const DATASTRUCTURE_CONTAINER* data, [[maybe_unused]] const ContainerDebugChangeCounts_* changeCounter, ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS&&... args)
        // clang-format off
        : fIterator{data, forward<ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS> (args)...}
#if qDebug
        , fChangeCounter{changeCounter}
        , fLastCapturedChangeCount { (changeCounter == nullptr) ? 0 : changeCounter->fChangeCount.load () }
#endif
    // clang-format on
    {
        RequireNotNull (data);
    }
    template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
    inline IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR, DATASTRUCTURE_CONTAINER_VALUE>::IteratorImplHelper_ (const DATASTRUCTURE_CONTAINER* data)
        : IteratorImplHelper_{data, nullptr}
    {
    }
#else
    template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
    template <typename... ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS>
    inline IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR, DATASTRUCTURE_CONTAINER_VALUE>::IteratorImplHelper_ (const DATASTRUCTURE_CONTAINER* data, [[maybe_unused]] const ContainerDebugChangeCounts_* changeCounter, ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS&&... args)
        // clang-format off
        : fIterator{data, forward<ADDITIONAL_BACKEND_ITERATOR_CTOR_ARGUMENTS> (args)...}
#if qDebug
        , fChangeCounter{changeCounter}
        , fLastCapturedChangeCount { (changeCounter == nullptr) ? 0 : changeCounter->fChangeCount.load () }
#endif
    // clang-format on
    {
        RequireNotNull (data);
    }
#endif
    template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
    typename Iterator<T>::RepSmartPtr IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR, DATASTRUCTURE_CONTAINER_VALUE>::Clone () const
    {
        ValidateChangeCount ();
        return Iterator<T>::template MakeSmartPtr<IteratorImplHelper_> (*this);
    }
    template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
    void IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR, DATASTRUCTURE_CONTAINER_VALUE>::More (optional<T>* result, bool advance)
    {
        RequireNotNull (result); // API says result ptr required
        ValidateChangeCount ();
        // Typically calls have advance = true
        if (advance) [[LIKELY_ATTR]] {
            Require (not fIterator.Done ()); // new requirement since Stroika 2.1b14
            ++fIterator;
        }
        if (fIterator.Done ()) [[UNLIKELY_ATTR]] {
            *result = nullopt;
        }
        else {
            *result = fIterator.Current ();
        }
    }
    template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
    bool IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR, DATASTRUCTURE_CONTAINER_VALUE>::Equals (const typename Iterator<T>::IRep* rhs) const
    {
        RequireNotNull (rhs);
        using ActualIterImplType_       = IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR, DATASTRUCTURE_CONTAINER_VALUE>;
        const ActualIterImplType_* rrhs = Debug::UncheckedDynamicCast<const ActualIterImplType_*> (rhs);
        return fIterator.Equals (rrhs->fIterator);
    }
#if qDebug
    template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
    void IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR, DATASTRUCTURE_CONTAINER_VALUE>::Invariant () const
    {
        ValidateChangeCount ();
    }
#endif
    template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
    inline void IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR, DATASTRUCTURE_CONTAINER_VALUE>::UpdateChangeCount ()
    {
#if qDebug
        if (fChangeCounter != nullptr) {
            fLastCapturedChangeCount = fChangeCounter->fChangeCount;
        }
#endif
    }
    template <typename T, typename DATASTRUCTURE_CONTAINER, typename DATASTRUCTURE_CONTAINER_ITERATOR, typename DATASTRUCTURE_CONTAINER_VALUE>
    inline void IteratorImplHelper_<T, DATASTRUCTURE_CONTAINER, DATASTRUCTURE_CONTAINER_ITERATOR, DATASTRUCTURE_CONTAINER_VALUE>::ValidateChangeCount () const
    {
#if qDebug
        if (fChangeCounter != nullptr) {
            Require (not fChangeCounter->fDeleted);                             // if this is triggered, it means the container changed so drastically that its rep was deleted
            Require (fChangeCounter->fChangeCount == fLastCapturedChangeCount); // if this fails, it almost certainly means you are using a stale iterator
        }
#endif
    }

}

#endif /* _Stroika_Foundation_Containers_Private_IteratorImplHelper_inl_ */
<|endoftext|>


<commit_before>/* hmac.hpp
 *
 * Copyright (C) 2003 Sawtooth Consulting Ltd.
 *
 * This file is part of yaSSL.
 *
 * yaSSL is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * yaSSL is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 */

/* hamc.hpp implements HMAC, see RFC 2104
*/

#ifndef TAO_CRYPT_HMAC_HPP
#define TAO_CRYPT_HMAC_HPP

#include "hash.hpp"

namespace TaoCrypt {

// HMAC class template
template <class T>
class HMAC {
public:
    enum { IPAD = 0x36, OPAD = 0x5C };

    HMAC() : ipad_(reinterpret_cast<byte*>(&ip_)),
             opad_(reinterpret_cast<byte*>(&op_)),
             innerHash_(reinterpret_cast<byte*>(&innerH_))
    {
        Init();
    }
    void Update(const byte*, word32);
    void Final(byte*);
    void Init();

    void SetKey(const byte*, word32);
private:
    byte* ipad_;
    byte* opad_;
    byte* innerHash_;
    bool  innerHashKeyed_;
    T     mac_;

    // MSVC 6 HACK, gives compiler error if calculated in array
    enum { BSIZE = T::BLOCK_SIZE  / sizeof(word32),
           DSIZE = T::DIGEST_SIZE / sizeof(word32) };

    word32 ip_[BSIZE];          // align ipad_ on word32
    word32 op_[BSIZE];          // align opad_ on word32
    word32 innerH_[DSIZE];      // align innerHash_ on word32

    void KeyInnerHash();

    HMAC(const HMAC&);
    HMAC& operator= (const HMAC&);
};

// Setup
template <class T>
void HMAC<T>::Init()
{
    mac_.Init();
    innerHashKeyed_ = false;
}

// Key generation
template <class T>
void HMAC<T>::SetKey(const byte* key, word32 length)
{
    Init();

    if (length <= T::BLOCK_SIZE)
        memcpy(ipad_, key, length);
    else {
        mac_.Update(key, length);
        mac_.Final(ipad_);
        length = T::DIGEST_SIZE;
    }
    memset(ipad_ + length, 0, T::BLOCK_SIZE - length);

    for (word32 i = 0; i < T::BLOCK_SIZE; i++) {
        opad_[i] = ipad_[i] ^ OPAD;
        ipad_[i] ^= IPAD;
    }
}

// Inner Key Hash
template <class T>
void HMAC<T>::KeyInnerHash()
{
    mac_.Update(ipad_, T::BLOCK_SIZE);
    innerHashKeyed_ = true;
}

// Update
template <class T>
void HMAC<T>::Update(const byte* msg, word32 length)
{
    if (!innerHashKeyed_)
        KeyInnerHash();
    mac_.Update(msg, length);
}

// Final
template <class T>
void HMAC<T>::Final(byte* hash)
{
    if (!innerHashKeyed_)
        KeyInnerHash();
    mac_.Final(innerHash_);

    mac_.Update(opad_, T::BLOCK_SIZE);
    mac_.Update(innerHash_, T::DIGEST_SIZE);
    mac_.Final(hash);

    innerHashKeyed_ = false;
}

} // namespace

#endif // TAO_CRYPT_HMAC_HPP
<commit_msg>Bug #13476  	yassl: openserv compile failure<commit_after>/* hmac.hpp
 *
 * Copyright (C) 2003 Sawtooth Consulting Ltd.
 *
 * This file is part of yaSSL.
 *
 * yaSSL is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * yaSSL is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 */

/* hamc.hpp implements HMAC, see RFC 2104
*/

#ifndef TAO_CRYPT_HMAC_HPP
#define TAO_CRYPT_HMAC_HPP

#include "hash.hpp"

namespace TaoCrypt {

// HMAC class template
template <class T>
class HMAC {
public:
    enum { IPAD = 0x36, OPAD = 0x5C };

    HMAC() : ipad_(reinterpret_cast<byte*>(&ip_)),
             opad_(reinterpret_cast<byte*>(&op_)),
             innerHash_(reinterpret_cast<byte*>(&innerH_))
    {
        Init();
    }
    void Update(const byte*, word32);
    void Final(byte*);
    void Init();

    void SetKey(const byte*, word32);
private:
    byte* ipad_;
    byte* opad_;
    byte* innerHash_;
    bool  innerHashKeyed_;
    T     mac_;

    // MSVC 6 HACK, gives compiler error if calculated in array
    enum { HMAC_BSIZE = T::BLOCK_SIZE  / sizeof(word32),
           HMAC_DSIZE = T::DIGEST_SIZE / sizeof(word32) };

    word32 ip_[HMAC_BSIZE];          // align ipad_ on word32
    word32 op_[HMAC_BSIZE];          // align opad_ on word32
    word32 innerH_[HMAC_DSIZE];      // align innerHash_ on word32

    void KeyInnerHash();

    HMAC(const HMAC&);
    HMAC& operator= (const HMAC&);
};

// Setup
template <class T>
void HMAC<T>::Init()
{
    mac_.Init();
    innerHashKeyed_ = false;
}

// Key generation
template <class T>
void HMAC<T>::SetKey(const byte* key, word32 length)
{
    Init();

    if (length <= T::BLOCK_SIZE)
        memcpy(ipad_, key, length);
    else {
        mac_.Update(key, length);
        mac_.Final(ipad_);
        length = T::DIGEST_SIZE;
    }
    memset(ipad_ + length, 0, T::BLOCK_SIZE - length);

    for (word32 i = 0; i < T::BLOCK_SIZE; i++) {
        opad_[i] = ipad_[i] ^ OPAD;
        ipad_[i] ^= IPAD;
    }
}

// Inner Key Hash
template <class T>
void HMAC<T>::KeyInnerHash()
{
    mac_.Update(ipad_, T::BLOCK_SIZE);
    innerHashKeyed_ = true;
}

// Update
template <class T>
void HMAC<T>::Update(const byte* msg, word32 length)
{
    if (!innerHashKeyed_)
        KeyInnerHash();
    mac_.Update(msg, length);
}

// Final
template <class T>
void HMAC<T>::Final(byte* hash)
{
    if (!innerHashKeyed_)
        KeyInnerHash();
    mac_.Final(innerHash_);

    mac_.Update(opad_, T::BLOCK_SIZE);
    mac_.Update(innerHash_, T::DIGEST_SIZE);
    mac_.Final(hash);

    innerHashKeyed_ = false;
}

} // namespace

#endif // TAO_CRYPT_HMAC_HPP
<|endoftext|>


<commit_before>/*
 * WeatherManagerImplementation.cpp
 *
 *  Created on: 11/03/2011
 *      Author: Anakis
 */

#include "engine/engine.h"

#include "server/zone/managers/weather/WeatherManager.h"
#include "server/zone/Zone.h"
#include "server/chat/ChatManager.h"
#include "events/WeatherChangeEvent.h"
#include "server/zone/managers/player/PlayerMap.h"
#include "server/zone/objects/creature/CreatureObject.h"
#include "server/zone/objects/creature/CreatureAttribute.h"
#include "server/zone/objects/creature/CreaturePosture.h"
#include "server/zone/objects/player/PlayerObject.h"
#include "weathermaps/WeatherMap.h"
#include "server/zone/packets/scene/ServerWeatherMessage.h"

void WeatherManagerImplementation::initialize() {
	//Customize the Manager's name.
	String managerName = "WeatherManager ";
	setLoggingName(managerName + zone->getZoneName());
	setGlobalLogging(true);
	setLogging(true);

	weatherEnabled = true;
	weatherChangeEvent = NULL;

	//Load weather configuration from the luas.
	//info("Loading configuration from Lua.");
	if(!loadLuaConfig()) {
		info("ERROR in Lua config. Loading default values.");
		loadDefaultValues();
	}

	windX.removeAll();
	windY.removeAll();
	windMagnitude.removeAll();

	for(int i = 0; i <= 200; ++i) {
		windX.add(((float)System::random(200) / 100.f) - 1);
		windY.add(((float)System::random(200) / 100.f) - 1);
		windMagnitude.add(((float)System::random(200) / 100.f) - 1);
	}

	createNewWeatherPattern();

	 info("Enabled");
}

bool WeatherManagerImplementation::loadLuaConfig() {
	Locker weatherManagerLocker(_this.get());

	Lua* lua = new Lua();
	lua->init();

	if (!lua->runFile("scripts/managers/weather_manager.lua"))
		return false;

	LuaObject luaObject = lua->getGlobalObject(zone->getZoneName());

	if (!luaObject.isValidTable())
		return false;

	//Starting weather
	baseWeather = luaObject.getByteField("defaultWeather");

	//New weather selection times.
	averageWeatherDuration = luaObject.getIntField("averageWeatherDuration");

	//Weather Stability.
	weatherStability = luaObject.getIntField("weatherStability");
	if(weatherStability > 100)
		weatherStability = 100;

	hasDamagingSandstorms = luaObject.getByteField("hasDamagingSandstorms");

	if(hasDamagingSandstorms) {

		sandstormDamage = luaObject.getIntField("sandstormDamage");
		if (sandstormDamage > 500)
			return false;
	}

	luaObject.pop();
	delete lua;
	lua = NULL;
	return true;
}

void WeatherManagerImplementation::loadDefaultValues() {
	Locker weatherManagerLocker(_this.get());

	weatherEnabled = true;

	baseWeather = 0;
	//Transition times.
	averageWeatherDuration = 3600; //seconds. 1 hour
	weatherStability = 80; // Pretty Stable

	hasDamagingSandstorms = false;
}

void WeatherManagerImplementation::createNewWeatherPattern() {

	Locker weatherManagerLocker(_this.get());

	int roll = System::random(100);

	for(int i = 0; i < 5; ++i) {
		float value = ((float)weatherStability + (i * ((100.f - (float)weatherStability) / (1.f + i))));
		value += (100.f - ((float)weatherStability + (4 * ((100.f - (float)weatherStability) / (5.f)))));

		if(roll <  value) {
			baseWeather = i;
			break;
		}
	}

	int duration = System::random(averageWeatherDuration) + (averageWeatherDuration / 2);
	currentMap = new WeatherMap(weatherStability, zone->getMinX(), zone->getMaxX(), zone->getMinY(), zone->getMaxY(), duration);

	if(weatherChangeEvent != NULL) {
		if(weatherChangeEvent->isScheduled())
			weatherChangeEvent->cancel();
	} else {
		weatherChangeEvent = new WeatherChangeEvent(_this.get());
	}

	weatherChangeEvent->reschedule((duration * 1.5) * 1000);
}

void WeatherManagerImplementation::sendWeatherTo(CreatureObject* player) {

	byte currentWeather = 0;

	if(currentMap != NULL)
		currentWeather = currentMap->getWeatherAt(player->getPositionX(), player->getPositionY()) + baseWeather;
	else
		currentWeather = baseWeather;

	if(currentWeather > 4)
		currentWeather = 0;

	if(hasDamagingSandstorms && currentWeather == WeatherManager::EXTREMESTORM) {
		applySandstormDamage(player);
	}

	if(player->getCurrentWeather() == currentWeather)
		return;

	if(hasDamagingSandstorms && player->getCurrentWeather() == WeatherManager::EXTREMESTORM) {
		player->sendSystemMessage("The storm has subsided.");
	}

	player->setCurrentWeather(currentWeather);

	if(hasDamagingSandstorms && currentWeather == WeatherManager::EXTREMESTORM) {
		player->sendSystemMessage("The weather around you quickly becomes damaging, seek shelter immediately.");
	}

	ServerWeatherMessage* weatherMessage = new ServerWeatherMessage(
			currentWeather,
			windX.get(player->getCurrentWind()),
			windMagnitude.get(player->getCurrentWind()),
			windY.get(player->getCurrentWind()));

	player->sendMessage(weatherMessage);

}

void WeatherManagerImplementation::applySandstormDamage(CreatureObject* player) {
	if (player == NULL)
		return;

	PlayerObject* ghost = player->getPlayerObject();

	//Check player's online status.
	if (ghost->isTeleporting() || !player->isOnline())
		return;

	//Check if player is in a shelter.
	if ((!player->isRidingMount() && player->getParentID() != 0) || player->getCurrentCamp() != NULL) //TODO: Add camp protection.
		return;

	//Blind player
	player->setBlindedState(60);

	//Calculate the sandstorm protection the player has.
	int totalCoverings = calculateSandstormProtection(player);

	//Apply wounds.
	int applicableDamage = sandstormDamage - totalCoverings;
	if (applicableDamage > 0) {
		player->inflictDamage(NULL, CreatureAttribute::HEALTH, applicableDamage, true, true);
		player->inflictDamage(NULL, CreatureAttribute::ACTION, applicableDamage, true, true);
		player->inflictDamage(NULL, CreatureAttribute::MIND, applicableDamage, true, true);
	}

	//Apply knockdown.
	int applicableKDChance = sandstormDamage - totalCoverings;
	if (applicableKDChance > 0 && !player->isProne() && !player->isKnockedDown() && System::random(200) > 198 ) {
		if (player->isRidingMount()) {
			player->sendSystemMessage("A gust of wind blows you off your vehicle!");
			player->dismount();
		} else
			player->sendSystemMessage("A gust of wind blows you off balance!");

		player->setPosture(CreaturePosture::KNOCKEDDOWN, true);
	}
}

int WeatherManagerImplementation::calculateSandstormProtection(CreatureObject* player) {
	if (player == NULL)
		return 0;

	int protection = 0;
	uint32 crc;

	//Check for protective head gear.
	ManagedReference<SceneObject*> hat = player->getSlottedObject("hat");
	if (hat != NULL) {
		crc = hat->getServerObjectCRC();
		if (crc == 0x612f992f || crc == 0xba3831b8 || crc == 0xdc8d2e72 || crc == 0x754b6f93) //Tusken Raider helmets, Swoop helmet, Large Headwrap.
			protection += 1;
		else if (hat->isArmorObject())
			protection += 1;
	}

	//Check for protective chest covering.
	bool tuskenRobe = false;
	ManagedReference<SceneObject*> robe = player->getSlottedObject("chest2");
	if (robe != NULL) {
		crc = robe->getServerObjectCRC();
		if (crc == 0xc20d81d9 || crc == 0x191a294e) { //Tusken Robes.
			tuskenRobe = true;
			protection += 2; //They cover both chest and legs.
		} else if (crc == 0xd95ec143 || crc == 0x3995e72f) //Scout Jacket, Heavy Reinforced Jacket.
			protection += 1;
		else if (crc == 0x9053a6ce || crc == 0x663c19d1) //Vested jacket, Desert Command Jacket.
			protection += 1;
		else if (robe->isArmorObject())
			protection += 1;
	}

	//Check for protective pants.
	if (!tuskenRobe) {
		ManagedReference<SceneObject*> pants = player->getSlottedObject("pants1");
		if (pants != NULL) {
			crc = pants->getServerObjectCRC();
			if (crc == 0x9488cb5f || crc == 0x10369d36 || crc == 0x9c6cabd4) //Paramilitary Camos, Basic Camos, Reinforced Pants.
				protection += 1;
			else if (crc == 0xb9f0dcd7 || crc == 0xc6ada1aa) //Desert Crawlers, Padded Workpants
				protection += 1;
		}

		ManagedReference<SceneObject*> pants2 = player->getSlottedObject("pants2");
		if (pants2 != NULL) {
			crc = pants2->getServerObjectCRC();
			if (pants2->isArmorObject())
				protection += 1;
		}
	}

	//Check for protective gloves.
	ManagedReference<SceneObject*> gloves = player->getSlottedObject("gloves");
	if (gloves != NULL) {
		crc = gloves->getServerObjectCRC();
		if (crc == 0x29fc844 || crc == 0x41ba6c29 || crc == 0x614eefaa) //Tusken gloves, Link-Steel Reinforced Gloves, Heavy Gloves.
			protection += 1;
		else if (gloves->isArmorObject())
			protection += 1;
	}

	//Check for protective boots.
	ManagedReference<SceneObject*> boots = player->getSlottedObject("shoes");
	if (boots != NULL) {
		crc = boots->getServerObjectCRC();
		if (crc == 0xbcc9eaac || crc == 0x873644ed) //Tusken boots, Sturdy boots
			protection += 1;
		else if (crc == 0x9192dd9e || crc == 0x35d80874) //Paneled Boots, Wrapped Boots.
			protection += 1;
		else if (boots->isArmorObject())
			protection += 1;
	}

	return protection;
}

void WeatherManagerImplementation::enableWeather(CreatureObject* player) {

	initialize();

	if (player != NULL)
		player->sendSystemMessage("The weather on this planet will now change automatically.");
}

void WeatherManagerImplementation::disableWeather(CreatureObject* player) {

	if (player == NULL || !weatherEnabled)
		return;

	Locker weatherManagerLocker(_this.get());
	weatherEnabled = false;

	if (weatherChangeEvent != NULL) {
		if (weatherChangeEvent->isScheduled())
			weatherChangeEvent->cancel();

		weatherChangeEvent = NULL;
	}

	currentMap = NULL;

	player->sendSystemMessage("The weather on this planet will no longer change automatically.");
}

void WeatherManagerImplementation::changeWeather(CreatureObject* player, int newWeather) {

	disableWeather(player);

	Locker weatherManagerLocker(_this.get());

	if(newWeather == 5)
		baseWeather = System::random(5);
	else {
		baseWeather = newWeather;
	}
}

void WeatherManagerImplementation::printInfo(CreatureObject* player) {

	if(currentMap == NULL) {
		player->sendSystemMessage("The weather currently is " + String::valueOf(baseWeather));
		return;
	}

	StringBuffer message;
	message << "Base: " << baseWeather << " " << currentMap->printInfo(player->getPositionX(), player->getPositionY());
	player->sendSystemMessage(message.toString());
}
<commit_msg>[changed] Weather pattern duration now scales down based on severity<commit_after>/*
 * WeatherManagerImplementation.cpp
 *
 *  Created on: 11/03/2011
 *      Author: Anakis
 */

#include "engine/engine.h"

#include "server/zone/managers/weather/WeatherManager.h"
#include "server/zone/Zone.h"
#include "server/chat/ChatManager.h"
#include "events/WeatherChangeEvent.h"
#include "server/zone/managers/player/PlayerMap.h"
#include "server/zone/objects/creature/CreatureObject.h"
#include "server/zone/objects/creature/CreatureAttribute.h"
#include "server/zone/objects/creature/CreaturePosture.h"
#include "server/zone/objects/player/PlayerObject.h"
#include "weathermaps/WeatherMap.h"
#include "server/zone/packets/scene/ServerWeatherMessage.h"

void WeatherManagerImplementation::initialize() {
	//Customize the Manager's name.
	String managerName = "WeatherManager ";
	setLoggingName(managerName + zone->getZoneName());
	setGlobalLogging(true);
	setLogging(true);

	weatherEnabled = true;
	weatherChangeEvent = NULL;

	//Load weather configuration from the luas.
	//info("Loading configuration from Lua.");
	if(!loadLuaConfig()) {
		info("ERROR in Lua config. Loading default values.");
		loadDefaultValues();
	}

	windX.removeAll();
	windY.removeAll();
	windMagnitude.removeAll();

	for(int i = 0; i <= 200; ++i) {
		windX.add(((float)System::random(200) / 100.f) - 1);
		windY.add(((float)System::random(200) / 100.f) - 1);
		windMagnitude.add(((float)System::random(200) / 100.f) - 1);
	}

	createNewWeatherPattern();

	 info("Enabled");
}

bool WeatherManagerImplementation::loadLuaConfig() {
	Locker weatherManagerLocker(_this.get());

	Lua* lua = new Lua();
	lua->init();

	if (!lua->runFile("scripts/managers/weather_manager.lua"))
		return false;

	LuaObject luaObject = lua->getGlobalObject(zone->getZoneName());

	if (!luaObject.isValidTable())
		return false;

	//Starting weather
	baseWeather = luaObject.getByteField("defaultWeather");

	//New weather selection times.
	averageWeatherDuration = luaObject.getIntField("averageWeatherDuration");

	//Weather Stability.
	weatherStability = luaObject.getIntField("weatherStability");
	if(weatherStability > 100)
		weatherStability = 100;

	hasDamagingSandstorms = luaObject.getByteField("hasDamagingSandstorms");

	if(hasDamagingSandstorms) {

		sandstormDamage = luaObject.getIntField("sandstormDamage");
		if (sandstormDamage > 500)
			return false;
	}

	luaObject.pop();
	delete lua;
	lua = NULL;
	return true;
}

void WeatherManagerImplementation::loadDefaultValues() {
	Locker weatherManagerLocker(_this.get());

	weatherEnabled = true;

	baseWeather = 0;
	//Transition times.
	averageWeatherDuration = 3600; //seconds. 1 hour
	weatherStability = 80; // Pretty Stable

	hasDamagingSandstorms = false;
}

void WeatherManagerImplementation::createNewWeatherPattern() {

	Locker weatherManagerLocker(_this.get());

	int roll = System::random(100);

	for(int i = 0; i < 5; ++i) {
		float value = ((float)weatherStability + (i * ((100.f - (float)weatherStability) / (1.f + i))));
		value += (100.f - ((float)weatherStability + (4 * ((100.f - (float)weatherStability) / (5.f)))));

		if(roll <  value) {
			baseWeather = i;
			break;
		}
	}

	int duration = (System::random(averageWeatherDuration) + (averageWeatherDuration / 2)) / (baseWeather + 1);
	currentMap = new WeatherMap(weatherStability, zone->getMinX(), zone->getMaxX(), zone->getMinY(), zone->getMaxY(), duration);

	if(weatherChangeEvent != NULL) {
		if(weatherChangeEvent->isScheduled())
			weatherChangeEvent->cancel();
	} else {
		weatherChangeEvent = new WeatherChangeEvent(_this.get());
	}

	weatherChangeEvent->reschedule(duration * 1000);
}

void WeatherManagerImplementation::sendWeatherTo(CreatureObject* player) {

	byte currentWeather = 0;

	if(currentMap != NULL)
		currentWeather = currentMap->getWeatherAt(player->getPositionX(), player->getPositionY()) + baseWeather;
	else
		currentWeather = baseWeather;

	if(currentWeather > 4)
		currentWeather = 0;

	if(hasDamagingSandstorms && currentWeather == WeatherManager::EXTREMESTORM) {
		applySandstormDamage(player);
	}

	if(player->getCurrentWeather() == currentWeather)
		return;

	if(hasDamagingSandstorms && player->getCurrentWeather() == WeatherManager::EXTREMESTORM) {
		player->sendSystemMessage("The storm has subsided.");
	}

	player->setCurrentWeather(currentWeather);

	if(hasDamagingSandstorms && currentWeather == WeatherManager::EXTREMESTORM) {
		player->sendSystemMessage("The weather around you quickly becomes damaging, seek shelter immediately.");
	}

	ServerWeatherMessage* weatherMessage = new ServerWeatherMessage(
			currentWeather,
			windX.get(player->getCurrentWind()),
			windMagnitude.get(player->getCurrentWind()),
			windY.get(player->getCurrentWind()));

	player->sendMessage(weatherMessage);

}

void WeatherManagerImplementation::applySandstormDamage(CreatureObject* player) {
	if (player == NULL)
		return;

	PlayerObject* ghost = player->getPlayerObject();

	//Check player's online status.
	if (ghost->isTeleporting() || !player->isOnline())
		return;

	//Check if player is in a shelter.
	if ((!player->isRidingMount() && player->getParentID() != 0) || player->getCurrentCamp() != NULL) //TODO: Add camp protection.
		return;

	//Blind player
	player->setBlindedState(60);

	//Calculate the sandstorm protection the player has.
	int totalCoverings = calculateSandstormProtection(player);

	//Apply wounds.
	int applicableDamage = sandstormDamage - totalCoverings;
	if (applicableDamage > 0) {
		player->inflictDamage(NULL, CreatureAttribute::HEALTH, applicableDamage, true, true);
		player->inflictDamage(NULL, CreatureAttribute::ACTION, applicableDamage, true, true);
		player->inflictDamage(NULL, CreatureAttribute::MIND, applicableDamage, true, true);
	}

	//Apply knockdown.
	int applicableKDChance = sandstormDamage - totalCoverings;
	if (applicableKDChance > 0 && !player->isProne() && !player->isKnockedDown() && System::random(200) > 198 ) {
		if (player->isRidingMount()) {
			player->sendSystemMessage("A gust of wind blows you off your vehicle!");
			player->dismount();
		} else
			player->sendSystemMessage("A gust of wind blows you off balance!");

		player->setPosture(CreaturePosture::KNOCKEDDOWN, true);
	}
}

int WeatherManagerImplementation::calculateSandstormProtection(CreatureObject* player) {
	if (player == NULL)
		return 0;

	int protection = 0;
	uint32 crc;

	//Check for protective head gear.
	ManagedReference<SceneObject*> hat = player->getSlottedObject("hat");
	if (hat != NULL) {
		crc = hat->getServerObjectCRC();
		if (crc == 0x612f992f || crc == 0xba3831b8 || crc == 0xdc8d2e72 || crc == 0x754b6f93) //Tusken Raider helmets, Swoop helmet, Large Headwrap.
			protection += 1;
		else if (hat->isArmorObject())
			protection += 1;
	}

	//Check for protective chest covering.
	bool tuskenRobe = false;
	ManagedReference<SceneObject*> robe = player->getSlottedObject("chest2");
	if (robe != NULL) {
		crc = robe->getServerObjectCRC();
		if (crc == 0xc20d81d9 || crc == 0x191a294e) { //Tusken Robes.
			tuskenRobe = true;
			protection += 2; //They cover both chest and legs.
		} else if (crc == 0xd95ec143 || crc == 0x3995e72f) //Scout Jacket, Heavy Reinforced Jacket.
			protection += 1;
		else if (crc == 0x9053a6ce || crc == 0x663c19d1) //Vested jacket, Desert Command Jacket.
			protection += 1;
		else if (robe->isArmorObject())
			protection += 1;
	}

	//Check for protective pants.
	if (!tuskenRobe) {
		ManagedReference<SceneObject*> pants = player->getSlottedObject("pants1");
		if (pants != NULL) {
			crc = pants->getServerObjectCRC();
			if (crc == 0x9488cb5f || crc == 0x10369d36 || crc == 0x9c6cabd4) //Paramilitary Camos, Basic Camos, Reinforced Pants.
				protection += 1;
			else if (crc == 0xb9f0dcd7 || crc == 0xc6ada1aa) //Desert Crawlers, Padded Workpants
				protection += 1;
		}

		ManagedReference<SceneObject*> pants2 = player->getSlottedObject("pants2");
		if (pants2 != NULL) {
			crc = pants2->getServerObjectCRC();
			if (pants2->isArmorObject())
				protection += 1;
		}
	}

	//Check for protective gloves.
	ManagedReference<SceneObject*> gloves = player->getSlottedObject("gloves");
	if (gloves != NULL) {
		crc = gloves->getServerObjectCRC();
		if (crc == 0x29fc844 || crc == 0x41ba6c29 || crc == 0x614eefaa) //Tusken gloves, Link-Steel Reinforced Gloves, Heavy Gloves.
			protection += 1;
		else if (gloves->isArmorObject())
			protection += 1;
	}

	//Check for protective boots.
	ManagedReference<SceneObject*> boots = player->getSlottedObject("shoes");
	if (boots != NULL) {
		crc = boots->getServerObjectCRC();
		if (crc == 0xbcc9eaac || crc == 0x873644ed) //Tusken boots, Sturdy boots
			protection += 1;
		else if (crc == 0x9192dd9e || crc == 0x35d80874) //Paneled Boots, Wrapped Boots.
			protection += 1;
		else if (boots->isArmorObject())
			protection += 1;
	}

	return protection;
}

void WeatherManagerImplementation::enableWeather(CreatureObject* player) {

	initialize();

	if (player != NULL)
		player->sendSystemMessage("The weather on this planet will now change automatically.");
}

void WeatherManagerImplementation::disableWeather(CreatureObject* player) {

	if (player == NULL || !weatherEnabled)
		return;

	Locker weatherManagerLocker(_this.get());
	weatherEnabled = false;

	if (weatherChangeEvent != NULL) {
		if (weatherChangeEvent->isScheduled())
			weatherChangeEvent->cancel();

		weatherChangeEvent = NULL;
	}

	currentMap = NULL;

	player->sendSystemMessage("The weather on this planet will no longer change automatically.");
}

void WeatherManagerImplementation::changeWeather(CreatureObject* player, int newWeather) {

	disableWeather(player);

	Locker weatherManagerLocker(_this.get());

	if(newWeather == 5)
		baseWeather = System::random(5);
	else {
		baseWeather = newWeather;
	}
}

void WeatherManagerImplementation::printInfo(CreatureObject* player) {

	if(currentMap == NULL) {
		player->sendSystemMessage("The weather currently is " + String::valueOf(baseWeather));
		return;
	}

	StringBuffer message;
	message << "Base: " << baseWeather << " " << currentMap->printInfo(player->getPositionX(), player->getPositionY());
	player->sendSystemMessage(message.toString());
}
<|endoftext|>


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

#include "TextureOGL.h"
#include "Engine.h"
#include "RendererOGL.h"
#include "Image.h"
#include "MathUtils.h"
#include "stb_image_resize.h"

namespace ouzel
{
    TextureOGL::TextureOGL()
    {

    }

    TextureOGL::~TextureOGL()
    {
        clean();
    }

    void TextureOGL::clean()
    {
        if (_textureId) glDeleteTextures(1, &_textureId);
    }

    bool TextureOGL::init(const Size2& size, bool dynamic, bool mipmaps)
    {
        if (!Texture::init(size, dynamic, mipmaps))
        {
            return false;
        }

        clean();

        glGenTextures(1, &_textureId);

        if (size.width > 0.0f && size.height > 0.0f)
        {
            GLint oldTextureId;
            glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTextureId);

            glBindTexture(GL_TEXTURE_2D, _textureId);

            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
                         static_cast<GLsizei>(size.width),
                         static_cast<GLsizei>(size.height),
                         0, GL_RGBA, GL_UNSIGNED_BYTE, 0);

            glBindTexture(GL_TEXTURE_2D, oldTextureId);

            if (std::static_pointer_cast<RendererOGL>(Engine::getInstance()->getRenderer())->checkOpenGLErrors())
            {
                return false;
            }
        }

        return true;
    }

    bool TextureOGL::initFromData(const void* data, const Size2& size, bool dynamic, bool mipmaps)
    {
        if (!Texture::initFromData(data, size, dynamic, mipmaps))
        {
            return false;
        }

        clean();

        GLint oldTextureId;
        glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTextureId);

        glGenTextures(1, &_textureId);

        glBindTexture(GL_TEXTURE_2D, _textureId);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

        glBindTexture(GL_TEXTURE_2D, oldTextureId);

        if (std::static_pointer_cast<RendererOGL>(Engine::getInstance()->getRenderer())->checkOpenGLErrors())
        {
            return false;
        }

        return uploadData(data,
                          static_cast<GLsizei>(size.width),
                          static_cast<GLsizei>(size.height));
    }

    bool TextureOGL::upload(const void* data, const Size2& size)
    {
        if (!Texture::upload(data, size))
        {
            return false;
        }

        return uploadData(data,
                          static_cast<GLsizei>(size.width),
                          static_cast<GLsizei>(size.height));
    }

    bool TextureOGL::uploadData(const void* data, GLsizei width, GLsizei height)
    {
        if (width <= 0 || height <= 0)
        {
            return false;
        }

        GLint oldTextureId;
        glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTextureId);

        if (oldTextureId != _textureId) glBindTexture(GL_TEXTURE_2D, _textureId);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height,
                     0, GL_RGBA, GL_UNSIGNED_BYTE, data);

        if (_mipmaps)
        {
            GLsizei mipWidth = width / 2;
            GLsizei mipHeight = height / 2;
            GLint mipLevel = 1;

            std::unique_ptr<uint8_t[]> mipMapData(new uint8_t[width * height * 4]);

            while (mipWidth >= 1 || mipHeight >= 1)
            {
                if (mipWidth < 1) mipWidth = 1;
                if (mipHeight < 1) mipHeight = 1;

                stbir_resize_uint8_generic(static_cast<const uint8_t*>(data), width, height, 0,
                                           mipMapData.get(), mipWidth, mipHeight, 0, 4,
                                           3, 0, STBIR_EDGE_CLAMP,
                                           STBIR_FILTER_MITCHELL, STBIR_COLORSPACE_LINEAR, nullptr);

                glTexImage2D(GL_TEXTURE_2D, mipLevel, GL_RGBA, mipWidth, mipHeight,
                             0, GL_RGBA, GL_UNSIGNED_BYTE, mipMapData.get());

                mipWidth /= 2;
                mipHeight /= 2;
                mipLevel++;
            }

            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
        }
        else
        {
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        }

        if (oldTextureId != _textureId) glBindTexture(GL_TEXTURE_2D, oldTextureId);

        if (std::static_pointer_cast<RendererOGL>(Engine::getInstance()->getRenderer())->checkOpenGLErrors())
        {
            return false;
        }

        return true;
    }
}
<commit_msg>Don't generate mip-maps for non-npot textures on OpenGLES<commit_after>// Copyright (C) 2016 Elviss Strazdins
// This file is part of the Ouzel engine.

#include "TextureOGL.h"
#include "Engine.h"
#include "RendererOGL.h"
#include "Image.h"
#include "MathUtils.h"
#include "stb_image_resize.h"

namespace ouzel
{
    TextureOGL::TextureOGL()
    {

    }

    TextureOGL::~TextureOGL()
    {
        clean();
    }

    void TextureOGL::clean()
    {
        if (_textureId) glDeleteTextures(1, &_textureId);
    }

    bool TextureOGL::init(const Size2& size, bool dynamic, bool mipmaps)
    {
        if (!Texture::init(size, dynamic, mipmaps))
        {
            return false;
        }

        clean();

        glGenTextures(1, &_textureId);

        if (size.width > 0.0f && size.height > 0.0f)
        {
            GLint oldTextureId;
            glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTextureId);

            glBindTexture(GL_TEXTURE_2D, _textureId);

            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
                         static_cast<GLsizei>(size.width),
                         static_cast<GLsizei>(size.height),
                         0, GL_RGBA, GL_UNSIGNED_BYTE, 0);

            glBindTexture(GL_TEXTURE_2D, oldTextureId);

            if (std::static_pointer_cast<RendererOGL>(Engine::getInstance()->getRenderer())->checkOpenGLErrors())
            {
                return false;
            }
        }

        return true;
    }

    bool TextureOGL::initFromData(const void* data, const Size2& size, bool dynamic, bool mipmaps)
    {
        if (!Texture::initFromData(data, size, dynamic, mipmaps))
        {
            return false;
        }

        clean();

        GLint oldTextureId;
        glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTextureId);

        glGenTextures(1, &_textureId);

        glBindTexture(GL_TEXTURE_2D, _textureId);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

        glBindTexture(GL_TEXTURE_2D, oldTextureId);

        if (std::static_pointer_cast<RendererOGL>(Engine::getInstance()->getRenderer())->checkOpenGLErrors())
        {
            return false;
        }

        return uploadData(data,
                          static_cast<GLsizei>(size.width),
                          static_cast<GLsizei>(size.height));
    }

    bool TextureOGL::upload(const void* data, const Size2& size)
    {
        if (!Texture::upload(data, size))
        {
            return false;
        }

        return uploadData(data,
                          static_cast<GLsizei>(size.width),
                          static_cast<GLsizei>(size.height));
    }

    bool TextureOGL::uploadData(const void* data, GLsizei width, GLsizei height)
    {
        if (width <= 0 || height <= 0)
        {
            return false;
        }

        GLint oldTextureId;
        glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTextureId);

        if (oldTextureId != _textureId) glBindTexture(GL_TEXTURE_2D, _textureId);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height,
                     0, GL_RGBA, GL_UNSIGNED_BYTE, data);

#ifdef SUPPORTS_OPENGLES
        if (_mipmaps && isPOT(width) && isPOT(height))
#else
        if (_mipmaps)
#endif
        {
            GLsizei mipWidth = width / 2;
            GLsizei mipHeight = height / 2;
            GLint mipLevel = 1;

            std::unique_ptr<uint8_t[]> mipMapData(new uint8_t[width * height * 4]);

            while (mipWidth >= 1 || mipHeight >= 1)
            {
                if (mipWidth < 1) mipWidth = 1;
                if (mipHeight < 1) mipHeight = 1;

                stbir_resize_uint8_generic(static_cast<const uint8_t*>(data), width, height, 0,
                                           mipMapData.get(), mipWidth, mipHeight, 0, 4,
                                           3, 0, STBIR_EDGE_CLAMP,
                                           STBIR_FILTER_MITCHELL, STBIR_COLORSPACE_LINEAR, nullptr);

                glTexImage2D(GL_TEXTURE_2D, mipLevel, GL_RGBA, mipWidth, mipHeight,
                             0, GL_RGBA, GL_UNSIGNED_BYTE, mipMapData.get());

                mipWidth /= 2;
                mipHeight /= 2;
                mipLevel++;
            }

            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
        }
        else
        {
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        }

        if (oldTextureId != _textureId) glBindTexture(GL_TEXTURE_2D, oldTextureId);

        if (std::static_pointer_cast<RendererOGL>(Engine::getInstance()->getRenderer())->checkOpenGLErrors())
        {
            return false;
        }

        return true;
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "timestamp.h"
#include <chrono>
#include <cmath>
#include <thread>
#include <sys/time.h>

using namespace std::chrono;

namespace fastos {

const TimeStamp::TimeT TimeStamp::MILLI;
const TimeStamp::TimeT TimeStamp::MICRO;
const TimeStamp::TimeT TimeStamp::NANO;
const TimeStamp::TimeT TimeStamp::US;
const TimeStamp::TimeT TimeStamp::MS;
const TimeStamp::TimeT TimeStamp::SEC;
const TimeStamp::TimeT TimeStamp::MINUTE;

std::string
TimeStamp::asString(double timeInSeconds)
{
    double intpart;
    double fractpart = std::modf(timeInSeconds, &intpart);
    time_t timeStamp = (time_t)intpart;
    struct tm timeStruct;
    gmtime_r(&timeStamp, &timeStruct);
    char timeString[128];
    strftime(timeString, sizeof(timeString), "%F %T", &timeStruct);
    char retval[160];
    uint32_t milliSeconds = std::min((uint32_t)(fractpart * 1000.0), 999u);
    snprintf(retval, sizeof(retval), "%s.%03u UTC", timeString, milliSeconds);
    return std::string(retval);
}

UTCTimeStamp
ClockSystem::now()
{
    struct timeval timeNow;
    gettimeofday(&timeNow, nullptr);
    int64_t ns = timeNow.tv_sec;
    ns *= TimeStamp::NANO;
    ns += timeNow.tv_usec*1000;
    return UTCTimeStamp(ns);
}

time_t
time() {
    return system_clock::to_time_t(system_clock::now());
}

namespace {

SteadyTimeStamp
steady_now() {
    return SteadyTimeStamp(duration_cast<nanoseconds>(steady_clock::now().time_since_epoch()).count());
}

}

std::ostream &
operator << (std::ostream & os, UTCTimeStamp ts) {
    return os << ts.toString();
}

std::ostream &
operator << (std::ostream & os, SteadyTimeStamp ts) {
    return os << ts.toString();
}

SteadyTimeStamp
ClockSteady::now()
{
    return steady_now();
}

const SteadyTimeStamp SteadyTimeStamp::ZERO;
const SteadyTimeStamp SteadyTimeStamp::FUTURE(TimeStamp::FUTURE);
const UTCTimeStamp UTCTimeStamp::ZERO;
const UTCTimeStamp UTCTimeStamp::FUTURE(TimeStamp::FUTURE);

UTCTimeStamp
SteadyTimeStamp::toUTC() const {
    UTCTimeStamp nowUtc = ClockSystem::now();
    SteadyTimeStamp nowSteady = ClockSteady::now();
    return nowUtc - (nowSteady - *this);
}

StopWatch::StopWatch()
    : _startTime(steady_now())
{ }

void
StopWatch::restart() {
    _startTime = steady_now();
}

TimeStamp
StopWatch::elapsed() const {
    TimeStamp diff(steady_now() - _startTime);
    return (diff > 0) ? diff : TimeStamp(0);
}

void
StopWatch::waitAtLeast(std::chrono::microseconds us, bool busyWait) {
    steady_clock::time_point startTime = steady_clock::now();
    steady_clock::time_point deadline = startTime + us;
    while (steady_clock::now() < deadline) {
        if (busyWait) {
            for (int i = 0; i < 1000; i++)
                ;
        } else {
            microseconds rem = (us - duration_cast<microseconds>(steady_clock::now() - startTime));
            std::this_thread::sleep_for(rem);
        }
    }
}

}
<commit_msg>Simplify.<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "timestamp.h"
#include <chrono>
#include <cmath>
#include <thread>
#include <sys/time.h>

using namespace std::chrono;

namespace fastos {

const TimeStamp::TimeT TimeStamp::MILLI;
const TimeStamp::TimeT TimeStamp::MICRO;
const TimeStamp::TimeT TimeStamp::NANO;
const TimeStamp::TimeT TimeStamp::US;
const TimeStamp::TimeT TimeStamp::MS;
const TimeStamp::TimeT TimeStamp::SEC;
const TimeStamp::TimeT TimeStamp::MINUTE;

std::string
TimeStamp::asString(double timeInSeconds)
{
    double intpart;
    double fractpart = std::modf(timeInSeconds, &intpart);
    time_t timeStamp = (time_t)intpart;
    struct tm timeStruct;
    gmtime_r(&timeStamp, &timeStruct);
    char timeString[128];
    strftime(timeString, sizeof(timeString), "%F %T", &timeStruct);
    char retval[160];
    uint32_t milliSeconds = std::min((uint32_t)(fractpart * 1000.0), 999u);
    snprintf(retval, sizeof(retval), "%s.%03u UTC", timeString, milliSeconds);
    return std::string(retval);
}

UTCTimeStamp
ClockSystem::now()
{
    struct timeval timeNow;
    gettimeofday(&timeNow, nullptr);
    int64_t ns = timeNow.tv_sec;
    ns *= TimeStamp::NANO;
    ns += timeNow.tv_usec*1000;
    return UTCTimeStamp(ns);
}

time_t
time() {
    return system_clock::to_time_t(system_clock::now());
}

namespace {

SteadyTimeStamp
steady_now() {
    return SteadyTimeStamp(duration_cast<nanoseconds>(steady_clock::now().time_since_epoch()).count());
}

}

std::ostream &
operator << (std::ostream & os, UTCTimeStamp ts) {
    return os << ts.toString();
}

std::ostream &
operator << (std::ostream & os, SteadyTimeStamp ts) {
    return os << ts.toString();
}

SteadyTimeStamp
ClockSteady::now()
{
    return steady_now();
}

const SteadyTimeStamp SteadyTimeStamp::ZERO;
const SteadyTimeStamp SteadyTimeStamp::FUTURE(TimeStamp::FUTURE);
const UTCTimeStamp UTCTimeStamp::ZERO;
const UTCTimeStamp UTCTimeStamp::FUTURE(TimeStamp::FUTURE);

UTCTimeStamp
SteadyTimeStamp::toUTC() const {
    UTCTimeStamp nowUtc = ClockSystem::now();
    SteadyTimeStamp nowSteady = ClockSteady::now();
    return nowUtc - (nowSteady - *this);
}

StopWatch::StopWatch()
    : _startTime(steady_now())
{ }

void
StopWatch::restart() {
    _startTime = steady_now();
}

TimeStamp
StopWatch::elapsed() const {
    return (steady_now() - _startTime);
}

void
StopWatch::waitAtLeast(std::chrono::microseconds us, bool busyWait) {
    if (busyWait) {
        steady_clock::time_point deadline = steady_clock::now() + us;
        while (steady_clock::now() < deadline) {
            if (busyWait) {
                for (int i = 0; i < 1000; i++) { }
            }
        }
    } else {
        std::this_thread::sleep_for(us);
    }
}

}
<|endoftext|>


<commit_before>#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <stdio.h>
#include <boost/algorithm/string.hpp>
#include <boost/range.hpp>
#include <boost/tokenizer.hpp>

#include "ObjLoader.hpp"
#include "ObjLoaderUtils.hpp"

using namespace boost;
using namespace ObjLoaderUtils;
ObjLoader::ObjLoader():
  vertex_array(),
  index_array()
{

}

void ObjLoader::load_file(const std::string& path) {
  std::ifstream file(path);
  if(!file.is_open()) {
    printf("Failed to open %s!", path.c_str());
    exit(EXIT_FAILURE);
  }
  std::string line;
  char_separator<char> space_sep(" ");
  while(getline(file, line)) {
    boost::trim(line);
    if(line.size() > 0) {
      tokenizer<char_separator<char> > st(line, space_sep);
      std::vector<std::string> tokens;
      //Might make parsing faster.
      //tokens.reserve(4);
      for(auto& token: st) {
	tokens.push_back(token);
      }
      handleTokens(tokens);
    }
  }
}

void ObjLoader::handleTokens(std::vector<std::string>& tokens) {
  const char* type = popFirstToken(tokens).c_str();
  if(!strcmp(type, "v")) {
    auto vert = toFloatArray<3>(tokens);
    posList.push_back(vert);
  } else if(!strcmp(type, "vt")) {
    auto vert = toFloatArray<2>(tokens);
    uvList.push_back(vert);
  } else if(!strcmp(type, "vn")) {
    auto vert = toFloatArray<3>(tokens);
    normalList.push_back(vert);
  } else if(!strcmp(type, "f")) {
    if(tokens.size() == 3) {
      createFace({tokens[0], tokens[1], tokens[2]});
    } else if(tokens.size() == 4) {
      createFace({tokens[0], tokens[2], tokens[3]});
      createFace({tokens[0], tokens[1], tokens[2]});
    }
  }
}

  template<long long unsigned int n>
    void printVec(std::array<float, n> vec) {
      for(const auto& v: vec)
	std::cout << v << ", ";
      std::cout << "\n";
    }

//TODO: First load triangle, then decide if it is already indexed
void ObjLoader::createFace(const std::vector<std::string>& face_string) {
  char_separator<char> slash_sep("/");
  Face face;
  face.verts.resize(3);
  for(auto i = 0u; i < face_string.size(); i++) {
    const auto& vertTokens = face_string[i];
    //Is the vertex already loaded to the buffer?
    Vertex vertex;
    if(loaded_vertices_map.count(vertTokens) > 0) {
      index_array.push_back(loaded_vertices_map[vertTokens]);
      vertex.isIndexed = true;
    }
    tokenizer<char_separator<char> > tokenizer(vertTokens, slash_sep);
    std::vector<int> vert;
    for(const auto& t: tokenizer)
      vert.push_back(atoi(t.c_str()) - 1);
    for(int j = 0; j < 3; j++)
      vertex.pos[j] = posList[vert[0]][j];
    for(int j = 0; j < 2; j++)
      vertex.uv[j] = uvList[vert[1]][j];
    for(int j = 0; j < 3; j++)
      vertex.normal[j] = normalList[vert[2]][j];
    face.verts[i] = vertex;
    //face.verts.push_back(vertex);
    std::cout << face.verts[i].pos[0] << ", ";
    std::cout << face.verts[i].pos[1] << ", ";
    std::cout << face.verts[i].pos[2] << "\n";

    if(!vertex.isIndexed) {
      loaded_vertices_map[vertTokens] = last_index;
      index_array.push_back(last_index);
      last_index++;
    }
  }

  calcTangent(face);
  for(const auto& vert: face.verts) {
    if(vert.isIndexed) {
      continue;
    }
    for(const auto& val: vert.pos)
      vertex_array.push_back(val);
    for(const auto& val: vert.uv)
      vertex_array.push_back(val);
    for(const auto& val: vert.normal)
      vertex_array.push_back(val);
    for(const auto& val: vert.tangent)
      vertex_array.push_back(val);
    for(const auto& val: vert.bitangent)
      vertex_array.push_back(val);
  }
}

std::vector<std::string> get_tokens(std::string line) {
  static char_separator<char> space_sep(" ");
  boost::trim(line);
  tokenizer<char_separator<char> > st(line, space_sep);
  std::vector<std::string> tokens;
  //Might make parsing faster.
  //tokens.reserve(4);
  for(auto& token: st) {
    tokens.push_back(token);
  }
  return tokens;
}

std::vector<Mesh> ObjLoader::preload(const std::string& filename) {
  file_list.push_back(filename);
  std::vector<Mesh> ret;
  std::ifstream file;
  int current_vertex_count = 0;
  file.open(filename, std::ios::in);
  if(!file.is_open()) {
    printf("Failed to open %s!", filename.c_str());
    exit(EXIT_FAILURE);
  }
  std::string line;
  while(getline(file, line)) {
    auto tokens = get_tokens(line);
    if(tokens.size() == 0) {
      continue;
    }

    if(!strcmp(tokens[0].c_str(), "g")) {
      if(current_vertex_count > 0) {
	Mesh mesh;
	mesh.name = last_name;
	mesh.start = last_end;
	mesh.end = vertex_count + last_end;
	mesh.material = mtl_loader.materials[last_material];

	mesh_list.push_back(mesh);
	ret.push_back(mesh);
      }

      last_name = tokens[1];
      last_end = vertex_count;
    } else if(!strcmp(tokens[0].c_str(), "f")) {
      if(tokens.size() == 4) {
	vertex_count += 3;
	current_vertex_count += 3;
      } else if(tokens.size() == 5) {
	vertex_count += 6;
	current_vertex_count += 6;
      }
    } else if(!strcmp(tokens[0].c_str(), "mtllib")) {
      mtl_loader.load_materials("assets/" + tokens[1]);
    } else if(!strcmp(tokens[0].c_str(), "usemtl")) {
      last_material = tokens[1];
    }
  }
  Mesh mesh;
  mesh.name = last_name;
  mesh.start = last_end;
  mesh.end = vertex_count + last_end;
  mesh.material = mtl_loader.materials[last_material];

  mesh_list.push_back(mesh);
  ret.push_back(mesh);

  file.close();
  last_end = vertex_count;

  return ret;
}

void ObjLoader::load_preloaded_data() {
  std::cout << "Reserving " << vertex_count << " for vertex array" << std::endl;
  vertex_array.reserve(vertex_count);
  last_index_count = 0;
  for(const auto& file: file_list) {
    load_file(file);
    //loaded_vertices.clear();
    loaded_vertices_map.clear();
    posList.clear();
    uvList.clear();
    normalList.clear();
    last_index_count = last_index;
  }
  /*
  for(const auto& p: (*vertex_array)) {
    std::cout << p << ", ";
  }
  */
}
<commit_msg>Removed old log prints + commented out code<commit_after>#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <stdio.h>
#include <boost/algorithm/string.hpp>
#include <boost/range.hpp>
#include <boost/tokenizer.hpp>

#include "ObjLoader.hpp"
#include "ObjLoaderUtils.hpp"

using namespace boost;
using namespace ObjLoaderUtils;
ObjLoader::ObjLoader():
  vertex_array(),
  index_array()
{

}

void ObjLoader::load_file(const std::string& path) {
  std::ifstream file(path);
  if(!file.is_open()) {
    printf("Failed to open %s!", path.c_str());
    exit(EXIT_FAILURE);
  }
  std::string line;
  char_separator<char> space_sep(" ");
  while(getline(file, line)) {
    boost::trim(line);
    if(line.size() > 0) {
      tokenizer<char_separator<char> > st(line, space_sep);
      std::vector<std::string> tokens;
      //Might make parsing faster.
      //tokens.reserve(4);
      for(auto& token: st) {
	tokens.push_back(token);
      }
      handleTokens(tokens);
    }
  }
}

void ObjLoader::handleTokens(std::vector<std::string>& tokens) {
  const char* type = popFirstToken(tokens).c_str();
  if(!strcmp(type, "v")) {
    auto vert = toFloatArray<3>(tokens);
    posList.push_back(vert);
  } else if(!strcmp(type, "vt")) {
    auto vert = toFloatArray<2>(tokens);
    uvList.push_back(vert);
  } else if(!strcmp(type, "vn")) {
    auto vert = toFloatArray<3>(tokens);
    normalList.push_back(vert);
  } else if(!strcmp(type, "f")) {
    if(tokens.size() == 3) {
      createFace({tokens[0], tokens[1], tokens[2]});
    } else if(tokens.size() == 4) {
      createFace({tokens[0], tokens[2], tokens[3]});
      createFace({tokens[0], tokens[1], tokens[2]});
    }
  }
}

  template<long long unsigned int n>
    void printVec(std::array<float, n> vec) {
      for(const auto& v: vec)
	std::cout << v << ", ";
      std::cout << "\n";
    }

void ObjLoader::createFace(const std::vector<std::string>& face_string) {
  char_separator<char> slash_sep("/");
  Face face;
  face.verts.resize(3);
  for(auto i = 0u; i < face_string.size(); i++) {
    const auto& vertTokens = face_string[i];
    //Is the vertex already loaded to the buffer?
    Vertex vertex;
    if(loaded_vertices_map.count(vertTokens) > 0) {
      index_array.push_back(loaded_vertices_map[vertTokens]);
      vertex.isIndexed = true;
    }
    tokenizer<char_separator<char> > tokenizer(vertTokens, slash_sep);
    std::vector<int> vert;
    for(const auto& t: tokenizer)
      vert.push_back(atoi(t.c_str()) - 1);
    for(int j = 0; j < 3; j++)
      vertex.pos[j] = posList[vert[0]][j];
    for(int j = 0; j < 2; j++)
      vertex.uv[j] = uvList[vert[1]][j];
    for(int j = 0; j < 3; j++)
      vertex.normal[j] = normalList[vert[2]][j];
    face.verts[i] = vertex;

    if(!vertex.isIndexed) {
      loaded_vertices_map[vertTokens] = last_index;
      index_array.push_back(last_index);
      last_index++;
    }
  }

  calcTangent(face);
  for(const auto& vert: face.verts) {
    if(vert.isIndexed) {
      continue;
    }
    for(const auto& val: vert.pos)
      vertex_array.push_back(val);
    for(const auto& val: vert.uv)
      vertex_array.push_back(val);
    for(const auto& val: vert.normal)
      vertex_array.push_back(val);
    for(const auto& val: vert.tangent)
      vertex_array.push_back(val);
    for(const auto& val: vert.bitangent)
      vertex_array.push_back(val);
  }
}

std::vector<std::string> get_tokens(std::string line) {
  static char_separator<char> space_sep(" ");
  boost::trim(line);
  tokenizer<char_separator<char> > st(line, space_sep);
  std::vector<std::string> tokens;
  //Might make parsing faster.
  //tokens.reserve(4);
  for(auto& token: st) {
    tokens.push_back(token);
  }
  return tokens;
}

std::vector<Mesh> ObjLoader::preload(const std::string& filename) {
  file_list.push_back(filename);
  std::vector<Mesh> ret;
  std::ifstream file;
  int current_vertex_count = 0;
  file.open(filename, std::ios::in);
  if(!file.is_open()) {
    printf("Failed to open %s!", filename.c_str());
    exit(EXIT_FAILURE);
  }
  std::string line;
  while(getline(file, line)) {
    auto tokens = get_tokens(line);
    if(tokens.size() == 0) {
      continue;
    }

    if(!strcmp(tokens[0].c_str(), "g")) {
      if(current_vertex_count > 0) {
	Mesh mesh;
	mesh.name = last_name;
	mesh.start = last_end;
	mesh.end = vertex_count + last_end;
	mesh.material = mtl_loader.materials[last_material];

	mesh_list.push_back(mesh);
	ret.push_back(mesh);
      }

      last_name = tokens[1];
      last_end = vertex_count;
    } else if(!strcmp(tokens[0].c_str(), "f")) {
      if(tokens.size() == 4) {
	vertex_count += 3;
	current_vertex_count += 3;
      } else if(tokens.size() == 5) {
	vertex_count += 6;
	current_vertex_count += 6;
      }
    } else if(!strcmp(tokens[0].c_str(), "mtllib")) {
      mtl_loader.load_materials("assets/" + tokens[1]);
    } else if(!strcmp(tokens[0].c_str(), "usemtl")) {
      last_material = tokens[1];
    }
  }
  Mesh mesh;
  mesh.name = last_name;
  mesh.start = last_end;
  mesh.end = vertex_count + last_end;
  mesh.material = mtl_loader.materials[last_material];

  mesh_list.push_back(mesh);
  ret.push_back(mesh);

  file.close();
  last_end = vertex_count;

  return ret;
}

void ObjLoader::load_preloaded_data() {
  std::cout << "Reserving " << vertex_count << " for vertex array" << std::endl;
  vertex_array.reserve(vertex_count);
  last_index_count = 0;
  for(const auto& file: file_list) {
    load_file(file);
    //loaded_vertices.clear();
    loaded_vertices_map.clear();
    posList.clear();
    uvList.clear();
    normalList.clear();
    last_index_count = last_index;
  }
  /*
  for(const auto& p: (*vertex_array)) {
    std::cout << p << ", ";
  }
  */
}
<|endoftext|>


<commit_before>/*
 * TetSubdivider.cpp
 *
 *  Created on: May 31, 2014
 *      Author: pourya
 */
#include "TetSubdivider.h"
#include "base/Logger.h"
#include <set>

using namespace PS;
using namespace std;

namespace PS {
namespace FEM {

//elements to be generated for case A
U32 g_elementTableCaseA[4][16] = {
		//Node 0: cutEdgeCode = 56, edges cut = 3, 4, 5
		{0, 12, 10, 14, 3, 13, 11, 15, 3, 1, 15, 11, 1, 2, 3, 11},

		//Node 1: cutEdgeCode = 37, edges cut = 0, 2, 5
		{1, 4, 8, 15, 3, 9, 5, 14, 0, 3, 14, 5, 0, 2, 3, 5},

		//Node 2: cutEdgeCode = 11, edges cut = 0, 1, 3
		{2, 5, 6, 11, 3, 7, 10, 4, 3, 1, 4, 10, 0, 1, 3, 10},

		//Node 3: cutEdgeCode = 22, edges cut = 1, 2, 4
		{3, 13, 9, 7, 1, 8, 12, 6, 1, 2, 12, 6, 0, 1, 2, 12},
};

//elements to be generated for case A
U32 g_elementTableCaseB[3][6][4] = {
		//case 0,
		{ {2, 6, 11, 1}, {8, 11, 15, 1}, {6, 11, 8, 1}, {3, 7, 9, 10}, {3, 10, 0, 9}, {0, 14, 10, 9}},

		//case 1,
		{ {3, 7, 13, 15}, {15, 1, 4, 7}, {15, 1, 3, 7}, {0, 12, 14, 6}, {2, 5, 6, 14}, {0, 14, 6, 2}},

		//case 2,
		{ {4, 10, 12, 0}, {0, 8, 12, 4}, {0, 8, 1, 4}, {3, 9, 13, 5}, {2, 5, 11, 3}, {3, 9, 5, 11}}
};

TetSubdivider::TetSubdivider(HalfEdgeTetMesh* pMesh) {
	m_lpHEMesh = pMesh;

	//case A
	m_mapCutEdgeCodeToTableEntry[56] = 0;
	m_mapCutEdgeCodeToTableEntry[37] = 1;
	m_mapCutEdgeCodeToTableEntry[11] = 2;
	m_mapCutEdgeCodeToTableEntry[22] = 3;

	//case B
	m_mapCutEdgeCodeToTableEntry[46] = 0;
	m_mapCutEdgeCodeToTableEntry[51] = 1;
	m_mapCutEdgeCodeToTableEntry[29] = 2;
}

TetSubdivider::~TetSubdivider() {
}

int TetSubdivider::generateCaseA(U32 element, U8 node, double targetDist,
									   U8& cutEdgeCode, U8& cutNodeCode, double (&tEdges)[6]) {

	if(node >= 4)
		return -1;
	if(!m_lpHEMesh->isElemIndex(element))
		return -1;

	cutEdgeCode = 0;
	cutNodeCode = 0;

	int res = 0;
	HalfEdgeTetMesh::ELEM elem = m_lpHEMesh->elemAt(element);
	for(int i=0; i<6; i++) {
		tEdges[i] = 0.0;

		HalfEdgeTetMesh::EDGE edge = m_lpHEMesh->edgeAt( m_lpHEMesh->edge_from_halfedge(elem.halfedge[i]) );

		if(edge.from == node || edge.to == node) {
			cutEdgeCode |= (1 << i);

			if(edge.from == node)
				tEdges[i] = targetDist;
			else
				tEdges[i] = 1.0 - targetDist;

			res ++;
		}
	}

	return res;

}

int TetSubdivider::generateCaseB(U32 element, U8 enteringface, U8& cutEdgeCode,
					  U8& cutNodeCode, double (&tEdges)[6]) {

	if(!m_lpHEMesh->isElemIndex(element))
		return -1;
	if(enteringface < 0 || enteringface > 2)
		return -1;

	cutEdgeCode = cutNodeCode = 0;
	for(int i=0; i<6; i++)
		tEdges[i] = 0.0;

	U8 edges[4];
	//face: entering edges --> exiting edges
	//0: 1, 2 --> 3, 5
	//1: 1, 4 --> 0, 5
	//2: 2, 4 --> 0, 3
	if(enteringface == 0) {
		edges[0] = 1;
		edges[1] = 2;
		edges[2] = 3;
		edges[3] = 5;
	}
	else if(enteringface == 1) {
		//edges = {1, 4, 0, 5};
		edges[0] = 1;
		edges[1] = 4;
		edges[2] = 0;
		edges[3] = 5;
	}
	else if(enteringface == 2) {
		//edges = {2, 4, 0, 3};
		edges[0] = 2;
		edges[1] = 4;
		edges[2] = 0;
		edges[3] = 3;
	}

	for(int i=0; i<4; i++) {
		cutEdgeCode |= (1 << edges[i]);

		tEdges[ edges[i] ] = 0.5;
	}

	return 1;
}

int TetSubdivider::subdivide(U32 element, U8 cutEdgeCode, U8 cutNodeCode, double tEdges[6], bool dosplit) {
	//Here an element is subdivided to 4 sub elements depending on the codes
	U8 ctCutEdges = 0;

	//6 edges per tet
	for(int i=0; i < 6; i++)
		ctCutEdges += ((cutEdgeCode & (1 << i)) != 0);

	U8 ctCutNodes = 0;

	//4 nodes per tet
	for(int i=0; i < 4; i++)
		ctCutNodes += ((cutNodeCode & (1 << i)) != 0);

	printf("Number of cutEdges: %d, cutNodes: %d \n", ctCutEdges, ctCutNodes);

	//fill the array of virtual nodes
	U32 vnodes[16];
	for(int i=0; i<16; i++)
		vnodes[i] = HalfEdgeTetMesh::INVALID_INDEX;
	const HalfEdgeTetMesh::ELEM& one = m_lpHEMesh->elemAt(element);

	//1st 4 nodes come from the original element
	for(int i=0; i<4; i++)
		vnodes[i] = one.nodes[i];

	//Mask to map edges indices to new generated node indices
	const int mapEdgeToMiddleNodes[12] = {4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};

	if(ctCutEdges > 0) {

		//loop over edges
		for(int i=0; i < 6; i++) {
			bool isCut = ((cutEdgeCode & (1 << i)) != 0);

			if(isCut) {
				U32 idxNP0, idxNP1;

				U32 idxEdgeToCut = m_lpHEMesh->edge_from_halfedge(one.halfedge[i]);
				if(!m_lpHEMesh->cut_edge(idxEdgeToCut, tEdges[i], &idxNP0, &idxNP1)) {
					LogErrorArg2("Unable to cut edge %d of element %d", i, element);
				}

				//generated nodes
				vnodes[ mapEdgeToMiddleNodes[i*2 + 0] ] = idxNP0;
				vnodes[ mapEdgeToMiddleNodes[i*2 + 1] ] = idxNP1;
			}
		}
	}

	//Case A: 3 cut edges. cutEdgeCodes = { 11, 22, 37, 56 }
	if(ctCutEdges == 3) {
		//Remove the original element
		m_lpHEMesh->remove_element(element);

		//find the local table entry to handle this case A
		int entry = m_mapCutEdgeCodeToTableEntry[cutEdgeCode];

		//report
		LogInfoArg3("Detected case is type A: cutEdgeCode: %u, cutNodeCode: %u, entry: %u", cutEdgeCode, cutNodeCode, entry);

		//generate 4 new tets
		for(int e = 0; e < 4; e++) {
			U32 n[4];

			for(int i = 0; i < 4; i++)
				n[i] = vnodes[ g_elementTableCaseA[entry][e * 4 + i] ];

			if(dosplit && e == 0) {
				vec3d pos[4];

				for(int k=0; k < 4; k++)
					pos[k] = m_lpHEMesh->nodeAt(n[k]).pos;

				vec3d centroid = pos[0];
				for(int k=1; k < 4; k++)
					centroid = centroid + pos[k];
				centroid = centroid * 0.25;

				vec3d norm = (pos[0] - centroid).normalized();
				double dist = (pos[0] - centroid).length() * 0.3;

				for(int k = 0; k<4; k++)
					m_lpHEMesh->nodeAt( n[ k ]).pos = pos[k] + norm * dist;

			}

			m_lpHEMesh->insert_element(n);
		}
	}
	//Case B: 4 cut edges. cutEdgeCodes = { 46, 51, 29 }
	else if(ctCutEdges == 4) {
		//Remove the original element
		m_lpHEMesh->remove_element(element);

		//find the local table entry to handle this case B
		int entry = m_mapCutEdgeCodeToTableEntry[cutEdgeCode];

		//report
		LogInfoArg3("Detected case is type B: cutEdgeCode: %u, cutNodeCode: %u, entry: %u", cutEdgeCode, cutNodeCode, entry);

		//generate 6 new tets
		for(int e = 0; e < 6; e++) {

			U32 n[4];
			for(int i = 0; i < 4; i++)
				n[i] = vnodes[ g_elementTableCaseB[entry][e][i] ];

			m_lpHEMesh->insert_element(n);
		}

		if(dosplit) {
			set<U32> splittedNodes1;
			set<U32> splittedNodes2;
			vec3d cent1, cent2;

			//insert nodes for the first 3 tets
			for(int e=0; e<3; e++) {
				for(int i = 0; i < 4; i++) {
					splittedNodes1.insert( vnodes[ g_elementTableCaseB[entry][e][i] ]);
				}
			}

			//insert nodes for the last 3 tets
			for(int e=3; e<6; e++) {
				for(int i = 0; i < 4; i++) {
					splittedNodes2.insert( vnodes[ g_elementTableCaseB[entry][e][i] ]);
				}
			}

			if(splittedNodes1.size() != 6 || splittedNodes2.size() != 6) {
				LogError("Splitted nodes are not sets of 6!");
				return -1;
			}

			vec3d arrP1[6];
			int i = 0;
			for(set<U32>::const_iterator it = splittedNodes1.begin(); it != splittedNodes1.end(); it++) {
				arrP1[i] = m_lpHEMesh->nodeAt( *it ).pos;
				if(i == 0)
					cent1 = arrP1[i];
				else
					cent1 = cent1 + arrP1[i];
				i++;
			}
			cent1 = cent1 * (1.0 / 6.0);

			//second set
			vec3d arrP2[6];
			i = 0;
			for(set<U32>::const_iterator it = splittedNodes2.begin(); it != splittedNodes2.end(); it++) {
				arrP2[i] = m_lpHEMesh->nodeAt( *it ).pos;
				if(i == 0)
					cent2 = arrP2[i];
				else
					cent2 = cent2 + arrP2[i];
				i++;
			}
			cent2 = cent2 * (1.0 / 6.0);

			//compute norm and dist
			vec3d norm = (cent1 - cent2).normalized();
			double dist = (cent1 - cent2).length() * 0.3;

			//splitted nodes
			i = 0;
			for(set<U32>::const_iterator it = splittedNodes1.begin(); it != splittedNodes1.end(); it++) {
				m_lpHEMesh->nodeAt( *it ).pos = arrP1[i] + norm * dist;
				i++;
			}
		}
	}
	else {
		LogErrorArg3("This case is not handled yet! cutEdgeCode = %u, cutNodeCode = %u, ctCutEdges = %u",
					 cutEdgeCode, cutNodeCode, ctCutEdges);
	}

	return cutEdgeCode;
}

void TetSubdivider::draw() {

	if(m_lpHEMesh)
		m_lpHEMesh->draw();
}

}
}

<commit_msg>modified tetsubd<commit_after>/*
 * TetSubdivider.cpp
 *
 *  Created on: May 31, 2014
 *      Author: pourya
 */
#include "TetSubdivider.h"
#include "base/Logger.h"
#include <set>

using namespace PS;
using namespace std;

namespace PS {
namespace FEM {

//elements to be generated for case A
U32 g_elementTableCaseA[4][16] = {
		//Node 0: cutEdgeCode = 56, edges cut = 3, 4, 5
		{0, 12, 10, 14, 3, 13, 11, 15, 3, 1, 15, 11, 1, 2, 3, 11},

		//Node 1: cutEdgeCode = 37, edges cut = 0, 2, 5
		{1, 4, 8, 15, 3, 9, 5, 14, 0, 3, 14, 5, 0, 2, 3, 5},

		//Node 2: cutEdgeCode = 11, edges cut = 0, 1, 3
		{2, 5, 6, 11, 3, 7, 10, 4, 3, 1, 4, 10, 0, 1, 3, 10},

		//Node 3: cutEdgeCode = 22, edges cut = 1, 2, 4
		{3, 13, 9, 7, 1, 8, 12, 6, 1, 2, 12, 6, 0, 1, 2, 12},
};

//elements to be generated for case A
U32 g_elementTableCaseB[3][6][4] = {
		//case 0,
		{ {2, 6, 11, 1}, {8, 11, 15, 1}, {6, 11, 8, 1}, {3, 7, 9, 10}, {3, 10, 0, 9}, {0, 14, 10, 9}},

		//case 1,
		{ {3, 7, 13, 15}, {15, 1, 4, 7}, {15, 1, 3, 7}, {0, 12, 14, 6}, {2, 5, 6, 14}, {0, 14, 6, 2}},

		//case 2,
		//{ {4, 10, 12, 0}, {0, 8, 12, 4}, {0, 8, 1, 4}, {3, 9, 13, 5}, {2, 5, 11, 3}, {3, 9, 5, 11}}
		{ {4, 10, 12, 0}, {0, 8, 12, 4}, {0, 8, 1, 4}, {3, 9, 13, 5}, {2, 5, 11, 3}, {3, 3, 3, 3}}
};

TetSubdivider::TetSubdivider(HalfEdgeTetMesh* pMesh) {
	m_lpHEMesh = pMesh;

	//case A
	m_mapCutEdgeCodeToTableEntry[56] = 0;
	m_mapCutEdgeCodeToTableEntry[37] = 1;
	m_mapCutEdgeCodeToTableEntry[11] = 2;
	m_mapCutEdgeCodeToTableEntry[22] = 3;

	//case B
	m_mapCutEdgeCodeToTableEntry[46] = 0;
	m_mapCutEdgeCodeToTableEntry[51] = 1;
	m_mapCutEdgeCodeToTableEntry[29] = 2;
}

TetSubdivider::~TetSubdivider() {
}

int TetSubdivider::generateCaseA(U32 element, U8 node, double targetDist,
									   U8& cutEdgeCode, U8& cutNodeCode, double (&tEdges)[6]) {

	if(node >= 4)
		return -1;
	if(!m_lpHEMesh->isElemIndex(element))
		return -1;

	cutEdgeCode = 0;
	cutNodeCode = 0;

	int res = 0;
	HalfEdgeTetMesh::ELEM elem = m_lpHEMesh->elemAt(element);
	for(int i=0; i<6; i++) {
		tEdges[i] = 0.0;

		HalfEdgeTetMesh::EDGE edge = m_lpHEMesh->edgeAt( m_lpHEMesh->edge_from_halfedge(elem.halfedge[i]) );

		if(edge.from == node || edge.to == node) {
			cutEdgeCode |= (1 << i);

			if(edge.from == node)
				tEdges[i] = targetDist;
			else
				tEdges[i] = 1.0 - targetDist;

			res ++;
		}
	}

	return res;

}

int TetSubdivider::generateCaseB(U32 element, U8 enteringface, U8& cutEdgeCode,
					  U8& cutNodeCode, double (&tEdges)[6]) {

	if(!m_lpHEMesh->isElemIndex(element))
		return -1;
	if(enteringface < 0 || enteringface > 2)
		return -1;

	cutEdgeCode = cutNodeCode = 0;
	for(int i=0; i<6; i++)
		tEdges[i] = 0.0;

	U8 edges[4];
	//face: entering edges --> exiting edges
	//0: 1, 2 --> 3, 5
	//1: 1, 4 --> 0, 5
	//2: 2, 4 --> 0, 3
	if(enteringface == 0) {
		edges[0] = 1;
		edges[1] = 2;
		edges[2] = 3;
		edges[3] = 5;
	}
	else if(enteringface == 1) {
		//edges = {1, 4, 0, 5};
		edges[0] = 1;
		edges[1] = 4;
		edges[2] = 0;
		edges[3] = 5;
	}
	else if(enteringface == 2) {
		//edges = {2, 4, 0, 3};
		edges[0] = 2;
		edges[1] = 4;
		edges[2] = 0;
		edges[3] = 3;
	}

	for(int i=0; i<4; i++) {
		cutEdgeCode |= (1 << edges[i]);

		tEdges[ edges[i] ] = 0.5;
	}

	return 1;
}

int TetSubdivider::subdivide(U32 element, U8 cutEdgeCode, U8 cutNodeCode, double tEdges[6], bool dosplit) {
	//Here an element is subdivided to 4 sub elements depending on the codes
	U8 ctCutEdges = 0;

	//6 edges per tet
	for(int i=0; i < 6; i++)
		ctCutEdges += ((cutEdgeCode & (1 << i)) != 0);

	U8 ctCutNodes = 0;

	//4 nodes per tet
	for(int i=0; i < 4; i++)
		ctCutNodes += ((cutNodeCode & (1 << i)) != 0);

	printf("Number of cutEdges: %d, cutNodes: %d \n", ctCutEdges, ctCutNodes);

	//fill the array of virtual nodes
	U32 vnodes[16];
	for(int i=0; i<16; i++)
		vnodes[i] = HalfEdgeTetMesh::INVALID_INDEX;
	const HalfEdgeTetMesh::ELEM& one = m_lpHEMesh->elemAt(element);

	//1st 4 nodes come from the original element
	for(int i=0; i<4; i++)
		vnodes[i] = one.nodes[i];

	//Mask to map edges indices to new generated node indices
	const int mapEdgeToMiddleNodes[12] = {4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};

	if(ctCutEdges > 0) {

		//loop over edges
		for(int i=0; i < 6; i++) {
			bool isCut = ((cutEdgeCode & (1 << i)) != 0);

			if(isCut) {
				U32 idxNP0, idxNP1;

				U32 idxEdgeToCut = m_lpHEMesh->edge_from_halfedge(one.halfedge[i]);
				if(!m_lpHEMesh->cut_edge(idxEdgeToCut, tEdges[i], &idxNP0, &idxNP1)) {
					LogErrorArg2("Unable to cut edge %d of element %d", i, element);
				}

				//generated nodes
				vnodes[ mapEdgeToMiddleNodes[i*2 + 0] ] = idxNP0;
				vnodes[ mapEdgeToMiddleNodes[i*2 + 1] ] = idxNP1;
			}
		}
	}

	//Case A: 3 cut edges. cutEdgeCodes = { 11, 22, 37, 56 }
	if(ctCutEdges == 3) {
		//Remove the original element
		m_lpHEMesh->remove_element(element);

		//find the local table entry to handle this case A
		int entry = m_mapCutEdgeCodeToTableEntry[cutEdgeCode];

		//report
		LogInfoArg3("Detected case is type A: cutEdgeCode: %u, cutNodeCode: %u, entry: %u", cutEdgeCode, cutNodeCode, entry);

		//generate 4 new tets
		for(int e = 0; e < 4; e++) {
			U32 n[4];

			for(int i = 0; i < 4; i++)
				n[i] = vnodes[ g_elementTableCaseA[entry][e * 4 + i] ];

			if(dosplit && e == 0) {
				vec3d pos[4];

				for(int k=0; k < 4; k++)
					pos[k] = m_lpHEMesh->nodeAt(n[k]).pos;

				vec3d centroid = pos[0];
				for(int k=1; k < 4; k++)
					centroid = centroid + pos[k];
				centroid = centroid * 0.25;

				vec3d norm = (pos[0] - centroid).normalized();
				double dist = (pos[0] - centroid).length() * 0.3;

				for(int k = 0; k<4; k++)
					m_lpHEMesh->nodeAt( n[ k ]).pos = pos[k] + norm * dist;

			}

			m_lpHEMesh->insert_element(n);
		}
	}
	//Case B: 4 cut edges. cutEdgeCodes = { 46, 51, 29 }
	else if(ctCutEdges == 4) {
		//Remove the original element
		m_lpHEMesh->remove_element(element);

		//find the local table entry to handle this case B
		int entry = m_mapCutEdgeCodeToTableEntry[cutEdgeCode];

		//report
		LogInfoArg3("Detected case is type B: cutEdgeCode: %u, cutNodeCode: %u, entry: %u", cutEdgeCode, cutNodeCode, entry);

		//generate 6 new tets
		for(int e = 0; e < 6; e++) {

			U32 n[4];
			for(int i = 0; i < 4; i++)
				n[i] = vnodes[ g_elementTableCaseB[entry][e][i] ];

			m_lpHEMesh->insert_element(n);
		}

		if(dosplit) {
			set<U32> splittedNodes1;
			set<U32> splittedNodes2;
			vec3d cent1, cent2;

			//insert nodes for the first 3 tets
			for(int e=0; e<3; e++) {
				for(int i = 0; i < 4; i++) {
					splittedNodes1.insert( vnodes[ g_elementTableCaseB[entry][e][i] ]);
				}
			}

			//insert nodes for the last 3 tets
			for(int e=3; e<6; e++) {
				for(int i = 0; i < 4; i++) {
					splittedNodes2.insert( vnodes[ g_elementTableCaseB[entry][e][i] ]);
				}
			}

			if(splittedNodes1.size() != 6 || splittedNodes2.size() != 6) {
				LogError("Splitted nodes are not sets of 6!");
				return -1;
			}

			vec3d arrP1[6];
			int i = 0;
			for(set<U32>::const_iterator it = splittedNodes1.begin(); it != splittedNodes1.end(); it++) {
				arrP1[i] = m_lpHEMesh->nodeAt( *it ).pos;
				if(i == 0)
					cent1 = arrP1[i];
				else
					cent1 = cent1 + arrP1[i];
				i++;
			}
			cent1 = cent1 * (1.0 / 6.0);

			//second set
			vec3d arrP2[6];
			i = 0;
			for(set<U32>::const_iterator it = splittedNodes2.begin(); it != splittedNodes2.end(); it++) {
				arrP2[i] = m_lpHEMesh->nodeAt( *it ).pos;
				if(i == 0)
					cent2 = arrP2[i];
				else
					cent2 = cent2 + arrP2[i];
				i++;
			}
			cent2 = cent2 * (1.0 / 6.0);

			//compute norm and dist
			vec3d norm = (cent1 - cent2).normalized();
			double dist = (cent1 - cent2).length() * 0.3;

			//splitted nodes
			i = 0;
			for(set<U32>::const_iterator it = splittedNodes1.begin(); it != splittedNodes1.end(); it++) {
				m_lpHEMesh->nodeAt( *it ).pos = arrP1[i] + norm * dist;
				i++;
			}
		}
	}
	else {
		LogErrorArg3("This case is not handled yet! cutEdgeCode = %u, cutNodeCode = %u, ctCutEdges = %u",
					 cutEdgeCode, cutNodeCode, ctCutEdges);
	}

	return cutEdgeCode;
}

void TetSubdivider::draw() {

	if(m_lpHEMesh)
		m_lpHEMesh->draw();
}

}
}

<|endoftext|>


<commit_before>#pragma once

#include "LevelList.hpp"
#include "GridMap.hpp"
#include "../tools/Overlap.hpp"

namespace maps { namespace grid
{

    template <class P>
    class MultiLevelGridMap : public GridMap<LevelList<P> >
    {
    public:
        typedef LevelList<P> CellType;

        MultiLevelGridMap(const Vector2ui &num_cells,
                    const Eigen::Vector2d &resolution,
                    const boost::shared_ptr<LocalMapData> &data) : GridMap<LevelList<P> >(num_cells, resolution, LevelList<P>(), data)
        {}

        MultiLevelGridMap(const Vector2ui &num_cells,
                    const Eigen::Vector2d &resolution) : GridMap<LevelList<P> >(num_cells, resolution, LevelList<P>())
        {}

        MultiLevelGridMap() {}

        class View : public GridMap<LevelList<const P *> >
        {
        public:
            View(const Vector2ui &num_cells,
                const Eigen::Vector2d &resolution) : GridMap<LevelList<const P *> >(num_cells, resolution, LevelList<const P *>())
            {
            };

            View() : GridMap<LevelList<const P *> >()
            {
            };
        };

        View intersectCuboid(const Eigen::AlignedBox3d& box) const
        {
            size_t ignore;
            return intersectCuboid(box, ignore);
        }

        /** @param outNumIntersections contains the number of mls patches that
                                       intersected the @p box*/
        View intersectCuboid(const Eigen::AlignedBox3d& box, size_t& outNumIntersections) const
        {
            double minHeight = box.min().z();
            double maxHeight = box.max().z();
            outNumIntersections = 0;

            Index minIdx;
            Index maxIdx;

            if(!this->toGrid(box.min(), minIdx))
            {
                return View();
            }

            if(!this->toGrid(box.max(), maxIdx))
            {
                return View();
            }

            Index newSize(maxIdx-minIdx);

            View ret(Vector2ui(newSize.x(), newSize.y()) , this->getResolution());

            for(size_t x = minIdx.x();x < maxIdx.x(); x++)
            {
                for(size_t y = minIdx.y(); y < maxIdx.y(); y++)
                {
                    Index curIdx(x,y);

                    LevelList<const P *> &retList(ret.at(Index(curIdx - minIdx)));

                    for(const P &p: this->at(curIdx))
                    {
                        if(::maps::tools::overlap(p.getMin(), p.getMax(), minHeight, maxHeight))
                        {
                            retList.insert(&p);
                            ++outNumIntersections;
                        }
                    }
                }
            }

            return ret;
        }

    };

}}
<commit_msg>Added intersectAABB()<commit_after>#pragma once

#include "LevelList.hpp"
#include "GridMap.hpp"
#include "../tools/Overlap.hpp"

namespace maps { namespace grid
{

    template <class P>
    class MultiLevelGridMap : public GridMap<LevelList<P> >
    {
    public:
        typedef LevelList<P> CellType;

        MultiLevelGridMap(const Vector2ui &num_cells,
                    const Eigen::Vector2d &resolution,
                    const boost::shared_ptr<LocalMapData> &data) : GridMap<LevelList<P> >(num_cells, resolution, LevelList<P>(), data)
        {}

        MultiLevelGridMap(const Vector2ui &num_cells,
                    const Eigen::Vector2d &resolution) : GridMap<LevelList<P> >(num_cells, resolution, LevelList<P>())
        {}

        MultiLevelGridMap() {}

        class View : public GridMap<LevelList<const P *> >
        {
        public:
            View(const Vector2ui &num_cells,
                const Eigen::Vector2d &resolution) : GridMap<LevelList<const P *> >(num_cells, resolution, LevelList<const P *>())
            {
            };

            View() : GridMap<LevelList<const P *> >()
            {
            };
        };

        View intersectCuboid(const Eigen::AlignedBox3d& box) const
        {
            size_t ignore;
            return intersectCuboid(box, ignore);
        }

        /** Intersects @p box with the mls map.
         * @return A list of patches and their grid indices that intersect the @p box.
         * @throw std::runtime_error if any part of @p box is outside the grid*/
        std::vector<std::pair<Index, const P*>> intersectAABB(const Eigen::AlignedBox3d& box) const
        {
            std::vector<std::pair<Index, const P*>> ret;
            double minHeight = box.min().z();
            double maxHeight = box.max().z();

            Index minIdx;
            Index maxIdx;

            if(!this->toGrid(box.min(), minIdx) || !this->toGrid(box.max(), maxIdx))
            {
                throw std::runtime_error("box outside map");
            }

            for(size_t x = minIdx.x();x < maxIdx.x(); x++)
            {
                for(size_t y = minIdx.y(); y < maxIdx.y(); y++)
                {
                    const Index curIdx(x,y);
                    for(const P &p: this->at(curIdx))
                    {
                        if(::maps::tools::overlap(p.getMin(), p.getMax(), minHeight, maxHeight))
                        {
                            ret.emplace_back(curIdx, &p);
                        }
                    }
                }
            }
            return ret;
        }

        /** @param outNumIntersections contains the number of mls patches that
                                       intersected the @p box*/
        View intersectCuboid(const Eigen::AlignedBox3d& box, size_t& outNumIntersections) const
        {
            double minHeight = box.min().z();
            double maxHeight = box.max().z();
            outNumIntersections = 0;

            Index minIdx;
            Index maxIdx;

            if(!this->toGrid(box.min(), minIdx))
            {
                return View();
            }

            if(!this->toGrid(box.max(), maxIdx))
            {
                return View();
            }

            Index newSize(maxIdx-minIdx);

            View ret(Vector2ui(newSize.x(), newSize.y()) , this->getResolution());

            for(size_t x = minIdx.x();x < maxIdx.x(); x++)
            {
                for(size_t y = minIdx.y(); y < maxIdx.y(); y++)
                {
                    Index curIdx(x,y);

                    LevelList<const P *> &retList(ret.at(Index(curIdx - minIdx)));

                    for(const P &p: this->at(curIdx))
                    {
                        if(::maps::tools::overlap(p.getMin(), p.getMax(), minHeight, maxHeight))
                        {
                            retList.insert(&p);
                            ++outNumIntersections;
                        }
                    }
                }
            }

            return ret;
        }

    };

}}
<|endoftext|>