<commit_before>#include <iostream>
#include <cstdlib>
#include <cassert>

#include "AnyOption.h"
//#include "VtkUgReader.h"

#include <vtkDataSetReader.h>
#include <vtkDataSet.h>
#include <vtkPointData.h>
#include <vtkCellData.h>

using namespace std;

// ---------------------------------------------------------------------------
int main(int argc, char *argv[])
{
    AnyOption *opt = new AnyOption();

    if (argc != 2)
    {
        cerr << "Usage: " << argv[0] << " " << "file.vtk" << endl;
        exit(1);
    }
    cout << "Reading " << argv[1] << endl;

    // ------------------------------------------------------
    cout << "<< Creating vtkDataSetReader" << endl;
    vtkDataSetReader *reader = vtkDataSetReader::New();
    reader->SetFileName(argv[1]);

    bool is_pd = reader->IsFilePolyData();
    cout << "Is file poly data? " << is_pd << endl;
    bool is_sp = reader->IsFileStructuredPoints();
    cout << "Is file structured points? " << is_sp << endl;
    bool is_sg = reader->IsFileStructuredGrid();
    cout << "Is file structured grid? " << is_sg << endl;
    bool is_ug = reader->IsFileUnstructuredGrid();
    cout << "Is file unstructured grid? " << is_ug << endl;
    bool is_rg = reader->IsFileRectilinearGrid();
    cout << "Is file rectilinear grid? " << is_rg << endl;
    bool is_valid = is_pd || is_sp || is_sg || is_ug || is_rg;
    assert(is_valid);

    //cout << reader->GetHeader() << endl;

    reader->Update();
    //reader->PrintSelf(cout, 0);

    int i,n;

    n = reader->GetNumberOfFieldDataInFile();
    cout << "Number of field data = " << n << endl;
    for (i = 0; i < n; i++)
    {
        const char *name = reader->GetFieldDataNameInFile(i);
        cout << "\t" << name << endl;
    }

    n = reader->GetNumberOfScalarsInFile();
    cout << "Number of scalars = " << n << endl;
    for (i = 0; i < n; i++)
    {
        const char *name = reader->GetScalarsNameInFile(i);
        cout << "\t" << name << endl;
    }

    n = reader->GetNumberOfVectorsInFile();
    cout << "Number of vectors = " << n << endl;
    for (i = 0; i < n; i++)
    {
        const char *name = reader->GetVectorsNameInFile(i);
        cout << "\t" << name << endl;
    }

    n = reader->GetNumberOfTensorsInFile();
    cout << "Number of tensors = " << n << endl;
    for (i = 0; i < n; i++)
    {
        const char *name = reader->GetTensorsNameInFile(i);
        cout << "\t" << name << endl;
    }

    // ------------------------------------------------------
    cout << "<< Creating vtkDataSet" << endl;
    vtkDataSet *dataset = reader->GetOutput();
    //dataset->PrintSelf(cout, 0);

    int nno,nel;
    nno = dataset->GetNumberOfPoints();
    nel = dataset->GetNumberOfCells();
    cout << "Number of points = " << nno << endl;
    cout << "Number of cells = " << nel << endl;

    // ------------------------------------------------------
    cout << "<< Creating vtkPointData" << endl;
    vtkPointData *pointData = dataset->GetPointData();
    //pointData->PrintSelf(cout, 0);

    // ------------------------------------------------------
    cout << "<< Creating vtkCellData" << endl;
    vtkCellData *cellData = dataset->GetCellData();
    //cellData->PrintSelf(cout, 0);

    // ------------------------------------------------------
    cout << "<< Sleeping..." << endl;
    sleep(100);

    return 0;
}
<commit_msg>Added various improvements to vtkls.cpp<commit_after>#include <iostream>
#include <cstdlib>
#include <cassert>

#include "AnyOption.h"

#include <vtkDataSetReader.h>
#include <vtkDataSet.h>
#include <vtkPointData.h>
#include <vtkCellData.h>

#include <vtkDataArray.h>

using namespace std;

typedef enum {
    VTK_FILE_NONE,
    VTK_FILE_POLYDATA,
    VTK_FILE_STRUCTURED_POINTS,
    VTK_FILE_STRUCTURED_GRID,
    VTK_FILE_UNSTRUCTURED_GRID,
    VTK_FILE_RECTILINEAR_GRID
} VtkFileType;

VtkFileType getFileType(vtkDataSetReader *reader)
{
    // XXX: are these mutually exclusive?
    if (reader->IsFilePolyData())
        return VTK_FILE_POLYDATA;
    if (reader->IsFileStructuredPoints())
        return VTK_FILE_STRUCTURED_POINTS;
    if (reader->IsFileStructuredGrid())
        return VTK_FILE_STRUCTURED_GRID;
    if (reader->IsFileUnstructuredGrid())
        return VTK_FILE_UNSTRUCTURED_GRID;
    if (reader->IsFileRectilinearGrid())
        return VTK_FILE_RECTILINEAR_GRID;
    return VTK_FILE_NONE;
}

const char *getFileTypeName(VtkFileType fileType)
{
    if (fileType == VTK_FILE_POLYDATA)
        return "polydata";
    if (fileType == VTK_FILE_STRUCTURED_POINTS)
        return "structured points";
    if (fileType == VTK_FILE_STRUCTURED_GRID)
        return "structured grid";
    if (fileType == VTK_FILE_UNSTRUCTURED_GRID)
        return "unstructured grid";
    if (fileType == VTK_FILE_RECTILINEAR_GRID)
        return "rectilinear grid";
    return "";
}

// ---------------------------------------------------------------------------
int main(int argc, char *argv[])
{
    bool verbose = false;
    bool by_class = false;
    bool by_arrays = true;

    int i,n;

    // ------------------------------------------------------
    /*
    if (argc != 2)
    {
        cerr << "Usage: " << argv[0] << " " << "file.vtk" << endl;
        exit(1);
    }
    // */

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

    AnyOption *opt = new AnyOption();

    opt->addUsage("Usage: vtkls file.vtk");

    opt->setFlag("help", 'h');
    opt->setFlag("verbose", 'v');
    opt->setFlag('c'); // sort by class
    opt->setFlag('a'); // sort by array

    opt->processCommandArgs(argc, argv);

    if (!opt->hasOptions())
    {
        opt->printUsage();
        delete opt;
        exit(1);
    }

    if (opt->getFlag("help"))
    {
        opt->printUsage();
        delete opt;
        exit(0);
    }

    if (opt->getFlag("verbose"))
    {
        verbose = true;
    }

    if (opt->getFlag('c') && !opt->getFlag('a'))
    {
        by_class = true;
        by_arrays = false;
    }
    if (opt->getFlag('a') && !opt->getFlag('c'))
    {
        by_arrays = true;
        by_class = false;
    }
    int nargs = opt->getArgc();
    if (nargs != 1)
    {
        opt->printUsage();
        delete opt;
        exit(1);
    }
    char *filename = opt->getArgv(0);

    // ------------------------------------------------------
    //
    // Assuming legacy format
    //
    if (verbose)
    {
        cout << "<< Creating vtkDataSetReader" << endl;
    }
    vtkDataSetReader *reader = vtkDataSetReader::New();
    reader->SetFileName(filename);
    cout << "Reading " << filename << endl;

    int ierr;
    ierr = reader->OpenVTKFile();   // does file exist?
    if (ierr == 0)
    {
        cerr << "vtkls: Could not open " << filename << endl;
        exit(1);
    }

    ierr = reader->ReadHeader();    // is the vtk header present?
    if (ierr == 0)
    {
        cerr << "vtkls: Unrecognized file " << filename << endl;
        exit(1);
    }

    /* // Determine type of file (direct method)
    bool is_pd = reader->IsFilePolyData();
    cout << "Is file poly data? " << is_pd << endl;
    bool is_sp = reader->IsFileStructuredPoints();
    cout << "Is file structured points? " << is_sp << endl;
    bool is_sg = reader->IsFileStructuredGrid();
    cout << "Is file structured grid? " << is_sg << endl;
    bool is_ug = reader->IsFileUnstructuredGrid();
    cout << "Is file unstructured grid? " << is_ug << endl;
    bool is_rg = reader->IsFileRectilinearGrid();
    cout << "Is file rectilinear grid? " << is_rg << endl;
    bool is_valid = is_pd || is_sp || is_sg || is_ug || is_rg;
    assert(is_valid); // */

    /* // Determine type of file (second method)
    VtkFileType fileType = getFileType(reader);
    const char *fileTypeName = getFileTypeName(fileType);
    cout << "Detected " << fileTypeName << " file" << endl;
    // */

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

    reader->Update();
    //reader->PrintSelf(cout, 0);

    if (verbose)
    {
        cout << "<< Creating vtkDataSet" << endl;
    }
    vtkDataSet *dataset = reader->GetOutput();
    //dataset->PrintSelf(cout, 0);

    if (verbose)
    {
        cout << "<< Creating vtkPointData" << endl;
    }
    vtkPointData *pointData = dataset->GetPointData();
    //pointData->PrintSelf(cout, 0);

    if (verbose)
    {
        cout << "<< Creating vtkCellData" << endl;
    }
    vtkCellData *cellData = dataset->GetCellData();
    //cellData->PrintSelf(cout, 0);

    // ------------------------------------------------------
    int nno,nel;

    nno = dataset->GetNumberOfPoints();
    if (nno > 0)
    {
        cout << "Points = " << nno << endl;
    }

    nel = dataset->GetNumberOfCells();
    if (nel > 0)
    {
        cout << "Cells = " << nel << endl;
    }

    // ------------------------------------------------------
    int numArrays;
    int numTuples, numComponents;

    if (by_arrays)
    {
        //*
        numArrays = pointData->GetNumberOfArrays();
        if (numArrays > 0)
        {
            //cout << "PointData" << endl;
            //cout << "\tNumber of arrays = " << numArrays << endl;
            for (i = 0; i < numArrays; i++)
            {
                vtkDataArray *dataArray = pointData->GetArray(i);
                const char *name = pointData->GetArrayName(i);
                numTuples = dataArray->GetNumberOfTuples();
                numComponents = dataArray->GetNumberOfComponents();
                cout << "PointDataArray[" << i << "] = " << name;
                //cout << "  " << dataArray->GetClassName();
                cout << "  " << "(" << numTuples << " x " << numComponents << ")";
                cout << endl;
            }
        }

        numArrays = cellData->GetNumberOfArrays();
        if (numArrays > 0)
        {
            //cout << "CellData" << endl;
            //cout << "\tNumber of arrays = " << numArrays << endl;
            for (i = 0; i < numArrays; i++)
            {
                vtkDataArray *dataArray = cellData->GetArray(i);
                const char *name = cellData->GetArrayName(i);
                numTuples = dataArray->GetNumberOfTuples();
                numComponents = dataArray->GetNumberOfComponents();
                cout << "CellDataArray[" << i << "] = " << name;
                //cout << "  " << dataArray->GetClassName();
                cout << "  " << "(" << numTuples << " x " << numComponents << ")";
                cout << endl;
            }
        }
        // */
    }

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

    if (by_class)
    {
        //*
        n = reader->GetNumberOfFieldDataInFile();
        //cout << "Number of field data = " << n << endl;
        for (i = 0; i < n; i++)
        {
            const char *name = reader->GetFieldDataNameInFile(i);
            cout << "FieldData[" << i << "] = " << name;
            cout << endl;
        }

        n = reader->GetNumberOfScalarsInFile();
        //cout << "Number of scalars = " << n << endl;
        for (i = 0; i < n; i++)
        {
            const char *name = reader->GetScalarsNameInFile(i);
            vtkDataArray *dataArray = pointData->GetArray(i);
            cout << "Scalars[" << i << "] = " << name;
            cout << endl;
        }

        n = reader->GetNumberOfVectorsInFile();
        //cout << "Number of vectors = " << n << endl;
        for (i = 0; i < n; i++)
        {
            const char *name = reader->GetVectorsNameInFile(i);
            cout << "Vectors[" << i << "] = " << name;
            cout << endl;
        }

        n = reader->GetNumberOfTensorsInFile();
        //cout << "Number of tensors = " << n << endl;
        for (i = 0; i < n; i++)
        {
            const char *name = reader->GetTensorsNameInFile(i);
            cout << "Tensors[" << i << "] = " << name;
            cout << endl;
        }
        // */
    }

    // ------------------------------------------------------
    // Sleep for a bit so we can examine memory usage with htop
    //cout << "<< Sleeping..." << endl;
    //sleep(100);

    delete opt;
    return 0;
}
<|endoftext|>


<commit_before>#include <osgUtil/RenderBin>
#include <osgUtil/RenderStage>

#include <osg/Statistics>

#include <algorithm>

using namespace osg;
using namespace osgUtil;

// register a RenderStage prototype with the RenderBin prototype list.
RegisterRenderBinProxy<RenderBin> s_registerRenderBinProxy;

#ifdef __DARWIN_OSX__
// PJA 10/1/02 - this is a hack to get OS X to build, if this code is included in DepthSortedBin.cpp it isnt executed
// register a RenderStage prototype with the RenderBin prototype list.
#include <osgUtil/DepthSortedBin>
RegisterRenderBinProxy<DepthSortedBin> s_registerDepthSortedBinProxy;
#endif

typedef std::map< std::string, osg::ref_ptr<RenderBin> > RenderBinPrototypeList;

RenderBinPrototypeList* renderBinPrototypeList()
{
    static RenderBinPrototypeList s_renderBinPrototypeList;
    return &s_renderBinPrototypeList;
}

RenderBin* RenderBin::createRenderBin(const std::string& binName)
{
//    cout << "creating RB "<<binName<<std::endl;

    RenderBinPrototypeList::iterator itr = renderBinPrototypeList()->find(binName);
    if (itr != renderBinPrototypeList()->end()) return dynamic_cast<RenderBin*>(itr->second->cloneType());
    else return NULL;
}

void RenderBin::addRenderBinPrototype(RenderBin* proto)
{
    if (proto)
    {
        (*renderBinPrototypeList())[proto->className()] = proto;
//        cout << "Adding RB "<<proto->className()<<std::endl;
    }
}

void RenderBin::removeRenderBinPrototype(RenderBin* proto)
{
    if (proto)
    {
        RenderBinPrototypeList::iterator itr = renderBinPrototypeList()->find(proto->className());
        if (itr != renderBinPrototypeList()->end()) renderBinPrototypeList()->erase(itr);
    }
}

RenderBin::RenderBin()
{
    _binNum = 0;
    _parent = NULL;
    _stage = NULL;
}

RenderBin::~RenderBin()
{
}

void RenderBin::reset()
{
    _renderGraphList.clear();
    _bins.clear();
}

void RenderBin::sort()
{
    for(RenderBinList::iterator itr = _bins.begin();
        itr!=_bins.end();
        ++itr)
    {
        itr->second->sort();
    }

    if (_sortLocalCallback.valid()) _sortLocalCallback->sort(this);
    else sort_local();
}

void RenderBin::sort_local()
{
    switch(_sortMode)
    {
        case(SORT_BY_STATE):
            sort_local_by_state();
            break;
        case(SORT_FRONT_TO_BACK):
            sort_local_front_to_back();
            break;
        case(SORT_BACK_TO_FONT):
            sort_local_back_to_front();
            break;
        default:
            break;
    }
}

struct SortByStateFunctor
{
    const bool operator() (const RenderGraph* lhs,const RenderGraph* rhs) const
    {
        return (*(lhs->_stateset)<*(rhs->_stateset));
    }
};

void RenderBin::sort_local_by_state()
{
    // actually we'll do nothing right now, as fine grained sorting by state
    // appears to cost more to do than it saves in draw.  The contents of
    // the RenderGraph leaves is already coasrse grained sorted, this
    // sorting is as a function of the cull traversal.
}

struct FrontToBackSortFunctor
{
    bool operator() (const RenderLeaf* lhs,const RenderLeaf* rhs) const
    {
        return (lhs->_depth<rhs->_depth);
    }
};

void RenderBin::sort_local_front_to_back()
{
    copyLeavesFromRenderGraphListToRenderLeafList();

    // now sort the list into acending depth order.
    std::sort(_renderLeafList.begin(),_renderLeafList.end(),FrontToBackSortFunctor());
}

struct BackToFrontSortFunctor
{
    const bool operator() (const RenderLeaf* lhs,const RenderLeaf* rhs) const
    {
        return (rhs->_depth<lhs->_depth);
    }
};

void RenderBin::sort_local_back_to_front()
{
    copyLeavesFromRenderGraphListToRenderLeafList();

    // now sort the list into acending depth order.
    std::sort(_renderLeafList.begin(),_renderLeafList.end(),BackToFrontSortFunctor());
}

void RenderBin::copyLeavesFromRenderGraphListToRenderLeafList()
{
    _renderLeafList.clear();

    int totalsize=0;
    RenderGraphList::iterator itr;
    for(itr=_renderGraphList.begin();
        itr!=_renderGraphList.end();
        ++itr)
    {
        totalsize += (*itr)->_leaves.size();
    }

    _renderLeafList.reserve(totalsize);

    // first copy all the leaves from the render graphs into the leaf list.
    for(itr=_renderGraphList.begin();
        itr!=_renderGraphList.end();
        ++itr)
    {
        for(RenderGraph::LeafList::iterator dw_itr = (*itr)->_leaves.begin();
            dw_itr != (*itr)->_leaves.end();
            ++dw_itr)
        {
            _renderLeafList.push_back(dw_itr->get());
        }
    }
}

RenderBin* RenderBin::find_or_insert(int binNum,const std::string& binName)
{
    // search for appropriate bin.
    RenderBinList::iterator itr = _bins.find(binNum);
    if (itr!=_bins.end()) return itr->second.get();

    // create a renderin bin and insert into bin list.
    RenderBin* rb = RenderBin::createRenderBin(binName);
    if (rb)
    {

        RenderStage* rs = dynamic_cast<RenderStage*>(rb);
        if (rs)
        {
            rs->_binNum = binNum;
            rs->_parent = NULL;
            rs->_stage = rs;
            _stage->addToDependencyList(rs);
        }
        else
        {
            rb->_binNum = binNum;
            rb->_parent = this;
            rb->_stage = _stage;
            _bins[binNum] = rb;
        }
    }
    return rb;
}

void RenderBin::draw(osg::State& state,RenderLeaf*& previous)
{
    // draw first set of draw bins.
    RenderBinList::iterator itr;
    for(itr = _bins.begin();
        itr!=_bins.end() && itr->first<0;
        ++itr)
    {
        itr->second->draw(state,previous);
    }

    draw_local(state,previous);

    for(;
        itr!=_bins.end();
        ++itr)
    {
        itr->second->draw(state,previous);
    }
}

void RenderBin::draw_local(osg::State& state,RenderLeaf*& previous)
{
    sort_local();

    // draw local bin.
    for(RenderGraphList::iterator oitr=_renderGraphList.begin();
        oitr!=_renderGraphList.end();
        ++oitr)
    {

        for(RenderGraph::LeafList::iterator dw_itr = (*oitr)->_leaves.begin();
            dw_itr != (*oitr)->_leaves.end();
            ++dw_itr)
        {
            RenderLeaf* rl = dw_itr->get();
            rl->render(state,previous);
            previous = rl;

        }
    }
}

// stats
bool RenderBin::getStats(osg::Statistics* primStats)
{ // different by return type - collects the stats in this renderrBin
    bool somestats=false;
    for(RenderGraphList::iterator oitr=_renderGraphList.begin();
        oitr!=_renderGraphList.end();
        ++oitr)
    {

        for(RenderGraph::LeafList::iterator dw_itr = (*oitr)->_leaves.begin();
            dw_itr != (*oitr)->_leaves.end();
            ++dw_itr)
        {
            RenderLeaf* rl = dw_itr->get();
            Drawable* dw= rl->_drawable;
            primStats->addOpaque(); // number of geosets
            if (rl->_modelview.get()) primStats->addMatrix(); // number of matrices
            if (dw)
            {
                // then tot up the primtive types and no vertices.
                dw->accept(*primStats); // use sub-class to find the stats for each drawable
            }
        }
        somestats=true;
    }
    return somestats;
}

void RenderBin::getPrims(osg::Statistics* primStats)
{
    static int ndepth;
    ndepth++;
    for(RenderBinList::iterator itr = _bins.begin();
        itr!=_bins.end();
        ++itr)
    {
        primStats->addBins(1);
        itr->second->getPrims(primStats);
    }
    getStats(primStats);
    ndepth--;

}

bool RenderBin::getPrims(osg::Statistics* primStats, const int nbin)
{ // collect stats for array of bins, maximum nbin
    // (which will be modified on next call if array of primStats is too small);
    // return 1 for OK;
    static int ndepth;
    bool ok=false;
    ndepth++;
    int nb=primStats[0].getBins();
    if (nb<nbin)
    { // if statement to protect against writing to bins beyond the maximum seen before
        primStats[nb].setBinNo(nb);
        primStats[nb].setDepth(ndepth);
        getStats(primStats+nb);
    }
    primStats[0].addBins(1);
    for(RenderBinList::iterator itr = _bins.begin();
        itr!=_bins.end();
        ++itr)
    {
        if (itr->second->getPrims(primStats, nbin)) ok = true;
    }
    ok=true;
    ndepth--;
    return ok;
}
<commit_msg>Fixed uninitialized _sortMode.<commit_after>#include <osgUtil/RenderBin>
#include <osgUtil/RenderStage>

#include <osg/Statistics>

#include <algorithm>

using namespace osg;
using namespace osgUtil;

// register a RenderStage prototype with the RenderBin prototype list.
RegisterRenderBinProxy<RenderBin> s_registerRenderBinProxy;

#ifdef __DARWIN_OSX__
// PJA 10/1/02 - this is a hack to get OS X to build, if this code is included in DepthSortedBin.cpp it isnt executed
// register a RenderStage prototype with the RenderBin prototype list.
#include <osgUtil/DepthSortedBin>
RegisterRenderBinProxy<DepthSortedBin> s_registerDepthSortedBinProxy;
#endif

typedef std::map< std::string, osg::ref_ptr<RenderBin> > RenderBinPrototypeList;

RenderBinPrototypeList* renderBinPrototypeList()
{
    static RenderBinPrototypeList s_renderBinPrototypeList;
    return &s_renderBinPrototypeList;
}

RenderBin* RenderBin::createRenderBin(const std::string& binName)
{
//    cout << "creating RB "<<binName<<std::endl;

    RenderBinPrototypeList::iterator itr = renderBinPrototypeList()->find(binName);
    if (itr != renderBinPrototypeList()->end()) return dynamic_cast<RenderBin*>(itr->second->cloneType());
    else return NULL;
}

void RenderBin::addRenderBinPrototype(RenderBin* proto)
{
    if (proto)
    {
        (*renderBinPrototypeList())[proto->className()] = proto;
//        cout << "Adding RB "<<proto->className()<<std::endl;
    }
}

void RenderBin::removeRenderBinPrototype(RenderBin* proto)
{
    if (proto)
    {
        RenderBinPrototypeList::iterator itr = renderBinPrototypeList()->find(proto->className());
        if (itr != renderBinPrototypeList()->end()) renderBinPrototypeList()->erase(itr);
    }
}

RenderBin::RenderBin()
{
    _binNum = 0;
    _parent = NULL;
    _stage = NULL;
    _sortMode = SORT_BY_STATE;
}

RenderBin::~RenderBin()
{
}

void RenderBin::reset()
{
    _renderGraphList.clear();
    _bins.clear();
}

void RenderBin::sort()
{
    for(RenderBinList::iterator itr = _bins.begin();
        itr!=_bins.end();
        ++itr)
    {
        itr->second->sort();
    }

    if (_sortLocalCallback.valid()) _sortLocalCallback->sort(this);
    else sort_local();
}

void RenderBin::sort_local()
{
    switch(_sortMode)
    {
        case(SORT_BY_STATE):
            sort_local_by_state();
            break;
        case(SORT_FRONT_TO_BACK):
            sort_local_front_to_back();
            break;
        case(SORT_BACK_TO_FONT):
            sort_local_back_to_front();
            break;
        default:
            break;
    }
}

struct SortByStateFunctor
{
    const bool operator() (const RenderGraph* lhs,const RenderGraph* rhs) const
    {
        return (*(lhs->_stateset)<*(rhs->_stateset));
    }
};

void RenderBin::sort_local_by_state()
{
    // actually we'll do nothing right now, as fine grained sorting by state
    // appears to cost more to do than it saves in draw.  The contents of
    // the RenderGraph leaves is already coasrse grained sorted, this
    // sorting is as a function of the cull traversal.
}

struct FrontToBackSortFunctor
{
    bool operator() (const RenderLeaf* lhs,const RenderLeaf* rhs) const
    {
        return (lhs->_depth<rhs->_depth);
    }
};

void RenderBin::sort_local_front_to_back()
{
    copyLeavesFromRenderGraphListToRenderLeafList();

    // now sort the list into acending depth order.
    std::sort(_renderLeafList.begin(),_renderLeafList.end(),FrontToBackSortFunctor());
}

struct BackToFrontSortFunctor
{
    const bool operator() (const RenderLeaf* lhs,const RenderLeaf* rhs) const
    {
        return (rhs->_depth<lhs->_depth);
    }
};

void RenderBin::sort_local_back_to_front()
{
    copyLeavesFromRenderGraphListToRenderLeafList();

    // now sort the list into acending depth order.
    std::sort(_renderLeafList.begin(),_renderLeafList.end(),BackToFrontSortFunctor());
}

void RenderBin::copyLeavesFromRenderGraphListToRenderLeafList()
{
    _renderLeafList.clear();

    int totalsize=0;
    RenderGraphList::iterator itr;
    for(itr=_renderGraphList.begin();
        itr!=_renderGraphList.end();
        ++itr)
    {
        totalsize += (*itr)->_leaves.size();
    }

    _renderLeafList.reserve(totalsize);

    // first copy all the leaves from the render graphs into the leaf list.
    for(itr=_renderGraphList.begin();
        itr!=_renderGraphList.end();
        ++itr)
    {
        for(RenderGraph::LeafList::iterator dw_itr = (*itr)->_leaves.begin();
            dw_itr != (*itr)->_leaves.end();
            ++dw_itr)
        {
            _renderLeafList.push_back(dw_itr->get());
        }
    }
}

RenderBin* RenderBin::find_or_insert(int binNum,const std::string& binName)
{
    // search for appropriate bin.
    RenderBinList::iterator itr = _bins.find(binNum);
    if (itr!=_bins.end()) return itr->second.get();

    // create a renderin bin and insert into bin list.
    RenderBin* rb = RenderBin::createRenderBin(binName);
    if (rb)
    {

        RenderStage* rs = dynamic_cast<RenderStage*>(rb);
        if (rs)
        {
            rs->_binNum = binNum;
            rs->_parent = NULL;
            rs->_stage = rs;
            _stage->addToDependencyList(rs);
        }
        else
        {
            rb->_binNum = binNum;
            rb->_parent = this;
            rb->_stage = _stage;
            _bins[binNum] = rb;
        }
    }
    return rb;
}

void RenderBin::draw(osg::State& state,RenderLeaf*& previous)
{
    // draw first set of draw bins.
    RenderBinList::iterator itr;
    for(itr = _bins.begin();
        itr!=_bins.end() && itr->first<0;
        ++itr)
    {
        itr->second->draw(state,previous);
    }

    draw_local(state,previous);

    for(;
        itr!=_bins.end();
        ++itr)
    {
        itr->second->draw(state,previous);
    }
}

void RenderBin::draw_local(osg::State& state,RenderLeaf*& previous)
{
    sort_local();

    // draw local bin.
    for(RenderGraphList::iterator oitr=_renderGraphList.begin();
        oitr!=_renderGraphList.end();
        ++oitr)
    {

        for(RenderGraph::LeafList::iterator dw_itr = (*oitr)->_leaves.begin();
            dw_itr != (*oitr)->_leaves.end();
            ++dw_itr)
        {
            RenderLeaf* rl = dw_itr->get();
            rl->render(state,previous);
            previous = rl;

        }
    }
}

// stats
bool RenderBin::getStats(osg::Statistics* primStats)
{ // different by return type - collects the stats in this renderrBin
    bool somestats=false;
    for(RenderGraphList::iterator oitr=_renderGraphList.begin();
        oitr!=_renderGraphList.end();
        ++oitr)
    {

        for(RenderGraph::LeafList::iterator dw_itr = (*oitr)->_leaves.begin();
            dw_itr != (*oitr)->_leaves.end();
            ++dw_itr)
        {
            RenderLeaf* rl = dw_itr->get();
            Drawable* dw= rl->_drawable;
            primStats->addOpaque(); // number of geosets
            if (rl->_modelview.get()) primStats->addMatrix(); // number of matrices
            if (dw)
            {
                // then tot up the primtive types and no vertices.
                dw->accept(*primStats); // use sub-class to find the stats for each drawable
            }
        }
        somestats=true;
    }
    return somestats;
}

void RenderBin::getPrims(osg::Statistics* primStats)
{
    static int ndepth;
    ndepth++;
    for(RenderBinList::iterator itr = _bins.begin();
        itr!=_bins.end();
        ++itr)
    {
        primStats->addBins(1);
        itr->second->getPrims(primStats);
    }
    getStats(primStats);
    ndepth--;

}

bool RenderBin::getPrims(osg::Statistics* primStats, const int nbin)
{ // collect stats for array of bins, maximum nbin
    // (which will be modified on next call if array of primStats is too small);
    // return 1 for OK;
    static int ndepth;
    bool ok=false;
    ndepth++;
    int nb=primStats[0].getBins();
    if (nb<nbin)
    { // if statement to protect against writing to bins beyond the maximum seen before
        primStats[nb].setBinNo(nb);
        primStats[nb].setDepth(ndepth);
        getStats(primStats+nb);
    }
    primStats[0].addBins(1);
    for(RenderBinList::iterator itr = _bins.begin();
        itr!=_bins.end();
        ++itr)
    {
        if (itr->second->getPrims(primStats, nbin)) ok = true;
    }
    ok=true;
    ndepth--;
    return ok;
}
<|endoftext|>


<commit_before>#include <memory>
#include <list>

#include "boost/format.hpp"

#include "packet.h"
#include "exceptions.h"
#include "parser.h"

namespace parse4880 {

SignaturePacket::SignaturePacket(std::string packet_data)
    : PGPPacket(packet_data) {
  // We need to parse a signature subpacket.  This could be either
  // a v3 or v4 signature, so we need to check first and switch on that.
  if (packet_data.length() < 1) {
    throw invalid_header_error(-1);
  }
  version_ = packet_data[0];
  if (version_ == 3) {
    // A version three signature packet has the following:
    //
    // [1] Version
    // [1] Length of hashed material
    // [1]   Signature type
    // [4]   Creation time
    // [8] Key ID
    // [1] Public-key algorithm
    // [1] Hash algorithm
    // [2] Left sixteen-most bits of hash value
    // [?] Signature
    //
    // This adds up to nineteen bytes plus the signature.
    if (packet_data.length() < 19) {
      throw invalid_header_error(-1);
    }

    // There should always be five bytes of hashed material, so check
    // that the provided length is correct.
    if (5 != packet_data[1]) {
      throw invalid_header_error(-1);
    }

    // We already know that the remainder of the data is there, so
    // we can just go ahead and copy it.

    // Signature type (byte 2)
    signature_type_ = packet_data[2];

    // TODO: Copy the creation time (bytes 3--6)

    // Key ID (bytes 7--14)
    key_id_ = packet_data.substr(7,8).c_str();

    // Algorithms (bytes 14--15)
    public_key_algorithm_ = packet_data[15];
    hash_algorithm_ = packet_data[16];

    // TODO: Copy the hash quick-check field (bytes 17--18)

    // The rest of the packet is the signature.
    signature_ = packet_data.substr(19);

    // Finally, save the signature data to be hashed.
    hashed_data_ = packet_data.substr(2, 5);
  }
  else if(version_ == 4) {
    // A version four signature has the following:
    //
    //   [1] Version number
    //   [1] Signature type
    //   [1] Public-key algorithm
    //   [1] Hash algorithm
    //   [2] Hashed subpacket data count
    //     [?] Hashed subpacket data
    //   [2] Unhashed subpacket data count
    //     [?] Unhashed subpacket data
    //   [2] Left sixteen bits of hash value
    //   [?] Signature

    if (packet_data.length() < 10) {
      throw invalid_header_error(0);
    }

    signature_type_       = packet_data[1];
    public_key_algorithm_ = packet_data[2];
    hash_algorithm_       = packet_data[3];

    size_t hashed_data_count = ReadInteger(packet_data.substr(4,2));
    if (packet_data.length() < 10+hashed_data_count) {
      throw invalid_header_error(1);
    }
    hashed_subpacket_data_ = packet_data.substr(6, hashed_data_count);
    subpackets_ = parse_subpackets(hashed_subpacket_data_);

    hashed_data_ = packet_data.substr(0, 6+hashed_data_count);

    size_t unhashed_data_count =
        ReadInteger(packet_data.substr(6+hashed_data_count, 2));

    if (packet_data.length() < 10+hashed_data_count+unhashed_data_count) {
      throw invalid_header_error(2);
    }
    unhashed_subpacket_data_ =
        packet_data.substr(6+hashed_data_count+2, unhashed_data_count);

    subpackets_.splice(subpackets_.end(),
                       parse_subpackets(unhashed_subpacket_data_));

    // TODO: Left sixteen bits

    signature_ = packet_data.substr(6 + hashed_data_count
                                    + 2 + unhashed_data_count + 2);
  }
  else {
    throw unsupported_feature_error(-1, "non-v3/v4 signatures");
  }

  SetSignaturePropertiesFromSubpackets();
}

uint8_t SignaturePacket::tag() const {
  return 2;
}

std::string SignaturePacket::str() const {
  char uid_string[17]; // Flawfinder: ignore (uids have known length)
  const unsigned char* unsigned_key_id =
      reinterpret_cast<const unsigned char*>(key_id_.c_str());
  snprintf(uid_string, 17, "%02x%02x%02x%02x%02x%02x%02x%02x",
           unsigned_key_id[0], unsigned_key_id[1], unsigned_key_id[2],
           unsigned_key_id[3], unsigned_key_id[4], unsigned_key_id[5],
           unsigned_key_id[6], unsigned_key_id[7]);
  return (boost::format("Signature, version %d, type 0x%02x, "
                        "uid %s")
          % static_cast<int>(version_)
          % static_cast<int>(signature_type_)
          % uid_string).str();
}

uint8_t SignaturePacket::version() const {
  return version_;
}

uint8_t SignaturePacket::signature_type() const {
  return signature_type_;
}

uint8_t SignaturePacket::public_key_algorithm() const {
  return public_key_algorithm_;
}

uint8_t SignaturePacket::hash_algorithm() const {
  return hash_algorithm_;
}

const std::string& SignaturePacket::hashed_subpacket_data() const {
  return hashed_subpacket_data_;
}

const std::string& SignaturePacket::unhashed_subpacket_data() const {
  return unhashed_subpacket_data_;
}

const uint8_t* SignaturePacket::hash_left_16bits() const {
  return hash_left_16bits_;
}

const std::string& SignaturePacket::signature() const {
  return signature_;
}

void SignaturePacket::SetSignaturePropertiesFromSubpackets() {
  const std::list<std::shared_ptr<PGPPacket>>& subpackets = this->subpackets();
  for (auto current_subpacket_ptr  = subpackets.begin();
            current_subpacket_ptr != subpackets.end();
            current_subpacket_ptr++) {
    // FIXME: This is bad.
    std::shared_ptr<UnknownPGPPacket> subpacket =
        std::dynamic_pointer_cast<UnknownPGPPacket>(*current_subpacket_ptr);

    if (nullptr == subpacket) {
      continue;
    }

    if (16 == subpacket->tag()) {
      std::string subpacket_key_id = subpacket->contents();
      if (8 != subpacket_key_id.length()) {
        throw invalid_packet_error(
            "Signature issuer subpacket has wrong length.");
      }
      key_id_ = subpacket_key_id;
    }
  }
}

const std::string& SignaturePacket::hashed_data() const {
  return hashed_data_;
}

}
<commit_msg>Changed signature packet parser to use safe string::at.<commit_after>#include <memory>
#include <list>

#include "boost/format.hpp"

#include "packet.h"
#include "exceptions.h"
#include "parser.h"

namespace parse4880 {

SignaturePacket::SignaturePacket(std::string packet_data)
    : PGPPacket(packet_data) {
  // We need to parse a signature subpacket.  This could be either
  // a v3 or v4 signature, so we need to check first and switch on that.
  if (packet_data.length() < 1) {
    throw invalid_header_error(-1);
  }
  version_ = packet_data.at(0);
  if (version_ == 3) {
    // A version three signature packet has the following:
    //
    // [1] Version
    // [1] Length of hashed material
    // [1]   Signature type
    // [4]   Creation time
    // [8] Key ID
    // [1] Public-key algorithm
    // [1] Hash algorithm
    // [2] Left sixteen-most bits of hash value
    // [?] Signature
    //
    // This adds up to nineteen bytes plus the signature.
    if (packet_data.length() < 19) {
      throw invalid_header_error(-1);
    }

    // There should always be five bytes of hashed material, so check
    // that the provided length is correct.
    if (5 != packet_data.at(1)) {
      throw invalid_header_error(-1);
    }

    // We already know that the remainder of the data is there, so
    // we can just go ahead and copy it.

    // Signature type (byte 2)
    signature_type_ = packet_data.at(2);

    // TODO: Copy the creation time (bytes 3--6)

    // Key ID (bytes 7--14)
    key_id_ = packet_data.substr(7,8).c_str();

    // Algorithms (bytes 14--15)
    public_key_algorithm_ = packet_data.at(15);
    hash_algorithm_ = packet_data.at(16);

    // TODO: Copy the hash quick-check field (bytes 17--18)

    // The rest of the packet is the signature.
    signature_ = packet_data.substr(19);

    // Finally, save the signature data to be hashed.
    hashed_data_ = packet_data.substr(2, 5);
  }
  else if(version_ == 4) {
    // A version four signature has the following:
    //
    //   [1] Version number
    //   [1] Signature type
    //   [1] Public-key algorithm
    //   [1] Hash algorithm
    //   [2] Hashed subpacket data count
    //     [?] Hashed subpacket data
    //   [2] Unhashed subpacket data count
    //     [?] Unhashed subpacket data
    //   [2] Left sixteen bits of hash value
    //   [?] Signature

    if (packet_data.length() < 10) {
      throw invalid_header_error(0);
    }

    signature_type_       = packet_data.at(1);
    public_key_algorithm_ = packet_data.at(2);
    hash_algorithm_       = packet_data.at(3);

    size_t hashed_data_count = ReadInteger(packet_data.substr(4,2));
    if (packet_data.length() < 10+hashed_data_count) {
      throw invalid_header_error(1);
    }
    hashed_subpacket_data_ = packet_data.substr(6, hashed_data_count);
    subpackets_ = parse_subpackets(hashed_subpacket_data_);

    hashed_data_ = packet_data.substr(0, 6+hashed_data_count);

    size_t unhashed_data_count =
        ReadInteger(packet_data.substr(6+hashed_data_count, 2));

    if (packet_data.length() < 10+hashed_data_count+unhashed_data_count) {
      throw invalid_header_error(2);
    }
    unhashed_subpacket_data_ =
        packet_data.substr(6+hashed_data_count+2, unhashed_data_count);

    subpackets_.splice(subpackets_.end(),
                       parse_subpackets(unhashed_subpacket_data_));

    // TODO: Left sixteen bits

    signature_ = packet_data.substr(6 + hashed_data_count
                                    + 2 + unhashed_data_count + 2);
  }
  else {
    throw unsupported_feature_error(-1, "non-v3/v4 signatures");
  }

  SetSignaturePropertiesFromSubpackets();
}

uint8_t SignaturePacket::tag() const {
  return 2;
}

std::string SignaturePacket::str() const {
  char uid_string[17]; // Flawfinder: ignore (uids have known length)
  const unsigned char* unsigned_key_id =
      reinterpret_cast<const unsigned char*>(key_id_.c_str());
  snprintf(uid_string, 17, "%02x%02x%02x%02x%02x%02x%02x%02x",
           unsigned_key_id[0], unsigned_key_id[1], unsigned_key_id[2],
           unsigned_key_id[3], unsigned_key_id[4], unsigned_key_id[5],
           unsigned_key_id[6], unsigned_key_id[7]);
  return (boost::format("Signature, version %d, type 0x%02x, "
                        "uid %s")
          % static_cast<int>(version_)
          % static_cast<int>(signature_type_)
          % uid_string).str();
}

uint8_t SignaturePacket::version() const {
  return version_;
}

uint8_t SignaturePacket::signature_type() const {
  return signature_type_;
}

uint8_t SignaturePacket::public_key_algorithm() const {
  return public_key_algorithm_;
}

uint8_t SignaturePacket::hash_algorithm() const {
  return hash_algorithm_;
}

const std::string& SignaturePacket::hashed_subpacket_data() const {
  return hashed_subpacket_data_;
}

const std::string& SignaturePacket::unhashed_subpacket_data() const {
  return unhashed_subpacket_data_;
}

const uint8_t* SignaturePacket::hash_left_16bits() const {
  return hash_left_16bits_;
}

const std::string& SignaturePacket::signature() const {
  return signature_;
}

void SignaturePacket::SetSignaturePropertiesFromSubpackets() {
  const std::list<std::shared_ptr<PGPPacket>>& subpackets = this->subpackets();
  for (auto current_subpacket_ptr  = subpackets.begin();
            current_subpacket_ptr != subpackets.end();
            current_subpacket_ptr++) {
    // FIXME: This is bad.
    std::shared_ptr<UnknownPGPPacket> subpacket =
        std::dynamic_pointer_cast<UnknownPGPPacket>(*current_subpacket_ptr);

    if (nullptr == subpacket) {
      continue;
    }

    if (16 == subpacket->tag()) {
      std::string subpacket_key_id = subpacket->contents();
      if (8 != subpacket_key_id.length()) {
        throw invalid_packet_error(
            "Signature issuer subpacket has wrong length.");
      }
      key_id_ = subpacket_key_id;
    }
  }
}

const std::string& SignaturePacket::hashed_data() const {
  return hashed_data_;
}

}
<|endoftext|>


<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008 Aristid Breitkreuz, Ruediger Sonderfeld

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.
*/

#include "flusspferd/xml/xml.hpp"
#include "flusspferd/xml/context.hpp"
#include "flusspferd/xml/parse.hpp"
#include "flusspferd/xml/push_parser.hpp"
#include "flusspferd/xml/node.hpp"
#include "flusspferd/xml/document.hpp"
#include "flusspferd/xml/text.hpp"
#include "flusspferd/xml/namespace.hpp"
#include "flusspferd/xml/reference.hpp"
#include "flusspferd/xml/attribute.hpp"
#include "flusspferd/xml/processing_instruction.hpp"
#include "flusspferd/function_adapter.hpp"
#include "flusspferd/local_root_scope.hpp"
#include "flusspferd/create.hpp"
#include "flusspferd/string.hpp"
#include "flusspferd/security.hpp"
#include <libxml/xmlIO.h>

using namespace flusspferd;
using namespace flusspferd::xml;

extern "C" value flusspferd_load(object container)
{
  return load_xml(container);
}

static void safety_io_callbacks();

object flusspferd::xml::load_xml(object container) {
  safety_io_callbacks();

  local_root_scope scope;

  value previous = container.get_property("XML");

  if (previous.is_object())
    return previous.to_object();

  LIBXML_TEST_VERSION

  object XML = flusspferd::create_object();

  load_class<node>(XML);
  load_class<document>(XML);
  load_class<text>(XML);
  load_class<comment>(XML);
  load_class<cdata_section>(XML);
  load_class<reference_>(XML);
  load_class<processing_instruction>(XML);
  load_class<attribute_>(XML);
  load_class<namespace_>(XML);

  load_class<push_parser>(XML);

  create_native_function(XML, "parseBlob", &parse_blob);
  create_native_function(XML, "parseFile", &parse_file);

  load_class<xml::context>(XML);

  container.define_property(
    "XML",
    XML,
    object::read_only_property | object::dont_enumerate);

  return XML;
}

template<int (*OldMatch)(char const *), unsigned mode>
static int safety_match(char const *name) {
  if (!OldMatch(name))
    return 0;

  std::string path(name);

  std::size_t nonletter = path.find_first_not_of(
    "abcdefghijklmnopqrstuvwxyz"
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ");

  if (nonletter != 0 && nonletter != std::string::npos &&
      path[nonletter] == ':')
    return flusspferd::security::get().check_url(path, mode);
  else
    return flusspferd::security::get().check_path(path, mode);
}

static void safety_io_callbacks() {
  xmlCleanupInputCallbacks();
  xmlCleanupOutputCallbacks();

#define REG_INPUT(name) \
  xmlRegisterInputCallbacks( \
    safety_match<name ## Match, security::READ>, \
    name ## Open, \
    name ## Read, \
    name ## Close) \
  /**/

  REG_INPUT(xmlFile);
  REG_INPUT(xmlIOHTTP);

  // disable any output
  xmlRegisterOutputCallbacks(0, 0, 0, 0);
}
<commit_msg>XML: call XML initialization more safely<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008 Aristid Breitkreuz, Ruediger Sonderfeld

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.
*/

#include "flusspferd/xml/xml.hpp"
#include "flusspferd/xml/context.hpp"
#include "flusspferd/xml/parse.hpp"
#include "flusspferd/xml/push_parser.hpp"
#include "flusspferd/xml/node.hpp"
#include "flusspferd/xml/document.hpp"
#include "flusspferd/xml/text.hpp"
#include "flusspferd/xml/namespace.hpp"
#include "flusspferd/xml/reference.hpp"
#include "flusspferd/xml/attribute.hpp"
#include "flusspferd/xml/processing_instruction.hpp"
#include "flusspferd/function_adapter.hpp"
#include "flusspferd/local_root_scope.hpp"
#include "flusspferd/create.hpp"
#include "flusspferd/string.hpp"
#include "flusspferd/security.hpp"
#include <boost/thread/once.hpp>
#include <libxml/xmlIO.h>
#include <libxml/xpath.h>

using namespace flusspferd;
using namespace flusspferd::xml;

extern "C" value flusspferd_load(object container)
{
  return load_xml(container);
}

static void safety_io_callbacks();

static void once() {
  LIBXML_TEST_VERSION
  xmlXPathInit();
  safety_io_callbacks();
}

static boost::once_flag once_flag;

object flusspferd::xml::load_xml(object container) {
  local_root_scope scope;

  value previous = container.get_property("XML");

  if (previous.is_object())
    return previous.to_object();

  boost::call_once(once_flag, &once);

  object XML = flusspferd::create_object();

  load_class<node>(XML);
  load_class<document>(XML);
  load_class<text>(XML);
  load_class<comment>(XML);
  load_class<cdata_section>(XML);
  load_class<reference_>(XML);
  load_class<processing_instruction>(XML);
  load_class<attribute_>(XML);
  load_class<namespace_>(XML);

  load_class<push_parser>(XML);

  create_native_function(XML, "parseBlob", &parse_blob);
  create_native_function(XML, "parseFile", &parse_file);

  load_class<xml::context>(XML);

  container.define_property(
    "XML",
    XML,
    object::read_only_property | object::dont_enumerate);

  return XML;
}

template<int (*OldMatch)(char const *), unsigned mode>
static int safety_match(char const *name) {
  if (!OldMatch(name))
    return 0;

  std::string path(name);

  std::size_t nonletter = path.find_first_not_of(
    "abcdefghijklmnopqrstuvwxyz"
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ");

  if (nonletter != 0 && nonletter != std::string::npos &&
      path[nonletter] == ':')
    return flusspferd::security::get().check_url(path, mode);
  else
    return flusspferd::security::get().check_path(path, mode);
}

static void safety_io_callbacks() {
  xmlCleanupInputCallbacks();
  xmlCleanupOutputCallbacks();

#define REG_INPUT(name) \
  xmlRegisterInputCallbacks( \
    safety_match<name ## Match, security::READ>, \
    name ## Open, \
    name ## Read, \
    name ## Close) \
  /**/

  REG_INPUT(xmlFile);
  REG_INPUT(xmlIOHTTP);

  // disable any output
  xmlRegisterOutputCallbacks(0, 0, 0, 0);
}
<|endoftext|>


<commit_before>/*--------------------------------------------------------------------------*\
 |                                                                          |
 |  Copyright (C) 1998                                                      |
 |                                                                          |
 |         , __                 , __                                        |
 |        /|/  \               /|/  \                                       |
 |         | __/ _   ,_         | __/ _   ,_                                |
 |         |   \|/  /  |  |   | |   \|/  /  |  |   |                        |
 |         |(__/|__/   |_/ \_/|/|(__/|__/   |_/ \_/|/                       |
 |                           /|                   /|                        |
 |                           \|                   \|                        |
 |                                                                          |
 |      Enrico Bertolazzi                                                   |
 |      Dipartimento di Ingegneria Industriale                              |
 |      Universita` degli Studi di Trento                                   |
 |      email: enrico.bertolazzi@unitn.it                                   |
 |                                                                          |
\*--------------------------------------------------------------------------*/
/*!
 *
 * \date     October 28, 2015
 * \version  5.1
 * \note     first release Jan 12, 1998
 *
 * \author   Enrico Bertolazzi
 *
 * \par      Affiliation:
 *           Department of Industrial Engineering

 *           University of Trento

 *           Via Sommarive 9, I -- 38123 Trento, Italy

 *           enrico.bertolazzi@unitn.it
 *
 */

#include "Splines.hh"
#include <cmath>

//! Various kind of splines
namespace Splines {

  char const * spline_type[] = {
    "constant",    // 0
    "linear",      // 1
    "cubic base",  // 2
    "cubic",       // 3
    "akima",       // 4
    "bessel",      // 5
    "pchip",       // 6
    "quintic",     // 7
    "spline set"   // 8
  } ;

  using std::abs ;
  using std::sqrt ;
  using std::cbrt ;

  static valueType const machineEps = std::numeric_limits<valueType>::epsilon() ;
  static valueType const m_2pi      = 6.28318530717958647692528676656  ; // 2*pi

  //! quadratic polinomial roots
  /*!
    Compute the roots of the polynomial

    \f[ a_0 + a_1 z + a_2 z^2 \f]

    and store the results is `real` and `imag`.
    It is assumed that \f$ a_2 \f$ is nonzero.
  */
  /*
    Converted to be compatible with ELF90 by Alan Miller
    amiller @ bigpond.net.au
    WWW-page: http://users.bigpond.net.au/amiller
    Latest revision - 27 February 1997
  */

  // num real roots, num complex root
  pair<int,int>
  quadraticRoots( valueType const a[3],
                  valueType       real[2],
                  valueType       imag[2] ) {

    // A x^2 + B x + C
    valueType const & C = a[0] ;
    valueType const & B = a[1] ;
    valueType const & A = a[2] ;

    real[0] = real[1] = imag[0] = imag[1] = 0 ;

    pair<int,int> res(0,0) ;
    if ( a[0] == 0 ) {
      real[0] = -B/A ;
      res.first = 1 ; // una singola radice reale
    } else {
      valueType twoA = 2*A ;
      valueType d    = B*B - 4*A*C ;
      valueType absd = abs(d) ;
      if ( absd <= 2*machineEps*B*B ) {
        real[0] = -B/twoA ; // EQUAL REAL ROOTS
        res.first = 1 ; // 2 radici reali coincidenti
      } else {
        valueType r = sqrt(absd) ;
        if ( d < 0 ) { // COMPLEX ROOTS
          real[0] = real[1] = -B/twoA ;
          imag[0] = abs(r/twoA) ;
          imag[1] = -imag[0] ;
          res.second = 2 ; // 2 radici complesse coniugate
        } else {
          // DISTINCT REAL ROOTS
          if ( B == 0  ) {
            real[0] = abs(r/twoA) ;
            real[1] = -real[0] ;
          } else {
            valueType w = -B ;
            if ( w > 0 ) w += r ; else w -= r ;
            w *= 0.5 ;
            real[0] = C/w ;
            real[1] = w/A ;
          }
          res.first = 2 ; // 2 radici reali distinte
        }
      }
    }
    return res ;
  }

  //! cubic polinomial roots
  /*!
    Compute the roots of the polynomial

    \f[ a_0 + a_1 z + a_2 z^2 + a_3 z^3 \f]

    and store the results is `real` and `imag`.
    It is assumed that \f$ a_3 \f$ is nonzero.
  */

  pair<int,int>
  cubicRoots( valueType const a[4],
              valueType       real[3],
              valueType       imag[3] ) {

    // initialize roots
    real[0] = real[1] = real[2] =
    imag[0] = imag[1] = imag[2] = 0 ;

    // trivial case
    if ( a[0] == 0 ) {
      pair<int,int> res = quadraticRoots( a+1, real+1, imag+1 ) ; // quadratica degenerata
      ++res.first ;
      return res ;
    }

    // trivial case
    if ( a[3] == 0 ) return quadraticRoots( a, real, imag ) ; // cubica degenerata

    // x^3 + A x^2 + B x + C
    valueType const C = a[0]/a[3] ;
    valueType const B = a[1]/a[3] ;
    valueType const A = a[2]/a[3] ;

    // p(y-A/3) = y^3 + p*y + q
    valueType const A3 = A/3 ;
    valueType const p  = B-A*A3 ;
    valueType const q  = C+A3*(2*(A3*A3)-B) ;

    // scaling equation p(S*z)/S^3 = z^3 + 3*(p/S^2/3)*z + 2*(q/S^3/2)
    valueType const S = max( sqrt(abs(p)), cbrt(abs(q)) ) ;

    // check for a triple root
    if ( S <= machineEps ) {
      real[0] = -A3 ;
      return pair<int,int>(1,0) ; // 3 radici reali coincidenti
    }

    valueType const P     = (p/3)/S/S ;
    valueType const sqrtP = sqrt(abs(p/3))/S ;
    valueType const Q     = (q/2)/S/S/S ;

    valueType const d     = P*P*P + Q*Q ;
    valueType const sqrtd = sqrt(abs(d)) ;

    pair<int,int> res(0,0) ;
    if ( sqrtd < abs(q)*machineEps ) {
      // P^3 = - Q^2
      // (x+2*a)(x-a)^2 = x^3 - 3*x*a^2 + 2*a^3
      // cioè -a^2 = P, a^3 = Q ==> a = sqrt(-P)
      valueType tmp = Q > 0 ? sqrtP : -sqrtP ;
      real[0] = tmp ;
      real[1] = -2*tmp ;
      res.first = 2 ; // 3 radici reali, 2 coincidenti
    } else if ( d > 0 ) {
      // w1 = (- Q + sqrt( P^3 + Q^2 ))^(1/3)
      // w2 = (- Q - sqrt( P^3 + Q^2 ))^(1/3)
      valueType w1, w2 ;
      if ( Q > 0 ) {
        w2 = - pow( sqrtd + Q, 1.0 / 3.0 ) ;
        w1 = - P / w2 ;
      } else {
        w1 =   pow( sqrtd - Q, 1.0 / 3.0 ) ;
        w2 = - P / w1 ;
      }
      real[0] = w1 + w2 ;
      real[1] =
      real[2] = -0.5*real[0] ;
      imag[1] = (w1-w2)*sqrt(3.0/4.0) ;
      imag[2] = -imag[1] ;
      res.first  = 1 ;
      res.second = 2 ; // 1 reale 2 complesse coniugate
    } else { // 3 radici reali
      // w1 = (- Q + I*sqrt(|P^3 + Q^2|) )^(1/3)
      // w2 = (- Q - I*sqrt(|P^3 + Q^2|) )^(1/3)
      valueType angle  = atan2( sqrtd, -Q ) ;
      if ( angle < 0 ) angle += m_2pi ;
      angle /= 3 ;
      valueType re = sqrtP * cos(angle) ;
      valueType im = sqrtP * sin(angle) ;
      //if ( Q > 0 ) re = -re ;
      real[0]  = 2*re ;
      real[1]  = real[2] = -re ;
      real[1] += sqrt(3.0) * im ;
      real[2] -= sqrt(3.0) * im ;
      res.first = 3 ; // 3 radici reali distinte
    }

    for ( indexType i = 0 ; i < res.first+res.second ; ++i ) {
      // scalo radici
      real[i] *= S ;
      imag[i] *= S ;
      // traslo radici
      real[i] -= A3 ;
    }

    return res ;
  }

  //! Check if cubic spline with this data is monotone, -2 non monotone data, -1 no, 0 yes, 1 strictly monotone
  indexType
  checkCubicSplineMonotonicity( valueType const X[],
                                valueType const Y[],
                                valueType const Yp[],
                                indexType       npts ) {
    // check monotonicity of data: (assuming X monotone)
    indexType flag = 1 ;
    for ( indexType i = 1 ; i < npts ; ++i ) {
      if ( Y[i-1] > Y[i] ) return -2 ; // non monotone data
      if ( Y[i-1] == Y[i] && X[i-1] < X[i] ) flag = 0 ; // non strict monotone
    }
    // pag 146 Methods of Shape-Preserving Spline Approximation, K
    for ( indexType i = 1 ; i < npts ; ++i ) {
      if ( X[i] <= X[i-1] ) continue ; // skip duplicate points
      valueType dd = (Y[i]-Y[i-1])/(X[i]-X[i-1]) ;
      valueType m0 = Yp[i-1]/dd ;
      valueType m1 = Yp[i]/dd ;
      if ( m0 < 0 || m1 < 0 ) return -1 ; // non monotone
      if ( m0 <= 3 && m1 <= 3 ) {
        if ( flag > 0 && i > 1      && (m0 == 0 || m0 == 3) ) flag = 0 ;
        if ( flag > 0 && i < npts-1 && (m1 == 0 || m1 == 3) ) flag = 0 ;
      } else {
        valueType tmp1 = 2*m0+m1-3 ;
        valueType tmp2 = 2*(m0+m1-2) ;
        valueType tmp3 = m0*tmp2-(tmp1*tmp1)  ;
        if ( tmp2 >= 0 ) {
          if ( tmp3 < 0 ) return -1 ; // non monotone spline
        } else {
          if ( tmp3 > 0 ) return -1 ;
        }
        if ( tmp3 == 0 ) flag = 0 ;
      }
    }
    return flag ; // passed all check
  }
}
<commit_msg>workaround for cbrt on WINDOWS<commit_after>/*--------------------------------------------------------------------------*\
 |                                                                          |
 |  Copyright (C) 1998                                                      |
 |                                                                          |
 |         , __                 , __                                        |
 |        /|/  \               /|/  \                                       |
 |         | __/ _   ,_         | __/ _   ,_                                |
 |         |   \|/  /  |  |   | |   \|/  /  |  |   |                        |
 |         |(__/|__/   |_/ \_/|/|(__/|__/   |_/ \_/|/                       |
 |                           /|                   /|                        |
 |                           \|                   \|                        |
 |                                                                          |
 |      Enrico Bertolazzi                                                   |
 |      Dipartimento di Ingegneria Industriale                              |
 |      Universita` degli Studi di Trento                                   |
 |      email: enrico.bertolazzi@unitn.it                                   |
 |                                                                          |
\*--------------------------------------------------------------------------*/
/*!
 *
 * \date     October 28, 2015
 * \version  5.1
 * \note     first release Jan 12, 1998
 *
 * \author   Enrico Bertolazzi
 *
 * \par      Affiliation:
 *           Department of Industrial Engineering

 *           University of Trento

 *           Via Sommarive 9, I -- 38123 Trento, Italy

 *           enrico.bertolazzi@unitn.it
 *
 */

#include "Splines.hh"
#include <cmath>

//! Various kind of splines
namespace Splines {

  char const * spline_type[] = {
    "constant",    // 0
    "linear",      // 1
    "cubic base",  // 2
    "cubic",       // 3
    "akima",       // 4
    "bessel",      // 5
    "pchip",       // 6
    "quintic",     // 7
    "spline set"   // 8
  } ;

  using std::abs ;
  using std::sqrt ;

  #ifdef _MSC_VER
  // cbrt is not available on WINDOWS?
  static
  inline
  valueType
  cbrt( valueType x )
  { return pow( x, 1.0/3.0 ) ; }
  #else
  using std::cbrt ;
  #endif

  static valueType const machineEps = std::numeric_limits<valueType>::epsilon() ;
  static valueType const m_2pi      = 6.28318530717958647692528676656  ; // 2*pi

  //! quadratic polinomial roots
  /*!
    Compute the roots of the polynomial

    \f[ a_0 + a_1 z + a_2 z^2 \f]

    and store the results is `real` and `imag`.
    It is assumed that \f$ a_2 \f$ is nonzero.
  */
  /*
    Converted to be compatible with ELF90 by Alan Miller
    amiller @ bigpond.net.au
    WWW-page: http://users.bigpond.net.au/amiller
    Latest revision - 27 February 1997
  */

  // num real roots, num complex root
  pair<int,int>
  quadraticRoots( valueType const a[3],
                  valueType       real[2],
                  valueType       imag[2] ) {

    // A x^2 + B x + C
    valueType const & C = a[0] ;
    valueType const & B = a[1] ;
    valueType const & A = a[2] ;

    real[0] = real[1] = imag[0] = imag[1] = 0 ;

    pair<int,int> res(0,0) ;
    if ( a[0] == 0 ) {
      real[0] = -B/A ;
      res.first = 1 ; // una singola radice reale
    } else {
      valueType twoA = 2*A ;
      valueType d    = B*B - 4*A*C ;
      valueType absd = abs(d) ;
      if ( absd <= 2*machineEps*B*B ) {
        real[0] = -B/twoA ; // EQUAL REAL ROOTS
        res.first = 1 ; // 2 radici reali coincidenti
      } else {
        valueType r = sqrt(absd) ;
        if ( d < 0 ) { // COMPLEX ROOTS
          real[0] = real[1] = -B/twoA ;
          imag[0] = abs(r/twoA) ;
          imag[1] = -imag[0] ;
          res.second = 2 ; // 2 radici complesse coniugate
        } else {
          // DISTINCT REAL ROOTS
          if ( B == 0  ) {
            real[0] = abs(r/twoA) ;
            real[1] = -real[0] ;
          } else {
            valueType w = -B ;
            if ( w > 0 ) w += r ; else w -= r ;
            w *= 0.5 ;
            real[0] = C/w ;
            real[1] = w/A ;
          }
          res.first = 2 ; // 2 radici reali distinte
        }
      }
    }
    return res ;
  }

  //! cubic polinomial roots
  /*!
    Compute the roots of the polynomial

    \f[ a_0 + a_1 z + a_2 z^2 + a_3 z^3 \f]

    and store the results is `real` and `imag`.
    It is assumed that \f$ a_3 \f$ is nonzero.
  */

  pair<int,int>
  cubicRoots( valueType const a[4],
              valueType       real[3],
              valueType       imag[3] ) {

    // initialize roots
    real[0] = real[1] = real[2] =
    imag[0] = imag[1] = imag[2] = 0 ;

    // trivial case
    if ( a[0] == 0 ) {
      pair<int,int> res = quadraticRoots( a+1, real+1, imag+1 ) ; // quadratica degenerata
      ++res.first ;
      return res ;
    }

    // trivial case
    if ( a[3] == 0 ) return quadraticRoots( a, real, imag ) ; // cubica degenerata

    // x^3 + A x^2 + B x + C
    valueType const C = a[0]/a[3] ;
    valueType const B = a[1]/a[3] ;
    valueType const A = a[2]/a[3] ;

    // p(y-A/3) = y^3 + p*y + q
    valueType const A3 = A/3 ;
    valueType const p  = B-A*A3 ;
    valueType const q  = C+A3*(2*(A3*A3)-B) ;

    // scaling equation p(S*z)/S^3 = z^3 + 3*(p/S^2/3)*z + 2*(q/S^3/2)
    valueType const S = max( sqrt(abs(p)), cbrt(abs(q)) ) ;

    // check for a triple root
    if ( S <= machineEps ) {
      real[0] = -A3 ;
      return pair<int,int>(1,0) ; // 3 radici reali coincidenti
    }

    valueType const P     = (p/3)/S/S ;
    valueType const sqrtP = sqrt(abs(p/3))/S ;
    valueType const Q     = (q/2)/S/S/S ;

    valueType const d     = P*P*P + Q*Q ;
    valueType const sqrtd = sqrt(abs(d)) ;

    pair<int,int> res(0,0) ;
    if ( sqrtd < abs(q)*machineEps ) {
      // P^3 = - Q^2
      // (x+2*a)(x-a)^2 = x^3 - 3*x*a^2 + 2*a^3
      // cioè -a^2 = P, a^3 = Q ==> a = sqrt(-P)
      valueType tmp = Q > 0 ? sqrtP : -sqrtP ;
      real[0] = tmp ;
      real[1] = -2*tmp ;
      res.first = 2 ; // 3 radici reali, 2 coincidenti
    } else if ( d > 0 ) {
      // w1 = (- Q + sqrt( P^3 + Q^2 ))^(1/3)
      // w2 = (- Q - sqrt( P^3 + Q^2 ))^(1/3)
      valueType w1, w2 ;
      if ( Q > 0 ) {
        w2 = - pow( sqrtd + Q, 1.0 / 3.0 ) ;
        w1 = - P / w2 ;
      } else {
        w1 =   pow( sqrtd - Q, 1.0 / 3.0 ) ;
        w2 = - P / w1 ;
      }
      real[0] = w1 + w2 ;
      real[1] =
      real[2] = -0.5*real[0] ;
      imag[1] = (w1-w2)*sqrt(3.0/4.0) ;
      imag[2] = -imag[1] ;
      res.first  = 1 ;
      res.second = 2 ; // 1 reale 2 complesse coniugate
    } else { // 3 radici reali
      // w1 = (- Q + I*sqrt(|P^3 + Q^2|) )^(1/3)
      // w2 = (- Q - I*sqrt(|P^3 + Q^2|) )^(1/3)
      valueType angle  = atan2( sqrtd, -Q ) ;
      if ( angle < 0 ) angle += m_2pi ;
      angle /= 3 ;
      valueType re = sqrtP * cos(angle) ;
      valueType im = sqrtP * sin(angle) ;
      //if ( Q > 0 ) re = -re ;
      real[0]  = 2*re ;
      real[1]  = real[2] = -re ;
      real[1] += sqrt(3.0) * im ;
      real[2] -= sqrt(3.0) * im ;
      res.first = 3 ; // 3 radici reali distinte
    }

    for ( indexType i = 0 ; i < res.first+res.second ; ++i ) {
      // scalo radici
      real[i] *= S ;
      imag[i] *= S ;
      // traslo radici
      real[i] -= A3 ;
    }

    return res ;
  }

  //! Check if cubic spline with this data is monotone, -2 non monotone data, -1 no, 0 yes, 1 strictly monotone
  indexType
  checkCubicSplineMonotonicity( valueType const X[],
                                valueType const Y[],
                                valueType const Yp[],
                                indexType       npts ) {
    // check monotonicity of data: (assuming X monotone)
    indexType flag = 1 ;
    for ( indexType i = 1 ; i < npts ; ++i ) {
      if ( Y[i-1] > Y[i] ) return -2 ; // non monotone data
      if ( Y[i-1] == Y[i] && X[i-1] < X[i] ) flag = 0 ; // non strict monotone
    }
    // pag 146 Methods of Shape-Preserving Spline Approximation, K
    for ( indexType i = 1 ; i < npts ; ++i ) {
      if ( X[i] <= X[i-1] ) continue ; // skip duplicate points
      valueType dd = (Y[i]-Y[i-1])/(X[i]-X[i-1]) ;
      valueType m0 = Yp[i-1]/dd ;
      valueType m1 = Yp[i]/dd ;
      if ( m0 < 0 || m1 < 0 ) return -1 ; // non monotone
      if ( m0 <= 3 && m1 <= 3 ) {
        if ( flag > 0 && i > 1      && (m0 == 0 || m0 == 3) ) flag = 0 ;
        if ( flag > 0 && i < npts-1 && (m1 == 0 || m1 == 3) ) flag = 0 ;
      } else {
        valueType tmp1 = 2*m0+m1-3 ;
        valueType tmp2 = 2*(m0+m1-2) ;
        valueType tmp3 = m0*tmp2-(tmp1*tmp1)  ;
        if ( tmp2 >= 0 ) {
          if ( tmp3 < 0 ) return -1 ; // non monotone spline
        } else {
          if ( tmp3 > 0 ) return -1 ;
        }
        if ( tmp3 == 0 ) flag = 0 ;
      }
    }
    return flag ; // passed all check
  }
}
<|endoftext|>


<commit_before>#include "platform/platform.h"

#include "power.h"
#include "lights.h"
#include "bluetooth.h"
#include "signals.h"
#include "util/timer.h"
#include "util/log.h"
#include "can/canread.h"

namespace usb = openxc::interface::usb;
namespace time = openxc::util::time;

using openxc::can::deinitialize;
using openxc::power::suspend;
using openxc::lights::deinitialize;
using openxc::signals::getCanBusCount;
using openxc::signals::getCanBuses;

void openxc::platform::suspend(Pipeline* pipeline) {
    debug("CAN went silent - disabling LED");

    // De-init and shut down all peripherals to save power
    for(int i = 0; i < getCanBusCount(); ++i) {
        can::deinitialize(&getCanBuses()[i]);
    }
    lights::deinitialize();
    usb::deinitialize(pipeline->usb);
    bluetooth::deinitialize();

    // Wait for peripherals to disabled before sleeping
    time::delayMs(100);
    power::suspend();
}
<commit_msg>Remove extra namespace imports.<commit_after>#include "platform/platform.h"

#include "power.h"
#include "lights.h"
#include "bluetooth.h"
#include "signals.h"
#include "util/timer.h"
#include "util/log.h"
#include "can/canread.h"

namespace usb = openxc::interface::usb;
namespace time = openxc::util::time;

using openxc::signals::getCanBusCount;
using openxc::signals::getCanBuses;

void openxc::platform::suspend(Pipeline* pipeline) {
    debug("CAN went silent - disabling LED");

    // De-init and shut down all peripherals to save power
    for(int i = 0; i < getCanBusCount(); ++i) {
        can::deinitialize(&getCanBuses()[i]);
    }
    lights::deinitialize();
    usb::deinitialize(pipeline->usb);
    bluetooth::deinitialize();

    // Wait for peripherals to disabled before sleeping
    time::delayMs(100);
    power::suspend();
}
<|endoftext|>


<commit_before>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2019 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#pragma once

#include <deque>
#include <vector>

#include "caf/fwd.hpp"
#include "caf/logger.hpp"
#include "caf/net/defaults.hpp"
#include "caf/net/endpoint_manager.hpp"
#include "caf/net/fwd.hpp"
#include "caf/net/receive_policy.hpp"
#include "caf/net/stream_socket.hpp"
#include "caf/net/transport_base.hpp"
#include "caf/net/transport_worker.hpp"
#include "caf/sec.hpp"
#include "caf/span.hpp"

namespace caf::net {

template <class Application>
using stream_transport_base = transport_base<
  stream_transport<Application>, transport_worker<Application>, stream_socket,
  Application, unit_t>;

/// Implements a stream_transport that manages a stream socket.
template <class Application>
class stream_transport : public stream_transport_base<Application> {
public:
  // -- member types -----------------------------------------------------------

  using application_type = Application;

  using worker_type = transport_worker<application_type>;

  using super = stream_transport_base<application_type>;

  using id_type = typename super::id_type;

  using buffer_type = typename super::buffer_type;

  using write_queue_type = std::deque<std::pair<bool, buffer_type>>;

  // -- constructors, destructors, and assignment operators --------------------

  stream_transport(stream_socket handle, application_type application)
    : super(handle, std::move(application)),
      written_(0),
      read_threshold_(1024),
      collected_(0),
      max_(1024),
      rd_flag_(net::receive_policy_flag::exactly) {
    CAF_ASSERT(handle != invalid_socket);
    nodelay(handle, true);
  }

  // -- member functions -------------------------------------------------------

  bool handle_read_event(endpoint_manager&) override {
    auto buf = this->read_buf_.data() + this->collected_;
    size_t len = this->read_threshold_ - this->collected_;
    CAF_LOG_TRACE(CAF_ARG2("handle", this->handle().id)
                  << CAF_ARG2("missing", len));
    auto ret = read(this->handle_, make_span(buf, len));
    // Update state.
    if (auto num_bytes = get_if<size_t>(&ret)) {
      CAF_LOG_DEBUG(CAF_ARG(len)
                    << CAF_ARG(this->handle_.id) << CAF_ARG(*num_bytes));
      this->collected_ += *num_bytes;
      if (this->collected_ >= this->read_threshold_) {
        if (auto err = this->next_layer_.handle_data(*this,
                                                     make_span(
                                                       this->read_buf_))) {
          CAF_LOG_ERROR("handle_data failed: " << CAF_ARG(err));
          return false;
        }
        this->prepare_next_read();
      }
    } else {
      auto err = get<sec>(ret);
      if (err != sec::unavailable_or_would_block) {
        CAF_LOG_DEBUG("read failed" << CAF_ARG(err));
        this->next_layer_.handle_error(err);
        return false;
      }
    }
    return true;
  }

  bool handle_write_event(endpoint_manager& manager) override {
    CAF_LOG_TRACE(CAF_ARG2("handle", this->handle_.id)
                  << CAF_ARG2("queue-size", write_queue_.size()));
    auto fetch_next_message = [&] {
      if (auto msg = manager.next_message()) {
        this->next_layer_.write_message(*this, std::move(msg));
        return true;
      }
      return false;
    };
    do {
      if (auto err = write_some())
        return err == sec::unavailable_or_would_block;
    } while (fetch_next_message());
    return !write_queue_.empty();
  }

  void write_packet(id_type, span<buffer_type*> buffers) override {
    CAF_LOG_TRACE("");
    CAF_ASSERT(!buffers.empty());
    if (this->write_queue_.empty())
      this->manager().register_writing();
    // By convention, the first buffer is a header buffer. Every other buffer is
    // a payload buffer.
    auto i = buffers.begin();
    this->write_queue_.emplace_back(true, std::move(*(*i++)));
    while (i != buffers.end())
      this->write_queue_.emplace_back(false, std::move(*(*i++)));
  }

  void configure_read(receive_policy::config cfg) override {
    rd_flag_ = cfg.first;
    max_ = cfg.second;
    prepare_next_read();
  }

private:
  // -- utility functions ------------------------------------------------------

  void prepare_next_read() {
    collected_ = 0;
    switch (rd_flag_) {
      case net::receive_policy_flag::exactly:
        if (this->read_buf_.size() != max_)
          this->read_buf_.resize(max_);
        read_threshold_ = max_;
        break;
      case net::receive_policy_flag::at_most:
        if (this->read_buf_.size() != max_)
          this->read_buf_.resize(max_);
        read_threshold_ = 1;
        break;
      case net::receive_policy_flag::at_least: {
        // read up to 10% more, but at least allow 100 bytes more
        auto max_size = max_ + std::max<size_t>(100, max_ / 10);
        if (this->read_buf_.size() != max_size)
          this->read_buf_.resize(max_size);
        read_threshold_ = max_;
        break;
      }
    }
  }

  error write_some() {
    // Helper function to sort empty buffers back into the right caches.
    auto recycle = [&]() {
      auto& front = this->write_queue_.front();
      auto& is_header = front.first;
      auto& buf = front.second;
      written_ = 0;
      buf.clear();
      if (is_header) {
        if (this->header_bufs_.size() < this->header_bufs_.capacity())
          this->header_bufs_.emplace_back(std::move(buf));
      } else if (this->payload_bufs_.size() < this->payload_bufs_.capacity()) {
        this->payload_bufs_.emplace_back(std::move(buf));
      }
      write_queue_.pop_front();
    };
    // Write buffers from the write_queue_ for as long as possible.
    while (!write_queue_.empty()) {
      auto& buf = write_queue_.front().second;
      CAF_ASSERT(!buf.empty());
      auto data = buf.data() + written_;
      auto len = buf.size() - written_;
      auto write_ret = write(this->handle(), make_span(data, len));
      if (auto num_bytes = get_if<size_t>(&write_ret)) {
        CAF_LOG_DEBUG(CAF_ARG(this->handle_.id) << CAF_ARG(*num_bytes));
        written_ += *num_bytes;
        if (written_ >= buf.size()) {
          recycle();
          written_ = 0;
        }
      } else {
        auto err = get<sec>(write_ret);
        if (err != sec::unavailable_or_would_block) {
          CAF_LOG_DEBUG("send failed" << CAF_ARG(err));
          this->next_layer_.handle_error(err);
        }
        return err;
      }
    }
    return none;
  }

  write_queue_type write_queue_;
  size_t written_;
  size_t read_threshold_;
  size_t collected_;
  size_t max_;
  receive_policy_flag rd_flag_;
  // TODO implement retries using this member!
  // size_t max_consecutive_reads_;
};

} // namespace caf::net
<commit_msg>Include review feedback<commit_after>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2019 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#pragma once

#include <deque>
#include <vector>

#include "caf/fwd.hpp"
#include "caf/logger.hpp"
#include "caf/net/defaults.hpp"
#include "caf/net/endpoint_manager.hpp"
#include "caf/net/fwd.hpp"
#include "caf/net/receive_policy.hpp"
#include "caf/net/stream_socket.hpp"
#include "caf/net/transport_base.hpp"
#include "caf/net/transport_worker.hpp"
#include "caf/sec.hpp"
#include "caf/span.hpp"

namespace caf::net {

template <class Application>
using stream_transport_base = transport_base<
  stream_transport<Application>, transport_worker<Application>, stream_socket,
  Application, unit_t>;

/// Implements a stream_transport that manages a stream socket.
template <class Application>
class stream_transport : public stream_transport_base<Application> {
public:
  // -- member types -----------------------------------------------------------

  using application_type = Application;

  using worker_type = transport_worker<application_type>;

  using super = stream_transport_base<application_type>;

  using id_type = typename super::id_type;

  using buffer_type = typename super::buffer_type;

  using write_queue_type = std::deque<std::pair<bool, buffer_type>>;

  // -- constructors, destructors, and assignment operators --------------------

  stream_transport(stream_socket handle, application_type application)
    : super(handle, std::move(application)),
      written_(0),
      read_threshold_(1024),
      collected_(0),
      max_(1024),
      rd_flag_(net::receive_policy_flag::exactly) {
    CAF_ASSERT(handle != invalid_socket);
    nodelay(handle, true);
  }

  // -- member functions -------------------------------------------------------

  bool handle_read_event(endpoint_manager&) override {
    auto buf = this->read_buf_.data() + this->collected_;
    size_t len = this->read_threshold_ - this->collected_;
    CAF_LOG_TRACE(CAF_ARG2("handle", this->handle().id)
                  << CAF_ARG2("missing", len));
    auto ret = read(this->handle_, make_span(buf, len));
    // Update state.
    if (auto num_bytes = get_if<size_t>(&ret)) {
      CAF_LOG_DEBUG(CAF_ARG(len)
                    << CAF_ARG(this->handle_.id) << CAF_ARG(*num_bytes));
      this->collected_ += *num_bytes;
      if (this->collected_ >= this->read_threshold_) {
        if (auto err = this->next_layer_.handle_data(*this,
                                                     make_span(
                                                       this->read_buf_))) {
          CAF_LOG_ERROR("handle_data failed: " << CAF_ARG(err));
          return false;
        }
        this->prepare_next_read();
      }
    } else {
      auto err = get<sec>(ret);
      if (err != sec::unavailable_or_would_block) {
        CAF_LOG_DEBUG("read failed" << CAF_ARG(err));
        this->next_layer_.handle_error(err);
        return false;
      }
    }
    return true;
  }

  bool handle_write_event(endpoint_manager& manager) override {
    CAF_LOG_TRACE(CAF_ARG2("handle", this->handle_.id)
                  << CAF_ARG2("queue-size", write_queue_.size()));
    auto drain_write_queue = []() -> error_code<sec> {
      // Helper function to sort empty buffers back into the right caches.
      auto recycle = [&]() {
        auto& front = this->write_queue_.front();
        auto& is_header = front.first;
        auto& buf = front.second;
        written_ = 0;
        buf.clear();
        if (is_header) {
          if (this->header_bufs_.size() < this->header_bufs_.capacity())
            this->header_bufs_.emplace_back(std::move(buf));
        } else if (this->payload_bufs_.size() < this->payload_bufs_.capacity()) {
          this->payload_bufs_.emplace_back(std::move(buf));
        }
        write_queue_.pop_front();
      };
      // Write buffers from the write_queue_ for as long as possible.
      while (!write_queue_.empty()) {
        auto& buf = write_queue_.front().second;
        CAF_ASSERT(!buf.empty());
        auto data = buf.data() + written_;
        auto len = buf.size() - written_;
        auto write_ret = write(this->handle(), make_span(data, len));
        if (auto num_bytes = get_if<size_t>(&write_ret)) {
          CAF_LOG_DEBUG(CAF_ARG(this->handle_.id) << CAF_ARG(*num_bytes));
          written_ += *num_bytes;
          if (written_ >= buf.size()) {
            recycle();
            written_ = 0;
          }
        } else {
          auto err = get<sec>(write_ret);
          if (err != sec::unavailable_or_would_block) {
            CAF_LOG_DEBUG("send failed" << CAF_ARG(err));
            this->next_layer_.handle_error(err);
          }
          return err;
        }
      }
      return none;
    };
    auto fetch_next_message = [&] {
      if (auto msg = manager.next_message()) {
        this->next_layer_.write_message(*this, std::move(msg));
        return true;
      }
      return false;
    };
    do {
      if (auto err = drain_write_queue())
        return err == sec::unavailable_or_would_block;
    } while (fetch_next_message());
    CAF_ASSERT(write_queue_.empty());
    return false;
  }

  void write_packet(id_type, span<buffer_type*> buffers) override {
    CAF_LOG_TRACE("");
    CAF_ASSERT(!buffers.empty());
    if (this->write_queue_.empty())
      this->manager().register_writing();
    // By convention, the first buffer is a header buffer. Every other buffer is
    // a payload buffer.
    auto i = buffers.begin();
    this->write_queue_.emplace_back(true, std::move(*(*i++)));
    while (i != buffers.end())
      this->write_queue_.emplace_back(false, std::move(*(*i++)));
  }

  void configure_read(receive_policy::config cfg) override {
    rd_flag_ = cfg.first;
    max_ = cfg.second;
    prepare_next_read();
  }

private:
  // -- utility functions ------------------------------------------------------

  void prepare_next_read() {
    collected_ = 0;
    switch (rd_flag_) {
      case net::receive_policy_flag::exactly:
        if (this->read_buf_.size() != max_)
          this->read_buf_.resize(max_);
        read_threshold_ = max_;
        break;
      case net::receive_policy_flag::at_most:
        if (this->read_buf_.size() != max_)
          this->read_buf_.resize(max_);
        read_threshold_ = 1;
        break;
      case net::receive_policy_flag::at_least: {
        // read up to 10% more, but at least allow 100 bytes more
        auto max_size = max_ + std::max<size_t>(100, max_ / 10);
        if (this->read_buf_.size() != max_size)
          this->read_buf_.resize(max_size);
        read_threshold_ = max_;
        break;
      }
    }
  }

  write_queue_type write_queue_;
  size_t written_;
  size_t read_threshold_;
  size_t collected_;
  size_t max_;
  receive_policy_flag rd_flag_;
  // TODO implement retries using this member!
  // size_t max_consecutive_reads_;
};

} // namespace caf::net
<|endoftext|>


<commit_before>/* +------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)            |
   |                          https://www.mrpt.org/                         |
   |                                                                        |
   | Copyright (c) 2005-2022, Individual contributors, see AUTHORS file     |
   | See: https://www.mrpt.org/Authors - All rights reserved.               |
   | Released under BSD License. See: https://www.mrpt.org/License          |
   +------------------------------------------------------------------------+ */

#include <gtest/gtest.h>
#include <mrpt/opengl/CBox.h>
#include <mrpt/opengl/CFBORender.h>
#include <mrpt/opengl/CGridPlaneXY.h>
#include <mrpt/opengl/CMesh.h>
#include <mrpt/opengl/CMeshFast.h>
#include <mrpt/opengl/CSphere.h>
#include <mrpt/opengl/CText3D.h>
#include <mrpt/opengl/stock_objects.h>
#include <mrpt/system/filesystem.h>
//
#include <Eigen/Dense>
//
#include <mrpt/config.h>  // for MRPT_HAS_*
#include <test_mrpt_common.h>

#if MRPT_HAS_OPENCV && MRPT_HAS_OPENGL_GLUT && MRPT_HAS_EGL
#define RUN_OFFSCREEN_RENDER_TESTS
#endif

// In MIPS, these tests crash in autobuilders, skip them:
#if defined(__mips__) || defined(__mips)
#undef RUN_OFFSCREEN_RENDER_TESTS
#endif

static float imageDiff(
	const mrpt::img::CImage& im1, const mrpt::img::CImage& im2)
{
	mrpt::math::CMatrixFloat r1, g1, b1;
	im1.getAsRGBMatrices(r1, g1, b1);

	mrpt::math::CMatrixFloat r2, g2, b2;
	im2.getAsRGBMatrices(r2, g2, b2);

	return (r1 - r2).asEigen().array().abs().sum() +
		(g1 - g2).asEigen().array().abs().sum() +
		(b1 - b2).asEigen().array().abs().sum();
}

static void test_opengl_CFBORender(const bool useCameraFromIntrinsics)
{
	using namespace mrpt;  // _deg
	using namespace std::string_literals;  // s
	using namespace mrpt::opengl;

	const std::string expected_RGB_img_file = UNITTEST_BASEDIR +
		"/tests/CFBORender_expected_rgb_"s +
		(useCameraFromIntrinsics ? "camInt"s : "camFOV"s) + ".png"s;

	const std::string expected_depth_img_file = UNITTEST_BASEDIR +
		"/tests/CFBORender_expected_depth_"s +
		(useCameraFromIntrinsics ? "camInt"s : "camFOV"s) + ".png"s;

	COpenGLScene scene;

	{
		auto obj = mrpt::opengl::CGridPlaneXY::Create(-20, 20, -20, 20, 0, 5);
		obj->setColor(0.4f, 0.4f, 0.4f);
		scene.insert(obj);
	}
	{
		auto obj = mrpt::opengl::CBox::Create(
			mrpt::math::TPoint3D(0, 0, 0), mrpt::math::TPoint3D(.1, .1, .1));
		obj->setColor(1.0f, 0.f, 0.f);
		obj->setName("x");
		obj->enableShowName(true);
		obj->setLocation(1.0, 0, 0);
		scene.insert(obj);
	}
	{
		auto obj = mrpt::opengl::CTexturedPlane::Create();
		obj->setPlaneCorners(-10, 10, -10, 10);
		obj->setColor_u8(0x00, 0xff, 0xff, 0xff);
		obj->setLocation(0, 0, -14);
		scene.insert(obj);
	}
	{
		auto obj = mrpt::opengl::CSphere::Create();
		obj->setColor(0, 0, 1);
		obj->setRadius(1.0f);
		obj->setLocation(0, 1, 0);
		obj->setName("ball_1");
		scene.insert(obj);
	}

	{
		auto obj = mrpt::opengl::CText3D::Create("Hi there!");
		obj->setLocation(5.0, 3.0, 1.0);
		scene.insert(obj);
	}
	{
		auto obj = opengl::stock_objects::CornerXYZ(2.0f);
		obj->setLocation(-3, -2, 0.5);
		scene.insert(obj);
	}

	// CMeshFast, CMesh:
	{
		double off_x = -5.0, STEP_X = 1.0;
		opengl::CMeshFast::Ptr obj1 = opengl::CMeshFast::Create();
		opengl::CMeshFast::Ptr obj2 = opengl::CMeshFast::Create();
		opengl::CMesh::Ptr obj3 = opengl::CMesh::Create();
		opengl::CMesh::Ptr obj4 = opengl::CMesh::Create();

		obj1->setXBounds(-1, 1);
		obj1->setYBounds(-1, 1);

		const int W = 128, H = 128;

		mrpt::math::CMatrixDynamic<float> Z(H, W);

		for (int r = 0; r < H; r++)
			for (int c = 0; c < W; c++)
				Z(r, c) = sin(0.05 * (c + r) - 0.5) * cos(0.9 - 0.03 * r);

		const std::string texture_file = mrpt::system::getShareMRPTDir() +
			"datasets/sample-texture-terrain.jpg"s;

		mrpt::img::CImage im;

		// obj1:
		obj1->setZ(Z);
		obj1->enableColorFromZ(true);
		obj1->setPointSize(2.0);
		obj1->setLocation(off_x, 0, 0);
		scene.insert(obj1);

		// obj 2:
		if (im.loadFromFile(texture_file))
		{
			obj2->assignImageAndZ(im, Z);
			obj2->setPointSize(2.0);
			obj2->setLocation(off_x, 3, 0);
			scene.insert(obj2);
		}

		off_x += STEP_X;

		// obj 3:
		obj3->setZ(Z);
		obj3->enableColorFromZ(true, mrpt::img::cmJET);
		obj3->enableWireFrame(true);
		obj3->setLocation(off_x, 0, 0);
		obj3->cullFaces(mrpt::opengl::TCullFace::BACK);
		scene.insert(obj3);

		// obj 4:
		if (im.getWidth() > 1)
		{
			obj4->assignImageAndZ(im, Z);
			obj4->setLocation(off_x, 3, 0);
			obj4->cullFaces(mrpt::opengl::TCullFace::BACK);
			scene.insert(obj4);
		}
	}

	int width = 500, height = 400;
	const double cameraFOVdeg = 120.0;

	CFBORender renderer(width, height);
	mrpt::img::CImage frame(width, height, mrpt::img::CH_RGB);
	mrpt::math::CMatrixFloat depth;

	scene.getViewport()->setCustomBackgroundColor({0.3f, 0.3f, 0.3f, 1.0f});
	const float clipMax = 25.0f;
	scene.getViewport()->setViewportClipDistances(0.1, clipMax);

	{
		CCamera& camera = renderer.getCamera(scene);

		if (useCameraFromIntrinsics)
		{
			mrpt::img::TCamera c1;
			c1.ncols = width;
			c1.nrows = height;
			c1.fx(width * 0.5);
			c1.fy(width * 0.5);
			c1.cx(width / 2);
			c1.cy(height / 2);

			camera.setProjectiveFromPinhole(c1);
		}
		else
		{
			camera.setProjectiveFOVdeg(cameraFOVdeg);
		}

		// Defined by setPose() instead of orbit values:
		camera.set6DOFMode(true);

		// Reference camera pose:
		auto robotPose = mrpt::poses::CPose3D(
			0, 0, 10.0, 0.0_deg /*yaw*/, 90.0_deg /*pitch*/, 0.0_deg /*roll*/);

		// Convert to +Z pointing forward camera axes:
		auto camPose =
			robotPose +
			mrpt::poses::CPose3D::FromYawPitchRoll(
				90.0_deg /*yaw*/, 0.0_deg /*pitch*/, 90.0_deg /*roll*/);

		camera.setPose(camPose);
	}

	renderer.render_RGBD(scene, frame, depth);

	mrpt::img::CImage gt_frame;
	bool readOk_rgb = gt_frame.loadFromFile(expected_RGB_img_file);

	EXPECT_TRUE(readOk_rgb);

	const float rgb_diff = imageDiff(gt_frame, frame);
	std::cout << "rgb_diff=" << rgb_diff << "\n";
	EXPECT_LT(rgb_diff, 5000.0f);

	{
		mrpt::img::CImage imDepth;
		depth *= (1.0f / clipMax);
		imDepth.setFromMatrix(depth, true);

		mrpt::img::CImage gt_imDepth;
		bool readOk_depth = gt_imDepth.loadFromFile(expected_depth_img_file);

		EXPECT_TRUE(readOk_depth);

		const float depth_diff = imageDiff(gt_imDepth, imDepth);
		std::cout << "depth_diff=" << depth_diff << "\n";
		EXPECT_LT(depth_diff, 3000.0f);
	}
}

#if defined(RUN_OFFSCREEN_RENDER_TESTS)
TEST(OpenGL, CFBORender_camera_intrinsics)
#else
TEST(OpenGL, DISABLED_CFBORender_camera_intrinsics)
#endif
{
	test_opengl_CFBORender(true);
}

#if defined(RUN_OFFSCREEN_RENDER_TESTS)
TEST(OpenGL, CFBORender_camera_fov)
#else
TEST(OpenGL, DISABLED_CFBORender_camera_fov)
#endif
{
	test_opengl_CFBORender(false);
}
<commit_msg>like last commit, for failing ppc arch too<commit_after>/* +------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)            |
   |                          https://www.mrpt.org/                         |
   |                                                                        |
   | Copyright (c) 2005-2022, Individual contributors, see AUTHORS file     |
   | See: https://www.mrpt.org/Authors - All rights reserved.               |
   | Released under BSD License. See: https://www.mrpt.org/License          |
   +------------------------------------------------------------------------+ */

#include <gtest/gtest.h>
#include <mrpt/opengl/CBox.h>
#include <mrpt/opengl/CFBORender.h>
#include <mrpt/opengl/CGridPlaneXY.h>
#include <mrpt/opengl/CMesh.h>
#include <mrpt/opengl/CMeshFast.h>
#include <mrpt/opengl/CSphere.h>
#include <mrpt/opengl/CText3D.h>
#include <mrpt/opengl/stock_objects.h>
#include <mrpt/system/filesystem.h>
//
#include <Eigen/Dense>
//
#include <mrpt/config.h>  // for MRPT_HAS_*
#include <test_mrpt_common.h>

#if MRPT_HAS_OPENCV && MRPT_HAS_OPENGL_GLUT && MRPT_HAS_EGL
#define RUN_OFFSCREEN_RENDER_TESTS
#endif

// In MIPS, these tests crash in autobuilders, skip them:
#if defined(__mips__) || defined(__mips)
#undef RUN_OFFSCREEN_RENDER_TESTS
#endif
// Idem with PowerPC:
#if defined(__powerpc) || defined(__powerpc__) || defined(__powerpc64__) ||    \
	defined(__POWERPC__) || defined(__ppc__) || defined(__PPC__) ||            \
	defined(_ARCH_PPC) || defined(__PPC64__) || defined(__ppc64__) ||          \
	defined(_ARCH_PPC64)
#undef RUN_OFFSCREEN_RENDER_TESTS
#endif

static float imageDiff(
	const mrpt::img::CImage& im1, const mrpt::img::CImage& im2)
{
	mrpt::math::CMatrixFloat r1, g1, b1;
	im1.getAsRGBMatrices(r1, g1, b1);

	mrpt::math::CMatrixFloat r2, g2, b2;
	im2.getAsRGBMatrices(r2, g2, b2);

	return (r1 - r2).asEigen().array().abs().sum() +
		(g1 - g2).asEigen().array().abs().sum() +
		(b1 - b2).asEigen().array().abs().sum();
}

static void test_opengl_CFBORender(const bool useCameraFromIntrinsics)
{
	using namespace mrpt;  // _deg
	using namespace std::string_literals;  // s
	using namespace mrpt::opengl;

	const std::string expected_RGB_img_file = UNITTEST_BASEDIR +
		"/tests/CFBORender_expected_rgb_"s +
		(useCameraFromIntrinsics ? "camInt"s : "camFOV"s) + ".png"s;

	const std::string expected_depth_img_file = UNITTEST_BASEDIR +
		"/tests/CFBORender_expected_depth_"s +
		(useCameraFromIntrinsics ? "camInt"s : "camFOV"s) + ".png"s;

	COpenGLScene scene;

	{
		auto obj = mrpt::opengl::CGridPlaneXY::Create(-20, 20, -20, 20, 0, 5);
		obj->setColor(0.4f, 0.4f, 0.4f);
		scene.insert(obj);
	}
	{
		auto obj = mrpt::opengl::CBox::Create(
			mrpt::math::TPoint3D(0, 0, 0), mrpt::math::TPoint3D(.1, .1, .1));
		obj->setColor(1.0f, 0.f, 0.f);
		obj->setName("x");
		obj->enableShowName(true);
		obj->setLocation(1.0, 0, 0);
		scene.insert(obj);
	}
	{
		auto obj = mrpt::opengl::CTexturedPlane::Create();
		obj->setPlaneCorners(-10, 10, -10, 10);
		obj->setColor_u8(0x00, 0xff, 0xff, 0xff);
		obj->setLocation(0, 0, -14);
		scene.insert(obj);
	}
	{
		auto obj = mrpt::opengl::CSphere::Create();
		obj->setColor(0, 0, 1);
		obj->setRadius(1.0f);
		obj->setLocation(0, 1, 0);
		obj->setName("ball_1");
		scene.insert(obj);
	}

	{
		auto obj = mrpt::opengl::CText3D::Create("Hi there!");
		obj->setLocation(5.0, 3.0, 1.0);
		scene.insert(obj);
	}
	{
		auto obj = opengl::stock_objects::CornerXYZ(2.0f);
		obj->setLocation(-3, -2, 0.5);
		scene.insert(obj);
	}

	// CMeshFast, CMesh:
	{
		double off_x = -5.0, STEP_X = 1.0;
		opengl::CMeshFast::Ptr obj1 = opengl::CMeshFast::Create();
		opengl::CMeshFast::Ptr obj2 = opengl::CMeshFast::Create();
		opengl::CMesh::Ptr obj3 = opengl::CMesh::Create();
		opengl::CMesh::Ptr obj4 = opengl::CMesh::Create();

		obj1->setXBounds(-1, 1);
		obj1->setYBounds(-1, 1);

		const int W = 128, H = 128;

		mrpt::math::CMatrixDynamic<float> Z(H, W);

		for (int r = 0; r < H; r++)
			for (int c = 0; c < W; c++)
				Z(r, c) = sin(0.05 * (c + r) - 0.5) * cos(0.9 - 0.03 * r);

		const std::string texture_file = mrpt::system::getShareMRPTDir() +
			"datasets/sample-texture-terrain.jpg"s;

		mrpt::img::CImage im;

		// obj1:
		obj1->setZ(Z);
		obj1->enableColorFromZ(true);
		obj1->setPointSize(2.0);
		obj1->setLocation(off_x, 0, 0);
		scene.insert(obj1);

		// obj 2:
		if (im.loadFromFile(texture_file))
		{
			obj2->assignImageAndZ(im, Z);
			obj2->setPointSize(2.0);
			obj2->setLocation(off_x, 3, 0);
			scene.insert(obj2);
		}

		off_x += STEP_X;

		// obj 3:
		obj3->setZ(Z);
		obj3->enableColorFromZ(true, mrpt::img::cmJET);
		obj3->enableWireFrame(true);
		obj3->setLocation(off_x, 0, 0);
		obj3->cullFaces(mrpt::opengl::TCullFace::BACK);
		scene.insert(obj3);

		// obj 4:
		if (im.getWidth() > 1)
		{
			obj4->assignImageAndZ(im, Z);
			obj4->setLocation(off_x, 3, 0);
			obj4->cullFaces(mrpt::opengl::TCullFace::BACK);
			scene.insert(obj4);
		}
	}

	int width = 500, height = 400;
	const double cameraFOVdeg = 120.0;

	CFBORender renderer(width, height);
	mrpt::img::CImage frame(width, height, mrpt::img::CH_RGB);
	mrpt::math::CMatrixFloat depth;

	scene.getViewport()->setCustomBackgroundColor({0.3f, 0.3f, 0.3f, 1.0f});
	const float clipMax = 25.0f;
	scene.getViewport()->setViewportClipDistances(0.1, clipMax);

	{
		CCamera& camera = renderer.getCamera(scene);

		if (useCameraFromIntrinsics)
		{
			mrpt::img::TCamera c1;
			c1.ncols = width;
			c1.nrows = height;
			c1.fx(width * 0.5);
			c1.fy(width * 0.5);
			c1.cx(width / 2);
			c1.cy(height / 2);

			camera.setProjectiveFromPinhole(c1);
		}
		else
		{
			camera.setProjectiveFOVdeg(cameraFOVdeg);
		}

		// Defined by setPose() instead of orbit values:
		camera.set6DOFMode(true);

		// Reference camera pose:
		auto robotPose = mrpt::poses::CPose3D(
			0, 0, 10.0, 0.0_deg /*yaw*/, 90.0_deg /*pitch*/, 0.0_deg /*roll*/);

		// Convert to +Z pointing forward camera axes:
		auto camPose =
			robotPose +
			mrpt::poses::CPose3D::FromYawPitchRoll(
				90.0_deg /*yaw*/, 0.0_deg /*pitch*/, 90.0_deg /*roll*/);

		camera.setPose(camPose);
	}

	renderer.render_RGBD(scene, frame, depth);

	mrpt::img::CImage gt_frame;
	bool readOk_rgb = gt_frame.loadFromFile(expected_RGB_img_file);

	EXPECT_TRUE(readOk_rgb);

	const float rgb_diff = imageDiff(gt_frame, frame);
	std::cout << "rgb_diff=" << rgb_diff << "\n";
	EXPECT_LT(rgb_diff, 5000.0f);

	{
		mrpt::img::CImage imDepth;
		depth *= (1.0f / clipMax);
		imDepth.setFromMatrix(depth, true);

		mrpt::img::CImage gt_imDepth;
		bool readOk_depth = gt_imDepth.loadFromFile(expected_depth_img_file);

		EXPECT_TRUE(readOk_depth);

		const float depth_diff = imageDiff(gt_imDepth, imDepth);
		std::cout << "depth_diff=" << depth_diff << "\n";
		EXPECT_LT(depth_diff, 3000.0f);
	}
}

#if defined(RUN_OFFSCREEN_RENDER_TESTS)
TEST(OpenGL, CFBORender_camera_intrinsics)
#else
TEST(OpenGL, DISABLED_CFBORender_camera_intrinsics)
#endif
{
	test_opengl_CFBORender(true);
}

#if defined(RUN_OFFSCREEN_RENDER_TESTS)
TEST(OpenGL, CFBORender_camera_fov)
#else
TEST(OpenGL, DISABLED_CFBORender_camera_fov)
#endif
{
	test_opengl_CFBORender(false);
}
<|endoftext|>