<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the tools applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QFile>
#include <QProcess>
#include <QLibraryInfo>
#include <qt_windows.h>
#include <io.h>

QT_BEGIN_NAMESPACE

static QString quotePath(const QString &s)
{
    if (!s.startsWith(QLatin1Char('\"')) && s.contains(QLatin1Char(' ')))
        return QLatin1Char('\"') + s + QLatin1Char('\"');
    return s;
}

static bool runWithQtInEnvironment(const QString &cmd)
{
    QProcess proc;

    // prepend the qt binary directory to the path
    QStringList env = QProcess::systemEnvironment();
    for (int i=0; i<env.count(); ++i) {
        QString var = env.at(i);
        int setidx = var.indexOf(QLatin1Char('='));
        if (setidx != -1) {
            QString varname = var.left(setidx).trimmed().toUpper();
            if (varname == QLatin1String("PATH")) {
                var = var.mid(setidx + 1);
                var = QLatin1String("PATH=") +
                    QLibraryInfo::location(QLibraryInfo::BinariesPath) +
                    QLatin1Char(';') + var;
                env[i] = var;
                break;
            }
        }
    }

    proc.setEnvironment(env);
    proc.start(cmd);
    proc.waitForFinished(-1);

    return (proc.exitCode() == 0);
}

static bool attachTypeLibrary(const QString &applicationName, int resource, const QByteArray &data, QString *errorMessage)
{
    HANDLE hExe = BeginUpdateResource((const wchar_t *)applicationName.utf16(), false);
    if (hExe == 0) {
        if (errorMessage)
            *errorMessage = QString::fromLatin1("Failed to attach type library to binary %1 - could not open file.").arg(applicationName);
        return false;
    }
    if (!UpdateResource(hExe, L"TYPELIB", MAKEINTRESOURCE(resource), 0, (void*)data.data(), data.count())) {
        EndUpdateResource(hExe, true);
        if (errorMessage)
            *errorMessage = QString::fromLatin1("Failed to attach type library to binary %1 - could not update file.").arg(applicationName);
        return false;
    }

    if (!EndUpdateResource(hExe,false)) {
        if (errorMessage)
            *errorMessage = QString::fromLatin1("Failed to attach type library to binary %1 - could not write file.").arg(applicationName);
        return false;
    }

    if (errorMessage)
        *errorMessage = QString::fromLatin1("Type library attached to %1.").arg(applicationName);
    return true;
}

static bool registerServer(const QString &input)
{
    bool ok = false;
    if (input.endsWith(QLatin1String(".exe"))) {
        ok = runWithQtInEnvironment(quotePath(input) + QLatin1String(" -regserver"));
    } else {
        HMODULE hdll = LoadLibrary((const wchar_t *)input.utf16());
        if (!hdll) {
            fprintf(stderr, "Couldn't load library file %s\n", (const char*)input.toLocal8Bit().data());
            return false;
        }
        typedef HRESULT(__stdcall* RegServerProc)();
        RegServerProc DllRegisterServer = (RegServerProc)GetProcAddress(hdll, "DllRegisterServer");
        if (!DllRegisterServer) {
            fprintf(stderr, "Library file %s doesn't appear to be a COM library\n", (const char*)input.toLocal8Bit().data());
            return false;
        }
        ok = DllRegisterServer() == S_OK;
    }
    return ok;
}

static bool unregisterServer(const QString &input)
{
    bool ok = false;
    if (input.endsWith(QLatin1String(".exe"))) {
        ok = runWithQtInEnvironment(quotePath(input) + QLatin1String(" -unregserver"));
    } else {
        HMODULE hdll = LoadLibrary((const wchar_t *)input.utf16());
        if (!hdll) {
            fprintf(stderr, "Couldn't load library file %s\n", (const char*)input.toLocal8Bit().data());
            return false;
        }
        typedef HRESULT(__stdcall* RegServerProc)();
        RegServerProc DllUnregisterServer = (RegServerProc)GetProcAddress(hdll, "DllUnregisterServer");
        if (!DllUnregisterServer) {
            fprintf(stderr, "Library file %s doesn't appear to be a COM library\n", (const char*)input.toLocal8Bit().data());
            return false;
        }
        ok = DllUnregisterServer() == S_OK;
    }
    return ok;
}

static HRESULT dumpIdl(const QString &input, const QString &idlfile, const QString &version)
{
    HRESULT res = E_FAIL;

    if (input.endsWith(QLatin1String(".exe"))) {
        if (runWithQtInEnvironment(quotePath(input) + QLatin1String(" -dumpidl ") + idlfile + QLatin1String(" -version ") + version))
            res = S_OK;
    } else {
        HMODULE hdll = LoadLibrary((const wchar_t *)input.utf16());
        if (!hdll) {
            fprintf(stderr, "Couldn't load library file %s\n", (const char*)input.toLocal8Bit().data());
            return 3;
        }
        typedef HRESULT(__stdcall* DumpIDLProc)(const QString&, const QString&);
        DumpIDLProc DumpIDL = (DumpIDLProc)GetProcAddress(hdll, "DumpIDL");
        if (!DumpIDL) {
            fprintf(stderr, "Couldn't resolve 'DumpIDL' symbol in %s\n", (const char*)input.toLocal8Bit().data());
            return 3;
        }
        res = DumpIDL(idlfile, version);
        FreeLibrary(hdll);
    }

    return res;
}

static void slashify(QString &s)
{
    if (!s.contains(QLatin1Char('/')))
        return;

    int i = 0;
    while (i < (int)s.length()) {
        if (s[i] == QLatin1Char('/'))
            s[i] = QLatin1Char('\\');
        ++i;
    }
}

int runIdc(int argc, char **argv)
{
    QString error;
    QString tlbfile;
    QString idlfile;
    QString input;
    QString version = QLatin1String("1.0");

    int i = 1;
    while (i < argc) {
        QString p = QString::fromLocal8Bit(argv[i]).toLower();

        if (p == QLatin1String("/idl") || p == QLatin1String("-idl")) {
            ++i;
            if (i > argc) {
                error = QLatin1String("Missing name for interface definition file!");
                break;
            }
            idlfile = QLatin1String(argv[i]);
            idlfile = idlfile.trimmed().toLower();
        } else if (p == QLatin1String("/version") || p == QLatin1String("-version")) {
            ++i;
            if (i > argc)
                version = QLatin1String("1.0");
            else
                version = QLatin1String(argv[i]);
        } else if (p == QLatin1String("/tlb") || p == QLatin1String("-tlb")) {
            ++i;
            if (i > argc) {
                error = QLatin1String("Missing name for type library file!");
                break;
            }
            tlbfile = QLatin1String(argv[i]);
            tlbfile = tlbfile.trimmed().toLower();
        } else if (p == QLatin1String("/v") || p == QLatin1String("-v")) {
            fprintf(stdout, "Qt Interface Definition Compiler version 1.0\n");
            return 0;
        } else if (p == QLatin1String("/regserver") || p == QLatin1String("-regserver")) {
            if (!registerServer(input)) {
                fprintf(stderr, "Failed to register server!\n");
                return 1;
            }
            fprintf(stderr, "Server registered successfully!\n");
            return 0;
        } else if (p == QLatin1String("/unregserver") || p == QLatin1String("-unregserver")) {
            if (!unregisterServer(input)) {
                fprintf(stderr, "Failed to unregister server!\n");
                return 1;
            }
            fprintf(stderr, "Server unregistered successfully!\n");
            return 0;
        } else if (p[0] == QLatin1Char('/') || p[0] == QLatin1Char('-')) {
            error = QLatin1String("Unknown option \"") + p + QLatin1Char('\"');
            break;
        } else {
            input = QLatin1String(argv[i]);
            input = input.trimmed().toLower();
        }
        i++;
    }
    if (!error.isEmpty()) {
        fprintf(stderr, "%s", error.toLatin1().data());
        fprintf(stderr, "\n");
        return 5;
    }
    if (input.isEmpty()) {
        fprintf(stderr, "No input file specified!\n");
        return 1;
    }
    if (input.endsWith(QLatin1String(".exe")) && tlbfile.isEmpty() && idlfile.isEmpty()) {
        fprintf(stderr, "No type output file specified!\n");
        return 2;
    }
    if (input.endsWith(QLatin1String(".dll")) && idlfile.isEmpty() && tlbfile.isEmpty()) {
        fprintf(stderr, "No interface definition file and no type library file specified!\n");
        return 3;
    }
    slashify(input);
    if (!tlbfile.isEmpty()) {
        slashify(tlbfile);
        QFile file(tlbfile);
        if (!file.open(QIODevice::ReadOnly)) {
            fprintf(stderr, "Couldn't open %s for read\n", (const char*)tlbfile.toLocal8Bit().data());
            return 4;
        }
        QByteArray data = file.readAll();
        QString error;
        bool ok = attachTypeLibrary(input, 1, data, &error);
        fprintf(stderr, "%s", error.toLatin1().data());
        fprintf(stderr, "\n");
        return ok ? 0 : 4;
    } else if (!idlfile.isEmpty()) {
        slashify(idlfile);
        idlfile = quotePath(idlfile);
        fprintf(stderr, "\n\n%s\n\n", (const char*)idlfile.toLocal8Bit().data());
        quotePath(input);
        HRESULT res = dumpIdl(input, idlfile, version);

        switch (res) {
        case S_OK:
            break;
        case E_FAIL:
            fprintf(stderr, "IDL generation failed trying to run program %s!\n", (const char*)input.toLocal8Bit().data());
            return res;
        case -1:
            fprintf(stderr, "Couldn't open %s for writing!\n", (const char*)idlfile.toLocal8Bit().data());
            return res;
        case 1:
            fprintf(stderr, "Malformed appID value in %s!\n", (const char*)input.toLocal8Bit().data());
            return res;
        case 2:
            fprintf(stderr, "Malformed typeLibID value in %s!\n", (const char*)input.toLocal8Bit().data());
            return res;
        case 3:
            fprintf(stderr, "Class has no metaobject information (error in %s)!\n", (const char*)input.toLocal8Bit().data());
            return res;
        case 4:
            fprintf(stderr, "Malformed classID value in %s!\n", (const char*)input.toLocal8Bit().data());
            return res;
        case 5:
            fprintf(stderr, "Malformed interfaceID value in %s!\n", (const char*)input.toLocal8Bit().data());
            return res;
        case 6:
            fprintf(stderr, "Malformed eventsID value in %s!\n", (const char*)input.toLocal8Bit().data());
            return res;

        default:
            fprintf(stderr, "Unknown error writing IDL from %s\n", (const char*)input.toLocal8Bit().data());
            return 7;
        }
    }
    return 0;
}

QT_END_NAMESPACE

int main(int argc, char **argv)
{
    return QT_PREPEND_NAMESPACE(runIdc)(argc, argv);
}
<commit_msg>do not lower-case input file names<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the tools applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QFile>
#include <QProcess>
#include <QLibraryInfo>
#include <qt_windows.h>
#include <io.h>

QT_BEGIN_NAMESPACE

static QString quotePath(const QString &s)
{
    if (!s.startsWith(QLatin1Char('\"')) && s.contains(QLatin1Char(' ')))
        return QLatin1Char('\"') + s + QLatin1Char('\"');
    return s;
}

static bool hasFileExtension(const QString &filePath, const QString &extension)
{
    return filePath.endsWith(extension, Qt::CaseInsensitive);
}

static bool hasExeExtension(const QString &filePath)
{
    return hasFileExtension(filePath, QStringLiteral(".exe"));
}

static bool hasDllExtension(const QString &filePath)
{
    return hasFileExtension(filePath, QStringLiteral(".dll"));
}

static bool runWithQtInEnvironment(const QString &cmd)
{
    QProcess proc;

    // prepend the qt binary directory to the path
    QStringList env = QProcess::systemEnvironment();
    for (int i=0; i<env.count(); ++i) {
        QString var = env.at(i);
        int setidx = var.indexOf(QLatin1Char('='));
        if (setidx != -1) {
            QString varname = var.left(setidx).trimmed().toUpper();
            if (varname == QLatin1String("PATH")) {
                var = var.mid(setidx + 1);
                var = QLatin1String("PATH=") +
                    QLibraryInfo::location(QLibraryInfo::BinariesPath) +
                    QLatin1Char(';') + var;
                env[i] = var;
                break;
            }
        }
    }

    proc.setEnvironment(env);
    proc.start(cmd);
    proc.waitForFinished(-1);

    return (proc.exitCode() == 0);
}

static bool attachTypeLibrary(const QString &applicationName, int resource, const QByteArray &data, QString *errorMessage)
{
    HANDLE hExe = BeginUpdateResource((const wchar_t *)applicationName.utf16(), false);
    if (hExe == 0) {
        if (errorMessage)
            *errorMessage = QString::fromLatin1("Failed to attach type library to binary %1 - could not open file.").arg(applicationName);
        return false;
    }
    if (!UpdateResource(hExe, L"TYPELIB", MAKEINTRESOURCE(resource), 0, (void*)data.data(), data.count())) {
        EndUpdateResource(hExe, true);
        if (errorMessage)
            *errorMessage = QString::fromLatin1("Failed to attach type library to binary %1 - could not update file.").arg(applicationName);
        return false;
    }

    if (!EndUpdateResource(hExe,false)) {
        if (errorMessage)
            *errorMessage = QString::fromLatin1("Failed to attach type library to binary %1 - could not write file.").arg(applicationName);
        return false;
    }

    if (errorMessage)
        *errorMessage = QString::fromLatin1("Type library attached to %1.").arg(applicationName);
    return true;
}

static bool registerServer(const QString &input)
{
    bool ok = false;
    if (hasExeExtension(input)) {
        ok = runWithQtInEnvironment(quotePath(input) + QLatin1String(" -regserver"));
    } else {
        HMODULE hdll = LoadLibrary((const wchar_t *)input.utf16());
        if (!hdll) {
            fprintf(stderr, "Couldn't load library file %s\n", (const char*)input.toLocal8Bit().data());
            return false;
        }
        typedef HRESULT(__stdcall* RegServerProc)();
        RegServerProc DllRegisterServer = (RegServerProc)GetProcAddress(hdll, "DllRegisterServer");
        if (!DllRegisterServer) {
            fprintf(stderr, "Library file %s doesn't appear to be a COM library\n", (const char*)input.toLocal8Bit().data());
            return false;
        }
        ok = DllRegisterServer() == S_OK;
    }
    return ok;
}

static bool unregisterServer(const QString &input)
{
    bool ok = false;
    if (hasExeExtension(input)) {
        ok = runWithQtInEnvironment(quotePath(input) + QLatin1String(" -unregserver"));
    } else {
        HMODULE hdll = LoadLibrary((const wchar_t *)input.utf16());
        if (!hdll) {
            fprintf(stderr, "Couldn't load library file %s\n", (const char*)input.toLocal8Bit().data());
            return false;
        }
        typedef HRESULT(__stdcall* RegServerProc)();
        RegServerProc DllUnregisterServer = (RegServerProc)GetProcAddress(hdll, "DllUnregisterServer");
        if (!DllUnregisterServer) {
            fprintf(stderr, "Library file %s doesn't appear to be a COM library\n", (const char*)input.toLocal8Bit().data());
            return false;
        }
        ok = DllUnregisterServer() == S_OK;
    }
    return ok;
}

static HRESULT dumpIdl(const QString &input, const QString &idlfile, const QString &version)
{
    HRESULT res = E_FAIL;

    if (hasExeExtension(input)) {
        if (runWithQtInEnvironment(quotePath(input) + QLatin1String(" -dumpidl ") + idlfile + QLatin1String(" -version ") + version))
            res = S_OK;
    } else {
        HMODULE hdll = LoadLibrary((const wchar_t *)input.utf16());
        if (!hdll) {
            fprintf(stderr, "Couldn't load library file %s\n", (const char*)input.toLocal8Bit().data());
            return 3;
        }
        typedef HRESULT(__stdcall* DumpIDLProc)(const QString&, const QString&);
        DumpIDLProc DumpIDL = (DumpIDLProc)GetProcAddress(hdll, "DumpIDL");
        if (!DumpIDL) {
            fprintf(stderr, "Couldn't resolve 'DumpIDL' symbol in %s\n", (const char*)input.toLocal8Bit().data());
            return 3;
        }
        res = DumpIDL(idlfile, version);
        FreeLibrary(hdll);
    }

    return res;
}

static void slashify(QString &s)
{
    if (!s.contains(QLatin1Char('/')))
        return;

    int i = 0;
    while (i < (int)s.length()) {
        if (s[i] == QLatin1Char('/'))
            s[i] = QLatin1Char('\\');
        ++i;
    }
}

int runIdc(int argc, char **argv)
{
    QString error;
    QString tlbfile;
    QString idlfile;
    QString input;
    QString version = QLatin1String("1.0");

    int i = 1;
    while (i < argc) {
        QString p = QString::fromLocal8Bit(argv[i]).toLower();

        if (p == QLatin1String("/idl") || p == QLatin1String("-idl")) {
            ++i;
            if (i > argc) {
                error = QLatin1String("Missing name for interface definition file!");
                break;
            }
            idlfile = QLatin1String(argv[i]);
            idlfile = idlfile.trimmed();
        } else if (p == QLatin1String("/version") || p == QLatin1String("-version")) {
            ++i;
            if (i > argc)
                version = QLatin1String("1.0");
            else
                version = QLatin1String(argv[i]);
        } else if (p == QLatin1String("/tlb") || p == QLatin1String("-tlb")) {
            ++i;
            if (i > argc) {
                error = QLatin1String("Missing name for type library file!");
                break;
            }
            tlbfile = QLatin1String(argv[i]);
            tlbfile = tlbfile.trimmed();
        } else if (p == QLatin1String("/v") || p == QLatin1String("-v")) {
            fprintf(stdout, "Qt Interface Definition Compiler version 1.0\n");
            return 0;
        } else if (p == QLatin1String("/regserver") || p == QLatin1String("-regserver")) {
            if (!registerServer(input)) {
                fprintf(stderr, "Failed to register server!\n");
                return 1;
            }
            fprintf(stderr, "Server registered successfully!\n");
            return 0;
        } else if (p == QLatin1String("/unregserver") || p == QLatin1String("-unregserver")) {
            if (!unregisterServer(input)) {
                fprintf(stderr, "Failed to unregister server!\n");
                return 1;
            }
            fprintf(stderr, "Server unregistered successfully!\n");
            return 0;
        } else if (p[0] == QLatin1Char('/') || p[0] == QLatin1Char('-')) {
            error = QLatin1String("Unknown option \"") + p + QLatin1Char('\"');
            break;
        } else {
            input = QLatin1String(argv[i]);
            input = input.trimmed();
        }
        i++;
    }
    if (!error.isEmpty()) {
        fprintf(stderr, "%s", error.toLatin1().data());
        fprintf(stderr, "\n");
        return 5;
    }
    if (input.isEmpty()) {
        fprintf(stderr, "No input file specified!\n");
        return 1;
    }
    if (hasExeExtension(input) && tlbfile.isEmpty() && idlfile.isEmpty()) {
        fprintf(stderr, "No type output file specified!\n");
        return 2;
    }
    if (hasDllExtension(input) && idlfile.isEmpty() && tlbfile.isEmpty()) {
        fprintf(stderr, "No interface definition file and no type library file specified!\n");
        return 3;
    }
    slashify(input);
    if (!tlbfile.isEmpty()) {
        slashify(tlbfile);
        QFile file(tlbfile);
        if (!file.open(QIODevice::ReadOnly)) {
            fprintf(stderr, "Couldn't open %s for read\n", (const char*)tlbfile.toLocal8Bit().data());
            return 4;
        }
        QByteArray data = file.readAll();
        QString error;
        bool ok = attachTypeLibrary(input, 1, data, &error);
        fprintf(stderr, "%s", error.toLatin1().data());
        fprintf(stderr, "\n");
        return ok ? 0 : 4;
    } else if (!idlfile.isEmpty()) {
        slashify(idlfile);
        idlfile = quotePath(idlfile);
        fprintf(stderr, "\n\n%s\n\n", (const char*)idlfile.toLocal8Bit().data());
        quotePath(input);
        HRESULT res = dumpIdl(input, idlfile, version);

        switch (res) {
        case S_OK:
            break;
        case E_FAIL:
            fprintf(stderr, "IDL generation failed trying to run program %s!\n", (const char*)input.toLocal8Bit().data());
            return res;
        case -1:
            fprintf(stderr, "Couldn't open %s for writing!\n", (const char*)idlfile.toLocal8Bit().data());
            return res;
        case 1:
            fprintf(stderr, "Malformed appID value in %s!\n", (const char*)input.toLocal8Bit().data());
            return res;
        case 2:
            fprintf(stderr, "Malformed typeLibID value in %s!\n", (const char*)input.toLocal8Bit().data());
            return res;
        case 3:
            fprintf(stderr, "Class has no metaobject information (error in %s)!\n", (const char*)input.toLocal8Bit().data());
            return res;
        case 4:
            fprintf(stderr, "Malformed classID value in %s!\n", (const char*)input.toLocal8Bit().data());
            return res;
        case 5:
            fprintf(stderr, "Malformed interfaceID value in %s!\n", (const char*)input.toLocal8Bit().data());
            return res;
        case 6:
            fprintf(stderr, "Malformed eventsID value in %s!\n", (const char*)input.toLocal8Bit().data());
            return res;

        default:
            fprintf(stderr, "Unknown error writing IDL from %s\n", (const char*)input.toLocal8Bit().data());
            return 7;
        }
    }
    return 0;
}

QT_END_NAMESPACE

int main(int argc, char **argv)
{
    return QT_PREPEND_NAMESPACE(runIdc)(argc, argv);
}
<|endoftext|>


<commit_before>/*
 * File:   main.cpp
 * Author: vehoff
 *
 * Created on February 3, 2010, 5:58 PM
 */

#include <stdlib.h>

#include "integralsapp.h"

/*
 *
 */
int main(int argc, char** argv) {

    Integrals int_calc;
    int_calc.Run(argc, argv);

    return (EXIT_SUCCESS);
}

<commit_msg>file not needed<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2016, Tom Honermann
//
// This file is distributed under the MIT License. See the accompanying file
// LICENSE.txt or http://www.opensource.org/licenses/mit-license.php for terms
// and conditions.

#ifndef TEXT_VIEW_CONCEPTS_HPP // {
#define TEXT_VIEW_CONCEPTS_HPP

#include <experimental/ranges/concepts>
#include <experimental/ranges/type_traits>
#include <text_view_detail/traits.hpp>
#include <text_view_detail/character_set_id.hpp>

namespace std {
namespace experimental {
inline namespace text {

namespace text_detail {
template<typename T, T t1, T t2>
concept bool SameValue() {
    return t1 == t2;
}

// FIXME: gcc bug 67565, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67565
// FIXME: Compile time performance is negatively impacted by concept definitions
// FIXME: specified with disjunction constraints.  Performance is significantly
// FIXME: improved by rewriting such constraints in terms of constexpr function
// FIXME: or variable templates.  Rewriting the CodeUnit and CodePoint concepts
// FIXME: in terms of is_code_unit_v and is_code_point_v dropped build times
// FIXME: from 5m50s to 2m00s.  Once the performance issues in the compiler are
// FIXME: addressed, is_code_unit_v and is_code_point_v can be removed and
// FIXME: the original CodeUnit and CodePoint concept definitions restored.
template<typename T>
constexpr bool is_code_unit_v =
    std::is_integral<T>::value
    && (std::is_unsigned<T>::value
        || std::is_same<std::remove_cv_t<T>, char>::value
        || std::is_same<std::remove_cv_t<T>, wchar_t>::value);

template<typename T>
constexpr bool is_code_point_v =
    std::is_integral<T>::value
    && (std::is_unsigned<T>::value
        || std::is_same<std::remove_cv_t<T>, char>::value
        || std::is_same<std::remove_cv_t<T>, wchar_t>::value);
} // text_detail namespace

/*
 * Code unit concept
 */
template<typename T>
concept bool CodeUnit() {
    return text_detail::is_code_unit_v<T>;
}

/*
 * Code point concept
 */
template<typename T>
concept bool CodePoint() {
    return text_detail::is_code_point_v<T>;
}

/*
 * Character set concept
 */
template<typename T>
concept bool CharacterSet() {
    return requires () {
               { T::get_name() } noexcept -> const char *;
           }
        && CodePoint<code_point_type_t<T>>();
}

/*
 * Character concept
 */
template<typename T>
concept bool Character() {
    return CharacterSet<character_set_type_t<T>>()
        && ranges::Regular<T>()
        && ranges::Copyable<T>()
        && requires (T t,
                     const T ct,
                     code_point_type_t<character_set_type_t<T>> cp)
           {
               t.set_code_point(cp);
               { ct.get_code_point() } noexcept
                   -> code_point_type_t<character_set_type_t<T>>;
               { ct.get_character_set_id() }
                   -> character_set_id;
           };
}

/*
 * Code unit iterator concept
 */
template<typename T>
concept bool CodeUnitIterator() {
    return ranges::Iterator<T>()
        && CodeUnit<ranges::value_type_t<T>>();
}

/*
 * Code unit output iterator concept
 */
template<typename T, typename V>
concept bool CodeUnitOutputIterator() {
    return ranges::OutputIterator<T, V>()
        && CodeUnit<V>();
}

/*
 * Text encoding state concept
 * These requirements are intended to match the char_traits<T>::state_type
 * requirements described in C++11 [char.traits.typedefs] 21.2.2p4.
 */
template<typename T>
concept bool TextEncodingState() {
    return ranges::Semiregular<T>();
}

/*
 * Text encoding state transition concept
 */
template<typename T>
concept bool TextEncodingStateTransition() {
    return ranges::Semiregular<T>();
}

/*
 * Text encoding concept
 */
template<typename T>
concept bool TextEncoding() {
    return requires () {
               { T::min_code_units } noexcept -> int;
               { T::max_code_units } noexcept -> int;
           }
        && TextEncodingState<typename T::state_type>()
        && TextEncodingStateTransition<typename T::state_transition_type>()
        && CodeUnit<code_unit_type_t<T>>()
        && Character<character_type_t<T>>()
        && requires () {
               { T::initial_state() } noexcept
                   -> const typename T::state_type&;
           };
}

/*
 * Text encoder concept
 */
template<typename T, typename CUIT>
concept bool TextEncoder() {
    return TextEncoding<T>()
        && CodeUnitOutputIterator<CUIT, code_unit_type_t<T>>()
        && requires (
               typename T::state_type &state,
               CUIT &out,
               typename T::state_transition_type stt,
               int &encoded_code_units)
           {
               T::encode_state_transition(state, out, stt, encoded_code_units);
           }
        && requires (
               typename T::state_type &state,
               CUIT &out,
               character_type_t<T> c,
               int &encoded_code_units)
           {
               T::encode(state, out, c, encoded_code_units);
           };
}

/*
 * Text decoder concept
 */
template<typename T, typename CUIT>
concept bool TextDecoder() {
    return TextEncoding<T>()
        && ranges::InputIterator<CUIT>()
        && ranges::ConvertibleTo<ranges::value_type_t<CUIT>,
                                 code_unit_type_t<T>>()
        && requires (
               typename T::state_type &state,
               CUIT &in_next,
               CUIT in_end,
               character_type_t<T> &c,
               int &decoded_code_units)
           {
               { T::decode(state, in_next, in_end, c, decoded_code_units) } -> bool;
           };
}

/*
 * Text forward decoder concept
 */
template<typename T, typename CUIT>
concept bool TextForwardDecoder() {
    return TextDecoder<T, CUIT>()
        && ranges::ForwardIterator<CUIT>();
}

/*
 * Text bidirectional decoder concept
 */
template<typename T, typename CUIT>
concept bool TextBidirectionalDecoder() {
    return TextForwardDecoder<T, CUIT>()
        && ranges::BidirectionalIterator<CUIT>()
        && requires (
               typename T::state_type &state,
               CUIT &in_next,
               CUIT in_end,
               character_type_t<T> &c,
               int &decoded_code_units)
           {
               { T::rdecode(state, in_next, in_end, c, decoded_code_units) } -> bool;
           };
}

/*
 * Text random access decoder concept
 */
template<typename T, typename CUIT>
concept bool TextRandomAccessDecoder() {
    return TextBidirectionalDecoder<T, CUIT>()
        && ranges::RandomAccessIterator<CUIT>()
        && text_detail::SameValue<int, T::min_code_units, T::max_code_units>()
        && std::is_empty<typename T::state_type>::value;
}

/*
 * Text iterator concept
 */
template<typename T>
concept bool TextIterator() {
    return ranges::Iterator<T>()
        && Character<ranges::value_type_t<T>>()
        && TextEncoding<encoding_type_t<T>>()
        && TextEncodingState<typename T::state_type>()
        && requires (const T ct) {
               { ct.state() } noexcept
                   -> const typename encoding_type_t<T>::state_type&;
           };
}

/*
 * Text sentinel concept
 */
template<typename T, typename I>
concept bool TextSentinel() {
    return ranges::Sentinel<T, I>()
        && TextIterator<I>();
}

/*
 * Text output iterator concept
 */
template<typename T>
concept bool TextOutputIterator() {
    return ranges::OutputIterator<T, character_type_t<encoding_type_t<T>>>()
        && TextEncoding<encoding_type_t<T>>()
        && TextEncodingState<typename T::state_type>()
        && requires (const T ct) {
               { ct.state() } noexcept
                   -> const typename encoding_type_t<T>::state_type&;
           };
}

/*
 * Text input iterator concept
 */
template<typename T>
concept bool TextInputIterator() {
    return TextIterator<T>()
        && ranges::InputIterator<T>();
}

/*
 * Text forward iterator concept
 */
template<typename T>
concept bool TextForwardIterator() {
    return TextInputIterator<T>()
        && ranges::ForwardIterator<T>();
}

/*
 * Text bidirectional iterator concept
 */
template<typename T>
concept bool TextBidirectionalIterator() {
    return TextForwardIterator<T>()
        && ranges::BidirectionalIterator<T>();
}

/*
 * Text random access iterator concept
 */
template<typename T>
concept bool TextRandomAccessIterator() {
    return TextBidirectionalIterator<T>()
        && ranges::RandomAccessIterator<T>();
}

/*
 * Text view concept
 */
template<typename T>
concept bool TextView() {
    return ranges::View<T>()
        && TextIterator<ranges::iterator_t<T>>()
        && TextEncoding<encoding_type_t<T>>()
        && ranges::View<typename T::view_type>()
        && TextEncodingState<typename T::state_type>()
        && CodeUnitIterator<typename T::code_unit_iterator>()
        && requires (T t, const T ct) {
               { t.base() } noexcept
                   -> typename T::view_type&;
               { ct.base() } noexcept
                   -> const typename T::view_type&;
               { ct.initial_state() } noexcept
                   -> const typename T::state_type&;
           };
}

/*
 * Text input view concept
 */
template<typename T>
concept bool TextInputView() {
    return TextView<T>()
        && TextInputIterator<ranges::iterator_t<T>>();
}

/*
 * Text forward view concept
 */
template<typename T>
concept bool TextForwardView() {
    return TextInputView<T>()
        && TextForwardIterator<ranges::iterator_t<T>>();
}

/*
 * Text bidirectional view concept
 */
template<typename T>
concept bool TextBidirectionalView() {
    return TextForwardView<T>()
        && TextBidirectionalIterator<ranges::iterator_t<T>>();
}

/*
 * Text random access view concept
 */
template<typename T>
concept bool TextRandomAccessView() {
    return TextBidirectionalView<T>()
        && TextRandomAccessIterator<ranges::iterator_t<T>>();
}

} // inline namespace text
} // namespace experimental
} // namespace std

#endif // } TEXT_VIEW_CONCEPTS_HPP
<commit_msg>Eliminate redundancy in Character concept: ranges::Regular subsumes ranges::Copyable.<commit_after>// Copyright (c) 2016, Tom Honermann
//
// This file is distributed under the MIT License. See the accompanying file
// LICENSE.txt or http://www.opensource.org/licenses/mit-license.php for terms
// and conditions.

#ifndef TEXT_VIEW_CONCEPTS_HPP // {
#define TEXT_VIEW_CONCEPTS_HPP

#include <experimental/ranges/concepts>
#include <experimental/ranges/type_traits>
#include <text_view_detail/traits.hpp>
#include <text_view_detail/character_set_id.hpp>

namespace std {
namespace experimental {
inline namespace text {

namespace text_detail {
template<typename T, T t1, T t2>
concept bool SameValue() {
    return t1 == t2;
}

// FIXME: gcc bug 67565, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67565
// FIXME: Compile time performance is negatively impacted by concept definitions
// FIXME: specified with disjunction constraints.  Performance is significantly
// FIXME: improved by rewriting such constraints in terms of constexpr function
// FIXME: or variable templates.  Rewriting the CodeUnit and CodePoint concepts
// FIXME: in terms of is_code_unit_v and is_code_point_v dropped build times
// FIXME: from 5m50s to 2m00s.  Once the performance issues in the compiler are
// FIXME: addressed, is_code_unit_v and is_code_point_v can be removed and
// FIXME: the original CodeUnit and CodePoint concept definitions restored.
template<typename T>
constexpr bool is_code_unit_v =
    std::is_integral<T>::value
    && (std::is_unsigned<T>::value
        || std::is_same<std::remove_cv_t<T>, char>::value
        || std::is_same<std::remove_cv_t<T>, wchar_t>::value);

template<typename T>
constexpr bool is_code_point_v =
    std::is_integral<T>::value
    && (std::is_unsigned<T>::value
        || std::is_same<std::remove_cv_t<T>, char>::value
        || std::is_same<std::remove_cv_t<T>, wchar_t>::value);
} // text_detail namespace

/*
 * Code unit concept
 */
template<typename T>
concept bool CodeUnit() {
    return text_detail::is_code_unit_v<T>;
}

/*
 * Code point concept
 */
template<typename T>
concept bool CodePoint() {
    return text_detail::is_code_point_v<T>;
}

/*
 * Character set concept
 */
template<typename T>
concept bool CharacterSet() {
    return requires () {
               { T::get_name() } noexcept -> const char *;
           }
        && CodePoint<code_point_type_t<T>>();
}

/*
 * Character concept
 */
template<typename T>
concept bool Character() {
    return CharacterSet<character_set_type_t<T>>()
        && ranges::Regular<T>()
        && requires (T t,
                     const T ct,
                     code_point_type_t<character_set_type_t<T>> cp)
           {
               t.set_code_point(cp);
               { ct.get_code_point() } noexcept
                   -> code_point_type_t<character_set_type_t<T>>;
               { ct.get_character_set_id() }
                   -> character_set_id;
           };
}

/*
 * Code unit iterator concept
 */
template<typename T>
concept bool CodeUnitIterator() {
    return ranges::Iterator<T>()
        && CodeUnit<ranges::value_type_t<T>>();
}

/*
 * Code unit output iterator concept
 */
template<typename T, typename V>
concept bool CodeUnitOutputIterator() {
    return ranges::OutputIterator<T, V>()
        && CodeUnit<V>();
}

/*
 * Text encoding state concept
 * These requirements are intended to match the char_traits<T>::state_type
 * requirements described in C++11 [char.traits.typedefs] 21.2.2p4.
 */
template<typename T>
concept bool TextEncodingState() {
    return ranges::Semiregular<T>();
}

/*
 * Text encoding state transition concept
 */
template<typename T>
concept bool TextEncodingStateTransition() {
    return ranges::Semiregular<T>();
}

/*
 * Text encoding concept
 */
template<typename T>
concept bool TextEncoding() {
    return requires () {
               { T::min_code_units } noexcept -> int;
               { T::max_code_units } noexcept -> int;
           }
        && TextEncodingState<typename T::state_type>()
        && TextEncodingStateTransition<typename T::state_transition_type>()
        && CodeUnit<code_unit_type_t<T>>()
        && Character<character_type_t<T>>()
        && requires () {
               { T::initial_state() } noexcept
                   -> const typename T::state_type&;
           };
}

/*
 * Text encoder concept
 */
template<typename T, typename CUIT>
concept bool TextEncoder() {
    return TextEncoding<T>()
        && CodeUnitOutputIterator<CUIT, code_unit_type_t<T>>()
        && requires (
               typename T::state_type &state,
               CUIT &out,
               typename T::state_transition_type stt,
               int &encoded_code_units)
           {
               T::encode_state_transition(state, out, stt, encoded_code_units);
           }
        && requires (
               typename T::state_type &state,
               CUIT &out,
               character_type_t<T> c,
               int &encoded_code_units)
           {
               T::encode(state, out, c, encoded_code_units);
           };
}

/*
 * Text decoder concept
 */
template<typename T, typename CUIT>
concept bool TextDecoder() {
    return TextEncoding<T>()
        && ranges::InputIterator<CUIT>()
        && ranges::ConvertibleTo<ranges::value_type_t<CUIT>,
                                 code_unit_type_t<T>>()
        && requires (
               typename T::state_type &state,
               CUIT &in_next,
               CUIT in_end,
               character_type_t<T> &c,
               int &decoded_code_units)
           {
               { T::decode(state, in_next, in_end, c, decoded_code_units) } -> bool;
           };
}

/*
 * Text forward decoder concept
 */
template<typename T, typename CUIT>
concept bool TextForwardDecoder() {
    return TextDecoder<T, CUIT>()
        && ranges::ForwardIterator<CUIT>();
}

/*
 * Text bidirectional decoder concept
 */
template<typename T, typename CUIT>
concept bool TextBidirectionalDecoder() {
    return TextForwardDecoder<T, CUIT>()
        && ranges::BidirectionalIterator<CUIT>()
        && requires (
               typename T::state_type &state,
               CUIT &in_next,
               CUIT in_end,
               character_type_t<T> &c,
               int &decoded_code_units)
           {
               { T::rdecode(state, in_next, in_end, c, decoded_code_units) } -> bool;
           };
}

/*
 * Text random access decoder concept
 */
template<typename T, typename CUIT>
concept bool TextRandomAccessDecoder() {
    return TextBidirectionalDecoder<T, CUIT>()
        && ranges::RandomAccessIterator<CUIT>()
        && text_detail::SameValue<int, T::min_code_units, T::max_code_units>()
        && std::is_empty<typename T::state_type>::value;
}

/*
 * Text iterator concept
 */
template<typename T>
concept bool TextIterator() {
    return ranges::Iterator<T>()
        && Character<ranges::value_type_t<T>>()
        && TextEncoding<encoding_type_t<T>>()
        && TextEncodingState<typename T::state_type>()
        && requires (const T ct) {
               { ct.state() } noexcept
                   -> const typename encoding_type_t<T>::state_type&;
           };
}

/*
 * Text sentinel concept
 */
template<typename T, typename I>
concept bool TextSentinel() {
    return ranges::Sentinel<T, I>()
        && TextIterator<I>();
}

/*
 * Text output iterator concept
 */
template<typename T>
concept bool TextOutputIterator() {
    return ranges::OutputIterator<T, character_type_t<encoding_type_t<T>>>()
        && TextEncoding<encoding_type_t<T>>()
        && TextEncodingState<typename T::state_type>()
        && requires (const T ct) {
               { ct.state() } noexcept
                   -> const typename encoding_type_t<T>::state_type&;
           };
}

/*
 * Text input iterator concept
 */
template<typename T>
concept bool TextInputIterator() {
    return TextIterator<T>()
        && ranges::InputIterator<T>();
}

/*
 * Text forward iterator concept
 */
template<typename T>
concept bool TextForwardIterator() {
    return TextInputIterator<T>()
        && ranges::ForwardIterator<T>();
}

/*
 * Text bidirectional iterator concept
 */
template<typename T>
concept bool TextBidirectionalIterator() {
    return TextForwardIterator<T>()
        && ranges::BidirectionalIterator<T>();
}

/*
 * Text random access iterator concept
 */
template<typename T>
concept bool TextRandomAccessIterator() {
    return TextBidirectionalIterator<T>()
        && ranges::RandomAccessIterator<T>();
}

/*
 * Text view concept
 */
template<typename T>
concept bool TextView() {
    return ranges::View<T>()
        && TextIterator<ranges::iterator_t<T>>()
        && TextEncoding<encoding_type_t<T>>()
        && ranges::View<typename T::view_type>()
        && TextEncodingState<typename T::state_type>()
        && CodeUnitIterator<typename T::code_unit_iterator>()
        && requires (T t, const T ct) {
               { t.base() } noexcept
                   -> typename T::view_type&;
               { ct.base() } noexcept
                   -> const typename T::view_type&;
               { ct.initial_state() } noexcept
                   -> const typename T::state_type&;
           };
}

/*
 * Text input view concept
 */
template<typename T>
concept bool TextInputView() {
    return TextView<T>()
        && TextInputIterator<ranges::iterator_t<T>>();
}

/*
 * Text forward view concept
 */
template<typename T>
concept bool TextForwardView() {
    return TextInputView<T>()
        && TextForwardIterator<ranges::iterator_t<T>>();
}

/*
 * Text bidirectional view concept
 */
template<typename T>
concept bool TextBidirectionalView() {
    return TextForwardView<T>()
        && TextBidirectionalIterator<ranges::iterator_t<T>>();
}

/*
 * Text random access view concept
 */
template<typename T>
concept bool TextRandomAccessView() {
    return TextBidirectionalView<T>()
        && TextRandomAccessIterator<ranges::iterator_t<T>>();
}

} // inline namespace text
} // namespace experimental
} // namespace std

#endif // } TEXT_VIEW_CONCEPTS_HPP
<|endoftext|>


<commit_before>// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Graphics/Loaders/OBJ.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/Model.hpp>
#include <Nazara/Graphics/Loaders/OBJ/MTLParser.hpp>
#include <Nazara/Graphics/Loaders/OBJ/OBJParser.hpp>
#include <Nazara/Utility/BufferMapper.hpp>
#include <Nazara/Utility/IndexMapper.hpp>
#include <Nazara/Utility/Mesh.hpp>
#include <Nazara/Utility/StaticMesh.hpp>
#include <limits>
#include <memory>
#include <unordered_map>
#include <Nazara/Graphics/Debug.hpp>

namespace
{
	bool IsSupported(const NzString& extension)
	{
		return (extension == "obj");
	}

	nzTernary Check(NzInputStream& stream, const NzModelParameters& parameters)
	{
		NazaraUnused(stream);
		NazaraUnused(parameters);

		return nzTernary_Unknown;
	}

	bool Load(NzModel* model, NzInputStream& stream, const NzModelParameters& parameters)
	{
		NzOBJParser parser(stream);

		if (!parser.Parse())
		{
			NazaraError("OBJ parser failed");
			return false;
		}

		NzMeshRef mesh = NzMesh::New();
		if (!mesh->CreateStatic()) // Ne devrait jamais échouer
		{
			NazaraInternalError("Failed to create mesh");
			return false;
		}

		const NzString* materials = parser.GetMaterials();
		const NzVector4f* positions = parser.GetPositions();
		const NzVector3f* normals = parser.GetNormals();
		const NzVector3f* texCoords = parser.GetTexCoords();

		std::vector<unsigned int> faceIndices;

		const NzOBJParser::Mesh* meshes = parser.GetMeshes();
		unsigned int meshCount = parser.GetMeshCount();
		for (unsigned int i = 0; i < meshCount; ++i)
		{
			unsigned int faceCount = meshes[i].faces.size();
			if (faceCount == 0)
				continue;

			std::vector<unsigned int> indices;
			indices.reserve(faceCount*3); // Pire cas si les faces sont des triangles

			// Bien plus rapide qu'un vector (pour la recherche)
			std::unordered_map<int, std::unordered_map<int, std::unordered_map<int, unsigned int>>> vertices;

			unsigned int vertexCount = 0;
			for (unsigned int j = 0; j < faceCount; ++j)
			{
				unsigned int faceVertexCount = meshes[i].faces[j].vertices.size();
				faceIndices.resize(faceVertexCount);

				for (unsigned int k = 0; k < faceVertexCount; ++k)
				{
					const NzOBJParser::FaceVertex& vertex = meshes[i].faces[j].vertices[k];

					auto& map = vertices[vertex.texCoord][vertex.normal];
					auto it = map.find(vertex.position);
					if (it == map.end())
					{
						faceIndices[k] = vertexCount;
						map[vertex.position] = vertexCount++;
					}
					else
						faceIndices[k] = it->second;
				}

				for (unsigned int k = 1; k < faceVertexCount-1; ++k)
				{
					indices.push_back(faceIndices[0]);
					indices.push_back(faceIndices[k]);
					indices.push_back(faceIndices[k+1]);
				}
			}

			// Création des buffers
			NzIndexBufferRef indexBuffer = NzIndexBuffer::New(vertexCount > std::numeric_limits<nzUInt16>::max(), indices.size(), parameters.mesh.storage, nzBufferUsage_Static);
			NzVertexBufferRef vertexBuffer = NzVertexBuffer::New(NzVertexDeclaration::Get(nzVertexLayout_XYZ_Normal_UV_Tangent), vertexCount, parameters.mesh.storage, nzBufferUsage_Static);

			// Remplissage des indices
			NzIndexMapper indexMapper(indexBuffer, nzBufferAccess_WriteOnly);
			for (unsigned int j = 0; j < indices.size(); ++j)
				indexMapper.Set(j, indices[j]);

			indexMapper.Unmap(); // Pour laisser les autres tâches affecter l'index buffer

			// Remplissage des vertices
			bool hasNormals = true;
			bool hasTexCoords = true;
			NzBufferMapper<NzVertexBuffer> vertexMapper(vertexBuffer, nzBufferAccess_WriteOnly);
			NzMeshVertex* meshVertices = static_cast<NzMeshVertex*>(vertexMapper.GetPointer());
			for (auto& uvIt : vertices)
			{
				for (auto& normalIt : uvIt.second)
				{
					for (auto& positionIt : normalIt.second)
					{
						NzMeshVertex& vertex = meshVertices[positionIt.second];

						const NzVector4f& vec = positions[positionIt.first];
						vertex.position.Set(vec.x, vec.y, vec.z);
						vertex.position *= parameters.mesh.scale/vec.w;

						int index;

						index = normalIt.first; // Normale
						if (index >= 0)
							vertex.normal = normals[index];
						else
							hasNormals = false;

						index = uvIt.first; // Coordonnées de texture
						if (index >= 0)
						{
							const NzVector3f& uvw = texCoords[index];
							vertex.uv.Set(uvw.x, (parameters.mesh.flipUVs) ? 1.f - uvw.y : uvw.y); // Inversion des UVs si demandé
						}
						else
							hasTexCoords = false;
					}
				}
			}

			vertexMapper.Unmap();

			NzStaticMeshRef subMesh = NzStaticMesh::New(mesh);
			if (!subMesh->Create(vertexBuffer))
			{
				NazaraError("Failed to create StaticMesh");
				continue;
			}

			if (parameters.mesh.optimizeIndexBuffers)
				indexBuffer->Optimize();

			subMesh->GenerateAABB();
			subMesh->SetIndexBuffer(indexBuffer);
			subMesh->SetMaterialIndex(meshes[i].material);
			subMesh->SetPrimitiveMode(nzPrimitiveMode_TriangleList);

			// Ce que nous pouvons générer dépend des données à disposition (par exemple les tangentes nécessitent des coordonnées de texture)
			if (hasNormals && hasTexCoords)
				subMesh->GenerateTangents();
			else if (hasTexCoords)
				subMesh->GenerateNormalsAndTangents();
			else
				subMesh->GenerateNormals();

			mesh->AddSubMesh(meshes[i].name + '_' + materials[meshes[i].material], subMesh);
		}
		mesh->SetMaterialCount(parser.GetMaterialCount());

		if (parameters.mesh.center)
			mesh->Recenter();

		model->SetMesh(mesh);

		// On charge les matériaux si demandé
		NzString mtlLib = parser.GetMtlLib();
		if (parameters.loadMaterials && !mtlLib.IsEmpty())
		{
			NzFile file(stream.GetDirectory() + mtlLib);
			if (file.Open(NzFile::ReadOnly | NzFile::Text))
			{
				NzMTLParser materialParser(file);
				if (materialParser.Parse())
				{
					std::unordered_map<NzString, NzMaterialRef> materialCache;
					NzString baseDir = file.GetDirectory();
					for (unsigned int i = 0; i < meshCount; ++i)
					{
						const NzString& matName = materials[meshes[i].material];
						const NzMTLParser::Material* mtlMat = materialParser.GetMaterial(matName);
						if (mtlMat)
						{
							auto it = materialCache.find(matName);
							if (it != materialCache.end())
								model->SetMaterial(meshes[i].material, it->second);
							else
							{
								NzMaterialRef material = NzMaterial::New();
								material->SetShader(parameters.material.shaderName);

								nzUInt8 alphaValue = static_cast<nzUInt8>(mtlMat->alpha*255.f);

								NzColor ambientColor(mtlMat->ambient);
								ambientColor.a = alphaValue;

								NzColor diffuseColor(mtlMat->diffuse);
								diffuseColor.a = alphaValue;

								NzColor specularColor(mtlMat->specular);
								specularColor.a = alphaValue;

								material->SetAmbientColor(ambientColor);
								material->SetDiffuseColor(diffuseColor);
								material->SetSpecularColor(specularColor);
								material->SetShininess(mtlMat->shininess);

								bool hasAlphaMap = false;;
								if (parameters.material.loadAlphaMap && !mtlMat->alphaMap.IsEmpty())
								{
									if (material->SetAlphaMap(baseDir + mtlMat->alphaMap))
										hasAlphaMap = true;
									else
										NazaraWarning("Failed to load alpha map (" + mtlMat->alphaMap + ')');
								}

								if (parameters.material.loadDiffuseMap && !mtlMat->diffuseMap.IsEmpty())
								{
									if (!material->SetDiffuseMap(baseDir + mtlMat->diffuseMap))
										NazaraWarning("Failed to load diffuse map (" + mtlMat->diffuseMap + ')');
								}

								if (parameters.material.loadSpecularMap && !mtlMat->specularMap.IsEmpty())
								{
									if (!material->SetSpecularMap(baseDir + mtlMat->specularMap))
										NazaraWarning("Failed to load specular map (" + mtlMat->specularMap + ')');
								}

								// Si nous avons une alpha map ou des couleurs transparentes,
								// nous devons configurer le matériau pour accepter la transparence au mieux
								if (hasAlphaMap || alphaValue != 255)
								{
									// On paramètre le matériau pour accepter la transparence au mieux
									material->Enable(nzRendererParameter_Blend, true);
									material->Enable(nzRendererParameter_DepthWrite, false);
									material->SetDstBlend(nzBlendFunc_InvSrcAlpha);
									material->SetSrcBlend(nzBlendFunc_SrcAlpha);
								}

								materialCache[matName] = material;

								model->SetMaterial(meshes[i].material, material);
							}
						}
						else
							NazaraWarning("MTL has no material \"" + matName + '"');
					}
				}
				else
					NazaraWarning("MTL parser failed");
			}
			else
				NazaraWarning("Failed to open MTL file (" + file.GetPath() + ')');
		}

		return true;
	}
}

void NzLoaders_OBJ_Register()
{
	NzModelLoader::RegisterLoader(IsSupported, Check, Load);
}

void NzLoaders_OBJ_Unregister()
{
	NzModelLoader::UnregisterLoader(IsSupported, Check, Load);
}
<commit_msg>(OBJLoader) Improved code<commit_after>// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Graphics/Loaders/OBJ.hpp>
#include <Nazara/Core/Algorithm.hpp>
#include <Nazara/Core/ErrorFlags.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/Model.hpp>
#include <Nazara/Graphics/Loaders/OBJ/MTLParser.hpp>
#include <Nazara/Graphics/Loaders/OBJ/OBJParser.hpp>
#include <Nazara/Utility/BufferMapper.hpp>
#include <Nazara/Utility/IndexMapper.hpp>
#include <Nazara/Utility/Mesh.hpp>
#include <Nazara/Utility/StaticMesh.hpp>
#include <limits>
#include <memory>
#include <unordered_map>
#include <Nazara/Graphics/Debug.hpp>

///TODO: N'avoir qu'un seul VertexBuffer communs à tous les meshes

namespace
{
	bool IsSupported(const NzString& extension)
	{
		return (extension == "obj");
	}

	nzTernary Check(NzInputStream& stream, const NzModelParameters& parameters)
	{
		NazaraUnused(stream);
		NazaraUnused(parameters);

		return nzTernary_Unknown;
	}

	bool LoadMaterials(NzModel* model, const NzString& filePath, const NzMaterialParams& parameters, const NzString* materials, const NzOBJParser::Mesh* meshes, unsigned int meshCount)
	{
		NzFile file(filePath);
		if (!file.Open(NzFile::ReadOnly | NzFile::Text))
		{
			NazaraError("Failed to open MTL file (" + file.GetPath() + ')');
			return false;
		}

		NzMTLParser materialParser(file);
		if (!materialParser.Parse())
		{
			NazaraError("MTL parser failed");
			return false;
		}

		std::unordered_map<NzString, NzMaterialRef> materialCache;
		NzString baseDir = file.GetDirectory();
		for (unsigned int i = 0; i < meshCount; ++i)
		{
			const NzString& matName = materials[meshes[i].material];
			const NzMTLParser::Material* mtlMat = materialParser.GetMaterial(matName);
			if (!mtlMat)
			{
				NazaraWarning("MTL has no material \"" + matName + '"');
				continue;
			}

			auto it = materialCache.find(matName);
			if (it == materialCache.end())
			{
				NzMaterialRef material = NzMaterial::New();
				material->SetShader(parameters.shaderName);

				nzUInt8 alphaValue = static_cast<nzUInt8>(mtlMat->alpha*255.f);

				NzColor ambientColor(mtlMat->ambient);
				NzColor diffuseColor(mtlMat->diffuse);
				NzColor specularColor(mtlMat->specular);
				ambientColor.a = alphaValue;
				diffuseColor.a = alphaValue;
				specularColor.a = alphaValue;

				material->SetAmbientColor(ambientColor);
				material->SetDiffuseColor(diffuseColor);
				material->SetSpecularColor(specularColor);
				material->SetShininess(mtlMat->shininess);

				bool isTranslucent = (alphaValue != 255);

				if (parameters.loadAlphaMap && !mtlMat->alphaMap.IsEmpty())
				{
					if (material->SetAlphaMap(baseDir + mtlMat->alphaMap))
						isTranslucent = true; // Une alpha map indique de la transparence
					else
						NazaraWarning("Failed to load alpha map (" + mtlMat->alphaMap + ')');
				}

				if (parameters.loadDiffuseMap && !mtlMat->diffuseMap.IsEmpty())
				{
					if (!material->SetDiffuseMap(baseDir + mtlMat->diffuseMap))
						NazaraWarning("Failed to load diffuse map (" + mtlMat->diffuseMap + ')');
				}

				if (parameters.loadSpecularMap && !mtlMat->specularMap.IsEmpty())
				{
					if (!material->SetSpecularMap(baseDir + mtlMat->specularMap))
						NazaraWarning("Failed to load specular map (" + mtlMat->specularMap + ')');
				}

				// Si nous avons une alpha map ou des couleurs transparentes,
				// nous devons configurer le matériau pour accepter la transparence au mieux
				if (isTranslucent)
				{
					// On paramètre le matériau pour accepter la transparence au mieux
					material->Enable(nzRendererParameter_Blend, true);
					material->Enable(nzRendererParameter_DepthWrite, false);
					material->SetDstBlend(nzBlendFunc_InvSrcAlpha);
					material->SetSrcBlend(nzBlendFunc_SrcAlpha);
				}

				it = materialCache.emplace(matName, std::move(material)).first;
			}

			model->SetMaterial(meshes[i].material, it->second);
		}
	}

	bool Load(NzModel* model, NzInputStream& stream, const NzModelParameters& parameters)
	{
		NzOBJParser parser(stream);
		if (!parser.Parse())
		{
			NazaraError("OBJ parser failed");
			return false;
		}

		NzMeshRef mesh = NzMesh::New();
		if (!mesh->CreateStatic()) // Ne devrait jamais échouer
		{
			NazaraInternalError("Failed to create mesh");
			return false;
		}

		const NzString* materials = parser.GetMaterials();
		const NzVector4f* positions = parser.GetPositions();
		const NzVector3f* normals = parser.GetNormals();
		const NzVector3f* texCoords = parser.GetTexCoords();

		const NzOBJParser::Mesh* meshes = parser.GetMeshes();
		unsigned int meshCount = parser.GetMeshCount();

		NazaraAssert(materials != nullptr && positions != nullptr && normals != nullptr &&
		             texCoords != nullptr && meshes != nullptr && meshCount > 0,
					 "Invalid OBJParser output");

		// Un conteneur temporaire pour contenir les indices de face avant triangulation
		std::vector<unsigned int> faceIndices(3); // Comme il y aura au moins trois sommets
		for (unsigned int i = 0; i < meshCount; ++i)
		{
			unsigned int faceCount = meshes[i].faces.size();
			if (faceCount == 0)
				continue;

			std::vector<unsigned int> indices;
			indices.reserve(faceCount*3); // Pire cas si les faces sont des triangles

			// Afin d'utiliser OBJParser::FaceVertex comme clé dans un unordered_map,
			// nous devons fournir un foncteur de hash ainsi qu'un foncteur de comparaison

			// Hash
			struct FaceVertexHasher
			{
				std::size_t operator()(const NzOBJParser::FaceVertex& o) const
				{
					std::size_t seed = 0;
					NzHashCombine(seed, o.normal);
					NzHashCombine(seed, o.position);
					NzHashCombine(seed, o.texCoord);

					return seed;
				}
			};

			// Comparaison
			struct FaceVertexComparator
			{
				bool operator()(const NzOBJParser::FaceVertex& lhs, const NzOBJParser::FaceVertex& rhs) const
				{
					return lhs.normal == rhs.normal &&
					       lhs.position == rhs.position &&
					       lhs.texCoord == rhs.texCoord;
				}
			};

			std::unordered_map<NzOBJParser::FaceVertex, unsigned int, FaceVertexHasher, FaceVertexComparator> vertices;

			unsigned int vertexCount = 0;
			for (unsigned int j = 0; j < faceCount; ++j)
			{
				unsigned int faceVertexCount = meshes[i].faces[j].vertices.size();
				faceIndices.resize(faceVertexCount);

				for (unsigned int k = 0; k < faceVertexCount; ++k)
				{
					const NzOBJParser::FaceVertex& vertex = meshes[i].faces[j].vertices[k];

					auto it = vertices.find(vertex);
					if (it == vertices.end())
						it = vertices.emplace(vertex, vertexCount++).first;

					faceIndices[k] = it->second;
				}

				for (unsigned int k = 1; k < faceVertexCount-1; ++k)
				{
					indices.push_back(faceIndices[0]);
					indices.push_back(faceIndices[k]);
					indices.push_back(faceIndices[k+1]);
				}
			}

			// Création des buffers
			NzIndexBufferRef indexBuffer = NzIndexBuffer::New(vertexCount > std::numeric_limits<nzUInt16>::max(), indices.size(), parameters.mesh.storage, nzBufferUsage_Static);
			NzVertexBufferRef vertexBuffer = NzVertexBuffer::New(NzVertexDeclaration::Get(nzVertexLayout_XYZ_Normal_UV_Tangent), vertexCount, parameters.mesh.storage, nzBufferUsage_Static);

			// Remplissage des indices
			NzIndexMapper indexMapper(indexBuffer, nzBufferAccess_WriteOnly);
			for (unsigned int j = 0; j < indices.size(); ++j)
				indexMapper.Set(j, indices[j]);

			indexMapper.Unmap(); // Pour laisser les autres tâches affecter l'index buffer

			// Remplissage des vertices
			bool hasNormals = true;
			bool hasTexCoords = true;
			NzBufferMapper<NzVertexBuffer> vertexMapper(vertexBuffer, nzBufferAccess_WriteOnly);
			NzMeshVertex* meshVertices = static_cast<NzMeshVertex*>(vertexMapper.GetPointer());
			for (auto& vertexPair : vertices)
			{
				const NzOBJParser::FaceVertex& vertexIndices = vertexPair.first;
				unsigned int index = vertexPair.second;

				NzMeshVertex& vertex = meshVertices[index];

				const NzVector4f& vec = positions[vertexIndices.position];
				vertex.position.Set(vec.x, vec.y, vec.z);
				vertex.position *= parameters.mesh.scale/vec.w;

				if (vertexIndices.normal >= 0)
					vertex.normal = normals[vertexIndices.normal];
				else
					hasNormals = false;

				if (vertexIndices.texCoord >= 0)
				{
					const NzVector3f& uvw = texCoords[vertexIndices.texCoord];
					vertex.uv.Set(uvw.x, (parameters.mesh.flipUVs) ? 1.f - uvw.y : uvw.y); // Inversion des UVs si demandé
				}
				else
					hasTexCoords = false;
			}

			vertexMapper.Unmap();

			NzStaticMeshRef subMesh = NzStaticMesh::New(mesh);
			if (!subMesh->Create(vertexBuffer))
			{
				NazaraError("Failed to create StaticMesh");
				continue;
			}

			if (parameters.mesh.optimizeIndexBuffers)
				indexBuffer->Optimize();

			subMesh->GenerateAABB();
			subMesh->SetIndexBuffer(indexBuffer);
			subMesh->SetMaterialIndex(meshes[i].material);
			subMesh->SetPrimitiveMode(nzPrimitiveMode_TriangleList);

			// Ce que nous pouvons générer dépend des données à disposition (par exemple les tangentes nécessitent des coordonnées de texture)
			if (hasNormals && hasTexCoords)
				subMesh->GenerateTangents();
			else if (hasTexCoords)
				subMesh->GenerateNormalsAndTangents();
			else
				subMesh->GenerateNormals();

			mesh->AddSubMesh(meshes[i].name + '_' + materials[meshes[i].material], subMesh);
		}
		mesh->SetMaterialCount(parser.GetMaterialCount());

		if (parameters.mesh.center)
			mesh->Recenter();

		model->SetMesh(mesh);

		// On charge les matériaux si demandé
		NzString mtlLib = parser.GetMtlLib();
		if (parameters.loadMaterials && !mtlLib.IsEmpty())
		{
			NzErrorFlags flags(nzErrorFlag_ThrowExceptionDisabled);
			LoadMaterials(model, stream.GetDirectory() + mtlLib, parameters.material, materials, meshes, meshCount);
		}

		return true;
	}
}

void NzLoaders_OBJ_Register()
{
	NzModelLoader::RegisterLoader(IsSupported, Check, Load);
}

void NzLoaders_OBJ_Unregister()
{
	NzModelLoader::UnregisterLoader(IsSupported, Check, Load);
}
<|endoftext|>


<commit_before>#ifndef DUNE_STUFF_GRID_PROVIDER_CUBE_HH
#define DUNE_STUFF_GRID_PROVIDER_CUBE_HH

#ifdef HAVE_CMAKE_CONFIG
 #include "cmake_config.h"
#elif defined (HAVE_CONFIG_H)
 #include <config.h>
#endif // ifdef HAVE_CMAKE_CONFIG

#ifdef HAVE_DUNE_GRID

// system
#include <sstream>
#include <type_traits>
#include <boost/assign/list_of.hpp>

// dune-common
#include <dune/common/parametertree.hh>
#include <dune/common/shared_ptr.hh>
#include <dune/common/exceptions.hh>
#include <dune/common/fvector.hh>

// dune-grid
#include <dune/grid/utility/structuredgridfactory.hh>
#include <dune/grid/yaspgrid.hh>
#ifdef HAVE_ALUGRID
#include <dune/grid/alugrid.hh>
#endif
#include <dune/grid/sgrid.hh>
#include <dune/grid/common/mcmgmapper.hh>
#include <dune/grid/io/file/vtk/vtkwriter.hh>

namespace Dune {

namespace Stuff {

namespace Grid {

namespace Provider {

/**
 *  \brief  Creates a grid of a cube in various dimensions.
 *
 *          Default implementation using the Dune::StructuredGridFactory to create a grid of a cube in 1, 2 or 3
 *          dimensions. Tested with
 *

 \c YASPGRID, \c variant 1, dim = 1, 2, 3,
 *
 \c SGRID, \c variant 1, dim = 1, 2, 3,
 *
 \c ALUGRID_SIMPLEX, \c variant 2, dim = 2, 3,
 *
 \c ALUGRID_CONFORM, \c variant 2, dim = 2, 2 and
 *
 \c ALUGRID_CUBE, \c variant 1, dim = 2, 3.

 *  \tparam GridImp
 *          Type of the underlying grid.
 *  \tparam variant
 *          Type of the codim 0 elements:
 *

\c 1: cubes
 *
2: simplices

 **/
template< typename GridImp, int variant >
class GenericCube
{
public:
  //! Type of the provided grid.
  typedef GridImp GridType;

private:
  typedef typename GridType::LeafGridView GridViewType;

public:
  //! Dimension of the provided grid.
  static const unsigned int dim = GridType::dimension;

  //! Type of the grids coordinates.
  typedef Dune::FieldVector< typename GridType::ctype, dim > CoordinateType;

  //! Unique identifier: \c stuff.grid.provider.cube
  static const std::string id;

  /**
   *  \brief      Creates a cube.
   *  \param[in]  paramTree
   *              A Dune::ParameterTree containing
   *

 the following keys directly or
   *
 a subtree named Cube::id, containing the following keys. If a subtree is present, it is always selected. Also it is solely selceted, so that all keys in the supertree are ignored.

   *              The actual keys are:
   *

 \c lowerLeft: \a double that is used as a lower left corner in each dimension.
   *
 \c upperRight: \a double that is used as an upper right corner in each dimension.
   *
 \c numElements.D \a int to denote the number of elements in direction of dimension D (has to be given for each dimension seperately).
   *
 \c level: \a int level of refinement. If given, overrides numElements and creates \f$ 2^level \f$ elements per dimension.
   *

   **/
  GenericCube(const Dune::ParameterTree paramTree)
    : lowerLeft_(0.0),
      upperRight_(1.0)
  {
    // select subtree (if necessary)
    Dune::ParameterTree paramTree_ = paramTree;
    if (paramTree.hasSub(id))
      paramTree_ = paramTree.sub(id);
    // get outer bounds
    const double lowerLeft = paramTree_.get("lowerLeft", 0.0);
    const double upperRight = paramTree_.get("upperRight", 1.0);
    assert(lowerLeft < upperRight);
    lowerLeft_ = lowerLeft;
    upperRight_ = upperRight;
    // get number of elements per dim
    if (paramTree.hasKey("level"))
      std::fill(numElements_.begin(), numElements_.end(), std::pow(2, paramTree.get("level", 1)));
    else {
      for (unsigned int d = 0; d < dim; ++d) {
        std::stringstream s;
        s << "numElements." << d;
        numElements_[d] = paramTree.get(s.str(), 1);
      }
    }
    buildGrid();
  } // Cube(const Dune::ParameterTree& paramTree)

  /**
   *  \brief      Creates a cube.
   *  \param[in]  lowerLeft
   *              A vector that is used as a lower left corner.
   *  \param[in]  upperRight
   *              A vector that is used as a upper right corner.
   *  \param[in]  level (optional)
   *              Level of refinement (see constructor for details).
   **/
  GenericCube(const CoordinateType& lowerLeft, const CoordinateType& upperRight, const int level = 1)
    : lowerLeft_(lowerLeft),
      upperRight_(upperRight)
  {
    std::fill(numElements_.begin(), numElements_.end(), std::pow(2, level));
    buildGrid();
  }

  /**
   *  \brief      Creates a cube.
   *  \param[in]  lowerLeft
   *              A double that is used as a lower left corner in each dimension.
   *  \param[in]  upperRight
   *              A double that is used as a upper right corner in each dimension.
   *  \param[in]  level (optional)
   *              Level of refinement (see constructor for details).
   **/
  GenericCube(const double lowerLeft, const double upperRight, const int level = 1)
    : lowerLeft_(lowerLeft),
      upperRight_(upperRight)
  {
    std::fill(numElements_.begin(), numElements_.end(), std::pow(2, level));
    buildGrid();
  }

  /**
    \brief      Creates a cube. This signature allows to prescribe anisotopic refinement
    \param[in]  lowerLeft
                A double that is used as a lower left corner in each dimension.
    \param[in]  upperRight
                A double that is used as a upper right corner in each dimension.
    \param[in]  elements_per_dim number of elements in each dimension.
                can contain 0 to dim elements (missing dimension are initialized to 1)
    \tparam Coord anything that CoordinateType allows to copy construct from
    \tparam ContainerType some sequence type that functions with std::begin/end
    \tparam T an unsigned integral Type
    **/
  template < class Coord, class ContainerType  >
  GenericCube(const Coord lowerLeft, const Coord upperRight,
       const ContainerType elements_per_dim = boost::assign::list_of<typename ContainerType::value_type>().repeat(GridType::dimensionworld,typename ContainerType::value_type(1)) )
    : lowerLeft_(lowerLeft),
      upperRight_(upperRight)
  {
    static_assert(std::is_unsigned<typename ContainerType::value_type>::value
        && std::is_integral<typename ContainerType::value_type>::value,
        "only unsigned integral number of elements per dimension allowed");
    //base init in case input is shorter
    std::fill(numElements_.begin(), numElements_.end(), 1);
    std::copy(elements_per_dim.begin(), elements_per_dim.end(), numElements_.begin());
    buildGrid();
  }

  /**
    \brief  Provides access to the created grid.
    \return Reference to the grid.
    **/
  GridType& grid()
  {
    return *grid_;
  }

  /**
   *  \brief  Provides const access to the created grid.
   *  \return Reference to the grid.
   **/
  const GridType& grid() const
  {
    return *grid_;
  }

  //! access to shared ptr
  Dune::shared_ptr< GridType > gridPtr()
  {
    return grid_;
  }

  const Dune::shared_ptr< const GridType > gridPtr() const
  {
    return grid_;
  }

  const CoordinateType& lowerLeft() const
  {
    return lowerLeft_;
  }

  const CoordinateType& upperRight() const
  {
    return upperRight_;
  }

  /**
   *  \brief      Visualizes the grid using Dune::VTKWriter.
   *  \param[in]  filename
   **/
  void visualize(const std::string filename = id + ".grid") const
  {
    // vtk writer
    GridViewType gridView = grid().leafView();
    Dune::VTKWriter< GridViewType > vtkwriter(gridView);
    // boundary id
    std::vector< double > boundaryId = generateBoundaryIdVisualization(gridView);
    vtkwriter.addCellData(boundaryId, "boundaryId");
    // codim 0 entity id
    std::vector< double > entityId = generateEntityVisualization(gridView);
    vtkwriter.addCellData(entityId, "entityId");
    // write
    vtkwriter.write(filename, Dune::VTK::ascii);
  } // void visualize(const std::string filename = id + ".grid") const

private:
  void buildGrid()
  {
    static_assert(variant >= 1 && variant <= 2, "only variant 1 and 2 are valid");
    switch (variant) {
      case 1:
        grid_ = Dune::StructuredGridFactory< GridType >::createCubeGrid(lowerLeft_, upperRight_, numElements_);
        break;
      case 2:
    default:
        grid_ = Dune::StructuredGridFactory< GridType >::createSimplexGrid(lowerLeft_, upperRight_, numElements_);
        break;
    }
  } // void buildGrid(const CoordinateType& lowerLeft, const CoordinateType& upperRight)

  std::vector< double > generateBoundaryIdVisualization(const GridViewType& gridView) const
  {
    typedef typename GridViewType::IndexSet::IndexType IndexType;
    typedef typename GridViewType::template Codim< 0 >::Entity EntityType;
    std::vector< double > data(gridView.indexSet().size(0));
    // walk the grid
    for (typename GridViewType::template Codim< 0 >::Iterator it = gridView.template begin< 0 >();
         it != gridView.template end< 0 >();
         ++it)
    {
      const EntityType& entity = *it;
      const IndexType& index = gridView.indexSet().index(entity);
      data[index] = 0.0;
      int numberOfBoundarySegments = 0;
      bool isOnBoundary = false;
      for (typename GridViewType::IntersectionIterator intersectionIt = gridView.ibegin(entity);
           intersectionIt != gridView.iend(entity);
           ++intersectionIt) {
        if (!intersectionIt->neighbor() && intersectionIt->boundary()){
          isOnBoundary = true;
          numberOfBoundarySegments += 1;
          data[index] += double(intersectionIt->boundaryId());
        }
      }
      if (isOnBoundary) {
        data[index] /= double(numberOfBoundarySegments);
      }
    } // walk the grid
    return data;
  } // std::vector< double > generateBoundaryIdVisualization(const GridViewType& gridView) const

  std::vector< double > generateEntityVisualization(const GridViewType& gridView) const
  {
    typedef typename GridViewType::IndexSet::IndexType IndexType;
    typedef typename GridViewType::template Codim< 0 >::Entity EntityType;
    std::vector< double > data(gridView.indexSet().size(0));
    // walk the grid
    for (typename GridViewType::template Codim< 0 >::Iterator it = gridView.template begin< 0 >();
         it != gridView.template end< 0 >();
         ++it)
    {
      const EntityType& entity = *it;
      const IndexType& index = gridView.indexSet().index(entity);
      data[index] = double(index);
    } // walk the grid
    return data;
  } // std::vector< double > generateEntityVisualization(const GridViewType& gridView) const

  CoordinateType lowerLeft_;
  CoordinateType upperRight_;
  Dune::array< unsigned int, dim > numElements_;
  Dune::shared_ptr< GridType > grid_;
}; // class GenericCube

template< typename GridImp, int variant >
const std::string GenericCube< GridImp, variant >::id = "stuff.grid.provider.cube";

template< typename GridType >
struct ElementVariant {
  static const int id = 2;
};

template< int dim >
struct ElementVariant< Dune::YaspGrid< dim > > {
  static const int id = 1;
};

template< int dim >
struct ElementVariant< Dune::SGrid< dim, dim > > {
  static const int id = 1;
};

#ifdef HAVE_ALUGRID
template< int dim >
struct ElementVariant< Dune::ALUCubeGrid< dim, dim > > {
  static const int id = 1;
};
#endif

// default implementation of a cube for any grid
// tested for
// dim = 2
//  ALUGRID_SIMPLEX, variant 2
//  ALUGRID_CONFORM, variant 2
// dim = 3
//  ALUGRID_SIMPLEX, variant 2
#if defined HAVE_CONFIG_H || defined HAVE_CMAKE_CONFIG
template< class GridType = Dune::GridSelector::GridType >
#else
template< class GridType >
#endif
class Cube
  : public GenericCube< GridType, ElementVariant<GridType>::id >
{
private:
  typedef GenericCube< GridType, ElementVariant<GridType>::id > BaseType;

public:
  typedef typename BaseType::CoordinateType CoordinateType;

  Cube(const Dune::ParameterTree& paramTree)
    : BaseType(paramTree)
  {}

  Cube(const CoordinateType& lowerLeft, const CoordinateType& upperRight, const int level = 1)
    : BaseType(lowerLeft, upperRight, level)
  {}

  Cube(const double lowerLeft, const double upperRight, const int level = 1)
    : BaseType(lowerLeft, upperRight, level)
  {}

  template < class Coord, class ContainerType  >
  Cube(const Coord lowerLeft, const Coord upperRight,
       const ContainerType elements_per_dim = boost::assign::list_of<typename ContainerType::value_type>().repeat(GridType::dimensionworld,typename ContainerType::value_type(1)) )
    : BaseType(lowerLeft, upperRight, elements_per_dim)
  {}
}; // class Cube

#if defined HAVE_CONFIG_H || defined HAVE_CMAKE_CONFIG
template< class GridType = Dune::GridSelector::GridType >
#else
template< class GridType >
#endif
class UnitCube
  : public Cube< GridType >
{
private:
  typedef Cube< GridType > BaseType;

public:
  UnitCube(const Dune::ParameterTree& paramTree)
    : BaseType(0.0, 1.0, paramTree.get("level", 1))
  {}

  UnitCube(const int level = 1)
    : BaseType(0.0, 1.0, level)
  {}
}; // class UnitCube

} // namespace Provider

} // namespace Grid

} // namespace Stuff

} // namespace Dune

#endif // HAVE_DUNE_GRID

#endif // DUNE_STUFF_GRID_PROVIDER_CUBE_HH
<commit_msg>[grid.provider.cube] derived from new interface<commit_after>#ifndef DUNE_STUFF_GRID_PROVIDER_CUBE_HH
#define DUNE_STUFF_GRID_PROVIDER_CUBE_HH

#ifdef HAVE_CMAKE_CONFIG
 #include "cmake_config.h"
#elif defined (HAVE_CONFIG_H)
 #include <config.h>
#endif // ifdef HAVE_CMAKE_CONFIG

#ifdef HAVE_DUNE_GRID

// system
#include <sstream>
#include <type_traits>
#include <boost/assign/list_of.hpp>

// dune-common
#include <dune/common/parametertree.hh>
#include <dune/common/shared_ptr.hh>
#include <dune/common/exceptions.hh>
#include <dune/common/fvector.hh>

// dune-grid
#include <dune/grid/utility/structuredgridfactory.hh>
#include <dune/grid/yaspgrid.hh>
#ifdef HAVE_ALUGRID
#include <dune/grid/alugrid.hh>
#endif
#include <dune/grid/sgrid.hh>
#include <dune/grid/common/mcmgmapper.hh>
#include <dune/grid/io/file/vtk/vtkwriter.hh>

// local
#include "interface.hh"

namespace Dune {

namespace Stuff {

namespace Grid {

namespace Provider {

/**
 *  \brief  Creates a grid of a cube in various dimensions.
 *
 *          Default implementation using the Dune::StructuredGridFactory to create a grid of a cube in 1, 2 or 3
 *          dimensions. Tested with
 *

 \c YASPGRID, \c variant 1, dim = 1, 2, 3,
 *
 \c SGRID, \c variant 1, dim = 1, 2, 3,
 *
 \c ALUGRID_SIMPLEX, \c variant 2, dim = 2, 3,
 *
 \c ALUGRID_CONFORM, \c variant 2, dim = 2, 2 and
 *
 \c ALUGRID_CUBE, \c variant 1, dim = 2, 3.

 *  \tparam GridImp
 *          Type of the underlying grid.
 *  \tparam variant
 *          Type of the codim 0 elements:
 *

\c 1: cubes
 *
2: simplices

 **/
template< typename GridImp, int variant >
class GenericCube
  : public Interface< GridImp >
{
public:
  //! Type of the provided grid.
  typedef GridImp GridType;

private:
  typedef typename GridType::LeafGridView GridViewType;

public:
  //! Dimension of the provided grid.
  static const unsigned int dim = GridType::dimension;

  //! Type of the grids coordinates.
  typedef Dune::FieldVector< typename GridType::ctype, dim > CoordinateType;

  //! Unique identifier: \c stuff.grid.provider.cube
  static const std::string static_id;

  /**
   *  \brief      Creates a cube.
   *  \param[in]  paramTree
   *              A Dune::ParameterTree containing
   *

 the following keys directly or
   *
 a subtree named Cube::id, containing the following keys. If a subtree is present, it is always selected. Also it is solely selceted, so that all keys in the supertree are ignored.

   *              The actual keys are:
   *

 \c lowerLeft: \a double that is used as a lower left corner in each dimension.
   *
 \c upperRight: \a double that is used as an upper right corner in each dimension.
   *
 \c numElements.D \a int to denote the number of elements in direction of dimension D (has to be given for each dimension seperately).
   *
 \c level: \a int level of refinement. If given, overrides numElements and creates \f$ 2^level \f$ elements per dimension.
   *

   **/
  GenericCube(const Dune::ParameterTree paramTree)
    : lowerLeft_(0.0),
      upperRight_(1.0)
  {
    // select subtree (if necessary)
    Dune::ParameterTree paramTree_ = paramTree;
    if (paramTree.hasSub(static_id))
      paramTree_ = paramTree.sub(static_id);
    // get outer bounds
    const double lowerLeft = paramTree_.get("lowerLeft", 0.0);
    const double upperRight = paramTree_.get("upperRight", 1.0);
    assert(lowerLeft < upperRight);
    lowerLeft_ = lowerLeft;
    upperRight_ = upperRight;
    // get number of elements per dim
    if (paramTree.hasKey("level"))
      std::fill(numElements_.begin(), numElements_.end(), std::pow(2, paramTree.get("level", 1)));
    else {
      for (unsigned int d = 0; d < dim; ++d) {
        std::stringstream s;
        s << "numElements." << d;
        numElements_[d] = paramTree.get(s.str(), 1);
      }
    }
    buildGrid();
  } // Cube(const Dune::ParameterTree& paramTree)

  /**
   *  \brief      Creates a cube.
   *  \param[in]  lowerLeft
   *              A vector that is used as a lower left corner.
   *  \param[in]  upperRight
   *              A vector that is used as a upper right corner.
   *  \param[in]  level (optional)
   *              Level of refinement (see constructor for details).
   **/
  GenericCube(const CoordinateType& lowerLeft, const CoordinateType& upperRight, const int level = 1)
    : lowerLeft_(lowerLeft),
      upperRight_(upperRight)
  {
    std::fill(numElements_.begin(), numElements_.end(), std::pow(2, level));
    buildGrid();
  }

  /**
   *  \brief      Creates a cube.
   *  \param[in]  lowerLeft
   *              A double that is used as a lower left corner in each dimension.
   *  \param[in]  upperRight
   *              A double that is used as a upper right corner in each dimension.
   *  \param[in]  level (optional)
   *              Level of refinement (see constructor for details).
   **/
  GenericCube(const double lowerLeft, const double upperRight, const int level = 1)
    : lowerLeft_(lowerLeft),
      upperRight_(upperRight)
  {
    std::fill(numElements_.begin(), numElements_.end(), std::pow(2, level));
    buildGrid();
  }

  /**
    \brief      Creates a cube. This signature allows to prescribe anisotopic refinement
    \param[in]  lowerLeft
                A double that is used as a lower left corner in each dimension.
    \param[in]  upperRight
                A double that is used as a upper right corner in each dimension.
    \param[in]  elements_per_dim number of elements in each dimension.
                can contain 0 to dim elements (missing dimension are initialized to 1)
    \tparam Coord anything that CoordinateType allows to copy construct from
    \tparam ContainerType some sequence type that functions with std::begin/end
    \tparam T an unsigned integral Type
    **/
  template < class Coord, class ContainerType  >
  GenericCube(const Coord lowerLeft, const Coord upperRight,
       const ContainerType elements_per_dim = boost::assign::list_of<typename ContainerType::value_type>().repeat(GridType::dimensionworld,typename ContainerType::value_type(1)) )
    : lowerLeft_(lowerLeft),
      upperRight_(upperRight)
  {
    static_assert(std::is_unsigned<typename ContainerType::value_type>::value
        && std::is_integral<typename ContainerType::value_type>::value,
        "only unsigned integral number of elements per dimension allowed");
    //base init in case input is shorter
    std::fill(numElements_.begin(), numElements_.end(), 1);
    std::copy(elements_per_dim.begin(), elements_per_dim.end(), numElements_.begin());
    buildGrid();
  }

  virtual std::string id() const
  {
    return static_id;
  }

  /**
    \brief  Provides access to the created grid.
    \return Reference to the grid.
    **/
  virtual GridType& grid()
  {
    return *grid_;
  }

  /**
   *  \brief  Provides const access to the created grid.
   *  \return Reference to the grid.
   **/
  virtual const GridType& grid() const
  {
    return *grid_;
  }

  //! access to shared ptr
  virtual Dune::shared_ptr< GridType > gridPtr()
  {
    return grid_;
  }

  virtual const Dune::shared_ptr< const GridType > gridPtr() const
  {
    return grid_;
  }

  const CoordinateType& lowerLeft() const
  {
    return lowerLeft_;
  }

  const CoordinateType& upperRight() const
  {
    return upperRight_;
  }

  /**
   *  \brief      Visualizes the grid using Dune::VTKWriter.
   *  \param[in]  filename
   **/
  virtual void visualize(const std::string filename = id + ".grid") const
  {
    // vtk writer
    GridViewType gridView = grid().leafView();
    Dune::VTKWriter< GridViewType > vtkwriter(gridView);
    // boundary id
    std::vector< double > boundaryId = generateBoundaryIdVisualization(gridView);
    vtkwriter.addCellData(boundaryId, "boundaryId");
    // codim 0 entity id
    std::vector< double > entityId = generateEntityVisualization(gridView);
    vtkwriter.addCellData(entityId, "entityId");
    // write
    vtkwriter.write(filename, Dune::VTK::ascii);
  } // void visualize(const std::string filename = id + ".grid") const

private:
  void buildGrid()
  {
    static_assert(variant >= 1 && variant <= 2, "only variant 1 and 2 are valid");
    switch (variant) {
      case 1:
        grid_ = Dune::StructuredGridFactory< GridType >::createCubeGrid(lowerLeft_, upperRight_, numElements_);
        break;
      case 2:
    default:
        grid_ = Dune::StructuredGridFactory< GridType >::createSimplexGrid(lowerLeft_, upperRight_, numElements_);
        break;
    }
  } // void buildGrid(const CoordinateType& lowerLeft, const CoordinateType& upperRight)

  std::vector< double > generateBoundaryIdVisualization(const GridViewType& gridView) const
  {
    typedef typename GridViewType::IndexSet::IndexType IndexType;
    typedef typename GridViewType::template Codim< 0 >::Entity EntityType;
    std::vector< double > data(gridView.indexSet().size(0));
    // walk the grid
    for (typename GridViewType::template Codim< 0 >::Iterator it = gridView.template begin< 0 >();
         it != gridView.template end< 0 >();
         ++it)
    {
      const EntityType& entity = *it;
      const IndexType& index = gridView.indexSet().index(entity);
      data[index] = 0.0;
      int numberOfBoundarySegments = 0;
      bool isOnBoundary = false;
      for (typename GridViewType::IntersectionIterator intersectionIt = gridView.ibegin(entity);
           intersectionIt != gridView.iend(entity);
           ++intersectionIt) {
        if (!intersectionIt->neighbor() && intersectionIt->boundary()){
          isOnBoundary = true;
          numberOfBoundarySegments += 1;
          data[index] += double(intersectionIt->boundaryId());
        }
      }
      if (isOnBoundary) {
        data[index] /= double(numberOfBoundarySegments);
      }
    } // walk the grid
    return data;
  } // std::vector< double > generateBoundaryIdVisualization(const GridViewType& gridView) const

  std::vector< double > generateEntityVisualization(const GridViewType& gridView) const
  {
    typedef typename GridViewType::IndexSet::IndexType IndexType;
    typedef typename GridViewType::template Codim< 0 >::Entity EntityType;
    std::vector< double > data(gridView.indexSet().size(0));
    // walk the grid
    for (typename GridViewType::template Codim< 0 >::Iterator it = gridView.template begin< 0 >();
         it != gridView.template end< 0 >();
         ++it)
    {
      const EntityType& entity = *it;
      const IndexType& index = gridView.indexSet().index(entity);
      data[index] = double(index);
    } // walk the grid
    return data;
  } // std::vector< double > generateEntityVisualization(const GridViewType& gridView) const

  CoordinateType lowerLeft_;
  CoordinateType upperRight_;
  Dune::array< unsigned int, dim > numElements_;
  Dune::shared_ptr< GridType > grid_;
}; // class GenericCube

template< typename GridImp, int variant >
const std::string GenericCube< GridImp, variant >::static_id = "stuff.grid.provider.cube";

template< typename GridType >
struct ElementVariant {
  static const int id = 2;
};

template< int dim >
struct ElementVariant< Dune::YaspGrid< dim > > {
  static const int id = 1;
};

template< int dim >
struct ElementVariant< Dune::SGrid< dim, dim > > {
  static const int id = 1;
};

#ifdef HAVE_ALUGRID
template< int dim >
struct ElementVariant< Dune::ALUCubeGrid< dim, dim > > {
  static const int id = 1;
};
#endif

// default implementation of a cube for any grid
// tested for
// dim = 2
//  ALUGRID_SIMPLEX, variant 2
//  ALUGRID_CONFORM, variant 2
// dim = 3
//  ALUGRID_SIMPLEX, variant 2
#if defined HAVE_CONFIG_H || defined HAVE_CMAKE_CONFIG
template< class GridType = Dune::GridSelector::GridType >
#else
template< class GridType >
#endif
class Cube
  : public GenericCube< GridType, ElementVariant<GridType>::id >
{
private:
  typedef GenericCube< GridType, ElementVariant<GridType>::id > BaseType;

public:
  typedef typename BaseType::CoordinateType CoordinateType;

  Cube(const Dune::ParameterTree& paramTree)
    : BaseType(paramTree)
  {}

  Cube(const CoordinateType& lowerLeft, const CoordinateType& upperRight, const int level = 1)
    : BaseType(lowerLeft, upperRight, level)
  {}

  Cube(const double lowerLeft, const double upperRight, const int level = 1)
    : BaseType(lowerLeft, upperRight, level)
  {}

  template < class Coord, class ContainerType  >
  Cube(const Coord lowerLeft, const Coord upperRight,
       const ContainerType elements_per_dim = boost::assign::list_of<typename ContainerType::value_type>().repeat(GridType::dimensionworld,typename ContainerType::value_type(1)) )
    : BaseType(lowerLeft, upperRight, elements_per_dim)
  {}
}; // class Cube

#if defined HAVE_CONFIG_H || defined HAVE_CMAKE_CONFIG
template< class GridType = Dune::GridSelector::GridType >
#else
template< class GridType >
#endif
class UnitCube
  : public Cube< GridType >
{
private:
  typedef Cube< GridType > BaseType;

public:
  UnitCube(const Dune::ParameterTree& paramTree)
    : BaseType(0.0, 1.0, paramTree.get("level", 1))
  {}

  UnitCube(const int level = 1)
    : BaseType(0.0, 1.0, level)
  {}
}; // class UnitCube

} // namespace Provider

} // namespace Grid

} // namespace Stuff

} // namespace Dune

#endif // HAVE_DUNE_GRID

#endif // DUNE_STUFF_GRID_PROVIDER_CUBE_HH
<|endoftext|>