<commit_before>//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007-2016 musikcube team
//
// 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 author nor the names of other 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.
//
//////////////////////////////////////////////////////////////////////////////

#include "pch.hpp"

#include <core/debug.h>
#include <core/audio/Player.h>
#include <core/plugin/PluginFactory.h>
#include <algorithm>

#define MAX_PREBUFFER_QUEUE_COUNT 8

using namespace musik::core::audio;
using std::min;
using std::max;

static std::string TAG = "Player";

PlayerPtr Player::Create(const std::string &url, OutputPtr output) {
    return PlayerPtr(new Player(url, output));
}

OutputPtr Player::CreateDefaultOutput() {
    /* if no output is specified, find all output plugins, and select the first one. */
    typedef std::vector<OutputPtr> OutputVector;

    OutputVector outputs = musik::core::PluginFactory::Instance().QueryInterface<
        IOutput, musik::core::PluginFactory::DestroyDeleter<IOutput> >("GetAudioOutput");

    if (!outputs.empty()) {
        musik::debug::info(TAG, "found an IOutput device!");
        return outputs.front();
    }

    return OutputPtr();
}

Player::Player(const std::string &url, OutputPtr output)
: state(Player::Precache)
, url(url)
, currentPosition(0)
, output(output)
, notifiedStarted(false)
, setPosition(-1) {
    musik::debug::info(TAG, "new instance created");

    /* we allow callers to specify an output device; but if they don't,
    we will create and manage our own. */
    if (!this->output) {
        throw std::runtime_error("output cannot be null!");
    }

    /* each player instance is driven by a background thread. start it. */
    this->thread.reset(new boost::thread(boost::bind(&Player::ThreadLoop, this)));
}

Player::~Player() {
    {
        boost::mutex::scoped_lock lock(this->queueMutex);
        this->state = Player::Quit;
        this->prebufferQueue.clear();
        this->writeToOutputCondition.notify_all();
    }

    this->thread->join();
}

void Player::Play() {
    boost::mutex::scoped_lock lock(this->queueMutex);
    this->state = Player::Playing;
    this->writeToOutputCondition.notify_all();
}

void Player::Stop() {
    boost::mutex::scoped_lock lock(this->queueMutex);
    this->state = Player::Quit;
    this->writeToOutputCondition.notify_all();
}

double Player::Position() {
    boost::mutex::scoped_lock lock(this->positionMutex);
    return this->currentPosition;
}

void Player::SetPosition(double seconds) {
    boost::mutex::scoped_lock lock(this->positionMutex);
    this->setPosition = std::max(0.0, seconds);
}

int Player::State() {
    boost::mutex::scoped_lock lock(this->queueMutex);
    return this->state;
}

void Player::ThreadLoop() {
    /* create and open the stream */
    this->stream = Stream::Create();

    if (this->stream->OpenStream(this->url)) {
        /* precache until buffers are full */
        bool keepPrecaching = true;
        while (this->State() == Precache && keepPrecaching) {
            keepPrecaching = this->PreBuffer();
        }

        /* wait until we enter the Playing or Quit state; we may still
        be in the Precache state. */
        {
            boost::mutex::scoped_lock lock(this->queueMutex);

            while (this->state == Precache) {
                this->writeToOutputCondition.wait(lock);
            }
        }

        /* we're ready to go.... */
        bool finished = false;
        BufferPtr buffer;

        while (!finished && !this->Exited()) {
            /* see if we've been asked to seek since the last sample was
            played. if we have, clear our output buffer and seek the
            stream. */
            double position = -1;

            {
                boost::mutex::scoped_lock lock(this->positionMutex);
                position = this->setPosition;
                this->setPosition = -1;
            }

            if (position != -1) {
                this->output->Stop(); /* flush all buffers */
                this->output->Resume(); /* start it back up */

                /* if we've allocated a buffer, but it hasn't been written
                to the output yet, unlock it. this is an important step, and if
                not performed, will result in a deadlock just below while
                waiting for all buffers to complete. */
                if (buffer) {
                    this->OnBufferProcessed(buffer.get());
                    buffer.reset();
                }

                {
                    boost::mutex::scoped_lock lock(this->queueMutex);

                    while (this->lockedBuffers.size() > 0) {
                        writeToOutputCondition.wait(this->queueMutex);
                    }
                }

                this->stream->SetPosition(position);

                {
                    boost::mutex::scoped_lock lock(this->queueMutex);
                    this->prebufferQueue.clear();
                }
            }

            /* let's see if we can find some samples to play */
            if (!buffer) {
                boost::mutex::scoped_lock lock(this->queueMutex);

                /* the buffer queue may already have some available if it was prefetched. */
                if (!this->prebufferQueue.empty()) {
                    buffer = this->prebufferQueue.front();
                    this->prebufferQueue.pop_front();
                }
                /* otherwise, we need to grab a buffer from the stream and add it to the queue */
                else {
                    buffer = this->stream->GetNextProcessedOutputBuffer();
                }

                /* lock it down until it's processed */
                if (buffer) {
                    this->lockedBuffers.push_back(buffer);
                }
            }

            /* if we have a decoded, processed buffer available. let's try to send it to
            the output device. */
            if (buffer) {
                if (this->output->Play(buffer.get(), this)) {
                    /* success! the buffer was accepted by the output.*/
                    /* lock it down so it's not destroyed until the output device lets us
                    know it's done with it. */
                    boost::mutex::scoped_lock lock(this->queueMutex);

                    if (this->lockedBuffers.size() == 1) {
                        this->currentPosition = buffer->Position();
                    }

                    buffer.reset(); /* important! we're done with this one locally. */
                }
                else {
                    /* the output device queue is full. we should block and wait until
                    the output lets us know that it needs more data */
                    boost::mutex::scoped_lock lock(this->queueMutex);
                    writeToOutputCondition.wait(this->queueMutex);
                }
            }
            /* if we're unable to obtain a buffer, it means we're out of data and the
            player is finished. terminate the thread. */
            else {
                finished = true;
            }
        }

        /* if the Quit flag isn't set, that means the stream has ended "naturally", i.e.
        it wasn't stopped by the user. raise the "almost ended" flag. */
        if (!this->Exited()) {
            this->PlaybackAlmostEnded(this);
        }
    }

    /* if the stream failed to open... */
    else {
        this->PlaybackError(this);
    }

    this->state = Player::Quit;

    /* wait until all remaining buffers have been written, set final state... */
    {
        boost::mutex::scoped_lock lock(this->queueMutex);

        while (this->lockedBuffers.size() > 0) {
            writeToOutputCondition.wait(this->queueMutex);
        }
    }

    this->PlaybackFinished(this);
}

void Player::ReleaseAllBuffers() {
    boost::mutex::scoped_lock lock(this->queueMutex);
    this->lockedBuffers.empty();
}

bool Player::PreBuffer() {
    /* don't prebuffer if the buffer is already full */
    if (this->prebufferQueue.size() < MAX_PREBUFFER_QUEUE_COUNT) {
        BufferPtr newBuffer = this->stream->GetNextProcessedOutputBuffer();

        if (newBuffer) {
            boost::mutex::scoped_lock lock(this->queueMutex);
            this->prebufferQueue.push_back(newBuffer);
        }

        return true;
    }

    return false;
}

bool Player::Exited() {
    boost::mutex::scoped_lock lock(this->queueMutex);
    return (this->state == Player::Quit);
}

void Player::OnBufferProcessed(IBuffer *buffer) {
    bool started = false;
    bool found = false;
    {
        boost::mutex::scoped_lock lock(this->queueMutex);

        /* removes the specified buffer from the list of locked buffers, and also
        lets the stream know it can be recycled. */
        BufferList::iterator it = this->lockedBuffers.begin();
        while (it != this->lockedBuffers.end() && !found) {
            if (it->get() == buffer) {
                found = true;

                if (this->stream) {
                    this->stream->OnBufferProcessedByPlayer(*it);
                }

                it = this->lockedBuffers.erase(it);

                /* this sets the current time in the stream. it does this by grabbing
                the time at the next buffer in the queue */
                if (!this->lockedBuffers.empty()) {
                    this->currentPosition = this->lockedBuffers.front()->Position();
                }
                else {
                    /* if the queue is drained, use the position from the buffer
                    that was just processed */
                    this->currentPosition = ((Buffer*) buffer)->Position();
                }

                /* if the output device's internal buffers are full, it will stop
                accepting new samples. now that a buffer has been processed, we can
                try to enqueue another sample. the thread loop blocks on this condition */
                this->writeToOutputCondition.notify_all();
            }
            else {
                ++it;
            }
        }

        if (!this->notifiedStarted) {
            this->notifiedStarted = true;
            started = true;
        }
    }

    /* we notify our listeners that we've started playing only after the first
    buffer has been consumed. this is because sometimes we precache buffers
    and send them to the output before they are actually processed by the
    output device */
    if (started) {
        this->PlaybackStarted(this);
    }
}
<commit_msg>Fixed a bug that could result in Player threads being unable to terminate.<commit_after>//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007-2016 musikcube team
//
// 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 author nor the names of other 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.
//
//////////////////////////////////////////////////////////////////////////////

#include "pch.hpp"

#include <core/debug.h>
#include <core/audio/Player.h>
#include <core/plugin/PluginFactory.h>
#include <algorithm>

#define MAX_PREBUFFER_QUEUE_COUNT 8

using namespace musik::core::audio;
using std::min;
using std::max;

static std::string TAG = "Player";

PlayerPtr Player::Create(const std::string &url, OutputPtr output) {
    return PlayerPtr(new Player(url, output));
}

OutputPtr Player::CreateDefaultOutput() {
    /* if no output is specified, find all output plugins, and select the first one. */
    typedef std::vector<OutputPtr> OutputVector;

    OutputVector outputs = musik::core::PluginFactory::Instance().QueryInterface<
        IOutput, musik::core::PluginFactory::DestroyDeleter<IOutput> >("GetAudioOutput");

    if (!outputs.empty()) {
        musik::debug::info(TAG, "found an IOutput device!");
        return outputs.front();
    }

    return OutputPtr();
}

Player::Player(const std::string &url, OutputPtr output)
: state(Player::Precache)
, url(url)
, currentPosition(0)
, output(output)
, notifiedStarted(false)
, setPosition(-1) {
    musik::debug::info(TAG, "new instance created");

    /* we allow callers to specify an output device; but if they don't,
    we will create and manage our own. */
    if (!this->output) {
        throw std::runtime_error("output cannot be null!");
    }

    /* each player instance is driven by a background thread. start it. */
    this->thread.reset(new boost::thread(boost::bind(&Player::ThreadLoop, this)));
}

Player::~Player() {
    {
        boost::mutex::scoped_lock lock(this->queueMutex);
        this->state = Player::Quit;
        this->prebufferQueue.clear();
        this->writeToOutputCondition.notify_all();
    }

    this->thread->join();
}

void Player::Play() {
    boost::mutex::scoped_lock lock(this->queueMutex);
    this->state = Player::Playing;
    this->writeToOutputCondition.notify_all();
}

void Player::Stop() {
    boost::mutex::scoped_lock lock(this->queueMutex);
    this->state = Player::Quit;
    this->writeToOutputCondition.notify_all();
}

double Player::Position() {
    boost::mutex::scoped_lock lock(this->positionMutex);
    return this->currentPosition;
}

void Player::SetPosition(double seconds) {
    boost::mutex::scoped_lock lock(this->positionMutex);
    this->setPosition = std::max(0.0, seconds);
}

int Player::State() {
    boost::mutex::scoped_lock lock(this->queueMutex);
    return this->state;
}

void Player::ThreadLoop() {
    /* create and open the stream */
    this->stream = Stream::Create();

    BufferPtr buffer;

    if (this->stream->OpenStream(this->url)) {
        /* precache until buffers are full */
        bool keepPrecaching = true;
        while (this->State() == Precache && keepPrecaching) {
            keepPrecaching = this->PreBuffer();
        }

        /* wait until we enter the Playing or Quit state; we may still
        be in the Precache state. */
        {
            boost::mutex::scoped_lock lock(this->queueMutex);

            while (this->state == Precache) {
                this->writeToOutputCondition.wait(lock);
            }
        }

        /* we're ready to go.... */
        bool finished = false;

        while (!finished && !this->Exited()) {
            /* see if we've been asked to seek since the last sample was
            played. if we have, clear our output buffer and seek the
            stream. */
            double position = -1;

            {
                boost::mutex::scoped_lock lock(this->positionMutex);
                position = this->setPosition;
                this->setPosition = -1;
            }

            if (position != -1) {
                this->output->Stop(); /* flush all buffers */
                this->output->Resume(); /* start it back up */

                /* if we've allocated a buffer, but it hasn't been written
                to the output yet, unlock it. this is an important step, and if
                not performed, will result in a deadlock just below while
                waiting for all buffers to complete. */
                if (buffer) {
                    this->OnBufferProcessed(buffer.get());
                    buffer.reset();
                }

                {
                    boost::mutex::scoped_lock lock(this->queueMutex);

                    while (this->lockedBuffers.size() > 0) {
                        writeToOutputCondition.wait(this->queueMutex);
                    }
                }

                this->stream->SetPosition(position);

                {
                    boost::mutex::scoped_lock lock(this->queueMutex);
                    this->prebufferQueue.clear();
                }
            }

            /* let's see if we can find some samples to play */
            if (!buffer) {
                boost::mutex::scoped_lock lock(this->queueMutex);

                /* the buffer queue may already have some available if it was prefetched. */
                if (!this->prebufferQueue.empty()) {
                    buffer = this->prebufferQueue.front();
                    this->prebufferQueue.pop_front();
                }
                /* otherwise, we need to grab a buffer from the stream and add it to the queue */
                else {
                    buffer = this->stream->GetNextProcessedOutputBuffer();
                }

                /* lock it down until it's processed */
                if (buffer) {
                    this->lockedBuffers.push_back(buffer);
                }
            }

            /* if we have a decoded, processed buffer available. let's try to send it to
            the output device. */
            if (buffer) {
                if (this->output->Play(buffer.get(), this)) {
                    /* success! the buffer was accepted by the output.*/
                    /* lock it down so it's not destroyed until the output device lets us
                    know it's done with it. */
                    boost::mutex::scoped_lock lock(this->queueMutex);

                    if (this->lockedBuffers.size() == 1) {
                        this->currentPosition = buffer->Position();
                    }

                    buffer.reset(); /* important! we're done with this one locally. */
                }
                else {
                    /* the output device queue is full. we should block and wait until
                    the output lets us know that it needs more data */
                    boost::mutex::scoped_lock lock(this->queueMutex);
                    writeToOutputCondition.wait(this->queueMutex);
                }
            }
            /* if we're unable to obtain a buffer, it means we're out of data and the
            player is finished. terminate the thread. */
            else {
                finished = true;
            }
        }

        /* if the Quit flag isn't set, that means the stream has ended "naturally", i.e.
        it wasn't stopped by the user. raise the "almost ended" flag. */
        if (!this->Exited()) {
            this->PlaybackAlmostEnded(this);
        }
    }

    /* if the stream failed to open... */
    else {
        this->PlaybackError(this);
    }

    this->state = Player::Quit;

    /* unlock any remaining buffers... see comment above */
    if (buffer) {
        this->OnBufferProcessed(buffer.get());
        buffer.reset();
    }

    /* wait until all remaining buffers have been written, set final state... */
    {
        boost::mutex::scoped_lock lock(this->queueMutex);

        while (this->lockedBuffers.size() > 0) {
            writeToOutputCondition.wait(this->queueMutex);
        }
    }

    this->PlaybackFinished(this);
}

void Player::ReleaseAllBuffers() {
    boost::mutex::scoped_lock lock(this->queueMutex);
    this->lockedBuffers.empty();
}

bool Player::PreBuffer() {
    /* don't prebuffer if the buffer is already full */
    if (this->prebufferQueue.size() < MAX_PREBUFFER_QUEUE_COUNT) {
        BufferPtr newBuffer = this->stream->GetNextProcessedOutputBuffer();

        if (newBuffer) {
            boost::mutex::scoped_lock lock(this->queueMutex);
            this->prebufferQueue.push_back(newBuffer);
        }

        return true;
    }

    return false;
}

bool Player::Exited() {
    boost::mutex::scoped_lock lock(this->queueMutex);
    return (this->state == Player::Quit);
}

void Player::OnBufferProcessed(IBuffer *buffer) {
    bool started = false;
    bool found = false;
    {
        boost::mutex::scoped_lock lock(this->queueMutex);

        /* removes the specified buffer from the list of locked buffers, and also
        lets the stream know it can be recycled. */
        BufferList::iterator it = this->lockedBuffers.begin();
        while (it != this->lockedBuffers.end() && !found) {
            if (it->get() == buffer) {
                found = true;

                if (this->stream) {
                    this->stream->OnBufferProcessedByPlayer(*it);
                }

                it = this->lockedBuffers.erase(it);

                /* this sets the current time in the stream. it does this by grabbing
                the time at the next buffer in the queue */
                if (!this->lockedBuffers.empty()) {
                    this->currentPosition = this->lockedBuffers.front()->Position();
                }
                else {
                    /* if the queue is drained, use the position from the buffer
                    that was just processed */
                    this->currentPosition = ((Buffer*) buffer)->Position();
                }

                /* if the output device's internal buffers are full, it will stop
                accepting new samples. now that a buffer has been processed, we can
                try to enqueue another sample. the thread loop blocks on this condition */
                this->writeToOutputCondition.notify_all();
            }
            else {
                ++it;
            }
        }

        if (!this->notifiedStarted) {
            this->notifiedStarted = true;
            started = true;
        }
    }

    /* we notify our listeners that we've started playing only after the first
    buffer has been consumed. this is because sometimes we precache buffers
    and send them to the output before they are actually processed by the
    output device */
    if (started) {
        this->PlaybackStarted(this);
    }
}
<|endoftext|>


<commit_before>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include "OpenAssetImport.h"

#include <assimp.hpp>      // C++ importer interface
#include <aiScene.h>       // Output data structure
#include <aiPostProcess.h> // Post processing flags
#include <Logger.h>
#include <DefaultLogger.h>
#include <Ogre.h>

using namespace Assimp;

namespace AssImp
{
    OpenAssetImport::OpenAssetImport() :
        importer_(new Importer()),
        logstream_(new AssImpLogStream()),
        loglevels_(Logger::DEBUGGING | Logger::INFO | Logger::ERR | Logger::WARN),
        default_flags_( aiProcess_JoinIdenticalVertices		|
                        aiProcess_Triangulate				|
                        aiProcess_RemoveComponent			|
                        aiProcess_GenNormals				|	// ignored if model already has normals
                        aiProcess_LimitBoneWeights			|
                        aiProcess_SortByPType				|	// remove point and line primitive types
                        aiProcess_ValidateDataStructure         // makes sure that all indices are valid, all animations and bones are linked correctly, all material references are correct...
                      )
    {
        // set up importer
        importer_->SetPropertyInteger(AI_CONFIG_PP_LBW_MAX_WEIGHTS, 4);	// limit bone weights to 4 vertices

        importer_->SetPropertyInteger(			// ignore vertex colours, textures, lights and cameras (for now)
            AI_CONFIG_PP_RVC_FLAGS,
            aiComponent_COLORS		|
            aiComponent_TEXTURES	|
            aiComponent_LIGHTS		|
            aiComponent_CAMERAS
            );

        importer_->SetPropertyInteger(			// ignore point and line primitives (for now)
            AI_CONFIG_PP_SBP_REMOVE,
            aiPrimitiveType_POINT		|
            aiPrimitiveType_LINE
            );

        Assimp::DefaultLogger::get()->attachStream(logstream_, loglevels_);
    }

    OpenAssetImport::~OpenAssetImport()
    {
        Assimp::DefaultLogger::get()->detatchStream(logstream_, loglevels_);
        delete logstream_;
    }

    bool OpenAssetImport::IsSupportedExtension(const QString& filename)
    {
        boost::filesystem::path path(filename.toStdString());
        QString extension = QString(path.extension().c_str()).toLower();

        return importer_->IsExtensionSupported(extension.toStdString());
    }

    void OpenAssetImport::GetMeshData(const QString& file, std::vector<MeshData> &outMeshData)
    {
        const aiScene *scene = importer_->ReadFile(file.toStdString(), default_flags_);

        if (scene)
        {
            const struct aiNode *rootNode = scene->mRootNode;

            aiMatrix4x4 transform;
            GetNodeData(scene, rootNode, file, transform, outMeshData);
        } else
        {
            // report error
            Foundation::RootLogError(importer_->GetErrorString());
        }
    }

    void OpenAssetImport::Import(const void *data, size_t length, const QString &name, const char* hint, const QString &nodeName, std::vector<std::string> &outMeshNames)
    {
        const aiScene *scene = importer_->ReadFileFromMemory(data, length, default_flags_, hint);

        if (scene)
        {
            const struct aiNode *rootNode = scene->mRootNode;

            ImportNode(scene, rootNode, name, nodeName, outMeshNames);
        } else
        {
            // report error
            Foundation::RootLogError(importer_->GetErrorString());
            //return QString(importer_->GetErrorString());
        }
    }

    void OpenAssetImport::GetNodeData(const aiScene *scene, const aiNode *node, const QString& file,
        const aiMatrix4x4 &parentTransform, std::vector<MeshData> &outMeshNames)
    {
        aiMatrix4x4 aiTransform = node->mTransformation;

        aiMatrix4x4 worldTransform =  parentTransform * aiTransform;

        aiVector3D pos;
        aiVector3D scale;
        Vector3df rote;
        aiQuaternion rotq;
        worldTransform.Decompose(scale, rotq, pos);
        Quaternion quat(rotq.x, rotq.y, rotq.z, rotq.w);

        quat.toEuler(rote);
        rote *= RADTODEG;

        if (node->mNumMeshes > 0)
        {
            MeshData data = { file, QString(node->mName.data), Transform(Vector3df(pos.x, pos.y, pos.z), rote, Vector3df(scale.x, scale.y, scale.z)) };
            outMeshNames.push_back(data);
        }

        // import children
        for (int i=0 ; i<node->mNumChildren ; ++i)
            GetNodeData(scene, node->mChildren[i], file, worldTransform, outMeshNames);
    }

    void OpenAssetImport::ImportNode(const aiScene *scene, const aiNode *node, const QString& file,
        const QString &nodeName, std::vector<std::string> &outMeshNames)
    {
        try
        {
   //         boost::filesystem::path path(file.toStdString());
   //         std::string meshname = path.filename() + boost::lexical_cast<std::string>(nodeIdx);
            std::string ogreMeshName = file.toStdString(); //std::string("mesh___") + meshname;
            std::string meshname = ogreMeshName;

            /*if (scene->mNumMaterials > 0)
            {
                // testing getting Ogre material.xml names
                aiString name;
                scene->mMaterials[0]->Get(AI_MATKEY_NAME,name);
                Foundation::RootLogInfo(std::string("Found material ") + std::string(name.data));
            }*/

            //aiMatrix4x4 transform = node->mTransformation;
            if (node->mNumMeshes > 0 && nodeName.compare(QString(node->mName.data)) == 0 && !Ogre::MeshManager::getSingleton().resourceExists(ogreMeshName))
            {
                Ogre::MeshPtr ogreMesh = Ogre::MeshManager::getSingleton().createManual(ogreMeshName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
                ogreMesh->setAutoBuildEdgeLists(false);

                Ogre::Vector3 vmin(std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
                Ogre::Vector3 vmax(std::numeric_limits<float>::min(), std::numeric_limits<float>::min(), std::numeric_limits<float>::min());

                for (unsigned int i=0 ; i<node->mNumMeshes ; ++i)
                {
                    const aiMesh *mesh = scene->mMeshes[node->mMeshes[i]];

                    Ogre::SubMesh *ogreSubmesh = ogreMesh->createSubMesh();

                    ogreSubmesh->useSharedVertices = false;
                    ogreSubmesh->vertexData = new Ogre::VertexData();
                    ogreSubmesh->vertexData->vertexCount = mesh->mNumVertices;
                    Ogre::VertexData *data = ogreSubmesh->vertexData;

                    // Vertex declarations
                    size_t offset = 0;
                    Ogre::VertexDeclaration* decl = data->vertexDeclaration;
                    decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
                    offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
                    decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);

                    offset = 0;
                    for (int tn=0 ; tn<AI_MAX_NUMBER_OF_TEXTURECOORDS ; ++tn)
                    {
                        if (mesh->mTextureCoords[tn])
                        {
                            if (mesh->mNumUVComponents[tn] == 3)
                            {
                                decl->addElement(1, offset, Ogre::VET_FLOAT3, Ogre::VES_TEXTURE_COORDINATES, tn);
                                offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
                            } else
                            {
                                decl->addElement(1, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, tn);
                                offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2);
                            }
                        }
                    }
                    if (mesh->HasTangentsAndBitangents())
                    {
                        decl->addElement(1, offset, Ogre::VET_FLOAT3, Ogre::VES_TANGENT);
                        offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
                        decl->addElement(1, offset, Ogre::VET_FLOAT3, Ogre::VES_BINORMAL);
                    }

                    // Write vertex data to buffer
                    Ogre::HardwareVertexBufferSharedPtr vbuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
                        decl->getVertexSize(0),                     // This value is the size of a vertex in memory
                        data->vertexCount,                          // The number of vertices you'll put into this buffer
                        Ogre::HardwareBuffer::HBU_DYNAMIC // Properties
                        );
                    Ogre::Real *vbData = static_cast<Ogre::Real*>(vbuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));

                    offset = 0;
                    for (unsigned int n=0 ; n<data->vertexCount ; ++n)
                    {
                        vbData[offset++] = mesh->mVertices[n].x;
                        vbData[offset++] = mesh->mVertices[n].y;
                        vbData[offset++] = mesh->mVertices[n].z;

                        vbData[offset++] = mesh->mNormals[n].x;
                        vbData[offset++] = mesh->mNormals[n].y;
                        vbData[offset++] = mesh->mNormals[n].z;

                        vmin.x = std::min(vmin.x, mesh->mVertices[n].x);
                        vmin.y = std::min(vmin.y, mesh->mVertices[n].y);
                        vmin.z = std::min(vmin.z, mesh->mVertices[n].z);

                        vmax.x = std::max(vmax.x, mesh->mVertices[n].x);
                        vmax.y = std::max(vmax.y, mesh->mVertices[n].y);
                        vmax.z = std::max(vmax.z, mesh->mVertices[n].z);
                    }
                    vbuf->unlock();
                    data->vertexBufferBinding->setBinding(0, vbuf);

                    if (mesh->HasTextureCoords(0))
                    {
                    vbuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
                        decl->getVertexSize(1),                     // This value is the size of a vertex in memory
                        data->vertexCount,                          // The number of vertices you'll put into this buffer
                        Ogre::HardwareBuffer::HBU_DYNAMIC // Properties
                        );
                    vbData = static_cast<Ogre::Real*>(vbuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));

                    offset = 0;
                    for (unsigned int n=0 ; n<data->vertexCount ; ++n)
                    {
                        for (int tn=0 ; tn<AI_MAX_NUMBER_OF_TEXTURECOORDS ; ++tn)
                        {
                            if (mesh->mTextureCoords[tn])
                            {
                                if (mesh->mNumUVComponents[tn] == 3)
                                {
                                    vbData[offset++] = mesh->mTextureCoords[tn][n].x;
                                    vbData[offset++] = mesh->mTextureCoords[tn][n].y;
                                    vbData[offset++] = mesh->mTextureCoords[tn][n].z;
                                } else
                                {
                                    vbData[offset++] = mesh->mTextureCoords[tn][n].x;
                                    vbData[offset++] = mesh->mTextureCoords[tn][n].y;
                                }
                            }
                        }

                        if (mesh->HasTangentsAndBitangents())
                        {
                            vbData[offset++] = mesh->mTangents[n].x;
                            vbData[offset++] = mesh->mTangents[n].y;
                            vbData[offset++] = mesh->mTangents[n].z;

                            vbData[offset++] = mesh->mBitangents[n].x;
                            vbData[offset++] = mesh->mBitangents[n].y;
                            vbData[offset++] = mesh->mBitangents[n].z;
                        }
                    }
                    vbuf->unlock();
                    data->vertexBufferBinding->setBinding(1, vbuf);
                    }

                    // indices
                    size_t numIndices = mesh->mNumFaces * 3;            // support only triangles, so 3 indices per face

                    Ogre::HardwareIndexBuffer::IndexType idxType = Ogre::HardwareIndexBuffer::IT_16BIT;
                    if (numIndices > 65535)
                        idxType = Ogre::HardwareIndexBuffer::IT_32BIT;

                    Ogre::HardwareIndexBufferSharedPtr ibuf = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(
                        idxType,                                        // You can use several different value types here
                        numIndices,                                     // The number of indices you'll put in that buffer
                        Ogre::HardwareBuffer::HBU_DYNAMIC     // Properties
                        );

                    if (idxType == Ogre::HardwareIndexBuffer::IT_16BIT)
                    {
                        u16 *idxData = static_cast<u16*>(ibuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));
                        offset = 0;
                        for (int n=0 ; n<mesh->mNumFaces ; ++n)
                        {
                            idxData[offset++] = mesh->mFaces[n].mIndices[0];
                            idxData[offset++] = mesh->mFaces[n].mIndices[1];
                            idxData[offset++] = mesh->mFaces[n].mIndices[2];
                        }
                    } else
                    {
                        u32 *idxData = static_cast<u32*>(ibuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));
                        offset = 0;
                        for (int n=0 ; n<mesh->mNumFaces ; ++n)
                        {
                            idxData[offset++] = mesh->mFaces[n].mIndices[0];
                            idxData[offset++] = mesh->mFaces[n].mIndices[1];
                            idxData[offset++] = mesh->mFaces[n].mIndices[2];
                        }
                    }
                    ibuf->unlock();

                    ogreSubmesh->indexData->indexBuffer = ibuf;         // The pointer to the index buffer
                    ogreSubmesh->indexData->indexCount = numIndices;    // The number of indices we'll use
                    ogreSubmesh->indexData->indexStart = 0;
                }

                if (vmin.x <= vmax.x && vmin.y <= vmax.y && vmin.z <= vmax.z)
                {
                    ogreMesh->_setBounds(Ogre::AxisAlignedBox(vmin, vmax));
                    Ogre::Real maxvertex = std::max(abs(vmax.x), std::max(abs(vmin.x), std::max(abs(vmax.y), std::max(abs(vmin.y), std::max(vmax.z, vmin.z)))));
                    ogreMesh->_setBoundingSphereRadius(maxvertex / 2.f);
                    ogreMesh->load();
                    outMeshNames.push_back(meshname);
                }
            }
        } catch (Ogre::Exception &)
        {
            // error
        }

        // import children
        for (int i=0 ; i<node->mNumChildren ; ++i)
            ImportNode(scene, node->mChildren[i], file, nodeName, outMeshNames);
    }

    void OpenAssetImport::AssImpLogStream::write(const char* message)
    {
        //! \todo doesn't work, check assimp docs for reason -cmayhem
        Foundation::RootLogInfo(message);
    }
}
<commit_msg>Fixed log capturing for Open Asset Import lib.<commit_after>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include "OpenAssetImport.h"

#include <assimp.hpp>      // C++ importer interface
#include <aiScene.h>       // Output data structure
#include <aiPostProcess.h> // Post processing flags
#include <Logger.h>
#include <DefaultLogger.h>
#include <Ogre.h>

using namespace Assimp;

namespace AssImp
{
    OpenAssetImport::OpenAssetImport() :
        importer_(new Importer()),
        logstream_(new AssImpLogStream()),
        loglevels_(Logger::DEBUGGING | Logger::INFO | Logger::ERR | Logger::WARN),
        default_flags_( aiProcess_JoinIdenticalVertices		|
                        aiProcess_Triangulate				|
                        aiProcess_RemoveComponent			|
                        aiProcess_GenNormals				|	// ignored if model already has normals
                        aiProcess_LimitBoneWeights			|
                        aiProcess_SortByPType				|	// remove point and line primitive types
                        aiProcess_ValidateDataStructure         // makes sure that all indices are valid, all animations and bones are linked correctly, all material references are correct...
                      )
    {
        // set up importer
        importer_->SetPropertyInteger(AI_CONFIG_PP_LBW_MAX_WEIGHTS, 4);	// limit bone weights to 4 vertices

        importer_->SetPropertyInteger(			// ignore vertex colours, textures, lights and cameras (for now)
            AI_CONFIG_PP_RVC_FLAGS,
            aiComponent_COLORS		|
            aiComponent_TEXTURES	|
            aiComponent_LIGHTS		|
            aiComponent_CAMERAS
            );

        importer_->SetPropertyInteger(			// ignore point and line primitives (for now)
            AI_CONFIG_PP_SBP_REMOVE,
            aiPrimitiveType_POINT		|
            aiPrimitiveType_LINE
            );
#ifdef _DEBUG
        DefaultLogger::create("", Logger::VERBOSE); // enable debug messages
#else
        DefaultLogger::create();
#endif
        Assimp::DefaultLogger::get()->attachStream(logstream_, loglevels_);
    }

    OpenAssetImport::~OpenAssetImport()
    {
        Assimp::DefaultLogger::get()->detatchStream(logstream_, loglevels_);
        delete logstream_;
        DefaultLogger::kill();
    }

    bool OpenAssetImport::IsSupportedExtension(const QString& filename)
    {
        boost::filesystem::path path(filename.toStdString());
        QString extension = QString(path.extension().c_str()).toLower();

        return importer_->IsExtensionSupported(extension.toStdString());
    }

    void OpenAssetImport::GetMeshData(const QString& file, std::vector<MeshData> &outMeshData)
    {
        const aiScene *scene = importer_->ReadFile(file.toStdString(), default_flags_);

        if (scene)
        {
            const struct aiNode *rootNode = scene->mRootNode;

            aiMatrix4x4 transform;
            GetNodeData(scene, rootNode, file, transform, outMeshData);
        } else
        {
            // report error
            Foundation::RootLogError(importer_->GetErrorString());
        }
    }

    void OpenAssetImport::Import(const void *data, size_t length, const QString &name, const char* hint, const QString &nodeName, std::vector<std::string> &outMeshNames)
    {
        const aiScene *scene = importer_->ReadFileFromMemory(data, length, default_flags_, hint);

        if (scene)
        {
            const struct aiNode *rootNode = scene->mRootNode;

            ImportNode(scene, rootNode, name, nodeName, outMeshNames);
        } else
        {
            // report error
            Foundation::RootLogError(importer_->GetErrorString());
            //return QString(importer_->GetErrorString());
        }
    }

    void OpenAssetImport::GetNodeData(const aiScene *scene, const aiNode *node, const QString& file,
        const aiMatrix4x4 &parentTransform, std::vector<MeshData> &outMeshNames)
    {
        aiMatrix4x4 aiTransform = node->mTransformation;

        aiMatrix4x4 worldTransform =  parentTransform * aiTransform;

        aiVector3D pos;
        aiVector3D scale;
        Vector3df rote;
        aiQuaternion rotq;
        worldTransform.Decompose(scale, rotq, pos);
        Quaternion quat(rotq.x, rotq.y, rotq.z, rotq.w);

        quat.toEuler(rote);
        rote *= RADTODEG;

        if (node->mNumMeshes > 0)
        {
            MeshData data = { file, QString(node->mName.data), Transform(Vector3df(pos.x, pos.y, pos.z), rote, Vector3df(scale.x, scale.y, scale.z)) };
            outMeshNames.push_back(data);
        }

        // import children
        for (int i=0 ; i<node->mNumChildren ; ++i)
            GetNodeData(scene, node->mChildren[i], file, worldTransform, outMeshNames);
    }

    void OpenAssetImport::ImportNode(const aiScene *scene, const aiNode *node, const QString& file,
        const QString &nodeName, std::vector<std::string> &outMeshNames)
    {
        try
        {
   //         boost::filesystem::path path(file.toStdString());
   //         std::string meshname = path.filename() + boost::lexical_cast<std::string>(nodeIdx);
            std::string ogreMeshName = file.toStdString(); //std::string("mesh___") + meshname;
            std::string meshname = ogreMeshName;

            /*if (scene->mNumMaterials > 0)
            {
                // testing getting Ogre material.xml names
                aiString name;
                scene->mMaterials[0]->Get(AI_MATKEY_NAME,name);
                Foundation::RootLogInfo(std::string("Found material ") + std::string(name.data));
            }*/

            //aiMatrix4x4 transform = node->mTransformation;
            if (node->mNumMeshes > 0 && nodeName.compare(QString(node->mName.data)) == 0 && !Ogre::MeshManager::getSingleton().resourceExists(ogreMeshName))
            {
                Ogre::MeshPtr ogreMesh = Ogre::MeshManager::getSingleton().createManual(ogreMeshName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
                ogreMesh->setAutoBuildEdgeLists(false);

                Ogre::Vector3 vmin(std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
                Ogre::Vector3 vmax(std::numeric_limits<float>::min(), std::numeric_limits<float>::min(), std::numeric_limits<float>::min());

                for (unsigned int i=0 ; i<node->mNumMeshes ; ++i)
                {
                    const aiMesh *mesh = scene->mMeshes[node->mMeshes[i]];

                    Ogre::SubMesh *ogreSubmesh = ogreMesh->createSubMesh();

                    ogreSubmesh->useSharedVertices = false;
                    ogreSubmesh->vertexData = new Ogre::VertexData();
                    ogreSubmesh->vertexData->vertexCount = mesh->mNumVertices;
                    Ogre::VertexData *data = ogreSubmesh->vertexData;

                    // Vertex declarations
                    size_t offset = 0;
                    Ogre::VertexDeclaration* decl = data->vertexDeclaration;
                    decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
                    offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
                    decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);

                    offset = 0;
                    for (int tn=0 ; tn<AI_MAX_NUMBER_OF_TEXTURECOORDS ; ++tn)
                    {
                        if (mesh->mTextureCoords[tn])
                        {
                            if (mesh->mNumUVComponents[tn] == 3)
                            {
                                decl->addElement(1, offset, Ogre::VET_FLOAT3, Ogre::VES_TEXTURE_COORDINATES, tn);
                                offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
                            } else
                            {
                                decl->addElement(1, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, tn);
                                offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2);
                            }
                        }
                    }
                    if (mesh->HasTangentsAndBitangents())
                    {
                        decl->addElement(1, offset, Ogre::VET_FLOAT3, Ogre::VES_TANGENT);
                        offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
                        decl->addElement(1, offset, Ogre::VET_FLOAT3, Ogre::VES_BINORMAL);
                    }

                    // Write vertex data to buffer
                    Ogre::HardwareVertexBufferSharedPtr vbuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
                        decl->getVertexSize(0),                     // This value is the size of a vertex in memory
                        data->vertexCount,                          // The number of vertices you'll put into this buffer
                        Ogre::HardwareBuffer::HBU_DYNAMIC // Properties
                        );
                    Ogre::Real *vbData = static_cast<Ogre::Real*>(vbuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));

                    offset = 0;
                    for (unsigned int n=0 ; n<data->vertexCount ; ++n)
                    {
                        vbData[offset++] = mesh->mVertices[n].x;
                        vbData[offset++] = mesh->mVertices[n].y;
                        vbData[offset++] = mesh->mVertices[n].z;

                        vbData[offset++] = mesh->mNormals[n].x;
                        vbData[offset++] = mesh->mNormals[n].y;
                        vbData[offset++] = mesh->mNormals[n].z;

                        vmin.x = std::min(vmin.x, mesh->mVertices[n].x);
                        vmin.y = std::min(vmin.y, mesh->mVertices[n].y);
                        vmin.z = std::min(vmin.z, mesh->mVertices[n].z);

                        vmax.x = std::max(vmax.x, mesh->mVertices[n].x);
                        vmax.y = std::max(vmax.y, mesh->mVertices[n].y);
                        vmax.z = std::max(vmax.z, mesh->mVertices[n].z);
                    }
                    vbuf->unlock();
                    data->vertexBufferBinding->setBinding(0, vbuf);

                    if (mesh->HasTextureCoords(0))
                    {
                    vbuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
                        decl->getVertexSize(1),                     // This value is the size of a vertex in memory
                        data->vertexCount,                          // The number of vertices you'll put into this buffer
                        Ogre::HardwareBuffer::HBU_DYNAMIC // Properties
                        );
                    vbData = static_cast<Ogre::Real*>(vbuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));

                    offset = 0;
                    for (unsigned int n=0 ; n<data->vertexCount ; ++n)
                    {
                        for (int tn=0 ; tn<AI_MAX_NUMBER_OF_TEXTURECOORDS ; ++tn)
                        {
                            if (mesh->mTextureCoords[tn])
                            {
                                if (mesh->mNumUVComponents[tn] == 3)
                                {
                                    vbData[offset++] = mesh->mTextureCoords[tn][n].x;
                                    vbData[offset++] = mesh->mTextureCoords[tn][n].y;
                                    vbData[offset++] = mesh->mTextureCoords[tn][n].z;
                                } else
                                {
                                    vbData[offset++] = mesh->mTextureCoords[tn][n].x;
                                    vbData[offset++] = mesh->mTextureCoords[tn][n].y;
                                }
                            }
                        }

                        if (mesh->HasTangentsAndBitangents())
                        {
                            vbData[offset++] = mesh->mTangents[n].x;
                            vbData[offset++] = mesh->mTangents[n].y;
                            vbData[offset++] = mesh->mTangents[n].z;

                            vbData[offset++] = mesh->mBitangents[n].x;
                            vbData[offset++] = mesh->mBitangents[n].y;
                            vbData[offset++] = mesh->mBitangents[n].z;
                        }
                    }
                    vbuf->unlock();
                    data->vertexBufferBinding->setBinding(1, vbuf);
                    }

                    // indices
                    size_t numIndices = mesh->mNumFaces * 3;            // support only triangles, so 3 indices per face

                    Ogre::HardwareIndexBuffer::IndexType idxType = Ogre::HardwareIndexBuffer::IT_16BIT;
                    if (numIndices > 65535)
                        idxType = Ogre::HardwareIndexBuffer::IT_32BIT;

                    Ogre::HardwareIndexBufferSharedPtr ibuf = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(
                        idxType,                                        // You can use several different value types here
                        numIndices,                                     // The number of indices you'll put in that buffer
                        Ogre::HardwareBuffer::HBU_DYNAMIC     // Properties
                        );

                    if (idxType == Ogre::HardwareIndexBuffer::IT_16BIT)
                    {
                        u16 *idxData = static_cast<u16*>(ibuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));
                        offset = 0;
                        for (int n=0 ; n<mesh->mNumFaces ; ++n)
                        {
                            idxData[offset++] = mesh->mFaces[n].mIndices[0];
                            idxData[offset++] = mesh->mFaces[n].mIndices[1];
                            idxData[offset++] = mesh->mFaces[n].mIndices[2];
                        }
                    } else
                    {
                        u32 *idxData = static_cast<u32*>(ibuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));
                        offset = 0;
                        for (int n=0 ; n<mesh->mNumFaces ; ++n)
                        {
                            idxData[offset++] = mesh->mFaces[n].mIndices[0];
                            idxData[offset++] = mesh->mFaces[n].mIndices[1];
                            idxData[offset++] = mesh->mFaces[n].mIndices[2];
                        }
                    }
                    ibuf->unlock();

                    ogreSubmesh->indexData->indexBuffer = ibuf;         // The pointer to the index buffer
                    ogreSubmesh->indexData->indexCount = numIndices;    // The number of indices we'll use
                    ogreSubmesh->indexData->indexStart = 0;
                }

                if (vmin.x <= vmax.x && vmin.y <= vmax.y && vmin.z <= vmax.z)
                {
                    ogreMesh->_setBounds(Ogre::AxisAlignedBox(vmin, vmax));
                    Ogre::Real maxvertex = std::max(abs(vmax.x), std::max(abs(vmin.x), std::max(abs(vmax.y), std::max(abs(vmin.y), std::max(vmax.z, vmin.z)))));
                    ogreMesh->_setBoundingSphereRadius(maxvertex / 2.f);
                    ogreMesh->load();
                    outMeshNames.push_back(meshname);
                }
            }
        } catch (Ogre::Exception &)
        {
            // error
        }

        // import children
        for (int i=0 ; i<node->mNumChildren ; ++i)
            ImportNode(scene, node->mChildren[i], file, nodeName, outMeshNames);
    }

    void OpenAssetImport::AssImpLogStream::write(const char* message)
    {
        //! \todo doesn't work, check assimp docs for reason -cmayhem
        Foundation::RootLogInfo(message);
    }
}
<|endoftext|>


<commit_before>#if HAVE_CONFIG_H
#include <config.h>
#endif

#include <xorg/gtest/xorg-gtest.h>

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xfixes.h>
#include <X11/extensions/XInput2.h>

#include "barriers-common.h"
#include "xit-event.h"
#include "helpers.h"

using namespace xorg::testing::evemu;

class BarrierNotify : public BarrierTest {};

#define ASSERT_PTR_POS(x, y)                            \
    QueryPointerPosition(dpy, &root_x, &root_y);        \
    ASSERT_EQ(x, root_x);                               \
    ASSERT_EQ(y, root_y);

TEST_F(BarrierNotify, ReceivesNotifyEvents)
{
    XORG_TESTCASE("Ensure that we receive BarrierNotify events\n"
                  "when barriers are hit.\n");

    ::Display *dpy = Display();
    Window root = DefaultRootWindow(dpy);
    PointerBarrier barrier;

    XIWarpPointer(dpy, VIRTUAL_CORE_POINTER_ID, None, root, 0, 0, 0, 0, 30, 30);

    barrier = XFixesCreatePointerBarrier(dpy, root, 20, 20, 20, 40, 0, 0, NULL);
    XSync(dpy, False);

    XIEventMask mask;
    mask.deviceid = XIAllMasterDevices;
    mask.mask_len = XIMaskLen(XI_LASTEVENT);
    mask.mask = reinterpret_cast<unsigned char*>(calloc(mask.mask_len, 1));
    XISetMask(mask.mask, XI_BarrierHitNotify);
    XISelectEvents(dpy, root, &mask, 1);
    free(mask.mask);
    XSync(dpy, False);

    dev->PlayOne(EV_REL, REL_X, -40, True);

    /* Ensure we have a BarrierHitNotify on our hands. */
    XITEvent<XIBarrierNotifyEvent> event(dpy, GenericEvent, xi2_opcode, XI_BarrierHitNotify);
    ASSERT_EQ(barrier, event.ev->barrier);
    ASSERT_EQ(20, event.ev->x);
    ASSERT_EQ(-40, event.ev->dx);

    XFixesDestroyPointerBarrier(dpy, barrier);
}

TEST_F(BarrierNotify, CorrectEventIDs)
{
    XORG_TESTCASE("Ensure that barrier event IDs have correct and "
                  "sequential values, and that multiple chained hits "
                  "have the same event ID\n");

    ::Display *dpy = Display();
    Window root = DefaultRootWindow(dpy);
    PointerBarrier barrier;

    XIWarpPointer(dpy, VIRTUAL_CORE_POINTER_ID, None, root, 0, 0, 0, 0, 30, 30);

    barrier = XFixesCreatePointerBarrier(dpy, root, 20, 20, 20, 40, 0, 0, NULL);
    XSync(dpy, False);

    XIEventMask mask;
    mask.deviceid = XIAllMasterDevices;
    mask.mask_len = XIMaskLen(XI_LASTEVENT);
    mask.mask = reinterpret_cast<unsigned char*>(calloc(mask.mask_len, 1));
    XISetMask(mask.mask, XI_BarrierHitNotify);
    XISetMask(mask.mask, XI_BarrierLeaveNotify);
    XISelectEvents(dpy, root, &mask, 1);
    free(mask.mask);
    XSync(dpy, False);

    /* Ensure we have a bunch of BarrierHitNotifys on our hands. */
    for (int i = 0; i < 10; i++) {
        dev->PlayOne(EV_REL, REL_X, -40, True);

        /* Ensure we have a BarrierHitNotify on our hands. */
        XITEvent<XIBarrierNotifyEvent> event(dpy, GenericEvent, xi2_opcode, XI_BarrierHitNotify);
        ASSERT_EQ(barrier, event.ev->barrier);
        ASSERT_EQ(20, event.ev->x);
        ASSERT_EQ(30, event.ev->y);
        ASSERT_EQ(-40, event.ev->dx);
        ASSERT_EQ(0, event.ev->dy);
        ASSERT_EQ(1, event.ev->event_id);
    }

    /* Move outside the hitbox, and ensure that we
     * get a BarrierNewEventNotify */
    dev->PlayOne(EV_REL, REL_X, 20, True);
    XITEvent<XIBarrierNotifyEvent> event(dpy, GenericEvent, xi2_opcode, XI_BarrierLeaveNotify);
    ASSERT_EQ(barrier, event.ev->barrier);
    ASSERT_EQ(2, event.ev->event_id);

    for (int i = 0; i < 10; i++) {
        dev->PlayOne(EV_REL, REL_X, -40, True);

        XITEvent<XIBarrierNotifyEvent> event(dpy, GenericEvent, xi2_opcode, XI_BarrierHitNotify);
        ASSERT_EQ(barrier, event.ev->barrier);
        ASSERT_EQ(2, event.ev->event_id);
    }

    /* Ensure that we're still inside the hit box. Event ID
     * should stay the same on such a minor change. */
    dev->PlayOne(EV_REL, REL_X, 1, True);

    for (int i = 0; i < 10; i++) {
        dev->PlayOne(EV_REL, REL_X, -40, True);

        XITEvent<XIBarrierNotifyEvent> event(dpy, GenericEvent, xi2_opcode, XI_BarrierHitNotify);
        ASSERT_EQ(barrier, event.ev->barrier);
        ASSERT_EQ(2, event.ev->event_id);
    }

    XFixesDestroyPointerBarrier(dpy, barrier);
}

TEST_F(BarrierNotify, BarrierReleases)
{
    XORG_TESTCASE("Ensure that releasing barriers works without "
                  "erroring out and allows pointer movement over "
                  "the barrier, and that we properly get a "
                  "XI_BarrierPointerReleasedNotify.\n");

    ::Display *dpy = Display();
    Window root = DefaultRootWindow(dpy);
    PointerBarrier barrier;

    XIEventMask mask;
    mask.deviceid = XIAllMasterDevices;
    mask.mask_len = XIMaskLen(XI_LASTEVENT);
    mask.mask = reinterpret_cast<unsigned char*>(calloc(mask.mask_len, 1));
    XISetMask(mask.mask, XI_BarrierHitNotify);
    XISetMask(mask.mask, XI_BarrierPointerReleasedNotify);
    XISetMask(mask.mask, XI_BarrierLeaveNotify);
    XISelectEvents(dpy, root, &mask, 1);
    free(mask.mask);
    XSync(dpy, False);

    XIWarpPointer(dpy, VIRTUAL_CORE_POINTER_ID, None, root, 0, 0, 0, 0, 30, 30);

    barrier = XFixesCreatePointerBarrier(dpy, root, 20, 20, 20, 40, 0, 0, NULL);
    XSync(dpy, False);

    dev->PlayOne(EV_REL, REL_X, -40, True);
    {
        XITEvent<XIBarrierNotifyEvent> event(dpy, GenericEvent, xi2_opcode, XI_BarrierHitNotify);
        ASSERT_EQ(barrier, event.ev->barrier);
        ASSERT_EQ(1, event.ev->event_id);
    }

    XIBarrierReleasePointer(dpy, barrier, 1, VIRTUAL_CORE_POINTER_ID);
    XSync(dpy, False);

    dev->PlayOne(EV_REL, REL_X, -40, True);
    {
        XITEvent<XIBarrierNotifyEvent> event(dpy, GenericEvent, xi2_opcode, XI_BarrierPointerReleasedNotify);
        ASSERT_EQ(barrier, event.ev->barrier);
        ASSERT_EQ(1, event.ev->event_id);
    }

    /* Immediately afterwards, we should have a new event notify
     * because we exited the hit box */
    {
        XITEvent<XIBarrierNotifyEvent> event(dpy, GenericEvent, xi2_opcode, XI_BarrierLeaveNotify);
        ASSERT_EQ(barrier, event.ev->barrier);
        ASSERT_EQ(2, event.ev->event_id);
    }

    XFixesDestroyPointerBarrier(dpy, barrier);
}
<commit_msg>Fix up for new protocol.<commit_after>#if HAVE_CONFIG_H
#include <config.h>
#endif

#include <xorg/gtest/xorg-gtest.h>

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xfixes.h>
#include <X11/extensions/XInput2.h>

#include "barriers-common.h"
#include "xit-event.h"
#include "helpers.h"

using namespace xorg::testing::evemu;

class BarrierNotify : public BarrierTest {};

#define ASSERT_PTR_POS(x, y)                            \
    QueryPointerPosition(dpy, &root_x, &root_y);        \
    ASSERT_EQ(x, root_x);                               \
    ASSERT_EQ(y, root_y);

TEST_F(BarrierNotify, ReceivesNotifyEvents)
{
    XORG_TESTCASE("Ensure that we receive BarrierNotify events\n"
                  "when barriers are hit.\n");

    ::Display *dpy = Display();
    Window root = DefaultRootWindow(dpy);
    PointerBarrier barrier;

    XIWarpPointer(dpy, VIRTUAL_CORE_POINTER_ID, None, root, 0, 0, 0, 0, 30, 30);

    barrier = XFixesCreatePointerBarrier(dpy, root, 20, 20, 20, 40, 0, 0, NULL);
    XSync(dpy, False);

    XIEventMask mask;
    mask.deviceid = XIAllMasterDevices;
    mask.mask_len = XIMaskLen(XI_LASTEVENT);
    mask.mask = reinterpret_cast<unsigned char*>(calloc(mask.mask_len, 1));
    XISetMask(mask.mask, XI_BarrierHit);
    XISelectEvents(dpy, root, &mask, 1);
    free(mask.mask);
    XSync(dpy, False);

    dev->PlayOne(EV_REL, REL_X, -40, True);

    /* Ensure we have a BarrierHit on our hands. */
    XITEvent<XIBarrierEvent> event(dpy, GenericEvent, xi2_opcode, XI_BarrierHit);
    ASSERT_EQ(barrier, event.ev->barrier);
    ASSERT_EQ(20, event.ev->root_x);
    ASSERT_EQ(-40, event.ev->dx);

    XFixesDestroyPointerBarrier(dpy, barrier);
}

TEST_F(BarrierNotify, CorrectEventIDs)
{
    XORG_TESTCASE("Ensure that barrier event IDs have correct and "
                  "sequential values, and that multiple chained hits "
                  "have the same event ID\n");

    ::Display *dpy = Display();
    Window root = DefaultRootWindow(dpy);
    PointerBarrier barrier;

    XIWarpPointer(dpy, VIRTUAL_CORE_POINTER_ID, None, root, 0, 0, 0, 0, 30, 30);

    barrier = XFixesCreatePointerBarrier(dpy, root, 20, 20, 20, 40, 0, 0, NULL);
    XSync(dpy, False);

    XIEventMask mask;
    mask.deviceid = XIAllMasterDevices;
    mask.mask_len = XIMaskLen(XI_LASTEVENT);
    mask.mask = reinterpret_cast<unsigned char*>(calloc(mask.mask_len, 1));
    XISetMask(mask.mask, XI_BarrierHit);
    XISetMask(mask.mask, XI_BarrierLeave);
    XISelectEvents(dpy, root, &mask, 1);
    free(mask.mask);
    XSync(dpy, False);

    /* Ensure we have a bunch of BarrierHits on our hands. */
    for (int i = 0; i < 10; i++) {
        dev->PlayOne(EV_REL, REL_X, -40, True);

        /* Ensure we have a BarrierHit on our hands. */
        XITEvent<XIBarrierEvent> event(dpy, GenericEvent, xi2_opcode, XI_BarrierHit);
        ASSERT_EQ(barrier, event.ev->barrier);
        ASSERT_EQ(20, event.ev->root_x);
        ASSERT_EQ(30, event.ev->root_y);
        ASSERT_EQ(-40, event.ev->dx);
        ASSERT_EQ(0, event.ev->dy);
        ASSERT_EQ(1, event.ev->event_id);
    }

    /* Move outside the hitbox, and ensure that we
     * get a BarrierNewEvent */
    dev->PlayOne(EV_REL, REL_X, 20, True);
    XITEvent<XIBarrierEvent> event(dpy, GenericEvent, xi2_opcode, XI_BarrierLeave);
    ASSERT_EQ(barrier, event.ev->barrier);
    ASSERT_EQ(2, event.ev->event_id);

    for (int i = 0; i < 10; i++) {
        dev->PlayOne(EV_REL, REL_X, -40, True);

        XITEvent<XIBarrierEvent> event(dpy, GenericEvent, xi2_opcode, XI_BarrierHit);
        ASSERT_EQ(barrier, event.ev->barrier);
        ASSERT_EQ(2, event.ev->event_id);
    }

    /* Ensure that we're still inside the hit box. Event ID
     * should stay the same on such a minor change. */
    dev->PlayOne(EV_REL, REL_X, 1, True);

    for (int i = 0; i < 10; i++) {
        dev->PlayOne(EV_REL, REL_X, -40, True);

        XITEvent<XIBarrierEvent> event(dpy, GenericEvent, xi2_opcode, XI_BarrierHit);
        ASSERT_EQ(barrier, event.ev->barrier);
        ASSERT_EQ(2, event.ev->event_id);
    }

    XFixesDestroyPointerBarrier(dpy, barrier);
}

TEST_F(BarrierNotify, BarrierReleases)
{
    XORG_TESTCASE("Ensure that releasing barriers works without "
                  "erroring out and allows pointer movement over "
                  "the barrier, and that we properly get a "
                  "XI_BarrierPointerReleased.\n");

    ::Display *dpy = Display();
    Window root = DefaultRootWindow(dpy);
    PointerBarrier barrier;

    XIEventMask mask;
    mask.deviceid = XIAllMasterDevices;
    mask.mask_len = XIMaskLen(XI_LASTEVENT);
    mask.mask = reinterpret_cast<unsigned char*>(calloc(mask.mask_len, 1));
    XISetMask(mask.mask, XI_BarrierHit);
    XISetMask(mask.mask, XI_BarrierPointerReleased);
    XISetMask(mask.mask, XI_BarrierLeave);
    XISelectEvents(dpy, root, &mask, 1);
    free(mask.mask);
    XSync(dpy, False);

    XIWarpPointer(dpy, VIRTUAL_CORE_POINTER_ID, None, root, 0, 0, 0, 0, 30, 30);

    barrier = XFixesCreatePointerBarrier(dpy, root, 20, 20, 20, 40, 0, 0, NULL);
    XSync(dpy, False);

    dev->PlayOne(EV_REL, REL_X, -40, True);
    {
        XITEvent<XIBarrierEvent> event(dpy, GenericEvent, xi2_opcode, XI_BarrierHit);
        ASSERT_EQ(barrier, event.ev->barrier);
        ASSERT_EQ(1, event.ev->event_id);
    }

    XIBarrierReleasePointer(dpy, barrier, 1, VIRTUAL_CORE_POINTER_ID);
    XSync(dpy, False);

    dev->PlayOne(EV_REL, REL_X, -40, True);
    {
        XITEvent<XIBarrierEvent> event(dpy, GenericEvent, xi2_opcode, XI_BarrierPointerReleased);
        ASSERT_EQ(barrier, event.ev->barrier);
        ASSERT_EQ(1, event.ev->event_id);
    }

    /* Immediately afterwards, we should have a new event
     * because we exited the hit box */
    {
        XITEvent<XIBarrierEvent> event(dpy, GenericEvent, xi2_opcode, XI_BarrierLeave);
        ASSERT_EQ(barrier, event.ev->barrier);
        ASSERT_EQ(2, event.ev->event_id);
    }

    XFixesDestroyPointerBarrier(dpy, barrier);
}
<|endoftext|>


<commit_before>#if !defined(__CINT__) || defined(__MAKECINT__)
// ROOT includes
#include "TSystem.h"
#include "TROOT.h"
#include "TString.h"

#endif

//_____________________________
void LoadRootAnalysis()
{
  gSystem->Load("libTree");
  gSystem->Load("libGeom");
  gSystem->Load("libVMC");
  gSystem->Load("libPhysics");
  gSystem->Load("libProof");
}

//_____________________________
void LoadAnalysis(const char* option = "")
{
  gSystem->Load("libANALYSIS.so");
  gSystem->Load("libOADB.so");
  gSystem->Load("libANALYSISalice.so");
  gSystem->Load("libCORRFW.so");
  TString opt(option);
  opt.ToUpper();
  if ( opt.Contains("PWG") ) {
    gSystem->Load("libPWGmuon.so");
  }
  if ( opt.Contains("PWGPP") ) {
    gSystem->Load("libPWGPPMUONlite.so");
  }
}

//_____________________________
void IncludeAliroot()
{
  gSystem->AddIncludePath("-I${ALICE_ROOT}/include");
  gSystem->AddIncludePath("-I${ALICE_INSTALL}/include");
  gSystem->AddIncludePath("-I${ALICE_BUILD}/include");
}

//_____________________________
void IncludeMuon()
{
  gSystem->AddIncludePath("-I${ALICE_ROOT}/MUON");
}

//_____________________________
void LoadLibsForMuonQA ( const char* option )
{
  TString opt(option);
  opt.ToLower();
  if ( opt.Contains("maketrend") ) {
    IncludeAliroot();
    gSystem->AddIncludePath("-I${ALICE_ROOT}/PWGPP/MUON/lite");
    LoadRootAnalysis();
    LoadAnalysis("PWGPP");
  }
  if ( opt.Contains("trigtrend") ) {
    IncludeAliroot();
    IncludeMuon();
    LoadAnalysis("PWG");
    gSystem->Load("libPWGmuondep.so");
  }
  if (opt.Contains("tracktrend") ) {
    IncludeAliroot();
    LoadAnalysis("PWG");
  }
}
<commit_msg>Check aliroot environmental variables before including path<commit_after>#if !defined(__CINT__) || defined(__MAKECINT__)
// ROOT includes
#include "TSystem.h"
#include "TROOT.h"
#include "TString.h"

#endif

//_____________________________
void LoadRootAnalysis()
{
  gSystem->Load("libTree");
  gSystem->Load("libGeom");
  gSystem->Load("libVMC");
  gSystem->Load("libPhysics");
  gSystem->Load("libProof");
}

//_____________________________
void LoadAnalysis(const char* option = "")
{
  gSystem->Load("libANALYSIS.so");
  gSystem->Load("libOADB.so");
  gSystem->Load("libANALYSISalice.so");
  gSystem->Load("libCORRFW.so");
  TString opt(option);
  opt.ToUpper();
  if ( opt.Contains("PWG") ) {
    gSystem->Load("libPWGmuon.so");
  }
  if ( opt.Contains("PWGPP") ) {
    gSystem->Load("libPWGPPMUONlite.so");
  }
}

//_____________________________
void IncludeAliroot()
{
  TString envList[3] = {"ALICE_ROOT","ALICE_INSTALL","ALICE_BUILD"};
  for ( Int_t ienv=0; ienv<3; ienv++ ) {
    if ( ! gSystem->Getenv(envList[ienv].Data()) ) continue;
    if ( gSystem->AccessPathName(gSystem->ExpandPathName(Form("${%s}/include",envList[ienv].Data()))) ) continue;
    gSystem->AddIncludePath(Form("-I${%s}/include",envList[ienv].Data()));
  }
}

//_____________________________
void IncludeMuon()
{
  gSystem->AddIncludePath("-I${ALICE_ROOT}/MUON");
}

//_____________________________
void LoadLibsForMuonQA ( const char* option )
{
  TString opt(option);
  opt.ToLower();
  if ( opt.Contains("maketrend") ) {
    IncludeAliroot();
    gSystem->AddIncludePath("-I${ALICE_ROOT}/PWGPP/MUON/lite");
    LoadRootAnalysis();
    LoadAnalysis("PWGPP");
  }
  if ( opt.Contains("trigtrend") ) {
    IncludeAliroot();
    IncludeMuon();
    LoadAnalysis("PWG");
    gSystem->Load("libPWGmuondep.so");
  }
  if (opt.Contains("tracktrend") ) {
    IncludeAliroot();
    LoadAnalysis("PWG");
  }
}
<|endoftext|>


<commit_before>#if ! defined (__CINT__) || defined (__MAKECINT__)
#include "TError.h"
#include "AliAnalysisManager.h"
#include "AliAnalysisDataContainer.h"
#include "AliLog.h"
#include "PWGPP/TRD/AliTRDpwgppHelper.h"
#include "PWGPP/TRD/AliTRDefficiency.h"
#include "PWGPP/TRD/AliTRDefficiencyMC.h"
#include "PWGPP/TRD/AliTRDmultiplicity.h"
#endif

void AddTRDefficiency(AliAnalysisManager *mgr, Int_t map, AliAnalysisDataContainer **ci/*, AliAnalysisDataContainer **co*/)
{
  Info("AddTRDefficiency", Form("[0]=\"%s\" [1]=\"%s\" [2]=\"%s\" [3]=\"%s\" [4]=\"%s\"", ci[0]->GetName(), ci[1]->GetName(), ci[2]->GetName(), ci[3]->GetName(), ci[4]->GetName()));

  AliAnalysisDataContainer *evInfoContainer = ci[3];
  AliTRDrecoTask *eff(NULL);
  mgr->AddTask(eff = new AliTRDefficiency((char*)"TRDefficiency"));
  res->SetMCdata((Bool_t)mgr->GetMCtruthEventHandler());
  eff->SetDebugLevel(0);
  //AliLog::SetClassDebugLevel("AliTRDefficiency", 5);
  Int_t trackStatus = 0; // barrel tracks
//                    = 1; // kink tracks
//                    = 2; // SA tracks
  mgr->ConnectInput(eff, 0, mgr->GetCommonInputContainer());  // connect main (ESD) container
  mgr->ConnectInput(eff, 1, ci[trackStatus]);                 // conect track info container
  mgr->ConnectInput(eff, 2, evInfoContainer);                 // conect event info container
  mgr->ConnectInput(eff, 3, ci[4]);                 // conect clusters container
  mgr->ConnectOutput(eff,1, mgr->CreateContainer(eff->GetName(), TObjArray::Class(), AliAnalysisManager::kOutputContainer, Form("%s:TRD_Performance", mgr->GetCommonFileName())));

  // TRD combined tracking efficiency
  if(mgr->GetMCtruthEventHandler() && TESTBIT(map, AliTRDpwgppHelper::kEfficiencyMC)) {
    mgr->AddTask(eff = new AliTRDefficiencyMC((char*)"TRDefficiencyMC"));
    eff->SetDebugLevel(0);
    //AliLog::SetClassDebugLevel("AliTRDefficiencyMC", 5);

    // Create containers for input/output
    mgr->ConnectInput(eff, 0, mgr->GetCommonInputContainer());
    mgr->ConnectInput(eff, 1, ci[trackStatus]);
    mgr->ConnectInput(eff, 2, evInfoContainer);
    mgr->ConnectOutput(eff, 1, mgr->CreateContainer(eff->GetName(), TObjArray::Class(), AliAnalysisManager::kOutputContainer, Form("%s:TRD_Performance", mgr->GetCommonFileName())));
  }

  // TRD single track selection
  if(!(TESTBIT(map, AliTRDpwgppHelper::kMultiplicity))) return;

  mgr->AddTask(eff = new AliTRDmultiplicity((char*)"TRDmultiplicity"));
  eff->SetDebugLevel(0);
  //AliLog::SetClassDebugLevel("AliTRDmultiplicity", 5);
  mgr->ConnectInput(eff, 0, mgr->GetCommonInputContainer());
  mgr->ConnectInput(eff, 1, ci[0]);
  mgr->ConnectOutput(eff, 1, mgr->CreateContainer(eff->GetName(), TObjArray::Class(), AliAnalysisManager::kOutputContainer, Form("%s:TRD_Calibration", mgr->GetCommonFileName())));
}

<commit_msg>fix compilation<commit_after>#if ! defined (__CINT__) || defined (__MAKECINT__)
#include "TError.h"
#include "AliAnalysisManager.h"
#include "AliAnalysisDataContainer.h"
#include "AliLog.h"
#include "PWGPP/TRD/AliTRDpwgppHelper.h"
#include "PWGPP/TRD/AliTRDefficiency.h"
#include "PWGPP/TRD/AliTRDefficiencyMC.h"
#include "PWGPP/TRD/AliTRDmultiplicity.h"
#endif

void AddTRDefficiency(AliAnalysisManager *mgr, Int_t map, AliAnalysisDataContainer **ci/*, AliAnalysisDataContainer **co*/)
{
  Info("AddTRDefficiency", Form("[0]=\"%s\" [1]=\"%s\" [2]=\"%s\" [3]=\"%s\" [4]=\"%s\"", ci[0]->GetName(), ci[1]->GetName(), ci[2]->GetName(), ci[3]->GetName(), ci[4]->GetName()));

  AliAnalysisDataContainer *evInfoContainer = ci[3];
  AliTRDrecoTask *eff(NULL);
  mgr->AddTask(eff = new AliTRDefficiency((char*)"TRDefficiency"));
  eff->SetMCdata((Bool_t)mgr->GetMCtruthEventHandler());
  eff->SetDebugLevel(0);
  //AliLog::SetClassDebugLevel("AliTRDefficiency", 5);
  Int_t trackStatus = 0; // barrel tracks
//                    = 1; // kink tracks
//                    = 2; // SA tracks
  mgr->ConnectInput(eff, 0, mgr->GetCommonInputContainer());  // connect main (ESD) container
  mgr->ConnectInput(eff, 1, ci[trackStatus]);                 // conect track info container
  mgr->ConnectInput(eff, 2, evInfoContainer);                 // conect event info container
  mgr->ConnectInput(eff, 3, ci[4]);                 // conect clusters container
  mgr->ConnectOutput(eff,1, mgr->CreateContainer(eff->GetName(), TObjArray::Class(), AliAnalysisManager::kOutputContainer, Form("%s:TRD_Performance", mgr->GetCommonFileName())));

  // TRD combined tracking efficiency
  if(mgr->GetMCtruthEventHandler() && TESTBIT(map, AliTRDpwgppHelper::kEfficiencyMC)) {
    mgr->AddTask(eff = new AliTRDefficiencyMC((char*)"TRDefficiencyMC"));
    eff->SetDebugLevel(0);
    //AliLog::SetClassDebugLevel("AliTRDefficiencyMC", 5);

    // Create containers for input/output
    mgr->ConnectInput(eff, 0, mgr->GetCommonInputContainer());
    mgr->ConnectInput(eff, 1, ci[trackStatus]);
    mgr->ConnectInput(eff, 2, evInfoContainer);
    mgr->ConnectOutput(eff, 1, mgr->CreateContainer(eff->GetName(), TObjArray::Class(), AliAnalysisManager::kOutputContainer, Form("%s:TRD_Performance", mgr->GetCommonFileName())));
  }

  // TRD single track selection
  if(!(TESTBIT(map, AliTRDpwgppHelper::kMultiplicity))) return;

  mgr->AddTask(eff = new AliTRDmultiplicity((char*)"TRDmultiplicity"));
  eff->SetDebugLevel(0);
  //AliLog::SetClassDebugLevel("AliTRDmultiplicity", 5);
  mgr->ConnectInput(eff, 0, mgr->GetCommonInputContainer());
  mgr->ConnectInput(eff, 1, ci[0]);
  mgr->ConnectOutput(eff, 1, mgr->CreateContainer(eff->GetName(), TObjArray::Class(), AliAnalysisManager::kOutputContainer, Form("%s:TRD_Calibration", mgr->GetCommonFileName())));
}

<|endoftext|>


<commit_before>// Resizer, LEF/DEF gate resizer
// Copyright (c) 2019, Parallax Software, Inc.
//
// 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
// (at your option) 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 <https://www.gnu.org/licenses/>.

#include "Machine.hh"
#include "PatternMatch.hh"
#include "ParseBus.hh"
#include "dbSdcNetwork.hh"

namespace sta {

static const char *
escapeDividers(const char *token,
	       const Network *network);

dbSdcNetwork::dbSdcNetwork(Network *network) :
  SdcNetwork(network)
{
}

// Override SdcNetwork to NetworkNameAdapter.
Instance *
dbSdcNetwork::findInstance(const char *path_name) const
{
  Instance *inst = network_->findInstance(path_name);
  if (inst == nullptr)
    inst = network_->findInstance(escapeDividers(path_name, this));
  return inst;
}

void
dbSdcNetwork::findInstancesMatching(const Instance *,
				    const PatternMatch *pattern,
				    InstanceSeq *insts) const
{
  if (pattern->hasWildcards())
    findInstancesMatching1(pattern, insts);
  else {
    Instance *inst = findInstance(pattern->pattern());
    if (inst)
      insts->push_back(inst);
    else {
      // Look for a match with path dividers escaped.
      const char *escaped = escapeChars(pattern->pattern(), divider_, '\0',
					escape_);
      inst = findInstance(escaped);
      if (inst)
	insts->push_back(inst);
      else
	// Malo
	findInstancesMatching1(pattern, insts);
    }
  }
}

void
dbSdcNetwork::findInstancesMatching1(const PatternMatch *pattern,
				     InstanceSeq *insts) const
{
  InstanceChildIterator *child_iter = childIterator(topInstance());
  while (child_iter->hasNext()) {
    Instance *child = child_iter->next();
    if (pattern->match(staToSdc(name(child))))
      insts->push_back(child);
  }
  delete child_iter;
}

void
dbSdcNetwork::findNetsMatching(const Instance *,
			       const PatternMatch *pattern,
			       NetSeq *nets) const
{
  if (pattern->hasWildcards())
    findNetsMatching1(pattern, nets);
  else {
    Net *net = findNet(pattern->pattern());
    if (net)
      nets->push_back(net);
    else {
      // Look for a match with path dividers escaped.
      const char *escaped = escapeChars(pattern->pattern(), divider_, '\0',
					escape_);
      net = findNet(escaped);
      if (net)
	nets->push_back(net);
      else
	findNetsMatching1(pattern, nets);
    }
  }
}

void
dbSdcNetwork::findNetsMatching1(const PatternMatch *pattern,
				NetSeq *nets) const
{
  NetIterator *net_iter = netIterator(topInstance());
  while (net_iter->hasNext()) {
    Net *net = net_iter->next();
    if (pattern->match(staToSdc(name(net))))
      nets->push_back(net);
  }
  delete net_iter;
}

void
dbSdcNetwork::findPinsMatching(const Instance *instance,
			       const PatternMatch *pattern,
			       PinSeq *pins) const
{
  if (stringEq(pattern->pattern(), "*")) {
    // Pattern of '*' matches all child instance pins.
    InstanceChildIterator *child_iter = childIterator(instance);
    while (child_iter->hasNext()) {
      Instance *child = child_iter->next();
      InstancePinIterator *pin_iter = pinIterator(child);
      while (pin_iter->hasNext()) {
	Pin *pin = pin_iter->next();
	pins->push_back(pin);
      }
      delete pin_iter;
    }
    delete child_iter;
  }
  else {
    char *inst_path, *port_name;
    pathNameLast(pattern->pattern(), inst_path, port_name);
    if (port_name) {
      PatternMatch inst_pattern(inst_path, pattern);
      InstanceSeq insts;
      findInstancesMatching(nullptr, &inst_pattern, &insts);
      PatternMatch port_pattern(port_name, pattern);
      for (auto inst : insts)
	findMatchingPins(inst, &port_pattern, pins);
    }
  }
}

void
dbSdcNetwork::findMatchingPins(const Instance *instance,
			       const PatternMatch *port_pattern,
			       PinSeq *pins) const
{
  if (instance != network_->topInstance()) {
    Cell *cell = network_->cell(instance);
    CellPortIterator *port_iter = network_->portIterator(cell);
    while (port_iter->hasNext()) {
      Port *port = port_iter->next();
      const char *port_name = network_->name(port);
      if (network_->hasMembers(port)) {
	bool bus_matches = port_pattern->match(port_name)
	  || port_pattern->match(escapeDividers(port_name, network_));
	PortMemberIterator *member_iter = network_->memberIterator(port);
	while (member_iter->hasNext()) {
	  Port *member_port = member_iter->next();
	  Pin *pin = network_->findPin(instance, member_port);
	  if (pin) {
	    if (bus_matches)
	      pins->push_back(pin);
	    else {
	      const char *member_name = network_->name(member_port);
	      if (port_pattern->match(member_name)
		  || port_pattern->match(escapeDividers(member_name, network_)))
		pins->push_back(pin);
	    }
	  }
	}
	delete member_iter;
      }
      else if (port_pattern->match(port_name)
	       || port_pattern->match(escapeDividers(port_name, network_))) {
	Pin *pin = network_->findPin(instance, port);
	if (pin)
	  pins->push_back(pin);
      }
    }
    delete port_iter;
  }
}

Pin *
dbSdcNetwork::findPin(const char *path_name) const
{
  char *inst_path, *port_name;
  pathNameLast(path_name, inst_path, port_name);
  if (inst_path) {
    Instance *inst = findInstance(inst_path);
    if (inst)
      return findPin(inst, port_name);
    else
      return nullptr;
  }
  else
    return findPin(topInstance(), path_name);
}

static const char *
escapeDividers(const char *token,
	       const Network *network)
{
  return escapeChars(token, network->pathDivider(), '\0',
		     network->pathEscape());
}

} // namespace
<commit_msg>dbSdcNetwork leak<commit_after>// Resizer, LEF/DEF gate resizer
// Copyright (c) 2019, Parallax Software, Inc.
//
// 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
// (at your option) 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 <https://www.gnu.org/licenses/>.

#include "Machine.hh"
#include "PatternMatch.hh"
#include "ParseBus.hh"
#include "dbSdcNetwork.hh"

namespace sta {

static const char *
escapeDividers(const char *token,
	       const Network *network);

dbSdcNetwork::dbSdcNetwork(Network *network) :
  SdcNetwork(network)
{
}

// Override SdcNetwork to NetworkNameAdapter.
Instance *
dbSdcNetwork::findInstance(const char *path_name) const
{
  Instance *inst = network_->findInstance(path_name);
  if (inst == nullptr)
    inst = network_->findInstance(escapeDividers(path_name, this));
  return inst;
}

void
dbSdcNetwork::findInstancesMatching(const Instance *,
				    const PatternMatch *pattern,
				    InstanceSeq *insts) const
{
  if (pattern->hasWildcards())
    findInstancesMatching1(pattern, insts);
  else {
    Instance *inst = findInstance(pattern->pattern());
    if (inst)
      insts->push_back(inst);
    else {
      // Look for a match with path dividers escaped.
      const char *escaped = escapeChars(pattern->pattern(), divider_, '\0',
					escape_);
      inst = findInstance(escaped);
      if (inst)
	insts->push_back(inst);
      else
	// Malo
	findInstancesMatching1(pattern, insts);
    }
  }
}

void
dbSdcNetwork::findInstancesMatching1(const PatternMatch *pattern,
				     InstanceSeq *insts) const
{
  InstanceChildIterator *child_iter = childIterator(topInstance());
  while (child_iter->hasNext()) {
    Instance *child = child_iter->next();
    if (pattern->match(staToSdc(name(child))))
      insts->push_back(child);
  }
  delete child_iter;
}

void
dbSdcNetwork::findNetsMatching(const Instance *,
			       const PatternMatch *pattern,
			       NetSeq *nets) const
{
  if (pattern->hasWildcards())
    findNetsMatching1(pattern, nets);
  else {
    Net *net = findNet(pattern->pattern());
    if (net)
      nets->push_back(net);
    else {
      // Look for a match with path dividers escaped.
      const char *escaped = escapeChars(pattern->pattern(), divider_, '\0',
					escape_);
      net = findNet(escaped);
      if (net)
	nets->push_back(net);
      else
	findNetsMatching1(pattern, nets);
    }
  }
}

void
dbSdcNetwork::findNetsMatching1(const PatternMatch *pattern,
				NetSeq *nets) const
{
  NetIterator *net_iter = netIterator(topInstance());
  while (net_iter->hasNext()) {
    Net *net = net_iter->next();
    if (pattern->match(staToSdc(name(net))))
      nets->push_back(net);
  }
  delete net_iter;
}

void
dbSdcNetwork::findPinsMatching(const Instance *instance,
			       const PatternMatch *pattern,
			       PinSeq *pins) const
{
  if (stringEq(pattern->pattern(), "*")) {
    // Pattern of '*' matches all child instance pins.
    InstanceChildIterator *child_iter = childIterator(instance);
    while (child_iter->hasNext()) {
      Instance *child = child_iter->next();
      InstancePinIterator *pin_iter = pinIterator(child);
      while (pin_iter->hasNext()) {
	Pin *pin = pin_iter->next();
	pins->push_back(pin);
      }
      delete pin_iter;
    }
    delete child_iter;
  }
  else {
    char *inst_path, *port_name;
    pathNameLast(pattern->pattern(), inst_path, port_name);
    if (port_name) {
      PatternMatch inst_pattern(inst_path, pattern);
      InstanceSeq insts;
      findInstancesMatching(nullptr, &inst_pattern, &insts);
      PatternMatch port_pattern(port_name, pattern);
      for (auto inst : insts)
	findMatchingPins(inst, &port_pattern, pins);
    }
  }
}

void
dbSdcNetwork::findMatchingPins(const Instance *instance,
			       const PatternMatch *port_pattern,
			       PinSeq *pins) const
{
  if (instance != network_->topInstance()) {
    Cell *cell = network_->cell(instance);
    CellPortIterator *port_iter = network_->portIterator(cell);
    while (port_iter->hasNext()) {
      Port *port = port_iter->next();
      const char *port_name = network_->name(port);
      if (network_->hasMembers(port)) {
	bool bus_matches = port_pattern->match(port_name)
	  || port_pattern->match(escapeDividers(port_name, network_));
	PortMemberIterator *member_iter = network_->memberIterator(port);
	while (member_iter->hasNext()) {
	  Port *member_port = member_iter->next();
	  Pin *pin = network_->findPin(instance, member_port);
	  if (pin) {
	    if (bus_matches)
	      pins->push_back(pin);
	    else {
	      const char *member_name = network_->name(member_port);
	      if (port_pattern->match(member_name)
		  || port_pattern->match(escapeDividers(member_name, network_)))
		pins->push_back(pin);
	    }
	  }
	}
	delete member_iter;
      }
      else if (port_pattern->match(port_name)
	       || port_pattern->match(escapeDividers(port_name, network_))) {
	Pin *pin = network_->findPin(instance, port);
	if (pin)
	  pins->push_back(pin);
      }
    }
    delete port_iter;
  }
}

Pin *
dbSdcNetwork::findPin(const char *path_name) const
{
  char *inst_path, *port_name;
  pathNameLast(path_name, inst_path, port_name);
  Pin *pin = nullptr;
  if (inst_path) {
    Instance *inst = findInstance(inst_path);
    if (inst)
      pin = findPin(inst, port_name);
    else
      pin = nullptr;
  }
  else
    pin = findPin(topInstance(), path_name);
  stringDelete(inst_path);
  stringDelete(port_name);
  return pin;
}

static const char *
escapeDividers(const char *token,
	       const Network *network)
{
  return escapeChars(token, network->pathDivider(), '\0',
		     network->pathEscape());
}

} // namespace
<|endoftext|>