<commit_before>#include <muduo/base/Logging.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/InetAddress.h>
#include <muduo/net/TcpClient.h>
#include <muduo/net/TcpServer.h>

#include <boost/bind.hpp>

#include <queue>
#include <utility>

#include <mcheck.h>
#include <stdio.h>
#include <unistd.h>

using namespace muduo;
using namespace muduo::net;

typedef boost::shared_ptr<TcpClient> TcpClientPtr;

const int kMaxConns = 1;
const size_t kMaxPacketLen = 255;
const size_t kHeaderLen = 3;

const uint16_t kListenPort = 9999;
const char* socksIp = "127.0.0.1";
const uint16_t kSocksPort = 2007;

struct Entry
{
  int connId;
  TcpClientPtr client;
  TcpConnectionPtr connection;
  Buffer pending;
};

class DemuxServer : boost::noncopyable
{
 public:
  DemuxServer(EventLoop* loop, const InetAddress& listenAddr, const InetAddress& socksAddr)
    : loop_(loop),
      server_(loop, listenAddr, "DemuxServer"),
      socksAddr_(socksAddr)
  {
    server_.setConnectionCallback(
        boost::bind(&DemuxServer::onServerConnection, this, _1));
    server_.setMessageCallback(
        boost::bind(&DemuxServer::onServerMessage, this, _1, _2, _3));
  }

  void start()
  {
    server_.start();
  }

  void onServerConnection(const TcpConnectionPtr& conn)
  {
    if (conn->connected())
    {
      if (serverConn_)
      {
        conn->shutdown();
      }
      else
      {
        serverConn_ = conn;
        LOG_INFO << "onServerConnection set serverConn_";
      }
    }
    else
    {
      if (serverConn_ == conn)
      {
        serverConn_.reset();
        LOG_INFO << "onServerConnection reset serverConn_";
      }
    }
  }

  void onServerMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp)
  {
    while (buf->readableBytes() > kHeaderLen)
    {
      size_t len = static_cast<uint8_t>(*buf->peek());
      if (buf->readableBytes() < len + kHeaderLen)
      {
        break;
      }
      else
      {
        int connId = static_cast<uint8_t>(buf->peek()[1]);
        connId |= (static_cast<uint8_t>(buf->peek()[2]) << 8);

        if (connId != 0)
        {
          assert(socksConns_.find(connId) != socksConns_.end());
          TcpConnectionPtr& socksConn = socksConns_[connId].connection;
          if (socksConn)
          {
            assert(socksConns_[connId].pending.readableBytes() == 0);
            socksConn->send(buf->peek() + kHeaderLen, len);
          }
          else
          {
            socksConns_[connId].pending.append(buf->peek() + kHeaderLen, len);
          }
        }
        else
        {
          string cmd(buf->peek() + kHeaderLen, len);
          doCommand(cmd);
        }
        buf->retrieve(len + kHeaderLen);
      }
    }
  }

  void doCommand(const string& cmd)
  {
    static const string kConn = "CONN ";

    int connId = atoi(&cmd[kConn.size()]);
    bool isUp = cmd.find(" IS UP") != string::npos;
    LOG_INFO << "doCommand " << connId << " " << isUp;
    if (isUp)
    {
      assert(socksConns_.find(connId) == socksConns_.end());
      char connName[256];
      snprintf(connName, sizeof connName, "SocksClient %d", connId);
      Entry entry;
      entry.connId = connId;
      entry.client.reset(new TcpClient(loop_, socksAddr_, connName));
      entry.client->setConnectionCallback(
          boost::bind(&DemuxServer::onSocksConnection, this, connId, _1));
      entry.client->setMessageCallback(
          boost::bind(&DemuxServer::onSocksMessage, this, connId, _1, _2, _3));
      // FIXME: setWriteCompleteCallback
      socksConns_[connId] = entry;
      entry.client->connect();
    }
    else
    {
      assert(socksConns_.find(connId) != socksConns_.end());
      TcpConnectionPtr& socksConn = socksConns_[connId].connection;
      if (socksConn)
      {
        socksConn->shutdown();
      }
      else
      {
        socksConns_.erase(connId);
      }
    }
  }

  void onSocksConnection(int connId, const TcpConnectionPtr& conn)
  {
    assert(socksConns_.find(connId) != socksConns_.end());
    if (conn->connected())
    {
      socksConns_[connId].connection = conn;
      Buffer& pendingData = socksConns_[connId].pending;
      if (pendingData.readableBytes() > 0)
      {
        conn->send(&pendingData);
      }
    }
    else
    {
      if (serverConn_)
      {
        char buf[256];
        int len = snprintf(buf, sizeof(buf), "DISCONNECT %d\r\n", connId);
        Buffer buffer;
        buffer.append(buf, len);
        sendServerPacket(0, &buffer);
      }
      else
      {
        socksConns_.erase(connId);
      }
    }
  }

  void onSocksMessage(int connId, const TcpConnectionPtr& conn, Buffer* buf, Timestamp)
  {
    assert(socksConns_.find(connId) != socksConns_.end());
    while (buf->readableBytes() > kMaxPacketLen)
    {
      Buffer packet;
      packet.append(buf->peek(), kMaxPacketLen);
      buf->retrieve(kMaxPacketLen);
      sendServerPacket(connId, &packet);
    }
    if (buf->readableBytes() > 0)
    {
      sendServerPacket(connId, buf);
    }
  }

  void sendServerPacket(int connId, Buffer* buf)
  {
    size_t len = buf->readableBytes();
    LOG_DEBUG << len;
    assert(len <= kMaxPacketLen);
    uint8_t header[kHeaderLen] = {
      static_cast<uint8_t>(len),
      static_cast<uint8_t>(connId & 0xFF),
      static_cast<uint8_t>((connId & 0xFF00) >> 8)
    };
    buf->prepend(header, kHeaderLen);
    if (serverConn_)
    {
      serverConn_->send(buf);
    }
  }

  EventLoop* loop_;
  TcpServer server_;
  TcpConnectionPtr serverConn_;
  const InetAddress socksAddr_;
  std::map<int, Entry> socksConns_;
};

int main(int argc, char* argv[])
{
  LOG_INFO << "pid = " << getpid();
  EventLoop loop;
  InetAddress listenAddr(kListenPort);
  if (argc > 1)
  {
    socksIp = argv[1];
  }
  InetAddress socksAddr(socksIp, kSocksPort);
  DemuxServer server(&loop, listenAddr, socksAddr);

  server.start();

  loop.loop();
}

<commit_msg>clear socksConn_ when server conn is down.<commit_after>#include <muduo/base/Logging.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/InetAddress.h>
#include <muduo/net/TcpClient.h>
#include <muduo/net/TcpServer.h>

#include <boost/bind.hpp>

#include <queue>
#include <utility>

#include <mcheck.h>
#include <stdio.h>
#include <unistd.h>

using namespace muduo;
using namespace muduo::net;

typedef boost::shared_ptr<TcpClient> TcpClientPtr;

const int kMaxConns = 1;
const size_t kMaxPacketLen = 255;
const size_t kHeaderLen = 3;

const uint16_t kListenPort = 9999;
const char* socksIp = "127.0.0.1";
const uint16_t kSocksPort = 7777;

struct Entry
{
  int connId;
  TcpClientPtr client;
  TcpConnectionPtr connection;
  Buffer pending;
};

class DemuxServer : boost::noncopyable
{
 public:
  DemuxServer(EventLoop* loop, const InetAddress& listenAddr, const InetAddress& socksAddr)
    : loop_(loop),
      server_(loop, listenAddr, "DemuxServer"),
      socksAddr_(socksAddr)
  {
    server_.setConnectionCallback(
        boost::bind(&DemuxServer::onServerConnection, this, _1));
    server_.setMessageCallback(
        boost::bind(&DemuxServer::onServerMessage, this, _1, _2, _3));
  }

  void start()
  {
    server_.start();
  }

  void onServerConnection(const TcpConnectionPtr& conn)
  {
    if (conn->connected())
    {
      if (serverConn_)
      {
        conn->shutdown();
      }
      else
      {
        serverConn_ = conn;
        LOG_INFO << "onServerConnection set serverConn_";
      }
    }
    else
    {
      if (serverConn_ == conn)
      {
        serverConn_.reset();
        socksConns_.clear();

        LOG_INFO << "onServerConnection reset serverConn_";
      }
    }
  }

  void onServerMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp)
  {
    while (buf->readableBytes() > kHeaderLen)
    {
      size_t len = static_cast<uint8_t>(*buf->peek());
      if (buf->readableBytes() < len + kHeaderLen)
      {
        break;
      }
      else
      {
        int connId = static_cast<uint8_t>(buf->peek()[1]);
        connId |= (static_cast<uint8_t>(buf->peek()[2]) << 8);

        if (connId != 0)
        {
          assert(socksConns_.find(connId) != socksConns_.end());
          TcpConnectionPtr& socksConn = socksConns_[connId].connection;
          if (socksConn)
          {
            assert(socksConns_[connId].pending.readableBytes() == 0);
            socksConn->send(buf->peek() + kHeaderLen, len);
          }
          else
          {
            socksConns_[connId].pending.append(buf->peek() + kHeaderLen, len);
          }
        }
        else
        {
          string cmd(buf->peek() + kHeaderLen, len);
          doCommand(cmd);
        }
        buf->retrieve(len + kHeaderLen);
      }
    }
  }

  void doCommand(const string& cmd)
  {
    static const string kConn = "CONN ";

    int connId = atoi(&cmd[kConn.size()]);
    bool isUp = cmd.find(" IS UP") != string::npos;
    LOG_INFO << "doCommand " << connId << " " << isUp;
    if (isUp)
    {
      assert(socksConns_.find(connId) == socksConns_.end());
      char connName[256];
      snprintf(connName, sizeof connName, "SocksClient %d", connId);
      Entry entry;
      entry.connId = connId;
      entry.client.reset(new TcpClient(loop_, socksAddr_, connName));
      entry.client->setConnectionCallback(
          boost::bind(&DemuxServer::onSocksConnection, this, connId, _1));
      entry.client->setMessageCallback(
          boost::bind(&DemuxServer::onSocksMessage, this, connId, _1, _2, _3));
      // FIXME: setWriteCompleteCallback
      socksConns_[connId] = entry;
      entry.client->connect();
    }
    else
    {
      assert(socksConns_.find(connId) != socksConns_.end());
      TcpConnectionPtr& socksConn = socksConns_[connId].connection;
      if (socksConn)
      {
        socksConn->shutdown();
      }
      else
      {
        socksConns_.erase(connId);
      }
    }
  }

  void onSocksConnection(int connId, const TcpConnectionPtr& conn)
  {
    assert(socksConns_.find(connId) != socksConns_.end());
    if (conn->connected())
    {
      socksConns_[connId].connection = conn;
      Buffer& pendingData = socksConns_[connId].pending;
      if (pendingData.readableBytes() > 0)
      {
        conn->send(&pendingData);
      }
    }
    else
    {
      if (serverConn_)
      {
        char buf[256];
        int len = snprintf(buf, sizeof(buf), "DISCONNECT %d\r\n", connId);
        Buffer buffer;
        buffer.append(buf, len);
        sendServerPacket(0, &buffer);
      }
      else
      {
        socksConns_.erase(connId);
      }
    }
  }

  void onSocksMessage(int connId, const TcpConnectionPtr& conn, Buffer* buf, Timestamp)
  {
    assert(socksConns_.find(connId) != socksConns_.end());
    while (buf->readableBytes() > kMaxPacketLen)
    {
      Buffer packet;
      packet.append(buf->peek(), kMaxPacketLen);
      buf->retrieve(kMaxPacketLen);
      sendServerPacket(connId, &packet);
    }
    if (buf->readableBytes() > 0)
    {
      sendServerPacket(connId, buf);
    }
  }

  void sendServerPacket(int connId, Buffer* buf)
  {
    size_t len = buf->readableBytes();
    LOG_DEBUG << len;
    assert(len <= kMaxPacketLen);
    uint8_t header[kHeaderLen] = {
      static_cast<uint8_t>(len),
      static_cast<uint8_t>(connId & 0xFF),
      static_cast<uint8_t>((connId & 0xFF00) >> 8)
    };
    buf->prepend(header, kHeaderLen);
    if (serverConn_)
    {
      serverConn_->send(buf);
    }
  }

  EventLoop* loop_;
  TcpServer server_;
  TcpConnectionPtr serverConn_;
  const InetAddress socksAddr_;
  std::map<int, Entry> socksConns_;
};

int main(int argc, char* argv[])
{
  LOG_INFO << "pid = " << getpid();
  EventLoop loop;
  InetAddress listenAddr(kListenPort);
  if (argc > 1)
  {
    socksIp = argv[1];
  }
  InetAddress socksAddr(socksIp, kSocksPort);
  DemuxServer server(&loop, listenAddr, socksAddr);

  server.start();

  loop.loop();
}

<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "qmljscomponentfromobjectdef.h"
#include "qmljscomponentnamedialog.h"

#include <coreplugin/ifile.h>

#include <qmljs/parser/qmljsast_p.h>
#include <qmljs/qmljsdocument.h>
#include <qmljstools/qmljsrefactoringchanges.h>

#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>

using namespace QmlJS::AST;
using namespace QmlJSEditor;
using namespace QmlJSEditor::Internal;
using namespace QmlJSTools;

namespace {

static QString toString(Statement *statement)
{
    ExpressionStatement *expStmt = cast<ExpressionStatement *>(statement);
    if (!expStmt)
        return QString::null;
    if (IdentifierExpression *idExp = cast<IdentifierExpression *>(expStmt->expression)) {
        return idExp->name->asString();
    } else if (StringLiteral *strExp = cast<StringLiteral *>(expStmt->expression)) {
        return strExp->value->asString();
    }
    return QString::null;
}

static QString getIdProperty(UiObjectDefinition *def)
{
    QString objectName;

    if (def && def->initializer) {
        for (UiObjectMemberList *iter = def->initializer->members; iter; iter = iter->next) {
            if (UiScriptBinding *script = cast<UiScriptBinding*>(iter->member)) {
                if (!script->qualifiedId)
                    continue;
                if (script->qualifiedId->next)
                    continue;
                if (script->qualifiedId->name) {
                    if (script->qualifiedId->name->asString() == QLatin1String("id"))
                        return toString(script->statement);
                    if (script->qualifiedId->name->asString() == QLatin1String("objectName"))
                        objectName = toString(script->statement);
                }
            }
        }
    }

    return objectName;
}

class Operation: public QmlJSQuickFixOperation
{
    UiObjectDefinition *m_objDef;
    QString m_componentName;

public:
    Operation(const QmlJSQuickFixState &state, UiObjectDefinition *objDef)
        : QmlJSQuickFixOperation(state, 0)
        , m_objDef(objDef)
    {
        Q_ASSERT(m_objDef != 0);

        m_componentName = getIdProperty(m_objDef);

        if (m_componentName.isEmpty()) {
            setDescription(QCoreApplication::translate("QmlJSEditor::ComponentFromObjectDef",
                                                       "Move Component into separate file"));
        } else {
            m_componentName[0] = m_componentName.at(0).toUpper();
            setDescription(QCoreApplication::translate("QmlJSEditor::ComponentFromObjectDef",
                                                       "Move Component into '%1.qml'").arg(m_componentName));
        }
    }

    virtual void performChanges(QmlJSRefactoringFile *currentFile, QmlJSRefactoringChanges *refactoring)
    {
        QString componentName = m_componentName;
        QString path = QFileInfo(fileName()).path();
        if (componentName.isEmpty()) {
            ComponentNameDialog::go(&componentName, &path, state().editor());
        }

        if (componentName.isEmpty() || path.isEmpty())
            return;

        const QString newFileName = path + QDir::separator() + componentName
                + QLatin1String(".qml");

        QString imports;
        UiProgram *prog = currentFile->qmljsDocument()->qmlProgram();
        if (prog && prog->imports) {
            const int start = currentFile->startOf(prog->imports->firstSourceLocation());
            const int end = currentFile->startOf(prog->members->member->firstSourceLocation());
            imports = currentFile->textOf(start, end);
        }

        const int start = currentFile->startOf(m_objDef->firstSourceLocation());
        const int end = currentFile->startOf(m_objDef->lastSourceLocation());
        const QString txt = imports + currentFile->textOf(start, end)
                + QLatin1String("}\n");

        // stop if we can't create the new file
        if (!refactoring->createFile(newFileName, txt))
            return;

        Utils::ChangeSet changes;
        changes.replace(start, end, componentName + QLatin1String(" {\n"));
        currentFile->change(changes);
        currentFile->indent(Range(start, end + 1));
    }
};

} // end of anonymous namespace

QList<QmlJSQuickFixOperation::Ptr> ComponentFromObjectDef::match(const QmlJSQuickFixState &state)
{
    const int pos = state.currentFile().cursor().position();

    QList<Node *> path = state.semanticInfo().astPath(pos);
    for (int i = path.size() - 1; i >= 0; --i) {
        Node *node = path.at(i);
        if (UiObjectDefinition *objDef = cast<UiObjectDefinition *>(node)) {
            if (!state.currentFile().isCursorOn(objDef->qualifiedTypeNameId))
                return noResult();
             // check that the node is not the root node
            if (i > 0 && !cast<UiProgram*>(path.at(i - 1))) {
                return singleResult(new Operation(state, objDef));
            }
        }
    }

    return noResult();
}
<commit_msg>Retain id when creating a component from an object.<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "qmljscomponentfromobjectdef.h"
#include "qmljscomponentnamedialog.h"

#include <coreplugin/ifile.h>

#include <qmljs/parser/qmljsast_p.h>
#include <qmljs/qmljsdocument.h>
#include <qmljstools/qmljsrefactoringchanges.h>

#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>

using namespace QmlJS::AST;
using namespace QmlJSEditor;
using namespace QmlJSEditor::Internal;
using namespace QmlJSTools;

namespace {

static QString toString(Statement *statement)
{
    ExpressionStatement *expStmt = cast<ExpressionStatement *>(statement);
    if (!expStmt)
        return QString::null;
    if (IdentifierExpression *idExp = cast<IdentifierExpression *>(expStmt->expression)) {
        return idExp->name->asString();
    } else if (StringLiteral *strExp = cast<StringLiteral *>(expStmt->expression)) {
        return strExp->value->asString();
    }
    return QString::null;
}

static QString getIdProperty(UiObjectDefinition *def)
{
    QString objectName;

    if (def && def->initializer) {
        for (UiObjectMemberList *iter = def->initializer->members; iter; iter = iter->next) {
            if (UiScriptBinding *script = cast<UiScriptBinding*>(iter->member)) {
                if (!script->qualifiedId)
                    continue;
                if (script->qualifiedId->next)
                    continue;
                if (script->qualifiedId->name) {
                    if (script->qualifiedId->name->asString() == QLatin1String("id"))
                        return toString(script->statement);
                    if (script->qualifiedId->name->asString() == QLatin1String("objectName"))
                        objectName = toString(script->statement);
                }
            }
        }
    }

    return objectName;
}

class Operation: public QmlJSQuickFixOperation
{
    UiObjectDefinition *m_objDef;
    QString m_idName, m_componentName;

public:
    Operation(const QmlJSQuickFixState &state, UiObjectDefinition *objDef)
        : QmlJSQuickFixOperation(state, 0)
        , m_objDef(objDef)
    {
        Q_ASSERT(m_objDef != 0);

        m_idName = getIdProperty(m_objDef);

        if (m_idName.isEmpty()) {
            setDescription(QCoreApplication::translate("QmlJSEditor::ComponentFromObjectDef",
                                                       "Move Component into separate file"));
        } else {
            m_componentName = m_idName;
            m_componentName[0] = m_componentName.at(0).toUpper();
            setDescription(QCoreApplication::translate("QmlJSEditor::ComponentFromObjectDef",
                                                       "Move Component into '%1.qml'").arg(m_componentName));
        }
    }

    virtual void performChanges(QmlJSRefactoringFile *currentFile, QmlJSRefactoringChanges *refactoring)
    {
        QString componentName = m_componentName;
        QString path = QFileInfo(fileName()).path();
        if (componentName.isEmpty()) {
            ComponentNameDialog::go(&componentName, &path, state().editor());
        }

        if (componentName.isEmpty() || path.isEmpty())
            return;

        const QString newFileName = path + QDir::separator() + componentName
                + QLatin1String(".qml");

        QString imports;
        UiProgram *prog = currentFile->qmljsDocument()->qmlProgram();
        if (prog && prog->imports) {
            const int start = currentFile->startOf(prog->imports->firstSourceLocation());
            const int end = currentFile->startOf(prog->members->member->firstSourceLocation());
            imports = currentFile->textOf(start, end);
        }

        const int start = currentFile->startOf(m_objDef->firstSourceLocation());
        const int end = currentFile->startOf(m_objDef->lastSourceLocation());
        const QString txt = imports + currentFile->textOf(start, end)
                + QLatin1String("}\n");

        // stop if we can't create the new file
        if (!refactoring->createFile(newFileName, txt))
            return;

        QString replacement = componentName + QLatin1String(" {\n");
        if (!m_idName.isEmpty())
                replacement += QLatin1String("id: ") + m_idName
                        + QLatin1Char('\n');

        Utils::ChangeSet changes;
        changes.replace(start, end, replacement);
        currentFile->change(changes);
        currentFile->indent(Range(start, end + 1));
    }
};

} // end of anonymous namespace

QList<QmlJSQuickFixOperation::Ptr> ComponentFromObjectDef::match(const QmlJSQuickFixState &state)
{
    const int pos = state.currentFile().cursor().position();

    QList<Node *> path = state.semanticInfo().astPath(pos);
    for (int i = path.size() - 1; i >= 0; --i) {
        Node *node = path.at(i);
        if (UiObjectDefinition *objDef = cast<UiObjectDefinition *>(node)) {
            if (!state.currentFile().isCursorOn(objDef->qualifiedTypeNameId))
                return noResult();
             // check that the node is not the root node
            if (i > 0 && !cast<UiProgram*>(path.at(i - 1))) {
                return singleResult(new Operation(state, objDef));
            }
        }
    }

    return noResult();
}
<|endoftext|>


<commit_before>#include "VDLog.h"

using namespace VideoDromm;

VDLog::VDLog()
{
	//fs::path path;
	//path = getAppPath() / "log";
	//auto bLog = log::makeLogger<log::LoggerBreakpoint>();
	//bLog->setTriggerLevel(log::LEVEL_ERROR);
	//log::makeLogger<log::LoggerFileRotating>(path.string(), "videodromm.%Y.%m.%d.txt", false);
}
<commit_msg>sysLogger<commit_after>#include "VDLog.h"

using namespace VideoDromm;

VDLog::VDLog()
{
	auto sysLogger = log::makeLogger<log::LoggerSystem>();
	sysLogger->setLoggingLevel(log::LEVEL_WARNING);
#ifdef _DEBUG
	/* fs::path path;
	path = getAppPath() / "log";
	auto bLog = log::makeLogger<log::LoggerBreakpoint>();
	bLog->setTriggerLevel(log::LEVEL_ERROR);
	log::makeLogger<log::LoggerFileRotating>(path.string(), "videodromm.%Y.%m.%d.txt", false);*/
	log::makeLogger<log::LoggerFileRotating>("/tmp/videodromm", "videodromm.%Y.%m.%d.txt", false);
#else

#endif  // _DEBUG
}
<|endoftext|>


<commit_before>#ifndef STAN_ANALYZE_MCMC_COMPUTE_EFFECTIVE_SAMPLE_SIZE_HPP
#define STAN_ANALYZE_MCMC_COMPUTE_EFFECTIVE_SAMPLE_SIZE_HPP

#include <stan/math/prim/mat/fun/Eigen.hpp>
#include <stan/analyze/mcmc/autocovariance.hpp>
#include <stan/analyze/mcmc/split_chains.hpp>
#include <algorithm>
#include <cmath>
#include <vector>

namespace stan {
namespace analyze {

  /**
   * Returns the effective sample size for the specified parameter
   * across all kept samples.
   *
   * See more details in Stan reference manual section "Effective
   * Sample Size". http://mc-stan.org/users/documentation
   *
   * Current implementation assumes chains are all of equal size and
   * draws are stored in contiguous blocks of memory.
   *
   * @param std::vector stores pointers to arrays of chains
   * @param std::vector stores sizes of chains
   * @return effective sample size for the specified parameter
   */
  template <typename DerivedA, typename DerivedB>
  inline
  double effective_sample_size_impl(const Eigen::MatrixBase<DerivedA>& acov,
                                    const Eigen::MatrixBase<DerivedB>& chain_mean) {

    int num_chains = chain_mean.size();
    Eigen::VectorXd chain_var(num_chains);
    for (int chain = 0; chain < num_chains; ++chain) {
      chain_var(chain) = acov(chain)(0);
    }

    // need to generalize to each jagged draws per chain
    int num_draws = acov(0).size();
    double mean_var = chain_var.mean() * num_draws / (num_draws - 1);
    double var_plus = mean_var * (num_draws - 1) / num_draws;
    if (num_chains > 1)
      var_plus += (chain_mean.array() - chain_mean.mean()).square().sum() / (num_chains - 1);

    Eigen::VectorXd rho_hat_s(num_draws);
    rho_hat_s.setZero();
    Eigen::VectorXd acov_s(num_chains);
    for (int chain = 0; chain < num_chains; ++chain)
      acov_s(chain) = acov(chain)(1);
    double rho_hat_even = 1.0;
    rho_hat_s(0) = rho_hat_even;
    double rho_hat_odd = 1 - (mean_var - acov_s.mean()) / var_plus;
    rho_hat_s(1) = rho_hat_odd;
    // Geyer's initial positive sequence
    size_t s = 1;
    for (; s < (num_draws - 4) && (rho_hat_even + rho_hat_odd) > 0;
         s += 2) {
      for (int chain = 0; chain < num_chains; ++chain)
        acov_s(chain) = acov(chain)(s + 1);
      rho_hat_even = 1 - (mean_var - acov_s.mean()) / var_plus;
      for (int chain = 0; chain < num_chains; ++chain)
        acov_s(chain) = acov(chain)(s + 2);
      rho_hat_odd = 1 - (mean_var - acov_s.mean()) / var_plus;
      if ((rho_hat_even + rho_hat_odd) >= 0) {
        rho_hat_s(s + 1) = rho_hat_even;
        rho_hat_s(s + 2) = rho_hat_odd;
      }
    }

    int max_s = s;
    // this is used in the improved estimate
    if (rho_hat_even > 0)
      rho_hat_s(max_s + 1) = rho_hat_even;

    // Geyer's initial monotone sequence
    for (int s = 1; s <= max_s - 3; s += 2) {
      if (rho_hat_s(s + 1) + rho_hat_s(s + 2) >
          rho_hat_s(s - 1) + rho_hat_s(s)) {
        rho_hat_s(s + 1) = (rho_hat_s(s - 1) + rho_hat_s(s)) / 2;
        rho_hat_s(s + 2) = rho_hat_s(s + 1);
      }
    }

    double ess = num_chains * num_draws;
    // Geyer's truncated estimate
    // Improved estimate reduces variance in antithetic case
    double tau_hat = -1 + 2 * rho_hat_s.head(max_s).sum() + rho_hat_s(max_s + 1);
    // Safety check for negative values and with max ess equal to ess*log10(ess)
    return ess / std::max(tau_hat, 1 / std::log10(ess));
  }

  /**
   * Returns the effective sample size for the specified parameter
   * across all kept samples.
   *
   * See more details in Stan reference manual section "Effective
   * Sample Size". http://mc-stan.org/users/documentation
   *
   * Current implementation assumes chains are all of equal size and
   * draws are stored in contiguous blocks of memory.
   *
   * @param Eigen::MatrixBase stores arrays of chains
   * @return effective sample size for the specified parameter
   */
  template <typename Derived>
  inline
  double compute_effective_sample_size(const Eigen::MatrixBase<Derived>& draws) {

    int num_chains = draws.cols();
    Eigen::Matrix<Eigen::VectorXd, Eigen::Dynamic, 1> acov(num_chains);
    Eigen::VectorXd chain_mean(num_chains);
    for (int chain = 0; chain < num_chains; ++chain) {
      autocovariance<double>(draws.col(chain), acov(chain));
      chain_mean(chain) = draws.col(chain).mean();
    }

    return effective_sample_size_impl(acov, chain_mean);
  }

    /**
     * Returns the effective sample size for the specified parameter
     * across all kept samples.
     *
     * See more details in Stan reference manual section "Effective
     * Sample Size". http://mc-stan.org/users/documentation
     *
     * Current implementation assumes chains are all of equal size and
     * draws are stored in contiguous blocks of memory.
     *
     * @param std::vector stores pointers to arrays of chains
     * @param std::vector stores sizes of chains
     * @return effective sample size for the specified parameter
     */
    inline
    double compute_effective_sample_size(std::vector<const double*> draws,
                                         std::vector<size_t> sizes) {

      // std::cout << compute_effective_sample_size(split_chains(draws, sizes))
      //           << std::endl;

      int num_chains = sizes.size();
      Eigen::Matrix<Eigen::VectorXd, Eigen::Dynamic, 1> acov(num_chains);
      Eigen::VectorXd chain_mean(num_chains);
      for (int chain = 0; chain < num_chains; ++chain) {
        Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, 1>>
          draw(draws[chain], sizes[chain]);
        autocovariance<double>(draw, acov(chain));
        chain_mean(chain) = draw.mean();
      }

      return effective_sample_size_impl(acov, chain_mean);
    }

    inline
    double compute_effective_sample_size(std::vector<const double*> draws,
                                         size_t size) {
      int num_chains = draws.size();
      std::vector<size_t> sizes(num_chains, size);
      return compute_effective_sample_size(draws, sizes);
    }
} // namespace analyze
} // namespace stan

#endif
<commit_msg>slight doc changes<commit_after>#ifndef STAN_ANALYZE_MCMC_COMPUTE_EFFECTIVE_SAMPLE_SIZE_HPP
#define STAN_ANALYZE_MCMC_COMPUTE_EFFECTIVE_SAMPLE_SIZE_HPP

#include <stan/math/prim/mat/fun/Eigen.hpp>
#include <stan/analyze/mcmc/autocovariance.hpp>
#include <stan/analyze/mcmc/split_chains.hpp>
#include <algorithm>
#include <cmath>
#include <vector>

namespace stan {
namespace analyze {

  /**
   * Returns the effective sample size for the specified parameter
   * across all kept samples.
   *
   * See more details in Stan reference manual section "Effective
   * Sample Size". http://mc-stan.org/users/documentation
   *
   * Current implementation assumes chains are all of equal size and
   * draws are stored in contiguous blocks of memory.
   *
   * @param Eigen::VectorXd stores autocovariance of each chain
   * @param Eigen::VectorXd stores means of each chain
   * @return effective sample size for the specified parameter
   */
  template <typename DerivedA, typename DerivedB>
  inline
  double effective_sample_size_impl(const Eigen::MatrixBase<DerivedA>& acov,
                                    const Eigen::MatrixBase<DerivedB>& chain_mean) {

    int num_chains = chain_mean.size();
    Eigen::VectorXd chain_var(num_chains);
    for (int chain = 0; chain < num_chains; ++chain) {
      chain_var(chain) = acov(chain)(0);
    }

    // need to generalize to each jagged draws per chain
    int num_draws = acov(0).size();
    double mean_var = chain_var.mean() * num_draws / (num_draws - 1);
    double var_plus = mean_var * (num_draws - 1) / num_draws;
    if (num_chains > 1)
      var_plus += (chain_mean.array() - chain_mean.mean()).square().sum() / (num_chains - 1);

    Eigen::VectorXd rho_hat_s(num_draws);
    rho_hat_s.setZero();
    Eigen::VectorXd acov_s(num_chains);
    for (int chain = 0; chain < num_chains; ++chain)
      acov_s(chain) = acov(chain)(1);
    double rho_hat_even = 1.0;
    rho_hat_s(0) = rho_hat_even;
    double rho_hat_odd = 1 - (mean_var - acov_s.mean()) / var_plus;
    rho_hat_s(1) = rho_hat_odd;
    // Geyer's initial positive sequence
    size_t s = 1;
    for (; s < (num_draws - 4) && (rho_hat_even + rho_hat_odd) > 0;
         s += 2) {
      for (int chain = 0; chain < num_chains; ++chain)
        acov_s(chain) = acov(chain)(s + 1);
      rho_hat_even = 1 - (mean_var - acov_s.mean()) / var_plus;
      for (int chain = 0; chain < num_chains; ++chain)
        acov_s(chain) = acov(chain)(s + 2);
      rho_hat_odd = 1 - (mean_var - acov_s.mean()) / var_plus;
      if ((rho_hat_even + rho_hat_odd) >= 0) {
        rho_hat_s(s + 1) = rho_hat_even;
        rho_hat_s(s + 2) = rho_hat_odd;
      }
    }

    int max_s = s;
    // this is used in the improved estimate
    if (rho_hat_even > 0)
      rho_hat_s(max_s + 1) = rho_hat_even;

    // Geyer's initial monotone sequence
    for (int s = 1; s <= max_s - 3; s += 2) {
      if (rho_hat_s(s + 1) + rho_hat_s(s + 2) >
          rho_hat_s(s - 1) + rho_hat_s(s)) {
        rho_hat_s(s + 1) = (rho_hat_s(s - 1) + rho_hat_s(s)) / 2;
        rho_hat_s(s + 2) = rho_hat_s(s + 1);
      }
    }

    double ess = num_chains * num_draws;
    // Geyer's truncated estimate
    // Improved estimate reduces variance in antithetic case
    double tau_hat = -1 + 2 * rho_hat_s.head(max_s).sum() + rho_hat_s(max_s + 1);
    // Safety check for negative values and with max ess equal to ess*log10(ess)
    return ess / std::max(tau_hat, 1 / std::log10(ess));
  }

  /**
   * Returns the effective sample size for the specified parameter
   * across all kept samples.
   *
   * See more details in Stan reference manual section "Effective
   * Sample Size". http://mc-stan.org/users/documentation
   *
   * Current implementation assumes chains are all of equal size and
   * draws are stored in contiguous blocks of memory.
   *
   * @param Eigen::MatrixBase stores arrays of chains
   * @return effective sample size for the specified parameter
   */
  template <typename Derived>
  inline
  double compute_effective_sample_size(const Eigen::MatrixBase<Derived>& draws) {

    int num_chains = draws.cols();
    Eigen::Matrix<Eigen::VectorXd, Eigen::Dynamic, 1> acov(num_chains);
    Eigen::VectorXd chain_mean(num_chains);
    for (int chain = 0; chain < num_chains; ++chain) {
      autocovariance<double>(draws.col(chain), acov(chain));
      chain_mean(chain) = draws.col(chain).mean();
    }

    return effective_sample_size_impl(acov, chain_mean);
  }

    /**
     * Returns the effective sample size for the specified parameter
     * across all kept samples.
     *
     * See more details in Stan reference manual section "Effective
     * Sample Size". http://mc-stan.org/users/documentation
     *
     * Current implementation assumes chains are all of equal size and
     * draws are stored in contiguous blocks of memory.
     *
     * @param std::vector stores pointers to arrays of chains
     * @param std::vector stores sizes of chains
     * @return effective sample size for the specified parameter
     */
    inline
    double compute_effective_sample_size(std::vector<const double*> draws,
                                         std::vector<size_t> sizes) {

      // std::cout << compute_effective_sample_size(split_chains(draws, sizes))
      //           << std::endl;

      int num_chains = sizes.size();
      Eigen::Matrix<Eigen::VectorXd, Eigen::Dynamic, 1> acov(num_chains);
      Eigen::VectorXd chain_mean(num_chains);
      for (int chain = 0; chain < num_chains; ++chain) {
        Eigen::Map<const Eigen::Matrix<double, Eigen::Dynamic, 1>>
          draw(draws[chain], sizes[chain]);
        autocovariance<double>(draw, acov(chain));
        chain_mean(chain) = draw.mean();
      }

      return effective_sample_size_impl(acov, chain_mean);
    }

    inline
    double compute_effective_sample_size(std::vector<const double*> draws,
                                         size_t size) {
      int num_chains = draws.size();
      std::vector<size_t> sizes(num_chains, size);
      return compute_effective_sample_size(draws, sizes);
    }
} // namespace analyze
} // namespace stan

#endif
<|endoftext|>


<commit_before>/*
 * Glib::Dispatcher example -- cross thread signalling
 * by Daniel Elstner  <daniel.elstner@gmx.net>
 *
 * modified to only use glibmm
 * by J. Abelardo Gutierrez <jabelardo@cantv.net>
 *
 * Copyright (c) 2002-2003  Free Software Foundation
 */

#include <sigc++/class_slot.h>
#include <glibmm.h>

#include <iostream>
#include <algorithm>
#include <functional>
#include <list>

namespace
{
Glib::RefPtr<Glib::MainLoop> main_loop;

class ThreadProgress : public sigc::trackable
{
public:
  ThreadProgress(int id, Glib::Mutex& mtx);
  virtual ~ThreadProgress();

  void launch();

  typedef sigc::signal<void, ThreadProgress*> type_signal_finished;
  type_signal_finished& signal_finished();
  int id() const;

private:
  unsigned int        progress_;
  Glib::Dispatcher    signal_increment_;
  type_signal_finished signal_finished_;
  int                 id_;
  Glib::Mutex&        cout_mutex_;

  void progress_increment();
  void thread_function();
};

//TODO: Rename to avoid confusion with Glib::Dispatcher.
class Dispatcher : public sigc::trackable
{
public:
  Dispatcher();
  virtual ~Dispatcher();

  void launch_threads();

private:
  std::list<ThreadProgress*>  progress_list_;
  Glib::Mutex                 cout_mutex_;

  void on_progress_finished(ThreadProgress* progress);
};

ThreadProgress::ThreadProgress(int id, Glib::Mutex& mtx)
:
  progress_ (0), id_ (id), cout_mutex_ (mtx)
{
  // Connect to the cross-thread signal.
  signal_increment_.connect(sigc::mem_fun(*this, &ThreadProgress::progress_increment));
}

ThreadProgress::~ThreadProgress()
{}

void ThreadProgress::launch()
{
  // Create a non-joinable thread -- it's deleted automatically on thread exit.
  Glib::Thread::create(sigc::mem_fun(*this, &ThreadProgress::thread_function), false);
}

ThreadProgress::type_signal_finished& ThreadProgress::signal_finished()
{
  return signal_finished_;
}

int ThreadProgress::id() const
{
  return id_;
}

void ThreadProgress::progress_increment()
{
  // Use an integer because floating point arithmetic is inaccurate --
  // we want to finish *exactly* after the 100th increment.
  ++progress_;

  cout_mutex_.lock();
  std::cout << "Thread " << id_ << ": " << progress_ << " %" << std::endl;
  cout_mutex_.unlock();

  if(progress_ >= 100)
    signal_finished().emit(this);
}

void ThreadProgress::thread_function()
{
  Glib::Rand rand;
  int usecs = 5000;

  for(int i = 0; i < 100; ++i)
  {
    usecs = rand.get_int_range(std::max(0, usecs - 1000 - i), std::min(20000, usecs + 1000 + i));
    Glib::usleep(usecs);

    // Tell the thread to increment the progress value.
    signal_increment_.emit();
  }
}

Dispatcher::Dispatcher()
:
  cout_mutex_ ()
{
  std::cout << "Thread Dispatcher Example." << std::endl;

  for(int i = 0; i < 5; ++i)
  {
    ThreadProgress *const progress = new ThreadProgress(i, cout_mutex_);
    progress_list_.push_back(progress);

    progress->signal_finished().connect(
        sigc::mem_fun(*this, &Dispatcher::on_progress_finished));
  }
}

Dispatcher::~Dispatcher()
{}

void Dispatcher::launch_threads()
{
  std::for_each(
      progress_list_.begin(), progress_list_.end(),
      std::mem_fun(&ThreadProgress::launch));
}

void Dispatcher::on_progress_finished(ThreadProgress* progress)
{
  cout_mutex_.lock();
  std::cout << "Thread " << progress->id() << ": finished." << std::endl;
  cout_mutex_.unlock();

  progress_list_.remove(progress);

  if(progress_list_.empty())
    main_loop->quit();
}

} // anonymous namespace

int main(int argc, char** argv)
{
  Glib::thread_init();
  main_loop = Glib::MainLoop::create();

  Dispatcher dispatcher;

  // Install a one-shot idle handler to launch the threads
  Glib::signal_idle().connect(
      sigc::bind_return(sigc::mem_fun(dispatcher, &Dispatcher::launch_threads), false));

  main_loop->run();

  return 0;
}

<commit_msg>Code cleanup. Most importantly, get rid of the locking around std::cout<commit_after>/*
 * Glib::Dispatcher example -- cross thread signalling
 * by Daniel Elstner  <daniel.elstner@gmx.net>
 *
 * modified to only use glibmm
 * by J. Abelardo Gutierrez <jabelardo@cantv.net>
 *
 * Copyright (c) 2002-2003  Free Software Foundation
 */

#include <glibmm.h>

#include <algorithm>
#include <functional>
#include <iostream>
#include <list>
#include <memory>

namespace
{

class ThreadProgress
{
public:
  explicit ThreadProgress(int id);
  ~ThreadProgress();

  void launch();

  sigc::signal<void>& signal_finished();
  int id() const;

private:
  int                 id_;
  unsigned int        progress_;
  Glib::Dispatcher    signal_increment_;
  sigc::signal<void>  signal_finished_;

  void progress_increment();
  void thread_function();
};

class Application : public sigc::trackable
{
public:
  Application();
  virtual ~Application();

  void launch_threads();
  void run();

private:
  Glib::RefPtr<Glib::MainLoop>  main_loop_;
  std::list<ThreadProgress*>    progress_list_;

  void on_progress_finished(ThreadProgress* thread_progress);
};

ThreadProgress::ThreadProgress(int id)
:
  id_       (id),
  progress_ (0)
{
  // Connect to the cross-thread signal.
  signal_increment_.connect(sigc::mem_fun(*this, &ThreadProgress::progress_increment));
}

ThreadProgress::~ThreadProgress()
{}

void ThreadProgress::launch()
{
  // Create a non-joinable thread -- it's deleted automatically on thread exit.
  Glib::Thread::create(sigc::mem_fun(*this, &ThreadProgress::thread_function), false);
}

sigc::signal<void>& ThreadProgress::signal_finished()
{
  return signal_finished_;
}

int ThreadProgress::id() const
{
  return id_;
}

void ThreadProgress::progress_increment()
{
  // Use an integer because floating point arithmetic is inaccurate --
  // we want to finish *exactly* after the 100th increment.
  ++progress_;

  std::cout << "Thread " << id_ << ": " << progress_ << '%' << std::endl;

  if(progress_ >= 100)
    signal_finished_();
}

void ThreadProgress::thread_function()
{
  Glib::Rand rand;
  int usecs = 5000;

  for(int i = 0; i < 100; ++i)
  {
    usecs = rand.get_int_range(std::max(0, usecs - 1000 - i), std::min(20000, usecs + 1000 + i));
    Glib::usleep(usecs);

    // Tell the main thread to increment the progress value.
    signal_increment_();
  }
}

Application::Application()
:
  main_loop_ (Glib::MainLoop::create())
{
  std::cout << "Thread Dispatcher Example." << std::endl;

  for(int i = 1; i <= 5; ++i)
  {
    std::auto_ptr<ThreadProgress> progress (new ThreadProgress(i));
    progress_list_.push_back(progress.get());

    progress->signal_finished().connect(
        sigc::bind(sigc::mem_fun(*this, &Application::on_progress_finished), progress.release()));
  }
}

Application::~Application()
{}

void Application::launch_threads()
{
  std::for_each(progress_list_.begin(), progress_list_.end(),
                std::mem_fun(&ThreadProgress::launch));
}

void Application::run()
{
  main_loop_->run();
}

void Application::on_progress_finished(ThreadProgress* thread_progress)
{
  {
    const std::auto_ptr<ThreadProgress> progress (thread_progress);
    progress_list_.remove(progress.get());

    std::cout << "Thread " << progress->id() << ": finished." << std::endl;
  }

  if(progress_list_.empty())
    main_loop_->quit();
}

} // anonymous namespace

int main(int argc, char** argv)
{
  Glib::thread_init();

  Application application;

  // Install a one-shot idle handler to launch the threads
  Glib::signal_idle().connect(
      sigc::bind_return(sigc::mem_fun(application, &Application::launch_threads), false));

  application.run();

  return 0;
}

<|endoftext|>


<commit_before>#include <string.h>

#include "base/logging.h"
#include "gfx/gl_common.h"
#include "gfx_es2/fbo.h"
#include "gfx/gl_common.h"
#include "gfx_es2/gl_state.h"

#if defined(USING_GLES2) && !defined(BLACKBERRY)
#ifndef GL_READ_FRAMEBUFFER
#define GL_READ_FRAMEBUFFER GL_FRAMEBUFFER
#define GL_DRAW_FRAMEBUFFER GL_FRAMEBUFFER
#endif
#ifndef GL_RGBA8
#define GL_RGBA8 GL_RGBA
#endif
#ifndef GL_DEPTH_COMPONENT24
#define GL_DEPTH_COMPONENT24 GL_DEPTH_COMPONENT24_OES
#endif
#ifndef GL_DEPTH24_STENCIL8_OES
#define GL_DEPTH24_STENCIL8_OES 0x88F0
#endif
#endif

#ifdef IOS
extern void bindDefaultFBO();
#endif

struct FBO {
	GLuint handle;
	GLuint color_texture;
	GLuint z_stencil_buffer;  // Either this is set, or the two below.
	GLuint z_buffer;
	GLuint stencil_buffer;

	int width;
	int height;
	FBOColorDepth colorDepth;
};

// On PC, we always use GL_DEPTH24_STENCIL8.
// On Android, we try to use what's available.

#ifndef USING_GLES2
FBO *fbo_ext_create(int width, int height, int num_color_textures, bool z_stencil, FBOColorDepth colorDepth) {
	FBO *fbo = new FBO();
	fbo->width = width;
	fbo->height = height;
	fbo->colorDepth = colorDepth;

	// Color texture is same everywhere
	glGenFramebuffersEXT(1, &fbo->handle);
	glGenTextures(1, &fbo->color_texture);

	// Create the surfaces.
	glBindTexture(GL_TEXTURE_2D, fbo->color_texture);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	// TODO: We could opt to only create 16-bit render targets on slow devices. For later.
	switch (colorDepth) {
	case FBO_8888:
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
		break;
	case FBO_4444:
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, NULL);
		break;
	case FBO_5551:
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, NULL);
		break;
	case FBO_565:
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL);
		break;
	}

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	fbo->stencil_buffer = 0;
	fbo->z_buffer = 0;
	// 24-bit Z, 8-bit stencil
	glGenRenderbuffersEXT(1, &fbo->z_stencil_buffer);
	glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo->z_stencil_buffer);
	glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT, width, height);
	//glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8, width, height);

	// Bind it all together
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->handle);
	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, fbo->color_texture, 0);
	glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->z_stencil_buffer);
	glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->z_stencil_buffer);

	GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
	switch(status) {
	case GL_FRAMEBUFFER_COMPLETE_EXT:
		// ILOG("Framebuffer verified complete.");
		break;
	case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
		ELOG("GL_FRAMEBUFFER_UNSUPPORTED");
		break;
	case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
		ELOG("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT ");
		break;
	default:
		FLOG("Other framebuffer error: %i", status);
		break;
	}
	// Unbind state we don't need
	glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
	glBindTexture(GL_TEXTURE_2D, 0);
	return fbo;
}
#endif

FBO *fbo_create(int width, int height, int num_color_textures, bool z_stencil, FBOColorDepth colorDepth) {
	CheckGLExtensions();

#ifndef USING_GLES2
	if(!gl_extensions.FBO_ARB)
		return fbo_ext_create(width, height, num_color_textures, z_stencil, colorDepth);
#endif

	FBO *fbo = new FBO();
	fbo->width = width;
	fbo->height = height;
	fbo->colorDepth = colorDepth;

	// Color texture is same everywhere
	glGenFramebuffers(1, &fbo->handle);
	glGenTextures(1, &fbo->color_texture);

	// Create the surfaces.
	glBindTexture(GL_TEXTURE_2D, fbo->color_texture);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	// TODO: We could opt to only create 16-bit render targets on slow devices. For later.
	switch (colorDepth) {
	case FBO_8888:
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
		break;
	case FBO_4444:
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, NULL);
		break;
	case FBO_5551:
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, NULL);
		break;
	case FBO_565:
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL);
		break;
	}

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

#ifdef USING_GLES2
	if (gl_extensions.OES_packed_depth_stencil) {
		ILOG("Creating %i x %i FBO using DEPTH24_STENCIL8", width, height);
		// Standard method
		fbo->stencil_buffer = 0;
		fbo->z_buffer = 0;
		// 24-bit Z, 8-bit stencil combined
		glGenRenderbuffers(1, &fbo->z_stencil_buffer);
		glBindRenderbuffer(GL_RENDERBUFFER, fbo->z_stencil_buffer);
		glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, width, height);

		// Bind it all together
		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo->handle);
		glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->color_texture, 0);
		glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer);
		glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer);
	} else {
		ILOG("Creating %i x %i FBO using separate stencil", width, height);
		// TEGRA
		fbo->z_stencil_buffer = 0;
		// 16/24-bit Z, separate 8-bit stencil
		glGenRenderbuffers(1, &fbo->z_buffer);
		glBindRenderbuffer(GL_RENDERBUFFER, fbo->z_buffer);
		glRenderbufferStorage(GL_RENDERBUFFER, gl_extensions.OES_depth24 ? GL_DEPTH_COMPONENT24 : GL_DEPTH_COMPONENT16, width, height);

		// 8-bit stencil buffer
		glGenRenderbuffers(1, &fbo->stencil_buffer);
		glBindRenderbuffer(GL_RENDERBUFFER, fbo->stencil_buffer);
		glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);

		// Bind it all together
		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo->handle);
		glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->color_texture, 0);
		glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo->z_buffer);
		glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo->stencil_buffer);
	}
#else
	fbo->stencil_buffer = 0;
	fbo->z_buffer = 0;
	// 24-bit Z, 8-bit stencil
	glGenRenderbuffers(1, &fbo->z_stencil_buffer);
	glBindRenderbuffer(GL_RENDERBUFFER, fbo->z_stencil_buffer);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);

	// Bind it all together
	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo->handle);
	glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->color_texture, 0);
	glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer);
	glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer);
#endif

	GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
	switch(status) {
	case GL_FRAMEBUFFER_COMPLETE:
		// ILOG("Framebuffer verified complete.");
		break;
	case GL_FRAMEBUFFER_UNSUPPORTED:
		ELOG("GL_FRAMEBUFFER_UNSUPPORTED");
		break;
	case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
		ELOG("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT ");
		break;
	default:
		FLOG("Other framebuffer error: %i", status);
		break;
	}
	// Unbind state we don't need
	glBindRenderbuffer(GL_RENDERBUFFER, 0);
	glBindTexture(GL_TEXTURE_2D, 0);
	return fbo;
}

void fbo_unbind() {
	CheckGLExtensions();

	if(gl_extensions.FBO_ARB){
		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
	}else{
#ifndef USING_GLES2
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
#endif
	}
#ifdef IOS
	bindDefaultFBO();
#endif
}

void fbo_bind_as_render_target(FBO *fbo) {
	if(gl_extensions.FBO_ARB){
		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo->handle);
	}else{
#ifndef USING_GLES2
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->handle);
#endif
	}
}

void fbo_bind_for_read(FBO *fbo) {
	if(gl_extensions.FBO_ARB){
		glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo->handle);
	}else{
#ifndef USING_GLES2
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->handle);
#endif
	}
}

void fbo_bind_color_as_texture(FBO *fbo, int color) {
	if (fbo) {
		glBindTexture(GL_TEXTURE_2D, fbo->color_texture);
	}
}

void fbo_destroy(FBO *fbo) {
	if(gl_extensions.FBO_ARB){
		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo->handle);
		glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
		glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
		glDeleteFramebuffers(1, &fbo->handle);
		glDeleteRenderbuffers(1, &fbo->z_stencil_buffer);
	}else{
#ifndef USING_GLES2
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->handle);
		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
		glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER_EXT, 0);
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
		glDeleteFramebuffersEXT(1, &fbo->handle);
		glDeleteRenderbuffersEXT(1, &fbo->z_stencil_buffer);
#endif
	}

	glDeleteTextures(1, &fbo->color_texture);
	delete fbo;
}

void fbo_get_dimensions(FBO *fbo, int *w, int *h) {
	*w = fbo->width;
	*h = fbo->height;
}

int fbo_get_color_texture(FBO *fbo) {
	return fbo->color_texture;
}
<commit_msg>Revert "Fix a redeclaration warning."<commit_after>#include <string.h>

#include "base/logging.h"
#include "gfx/gl_common.h"
#include "gfx_es2/fbo.h"
#include "gfx/gl_common.h"
#include "gfx_es2/gl_state.h"

#if defined(USING_GLES2) && !defined(BLACKBERRY)
#define GL_READ_FRAMEBUFFER GL_FRAMEBUFFER
#define GL_DRAW_FRAMEBUFFER GL_FRAMEBUFFER
#define GL_RGBA8 GL_RGBA
#ifndef GL_DEPTH_COMPONENT24
#define GL_DEPTH_COMPONENT24 GL_DEPTH_COMPONENT24_OES
#endif
#ifndef GL_DEPTH24_STENCIL8_OES
#define GL_DEPTH24_STENCIL8_OES 0x88F0
#endif
#endif

#ifdef IOS
extern void bindDefaultFBO();
#endif

struct FBO {
	GLuint handle;
	GLuint color_texture;
	GLuint z_stencil_buffer;  // Either this is set, or the two below.
	GLuint z_buffer;
	GLuint stencil_buffer;

	int width;
	int height;
	FBOColorDepth colorDepth;
};

// On PC, we always use GL_DEPTH24_STENCIL8.
// On Android, we try to use what's available.

#ifndef USING_GLES2
FBO *fbo_ext_create(int width, int height, int num_color_textures, bool z_stencil, FBOColorDepth colorDepth) {
	FBO *fbo = new FBO();
	fbo->width = width;
	fbo->height = height;
	fbo->colorDepth = colorDepth;

	// Color texture is same everywhere
	glGenFramebuffersEXT(1, &fbo->handle);
	glGenTextures(1, &fbo->color_texture);

	// Create the surfaces.
	glBindTexture(GL_TEXTURE_2D, fbo->color_texture);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	// TODO: We could opt to only create 16-bit render targets on slow devices. For later.
	switch (colorDepth) {
	case FBO_8888:
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
		break;
	case FBO_4444:
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, NULL);
		break;
	case FBO_5551:
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, NULL);
		break;
	case FBO_565:
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL);
		break;
	}

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	fbo->stencil_buffer = 0;
	fbo->z_buffer = 0;
	// 24-bit Z, 8-bit stencil
	glGenRenderbuffersEXT(1, &fbo->z_stencil_buffer);
	glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo->z_stencil_buffer);
	glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT, width, height);
	//glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8, width, height);

	// Bind it all together
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->handle);
	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, fbo->color_texture, 0);
	glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->z_stencil_buffer);
	glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->z_stencil_buffer);

	GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
	switch(status) {
	case GL_FRAMEBUFFER_COMPLETE_EXT:
		// ILOG("Framebuffer verified complete.");
		break;
	case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
		ELOG("GL_FRAMEBUFFER_UNSUPPORTED");
		break;
	case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
		ELOG("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT ");
		break;
	default:
		FLOG("Other framebuffer error: %i", status);
		break;
	}
	// Unbind state we don't need
	glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
	glBindTexture(GL_TEXTURE_2D, 0);
	return fbo;
}
#endif

FBO *fbo_create(int width, int height, int num_color_textures, bool z_stencil, FBOColorDepth colorDepth) {
	CheckGLExtensions();

#ifndef USING_GLES2
	if(!gl_extensions.FBO_ARB)
		return fbo_ext_create(width, height, num_color_textures, z_stencil, colorDepth);
#endif

	FBO *fbo = new FBO();
	fbo->width = width;
	fbo->height = height;
	fbo->colorDepth = colorDepth;

	// Color texture is same everywhere
	glGenFramebuffers(1, &fbo->handle);
	glGenTextures(1, &fbo->color_texture);

	// Create the surfaces.
	glBindTexture(GL_TEXTURE_2D, fbo->color_texture);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	// TODO: We could opt to only create 16-bit render targets on slow devices. For later.
	switch (colorDepth) {
	case FBO_8888:
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
		break;
	case FBO_4444:
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, NULL);
		break;
	case FBO_5551:
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, NULL);
		break;
	case FBO_565:
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL);
		break;
	}

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

#ifdef USING_GLES2
	if (gl_extensions.OES_packed_depth_stencil) {
		ILOG("Creating %i x %i FBO using DEPTH24_STENCIL8", width, height);
		// Standard method
		fbo->stencil_buffer = 0;
		fbo->z_buffer = 0;
		// 24-bit Z, 8-bit stencil combined
		glGenRenderbuffers(1, &fbo->z_stencil_buffer);
		glBindRenderbuffer(GL_RENDERBUFFER, fbo->z_stencil_buffer);
		glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, width, height);

		// Bind it all together
		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo->handle);
		glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->color_texture, 0);
		glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer);
		glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer);
	} else {
		ILOG("Creating %i x %i FBO using separate stencil", width, height);
		// TEGRA
		fbo->z_stencil_buffer = 0;
		// 16/24-bit Z, separate 8-bit stencil
		glGenRenderbuffers(1, &fbo->z_buffer);
		glBindRenderbuffer(GL_RENDERBUFFER, fbo->z_buffer);
		glRenderbufferStorage(GL_RENDERBUFFER, gl_extensions.OES_depth24 ? GL_DEPTH_COMPONENT24 : GL_DEPTH_COMPONENT16, width, height);

		// 8-bit stencil buffer
		glGenRenderbuffers(1, &fbo->stencil_buffer);
		glBindRenderbuffer(GL_RENDERBUFFER, fbo->stencil_buffer);
		glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);

		// Bind it all together
		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo->handle);
		glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->color_texture, 0);
		glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo->z_buffer);
		glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo->stencil_buffer);
	}
#else
	fbo->stencil_buffer = 0;
	fbo->z_buffer = 0;
	// 24-bit Z, 8-bit stencil
	glGenRenderbuffers(1, &fbo->z_stencil_buffer);
	glBindRenderbuffer(GL_RENDERBUFFER, fbo->z_stencil_buffer);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);

	// Bind it all together
	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo->handle);
	glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->color_texture, 0);
	glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer);
	glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer);
#endif

	GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
	switch(status) {
	case GL_FRAMEBUFFER_COMPLETE:
		// ILOG("Framebuffer verified complete.");
		break;
	case GL_FRAMEBUFFER_UNSUPPORTED:
		ELOG("GL_FRAMEBUFFER_UNSUPPORTED");
		break;
	case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
		ELOG("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT ");
		break;
	default:
		FLOG("Other framebuffer error: %i", status);
		break;
	}
	// Unbind state we don't need
	glBindRenderbuffer(GL_RENDERBUFFER, 0);
	glBindTexture(GL_TEXTURE_2D, 0);
	return fbo;
}

void fbo_unbind() {
	CheckGLExtensions();

	if(gl_extensions.FBO_ARB){
		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
	}else{
#ifndef USING_GLES2
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
#endif
	}
#ifdef IOS
	bindDefaultFBO();
#endif
}

void fbo_bind_as_render_target(FBO *fbo) {
	if(gl_extensions.FBO_ARB){
		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo->handle);
	}else{
#ifndef USING_GLES2
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->handle);
#endif
	}
}

void fbo_bind_for_read(FBO *fbo) {
	if(gl_extensions.FBO_ARB){
		glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo->handle);
	}else{
#ifndef USING_GLES2
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->handle);
#endif
	}
}

void fbo_bind_color_as_texture(FBO *fbo, int color) {
	if (fbo) {
		glBindTexture(GL_TEXTURE_2D, fbo->color_texture);
	}
}

void fbo_destroy(FBO *fbo) {
	if(gl_extensions.FBO_ARB){
		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo->handle);
		glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
		glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
		glDeleteFramebuffers(1, &fbo->handle);
		glDeleteRenderbuffers(1, &fbo->z_stencil_buffer);
	}else{
#ifndef USING_GLES2
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->handle);
		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
		glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER_EXT, 0);
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
		glDeleteFramebuffersEXT(1, &fbo->handle);
		glDeleteRenderbuffersEXT(1, &fbo->z_stencil_buffer);
#endif
	}

	glDeleteTextures(1, &fbo->color_texture);
	delete fbo;
}

void fbo_get_dimensions(FBO *fbo, int *w, int *h) {
	*w = fbo->width;
	*h = fbo->height;
}

int fbo_get_color_texture(FBO *fbo) {
	return fbo->color_texture;
}
<|endoftext|>


<commit_before>#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include <memory>
#include <algorithm>

#include "Vec2i.h"
#include "IMapElement.h"
#include "CActor.h"
#include "CDoorway.h"
#include "CMap.h"
#include "CDoorway.h"
#include "CBaphomet.h"
#include "CCuco.h"
#include "CDemon.h"
#include "CMoura.h"
#include "CWizard.h"
#include "IRenderer.h"
#include "CConsoleRenderer.h"
#include "CGame.h"
#include "CFireball.h"

namespace WizardOfGalicia {

  std::string CGame::readMap( std::string mapName ) {

    std::string entry;
    std::ifstream mapFile( "res/map1.txt" );

    char line[ 80 ];

    while ( !mapFile.eof() ) {
      mapFile >> line;
      entry += line;
    }

    auto position = entry.find('\n' );

    while ( position != std::string::npos ) {
      entry.replace( position, 1, "" );
      position = entry.find( '\n', position + 1);
    }

    return entry;
  }

  void CGame::endOfTurn() {
    map->endOfTurn();
    ++turn;
  }

  void CGame::update() {

    for ( auto actor : map->actors ) {
      if ( actor->hp > 0 ) {
	actor->update(map);
      } else {
	map->map[ actor->position.y][actor->position.x] = nullptr;
      }
    }

    map->actors.erase( std::remove_if( map->actors.begin(), map->actors.end(),
				       [](std::shared_ptr<CActor> actor){ return actor->hp <= 0;}
				       ), map->actors.end() );
  }

  void CGame::runGame( IRenderer *renderer ) {

    turn = 1;

    std::string entry;
    std::string mapData =  readMap( "res/map1.txt" );

    map = std::make_shared<CMap>( mapData );

    std::shared_ptr<CActor> avatar = map->mWizard;

    while ( true ) {

      renderer->drawMap( *map, avatar );

      if ( avatar != nullptr &&  avatar->hp <= 0 ) {
	std::cout << "DEAD" << std::endl;
	avatar = nullptr;
      }

      std::cin >> entry;

      if ( avatar != nullptr ) {

	if ( entry == "s" ) {
	  map->move( Direction::E, avatar );
	}

	if ( entry == "w" ) {
	  map->move( Direction::N, avatar );
	}

	if ( entry == "a" ) {
	  map->move( Direction::W, avatar );
	}

	if ( entry == "i" ) {
	  avatar->turnLeft();
	}

	if ( entry == "o" ) {
	  map->move( avatar->direction, avatar );
	}

	if ( entry == "p" ) {
	  avatar->turnRight();
	}

	if ( entry == "k" ) {

	}

	if ( entry == "l" ) {
	}

	if ( entry == "f" ) {
	  map->cast( avatar );
	}

	if ( entry == "z" ) {
	  map->move( Direction::S, avatar );
	}

	if ( entry == "c" ) {

	  int x;
	  int y;

	  std::cout << "target x?" << std::endl;
	  std::cin >> x;
	  std::cout << "target y?" << std::endl;
	  std::cin >> y;

	  map->attack( avatar, x, y, false );
	}

	update();
	endOfTurn();
      }
    }
  }
}
<commit_msg>Only end a turn and update game stats for players moving and firing<commit_after>#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include <memory>
#include <algorithm>

#include "Vec2i.h"
#include "IMapElement.h"
#include "CActor.h"
#include "CDoorway.h"
#include "CMap.h"
#include "CDoorway.h"
#include "CBaphomet.h"
#include "CCuco.h"
#include "CDemon.h"
#include "CMoura.h"
#include "CWizard.h"
#include "IRenderer.h"
#include "CConsoleRenderer.h"
#include "CGame.h"
#include "CFireball.h"

namespace WizardOfGalicia {

  std::string CGame::readMap( std::string mapName ) {

    std::string entry;
    std::ifstream mapFile( "res/map1.txt" );

    char line[ 80 ];

    while ( !mapFile.eof() ) {
      mapFile >> line;
      entry += line;
    }

    auto position = entry.find('\n' );

    while ( position != std::string::npos ) {
      entry.replace( position, 1, "" );
      position = entry.find( '\n', position + 1);
    }

    return entry;
  }

  void CGame::endOfTurn() {
    map->endOfTurn();
    ++turn;
  }

  void CGame::update() {

    for ( auto actor : map->actors ) {
      if ( actor->hp > 0 ) {
	actor->update(map);
      } else {
	map->map[ actor->position.y][actor->position.x] = nullptr;
      }
    }

    map->actors.erase( std::remove_if( map->actors.begin(), map->actors.end(),
				       [](std::shared_ptr<CActor> actor){ return actor->hp <= 0;}
				       ), map->actors.end() );
  }

  void CGame::runGame( IRenderer *renderer ) {

    turn = 1;
    bool shouldEndTurn = false;
    std::string entry;
    std::string mapData =  readMap( "res/map1.txt" );

    map = std::make_shared<CMap>( mapData );

    std::shared_ptr<CActor> avatar = map->mWizard;

    while ( true ) {

      renderer->drawMap( *map, avatar );

      if ( avatar != nullptr &&  avatar->hp <= 0 ) {
	std::cout << "DEAD" << std::endl;
	avatar = nullptr;
      }

      std::cin >> entry;

      if ( avatar != nullptr ) {

	if ( entry == "s" ) {
	  map->move( Direction::E, avatar );
	  shouldEndTurn = true;
	}

	if ( entry == "w" ) {
	  map->move( Direction::N, avatar );
	  shouldEndTurn = true;
	}

	if ( entry == "a" ) {
	  map->move( Direction::W, avatar );
	  shouldEndTurn = true;
	}

	if ( entry == "i" ) {
	  avatar->turnLeft();
	}

	if ( entry == "o" ) {
	  shouldEndTurn = true;
	  map->move( avatar->direction, avatar );
	}

	if ( entry == "p" ) {
	  avatar->turnRight();
	}

	if ( entry == "k" ) {

	}

	if ( entry == "l" ) {
	}

	if ( entry == "f" ) {
	  map->cast( avatar );
	  shouldEndTurn = true;
	}

	if ( entry == "z" ) {
	  map->move( Direction::S, avatar );
	}

	if ( shouldEndTurn ) {
	  update();
	  endOfTurn();
	  shouldEndTurn = false;
	}
      }
    }
  }
}
<|endoftext|>


<commit_before>// ***************************************************************************
// FastaIndex.cpp (c) 2010 Erik Garrison <erik.garrison@bc.edu>
// Marth Lab, Department of Biology, Boston College
// All rights reserved.
// ---------------------------------------------------------------------------
// Last modified: 9 February 2010 (EG)
// ---------------------------------------------------------------------------

#include "Fasta.h"

FastaIndexEntry::FastaIndexEntry(string name, int length, long long offset, int line_blen, int line_len)
    : name(name)
    , length(length)
    , offset(offset)
    , line_blen(line_blen)
    , line_len(line_len)
{}

FastaIndexEntry::FastaIndexEntry(void) // empty constructor
{ clear(); }

FastaIndexEntry::~FastaIndexEntry(void)
{}

void FastaIndexEntry::clear(void)
{
    name = "";
    length = 0;
    offset = -1;  // no real offset will ever be below 0, so this allows us to
                  // check if we have already recorded a real offset
    line_blen = 0;
    line_len = 0;
}

ostream& operator<<(ostream& output, const FastaIndexEntry& e) {
    // just write the first component of the name, for compliance with other tools
    output << split(e.name, ' ').at(0) << "\t" << e.length << "\t" << e.offset << "\t" <<
        e.line_blen << "\t" << e.line_len;
    return output;  // for multiple << operators.
}

FastaIndex::FastaIndex(void)
{}

void FastaIndex::readIndexFile(string fname) {
    string line;
    long long linenum = 0;
    indexFile.open(fname.c_str(), ifstream::in);
    if (indexFile.is_open()) {
        while (getline (indexFile, line)) {
            ++linenum;
            // the fai format defined in samtools is tab-delimited, every line being:
            // fai->name[i], (int)x.len, (long long)x.offset, (int)x.line_blen, (int)x.line_len
            vector<string> fields = split(line, '\t');
            if (fields.size() == 5) {  // if we don't get enough fields then there is a problem with the file
                // note that fields[0] is the sequence name
                char* end;
                string name = split(fields[0], " \t").at(0);  // key by first token of name
                sequenceNames.push_back(name);
                this->insert(make_pair(name, FastaIndexEntry(fields[0], atoi(fields[1].c_str()),
                                                    strtoll(fields[2].c_str(), &end, 10),
                                                    atoi(fields[3].c_str()),
                                                    atoi(fields[4].c_str()))));
            } else {
                cerr << "Warning: malformed fasta index file " << fname <<
                    "does not have enough fields @ line " << linenum << endl;
                cerr << line << endl;
                exit(1);
            }
        }
    } else {
        cerr << "could not open index file " << fname << endl;
        exit(1);
    }
}

// for consistency this should be a class method
bool fastaIndexEntryCompare ( FastaIndexEntry a, FastaIndexEntry b) { return (a.offset<b.offset); }

ostream& operator<<(ostream& output, FastaIndex& fastaIndex) {
    vector<FastaIndexEntry> sortedIndex;
    for(vector<string>::const_iterator it = fastaIndex.sequenceNames.begin(); it != fastaIndex.sequenceNames.end(); ++it)
    {
        sortedIndex.push_back(fastaIndex[*it]);
    }
    sort(sortedIndex.begin(), sortedIndex.end(), fastaIndexEntryCompare);
    for( vector<FastaIndexEntry>::iterator fit = sortedIndex.begin(); fit != sortedIndex.end(); ++fit) {
        output << *fit << endl;
    }
}

void FastaIndex::indexReference(string refname) {
    // overview:
    //  for line in the reference fasta file
    //  track byte offset from the start of the file
    //  if line is a fasta header, take the name and dump the last sequnece to the index
    //  if line is a sequence, add it to the current sequence
    //cerr << "indexing fasta reference " << refname << endl;
    string line;
    FastaIndexEntry entry;  // an entry buffer used in processing
    entry.clear();
    int line_length = 0;
    long long offset = 0;  // byte offset from start of file
    long long line_number = 0; // current line number
    bool mismatchedLineLengths = false; // flag to indicate if our line length changes mid-file
                                        // this will be used to raise an error
                                        // if we have a line length change at
                                        // any line other than the last line in
                                        // the sequence
    bool emptyLine = false;  // flag to catch empty lines, which we allow for
                             // index generation only on the last line of the sequence
    ifstream refFile;
    refFile.open(refname.c_str());
    if (refFile.is_open()) {
        while (getline(refFile, line)) {
            ++line_number;
            line_length = line.length();
            if (line[0] == ';') {
                // fasta comment, skip
            } else if (line[0] == '+') {
                // fastq quality header
                getline(refFile, line);
                line_length = line.length();
                offset += line_length + 1;
                // get and don't handle the quality line
                getline(refFile, line);
                line_length = line.length();
            } else if (line[0] == '>' || line[0] == '@') { // fasta /fastq header
                // if we aren't on the first entry, push the last sequence into the index
                if (entry.name != "") {
                    mismatchedLineLengths = false; // reset line length error tracker for every new sequence
                    emptyLine = false;
                    flushEntryToIndex(entry);
                    entry.clear();
                }
                entry.name = line.substr(1, line_length - 1);
            } else { // we assume we have found a sequence line
                if (entry.offset == -1) // NB initially the offset is -1
                    entry.offset = offset;
                entry.length += line_length;
                if (entry.line_len) {
                    //entry.line_len = entry.line_len ? entry.line_len : line_length + 1;
                    if (mismatchedLineLengths || emptyLine) {
                        if (line_length == 0) {
                            emptyLine = true; // flag empty lines, raise error only if this is embedded in the sequence
                        } else {
                            if (emptyLine) {
                                cerr << "ERROR: embedded newline";
                            } else {
                                cerr << "ERROR: mismatched line lengths";
                            }
                            cerr << " at line " << line_number << " within sequence " << entry.name <<
                                endl << "File not suitable for fasta index generation." << endl;
                            exit(1);
                        }
                    }
                    // this flag is set here and checked on the next line
                    // because we may have reached the end of the sequence, in
                    // which case a mismatched line length is OK
                    if (entry.line_len != line_length + 1) {
                        mismatchedLineLengths = true;
                        if (line_length == 0) {
                            emptyLine = true; // flag empty lines, raise error only if this is embedded in the sequence
                        }
                    }
                } else {
                    entry.line_len = line_length + 1; // first line
                }
                entry.line_blen = entry.line_len - 1;
            }
            offset += line_length + 1;
        }
        // we've hit the end of the fasta file!
        // flush the last entry
        flushEntryToIndex(entry);
    } else {
        cerr << "could not open reference file " << refname << " for indexing!" << endl;
        exit(1);
    }
}

void FastaIndex::flushEntryToIndex(FastaIndexEntry& entry) {
    string name = split(entry.name, " \t").at(0);  // key by first token of name
    sequenceNames.push_back(name);
    this->insert(make_pair(name, FastaIndexEntry(entry.name, entry.length,
                        entry.offset, entry.line_blen,
                        entry.line_len)));

}

void FastaIndex::writeIndexFile(string fname) {
    //cerr << "writing fasta index file " << fname << endl;
    ofstream file;
    file.open(fname.c_str());
    if (file.is_open()) {
        file << *this;
    } else {
        cerr << "could not open index file " << fname << " for writing!" << endl;
        exit(1);
    }
}

FastaIndex::~FastaIndex(void) {
    indexFile.close();
}

FastaIndexEntry FastaIndex::entry(string name) {
    FastaIndex::iterator e = this->find(name);
    if (e == this->end()) {
        cerr << "unable to find FASTA index entry for '" << name << "'" << endl;
        exit(1);
    } else {
        return e->second;
    }
}

string FastaIndex::indexFileExtension() { return ".fai"; }

/*
FastaReference::FastaReference(string reffilename) {
}
*/

void FastaReference::open(string reffilename) {
    filename = reffilename;
    if (!(file = fopen(filename.c_str(), "r"))) {
        cerr << "could not open " << filename << endl;
        exit(1);
    }
    index = new FastaIndex();
    struct stat stFileInfo;
    string indexFileName = filename + index->indexFileExtension();
    // if we can find an index file, use it
    if(stat(indexFileName.c_str(), &stFileInfo) == 0) {
        index->readIndexFile(indexFileName);
    } else { // otherwise, read the reference and generate the index file in the cwd
        cerr << "index file " << indexFileName << " not found, generating..." << endl;
        index->indexReference(filename);
        index->writeIndexFile(indexFileName);
    }
}

FastaReference::~FastaReference(void) {
    fclose(file);
    delete index;
}

string removeIupac(string& str) {
	for (int i=0; i<str.length(); ++i) {
		char c = str[i];
		if (c != 'A' && c != 'T' && c != 'G' && c != 'C' && c != 'N' &&
				c != 'a' && c != 't' && c != 'g' && c != 'c' && c != 'n') {
			str[i] = 'N';
		}
	}
	return str;
}

string FastaReference::getSequence(string seqname) {
    FastaIndexEntry entry = index->entry(seqname);
    int newlines_in_sequence = entry.length / entry.line_blen;
    int seqlen = newlines_in_sequence  + entry.length;
    char* seq = (char*) calloc (seqlen + 1, sizeof(char));
    fseek64(file, entry.offset, SEEK_SET);
    fread(seq, sizeof(char), seqlen, file);
    seq[seqlen] = '\0';
    char* pbegin = seq;
    char* pend = seq + (seqlen/sizeof(char));
    pend = remove(pbegin, pend, '\n');
    pend = remove(pbegin, pend, '\0');
    string s = seq;
    free(seq);
    s.resize((pend - pbegin)/sizeof(char));
	return removeIupac(s);
}

// TODO cleanup; odd function.  use a map
string FastaReference::sequenceNameStartingWith(string seqnameStart) {
    try {
        return (*index)[seqnameStart].name;
    } catch (exception& e) {
        cerr << e.what() << ": unable to find index entry for " << seqnameStart << endl;
        exit(1);
    }
}

string FastaReference::getSubSequence(string seqname, int start, int length) {
    FastaIndexEntry entry = index->entry(seqname);
    length = min(length, entry.length - start);
    if (start < 0 || length < 1) {
        return "";
    }
    // we have to handle newlines
    // approach: count newlines before start
    //           count newlines by end of read
    //             subtracting newlines before start find count of embedded newlines
    int newlines_before = start > 0 ? (start - 1) / entry.line_blen : 0;
    int newlines_by_end = (start + length - 1) / entry.line_blen;
    int newlines_inside = newlines_by_end - newlines_before;
    int seqlen = length + newlines_inside;
    char* seq = (char*) calloc (seqlen + 1, sizeof(char));
    fseek64(file, (off_t) (entry.offset + newlines_before + start), SEEK_SET);
    fread(seq, sizeof(char), (off_t) seqlen, file);
    seq[seqlen] = '\0';
    char* pbegin = seq;
    char* pend = seq + (seqlen/sizeof(char));
    pend = remove(pbegin, pend, '\n');
    pend = remove(pbegin, pend, '\0');
    string s = seq;
    free(seq);
    s.resize((pend - pbegin)/sizeof(char));
	return removeIupac(s);
}

long unsigned int FastaReference::sequenceLength(string seqname) {
    FastaIndexEntry entry = index->entry(seqname);
    return entry.length;
}

<commit_msg>Clean up whitespace and shorten code<commit_after>// ***************************************************************************
// FastaIndex.cpp (c) 2010 Erik Garrison <erik.garrison@bc.edu>
// Marth Lab, Department of Biology, Boston College
// All rights reserved.
// ---------------------------------------------------------------------------
// Last modified: 9 February 2010 (EG)
// ---------------------------------------------------------------------------

#include "Fasta.h"

FastaIndexEntry::FastaIndexEntry(string name, int length, long long offset, int line_blen, int line_len)
    : name(name)
    , length(length)
    , offset(offset)
    , line_blen(line_blen)
    , line_len(line_len)
{}

FastaIndexEntry::FastaIndexEntry(void) // empty constructor
{ clear(); }

FastaIndexEntry::~FastaIndexEntry(void)
{}

void FastaIndexEntry::clear(void)
{
    name = "";
    length = 0;
    offset = -1;  // no real offset will ever be below 0, so this allows us to
                  // check if we have already recorded a real offset
    line_blen = 0;
    line_len = 0;
}

ostream& operator<<(ostream& output, const FastaIndexEntry& e) {
    // just write the first component of the name, for compliance with other tools
    output << split(e.name, ' ').at(0) << "\t" << e.length << "\t" << e.offset << "\t" <<
        e.line_blen << "\t" << e.line_len;
    return output;  // for multiple << operators.
}

FastaIndex::FastaIndex(void)
{}

void FastaIndex::readIndexFile(string fname) {
    string line;
    long long linenum = 0;
    indexFile.open(fname.c_str(), ifstream::in);
    if (indexFile.is_open()) {
        while (getline (indexFile, line)) {
            ++linenum;
            // the fai format defined in samtools is tab-delimited, every line being:
            // fai->name[i], (int)x.len, (long long)x.offset, (int)x.line_blen, (int)x.line_len
            vector<string> fields = split(line, '\t');
            if (fields.size() == 5) {  // if we don't get enough fields then there is a problem with the file
                // note that fields[0] is the sequence name
                char* end;
                string name = split(fields[0], " \t").at(0);  // key by first token of name
                sequenceNames.push_back(name);
                this->insert(make_pair(name, FastaIndexEntry(fields[0], atoi(fields[1].c_str()),
                                                    strtoll(fields[2].c_str(), &end, 10),
                                                    atoi(fields[3].c_str()),
                                                    atoi(fields[4].c_str()))));
            } else {
                cerr << "Warning: malformed fasta index file " << fname <<
                    "does not have enough fields @ line " << linenum << endl;
                cerr << line << endl;
                exit(1);
            }
        }
    } else {
        cerr << "could not open index file " << fname << endl;
        exit(1);
    }
}

// for consistency this should be a class method
bool fastaIndexEntryCompare ( FastaIndexEntry a, FastaIndexEntry b) { return (a.offset<b.offset); }

ostream& operator<<(ostream& output, FastaIndex& fastaIndex) {
    vector<FastaIndexEntry> sortedIndex;
    for(vector<string>::const_iterator it = fastaIndex.sequenceNames.begin(); it != fastaIndex.sequenceNames.end(); ++it)
    {
        sortedIndex.push_back(fastaIndex[*it]);
    }
    sort(sortedIndex.begin(), sortedIndex.end(), fastaIndexEntryCompare);
    for( vector<FastaIndexEntry>::iterator fit = sortedIndex.begin(); fit != sortedIndex.end(); ++fit) {
        output << *fit << endl;
    }
}

void FastaIndex::indexReference(string refname) {
    // overview:
    //  for line in the reference fasta file
    //  track byte offset from the start of the file
    //  if line is a fasta header, take the name and dump the last sequnece to the index
    //  if line is a sequence, add it to the current sequence
    //cerr << "indexing fasta reference " << refname << endl;
    string line;
    FastaIndexEntry entry;  // an entry buffer used in processing
    entry.clear();
    int line_length = 0;
    long long offset = 0;  // byte offset from start of file
    long long line_number = 0; // current line number
    bool mismatchedLineLengths = false; // flag to indicate if our line length changes mid-file
                                        // this will be used to raise an error
                                        // if we have a line length change at
                                        // any line other than the last line in
                                        // the sequence
    bool emptyLine = false;  // flag to catch empty lines, which we allow for
                             // index generation only on the last line of the sequence
    ifstream refFile;
    refFile.open(refname.c_str());
    if (refFile.is_open()) {
        while (getline(refFile, line)) {
            ++line_number;
            line_length = line.length();
            if (line[0] == ';') {
                // fasta comment, skip
            } else if (line[0] == '+') {
                // fastq quality header
                getline(refFile, line);
                line_length = line.length();
                offset += line_length + 1;
                // get and don't handle the quality line
                getline(refFile, line);
                line_length = line.length();
            } else if (line[0] == '>' || line[0] == '@') { // fasta /fastq header
                // if we aren't on the first entry, push the last sequence into the index
                if (entry.name != "") {
                    mismatchedLineLengths = false; // reset line length error tracker for every new sequence
                    emptyLine = false;
                    flushEntryToIndex(entry);
                    entry.clear();
                }
                entry.name = line.substr(1, line_length - 1);
            } else { // we assume we have found a sequence line
                if (entry.offset == -1) // NB initially the offset is -1
                    entry.offset = offset;
                entry.length += line_length;
                if (entry.line_len) {
                    //entry.line_len = entry.line_len ? entry.line_len : line_length + 1;
                    if (mismatchedLineLengths || emptyLine) {
                        if (line_length == 0) {
                            emptyLine = true; // flag empty lines, raise error only if this is embedded in the sequence
                        } else {
                            if (emptyLine) {
                                cerr << "ERROR: embedded newline";
                            } else {
                                cerr << "ERROR: mismatched line lengths";
                            }
                            cerr << " at line " << line_number << " within sequence " << entry.name <<
                                endl << "File not suitable for fasta index generation." << endl;
                            exit(1);
                        }
                    }
                    // this flag is set here and checked on the next line
                    // because we may have reached the end of the sequence, in
                    // which case a mismatched line length is OK
                    if (entry.line_len != line_length + 1) {
                        mismatchedLineLengths = true;
                        if (line_length == 0) {
                            emptyLine = true; // flag empty lines, raise error only if this is embedded in the sequence
                        }
                    }
                } else {
                    entry.line_len = line_length + 1; // first line
                }
                entry.line_blen = entry.line_len - 1;
            }
            offset += line_length + 1;
        }
        // we've hit the end of the fasta file!
        // flush the last entry
        flushEntryToIndex(entry);
    } else {
        cerr << "could not open reference file " << refname << " for indexing!" << endl;
        exit(1);
    }
}

void FastaIndex::flushEntryToIndex(FastaIndexEntry& entry) {
    string name = split(entry.name, " \t").at(0);  // key by first token of name
    sequenceNames.push_back(name);
    this->insert(make_pair(name, FastaIndexEntry(entry.name, entry.length,
                        entry.offset, entry.line_blen,
                        entry.line_len)));

}

void FastaIndex::writeIndexFile(string fname) {
    //cerr << "writing fasta index file " << fname << endl;
    ofstream file;
    file.open(fname.c_str());
    if (file.is_open()) {
        file << *this;
    } else {
        cerr << "could not open index file " << fname << " for writing!" << endl;
        exit(1);
    }
}

FastaIndex::~FastaIndex(void) {
    indexFile.close();
}

FastaIndexEntry FastaIndex::entry(string name) {
    FastaIndex::iterator e = this->find(name);
    if (e == this->end()) {
        cerr << "unable to find FASTA index entry for '" << name << "'" << endl;
        exit(1);
    } else {
        return e->second;
    }
}

string FastaIndex::indexFileExtension() { return ".fai"; }

/*
FastaReference::FastaReference(string reffilename) {
}
*/

void FastaReference::open(string reffilename) {
    filename = reffilename;
    if (!(file = fopen(filename.c_str(), "r"))) {
        cerr << "could not open " << filename << endl;
        exit(1);
    }
    index = new FastaIndex();
    struct stat stFileInfo;
    string indexFileName = filename + index->indexFileExtension();
    // if we can find an index file, use it
    if(stat(indexFileName.c_str(), &stFileInfo) == 0) {
        index->readIndexFile(indexFileName);
    } else { // otherwise, read the reference and generate the index file in the cwd
        cerr << "index file " << indexFileName << " not found, generating..." << endl;
        index->indexReference(filename);
        index->writeIndexFile(indexFileName);
    }
}

FastaReference::~FastaReference(void) {
    fclose(file);
    delete index;
}

string removeIupacBases(string& str) {
    const string bases = "ATGCNatgcn";
    size_t found = str.find_first_not_of(bases);
    while (found != string::npos) {
        str[found] = 'N';
        found = str.find_first_not_of(bases, found + 1);
    }
    return str;
}

string FastaReference::getSequence(string seqname) {
    FastaIndexEntry entry = index->entry(seqname);
    int newlines_in_sequence = entry.length / entry.line_blen;
    int seqlen = newlines_in_sequence  + entry.length;
    char* seq = (char*) calloc (seqlen + 1, sizeof(char));
    fseek64(file, entry.offset, SEEK_SET);
    fread(seq, sizeof(char), seqlen, file);
    seq[seqlen] = '\0';
    char* pbegin = seq;
    char* pend = seq + (seqlen/sizeof(char));
    pend = remove(pbegin, pend, '\n');
    pend = remove(pbegin, pend, '\0');
    string s = seq;
    free(seq);
    s.resize((pend - pbegin)/sizeof(char));
    return removeIupacBases(s);
}

// TODO cleanup; odd function.  use a map
string FastaReference::sequenceNameStartingWith(string seqnameStart) {
    try {
        return (*index)[seqnameStart].name;
    } catch (exception& e) {
        cerr << e.what() << ": unable to find index entry for " << seqnameStart << endl;
        exit(1);
    }
}

string FastaReference::getSubSequence(string seqname, int start, int length) {
    FastaIndexEntry entry = index->entry(seqname);
    length = min(length, entry.length - start);
    if (start < 0 || length < 1) {
        return "";
    }
    // we have to handle newlines
    // approach: count newlines before start
    //           count newlines by end of read
    //             subtracting newlines before start find count of embedded newlines
    int newlines_before = start > 0 ? (start - 1) / entry.line_blen : 0;
    int newlines_by_end = (start + length - 1) / entry.line_blen;
    int newlines_inside = newlines_by_end - newlines_before;
    int seqlen = length + newlines_inside;
    char* seq = (char*) calloc (seqlen + 1, sizeof(char));
    fseek64(file, (off_t) (entry.offset + newlines_before + start), SEEK_SET);
    fread(seq, sizeof(char), (off_t) seqlen, file);
    seq[seqlen] = '\0';
    char* pbegin = seq;
    char* pend = seq + (seqlen/sizeof(char));
    pend = remove(pbegin, pend, '\n');
    pend = remove(pbegin, pend, '\0');
    string s = seq;
    free(seq);
    s.resize((pend - pbegin)/sizeof(char));
    return removeIupacBases(s);
}

long unsigned int FastaReference::sequenceLength(string seqname) {
    FastaIndexEntry entry = index->entry(seqname);
    return entry.length;
}

<|endoftext|>