<commit_before>//
//  niihdr.cpp
//  NiftiImage
//
//  Created by Tobias Wood on 08/07/2013.
//  Copyright (c) 2013 Tobias Wood. All rights reserved.
//

#include <memory>
#include <vector>
#include <iostream>
#include <getopt.h>

#include "Nifti/Nifti.h"

using namespace std;

const string usage = "niihdr - A utility for getting information from Nifti headers.\n\
\n\
Usage: niihdr [options] file1 [other files]\n\
By default the abbreviated header will be printed for each file.\n\
Alternatively the entire header or specific fields can be printed.\n\
\n\
Options:\n\
	-a, --abbrev : Print the abbreviated header (default).\n\
	-f, --full   : Print the entire header.\n\
	-h, --help   : Print this message and quit.\n\
	--rank       : Print the rank (number of dimensions).\n\
	--dims       : Print the image dimensions.\n\
	--voxdims    : Print the voxel dimensions.\n\
	--tr         : Print the TR.\n\
	--xform      : Print the highest priority transform.\n\
";

static int printAbbrev = false, printFull = false,
           printRank = false, printDims = false, printVoxdims = false,
           printTR = false, printXform = false;

static struct option long_options[] = {
	{"abbrev",  no_argument, 0, 'a'},
	{"full",    no_argument, 0, 'f'},
	{"help",    no_argument, 0, 'h'},
	{"rank",    no_argument, &printRank, 1},
	{"dims",    no_argument, &printDims, 1},
	{"voxdims", no_argument, &printVoxdims, 1},
	{"tr",      no_argument, &printTR, 1},
	{"xform",   no_argument, &printXform, 1},
	{0, 0, 0, 0}
};

int main(int argc, char **argv) {
	int indexptr = 0, c;
	while ((c = getopt_long(argc, argv, "afch", long_options, &indexptr)) != -1) {
		switch (c) {
			case 'a': printAbbrev = true; printFull = false; break;
			case 'f': printFull = true; printAbbrev = false; break;
			case '?': // getopt will print an error message
			case 'h':
				cout << usage << endl;
				return EXIT_FAILURE;
		}
	}
	if ((argc - optind) <= 0 ) {
		cerr << "No input image file specified." << endl;
		cout << usage << endl;
		return EXIT_FAILURE;
	} else if (optind == 1) { // No other arguments specified
		printAbbrev = true;
	}
	vector<Nifti::File> images;
	try {
		images.reserve(argc - optind); // emplace_back can still trigger copies if the vector has to be resized
		for (;optind < argc; optind++) {
			images.emplace_back(argv[optind]);
		}
	} catch (exception &e) {
		cerr << e.what() << endl;
	}

	for (auto& im: images) {
		Nifti::Header hdr = im.header();
		if (printAbbrev) {
			cout << "Image path: " << im.imagePath() << endl;
			cout << "Datatype:   " << hdr.typeInfo().name << endl;
			cout << "Dimensions: " << hdr.dims().transpose() << " (rank " << to_string(hdr.rank()) << ")" << endl;
			cout << "Voxel size: " << hdr.voxDims().transpose() << endl;
			cout << "XForm: " << endl << hdr.transform().matrix() << endl;
			(im.extensions().size() > 0) ? cout << "Has extensions." << endl : cout << "No extensions." << endl;
		}
		if (printFull) {
			cout << "Full Nifti Header for file: " << im.imagePath() << endl;
			cout << hdr << endl;
			cout << "Number of extensions: " << im.extensions().size() << endl;
		}
		if (printRank) { cout << hdr.rank() << endl; }
		if (printDims) { cout << hdr.dims().transpose() << endl; }
		if (printVoxdims) {
			if (hdr.rank() > 3) {
				cout << hdr.voxDims().head(3).transpose() << endl;
			} else {
				cout << hdr.voxDims() << endl;
			}
		}
		if (printTR) { cout << hdr.voxDim(4) << endl; }
		if (printXform) { cout << hdr.transform().matrix() << endl; }
	}

	return EXIT_SUCCESS;
}

<commit_msg>Removed catching of exceptions while opening a file so it will fail in scripts correctly.<commit_after>//
//  niihdr.cpp
//  NiftiImage
//
//  Created by Tobias Wood on 08/07/2013.
//  Copyright (c) 2013 Tobias Wood. All rights reserved.
//

#include <memory>
#include <vector>
#include <iostream>
#include <getopt.h>

#include "Nifti/Nifti.h"

using namespace std;

const string usage = "niihdr - A utility for getting information from Nifti headers.\n\
\n\
Usage: niihdr [options] file1 [other files]\n\
By default the abbreviated header will be printed for each file.\n\
Alternatively the entire header or specific fields can be printed.\n\
\n\
Options:\n\
	-a, --abbrev : Print the abbreviated header (default).\n\
	-f, --full   : Print the entire header.\n\
	-h, --help   : Print this message and quit.\n\
	--rank       : Print the rank (number of dimensions).\n\
	--dims       : Print the image dimensions.\n\
	--voxdims    : Print the voxel dimensions.\n\
	--tr         : Print the TR.\n\
	--xform      : Print the highest priority transform.\n\
";

static int printAbbrev = false, printFull = false,
           printRank = false, printDims = false, printVoxdims = false,
           printTR = false, printXform = false;

static struct option long_options[] = {
	{"abbrev",  no_argument, 0, 'a'},
	{"full",    no_argument, 0, 'f'},
	{"help",    no_argument, 0, 'h'},
	{"rank",    no_argument, &printRank, 1},
	{"dims",    no_argument, &printDims, 1},
	{"voxdims", no_argument, &printVoxdims, 1},
	{"tr",      no_argument, &printTR, 1},
	{"xform",   no_argument, &printXform, 1},
	{0, 0, 0, 0}
};

int main(int argc, char **argv) {
	int indexptr = 0, c;
	while ((c = getopt_long(argc, argv, "afch", long_options, &indexptr)) != -1) {
		switch (c) {
			case 'a': printAbbrev = true; printFull = false; break;
			case 'f': printFull = true; printAbbrev = false; break;
			case '?': // getopt will print an error message
			case 'h':
				cout << usage << endl;
				return EXIT_FAILURE;
		}
	}
	if ((argc - optind) <= 0 ) {
		cerr << "No input image file specified." << endl;
		cout << usage << endl;
		return EXIT_FAILURE;
	} else if (optind == 1) { // No other arguments specified
		printAbbrev = true;
	}
	vector<Nifti::File> images;
	images.reserve(argc - optind); // emplace_back can still trigger copies if the vector has to be resized
	for (;optind < argc; optind++) {
		images.emplace_back(argv[optind]);
	}

	for (auto& im: images) {
		Nifti::Header hdr = im.header();
		if (printAbbrev) {
			cout << "Image path: " << im.imagePath() << endl;
			cout << "Datatype:   " << hdr.typeInfo().name << endl;
			cout << "Dimensions: " << hdr.dims().transpose() << " (rank " << to_string(hdr.rank()) << ")" << endl;
			cout << "Voxel size: " << hdr.voxDims().transpose() << endl;
			cout << "XForm: " << endl << hdr.transform().matrix() << endl;
			(im.extensions().size() > 0) ? cout << "Has extensions." << endl : cout << "No extensions." << endl;
		}
		if (printFull) {
			cout << "Full Nifti Header for file: " << im.imagePath() << endl;
			cout << hdr << endl;
			cout << "Number of extensions: " << im.extensions().size() << endl;
		}
		if (printRank) { cout << hdr.rank() << endl; }
		if (printDims) { cout << hdr.dims().transpose() << endl; }
		if (printVoxdims) {
			if (hdr.rank() > 3) {
				cout << hdr.voxDims().head(3).transpose() << endl;
			} else {
				cout << hdr.voxDims() << endl;
			}
		}
		if (printTR) { cout << hdr.voxDim(4) << endl; }
		if (printXform) { cout << hdr.transform().matrix() << endl; }
	}

	return EXIT_SUCCESS;
}

<|endoftext|>


<commit_before>// Copyright (c) 2009-2013 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "allocators.h"

#ifdef WIN32
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0501
#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
// This is used to attempt to keep keying material out of swap
// Note that VirtualLock does not provide this as a guarantee on Windows,
// but, in practice, memory that has been VirtualLock'd almost never gets written to
// the pagefile except in rare circumstances where memory is extremely low.
#else
#include <sys/mman.h>
#include <limits.h> // for PAGESIZE
#include <unistd.h> // for sysconf
#endif

LockedPageManager* LockedPageManager::_instance = NULL;
boost::once_flag LockedPageManager::init_flag = BOOST_ONCE_INIT;

/** Determine system page size in bytes */
static inline size_t GetSystemPageSize()
{
    size_t page_size;
#if defined(WIN32)
    SYSTEM_INFO sSysInfo;
    GetSystemInfo(&sSysInfo);
    page_size = sSysInfo.dwPageSize;
#elif defined(PAGESIZE) // defined in limits.h
    page_size = PAGESIZE;
#else // assume some POSIX OS
    page_size = sysconf(_SC_PAGESIZE);
#endif
    return page_size;
}

bool MemoryPageLocker::Lock(const void *addr, size_t len)
{
#ifdef WIN32
    return VirtualLock(const_cast<void*>(addr), len) != 0;
#else
    return mlock(addr, len) == 0;
#endif
}

bool MemoryPageLocker::Unlock(const void *addr, size_t len)
{
#ifdef WIN32
    return VirtualUnlock(const_cast<void*>(addr), len) != 0;
#else
    return munlock(addr, len) == 0;
#endif
}

LockedPageManager::LockedPageManager() : LockedPageManagerBase<MemoryPageLocker>(GetSystemPageSize())
{
}
<commit_msg>Apply some basic code cleanup to allocators.cpp<commit_after>// Copyright (c) 2009-2013 The Bitcoin Core developers
// Copyright (c) 2017 The Ion Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "allocators.h"

#ifdef WIN32
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0501
#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
// This is used to attempt to keep keying material out of swap
// Note that VirtualLock does not provide this as a guarantee on Windows,
// but, in practice, memory that has been VirtualLock'd almost never gets written to
// the pagefile except in rare circumstances where memory is extremely low.
#else
#include <sys/mman.h>
#include <limits.h> // for PAGESIZE
#include <unistd.h> // for sysconf
#endif

LockedPageManager* LockedPageManager::_instance = NULL;
boost::once_flag LockedPageManager::init_flag = BOOST_ONCE_INIT;

/** Determine system page size in bytes */
static inline size_t GetSystemPageSize()
{
    size_t page_size;
#if defined(WIN32)
    SYSTEM_INFO sSysInfo;
    GetSystemInfo(&sSysInfo);
    page_size = sSysInfo.dwPageSize;
#elif defined(PAGESIZE) // defined in limits.h
    page_size = PAGESIZE;
#else                   // assume some POSIX OS
    page_size = sysconf(_SC_PAGESIZE);
#endif
    return page_size;
}

bool MemoryPageLocker::Lock(const void* addr, size_t len)
{
#ifdef WIN32
    return VirtualLock(const_cast<void*>(addr), len) != 0;
#else
    return mlock(addr, len) == 0;
#endif
}

bool MemoryPageLocker::Unlock(const void* addr, size_t len)
{
#ifdef WIN32
    return VirtualUnlock(const_cast<void*>(addr), len) != 0;
#else
    return munlock(addr, len) == 0;
#endif
}

LockedPageManager::LockedPageManager() : LockedPageManagerBase<MemoryPageLocker>(GetSystemPageSize())
{
}
<|endoftext|>


<commit_before>#include <iostream>
#include <cassert>
#include "VtkXmlReader.h"

#include "vtkCellArray.h"
#include "vtkPointData.h"
#include "vtkDoubleArray.h"
#include "vtkFloatArray.h"

using namespace std;

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

cigma::VtkXmlReader::VtkXmlReader()
{
    reader = 0;
    grid = 0;
}

cigma::VtkXmlReader::~VtkXmlReader()
{
    //close();  // XXX: make sure this call resets both reader and grid
}

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

int cigma::VtkXmlReader::
open(std::string filename)
{
    reader = vtkXMLStructuredGridReader::New();
    reader->SetFileName(filename.c_str());
    reader->Update();
    //cout << "Reading " << filename << endl;
    //reader->PrintSelf(cout, 4)

    grid = reader->GetOutput();
    //cout << endl << endl;
    //grid->PrintSelf(cout, 4);
}

void cigma::VtkXmlReader::
close()
{
    // XXX: don't forget to reset values of reader and grid
}

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

void cigma::VtkXmlReader::
get_dataset(const char *loc, double **data, int *num, int *dim)
{
    assert(grid != 0);
    assert(loc != 0);

    int size = 0;
    int dims[2] = {0, 0};
    double *array = 0;

    vtkPointData *pointData = grid->GetPointData();

    if (pointData->HasArray(loc) == 1)
    {
        vtkDataArray *dataArray = pointData->GetArray(loc);
        assert(dataArray != 0);

        dims[0] = dataArray->GetNumberOfTuples();
        dims[1] = dataArray->GetNumberOfComponents();

        size = dims[0] * dims[1];
        array = new double[size];

        int dataType = dataArray->GetDataType();

        if (dataType == VTK_DOUBLE)
        {
            double *ptr = static_cast<double*>(dataArray->GetVoidPointer(0));
            for (int i = 0; i < size; i++)
            {
                array[i] = ptr[i];
            }
        }
        else if (dataType == VTK_FLOAT)
        {
            float *ptr = static_cast<float*>(dataArray->GetVoidPointer(0));
            for (int i = 0; i < size; i++)
            {
                array[i] = ptr[i];
            }
        }
        else
        {
            assert(false); // XXX: throw exception instead
        }
    }

    *data = array;
    *num = dims[0];
    *dim = dims[1];
}

void cigma::VtkXmlReader::
get_coordinates(const char *loc, double **coordinates, int *nno, int *nsd)
{
    get_coordinates(coordinates, nno, nsd);
}

void cigma::VtkXmlReader::
get_connectivity(const char *loc, int **connectivity, int *nel, int *ndofs)
{
    get_connectivity(connectivity, nel, ndofs);
}

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

void cigma::VtkXmlReader::
get_coordinates(double **coordinates, int *nno, int *nsd)
{
    assert(grid != 0);

    vtkPoints *points = grid->GetPoints();
    //points->PrintSelf(cout, 0);

    int dims[2];
    dims[0] = points->GetNumberOfPoints();
    dims[1] = 3;

    // XXX: need to know if we're loading 2D cells, so we can
    // recalculate size & nsd....if 3D, we leave things alone

    // XXX: for now, assume 2D grid of quadrangles

    //int size = dims[0] * dims[1];
    int size = dims[0] * 2;
    double *coords = new double[size];

    int dataType = points->GetDataType();

    if (dataType == VTK_DOUBLE)
    {
        double *ptr = static_cast<double*>(points->GetVoidPointer(0));
        for (int i = 0; i < dims[0]; i++)
        {
            coords[2*i + 0] = ptr[3*i + 0];
            coords[2*i + 1] = ptr[3*i + 1];
        } /*
        for (int i = 0; i < size; i++)
        {
            coords[i] = ptr[i];
        } // */
    }
    else if (dataType == VTK_FLOAT)
    {
        float *ptr = static_cast<float*>(points->GetVoidPointer(0));
        for (int i = 0; i < dims[0]; i++)
        {
            coords[2*i + 0] = ptr[3*i + 0];
            coords[2*i + 1] = ptr[3*i + 1];
        } /*
        for (int i = 0; i < size; i++)
        {
            coords[i] = ptr[i];
        } // */
    }
    else
    {
        assert(false); // XXX: throw exception instead
    }

    *coordinates = coords;
    *nno = dims[0];
    *nsd = dims[1];
}

void cigma::VtkXmlReader::
get_connectivity(int **connectivity, int *nel, int *ndofs)
{
    //
    // XXX: for now, assume 2D grid of quadrangles
    //
    int nx, ny;
    int ex, ey;
    int *connect = 0;
    int ndofs_per_cell;
    int num_cells;
    int extent[6];

    num_cells = grid->GetNumberOfCells();
    ndofs_per_cell = 4;

    grid->GetExtent(extent);

    nx = extent[1] + 1;
    ny = extent[3] + 1;

    ex = nx - 1;
    ey = ny - 1;

    connect = new int[ex * ey * ndofs_per_cell];
    for (int j = 0; j < ny-1; j++)
    {
        for (int i = 0; i < nx-1; i++)
        {
            int e = i + j*ex;
            connect[4*e + 0] =  i    +  j*nx;
            connect[4*e + 1] = (i+1) +  j*nx;
            connect[4*e + 2] = (i+1) + (j+1)*nx;
            connect[4*e + 3] =  i    + (j+1)*nx;
        }
    }

    *connectivity = connect;
    *nel = num_cells;
    *ndofs = ndofs_per_cell;
}

// ---------------------------------------------------------------------------
<commit_msg>Forgot to give successful return code in VtkXmlReader::open()<commit_after>#include <iostream>
#include <cassert>
#include "VtkXmlReader.h"

#include "vtkCellArray.h"
#include "vtkPointData.h"
#include "vtkDoubleArray.h"
#include "vtkFloatArray.h"

using namespace std;

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

cigma::VtkXmlReader::VtkXmlReader()
{
    reader = 0;
    grid = 0;
}

cigma::VtkXmlReader::~VtkXmlReader()
{
    //close();  // XXX: make sure this call resets both reader and grid
}

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

int cigma::VtkXmlReader::
open(std::string filename)
{
    reader = vtkXMLStructuredGridReader::New();
    reader->SetFileName(filename.c_str());
    reader->Update();
    //cout << "Reading " << filename << endl;
    //reader->PrintSelf(cout, 4)

    grid = reader->GetOutput();
    //cout << endl << endl;
    //grid->PrintSelf(cout, 4);

    return 0;
}

void cigma::VtkXmlReader::
close()
{
    // XXX: don't forget to reset values of reader and grid
}

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

void cigma::VtkXmlReader::
get_dataset(const char *loc, double **data, int *num, int *dim)
{
    assert(grid != 0);
    assert(loc != 0);

    int size = 0;
    int dims[2] = {0, 0};
    double *array = 0;

    vtkPointData *pointData = grid->GetPointData();

    if (pointData->HasArray(loc) == 1)
    {
        vtkDataArray *dataArray = pointData->GetArray(loc);
        assert(dataArray != 0);

        dims[0] = dataArray->GetNumberOfTuples();
        dims[1] = dataArray->GetNumberOfComponents();

        size = dims[0] * dims[1];
        array = new double[size];

        int dataType = dataArray->GetDataType();

        if (dataType == VTK_DOUBLE)
        {
            double *ptr = static_cast<double*>(dataArray->GetVoidPointer(0));
            for (int i = 0; i < size; i++)
            {
                array[i] = ptr[i];
            }
        }
        else if (dataType == VTK_FLOAT)
        {
            float *ptr = static_cast<float*>(dataArray->GetVoidPointer(0));
            for (int i = 0; i < size; i++)
            {
                array[i] = ptr[i];
            }
        }
        else
        {
            assert(false); // XXX: throw exception instead
        }
    }

    *data = array;
    *num = dims[0];
    *dim = dims[1];
}

void cigma::VtkXmlReader::
get_coordinates(const char *loc, double **coordinates, int *nno, int *nsd)
{
    get_coordinates(coordinates, nno, nsd);
}

void cigma::VtkXmlReader::
get_connectivity(const char *loc, int **connectivity, int *nel, int *ndofs)
{
    get_connectivity(connectivity, nel, ndofs);
}

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

void cigma::VtkXmlReader::
get_coordinates(double **coordinates, int *nno, int *nsd)
{
    assert(grid != 0);

    vtkPoints *points = grid->GetPoints();
    //points->PrintSelf(cout, 0);

    int dims[2];
    dims[0] = points->GetNumberOfPoints();
    dims[1] = 3;

    // XXX: need to know if we're loading 2D cells, so we can
    // recalculate size & nsd....if 3D, we leave things alone

    // XXX: for now, assume 2D grid of quadrangles

    //int size = dims[0] * dims[1];
    int size = dims[0] * 2;
    double *coords = new double[size];

    int dataType = points->GetDataType();

    if (dataType == VTK_DOUBLE)
    {
        double *ptr = static_cast<double*>(points->GetVoidPointer(0));
        for (int i = 0; i < dims[0]; i++)
        {
            coords[2*i + 0] = ptr[3*i + 0];
            coords[2*i + 1] = ptr[3*i + 1];
        } /*
        for (int i = 0; i < size; i++)
        {
            coords[i] = ptr[i];
        } // */
    }
    else if (dataType == VTK_FLOAT)
    {
        float *ptr = static_cast<float*>(points->GetVoidPointer(0));
        for (int i = 0; i < dims[0]; i++)
        {
            coords[2*i + 0] = ptr[3*i + 0];
            coords[2*i + 1] = ptr[3*i + 1];
        } /*
        for (int i = 0; i < size; i++)
        {
            coords[i] = ptr[i];
        } // */
    }
    else
    {
        assert(false); // XXX: throw exception instead
    }

    *coordinates = coords;
    *nno = dims[0];
    *nsd = dims[1];
}

void cigma::VtkXmlReader::
get_connectivity(int **connectivity, int *nel, int *ndofs)
{
    //
    // XXX: for now, assume 2D grid of quadrangles
    //
    int nx, ny;
    int ex, ey;
    int *connect = 0;
    int ndofs_per_cell;
    int num_cells;
    int extent[6];

    num_cells = grid->GetNumberOfCells();
    ndofs_per_cell = 4;

    grid->GetExtent(extent);

    nx = extent[1] + 1;
    ny = extent[3] + 1;

    ex = nx - 1;
    ey = ny - 1;

    connect = new int[ex * ey * ndofs_per_cell];
    for (int j = 0; j < ny-1; j++)
    {
        for (int i = 0; i < nx-1; i++)
        {
            int e = i + j*ex;
            connect[4*e + 0] =  i    +  j*nx;
            connect[4*e + 1] = (i+1) +  j*nx;
            connect[4*e + 2] = (i+1) + (j+1)*nx;
            connect[4*e + 3] =  i    + (j+1)*nx;
        }
    }

    *connectivity = connect;
    *nel = num_cells;
    *ndofs = ndofs_per_cell;
}

// ---------------------------------------------------------------------------
<|endoftext|>


<commit_before>#ifndef _MZ_SHARE_NONELOCK_HPP_
#define _MZ_SHARE_NONELOCK_HPP_

#include "Metazion/Share/ShareInclude.hpp"

DECL_NAMESPACE_MZ_SHARE_BEGIN

class NoneLock {
    MZ_DISALLOW_COPY_AND_ASSIGN(NoneLock)

public:
    NoneLock() {}

    ~NoneLock() {}

public:
    void lock() {}

    bool try_lock() { return true; }

    void unlock() {}
};

DECL_NAMESPACE_MZ_SHARE_END

#endif // _MZ_SHARE_NONELOCK_HPP_
<commit_msg>Update none lock<commit_after>#ifndef _MZ_SHARE_NONELOCK_HPP_
#define _MZ_SHARE_NONELOCK_HPP_

#include "Metazion/Share/ShareInclude.hpp"

#include <mutex>

DECL_NAMESPACE_MZ_SHARE_BEGIN

class NoneLock {
    MZ_DISALLOW_COPY_AND_ASSIGN(NoneLock)

public:
    NoneLock() {}

    ~NoneLock() {}

public:
    void lock() {}

    bool try_lock() { return true; }

    void unlock() {}
};

DECL_NAMESPACE_MZ_SHARE_END

#endif // _MZ_SHARE_NONELOCK_HPP_
<|endoftext|>


<commit_before>// The libMesh Finite Element Library.
// Copyright (C) 2002-2012 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

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

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include "libmesh/diff_system.h"
#include "libmesh/dof_map.h"
#include "libmesh/libmesh_logging.h"
#include "libmesh/petsc_diff_solver.h"
#include "libmesh/petsc_matrix.h"
#include "libmesh/petsc_vector.h"

#ifdef LIBMESH_HAVE_PETSC

namespace libMesh
{

//--------------------------------------------------------------------
// Functions with C linkage to pass to PETSc.  PETSc will call these
// methods as needed.
//
// Since they must have C linkage they have no knowledge of a namespace.
// Give them an obscure name to avoid namespace pollution.
extern "C"
{
  // Older versions of PETSc do not have the different int typedefs.
  // On 64-bit machines, PetscInt may actually be a long long int.
  // This change occurred in Petsc-2.2.1.
#if PETSC_VERSION_LESS_THAN(2,2,1)
  typedef int PetscErrorCode;
  typedef int PetscInt;
#endif

// Function to hand to PETSc's SNES,
// which monitors convergence at X
PetscErrorCode
__libmesh_petsc_diff_solver_monitor (SNES snes, PetscInt its,
                                     PetscReal fnorm, void *ctx)
{
  PetscDiffSolver& solver =
    *(static_cast<PetscDiffSolver*> (ctx));

  if (solver.verbose)
    libMesh::out << "  PetscDiffSolver step " << its
                 << ", |residual|_2 = " << fnorm << std::endl;
  if (solver.linear_solution_monitor.get()) {
    int ierr = 0;

    Vec petsc_delta_u;
    ierr = SNESGetSolutionUpdate(snes, &petsc_delta_u);
    CHKERRABORT(libMesh::COMM_WORLD, ierr);
    PetscVector<Number> delta_u(petsc_delta_u);
    delta_u.close();

    Vec petsc_u;
    ierr = SNESGetSolution(snes, &petsc_u);
    CHKERRABORT(libMesh::COMM_WORLD, ierr);
    PetscVector<Number> u(petsc_u);
    u.close();

    Vec petsc_res;
    ierr = SNESGetFunction(snes, &petsc_res, NULL, NULL);
    CHKERRABORT(libMesh::COMM_WORLD, ierr);
    PetscVector<Number> res(petsc_res);
    res.close();

    (*solver.linear_solution_monitor)(
            delta_u, delta_u.l2_norm(),
            u, u.l2_norm(),
            res, res.l2_norm(), its);
  }
  return 0;
}

// Functions to hand to PETSc's SNES,
// which compute the residual or jacobian at X
PetscErrorCode
__libmesh_petsc_diff_solver_residual (SNES, Vec x, Vec r, void *ctx)
{
  libmesh_assert(x);
  libmesh_assert(r);
  libmesh_assert(ctx);

  PetscDiffSolver& solver =
    *(static_cast<PetscDiffSolver*> (ctx));
  ImplicitSystem &sys = solver.system();

  if (solver.verbose)
    libMesh::out << "Assembling the residual" << std::endl;

  PetscVector<Number>& X_system =
    *libmesh_cast_ptr<PetscVector<Number>*>(sys.solution.get());
  PetscVector<Number>& R_system =
    *libmesh_cast_ptr<PetscVector<Number>*>(sys.rhs);
  PetscVector<Number> X_input(x, sys.comm()), R_input(r, sys.comm());

  // DiffSystem assembles from the solution and into the rhs, so swap
  // those with our input vectors before assembling.  They'll probably
  // already be references to the same vectors, but PETSc might do
  // something tricky.
  X_input.swap(X_system);
  R_input.swap(R_system);

  // We may need to correct a non-conforming solution
  sys.get_dof_map().enforce_constraints_exactly(sys);

  // We may need to localize a parallel solution
  sys.update();

  // Do DiffSystem assembly
  sys.assembly(true, false);
  R_system.close();

  // Swap back
  X_input.swap(X_system);
  R_input.swap(R_system);

  // No errors, we hope
  return 0;
}

PetscErrorCode
__libmesh_petsc_diff_solver_jacobian (SNES, Vec x, Mat *libmesh_dbg_var(j), Mat *pc,
                                      MatStructure *msflag, void *ctx)
{
  libmesh_assert(x);
  libmesh_assert(j);
//  libmesh_assert_equal_to (pc, j);  // We don't use separate preconditioners yet
  libmesh_assert(ctx);

  PetscDiffSolver& solver =
    *(static_cast<PetscDiffSolver*> (ctx));
  ImplicitSystem &sys = solver.system();

  if (solver.verbose)
    libMesh::out << "Assembling the Jacobian" << std::endl;

  PetscVector<Number>& X_system =
    *libmesh_cast_ptr<PetscVector<Number>*>(sys.solution.get());
  PetscVector<Number> X_input(x, sys.comm());

  PetscMatrix<Number> J_input(*pc, sys.comm());
  PetscMatrix<Number>& J_system =
    *libmesh_cast_ptr<PetscMatrix<Number>*>(sys.matrix);

  // DiffSystem assembles from the solution and into the jacobian, so
  // swap those with our input vectors before assembling.  They'll
  // probably already be references to the same vectors, but PETSc
  // might do something tricky.
  X_input.swap(X_system);
  J_input.swap(J_system);

  // We may need to correct a non-conforming solution
  sys.get_dof_map().enforce_constraints_exactly(sys);

  // We may need to localize a parallel solution
  sys.update();

  // Do DiffSystem assembly
  sys.assembly(false, true);
  J_system.close();

  // Swap back
  X_input.swap(X_system);
  J_input.swap(J_system);

  *msflag = SAME_NONZERO_PATTERN;

  // No errors, we hope
  return 0;
}

} // extern "C"

PetscDiffSolver::PetscDiffSolver (sys_type& s)
  : Parent(s)
{
}

void PetscDiffSolver::init ()
{
  START_LOG("init()", "PetscDiffSolver");

  Parent::init();

  int ierr=0;

#if PETSC_VERSION_LESS_THAN(2,1,2)
  // At least until Petsc 2.1.1, the SNESCreate had a different
  // calling syntax.  The second argument was of type SNESProblemType,
  // and could have a value of either SNES_NONLINEAR_EQUATIONS or
  // SNES_UNCONSTRAINED_MINIMIZATION.
  ierr = SNESCreate(this->comm().get(), SNES_NONLINEAR_EQUATIONS, &_snes);
  LIBMESH_CHKERRABORT(ierr);
#else
  ierr = SNESCreate(this->comm().get(),&_snes);
  LIBMESH_CHKERRABORT(ierr);
#endif

#if PETSC_VERSION_LESS_THAN(2,3,3)
  ierr = SNESSetMonitor (_snes, __libmesh_petsc_diff_solver_monitor,
                         this, PETSC_NULL);
#else
  // API name change in PETSc 2.3.3
  ierr = SNESMonitorSet (_snes, __libmesh_petsc_diff_solver_monitor,
                         this, PETSC_NULL);
#endif
  LIBMESH_CHKERRABORT(ierr);

  ierr = SNESSetFromOptions(_snes);
  LIBMESH_CHKERRABORT(ierr);

  STOP_LOG("init()", "PetscDiffSolver");
}

PetscDiffSolver::~PetscDiffSolver ()
{
}

void PetscDiffSolver::clear()
{
  START_LOG("clear()", "PetscDiffSolver");

  int ierr=0;

  ierr = LibMeshSNESDestroy(&_snes);
  LIBMESH_CHKERRABORT(ierr);

  STOP_LOG("clear()", "PetscDiffSolver");
}

void PetscDiffSolver::reinit()
{
  Parent::reinit();
}

DiffSolver::SolveResult convert_solve_result(SNESConvergedReason r)
{
  switch (r)
    {
    case SNES_CONVERGED_FNORM_ABS:
      return DiffSolver::CONVERGED_ABSOLUTE_RESIDUAL;
    case SNES_CONVERGED_FNORM_RELATIVE:
      return DiffSolver::CONVERGED_RELATIVE_RESIDUAL;
#if PETSC_VERSION_LESS_THAN(3,2,1)
    case SNES_CONVERGED_PNORM_RELATIVE:
#else
    case SNES_CONVERGED_SNORM_RELATIVE:
#endif
      return DiffSolver::CONVERGED_RELATIVE_STEP;
#if !PETSC_VERSION_LESS_THAN(2,3,3)
    case SNES_CONVERGED_ITS:
#endif
    case SNES_CONVERGED_TR_DELTA:
      return DiffSolver::CONVERGED_NO_REASON;
    case SNES_DIVERGED_FUNCTION_DOMAIN:
    case SNES_DIVERGED_FUNCTION_COUNT:
    case SNES_DIVERGED_FNORM_NAN:
#if !PETSC_VERSION_LESS_THAN(3,3,0)
    case SNES_DIVERGED_INNER:
#endif
#if !PETSC_VERSION_LESS_THAN(2,3,2)
    case SNES_DIVERGED_LINEAR_SOLVE:
#endif
    case SNES_DIVERGED_LOCAL_MIN:
      return DiffSolver::DIVERGED_NO_REASON;
    case SNES_DIVERGED_MAX_IT:
      return DiffSolver::DIVERGED_MAX_NONLINEAR_ITERATIONS;
#if !PETSC_VERSION_LESS_THAN(3,2,0)
    case SNES_DIVERGED_LINE_SEARCH:
      return DiffSolver::DIVERGED_BACKTRACKING_FAILURE;
#endif
      // In PETSc, SNES_CONVERGED_ITERATING means
      // the solve is still iterating, but by the
      // time we get here, we must have either
      // converged or diverged, so
      // SNES_CONVERGED_ITERATING is invalid.
    case SNES_CONVERGED_ITERATING:
      return DiffSolver::INVALID_SOLVE_RESULT;
    }
  return DiffSolver::INVALID_SOLVE_RESULT;
}

unsigned int PetscDiffSolver::solve()
{
  this->init();

  START_LOG("solve()", "PetscDiffSolver");

  PetscVector<Number> &x =
    *(libmesh_cast_ptr<PetscVector<Number>*>(_system.solution.get()));
  PetscMatrix<Number> &jac =
    *(libmesh_cast_ptr<PetscMatrix<Number>*>(_system.matrix));
  PetscVector<Number> &r =
    *(libmesh_cast_ptr<PetscVector<Number>*>(_system.rhs));

#ifdef LIBMESH_ENABLE_CONSTRAINTS
  _system.get_dof_map().enforce_constraints_exactly(_system);
#endif

  int ierr = 0;

  ierr = SNESSetFunction (_snes, r.vec(),
                          __libmesh_petsc_diff_solver_residual, this);
    LIBMESH_CHKERRABORT(ierr);

  ierr = SNESSetJacobian (_snes, jac.mat(), jac.mat(),
                          __libmesh_petsc_diff_solver_jacobian, this);
    LIBMESH_CHKERRABORT(ierr);

# if PETSC_VERSION_LESS_THAN(2,2,0)

  ierr = SNESSolve (_snes, x.vec(), &_outer_iterations);
         LIBMESH_CHKERRABORT(ierr);

// 2.2.x style
#elif PETSC_VERSION_LESS_THAN(2,3,0)

  ierr = SNESSolve (_snes, x.vec());
         LIBMESH_CHKERRABORT(ierr);

// 2.3.x & newer style
#else

  ierr = SNESSolve (_snes, PETSC_NULL, x.vec());
         LIBMESH_CHKERRABORT(ierr);

#endif

  STOP_LOG("solve()", "PetscDiffSolver");

  SNESConvergedReason reason;
  SNESGetConvergedReason(_snes, &reason);

  this->clear();

  return convert_solve_result(reason);
}

} // namespace libMesh

#endif // LIBMESH_HAVE_PETSC
<commit_msg>Adding comm arguments to PetscVector constructors.<commit_after>// The libMesh Finite Element Library.
// Copyright (C) 2002-2012 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

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

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include "libmesh/diff_system.h"
#include "libmesh/dof_map.h"
#include "libmesh/libmesh_logging.h"
#include "libmesh/petsc_diff_solver.h"
#include "libmesh/petsc_matrix.h"
#include "libmesh/petsc_vector.h"

#ifdef LIBMESH_HAVE_PETSC

namespace libMesh
{

//--------------------------------------------------------------------
// Functions with C linkage to pass to PETSc.  PETSc will call these
// methods as needed.
//
// Since they must have C linkage they have no knowledge of a namespace.
// Give them an obscure name to avoid namespace pollution.
extern "C"
{
  // Older versions of PETSc do not have the different int typedefs.
  // On 64-bit machines, PetscInt may actually be a long long int.
  // This change occurred in Petsc-2.2.1.
#if PETSC_VERSION_LESS_THAN(2,2,1)
  typedef int PetscErrorCode;
  typedef int PetscInt;
#endif

// Function to hand to PETSc's SNES,
// which monitors convergence at X
PetscErrorCode
__libmesh_petsc_diff_solver_monitor (SNES snes, PetscInt its,
                                     PetscReal fnorm, void *ctx)
{
  PetscDiffSolver& solver =
    *(static_cast<PetscDiffSolver*> (ctx));

  if (solver.verbose)
    libMesh::out << "  PetscDiffSolver step " << its
                 << ", |residual|_2 = " << fnorm << std::endl;
  if (solver.linear_solution_monitor.get()) {
    int ierr = 0;

    Vec petsc_delta_u;
    ierr = SNESGetSolutionUpdate(snes, &petsc_delta_u);
    CHKERRABORT(libMesh::COMM_WORLD, ierr);
    PetscVector<Number> delta_u(petsc_delta_u, solver.comm());
    delta_u.close();

    Vec petsc_u;
    ierr = SNESGetSolution(snes, &petsc_u);
    CHKERRABORT(libMesh::COMM_WORLD, ierr);
    PetscVector<Number> u(petsc_u, solver.comm());
    u.close();

    Vec petsc_res;
    ierr = SNESGetFunction(snes, &petsc_res, NULL, NULL);
    CHKERRABORT(libMesh::COMM_WORLD, ierr);
    PetscVector<Number> res(petsc_res, solver.comm());
    res.close();

    (*solver.linear_solution_monitor)(
            delta_u, delta_u.l2_norm(),
            u, u.l2_norm(),
            res, res.l2_norm(), its);
  }
  return 0;
}

// Functions to hand to PETSc's SNES,
// which compute the residual or jacobian at X
PetscErrorCode
__libmesh_petsc_diff_solver_residual (SNES, Vec x, Vec r, void *ctx)
{
  libmesh_assert(x);
  libmesh_assert(r);
  libmesh_assert(ctx);

  PetscDiffSolver& solver =
    *(static_cast<PetscDiffSolver*> (ctx));
  ImplicitSystem &sys = solver.system();

  if (solver.verbose)
    libMesh::out << "Assembling the residual" << std::endl;

  PetscVector<Number>& X_system =
    *libmesh_cast_ptr<PetscVector<Number>*>(sys.solution.get());
  PetscVector<Number>& R_system =
    *libmesh_cast_ptr<PetscVector<Number>*>(sys.rhs);
  PetscVector<Number> X_input(x, sys.comm()), R_input(r, sys.comm());

  // DiffSystem assembles from the solution and into the rhs, so swap
  // those with our input vectors before assembling.  They'll probably
  // already be references to the same vectors, but PETSc might do
  // something tricky.
  X_input.swap(X_system);
  R_input.swap(R_system);

  // We may need to correct a non-conforming solution
  sys.get_dof_map().enforce_constraints_exactly(sys);

  // We may need to localize a parallel solution
  sys.update();

  // Do DiffSystem assembly
  sys.assembly(true, false);
  R_system.close();

  // Swap back
  X_input.swap(X_system);
  R_input.swap(R_system);

  // No errors, we hope
  return 0;
}

PetscErrorCode
__libmesh_petsc_diff_solver_jacobian (SNES, Vec x, Mat *libmesh_dbg_var(j), Mat *pc,
                                      MatStructure *msflag, void *ctx)
{
  libmesh_assert(x);
  libmesh_assert(j);
//  libmesh_assert_equal_to (pc, j);  // We don't use separate preconditioners yet
  libmesh_assert(ctx);

  PetscDiffSolver& solver =
    *(static_cast<PetscDiffSolver*> (ctx));
  ImplicitSystem &sys = solver.system();

  if (solver.verbose)
    libMesh::out << "Assembling the Jacobian" << std::endl;

  PetscVector<Number>& X_system =
    *libmesh_cast_ptr<PetscVector<Number>*>(sys.solution.get());
  PetscVector<Number> X_input(x, sys.comm());

  PetscMatrix<Number> J_input(*pc, sys.comm());
  PetscMatrix<Number>& J_system =
    *libmesh_cast_ptr<PetscMatrix<Number>*>(sys.matrix);

  // DiffSystem assembles from the solution and into the jacobian, so
  // swap those with our input vectors before assembling.  They'll
  // probably already be references to the same vectors, but PETSc
  // might do something tricky.
  X_input.swap(X_system);
  J_input.swap(J_system);

  // We may need to correct a non-conforming solution
  sys.get_dof_map().enforce_constraints_exactly(sys);

  // We may need to localize a parallel solution
  sys.update();

  // Do DiffSystem assembly
  sys.assembly(false, true);
  J_system.close();

  // Swap back
  X_input.swap(X_system);
  J_input.swap(J_system);

  *msflag = SAME_NONZERO_PATTERN;

  // No errors, we hope
  return 0;
}

} // extern "C"

PetscDiffSolver::PetscDiffSolver (sys_type& s)
  : Parent(s)
{
}

void PetscDiffSolver::init ()
{
  START_LOG("init()", "PetscDiffSolver");

  Parent::init();

  int ierr=0;

#if PETSC_VERSION_LESS_THAN(2,1,2)
  // At least until Petsc 2.1.1, the SNESCreate had a different
  // calling syntax.  The second argument was of type SNESProblemType,
  // and could have a value of either SNES_NONLINEAR_EQUATIONS or
  // SNES_UNCONSTRAINED_MINIMIZATION.
  ierr = SNESCreate(this->comm().get(), SNES_NONLINEAR_EQUATIONS, &_snes);
  LIBMESH_CHKERRABORT(ierr);
#else
  ierr = SNESCreate(this->comm().get(),&_snes);
  LIBMESH_CHKERRABORT(ierr);
#endif

#if PETSC_VERSION_LESS_THAN(2,3,3)
  ierr = SNESSetMonitor (_snes, __libmesh_petsc_diff_solver_monitor,
                         this, PETSC_NULL);
#else
  // API name change in PETSc 2.3.3
  ierr = SNESMonitorSet (_snes, __libmesh_petsc_diff_solver_monitor,
                         this, PETSC_NULL);
#endif
  LIBMESH_CHKERRABORT(ierr);

  ierr = SNESSetFromOptions(_snes);
  LIBMESH_CHKERRABORT(ierr);

  STOP_LOG("init()", "PetscDiffSolver");
}

PetscDiffSolver::~PetscDiffSolver ()
{
}

void PetscDiffSolver::clear()
{
  START_LOG("clear()", "PetscDiffSolver");

  int ierr=0;

  ierr = LibMeshSNESDestroy(&_snes);
  LIBMESH_CHKERRABORT(ierr);

  STOP_LOG("clear()", "PetscDiffSolver");
}

void PetscDiffSolver::reinit()
{
  Parent::reinit();
}

DiffSolver::SolveResult convert_solve_result(SNESConvergedReason r)
{
  switch (r)
    {
    case SNES_CONVERGED_FNORM_ABS:
      return DiffSolver::CONVERGED_ABSOLUTE_RESIDUAL;
    case SNES_CONVERGED_FNORM_RELATIVE:
      return DiffSolver::CONVERGED_RELATIVE_RESIDUAL;
#if PETSC_VERSION_LESS_THAN(3,2,1)
    case SNES_CONVERGED_PNORM_RELATIVE:
#else
    case SNES_CONVERGED_SNORM_RELATIVE:
#endif
      return DiffSolver::CONVERGED_RELATIVE_STEP;
#if !PETSC_VERSION_LESS_THAN(2,3,3)
    case SNES_CONVERGED_ITS:
#endif
    case SNES_CONVERGED_TR_DELTA:
      return DiffSolver::CONVERGED_NO_REASON;
    case SNES_DIVERGED_FUNCTION_DOMAIN:
    case SNES_DIVERGED_FUNCTION_COUNT:
    case SNES_DIVERGED_FNORM_NAN:
#if !PETSC_VERSION_LESS_THAN(3,3,0)
    case SNES_DIVERGED_INNER:
#endif
#if !PETSC_VERSION_LESS_THAN(2,3,2)
    case SNES_DIVERGED_LINEAR_SOLVE:
#endif
    case SNES_DIVERGED_LOCAL_MIN:
      return DiffSolver::DIVERGED_NO_REASON;
    case SNES_DIVERGED_MAX_IT:
      return DiffSolver::DIVERGED_MAX_NONLINEAR_ITERATIONS;
#if !PETSC_VERSION_LESS_THAN(3,2,0)
    case SNES_DIVERGED_LINE_SEARCH:
      return DiffSolver::DIVERGED_BACKTRACKING_FAILURE;
#endif
      // In PETSc, SNES_CONVERGED_ITERATING means
      // the solve is still iterating, but by the
      // time we get here, we must have either
      // converged or diverged, so
      // SNES_CONVERGED_ITERATING is invalid.
    case SNES_CONVERGED_ITERATING:
      return DiffSolver::INVALID_SOLVE_RESULT;
    }
  return DiffSolver::INVALID_SOLVE_RESULT;
}

unsigned int PetscDiffSolver::solve()
{
  this->init();

  START_LOG("solve()", "PetscDiffSolver");

  PetscVector<Number> &x =
    *(libmesh_cast_ptr<PetscVector<Number>*>(_system.solution.get()));
  PetscMatrix<Number> &jac =
    *(libmesh_cast_ptr<PetscMatrix<Number>*>(_system.matrix));
  PetscVector<Number> &r =
    *(libmesh_cast_ptr<PetscVector<Number>*>(_system.rhs));

#ifdef LIBMESH_ENABLE_CONSTRAINTS
  _system.get_dof_map().enforce_constraints_exactly(_system);
#endif

  int ierr = 0;

  ierr = SNESSetFunction (_snes, r.vec(),
                          __libmesh_petsc_diff_solver_residual, this);
    LIBMESH_CHKERRABORT(ierr);

  ierr = SNESSetJacobian (_snes, jac.mat(), jac.mat(),
                          __libmesh_petsc_diff_solver_jacobian, this);
    LIBMESH_CHKERRABORT(ierr);

# if PETSC_VERSION_LESS_THAN(2,2,0)

  ierr = SNESSolve (_snes, x.vec(), &_outer_iterations);
         LIBMESH_CHKERRABORT(ierr);

// 2.2.x style
#elif PETSC_VERSION_LESS_THAN(2,3,0)

  ierr = SNESSolve (_snes, x.vec());
         LIBMESH_CHKERRABORT(ierr);

// 2.3.x & newer style
#else

  ierr = SNESSolve (_snes, PETSC_NULL, x.vec());
         LIBMESH_CHKERRABORT(ierr);

#endif

  STOP_LOG("solve()", "PetscDiffSolver");

  SNESConvergedReason reason;
  SNESGetConvergedReason(_snes, &reason);

  this->clear();

  return convert_solve_result(reason);
}

} // namespace libMesh

#endif // LIBMESH_HAVE_PETSC
<|endoftext|>


<commit_before>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include "OpenAssetImport.h"

#include <assimp.hpp>      // C++ importer interface
#include <aiScene.h>       // Output data structure
#include <aiPostProcess.h> // Post processing flags
#include <Logger.h>
#include <DefaultLogger.h>
#include <Ogre.h>

using namespace Assimp;

namespace AssImp
{
    OpenAssetImport::OpenAssetImport() :
        importer_(new Importer()),
        logstream_(new AssImpLogStream()),
        loglevels_(Logger::DEBUGGING | Logger::INFO | Logger::ERR | Logger::WARN),
        default_flags_( aiProcess_JoinIdenticalVertices		|
                        aiProcess_Triangulate				|
                        aiProcess_RemoveComponent			|
                        aiProcess_GenNormals				|	// ignored if model already has normals
                        aiProcess_LimitBoneWeights			|
                        aiProcess_SortByPType				|	// remove point and line primitive types
                        aiProcess_ValidateDataStructure         // makes sure that all indices are valid, all animations and bones are linked correctly, all material references are correct...
                      )
    {
        // set up importer
        importer_->SetPropertyInteger(AI_CONFIG_PP_LBW_MAX_WEIGHTS, 4);	// limit bone weights to 4 vertices

        importer_->SetPropertyInteger(			// ignore vertex colours, textures, lights and cameras (for now)
            AI_CONFIG_PP_RVC_FLAGS,
            aiComponent_COLORS		|
            aiComponent_TEXTURES	|
            aiComponent_LIGHTS		|
            aiComponent_CAMERAS
            );

        importer_->SetPropertyInteger(			// ignore point and line primitives (for now)
            AI_CONFIG_PP_SBP_REMOVE,
            aiPrimitiveType_POINT		|
            aiPrimitiveType_LINE
            );

        Assimp::DefaultLogger::get()->attachStream(logstream_, loglevels_);
    }

    OpenAssetImport::~OpenAssetImport()
    {
        Assimp::DefaultLogger::get()->detatchStream(logstream_, loglevels_);
        delete logstream_;
    }

    bool OpenAssetImport::IsSupportedExtension(const QString& filename)
    {
        boost::filesystem::path path(filename.toStdString());
        QString extension = QString(path.extension().c_str()).toLower();

        return importer_->IsExtensionSupported(extension.toStdString());
    }

    void OpenAssetImport::GetMeshData(const QString& file, std::vector<MeshData> &outMeshData)
    {
        const aiScene *scene = importer_->ReadFile(file.toStdString(), default_flags_);

        if (scene)
        {
            const struct aiNode *rootNode = scene->mRootNode;

            aiMatrix4x4 transform;
            GetNodeData(scene, rootNode, file, transform, outMeshData);
        } else
        {
            // report error
            Foundation::RootLogError(importer_->GetErrorString());
        }
    }

    void OpenAssetImport::Import(const void *data, size_t length, const QString &name, const char* hint, const QString &nodeName, std::vector<std::string> &outMeshNames)
    {
        const aiScene *scene = importer_->ReadFileFromMemory(data, length, default_flags_, hint);

        if (scene)
        {
            const struct aiNode *rootNode = scene->mRootNode;

            ImportNode(scene, rootNode, name, nodeName, outMeshNames);
        } else
        {
            // report error
            Foundation::RootLogError(importer_->GetErrorString());
            //return QString(importer_->GetErrorString());
        }
    }

    void OpenAssetImport::GetNodeData(const aiScene *scene, const aiNode *node, const QString& file,
        const aiMatrix4x4 &parentTransform, std::vector<MeshData> &outMeshNames)
    {
        aiMatrix4x4 aiTransform = node->mTransformation;

        aiMatrix4x4 worldTransform =  parentTransform * aiTransform;

        aiVector3D pos;
        aiVector3D scale;
        Vector3df rote;
        aiQuaternion rotq;
        worldTransform.Decompose(scale, rotq, pos);
        Quaternion quat(rotq.x, rotq.y, rotq.z, rotq.w);

        quat.toEuler(rote);
        rote *= RADTODEG;

        if (node->mNumMeshes > 0)
        {
            MeshData data = { file, QString(node->mName.data), Transform(Vector3df(pos.x, pos.y, pos.z), rote, Vector3df(scale.x, scale.y, scale.z)) };
            outMeshNames.push_back(data);
        }

        // import children
        for (int i=0 ; i<node->mNumChildren ; ++i)
            GetNodeData(scene, node->mChildren[i], file, worldTransform, outMeshNames);
    }

    void OpenAssetImport::ImportNode(const aiScene *scene, const aiNode *node, const QString& file,
        const QString &nodeName, std::vector<std::string> &outMeshNames)
    {
        try
        {
   //         boost::filesystem::path path(file.toStdString());
   //         std::string meshname = path.filename() + boost::lexical_cast<std::string>(nodeIdx);
            std::string ogreMeshName = file.toStdString(); //std::string("mesh___") + meshname;
            std::string meshname = ogreMeshName;

            /*if (scene->mNumMaterials > 0)
            {
                // testing getting Ogre material.xml names
                aiString name;
                scene->mMaterials[0]->Get(AI_MATKEY_NAME,name);
                Foundation::RootLogInfo(std::string("Found material ") + std::string(name.data));
            }*/

            //aiMatrix4x4 transform = node->mTransformation;
            if (node->mNumMeshes > 0 && nodeName.compare(QString(node->mName.data)) == 0 && !Ogre::MeshManager::getSingleton().resourceExists(ogreMeshName))
            {
                Ogre::MeshPtr ogreMesh = Ogre::MeshManager::getSingleton().createManual(ogreMeshName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
                ogreMesh->setAutoBuildEdgeLists(false);

                Ogre::Vector3 vmin(std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
                Ogre::Vector3 vmax(std::numeric_limits<float>::min(), std::numeric_limits<float>::min(), std::numeric_limits<float>::min());

                for (unsigned int i=0 ; i<node->mNumMeshes ; ++i)
                {
                    const aiMesh *mesh = scene->mMeshes[node->mMeshes[i]];

                    Ogre::SubMesh *ogreSubmesh = ogreMesh->createSubMesh();

                    ogreSubmesh->useSharedVertices = false;
                    ogreSubmesh->vertexData = new Ogre::VertexData();
                    ogreSubmesh->vertexData->vertexCount = mesh->mNumVertices;
                    Ogre::VertexData *data = ogreSubmesh->vertexData;

                    // Vertex declarations
                    size_t offset = 0;
                    Ogre::VertexDeclaration* decl = data->vertexDeclaration;
                    decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
                    offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
                    decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);

                    offset = 0;
                    for (int tn=0 ; tn<AI_MAX_NUMBER_OF_TEXTURECOORDS ; ++tn)
                    {
                        if (mesh->mTextureCoords[tn])
                        {
                            if (mesh->mNumUVComponents[tn] == 3)
                            {
                                decl->addElement(1, offset, Ogre::VET_FLOAT3, Ogre::VES_TEXTURE_COORDINATES, tn);
                                offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
                            } else
                            {
                                decl->addElement(1, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, tn);
                                offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2);
                            }
                        }
                    }
                    if (mesh->HasTangentsAndBitangents())
                    {
                        decl->addElement(1, offset, Ogre::VET_FLOAT3, Ogre::VES_TANGENT);
                        offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
                        decl->addElement(1, offset, Ogre::VET_FLOAT3, Ogre::VES_BINORMAL);
                    }

                    // Write vertex data to buffer
                    Ogre::HardwareVertexBufferSharedPtr vbuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
                        decl->getVertexSize(0),                     // This value is the size of a vertex in memory
                        data->vertexCount,                          // The number of vertices you'll put into this buffer
                        Ogre::HardwareBuffer::HBU_DYNAMIC // Properties
                        );
                    Ogre::Real *vbData = static_cast<Ogre::Real*>(vbuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));

                    offset = 0;
                    for (unsigned int n=0 ; n<data->vertexCount ; ++n)
                    {
                        vbData[offset++] = mesh->mVertices[n].x;
                        vbData[offset++] = mesh->mVertices[n].y;
                        vbData[offset++] = mesh->mVertices[n].z;

                        vbData[offset++] = mesh->mNormals[n].x;
                        vbData[offset++] = mesh->mNormals[n].y;
                        vbData[offset++] = mesh->mNormals[n].z;

                        vmin.x = std::min(vmin.x, mesh->mVertices[n].x);
                        vmin.y = std::min(vmin.y, mesh->mVertices[n].y);
                        vmin.z = std::min(vmin.z, mesh->mVertices[n].z);

                        vmax.x = std::max(vmax.x, mesh->mVertices[n].x);
                        vmax.y = std::max(vmax.y, mesh->mVertices[n].y);
                        vmax.z = std::max(vmax.z, mesh->mVertices[n].z);
                    }
                    vbuf->unlock();
                    data->vertexBufferBinding->setBinding(0, vbuf);

                    if (mesh->HasTextureCoords(0))
                    {
                    vbuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
                        decl->getVertexSize(1),                     // This value is the size of a vertex in memory
                        data->vertexCount,                          // The number of vertices you'll put into this buffer
                        Ogre::HardwareBuffer::HBU_DYNAMIC // Properties
                        );
                    vbData = static_cast<Ogre::Real*>(vbuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));

                    offset = 0;
                    for (unsigned int n=0 ; n<data->vertexCount ; ++n)
                    {
                        for (int tn=0 ; tn<AI_MAX_NUMBER_OF_TEXTURECOORDS ; ++tn)
                        {
                            if (mesh->mTextureCoords[tn])
                            {
                                if (mesh->mNumUVComponents[tn] == 3)
                                {
                                    vbData[offset++] = mesh->mTextureCoords[tn][n].x;
                                    vbData[offset++] = mesh->mTextureCoords[tn][n].y;
                                    vbData[offset++] = mesh->mTextureCoords[tn][n].z;
                                } else
                                {
                                    vbData[offset++] = mesh->mTextureCoords[tn][n].x;
                                    vbData[offset++] = mesh->mTextureCoords[tn][n].y;
                                }
                            }
                        }

                        if (mesh->HasTangentsAndBitangents())
                        {
                            vbData[offset++] = mesh->mTangents[n].x;
                            vbData[offset++] = mesh->mTangents[n].y;
                            vbData[offset++] = mesh->mTangents[n].z;

                            vbData[offset++] = mesh->mBitangents[n].x;
                            vbData[offset++] = mesh->mBitangents[n].y;
                            vbData[offset++] = mesh->mBitangents[n].z;
                        }
                    }
                    vbuf->unlock();
                    data->vertexBufferBinding->setBinding(1, vbuf);
                    }

                    // indices
                    size_t numIndices = mesh->mNumFaces * 3;            // support only triangles, so 3 indices per face

                    Ogre::HardwareIndexBuffer::IndexType idxType = Ogre::HardwareIndexBuffer::IT_16BIT;
                    if (numIndices > 65535)
                        idxType = Ogre::HardwareIndexBuffer::IT_32BIT;

                    Ogre::HardwareIndexBufferSharedPtr ibuf = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(
                        idxType,                                        // You can use several different value types here
                        numIndices,                                     // The number of indices you'll put in that buffer
                        Ogre::HardwareBuffer::HBU_DYNAMIC     // Properties
                        );

                    if (idxType == Ogre::HardwareIndexBuffer::IT_16BIT)
                    {
                        u16 *idxData = static_cast<u16*>(ibuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));
                        offset = 0;
                        for (int n=0 ; n<mesh->mNumFaces ; ++n)
                        {
                            idxData[offset++] = mesh->mFaces[n].mIndices[0];
                            idxData[offset++] = mesh->mFaces[n].mIndices[1];
                            idxData[offset++] = mesh->mFaces[n].mIndices[2];
                        }
                    } else
                    {
                        u32 *idxData = static_cast<u32*>(ibuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));
                        offset = 0;
                        for (int n=0 ; n<mesh->mNumFaces ; ++n)
                        {
                            idxData[offset++] = mesh->mFaces[n].mIndices[0];
                            idxData[offset++] = mesh->mFaces[n].mIndices[1];
                            idxData[offset++] = mesh->mFaces[n].mIndices[2];
                        }
                    }
                    ibuf->unlock();

                    ogreSubmesh->indexData->indexBuffer = ibuf;         // The pointer to the index buffer
                    ogreSubmesh->indexData->indexCount = numIndices;    // The number of indices we'll use
                    ogreSubmesh->indexData->indexStart = 0;
                }

                if (vmin.x <= vmax.x && vmin.y <= vmax.y && vmin.z <= vmax.z)
                {
                    ogreMesh->_setBounds(Ogre::AxisAlignedBox(vmin, vmax));
                    Ogre::Real maxvertex = std::max(abs(vmax.x), std::max(abs(vmin.x), std::max(abs(vmax.y), std::max(abs(vmin.y), std::max(vmax.z, vmin.z)))));
                    ogreMesh->_setBoundingSphereRadius(maxvertex / 2.f);
                    ogreMesh->load();
                    outMeshNames.push_back(meshname);
                }
            }
        } catch (Ogre::Exception &)
        {
            // error
        }

        // import children
        for (int i=0 ; i<node->mNumChildren ; ++i)
            ImportNode(scene, node->mChildren[i], file, nodeName, outMeshNames);
    }

    void OpenAssetImport::AssImpLogStream::write(const char* message)
    {
        //! \todo doesn't work, check assimp docs for reason -cmayhem
        Foundation::RootLogInfo(message);
    }
}
<commit_msg>Fixed log capturing for Open Asset Import lib.<commit_after>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include "OpenAssetImport.h"

#include <assimp.hpp>      // C++ importer interface
#include <aiScene.h>       // Output data structure
#include <aiPostProcess.h> // Post processing flags
#include <Logger.h>
#include <DefaultLogger.h>
#include <Ogre.h>

using namespace Assimp;

namespace AssImp
{
    OpenAssetImport::OpenAssetImport() :
        importer_(new Importer()),
        logstream_(new AssImpLogStream()),
        loglevels_(Logger::DEBUGGING | Logger::INFO | Logger::ERR | Logger::WARN),
        default_flags_( aiProcess_JoinIdenticalVertices		|
                        aiProcess_Triangulate				|
                        aiProcess_RemoveComponent			|
                        aiProcess_GenNormals				|	// ignored if model already has normals
                        aiProcess_LimitBoneWeights			|
                        aiProcess_SortByPType				|	// remove point and line primitive types
                        aiProcess_ValidateDataStructure         // makes sure that all indices are valid, all animations and bones are linked correctly, all material references are correct...
                      )
    {
        // set up importer
        importer_->SetPropertyInteger(AI_CONFIG_PP_LBW_MAX_WEIGHTS, 4);	// limit bone weights to 4 vertices

        importer_->SetPropertyInteger(			// ignore vertex colours, textures, lights and cameras (for now)
            AI_CONFIG_PP_RVC_FLAGS,
            aiComponent_COLORS		|
            aiComponent_TEXTURES	|
            aiComponent_LIGHTS		|
            aiComponent_CAMERAS
            );

        importer_->SetPropertyInteger(			// ignore point and line primitives (for now)
            AI_CONFIG_PP_SBP_REMOVE,
            aiPrimitiveType_POINT		|
            aiPrimitiveType_LINE
            );
#ifdef _DEBUG
        DefaultLogger::create("", Logger::VERBOSE); // enable debug messages
#else
        DefaultLogger::create();
#endif
        Assimp::DefaultLogger::get()->attachStream(logstream_, loglevels_);
    }

    OpenAssetImport::~OpenAssetImport()
    {
        Assimp::DefaultLogger::get()->detatchStream(logstream_, loglevels_);
        delete logstream_;
        DefaultLogger::kill();
    }

    bool OpenAssetImport::IsSupportedExtension(const QString& filename)
    {
        boost::filesystem::path path(filename.toStdString());
        QString extension = QString(path.extension().c_str()).toLower();

        return importer_->IsExtensionSupported(extension.toStdString());
    }

    void OpenAssetImport::GetMeshData(const QString& file, std::vector<MeshData> &outMeshData)
    {
        const aiScene *scene = importer_->ReadFile(file.toStdString(), default_flags_);

        if (scene)
        {
            const struct aiNode *rootNode = scene->mRootNode;

            aiMatrix4x4 transform;
            GetNodeData(scene, rootNode, file, transform, outMeshData);
        } else
        {
            // report error
            Foundation::RootLogError(importer_->GetErrorString());
        }
    }

    void OpenAssetImport::Import(const void *data, size_t length, const QString &name, const char* hint, const QString &nodeName, std::vector<std::string> &outMeshNames)
    {
        const aiScene *scene = importer_->ReadFileFromMemory(data, length, default_flags_, hint);

        if (scene)
        {
            const struct aiNode *rootNode = scene->mRootNode;

            ImportNode(scene, rootNode, name, nodeName, outMeshNames);
        } else
        {
            // report error
            Foundation::RootLogError(importer_->GetErrorString());
            //return QString(importer_->GetErrorString());
        }
    }

    void OpenAssetImport::GetNodeData(const aiScene *scene, const aiNode *node, const QString& file,
        const aiMatrix4x4 &parentTransform, std::vector<MeshData> &outMeshNames)
    {
        aiMatrix4x4 aiTransform = node->mTransformation;

        aiMatrix4x4 worldTransform =  parentTransform * aiTransform;

        aiVector3D pos;
        aiVector3D scale;
        Vector3df rote;
        aiQuaternion rotq;
        worldTransform.Decompose(scale, rotq, pos);
        Quaternion quat(rotq.x, rotq.y, rotq.z, rotq.w);

        quat.toEuler(rote);
        rote *= RADTODEG;

        if (node->mNumMeshes > 0)
        {
            MeshData data = { file, QString(node->mName.data), Transform(Vector3df(pos.x, pos.y, pos.z), rote, Vector3df(scale.x, scale.y, scale.z)) };
            outMeshNames.push_back(data);
        }

        // import children
        for (int i=0 ; i<node->mNumChildren ; ++i)
            GetNodeData(scene, node->mChildren[i], file, worldTransform, outMeshNames);
    }

    void OpenAssetImport::ImportNode(const aiScene *scene, const aiNode *node, const QString& file,
        const QString &nodeName, std::vector<std::string> &outMeshNames)
    {
        try
        {
   //         boost::filesystem::path path(file.toStdString());
   //         std::string meshname = path.filename() + boost::lexical_cast<std::string>(nodeIdx);
            std::string ogreMeshName = file.toStdString(); //std::string("mesh___") + meshname;
            std::string meshname = ogreMeshName;

            /*if (scene->mNumMaterials > 0)
            {
                // testing getting Ogre material.xml names
                aiString name;
                scene->mMaterials[0]->Get(AI_MATKEY_NAME,name);
                Foundation::RootLogInfo(std::string("Found material ") + std::string(name.data));
            }*/

            //aiMatrix4x4 transform = node->mTransformation;
            if (node->mNumMeshes > 0 && nodeName.compare(QString(node->mName.data)) == 0 && !Ogre::MeshManager::getSingleton().resourceExists(ogreMeshName))
            {
                Ogre::MeshPtr ogreMesh = Ogre::MeshManager::getSingleton().createManual(ogreMeshName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
                ogreMesh->setAutoBuildEdgeLists(false);

                Ogre::Vector3 vmin(std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
                Ogre::Vector3 vmax(std::numeric_limits<float>::min(), std::numeric_limits<float>::min(), std::numeric_limits<float>::min());

                for (unsigned int i=0 ; i<node->mNumMeshes ; ++i)
                {
                    const aiMesh *mesh = scene->mMeshes[node->mMeshes[i]];

                    Ogre::SubMesh *ogreSubmesh = ogreMesh->createSubMesh();

                    ogreSubmesh->useSharedVertices = false;
                    ogreSubmesh->vertexData = new Ogre::VertexData();
                    ogreSubmesh->vertexData->vertexCount = mesh->mNumVertices;
                    Ogre::VertexData *data = ogreSubmesh->vertexData;

                    // Vertex declarations
                    size_t offset = 0;
                    Ogre::VertexDeclaration* decl = data->vertexDeclaration;
                    decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
                    offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
                    decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);

                    offset = 0;
                    for (int tn=0 ; tn<AI_MAX_NUMBER_OF_TEXTURECOORDS ; ++tn)
                    {
                        if (mesh->mTextureCoords[tn])
                        {
                            if (mesh->mNumUVComponents[tn] == 3)
                            {
                                decl->addElement(1, offset, Ogre::VET_FLOAT3, Ogre::VES_TEXTURE_COORDINATES, tn);
                                offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
                            } else
                            {
                                decl->addElement(1, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, tn);
                                offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2);
                            }
                        }
                    }
                    if (mesh->HasTangentsAndBitangents())
                    {
                        decl->addElement(1, offset, Ogre::VET_FLOAT3, Ogre::VES_TANGENT);
                        offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
                        decl->addElement(1, offset, Ogre::VET_FLOAT3, Ogre::VES_BINORMAL);
                    }

                    // Write vertex data to buffer
                    Ogre::HardwareVertexBufferSharedPtr vbuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
                        decl->getVertexSize(0),                     // This value is the size of a vertex in memory
                        data->vertexCount,                          // The number of vertices you'll put into this buffer
                        Ogre::HardwareBuffer::HBU_DYNAMIC // Properties
                        );
                    Ogre::Real *vbData = static_cast<Ogre::Real*>(vbuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));

                    offset = 0;
                    for (unsigned int n=0 ; n<data->vertexCount ; ++n)
                    {
                        vbData[offset++] = mesh->mVertices[n].x;
                        vbData[offset++] = mesh->mVertices[n].y;
                        vbData[offset++] = mesh->mVertices[n].z;

                        vbData[offset++] = mesh->mNormals[n].x;
                        vbData[offset++] = mesh->mNormals[n].y;
                        vbData[offset++] = mesh->mNormals[n].z;

                        vmin.x = std::min(vmin.x, mesh->mVertices[n].x);
                        vmin.y = std::min(vmin.y, mesh->mVertices[n].y);
                        vmin.z = std::min(vmin.z, mesh->mVertices[n].z);

                        vmax.x = std::max(vmax.x, mesh->mVertices[n].x);
                        vmax.y = std::max(vmax.y, mesh->mVertices[n].y);
                        vmax.z = std::max(vmax.z, mesh->mVertices[n].z);
                    }
                    vbuf->unlock();
                    data->vertexBufferBinding->setBinding(0, vbuf);

                    if (mesh->HasTextureCoords(0))
                    {
                    vbuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
                        decl->getVertexSize(1),                     // This value is the size of a vertex in memory
                        data->vertexCount,                          // The number of vertices you'll put into this buffer
                        Ogre::HardwareBuffer::HBU_DYNAMIC // Properties
                        );
                    vbData = static_cast<Ogre::Real*>(vbuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));

                    offset = 0;
                    for (unsigned int n=0 ; n<data->vertexCount ; ++n)
                    {
                        for (int tn=0 ; tn<AI_MAX_NUMBER_OF_TEXTURECOORDS ; ++tn)
                        {
                            if (mesh->mTextureCoords[tn])
                            {
                                if (mesh->mNumUVComponents[tn] == 3)
                                {
                                    vbData[offset++] = mesh->mTextureCoords[tn][n].x;
                                    vbData[offset++] = mesh->mTextureCoords[tn][n].y;
                                    vbData[offset++] = mesh->mTextureCoords[tn][n].z;
                                } else
                                {
                                    vbData[offset++] = mesh->mTextureCoords[tn][n].x;
                                    vbData[offset++] = mesh->mTextureCoords[tn][n].y;
                                }
                            }
                        }

                        if (mesh->HasTangentsAndBitangents())
                        {
                            vbData[offset++] = mesh->mTangents[n].x;
                            vbData[offset++] = mesh->mTangents[n].y;
                            vbData[offset++] = mesh->mTangents[n].z;

                            vbData[offset++] = mesh->mBitangents[n].x;
                            vbData[offset++] = mesh->mBitangents[n].y;
                            vbData[offset++] = mesh->mBitangents[n].z;
                        }
                    }
                    vbuf->unlock();
                    data->vertexBufferBinding->setBinding(1, vbuf);
                    }

                    // indices
                    size_t numIndices = mesh->mNumFaces * 3;            // support only triangles, so 3 indices per face

                    Ogre::HardwareIndexBuffer::IndexType idxType = Ogre::HardwareIndexBuffer::IT_16BIT;
                    if (numIndices > 65535)
                        idxType = Ogre::HardwareIndexBuffer::IT_32BIT;

                    Ogre::HardwareIndexBufferSharedPtr ibuf = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(
                        idxType,                                        // You can use several different value types here
                        numIndices,                                     // The number of indices you'll put in that buffer
                        Ogre::HardwareBuffer::HBU_DYNAMIC     // Properties
                        );

                    if (idxType == Ogre::HardwareIndexBuffer::IT_16BIT)
                    {
                        u16 *idxData = static_cast<u16*>(ibuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));
                        offset = 0;
                        for (int n=0 ; n<mesh->mNumFaces ; ++n)
                        {
                            idxData[offset++] = mesh->mFaces[n].mIndices[0];
                            idxData[offset++] = mesh->mFaces[n].mIndices[1];
                            idxData[offset++] = mesh->mFaces[n].mIndices[2];
                        }
                    } else
                    {
                        u32 *idxData = static_cast<u32*>(ibuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));
                        offset = 0;
                        for (int n=0 ; n<mesh->mNumFaces ; ++n)
                        {
                            idxData[offset++] = mesh->mFaces[n].mIndices[0];
                            idxData[offset++] = mesh->mFaces[n].mIndices[1];
                            idxData[offset++] = mesh->mFaces[n].mIndices[2];
                        }
                    }
                    ibuf->unlock();

                    ogreSubmesh->indexData->indexBuffer = ibuf;         // The pointer to the index buffer
                    ogreSubmesh->indexData->indexCount = numIndices;    // The number of indices we'll use
                    ogreSubmesh->indexData->indexStart = 0;
                }

                if (vmin.x <= vmax.x && vmin.y <= vmax.y && vmin.z <= vmax.z)
                {
                    ogreMesh->_setBounds(Ogre::AxisAlignedBox(vmin, vmax));
                    Ogre::Real maxvertex = std::max(abs(vmax.x), std::max(abs(vmin.x), std::max(abs(vmax.y), std::max(abs(vmin.y), std::max(vmax.z, vmin.z)))));
                    ogreMesh->_setBoundingSphereRadius(maxvertex / 2.f);
                    ogreMesh->load();
                    outMeshNames.push_back(meshname);
                }
            }
        } catch (Ogre::Exception &)
        {
            // error
        }

        // import children
        for (int i=0 ; i<node->mNumChildren ; ++i)
            ImportNode(scene, node->mChildren[i], file, nodeName, outMeshNames);
    }

    void OpenAssetImport::AssImpLogStream::write(const char* message)
    {
        //! \todo doesn't work, check assimp docs for reason -cmayhem
        Foundation::RootLogInfo(message);
    }
}
<|endoftext|>


<commit_before>#include "alloni/al_Ni.hpp"

#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <algorithm>
#include <XnCppWrapper.h>
//#include <usb.h>

using namespace al;

xn::Context context;
XnStatus status;

std::vector<xn::NodeInfo> device_nodes, depth_nodes, image_nodes;
std::map< unsigned char, std::map<unsigned char, unsigned > > bus_map;
//static bool initialized = false;

static bool ok(XnStatus status) {
	if (status != XN_STATUS_OK) {
		printf("OpenNI error: %s\n", xnGetStatusString(status));
		return false;
	}
	return true;
}

Ni& Ni :: get() {
	static Ni singleton;
	return singleton;
}

xn::NodeInfoList device_node_info_list, depth_node_info_list;

Ni :: Ni() {
	int i;

	// enumerate devices:
	if (!ok(context.Init())) return;

	printf("created Ni\n");

	// enumerate all devices
	printf("Searching for OpenNI compliant USB devices:\n");
	if (!ok(context.EnumerateProductionTrees(XN_NODE_TYPE_DEVICE, NULL, device_node_info_list))) return;

	printf("listing devices\n");
	i=0;
	for (xn::NodeInfoList::Iterator nodeIt = device_node_info_list.Begin (); nodeIt != device_node_info_list.End (); ++nodeIt, ++i) {
		const xn::NodeInfo& info = *nodeIt;
		const XnProductionNodeDescription& description = info.GetDescription();
		unsigned short vendor_id;
		unsigned short product_id;
		unsigned char bus;
		unsigned char address;
		sscanf(info.GetCreationInfo(), "%hx/%hx@%hhu/%hhu", &vendor_id, &product_id, &bus, &address);
		std::string connection_string = info.GetCreationInfo();
		std::transform (connection_string.begin (), connection_string.end (), connection_string.begin (), std::towlower);
		printf(">%2d (USB bus %2i address %2i): vendor %s (vendor_id %i) name %s (product_id %i), connection string %s\n",
			i, bus, address,
			description.strVendor, vendor_id,
			description.strName, product_id,
			connection_string.c_str());

		if (connection_string.substr (0,4) == "045e") {
			printf("\t(Kinect)\n");
		}

		device_nodes.push_back(info);
		bus_map[bus][address] = device_nodes.size();
	}

	depth_nodes.clear();
	if (!ok(context.EnumerateProductionTrees(XN_NODE_TYPE_DEPTH, NULL, depth_node_info_list))) return;
	i=0;
	for (xn::NodeInfoList::Iterator nodeIt = depth_node_info_list.Begin (); nodeIt != depth_node_info_list.End (); ++nodeIt, ++i) {
		xn::NodeInfo info = *nodeIt;
		const XnProductionNodeDescription& description = info.GetDescription();
		printf("depth %2d: vendor %s name %s, connection %s\n", i, description.strVendor, description.strName, info.GetCreationInfo());
		depth_nodes.push_back(info);
	}
	printf("Initialized OpenNI\n");
}

struct Kinect :: Impl {

	Impl(xn::NodeInfo info) {
		hasData = false;
		if (!ok(context.CreateProductionTree(info))) return;
		if (!ok(info.GetInstance(mDepthGenerator))) return;

		XnMapOutputMode mode;
		mode.nXRes = 640;
		mode.nYRes = 480;
		mode.nFPS = 30;
		mDepthGenerator.SetMapOutputMode(mode);
		mDepthGenerator.SetIntProperty ("RegistrationType", 2);	// 2 for kinect, 1 for primesense

		mDepthGenerator.RegisterToNewDataAvailable(NewDepthDataAvailable, this, mDepthCallbackHandle);

	}

	~Impl() {
		mDepthGenerator.UnregisterFromNewDataAvailable(mDepthCallbackHandle);
	}

	static void NewDepthDataAvailable (xn::ProductionNode& node, void* cookie) {
		Impl * self = (Impl *)cookie;
		//printf("%p\n", cookie);
		//printf("new depth data %p\n", cookie);
		// trigger condition:
		self->hasData = true;
	}

	bool getMetaData() {
		//XnUInt64 timestamp;
		hasData = false;
		//printf("!");
		//if (mDepthGenerator.IsNewDataAvailable(&timestamp)) {
			//if (ok(context.WaitOneUpdateAll(mDepthGenerator))) {	// nice fps on osx
			//if (ok(context.WaitAndUpdateAll())) {
			if (ok(mDepthGenerator.WaitAndUpdateData())) {
				//printf("%p\n", this);
				mDepthGenerator.GetMetaData(mDepthMD);
				return true;
			}
		//}
		return false;
	}

	xn::DepthGenerator mDepthGenerator;
	xn::DepthMetaData mDepthMD;
  	XnCallbackHandle mDepthCallbackHandle;
	bool hasData;
};

Kinect :: Kinect(unsigned deviceID)
:	mImpl(NULL),
	mDepthArray(1, AlloFloat32Ty, 640, 480),
	mRawDepthArray(1, AlloFloat32Ty, 640, 480),
	mRealWorldArray(3, AlloFloat32Ty, 640, 480),
	mTime(0),
	mDepthNormalize(true),
	mFPS(0),
	mDeviceID(deviceID),
	mZPD(120),
	mZPPS(0.104200)
{
	printf("created Kinect\n");
}

Kinect :: ~Kinect() {
	if (mImpl) delete mImpl;
}

void * Kinect :: getContext() {
	Ni::get();
	return (void *)&context;
}

bool Kinect :: start() {
	return mThread.start(threadFunction, this);
}

bool Kinect :: stop() {
	if (mImpl == 0) return false;
	mActive = false;
	return mThread.join();
}

//void Kinect :: toRealWorld(unsigned count, Vec3f pos[], Vec3f res[]) const {
//	if (mImpl) mImpl->mDepthGenerator.ConvertProjectiveToRealWorld(count, (const XnPoint3D *)pos, (XnPoint3D *)res);
//}

//void Kinect :: toProjective(unsigned count, Vec3f pos[], Vec3f res[]) const {
//	if (mImpl) mImpl->mDepthGenerator.ConvertRealWorldToProjective(count, (const XnPoint3D *)pos, (XnPoint3D *)res);
//}

bool Kinect :: tick() {
	if(mImpl->hasData && mImpl->getMetaData()) {
		const XnUInt xres = mImpl->mDepthMD.XRes();
		const XnUInt yres = mImpl->mDepthMD.YRes();
		const XnDepthPixel zres = mImpl->mDepthMD.ZRes();
		const XnDepthPixel* pDepth = mImpl->mDepthMD.Data();

		const float zscale = mDepthNormalize ? 1.f/zres : 1.f;
		const float zoffset = 0.f;

		//printf("%p: %ix%ix%i, %f fps\n", this, xres, yres, (int)zres, mFPS);

		// copy into Array:
		float * optr = (float *)mDepthArray.data.ptr;
		float * rptr = (float *)mRawDepthArray.data.ptr;
		//for (unsigned i=0; i<xres*yres; i++) {

		for (unsigned y=0; y<yres; y++) {
			for (unsigned x=0; x<xres; x++) {
				XnDepthPixel D = (*pDepth++);
				*rptr++ = D;
				*optr++ = D * zscale + zoffset;
				Vec3d p(toRealWorld(x, y, D));
				mRealWorldArray.write(p.elems, x, y);
			}
		}

		// update FPS:
		al_sec when = al_time();
		al_sec dt = when - mTime;
		mTime = when;
		mFPS = 1./dt;

		// callbacks:
		for (std::list<Callback *>::iterator it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
			(*it)->onKinectData(*this);
		}
	}

	return true;
}

void * Kinect :: threadFunction(void * userData) {
	Kinect& self = *(Kinect *)userData;

	// find the info for this device:
	printf("started Kinect thread\n");
	Ni::get();
	if (self.mDeviceID < depth_nodes.size()) {
		xn::NodeInfo info = depth_nodes[self.mDeviceID % depth_nodes.size()];
		self.mImpl = new Impl(info);

		if (self.mImpl) {
			printf("start generating kinect... %p\n", userData);
			XnStatus s = self.mImpl->mDepthGenerator.StartGenerating();
			if (!ok(s)) return 0;

			//self.mImpl->mDepthGenerator.GetIntProperty("ZPD", (XnUInt64&)self.mZPD);
			//self.mImpl->mDepthGenerator.GetRealProperty("ZPPS", self.mZPPS);

			self.mTime = al_time();
			self.mActive = true;

			self.mImpl->hasData = false;

			while (self.mActive && self.tick()) { al_sleep(0.010); }

			ok(self.mImpl->mDepthGenerator.StopGenerating());
		}

		delete self.mImpl;
		self.mImpl = NULL;
	}
	return 0;
}
<commit_msg>knights who say Ni<commit_after>#include "alloni/al_Ni.hpp"

#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <algorithm>
#include <XnCppWrapper.h>
//#include <usb.h>

using namespace al;

xn::Context context;
XnStatus status;

std::vector<xn::NodeInfo> device_nodes, depth_nodes, image_nodes;
std::map< unsigned char, std::map<unsigned char, unsigned > > bus_map;
//static bool initialized = false;

static bool ok(XnStatus status) {
	if (status != XN_STATUS_OK) {
		printf("OpenNI error: %s\n", xnGetStatusString(status));
		return false;
	}
	return true;
}

Ni& Ni :: get() {
	static Ni singleton;
	return singleton;
}

xn::NodeInfoList device_node_info_list, depth_node_info_list;

Ni :: Ni() {
	int i;

	// enumerate devices:
	if (!ok(context.Init())) return;

	printf("created Ni\n");

	// enumerate all devices
	printf("Searching for OpenNI compliant USB devices:\n");
	if (!ok(context.EnumerateProductionTrees(XN_NODE_TYPE_DEVICE, NULL, device_node_info_list))) return;

	printf("listing devices\n");
	i=0;
	for (xn::NodeInfoList::Iterator nodeIt = device_node_info_list.Begin (); nodeIt != device_node_info_list.End (); ++nodeIt, ++i) {
		const xn::NodeInfo& info = *nodeIt;
		const XnProductionNodeDescription& description = info.GetDescription();
		unsigned short vendor_id;
		unsigned short product_id;
		unsigned char bus;
		unsigned char address;
		sscanf(info.GetCreationInfo(), "%hx/%hx@%hhu/%hhu", &vendor_id, &product_id, &bus, &address);
		std::string connection_string = info.GetCreationInfo();
		std::transform (connection_string.begin (), connection_string.end (), connection_string.begin (), std::towlower);
		printf(">%2d (USB bus %2i address %2i): vendor %s (vendor_id %i) name %s (product_id %i), connection string %s\n",
			i, bus, address,
			description.strVendor, vendor_id,
			description.strName, product_id,
			connection_string.c_str());

		if (connection_string.substr (0,4) == "045e") {
			printf("\t(Kinect)\n");
		}

		device_nodes.push_back(info);
		bus_map[bus][address] = device_nodes.size();
	}

	depth_nodes.clear();
	if (!ok(context.EnumerateProductionTrees(XN_NODE_TYPE_DEPTH, NULL, depth_node_info_list))) return;
	i=0;
	for (xn::NodeInfoList::Iterator nodeIt = depth_node_info_list.Begin (); nodeIt != depth_node_info_list.End (); ++nodeIt, ++i) {
		xn::NodeInfo info = *nodeIt;
		const XnProductionNodeDescription& description = info.GetDescription();
		printf("depth %2d: vendor %s name %s, connection %s\n", i, description.strVendor, description.strName, info.GetCreationInfo());
		depth_nodes.push_back(info);
	}
	printf("Initialized OpenNI\n");
}

struct Kinect :: Impl {

	Impl(xn::NodeInfo info) {
		hasData = false;
		if (!ok(context.CreateProductionTree(info))) return;
		if (!ok(info.GetInstance(mDepthGenerator))) return;

		XnMapOutputMode mode;
		mode.nXRes = 640;
		mode.nYRes = 480;
		mode.nFPS = 30;
		mDepthGenerator.SetMapOutputMode(mode);
		mDepthGenerator.SetIntProperty ("RegistrationType", 2);	// 2 for kinect, 1 for primesense

		mDepthGenerator.RegisterToNewDataAvailable(NewDepthDataAvailable, this, mDepthCallbackHandle);

	}

	~Impl() {
		mDepthGenerator.UnregisterFromNewDataAvailable(mDepthCallbackHandle);
	}

	static void NewDepthDataAvailable (xn::ProductionNode& node, void* cookie) {
		Impl * self = (Impl *)cookie;
		//printf("%p\n", cookie);
		//printf("new depth data %p\n", cookie);
		// trigger condition:
		self->hasData = true;
	}

	bool getMetaData() {
		//XnUInt64 timestamp;
		hasData = false;
		//printf("!");
		//if (mDepthGenerator.IsNewDataAvailable(&timestamp)) {
			//if (ok(context.WaitOneUpdateAll(mDepthGenerator))) {	// nice fps on osx
			//if (ok(context.WaitAndUpdateAll())) {
			if (ok(mDepthGenerator.WaitAndUpdateData())) {
				//printf("%p\n", this);
				mDepthGenerator.GetMetaData(mDepthMD);
				return true;
			}
		//}
		return false;
	}

	xn::DepthGenerator mDepthGenerator;
	xn::DepthMetaData mDepthMD;
  	XnCallbackHandle mDepthCallbackHandle;
	bool hasData;
};

Kinect :: Kinect(unsigned deviceID)
:	mImpl(NULL),
	mDepthArray(1, AlloFloat32Ty, 640, 480),
	mRawDepthArray(1, AlloFloat32Ty, 640, 480),
	mRealWorldArray(3, AlloFloat32Ty, 640, 480),
	mTime(0),
	mDepthNormalize(true),
	mFPS(0),
	mDeviceID(deviceID),
	mZPD(120),
	mZPPS(0.104200)
{
	printf("created Kinect\n");
}

Kinect :: ~Kinect() {
	if (mImpl) delete mImpl;
}

void * Kinect :: getContext() {
	Ni::get();
	return (void *)&context;
}

bool Kinect :: start() {
	return mThread.start(threadFunction, this);
}

bool Kinect :: stop() {
	if (mImpl == 0) return false;
	mActive = false;
	return mThread.join();
}

//void Kinect :: toRealWorld(unsigned count, Vec3f pos[], Vec3f res[]) const {
//	if (mImpl) mImpl->mDepthGenerator.ConvertProjectiveToRealWorld(count, (const XnPoint3D *)pos, (XnPoint3D *)res);
//}

//void Kinect :: toProjective(unsigned count, Vec3f pos[], Vec3f res[]) const {
//	if (mImpl) mImpl->mDepthGenerator.ConvertRealWorldToProjective(count, (const XnPoint3D *)pos, (XnPoint3D *)res);
//}

bool Kinect :: tick() {
	if(mImpl->hasData && mImpl->getMetaData()) {
		const XnUInt xres = mImpl->mDepthMD.XRes();
		const XnUInt yres = mImpl->mDepthMD.YRes();
		const XnDepthPixel zres = mImpl->mDepthMD.ZRes();
		const XnDepthPixel* pDepth = mImpl->mDepthMD.Data();

		const float zscale = mDepthNormalize ? 1.f/zres : 1.f;
		const float zoffset = 0.f;

		//printf("%p: %ix%ix%i, %f fps\n", this, xres, yres, (int)zres, mFPS);

		// copy into Array:
		float * optr = (float *)mDepthArray.data.ptr;
		float * rptr = (float *)mRawDepthArray.data.ptr;
		//for (unsigned i=0; i<xres*yres; i++) {

		for (unsigned y=0; y<yres; y++) {
			for (unsigned x=0; x<xres; x++) {
				XnDepthPixel D = (*pDepth++);
				*rptr++ = D;
				*optr++ = D * zscale + zoffset;
				Vec3d p(toRealWorld(x, y, D));
				mRealWorldArray.write(p.elems, x, y);
			}
		}

		// update FPS:
		al_sec when = al_time();
		al_sec dt = when - mTime;
		mTime = when;
		mFPS = 1./dt;

		// callbacks:
		for (std::list<Callback *>::iterator it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
			(*it)->onKinectData(*this);
		}
	}

	return true;
}

void * Kinect :: threadFunction(void * userData) {
	Kinect& self = *(Kinect *)userData;

	// find the info for this device:
	printf("started Kinect thread\n");
	Ni::get();
	if (self.mDeviceID < depth_nodes.size()) {
		xn::NodeInfo info = depth_nodes[self.mDeviceID % depth_nodes.size()];
		self.mImpl = new Impl(info);

		if (self.mImpl) {
			printf("start generating kinect... %p\n", userData);
			XnStatus s = self.mImpl->mDepthGenerator.StartGenerating();
			if (!ok(s)) return 0;

			self.mImpl->mDepthGenerator.GetIntProperty("ZPD", (XnUInt64&)self.mZPD);
			self.mImpl->mDepthGenerator.GetRealProperty("ZPPS", self.mZPPS);

			self.mTime = al_time();
			self.mActive = true;

			self.mImpl->hasData = false;

			while (self.mActive && self.tick()) { al_sleep(0.010); }

			ok(self.mImpl->mDepthGenerator.StopGenerating());
		}

		delete self.mImpl;
		self.mImpl = NULL;
	}
	return 0;
}
<|endoftext|>