<commit_before>/***********************************************************************
    created:    Wed Jan 13 2010
    author:     Paul D Turner <paul@cegui.org.uk>
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2010 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/
#include "CEGUI/GeometryBuffer.h"
#include "CEGUI/Vertex.h"
#include "CEGUI/ShaderParameterBindings.h"
#include "CEGUI/RenderTarget.h"

#include <glm/gtc/matrix_transform.hpp>

#include <vector>
#include <algorithm>
#include <iterator>
#include <stddef.h>

namespace CEGUI
{
//---------------------------------------------------------------------------//
GeometryBuffer::GeometryBuffer(RefCounted<RenderMaterial> renderMaterial):
    d_renderMaterial(renderMaterial),
    d_translation(0, 0, 0),
    d_rotation(1, 0, 0, 0), // <-- IDENTITY
    d_scale(1.0f, 1.0f, 1.0f),
    d_pivot(0, 0, 0),
    d_customTransform(1.0f),
    d_matrixValid(false),
    d_lastRenderTarget(0),
    d_lastRenderTargetActivationCount(0),
    d_blendMode(BM_NORMAL),
    d_polygonFillRule(PFR_NONE),
    d_postStencilVertexCount(0),
    d_effect(0),
    d_alpha(1.0f),
    d_clippingActive(false),
    d_clippingRegion(0, 0, 0, 0),
    d_preparedClippingRegion(0, 0, 0, 0)
{}

//---------------------------------------------------------------------------//
GeometryBuffer::~GeometryBuffer()
{}

//---------------------------------------------------------------------------//
void GeometryBuffer::setBlendMode(const BlendMode mode)
{
    d_blendMode = mode;
}

//---------------------------------------------------------------------------//
BlendMode GeometryBuffer::getBlendMode() const
{
    return d_blendMode;
}

//---------------------------------------------------------------------------//
void GeometryBuffer::appendGeometry(const std::vector<ColouredVertex>& coloured_vertices)
{
    if(coloured_vertices.empty())
        return;

    appendGeometry(&coloured_vertices[0], coloured_vertices.size());
}

//---------------------------------------------------------------------------//
void GeometryBuffer::appendGeometry(const ColouredVertex* vertex_array,
                                    std::size_t vertex_count)
{
    // Create a temporary array to contain our data
    static const std::size_t vertexDataSize = 7;
    std::size_t fullArraySize = vertexDataSize * vertex_count;
    float* vertexData = new float[fullArraySize];

    // Add the vertex data in their default order into an array
    const ColouredVertex* vs = vertex_array;
    for (std::size_t i = 0; i < vertex_count; ++i, ++vs)
    {
        // Add all the elements in the default order for textured and coloured
        // geometry into the vector
        std::size_t currentIndex = i * vertexDataSize;

        vertexData[currentIndex + 0] = vs->d_position.x;
        vertexData[currentIndex + 1] = vs->d_position.y;
        vertexData[currentIndex + 2] = vs->d_position.z;
        vertexData[currentIndex + 3] = vs->d_colour.x;
        vertexData[currentIndex + 4] = vs->d_colour.y;
        vertexData[currentIndex + 5] = vs->d_colour.z;
        vertexData[currentIndex + 6] = vs->d_colour.w;
    }

    // Append the prepared geometry data
    appendGeometry(vertexData, fullArraySize);

    delete[] vertexData;
}

//---------------------------------------------------------------------------//
void GeometryBuffer::appendGeometry(const std::vector<TexturedColouredVertex>& textured_vertices)
{
    if(textured_vertices.empty())
        return;

    appendGeometry(&textured_vertices[0], textured_vertices.size());
}

//---------------------------------------------------------------------------//
void GeometryBuffer::appendGeometry(const TexturedColouredVertex* vertex_array,
                                    std::size_t vertex_count)
{
    // Create a temporary array to contain our data
    static const std::size_t vertexDataSize = 9;
    std::size_t fullArraySize = vertexDataSize * vertex_count;
    float* vertexData = new float[fullArraySize];

    // Add the vertex data in their default order into an array
    const TexturedColouredVertex* vs = vertex_array;
    for (std::size_t i = 0; i < vertex_count; ++i, ++vs)
    {
        // Add all the elements in the default order for textured and coloured
        // geometry into the vector
        std::size_t currentIndex = i * vertexDataSize;

        vertexData[currentIndex + 0] = vs->d_position.x;
        vertexData[currentIndex + 1] = vs->d_position.y;
        vertexData[currentIndex + 2] = vs->d_position.z;
        vertexData[currentIndex + 3] = vs->d_colour.x;
        vertexData[currentIndex + 4] = vs->d_colour.y;
        vertexData[currentIndex + 5] = vs->d_colour.z;
        vertexData[currentIndex + 6] = vs->d_colour.w;
        vertexData[currentIndex + 7] = vs->d_texCoords.x;
        vertexData[currentIndex + 8] = vs->d_texCoords.y;
    }

    // Append the prepared geometry data
    appendGeometry(vertexData, fullArraySize);

    delete[] vertexData;
}

//---------------------------------------------------------------------------//
void GeometryBuffer::appendGeometry(const float* vertex_data,
                                    std::size_t array_size)
{
    d_vertexData.reserve( d_vertexData.size() + array_size);
    std::copy(vertex_data, vertex_data + array_size, std::back_inserter(d_vertexData));

    // Update size of geometry buffer
    d_vertexCount = d_vertexData.size() / getVertexAttributeElementCount();
}

//---------------------------------------------------------------------------//
void GeometryBuffer::appendVertex(const TexturedColouredVertex& vertex)
{
    // Add the vertex data in their default order into an array
    float vertexData[9];

    // Copy the vertex attributes into the array
    vertexData[0] = vertex.d_position.x;
    vertexData[1] = vertex.d_position.y;
    vertexData[2] = vertex.d_position.z;
    vertexData[3] = vertex.d_colour.x;
    vertexData[4] = vertex.d_colour.y;
    vertexData[5] = vertex.d_colour.z;
    vertexData[6] = vertex.d_colour.w;
    vertexData[7] = vertex.d_texCoords.x;
    vertexData[8] = vertex.d_texCoords.y;

    appendGeometry(vertexData, 9);
}

//---------------------------------------------------------------------------//
void GeometryBuffer::appendVertex(const ColouredVertex& vertex)
{
    // Add the vertex data in their default order into an array
    float vertexData[7];

    // Copy the vertex attributes into the array
    vertexData[0] = vertex.d_position.x;
    vertexData[1] = vertex.d_position.y;
    vertexData[2] = vertex.d_position.z;
    vertexData[3] = vertex.d_colour.x;
    vertexData[4] = vertex.d_colour.y;
    vertexData[5] = vertex.d_colour.z;
    vertexData[6] = vertex.d_colour.w;

    appendGeometry(vertexData, 7);
}

//---------------------------------------------------------------------------//
int GeometryBuffer::getVertexAttributeElementCount() const
{
    int count = 0;

    const unsigned int attribute_count = d_vertexAttributes.size();
    for (unsigned int i = 0; i < attribute_count; ++i)
    {
        switch(d_vertexAttributes.at(i))
        {
            case VAT_POSITION0:
                count += 3;
                break;
            case VAT_COLOUR0:
                count += 4;
                break;
            case VAT_TEXCOORD0:
                count += 2;
                break;
            default:
                break;
        }
    }

    return count;
}

//---------------------------------------------------------------------------//
void GeometryBuffer::resetVertexAttributes()
{
    d_vertexAttributes.clear();
}

//---------------------------------------------------------------------------//
void GeometryBuffer::addVertexAttribute(VertexAttributeType attribute)
{
    d_vertexAttributes.push_back(attribute);
}

//---------------------------------------------------------------------------//
RefCounted<RenderMaterial> GeometryBuffer::getRenderMaterial() const
{
    return d_renderMaterial;
}

//---------------------------------------------------------------------------//
void GeometryBuffer::setRenderMaterial(RefCounted<RenderMaterial> render_material)
{
    d_renderMaterial = render_material;
}

//---------------------------------------------------------------------------//
void GeometryBuffer::setStencilRenderingActive(PolygonFillRule fill_rule)
{
    d_polygonFillRule = fill_rule;
}

//---------------------------------------------------------------------------//
void GeometryBuffer::setStencilPostRenderingVertexCount(unsigned int vertex_count)
{
    d_postStencilVertexCount = vertex_count;
}

//----------------------------------------------------------------------------//
void GeometryBuffer::setRenderEffect(RenderEffect* effect)
{
    d_effect = effect;
}

//----------------------------------------------------------------------------//
RenderEffect* GeometryBuffer::getRenderEffect()
{
    return d_effect;
}

//----------------------------------------------------------------------------//
void GeometryBuffer::setTranslation(const glm::vec3& translation)
{
    if (d_translation != translation)
    {
        d_translation = translation;
        d_matrixValid = false;
    }
}

//----------------------------------------------------------------------------//
void GeometryBuffer::setRotation(const glm::quat& rotationQuat)
{
    if (d_rotation != rotationQuat)
    {
        d_rotation = rotationQuat;
        d_matrixValid = false;
    }
}

//----------------------------------------------------------------------------//
void GeometryBuffer::setScale(const glm::vec3& scale)
{
    if (d_scale != scale)
    {
        d_scale = scale;
        d_matrixValid = false;
    }
}

//----------------------------------------------------------------------------//
void GeometryBuffer::setScale(const glm::vec2& scale)
{
    setScale(glm::vec3(scale, 0));
}

//----------------------------------------------------------------------------//
void GeometryBuffer::setPivot(const glm::vec3& p)
{
    if (d_pivot != p)
    {
        d_pivot = p;
        d_matrixValid = false;
    }
}

//----------------------------------------------------------------------------//
void GeometryBuffer::setCustomTransform(const glm::mat4x4& transformation)
{
    if(d_customTransform != transformation)
    {
        d_customTransform = transformation;
        d_matrixValid = false;
    }
}

void GeometryBuffer::setClippingRegion(const Rectf& region)
{
    d_clippingRegion = region;

    d_preparedClippingRegion.top(std::max(0.0f, region.top()));
    d_preparedClippingRegion.bottom(std::max(0.0f, region.bottom()));
    d_preparedClippingRegion.left(std::max(0.0f, region.left()));
    d_preparedClippingRegion.right(std::max(0.0f, region.right()));
}

const Rectf& GeometryBuffer::getClippingRegion()
{
    return d_clippingRegion;
}

const Rectf& GeometryBuffer::getPreparedClippingRegion()
{
    return d_preparedClippingRegion;
}

//----------------------------------------------------------------------------//
void GeometryBuffer::setClippingActive(const bool active)
{
    d_clippingActive = active;
}

//----------------------------------------------------------------------------//
bool GeometryBuffer::isClippingActive() const
{
    return d_clippingActive;
}

//----------------------------------------------------------------------------//
std::size_t GeometryBuffer::getVertexCount() const
{
    return d_vertexCount;
}

//----------------------------------------------------------------------------//
void GeometryBuffer::reset()
{
    d_vertexData.clear();
    d_clippingActive = true;
}

//----------------------------------------------------------------------------//
void GeometryBuffer::setTexture(const std::string& parameterName, const Texture* texture)
{
    CEGUI::ShaderParameterBindings* shaderParameterBindings = (*d_renderMaterial).getShaderParamBindings();
    shaderParameterBindings->setParameter(parameterName, texture);
}

//---------------------------------------------------------------------------//
void GeometryBuffer::setAlpha(float alpha)
{
    d_alpha = alpha;
}

//---------------------------------------------------------------------------//
float GeometryBuffer::getAlpha() const
{
    return d_alpha;
}

//---------------------------------------------------------------------------//
void GeometryBuffer::invalidateMatrix()
{
    d_matrixValid = false;
}

//---------------------------------------------------------------------------//
const RenderTarget* GeometryBuffer::getLastRenderTarget() const
{
    return d_lastRenderTarget;
}

//---------------------------------------------------------------------------//
bool GeometryBuffer::isRenderTargetDataValid(const RenderTarget* activeRenderTarget) const
{
    //! The data received from the RenderTarget is only valid if:
    //! 1. The RenderTarget is the same as the one used the last time
    //! 2. The GeometryBuffer never skipped a RenderTarget activation (Checked via counter)
    return (d_lastRenderTarget == activeRenderTarget) && (d_lastRenderTargetActivationCount + 1 == activeRenderTarget->getActivationCounter());
}

//--------------------------------------------------------------------------//
void GeometryBuffer::updateRenderTargetData(const RenderTarget* activeRenderTarget) const
{
    d_lastRenderTarget = activeRenderTarget;
    d_lastRenderTargetActivationCount = activeRenderTarget->getActivationCounter();
}

//----------------------------------------------------------------------------//
glm::mat4 GeometryBuffer::getModelMatrix() const
{
    glm::mat4 modelMatrix = glm::translate(glm::mat4(1.0f), d_translation + d_pivot);

    const glm::mat4 scale_matrix(glm::scale(glm::mat4(1.0f), d_scale));
    modelMatrix *= glm::mat4_cast(d_rotation) * scale_matrix;

    const glm::mat4 translMatrix = glm::translate(glm::mat4(1.0f), -d_pivot);
    modelMatrix *=  translMatrix * d_customTransform;

    return modelMatrix;
}

}

<commit_msg>MOD: Code cleanup in GeometryBuffer constructor<commit_after>/***********************************************************************
    created:    Wed Jan 13 2010
    author:     Paul D Turner <paul@cegui.org.uk>
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2010 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/
#include "CEGUI/GeometryBuffer.h"
#include "CEGUI/Vertex.h"
#include "CEGUI/ShaderParameterBindings.h"
#include "CEGUI/RenderTarget.h"

#include <glm/gtc/matrix_transform.hpp>

#include <vector>
#include <algorithm>
#include <iterator>
#include <stddef.h>

namespace CEGUI
{
//---------------------------------------------------------------------------//
GeometryBuffer::GeometryBuffer(RefCounted<RenderMaterial> renderMaterial):
    d_renderMaterial(renderMaterial),
    d_vertexCount(0),
    d_translation(0, 0, 0),
    d_rotation(1, 0, 0, 0), // <-- IDENTITY
    d_scale(1.0f, 1.0f, 1.0f),
    d_pivot(0, 0, 0),
    d_customTransform(1.0f),
    d_matrixValid(false),
    d_lastRenderTarget(0),
    d_lastRenderTargetActivationCount(0),
    d_blendMode(BM_NORMAL),
    d_polygonFillRule(PFR_NONE),
    d_postStencilVertexCount(0),
    d_effect(nullptr),
    d_clippingRegion(0, 0, 0, 0),
    d_preparedClippingRegion(0, 0, 0, 0),
    d_clippingActive(false),
    d_alpha(1.0f)
{}

//---------------------------------------------------------------------------//
GeometryBuffer::~GeometryBuffer()
{}

//---------------------------------------------------------------------------//
void GeometryBuffer::setBlendMode(const BlendMode mode)
{
    d_blendMode = mode;
}

//---------------------------------------------------------------------------//
BlendMode GeometryBuffer::getBlendMode() const
{
    return d_blendMode;
}

//---------------------------------------------------------------------------//
void GeometryBuffer::appendGeometry(const std::vector<ColouredVertex>& coloured_vertices)
{
    if(coloured_vertices.empty())
        return;

    appendGeometry(&coloured_vertices[0], coloured_vertices.size());
}

//---------------------------------------------------------------------------//
void GeometryBuffer::appendGeometry(const ColouredVertex* vertex_array,
                                    std::size_t vertex_count)
{
    // Create a temporary array to contain our data
    static const std::size_t vertexDataSize = 7;
    std::size_t fullArraySize = vertexDataSize * vertex_count;
    float* vertexData = new float[fullArraySize];

    // Add the vertex data in their default order into an array
    const ColouredVertex* vs = vertex_array;
    for (std::size_t i = 0; i < vertex_count; ++i, ++vs)
    {
        // Add all the elements in the default order for textured and coloured
        // geometry into the vector
        std::size_t currentIndex = i * vertexDataSize;

        vertexData[currentIndex + 0] = vs->d_position.x;
        vertexData[currentIndex + 1] = vs->d_position.y;
        vertexData[currentIndex + 2] = vs->d_position.z;
        vertexData[currentIndex + 3] = vs->d_colour.x;
        vertexData[currentIndex + 4] = vs->d_colour.y;
        vertexData[currentIndex + 5] = vs->d_colour.z;
        vertexData[currentIndex + 6] = vs->d_colour.w;
    }

    // Append the prepared geometry data
    appendGeometry(vertexData, fullArraySize);

    delete[] vertexData;
}

//---------------------------------------------------------------------------//
void GeometryBuffer::appendGeometry(const std::vector<TexturedColouredVertex>& textured_vertices)
{
    if(textured_vertices.empty())
        return;

    appendGeometry(&textured_vertices[0], textured_vertices.size());
}

//---------------------------------------------------------------------------//
void GeometryBuffer::appendGeometry(const TexturedColouredVertex* vertex_array,
                                    std::size_t vertex_count)
{
    // Create a temporary array to contain our data
    static const std::size_t vertexDataSize = 9;
    std::size_t fullArraySize = vertexDataSize * vertex_count;
    float* vertexData = new float[fullArraySize];

    // Add the vertex data in their default order into an array
    const TexturedColouredVertex* vs = vertex_array;
    for (std::size_t i = 0; i < vertex_count; ++i, ++vs)
    {
        // Add all the elements in the default order for textured and coloured
        // geometry into the vector
        std::size_t currentIndex = i * vertexDataSize;

        vertexData[currentIndex + 0] = vs->d_position.x;
        vertexData[currentIndex + 1] = vs->d_position.y;
        vertexData[currentIndex + 2] = vs->d_position.z;
        vertexData[currentIndex + 3] = vs->d_colour.x;
        vertexData[currentIndex + 4] = vs->d_colour.y;
        vertexData[currentIndex + 5] = vs->d_colour.z;
        vertexData[currentIndex + 6] = vs->d_colour.w;
        vertexData[currentIndex + 7] = vs->d_texCoords.x;
        vertexData[currentIndex + 8] = vs->d_texCoords.y;
    }

    // Append the prepared geometry data
    appendGeometry(vertexData, fullArraySize);

    delete[] vertexData;
}

//---------------------------------------------------------------------------//
void GeometryBuffer::appendGeometry(const float* vertex_data,
                                    std::size_t array_size)
{
    d_vertexData.reserve( d_vertexData.size() + array_size);
    std::copy(vertex_data, vertex_data + array_size, std::back_inserter(d_vertexData));

    // Update size of geometry buffer
    d_vertexCount = d_vertexData.size() / getVertexAttributeElementCount();
}

//---------------------------------------------------------------------------//
void GeometryBuffer::appendVertex(const TexturedColouredVertex& vertex)
{
    // Add the vertex data in their default order into an array
    float vertexData[9];

    // Copy the vertex attributes into the array
    vertexData[0] = vertex.d_position.x;
    vertexData[1] = vertex.d_position.y;
    vertexData[2] = vertex.d_position.z;
    vertexData[3] = vertex.d_colour.x;
    vertexData[4] = vertex.d_colour.y;
    vertexData[5] = vertex.d_colour.z;
    vertexData[6] = vertex.d_colour.w;
    vertexData[7] = vertex.d_texCoords.x;
    vertexData[8] = vertex.d_texCoords.y;

    appendGeometry(vertexData, 9);
}

//---------------------------------------------------------------------------//
void GeometryBuffer::appendVertex(const ColouredVertex& vertex)
{
    // Add the vertex data in their default order into an array
    float vertexData[7];

    // Copy the vertex attributes into the array
    vertexData[0] = vertex.d_position.x;
    vertexData[1] = vertex.d_position.y;
    vertexData[2] = vertex.d_position.z;
    vertexData[3] = vertex.d_colour.x;
    vertexData[4] = vertex.d_colour.y;
    vertexData[5] = vertex.d_colour.z;
    vertexData[6] = vertex.d_colour.w;

    appendGeometry(vertexData, 7);
}

//---------------------------------------------------------------------------//
int GeometryBuffer::getVertexAttributeElementCount() const
{
    int count = 0;

    const unsigned int attribute_count = d_vertexAttributes.size();
    for (unsigned int i = 0; i < attribute_count; ++i)
    {
        switch(d_vertexAttributes.at(i))
        {
            case VAT_POSITION0:
                count += 3;
                break;
            case VAT_COLOUR0:
                count += 4;
                break;
            case VAT_TEXCOORD0:
                count += 2;
                break;
            default:
                break;
        }
    }

    return count;
}

//---------------------------------------------------------------------------//
void GeometryBuffer::resetVertexAttributes()
{
    d_vertexAttributes.clear();
}

//---------------------------------------------------------------------------//
void GeometryBuffer::addVertexAttribute(VertexAttributeType attribute)
{
    d_vertexAttributes.push_back(attribute);
}

//---------------------------------------------------------------------------//
RefCounted<RenderMaterial> GeometryBuffer::getRenderMaterial() const
{
    return d_renderMaterial;
}

//---------------------------------------------------------------------------//
void GeometryBuffer::setRenderMaterial(RefCounted<RenderMaterial> render_material)
{
    d_renderMaterial = render_material;
}

//---------------------------------------------------------------------------//
void GeometryBuffer::setStencilRenderingActive(PolygonFillRule fill_rule)
{
    d_polygonFillRule = fill_rule;
}

//---------------------------------------------------------------------------//
void GeometryBuffer::setStencilPostRenderingVertexCount(unsigned int vertex_count)
{
    d_postStencilVertexCount = vertex_count;
}

//----------------------------------------------------------------------------//
void GeometryBuffer::setRenderEffect(RenderEffect* effect)
{
    d_effect = effect;
}

//----------------------------------------------------------------------------//
RenderEffect* GeometryBuffer::getRenderEffect()
{
    return d_effect;
}

//----------------------------------------------------------------------------//
void GeometryBuffer::setTranslation(const glm::vec3& translation)
{
    if (d_translation != translation)
    {
        d_translation = translation;
        d_matrixValid = false;
    }
}

//----------------------------------------------------------------------------//
void GeometryBuffer::setRotation(const glm::quat& rotationQuat)
{
    if (d_rotation != rotationQuat)
    {
        d_rotation = rotationQuat;
        d_matrixValid = false;
    }
}

//----------------------------------------------------------------------------//
void GeometryBuffer::setScale(const glm::vec3& scale)
{
    if (d_scale != scale)
    {
        d_scale = scale;
        d_matrixValid = false;
    }
}

//----------------------------------------------------------------------------//
void GeometryBuffer::setScale(const glm::vec2& scale)
{
    setScale(glm::vec3(scale, 0));
}

//----------------------------------------------------------------------------//
void GeometryBuffer::setPivot(const glm::vec3& p)
{
    if (d_pivot != p)
    {
        d_pivot = p;
        d_matrixValid = false;
    }
}

//----------------------------------------------------------------------------//
void GeometryBuffer::setCustomTransform(const glm::mat4x4& transformation)
{
    if(d_customTransform != transformation)
    {
        d_customTransform = transformation;
        d_matrixValid = false;
    }
}

void GeometryBuffer::setClippingRegion(const Rectf& region)
{
    d_clippingRegion = region;

    d_preparedClippingRegion.top(std::max(0.0f, region.top()));
    d_preparedClippingRegion.bottom(std::max(0.0f, region.bottom()));
    d_preparedClippingRegion.left(std::max(0.0f, region.left()));
    d_preparedClippingRegion.right(std::max(0.0f, region.right()));
}

const Rectf& GeometryBuffer::getClippingRegion()
{
    return d_clippingRegion;
}

const Rectf& GeometryBuffer::getPreparedClippingRegion()
{
    return d_preparedClippingRegion;
}

//----------------------------------------------------------------------------//
void GeometryBuffer::setClippingActive(const bool active)
{
    d_clippingActive = active;
}

//----------------------------------------------------------------------------//
bool GeometryBuffer::isClippingActive() const
{
    return d_clippingActive;
}

//----------------------------------------------------------------------------//
std::size_t GeometryBuffer::getVertexCount() const
{
    return d_vertexCount;
}

//----------------------------------------------------------------------------//
void GeometryBuffer::reset()
{
    d_vertexData.clear();
    d_clippingActive = true;
}

//----------------------------------------------------------------------------//
void GeometryBuffer::setTexture(const std::string& parameterName, const Texture* texture)
{
    CEGUI::ShaderParameterBindings* shaderParameterBindings = (*d_renderMaterial).getShaderParamBindings();
    shaderParameterBindings->setParameter(parameterName, texture);
}

//---------------------------------------------------------------------------//
void GeometryBuffer::setAlpha(float alpha)
{
    d_alpha = alpha;
}

//---------------------------------------------------------------------------//
float GeometryBuffer::getAlpha() const
{
    return d_alpha;
}

//---------------------------------------------------------------------------//
void GeometryBuffer::invalidateMatrix()
{
    d_matrixValid = false;
}

//---------------------------------------------------------------------------//
const RenderTarget* GeometryBuffer::getLastRenderTarget() const
{
    return d_lastRenderTarget;
}

//---------------------------------------------------------------------------//
bool GeometryBuffer::isRenderTargetDataValid(const RenderTarget* activeRenderTarget) const
{
    //! The data received from the RenderTarget is only valid if:
    //! 1. The RenderTarget is the same as the one used the last time
    //! 2. The GeometryBuffer never skipped a RenderTarget activation (Checked via counter)
    return (d_lastRenderTarget == activeRenderTarget) && (d_lastRenderTargetActivationCount + 1 == activeRenderTarget->getActivationCounter());
}

//--------------------------------------------------------------------------//
void GeometryBuffer::updateRenderTargetData(const RenderTarget* activeRenderTarget) const
{
    d_lastRenderTarget = activeRenderTarget;
    d_lastRenderTargetActivationCount = activeRenderTarget->getActivationCounter();
}

//----------------------------------------------------------------------------//
glm::mat4 GeometryBuffer::getModelMatrix() const
{
    glm::mat4 modelMatrix = glm::translate(glm::mat4(1.0f), d_translation + d_pivot);

    const glm::mat4 scale_matrix(glm::scale(glm::mat4(1.0f), d_scale));
    modelMatrix *= glm::mat4_cast(d_rotation) * scale_matrix;

    const glm::mat4 translMatrix = glm::translate(glm::mat4(1.0f), -d_pivot);
    modelMatrix *=  translMatrix * d_customTransform;

    return modelMatrix;
}

}

<|endoftext|>


<commit_before>/***********************************************************************
    filename:   TreeView.cpp
    created:    Fri Jun 06 2014
    author:     Timotei Dolean <timotei21@gmail.com>

    purpose:    Implementation of the base class for all item model-based views.
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2014 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
***************************************************************************/
#include "CEGUI/views/TreeView.h"
#include "CEGUI/CoordConverter.h"

namespace CEGUI
{
//----------------------------------------------------------------------------//
TreeViewWindowRenderer::TreeViewWindowRenderer(const String& type) :
    ItemViewWindowRenderer(type)
{
}

//----------------------------------------------------------------------------//
const String TreeView::EventNamespace("TreeView");
const String TreeView::WidgetTypeName("CEGUI/TreeView");

//----------------------------------------------------------------------------//
TreeViewItemRenderingState::TreeViewItemRenderingState() :
    d_totalChildCount(0),
    d_size(0, 0),
    d_isSelected(false),
    d_childId(0),
    d_subtreeIsExpanded(false)
{
}

//----------------------------------------------------------------------------//
TreeView::TreeView(const String& type, const String& name) :
    ItemView(type, name)
{
}

//----------------------------------------------------------------------------//
TreeView::~TreeView()
{
}

//----------------------------------------------------------------------------//
const TreeViewItemRenderingState& TreeView::getRootItemState() const
{
    return d_rootItemState;
}

//----------------------------------------------------------------------------//
void TreeView::prepareForRender()
{
    ItemView::prepareForRender();
    //TODO: better way of ignoring the null item model? E.g.: warn? Throw an exception?
    if (d_itemModel == 0 || !isDirty())
        return;

    if (d_needsFullRender)
    {
        ModelIndex root_index = d_itemModel->getRootIndex();
        d_renderedMaxWidth = 0;
        d_renderedTotalHeight = 0;

        d_rootItemState = TreeViewItemRenderingState();
        d_rootItemState.d_subtreeIsExpanded = true;

        computeRenderedChildrenForItem(d_rootItemState, root_index,
            d_renderedMaxWidth, d_renderedTotalHeight);
    }
    else
    {
        updateRenderingStateForItem(d_rootItemState,
            d_renderedMaxWidth, d_renderedTotalHeight);
    }

    updateScrollbars();
    setIsDirty(false);
    d_needsFullRender = false;
}

//----------------------------------------------------------------------------//
bool TreeView::handleSelection(const Vector2f& position, bool should_select,
    bool is_cumulative, bool is_range)
{
    return handleSelection(
        indexAtWithAction(position, &TreeView::handleSelectionAction),
        should_select, is_cumulative, is_range);
}

//----------------------------------------------------------------------------//
bool TreeView::handleSelection(const ModelIndex& index, bool should_select,
    bool is_cumulative, bool is_range)
{
    return ItemView::handleSelection(index, should_select, is_cumulative, is_range);
}

//----------------------------------------------------------------------------//
TreeViewItemRenderingState TreeView::computeRenderingStateForIndex(
    const ModelIndex& parent_index, size_t child_id, float& rendered_max_width,
    float& rendered_total_height)
{
    ModelIndex& index = d_itemModel->makeIndex(child_id, parent_index);
    TreeViewItemRenderingState state;
    fillRenderingState(state, index, rendered_max_width, rendered_total_height);

    computeRenderedChildrenForItem(state, index, rendered_max_width,
        rendered_total_height);

    state.d_parentIndex = parent_index;
    state.d_childId = child_id;

    return state;
}

//----------------------------------------------------------------------------//
void TreeView::computeRenderedChildrenForItem(TreeViewItemRenderingState &item,
    const ModelIndex& index, float& rendered_max_width, float& rendered_total_height)
{
    size_t child_count = d_itemModel->getChildCount(index);
    item.d_totalChildCount = child_count;

    if (!item.d_subtreeIsExpanded)
        return;

    for (size_t child = 0; child < child_count; ++child)
    {
        item.d_renderedChildren.push_back(
            computeRenderingStateForIndex(index, child, rendered_max_width,
            rendered_total_height));
    }
}

//----------------------------------------------------------------------------//
void TreeView::updateRenderingStateForItem(TreeViewItemRenderingState& item,
    float& rendered_max_width, float& rendered_total_height)
{
    // subtract the previous height
    rendered_total_height -= item.d_size.d_height;

    fillRenderingState(item,
        d_itemModel->makeIndex(item.d_childId, item.d_parentIndex),
        rendered_max_width, rendered_total_height);

    for (ItemStateVector::iterator itor = item.d_renderedChildren.begin();
        itor != item.d_renderedChildren.end(); ++itor)
    {
        updateRenderingStateForItem(*itor, rendered_max_width, rendered_total_height);
    }
}

//----------------------------------------------------------------------------//
void TreeView::fillRenderingState(TreeViewItemRenderingState& item,
    const ModelIndex& index, float& rendered_max_width, float& rendered_total_height)
{
    String text = d_itemModel->getData(index);
    RenderedString rendered_string = getRenderedStringParser().parse(
        text, getFont(), &d_textColourRect);
    item.d_string = rendered_string;
    item.d_text = text;

    item.d_size = Sizef(
        rendered_string.getHorizontalExtent(this),
        rendered_string.getVerticalExtent(this));

    rendered_max_width = ceguimax(rendered_max_width, item.d_size.d_width);
    rendered_total_height += item.d_size.d_height;

    item.d_isSelected = isIndexSelected(index);
}

//----------------------------------------------------------------------------//
ModelIndex TreeView::indexAt(const Vector2f& position)
{
    return indexAtWithAction(position, &TreeView::noopAction);
}

//----------------------------------------------------------------------------//
CEGUI::ModelIndex TreeView::indexAtWithAction(const Vector2f& position,
    TreeViewItemAction action)
{
    if (d_itemModel == 0)
        return ModelIndex();

    //TODO: add prepareForLayout() as a cheaper operation alternative?
    prepareForRender();

    Vector2f window_position = CoordConverter::screenToWindow(*this, position);
    Rectf render_area(getViewRenderer()->getViewRenderArea());
    if (!render_area.isPointInRect(window_position))
        return ModelIndex();

    float cur_height = render_area.d_min.d_y - getVertScrollbar()->getScrollPosition();
    bool handled = false;
    // root is actually depth = -1, since its a dummy tree item.
    return indexAtRecursive(d_rootItemState, cur_height, window_position,
        handled, action, -1);
}

//----------------------------------------------------------------------------//
ModelIndex TreeView::indexAtRecursive(TreeViewItemRenderingState& item,
    float& cur_height, const Vector2f& window_position, bool& handled,
    TreeViewItemAction action, int depth)
{
    float next_height = cur_height + item.d_size.d_height;

    if (window_position.d_y >= cur_height &&
        window_position.d_y <= next_height)
    {
        handled = true;

        float expander_width = getViewRenderer()->getSubtreeExpanderSize().d_width;
        float base_x = getViewRenderer()->getSubtreeExpanderXIndent(depth);
        base_x -= getHorzScrollbar()->getScrollPosition();
        if (window_position.d_x >= base_x &&
            window_position.d_x <= base_x + expander_width)
        {
            (this->*action)(item, true);
            return ModelIndex();
        }

        (this->*action)(item, false);
        return ModelIndex(d_itemModel->makeIndex(item.d_childId, item.d_parentIndex));
    }

    cur_height = next_height;

    for (size_t i = 0; i < item.d_renderedChildren.size(); ++i)
    {
        ModelIndex index = indexAtRecursive(item.d_renderedChildren.at(i),
            cur_height, window_position, handled, action, depth + 1);
        if (handled)
            return index;
    }

    return ModelIndex();
}

//----------------------------------------------------------------------------//
TreeViewWindowRenderer* TreeView::getViewRenderer()
{
    return static_cast<TreeViewWindowRenderer*>(ItemView::getViewRenderer());
}

//----------------------------------------------------------------------------//
void TreeView::toggleSubtree(TreeViewItemRenderingState& item)
{
    if (d_itemModel == 0)
        return;

    item.d_subtreeIsExpanded = !item.d_subtreeIsExpanded;

    if (item.d_subtreeIsExpanded)
    {
        computeRenderedChildrenForItem(item,
            d_itemModel->makeIndex(item.d_childId, item.d_parentIndex),
            d_renderedMaxWidth, d_renderedTotalHeight);
    }
    else
    {
        clearItemRenderedChildren(item, d_renderedTotalHeight);
    }

    updateScrollbars();
    // we need just a simple invalidation. No need to redo the render state
    // as we modified it ourself directly.
    invalidate(false);
}

//----------------------------------------------------------------------------//
void TreeView::clearItemRenderedChildren(TreeViewItemRenderingState& item,
    float& renderedTotalHeight)
{
    std::vector<TreeViewItemRenderingState>::iterator itor =
        item.d_renderedChildren.begin();

    while (itor != item.d_renderedChildren.end())
    {
        clearItemRenderedChildren(*itor, renderedTotalHeight);

        d_renderedTotalHeight -= item.d_size.d_height;
        itor = item.d_renderedChildren.erase(itor);
    }
}

//----------------------------------------------------------------------------//
void TreeView::handleSelectionAction(TreeViewItemRenderingState& item, bool toggles_expander)
{
    if (!toggles_expander)
        return;

    toggleSubtree(item);
}

//----------------------------------------------------------------------------//
bool TreeView::onChildrenRemoved(const EventArgs& args)
{
    ItemView::onChildrenRemoved(args);

    const ModelEventArgs& margs = static_cast<const ModelEventArgs&>(args);
    TreeViewItemRenderingState* item = getTreeViewItemForIndex(margs.d_parentIndex);

    if (item == 0)
        return true;

    // update existing child ids
    for (ItemStateVector::iterator
        itor = item->d_renderedChildren.begin() + margs.d_startId;
        itor != item->d_renderedChildren.end(); ++itor)
    {
        (*itor).d_childId -= margs.d_count;
    }

    item->d_renderedChildren.erase(
        item->d_renderedChildren.begin() + margs.d_startId,
        item->d_renderedChildren.begin() + margs.d_startId + margs.d_count);
    item->d_totalChildCount -= margs.d_count;

    invalidateView(false);
    return true;
}

//----------------------------------------------------------------------------//
bool TreeView::onChildrenAdded(const EventArgs& args)
{
    ItemView::onChildrenAdded(args);

    const ModelEventArgs& margs = static_cast<const ModelEventArgs&>(args);
    TreeViewItemRenderingState* item = getTreeViewItemForIndex(margs.d_parentIndex);

    if (item == 0)
        return true;

    std::vector<TreeViewItemRenderingState> states;
    for (size_t id = margs.d_startId; id < margs.d_startId + margs.d_count; ++id)
    {
        states.push_back(computeRenderingStateForIndex(margs.d_parentIndex, id,
            d_renderedMaxWidth, d_renderedTotalHeight));
    }

    // update existing child ids
    for (ItemStateVector::iterator
        itor = item->d_renderedChildren.begin() + margs.d_startId;
        itor != item->d_renderedChildren.end(); ++itor)
    {
        (*itor).d_childId += margs.d_count;
    }

    item->d_renderedChildren.insert(
        item->d_renderedChildren.begin() + margs.d_startId,
        states.begin(), states.end());
    item->d_totalChildCount += margs.d_count;

    invalidateView(false);
    return true;
}

//----------------------------------------------------------------------------//
TreeViewItemRenderingState* TreeView::getTreeViewItemForIndex(const ModelIndex& index)
{
    std::vector<int> ids_stack;
    ModelIndex root_index = d_itemModel->getRootIndex();
    ModelIndex temp_index = index;

    // we create a stack of child ids which will allow us to drill back
    // in the right hierarchy.
    do
    {
        int id = d_itemModel->getChildId(temp_index);
        if (id == -1)
            break;

        ids_stack.push_back(id);
        temp_index = d_itemModel->getParentIndex(temp_index);
    } while (d_itemModel->isValidIndex(temp_index) &&
        !d_itemModel->areIndicesEqual(temp_index, root_index));

    TreeViewItemRenderingState* item = &d_rootItemState;
    while(!ids_stack.empty())
    {
        int child_id = ids_stack.back();
        ids_stack.pop_back();

        if (static_cast<size_t>(child_id) >= item->d_renderedChildren.size())
            return 0;

        item = &item->d_renderedChildren.at(child_id);
    }

    return item;
}
}
<commit_msg>Don't update the rendered children state if subtree is not expanded<commit_after>/***********************************************************************
    filename:   TreeView.cpp
    created:    Fri Jun 06 2014
    author:     Timotei Dolean <timotei21@gmail.com>

    purpose:    Implementation of the base class for all item model-based views.
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2014 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
***************************************************************************/
#include "CEGUI/views/TreeView.h"
#include "CEGUI/CoordConverter.h"

namespace CEGUI
{
//----------------------------------------------------------------------------//
TreeViewWindowRenderer::TreeViewWindowRenderer(const String& type) :
    ItemViewWindowRenderer(type)
{
}

//----------------------------------------------------------------------------//
const String TreeView::EventNamespace("TreeView");
const String TreeView::WidgetTypeName("CEGUI/TreeView");

//----------------------------------------------------------------------------//
TreeViewItemRenderingState::TreeViewItemRenderingState() :
    d_totalChildCount(0),
    d_size(0, 0),
    d_isSelected(false),
    d_childId(0),
    d_subtreeIsExpanded(false)
{
}

//----------------------------------------------------------------------------//
TreeView::TreeView(const String& type, const String& name) :
    ItemView(type, name)
{
}

//----------------------------------------------------------------------------//
TreeView::~TreeView()
{
}

//----------------------------------------------------------------------------//
const TreeViewItemRenderingState& TreeView::getRootItemState() const
{
    return d_rootItemState;
}

//----------------------------------------------------------------------------//
void TreeView::prepareForRender()
{
    ItemView::prepareForRender();
    //TODO: better way of ignoring the null item model? E.g.: warn? Throw an exception?
    if (d_itemModel == 0 || !isDirty())
        return;

    if (d_needsFullRender)
    {
        ModelIndex root_index = d_itemModel->getRootIndex();
        d_renderedMaxWidth = 0;
        d_renderedTotalHeight = 0;

        d_rootItemState = TreeViewItemRenderingState();
        d_rootItemState.d_subtreeIsExpanded = true;

        computeRenderedChildrenForItem(d_rootItemState, root_index,
            d_renderedMaxWidth, d_renderedTotalHeight);
    }
    else
    {
        updateRenderingStateForItem(d_rootItemState,
            d_renderedMaxWidth, d_renderedTotalHeight);
    }

    updateScrollbars();
    setIsDirty(false);
    d_needsFullRender = false;
}

//----------------------------------------------------------------------------//
bool TreeView::handleSelection(const Vector2f& position, bool should_select,
    bool is_cumulative, bool is_range)
{
    return handleSelection(
        indexAtWithAction(position, &TreeView::handleSelectionAction),
        should_select, is_cumulative, is_range);
}

//----------------------------------------------------------------------------//
bool TreeView::handleSelection(const ModelIndex& index, bool should_select,
    bool is_cumulative, bool is_range)
{
    return ItemView::handleSelection(index, should_select, is_cumulative, is_range);
}

//----------------------------------------------------------------------------//
TreeViewItemRenderingState TreeView::computeRenderingStateForIndex(
    const ModelIndex& parent_index, size_t child_id, float& rendered_max_width,
    float& rendered_total_height)
{
    ModelIndex& index = d_itemModel->makeIndex(child_id, parent_index);
    TreeViewItemRenderingState state;
    fillRenderingState(state, index, rendered_max_width, rendered_total_height);

    computeRenderedChildrenForItem(state, index, rendered_max_width,
        rendered_total_height);

    state.d_parentIndex = parent_index;
    state.d_childId = child_id;

    return state;
}

//----------------------------------------------------------------------------//
void TreeView::computeRenderedChildrenForItem(TreeViewItemRenderingState &item,
    const ModelIndex& index, float& rendered_max_width, float& rendered_total_height)
{
    size_t child_count = d_itemModel->getChildCount(index);
    item.d_totalChildCount = child_count;

    if (!item.d_subtreeIsExpanded)
        return;

    for (size_t child = 0; child < child_count; ++child)
    {
        item.d_renderedChildren.push_back(
            computeRenderingStateForIndex(index, child, rendered_max_width,
            rendered_total_height));
    }
}

//----------------------------------------------------------------------------//
void TreeView::updateRenderingStateForItem(TreeViewItemRenderingState& item,
    float& rendered_max_width, float& rendered_total_height)
{
    // subtract the previous height
    rendered_total_height -= item.d_size.d_height;

    fillRenderingState(item,
        d_itemModel->makeIndex(item.d_childId, item.d_parentIndex),
        rendered_max_width, rendered_total_height);

    for (ItemStateVector::iterator itor = item.d_renderedChildren.begin();
        itor != item.d_renderedChildren.end(); ++itor)
    {
        updateRenderingStateForItem(*itor, rendered_max_width, rendered_total_height);
    }
}

//----------------------------------------------------------------------------//
void TreeView::fillRenderingState(TreeViewItemRenderingState& item,
    const ModelIndex& index, float& rendered_max_width, float& rendered_total_height)
{
    String text = d_itemModel->getData(index);
    RenderedString rendered_string = getRenderedStringParser().parse(
        text, getFont(), &d_textColourRect);
    item.d_string = rendered_string;
    item.d_text = text;

    item.d_size = Sizef(
        rendered_string.getHorizontalExtent(this),
        rendered_string.getVerticalExtent(this));

    rendered_max_width = ceguimax(rendered_max_width, item.d_size.d_width);
    rendered_total_height += item.d_size.d_height;

    item.d_isSelected = isIndexSelected(index);
}

//----------------------------------------------------------------------------//
ModelIndex TreeView::indexAt(const Vector2f& position)
{
    return indexAtWithAction(position, &TreeView::noopAction);
}

//----------------------------------------------------------------------------//
CEGUI::ModelIndex TreeView::indexAtWithAction(const Vector2f& position,
    TreeViewItemAction action)
{
    if (d_itemModel == 0)
        return ModelIndex();

    //TODO: add prepareForLayout() as a cheaper operation alternative?
    prepareForRender();

    Vector2f window_position = CoordConverter::screenToWindow(*this, position);
    Rectf render_area(getViewRenderer()->getViewRenderArea());
    if (!render_area.isPointInRect(window_position))
        return ModelIndex();

    float cur_height = render_area.d_min.d_y - getVertScrollbar()->getScrollPosition();
    bool handled = false;
    // root is actually depth = -1, since its a dummy tree item.
    return indexAtRecursive(d_rootItemState, cur_height, window_position,
        handled, action, -1);
}

//----------------------------------------------------------------------------//
ModelIndex TreeView::indexAtRecursive(TreeViewItemRenderingState& item,
    float& cur_height, const Vector2f& window_position, bool& handled,
    TreeViewItemAction action, int depth)
{
    float next_height = cur_height + item.d_size.d_height;

    if (window_position.d_y >= cur_height &&
        window_position.d_y <= next_height)
    {
        handled = true;

        float expander_width = getViewRenderer()->getSubtreeExpanderSize().d_width;
        float base_x = getViewRenderer()->getSubtreeExpanderXIndent(depth);
        base_x -= getHorzScrollbar()->getScrollPosition();
        if (window_position.d_x >= base_x &&
            window_position.d_x <= base_x + expander_width)
        {
            (this->*action)(item, true);
            return ModelIndex();
        }

        (this->*action)(item, false);
        return ModelIndex(d_itemModel->makeIndex(item.d_childId, item.d_parentIndex));
    }

    cur_height = next_height;

    for (size_t i = 0; i < item.d_renderedChildren.size(); ++i)
    {
        ModelIndex index = indexAtRecursive(item.d_renderedChildren.at(i),
            cur_height, window_position, handled, action, depth + 1);
        if (handled)
            return index;
    }

    return ModelIndex();
}

//----------------------------------------------------------------------------//
TreeViewWindowRenderer* TreeView::getViewRenderer()
{
    return static_cast<TreeViewWindowRenderer*>(ItemView::getViewRenderer());
}

//----------------------------------------------------------------------------//
void TreeView::toggleSubtree(TreeViewItemRenderingState& item)
{
    if (d_itemModel == 0)
        return;

    item.d_subtreeIsExpanded = !item.d_subtreeIsExpanded;

    if (item.d_subtreeIsExpanded)
    {
        computeRenderedChildrenForItem(item,
            d_itemModel->makeIndex(item.d_childId, item.d_parentIndex),
            d_renderedMaxWidth, d_renderedTotalHeight);
    }
    else
    {
        clearItemRenderedChildren(item, d_renderedTotalHeight);
    }

    updateScrollbars();
    // we need just a simple invalidation. No need to redo the render state
    // as we modified it ourself directly.
    invalidate(false);
}

//----------------------------------------------------------------------------//
void TreeView::clearItemRenderedChildren(TreeViewItemRenderingState& item,
    float& renderedTotalHeight)
{
    std::vector<TreeViewItemRenderingState>::iterator itor =
        item.d_renderedChildren.begin();

    while (itor != item.d_renderedChildren.end())
    {
        clearItemRenderedChildren(*itor, renderedTotalHeight);

        d_renderedTotalHeight -= item.d_size.d_height;
        itor = item.d_renderedChildren.erase(itor);
    }
}

//----------------------------------------------------------------------------//
void TreeView::handleSelectionAction(TreeViewItemRenderingState& item, bool toggles_expander)
{
    if (!toggles_expander)
        return;

    toggleSubtree(item);
}

//----------------------------------------------------------------------------//
bool TreeView::onChildrenRemoved(const EventArgs& args)
{
    ItemView::onChildrenRemoved(args);

    const ModelEventArgs& margs = static_cast<const ModelEventArgs&>(args);
    TreeViewItemRenderingState* item = getTreeViewItemForIndex(margs.d_parentIndex);

    if (item == 0)
        return true;

    item->d_totalChildCount -= margs.d_count;

    if (!item->d_subtreeIsExpanded)
        return true;

    // update existing child ids
    for (ItemStateVector::iterator
        itor = item->d_renderedChildren.begin() + margs.d_startId;
        itor != item->d_renderedChildren.end(); ++itor)
    {
        (*itor).d_childId -= margs.d_count;
    }

    item->d_renderedChildren.erase(
        item->d_renderedChildren.begin() + margs.d_startId,
        item->d_renderedChildren.begin() + margs.d_startId + margs.d_count);

    invalidateView(false);
    return true;
}

//----------------------------------------------------------------------------//
bool TreeView::onChildrenAdded(const EventArgs& args)
{
    ItemView::onChildrenAdded(args);

    const ModelEventArgs& margs = static_cast<const ModelEventArgs&>(args);
    TreeViewItemRenderingState* item = getTreeViewItemForIndex(margs.d_parentIndex);

    if (item == 0)
        return true;

    item->d_totalChildCount += margs.d_count;

    if (!item->d_subtreeIsExpanded)
        return true;

    std::vector<TreeViewItemRenderingState> states;
    for (size_t id = margs.d_startId; id < margs.d_startId + margs.d_count; ++id)
    {
        states.push_back(computeRenderingStateForIndex(margs.d_parentIndex, id,
            d_renderedMaxWidth, d_renderedTotalHeight));
    }

    // update existing child ids
    for (ItemStateVector::iterator
        itor = item->d_renderedChildren.begin() + margs.d_startId;
        itor != item->d_renderedChildren.end(); ++itor)
    {
        (*itor).d_childId += margs.d_count;
    }

    item->d_renderedChildren.insert(
        item->d_renderedChildren.begin() + margs.d_startId,
        states.begin(), states.end());

    invalidateView(false);
    return true;
}

//----------------------------------------------------------------------------//
TreeViewItemRenderingState* TreeView::getTreeViewItemForIndex(const ModelIndex& index)
{
    std::vector<int> ids_stack;
    ModelIndex root_index = d_itemModel->getRootIndex();
    ModelIndex temp_index = index;

    // we create a stack of child ids which will allow us to drill back
    // in the right hierarchy.
    do
    {
        int id = d_itemModel->getChildId(temp_index);
        if (id == -1)
            break;

        ids_stack.push_back(id);
        temp_index = d_itemModel->getParentIndex(temp_index);
    } while (d_itemModel->isValidIndex(temp_index) &&
        !d_itemModel->areIndicesEqual(temp_index, root_index));

    TreeViewItemRenderingState* item = &d_rootItemState;
    while(!ids_stack.empty())
    {
        int child_id = ids_stack.back();
        ids_stack.pop_back();

        if (static_cast<size_t>(child_id) >= item->d_renderedChildren.size())
            return 0;

        item = &item->d_renderedChildren.at(child_id);
    }

    return item;
}
}
<|endoftext|>


<commit_before>#include <iostream>

/////////////////////////////////////////
///
/// if_
///         check condition and returns
///         different values accordingly.
///
/////////////////////////////////////////
template<bool condition,typename T, T if_true, T if_false>
struct if_;

template<typename T, T if_true, T if_false>
struct if_<true, T, if_true, if_false>{
    static const T result = if_true;
};

template<typename T, T if_true, T if_false>
struct if_<false, T, if_true, if_false>{
    static const T result = if_false;
};
/////////////////////////////////////////
///
/// bool_array_
///             creates completime array
///             with runtime accessable
///             elements.
///
/////////////////////////////////////////
template<bool... values>
struct bool_array{
    static const bool value[sizeof...(values)];
};
template<bool... values>
bool const bool_array<values...>::value[] = {values ...};

/////////////////////////////////////////
///
/// get_index_
///             access array elements
///             compile-time.
///
/////////////////////////////////////////
template<size_t index, size_t start, typename...>
struct get_index;

template<size_t index, template<bool...> class array_, bool value, bool... values>
struct get_index<index, index, array_<value, values...>>{
    static const bool result = value;
};

template<size_t index, size_t start, template<bool...> class array_, bool value, bool... values>
struct get_index<index, start, array_<value, values...>> : get_index<index, start + 1, array_<values...>>{};

/////////////////////////////////////////////////////////////////
///
/// replace_
///             Replace elements with value after each interval.
///             First replacement starts after interval * 2.
///
///             Used for setting all values that are divideable
///             with a prime number as a non prime number
///
/////////////////////////////////////////////////////////////////
template<bool new_value, size_t interval, size_t interval_left, typename...>
struct replace_rec;

template<bool new_value, size_t interval, typename...>
struct replace_;

// End, when array is empty
template<bool new_value, size_t interval, size_t interval_left, template<bool...> class array_, bool... new_values>
struct replace_rec<new_value, interval, interval_left, array_<new_values...>, array_<>> : bool_array<new_values...>{
    typedef bool_array<new_values...> type;
};

// Recursive call to replace value.
template<bool new_value, size_t interval, size_t interval_left, template<bool...> class array_, bool old_value, bool... new_values, bool... old_values>
struct  replace_rec<new_value, interval, interval_left, array_<new_values...>, array_<old_value, old_values...>> :
        replace_rec<
            new_value,
            interval,
            if_<interval_left == 1, size_t,
                interval,
            //else
                interval_left - 1>::result,
            array_<new_values..., if_<interval_left == 1, size_t, new_value, old_value>::result> , array_<old_values...>>{};

//wrapper for more easy start call
template<bool new_value, size_t interval, template<bool...> class array_, bool old_value, bool... old_values>
struct  replace_<new_value, interval, array_<old_value, old_values...>> :
        replace_rec<new_value, interval, interval * 2, array_<new_value> , array_<old_values...>>{};

/////////////////////////////////////////////////////////////////
///
/// bool_generator
///             Create a compile-time boolean array filled with
///             values.
///
/////////////////////////////////////////////////////////////////
template<int N, bool value, bool... values> struct bool_generator;
// End when N reaches 0
template<bool value, bool... values> struct bool_generator<0, value, values...> : bool_array<values...> {
    typedef bool_array<values...> type;
};
// Recursive inheritance to generate all values
template<int N, bool value, bool... values> struct bool_generator : bool_generator<N - 1, value , value , values...> {};

///////////////////////////////////////////////////////////////////
///
/// calc_prime_array
///             generates a compiletime bool array with each index
///             set to whenever that number is a prime or not.
///
///////////////////////////////////////////////////////////////////
template<size_t N, size_t current, typename...> struct calc_prime_array;

// Recursive inheritance to generate prime array
template<size_t N, size_t current, template<bool...> class array_, bool... values>
struct calc_prime_array<N, current, array_<values...>> : calc_prime_array<N, current + 1, typename replace_<false,
    if_<get_index<current, 0, bool_array<values...>>::result, size_t, current, N>::result, array_<values...>>::type > {};

//When current == N, we have reached the end
template<size_t N, template<bool...> class array_, bool... values>
struct calc_prime_array<N, N, array_<values...>> : bool_array<values...>{};

///////////////////////////////////////////////////////////////////
///
/// is_prime
///             generates a compiletime bool array with the size of
///             max, and evalute witch are primes or not
///             (compile-time).
///
/// USAGE:      is_prime(i) //i should be less than 200
///             is_prime<max>(i) // i should be less than max
///
///////////////////////////////////////////////////////////////////
template<size_t max = 200>
bool is_prime(size_t number){
    return calc_prime_array<max, 2, typename bool_generator<max, true>::type>::value[number];
}

int main(){
    const int max = 50;
    for (int i = 0; i < max; ++i)
    {
        if(is_prime(i)) std::cout << i << std::endl;
    }
    std::cout << std::endl;
}<commit_msg>cleaned code and turned most static const varables into enums for pure calculation time computations.<commit_after>#include <iostream>
#include <cassert>
#include <string>

/////////////////////////////////////////
///
/// if_
///         check condition and returns
///         different values accordingly.
///
/////////////////////////////////////////
template<bool condition, unsigned if_true, unsigned if_false>
struct if_;

template<unsigned if_true, unsigned if_false>
struct if_<true, if_true, if_false>{
    enum{ result = if_true };
};

template<unsigned if_true, unsigned if_false>
struct if_<false, if_true, if_false>{
    enum{ result = if_false };
};
/////////////////////////////////////////
///
/// bool_array_
///             creates completime array
///             with runtime accessable
///             elements.
///
/////////////////////////////////////////
template<bool... values>
struct bool_array{
    static const bool value[sizeof...(values)];
};
template<bool... values>
bool const bool_array<values...>::value[] = {values ...};

/////////////////////////////////////////
///
/// get_index_
///             access array elements
///             compile-time.
///
/////////////////////////////////////////
template<size_t index, size_t start, typename...>
struct get_index;

template<size_t index, template<bool...> class array_, bool value, bool... values>
struct get_index<index, index, array_<value, values...>>{
    enum{ result = value };
};

template<size_t index, size_t start, template<bool...> class array_, bool value, bool... values>
struct get_index<index, start, array_<value, values...>> : get_index<index, start + 1, array_<values...>>{};

/////////////////////////////////////////////////////////////////
///
/// replace_
///             Replace elements with value after each interval.
///             First replacement starts after interval * 2.
///
///             Used for setting all values that are divideable
///             with a prime number as a non prime number
///
/////////////////////////////////////////////////////////////////
template<bool new_value, size_t interval, size_t interval_left, typename...>
struct replace_rec;

template<bool new_value, size_t interval, typename...>
struct replace_;

// End, when array is empty
template<bool new_value, size_t interval, size_t interval_left, template<bool...> class array_, bool... new_values>
struct replace_rec<new_value, interval, interval_left, array_<new_values...>, array_<>> : bool_array<new_values...>{
    typedef bool_array<new_values...> type;
};

// Recursive call to replace value.
template<bool new_value, size_t interval, size_t interval_left, template<bool...> class array_, bool old_value, bool... new_values, bool... old_values>
struct  replace_rec<new_value, interval, interval_left, array_<new_values...>, array_<old_value, old_values...>> :
        replace_rec<new_value, interval,
            if_<interval_left == 1,
                interval,
            //else
                interval_left - 1>::result,
            array_<new_values..., if_<interval_left == 1, new_value, old_value>::result> , array_<old_values...>>{};

//wrapper for more easy start call
template<bool new_value, size_t interval, template<bool...> class array_, bool old_value, bool... old_values>
struct  replace_<new_value, interval, array_<old_value, old_values...>> :
        replace_rec<new_value, interval, interval * 2, array_<new_value> , array_<old_values...>>{};

/////////////////////////////////////////////////////////////////
///
/// bool_generator
///             Create a compile-time boolean array filled with
///             values.
///
/////////////////////////////////////////////////////////////////
template<int N, bool value, bool... values> struct bool_generator;
// End when N reaches 0
template<bool value, bool... values> struct bool_generator<0, value, values...> : bool_array<values...> {
    typedef bool_array<values...> type;
};
// Recursive inheritance to generate all values
template<int N, bool value, bool... values> struct bool_generator : bool_generator<N - 1, value , values..., value> {};

///////////////////////////////////////////////////////////////////
///
/// calc_prime_array
///             generates a compiletime bool array with each index
///             set to whenever that number is a prime or not.
///
///////////////////////////////////////////////////////////////////
template<size_t N, size_t current, typename...> struct calc_prime_array;

// Recursive inheritance to generate prime array
template<size_t N, size_t current, template<bool...> class array_, bool... values>
struct calc_prime_array<N, current, array_<values...>> : calc_prime_array<N, current + 1, typename replace_<false,
    if_<get_index<current, 0, bool_array<values...>>::result, current, N>::result, array_<values...>>::type > {};

//When current == N, we have reached the end
template<size_t N, template<bool...> class array_, bool... values>
struct calc_prime_array<N, N, array_<values...>> : bool_array<values...>{};

///////////////////////////////////////////////////////////////////
///
/// is_prime
///             generates a compiletime bool array with the size of
///             max, and evalute witch are primes or not
///             (compile-time).
///
/// USAGE:      is_prime(i) //i should be less than 200
///             is_prime<max>(i) // i should be less than max
///
///////////////////////////////////////////////////////////////////
template<size_t max = 200>
bool is_prime(size_t number){
    assert(number < max);
    return calc_prime_array<max, 2, typename bool_generator<max, true, false, false>::type>::value[number];
}

int main(){
    const int max = 50;
    for (int i = 0; i < max; ++i)
    {
        if(is_prime<max>(i)) std::cout << i << std::endl;
    }
    std::cout << std::endl;
    std::string input = "";
    while(input != "q") {
        std::cout << "Check if number is prime (max " << max << "): ";
        std::cin >> input;
        int value = atoi(input.c_str());
        std::cout << (input == "q"? "goodbye" : is_prime<max>(value) == false? "no" : "yes") << std::endl;
    }
}<|endoftext|>


<commit_before>/*
 * InitialServer.cpp
 *
 *  Created on: 06.06.2016
 *      Author: hartung
 */

#include "../include/InitialNetworkServer.hpp"

#include "initialization/MainFactory.hpp"
#include "util/FileHelper.hpp"

namespace Network
{
    InitialNetworkServer::InitialNetworkServer(const int & port, Initialization::ProgramPlan & plan)
            : _plan(plan),
              _offsets(4, 0)
    {
        _networkPlan.server = std::shared_ptr<NetOff::SimulationServer>(new NetOff::SimulationServer(port));
    }

    InitialNetworkServer::~InitialNetworkServer()
    {

    }

    NetworkPlan InitialNetworkServer::getNetworkPlan()
    {
        return _networkPlan;
    }

    void InitialNetworkServer::start()
    {
        NetOff::SimulationServer & server = *_networkPlan.server.get();
        if (!server.initializeConnection())
            throw std::runtime_error("Couldn't initialize network connection.");

        bool run = true;
        while (run)
        {
            NetOff::InitialClientMessageSpecifyer spec = server.getInitialClientRequest();
            switch (spec)
            {
                case NetOff::InitialClientMessageSpecifyer::ADD_SIM:
                {
                    addSim();
                    break;
                }
                case NetOff::InitialClientMessageSpecifyer::GET_FILE:
                    getFile();
                    break;
                case NetOff::InitialClientMessageSpecifyer::INIT_SIM:
                    initSim();
                    break;
                case NetOff::InitialClientMessageSpecifyer::CLIENT_INIT_ABORT:
                    server.deinitialize();
                    throw std::runtime_error("Client aborted connection in initialization.");
                    break;
                case NetOff::InitialClientMessageSpecifyer::START:
                    startSim();
                    run = false;
                    break;
            }
        }
    }

    void InitialNetworkServer::getFile()
    {
        NetOff::SimulationServer & server = *_networkPlan.server.get();
        int newId = server.getLastSimId();
        std::string filePath = Util::FileHelper::find(_tmpFmus[newId]->getWorkingDirectory(), server.getSimulationFileName(), true);
        if (filePath.empty())
        {
            if (server.getSimulationFileName().find('/') != std::string::npos)
            {
                filePath = Util::FileHelper::absoluteFilePath(server.getSimulationFileName());  // look from root
            }
            if (filePath.empty())
                throw std::runtime_error("Couldn't find requested file.");
        }
        server.confirmSimulationFile(newId, filePath);
    }

    void InitialNetworkServer::initSim()
    {
        NetOff::SimulationServer & server = *_networkPlan.server.get();
        int newId = server.getLastSimId();

        FMI::AbstractFmu * fmu = _tmpFmus[newId].get();
        if (fmu->isLoaded())
        {
            const FMI::ValueReferenceCollection & refs = fmu->getAllValueReferences();
            const FMI::ValueInfo & vi = fmu->getValueInfo();

            _networkPlan.fmuNet[newId].outputMap = getMappingFromNameList(refs, server.getSelectedOutputVariables(newId), vi, true);
            _networkPlan.fmuNet[newId].inputMap = getMappingFromNameList(refs, server.getSelectedInputVariables(newId), vi, false);
        }
        else
            throw std::runtime_error("Remote simulation failed. Fmu couldn't be initialized.");

        FMI::ValueCollection tmpVals = _networkPlan.fmuNet[newId].outputMap.pack(fmu->getValues(FMI::ReferenceContainerType::ALL));
        NetOff::ValueContainer & initialValues = server.getOutputValueContainer(newId);
        initialValues.setRealValues(tmpVals.getValues<real_type>().data());
        initialValues.setIntValues(tmpVals.getValues<int_type>().data());
        initialValues.setBoolValues(tmpVals.getValues<bool_type>().data());
        server.confirmSimulationInit(newId, initialValues);
    }

    std::shared_ptr<Initialization::FmuPlan> InitialNetworkServer::findFmuInProgramPlan(const std::string fmuPath, Network::NetworkFmuInformation & netInfo)
    {
        std::shared_ptr<Initialization::FmuPlan> res;
        size_type simId = 0, coreId = 0, solveId = 0;
        for (const auto & simPlanVec : _plan.simPlans)
            for (const auto & simPlan : simPlanVec)
            {
                for (const auto & solvPlan : simPlan.dataManager.solvers)
                {
                    if (fmuPath == Util::FileHelper::absoluteFilePath(solvPlan->fmu->path) || fmuPath == solvPlan->fmu->name || fmuPath == solvPlan->fmu->name + std::string(".fmu"))
                    {
                        res = solvPlan->fmu;
                        netInfo.simPos = simId;
                        netInfo.corePos = coreId;
                        netInfo.solverPos = solveId;
                        return res;
                    }
                    ++solveId;
                }
                ++coreId;
            }
        ++simId;

        return res;
    }

    void InitialNetworkServer::addSim()
    {
        NetOff::SimulationServer & server = *_networkPlan.server.get();
        std::vector<Network::NetworkFmuInformation> &netFmuVec = _networkPlan.fmuNet;

        Initialization::MainFactory mf;
        int newId = std::get<1>(server.getAddedSimulation());

        netFmuVec.resize(newId + 1);
        _tmpFmus.resize(newId + 1);

        std::shared_ptr<Initialization::FmuPlan> fmuPlan = findFmuInProgramPlan(std::get<0>(server.getAddedSimulation()), netFmuVec[newId]);
        if (!fmuPlan)
        {
            server.deinitialize();
            throw std::runtime_error("Couldn't find fmu with given path.");
        }

        _tmpFmus[newId] = std::shared_ptr<FMI::AbstractFmu>(mf.createFmu(*fmuPlan));
        _tmpFmus[newId]->load();
        const FMI::ValueInfo & info = _tmpFmus[newId]->getValueInfo();

        NetOff::VariableList inputVarNames(info.getInputValueNames<real_type>(), info.getInputValueNames<int_type>(), info.getInputValueNames<bool_type>()),
                outputVarNames(info.getValueNames<real_type>(), info.getValueNames<int_type>(), info.getValueNames<bool_type>());
        server.confirmSimulationAdd(newId, inputVarNames, outputVarNames);
    }

    void InitialNetworkServer::startSim()
    {
        for (const auto & fmu : _tmpFmus)
            fmu->unload();

    }

    FMI::InputMapping InitialNetworkServer::getMappingFromNameList(const FMI::ValueReferenceCollection& refs, const NetOff::VariableList& vars,
                                                                   const FMI::ValueInfo& vi, bool fromFmu)
    {
        FMI::InputMapping mapping;
        addRefsToMapping<real_type>(mapping, vars.getReals(), vi, refs, fromFmu);
        addRefsToMapping<int_type>(mapping, vars.getInts(), vi, refs, fromFmu);
        addRefsToMapping<bool_type>(mapping, vars.getBools(), vi, refs, fromFmu);
        return mapping;
    }

}
<commit_msg>Remove empty line<commit_after>/*
 * InitialServer.cpp
 *
 *  Created on: 06.06.2016
 *      Author: hartung
 */

#include "../include/InitialNetworkServer.hpp"

#include "initialization/MainFactory.hpp"
#include "util/FileHelper.hpp"

namespace Network
{
    InitialNetworkServer::InitialNetworkServer(const int & port, Initialization::ProgramPlan & plan)
            : _plan(plan),
              _offsets(4, 0)
    {
        _networkPlan.server = std::shared_ptr<NetOff::SimulationServer>(new NetOff::SimulationServer(port));
    }

    InitialNetworkServer::~InitialNetworkServer()
    {

    }

    NetworkPlan InitialNetworkServer::getNetworkPlan()
    {
        return _networkPlan;
    }

    void InitialNetworkServer::start()
    {
        NetOff::SimulationServer & server = *_networkPlan.server.get();
        if (!server.initializeConnection())
            throw std::runtime_error("Couldn't initialize network connection.");

        bool run = true;
        while (run)
        {
            NetOff::InitialClientMessageSpecifyer spec = server.getInitialClientRequest();
            switch (spec)
            {
                case NetOff::InitialClientMessageSpecifyer::ADD_SIM:
                {
                    addSim();
                    break;
                }
                case NetOff::InitialClientMessageSpecifyer::GET_FILE:
                    getFile();
                    break;
                case NetOff::InitialClientMessageSpecifyer::INIT_SIM:
                    initSim();
                    break;
                case NetOff::InitialClientMessageSpecifyer::CLIENT_INIT_ABORT:
                    server.deinitialize();
                    throw std::runtime_error("Client aborted connection in initialization.");
                    break;
                case NetOff::InitialClientMessageSpecifyer::START:
                    startSim();
                    run = false;
                    break;
            }
        }
    }

    void InitialNetworkServer::getFile()
    {
        NetOff::SimulationServer & server = *_networkPlan.server.get();
        int newId = server.getLastSimId();
        std::string filePath = Util::FileHelper::find(_tmpFmus[newId]->getWorkingDirectory(), server.getSimulationFileName(), true);
        if (filePath.empty())
        {
            if (server.getSimulationFileName().find('/') != std::string::npos)
            {
                filePath = Util::FileHelper::absoluteFilePath(server.getSimulationFileName());  // look from root
            }
            if (filePath.empty())
                throw std::runtime_error("Couldn't find requested file.");
        }
        server.confirmSimulationFile(newId, filePath);
    }

    void InitialNetworkServer::initSim()
    {
        NetOff::SimulationServer & server = *_networkPlan.server.get();
        int newId = server.getLastSimId();

        FMI::AbstractFmu * fmu = _tmpFmus[newId].get();
        if (fmu->isLoaded())
        {
            const FMI::ValueReferenceCollection & refs = fmu->getAllValueReferences();
            const FMI::ValueInfo & vi = fmu->getValueInfo();

            _networkPlan.fmuNet[newId].outputMap = getMappingFromNameList(refs, server.getSelectedOutputVariables(newId), vi, true);
            _networkPlan.fmuNet[newId].inputMap = getMappingFromNameList(refs, server.getSelectedInputVariables(newId), vi, false);
        }
        else
            throw std::runtime_error("Remote simulation failed. Fmu couldn't be initialized.");

        FMI::ValueCollection tmpVals = _networkPlan.fmuNet[newId].outputMap.pack(fmu->getValues(FMI::ReferenceContainerType::ALL));
        NetOff::ValueContainer & initialValues = server.getOutputValueContainer(newId);
        initialValues.setRealValues(tmpVals.getValues<real_type>().data());
        initialValues.setIntValues(tmpVals.getValues<int_type>().data());
        initialValues.setBoolValues(tmpVals.getValues<bool_type>().data());
        server.confirmSimulationInit(newId, initialValues);
    }

    std::shared_ptr<Initialization::FmuPlan> InitialNetworkServer::findFmuInProgramPlan(const std::string fmuPath, Network::NetworkFmuInformation & netInfo)
    {
        std::shared_ptr<Initialization::FmuPlan> res;
        size_type simId = 0, coreId = 0, solveId = 0;
        for (const auto & simPlanVec : _plan.simPlans)
            for (const auto & simPlan : simPlanVec)
            {
                for (const auto & solvPlan : simPlan.dataManager.solvers)
                {
                    if (fmuPath == Util::FileHelper::absoluteFilePath(solvPlan->fmu->path) || fmuPath == solvPlan->fmu->name || fmuPath == solvPlan->fmu->name + std::string(".fmu"))
                    {
                        res = solvPlan->fmu;
                        netInfo.simPos = simId;
                        netInfo.corePos = coreId;
                        netInfo.solverPos = solveId;
                        return res;
                    }
                    ++solveId;
                }
                ++coreId;
            }
        ++simId;

        return res;
    }

    void InitialNetworkServer::addSim()
    {
        NetOff::SimulationServer & server = *_networkPlan.server.get();
        std::vector<Network::NetworkFmuInformation> &netFmuVec = _networkPlan.fmuNet;

        Initialization::MainFactory mf;
        int newId = std::get<1>(server.getAddedSimulation());

        netFmuVec.resize(newId + 1);
        _tmpFmus.resize(newId + 1);

        std::shared_ptr<Initialization::FmuPlan> fmuPlan = findFmuInProgramPlan(std::get<0>(server.getAddedSimulation()), netFmuVec[newId]);
        if (!fmuPlan)
        {
            server.deinitialize();
            throw std::runtime_error("Couldn't find fmu with given path.");
        }

        _tmpFmus[newId] = std::shared_ptr<FMI::AbstractFmu>(mf.createFmu(*fmuPlan));
        _tmpFmus[newId]->load();
        const FMI::ValueInfo & info = _tmpFmus[newId]->getValueInfo();

        NetOff::VariableList inputVarNames(info.getInputValueNames<real_type>(), info.getInputValueNames<int_type>(), info.getInputValueNames<bool_type>()),
                outputVarNames(info.getValueNames<real_type>(), info.getValueNames<int_type>(), info.getValueNames<bool_type>());
        server.confirmSimulationAdd(newId, inputVarNames, outputVarNames);
    }

    void InitialNetworkServer::startSim()
    {
        for (const auto & fmu : _tmpFmus)
            fmu->unload();
    }

    FMI::InputMapping InitialNetworkServer::getMappingFromNameList(const FMI::ValueReferenceCollection& refs, const NetOff::VariableList& vars,
                                                                   const FMI::ValueInfo& vi, bool fromFmu)
    {
        FMI::InputMapping mapping;
        addRefsToMapping<real_type>(mapping, vars.getReals(), vi, refs, fromFmu);
        addRefsToMapping<int_type>(mapping, vars.getInts(), vi, refs, fromFmu);
        addRefsToMapping<bool_type>(mapping, vars.getBools(), vi, refs, fromFmu);
        return mapping;
    }

}
<|endoftext|>