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

#include <QApplication>
#include <QCommandLineParser>
#include <QDir>
#include <QFileInfo>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
#include <QStandardPaths>
#include <QSysInfo>
#include "Code/CaptureContext.h"
#include "Code/QRDUtils.h"
#include "Code/Resources.h"
#include "Code/pyrenderdoc/PythonContext.h"
#include "Windows/Dialogs/CrashDialog.h"
#include "Windows/MainWindow.h"
#include "version.h"

#if defined(Q_OS_WIN32)
extern "C" {
_declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
}
#endif

REPLAY_PROGRAM_MARKER()

void sharedLogOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
  LogType logtype = LogType::Comment;

  switch(type)
  {
    case QtDebugMsg: logtype = LogType::Debug; break;
    case QtInfoMsg: logtype = LogType::Comment; break;
    case QtWarningMsg: logtype = LogType::Warning; break;
    case QtCriticalMsg: logtype = LogType::Error; break;
    case QtFatalMsg: logtype = LogType::Fatal; break;
  }

  RENDERDOC_LogMessage(logtype, "QTRD", context.file, context.line, msg.toUtf8().data());
}

static QString tr(const char *string)
{
  return QApplication::translate("qrenderdoc", string);
}

void hideOption(QCommandLineOption &opt)
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)
  opt.setFlags(QCommandLineOption::HiddenFromHelp);
#else
  opt.setHidden(true);
#endif
}

int main(int argc, char *argv[])
{
  // call this as the very first thing - no-op on other platforms, but on linux it means
  // XInitThreads will be called allowing driver access to xlib on multiple threads.
  QCoreApplication::setAttribute(Qt::AA_X11InitThreads);

  qInstallMessageHandler(sharedLogOutput);

  qInfo() << "QRenderDoc initialising.";

  QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
  QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);

  QApplication::setApplicationVersion(lit(FULL_VERSION_STRING));

  QApplication application(argc, argv);

  QCommandLineParser parser;
  parser.setApplicationDescription(tr("Qt UI for RenderDoc"));
  QCommandLineOption helpOption = parser.addHelpOption();
  QCommandLineOption versionOption = parser.addVersionOption();

  QCommandLineOption tempfile(
      lit("tempfile"), tr("The filename to be opened is a temporary file owned by this instance."));
  parser.addOption(tempfile);

  QCommandLineOption targetcontrol({lit("targetcontrol"), lit("remoteaccess")},
                                   tr("A target control connection to open on startup."),
                                   lit("host:port"));
  parser.addOption(targetcontrol);

  QCommandLineOption python({lit("python"), lit("script"), lit("py")},
                            tr("Run a python script before opening the main UI."),
                            lit("filename.py"));
  parser.addOption(python);

  // secret non-described options
  QCommandLineOption installLayer(lit("install_vulkan_layer"), QString(), lit("root_or_not"));
  hideOption(installLayer);
  parser.addOption(installLayer);

  QCommandLineOption updateFailed(lit("updatefailed"), QString(), lit("errormsg"));
  hideOption(updateFailed);
  parser.addOption(updateFailed);

  QCommandLineOption updateDone(lit("updatedone"));
  hideOption(updateDone);
  parser.addOption(updateDone);

  QCommandLineOption crashReport(lit("crash"), QString(), lit("reportpath"));
  hideOption(crashReport);
  parser.addOption(crashReport);

#if !defined(RELEASE)
  QCommandLineOption unittests(lit("unittest"), tr("Run unit tests"));
  parser.addOption(unittests);
#endif

  parser.addPositionalArgument(lit("filename"), tr("The file to open."));

  bool parsedCommands = parser.parse(application.arguments());

  if(!parsedCommands)
  {
    QString error = parser.errorText();
    printf("%s\n", error.toUtf8().data());
    return 1;
  }

  if(parser.isSet(helpOption))
  {
    parser.showHelp();
    return 0;
  }

  if(parser.isSet(versionOption))
  {
    printf("QRenderDoc v%s (%s)\n", MAJOR_MINOR_VERSION_STRING, GitVersionHash);
#if defined(DISTRIBUTION_VERSION)
    printf("Packaged for %s - %s\n", DISTRIBUTION_NAME, DISTRIBUTION_CONTACT);
#endif
    return 0;
  }

#if !defined(RELEASE)
  if(parser.isSet(unittests))
  {
    PythonContext::GlobalInit();

    bool errors = false;

    qInfo() << "Checking python binding consistency.";

    {
      PythonContextHandle py;
      errors = py.ctx().CheckInterfaces();
    }

    if(errors)
    {
      qCritical() << "Found errors in python bindings. Please fix!";
      return 1;
    }

    qInfo() << "Python bindings are consistent.";
    return 0;
  }
#endif

  if(parser.isSet(installLayer))
  {
    qInfo() << "Updating Vulkan layer registration";
    if(parser.value(installLayer) == lit("root"))
      RENDERDOC_UpdateVulkanLayerRegistration(true);
    else
      RENDERDOC_UpdateVulkanLayerRegistration(false);
    return 0;
  }

  bool temp = parser.isSet(tempfile);

  bool updateApplied = false;

  if(parser.isSet(updateFailed))
  {
    RDDialog::critical(NULL, tr("Error updating"),
                       tr("Error applying update: %1").arg(parser.value(updateFailed)));
  }

  if(parser.isSet(updateDone))
  {
    updateApplied = true;

    RENDERDOC_UpdateInstalledVersionNumber();
  }

  QString remoteHost;
  uint remoteIdent = 0;

  if(parser.isSet(targetcontrol))
  {
    QRegularExpression regexp(lit("^([a-zA-Z0-9_-]+:)?([0-9]+)$"));

    QRegularExpressionMatch match = regexp.match(parser.value(targetcontrol));

    if(!match.hasMatch())
    {
      qCritical() << "--targetcontrol option must be followed by host:port";
      return 1;
    }

    QString host = match.captured(1);

    if(host.length() > 0 && host[host.length() - 1] == QLatin1Char(':'))
      host.chop(1);

    bool ok = false;
    uint32_t ident = match.captured(2).toUInt(&ok);

    if(ok)
    {
      remoteHost = host;
      remoteIdent = ident;
    }
    else
    {
      qCritical() << "--targetcontrol parameter" << match.captured(1) << "malformed";
      return 1;
    }
  }

  QString crashReportPath;
  if(parser.isSet(crashReport))
    crashReportPath = parser.value(crashReport);

  QStringList pyscripts = parser.values(python);

  // load the first filename in the positional arguments.
  QStringList remaining = parser.positionalArguments();

  QString filename;
  for(int i = 0; i < remaining.count(); i++)
  {
    const QString &fn = remaining[i];
    QFileInfo checkFile(fn);
    if(checkFile.exists() && checkFile.isFile())
    {
      filename = fn;
      remaining.removeAt(i);
      break;
    }
  }

  RegisterMetatypeConversions();

  {
    PersistantConfig config;

    {
      QString configPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
      QDir dir(configPath);

      if(!dir.exists())
        dir.mkpath(configPath);
    }

    QString configFilename = configFilePath(lit("UI.config"));

    if(!config.Load(configFilename))
    {
      RDDialog::critical(
          NULL, CaptureContext::tr("Error loading config"),
          CaptureContext::tr(
              "Error loading config file\n%1\nA default config is loaded and will be saved out.")
              .arg(configFilename));
    }

    if(!config.Analytics_TotalOptOut)
      Analytics::Load();

    bool isDarkTheme = IsDarkTheme();

    bool styleSet = config.SetStyle();

    // unrecognised style, or empty (none set), choose a default
    if(!styleSet)
    {
      config.UIStyle = isDarkTheme ? lit("RDDark") : lit("RDLight");

      config.SetStyle();
    }

    config.SetupFormatting();

    Resources::Initialise();

    GUIInvoke::init();

    {
      GlobalEnvironment env;
#if defined(RENDERDOC_PLATFORM_LINUX)
      env.xlibDisplay = QX11Info::display();
#endif
      rdcarray<rdcstr> coreargs;
      if(!crashReportPath.isEmpty())
        coreargs.push_back("--crash");
      for(const QString &arg : remaining)
        coreargs.push_back(arg);
      RENDERDOC_InitGlobalEnv(env, coreargs);
    }

    if(!crashReportPath.isEmpty())
    {
      QFile f(crashReportPath);

      if(f.exists() && f.open(QIODevice::ReadOnly | QIODevice::Text))
      {
        QVariantMap json = JSONToVariant(QString::fromUtf8(f.readAll()));

        if(json.contains(lit("report")))
        {
          CrashDialog dialog(config, json);

          RDDialog::show(&dialog);
        }
      }
    }
    else
    {
      PythonContext::GlobalInit();

      CaptureContext ctx(filename, remoteHost, remoteIdent, temp, config);

      Analytics::Prompt(ctx, config);

      ANALYTIC_SET(Environment.RenderDocVersion, lit(FULL_VERSION_STRING));
#if defined(DISTRIBUTION_VERSION)
      ANALYTIC_SET(Environment.DistributionVersion, lit(DISTRIBUTION_NAME));
#endif
      ANALYTIC_SET(Environment.Bitness, ((sizeof(void *) == sizeof(uint64_t)) ? 64 : 32));
      ANALYTIC_SET(Environment.OSVersion, QSysInfo::prettyProductName());

#if RENDERDOC_STABLE_BUILD
      ANALYTIC_SET(Environment.OfficialBuildRun, true);
#else
      ANALYTIC_SET(Environment.DevelBuildRun, true);
#endif

      ANALYTIC_SET(DaysUsed[QDateTime::currentDateTime().date().day()], true);

      if(!pyscripts.isEmpty())
      {
        PythonContextHandle py;

        ANALYTIC_SET(UIFeatures.PythonInterop, true);

        py.ctx().setGlobal("pyrenderdoc", (ICaptureContext *)&ctx);

        QObject::connect(&py.ctx(), &PythonContext::exception,
                         [](const QString &type, const QString &value, int, QList<QString> frames) {

                           QString exString;

                           if(!frames.isEmpty())
                           {
                             exString += tr("Traceback (most recent call last):\n");
                             for(const QString &f : frames)
                               exString += QFormatStr("  %1\n").arg(f);
                           }

                           exString += QFormatStr("%1: %2\n").arg(type).arg(value);

                           qCritical("%s", exString.toUtf8().data());
                         });

        QObject::connect(&py.ctx(), &PythonContext::textOutput,
                         [](bool isStdError, const QString &output) {
                           if(isStdError)
                             qCritical("%s", output.toUtf8().data());
                           else
                             qInfo("%s", output.toUtf8().data());
                         });

        for(const QString &f : pyscripts)
        {
          QFileInfo checkFile(f);
          if(checkFile.exists() && checkFile.isFile())
          {
            qInfo() << "running" << f;
            py.ctx().executeFile(f);
          }
          else
          {
            qWarning() << "Invalid python script" << f;
          }
        }
      }

      if(updateApplied)
      {
        config.CheckUpdate_UpdateAvailable = false;
        config.CheckUpdate_UpdateResponse = "";
        config.Save();
      }

      while(ctx.isRunning())
      {
        application.processEvents(QEventLoop::WaitForMoreEvents);
        QCoreApplication::sendPostedEvents();
        QCoreApplication::sendPostedEvents(NULL, QEvent::DeferredDelete);
      }

      config.Save();
    }

    PythonContext::GlobalShutdown();

    Formatter::shutdown();
  }

  return 0;
}
<commit_msg>Don't create GUI application to run unit tests<commit_after>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2016-2018 Baldur Karlsson
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 ******************************************************************************/

#include <QApplication>
#include <QCommandLineParser>
#include <QDir>
#include <QFileInfo>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
#include <QStandardPaths>
#include <QSysInfo>
#include "Code/CaptureContext.h"
#include "Code/QRDUtils.h"
#include "Code/Resources.h"
#include "Code/pyrenderdoc/PythonContext.h"
#include "Windows/Dialogs/CrashDialog.h"
#include "Windows/MainWindow.h"
#include "version.h"

#if defined(Q_OS_WIN32)
extern "C" {
_declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
}
#endif

REPLAY_PROGRAM_MARKER()

void sharedLogOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
  LogType logtype = LogType::Comment;

  switch(type)
  {
    case QtDebugMsg: logtype = LogType::Debug; break;
    case QtInfoMsg: logtype = LogType::Comment; break;
    case QtWarningMsg: logtype = LogType::Warning; break;
    case QtCriticalMsg: logtype = LogType::Error; break;
    case QtFatalMsg: logtype = LogType::Fatal; break;
  }

  RENDERDOC_LogMessage(logtype, "QTRD", context.file, context.line, msg.toUtf8().data());
}

static QString tr(const char *string)
{
  return QApplication::translate("qrenderdoc", string);
}

void hideOption(QCommandLineOption &opt)
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)
  opt.setFlags(QCommandLineOption::HiddenFromHelp);
#else
  opt.setHidden(true);
#endif
}

int main(int argc, char *argv[])
{
  // call this as the very first thing - no-op on other platforms, but on linux it means
  // XInitThreads will be called allowing driver access to xlib on multiple threads.
  QCoreApplication::setAttribute(Qt::AA_X11InitThreads);

  qInstallMessageHandler(sharedLogOutput);

  qInfo() << "QRenderDoc initialising.";

  QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
  QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);

  QApplication::setApplicationVersion(lit(FULL_VERSION_STRING));

// shortcut here so we can run this with a non-GUI application
#if !defined(RELEASE)
  if(QString::fromUtf8(argv[1]) == lit("--unittest"))
  {
    QCoreApplication application(argc, argv);
    PythonContext::GlobalInit();

    bool errors = false;

    qInfo() << "Checking python binding consistency.";

    {
      PythonContextHandle py;
      errors = py.ctx().CheckInterfaces();
    }

    if(errors)
    {
      qCritical() << "Found errors in python bindings. Please fix!";
      return 1;
    }

    qInfo() << "Python bindings are consistent.";
    return 0;
  }
#endif

  QApplication application(argc, argv);

  QCommandLineParser parser;
  parser.setApplicationDescription(tr("Qt UI for RenderDoc"));
  QCommandLineOption helpOption = parser.addHelpOption();
  QCommandLineOption versionOption = parser.addVersionOption();

  QCommandLineOption tempfile(
      lit("tempfile"), tr("The filename to be opened is a temporary file owned by this instance."));
  parser.addOption(tempfile);

  QCommandLineOption targetcontrol({lit("targetcontrol"), lit("remoteaccess")},
                                   tr("A target control connection to open on startup."),
                                   lit("host:port"));
  parser.addOption(targetcontrol);

  QCommandLineOption python({lit("python"), lit("script"), lit("py")},
                            tr("Run a python script before opening the main UI."),
                            lit("filename.py"));
  parser.addOption(python);

  // secret non-described options
  QCommandLineOption installLayer(lit("install_vulkan_layer"), QString(), lit("root_or_not"));
  hideOption(installLayer);
  parser.addOption(installLayer);

  QCommandLineOption updateFailed(lit("updatefailed"), QString(), lit("errormsg"));
  hideOption(updateFailed);
  parser.addOption(updateFailed);

  QCommandLineOption updateDone(lit("updatedone"));
  hideOption(updateDone);
  parser.addOption(updateDone);

  QCommandLineOption crashReport(lit("crash"), QString(), lit("reportpath"));
  hideOption(crashReport);
  parser.addOption(crashReport);

  parser.addPositionalArgument(lit("filename"), tr("The file to open."));

  bool parsedCommands = parser.parse(application.arguments());

  if(!parsedCommands)
  {
    QString error = parser.errorText();
    printf("%s\n", error.toUtf8().data());
    return 1;
  }

  if(parser.isSet(helpOption))
  {
    parser.showHelp();
    return 0;
  }

  if(parser.isSet(versionOption))
  {
    printf("QRenderDoc v%s (%s)\n", MAJOR_MINOR_VERSION_STRING, GitVersionHash);
#if defined(DISTRIBUTION_VERSION)
    printf("Packaged for %s - %s\n", DISTRIBUTION_NAME, DISTRIBUTION_CONTACT);
#endif
    return 0;
  }

  if(parser.isSet(installLayer))
  {
    qInfo() << "Updating Vulkan layer registration";
    if(parser.value(installLayer) == lit("root"))
      RENDERDOC_UpdateVulkanLayerRegistration(true);
    else
      RENDERDOC_UpdateVulkanLayerRegistration(false);
    return 0;
  }

  bool temp = parser.isSet(tempfile);

  bool updateApplied = false;

  if(parser.isSet(updateFailed))
  {
    RDDialog::critical(NULL, tr("Error updating"),
                       tr("Error applying update: %1").arg(parser.value(updateFailed)));
  }

  if(parser.isSet(updateDone))
  {
    updateApplied = true;

    RENDERDOC_UpdateInstalledVersionNumber();
  }

  QString remoteHost;
  uint remoteIdent = 0;

  if(parser.isSet(targetcontrol))
  {
    QRegularExpression regexp(lit("^([a-zA-Z0-9_-]+:)?([0-9]+)$"));

    QRegularExpressionMatch match = regexp.match(parser.value(targetcontrol));

    if(!match.hasMatch())
    {
      qCritical() << "--targetcontrol option must be followed by host:port";
      return 1;
    }

    QString host = match.captured(1);

    if(host.length() > 0 && host[host.length() - 1] == QLatin1Char(':'))
      host.chop(1);

    bool ok = false;
    uint32_t ident = match.captured(2).toUInt(&ok);

    if(ok)
    {
      remoteHost = host;
      remoteIdent = ident;
    }
    else
    {
      qCritical() << "--targetcontrol parameter" << match.captured(1) << "malformed";
      return 1;
    }
  }

  QString crashReportPath;
  if(parser.isSet(crashReport))
    crashReportPath = parser.value(crashReport);

  QStringList pyscripts = parser.values(python);

  // load the first filename in the positional arguments.
  QStringList remaining = parser.positionalArguments();

  QString filename;
  for(int i = 0; i < remaining.count(); i++)
  {
    const QString &fn = remaining[i];
    QFileInfo checkFile(fn);
    if(checkFile.exists() && checkFile.isFile())
    {
      filename = fn;
      remaining.removeAt(i);
      break;
    }
  }

  RegisterMetatypeConversions();

  {
    PersistantConfig config;

    {
      QString configPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
      QDir dir(configPath);

      if(!dir.exists())
        dir.mkpath(configPath);
    }

    QString configFilename = configFilePath(lit("UI.config"));

    if(!config.Load(configFilename))
    {
      RDDialog::critical(
          NULL, CaptureContext::tr("Error loading config"),
          CaptureContext::tr(
              "Error loading config file\n%1\nA default config is loaded and will be saved out.")
              .arg(configFilename));
    }

    if(!config.Analytics_TotalOptOut)
      Analytics::Load();

    bool isDarkTheme = IsDarkTheme();

    bool styleSet = config.SetStyle();

    // unrecognised style, or empty (none set), choose a default
    if(!styleSet)
    {
      config.UIStyle = isDarkTheme ? lit("RDDark") : lit("RDLight");

      config.SetStyle();
    }

    config.SetupFormatting();

    Resources::Initialise();

    GUIInvoke::init();

    {
      GlobalEnvironment env;
#if defined(RENDERDOC_PLATFORM_LINUX)
      env.xlibDisplay = QX11Info::display();
#endif
      rdcarray<rdcstr> coreargs;
      if(!crashReportPath.isEmpty())
        coreargs.push_back("--crash");
      for(const QString &arg : remaining)
        coreargs.push_back(arg);
      RENDERDOC_InitGlobalEnv(env, coreargs);
    }

    if(!crashReportPath.isEmpty())
    {
      QFile f(crashReportPath);

      if(f.exists() && f.open(QIODevice::ReadOnly | QIODevice::Text))
      {
        QVariantMap json = JSONToVariant(QString::fromUtf8(f.readAll()));

        if(json.contains(lit("report")))
        {
          CrashDialog dialog(config, json);

          RDDialog::show(&dialog);
        }
      }
    }
    else
    {
      PythonContext::GlobalInit();

      CaptureContext ctx(filename, remoteHost, remoteIdent, temp, config);

      Analytics::Prompt(ctx, config);

      ANALYTIC_SET(Environment.RenderDocVersion, lit(FULL_VERSION_STRING));
#if defined(DISTRIBUTION_VERSION)
      ANALYTIC_SET(Environment.DistributionVersion, lit(DISTRIBUTION_NAME));
#endif
      ANALYTIC_SET(Environment.Bitness, ((sizeof(void *) == sizeof(uint64_t)) ? 64 : 32));
      ANALYTIC_SET(Environment.OSVersion, QSysInfo::prettyProductName());

#if RENDERDOC_STABLE_BUILD
      ANALYTIC_SET(Environment.OfficialBuildRun, true);
#else
      ANALYTIC_SET(Environment.DevelBuildRun, true);
#endif

      ANALYTIC_SET(DaysUsed[QDateTime::currentDateTime().date().day()], true);

      if(!pyscripts.isEmpty())
      {
        PythonContextHandle py;

        ANALYTIC_SET(UIFeatures.PythonInterop, true);

        py.ctx().setGlobal("pyrenderdoc", (ICaptureContext *)&ctx);

        QObject::connect(&py.ctx(), &PythonContext::exception,
                         [](const QString &type, const QString &value, int, QList<QString> frames) {

                           QString exString;

                           if(!frames.isEmpty())
                           {
                             exString += tr("Traceback (most recent call last):\n");
                             for(const QString &f : frames)
                               exString += QFormatStr("  %1\n").arg(f);
                           }

                           exString += QFormatStr("%1: %2\n").arg(type).arg(value);

                           qCritical("%s", exString.toUtf8().data());
                         });

        QObject::connect(&py.ctx(), &PythonContext::textOutput,
                         [](bool isStdError, const QString &output) {
                           if(isStdError)
                             qCritical("%s", output.toUtf8().data());
                           else
                             qInfo("%s", output.toUtf8().data());
                         });

        for(const QString &f : pyscripts)
        {
          QFileInfo checkFile(f);
          if(checkFile.exists() && checkFile.isFile())
          {
            qInfo() << "running" << f;
            py.ctx().executeFile(f);
          }
          else
          {
            qWarning() << "Invalid python script" << f;
          }
        }
      }

      if(updateApplied)
      {
        config.CheckUpdate_UpdateAvailable = false;
        config.CheckUpdate_UpdateResponse = "";
        config.Save();
      }

      while(ctx.isRunning())
      {
        application.processEvents(QEventLoop::WaitForMoreEvents);
        QCoreApplication::sendPostedEvents();
        QCoreApplication::sendPostedEvents(NULL, QEvent::DeferredDelete);
      }

      config.Save();
    }

    PythonContext::GlobalShutdown();

    Formatter::shutdown();
  }

  return 0;
}
<|endoftext|>


<commit_before>
#pragma once

#include "geometry/frame.hpp"
#include "geometry/grassmann.hpp"
#include "geometry/named_quantities.hpp"
#include "geometry/r3_element.hpp"
#include "quantities/named_quantities.hpp"
#include "serialization/geometry.pb.h"

namespace principia {
namespace physics {
namespace internal_euler_solver {

using geometry::Bivector;
using geometry::Frame;
using geometry::Instant;
using geometry::R3Element;
using quantities::Angle;
using quantities::AngularFrequency;
using quantities::AngularMomentum;
using quantities::MomentOfInertia;
using quantities::NaN;

// A solver for Euler's rotation equations.  It follows Celledoni, Fassò,
// Säfström and Zanna, 2007, The exact computation of the free rigid body motion
// and its use in splitting method.
class EulerSolver {
 public:
  using PrincipalAxesFrame = Frame<serialization::Frame::PhysicsTag,
                                   serialization::Frame::PRINCIPAL_AXES,
                                   /*frame_is_inertial*/ false>;
  using AngularMomentumBivector = Bivector<AngularMomentum, PrincipalAxesFrame>;

  // Constructs a solver for a body with the given moments_of_inertia in its
  // principal axes frame.  The moments must be in increasing order.  At
  // initial_time the angular momentum is initial_angular_momentum.
  EulerSolver(R3Element<MomentOfInertia> const& moments_of_inertia,
              AngularMomentumBivector const& initial_angular_momentum,
              Instant const& initial_time);

  // Computes the angular momentum at the given time.
  AngularMomentumBivector AngularMomentumAt(Instant const& time) const;

private:
  // The formula to use, following Cellodoni et al., Section 2.2.  They don't
  // have a formula for the spherical case.
  enum class Formula {
    i,
    ii,
    iii,
    Sphere
  };

  // Construction parameters.
  AngularMomentumBivector const initial_angular_momentum_;
  Instant const initial_time_;

  // Amusingly, the formula to use is a constant of motion.
  Formula formula_;

  // Only the parameters needed for the selected formula are non-NaN after
  // construction.
  AngularMomentum B₁₃_ = NaN<AngularMomentum>();
  AngularMomentum B₃₁_ = NaN<AngularMomentum>();
  AngularMomentum B₂₁_ = NaN<AngularMomentum>();
  AngularMomentum B₂₃_ = NaN<AngularMomentum>();
  AngularMomentum G_ = NaN<AngularMomentum>();
  AngularFrequency λ₁_ = NaN<AngularFrequency>();
  AngularFrequency λ₃_ = NaN<AngularFrequency>();
  double mc_ = NaN<double>();
  Angle ν_ = NaN<Angle>();
  double σʹ_ = NaN<double>();
};

}  // namespace internal_euler_solver

using internal_euler_solver::EulerSolver;

}  // namespace physics
}  // namespace principia
<commit_msg>More cleanups.<commit_after>
#pragma once

#include "geometry/frame.hpp"
#include "geometry/grassmann.hpp"
#include "geometry/named_quantities.hpp"
#include "geometry/r3_element.hpp"
#include "quantities/named_quantities.hpp"
#include "serialization/geometry.pb.h"

namespace principia {
namespace physics {
namespace internal_euler_solver {

using geometry::Bivector;
using geometry::Frame;
using geometry::Instant;
using geometry::R3Element;
using quantities::Angle;
using quantities::AngularFrequency;
using quantities::AngularMomentum;
using quantities::MomentOfInertia;
using quantities::NaN;

// A solver for Euler's rotation equations.  It follows Celledoni, Fassò,
// Säfström and Zanna, 2007, The exact computation of the free rigid body motion
// and its use in splitting method.
class EulerSolver {
 public:
  using PrincipalAxesFrame = Frame<serialization::Frame::PhysicsTag,
                                   serialization::Frame::PRINCIPAL_AXES,
                                   /*frame_is_inertial*/ false>;
  using AngularMomentumBivector = Bivector<AngularMomentum, PrincipalAxesFrame>;

  // Constructs a solver for a body with the given moments_of_inertia in its
  // principal axes frame.  The moments must be in increasing order.  At
  // initial_time the angular momentum is initial_angular_momentum.
  EulerSolver(R3Element<MomentOfInertia> const& moments_of_inertia,
              AngularMomentumBivector const& initial_angular_momentum,
              Instant const& initial_time);

  // Computes the angular momentum at the given time.
  AngularMomentumBivector AngularMomentumAt(Instant const& time) const;

private:
  // The formula to use, following Cellodoni et al., Section 2.2.  They don't
  // have a formula for the spherical case.
  enum class Formula {
    i,
    ii,
    iii,
    Sphere
  };

  // Construction parameters.
  AngularMomentumBivector const initial_angular_momentum_;
  Instant const initial_time_;

  // Amusingly, the formula to use is a constant of motion.
  Formula formula_;

  // Only the parameters needed for the selected formula are non-NaN after
  // construction.
  AngularMomentum B₁₃_ = NaN<AngularMomentum>();
  AngularMomentum B₃₁_ = NaN<AngularMomentum>();
  AngularMomentum B₂₁_ = NaN<AngularMomentum>();
  AngularMomentum B₂₃_ = NaN<AngularMomentum>();
  AngularMomentum G_ = NaN<AngularMomentum>();
  AngularFrequency λ₁_ = NaN<AngularFrequency>();
  AngularFrequency λ₃_ = NaN<AngularFrequency>();
  double mc_ = NaN<double>();
  Angle ν_ = NaN<Angle>();
};

}  // namespace internal_euler_solver

using internal_euler_solver::EulerSolver;

}  // namespace physics
}  // namespace principia
<|endoftext|>


<commit_before>
#pragma once

#include "quantities/dimensions.hpp"

#include "base/not_constructible.hpp"

namespace principia {
namespace quantities {
namespace internal_dimensions {

using base::not_constructible;

class ExponentSerializer : not_constructible {
 public:
  // Returns true if the exponent is in the range that we can serialize.
  static constexpr bool IsSerializable(std::int64_t exponent);

  // Returns the serialized representation of the exponent.  |position| is the
  // 0-based position of the dimension in the representation.
  static constexpr std::int64_t Representation(
      std::int64_t exponent,
      std::int64_t position);

 private:
  static constexpr std::int64_t min_exponent = -24;
  static constexpr std::int64_t max_exponent = 7;
  static constexpr std::int64_t exponent_mask = 0x1F;
  static constexpr std::int64_t exponent_bits = 5;
};

constexpr bool ExponentSerializer::IsSerializable(
    std::int64_t const exponent) {
  return exponent >= min_exponent && exponent <= max_exponent;
}

constexpr std::int64_t ExponentSerializer::Representation(
    std::int64_t const exponent,
    std::int64_t const position) {
  // For exponents in [-16, 7] this returns the representations
  // 0x10, 0x11, ... 0x00, ... 0x07.  For exponents in [-24, -17] this returns
  // the representations 0x08, 0x09, ... 0x0F.  The latter used to be reserved
  // for exponents in the range [8, 15] but we believe that we never used them,
  // and with polynomials in the monomial basis we need large negative
  // exponents.
  return (exponent & exponent_mask) << (position * exponent_bits);
}

template<std::int64_t LengthExponent,
         std::int64_t MassExponent,
         std::int64_t TimeExponent,
         std::int64_t CurrentExponent,
         std::int64_t TemperatureExponent,
         std::int64_t AmountExponent,
         std::int64_t LuminousIntensityExponent,
         std::int64_t AngleExponent>
struct Dimensions : not_constructible {
  enum {
    Length            = LengthExponent,
    Mass              = MassExponent,
    Time              = TimeExponent,
    Current           = CurrentExponent,
    Temperature       = TemperatureExponent,
    Amount            = AmountExponent,
    LuminousIntensity = LuminousIntensityExponent,
    Angle             = AngleExponent,
  };

  static std::int64_t constexpr representation =
      ExponentSerializer::Representation(LengthExponent, 0)            |
      ExponentSerializer::Representation(MassExponent, 1)              |
      ExponentSerializer::Representation(TimeExponent, 2)              |
      ExponentSerializer::Representation(CurrentExponent, 3)           |
      ExponentSerializer::Representation(TemperatureExponent, 4)       |
      ExponentSerializer::Representation(AmountExponent, 5)            |
      ExponentSerializer::Representation(LuminousIntensityExponent, 6) |
      ExponentSerializer::Representation(AngleExponent, 7);
};

template<typename Dimensions>
struct DimensionsAreSerializable : std::true_type {
  static_assert(ExponentSerializer::IsSerializable(Dimensions::Length),
                "Invalid length exponent");
  static_assert(ExponentSerializer::IsSerializable(Dimensions::Mass),
                "Invalid mass exponent");
  static_assert(ExponentSerializer::IsSerializable(Dimensions::Time),
                "Invalid time exponent");
  static_assert(ExponentSerializer::IsSerializable(Dimensions::Current),
                "Invalid current exponent");
  static_assert(ExponentSerializer::IsSerializable(Dimensions::Temperature),
                "Invalid temperature exponent");
  static_assert(ExponentSerializer::IsSerializable(Dimensions::Amount),
                "Invalid amount exponent");
  static_assert(ExponentSerializer::IsSerializable(
                    Dimensions::LuminousIntensity),
                "Invalid luminous intensity exponent");
  static_assert(ExponentSerializer::IsSerializable(Dimensions::Angle),
                "Invalid angle exponent");
};

template<typename Dimensions, int n>
struct DimensionsExponentiationGenerator : not_constructible {
  using Type =
      internal_dimensions::Dimensions<Dimensions::Length * n,
                                      Dimensions::Mass * n,
                                      Dimensions::Time * n,
                                      Dimensions::Current * n,
                                      Dimensions::Temperature * n,
                                      Dimensions::Amount * n,
                                      Dimensions::LuminousIntensity * n,
                                      Dimensions::Angle * n>;
};

template<typename Dimensions, int n>
struct DimensionsNthRootGenerator : not_constructible {
  static_assert((Dimensions::Length % n) == 0 &&
                (Dimensions::Mass % n) == 0 &&
                (Dimensions::Time % n) == 0 &&
                (Dimensions::Current % n) == 0 &&
                (Dimensions::Temperature % n) == 0 &&
                (Dimensions::Amount % n) == 0 &&
                (Dimensions::LuminousIntensity % n) == 0 &&
                (Dimensions::Angle % n) == 0,
                "Dimensions not suitable for Nth root");

  using Type =
      internal_dimensions::Dimensions<Dimensions::Length / n,
                                      Dimensions::Mass / n,
                                      Dimensions::Time / n,
                                      Dimensions::Current / n,
                                      Dimensions::Temperature / n,
                                      Dimensions::Amount / n,
                                      Dimensions::LuminousIntensity / n,
                                      Dimensions::Angle / n>;
};

template<typename LDimensions, typename RDimensions>
struct DimensionsProductGenerator : not_constructible {
  using Type = Dimensions<LDimensions::Length + RDimensions::Length,
                          LDimensions::Mass + RDimensions::Mass,
                          LDimensions::Time + RDimensions::Time,
                          LDimensions::Current + RDimensions::Current,
                          LDimensions::Temperature + RDimensions::Temperature,
                          LDimensions::Amount + RDimensions::Amount,
                          LDimensions::LuminousIntensity +
                              RDimensions::LuminousIntensity,
                          LDimensions::Angle + RDimensions::Angle>;
};

template<typename LDimensions, typename RDimensions>
struct DimensionsQuotientGenerator : not_constructible {
  using Type = Dimensions<LDimensions::Length - RDimensions::Length,
                          LDimensions::Mass - RDimensions::Mass,
                          LDimensions::Time - RDimensions::Time,
                          LDimensions::Current - RDimensions::Current,
                          LDimensions::Temperature - RDimensions::Temperature,
                          LDimensions::Amount - RDimensions::Amount,
                          LDimensions::LuminousIntensity -
                              RDimensions::LuminousIntensity,
                          LDimensions::Angle - RDimensions::Angle>;
};

}  // namespace internal_dimensions
}  // namespace quantities
}  // namespace principia
<commit_msg>Stop relying on operations deprecated by https://reviews.llvm.org/D71576.<commit_after>
#pragma once

#include "quantities/dimensions.hpp"

#include "base/not_constructible.hpp"

namespace principia {
namespace quantities {
namespace internal_dimensions {

using base::not_constructible;

class ExponentSerializer : not_constructible {
 public:
  // Returns true if the exponent is in the range that we can serialize.
  static constexpr bool IsSerializable(std::int64_t exponent);

  // Returns the serialized representation of the exponent.  |position| is the
  // 0-based position of the dimension in the representation.
  static constexpr std::int64_t Representation(
      std::int64_t exponent,
      std::int64_t position);

 private:
  static constexpr std::int64_t min_exponent = -24;
  static constexpr std::int64_t max_exponent = 7;
  static constexpr std::int64_t exponent_mask = 0x1F;
  static constexpr std::int64_t exponent_bits = 5;
};

constexpr bool ExponentSerializer::IsSerializable(
    std::int64_t const exponent) {
  return exponent >= min_exponent && exponent <= max_exponent;
}

constexpr std::int64_t ExponentSerializer::Representation(
    std::int64_t const exponent,
    std::int64_t const position) {
  // For exponents in [-16, 7] this returns the representations
  // 0x10, 0x11, ... 0x00, ... 0x07.  For exponents in [-24, -17] this returns
  // the representations 0x08, 0x09, ... 0x0F.  The latter used to be reserved
  // for exponents in the range [8, 15] but we believe that we never used them,
  // and with polynomials in the monomial basis we need large negative
  // exponents.
  return (exponent & exponent_mask) << (position * exponent_bits);
}

template<std::int64_t LengthExponent,
         std::int64_t MassExponent,
         std::int64_t TimeExponent,
         std::int64_t CurrentExponent,
         std::int64_t TemperatureExponent,
         std::int64_t AmountExponent,
         std::int64_t LuminousIntensityExponent,
         std::int64_t AngleExponent>
struct Dimensions : not_constructible {
  static constexpr std::int64_t Length            = LengthExponent;
  static constexpr std::int64_t Mass              = MassExponent;
  static constexpr std::int64_t Time              = TimeExponent;
  static constexpr std::int64_t Current           = CurrentExponent;
  static constexpr std::int64_t Temperature       = TemperatureExponent;
  static constexpr std::int64_t Amount            = AmountExponent;
  static constexpr std::int64_t LuminousIntensity = LuminousIntensityExponent;
  static constexpr std::int64_t Angle             = AngleExponent;

  static std::int64_t constexpr representation =
      ExponentSerializer::Representation(LengthExponent, 0)            |
      ExponentSerializer::Representation(MassExponent, 1)              |
      ExponentSerializer::Representation(TimeExponent, 2)              |
      ExponentSerializer::Representation(CurrentExponent, 3)           |
      ExponentSerializer::Representation(TemperatureExponent, 4)       |
      ExponentSerializer::Representation(AmountExponent, 5)            |
      ExponentSerializer::Representation(LuminousIntensityExponent, 6) |
      ExponentSerializer::Representation(AngleExponent, 7);
};

template<typename Dimensions>
struct DimensionsAreSerializable : std::true_type {
  static_assert(ExponentSerializer::IsSerializable(Dimensions::Length),
                "Invalid length exponent");
  static_assert(ExponentSerializer::IsSerializable(Dimensions::Mass),
                "Invalid mass exponent");
  static_assert(ExponentSerializer::IsSerializable(Dimensions::Time),
                "Invalid time exponent");
  static_assert(ExponentSerializer::IsSerializable(Dimensions::Current),
                "Invalid current exponent");
  static_assert(ExponentSerializer::IsSerializable(Dimensions::Temperature),
                "Invalid temperature exponent");
  static_assert(ExponentSerializer::IsSerializable(Dimensions::Amount),
                "Invalid amount exponent");
  static_assert(ExponentSerializer::IsSerializable(
                    Dimensions::LuminousIntensity),
                "Invalid luminous intensity exponent");
  static_assert(ExponentSerializer::IsSerializable(Dimensions::Angle),
                "Invalid angle exponent");
};

template<typename Dimensions, int n>
struct DimensionsExponentiationGenerator : not_constructible {
  using Type =
      internal_dimensions::Dimensions<Dimensions::Length * n,
                                      Dimensions::Mass * n,
                                      Dimensions::Time * n,
                                      Dimensions::Current * n,
                                      Dimensions::Temperature * n,
                                      Dimensions::Amount * n,
                                      Dimensions::LuminousIntensity * n,
                                      Dimensions::Angle * n>;
};

template<typename Dimensions, int n>
struct DimensionsNthRootGenerator : not_constructible {
  static_assert((Dimensions::Length % n) == 0 &&
                (Dimensions::Mass % n) == 0 &&
                (Dimensions::Time % n) == 0 &&
                (Dimensions::Current % n) == 0 &&
                (Dimensions::Temperature % n) == 0 &&
                (Dimensions::Amount % n) == 0 &&
                (Dimensions::LuminousIntensity % n) == 0 &&
                (Dimensions::Angle % n) == 0,
                "Dimensions not suitable for Nth root");

  using Type =
      internal_dimensions::Dimensions<Dimensions::Length / n,
                                      Dimensions::Mass / n,
                                      Dimensions::Time / n,
                                      Dimensions::Current / n,
                                      Dimensions::Temperature / n,
                                      Dimensions::Amount / n,
                                      Dimensions::LuminousIntensity / n,
                                      Dimensions::Angle / n>;
};

template<typename LDimensions, typename RDimensions>
struct DimensionsProductGenerator : not_constructible {
  using Type = Dimensions<LDimensions::Length + RDimensions::Length,
                          LDimensions::Mass + RDimensions::Mass,
                          LDimensions::Time + RDimensions::Time,
                          LDimensions::Current + RDimensions::Current,
                          LDimensions::Temperature + RDimensions::Temperature,
                          LDimensions::Amount + RDimensions::Amount,
                          LDimensions::LuminousIntensity +
                              RDimensions::LuminousIntensity,
                          LDimensions::Angle + RDimensions::Angle>;
};

template<typename LDimensions, typename RDimensions>
struct DimensionsQuotientGenerator : not_constructible {
  using Type = Dimensions<LDimensions::Length - RDimensions::Length,
                          LDimensions::Mass - RDimensions::Mass,
                          LDimensions::Time - RDimensions::Time,
                          LDimensions::Current - RDimensions::Current,
                          LDimensions::Temperature - RDimensions::Temperature,
                          LDimensions::Amount - RDimensions::Amount,
                          LDimensions::LuminousIntensity -
                              RDimensions::LuminousIntensity,
                          LDimensions::Angle - RDimensions::Angle>;
};

}  // namespace internal_dimensions
}  // namespace quantities
}  // namespace principia
<|endoftext|>


<commit_before>// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM 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) version 2.1 dated February 1999.

#ifndef MFEM_CUDA_HPP
#define MFEM_CUDA_HPP

#include <cstddef>

// *****************************************************************************
#ifdef __NVCC__
#include <cuda.h>
inline void cuCheck(const unsigned int c)
{
   MFEM_ASSERT(c == cudaSuccess, cudaGetErrorString(cudaGetLastError()));
}
template <typename BODY> __global__ static
void cuKernel(const int N, BODY body)
{
   const int k = blockDim.x*blockIdx.x + threadIdx.x;
   if (k >= N) { return; }
   body(k);
}
template <int BLOCKS, typename DBODY>
void cuWrap(const int N, DBODY &&d_body)
{
   if (N==0) { return; }
   const int GRID = (N+BLOCKS-1)/BLOCKS;
   cuKernel<<<GRID,BLOCKS>>>(N,d_body);
   const cudaError_t last = cudaGetLastError();
   MFEM_ASSERT(last == cudaSuccess, cudaGetErrorString(last));
}
template<typename T>
__host__ __device__ inline T AtomicAdd(T* address, T val)
{
   return atomicAdd(address, val);
}
#else // ***********************************************************************
#define __host__
#define __device__
#define __constant__
typedef int CUdevice;
typedef int CUcontext;
typedef void* CUstream;
template <int BLOCKS, typename DBODY>
void cuWrap(const int N, DBODY &&d_body) {}
template<typename T> inline T AtomicAdd(T* address, T val)
{
   return *address += val;
}
#endif // __NVCC__

// *****************************************************************************
namespace mfem
{

// *****************************************************************************
// * Allocates device memory
// *****************************************************************************
void* cuMemAlloc(void **d_ptr, size_t bytes);

// *****************************************************************************
// * Frees device memory
// *****************************************************************************
void* cuMemFree(void *d_ptr);

// *****************************************************************************
// * Copies memory from Host to Device
// *****************************************************************************
void* cuMemcpyHtoD(void *d_dst, const void *h_src, size_t bytes);

// *****************************************************************************
// * Copies memory from Host to Device
// *****************************************************************************
void* cuMemcpyHtoDAsync(void *d_dst, const void *h_src,
                        size_t bytes, void *stream);

// *****************************************************************************
// * Copies memory from Device to Device
// *****************************************************************************
void* cuMemcpyDtoD(void *d_dst, void *d_src, size_t bytes);

// *****************************************************************************
// * Copies memory from Device to Device
// *****************************************************************************
void* cuMemcpyDtoDAsync(void *d_dst, void *d_src, size_t bytes, void *stream);

// *****************************************************************************
// * Copies memory from Device to Host
// *****************************************************************************
void* cuMemcpyDtoH(void *h_dst, void *d_src, size_t bytes);

// *****************************************************************************
// * Copies memory from Device to Host
// *****************************************************************************
void* cuMemcpyDtoHAsync(void *h_dst, void *d_src, size_t bytes, void *stream);

} // namespace mfem

#endif // MFEM_CUDA_HPP
<commit_msg>adjustments to atomic - adds flexibility<commit_after>// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM 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) version 2.1 dated February 1999.

#ifndef MFEM_CUDA_HPP
#define MFEM_CUDA_HPP

#include <cstddef>

// *****************************************************************************
#ifdef __NVCC__
#include <cuda.h>
inline void cuCheck(const unsigned int c)
{
   MFEM_ASSERT(c == cudaSuccess, cudaGetErrorString(cudaGetLastError()));
}
template <typename BODY> __global__ static
void cuKernel(const int N, BODY body)
{
   const int k = blockDim.x*blockIdx.x + threadIdx.x;
   if (k >= N) { return; }
   body(k);
}
template <int BLOCKS, typename DBODY>
void cuWrap(const int N, DBODY &&d_body)
{
   if (N==0) { return; }
   const int GRID = (N+BLOCKS-1)/BLOCKS;
   cuKernel<<<GRID,BLOCKS>>>(N,d_body);
   const cudaError_t last = cudaGetLastError();
   MFEM_ASSERT(last == cudaSuccess, cudaGetErrorString(last));
}
#else // ***********************************************************************
#define __host__
#define __device__
#define __constant__
typedef int CUdevice;
typedef int CUcontext;
typedef void* CUstream;
template <int BLOCKS, typename DBODY>
void cuWrap(const int N, DBODY &&d_body) {}
#endif // __NVCC__

#if defined(__CUDA_ARCH__)
template<typename T>
__device__ inline T AtomicAdd(T* address, T val)
{
  return atomicAdd(address, val);
}
#else
template<typename T> inline T AtomicAdd(T* address, T val)
{
#if defined(_OPENMP)
#pragma omp atomic
  *address += val;
#else
  *address += val;
#endif
  return *address;
}
#endif //__CUDA_ARCH__
// *****************************************************************************
namespace mfem
{

// *****************************************************************************
// * Allocates device memory
// *****************************************************************************
void* cuMemAlloc(void **d_ptr, size_t bytes);

// *****************************************************************************
// * Frees device memory
// *****************************************************************************
void* cuMemFree(void *d_ptr);

// *****************************************************************************
// * Copies memory from Host to Device
// *****************************************************************************
void* cuMemcpyHtoD(void *d_dst, const void *h_src, size_t bytes);

// *****************************************************************************
// * Copies memory from Host to Device
// *****************************************************************************
void* cuMemcpyHtoDAsync(void *d_dst, const void *h_src,
                        size_t bytes, void *stream);

// *****************************************************************************
// * Copies memory from Device to Device
// *****************************************************************************
void* cuMemcpyDtoD(void *d_dst, void *d_src, size_t bytes);

// *****************************************************************************
// * Copies memory from Device to Device
// *****************************************************************************
void* cuMemcpyDtoDAsync(void *d_dst, void *d_src, size_t bytes, void *stream);

// *****************************************************************************
// * Copies memory from Device to Host
// *****************************************************************************
void* cuMemcpyDtoH(void *h_dst, void *d_src, size_t bytes);

// *****************************************************************************
// * Copies memory from Device to Host
// *****************************************************************************
void* cuMemcpyDtoHAsync(void *h_dst, void *d_src, size_t bytes, void *stream);

} // namespace mfem

#endif // MFEM_CUDA_HPP
<|endoftext|>


<commit_before>/*
   Copyright (C) 2015 Preet Desai (preet.desai@gmail.com)

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#include <algorithm>

#include <glm/gtx/string_cast.hpp>

#include <ks/gl/KsGLCommands.hpp>
#include <raintk/RainTkLog.hpp>
#include <raintk/RainTkMainDrawStage.hpp>

namespace raintk
{
    void MainDrawStage::SyncView(glm::vec4 const &viewport,
                                 ks::gl::Camera<float> const &camera)
    {
        m_viewport = viewport;
        m_camera = camera;
    }

    void MainDrawStage::SyncClipRegions(std::vector<BoundingBox> const &list_clip_regions)
    {
        m_list_clip_regions = list_clip_regions;
    }

    void MainDrawStage::SyncDrawOrder(std::vector<Id> const &list_opq_draw_order,
                                      std::vector<Id> const &list_xpr_draw_order)
    {
        m_list_opq_draw_order = list_opq_draw_order;
        m_list_xpr_draw_order = list_xpr_draw_order;
    }

    void MainDrawStage::Render(ks::draw::DrawParams<DrawKey> &p)
    {
        auto const &camera = m_camera;
        auto const &viewport = m_viewport;

        // reset stats
        this->m_stats.reset();

        // get params
        auto& list_draw_calls = p.list_draw_calls;

        // Setup viewport (all values in pixels)
        // z == width, w == height
        ks::gl::Viewport(viewport.x,viewport.y,viewport.z,viewport.w);

        // Enable scissor test to allow for clipping
        p.state_set->SetScissorTest(GL_TRUE);

        // Enable depth writes to clear the buffer
        p.state_set->SetDepthMask(GL_TRUE);
        p.state_set->SetClearColor(0.15,0.15,0.15,1.0);

        // Set the scissor extents to the viewport so that
        // everything cleared
        ks::gl::Scissor(viewport.x,viewport.y,viewport.z,viewport.w);

        ks::gl::Clear(ks::gl::ColorBufferBit |
                      ks::gl::DepthBufferBit |
                      ks::gl::StencilBufferBit);

        DrawKey prev_key; // key value should be 0

        // Opaque draw calls
        for(auto const dc_id : m_list_opq_draw_order)
        {
            auto& draw_call = list_draw_calls[dc_id];
            setupState(viewport,camera,p,prev_key,draw_call.key);

            ks::gl::ShaderProgram* shader =
                    p.list_shaders[draw_call.key.GetShader()].get();

            // Set the individual uniforms
            if(draw_call.list_uniforms)
            {
                auto &list_uniforms = *(draw_call.list_uniforms);
                for(auto &uniform : list_uniforms) {
                    uniform->GLSetUniform(shader);
                }
            }

            // Draw!
            issueDrawCall(shader,draw_call);
        }

        // Transparent draw calls
        for(auto const dc_id : m_list_xpr_draw_order)
        {
            auto& draw_call = list_draw_calls[dc_id];
            setupState(viewport,camera,p,prev_key,draw_call.key);

            ks::gl::ShaderProgram* shader =
                    p.list_shaders[draw_call.key.GetShader()].get();

            // Set the individual uniforms
            if(draw_call.list_uniforms)
            {
                auto &list_uniforms = *(draw_call.list_uniforms);
                for(auto &uniform : list_uniforms) {
                    uniform->GLSetUniform(shader);
                }
            }

            // Draw!
            issueDrawCall(shader,draw_call);
        }

        // Disable scissor test to reset to
        // defaults for other draw stages
        p.state_set->SetScissorTest(GL_FALSE);
    }

    void MainDrawStage::Reset()
    {
        // TODO
    }

    void MainDrawStage::setupState(glm::vec4 const &viewport,
                                   ks::gl::Camera<float> const &camera,
                                   ks::draw::DrawParams<DrawKey>& p,
                                   DrawKey& prev_key,
                                   DrawKey const curr_key)
    {
        if(!(prev_key == curr_key))
        {
            auto const clip_id = curr_key.GetClip();
            auto const shader_id = curr_key.GetShader();
            auto const depth_config_id = curr_key.GetDepthConfig();
            auto const blend_config_id = curr_key.GetBlendConfig();
            auto const stencil_config_id = curr_key.GetStencilConfig();
            auto const texture_set_id = curr_key.GetTextureSet();
            auto const uniform_set_id = curr_key.GetUniformSet();

            if(prev_key.GetClip() != curr_key.GetClip())
            {
                glm::mat4 const m4_pv =
                        camera.GetProjMatrix()*
                        camera.GetViewMatrix();

                // Clip structure:
                // NOTE: The 'z' and 'w' are NOT width and height
                // glm vec4 [x,y,z,w]: [x0,y0,x1,y1]
                auto const &clip_bbox = m_list_clip_regions[clip_id];
                glm::vec4 const clip(
                            clip_bbox.x0,
                            clip_bbox.y0,
                            clip_bbox.x1,
                            clip_bbox.y1);

                auto const ndc_clip_bl = m4_pv*glm::vec4(clip.x,clip.w,0,1);
                auto const ndc_clip_tr = m4_pv*glm::vec4(clip.z,clip.y,0,1);

                float clip_x = 0.5*(ndc_clip_bl.x+1.0)*viewport.z;
                float clip_y = 0.5*(ndc_clip_bl.y+1.0)*viewport.w;
                float clip_w = (0.5*(ndc_clip_tr.x+1.0))*viewport.z - clip_x;
                float clip_h = (0.5*(ndc_clip_tr.y+1.0))*viewport.w - clip_y;

                // TODO clip should consider viewport x,y; currently we
                // only consider the width and height of the viewport
                ks::gl::Scissor(clip_x,clip_y,clip_w,clip_h);
            }

            if(prev_key.GetShader() != curr_key.GetShader())
            {
                auto& shader = p.list_shaders[shader_id];

                glm::mat4 const u_m4_pv =
                        camera.GetProjMatrix()*
                        camera.GetViewMatrix();

                shader->GLEnable(p.state_set);
                shader->GLSetUniform("u_m4_pv",u_m4_pv);
                this->m_stats.shader_switches++;
            }

            if((prev_key.GetDepthConfig() != depth_config_id) && (depth_config_id > 0))
            {
                p.list_depth_configs[depth_config_id](p.state_set);
                this->m_stats.raster_ops++;
            }

            if((prev_key.GetBlendConfig() != blend_config_id) && (blend_config_id > 0))
            {
                p.list_blend_configs[blend_config_id](p.state_set);
                this->m_stats.raster_ops++;
            }

            if((prev_key.GetStencilConfig() != stencil_config_id) && (stencil_config_id > 0))
            {
                p.list_stencil_configs[stencil_config_id](p.state_set);
                this->m_stats.raster_ops++;
            }

            if(prev_key.GetTextureSet() != texture_set_id)
            {
                auto& texture_set = p.list_texture_sets[texture_set_id];

                for(auto& desc : texture_set->list_texture_desc)
                {
                    auto& texture = desc.first;
                    auto tex_unit = desc.second;

                    texture->GLBind(p.state_set,tex_unit);
                    this->m_stats.texture_switches++;
                }
            }

            if(prev_key.GetUniformSet() != uniform_set_id)
            {
                auto& uniform_set = p.list_uniform_sets[uniform_set_id];
                auto& shader = p.list_shaders[shader_id];

                for(auto& uniform : uniform_set->list_uniforms)
                {
                    uniform->GLSetUniform(shader.get());
                }
            }

            prev_key = curr_key;
        }
    }

    void MainDrawStage::issueDrawCall(ks::gl::ShaderProgram* shader,
                                      DrawCall &draw_call)
    {
        // Draw
        // TODO: Since we are drawing all buffers in
        // a tight loop, we might be able to check
        // when we really need to bind/unbind buffers
        // to avoid redundant calls

        auto primitive = draw_call.key.GetPrimitive();

        if(draw_call.draw_ix.buffer) {
            // bind vertex buffers
            bool ok = true;
            for(auto& range : draw_call.list_draw_vx) {
                ok = ok && range.buffer->GLBindVxBuff(
                            shader,range.start_byte);
            }

            // bind index buffer
            ok = ok && draw_call.draw_ix.buffer->GLBind();

            assert(ok);

            ks::gl::DrawElements(
                        primitive,
                        draw_call.draw_ix.start_byte,
                        draw_call.draw_ix.size_bytes);

            for(auto& range : draw_call.list_draw_vx) {
                range.buffer->GLUnbind();
            }
            draw_call.draw_ix.buffer->GLUnbind();
        }
        else {
            // bind vertex buffers
            bool ok = true;
            for(auto& range : draw_call.list_draw_vx) {
                ok = ok && range.buffer->GLBindVxBuff(
                            shader,range.start_byte);
            }

            auto& first_range = draw_call.list_draw_vx[0];

            ks::gl::DrawArrays(
                        primitive,
                        first_range.buffer->GetVertexSizeBytes(),
                        0,first_range.size_bytes);

            for(auto& range : draw_call.list_draw_vx) {
                range.buffer->GLUnbind();
            }
        }

        this->m_stats.draw_calls++;
    }
}
<commit_msg>Adjusted clipping with glScissor to reflect pixel rasterization to try and avoid off-by-one pixel clips<commit_after>/*
   Copyright (C) 2015 Preet Desai (preet.desai@gmail.com)

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#include <algorithm>

#include <glm/gtx/string_cast.hpp>

#include <ks/gl/KsGLCommands.hpp>
#include <raintk/RainTkLog.hpp>
#include <raintk/RainTkMainDrawStage.hpp>

namespace raintk
{
    void MainDrawStage::SyncView(glm::vec4 const &viewport,
                                 ks::gl::Camera<float> const &camera)
    {
        m_viewport = viewport;
        m_camera = camera;
    }

    void MainDrawStage::SyncClipRegions(std::vector<BoundingBox> const &list_clip_regions)
    {
        m_list_clip_regions = list_clip_regions;
    }

    void MainDrawStage::SyncDrawOrder(std::vector<Id> const &list_opq_draw_order,
                                      std::vector<Id> const &list_xpr_draw_order)
    {
        m_list_opq_draw_order = list_opq_draw_order;
        m_list_xpr_draw_order = list_xpr_draw_order;
    }

    void MainDrawStage::Render(ks::draw::DrawParams<DrawKey> &p)
    {
        auto const &camera = m_camera;
        auto const &viewport = m_viewport;

        // reset stats
        this->m_stats.reset();

        // get params
        auto& list_draw_calls = p.list_draw_calls;

        // Setup viewport (all values in pixels)
        // z == width, w == height
        ks::gl::Viewport(viewport.x,viewport.y,viewport.z,viewport.w);

        // Enable scissor test to allow for clipping
        p.state_set->SetScissorTest(GL_TRUE);

        // Enable depth writes to clear the buffer
        p.state_set->SetDepthMask(GL_TRUE);
        p.state_set->SetClearColor(0.15,0.15,0.15,1.0);

        // Set the scissor extents to the viewport so that
        // everything cleared
        ks::gl::Scissor(viewport.x,viewport.y,viewport.z,viewport.w);

        ks::gl::Clear(ks::gl::ColorBufferBit |
                      ks::gl::DepthBufferBit |
                      ks::gl::StencilBufferBit);

        DrawKey prev_key; // key value should be 0

        // Opaque draw calls
        for(auto const dc_id : m_list_opq_draw_order)
        {
            auto& draw_call = list_draw_calls[dc_id];
            setupState(viewport,camera,p,prev_key,draw_call.key);

            ks::gl::ShaderProgram* shader =
                    p.list_shaders[draw_call.key.GetShader()].get();

            // Set the individual uniforms
            if(draw_call.list_uniforms)
            {
                auto &list_uniforms = *(draw_call.list_uniforms);
                for(auto &uniform : list_uniforms) {
                    uniform->GLSetUniform(shader);
                }
            }

            // Draw!
            issueDrawCall(shader,draw_call);
        }

        // Transparent draw calls
        for(auto const dc_id : m_list_xpr_draw_order)
        {
            auto& draw_call = list_draw_calls[dc_id];
            setupState(viewport,camera,p,prev_key,draw_call.key);

            ks::gl::ShaderProgram* shader =
                    p.list_shaders[draw_call.key.GetShader()].get();

            // Set the individual uniforms
            if(draw_call.list_uniforms)
            {
                auto &list_uniforms = *(draw_call.list_uniforms);
                for(auto &uniform : list_uniforms) {
                    uniform->GLSetUniform(shader);
                }
            }

            // Draw!
            issueDrawCall(shader,draw_call);
        }

        // Disable scissor test to reset to
        // defaults for other draw stages
        p.state_set->SetScissorTest(GL_FALSE);
    }

    void MainDrawStage::Reset()
    {
        // TODO
    }

    namespace
    {
        float GetFraction(float f)
        {
            return (f - sint(f));
        }
    }

    void MainDrawStage::setupState(glm::vec4 const &viewport,
                                   ks::gl::Camera<float> const &camera,
                                   ks::draw::DrawParams<DrawKey>& p,
                                   DrawKey& prev_key,
                                   DrawKey const curr_key)
    {
        if(!(prev_key == curr_key))
        {
            auto const clip_id = curr_key.GetClip();
            auto const shader_id = curr_key.GetShader();
            auto const depth_config_id = curr_key.GetDepthConfig();
            auto const blend_config_id = curr_key.GetBlendConfig();
            auto const stencil_config_id = curr_key.GetStencilConfig();
            auto const texture_set_id = curr_key.GetTextureSet();
            auto const uniform_set_id = curr_key.GetUniformSet();

            if(prev_key.GetClip() != curr_key.GetClip())
            {
                glm::mat4 const m4_pv =
                        camera.GetProjMatrix()*
                        camera.GetViewMatrix();

                // Clip structure:
                // NOTE: The 'z' and 'w' are NOT width and height
                // glm vec4 [x,y,z,w]: [x0,y0,x1,y1]
                auto const &clip_bbox = m_list_clip_regions[clip_id];
                glm::vec4 const clip(
                            clip_bbox.x0,
                            clip_bbox.y0,
                            clip_bbox.x1,
                            clip_bbox.y1);

                auto const ndc_clip_bl = m4_pv*glm::vec4(clip.x,clip.w,0,1);
                auto const ndc_clip_tr = m4_pv*glm::vec4(clip.z,clip.y,0,1);

                float clip_x0 = 0.5*(ndc_clip_bl.x+1.0)*viewport.z;
                float clip_y0 = 0.5*(ndc_clip_bl.y+1.0)*viewport.w;
                float clip_x1 = (0.5*(ndc_clip_tr.x+1.0))*viewport.z;
                float clip_y1 = (0.5*(ndc_clip_tr.y+1.0))*viewport.w;

                // clip_x,y,w,h are now in window coordinates with (0,0)
                // representing the bottom left of the window

                // A pixel is considered inside the clip rectangle if:
                // * It contains the pixel center (0.5,0.5)
                // * The left edge is on the pixel center
                // * The top edge is on the pixel center
                // ref: https://msdn.microsoft.com/en-us/library/windows/desktop/cc627092(v=vs.85).aspx

                // We need to compensate for the above cases because the
                // coordinates will be truncated when they are converted
                // to integers for the glScissor call

                sint clip_x0_px = clip_x0+0.5f;
                sint clip_y0_px = clip_y0;
                sint clip_x1_px = clip_x1;
                sint clip_y1_px = clip_y1+0.5f;

                // bottom
                if(GetFraction(clip_y0) >= 0.5f)
                {
                    clip_y0_px++;
                }

                // right
                if(GetFraction(clip_x1) > 0.5f)
                {
                    clip_x1_px++;
                }

                // TODO clip should consider viewport x,y; currently we
                // only consider the width and height of the viewport
                ks::gl::Scissor(
                            clip_x0_px,
                            clip_y0_px,
                            clip_x1_px-clip_x0_px,
                            clip_y1_px-clip_y0_px);
            }

            if(prev_key.GetShader() != curr_key.GetShader())
            {
                auto& shader = p.list_shaders[shader_id];

                glm::mat4 const u_m4_pv =
                        camera.GetProjMatrix()*
                        camera.GetViewMatrix();

                shader->GLEnable(p.state_set);
                shader->GLSetUniform("u_m4_pv",u_m4_pv);
                this->m_stats.shader_switches++;
            }

            if((prev_key.GetDepthConfig() != depth_config_id) && (depth_config_id > 0))
            {
                p.list_depth_configs[depth_config_id](p.state_set);
                this->m_stats.raster_ops++;
            }

            if((prev_key.GetBlendConfig() != blend_config_id) && (blend_config_id > 0))
            {
                p.list_blend_configs[blend_config_id](p.state_set);
                this->m_stats.raster_ops++;
            }

            if((prev_key.GetStencilConfig() != stencil_config_id) && (stencil_config_id > 0))
            {
                p.list_stencil_configs[stencil_config_id](p.state_set);
                this->m_stats.raster_ops++;
            }

            if(prev_key.GetTextureSet() != texture_set_id)
            {
                auto& texture_set = p.list_texture_sets[texture_set_id];

                for(auto& desc : texture_set->list_texture_desc)
                {
                    auto& texture = desc.first;
                    auto tex_unit = desc.second;

                    texture->GLBind(p.state_set,tex_unit);
                    this->m_stats.texture_switches++;
                }
            }

            if(prev_key.GetUniformSet() != uniform_set_id)
            {
                auto& uniform_set = p.list_uniform_sets[uniform_set_id];
                auto& shader = p.list_shaders[shader_id];

                for(auto& uniform : uniform_set->list_uniforms)
                {
                    uniform->GLSetUniform(shader.get());
                }
            }

            prev_key = curr_key;
        }
    }

    void MainDrawStage::issueDrawCall(ks::gl::ShaderProgram* shader,
                                      DrawCall &draw_call)
    {
        // Draw
        // TODO: Since we are drawing all buffers in
        // a tight loop, we might be able to check
        // when we really need to bind/unbind buffers
        // to avoid redundant calls

        auto primitive = draw_call.key.GetPrimitive();

        if(draw_call.draw_ix.buffer) {
            // bind vertex buffers
            bool ok = true;
            for(auto& range : draw_call.list_draw_vx) {
                ok = ok && range.buffer->GLBindVxBuff(
                            shader,range.start_byte);
            }

            // bind index buffer
            ok = ok && draw_call.draw_ix.buffer->GLBind();

            assert(ok);

            ks::gl::DrawElements(
                        primitive,
                        draw_call.draw_ix.start_byte,
                        draw_call.draw_ix.size_bytes);

            for(auto& range : draw_call.list_draw_vx) {
                range.buffer->GLUnbind();
            }
            draw_call.draw_ix.buffer->GLUnbind();
        }
        else {
            // bind vertex buffers
            bool ok = true;
            for(auto& range : draw_call.list_draw_vx) {
                ok = ok && range.buffer->GLBindVxBuff(
                            shader,range.start_byte);
            }

            auto& first_range = draw_call.list_draw_vx[0];

            ks::gl::DrawArrays(
                        primitive,
                        first_range.buffer->GetVertexSizeBytes(),
                        0,first_range.size_bytes);

            for(auto& range : draw_call.list_draw_vx) {
                range.buffer->GLUnbind();
            }
        }

        this->m_stats.draw_calls++;
    }
}
<|endoftext|>


<commit_before>
#include "chunk_headers.hpp"
#include "magic_number.hpp"
#include "msh_builder.hpp"
#include "type_pun.hpp"
#include "ucfb_reader.hpp"

namespace {

#pragma pack(push, 1)

struct Mask {
   Magic_number mn;
   std::uint32_t size;

   msh::Collision_flags flags;
};

static_assert(std::is_standard_layout_v<Mask>);
static_assert(sizeof(Mask) == 12);

struct Parent {
   Magic_number mn;
   std::uint32_t size;

   char str[];
};

static_assert(std::is_standard_layout_v<Parent>);
static_assert(sizeof(Parent) == 8);

struct Xframe {
   Magic_number mn;
   std::uint32_t size;

   glm::mat3 rotation;
   glm::vec3 position;
};

static_assert(std::is_standard_layout_v<Xframe>);
static_assert(sizeof(Xframe) == 56);

struct Data {
   Magic_number mn;
   std::uint32_t size;
   msh::Primitive_type type;
   glm::vec3 prim_size;
};

static_assert(std::is_standard_layout_v<Data>);
static_assert(sizeof(Data) == 24);

#pragma pack(pop)

template<typename Type>
const Type& find_chunk(std::uint32_t& head, const std::uint32_t end, const Byte* bytes,
                       Magic_number mn)
{
   while (head < end) {
      const auto& chunk = view_type_as<chunks::Unknown>(bytes[head]);

      head += chunk.size + 8;
      if (head % 4 != 0) head += (4 - (head % 4));

      if (chunk.mn == mn) return view_type_as<Type>(chunk);
   }

   throw std::runtime_error{"badly formed collision primitive"};
}

template<typename Type>
const Type* find_optional_chunk(std::uint32_t& head, const std::uint32_t end,
                                const Byte* bytes, Magic_number mn,
                                Magic_number end_at_mn)
{
   std::uint32_t local_head = head;

   while (local_head < end) {
      const auto& chunk = view_type_as<chunks::Unknown>(bytes[head]);

      local_head += chunk.size + 8;
      if (local_head % 4 != 0) local_head += (4 - (local_head % 4));

      if (chunk.mn == end_at_mn) return nullptr;
      if (chunk.mn == mn) {
         head = local_head;

         return &view_type_as<Type>(chunk);
      }
   }

   return nullptr;
}

auto read_primitive(std::uint32_t& head, const std::uint32_t end,
                    const chunks::Primitives& prim) -> msh::Collision_primitive
{
   msh::Collision_primitive msh_prim;

   find_chunk<chunks::Unknown>(head, end, &prim.bytes[0], "NAME"_mn);

   const auto* mask =
      find_optional_chunk<Mask>(head, end, &prim.bytes[0], "MASK"_mn, "NAME"_mn);

   if (mask) msh_prim.flags = mask->flags;

   const auto& parent = find_chunk<Parent>(head, end, &prim.bytes[0], "PRNT"_mn);
   msh_prim.parent = std::string{&parent.str[0], parent.size - 1};

   const auto& xframe = find_chunk<Xframe>(head, end, &prim.bytes[0], "XFRM"_mn);

   msh_prim.rotation = glm::quat_cast(xframe.rotation);
   msh_prim.position = xframe.position;

   const auto& data = find_chunk<Data>(head, end, &prim.bytes[0], "DATA"_mn);

   msh_prim.type = data.type;
   msh_prim.size = data.prim_size;

   return msh_prim;
}
}

void handle_primitives(Ucfb_reader primitives, msh::Builders_map& builders)
{
   const auto& prim = primitives.view_as_chunk<chunks::Primitives>();

   std::string name{reinterpret_cast<const char*>(&prim.bytes[0]), prim.info_size - 5};

   std::uint32_t head = prim.info_size;
   const std::uint32_t end = prim.size - 8;

   if (head % 4 != 0) head += (4 - (head % 4));

   auto& builder = builders[name];

   while (head < end) {
      builder.add_collision_primitive(read_primitive(head, end, prim));
   }
}<commit_msg>Shifted handle_primitives over to Ucfb_readers<commit_after>
#include "chunk_headers.hpp"
#include "glm_pod_wrappers.hpp"
#include "magic_number.hpp"
#include "msh_builder.hpp"
#include "type_pun.hpp"
#include "ucfb_reader.hpp"

#include "glm/gtc/quaternion.hpp"

namespace {

struct Xframe {
   pod::Mat3 rotation;
   pod::Vec3 position;
};

static_assert(std::is_pod_v<Xframe>);
static_assert(sizeof(Xframe) == 48);

struct Primitive_Data {
   msh::Primitive_type type;
   pod::Vec3 size;
};

static_assert(std::is_pod_v<Primitive_Data>);
static_assert(sizeof(Primitive_Data) == 16);

auto read_primitive(Ucfb_reader& primitives) -> msh::Collision_primitive
{
   msh::Collision_primitive msh_prim;

   primitives.read_child_strict<"NAME"_mn>();

   auto mask = primitives.read_child_strict_optional<"MASK"_mn>();

   if (mask) msh_prim.flags = mask->read_trivial<msh::Collision_flags>();

   msh_prim.parent = primitives.read_child_strict<"PRNT"_mn>().read_string();

   const auto xframe = primitives.read_child_strict<"XFRM"_mn>().read_trivial<Xframe>();

   msh_prim.rotation = glm::quat_cast(glm::mat3{xframe.rotation});
   msh_prim.position = xframe.position;

   const auto data =
      primitives.read_child_strict<"DATA"_mn>().read_trivial<Primitive_Data>();

   msh_prim.type = data.type;
   msh_prim.size = data.size;

   return msh_prim;
}
}

void handle_primitives(Ucfb_reader primitives, msh::Builders_map& builders)
{
   auto info = primitives.read_child_strict<"INFO"_mn>();

   std::string name{info.read_string_unaligned()};
   const auto primitive_count = info.read_trivial<std::int32_t>();

   auto& builder = builders[name];

   for (auto i = 0; i < primitive_count; ++i) {
      builder.add_collision_primitive(read_primitive(primitives));
   }
}<|endoftext|>


<commit_before>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <stdexcept>

#include <nix/hdf5/DataTypeHDF5.hpp>

#include <iostream>
#include <cassert>

namespace nix {
namespace hdf5 {

H5::DataType data_type_to_h5_filetype(DataType dtype) {

    switch (dtype) {

        case DataType::Bool:   return H5::PredType::STD_B8LE;
        case DataType::Int8:   return H5::PredType::STD_I8LE;
        case DataType::Int16:  return H5::PredType::STD_I16LE;
        case DataType::Int32:  return H5::PredType::STD_I32LE;
        case DataType::Int64:  return H5::PredType::STD_I64LE;
        case DataType::UInt8:  return H5::PredType::STD_U8LE;
        case DataType::UInt16: return H5::PredType::STD_U16LE;
        case DataType::UInt32: return H5::PredType::STD_U32LE;
        case DataType::UInt64: return H5::PredType::STD_U64LE;
        case DataType::Float:  return H5::PredType::IEEE_F32LE;
        case DataType::Double: return H5::PredType::IEEE_F64LE;
        case DataType::String: return H5::StrType(H5::PredType::C_S1, H5T_VARIABLE);

        default:
            throw std::invalid_argument("Unkown DataType"); //FIXME
    }

    return H5::DataType();
}

template<size_t>
H5::DataType bool_to_predtype(void) { throw std::invalid_argument("sizeof(bool) > 8 not supported."); };

template<> H5::DataType bool_to_predtype<1>() { return H5::PredType::NATIVE_B8;  }
template<> H5::DataType bool_to_predtype<2>() { return H5::PredType::NATIVE_B16; }
template<> H5::DataType bool_to_predtype<4>() { return H5::PredType::NATIVE_B32; }
template<> H5::DataType bool_to_predtype<8>() { return H5::PredType::NATIVE_B64; }

H5::DataType data_type_to_h5_memtype(DataType dtype) {

    switch(dtype) {
        case DataType::Bool:   return bool_to_predtype<sizeof(bool)>();
        case DataType::Int8:   return H5::PredType::NATIVE_INT8;
        case DataType::Int16:  return H5::PredType::NATIVE_INT16;
        case DataType::Int32:  return H5::PredType::NATIVE_INT32;
        case DataType::Int64:  return H5::PredType::NATIVE_INT64;
        case DataType::UInt8:  return H5::PredType::NATIVE_UINT8;
        case DataType::UInt16: return H5::PredType::NATIVE_UINT16;
        case DataType::UInt32: return H5::PredType::NATIVE_UINT32;
        case DataType::UInt64: return H5::PredType::NATIVE_UINT64;
        case DataType::Float:  return H5::PredType::NATIVE_FLOAT;
        case DataType::Double: return H5::PredType::NATIVE_DOUBLE;
        case DataType::String: return H5::StrType(H5::PredType::C_S1, H5T_VARIABLE);

        default:
            throw std::invalid_argument("DataType not handled!"); //FIXME
    }

    return H5::DataType();
}

#define NOT_IMPLEMENTED false

DataType
data_type_from_h5(H5T_class_t vclass, size_t vsize, H5T_sign_t vsign)
{
    if (vclass == H5T_INTEGER) {
        switch (vsize) {
        case 1: return vsign == H5T_SGN_2 ? DataType::Int8  : DataType::UInt8;
        case 2: return vsign == H5T_SGN_2 ? DataType::Int16 : DataType::UInt16;
        case 4: return vsign == H5T_SGN_2 ? DataType::Int32 : DataType::UInt32;
        case 8: return vsign == H5T_SGN_2 ? DataType::Int64 : DataType::UInt64;
        }
    } else if (vclass == H5T_FLOAT) {
        return vsize == 8 ? DataType::Double : DataType::Float;
    } else if (vclass == H5T_STRING) {
        return DataType::String;
    } else if (vclass == H5T_BITFIELD) {
        switch (vsize) {
        case 1: return DataType::Bool;
        }
    }

    std::cerr << "FIXME: Not implemented " << vclass << " " << vsize << " " << vsign << " " << std::endl;
    assert(NOT_IMPLEMENTED);
    return DataType::Nothing;
}

} // namespace hdf4
} // namespace nix
<commit_msg>data_type_to_h5_*type: explicitly handle all types in switch<commit_after>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <stdexcept>

#include <nix/hdf5/DataTypeHDF5.hpp>

#include <iostream>
#include <cassert>

namespace nix {
namespace hdf5 {

H5::DataType data_type_to_h5_filetype(DataType dtype) {

   /* The switch is structred in a way in order to get
      warnings from the compiler when not all cases are
      handled and throw an exception if one of the not
      handled cases actually appears (i.e., we have no
      default case, because that silences the compiler.)
   */

    switch (dtype) {

        case DataType::Bool:   return H5::PredType::STD_B8LE;
        case DataType::Int8:   return H5::PredType::STD_I8LE;
        case DataType::Int16:  return H5::PredType::STD_I16LE;
        case DataType::Int32:  return H5::PredType::STD_I32LE;
        case DataType::Int64:  return H5::PredType::STD_I64LE;
        case DataType::UInt8:  return H5::PredType::STD_U8LE;
        case DataType::UInt16: return H5::PredType::STD_U16LE;
        case DataType::UInt32: return H5::PredType::STD_U32LE;
        case DataType::UInt64: return H5::PredType::STD_U64LE;
        case DataType::Float:  return H5::PredType::IEEE_F32LE;
        case DataType::Double: return H5::PredType::IEEE_F64LE;
        case DataType::String: return H5::StrType(H5::PredType::C_S1, H5T_VARIABLE);

        case DataType::Char: break; //FIXME
        case DataType::Nothing: break;
        case DataType::Date: break;
        case DataType::DateTime: break;
    }

    throw std::invalid_argument("Unkown DataType"); //FIXME
}

template<size_t>
H5::DataType bool_to_predtype(void) { throw std::invalid_argument("sizeof(bool) > 8 not supported."); };

template<> H5::DataType bool_to_predtype<1>() { return H5::PredType::NATIVE_B8;  }
template<> H5::DataType bool_to_predtype<2>() { return H5::PredType::NATIVE_B16; }
template<> H5::DataType bool_to_predtype<4>() { return H5::PredType::NATIVE_B32; }
template<> H5::DataType bool_to_predtype<8>() { return H5::PredType::NATIVE_B64; }

H5::DataType data_type_to_h5_memtype(DataType dtype) {

    // See data_type_to_h5_filetype for the reason why the switch is structured
    // in the way it is.

    switch(dtype) {
        //special case the bool
        //we treat them as bit fields for now, since hdf5 has no bool support
        //as of 1.8.12
        case DataType::Bool:   return bool_to_predtype<sizeof(bool)>();
        case DataType::Int8:   return H5::PredType::NATIVE_INT8;
        case DataType::Int16:  return H5::PredType::NATIVE_INT16;
        case DataType::Int32:  return H5::PredType::NATIVE_INT32;
        case DataType::Int64:  return H5::PredType::NATIVE_INT64;
        case DataType::UInt8:  return H5::PredType::NATIVE_UINT8;
        case DataType::UInt16: return H5::PredType::NATIVE_UINT16;
        case DataType::UInt32: return H5::PredType::NATIVE_UINT32;
        case DataType::UInt64: return H5::PredType::NATIVE_UINT64;
        case DataType::Float:  return H5::PredType::NATIVE_FLOAT;
        case DataType::Double: return H5::PredType::NATIVE_DOUBLE;
        case DataType::String: return H5::StrType(H5::PredType::C_S1, H5T_VARIABLE);

        case DataType::Char: break; //FIXME
        case DataType::Nothing: break;
        case DataType::Date: break;
        case DataType::DateTime: break;
    }

    throw std::invalid_argument("DataType not handled!"); //FIXME
}

#define NOT_IMPLEMENTED false

DataType
data_type_from_h5(H5T_class_t vclass, size_t vsize, H5T_sign_t vsign)
{
    if (vclass == H5T_INTEGER) {
        switch (vsize) {
        case 1: return vsign == H5T_SGN_2 ? DataType::Int8  : DataType::UInt8;
        case 2: return vsign == H5T_SGN_2 ? DataType::Int16 : DataType::UInt16;
        case 4: return vsign == H5T_SGN_2 ? DataType::Int32 : DataType::UInt32;
        case 8: return vsign == H5T_SGN_2 ? DataType::Int64 : DataType::UInt64;
        }
    } else if (vclass == H5T_FLOAT) {
        return vsize == 8 ? DataType::Double : DataType::Float;
    } else if (vclass == H5T_STRING) {
        return DataType::String;
    } else if (vclass == H5T_BITFIELD) {
        switch (vsize) {
        case 1: return DataType::Bool;
        }
    }

    std::cerr << "FIXME: Not implemented " << vclass << " " << vsize << " " << vsign << " " << std::endl;
    assert(NOT_IMPLEMENTED);
    return DataType::Nothing;
}

} // namespace hdf4
} // namespace nix
<|endoftext|>


<commit_before>#include <iostream>
#include <stdlib.h>

using namespace std;

void options();

int main()
{
    cout<<"line has been cut"<<endl;
    options();
    return(0);
}

void temp()

void otheroptions(){
    int input;
    {
        cout << "Please select an option:" << endl
        << "1.love oskars " << endl
        << "2.Go to neighbours " << endl
        << "3.Hide " << endl
        << "4.Shout for help " << endl;
        cin >> input;

       switch(input)
       {
           case 1:
               cout<<"love oskars"<< endl;
               break;

       }

    }
}

void options()
{
    int input;

    {
        cout << "Please select an option:" << endl
        << "1.Search the house " << endl
        << "2.Go to neighbours " << endl
        << "3.Hide " << endl;
        cin >> input;

       switch(input)
       {
           case 0:
               exit(0);
           case 1:
               cout << "Search the house" << endl;
               otheroptions();

               break;
           case 2:
               cout << "Go to neighbours" << endl;
               break;
           case 3:
               cout << "Hide " << endl;

               break;
           case 4:
               cout << "Shout for help" <<endl;
               break;
           default:
               cout<<"invalid option please choose between 1 and 4"<< endl;
         }

       }
}

<commit_msg>call family updated-ak<commit_after>#include <iostream>
#include <stdlib.h>

using namespace std;

void options();

int main()
{
    cout<<"line has been cut"<<endl;
    options();
    return(0);
}

void idiot()
{
    int input;
    {
        cout << "You die, from a zombie attack bet you wished you had a weapon to defend yourself" <<endl;
        cout << "GAME OVER"<< endl;
    }
}

void temp(){
    int input;
    {
        cout << "9mm Pistol has been added to you're inventory" <<endl;
        cout << "Please select an option:" << endl
        << "1. Go outside " << endl
        << "2.Shout for help " << endl;
        cin >> input;

       switch(input)
       {
           case 1:
               cout<<"Go outside"<< endl;
               break;
           case 2:
               cout<<"Shout for help"<< endl;
               break;

       }

    }
}

void otheroptions()
{
    int input;
    {
        cout << "You've found a pistol" << endl;
        cout << "Please select an option:" << endl;
        cout<< "1.Pick up pistol" << endl;
        cout<< "2.Leave Pistol " << endl;
        cin >> input;

       switch(input)
       {
           case 1:
               cout<<"Pick up pistol"<< endl;
               temp();
               break;
           case 2:
               cout<<"Leave pistol"<< endl;
               idiot();
               break;

       }

    }
}

void options()
{
    int input;

    {
        cout << "Please select an option:" << endl
        << "1.Search the house " << endl
        << "2.Go to neighbours " << endl
        << "3.Hide " << endl;
        cin >> input;

       switch(input)
       {
           case 0:
               exit(0);
           case 1:
               cout << "Search the house" << endl;
               otheroptions();

               break;
           case 2:
               cout << "Go to neighbours" << endl;
               break;
           case 3:
               cout << "Hide " << endl;
               cout << "you die from starvation" << endl;
               cout << "GAME OVER" << endl;
               break;
           default:
               cout<<"invalid option please choose between 1 and 4"<< endl;
         }

       }
}

<|endoftext|>