<commit_before>#include "Genes/Look_Ahead_Gene.h"

#include <cassert>
#include <memory>
#include <algorithm>

#include "Genes/Gene.h"
#include "Utility.h"
#include "Game/Board.h"
#include "Game/Clock.h"

class Move;

Look_Ahead_Gene::Look_Ahead_Gene() :
    mean_game_length(50),
    game_length_uncertainty(0.5),
    speculation_constant(1.0),
    capturing_speculation_constant(1.0)
{
}

void Look_Ahead_Gene::reset_properties() const
{
    properties["Mean Game Length"] = mean_game_length;
    properties["Game Length Uncertainty"] = game_length_uncertainty;
    properties["Speculation Constant"] = speculation_constant;
    properties["Capturing Speculation Constant"] = capturing_speculation_constant;
}

void Look_Ahead_Gene::load_properties()
{
    mean_game_length = properties["Mean Game Length"];
    game_length_uncertainty = properties["Game Length Uncertainty"];
    speculation_constant = properties["Speculation Constant"];
    capturing_speculation_constant = properties["Capturing Speculation Constant"];
}

double Look_Ahead_Gene::time_to_examine(const Board& board, const Clock& clock) const
{
    auto time_left = clock.time_left(board.whose_turn());
    auto moves_to_reset = clock.moves_to_reset(board.whose_turn());

    auto moves_so_far = board.get_game_record().size()/2; // only count moves by this player
    auto moves_left = Math::average_moves_left(mean_game_length, game_length_uncertainty, moves_so_far);

    return time_left/std::min(moves_left, double(moves_to_reset));
}

void Look_Ahead_Gene::gene_specific_mutation()
{
    switch(Random::random_integer(1, 4))
    {
        case 1:
            mean_game_length = std::max(1.0, mean_game_length + Random::random_normal(1.0));
            break;
        case 2:
            game_length_uncertainty = std::abs(game_length_uncertainty + Random::random_normal(0.05));
            break;
        case 3:
            speculation_constant += Random::random_normal(0.01);
            break;
        case 4:
            capturing_speculation_constant += Random::random_normal(0.01);
            break;
        default:
            assert(false); // If here, random_integer() called with wrong parameters
            break;
    }
}

std::unique_ptr<Gene> Look_Ahead_Gene::duplicate() const
{
    return std::make_unique<Look_Ahead_Gene>(*this);
}

std::string Look_Ahead_Gene::name() const
{
    return "Look Ahead Gene";
}

double Look_Ahead_Gene::score_board(const Board&) const
{
    return 0.0;
}

double Look_Ahead_Gene::speculation_time_factor(const Board& board) const
{
    return board.capture_possible() ? capturing_speculation_constant : speculation_constant;
}
<commit_msg>Increase mutation rate of speculation constants<commit_after>#include "Genes/Look_Ahead_Gene.h"

#include <cassert>
#include <memory>
#include <algorithm>

#include "Genes/Gene.h"
#include "Utility.h"
#include "Game/Board.h"
#include "Game/Clock.h"

class Move;

Look_Ahead_Gene::Look_Ahead_Gene() :
    mean_game_length(50),
    game_length_uncertainty(0.5),
    speculation_constant(1.0),
    capturing_speculation_constant(1.0)
{
}

void Look_Ahead_Gene::reset_properties() const
{
    properties["Mean Game Length"] = mean_game_length;
    properties["Game Length Uncertainty"] = game_length_uncertainty;
    properties["Speculation Constant"] = speculation_constant;
    properties["Capturing Speculation Constant"] = capturing_speculation_constant;
}

void Look_Ahead_Gene::load_properties()
{
    mean_game_length = properties["Mean Game Length"];
    game_length_uncertainty = properties["Game Length Uncertainty"];
    speculation_constant = properties["Speculation Constant"];
    capturing_speculation_constant = properties["Capturing Speculation Constant"];
}

double Look_Ahead_Gene::time_to_examine(const Board& board, const Clock& clock) const
{
    auto time_left = clock.time_left(board.whose_turn());
    auto moves_to_reset = clock.moves_to_reset(board.whose_turn());

    auto moves_so_far = board.get_game_record().size()/2; // only count moves by this player
    auto moves_left = Math::average_moves_left(mean_game_length, game_length_uncertainty, moves_so_far);

    return time_left/std::min(moves_left, double(moves_to_reset));
}

void Look_Ahead_Gene::gene_specific_mutation()
{
    switch(Random::random_integer(1, 4))
    {
        case 1:
            mean_game_length = std::max(1.0, mean_game_length + Random::random_normal(1.0));
            break;
        case 2:
            game_length_uncertainty = std::abs(game_length_uncertainty + Random::random_normal(0.05));
            break;
        case 3:
            speculation_constant += Random::random_normal(0.05);
            break;
        case 4:
            capturing_speculation_constant += Random::random_normal(0.05);
            break;
        default:
            assert(false); // If here, random_integer() called with wrong parameters
            break;
    }
}

std::unique_ptr<Gene> Look_Ahead_Gene::duplicate() const
{
    return std::make_unique<Look_Ahead_Gene>(*this);
}

std::string Look_Ahead_Gene::name() const
{
    return "Look Ahead Gene";
}

double Look_Ahead_Gene::score_board(const Board&) const
{
    return 0.0;
}

double Look_Ahead_Gene::speculation_time_factor(const Board& board) const
{
    return board.capture_possible() ? capturing_speculation_constant : speculation_constant;
}
<|endoftext|>


<commit_before>#include <GuiBase/Viewer/Viewer.hpp>

#include <iostream>

#include <QTimer>
#include <QMouseEvent>
#include <QPainter>

#include <Core/String/StringUtils.hpp>
#include <Core/Log/Log.hpp>
#include <Core/Math/ColorPresets.hpp>
#include <Core/Math/Math.hpp>
#include <Core/Containers/MakeShared.hpp>

#include <Core/Image/stb_image_write.h>

#include <Engine/Renderer/OpenGL/OpenGL.hpp>
#include <Engine/Component/Component.hpp>
#include <Engine/Renderer/Renderer.hpp>
#include <Engine/Renderer/Light/DirLight.hpp>
#include <Engine/Renderer/Camera/Camera.hpp>
#include <Engine/Renderer/Texture/Texture.hpp>
#include <Engine/Managers/SystemDisplay/SystemDisplay.hpp>
#include <Engine/Renderer/Renderers/ForwardRenderer.hpp>

#include <GuiBase/Viewer/TrackballCamera.hpp>
#include <GuiBase/Viewer/Gizmo/GizmoManager.hpp>
#include <GuiBase/Utils/Keyboard.hpp>

namespace Ra
{
    Gui::Viewer::Viewer( QWidget* parent )
        : QOpenGLWidget( parent )
        , m_gizmoManager(new GizmoManager(this))
        , m_renderThread( nullptr )
    {
        // Allow Viewer to receive events
        setFocusPolicy( Qt::StrongFocus );
        setMinimumSize( QSize( 800, 600 ) );

        m_camera.reset( new Gui::TrackballCamera( width(), height() ) );

        /// Intercept events to properly lock the renderer when it is compositing.

    }

    Gui::Viewer::~Viewer(){}

    void Gui::Viewer::initializeGL()
    {
        initializeOpenGLFunctions();

        LOG( logINFO ) << "*** Radium Engine Viewer ***";
        LOG( logINFO ) << "Renderer : " << glGetString( GL_RENDERER );
        LOG( logINFO ) << "Vendor   : " << glGetString( GL_VENDOR );
        LOG( logINFO ) << "OpenGL   : " << glGetString( GL_VERSION );
        LOG( logINFO ) << "GLSL     : " << glGetString( GL_SHADING_LANGUAGE_VERSION );

#if defined (OS_WINDOWS)
        glewExperimental = GL_TRUE;

        GLuint result = glewInit();
        if ( result != GLEW_OK )
        {
            std::string errorStr;
            Ra::Core::StringUtils::stringPrintf( errorStr, " GLEW init failed : %s", glewGetErrorString( result ) );
            CORE_ERROR( errorStr.c_str() );
        }
        else
        {
            LOG( logINFO ) << "GLEW     : " << glewGetString( GLEW_VERSION );
            glFlushError();
        }

#endif

        // FIXME(Charly): Renderer type should not be changed here
        m_renderers.resize( 1 );
        // FIXME(Mathias): width and height might be wrong the first time ResizeGL is called (see QOpenGLWidget doc). This may cause problem on Retina display under MacOsX
        m_renderers[0].reset( new Engine::ForwardRenderer( width(), height() ) );

        for ( auto& renderer : m_renderers )
        {
            renderer->initialize();
        }

        m_currentRenderer = m_renderers[0].get();

        auto light = Ra::Core::make_shared<Engine::DirectionalLight>();

        for ( auto& renderer : m_renderers )
        {
            renderer->addLight( light );
        }

        m_camera->attachLight( light );

        emit rendererReady();
    }

    Gui::CameraInterface* Gui::Viewer::getCameraInterface()
    {
        return m_camera.get();
    }

    Gui::GizmoManager* Gui::Viewer::getGizmoManager()
    {
        return m_gizmoManager;
    }

    const Engine::Renderer* Gui::Viewer::getRenderer() const
    {
        return m_currentRenderer;
    }

    void Gui::Viewer::onAboutToCompose()
    {
        // This slot function is called from the main thread as part of the event loop
        // when the GUI is about to update. We have to wait for the rendering to finish.
        m_currentRenderer->lockRendering();
    }

    void Gui::Viewer::onFrameSwapped()
    {
        // This slot is called from the main thread as part of the event loop when the
        // GUI has finished displaying the rendered image, so we unlock the renderer.
        m_currentRenderer->unlockRendering();
    }

    void Gui::Viewer::onAboutToResize()
    {
        // Like swap buffers, resizing is a blocking operation and we have to wait for the rendering
        // to finish before resizing.
        m_currentRenderer->lockRendering();
    }

    void Gui::Viewer::onResized()
    {
        m_currentRenderer->unlockRendering();
    }

    void Gui::Viewer::resizeGL( int width, int height )
    {
        // FIXME(Mathias) : Problem of glarea dimension on OsX Retina Display (half the size)
        // Renderer should have been locked by previous events.
        m_camera->resizeViewport( width, height );
        m_currentRenderer->resize( width, height );
    }

    void Gui::Viewer::mousePressEvent( QMouseEvent* event )
    {
        switch ( event->button() )
        {
            case Qt::LeftButton:
            {
#ifdef OS_MACOS
                // (Mathias) no middle button on Apple (only left, right and wheel)
                // replace middle button by <ctrl>+left (note : ctrl = "command"
                // fake the subsistem by setting MiddleButtonEvent and masking ControlModifier
                if (event->modifiers().testFlag( Qt::ControlModifier ) )
                {
                    auto mods = event->modifiers();
                    mods^=Qt::ControlModifier;
                    QMouseEvent macevent(event->type(), event->localPos(), event->windowPos(), event->screenPos(),
                                                    Qt::MiddleButton, event->buttons(),
                                                    mods, event->source() );
                    m_camera->handleMousePressEvent(&macevent);
                }
#endif
                if ( isKeyPressed( Qt::Key_Space ) )
                {
                    LOG( logINFO ) << "Raycast query launched";
                    Core::Ray r = m_camera->getCamera()->getRayFromScreen(Core::Vector2(event->x(), event->y()));
                    RA_DISPLAY_POINT(r.origin(), Core::Colors::Cyan(), 0.1f);
                    RA_DISPLAY_RAY(r, Core::Colors::Yellow());
                    auto ents = Engine::RadiumEngine::getInstance()->getEntityManager()->getEntities();
                    for (auto e : ents)
                    {
                        e->rayCastQuery(r);
                    }
                }
                else
                {
                    Engine::Renderer::PickingQuery query  = { Core::Vector2(event->x(), height() - event->y()), Core::MouseButton::RA_MOUSE_LEFT_BUTTON };
                    m_currentRenderer->addPickingRequest(query);
                    m_gizmoManager->handleMousePressEvent(event);
                }
            }
            break;

            case Qt::MiddleButton:
            {
                m_camera->handleMousePressEvent(event);
            }
            break;

            case Qt::RightButton:
            {
                // Check picking
                Engine::Renderer::PickingQuery query  = { Core::Vector2(event->x(), height() - event->y()), Core::MouseButton::RA_MOUSE_RIGHT_BUTTON };
                m_currentRenderer->addPickingRequest(query);
            }
            break;

            default:
            {
            } break;
        }
    }

    void Gui::Viewer::mouseReleaseEvent( QMouseEvent* event )
    {
        m_camera->handleMouseReleaseEvent( event );
        m_gizmoManager->handleMouseReleaseEvent(event);
    }

    void Gui::Viewer::mouseMoveEvent( QMouseEvent* event )
    {
        m_camera->handleMouseMoveEvent( event );
        m_gizmoManager->handleMouseMoveEvent(event);
    }

    void Gui::Viewer::wheelEvent( QWheelEvent* event )
    {
        m_camera->handleWheelEvent(event);
        QOpenGLWidget::wheelEvent( event );
    }

    void Gui::Viewer::keyPressEvent( QKeyEvent* event )
    {
        keyPressed(event->key());
        m_camera->handleKeyPressEvent( event );

        QOpenGLWidget::keyPressEvent(event);
    }

    void Gui::Viewer::keyReleaseEvent( QKeyEvent* event )
    {
        keyReleased(event->key());
        m_camera->handleKeyReleaseEvent( event );

        if (event->key() == Qt::Key_Z && !event->isAutoRepeat())
        {
            m_currentRenderer->toggleWireframe();
        }

        QOpenGLWidget::keyReleaseEvent(event);
    }

    void Gui::Viewer::reloadShaders()
    {
        // FIXME : check thread-saefty of this.
        m_currentRenderer->lockRendering();
        makeCurrent();
        m_currentRenderer->reloadShaders();
        doneCurrent();
        m_currentRenderer->unlockRendering();
    }

    void Gui::Viewer::displayTexture( const QString &tex )
    {
        m_currentRenderer->lockRendering();
        m_currentRenderer->displayTexture( tex.toStdString() );
        m_currentRenderer->unlockRendering();
    }

    void Gui::Viewer::changeRenderer( int index )
    {
        // NOTE(Charly): This is probably buggy since it has not been tested.
        LOG( logWARNING ) << "Changing renderers might be buggy since it has not been tested.";
        m_currentRenderer->lockRendering();
        m_currentRenderer = m_renderers[index].get();
        m_currentRenderer->initialize();
        m_currentRenderer->resize( width(), height() );
        m_currentRenderer->unlockRendering();
    }

    // Asynchronous rendering implementation

    void Gui::Viewer::startRendering( const Scalar dt )
    {
        makeCurrent();

        // Move camera if needed. Disabled for now as it takes too long (see issue #69)
        //m_camera->update( dt );

        Engine::RenderData data;
        data.dt = dt;
        data.projMatrix = m_camera->getProjMatrix();
        data.viewMatrix = m_camera->getViewMatrix();
        m_currentRenderer->render( data );
    }

    void Gui::Viewer::waitForRendering()
    {
    }

    void Gui::Viewer::handleFileLoading( const std::string& file )
    {
        for ( auto& renderer : m_renderers )
        {
            renderer->handleFileLoading( file );
        }
    }

    void Gui::Viewer::processPicking()
    {
        CORE_ASSERT( m_currentRenderer->getPickingQueries().size() == m_currentRenderer->getPickingResults().size(),
                    "There should be one result per query." );

        for (uint i = 0 ; i < m_currentRenderer->getPickingQueries().size(); ++i)
        {
            const Engine::Renderer::PickingQuery& query  = m_currentRenderer->getPickingQueries()[i];
            if ( query.m_button == Core::MouseButton::RA_MOUSE_LEFT_BUTTON)
            {
                emit leftClickPicking(m_currentRenderer->getPickingResults()[i]);
            }
            else if (query.m_button == Core::MouseButton::RA_MOUSE_RIGHT_BUTTON)
            {
                emit rightClickPicking(m_currentRenderer->getPickingResults()[i]);
            }
        }
    }

    void Gui::Viewer::fitCameraToScene( const Core::Aabb& aabb )
    {
        m_camera->fitScene( aabb );
    }

    std::vector<std::string> Gui::Viewer::getRenderersName() const
    {
        std::vector<std::string> ret;

        for ( const auto& r : m_renderers )
        {
            ret.push_back( r->getRendererName() );
        }

        return ret;
    }

    void Gui::Viewer::grabFrame( const std::string& filename )
    {
        makeCurrent();

        Engine::Texture* tex = m_currentRenderer->getDisplayTexture();
        tex->bind();

        // Get a buffer to store the pixels of the OpenGL texture (in float format)
        float* pixels = new float[tex->width() * tex->height() * 4];

        // Grab the texture data
        GL_ASSERT(glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, pixels));

        // Now we must convert the floats to RGB while flipping the image updisde down.
        unsigned char* writtenPixels = new uchar[tex->width() * tex->height() * 4];
        for (uint j = 0; j < tex->height(); ++j)
        {
            for (uint i = 0; i < tex->width(); ++i)
            {
                uint in = 4 * (j * tex->width() + i);  // Index in the texture buffer
                uint ou = 4 * ((tex->height() - 1 - j) * tex->width() + i); // Index in the final image (note the j flipping).

                writtenPixels[ou + 0] = Ra::Core::Math::clamp<uchar>(pixels[in + 0] * 255.f, 0u, 0xffu);
                writtenPixels[ou + 1] = Ra::Core::Math::clamp<uchar>(pixels[in + 1] * 255.f, 0u, 0xffu);
                writtenPixels[ou + 2] = Ra::Core::Math::clamp<uchar>(pixels[in + 2] * 255.f, 0u, 0xffu);
                writtenPixels[ou + 3] = 0xff;
            }
        }

        std::string ext = Core::StringUtils::getFileExt(filename);

        if (ext == "bmp")
        {
            stbi_write_bmp(filename.c_str(), tex->width(), tex->height(), 4, writtenPixels);
        }
        else if (ext == "png")
        {
            stbi_write_png(filename.c_str(), tex->width(), tex->height(), 4, writtenPixels, tex->width() * 4 * sizeof(uchar));
        }
        else
        {
            LOG(logWARNING) << "Cannot write frame to "<<filename<<" : unsupported extension";
        }

        delete[] pixels;
        delete[] writtenPixels;
    }

    void Gui::Viewer::enablePostProcess(int enabled)
    {
        m_currentRenderer->enablePostProcess(enabled);
    }

    void Gui::Viewer::enableDebugDraw(int enabled)
    {
        m_currentRenderer->enableDebugDraw(enabled);
    }
} // namespace Ra
<commit_msg>fix viewer<commit_after>#include <GuiBase/Viewer/Viewer.hpp>

#include <iostream>

#include <QTimer>
#include <QMouseEvent>
#include <QPainter>

#include <Core/String/StringUtils.hpp>
#include <Core/Log/Log.hpp>
#include <Core/Math/ColorPresets.hpp>
#include <Core/Math/Math.hpp>
#include <Core/Containers/MakeShared.hpp>

#include <Core/Image/stb_image_write.h>

#include <Engine/Renderer/OpenGL/OpenGL.hpp>
#include <Engine/Component/Component.hpp>
#include <Engine/Renderer/Renderer.hpp>
#include <Engine/Renderer/Light/DirLight.hpp>
#include <Engine/Renderer/Camera/Camera.hpp>
#include <Engine/Renderer/Texture/Texture.hpp>
#include <Engine/Managers/SystemDisplay/SystemDisplay.hpp>
#include <Engine/Renderer/Renderers/ForwardRenderer.hpp>

#include <GuiBase/Viewer/TrackballCamera.hpp>
#include <GuiBase/Viewer/Gizmo/GizmoManager.hpp>
#include <GuiBase/Utils/Keyboard.hpp>

namespace Ra
{
    Gui::Viewer::Viewer( QWidget* parent )
        : QOpenGLWidget( parent )
        , m_gizmoManager(new GizmoManager(this))
        , m_renderThread( nullptr )
    {
        // Allow Viewer to receive events
        setFocusPolicy( Qt::StrongFocus );
        setMinimumSize( QSize( 800, 600 ) );

        m_camera.reset( new Gui::TrackballCamera( width(), height() ) );

        /// Intercept events to properly lock the renderer when it is compositing.

    }

    Gui::Viewer::~Viewer(){}

    void Gui::Viewer::initializeGL()
    {
        initializeOpenGLFunctions();

        LOG( logINFO ) << "*** Radium Engine Viewer ***";
        LOG( logINFO ) << "Renderer : " << glGetString( GL_RENDERER );
        LOG( logINFO ) << "Vendor   : " << glGetString( GL_VENDOR );
        LOG( logINFO ) << "OpenGL   : " << glGetString( GL_VERSION );
        LOG( logINFO ) << "GLSL     : " << glGetString( GL_SHADING_LANGUAGE_VERSION );

#if defined (OS_WINDOWS)
        glewExperimental = GL_TRUE;

        GLuint result = glewInit();
        if ( result != GLEW_OK )
        {
            std::string errorStr;
            Ra::Core::StringUtils::stringPrintf( errorStr, " GLEW init failed : %s", glewGetErrorString( result ) );
            CORE_ERROR( errorStr.c_str() );
        }
        else
        {
            LOG( logINFO ) << "GLEW     : " << glewGetString( GLEW_VERSION );
            glFlushError();
        }

#endif

        // FIXME(Charly): Renderer type should not be changed here
        m_renderers.resize( 1 );
        // FIXME(Mathias): width and height might be wrong the first time ResizeGL is called (see QOpenGLWidget doc). This may cause problem on Retina display under MacOsX
        m_renderers[0].reset( new Engine::ForwardRenderer( width(), height() ) );

        for ( auto& renderer : m_renderers )
        {
            renderer->initialize();
        }

        m_currentRenderer = m_renderers[0].get();

        auto light = Ra::Core::make_shared<Engine::DirectionalLight>();

        for ( auto& renderer : m_renderers )
        {
            renderer->addLight( light );
        }

        m_camera->attachLight( light );

        emit rendererReady();
    }

    Gui::CameraInterface* Gui::Viewer::getCameraInterface()
    {
        return m_camera.get();
    }

    Gui::GizmoManager* Gui::Viewer::getGizmoManager()
    {
        return m_gizmoManager;
    }

    const Engine::Renderer* Gui::Viewer::getRenderer() const
    {
        return m_currentRenderer;
    }

    void Gui::Viewer::onAboutToCompose()
    {
        // This slot function is called from the main thread as part of the event loop
        // when the GUI is about to update. We have to wait for the rendering to finish.
        m_currentRenderer->lockRendering();
    }

    void Gui::Viewer::onFrameSwapped()
    {
        // This slot is called from the main thread as part of the event loop when the
        // GUI has finished displaying the rendered image, so we unlock the renderer.
        m_currentRenderer->unlockRendering();
    }

    void Gui::Viewer::onAboutToResize()
    {
        // Like swap buffers, resizing is a blocking operation and we have to wait for the rendering
        // to finish before resizing.
        m_currentRenderer->lockRendering();
    }

    void Gui::Viewer::onResized()
    {
        m_currentRenderer->unlockRendering();
    }

    void Gui::Viewer::resizeGL( int width, int height )
    {
        // FIXME(Mathias) : Problem of glarea dimension on OsX Retina Display (half the size)
        // Renderer should have been locked by previous events.
        m_camera->resizeViewport( width, height );
        m_currentRenderer->resize( width, height );
    }

    void Gui::Viewer::mousePressEvent( QMouseEvent* event )
    {
        switch ( event->button() )
        {
            case Qt::LeftButton:
            {
#ifdef OS_MACOS
                // (Mathias) no middle button on Apple (only left, right and wheel)
                // replace middle button by <ctrl>+left (note : ctrl = "command"
                // fake the subsistem by setting MiddleButtonEvent and masking ControlModifier
                if (event->modifiers().testFlag( Qt::ControlModifier ) )
                {
                    auto mods = event->modifiers();
                    mods^=Qt::ControlModifier;
                    QMouseEvent macevent(event->type(), event->localPos(), event->windowPos(), event->screenPos(),
                                                    Qt::MiddleButton, event->buttons(),
                                                    mods, event->source() );
                    m_camera->handleMousePressEvent(&macevent);
                }
#endif
                if ( isKeyPressed( Qt::Key_Space ) )
                {
                    LOG( logINFO ) << "Raycast query launched";
                    Core::Ray r = m_camera->getCamera()->getRayFromScreen(Core::Vector2(event->x(), event->y()));
                    RA_DISPLAY_POINT(r.origin(), Core::Colors::Cyan(), 0.1f);
                    RA_DISPLAY_RAY(r, Core::Colors::Yellow());
                    auto ents = Engine::RadiumEngine::getInstance()->getEntityManager()->getEntities();
                    for (auto e : ents)
                    {
                        e->rayCastQuery(r);
                    }
                }
                else
                {
                    Engine::Renderer::PickingQuery query  = { Core::Vector2(event->x(), height() - event->y()), Core::MouseButton::RA_MOUSE_LEFT_BUTTON };
                    m_currentRenderer->addPickingRequest(query);
                    m_gizmoManager->handleMousePressEvent(event);
                }
            }
            break;

            case Qt::MiddleButton:
            {
                m_camera->handleMousePressEvent(event);
            }
            break;

            case Qt::RightButton:
            {
                // Check picking
                Engine::Renderer::PickingQuery query  = { Core::Vector2(event->x(), height() - event->y()), Core::MouseButton::RA_MOUSE_RIGHT_BUTTON };
                m_currentRenderer->addPickingRequest(query);
            }
            break;

            default:
            {
            } break;
        }
    }

    void Gui::Viewer::mouseReleaseEvent( QMouseEvent* event )
    {
        m_camera->handleMouseReleaseEvent( event );
        m_gizmoManager->handleMouseReleaseEvent(event);
    }

    void Gui::Viewer::mouseMoveEvent( QMouseEvent* event )
    {
        m_camera->handleMouseMoveEvent( event );
        m_gizmoManager->handleMouseMoveEvent(event);
    }

    void Gui::Viewer::wheelEvent( QWheelEvent* event )
    {
        m_camera->handleWheelEvent(event);
        QOpenGLWidget::wheelEvent( event );
    }

    void Gui::Viewer::keyPressEvent( QKeyEvent* event )
    {
        keyPressed(event->key());
        m_camera->handleKeyPressEvent( event );

        QOpenGLWidget::keyPressEvent(event);
    }

    void Gui::Viewer::keyReleaseEvent( QKeyEvent* event )
    {
        keyReleased(event->key());
        m_camera->handleKeyReleaseEvent( event );

        if (event->key() == Qt::Key_Z && !event->isAutoRepeat())
        {
            m_currentRenderer->toggleWireframe();
        }

        QOpenGLWidget::keyReleaseEvent(event);
    }

    void Gui::Viewer::reloadShaders()
    {
        // FIXME : check thread-saefty of this.
        m_currentRenderer->lockRendering();
        makeCurrent();
        m_currentRenderer->reloadShaders();
        doneCurrent();
        m_currentRenderer->unlockRendering();
    }

    void Gui::Viewer::displayTexture( const QString &tex )
    {
        m_currentRenderer->lockRendering();
        m_currentRenderer->displayTexture( tex.toStdString() );
        m_currentRenderer->unlockRendering();
    }

    void Gui::Viewer::changeRenderer( int index )
    {
        // NOTE(Charly): This is probably buggy since it has not been tested.
        LOG( logWARNING ) << "Changing renderers might be buggy since it has not been tested.";
        m_currentRenderer->lockRendering();
        m_currentRenderer = m_renderers[index].get();
        m_currentRenderer->initialize();
        m_currentRenderer->resize( width(), height() );
        m_currentRenderer->unlockRendering();
    }

    // Asynchronous rendering implementation

    void Gui::Viewer::startRendering( const Scalar dt )
    {
        makeCurrent();

        // Move camera if needed. Disabled for now as it takes too long (see issue #69)
        //m_camera->update( dt );

        Engine::RenderData data;
        data.dt = dt;
        data.projMatrix = m_camera->getProjMatrix();
        data.viewMatrix = m_camera->getViewMatrix();
        m_currentRenderer->render( data );
    }

    void Gui::Viewer::waitForRendering()
    {
    }

    void Gui::Viewer::handleFileLoading( const std::string& file )
    {
        for ( auto& renderer : m_renderers )
        {
            renderer->handleFileLoading( file );
        }
    }

    void Gui::Viewer::processPicking()
    {
        CORE_ASSERT( m_currentRenderer->getPickingQueries().size() == m_currentRenderer->getPickingResults().size(),
                    "There should be one result per query." );

        for (uint i = 0 ; i < m_currentRenderer->getPickingQueries().size(); ++i)
        {
            const Engine::Renderer::PickingQuery& query  = m_currentRenderer->getPickingQueries()[i];
            if ( query.m_button == Core::MouseButton::RA_MOUSE_LEFT_BUTTON)
            {
                emit leftClickPicking(m_currentRenderer->getPickingResults()[i]);
            }
            else if (query.m_button == Core::MouseButton::RA_MOUSE_RIGHT_BUTTON)
            {
                emit rightClickPicking(m_currentRenderer->getPickingResults()[i]);
            }
        }
    }

    void Gui::Viewer::fitCameraToScene( const Core::Aabb& aabb )
    {
        m_camera->fitScene( aabb );
    }

    std::vector<std::string> Gui::Viewer::getRenderersName() const
    {
        std::vector<std::string> ret;

        for ( const auto& r : m_renderers )
        {
            ret.push_back( r->getRendererName() );
        }

        return ret;
    }

    void Gui::Viewer::grabFrame( const std::string& filename )
    {
        makeCurrent();

        Engine::Texture* tex = m_currentRenderer->getDisplayTexture();
        tex->bind();

        // Get a buffer to store the pixels of the OpenGL texture (in float format)
        float* pixels = new float[tex->width() * tex->height() * 4];

        // Grab the texture data
        GL_ASSERT(glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, pixels));

        // Now we must convert the floats to RGB while flipping the image updisde down.
        uchar* writtenPixels = new uchar[tex->width() * tex->height() * 4];
        for (uint j = 0; j < tex->height(); ++j)
        {
            for (uint i = 0; i < tex->width(); ++i)
            {
                uint in = 4 * (j * tex->width() + i);  // Index in the texture buffer
                uint ou = 4 * ((tex->height() - 1 - j) * tex->width() + i); // Index in the final image (note the j flipping).

                writtenPixels[ou + 0] = (uchar)Ra::Core::Math::clamp<Scalar>(pixels[in + 0] * 255.f, 0, 255);
                writtenPixels[ou + 1] = (uchar)Ra::Core::Math::clamp<Scalar>(pixels[in + 1] * 255.f, 0, 255);
                writtenPixels[ou + 2] = (uchar)Ra::Core::Math::clamp<Scalar>(pixels[in + 2] * 255.f, 0, 255);
                writtenPixels[ou + 3] = 0xff;
            }
        }

        std::string ext = Core::StringUtils::getFileExt(filename);

        if (ext == "bmp")
        {
            stbi_write_bmp(filename.c_str(), tex->width(), tex->height(), 4, writtenPixels);
        }
        else if (ext == "png")
        {
            stbi_write_png(filename.c_str(), tex->width(), tex->height(), 4, writtenPixels, tex->width() * 4 * sizeof(uchar));
        }
        else
        {
            LOG(logWARNING) << "Cannot write frame to "<<filename<<" : unsupported extension";
        }

        delete[] pixels;
        delete[] writtenPixels;
    }

    void Gui::Viewer::enablePostProcess(int enabled)
    {
        m_currentRenderer->enablePostProcess(enabled);
    }

    void Gui::Viewer::enableDebugDraw(int enabled)
    {
        m_currentRenderer->enableDebugDraw(enabled);
    }
} // namespace Ra
<|endoftext|>


<commit_before>/*  This file is part of the KDE project.

Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).

This library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 or 3 of the License.

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, see <http://www.gnu.org/licenses/>.

*/

#include "mediaobject.h"

#include "mmf_medianode.h"

QT_BEGIN_NAMESPACE

using namespace Phonon;
using namespace Phonon::MMF;

MMF::MediaNode::MediaNode(QObject *parent) : QObject::QObject(parent)
                                           , m_source(0)
                                           , m_target(0)
                                           , m_isApplied(false)
{
}

bool MMF::MediaNode::connectMediaNode(MediaNode *target)
{
    m_target = target;
    m_target->setSource(this);

    return applyNodesOnMediaObject(target);
}

bool MMF::MediaNode::disconnectMediaNode(MediaNode *target)
{
    Q_UNUSED(target);
    m_target = 0;
    m_isApplied = false;
    return false;
}

void MMF::MediaNode::setSource(MediaNode *source)
{
    m_source = source;
}

MMF::MediaNode *MMF::MediaNode::source() const
{
    return m_source;
}

MMF::MediaNode *MMF::MediaNode::target() const
{
    return m_target;
}

bool MMF::MediaNode::applyNodesOnMediaObject(MediaNode *)
{
    // Algorithmically, this can be expressed in a more efficient way by
    // exercising available assumptions, but it complicates code for input
    // data(length of the graph) which typically is very small.

    // First, we go to the very beginning of the graph.
	MMF::MediaNode *current = this;
    do {
        MediaNode *const candidate = current->source();
        if (candidate)
            current = candidate;
        else
            break;
    }
    while (current);

    // Now we do two things, while walking to the other end:
    // 1. Find the MediaObject, if present
    // 2. Collect a list of all unapplied MediaNodes

    QList<MediaNode *> unapplied;
    MMF::MediaObject *mo = 0;

    do {
        if (!current->m_isApplied)
            unapplied.append(current);

        if (!mo)
            mo = qobject_cast<MMF::MediaObject *>(current);

        current = current->target();
    }
    while (current);

    // Now, lets activate all the objects, if we found the MediaObject.

    if (mo) {
        for (int i = 0; i < unapplied.count(); ++i) {
            MediaNode *const at = unapplied.at(i);

            // We don't want to apply MediaObject on itself.
            if (at != mo)
                at->activateOnMediaObject(mo);
        }
    }

    return true;
}

QT_END_NAMESPACE

<commit_msg>Use correct return value.<commit_after>/*  This file is part of the KDE project.

Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).

This library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 or 3 of the License.

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, see <http://www.gnu.org/licenses/>.

*/

#include "mediaobject.h"

#include "mmf_medianode.h"

QT_BEGIN_NAMESPACE

using namespace Phonon;
using namespace Phonon::MMF;

MMF::MediaNode::MediaNode(QObject *parent) : QObject::QObject(parent)
                                           , m_source(0)
                                           , m_target(0)
                                           , m_isApplied(false)
{
}

bool MMF::MediaNode::connectMediaNode(MediaNode *target)
{
    m_target = target;
    m_target->setSource(this);

    return applyNodesOnMediaObject(target);
}

bool MMF::MediaNode::disconnectMediaNode(MediaNode *target)
{
    Q_UNUSED(target);
    m_target = 0;
    m_isApplied = false;
    return true;
}

void MMF::MediaNode::setSource(MediaNode *source)
{
    m_source = source;
}

MMF::MediaNode *MMF::MediaNode::source() const
{
    return m_source;
}

MMF::MediaNode *MMF::MediaNode::target() const
{
    return m_target;
}

bool MMF::MediaNode::applyNodesOnMediaObject(MediaNode *)
{
    // Algorithmically, this can be expressed in a more efficient way by
    // exercising available assumptions, but it complicates code for input
    // data(length of the graph) which typically is very small.

    // First, we go to the very beginning of the graph.
	MMF::MediaNode *current = this;
    do {
        MediaNode *const candidate = current->source();
        if (candidate)
            current = candidate;
        else
            break;
    }
    while (current);

    // Now we do two things, while walking to the other end:
    // 1. Find the MediaObject, if present
    // 2. Collect a list of all unapplied MediaNodes

    QList<MediaNode *> unapplied;
    MMF::MediaObject *mo = 0;

    do {
        if (!current->m_isApplied)
            unapplied.append(current);

        if (!mo)
            mo = qobject_cast<MMF::MediaObject *>(current);

        current = current->target();
    }
    while (current);

    // Now, lets activate all the objects, if we found the MediaObject.

    if (mo) {
        for (int i = 0; i < unapplied.count(); ++i) {
            MediaNode *const at = unapplied.at(i);

            // We don't want to apply MediaObject on itself.
            if (at != mo)
                at->activateOnMediaObject(mo);
        }
    }

    return true;
}

QT_END_NAMESPACE

<|endoftext|>


<commit_before>#include <babylon/materialslibrary/gradient/gradient_material.h>

#include <nlohmann/json.hpp>

#include <babylon/buffers/vertex_buffer.h>
#include <babylon/cameras/camera.h>
#include <babylon/engines/engine.h>
#include <babylon/engines/scene.h>
#include <babylon/materials/effect.h>
#include <babylon/materials/effect_fallbacks.h>
#include <babylon/materials/ieffect_creation_options.h>
#include <babylon/materials/image_processing_configuration.h>
#include <babylon/materials/material_helper.h>
#include <babylon/materialslibrary/gradient/gradient_fragment_fx.h>
#include <babylon/materialslibrary/gradient/gradient_vertex_fx.h>
#include <babylon/meshes/abstract_mesh.h>
#include <babylon/meshes/mesh.h>
#include <babylon/meshes/sub_mesh.h>

namespace BABYLON {
namespace MaterialsLibrary {

GradientMaterial::GradientMaterial(const std::string& iName, Scene* scene)
    : PushMaterial{iName, scene}
    , maxSimultaneousLights{this, &GradientMaterial::get_maxSimultaneousLights,
                            &GradientMaterial::set_maxSimultaneousLights}
    , topColor{Color3(1.f, 0.f, 0.f)}
    , topColorAlpha{1.f}
    , bottomColor{Color3(0.f, 0.f, 1.f)}
    , bottomColorAlpha{1.f}
    , offset{0}
    , scale{1.f}
    , smoothness{1.f}
    , disableLighting{this, &GradientMaterial::get_disableLighting,
                      &GradientMaterial::set_disableLighting}
    , _maxSimultaneousLights{4}
    , _disableLighting{false}
{
  // Vertex shader
  Effect::ShadersStore()["gradientVertexShader"] = gradientVertexShader;

  // Fragment shader
  Effect::ShadersStore()["gradientPixelShader"] = gradientPixelShader;
}

GradientMaterial::~GradientMaterial() = default;

unsigned int GradientMaterial::get_maxSimultaneousLights() const
{
  return _maxSimultaneousLights;
}

void GradientMaterial::set_maxSimultaneousLights(unsigned int value)
{
  if (_maxSimultaneousLights != value) {
    _maxSimultaneousLights = value;
    _markAllSubMeshesAsLightsDirty();
  }
}

bool GradientMaterial::get_disableLighting() const
{
  return _disableLighting;
}

void GradientMaterial::set_disableLighting(bool value)
{
  if (_disableLighting != value) {
    _disableLighting = value;
    _markAllSubMeshesAsLightsDirty();
  }
}

bool GradientMaterial::needAlphaBlending() const
{
  return (alpha < 1.f || topColorAlpha < 1.f || bottomColorAlpha < 1.f);
}

bool GradientMaterial::needAlphaTesting() const
{
  return true;
}

BaseTexturePtr GradientMaterial::getAlphaTestTexture()
{
  return nullptr;
}

bool GradientMaterial::isReadyForSubMesh(AbstractMesh* mesh, SubMesh* subMesh, bool useInstances)
{
  if (isFrozen()) {
    if (subMesh->effect() && subMesh->effect()->_wasPreviouslyReady) {
      return true;
    }
  }

  if (!subMesh->_materialDefines) {
    subMesh->materialDefines = std::make_shared<GradientMaterialDefines>();
  }

  auto definesPtr = std::static_pointer_cast<GradientMaterialDefines>(subMesh->_materialDefines);
  auto& defines   = *definesPtr.get();
  auto scene      = getScene();

  if (_isReadyForSubMesh(subMesh)) {
    return true;
  }

  auto engine = scene->getEngine();

  MaterialHelper::PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances);

  MaterialHelper::PrepareDefinesForMisc(mesh, scene, false, pointsCloud(), fogEnabled(),
                                        _shouldTurnAlphaTestOn(mesh), defines);

  defines._needNormals = MaterialHelper::PrepareDefinesForLights(
    scene, mesh, defines, false, _maxSimultaneousLights, _disableLighting);

  defines.boolDef["EMISSIVE"] = _disableLighting;

  // Attribs
  MaterialHelper::PrepareDefinesForAttributes(mesh, defines, false, true);

  // Get correct effect
  if (defines.isDirty()) {
    defines.markAsProcessed();

    scene->resetCachedMaterial();

    // Fallbacks
    auto fallbacks = std::make_unique<EffectFallbacks>();
    if (defines["FOG"]) {
      fallbacks->addFallback(1, "FOG");
    }

    MaterialHelper::HandleFallbacksForShadows(defines, *fallbacks);

    if (defines.intDef["NUM_BONE_INFLUENCERS"] > 0) {
      fallbacks->addCPUSkinningFallback(0, mesh);
    }

    defines.boolDef["IMAGEPROCESSINGPOSTPROCESS"]
      = scene->imageProcessingConfiguration()->applyByPostProcess();

    // Attributes
    std::vector<std::string> attribs{VertexBuffer::PositionKind};

    if (defines["NORMAL"]) {
      attribs.emplace_back(VertexBuffer::NormalKind);
    }

    if (defines["UV1"]) {
      attribs.emplace_back(VertexBuffer::UVKind);
    }

    if (defines["UV2"]) {
      attribs.emplace_back(VertexBuffer::UV2Kind);
    }

    if (defines["VERTEXCOLOR"]) {
      attribs.emplace_back(VertexBuffer::ColorKind);
    }

    MaterialHelper::PrepareAttributesForBones(attribs, mesh, defines, *fallbacks);
    MaterialHelper::PrepareAttributesForInstances(attribs, defines);

    // Legacy browser patch
    const std::string shaderName{"gradient"};
    auto join = defines.toString();
    const std::vector<std::string> uniforms{
      "world",       "view",        "viewProjection", "vEyePosition", "vLightsType",
      "vFogInfos",   "vFogColor",   "pointSize",      "mBones",       "vClipPlane",
      "vClipPlane2", "vClipPlane3", "vClipPlane4",    "vClipPlane5",  "vClipPlane6",
      "topColor",    "bottomColor", "offset",         "smoothness",   "scale"};
    const std::vector<std::string> samplers{"diffuseSampler"};
    const std::vector<std::string> uniformBuffers{};

    IEffectCreationOptions options;
    options.attributes            = std::move(attribs);
    options.uniformsNames         = std::move(uniforms);
    options.uniformBuffersNames   = std::move(uniformBuffers);
    options.samplers              = std::move(samplers);
    options.materialDefines       = &defines;
    options.defines               = std::move(join);
    options.maxSimultaneousLights = 4;
    options.fallbacks             = std::move(fallbacks);
    options.onCompiled            = onCompiled;
    options.onError               = onError;
    options.indexParameters       = {{"maxSimultaneousLights", 4}};

    MaterialHelper::PrepareUniformsAndSamplersList(options);

    subMesh->setEffect(scene->getEngine()->createEffect(shaderName, options, engine), definesPtr,
                       _materialContext);
  }
  if (!subMesh->effect() || !subMesh->effect()->isReady()) {
    return false;
  }

  defines._renderId                      = scene->getRenderId();
  subMesh->effect()->_wasPreviouslyReady = true;

  return true;
}

void GradientMaterial::bindForSubMesh(Matrix& world, Mesh* mesh, SubMesh* subMesh)
{
  auto scene = getScene();

  auto defines = static_cast<GradientMaterialDefines*>(subMesh->_materialDefines.get());
  if (!defines) {
    return;
  }

  auto effect = subMesh->effect();
  if (!effect) {
    return;
  }

  _activeEffect = effect;

  // Matrices
  bindOnlyWorldMatrix(world);
  _activeEffect->setMatrix("viewProjection", scene->getTransformMatrix());

  // Bones
  MaterialHelper::BindBonesParameters(mesh, effect.get());

  if (_mustRebind(scene, effect)) {
    // Clip plane
    MaterialHelper::BindClipPlane(effect, scene);

    // Point size
    if (pointsCloud()) {
      _activeEffect->setFloat("pointSize", pointSize);
    }

    scene->bindEyePosition(effect.get());
  }

  if (scene->lightsEnabled() && !disableLighting) {
    MaterialHelper::BindLights(scene, mesh, _activeEffect.get(), *defines, maxSimultaneousLights);
  }

  // View
  if (scene->fogEnabled() && mesh->applyFog() && scene->fogMode() != Scene::FOGMODE_NONE) {
    _activeEffect->setMatrix("view", scene->getViewMatrix());
  }

  // Fog
  MaterialHelper::BindFogParameters(scene, mesh, _activeEffect);

  _activeEffect->setColor4("topColor", topColor, topColorAlpha);
  _activeEffect->setColor4("bottomColor", bottomColor, bottomColorAlpha);
  _activeEffect->setFloat("offset", offset);
  _activeEffect->setFloat("scale", scale);
  _activeEffect->setFloat("smoothness", smoothness);

  _afterBind(mesh, _activeEffect);
}

std::vector<IAnimatablePtr> GradientMaterial::getAnimatables()
{
  return std::vector<IAnimatablePtr>();
}

void GradientMaterial::dispose(bool forceDisposeEffect, bool forceDisposeTextures,
                               bool /*notBoundToMesh*/)
{
  PushMaterial::dispose(forceDisposeEffect, forceDisposeTextures);
}

MaterialPtr GradientMaterial::clone(const std::string& /*name*/, bool /*cloneChildren*/) const
{
  return nullptr;
}

json GradientMaterial::serialize() const
{
  return nullptr;
}

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

GradientMaterial* GradientMaterial::Parse(const json& /*source*/, Scene* /*scene*/,
                                          const std::string& /*rootUrl*/)
{
  return nullptr;
}

} // end of namespace MaterialsLibrary
} // end of namespace BABYLON
<commit_msg>const correctness<commit_after>#include <babylon/materialslibrary/gradient/gradient_material.h>

#include <nlohmann/json.hpp>

#include <babylon/buffers/vertex_buffer.h>
#include <babylon/cameras/camera.h>
#include <babylon/engines/engine.h>
#include <babylon/engines/scene.h>
#include <babylon/materials/effect.h>
#include <babylon/materials/effect_fallbacks.h>
#include <babylon/materials/ieffect_creation_options.h>
#include <babylon/materials/image_processing_configuration.h>
#include <babylon/materials/material_helper.h>
#include <babylon/materialslibrary/gradient/gradient_fragment_fx.h>
#include <babylon/materialslibrary/gradient/gradient_vertex_fx.h>
#include <babylon/meshes/abstract_mesh.h>
#include <babylon/meshes/mesh.h>
#include <babylon/meshes/sub_mesh.h>

namespace BABYLON {
namespace MaterialsLibrary {

GradientMaterial::GradientMaterial(const std::string& iName, Scene* scene)
    : PushMaterial{iName, scene}
    , maxSimultaneousLights{this, &GradientMaterial::get_maxSimultaneousLights,
                            &GradientMaterial::set_maxSimultaneousLights}
    , topColor{Color3(1.f, 0.f, 0.f)}
    , topColorAlpha{1.f}
    , bottomColor{Color3(0.f, 0.f, 1.f)}
    , bottomColorAlpha{1.f}
    , offset{0}
    , scale{1.f}
    , smoothness{1.f}
    , disableLighting{this, &GradientMaterial::get_disableLighting,
                      &GradientMaterial::set_disableLighting}
    , _maxSimultaneousLights{4}
    , _disableLighting{false}
{
  // Vertex shader
  Effect::ShadersStore()["gradientVertexShader"] = gradientVertexShader;

  // Fragment shader
  Effect::ShadersStore()["gradientPixelShader"] = gradientPixelShader;
}

GradientMaterial::~GradientMaterial() = default;

unsigned int GradientMaterial::get_maxSimultaneousLights() const
{
  return _maxSimultaneousLights;
}

void GradientMaterial::set_maxSimultaneousLights(unsigned int value)
{
  if (_maxSimultaneousLights != value) {
    _maxSimultaneousLights = value;
    _markAllSubMeshesAsLightsDirty();
  }
}

bool GradientMaterial::get_disableLighting() const
{
  return _disableLighting;
}

void GradientMaterial::set_disableLighting(bool value)
{
  if (_disableLighting != value) {
    _disableLighting = value;
    _markAllSubMeshesAsLightsDirty();
  }
}

bool GradientMaterial::needAlphaBlending() const
{
  return (alpha < 1.f || topColorAlpha < 1.f || bottomColorAlpha < 1.f);
}

bool GradientMaterial::needAlphaTesting() const
{
  return true;
}

BaseTexturePtr GradientMaterial::getAlphaTestTexture()
{
  return nullptr;
}

bool GradientMaterial::isReadyForSubMesh(AbstractMesh* mesh, SubMesh* subMesh, bool useInstances)
{
  if (isFrozen()) {
    if (subMesh->effect() && subMesh->effect()->_wasPreviouslyReady) {
      return true;
    }
  }

  if (!subMesh->_materialDefines) {
    subMesh->materialDefines = std::make_shared<GradientMaterialDefines>();
  }

  auto definesPtr  = std::static_pointer_cast<GradientMaterialDefines>(subMesh->_materialDefines);
  auto& defines    = *definesPtr.get();
  const auto scene = getScene();

  if (_isReadyForSubMesh(subMesh)) {
    return true;
  }

  const auto engine = scene->getEngine();

  MaterialHelper::PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances);

  MaterialHelper::PrepareDefinesForMisc(mesh, scene, false, pointsCloud(), fogEnabled(),
                                        _shouldTurnAlphaTestOn(mesh), defines);

  defines._needNormals = MaterialHelper::PrepareDefinesForLights(
    scene, mesh, defines, false, _maxSimultaneousLights, _disableLighting);

  defines.boolDef["EMISSIVE"] = _disableLighting;

  // Attribs
  MaterialHelper::PrepareDefinesForAttributes(mesh, defines, false, true);

  // Get correct effect
  if (defines.isDirty()) {
    defines.markAsProcessed();

    scene->resetCachedMaterial();

    // Fallbacks
    auto fallbacks = std::make_unique<EffectFallbacks>();
    if (defines["FOG"]) {
      fallbacks->addFallback(1, "FOG");
    }

    MaterialHelper::HandleFallbacksForShadows(defines, *fallbacks);

    if (defines.intDef["NUM_BONE_INFLUENCERS"] > 0) {
      fallbacks->addCPUSkinningFallback(0, mesh);
    }

    defines.boolDef["IMAGEPROCESSINGPOSTPROCESS"]
      = scene->imageProcessingConfiguration()->applyByPostProcess();

    // Attributes
    std::vector<std::string> attribs{VertexBuffer::PositionKind};

    if (defines["NORMAL"]) {
      attribs.emplace_back(VertexBuffer::NormalKind);
    }

    if (defines["UV1"]) {
      attribs.emplace_back(VertexBuffer::UVKind);
    }

    if (defines["UV2"]) {
      attribs.emplace_back(VertexBuffer::UV2Kind);
    }

    if (defines["VERTEXCOLOR"]) {
      attribs.emplace_back(VertexBuffer::ColorKind);
    }

    MaterialHelper::PrepareAttributesForBones(attribs, mesh, defines, *fallbacks);
    MaterialHelper::PrepareAttributesForInstances(attribs, defines);

    // Legacy browser patch
    const std::string shaderName{"gradient"};
    auto join = defines.toString();
    const std::vector<std::string> uniforms{
      "world",       "view",        "viewProjection", "vEyePosition", "vLightsType",
      "vFogInfos",   "vFogColor",   "pointSize",      "mBones",       "vClipPlane",
      "vClipPlane2", "vClipPlane3", "vClipPlane4",    "vClipPlane5",  "vClipPlane6",
      "topColor",    "bottomColor", "offset",         "smoothness",   "scale"};
    const std::vector<std::string> samplers{"diffuseSampler"};
    const std::vector<std::string> uniformBuffers{};

    IEffectCreationOptions options;
    options.attributes            = std::move(attribs);
    options.uniformsNames         = std::move(uniforms);
    options.uniformBuffersNames   = std::move(uniformBuffers);
    options.samplers              = std::move(samplers);
    options.materialDefines       = &defines;
    options.defines               = std::move(join);
    options.maxSimultaneousLights = 4;
    options.fallbacks             = std::move(fallbacks);
    options.onCompiled            = onCompiled;
    options.onError               = onError;
    options.indexParameters       = {{"maxSimultaneousLights", 4}};

    MaterialHelper::PrepareUniformsAndSamplersList(options);

    subMesh->setEffect(scene->getEngine()->createEffect(shaderName, options, engine), definesPtr,
                       _materialContext);
  }
  if (!subMesh->effect() || !subMesh->effect()->isReady()) {
    return false;
  }

  defines._renderId                      = scene->getRenderId();
  subMesh->effect()->_wasPreviouslyReady = true;

  return true;
}

void GradientMaterial::bindForSubMesh(Matrix& world, Mesh* mesh, SubMesh* subMesh)
{
  const auto scene = getScene();

  auto defines = static_cast<GradientMaterialDefines*>(subMesh->_materialDefines.get());
  if (!defines) {
    return;
  }

  const auto effect = subMesh->effect();
  if (!effect) {
    return;
  }

  _activeEffect = effect;

  // Matrices
  bindOnlyWorldMatrix(world);
  _activeEffect->setMatrix("viewProjection", scene->getTransformMatrix());

  // Bones
  MaterialHelper::BindBonesParameters(mesh, effect.get());

  if (_mustRebind(scene, effect)) {
    // Clip plane
    MaterialHelper::BindClipPlane(effect, scene);

    // Point size
    if (pointsCloud()) {
      _activeEffect->setFloat("pointSize", pointSize);
    }

    scene->bindEyePosition(effect.get());
  }

  if (scene->lightsEnabled() && !disableLighting) {
    MaterialHelper::BindLights(scene, mesh, _activeEffect.get(), *defines, maxSimultaneousLights);
  }

  // View
  if (scene->fogEnabled() && mesh->applyFog() && scene->fogMode() != Scene::FOGMODE_NONE) {
    _activeEffect->setMatrix("view", scene->getViewMatrix());
  }

  // Fog
  MaterialHelper::BindFogParameters(scene, mesh, _activeEffect);

  _activeEffect->setColor4("topColor", topColor, topColorAlpha);
  _activeEffect->setColor4("bottomColor", bottomColor, bottomColorAlpha);
  _activeEffect->setFloat("offset", offset);
  _activeEffect->setFloat("scale", scale);
  _activeEffect->setFloat("smoothness", smoothness);

  _afterBind(mesh, _activeEffect);
}

std::vector<IAnimatablePtr> GradientMaterial::getAnimatables()
{
  return std::vector<IAnimatablePtr>();
}

void GradientMaterial::dispose(bool forceDisposeEffect, bool forceDisposeTextures,
                               bool /*notBoundToMesh*/)
{
  PushMaterial::dispose(forceDisposeEffect, forceDisposeTextures);
}

MaterialPtr GradientMaterial::clone(const std::string& /*name*/, bool /*cloneChildren*/) const
{
  return nullptr;
}

json GradientMaterial::serialize() const
{
  return nullptr;
}

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

GradientMaterial* GradientMaterial::Parse(const json& /*source*/, Scene* /*scene*/,
                                          const std::string& /*rootUrl*/)
{
  return nullptr;
}

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


<commit_before>// TODO(ralntdir):
// Think how to clean SDL if the programs ends with some crash
// Finished the program if there is a problem at SDL/IMG init or
// when creating the window or the renderer

#include <iostream>

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>

// TODO(ralntdir): read this from a scene file?
#define WIDTH 400
#define HEIGHT 200
#define MAX_COLOR 255

int main(int argc, char* argv[])
{
  SDL_Window *window;
  SDL_Renderer *renderer;
  SDL_Surface *surface;
  SDL_Texture *texture;

  // Init SDL
  if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
  {
    std::cout << "Error in SDL_Init(): " << SDL_GetError() << "\n";
  }

  // Init SDL_Image
  if (IMG_Init(0) < 0)
  {
    std::cout << "Error in IMG_Init(): " << IMG_GetError() << "\n";
  }

  // Create a Window
  // NOTE(ralntdir): SDL_WINDOW_SHOWN is ignored by SDL_CreateWindow().
  // The SDL_Window is implicitly shown if SDL_WINDOW_HIDDEN is not set.
  window = SDL_CreateWindow("Devember RT", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
                            WIDTH, HEIGHT, SDL_WINDOW_SHOWN);

  if (window == 0)
  {
    std::cout << "Error in SDL_CreateWindow(): " << SDL_GetError() << "\n";
  }

  // Create a Renderer
  renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

  if (renderer == 0)
  {
    std::cout << "Error in SDL_CreateRenderer(): " << SDL_GetError() << "\n";
  }

  // Create a .ppm file
  std::cout << "P3\n";
  std::cout << "# image.ppm\n";
  std::cout << WIDTH << " " << HEIGHT << "\n";
  std::cout << MAX_COLOR << "\n";

  // NOTE(ralntdir): From top to bottom
  for (int i = HEIGHT; i > 0 ; i--)
  {
    for (int j = 0; j < WIDTH; j++)
    {
      int r = 0;
      int g = (255.00*i/HEIGHT);
      int b = (255.00*j/WIDTH);

      std::cout << r << " " << g << " " << b << "\n";
    }
  }

  // Load the image
  // TODO(ralntdir): right now I'm loading the image from the previous
  // execution!!!! Change this!!!!!
  surface = IMG_Load("image.ppm");
  if (surface == 0)
  {
    std::cout << "Error in IMG_Load(): " << IMG_GetError() << "\n";
  }

  texture = SDL_CreateTextureFromSurface(renderer, surface);
  if (texture == 0)
  {
    std::cout << "Error in SDL_CreateTextureFromSurface(): " << SDL_GetError() << "\n";
  }
  SDL_FreeSurface(surface);

  // Show the texture
  SDL_RenderCopy(renderer, texture, 0, 0);
  SDL_RenderPresent(renderer);
  SDL_Delay(5000);

  // Free the texture
  SDL_DestroyTexture(texture);
  // Quit IMG
  IMG_Quit();
  // Quit SDL
  SDL_Quit();

  return(0);
}
<commit_msg>Create and save the image and then load it and show it in the SDL window<commit_after>// TODO(ralntdir):
// Think how to clean SDL if the programs ends with some crash
// Finished the program if there is a problem at SDL/IMG init or
// when creating the window or the renderer
//
// Features to add:
// sphere "class"
// ray "class"
// ray->sphere intersection

#include <iostream>
#include <fstream>

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>

// TODO(ralntdir): read this from a scene file?
#define WIDTH 400
#define HEIGHT 200
#define MAX_COLOR 255

int main(int argc, char* argv[])
{
  SDL_Window *window;
  SDL_Renderer *renderer;
  SDL_Surface *surface;
  SDL_Texture *texture;

  // Init SDL
  if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
  {
    std::cout << "Error in SDL_Init(): " << SDL_GetError() << "\n";
  }

  // Init SDL_Image
  if (IMG_Init(0) < 0)
  {
    std::cout << "Error in IMG_Init(): " << IMG_GetError() << "\n";
  }

  // Create a Window
  // NOTE(ralntdir): SDL_WINDOW_SHOWN is ignored by SDL_CreateWindow().
  // The SDL_Window is implicitly shown if SDL_WINDOW_HIDDEN is not set.
  window = SDL_CreateWindow("Devember RT", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
                            WIDTH, HEIGHT, SDL_WINDOW_SHOWN);

  if (window == 0)
  {
    std::cout << "Error in SDL_CreateWindow(): " << SDL_GetError() << "\n";
  }

  // Create a Renderer
  renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

  if (renderer == 0)
  {
    std::cout << "Error in SDL_CreateRenderer(): " << SDL_GetError() << "\n";
  }

  // Create a .ppm file
  std::ofstream ofs("image.ppm", std::ofstream::out | std::ofstream::binary);

  ofs << "P3\n";
  ofs << "# image.ppm\n";
  ofs << WIDTH << " " << HEIGHT << "\n";
  ofs << MAX_COLOR << "\n";

  // NOTE(ralntdir): From top to bottom
  for (int i = HEIGHT; i > 0 ; i--)
  {
    for (int j = 0; j < WIDTH; j++)
    {
      int g = 0;
      int r = (255.00*i/HEIGHT);
      int b = (255.00*j/WIDTH);

      ofs << r << " " << g << " " << b << "\n";
    }
  }

  ofs.close();

  // Load the image
  // TODO(ralntdir): right now I'm loading the image from the previous
  // execution!!!! Change this!!!!!
  surface = IMG_Load("image.ppm");
  if (surface == 0)
  {
    std::cout << "Error in IMG_Load(): " << IMG_GetError() << "\n";
  }

  texture = SDL_CreateTextureFromSurface(renderer, surface);
  if (texture == 0)
  {
    std::cout << "Error in SDL_CreateTextureFromSurface(): " << SDL_GetError() << "\n";
  }
  SDL_FreeSurface(surface);

  // Show the texture
  SDL_RenderCopy(renderer, texture, 0, 0);
  SDL_RenderPresent(renderer);
  SDL_Delay(5000);

  // Free the texture
  SDL_DestroyTexture(texture);
  // Quit IMG
  IMG_Quit();
  // Quit SDL
  SDL_Quit();

  return(0);
}
<|endoftext|>


<commit_before>// Copyright eeGeo Ltd (2012-2015), All Rights Reserved

#include "SelectFirstResultSearchService.h"
#include "SearchQueryPerformer.h"
#include "InteriorInteractionModel.h"
#include "IMenuOption.h"
#include "SearchResultModel.h"
#include "ISearchResultRepository.h"
#include "IMenuModel.h"

namespace ExampleApp
{
    namespace Search
    {
        namespace SelectFirstResult
        {
            namespace SdkModel
            {
                SelectFirstResultSearchService::SelectFirstResultSearchService(Search::SdkModel::ISearchQueryPerformer& searchQueryPerformer,
                                                     Menu::View::IMenuSectionViewModel& searchSectionViewModel,
                                                     Search::SdkModel::ISearchResultRepository& searchResultRepository)
                : m_searchQueryPerformer(searchQueryPerformer)
                , m_searchResultRepository(searchResultRepository)
                , m_searchSectionViewModel(searchSectionViewModel)
                , m_searchResultAddedCallback(this, &SelectFirstResultSearchService::OnSearchResultAdded)
                , m_didTransition(false)
                {
                    m_searchResultRepository.InsertItemAddedCallback(m_searchResultAddedCallback);
                }

                SelectFirstResultSearchService::~SelectFirstResultSearchService()
                {
                    m_searchResultRepository.RemoveItemAddedCallback(m_searchResultAddedCallback);
                }

                void SelectFirstResultSearchService::HandleSearch(std::string& queryString, const std::string& interiorId)
                {
                    m_searchQueryPerformer.RemoveSearchQueryResults();
                    m_searchQueryPerformer.PerformSearchQuery(queryString.c_str(), false, true, interiorId);

                    m_didTransition = false;
                }

                void SelectFirstResultSearchService::OnSearchResultAdded(Search::SdkModel::SearchResultModel*& pSearchResultModel)
                {
                    if(!m_didTransition)
                    {
                        if(m_searchSectionViewModel.Size() > 0)
                        {
                            m_searchSectionViewModel.GetItemAtIndex(0).MenuOption().Select();
                            m_didTransition = true;
                        }
                    }
                }
            }
        }
    }
}

<commit_msg>Fixed a bug with searchfirstresultsearchservice It no longer transition to the first result on a normal search in example app. Buddy: Sam A<commit_after>// Copyright eeGeo Ltd (2012-2015), All Rights Reserved

#include "SelectFirstResultSearchService.h"
#include "SearchQueryPerformer.h"
#include "InteriorInteractionModel.h"
#include "IMenuOption.h"
#include "SearchResultModel.h"
#include "ISearchResultRepository.h"
#include "IMenuModel.h"

namespace ExampleApp
{
    namespace Search
    {
        namespace SelectFirstResult
        {
            namespace SdkModel
            {
                SelectFirstResultSearchService::SelectFirstResultSearchService(Search::SdkModel::ISearchQueryPerformer& searchQueryPerformer,
                                                     Menu::View::IMenuSectionViewModel& searchSectionViewModel,
                                                     Search::SdkModel::ISearchResultRepository& searchResultRepository)
                : m_searchQueryPerformer(searchQueryPerformer)
                , m_searchResultRepository(searchResultRepository)
                , m_searchSectionViewModel(searchSectionViewModel)
                , m_searchResultAddedCallback(this, &SelectFirstResultSearchService::OnSearchResultAdded)
                , m_didTransition(true)
                {
                    m_searchResultRepository.InsertItemAddedCallback(m_searchResultAddedCallback);
                }

                SelectFirstResultSearchService::~SelectFirstResultSearchService()
                {
                    m_searchResultRepository.RemoveItemAddedCallback(m_searchResultAddedCallback);
                }

                void SelectFirstResultSearchService::HandleSearch(std::string& queryString, const std::string& interiorId)
                {
                    m_searchQueryPerformer.RemoveSearchQueryResults();
                    m_searchQueryPerformer.PerformSearchQuery(queryString.c_str(), false, true, interiorId);

                    m_didTransition = false;
                }

                void SelectFirstResultSearchService::OnSearchResultAdded(Search::SdkModel::SearchResultModel*& pSearchResultModel)
                {
                    if(!m_didTransition)
                    {
                        if(m_searchSectionViewModel.Size() > 0)
                        {
                            m_searchSectionViewModel.GetItemAtIndex(0).MenuOption().Select();
                            m_didTransition = true;
                        }
                    }
                }
            }
        }
    }
}

<|endoftext|>


<commit_before>/*
**  Copyright (C) 2012, 2013 Aldebaran Robotics
**  See COPYING for the license
*/
#include <qi/type/detail/staticobjecttype.hpp>
#include <qi/anyobject.hpp>
#include <qi/signal.hpp>
#include <qi/property.hpp>
#include <qi/jsoncodec.hpp>
#include <qi/strand.hpp>

qiLogCategory("qitype.object");

namespace qi
{

namespace detail
{

void StaticObjectTypeBase::initialize(const MetaObject& mo, const ObjectTypeData& data)
{
  _metaObject = mo;
  _data = data;
}

ObjectUid StaticObjectTypeBase::uid(void* instance) const
{
  QI_ASSERT_TRUE(instance);
  return os::ptrUid(instance);
}

const MetaObject&
StaticObjectTypeBase::metaObject(void* )
{
  return _metaObject;
}

namespace {
  template <typename T>
  void noopDeleter(T* obj)
  {}
}

qi::Future<AnyReference>
StaticObjectTypeBase::metaCall(void* instance, AnyObject context, unsigned int methodId,
                               const GenericFunctionParameters& params,
                               MetaCallType callType, Signature returnSignature)
{
  ObjectTypeData::MethodMap::iterator i;
  i = _data.methodMap.find(methodId);
  if (i == _data.methodMap.end())
  {
    return qi::makeFutureError<AnyReference>("No such method");
  }

  if (returnSignature.isValid())
  {
    const MetaMethod *mm = metaObject(instance).method(methodId);
    if (!mm)
      return makeFutureError<AnyReference>("Unexpected error: MetaMethod not found");
    if (mm->returnSignature().isConvertibleTo(returnSignature) == 0)
    {
      if (returnSignature.isConvertibleTo(mm->returnSignature())==0)
        return makeFutureError<AnyReference>(
          "Call error: will not be able to convert return type from "
          + mm->returnSignature().toString()
          + " to " + returnSignature.toString());
      else
       qiLogWarning() << "Return signature might be incorrect depending on the value, from "
          + mm->returnSignature().toString()
          + " to " + returnSignature.toString();
    }
  }

  MetaCallType methodThreadingModel = i->second.second;

  ExecutionContext* ec = getExecutionContext(instance, context, methodThreadingModel);

  AnyFunction method = i->second.first;
  AnyReference self;
  if (methodId >= Manageable::startId  && methodId < Manageable::endId)
  {
    self = AnyReference(qi::typeOf<Manageable>(), static_cast<Manageable*>(context.asGenericObject()));
  }
  else
  {
    self = AnyReference(this, instance);
  }
  GenericFunctionParameters p2;
  p2.reserve(params.size()+1);
  p2.push_back(self);
  p2.insert(p2.end(), params.begin(), params.end());

  return ::qi::metaCall(ec, _data.threadingModel, methodThreadingModel, callType, context, methodId, method, p2, true);
}

ExecutionContext* StaticObjectTypeBase::getExecutionContext(
    void* instance, qi::AnyObject context, MetaCallType methodThreadingModel)
{
  ExecutionContext* ec = context.executionContext();
  if (_data.threadingModel == ObjectThreadingModel_SingleThread)
  {
    // execute queued methods on global eventloop if they are of queued type
    if (methodThreadingModel == MetaCallType_Queued)
      ec = 0;
    else if (!ec)
    {
      boost::shared_ptr<Manageable> manageable = context.managedObjectPtr();
      boost::mutex::scoped_lock l(manageable->initMutex());
      if (!manageable->executionContext())
      {
        if (_data.strandAccessor)
          manageable->forceExecutionContext(boost::shared_ptr<qi::Strand>(
                _data.strandAccessor.call<qi::Strand*>(instance),
                &noopDeleter<qi::Strand>));
        else
          manageable->forceExecutionContext(boost::shared_ptr<qi::Strand>(
                new qi::Strand(*::qi::getEventLoop())));
      }
      ec = context.executionContext();
    }
  }
  return ec;
}

static PropertyBase* property(ObjectTypeData& data, void* instance, unsigned int signal)
{
  ObjectTypeData::PropertyGetterMap::iterator i;
  i = data.propertyGetterMap.find(signal);
  if (i == data.propertyGetterMap.end())
    return  nullptr;
  PropertyBase* sig = i->second(instance);
  if (!sig)
  {
    qiLogError() << "Property getter returned NULL";
    return  nullptr;
  }
  return sig;
}

static SignalBase* getSignal(ObjectTypeData& data, void* instance, unsigned int signal)
{
  ObjectTypeData::SignalGetterMap::iterator i;
  i = data.signalGetterMap.find(signal);
  if (i == data.signalGetterMap.end())
  {
    PropertyBase* prop = property(data, instance, signal);
    if (prop)
      return prop->signal();
    return  nullptr;
  }
  SignalBase* sig = i->second(instance);
  if (!sig)
  {
    qiLogError() << "Signal getter returned NULL";
    return  nullptr;
  }
  return sig;
}

static void reportError(qi::Future<AnyReference> fut) {
  if (fut.hasError()) {
    qiLogWarning() << "metaPost failed: " << fut.error();
    return;
  }
  qi::AnyReference ref = fut.value();
  ref.destroy();
}

void StaticObjectTypeBase::metaPost(void* instance, AnyObject context, unsigned int signal,
                                    const GenericFunctionParameters& params)
{
  if (SignalBase* sb = getSignal(_data, instance, signal))
  {
    sb->trigger(params);
  }
  else if (_data.methodMap.find(signal) != _data.methodMap.end())
  { // try method
    qi::Future<AnyReference> fut = metaCall(instance, context, signal, params, MetaCallType_Queued, Signature());
    fut.connect(&reportError);
  }
  else
  {
    qiLogWarning() << "post: no such signal or method " << signal;
    return;
  }
}

qi::Future<SignalLink> StaticObjectTypeBase::connect(void* instance, AnyObject context, unsigned int event,
                                                       const SignalSubscriber& subscriber)
{
  if (event >= Manageable::startId && event < Manageable::endId)
    instance = static_cast<Manageable*>(context.asGenericObject());
  SignalBase* sb = getSignal(_data, instance, event);
  if (!sb) {
    qiLogWarning() << "connect: no such signal: " << event;
    return qi::makeFutureError<SignalLink>("Cant find signal");
  }
  SignalLink id = sb->connect(subscriber);
  if (id == SignalBase::invalidSignalLink)
    return qi::Future<SignalLink>(id);
  SignalLink link = ((SignalLink)event << 32) + id;
  QI_ASSERT(link >> 32 == event);
  QI_ASSERT((link & 0xFFFFFFFF) == id);
  qiLogDebug() << "Connect " << event <<' ' << id << ' ' << link;
  return qi::Future<SignalLink>(link);
}

qi::Future<void> StaticObjectTypeBase::disconnect(void* instance, AnyObject context, SignalLink linkId)
{
  qiLogDebug() << "Disconnect " << linkId;
  unsigned int event = linkId >> 32;
  unsigned int link = linkId & 0xFFFFFFFF;
  if (event >= Manageable::startId && event < Manageable::endId)
    instance = static_cast<Manageable*>(context.asGenericObject());
  SignalBase* sb = getSignal(_data, instance, event);
  if (!sb)
  {
    qiLogWarning() << "disconnect: no such signal: " << event;
    return qi::makeFutureError<void>("Cant find signal");
  }

  return sb->disconnectAsync(link).andThen([](bool successful)
  {
    if (!successful)
      throw std::runtime_error("signal registration failed");
  });
}

qi::Future<AnyValue> StaticObjectTypeBase::property(void* instance, AnyObject context, unsigned int id)
{
  PropertyBase* p = ::qi::detail::property(_data, instance, id);
  if (!p)
  {
    qiLogWarning() << "property: no such property: " << id;
    return qi::makeFutureError<AnyValue>("Cant find property");
  }
  ExecutionContext* ec = getExecutionContext(instance, context);
  if (ec)
    return ec->async([p]{
          return p->value().async();
        }).unwrap();
  else
    return p->value();
}

static void setPropertyValue(PropertyBase* property, AnyValue value)
{
  property->setValue(value.asReference());
}

qi::Future<void> StaticObjectTypeBase::setProperty(void* instance, AnyObject context, unsigned int id, AnyValue value)
{
  PropertyBase* p = ::qi::detail::property(_data, instance, id);
  if (!p)
  {
    qiLogWarning() << "setProperty: no such property: " << id;
    return qi::makeFutureError<void>("Cant find property");
  }
  qiLogDebug() << "SetProperty " << id << " " << encodeJSON(value);
  ExecutionContext* ec = getExecutionContext(instance, context);
  if (ec)
    return ec->async(boost::bind(&setPropertyValue, p, value));
  else
  {
    try
    {
      p->setValue(value.asReference());
    }
    catch(const std::exception& e)
    {
      return qi::makeFutureError<void>(std::string("setProperty: ") + e.what());
    }
    return qi::Future<void>(0);
  }
}

const std::vector<std::pair<TypeInterface*, std::ptrdiff_t> >& StaticObjectTypeBase::parentTypes()
{
  return _data.parentTypes;
}

const TypeInfo& StaticObjectTypeBase::info()
{
  return _data.classType->info();
}

void* StaticObjectTypeBase::initializeStorage(void* ptr)
{
  return _data.classType->initializeStorage(ptr);
}

void* StaticObjectTypeBase::ptrFromStorage(void** ptr)
{
  return _data.classType->ptrFromStorage(ptr);
}

void* StaticObjectTypeBase::clone(void* inst)
{
  return _data.classType->clone(inst);
}

void StaticObjectTypeBase::destroy(void* inst)
{
  _data.classType->destroy(inst);
}

bool StaticObjectTypeBase::less(void* a, void* b)
{
  return a<b;
}

}

}
<commit_msg>qi.type: Removes wait in `StaticObjectTypeBase::setProperty`.<commit_after>/*
**  Copyright (C) 2012, 2013 Aldebaran Robotics
**  See COPYING for the license
*/
#include <qi/type/detail/staticobjecttype.hpp>
#include <qi/anyobject.hpp>
#include <qi/signal.hpp>
#include <qi/property.hpp>
#include <qi/jsoncodec.hpp>
#include <qi/strand.hpp>

qiLogCategory("qitype.object");

namespace qi
{

namespace detail
{

void StaticObjectTypeBase::initialize(const MetaObject& mo, const ObjectTypeData& data)
{
  _metaObject = mo;
  _data = data;
}

ObjectUid StaticObjectTypeBase::uid(void* instance) const
{
  QI_ASSERT_TRUE(instance);
  return os::ptrUid(instance);
}

const MetaObject&
StaticObjectTypeBase::metaObject(void* )
{
  return _metaObject;
}

namespace {
  template <typename T>
  void noopDeleter(T* obj)
  {}
}

qi::Future<AnyReference>
StaticObjectTypeBase::metaCall(void* instance, AnyObject context, unsigned int methodId,
                               const GenericFunctionParameters& params,
                               MetaCallType callType, Signature returnSignature)
{
  ObjectTypeData::MethodMap::iterator i;
  i = _data.methodMap.find(methodId);
  if (i == _data.methodMap.end())
  {
    return qi::makeFutureError<AnyReference>("No such method");
  }

  if (returnSignature.isValid())
  {
    const MetaMethod *mm = metaObject(instance).method(methodId);
    if (!mm)
      return makeFutureError<AnyReference>("Unexpected error: MetaMethod not found");
    if (mm->returnSignature().isConvertibleTo(returnSignature) == 0)
    {
      if (returnSignature.isConvertibleTo(mm->returnSignature())==0)
        return makeFutureError<AnyReference>(
          "Call error: will not be able to convert return type from "
          + mm->returnSignature().toString()
          + " to " + returnSignature.toString());
      else
       qiLogWarning() << "Return signature might be incorrect depending on the value, from "
          + mm->returnSignature().toString()
          + " to " + returnSignature.toString();
    }
  }

  MetaCallType methodThreadingModel = i->second.second;

  ExecutionContext* ec = getExecutionContext(instance, context, methodThreadingModel);

  AnyFunction method = i->second.first;
  AnyReference self;
  if (methodId >= Manageable::startId  && methodId < Manageable::endId)
  {
    self = AnyReference(qi::typeOf<Manageable>(), static_cast<Manageable*>(context.asGenericObject()));
  }
  else
  {
    self = AnyReference(this, instance);
  }
  GenericFunctionParameters p2;
  p2.reserve(params.size()+1);
  p2.push_back(self);
  p2.insert(p2.end(), params.begin(), params.end());

  return ::qi::metaCall(ec, _data.threadingModel, methodThreadingModel, callType, context, methodId, method, p2, true);
}

ExecutionContext* StaticObjectTypeBase::getExecutionContext(
    void* instance, qi::AnyObject context, MetaCallType methodThreadingModel)
{
  ExecutionContext* ec = context.executionContext();
  if (_data.threadingModel == ObjectThreadingModel_SingleThread)
  {
    // execute queued methods on global eventloop if they are of queued type
    if (methodThreadingModel == MetaCallType_Queued)
      ec = 0;
    else if (!ec)
    {
      boost::shared_ptr<Manageable> manageable = context.managedObjectPtr();
      boost::mutex::scoped_lock l(manageable->initMutex());
      if (!manageable->executionContext())
      {
        if (_data.strandAccessor)
          manageable->forceExecutionContext(boost::shared_ptr<qi::Strand>(
                _data.strandAccessor.call<qi::Strand*>(instance),
                &noopDeleter<qi::Strand>));
        else
          manageable->forceExecutionContext(boost::shared_ptr<qi::Strand>(
                new qi::Strand(*::qi::getEventLoop())));
      }
      ec = context.executionContext();
    }
  }
  return ec;
}

static PropertyBase* property(ObjectTypeData& data, void* instance, unsigned int signal)
{
  ObjectTypeData::PropertyGetterMap::iterator i;
  i = data.propertyGetterMap.find(signal);
  if (i == data.propertyGetterMap.end())
    return  nullptr;
  PropertyBase* sig = i->second(instance);
  if (!sig)
  {
    qiLogError() << "Property getter returned NULL";
    return  nullptr;
  }
  return sig;
}

static SignalBase* getSignal(ObjectTypeData& data, void* instance, unsigned int signal)
{
  ObjectTypeData::SignalGetterMap::iterator i;
  i = data.signalGetterMap.find(signal);
  if (i == data.signalGetterMap.end())
  {
    PropertyBase* prop = property(data, instance, signal);
    if (prop)
      return prop->signal();
    return  nullptr;
  }
  SignalBase* sig = i->second(instance);
  if (!sig)
  {
    qiLogError() << "Signal getter returned NULL";
    return  nullptr;
  }
  return sig;
}

static void reportError(qi::Future<AnyReference> fut) {
  if (fut.hasError()) {
    qiLogWarning() << "metaPost failed: " << fut.error();
    return;
  }
  qi::AnyReference ref = fut.value();
  ref.destroy();
}

void StaticObjectTypeBase::metaPost(void* instance, AnyObject context, unsigned int signal,
                                    const GenericFunctionParameters& params)
{
  if (SignalBase* sb = getSignal(_data, instance, signal))
  {
    sb->trigger(params);
  }
  else if (_data.methodMap.find(signal) != _data.methodMap.end())
  { // try method
    qi::Future<AnyReference> fut = metaCall(instance, context, signal, params, MetaCallType_Queued, Signature());
    fut.connect(&reportError);
  }
  else
  {
    qiLogWarning() << "post: no such signal or method " << signal;
    return;
  }
}

qi::Future<SignalLink> StaticObjectTypeBase::connect(void* instance, AnyObject context, unsigned int event,
                                                       const SignalSubscriber& subscriber)
{
  if (event >= Manageable::startId && event < Manageable::endId)
    instance = static_cast<Manageable*>(context.asGenericObject());
  SignalBase* sb = getSignal(_data, instance, event);
  if (!sb) {
    qiLogWarning() << "connect: no such signal: " << event;
    return qi::makeFutureError<SignalLink>("Cant find signal");
  }
  SignalLink id = sb->connect(subscriber);
  if (id == SignalBase::invalidSignalLink)
    return qi::Future<SignalLink>(id);
  SignalLink link = ((SignalLink)event << 32) + id;
  QI_ASSERT(link >> 32 == event);
  QI_ASSERT((link & 0xFFFFFFFF) == id);
  qiLogDebug() << "Connect " << event <<' ' << id << ' ' << link;
  return qi::Future<SignalLink>(link);
}

qi::Future<void> StaticObjectTypeBase::disconnect(void* instance, AnyObject context, SignalLink linkId)
{
  qiLogDebug() << "Disconnect " << linkId;
  unsigned int event = linkId >> 32;
  unsigned int link = linkId & 0xFFFFFFFF;
  if (event >= Manageable::startId && event < Manageable::endId)
    instance = static_cast<Manageable*>(context.asGenericObject());
  SignalBase* sb = getSignal(_data, instance, event);
  if (!sb)
  {
    qiLogWarning() << "disconnect: no such signal: " << event;
    return qi::makeFutureError<void>("Cant find signal");
  }

  return sb->disconnectAsync(link).andThen([](bool successful)
  {
    if (!successful)
      throw std::runtime_error("signal registration failed");
  });
}

qi::Future<AnyValue> StaticObjectTypeBase::property(void* instance, AnyObject context, unsigned int id)
{
  PropertyBase* p = ::qi::detail::property(_data, instance, id);
  if (!p)
  {
    qiLogWarning() << "property: no such property: " << id;
    return qi::makeFutureError<AnyValue>("Cant find property");
  }
  ExecutionContext* ec = getExecutionContext(instance, context);
  if (ec)
    return ec->async([p]{
          return p->value().async();
        }).unwrap();
  else
    return p->value();
}

static void setPropertyValue(PropertyBase* property, AnyValue value)
{
  property->setValue(value.asReference());
}

qi::Future<void> StaticObjectTypeBase::setProperty(void* instance, AnyObject context, unsigned int id, AnyValue value)
{
  PropertyBase* p = ::qi::detail::property(_data, instance, id);
  if (!p)
  {
    qiLogWarning() << "setProperty: no such property: " << id;
    return qi::makeFutureError<void>("Cant find property");
  }
  qiLogDebug() << "SetProperty " << id << " " << encodeJSON(value);
  ExecutionContext* ec = getExecutionContext(instance, context);
  if (ec)
    return ec->async(boost::bind(&setPropertyValue, p, value));
  else
  {
    const auto asyncSetValue = [&]{
      return p->setValue(value.asReference()).async();
    };
    const auto formatError = [&](const std::string& err) {
      return str(boost::format("Failed to set object property '%1%', reason: %2%") % id % err);
    };
    return ka::invoke_catch(futureErrorFromException<void>(formatError), asyncSetValue);
  }
}

const std::vector<std::pair<TypeInterface*, std::ptrdiff_t> >& StaticObjectTypeBase::parentTypes()
{
  return _data.parentTypes;
}

const TypeInfo& StaticObjectTypeBase::info()
{
  return _data.classType->info();
}

void* StaticObjectTypeBase::initializeStorage(void* ptr)
{
  return _data.classType->initializeStorage(ptr);
}

void* StaticObjectTypeBase::ptrFromStorage(void** ptr)
{
  return _data.classType->ptrFromStorage(ptr);
}

void* StaticObjectTypeBase::clone(void* inst)
{
  return _data.classType->clone(inst);
}

void StaticObjectTypeBase::destroy(void* inst)
{
  _data.classType->destroy(inst);
}

bool StaticObjectTypeBase::less(void* a, void* b)
{
  return a<b;
}

}

}
<|endoftext|>


<commit_before>#ifndef BTREEINC
#include <binarytree.h>
#define BTREEINC
#endif

template <class T>
BinaryTree<T>::BinaryTree()
	: root(nullptr), levels(0) {}

template <class T>
BinaryTree<T>::~BinaryTree() {
	delete root;
}

template <class T>
unsigned int BinaryTree<T>::Levels() const {
	return levels;
}

template <class T>
void BinaryTree<T>::Add(T i) {

	levels++;

	if (root == nullptr) {
		root = NewNode<T>(i);
		return;
	}

	if (root->Value < i) {
		return add(i, root->Right);
	}
	add(i, root->Left);
	return;
}

template <class T>
void BinaryTree<T>::add(T i, Tree<T>* &leaf) {
	if (leaf == nullptr) {
		leaf = NewNode<T>(i);
		return;
	}
	if (leaf->Value < i) {
		return add(i, leaf->Right);
	}
	return add(i, leaf->Left);
}

template <class T>
vector<T> BinaryTree<T>::Walk() {

	vector<T> out;
	if (root == nullptr) {
		cout << "here\n";
		return out;
	}

	walk(root->Left, out);
	out.push_back(root->Value);
	walk(root->Right, out);

	return out;
}

template <class T>
vector<T> BinaryTree<T>::walk(Tree<T> *leaf, vector<T>& out) {
	if (leaf == nullptr) {
		return out;
	}

	walk(leaf->Left, out);
	out.push_back(leaf->Value);
	walk(leaf->Right, out);

	return out;
}

int main() {
	BinaryTree<int> btree;
	vector<int> tree;

	btree.Add(0);
	btree.Add(4);
	btree.Add(5);
	btree.Add(-2);
	btree.Add(-1);
	btree.Add(8);

	tree = btree.Walk();

	cout << "[ ";
	for (auto x = tree.begin(); x != tree.end(); ++x) {
		cout << (*x) << " ";
	}
	cout << "]\n";

	BinaryTree<string> btreestr;
	vector<string> treestr;

	btreestr.Add("YoYo");
	btreestr.Add("Hi");
	btreestr.Add("Howdy");
	btreestr.Add("Sup");
	btreestr.Add("Hello");
	btreestr.Add("Wassup");

	treestr = btreestr.Walk();

	cout << "[ ";
	for (auto x = treestr.begin(); x != treestr.end(); ++x) {
		cout << (*x) << " ";
	}
	cout << "]\n";

	BinaryTree<double> btreedbl;
	vector<double> treedbl;
	btreedbl.Add(0.001);
	btreedbl.Add(-0.001);
	btreedbl.Add(0.0123);
	btreedbl.Add(123123.00);
	btreedbl.Add(123121.001);
	btreedbl.Add(0.021);

	treedbl = btreedbl.Walk();

	cout << "[ ";
	for (auto x = treedbl.begin(); x != treedbl.end(); ++x) {
		cout << (*x) << " ";
	}
	cout << "]\n";

	{ BinaryTree<int> nbtree; }

	return 0;
}
<commit_msg>Removed main<commit_after>#ifndef BTREEINC
#include <binarytree.h>
#define BTREEINC
#endif

template <class T>
BinaryTree<T>::BinaryTree()
	: root(nullptr), levels(0) {}

template <class T>
BinaryTree<T>::~BinaryTree() {
	delete root;
}

template <class T>
unsigned int BinaryTree<T>::Levels() const {
	return levels;
}

template <class T>
void BinaryTree<T>::Add(T i) {

	levels++;

	if (root == nullptr) {
		root = NewNode<T>(i);
		return;
	}

	if (root->Value < i) {
		return add(i, root->Right);
	}
	add(i, root->Left);
	return;
}

template <class T>
void BinaryTree<T>::add(T i, Tree<T>* &leaf) {
	if (leaf == nullptr) {
		leaf = NewNode<T>(i);
		return;
	}
	if (leaf->Value < i) {
		return add(i, leaf->Right);
	}
	return add(i, leaf->Left);
}

template <class T>
vector<T> BinaryTree<T>::Walk() {

	vector<T> out;
	if (root == nullptr) {
		cout << "here\n";
		return out;
	}

	walk(root->Left, out);
	out.push_back(root->Value);
	walk(root->Right, out);

	return out;
}

template <class T>
vector<T> BinaryTree<T>::walk(Tree<T> *leaf, vector<T>& out) {
	if (leaf == nullptr) {
		return out;
	}

	walk(leaf->Left, out);
	out.push_back(leaf->Value);
	walk(leaf->Right, out);

	return out;
}

<|endoftext|>


<commit_before>// Time:  O(n^2 * l), l is the average length of words
// Space: O(n)

class Solution {
public:
    int numSimilarGroups(vector<string>& A) {
        UnionFind union_find(A.size());
        for (int i = 0; i < A.size(); ++i) {
            for (int j = 0; j < i; ++j) {
                if (isSimilar(A[i], A[j])) {
                    union_find.union_set(i, j);
                }
            }
        }
        return union_find.size();
    }

private:
    bool isSimilar(const string& a, const string& b) {
        int diff = 0;
        for (int i = 0; i < a.length(); ++i) {
            if (a[i] != b[i]) {
                ++diff;
            }
        }
        return diff == 2;
    }

    class UnionFind {
        public:
            UnionFind(const int n) : set_(n), size_(n) {
                iota(set_.begin(), set_.end(), 0);
            }

            int find_set(const int x) {
               if (set_[x] != x) {
                   set_[x] = find_set(set_[x]);  // Path compression.
               }
               return set_[x];
            }

            bool union_set(const int x, const int y) {
                int x_root = find_set(x), y_root = find_set(y);
                if (x_root == y_root) {
                    return false;
                }
                set_[min(x_root, y_root)] = max(x_root, y_root);
                --size_;
                return true;
            }

            int size() const {
                return size_;
            }

        private:
            vector<int> set_;
            int size_;
    };
};

// Time:  O(n^2 * l) ~ O(n * l^4)
// Space: O(n) ~ O(n * l^3)
class Solution_MLE {
public:
    int numSimilarGroups(vector<string>& A) {
        const int N = A.size(), L = A[0].length();
        UnionFind union_find(A.size());
        if (N < L*L) {
            for (int i = 0; i < N; ++i) {
                for (int j = 0; j < i; ++j) {
                    if (isSimilar(A[i], A[j])) {
                        union_find.union_set(i, j);
                    }
                }
            }
        } else {
            unordered_map<string, vector<int>> buckets;
            unordered_set<string> lookup;
            for (int i = 0; i < A.size(); ++i) {
                auto word = A[i];
                if (!lookup.count(word)) {
                    buckets[word].emplace_back(i);
                    lookup.emplace(word);
                }
                for (int j1 = 0; j1 < L; ++j1) {
                    for (int j2 = 0; j2 < j1; ++j2) {
                        swap(word[j1], word[j2]);
                        buckets[word].emplace_back(i);
                        swap(word[j1], word[j2]);
                    }
                }
            }
            for (const auto& word : A) {
                for (int i = 0; i < buckets[word].size(); ++i) {
                    for (int j = 0; j < i; ++j) {
                        union_find.union_set(buckets[word][i], buckets[word][j]);
                    }
                }
            }
        }
        return union_find.size();
    }

private:
    bool isSimilar(const string &a, const string &b) {
        int diff = 0;
        for (int i = 0; i < a.length(); ++i) {
            if (a[i] != b[i]) {
                ++diff;
            }
        }
        return diff == 2;
    }

    class UnionFind {
        public:
            UnionFind(const int n) : set_(n), size_(n) {
                iota(set_.begin(), set_.end(), 0);
            }

            int find_set(const int x) {
               if (set_[x] != x) {
                   set_[x] = find_set(set_[x]);  // Path compression.
               }
               return set_[x];
            }

            bool union_set(const int x, const int y) {
                int x_root = find_set(x), y_root = find_set(y);
                if (x_root == y_root) {
                    return false;
                }
                set_[min(x_root, y_root)] = max(x_root, y_root);
                --size_;
                return true;
            }

            int size() const {
                return size_;
            }

        private:
            vector<int> set_;
            int size_;
    };
};
<commit_msg>Update similar-string-groups.cpp<commit_after>// Time:  O(n^2 * l), l is the average length of words
// Space: O(n)

class Solution {
public:
    int numSimilarGroups(vector<string>& A) {
        UnionFind union_find(A.size());
        for (int i = 0; i < A.size(); ++i) {
            for (int j = 0; j < i; ++j) {
                if (isSimilar(A[i], A[j])) {
                    union_find.union_set(i, j);
                }
            }
        }
        return union_find.size();
    }

private:
    bool isSimilar(const string& a, const string& b) {
        int diff = 0;
        for (int i = 0; i < a.length(); ++i) {
            if (a[i] != b[i]) {
                if (++diff > 2) {
                    return false;
                }
            }
        }
        return diff == 2;
    }

    class UnionFind {
        public:
            UnionFind(const int n) : set_(n), size_(n) {
                iota(set_.begin(), set_.end(), 0);
            }

            int find_set(const int x) {
               if (set_[x] != x) {
                   set_[x] = find_set(set_[x]);  // Path compression.
               }
               return set_[x];
            }

            bool union_set(const int x, const int y) {
                int x_root = find_set(x), y_root = find_set(y);
                if (x_root == y_root) {
                    return false;
                }
                set_[min(x_root, y_root)] = max(x_root, y_root);
                --size_;
                return true;
            }

            int size() const {
                return size_;
            }

        private:
            vector<int> set_;
            int size_;
    };
};

// Time:  O(n^2 * l) ~ O(n * l^4)
// Space: O(n) ~ O(n * l^3)
class Solution_MLE {
public:
    int numSimilarGroups(vector<string>& A) {
        const int N = A.size(), L = A[0].length();
        UnionFind union_find(A.size());
        if (N < L*L) {
            for (int i = 0; i < N; ++i) {
                for (int j = 0; j < i; ++j) {
                    if (isSimilar(A[i], A[j])) {
                        union_find.union_set(i, j);
                    }
                }
            }
        } else {
            unordered_map<string, vector<int>> buckets;
            unordered_set<string> lookup;
            for (int i = 0; i < A.size(); ++i) {
                auto word = A[i];
                if (!lookup.count(word)) {
                    buckets[word].emplace_back(i);
                    lookup.emplace(word);
                }
                for (int j1 = 0; j1 < L; ++j1) {
                    for (int j2 = 0; j2 < j1; ++j2) {
                        swap(word[j1], word[j2]);
                        buckets[word].emplace_back(i);
                        swap(word[j1], word[j2]);
                    }
                }
            }
            for (const auto& word : A) {
                for (int i = 0; i < buckets[word].size(); ++i) {
                    for (int j = 0; j < i; ++j) {
                        union_find.union_set(buckets[word][i], buckets[word][j]);
                    }
                }
            }
        }
        return union_find.size();
    }

private:
    bool isSimilar(const string& a, const string& b) {
        int diff = 0;
        for (int i = 0; i < a.length(); ++i) {
            if (a[i] != b[i]) {
                if (++diff > 2) {
                    return false;
                }
            }
        }
        return diff == 2;
    }

    class UnionFind {
        public:
            UnionFind(const int n) : set_(n), size_(n) {
                iota(set_.begin(), set_.end(), 0);
            }

            int find_set(const int x) {
               if (set_[x] != x) {
                   set_[x] = find_set(set_[x]);  // Path compression.
               }
               return set_[x];
            }

            bool union_set(const int x, const int y) {
                int x_root = find_set(x), y_root = find_set(y);
                if (x_root == y_root) {
                    return false;
                }
                set_[min(x_root, y_root)] = max(x_root, y_root);
                --size_;
                return true;
            }

            int size() const {
                return size_;
            }

        private:
            vector<int> set_;
            int size_;
    };
};
<|endoftext|>