<commit_before>//
// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

// geometry/VertexDataManager.h: Defines the VertexDataManager, a class that
// runs the Buffer translation process.

#include "geometry/VertexDataManager.h"

#include "common/debug.h"
#include "Program.h"

#include "Buffer.h"
#include "geometry/backend.h"
#include "geometry/IndexDataManager.h"

namespace
{
    enum { INITIAL_STREAM_BUFFER_SIZE = 1024*1024 };
}

namespace gl
{

VertexDataManager::VertexDataManager(Context *context, BufferBackEnd *backend)
    : mContext(context), mBackend(backend), mDirtyCurrentValues(true)
{
    mStreamBuffer = mBackend->createVertexBuffer(INITIAL_STREAM_BUFFER_SIZE);
    try
    {
        mCurrentValueBuffer = mBackend->createVertexBuffer(4*sizeof(float)*MAX_VERTEX_ATTRIBS);
    }
    catch (...)
    {
        delete mStreamBuffer;
        throw;
    }
}

VertexDataManager::~VertexDataManager()
{
    delete mStreamBuffer;
    delete mCurrentValueBuffer;
}

VertexDataManager::ArrayTranslationHelper::ArrayTranslationHelper(GLint first, GLsizei count)
    : mFirst(first), mCount(count)
{
}

void VertexDataManager::ArrayTranslationHelper::translate(const FormatConverter &converter, GLsizei stride, const void *source, void *dest)
{
    converter.convertArray(source, stride, mCount, dest);
}

VertexDataManager::IndexedTranslationHelper::IndexedTranslationHelper(const Index *indices, Index minIndex, GLsizei count)
    : mIndices(indices), mMinIndex(minIndex), mCount(count)
{
}

void VertexDataManager::IndexedTranslationHelper::translate(const FormatConverter &converter, GLsizei stride, const void *source, void *dest)
{
    converter.convertIndexed(source, stride, mMinIndex, mCount, mIndices, dest);
}

std::bitset<MAX_VERTEX_ATTRIBS> VertexDataManager::activeAttribs()
{
    std::bitset<MAX_VERTEX_ATTRIBS> active;

    Program *p = mContext->getCurrentProgram();

    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    {
        if (p->isActiveAttribute(i))
            active[i] = true;
    }

    return active;
}

GLenum VertexDataManager::preRenderValidate(GLint start, GLsizei count,
                                            TranslatedAttribute *outAttribs)

{
    ArrayTranslationHelper translationHelper(start, count);

    return internalPreRenderValidate(mContext->vertexAttribute, activeAttribs(), start, start+count-1, &translationHelper, outAttribs);
}

GLenum VertexDataManager::preRenderValidate(const TranslatedIndexData &indexInfo,
                                            TranslatedAttribute *outAttribs)

{
    IndexedTranslationHelper translationHelper(indexInfo.indices, indexInfo.minIndex, indexInfo.count);

    return internalPreRenderValidate(mContext->vertexAttribute, activeAttribs(), indexInfo.minIndex, indexInfo.maxIndex, &translationHelper, outAttribs);
}

GLenum VertexDataManager::internalPreRenderValidate(const AttributeState *attribs,
                                                    const std::bitset<MAX_VERTEX_ATTRIBS> &activeAttribs,
                                                    Index minIndex,
                                                    Index maxIndex,
                                                    TranslationHelper *translator,
                                                    TranslatedAttribute *outAttribs)
{
    std::bitset<MAX_VERTEX_ATTRIBS> translateOrLift;

    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    {
        if (!activeAttribs[i] && attribs[i].mEnabled && attribs[i].mBoundBuffer != 0 && !mContext->getBuffer(attribs[i].mBoundBuffer))
            return GL_INVALID_OPERATION;
    }

    TranslatedAttribute translated[MAX_VERTEX_ATTRIBS];

    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    {
        translated[i].enabled = activeAttribs[i];
    }

    processNonArrayAttributes(attribs, activeAttribs, translated);

    // Handle the identity-mapped attributes.

    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    {
        if (activeAttribs[i] && attribs[i].mEnabled)
        {
            if (attribs[i].mBoundBuffer != 0 && mBackend->getFormatConverter(attribs[i].mType, attribs[i].mSize, attribs[i].mNormalized).identity)
            {
                translated[i].type = attribs[i].mType;
                translated[i].size = attribs[i].mSize;
                translated[i].normalized = attribs[i].mNormalized;
                translated[i].stride = interpretGlStride(attribs[i]);
                translated[i].offset = static_cast<std::size_t>(static_cast<const char*>(attribs[i].mPointer) - static_cast<const char*>(NULL)) + translated[i].stride * minIndex;
                translated[i].buffer = mContext->getBuffer(attribs[i].mBoundBuffer)->identityBuffer();
            }
            else
            {
                translateOrLift[i] = true;
            }
        }
    }

    // Handle any attributes needing translation or lifting.
    if (translateOrLift.any())
    {
        std::size_t count = maxIndex - minIndex + 1;

        std::size_t requiredSpace = 0;

        for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
        {
            if (translateOrLift[i])
            {
                requiredSpace += spaceRequired(attribs[i], count);
            }
        }

        if (requiredSpace > mStreamBuffer->size())
        {
            std::size_t newSize = std::max(requiredSpace, 3 * mStreamBuffer->size() / 2); // 1.5 x mStreamBuffer->size() is arbitrary and should be checked to see we don't have too many reallocations.

            TranslatedVertexBuffer *newStreamBuffer = mBackend->createVertexBuffer(newSize);

            delete mStreamBuffer;
            mStreamBuffer = newStreamBuffer;
        }

        mStreamBuffer->reserveSpace(requiredSpace);

        for (size_t i = 0; i < MAX_VERTEX_ATTRIBS; i++)
        {
            if (translateOrLift[i])
            {
                FormatConverter formatConverter = mBackend->getFormatConverter(attribs[i].mType, attribs[i].mSize, attribs[i].mNormalized);

                translated[i].type = attribs[i].mType;
                translated[i].size = attribs[i].mSize;
                translated[i].normalized = attribs[i].mNormalized;
                translated[i].stride = formatConverter.outputVertexSize;
                translated[i].buffer = mStreamBuffer;

                void *output = mStreamBuffer->map(spaceRequired(attribs[i], count), &translated[i].offset);

                const void *input;
                if (attribs[i].mBoundBuffer)
                {
                    input = mContext->getBuffer(attribs[i].mBoundBuffer)->data();
                    input = static_cast<const char*>(input) + reinterpret_cast<size_t>(attribs[i].mPointer);
                }
                else
                {
                    input = attribs[i].mPointer;
                }

                size_t inputStride = interpretGlStride(attribs[i]);

                input = static_cast<const char*>(input) + inputStride * minIndex;

                translator->translate(formatConverter, interpretGlStride(attribs[i]), input, output);

                mStreamBuffer->unmap();
            }
        }
    }

    std::copy(translated, translated + MAX_VERTEX_ATTRIBS, outAttribs);

    return GL_NO_ERROR;
}

void VertexDataManager::reloadCurrentValues(const AttributeState *attribs, std::size_t *offset)
{
    if (mDirtyCurrentValues)
    {
        std::size_t totalSize = 4 * sizeof(float) * MAX_VERTEX_ATTRIBS;

        mCurrentValueBuffer->reserveSpace(totalSize);

        float* p = static_cast<float*>(mCurrentValueBuffer->map(totalSize, offset));

        for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
        {
            memcpy(&p[i*4], attribs[i].mCurrentValue, sizeof(attribs[i].mCurrentValue)); // FIXME: this should be doing a translation. This assumes that GL_FLOATx4 is supported.
        }

        mCurrentValueBuffer->unmap();

        mDirtyCurrentValues = false;
    }
}

std::size_t VertexDataManager::typeSize(GLenum type) const
{
    switch (type)
    {
      case GL_BYTE: case GL_UNSIGNED_BYTE: return sizeof(GLbyte);
      case GL_SHORT: case GL_UNSIGNED_SHORT: return sizeof(GLshort);
      case GL_FIXED: return sizeof(GLfixed);
      case GL_FLOAT: return sizeof(GLfloat);
      default: UNREACHABLE(); return sizeof(GLfloat);
    }
}

std::size_t VertexDataManager::interpretGlStride(const AttributeState &attrib) const
{
    return attrib.mStride ? attrib.mStride : typeSize(attrib.mType) * attrib.mSize;
}

// Round up x (>=0) to the next multiple of multiple (>0).
// 0 rounds up to 0.
std::size_t VertexDataManager::roundUp(std::size_t x, std::size_t multiple) const
{
    ASSERT(x >= 0);
    ASSERT(multiple > 0);

    std::size_t remainder = x % multiple;
    if (remainder != 0)
    {
        return x + multiple - remainder;
    }
    else
    {
        return x;
    }
}

std::size_t VertexDataManager::spaceRequired(const AttributeState &attrib, std::size_t maxVertex) const
{
    std::size_t size = mBackend->getFormatConverter(attrib.mType, attrib.mSize, attrib.mNormalized).outputVertexSize;
    size *= maxVertex;

    return roundUp(size, 4 * sizeof(GLfloat));
}

void VertexDataManager::processNonArrayAttributes(const AttributeState *attribs, const std::bitset<MAX_VERTEX_ATTRIBS> &activeAttribs, TranslatedAttribute *translated)
{
    bool usesCurrentValues = false;

    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    {
        if (activeAttribs[i] && !attribs[i].mEnabled)
        {
            usesCurrentValues = true;
            break;
        }
    }

    if (usesCurrentValues)
    {
        std::size_t currentValueOffset;

        reloadCurrentValues(attribs, &currentValueOffset);

        for (std::size_t i = 0; i < MAX_VERTEX_ATTRIBS; i++)
        {
            if (activeAttribs[i] && !attribs[i].mEnabled)
            {
                translated[i].buffer = mCurrentValueBuffer;

                translated[i].type = GL_FLOAT;
                translated[i].size = 4;
                translated[i].normalized = false;
                translated[i].stride = 0;
                translated[i].offset = currentValueOffset + 4 * sizeof(float) * i;
            }
        }
    }
}

}
<commit_msg>fix warning for std::copy<commit_after>//
// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

// geometry/VertexDataManager.h: Defines the VertexDataManager, a class that
// runs the Buffer translation process.

#include "geometry/VertexDataManager.h"

#include "common/debug.h"
#include "Program.h"

#include "Buffer.h"
#include "geometry/backend.h"
#include "geometry/IndexDataManager.h"

namespace
{
    enum { INITIAL_STREAM_BUFFER_SIZE = 1024*1024 };
}

namespace gl
{

VertexDataManager::VertexDataManager(Context *context, BufferBackEnd *backend)
    : mContext(context), mBackend(backend), mDirtyCurrentValues(true)
{
    mStreamBuffer = mBackend->createVertexBuffer(INITIAL_STREAM_BUFFER_SIZE);
    try
    {
        mCurrentValueBuffer = mBackend->createVertexBuffer(4*sizeof(float)*MAX_VERTEX_ATTRIBS);
    }
    catch (...)
    {
        delete mStreamBuffer;
        throw;
    }
}

VertexDataManager::~VertexDataManager()
{
    delete mStreamBuffer;
    delete mCurrentValueBuffer;
}

VertexDataManager::ArrayTranslationHelper::ArrayTranslationHelper(GLint first, GLsizei count)
    : mFirst(first), mCount(count)
{
}

void VertexDataManager::ArrayTranslationHelper::translate(const FormatConverter &converter, GLsizei stride, const void *source, void *dest)
{
    converter.convertArray(source, stride, mCount, dest);
}

VertexDataManager::IndexedTranslationHelper::IndexedTranslationHelper(const Index *indices, Index minIndex, GLsizei count)
    : mIndices(indices), mMinIndex(minIndex), mCount(count)
{
}

void VertexDataManager::IndexedTranslationHelper::translate(const FormatConverter &converter, GLsizei stride, const void *source, void *dest)
{
    converter.convertIndexed(source, stride, mMinIndex, mCount, mIndices, dest);
}

std::bitset<MAX_VERTEX_ATTRIBS> VertexDataManager::activeAttribs()
{
    std::bitset<MAX_VERTEX_ATTRIBS> active;

    Program *p = mContext->getCurrentProgram();

    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    {
        if (p->isActiveAttribute(i))
            active[i] = true;
    }

    return active;
}

GLenum VertexDataManager::preRenderValidate(GLint start, GLsizei count,
                                            TranslatedAttribute *outAttribs)

{
    ArrayTranslationHelper translationHelper(start, count);

    return internalPreRenderValidate(mContext->vertexAttribute, activeAttribs(), start, start+count-1, &translationHelper, outAttribs);
}

GLenum VertexDataManager::preRenderValidate(const TranslatedIndexData &indexInfo,
                                            TranslatedAttribute *outAttribs)

{
    IndexedTranslationHelper translationHelper(indexInfo.indices, indexInfo.minIndex, indexInfo.count);

    return internalPreRenderValidate(mContext->vertexAttribute, activeAttribs(), indexInfo.minIndex, indexInfo.maxIndex, &translationHelper, outAttribs);
}

GLenum VertexDataManager::internalPreRenderValidate(const AttributeState *attribs,
                                                    const std::bitset<MAX_VERTEX_ATTRIBS> &activeAttribs,
                                                    Index minIndex,
                                                    Index maxIndex,
                                                    TranslationHelper *translator,
                                                    TranslatedAttribute *translated)
{
    std::bitset<MAX_VERTEX_ATTRIBS> translateOrLift;

    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    {
        if (!activeAttribs[i] && attribs[i].mEnabled && attribs[i].mBoundBuffer != 0 && !mContext->getBuffer(attribs[i].mBoundBuffer))
            return GL_INVALID_OPERATION;
    }

    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    {
        translated[i].enabled = activeAttribs[i];
    }

    processNonArrayAttributes(attribs, activeAttribs, translated);

    // Handle the identity-mapped attributes.

    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    {
        if (activeAttribs[i] && attribs[i].mEnabled)
        {
            if (attribs[i].mBoundBuffer != 0 && mBackend->getFormatConverter(attribs[i].mType, attribs[i].mSize, attribs[i].mNormalized).identity)
            {
                translated[i].type = attribs[i].mType;
                translated[i].size = attribs[i].mSize;
                translated[i].normalized = attribs[i].mNormalized;
                translated[i].stride = interpretGlStride(attribs[i]);
                translated[i].offset = static_cast<std::size_t>(static_cast<const char*>(attribs[i].mPointer) - static_cast<const char*>(NULL)) + translated[i].stride * minIndex;
                translated[i].buffer = mContext->getBuffer(attribs[i].mBoundBuffer)->identityBuffer();
            }
            else
            {
                translateOrLift[i] = true;
            }
        }
    }

    // Handle any attributes needing translation or lifting.
    if (translateOrLift.any())
    {
        std::size_t count = maxIndex - minIndex + 1;

        std::size_t requiredSpace = 0;

        for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
        {
            if (translateOrLift[i])
            {
                requiredSpace += spaceRequired(attribs[i], count);
            }
        }

        if (requiredSpace > mStreamBuffer->size())
        {
            std::size_t newSize = std::max(requiredSpace, 3 * mStreamBuffer->size() / 2); // 1.5 x mStreamBuffer->size() is arbitrary and should be checked to see we don't have too many reallocations.

            TranslatedVertexBuffer *newStreamBuffer = mBackend->createVertexBuffer(newSize);

            delete mStreamBuffer;
            mStreamBuffer = newStreamBuffer;
        }

        mStreamBuffer->reserveSpace(requiredSpace);

        for (size_t i = 0; i < MAX_VERTEX_ATTRIBS; i++)
        {
            if (translateOrLift[i])
            {
                FormatConverter formatConverter = mBackend->getFormatConverter(attribs[i].mType, attribs[i].mSize, attribs[i].mNormalized);

                translated[i].type = attribs[i].mType;
                translated[i].size = attribs[i].mSize;
                translated[i].normalized = attribs[i].mNormalized;
                translated[i].stride = formatConverter.outputVertexSize;
                translated[i].buffer = mStreamBuffer;

                void *output = mStreamBuffer->map(spaceRequired(attribs[i], count), &translated[i].offset);

                const void *input;
                if (attribs[i].mBoundBuffer)
                {
                    input = mContext->getBuffer(attribs[i].mBoundBuffer)->data();
                    input = static_cast<const char*>(input) + reinterpret_cast<size_t>(attribs[i].mPointer);
                }
                else
                {
                    input = attribs[i].mPointer;
                }

                size_t inputStride = interpretGlStride(attribs[i]);

                input = static_cast<const char*>(input) + inputStride * minIndex;

                translator->translate(formatConverter, interpretGlStride(attribs[i]), input, output);

                mStreamBuffer->unmap();
            }
        }
    }

    return GL_NO_ERROR;
}

void VertexDataManager::reloadCurrentValues(const AttributeState *attribs, std::size_t *offset)
{
    if (mDirtyCurrentValues)
    {
        std::size_t totalSize = 4 * sizeof(float) * MAX_VERTEX_ATTRIBS;

        mCurrentValueBuffer->reserveSpace(totalSize);

        float* p = static_cast<float*>(mCurrentValueBuffer->map(totalSize, offset));

        for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
        {
            memcpy(&p[i*4], attribs[i].mCurrentValue, sizeof(attribs[i].mCurrentValue)); // FIXME: this should be doing a translation. This assumes that GL_FLOATx4 is supported.
        }

        mCurrentValueBuffer->unmap();

        mDirtyCurrentValues = false;
    }
}

std::size_t VertexDataManager::typeSize(GLenum type) const
{
    switch (type)
    {
      case GL_BYTE: case GL_UNSIGNED_BYTE: return sizeof(GLbyte);
      case GL_SHORT: case GL_UNSIGNED_SHORT: return sizeof(GLshort);
      case GL_FIXED: return sizeof(GLfixed);
      case GL_FLOAT: return sizeof(GLfloat);
      default: UNREACHABLE(); return sizeof(GLfloat);
    }
}

std::size_t VertexDataManager::interpretGlStride(const AttributeState &attrib) const
{
    return attrib.mStride ? attrib.mStride : typeSize(attrib.mType) * attrib.mSize;
}

// Round up x (>=0) to the next multiple of multiple (>0).
// 0 rounds up to 0.
std::size_t VertexDataManager::roundUp(std::size_t x, std::size_t multiple) const
{
    ASSERT(x >= 0);
    ASSERT(multiple > 0);

    std::size_t remainder = x % multiple;
    if (remainder != 0)
    {
        return x + multiple - remainder;
    }
    else
    {
        return x;
    }
}

std::size_t VertexDataManager::spaceRequired(const AttributeState &attrib, std::size_t maxVertex) const
{
    std::size_t size = mBackend->getFormatConverter(attrib.mType, attrib.mSize, attrib.mNormalized).outputVertexSize;
    size *= maxVertex;

    return roundUp(size, 4 * sizeof(GLfloat));
}

void VertexDataManager::processNonArrayAttributes(const AttributeState *attribs, const std::bitset<MAX_VERTEX_ATTRIBS> &activeAttribs, TranslatedAttribute *translated)
{
    bool usesCurrentValues = false;

    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
    {
        if (activeAttribs[i] && !attribs[i].mEnabled)
        {
            usesCurrentValues = true;
            break;
        }
    }

    if (usesCurrentValues)
    {
        std::size_t currentValueOffset;

        reloadCurrentValues(attribs, &currentValueOffset);

        for (std::size_t i = 0; i < MAX_VERTEX_ATTRIBS; i++)
        {
            if (activeAttribs[i] && !attribs[i].mEnabled)
            {
                translated[i].buffer = mCurrentValueBuffer;

                translated[i].type = GL_FLOAT;
                translated[i].size = 4;
                translated[i].normalized = false;
                translated[i].stride = 0;
                translated[i].offset = currentValueOffset + 4 * sizeof(float) * i;
            }
        }
    }
}

}
<|endoftext|>


<commit_before>// Copyright 2012-2013 Samplecount S.L.
//
// 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.

#ifndef METHCLA_UTILITY_MESSAGEQUEUE_HPP_INCLUDED
#define METHCLA_UTILITY_MESSAGEQUEUE_HPP_INCLUDED

#include <array>
#include <atomic>
#include <list>
#include <mutex>
#include <thread>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include <boost/lockfree/spsc_queue.hpp>
#pragma GCC diagnostic pop
#include <boost/noncopyable.hpp>

#include "Methcla/Utility/Semaphore.hpp"

#define METHCLA_WORKER_USE_LIST 0
#define METHCLA_WORKER_USE_PTHREAD 0
#define METHCLA_WORKER_AUDIO_THREAD 0

#if __APPLE__
# include <libkern/OSAtomic.h>
# define METHCLA_WORKER_MEMORY_BARRIER OSMemoryBarrier()
#else
# define METHCLA_WORKER_MEMORY_BARRIER
#endif

#if METHCLA_WORKER_USE_PTHREAD
# include <pthread.h>
#endif

namespace Methcla { namespace Utility {

#if METHCLA_WORKER_USE_LIST
template <class T> class ListQueue
{
public:
#if METHCLA_WORKER_USE_PTHREAD && !METHCLA_WORKER_AUDIO_THREAD
    ListQueue()
    {
        pthread_mutex_init(&m_mutex, nullptr);
    }
    ~ListQueue()
    {
        pthread_mutex_destroy(&m_mutex);
    }
#endif

    bool push(const T& a)
    {
#if !METHCLA_WORKER_AUDIO_THREAD
#if METHCLA_WORKER_USE_PTHREAD
        pthread_mutex_lock(&m_mutex);
#else
        std::lock_guard<std::mutex> lock(m_mutex);
#endif
#endif
        m_list.push_back(a);
#if !METHCLA_WORKER_AUDIO_THREAD
        METHCLA_WORKER_MEMORY_BARRIER;
#endif
#if METHCLA_WORKER_USE_PTHREAD && !METHCLA_WORKER_AUDIO_THREAD
        pthread_mutex_unlock(&m_mutex);
#endif
        return true;
    }

    bool pop(T& a)
    {
#if !METHCLA_WORKER_AUDIO_THREAD
#if METHCLA_WORKER_USE_PTHREAD
        pthread_mutex_lock(&m_mutex);
#else
        std::lock_guard<std::mutex> lock(m_mutex);
#endif
#endif
        if (m_list.empty())
            return false;
        a = m_list.front();
        m_list.pop_front();
#if !METHCLA_WORKER_AUDIO_THREAD
        METHCLA_WORKER_MEMORY_BARRIER;
#endif
#if METHCLA_WORKER_USE_PTHREAD && !METHCLA_WORKER_AUDIO_THREAD
        pthread_mutex_unlock(&m_mutex);
#endif
        return true;
    }

private:
#if !METHCLA_WORKER_AUDIO_THREAD
#if METHCLA_WORKER_USE_PTHREAD
    pthread_mutex_t m_mutex;
#else
    std::mutex   m_mutex;
#endif
#endif
    std::list<T> m_list;
};
#endif // METHCLA_WORKER_USE_LIST

//* MWSR queue for sending commands to the engine.
// Request payload lifetime: from request until response callback.
// Caller is responsible for freeing request payload after the response callback has been called.
template <typename T, size_t queueSize> class MessageQueue : boost::noncopyable
{
public:
    inline void send(const T& msg)
    {
        std::lock_guard<std::mutex> lock(m_mutex);
        bool success = m_queue.push(msg);
        if (!success) throw std::runtime_error("Message queue overflow");
    }

    inline bool next(T& msg)
    {
        return m_queue.pop(msg);
    }

private:
    typedef boost::lockfree::spsc_queue<T,boost::lockfree::capacity<queueSize>> Queue;
    Queue      m_queue;
    std::mutex m_mutex;
};

template <class Command> class Transport : boost::noncopyable
{
public:
    Transport(size_t queueSize)
#if !METHCLA_WORKER_USE_LIST
        : m_queue(queueSize)
#endif
    { }
    virtual ~Transport()
    { }

    virtual void send(const Command& cmd) = 0;

    virtual bool dequeue(Command& cmd) = 0;

    void drain()
    {
        Command cmd;
        while (dequeue(cmd)) {
            cmd.perform();
        }
    }

protected:
    void sendCommand(const Command& cmd)
    {
        bool success = m_queue.push(cmd);
        if (!success) throw std::runtime_error("Channel overflow");
    }

protected:
#if METHCLA_WORKER_USE_LIST
    typedef ListQueue<Command> Queue;
#else
    typedef boost::lockfree::spsc_queue<Command> Queue;
    // typedef boost::lockfree::queue<Command,boost::lockfree::capacity<queueSize>> Queue;
#endif
    Queue m_queue;
};

template <class Command> class ToWorker : public Transport<Command>
{
public:
    ToWorker(size_t queueSize, std::function<void()> signal)
        : Transport<Command>(queueSize)
        , m_signal(signal)
    { }

    virtual void send(const Command& cmd) override
    {
        this->sendCommand(cmd);
#if !METHCLA_WORKER_AUDIO_THREAD
        if (m_signal) m_signal();
#endif
    }

    bool dequeue(Command& cmd)
    {
#if !METHCLA_WORKER_USE_LIST && !METHCLA_WORKER_AUDIO_THREAD
        std::lock_guard<std::mutex> lock(m_mutex);
#endif
        return this->m_queue.pop(cmd);
    }

private:
    std::function<void()> m_signal;
#if !METHCLA_WORKER_USE_LIST && !METHCLA_WORKER_AUDIO_THREAD
    std::mutex          m_mutex;
#endif
};

template <class Command> class FromWorker : public Transport<Command>
{
public:
    FromWorker(size_t queueSize)
        : Transport<Command>(queueSize)
    { }

    virtual void send(const Command& cmd) override
    {
#if !METHCLA_WORKER_USE_LIST && !METHCLA_WORKER_AUDIO_THREAD
        std::lock_guard<std::mutex> lock(m_mutex);
#endif
        this->sendCommand(cmd);
    }

    bool dequeue(Command& cmd) override
    {
        return this->m_queue.pop(cmd);
    }

private:
#if !METHCLA_WORKER_USE_LIST && !METHCLA_WORKER_AUDIO_THREAD
    std::mutex m_mutex;
#endif
};

template <typename Command> class Worker : boost::noncopyable
{
public:
    Worker(size_t queueSize)
        : m_queueSize(queueSize)
        , m_toWorker(queueSize, [this](){ this->signalWorker(); })
        , m_fromWorker(queueSize)
    { }

    size_t maxCapacity() const
    {
        return m_queueSize - 1;
    }

    void sendToWorker(const Command& cmd)
    {
        m_toWorker.send(cmd);
    }

    void sendFromWorker(const Command& cmd)
    {
        m_fromWorker.send(cmd);
    }

    void perform()
    {
        m_fromWorker.drain();
#if METHCLA_WORKER_AUDIO_THREAD
        work();
#endif
    }

protected:
    void work()
    {
        m_toWorker.drain();
    }

    virtual void signalWorker() { }

private:
    size_t              m_queueSize;
    ToWorker<Command>   m_toWorker;
    FromWorker<Command> m_fromWorker;
};

template <typename Command> class WorkerThread : public Worker<Command>
{
public:
    WorkerThread(size_t queueSize, size_t numThreads=1)
        : Worker<Command>(queueSize)
        , m_continue(true)
    {
#if !METHCLA_WORKER_AUDIO_THREAD
        start(numThreads);
#endif
    }

    ~WorkerThread()
    {
#if !METHCLA_WORKER_AUDIO_THREAD
        m_continue.store(false, std::memory_order_relaxed);
        // m_continue = false;
        m_sem.post();
        join();
#endif
    }

private:
#if !METHCLA_WORKER_USE_PTHREAD
    typedef std::thread thread;
#endif

#if !METHCLA_WORKER_AUDIO_THREAD
    void start(size_t /*numThreads*/)
    {
#if METHCLA_WORKER_USE_PTHREAD
        pthread_create(&m_thread, nullptr, threadFunc, this);
#else
        // for (size_t i=0; i < std::max<size_t>(1, numThreads); i++) {
        //     m_threads.emplace_back([this](){ this->process(); });
        // }
        m_thread = thread([this](){ this->process(); });
#endif
    }

    void join()
    {
#if METHCLA_WORKER_USE_PTHREAD
        pthread_join(m_thread, nullptr);
#else
        // for (auto& t : m_threads) { t.join(); }
        m_thread.join();
#endif
    }

    void process()
    {
        for (;;) {
            m_sem.wait();
            bool cont = m_continue.load(std::memory_order_relaxed);
            // bool cont = m_continue;
            if (cont) {
                this->work();
            } else {
                break;
            }
        }
    }

    virtual void signalWorker() override
    {
        m_sem.post();
    }
#if METHCLA_WORKER_USE_PTHREAD
    static void* threadFunc(void* data)
    {
        ((WorkerThread<Command>*)data)->process();
        return nullptr;
    }
#endif
#endif // !METHCLA_WORKER_AUDIO_THREAD

private:
    Semaphore           m_sem;
    // bool m_continue;
    std::atomic<bool> m_continue;
    // std::vector<std::thread>    m_threads;
#if METHCLA_WORKER_USE_PTHREAD
    pthread_t m_thread;
#else
    thread m_thread;
#endif
};

} }

#endif // METHCLA_UTILITY_MESSAGEQUEUE_HPP_INCLUDED
<commit_msg>Remove debugging code from worker thread implementation<commit_after>// Copyright 2012-2013 Samplecount S.L.
//
// 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.

#ifndef METHCLA_UTILITY_MESSAGEQUEUE_HPP_INCLUDED
#define METHCLA_UTILITY_MESSAGEQUEUE_HPP_INCLUDED

#include <array>
#include <atomic>
#include <mutex>
#include <thread>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include <boost/lockfree/spsc_queue.hpp>
#pragma GCC diagnostic pop
#include <boost/noncopyable.hpp>

#include "Methcla/Utility/Semaphore.hpp"

namespace Methcla { namespace Utility {

//* MWSR queue for sending commands to the engine.
// Request payload lifetime: from request until response callback.
// Caller is responsible for freeing request payload after the response callback has been called.
template <typename T, size_t queueSize> class MessageQueue : boost::noncopyable
{
public:
    inline void send(const T& msg)
    {
        std::lock_guard<std::mutex> lock(m_mutex);
        bool success = m_queue.push(msg);
        if (!success) throw std::runtime_error("Message queue overflow");
    }

    inline bool next(T& msg)
    {
        return m_queue.pop(msg);
    }

private:
    typedef boost::lockfree::spsc_queue<T,boost::lockfree::capacity<queueSize>> Queue;
    Queue      m_queue;
    std::mutex m_mutex;
};

template <class Command> class Transport : boost::noncopyable
{
public:
    Transport(size_t queueSize)
        : m_queue(queueSize)
    { }
    virtual ~Transport()
    { }

    virtual void send(const Command& cmd) = 0;

    virtual bool dequeue(Command& cmd) = 0;

    void drain()
    {
        Command cmd;
        while (dequeue(cmd)) {
            cmd.perform();
        }
    }

protected:
    void sendCommand(const Command& cmd)
    {
        bool success = m_queue.push(cmd);
        if (!success) throw std::runtime_error("Channel overflow");
    }

protected:
    typedef boost::lockfree::spsc_queue<Command> Queue;
    // typedef boost::lockfree::queue<Command,boost::lockfree::capacity<queueSize>> Queue;
    Queue m_queue;
};

template <class Command> class ToWorker : public Transport<Command>
{
public:
    ToWorker(size_t queueSize, std::function<void()> signal)
        : Transport<Command>(queueSize)
        , m_signal(signal)
    { }

    virtual void send(const Command& cmd) override
    {
        this->sendCommand(cmd);
        if (m_signal) m_signal();
    }

    bool dequeue(Command& cmd)
    {
        std::lock_guard<std::mutex> lock(m_mutex);
        return this->m_queue.pop(cmd);
    }

private:
    std::function<void()> m_signal;
    std::mutex            m_mutex;
};

template <class Command> class FromWorker : public Transport<Command>
{
public:
    FromWorker(size_t queueSize)
        : Transport<Command>(queueSize)
    { }

    virtual void send(const Command& cmd) override
    {
        std::lock_guard<std::mutex> lock(m_mutex);
        this->sendCommand(cmd);
    }

    bool dequeue(Command& cmd) override
    {
        return this->m_queue.pop(cmd);
    }

private:
    std::mutex m_mutex;
};

template <typename Command> class Worker : boost::noncopyable
{
public:
    Worker(size_t queueSize)
        : m_queueSize(queueSize)
        , m_toWorker(queueSize, [this](){ this->signalWorker(); })
        , m_fromWorker(queueSize)
    { }

    size_t maxCapacity() const
    {
        return m_queueSize - 1;
    }

    void sendToWorker(const Command& cmd)
    {
        m_toWorker.send(cmd);
    }

    void sendFromWorker(const Command& cmd)
    {
        m_fromWorker.send(cmd);
    }

    void perform()
    {
        m_fromWorker.drain();
    }

protected:
    void work()
    {
        m_toWorker.drain();
    }

    virtual void signalWorker() { }

private:
    size_t              m_queueSize;
    ToWorker<Command>   m_toWorker;
    FromWorker<Command> m_fromWorker;
};

template <typename Command> class WorkerThread : public Worker<Command>
{
public:
    WorkerThread(size_t queueSize, size_t numThreads=1)
        : Worker<Command>(queueSize)
        , m_continue(true)
    {
        start(numThreads);
    }

    ~WorkerThread()
    {
        m_continue.store(false, std::memory_order_relaxed);
        m_sem.post();
        join();
    }

private:
    typedef std::thread thread;

    void start(size_t /*numThreads*/)
    {
        // for (size_t i=0; i < std::max<size_t>(1, numThreads); i++) {
        //     m_threads.emplace_back([this](){ this->process(); });
        // }
        m_thread = thread([this](){ this->process(); });
    }

    void join()
    {
        // for (auto& t : m_threads) { t.join(); }
        m_thread.join();
    }

    void process()
    {
        for (;;) {
            m_sem.wait();
            bool cont = m_continue.load(std::memory_order_relaxed);
            if (cont) {
                this->work();
            } else {
                break;
            }
        }
    }

    virtual void signalWorker() override
    {
        m_sem.post();
    }

private:
    Semaphore         m_sem;
    std::atomic<bool> m_continue;
    // std::vector<std::thread>    m_threads;
    thread m_thread;
};

} }

#endif // METHCLA_UTILITY_MESSAGEQUEUE_HPP_INCLUDED
<|endoftext|>


<commit_before>/******************************************************************************\
* EventHandler.hpp                                                             *
* An event handler providing GUI-like events                                   *
*                                                                              *
* Copyright (C) 2006-2010 by Leandro Motta Barros.                             *
*                                                                              *
* This program is distributed under the OpenSceneGraph Public License. You     *
* should have received a copy of it with the source distribution, in a file    *
* named 'COPYING.txt'.                                                         *
\******************************************************************************/

#ifndef _GUISH_EVENT_HANDLER_HPP_
#define _GUISH_EVENT_HANDLER_HPP_

#include <boost/signal.hpp>
#include <osgGA/GUIEventHandler>
#include <osgUtil/LineSegmentIntersector>
#include <osgViewer/View>
#include <OSGUIsh/FocusPolicy.hpp>
#include <OSGUIsh/ManualFocusPolicy.hpp>

namespace OSGUIsh
{
   /**
    * A \c struct grouping parameters passed to event handlers. Future versions
    * of OSGUish may add more members here if necessary without breaking
    * existing user code.
    * @note Be aware that, in the general case, <tt>hit.nodePath.back() !=
    *       node</tt>. \c hit contains the actual, "low level" hit, while \c
    *       node contains the node registered with OSGUish. For instance,
    *       suppose you register a car node, that has a car body node and four
    *       wheel nodes as subnodes. \c node will always be the whole car, while
    *       \c hit will be the "car body" or one of the "wheels".
    */
   struct HandlerParams
   {
      public:
         /// Convenience constructor.
         HandlerParams(NodePtr nodeParam,
                       const osgGA::GUIEventAdapter& eventParam,
                       const Intersection_t& hitParam)
            : node(nodeParam), event(eventParam), hit(hitParam)
         { }

         /// The node generating the event.
         NodePtr node;

         /**
          * The event data, as passed by OSG. Here you can find many useful
          * information, like "which mouse button was pressed".
          */
         const osgGA::GUIEventAdapter& event;

         /**
          * The \c Intersection_t for the node that was under the mouse pointer
          * when the event was generated.
          * @note Notice that, in some cases, the \c Intersection_t for the node
          *       under the mouse pointer doesn't really have something to do
          *       with the event being handled. For example, if the event is a
          *       \c KeyUp and the focus policy is not the "node under mouse has
          *       focus" policy, than the hit may not be related to the node
          *       generating the event.
          *       <p>Also, in cases like that, the hit may even be invalid,
          *       since, perhaps, there will not be any registered node under
          *       the mouse pointer. Figuring out if \c hit contains valid and
          *       meaningful information is up to the user.
          */
         const Intersection_t& hit;
   };

   /**
    * An event handler providing GUI-like events for nodes. The \c EventHandler
    * has an internal list of nodes being "observed". Every observed node has a
    * collection of signals associated to it. These signals represent the events
    * that can be generated for the node.
    */
   class EventHandler: public osgGA::GUIEventHandler
   {
      public:
         /**
          * Constructs an \c EventHandler.
          * @param kbdPolicyFactory The factory that will be used to create the
          *        \c FocusPolicy used to automatically set the focus for
          *        keyboard events.
          * @param wheelPolicyFactory The factory that will be used to create
          *        the \c FocusPolicy used to automatically set the focus for
          *        mouse wheel events.
          */
         EventHandler(const FocusPolicyFactory& kbdPolicyFactory =
                      FocusPolicyFactoryMason<ManualFocusPolicy>(),
                      const FocusPolicyFactory& wheelPolicyFactory =
                      FocusPolicyFactoryMason<ManualFocusPolicy>());

         /**
          * Handles upcoming events (overloads virtual method).
          * @return See \c handleReturnValues_, please.
          */
         bool handle(const osgGA::GUIEventAdapter& ea,
                     osgGA::GUIActionAdapter&);

         /// A type representing a sequence of node masks.
         typedef std::vector<osg::Node::NodeMask> NodeMasks_t;

         /**
          * Sets node mask that will be used when picking. The default node mask
          * is 0xFFFFFFFF, meaning that every node with at least one bit set on
          * their node masks will be taken into account for picking. (All this
          * just means that you don't change any setting related to node masks,
          * OSGUIsh will not ignore any node when picking.)
          *
          * So, when should one explicitly set the picking mask? The easy answer
          * is "whenever one wants to ignore some nodes when picking". (When
          * picking, OSGUIsh (OSG, in fact) will perform a bitwise AND between
          * the picking root set here and each node's node mask; if the result
          * is zero, the node will be ignored.)
          *
          * The interesting part is that OSGUIsh supports multiple picking
          * masks. First, it will try to pick nodes using the first node mask;
          * if no node is picked, it will try picking using the second picking
          * mask and so on.
          *
          * Creative people may find various uses for this, but the feature was
          * implemented so that picking could work with HUDs. When using
          * multiple <tt>osg::Camera</tt>s (as is the case when using HUDs),
          * picking in OSG can be problematic. The details of this problem are
          * not important here (anyway, basically, we don't have control on the
          * relative "z-order" of objects viewed by different
          * <tt>Camera</tt>s). But it is important to know that, if we want to
          * pick objects in different camera nodes, we may have some
          * unpredictable results.
          *
          * So, to enable proper picking in HUDs, OSGUIsh can use this scheme of
          * multiple picking roots.
          *
          * @see setPickingMasks() which are the methods capable of setting
          *      multiple picking roots.
          *
          * @param newMask The new node mask to be used when picking.
          */
         void setPickingMask(osg::Node::NodeMask newMask);

         /**
          * Sets the node masks used when picking.
          * @param newMask1 The first node mask to be tried when picking.
          * @param newMask2 The second node mask to be tried when picking.
          * @see setPickingMask for a description of why using multiple picking
          *      roots can be useful (tip: HUD).
          */
         void setPickingMasks(osg::Node::NodeMask newMask1,
                              osg::Node::NodeMask newMask2);

         /**
          * Sets the node masks used when picking.
          * @param newMask1 The first node mask to be tried when picking.
          * @param newMask2 The second node mask to be tried when picking.
          * @param newMask3 The third node mask to be tried when picking.
          * @see setPickingMask for a description of why using multiple picking
          *      roots can be useful (tip: HUD).
          */
         void setPickingMasks(osg::Node::NodeMask newMask1,
                              osg::Node::NodeMask newMask2,
                              osg::Node::NodeMask newMask3);

         /**
          * Sets the node masks used when picking.
          * @param newMasks A vector with the node masks to be tried when
          *        picking (they'll be tried in sequence).
          * @see setPickingMask for a description of why using multiple picking
          *      roots can be useful (tip: HUD).
          */
         void setPickingMasks(const NodeMasks_t& newMasks);

         /**
          * A type representing a signal used in OSGUIsh. This signal returns
          * nothing and takes a \c HandlerParams, which packs all relevant data
          * for an event handler function.
          */
         typedef boost::signal<void (HandlerParams&)> Signal_t;

         /// A (smart) pointer to a \c Signal_t;
         typedef boost::shared_ptr<Signal_t> SignalPtr;

         /**
          * Adds a given node to the list of nodes being "observed" by this \c
          * EventHandler. In other words, after this call, signals for this node
          * will be triggered.
          * @param node The node that will be added to this \c EventHandler.
          */
         void addNode(const NodePtr node);

         /**
          * Returns a signal associated with a given node. This is typically
          * used to call \c connect() on the returned signal.
          * @param node The desired node.
          * @param signal The desired signal. Valid signals are
          *        <tt>"MouseEnter"</tt>, <tt>"MouseLeave"</tt>,
          *        <tt>"MouseMove"</tt>, <tt>"MouseDown"</tt>,
          *        <tt>"MouseUp"</tt>, <tt>"Click"</tt>, <tt>"DoubleClick"</tt>,
          *        <tt>"MouseWheelUp"</tt>, <tt>"MouseWheelDown"</tt>,
          *        <tt>"KeyUp"</tt> and <tt>"KeyDown"</tt>.
          * @note The "mouse move" event is "relative": if the mouse is not
          *       moving, but a node is moving "below" it, mouse move events
          *       will be generated.
          */
         SignalPtr getSignal(const NodePtr node, const std::string& signal);

         /**
          * Ignores or stops to ignore faces that are back-facing the viewer
          * when picking. It may be useful to ignore back faces when backface
          * culling is enabled.
          * @param ignore If \c true, back faces will be ignored when picking.
          *        If \c false, back faces will be considered when piking.
          * @bug "Ignore back faces" will not work always. More specifically, it
          *      will work only when picking gets at least two hits. It doesn't
          *      matter if these two hits are of front or back facing faces (or
          *      a combination of them). If there is only a single hit, it will
          *      not be ignored, even the face hit was a back facing one.
          */
         void ignoreBackFaces(bool ignore = true)
         { ignoreBackFaces_ = ignore; }

         /**
          * Manually sets the node that will receive keyboard events. Notice
          * that focus policies allow to set this automatically.
          */
         void setKeyboardFocus(const NodePtr node);

         /**
          * Sets the node that will receive mouse wheel events. Notice that
          * focus policies allow to set this automatically.
          */
         void setMouseWheelFocus(const NodePtr node);

         /**
          * Sets the focus policy for keyboard events to a given one.
          * @param policyFactory The factory that will be used to create the
          *        actual policy.
          */
         void setKeyboardFocusPolicy(const FocusPolicyFactory& policyFactory);

         /**
          * Sets the focus policy for mouse wheel events to a given one.
          * @param policyFactory The factory that will be used to create the
          *        actual policy.
          */
         void setMouseWheelFocusPolicy(const FocusPolicyFactory& policyFactory);

      private:
         /**
          * Returns the first node in an \c osg::NodePath that is present in the
          * list of nodes being "observed" by this \c EventHandler. This is
          * necessary in the cases in which the user is picking a node that is
          * child of an added node. That's the case, for instance, of when the
          * user adds a node read from a 3D model file returned by \c
          * osgDB::readNodeFile().
          * @param nodePath The node path leading to the node being queried.
          * @returns The first node in \c nodePath that was added to the list of
          *          nodes being observed.
          */
         NodePtr getObservedNode(const osg::NodePath& nodePath);

         /**
          * Handles a \c FRAME event triggered by OSG. Signals triggered here
          * are <tt>"MouseEnter"</tt>, <tt>"MouseLeave"</tt> and
          * <tt>"MouseMove"</tt>.
          * @param ea The event generated by OSG.
          */
         void handleFrameEvent(osgViewer::View* view,
                               const osgGA::GUIEventAdapter& ea);

         /**
          * Handles a \c PUSH event triggered by OSG. The only signal triggered
          * here is <tt>"MouseDown"</tt>, but this function also does
          * bookkeeping related to other mouse signals.
          * @param ea The event generated by OSG.
          */
         void handlePushEvent(const osgGA::GUIEventAdapter& ea);

         /**
          * Handles a \c RELEASE event triggered by OSG. Signals triggered here
          * are <tt>"MouseUp"</tt>, <tt>"Click"</tt> and <tt>"DoubleClick"</tt>.
          * @param ea The event generated by OSG.
          */
         void handleReleaseEvent(const osgGA::GUIEventAdapter& ea);

         /**
          * Handles a \c KEYDOWN event triggered by OSG. The only signal
          * triggered here is <tt>"KeyDown"</tt>.
          * @param ea The event generated by OSG.
          */
         void handleKeyDownEvent(const osgGA::GUIEventAdapter& ea);

         /**
          * Handles a \c KEYUP event triggered by OSG. The only signal triggered
          * here is <tt>"KeyUp"</tt>.
          * @param ea The event generated by OSG.
          */
         void handleKeyUpEvent(const osgGA::GUIEventAdapter& ea);

         /**
          * Handles a \c SCROLL event triggered by OSG. The signals triggered
          * here are <tt>"ScrollUp"</tt> and <tt>"ScrollDown"</tt>.
          * @param ea The event generated by OSG.
          */
         void handleScrollEvent(const osgGA::GUIEventAdapter& ea);

         /**
          * If this is \c true, faces back-facing the viewer will be ignored
          * while picking.
          */
         bool ignoreBackFaces_;

         /**
          * The sequence of node masks used when picking.
          * @see setPickingRoot for a discussion on how this is used and why
          *      this is necessary.
          */
         NodeMasks_t pickingMasks_;

         /**
          * The values to be returned by the \c handle() method, depending on
          * the event type it is handling. Currently, this is not initialized,
          * meaning that \c handle(), by default, returns \c false for all event
          * types.
          * @todo Implement a method like \c setHandleReturnValue(), so that the
          *        user can configure this.
          */
         std::map <osgGA::GUIEventAdapter::EventType, bool> handleReturnValues_;

         /// Type mapping a signal name to the signal object.
         typedef std::map <std::string, SignalPtr> SignalCollection_t;

         /// Type mapping nodes to the collection of signals associated to it.
         typedef std::map <NodePtr, SignalCollection_t > SignalsMap_t;

         /**
          * Structure containing all the signals used by this \c EventHandler.
          * It can be used with a syntax like this:
          * <tt>signals_[node]["MouseMove"]->connect(&MyHandler);</tt>
          */
         SignalsMap_t signals_;

         /**
          * The \c Intersection_t structure for the node currently under the
          * mouse pointer. (Respecting the \c ignoreBackFaces_ flag.)
          */
         Intersection_t hitUnderMouse_;

         //
         // For "MouseEnter", "MouseLeave", "MouseMove"
         //

         /// The node currently under the mouse pointer.
         NodePtr nodeUnderMouse_;

         /**
          * The position (in the object coordinate system) of \c nodeUnderMouse_
          * currently under the mouse pointer.
          */
         osg::Vec3 positionUnderMouse_;

         //
         // For "Click" and "DoubleClick"
         //

         /// The buttons of a mouse.
         enum MouseButton
         {
            LEFT_MOUSE_BUTTON,   ///< The left button.
            MIDDLE_MOUSE_BUTTON, ///< The middle button.
            RIGHT_MOUSE_BUTTON,  ///< The right button.
            MOUSE_BUTTON_COUNT   ///< The number of buttons in a mouse.
         };

         /**
          * Returns the mouse button used in the \c osgGA::GUIEventAdapter
          * passed as parameter.
          */
         MouseButton getMouseButton(const osgGA::GUIEventAdapter& ea);

         /**
          * An array indicating (for every mouse button) which was the node that
          * received the last mouse down event. This is used to identify clicks.
          */
         NodePtr nodeThatGotMouseDown_[MOUSE_BUTTON_COUNT];

         /**
          * An array indicating (for every mouse button) which was the node that
          * received the last click event. This is used to identify double
          * clicks.
          */
         NodePtr nodeThatGotClick_[MOUSE_BUTTON_COUNT];

         /**
          * An array indicating (for every mouse button) the time at which the
          * last click event has happened. This is used to identify double
          * clicks.
          */
         double timeOfLastClick_[MOUSE_BUTTON_COUNT];

         //
         // For "KeyUp" and "KeyDown"
         //

         /// The node receiving keyboard events.
         NodePtr kbdFocus_;

         /// The focus policy for keyboard-related events.
         FocusPolicyPtr kbdFocusPolicy_;

         //
         // For "MouseWheelUp" and "MouseWheelDown"
         //

         /// The node receiving mouse wheel events.
         NodePtr wheelFocus_;

         /// The focus policy for mouse wheel-related events.
         FocusPolicyPtr wheelFocusPolicy_;
   };

} // namespace OSGUIsh

#endif // _GUISH_EVENT_HANDLER_HPP_
<commit_msg>Documented a missing parameter.<commit_after>/******************************************************************************\
* EventHandler.hpp                                                             *
* An event handler providing GUI-like events                                   *
*                                                                              *
* Copyright (C) 2006-2010 by Leandro Motta Barros.                             *
*                                                                              *
* This program is distributed under the OpenSceneGraph Public License. You     *
* should have received a copy of it with the source distribution, in a file    *
* named 'COPYING.txt'.                                                         *
\******************************************************************************/

#ifndef _GUISH_EVENT_HANDLER_HPP_
#define _GUISH_EVENT_HANDLER_HPP_

#include <boost/signal.hpp>
#include <osgGA/GUIEventHandler>
#include <osgUtil/LineSegmentIntersector>
#include <osgViewer/View>
#include <OSGUIsh/FocusPolicy.hpp>
#include <OSGUIsh/ManualFocusPolicy.hpp>

namespace OSGUIsh
{
   /**
    * A \c struct grouping parameters passed to event handlers. Future versions
    * of OSGUish may add more members here if necessary without breaking
    * existing user code.
    * @note Be aware that, in the general case, <tt>hit.nodePath.back() !=
    *       node</tt>. \c hit contains the actual, "low level" hit, while \c
    *       node contains the node registered with OSGUish. For instance,
    *       suppose you register a car node, that has a car body node and four
    *       wheel nodes as subnodes. \c node will always be the whole car, while
    *       \c hit will be the "car body" or one of the "wheels".
    */
   struct HandlerParams
   {
      public:
         /// Convenience constructor.
         HandlerParams(NodePtr nodeParam,
                       const osgGA::GUIEventAdapter& eventParam,
                       const Intersection_t& hitParam)
            : node(nodeParam), event(eventParam), hit(hitParam)
         { }

         /// The node generating the event.
         NodePtr node;

         /**
          * The event data, as passed by OSG. Here you can find many useful
          * information, like "which mouse button was pressed".
          */
         const osgGA::GUIEventAdapter& event;

         /**
          * The \c Intersection_t for the node that was under the mouse pointer
          * when the event was generated.
          * @note Notice that, in some cases, the \c Intersection_t for the node
          *       under the mouse pointer doesn't really have something to do
          *       with the event being handled. For example, if the event is a
          *       \c KeyUp and the focus policy is not the "node under mouse has
          *       focus" policy, than the hit may not be related to the node
          *       generating the event.
          *       <p>Also, in cases like that, the hit may even be invalid,
          *       since, perhaps, there will not be any registered node under
          *       the mouse pointer. Figuring out if \c hit contains valid and
          *       meaningful information is up to the user.
          */
         const Intersection_t& hit;
   };

   /**
    * An event handler providing GUI-like events for nodes. The \c EventHandler
    * has an internal list of nodes being "observed". Every observed node has a
    * collection of signals associated to it. These signals represent the events
    * that can be generated for the node.
    */
   class EventHandler: public osgGA::GUIEventHandler
   {
      public:
         /**
          * Constructs an \c EventHandler.
          * @param kbdPolicyFactory The factory that will be used to create the
          *        \c FocusPolicy used to automatically set the focus for
          *        keyboard events.
          * @param wheelPolicyFactory The factory that will be used to create
          *        the \c FocusPolicy used to automatically set the focus for
          *        mouse wheel events.
          */
         EventHandler(const FocusPolicyFactory& kbdPolicyFactory =
                      FocusPolicyFactoryMason<ManualFocusPolicy>(),
                      const FocusPolicyFactory& wheelPolicyFactory =
                      FocusPolicyFactoryMason<ManualFocusPolicy>());

         /**
          * Handles upcoming events (overloads virtual method).
          * @return See \c handleReturnValues_, please.
          */
         bool handle(const osgGA::GUIEventAdapter& ea,
                     osgGA::GUIActionAdapter&);

         /// A type representing a sequence of node masks.
         typedef std::vector<osg::Node::NodeMask> NodeMasks_t;

         /**
          * Sets node mask that will be used when picking. The default node mask
          * is 0xFFFFFFFF, meaning that every node with at least one bit set on
          * their node masks will be taken into account for picking. (All this
          * just means that you don't change any setting related to node masks,
          * OSGUIsh will not ignore any node when picking.)
          *
          * So, when should one explicitly set the picking mask? The easy answer
          * is "whenever one wants to ignore some nodes when picking". (When
          * picking, OSGUIsh (OSG, in fact) will perform a bitwise AND between
          * the picking root set here and each node's node mask; if the result
          * is zero, the node will be ignored.)
          *
          * The interesting part is that OSGUIsh supports multiple picking
          * masks. First, it will try to pick nodes using the first node mask;
          * if no node is picked, it will try picking using the second picking
          * mask and so on.
          *
          * Creative people may find various uses for this, but the feature was
          * implemented so that picking could work with HUDs. When using
          * multiple <tt>osg::Camera</tt>s (as is the case when using HUDs),
          * picking in OSG can be problematic. The details of this problem are
          * not important here (anyway, basically, we don't have control on the
          * relative "z-order" of objects viewed by different
          * <tt>Camera</tt>s). But it is important to know that, if we want to
          * pick objects in different camera nodes, we may have some
          * unpredictable results.
          *
          * So, to enable proper picking in HUDs, OSGUIsh can use this scheme of
          * multiple picking roots.
          *
          * @see setPickingMasks() which are the methods capable of setting
          *      multiple picking roots.
          *
          * @param newMask The new node mask to be used when picking.
          */
         void setPickingMask(osg::Node::NodeMask newMask);

         /**
          * Sets the node masks used when picking.
          * @param newMask1 The first node mask to be tried when picking.
          * @param newMask2 The second node mask to be tried when picking.
          * @see setPickingMask for a description of why using multiple picking
          *      roots can be useful (tip: HUD).
          */
         void setPickingMasks(osg::Node::NodeMask newMask1,
                              osg::Node::NodeMask newMask2);

         /**
          * Sets the node masks used when picking.
          * @param newMask1 The first node mask to be tried when picking.
          * @param newMask2 The second node mask to be tried when picking.
          * @param newMask3 The third node mask to be tried when picking.
          * @see setPickingMask for a description of why using multiple picking
          *      roots can be useful (tip: HUD).
          */
         void setPickingMasks(osg::Node::NodeMask newMask1,
                              osg::Node::NodeMask newMask2,
                              osg::Node::NodeMask newMask3);

         /**
          * Sets the node masks used when picking.
          * @param newMasks A vector with the node masks to be tried when
          *        picking (they'll be tried in sequence).
          * @see setPickingMask for a description of why using multiple picking
          *      roots can be useful (tip: HUD).
          */
         void setPickingMasks(const NodeMasks_t& newMasks);

         /**
          * A type representing a signal used in OSGUIsh. This signal returns
          * nothing and takes a \c HandlerParams, which packs all relevant data
          * for an event handler function.
          */
         typedef boost::signal<void (HandlerParams&)> Signal_t;

         /// A (smart) pointer to a \c Signal_t;
         typedef boost::shared_ptr<Signal_t> SignalPtr;

         /**
          * Adds a given node to the list of nodes being "observed" by this \c
          * EventHandler. In other words, after this call, signals for this node
          * will be triggered.
          * @param node The node that will be added to this \c EventHandler.
          */
         void addNode(const NodePtr node);

         /**
          * Returns a signal associated with a given node. This is typically
          * used to call \c connect() on the returned signal.
          * @param node The desired node.
          * @param signal The desired signal. Valid signals are
          *        <tt>"MouseEnter"</tt>, <tt>"MouseLeave"</tt>,
          *        <tt>"MouseMove"</tt>, <tt>"MouseDown"</tt>,
          *        <tt>"MouseUp"</tt>, <tt>"Click"</tt>, <tt>"DoubleClick"</tt>,
          *        <tt>"MouseWheelUp"</tt>, <tt>"MouseWheelDown"</tt>,
          *        <tt>"KeyUp"</tt> and <tt>"KeyDown"</tt>.
          * @note The "mouse move" event is "relative": if the mouse is not
          *       moving, but a node is moving "below" it, mouse move events
          *       will be generated.
          */
         SignalPtr getSignal(const NodePtr node, const std::string& signal);

         /**
          * Ignores or stops to ignore faces that are back-facing the viewer
          * when picking. It may be useful to ignore back faces when backface
          * culling is enabled.
          * @param ignore If \c true, back faces will be ignored when picking.
          *        If \c false, back faces will be considered when piking.
          * @bug "Ignore back faces" will not work always. More specifically, it
          *      will work only when picking gets at least two hits. It doesn't
          *      matter if these two hits are of front or back facing faces (or
          *      a combination of them). If there is only a single hit, it will
          *      not be ignored, even the face hit was a back facing one.
          */
         void ignoreBackFaces(bool ignore = true)
         { ignoreBackFaces_ = ignore; }

         /**
          * Manually sets the node that will receive keyboard events. Notice
          * that focus policies allow to set this automatically.
          */
         void setKeyboardFocus(const NodePtr node);

         /**
          * Sets the node that will receive mouse wheel events. Notice that
          * focus policies allow to set this automatically.
          */
         void setMouseWheelFocus(const NodePtr node);

         /**
          * Sets the focus policy for keyboard events to a given one.
          * @param policyFactory The factory that will be used to create the
          *        actual policy.
          */
         void setKeyboardFocusPolicy(const FocusPolicyFactory& policyFactory);

         /**
          * Sets the focus policy for mouse wheel events to a given one.
          * @param policyFactory The factory that will be used to create the
          *        actual policy.
          */
         void setMouseWheelFocusPolicy(const FocusPolicyFactory& policyFactory);

      private:
         /**
          * Returns the first node in an \c osg::NodePath that is present in the
          * list of nodes being "observed" by this \c EventHandler. This is
          * necessary in the cases in which the user is picking a node that is
          * child of an added node. That's the case, for instance, of when the
          * user adds a node read from a 3D model file returned by \c
          * osgDB::readNodeFile().
          * @param nodePath The node path leading to the node being queried.
          * @returns The first node in \c nodePath that was added to the list of
          *          nodes being observed.
          */
         NodePtr getObservedNode(const osg::NodePath& nodePath);

         /**
          * Handles a \c FRAME event triggered by OSG. Signals triggered here
          * are <tt>"MouseEnter"</tt>, <tt>"MouseLeave"</tt> and
          * <tt>"MouseMove"</tt>.
          * @param view The view displaying the scene.
          * @param ea The event generated by OSG.
          */
         void handleFrameEvent(osgViewer::View* view,
                               const osgGA::GUIEventAdapter& ea);

         /**
          * Handles a \c PUSH event triggered by OSG. The only signal triggered
          * here is <tt>"MouseDown"</tt>, but this function also does
          * bookkeeping related to other mouse signals.
          * @param ea The event generated by OSG.
          */
         void handlePushEvent(const osgGA::GUIEventAdapter& ea);

         /**
          * Handles a \c RELEASE event triggered by OSG. Signals triggered here
          * are <tt>"MouseUp"</tt>, <tt>"Click"</tt> and <tt>"DoubleClick"</tt>.
          * @param ea The event generated by OSG.
          */
         void handleReleaseEvent(const osgGA::GUIEventAdapter& ea);

         /**
          * Handles a \c KEYDOWN event triggered by OSG. The only signal
          * triggered here is <tt>"KeyDown"</tt>.
          * @param ea The event generated by OSG.
          */
         void handleKeyDownEvent(const osgGA::GUIEventAdapter& ea);

         /**
          * Handles a \c KEYUP event triggered by OSG. The only signal triggered
          * here is <tt>"KeyUp"</tt>.
          * @param ea The event generated by OSG.
          */
         void handleKeyUpEvent(const osgGA::GUIEventAdapter& ea);

         /**
          * Handles a \c SCROLL event triggered by OSG. The signals triggered
          * here are <tt>"ScrollUp"</tt> and <tt>"ScrollDown"</tt>.
          * @param ea The event generated by OSG.
          */
         void handleScrollEvent(const osgGA::GUIEventAdapter& ea);

         /**
          * If this is \c true, faces back-facing the viewer will be ignored
          * while picking.
          */
         bool ignoreBackFaces_;

         /**
          * The sequence of node masks used when picking.
          * @see setPickingRoot for a discussion on how this is used and why
          *      this is necessary.
          */
         NodeMasks_t pickingMasks_;

         /**
          * The values to be returned by the \c handle() method, depending on
          * the event type it is handling. Currently, this is not initialized,
          * meaning that \c handle(), by default, returns \c false for all event
          * types.
          * @todo Implement a method like \c setHandleReturnValue(), so that the
          *        user can configure this.
          */
         std::map <osgGA::GUIEventAdapter::EventType, bool> handleReturnValues_;

         /// Type mapping a signal name to the signal object.
         typedef std::map <std::string, SignalPtr> SignalCollection_t;

         /// Type mapping nodes to the collection of signals associated to it.
         typedef std::map <NodePtr, SignalCollection_t > SignalsMap_t;

         /**
          * Structure containing all the signals used by this \c EventHandler.
          * It can be used with a syntax like this:
          * <tt>signals_[node]["MouseMove"]->connect(&MyHandler);</tt>
          */
         SignalsMap_t signals_;

         /**
          * The \c Intersection_t structure for the node currently under the
          * mouse pointer. (Respecting the \c ignoreBackFaces_ flag.)
          */
         Intersection_t hitUnderMouse_;

         //
         // For "MouseEnter", "MouseLeave", "MouseMove"
         //

         /// The node currently under the mouse pointer.
         NodePtr nodeUnderMouse_;

         /**
          * The position (in the object coordinate system) of \c nodeUnderMouse_
          * currently under the mouse pointer.
          */
         osg::Vec3 positionUnderMouse_;

         //
         // For "Click" and "DoubleClick"
         //

         /// The buttons of a mouse.
         enum MouseButton
         {
            LEFT_MOUSE_BUTTON,   ///< The left button.
            MIDDLE_MOUSE_BUTTON, ///< The middle button.
            RIGHT_MOUSE_BUTTON,  ///< The right button.
            MOUSE_BUTTON_COUNT   ///< The number of buttons in a mouse.
         };

         /**
          * Returns the mouse button used in the \c osgGA::GUIEventAdapter
          * passed as parameter.
          */
         MouseButton getMouseButton(const osgGA::GUIEventAdapter& ea);

         /**
          * An array indicating (for every mouse button) which was the node that
          * received the last mouse down event. This is used to identify clicks.
          */
         NodePtr nodeThatGotMouseDown_[MOUSE_BUTTON_COUNT];

         /**
          * An array indicating (for every mouse button) which was the node that
          * received the last click event. This is used to identify double
          * clicks.
          */
         NodePtr nodeThatGotClick_[MOUSE_BUTTON_COUNT];

         /**
          * An array indicating (for every mouse button) the time at which the
          * last click event has happened. This is used to identify double
          * clicks.
          */
         double timeOfLastClick_[MOUSE_BUTTON_COUNT];

         //
         // For "KeyUp" and "KeyDown"
         //

         /// The node receiving keyboard events.
         NodePtr kbdFocus_;

         /// The focus policy for keyboard-related events.
         FocusPolicyPtr kbdFocusPolicy_;

         //
         // For "MouseWheelUp" and "MouseWheelDown"
         //

         /// The node receiving mouse wheel events.
         NodePtr wheelFocus_;

         /// The focus policy for mouse wheel-related events.
         FocusPolicyPtr wheelFocusPolicy_;
   };

} // namespace OSGUIsh

#endif // _GUISH_EVENT_HANDLER_HPP_
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: typedetectionimport.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-03-29 14:53:15 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): Martin Gallwey (gallwey@sun.com)
 *
 *
 ************************************************************************/

#ifndef _COM_SUN_STAR_XML_SAX_INPUTSOURCE_HPP_
#include <com/sun/star/xml/sax/InputSource.hpp>
#endif
#ifndef _COM_SUN_STAR_XML_SAX_XPARSER_HPP_
#include <com/sun/star/xml/sax/XParser.hpp>
#endif
#ifndef _COM_SUN_STAR_XML_SAX_XATTRIBUTELIST_HPP_
#include <com/sun/star/xml/sax/XAttributeList.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_PROPERTYVALUE_HPP_
#include <com/sun/star/beans/PropertyValue.hpp>
#endif

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

#include "typedetectionimport.hxx"
#include "xmlfiltersettingsdialog.hxx"

using namespace com::sun::star::lang;
using namespace com::sun::star::uno;
using namespace com::sun::star::io;
using namespace com::sun::star::beans;
using namespace com::sun::star::xml::sax;
using namespace com::sun::star;
using namespace rtl;
using namespace std;

TypeDetectionImporter::TypeDetectionImporter( Reference< XMultiServiceFactory >& xMSF )
:   mxMSF(xMSF),
    sCdataAttribute( RTL_CONSTASCII_USTRINGPARAM( "CDATA" ) ),
    sWhiteSpace( RTL_CONSTASCII_USTRINGPARAM( " " ) ),
    sRootNode( RTL_CONSTASCII_USTRINGPARAM( "oor:component-data" ) ),
    sNode( RTL_CONSTASCII_USTRINGPARAM( "node" ) ),
    sName( RTL_CONSTASCII_USTRINGPARAM( "oor:name" ) ),
    sProp( RTL_CONSTASCII_USTRINGPARAM( "prop" ) ),
    sValue( RTL_CONSTASCII_USTRINGPARAM( "value" ) ),
    sUIName( RTL_CONSTASCII_USTRINGPARAM( "UIName" ) ),
    sData( RTL_CONSTASCII_USTRINGPARAM( "Data" ) ),
    sFilters( RTL_CONSTASCII_USTRINGPARAM( "Filters" ) ),
    sTypes( RTL_CONSTASCII_USTRINGPARAM( "Types" ) ),
    sFilterAdaptorService( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.comp.Writer.XmlFilterAdaptor" ) ),
    sXSLTFilterService( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.documentconversion.XSLTFilter" ) )
{
}

TypeDetectionImporter::~TypeDetectionImporter (void )
{
}

void TypeDetectionImporter::doImport( Reference< XMultiServiceFactory >& xMSF, Reference< XInputStream > xIS, XMLFilterVector& rFilters )
{
    try
    {
        Reference< XParser > xParser( xMSF->createInstance(OUString::createFromAscii( "com.sun.star.xml.sax.Parser" ) ), UNO_QUERY );
        if( xParser.is() )
        {
            TypeDetectionImporter* pImporter = new TypeDetectionImporter( xMSF );
            Reference < XDocumentHandler > xDocHandler( pImporter );
            xParser->setDocumentHandler( xDocHandler );

            InputSource source;
            source.aInputStream = xIS;

            // start parsing
            xParser->parseStream( source );

            pImporter->fillFilterVector( rFilters );
        }
    }
    catch( Exception& e )
    {
        DBG_ERROR( "TypeDetectionImporter::doImport exception catched!" );
    }
}

void TypeDetectionImporter::fillFilterVector(  XMLFilterVector& rFilters )
{
    // create filter infos from imported filter nodes
    NodeVector::iterator aIter = maFilterNodes.begin();
    while( aIter != maFilterNodes.end() )
    {
        filter_info_impl* pFilter = createFilterForNode( (*aIter) );
        if( pFilter )
            rFilters.push_back( pFilter );

        delete (*aIter++);
    }

    // now delete type nodes
    aIter = maTypeNodes.begin();
    while( aIter != maTypeNodes.end() )
        delete (*aIter++);
}

static OUString getSubdata( int index, sal_Unicode delimeter, const OUString& rData )
{
    sal_Int32 nLastIndex = 0;

    sal_Int32 nNextIndex = rData.indexOf( delimeter );

    OUString aSubdata;

    while( index )
    {
        nLastIndex = nNextIndex + 1;
        nNextIndex = rData.indexOf( delimeter, nLastIndex );

        index--;

        if( (index > 0) && (nLastIndex == 0) )
            return aSubdata;
    }

    if( nNextIndex == -1 )
    {
        aSubdata = rData.copy( nLastIndex );
    }
    else
    {
        aSubdata = rData.copy( nLastIndex, nNextIndex - nLastIndex );
    }

    return aSubdata;
}

Node* TypeDetectionImporter::findTypeNode( const OUString& rType )
{
    // now delete type nodes
    NodeVector::iterator aIter = maTypeNodes.begin();
    while( aIter != maTypeNodes.end() )
    {
        if( (*aIter)->maName == rType )
            return (*aIter);

        aIter++;
    }

    return NULL;
}

filter_info_impl* TypeDetectionImporter::createFilterForNode( Node * pNode )
{
    filter_info_impl* pFilter = new filter_info_impl;

    pFilter->maFilterName = pNode->maName;
    pFilter->maInterfaceName = pNode->maPropertyMap[sUIName];

    OUString aData = pNode->maPropertyMap[sData];

    sal_Unicode aComma(',');

    pFilter->maType = getSubdata( 1, aComma, aData  );
    pFilter->maDocumentService = getSubdata( 2, aComma, aData );

    OUString aFilterService( getSubdata( 3, aComma, aData ) );
    pFilter->maFlags = getSubdata( 4, aComma, aData ).toInt32();

    // parse filter user data
    sal_Unicode aDelim(';');
    OUString aFilterUserData( getSubdata( 5, aComma, aData ) );

    OUString aAdapterService( getSubdata( 0, aDelim, aFilterUserData ) );
    //Import/ExportService
    pFilter->maImportService = getSubdata( 2, aDelim, aFilterUserData );
    pFilter->maExportService = getSubdata( 3, aDelim, aFilterUserData );
    pFilter->maImportXSLT = getSubdata( 4, aDelim, aFilterUserData );
    pFilter->maExportXSLT = getSubdata( 5, aDelim, aFilterUserData );
    pFilter->maDTD = getSubdata( 6, aDelim, aFilterUserData );
    pFilter->maComment = getSubdata( 7, aDelim, aFilterUserData );

    pFilter->maImportTemplate = getSubdata( 7, aComma, aData );

    Node* pTypeNode = findTypeNode( pFilter->maType );
    if( pTypeNode )
    {
        OUString aTypeUserData( pTypeNode->maPropertyMap[sData] );

        pFilter->maDocType = getSubdata( 2, aComma, aTypeUserData );
        pFilter->maExtension = getSubdata( 4, aComma, aTypeUserData );
        pFilter->mnDocumentIconID = getSubdata( 5, aComma, aTypeUserData ).toInt32();
    }

    bool bOk = true;

    if( pTypeNode == NULL )
        bOk = false;

    if( pFilter->maFilterName.getLength() == 0 )
        bOk = false;

    if( pFilter->maInterfaceName.getLength() == 0 )
        bOk = false;

    if( pFilter->maType.getLength() == 0 )
        bOk = false;

    if( pFilter->maFlags == 0 )
        bOk = false;

    if( aFilterService != sFilterAdaptorService )
        bOk = false;

    if( aAdapterService != sXSLTFilterService )
        bOk = false;

    if( pFilter->maExtension.getLength() == 0 )
        bOk = false;

    if( !bOk )
    {
        delete pFilter;
        pFilter = NULL;
    }

    return pFilter;
}

void SAL_CALL TypeDetectionImporter::startDocument(  )
        throw(xml::sax::SAXException, uno::RuntimeException)
{
}

void SAL_CALL TypeDetectionImporter::endDocument(  )
        throw(xml::sax::SAXException, uno::RuntimeException)
{
}

void SAL_CALL TypeDetectionImporter::startElement( const OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs )
        throw(xml::sax::SAXException, uno::RuntimeException)
{
    ImportState eNewState = e_Unknown;

    if( maStack.empty() )
    {
        // #109668# support legacy name as well on import
        if( aName == sRootNode || aName.equalsAscii("oor:node") )
        {
            eNewState = e_Root;
        }
    }
    else if( maStack.top() == e_Root )
    {
        if( aName == sNode )
        {
            OUString aNodeName( xAttribs->getValueByName( sName ) );

            if( aNodeName == sFilters )
            {
                eNewState = e_Filters;
            }
            else if( aNodeName == sTypes )
            {
                eNewState = e_Types;
            }
        }
    }
    else if( (maStack.top() == e_Filters) || (maStack.top() == e_Types) )
    {
        if( aName == sNode )
        {
            maNodeName = xAttribs->getValueByName( sName );

            eNewState = (maStack.top() == e_Filters) ? e_Filter : e_Type;
        }
    }
    else if( (maStack.top() == e_Filter) || (maStack.top() == e_Type))
    {
        if( aName == sProp )
        {
            maPropertyName = xAttribs->getValueByName( sName );
            eNewState = e_Property;
        }
    }
    else if( maStack.top() == e_Property )
    {
        if( aName == sValue )
        {
            eNewState = e_Value;
            maValue = OUString();
        }
    }

    maStack.push( eNewState );
}
void SAL_CALL TypeDetectionImporter::endElement( const OUString& aName )
    throw(xml::sax::SAXException, uno::RuntimeException)
{
    if( !maStack.empty()  )
    {
        ImportState eCurrentState = maStack.top();
        switch( eCurrentState )
        {
        case e_Filter:
        case e_Type:
            {
                Node* pNode = new Node;
                pNode->maName = maNodeName;
                pNode->maPropertyMap = maPropertyMap;
                maPropertyMap.clear();

                if( eCurrentState == e_Filter )
                {
                    maFilterNodes.push_back( pNode );
                }
                else
                {
                    maTypeNodes.push_back( pNode );
                }
            }
            break;

        case e_Property:
            maPropertyMap[ maPropertyName ] = maValue;
            break;
        }

        maStack.pop();
    }
}
void SAL_CALL TypeDetectionImporter::characters( const OUString& aChars )
        throw(xml::sax::SAXException, uno::RuntimeException)
{
    if( !maStack.empty() && maStack.top() == e_Value )
    {
        maValue += aChars;
    }
}
void SAL_CALL TypeDetectionImporter::ignorableWhitespace( const OUString& aWhitespaces )
        throw(xml::sax::SAXException, uno::RuntimeException)
{
}
void SAL_CALL TypeDetectionImporter::processingInstruction( const OUString& aTarget, const OUString& aData )
        throw(xml::sax::SAXException, uno::RuntimeException)
{
}
void SAL_CALL TypeDetectionImporter::setDocumentLocator( const uno::Reference< xml::sax::XLocator >& xLocator )
        throw(xml::sax::SAXException, uno::RuntimeException)
{
}

<commit_msg>INTEGRATION: CWS ooo19126 (1.4.114); FILE MERGED 2005/09/05 14:31:50 rt 1.4.114.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: typedetectionimport.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 22:15:40 $
 *
 *  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 _COM_SUN_STAR_XML_SAX_INPUTSOURCE_HPP_
#include <com/sun/star/xml/sax/InputSource.hpp>
#endif
#ifndef _COM_SUN_STAR_XML_SAX_XPARSER_HPP_
#include <com/sun/star/xml/sax/XParser.hpp>
#endif
#ifndef _COM_SUN_STAR_XML_SAX_XATTRIBUTELIST_HPP_
#include <com/sun/star/xml/sax/XAttributeList.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_PROPERTYVALUE_HPP_
#include <com/sun/star/beans/PropertyValue.hpp>
#endif

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

#include "typedetectionimport.hxx"
#include "xmlfiltersettingsdialog.hxx"

using namespace com::sun::star::lang;
using namespace com::sun::star::uno;
using namespace com::sun::star::io;
using namespace com::sun::star::beans;
using namespace com::sun::star::xml::sax;
using namespace com::sun::star;
using namespace rtl;
using namespace std;

TypeDetectionImporter::TypeDetectionImporter( Reference< XMultiServiceFactory >& xMSF )
:   mxMSF(xMSF),
    sCdataAttribute( RTL_CONSTASCII_USTRINGPARAM( "CDATA" ) ),
    sWhiteSpace( RTL_CONSTASCII_USTRINGPARAM( " " ) ),
    sRootNode( RTL_CONSTASCII_USTRINGPARAM( "oor:component-data" ) ),
    sNode( RTL_CONSTASCII_USTRINGPARAM( "node" ) ),
    sName( RTL_CONSTASCII_USTRINGPARAM( "oor:name" ) ),
    sProp( RTL_CONSTASCII_USTRINGPARAM( "prop" ) ),
    sValue( RTL_CONSTASCII_USTRINGPARAM( "value" ) ),
    sUIName( RTL_CONSTASCII_USTRINGPARAM( "UIName" ) ),
    sData( RTL_CONSTASCII_USTRINGPARAM( "Data" ) ),
    sFilters( RTL_CONSTASCII_USTRINGPARAM( "Filters" ) ),
    sTypes( RTL_CONSTASCII_USTRINGPARAM( "Types" ) ),
    sFilterAdaptorService( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.comp.Writer.XmlFilterAdaptor" ) ),
    sXSLTFilterService( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.documentconversion.XSLTFilter" ) )
{
}

TypeDetectionImporter::~TypeDetectionImporter (void )
{
}

void TypeDetectionImporter::doImport( Reference< XMultiServiceFactory >& xMSF, Reference< XInputStream > xIS, XMLFilterVector& rFilters )
{
    try
    {
        Reference< XParser > xParser( xMSF->createInstance(OUString::createFromAscii( "com.sun.star.xml.sax.Parser" ) ), UNO_QUERY );
        if( xParser.is() )
        {
            TypeDetectionImporter* pImporter = new TypeDetectionImporter( xMSF );
            Reference < XDocumentHandler > xDocHandler( pImporter );
            xParser->setDocumentHandler( xDocHandler );

            InputSource source;
            source.aInputStream = xIS;

            // start parsing
            xParser->parseStream( source );

            pImporter->fillFilterVector( rFilters );
        }
    }
    catch( Exception& e )
    {
        DBG_ERROR( "TypeDetectionImporter::doImport exception catched!" );
    }
}

void TypeDetectionImporter::fillFilterVector(  XMLFilterVector& rFilters )
{
    // create filter infos from imported filter nodes
    NodeVector::iterator aIter = maFilterNodes.begin();
    while( aIter != maFilterNodes.end() )
    {
        filter_info_impl* pFilter = createFilterForNode( (*aIter) );
        if( pFilter )
            rFilters.push_back( pFilter );

        delete (*aIter++);
    }

    // now delete type nodes
    aIter = maTypeNodes.begin();
    while( aIter != maTypeNodes.end() )
        delete (*aIter++);
}

static OUString getSubdata( int index, sal_Unicode delimeter, const OUString& rData )
{
    sal_Int32 nLastIndex = 0;

    sal_Int32 nNextIndex = rData.indexOf( delimeter );

    OUString aSubdata;

    while( index )
    {
        nLastIndex = nNextIndex + 1;
        nNextIndex = rData.indexOf( delimeter, nLastIndex );

        index--;

        if( (index > 0) && (nLastIndex == 0) )
            return aSubdata;
    }

    if( nNextIndex == -1 )
    {
        aSubdata = rData.copy( nLastIndex );
    }
    else
    {
        aSubdata = rData.copy( nLastIndex, nNextIndex - nLastIndex );
    }

    return aSubdata;
}

Node* TypeDetectionImporter::findTypeNode( const OUString& rType )
{
    // now delete type nodes
    NodeVector::iterator aIter = maTypeNodes.begin();
    while( aIter != maTypeNodes.end() )
    {
        if( (*aIter)->maName == rType )
            return (*aIter);

        aIter++;
    }

    return NULL;
}

filter_info_impl* TypeDetectionImporter::createFilterForNode( Node * pNode )
{
    filter_info_impl* pFilter = new filter_info_impl;

    pFilter->maFilterName = pNode->maName;
    pFilter->maInterfaceName = pNode->maPropertyMap[sUIName];

    OUString aData = pNode->maPropertyMap[sData];

    sal_Unicode aComma(',');

    pFilter->maType = getSubdata( 1, aComma, aData  );
    pFilter->maDocumentService = getSubdata( 2, aComma, aData );

    OUString aFilterService( getSubdata( 3, aComma, aData ) );
    pFilter->maFlags = getSubdata( 4, aComma, aData ).toInt32();

    // parse filter user data
    sal_Unicode aDelim(';');
    OUString aFilterUserData( getSubdata( 5, aComma, aData ) );

    OUString aAdapterService( getSubdata( 0, aDelim, aFilterUserData ) );
    //Import/ExportService
    pFilter->maImportService = getSubdata( 2, aDelim, aFilterUserData );
    pFilter->maExportService = getSubdata( 3, aDelim, aFilterUserData );
    pFilter->maImportXSLT = getSubdata( 4, aDelim, aFilterUserData );
    pFilter->maExportXSLT = getSubdata( 5, aDelim, aFilterUserData );
    pFilter->maDTD = getSubdata( 6, aDelim, aFilterUserData );
    pFilter->maComment = getSubdata( 7, aDelim, aFilterUserData );

    pFilter->maImportTemplate = getSubdata( 7, aComma, aData );

    Node* pTypeNode = findTypeNode( pFilter->maType );
    if( pTypeNode )
    {
        OUString aTypeUserData( pTypeNode->maPropertyMap[sData] );

        pFilter->maDocType = getSubdata( 2, aComma, aTypeUserData );
        pFilter->maExtension = getSubdata( 4, aComma, aTypeUserData );
        pFilter->mnDocumentIconID = getSubdata( 5, aComma, aTypeUserData ).toInt32();
    }

    bool bOk = true;

    if( pTypeNode == NULL )
        bOk = false;

    if( pFilter->maFilterName.getLength() == 0 )
        bOk = false;

    if( pFilter->maInterfaceName.getLength() == 0 )
        bOk = false;

    if( pFilter->maType.getLength() == 0 )
        bOk = false;

    if( pFilter->maFlags == 0 )
        bOk = false;

    if( aFilterService != sFilterAdaptorService )
        bOk = false;

    if( aAdapterService != sXSLTFilterService )
        bOk = false;

    if( pFilter->maExtension.getLength() == 0 )
        bOk = false;

    if( !bOk )
    {
        delete pFilter;
        pFilter = NULL;
    }

    return pFilter;
}

void SAL_CALL TypeDetectionImporter::startDocument(  )
        throw(xml::sax::SAXException, uno::RuntimeException)
{
}

void SAL_CALL TypeDetectionImporter::endDocument(  )
        throw(xml::sax::SAXException, uno::RuntimeException)
{
}

void SAL_CALL TypeDetectionImporter::startElement( const OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs )
        throw(xml::sax::SAXException, uno::RuntimeException)
{
    ImportState eNewState = e_Unknown;

    if( maStack.empty() )
    {
        // #109668# support legacy name as well on import
        if( aName == sRootNode || aName.equalsAscii("oor:node") )
        {
            eNewState = e_Root;
        }
    }
    else if( maStack.top() == e_Root )
    {
        if( aName == sNode )
        {
            OUString aNodeName( xAttribs->getValueByName( sName ) );

            if( aNodeName == sFilters )
            {
                eNewState = e_Filters;
            }
            else if( aNodeName == sTypes )
            {
                eNewState = e_Types;
            }
        }
    }
    else if( (maStack.top() == e_Filters) || (maStack.top() == e_Types) )
    {
        if( aName == sNode )
        {
            maNodeName = xAttribs->getValueByName( sName );

            eNewState = (maStack.top() == e_Filters) ? e_Filter : e_Type;
        }
    }
    else if( (maStack.top() == e_Filter) || (maStack.top() == e_Type))
    {
        if( aName == sProp )
        {
            maPropertyName = xAttribs->getValueByName( sName );
            eNewState = e_Property;
        }
    }
    else if( maStack.top() == e_Property )
    {
        if( aName == sValue )
        {
            eNewState = e_Value;
            maValue = OUString();
        }
    }

    maStack.push( eNewState );
}
void SAL_CALL TypeDetectionImporter::endElement( const OUString& aName )
    throw(xml::sax::SAXException, uno::RuntimeException)
{
    if( !maStack.empty()  )
    {
        ImportState eCurrentState = maStack.top();
        switch( eCurrentState )
        {
        case e_Filter:
        case e_Type:
            {
                Node* pNode = new Node;
                pNode->maName = maNodeName;
                pNode->maPropertyMap = maPropertyMap;
                maPropertyMap.clear();

                if( eCurrentState == e_Filter )
                {
                    maFilterNodes.push_back( pNode );
                }
                else
                {
                    maTypeNodes.push_back( pNode );
                }
            }
            break;

        case e_Property:
            maPropertyMap[ maPropertyName ] = maValue;
            break;
        }

        maStack.pop();
    }
}
void SAL_CALL TypeDetectionImporter::characters( const OUString& aChars )
        throw(xml::sax::SAXException, uno::RuntimeException)
{
    if( !maStack.empty() && maStack.top() == e_Value )
    {
        maValue += aChars;
    }
}
void SAL_CALL TypeDetectionImporter::ignorableWhitespace( const OUString& aWhitespaces )
        throw(xml::sax::SAXException, uno::RuntimeException)
{
}
void SAL_CALL TypeDetectionImporter::processingInstruction( const OUString& aTarget, const OUString& aData )
        throw(xml::sax::SAXException, uno::RuntimeException)
{
}
void SAL_CALL TypeDetectionImporter::setDocumentLocator( const uno::Reference< xml::sax::XLocator >& xLocator )
        throw(xml::sax::SAXException, uno::RuntimeException)
{
}

<|endoftext|>


<commit_before>//
// File:   gmxtrajectoryreader.cc
// Author: ruehle
//
// Created on April 5, 2007, 2:42 PM
//

#include <iostream>
#include "topology.h"
#include "gmxtrajectoryreader.h"

using namespace std;

bool GMXTrajectoryReader::Open(const string &file)
{
       _filename = file;
       return true;
}

void GMXTrajectoryReader::Close()
{
    gmx::close_trx(_gmx_status);
}

bool GMXTrajectoryReader::FirstFrame(Topology &conf)
{
    if(!gmx::read_first_frame(&_gmx_status,(char*)_filename.c_str(),&_gmx_frame,TRX_READ_X | TRX_READ_F))
        return false;
    matrix m;
    for(int i=0; i<3; i++)
        for(int j=0; j<3; j++)
            m[i][j] = _gmx_frame.box[j][i];
    conf.setBox(m);
    conf.setTime(_gmx_frame.time);
    conf.setStep(_gmx_frame.step);
    cout << endl;

    //conf.HasPos(true);
    //conf.HasF(_gmx_frame.bF);

    for(int i=0; i<_gmx_frame.natoms; i++) {
        double r[3] = { _gmx_frame.x[i][XX],  _gmx_frame.x[i][YY], _gmx_frame.x[i][ZZ] };
        conf.getBead(i)->setPos(r);
        if(_gmx_frame.bF) {
            double f[3] = { _gmx_frame.f[i][XX],  _gmx_frame.f[i][YY], _gmx_frame.f[i][ZZ] };
            conf.getBead(i)->setF(f);
        }
    }
    return true;
}

bool GMXTrajectoryReader::NextFrame(Topology &conf)
{
    if(!gmx::read_next_frame(_gmx_status,&_gmx_frame))
        return false;
    matrix m;
    for(int i=0; i<3; i++)
        for(int j=0; j<3; j++)
            m[i][j] = _gmx_frame.box[j][i];
    conf.setTime(_gmx_frame.time);
    conf.setStep(_gmx_frame.step);
    conf.setBox(m);

    //conf.HasF(_gmx_frame.bF);

    for(int i=0; i<_gmx_frame.natoms; i++) {
        double r[3] = { _gmx_frame.x[i][XX],  _gmx_frame.x[i][YY], _gmx_frame.x[i][ZZ] };
        conf.getBead(i)->setPos(r);
        if(_gmx_frame.bF) {
            double f[3] = { _gmx_frame.f[i][XX],  _gmx_frame.f[i][YY], _gmx_frame.f[i][ZZ] };
            conf.getBead(i)->setF(f);
        }
    }
    return true;
}
<commit_msg>more strict checking for trajectoryreader<commit_after>//
// File:   gmxtrajectoryreader.cc
// Author: ruehle
//
// Created on April 5, 2007, 2:42 PM
//

#include <iostream>
#include "topology.h"
#include "gmxtrajectoryreader.h"

using namespace std;

bool GMXTrajectoryReader::Open(const string &file)
{
       _filename = file;
       return true;
}

void GMXTrajectoryReader::Close()
{
    gmx::close_trx(_gmx_status);
}

bool GMXTrajectoryReader::FirstFrame(Topology &conf)
{
    if(!gmx::read_first_frame(&_gmx_status,(char*)_filename.c_str(),&_gmx_frame,TRX_READ_X | TRX_READ_F))
        throw std::runtime_error(string("cannot open ") + _filename);

    matrix m;
    for(int i=0; i<3; i++)
        for(int j=0; j<3; j++)
            m[i][j] = _gmx_frame.box[j][i];
    conf.setBox(m);
    conf.setTime(_gmx_frame.time);
    conf.setStep(_gmx_frame.step);
    cout << endl;

    if(_gmx_frame.natoms != conf.Beads().size())
        throw std::runtime_error("number of beads in trajectory do not match topology");

    //conf.HasPos(true);
    //conf.HasF(_gmx_frame.bF);

    for(int i=0; i<_gmx_frame.natoms; i++) {
        double r[3] = { _gmx_frame.x[i][XX],  _gmx_frame.x[i][YY], _gmx_frame.x[i][ZZ] };
        conf.getBead(i)->setPos(r);
        if(_gmx_frame.bF) {
            double f[3] = { _gmx_frame.f[i][XX],  _gmx_frame.f[i][YY], _gmx_frame.f[i][ZZ] };
            conf.getBead(i)->setF(f);
        }
    }
    return true;
}

bool GMXTrajectoryReader::NextFrame(Topology &conf)
{
    if(!gmx::read_next_frame(_gmx_status,&_gmx_frame))
        return false;
    matrix m;
    for(int i=0; i<3; i++)
        for(int j=0; j<3; j++)
            m[i][j] = _gmx_frame.box[j][i];
    conf.setTime(_gmx_frame.time);
    conf.setStep(_gmx_frame.step);
    conf.setBox(m);

    //conf.HasF(_gmx_frame.bF);

    for(int i=0; i<_gmx_frame.natoms; i++) {
        double r[3] = { _gmx_frame.x[i][XX],  _gmx_frame.x[i][YY], _gmx_frame.x[i][ZZ] };
        conf.getBead(i)->setPos(r);
        if(_gmx_frame.bF) {
            double f[3] = { _gmx_frame.f[i][XX],  _gmx_frame.f[i][YY], _gmx_frame.f[i][ZZ] };
            conf.getBead(i)->setF(f);
        }
    }
    return true;
}
<|endoftext|>