<commit_before>/*
* AscEmu Framework based on Arcemu MMORPG Server
* Copyright (C) 2014-2016 AscEmu Team <http://www.ascemu.org>
* Copyright (C) 2009-2012 ArcEmu Team <http://www.arcemu.org>
* Copyright (C) 2008-2009 Sun++ Team <http://www.sunplusplus.info>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program 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, see <http://www.gnu.org/licenses/>.
*/

#include "Setup.h"

class GossipScourgeGryphon : public GossipScript
{
    public:
        void GossipHello(Object* pObject, Player* plr)
        {
            if (plr->HasQuest(12670) || plr->HasFinishedQuest(12670))
            {
                if (TaxiPath* path = sTaxiMgr.GetTaxiPath(pObject->GetEntry() == 29488 ? 1053 : 1054))
                    plr->TaxiStart(path, 26308, 0);
            }
        }
};

#define CN_INITIATE_1                29519
#define CN_INITIATE_2                29565
#define CN_INITIATE_3                29567
#define CN_INITIATE_4                29520

class AcherusSoulPrison : GameObjectAIScript
{
    public:
        AcherusSoulPrison(GameObject* goinstance) : GameObjectAIScript(goinstance) {}
        static GameObjectAIScript* Create(GameObject* GO)
        {
            return new AcherusSoulPrison(GO);
        }

        void OnActivate(Player* pPlayer)
        {
            QuestLogEntry* en = pPlayer->GetQuestLogForEntry(12848);
            if(!en)
                return;

            float SSX = pPlayer->GetPositionX();
            float SSY = pPlayer->GetPositionY();
            float SSZ = pPlayer->GetPositionZ();

            Creature* pCreature = pPlayer->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(SSX, SSY, SSZ);

            if(!pCreature || !pCreature->isAlive())
                return;

            if(pCreature->GetEntry() == CN_INITIATE_1 || pCreature->GetEntry() == CN_INITIATE_2 || pCreature->GetEntry() == CN_INITIATE_3 || pCreature->GetEntry() == CN_INITIATE_4)
            {
                pPlayer->SendChatMessage(CHAT_MSG_SAY, LANG_UNIVERSAL, "I give you the key to your salvation");
                pCreature->SetUInt64Value(UNIT_FIELD_FLAGS, 0);
                pCreature->GetAIInterface()->setNextTarget(pPlayer);
                pCreature->GetAIInterface()->AttackReaction(pPlayer, 1, 0);
                pCreature->SendChatMessage(CHAT_MSG_MONSTER_SAY, LANG_UNIVERSAL, "You have committed a big mistake, demon");

                if(en->GetMobCount(0) != 0)
                    return;

                en->SetMobCount(0, 1);
                en->SendUpdateAddKill(0);
                en->UpdatePlayerFields();
            }

        }
};

class QuestInServiceOfLichKing : public QuestScript
{
    public:
        void OnQuestStart(Player* mTarget, QuestLogEntry* /*qLogEntry*/)
        {
            // Play first sound
            mTarget->PlaySound(14734);

            // Play second sound after 22.5 seconds
            sEventMgr.AddEvent(mTarget, &Player::PlaySound, (uint32)14735, EVENT_UNK, 22500, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);

            // Play third sound after 48.5 seconds
            sEventMgr.AddEvent(mTarget, &Player::PlaySound, (uint32)14736, EVENT_UNK, 48500, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
        }
};

// QuestID for Praparation for the Battle
enum QUEST_12842_ENUM
{
    QUEST_PREPARATION                   = 12842,

    SPELL_RUNE_I                        = 53341, // Spell Rune of Cinderglacier
    SPELL_RUNE_II                       = 53343, // Spell Rune of Razorice
    SPELL_PREPERATION_FOR_BATTLE_CREDIT = 54586
};

bool PreparationForBattleEffect(uint32 effectIndex, Spell* pSpell)
{
    Player* pCaster = pSpell->p_caster;
    if (pCaster == nullptr)
        return false;

    // Apply spell if caster has quest and still heven't completed it yet
    if (pCaster->HasQuest(QUEST_PREPARATION) && !pCaster->HasFinishedQuest(QUEST_PREPARATION))
        pCaster->CastSpell(pCaster, SPELL_PREPERATION_FOR_BATTLE_CREDIT, true);

    return true;
}

void SetupDeathKnight(ScriptMgr* mgr)
{
    mgr->register_gossip_script(29488, new GossipScourgeGryphon);
    mgr->register_gossip_script(29501, new GossipScourgeGryphon);

    mgr->register_dummy_spell(SPELL_RUNE_I, &PreparationForBattleEffect);
    mgr->register_dummy_spell(SPELL_RUNE_II, &PreparationForBattleEffect);
    mgr->register_quest_script(12593, new QuestInServiceOfLichKing);

    // These gobs had already a script by Type (in gameobject_names Type = 1 = Button).
    mgr->register_gameobject_script(191588, &AcherusSoulPrison::Create);
    mgr->register_gameobject_script(191577, &AcherusSoulPrison::Create);
    mgr->register_gameobject_script(191580, &AcherusSoulPrison::Create);
    mgr->register_gameobject_script(191581, &AcherusSoulPrison::Create);
    mgr->register_gameobject_script(191582, &AcherusSoulPrison::Create);
    mgr->register_gameobject_script(191583, &AcherusSoulPrison::Create);
    mgr->register_gameobject_script(191584, &AcherusSoulPrison::Create);
    mgr->register_gameobject_script(191585, &AcherusSoulPrison::Create);
    mgr->register_gameobject_script(191586, &AcherusSoulPrison::Create);
    mgr->register_gameobject_script(191587, &AcherusSoulPrison::Create);
    mgr->register_gameobject_script(191589, &AcherusSoulPrison::Create);
    mgr->register_gameobject_script(191590, &AcherusSoulPrison::Create);

}
<commit_msg>Style changes for Quest_DeathKnight.cpp<commit_after>/*
* AscEmu Framework based on Arcemu MMORPG Server
* Copyright (C) 2014-2016 AscEmu Team <http://www.ascemu.org>
* Copyright (C) 2009-2012 ArcEmu Team <http://www.arcemu.org>
* Copyright (C) 2008-2009 Sun++ Team <http://www.sunplusplus.info>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program 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, see <http://www.gnu.org/licenses/>.
*/

#include "Setup.h"

class GossipScourgeGryphon : public GossipScript
{
    public:

        void GossipHello(Object* pObject, Player* plr)
        {
            if (plr->HasQuest(12670) || plr->HasFinishedQuest(12670))
            {
                if (TaxiPath* path = sTaxiMgr.GetTaxiPath(pObject->GetEntry() == 29488 ? 1053 : 1054))
                    plr->TaxiStart(path, 26308, 0);
            }
        }
};

#define CN_INITIATE_1                29519
#define CN_INITIATE_2                29565
#define CN_INITIATE_3                29567
#define CN_INITIATE_4                29520

class AcherusSoulPrison : GameObjectAIScript
{
    public:

        AcherusSoulPrison(GameObject* goinstance) : GameObjectAIScript(goinstance) {}
        static GameObjectAIScript* Create(GameObject* GO)
        {
            return new AcherusSoulPrison(GO);
        }

        void OnActivate(Player* pPlayer)
        {
            QuestLogEntry* en = pPlayer->GetQuestLogForEntry(12848);
            if (!en)
                return;

            float SSX = pPlayer->GetPositionX();
            float SSY = pPlayer->GetPositionY();
            float SSZ = pPlayer->GetPositionZ();

            Creature* pCreature = pPlayer->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(SSX, SSY, SSZ);

            if (!pCreature || !pCreature->isAlive())
                return;

            if (pCreature->GetEntry() == CN_INITIATE_1 || pCreature->GetEntry() == CN_INITIATE_2 || pCreature->GetEntry() == CN_INITIATE_3 || pCreature->GetEntry() == CN_INITIATE_4)
            {
                pPlayer->SendChatMessage(CHAT_MSG_SAY, LANG_UNIVERSAL, "I give you the key to your salvation");
                pCreature->SetUInt64Value(UNIT_FIELD_FLAGS, 0);
                pCreature->GetAIInterface()->setNextTarget(pPlayer);
                pCreature->GetAIInterface()->AttackReaction(pPlayer, 1, 0);
                pCreature->SendChatMessage(CHAT_MSG_MONSTER_SAY, LANG_UNIVERSAL, "You have committed a big mistake, demon");

                if (en->GetMobCount(0) != 0)
                    return;

                en->SetMobCount(0, 1);
                en->SendUpdateAddKill(0);
                en->UpdatePlayerFields();
            }

        }
};

class QuestInServiceOfLichKing : public QuestScript
{
    public:

        void OnQuestStart(Player* mTarget, QuestLogEntry* /*qLogEntry*/)
        {
            // Play first sound
            mTarget->PlaySound(14734);

            // Play second sound after 22.5 seconds
            sEventMgr.AddEvent(mTarget, &Player::PlaySound, (uint32)14735, EVENT_UNK, 22500, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);

            // Play third sound after 48.5 seconds
            sEventMgr.AddEvent(mTarget, &Player::PlaySound, (uint32)14736, EVENT_UNK, 48500, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
        }
};

// QuestID for Praparation for the Battle
enum QUEST_12842_ENUM
{
    QUEST_PREPARATION = 12842,

    SPELL_RUNE_I = 53341, // Spell Rune of Cinderglacier
    SPELL_RUNE_II = 53343, // Spell Rune of Razorice
    SPELL_PREPERATION_FOR_BATTLE_CREDIT = 54586
};

bool PreparationForBattleEffect(uint32 effectIndex, Spell* pSpell)
{
    Player* pCaster = pSpell->p_caster;
    if (pCaster == nullptr)
        return false;

    // Apply spell if caster has quest and still heven't completed it yet
    if (pCaster->HasQuest(QUEST_PREPARATION) && !pCaster->HasFinishedQuest(QUEST_PREPARATION))
        pCaster->CastSpell(pCaster, SPELL_PREPERATION_FOR_BATTLE_CREDIT, true);

    return true;
}

void SetupDeathKnight(ScriptMgr* mgr)
{
    mgr->register_gossip_script(29488, new GossipScourgeGryphon);
    mgr->register_gossip_script(29501, new GossipScourgeGryphon);

    mgr->register_dummy_spell(SPELL_RUNE_I, &PreparationForBattleEffect);
    mgr->register_dummy_spell(SPELL_RUNE_II, &PreparationForBattleEffect);
    mgr->register_quest_script(12593, new QuestInServiceOfLichKing);

    mgr->register_gameobject_script(191588, &AcherusSoulPrison::Create);
    mgr->register_gameobject_script(191577, &AcherusSoulPrison::Create);
    mgr->register_gameobject_script(191580, &AcherusSoulPrison::Create);
    mgr->register_gameobject_script(191581, &AcherusSoulPrison::Create);
    mgr->register_gameobject_script(191582, &AcherusSoulPrison::Create);
    mgr->register_gameobject_script(191583, &AcherusSoulPrison::Create);
    mgr->register_gameobject_script(191584, &AcherusSoulPrison::Create);
    mgr->register_gameobject_script(191585, &AcherusSoulPrison::Create);
    mgr->register_gameobject_script(191586, &AcherusSoulPrison::Create);
    mgr->register_gameobject_script(191587, &AcherusSoulPrison::Create);
    mgr->register_gameobject_script(191589, &AcherusSoulPrison::Create);
    mgr->register_gameobject_script(191590, &AcherusSoulPrison::Create);
}
<|endoftext|>


<commit_before>// Copyright 2013-2015, Durachenko Aleksey V. <durachenko.aleksey@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
#include "qsesppselectionplot.h"
#include <QPainter>
#include "qseselection.h"

QseSppSelectionPlot::QseSppSelectionPlot(QObject *parent)
    : QseAbstractSppPlot(parent)
{
    m_brush = Qt::blue;
    m_opacity = 0.5;
    m_selection = 0;
}

void QseSppSelectionPlot::setBrush(const QBrush &brush)
{
    if (m_brush != brush)
    {
        m_brush = brush;
        setUpdateOnce(true);
    }
}

void QseSppSelectionPlot::setOpacity(qreal opacity)
{
    if (m_opacity != opacity)
    {
        m_opacity = opacity;
        setUpdateOnce(true);
    }
}

void QseSppSelectionPlot::setSelection(QseSelection *selection)
{
    if (m_selection)
        disconnect(m_selection, 0, this, 0);

    m_selection = selection;
    if (m_selection)
    {
        connect(m_selection, SIGNAL(selectionChanged()),
                this, SLOT(setUpdateOnce()));
        connect(m_selection, SIGNAL(destroyed(QObject*)),
                this, SLOT(selection_destroyed(QObject*)));
    }

    setUpdateOnce(true);
}

bool QseSppSelectionPlot::hasChanges(const QRect &rect,
        const QseSppGeometry &geometry)
{
    return (isUpdateOnce() || rect != lastRect() || geometry != lastGeometry());
}

bool QseSppSelectionPlot::isVisible(const QRect &rect,
        const QseSppGeometry &geometry)
{
    if (m_selection == 0)
        return false;

    if (m_selection->isNull())
        return false;

    // TODO: fix algorithm, because it can cause the overflow
    int sl = QseSppGeometry::calcOffset(geometry,
                m_selection->selectedRange().first());
    int sr = QseSppGeometry::calcOffset(geometry,
                m_selection->selectedRange().last());

    if ((sl < 0 && sr < 0) || (sl >= rect.width() && sr >= rect.width()))
        return false;

    return true;
}

void QseSppSelectionPlot::draw(QPainter *painter, const QRect &rect,
        const QseSppGeometry &geometry)
{
    if (isVisible(rect, geometry))
    {
        // TODO: fix algorithm, because it can cause the overflow
        int sl = QseSppGeometry::calcOffset(geometry,
                    m_selection->selectedRange().first());
        int sr = QseSppGeometry::calcOffset(geometry,
                    m_selection->selectedRange().last());

        if (sl < 0)
            sl = 0;
        if (sr >= rect.width())
            sr = rect.width()-1;

        painter->save();
        painter->setOpacity(m_opacity);
        painter->fillRect(sl, 0, sr-sl+1, rect.height(), m_brush);
        painter->restore();
    }

    QseAbstractSppPlot::draw(painter, rect, geometry);
}

void QseSppSelectionPlot::selection_destroyed(QObject *obj)
{
    if (obj == m_selection)
        m_selection = 0;
}
<commit_msg>fix integer overflow possibility<commit_after>// Copyright 2013-2015, Durachenko Aleksey V. <durachenko.aleksey@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
#include "qsesppselectionplot.h"
#include <QPainter>
#include "qseselection.h"

QseSppSelectionPlot::QseSppSelectionPlot(QObject *parent)
    : QseAbstractSppPlot(parent)
{
    m_brush = Qt::blue;
    m_opacity = 0.5;
    m_selection = 0;
}

void QseSppSelectionPlot::setBrush(const QBrush &brush)
{
    if (m_brush != brush)
    {
        m_brush = brush;
        setUpdateOnce(true);
    }
}

void QseSppSelectionPlot::setOpacity(qreal opacity)
{
    if (m_opacity != opacity)
    {
        m_opacity = opacity;
        setUpdateOnce(true);
    }
}

void QseSppSelectionPlot::setSelection(QseSelection *selection)
{
    if (m_selection)
        disconnect(m_selection, 0, this, 0);

    m_selection = selection;
    if (m_selection)
    {
        connect(m_selection, SIGNAL(selectionChanged()),
                this, SLOT(setUpdateOnce()));
        connect(m_selection, SIGNAL(destroyed(QObject*)),
                this, SLOT(selection_destroyed(QObject*)));
    }

    setUpdateOnce(true);
}

bool QseSppSelectionPlot::hasChanges(const QRect &rect,
        const QseSppGeometry &geometry)
{
    return (isUpdateOnce() || rect != lastRect() || geometry != lastGeometry());
}

bool QseSppSelectionPlot::isVisible(const QRect &rect,
        const QseSppGeometry &geometry)
{
    if (m_selection == 0)
        return false;

    if (m_selection->isNull())
        return false;

    const qint64 firstVisibleSample = geometry.x();
    const qint64 lastVisibleSample = firstVisibleSample
            + QseSppGeometry::samplesFromWidth(geometry, rect.width());

    if (m_selection->selectedRange().first() >= lastVisibleSample)
        return false;

    if (m_selection->selectedRange().last() <= firstVisibleSample)
        return false;

    return true;
}

void QseSppSelectionPlot::draw(QPainter *painter, const QRect &rect,
        const QseSppGeometry &geometry)
{
    if (isVisible(rect, geometry))
    {
        const qint64 firstVisibleSample = geometry.x();
        const qint64 lastVisibleSample =
                QseSppGeometry::calcSampleIndex(geometry, rect.width());

        int sl = 0;
        if (m_selection->selectedRange().first() > firstVisibleSample)
            sl = QseSppGeometry::calcOffset(geometry,
                    m_selection->selectedRange().first());

        int sr = rect.width()-1;
        if (m_selection->selectedRange().last() <= lastVisibleSample)
            sr = QseSppGeometry::calcOffset(geometry,
                    m_selection->selectedRange().last());

        painter->save();
        painter->setOpacity(m_opacity);
        painter->fillRect(sl, 0, sr-sl+1, rect.height(), m_brush);
        painter->restore();
    }

    QseAbstractSppPlot::draw(painter, rect, geometry);
}

void QseSppSelectionPlot::selection_destroyed(QObject *obj)
{
    if (obj == m_selection)
        m_selection = 0;
}
<|endoftext|>


<commit_before>
#include <iostream>
#include <memory>
#include <SDL.h>
#include <images.h>
#include <SOIL.h>
#include <res_path.h>

namespace venk
{

    std::shared_ptr<Image> image_load(const std::string& fileName)
    {
		auto image_deleter = [](Image *i) {
			if (i) {
				SOIL_free_image_data(i->pixels);
				delete i;
			}
		};
		std::shared_ptr<Image> img(new Image, image_deleter);
		SDL_RWops *rwops = SDL_RWFromFile(fileName.c_str(), "rb");
		if (rwops != nullptr) {
			Sint64 size = SDL_RWsize(rwops);
			if (size != -1L) {
				void *buf = SDL_malloc(size);
				size_t read = SDL_RWread(rwops, buf, 1, size);
				if (read == size) {
					img->pixels = SOIL_load_image_from_memory((const unsigned char*)buf, size, &img->width, &img->height, &img->channels, SOIL_LOAD_AUTO);
					if (img->pixels != nullptr) {
						SDL_RWclose(rwops);
						return img;
					} else {
						std::cerr << "Creating " << fileName << " failed" << std::endl;
					}
				} else {
					std::cerr << "Reading " << fileName << " failed" << std::endl;
				}
				SDL_free(buf);
			} else {
				std::cerr << "Probing " << fileName << " failed" << std::endl;
			}
		} else {
			std::cerr << "Opening " << fileName << " failed" << std::endl;
		}
		SDL_RWclose(rwops);
		return nullptr;
    }

    std::shared_ptr<SDL_Surface> surface_from_image(std::shared_ptr<Image> img)
    {

#if SDL_BYTEORDER == SDL_BIG_ENDIAN
		Uint32 rmask = 0xff000000;
		Uint32 gmask = 0x00ff0000;
		Uint32 bmask = 0x0000ff00;
		Uint32 amask = 0x000000ff;
#else
		Uint32 rmask = 0x000000ff;
		Uint32 gmask = 0x0000ff00;
		Uint32 bmask = 0x00ff0000;
		Uint32 amask = 0xff000000;
#endif

		auto surface_deleter = [](SDL_Surface* s) {
			if(s) SDL_FreeSurface(s);
		};
		std::shared_ptr<SDL_Surface> result(SDL_CreateRGBSurfaceFrom(img->pixels, img->width, img->height, img->channels * 8, img->width * img->channels, rmask, gmask, bmask, amask ),
											surface_deleter);
		SDL_SetSurfaceBlendMode(result.get(), SDL_BLENDMODE_NONE);
		return result;
    }

}
<commit_msg>Begining of font wrapper class.<commit_after>
#include <iostream>
#include <memory>
#include <SDL.h>
#include <SOIL.h>
#include <images.h>
#include <res_path.h>

namespace venk
{

    std::shared_ptr<Image> image_load(const std::string& fileName)
    {
		auto image_deleter = [](Image *i) {
			if (i) {
				SOIL_free_image_data(i->pixels);
				delete i;
			}
		};
		std::shared_ptr<Image> img(new Image, image_deleter);
		SDL_RWops *rwops = SDL_RWFromFile(fileName.c_str(), "rb");
		if (rwops != nullptr) {
			Sint64 size = SDL_RWsize(rwops);
			if (size != -1L) {
				void *buf = SDL_malloc(size);
				size_t read = SDL_RWread(rwops, buf, 1, size);
				if (read == size) {
					img->pixels = SOIL_load_image_from_memory((const unsigned char*)buf, size, &img->width, &img->height, &img->channels, SOIL_LOAD_AUTO);
					if (img->pixels != nullptr) {
						SDL_RWclose(rwops);
						return img;
					} else {
						std::cerr << "Creating " << fileName << " failed" << std::endl;
					}
				} else {
					std::cerr << "Reading " << fileName << " failed" << std::endl;
				}
				SDL_free(buf);
			} else {
				std::cerr << "Probing " << fileName << " failed" << std::endl;
			}
		} else {
			std::cerr << "Opening " << fileName << " failed" << std::endl;
		}
		SDL_RWclose(rwops);
		return nullptr;
    }

    std::shared_ptr<SDL_Surface> surface_from_image(std::shared_ptr<Image> img)
    {

#if SDL_BYTEORDER == SDL_BIG_ENDIAN
		Uint32 rmask = 0xff000000;
		Uint32 gmask = 0x00ff0000;
		Uint32 bmask = 0x0000ff00;
		Uint32 amask = 0x000000ff;
#else
		Uint32 rmask = 0x000000ff;
		Uint32 gmask = 0x0000ff00;
		Uint32 bmask = 0x00ff0000;
		Uint32 amask = 0xff000000;
#endif

		auto surface_deleter = [](SDL_Surface* s) {
			if(s) SDL_FreeSurface(s);
		};
		std::shared_ptr<SDL_Surface> result(SDL_CreateRGBSurfaceFrom(img->pixels, img->width, img->height, img->channels * 8, img->width * img->channels, rmask, gmask, bmask, amask ),
											surface_deleter);
		SDL_SetSurfaceBlendMode(result.get(), SDL_BLENDMODE_NONE);
		return result;
    }

}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: groupproperties.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: ihi $ $Date: 2006-11-14 13:11:07 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _SDR_PROPERTIES_GROUPPROPERTIES_HXX
#define _SDR_PROPERTIES_GROUPPROPERTIES_HXX

#ifndef _SDR_PROPERTIES_DEFAULTPROPERTIES_HXX
#include <svx/sdr/properties/defaultproperties.hxx>
#endif

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

namespace sdr
{
    namespace properties
    {
        class GroupProperties : public DefaultProperties
        {
        protected:
            // create a new itemset
            virtual SfxItemSet& CreateObjectSpecificItemSet(SfxItemPool& rPool);

            // test changeability for a single item
            virtual sal_Bool AllowItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem = 0) const;

            // Do the ItemChange, may do special handling
            virtual void ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem = 0);

            // Called after ItemChange() is done for all items.
            virtual void PostItemChange(const sal_uInt16 nWhich);

            // react on ItemSet changes
            virtual void ItemSetChanged(const SfxItemSet& rSet);

        public:
            // basic constructor
            GroupProperties(SdrObject& rObj);

            // copy constructor
            GroupProperties(const GroupProperties& rProps, SdrObject& rObj);

            // destructor
            virtual ~GroupProperties();

            // Clone() operator, normally just calls the local copy constructor
            virtual BaseProperties& Clone(SdrObject& rObj) const;

            // get itemset
            virtual const SfxItemSet& GetObjectItemSet() const;

            // get merged ItemSet. Normally, this maps directly to GetObjectItemSet(), but may
            // be overloaded e.g for group objects to return a merged ItemSet of the object.
            // When using this method the returned ItemSet may contain items in the state
            // SFX_ITEM_DONTCARE which means there were several such items with different
            // values.
            virtual const SfxItemSet& GetMergedItemSet() const;

            // Set merged ItemSet. Normally, this maps to SetObjectItemSet().
            virtual void SetMergedItemSet(const SfxItemSet& rSet, sal_Bool bClearAllItems = sal_False);

            // set single item
            virtual void SetObjectItem(const SfxPoolItem& rItem);

            // set single item direct, do not do any notifies or things like that
            virtual void SetObjectItemDirect(const SfxPoolItem& rItem);

            // clear single item
            virtual void ClearObjectItem(const sal_uInt16 nWhich = 0);

            // clear single item direct, do not do any notifies or things like that.
            // Also supports complete deleteion of items when default parameter 0 is used.
            virtual void ClearObjectItemDirect(const sal_uInt16 nWhich = 0);

            // Set a single item, iterate over hierarchies if necessary.
            virtual void SetMergedItem(const SfxPoolItem& rItem);

            // Clear a single item, iterate over hierarchies if necessary.
            virtual void ClearMergedItem(const sal_uInt16 nWhich = 0);

            // set complete item set
            virtual void SetObjectItemSet(const SfxItemSet& rSet);

            // set a new StyleSheet
            virtual void SetStyleSheet(SfxStyleSheet* pNewStyleSheet, sal_Bool bDontRemoveHardAttr);

            // get the local StyleSheet
            virtual SfxStyleSheet* GetStyleSheet() const;

            // force default attributes for a specific object type, called from
            // DefaultProperties::GetObjectItemSet() if a new ItemSet is created
            virtual void ForceDefaultAttributes();

            // Move properties to a new ItemPool.
            virtual void MoveToItemPool(SfxItemPool* pSrcPool, SfxItemPool* pDestPool, SdrModel* pNewModel = 0L);

            // force all attributes which come from styles to hard attributes
            // to be able to live without the style.
            virtual void ForceStyleToHardAttributes(sal_Bool bPseudoSheetsOnly = sal_False);
        };
    } // end of namespace properties
} // end of namespace sdr

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

#endif //_SDR_PROPERTIES_GROUPPROPERTIES_HXX

// eof
<commit_msg>INTEGRATION: CWS aw036 (1.4.594); FILE MERGED 2006/10/26 15:57:01 aw 1.4.594.1: #i61284#: BurnInStyleSheetAttributes for text corrected; #i70852#: Set/GetLayer cleanup and implementation for FmFormObj<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: groupproperties.hxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: vg $ $Date: 2006-11-21 16:43:17 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _SDR_PROPERTIES_GROUPPROPERTIES_HXX
#define _SDR_PROPERTIES_GROUPPROPERTIES_HXX

#ifndef _SDR_PROPERTIES_DEFAULTPROPERTIES_HXX
#include <svx/sdr/properties/defaultproperties.hxx>
#endif

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

namespace sdr
{
    namespace properties
    {
        class GroupProperties : public DefaultProperties
        {
        protected:
            // create a new itemset
            virtual SfxItemSet& CreateObjectSpecificItemSet(SfxItemPool& rPool);

            // test changeability for a single item
            virtual sal_Bool AllowItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem = 0) const;

            // Do the ItemChange, may do special handling
            virtual void ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem = 0);

            // Called after ItemChange() is done for all items.
            virtual void PostItemChange(const sal_uInt16 nWhich);

            // react on ItemSet changes
            virtual void ItemSetChanged(const SfxItemSet& rSet);

        public:
            // basic constructor
            GroupProperties(SdrObject& rObj);

            // copy constructor
            GroupProperties(const GroupProperties& rProps, SdrObject& rObj);

            // destructor
            virtual ~GroupProperties();

            // Clone() operator, normally just calls the local copy constructor
            virtual BaseProperties& Clone(SdrObject& rObj) const;

            // get itemset
            virtual const SfxItemSet& GetObjectItemSet() const;

            // get merged ItemSet. Normally, this maps directly to GetObjectItemSet(), but may
            // be overloaded e.g for group objects to return a merged ItemSet of the object.
            // When using this method the returned ItemSet may contain items in the state
            // SFX_ITEM_DONTCARE which means there were several such items with different
            // values.
            virtual const SfxItemSet& GetMergedItemSet() const;

            // Set merged ItemSet. Normally, this maps to SetObjectItemSet().
            virtual void SetMergedItemSet(const SfxItemSet& rSet, sal_Bool bClearAllItems = sal_False);

            // set single item
            virtual void SetObjectItem(const SfxPoolItem& rItem);

            // set single item direct, do not do any notifies or things like that
            virtual void SetObjectItemDirect(const SfxPoolItem& rItem);

            // clear single item
            virtual void ClearObjectItem(const sal_uInt16 nWhich = 0);

            // clear single item direct, do not do any notifies or things like that.
            // Also supports complete deleteion of items when default parameter 0 is used.
            virtual void ClearObjectItemDirect(const sal_uInt16 nWhich = 0);

            // Set a single item, iterate over hierarchies if necessary.
            virtual void SetMergedItem(const SfxPoolItem& rItem);

            // Clear a single item, iterate over hierarchies if necessary.
            virtual void ClearMergedItem(const sal_uInt16 nWhich = 0);

            // set complete item set
            virtual void SetObjectItemSet(const SfxItemSet& rSet);

            // set a new StyleSheet
            virtual void SetStyleSheet(SfxStyleSheet* pNewStyleSheet, sal_Bool bDontRemoveHardAttr);

            // get the local StyleSheet
            virtual SfxStyleSheet* GetStyleSheet() const;

            // force default attributes for a specific object type, called from
            // DefaultProperties::GetObjectItemSet() if a new ItemSet is created
            virtual void ForceDefaultAttributes();

            // Move properties to a new ItemPool.
            virtual void MoveToItemPool(SfxItemPool* pSrcPool, SfxItemPool* pDestPool, SdrModel* pNewModel = 0L);

            // force all attributes which come from styles to hard attributes
            // to be able to live without the style.
            virtual void ForceStyleToHardAttributes();
        };
    } // end of namespace properties
} // end of namespace sdr

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

#endif //_SDR_PROPERTIES_GROUPPROPERTIES_HXX

// eof
<|endoftext|>


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

#include <cstring>
#include <fstream>

#include "misc/size.hpp"
#include "logger.h"

namespace fuzzyrat {

static const char *levelStrTable[] = {
#define GEN_STR(E) #E,
        EACH_LOG_LEVEL(GEN_STR)
#undef GEN_STR
};

static LogLevel parseLevel(const char *str, LogLevel defaultLevel) {
    if(str != nullptr) {
        unsigned int index = 0;
        for(; index < ydsh::arraySize(levelStrTable); index++) {
            if(strcasecmp(str, levelStrTable[index]) == 0) {
                return static_cast<LogLevel>(index);
            }
        }
    }
    return defaultLevel;
}

std::ostream &operator<<(std::ostream &stream, LogLevel level) {
    return stream << "[" << levelStrTable[static_cast<unsigned int>(level)] << "]";
}

// ####################
// ##     Logger     ##
// ####################

Logger::Logger() : stream_(nullptr), level_(LogLevel::info) {
    // init appender
    const char *appender = getenv("FRAT_APPENDER");
    if(appender != nullptr) {
        std::ostream *os = new std::ofstream(appender);
        if(!(*os)) {
            delete os;
            os = nullptr;
        }
        this->stream_ = os;
    }
    if(this->stream_ == nullptr) {
        this->stream_ = &std::cerr;
    }

    // log level
    this->level_ = parseLevel(getenv("FRAT_LEVEL"), LogLevel::info);
}

Logger::~Logger() {
    if(this->stream_ != &std::cerr) {
        delete this->stream_;
    }
}

Logger &Logger::instance() {
    static Logger logger;
    return logger;
}

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

#include <cstring>
#include <fstream>

#include "misc/size.hpp"
#include "logger.h"

namespace fuzzyrat {

static const char *levelStrTable[] = {
#define GEN_STR(E) #E,
        EACH_LOG_LEVEL(GEN_STR)
#undef GEN_STR
};

static LogLevel parseLevel(const char *str, LogLevel defaultLevel) {
    if(str != nullptr) {
        unsigned int index = 0;
        for(; index < ydsh::arraySize(levelStrTable); index++) {
            if(strcasecmp(str, levelStrTable[index]) == 0) {
                return static_cast<LogLevel>(index);
            }
        }
    }
    return defaultLevel;
}

std::ostream &operator<<(std::ostream &stream, LogLevel level) {
    return stream << "[" << levelStrTable[static_cast<unsigned int>(level)] << "]";
}

// ####################
// ##     Logger     ##
// ####################

Logger::Logger() : stream_(nullptr), level_(LogLevel::info) {
    // init appender
    const char *appender = getenv("FRAT_APPENDER");
    if(appender != nullptr) {
        std::ostream *os = new std::ofstream(appender);
        if(!(*os)) {
            delete os;
            os = nullptr;
        }
        this->stream_ = os;
    }
    if(this->stream_ == nullptr) {
        this->stream_ = &std::cerr;
    }

    // log level
    this->level_ = parseLevel(getenv("FRAT_LEVEL"), LogLevel::error);
}

Logger::~Logger() {
    if(this->stream_ != &std::cerr) {
        delete this->stream_;
    }
}

Logger &Logger::instance() {
    static Logger logger;
    return logger;
}

} // namespace fuzzyrat<|endoftext|>


<commit_before>/*
Copyright (c) 2016 Carl Sherrell

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

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

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

#include "mlutil.h"
#include <sys/stat.h>
#include <dirent.h>

namespace puml {

const ml_string &TREE_MODEL_FILE_PREFIX = "tree";

bool prepareDirectoryForModelSave(const ml_string &path_to_dir,
				  bool overwrite_existing) {

  if((path_to_dir == ".") || (path_to_dir == "..")) {
    return(false);
  }

  // clear the directory if it already exists and we are allowed to overwrite.
  struct stat info;
  if((stat(path_to_dir.c_str(), &info) == 0) && (info.st_mode & S_IFDIR)) {

    if(!overwrite_existing) {
      log_error("directory exists and we aren't allowed to overwrite\n");
      return(false);
    }

    ml_string rm_cmd = ml_string("rm -f ") + path_to_dir + "/*.json";
    if(system(rm_cmd.c_str())){
      log_error("couldn't clear model files from directory: %s\n", path_to_dir.c_str());
      return(false);
    }
  }
  else {
    // the directory doesn't exist so we will create it.
    if(mkdir(path_to_dir.c_str(), 0755)) {
      log_error("couldn't create model save directory: %s\n", path_to_dir.c_str());
      perror("ERROR --> mkdir");
      return(false);
    }
  }

  return(true);
}

bool readDecisionTreesFromDirectory(const ml_string &path_to_dir,
				    ml_vector<dt_tree> &trees) {
  trees.clear();

  DIR *d = 0;
  struct dirent *dir = 0;
  d = opendir(path_to_dir.c_str());
  if(!d) {
    return(false);
  }

  while((dir = readdir(d)) != NULL) {
    ml_string file_name(dir->d_name);
    if(file_name.compare(0, TREE_MODEL_FILE_PREFIX.length(),
			 TREE_MODEL_FILE_PREFIX) != 0) {
      continue;
    }

    ml_string full_path = path_to_dir + "/" + dir->d_name;
    dt_tree tree = {};
    if(!readDecisionTreeFromFile(full_path, tree)) {
      log_error("failed to parse tree from json: %s\n", full_path.c_str());
      return(false);
    }

    trees.push_back(tree);
  }

  closedir(d);

  return(true);
}

} // namespace puml
<commit_msg>mv the previous model save directory instead of removing files<commit_after>/*
Copyright (c) 2016 Carl Sherrell

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

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

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

#include "mlutil.h"
#include <sstream>
#include <sys/stat.h>
#include <dirent.h>

namespace puml {

const ml_string &TREE_MODEL_FILE_PREFIX = "tree";

bool prepareDirectoryForModelSave(const ml_string &path_to_dir,
				  bool overwrite_existing) {

  if((path_to_dir == ".") || (path_to_dir == "..")) {
    return(false);
  }

  // move the directory if it already exists and we are allowed to overwrite.
  struct stat info;
  if((stat(path_to_dir.c_str(), &info) == 0) && (info.st_mode & S_IFDIR)) {

    if(!overwrite_existing) {
      log_error("directory exists and we aren't allowed to overwrite\n");
      return(false);
    }

    std::time_t timestamp = std::time(0);
    std::ostringstream ss;
    ss << "mv " << path_to_dir << " " << path_to_dir << "." << timestamp;
    if(system(ss.str().c_str())){
      log_error("couldn't replace previous model directory: %s\n", path_to_dir.c_str());
      return(false);
    }
  }

  // create the model save directory
  if(mkdir(path_to_dir.c_str(), 0755)) {
    log_error("couldn't create model save directory: %s\n", path_to_dir.c_str());
    perror("ERROR --> mkdir");
    return(false);
  }

  return(true);
}

bool readDecisionTreesFromDirectory(const ml_string &path_to_dir,
				    ml_vector<dt_tree> &trees) {
  trees.clear();

  DIR *d = 0;
  struct dirent *dir = 0;
  d = opendir(path_to_dir.c_str());
  if(!d) {
    return(false);
  }

  while((dir = readdir(d)) != NULL) {
    ml_string file_name(dir->d_name);
    if(file_name.compare(0, TREE_MODEL_FILE_PREFIX.length(),
			 TREE_MODEL_FILE_PREFIX) != 0) {
      continue;
    }

    ml_string full_path = path_to_dir + "/" + dir->d_name;
    dt_tree tree = {};
    if(!readDecisionTreeFromFile(full_path, tree)) {
      log_error("failed to parse tree from json: %s\n", full_path.c_str());
      return(false);
    }

    trees.push_back(tree);
  }

  closedir(d);

  return(true);
}

} // namespace puml
<|endoftext|>


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

/*!

@mainpage
  Joystick teleoperation node for use within the mixed initiative framework. The user can operate the robot in
  teleoperation mode and change on the fly autonomy level/mode. Also a stop button is implimented.
  It was ment to be used with an Xbox 360 joystick but should work with any joystick.

@section usage Usage
@par
@verbatim
$ mixed_initiative_teleop
@endverbatim

@section topic ROS topics

Publishes to (name / type):
-@b /teleop/cmd_vel: will publish to /teleop/cmd_vel a geometry_msgs/Twist.msg type message to drrobot_player.
 For differential robots, linear.x is forward/backward speed (m/sec), and angular.z (rad/sec)is the angular speed.

*/

#include "sensor_msgs/JointState.h"
#include "trajectory_msgs/JointTrajectory.h"
#include "control_msgs/JointTrajectoryControllerState.h"
#include <ros/ros.h>
#include <sensor_msgs/Joy.h>
#include <geometry_msgs/Twist.h>
#include <ros/console.h>

#include <std_msgs/Int8.h>
#include <std_msgs/Bool.h>

class JoystickTeleop
{

public:
    JoystickTeleop();

private:
    void joyCallback(const sensor_msgs::Joy::ConstPtr& joy);
    void flipper_joint_statesCallback(const control_msgs::JointTrajectoryControllerState::ConstPtr &msg);

    ros::NodeHandle nh_;

    int linear_axis_, angular_axis_, control_button_, stop_button_, auto_button_, teleop_button_, enable_vel_button_, lighton_button_, lightoff_button_, bluelighton_button_, bluelightoff_button_;
    int axis_flipper_, button_flipper_front_down_, button_flipper_front_up_, button_flipper_rear_down_, button_flipper_rear_up_;
    double linear_scaling_, angular_scaling_, scale_flipper_, scale_flipper_rear_, scale_flipper_front_;

    std::vector<std::string> flipper_joint_names_;
    trajectory_msgs::JointTrajectoryPoint current_flipper_joints_;

    ros::Publisher vel_pub_, mode_pub_, light_pub_, bluelight_pub_ , jointstate_pub_, flipper_joints_pub_;

    ros::Subscriber joy_sub_, flipper_joint_states_sub_;

};

JoystickTeleop::JoystickTeleop()
{
    // Default movement axis
    nh_.param("axis_linear", linear_axis_, 1);
    nh_.param("axis_angular", angular_axis_, 0);

    // Default scaling parameters
    nh_.param("scale_angular", angular_scaling_, 0.5);
    nh_.param("scale_linear", linear_scaling_, 0.2);

    //Default buttons for Xbox 360 joystick.
    nh_.param("teleop_button", teleop_button_, 3); // Y button
    nh_.param("auto_button", auto_button_, 0);     // A button
    nh_.param("stop_button", stop_button_, 4);     // LB button
    nh_.param("enable_vel_button", enable_vel_button_, 5);     // RB button
    nh_.param("bluelightoff_button", bluelightoff_button_, 1);     // B button
    nh_.param("bluelighton_button", bluelighton_button_, 2);     // X button
    nh_.param("lightoff_button", lightoff_button_, 7);     // start button
    nh_.param("lighton_button", lighton_button_, 6);     // back/select button

    // default buttons and axis for flippers
    nh_.param("axis_flipper", axis_flipper_, 4);
    nh_.param("scale_flipper", scale_flipper_, 0.6);
    nh_.param("button_flipper_front_down", button_flipper_front_down_, 0); //6,7;
    nh_.param("button_flipper_front_up", button_flipper_front_up_, 1);
    nh_.param("button_flipper_rear_down", button_flipper_rear_down_, 2);
    nh_.param("button_flipper_rear_up", button_flipper_rear_up_, 3);
    nh_.param("scale_flipper_front", scale_flipper_front_, 0.6);
    nh_.param("scale_flipper_rear", scale_flipper_rear_, 0.6);

    vel_pub_ = nh_.advertise<geometry_msgs::Twist>("/teleop/cmd_vel", 5);
    mode_pub_ = nh_.advertise<std_msgs::Int8>("/control_mode", 5);
    light_pub_ = nh_.advertise<std_msgs::Bool>("/light", 5);
    bluelight_pub_ = nh_.advertise<std_msgs::Bool>("/bluelight", 5);
    jointstate_pub_ = nh_.advertise<sensor_msgs::JointState>("jointstate_cmd", 1);
    flipper_joints_pub_= nh_.advertise<trajectory_msgs::JointTrajectory>("//flipper/flipper_traj_controller/command", 1);

    joy_sub_ = nh_.subscribe<sensor_msgs::Joy>("joy", 2, &JoystickTeleop::joyCallback, this);
    flipper_joint_states_sub_ = nh_.subscribe<control_msgs::JointTrajectoryControllerState>("/flipper/flipper_traj_controller/state", 1, &JoystickTeleop::flipper_joint_statesCallback, this);

}

void JoystickTeleop::joyCallback(const sensor_msgs::Joy::ConstPtr& joy)
{
    geometry_msgs::Twist cmd_vel;
    std_msgs::Int8 mode;
    std_msgs::Bool bluelight, light;
    sensor_msgs::JointState jsm;
    trajectory_msgs::JointTrajectory flipper_traj;
    trajectory_msgs::JointTrajectoryPoint flipper_desired_joint_states;

    if (joy->buttons.size() > enable_vel_button_ && joy->buttons[enable_vel_button_])
    {

        // movement commands
        cmd_vel.linear.x = linear_scaling_ * joy->axes[linear_axis_];
        cmd_vel.angular.z = angular_scaling_ * joy->axes[angular_axis_];

        vel_pub_.publish(cmd_vel);
    }

    else
    {
        cmd_vel.linear.x = 0;
        cmd_vel.angular.z = 0;

        vel_pub_.publish(cmd_vel);
    }

    // autonomy mode choice
    if (joy->buttons[stop_button_]){
        mode.data=0;
        mode_pub_.publish(mode);
    }
    if (joy->buttons[teleop_button_]){
        mode.data=1;
        mode_pub_.publish(mode);
    }
    if (joy->buttons[auto_button_]){
        mode.data=2;
        mode_pub_.publish(mode);
    }

    // blue lights control
    if (joy->buttons[bluelighton_button_])
    {
        bluelight.data = true;
        bluelight_pub_.publish(bluelight);
    }

    if (joy->buttons[bluelightoff_button_])
    {
        bluelight.data = false;
        bluelight_pub_.publish(bluelight);
    }
    // lights control
    if (joy->buttons[lighton_button_])
    {
        light.data = true;
        light_pub_.publish(light);
    }

    if (joy->buttons[lightoff_button_])
    {
        light.data = false;
        light_pub_.publish(light);
    }

    // flipper control
    jsm.header.frame_id = "flippers_front";
    jsm.header.stamp = ros::Time::now();
    jsm.name.push_back("flippers_front");
    jsm.position.push_back(joy->axes[axis_flipper_] * scale_flipper_);
    jointstate_pub_.publish(jsm);

    // not sure at all what this bit from taurob original code does

    ros::Duration dur(0.5);

    for(int i=0; i < flipper_joint_names_.size(); i++)
    {
        flipper_traj.joint_names.push_back(flipper_joint_names_[i]);
        if (i == 0)
        {
            flipper_desired_joint_states.positions.push_back(
                        current_flipper_joints_.positions.at(i) +
                        joy->buttons[button_flipper_front_up_] * -scale_flipper_front_ +
                        joy->buttons[button_flipper_front_down_] * scale_flipper_front_);
        }
        else
        {
            flipper_desired_joint_states.positions.push_back(
                        current_flipper_joints_.positions.at(i) +
                        joy->buttons[button_flipper_rear_up_] * -scale_flipper_rear_ +
                        joy->buttons[button_flipper_rear_down_] * scale_flipper_rear_);
        }
    }

    flipper_desired_joint_states.time_from_start=dur;
            flipper_traj.header.stamp = ros::Time::now();
            flipper_traj.points.push_back(flipper_desired_joint_states);
            flipper_joints_pub_.publish(flipper_traj);

}

void JoystickTeleop::flipper_joint_statesCallback(const control_msgs::JointTrajectoryControllerState::ConstPtr &msg)
{
    flipper_joint_names_= msg->joint_names;
    current_flipper_joints_= msg->actual;
}

int main(int argc, char** argv)
{
    ros::init(argc, argv, "taurob_mi_teleop_node");
    JoystickTeleop joystick_teleop;

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

/*!

@mainpage
  Joystick teleoperation node for use within the mixed initiative framework. The user can operate the robot in
  teleoperation mode and change on the fly autonomy level/mode. Also a stop button is implimented.
  It was ment to be used with an Xbox 360 joystick but should work with any joystick.

@section usage Usage
@par
@verbatim
$ mixed_initiative_teleop
@endverbatim

@section topic ROS topics

Publishes to (name / type):
-@b /teleop/cmd_vel: will publish to /teleop/cmd_vel a geometry_msgs/Twist.msg type message to drrobot_player.
 For differential robots, linear.x is forward/backward speed (m/sec), and angular.z (rad/sec)is the angular speed.

*/

#include "sensor_msgs/JointState.h"
#include "trajectory_msgs/JointTrajectory.h"
#include "control_msgs/JointTrajectoryControllerState.h"
#include <ros/ros.h>
#include <sensor_msgs/Joy.h>
#include <geometry_msgs/Twist.h>
#include <ros/console.h>

#include <std_msgs/Int8.h>
#include <std_msgs/Bool.h>

class JoystickTeleop
{

public:
    JoystickTeleop();

private:
    void joyCallback(const sensor_msgs::Joy::ConstPtr& joy);
    void flipper_joint_statesCallback(const control_msgs::JointTrajectoryControllerState::ConstPtr &msg);

    ros::NodeHandle nh_;

    int linear_axis_, angular_axis_, control_button_, stop_button_, auto_button_, teleop_button_, enable_vel_button_, lighton_button_, lightoff_button_, bluelighton_button_, bluelightoff_button_;
    int axis_flipper_, button_flipper_front_down_, button_flipper_front_up_, button_flipper_rear_down_, button_flipper_rear_up_;
    double linear_scaling_, angular_scaling_, scale_flipper_, scale_flipper_rear_, scale_flipper_front_;

    std::vector<std::string> flipper_joint_names_;
    trajectory_msgs::JointTrajectoryPoint current_flipper_joints_;

    ros::Publisher vel_pub_, mode_pub_, light_pub_, bluelight_pub_ , jointstate_pub_, flipper_joints_pub_;

    ros::Subscriber joy_sub_, flipper_joint_states_sub_;

};

JoystickTeleop::JoystickTeleop()
{
    // Default movement axis
    nh_.param("axis_linear", linear_axis_, 1);
    nh_.param("axis_angular", angular_axis_, 0);

    // Default scaling parameters
    nh_.param("scale_angular", angular_scaling_, 0.6);
    nh_.param("scale_linear", linear_scaling_, 0.25);

    //Default buttons for Xbox 360 joystick.
    nh_.param("teleop_button", teleop_button_, 3); // Y button
    nh_.param("auto_button", auto_button_, 0);     // A button
    nh_.param("stop_button", stop_button_, 4);     // LB button
    nh_.param("enable_vel_button", enable_vel_button_, 5);     // RB button
    nh_.param("bluelightoff_button", bluelightoff_button_, 1);     // B button
    nh_.param("bluelighton_button", bluelighton_button_, 2);     // X button
    nh_.param("lightoff_button", lightoff_button_, 7);     // start button
    nh_.param("lighton_button", lighton_button_, 6);     // back/select button

    // default buttons and axis for flippers
    nh_.param("axis_flipper", axis_flipper_, 4);
    nh_.param("scale_flipper", scale_flipper_, 0.6);
    nh_.param("button_flipper_front_down", button_flipper_front_down_, 0); //6,7;
    nh_.param("button_flipper_front_up", button_flipper_front_up_, 1);
    nh_.param("button_flipper_rear_down", button_flipper_rear_down_, 2);
    nh_.param("button_flipper_rear_up", button_flipper_rear_up_, 3);
    nh_.param("scale_flipper_front", scale_flipper_front_, 0.6);
    nh_.param("scale_flipper_rear", scale_flipper_rear_, 0.6);

    vel_pub_ = nh_.advertise<geometry_msgs::Twist>("/teleop/cmd_vel", 5);
    mode_pub_ = nh_.advertise<std_msgs::Int8>("/control_mode", 5);
    light_pub_ = nh_.advertise<std_msgs::Bool>("/light", 5);
    bluelight_pub_ = nh_.advertise<std_msgs::Bool>("/bluelight", 5);
    jointstate_pub_ = nh_.advertise<sensor_msgs::JointState>("jointstate_cmd", 1);
    flipper_joints_pub_= nh_.advertise<trajectory_msgs::JointTrajectory>("//flipper/flipper_traj_controller/command", 1);

    joy_sub_ = nh_.subscribe<sensor_msgs::Joy>("joy", 2, &JoystickTeleop::joyCallback, this);
    flipper_joint_states_sub_ = nh_.subscribe<control_msgs::JointTrajectoryControllerState>("/flipper/flipper_traj_controller/state", 1, &JoystickTeleop::flipper_joint_statesCallback, this);

}

void JoystickTeleop::joyCallback(const sensor_msgs::Joy::ConstPtr& joy)
{
    geometry_msgs::Twist cmd_vel;
    std_msgs::Int8 mode;
    std_msgs::Bool bluelight, light;
    sensor_msgs::JointState jsm;
    trajectory_msgs::JointTrajectory flipper_traj;
    trajectory_msgs::JointTrajectoryPoint flipper_desired_joint_states;

    if (joy->buttons.size() > enable_vel_button_ && joy->buttons[enable_vel_button_])
    {

        // movement commands
        cmd_vel.linear.x = linear_scaling_ * joy->axes[linear_axis_];
        cmd_vel.angular.z = angular_scaling_ * joy->axes[angular_axis_];

        vel_pub_.publish(cmd_vel);
    }

    else
    {
        cmd_vel.linear.x = 0;
        cmd_vel.angular.z = 0;

        vel_pub_.publish(cmd_vel);
    }

    // autonomy mode choice
    if (joy->buttons[stop_button_]){
        mode.data=0;
        mode_pub_.publish(mode);
    }
    if (joy->buttons[teleop_button_]){
        mode.data=1;
        mode_pub_.publish(mode);
    }
    if (joy->buttons[auto_button_]){
        mode.data=2;
        mode_pub_.publish(mode);
    }

    // blue lights control
    if (joy->buttons[bluelighton_button_])
    {
        bluelight.data = true;
        bluelight_pub_.publish(bluelight);
    }

    if (joy->buttons[bluelightoff_button_])
    {
        bluelight.data = false;
        bluelight_pub_.publish(bluelight);
    }
    // lights control
    if (joy->buttons[lighton_button_])
    {
        light.data = true;
        light_pub_.publish(light);
    }

    if (joy->buttons[lightoff_button_])
    {
        light.data = false;
        light_pub_.publish(light);
    }

    // flipper control
    jsm.header.frame_id = "flippers_front";
    jsm.header.stamp = ros::Time::now();
    jsm.name.push_back("flippers_front");
    jsm.position.push_back(joy->axes[axis_flipper_] * scale_flipper_);
    jointstate_pub_.publish(jsm);

    // not sure at all what this bit from taurob original code does

    ros::Duration dur(0.5);

    for(int i=0; i < flipper_joint_names_.size(); i++)
    {
        flipper_traj.joint_names.push_back(flipper_joint_names_[i]);
        if (i == 0)
        {
            flipper_desired_joint_states.positions.push_back(
                        current_flipper_joints_.positions.at(i) +
                        joy->buttons[button_flipper_front_up_] * -scale_flipper_front_ +
                        joy->buttons[button_flipper_front_down_] * scale_flipper_front_);
        }
        else
        {
            flipper_desired_joint_states.positions.push_back(
                        current_flipper_joints_.positions.at(i) +
                        joy->buttons[button_flipper_rear_up_] * -scale_flipper_rear_ +
                        joy->buttons[button_flipper_rear_down_] * scale_flipper_rear_);
        }
    }

    flipper_desired_joint_states.time_from_start=dur;
            flipper_traj.header.stamp = ros::Time::now();
            flipper_traj.points.push_back(flipper_desired_joint_states);
            flipper_joints_pub_.publish(flipper_traj);

}

void JoystickTeleop::flipper_joint_statesCallback(const control_msgs::JointTrajectoryControllerState::ConstPtr &msg)
{
    flipper_joint_names_= msg->joint_names;
    current_flipper_joints_= msg->actual;
}

int main(int argc, char** argv)
{
    ros::init(argc, argv, "taurob_mi_teleop_node");
    JoystickTeleop joystick_teleop;

    ros::Rate r(20); // 20 hz
    while (ros::ok())
    {
        ros::spinOnce();
        r.sleep();
    }
}
<|endoftext|>


<commit_before>#include <babylon/meshes/sub_mesh.h>

#include <babylon/babylon_stl_util.h>
#include <babylon/collisions/intersection_info.h>
#include <babylon/culling/bounding_info.h>
#include <babylon/culling/ray.h>
#include <babylon/engines/constants.h>
#include <babylon/engines/engine.h>
#include <babylon/engines/scene.h>
#include <babylon/materials/multi_material.h>
#include <babylon/materials/standard_material.h>
#include <babylon/materials/standard_material_defines.h>
#include <babylon/maths/functions.h>
#include <babylon/maths/plane.h>
#include <babylon/meshes/abstract_mesh.h>
#include <babylon/meshes/geometry.h>
#include <babylon/meshes/instanced_lines_mesh.h>
#include <babylon/meshes/lines_mesh.h>
#include <babylon/meshes/transform_node.h>
#include <babylon/meshes/vertex_buffer.h>
#include <babylon/misc/tools.h>

namespace BABYLON {

SubMesh::SubMesh(unsigned int iMaterialIndex, unsigned int iVerticesStart, size_t iVerticesCount,
                 unsigned int iIndexStart, size_t iIndexCount, const AbstractMeshPtr& mesh,
                 const MeshPtr& renderingMesh, bool iCreateBoundingBox)
    : materialIndex{iMaterialIndex}
    , verticesStart{iVerticesStart}
    , verticesCount{iVerticesCount}
    , indexStart{iIndexStart}
    , indexCount{iIndexCount}
    , createBoundingBox{iCreateBoundingBox}
    , _linesIndexCount{0}
    , _lastColliderTransformMatrix{nullptr}
    , _renderId{0}
    , _alphaIndex{0}
    , _distanceToCamera{0.f}
    , _mesh{mesh}
    , _boundingInfo{nullptr}
    , _linesIndexBuffer{nullptr}
    , _currentMaterial{nullptr}
{
  _renderingMesh = renderingMesh ? renderingMesh : std::static_pointer_cast<Mesh>(mesh);

  _id = mesh->subMeshes.size() /*- 1*/; // Submesh is not yet to the list

  if (createBoundingBox) {
    refreshBoundingInfo();
    mesh->computeWorldMatrix(true);
  }
}

SubMesh::~SubMesh() = default;

void SubMesh::addToMesh(const std::shared_ptr<SubMesh>& newSubMesh)
{
  _mesh->subMeshes.emplace_back(newSubMesh);
}

SubMeshPtr SubMesh::AddToMesh(unsigned int materialIndex, unsigned int verticesStart,
                              size_t verticesCount, unsigned int indexStart, size_t indexCount,
                              const AbstractMeshPtr& mesh, const MeshPtr& renderingMesh,
                              bool createBoundingBox)
{
  return SubMesh::New(materialIndex, verticesStart, verticesCount, indexStart, indexCount, mesh,
                      renderingMesh, createBoundingBox);
}

bool SubMesh::isGlobal() const
{
  return (verticesStart == 0 && verticesCount == _mesh->getTotalVertices());
}

BoundingInfoPtr& SubMesh::getBoundingInfo()
{
  if (isGlobal()) {
    return _mesh->getBoundingInfo();
  }

  return _boundingInfo;
}

SubMesh& SubMesh::setBoundingInfo(const BoundingInfo& boundingInfo)
{
  _boundingInfo = std::make_unique<BoundingInfo>(boundingInfo);
  return *this;
}

AbstractMeshPtr& SubMesh::getMesh()
{
  return _mesh;
}

MeshPtr& SubMesh::getRenderingMesh()
{
  return _renderingMesh;
}

MaterialPtr SubMesh::getMaterial()
{
  auto rootMaterial = _renderingMesh->getMaterial();

  if (!rootMaterial) {
    return _mesh->getScene()->defaultMaterial();
  }
  else if (rootMaterial && (rootMaterial->type() == Type::MULTIMATERIAL)) {
    auto multiMaterial     = std::static_pointer_cast<MultiMaterial>(rootMaterial);
    auto effectiveMaterial = multiMaterial->getSubMaterial(materialIndex);

    if (_currentMaterial != effectiveMaterial) {
      _currentMaterial = effectiveMaterial;
      _materialDefines = nullptr;
    }

    return effectiveMaterial;
  }

  return rootMaterial;
}

// Methods
SubMesh& SubMesh::refreshBoundingInfo(const Float32Array& iData)
{
  _lastColliderWorldVertices.clear();

  if (isGlobal() || !_renderingMesh || !_renderingMesh->geometry()) {
    return *this;
  }

  auto data = !iData.empty() ? iData : _renderingMesh->getVerticesData(VertexBuffer::PositionKind);

  if (data.empty()) {
    _boundingInfo = std::make_unique<BoundingInfo>(*_mesh->_boundingInfo);
    return *this;
  }

  auto indices = _renderingMesh->getIndices();
  MinMax extend;

  // Is this the only submesh?
  if (indexStart == 0 && indexCount == indices.size()) {
    const auto& boundingInfo = *_renderingMesh->getBoundingInfo();

    // the rendering mesh's bounding info can be used, it is the standard
    // submesh for all indices.
    extend = {
      boundingInfo.minimum, // minimum
      boundingInfo.maximum  // maximum
    };
  }
  else {
    extend = extractMinAndMaxIndexed(data, indices, indexStart, indexCount,
                                     *_renderingMesh->geometry()->boundingBias());
  }

  if (_boundingInfo) {
    _boundingInfo->reConstruct(extend.min, extend.max);
  }
  else {
    _boundingInfo = std::make_shared<BoundingInfo>(extend.min, extend.max);
  }

  return *this;
}

bool SubMesh::_checkCollision(const Collider& collider)
{
  const auto& boundingInfo = *getBoundingInfo();

  return boundingInfo._checkCollision(collider);
}

SubMesh& SubMesh::updateBoundingInfo(const Matrix& world)
{
  auto boundingInfo = getBoundingInfo();

  if (!boundingInfo) {
    refreshBoundingInfo();
    boundingInfo = getBoundingInfo();
  }
  boundingInfo->update(world);

  return *this;
}

bool SubMesh::isInFrustum(const std::array<Plane, 6>& frustumPlanes, unsigned int /*strategy*/)
{
  auto boundingInfo = getBoundingInfo();

  if (!boundingInfo) {
    return false;
  }

  return boundingInfo->isInFrustum(frustumPlanes, _mesh->cullingStrategy);
}

bool SubMesh::isCompletelyInFrustum(const std::array<Plane, 6>& frustumPlanes)
{
  auto boundingInfo = getBoundingInfo();

  if (!boundingInfo) {
    return false;
  }

  return boundingInfo->isCompletelyInFrustum(frustumPlanes);
}

SubMesh& SubMesh::render(bool enableAlphaMode)
{
  _renderingMesh->render(this, enableAlphaMode);
  return *this;
}

WebGLDataBufferPtr& SubMesh::_getLinesIndexBuffer(const IndicesArray& indices, Engine* engine)
{
  if (!_linesIndexBuffer) {
    Uint32Array linesIndices;

    for (auto index = indexStart; index < indexStart + indexCount; index += 3) {
      stl_util::concat(linesIndices, {indices[index + 0], indices[index + 1], indices[index + 1],
                                      indices[index + 2], indices[index + 2], indices[index + 0]});
    }

    _linesIndexBuffer = engine->createIndexBuffer(linesIndices);
    _linesIndexCount  = linesIndices.size();
  }
  return _linesIndexBuffer;
}

bool SubMesh::canIntersects(const Ray& ray)
{
  auto boundingInfo = getBoundingInfo();

  if (!boundingInfo) {
    return false;
  }

  return ray.intersectsBox(boundingInfo->boundingBox);
}

std::optional<IntersectionInfo>
SubMesh::intersects(Ray& ray, const std::vector<Vector3>& positions, const Uint32Array& indices,
                    bool fastCheck, const TrianglePickingPredicate& trianglePredicate)
{
  std::optional<IntersectionInfo> intersectInfo = std::nullopt;

  const auto material = getMaterial();
  if (!material) {
    return intersectInfo;
  }

  switch (material->fillMode()) {
    case Constants::MATERIAL_PointListDrawMode:
    case Constants::MATERIAL_LineListDrawMode:
    case Constants::MATERIAL_LineLoopDrawMode:
    case Constants::MATERIAL_LineStripDrawMode:
    case Constants::MATERIAL_TriangleFanDrawMode:
    case Constants::MATERIAL_TriangleStripDrawMode:
      return std::nullopt;
  }

  // LineMesh first as it's also a Mesh...
  if (_mesh->getClassName() == "InstancedLinesMesh" || _mesh->getClassName() == "LinesMesh") {
    auto intersectionThreshold = std::static_pointer_cast<LinesMesh>(_mesh)->intersectionThreshold;
    // Check if mesh is unindexed
    if (indices.empty()) {
      return _intersectUnIndexedLines(ray, positions, indices, intersectionThreshold, fastCheck);
    }
    return _intersectLines(ray, positions, indices, intersectionThreshold, fastCheck);
  }
  else {
    // Check if mesh is unindexed
    if (indices.empty() && _mesh->_unIndexed) {
      return _intersectUnIndexedTriangles(ray, positions, indices, fastCheck, trianglePredicate);
    }

    return _intersectTriangles(ray, positions, indices, fastCheck, trianglePredicate);
  }
}

std::optional<IntersectionInfo>
SubMesh::_intersectLines(Ray& ray, const std::vector<Vector3>& positions,
                         const IndicesArray& indices, float intersectionThreshold, bool fastCheck)
{
  std::optional<IntersectionInfo> intersectInfo = std::nullopt;

  // Line test
  for (auto index = indexStart; index < indexStart + indexCount; index += 2) {
    const auto& p0 = positions[indices[index]];
    const auto& p1 = positions[indices[index + 1]];

    const auto length = ray.intersectionSegment(p0, p1, intersectionThreshold);
    if (length < 0.f) {
      continue;
    }

    if (fastCheck || !intersectInfo || length < intersectInfo->distance) {
      intersectInfo         = IntersectionInfo(0.f, 0.f, length);
      intersectInfo->faceId = index / 2;
      if (fastCheck) {
        break;
      }
    }
  }

  return intersectInfo;
}

std::optional<IntersectionInfo>
SubMesh::_intersectUnIndexedLines(Ray& ray, const std::vector<Vector3>& positions,
                                  const IndicesArray& /*indices*/, float intersectionThreshold,
                                  bool fastCheck)
{
  std::optional<IntersectionInfo> intersectInfo = std::nullopt;

  // Line test
  for (auto index = verticesStart; index < verticesStart + verticesCount; index += 2) {
    const auto& p0 = positions[index];
    const auto& p1 = positions[index + 1];

    const auto length = ray.intersectionSegment(p0, p1, intersectionThreshold);
    if (length < 0.f) {
      continue;
    }

    if (fastCheck || !intersectInfo || length < intersectInfo->distance) {
      intersectInfo         = IntersectionInfo(0.f, 0.f, length);
      intersectInfo->faceId = index / 2;
      if (fastCheck) {
        break;
      }
    }
  }

  return intersectInfo;
}

std::optional<IntersectionInfo>
SubMesh::_intersectTriangles(Ray& ray, const std::vector<Vector3>& positions,
                             const IndicesArray& indices, bool fastCheck,
                             const TrianglePickingPredicate& trianglePredicate)
{
  if (positions.empty())
    return std::nullopt;

  std::optional<IntersectionInfo> intersectInfo = std::nullopt;

  // Triangles test
  for (auto index = indexStart; index < indexStart + indexCount; index += 3) {
    const auto& p0 = positions[indices[index]];
    const auto& p1 = positions[indices[index + 1]];
    const auto& p2 = positions[indices[index + 2]];

    if (trianglePredicate && !trianglePredicate(p0, p1, p2, ray)) {
      continue;
    }

    const auto currentIntersectInfo = ray.intersectsTriangle(p0, p1, p2);

    if (currentIntersectInfo) {
      if (currentIntersectInfo->distance < 0.f) {
        continue;
      }

      if (fastCheck || !intersectInfo || currentIntersectInfo->distance < intersectInfo->distance) {
        intersectInfo         = currentIntersectInfo;
        intersectInfo->faceId = index / 3;

        if (fastCheck) {
          break;
        }
      }
    }
  }

  return intersectInfo;
}

std::optional<IntersectionInfo>
SubMesh::_intersectUnIndexedTriangles(Ray& ray, const std::vector<Vector3>& positions,
                                      const IndicesArray& /*indices*/, bool fastCheck,
                                      const TrianglePickingPredicate& trianglePredicate)
{
  std::optional<IntersectionInfo> intersectInfo = std::nullopt;

  // Triangles test
  for (auto index = indexStart; index < indexStart + indexCount; index += 3) {
    const auto& p0 = positions[index];
    const auto& p1 = positions[index + 1];
    const auto& p2 = positions[index + 2];

    if (trianglePredicate && !trianglePredicate(p0, p1, p2, ray)) {
      continue;
    }

    const auto currentIntersectInfo = ray.intersectsTriangle(p0, p1, p2);

    if (currentIntersectInfo) {
      if (currentIntersectInfo->distance < 0.f) {
        continue;
      }

      if (fastCheck || !intersectInfo || currentIntersectInfo->distance < intersectInfo->distance) {
        intersectInfo         = currentIntersectInfo;
        intersectInfo->faceId = index / 3;

        if (fastCheck) {
          break;
        }
      }
    }
  }

  return intersectInfo;
}

void SubMesh::_rebuild()
{
  if (_linesIndexBuffer) {
    _linesIndexBuffer = nullptr;
  }
}

// Clone
SubMeshPtr SubMesh::clone(const AbstractMeshPtr& newMesh, const MeshPtr& newRenderingMesh)
{
  auto result = SubMesh::New(materialIndex, verticesStart, verticesCount, indexStart, indexCount,
                             newMesh, newRenderingMesh, false);

  if (!isGlobal()) {
    auto boundingInfo = getBoundingInfo();

    if (!boundingInfo) {
      return result;
    }

    result->_boundingInfo
      = std::make_shared<BoundingInfo>(boundingInfo->minimum, boundingInfo->maximum);
  }

  return result;
}

// Dispose
void SubMesh::dispose()
{
  if (_linesIndexBuffer) {
    _mesh->getScene()->getEngine()->_releaseBuffer(_linesIndexBuffer);
    _linesIndexBuffer = nullptr;
  }

  // Remove from mesh
  stl_util::remove_vector_elements_equal_sharedptr(_mesh->subMeshes, this);
}

std::string SubMesh::getClassName() const
{
  return "SubMesh";
}

SubMeshPtr SubMesh::CreateFromIndices(unsigned int materialIndex, unsigned int startIndex,
                                      size_t indexCount, const AbstractMeshPtr& mesh,
                                      const MeshPtr& renderingMesh)
{
  auto minVertexIndex = std::numeric_limits<unsigned>::max();
  auto maxVertexIndex = std::numeric_limits<unsigned>::lowest();

  auto whatWillRender = renderingMesh ? renderingMesh : std::static_pointer_cast<Mesh>(mesh);
  auto indices        = whatWillRender->getIndices();

  for (size_t index = startIndex; index < startIndex + indexCount; ++index) {
    auto& vertexIndex = indices[index];

    if (vertexIndex < minVertexIndex) {
      minVertexIndex = vertexIndex;
    }
    if (vertexIndex > maxVertexIndex) {
      maxVertexIndex = vertexIndex;
    }
  }

  return SubMesh::New(materialIndex, minVertexIndex, maxVertexIndex - minVertexIndex + 1,
                      startIndex, indexCount, mesh, renderingMesh);
}

} // end of namespace BABYLON
<commit_msg>updated BabylonFileLoader class to v4.1.0-beta.13<commit_after>#include <babylon/meshes/sub_mesh.h>

#include <babylon/babylon_stl_util.h>
#include <babylon/collisions/intersection_info.h>
#include <babylon/culling/bounding_info.h>
#include <babylon/culling/ray.h>
#include <babylon/engines/constants.h>
#include <babylon/engines/engine.h>
#include <babylon/engines/scene.h>
#include <babylon/materials/multi_material.h>
#include <babylon/materials/standard_material.h>
#include <babylon/materials/standard_material_defines.h>
#include <babylon/maths/functions.h>
#include <babylon/maths/plane.h>
#include <babylon/meshes/abstract_mesh.h>
#include <babylon/meshes/geometry.h>
#include <babylon/meshes/instanced_lines_mesh.h>
#include <babylon/meshes/lines_mesh.h>
#include <babylon/meshes/transform_node.h>
#include <babylon/meshes/vertex_buffer.h>
#include <babylon/misc/tools.h>

namespace BABYLON {

SubMesh::SubMesh(unsigned int iMaterialIndex, unsigned int iVerticesStart, size_t iVerticesCount,
                 unsigned int iIndexStart, size_t iIndexCount, const AbstractMeshPtr& mesh,
                 const MeshPtr& renderingMesh, bool iCreateBoundingBox)
    : materialIndex{iMaterialIndex}
    , verticesStart{iVerticesStart}
    , verticesCount{iVerticesCount}
    , indexStart{iIndexStart}
    , indexCount{iIndexCount}
    , createBoundingBox{iCreateBoundingBox}
    , _linesIndexCount{0}
    , _lastColliderTransformMatrix{nullptr}
    , _renderId{0}
    , _alphaIndex{0}
    , _distanceToCamera{0.f}
    , _mesh{mesh}
    , _boundingInfo{nullptr}
    , _linesIndexBuffer{nullptr}
    , _currentMaterial{nullptr}
{
  _renderingMesh = renderingMesh ? renderingMesh : std::static_pointer_cast<Mesh>(mesh);

  _id = mesh->subMeshes.size() /*- 1*/; // Submesh is not yet to the list

  if (createBoundingBox) {
    refreshBoundingInfo();
    mesh->computeWorldMatrix(true);
  }
}

SubMesh::~SubMesh() = default;

void SubMesh::addToMesh(const std::shared_ptr<SubMesh>& newSubMesh)
{
  _mesh->subMeshes.emplace_back(newSubMesh);
}

SubMeshPtr SubMesh::AddToMesh(unsigned int materialIndex, unsigned int verticesStart,
                              size_t verticesCount, unsigned int indexStart, size_t indexCount,
                              const AbstractMeshPtr& mesh, const MeshPtr& renderingMesh,
                              bool createBoundingBox)
{
  return SubMesh::New(materialIndex, verticesStart, verticesCount, indexStart, indexCount, mesh,
                      renderingMesh, createBoundingBox);
}

bool SubMesh::isGlobal() const
{
  return (verticesStart == 0 && verticesCount == _mesh->getTotalVertices());
}

BoundingInfoPtr& SubMesh::getBoundingInfo()
{
  if (isGlobal()) {
    return _mesh->getBoundingInfo();
  }

  return _boundingInfo;
}

SubMesh& SubMesh::setBoundingInfo(const BoundingInfo& boundingInfo)
{
  _boundingInfo = std::make_unique<BoundingInfo>(boundingInfo);
  return *this;
}

AbstractMeshPtr& SubMesh::getMesh()
{
  return _mesh;
}

MeshPtr& SubMesh::getRenderingMesh()
{
  return _renderingMesh;
}

MaterialPtr SubMesh::getMaterial()
{
  auto rootMaterial = _renderingMesh->getMaterial();

  if (!rootMaterial) {
    return _mesh->getScene()->defaultMaterial();
  }
  else if (rootMaterial && (rootMaterial->type() == Type::MULTIMATERIAL)) {
    auto multiMaterial     = std::static_pointer_cast<MultiMaterial>(rootMaterial);
    auto effectiveMaterial = multiMaterial->getSubMaterial(materialIndex);

    if (_currentMaterial != effectiveMaterial) {
      _currentMaterial = effectiveMaterial;
      _materialDefines = nullptr;
    }

    return effectiveMaterial;
  }

  return rootMaterial;
}

// Methods
SubMesh& SubMesh::refreshBoundingInfo(const Float32Array& iData)
{
  _lastColliderWorldVertices.clear();

  if (isGlobal() || !_renderingMesh || !_renderingMesh->geometry()) {
    return *this;
  }

  auto data = !iData.empty() ? iData : _renderingMesh->getVerticesData(VertexBuffer::PositionKind);

  if (data.empty()) {
    _boundingInfo = std::make_unique<BoundingInfo>(*_mesh->_boundingInfo);
    return *this;
  }

  auto indices = _renderingMesh->getIndices();
  MinMax extend;

  // Is this the only submesh?
  if (indexStart == 0 && indexCount == indices.size()) {
    const auto& boundingInfo = *_renderingMesh->getBoundingInfo();

    // the rendering mesh's bounding info can be used, it is the standard
    // submesh for all indices.
    extend = {
      boundingInfo.minimum, // minimum
      boundingInfo.maximum  // maximum
    };
  }
  else {
    extend = extractMinAndMaxIndexed(data, indices, indexStart, indexCount,
                                     *_renderingMesh->geometry()->boundingBias());
  }

  if (_boundingInfo) {
    _boundingInfo->reConstruct(extend.min, extend.max);
  }
  else {
    _boundingInfo = std::make_shared<BoundingInfo>(extend.min, extend.max);
  }

  return *this;
}

bool SubMesh::_checkCollision(const Collider& collider)
{
  const auto& boundingInfo = *getBoundingInfo();

  return boundingInfo._checkCollision(collider);
}

SubMesh& SubMesh::updateBoundingInfo(const Matrix& world)
{
  auto boundingInfo = getBoundingInfo();

  if (!boundingInfo) {
    refreshBoundingInfo();
    boundingInfo = getBoundingInfo();
  }
  if (boundingInfo) {
    boundingInfo->update(world);
  }

  return *this;
}

bool SubMesh::isInFrustum(const std::array<Plane, 6>& frustumPlanes, unsigned int /*strategy*/)
{
  auto boundingInfo = getBoundingInfo();

  if (!boundingInfo) {
    return false;
  }

  return boundingInfo->isInFrustum(frustumPlanes, _mesh->cullingStrategy);
}

bool SubMesh::isCompletelyInFrustum(const std::array<Plane, 6>& frustumPlanes)
{
  auto boundingInfo = getBoundingInfo();

  if (!boundingInfo) {
    return false;
  }

  return boundingInfo->isCompletelyInFrustum(frustumPlanes);
}

SubMesh& SubMesh::render(bool enableAlphaMode)
{
  _renderingMesh->render(this, enableAlphaMode,
                         _mesh->_internalAbstractMeshDataInfo._actAsRegularMesh ? _mesh : nullptr);
  return *this;
}

WebGLDataBufferPtr& SubMesh::_getLinesIndexBuffer(const IndicesArray& indices, Engine* engine)
{
  if (!_linesIndexBuffer) {
    Uint32Array linesIndices;

    for (auto index = indexStart; index < indexStart + indexCount; index += 3) {
      stl_util::concat(linesIndices, {indices[index + 0], indices[index + 1], indices[index + 1],
                                      indices[index + 2], indices[index + 2], indices[index + 0]});
    }

    _linesIndexBuffer = engine->createIndexBuffer(linesIndices);
    _linesIndexCount  = linesIndices.size();
  }
  return _linesIndexBuffer;
}

bool SubMesh::canIntersects(const Ray& ray)
{
  auto boundingInfo = getBoundingInfo();

  if (!boundingInfo) {
    return false;
  }

  return ray.intersectsBox(boundingInfo->boundingBox);
}

std::optional<IntersectionInfo>
SubMesh::intersects(Ray& ray, const std::vector<Vector3>& positions, const Uint32Array& indices,
                    bool fastCheck, const TrianglePickingPredicate& trianglePredicate)
{
  std::optional<IntersectionInfo> intersectInfo = std::nullopt;

  const auto material = getMaterial();
  if (!material) {
    return intersectInfo;
  }

  switch (material->fillMode()) {
    case Constants::MATERIAL_PointListDrawMode:
    case Constants::MATERIAL_LineListDrawMode:
    case Constants::MATERIAL_LineLoopDrawMode:
    case Constants::MATERIAL_LineStripDrawMode:
    case Constants::MATERIAL_TriangleFanDrawMode:
    case Constants::MATERIAL_TriangleStripDrawMode:
      return std::nullopt;
  }

  // LineMesh first as it's also a Mesh...
  if (_mesh->getClassName() == "InstancedLinesMesh" || _mesh->getClassName() == "LinesMesh") {
    auto intersectionThreshold = std::static_pointer_cast<LinesMesh>(_mesh)->intersectionThreshold;
    // Check if mesh is unindexed
    if (indices.empty()) {
      return _intersectUnIndexedLines(ray, positions, indices, intersectionThreshold, fastCheck);
    }
    return _intersectLines(ray, positions, indices, intersectionThreshold, fastCheck);
  }
  else {
    // Check if mesh is unindexed
    if (indices.empty() && _mesh->_unIndexed) {
      return _intersectUnIndexedTriangles(ray, positions, indices, fastCheck, trianglePredicate);
    }

    return _intersectTriangles(ray, positions, indices, fastCheck, trianglePredicate);
  }
}

std::optional<IntersectionInfo>
SubMesh::_intersectLines(Ray& ray, const std::vector<Vector3>& positions,
                         const IndicesArray& indices, float intersectionThreshold, bool fastCheck)
{
  std::optional<IntersectionInfo> intersectInfo = std::nullopt;

  // Line test
  for (auto index = indexStart; index < indexStart + indexCount; index += 2) {
    const auto& p0 = positions[indices[index]];
    const auto& p1 = positions[indices[index + 1]];

    const auto length = ray.intersectionSegment(p0, p1, intersectionThreshold);
    if (length < 0.f) {
      continue;
    }

    if (fastCheck || !intersectInfo || length < intersectInfo->distance) {
      intersectInfo         = IntersectionInfo(0.f, 0.f, length);
      intersectInfo->faceId = index / 2;
      if (fastCheck) {
        break;
      }
    }
  }

  return intersectInfo;
}

std::optional<IntersectionInfo>
SubMesh::_intersectUnIndexedLines(Ray& ray, const std::vector<Vector3>& positions,
                                  const IndicesArray& /*indices*/, float intersectionThreshold,
                                  bool fastCheck)
{
  std::optional<IntersectionInfo> intersectInfo = std::nullopt;

  // Line test
  for (auto index = verticesStart; index < verticesStart + verticesCount; index += 2) {
    const auto& p0 = positions[index];
    const auto& p1 = positions[index + 1];

    const auto length = ray.intersectionSegment(p0, p1, intersectionThreshold);
    if (length < 0.f) {
      continue;
    }

    if (fastCheck || !intersectInfo || length < intersectInfo->distance) {
      intersectInfo         = IntersectionInfo(0.f, 0.f, length);
      intersectInfo->faceId = index / 2;
      if (fastCheck) {
        break;
      }
    }
  }

  return intersectInfo;
}

std::optional<IntersectionInfo>
SubMesh::_intersectTriangles(Ray& ray, const std::vector<Vector3>& positions,
                             const IndicesArray& indices, bool fastCheck,
                             const TrianglePickingPredicate& trianglePredicate)
{
  if (positions.empty())
    return std::nullopt;

  std::optional<IntersectionInfo> intersectInfo = std::nullopt;

  // Triangles test
  for (auto index = indexStart; index < indexStart + indexCount; index += 3) {
    const auto& p0 = positions[indices[index]];
    const auto& p1 = positions[indices[index + 1]];
    const auto& p2 = positions[indices[index + 2]];

    if (trianglePredicate && !trianglePredicate(p0, p1, p2, ray)) {
      continue;
    }

    const auto currentIntersectInfo = ray.intersectsTriangle(p0, p1, p2);

    if (currentIntersectInfo) {
      if (currentIntersectInfo->distance < 0.f) {
        continue;
      }

      if (fastCheck || !intersectInfo || currentIntersectInfo->distance < intersectInfo->distance) {
        intersectInfo         = currentIntersectInfo;
        intersectInfo->faceId = index / 3;

        if (fastCheck) {
          break;
        }
      }
    }
  }

  return intersectInfo;
}

std::optional<IntersectionInfo>
SubMesh::_intersectUnIndexedTriangles(Ray& ray, const std::vector<Vector3>& positions,
                                      const IndicesArray& /*indices*/, bool fastCheck,
                                      const TrianglePickingPredicate& trianglePredicate)
{
  std::optional<IntersectionInfo> intersectInfo = std::nullopt;

  // Triangles test
  for (auto index = indexStart; index < indexStart + indexCount; index += 3) {
    const auto& p0 = positions[index];
    const auto& p1 = positions[index + 1];
    const auto& p2 = positions[index + 2];

    if (trianglePredicate && !trianglePredicate(p0, p1, p2, ray)) {
      continue;
    }

    const auto currentIntersectInfo = ray.intersectsTriangle(p0, p1, p2);

    if (currentIntersectInfo) {
      if (currentIntersectInfo->distance < 0.f) {
        continue;
      }

      if (fastCheck || !intersectInfo || currentIntersectInfo->distance < intersectInfo->distance) {
        intersectInfo         = currentIntersectInfo;
        intersectInfo->faceId = index / 3;

        if (fastCheck) {
          break;
        }
      }
    }
  }

  return intersectInfo;
}

void SubMesh::_rebuild()
{
  if (_linesIndexBuffer) {
    _linesIndexBuffer = nullptr;
  }
}

// Clone
SubMeshPtr SubMesh::clone(const AbstractMeshPtr& newMesh, const MeshPtr& newRenderingMesh)
{
  auto result = SubMesh::New(materialIndex, verticesStart, verticesCount, indexStart, indexCount,
                             newMesh, newRenderingMesh, false);

  if (!isGlobal()) {
    auto boundingInfo = getBoundingInfo();

    if (!boundingInfo) {
      return result;
    }

    result->_boundingInfo
      = std::make_shared<BoundingInfo>(boundingInfo->minimum, boundingInfo->maximum);
  }

  return result;
}

// Dispose
void SubMesh::dispose()
{
  if (_linesIndexBuffer) {
    _mesh->getScene()->getEngine()->_releaseBuffer(_linesIndexBuffer);
    _linesIndexBuffer = nullptr;
  }

  // Remove from mesh
  stl_util::remove_vector_elements_equal_sharedptr(_mesh->subMeshes, this);
}

std::string SubMesh::getClassName() const
{
  return "SubMesh";
}

SubMeshPtr SubMesh::CreateFromIndices(unsigned int materialIndex, unsigned int startIndex,
                                      size_t indexCount, const AbstractMeshPtr& mesh,
                                      const MeshPtr& renderingMesh)
{
  auto minVertexIndex = std::numeric_limits<unsigned>::max();
  auto maxVertexIndex = std::numeric_limits<unsigned>::lowest();

  auto whatWillRender = renderingMesh ? renderingMesh : std::static_pointer_cast<Mesh>(mesh);
  auto indices        = whatWillRender->getIndices();

  for (size_t index = startIndex; index < startIndex + indexCount; ++index) {
    auto& vertexIndex = indices[index];

    if (vertexIndex < minVertexIndex) {
      minVertexIndex = vertexIndex;
    }
    if (vertexIndex > maxVertexIndex) {
      maxVertexIndex = vertexIndex;
    }
  }

  return SubMesh::New(materialIndex, minVertexIndex, maxVertexIndex - minVertexIndex + 1,
                      startIndex, indexCount, mesh, renderingMesh);
}

} // end of namespace BABYLON
<|endoftext|>