<commit_before>#include <Gui/Viewer/TrackballCameraManipulator.hpp>

#include <Core/Asset/Camera.hpp>
#include <Core/Math/Math.hpp>
#include <Core/Utils/Log.hpp>
#include <Engine/RadiumEngine.hpp>
#include <Engine/Rendering/RenderObject.hpp>
#include <Engine/Rendering/RenderObjectManager.hpp>
#include <Engine/Scene/Light.hpp>
#include <Engine/Scene/SystemDisplay.hpp>
#include <Gui/Utils/KeyMappingManager.hpp>
#include <Gui/Utils/Keyboard.hpp>

#include <Engine/Scene/CameraComponent.hpp>
#include <QApplication>
#include <QMessageBox>
#include <algorithm>
#include <iostream>

namespace Ra {

using Core::Math::Pi;
using namespace Ra::Core::Utils;

namespace Gui {

#define KMA_VALUE( XX ) KeyMappingManager::KeyMappingAction TrackballCameraManipulator::XX;
KeyMappingCamera
#undef KMA_VALUE

void TrackballCameraManipulator::configureKeyMapping_impl() {

    TrackballCameraMapping::setContext(
        KeyMappingManager::getInstance()->getContext( "CameraContext" ) );
    if ( TrackballCameraMapping::getContext().isInvalid() )
    {
        LOG( logINFO )
            << "CameraContext not defined (maybe the configuration file do not contains it)";
        LOG( logERROR ) << "CameraContext all keymapping invalide !";
        return;
    }

#define KMA_VALUE( XX )                                                                          \
    XX = KeyMappingManager::getInstance()->getActionIndex( TrackballCameraMapping::getContext(), \
                                                           #XX );
    KeyMappingCamera
#undef KMA_VALUE
}

TrackballCameraManipulator::TrackballCameraManipulator() : CameraManipulator() {
    resetCamera();
}

TrackballCameraManipulator::TrackballCameraManipulator( const CameraManipulator& other ) :
    CameraManipulator( other ) {
    m_distFromCenter = ( m_referenceFrame.translation() - m_camera->getPosition() ).norm();
    updatePhiTheta();
}

TrackballCameraManipulator::~TrackballCameraManipulator() = default;

void TrackballCameraManipulator::resetCamera() {
    m_camera->setFrame( Core::Transform::Identity() );
    m_camera->setPosition( Core::Vector3( 0_ra, 0_ra, 2_ra ) );
    m_camera->setDirection( Core::Vector3( 0_ra, 0_ra, -1_ra ) );
    m_distFromCenter               = 2.0_ra;
    m_referenceFrame               = Core::Transform::Identity();
    m_referenceFrame.translation() = Core::Vector3::Zero();

    updatePhiTheta();

    ///\todo get rid of these light stuff
    if ( m_light != nullptr )
    {
        m_light->setPosition( m_camera->getPosition() );
        m_light->setDirection( m_camera->getDirection() );
    }
}

void TrackballCameraManipulator::updateCamera() {
    // try to keep target near the previous camera's one, take it at the same distance from
    // camera, but in the new direction.
    m_distFromCenter = ( m_referenceFrame.translation() - m_camera->getPosition() ).norm();
    m_referenceFrame = m_camera->getFrame();
    m_referenceFrame.translation() =
        m_camera->getPosition() + m_distFromCenter * m_camera->getDirection();

    updatePhiTheta();

    if ( m_light != nullptr )
    {
        m_light->setPosition( m_camera->getPosition() );
        m_light->setDirection( m_camera->getDirection() );
    }
}

void TrackballCameraManipulator::setTrackballRadius( Scalar rad ) {
    m_distFromCenter = rad;
    m_referenceFrame.translation() =
        m_camera->getPosition() + m_distFromCenter * m_camera->getDirection();
}

Scalar TrackballCameraManipulator::getTrackballRadius() const {
    return m_distFromCenter;
}

Core::Transform::ConstTranslationPart TrackballCameraManipulator::getTrackballCenter() const {
    return m_referenceFrame.translation();
}

bool TrackballCameraManipulator::handleMousePressEvent( QMouseEvent* event,
                                                        const Qt::MouseButtons& buttons,
                                                        const Qt::KeyboardModifiers& modifiers,
                                                        int key ) {
    m_lastMouseX    = event->pos().x();
    m_lastMouseY    = event->pos().y();
    m_phiDir        = -Core::Math::signNZ( m_theta );
    m_currentAction = KeyMappingManager::getInstance()->getAction(
        TrackballCameraMapping::getContext(), buttons, modifiers, key, false );

    return m_currentAction.isValid();
}

bool TrackballCameraManipulator::handleMouseMoveEvent( QMouseEvent* event,
                                                       const Qt::MouseButtons& /*buttons*/,
                                                       const Qt::KeyboardModifiers& /* modifiers*/,
                                                       int /*key*/ ) {

    Scalar dx = ( event->pos().x() - m_lastMouseX ) / m_camera->getWidth();
    Scalar dy = ( event->pos().y() - m_lastMouseY ) / m_camera->getHeight();

    if ( event->modifiers().testFlag( Qt::AltModifier ) ) { m_quickCameraModifier = 10.0_ra; }
    else
    { m_quickCameraModifier = 2.0_ra; }

    if ( m_currentAction == TRACKBALLCAMERA_ROTATE )
        handleCameraRotate( dx, dy );
    else if ( m_currentAction == TRACKBALLCAMERA_PAN )
        handleCameraPan( dx, dy );
    else if ( m_currentAction == TRACKBALLCAMERA_ZOOM )
        handleCameraZoom( dx, dy );
    else if ( m_currentAction == TRACKBALLCAMERA_MOVE_FORWARD )
        handleCameraMoveForward( dx, dy );

    m_lastMouseX = event->pos().x();
    m_lastMouseY = event->pos().y();

    if ( m_light != nullptr )
    {
        m_light->setPosition( m_camera->getPosition() );
        m_light->setDirection( m_camera->getDirection() );
    }

    return m_currentAction.isValid();
}

bool TrackballCameraManipulator::handleMouseReleaseEvent( QMouseEvent* /*event*/ ) {
    m_currentAction       = KeyMappingManager::KeyMappingAction::Invalid();
    m_quickCameraModifier = 1.0_ra;
    return true;
}

bool TrackballCameraManipulator::handleWheelEvent( QWheelEvent* event,
                                                   const Qt::MouseButtons& buttons,
                                                   const Qt::KeyboardModifiers& modifiers,
                                                   int key

) {
    auto action = KeyMappingManager::getInstance()->getAction(
        TrackballCameraMapping::getContext(), buttons, modifiers, key, true );

    if ( action == TRACKBALLCAMERA_MOVE_FORWARD )
    {
        handleCameraMoveForward(
            ( event->angleDelta().y() * 0.01_ra + event->angleDelta().x() * 0.01_ra ) *
            m_wheelSpeedModifier );
    }
    else if ( action == TRACKBALLCAMERA_ZOOM )
    {
        handleCameraZoom(
            ( event->angleDelta().y() * 0.01_ra + event->angleDelta().x() * 0.01_ra ) *
            m_wheelSpeedModifier );
    }

    if ( m_light != nullptr )
    {
        m_light->setPosition( m_camera->getPosition() );
        m_light->setDirection( m_camera->getDirection() );
    }

    return action.isValid();
}

bool TrackballCameraManipulator::handleKeyPressEvent(
    QKeyEvent* /*event*/,
    const KeyMappingManager::KeyMappingAction& action ) {

    using ProjType = Ra::Core::Asset::Camera::ProjType;
    if ( action == TRACKBALLCAMERA_PROJ_MODE )
    {
        m_camera->setType( m_camera->getType() == ProjType::ORTHOGRAPHIC ? ProjType::PERSPECTIVE
                                                                         : ProjType::ORTHOGRAPHIC );
        return true;
    }

    return false;
}

bool TrackballCameraManipulator::handleKeyReleaseEvent( QKeyEvent* /*e*/ ) {
    return false;
}

void TrackballCameraManipulator::setCameraPosition( const Core::Vector3& position ) {
    if ( position == m_referenceFrame.translation() )
    {
        QMessageBox::warning( nullptr, "Error", "Position cannot be set to target point" );
        return;
    }
    m_camera->setPosition( position );
    m_referenceFrame.translation() = position + m_distFromCenter * m_camera->getDirection();

    updatePhiTheta();

    if ( m_light != nullptr )
    {
        m_light->setPosition( m_camera->getPosition() );
        m_light->setDirection( m_camera->getDirection() );
    }
}

void TrackballCameraManipulator::setCameraTarget( const Core::Vector3& target ) {
    if ( m_camera->getPosition() == m_referenceFrame.translation() )
    {
        QMessageBox::warning( nullptr, "Error", "Target cannot be set to current camera position" );
        return;
    }

    m_referenceFrame.translation() = target;

    m_camera->setDirection( ( target - m_camera->getPosition() ).normalized() );
    m_distFromCenter = ( target - m_camera->getPosition() ).norm();
    updatePhiTheta();

    if ( m_light != nullptr ) { m_light->setDirection( m_camera->getDirection() ); }
}

void TrackballCameraManipulator::fitScene( const Core::Aabb& aabb ) {

    Scalar f = m_camera->getFOV();
    Scalar a = m_camera->getAspect();

    const Scalar r = ( aabb.max() - aabb.min() ).norm() / 2_ra;
    const Scalar x = r / std::sin( f / 2_ra );
    const Scalar y = r / std::sin( f * a / 2_ra );
    Scalar d       = std::max( std::max( x, y ), 0.001_ra );

    m_camera->setFrame( Core::Transform::Identity() );
    Core::Vector3 camPos {aabb.center().x(), aabb.center().y(), aabb.center().z() + d};
    m_camera->setPosition( camPos );
    Core::Vector3 camDir {aabb.center() - camPos};
    m_distFromCenter = camDir.norm();
    m_camera->setDirection( camDir / m_distFromCenter );

    // no ref camera here, use wolrd frame to align with
    m_referenceFrame.setIdentity();
    m_referenceFrame.translation() = aabb.center();

    updatePhiTheta();

    if ( m_light != nullptr )
    {
        m_light->setPosition( m_camera->getPosition() );
        m_light->setDirection( m_camera->getDirection() );
    }
}

void TrackballCameraManipulator::handleCameraRotate( Scalar dx, Scalar dy ) {
    Scalar dphi   = m_phiDir * dx * m_cameraSensitivity * m_quickCameraModifier;
    Scalar dtheta = -dy * m_cameraSensitivity * m_quickCameraModifier;

    Scalar phi   = m_phi + dphi;
    Scalar theta = m_theta + dtheta;
    Core::Vector3 dir {std::sin( phi ) * std::sin( theta ),
                       std::cos( theta ),
                       std::cos( phi ) * std::sin( theta )};

    Core::Vector3 right {-dir[2], 0, dir[0]};
    right.normalize();
    if ( ( m_referenceFrame.linear().inverse() * m_camera->getRightVector() ).dot( right ) < 0 )
        right = -right;

    Core::Vector3 up = dir.cross( right ).normalized();

    dir   = m_referenceFrame.linear() * dir;
    right = m_referenceFrame.linear() * right;
    up    = m_referenceFrame.linear() * up;

    Core::Matrix3 m;
    // clang-format off
    m << right[0], up[0], dir[0], //
         right[1], up[1], dir[1], //
         right[2], up[2], dir[2]; //
    // clang-format on
    Core::Transform t;

    t.setIdentity();
    t.linear()        = m;
    Core::Vector3 pos = m_referenceFrame.translation() + m_distFromCenter * dir;
    t.translation()   = pos;
    m_camera->setFrame( t );

    m_phi   = phi;
    m_theta = theta;

    clampThetaPhi();
}

void TrackballCameraManipulator::handleCameraPan( Scalar dx, Scalar dy ) {
    Scalar x = dx * m_cameraSensitivity * m_quickCameraModifier * m_distFromCenter * 0.1_ra;
    Scalar y = dy * m_cameraSensitivity * m_quickCameraModifier * m_distFromCenter * 0.1_ra;
    // Move camera and trackball center, keep the distance to the center
    Core::Vector3 R = -m_camera->getRightVector();
    Core::Vector3 U = m_camera->getUpVector();

    Core::Transform T( Core::Transform::Identity() );
    Core::Vector3 t = x * R + y * U;
    T.translate( t );

    m_camera->applyTransform( T );
    m_referenceFrame.translation() += t;
}

void TrackballCameraManipulator::handleCameraMoveForward( Scalar dx, Scalar dy ) {
    handleCameraMoveForward( Ra::Core::Math::sign( dy ) * Ra::Core::Vector2 {dx, dy}.norm() );
}

void TrackballCameraManipulator::handleCameraMoveForward( Scalar z ) {

    Scalar moveFactor = z * m_distFromCenter * m_cameraSensitivity * m_quickCameraModifier;

    Core::Transform T( Core::Transform::Identity() );
    T.translate( moveFactor * m_camera->getDirection() );

    m_camera->applyTransform( T );

    m_distFromCenter = ( m_referenceFrame.translation() - m_camera->getPosition() ).norm();
}

void TrackballCameraManipulator::handleCameraZoom( Scalar dx, Scalar dy ) {
    handleCameraZoom( Ra::Core::Math::sign( dy ) * Ra::Core::Vector2 {dx, dy}.norm() );
}

void TrackballCameraManipulator::handleCameraZoom( Scalar z ) {
    const Scalar epsIn  = 0.1_ra;
    const Scalar epsOut = 3.1_ra;
    Scalar zoom =
        std::clamp( m_camera->getZoomFactor() - z * m_cameraSensitivity * m_quickCameraModifier,
                    epsIn,
                    epsOut );
    m_camera->setZoomFactor( zoom );
}

void TrackballCameraManipulator::updatePhiTheta() {
    using Core::Math::areApproxEqual;
    const Core::Vector3 R = m_referenceFrame.linear().inverse() * ( -m_camera->getDirection() );

    m_theta = std::acos( R.y() );

    // unlikely to have z and x to 0, unless direction is perfectly aligned with
    // m_referenceFrame.z() in this case phi is given by the relative orientation of right/up in the
    // z/x plane of m_reference frame.
    if ( UNLIKELY( areApproxEqual( R.z(), 0_ra ) && areApproxEqual( R.x(), 0_ra ) ) )
    {
        Scalar fx = m_referenceFrame.matrix().block<3, 1>( 0, 2 ).dot( m_camera->getRightVector() );
        Scalar fy = m_referenceFrame.matrix().block<3, 1>( 0, 2 ).dot( m_camera->getUpVector() );
        m_phi     = std::atan2( fx, fy );
    }
    else
    { m_phi = std::atan2( R.x(), R.z() ); }

    // no need to clamp, atan2 is by def \in [-pi,pi]
    // acos in [0, pi]
    // clampThetaPhi();
    CORE_ASSERT( std::isfinite( m_theta ) && std::isfinite( m_phi ), "Error in trackball camera" );
}

void TrackballCameraManipulator::clampThetaPhi() {
    // Keep phi between 0 and 2pi
    if ( m_phi < 0_ra ) { m_phi += 2_ra * Pi; }
    // Keep theta in [-pi, pi] (instead of [0,pi]) to allows scene flip
    if ( m_theta < -Pi ) { m_theta += 2_ra * Pi; }
    if ( m_theta > Pi ) { m_theta -= 2_ra * Pi; }
}

bool TrackballCameraManipulator::checkIntegrity( const std::string& mess ) const {
    Core::Vector3 c = m_camera->getPosition() + m_distFromCenter * m_camera->getDirection();
    Scalar d        = ( m_referenceFrame.translation() - c ).norm();
    if ( d > 0.001_ra )
    {
        LOG( logWARNING ) << "TrackballCameraManipulator Integrity problem : " << mess;
        LOG( logWARNING ) << "\t Position  " << m_camera->getPosition().transpose();
        LOG( logWARNING ) << "\t Ref       "
                          << ( m_referenceFrame.translation() +
                               m_distFromCenter * ( -m_camera->getDirection() ) )
                                 .transpose();
        LOG( logWARNING ) << "\t Direction " << m_camera->getDirection().transpose();
        LOG( logWARNING ) << "\t Center    " << c.transpose();
        LOG( logWARNING ) << "\t Distance  " << d;
        LOG( logWARNING ) << "\t angles    " << m_phi << " " << m_theta;
    }
    return d < 0.001_ra;
}

} // namespace Gui
} // namespace Ra
<commit_msg>[gui] unbound camera zoom for ortho.<commit_after>#include <Gui/Viewer/TrackballCameraManipulator.hpp>

#include <Core/Asset/Camera.hpp>
#include <Core/Math/Math.hpp>
#include <Core/Utils/Log.hpp>
#include <Engine/RadiumEngine.hpp>
#include <Engine/Rendering/RenderObject.hpp>
#include <Engine/Rendering/RenderObjectManager.hpp>
#include <Engine/Scene/Light.hpp>
#include <Engine/Scene/SystemDisplay.hpp>
#include <Gui/Utils/KeyMappingManager.hpp>
#include <Gui/Utils/Keyboard.hpp>

#include <Engine/Scene/CameraComponent.hpp>
#include <QApplication>
#include <QMessageBox>
#include <algorithm>
#include <iostream>

namespace Ra {

using Core::Math::Pi;
using namespace Ra::Core::Utils;

namespace Gui {

#define KMA_VALUE( XX ) KeyMappingManager::KeyMappingAction TrackballCameraManipulator::XX;
KeyMappingCamera
#undef KMA_VALUE

void TrackballCameraManipulator::configureKeyMapping_impl() {

    TrackballCameraMapping::setContext(
        KeyMappingManager::getInstance()->getContext( "CameraContext" ) );
    if ( TrackballCameraMapping::getContext().isInvalid() )
    {
        LOG( logINFO )
            << "CameraContext not defined (maybe the configuration file do not contains it)";
        LOG( logERROR ) << "CameraContext all keymapping invalide !";
        return;
    }

#define KMA_VALUE( XX )                                                                          \
    XX = KeyMappingManager::getInstance()->getActionIndex( TrackballCameraMapping::getContext(), \
                                                           #XX );
    KeyMappingCamera
#undef KMA_VALUE
}

TrackballCameraManipulator::TrackballCameraManipulator() : CameraManipulator() {
    resetCamera();
}

TrackballCameraManipulator::TrackballCameraManipulator( const CameraManipulator& other ) :
    CameraManipulator( other ) {
    m_distFromCenter = ( m_referenceFrame.translation() - m_camera->getPosition() ).norm();
    updatePhiTheta();
}

TrackballCameraManipulator::~TrackballCameraManipulator() = default;

void TrackballCameraManipulator::resetCamera() {
    m_camera->setFrame( Core::Transform::Identity() );
    m_camera->setPosition( Core::Vector3( 0_ra, 0_ra, 2_ra ) );
    m_camera->setDirection( Core::Vector3( 0_ra, 0_ra, -1_ra ) );
    m_distFromCenter               = 2.0_ra;
    m_referenceFrame               = Core::Transform::Identity();
    m_referenceFrame.translation() = Core::Vector3::Zero();

    updatePhiTheta();

    ///\todo get rid of these light stuff
    if ( m_light != nullptr )
    {
        m_light->setPosition( m_camera->getPosition() );
        m_light->setDirection( m_camera->getDirection() );
    }
}

void TrackballCameraManipulator::updateCamera() {
    // try to keep target near the previous camera's one, take it at the same distance from
    // camera, but in the new direction.
    m_distFromCenter = ( m_referenceFrame.translation() - m_camera->getPosition() ).norm();
    m_referenceFrame = m_camera->getFrame();
    m_referenceFrame.translation() =
        m_camera->getPosition() + m_distFromCenter * m_camera->getDirection();

    updatePhiTheta();

    if ( m_light != nullptr )
    {
        m_light->setPosition( m_camera->getPosition() );
        m_light->setDirection( m_camera->getDirection() );
    }
}

void TrackballCameraManipulator::setTrackballRadius( Scalar rad ) {
    m_distFromCenter = rad;
    m_referenceFrame.translation() =
        m_camera->getPosition() + m_distFromCenter * m_camera->getDirection();
}

Scalar TrackballCameraManipulator::getTrackballRadius() const {
    return m_distFromCenter;
}

Core::Transform::ConstTranslationPart TrackballCameraManipulator::getTrackballCenter() const {
    return m_referenceFrame.translation();
}

bool TrackballCameraManipulator::handleMousePressEvent( QMouseEvent* event,
                                                        const Qt::MouseButtons& buttons,
                                                        const Qt::KeyboardModifiers& modifiers,
                                                        int key ) {
    m_lastMouseX    = event->pos().x();
    m_lastMouseY    = event->pos().y();
    m_phiDir        = -Core::Math::signNZ( m_theta );
    m_currentAction = KeyMappingManager::getInstance()->getAction(
        TrackballCameraMapping::getContext(), buttons, modifiers, key, false );

    return m_currentAction.isValid();
}

bool TrackballCameraManipulator::handleMouseMoveEvent( QMouseEvent* event,
                                                       const Qt::MouseButtons& /*buttons*/,
                                                       const Qt::KeyboardModifiers& /* modifiers*/,
                                                       int /*key*/ ) {

    Scalar dx = ( event->pos().x() - m_lastMouseX ) / m_camera->getWidth();
    Scalar dy = ( event->pos().y() - m_lastMouseY ) / m_camera->getHeight();

    if ( event->modifiers().testFlag( Qt::AltModifier ) ) { m_quickCameraModifier = 10.0_ra; }
    else
    { m_quickCameraModifier = 2.0_ra; }

    if ( m_currentAction == TRACKBALLCAMERA_ROTATE )
        handleCameraRotate( dx, dy );
    else if ( m_currentAction == TRACKBALLCAMERA_PAN )
        handleCameraPan( dx, dy );
    else if ( m_currentAction == TRACKBALLCAMERA_ZOOM )
        handleCameraZoom( dx, dy );
    else if ( m_currentAction == TRACKBALLCAMERA_MOVE_FORWARD )
        handleCameraMoveForward( dx, dy );

    m_lastMouseX = event->pos().x();
    m_lastMouseY = event->pos().y();

    if ( m_light != nullptr )
    {
        m_light->setPosition( m_camera->getPosition() );
        m_light->setDirection( m_camera->getDirection() );
    }

    return m_currentAction.isValid();
}

bool TrackballCameraManipulator::handleMouseReleaseEvent( QMouseEvent* /*event*/ ) {
    m_currentAction       = KeyMappingManager::KeyMappingAction::Invalid();
    m_quickCameraModifier = 1.0_ra;
    return true;
}

bool TrackballCameraManipulator::handleWheelEvent( QWheelEvent* event,
                                                   const Qt::MouseButtons& buttons,
                                                   const Qt::KeyboardModifiers& modifiers,
                                                   int key

) {
    auto action = KeyMappingManager::getInstance()->getAction(
        TrackballCameraMapping::getContext(), buttons, modifiers, key, true );

    if ( action == TRACKBALLCAMERA_MOVE_FORWARD )
    {
        handleCameraMoveForward(
            ( event->angleDelta().y() * 0.01_ra + event->angleDelta().x() * 0.01_ra ) *
            m_wheelSpeedModifier );
    }
    else if ( action == TRACKBALLCAMERA_ZOOM )
    {
        handleCameraZoom(
            ( event->angleDelta().y() * 0.01_ra + event->angleDelta().x() * 0.01_ra ) *
            m_wheelSpeedModifier );
    }

    if ( m_light != nullptr )
    {
        m_light->setPosition( m_camera->getPosition() );
        m_light->setDirection( m_camera->getDirection() );
    }

    return action.isValid();
}

bool TrackballCameraManipulator::handleKeyPressEvent(
    QKeyEvent* /*event*/,
    const KeyMappingManager::KeyMappingAction& action ) {

    using ProjType = Ra::Core::Asset::Camera::ProjType;
    if ( action == TRACKBALLCAMERA_PROJ_MODE )
    {
        m_camera->setType( m_camera->getType() == ProjType::ORTHOGRAPHIC ? ProjType::PERSPECTIVE
                                                                         : ProjType::ORTHOGRAPHIC );
        return true;
    }

    return false;
}

bool TrackballCameraManipulator::handleKeyReleaseEvent( QKeyEvent* /*e*/ ) {
    return false;
}

void TrackballCameraManipulator::setCameraPosition( const Core::Vector3& position ) {
    if ( position == m_referenceFrame.translation() )
    {
        QMessageBox::warning( nullptr, "Error", "Position cannot be set to target point" );
        return;
    }
    m_camera->setPosition( position );
    m_referenceFrame.translation() = position + m_distFromCenter * m_camera->getDirection();

    updatePhiTheta();

    if ( m_light != nullptr )
    {
        m_light->setPosition( m_camera->getPosition() );
        m_light->setDirection( m_camera->getDirection() );
    }
}

void TrackballCameraManipulator::setCameraTarget( const Core::Vector3& target ) {
    if ( m_camera->getPosition() == m_referenceFrame.translation() )
    {
        QMessageBox::warning( nullptr, "Error", "Target cannot be set to current camera position" );
        return;
    }

    m_referenceFrame.translation() = target;

    m_camera->setDirection( ( target - m_camera->getPosition() ).normalized() );
    m_distFromCenter = ( target - m_camera->getPosition() ).norm();
    updatePhiTheta();

    if ( m_light != nullptr ) { m_light->setDirection( m_camera->getDirection() ); }
}

void TrackballCameraManipulator::fitScene( const Core::Aabb& aabb ) {

    Scalar f = m_camera->getFOV();
    Scalar a = m_camera->getAspect();

    const Scalar r = ( aabb.max() - aabb.min() ).norm() / 2_ra;
    const Scalar x = r / std::sin( f / 2_ra );
    const Scalar y = r / std::sin( f * a / 2_ra );
    Scalar d       = std::max( std::max( x, y ), 0.001_ra );

    m_camera->setFrame( Core::Transform::Identity() );
    Core::Vector3 camPos {aabb.center().x(), aabb.center().y(), aabb.center().z() + d};
    m_camera->setPosition( camPos );
    Core::Vector3 camDir {aabb.center() - camPos};
    m_distFromCenter = camDir.norm();
    m_camera->setDirection( camDir / m_distFromCenter );

    // no ref camera here, use wolrd frame to align with
    m_referenceFrame.setIdentity();
    m_referenceFrame.translation() = aabb.center();

    updatePhiTheta();

    if ( m_light != nullptr )
    {
        m_light->setPosition( m_camera->getPosition() );
        m_light->setDirection( m_camera->getDirection() );
    }
}

void TrackballCameraManipulator::handleCameraRotate( Scalar dx, Scalar dy ) {
    Scalar dphi   = m_phiDir * dx * m_cameraSensitivity * m_quickCameraModifier;
    Scalar dtheta = -dy * m_cameraSensitivity * m_quickCameraModifier;

    Scalar phi   = m_phi + dphi;
    Scalar theta = m_theta + dtheta;
    Core::Vector3 dir {std::sin( phi ) * std::sin( theta ),
                       std::cos( theta ),
                       std::cos( phi ) * std::sin( theta )};

    Core::Vector3 right {-dir[2], 0, dir[0]};
    right.normalize();
    if ( ( m_referenceFrame.linear().inverse() * m_camera->getRightVector() ).dot( right ) < 0 )
        right = -right;

    Core::Vector3 up = dir.cross( right ).normalized();

    dir   = m_referenceFrame.linear() * dir;
    right = m_referenceFrame.linear() * right;
    up    = m_referenceFrame.linear() * up;

    Core::Matrix3 m;
    // clang-format off
    m << right[0], up[0], dir[0], //
         right[1], up[1], dir[1], //
         right[2], up[2], dir[2]; //
    // clang-format on
    Core::Transform t;

    t.setIdentity();
    t.linear()        = m;
    Core::Vector3 pos = m_referenceFrame.translation() + m_distFromCenter * dir;
    t.translation()   = pos;
    m_camera->setFrame( t );

    m_phi   = phi;
    m_theta = theta;

    clampThetaPhi();
}

void TrackballCameraManipulator::handleCameraPan( Scalar dx, Scalar dy ) {
    Scalar x = dx * m_cameraSensitivity * m_quickCameraModifier * m_distFromCenter * 0.1_ra;
    Scalar y = dy * m_cameraSensitivity * m_quickCameraModifier * m_distFromCenter * 0.1_ra;
    // Move camera and trackball center, keep the distance to the center
    Core::Vector3 R = -m_camera->getRightVector();
    Core::Vector3 U = m_camera->getUpVector();

    Core::Transform T( Core::Transform::Identity() );
    Core::Vector3 t = x * R + y * U;
    T.translate( t );

    m_camera->applyTransform( T );
    m_referenceFrame.translation() += t;
}

void TrackballCameraManipulator::handleCameraMoveForward( Scalar dx, Scalar dy ) {
    handleCameraMoveForward( Ra::Core::Math::sign( dy ) * Ra::Core::Vector2 {dx, dy}.norm() );
}

void TrackballCameraManipulator::handleCameraMoveForward( Scalar z ) {

    Scalar moveFactor = z * m_distFromCenter * m_cameraSensitivity * m_quickCameraModifier;

    Core::Transform T( Core::Transform::Identity() );
    T.translate( moveFactor * m_camera->getDirection() );

    m_camera->applyTransform( T );

    m_distFromCenter = ( m_referenceFrame.translation() - m_camera->getPosition() ).norm();
}

void TrackballCameraManipulator::handleCameraZoom( Scalar dx, Scalar dy ) {
    handleCameraZoom( Ra::Core::Math::sign( dy ) * Ra::Core::Vector2 {dx, dy}.norm() );
}

void TrackballCameraManipulator::handleCameraZoom( Scalar z ) {
    Scalar zoom = m_camera->getZoomFactor() - z * m_cameraSensitivity * m_quickCameraModifier;
    m_camera->setZoomFactor( zoom );
}

void TrackballCameraManipulator::updatePhiTheta() {
    using Core::Math::areApproxEqual;
    const Core::Vector3 R = m_referenceFrame.linear().inverse() * ( -m_camera->getDirection() );

    m_theta = std::acos( R.y() );

    // unlikely to have z and x to 0, unless direction is perfectly aligned with
    // m_referenceFrame.z() in this case phi is given by the relative orientation of right/up in the
    // z/x plane of m_reference frame.
    if ( UNLIKELY( areApproxEqual( R.z(), 0_ra ) && areApproxEqual( R.x(), 0_ra ) ) )
    {
        Scalar fx = m_referenceFrame.matrix().block<3, 1>( 0, 2 ).dot( m_camera->getRightVector() );
        Scalar fy = m_referenceFrame.matrix().block<3, 1>( 0, 2 ).dot( m_camera->getUpVector() );
        m_phi     = std::atan2( fx, fy );
    }
    else
    { m_phi = std::atan2( R.x(), R.z() ); }

    // no need to clamp, atan2 is by def \in [-pi,pi]
    // acos in [0, pi]
    // clampThetaPhi();
    CORE_ASSERT( std::isfinite( m_theta ) && std::isfinite( m_phi ), "Error in trackball camera" );
}

void TrackballCameraManipulator::clampThetaPhi() {
    // Keep phi between 0 and 2pi
    if ( m_phi < 0_ra ) { m_phi += 2_ra * Pi; }
    // Keep theta in [-pi, pi] (instead of [0,pi]) to allows scene flip
    if ( m_theta < -Pi ) { m_theta += 2_ra * Pi; }
    if ( m_theta > Pi ) { m_theta -= 2_ra * Pi; }
}

bool TrackballCameraManipulator::checkIntegrity( const std::string& mess ) const {
    Core::Vector3 c = m_camera->getPosition() + m_distFromCenter * m_camera->getDirection();
    Scalar d        = ( m_referenceFrame.translation() - c ).norm();
    if ( d > 0.001_ra )
    {
        LOG( logWARNING ) << "TrackballCameraManipulator Integrity problem : " << mess;
        LOG( logWARNING ) << "\t Position  " << m_camera->getPosition().transpose();
        LOG( logWARNING ) << "\t Ref       "
                          << ( m_referenceFrame.translation() +
                               m_distFromCenter * ( -m_camera->getDirection() ) )
                                 .transpose();
        LOG( logWARNING ) << "\t Direction " << m_camera->getDirection().transpose();
        LOG( logWARNING ) << "\t Center    " << c.transpose();
        LOG( logWARNING ) << "\t Distance  " << d;
        LOG( logWARNING ) << "\t angles    " << m_phi << " " << m_theta;
    }
    return d < 0.001_ra;
}

} // namespace Gui
} // namespace Ra
<|endoftext|>


<commit_before>/*****************************************************************************
 * interface_widgets.hpp : Custom widgets for the main interface
 ****************************************************************************
 * Copyright (C) 2006 the VideoLAN team
 * $Id$
 *
 * Authors: Clément Stenac <zorglub@videolan.org>
 *          Jean-Baptiste Kempf <jb@videolan.org>
 *          Rafaël Carré <funman@videolanorg>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifndef _INTFWIDGETS_H_
#define _INTFWIDGETS_H_

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <vlc_common.h>
#include <vlc_interface.h>
#include <vlc_aout.h>

#include "qt4.hpp"
#include "main_interface.hpp"
#include "input_manager.hpp"

#include <QWidget>
#include <QFrame>

#define VOLUME_MAX 200

/* on WIN32 hide() for fullscreen controller doesnt work, so it have to be
   done by trick with setting the opacity of window */
#ifdef WIN32
    #define WIN32TRICK
#endif

/* to trying transparency with fullscreen controller on windows enable that */
#define HAVE_TRANSPARENCY 0
/* it can be enabled on-non windows systems,
   but it will be transparent only with composite manager */
#ifndef WIN32
    #define HAVE_TRANSPARENCY 1
#endif

/* Default value of opacity for FS controller */
#define DEFAULT_OPACITY 0.75

class ResizeEvent;
class QPalette;
class QPixmap;
class QLabel;
class QHBoxLayout;

/******************** Video Widget ****************/
class VideoWidget : public QFrame
{
    Q_OBJECT
friend class MainInterface;

public:
    VideoWidget( intf_thread_t * );
    virtual ~VideoWidget();

    void *request( vout_thread_t *, int *, int *,
                   unsigned int *, unsigned int * );
    void  release( void * );
    int   control( void *, int, va_list );

    virtual QSize sizeHint() const;
private:
    intf_thread_t *p_intf;
    vout_thread_t *p_vout;

    vlc_mutex_t lock;
    QSize videoSize;

signals:
    void askVideoWidgetToShow();
    //void askResize();

public slots:
    void SetSizing( unsigned int, unsigned int );
};

/******************** Background Widget ****************/
class BackgroundWidget : public QWidget
{
    Q_OBJECT
public:
    BackgroundWidget( intf_thread_t * );
    virtual ~BackgroundWidget();

private:
    QPalette plt;
    QLabel *label;
    virtual void contextMenuEvent( QContextMenuEvent *event );
    intf_thread_t *p_intf;
    virtual void resizeEvent( QResizeEvent * event );
public slots:
    void toggle(){ TOGGLEV( this ); }
    void updateArt( QString );
};

class VisualSelector : public QFrame
{
    Q_OBJECT
public:
    VisualSelector( intf_thread_t *);
    virtual ~VisualSelector();
private:
    intf_thread_t *p_intf;
    QLabel *current;
private slots:
    void prev();
    void next();
};

/* Advanced Button Bar */
class QPushButton;
class AdvControlsWidget : public QFrame
{
    Q_OBJECT
public:
    AdvControlsWidget( intf_thread_t *);
    virtual ~AdvControlsWidget();

    void enableInput( bool );
    void enableVideo( bool );

private:
    intf_thread_t *p_intf;
    QPushButton *recordButton, *ABButton;
    QPushButton *snapshotButton, *frameButton;

    mtime_t timeA, timeB;

private slots:
    void snapshot();
#if 0
    void frame();
#endif
    void fromAtoB();
    void record();
    void AtoBLoop( float, int, int );
};

/* Button Bar */
class InputSlider;
class QSlider;
class QGridLayout;
class VolumeClickHandler;
class SoundSlider;
class QAbstractSlider;
class QToolButton;

class ControlsWidget : public QFrame
{
    Q_OBJECT
public:
    /* p_intf, advanced control visible or not, blingbling or not */
    ControlsWidget( intf_thread_t *_p_i, MainInterface *_p_mi,
        bool b_advControls, bool b_shiny, bool b_fsCreation = false);
    virtual ~ControlsWidget();

    QPushButton *playlistButton;
    void setStatus( int );
    void enableInput( bool );
    void enableVideo( bool );
public slots:
    void setNavigation( int );
protected:
    friend class MainInterface;
    friend class VolumeClickHandler;
protected:
    intf_thread_t       *p_intf;
    QWidget             *discFrame;
    QWidget             *telexFrame;
    QGridLayout         *controlLayout;
    InputSlider         *slider;
    QPushButton         *prevSectionButton, *nextSectionButton, *menuButton;
    QPushButton         *playButton, *fullscreenButton, *extSettingsButton;
    QToolButton         *slowerButton, *fasterButton;
    QHBoxLayout         *controlButLayout;
    AdvControlsWidget   *advControls;
    QLabel              *volMuteLabel;
    QAbstractSlider     *volumeSlider;
    VolumeClickHandler  *hVolLabel;

    bool                 b_advancedVisible;
protected slots:
    void play();
    void stop();
    void prev();
    void next();
    void updateVolume( int );
    void updateVolume( void );
    void updateInput();
    void fullscreen();
    void extSettings();
    void faster();
    void slower();
    void toggleAdvanced();
signals:
    void advancedControlsToggled( bool );
};

/***********************************
 * Fullscreen controller
 ***********************************/

static int showFullscreenControllCallback(vlc_object_t *vlc_object, const char *variable, vlc_value_t old_val,
    vlc_value_t new_val, void *data);

static int regMouseMoveCallback(vlc_object_t *vlc_object, const char *variable, vlc_value_t old_val,
    vlc_value_t new_val, void *data);

class FullscreenControllerWidget : public ControlsWidget
{
    Q_OBJECT
public:
    FullscreenControllerWidget( intf_thread_t *, MainInterface*, bool, bool );
    virtual ~FullscreenControllerWidget();

    void SetHideTimeout( int hideTimeout ) { i_hideTimeout = hideTimeout; }
    void regFullscreenCallback( vout_thread_t *p_vout );

    bool isFSCHidden();

public slots:
    void unregFullscreenCallback();

protected:
    friend class MainInterface;
    friend class VolumeClickHandler;

    virtual void mouseMoveEvent( QMouseEvent *event );
    virtual void mousePressEvent( QMouseEvent *event );
    virtual void enterEvent( QEvent *event );
    virtual void leaveEvent( QEvent *event );
    virtual void keyPressEvent( QKeyEvent *event );

private slots:
    void hideFSControllerWidget();
    void slowHideFSC();

private:
    QTimer *p_hideTimer;

#if HAVE_TRANSPARENCY
    QTimer *p_slowHideTimer;
#endif

    int i_lastPosX;
    int i_lastPosY;
    int i_hideTimeout;  /* FSC hiding timeout, same as mouse hiding timeout */
    bool b_mouseIsOver;

#ifdef WIN32TRICK
    bool fscHidden;
#endif

    virtual void customEvent( QEvent *event );
};

class VolumeClickHandler : public QObject
{
public:
    VolumeClickHandler( intf_thread_t *_p_intf, ControlsWidget *_m ) :QObject(_m)
    {m = _m; p_intf = _p_intf; }
    virtual ~VolumeClickHandler() {};
    bool eventFilter( QObject *obj, QEvent *e )
    {
        if (e->type() == QEvent::MouseButtonPress  )
        {
            aout_VolumeMute( p_intf, NULL );
            audio_volume_t i_volume;
            aout_VolumeGet( p_intf, &i_volume );
            m->updateVolume( i_volume *  VOLUME_MAX / (AOUT_VOLUME_MAX/2) );
            return true;
        }
        return false;
    }
private:
    ControlsWidget *m;
    intf_thread_t *p_intf;
};

#include <QLabel>
#include <QMouseEvent>
class TimeLabel : public QLabel
{
    Q_OBJECT
    void mousePressEvent( QMouseEvent *event )
    {
        emit timeLabelClicked();
    }
    void mouseDoubleClickEvent( QMouseEvent *event )
    {
        emit timeLabelDoubleClicked();
    }
signals:
    void timeLabelClicked();
    void timeLabelDoubleClicked();
};

class SpeedLabel : public QLabel
{
    Q_OBJECT
public:
    SpeedLabel( intf_thread_t *_p_intf, const QString text ): QLabel( text)
    { p_intf = _p_intf; }

protected:
    virtual void mouseDoubleClickEvent ( QMouseEvent * event )
    {
        THEMIM->getIM()->setRate( INPUT_RATE_DEFAULT );
    }
private:
    intf_thread_t *p_intf;
};

/******************** Speed Control Widgets ****************/
class SpeedControlWidget : public QFrame
{
    Q_OBJECT
public:
    SpeedControlWidget( intf_thread_t *);
    virtual ~SpeedControlWidget();
    void updateControls( int );
private:
    intf_thread_t *p_intf;
    QSlider *speedSlider;
public slots:
    void setEnable( bool );
private slots:
    void updateRate( int );
    void resetRate();
};

#endif
<commit_msg>Warning killing.<commit_after>/*****************************************************************************
 * interface_widgets.hpp : Custom widgets for the main interface
 ****************************************************************************
 * Copyright (C) 2006 the VideoLAN team
 * $Id$
 *
 * Authors: Clément Stenac <zorglub@videolan.org>
 *          Jean-Baptiste Kempf <jb@videolan.org>
 *          Rafaël Carré <funman@videolanorg>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifndef _INTFWIDGETS_H_
#define _INTFWIDGETS_H_

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <vlc_common.h>
#include <vlc_interface.h>
#include <vlc_aout.h>

#include "qt4.hpp"
#include "main_interface.hpp"
#include "input_manager.hpp"

#include <QWidget>
#include <QFrame>

#define VOLUME_MAX 200

/* on WIN32 hide() for fullscreen controller doesnt work, so it have to be
   done by trick with setting the opacity of window */
#ifdef WIN32
    #define WIN32TRICK
#endif

/* to trying transparency with fullscreen controller on windows enable that */
/* it can be enabled on-non windows systems,
   but it will be transparent only with composite manager */
#ifndef WIN32
    #define HAVE_TRANSPARENCY 1
#else
    #define HAVE_TRANSPARENCY 0
#endif

/* Default value of opacity for FS controller */
#define DEFAULT_OPACITY 0.75

class ResizeEvent;
class QPalette;
class QPixmap;
class QLabel;
class QHBoxLayout;

/******************** Video Widget ****************/
class VideoWidget : public QFrame
{
    Q_OBJECT
friend class MainInterface;

public:
    VideoWidget( intf_thread_t * );
    virtual ~VideoWidget();

    void *request( vout_thread_t *, int *, int *,
                   unsigned int *, unsigned int * );
    void  release( void * );
    int   control( void *, int, va_list );

    virtual QSize sizeHint() const;
private:
    intf_thread_t *p_intf;
    vout_thread_t *p_vout;

    vlc_mutex_t lock;
    QSize videoSize;

signals:
    void askVideoWidgetToShow();
    //void askResize();

public slots:
    void SetSizing( unsigned int, unsigned int );
};

/******************** Background Widget ****************/
class BackgroundWidget : public QWidget
{
    Q_OBJECT
public:
    BackgroundWidget( intf_thread_t * );
    virtual ~BackgroundWidget();

private:
    QPalette plt;
    QLabel *label;
    virtual void contextMenuEvent( QContextMenuEvent *event );
    intf_thread_t *p_intf;
    virtual void resizeEvent( QResizeEvent * event );
public slots:
    void toggle(){ TOGGLEV( this ); }
    void updateArt( QString );
};

class VisualSelector : public QFrame
{
    Q_OBJECT
public:
    VisualSelector( intf_thread_t *);
    virtual ~VisualSelector();
private:
    intf_thread_t *p_intf;
    QLabel *current;
private slots:
    void prev();
    void next();
};

/* Advanced Button Bar */
class QPushButton;
class AdvControlsWidget : public QFrame
{
    Q_OBJECT
public:
    AdvControlsWidget( intf_thread_t *);
    virtual ~AdvControlsWidget();

    void enableInput( bool );
    void enableVideo( bool );

private:
    intf_thread_t *p_intf;
    QPushButton *recordButton, *ABButton;
    QPushButton *snapshotButton, *frameButton;

    mtime_t timeA, timeB;

private slots:
    void snapshot();
#if 0
    void frame();
#endif
    void fromAtoB();
    void record();
    void AtoBLoop( float, int, int );
};

/* Button Bar */
class InputSlider;
class QSlider;
class QGridLayout;
class VolumeClickHandler;
class SoundSlider;
class QAbstractSlider;
class QToolButton;

class ControlsWidget : public QFrame
{
    Q_OBJECT
public:
    /* p_intf, advanced control visible or not, blingbling or not */
    ControlsWidget( intf_thread_t *_p_i, MainInterface *_p_mi,
        bool b_advControls, bool b_shiny, bool b_fsCreation = false);
    virtual ~ControlsWidget();

    QPushButton *playlistButton;
    void setStatus( int );
    void enableInput( bool );
    void enableVideo( bool );
public slots:
    void setNavigation( int );
protected:
    friend class MainInterface;
    friend class VolumeClickHandler;
protected:
    intf_thread_t       *p_intf;
    QWidget             *discFrame;
    QWidget             *telexFrame;
    QGridLayout         *controlLayout;
    InputSlider         *slider;
    QPushButton         *prevSectionButton, *nextSectionButton, *menuButton;
    QPushButton         *playButton, *fullscreenButton, *extSettingsButton;
    QToolButton         *slowerButton, *fasterButton;
    QHBoxLayout         *controlButLayout;
    AdvControlsWidget   *advControls;
    QLabel              *volMuteLabel;
    QAbstractSlider     *volumeSlider;
    VolumeClickHandler  *hVolLabel;

    bool                 b_advancedVisible;
protected slots:
    void play();
    void stop();
    void prev();
    void next();
    void updateVolume( int );
    void updateVolume( void );
    void updateInput();
    void fullscreen();
    void extSettings();
    void faster();
    void slower();
    void toggleAdvanced();
signals:
    void advancedControlsToggled( bool );
};

/***********************************
 * Fullscreen controller
 ***********************************/

static int showFullscreenControllCallback(vlc_object_t *vlc_object, const char *variable, vlc_value_t old_val,
    vlc_value_t new_val, void *data);

static int regMouseMoveCallback(vlc_object_t *vlc_object, const char *variable, vlc_value_t old_val,
    vlc_value_t new_val, void *data);

class FullscreenControllerWidget : public ControlsWidget
{
    Q_OBJECT
public:
    FullscreenControllerWidget( intf_thread_t *, MainInterface*, bool, bool );
    virtual ~FullscreenControllerWidget();

    void SetHideTimeout( int hideTimeout ) { i_hideTimeout = hideTimeout; }
    void regFullscreenCallback( vout_thread_t *p_vout );

    bool isFSCHidden();

public slots:
    void unregFullscreenCallback();

protected:
    friend class MainInterface;
    friend class VolumeClickHandler;

    virtual void mouseMoveEvent( QMouseEvent *event );
    virtual void mousePressEvent( QMouseEvent *event );
    virtual void enterEvent( QEvent *event );
    virtual void leaveEvent( QEvent *event );
    virtual void keyPressEvent( QKeyEvent *event );

private slots:
    void hideFSControllerWidget();
    void slowHideFSC();

private:
    QTimer *p_hideTimer;

#if HAVE_TRANSPARENCY
    QTimer *p_slowHideTimer;
#endif

    int i_lastPosX;
    int i_lastPosY;
    int i_hideTimeout;  /* FSC hiding timeout, same as mouse hiding timeout */
    bool b_mouseIsOver;

#ifdef WIN32TRICK
    bool fscHidden;
#endif

    virtual void customEvent( QEvent *event );
};

class VolumeClickHandler : public QObject
{
public:
    VolumeClickHandler( intf_thread_t *_p_intf, ControlsWidget *_m ) :QObject(_m)
    {m = _m; p_intf = _p_intf; }
    virtual ~VolumeClickHandler() {};
    bool eventFilter( QObject *obj, QEvent *e )
    {
        if (e->type() == QEvent::MouseButtonPress  )
        {
            aout_VolumeMute( p_intf, NULL );
            audio_volume_t i_volume;
            aout_VolumeGet( p_intf, &i_volume );
            m->updateVolume( i_volume *  VOLUME_MAX / (AOUT_VOLUME_MAX/2) );
            return true;
        }
        return false;
    }
private:
    ControlsWidget *m;
    intf_thread_t *p_intf;
};

#include <QLabel>
#include <QMouseEvent>
class TimeLabel : public QLabel
{
    Q_OBJECT
    void mousePressEvent( QMouseEvent *event )
    {
        emit timeLabelClicked();
    }
    void mouseDoubleClickEvent( QMouseEvent *event )
    {
        emit timeLabelDoubleClicked();
    }
signals:
    void timeLabelClicked();
    void timeLabelDoubleClicked();
};

class SpeedLabel : public QLabel
{
    Q_OBJECT
public:
    SpeedLabel( intf_thread_t *_p_intf, const QString text ): QLabel( text)
    { p_intf = _p_intf; }

protected:
    virtual void mouseDoubleClickEvent ( QMouseEvent * event )
    {
        THEMIM->getIM()->setRate( INPUT_RATE_DEFAULT );
    }
private:
    intf_thread_t *p_intf;
};

/******************** Speed Control Widgets ****************/
class SpeedControlWidget : public QFrame
{
    Q_OBJECT
public:
    SpeedControlWidget( intf_thread_t *);
    virtual ~SpeedControlWidget();
    void updateControls( int );
private:
    intf_thread_t *p_intf;
    QSlider *speedSlider;
public slots:
    void setEnable( bool );
private slots:
    void updateRate( int );
    void resetRate();
};

#endif
<|endoftext|>


<commit_before>#include "engine.h"
#include "random.h"
#include "gameEntity.h"
#include "Updatable.h"
#include "collisionable.h"

#ifdef DEBUG
#include <typeinfo>
int DEBUG_PobjCount;
PObject* DEBUG_PobjListStart;
#endif

Engine* engine;

Engine::Engine()
{
    engine = this;
    initRandom();
    windowManager = nullptr;
    CollisionManager::initialize();
    InputHandler::initialize();
    gameSpeed = 1.0;
    running = true;
    elapsedTime = 0.0;

    soundManager = new SoundManager();
}
Engine::~Engine()
{
    delete soundManager;
    soundManager = nullptr;
}

void Engine::registerObject(string name, P<PObject> obj)
{
    objectMap[name] = obj;
}

P<PObject> Engine::getObject(string name)
{
    if (!objectMap[name])
        return NULL;
    return objectMap[name];
}

void Engine::runMainLoop()
{
    windowManager = dynamic_cast<WindowManager*>(*getObject("windowManager"));
    if (!windowManager)
    {
        sf::Clock frameTimeClock;
        while(running)
        {
            float delta = frameTimeClock.getElapsedTime().asSeconds();
            frameTimeClock.restart();
            if (delta > 0.5)
                delta = 0.5;
            if (delta < 0.001)
                delta = 0.001;
            delta *= gameSpeed;

            entityList.update();
            foreach(Updatable, u, updatableList)
                u->update(delta);
            elapsedTime += delta;
            CollisionManager::handleCollisions(delta);
            ScriptObject::clearDestroyedObjects();
            soundManager->updateTick();

            sf::sleep(sf::seconds(1.0/60.0 - delta));
            //if (elapsedTime > 2.0)
            //    break;
        }
    }else{
        sf::Clock frameTimeClock;
#ifdef DEBUG
        sf::Clock debugOutputClock;
#endif
        last_key_press = sf::Keyboard::Unknown;

        while (windowManager->window.isOpen())
        {
            InputHandler::mouse_wheel_delta = 0;
            // Handle events
            sf::Event event;
            while (windowManager->window.pollEvent(event))
            {
                handleEvent(event);
            }
            if (last_key_press != sf::Keyboard::Unknown)
            {
                InputHandler::fireKeyEvent(last_key_press, -1);
                last_key_press = sf::Keyboard::Unknown;
            }

#ifdef DEBUG
            if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape) && windowManager->hasFocus())
                windowManager->window.close();

            if (debugOutputClock.getElapsedTime().asSeconds() > 1.0)
            {
                printf("Object count: %4d %4d %4d\n", DEBUG_PobjCount, updatableList.size(), entityList.size());
                debugOutputClock.restart();
            }
#endif

            float delta = frameTimeClock.restart().asSeconds();
            if (delta > 0.5)
                delta = 0.5;
            if (delta < 0.001)
                delta = 0.001;
            delta *= gameSpeed;
#ifdef DEBUG
            if (sf::Keyboard::isKeyPressed(sf::Keyboard::Tab))
                delta /= 5.0;
            if (sf::Keyboard::isKeyPressed(sf::Keyboard::Tilde))
                delta *= 5.0;
#endif
            EngineTiming engine_timing;

            sf::Clock engine_timing_clock;
            InputHandler::update();
            entityList.update();
            foreach(Updatable, u, updatableList)
                u->update(delta);
            elapsedTime += delta;
            engine_timing.update = engine_timing_clock.restart().asSeconds();
            CollisionManager::handleCollisions(delta);
            engine_timing.collision = engine_timing_clock.restart().asSeconds();
            ScriptObject::clearDestroyedObjects();
            soundManager->updateTick();

            // Clear the window
            windowManager->render();
            engine_timing.render = engine_timing_clock.restart().asSeconds();

            last_engine_timing = engine_timing;
        }
        soundManager->stopMusic();
    }
}

void Engine::handleEvent(sf::Event& event)
{
    // Window closed: exit
    if ((event.type == sf::Event::Closed))
    {
        windowManager->window.close();
    }
    if (event.type == sf::Event::GainedFocus)
        windowManager->windowHasFocus = true;
    if (event.type == sf::Event::LostFocus)
        windowManager->windowHasFocus = false;
#ifdef DEBUG
    if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::L))
    {
        int n = 0;
        printf("---------------------\n");
        for(PObject* obj = DEBUG_PobjListStart; obj; obj = obj->DEBUG_PobjListNext)
            printf("%c%4d: %4d: %s\n", obj->isDestroyed() ? '>' : ' ', n++, obj->getRefCount(), typeid(*obj).name());
        printf("---------------------\n");
    }
#endif
    if (event.type == sf::Event::KeyPressed)
    {
        InputHandler::keyboard_button_down[event.key.code] = true;
        last_key_press = event.key.code;
    }
    if (event.type == sf::Event::KeyReleased)
        InputHandler::keyboard_button_down[event.key.code] = false;
    if (event.type == sf::Event::TextEntered && event.text.unicode > 31 && event.text.unicode < 128)
    {
        if (last_key_press != sf::Keyboard::Unknown)
        {
            InputHandler::fireKeyEvent(last_key_press, event.text.unicode);
            last_key_press = sf::Keyboard::Unknown;
        }
    }
    if (event.type == sf::Event::MouseWheelMoved)
        InputHandler::mouse_wheel_delta += event.mouseWheel.delta;
    if (event.type == sf::Event::MouseButtonPressed)
        InputHandler::mouse_button_down[event.mouseButton.button] = true;
    if (event.type == sf::Event::MouseButtonReleased)
        InputHandler::mouse_button_down[event.mouseButton.button] = false;
    if (event.type == sf::Event::Resized)
        windowManager->setupView();
#ifdef __ANDROID__
    //Focus lost and focus gained events are used when the application window is created and destroyed.
    if (event.type == sf::Event::LostFocus)
    {
        windowManager->window.close();
    }

    //The MouseEntered and MouseLeft events are received when the activity needs to pause or resume.
    if (event.type == sf::Event::MouseLeft)
    {
        //Pause is when a small popup is on top of the window. So keep running.
        while(windowManager->window.isOpen() && windowManager->window.waitEvent(event))
        {
            if (event.type != sf::Event::MouseLeft)
                handleEvent(event);
            if (event.type == sf::Event::MouseEntered)
                break;
        }
    }
#endif//__ANDROID__
}

void Engine::setGameSpeed(float speed)
{
    gameSpeed = speed;
}

float Engine::getGameSpeed()
{
    return gameSpeed;
}

float Engine::getElapsedTime()
{
    return elapsedTime;
}

Engine::EngineTiming Engine::getEngineTiming()
{
    return last_engine_timing;
}

void Engine::shutdown()
{
    if (windowManager)
        windowManager->close();
    running = false;
}
<commit_msg>Change how shutting down the engine is handled. Hopefully fixing some android issues.<commit_after>#include "engine.h"
#include "random.h"
#include "gameEntity.h"
#include "Updatable.h"
#include "collisionable.h"

#ifdef DEBUG
#include <typeinfo>
int DEBUG_PobjCount;
PObject* DEBUG_PobjListStart;
#endif

Engine* engine;

Engine::Engine()
{
    engine = this;
    initRandom();
    windowManager = nullptr;
    CollisionManager::initialize();
    InputHandler::initialize();
    gameSpeed = 1.0;
    running = true;
    elapsedTime = 0.0;

    soundManager = new SoundManager();
}
Engine::~Engine()
{
    if (windowManager)
        windowManager->close();
    delete soundManager;
    soundManager = nullptr;
}

void Engine::registerObject(string name, P<PObject> obj)
{
    objectMap[name] = obj;
}

P<PObject> Engine::getObject(string name)
{
    if (!objectMap[name])
        return NULL;
    return objectMap[name];
}

void Engine::runMainLoop()
{
    windowManager = dynamic_cast<WindowManager*>(*getObject("windowManager"));
    if (!windowManager)
    {
        sf::Clock frameTimeClock;
        while(running)
        {
            float delta = frameTimeClock.getElapsedTime().asSeconds();
            frameTimeClock.restart();
            if (delta > 0.5)
                delta = 0.5;
            if (delta < 0.001)
                delta = 0.001;
            delta *= gameSpeed;

            entityList.update();
            foreach(Updatable, u, updatableList)
                u->update(delta);
            elapsedTime += delta;
            CollisionManager::handleCollisions(delta);
            ScriptObject::clearDestroyedObjects();
            soundManager->updateTick();

            sf::sleep(sf::seconds(1.0/60.0 - delta));
            //if (elapsedTime > 2.0)
            //    break;
        }
    }else{
        sf::Clock frameTimeClock;
#ifdef DEBUG
        sf::Clock debugOutputClock;
#endif
        last_key_press = sf::Keyboard::Unknown;

        while(running && windowManager->window.isOpen())
        {
            InputHandler::mouse_wheel_delta = 0;
            // Handle events
            sf::Event event;
            while (windowManager->window.pollEvent(event))
            {
                handleEvent(event);
            }
            if (last_key_press != sf::Keyboard::Unknown)
            {
                InputHandler::fireKeyEvent(last_key_press, -1);
                last_key_press = sf::Keyboard::Unknown;
            }

#ifdef DEBUG
            if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape) && windowManager->hasFocus())
                running = false;

            if (debugOutputClock.getElapsedTime().asSeconds() > 1.0)
            {
                printf("Object count: %4d %4d %4d\n", DEBUG_PobjCount, updatableList.size(), entityList.size());
                debugOutputClock.restart();
            }
#endif

            float delta = frameTimeClock.restart().asSeconds();
            if (delta > 0.5)
                delta = 0.5;
            if (delta < 0.001)
                delta = 0.001;
            delta *= gameSpeed;
#ifdef DEBUG
            if (sf::Keyboard::isKeyPressed(sf::Keyboard::Tab))
                delta /= 5.0;
            if (sf::Keyboard::isKeyPressed(sf::Keyboard::Tilde))
                delta *= 5.0;
#endif
            EngineTiming engine_timing;

            sf::Clock engine_timing_clock;
            InputHandler::update();
            entityList.update();
            foreach(Updatable, u, updatableList)
                u->update(delta);
            elapsedTime += delta;
            engine_timing.update = engine_timing_clock.restart().asSeconds();
            CollisionManager::handleCollisions(delta);
            engine_timing.collision = engine_timing_clock.restart().asSeconds();
            ScriptObject::clearDestroyedObjects();
            soundManager->updateTick();

            // Clear the window
            windowManager->render();
            engine_timing.render = engine_timing_clock.restart().asSeconds();

            last_engine_timing = engine_timing;
        }
        soundManager->stopMusic();
    }
}

void Engine::handleEvent(sf::Event& event)
{
    // Window closed: exit
    if ((event.type == sf::Event::Closed))
        running = false;
    if (event.type == sf::Event::GainedFocus)
        windowManager->windowHasFocus = true;
    if (event.type == sf::Event::LostFocus)
        windowManager->windowHasFocus = false;
#ifdef DEBUG
    if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::L))
    {
        int n = 0;
        printf("---------------------\n");
        for(PObject* obj = DEBUG_PobjListStart; obj; obj = obj->DEBUG_PobjListNext)
            printf("%c%4d: %4d: %s\n", obj->isDestroyed() ? '>' : ' ', n++, obj->getRefCount(), typeid(*obj).name());
        printf("---------------------\n");
    }
#endif
    if (event.type == sf::Event::KeyPressed)
    {
        InputHandler::keyboard_button_down[event.key.code] = true;
        last_key_press = event.key.code;
    }
    if (event.type == sf::Event::KeyReleased)
        InputHandler::keyboard_button_down[event.key.code] = false;
    if (event.type == sf::Event::TextEntered && event.text.unicode > 31 && event.text.unicode < 128)
    {
        if (last_key_press != sf::Keyboard::Unknown)
        {
            InputHandler::fireKeyEvent(last_key_press, event.text.unicode);
            last_key_press = sf::Keyboard::Unknown;
        }
    }
    if (event.type == sf::Event::MouseWheelMoved)
        InputHandler::mouse_wheel_delta += event.mouseWheel.delta;
    if (event.type == sf::Event::MouseButtonPressed)
        InputHandler::mouse_button_down[event.mouseButton.button] = true;
    if (event.type == sf::Event::MouseButtonReleased)
        InputHandler::mouse_button_down[event.mouseButton.button] = false;
    if (event.type == sf::Event::Resized)
        windowManager->setupView();
#ifdef __ANDROID__
    //Focus lost and focus gained events are used when the application window is created and destroyed.
    if (event.type == sf::Event::LostFocus)
        running = false;

    //The MouseEntered and MouseLeft events are received when the activity needs to pause or resume.
    if (event.type == sf::Event::MouseLeft)
    {
        //Pause is when a small popup is on top of the window. So keep running.
        while(windowManager->window.isOpen() && windowManager->window.waitEvent(event))
        {
            if (event.type != sf::Event::MouseLeft)
                handleEvent(event);
            if (event.type == sf::Event::MouseEntered)
                break;
        }
    }
#endif//__ANDROID__
}

void Engine::setGameSpeed(float speed)
{
    gameSpeed = speed;
}

float Engine::getGameSpeed()
{
    return gameSpeed;
}

float Engine::getElapsedTime()
{
    return elapsedTime;
}

Engine::EngineTiming Engine::getEngineTiming()
{
    return last_engine_timing;
}

void Engine::shutdown()
{
    running = false;
}
<|endoftext|>


<commit_before>/***************************************************************************
 *  The Kernel-Machine Library                                             *
 *  Copyright (C) 2004, 2005, 2006 by Rutger W. ter Borg                   *
 *                                                                         *
 *  This program is free software; you can redistribute it and/or          *
 *  modify it under the terms of the GNU General Public License            *
 *  as published by the Free Software Foundation; either version 2         *
 *  of the License, or (at your option) any later version.                 *
 *                                                                         *
 *  This program is distributed in the hope that it will be useful,        *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
 *  GNU General Public License for more details.                           *
 *                                                                         *
 *  You should have received a copy of the GNU General Public License      *
 *  along with this program; if not, write to the Free Software            *
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307  *
 ***************************************************************************/

#include <boost/math/special_functions/sinc.hpp>
#include <boost/random/variate_generator.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/normal_distribution.hpp>
#include <kml/gaussian.hpp>
#include <kml/statistics.hpp>
#include <boost/numeric/ublas/io.hpp>

#include <boost/vector_property_map.hpp>

//#include <kml/online_svm.hpp>
//#include <kml/rvm.hpp>
#include <kml/krls.hpp>

int main(int argc, char *argv[]) {

    boost::mt19937 randomness;
    boost::normal_distribution<double> norm_dist( 0.0, 0.1 );
    boost::variate_generator<boost::mt19937, boost::normal_distribution<double> > noise( randomness, norm_dist );

    typedef std::pair<ublas::vector<double>, double> example_type;
    typedef boost::vector_property_map< example_type > data_type;
    data_type data;

    int N = 50;
    std::vector<ublas::vector<double> > x_vec(N);
    for( int i=0; i<N; ++i ) {
	example_type::first_type x(1);
	x[0] = (double(i)/double(N-1))*20.0-10.0;
        x_vec[i] = x;
        data[i] = std::make_pair( x, boost::math::sinc_pi(x[0]) + noise() );
    }

    std::cout << "Training kernel machine..." << std::endl;

    typedef kml::regression< example_type > problem_type;
    typedef kml::gaussian< example_type::first_type > kernel_type;

//    kml::online_svm< problem_type, kernel_type, data_type > my_machine( 10.0, 0.1, kernel_type(1.6), data );
    kml::krls< problem_type, kernel_type, data_type > my_machine( 1e-1, 1e-3, kernel_type(1.6), data );

    std::vector< int > random_order;
    for( int i=0; i<N; ++i ) random_order.push_back(i);

    std::random_shuffle( random_order.begin(), random_order.end() );

    my_machine.learn( random_order.begin(), random_order.end() );

    std::cout << "Making predictions..." << std::endl;
    ublas::vector<double> y_test(N);

    std::transform( x_vec.begin(), x_vec.end(), y_test.begin(), my_machine );
//      std::cout << "RMSE " << kml::root_mean_square( y - y_test ) << std::endl;
//      std::cout << "Cor  " << kml::correlation( y, y_test ) << std::endl;

     std::cout << "Predicted output values:" << std::endl;
     std::cout << y_test << std::endl;

    return EXIT_SUCCESS;
}
<commit_msg>updated example/svm_regression to use boost::tuple<commit_after>/***************************************************************************
 *  The Kernel-Machine Library                                             *
 *  Copyright (C) 2004, 2005, 2006 by Rutger W. ter Borg                   *
 *                                                                         *
 *  This program is free software; you can redistribute it and/or          *
 *  modify it under the terms of the GNU General Public License            *
 *  as published by the Free Software Foundation; either version 2         *
 *  of the License, or (at your option) any later version.                 *
 *                                                                         *
 *  This program is distributed in the hope that it will be useful,        *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
 *  GNU General Public License for more details.                           *
 *                                                                         *
 *  You should have received a copy of the GNU General Public License      *
 *  along with this program; if not, write to the Free Software            *
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307  *
 ***************************************************************************/

#include <boost/math/special_functions/sinc.hpp>
#include <boost/random/variate_generator.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/normal_distribution.hpp>
#include <kml/gaussian.hpp>
#include <kml/statistics.hpp>
#include <boost/numeric/ublas/io.hpp>

#include <boost/vector_property_map.hpp>
#include <boost/tuple/tuple.hpp>

//#include <kml/online_svm.hpp>
//#include <kml/rvm.hpp>
#include <kml/krls.hpp>

int main(int argc, char *argv[]) {

    boost::mt19937 randomness;
    boost::normal_distribution<double> norm_dist( 0.0, 0.1 );
    boost::variate_generator<boost::mt19937, boost::normal_distribution<double> > noise( randomness, norm_dist );

    typedef boost::tuple<ublas::vector<double>, double> example_type;
    typedef boost::vector_property_map< example_type > data_type;
    data_type data;

    int N = 50;
    std::vector<ublas::vector<double> > x_vec(N);
    for( int i=0; i<N; ++i ) {
	boost::tuples::element<0,example_type>::type x(1);
	x[0] = (double(i)/double(N-1))*20.0-10.0;
        x_vec[i] = x;
        data[i] = boost::make_tuple( x, boost::math::sinc_pi(x[0]) + noise() );
    }

    std::cout << "Training kernel machine..." << std::endl;

    typedef kml::regression< example_type > problem_type;
    typedef kml::gaussian< problem_type::input_type > kernel_type;

//    kml::online_svm< problem_type, kernel_type, data_type > my_machine( 10.0, 0.1, kernel_type(1.6), data );
    kml::krls< problem_type, kernel_type, data_type > my_machine( 1e-1, 1e-3, kernel_type(1.6), data );

    std::vector< int > random_order;
    for( int i=0; i<N; ++i ) random_order.push_back(i);

    std::random_shuffle( random_order.begin(), random_order.end() );

    my_machine.learn( random_order.begin(), random_order.end() );

    std::cout << "Making predictions..." << std::endl;
    ublas::vector<double> y_test(N);

    std::transform( x_vec.begin(), x_vec.end(), y_test.begin(), my_machine );
//      std::cout << "RMSE " << kml::root_mean_square( y - y_test ) << std::endl;
//      std::cout << "Cor  " << kml::correlation( y, y_test ) << std::endl;

     std::cout << "Predicted output values:" << std::endl;
     std::cout << y_test << std::endl;

    return EXIT_SUCCESS;
}<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// <string>
// UNSUPPORTED: c++98, c++03, c++11, c++14
// UNSUPPORTED: libcpp-no-deduction-guides

// template<class InputIterator,
//      class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
//  basic_string(InputIterator, InputIterator, Allocator = Allocator())
//    -> basic_string<typename iterator_traits<InputIterator>::value_type,
//                 char_traits<typename iterator_traits<InputIterator>::value_type>,
//                 Allocator>;
//
//  The deduction guide shall not participate in overload resolution if InputIterator
//  is a type that does not qualify as an input iterator, or if Allocator is a type
//  that does not qualify as an allocator.

#include <string>
#include <iterator>
#include <cassert>
#include <cstddef>

#include "test_macros.h"

class NotAnItertor {};

template <typename T>
struct NotAnAllocator { typedef T value_type; };

int main()
{
    { // Not an iterator at all
    std::basic_string s1{NotAnItertor{}, NotAnItertor{}, std::allocator<char>{}}; // expected-error {{no viable constructor or deduction guide for deduction of template arguments of 'basic_string'}}
    }
    { // Not an input iterator
    const char16_t* s = u"12345678901234";
    std::basic_string<char16_t> s0;
    std::basic_string s1{std::back_insert_iterator(s0), //  expected-error {{no viable constructor or deduction guide for deduction of template arguments of 'basic_string'}}
                         std::back_insert_iterator(s0),
                         std::allocator<char16_t>{}};
    }
    { // Not an allocator
    const wchar_t* s = L"12345678901234";
    std::basic_string s1{s, s+10, NotAnAllocator<wchar_t>{}}; // expected-error {{no viable constructor or deduction guide for deduction of template arguments of 'basic_string'}}
    }

}
<commit_msg>[libcxx][test] Reverting r327178 and r327190.<commit_after>//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// <string>
// UNSUPPORTED: c++98, c++03, c++11, c++14
// UNSUPPORTED: clang-3.3, clang-3.4, clang-3.5, clang-3.6, clang-3.7, clang-3.8, clang-3.9, clang-4.0
// UNSUPPORTED: apple-clang-6, apple-clang-7, apple-clang-8.0

// template<class InputIterator,
//      class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
//  basic_string(InputIterator, InputIterator, Allocator = Allocator())
//    -> basic_string<typename iterator_traits<InputIterator>::value_type,
//                 char_traits<typename iterator_traits<InputIterator>::value_type>,
//                 Allocator>;
//
//  The deduction guide shall not participate in overload resolution if InputIterator
//  is a type that does not qualify as an input iterator, or if Allocator is a type
//  that does not qualify as an allocator.

#include <string>
#include <iterator>
#include <cassert>
#include <cstddef>

#include "test_macros.h"

class NotAnItertor {};

template <typename T>
struct NotAnAllocator { typedef T value_type; };

int main()
{
    { // Not an iterator at all
    std::basic_string s1{NotAnItertor{}, NotAnItertor{}, std::allocator<char>{}}; // expected-error {{no viable constructor or deduction guide for deduction of template arguments of 'basic_string'}}
    }
    { // Not an input iterator
    const char16_t* s = u"12345678901234";
    std::basic_string<char16_t> s0;
    std::basic_string s1{std::back_insert_iterator(s0), //  expected-error {{no viable constructor or deduction guide for deduction of template arguments of 'basic_string'}}
                         std::back_insert_iterator(s0),
                         std::allocator<char16_t>{}};
    }
    { // Not an allocator
    const wchar_t* s = L"12345678901234";
    std::basic_string s1{s, s+10, NotAnAllocator<wchar_t>{}}; // expected-error {{no viable constructor or deduction guide for deduction of template arguments of 'basic_string'}}
    }

}
<|endoftext|>


<commit_before>#include <iostream>
#include <algorithm>
#include <iterator>
#include <tuple>
#include <set>
#include <vector>
#include <utility>
#include <iomanip>
#include <chrono>
// #include <bits/stdc++.h>

using ull = unsigned long long;
constexpr double CACHE_SIZE_FACTOR = 1.0 / (10 * 10 * 10); // size of the range between each cache

class LogEntry {
public:
    LogEntry () : endtime(0), starttime(0), bitrate(0), streamed(0), prev_streamed(0), duration(0) {}
    ull endtime, starttime;
    unsigned int bitrate;
    double streamed, prev_streamed, duration;
};

using LogEntries = std::vector<LogEntry>;
using LogCache = std::vector<std::pair<const std::size_t, const std::size_t>>;

LogEntries reorder(const LogEntries&, LogCache&);
void repl(const LogEntries&, const LogCache&, int);
bool compare(const LogEntry&, const LogEntry&);
std::istream &operator >> (std::istream&, LogEntry&);

#ifdef DEBUG
template <typename T>
std::ostream &operator << (std::ostream&, const std::vector<T>&);

std::ostream &operator << (std::ostream&, const LogEntry&);

template <typename F, typename S>
std::ostream &operator << (std::ostream&, const std::pair<F, S>&);
#endif

int main() {

    // Remove synchronization between cstdio and iostream
    std::ios_base::sync_with_stdio(false);
    // Prevent flushing of output stream before each io operation
    std::cin.tie(nullptr);

    LogEntries logEntries;
    int logsize;
    std::cin >> logsize;

    std::copy_n(std::istream_iterator<LogEntry>(std::cin), logsize,
        std::back_inserter(logEntries));

    #ifdef DEBUG
    // std::cout << "\n" << logEntries << "\n\n";
    #endif

    LogCache cache;
    logEntries = reorder(logEntries, cache);

    #ifdef DEBUG
    // std::cout << "\n" << logEntries << "\n\n";

    // std::cout << "\n" << cache << "\n\n";
    std::cout << "Entries size: " << logEntries.size() << "\nCache size: " << cache.size() << '\n';
    std::cout << "Cache contents:\n" << cache << '\n';
    #endif

    if (std::cin >> logsize) {
        repl(logEntries, cache, logsize);
    }

    return 0;
}

/**
 * @brief Reads time ranges and sells lambourghinis'
 * @details The repl stands for READ-EVALUATE-PRINT-LOOP.
 * This method in particular will read any time range given, determine which log entries
 * fall under this time range. It will then take the streams available under this
 * time range and print what percentage of those streams were fully contained
 * within the range given
 *
 * @param entries The collection of logs. This must have gone through the reorder
 * function before it can be used here
 * @param count The number of queries to expect
 */
void repl(const LogEntries& entries, const LogCache& cache, int count) {
    LogEntries::const_iterator hi, lo;
    LogEntry query;
    std::cout.precision(3);
    std::cout.setf(std::ios_base::fixed);

    for (std::cin >> query.starttime >> query.endtime; count--;
        std::cin >> query.starttime >> query.endtime) {

        std::tie(lo, hi) = std::equal_range(entries.begin(), entries.end(),
            query, compare);

        hi--;

        if (query.starttime < lo->starttime) {
            query.starttime = lo->starttime;
        }

        if (query.endtime > hi->endtime) {
            query.endtime = hi->endtime;
        }

        query.streamed = (hi->prev_streamed - lo->prev_streamed - lo->streamed) +
        ((lo->endtime - query.starttime) / lo->duration * lo->streamed) +
        ((query.endtime - hi->starttime) / hi->duration * hi->streamed);

        std::cout << query.streamed << '\n';
    }
}

/**
 * @brief Extract the non-overlapping ranges from the given log entries
 * @details The method ...
 *
 * @param entries The vector of log entries from which to extract non
 * overlapping ranges from
 * @return A vector of Log Entries where all the entries are non overlapping
 */
LogEntries extract_ranges(const LogEntries& entries) {
    // Use a set to avoid duplicates and make the entries sorted 2 birds one set
    std::set<ull> times;
    std::set<ull>::const_iterator iter;

    for (std::size_t t = 0; t < entries.size(); t++) {
        times.insert(entries[t].starttime);
        times.insert(entries[t].endtime);
    }

    LogEntries merged;
    LogEntry range;

    for (iter = times.begin(); iter != times.end();) {
        range.starttime = *iter++;
        if (iter != times.end()) {
            range.endtime = *iter;
            range.duration = range.endtime - range.starttime;
            merged.push_back(range);
        }
    }
    return merged;
}

/**
 * @brief Aranges the logs into non overlapping ranges for easier usage
 * @details The logs are taken one by one and we cut them up into smaller
 * logs which do not overlap. By doing this, it is easier to work with ranges
 * because you don't have to worry about anything they overlap
 *
 * @param entries The initial entries we got as input
 */
LogEntries reorder(const LogEntries &entries, LogCache& cache) {
    LogEntries ranges = extract_ranges(entries);
    LogEntries::iterator hi, lo;

    // compute the cache size (atleast size 1)
    std::size_t num_buckets = static_cast<double>(ranges.size()) * CACHE_SIZE_FACTOR + 1;
    cache.reserve(num_buckets);

    // The max time interval maintained within each range in the cache
    const ull max_interval = (ranges.back().endtime - ranges[0].starttime + num_buckets) / num_buckets;

    #ifdef DEBUG
    std::cout << "Cache size factor: " << CACHE_SIZE_FACTOR << '\n'
    << "Number of buckets: " << num_buckets << '\n'
    << "Max interval: " << max_interval << '\n';
    #endif

    for (auto &entry : entries) {
        std::tie(lo, hi) = std::equal_range(ranges.begin(), ranges.end(),
            entry, compare);

        std::for_each(lo, hi, [&entry](LogEntry& val) {
            val.bitrate += entry.bitrate;
        });
    }

    LogEntries::iterator beg = ranges.begin(), curr;
    beg->streamed = beg->duration / 1000 * beg->bitrate;
    ull start_time = beg->starttime;

    // auto start = std::chrono::steady_clock::now();

    for (curr = beg + 1; curr != ranges.end(); curr++) {
        curr->streamed = curr->duration / 1000 * curr->bitrate;
        curr->prev_streamed = (curr - 1)->streamed + (curr - 1)->prev_streamed;

        if (curr->starttime - start_time > max_interval) {
            cache.emplace_back(std::distance(ranges.begin(), beg), std::distance(ranges.begin(), curr));
            beg = curr;
            start_time = curr->starttime;
        }
    }
    cache.emplace_back(std::distance(ranges.begin(), beg), std::distance(ranges.begin(), curr));
    // std::cout << "This took: "
    // << std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::steady_clock::now() - start).count()
    // << " seconds\n";

    return ranges;
}

inline bool compare(const LogEntry& lhs, const LogEntry& rhs) {
    return lhs.endtime <= rhs.starttime;
}

std::istream &operator >> (std::istream& iss, LogEntry& entry) {
    iss >> entry.endtime >> entry.duration >> entry.bitrate;
    entry.starttime = entry.endtime - entry.duration;
    return iss;
}

std::ostream &operator << (std::ostream& oss, const LogEntry& entry) {
    oss << "start=" << entry.starttime << ", end=" << entry.endtime
    << ", bitrate(s)=" << entry.bitrate << ", streamed(kb)="
    << std::setprecision(3) << std::fixed << entry.streamed;

    return oss;
}

template <typename F, typename S>
std::ostream &operator << (std::ostream& oss, const std::pair<F, S> &p) {
    return oss << "(First=>" << p.first << ", second=>" << p.second << ")";
}

template <typename T>
std::ostream &operator << (std::ostream& oss, const std::vector<T>& v) {
    for (auto& item : v) {
        oss << item << "\n";
    }
    return oss;
}
<commit_msg>This one is not working either<commit_after>#include <iostream>
#include <algorithm>
#include <iterator>
#include <tuple>
#include <set>
#include <vector>
#include <utility>
#include <iomanip>
#include <limits>
// #include <bits/stdc++.h>

using ull = unsigned long long;

// 100 seconds of information cached
constexpr std::size_t STORED_DURATION = 100 * 1000;

class LogEntry {
public:
    LogEntry () : endtime(0), starttime(0), bitrate(0), streamed(0), prev_streamed(0), duration(0) {}
    ull endtime, starttime;
    unsigned int bitrate;
    double streamed, prev_streamed, duration;
};

using LogEntries = std::vector<LogEntry>;

LogEntries reorder(const LogEntries&);
void repl(const LogEntries&, int);
bool compare(const LogEntry&, const LogEntry&);
std::istream &operator >> (std::istream&, LogEntry&);

#ifdef DEBUG
template <typename T>
std::ostream &operator << (std::ostream&, const std::vector<T>&);

std::ostream &operator << (std::ostream&, const LogEntry&);

template <typename F, typename S>
std::ostream &operator << (std::ostream&, const std::pair<F, S>&);
#endif

int main() {

    // Remove synchronization between cstdio and iostream
    std::ios_base::sync_with_stdio(false);
    // Prevent flushing of output stream before each io operation
    std::cin.tie(nullptr);

    LogEntries logEntries;
    int logsize;
    std::cin >> logsize;

    std::copy_n(std::istream_iterator<LogEntry>(std::cin), logsize,
        std::back_inserter(logEntries));

    #ifdef DEBUG
    // std::cout << "\n" << logEntries << "\n\n";
    #endif

    logEntries = reorder(logEntries);

    #ifdef DEBUG
    std::cout << "\n" << logEntries << "\n\n";

    // std::cout << "\n" << cache << "\n\n";
    // std::cout << "Entries size: " << logEntries.size() << '\n';
    #endif

    if (std::cin >> logsize) {
        repl(logEntries, logsize);
    }

    return 0;
}

/**
 * @brief Reads time ranges and sells lambourghinis'
 * @details The repl stands for READ-EVALUATE-PRINT-LOOP.
 * This method in particular will read any time range given, determine which log entries
 * fall under this time range. It will then take the streams available under this
 * time range and print what percentage of those streams were fully contained
 * within the range given
 *
 * @param entries The collection of logs. This must have gone through the reorder
 * function before it can be used here
 * @param count The number of queries to expect
 */
void repl(const LogEntries& entries, int count) {
    LogEntries::const_iterator hi, lo;
    LogEntry query;
    std::cout.precision(3);
    std::cout.setf(std::ios_base::fixed);

    for (std::cin >> query.starttime >> query.endtime; count--;
        std::cin >> query.starttime >> query.endtime) {

        std::tie(lo, hi) = std::equal_range(entries.begin(), entries.end(),
            query, compare);

        hi--;
        std::cout << query << std::endl << *lo << std::endl << *hi << std::endl;

        if (query.starttime < lo->starttime) {
            query.starttime = lo->starttime;
        }

        if (query.endtime > hi->endtime) {
            query.endtime = hi->endtime;
        }

        query.streamed = (hi->prev_streamed - lo->prev_streamed - lo->streamed) +
        ((lo->endtime - query.starttime) / lo->duration * lo->streamed) +
        ((query.endtime - hi->starttime) / hi->duration * hi->streamed);

        std::cout << query.streamed << "\n\n";
    }
}

/**
 * @brief Extract the non-overlapping ranges from the given log entries
 * @details The method ...
 *
 * @param entries The vector of log entries from which to extract non
 * overlapping ranges from
 * @return A vector of Log Entries where all the entries are non overlapping
 */
LogEntries extract_ranges(const LogEntries& entries) {
    ull smaller = std::numeric_limits<ull>::max(), larger = 0;

    for (auto& entry: entries) {
        if (entry.starttime < smaller) {
            smaller = entry.starttime;
        }

        if (entry.endtime > larger) {
            larger = entry.endtime;
        }
    }

    LogEntries merged;
    LogEntry range;

    #ifdef DEBUG
    std::cout << "Min: " << smaller << "\nMax: " << larger << '\n';
    #endif

    while (smaller + STORED_DURATION < larger) {
        range.starttime = smaller;
        range.endtime = smaller + STORED_DURATION;
        range.duration = range.endtime - range.starttime;
        merged.push_back(range);
        smaller += STORED_DURATION;
    }
    range.starttime = smaller;
    range.endtime = larger;
    range.duration = range.endtime - range.starttime;
    merged.push_back(range);

    return merged;
}

/**
 * @brief Aranges the logs into non overlapping ranges for easier usage
 * @details The logs are taken one by one and we cut them up into smaller
 * logs which do not overlap. By doing this, it is easier to work with ranges
 * because you don't have to worry about anything they overlap
 *
 * @param entries The initial entries we got as input
 */
LogEntries reorder(const LogEntries &entries) {
    LogEntries ranges = extract_ranges(entries);
    LogEntries::iterator hi, lo;

    for (auto &entry : entries) {
        std::tie(lo, hi) = std::equal_range(ranges.begin(), ranges.end(),
            entry, compare);

        std::for_each(lo, hi, [&entry](LogEntry& val) {
            // if (val.endtime > entry.starttime && val.starttime < entry.endtime) {
            if (val.starttime < entry.starttime && val.endtime > entry.endtime) {
                 val.streamed += (entry.endtime - entry.starttime) / 1000 * entry.bitrate;
            } else if (val.starttime < entry.starttime) {
                val.streamed += (val.endtime - entry.starttime) / 1000 * entry.bitrate;
            } else if (val.endtime > entry.endtime) {
                val.streamed += (entry.endtime - val.starttime) / 1000 * entry.bitrate;
            } else {
                val.streamed += (val.endtime - val.starttime) / 1000 * entry.bitrate;
            }
            // }
        });
    }

    LogEntries::iterator curr = ranges.begin();
    // curr->streamed = curr->duration / 1000 * curr->bitrate;

    while (++curr != ranges.end()) {
        // curr->streamed = curr->duration / 1000 * curr->bitrate;
        curr->prev_streamed = (curr - 1)->streamed + (curr - 1)->prev_streamed;
    }
    return ranges;
}

inline bool compare(const LogEntry& lhs, const LogEntry& rhs) {
    return lhs.endtime <= rhs.starttime;
}

std::istream &operator >> (std::istream& iss, LogEntry& entry) {
    iss >> entry.endtime >> entry.duration >> entry.bitrate;
    entry.starttime = entry.endtime - entry.duration;
    return iss;
}

std::ostream &operator << (std::ostream& oss, const LogEntry& entry) {
    oss << "start=" << entry.starttime << ", end=" << entry.endtime
    << ", bitrate(s)=" << entry.bitrate << ", streamed(kb)="
    << std::setprecision(3) << std::fixed << entry.streamed;

    return oss;
}

template <typename F, typename S>
std::ostream &operator << (std::ostream& oss, const std::pair<F, S> &p) {
    return oss << "(First=>" << p.first << ", second=>" << p.second << ")";
}

template <typename T>
std::ostream &operator << (std::ostream& oss, const std::vector<T>& v) {
    for (auto& item : v) {
        oss << item << "\n";
    }
    return oss;
}
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Lukasz Janyst <ljanyst@cern.ch>
//------------------------------------------------------------------------------

#include "cling/Interpreter/Interpreter.h"
#include "cling/MetaProcessor/MetaProcessor.h"
#include "cling/UserInterface/UserInterface.h"

#include "clang/Basic/LangOptions.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/HeaderSearchOptions.h"

#include "llvm/Support/Signals.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/ManagedStatic.h"

#include <iostream>
#include <vector>
#include <string>

int main( int argc, char **argv ) {

  llvm::llvm_shutdown_obj shutdownTrigger;

  //llvm::sys::PrintStackTraceOnErrorSignal();
  //llvm::PrettyStackTraceProgram X(argc, argv);

  // Set up the interpreter
  cling::Interpreter interp(argc, argv);
  if (interp.getOptions().Help) {
    return 0;
  }

  clang::CompilerInstance* CI = interp.getCI();
  interp.AddIncludePath(".");

  for (size_t I = 0, N = interp.getOptions().LibsToLoad.size(); I < N; ++I) {
    interp.loadFile(interp.getOptions().LibsToLoad[I]);
  }

   bool ret = true;
   const std::vector<clang::FrontendInputFile>& Inputs
     = CI->getInvocation().getFrontendOpts().Inputs;

   // Interactive means no input (or one input that's "-")
   bool Interactive = Inputs.empty() || (Inputs.size() == 1
                                         && Inputs[0].File == "-");

   cling::UserInterface ui(interp);
   // If we are not interactive we're supposed to parse files
   if (!Interactive) {
     for (size_t I = 0, N = Inputs.size(); I < N; ++I) {
       ret = ui.getMetaProcessor()->process((".x " + Inputs[I].File).c_str());
     }
   }
   else {
      cling::UserInterface ui(interp);
      ui.runInteractively(interp.getOptions().NoLogo);
   }

   // if we are running with -verify a reported has to be returned as unsuccess.
   // This is relevan especially for the test suite.
   if (CI->getDiagnosticOpts().VerifyDiagnostics)
     ret = !CI->getDiagnostics().getClient()->getNumErrors();

   return ret ? 0 : 1;
}
<commit_msg>In interactive mode act as a compiler - return !=0 if there were errors.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Lukasz Janyst <ljanyst@cern.ch>
//------------------------------------------------------------------------------

#include "cling/Interpreter/Interpreter.h"
#include "cling/MetaProcessor/MetaProcessor.h"
#include "cling/UserInterface/UserInterface.h"

#include "clang/Basic/LangOptions.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/HeaderSearchOptions.h"

#include "llvm/Support/Signals.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/ManagedStatic.h"

#include <iostream>
#include <vector>
#include <string>

int main( int argc, char **argv ) {

  llvm::llvm_shutdown_obj shutdownTrigger;

  //llvm::sys::PrintStackTraceOnErrorSignal();
  //llvm::PrettyStackTraceProgram X(argc, argv);

  // Set up the interpreter
  cling::Interpreter interp(argc, argv);
  if (interp.getOptions().Help) {
    return 0;
  }

  clang::CompilerInstance* CI = interp.getCI();
  interp.AddIncludePath(".");

  for (size_t I = 0, N = interp.getOptions().LibsToLoad.size(); I < N; ++I) {
    interp.loadFile(interp.getOptions().LibsToLoad[I]);
  }

   bool ret = true;
   const std::vector<clang::FrontendInputFile>& Inputs
     = CI->getInvocation().getFrontendOpts().Inputs;

   // Interactive means no input (or one input that's "-")
   bool Interactive = Inputs.empty() || (Inputs.size() == 1
                                         && Inputs[0].File == "-");

   cling::UserInterface ui(interp);
   // If we are not interactive we're supposed to parse files
   if (!Interactive) {
     for (size_t I = 0, N = Inputs.size(); I < N; ++I) {
       ui.getMetaProcessor()->process((".x " + Inputs[I].File).c_str());
       ret = !CI->getDiagnostics().getClient()->getNumErrors();
     }
   }
   else {
      cling::UserInterface ui(interp);
      ui.runInteractively(interp.getOptions().NoLogo);
   }

   // if we are running with -verify a reported has to be returned as unsuccess.
   // This is relevan especially for the test suite.
   if (CI->getDiagnosticOpts().VerifyDiagnostics)
     ret = !CI->getDiagnostics().getClient()->getNumErrors();

   return ret ? 0 : 1;
}
<|endoftext|>