<commit_before>#include "optionsmodel.h"
#include "bitcoinunits.h"
#include <QSettings>

#include "init.h"
#include "walletdb.h"

OptionsModel::OptionsModel(QObject *parent) :
    QAbstractListModel(parent)
{
    Init();
}

void OptionsModel::Init()
{
    QSettings settings;

    // These are QT-only settings:
    nDisplayUnit = settings.value("nDisplayUnit", BitcoinUnits::BTC).toInt();
    bDisplayAddresses = settings.value("bDisplayAddresses", false).toBool();
    fMinimizeToTray = settings.value("fMinimizeToTray", false).toBool();
    fMinimizeOnClose = settings.value("fMinimizeOnClose", false).toBool();
    nTransactionFee = settings.value("nTransactionFee").toLongLong();

    // These are shared with core bitcoin; we want
    // command-line options to override the GUI settings:
    if (settings.contains("fUseUPnP"))
        SoftSetBoolArg("-upnp", settings.value("fUseUPnP").toBool());
    if (settings.contains("addrProxy") && settings.value("fUseProxy").toBool())
        SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString());
}

bool OptionsModel::Upgrade()
{
    QSettings settings;

    if (settings.contains("bImportFinished"))
        return false; // Already upgraded

    settings.setValue("bImportFinished", true);

    // Move settings from old wallet.dat (if any):
    CWalletDB walletdb("wallet.dat");

    QList<QString> intOptions;
    intOptions << "nDisplayUnit" << "nTransactionFee";
    foreach(QString key, intOptions)
    {
        int value = 0;
        if (walletdb.ReadSetting(key.toStdString(), value))
        {
            settings.setValue(key, value);
            walletdb.EraseSetting(key.toStdString());
        }
    }
    QList<QString> boolOptions;
    boolOptions << "bDisplayAddresses" << "fMinimizeToTray" << "fMinimizeOnClose" << "fUseProxy" << "fUseUPnP";
    foreach(QString key, boolOptions)
    {
        bool value = false;
        if (walletdb.ReadSetting(key.toStdString(), value))
        {
            settings.setValue(key, value);
            walletdb.EraseSetting(key.toStdString());
        }
    }
    try
    {
        CAddress addrProxyAddress;
        if (walletdb.ReadSetting("addrProxy", addrProxyAddress))
        {
            addrProxy = addrProxyAddress;
            settings.setValue("addrProxy", addrProxy.ToStringIPPort().c_str());
            walletdb.EraseSetting("addrProxy");
        }
    }
    catch (std::ios_base::failure &e)
    {
        // 0.6.0rc1 saved this as a CService, which causes failure when parsing as a CAddress
        if (walletdb.ReadSetting("addrProxy", addrProxy))
        {
            settings.setValue("addrProxy", addrProxy.ToStringIPPort().c_str());
            walletdb.EraseSetting("addrProxy");
        }
    }
    Init();

    return true;
}

int OptionsModel::rowCount(const QModelIndex & parent) const
{
    return OptionIDRowCount;
}

QVariant OptionsModel::data(const QModelIndex & index, int role) const
{
    if(role == Qt::EditRole)
    {
        QSettings settings;
        switch(index.row())
        {
        case StartAtStartup:
            return QVariant(GetStartOnSystemStartup());
        case MinimizeToTray:
            return QVariant(fMinimizeToTray);
        case MapPortUPnP:
            return settings.value("fUseUPnP", GetBoolArg("-upnp", true));
        case MinimizeOnClose:
            return QVariant(fMinimizeOnClose);
        case ConnectSOCKS4:
            return settings.value("fUseProxy", false);
        case ProxyIP:
            return QVariant(QString::fromStdString(addrProxy.ToStringIP()));
        case ProxyPort:
            return QVariant(addrProxy.GetPort());
        case Fee:
            return QVariant(nTransactionFee);
        case DisplayUnit:
            return QVariant(nDisplayUnit);
        case DisplayAddresses:
            return QVariant(bDisplayAddresses);
        default:
            return QVariant();
        }
    }
    return QVariant();
}

bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, int role)
{
    bool successful = true; /* set to false on parse error */
    if(role == Qt::EditRole)
    {
        QSettings settings;
        switch(index.row())
        {
        case StartAtStartup:
            successful = SetStartOnSystemStartup(value.toBool());
            break;
        case MinimizeToTray:
            fMinimizeToTray = value.toBool();
            settings.setValue("fMinimizeToTray", fMinimizeToTray);
            break;
        case MapPortUPnP:
            {
                bool bUseUPnP = value.toBool();
                settings.setValue("fUseUPnP", bUseUPnP);
                MapPort(bUseUPnP);
            }
            break;
        case MinimizeOnClose:
            fMinimizeOnClose = value.toBool();
            settings.setValue("fMinimizeOnClose", fMinimizeOnClose);
            break;
        case ConnectSOCKS4:
            fUseProxy = value.toBool();
            settings.setValue("fUseProxy", fUseProxy);
            break;
        case ProxyIP:
            {
                // Use CAddress to parse and check IP
                CNetAddr addr(value.toString().toStdString());
                if (addr.IsValid())
                {
                    addrProxy.SetIP(addr);
                    settings.setValue("addrProxy", addrProxy.ToStringIPPort().c_str());
                }
                else
                {
                    successful = false;
                }
            }
            break;
        case ProxyPort:
            {
                int nPort = atoi(value.toString().toAscii().data());
                if (nPort > 0 && nPort < std::numeric_limits<unsigned short>::max())
                {
                    addrProxy.SetPort(nPort);
                    settings.setValue("addrProxy", addrProxy.ToStringIPPort().c_str());
                }
                else
                {
                    successful = false;
                }
            }
            break;
        case Fee: {
            nTransactionFee = value.toLongLong();
            settings.setValue("nTransactionFee", nTransactionFee);
            }
            break;
        case DisplayUnit: {
            int unit = value.toInt();
            nDisplayUnit = unit;
            settings.setValue("nDisplayUnit", nDisplayUnit);
            emit displayUnitChanged(unit);
            }
        case DisplayAddresses: {
            bDisplayAddresses = value.toBool();
            settings.setValue("bDisplayAddresses", bDisplayAddresses);
            }
        default:
            break;
        }
    }
    emit dataChanged(index, index);

    return successful;
}

qint64 OptionsModel::getTransactionFee()
{
    return nTransactionFee;
}

bool OptionsModel::getMinimizeToTray()
{
    return fMinimizeToTray;
}

bool OptionsModel::getMinimizeOnClose()
{
    return fMinimizeOnClose;
}

int OptionsModel::getDisplayUnit()
{
    return nDisplayUnit;
}

bool OptionsModel::getDisplayAddresses()
{
    return bDisplayAddresses;
}
<commit_msg>Add missing breaks in optionmodel's switch case<commit_after>#include "optionsmodel.h"
#include "bitcoinunits.h"
#include <QSettings>

#include "init.h"
#include "walletdb.h"

OptionsModel::OptionsModel(QObject *parent) :
    QAbstractListModel(parent)
{
    Init();
}

void OptionsModel::Init()
{
    QSettings settings;

    // These are QT-only settings:
    nDisplayUnit = settings.value("nDisplayUnit", BitcoinUnits::BTC).toInt();
    bDisplayAddresses = settings.value("bDisplayAddresses", false).toBool();
    fMinimizeToTray = settings.value("fMinimizeToTray", false).toBool();
    fMinimizeOnClose = settings.value("fMinimizeOnClose", false).toBool();
    nTransactionFee = settings.value("nTransactionFee").toLongLong();

    // These are shared with core bitcoin; we want
    // command-line options to override the GUI settings:
    if (settings.contains("fUseUPnP"))
        SoftSetBoolArg("-upnp", settings.value("fUseUPnP").toBool());
    if (settings.contains("addrProxy") && settings.value("fUseProxy").toBool())
        SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString());
}

bool OptionsModel::Upgrade()
{
    QSettings settings;

    if (settings.contains("bImportFinished"))
        return false; // Already upgraded

    settings.setValue("bImportFinished", true);

    // Move settings from old wallet.dat (if any):
    CWalletDB walletdb("wallet.dat");

    QList<QString> intOptions;
    intOptions << "nDisplayUnit" << "nTransactionFee";
    foreach(QString key, intOptions)
    {
        int value = 0;
        if (walletdb.ReadSetting(key.toStdString(), value))
        {
            settings.setValue(key, value);
            walletdb.EraseSetting(key.toStdString());
        }
    }
    QList<QString> boolOptions;
    boolOptions << "bDisplayAddresses" << "fMinimizeToTray" << "fMinimizeOnClose" << "fUseProxy" << "fUseUPnP";
    foreach(QString key, boolOptions)
    {
        bool value = false;
        if (walletdb.ReadSetting(key.toStdString(), value))
        {
            settings.setValue(key, value);
            walletdb.EraseSetting(key.toStdString());
        }
    }
    try
    {
        CAddress addrProxyAddress;
        if (walletdb.ReadSetting("addrProxy", addrProxyAddress))
        {
            addrProxy = addrProxyAddress;
            settings.setValue("addrProxy", addrProxy.ToStringIPPort().c_str());
            walletdb.EraseSetting("addrProxy");
        }
    }
    catch (std::ios_base::failure &e)
    {
        // 0.6.0rc1 saved this as a CService, which causes failure when parsing as a CAddress
        if (walletdb.ReadSetting("addrProxy", addrProxy))
        {
            settings.setValue("addrProxy", addrProxy.ToStringIPPort().c_str());
            walletdb.EraseSetting("addrProxy");
        }
    }
    Init();

    return true;
}

int OptionsModel::rowCount(const QModelIndex & parent) const
{
    return OptionIDRowCount;
}

QVariant OptionsModel::data(const QModelIndex & index, int role) const
{
    if(role == Qt::EditRole)
    {
        QSettings settings;
        switch(index.row())
        {
        case StartAtStartup:
            return QVariant(GetStartOnSystemStartup());
        case MinimizeToTray:
            return QVariant(fMinimizeToTray);
        case MapPortUPnP:
            return settings.value("fUseUPnP", GetBoolArg("-upnp", true));
        case MinimizeOnClose:
            return QVariant(fMinimizeOnClose);
        case ConnectSOCKS4:
            return settings.value("fUseProxy", false);
        case ProxyIP:
            return QVariant(QString::fromStdString(addrProxy.ToStringIP()));
        case ProxyPort:
            return QVariant(addrProxy.GetPort());
        case Fee:
            return QVariant(nTransactionFee);
        case DisplayUnit:
            return QVariant(nDisplayUnit);
        case DisplayAddresses:
            return QVariant(bDisplayAddresses);
        default:
            return QVariant();
        }
    }
    return QVariant();
}

bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, int role)
{
    bool successful = true; /* set to false on parse error */
    if(role == Qt::EditRole)
    {
        QSettings settings;
        switch(index.row())
        {
        case StartAtStartup:
            successful = SetStartOnSystemStartup(value.toBool());
            break;
        case MinimizeToTray:
            fMinimizeToTray = value.toBool();
            settings.setValue("fMinimizeToTray", fMinimizeToTray);
            break;
        case MapPortUPnP:
            {
                bool bUseUPnP = value.toBool();
                settings.setValue("fUseUPnP", bUseUPnP);
                MapPort(bUseUPnP);
            }
            break;
        case MinimizeOnClose:
            fMinimizeOnClose = value.toBool();
            settings.setValue("fMinimizeOnClose", fMinimizeOnClose);
            break;
        case ConnectSOCKS4:
            fUseProxy = value.toBool();
            settings.setValue("fUseProxy", fUseProxy);
            break;
        case ProxyIP:
            {
                // Use CAddress to parse and check IP
                CNetAddr addr(value.toString().toStdString());
                if (addr.IsValid())
                {
                    addrProxy.SetIP(addr);
                    settings.setValue("addrProxy", addrProxy.ToStringIPPort().c_str());
                }
                else
                {
                    successful = false;
                }
            }
            break;
        case ProxyPort:
            {
                int nPort = atoi(value.toString().toAscii().data());
                if (nPort > 0 && nPort < std::numeric_limits<unsigned short>::max())
                {
                    addrProxy.SetPort(nPort);
                    settings.setValue("addrProxy", addrProxy.ToStringIPPort().c_str());
                }
                else
                {
                    successful = false;
                }
            }
            break;
        case Fee: {
            nTransactionFee = value.toLongLong();
            settings.setValue("nTransactionFee", nTransactionFee);
            }
            break;
        case DisplayUnit: {
            int unit = value.toInt();
            nDisplayUnit = unit;
            settings.setValue("nDisplayUnit", nDisplayUnit);
            emit displayUnitChanged(unit);
            }
            break;
        case DisplayAddresses: {
            bDisplayAddresses = value.toBool();
            settings.setValue("bDisplayAddresses", bDisplayAddresses);
            }
            break;
        default:
            break;
        }
    }
    emit dataChanged(index, index);

    return successful;
}

qint64 OptionsModel::getTransactionFee()
{
    return nTransactionFee;
}

bool OptionsModel::getMinimizeToTray()
{
    return fMinimizeToTray;
}

bool OptionsModel::getMinimizeOnClose()
{
    return fMinimizeOnClose;
}

int OptionsModel::getDisplayUnit()
{
    return nDisplayUnit;
}

bool OptionsModel::getDisplayAddresses()
{
    return bDisplayAddresses;
}
<|endoftext|>


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

#include "native_client/src/trusted/plugin/srpc/video.h"
#include "native_client/src/trusted/plugin/srpc/browser_interface.h"

// This file provides empty implementation for video functions used in NaCl code
// These functions should not be used when running as part of Chrome, but to
// avoid multiple changes in many places in the code, we just provide this
// dummy implementation.

namespace plugin {

class Plugin;

void VideoGlobalLock() {
  return;
}

void VideoGlobalUnlock() {
  return;
}

void VideoMap::Redraw() {
  return;
}

void VideoMap::RedrawAsync(void *platform_parm) {
  return;
}

// assumes event is already normalized to NaClMultimediaEvent
int VideoMap::EventQueuePut(union NaClMultimediaEvent *event) {
  return -1;
}

// tests event queue to see if it is full
int VideoMap::EventQueueIsFull() {
  return 1;
}

// Gets the last recorded mouse motion (position)
// note: outputs normalized for NaCl events
void VideoMap::GetMotion(uint16_t *x, uint16_t *y) {
  return;
}

// Sets the mouse motion (position)
// note: the inputs must be normalized for NaCl events
void VideoMap::SetMotion(uint16_t x, uint16_t y, int last_valid) {
  return;
}

// Gets the relative mouse motion and updates position
// note: the inputs must be normalized for NaCl events
void VideoMap::GetRelativeMotion(uint16_t x,
                                 uint16_t y,
                                 int16_t *rel_x,
                                 int16_t *rel_y) {
  return;
}

// Gets the current mouse button state
// note: output is normalized for NaCl events
int VideoMap::GetButton() {
  return 0;
}

// Modifies the mouse button state
// note: input must be normalized for NaCl events
void VideoMap::SetButton(int button, int state) {
  return;
}

// Modifies the keyboard modifier state (shift, ctrl, alt, etc)
// note: input must be normalized for NaCl events
void VideoMap::SetKeyMod(int nsym, int state) {
  return;
}

// Gets the current keyboard modifier state
// note: output is normalized for NaCl Events
int VideoMap::GetKeyMod() {
  return 0;
}

// handle video map specific NPAPI SetWindow
bool VideoMap::SetWindow(PluginWindow *window) {
  // TODO(gregoryd): do something with this information
  // or remove this file.
  return true;
}

int16_t VideoMap::HandleEvent(void *param) {
  return 0;
}

ScriptableHandle* VideoMap::VideoSharedMemorySetup() {
  return NULL;
}

void VideoMap::Invalidate() {
  return;
}

VideoCallbackData* VideoMap::InitCallbackData(nacl::DescWrapper* desc,
                                              BrowserInterface *p,
                                              MultimediaSocket *msp) {
  return NULL;
}

// static method
VideoCallbackData* VideoMap::ReleaseCallbackData(VideoCallbackData* vcd) {
  return NULL;
}

// static method
// normally, the Release version is preferred, which reference counts.
// in some cases we may just need to forcefully delete the callback data,
// and ignore the refcount.
void VideoMap::ForceDeleteCallbackData(VideoCallbackData* vcd) {
  return;
}

// opens shared memory map into untrusted space
// returns 0 success, -1 failure
int VideoMap::InitializeSharedMemory(PluginWindow *window) {
  return -1;
}

// this is the draw method the upcall thread should invoke
void VideoMap::RequestRedraw() {
  return;
}

VideoMap::VideoMap(BrowserInterface *browser_interface) {
  browser_interface_ = browser_interface;
}

VideoMap::~VideoMap() {
}

}  // namespace plugin
<commit_msg>Once more trying to fix Chrome video build errors.<commit_after>// Copyright (c) 2008 The Native Client Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "native_client/src/trusted/plugin/srpc/video.h"
#include "native_client/src/trusted/plugin/srpc/browser_interface.h"

// This file provides empty implementation for video functions used in NaCl code
// These functions should not be used when running as part of Chrome, but to
// avoid multiple changes in many places in the code, we just provide this
// dummy implementation.

namespace plugin {

class Plugin;

void VideoGlobalLock() {
  return;
}

void VideoGlobalUnlock() {
  return;
}

void VideoMap::Redraw() {
  return;
}

void VideoMap::RedrawAsync(void *platform_parm) {
  return;
}

// assumes event is already normalized to NaClMultimediaEvent
int VideoMap::EventQueuePut(union NaClMultimediaEvent *event) {
  return -1;
}

// tests event queue to see if it is full
int VideoMap::EventQueueIsFull() {
  return 1;
}

// Gets the last recorded mouse motion (position)
// note: outputs normalized for NaCl events
void VideoMap::GetMotion(uint16_t *x, uint16_t *y) {
  return;
}

// Sets the mouse motion (position)
// note: the inputs must be normalized for NaCl events
void VideoMap::SetMotion(uint16_t x, uint16_t y, int last_valid) {
  return;
}

// Gets the relative mouse motion and updates position
// note: the inputs must be normalized for NaCl events
void VideoMap::GetRelativeMotion(uint16_t x,
                                 uint16_t y,
                                 int16_t *rel_x,
                                 int16_t *rel_y) {
  return;
}

// Gets the current mouse button state
// note: output is normalized for NaCl events
int VideoMap::GetButton() {
  return 0;
}

// Modifies the mouse button state
// note: input must be normalized for NaCl events
void VideoMap::SetButton(int button, int state) {
  return;
}

// Modifies the keyboard modifier state (shift, ctrl, alt, etc)
// note: input must be normalized for NaCl events
void VideoMap::SetKeyMod(int nsym, int state) {
  return;
}

// Gets the current keyboard modifier state
// note: output is normalized for NaCl Events
int VideoMap::GetKeyMod() {
  return 0;
}

// handle video map specific NPAPI SetWindow
bool VideoMap::SetWindow(PluginWindow *window) {
  // TODO(gregoryd): do something with this information
  // or remove this file.
  return true;
}

int16_t VideoMap::HandleEvent(void *param) {
  return 0;
}

ScriptableHandle* VideoMap::VideoSharedMemorySetup() {
  return NULL;
}

void VideoMap::Invalidate() {
  return;
}

VideoCallbackData* VideoMap::InitCallbackData(nacl::DescWrapper* desc,
                                              Plugin *p,
                                              MultimediaSocket *msp) {
  return NULL;
}

// static method
VideoCallbackData* VideoMap::ReleaseCallbackData(VideoCallbackData* vcd) {
  return NULL;
}

// static method
// normally, the Release version is preferred, which reference counts.
// in some cases we may just need to forcefully delete the callback data,
// and ignore the refcount.
void VideoMap::ForceDeleteCallbackData(VideoCallbackData* vcd) {
  return;
}

// opens shared memory map into untrusted space
// returns 0 success, -1 failure
int VideoMap::InitializeSharedMemory(PluginWindow *window) {
  return -1;
}

// this is the draw method the upcall thread should invoke
void VideoMap::RequestRedraw() {
  return;
}

VideoMap::VideoMap(Plugin *plugin) {
}

VideoMap::~VideoMap() {
}

}  // namespace plugin
<|endoftext|>


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

daemon gpl source code
copyright (c) 2013 unvanquished developers

this file is part of the daemon gpl source code (daemon source code).

daemon source code 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 3 of the license, or
(at your option) any later version.

daemon source code 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 daemon source code.  if not, see <http://www.gnu.org/licenses/>.

===========================================================================
*/

#include "AudioPrivate.h"

namespace Audio {

    //TODO lazily check for the values
    static Cvar::Range<Cvar::Cvar<float>> effectsVolume("audio.volume.effects", "the volume of the effects", Cvar::ARCHIVE, 0.8f, 0.0f, 1.0f);
    static Cvar::Range<Cvar::Cvar<float>> musicVolume("audio.volume.music", "the volume of the music", Cvar::ARCHIVE, 0.8f, 0.0f, 1.0f);

    // We have a big, fixed number of source to avoid rendering too many sounds and slowing down the rest of the engine.
    struct sourceRecord_t {
        AL::Source source;
        std::shared_ptr<Sound> usingSound;
        bool active;
        int priority;
    };

    static sourceRecord_t* sources = nullptr;
    static const int nSources = 128; //TODO see what's the limit for OpenAL soft

    sourceRecord_t* GetSource(int priority);

    static bool initialized = false;

    void InitSounds() {
        if (initialized) {
            return;
        }

        sources = new sourceRecord_t[nSources];

        for (int i = 0; i < nSources; i++) {
            sources[i].active = false;
        }

        initialized = true;
    }

    void ShutdownSounds() {
        if (not initialized) {
            return;
        }

        delete[] sources;
        sources = nullptr;

        initialized = false;
    }

    void UpdateSounds() {
        for (int i = 0; i < nSources; i++) {
            if (sources[i].active) {
                auto sound = sources[i].usingSound;

                // Update and Emitter::UpdateSound can call Sound::Stop
                if (not sound->IsStopped()) {
                    sound->Update();
                }

                if (not sound->IsStopped()) {
                    sound->GetEmitter()->UpdateSound(*sound);
                }

                if (sound->IsStopped()) {
                    sources[i].active = false;
                    sources[i].usingSound = nullptr;
                }
            }
        }
    }

    void AddSound(std::shared_ptr<Emitter> emitter, std::shared_ptr<Sound> sound, int priority) {
        sourceRecord_t* source = GetSource(priority);

        if (source) {
            // Make the source forget if it was a "static" or a "streaming" source.
            source->source.ResetBuffer();
            sound->SetEmitter(emitter);
            sound->AcquireSource(source->source);
            source->usingSound = sound;
            source->priority = priority;
            source->active = true;

            sound->FinishSetup();
            sound->Play();
        }
    }

    // Finds a inactive or low-priority source to play a new sound.
    sourceRecord_t* GetSource(int priority) {
        //TODO make a better heuristic? (take into account the distance / the volume /... ?)
        int best = -1;
        int bestPriority = priority;

        // Gets the minimum sound by comparing activity first then priority
        for (int i = 0; i < nSources; i++) {
            sourceRecord_t& source = sources[i];

            if (not source.active) {
                return &source;
            }

            if (best < 0 && source.priority <= priority) {
                best = i;
                bestPriority = source.priority;
                continue;
            }

            if (source.priority < bestPriority) {
                best = i;
                bestPriority = source.priority;
                continue;
            }
        }

        if (best >= 0) {
            sourceRecord_t& source = sources[best];

            source.source.Stop();
            source.source.RemoveAllQueuedBuffers();

            source.usingSound = nullptr;
            return &source;
        } else {
            return nullptr;
        }
    }

    // Implementation of Sound

    Sound::Sound(): positionalGain(1.0f), soundGain(1.0f), currentGain(1.0f), playing(false), source(nullptr) {
    }

    Sound::~Sound() {
    }

    void Sound::Play() {
        source->Play();
        playing = true;
    }

    void Sound::Stop() {
        source->Stop();
        playing = false;
    }

    bool Sound::IsStopped() {
        return not playing;
    }

    void Sound::SetPositionalGain(float gain) {
        positionalGain = gain;
    }

    void Sound::SetSoundGain(float gain) {
        soundGain = gain;
    }

    float Sound::GetCurrentGain() {
        return currentGain;
    }

    void Sound::SetEmitter(std::shared_ptr<Emitter> emitter) {
        this->emitter = emitter;
    }

    std::shared_ptr<Emitter> Sound::GetEmitter() {
        return emitter;
    }

    void Sound::AcquireSource(AL::Source& source) {
        this->source = &source;

        source.SetLooping(false);

        SetupSource(source);
        emitter->SetupSound(*this);
    }

    AL::Source& Sound::GetSource() {
        return *source;
    }

    // Set the gain before the source is started to avoid having a few milliseconds of very lound sound
    void Sound::FinishSetup() {
        currentGain = positionalGain * soundGain * effectsVolume.Get();
        source->SetGain(currentGain);
    }

    void Sound::Update() {
        // Fade the Gain update to avoid "ticking" sounds when there is a gain discontinuity
        float targetGain = positionalGain * soundGain * effectsVolume.Get();

        //TODO make it framerate independant and fade out in about 1/8 seconds ?
        if (currentGain > targetGain) {
            currentGain = std::max(currentGain - 0.02f, targetGain);
            //currentGain = std::max(currentGain * 1.05f, targetGain);
        } else if (currentGain < targetGain) {
            currentGain = std::min(currentGain + 0.02f, targetGain);
            //currentGain = std::min(currentGain / 1.05f - 0.01f, targetGain);
        }

        source->SetGain(currentGain);

        InternalUpdate();
    }
    // Implementation of OneShotSound

    OneShotSound::OneShotSound(Sample* sample): sample(sample) {
    }

    OneShotSound::~OneShotSound() {
    }

    void OneShotSound::SetupSource(AL::Source& source) {
        source.SetBuffer(sample->GetBuffer());
        SetSoundGain(effectsVolume.Get());
    }

    void OneShotSound::InternalUpdate() {
        if (GetSource().IsStopped()) {
            Stop();
            return;
        }
        SetSoundGain(effectsVolume.Get());
    }

    // Implementation of LoopingSound

    LoopingSound::LoopingSound(Sample* sample): sample(sample), fadingOut(false) {
    }

    LoopingSound::~LoopingSound() {
    }

    void LoopingSound::FadeOutAndDie() {
        fadingOut = true;
        SetSoundGain(0.0f);
    }

    void LoopingSound::SetupSource(AL::Source& source) {
        source.SetLooping(true);
        source.SetBuffer(sample->GetBuffer());
        SetSoundGain(effectsVolume.Get());
    }

    void LoopingSound::InternalUpdate() {
        if (fadingOut and GetCurrentGain() == 0.0f) {
            Stop();
        }

        if (not fadingOut) {
            SetSoundGain(effectsVolume.Get());
        }
    }

    // Implementation of MusicSound

    MusicSound::MusicSound(Str::StringRef leadingStreamName, Str::StringRef loopStreamName)
        : leadingStream(S_CodecOpenStream(leadingStreamName.c_str())),
          loopStreamName(loopStreamName), loopStream(nullptr), playingLeadingSound(true){
    }

    MusicSound::~MusicSound() {
        if (leadingStream) {
            S_CodecCloseStream(leadingStream);
        }
        if (loopStream) {
            S_CodecCloseStream(loopStream);
        }
    }

    void MusicSound::SetupSource(AL::Source& source) {
        for (int i = 0; i < NUM_BUFFERS; i++) {
            AppendBuffer(source, std::move(AL::Buffer()));
        }
        SetSoundGain(musicVolume.Get());
    }

    void MusicSound::InternalUpdate() {
        AL::Source& source = GetSource();

        // Fill processed buffers and queue them back in the source
        while (source.GetNumProcessedBuffers() > 0) {
            AppendBuffer(source, std::move(source.PopBuffer()));
        }

        // If we don't have any more buffers queued it means we have to stop the music
        if (source.GetNumQueuedBuffers() == 0) {
            Stop();

        // If the source stopped because of a lack of buffer but we still have data to play we start the source again
        } else if (source.IsStopped()) {
            Play();
        }

        SetSoundGain(musicVolume.Get());
    }

    void MusicSound::AppendBuffer(AL::Source& source, AL::Buffer buffer) {
        snd_stream_t* streamToRead;
        if (playingLeadingSound and leadingStream) {
            streamToRead = leadingStream;
        } else if (loopStream) {
            streamToRead = loopStream;
        } else {
            return;
        }

        static char tempBuffer[CHUNK_SIZE];
        int lengthRead = S_CodecReadStream(streamToRead, CHUNK_SIZE, tempBuffer);

        // if a stream is finished, we start playing the loop again, if possible
        if (lengthRead == 0) {
            S_CodecCloseStream(streamToRead);
            playingLeadingSound = false;
            // either the stream was the leadin stream and we null it
            leadingStream = nullptr;
            // either it is the loop stream and we overwrite it
            loopStream = S_CodecOpenStream(loopStreamName.c_str());
            AppendBuffer(source, std::move(buffer));
            return;
        }

        snd_info_t streamInfo = streamToRead->info;
        streamInfo.size = lengthRead; // this isn't set by Codec
        buffer.Feed(streamInfo, tempBuffer);

        source.QueueBuffer(std::move(buffer));
    }

    // Implementation of StreamingSound

    StreamingSound::StreamingSound() {
    }

    StreamingSound::~StreamingSound() {
    }

    void StreamingSound::SetupSource(AL::Source&) {
    }

    void StreamingSound::InternalUpdate() {
        AL::Source& source = GetSource();

        while (source.GetNumProcessedBuffers() > 0) {
            source.PopBuffer();
        }

        if (source.GetNumQueuedBuffers() == 0) {
            Stop();
        }
    }

	//TODO somehow try to catch back when data is coming faster than we consume (e.g. capture data)
    void StreamingSound::AppendBuffer(AL::Buffer buffer) {
        if (IsStopped()) {
            return;
        }

        AL::Source& source = GetSource();
        source.QueueBuffer(std::move(buffer));

        if (source.IsStopped()) {
            source.Play();
        }
    }

    void StreamingSound::SetGain(float gain) {
        SetSoundGain(gain);
    }
}
<commit_msg>Audio: fix the music loop not starting if there is no leading sound<commit_after>/*
===========================================================================

daemon gpl source code
copyright (c) 2013 unvanquished developers

this file is part of the daemon gpl source code (daemon source code).

daemon source code 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 3 of the license, or
(at your option) any later version.

daemon source code 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 daemon source code.  if not, see <http://www.gnu.org/licenses/>.

===========================================================================
*/

#include "AudioPrivate.h"

namespace Audio {

    //TODO lazily check for the values
    static Cvar::Range<Cvar::Cvar<float>> effectsVolume("audio.volume.effects", "the volume of the effects", Cvar::ARCHIVE, 0.8f, 0.0f, 1.0f);
    static Cvar::Range<Cvar::Cvar<float>> musicVolume("audio.volume.music", "the volume of the music", Cvar::ARCHIVE, 0.8f, 0.0f, 1.0f);

    // We have a big, fixed number of source to avoid rendering too many sounds and slowing down the rest of the engine.
    struct sourceRecord_t {
        AL::Source source;
        std::shared_ptr<Sound> usingSound;
        bool active;
        int priority;
    };

    static sourceRecord_t* sources = nullptr;
    static const int nSources = 128; //TODO see what's the limit for OpenAL soft

    sourceRecord_t* GetSource(int priority);

    static bool initialized = false;

    void InitSounds() {
        if (initialized) {
            return;
        }

        sources = new sourceRecord_t[nSources];

        for (int i = 0; i < nSources; i++) {
            sources[i].active = false;
        }

        initialized = true;
    }

    void ShutdownSounds() {
        if (not initialized) {
            return;
        }

        delete[] sources;
        sources = nullptr;

        initialized = false;
    }

    void UpdateSounds() {
        for (int i = 0; i < nSources; i++) {
            if (sources[i].active) {
                auto sound = sources[i].usingSound;

                // Update and Emitter::UpdateSound can call Sound::Stop
                if (not sound->IsStopped()) {
                    sound->Update();
                }

                if (not sound->IsStopped()) {
                    sound->GetEmitter()->UpdateSound(*sound);
                }

                if (sound->IsStopped()) {
                    sources[i].active = false;
                    sources[i].usingSound = nullptr;
                }
            }
        }
    }

    void AddSound(std::shared_ptr<Emitter> emitter, std::shared_ptr<Sound> sound, int priority) {
        sourceRecord_t* source = GetSource(priority);

        if (source) {
            // Make the source forget if it was a "static" or a "streaming" source.
            source->source.ResetBuffer();
            sound->SetEmitter(emitter);
            sound->AcquireSource(source->source);
            source->usingSound = sound;
            source->priority = priority;
            source->active = true;

            sound->FinishSetup();
            sound->Play();
        }
    }

    // Finds a inactive or low-priority source to play a new sound.
    sourceRecord_t* GetSource(int priority) {
        //TODO make a better heuristic? (take into account the distance / the volume /... ?)
        int best = -1;
        int bestPriority = priority;

        // Gets the minimum sound by comparing activity first then priority
        for (int i = 0; i < nSources; i++) {
            sourceRecord_t& source = sources[i];

            if (not source.active) {
                return &source;
            }

            if (best < 0 && source.priority <= priority) {
                best = i;
                bestPriority = source.priority;
                continue;
            }

            if (source.priority < bestPriority) {
                best = i;
                bestPriority = source.priority;
                continue;
            }
        }

        if (best >= 0) {
            sourceRecord_t& source = sources[best];

            source.source.Stop();
            source.source.RemoveAllQueuedBuffers();

            source.usingSound = nullptr;
            return &source;
        } else {
            return nullptr;
        }
    }

    // Implementation of Sound

    Sound::Sound(): positionalGain(1.0f), soundGain(1.0f), currentGain(1.0f), playing(false), source(nullptr) {
    }

    Sound::~Sound() {
    }

    void Sound::Play() {
        source->Play();
        playing = true;
    }

    void Sound::Stop() {
        source->Stop();
        playing = false;
    }

    bool Sound::IsStopped() {
        return not playing;
    }

    void Sound::SetPositionalGain(float gain) {
        positionalGain = gain;
    }

    void Sound::SetSoundGain(float gain) {
        soundGain = gain;
    }

    float Sound::GetCurrentGain() {
        return currentGain;
    }

    void Sound::SetEmitter(std::shared_ptr<Emitter> emitter) {
        this->emitter = emitter;
    }

    std::shared_ptr<Emitter> Sound::GetEmitter() {
        return emitter;
    }

    void Sound::AcquireSource(AL::Source& source) {
        this->source = &source;

        source.SetLooping(false);

        SetupSource(source);
        emitter->SetupSound(*this);
    }

    AL::Source& Sound::GetSource() {
        return *source;
    }

    // Set the gain before the source is started to avoid having a few milliseconds of very lound sound
    void Sound::FinishSetup() {
        currentGain = positionalGain * soundGain * effectsVolume.Get();
        source->SetGain(currentGain);
    }

    void Sound::Update() {
        // Fade the Gain update to avoid "ticking" sounds when there is a gain discontinuity
        float targetGain = positionalGain * soundGain * effectsVolume.Get();

        //TODO make it framerate independant and fade out in about 1/8 seconds ?
        if (currentGain > targetGain) {
            currentGain = std::max(currentGain - 0.02f, targetGain);
            //currentGain = std::max(currentGain * 1.05f, targetGain);
        } else if (currentGain < targetGain) {
            currentGain = std::min(currentGain + 0.02f, targetGain);
            //currentGain = std::min(currentGain / 1.05f - 0.01f, targetGain);
        }

        source->SetGain(currentGain);

        InternalUpdate();
    }
    // Implementation of OneShotSound

    OneShotSound::OneShotSound(Sample* sample): sample(sample) {
    }

    OneShotSound::~OneShotSound() {
    }

    void OneShotSound::SetupSource(AL::Source& source) {
        source.SetBuffer(sample->GetBuffer());
        SetSoundGain(effectsVolume.Get());
    }

    void OneShotSound::InternalUpdate() {
        if (GetSource().IsStopped()) {
            Stop();
            return;
        }
        SetSoundGain(effectsVolume.Get());
    }

    // Implementation of LoopingSound

    LoopingSound::LoopingSound(Sample* sample): sample(sample), fadingOut(false) {
    }

    LoopingSound::~LoopingSound() {
    }

    void LoopingSound::FadeOutAndDie() {
        fadingOut = true;
        SetSoundGain(0.0f);
    }

    void LoopingSound::SetupSource(AL::Source& source) {
        source.SetLooping(true);
        source.SetBuffer(sample->GetBuffer());
        SetSoundGain(effectsVolume.Get());
    }

    void LoopingSound::InternalUpdate() {
        if (fadingOut and GetCurrentGain() == 0.0f) {
            Stop();
        }

        if (not fadingOut) {
            SetSoundGain(effectsVolume.Get());
        }
    }

    // Implementation of MusicSound

    MusicSound::MusicSound(Str::StringRef leadingStreamName, Str::StringRef loopStreamName)
        : leadingStream(nullptr), loopStreamName(loopStreamName), loopStream(nullptr), playingLeadingSound(true) {

        //Try to open the leading sound
        if (leadingStreamName != "") {
            leadingStream = S_CodecOpenStream(leadingStreamName.c_str());
        }

        //Start the loop if it failed
        if (not leadingStream) {
            playingLeadingSound = false;
            if (loopStreamName != "") {
                loopStream = S_CodecOpenStream(loopStreamName.c_str());
            }
        }
    }

    MusicSound::~MusicSound() {
        if (leadingStream) {
            S_CodecCloseStream(leadingStream);
        }
        if (loopStream) {
            S_CodecCloseStream(loopStream);
        }
    }

    void MusicSound::SetupSource(AL::Source& source) {
        for (int i = 0; i < NUM_BUFFERS; i++) {
            AppendBuffer(source, std::move(AL::Buffer()));
        }
        SetSoundGain(musicVolume.Get());
    }

    void MusicSound::InternalUpdate() {
        AL::Source& source = GetSource();

        // Fill processed buffers and queue them back in the source
        while (source.GetNumProcessedBuffers() > 0) {
            AppendBuffer(source, std::move(source.PopBuffer()));
        }

        // If we don't have any more buffers queued it means we have to stop the music
        if (source.GetNumQueuedBuffers() == 0) {
            Stop();

        // If the source stopped because of a lack of buffer but we still have data to play we start the source again
        } else if (source.IsStopped()) {
            Play();
        }

        SetSoundGain(musicVolume.Get());
    }

    void MusicSound::AppendBuffer(AL::Source& source, AL::Buffer buffer) {
        snd_stream_t* streamToRead;
        if (playingLeadingSound and leadingStream) {
            streamToRead = leadingStream;
        } else if (loopStream) {
            streamToRead = loopStream;
        } else {
            return;
        }

        static char tempBuffer[CHUNK_SIZE];
        int lengthRead = S_CodecReadStream(streamToRead, CHUNK_SIZE, tempBuffer);

        // if a stream is finished, we start playing the loop again, if possible
        if (lengthRead == 0) {
            S_CodecCloseStream(streamToRead);
            playingLeadingSound = false;
            // either the stream was the leadin stream and we null it
            leadingStream = nullptr;

            // either it is the loop stream and we overwrite it
            if (loopStreamName != "") {
                loopStream = S_CodecOpenStream(loopStreamName.c_str());
                AppendBuffer(source, std::move(buffer));
            }
            return;
        }

        snd_info_t streamInfo = streamToRead->info;
        streamInfo.size = lengthRead; // this isn't set by Codec
        buffer.Feed(streamInfo, tempBuffer);

        source.QueueBuffer(std::move(buffer));
    }

    // Implementation of StreamingSound

    StreamingSound::StreamingSound() {
    }

    StreamingSound::~StreamingSound() {
    }

    void StreamingSound::SetupSource(AL::Source&) {
    }

    void StreamingSound::InternalUpdate() {
        AL::Source& source = GetSource();

        while (source.GetNumProcessedBuffers() > 0) {
            source.PopBuffer();
        }

        if (source.GetNumQueuedBuffers() == 0) {
            Stop();
        }
    }

	//TODO somehow try to catch back when data is coming faster than we consume (e.g. capture data)
    void StreamingSound::AppendBuffer(AL::Buffer buffer) {
        if (IsStopped()) {
            return;
        }

        AL::Source& source = GetSource();
        source.QueueBuffer(std::move(buffer));

        if (source.IsStopped()) {
            source.Play();
        }
    }

    void StreamingSound::SetGain(float gain) {
        SetSoundGain(gain);
    }
}
<|endoftext|>


<commit_before>#include "scene/Scene.hpp"
#include "scene/Sky.hpp"
#include "system/TextUtilities.hpp"
#include "system/Query.hpp"

#include <map>
#include <sstream>

Scene::Scene(const std::string & name) {
	// Append the extension if needed.
	std::string fullName = name;
	if(!TextUtilities::hasSuffix(name, ".scene")) {
		fullName += ".scene";
	}
	_name = fullName;
}

void printToken(const KeyValues & tk, const std::string & shift) {
	Log::Info() << shift << tk.key << ": " << std::endl;
	if(!tk.values.empty()) {
		Log::Info() << shift << "\t";
		for(const auto & val : tk.values) {
			Log::Info() << val << " | ";
		}
		Log::Info() << std::endl;
	}
	for(const auto & subtk : tk.elements) {
		printToken(subtk, shift + "\t");
	}
}

bool Scene::init(Storage options) {
	if(_loaded) {
		return true;
	}

	Query timer;
	timer.begin();

	// Define loaders for each keyword.
	std::map<std::string, void (Scene::*)(const KeyValues &, Storage)> loaders = {
		{"scene", &Scene::loadScene}, {"object", &Scene::loadObject}, {"point", &Scene::loadLight}, {"directional", &Scene::loadLight}, {"spot", &Scene::loadLight}, {"camera", &Scene::loadCamera}, {"background", &Scene::loadBackground}, {"probe", &Scene::loadProbe}};

	// Parse the file.
	const std::string sceneFile			   = Resources::manager().getString(_name);
	if(sceneFile.empty()) {
		return false;
	}
	const std::vector<KeyValues> allParams = Codable::decode(sceneFile);

	// Process each group of keyvalues.
	for(const auto & element : allParams) {
		const std::string key = element.key;
		// By construction (see above), all keys should have a loader.
		(this->*loaders[key])(element, options);
	}

	// Update all objects poses.
	for(auto & object : objects) {
		const glm::mat4 newModel = _sceneModel * object.model();
		object.set(newModel);
	}
	// The scene model matrix has been applied to all objects, we can reset it.
	_sceneModel = glm::mat4(1.0f);
	// Update all lights bounding box infos.
	_bbox = computeBoundingBox(true);
	for(auto & light : lights) {
		light->setScene(_bbox);
	}

	// Check if the environment has been setup.
	if(environment.type() == LightProbe::Type::DEFAULT){
		KeyValues defaultKv("probe");
		environment.decode(defaultKv, options);
	}
	_loaded = true;

	// Check if the scene is static.
	for(const auto & obj : objects){
		if(obj.animated()){
			_animated = true;
			break;
		}
	}
	for(const auto & light : lights){
		if(light->animated()){
			_animated = true;
			break;
		}
	}

	timer.end();
	Log::Info() << Log::Resources << "Loading took " << (float(timer.value())/1000000.0f) << "ms." << std::endl;
	return true;
}

void Scene::loadObject(const KeyValues & params, Storage options) {
	objects.emplace_back();
	objects.back().decode(params, options);
}

void Scene::loadLight(const KeyValues & params, Storage) {
	const auto light = Light::decode(params);
	if(light) {
		lights.push_back(light);
	}
}

void Scene::loadCamera(const KeyValues & params, Storage) {
	_camera.decode(params);
}

void Scene::loadBackground(const KeyValues & params, Storage options) {
	background = std::unique_ptr<Object>(new Object(Object::Type::Common, Resources::manager().getMesh("plane", options), false));

	for(const auto & param : params.elements) {
		if(param.key == "color") {
			backgroundMode = Background::COLOR;
			// Background is a plane, store the color.
			backgroundColor = Codable::decodeVec3(param);

		} else if(param.key == "image" && !param.elements.empty()) {
			backgroundMode = Background::IMAGE;
			// Load image described as sub-element.
			const auto texInfos = Codable::decodeTexture(param.elements[0]);
			const Texture * tex = Resources::manager().getTexture(texInfos.first, texInfos.second, options);
			background->addTexture(tex);

		} else if(param.key == "cube" && !param.elements.empty()) {
			backgroundMode = Background::SKYBOX;
			// Object is a textured skybox.
			background = std::unique_ptr<Object>(new Object(Object::Type::Common, Resources::manager().getMesh("skybox", options), false));
			background->decode(params, options);
			// Load cubemap described as subelement.
			const auto texInfos = Codable::decodeTexture(param.elements[0]);
			const Texture * tex = Resources::manager().getTexture(texInfos.first, texInfos.second, options);
			background->addTexture(tex);

		} else if(param.key == "sun") {
			// In that case the background is a sky object.
			backgroundMode = Background::ATMOSPHERE;
			background	 = std::unique_ptr<Sky>(new Sky(options));
			background->decode(params, options);
			// Load the scattering table.
			const Texture * tex = Resources::manager().getTexture("scattering-precomputed", {Layout::RGB32F, Filter::LINEAR_LINEAR, Wrap::CLAMP}, options);
			background->addTexture(tex);
		}
	}
}

void Scene::loadProbe(const KeyValues & params, Storage options) {
	environment.decode(params, options);
}

void Scene::loadScene(const KeyValues & params, Storage) {
	// Update matrix, there is at most one transformation in the scene object.
	_sceneModel = Codable::decodeTransformation(params.elements);
}

std::vector<KeyValues> Scene::encode() const {
	std::vector<KeyValues> tokens;

	// Encode the scene
	tokens.emplace_back("scene");
	auto & scnNode = tokens.back();
	scnNode.elements.push_back(environment.encode());

	// Encode the scene transformation.
	const auto modelKeys = Codable::encode(_sceneModel);
	for(const auto & key : modelKeys){
		scnNode.elements.push_back(key);
	}

	// Encode the background.
	KeyValues bgNode("background");

	switch (backgroundMode) {
		case Background::COLOR:
			bgNode.elements.emplace_back("color");
			bgNode.elements.back().values = { Codable::encode(backgroundColor) };
			break;
		case Background::IMAGE:
			bgNode.elements.emplace_back("image");
			bgNode.elements.back().elements = { Codable::encode(background->textures()[0]) };
			break;
		case Background::SKYBOX:
			bgNode.elements.emplace_back("cube");
			bgNode.elements.back().elements = { Codable::encode(background->textures()[0]) };
		break;
		case Background::ATMOSPHERE:
			bgNode = background->encode();
			bgNode.key = "background";
		break;
		default:
			break;
	}
	tokens.push_back(bgNode);
	// Encode the objects
	for(const auto & obj : objects){
		tokens.push_back(obj.encode());
	}
	// Encode the lights
	for(const auto & light : lights){
		tokens.push_back(light->encode());
	}
	tokens.push_back(_camera.encode());
	return tokens;
}

BoundingBox Scene::computeBoundingBox(bool onlyShadowCasters) {
	BoundingBox bbox;
	if(objects.empty()) {
		return bbox;
	}

	for(Object & obj : objects) {
		if(onlyShadowCasters && !obj.castsShadow()) {
			continue;
		}
		bbox.merge(obj.boundingBox());
	}
	Log::Info() << Log::Resources << "Scene bounding box:" << std::endl
				<< "\t\tmini: " << bbox.minis << std::endl
				<< "\t\tmaxi: " << bbox.maxis << "." << std::endl;
	return bbox;
}

void Scene::update(double fullTime, double frameTime) {
	for(auto & light : lights) {
		light->update(fullTime, frameTime);
	}
	for(auto & object : objects) {
		object.update(fullTime, frameTime);
	}
	background->update(fullTime, frameTime);
}
<commit_msg>Scene: pre-sort objects based on material.<commit_after>#include "scene/Scene.hpp"
#include "scene/Sky.hpp"
#include "system/TextUtilities.hpp"
#include "system/Query.hpp"

#include <map>
#include <sstream>

Scene::Scene(const std::string & name) {
	// Append the extension if needed.
	std::string fullName = name;
	if(!TextUtilities::hasSuffix(name, ".scene")) {
		fullName += ".scene";
	}
	_name = fullName;
}

void printToken(const KeyValues & tk, const std::string & shift) {
	Log::Info() << shift << tk.key << ": " << std::endl;
	if(!tk.values.empty()) {
		Log::Info() << shift << "\t";
		for(const auto & val : tk.values) {
			Log::Info() << val << " | ";
		}
		Log::Info() << std::endl;
	}
	for(const auto & subtk : tk.elements) {
		printToken(subtk, shift + "\t");
	}
}

bool Scene::init(Storage options) {
	if(_loaded) {
		return true;
	}

	Query timer;
	timer.begin();

	// Define loaders for each keyword.
	std::map<std::string, void (Scene::*)(const KeyValues &, Storage)> loaders = {
		{"scene", &Scene::loadScene}, {"object", &Scene::loadObject}, {"point", &Scene::loadLight}, {"directional", &Scene::loadLight}, {"spot", &Scene::loadLight}, {"camera", &Scene::loadCamera}, {"background", &Scene::loadBackground}, {"probe", &Scene::loadProbe}};

	// Parse the file.
	const std::string sceneFile			   = Resources::manager().getString(_name);
	if(sceneFile.empty()) {
		return false;
	}
	const std::vector<KeyValues> allParams = Codable::decode(sceneFile);

	// Process each group of keyvalues.
	for(const auto & element : allParams) {
		const std::string key = element.key;
		// By construction (see above), all keys should have a loader.
		(this->*loaders[key])(element, options);
	}

	// Update all objects poses.
	for(auto & object : objects) {
		const glm::mat4 newModel = _sceneModel * object.model();
		object.set(newModel);
	}
	// The scene model matrix has been applied to all objects, we can reset it.
	_sceneModel = glm::mat4(1.0f);
	// Update all lights bounding box infos.
	_bbox = computeBoundingBox(true);
	for(auto & light : lights) {
		light->setScene(_bbox);
	}

	// Check if the environment has been setup.
	if(environment.type() == LightProbe::Type::DEFAULT){
		KeyValues defaultKv("probe");
		environment.decode(defaultKv, options);
	}
	_loaded = true;

	// Sort objects by material.
	std::sort(objects.begin(), objects.end(), [](const Object & a, const Object & b){
		return int(a.type()) < int(b.type());
	});

	// Check if the scene is static.
	for(const auto & obj : objects){
		if(obj.animated()){
			_animated = true;
			break;
		}
	}
	for(const auto & light : lights){
		if(light->animated()){
			_animated = true;
			break;
		}
	}

	timer.end();
	Log::Info() << Log::Resources << "Loading took " << (float(timer.value())/1000000.0f) << "ms." << std::endl;
	return true;
}

void Scene::loadObject(const KeyValues & params, Storage options) {
	objects.emplace_back();
	objects.back().decode(params, options);
}

void Scene::loadLight(const KeyValues & params, Storage) {
	const auto light = Light::decode(params);
	if(light) {
		lights.push_back(light);
	}
}

void Scene::loadCamera(const KeyValues & params, Storage) {
	_camera.decode(params);
}

void Scene::loadBackground(const KeyValues & params, Storage options) {
	background = std::unique_ptr<Object>(new Object(Object::Type::Common, Resources::manager().getMesh("plane", options), false));

	for(const auto & param : params.elements) {
		if(param.key == "color") {
			backgroundMode = Background::COLOR;
			// Background is a plane, store the color.
			backgroundColor = Codable::decodeVec3(param);

		} else if(param.key == "image" && !param.elements.empty()) {
			backgroundMode = Background::IMAGE;
			// Load image described as sub-element.
			const auto texInfos = Codable::decodeTexture(param.elements[0]);
			const Texture * tex = Resources::manager().getTexture(texInfos.first, texInfos.second, options);
			background->addTexture(tex);

		} else if(param.key == "cube" && !param.elements.empty()) {
			backgroundMode = Background::SKYBOX;
			// Object is a textured skybox.
			background = std::unique_ptr<Object>(new Object(Object::Type::Common, Resources::manager().getMesh("skybox", options), false));
			background->decode(params, options);
			// Load cubemap described as subelement.
			const auto texInfos = Codable::decodeTexture(param.elements[0]);
			const Texture * tex = Resources::manager().getTexture(texInfos.first, texInfos.second, options);
			background->addTexture(tex);

		} else if(param.key == "sun") {
			// In that case the background is a sky object.
			backgroundMode = Background::ATMOSPHERE;
			background	 = std::unique_ptr<Sky>(new Sky(options));
			background->decode(params, options);
			// Load the scattering table.
			const Texture * tex = Resources::manager().getTexture("scattering-precomputed", {Layout::RGB32F, Filter::LINEAR_LINEAR, Wrap::CLAMP}, options);
			background->addTexture(tex);
		}
	}
}

void Scene::loadProbe(const KeyValues & params, Storage options) {
	environment.decode(params, options);
}

void Scene::loadScene(const KeyValues & params, Storage) {
	// Update matrix, there is at most one transformation in the scene object.
	_sceneModel = Codable::decodeTransformation(params.elements);
}

std::vector<KeyValues> Scene::encode() const {
	std::vector<KeyValues> tokens;

	// Encode the scene
	tokens.emplace_back("scene");
	auto & scnNode = tokens.back();
	scnNode.elements.push_back(environment.encode());

	// Encode the scene transformation.
	const auto modelKeys = Codable::encode(_sceneModel);
	for(const auto & key : modelKeys){
		scnNode.elements.push_back(key);
	}

	// Encode the background.
	KeyValues bgNode("background");

	switch (backgroundMode) {
		case Background::COLOR:
			bgNode.elements.emplace_back("color");
			bgNode.elements.back().values = { Codable::encode(backgroundColor) };
			break;
		case Background::IMAGE:
			bgNode.elements.emplace_back("image");
			bgNode.elements.back().elements = { Codable::encode(background->textures()[0]) };
			break;
		case Background::SKYBOX:
			bgNode.elements.emplace_back("cube");
			bgNode.elements.back().elements = { Codable::encode(background->textures()[0]) };
		break;
		case Background::ATMOSPHERE:
			bgNode = background->encode();
			bgNode.key = "background";
		break;
		default:
			break;
	}
	tokens.push_back(bgNode);
	// Encode the objects
	for(const auto & obj : objects){
		tokens.push_back(obj.encode());
	}
	// Encode the lights
	for(const auto & light : lights){
		tokens.push_back(light->encode());
	}
	tokens.push_back(_camera.encode());
	return tokens;
}

BoundingBox Scene::computeBoundingBox(bool onlyShadowCasters) {
	BoundingBox bbox;
	if(objects.empty()) {
		return bbox;
	}

	for(Object & obj : objects) {
		if(onlyShadowCasters && !obj.castsShadow()) {
			continue;
		}
		bbox.merge(obj.boundingBox());
	}
	Log::Info() << Log::Resources << "Scene bounding box:" << std::endl
				<< "\t\tmini: " << bbox.minis << std::endl
				<< "\t\tmaxi: " << bbox.maxis << "." << std::endl;
	return bbox;
}

void Scene::update(double fullTime, double frameTime) {
	for(auto & light : lights) {
		light->update(fullTime, frameTime);
	}
	for(auto & object : objects) {
		object.update(fullTime, frameTime);
	}
	background->update(fullTime, frameTime);
}
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
//  imgui-metal.c
//  Since this will only need to compile with clang we can
//  mix C99 designated initializers and C++ code.
//
//  NOTE: this demo is using the sokol_imgui.h utility header which
//  implements a renderer for Dear ImGui on top of sokol_gfx.h, but without
//  sokol_app.h (via the config define SOKOL_IMGUI_NO_SOKOL_APP).
//------------------------------------------------------------------------------
#include "osxentry.h"
#include "sokol_gfx.h"
#include "sokol_time.h"
#include "imgui.h"
#define SOKOL_METAL
#define SOKOL_IMGUI_IMPL
#define SOKOL_IMGUI_NO_SOKOL_APP
#include "sokol_imgui.h"

static const int WIDTH = 1024;
static const int HEIGHT = 768;

static uint64_t last_time = 0;
static bool show_test_window = true;
static bool show_another_window = false;
static sg_pass_action pass_action;

void init() {
    // setup sokol_gfx and sokol_time
    sg_desc desc = {
        .context = osx_get_context()
    };
    sg_setup(&desc);
    stm_setup();
    simgui_desc_t simgui_desc = { };
    simgui_setup(&simgui_desc);

    // setup the imgui environment
    ImGuiIO& io = ImGui::GetIO();
    io.KeyMap[ImGuiKey_Tab] = 0x30;
    io.KeyMap[ImGuiKey_LeftArrow] = 0x7B;
    io.KeyMap[ImGuiKey_RightArrow] = 0x7C;
    io.KeyMap[ImGuiKey_DownArrow] = 0x7D;
    io.KeyMap[ImGuiKey_UpArrow] = 0x7E;
    io.KeyMap[ImGuiKey_Home] = 0x73;
    io.KeyMap[ImGuiKey_End] = 0x77;
    io.KeyMap[ImGuiKey_Delete] = 0x75;
    io.KeyMap[ImGuiKey_Backspace] = 0x33;
    io.KeyMap[ImGuiKey_Enter] = 0x24;
    io.KeyMap[ImGuiKey_Escape] = 0x35;
    io.KeyMap[ImGuiKey_A] = 0x00;
    io.KeyMap[ImGuiKey_C] = 0x08;
    io.KeyMap[ImGuiKey_V] = 0x09;
    io.KeyMap[ImGuiKey_X] = 0x07;
    io.KeyMap[ImGuiKey_Y] = 0x10;
    io.KeyMap[ImGuiKey_Z] = 0x06;

    // OSX => ImGui input forwarding
    osx_mouse_pos([] (float x, float y) { ImGui::GetIO().MousePos = ImVec2(x, y); });
    osx_mouse_btn_down([] (int btn)     { ImGui::GetIO().MouseDown[btn] = true; });
    osx_mouse_btn_up([] (int btn)       { ImGui::GetIO().MouseDown[btn] = false; });
    osx_mouse_wheel([] (float v)        { ImGui::GetIO().MouseWheel = 0.25f * v; });
    osx_key_down([] (int key)           { if (key < 512) ImGui::GetIO().KeysDown[key] = true; });
    osx_key_up([] (int key)             { if (key < 512) ImGui::GetIO().KeysDown[key] = false; });
    osx_char([] (wchar_t c)             { ImGui::GetIO().AddInputCharacter(c); });

    // initial clear color
    pass_action = (sg_pass_action){
        .colors[0] = { .action = SG_ACTION_CLEAR, .val = { 0.0f, 0.5f, 0.7f, 1.0f } }
    };
}

void frame() {
    const int width = osx_width();
    const int height = osx_height();
    simgui_new_frame(width, height, stm_laptime(&last_time));

    // 1. Show a simple window
    // Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug"
    static float f = 0.0f;
    ImGui::Text("Hello, world!");
    ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
    ImGui::ColorEdit3("clear color", &pass_action.colors[0].val[0]);
    if (ImGui::Button("Test Window")) show_test_window ^= 1;
    if (ImGui::Button("Another Window")) show_another_window ^= 1;
    ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);

    // 2. Show another simple window, this time using an explicit Begin/End pair
    if (show_another_window) {
        ImGui::SetNextWindowSize(ImVec2(200,100), ImGuiCond_FirstUseEver);
        ImGui::Begin("Another Window", &show_another_window);
        ImGui::Text("Hello");
        ImGui::End();
    }

    // 3. Show the ImGui test window. Most of the sample code is in ImGui::ShowTestWindow()
    if (show_test_window) {
        ImGui::SetNextWindowPos(ImVec2(460, 20), ImGuiCond_FirstUseEver);
        ImGui::ShowTestWindow();
    }

    // the sokol draw pass
    sg_begin_default_pass(&pass_action, width, height);
    simgui_render();
    sg_end_pass();
    sg_commit();
}

void shutdown() {
    simgui_shutdown();
    sg_shutdown();
}

int main() {
    osx_start(WIDTH, HEIGHT, 1, "Sokol Dear ImGui (Metal)", init, frame, shutdown);
    return 0;
}
<commit_msg>imgui-metal: fix frametime computation<commit_after>//------------------------------------------------------------------------------
//  imgui-metal.c
//  Since this will only need to compile with clang we can
//  mix C99 designated initializers and C++ code.
//
//  NOTE: this demo is using the sokol_imgui.h utility header which
//  implements a renderer for Dear ImGui on top of sokol_gfx.h, but without
//  sokol_app.h (via the config define SOKOL_IMGUI_NO_SOKOL_APP).
//------------------------------------------------------------------------------
#include "osxentry.h"
#include "sokol_gfx.h"
#include "sokol_time.h"
#include "imgui.h"
#define SOKOL_METAL
#define SOKOL_IMGUI_IMPL
#define SOKOL_IMGUI_NO_SOKOL_APP
#include "sokol_imgui.h"

static const int WIDTH = 1024;
static const int HEIGHT = 768;

static uint64_t last_time = 0;
static bool show_test_window = true;
static bool show_another_window = false;
static sg_pass_action pass_action;

void init() {
    // setup sokol_gfx and sokol_time
    sg_desc desc = {
        .context = osx_get_context()
    };
    sg_setup(&desc);
    stm_setup();
    simgui_desc_t simgui_desc = { };
    simgui_setup(&simgui_desc);

    // setup the imgui environment
    ImGuiIO& io = ImGui::GetIO();
    io.KeyMap[ImGuiKey_Tab] = 0x30;
    io.KeyMap[ImGuiKey_LeftArrow] = 0x7B;
    io.KeyMap[ImGuiKey_RightArrow] = 0x7C;
    io.KeyMap[ImGuiKey_DownArrow] = 0x7D;
    io.KeyMap[ImGuiKey_UpArrow] = 0x7E;
    io.KeyMap[ImGuiKey_Home] = 0x73;
    io.KeyMap[ImGuiKey_End] = 0x77;
    io.KeyMap[ImGuiKey_Delete] = 0x75;
    io.KeyMap[ImGuiKey_Backspace] = 0x33;
    io.KeyMap[ImGuiKey_Enter] = 0x24;
    io.KeyMap[ImGuiKey_Escape] = 0x35;
    io.KeyMap[ImGuiKey_A] = 0x00;
    io.KeyMap[ImGuiKey_C] = 0x08;
    io.KeyMap[ImGuiKey_V] = 0x09;
    io.KeyMap[ImGuiKey_X] = 0x07;
    io.KeyMap[ImGuiKey_Y] = 0x10;
    io.KeyMap[ImGuiKey_Z] = 0x06;

    // OSX => ImGui input forwarding
    osx_mouse_pos([] (float x, float y) { ImGui::GetIO().MousePos = ImVec2(x, y); });
    osx_mouse_btn_down([] (int btn)     { ImGui::GetIO().MouseDown[btn] = true; });
    osx_mouse_btn_up([] (int btn)       { ImGui::GetIO().MouseDown[btn] = false; });
    osx_mouse_wheel([] (float v)        { ImGui::GetIO().MouseWheel = 0.25f * v; });
    osx_key_down([] (int key)           { if (key < 512) ImGui::GetIO().KeysDown[key] = true; });
    osx_key_up([] (int key)             { if (key < 512) ImGui::GetIO().KeysDown[key] = false; });
    osx_char([] (wchar_t c)             { ImGui::GetIO().AddInputCharacter(c); });

    // initial clear color
    pass_action = (sg_pass_action){
        .colors[0] = { .action = SG_ACTION_CLEAR, .val = { 0.0f, 0.5f, 0.7f, 1.0f } }
    };
}

void frame() {
    const int width = osx_width();
    const int height = osx_height();
    simgui_new_frame(width, height, stm_sec(stm_laptime(&last_time)));

    // 1. Show a simple window
    // Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug"
    static float f = 0.0f;
    ImGui::Text("Hello, world!");
    ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
    ImGui::ColorEdit3("clear color", &pass_action.colors[0].val[0]);
    if (ImGui::Button("Test Window")) show_test_window ^= 1;
    if (ImGui::Button("Another Window")) show_another_window ^= 1;
    ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);

    // 2. Show another simple window, this time using an explicit Begin/End pair
    if (show_another_window) {
        ImGui::SetNextWindowSize(ImVec2(200,100), ImGuiCond_FirstUseEver);
        ImGui::Begin("Another Window", &show_another_window);
        ImGui::Text("Hello");
        ImGui::End();
    }

    // 3. Show the ImGui test window. Most of the sample code is in ImGui::ShowTestWindow()
    if (show_test_window) {
        ImGui::SetNextWindowPos(ImVec2(460, 20), ImGuiCond_FirstUseEver);
        ImGui::ShowTestWindow();
    }

    // the sokol draw pass
    sg_begin_default_pass(&pass_action, width, height);
    simgui_render();
    sg_end_pass();
    sg_commit();
}

void shutdown() {
    simgui_shutdown();
    sg_shutdown();
}

int main() {
    osx_start(WIDTH, HEIGHT, 1, "Sokol Dear ImGui (Metal)", init, frame, shutdown);
    return 0;
}
<|endoftext|>


<commit_before>#include "simplesp.h"
#include "spex/spcv.h"

using namespace sp;

void sample(cv::Mat &cvimg, const int key);

int main(){
    cv::VideoCapture cap(0);
    if (cap.isOpened() == false){
        printf("could not find USB camera\n");
        exit(0);
    }

    printf("'s' key : switch center pose / markers pose\n");
    printf("'ESC' key : exit\n");

    int key = 0;

    // 27 = 'ESC' key
    while ((key = cv::waitKey(1)) != 27){

        // capture
        cv::Mat cvimg;
        cap >> cvimg;

        sample(cvimg, key);

        cv::imshow("bitmarker", cvimg);
    }

    cv::destroyAllWindows();
    return 0;
}

void sample(cv::Mat &cvimg, const int key){
    Mem2<Col3> img;

    // convert data type
    cvCnvImg(img, cvimg);

    // markers parameter
    Mem1<BitMarkerParam> mrks;

    // set marker info
    {
        const int dsize[2] = { 4, 3 };
        const int block = 3;
        const double length = 60.0;
        const double interval = 5.0;

        //const int dsize[2] = { 8, 6 };
        //const int block = 3;
        //const double length = 28.0;
        //const double interval = 5.0;

        mrks = getBitMarkerParam(0, block, length, dsize[0], dsize[1], interval);

        SP_ONCE(saveBitMarkerParamSVG("mrks.svg", 0, block, length, dsize[0], dsize[1], interval));
    }

    // detector class
    BitMarker bitMarker;

    static bool flag = true;
    if (key == 's') flag ^= true;

    // detect marker
    if(flag){
        bitMarker.addMrks(mrks);

        bitMarker.execute(img);

        if (bitMarker.getPose(0) != NULL) {

            const Mem1<Vec2> &cpixs = *bitMarker.getCrspPixs(0);
            renderPoint(img, *bitMarker.getCrspPixs(0), getCol(0, 255, 255), 3);

            renderAxis(img, bitMarker.getCam(), *bitMarker.getPose(0), 50.0, 2);
        }
    }
    else {
        for (int i = 0; i < mrks.size(); i++) {
            mrks[i].offset = zeroPose();
            bitMarker.addMrks(mrks[i]);
        }

        bitMarker.execute(img);

        for (int i = 0; i < mrks.size(); i++) {
            if (bitMarker.getPose(i) == NULL) continue;

            const Mem1<Vec2> &cpixs = *bitMarker.getCrspPixs(i);
            renderPoint(img, cpixs, getCol(0, 255, 255), 3);

            renderAxis(img, bitMarker.getCam(), *bitMarker.getPose(i), 20.0, 2);
        }
    }

    cvCnvImg(cvimg, img);
}

<commit_msg>refactoring<commit_after>#include "simplesp.h"
#include "spex/spcv.h"

using namespace sp;

void sample(cv::Mat &cvimg, const int key);

int main(){
    cv::VideoCapture cap(0);
    if (cap.isOpened() == false){
        printf("could not find USB camera\n");
        exit(0);
    }

    printf("'s' key : switch center pose / markers pose\n");
    printf("'ESC' key : exit\n");

    int key = 0;

    // 27 = 'ESC' key
    while ((key = cv::waitKey(1)) != 27){

        // capture
        cv::Mat cvimg;
        cap >> cvimg;

        sample(cvimg, key);

        cv::imshow("bitmarker", cvimg);
    }

    cv::destroyAllWindows();
    return 0;
}

void sample(cv::Mat &cvimg, const int key){
    Mem2<Col3> img;

    // convert data type
    cvCnvImg(img, cvimg);

    // markers parameter
    Mem1<BitMarkerParam> mrks;

    // set marker info
    {
        const int dsize[2] = { 4, 3 };
        const int block = 3;
        const double length = 60.0;
        const double interval = 5.0;

        //const int dsize[2] = { 8, 6 };
        //const int block = 3;
        //const double length = 28.0;
        //const double interval = 5.0;

        mrks = getBitMarkerParam(0, block, length, dsize[0], dsize[1], interval);

        SP_ONCE(saveBitMarkerParamSVG("mrks.svg", 0, block, length, dsize[0], dsize[1], interval));
    }

    // detector class
    BitMarker bitMarker;

    static bool flag = true;
    if (key == 's') flag ^= true;

    // detect marker
    if(flag){

        bitMarker.addMrks(mrks);

        bitMarker.execute(img);
    }
    else {
        for (int i = 0; i < mrks.size(); i++) {
            mrks[i].offset = zeroPose();
            bitMarker.addMrks(mrks[i]);
        }

        bitMarker.execute(img);
    }

    // render
    {
        for (int i = 0; i < bitMarker.size(); i++) {
            if (bitMarker.getPose(i) == NULL) continue;

            const Mem1<Vec2> &cpixs = *bitMarker.getCrspPixs(i);
            renderPoint(img, cpixs, getCol(0, 255, 255), 3);

            renderAxis(img, bitMarker.getCam(), *bitMarker.getPose(i), 30.0, 2);
        }
    }

    cvCnvImg(cvimg, img);
}

<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * 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 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <mapnik/feature_type_style.hpp>

namespace mapnik
{

static const char * filter_mode_strings[] = {
    "all",
    "first",
    ""
};

IMPLEMENT_ENUM( filter_mode_e, filter_mode_strings )

feature_type_style::feature_type_style()
    : filter_mode_(FILTER_ALL),
      scale_denom_validity_(-1) {}

feature_type_style::feature_type_style(feature_type_style const& rhs, bool deep_copy)
    : filter_mode_(rhs.filter_mode_),
      scale_denom_valicity_(-1)
{
    if (!deep_copy) {
        rules_ = rhs.rules_;
    } else {
        rules::const_iterator it  = rhs.rules_.begin(),
                        end = rhs.rules_.end();
        for(; it != end; ++it) {
            rules_.push_back(rule(*it, deep_copy));
        }
    }
}

feature_type_style& feature_type_style::operator=(feature_type_style const& rhs)
{
    if (this == &rhs) return *this;
    rules_=rhs.rules_;
    scale_denom_validity_ = -1;
    return *this;
}

void feature_type_style::add_rule(rule const& rule)
{
    rules_.push_back(rule);
    scale_denom_validity_ = -1;
}

rules const& feature_type_style::get_rules() const
{
    return rules_;
}

rules &feature_type_style::get_rules_nonconst()
{
    return rules_;
}

void feature_type_style::set_filter_mode(filter_mode_e mode)
{
    filter_mode_ = mode;
}

filter_mode_e feature_type_style::get_filter_mode() const
{
    return filter_mode_;
}

void feature_type_style::update_rule_cache(double scale_denom)
{
    if_rules_.clear();
    else_rules_.clear();
    also_rules_.clear();

    BOOST_FOREACH(rule const& r, rules_)
    {
        if (r.active(scale_denom))
        {
            if (r.has_else_filter())
            {
                else_rules_.push_back(const_cast<rule*>(&r));
            }
            else if (r.has_also_filter())
            {
                also_rules_.push_back(const_cast<rule*>(&r));
            }
            else
            {
                if_rules_.push_back(const_cast<rule*>(&r));
            }
        }
    }

    scale_denom_validity_ = scale_denom;
}

rule_ptrs const& feature_type_style::get_if_rules(double scale_denom)
{
    if (scale_denom_validity_ != scale_denom)
    {
        update_rule_cache(scale_denom);
    }
    return if_rules_;
}

rule_ptrs const& feature_type_style::get_else_rules(double scale_denom)
{
    if (scale_denom_validity_ != scale_denom)
    {
        update_rule_cache(scale_denom);
    }
    return else_rules_;
}

rule_ptrs const& feature_type_style::get_also_rules(double scale_denom)
{
    if (scale_denom_validity_ != scale_denom)
    {
        update_rule_cache(scale_denom);
    }
    return also_rules_;
}

}
<commit_msg>fix typo<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * 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 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <mapnik/feature_type_style.hpp>

namespace mapnik
{

static const char * filter_mode_strings[] = {
    "all",
    "first",
    ""
};

IMPLEMENT_ENUM( filter_mode_e, filter_mode_strings )

feature_type_style::feature_type_style()
    : filter_mode_(FILTER_ALL),
      scale_denom_validity_(-1) {}

feature_type_style::feature_type_style(feature_type_style const& rhs, bool deep_copy)
    : filter_mode_(rhs.filter_mode_),
      scale_denom_validity_(-1)
{
    if (!deep_copy) {
        rules_ = rhs.rules_;
    } else {
        rules::const_iterator it  = rhs.rules_.begin(),
                        end = rhs.rules_.end();
        for(; it != end; ++it) {
            rules_.push_back(rule(*it, deep_copy));
        }
    }
}

feature_type_style& feature_type_style::operator=(feature_type_style const& rhs)
{
    if (this == &rhs) return *this;
    rules_=rhs.rules_;
    scale_denom_validity_ = -1;
    return *this;
}

void feature_type_style::add_rule(rule const& rule)
{
    rules_.push_back(rule);
    scale_denom_validity_ = -1;
}

rules const& feature_type_style::get_rules() const
{
    return rules_;
}

rules &feature_type_style::get_rules_nonconst()
{
    return rules_;
}

void feature_type_style::set_filter_mode(filter_mode_e mode)
{
    filter_mode_ = mode;
}

filter_mode_e feature_type_style::get_filter_mode() const
{
    return filter_mode_;
}

void feature_type_style::update_rule_cache(double scale_denom)
{
    if_rules_.clear();
    else_rules_.clear();
    also_rules_.clear();

    BOOST_FOREACH(rule const& r, rules_)
    {
        if (r.active(scale_denom))
        {
            if (r.has_else_filter())
            {
                else_rules_.push_back(const_cast<rule*>(&r));
            }
            else if (r.has_also_filter())
            {
                also_rules_.push_back(const_cast<rule*>(&r));
            }
            else
            {
                if_rules_.push_back(const_cast<rule*>(&r));
            }
        }
    }

    scale_denom_validity_ = scale_denom;
}

rule_ptrs const& feature_type_style::get_if_rules(double scale_denom)
{
    if (scale_denom_validity_ != scale_denom)
    {
        update_rule_cache(scale_denom);
    }
    return if_rules_;
}

rule_ptrs const& feature_type_style::get_else_rules(double scale_denom)
{
    if (scale_denom_validity_ != scale_denom)
    {
        update_rule_cache(scale_denom);
    }
    return else_rules_;
}

rule_ptrs const& feature_type_style::get_also_rules(double scale_denom)
{
    if (scale_denom_validity_ != scale_denom)
    {
        update_rule_cache(scale_denom);
    }
    return also_rules_;
}

}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <stdio.h>

#include <cstdlib>

#include "gtest/gtest.h"
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/test/testsupport/fileutils.h"
#include "webrtc/tools/frame_editing/frame_editing_lib.h"

namespace webrtc {
namespace test {

const int kWidth = 352;
const int kHeight = 288;
const int kFrameSize = CalcBufferSize(kI420, kWidth, kHeight);
const std::string kRefVideo = ResourcePath("foreman_cif", "yuv");
const std::string kTestVideo = OutputPath() + "testvideo.yuv";

class FrameEditingTest : public ::testing::Test {
 protected:
  virtual void SetUp() {
    original_fid_ = fopen(kRefVideo.c_str(), "rb");
    ASSERT_TRUE(original_fid_ != NULL);
    edited_fid_ = fopen(kTestVideo.c_str(), "rb");
    ASSERT_TRUE(edited_fid_ != NULL);
    original_buffer_.reset(new int[kFrameSize]);
    edited_buffer_.reset(new int[kFrameSize]);
    num_frames_read_ = 0;
  }
  virtual void TearDown() {
    fclose(original_fid_);
    fclose(edited_fid_);
  }
  // Compares the frames in both streams to the end of one of the streams.
  void CompareToTheEnd(FILE* test_video_fid, FILE* ref_video_fid,
                       scoped_array<int>* ref_buffer,
                       scoped_array<int>* test_buffer) {
    while (!feof(test_video_fid) && !feof(ref_video_fid)) {
      num_bytes_read_ = fread(ref_buffer->get(), 1, kFrameSize, ref_video_fid);
      if (!feof(ref_video_fid)) {
        EXPECT_EQ(kFrameSize, num_bytes_read_);
      }
      num_bytes_read_ = fread(test_buffer->get(), 1, kFrameSize,
                              test_video_fid);
      if (!feof(test_video_fid)) {
        EXPECT_EQ(kFrameSize, num_bytes_read_);
      }
      if (!feof(test_video_fid) && !feof(test_video_fid)) {
        EXPECT_EQ(0, memcmp(ref_buffer->get(), test_buffer->get(),
                            kFrameSize));
      }
    }
    // There should not be anything left in either stream.
    EXPECT_EQ(!feof(test_video_fid), !feof(ref_video_fid));
  }
  FILE* original_fid_;
  FILE* edited_fid_;
  int kFrameSize_;
  int num_bytes_read_;
  scoped_array<int> original_buffer_;
  scoped_array<int> edited_buffer_;
  int num_frames_read_;
};

TEST_F(FrameEditingTest, ValidInPath) {
  const int kFirstFrameToProcess = 160;
  const int kInterval = -1;
  const int kLastFrameToProcess = 240;

  int result = EditFrames(kRefVideo, kWidth, kHeight, kFirstFrameToProcess,
                          kInterval, kLastFrameToProcess, kTestVideo);
  EXPECT_EQ(0, result);

  for (int i = 1; i < kFirstFrameToProcess; ++i) {
    num_bytes_read_ = fread(original_buffer_.get(), 1, kFrameSize,
                            original_fid_);
    EXPECT_EQ(kFrameSize, num_bytes_read_);

    num_bytes_read_ = fread(edited_buffer_.get(), 1, kFrameSize, edited_fid_);
    EXPECT_EQ(kFrameSize, num_bytes_read_);

    EXPECT_EQ(0, memcmp(original_buffer_.get(), edited_buffer_.get(),
                        kFrameSize));
  }
  // Do not compare the frames that have been cut.
  for (int i = kFirstFrameToProcess; i <= kLastFrameToProcess; ++i) {
    num_bytes_read_ = fread(original_buffer_.get(), 1, kFrameSize,
                            original_fid_);
    EXPECT_EQ(kFrameSize, num_bytes_read_);
  }
  CompareToTheEnd(edited_fid_, original_fid_, &original_buffer_,
                  &edited_buffer_);
}

TEST_F(FrameEditingTest, EmptySetToCut) {
  const int kFirstFrameToProcess = 2;
  const int kInterval = -1;
  const int kLastFrameToProcess = 1;

  int result = EditFrames(kRefVideo, kWidth, kHeight, kFirstFrameToProcess,
                          kInterval, kLastFrameToProcess, kTestVideo);
  EXPECT_EQ(-10, result);
}

TEST_F(FrameEditingTest, InValidInPath) {
  const std::string kRefVideo = "PATH/THAT/DOES/NOT/EXIST";

  const int kFirstFrameToProcess = 30;
  const int kInterval = 1;
  const int kLastFrameToProcess = 120;

  int result = EditFrames(kRefVideo, kWidth, kHeight, kFirstFrameToProcess,
                          kInterval, kLastFrameToProcess, kTestVideo);
  EXPECT_EQ(-11, result);
}

TEST_F(FrameEditingTest, DeletingEverySecondFrame) {
  const int kFirstFrameToProcess = 1;
  const int kInterval = -2;
  const int kLastFrameToProcess = 10000;
  // Set kLastFrameToProcess to a large value so that all frame are processed.
  int result = EditFrames(kRefVideo, kWidth, kHeight, kFirstFrameToProcess,
                          kInterval, kLastFrameToProcess, kTestVideo);
  EXPECT_EQ(0, result);

  while (!feof(original_fid_) && !feof(edited_fid_)) {
    num_bytes_read_ =
        fread(original_buffer_.get(), 1, kFrameSize, original_fid_);
    if (!feof(original_fid_)) {
      EXPECT_EQ(kFrameSize, num_bytes_read_);
      num_frames_read_++;
    }
    // We want to compare every second frame of the original to the edited.
    // kInterval=-2 and (num_frames_read_ - 1) % kInterval  will be -1 for
    // every second frame.
    // num_frames_read_ - 1 because we have deleted frame number 2, 4 , 6 etc.
    if ((num_frames_read_ - 1) % kInterval == -1) {
      num_bytes_read_ = fread(edited_buffer_.get(), 1, kFrameSize,
                              edited_fid_);
      if (!feof(edited_fid_)) {
        EXPECT_EQ(kFrameSize, num_bytes_read_);
      }
      if (!feof(original_fid_) && !feof(edited_fid_)) {
        EXPECT_EQ(0, memcmp(original_buffer_.get(),
                            edited_buffer_.get(), kFrameSize));
      }
    }
  }
}

TEST_F(FrameEditingTest, RepeatFrames) {
  const int kFirstFrameToProcess = 160;
  const int kInterval = 2;
  const int kLastFrameToProcess = 240;

  int result = EditFrames(kRefVideo, kWidth, kHeight, kFirstFrameToProcess,
                          kInterval, kLastFrameToProcess, kTestVideo);
  EXPECT_EQ(0, result);

  for (int i = 1; i < kFirstFrameToProcess; ++i) {
    num_bytes_read_ = fread(original_buffer_.get(), 1, kFrameSize,
                            original_fid_);
    EXPECT_EQ(kFrameSize, num_bytes_read_);

    num_bytes_read_ = fread(edited_buffer_.get(), 1, kFrameSize, edited_fid_);
    EXPECT_EQ(kFrameSize, num_bytes_read_);

    EXPECT_EQ(0, memcmp(original_buffer_.get(), edited_buffer_.get(),
                        kFrameSize));
  }
  // Do not compare the frames that have been repeated.
  for (int i = kFirstFrameToProcess; i <= kLastFrameToProcess; ++i) {
    num_bytes_read_ = fread(original_buffer_.get(), 1, kFrameSize,
                            original_fid_);
    EXPECT_EQ(kFrameSize, num_bytes_read_);
    for (int i = 1; i <= kInterval; ++i) {
      num_bytes_read_ = fread(edited_buffer_.get(), 1, kFrameSize,
                              edited_fid_);
      EXPECT_EQ(kFrameSize, num_bytes_read_);
      EXPECT_EQ(0, memcmp(original_buffer_.get(), edited_buffer_.get(),
                          kFrameSize));
    }
  }
  CompareToTheEnd(edited_fid_, original_fid_, &original_buffer_,
                  &edited_buffer_);
}
}  // namespace test
}  // namespace webrtc

<commit_msg>Fix frame_editing_unittest.cc<commit_after>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <stdio.h>

#include <cstdlib>
#include <fstream>

#include "gtest/gtest.h"
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/test/testsupport/fileutils.h"
#include "webrtc/tools/frame_editing/frame_editing_lib.h"

namespace webrtc {
namespace test {

const int kWidth = 352;
const int kHeight = 288;
const int kFrameSize = CalcBufferSize(kI420, kWidth, kHeight);
const std::string kRefVideo = ResourcePath("foreman_cif", "yuv");
const std::string kTestVideo = OutputPath() + "testvideo.yuv";

class FrameEditingTest : public ::testing::Test {
 protected:
  virtual void SetUp() {
    original_fid_ = fopen(kRefVideo.c_str(), "rb");
    ASSERT_TRUE(original_fid_ != NULL);

    // Ensure the output file exists on disk.
    std::ofstream(kTestVideo.c_str(), std::ios::out);
    // Open the output file for reading.
    // TODO(holmer): Figure out why this file has to be opened here (test fails
    // if it's opened after the write operation performed in EditFrames).
    edited_fid_ = fopen(kTestVideo.c_str(), "rb");
    ASSERT_TRUE(edited_fid_ != NULL);

    original_buffer_.reset(new int[kFrameSize]);
    edited_buffer_.reset(new int[kFrameSize]);
    num_frames_read_ = 0;
  }
  virtual void TearDown() {
    fclose(original_fid_);
    fclose(edited_fid_);
  }
  // Compares the frames in both streams to the end of one of the streams.
  void CompareToTheEnd(FILE* test_video_fid, FILE* ref_video_fid,
                       scoped_array<int>* ref_buffer,
                       scoped_array<int>* test_buffer) {
    while (!feof(test_video_fid) && !feof(ref_video_fid)) {
      num_bytes_read_ = fread(ref_buffer->get(), 1, kFrameSize, ref_video_fid);
      if (!feof(ref_video_fid)) {
        EXPECT_EQ(kFrameSize, num_bytes_read_);
      }
      num_bytes_read_ = fread(test_buffer->get(), 1, kFrameSize,
                              test_video_fid);
      if (!feof(test_video_fid)) {
        EXPECT_EQ(kFrameSize, num_bytes_read_);
      }
      if (!feof(test_video_fid) && !feof(test_video_fid)) {
        EXPECT_EQ(0, memcmp(ref_buffer->get(), test_buffer->get(),
                            kFrameSize));
      }
    }
    // There should not be anything left in either stream.
    EXPECT_EQ(!feof(test_video_fid), !feof(ref_video_fid));
  }
  FILE* original_fid_;
  FILE* edited_fid_;
  int kFrameSize_;
  int num_bytes_read_;
  scoped_array<int> original_buffer_;
  scoped_array<int> edited_buffer_;
  int num_frames_read_;
};

TEST_F(FrameEditingTest, ValidInPath) {
  const int kFirstFrameToProcess = 160;
  const int kInterval = -1;
  const int kLastFrameToProcess = 240;

  int result = EditFrames(kRefVideo, kWidth, kHeight, kFirstFrameToProcess,
                          kInterval, kLastFrameToProcess, kTestVideo);
  EXPECT_EQ(0, result);

  for (int i = 1; i < kFirstFrameToProcess; ++i) {
    num_bytes_read_ = fread(original_buffer_.get(), 1, kFrameSize,
                            original_fid_);
    EXPECT_EQ(kFrameSize, num_bytes_read_);

    num_bytes_read_ = fread(edited_buffer_.get(), 1, kFrameSize, edited_fid_);
    EXPECT_EQ(kFrameSize, num_bytes_read_);

    EXPECT_EQ(0, memcmp(original_buffer_.get(), edited_buffer_.get(),
                        kFrameSize));
  }
  // Do not compare the frames that have been cut.
  for (int i = kFirstFrameToProcess; i <= kLastFrameToProcess; ++i) {
    num_bytes_read_ = fread(original_buffer_.get(), 1, kFrameSize,
                            original_fid_);
    EXPECT_EQ(kFrameSize, num_bytes_read_);
  }
  CompareToTheEnd(edited_fid_, original_fid_, &original_buffer_,
                  &edited_buffer_);
}

TEST_F(FrameEditingTest, EmptySetToCut) {
  const int kFirstFrameToProcess = 2;
  const int kInterval = -1;
  const int kLastFrameToProcess = 1;

  int result = EditFrames(kRefVideo, kWidth, kHeight, kFirstFrameToProcess,
                          kInterval, kLastFrameToProcess, kTestVideo);
  EXPECT_EQ(-10, result);
}

TEST_F(FrameEditingTest, InValidInPath) {
  const std::string kRefVideo = "PATH/THAT/DOES/NOT/EXIST";

  const int kFirstFrameToProcess = 30;
  const int kInterval = 1;
  const int kLastFrameToProcess = 120;

  int result = EditFrames(kRefVideo, kWidth, kHeight, kFirstFrameToProcess,
                          kInterval, kLastFrameToProcess, kTestVideo);
  EXPECT_EQ(-11, result);
}

TEST_F(FrameEditingTest, DeletingEverySecondFrame) {
  const int kFirstFrameToProcess = 1;
  const int kInterval = -2;
  const int kLastFrameToProcess = 10000;
  // Set kLastFrameToProcess to a large value so that all frame are processed.
  int result = EditFrames(kRefVideo, kWidth, kHeight, kFirstFrameToProcess,
                          kInterval, kLastFrameToProcess, kTestVideo);
  EXPECT_EQ(0, result);

  while (!feof(original_fid_) && !feof(edited_fid_)) {
    num_bytes_read_ =
        fread(original_buffer_.get(), 1, kFrameSize, original_fid_);
    if (!feof(original_fid_)) {
      EXPECT_EQ(kFrameSize, num_bytes_read_);
      num_frames_read_++;
    }
    // We want to compare every second frame of the original to the edited.
    // kInterval=-2 and (num_frames_read_ - 1) % kInterval  will be -1 for
    // every second frame.
    // num_frames_read_ - 1 because we have deleted frame number 2, 4 , 6 etc.
    if ((num_frames_read_ - 1) % kInterval == -1) {
      num_bytes_read_ = fread(edited_buffer_.get(), 1, kFrameSize,
                              edited_fid_);
      if (!feof(edited_fid_)) {
        EXPECT_EQ(kFrameSize, num_bytes_read_);
      }
      if (!feof(original_fid_) && !feof(edited_fid_)) {
        EXPECT_EQ(0, memcmp(original_buffer_.get(),
                            edited_buffer_.get(), kFrameSize));
      }
    }
  }
}

TEST_F(FrameEditingTest, RepeatFrames) {
  const int kFirstFrameToProcess = 160;
  const int kInterval = 2;
  const int kLastFrameToProcess = 240;

  int result = EditFrames(kRefVideo, kWidth, kHeight, kFirstFrameToProcess,
                          kInterval, kLastFrameToProcess, kTestVideo);
  EXPECT_EQ(0, result);

  for (int i = 1; i < kFirstFrameToProcess; ++i) {
    num_bytes_read_ = fread(original_buffer_.get(), 1, kFrameSize,
                            original_fid_);
    EXPECT_EQ(kFrameSize, num_bytes_read_);

    num_bytes_read_ = fread(edited_buffer_.get(), 1, kFrameSize, edited_fid_);
    EXPECT_EQ(kFrameSize, num_bytes_read_);

    EXPECT_EQ(0, memcmp(original_buffer_.get(), edited_buffer_.get(),
                        kFrameSize));
  }
  // Do not compare the frames that have been repeated.
  for (int i = kFirstFrameToProcess; i <= kLastFrameToProcess; ++i) {
    num_bytes_read_ = fread(original_buffer_.get(), 1, kFrameSize,
                            original_fid_);
    EXPECT_EQ(kFrameSize, num_bytes_read_);
    for (int i = 1; i <= kInterval; ++i) {
      num_bytes_read_ = fread(edited_buffer_.get(), 1, kFrameSize,
                              edited_fid_);
      EXPECT_EQ(kFrameSize, num_bytes_read_);
      EXPECT_EQ(0, memcmp(original_buffer_.get(), edited_buffer_.get(),
                          kFrameSize));
    }
  }
  CompareToTheEnd(edited_fid_, original_fid_, &original_buffer_,
                  &edited_buffer_);
}
}  // namespace test
}  // namespace webrtc

<|endoftext|>