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

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

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

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this library.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <QUrl>

#include "abstractmediaplayer.h"
#include "defs.h"
#include "mediaobject.h"
#include "utils.h"

QT_BEGIN_NAMESPACE

using namespace Phonon;
using namespace Phonon::MMF;

/*! \class MMF::AbstractMediaPlayer
  \internal
*/

//-----------------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------------

const int       NullMaxVolume = -1;
const int       BufferStatusTimerInterval = 100; // ms

//-----------------------------------------------------------------------------
// Constructor / destructor
//-----------------------------------------------------------------------------

MMF::AbstractMediaPlayer::AbstractMediaPlayer
    (MediaObject *parent, const AbstractPlayer *player)
        :   AbstractPlayer(player)
        ,   m_parent(parent)
        ,   m_playPending(false)
        ,   m_positionTimer(new QTimer(this))
        ,   m_bufferStatusTimer(new QTimer(this))
        ,   m_mmfMaxVolume(NullMaxVolume)
        ,   m_prefinishMarkSent(false)
        ,   m_aboutToFinishSent(false)
{
    connect(m_positionTimer.data(), SIGNAL(timeout()), this, SLOT(positionTick()));
    connect(m_bufferStatusTimer.data(), SIGNAL(timeout()), this, SLOT(bufferStatusTick()));
}

//-----------------------------------------------------------------------------
// MediaObjectInterface
//-----------------------------------------------------------------------------

void MMF::AbstractMediaPlayer::play()
{
    TRACE_CONTEXT(AbstractMediaPlayer::play, EAudioApi);
    TRACE_ENTRY("state %d", privateState());

    switch (privateState()) {
    case GroundState:
        setError(tr("Not ready to play"));
        break;

    case LoadingState:
        m_playPending = true;
        break;

    case StoppedState:
    case PausedState:
        doPlay();
        startPositionTimer();
        changeState(PlayingState);
        break;

    case PlayingState:
    case BufferingState:
    case ErrorState:
        // Do nothing
        break;

        // Protection against adding new states and forgetting to update this switch
    default:
        TRACE_PANIC(InvalidStatePanic);
    }

    TRACE_EXIT("state %d", privateState());
}

void MMF::AbstractMediaPlayer::pause()
{
    TRACE_CONTEXT(AbstractMediaPlayer::pause, EAudioApi);
    TRACE_ENTRY("state %d", privateState());

    m_playPending = false;
    stopTimers();

    switch (privateState()) {
    case GroundState:
    case LoadingState:
    case PausedState:
    case StoppedState:
        // Do nothing
        break;

    case PlayingState:
    case BufferingState:
        changeState(PausedState);
        // Fall through
    case ErrorState:
        doPause();
        break;

        // Protection against adding new states and forgetting to update this switch
    default:
        TRACE_PANIC(InvalidStatePanic);
    }

    TRACE_EXIT("state %d", privateState());
}

void MMF::AbstractMediaPlayer::stop()
{
    TRACE_CONTEXT(AbstractMediaPlayer::stop, EAudioApi);
    TRACE_ENTRY("state %d", privateState());

    m_playPending = false;
    stopTimers();

    switch (privateState()) {
    case GroundState:
    case LoadingState:
    case StoppedState:
    case ErrorState:
        // Do nothing
        break;

    case PlayingState:
    case BufferingState:
    case PausedState:
        doStop();
        changeState(StoppedState);
        break;

        // Protection against adding new states and forgetting to update this switch
    default:
        TRACE_PANIC(InvalidStatePanic);
    }

    TRACE_EXIT("state %d", privateState());
}

void MMF::AbstractMediaPlayer::seek(qint64 ms)
{
    TRACE_CONTEXT(AbstractMediaPlayer::seek, EAudioApi);
    TRACE_ENTRY("state %d pos %Ld", state(), ms);

    switch (privateState()) {
    // Fallthrough all these
    case GroundState:
    case StoppedState:
    case PausedState:
    case PlayingState:
    case LoadingState:
    {
        bool wasPlaying = false;
        if (state() == PlayingState) {
            stopPositionTimer();
            doPause();
            wasPlaying = true;
        }

        doSeek(ms);
        resetMarksIfRewound();

        if(wasPlaying && state() != ErrorState) {
            doPlay();
            startPositionTimer();
        }

        break;
    }
    case BufferingState:
    // Fallthrough
    case ErrorState:
        // Do nothing
        break;
    }

    TRACE_EXIT_0();
}

bool MMF::AbstractMediaPlayer::isSeekable() const
{
    return true;
}

void MMF::AbstractMediaPlayer::doSetTickInterval(qint32 interval)
{
    TRACE_CONTEXT(AbstractMediaPlayer::doSetTickInterval, EAudioApi);
    TRACE_ENTRY("state %d m_interval %d interval %d", privateState(), tickInterval(), interval);

    m_positionTimer->setInterval(interval);

    TRACE_EXIT_0();
}

void MMF::AbstractMediaPlayer::open(const MediaSource &source, RFile& file)
{
    TRACE_CONTEXT(AbstractMediaPlayer::setFileSource, EAudioApi);
    TRACE_ENTRY("state %d source.type %d", privateState(), source.type());

    close();
    changeState(GroundState);

    TInt symbianErr = KErrNone;
    QString errorMessage;

    switch (source.type()) {
    case MediaSource::LocalFile: {
        symbianErr = openFile(file);
        if (KErrNone != symbianErr)
            errorMessage = tr("Error opening file");
        break;
    }

    case MediaSource::Url: {
        const QUrl url(source.url());

        if (url.scheme() == QLatin1String("file")) {
            symbianErr = openFile(file);
            if (KErrNone != symbianErr)
                errorMessage = tr("Error opening file");
        } else {
            symbianErr = openUrl(url.toString());
            if (KErrNone != symbianErr)
                errorMessage = tr("Error opening URL");
        }

        break;
    }

    case MediaSource::Invalid:
    case MediaSource::Disc:
    case MediaSource::Stream:
        TRACE_0("Error opening source: type not supported");
        errorMessage = tr("Error opening source: type not supported");
        break;

    case MediaSource::Empty:
        TRACE_0("Empty source - doing nothing");
        TRACE_EXIT_0();
        return;

        // Protection against adding new media types and forgetting to update this switch
    default:
        TRACE_PANIC(InvalidMediaTypePanic);
    }

    if (errorMessage.isEmpty()) {
        changeState(LoadingState);
    } else {
        if (symbianErr)
            setError(errorMessage, symbianErr);
        else
            setError(errorMessage);
    }

    TRACE_EXIT_0();
}

void MMF::AbstractMediaPlayer::volumeChanged(qreal volume)
{
    TRACE_CONTEXT(AbstractMediaPlayer::volumeChanged, EAudioInternal);
    TRACE_ENTRY("state %d", privateState());

    AbstractPlayer::volumeChanged(volume);
    doVolumeChanged();

    TRACE_EXIT_0();
}

//-----------------------------------------------------------------------------
// Private functions
//-----------------------------------------------------------------------------

void MMF::AbstractMediaPlayer::startPositionTimer()
{
    m_positionTimer->start(tickInterval());
}

void MMF::AbstractMediaPlayer::stopPositionTimer()
{
    m_positionTimer->stop();
}

void MMF::AbstractMediaPlayer::startBufferStatusTimer()
{
    m_bufferStatusTimer->start(BufferStatusTimerInterval);
}

void MMF::AbstractMediaPlayer::stopBufferStatusTimer()
{
    m_bufferStatusTimer->stop();
}

void MMF::AbstractMediaPlayer::stopTimers()
{
    stopPositionTimer();
    stopBufferStatusTimer();
}

void MMF::AbstractMediaPlayer::doVolumeChanged()
{
    switch (privateState()) {
    case GroundState:
    case LoadingState:
    case ErrorState:
        // Do nothing
        break;

    case StoppedState:
    case PausedState:
    case PlayingState:
    case BufferingState: {
        const qreal volume = (m_volume * m_mmfMaxVolume) + 0.5;
        const int err = setDeviceVolume(volume);

        if (KErrNone != err) {
            setError(tr("Setting volume failed"), err);
        }
        break;
    }

    // Protection against adding new states and forgetting to update this
    // switch
    default:
        Utils::panic(InvalidStatePanic);
    }
}

//-----------------------------------------------------------------------------
// Protected functions
//-----------------------------------------------------------------------------

void MMF::AbstractMediaPlayer::bufferingStarted()
{
    m_stateBeforeBuffering = privateState();
    changeState(BufferingState);
    bufferStatusTick();
    startBufferStatusTimer();
}

void MMF::AbstractMediaPlayer::bufferingComplete()
{
    stopBufferStatusTimer();
    emit MMF::AbstractPlayer::bufferStatus(100);
    changeState(m_stateBeforeBuffering);
}

void MMF::AbstractMediaPlayer::maxVolumeChanged(int mmfMaxVolume)
{
    m_mmfMaxVolume = mmfMaxVolume;
    doVolumeChanged();
}

void MMF::AbstractMediaPlayer::playbackComplete(int error)
{
    stopTimers();

    if (KErrNone == error) {
        changeState(StoppedState);

        // MediaObject::switchToNextSource deletes the current player, so we
        // call it via delayed slot invokation to ensure that this object does
        // not get deleted during execution of a member function.
        QMetaObject::invokeMethod(m_parent, "switchToNextSource", Qt::QueuedConnection);
    }
    else {
        setError(tr("Playback complete"), error);
    }
}

qint64 MMF::AbstractMediaPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds &in)
{
    return in.Int64() / 1000;
}

//-----------------------------------------------------------------------------
// Slots
//-----------------------------------------------------------------------------

void MMF::AbstractMediaPlayer::positionTick()
{
    emitMarksIfReached();

    const qint64 current = currentTime();
    emit MMF::AbstractPlayer::tick(current);
}

void MMF::AbstractMediaPlayer::emitMarksIfReached()
{
    const qint64 current = currentTime();
    const qint64 total = totalTime();
    const qint64 remaining = total - current;

    if (prefinishMark() && !m_prefinishMarkSent) {
        if (remaining < (prefinishMark() + tickInterval()/2)) {
            m_prefinishMarkSent = true;
            emit prefinishMarkReached(remaining);
        }
    }

    if (!m_aboutToFinishSent) {
        if (remaining < tickInterval()) {
            m_aboutToFinishSent = true;
            emit aboutToFinish();
        }
    }
}

void MMF::AbstractMediaPlayer::resetMarksIfRewound()
{
    const qint64 current = currentTime();
    const qint64 total = totalTime();
    const qint64 remaining = total - current;

    if (prefinishMark() && m_prefinishMarkSent)
        if (remaining >= (prefinishMark() + tickInterval()/2))
            m_prefinishMarkSent = false;

    if (m_aboutToFinishSent)
        if (remaining >= tickInterval())
            m_aboutToFinishSent = false;
}

void MMF::AbstractMediaPlayer::bufferStatusTick()
{
    emit MMF::AbstractPlayer::bufferStatus(bufferStatus());
}

void MMF::AbstractMediaPlayer::changeState(PrivateState newState)
{
    TRACE_CONTEXT(AbstractMediaPlayer::changeState, EAudioInternal);

    const Phonon::State oldPhononState = phononState(privateState());
    const Phonon::State newPhononState = phononState(newState);

    // TODO: add some invariants to check that the transition is valid
    AbstractPlayer::changeState(newState);

    if (LoadingState == oldPhononState && StoppedState == newPhononState) {
        // Ensure initial volume is set on MMF API before starting playback
        doVolumeChanged();

        // Check whether play() was called while clip was being loaded.  If so,
        // playback should be started now
        if (m_playPending) {
            TRACE_0("play was called while loading; starting playback now");
            m_playPending = false;
            play();
        }
    }
}

void MMF::AbstractMediaPlayer::updateMetaData()
{
    TRACE_CONTEXT(AbstractMediaPlayer::updateMetaData, EAudioInternal);
    TRACE_ENTRY_0();

    m_metaData.clear();

    const int numberOfEntries = numberOfMetaDataEntries();
    for(int i=0; i<numberOfEntries; ++i) {
        const QPair<QString, QString> entry = metaDataEntry(i);

        // Note that we capitalize the key, as required by the Ogg Vorbis
        // metadata standard to which Phonon adheres:
        // http://xiph.org/vorbis/doc/v-comment.html
        m_metaData.insert(entry.first.toUpper(), entry.second);
    }

    emit metaDataChanged(m_metaData);

    TRACE_EXIT_0();
}

QT_END_NAMESPACE

<commit_msg>Removed dead code from Phonon MMF backend<commit_after>/*  This file is part of the KDE project.

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

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

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this library.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <QUrl>

#include "abstractmediaplayer.h"
#include "defs.h"
#include "mediaobject.h"
#include "utils.h"

QT_BEGIN_NAMESPACE

using namespace Phonon;
using namespace Phonon::MMF;

/*! \class MMF::AbstractMediaPlayer
  \internal
*/

//-----------------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------------

const int       NullMaxVolume = -1;
const int       BufferStatusTimerInterval = 100; // ms

//-----------------------------------------------------------------------------
// Constructor / destructor
//-----------------------------------------------------------------------------

MMF::AbstractMediaPlayer::AbstractMediaPlayer
    (MediaObject *parent, const AbstractPlayer *player)
        :   AbstractPlayer(player)
        ,   m_parent(parent)
        ,   m_playPending(false)
        ,   m_positionTimer(new QTimer(this))
        ,   m_bufferStatusTimer(new QTimer(this))
        ,   m_mmfMaxVolume(NullMaxVolume)
        ,   m_prefinishMarkSent(false)
        ,   m_aboutToFinishSent(false)
{
    connect(m_positionTimer.data(), SIGNAL(timeout()), this, SLOT(positionTick()));
    connect(m_bufferStatusTimer.data(), SIGNAL(timeout()), this, SLOT(bufferStatusTick()));
}

//-----------------------------------------------------------------------------
// MediaObjectInterface
//-----------------------------------------------------------------------------

void MMF::AbstractMediaPlayer::play()
{
    TRACE_CONTEXT(AbstractMediaPlayer::play, EAudioApi);
    TRACE_ENTRY("state %d", privateState());

    switch (privateState()) {
    case GroundState:
        setError(tr("Not ready to play"));
        break;

    case LoadingState:
        m_playPending = true;
        break;

    case StoppedState:
    case PausedState:
        doPlay();
        startPositionTimer();
        changeState(PlayingState);
        break;

    case PlayingState:
    case BufferingState:
    case ErrorState:
        // Do nothing
        break;

        // Protection against adding new states and forgetting to update this switch
    default:
        TRACE_PANIC(InvalidStatePanic);
    }

    TRACE_EXIT("state %d", privateState());
}

void MMF::AbstractMediaPlayer::pause()
{
    TRACE_CONTEXT(AbstractMediaPlayer::pause, EAudioApi);
    TRACE_ENTRY("state %d", privateState());

    m_playPending = false;
    stopTimers();

    switch (privateState()) {
    case GroundState:
    case LoadingState:
    case PausedState:
    case StoppedState:
        // Do nothing
        break;

    case PlayingState:
    case BufferingState:
        changeState(PausedState);
        // Fall through
    case ErrorState:
        doPause();
        break;

        // Protection against adding new states and forgetting to update this switch
    default:
        TRACE_PANIC(InvalidStatePanic);
    }

    TRACE_EXIT("state %d", privateState());
}

void MMF::AbstractMediaPlayer::stop()
{
    TRACE_CONTEXT(AbstractMediaPlayer::stop, EAudioApi);
    TRACE_ENTRY("state %d", privateState());

    m_playPending = false;
    stopTimers();

    switch (privateState()) {
    case GroundState:
    case LoadingState:
    case StoppedState:
    case ErrorState:
        // Do nothing
        break;

    case PlayingState:
    case BufferingState:
    case PausedState:
        doStop();
        changeState(StoppedState);
        break;

        // Protection against adding new states and forgetting to update this switch
    default:
        TRACE_PANIC(InvalidStatePanic);
    }

    TRACE_EXIT("state %d", privateState());
}

void MMF::AbstractMediaPlayer::seek(qint64 ms)
{
    TRACE_CONTEXT(AbstractMediaPlayer::seek, EAudioApi);
    TRACE_ENTRY("state %d pos %Ld", state(), ms);

    switch (privateState()) {
    // Fallthrough all these
    case GroundState:
    case StoppedState:
    case PausedState:
    case PlayingState:
    case LoadingState:
    {
        bool wasPlaying = false;
        if (state() == PlayingState) {
            stopPositionTimer();
            doPause();
            wasPlaying = true;
        }

        doSeek(ms);
        resetMarksIfRewound();

        if(wasPlaying && state() != ErrorState) {
            doPlay();
            startPositionTimer();
        }

        break;
    }
    case BufferingState:
    // Fallthrough
    case ErrorState:
        // Do nothing
        break;
    }

    TRACE_EXIT_0();
}

bool MMF::AbstractMediaPlayer::isSeekable() const
{
    return true;
}

void MMF::AbstractMediaPlayer::doSetTickInterval(qint32 interval)
{
    TRACE_CONTEXT(AbstractMediaPlayer::doSetTickInterval, EAudioApi);
    TRACE_ENTRY("state %d m_interval %d interval %d", privateState(), tickInterval(), interval);

    m_positionTimer->setInterval(interval);

    TRACE_EXIT_0();
}

void MMF::AbstractMediaPlayer::open(const MediaSource &source, RFile& file)
{
    TRACE_CONTEXT(AbstractMediaPlayer::setFileSource, EAudioApi);
    TRACE_ENTRY("state %d source.type %d", privateState(), source.type());

    close();
    changeState(GroundState);

    TInt symbianErr = KErrNone;
    QString errorMessage;

    switch (source.type()) {
    case MediaSource::LocalFile: {
        symbianErr = openFile(file);
        if (KErrNone != symbianErr)
            errorMessage = tr("Error opening file");
        break;
    }

    case MediaSource::Url: {
        const QUrl url(source.url());

        if (url.scheme() == QLatin1String("file")) {
            symbianErr = openFile(file);
            if (KErrNone != symbianErr)
                errorMessage = tr("Error opening file");
        } else {
            symbianErr = openUrl(url.toString());
            if (KErrNone != symbianErr)
                errorMessage = tr("Error opening URL");
        }

        break;
    }

    // Other source types are handled in MediaObject::createPlayer

    // Protection against adding new media types and forgetting to update this switch
    default:
        TRACE_PANIC(InvalidMediaTypePanic);
    }

    if (errorMessage.isEmpty()) {
        changeState(LoadingState);
    } else {
        if (symbianErr)
            setError(errorMessage, symbianErr);
        else
            setError(errorMessage);
    }

    TRACE_EXIT_0();
}

void MMF::AbstractMediaPlayer::volumeChanged(qreal volume)
{
    TRACE_CONTEXT(AbstractMediaPlayer::volumeChanged, EAudioInternal);
    TRACE_ENTRY("state %d", privateState());

    AbstractPlayer::volumeChanged(volume);
    doVolumeChanged();

    TRACE_EXIT_0();
}

//-----------------------------------------------------------------------------
// Private functions
//-----------------------------------------------------------------------------

void MMF::AbstractMediaPlayer::startPositionTimer()
{
    m_positionTimer->start(tickInterval());
}

void MMF::AbstractMediaPlayer::stopPositionTimer()
{
    m_positionTimer->stop();
}

void MMF::AbstractMediaPlayer::startBufferStatusTimer()
{
    m_bufferStatusTimer->start(BufferStatusTimerInterval);
}

void MMF::AbstractMediaPlayer::stopBufferStatusTimer()
{
    m_bufferStatusTimer->stop();
}

void MMF::AbstractMediaPlayer::stopTimers()
{
    stopPositionTimer();
    stopBufferStatusTimer();
}

void MMF::AbstractMediaPlayer::doVolumeChanged()
{
    switch (privateState()) {
    case GroundState:
    case LoadingState:
    case ErrorState:
        // Do nothing
        break;

    case StoppedState:
    case PausedState:
    case PlayingState:
    case BufferingState: {
        const qreal volume = (m_volume * m_mmfMaxVolume) + 0.5;
        const int err = setDeviceVolume(volume);

        if (KErrNone != err) {
            setError(tr("Setting volume failed"), err);
        }
        break;
    }

    // Protection against adding new states and forgetting to update this
    // switch
    default:
        Utils::panic(InvalidStatePanic);
    }
}

//-----------------------------------------------------------------------------
// Protected functions
//-----------------------------------------------------------------------------

void MMF::AbstractMediaPlayer::bufferingStarted()
{
    m_stateBeforeBuffering = privateState();
    changeState(BufferingState);
    bufferStatusTick();
    startBufferStatusTimer();
}

void MMF::AbstractMediaPlayer::bufferingComplete()
{
    stopBufferStatusTimer();
    emit MMF::AbstractPlayer::bufferStatus(100);
    changeState(m_stateBeforeBuffering);
}

void MMF::AbstractMediaPlayer::maxVolumeChanged(int mmfMaxVolume)
{
    m_mmfMaxVolume = mmfMaxVolume;
    doVolumeChanged();
}

void MMF::AbstractMediaPlayer::playbackComplete(int error)
{
    stopTimers();

    if (KErrNone == error) {
        changeState(StoppedState);

        // MediaObject::switchToNextSource deletes the current player, so we
        // call it via delayed slot invokation to ensure that this object does
        // not get deleted during execution of a member function.
        QMetaObject::invokeMethod(m_parent, "switchToNextSource", Qt::QueuedConnection);
    }
    else {
        setError(tr("Playback complete"), error);
    }
}

qint64 MMF::AbstractMediaPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds &in)
{
    return in.Int64() / 1000;
}

//-----------------------------------------------------------------------------
// Slots
//-----------------------------------------------------------------------------

void MMF::AbstractMediaPlayer::positionTick()
{
    emitMarksIfReached();

    const qint64 current = currentTime();
    emit MMF::AbstractPlayer::tick(current);
}

void MMF::AbstractMediaPlayer::emitMarksIfReached()
{
    const qint64 current = currentTime();
    const qint64 total = totalTime();
    const qint64 remaining = total - current;

    if (prefinishMark() && !m_prefinishMarkSent) {
        if (remaining < (prefinishMark() + tickInterval()/2)) {
            m_prefinishMarkSent = true;
            emit prefinishMarkReached(remaining);
        }
    }

    if (!m_aboutToFinishSent) {
        if (remaining < tickInterval()) {
            m_aboutToFinishSent = true;
            emit aboutToFinish();
        }
    }
}

void MMF::AbstractMediaPlayer::resetMarksIfRewound()
{
    const qint64 current = currentTime();
    const qint64 total = totalTime();
    const qint64 remaining = total - current;

    if (prefinishMark() && m_prefinishMarkSent)
        if (remaining >= (prefinishMark() + tickInterval()/2))
            m_prefinishMarkSent = false;

    if (m_aboutToFinishSent)
        if (remaining >= tickInterval())
            m_aboutToFinishSent = false;
}

void MMF::AbstractMediaPlayer::bufferStatusTick()
{
    emit MMF::AbstractPlayer::bufferStatus(bufferStatus());
}

void MMF::AbstractMediaPlayer::changeState(PrivateState newState)
{
    TRACE_CONTEXT(AbstractMediaPlayer::changeState, EAudioInternal);

    const Phonon::State oldPhononState = phononState(privateState());
    const Phonon::State newPhononState = phononState(newState);

    // TODO: add some invariants to check that the transition is valid
    AbstractPlayer::changeState(newState);

    if (LoadingState == oldPhononState && StoppedState == newPhononState) {
        // Ensure initial volume is set on MMF API before starting playback
        doVolumeChanged();

        // Check whether play() was called while clip was being loaded.  If so,
        // playback should be started now
        if (m_playPending) {
            TRACE_0("play was called while loading; starting playback now");
            m_playPending = false;
            play();
        }
    }
}

void MMF::AbstractMediaPlayer::updateMetaData()
{
    TRACE_CONTEXT(AbstractMediaPlayer::updateMetaData, EAudioInternal);
    TRACE_ENTRY_0();

    m_metaData.clear();

    const int numberOfEntries = numberOfMetaDataEntries();
    for(int i=0; i<numberOfEntries; ++i) {
        const QPair<QString, QString> entry = metaDataEntry(i);

        // Note that we capitalize the key, as required by the Ogg Vorbis
        // metadata standard to which Phonon adheres:
        // http://xiph.org/vorbis/doc/v-comment.html
        m_metaData.insert(entry.first.toUpper(), entry.second);
    }

    emit metaDataChanged(m_metaData);

    TRACE_EXIT_0();
}

QT_END_NAMESPACE

<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkPainterPolyDataMapper.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkPainterPolyDataMapper.h"

#include "vtkChooserPainter.h"
#include "vtkClipPlanesPainter.h"
#include "vtkCoincidentTopologyResolutionPainter.h"
#include "vtkCommand.h"
#include "vtkDefaultPainter.h"
#include "vtkDisplayListPainter.h"
#include "vtkGarbageCollector.h"
#include "vtkGenericVertexAttributeMapping.h"
#include "vtkHardwareSelectionPolyDataPainter.h"
#include "vtkInformation.h"
#include "vtkInformationObjectBaseKey.h"
#include "vtkInformationVector.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkPlaneCollection.h"
#include "vtkPolyData.h"
#include "vtkPrimitivePainter.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkScalarsToColorsPainter.h"
#include "vtkStandardPolyDataPainter.h"

vtkStandardNewMacro(vtkPainterPolyDataMapper);
//-----------------------------------------------------------------------------
class vtkPainterPolyDataMapperObserver : public vtkCommand
{
public:
  static vtkPainterPolyDataMapperObserver* New()
    { return new vtkPainterPolyDataMapperObserver; }

  virtual void Execute(vtkObject* caller, unsigned long event, void*)
    {
    vtkPainter* p = vtkPainter::SafeDownCast(caller);
    if (this->Target && p && event == vtkCommand::ProgressEvent)
      {
      this->Target->UpdateProgress(p->GetProgress());
      }
    }
  vtkPainterPolyDataMapperObserver()
    {
    this->Target = 0;
    }
  vtkPainterPolyDataMapper* Target;
};

//-----------------------------------------------------------------------------
vtkPainterPolyDataMapper::vtkPainterPolyDataMapper()
{
  this->Painter = 0;

  this->PainterInformation = vtkInformation::New();

  this->Observer = vtkPainterPolyDataMapperObserver::New();
  this->Observer->Target = this;

  vtkDefaultPainter* dp = vtkDefaultPainter::New();
  this->SetPainter(dp);
  dp->Delete();

  vtkChooserPainter* cp = vtkChooserPainter::New();
  this->Painter->SetDelegatePainter(cp);
  cp->Delete();

  this->SelectionPainter = 0;
  vtkPainter* selPainter = vtkHardwareSelectionPolyDataPainter::New();
  this->SetSelectionPainter(selPainter);
  selPainter->Delete();
}

//-----------------------------------------------------------------------------
vtkPainterPolyDataMapper::~vtkPainterPolyDataMapper()
{
  this->SetPainter(NULL);
  this->SetSelectionPainter(0);
  this->Observer->Target = NULL;
  this->Observer->Delete();
  this->PainterInformation->Delete();
}

//---------------------------------------------------------------------------
void vtkPainterPolyDataMapper::MapDataArrayToVertexAttribute(
  const char* vertexAttributeName,
  const char* dataArrayName,
  int field,
  int componentno)
{
  vtkGenericVertexAttributeMapping* mappings = 0;
  if( this->PainterInformation->Has(
      vtkPrimitivePainter::DATA_ARRAY_TO_VERTEX_ATTRIBUTE()) )
    {
    mappings = vtkGenericVertexAttributeMapping::SafeDownCast(
      this->PainterInformation->Get(
        vtkPolyDataPainter::DATA_ARRAY_TO_VERTEX_ATTRIBUTE()));
    }

  if (mappings==NULL)
    {
    mappings = vtkGenericVertexAttributeMapping::New();
    this->PainterInformation->Set(
      vtkPolyDataPainter::DATA_ARRAY_TO_VERTEX_ATTRIBUTE(), mappings);
    mappings->Delete();
    }

  mappings->AddMapping(
    vertexAttributeName, dataArrayName, field, componentno);
}

//---------------------------------------------------------------------------
void vtkPainterPolyDataMapper::MapDataArrayToMultiTextureAttribute(
  int unit,
  const char* dataArrayName,
  int field,
  int componentno)
{
  vtkGenericVertexAttributeMapping* mappings = 0;
  if( this->PainterInformation->Has(
      vtkPrimitivePainter::DATA_ARRAY_TO_VERTEX_ATTRIBUTE()) )
    {
    mappings = vtkGenericVertexAttributeMapping::SafeDownCast(
      this->PainterInformation->Get(
        vtkPolyDataPainter::DATA_ARRAY_TO_VERTEX_ATTRIBUTE()));
    }

  if (mappings==NULL)
    {
    mappings = vtkGenericVertexAttributeMapping::New();
    this->PainterInformation->Set(
      vtkPolyDataPainter::DATA_ARRAY_TO_VERTEX_ATTRIBUTE(), mappings);
    mappings->Delete();
    }

  mappings->AddMapping(
    unit, dataArrayName, field, componentno);
}

//-----------------------------------------------------------------------------
void vtkPainterPolyDataMapper::RemoveAllVertexAttributeMappings()
{
  vtkGenericVertexAttributeMapping* mappings = 0;
  if( this->PainterInformation->Has(
      vtkPrimitivePainter::DATA_ARRAY_TO_VERTEX_ATTRIBUTE()) )
    {
    mappings = vtkGenericVertexAttributeMapping::SafeDownCast(
      this->PainterInformation->Get(
        vtkPolyDataPainter::DATA_ARRAY_TO_VERTEX_ATTRIBUTE()));
    mappings->RemoveAllMappings();
    }
}

//-----------------------------------------------------------------------------
void vtkPainterPolyDataMapper::RemoveVertexAttributeMapping(
  const char* vertexAttributeName)
{
  vtkGenericVertexAttributeMapping* mappings = 0;
  if( this->PainterInformation->Has(
      vtkPrimitivePainter::DATA_ARRAY_TO_VERTEX_ATTRIBUTE()) )
    {
    mappings = vtkGenericVertexAttributeMapping::SafeDownCast(
      this->PainterInformation->Get(
        vtkPolyDataPainter::DATA_ARRAY_TO_VERTEX_ATTRIBUTE()));
    mappings->RemoveMapping(vertexAttributeName);
    }
}

//-----------------------------------------------------------------------------
void vtkPainterPolyDataMapper::SetPainter(vtkPainter* p)
{
  if (this->Painter)
    {
    this->Painter->RemoveObservers(vtkCommand::ProgressEvent, this->Observer);
    this->Painter->SetInformation(0);
    }
  vtkSetObjectBodyMacro(Painter, vtkPainter, p);

   if (this->Painter)
    {
    this->Painter->AddObserver(vtkCommand::ProgressEvent, this->Observer);
    this->Painter->SetInformation(this->PainterInformation);
    }
}

//-----------------------------------------------------------------------------
void vtkPainterPolyDataMapper::SetSelectionPainter(vtkPainter* p)
{
  if (this->SelectionPainter)
    {
    this->SelectionPainter->SetInformation(0);
    this->SelectionPainter->RemoveObservers(vtkCommand::ProgressEvent, this->Observer);
    }
  vtkSetObjectBodyMacro(SelectionPainter, vtkPainter, p);
   if (this->SelectionPainter)
    {
    this->SelectionPainter->AddObserver(vtkCommand::ProgressEvent, this->Observer);
    this->SelectionPainter->SetInformation(this->PainterInformation);
    }
}

//-----------------------------------------------------------------------------
void vtkPainterPolyDataMapper::ReportReferences(vtkGarbageCollector *collector)
{
  this->Superclass::ReportReferences(collector);
  vtkGarbageCollectorReport(collector, this->Painter, "Painter");
  vtkGarbageCollectorReport(collector, this->SelectionPainter, "SelectionPainter");
}

//-----------------------------------------------------------------------------
void vtkPainterPolyDataMapper::ReleaseGraphicsResources(vtkWindow *w)
{
  if (this->Painter)
    {
    this->Painter->ReleaseGraphicsResources(w);
    }
}

//-----------------------------------------------------------------------------
void vtkPainterPolyDataMapper::UpdatePainterInformation()
{
  vtkInformation* info = this->PainterInformation;

  info->Set(vtkPainter::STATIC_DATA(), this->Static);

  info->Set(vtkScalarsToColorsPainter::USE_LOOKUP_TABLE_SCALAR_RANGE(),
    this->GetUseLookupTableScalarRange());
  info->Set(vtkScalarsToColorsPainter::SCALAR_RANGE(),
    this->GetScalarRange(), 2);
  info->Set(vtkScalarsToColorsPainter::SCALAR_MODE(), this->GetScalarMode());
  info->Set(vtkScalarsToColorsPainter::COLOR_MODE(), this->GetColorMode());
  info->Set(vtkScalarsToColorsPainter::INTERPOLATE_SCALARS_BEFORE_MAPPING(),
    this->GetInterpolateScalarsBeforeMapping());
  info->Set(vtkScalarsToColorsPainter::LOOKUP_TABLE(), this->LookupTable);
  info->Set(vtkScalarsToColorsPainter::SCALAR_VISIBILITY(),
    this->GetScalarVisibility());
  info->Set(vtkScalarsToColorsPainter::ARRAY_ACCESS_MODE(),
    this->ArrayAccessMode);
  info->Set(vtkScalarsToColorsPainter::ARRAY_ID(), this->ArrayId);
  info->Set(vtkScalarsToColorsPainter::ARRAY_NAME(), this->ArrayName);
  info->Set(vtkScalarsToColorsPainter::ARRAY_COMPONENT(), this->ArrayComponent);
  info->Set(vtkScalarsToColorsPainter::SCALAR_MATERIAL_MODE(),
    this->GetScalarMaterialMode());

  info->Set(vtkClipPlanesPainter::CLIPPING_PLANES(), this->ClippingPlanes);

  info->Set(vtkCoincidentTopologyResolutionPainter::RESOLVE_COINCIDENT_TOPOLOGY(),
    this->GetResolveCoincidentTopology());
  info->Set(vtkCoincidentTopologyResolutionPainter::Z_SHIFT(),
    this->GetResolveCoincidentTopologyZShift());
  double p[2];
  this->GetResolveCoincidentTopologyPolygonOffsetParameters(p[0], p[1]);
  info->Set(vtkCoincidentTopologyResolutionPainter::POLYGON_OFFSET_PARAMETERS(),
    p, 2);
  info->Set(vtkCoincidentTopologyResolutionPainter::POLYGON_OFFSET_FACES(),
    this->GetResolveCoincidentTopologyPolygonOffsetFaces());

  int immr = (this->ImmediateModeRendering ||
              vtkMapper::GetGlobalImmediateModeRendering());
  info->Set(vtkDisplayListPainter::IMMEDIATE_MODE_RENDERING(), immr);
}

//-----------------------------------------------------------------------------
void vtkPainterPolyDataMapper::RenderPiece(vtkRenderer* ren, vtkActor* act)
{
  vtkDataObject *input= this->GetInputDataObject(0, 0);

   vtkStandardPolyDataPainter * painter =
    vtkStandardPolyDataPainter::SafeDownCast(this->Painter);
  if (painter != NULL && vtkPolyData::SafeDownCast(input))
    {
    // FIXME: This is not supported currently for composite datasets.
    vtkInformationVector *inArrayVec =
      this->Information->Get(INPUT_ARRAYS_TO_PROCESS());
    int numArrays = inArrayVec->GetNumberOfInformationObjects();

    for(int i = 0; i < numArrays; i++)
      {
      painter->AddMultiTextureCoordsArray(this->GetInputArrayToProcess(i,input));
      }
    }

  //
  // make sure that we've been properly initialized
  //
  if (ren->GetRenderWindow()->CheckAbortStatus())
    {
    return;
    }

  if ( input == NULL )
    {
    vtkErrorMacro(<< "No input!");
    return;
    }
  else
    {
    this->InvokeEvent(vtkCommand::StartEvent,NULL);
    if (!this->Static)
      {
      this->GetInputAlgorithm()->Update();
      }
    this->InvokeEvent(vtkCommand::EndEvent,NULL);

    // This check is unnecessary since the mapper will be cropped out by culling
    // if it returns invalid bounds which is what will happen when input has no
    // points.
    // vtkIdType numPts = input->GetNumberOfPoints();
    // if (numPts == 0)
    //   {
    //   vtkDebugMacro(<< "No points!");
    //   return;
    //   }
    }

  // Update Painter information if obsolete.
  if (this->PainterUpdateTime < this->GetMTime())
    {
    this->UpdatePainterInformation();
    this->PainterUpdateTime.Modified();
    }

  // make sure our window is current
  ren->GetRenderWindow()->MakeCurrent();
  this->TimeToDraw = 0.0;

  // If we are rendering in selection mode, then we use the selection painter
  // instead of the standard painter.
  if (this->SelectionPainter && ren->GetSelector())
    {
    this->SelectionPainter->SetInput(input);
    this->SelectionPainter->Render(ren, act, 0xff,
      (this->ForceCompileOnly==1));
    this->TimeToDraw = this->SelectionPainter->GetTimeToDraw();
    }
  else if (this->SelectionPainter && this->SelectionPainter != this->Painter)
    {
    this->SelectionPainter->ReleaseGraphicsResources(ren->GetRenderWindow());
    }

  if (this->Painter && ren->GetSelector() == 0)
    {
    // Pass polydata.
    this->Painter->SetInput(input);
    this->Painter->Render(ren, act, 0xff,this->ForceCompileOnly==1);
    this->TimeToDraw = this->Painter->GetTimeToDraw();
    }

  // If the timer is not accurate enough, set it to a small
  // time so that it is not zero
  if ( this->TimeToDraw == 0.0 )
    {
    this->TimeToDraw = 0.0001;
    }

  this->UpdateProgress(1.0);
}

//-------------------------------------------------------------------------
void vtkPainterPolyDataMapper::ComputeBounds()
{
  this->GetInput()->GetBounds(this->Bounds);

  // if the mapper has a painter, update the bounds in the painter
  vtkPainter *painter = this->GetPainter();
  if (painter)
    {
    // Update Painter information if obsolete.
    if (this->PainterUpdateTime < this->GetMTime())
      {
      this->UpdatePainterInformation();
      this->PainterUpdateTime.Modified();
      }
    painter->UpdateBounds(this->Bounds);
    }
}

//-----------------------------------------------------------------------------
bool vtkPainterPolyDataMapper::GetIsOpaque()
{
  if (this->ScalarVisibility &&
    this->ColorMode == VTK_COLOR_MODE_DEFAULT)
    {
    vtkPolyData* input =
      vtkPolyData::SafeDownCast(this->GetInputDataObject(0, 0));
    if (input)
      {
      int cellFlag;
      vtkDataArray* scalars = this->GetScalars(input,
        this->ScalarMode, this->ArrayAccessMode, this->ArrayId,
        this->ArrayName, cellFlag);
      if (scalars && scalars->IsA("vtkUnsignedCharArray") &&
        (scalars->GetNumberOfComponents() ==  4 /*(RGBA)*/ ||
         scalars->GetNumberOfComponents() == 2 /*(LuminanceAlpha)*/))
        {
        vtkUnsignedCharArray* colors =
          static_cast<vtkUnsignedCharArray*>(scalars);
        if ((colors->GetNumberOfComponents() == 4 && colors->GetValueRange(3)[0] < 255) ||
          (colors->GetNumberOfComponents() == 2 && colors->GetValueRange(1)[0] < 255))
          {
          // If the opacity is 255, despite the fact that the user specified
          // RGBA, we know that the Alpha is 100% opaque. So treat as opaque.
          return false;
          }
        }
      }
    }
  return this->Superclass::GetIsOpaque();
}

//-----------------------------------------------------------------------------
void vtkPainterPolyDataMapper::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  os << indent << "Painter: " ;
  if (this->Painter)
    {
    os << endl;
    this->Painter->PrintSelf(os, indent.GetNextIndent());
    }
  else
    {
    os << indent << "(none)" << endl;
    }
  os << indent << "SelectionPainter: " << this->SelectionPainter << endl;
}
<commit_msg>BUG #14273: Don't segfault when mapper has empty input.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkPainterPolyDataMapper.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkPainterPolyDataMapper.h"

#include "vtkChooserPainter.h"
#include "vtkClipPlanesPainter.h"
#include "vtkCoincidentTopologyResolutionPainter.h"
#include "vtkCommand.h"
#include "vtkDefaultPainter.h"
#include "vtkDisplayListPainter.h"
#include "vtkGarbageCollector.h"
#include "vtkGenericVertexAttributeMapping.h"
#include "vtkHardwareSelectionPolyDataPainter.h"
#include "vtkInformation.h"
#include "vtkInformationObjectBaseKey.h"
#include "vtkInformationVector.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkPlaneCollection.h"
#include "vtkPolyData.h"
#include "vtkPrimitivePainter.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkScalarsToColorsPainter.h"
#include "vtkStandardPolyDataPainter.h"

vtkStandardNewMacro(vtkPainterPolyDataMapper);
//-----------------------------------------------------------------------------
class vtkPainterPolyDataMapperObserver : public vtkCommand
{
public:
  static vtkPainterPolyDataMapperObserver* New()
    { return new vtkPainterPolyDataMapperObserver; }

  virtual void Execute(vtkObject* caller, unsigned long event, void*)
    {
    vtkPainter* p = vtkPainter::SafeDownCast(caller);
    if (this->Target && p && event == vtkCommand::ProgressEvent)
      {
      this->Target->UpdateProgress(p->GetProgress());
      }
    }
  vtkPainterPolyDataMapperObserver()
    {
    this->Target = 0;
    }
  vtkPainterPolyDataMapper* Target;
};

//-----------------------------------------------------------------------------
vtkPainterPolyDataMapper::vtkPainterPolyDataMapper()
{
  this->Painter = 0;

  this->PainterInformation = vtkInformation::New();

  this->Observer = vtkPainterPolyDataMapperObserver::New();
  this->Observer->Target = this;

  vtkDefaultPainter* dp = vtkDefaultPainter::New();
  this->SetPainter(dp);
  dp->Delete();

  vtkChooserPainter* cp = vtkChooserPainter::New();
  this->Painter->SetDelegatePainter(cp);
  cp->Delete();

  this->SelectionPainter = 0;
  vtkPainter* selPainter = vtkHardwareSelectionPolyDataPainter::New();
  this->SetSelectionPainter(selPainter);
  selPainter->Delete();
}

//-----------------------------------------------------------------------------
vtkPainterPolyDataMapper::~vtkPainterPolyDataMapper()
{
  this->SetPainter(NULL);
  this->SetSelectionPainter(0);
  this->Observer->Target = NULL;
  this->Observer->Delete();
  this->PainterInformation->Delete();
}

//---------------------------------------------------------------------------
void vtkPainterPolyDataMapper::MapDataArrayToVertexAttribute(
  const char* vertexAttributeName,
  const char* dataArrayName,
  int field,
  int componentno)
{
  vtkGenericVertexAttributeMapping* mappings = 0;
  if( this->PainterInformation->Has(
      vtkPrimitivePainter::DATA_ARRAY_TO_VERTEX_ATTRIBUTE()) )
    {
    mappings = vtkGenericVertexAttributeMapping::SafeDownCast(
      this->PainterInformation->Get(
        vtkPolyDataPainter::DATA_ARRAY_TO_VERTEX_ATTRIBUTE()));
    }

  if (mappings==NULL)
    {
    mappings = vtkGenericVertexAttributeMapping::New();
    this->PainterInformation->Set(
      vtkPolyDataPainter::DATA_ARRAY_TO_VERTEX_ATTRIBUTE(), mappings);
    mappings->Delete();
    }

  mappings->AddMapping(
    vertexAttributeName, dataArrayName, field, componentno);
}

//---------------------------------------------------------------------------
void vtkPainterPolyDataMapper::MapDataArrayToMultiTextureAttribute(
  int unit,
  const char* dataArrayName,
  int field,
  int componentno)
{
  vtkGenericVertexAttributeMapping* mappings = 0;
  if( this->PainterInformation->Has(
      vtkPrimitivePainter::DATA_ARRAY_TO_VERTEX_ATTRIBUTE()) )
    {
    mappings = vtkGenericVertexAttributeMapping::SafeDownCast(
      this->PainterInformation->Get(
        vtkPolyDataPainter::DATA_ARRAY_TO_VERTEX_ATTRIBUTE()));
    }

  if (mappings==NULL)
    {
    mappings = vtkGenericVertexAttributeMapping::New();
    this->PainterInformation->Set(
      vtkPolyDataPainter::DATA_ARRAY_TO_VERTEX_ATTRIBUTE(), mappings);
    mappings->Delete();
    }

  mappings->AddMapping(
    unit, dataArrayName, field, componentno);
}

//-----------------------------------------------------------------------------
void vtkPainterPolyDataMapper::RemoveAllVertexAttributeMappings()
{
  vtkGenericVertexAttributeMapping* mappings = 0;
  if( this->PainterInformation->Has(
      vtkPrimitivePainter::DATA_ARRAY_TO_VERTEX_ATTRIBUTE()) )
    {
    mappings = vtkGenericVertexAttributeMapping::SafeDownCast(
      this->PainterInformation->Get(
        vtkPolyDataPainter::DATA_ARRAY_TO_VERTEX_ATTRIBUTE()));
    mappings->RemoveAllMappings();
    }
}

//-----------------------------------------------------------------------------
void vtkPainterPolyDataMapper::RemoveVertexAttributeMapping(
  const char* vertexAttributeName)
{
  vtkGenericVertexAttributeMapping* mappings = 0;
  if( this->PainterInformation->Has(
      vtkPrimitivePainter::DATA_ARRAY_TO_VERTEX_ATTRIBUTE()) )
    {
    mappings = vtkGenericVertexAttributeMapping::SafeDownCast(
      this->PainterInformation->Get(
        vtkPolyDataPainter::DATA_ARRAY_TO_VERTEX_ATTRIBUTE()));
    mappings->RemoveMapping(vertexAttributeName);
    }
}

//-----------------------------------------------------------------------------
void vtkPainterPolyDataMapper::SetPainter(vtkPainter* p)
{
  if (this->Painter)
    {
    this->Painter->RemoveObservers(vtkCommand::ProgressEvent, this->Observer);
    this->Painter->SetInformation(0);
    }
  vtkSetObjectBodyMacro(Painter, vtkPainter, p);

   if (this->Painter)
    {
    this->Painter->AddObserver(vtkCommand::ProgressEvent, this->Observer);
    this->Painter->SetInformation(this->PainterInformation);
    }
}

//-----------------------------------------------------------------------------
void vtkPainterPolyDataMapper::SetSelectionPainter(vtkPainter* p)
{
  if (this->SelectionPainter)
    {
    this->SelectionPainter->SetInformation(0);
    this->SelectionPainter->RemoveObservers(vtkCommand::ProgressEvent, this->Observer);
    }
  vtkSetObjectBodyMacro(SelectionPainter, vtkPainter, p);
   if (this->SelectionPainter)
    {
    this->SelectionPainter->AddObserver(vtkCommand::ProgressEvent, this->Observer);
    this->SelectionPainter->SetInformation(this->PainterInformation);
    }
}

//-----------------------------------------------------------------------------
void vtkPainterPolyDataMapper::ReportReferences(vtkGarbageCollector *collector)
{
  this->Superclass::ReportReferences(collector);
  vtkGarbageCollectorReport(collector, this->Painter, "Painter");
  vtkGarbageCollectorReport(collector, this->SelectionPainter, "SelectionPainter");
}

//-----------------------------------------------------------------------------
void vtkPainterPolyDataMapper::ReleaseGraphicsResources(vtkWindow *w)
{
  if (this->Painter)
    {
    this->Painter->ReleaseGraphicsResources(w);
    }
}

//-----------------------------------------------------------------------------
void vtkPainterPolyDataMapper::UpdatePainterInformation()
{
  vtkInformation* info = this->PainterInformation;

  info->Set(vtkPainter::STATIC_DATA(), this->Static);

  info->Set(vtkScalarsToColorsPainter::USE_LOOKUP_TABLE_SCALAR_RANGE(),
    this->GetUseLookupTableScalarRange());
  info->Set(vtkScalarsToColorsPainter::SCALAR_RANGE(),
    this->GetScalarRange(), 2);
  info->Set(vtkScalarsToColorsPainter::SCALAR_MODE(), this->GetScalarMode());
  info->Set(vtkScalarsToColorsPainter::COLOR_MODE(), this->GetColorMode());
  info->Set(vtkScalarsToColorsPainter::INTERPOLATE_SCALARS_BEFORE_MAPPING(),
    this->GetInterpolateScalarsBeforeMapping());
  info->Set(vtkScalarsToColorsPainter::LOOKUP_TABLE(), this->LookupTable);
  info->Set(vtkScalarsToColorsPainter::SCALAR_VISIBILITY(),
    this->GetScalarVisibility());
  info->Set(vtkScalarsToColorsPainter::ARRAY_ACCESS_MODE(),
    this->ArrayAccessMode);
  info->Set(vtkScalarsToColorsPainter::ARRAY_ID(), this->ArrayId);
  info->Set(vtkScalarsToColorsPainter::ARRAY_NAME(), this->ArrayName);
  info->Set(vtkScalarsToColorsPainter::ARRAY_COMPONENT(), this->ArrayComponent);
  info->Set(vtkScalarsToColorsPainter::SCALAR_MATERIAL_MODE(),
    this->GetScalarMaterialMode());

  info->Set(vtkClipPlanesPainter::CLIPPING_PLANES(), this->ClippingPlanes);

  info->Set(vtkCoincidentTopologyResolutionPainter::RESOLVE_COINCIDENT_TOPOLOGY(),
    this->GetResolveCoincidentTopology());
  info->Set(vtkCoincidentTopologyResolutionPainter::Z_SHIFT(),
    this->GetResolveCoincidentTopologyZShift());
  double p[2];
  this->GetResolveCoincidentTopologyPolygonOffsetParameters(p[0], p[1]);
  info->Set(vtkCoincidentTopologyResolutionPainter::POLYGON_OFFSET_PARAMETERS(),
    p, 2);
  info->Set(vtkCoincidentTopologyResolutionPainter::POLYGON_OFFSET_FACES(),
    this->GetResolveCoincidentTopologyPolygonOffsetFaces());

  int immr = (this->ImmediateModeRendering ||
              vtkMapper::GetGlobalImmediateModeRendering());
  info->Set(vtkDisplayListPainter::IMMEDIATE_MODE_RENDERING(), immr);
}

//-----------------------------------------------------------------------------
void vtkPainterPolyDataMapper::RenderPiece(vtkRenderer* ren, vtkActor* act)
{
  vtkDataObject *input= this->GetInputDataObject(0, 0);

   vtkStandardPolyDataPainter * painter =
    vtkStandardPolyDataPainter::SafeDownCast(this->Painter);
  if (painter != NULL && vtkPolyData::SafeDownCast(input))
    {
    // FIXME: This is not supported currently for composite datasets.
    vtkInformationVector *inArrayVec =
      this->Information->Get(INPUT_ARRAYS_TO_PROCESS());
    int numArrays = inArrayVec->GetNumberOfInformationObjects();

    for(int i = 0; i < numArrays; i++)
      {
      painter->AddMultiTextureCoordsArray(this->GetInputArrayToProcess(i,input));
      }
    }

  //
  // make sure that we've been properly initialized
  //
  if (ren->GetRenderWindow()->CheckAbortStatus())
    {
    return;
    }

  if ( input == NULL )
    {
    vtkErrorMacro(<< "No input!");
    return;
    }
  else
    {
    this->InvokeEvent(vtkCommand::StartEvent,NULL);
    if (!this->Static)
      {
      this->GetInputAlgorithm()->Update();
      }
    this->InvokeEvent(vtkCommand::EndEvent,NULL);

    // This check is unnecessary since the mapper will be cropped out by culling
    // if it returns invalid bounds which is what will happen when input has no
    // points.
    // vtkIdType numPts = input->GetNumberOfPoints();
    // if (numPts == 0)
    //   {
    //   vtkDebugMacro(<< "No points!");
    //   return;
    //   }
    }

  // Update Painter information if obsolete.
  if (this->PainterUpdateTime < this->GetMTime())
    {
    this->UpdatePainterInformation();
    this->PainterUpdateTime.Modified();
    }

  // make sure our window is current
  ren->GetRenderWindow()->MakeCurrent();
  this->TimeToDraw = 0.0;

  // If we are rendering in selection mode, then we use the selection painter
  // instead of the standard painter.
  if (this->SelectionPainter && ren->GetSelector())
    {
    this->SelectionPainter->SetInput(input);
    this->SelectionPainter->Render(ren, act, 0xff,
      (this->ForceCompileOnly==1));
    this->TimeToDraw = this->SelectionPainter->GetTimeToDraw();
    }
  else if (this->SelectionPainter && this->SelectionPainter != this->Painter)
    {
    this->SelectionPainter->ReleaseGraphicsResources(ren->GetRenderWindow());
    }

  if (this->Painter && ren->GetSelector() == 0)
    {
    // Pass polydata.
    this->Painter->SetInput(input);
    this->Painter->Render(ren, act, 0xff,this->ForceCompileOnly==1);
    this->TimeToDraw = this->Painter->GetTimeToDraw();
    }

  // If the timer is not accurate enough, set it to a small
  // time so that it is not zero
  if ( this->TimeToDraw == 0.0 )
    {
    this->TimeToDraw = 0.0001;
    }

  this->UpdateProgress(1.0);
}

//-------------------------------------------------------------------------
void vtkPainterPolyDataMapper::ComputeBounds()
{
  if (!this->GetInput())
    {
    vtkMath::UninitializeBounds(this->Bounds);
    return;
    }

  this->GetInput()->GetBounds(this->Bounds);

  // if the mapper has a painter, update the bounds in the painter
  vtkPainter *painter = this->GetPainter();
  if (painter)
    {
    // Update Painter information if obsolete.
    if (this->PainterUpdateTime < this->GetMTime())
      {
      this->UpdatePainterInformation();
      this->PainterUpdateTime.Modified();
      }
    painter->UpdateBounds(this->Bounds);
    }
}

//-----------------------------------------------------------------------------
bool vtkPainterPolyDataMapper::GetIsOpaque()
{
  if (this->ScalarVisibility &&
    this->ColorMode == VTK_COLOR_MODE_DEFAULT)
    {
    vtkPolyData* input =
      vtkPolyData::SafeDownCast(this->GetInputDataObject(0, 0));
    if (input)
      {
      int cellFlag;
      vtkDataArray* scalars = this->GetScalars(input,
        this->ScalarMode, this->ArrayAccessMode, this->ArrayId,
        this->ArrayName, cellFlag);
      if (scalars && scalars->IsA("vtkUnsignedCharArray") &&
        (scalars->GetNumberOfComponents() ==  4 /*(RGBA)*/ ||
         scalars->GetNumberOfComponents() == 2 /*(LuminanceAlpha)*/))
        {
        vtkUnsignedCharArray* colors =
          static_cast<vtkUnsignedCharArray*>(scalars);
        if ((colors->GetNumberOfComponents() == 4 && colors->GetValueRange(3)[0] < 255) ||
          (colors->GetNumberOfComponents() == 2 && colors->GetValueRange(1)[0] < 255))
          {
          // If the opacity is 255, despite the fact that the user specified
          // RGBA, we know that the Alpha is 100% opaque. So treat as opaque.
          return false;
          }
        }
      }
    }
  return this->Superclass::GetIsOpaque();
}

//-----------------------------------------------------------------------------
void vtkPainterPolyDataMapper::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  os << indent << "Painter: " ;
  if (this->Painter)
    {
    os << endl;
    this->Painter->PrintSelf(os, indent.GetNextIndent());
    }
  else
    {
    os << indent << "(none)" << endl;
    }
  os << indent << "SelectionPainter: " << this->SelectionPainter << endl;
}
<|endoftext|>


<commit_before>// Copyright 2010-2021 Google LLC
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This file wraps the swig_helper.h classes in python using pybind11.
// Because pybind11_protobuf does not support building with CMake for OR-Tools,
// the API has been transformed to use serialized protos from Python to C++ and
// from C++ to python:
//   from Python to C++: use proto.SerializeToString(). This creates a python
//     string that is passed to C++ and parsed back to proto.
//   from C++ to Python, we cast the result of proto.SerializeAsString() to
//     pybind11::bytes. This is passed back to python, which will reconstruct
//     the proto using PythonProto.FromString(byte[]).

#include "ortools/sat/swig_helper.h"

#include <string>

#include "ortools/sat/cp_model.pb.h"
#include "ortools/util/sorted_interval_list.h"
#include "pybind11/functional.h"
#include "pybind11/pybind11.h"
#include "pybind11/stl.h"

using ::operations_research::Domain;
using ::operations_research::sat::CpModelProto;
using ::operations_research::sat::CpSatHelper;
using ::operations_research::sat::CpSolverResponse;
using ::operations_research::sat::IntegerVariableProto;
using ::operations_research::sat::SatParameters;
using ::operations_research::sat::SolutionCallback;
using ::operations_research::sat::SolveWrapper;
using ::pybind11::arg;

class PySolutionCallback : public SolutionCallback {
 public:
  using SolutionCallback::SolutionCallback; /* Inherit constructors */

  void OnSolutionCallback() const override {
    ::pybind11::gil_scoped_acquire acquire;
    PYBIND11_OVERRIDE_PURE(
        void,               /* Return type */
        SolutionCallback,   /* Parent class */
        OnSolutionCallback, /* Name of function */
        /* This function has no arguments. The trailing comma
           in the previous line is needed for some compilers */
    );
  }
};

void SetSerializedParameters(const std::string& serialized_parameters,
                             SolveWrapper* solve_wrapper) {
  SatParameters parameters;
  if (parameters.ParseFromString(serialized_parameters)) {
    solve_wrapper->SetParameters(parameters);
  }
}

pybind11::bytes SerializedSolve(const std::string& serialized_model,
                                SolveWrapper* solve_wrapper) {
  ::pybind11::gil_scoped_release release;
  CpModelProto model_proto;
  model_proto.ParseFromString(serialized_model);
  return solve_wrapper->Solve(model_proto).SerializeAsString();
}

std::string SerializedModelStats(const std::string& serialized_model) {
  CpModelProto model_proto;
  model_proto.ParseFromString(serialized_model);
  return CpSatHelper::ModelStats(model_proto);
}

std::string SerializedSolverResponseStats(
    const std::string& serialized_response) {
  CpSolverResponse response_proto;
  response_proto.ParseFromString(serialized_response);
  return CpSatHelper::SolverResponseStats(response_proto);
}

std::string SerializedValidateModel(const std::string& serialized_model) {
  CpModelProto model_proto;
  model_proto.ParseFromString(serialized_model);
  return CpSatHelper::ValidateModel(model_proto);
}

Domain SerializedVariableDomain(const std::string& serialized_variable) {
  IntegerVariableProto variable_proto;
  variable_proto.ParseFromString(serialized_variable);
  return CpSatHelper::VariableDomain(variable_proto);
}

bool SerializedWriteModelToFile(const std::string& serialized_model,
                                const std::string& filename) {
  CpModelProto model_proto;
  model_proto.ParseFromString(serialized_model);
  return CpSatHelper::WriteModelToFile(model_proto, filename);
}

pybind11::bytes SerializedResponse(const SolutionCallback& solution_callback) {
  return solution_callback.Response().SerializeAsString();
}

PYBIND11_MODULE(swig_helper, m) {
  pybind11::module::import("ortools.util.python.sorted_interval_list");

  pybind11::class_<SolutionCallback, PySolutionCallback>(m, "SolutionCallback")
      .def(pybind11::init<>())
      .def("OnSolutionCallback", &SolutionCallback::OnSolutionCallback)
      .def("BestObjectiveBound", &SolutionCallback::BestObjectiveBound)
      .def("DeterministicTime", &SolutionCallback::DeterministicTime)
      .def("HasResponse", &SolutionCallback::HasResponse)
      .def("NumBinaryPropagations", &SolutionCallback::NumBinaryPropagations)
      .def("NumBooleans", &SolutionCallback::NumBooleans)
      .def("NumBranches", &SolutionCallback::NumBranches)
      .def("NumConflicts", &SolutionCallback::NumConflicts)
      .def("NumIntegerPropagations", &SolutionCallback::NumIntegerPropagations)
      .def("ObjectiveValue", &SolutionCallback::ObjectiveValue)
      .def_static("SerializedResponse", &SerializedResponse,
                  arg("solution_callback"))
      .def("SolutionBooleanValue", &SolutionCallback::SolutionBooleanValue,
           arg("index"))
      .def("SolutionIntegerValue", &SolutionCallback::SolutionIntegerValue,
           arg("index"))
      .def("StopSearch", &SolutionCallback::StopSearch)
      .def("UserTime", &SolutionCallback::UserTime)
      .def("WallTime", &SolutionCallback::WallTime);

  pybind11::class_<SolveWrapper>(m, "SolveWrapper")
      .def(pybind11::init<>())
      .def("AddLogCallback", &SolveWrapper::AddLogCallback, arg("log_callback"))
      .def("AddSolutionCallback", &SolveWrapper::AddSolutionCallback,
           arg("callback"))
      .def("ClearSolutionCallback", &SolveWrapper::ClearSolutionCallback)
      .def_static("SetSerializedParameters", &SetSerializedParameters,
                  arg("serialized_parameters"), arg("solve_wrapper"))
      .def_static("SerializedSolve", &SerializedSolve, arg("model_proto"),
                  arg("solve_wrapper"))
      .def("StopSearch", &SolveWrapper::StopSearch);

  pybind11::class_<CpSatHelper>(m, "CpSatHelper")
      .def_static("SerializedModelStats", &SerializedModelStats,
                  arg("serialized_model"))
      .def_static("SerializedSolverResponseStats",
                  &SerializedSolverResponseStats, arg("serialized_response"))
      .def_static("SerializedValidateModel", &SerializedValidateModel,
                  arg("serialized_model"))
      .def_static("SerializedVariableDomain", &SerializedVariableDomain,
                  arg("serialized_variable"))
      .def_static("SerializedWriteModelToFile", &SerializedWriteModelToFile,
                  arg("serialized_model"), arg("filename"));
}
<commit_msg>python: Fix pymalloc after releasing gil (#3329)<commit_after>// Copyright 2010-2021 Google LLC
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This file wraps the swig_helper.h classes in python using pybind11.
// Because pybind11_protobuf does not support building with CMake for OR-Tools,
// the API has been transformed to use serialized protos from Python to C++ and
// from C++ to python:
//   from Python to C++: use proto.SerializeToString(). This creates a python
//     string that is passed to C++ and parsed back to proto.
//   from C++ to Python, we cast the result of proto.SerializeAsString() to
//     pybind11::bytes. This is passed back to python, which will reconstruct
//     the proto using PythonProto.FromString(byte[]).

#include "ortools/sat/swig_helper.h"

#include <string>

#include "ortools/sat/cp_model.pb.h"
#include "ortools/util/sorted_interval_list.h"
#include "pybind11/functional.h"
#include "pybind11/pybind11.h"
#include "pybind11/stl.h"

using ::operations_research::Domain;
using ::operations_research::sat::CpModelProto;
using ::operations_research::sat::CpSatHelper;
using ::operations_research::sat::CpSolverResponse;
using ::operations_research::sat::IntegerVariableProto;
using ::operations_research::sat::SatParameters;
using ::operations_research::sat::SolutionCallback;
using ::operations_research::sat::SolveWrapper;
using ::pybind11::arg;

class PySolutionCallback : public SolutionCallback {
 public:
  using SolutionCallback::SolutionCallback; /* Inherit constructors */

  void OnSolutionCallback() const override {
    ::pybind11::gil_scoped_acquire acquire;
    PYBIND11_OVERRIDE_PURE(
        void,               /* Return type */
        SolutionCallback,   /* Parent class */
        OnSolutionCallback, /* Name of function */
        /* This function has no arguments. The trailing comma
           in the previous line is needed for some compilers */
    );
  }
};

void SetSerializedParameters(const std::string& serialized_parameters,
                             SolveWrapper* solve_wrapper) {
  SatParameters parameters;
  if (parameters.ParseFromString(serialized_parameters)) {
    solve_wrapper->SetParameters(parameters);
  }
}

pybind11::bytes SerializedSolve(const std::string& serialized_model,
                                SolveWrapper* solve_wrapper) {
  std::string result;
  {
    ::pybind11::gil_scoped_release release;
    CpModelProto model_proto;
    model_proto.ParseFromString(serialized_model);
    result = solve_wrapper->Solve(model_proto).SerializeAsString();
  }
  return result;
}

std::string SerializedModelStats(const std::string& serialized_model) {
  CpModelProto model_proto;
  model_proto.ParseFromString(serialized_model);
  return CpSatHelper::ModelStats(model_proto);
}

std::string SerializedSolverResponseStats(
    const std::string& serialized_response) {
  CpSolverResponse response_proto;
  response_proto.ParseFromString(serialized_response);
  return CpSatHelper::SolverResponseStats(response_proto);
}

std::string SerializedValidateModel(const std::string& serialized_model) {
  CpModelProto model_proto;
  model_proto.ParseFromString(serialized_model);
  return CpSatHelper::ValidateModel(model_proto);
}

Domain SerializedVariableDomain(const std::string& serialized_variable) {
  IntegerVariableProto variable_proto;
  variable_proto.ParseFromString(serialized_variable);
  return CpSatHelper::VariableDomain(variable_proto);
}

bool SerializedWriteModelToFile(const std::string& serialized_model,
                                const std::string& filename) {
  CpModelProto model_proto;
  model_proto.ParseFromString(serialized_model);
  return CpSatHelper::WriteModelToFile(model_proto, filename);
}

pybind11::bytes SerializedResponse(const SolutionCallback& solution_callback) {
  return solution_callback.Response().SerializeAsString();
}

PYBIND11_MODULE(swig_helper, m) {
  pybind11::module::import("ortools.util.python.sorted_interval_list");

  pybind11::class_<SolutionCallback, PySolutionCallback>(m, "SolutionCallback")
      .def(pybind11::init<>())
      .def("OnSolutionCallback", &SolutionCallback::OnSolutionCallback)
      .def("BestObjectiveBound", &SolutionCallback::BestObjectiveBound)
      .def("DeterministicTime", &SolutionCallback::DeterministicTime)
      .def("HasResponse", &SolutionCallback::HasResponse)
      .def("NumBinaryPropagations", &SolutionCallback::NumBinaryPropagations)
      .def("NumBooleans", &SolutionCallback::NumBooleans)
      .def("NumBranches", &SolutionCallback::NumBranches)
      .def("NumConflicts", &SolutionCallback::NumConflicts)
      .def("NumIntegerPropagations", &SolutionCallback::NumIntegerPropagations)
      .def("ObjectiveValue", &SolutionCallback::ObjectiveValue)
      .def_static("SerializedResponse", &SerializedResponse,
                  arg("solution_callback"))
      .def("SolutionBooleanValue", &SolutionCallback::SolutionBooleanValue,
           arg("index"))
      .def("SolutionIntegerValue", &SolutionCallback::SolutionIntegerValue,
           arg("index"))
      .def("StopSearch", &SolutionCallback::StopSearch)
      .def("UserTime", &SolutionCallback::UserTime)
      .def("WallTime", &SolutionCallback::WallTime);

  pybind11::class_<SolveWrapper>(m, "SolveWrapper")
      .def(pybind11::init<>())
      .def("AddLogCallback", &SolveWrapper::AddLogCallback, arg("log_callback"))
      .def("AddSolutionCallback", &SolveWrapper::AddSolutionCallback,
           arg("callback"))
      .def("ClearSolutionCallback", &SolveWrapper::ClearSolutionCallback)
      .def_static("SetSerializedParameters", &SetSerializedParameters,
                  arg("serialized_parameters"), arg("solve_wrapper"))
      .def_static("SerializedSolve", &SerializedSolve, arg("model_proto"),
                  arg("solve_wrapper"))
      .def("StopSearch", &SolveWrapper::StopSearch);

  pybind11::class_<CpSatHelper>(m, "CpSatHelper")
      .def_static("SerializedModelStats", &SerializedModelStats,
                  arg("serialized_model"))
      .def_static("SerializedSolverResponseStats",
                  &SerializedSolverResponseStats, arg("serialized_response"))
      .def_static("SerializedValidateModel", &SerializedValidateModel,
                  arg("serialized_model"))
      .def_static("SerializedVariableDomain", &SerializedVariableDomain,
                  arg("serialized_variable"))
      .def_static("SerializedWriteModelToFile", &SerializedWriteModelToFile,
                  arg("serialized_model"), arg("filename"));
}
<|endoftext|>


<commit_before>// location.cxx -- class for determining model location in the flightgear world.
//
// Written by Jim Wilson, David Megginson, started April 2002.
// Based largely on code by Curtis Olson and Norman Vine.
//
// Copyright (C) 2002  Curtis L. Olson - curt@flightgear.org
//
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$

#include <simgear/compiler.h>

#ifdef HAVE_CONFIG_H
#  include <simgear_config.h>
#endif

#include <simgear/debug/logstream.hxx>
#include <simgear/constants.h>
#include <simgear/math/point3d.hxx>
#include <simgear/math/polar3d.hxx>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/math/vector.hxx>

#include "location.hxx"

/**
 * make model transformation Matrix - based on optimizations by NHV
 */
static void MakeTRANS( sgMat4 dst, const double Theta,
			const double Phi, const double Psi,
                        const sgMat4 UP)
{
    SGfloat cosTheta = (SGfloat) cos(Theta);
    SGfloat sinTheta = (SGfloat) sin(Theta);
    SGfloat cosPhi   = (SGfloat) cos(Phi);
    SGfloat sinPhi   = (SGfloat) sin(Phi);
    SGfloat sinPsi   = (SGfloat) sin(Psi) ;
    SGfloat cosPsi   = (SGfloat) cos(Psi) ;

    sgMat4 tmp;

    tmp[0][0] = cosPhi * cosTheta;
    tmp[0][1] =	sinPhi * cosPsi + cosPhi * -sinTheta * -sinPsi;
    tmp[0][2] =	sinPhi * sinPsi + cosPhi * -sinTheta * cosPsi;

    tmp[1][0] = -sinPhi * cosTheta;
    tmp[1][1] =	cosPhi * cosPsi + -sinPhi * -sinTheta * -sinPsi;
    tmp[1][2] =	cosPhi * sinPsi + -sinPhi * -sinTheta * cosPsi;

    tmp[2][0] = sinTheta;
    tmp[2][1] =	cosTheta * -sinPsi;
    tmp[2][2] =	cosTheta * cosPsi;

    float a = UP[0][0];
    float b = UP[1][0];
    float c = UP[2][0];
    dst[2][0] = a*tmp[0][0] + b*tmp[0][1] + c*tmp[0][2] ;
    dst[1][0] = a*tmp[1][0] + b*tmp[1][1] + c*tmp[1][2] ;
    dst[0][0] = -(a*tmp[2][0] + b*tmp[2][1] + c*tmp[2][2]) ;
    dst[3][0] = SG_ZERO ;

    a = UP[0][1];
    b = UP[1][1];
    c = UP[2][1];
    dst[2][1] = a*tmp[0][0] + b*tmp[0][1] + c*tmp[0][2] ;
    dst[1][1] = a*tmp[1][0] + b*tmp[1][1] + c*tmp[1][2] ;
    dst[0][1] = -(a*tmp[2][0] + b*tmp[2][1] + c*tmp[2][2]) ;
    dst[3][1] = SG_ZERO ;

    a = UP[0][2];
    c = UP[2][2];
    dst[2][2] = a*tmp[0][0] + c*tmp[0][2] ;
    dst[1][2] = a*tmp[1][0] + c*tmp[1][2] ;
    dst[0][2] = -(a*tmp[2][0] + c*tmp[2][2]) ;
    dst[3][2] = SG_ZERO ;

    dst[2][3] = SG_ZERO ;
    dst[1][3] = SG_ZERO ;
    dst[0][3] = SG_ZERO ;
    dst[3][3] = SG_ONE ;

}

////////////////////////////////////////////////////////////////////////
// Implementation of SGLocation.
////////////////////////////////////////////////////////////////////////

// Constructor
SGLocation::SGLocation( void ):
    _dirty(true),
    _lon_deg(0),
    _lat_deg(0),
    _alt_ft(0),
    _roll_deg(0),
    _pitch_deg(0),
    _heading_deg(0),
    _cur_elev_m(0),
    _tile_center(0)
{
    sgdZeroVec3(_absolute_view_pos);
    sgZeroVec3(_relative_view_pos);
    sgZeroVec3(_zero_elev_view_pos);
    sgMakeRotMat4( UP, 0.0, 0.0, 0.0 );
    sgMakeRotMat4( TRANS, 0.0, 0.0, 0.0 );
}

// Destructor
SGLocation::~SGLocation( void ) {
}

void
SGLocation::init ()
{
}

void
SGLocation::bind ()
{
}

void
SGLocation::unbind ()
{
}

void
SGLocation::setPosition (double lon_deg, double lat_deg, double alt_ft)
{
  _dirty = true;
  _lon_deg = lon_deg;
  _lat_deg = lat_deg;
  _alt_ft = alt_ft;
}

void
SGLocation::setOrientation (double roll_deg, double pitch_deg, double heading_deg)
{
  _dirty = true;
  _roll_deg = roll_deg;
  _pitch_deg = pitch_deg;
  _heading_deg = heading_deg;
}

double *
SGLocation::get_absolute_view_pos( const Point3D scenery_center )
{
    if ( _dirty ) {
        recalc( scenery_center );
    }
    return _absolute_view_pos;
}

float *
SGLocation::getRelativeViewPos( const Point3D scenery_center )
{
    if ( _dirty ) {
        recalc( scenery_center );
    }
    return _relative_view_pos;
}

float *
SGLocation::getZeroElevViewPos( const Point3D scenery_center )
{
    if ( _dirty ) {
        recalc( scenery_center );
    }
    return _zero_elev_view_pos;
}

// recalc() is done every time one of the setters is called (making the
// cached data "dirty") on the next "get".  It calculates all the outputs
// for viewer.
void
SGLocation::recalc( const Point3D scenery_center )
{

  recalcPosition( _lon_deg, _lat_deg, _alt_ft, scenery_center );

  // Make the world up rotation matrix for eye positioin...
  sgMakeRotMat4( UP, _lon_deg, 0.0, -_lat_deg );

  // get the world up radial vector from planet center for output
  sgSetVec3( _world_up, UP[0][0], UP[0][1], UP[0][2] );

  // Creat local matrix with current geodetic position.  Converting
  // the orientation (pitch/roll/heading) to vectors.
  MakeTRANS( TRANS, _pitch_deg * SG_DEGREES_TO_RADIANS,
                      _roll_deg * SG_DEGREES_TO_RADIANS,
                      -_heading_deg * SG_DEGREES_TO_RADIANS,
                      UP);

  // Given a vector pointing straight down (-Z), map into onto the
  // local plane representing "horizontal".  This should give us the
  // local direction for moving "south".
  sgVec3 minus_z;
  sgSetVec3( minus_z, 0.0, 0.0, -1.0 );

  sgmap_vec_onto_cur_surface_plane(_world_up, _relative_view_pos, minus_z,
				     _surface_south);
  sgNormalizeVec3(_surface_south);

  // now calculate the surface east vector
  sgVec3 world_down;
  sgNegateVec3(world_down, _world_up);
  sgVectorProductVec3(_surface_east, _surface_south, world_down);

  set_clean();
}

void
SGLocation::recalcPosition( double lon_deg, double lat_deg, double alt_ft,
                            const Point3D scenery_center ) const
{
  double lat = lat_deg * SGD_DEGREES_TO_RADIANS;
  double lon = lon_deg * SGD_DEGREES_TO_RADIANS;
  double alt = alt_ft * SG_FEET_TO_METER;

  sgGeodToCart(lat, lon, alt, _absolute_view_pos);

  int i;
  double ground[3];
  sgGeodToCart(lat, lon, 0, ground);
  for(i=0; i<3; i++)
      _zero_elev_view_pos[i] = ground[i] - _tile_center[i];

  // FIXME: view position should ONLY be calculated in the viewer...
  // Anything else should calculate their own positions relative to the
  // viewer's tile_center.
  for(i=0; i<3; i++)
    _relative_view_pos[i] = _absolute_view_pos[i] - scenery_center[i];
}

void
SGLocation::update (int dt)
{
}
<commit_msg>Frederic Bouvier:<commit_after>// location.cxx -- class for determining model location in the flightgear world.
//
// Written by Jim Wilson, David Megginson, started April 2002.
// Based largely on code by Curtis Olson and Norman Vine.
//
// Copyright (C) 2002  Curtis L. Olson - curt@flightgear.org
//
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$

#include <simgear/compiler.h>

#ifdef HAVE_CONFIG_H
#  include <simgear_config.h>
#endif

#include <simgear/debug/logstream.hxx>
#include <simgear/constants.h>
#include <simgear/math/point3d.hxx>
#include <simgear/math/polar3d.hxx>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/math/vector.hxx>

#include "location.hxx"

/**
 * make model transformation Matrix - based on optimizations by NHV
 */
static void MakeTRANS( sgMat4 dst, const double Theta,
			const double Phi, const double Psi,
                        const sgMat4 UP)
{
    SGfloat cosTheta = (SGfloat) cos(Theta);
    SGfloat sinTheta = (SGfloat) sin(Theta);
    SGfloat cosPhi   = (SGfloat) cos(Phi);
    SGfloat sinPhi   = (SGfloat) sin(Phi);
    SGfloat sinPsi   = (SGfloat) sin(Psi) ;
    SGfloat cosPsi   = (SGfloat) cos(Psi) ;

    sgMat4 tmp;

    tmp[0][0] = cosPhi * cosTheta;
    tmp[0][1] =	sinPhi * cosPsi + cosPhi * -sinTheta * -sinPsi;
    tmp[0][2] =	sinPhi * sinPsi + cosPhi * -sinTheta * cosPsi;

    tmp[1][0] = -sinPhi * cosTheta;
    tmp[1][1] =	cosPhi * cosPsi + -sinPhi * -sinTheta * -sinPsi;
    tmp[1][2] =	cosPhi * sinPsi + -sinPhi * -sinTheta * cosPsi;

    tmp[2][0] = sinTheta;
    tmp[2][1] =	cosTheta * -sinPsi;
    tmp[2][2] =	cosTheta * cosPsi;

    float a = UP[0][0];
    float b = UP[1][0];
    float c = UP[2][0];
    dst[2][0] = a*tmp[0][0] + b*tmp[0][1] + c*tmp[0][2] ;
    dst[1][0] = a*tmp[1][0] + b*tmp[1][1] + c*tmp[1][2] ;
    dst[0][0] = -(a*tmp[2][0] + b*tmp[2][1] + c*tmp[2][2]) ;
    dst[3][0] = SG_ZERO ;

    a = UP[0][1];
    b = UP[1][1];
    c = UP[2][1];
    dst[2][1] = a*tmp[0][0] + b*tmp[0][1] + c*tmp[0][2] ;
    dst[1][1] = a*tmp[1][0] + b*tmp[1][1] + c*tmp[1][2] ;
    dst[0][1] = -(a*tmp[2][0] + b*tmp[2][1] + c*tmp[2][2]) ;
    dst[3][1] = SG_ZERO ;

    a = UP[0][2];
    c = UP[2][2];
    dst[2][2] = a*tmp[0][0] + c*tmp[0][2] ;
    dst[1][2] = a*tmp[1][0] + c*tmp[1][2] ;
    dst[0][2] = -(a*tmp[2][0] + c*tmp[2][2]) ;
    dst[3][2] = SG_ZERO ;

    dst[2][3] = SG_ZERO ;
    dst[1][3] = SG_ZERO ;
    dst[0][3] = SG_ZERO ;
    dst[3][3] = SG_ONE ;

}

////////////////////////////////////////////////////////////////////////
// Implementation of SGLocation.
////////////////////////////////////////////////////////////////////////

// Constructor
SGLocation::SGLocation( void ):
    _dirty(true),
    _lon_deg(-1000),
    _lat_deg(0),
    _alt_ft(0),
    _roll_deg(0),
    _pitch_deg(0),
    _heading_deg(0),
    _cur_elev_m(0),
    _tile_center(0)
{
    sgdZeroVec3(_absolute_view_pos);
    sgZeroVec3(_relative_view_pos);
    sgZeroVec3(_zero_elev_view_pos);
    sgMakeRotMat4( UP, 0.0, 0.0, 0.0 );
    sgMakeRotMat4( TRANS, 0.0, 0.0, 0.0 );
}

// Destructor
SGLocation::~SGLocation( void ) {
}

void
SGLocation::init ()
{
}

void
SGLocation::bind ()
{
}

void
SGLocation::unbind ()
{
}

void
SGLocation::setPosition (double lon_deg, double lat_deg, double alt_ft)
{
  _dirty = true;
  _lon_deg = lon_deg;
  _lat_deg = lat_deg;
  _alt_ft = alt_ft;
}

void
SGLocation::setOrientation (double roll_deg, double pitch_deg, double heading_deg)
{
  _dirty = true;
  _roll_deg = roll_deg;
  _pitch_deg = pitch_deg;
  _heading_deg = heading_deg;
}

double *
SGLocation::get_absolute_view_pos( const Point3D scenery_center )
{
    if ( _dirty ) {
        recalc( scenery_center );
    }
    return _absolute_view_pos;
}

float *
SGLocation::getRelativeViewPos( const Point3D scenery_center )
{
    if ( _dirty ) {
        recalc( scenery_center );
    }
    return _relative_view_pos;
}

float *
SGLocation::getZeroElevViewPos( const Point3D scenery_center )
{
    if ( _dirty ) {
        recalc( scenery_center );
    }
    return _zero_elev_view_pos;
}

// recalc() is done every time one of the setters is called (making the
// cached data "dirty") on the next "get".  It calculates all the outputs
// for viewer.
void
SGLocation::recalc( const Point3D scenery_center )
{

  recalcPosition( _lon_deg, _lat_deg, _alt_ft, scenery_center );

  // Make the world up rotation matrix for eye positioin...
  sgMakeRotMat4( UP, _lon_deg, 0.0, -_lat_deg );

  // get the world up radial vector from planet center for output
  sgSetVec3( _world_up, UP[0][0], UP[0][1], UP[0][2] );

  // Creat local matrix with current geodetic position.  Converting
  // the orientation (pitch/roll/heading) to vectors.
  MakeTRANS( TRANS, _pitch_deg * SG_DEGREES_TO_RADIANS,
                      _roll_deg * SG_DEGREES_TO_RADIANS,
                      -_heading_deg * SG_DEGREES_TO_RADIANS,
                      UP);

  // Given a vector pointing straight down (-Z), map into onto the
  // local plane representing "horizontal".  This should give us the
  // local direction for moving "south".
  sgVec3 minus_z;
  sgSetVec3( minus_z, 0.0, 0.0, -1.0 );

  sgmap_vec_onto_cur_surface_plane(_world_up, _relative_view_pos, minus_z,
				     _surface_south);
  sgNormalizeVec3(_surface_south);

  // now calculate the surface east vector
  sgVec3 world_down;
  sgNegateVec3(world_down, _world_up);
  sgVectorProductVec3(_surface_east, _surface_south, world_down);

  set_clean();
}

void
SGLocation::recalcPosition( double lon_deg, double lat_deg, double alt_ft,
                            const Point3D scenery_center ) const
{
  double lat = lat_deg * SGD_DEGREES_TO_RADIANS;
  double lon = lon_deg * SGD_DEGREES_TO_RADIANS;
  double alt = alt_ft * SG_FEET_TO_METER;

  sgGeodToCart(lat, lon, alt, _absolute_view_pos);

  int i;
  double ground[3];
  sgGeodToCart(lat, lon, 0, ground);
  for(i=0; i<3; i++)
      _zero_elev_view_pos[i] = ground[i] - _tile_center[i];

  // FIXME: view position should ONLY be calculated in the viewer...
  // Anything else should calculate their own positions relative to the
  // viewer's tile_center.
  for(i=0; i<3; i++)
    _relative_view_pos[i] = _absolute_view_pos[i] - scenery_center[i];
}

void
SGLocation::update (int dt)
{
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2017, Vlad Meșco
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "model.h"
#include "window.h"
#include "logger.h"

#include <FL/Fl.H>

#include <algorithm>
#include <vector>
#include <cassert>

std::vector<Schema> drumSchemas {
    /* Basic Drum */
    {
        "Mono",
        {
            { "path", Schema::STRING },
            { "volume", Schema::NUMBER },
        },
    },
    /* Stereo Drum */
    {
        "Stereo",
        {
            { "path", Schema::STRING },
            { "volume", Schema::NUMBER },
            { "stereo", Schema::STUB, {
                                                      { "pan", Schema::READ_ONLY_STRING },
                                                  }},
            { "params", Schema::SUBSCHEMA, {
                                               { "pan", Schema::NUMBER },
                                           }},
        },
    },
    /* Chorus Drum */
    {
        "Chorus",
        {
            { "path", Schema::STRING },
            { "volume", Schema::NUMBER },
            { "stereo", Schema::STUB, {
                                                      { "chorus", Schema::READ_ONLY_STRING },
                                                  }},
            { "params", Schema::SUBSCHEMA, {
                                               { "pan", Schema::NUMBER },
                                               { "delay", Schema::NUMBER },
                                               { "amount", Schema::NUMBER },
                                               { "speed", Schema::NUMBER },
                                               { "depth", Schema::NUMBER },
                                           }},
        },
    },
};

std::vector<Schema> whatSchemas {
    {
        "Standard",
        {
            { "bpm", Schema::NUMBER },
        },
    },
};

std::list<Vindow*> windows;

std::shared_ptr<Model> load_model(std::string path)
{
    return {};
}

void save_model(std::shared_ptr<Model> m)
{
}

bool is_any_model_dirty()
{
    return std::any_of(windows.begin(), windows.end(), [](Vindow* w) -> bool {
                return w->GetModel()->dirty;
            });
}

void create_window(std::shared_ptr<Model> m)
{
    windows.emplace_back(new Vindow(m, drumSchemas, whatSchemas));
    assert(m);
    assert(windows.back()->GetModel());
    windows.back()->show();
}

void destroy_window(Vindow* whom)
{
    auto found = std::find_if(windows.begin(), windows.end(), [whom](Vindow * w) -> bool {
                return w == whom;
            });
    if(found == windows.end())
    {
        fprintf(stderr, "window not found... not abort()-ing to not lose data, but it should be fixed");
        return;
    }
    windows.erase(found);
    Fl::delete_widget(whom);
}

int main(int argc, char* argv[])
{
    Fl::scheme("gtk+");
#if 1
    /* test code */
    std::shared_ptr<Model> m(new Model());
    m->whos.push_back({
                "kick",
                &drumSchemas[0],
                {
                    { "path", "kick.wav" },
                    { "volume", "100" },
                }
            });
    m->whos.push_back({
                "snare",
                &drumSchemas[1],
                {
                    { "path", "snare.wav" },
                    { "volume", "100" },
                    { "stereo", "chorus" },
                    { "pan", "-10" },
                }
            });
    m->whos.push_back({
                "hat",
                &drumSchemas[2],
                {
                    { "path", "snare.wav" },
                    { "volume", "100" },
                    { "stereo", "chorus" },
                    { "pan", "-10" },
                    { "delay", "3" },
                    { "amount", "60" },
                    { "speed", "30" },
                    { "depth", "30" },
                }
            });
    m->whats.push_back({
                "A1",
                "120",
                &whatSchemas[0],
                {
                    { '!', '.', '/', },
                    { '.', '!', ':', },
                    { '.', '.', '/', },
                }});
    m->output.push_back({{ '1' }});
    m->output.push_back({{ '1' }});
    for(size_t i = 0; i < 80; ++i) {
        m->output.push_back({{ '.' }});
    }
    m->output.push_back({{ '1' }});
    create_window(m);

    return Fl::run();
#endif
}
<commit_msg>fix indent<commit_after>/*
Copyright (c) 2017, Vlad Meșco
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "model.h"
#include "window.h"
#include "logger.h"

#include <FL/Fl.H>

#include <algorithm>
#include <vector>
#include <cassert>

std::vector<Schema> drumSchemas {
    /* Basic Drum */
    {
        "Mono",
        {
            { "path", Schema::STRING },
            { "volume", Schema::NUMBER },
        },
    },
    /* Stereo Drum */
    {
        "Stereo",
        {
            { "path", Schema::STRING },
            { "volume", Schema::NUMBER },
            { "stereo", Schema::STUB, {
                                          { "pan", Schema::READ_ONLY_STRING },
                                      }},
            { "params", Schema::SUBSCHEMA, {
                                               { "pan", Schema::NUMBER },
                                           }},
        },
    },
    /* Chorus Drum */
    {
        "Chorus",
        {
            { "path", Schema::STRING },
            { "volume", Schema::NUMBER },
            { "stereo", Schema::STUB, {
                                          { "chorus", Schema::READ_ONLY_STRING },
                                      }},
            { "params", Schema::SUBSCHEMA, {
                                               { "pan", Schema::NUMBER },
                                               { "delay", Schema::NUMBER },
                                               { "amount", Schema::NUMBER },
                                               { "speed", Schema::NUMBER },
                                               { "depth", Schema::NUMBER },
                                           }},
        },
    },
};

std::vector<Schema> whatSchemas {
    {
        "Standard",
        {
            { "bpm", Schema::NUMBER },
        },
    },
};

std::list<Vindow*> windows;

std::shared_ptr<Model> load_model(std::string path)
{
    return {};
}

void save_model(std::shared_ptr<Model> m)
{
}

bool is_any_model_dirty()
{
    return std::any_of(windows.begin(), windows.end(), [](Vindow* w) -> bool {
                return w->GetModel()->dirty;
            });
}

void create_window(std::shared_ptr<Model> m)
{
    windows.emplace_back(new Vindow(m, drumSchemas, whatSchemas));
    assert(m);
    assert(windows.back()->GetModel());
    windows.back()->show();
}

void destroy_window(Vindow* whom)
{
    auto found = std::find_if(windows.begin(), windows.end(), [whom](Vindow * w) -> bool {
                return w == whom;
            });
    if(found == windows.end())
    {
        fprintf(stderr, "window not found... not abort()-ing to not lose data, but it should be fixed");
        return;
    }
    windows.erase(found);
    Fl::delete_widget(whom);
}

int main(int argc, char* argv[])
{
    Fl::scheme("gtk+");
#if 1
    /* test code */
    std::shared_ptr<Model> m(new Model());
    m->whos.push_back({
                "kick",
                &drumSchemas[0],
                {
                    { "path", "kick.wav" },
                    { "volume", "100" },
                }
            });
    m->whos.push_back({
                "snare",
                &drumSchemas[1],
                {
                    { "path", "snare.wav" },
                    { "volume", "100" },
                    { "stereo", "chorus" },
                    { "pan", "-10" },
                }
            });
    m->whos.push_back({
                "hat",
                &drumSchemas[2],
                {
                    { "path", "snare.wav" },
                    { "volume", "100" },
                    { "stereo", "chorus" },
                    { "pan", "-10" },
                    { "delay", "3" },
                    { "amount", "60" },
                    { "speed", "30" },
                    { "depth", "30" },
                }
            });
    m->whats.push_back({
                "A1",
                "120",
                &whatSchemas[0],
                {
                    { '!', '.', '/', },
                    { '.', '!', ':', },
                    { '.', '.', '/', },
                }});
    m->output.push_back({{ '1' }});
    m->output.push_back({{ '1' }});
    for(size_t i = 0; i < 80; ++i) {
        m->output.push_back({{ '.' }});
    }
    m->output.push_back({{ '1' }});
    create_window(m);

    return Fl::run();
#endif
}
<|endoftext|>