<commit_before>#include "Overlay.h"
#include "ui_Overlay.h"

#include "../Hearthstone.h"
#include "../Settings.h"

#ifdef Q_OS_MAC
#include <objc/objc-runtime.h>
#endif

#include <cassert>

#include <QJsonArray>
#include <QJsonObject>
#include <QJsonDocument>
#include <QFile>
#include <QMouseEvent>

#define CHECK_FOR_OVERLAY_HOVER_INTERVAL_MS 100

class OverlayHistoryWindow {
private:
  QString mTitle;
  OverlayHistoryList mHistory;

  QFont mRowFont;
  QFont mTitleFont;

  int mWidth;

  int mPadding;
  int mRowSpacing;

  int TitleHeight() const {
    QFontMetrics titleMetrics( mTitleFont );
    return titleMetrics.ascent() - titleMetrics.descent();
  }

  int Padding() const {
    return mPadding;
  }

  int RowSpacing() const {
    return mRowSpacing;
  }

  int RowHeight() const {
    QFontMetrics rowMetrics( mRowFont );
    return rowMetrics.ascent() - rowMetrics.descent();
  }

  int RowWidth() const {
    return Width() - Padding() * 2;
  }

  void DrawMana( QPainter& painter, int x, int y, int width, int height, int mana ) const {
    // Draw mana
    QPen origPen = painter.pen();
    QPen pen( QColor( 0, 52, 113 ) );
    pen.setCosmetic( true );
    pen.setWidth( 1 );
    painter.setPen( pen );

    QBrush brush( QColor( 40, 119, 238 ) );
    painter.setBrush( brush );

    QTransform transform;
    painter.translate( x + width * 0.5, y + height * 0.5 );
    painter.scale( width * 0.8, height * 0.8 );

    static const QPointF points[5] = {
      QPointF( 0.0, -1.0 ),
      QPointF( 1.0, -0.2 ),
      QPointF( 0.6, 1.0 ),
      QPointF( -0.6, 1.0 ),
      QPointF( -1.0, -0.2 ),
    };
    painter.drawConvexPolygon( points, 5 );
    painter.resetTransform();
    painter.setPen( origPen );

    painter.drawText( x, y, width, height, Qt::AlignCenter | Qt::AlignVCenter, QString::number( mana ) );
  }

  void DrawCardLine( QPainter& painter, int x, int y, int width, int height, const QString& name, int count ) const {
    QString line = name;
    if( count > 1 ) {
      line += QString( " (x%1)" ).arg( count );
    }

    painter.drawText( x, y, width, height, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip, line );
    painter.resetTransform();
  }

public:
  OverlayHistoryWindow( const QString& title, const OverlayHistoryList& history, int width, int padding, int rowSpacing, int titleFontSize, int rowFontSize )
    : mTitle( title ), mHistory( history ), mWidth( width ), mPadding( padding ), mRowSpacing( rowSpacing )
  {
    mRowFont.setPixelSize( titleFontSize );
    mTitleFont.setPixelSize( rowFontSize );
    mTitleFont.setUnderline( true );
    mTitleFont.setBold( true );
  }

  int Width() const {
    return mWidth;
  }

  int Height() const {
    return ( mHistory.count() - 1 ) * RowSpacing() + // Spacing between items
      mHistory.count() * RowHeight() + // Height per item
      TitleHeight() + RowSpacing() + // Title
      Padding() * 2; // Overall padding
  }

  void Paint( QPainter& painter, int x, int y ) const {
    painter.save();

    QRect rect( x, y, Width(), Height() );
    painter.setClipRect( rect );

    // BG
    QPen pen = QPen( QColor( 160, 160, 160 ) );
    pen.setWidth( 3 );
    painter.setPen( pen );
    painter.setBrush( QBrush( QColor( 70, 70, 70, 175 ) ) );
    painter.drawRoundedRect( rect, 10, 10 );

    // Title
    y += Padding();
    painter.setPen( QPen( Qt::white) );
    painter.setFont( mTitleFont );
    painter.drawText( x, y, Width(), TitleHeight(), Qt::AlignCenter | Qt::AlignVCenter | Qt::TextDontClip, mTitle );
    y += TitleHeight() + RowSpacing();

    // Lines
    painter.setPen( QPen( Qt::white) );
    painter.setFont( mRowFont );
    for( const QVariantMap& it : mHistory ) {
      int mx = x + Padding();
      DrawMana( painter, mx, y, RowHeight(), RowHeight(), it["mana"].toInt() );
      int cx = mx + RowHeight() + 5;
      DrawCardLine( painter, cx, y, RowWidth() - cx, RowHeight(), it["name"].toString(), it["count"].toInt() );
      y += RowHeight();
      y += RowSpacing();
    }

    painter.restore();
  }

};

Overlay::Overlay( QWidget *parent )
  : QMainWindow( parent ), mUI( new Ui::Overlay ), mShowPlayerHistory( PLAYER_UNKNOWN )
{
  mUI->setupUi( this );
  setWindowFlags( Qt::NoDropShadowWindowHint | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::Window );
  setAttribute( Qt::WA_TranslucentBackground );

  connect( Hearthstone::Instance(), &Hearthstone::GameWindowChanged, this, &Overlay::HandleGameWindowChanged );
  connect( Hearthstone::Instance(), &Hearthstone::GameStarted, this, &Overlay::HandleGameStarted );
  connect( Hearthstone::Instance(), &Hearthstone::GameStopped, this, &Overlay::HandleGameStopped );

  connect( &mCheckForHoverTimer, &QTimer::timeout, this, &Overlay::CheckForHover );

  connect( Settings::Instance(), &Settings::OverlayEnabledChanged, this, &Overlay::HandleOverlaySettingChanged );

  LoadCards();

  hide();

#ifdef Q_OS_MAC
  WId windowObject = this->winId();
  objc_object* nsviewObject = reinterpret_cast<objc_object*>(windowObject);
  objc_object* nsWindowObject = objc_msgSend( nsviewObject, sel_registerName("window") );
  int NSWindowCollectionBehaviorCanJoinAllSpaces = 1 << 0;
  objc_msgSend( nsWindowObject, sel_registerName("setCollectionBehavior:"), NSWindowCollectionBehaviorCanJoinAllSpaces );
#endif
}

Overlay::~Overlay() {
  delete mUI;
}

void Overlay::CheckForHover() {
  QPoint mouseLoc = mapFromGlobal( QCursor::pos() );

  Player showPlayerHistory = PLAYER_UNKNOWN;

  if( mPlayerDeckRect.contains( mouseLoc ) ) {
    showPlayerHistory = PLAYER_SELF;
  } else if( mOpponentDeckRect.contains( mouseLoc ) ) {
    showPlayerHistory = PLAYER_OPPONENT;
  }

  if( mShowPlayerHistory != showPlayerHistory ) {
    mShowPlayerHistory = showPlayerHistory;
    update();
  }
}

void Overlay::LoadCards() {
  QFile file( ":/data/cards.json" );
  bool opened = file.open( QIODevice::ReadOnly | QIODevice::Text );
  assert( opened );

  QByteArray jsonData = file.readAll();
  QJsonParseError error;
  QJsonArray jsonCards = QJsonDocument::fromJson( jsonData, &error ).array();
  assert( error.error == QJsonParseError::NoError );

  mCardDB.clear();

  for( QJsonValueRef jsonCardRef : jsonCards ) {
    QJsonObject jsonCard = jsonCardRef.toObject();
    mCardDB[ jsonCard["id"].toString() ] = jsonCard.toVariantMap();
  }
}

void PaintHistoryInScreen( QPainter& painter, const OverlayHistoryWindow& wnd, const QPoint& pos ) {
  int padding = 10;

  QRect rect( pos.x() + 20, pos.y(), wnd.Width(), wnd.Height() );
  rect.translate( -qMax( rect.right() - painter.device()->width() + padding, 0 ), -qMax( rect.bottom() - painter.device()->height() + padding, 0 ) ); // fit to window
  wnd.Paint( painter, rect.x(), rect.y() );
}

void Overlay::paintEvent( QPaintEvent* ) {
  QPainter painter( this );
  painter.setRenderHint( QPainter::Antialiasing );

  int overlayWidth = 200;

  if( mShowPlayerHistory == PLAYER_SELF && mPlayerHistory.count() > 0 ) {
    OverlayHistoryWindow wnd( "Cards drawn", mPlayerHistory, overlayWidth, 10, 10, 12, 12 );
    PaintHistoryInScreen( painter, wnd, mPlayerDeckRect.topRight() + QPoint( 20, 0 ) );
  } else if( mShowPlayerHistory == PLAYER_OPPONENT && mOpponentHistory.count() > 0 ) {
    OverlayHistoryWindow wnd( "Cards played by opponent", mOpponentHistory, overlayWidth, 10, 10, 12, 12 );
    PaintHistoryInScreen( painter, wnd, mOpponentDeckRect.topRight() + QPoint( 20, 0 ) );
  }
}

void Overlay::HandleGameWindowChanged( int x, int y, int w, int h ) {
  move( x, y );
  setFixedSize( w, h );

  int minWidth = h * 4 / 3;
  mPlayerDeckRect = QRect( w / 2 + 0.440 * minWidth, h * 0.510, 0.05 * minWidth, h * 0.170 );
  mOpponentDeckRect = mPlayerDeckRect.translated( -0.005 * minWidth, -0.275 * h );

  update();
}

void Overlay::Update() {
  if( Settings::Instance()->OverlayEnabled() ) {
    show();
  } else {
    hide();
  }

  update();
}

void Overlay::HandleGameStarted() {
  mCheckForHoverTimer.start( CHECK_FOR_OVERLAY_HOVER_INTERVAL_MS );
  Update();
}

void Overlay::HandleGameStopped() {
  mCheckForHoverTimer.stop();
  Update();
}

void Overlay::UpdateHistoryFor( Player player, const ::CardHistoryList& list ) {
  QMap< QString, QVariantMap > entries;

  for( const CardHistoryItem& it : list ) {
    const QString& cardId = it.cardId;

    if( cardId.isEmpty() ) {
      continue;
    }

    if( !mCardDB.contains( cardId ) ) {
      DBG( "Card %s not found", qt2cstr( cardId ) );
      continue;
    }

    if( mCardDB[ cardId ][ "type" ] == "hero" ) {
      continue;
    }

    if( it.player != player ) {
      continue;
    }

    QVariantMap& entry = entries[ cardId ];
    entry[ "count" ] = entry.value( "count", 0 ).toInt() + 1;
    entry[ "mana" ] = mCardDB[ cardId ][ "mana" ];
    entry[ "name" ] = mCardDB[ cardId ][ "name" ];
  }

  OverlayHistoryList* ref;
  if( player == PLAYER_SELF ) {
    ref = &mPlayerHistory;
  } else {
    ref = &mOpponentHistory;
  }

  *ref = entries.values();

  qSort( ref->begin(), ref->end(), []( const QVariantMap& a, const QVariantMap& b ) {
    if( a["mana"].toInt() == b["mana"].toInt() ) {
      return a["name"].toString() < b["name"].toString();
    } else {
      return a["mana"].toInt() < b["mana"].toInt();
    }
  });
}

void Overlay::HandleCardsDrawnUpdate( const ::CardHistoryList& cardsDrawn ) {
  UpdateHistoryFor( PLAYER_OPPONENT, cardsDrawn );
  UpdateHistoryFor( PLAYER_SELF, cardsDrawn );
  Update();
}

void Overlay::HandleOverlaySettingChanged( bool enabled ) {
  UNUSED_ARG( enabled );

  Update();
}
<commit_msg>Make count more visible<commit_after>#include "Overlay.h"
#include "ui_Overlay.h"

#include "../Hearthstone.h"
#include "../Settings.h"

#ifdef Q_OS_MAC
#include <objc/objc-runtime.h>
#endif

#include <cassert>

#include <QJsonArray>
#include <QJsonObject>
#include <QJsonDocument>
#include <QFile>
#include <QMouseEvent>

#define CHECK_FOR_OVERLAY_HOVER_INTERVAL_MS 100

class OverlayHistoryWindow {
private:
  QString mTitle;
  OverlayHistoryList mHistory;

  QFont mRowFont;
  QFont mTitleFont;

  int mWidth;

  int mPadding;
  int mRowSpacing;

  int TitleHeight() const {
    QFontMetrics titleMetrics( mTitleFont );
    return titleMetrics.ascent() - titleMetrics.descent();
  }

  int Padding() const {
    return mPadding;
  }

  int RowSpacing() const {
    return mRowSpacing;
  }

  int RowHeight() const {
    QFontMetrics rowMetrics( mRowFont );
    return rowMetrics.ascent() - rowMetrics.descent();
  }

  int RowWidth() const {
    return Width() - Padding() * 2;
  }

  void DrawMana( QPainter& painter, int x, int y, int width, int height, int mana ) const {
    // Draw mana
    QPen origPen = painter.pen();
    QPen pen( QColor( 0, 52, 113 ) );
    pen.setCosmetic( true );
    pen.setWidth( 1 );
    painter.setPen( pen );

    QBrush brush( QColor( 40, 119, 238 ) );
    painter.setBrush( brush );

    QTransform transform;
    painter.translate( x + width * 0.5, y + height * 0.5 );
    painter.scale( width * 0.8, height * 0.8 );

    static const QPointF points[5] = {
      QPointF( 0.0, -1.0 ),
      QPointF( 1.0, -0.2 ),
      QPointF( 0.6, 1.0 ),
      QPointF( -0.6, 1.0 ),
      QPointF( -1.0, -0.2 ),
    };
    painter.drawConvexPolygon( points, 5 );
    painter.resetTransform();
    painter.setPen( origPen );

    painter.drawText( x, y, width, height, Qt::AlignCenter | Qt::AlignVCenter, QString::number( mana ) );
  }

  void DrawCardLine( QPainter& painter, int x, int y, int width, int height, const QString& name, int count ) const {
    painter.save();
    painter.drawText( x, y, width, height, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip, name );

    if( count > 1 ) {
      int nameWidth = QFontMetrics( painter.font() ).width( name + " " );
      QString countString = QString( "x%1" ).arg( count );
      QFont font = painter.font();
      font.setBold( true );
      painter.setFont( font );
      painter.drawText( x + nameWidth, y, width - nameWidth, height, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip, countString );
    }
    painter.restore();
  }

public:
  OverlayHistoryWindow( const QString& title, const OverlayHistoryList& history, int width, int padding, int rowSpacing, int titleFontSize, int rowFontSize )
    : mTitle( title ), mHistory( history ), mWidth( width ), mPadding( padding ), mRowSpacing( rowSpacing )
  {
    mRowFont.setPixelSize( titleFontSize );
    mTitleFont.setPixelSize( rowFontSize );
    mTitleFont.setUnderline( true );
    mTitleFont.setBold( true );
  }

  int Width() const {
    return mWidth;
  }

  int Height() const {
    return ( mHistory.count() - 1 ) * RowSpacing() + // Spacing between items
      mHistory.count() * RowHeight() + // Height per item
      TitleHeight() + RowSpacing() + // Title
      Padding() * 2; // Overall padding
  }

  void Paint( QPainter& painter, int x, int y ) const {
    painter.save();

    QRect rect( x, y, Width(), Height() );
    painter.setClipRect( rect );

    // BG
    QPen pen = QPen( QColor( 160, 160, 160 ) );
    pen.setWidth( 3 );
    painter.setPen( pen );
    painter.setBrush( QBrush( QColor( 70, 70, 70, 175 ) ) );
    painter.drawRoundedRect( rect, 10, 10 );

    // Title
    y += Padding();
    painter.setPen( QPen( Qt::white) );
    painter.setFont( mTitleFont );
    painter.drawText( x, y, Width(), TitleHeight(), Qt::AlignCenter | Qt::AlignVCenter | Qt::TextDontClip, mTitle );
    y += TitleHeight() + RowSpacing();

    // Lines
    painter.setPen( QPen( Qt::white) );
    painter.setFont( mRowFont );
    for( const QVariantMap& it : mHistory ) {
      int mx = x + Padding();
      DrawMana( painter, mx, y, RowHeight(), RowHeight(), it["mana"].toInt() );
      int cx = mx + RowHeight() + 5;
      DrawCardLine( painter, cx, y, RowWidth() - cx, RowHeight(), it["name"].toString(), it["count"].toInt() );
      y += RowHeight();
      y += RowSpacing();
    }

    painter.restore();
  }

};

Overlay::Overlay( QWidget *parent )
  : QMainWindow( parent ), mUI( new Ui::Overlay ), mShowPlayerHistory( PLAYER_UNKNOWN )
{
  mUI->setupUi( this );
  setWindowFlags( Qt::NoDropShadowWindowHint | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::Window );
  setAttribute( Qt::WA_TranslucentBackground );

  connect( Hearthstone::Instance(), &Hearthstone::GameWindowChanged, this, &Overlay::HandleGameWindowChanged );
  connect( Hearthstone::Instance(), &Hearthstone::GameStarted, this, &Overlay::HandleGameStarted );
  connect( Hearthstone::Instance(), &Hearthstone::GameStopped, this, &Overlay::HandleGameStopped );

  connect( &mCheckForHoverTimer, &QTimer::timeout, this, &Overlay::CheckForHover );

  connect( Settings::Instance(), &Settings::OverlayEnabledChanged, this, &Overlay::HandleOverlaySettingChanged );

  LoadCards();

  hide();

#ifdef Q_OS_MAC
  WId windowObject = this->winId();
  objc_object* nsviewObject = reinterpret_cast<objc_object*>(windowObject);
  objc_object* nsWindowObject = objc_msgSend( nsviewObject, sel_registerName("window") );
  int NSWindowCollectionBehaviorCanJoinAllSpaces = 1 << 0;
  objc_msgSend( nsWindowObject, sel_registerName("setCollectionBehavior:"), NSWindowCollectionBehaviorCanJoinAllSpaces );
#endif
}

Overlay::~Overlay() {
  delete mUI;
}

void Overlay::CheckForHover() {
  QPoint mouseLoc = mapFromGlobal( QCursor::pos() );

  Player showPlayerHistory = PLAYER_UNKNOWN;

  if( mPlayerDeckRect.contains( mouseLoc ) ) {
    showPlayerHistory = PLAYER_SELF;
  } else if( mOpponentDeckRect.contains( mouseLoc ) ) {
    showPlayerHistory = PLAYER_OPPONENT;
  }

  if( mShowPlayerHistory != showPlayerHistory ) {
    mShowPlayerHistory = showPlayerHistory;
    update();
  }
}

void Overlay::LoadCards() {
  QFile file( ":/data/cards.json" );
  bool opened = file.open( QIODevice::ReadOnly | QIODevice::Text );
  assert( opened );

  QByteArray jsonData = file.readAll();
  QJsonParseError error;
  QJsonArray jsonCards = QJsonDocument::fromJson( jsonData, &error ).array();
  assert( error.error == QJsonParseError::NoError );

  mCardDB.clear();

  for( QJsonValueRef jsonCardRef : jsonCards ) {
    QJsonObject jsonCard = jsonCardRef.toObject();
    mCardDB[ jsonCard["id"].toString() ] = jsonCard.toVariantMap();
  }
}

void PaintHistoryInScreen( QPainter& painter, const OverlayHistoryWindow& wnd, const QPoint& pos ) {
  int padding = 10;

  QRect rect( pos.x() + 20, pos.y(), wnd.Width(), wnd.Height() );
  rect.translate( -qMax( rect.right() - painter.device()->width() + padding, 0 ), -qMax( rect.bottom() - painter.device()->height() + padding, 0 ) ); // fit to window
  wnd.Paint( painter, rect.x(), rect.y() );
}

void Overlay::paintEvent( QPaintEvent* ) {
  QPainter painter( this );
  painter.setRenderHint( QPainter::Antialiasing );

  int overlayWidth = 200;

  if( mShowPlayerHistory == PLAYER_SELF && mPlayerHistory.count() > 0 ) {
    OverlayHistoryWindow wnd( "Cards drawn", mPlayerHistory, overlayWidth, 10, 10, 12, 12 );
    PaintHistoryInScreen( painter, wnd, mPlayerDeckRect.topRight() + QPoint( 20, 0 ) );
  } else if( mShowPlayerHistory == PLAYER_OPPONENT && mOpponentHistory.count() > 0 ) {
    OverlayHistoryWindow wnd( "Cards played by opponent", mOpponentHistory, overlayWidth, 10, 10, 12, 12 );
    PaintHistoryInScreen( painter, wnd, mOpponentDeckRect.topRight() + QPoint( 20, 0 ) );
  }
}

void Overlay::HandleGameWindowChanged( int x, int y, int w, int h ) {
  move( x, y );
  setFixedSize( w, h );

  int minWidth = h * 4 / 3;
  mPlayerDeckRect = QRect( w / 2 + 0.440 * minWidth, h * 0.510, 0.05 * minWidth, h * 0.170 );
  mOpponentDeckRect = mPlayerDeckRect.translated( -0.005 * minWidth, -0.275 * h );

  update();
}

void Overlay::Update() {
  if( Settings::Instance()->OverlayEnabled() ) {
    show();
  } else {
    hide();
  }

  update();
}

void Overlay::HandleGameStarted() {
  mCheckForHoverTimer.start( CHECK_FOR_OVERLAY_HOVER_INTERVAL_MS );
  Update();
}

void Overlay::HandleGameStopped() {
  mCheckForHoverTimer.stop();
  Update();
}

void Overlay::UpdateHistoryFor( Player player, const ::CardHistoryList& list ) {
  QMap< QString, QVariantMap > entries;

  for( const CardHistoryItem& it : list ) {
    const QString& cardId = it.cardId;

    if( cardId.isEmpty() ) {
      continue;
    }

    if( !mCardDB.contains( cardId ) ) {
      DBG( "Card %s not found", qt2cstr( cardId ) );
      continue;
    }

    if( mCardDB[ cardId ][ "type" ] == "hero" ) {
      continue;
    }

    if( it.player != player ) {
      continue;
    }

    QVariantMap& entry = entries[ cardId ];
    entry[ "count" ] = entry.value( "count", 0 ).toInt() + 1;
    entry[ "mana" ] = mCardDB[ cardId ][ "mana" ];
    entry[ "name" ] = mCardDB[ cardId ][ "name" ];
  }

  OverlayHistoryList* ref;
  if( player == PLAYER_SELF ) {
    ref = &mPlayerHistory;
  } else {
    ref = &mOpponentHistory;
  }

  *ref = entries.values();

  qSort( ref->begin(), ref->end(), []( const QVariantMap& a, const QVariantMap& b ) {
    if( a["mana"].toInt() == b["mana"].toInt() ) {
      return a["name"].toString() < b["name"].toString();
    } else {
      return a["mana"].toInt() < b["mana"].toInt();
    }
  });
}

void Overlay::HandleCardsDrawnUpdate( const ::CardHistoryList& cardsDrawn ) {
  UpdateHistoryFor( PLAYER_OPPONENT, cardsDrawn );
  UpdateHistoryFor( PLAYER_SELF, cardsDrawn );
  Update();
}

void Overlay::HandleOverlaySettingChanged( bool enabled ) {
  UNUSED_ARG( enabled );

  Update();
}
<|endoftext|>


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

#include "LibVirtDriver.h"

#include "Nebula.h"
#include <sstream>
#include <fstream>
#include <libgen.h>

int LibVirtDriver::deployment_description_vmware(
        const VirtualMachine *  vm,
        const string&           file_name) const
{
    ofstream                    file;

    int                         num;
    vector<const Attribute *>   attrs;

    string  vcpu;
    string  memory;

    int     memory_in_kb = 0;

    string  arch       = "";

    const VectorAttribute * disk;
    const VectorAttribute * context;

    string  type       = "";
    string  target     = "";
    string  bus        = "";
    string  ro         = "";
    string  source     = "";
    string  datastore  = "";
    string  driver     = "";
    string  default_driver = "";
    bool    readonly;

    const VectorAttribute * nic;

    string  mac        = "";
    string  bridge     = "";
    string  script     = "";
    string  model      = "";

    const VectorAttribute * raw;
    string data;

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

    file.open(file_name.c_str(), ios::out);

    if (file.fail() == true)
    {
        goto error_vmware_file;
    }

    // ------------------------------------------------------------------------
    // Starting XML document
    // ------------------------------------------------------------------------

    file << "<domain type='" << emulator << "'>" << endl;

    // ------------------------------------------------------------------------
    // Domain name
    // ------------------------------------------------------------------------

    file << "\t<name>one-" << vm->get_oid() << "</name>" << endl;

    // ------------------------------------------------------------------------
    // CPU
    // ------------------------------------------------------------------------

    vm->get_template_attribute("VCPU", vcpu);

    if(vcpu.empty())
    {
        get_default("VCPU", vcpu);
    }

    if (!vcpu.empty())
    {
        file << "\t<vcpu>" << vcpu << "</vcpu>" << endl;
    }

    // ------------------------------------------------------------------------
    // Memory
    // ------------------------------------------------------------------------

    vm->get_template_attribute("MEMORY",memory);

    if (memory.empty())
    {
        get_default("MEMORY",memory);
    }

    if (!memory.empty())
    {
        memory_in_kb = atoi(memory.c_str()) * 1024;

        file << "\t<memory>" << memory_in_kb << "</memory>" << endl;
    }
    else
    {
        goto error_vmware_memory;
    }

    // ------------------------------------------------------------------------
    //  OS and boot options
    // ------------------------------------------------------------------------

    num = vm->get_template_attribute("OS",attrs);

    // Get values & defaults
    if ( num > 0 )
    {
        const VectorAttribute * os;

        os = dynamic_cast<const VectorAttribute *>(attrs[0]);

        if( os != 0 )
        {
            arch = os->vector_value("ARCH");
        }
    }

    if ( arch.empty() )
    {
        get_default("OS","ARCH",arch);

        if (arch.empty())
        {
            goto error_vmware_arch;
        }
    }

    // Start writing to the file with the info we got

    file << "\t<os>" << endl;

    file << "\t\t<type arch='" << arch << "'>hvm</type>" << endl;

    file << "\t</os>" << endl;

    attrs.clear();

    // ------------------------------------------------------------------------
    // Disks
    // ------------------------------------------------------------------------

    file << "\t<devices>" << endl;

    get_default("DISK","DRIVER",default_driver);

    num = vm->get_template_attribute("DISK",attrs);

    if (num!=0)
    {
        get_default("DATASTORE", datastore);
    }

    for (int i=0; i < num ;i++)
    {
        disk = dynamic_cast<const VectorAttribute *>(attrs[i]);

        if ( disk == 0 )
        {
         continue;
        }

        type   = disk->vector_value("TYPE");
        target = disk->vector_value("TARGET");
        ro     = disk->vector_value("READONLY");
        bus    = disk->vector_value("BUS");
        source = disk->vector_value("SOURCE");
        driver = disk->vector_value("DRIVER");

        if (target.empty())
        {
            goto error_vmware_disk;
        }

        readonly = false;

        if ( !ro.empty() )
        {
            transform(ro.begin(),ro.end(),ro.begin(),(int(*)(int))toupper);

            if ( ro == "YES" )
            {
                readonly = true;
            }
        }

        if (type.empty() == false)
        {
            transform(type.begin(),type.end(),type.begin(),(int(*)(int))toupper);
        }

        if ( type == "BLOCK" )
        {
            file << "\t\t<disk type='block' device='disk'>" << endl;
            file << "\t\t\t<source dev='" << source << "'/>"  << endl;
        }
        else if ( type == "CDROM" )
        {
            file << "\t\t<disk type='file' device='cdrom'>" << endl;
            file << "\t\t\t<source file='" << source << "'/>"  << endl;
        }
        else
        {
            file << "\t\t<disk type='file' device='disk'>" << endl
                 << "\t\t\t<source file='[" <<  datastore <<"] " << vm->get_oid()
                 << "/images/disk." << i << "/disk.vmdk'/>" << endl;
        }

        file << "\t\t\t<target dev='" << target << "'";

        if (!bus.empty())
        {
            file << " bus='" << bus << "'/>" << endl;
        }
        else
        {
            file << "/>" << endl;
        }

        file << "\t\t\t<driver name='";

        if ( !driver.empty() )
        {
            file << driver << "'/>" << endl;
        }
        else
        {
            if (!default_driver.empty())
            {
                file << default_driver << "'/>" << endl;
            }
        }

        if (readonly)
        {
            file << "\t\t\t<readonly/>" << endl;
        }

        file << "\t\t</disk>" << endl;
    }

    attrs.clear();

    // ------------------------------------------------------------------------
    // Context Device
    // ------------------------------------------------------------------------

    if ( vm->get_template_attribute("CONTEXT",attrs) == 1 )
    {
        context = dynamic_cast<const VectorAttribute *>(attrs[0]);
        target  = context->vector_value("TARGET");

        if ( !target.empty() )
        {
            file << "\t\t<disk type='file' device='cdrom'>" << endl;
            file << "\t\t\t<source file='[" <<  datastore <<"] " << vm->get_oid()
                 << "/disk." << num << ".iso'/>" << endl;
            file << "\t\t\t<target dev='" << target << "'/>" << endl;
            file << "\t\t\t<readonly/>" << endl;
            file << "\t\t</disk>" << endl;
        }
        else
        {
            vm->log("VMM", Log::WARNING, "Could not find target device to"
                " attach context, will continue without it.");
        }
    }

    attrs.clear();

    // ------------------------------------------------------------------------
    // Network interfaces
    // ------------------------------------------------------------------------

    num = vm->get_template_attribute("NIC",attrs);

    for(int i=0; i<num; i++)
    {
        nic = dynamic_cast<const VectorAttribute *>(attrs[i]);

        if ( nic == 0 )
        {
            continue;
        }

        bridge = nic->vector_value("BRIDGE");
        mac    = nic->vector_value("MAC");
        target = nic->vector_value("TARGET");
        script = nic->vector_value("SCRIPT");
        model  = nic->vector_value("MODEL");

        if ( bridge.empty() )
        {
            file << "\t\t<interface type='ethernet'>" << endl;
        }
        else
        {
            file << "\t\t<interface type='bridge'>" << endl;
            file << "\t\t\t<source bridge='" << bridge << "'/>" << endl;
        }

        if( !mac.empty() )
        {
            file << "\t\t\t<mac address='" << mac << "'/>" << endl;
        }

        if( !target.empty() )
        {
            file << "\t\t\t<target dev='" << target << "'/>" << endl;
        }

        if( !script.empty() )
        {
            file << "\t\t\t<script path='" << script << "'/>" << endl;
        }

        if( !model.empty() )
        {
            file << "\t\t\t<model type='" << model << "'/>" << endl;
        }

        file << "\t\t</interface>" << endl;

    }

    attrs.clear();

    file << "\t</devices>" << endl;

    // ------------------------------------------------------------------------
    // Raw VMware attributes
    // ------------------------------------------------------------------------

    num = vm->get_template_attribute("RAW",attrs);

    for(int i=0; i<num;i++)
    {
        raw = dynamic_cast<const VectorAttribute *>(attrs[i]);

        if ( raw == 0 )
        {
            continue;
        }

        type = raw->vector_value("TYPE");

        transform(type.begin(),type.end(),type.begin(),(int(*)(int))toupper);

        if ( type == "VMWARE" )
        {
            data = raw->vector_value("DATA");
            file << "\t" << data << endl;
        }
    }

    file << "</domain>" << endl;

    file.close();

    return 0;

error_vmware_file:
    vm->log("VMM", Log::ERROR, "Could not open VMWARE deployment file.");
    return -1;

error_vmware_arch:
    vm->log("VMM", Log::ERROR, "No ARCH defined and no default provided.");
    file.close();
    return -1;

error_vmware_memory:
    vm->log("VMM", Log::ERROR, "No MEMORY defined and no default provided.");
    file.close();
    return -1;

error_vmware_disk:
    vm->log("VMM", Log::ERROR, "Wrong target value in DISK.");
    file.close();
    return -1;
}
<commit_msg>bug #649: CDROM iso images in VMware must end with iso suffix<commit_after>/* -------------------------------------------------------------------------- */
/* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org)             */
/*                                                                            */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may    */
/* not use this file except in compliance with the License. You may obtain    */
/* a copy of the License at                                                   */
/*                                                                            */
/* http://www.apache.org/licenses/LICENSE-2.0                                 */
/*                                                                            */
/* Unless required by applicable law or agreed to in writing, software        */
/* distributed under the License is distributed on an "AS IS" BASIS,          */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   */
/* See the License for the specific language governing permissions and        */
/* limitations under the License.                                             */
/* -------------------------------------------------------------------------- */

#include "LibVirtDriver.h"

#include "Nebula.h"
#include <sstream>
#include <fstream>
#include <libgen.h>

int LibVirtDriver::deployment_description_vmware(
        const VirtualMachine *  vm,
        const string&           file_name) const
{
    ofstream                    file;

    int                         num;
    vector<const Attribute *>   attrs;

    string  vcpu;
    string  memory;

    int     memory_in_kb = 0;

    string  arch       = "";

    const VectorAttribute * disk;
    const VectorAttribute * context;

    string  type       = "";
    string  target     = "";
    string  bus        = "";
    string  ro         = "";
    string  source     = "";
    string  datastore  = "";
    string  driver     = "";
    string  default_driver = "";
    bool    readonly;

    const VectorAttribute * nic;

    string  mac        = "";
    string  bridge     = "";
    string  script     = "";
    string  model      = "";

    const VectorAttribute * raw;
    string data;

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

    file.open(file_name.c_str(), ios::out);

    if (file.fail() == true)
    {
        goto error_vmware_file;
    }

    // ------------------------------------------------------------------------
    // Starting XML document
    // ------------------------------------------------------------------------

    file << "<domain type='" << emulator << "'>" << endl;

    // ------------------------------------------------------------------------
    // Domain name
    // ------------------------------------------------------------------------

    file << "\t<name>one-" << vm->get_oid() << "</name>" << endl;

    // ------------------------------------------------------------------------
    // CPU
    // ------------------------------------------------------------------------

    vm->get_template_attribute("VCPU", vcpu);

    if(vcpu.empty())
    {
        get_default("VCPU", vcpu);
    }

    if (!vcpu.empty())
    {
        file << "\t<vcpu>" << vcpu << "</vcpu>" << endl;
    }

    // ------------------------------------------------------------------------
    // Memory
    // ------------------------------------------------------------------------

    vm->get_template_attribute("MEMORY",memory);

    if (memory.empty())
    {
        get_default("MEMORY",memory);
    }

    if (!memory.empty())
    {
        memory_in_kb = atoi(memory.c_str()) * 1024;

        file << "\t<memory>" << memory_in_kb << "</memory>" << endl;
    }
    else
    {
        goto error_vmware_memory;
    }

    // ------------------------------------------------------------------------
    //  OS and boot options
    // ------------------------------------------------------------------------

    num = vm->get_template_attribute("OS",attrs);

    // Get values & defaults
    if ( num > 0 )
    {
        const VectorAttribute * os;

        os = dynamic_cast<const VectorAttribute *>(attrs[0]);

        if( os != 0 )
        {
            arch = os->vector_value("ARCH");
        }
    }

    if ( arch.empty() )
    {
        get_default("OS","ARCH",arch);

        if (arch.empty())
        {
            goto error_vmware_arch;
        }
    }

    // Start writing to the file with the info we got

    file << "\t<os>" << endl;

    file << "\t\t<type arch='" << arch << "'>hvm</type>" << endl;

    file << "\t</os>" << endl;

    attrs.clear();

    // ------------------------------------------------------------------------
    // Disks
    // ------------------------------------------------------------------------

    file << "\t<devices>" << endl;

    get_default("DISK","DRIVER",default_driver);

    num = vm->get_template_attribute("DISK",attrs);

    if (num!=0)
    {
        get_default("DATASTORE", datastore);
    }

    for (int i=0; i < num ;i++)
    {
        disk = dynamic_cast<const VectorAttribute *>(attrs[i]);

        if ( disk == 0 )
        {
         continue;
        }

        type   = disk->vector_value("TYPE");
        target = disk->vector_value("TARGET");
        ro     = disk->vector_value("READONLY");
        bus    = disk->vector_value("BUS");
        source = disk->vector_value("SOURCE");
        driver = disk->vector_value("DRIVER");

        if (target.empty())
        {
            goto error_vmware_disk;
        }

        readonly = false;

        if ( !ro.empty() )
        {
            transform(ro.begin(),ro.end(),ro.begin(),(int(*)(int))toupper);

            if ( ro == "YES" )
            {
                readonly = true;
            }
        }

        if (type.empty() == false)
        {
            transform(type.begin(),type.end(),type.begin(),(int(*)(int))toupper);
        }

        if ( type == "BLOCK" )
        {
            file << "\t\t<disk type='block' device='disk'>" << endl;
            file << "\t\t\t<source file=[" <<  datastore << "] " << vm->get_oid()
                << "/images/disk."  << i << "'/>"  << endl;
        }
        else if ( type == "CDROM" )
        {
            file << "\t\t<disk type='file' device='cdrom'>" << endl;
            file << "\t\t\t<source file=[" <<  datastore << "] " << vm->get_oid()
                << "/images/disk."  << i << ".iso'/>"  << endl;
        }
        else
        {
            file << "\t\t<disk type='file' device='disk'>" << endl
                 << "\t\t\t<source file='[" <<  datastore <<"] " << vm->get_oid()
                 << "/images/disk." << i << "/disk.vmdk'/>" << endl;
        }

        file << "\t\t\t<target dev='" << target << "'";

        if (!bus.empty())
        {
            file << " bus='" << bus << "'/>" << endl;
        }
        else
        {
            file << "/>" << endl;
        }

        file << "\t\t\t<driver name='";

        if ( !driver.empty() )
        {
            file << driver << "'/>" << endl;
        }
        else
        {
            if (!default_driver.empty())
            {
                file << default_driver << "'/>" << endl;
            }
        }

        if (readonly)
        {
            file << "\t\t\t<readonly/>" << endl;
        }

        file << "\t\t</disk>" << endl;
    }

    attrs.clear();

    // ------------------------------------------------------------------------
    // Context Device
    // ------------------------------------------------------------------------

    if ( vm->get_template_attribute("CONTEXT",attrs) == 1 )
    {
        context = dynamic_cast<const VectorAttribute *>(attrs[0]);
        target  = context->vector_value("TARGET");

        if ( !target.empty() )
        {
            file << "\t\t<disk type='file' device='cdrom'>" << endl;
            file << "\t\t\t<source file='[" <<  datastore <<"] " << vm->get_oid()
                 << "/disk." << num << ".iso'/>" << endl;
            file << "\t\t\t<target dev='" << target << "'/>" << endl;
            file << "\t\t\t<readonly/>" << endl;
            file << "\t\t</disk>" << endl;
        }
        else
        {
            vm->log("VMM", Log::WARNING, "Could not find target device to"
                " attach context, will continue without it.");
        }
    }

    attrs.clear();

    // ------------------------------------------------------------------------
    // Network interfaces
    // ------------------------------------------------------------------------

    num = vm->get_template_attribute("NIC",attrs);

    for(int i=0; i<num; i++)
    {
        nic = dynamic_cast<const VectorAttribute *>(attrs[i]);

        if ( nic == 0 )
        {
            continue;
        }

        bridge = nic->vector_value("BRIDGE");
        mac    = nic->vector_value("MAC");
        target = nic->vector_value("TARGET");
        script = nic->vector_value("SCRIPT");
        model  = nic->vector_value("MODEL");

        if ( bridge.empty() )
        {
            file << "\t\t<interface type='ethernet'>" << endl;
        }
        else
        {
            file << "\t\t<interface type='bridge'>" << endl;
            file << "\t\t\t<source bridge='" << bridge << "'/>" << endl;
        }

        if( !mac.empty() )
        {
            file << "\t\t\t<mac address='" << mac << "'/>" << endl;
        }

        if( !target.empty() )
        {
            file << "\t\t\t<target dev='" << target << "'/>" << endl;
        }

        if( !script.empty() )
        {
            file << "\t\t\t<script path='" << script << "'/>" << endl;
        }

        if( !model.empty() )
        {
            file << "\t\t\t<model type='" << model << "'/>" << endl;
        }

        file << "\t\t</interface>" << endl;

    }

    attrs.clear();

    file << "\t</devices>" << endl;

    // ------------------------------------------------------------------------
    // Raw VMware attributes
    // ------------------------------------------------------------------------

    num = vm->get_template_attribute("RAW",attrs);

    for(int i=0; i<num;i++)
    {
        raw = dynamic_cast<const VectorAttribute *>(attrs[i]);

        if ( raw == 0 )
        {
            continue;
        }

        type = raw->vector_value("TYPE");

        transform(type.begin(),type.end(),type.begin(),(int(*)(int))toupper);

        if ( type == "VMWARE" )
        {
            data = raw->vector_value("DATA");
            file << "\t" << data << endl;
        }
    }

    file << "</domain>" << endl;

    file.close();

    return 0;

error_vmware_file:
    vm->log("VMM", Log::ERROR, "Could not open VMWARE deployment file.");
    return -1;

error_vmware_arch:
    vm->log("VMM", Log::ERROR, "No ARCH defined and no default provided.");
    file.close();
    return -1;

error_vmware_memory:
    vm->log("VMM", Log::ERROR, "No MEMORY defined and no default provided.");
    file.close();
    return -1;

error_vmware_disk:
    vm->log("VMM", Log::ERROR, "Wrong target value in DISK.");
    file.close();
    return -1;
}
<|endoftext|>


<commit_before>/*
kmsc - Kurento Media Server C/C++ implementation
Copyright (C) 2012 Tikal Technologies

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

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

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

#include "MediaServerServiceHandler.h"
#include <gst/gst.h>

#define GST_CAT_DEFAULT media_server_service_handler
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define GST_DEFAULT_NAME "media_server_service_handler"

using ::kurento::MediaServerServiceHandler;
using ::kurento::MediaObject;
using ::kurento::MediaType;

MediaServerServiceHandler::MediaServerServiceHandler()
{
	GST_DEBUG_CATEGORY_INIT(GST_CAT_DEFAULT, GST_DEFAULT_NAME, 0, GST_DEFAULT_NAME);
}

MediaServerServiceHandler::~MediaServerServiceHandler()
{

}

void
MediaServerServiceHandler::ping(const MediaObject& resource, const int32_t timeout)
{

}

void
MediaServerServiceHandler::release(const MediaObject& mediaObject)
{

}

void
MediaServerServiceHandler::createMediaFactory(MediaObject& _return)
{
	GST_INFO("createMediaFactory");
}

void
MediaServerServiceHandler::createMediaPlayer(MediaObject& _return, const MediaObject& mediaFactory)
{

}

void
MediaServerServiceHandler::createMediaRecorder(MediaObject& _return, const MediaObject& mediaFactory)
{

}

void
MediaServerServiceHandler::createStream(MediaObject& _return, const MediaObject& mediaFactory)
{

}

void
MediaServerServiceHandler::createMixer(MediaObject& _return, const MediaObject& mediaFactory)
{

}

MediaType::type
MediaServerServiceHandler::getMediaType(const MediaObject& mediaElement)
{
	return MediaType::AUDIO;
}

void
MediaServerServiceHandler::connect(const MediaObject& mediaSrc, const MediaObject& mediaSink)
{

}

void
MediaServerServiceHandler::disconnect(const MediaObject& src, const MediaObject& mediaSink)
{

}

void
MediaServerServiceHandler::getConnectedSinks(std::vector<MediaObject> & _return, const MediaObject& mediaSrc)
{

}

void
MediaServerServiceHandler::getConnectedSrc(MediaObject& _return, const MediaObject& mediaSink)
{

}

void
MediaServerServiceHandler::join(const MediaObject& joinableA, const MediaObject& joinableB)
{

}

void
MediaServerServiceHandler::unjoin(const MediaObject& joinableA, const MediaObject& joinableB)
{

}

void
MediaServerServiceHandler::getMediaSrcs(std::vector<MediaObject> & _return, const MediaObject& joinable)
{

}

void
MediaServerServiceHandler::getMediaSinks(std::vector<MediaObject> & _return, const MediaObject& joinable)
{

}

void
MediaServerServiceHandler::getMediaSrcsByMediaType(std::vector<MediaObject> & _return, const MediaObject& joinable, const MediaType::type mediaType)
{

}

void
MediaServerServiceHandler::getMediaSinksByMediaType(std::vector<MediaObject> & _return, const MediaObject& joinable, const MediaType::type mediaType)
{

}

void
MediaServerServiceHandler::play(const MediaObject& mediaPlayer)
{
	GST_INFO("play");
}

void
MediaServerServiceHandler::pausePlayer(const MediaObject& mediaPlayer)
{

}

void
MediaServerServiceHandler::stopPlayer(const MediaObject& mediaPlayer)
{

}

void
MediaServerServiceHandler::record(const MediaObject& mediaRecorder)
{

}

void
MediaServerServiceHandler::pauseRecorder(const MediaObject& mediaRecorder)
{

}

void
MediaServerServiceHandler::stopRecorder(const MediaObject& mediaRecorder)
{

}

void
MediaServerServiceHandler::generateOffer(std::string& _return, const MediaObject& stream)
{
	GST_INFO("generateOffer");
	_return.assign("SessionDescriptor test from generateOffer");
}

void
MediaServerServiceHandler::processAnswer(std::string& _return, const MediaObject& stream, const std::string& anwser)
{
	GST_INFO("generateOffer");
	_return.assign("SessionDescriptor test from processAnswer");
}

void
MediaServerServiceHandler::processOffer(std::string& _return, const MediaObject& stream, const std::string& offer)
{
	GST_INFO("generateOffer");
	_return.assign("SessionDescriptor test from processOffer");
}

void
MediaServerServiceHandler::getLocalDescriptor(std::string& _return, const MediaObject& stream)
{

}

void
MediaServerServiceHandler::getRemoteDescriptor(std::string& _return, const MediaObject& stream)
{

}

void
MediaServerServiceHandler::getMixerPort(MediaObject& _return, const MediaObject& mixer)
{

}

void
MediaServerServiceHandler::getMixer(MediaObject& _return, const MediaObject& mixerPort)
{

}
<commit_msg>Add log for each method of MediaServerServiceHandler.<commit_after>/*
kmsc - Kurento Media Server C/C++ implementation
Copyright (C) 2012 Tikal Technologies

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

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

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

#include "MediaServerServiceHandler.h"
#include <gst/gst.h>

#define GST_CAT_DEFAULT media_server_service_handler
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define GST_DEFAULT_NAME "media_server_service_handler"

using ::kurento::MediaServerServiceHandler;
using ::kurento::MediaObject;
using ::kurento::MediaType;

MediaServerServiceHandler::MediaServerServiceHandler()
{
	GST_DEBUG_CATEGORY_INIT(GST_CAT_DEFAULT, GST_DEFAULT_NAME, 0, GST_DEFAULT_NAME);
}

MediaServerServiceHandler::~MediaServerServiceHandler()
{

}

void
MediaServerServiceHandler::ping(const MediaObject& resource, const int32_t timeout)
{
	GST_INFO("ping");
}

void
MediaServerServiceHandler::release(const MediaObject& mediaObject)
{
	GST_INFO("release");
}

void
MediaServerServiceHandler::createMediaFactory(MediaObject& _return)
{
	GST_INFO("createMediaFactory");
}

void
MediaServerServiceHandler::createMediaPlayer(MediaObject& _return, const MediaObject& mediaFactory)
{
	GST_INFO("createMediaPlayer");
}

void
MediaServerServiceHandler::createMediaRecorder(MediaObject& _return, const MediaObject& mediaFactory)
{
	GST_INFO("createMediaRecorder");
}

void
MediaServerServiceHandler::createStream(MediaObject& _return, const MediaObject& mediaFactory)
{
	GST_INFO("createStream");
}

void
MediaServerServiceHandler::createMixer(MediaObject& _return, const MediaObject& mediaFactory)
{
	GST_INFO("createMixer");
}

MediaType::type
MediaServerServiceHandler::getMediaType(const MediaObject& mediaElement)
{
	GST_INFO("getMediaType");
	return MediaType::AUDIO;
}

void
MediaServerServiceHandler::connect(const MediaObject& mediaSrc, const MediaObject& mediaSink)
{
	GST_INFO("connect");
}

void
MediaServerServiceHandler::disconnect(const MediaObject& src, const MediaObject& mediaSink)
{
	GST_INFO("disconnect");
}

void
MediaServerServiceHandler::getConnectedSinks(std::vector<MediaObject> & _return, const MediaObject& mediaSrc)
{
	GST_INFO("getConnectedSinks");
}

void
MediaServerServiceHandler::getConnectedSrc(MediaObject& _return, const MediaObject& mediaSink)
{
	GST_INFO("getConnectedSrc");
}

void
MediaServerServiceHandler::join(const MediaObject& joinableA, const MediaObject& joinableB)
{
	GST_INFO("join");
}

void
MediaServerServiceHandler::unjoin(const MediaObject& joinableA, const MediaObject& joinableB)
{
	GST_INFO("unjoin");
}

void
MediaServerServiceHandler::getMediaSrcs(std::vector<MediaObject> & _return, const MediaObject& joinable)
{
	GST_INFO("getMediaSrcs");
}

void
MediaServerServiceHandler::getMediaSinks(std::vector<MediaObject> & _return, const MediaObject& joinable)
{
	GST_INFO("getMediaSinks");
}

void
MediaServerServiceHandler::getMediaSrcsByMediaType(std::vector<MediaObject> & _return, const MediaObject& joinable, const MediaType::type mediaType)
{
	GST_INFO("getMediaSrcsByMediaType");
}

void
MediaServerServiceHandler::getMediaSinksByMediaType(std::vector<MediaObject> & _return, const MediaObject& joinable, const MediaType::type mediaType)
{
	GST_INFO("getMediaSinksByMediaType");
}

void
MediaServerServiceHandler::play(const MediaObject& mediaPlayer)
{
	GST_INFO("play");
}

void
MediaServerServiceHandler::pausePlayer(const MediaObject& mediaPlayer)
{
	GST_INFO("pausePlayer");
}

void
MediaServerServiceHandler::stopPlayer(const MediaObject& mediaPlayer)
{
	GST_INFO("stopPlayer");
}

void
MediaServerServiceHandler::record(const MediaObject& mediaRecorder)
{
	GST_INFO("record");
}

void
MediaServerServiceHandler::pauseRecorder(const MediaObject& mediaRecorder)
{
	GST_INFO("pauseRecorder");
}

void
MediaServerServiceHandler::stopRecorder(const MediaObject& mediaRecorder)
{
	GST_INFO("stopRecorder");
}

void
MediaServerServiceHandler::generateOffer(std::string& _return, const MediaObject& stream)
{
	GST_INFO("generateOffer");
	_return.assign("SessionDescriptor test from generateOffer");
}

void
MediaServerServiceHandler::processAnswer(std::string& _return, const MediaObject& stream, const std::string& anwser)
{
	GST_INFO("generateOffer");
	_return.assign("SessionDescriptor test from processAnswer");
}

void
MediaServerServiceHandler::processOffer(std::string& _return, const MediaObject& stream, const std::string& offer)
{
	GST_INFO("generateOffer");
	_return.assign("SessionDescriptor test from processOffer");
}

void
MediaServerServiceHandler::getLocalDescriptor(std::string& _return, const MediaObject& stream)
{
	GST_INFO("getLocalDescriptor");
}

void
MediaServerServiceHandler::getRemoteDescriptor(std::string& _return, const MediaObject& stream)
{
	GST_INFO("getRemoteDescriptor");
}

void
MediaServerServiceHandler::getMixerPort(MediaObject& _return, const MediaObject& mixer)
{
	GST_INFO("getMixerPort");
}

void
MediaServerServiceHandler::getMixer(MediaObject& _return, const MediaObject& mixerPort)
{
	GST_INFO("getMixer");
}
<|endoftext|>


<commit_before>/*-
 * Copyright (c) 2010 Benjamin Close <Benjamin.Close@clearchain.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
#include <assert.h>
#include "VideoDecoder.h"

namespace wcl
{

VideoDecoder::VideoDecoder(const std::string &path , const bool iautofpslimit, const bool autoplay)
    throw( const std::string &):
	isvalid(false),playedFrames(0),autoFPSLimit(iautofpslimit), paused(!autoplay)
{
    VideoDecoder::libraryInit();

    if( av_open_input_file( &this->formatContext, path.c_str(), NULL, 0, NULL) != 0){
	throw std::string("Unable To Open Video File");
    }

    if(av_find_stream_info(this->formatContext) < 0 )
	throw std::string("No Video Stream Information Exists");

#ifdef DEBUG
    dump_format(this->formatContext, 0, 0, false);
#endif

    if( (this->index = this->findVideoStream()) == -1 )
	throw std::string("No Video Streams Exist");

    // Store the codec context
    this->codecContext = this->formatContext->streams[this->index]->codec;

    this->findDecoder(this->codecContext->codec_id);

    this->allocateConversionBuffer( this->codecContext->width,
				    this->codecContext->height );

    this->width = this->codecContext->width;
    this->height = this->codecContext->height;

    this->startTime = av_gettime();

	if (paused)
		this->pauseTime = this->startTime;
}

VideoDecoder::VideoDecoder(const unsigned iwidth, const unsigned iheight,
			   const CodecID codec, const bool iautofpslimit, const bool autoplay):
    formatContext(NULL),
    isvalid(false),width(iwidth),height(iheight),
    index(-1),playedFrames(0),autoFPSLimit(iautofpslimit), paused(!autoplay)
{
    VideoDecoder::libraryInit();

    this->codecContext = avcodec_alloc_context();
    this->codecContext->width = iwidth;
    this->codecContext->height = iheight;

    /**
     * XXX This is not right. How can we guarentee that the input format is
     * YUV422 - this should be able to be either specified in the constructor
     * else av* should be able to work it out. For now we hard code it
     * - benjsc 20100719
     */
    this->codecContext->pix_fmt= PIX_FMT_YUV422P;

    this->findDecoder(codec);
    this->allocateConversionBuffer( this->width, this->height );

    this->startTime = av_gettime();

	if (paused)
		this->pauseTime = this->startTime;
}

int VideoDecoder::findVideoStream(const int nth)
{
    unsigned i;
    int vstreams;

    // In order to find a stream the formatContext must already be initialised
    // this currently only happens for file loads, not when the user specifies
    // the input format
    assert( this->formatContext != NULL );

    for(i = 0, vstreams=0; i < this->formatContext->nb_streams; i++ ){
	if( this->formatContext->streams[i]->codec->codec_type ==CODEC_TYPE_VIDEO){
	    if( vstreams == nth )
		return i;
	    else {
		vstreams++;
	    }
	}
    }

    return -1;
}

void VideoDecoder::findDecoder(const enum CodecID id)
    throw (const std::string &)
{
    AVCodec *codec = avcodec_find_decoder(id);
    if( codec == NULL )
	throw std::string("Decoding Codec not found");

#if 0
    // Handle partial frames, not sure if this is useful
    if(codec->capabilities & CODEC_CAP_TRUNCATED)
	this->codecContext->flags |=CODEC_FLAG_TRUNCATED;
#endif

    if(avcodec_open(this->codecContext, codec)<0)
	throw std::string("Unable to open decoding Codec");

    // Hack to correct wrong frame rates that seem to be generated by some
    // codecs
    if(this->codecContext->time_base.num>1000 && this->codecContext->time_base.den==1)
	this->codecContext->time_base.den=1000;

}

VideoDecoder::~VideoDecoder()
{
    this->destroyConversionBuffer();
    avcodec_close(this->codecContext);

    if( this->formatContext ){
	av_close_input_file(this->formatContext);
    }
    else
	av_free(this->codecContext);
}

void VideoDecoder::nextFrame(const unsigned char *ibuffer, const unsigned buffersize)
{
    avcodec_decode_video(this->codecContext, this->someFrame, &this->isvalid,
			 (uint8_t *)ibuffer, buffersize);

}

const unsigned char *VideoDecoder::getFrame()
{
    // FormatContext is only defined if we are reading from a file. In that
    // case, next frame will not be called hence we must read from the file
    // We also rate limit based on the internal playback rate of the file
    if( this->formatContext ){
	AVPacket packet;
	bool found=false;

	int64_t neededFrame=0;;

	if (paused)
		return (unsigned char *)this->buffer;

	// Check to see if we are being called faster than the movie should be
	// played back if we are and we are limiting the frames, simply return
	// the same buffer;
	if( this->autoFPSLimit ){
	    neededFrame= (int)(((av_gettime()-this->startTime)/1000000.0)*this->getFPS());
	    if(neededFrame <= this->playedFrames )
		return (unsigned char *)this->buffer;
	}

	// Keep processing frames until we find the next frame we are
	// after. This may be more than one frame if autofps limiting is enabled
	while(av_read_frame(this->formatContext, &packet) >= 0 && !found){
		if( packet.stream_index==this->index){
			avcodec_decode_video(this->codecContext, this->someFrame,
					&this->isvalid, packet.data, packet.size);
			if( this->isvalid ){
				this->playedFrames++;
				sws_scale(this->imageConvertContext,
						this->someFrame->data, this->someFrame->linesize,
						0, this->height,
						this->RGBFrame->data, this->RGBFrame->linesize);

				// If we are rate limiting, keep decoding frames until
				// we catch up to where we should be
				if(this->autoFPSLimit ){
					if(this->playedFrames >= neededFrame )
						found=true;
				}
				// Else we simply return the next frame
				else {
					found=true;
				}
			}
		}
		av_free_packet(&packet);
	}

	// No more frames in the file
	if(!found)
	    return NULL;
    } else {
	//
	// Stream decoding
	//
	if( this->isvalid ){
		this->playedFrames++;
		sws_scale(this->imageConvertContext,
			  this->someFrame->data, this->someFrame->linesize,
			  0, this->height,
			  this->RGBFrame->data, this->RGBFrame->linesize);
	}
    }
    return (unsigned char *)this->buffer;
}

void VideoDecoder::libraryInit()
{
    static int init;
    if(!init){
	av_register_all();
	init=1;
    }
}

void VideoDecoder::allocateConversionBuffer(const unsigned width, const unsigned height)
{
    this->someFrame = avcodec_alloc_frame();
    this->RGBFrame = avcodec_alloc_frame();
    int size = avpicture_get_size(PIX_FMT_RGB24, width, height);
    this->buffer = new uint8_t[size];
    avpicture_fill((AVPicture *)this->RGBFrame, this->buffer, PIX_FMT_RGB24, width, height);
    this->imageConvertContext =  sws_getContext( width, height,
						 this->codecContext->pix_fmt,
						 width, height,
						 PIX_FMT_RGB24, SWS_BICUBIC,
						 NULL, NULL, NULL );
}

void VideoDecoder::destroyConversionBuffer()
{
    delete [] this->buffer;

    av_free(this->RGBFrame);
    av_free(this->someFrame);
    sws_freeContext( this->imageConvertContext);
}

unsigned VideoDecoder::getWidth() const
{
    return this->width;
}

unsigned VideoDecoder::getHeight() const
{
    return this->height;
}

float VideoDecoder::getFPS() const
{
    if( this->formatContext &&  this->autoFPSLimit ){
	return(1.0 *
	       this->formatContext->streams[this->index]->r_frame_rate.num /
	       (float) this->formatContext->streams[this->index]->r_frame_rate.den);
    } else {
	float t = (av_gettime()-this->startTime)/1000000.0;
	return (t>1? this->playedFrames / t : 0);
    }
}

int64_t VideoDecoder::getCurrentFrame() const
{
    return this->playedFrames;
}

int64_t VideoDecoder::getLastFrame() const
{
    if( this->formatContext )
	return this->formatContext->streams[this->index]->nb_frames;

    return -1;
}

void VideoDecoder::rewind()
{
	if( this->formatContext )
	{
		av_seek_frame(this->formatContext, this->index,0, AVSEEK_FLAG_BACKWARD);
		avcodec_flush_buffers(this->codecContext);
		playedFrames = 0;
		startTime = av_gettime();
	}
}

void VideoDecoder::setPaused(bool p)
{
	if (p && !this->paused)
	{
		this->pauseTime = av_gettime();
		this->paused = true;
	}
	else if (!p && this->paused)
	{
		int64_t diff = av_gettime() - pauseTime;
		startTime += diff;
		paused = false;
	}
}

bool VideoDecoder::atEnd() const
{
    if( this->formatContext && this->getCurrentFrame() >= this->getLastFrame())
		return true;
    return false;
}

};

<commit_msg>Stopped VideoDecoder from leaking memory like a seive.<commit_after>/*-
 * Copyright (c) 2010 Benjamin Close <Benjamin.Close@clearchain.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
#include <assert.h>
#include "VideoDecoder.h"

namespace wcl
{

VideoDecoder::VideoDecoder(const std::string &path , const bool iautofpslimit, const bool autoplay)
    throw( const std::string &):
	isvalid(false),playedFrames(0),autoFPSLimit(iautofpslimit), paused(!autoplay)
{
    VideoDecoder::libraryInit();

    if( av_open_input_file( &this->formatContext, path.c_str(), NULL, 0, NULL) != 0){
	throw std::string("Unable To Open Video File");
    }

    if(av_find_stream_info(this->formatContext) < 0 )
	throw std::string("No Video Stream Information Exists");

#ifdef DEBUG
    dump_format(this->formatContext, 0, 0, false);
#endif

    if( (this->index = this->findVideoStream()) == -1 )
	throw std::string("No Video Streams Exist");

    // Store the codec context
    this->codecContext = this->formatContext->streams[this->index]->codec;

    this->findDecoder(this->codecContext->codec_id);

    this->allocateConversionBuffer( this->codecContext->width,
				    this->codecContext->height );

    this->width = this->codecContext->width;
    this->height = this->codecContext->height;

    this->startTime = av_gettime();

	if (paused)
		this->pauseTime = this->startTime;
}

VideoDecoder::VideoDecoder(const unsigned iwidth, const unsigned iheight,
			   const CodecID codec, const bool iautofpslimit, const bool autoplay):
    formatContext(NULL),
    isvalid(false),width(iwidth),height(iheight),
    index(-1),playedFrames(0),autoFPSLimit(iautofpslimit), paused(!autoplay)
{
    VideoDecoder::libraryInit();

    this->codecContext = avcodec_alloc_context();
    this->codecContext->width = iwidth;
    this->codecContext->height = iheight;

    /**
     * XXX This is not right. How can we guarentee that the input format is
     * YUV422 - this should be able to be either specified in the constructor
     * else av* should be able to work it out. For now we hard code it
     * - benjsc 20100719
     */
    this->codecContext->pix_fmt= PIX_FMT_YUV422P;

    this->findDecoder(codec);
    this->allocateConversionBuffer( this->width, this->height );

    this->startTime = av_gettime();

	if (paused)
		this->pauseTime = this->startTime;
}

int VideoDecoder::findVideoStream(const int nth)
{
    unsigned i;
    int vstreams;

    // In order to find a stream the formatContext must already be initialised
    // this currently only happens for file loads, not when the user specifies
    // the input format
    assert( this->formatContext != NULL );

    for(i = 0, vstreams=0; i < this->formatContext->nb_streams; i++ ){
	if( this->formatContext->streams[i]->codec->codec_type ==CODEC_TYPE_VIDEO){
	    if( vstreams == nth )
		return i;
	    else {
		vstreams++;
	    }
	}
    }

    return -1;
}

void VideoDecoder::findDecoder(const enum CodecID id)
    throw (const std::string &)
{
    AVCodec *codec = avcodec_find_decoder(id);
    if( codec == NULL )
	throw std::string("Decoding Codec not found");

#if 0
    // Handle partial frames, not sure if this is useful
    if(codec->capabilities & CODEC_CAP_TRUNCATED)
	this->codecContext->flags |=CODEC_FLAG_TRUNCATED;
#endif

    if(avcodec_open(this->codecContext, codec)<0)
	throw std::string("Unable to open decoding Codec");

    // Hack to correct wrong frame rates that seem to be generated by some
    // codecs
    if(this->codecContext->time_base.num>1000 && this->codecContext->time_base.den==1)
	this->codecContext->time_base.den=1000;

}

VideoDecoder::~VideoDecoder()
{
    this->destroyConversionBuffer();
    avcodec_close(this->codecContext);

    if( this->formatContext ){
	av_close_input_file(this->formatContext);
    }
    else
	av_free(this->codecContext);
}

void VideoDecoder::nextFrame(const unsigned char *ibuffer, const unsigned buffersize)
{
    avcodec_decode_video(this->codecContext, this->someFrame, &this->isvalid,
			 (uint8_t *)ibuffer, buffersize);

}

const unsigned char *VideoDecoder::getFrame()
{
    // FormatContext is only defined if we are reading from a file. In that
    // case, next frame will not be called hence we must read from the file
    // We also rate limit based on the internal playback rate of the file
    if( this->formatContext ){
	AVPacket packet;
	bool found=false;

	int64_t neededFrame=0;;

	if (paused)
		return (unsigned char *)this->buffer;

	// Check to see if we are being called faster than the movie should be
	// played back if we are and we are limiting the frames, simply return
	// the same buffer;
	if( this->autoFPSLimit ){
	    neededFrame= (int)(((av_gettime()-this->startTime)/1000000.0)*this->getFPS());
	    if(neededFrame <= this->playedFrames )
		return (unsigned char *)this->buffer;
	}

	// Keep processing frames until we find the next frame we are
	// after. This may be more than one frame if autofps limiting is enabled
	while(!found && av_read_frame(this->formatContext, &packet) >= 0){
		if( packet.stream_index==this->index){
			avcodec_decode_video(this->codecContext, this->someFrame,
					&this->isvalid, packet.data, packet.size);
			if( this->isvalid ){
				this->playedFrames++;
				sws_scale(this->imageConvertContext,
						this->someFrame->data, this->someFrame->linesize,
						0, this->height,
						this->RGBFrame->data, this->RGBFrame->linesize);

				// If we are rate limiting, keep decoding frames until
				// we catch up to where we should be
				if(this->autoFPSLimit ){
					if(this->playedFrames >= neededFrame )
						found=true;
				}
				// Else we simply return the next frame
				else {
					found=true;
				}
			}
		}
		av_free_packet(&packet);
	}

	// No more frames in the file
	if(!found)
	    return NULL;
    } else {
	//
	// Stream decoding
	//
	if( this->isvalid ){
		this->playedFrames++;
		sws_scale(this->imageConvertContext,
			  this->someFrame->data, this->someFrame->linesize,
			  0, this->height,
			  this->RGBFrame->data, this->RGBFrame->linesize);
	}
    }
    return (unsigned char *)this->buffer;
}

void VideoDecoder::libraryInit()
{
    static int init;
    if(!init){
	av_register_all();
	init=1;
    }
}

void VideoDecoder::allocateConversionBuffer(const unsigned width, const unsigned height)
{
    this->someFrame = avcodec_alloc_frame();
    this->RGBFrame = avcodec_alloc_frame();
    int size = avpicture_get_size(PIX_FMT_RGB24, width, height);
    this->buffer = new uint8_t[size];
    avpicture_fill((AVPicture *)this->RGBFrame, this->buffer, PIX_FMT_RGB24, width, height);
    this->imageConvertContext =  sws_getContext( width, height,
						 this->codecContext->pix_fmt,
						 width, height,
						 PIX_FMT_RGB24, SWS_BICUBIC,
						 NULL, NULL, NULL );
}

void VideoDecoder::destroyConversionBuffer()
{
    delete [] this->buffer;

    av_free(this->RGBFrame);
    av_free(this->someFrame);
    sws_freeContext( this->imageConvertContext);
}

unsigned VideoDecoder::getWidth() const
{
    return this->width;
}

unsigned VideoDecoder::getHeight() const
{
    return this->height;
}

float VideoDecoder::getFPS() const
{
    if( this->formatContext &&  this->autoFPSLimit ){
	return(1.0 *
	       this->formatContext->streams[this->index]->r_frame_rate.num /
	       (float) this->formatContext->streams[this->index]->r_frame_rate.den);
    } else {
	float t = (av_gettime()-this->startTime)/1000000.0;
	return (t>1? this->playedFrames / t : 0);
    }
}

int64_t VideoDecoder::getCurrentFrame() const
{
    return this->playedFrames;
}

int64_t VideoDecoder::getLastFrame() const
{
    if( this->formatContext )
	return this->formatContext->streams[this->index]->nb_frames;

    return -1;
}

void VideoDecoder::rewind()
{
	if( this->formatContext )
	{
		av_seek_frame(this->formatContext, this->index,0, AVSEEK_FLAG_BACKWARD);
		avcodec_flush_buffers(this->codecContext);
		playedFrames = 0;
		startTime = av_gettime();
	}
}

void VideoDecoder::setPaused(bool p)
{
	if (p && !this->paused)
	{
		this->pauseTime = av_gettime();
		this->paused = true;
	}
	else if (!p && this->paused)
	{
		int64_t diff = av_gettime() - pauseTime;
		startTime += diff;
		paused = false;
	}
}

bool VideoDecoder::atEnd() const
{
    if( this->formatContext && this->getCurrentFrame() >= this->getLastFrame())
		return true;
    return false;
}

};

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2009, 2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

/**
 ** \file object/UVar.cc
 ** \brief Creation of the URBI object UVar.
 */

# include <kernel/userver.hh>
# include <kernel/uvalue-cast.hh>

# include <object/symbols.hh>
# include <object/urbi-exception.hh>
# include <object/uvar.hh>

# include <urbi/object/global.hh>
# include <urbi/object/list.hh>
# include <urbi/object/lobby.hh>

# include <runner/runner.hh>
# include <runner/interpreter.hh>

namespace urbi
{
  namespace object
  {
    static inline void
    show_exception_message(runner::Runner& r, rObject self, const char* m1,
                           const char* m2)
    {
      r.lobby_get()->call(SYMBOL(send),
                          new object::String(
                            m1
                            + libport::format(
                              "%s.%s",
                              self->slot_get(SYMBOL(ownerName))->as<String>()->value_get(),
                              self->slot_get(SYMBOL(initialName))->as<String>()->value_get()
                              )
                            + m2),
                          new object::String("error"));
    }

    static inline void callNotify(runner::Runner& r, rObject self,
                                  libport::Symbol notifyList)
    {
      rList l =
        self->slot_get(notifyList)->slot_get(SYMBOL(values))->as<List>();
      objects_type args;
      args.push_back(self);
      List::value_type& callbacks = l->value_get();
      for (List::value_type::iterator i = callbacks.begin();
           i != callbacks.end(); )
      {
        bool failed = true;
        try
        {
          r.apply(*i, SYMBOL(NOTIFY), args);
          failed = false;
        }
        catch(UrbiException& e)
        {
          show_exception_message(r, self,
                                 "!!! Exception caught while processing notify on ", " :");
          runner::Interpreter& in = dynamic_cast<runner::Interpreter&>(r);
          in.show_exception(e);

        }
        catch(sched::exception& e)
        {
          throw;
        }
        catch(...)
        {
          show_exception_message(r, self,
                                 "!!! Unknown exception called while processing notify on ", "");
        }
        if (failed && self->slot_get(SYMBOL(eraseThrowingCallbacks))->as_bool())
        {
          // 'value' is just a cache, not the actual storage location.
          self->slot_get(notifyList)->call(SYMBOL(remove), *i);
          i = callbacks.erase(i);
        }
        else
          ++i;
      }
    }

    static rObject
    update_bounce(objects_type args)
    {
      //called with self slotname slotval
      check_arg_count(args.size() - 1, 2);
      libport::intrusive_ptr<UVar> rvar =
        args.front()
        ->slot_get(libport::Symbol(args[1]->as<String>()->value_get())).value()
        .unsafe_cast<UVar>();
      if (!rvar)
        RAISE("UVar updatehook called on non-uvar slot");
      rvar->update_(args[2]);
      return void_class;
    }

    UVar::UVar()
      : Primitive( boost::bind(&UVar::accessor, this))
      , looping_(false)
      , inAccess_(false)
      , waiterCount_(0)
    {
      protos_set(new List);
      proto_add(proto ? rPrimitive(proto) : Primitive::proto);
      slot_set(SYMBOL(waiterTag), new Tag());
    }

    UVar::UVar(libport::intrusive_ptr<UVar>)
      : Primitive( boost::bind(&UVar::accessor, this))
      , looping_(false)
      , inAccess_(false)
      , waiterCount_(0)
    {
      protos_set(new List);
      proto_add(proto ? rPrimitive(proto) : Primitive::proto);
      slot_set(SYMBOL(waiterTag), new Tag());
    }

    void
    UVar::loopCheck()
    {
      runner::Runner& r = ::kernel::urbiserver->getCurrentRunner();
      // Prepare a call to System.period.  Keep its computation in the
      // loop, so that we can change it at run time.
      CAPTURE_GLOBAL(System);
      objects_type args;
      args << System;

      // Loop if we have both notifychange and notifyaccess callbacs.
      // Listeners on the changed event counts as notifychange
      if (!looping_
          &&
          (!slot_get(SYMBOL(change))->call(SYMBOL(empty))->as_bool()
           || slot_get(SYMBOL(changed))->call(SYMBOL(hasSubscribers))->as_bool()
           )
          && !slot_get(SYMBOL(access))->call(SYMBOL(empty))->as_bool())
      {
        looping_ = true;
        while (true)
        {
          accessor();
          rObject period = args[0]->call_with_this(SYMBOL(period), args);
          r.yield_until(libport::utime() +
                        libport::utime_t(period->as<Float>()->value_get()
                                         * 1000000.0));
        }
      }
    }

    void
    UVar::checkBypassCopy()
    {
      // If there are blocked reads, call extract to force caching of the
      // temporary value, and unblock them.
      if (waiterCount_)
      {
        rUValue val = slot_get(slot_get(SYMBOL(owned))->as_bool()
                               ? SYMBOL(valsensor)
                               : SYMBOL(val))
                      ->as<UValue>();
        if (val)
          val->extract();
        slot_get(SYMBOL(waiterTag))->call(SYMBOL(stop));
      }
    }

    rObject
    UVar::update_(rObject val)
    {
      runner::Runner& r = ::kernel::urbiserver->getCurrentRunner();
      slot_update(SYMBOL(val), val);
      if (slot_get(SYMBOL(owned))->as_bool())
        callNotify(r, rObject(this), SYMBOL(changeOwned));
      else
      {
        checkBypassCopy();
        std::set<void*>::iterator i = inChange_.find(&r);
        if (i == inChange_.end())
        {
          // callNotify does not throw, this is safe.
          i = inChange_.insert(&r).first;
          callNotify(r, rObject(this), SYMBOL(change));
          inChange_.erase(i);
        }
        slot_get(SYMBOL(changed))->call("emit");
      }
      return val;
    }

    rObject
    UVar::accessor()
    {
      return getter(false);
    }

    rObject
    UVar::getter(bool fromCXX)
    {
      runner::Runner& r = ::kernel::urbiserver->getCurrentRunner();

      if (this == proto.get())
        return this;
      if (!inAccess_)
      {
        inAccess_ = true;
        callNotify(r, rObject(this), SYMBOL(access));
        inAccess_ = false;
      }
      rObject res = slot_get(slot_get(SYMBOL(owned))->as_bool()
                             ? SYMBOL(valsensor)
                             : SYMBOL(val));
      if (!fromCXX)
      {
        if (object::rUValue bv = res->as<object::UValue>())
        {
          if (bv->bypassMode_ && bv->extract() == nil_class)
          {
            // This is a read on a bypass-mode UVar, from outside any
            // notifychange: the value is not available.
            // So we mark that we wait by inc-ing waiterCount, and wait
            // on waiterTag until we timeout, or someone writes to the UVar
            // and unlock us.

            // free the shared ptrs
            res.reset();
            bv.reset();
            ++waiterCount_;
            slot_get(SYMBOL(waiterTag))->call(SYMBOL(waitUntilStopped),
                                              new Float(0.5));
            --waiterCount_;
            // The val slot likely changed, fetch it again.
            res = slot_get(slot_get(SYMBOL(owned))->as_bool()
                           ? SYMBOL(valsensor)
                           : SYMBOL(val));
            if (object::rUValue bv = res->as<object::UValue>())
              return bv->extract();
            else
              return res;
          }
          return bv->extract();
        }
      }
      return res;
    }

    rObject
    UVar::writeOwned(rObject newval)
    {
      runner::Runner& r = ::kernel::urbiserver->getCurrentRunner();
      slot_update(SYMBOL(valsensor), newval);
      checkBypassCopy();
      callNotify(r, rObject(this), SYMBOL(change));
      slot_get(SYMBOL(changed))->call("emit");
      return newval;
    }

    void
    UVar::initialize(CxxObject::Binder<UVar>& bind)
    {
      bind(SYMBOL(writeOwned), &UVar::writeOwned);
      bind(SYMBOL(update_), &UVar::update_);
      bind(SYMBOL(loopCheck), &UVar::loopCheck);
      bind(SYMBOL(accessor), &UVar::accessor);
      proto->slot_set(SYMBOL(update_bounce), new Primitive(&update_bounce));
    }

    URBI_CXX_OBJECT_REGISTER(UVar)
      : Primitive( boost::bind(&UVar::accessor, this))
      , looping_(false)
      , inAccess_(false)
    {}

    UValue::UValue()
      : bypassMode_(false)
    {
      protos_set(new List);
      proto_add(proto ? rObject(proto) : CxxObject::proto);
    }

    UValue::UValue(libport::intrusive_ptr<UValue>)
      : bypassMode_(false)
    {
      protos_set(new List);
      proto_add(proto ? rObject(proto) : CxxObject::proto);
    }

    UValue::UValue(const urbi::UValue& v, bool bypass)
      : bypassMode_(false)
    {
      protos_set(new List);
      proto_add(proto ? rObject(proto) : CxxObject::proto);
      put(v, bypass);
    }

    UValue::~UValue()
    {}

    rObject
    UValue::extract()
    {
      if (cache_)
        return cache_;
      if (value_.type == urbi::DATA_VOID)
        return nil_class;
      if (!cache_)
        cache_ = object_cast(value_);
      return cache_;
    }

    std::string
    UValue::extractAsToplevelPrintable()
    {
      if (value_.type == urbi::DATA_VOID && cache_)
      { // Someone used put, cache_ is more recent
        return cache_->call("asToplevelPrintable")->as<String>()->value_get();
      }
      std::stringstream s;
      value_.print(s);
      return s.str();
    }

    const urbi::UValue&
    UValue::value_get()
    {
      static urbi::UValue dummy;
      if (value_.type != urbi::DATA_VOID)
        return value_;
      if (!cache_ || cache_ == nil_class)
        return dummy;
      value_ = ::uvalue_cast(cache_);
      alocated_ = true;
      return value_;
    }

    void
    UValue::invalidate()
    {
      if (!alocated_)
        value_ = urbi::UValue();
    }

    void
    UValue::put(const urbi::UValue& v,  bool bypass)
    {
      bypassMode_ = bypass;
      alocated_ = !bypass;
      value_.set(v, !bypass);
      cache_ = 0;
    }

    void
    UValue::put(rObject r)
    {
      value_ = urbi::UValue();
      cache_ = r;
    }

    void
    UValue::initialize(CxxObject::Binder<UValue>& bind)
    {
      bind(SYMBOL(extract), &UValue::extract);
      bind(SYMBOL(extractAsToplevelPrintable),
           &UValue::extractAsToplevelPrintable);
      bind(SYMBOL(invalidate), &UValue::invalidate);
      bind(SYMBOL(put), (void (UValue::*)(rObject))&UValue::put);
    }

    URBI_CXX_OBJECT_REGISTER(UValue)
    {}
  }
}
<commit_msg>UObject: do not store object::UValue for floating type, rangemin/max conflict.<commit_after>/*
 * Copyright (C) 2009, 2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

/**
 ** \file object/UVar.cc
 ** \brief Creation of the URBI object UVar.
 */

# include <kernel/userver.hh>
# include <kernel/uvalue-cast.hh>

# include <object/symbols.hh>
# include <object/urbi-exception.hh>
# include <object/uvar.hh>

# include <urbi/object/global.hh>
# include <urbi/object/list.hh>
# include <urbi/object/lobby.hh>

# include <runner/runner.hh>
# include <runner/interpreter.hh>

namespace urbi
{
  namespace object
  {
    static inline void
    show_exception_message(runner::Runner& r, rObject self, const char* m1,
                           const char* m2)
    {
      r.lobby_get()->call(SYMBOL(send),
                          new object::String(
                            m1
                            + libport::format(
                              "%s.%s",
                              self->slot_get(SYMBOL(ownerName))->as<String>()->value_get(),
                              self->slot_get(SYMBOL(initialName))->as<String>()->value_get()
                              )
                            + m2),
                          new object::String("error"));
    }

    static inline void callNotify(runner::Runner& r, rObject self,
                                  libport::Symbol notifyList)
    {
      rList l =
        self->slot_get(notifyList)->slot_get(SYMBOL(values))->as<List>();
      objects_type args;
      args.push_back(self);
      List::value_type& callbacks = l->value_get();
      for (List::value_type::iterator i = callbacks.begin();
           i != callbacks.end(); )
      {
        bool failed = true;
        try
        {
          r.apply(*i, SYMBOL(NOTIFY), args);
          failed = false;
        }
        catch(UrbiException& e)
        {
          show_exception_message(r, self,
                                 "!!! Exception caught while processing notify on ", " :");
          runner::Interpreter& in = dynamic_cast<runner::Interpreter&>(r);
          in.show_exception(e);

        }
        catch(sched::exception& e)
        {
          throw;
        }
        catch(...)
        {
          show_exception_message(r, self,
                                 "!!! Unknown exception called while processing notify on ", "");
        }
        if (failed && self->slot_get(SYMBOL(eraseThrowingCallbacks))->as_bool())
        {
          // 'value' is just a cache, not the actual storage location.
          self->slot_get(notifyList)->call(SYMBOL(remove), *i);
          i = callbacks.erase(i);
        }
        else
          ++i;
      }
    }

    static rObject
    update_bounce(objects_type args)
    {
      //called with self slotname slotval
      check_arg_count(args.size() - 1, 2);
      libport::intrusive_ptr<UVar> rvar =
        args.front()
        ->slot_get(libport::Symbol(args[1]->as<String>()->value_get())).value()
        .unsafe_cast<UVar>();
      if (!rvar)
        RAISE("UVar updatehook called on non-uvar slot");
      rvar->update_(args[2]);
      return void_class;
    }

    UVar::UVar()
      : Primitive( boost::bind(&UVar::accessor, this))
      , looping_(false)
      , inAccess_(false)
      , waiterCount_(0)
    {
      protos_set(new List);
      proto_add(proto ? rPrimitive(proto) : Primitive::proto);
      slot_set(SYMBOL(waiterTag), new Tag());
    }

    UVar::UVar(libport::intrusive_ptr<UVar>)
      : Primitive( boost::bind(&UVar::accessor, this))
      , looping_(false)
      , inAccess_(false)
      , waiterCount_(0)
    {
      protos_set(new List);
      proto_add(proto ? rPrimitive(proto) : Primitive::proto);
      slot_set(SYMBOL(waiterTag), new Tag());
    }

    void
    UVar::loopCheck()
    {
      runner::Runner& r = ::kernel::urbiserver->getCurrentRunner();
      // Prepare a call to System.period.  Keep its computation in the
      // loop, so that we can change it at run time.
      CAPTURE_GLOBAL(System);
      objects_type args;
      args << System;

      // Loop if we have both notifychange and notifyaccess callbacs.
      // Listeners on the changed event counts as notifychange
      if (!looping_
          &&
          (!slot_get(SYMBOL(change))->call(SYMBOL(empty))->as_bool()
           || slot_get(SYMBOL(changed))->call(SYMBOL(hasSubscribers))->as_bool()
           )
          && !slot_get(SYMBOL(access))->call(SYMBOL(empty))->as_bool())
      {
        looping_ = true;
        while (true)
        {
          accessor();
          rObject period = args[0]->call_with_this(SYMBOL(period), args);
          r.yield_until(libport::utime() +
                        libport::utime_t(period->as<Float>()->value_get()
                                         * 1000000.0));
        }
      }
    }

    void
    UVar::checkBypassCopy()
    {
      // If there are blocked reads, call extract to force caching of the
      // temporary value, and unblock them.
      if (waiterCount_)
      {
        rUValue val = slot_get(slot_get(SYMBOL(owned))->as_bool()
                               ? SYMBOL(valsensor)
                               : SYMBOL(val))
                      ->as<UValue>();
        if (val)
          val->extract();
        slot_get(SYMBOL(waiterTag))->call(SYMBOL(stop));
      }
    }

    rObject
    UVar::update_(rObject val)
    {
      // Do not bother with object::UValue for numeric types.
      if (rUValue uval = val->as<object::UValue>())
       if (uval->value_get().type == urbi::DATA_DOUBLE)
         val = uval->extract();
      runner::Runner& r = ::kernel::urbiserver->getCurrentRunner();
      slot_update(SYMBOL(val), val);
      if (slot_get(SYMBOL(owned))->as_bool())
        callNotify(r, rObject(this), SYMBOL(changeOwned));
      else
      {
        checkBypassCopy();
        std::set<void*>::iterator i = inChange_.find(&r);
        if (i == inChange_.end())
        {
          // callNotify does not throw, this is safe.
          i = inChange_.insert(&r).first;
          callNotify(r, rObject(this), SYMBOL(change));
          inChange_.erase(i);
        }
        slot_get(SYMBOL(changed))->call("emit");
      }
      return val;
    }

    rObject
    UVar::accessor()
    {
      return getter(false);
    }

    rObject
    UVar::getter(bool fromCXX)
    {
      runner::Runner& r = ::kernel::urbiserver->getCurrentRunner();

      if (this == proto.get())
        return this;
      if (!inAccess_)
      {
        inAccess_ = true;
        callNotify(r, rObject(this), SYMBOL(access));
        inAccess_ = false;
      }
      rObject res = slot_get(slot_get(SYMBOL(owned))->as_bool()
                             ? SYMBOL(valsensor)
                             : SYMBOL(val));
      if (!fromCXX)
      {
        if (object::rUValue bv = res->as<object::UValue>())
        {
          if (bv->bypassMode_ && bv->extract() == nil_class)
          {
            // This is a read on a bypass-mode UVar, from outside any
            // notifychange: the value is not available.
            // So we mark that we wait by inc-ing waiterCount, and wait
            // on waiterTag until we timeout, or someone writes to the UVar
            // and unlock us.

            // free the shared ptrs
            res.reset();
            bv.reset();
            ++waiterCount_;
            slot_get(SYMBOL(waiterTag))->call(SYMBOL(waitUntilStopped),
                                              new Float(0.5));
            --waiterCount_;
            // The val slot likely changed, fetch it again.
            res = slot_get(slot_get(SYMBOL(owned))->as_bool()
                           ? SYMBOL(valsensor)
                           : SYMBOL(val));
            if (object::rUValue bv = res->as<object::UValue>())
              return bv->extract();
            else
              return res;
          }
          return bv->extract();
        }
      }
      return res;
    }

    rObject
    UVar::writeOwned(rObject newval)
    {
      runner::Runner& r = ::kernel::urbiserver->getCurrentRunner();
      slot_update(SYMBOL(valsensor), newval);
      checkBypassCopy();
      callNotify(r, rObject(this), SYMBOL(change));
      slot_get(SYMBOL(changed))->call("emit");
      return newval;
    }

    void
    UVar::initialize(CxxObject::Binder<UVar>& bind)
    {
      bind(SYMBOL(writeOwned), &UVar::writeOwned);
      bind(SYMBOL(update_), &UVar::update_);
      bind(SYMBOL(loopCheck), &UVar::loopCheck);
      bind(SYMBOL(accessor), &UVar::accessor);
      proto->slot_set(SYMBOL(update_bounce), new Primitive(&update_bounce));
    }

    URBI_CXX_OBJECT_REGISTER(UVar)
      : Primitive( boost::bind(&UVar::accessor, this))
      , looping_(false)
      , inAccess_(false)
    {}

    UValue::UValue()
      : bypassMode_(false)
    {
      protos_set(new List);
      proto_add(proto ? rObject(proto) : CxxObject::proto);
    }

    UValue::UValue(libport::intrusive_ptr<UValue>)
      : bypassMode_(false)
    {
      protos_set(new List);
      proto_add(proto ? rObject(proto) : CxxObject::proto);
    }

    UValue::UValue(const urbi::UValue& v, bool bypass)
      : bypassMode_(false)
    {
      protos_set(new List);
      proto_add(proto ? rObject(proto) : CxxObject::proto);
      put(v, bypass);
    }

    UValue::~UValue()
    {}

    rObject
    UValue::extract()
    {
      if (cache_)
        return cache_;
      if (value_.type == urbi::DATA_VOID)
        return nil_class;
      if (!cache_)
        cache_ = object_cast(value_);
      return cache_;
    }

    std::string
    UValue::extractAsToplevelPrintable()
    {
      if (value_.type == urbi::DATA_VOID && cache_)
      { // Someone used put, cache_ is more recent
        return cache_->call("asToplevelPrintable")->as<String>()->value_get();
      }
      std::stringstream s;
      value_.print(s);
      return s.str();
    }

    const urbi::UValue&
    UValue::value_get()
    {
      static urbi::UValue dummy;
      if (value_.type != urbi::DATA_VOID)
        return value_;
      if (!cache_ || cache_ == nil_class)
        return dummy;
      value_ = ::uvalue_cast(cache_);
      alocated_ = true;
      return value_;
    }

    void
    UValue::invalidate()
    {
      if (!alocated_)
        value_ = urbi::UValue();
    }

    void
    UValue::put(const urbi::UValue& v,  bool bypass)
    {
      bypassMode_ = bypass;
      alocated_ = !bypass;
      value_.set(v, !bypass);
      cache_ = 0;
    }

    void
    UValue::put(rObject r)
    {
      value_ = urbi::UValue();
      cache_ = r;
    }

    void
    UValue::initialize(CxxObject::Binder<UValue>& bind)
    {
      bind(SYMBOL(extract), &UValue::extract);
      bind(SYMBOL(extractAsToplevelPrintable),
           &UValue::extractAsToplevelPrintable);
      bind(SYMBOL(invalidate), &UValue::invalidate);
      bind(SYMBOL(put), (void (UValue::*)(rObject))&UValue::put);
    }

    URBI_CXX_OBJECT_REGISTER(UValue)
    {}
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Luke San Antonio
 * All rights reserved.
 */
#include "map.h"
#include "../common/grid_iterator.h"
namespace game
{
  Terrain make_flat_terrain(int alt, int w, int h)
  {
    auto terrain = Terrain{};
    for(int i = 0; i < h; ++i)
    {
      terrain.altitude.emplace_back();
      for(int j = 0; j < w; ++j)
      {
        terrain.altitude.back().push_back(alt);
      }
    }

    terrain.w = w;
    terrain.h = h;

    return terrain;
  }
  Mesh_Data make_terrain_mesh(Terrain const& t, double scale_fac,
                              double flat_fac) noexcept
  {
    std::array<Vertex, 4> vertices;
    std::vector<unsigned int> faces { 1, 3, 2, 0, 1, 2 };

    vertices[0].position = {0.0, 0.0, 1.0};
    vertices[1].position = {0.0, 0.0, 0.0};
    vertices[2].position = {1.0, 0.0, 1.0};
    vertices[3].position = {1.0, 0.0, 0.0};

    vertices[0].uv = {0.0, 1.0};
    vertices[1].uv = {0.0, 0.0};
    vertices[2].uv = {1.0, 1.0};
    vertices[3].uv = {1.0, 0.0};

    auto mesh = Mesh_Data{};

    // Add some amount of rectangles, then adjust their height.
    // Doesn't work when t.h or t.w == 1 or 0
    auto iteration = 0;
    for(int i = 0; i < t.h - 1; ++i)
    {
      for(int j = 0; j < t.w - 1; ++j)
      {
        std::array<Vertex, 4> mod_verts = vertices;

        for(auto& vertex : mod_verts)
        {
          // Scale the width and depth by flat_fac and the height by scale_fac.
          // We also translate the squares based on their position on the grid.
          vertex.position.x += j *= flat_fac;
          vertex.position.y = t.altitude[i][j] * scale_fac;
          vertex.position.z += i *= flat_fac;
        }

        using std::end;
        // Insert the vertices.
        mesh.vertices.insert(end(mesh.vertices), begin(mod_verts),
                             end(mod_verts));

        for(auto face : faces)
        {
          // Adjust the face by our current iteration.
          mesh.elements.push_back(face + vertices.size() * iteration);
        }

        ++iteration;
      }
    }

    return mesh;
  }
  Structure_Instance::
  Structure_Instance(IStructure& s, Orient o) noexcept
    : structure_type(&s),
      obj(structure_type->make_obj()),
      orientation(o) {}
  Structure_Instance::Structure_Instance(Structure_Instance const& s) noexcept
    : structure_type(s.structure_type),
      obj(share_object_keep_ownership(s.obj)),
      orientation(s.orientation) {}
  Structure_Instance& Structure_Instance::
  operator=(Structure_Instance const& i) noexcept
  {
    structure_type = i.structure_type;
    obj = share_object_keep_ownership(i.obj);
    orientation = i.orientation;
    return *this;
  }
}
<commit_msg>Terrain -> Mesh now correctly honors the x-z scale (flat_fac).<commit_after>/*
 * Copyright (C) 2015 Luke San Antonio
 * All rights reserved.
 */
#include "map.h"
#include "../common/grid_iterator.h"
namespace game
{
  Terrain make_flat_terrain(int alt, int w, int h)
  {
    auto terrain = Terrain{};
    for(int i = 0; i < h; ++i)
    {
      terrain.altitude.emplace_back();
      for(int j = 0; j < w; ++j)
      {
        terrain.altitude.back().push_back(alt);
      }
    }

    terrain.w = w;
    terrain.h = h;

    return terrain;
  }
  Mesh_Data make_terrain_mesh(Terrain const& t, double scale_fac,
                              double flat_fac) noexcept
  {
    std::array<Vertex, 4> vertices;
    std::vector<unsigned int> faces { 1, 3, 2, 0, 1, 2 };

    vertices[0].position = {0.0, 0.0, 1.0};
    vertices[1].position = {0.0, 0.0, 0.0};
    vertices[2].position = {1.0, 0.0, 1.0};
    vertices[3].position = {1.0, 0.0, 0.0};

    vertices[0].uv = {0.0, 1.0};
    vertices[1].uv = {0.0, 0.0};
    vertices[2].uv = {1.0, 1.0};
    vertices[3].uv = {1.0, 0.0};

    auto mesh = Mesh_Data{};

    // Add some amount of rectangles, then adjust their height.
    // Doesn't work when t.h or t.w == 1 or 0
    auto iteration = 0;
    for(int i = 0; i < t.h - 1; ++i)
    {
      for(int j = 0; j < t.w - 1; ++j)
      {
        std::array<Vertex, 4> mod_verts = vertices;

        for(auto& vertex : mod_verts)
        {
          // Scale the width and depth by flat_fac and the height by scale_fac.
          // We also translate the squares based on their position on the grid.
          vertex.position.x = (vertex.position.x + j) * flat_fac;
          vertex.position.y = t.altitude[i][j] * scale_fac;
          vertex.position.z = (vertex.position.z + i) * flat_fac;
        }

        using std::end;
        // Insert the vertices.
        mesh.vertices.insert(end(mesh.vertices), begin(mod_verts),
                             end(mod_verts));

        for(auto face : faces)
        {
          // Adjust the face by our current iteration.
          mesh.elements.push_back(face + vertices.size() * iteration);
        }

        ++iteration;
      }
    }

    return mesh;
  }
  Structure_Instance::
  Structure_Instance(IStructure& s, Orient o) noexcept
    : structure_type(&s),
      obj(structure_type->make_obj()),
      orientation(o) {}
  Structure_Instance::Structure_Instance(Structure_Instance const& s) noexcept
    : structure_type(s.structure_type),
      obj(share_object_keep_ownership(s.obj)),
      orientation(s.orientation) {}
  Structure_Instance& Structure_Instance::
  operator=(Structure_Instance const& i) noexcept
  {
    structure_type = i.structure_type;
    obj = share_object_keep_ownership(i.obj);
    orientation = i.orientation;
    return *this;
  }
}
<|endoftext|>