<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2008 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "DivNode.h"
#include "SDLDisplayEngine.h"
#include "Player.h"
#include "NodeDefinition.h"

#include "../base/Point.h"
#include "../base/Exception.h"
#include "../base/Logger.h"
#include "../base/StringHelper.h"
#include "../base/FileHelper.h"
#include "../base/MathHelper.h"

#include <iostream>
#include <sstream>

using namespace std;
using namespace boost;

namespace avg {

NodeDefinition DivNode::createDefinition()
{
    string sChildArray[] = {"image", "div", "canvas", "words", "video", "camera",
            "panoimage", "sound", "line", "rect", "curve", "polyline", "polygon",
            "circle"};
    vector<string> sChildren = vectorFromCArray(
            sizeof(sChildArray) / sizeof(*sChildArray), sChildArray);
    return NodeDefinition("div", Node::buildNode<DivNode>)
        .extendDefinition(AreaNode::createDefinition())
        .addChildren(sChildren)
        .addArg(Arg<bool>("crop", true, false, offsetof(DivNode, m_bCrop)))
        .addArg(Arg<string>("elementoutlinecolor", "", false,
                offsetof(DivNode, m_sElementOutlineColor)))
        .addArg(Arg<string>("mediadir", "", false, offsetof(DivNode, m_sMediaDir)));
}

DivNode::DivNode(const ArgList& Args, bool)
{
    Args.setMembers(this);
    setElementOutlineColor(m_sElementOutlineColor);
}

DivNode::~DivNode()
{
}

void DivNode::setRenderingEngines(DisplayEngine * pDisplayEngine,
        AudioEngine * pAudioEngine)
{
    AreaNode::setRenderingEngines(pDisplayEngine, pAudioEngine);
    for  (int i = 0; i<(int)m_Children.size(); ++i) {
        m_Children[i]->setRenderingEngines(pDisplayEngine, pAudioEngine);
    }
}

void DivNode::connect()
{
    AreaNode::connect();
    for (int i = 0; i< (int)m_Children.size(); ++i) {
        m_Children[i]->connect();
    }
}

void DivNode::disconnect()
{
    for  (int i = 0; i< (int)m_Children.size(); ++i) {
        m_Children[i]->disconnect();
    }
    AreaNode::disconnect();
}

bool DivNode::getCrop() const
{
    return m_bCrop;
}

void DivNode::setCrop(bool bCrop)
{
    m_bCrop = bCrop;
}

const std::string& DivNode::getElementOutlineColor() const
{
    return m_sElementOutlineColor;
}

void DivNode::setElementOutlineColor(const std::string& sColor)
{
    m_sElementOutlineColor = sColor;
    if (sColor == "") {
        m_ElementOutlineColor = Pixel32(0,0,0,0);
    } else {
        m_ElementOutlineColor = colorStringToColor(m_sElementOutlineColor);
    }
}

const string& DivNode::getMediaDir() const
{
    return m_sMediaDir;
}

void DivNode::setMediaDir(const string& sMediaDir)
{
    m_sMediaDir = sMediaDir;
    checkReload();
}

int DivNode::getNumChildren()
{
    return int(m_Children.size());
}

const NodePtr& DivNode::getChild(unsigned i)
{
    if (i >= m_Children.size()) {
        stringstream s;
        s << "Index " << i << " is out of range in DivNode::getChild()";
        throw(Exception(AVG_ERR_OUT_OF_RANGE, s.str()));
    }
    return m_Children[i];
}

void DivNode::appendChild(NodePtr pNewNode)
{
    insertChild(pNewNode, unsigned(m_Children.size()));
}

void DivNode::insertChildBefore(NodePtr pNewNode, NodePtr pOldChild)
{
    if (!pOldChild) {
        throw Exception(AVG_ERR_NO_NODE,
                getID()+"::insertChildBefore called without a node.");
    }
    unsigned i = indexOf(pOldChild);
    insertChild(pNewNode, i);
}

void DivNode::insertChild(NodePtr pNewNode, unsigned i)
{
    if (!pNewNode) {
        throw Exception(AVG_ERR_NO_NODE,
                getID()+"::insertChild called without a node.");
    }
    if (!isChildTypeAllowed(pNewNode->getTypeStr())) {
        throw(Exception(AVG_ERR_ALREADY_CONNECTED,
                "Can't insert a node of type "+pNewNode->getTypeStr()+
                " into a node of type "+getTypeStr()+"."));

    }
    if (pNewNode->getState() == NS_CONNECTED || pNewNode->getState() == NS_CANRENDER)
    {
        throw(Exception(AVG_ERR_ALREADY_CONNECTED,
                "Can't connect node with id "+pNewNode->getID()+
                ": already connected."));
    }
    if (i>m_Children.size()) {
        throw(Exception(AVG_ERR_OUT_OF_RANGE,
                pNewNode->getID()+"::insertChild: index out of bounds."));
    }
    std::vector<NodePtr>::iterator Pos = m_Children.begin()+i;
    if (getState() == NS_CONNECTED || getState() == NS_CANRENDER) {
        Player::get()->registerNode(pNewNode);
    }
    m_Children.insert(Pos, pNewNode);
    DivNodePtr Ptr = boost::dynamic_pointer_cast<DivNode>(getThis());
    pNewNode->setParent(Ptr, getState());
    if (getState() == NS_CANRENDER) {
        pNewNode->setRenderingEngines(getDisplayEngine(), getAudioEngine());
    }
}

void DivNode::removeChild(NodePtr pNode)
{
    int i = indexOf(pNode);
    pNode->removeParent();
    m_Children.erase(m_Children.begin()+i);
}

void DivNode::removeChild(unsigned i)
{
    if (i>m_Children.size()-1) {
        throw(Exception(AVG_ERR_OUT_OF_RANGE,
                getID()+"::removeChild: index "+toString(i)+" out of bounds."));
    }
    NodePtr pNode = getChild(i);
    pNode->removeParent();
    m_Children.erase(m_Children.begin()+i);
}

void DivNode::reorderChild(NodePtr pNode, unsigned j)
{
    if (j > m_Children.size()-1) {
        throw(Exception(AVG_ERR_OUT_OF_RANGE,
                getID()+"::reorderChild: index "+toString(j)+" out of bounds."));
    }
    int i = indexOf(pNode);
    m_Children.erase(m_Children.begin()+i);
    std::vector<NodePtr>::iterator Pos = m_Children.begin()+j;
    m_Children.insert(Pos, pNode);
}

void DivNode::reorderChild(unsigned i, unsigned j)
{
    if (i>m_Children.size()-1 || j > m_Children.size()-1) {
        throw(Exception(AVG_ERR_OUT_OF_RANGE,
                getID()+"::reorderChild: index out of bounds."));
    }
    NodePtr pNode = getChild(i);
    m_Children.erase(m_Children.begin()+i);
    std::vector<NodePtr>::iterator Pos = m_Children.begin()+j;
    m_Children.insert(Pos, pNode);
}

int DivNode::indexOf(NodePtr pChild)
{
    if (!pChild) {
        throw Exception(AVG_ERR_NO_NODE,
                getID()+"::indexOf called without a node.");
    }
    for  (int i = 0; i< (int)m_Children.size(); ++i) {
        if (m_Children[i] == pChild) {
            return i;
        }
    }
    throw(Exception(AVG_ERR_OUT_OF_RANGE,
            "indexOf: node '"+pChild->getID()+"' is not a child of node '"
            +getID()+"'"));
}

NodePtr DivNode::getElementByPos(const DPoint & pos)
{
    if (pos.x >= 0 && pos.y >= 0 && pos.x < getSize().x && pos.y < getSize().y &&
            reactsToMouseEvents())
    {
        for (int i=getNumChildren()-1; i>=0; i--) {
            // TODO: Move coordinate handling to Node (& get rid of AreaNode entirely?)
            AreaNodePtr pCurChild = dynamic_pointer_cast<AreaNode>(getChild(i));
            NodePtr pFoundNode;
            DPoint relPos;
            if (pCurChild) {
                relPos = pCurChild->toLocal(pos);
                pFoundNode = pCurChild->getElementByPos(relPos);
            } else {
                pFoundNode = getChild(i)->getElementByPos(pos);
            }
            if (pFoundNode) {
                return pFoundNode;
            }
        }
        // Pos isn't in any of the children.
        if (getSize() != DPoint(10000, 10000)) {
            // Explicit width/height given for div.
            return getThis();
        } else {
            // Explicit width/height not given: div itself doesn't react.
            return NodePtr();
        }
    } else {
        return NodePtr();
    }
}

void DivNode::preRender()
{
    Node::preRender();
    for (int i=0; i<getNumChildren(); i++) {
        getChild(i)->preRender();
    }
}

void DivNode::render(const DRect& rect)
{
    DPoint Viewport = getSize();
    if (getCrop()) {
        DRect ClipRect(0, 0, Viewport.x, Viewport.y);
        getDisplayEngine()->pushClipRect(ClipRect);
    }
    for (int i=0; i<getNumChildren(); i++) {
        getDisplayEngine()->pushShader();
        getChild(i)->maybeRender(rect);
        getDisplayEngine()->popShader();
    }
    if (getCrop()) {
        getDisplayEngine()->popClipRect();
    }
}

void DivNode::renderOutlines(VertexArrayPtr pVA, Pixel32 color)
{
    Pixel32 effColor = color;
    if (m_ElementOutlineColor != Pixel32(0,0,0,0)) {
        effColor = m_ElementOutlineColor;
        effColor.setA(128);
    }
    if (effColor != Pixel32(0,0,0,0)) {
        DPoint size = getSize();
        if (size == DPoint(10000, 10000)) {
            DPoint p0 = getAbsPos(DPoint(-4, 0.5));
            DPoint p1 = getAbsPos(DPoint(5, 0.5));
            DPoint p2 = getAbsPos(DPoint(0.5, -4));
            DPoint p3 = getAbsPos(DPoint(0.5, 5));
            pVA->addLineData(effColor, p0, p1, 1);
            pVA->addLineData(effColor, p2, p3, 1);
        } else {
            DPoint p0 = getAbsPos(DPoint(0.5, 0.5));
            DPoint p1 = getAbsPos(DPoint(size.x+0.5,0.5));
            DPoint p2 = getAbsPos(DPoint(size.x+0.5,size.y+0.5));
            DPoint p3 = getAbsPos(DPoint(0.5,size.y+0.5));
            pVA->addLineData(effColor, p0, p1, 1);
            pVA->addLineData(effColor, p1, p2, 1);
            pVA->addLineData(effColor, p2, p3, 1);
            pVA->addLineData(effColor, p3, p0, 1);
        }
    }
    for (int i=0; i<getNumChildren(); i++) {
        getChild(i)->renderOutlines(pVA, effColor);
    }
}

string DivNode::getEffectiveMediaDir()
{
    string sMediaDir = m_sMediaDir;
    if (!isAbsPath(sMediaDir)) {
        if (getParent()) {
            sMediaDir = getParent()->getEffectiveMediaDir()+m_sMediaDir;
        } else {
            sMediaDir = Player::get()->getRootMediaDir()+m_sMediaDir;
        }
    }
    if (sMediaDir[sMediaDir.length()-1] != '/') {
        sMediaDir += '/';
    }
    return sMediaDir;
}

void DivNode::checkReload()
{
    for(int i=0; i<getNumChildren(); ++i) {
        getChild(i)->checkReload();
    }
}

string DivNode::dump(int indent)
{
    string dumpStr = AreaNode::dump () + "\n";
    vector<NodePtr>::iterator it;
    for (it=m_Children.begin(); it<m_Children.end(); it++) {
        dumpStr += (*it)->dump(indent+2)+"\n";
    }
    return dumpStr;
}

IntPoint DivNode::getMediaSize()
{
    return IntPoint(10000,10000);
}

bool DivNode::isChildTypeAllowed(const string& sType)
{
    return getDefinition()->isChildAllowed(sType);
}

}
<commit_msg>div nodes without size now pass events to children at negative coordinates.<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2008 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "DivNode.h"
#include "SDLDisplayEngine.h"
#include "Player.h"
#include "NodeDefinition.h"

#include "../base/Point.h"
#include "../base/Exception.h"
#include "../base/Logger.h"
#include "../base/StringHelper.h"
#include "../base/FileHelper.h"
#include "../base/MathHelper.h"

#include <iostream>
#include <sstream>

using namespace std;
using namespace boost;

namespace avg {

NodeDefinition DivNode::createDefinition()
{
    string sChildArray[] = {"image", "div", "canvas", "words", "video", "camera",
            "panoimage", "sound", "line", "rect", "curve", "polyline", "polygon",
            "circle"};
    vector<string> sChildren = vectorFromCArray(
            sizeof(sChildArray) / sizeof(*sChildArray), sChildArray);
    return NodeDefinition("div", Node::buildNode<DivNode>)
        .extendDefinition(AreaNode::createDefinition())
        .addChildren(sChildren)
        .addArg(Arg<bool>("crop", true, false, offsetof(DivNode, m_bCrop)))
        .addArg(Arg<string>("elementoutlinecolor", "", false,
                offsetof(DivNode, m_sElementOutlineColor)))
        .addArg(Arg<string>("mediadir", "", false, offsetof(DivNode, m_sMediaDir)));
}

DivNode::DivNode(const ArgList& Args, bool)
{
    Args.setMembers(this);
    setElementOutlineColor(m_sElementOutlineColor);
}

DivNode::~DivNode()
{
}

void DivNode::setRenderingEngines(DisplayEngine * pDisplayEngine,
        AudioEngine * pAudioEngine)
{
    AreaNode::setRenderingEngines(pDisplayEngine, pAudioEngine);
    for  (int i = 0; i<(int)m_Children.size(); ++i) {
        m_Children[i]->setRenderingEngines(pDisplayEngine, pAudioEngine);
    }
}

void DivNode::connect()
{
    AreaNode::connect();
    for (int i = 0; i< (int)m_Children.size(); ++i) {
        m_Children[i]->connect();
    }
}

void DivNode::disconnect()
{
    for  (int i = 0; i< (int)m_Children.size(); ++i) {
        m_Children[i]->disconnect();
    }
    AreaNode::disconnect();
}

bool DivNode::getCrop() const
{
    return m_bCrop;
}

void DivNode::setCrop(bool bCrop)
{
    m_bCrop = bCrop;
}

const std::string& DivNode::getElementOutlineColor() const
{
    return m_sElementOutlineColor;
}

void DivNode::setElementOutlineColor(const std::string& sColor)
{
    m_sElementOutlineColor = sColor;
    if (sColor == "") {
        m_ElementOutlineColor = Pixel32(0,0,0,0);
    } else {
        m_ElementOutlineColor = colorStringToColor(m_sElementOutlineColor);
    }
}

const string& DivNode::getMediaDir() const
{
    return m_sMediaDir;
}

void DivNode::setMediaDir(const string& sMediaDir)
{
    m_sMediaDir = sMediaDir;
    checkReload();
}

int DivNode::getNumChildren()
{
    return int(m_Children.size());
}

const NodePtr& DivNode::getChild(unsigned i)
{
    if (i >= m_Children.size()) {
        stringstream s;
        s << "Index " << i << " is out of range in DivNode::getChild()";
        throw(Exception(AVG_ERR_OUT_OF_RANGE, s.str()));
    }
    return m_Children[i];
}

void DivNode::appendChild(NodePtr pNewNode)
{
    insertChild(pNewNode, unsigned(m_Children.size()));
}

void DivNode::insertChildBefore(NodePtr pNewNode, NodePtr pOldChild)
{
    if (!pOldChild) {
        throw Exception(AVG_ERR_NO_NODE,
                getID()+"::insertChildBefore called without a node.");
    }
    unsigned i = indexOf(pOldChild);
    insertChild(pNewNode, i);
}

void DivNode::insertChild(NodePtr pNewNode, unsigned i)
{
    if (!pNewNode) {
        throw Exception(AVG_ERR_NO_NODE,
                getID()+"::insertChild called without a node.");
    }
    if (!isChildTypeAllowed(pNewNode->getTypeStr())) {
        throw(Exception(AVG_ERR_ALREADY_CONNECTED,
                "Can't insert a node of type "+pNewNode->getTypeStr()+
                " into a node of type "+getTypeStr()+"."));

    }
    if (pNewNode->getState() == NS_CONNECTED || pNewNode->getState() == NS_CANRENDER)
    {
        throw(Exception(AVG_ERR_ALREADY_CONNECTED,
                "Can't connect node with id "+pNewNode->getID()+
                ": already connected."));
    }
    if (i>m_Children.size()) {
        throw(Exception(AVG_ERR_OUT_OF_RANGE,
                pNewNode->getID()+"::insertChild: index out of bounds."));
    }
    std::vector<NodePtr>::iterator Pos = m_Children.begin()+i;
    if (getState() == NS_CONNECTED || getState() == NS_CANRENDER) {
        Player::get()->registerNode(pNewNode);
    }
    m_Children.insert(Pos, pNewNode);
    DivNodePtr Ptr = boost::dynamic_pointer_cast<DivNode>(getThis());
    pNewNode->setParent(Ptr, getState());
    if (getState() == NS_CANRENDER) {
        pNewNode->setRenderingEngines(getDisplayEngine(), getAudioEngine());
    }
}

void DivNode::removeChild(NodePtr pNode)
{
    int i = indexOf(pNode);
    pNode->removeParent();
    m_Children.erase(m_Children.begin()+i);
}

void DivNode::removeChild(unsigned i)
{
    if (i>m_Children.size()-1) {
        throw(Exception(AVG_ERR_OUT_OF_RANGE,
                getID()+"::removeChild: index "+toString(i)+" out of bounds."));
    }
    NodePtr pNode = getChild(i);
    pNode->removeParent();
    m_Children.erase(m_Children.begin()+i);
}

void DivNode::reorderChild(NodePtr pNode, unsigned j)
{
    if (j > m_Children.size()-1) {
        throw(Exception(AVG_ERR_OUT_OF_RANGE,
                getID()+"::reorderChild: index "+toString(j)+" out of bounds."));
    }
    int i = indexOf(pNode);
    m_Children.erase(m_Children.begin()+i);
    std::vector<NodePtr>::iterator Pos = m_Children.begin()+j;
    m_Children.insert(Pos, pNode);
}

void DivNode::reorderChild(unsigned i, unsigned j)
{
    if (i>m_Children.size()-1 || j > m_Children.size()-1) {
        throw(Exception(AVG_ERR_OUT_OF_RANGE,
                getID()+"::reorderChild: index out of bounds."));
    }
    NodePtr pNode = getChild(i);
    m_Children.erase(m_Children.begin()+i);
    std::vector<NodePtr>::iterator Pos = m_Children.begin()+j;
    m_Children.insert(Pos, pNode);
}

int DivNode::indexOf(NodePtr pChild)
{
    if (!pChild) {
        throw Exception(AVG_ERR_NO_NODE,
                getID()+"::indexOf called without a node.");
    }
    for  (int i = 0; i< (int)m_Children.size(); ++i) {
        if (m_Children[i] == pChild) {
            return i;
        }
    }
    throw(Exception(AVG_ERR_OUT_OF_RANGE,
            "indexOf: node '"+pChild->getID()+"' is not a child of node '"
            +getID()+"'"));
}

NodePtr DivNode::getElementByPos(const DPoint & pos)
{
    if (reactsToMouseEvents() &&
            ((getSize() == DPoint(10000, 10000) ||
             (pos.x >= 0 && pos.y >= 0 && pos.x < getSize().x && pos.y < getSize().y))))
    {
        for (int i=getNumChildren()-1; i>=0; i--) {
            // TODO: Move coordinate handling to Node (& get rid of AreaNode entirely?)
            AreaNodePtr pCurChild = dynamic_pointer_cast<AreaNode>(getChild(i));
            NodePtr pFoundNode;
            DPoint relPos;
            if (pCurChild) {
                relPos = pCurChild->toLocal(pos);
                pFoundNode = pCurChild->getElementByPos(relPos);
            } else {
                pFoundNode = getChild(i)->getElementByPos(pos);
            }
            if (pFoundNode) {
                return pFoundNode;
            }
        }
        // Pos isn't in any of the children.
        if (getSize() == DPoint(10000, 10000)) {
            // Explicit width/height not given: div itself doesn't react.
            return NodePtr();
        } else {
            // Explicit width/height given for div.
            return getThis();
        }
    } else {
        return NodePtr();
    }
}

void DivNode::preRender()
{
    Node::preRender();
    for (int i=0; i<getNumChildren(); i++) {
        getChild(i)->preRender();
    }
}

void DivNode::render(const DRect& rect)
{
    DPoint Viewport = getSize();
    if (getCrop()) {
        DRect ClipRect(0, 0, Viewport.x, Viewport.y);
        getDisplayEngine()->pushClipRect(ClipRect);
    }
    for (int i=0; i<getNumChildren(); i++) {
        getDisplayEngine()->pushShader();
        getChild(i)->maybeRender(rect);
        getDisplayEngine()->popShader();
    }
    if (getCrop()) {
        getDisplayEngine()->popClipRect();
    }
}

void DivNode::renderOutlines(VertexArrayPtr pVA, Pixel32 color)
{
    Pixel32 effColor = color;
    if (m_ElementOutlineColor != Pixel32(0,0,0,0)) {
        effColor = m_ElementOutlineColor;
        effColor.setA(128);
    }
    if (effColor != Pixel32(0,0,0,0)) {
        DPoint size = getSize();
        if (size == DPoint(10000, 10000)) {
            DPoint p0 = getAbsPos(DPoint(-4, 0.5));
            DPoint p1 = getAbsPos(DPoint(5, 0.5));
            DPoint p2 = getAbsPos(DPoint(0.5, -4));
            DPoint p3 = getAbsPos(DPoint(0.5, 5));
            pVA->addLineData(effColor, p0, p1, 1);
            pVA->addLineData(effColor, p2, p3, 1);
        } else {
            DPoint p0 = getAbsPos(DPoint(0.5, 0.5));
            DPoint p1 = getAbsPos(DPoint(size.x+0.5,0.5));
            DPoint p2 = getAbsPos(DPoint(size.x+0.5,size.y+0.5));
            DPoint p3 = getAbsPos(DPoint(0.5,size.y+0.5));
            pVA->addLineData(effColor, p0, p1, 1);
            pVA->addLineData(effColor, p1, p2, 1);
            pVA->addLineData(effColor, p2, p3, 1);
            pVA->addLineData(effColor, p3, p0, 1);
        }
    }
    for (int i=0; i<getNumChildren(); i++) {
        getChild(i)->renderOutlines(pVA, effColor);
    }
}

string DivNode::getEffectiveMediaDir()
{
    string sMediaDir = m_sMediaDir;
    if (!isAbsPath(sMediaDir)) {
        if (getParent()) {
            sMediaDir = getParent()->getEffectiveMediaDir()+m_sMediaDir;
        } else {
            sMediaDir = Player::get()->getRootMediaDir()+m_sMediaDir;
        }
    }
    if (sMediaDir[sMediaDir.length()-1] != '/') {
        sMediaDir += '/';
    }
    return sMediaDir;
}

void DivNode::checkReload()
{
    for(int i=0; i<getNumChildren(); ++i) {
        getChild(i)->checkReload();
    }
}

string DivNode::dump(int indent)
{
    string dumpStr = AreaNode::dump () + "\n";
    vector<NodePtr>::iterator it;
    for (it=m_Children.begin(); it<m_Children.end(); it++) {
        dumpStr += (*it)->dump(indent+2)+"\n";
    }
    return dumpStr;
}

IntPoint DivNode::getMediaSize()
{
    return IntPoint(10000,10000);
}

bool DivNode::isChildTypeAllowed(const string& sType)
{
    return getDefinition()->isChildAllowed(sType);
}

}
<|endoftext|>


<commit_before>//===-- NativeProcessProtocolTest.cpp ---------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lldb/Host/common/NativeProcessProtocol.h"
#include "llvm/Testing/Support/Error.h"
#include "gmock/gmock.h"

using namespace lldb_private;
using namespace lldb;
using namespace testing;

namespace {
class MockDelegate : public NativeProcessProtocol::NativeDelegate {
public:
  MOCK_METHOD1(InitializeDelegate, void(NativeProcessProtocol *Process));
  MOCK_METHOD2(ProcessStateChanged,
               void(NativeProcessProtocol *Process, StateType State));
  MOCK_METHOD1(DidExec, void(NativeProcessProtocol *Process));
};

class MockProcess : public NativeProcessProtocol {
public:
  MockProcess(NativeDelegate &Delegate, const ArchSpec &Arch,
              lldb::pid_t Pid = 1)
      : NativeProcessProtocol(Pid, -1, Delegate), Arch(Arch) {}

  MOCK_METHOD1(Resume, Status(const ResumeActionList &ResumeActions));
  MOCK_METHOD0(Halt, Status());
  MOCK_METHOD0(Detach, Status());
  MOCK_METHOD1(Signal, Status(int Signo));
  MOCK_METHOD0(Kill, Status());
  MOCK_METHOD3(AllocateMemory,
               Status(size_t Size, uint32_t Permissions, addr_t &Addr));
  MOCK_METHOD1(DeallocateMemory, Status(addr_t Addr));
  MOCK_METHOD0(GetSharedLibraryInfoAddress, addr_t());
  MOCK_METHOD0(UpdateThreads, size_t());
  MOCK_CONST_METHOD0(GetAuxvData,
                     llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>());
  MOCK_METHOD2(GetLoadedModuleFileSpec,
               Status(const char *ModulePath, FileSpec &Spec));
  MOCK_METHOD2(GetFileLoadAddress,
               Status(const llvm::StringRef &FileName, addr_t &Addr));

  const ArchSpec &GetArchitecture() const override { return Arch; }
  Status SetBreakpoint(lldb::addr_t Addr, uint32_t Size,
                       bool Hardware) override {
    if (Hardware)
      return SetHardwareBreakpoint(Addr, Size);
    else
      return SetSoftwareBreakpoint(Addr, Size);
  }

  // Redirect base class Read/Write Memory methods to functions whose signatures
  // are more mock-friendly.
  Status ReadMemory(addr_t Addr, void *Buf, size_t Size,
                    size_t &BytesRead) override;
  Status WriteMemory(addr_t Addr, const void *Buf, size_t Size,
                     size_t &BytesWritten) override;

  MOCK_METHOD2(ReadMemory,
               llvm::Expected<std::vector<uint8_t>>(addr_t Addr, size_t Size));
  MOCK_METHOD2(WriteMemory,
               llvm::Expected<size_t>(addr_t Addr,
                                      llvm::ArrayRef<uint8_t> Data));

  using NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode;
  llvm::Expected<std::vector<uint8_t>> ReadMemoryWithoutTrap(addr_t Addr,
                                                             size_t Size);

private:
  ArchSpec Arch;
};

class FakeMemory {
public:
  FakeMemory(llvm::ArrayRef<uint8_t> Data) : Data(Data) {}
  llvm::Expected<std::vector<uint8_t>> Read(addr_t Addr, size_t Size);
  llvm::Expected<size_t> Write(addr_t Addr, llvm::ArrayRef<uint8_t> Chunk);

private:
  std::vector<uint8_t> Data;
};
} // namespace

Status MockProcess::ReadMemory(addr_t Addr, void *Buf, size_t Size,
                               size_t &BytesRead) {
  auto ExpectedMemory = ReadMemory(Addr, Size);
  if (!ExpectedMemory) {
    BytesRead = 0;
    return Status(ExpectedMemory.takeError());
  }
  BytesRead = ExpectedMemory->size();
  assert(BytesRead <= Size);
  std::memcpy(Buf, ExpectedMemory->data(), BytesRead);
  return Status();
}

Status MockProcess::WriteMemory(addr_t Addr, const void *Buf, size_t Size,
                                size_t &BytesWritten) {
  auto ExpectedBytes = WriteMemory(
      Addr, llvm::makeArrayRef(static_cast<const uint8_t *>(Buf), Size));
  if (!ExpectedBytes) {
    BytesWritten = 0;
    return Status(ExpectedBytes.takeError());
  }
  BytesWritten = *ExpectedBytes;
  return Status();
}

llvm::Expected<std::vector<uint8_t>>
MockProcess::ReadMemoryWithoutTrap(addr_t Addr, size_t Size) {
  std::vector<uint8_t> Data(Size, 0);
  size_t BytesRead;
  Status ST = NativeProcessProtocol::ReadMemoryWithoutTrap(
      Addr, Data.data(), Data.size(), BytesRead);
  if (ST.Fail())
    return ST.ToError();
  Data.resize(BytesRead);
  return std::move(Data);
}

llvm::Expected<std::vector<uint8_t>> FakeMemory::Read(addr_t Addr,
                                                      size_t Size) {
  if (Addr >= Data.size())
    return llvm::createStringError(llvm::inconvertibleErrorCode(),
                                   "Address out of range.");
  Size = std::min(Size, Data.size() - (size_t)Addr);
  auto Begin = std::next(Data.begin(), Addr);
  return std::vector<uint8_t>(Begin, std::next(Begin, Size));
}

llvm::Expected<size_t> FakeMemory::Write(addr_t Addr,
                                         llvm::ArrayRef<uint8_t> Chunk) {
  if (Addr >= Data.size())
    return llvm::createStringError(llvm::inconvertibleErrorCode(),
                                   "Address out of range.");
  size_t Size = std::min(Chunk.size(), Data.size() - (size_t)Addr);
  std::copy_n(Chunk.begin(), Size, &Data[Addr]);
  return Size;
}

TEST(NativeProcessProtocolTest, SetBreakpoint) {
  NiceMock<MockDelegate> DummyDelegate;
  MockProcess Process(DummyDelegate, ArchSpec("x86_64-pc-linux"));
  auto Trap = cantFail(Process.GetSoftwareBreakpointTrapOpcode(1));
  InSequence S;
  EXPECT_CALL(Process, ReadMemory(0x47, 1))
      .WillOnce(Return(ByMove(std::vector<uint8_t>{0xbb})));
  EXPECT_CALL(Process, WriteMemory(0x47, Trap)).WillOnce(Return(ByMove(1)));
  EXPECT_CALL(Process, ReadMemory(0x47, 1)).WillOnce(Return(ByMove(Trap)));
  EXPECT_THAT_ERROR(Process.SetBreakpoint(0x47, 0, false).ToError(),
                    llvm::Succeeded());
}

TEST(NativeProcessProtocolTest, SetBreakpointFailRead) {
  NiceMock<MockDelegate> DummyDelegate;
  MockProcess Process(DummyDelegate, ArchSpec("x86_64-pc-linux"));
  EXPECT_CALL(Process, ReadMemory(0x47, 1))
      .WillOnce(Return(ByMove(
          llvm::createStringError(llvm::inconvertibleErrorCode(), "Foo"))));
  EXPECT_THAT_ERROR(Process.SetBreakpoint(0x47, 0, false).ToError(),
                    llvm::Failed());
}

TEST(NativeProcessProtocolTest, SetBreakpointFailWrite) {
  NiceMock<MockDelegate> DummyDelegate;
  MockProcess Process(DummyDelegate, ArchSpec("x86_64-pc-linux"));
  auto Trap = cantFail(Process.GetSoftwareBreakpointTrapOpcode(1));
  InSequence S;
  EXPECT_CALL(Process, ReadMemory(0x47, 1))
      .WillOnce(Return(ByMove(std::vector<uint8_t>{0xbb})));
  EXPECT_CALL(Process, WriteMemory(0x47, Trap))
      .WillOnce(Return(ByMove(
          llvm::createStringError(llvm::inconvertibleErrorCode(), "Foo"))));
  EXPECT_THAT_ERROR(Process.SetBreakpoint(0x47, 0, false).ToError(),
                    llvm::Failed());
}

TEST(NativeProcessProtocolTest, SetBreakpointFailVerify) {
  NiceMock<MockDelegate> DummyDelegate;
  MockProcess Process(DummyDelegate, ArchSpec("x86_64-pc-linux"));
  auto Trap = cantFail(Process.GetSoftwareBreakpointTrapOpcode(1));
  InSequence S;
  EXPECT_CALL(Process, ReadMemory(0x47, 1))
      .WillOnce(Return(ByMove(std::vector<uint8_t>{0xbb})));
  EXPECT_CALL(Process, WriteMemory(0x47, Trap)).WillOnce(Return(ByMove(1)));
  EXPECT_CALL(Process, ReadMemory(0x47, 1))
      .WillOnce(Return(ByMove(
          llvm::createStringError(llvm::inconvertibleErrorCode(), "Foo"))));
  EXPECT_THAT_ERROR(Process.SetBreakpoint(0x47, 0, false).ToError(),
                    llvm::Failed());
}

TEST(NativeProcessProtocolTest, ReadMemoryWithoutTrap) {
  NiceMock<MockDelegate> DummyDelegate;
  MockProcess Process(DummyDelegate, ArchSpec("aarch64-pc-linux"));
  FakeMemory M{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}};
  EXPECT_CALL(Process, ReadMemory(_, _))
      .WillRepeatedly(Invoke(&M, &FakeMemory::Read));
  EXPECT_CALL(Process, WriteMemory(_, _))
      .WillRepeatedly(Invoke(&M, &FakeMemory::Write));

  EXPECT_THAT_ERROR(Process.SetBreakpoint(0x4, 0, false).ToError(),
                    llvm::Succeeded());
  EXPECT_THAT_EXPECTED(
      Process.ReadMemoryWithoutTrap(0, 10),
      llvm::HasValue(std::vector<uint8_t>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}));
  EXPECT_THAT_EXPECTED(Process.ReadMemoryWithoutTrap(0, 6),
                       llvm::HasValue(std::vector<uint8_t>{0, 1, 2, 3, 4, 5}));
  EXPECT_THAT_EXPECTED(Process.ReadMemoryWithoutTrap(6, 4),
                       llvm::HasValue(std::vector<uint8_t>{6, 7, 8, 9}));
  EXPECT_THAT_EXPECTED(Process.ReadMemoryWithoutTrap(6, 2),
                       llvm::HasValue(std::vector<uint8_t>{6, 7}));
  EXPECT_THAT_EXPECTED(Process.ReadMemoryWithoutTrap(4, 2),
                       llvm::HasValue(std::vector<uint8_t>{4, 5}));
}
<commit_msg>NativeProcessProtocolTest: fix -Winconsistent-missing-override warning<commit_after>//===-- NativeProcessProtocolTest.cpp ---------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lldb/Host/common/NativeProcessProtocol.h"
#include "llvm/Testing/Support/Error.h"
#include "gmock/gmock.h"

using namespace lldb_private;
using namespace lldb;
using namespace testing;

namespace {
class MockDelegate : public NativeProcessProtocol::NativeDelegate {
public:
  MOCK_METHOD1(InitializeDelegate, void(NativeProcessProtocol *Process));
  MOCK_METHOD2(ProcessStateChanged,
               void(NativeProcessProtocol *Process, StateType State));
  MOCK_METHOD1(DidExec, void(NativeProcessProtocol *Process));
};

// NB: This class doesn't use the override keyword to avoid
// -Winconsistent-missing-override warnings from the compiler. The
// inconsistency comes from the overriding definitions in the MOCK_*** macros.
class MockProcess : public NativeProcessProtocol {
public:
  MockProcess(NativeDelegate &Delegate, const ArchSpec &Arch,
              lldb::pid_t Pid = 1)
      : NativeProcessProtocol(Pid, -1, Delegate), Arch(Arch) {}

  MOCK_METHOD1(Resume, Status(const ResumeActionList &ResumeActions));
  MOCK_METHOD0(Halt, Status());
  MOCK_METHOD0(Detach, Status());
  MOCK_METHOD1(Signal, Status(int Signo));
  MOCK_METHOD0(Kill, Status());
  MOCK_METHOD3(AllocateMemory,
               Status(size_t Size, uint32_t Permissions, addr_t &Addr));
  MOCK_METHOD1(DeallocateMemory, Status(addr_t Addr));
  MOCK_METHOD0(GetSharedLibraryInfoAddress, addr_t());
  MOCK_METHOD0(UpdateThreads, size_t());
  MOCK_CONST_METHOD0(GetAuxvData,
                     llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>());
  MOCK_METHOD2(GetLoadedModuleFileSpec,
               Status(const char *ModulePath, FileSpec &Spec));
  MOCK_METHOD2(GetFileLoadAddress,
               Status(const llvm::StringRef &FileName, addr_t &Addr));

  const ArchSpec &GetArchitecture() const /*override*/ { return Arch; }
  Status SetBreakpoint(lldb::addr_t Addr, uint32_t Size,
                       bool Hardware) /*override*/ {
    if (Hardware)
      return SetHardwareBreakpoint(Addr, Size);
    else
      return SetSoftwareBreakpoint(Addr, Size);
  }

  // Redirect base class Read/Write Memory methods to functions whose signatures
  // are more mock-friendly.
  Status ReadMemory(addr_t Addr, void *Buf, size_t Size,
                    size_t &BytesRead) /*override*/;
  Status WriteMemory(addr_t Addr, const void *Buf, size_t Size,
                     size_t &BytesWritten) /*override*/;

  MOCK_METHOD2(ReadMemory,
               llvm::Expected<std::vector<uint8_t>>(addr_t Addr, size_t Size));
  MOCK_METHOD2(WriteMemory,
               llvm::Expected<size_t>(addr_t Addr,
                                      llvm::ArrayRef<uint8_t> Data));

  using NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode;
  llvm::Expected<std::vector<uint8_t>> ReadMemoryWithoutTrap(addr_t Addr,
                                                             size_t Size);

private:
  ArchSpec Arch;
};

class FakeMemory {
public:
  FakeMemory(llvm::ArrayRef<uint8_t> Data) : Data(Data) {}
  llvm::Expected<std::vector<uint8_t>> Read(addr_t Addr, size_t Size);
  llvm::Expected<size_t> Write(addr_t Addr, llvm::ArrayRef<uint8_t> Chunk);

private:
  std::vector<uint8_t> Data;
};
} // namespace

Status MockProcess::ReadMemory(addr_t Addr, void *Buf, size_t Size,
                               size_t &BytesRead) {
  auto ExpectedMemory = ReadMemory(Addr, Size);
  if (!ExpectedMemory) {
    BytesRead = 0;
    return Status(ExpectedMemory.takeError());
  }
  BytesRead = ExpectedMemory->size();
  assert(BytesRead <= Size);
  std::memcpy(Buf, ExpectedMemory->data(), BytesRead);
  return Status();
}

Status MockProcess::WriteMemory(addr_t Addr, const void *Buf, size_t Size,
                                size_t &BytesWritten) {
  auto ExpectedBytes = WriteMemory(
      Addr, llvm::makeArrayRef(static_cast<const uint8_t *>(Buf), Size));
  if (!ExpectedBytes) {
    BytesWritten = 0;
    return Status(ExpectedBytes.takeError());
  }
  BytesWritten = *ExpectedBytes;
  return Status();
}

llvm::Expected<std::vector<uint8_t>>
MockProcess::ReadMemoryWithoutTrap(addr_t Addr, size_t Size) {
  std::vector<uint8_t> Data(Size, 0);
  size_t BytesRead;
  Status ST = NativeProcessProtocol::ReadMemoryWithoutTrap(
      Addr, Data.data(), Data.size(), BytesRead);
  if (ST.Fail())
    return ST.ToError();
  Data.resize(BytesRead);
  return std::move(Data);
}

llvm::Expected<std::vector<uint8_t>> FakeMemory::Read(addr_t Addr,
                                                      size_t Size) {
  if (Addr >= Data.size())
    return llvm::createStringError(llvm::inconvertibleErrorCode(),
                                   "Address out of range.");
  Size = std::min(Size, Data.size() - (size_t)Addr);
  auto Begin = std::next(Data.begin(), Addr);
  return std::vector<uint8_t>(Begin, std::next(Begin, Size));
}

llvm::Expected<size_t> FakeMemory::Write(addr_t Addr,
                                         llvm::ArrayRef<uint8_t> Chunk) {
  if (Addr >= Data.size())
    return llvm::createStringError(llvm::inconvertibleErrorCode(),
                                   "Address out of range.");
  size_t Size = std::min(Chunk.size(), Data.size() - (size_t)Addr);
  std::copy_n(Chunk.begin(), Size, &Data[Addr]);
  return Size;
}

TEST(NativeProcessProtocolTest, SetBreakpoint) {
  NiceMock<MockDelegate> DummyDelegate;
  MockProcess Process(DummyDelegate, ArchSpec("x86_64-pc-linux"));
  auto Trap = cantFail(Process.GetSoftwareBreakpointTrapOpcode(1));
  InSequence S;
  EXPECT_CALL(Process, ReadMemory(0x47, 1))
      .WillOnce(Return(ByMove(std::vector<uint8_t>{0xbb})));
  EXPECT_CALL(Process, WriteMemory(0x47, Trap)).WillOnce(Return(ByMove(1)));
  EXPECT_CALL(Process, ReadMemory(0x47, 1)).WillOnce(Return(ByMove(Trap)));
  EXPECT_THAT_ERROR(Process.SetBreakpoint(0x47, 0, false).ToError(),
                    llvm::Succeeded());
}

TEST(NativeProcessProtocolTest, SetBreakpointFailRead) {
  NiceMock<MockDelegate> DummyDelegate;
  MockProcess Process(DummyDelegate, ArchSpec("x86_64-pc-linux"));
  EXPECT_CALL(Process, ReadMemory(0x47, 1))
      .WillOnce(Return(ByMove(
          llvm::createStringError(llvm::inconvertibleErrorCode(), "Foo"))));
  EXPECT_THAT_ERROR(Process.SetBreakpoint(0x47, 0, false).ToError(),
                    llvm::Failed());
}

TEST(NativeProcessProtocolTest, SetBreakpointFailWrite) {
  NiceMock<MockDelegate> DummyDelegate;
  MockProcess Process(DummyDelegate, ArchSpec("x86_64-pc-linux"));
  auto Trap = cantFail(Process.GetSoftwareBreakpointTrapOpcode(1));
  InSequence S;
  EXPECT_CALL(Process, ReadMemory(0x47, 1))
      .WillOnce(Return(ByMove(std::vector<uint8_t>{0xbb})));
  EXPECT_CALL(Process, WriteMemory(0x47, Trap))
      .WillOnce(Return(ByMove(
          llvm::createStringError(llvm::inconvertibleErrorCode(), "Foo"))));
  EXPECT_THAT_ERROR(Process.SetBreakpoint(0x47, 0, false).ToError(),
                    llvm::Failed());
}

TEST(NativeProcessProtocolTest, SetBreakpointFailVerify) {
  NiceMock<MockDelegate> DummyDelegate;
  MockProcess Process(DummyDelegate, ArchSpec("x86_64-pc-linux"));
  auto Trap = cantFail(Process.GetSoftwareBreakpointTrapOpcode(1));
  InSequence S;
  EXPECT_CALL(Process, ReadMemory(0x47, 1))
      .WillOnce(Return(ByMove(std::vector<uint8_t>{0xbb})));
  EXPECT_CALL(Process, WriteMemory(0x47, Trap)).WillOnce(Return(ByMove(1)));
  EXPECT_CALL(Process, ReadMemory(0x47, 1))
      .WillOnce(Return(ByMove(
          llvm::createStringError(llvm::inconvertibleErrorCode(), "Foo"))));
  EXPECT_THAT_ERROR(Process.SetBreakpoint(0x47, 0, false).ToError(),
                    llvm::Failed());
}

TEST(NativeProcessProtocolTest, ReadMemoryWithoutTrap) {
  NiceMock<MockDelegate> DummyDelegate;
  MockProcess Process(DummyDelegate, ArchSpec("aarch64-pc-linux"));
  FakeMemory M{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}};
  EXPECT_CALL(Process, ReadMemory(_, _))
      .WillRepeatedly(Invoke(&M, &FakeMemory::Read));
  EXPECT_CALL(Process, WriteMemory(_, _))
      .WillRepeatedly(Invoke(&M, &FakeMemory::Write));

  EXPECT_THAT_ERROR(Process.SetBreakpoint(0x4, 0, false).ToError(),
                    llvm::Succeeded());
  EXPECT_THAT_EXPECTED(
      Process.ReadMemoryWithoutTrap(0, 10),
      llvm::HasValue(std::vector<uint8_t>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}));
  EXPECT_THAT_EXPECTED(Process.ReadMemoryWithoutTrap(0, 6),
                       llvm::HasValue(std::vector<uint8_t>{0, 1, 2, 3, 4, 5}));
  EXPECT_THAT_EXPECTED(Process.ReadMemoryWithoutTrap(6, 4),
                       llvm::HasValue(std::vector<uint8_t>{6, 7, 8, 9}));
  EXPECT_THAT_EXPECTED(Process.ReadMemoryWithoutTrap(6, 2),
                       llvm::HasValue(std::vector<uint8_t>{6, 7}));
  EXPECT_THAT_EXPECTED(Process.ReadMemoryWithoutTrap(4, 2),
                       llvm::HasValue(std::vector<uint8_t>{4, 5}));
}
<|endoftext|>


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

// NOLINT(namespace-envoy)
#include "proxy_wasm_intrinsics.h"

// Required Proxy-Wasm ABI version.
extern "C" PROXY_WASM_KEEPALIVE void proxy_abi_version_0_2_0() {}

static std::unordered_map<std::string, RootFactory> *root_factories = nullptr;
static std::unordered_map<std::string, ContextFactory> *context_factories = nullptr;
static std::unordered_map<int32_t, std::unique_ptr<ContextBase>> context_map;
static std::unordered_map<std::string, RootContext *> root_context_map;

RegisterContextFactory::RegisterContextFactory(ContextFactory context_factory,
                                               RootFactory root_factory, std::string_view root_id) {
  if (!root_factories) {
    root_factories = new std::unordered_map<std::string, RootFactory>;
    context_factories = new std::unordered_map<std::string, ContextFactory>;
  }
  if (context_factory)
    (*context_factories)[std::string(root_id)] = context_factory;
  if (root_factory)
    (*root_factories)[std::string(root_id)] = root_factory;
}

static Context *ensureContext(uint32_t context_id, uint32_t root_context_id) {
  auto e = context_map.insert(std::make_pair(context_id, nullptr));
  if (e.second) {
    RootContext *root = context_map[root_context_id].get()->asRoot();
    std::string root_id = std::string(root->root_id());
    if (!context_factories) {
      e.first->second = std::make_unique<Context>(context_id, root);
      return e.first->second->asContext();
    }
    auto factory = context_factories->find(root_id);
    if (factory == context_factories->end()) {
      e.first->second = std::make_unique<Context>(context_id, root);
      return e.first->second->asContext();
    } else {
      e.first->second = factory->second(context_id, root);
    }
  }
  return e.first->second->asContext();
}

static RootContext *ensureRootContext(uint32_t context_id) {
  auto it = context_map.find(context_id);
  if (it != context_map.end()) {
    return it->second->asRoot();
  }
  const char *root_id_ptr = nullptr;
  size_t root_id_size = 0;
  CHECK_RESULT(proxy_get_property("plugin_root_id", sizeof("plugin_root_id") - 1, &root_id_ptr,
                                  &root_id_size));
  auto root_id = std::make_unique<WasmData>(root_id_ptr, root_id_size);
  auto root_id_string = root_id->toString();
  if (!root_factories) {
    auto context = std::make_unique<RootContext>(context_id, root_id->view());
    RootContext *root_context = context->asRoot();
    context_map[context_id] = std::move(context);
    root_context_map[root_id_string] = root_context;
    return root_context;
  }
  auto factory = root_factories->find(root_id_string);
  RootContext *root_context;
  if (factory != root_factories->end()) {
    auto context = factory->second(context_id, root_id->view());
    root_context = context->asRoot();
    root_context_map[root_id_string] = root_context;
    context_map[context_id] = std::move(context);
  } else {
    auto context = std::make_unique<RootContext>(context_id, root_id->view());
    root_context = context->asRoot();
    context_map[context_id] = std::move(context);
    root_context_map[root_id_string] = root_context;
  }
  return root_context;
}

ContextBase *getContextBase(uint32_t context_id) {
  auto it = context_map.find(context_id);
  if (it == context_map.end()) {
    return nullptr;
  }
  return it->second.get();
}

Context *getContext(uint32_t context_id) {
  auto it = context_map.find(context_id);
  if (it == context_map.end() || !it->second->asContext()) {
    return nullptr;
  }
  return it->second->asContext();
}

RootContext *getRootContext(uint32_t context_id) {
  auto it = context_map.find(context_id);
  if (it == context_map.end() || !it->second->asRoot()) {
    return nullptr;
  }
  return it->second->asRoot();
}

RootContext *getRoot(std::string_view root_id) {
  auto it = root_context_map.find(std::string(root_id));
  if (it != root_context_map.end()) {
    return it->second;
  }
  return nullptr;
}

extern "C" PROXY_WASM_KEEPALIVE uint32_t proxy_on_vm_start(uint32_t root_context_id,
                                                           uint32_t vm_configuration_size) {
  return getRootContext(root_context_id)->onStart(vm_configuration_size);
}

extern "C" PROXY_WASM_KEEPALIVE uint32_t proxy_validate_configuration(uint32_t root_context_id,
                                                                      uint32_t configuration_size) {
  return getRootContext(root_context_id)->validateConfiguration(configuration_size) ? 1 : 0;
}

extern "C" PROXY_WASM_KEEPALIVE uint32_t proxy_on_configure(uint32_t root_context_id,
                                                            uint32_t configuration_size) {
  return getRootContext(root_context_id)->onConfigure(configuration_size) ? 1 : 0;
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_tick(uint32_t root_context_id) {
  getRootContext(root_context_id)->onTick();
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_context_create(uint32_t context_id,
                                                             uint32_t parent_context_id) {
  if (parent_context_id) {
    ensureContext(context_id, parent_context_id)->onCreate();
  } else {
    ensureRootContext(context_id)->onCreate();
  }
}

extern "C" PROXY_WASM_KEEPALIVE FilterStatus proxy_on_new_connection(uint32_t context_id) {
  return getContext(context_id)->onNewConnection();
}

extern "C" PROXY_WASM_KEEPALIVE FilterStatus proxy_on_downstream_data(uint32_t context_id,
                                                                      uint32_t data_length,
                                                                      uint32_t end_of_stream) {
  return getContext(context_id)
      ->onDownstreamData(static_cast<size_t>(data_length), end_of_stream != 0);
}

extern "C" PROXY_WASM_KEEPALIVE FilterStatus proxy_on_upstream_data(uint32_t context_id,
                                                                    uint32_t data_length,
                                                                    uint32_t end_of_stream) {
  return getContext(context_id)
      ->onUpstreamData(static_cast<size_t>(data_length), end_of_stream != 0);
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_downstream_connection_close(uint32_t context_id,
                                                                          uint32_t close_type) {
  return getContext(context_id)->onDownstreamConnectionClose(static_cast<CloseType>(close_type));
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_upstream_connection_close(uint32_t context_id,
                                                                        uint32_t close_type) {
  return getContext(context_id)->onUpstreamConnectionClose(static_cast<CloseType>(close_type));
}

extern "C" PROXY_WASM_KEEPALIVE FilterHeadersStatus
proxy_on_request_headers(uint32_t context_id, uint32_t headers, uint32_t end_of_stream) {
  return getContext(context_id)->onRequestHeaders(headers, end_of_stream != 0);
}

extern "C" PROXY_WASM_KEEPALIVE FilterMetadataStatus proxy_on_request_metadata(uint32_t context_id,
                                                                               uint32_t elements) {
  return getContext(context_id)->onRequestMetadata(elements);
}

extern "C" PROXY_WASM_KEEPALIVE FilterDataStatus proxy_on_request_body(uint32_t context_id,
                                                                       uint32_t body_buffer_length,
                                                                       uint32_t end_of_stream) {
  return getContext(context_id)
      ->onRequestBody(static_cast<size_t>(body_buffer_length), end_of_stream != 0);
}

extern "C" PROXY_WASM_KEEPALIVE FilterTrailersStatus proxy_on_request_trailers(uint32_t context_id,
                                                                               uint32_t trailers) {
  return getContext(context_id)->onRequestTrailers(trailers);
}

extern "C" PROXY_WASM_KEEPALIVE FilterHeadersStatus
proxy_on_response_headers(uint32_t context_id, uint32_t headers, uint32_t end_of_stream) {
  return getContext(context_id)->onResponseHeaders(headers, end_of_stream != 0);
}

extern "C" PROXY_WASM_KEEPALIVE FilterMetadataStatus proxy_on_response_metadata(uint32_t context_id,
                                                                                uint32_t elements) {
  return getContext(context_id)->onResponseMetadata(elements);
}

extern "C" PROXY_WASM_KEEPALIVE FilterDataStatus proxy_on_response_body(uint32_t context_id,
                                                                        uint32_t body_buffer_length,
                                                                        uint32_t end_of_stream) {
  return getContext(context_id)
      ->onResponseBody(static_cast<size_t>(body_buffer_length), end_of_stream != 0);
}

extern "C" PROXY_WASM_KEEPALIVE FilterTrailersStatus proxy_on_response_trailers(uint32_t context_id,
                                                                                uint32_t trailers) {
  return getContext(context_id)->onResponseTrailers(trailers);
}

extern "C" PROXY_WASM_KEEPALIVE uint32_t proxy_on_done(uint32_t context_id) {
  return getContextBase(context_id)->onDoneBase();
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_log(uint32_t context_id) {
  getContext(context_id)->onLog();
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_delete(uint32_t context_id) {
  getContextBase(context_id)->onDelete();
  context_map.erase(context_id);
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_http_call_response(uint32_t context_id,
                                                                 uint32_t token, uint32_t headers,
                                                                 uint32_t body_size,
                                                                 uint32_t trailers) {
  getRootContext(context_id)
      ->onHttpCallResponse(token, headers, static_cast<size_t>(body_size), trailers);
}

extern "C" PROXY_WASM_KEEPALIVE void
proxy_on_grpc_receive_initial_metadata(uint32_t context_id, uint32_t token, uint32_t headers) {
  getRootContext(context_id)->onGrpcReceiveInitialMetadata(token, headers);
}

extern "C" PROXY_WASM_KEEPALIVE void
proxy_on_grpc_receive_trailing_metadata(uint32_t context_id, uint32_t token, uint32_t trailers) {
  getRootContext(context_id)->onGrpcReceiveTrailingMetadata(token, trailers);
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_grpc_receive(uint32_t context_id, uint32_t token,
                                                           uint32_t response_size) {
  getRootContext(context_id)->onGrpcReceive(token, static_cast<size_t>(response_size));
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_grpc_close(uint32_t context_id, uint32_t token,
                                                         uint32_t status_code) {
  getRootContext(context_id)->onGrpcClose(token, static_cast<GrpcStatus>(status_code));
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_queue_ready(uint32_t context_id, uint32_t token) {
  getRootContext(context_id)->onQueueReady(token);
}

extern "C" PROXY_WASM_KEEPALIVE void
proxy_on_foreign_function(uint32_t context_id, uint32_t foreign_function_id, uint32_t data_size) {
  getContextBase(context_id)->onForeignFunction(foreign_function_id, data_size);
}
<commit_msg>Change ABI version to 0.2.1 (#45)<commit_after>// Copyright 2016-2019 Envoy Project Authors
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// NOLINT(namespace-envoy)
#include "proxy_wasm_intrinsics.h"

// Required Proxy-Wasm ABI version.
extern "C" PROXY_WASM_KEEPALIVE void proxy_abi_version_0_2_1() {}

static std::unordered_map<std::string, RootFactory> *root_factories = nullptr;
static std::unordered_map<std::string, ContextFactory> *context_factories = nullptr;
static std::unordered_map<int32_t, std::unique_ptr<ContextBase>> context_map;
static std::unordered_map<std::string, RootContext *> root_context_map;

RegisterContextFactory::RegisterContextFactory(ContextFactory context_factory,
                                               RootFactory root_factory, std::string_view root_id) {
  if (!root_factories) {
    root_factories = new std::unordered_map<std::string, RootFactory>;
    context_factories = new std::unordered_map<std::string, ContextFactory>;
  }
  if (context_factory)
    (*context_factories)[std::string(root_id)] = context_factory;
  if (root_factory)
    (*root_factories)[std::string(root_id)] = root_factory;
}

static Context *ensureContext(uint32_t context_id, uint32_t root_context_id) {
  auto e = context_map.insert(std::make_pair(context_id, nullptr));
  if (e.second) {
    RootContext *root = context_map[root_context_id].get()->asRoot();
    std::string root_id = std::string(root->root_id());
    if (!context_factories) {
      e.first->second = std::make_unique<Context>(context_id, root);
      return e.first->second->asContext();
    }
    auto factory = context_factories->find(root_id);
    if (factory == context_factories->end()) {
      e.first->second = std::make_unique<Context>(context_id, root);
      return e.first->second->asContext();
    } else {
      e.first->second = factory->second(context_id, root);
    }
  }
  return e.first->second->asContext();
}

static RootContext *ensureRootContext(uint32_t context_id) {
  auto it = context_map.find(context_id);
  if (it != context_map.end()) {
    return it->second->asRoot();
  }
  const char *root_id_ptr = nullptr;
  size_t root_id_size = 0;
  CHECK_RESULT(proxy_get_property("plugin_root_id", sizeof("plugin_root_id") - 1, &root_id_ptr,
                                  &root_id_size));
  auto root_id = std::make_unique<WasmData>(root_id_ptr, root_id_size);
  auto root_id_string = root_id->toString();
  if (!root_factories) {
    auto context = std::make_unique<RootContext>(context_id, root_id->view());
    RootContext *root_context = context->asRoot();
    context_map[context_id] = std::move(context);
    root_context_map[root_id_string] = root_context;
    return root_context;
  }
  auto factory = root_factories->find(root_id_string);
  RootContext *root_context;
  if (factory != root_factories->end()) {
    auto context = factory->second(context_id, root_id->view());
    root_context = context->asRoot();
    root_context_map[root_id_string] = root_context;
    context_map[context_id] = std::move(context);
  } else {
    auto context = std::make_unique<RootContext>(context_id, root_id->view());
    root_context = context->asRoot();
    context_map[context_id] = std::move(context);
    root_context_map[root_id_string] = root_context;
  }
  return root_context;
}

ContextBase *getContextBase(uint32_t context_id) {
  auto it = context_map.find(context_id);
  if (it == context_map.end()) {
    return nullptr;
  }
  return it->second.get();
}

Context *getContext(uint32_t context_id) {
  auto it = context_map.find(context_id);
  if (it == context_map.end() || !it->second->asContext()) {
    return nullptr;
  }
  return it->second->asContext();
}

RootContext *getRootContext(uint32_t context_id) {
  auto it = context_map.find(context_id);
  if (it == context_map.end() || !it->second->asRoot()) {
    return nullptr;
  }
  return it->second->asRoot();
}

RootContext *getRoot(std::string_view root_id) {
  auto it = root_context_map.find(std::string(root_id));
  if (it != root_context_map.end()) {
    return it->second;
  }
  return nullptr;
}

extern "C" PROXY_WASM_KEEPALIVE uint32_t proxy_on_vm_start(uint32_t root_context_id,
                                                           uint32_t vm_configuration_size) {
  return getRootContext(root_context_id)->onStart(vm_configuration_size);
}

extern "C" PROXY_WASM_KEEPALIVE uint32_t proxy_validate_configuration(uint32_t root_context_id,
                                                                      uint32_t configuration_size) {
  return getRootContext(root_context_id)->validateConfiguration(configuration_size) ? 1 : 0;
}

extern "C" PROXY_WASM_KEEPALIVE uint32_t proxy_on_configure(uint32_t root_context_id,
                                                            uint32_t configuration_size) {
  return getRootContext(root_context_id)->onConfigure(configuration_size) ? 1 : 0;
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_tick(uint32_t root_context_id) {
  getRootContext(root_context_id)->onTick();
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_context_create(uint32_t context_id,
                                                             uint32_t parent_context_id) {
  if (parent_context_id) {
    ensureContext(context_id, parent_context_id)->onCreate();
  } else {
    ensureRootContext(context_id)->onCreate();
  }
}

extern "C" PROXY_WASM_KEEPALIVE FilterStatus proxy_on_new_connection(uint32_t context_id) {
  return getContext(context_id)->onNewConnection();
}

extern "C" PROXY_WASM_KEEPALIVE FilterStatus proxy_on_downstream_data(uint32_t context_id,
                                                                      uint32_t data_length,
                                                                      uint32_t end_of_stream) {
  return getContext(context_id)
      ->onDownstreamData(static_cast<size_t>(data_length), end_of_stream != 0);
}

extern "C" PROXY_WASM_KEEPALIVE FilterStatus proxy_on_upstream_data(uint32_t context_id,
                                                                    uint32_t data_length,
                                                                    uint32_t end_of_stream) {
  return getContext(context_id)
      ->onUpstreamData(static_cast<size_t>(data_length), end_of_stream != 0);
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_downstream_connection_close(uint32_t context_id,
                                                                          uint32_t close_type) {
  return getContext(context_id)->onDownstreamConnectionClose(static_cast<CloseType>(close_type));
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_upstream_connection_close(uint32_t context_id,
                                                                        uint32_t close_type) {
  return getContext(context_id)->onUpstreamConnectionClose(static_cast<CloseType>(close_type));
}

extern "C" PROXY_WASM_KEEPALIVE FilterHeadersStatus
proxy_on_request_headers(uint32_t context_id, uint32_t headers, uint32_t end_of_stream) {
  return getContext(context_id)->onRequestHeaders(headers, end_of_stream != 0);
}

extern "C" PROXY_WASM_KEEPALIVE FilterMetadataStatus proxy_on_request_metadata(uint32_t context_id,
                                                                               uint32_t elements) {
  return getContext(context_id)->onRequestMetadata(elements);
}

extern "C" PROXY_WASM_KEEPALIVE FilterDataStatus proxy_on_request_body(uint32_t context_id,
                                                                       uint32_t body_buffer_length,
                                                                       uint32_t end_of_stream) {
  return getContext(context_id)
      ->onRequestBody(static_cast<size_t>(body_buffer_length), end_of_stream != 0);
}

extern "C" PROXY_WASM_KEEPALIVE FilterTrailersStatus proxy_on_request_trailers(uint32_t context_id,
                                                                               uint32_t trailers) {
  return getContext(context_id)->onRequestTrailers(trailers);
}

extern "C" PROXY_WASM_KEEPALIVE FilterHeadersStatus
proxy_on_response_headers(uint32_t context_id, uint32_t headers, uint32_t end_of_stream) {
  return getContext(context_id)->onResponseHeaders(headers, end_of_stream != 0);
}

extern "C" PROXY_WASM_KEEPALIVE FilterMetadataStatus proxy_on_response_metadata(uint32_t context_id,
                                                                                uint32_t elements) {
  return getContext(context_id)->onResponseMetadata(elements);
}

extern "C" PROXY_WASM_KEEPALIVE FilterDataStatus proxy_on_response_body(uint32_t context_id,
                                                                        uint32_t body_buffer_length,
                                                                        uint32_t end_of_stream) {
  return getContext(context_id)
      ->onResponseBody(static_cast<size_t>(body_buffer_length), end_of_stream != 0);
}

extern "C" PROXY_WASM_KEEPALIVE FilterTrailersStatus proxy_on_response_trailers(uint32_t context_id,
                                                                                uint32_t trailers) {
  return getContext(context_id)->onResponseTrailers(trailers);
}

extern "C" PROXY_WASM_KEEPALIVE uint32_t proxy_on_done(uint32_t context_id) {
  return getContextBase(context_id)->onDoneBase();
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_log(uint32_t context_id) {
  getContext(context_id)->onLog();
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_delete(uint32_t context_id) {
  getContextBase(context_id)->onDelete();
  context_map.erase(context_id);
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_http_call_response(uint32_t context_id,
                                                                 uint32_t token, uint32_t headers,
                                                                 uint32_t body_size,
                                                                 uint32_t trailers) {
  getRootContext(context_id)
      ->onHttpCallResponse(token, headers, static_cast<size_t>(body_size), trailers);
}

extern "C" PROXY_WASM_KEEPALIVE void
proxy_on_grpc_receive_initial_metadata(uint32_t context_id, uint32_t token, uint32_t headers) {
  getRootContext(context_id)->onGrpcReceiveInitialMetadata(token, headers);
}

extern "C" PROXY_WASM_KEEPALIVE void
proxy_on_grpc_receive_trailing_metadata(uint32_t context_id, uint32_t token, uint32_t trailers) {
  getRootContext(context_id)->onGrpcReceiveTrailingMetadata(token, trailers);
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_grpc_receive(uint32_t context_id, uint32_t token,
                                                           uint32_t response_size) {
  getRootContext(context_id)->onGrpcReceive(token, static_cast<size_t>(response_size));
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_grpc_close(uint32_t context_id, uint32_t token,
                                                         uint32_t status_code) {
  getRootContext(context_id)->onGrpcClose(token, static_cast<GrpcStatus>(status_code));
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_queue_ready(uint32_t context_id, uint32_t token) {
  getRootContext(context_id)->onQueueReady(token);
}

extern "C" PROXY_WASM_KEEPALIVE void
proxy_on_foreign_function(uint32_t context_id, uint32_t foreign_function_id, uint32_t data_size) {
  getContextBase(context_id)->onForeignFunction(foreign_function_id, data_size);
}
<|endoftext|>


<commit_before>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2015 Francois Beaune, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "projectbuilder.h"

// appleseed-max headers.
#include "maxsceneentities.h"
#include "utilities.h"

// appleseed.renderer headers.
#include "renderer/api/camera.h"
#include "renderer/api/environment.h"
#include "renderer/api/frame.h"
#include "renderer/api/object.h"
#include "renderer/api/project.h"
#include "renderer/api/scene.h"
#include "renderer/api/utility.h"

// appleseed.foundation headers.
#include "foundation/math/scalar.h"
#include "foundation/math/transform.h"
#include "foundation/platform/compiler.h"
#include "foundation/utility/containers/dictionary.h"

// 3ds Max headers.
#include <bitmap.h>
#include <object.h>
#include <render.h>
#include <triobj.h>

// Standard headers.
#include <cassert>
#include <cstddef>
#include <limits>
#include <string>
#include <vector>

namespace asf = foundation;
namespace asr = renderer;

namespace
{
    asf::auto_release_ptr<asr::Camera> build_camera(
        INode*                  view_node,
        const ViewParams&       view_params,
        Bitmap*                 bitmap,
        const TimeValue         time)
    {
        asr::ParamArray params;

        if (view_params.projType == PROJ_PERSPECTIVE)
        {
            params.insert("film_dimensions", make_vec_string(bitmap->Width(), bitmap->Height()));
            params.insert("horizontal_fov", asf::rad_to_deg(view_params.fov));
        }
        else
        {
            assert(view_params.projType == PROJ_PARALLEL);

            const float ViewDefaultWidth = 400.0f;
            const float aspect = static_cast<float>(bitmap->Height()) / bitmap->Width();
            const float film_width = ViewDefaultWidth * view_params.zoom;
            const float film_height = film_width * aspect;
            params.insert("film_dimensions", make_vec_string(film_width, film_height));
        }

        asf::Matrix4d camera_matrix = max_to_as(Inverse(view_params.affineTM));

        if (view_node)
        {
            const ObjectState& os = view_node->EvalWorldState(time);
            switch (os.obj->SuperClassID())
            {
              case CAMERA_CLASS_ID:
                {
                    CameraObject* cam = static_cast<CameraObject*>(os.obj);

                    Interval validity_interval;
                    validity_interval.SetInfinite();

                    Matrix3 cam_to_world = view_node->GetObjTMAfterWSM(time, &validity_interval);
                    cam_to_world.NoScale();
                    camera_matrix = max_to_as(cam_to_world);

                    CameraState cam_state;
                    cam->EvalCameraState(time, validity_interval, &cam_state);

                    if (cam_state.manualClip)
                        params.insert("near_z", cam_state.hither);
                }
                break;

              case LIGHT_CLASS_ID:
                {
                    // todo: implement.
                }
                break;

              default:
                assert(!"Unexpected super class ID  for camera.");
            }
        }

        asf::auto_release_ptr<renderer::Camera> camera =
            view_params.projType == PROJ_PERSPECTIVE
                ? asr::PinholeCameraFactory().create("camera", params)
                : asr::OrthographicCameraFactory().create("camera", params);

        camera->transform_sequence().set_transform(
            0.0, asf::Transformd::from_local_to_parent(camera_matrix));

        return camera;
    }

    TriObject* get_tri_object_from_node(
        const ObjectState&      object_state,
        const TimeValue         time,
        bool&                   must_delete)
    {
        assert(object_state.obj);

        must_delete = false;

        const Class_ID TriObjectClassID(TRIOBJ_CLASS_ID, 0);

        if (!object_state.obj->CanConvertToType(TriObjectClassID))
            return 0;

        TriObject* tri_object = static_cast<TriObject*>(object_state.obj->ConvertToType(time, TriObjectClassID));
        must_delete = tri_object != object_state.obj;

        return tri_object;
    }

    void add_object(
        asr::Assembly&          assembly,
        INode*                  node,
        const TimeValue         time)
    {
        // Retrieve the name of the referenced object.
        Object* max_object = node->GetObjectRef();
        const std::string object_name = utf8_encode(max_object->GetObjectName());

        // Create the object if it doesn't already exist in the appleseed scene.
        if (assembly.objects().get_by_name(object_name.c_str()) == 0)
        {
            // Retrieve the ObjectState at the desired time.
            const ObjectState object_state = node->EvalWorldState(time);

            // Convert the object to a TriObject.
            bool must_delete_tri_object;
            TriObject* tri_object = get_tri_object_from_node(object_state, time, must_delete_tri_object);
            if (tri_object == 0)
            {
                // todo: emit a message?
                return;
            }

            // Create a new mesh object.
            asf::auto_release_ptr<asr::MeshObject> object(
                asr::MeshObjectFactory::create(object_name.c_str(), asr::ParamArray()));
            {
                Mesh& mesh = tri_object->GetMesh();

                // Copy vertices to the mesh object.
                object->reserve_vertices(mesh.getNumVerts());
                for (int i = 0, e = mesh.getNumVerts(); i < e; ++i)
                {
                    const Point3& v = mesh.getVert(i);
                    //object->push_vertex(max_to_as(v));
                    object->push_vertex(asf::Vector3d(v.x, v.y, v.z));
                }

                // Copy triangles to mesh object.
                object->reserve_triangles(mesh.getNumFaces());
                for (int i = 0, e = mesh.getNumFaces(); i < e; ++i)
                {
                    Face& face = mesh.faces[i];
                    const asr::Triangle triangle(
                        face.getVert(0),
                        face.getVert(1),
                        face.getVert(2));
                    object->push_triangle(triangle);
                }

                // Delete the TriObject if necessary.
                if (must_delete_tri_object)
                    tri_object->DeleteMe();
            }

            // Insert the object into the assembly.
            assembly.objects().insert(asf::auto_release_ptr<asr::Object>(object));
        }

        // Figure out a unique name for this instance.
        std::string instance_name = utf8_encode(node->GetName());
        if (assembly.object_instances().get_by_name(instance_name.c_str()) != 0)
            instance_name = asr::make_unique_name(instance_name, assembly.object_instances());

        // Create an instance of the object and insert it into the assembly.
        assembly.object_instances().insert(
            asr::ObjectInstanceFactory::create(
                instance_name.c_str(),
                asr::ParamArray(),
                object_name.c_str(),
                asf::Transformd::from_local_to_parent(
                    max_to_as(node->GetObjTMAfterWSM(time))),
                asf::StringDictionary()));
    }

    void populate_assembly(
        asr::Assembly&          assembly,
        const MaxSceneEntities& entities,
        const TimeValue         time)
    {
        for (size_t i = 0, e = entities.m_instances.size(); i < e; ++i)
            add_object(assembly, entities.m_instances[i], time);
    }
}

asf::auto_release_ptr<asr::Project> build_project(
    const MaxSceneEntities&     entities,
    INode*                      view_node,
    const ViewParams&           view_params,
    Bitmap*                     bitmap,
    const TimeValue             time)
{
    // Create an empty project.
    asf::auto_release_ptr<asr::Project> project(
        asr::ProjectFactory::create("project"));

    // Add default configurations to the project.
    project->add_default_configurations();

    // Set the number of samples.
    project->configurations()
        .get_by_name("final")->get_parameters()
            .insert_path("uniform_pixel_renderer.samples", "1");

    // Create a scene.
    asf::auto_release_ptr<asr::Scene> scene(asr::SceneFactory::create());

    // Create an assembly.
    asf::auto_release_ptr<asr::Assembly> assembly(
        asr::AssemblyFactory().create("assembly", asr::ParamArray()));

    // Populate the assembly with entities from the 3ds Max scene.
    populate_assembly(assembly.ref(), entities, time);

    // Create an instance of the assembly and insert it into the scene.
    asf::auto_release_ptr<asr::AssemblyInstance> assembly_instance(
        asr::AssemblyInstanceFactory::create(
            "assembly_inst",
            asr::ParamArray(),
            "assembly"));
    assembly_instance
        ->transform_sequence()
            .set_transform(0.0, asf::Transformd::identity());
    scene->assembly_instances().insert(assembly_instance);

    // Insert the assembly into the scene.
    scene->assemblies().insert(assembly);

    // Create a default environment and bind it to the scene.
    scene->set_environment(
        asr::EnvironmentFactory::create("environment", asr::ParamArray()));

    // Create a camera.
    scene->set_camera(
        build_camera(
            view_node,
            view_params,
            bitmap,
            time));

    // Create a frame and bind it to the project.
    project->set_frame(
        asr::FrameFactory::create(
            "beauty",
            asr::ParamArray()
                .insert("camera", scene->get_camera()->get_name())
                .insert("resolution", make_vec_string(bitmap->Width(), bitmap->Height()))
                .insert("color_space", "linear_rgb")));

    // Bind the scene to the project.
    project->set_scene(scene);

    return project;
}
<commit_msg>Temporarily disable broken instancing support<commit_after>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2015 Francois Beaune, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "projectbuilder.h"

// appleseed-max headers.
#include "maxsceneentities.h"
#include "utilities.h"

// appleseed.renderer headers.
#include "renderer/api/camera.h"
#include "renderer/api/environment.h"
#include "renderer/api/frame.h"
#include "renderer/api/object.h"
#include "renderer/api/project.h"
#include "renderer/api/scene.h"
#include "renderer/api/utility.h"

// appleseed.foundation headers.
#include "foundation/math/scalar.h"
#include "foundation/math/transform.h"
#include "foundation/platform/compiler.h"
#include "foundation/utility/containers/dictionary.h"

// 3ds Max headers.
#include <bitmap.h>
#include <object.h>
#include <render.h>
#include <triobj.h>

// Standard headers.
#include <cassert>
#include <cstddef>
#include <limits>
#include <string>
#include <vector>

namespace asf = foundation;
namespace asr = renderer;

namespace
{
    asf::auto_release_ptr<asr::Camera> build_camera(
        INode*                  view_node,
        const ViewParams&       view_params,
        Bitmap*                 bitmap,
        const TimeValue         time)
    {
        asr::ParamArray params;

        if (view_params.projType == PROJ_PERSPECTIVE)
        {
            params.insert("film_dimensions", make_vec_string(bitmap->Width(), bitmap->Height()));
            params.insert("horizontal_fov", asf::rad_to_deg(view_params.fov));
        }
        else
        {
            assert(view_params.projType == PROJ_PARALLEL);

            const float ViewDefaultWidth = 400.0f;
            const float aspect = static_cast<float>(bitmap->Height()) / bitmap->Width();
            const float film_width = ViewDefaultWidth * view_params.zoom;
            const float film_height = film_width * aspect;
            params.insert("film_dimensions", make_vec_string(film_width, film_height));
        }

        asf::Matrix4d camera_matrix = max_to_as(Inverse(view_params.affineTM));

        if (view_node)
        {
            const ObjectState& os = view_node->EvalWorldState(time);
            switch (os.obj->SuperClassID())
            {
              case CAMERA_CLASS_ID:
                {
                    CameraObject* cam = static_cast<CameraObject*>(os.obj);

                    Interval validity_interval;
                    validity_interval.SetInfinite();

                    Matrix3 cam_to_world = view_node->GetObjTMAfterWSM(time, &validity_interval);
                    cam_to_world.NoScale();
                    camera_matrix = max_to_as(cam_to_world);

                    CameraState cam_state;
                    cam->EvalCameraState(time, validity_interval, &cam_state);

                    if (cam_state.manualClip)
                        params.insert("near_z", cam_state.hither);
                }
                break;

              case LIGHT_CLASS_ID:
                {
                    // todo: implement.
                }
                break;

              default:
                assert(!"Unexpected super class ID  for camera.");
            }
        }

        asf::auto_release_ptr<renderer::Camera> camera =
            view_params.projType == PROJ_PERSPECTIVE
                ? asr::PinholeCameraFactory().create("camera", params)
                : asr::OrthographicCameraFactory().create("camera", params);

        camera->transform_sequence().set_transform(
            0.0, asf::Transformd::from_local_to_parent(camera_matrix));

        return camera;
    }

    TriObject* get_tri_object_from_node(
        const ObjectState&      object_state,
        const TimeValue         time,
        bool&                   must_delete)
    {
        assert(object_state.obj);

        must_delete = false;

        const Class_ID TriObjectClassID(TRIOBJ_CLASS_ID, 0);

        if (!object_state.obj->CanConvertToType(TriObjectClassID))
            return 0;

        TriObject* tri_object = static_cast<TriObject*>(object_state.obj->ConvertToType(time, TriObjectClassID));
        must_delete = tri_object != object_state.obj;

        return tri_object;
    }

    void add_object(
        asr::Assembly&          assembly,
        INode*                  node,
        const TimeValue         time)
    {
        // Retrieve the name of the referenced object.
        Object* max_object = node->GetObjectRef();
        std::string object_name = utf8_encode(max_object->GetObjectName());

        // todo: handle instancing.
        if (assembly.objects().get_by_name(object_name.c_str()) != 0)
            object_name = asr::make_unique_name(object_name, assembly.objects());

        // Create the object if it doesn't already exist in the appleseed scene.
        if (assembly.objects().get_by_name(object_name.c_str()) == 0)
        {
            // Retrieve the ObjectState at the desired time.
            const ObjectState object_state = node->EvalWorldState(time);

            // Convert the object to a TriObject.
            bool must_delete_tri_object;
            TriObject* tri_object = get_tri_object_from_node(object_state, time, must_delete_tri_object);
            if (tri_object == 0)
            {
                // todo: emit a message?
                return;
            }

            // Create a new mesh object.
            asf::auto_release_ptr<asr::MeshObject> object(
                asr::MeshObjectFactory::create(object_name.c_str(), asr::ParamArray()));
            {
                Mesh& mesh = tri_object->GetMesh();

                // Copy vertices to the mesh object.
                object->reserve_vertices(mesh.getNumVerts());
                for (int i = 0, e = mesh.getNumVerts(); i < e; ++i)
                {
                    const Point3& v = mesh.getVert(i);
                    //object->push_vertex(max_to_as(v));
                    object->push_vertex(asf::Vector3d(v.x, v.y, v.z));
                }

                // Copy triangles to mesh object.
                object->reserve_triangles(mesh.getNumFaces());
                for (int i = 0, e = mesh.getNumFaces(); i < e; ++i)
                {
                    Face& face = mesh.faces[i];
                    const asr::Triangle triangle(
                        face.getVert(0),
                        face.getVert(1),
                        face.getVert(2));
                    object->push_triangle(triangle);
                }

                // Delete the TriObject if necessary.
                if (must_delete_tri_object)
                    tri_object->DeleteMe();
            }

            // Insert the object into the assembly.
            assembly.objects().insert(asf::auto_release_ptr<asr::Object>(object));
        }

        // Figure out a unique name for this instance.
        std::string instance_name = utf8_encode(node->GetName());
        if (assembly.object_instances().get_by_name(instance_name.c_str()) != 0)
            instance_name = asr::make_unique_name(instance_name, assembly.object_instances());

        // Create an instance of the object and insert it into the assembly.
        assembly.object_instances().insert(
            asr::ObjectInstanceFactory::create(
                instance_name.c_str(),
                asr::ParamArray(),
                object_name.c_str(),
                asf::Transformd::from_local_to_parent(
                    max_to_as(node->GetObjTMAfterWSM(time))),
                asf::StringDictionary()));
    }

    void populate_assembly(
        asr::Assembly&          assembly,
        const MaxSceneEntities& entities,
        const TimeValue         time)
    {
        for (size_t i = 0, e = entities.m_instances.size(); i < e; ++i)
            add_object(assembly, entities.m_instances[i], time);
    }
}

asf::auto_release_ptr<asr::Project> build_project(
    const MaxSceneEntities&     entities,
    INode*                      view_node,
    const ViewParams&           view_params,
    Bitmap*                     bitmap,
    const TimeValue             time)
{
    // Create an empty project.
    asf::auto_release_ptr<asr::Project> project(
        asr::ProjectFactory::create("project"));

    // Add default configurations to the project.
    project->add_default_configurations();

    // Set the number of samples.
    project->configurations()
        .get_by_name("final")->get_parameters()
            .insert_path("uniform_pixel_renderer.samples", "1");

    // Create a scene.
    asf::auto_release_ptr<asr::Scene> scene(asr::SceneFactory::create());

    // Create an assembly.
    asf::auto_release_ptr<asr::Assembly> assembly(
        asr::AssemblyFactory().create("assembly", asr::ParamArray()));

    // Populate the assembly with entities from the 3ds Max scene.
    populate_assembly(assembly.ref(), entities, time);

    // Create an instance of the assembly and insert it into the scene.
    asf::auto_release_ptr<asr::AssemblyInstance> assembly_instance(
        asr::AssemblyInstanceFactory::create(
            "assembly_inst",
            asr::ParamArray(),
            "assembly"));
    assembly_instance
        ->transform_sequence()
            .set_transform(0.0, asf::Transformd::identity());
    scene->assembly_instances().insert(assembly_instance);

    // Insert the assembly into the scene.
    scene->assemblies().insert(assembly);

    // Create a default environment and bind it to the scene.
    scene->set_environment(
        asr::EnvironmentFactory::create("environment", asr::ParamArray()));

    // Create a camera.
    scene->set_camera(
        build_camera(
            view_node,
            view_params,
            bitmap,
            time));

    // Create a frame and bind it to the project.
    project->set_frame(
        asr::FrameFactory::create(
            "beauty",
            asr::ParamArray()
                .insert("camera", scene->get_camera()->get_name())
                .insert("resolution", make_vec_string(bitmap->Width(), bitmap->Height()))
                .insert("color_space", "linear_rgb")));

    // Bind the scene to the project.
    project->set_scene(scene);

    return project;
}
<|endoftext|>


<commit_before>/*
author: Nathan Turner
date:3/27/16
ussage: ./waf --run scratch/udpchain.cc
*/

#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/csma-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/applications-module.h"
#include "ns3/ipv4-global-routing-helper.h"

// Default Network Topology
//
//   A    B    C    D
//   |    |    |    |
//   ================
//     LAN 10.1.1.0

using namespace ns3;

NS_LOG_COMPONENT_DEFINE ("Lab4: udpchain");

int
main (int argc, char *argv[])
{
  bool verbose = true;
//  uint32_t nCsma = 5;

  CommandLine cmd;
  cmd.AddValue ("verbose", "Tell echo applications to log if true", verbose);

  cmd.Parse (argc,argv);

  if (verbose)
    {
      LogComponentEnable ("UdpEchoClientApplication", LOG_LEVEL_INFO);
      LogComponentEnable ("UdpEchoServerApplication", LOG_LEVEL_INFO);
export NS_LOG=UdpEchoClientApplication=level_all;
    }

//  NodeContainer p2pNodes;
//  p2pNodes.Create (2);

  NodeContainer csmaNodes;
//  csmaNodes.Add (p2pNodes.Get (1));
  csmaNodes.Create (4);

//  PointToPointHelper pointToPoint;
//  pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
//  pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));

//  NetDeviceContainer p2pDevices;
//  p2pDevices = pointToPoint.Install (p2pNodes);

  CsmaHelper csma;
  csma.SetChannelAttribute ("DataRate", StringValue ("1Mbps"));
  csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (10)));

  NetDeviceContainer csmaDevices;
  csmaDevices = csma.Install (csmaNodes);

  InternetStackHelper stack;
  stack.Install (csmaNodes);

  Ipv4AddressHelper address;
  address.SetBase ("10.1.1.0", "255.255.255.0");
//  Ipv4InterfaceContainer p2pInterfaces;
//  p2pInterfaces = address.Assign (p2pDevices);

//  address.SetBase ("10.1.2.0", "255.255.255.0");
  Ipv4InterfaceContainer csmaInterfaces;
  csmaInterfaces = address.Assign (csmaDevices);

  UdpEchoServerHelper echoServer (9);

  ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (3));
  serverApps.Start (Seconds (1.0));
  serverApps.Stop (Seconds (10.0));

  UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (3), 9);
  echoClient.SetAttribute ("MaxPackets", UintegerValue (5));
  echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.0)));
  echoClient.SetAttribute ("PacketSize", UintegerValue (1024));

  ApplicationContainer clientApps = echoClient.Install (csmaNodes.Get (0));
  clientApps.Start (Seconds (2.0));
  clientApps.Stop (Seconds (10.0));

  Ipv4GlobalRoutingHelper::PopulateRoutingTables ();

//  pointToPoint.EnablePcapAll ("second");
  csma.EnablePcap ("udpchain", csmaDevices.Get (0), true);
  csma.EnablePcap ("udpchain", csmaDevices.Get (1), true);
  csma.EnablePcap ("udpchain", csmaDevices.Get (2), true);
  csma.EnablePcap ("udpchain", csmaDevices.Get (3), true);

  Simulator::Run ();
  Simulator::Destroy ();
  return 0;
}
<commit_msg>updated lab4<commit_after>/*
author: Nathan Turner
date:3/27/16
ussage: ./waf --run scratch/udpchain.cc
*/

#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/csma-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/applications-module.h"
#include "ns3/ipv4-global-routing-helper.h"

// Default Network Topology
//
//   A    B    C    D
//   |    |    |    |
//   ================
//     LAN 10.1.1.0

using namespace ns3;

NS_LOG_COMPONENT_DEFINE ("Lab4: udpchain");

int
main (int argc, char *argv[])
{
  bool verbose = true;

  CommandLine cmd;
  cmd.AddValue ("verbose", "Tell echo applications to log if true", verbose);

  cmd.Parse (argc,argv);

  if (verbose)
    {
      LogComponentEnable ("UdpEchoClientApplication", LOG_LEVEL_INFO);
      LogComponentEnable ("UdpEchoServerApplication", LOG_LEVEL_INFO);
export NS_LOG=UdpEchoClientApplication=level_all;
    }

  NodeContainer csmaNodes;
  csmaNodes.Create (4);

  CsmaHelper csma;
  csma.SetChannelAttribute ("DataRate", StringValue ("1Mbps"));
  csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (10)));

  NetDeviceContainer csmaDevices;
  csmaDevices = csma.Install (csmaNodes);

  InternetStackHelper stack;
  stack.Install (csmaNodes);

  Ipv4AddressHelper address;
  address.SetBase ("10.1.1.0", "255.255.255.0");

  Ipv4InterfaceContainer csmaInterfaces;
  csmaInterfaces = address.Assign (csmaDevices);

  UdpEchoServerHelper echoServer (9);

  ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (3));
  serverApps.Start (Seconds (1.0));
  serverApps.Stop (Seconds (10.0));

  UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (3), 9);
  echoClient.SetAttribute ("MaxPackets", UintegerValue (5));
  echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.0)));
  echoClient.SetAttribute ("PacketSize", UintegerValue (1024));

  ApplicationContainer clientApps = echoClient.Install (csmaNodes.Get (0));
  clientApps.Start (Seconds (2.0));
  clientApps.Stop (Seconds (10.0));

  Ipv4GlobalRoutingHelper::PopulateRoutingTables ();

//  pointToPoint.EnablePcapAll ("second");
  csma.EnablePcap ("udpchain", csmaDevices.Get (0), true);
  csma.EnablePcap ("udpchain", csmaDevices.Get (1), true);
  csma.EnablePcap ("udpchain", csmaDevices.Get (2), true);
  csma.EnablePcap ("udpchain", csmaDevices.Get (3), true);

  Simulator::Run ();
  Simulator::Destroy ();
  return 0;
}
<|endoftext|>