<commit_before>/*===========================================================================*\
 *                                                                           *
 *                               OpenMesh                                    *
 *      Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen      *
 *                           www.openmesh.org                                *
 *                                                                           *
 *---------------------------------------------------------------------------*
 *  This file is part of OpenMesh.                                           *
 *                                                                           *
 *  OpenMesh 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 3 of           *
 *  the License, or (at your option) any later version with the              *
 *  following exceptions:                                                    *
 *                                                                           *
 *  If other files instantiate templates or use macros                       *
 *  or inline functions from this file, or you compile this file and         *
 *  link it with other files to produce an executable, this file does        *
 *  not by itself cause the resulting executable to be covered by the        *
 *  GNU Lesser General Public License. This exception does not however       *
 *  invalidate any other reasons why the executable file might be            *
 *  covered by the GNU Lesser General Public License.                        *
 *                                                                           *
 *  OpenMesh 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 LesserGeneral Public          *
 *  License along with OpenMesh.  If not,                                    *
 *  see <http://www.gnu.org/licenses/>.                                      *
 *                                                                           *
 \*===========================================================================*/

/*===========================================================================*\
 *                                                                           *
 *   $Revision: 460 $                                                         *
 *   $Date: 2011-11-16 10:45:08 +0100 (Mi, 16 Nov 2011) $                   *
 *                                                                           *
 \*===========================================================================*/

/** \file McDecimaterT.cc
 */

//=============================================================================
//
//  CLASS McDecimaterT - IMPLEMENTATION
//
//=============================================================================
#define OPENMESH_MULTIPLE_CHOICE_DECIMATER_DECIMATERT_CC

//== INCLUDES =================================================================

#include <OpenMesh/Tools/Decimater/McDecimaterT.hh>

#include <vector>
#if defined(OM_CC_MIPS)
#  include <float.h>
#else
#  include <cfloat>
#endif

//== NAMESPACE ===============================================================

namespace OpenMesh {
namespace Decimater {

//== IMPLEMENTATION ==========================================================

template<class Mesh>
McDecimaterT<Mesh>::McDecimaterT(Mesh& _mesh) :
  BaseDecimaterT<Mesh>(_mesh),
    mesh_(_mesh), randomSamples_(10) {

  // default properties
  mesh_.request_vertex_status();
  mesh_.request_halfedge_status();
  mesh_.request_edge_status();
  mesh_.request_face_status();
  mesh_.request_face_normals();

}

//-----------------------------------------------------------------------------

template<class Mesh>
McDecimaterT<Mesh>::~McDecimaterT() {
  // default properties
  mesh_.release_vertex_status();
  mesh_.release_edge_status();
  mesh_.release_halfedge_status();
  mesh_.release_face_status();
  mesh_.release_face_normals();

}

//-----------------------------------------------------------------------------
template<class Mesh>
size_t McDecimaterT<Mesh>::decimate(size_t _n_collapses) {

  if (!this->is_initialized())
    return 0;

  unsigned int n_collapses(0);

  while ( n_collapses <  _n_collapses) {

    // Optimal id and value will be collected during the random sampling
    typename Mesh::HalfedgeHandle bestHandle(-1);
    double bestEnergy = FLT_MAX;

    // Generate random samples for collapses
    for ( unsigned int i = 0; i < randomSamples_; ++i) {

      // Random halfedge handle
      typename Mesh::HalfedgeHandle tmpHandle = typename Mesh::HalfedgeHandle(double(rand()) / RAND_MAX * mesh_.n_halfedges() );

      // if it is not deleted, we analyse it
      if ( ! mesh_.status(tmpHandle).deleted()  ) {

        CollapseInfo ci(mesh_, tmpHandle);

        // Check if legal we analyze the priority of this collapse operation
        if (this->is_collapse_legal(ci)) {
          double energy = this->collapse_priority(ci);

          // Check if the current samples energy is better than any energy before
          if ( energy < bestEnergy ) {
            bestEnergy = energy;
            bestHandle = tmpHandle;
          }
        } else {
          continue;
        }
      }

    }

    // Found the best energy?
    if ( bestEnergy != FLT_MAX ) {

      // setup collapse info
      CollapseInfo ci(mesh_, bestHandle);

      // check topological correctness AGAIN !
      if (!this->is_collapse_legal(ci))
        continue;

      // pre-processing
      this->preprocess_collapse(ci);

      // perform collapse
      mesh_.collapse(bestHandle);
      ++n_collapses;

      // update triangle normals
      typename Mesh::VertexFaceIter vf_it = mesh_.vf_iter(ci.v1);
      for (; vf_it; ++vf_it)
        if (!mesh_.status(vf_it).deleted())
          mesh_.set_normal(vf_it, mesh_.calc_face_normal(vf_it.handle()));

      // post-process collapse
      this->postprocess_collapse(ci);

    }

  }

  // DON'T do garbage collection here! It's up to the application.
  return n_collapses;
}

//-----------------------------------------------------------------------------

template<class Mesh>
size_t McDecimaterT<Mesh>::decimate_to_faces(size_t _nv, size_t _nf) {
  if (!this->is_initialized())
    return 0;

  unsigned int nv = mesh_.n_vertices();
  unsigned int nf = mesh_.n_faces();
  unsigned int n_collapses(0);

  while ( (_nv < nv) && (_nf < nf) ) {

    // Optimal id and value will be collected during the random sampling
    typename Mesh::HalfedgeHandle bestHandle(-1);
    double bestEnergy = FLT_MAX;

    // Generate random samples for collapses
    for ( unsigned int i = 0; i < randomSamples_; ++i) {

      // Random halfedge handle
      typename Mesh::HalfedgeHandle tmpHandle = typename Mesh::HalfedgeHandle(double(rand()) / RAND_MAX * mesh_.n_halfedges() );

      // if it is not deleted, we analyse it
      if ( ! mesh_.status(tmpHandle).deleted()  ) {

        CollapseInfo ci(mesh_, tmpHandle);

        // Check if legal we analyze the priority of this collapse operation
        if (is_collapse_legal(ci)) {
          double energy = collapse_priority(ci);

          // Check if the current samples energy is better than any energy before
          if ( energy < bestEnergy ) {
            bestEnergy = energy;
            bestHandle = tmpHandle;
          }
        } else {
          continue;
        }
      }

    }

    // Found the best energy?
    if ( bestEnergy != FLT_MAX ) {

      // setup collapse info
      CollapseInfo ci(mesh_, bestHandle);

      // check topological correctness AGAIN !
      if (!is_collapse_legal(ci))
        continue;

      // adjust complexity in advance (need boundary status)
      ++n_collapses;

      // One vertex is killed by the collapse
      --nv;

      // If we are at a boundary, one face is lost,
      // otherwise two
      if (mesh_.is_boundary(ci.v0v1) || mesh_.is_boundary(ci.v1v0))
        --nf;
      else
        nf -= 2;

      // pre-processing
      preprocess_collapse(ci);

      // perform collapse
      mesh_.collapse(bestHandle);
      ++n_collapses;

      // update triangle normals
      typename Mesh::VertexFaceIter vf_it = mesh_.vf_iter(ci.v1);
      for (; vf_it; ++vf_it)
        if (!mesh_.status(vf_it).deleted())
          mesh_.set_normal(vf_it, mesh_.calc_face_normal(vf_it.handle()));

      // post-process collapse
      postprocess_collapse(ci);

    }

  }

  // DON'T do garbage collection here! It's up to the application.
  return n_collapses;
}

//=============================================================================
}// END_NS_MC_DECIMATER
} // END_NS_OPENMESH
//=============================================================================

<commit_msg>- more this ptr<commit_after>/*===========================================================================*\
 *                                                                           *
 *                               OpenMesh                                    *
 *      Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen      *
 *                           www.openmesh.org                                *
 *                                                                           *
 *---------------------------------------------------------------------------*
 *  This file is part of OpenMesh.                                           *
 *                                                                           *
 *  OpenMesh 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 3 of           *
 *  the License, or (at your option) any later version with the              *
 *  following exceptions:                                                    *
 *                                                                           *
 *  If other files instantiate templates or use macros                       *
 *  or inline functions from this file, or you compile this file and         *
 *  link it with other files to produce an executable, this file does        *
 *  not by itself cause the resulting executable to be covered by the        *
 *  GNU Lesser General Public License. This exception does not however       *
 *  invalidate any other reasons why the executable file might be            *
 *  covered by the GNU Lesser General Public License.                        *
 *                                                                           *
 *  OpenMesh 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 LesserGeneral Public          *
 *  License along with OpenMesh.  If not,                                    *
 *  see <http://www.gnu.org/licenses/>.                                      *
 *                                                                           *
 \*===========================================================================*/

/*===========================================================================*\
 *                                                                           *
 *   $Revision: 460 $                                                         *
 *   $Date: 2011-11-16 10:45:08 +0100 (Mi, 16 Nov 2011) $                   *
 *                                                                           *
 \*===========================================================================*/

/** \file McDecimaterT.cc
 */

//=============================================================================
//
//  CLASS McDecimaterT - IMPLEMENTATION
//
//=============================================================================
#define OPENMESH_MULTIPLE_CHOICE_DECIMATER_DECIMATERT_CC

//== INCLUDES =================================================================

#include <OpenMesh/Tools/Decimater/McDecimaterT.hh>

#include <vector>
#if defined(OM_CC_MIPS)
#  include <float.h>
#else
#  include <cfloat>
#endif

//== NAMESPACE ===============================================================

namespace OpenMesh {
namespace Decimater {

//== IMPLEMENTATION ==========================================================

template<class Mesh>
McDecimaterT<Mesh>::McDecimaterT(Mesh& _mesh) :
  BaseDecimaterT<Mesh>(_mesh),
    mesh_(_mesh), randomSamples_(10) {

  // default properties
  mesh_.request_vertex_status();
  mesh_.request_halfedge_status();
  mesh_.request_edge_status();
  mesh_.request_face_status();
  mesh_.request_face_normals();

}

//-----------------------------------------------------------------------------

template<class Mesh>
McDecimaterT<Mesh>::~McDecimaterT() {
  // default properties
  mesh_.release_vertex_status();
  mesh_.release_edge_status();
  mesh_.release_halfedge_status();
  mesh_.release_face_status();
  mesh_.release_face_normals();

}

//-----------------------------------------------------------------------------
template<class Mesh>
size_t McDecimaterT<Mesh>::decimate(size_t _n_collapses) {

  if (!this->is_initialized())
    return 0;

  unsigned int n_collapses(0);

  while ( n_collapses <  _n_collapses) {

    // Optimal id and value will be collected during the random sampling
    typename Mesh::HalfedgeHandle bestHandle(-1);
    double bestEnergy = FLT_MAX;

    // Generate random samples for collapses
    for ( unsigned int i = 0; i < randomSamples_; ++i) {

      // Random halfedge handle
      typename Mesh::HalfedgeHandle tmpHandle = typename Mesh::HalfedgeHandle(double(rand()) / RAND_MAX * mesh_.n_halfedges() );

      // if it is not deleted, we analyse it
      if ( ! mesh_.status(tmpHandle).deleted()  ) {

        CollapseInfo ci(mesh_, tmpHandle);

        // Check if legal we analyze the priority of this collapse operation
        if (this->is_collapse_legal(ci)) {
          double energy = this->collapse_priority(ci);

          // Check if the current samples energy is better than any energy before
          if ( energy < bestEnergy ) {
            bestEnergy = energy;
            bestHandle = tmpHandle;
          }
        } else {
          continue;
        }
      }

    }

    // Found the best energy?
    if ( bestEnergy != FLT_MAX ) {

      // setup collapse info
      CollapseInfo ci(mesh_, bestHandle);

      // check topological correctness AGAIN !
      if (!this->is_collapse_legal(ci))
        continue;

      // pre-processing
      this->preprocess_collapse(ci);

      // perform collapse
      mesh_.collapse(bestHandle);
      ++n_collapses;

      // update triangle normals
      typename Mesh::VertexFaceIter vf_it = mesh_.vf_iter(ci.v1);
      for (; vf_it; ++vf_it)
        if (!mesh_.status(vf_it).deleted())
          mesh_.set_normal(vf_it, mesh_.calc_face_normal(vf_it.handle()));

      // post-process collapse
      this->postprocess_collapse(ci);

    }

  }

  // DON'T do garbage collection here! It's up to the application.
  return n_collapses;
}

//-----------------------------------------------------------------------------

template<class Mesh>
size_t McDecimaterT<Mesh>::decimate_to_faces(size_t _nv, size_t _nf) {
  if (!this->is_initialized())
    return 0;

  unsigned int nv = mesh_.n_vertices();
  unsigned int nf = mesh_.n_faces();
  unsigned int n_collapses(0);

  while ( (_nv < nv) && (_nf < nf) ) {

    // Optimal id and value will be collected during the random sampling
    typename Mesh::HalfedgeHandle bestHandle(-1);
    double bestEnergy = FLT_MAX;

    // Generate random samples for collapses
    for ( unsigned int i = 0; i < randomSamples_; ++i) {

      // Random halfedge handle
      typename Mesh::HalfedgeHandle tmpHandle = typename Mesh::HalfedgeHandle(double(rand()) / RAND_MAX * mesh_.n_halfedges() );

      // if it is not deleted, we analyse it
      if ( ! mesh_.status(tmpHandle).deleted()  ) {

        CollapseInfo ci(mesh_, tmpHandle);

        // Check if legal we analyze the priority of this collapse operation
        if (this->is_collapse_legal(ci)) {
          double energy = this->collapse_priority(ci);

          // Check if the current samples energy is better than any energy before
          if ( energy < bestEnergy ) {
            bestEnergy = energy;
            bestHandle = tmpHandle;
          }
        } else {
          continue;
        }
      }

    }

    // Found the best energy?
    if ( bestEnergy != FLT_MAX ) {

      // setup collapse info
      CollapseInfo ci(mesh_, bestHandle);

      // check topological correctness AGAIN !
      if (!this->is_collapse_legal(ci))
        continue;

      // adjust complexity in advance (need boundary status)
      ++n_collapses;

      // One vertex is killed by the collapse
      --nv;

      // If we are at a boundary, one face is lost,
      // otherwise two
      if (mesh_.is_boundary(ci.v0v1) || mesh_.is_boundary(ci.v1v0))
        --nf;
      else
        nf -= 2;

      // pre-processing
      this->preprocess_collapse(ci);

      // perform collapse
      mesh_.collapse(bestHandle);
      ++n_collapses;

      // update triangle normals
      typename Mesh::VertexFaceIter vf_it = mesh_.vf_iter(ci.v1);
      for (; vf_it; ++vf_it)
        if (!mesh_.status(vf_it).deleted())
          mesh_.set_normal(vf_it, mesh_.calc_face_normal(vf_it.handle()));

      // post-process collapse
      this->postprocess_collapse(ci);

    }

  }

  // DON'T do garbage collection here! It's up to the application.
  return n_collapses;
}

//=============================================================================
}// END_NS_MC_DECIMATER
} // END_NS_OPENMESH
//=============================================================================

<|endoftext|>


<commit_before>#include "tangram.h"

#include "platform.h"
#include "scene/scene.h"
#include "scene/sceneLoader.h"
#include "style/style.h"
#include "text/fontContext.h"
#include "labels/labels.h"
#include "tile/tileManager.h"
#include "tile/tile.h"
#include "gl/error.h"
#include "gl/shaderProgram.h"
#include "scene/skybox.h"
#include "view/view.h"
#include "gl/renderState.h"
#include "util/inputHandler.h"
#include <memory>
#include <cmath>
#include <bitset>

namespace Tangram {

std::unique_ptr<TileManager> m_tileManager;
std::shared_ptr<Scene> m_scene;
std::shared_ptr<View> m_view;
std::unique_ptr<Labels> m_labels;
std::shared_ptr<FontContext> m_ftContext;
std::unique_ptr<Skybox> m_skybox;
std::unique_ptr<InputHandler> m_inputHandler;

static float g_time = 0.0;
static std::bitset<8> g_flags = 0;

void initialize() {

    logMsg("initialize\n");

    if (!m_tileManager) {

        // Create view
        m_view = std::make_shared<View>();

        // Create a scene object
        m_scene = std::make_shared<Scene>();

        // Input handler
        m_inputHandler = std::unique_ptr<InputHandler>(new InputHandler(m_view));

        m_skybox = std::unique_ptr<Skybox>(new Skybox("cubemap.png"));
        m_skybox->init();

        // Create a tileManager
        m_tileManager = TileManager::GetInstance();

        // Pass references to the view and scene into the tile manager
        m_tileManager->setView(m_view);
        m_tileManager->setScene(m_scene);

        // Font and label setup
        m_ftContext = FontContext::GetInstance();
        m_ftContext->addFont("FiraSans-Medium.ttf", "FiraSans");
        m_labels = std::unique_ptr<Labels>(new Labels());

        SceneLoader loader;
        loader.loadScene("config.yaml", *m_scene, *m_tileManager, *m_view);

    }

    RenderState::configure();

    while (Error::hadGlError("Tangram::initialize()")) {}

    logMsg("finish initialize\n");

}

void resize(int _newWidth, int _newHeight) {

    logMsg("resize: %d x %d\n", _newWidth, _newHeight);

    glViewport(0, 0, _newWidth, _newHeight);

    if (m_view) {
        m_view->setSize(_newWidth, _newHeight);
    }

    for (auto& style : m_scene->styles()) {
        style->viewportHasChanged();
    }

    while (Error::hadGlError("Tangram::resize()")) {}

}

void update(float _dt) {

    g_time += _dt;

    m_inputHandler->update(_dt);

    m_view->update();

    m_tileManager->updateTileSet();

    if (m_view->changedOnLastUpdate() || m_tileManager->hasTileSetChanged() || m_labels->needUpdate()) {

        auto& tileSet = m_tileManager->getVisibleTiles();

        for (const auto& mapIDandTile : tileSet) {
            const auto& tile = mapIDandTile.second;
            if (tile->isReady()) {
                tile->update(_dt, *m_view);
            }
        }

        m_labels->update(*m_view, _dt, m_scene->styles(), tileSet);
    }

    if (m_scene) {
        // Update lights and styles
    }
}

void render() {

    // Set up openGL for new frame
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Loop over all styles
    for (const auto& style : m_scene->styles()) {
        style->onBeginDrawFrame(*m_view, *m_scene);

        // Loop over all tiles in m_tileSet
        for (const auto& mapIDandTile : m_tileManager->getVisibleTiles()) {
            const std::shared_ptr<Tile>& tile = mapIDandTile.second;
            if (tile->isReady()) {
                // Draw tile!
                tile->draw(*style, *m_view);
            }
        }

        style->onEndDrawFrame();
    }

    m_skybox->draw(*m_view);

    m_labels->drawDebug(*m_view);

    while (Error::hadGlError("Tangram::render()")) {}
}

void setPosition(double _lon, double _lat) {

    glm::dvec2 meters = m_view->getMapProjection().LonLatToMeters({ _lon, _lat});
    m_view->setPosition(meters.x, meters.y);
    requestRender();

}

void getPosition(double& _lon, double& _lat) {

    glm::dvec2 meters(m_view->getPosition().x, m_view->getPosition().y);
    glm::dvec2 degrees = m_view->getMapProjection().MetersToLonLat(meters);
    _lon = degrees.x;
    _lat = degrees.y;

}

void setZoom(float _z) {

    m_view->setZoom(_z);
    requestRender();

}

float getZoom() {

    return m_view->getZoom();

}

void setRotation(float _radians) {

    m_view->setRoll(_radians);
    requestRender();

}

float getRotation() {

    return m_view->getRoll();

}

void setTilt(float _radians) {

    m_view->setPitch(_radians);
    requestRender();

}

float getTilt() {

    return m_view->getPitch();

}

void screenToWorldCoordinates(double& _x, double& _y) {

    float screenX = _x, screenY = _y;
    m_view->screenToGroundPlane(screenX, screenY);
    glm::dvec2 meters(screenX + m_view->getPosition().x, screenY + m_view->getPosition().y);
    glm::dvec2 lonLat = m_view->getMapProjection().MetersToLonLat(meters);
    _x = lonLat.x;
    _y = lonLat.y;

}

void setPixelScale(float _pixelsPerPoint) {

    if (m_view) {
        m_view->setPixelScale(_pixelsPerPoint);
    }

    for (auto& style : m_scene->styles()) {
        style->setPixelScale(_pixelsPerPoint);
    }

}

void handleTapGesture(float _posX, float _posY) {

    m_inputHandler->handleTapGesture(_posX, _posY);

}

void handleDoubleTapGesture(float _posX, float _posY) {

    m_inputHandler->handleDoubleTapGesture(_posX, _posY);

}

void handlePanGesture(float _startX, float _startY, float _endX, float _endY) {

    m_inputHandler->handlePanGesture(_startX, _startY, _endX, _endY);

}

void handlePinchGesture(float _posX, float _posY, float _scale, float _velocity) {

    m_inputHandler->handlePinchGesture(_posX, _posY, _scale, _velocity);

}

void handleRotateGesture(float _posX, float _posY, float _radians) {

    m_inputHandler->handleRotateGesture(_posX, _posY, _radians);

}

void handleShoveGesture(float _distance) {

    m_inputHandler->handleShoveGesture(_distance);

}

void setDebugFlag(DebugFlags _flag, bool _on) {

    g_flags.set(_flag, _on);
    m_view->setZoom(m_view->getZoom()); // Force the view to refresh

}

bool getDebugFlag(DebugFlags _flag) {

    return g_flags.test(_flag);

}

void toggleDebugFlag(DebugFlags _flag) {

    g_flags.flip(_flag);
    m_view->setZoom(m_view->getZoom()); // Force the view to refresh

}

void onContextDestroyed() {

    logMsg("context destroyed\n");

    if (m_tileManager) {
        m_tileManager->clearTileSet();
    }

    // The OpenGL context has been destroyed since the last time resources were created,
    // so we invalidate all data that depends on OpenGL object handles.

    // ShaderPrograms are invalidated and immediately rebuilt
    ShaderProgram::invalidateAllPrograms();

    // Buffer objects are invalidated and re-uploaded the next time they are used
    VboMesh::invalidateAllVBOs();

    // Texture objects are invalidated and re-uploaded the next time they are updated
    Texture::invalidateAllTextures();

    // Reconfigure the render states
    RenderState::configure();

    for (auto& style : m_scene->styles()) {
        style->notifyGLContextLost();
    }
}

}
<commit_msg>fix crash on android on first context destroyed call<commit_after>#include "tangram.h"

#include "platform.h"
#include "scene/scene.h"
#include "scene/sceneLoader.h"
#include "style/style.h"
#include "text/fontContext.h"
#include "labels/labels.h"
#include "tile/tileManager.h"
#include "tile/tile.h"
#include "gl/error.h"
#include "gl/shaderProgram.h"
#include "scene/skybox.h"
#include "view/view.h"
#include "gl/renderState.h"
#include "util/inputHandler.h"
#include <memory>
#include <cmath>
#include <bitset>

namespace Tangram {

std::unique_ptr<TileManager> m_tileManager;
std::shared_ptr<Scene> m_scene;
std::shared_ptr<View> m_view;
std::unique_ptr<Labels> m_labels;
std::shared_ptr<FontContext> m_ftContext;
std::unique_ptr<Skybox> m_skybox;
std::unique_ptr<InputHandler> m_inputHandler;

static float g_time = 0.0;
static std::bitset<8> g_flags = 0;

void initialize() {

    logMsg("initialize\n");

    if (!m_tileManager) {

        // Create view
        m_view = std::make_shared<View>();

        // Create a scene object
        m_scene = std::make_shared<Scene>();

        // Input handler
        m_inputHandler = std::unique_ptr<InputHandler>(new InputHandler(m_view));

        m_skybox = std::unique_ptr<Skybox>(new Skybox("cubemap.png"));
        m_skybox->init();

        // Create a tileManager
        m_tileManager = TileManager::GetInstance();

        // Pass references to the view and scene into the tile manager
        m_tileManager->setView(m_view);
        m_tileManager->setScene(m_scene);

        // Font and label setup
        m_ftContext = FontContext::GetInstance();
        m_ftContext->addFont("FiraSans-Medium.ttf", "FiraSans");
        m_labels = std::unique_ptr<Labels>(new Labels());

        SceneLoader loader;
        loader.loadScene("config.yaml", *m_scene, *m_tileManager, *m_view);

        RenderState::configure();
    }

    while (Error::hadGlError("Tangram::initialize()")) {}

    logMsg("finish initialize\n");

}

void resize(int _newWidth, int _newHeight) {

    logMsg("resize: %d x %d\n", _newWidth, _newHeight);

    glViewport(0, 0, _newWidth, _newHeight);

    if (m_view) {
        m_view->setSize(_newWidth, _newHeight);
    }

    for (auto& style : m_scene->styles()) {
        style->viewportHasChanged();
    }

    while (Error::hadGlError("Tangram::resize()")) {}

}

void update(float _dt) {

    g_time += _dt;

    m_inputHandler->update(_dt);

    m_view->update();

    m_tileManager->updateTileSet();

    if (m_view->changedOnLastUpdate() || m_tileManager->hasTileSetChanged() || m_labels->needUpdate()) {

        auto& tileSet = m_tileManager->getVisibleTiles();

        for (const auto& mapIDandTile : tileSet) {
            const auto& tile = mapIDandTile.second;
            if (tile->isReady()) {
                tile->update(_dt, *m_view);
            }
        }

        m_labels->update(*m_view, _dt, m_scene->styles(), tileSet);
    }

    if (m_scene) {
        // Update lights and styles
    }
}

void render() {

    // Set up openGL for new frame
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Loop over all styles
    for (const auto& style : m_scene->styles()) {
        style->onBeginDrawFrame(*m_view, *m_scene);

        // Loop over all tiles in m_tileSet
        for (const auto& mapIDandTile : m_tileManager->getVisibleTiles()) {
            const std::shared_ptr<Tile>& tile = mapIDandTile.second;
            if (tile->isReady()) {
                // Draw tile!
                tile->draw(*style, *m_view);
            }
        }

        style->onEndDrawFrame();
    }

    m_skybox->draw(*m_view);

    m_labels->drawDebug(*m_view);

    while (Error::hadGlError("Tangram::render()")) {}
}

void setPosition(double _lon, double _lat) {

    glm::dvec2 meters = m_view->getMapProjection().LonLatToMeters({ _lon, _lat});
    m_view->setPosition(meters.x, meters.y);
    requestRender();

}

void getPosition(double& _lon, double& _lat) {

    glm::dvec2 meters(m_view->getPosition().x, m_view->getPosition().y);
    glm::dvec2 degrees = m_view->getMapProjection().MetersToLonLat(meters);
    _lon = degrees.x;
    _lat = degrees.y;

}

void setZoom(float _z) {

    m_view->setZoom(_z);
    requestRender();

}

float getZoom() {

    return m_view->getZoom();

}

void setRotation(float _radians) {

    m_view->setRoll(_radians);
    requestRender();

}

float getRotation() {

    return m_view->getRoll();

}

void setTilt(float _radians) {

    m_view->setPitch(_radians);
    requestRender();

}

float getTilt() {

    return m_view->getPitch();

}

void screenToWorldCoordinates(double& _x, double& _y) {

    float screenX = _x, screenY = _y;
    m_view->screenToGroundPlane(screenX, screenY);
    glm::dvec2 meters(screenX + m_view->getPosition().x, screenY + m_view->getPosition().y);
    glm::dvec2 lonLat = m_view->getMapProjection().MetersToLonLat(meters);
    _x = lonLat.x;
    _y = lonLat.y;

}

void setPixelScale(float _pixelsPerPoint) {

    if (m_view) {
        m_view->setPixelScale(_pixelsPerPoint);
    }

    for (auto& style : m_scene->styles()) {
        style->setPixelScale(_pixelsPerPoint);
    }

}

void handleTapGesture(float _posX, float _posY) {

    m_inputHandler->handleTapGesture(_posX, _posY);

}

void handleDoubleTapGesture(float _posX, float _posY) {

    m_inputHandler->handleDoubleTapGesture(_posX, _posY);

}

void handlePanGesture(float _startX, float _startY, float _endX, float _endY) {

    m_inputHandler->handlePanGesture(_startX, _startY, _endX, _endY);

}

void handlePinchGesture(float _posX, float _posY, float _scale, float _velocity) {

    m_inputHandler->handlePinchGesture(_posX, _posY, _scale, _velocity);

}

void handleRotateGesture(float _posX, float _posY, float _radians) {

    m_inputHandler->handleRotateGesture(_posX, _posY, _radians);

}

void handleShoveGesture(float _distance) {

    m_inputHandler->handleShoveGesture(_distance);

}

void setDebugFlag(DebugFlags _flag, bool _on) {

    g_flags.set(_flag, _on);
    m_view->setZoom(m_view->getZoom()); // Force the view to refresh

}

bool getDebugFlag(DebugFlags _flag) {

    return g_flags.test(_flag);

}

void toggleDebugFlag(DebugFlags _flag) {

    g_flags.flip(_flag);
    m_view->setZoom(m_view->getZoom()); // Force the view to refresh

}

void onContextDestroyed() {

    logMsg("context destroyed\n");

    if (m_tileManager) {
        m_tileManager->clearTileSet();

        for (auto& style : m_scene->styles()) {
            style->notifyGLContextLost();
        }
    }

    // The OpenGL context has been destroyed since the last time resources were created,
    // so we invalidate all data that depends on OpenGL object handles.

    // ShaderPrograms are invalidated and immediately rebuilt
    ShaderProgram::invalidateAllPrograms();

    // Buffer objects are invalidated and re-uploaded the next time they are used
    VboMesh::invalidateAllVBOs();

    // Texture objects are invalidated and re-uploaded the next time they are updated
    Texture::invalidateAllTextures();

    // Reconfigure the render states
    RenderState::configure();
}

}
<|endoftext|>


<commit_before>#include "tangram.h"

#include <memory>
#include <utility>
#include <cmath>

#include "platform.h"
#include "tile/tileManager.h"
#include "view/view.h"
#include "data/dataSource.h"

#include "style/polygonStyle.h"
#include "style/polylineStyle.h"
#include "scene/scene.h"
#include "util/error.h"

namespace Tangram {

std::unique_ptr<TileManager> m_tileManager;
std::shared_ptr<Scene> m_scene;
std::shared_ptr<View> m_view;

void initialize() {

    logMsg("%s\n", "initialize");

    // Create view
    if (!m_view) {
        m_view = std::make_shared<View>();

        // Move the view to coordinates in Manhattan so we have something interesting to test
        glm::dvec2 target = m_view->getMapProjection().LonLatToMeters(glm::dvec2(-74.00796, 40.70361));
        m_view->setPosition(target.x, target.y);
    }

    // Create a scene object
    if (!m_scene) {
        m_scene = std::make_shared<Scene>();

        // Load style(s); hard-coded for now
        std::unique_ptr<Style> polyStyle(new PolygonStyle("Polygon"));
        polyStyle->addLayers({
            "buildings",
            "water",
            "earth",
            "landuse"
        });
        m_scene->addStyle(std::move(polyStyle));

        std::unique_ptr<Style> linesStyle(new PolylineStyle("Polyline"));
        linesStyle->addLayers({"roads"});
        m_scene->addStyle(std::move(linesStyle));
    }

    // Create a tileManager
    if (!m_tileManager) {
        m_tileManager = TileManager::GetInstance();

        // Pass references to the view and scene into the tile manager
        m_tileManager->setView(m_view);
        m_tileManager->setScene(m_scene);

        // Add a tile data source
        std::unique_ptr<DataSource> dataSource(new MapzenVectorTileJson());
        m_tileManager->addDataSource(std::move(dataSource));
    }

    // Set up openGL state
    glDisable(GL_BLEND);
    glDisable(GL_STENCIL_TEST);
    glEnable(GL_DEPTH_TEST);
    glClearDepthf(1.0);
    glDepthRangef(0.0, 1.0);
    glDepthMask(GL_TRUE);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_CULL_FACE);
    glFrontFace(GL_CCW);
    glCullFace(GL_BACK);
    glClearColor(0.3f, 0.3f, 0.3f, 1.0f);

    while (Error::hadGlError("Tangram::initialize()")) {}

    logMsg("%s\n", "finish initialize");

}

void resize(int _newWidth, int _newHeight) {

    logMsg("resize: %d x %d\n", _newWidth, _newHeight);

    glViewport(0, 0, _newWidth, _newHeight);

    if (m_view) {
        m_view->setSize(_newWidth, _newHeight);
    }

    while (Error::hadGlError("Tangram::resize()")) {}

}

void update(float _dt) {

    if (m_view) {
        m_view->update();
    }

    if (m_tileManager) {
        m_tileManager->updateTileSet();
    }

}

void render() {

    // Set up openGL for new frame
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glm::dmat4 viewProj = m_view->getViewProjectionMatrix();

    // Loop over all styles
    for (const auto& style : m_scene->getStyles()) {

        style->setup();

        // Loop over all tiles in m_tileSet
        for (const auto& mapIDandTile : m_tileManager->getVisibleTiles()) {
            const std::shared_ptr<MapTile>& tile = mapIDandTile.second;
            if(tile->hasGeometry()) {
                if (tile->getProxyCounter() > 0)
                {
                    // Draw proxy tiles
                    //glPolygonOffset
                    logMsg(" Drawing Proxy: [%d, %d, %d], having count: %d\n", tile->getID().x, tile->getID().y, tile->getID().z, tile->getProxyCounter());
                    tile->draw(*style, viewProj);
                }
                else {
                    // Draw visible tile
                    tile->draw(*style, viewProj);
                }
            }
        }

    }

    while (Error::hadGlError("Tangram::render()")) {}

}

void setPixelScale(float _pixelsPerPoint) {

    if (m_view) {
        m_view->setPixelScale(_pixelsPerPoint);
    }

}

void handleTapGesture(float _posX, float _posY) {

    float dx = m_view->toWorldDistance(_posX - 0.5 * m_view->getWidth());
    float dy = m_view->toWorldDistance(_posY - 0.5 * m_view->getHeight());

    // Flip y displacement to change from screen coordinates to world coordinates
    m_view->translate(dx, -dy);
    logMsg("Tap: (%f,%f)\n", _posX, _posY);

}

void handleDoubleTapGesture(float _posX, float _posY) {

    logMsg("Double tap: (%f,%f)\n", _posX, _posY);
    m_view->zoom(1.0);
}

void handlePanGesture(float _dX, float _dY) {

    float dx = m_view->toWorldDistance(_dX);
    float dy = m_view->toWorldDistance(_dY);

    // We flip the signs of dx and dy to move the camera in the opposite direction
    // of the intended "world movement", but dy gets flipped once more because screen
    // coordinates have y pointing down and our world coordinates have y pointing up
    m_view->translate(-dx, dy);
    logMsg("Drag: (%f,%f)\n", _dX, _dY);

}

void handlePinchGesture(float _posX, float _posY, float _scale) {
    logMsg("Pinch: (%f, %f)\tscale: (%f)\n", _posX, _posY, _scale);
    m_view->zoom(log2f(_scale));
}

void teardown() {
    // TODO: Release resources!
}

void onContextDestroyed() {

    // The OpenGL context has been destroyed since the last time resources were created,
    // so we invalidate all data that depends on OpenGL object handles.

    // ShaderPrograms are invalidated and immediately rebuilt
    ShaderProgram::invalidateAllPrograms();

    // Buffer objects are invalidated and re-uploaded the next time they are used
    VboMesh::invalidateAllVBOs();

}

}
<commit_msg>Drawing proxy tiles behind visible tiles<commit_after>#include "tangram.h"

#include <memory>
#include <utility>
#include <cmath>
#include <set>

#include "platform.h"
#include "tile/tileManager.h"
#include "view/view.h"
#include "data/dataSource.h"

#include "style/polygonStyle.h"
#include "style/polylineStyle.h"
#include "scene/scene.h"
#include "util/error.h"

namespace Tangram {

std::unique_ptr<TileManager> m_tileManager;
std::shared_ptr<Scene> m_scene;
std::shared_ptr<View> m_view;

void initialize() {

    logMsg("%s\n", "initialize");

    // Create view
    if (!m_view) {
        m_view = std::make_shared<View>();

        // Move the view to coordinates in Manhattan so we have something interesting to test
        glm::dvec2 target = m_view->getMapProjection().LonLatToMeters(glm::dvec2(-74.00796, 40.70361));
        m_view->setPosition(target.x, target.y);
    }

    // Create a scene object
    if (!m_scene) {
        m_scene = std::make_shared<Scene>();

        // Load style(s); hard-coded for now
        std::unique_ptr<Style> polyStyle(new PolygonStyle("Polygon"));
        polyStyle->addLayers({
            "buildings",
            "water",
            "earth",
            "landuse"
        });
        m_scene->addStyle(std::move(polyStyle));

        std::unique_ptr<Style> linesStyle(new PolylineStyle("Polyline"));
        linesStyle->addLayers({"roads"});
        m_scene->addStyle(std::move(linesStyle));
    }

    // Create a tileManager
    if (!m_tileManager) {
        m_tileManager = TileManager::GetInstance();

        // Pass references to the view and scene into the tile manager
        m_tileManager->setView(m_view);
        m_tileManager->setScene(m_scene);

        // Add a tile data source
        std::unique_ptr<DataSource> dataSource(new MapzenVectorTileJson());
        m_tileManager->addDataSource(std::move(dataSource));
    }

    // Set up openGL state
    glDisable(GL_BLEND);
    glDisable(GL_STENCIL_TEST);
    glEnable(GL_DEPTH_TEST);
    glClearDepthf(1.0);
    glDepthRangef(0.0, 1.0);
    glDepthMask(GL_TRUE);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_CULL_FACE);
    glFrontFace(GL_CCW);
    glCullFace(GL_BACK);
    glClearColor(0.3f, 0.3f, 0.3f, 1.0f);

    while (Error::hadGlError("Tangram::initialize()")) {}

    logMsg("%s\n", "finish initialize");

}

void resize(int _newWidth, int _newHeight) {

    logMsg("resize: %d x %d\n", _newWidth, _newHeight);

    glViewport(0, 0, _newWidth, _newHeight);

    if (m_view) {
        m_view->setSize(_newWidth, _newHeight);
    }

    while (Error::hadGlError("Tangram::resize()")) {}

}

void update(float _dt) {

    if (m_view) {
        m_view->update();
    }

    if (m_tileManager) {
        m_tileManager->updateTileSet();
    }

}

void render() {

    // Set up openGL for new frame
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glm::dmat4 viewProj = m_view->getViewProjectionMatrix();

    // Loop over all styles
    for (const auto& style : m_scene->getStyles()) {

        style->setup();

        // Loop over all tiles in m_tileSet
        for (const auto& mapIDandTile : m_tileManager->getVisibleTiles()) {
            const std::shared_ptr<MapTile>& tile = mapIDandTile.second;
            if(tile->hasGeometry()) {
                if (tile->getProxyCounter() > 0)
                {
                    // Draw proxy tiles
                    glEnable(GL_POLYGON_OFFSET_FILL);
                    glPolygonOffset(1.0, 1.0);
                    tile->draw(*style, viewProj);
                }
                else {
                    // Draw visible tile
                    glDisable(GL_POLYGON_OFFSET_FILL);
                    tile->draw(*style, viewProj);
                }
            }
        }

    }

    while (Error::hadGlError("Tangram::render()")) {}

}

void setPixelScale(float _pixelsPerPoint) {

    if (m_view) {
        m_view->setPixelScale(_pixelsPerPoint);
    }

}

void handleTapGesture(float _posX, float _posY) {

    float dx = m_view->toWorldDistance(_posX - 0.5 * m_view->getWidth());
    float dy = m_view->toWorldDistance(_posY - 0.5 * m_view->getHeight());

    // Flip y displacement to change from screen coordinates to world coordinates
    m_view->translate(dx, -dy);
    logMsg("Tap: (%f,%f)\n", _posX, _posY);

}

void handleDoubleTapGesture(float _posX, float _posY) {

    logMsg("Double tap: (%f,%f)\n", _posX, _posY);
    m_view->zoom(1.0);
}

void handlePanGesture(float _dX, float _dY) {

    float dx = m_view->toWorldDistance(_dX);
    float dy = m_view->toWorldDistance(_dY);

    // We flip the signs of dx and dy to move the camera in the opposite direction
    // of the intended "world movement", but dy gets flipped once more because screen
    // coordinates have y pointing down and our world coordinates have y pointing up
    m_view->translate(-dx, dy);
    logMsg("Drag: (%f,%f)\n", _dX, _dY);

}

void handlePinchGesture(float _posX, float _posY, float _scale) {
    logMsg("Pinch: (%f, %f)\tscale: (%f)\n", _posX, _posY, _scale);
    m_view->zoom(log2f(_scale));
}

void teardown() {
    // TODO: Release resources!
}

void onContextDestroyed() {

    // The OpenGL context has been destroyed since the last time resources were created,
    // so we invalidate all data that depends on OpenGL object handles.

    // ShaderPrograms are invalidated and immediately rebuilt
    ShaderProgram::invalidateAllPrograms();

    // Buffer objects are invalidated and re-uploaded the next time they are used
    VboMesh::invalidateAllVBOs();

}

}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2016 Luke San Antonio
 * All rights reserved.
 */
#pragma once
#include <atomic>
namespace redc
{
  // We have a lot of resources that don't need to be kept alive by the engine,
  // but do need to be properly uninitialized before the engine is
  // uninitialized itself. We can achieve this by sharing the ownership of the
  // pointer between peer objects. One of them goes out of scope? Deallocate
  // the data immediately.

  // The above being said, it would also be convenient if we could have
  // external references to the peer that keep it alive. Basically, the peer
  // represents the lowest common denominator of use. When all the shared
  // references (different type of object) get destructed and at least one peer
  // no longer cares about the object, we can finally uninitialize the memory.
  // This makes sense for our engine because we must only keep a resource alive
  // if:
  // - The mod is currently holding a reference to it
  // - Some part of the engine is holding a reference to it
  // However, deallocation must happen if
  // - The engine is about to be uninitialized itself, or
  // - Neither the mod nor any part of the engine is using the resource.

  // This is different from a shared_ptr / weak_ptr relationship because if we
  // store a weak_ptr in the engine and give lua a shared_ptr, lua gets to call
  // the shots, when to uninitialize the resource, which could be after we
  // uninitialize the engine - that doesn't help us.
  // On the other hand, if we give the weak_ptr to lua and give the shared_ptr
  // to the engine, we'll have to manually go through and figure out what
  // resources have been dropped / gc'd by lua anyway. This can be done with
  // some sort of primitive gc step of our own every few frames, but would
  // still complicate the interface of the Engine structure, as well as any
  // associated implementation. Furthermore, I have no idea how many resources
  // are going to be controlled in this way, meaning it would only get worse.
  // This is just my solution / abstraction to this problem. Also, this is not
  // typical use of shared_ptr / weak_ptr so it could get confusing, etc.

  // Our solution still requires a basic gc step to remove all unused peer
  // pointers, but we can probably go a while not worrying about it, or better
  // yet, do it gradually! When allocating a resource, we give one peer pointer
  // to Lua, one peer pointer to the engine. Any internal users of the resource
  // can lock() it to keep it alive for the time being. The locking
  // functionality will not be directly exposed to the lua mod. The only issue
  // will be circular dependencies. I think the trick here is to order the
  // members of Engine such that things only depend on things above them and
  // not the other way around, that way everything will be destructed in the
  // right order. It's easy enough to make a weak lock or just use a vanilla
  // pointer, etc.

  // two scenarios where data
  // *should* be uninitialized: When lua is done with it and when the engine
  // is uninitialized. The two things are the reverse of mutually exclusive -
  // each one

  namespace detail
  {
    template <class T>
    struct Peer_Ptr_Data
    {
      // Aka payload
      T* ptr;

      std::atomic<unsigned long> lock_count;
      std::atomic<unsigned long> peer_count;

      // When a peer destructs it will signal the locks to uninitialize the
      // payload.
      std::atomic<bool> keep_alive;
    };

    // Attempt to delete the data, based on new values of peer_count, etc.
    template <class T>
    void attempt_reset(Peer_Ptr_Data<T>*& data)
    {
      // We can't do anything if there is a lock on the resource.
      if(data->lock_count.load() == 0)
      {
        // If we aren't compelled to keep the pointer alive, deallocate it.
        if(!data->keep_alive.load())
        {
          // TODO: Support custom deleter!!
          delete data->ptr;
          data->ptr = nullptr;
        }

        // If we are the last peer, we can also deallocate the container.
        if(data->peer_count.load() == 0)
        {
          // The fact that we use delete is coupled to the fact that
          // make_peer_ptrs uses new.
          delete data;
          data = nullptr;
        }
      }
    }
  }

  // This is a standard ref-counted interface to the peer pointer, these will
  // keep the pointer alive so use them sparingly.

  // It's possible that we may have to deallocate either of the pointers here.
  template <class T>
  struct Peer_Lock
  {
    Peer_Lock() : data_(nullptr) {}
    ~Peer_Lock();

    Peer_Lock(Peer_Lock&& ptr);
    Peer_Lock(Peer_Lock const&);

    Peer_Lock& operator=(Peer_Lock&& ptr);
    Peer_Lock& operator=(Peer_Lock const& ptr);

    T* operator->() const;
    T& operator*() const;

    T* get() const;

    void reset();

  private:
    Peer_Lock(detail::Peer_Ptr_Data<T>* data);

    detail::Peer_Ptr_Data<T>* data_;

    template <class U>
    friend class Peer_Ptr;
  };

  template <class T>
  Peer_Lock<T>::~Peer_Lock()
  {
    reset();
  }

  template <class T>
  Peer_Lock<T>::Peer_Lock(Peer_Lock&& ptr) : data_(ptr.data_)
  {
    ptr.data_ = nullptr;
  }
  template <class T>
  Peer_Lock<T>::Peer_Lock(Peer_Lock const& rhs) : data_(rhs.data_)
  {
    // If we are given data, inform the container that there is a new lock (us).
    if(data_) ++data_->lock_count;
  }

  template <class T>
  Peer_Lock<T>& Peer_Lock<T>::operator=(Peer_Lock&& rhs)
  {
    this->data_ = rhs.data_;
    rhs.data_ = nullptr;

    return *this;
  }
  template <class T>
  Peer_Lock<T>& Peer_Lock<T>::operator=(Peer_Lock const& rhs)
  {
    // Are we actually locking the same thing?
    if(data_ == rhs.data_) return *this;

    // Nope, reset our data and grab theirs
    reset();
    data_ = rhs.data_;

    // One more lock
    if(data_) ++data_->lock_count;
    return *this;
  }

  template <class T>
  T* Peer_Lock<T>::operator->() const
  {
    return get();
  }
  template <class T>
  T& Peer_Lock<T>::operator*() const
  {
    return *get();
  }

  template <class T>
  T* Peer_Lock<T>::get() const
  {
    if(data_) return data_->ptr;
    else return nullptr;
  }

  template <class T>
  Peer_Lock<T>::Peer_Lock(detail::Peer_Ptr_Data<T>* data) : data_(data)
  {
    ++data->lock_count;
  }

  template <class T>
  void Peer_Lock<T>::reset()
  {
    // No data?
    if(!data_) return; // No problem!

    // One less lock
    --data_->lock_count;

    // Do any cleanup that is necessary at this point.
    attempt_reset(data_);

    // We did all we could do, now it's time to say our farewells.
    data_ = nullptr;
  }

  template <class T>
  struct Peer_Ptr
  {
    Peer_Ptr() : data_(nullptr) {}

    template <class U>
    Peer_Ptr(std::unique_ptr<U> ptr);

    template <class U>
    Peer_Ptr& operator=(std::unique_ptr<U> ptr);

    ~Peer_Ptr();

    Peer_Ptr(Peer_Ptr&& ptr);
    Peer_Ptr(Peer_Ptr const&) = delete;

    Peer_Ptr& operator=(Peer_Ptr&& ptr);
    Peer_Ptr& operator=(Peer_Ptr const& ptr) = delete;

    T* operator->() const;
    T& operator*() const;

    T* get() const;

    Peer_Ptr<T> peer() const;
    Peer_Lock<T> lock() const;

    std::size_t peers() const;

    void reset();

  private:
    Peer_Ptr(detail::Peer_Ptr_Data<T>* data);

    detail::Peer_Ptr_Data<T>* data_;
  };

  // Unique pointer construction, the engine will probably make new peers later
  // with peer().
  template <class T>
  template <class U>
  Peer_Ptr<T>::Peer_Ptr(std::unique_ptr<U> ptr) : data_(nullptr)
  {
    *this = std::move(ptr);
  }
  template <class T>
  template <class U>
  Peer_Ptr<T>& Peer_Ptr<T>::operator=(std::unique_ptr<U> ptr)
  {
    reset();

    // Don't worry about it if this ia nullptr.
    if(!ptr) return *this;

    data_ = new detail::Peer_Ptr_Data<T>;
    data_->ptr = ptr.release();
    data_->lock_count = 0;
    data_->keep_alive = true;

    // Us!
    data_->peer_count = 1;

    return *this;
  }

  template <class T>
  Peer_Ptr<T>::~Peer_Ptr()
  {
    reset();
  }

  template <class T>
  Peer_Ptr<T>::Peer_Ptr(Peer_Ptr&& rhs) : data_(rhs.data_)
  {
    rhs.data_ = nullptr;
  }

  template <class T>
  Peer_Ptr<T>& Peer_Ptr<T>::operator=(Peer_Ptr&& rhs)
  {
    this->data_ = rhs.data_;
    rhs.data_ = nullptr;

    return *this;
  }

  template <class T>
  T* Peer_Ptr<T>::operator->() const
  {
    return get();
  }

  template <class T>
  T& Peer_Ptr<T>::operator*() const
  {
    return *get();
  }

  template <class T>
  T* Peer_Ptr<T>::get() const
  {
    if(data_) return data_->ptr;
    else return nullptr;
  }

  template <class T>
  Peer_Lock<T> Peer_Ptr<T>::lock() const
  {
    return Peer_Lock<T>{data_};
  }
  template <class T>
  Peer_Ptr<T> Peer_Ptr<T>::peer() const
  {
    // Be careful! We are making yet another in for the data to be delete'd
    // from under us!
    return Peer_Ptr{data_};
  }

  template <class T>
  std::size_t Peer_Ptr<T>::peers() const
  {
    if(!data_) return 0;
    return data_->peer_count.load();
  }

  template <class T>
  void Peer_Ptr<T>::reset()
  {
    // If we don't have any data, fo'get about it
    if(!data_) return;

    // At least one less peer (us) no longer active.
    --data_->peer_count;

    // Since we're a peer, the data can be deallocated as soon as possible.
    data_->keep_alive = false;

    // Attempt to reclaim the data if possible at this point.
    attempt_reset(data_);

    // Byebye data
    data_ = nullptr;
  }

  template <class T>
  Peer_Ptr<T>::Peer_Ptr(detail::Peer_Ptr_Data<T>* data) : data_(data)
  {
    if(data_) ++data_->peer_count;
  }

  template <class T, class... Args>
  Peer_Ptr<T> make_peer_ptr(Args&&... args)
  {
    auto ptr = std::make_unique<T>(std::forward<Args>(args)...);
    return Peer_Ptr<T>{std::move(ptr)};
  }

  // How client code must construct a Peer_Ptr.
  template <class T, unsigned int N, class... Args>
  std::enable_if_t<N == (sizeof...(Args) + 1), std::array<Peer_Ptr<T>, N> >
  make_peer_array_impl(Peer_Ptr<T>&& ptr, Args&&... args)
  {
    // We have all peer pointers we need, move them into a new array.
    return std::array<Peer_Ptr<T>, N>{std::move(ptr), std::forward<Args>(args)...};
  }

  template <class T, unsigned int N, class... Args>
  std::enable_if_t<N != (sizeof...(Args) + 1), std::array<Peer_Ptr<T>, N> >
  make_peer_array_impl(Peer_Ptr<T>&& ptr, Args&&... args)
  {
    // We can't use fill because we do want many (independent) instances of a
    // peer and we can't do a copy.

    // Add a peer, we are not there yet!
    return make_peer_array_impl<T, N>(std::move(ptr),
                                      std::forward<Args>(args)...,
                                      ptr.peer());
  }

  template <class T, unsigned int N, class... Args>
  std::array<Peer_Ptr<T>, N> make_peer_array(Args&&... args)
  {
    // Our args are for the payload

    // Initialize the actual data / payload.
    auto peer = make_peer_ptr<T>(std::forward<Args>(args)...);
    return make_peer_array_impl<T, N>(std::move(peer));
  }

  template <class T, class... Args>
  std::pair<Peer_Ptr<T>, Peer_Ptr<T> > make_peer_pair(Args&&... args)
  {
    auto arr = make_peer_array<T, 2>(std::forward<Args>(args)...);
    return std::make_pair(std::move(arr[0]), std::move(arr[1]));
  }
}
<commit_msg>Add constructor from raw pointer to peer ptr<commit_after>/*
 * Copyright (C) 2016 Luke San Antonio
 * All rights reserved.
 */
#pragma once
#include <atomic>
namespace redc
{
  // We have a lot of resources that don't need to be kept alive by the engine,
  // but do need to be properly uninitialized before the engine is
  // uninitialized itself. We can achieve this by sharing the ownership of the
  // pointer between peer objects. One of them goes out of scope? Deallocate
  // the data immediately.

  // The above being said, it would also be convenient if we could have
  // external references to the peer that keep it alive. Basically, the peer
  // represents the lowest common denominator of use. When all the shared
  // references (different type of object) get destructed and at least one peer
  // no longer cares about the object, we can finally uninitialize the memory.
  // This makes sense for our engine because we must only keep a resource alive
  // if:
  // - The mod is currently holding a reference to it
  // - Some part of the engine is holding a reference to it
  // However, deallocation must happen if
  // - The engine is about to be uninitialized itself, or
  // - Neither the mod nor any part of the engine is using the resource.

  // This is different from a shared_ptr / weak_ptr relationship because if we
  // store a weak_ptr in the engine and give lua a shared_ptr, lua gets to call
  // the shots, when to uninitialize the resource, which could be after we
  // uninitialize the engine - that doesn't help us.
  // On the other hand, if we give the weak_ptr to lua and give the shared_ptr
  // to the engine, we'll have to manually go through and figure out what
  // resources have been dropped / gc'd by lua anyway. This can be done with
  // some sort of primitive gc step of our own every few frames, but would
  // still complicate the interface of the Engine structure, as well as any
  // associated implementation. Furthermore, I have no idea how many resources
  // are going to be controlled in this way, meaning it would only get worse.
  // This is just my solution / abstraction to this problem. Also, this is not
  // typical use of shared_ptr / weak_ptr so it could get confusing, etc.

  // Our solution still requires a basic gc step to remove all unused peer
  // pointers, but we can probably go a while not worrying about it, or better
  // yet, do it gradually! When allocating a resource, we give one peer pointer
  // to Lua, one peer pointer to the engine. Any internal users of the resource
  // can lock() it to keep it alive for the time being. The locking
  // functionality will not be directly exposed to the lua mod. The only issue
  // will be circular dependencies. I think the trick here is to order the
  // members of Engine such that things only depend on things above them and
  // not the other way around, that way everything will be destructed in the
  // right order. It's easy enough to make a weak lock or just use a vanilla
  // pointer, etc.

  // two scenarios where data
  // *should* be uninitialized: When lua is done with it and when the engine
  // is uninitialized. The two things are the reverse of mutually exclusive -
  // each one

  namespace detail
  {
    template <class T>
    struct Peer_Ptr_Data
    {
      // Aka payload
      T* ptr;

      std::atomic<unsigned long> lock_count;
      std::atomic<unsigned long> peer_count;

      // When a peer destructs it will signal the locks to uninitialize the
      // payload.
      std::atomic<bool> keep_alive;
    };

    // Attempt to delete the data, based on new values of peer_count, etc.
    template <class T>
    void attempt_reset(Peer_Ptr_Data<T>*& data)
    {
      // We can't do anything if there is a lock on the resource.
      if(data->lock_count.load() == 0)
      {
        // If we aren't compelled to keep the pointer alive, deallocate it.
        if(!data->keep_alive.load())
        {
          // TODO: Support custom deleter!!
          delete data->ptr;
          data->ptr = nullptr;
        }

        // If we are the last peer, we can also deallocate the container.
        if(data->peer_count.load() == 0)
        {
          // The fact that we use delete is coupled to the fact that
          // make_peer_ptrs uses new.
          delete data;
          data = nullptr;
        }
      }
    }
  }

  // This is a standard ref-counted interface to the peer pointer, these will
  // keep the pointer alive so use them sparingly.

  // It's possible that we may have to deallocate either of the pointers here.
  template <class T>
  struct Peer_Lock
  {
    Peer_Lock() : data_(nullptr) {}
    ~Peer_Lock();

    Peer_Lock(Peer_Lock&& ptr);
    Peer_Lock(Peer_Lock const&);

    Peer_Lock& operator=(Peer_Lock&& ptr);
    Peer_Lock& operator=(Peer_Lock const& ptr);

    T* operator->() const;
    T& operator*() const;

    T* get() const;

    void reset();

  private:
    Peer_Lock(detail::Peer_Ptr_Data<T>* data);

    detail::Peer_Ptr_Data<T>* data_;

    template <class U>
    friend class Peer_Ptr;
  };

  template <class T>
  Peer_Lock<T>::~Peer_Lock()
  {
    reset();
  }

  template <class T>
  Peer_Lock<T>::Peer_Lock(Peer_Lock&& ptr) : data_(ptr.data_)
  {
    ptr.data_ = nullptr;
  }
  template <class T>
  Peer_Lock<T>::Peer_Lock(Peer_Lock const& rhs) : data_(rhs.data_)
  {
    // If we are given data, inform the container that there is a new lock (us).
    if(data_) ++data_->lock_count;
  }

  template <class T>
  Peer_Lock<T>& Peer_Lock<T>::operator=(Peer_Lock&& rhs)
  {
    this->data_ = rhs.data_;
    rhs.data_ = nullptr;

    return *this;
  }
  template <class T>
  Peer_Lock<T>& Peer_Lock<T>::operator=(Peer_Lock const& rhs)
  {
    // Are we actually locking the same thing?
    if(data_ == rhs.data_) return *this;

    // Nope, reset our data and grab theirs
    reset();
    data_ = rhs.data_;

    // One more lock
    if(data_) ++data_->lock_count;
    return *this;
  }

  template <class T>
  T* Peer_Lock<T>::operator->() const
  {
    return get();
  }
  template <class T>
  T& Peer_Lock<T>::operator*() const
  {
    return *get();
  }

  template <class T>
  T* Peer_Lock<T>::get() const
  {
    if(data_) return data_->ptr;
    else return nullptr;
  }

  template <class T>
  Peer_Lock<T>::Peer_Lock(detail::Peer_Ptr_Data<T>* data) : data_(data)
  {
    ++data->lock_count;
  }

  template <class T>
  void Peer_Lock<T>::reset()
  {
    // No data?
    if(!data_) return; // No problem!

    // One less lock
    --data_->lock_count;

    // Do any cleanup that is necessary at this point.
    attempt_reset(data_);

    // We did all we could do, now it's time to say our farewells.
    data_ = nullptr;
  }

  template <class T>
  struct Peer_Ptr
  {
    Peer_Ptr() : data_(nullptr) {}

    template <class U>
    explicit Peer_Ptr(U* pointer);

    template <class U>
    Peer_Ptr(std::unique_ptr<U> ptr);

    template <class U>
    Peer_Ptr& operator=(std::unique_ptr<U> ptr);

    ~Peer_Ptr();

    Peer_Ptr(Peer_Ptr&& ptr);
    Peer_Ptr(Peer_Ptr const&) = delete;

    Peer_Ptr& operator=(Peer_Ptr&& ptr);
    Peer_Ptr& operator=(Peer_Ptr const& ptr) = delete;

    T* operator->() const;
    T& operator*() const;

    T* get() const;

    Peer_Ptr<T> peer() const;
    Peer_Lock<T> lock() const;

    std::size_t peers() const;

    void reset();

  private:
    Peer_Ptr(detail::Peer_Ptr_Data<T>* data);

    detail::Peer_Ptr_Data<T>* data_;
  };

  template <class T>
  template <class U>
  Peer_Ptr<T>::Peer_Ptr(U* data) : data_(new detail::Peer_Ptr_Data<T>())
  {
    data_->ptr = data;
    data_->lock_count = 0;
    data_->keep_alive = true;
    data_->peer_count = 1;
  }
  // Unique pointer construction, the engine will probably make new peers later
  // with peer().
  template <class T>
  template <class U>
  Peer_Ptr<T>::Peer_Ptr(std::unique_ptr<U> ptr) : data_(nullptr)
  {
    *this = std::move(ptr);
  }
  template <class T>
  template <class U>
  Peer_Ptr<T>& Peer_Ptr<T>::operator=(std::unique_ptr<U> ptr)
  {
    reset();

    // Don't worry about it if this ia nullptr.
    if(!ptr) return *this;

    data_ = new detail::Peer_Ptr_Data<T>;
    data_->ptr = ptr.release();
    data_->lock_count = 0;
    data_->keep_alive = true;

    // Us!
    data_->peer_count = 1;

    return *this;
  }

  template <class T>
  Peer_Ptr<T>::~Peer_Ptr()
  {
    reset();
  }

  template <class T>
  Peer_Ptr<T>::Peer_Ptr(Peer_Ptr&& rhs) : data_(rhs.data_)
  {
    rhs.data_ = nullptr;
  }

  template <class T>
  Peer_Ptr<T>& Peer_Ptr<T>::operator=(Peer_Ptr&& rhs)
  {
    this->data_ = rhs.data_;
    rhs.data_ = nullptr;

    return *this;
  }

  template <class T>
  T* Peer_Ptr<T>::operator->() const
  {
    return get();
  }

  template <class T>
  T& Peer_Ptr<T>::operator*() const
  {
    return *get();
  }

  template <class T>
  T* Peer_Ptr<T>::get() const
  {
    if(data_) return data_->ptr;
    else return nullptr;
  }

  template <class T>
  Peer_Lock<T> Peer_Ptr<T>::lock() const
  {
    return Peer_Lock<T>{data_};
  }
  template <class T>
  Peer_Ptr<T> Peer_Ptr<T>::peer() const
  {
    // Be careful! We are making yet another in for the data to be delete'd
    // from under us!
    return Peer_Ptr{data_};
  }

  template <class T>
  std::size_t Peer_Ptr<T>::peers() const
  {
    if(!data_) return 0;
    return data_->peer_count.load();
  }

  template <class T>
  void Peer_Ptr<T>::reset()
  {
    // If we don't have any data, fo'get about it
    if(!data_) return;

    // At least one less peer (us) no longer active.
    --data_->peer_count;

    // Since we're a peer, the data can be deallocated as soon as possible.
    data_->keep_alive = false;

    // Attempt to reclaim the data if possible at this point.
    attempt_reset(data_);

    // Byebye data
    data_ = nullptr;
  }

  template <class T>
  Peer_Ptr<T>::Peer_Ptr(detail::Peer_Ptr_Data<T>* data) : data_(data)
  {
    if(data_) ++data_->peer_count;
  }

  template <class T, class... Args>
  Peer_Ptr<T> make_peer_ptr(Args&&... args)
  {
    auto ptr = std::make_unique<T>(std::forward<Args>(args)...);
    return Peer_Ptr<T>{std::move(ptr)};
  }

  // How client code must construct a Peer_Ptr.
  template <class T, unsigned int N, class... Args>
  std::enable_if_t<N == (sizeof...(Args) + 1), std::array<Peer_Ptr<T>, N> >
  make_peer_array_impl(Peer_Ptr<T>&& ptr, Args&&... args)
  {
    // We have all peer pointers we need, move them into a new array.
    return std::array<Peer_Ptr<T>, N>{std::move(ptr), std::forward<Args>(args)...};
  }

  template <class T, unsigned int N, class... Args>
  std::enable_if_t<N != (sizeof...(Args) + 1), std::array<Peer_Ptr<T>, N> >
  make_peer_array_impl(Peer_Ptr<T>&& ptr, Args&&... args)
  {
    // We can't use fill because we do want many (independent) instances of a
    // peer and we can't do a copy.

    // Add a peer, we are not there yet!
    return make_peer_array_impl<T, N>(std::move(ptr),
                                      std::forward<Args>(args)...,
                                      ptr.peer());
  }

  template <class T, unsigned int N, class... Args>
  std::array<Peer_Ptr<T>, N> make_peer_array(Args&&... args)
  {
    // Our args are for the payload

    // Initialize the actual data / payload.
    auto peer = make_peer_ptr<T>(std::forward<Args>(args)...);
    return make_peer_array_impl<T, N>(std::move(peer));
  }

  template <class T, class... Args>
  std::pair<Peer_Ptr<T>, Peer_Ptr<T> > make_peer_pair(Args&&... args)
  {
    auto arr = make_peer_array<T, 2>(std::forward<Args>(args)...);
    return std::make_pair(std::move(arr[0]), std::move(arr[1]));
  }
}
<|endoftext|>


<commit_before>class Solution {
    public:
        bool canJump(int A[], int n) {
            if(n == 0) return true;
            bool *flag = new bool[n];
            memset((void*)flag, false, sizeof(bool)*n);
            flag[n-1] = true;
            for(int i = n - 1; i >=0; i --){
                if(A[i] >= n - i){flag[i] = true; continue;}
                for(int j = i + 1; j <= i + A[i]; ++j){
                    if(flag[j] == true){flag[i] = true; break;}
                }
            }
            return flag[0];
        }
};
<commit_msg>add a o(n) time solution, accepted<commit_after>class Solution {
    public:
        bool canJump(int A[], int n) {
            if(n == 0) return true;
            int stop1 = A[0];
            for(int i = 0; i != n && i <= stop1; ++i){
                int stop2 = i + A[i];
                if(stop2 > stop1) stop1 = stop2;
                if(stop1 >= n - 1) return true;
            }
            return false;
        }
};
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: ECatalog.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: oj $ $Date: 2001-10-05 06:15:31 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _CONNECTIVITY_FLAT_CATALOG_HXX_
#include "flat/ECatalog.hxx"
#endif

#ifndef _CONNECTIVITY_FLAT_DCONNECTION_HXX_
#include "flat/EConnection.hxx"
#endif
#ifndef _CONNECTIVITY_FLAT_TABLES_HXX_
#include "flat/ETables.hxx"
#endif
#ifndef _COM_SUN_STAR_SDBC_XROW_HPP_
#include <com/sun/star/sdbc/XRow.hpp>
#endif
#ifndef _COM_SUN_STAR_SDBC_XRESULTSET_HPP_
#include <com/sun/star/sdbc/XResultSet.hpp>
#endif

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::sdbcx;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::container;

// -------------------------------------------------------------------------
using namespace connectivity::flat;
// -------------------------------------------------------------------------
OFlatCatalog::OFlatCatalog(OFlatConnection* _pCon) : file::OFileCatalog(_pCon)
{
}
// -------------------------------------------------------------------------
void OFlatCatalog::refreshTables()
{
    TStringVector aVector;
    Sequence< ::rtl::OUString > aTypes;
    Reference< XResultSet > xResult = m_xMetaData->getTables(Any(),
        ::rtl::OUString::createFromAscii("%"),::rtl::OUString::createFromAscii("%"),aTypes);

    if(xResult.is())
    {
        Reference< XRow > xRow(xResult,UNO_QUERY);
        while(xResult->next())
            aVector.push_back(xRow->getString(3));
    }
    if(m_pTables)
        m_pTables->reFill(aVector);
    else
        m_pTables = new OFlatTables(m_xMetaData,*this,m_aMutex,aVector);
}
// -----------------------------------------------------------------------------

<commit_msg>INTEGRATION: CWS ooo19126 (1.4.342); FILE MERGED 2005/09/05 17:23:53 rt 1.4.342.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: ECatalog.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 05:59:19 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _CONNECTIVITY_FLAT_CATALOG_HXX_
#include "flat/ECatalog.hxx"
#endif

#ifndef _CONNECTIVITY_FLAT_DCONNECTION_HXX_
#include "flat/EConnection.hxx"
#endif
#ifndef _CONNECTIVITY_FLAT_TABLES_HXX_
#include "flat/ETables.hxx"
#endif
#ifndef _COM_SUN_STAR_SDBC_XROW_HPP_
#include <com/sun/star/sdbc/XRow.hpp>
#endif
#ifndef _COM_SUN_STAR_SDBC_XRESULTSET_HPP_
#include <com/sun/star/sdbc/XResultSet.hpp>
#endif

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::sdbcx;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::container;

// -------------------------------------------------------------------------
using namespace connectivity::flat;
// -------------------------------------------------------------------------
OFlatCatalog::OFlatCatalog(OFlatConnection* _pCon) : file::OFileCatalog(_pCon)
{
}
// -------------------------------------------------------------------------
void OFlatCatalog::refreshTables()
{
    TStringVector aVector;
    Sequence< ::rtl::OUString > aTypes;
    Reference< XResultSet > xResult = m_xMetaData->getTables(Any(),
        ::rtl::OUString::createFromAscii("%"),::rtl::OUString::createFromAscii("%"),aTypes);

    if(xResult.is())
    {
        Reference< XRow > xRow(xResult,UNO_QUERY);
        while(xResult->next())
            aVector.push_back(xRow->getString(3));
    }
    if(m_pTables)
        m_pTables->reFill(aVector);
    else
        m_pTables = new OFlatTables(m_xMetaData,*this,m_aMutex,aVector);
}
// -----------------------------------------------------------------------------

<|endoftext|>


<commit_before>#define MS_CLASS "RTC::Consumer"
// #define MS_LOG_DEV

#include "RTC/Consumer.hpp"
#include "Logger.hpp"
#include "MediaSoupError.hpp"
#include "Utils.hpp"
#include "RTC/RTCP/FeedbackRtpNack.hpp"
#include "RTC/RTCP/SenderReport.hpp"
#include <vector>

namespace RTC
{
	/* Static. */

	static std::vector<RTC::RtpPacket*> RtpRetransmissionContainer(18);

	/* Instance methods. */

	Consumer::Consumer(
	    Channel::Notifier* notifier, uint32_t consumerId, RTC::Media::Kind kind, uint32_t sourceProducerId)
	    : consumerId(consumerId), kind(kind), sourceProducerId(sourceProducerId), notifier(notifier)
	{
		MS_TRACE();

		// Set the RTCP report generation interval.
		if (this->kind == RTC::Media::Kind::AUDIO)
			this->maxRtcpInterval = RTC::RTCP::MaxAudioIntervalMs;
		else
			this->maxRtcpInterval = RTC::RTCP::MaxVideoIntervalMs;
	}

	Consumer::~Consumer()
	{
		MS_TRACE();

		if (this->rtpStream)
			delete this->rtpStream;
	}

	void Consumer::Destroy()
	{
		MS_TRACE();

		for (auto& listener : this->listeners)
		{
			listener->OnConsumerClosed(this);
		}

		this->notifier->Emit(this->consumerId, "close");

		delete this;
	}

	Json::Value Consumer::ToJson() const
	{
		MS_TRACE();

		static const Json::StaticString JsonStringConsumerId{ "consumerId" };
		static const Json::StaticString JsonStringKind{ "kind" };
		static const Json::StaticString JsonStringSourceProducerId{ "sourceProducerId" };
		static const Json::StaticString JsonStringRtpParameters{ "rtpParameters" };
		static const Json::StaticString JsonStringRtpStream{ "rtpStream" };
		static const Json::StaticString JsonStringEnabled{ "enabled" };
		static const Json::StaticString JsonStringPaused{ "paused" };
		static const Json::StaticString JsonStringSourcePaused{ "sourcePaused" };

		Json::Value json(Json::objectValue);

		json[JsonStringConsumerId] = Json::UInt{ this->consumerId };

		json[JsonStringKind] = RTC::Media::GetJsonString(this->kind);

		json[JsonStringSourceProducerId] = Json::UInt{ this->sourceProducerId };

		if (this->transport)
			json[JsonStringRtpParameters] = this->rtpParameters.ToJson();

		if (this->rtpStream)
			json[JsonStringRtpStream] = this->rtpStream->ToJson();

		json[JsonStringPaused] = this->paused;

		json[JsonStringSourcePaused] = this->sourcePaused;

		return json;
	}

	void Consumer::HandleRequest(Channel::Request* request)
	{
		MS_TRACE();

		switch (request->methodId)
		{
			case Channel::Request::MethodId::CONSUMER_DUMP:
			{
				auto json = ToJson();

				request->Accept(json);

				break;
			}

			case Channel::Request::MethodId::CONSUMER_PAUSE:
			{
				this->paused = true;

				request->Accept();

				break;
			}

			case Channel::Request::MethodId::CONSUMER_RESUME:
			{
				bool wasPaused = IsPaused();

				this->paused = false;

				request->Accept();

				if (IsEnabled() && wasPaused && !IsPaused())
				{
					for (auto& listener : this->listeners)
					{
						listener->OnConsumerFullFrameRequired(this);
					}
				}

				break;
			}

			default:
			{
				MS_ERROR("unknown method");

				request->Reject("unknown method");
			}
		}
	}

	void Consumer::Enable(RTC::Transport* transport, RTC::RtpParameters& rtpParameters)
	{
		MS_TRACE();

		if (IsEnabled())
			Disable();

		this->transport     = transport;
		this->rtpParameters = rtpParameters;

		FillSupportedCodecPayloadTypes();

		// Create RtpStreamSend instance.
		CreateRtpStream(this->rtpParameters.encodings[0]);
	}

	void Consumer::Disable()
	{
		MS_TRACE();

		this->transport = nullptr;

		this->supportedCodecPayloadTypes.clear();

		if (this->rtpStream)
		{
			delete this->rtpStream;
			this->rtpStream = nullptr;
		}

		// Reset RTCP and RTP counter stuff.
		this->lastRtcpSentTime = 0;
		this->transmittedCounter.Reset();
		this->retransmittedCounter.Reset();
	}

	void Consumer::SendRtpPacket(RTC::RtpPacket* packet)
	{
		MS_TRACE();

		// If paused don't forward RTP.
		if (IsPaused())
			return;

		// Ignore the packet if the SSRC is not the single one in the sender
		// RTP parameters.
		if (packet->GetSsrc() != this->rtpParameters.encodings[0].ssrc)
		{
			MS_WARN_TAG(rtp, "ignoring packet with unknown SSRC [ssrc:%" PRIu32 "]", packet->GetSsrc());

			return;
		}

		// Map the payload type.
		auto payloadType = packet->GetPayloadType();

		// NOTE: This may happen if this Consumer supports just some codecs of those
		// in the corresponding Producer.
		if (this->supportedCodecPayloadTypes.find(payloadType) == this->supportedCodecPayloadTypes.end())
		{
			MS_DEBUG_DEV("payload type not supported [payloadType:%" PRIu8 "]", payloadType);

			return;
		}

		// Process the packet.
		if (!this->rtpStream->ReceivePacket(packet))
			return;

		// Send the packet.
		this->transport->SendRtpPacket(packet);

		// Update transmitted RTP data counter.
		this->transmittedCounter.Update(packet);
	}

	void Consumer::GetRtcp(RTC::RTCP::CompoundPacket* packet, uint64_t now)
	{
		MS_TRACE();

		if (static_cast<float>((now - this->lastRtcpSentTime) * 1.15) < this->maxRtcpInterval)
			return;

		auto* report = this->rtpStream->GetRtcpSenderReport(now);

		if (report == nullptr)
			return;

		// NOTE: This assumes a single stream.
		uint32_t ssrc     = this->rtpParameters.encodings[0].ssrc;
		std::string cname = this->rtpParameters.rtcp.cname;

		report->SetSsrc(ssrc);
		packet->AddSenderReport(report);

		// Build SDES chunk for this sender.
		auto sdesChunk = new RTC::RTCP::SdesChunk(ssrc);
		auto sdesItem =
		    new RTC::RTCP::SdesItem(RTC::RTCP::SdesItem::Type::CNAME, cname.size(), cname.c_str());

		sdesChunk->AddItem(sdesItem);
		packet->AddSdesChunk(sdesChunk);
		this->lastRtcpSentTime = now;
	}

	void Consumer::ReceiveNack(RTC::RTCP::FeedbackRtpNackPacket* nackPacket)
	{
		MS_TRACE();

		for (auto it = nackPacket->Begin(); it != nackPacket->End(); ++it)
		{
			RTC::RTCP::FeedbackRtpNackItem* item = *it;

			this->rtpStream->RequestRtpRetransmission(
			    item->GetPacketId(), item->GetLostPacketBitmask(), RtpRetransmissionContainer);

			auto it2 = RtpRetransmissionContainer.begin();
			for (; it2 != RtpRetransmissionContainer.end(); ++it2)
			{
				RTC::RtpPacket* packet = *it2;

				if (packet == nullptr)
					break;

				RetransmitRtpPacket(packet);
			}
		}
	}

	void Consumer::ReceiveRtcpReceiverReport(RTC::RTCP::ReceiverReport* report)
	{
		MS_TRACE();

		this->rtpStream->ReceiveRtcpReceiverReport(report);
	}

	void Consumer::RequestFullFrame()
	{
		MS_TRACE();

		for (auto& listener : this->listeners)
		{
			listener->OnConsumerFullFrameRequired(this);
		}
	}

	void Consumer::FillSupportedCodecPayloadTypes()
	{
		MS_TRACE();

		for (auto& codec : this->rtpParameters.codecs)
		{
			this->supportedCodecPayloadTypes.insert(codec.payloadType);
		}
	}

	void Consumer::CreateRtpStream(RTC::RtpEncodingParameters& encoding)
	{
		MS_TRACE();

		uint32_t ssrc = encoding.ssrc;
		// Get the codec of the stream/encoding.
		auto& codec = this->rtpParameters.GetCodecForEncoding(encoding);
		bool useNack{ false };
		bool usePli{ false };

		for (auto& fb : codec.rtcpFeedback)
		{
			if (!useNack && fb.type == "nack")
			{
				MS_DEBUG_TAG(rtcp, "enabling NACK reception");

				useNack = true;
			}
			if (!usePli && fb.type == "nack" && fb.parameter == "pli")
			{
				MS_DEBUG_TAG(rtcp, "enabling PLI reception");

				usePli = true;
			}
		}

		// Create stream params.
		RTC::RtpStream::Params params;

		params.ssrc        = ssrc;
		params.payloadType = codec.payloadType;
		params.mime        = codec.mime;
		params.clockRate   = codec.clockRate;
		params.useNack     = useNack;
		params.usePli      = usePli;

		// Create a RtpStreamSend for sending a single media stream.
		if (useNack)
			this->rtpStream = new RTC::RtpStreamSend(params, 750);
		else
			this->rtpStream = new RTC::RtpStreamSend(params, 0);

		if (encoding.hasRtx && encoding.rtx.ssrc != 0u)
		{
			auto& codec = this->rtpParameters.GetRtxCodecForEncoding(encoding);

			this->rtpStream->SetRtx(codec.payloadType, encoding.rtx.ssrc);
		}
	}

	void Consumer::RetransmitRtpPacket(RTC::RtpPacket* packet)
	{
		MS_TRACE();

		RTC::RtpPacket* rtxPacket{ nullptr };

		if (this->rtpStream->HasRtx())
		{
			static uint8_t RtxBuffer[MtuSize];

			rtxPacket = packet->Clone(RtxBuffer);
			this->rtpStream->RtxEncode(rtxPacket);

			MS_DEBUG_TAG(
			    rtx,
			    "sending rtx packet [ssrc: %" PRIu32 " seqnr: %" PRIu16
			    "] recovering original [ssrc: %" PRIu32 " seqnr: %" PRIu16 "]",
			    rtxPacket->GetSsrc(),
			    rtxPacket->GetSequenceNumber(),
			    packet->GetSsrc(),
			    packet->GetSequenceNumber());
		}
		else
		{
			rtxPacket = packet;
			MS_DEBUG_TAG(
			    rtx,
			    "retransmitting packet [ssrc: %" PRIu32 " seqnr: %" PRIu16 "]",
			    rtxPacket->GetSsrc(),
			    rtxPacket->GetSequenceNumber());
		}

		// Update retransmitted RTP data counter.
		this->retransmittedCounter.Update(rtxPacket);

		// Send the packet.
		this->transport->SendRtpPacket(rtxPacket);

		// Delete the RTX RtpPacket if it was created.
		if (rtxPacket != packet)
			delete rtxPacket;
	}
} // namespace RTC
<commit_msg>Add comments<commit_after>#define MS_CLASS "RTC::Consumer"
// #define MS_LOG_DEV

#include "RTC/Consumer.hpp"
#include "Logger.hpp"
#include "MediaSoupError.hpp"
#include "Utils.hpp"
#include "RTC/RTCP/FeedbackRtpNack.hpp"
#include "RTC/RTCP/SenderReport.hpp"
#include <vector>

namespace RTC
{
	/* Static. */

	static std::vector<RTC::RtpPacket*> RtpRetransmissionContainer(18);

	/* Instance methods. */

	Consumer::Consumer(
	    Channel::Notifier* notifier, uint32_t consumerId, RTC::Media::Kind kind, uint32_t sourceProducerId)
	    : consumerId(consumerId), kind(kind), sourceProducerId(sourceProducerId), notifier(notifier)
	{
		MS_TRACE();

		// Set the RTCP report generation interval.
		if (this->kind == RTC::Media::Kind::AUDIO)
			this->maxRtcpInterval = RTC::RTCP::MaxAudioIntervalMs;
		else
			this->maxRtcpInterval = RTC::RTCP::MaxVideoIntervalMs;
	}

	Consumer::~Consumer()
	{
		MS_TRACE();

		if (this->rtpStream)
			delete this->rtpStream;
	}

	void Consumer::Destroy()
	{
		MS_TRACE();

		for (auto& listener : this->listeners)
		{
			listener->OnConsumerClosed(this);
		}

		this->notifier->Emit(this->consumerId, "close");

		delete this;
	}

	Json::Value Consumer::ToJson() const
	{
		MS_TRACE();

		static const Json::StaticString JsonStringConsumerId{ "consumerId" };
		static const Json::StaticString JsonStringKind{ "kind" };
		static const Json::StaticString JsonStringSourceProducerId{ "sourceProducerId" };
		static const Json::StaticString JsonStringRtpParameters{ "rtpParameters" };
		static const Json::StaticString JsonStringRtpStream{ "rtpStream" };
		static const Json::StaticString JsonStringEnabled{ "enabled" };
		static const Json::StaticString JsonStringPaused{ "paused" };
		static const Json::StaticString JsonStringSourcePaused{ "sourcePaused" };

		Json::Value json(Json::objectValue);

		json[JsonStringConsumerId] = Json::UInt{ this->consumerId };

		json[JsonStringKind] = RTC::Media::GetJsonString(this->kind);

		json[JsonStringSourceProducerId] = Json::UInt{ this->sourceProducerId };

		if (this->transport)
			json[JsonStringRtpParameters] = this->rtpParameters.ToJson();

		if (this->rtpStream)
			json[JsonStringRtpStream] = this->rtpStream->ToJson();

		json[JsonStringPaused] = this->paused;

		json[JsonStringSourcePaused] = this->sourcePaused;

		return json;
	}

	void Consumer::HandleRequest(Channel::Request* request)
	{
		MS_TRACE();

		switch (request->methodId)
		{
			case Channel::Request::MethodId::CONSUMER_DUMP:
			{
				auto json = ToJson();

				request->Accept(json);

				break;
			}

			case Channel::Request::MethodId::CONSUMER_PAUSE:
			{
				this->paused = true;

				request->Accept();

				break;
			}

			case Channel::Request::MethodId::CONSUMER_RESUME:
			{
				bool wasPaused = IsPaused();

				this->paused = false;

				request->Accept();

				if (IsEnabled() && wasPaused && !IsPaused())
				{
					for (auto& listener : this->listeners)
					{
						listener->OnConsumerFullFrameRequired(this);
					}
				}

				break;
			}

			default:
			{
				MS_ERROR("unknown method");

				request->Reject("unknown method");
			}
		}
	}

	/**
	 * A Transport has been assigned, and hence sending RTP parameters.
	 */
	void Consumer::Enable(RTC::Transport* transport, RTC::RtpParameters& rtpParameters)
	{
		MS_TRACE();

		if (IsEnabled())
			Disable();

		this->transport     = transport;
		this->rtpParameters = rtpParameters;

		FillSupportedCodecPayloadTypes();

		// Create RtpStreamSend instance.
		CreateRtpStream(this->rtpParameters.encodings[0]);
	}

	/**
	 * Called when the Transport assigned to this Consumer has been closed, so this
	 * Consumer becomes unhandled.
	 */
	void Consumer::Disable()
	{
		MS_TRACE();

		this->transport = nullptr;

		this->supportedCodecPayloadTypes.clear();

		if (this->rtpStream)
		{
			delete this->rtpStream;
			this->rtpStream = nullptr;
		}

		// Reset RTCP and RTP counter stuff.
		this->lastRtcpSentTime = 0;
		this->transmittedCounter.Reset();
		this->retransmittedCounter.Reset();
	}

	void Consumer::SendRtpPacket(RTC::RtpPacket* packet)
	{
		MS_TRACE();

		// If paused don't forward RTP.
		if (IsPaused())
			return;

		// Ignore the packet if the SSRC is not the single one in the sender
		// RTP parameters.
		if (packet->GetSsrc() != this->rtpParameters.encodings[0].ssrc)
		{
			MS_WARN_TAG(rtp, "ignoring packet with unknown SSRC [ssrc:%" PRIu32 "]", packet->GetSsrc());

			return;
		}

		// Map the payload type.
		auto payloadType = packet->GetPayloadType();

		// NOTE: This may happen if this Consumer supports just some codecs of those
		// in the corresponding Producer.
		if (this->supportedCodecPayloadTypes.find(payloadType) == this->supportedCodecPayloadTypes.end())
		{
			MS_DEBUG_DEV("payload type not supported [payloadType:%" PRIu8 "]", payloadType);

			return;
		}

		// Process the packet.
		if (!this->rtpStream->ReceivePacket(packet))
			return;

		// Send the packet.
		this->transport->SendRtpPacket(packet);

		// Update transmitted RTP data counter.
		this->transmittedCounter.Update(packet);
	}

	void Consumer::GetRtcp(RTC::RTCP::CompoundPacket* packet, uint64_t now)
	{
		MS_TRACE();

		if (static_cast<float>((now - this->lastRtcpSentTime) * 1.15) < this->maxRtcpInterval)
			return;

		auto* report = this->rtpStream->GetRtcpSenderReport(now);

		if (report == nullptr)
			return;

		// NOTE: This assumes a single stream.
		uint32_t ssrc     = this->rtpParameters.encodings[0].ssrc;
		std::string cname = this->rtpParameters.rtcp.cname;

		report->SetSsrc(ssrc);
		packet->AddSenderReport(report);

		// Build SDES chunk for this sender.
		auto sdesChunk = new RTC::RTCP::SdesChunk(ssrc);
		auto sdesItem =
		    new RTC::RTCP::SdesItem(RTC::RTCP::SdesItem::Type::CNAME, cname.size(), cname.c_str());

		sdesChunk->AddItem(sdesItem);
		packet->AddSdesChunk(sdesChunk);
		this->lastRtcpSentTime = now;
	}

	void Consumer::ReceiveNack(RTC::RTCP::FeedbackRtpNackPacket* nackPacket)
	{
		MS_TRACE();

		for (auto it = nackPacket->Begin(); it != nackPacket->End(); ++it)
		{
			RTC::RTCP::FeedbackRtpNackItem* item = *it;

			this->rtpStream->RequestRtpRetransmission(
			    item->GetPacketId(), item->GetLostPacketBitmask(), RtpRetransmissionContainer);

			auto it2 = RtpRetransmissionContainer.begin();
			for (; it2 != RtpRetransmissionContainer.end(); ++it2)
			{
				RTC::RtpPacket* packet = *it2;

				if (packet == nullptr)
					break;

				RetransmitRtpPacket(packet);
			}
		}
	}

	void Consumer::ReceiveRtcpReceiverReport(RTC::RTCP::ReceiverReport* report)
	{
		MS_TRACE();

		this->rtpStream->ReceiveRtcpReceiverReport(report);
	}

	void Consumer::RequestFullFrame()
	{
		MS_TRACE();

		for (auto& listener : this->listeners)
		{
			listener->OnConsumerFullFrameRequired(this);
		}
	}

	void Consumer::FillSupportedCodecPayloadTypes()
	{
		MS_TRACE();

		for (auto& codec : this->rtpParameters.codecs)
		{
			this->supportedCodecPayloadTypes.insert(codec.payloadType);
		}
	}

	void Consumer::CreateRtpStream(RTC::RtpEncodingParameters& encoding)
	{
		MS_TRACE();

		uint32_t ssrc = encoding.ssrc;
		// Get the codec of the stream/encoding.
		auto& codec = this->rtpParameters.GetCodecForEncoding(encoding);
		bool useNack{ false };
		bool usePli{ false };

		for (auto& fb : codec.rtcpFeedback)
		{
			if (!useNack && fb.type == "nack")
			{
				MS_DEBUG_TAG(rtcp, "enabling NACK reception");

				useNack = true;
			}
			if (!usePli && fb.type == "nack" && fb.parameter == "pli")
			{
				MS_DEBUG_TAG(rtcp, "enabling PLI reception");

				usePli = true;
			}
		}

		// Create stream params.
		RTC::RtpStream::Params params;

		params.ssrc        = ssrc;
		params.payloadType = codec.payloadType;
		params.mime        = codec.mime;
		params.clockRate   = codec.clockRate;
		params.useNack     = useNack;
		params.usePli      = usePli;

		// Create a RtpStreamSend for sending a single media stream.
		if (useNack)
			this->rtpStream = new RTC::RtpStreamSend(params, 750);
		else
			this->rtpStream = new RTC::RtpStreamSend(params, 0);

		if (encoding.hasRtx && encoding.rtx.ssrc != 0u)
		{
			auto& codec = this->rtpParameters.GetRtxCodecForEncoding(encoding);

			this->rtpStream->SetRtx(codec.payloadType, encoding.rtx.ssrc);
		}
	}

	void Consumer::RetransmitRtpPacket(RTC::RtpPacket* packet)
	{
		MS_TRACE();

		RTC::RtpPacket* rtxPacket{ nullptr };

		if (this->rtpStream->HasRtx())
		{
			static uint8_t RtxBuffer[MtuSize];

			rtxPacket = packet->Clone(RtxBuffer);
			this->rtpStream->RtxEncode(rtxPacket);

			MS_DEBUG_TAG(
			    rtx,
			    "sending rtx packet [ssrc: %" PRIu32 " seqnr: %" PRIu16
			    "] recovering original [ssrc: %" PRIu32 " seqnr: %" PRIu16 "]",
			    rtxPacket->GetSsrc(),
			    rtxPacket->GetSequenceNumber(),
			    packet->GetSsrc(),
			    packet->GetSequenceNumber());
		}
		else
		{
			rtxPacket = packet;
			MS_DEBUG_TAG(
			    rtx,
			    "retransmitting packet [ssrc: %" PRIu32 " seqnr: %" PRIu16 "]",
			    rtxPacket->GetSsrc(),
			    rtxPacket->GetSequenceNumber());
		}

		// Update retransmitted RTP data counter.
		this->retransmittedCounter.Update(rtxPacket);

		// Send the packet.
		this->transport->SendRtpPacket(rtxPacket);

		// Delete the RTX RtpPacket if it was created.
		if (rtxPacket != packet)
			delete rtxPacket;
	}
} // namespace RTC
<|endoftext|>


<commit_before>/* This file is part of Ingen.
 * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
 *
 * Ingen is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * Ingen 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 details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include "SetMetadataEvent.hpp"
#include <string>
#include <boost/format.hpp>
#include "Responder.hpp"
#include "Engine.hpp"
#include "PortImpl.hpp"
#include "ClientBroadcaster.hpp"
#include "GraphObjectImpl.hpp"
#include "EngineStore.hpp"

using std::string;

namespace Ingen {

SetMetadataEvent::SetMetadataEvent(
		Engine&              engine,
		SharedPtr<Responder> responder,
		SampleCount          timestamp,
		bool                 property,
		const string&        path,
		const string&        key,
		const Atom&          value)
	: QueuedEvent(engine, responder, timestamp)
	, _error(NO_ERROR)
	, _special_type(NONE)
	, _property(property)
	, _path(path)
	, _key(key)
	, _value(value)
	, _object(NULL)
{
}

void
SetMetadataEvent::pre_process()
{
	if (!Path::is_valid(_path)) {
		_error = INVALID_PATH;
		QueuedEvent::pre_process();
		return;
	}

	_object = _engine.engine_store()->find_object(_path);
	if (_object == NULL) {
		QueuedEvent::pre_process();
		return;
	}

	if (_property)
		_object->set_property(_key, _value);
	else
		_object->set_variable(_key, _value);

	if (_key == "ingen:broadcast") {
		std::cout << "BROADCAST" << std::endl;
		_special_type = ENABLE_BROADCAST;
	}

	QueuedEvent::pre_process();
}

void
SetMetadataEvent::execute(ProcessContext& context)
{
	if (_special_type == ENABLE_BROADCAST) {
		PortImpl* port = dynamic_cast<PortImpl*>(_object);
		if (port)
			port->broadcast(_value.get_bool());
	}

	QueuedEvent::execute(context);
	// Do nothing
}

void
SetMetadataEvent::post_process()
{
	if (_error == INVALID_PATH) {
		_responder->respond_error((boost::format("Invalid path %1% setting %2%") % _path % _key).str());
	} else if (_object == NULL) {
		string msg = (boost::format("Unable to find object %1% to set %2%") % _path % _key).str();
		_responder->respond_error(msg);
	} else {
		_responder->respond_ok();
		if (_property)
			_engine.broadcaster()->send_property_change(_path, _key, _value);
		else
			_engine.broadcaster()->send_variable_change(_path, _key, _value);
	}
}

} // namespace Ingen
<commit_msg>Shutup.<commit_after>/* This file is part of Ingen.
 * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
 *
 * Ingen is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * Ingen 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 details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include "SetMetadataEvent.hpp"
#include <string>
#include <boost/format.hpp>
#include "Responder.hpp"
#include "Engine.hpp"
#include "PortImpl.hpp"
#include "ClientBroadcaster.hpp"
#include "GraphObjectImpl.hpp"
#include "EngineStore.hpp"

using std::string;

namespace Ingen {

SetMetadataEvent::SetMetadataEvent(
		Engine&              engine,
		SharedPtr<Responder> responder,
		SampleCount          timestamp,
		bool                 property,
		const string&        path,
		const string&        key,
		const Atom&          value)
	: QueuedEvent(engine, responder, timestamp)
	, _error(NO_ERROR)
	, _special_type(NONE)
	, _property(property)
	, _path(path)
	, _key(key)
	, _value(value)
	, _object(NULL)
{
}

void
SetMetadataEvent::pre_process()
{
	if (!Path::is_valid(_path)) {
		_error = INVALID_PATH;
		QueuedEvent::pre_process();
		return;
	}

	_object = _engine.engine_store()->find_object(_path);
	if (_object == NULL) {
		QueuedEvent::pre_process();
		return;
	}

	if (_property)
		_object->set_property(_key, _value);
	else
		_object->set_variable(_key, _value);

	if (_key == "ingen:broadcast")
		_special_type = ENABLE_BROADCAST;

	QueuedEvent::pre_process();
}

void
SetMetadataEvent::execute(ProcessContext& context)
{
	if (_special_type == ENABLE_BROADCAST) {
		PortImpl* port = dynamic_cast<PortImpl*>(_object);
		if (port)
			port->broadcast(_value.get_bool());
	}

	QueuedEvent::execute(context);
	// Do nothing
}

void
SetMetadataEvent::post_process()
{
	if (_error == INVALID_PATH) {
		_responder->respond_error((boost::format("Invalid path %1% setting %2%") % _path % _key).str());
	} else if (_object == NULL) {
		string msg = (boost::format("Unable to find object %1% to set %2%") % _path % _key).str();
		_responder->respond_error(msg);
	} else {
		_responder->respond_ok();
		if (_property)
			_engine.broadcaster()->send_property_change(_path, _key, _value);
		else
			_engine.broadcaster()->send_variable_change(_path, _key, _value);
	}
}

} // namespace Ingen
<|endoftext|>