<commit_before>/* vim: set ft=cpp fenc=utf-8 sw=2 ts=2 et: */
/*
 * Copyright (c) 2013 Chongyu Zhu <lembacon@gmail.com>
 *
 * 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 <stdlib.h>
#include <stdio.h>
#include <dirent.h>
#include <getopt.h>
#include <unistd.h>
#include <pthread.h>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include "Defines.h"
#include "TagFormatter.h"
#include "Configuration.h"
#include "ClangTool.h"
#include "ClangFrontendAction.h"

static int flag_recursive = 0;

static struct option options[] = {
  { "file", required_argument, NULL, 'f' },
  { "recursive", no_argument, &flag_recursive, 1 },
  { "vim-conf", no_argument, NULL, 0 },
  { "version", no_argument, NULL, 'v' },
  { "help", no_argument, NULL, 'h' },
  { NULL, 0, NULL, 0 }
};

static void usage(void) {
  std::ostringstream os;
  os << "Usage: " << OBJCTAGS_PROGRAM_NAME << " [options] [file(s)]\n";
  os << "\n";
  os << "  -f, --file [FILE]  Output file. '-' for stdout.\n";
  os << "  -r, --recursive    Recursively search for source files\n";
  os << "      --vim-conf     Show vim conf for TagBar\n";
  os << "  -v, --version      Show version\n";
  os << "  -h, --help         Show help\n";
  fprintf(stderr, "%s\n", os.str().c_str());
}

static void version(void) {
  fprintf(stderr, "%s %s\n", OBJCTAGS_PROGRAM_NAME, OBJCTAGS_PROGRAM_VERSION);
}

static void vim_conf(void) {
  printf("%s\n", objctags::tagbarConfigurations().c_str());
}

struct ThreadInfo {
  pthread_t thread;
  pthread_mutex_t *tagFormatterMutex;
  objctags::TagFormatter *tagFormatter;
  std::vector<std::string> sourceFiles;
};

static void *threadMain(void *data) {
  ThreadInfo *threadInfo = (ThreadInfo *)data;
  for (size_t i = 0; i < threadInfo->sourceFiles.size(); i++) {
    objctags::Configuration config;
    //config.setSourceType(objctags::getSourceTypeForFileName(threadInfo->sourceFiles[i]));
    config.setSourceType("objective-c++");

    objctags::TagInfoVector tagInfoVector;
    objctags::runClangToolOnCodeWithArgs(new objctags::ClangFrontendAction(tagInfoVector),
                                         objctags::readFile(threadInfo->sourceFiles[i]),
                                         config.getClangArgs(),
                                         threadInfo->sourceFiles[i]);

    pthread_mutex_lock(threadInfo->tagFormatterMutex);
    threadInfo->tagFormatter->merge(tagInfoVector);
    pthread_mutex_unlock(threadInfo->tagFormatterMutex);
  }
  return NULL;
}

int main(int argc, char **argv) {
  int ch;
  int opt_index;
  std::string file = "tags";

  if (argc == 1) {
    usage();
    exit(EXIT_SUCCESS);
  }

  while ((ch = getopt_long(argc, argv, "f:rvh", options, &opt_index)) != -1) {
    switch (ch) {
      case 0:
        if (opt_index == 2) {
          vim_conf();
          exit(EXIT_SUCCESS);
        }
        break;

      case 'f':
        file = optarg;
        break;

      case 'r':
        flag_recursive = 1;
        break;

      case 'v':
        version();
        exit(EXIT_SUCCESS);

      case 'h':
        usage();
        exit(EXIT_SUCCESS);

      case '?':
        usage();
        exit(EXIT_FAILURE);

      default:
        abort();
    }
  }

  argc -= optind;
  argv += optind;

  std::vector<std::string> sourceFiles;

  if (flag_recursive) {
    std::string directory;
    if (argc > 0) {
      directory = argv[0];
    }
    else {
      directory = ".";
    }

    std::string expandedDir = objctags::expandPath(directory);
    DIR *dir = opendir(expandedDir.c_str());
    if (dir == NULL) {
      fprintf(stderr, "'%s' is not a valid directory\n", directory.c_str());
      exit(EXIT_FAILURE);
    }
    else {
      closedir(dir);
    }

    sourceFiles = objctags::recursivelySearchSourceFiles(expandedDir);
  }
  else {
    if (argc == 0) {
      fprintf(stderr, "missing input directory or files\n");
      exit(EXIT_FAILURE);
    }

    for (int i = 0; i < argc; i++) {
      sourceFiles.push_back(objctags::expandPath(argv[i]));
    }
  }

  objctags::TagFormatter tagFormatter;
  pthread_mutex_t tagFormatterMutex;
  pthread_mutex_init(&tagFormatterMutex, NULL);

  size_t threadCount = sysconf(_SC_NPROCESSORS_ONLN);
  ThreadInfo *threads = new ThreadInfo[threadCount];

  size_t perThreadSFCount = sourceFiles.size() / threadCount;
  size_t remainingSFCount = sourceFiles.size() % threadCount;

  for (size_t i = 0; i < threadCount; i++) {
    threads[i].tagFormatterMutex = &tagFormatterMutex;
    threads[i].tagFormatter = &tagFormatter;
    std::vector<std::string>::iterator startIterator = sourceFiles.begin() + i * perThreadSFCount;
    threads[i].sourceFiles.insert(threads[i].sourceFiles.begin(), startIterator, startIterator + perThreadSFCount);
  }
  for (size_t i = 0; i < remainingSFCount; i++) {
    threads[i].sourceFiles.push_back(sourceFiles[sourceFiles.size() - remainingSFCount + i]);
  }

  for (size_t i = 0; i < threadCount; i++) {
    pthread_create(&threads[i].thread, NULL, threadMain, &threads[i]);
  }
  for (size_t i = 0; i < threadCount; i++) {
    pthread_join(threads[i].thread, NULL);
  }

  pthread_mutex_destroy(&tagFormatterMutex);
  delete[] threads;

  if (file == "-") {
    printf("%s\n", tagFormatter.str().c_str());
  }
  else {
    std::ofstream fs(objctags::expandPath(file).c_str());
    fs << tagFormatter.str() << "\n";
  }

  return 0;
}
<commit_msg>recursive flag should be '-R' rather than '-r'<commit_after>/* vim: set ft=cpp fenc=utf-8 sw=2 ts=2 et: */
/*
 * Copyright (c) 2013 Chongyu Zhu <lembacon@gmail.com>
 *
 * 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 <stdlib.h>
#include <stdio.h>
#include <dirent.h>
#include <getopt.h>
#include <unistd.h>
#include <pthread.h>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include "Defines.h"
#include "TagFormatter.h"
#include "Configuration.h"
#include "ClangTool.h"
#include "ClangFrontendAction.h"

static int flag_recursive = 0;

static struct option options[] = {
  { "file", required_argument, NULL, 'f' },
  { "recursive", no_argument, &flag_recursive, 1 },
  { "vim-conf", no_argument, NULL, 0 },
  { "version", no_argument, NULL, 'v' },
  { "help", no_argument, NULL, 'h' },
  { NULL, 0, NULL, 0 }
};

static void usage(void) {
  std::ostringstream os;
  os << "Usage: " << OBJCTAGS_PROGRAM_NAME << " [options] [file(s)]\n";
  os << "\n";
  os << "  -f, --file [FILE]  Output file. '-' for stdout.\n";
  os << "  -R, --recursive    Recursively search for source files\n";
  os << "      --vim-conf     Show vim conf for TagBar\n";
  os << "  -v, --version      Show version\n";
  os << "  -h, --help         Show help\n";
  fprintf(stderr, "%s\n", os.str().c_str());
}

static void version(void) {
  fprintf(stderr, "%s %s\n", OBJCTAGS_PROGRAM_NAME, OBJCTAGS_PROGRAM_VERSION);
}

static void vim_conf(void) {
  printf("%s\n", objctags::tagbarConfigurations().c_str());
}

struct ThreadInfo {
  pthread_t thread;
  pthread_mutex_t *tagFormatterMutex;
  objctags::TagFormatter *tagFormatter;
  std::vector<std::string> sourceFiles;
};

static void *threadMain(void *data) {
  ThreadInfo *threadInfo = (ThreadInfo *)data;
  for (size_t i = 0; i < threadInfo->sourceFiles.size(); i++) {
    objctags::Configuration config;
    //config.setSourceType(objctags::getSourceTypeForFileName(threadInfo->sourceFiles[i]));
    config.setSourceType("objective-c++");

    objctags::TagInfoVector tagInfoVector;
    objctags::runClangToolOnCodeWithArgs(new objctags::ClangFrontendAction(tagInfoVector),
                                         objctags::readFile(threadInfo->sourceFiles[i]),
                                         config.getClangArgs(),
                                         threadInfo->sourceFiles[i]);

    pthread_mutex_lock(threadInfo->tagFormatterMutex);
    threadInfo->tagFormatter->merge(tagInfoVector);
    pthread_mutex_unlock(threadInfo->tagFormatterMutex);
  }
  return NULL;
}

int main(int argc, char **argv) {
  int ch;
  int opt_index;
  std::string file = "tags";

  if (argc == 1) {
    usage();
    exit(EXIT_SUCCESS);
  }

  while ((ch = getopt_long(argc, argv, "f:rvh", options, &opt_index)) != -1) {
    switch (ch) {
      case 0:
        if (opt_index == 2) {
          vim_conf();
          exit(EXIT_SUCCESS);
        }
        break;

      case 'f':
        file = optarg;
        break;

      case 'R':
        flag_recursive = 1;
        break;

      case 'v':
        version();
        exit(EXIT_SUCCESS);

      case 'h':
        usage();
        exit(EXIT_SUCCESS);

      case '?':
        usage();
        exit(EXIT_FAILURE);

      default:
        abort();
    }
  }

  argc -= optind;
  argv += optind;

  std::vector<std::string> sourceFiles;

  if (flag_recursive) {
    std::string directory;
    if (argc > 0) {
      directory = argv[0];
    }
    else {
      directory = ".";
    }

    std::string expandedDir = objctags::expandPath(directory);
    DIR *dir = opendir(expandedDir.c_str());
    if (dir == NULL) {
      fprintf(stderr, "'%s' is not a valid directory\n", directory.c_str());
      exit(EXIT_FAILURE);
    }
    else {
      closedir(dir);
    }

    sourceFiles = objctags::recursivelySearchSourceFiles(expandedDir);
  }
  else {
    if (argc == 0) {
      fprintf(stderr, "missing input directory or files\n");
      exit(EXIT_FAILURE);
    }

    for (int i = 0; i < argc; i++) {
      sourceFiles.push_back(objctags::expandPath(argv[i]));
    }
  }

  objctags::TagFormatter tagFormatter;
  pthread_mutex_t tagFormatterMutex;
  pthread_mutex_init(&tagFormatterMutex, NULL);

  size_t threadCount = sysconf(_SC_NPROCESSORS_ONLN);
  ThreadInfo *threads = new ThreadInfo[threadCount];

  size_t perThreadSFCount = sourceFiles.size() / threadCount;
  size_t remainingSFCount = sourceFiles.size() % threadCount;

  for (size_t i = 0; i < threadCount; i++) {
    threads[i].tagFormatterMutex = &tagFormatterMutex;
    threads[i].tagFormatter = &tagFormatter;
    std::vector<std::string>::iterator startIterator = sourceFiles.begin() + i * perThreadSFCount;
    threads[i].sourceFiles.insert(threads[i].sourceFiles.begin(), startIterator, startIterator + perThreadSFCount);
  }
  for (size_t i = 0; i < remainingSFCount; i++) {
    threads[i].sourceFiles.push_back(sourceFiles[sourceFiles.size() - remainingSFCount + i]);
  }

  for (size_t i = 0; i < threadCount; i++) {
    pthread_create(&threads[i].thread, NULL, threadMain, &threads[i]);
  }
  for (size_t i = 0; i < threadCount; i++) {
    pthread_join(threads[i].thread, NULL);
  }

  pthread_mutex_destroy(&tagFormatterMutex);
  delete[] threads;

  if (file == "-") {
    printf("%s\n", tagFormatter.str().c_str());
  }
  else {
    std::ofstream fs(objctags::expandPath(file).c_str());
    fs << tagFormatter.str() << "\n";
  }

  return 0;
}
<|endoftext|>


<commit_before>#include "chainparams.h"
#include "options.h"
#include "util.h"
#include <stdexcept>
#include <boost/thread.hpp>

static std::unique_ptr<ArgGetter> Args;

struct DefaultGetter : public ArgGetter {
    virtual bool GetBool(const std::string& arg, bool def) {
        return ::GetBoolArg(arg, def);
    }
    virtual std::vector<std::string> GetMultiArgs(const std::string& arg) {
        if (!mapMultiArgs.count(arg))
            return std::vector<std::string>();

        return mapMultiArgs[arg];
    }
    virtual int64_t GetArg(const std::string& strArg, int64_t nDefault) {
        return ::GetArg(strArg, nDefault);
    }
};

Opt::Opt() {
    if (!bool(Args.get()))
        Args.reset(new DefaultGetter());
}

bool Opt::IsStealthMode() {
    return Args->GetBool("-stealth-mode", false);
}

bool Opt::HidePlatform() {
    return Args->GetBool("-hide-platform", false);
}

std::vector<std::string> Opt::UAComment(bool validate) {
    std::vector<std::string> uacomments = Args->GetMultiArgs("-uacomment");
    if (!validate)
        return uacomments;

    typedef std::vector<std::string>::const_iterator auto_;
    for (auto_ c = uacomments.begin(); c != uacomments.end(); ++c) {
        size_t pos = c->find_first_of("/:()");
        if (pos == std::string::npos)
            continue;
        std::stringstream ss;
        ss << "-uacomment '" << *c << "' contains the reserved character '"
            << c->at(pos) << "'.The following characters are reserved: / : ( )";
        throw std::invalid_argument(ss.str());
    }

    return uacomments;
}

int Opt::ScriptCheckThreads() {
    // -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency
    int nScriptCheckThreads = Args->GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS);
    if (nScriptCheckThreads <= 0)
        nScriptCheckThreads += GetNumCores();
    if (nScriptCheckThreads <= 1)
        nScriptCheckThreads = 0;
    else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS)
        nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS;
    return nScriptCheckThreads;
}

int64_t Opt::CheckpointDays() {
    int64_t def = DEFAULT_CHECKPOINT_DAYS * std::max(1, ScriptCheckThreads());
    return std::max(int64_t(1), Args->GetArg("-checkpoint-days", def));
}

uint64_t Opt::MaxBlockSizeVote() {
    return Args->GetArg("-maxblocksizevote", 0);
}

int64_t Opt::UAHFTime() const {
    int64_t defaultUAHFTime = Params().NetworkIDString() == CBaseChainParams::REGTEST ?
                              Params().GenesisBlock().nTime :
                              UAHF_DEFAULT_ACTIVATION_TIME;

    return Args->GetArg("-uahftime", defaultUAHFTime);
}

int Opt::UAHFProtectSunset() {
    return Args->GetArg("-uahfprotectsunset", UAHF_DEFAULT_PROTECT_THIS_SUNSET);
}

int64_t Opt::RespendRelayLimit() const {
    return Args->GetArg("-limitrespendrelay", 100);
}

bool Opt::UseCashAddr() const {
    return Args->GetBool("-usecashaddr", bool(UAHFTime()));
}

bool Opt::UsingThinBlocks() {
    if (IsStealthMode())
        return false;
    return Args->GetBool("-use-thin-blocks", true);
}

/// Don't request blocks from nodes that don't support thin blocks.
bool Opt::AvoidFullBlocks() {
    return Args->GetArg("-use-thin-blocks", 1) == 2
        || Args->GetArg("-use-thin-blocks", 1) == 3;
}

int Opt::ThinBlocksMaxParallel() {
    return Args->GetArg("-thin-blocks-max-parallel", 3);
}

bool Opt::PreferXThinBlocks() const {
    return Args->GetBool("-prefer-xthin-blocks", false);
}

std::unique_ptr<ArgReset> SetDummyArgGetter(std::unique_ptr<ArgGetter> getter) {
    Args.reset(getter.release());
    return std::unique_ptr<ArgReset>(new ArgReset);
}

ArgReset::~ArgReset() {
    Args.reset(new DefaultGetter());
}

bool DummyArgGetter::GetBool(const std::string& arg, bool def) {
    return customArgs.count(arg) ? bool(customArgs[arg]) : def;
}

std::vector<std::string> DummyArgGetter::GetMultiArgs(const std::string&) {
    assert(!"not supported");
}

int64_t DummyArgGetter::GetArg(const std::string& arg, int64_t def) {
    return customArgs.count(arg) ? customArgs[arg] : def;
}

void DummyArgGetter::Set(const std::string& arg, int64_t val) {
    customArgs[arg] = val;
}
<commit_msg>Check CPU core count once only<commit_after>#include "chainparams.h"
#include "options.h"
#include "util.h"
#include <stdexcept>
#include <boost/thread.hpp>

static std::unique_ptr<ArgGetter> Args;

struct DefaultGetter : public ArgGetter {
    virtual bool GetBool(const std::string& arg, bool def) {
        return ::GetBoolArg(arg, def);
    }
    virtual std::vector<std::string> GetMultiArgs(const std::string& arg) {
        if (!mapMultiArgs.count(arg))
            return std::vector<std::string>();

        return mapMultiArgs[arg];
    }
    virtual int64_t GetArg(const std::string& strArg, int64_t nDefault) {
        return ::GetArg(strArg, nDefault);
    }
};

Opt::Opt() {
    if (!bool(Args.get()))
        Args.reset(new DefaultGetter());
}

bool Opt::IsStealthMode() {
    return Args->GetBool("-stealth-mode", false);
}

bool Opt::HidePlatform() {
    return Args->GetBool("-hide-platform", false);
}

std::vector<std::string> Opt::UAComment(bool validate) {
    std::vector<std::string> uacomments = Args->GetMultiArgs("-uacomment");
    if (!validate)
        return uacomments;

    typedef std::vector<std::string>::const_iterator auto_;
    for (auto_ c = uacomments.begin(); c != uacomments.end(); ++c) {
        size_t pos = c->find_first_of("/:()");
        if (pos == std::string::npos)
            continue;
        std::stringstream ss;
        ss << "-uacomment '" << *c << "' contains the reserved character '"
            << c->at(pos) << "'.The following characters are reserved: / : ( )";
        throw std::invalid_argument(ss.str());
    }

    return uacomments;
}

int Opt::ScriptCheckThreads() {
    // -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency
    int nScriptCheckThreads = Args->GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS);
    if (nScriptCheckThreads <= 0) {
        static int numCores = GetNumCores();
        nScriptCheckThreads += numCores;
    }
    if (nScriptCheckThreads <= 1)
        nScriptCheckThreads = 0;
    else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS)
        nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS;
    return nScriptCheckThreads;
}

int64_t Opt::CheckpointDays() {
    int64_t def = DEFAULT_CHECKPOINT_DAYS * std::max(1, ScriptCheckThreads());
    return std::max(int64_t(1), Args->GetArg("-checkpoint-days", def));
}

uint64_t Opt::MaxBlockSizeVote() {
    return Args->GetArg("-maxblocksizevote", 0);
}

int64_t Opt::UAHFTime() const {
    int64_t defaultUAHFTime = Params().NetworkIDString() == CBaseChainParams::REGTEST ?
                              Params().GenesisBlock().nTime :
                              UAHF_DEFAULT_ACTIVATION_TIME;

    return Args->GetArg("-uahftime", defaultUAHFTime);
}

int Opt::UAHFProtectSunset() {
    return Args->GetArg("-uahfprotectsunset", UAHF_DEFAULT_PROTECT_THIS_SUNSET);
}

int64_t Opt::RespendRelayLimit() const {
    return Args->GetArg("-limitrespendrelay", 100);
}

bool Opt::UseCashAddr() const {
    return Args->GetBool("-usecashaddr", bool(UAHFTime()));
}

bool Opt::UsingThinBlocks() {
    if (IsStealthMode())
        return false;
    return Args->GetBool("-use-thin-blocks", true);
}

/// Don't request blocks from nodes that don't support thin blocks.
bool Opt::AvoidFullBlocks() {
    return Args->GetArg("-use-thin-blocks", 1) == 2
        || Args->GetArg("-use-thin-blocks", 1) == 3;
}

int Opt::ThinBlocksMaxParallel() {
    return Args->GetArg("-thin-blocks-max-parallel", 3);
}

bool Opt::PreferXThinBlocks() const {
    return Args->GetBool("-prefer-xthin-blocks", false);
}

std::unique_ptr<ArgReset> SetDummyArgGetter(std::unique_ptr<ArgGetter> getter) {
    Args.reset(getter.release());
    return std::unique_ptr<ArgReset>(new ArgReset);
}

ArgReset::~ArgReset() {
    Args.reset(new DefaultGetter());
}

bool DummyArgGetter::GetBool(const std::string& arg, bool def) {
    return customArgs.count(arg) ? bool(customArgs[arg]) : def;
}

std::vector<std::string> DummyArgGetter::GetMultiArgs(const std::string&) {
    assert(!"not supported");
}

int64_t DummyArgGetter::GetArg(const std::string& arg, int64_t def) {
    return customArgs.count(arg) ? customArgs[arg] : def;
}

void DummyArgGetter::Set(const std::string& arg, int64_t val) {
    customArgs[arg] = val;
}
<|endoftext|>


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

#pragma once

#ifndef NDK_SERVER
#ifndef NDK_COMPONENTS_GRAPHICSCOMPONENT_HPP
#define NDK_COMPONENTS_GRAPHICSCOMPONENT_HPP

#include <Nazara/Graphics/InstancedRenderable.hpp>
#include <Nazara/Utility/Node.hpp>
#include <NDK/Component.hpp>

namespace Ndk
{
	class GraphicsComponent;

	using GraphicsComponentHandle = Nz::ObjectHandle<GraphicsComponent>;

	class NDK_API GraphicsComponent : public Component<GraphicsComponent>, public Nz::HandledObject<GraphicsComponent>
	{
		friend class RenderSystem;

		public:
			using RenderableList = std::vector<Nz::InstancedRenderableRef>;

			GraphicsComponent() = default;
			inline GraphicsComponent(const GraphicsComponent& graphicsComponent);
			~GraphicsComponent() = default;

			inline void AddToRenderQueue(Nz::AbstractRenderQueue* renderQueue) const;

			inline void Attach(Nz::InstancedRenderableRef renderable, int renderOrder = 0);

			inline void Clear();

			inline void Detach(const Nz::InstancedRenderableRef& renderable);

			inline void EnsureBoundingVolumeUpdate() const;
			inline void EnsureTransformMatrixUpdate() const;

			inline void GetAttachedRenderables(Nz::InstancedRenderableRef* renderables) const;
			inline std::size_t GetAttachedRenderableCount() const;

			inline const Nz::BoundingVolumef& GetBoundingVolume() const;

			static ComponentIndex componentIndex;

		private:
			inline void InvalidateBoundingVolume();
			void InvalidateRenderableData(const Nz::InstancedRenderable* renderable, Nz::UInt32 flags, std::size_t index);
			inline void InvalidateRenderables();
			inline void InvalidateTransformMatrix();

			void OnAttached() override;
			void OnComponentAttached(BaseComponent& component) override;
			void OnComponentDetached(BaseComponent& component) override;
			void OnDetached() override;
			void OnNodeInvalidated(const Nz::Node* node);

			void UpdateBoundingVolume() const;
			void UpdateTransformMatrix() const;

			NazaraSlot(Nz::Node, OnNodeInvalidation, m_nodeInvalidationSlot);

			struct Renderable
			{
				Renderable(Nz::Matrix4f& transformMatrix) :
				data(transformMatrix),
				dataUpdated(false)
				{
				}

				Renderable(Renderable&& renderable) noexcept :
				data(std::move(renderable.data)),
				renderable(std::move(renderable.renderable)),
				dataUpdated(renderable.dataUpdated)
				{
				}

				Renderable& operator=(Renderable&& r) noexcept
				{
					data = std::move(r.data);
					dataUpdated = r.dataUpdated;
					renderable = std::move(r.renderable);

					return *this;
				}

				NazaraSlot(Nz::InstancedRenderable, OnInstancedRenderableInvalidateData, renderableInvalidationSlot);

				mutable Nz::InstancedRenderable::InstanceData data;
				Nz::InstancedRenderableRef renderable;
				mutable bool dataUpdated;
			};

			std::vector<Renderable> m_renderables;
			mutable Nz::BoundingVolumef m_boundingVolume;
			mutable Nz::Matrix4f m_transformMatrix;
			mutable bool m_boundingVolumeUpdated;
			mutable bool m_transformMatrixUpdated;
	};
}

#include <NDK/Components/GraphicsComponent.inl>

#endif // NDK_COMPONENTS_GRAPHICSCOMPONENT_HPP
#endif // NDK_SERVER<commit_msg>Fix typo<commit_after>// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp

#pragma once

#ifndef NDK_SERVER
#ifndef NDK_COMPONENTS_GRAPHICSCOMPONENT_HPP
#define NDK_COMPONENTS_GRAPHICSCOMPONENT_HPP

#include <Nazara/Graphics/InstancedRenderable.hpp>
#include <Nazara/Utility/Node.hpp>
#include <NDK/Component.hpp>

namespace Ndk
{
	class GraphicsComponent;

	using GraphicsComponentHandle = Nz::ObjectHandle<GraphicsComponent>;

	class NDK_API GraphicsComponent : public Component<GraphicsComponent>, public Nz::HandledObject<GraphicsComponent>
	{
		friend class RenderSystem;

		public:
			using RenderableList = std::vector<Nz::InstancedRenderableRef>;

			GraphicsComponent() = default;
			inline GraphicsComponent(const GraphicsComponent& graphicsComponent);
			~GraphicsComponent() = default;

			inline void AddToRenderQueue(Nz::AbstractRenderQueue* renderQueue) const;

			inline void Attach(Nz::InstancedRenderableRef renderable, int renderOrder = 0);

			inline void Clear();

			inline void Detach(const Nz::InstancedRenderableRef& renderable);

			inline void EnsureBoundingVolumeUpdate() const;
			inline void EnsureTransformMatrixUpdate() const;

			inline void GetAttachedRenderables(RenderableList* renderables) const;
			inline std::size_t GetAttachedRenderableCount() const;

			inline const Nz::BoundingVolumef& GetBoundingVolume() const;

			static ComponentIndex componentIndex;

		private:
			inline void InvalidateBoundingVolume();
			void InvalidateRenderableData(const Nz::InstancedRenderable* renderable, Nz::UInt32 flags, std::size_t index);
			inline void InvalidateRenderables();
			inline void InvalidateTransformMatrix();

			void OnAttached() override;
			void OnComponentAttached(BaseComponent& component) override;
			void OnComponentDetached(BaseComponent& component) override;
			void OnDetached() override;
			void OnNodeInvalidated(const Nz::Node* node);

			void UpdateBoundingVolume() const;
			void UpdateTransformMatrix() const;

			NazaraSlot(Nz::Node, OnNodeInvalidation, m_nodeInvalidationSlot);

			struct Renderable
			{
				Renderable(Nz::Matrix4f& transformMatrix) :
				data(transformMatrix),
				dataUpdated(false)
				{
				}

				Renderable(Renderable&& renderable) noexcept :
				data(std::move(renderable.data)),
				renderable(std::move(renderable.renderable)),
				dataUpdated(renderable.dataUpdated)
				{
				}

				Renderable& operator=(Renderable&& r) noexcept
				{
					data = std::move(r.data);
					dataUpdated = r.dataUpdated;
					renderable = std::move(r.renderable);

					return *this;
				}

				NazaraSlot(Nz::InstancedRenderable, OnInstancedRenderableInvalidateData, renderableInvalidationSlot);

				mutable Nz::InstancedRenderable::InstanceData data;
				Nz::InstancedRenderableRef renderable;
				mutable bool dataUpdated;
			};

			std::vector<Renderable> m_renderables;
			mutable Nz::BoundingVolumef m_boundingVolume;
			mutable Nz::Matrix4f m_transformMatrix;
			mutable bool m_boundingVolumeUpdated;
			mutable bool m_transformMatrixUpdated;
	};
}

#include <NDK/Components/GraphicsComponent.inl>

#endif // NDK_COMPONENTS_GRAPHICSCOMPONENT_HPP
#endif // NDK_SERVER<|endoftext|>


<commit_before>/* -------------------------------------------------------------------------- *
 *                      SimTK Core: SimTK Simbody(tm)                         *
 * -------------------------------------------------------------------------- *
 * This is part of the SimTK Core biosimulation toolkit originating from      *
 * Simbios, the NIH National Center for Physics-Based Simulation of           *
 * Biological Structures at Stanford, funded under the NIH Roadmap for        *
 * Medical Research, grant U54 GM072970. See https://simtk.org.               *
 *                                                                            *
 * Portions copyright (c) 2011 Stanford University and the Authors.           *
 * Authors: Peter Eastman                                                     *
 * Contributors:                                                              *
 *                                                                            *
 * 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, CONTRIBUTORS 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 "SimTKsimbody.h"
#include <ctime>

using std::cout;
using std::endl;

using namespace SimTK;

/**
 * This test measures the speed of various multibody calculations.  It executes a collection of operations
 * on various systems.  The CPU time required to perform each operation 1000 times is measured and
 * printed to the console.
 *
 * Each test system contains 256 identical bodies (plus ground), but they differ in the type of
 * bodies and their arrangement into a multibody tree.  The arrangements include 1) all bodies attached
 * directly to ground, 2) the bodies linked in a single chain, and 3) the bodies arranged to form
 * a binary tree.
 */

// The following routines define the operations to be profiled.

void doRealizePosition(MultibodySystem& system, State& state) {
    state.invalidateAllCacheAtOrAbove(Stage::Time);
    system.realize(state, Stage::Position);
}

void doRealizeVelocity(MultibodySystem& system, State& state) {
    state.invalidateAllCacheAtOrAbove(Stage::Time);
    system.realize(state, Stage::Velocity);
}

void doRealizeAcceleration(MultibodySystem& system, State& state) {
    state.invalidateAllCacheAtOrAbove(Stage::Time);
    system.realize(state, Stage::Acceleration);
}

void doCalcMV(MultibodySystem& system, State& state) {
    const SimbodyMatterSubsystem& matter = system.getMatterSubsystem();
    Vector v(matter.getNumMobilities());
    Vector mv;
    matter.calcMV(state, v, mv);
}

void doCalcMInverseV(MultibodySystem& system, State& state) {
    const SimbodyMatterSubsystem& matter = system.getMatterSubsystem();
    Vector v(matter.getNumMobilities());
    Vector minvv;
    matter.calcMInverseV(state, v, minvv);
}

void doCalcResidualForceIgnoringConstraints(MultibodySystem& system, State& state) {
    const SimbodyMatterSubsystem& matter = system.getMatterSubsystem();
    Vector appliedMobilityForces(matter.getNumMobilities());
    Vector_<SpatialVec> appliedBodyForces(matter.getNumBodies());
    Vector knownUdot, residualMobilityForces;
    matter.calcResidualForceIgnoringConstraints(state, appliedMobilityForces, appliedBodyForces, knownUdot, residualMobilityForces);
}

void doCalcMobilizerReactionForces(MultibodySystem& system, State& state) {
    Vector_<SpatialVec> forces;
    system.getMatterSubsystem().calcMobilizerReactionForces(state, forces);
}

void doCalcInternalGradientFromSpatial(MultibodySystem& system, State& state) {
    const SimbodyMatterSubsystem& matter = system.getMatterSubsystem();
    Vector_<SpatialVec> dEdR(matter.getNumBodies());
    Vector dEdQ;
    matter.calcInternalGradientFromSpatial(state, dEdR, dEdQ);
}

/**
 * Time how long it takes to perform an operation 1000 times.  The test is repeated 5 times,
 * and the average is returned.  The return value represents CPU time, *not* clock time.
 */
Real timeComputation(MultibodySystem& system, void function(MultibodySystem& system, State& state)) {
    const int repeats = 5;
    Vector times(repeats);
    State state = system.getDefaultState();
    system.realize(state, Stage::Acceleration);

    // Repeatedly measure the CPU time for performing the operation 1000 times.

    for (int i = 0; i < repeats; i++) {
        clock_t start = clock();
        for (int j = 0; j < 1000; j++)
            function(system, state);
        clock_t end = clock();
        times[i] = (Real) (end-start)/CLOCKS_PER_SEC;
    }
    return mean(times);
}

/**
 * Time all the different calculations for one system.
 */
void runAllTests(MultibodySystem& system) {
    std::cout << "realizePosition: " << timeComputation(system, doRealizePosition) << std::endl;
    std::cout << "realizeVelocity: " << timeComputation(system, doRealizeVelocity) << std::endl;
    std::cout << "realizeAcceleration: " << timeComputation(system, doRealizeAcceleration) << std::endl;
    std::cout << "calcMV: " << timeComputation(system, doCalcMV) << std::endl;
    std::cout << "calcMInverseV: " << timeComputation(system, doCalcMInverseV) << std::endl;
    std::cout << "calcResidualForceIgnoringConstraints: " << timeComputation(system, doCalcResidualForceIgnoringConstraints) << std::endl;
    std::cout << "calcMobilizerReactionForces: " << timeComputation(system, doCalcMobilizerReactionForces) << std::endl;
    std::cout << "calcInternalGradientFromSpatial: " << timeComputation(system, doCalcInternalGradientFromSpatial) << std::endl;
}

// The following routines create the systems to be profiled.

void createParticles(MultibodySystem& system) {
    SimbodyMatterSubsystem matter(system);
    Body::Rigid body;
    for (int i = 0; i < 256; i++)
        MobilizedBody::Translation next(matter.updGround(), Vec3(1, 0, 0), body, Vec3(0));
    system.realizeTopology();
}

void createFreeBodies(MultibodySystem& system) {
    SimbodyMatterSubsystem matter(system);
    Body::Rigid body;
    for (int i = 0; i < 256; i++)
        MobilizedBody::Free next(matter.updGround(), Vec3(1, 0, 0), body, Vec3(0));
    system.realizeTopology();
}

void createPinChain(MultibodySystem& system) {
    SimbodyMatterSubsystem matter(system);
    Body::Rigid body;
    MobilizedBody last = matter.updGround();
    for (int i = 0; i < 256; i++) {
        MobilizedBody::Pin next(last, Vec3(1, 0, 0), body, Vec3(0));
        last = next;
    }
    system.realizeTopology();
}

void createBallChain(MultibodySystem& system) {
    SimbodyMatterSubsystem matter(system);
    Body::Rigid body;
    MobilizedBody last = matter.updGround();
    for (int i = 0; i < 256; i++) {
        MobilizedBody::Ball next(last, Vec3(1, 0, 0), body, Vec3(0));
        last = next;
    }
    system.realizeTopology();
}

void createPinTree(MultibodySystem& system) {
    SimbodyMatterSubsystem matter(system);
    Body::Rigid body;
    for (int i = 0; i < 256; i++) {
        MobilizedBody& parent = matter.updMobilizedBody(MobilizedBodyIndex(i/2));
        MobilizedBody::Pin next(parent, Vec3(1, 0, 0), body, Vec3(0));
    }
    system.realizeTopology();
}

void createBallTree(MultibodySystem& system) {
    SimbodyMatterSubsystem matter(system);
    Body::Rigid body;
    for (int i = 0; i < 256; i++) {
        MobilizedBody& parent = matter.updMobilizedBody(MobilizedBodyIndex(i/2));
        MobilizedBody::Ball next(parent, Vec3(1, 0, 0), body, Vec3(0));
    }
    system.realizeTopology();
}

int main() {
    {
        std::cout << "\nParticles:\n" << std::endl;
        MultibodySystem system;
        createParticles(system);
        runAllTests(system);
    }
    {
        std::cout << "\nFree Bodies:\n" << std::endl;
        MultibodySystem system;
        createFreeBodies(system);
        runAllTests(system);
    }
    {
        std::cout << "\nPin Chain:\n" << std::endl;
        MultibodySystem system;
        createPinChain(system);
        runAllTests(system);
    }
    {
        std::cout << "\nBall Chain:\n" << std::endl;
        MultibodySystem system;
        createBallChain(system);
        runAllTests(system);
    }
    {
        std::cout << "\nPin Tree:\n" << std::endl;
        MultibodySystem system;
        createPinTree(system);
        runAllTests(system);
    }
    {
        std::cout << "\nBall Tree:\n" << std::endl;
        MultibodySystem system;
        createBallTree(system);
        runAllTests(system);
    }
}<commit_msg>Minor improvements to TestMultibodyPerformance<commit_after>/* -------------------------------------------------------------------------- *
 *                      SimTK Core: SimTK Simbody(tm)                         *
 * -------------------------------------------------------------------------- *
 * This is part of the SimTK Core biosimulation toolkit originating from      *
 * Simbios, the NIH National Center for Physics-Based Simulation of           *
 * Biological Structures at Stanford, funded under the NIH Roadmap for        *
 * Medical Research, grant U54 GM072970. See https://simtk.org.               *
 *                                                                            *
 * Portions copyright (c) 2011 Stanford University and the Authors.           *
 * Authors: Peter Eastman                                                     *
 * Contributors:                                                              *
 *                                                                            *
 * 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, CONTRIBUTORS 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 "SimTKsimbody.h"

using std::cout;
using std::endl;

using namespace SimTK;

/**
 * This test measures the speed of various multibody calculations.  It executes a collection of operations
 * on various systems.  The CPU time required to perform each operation 1000 times is measured and
 * printed to the console.
 *
 * Each test system contains 256 identical bodies (plus ground), but they differ in the type of
 * bodies and their arrangement into a multibody tree.  The arrangements include 1) all bodies attached
 * directly to ground, 2) the bodies linked in a single chain, and 3) the bodies arranged to form
 * a binary tree.
 */

// The following routines define the operations to be profiled.

void doRealizePosition(MultibodySystem& system, State& state) {
    state.invalidateAllCacheAtOrAbove(Stage::Time);
    system.realize(state, Stage::Position);
}

void doRealizeVelocity(MultibodySystem& system, State& state) {
    state.invalidateAllCacheAtOrAbove(Stage::Time);
    system.realize(state, Stage::Velocity);
}

void doRealizeAcceleration(MultibodySystem& system, State& state) {
    state.invalidateAllCacheAtOrAbove(Stage::Time);
    system.realize(state, Stage::Acceleration);
}

void doCalcMV(MultibodySystem& system, State& state) {
    const SimbodyMatterSubsystem& matter = system.getMatterSubsystem();
    Vector v(matter.getNumMobilities(), 1.0);
    Vector mv;
    matter.calcMV(state, v, mv);
}

void doCalcMInverseV(MultibodySystem& system, State& state) {
    const SimbodyMatterSubsystem& matter = system.getMatterSubsystem();
    Vector v(matter.getNumMobilities(), 1.0);
    Vector minvv;
    matter.calcMInverseV(state, v, minvv);
}

void doCalcResidualForceIgnoringConstraints(MultibodySystem& system, State& state) {
    const SimbodyMatterSubsystem& matter = system.getMatterSubsystem();
    Vector appliedMobilityForces(matter.getNumMobilities(), 1.0);
    Vector_<SpatialVec> appliedBodyForces(matter.getNumBodies(), SpatialVec(Vec3(1, 0, 0), Vec3(0, 1, 0)));
    Vector knownUdot, residualMobilityForces;
    matter.calcResidualForceIgnoringConstraints(state, appliedMobilityForces, appliedBodyForces, knownUdot, residualMobilityForces);
}

void doCalcMobilizerReactionForces(MultibodySystem& system, State& state) {
    Vector_<SpatialVec> forces;
    system.getMatterSubsystem().calcMobilizerReactionForces(state, forces);
}

void doCalcInternalGradientFromSpatial(MultibodySystem& system, State& state) {
    const SimbodyMatterSubsystem& matter = system.getMatterSubsystem();
    Vector_<SpatialVec> dEdR(matter.getNumBodies(), SpatialVec(Vec3(1, 0, 0), Vec3(0, 1, 0)));
    Vector dEdQ;
    matter.calcInternalGradientFromSpatial(state, dEdR, dEdQ);
}

/**
 * Time how long it takes to perform an operation 1000 times.  The test is repeated 5 times,
 * and the average is returned.  The return value represents CPU time, *not* clock time.
 */
Real timeComputation(MultibodySystem& system, void function(MultibodySystem& system, State& state)) {
    const int repeats = 5;
    Vector times(repeats);
    State state = system.getDefaultState();
    system.realize(state, Stage::Acceleration);

    // Repeatedly measure the CPU time for performing the operation 1000 times.

    for (int i = 0; i < repeats; i++) {
        Real start = cpuTime();
        for (int j = 0; j < 1000; j++)
            function(system, state);
        Real end = cpuTime();
        times[i] = end-start;
    }
    return mean(times);
}

/**
 * Time all the different calculations for one system.
 */
void runAllTests(MultibodySystem& system) {
    std::cout << "realizePosition: " << timeComputation(system, doRealizePosition) << std::endl;
    std::cout << "realizeVelocity: " << timeComputation(system, doRealizeVelocity) << std::endl;
    std::cout << "realizeAcceleration: " << timeComputation(system, doRealizeAcceleration) << std::endl;
    std::cout << "calcMV: " << timeComputation(system, doCalcMV) << std::endl;
    std::cout << "calcMInverseV: " << timeComputation(system, doCalcMInverseV) << std::endl;
    std::cout << "calcResidualForceIgnoringConstraints: " << timeComputation(system, doCalcResidualForceIgnoringConstraints) << std::endl;
    std::cout << "calcMobilizerReactionForces: " << timeComputation(system, doCalcMobilizerReactionForces) << std::endl;
    std::cout << "calcInternalGradientFromSpatial: " << timeComputation(system, doCalcInternalGradientFromSpatial) << std::endl;
}

// The following routines create the systems to be profiled.

void createParticles(MultibodySystem& system) {
    SimbodyMatterSubsystem matter(system);
    Body::Rigid body;
    for (int i = 0; i < 256; i++)
        MobilizedBody::Translation next(matter.updGround(), Vec3(1, 0, 0), body, Vec3(0));
    system.realizeTopology();
}

void createFreeBodies(MultibodySystem& system) {
    SimbodyMatterSubsystem matter(system);
    Body::Rigid body;
    for (int i = 0; i < 256; i++)
        MobilizedBody::Free next(matter.updGround(), Vec3(1, 0, 0), body, Vec3(0));
    system.realizeTopology();
}

void createPinChain(MultibodySystem& system) {
    SimbodyMatterSubsystem matter(system);
    Body::Rigid body;
    MobilizedBody last = matter.updGround();
    for (int i = 0; i < 256; i++) {
        MobilizedBody::Pin next(last, Vec3(1, 0, 0), body, Vec3(0));
        last = next;
    }
    system.realizeTopology();
}

void createBallChain(MultibodySystem& system) {
    SimbodyMatterSubsystem matter(system);
    Body::Rigid body;
    MobilizedBody last = matter.updGround();
    for (int i = 0; i < 256; i++) {
        MobilizedBody::Ball next(last, Vec3(1, 0, 0), body, Vec3(0));
        last = next;
    }
    system.realizeTopology();
}

void createPinTree(MultibodySystem& system) {
    SimbodyMatterSubsystem matter(system);
    Body::Rigid body;
    for (int i = 0; i < 256; i++) {
        MobilizedBody& parent = matter.updMobilizedBody(MobilizedBodyIndex(i/2));
        MobilizedBody::Pin next(parent, Vec3(1, 0, 0), body, Vec3(0));
    }
    system.realizeTopology();
}

void createBallTree(MultibodySystem& system) {
    SimbodyMatterSubsystem matter(system);
    Body::Rigid body;
    for (int i = 0; i < 256; i++) {
        MobilizedBody& parent = matter.updMobilizedBody(MobilizedBodyIndex(i/2));
        MobilizedBody::Ball next(parent, Vec3(1, 0, 0), body, Vec3(0));
    }
    system.realizeTopology();
}

int main() {
    {
        std::cout << "\nParticles:\n" << std::endl;
        MultibodySystem system;
        createParticles(system);
        runAllTests(system);
    }
    {
        std::cout << "\nFree Bodies:\n" << std::endl;
        MultibodySystem system;
        createFreeBodies(system);
        runAllTests(system);
    }
    {
        std::cout << "\nPin Chain:\n" << std::endl;
        MultibodySystem system;
        createPinChain(system);
        runAllTests(system);
    }
    {
        std::cout << "\nBall Chain:\n" << std::endl;
        MultibodySystem system;
        createBallChain(system);
        runAllTests(system);
    }
    {
        std::cout << "\nPin Tree:\n" << std::endl;
        MultibodySystem system;
        createPinTree(system);
        runAllTests(system);
    }
    {
        std::cout << "\nBall Tree:\n" << std::endl;
        MultibodySystem system;
        createBallTree(system);
        runAllTests(system);
    }
}<|endoftext|>


<commit_before>// Ouzel by Elviss Strazdins

#pragma push_macro("WIN32_LEAN_AND_MEAN")
#pragma push_macro("NOMINMAX")
#ifndef WIN32_LEAN_AND_MEAN
#  define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#  define NOMINMAX
#endif
#include <Windows.h>
#include <WbemIdl.h>
#include <OleAuto.h>
#pragma pop_macro("WIN32_LEAN_AND_MEAN")
#pragma pop_macro("NOMINMAX")

#include "InputSystemWin.hpp"
#include "DIErrorCategory.hpp"
#include "GamepadDeviceDI.hpp"
#include "GamepadDeviceXI.hpp"
#include "CursorWin.hpp"
#include "../../core/Engine.hpp"
#include "../../core/windows/NativeWindowWin.hpp"
#include "../../utils/Log.hpp"

namespace ouzel::input::windows
{
    namespace
    {
        const ErrorCategory errorCategory{};

        BOOL CALLBACK enumDevicesCallback(const DIDEVICEINSTANCEW* didInstance, VOID* context)
        {
            const auto inputSystemWin = static_cast<InputSystem*>(context);
            inputSystemWin->handleDeviceConnect(didInstance);

            return DIENUM_CONTINUE;
        }
    }

    const std::error_category& getErrorCategory() noexcept
    {
        return errorCategory;
    }

    InputSystem::InputSystem(const std::function<std::future<bool>(const Event&)>& initCallback):
                             input::InputSystem(initCallback),
                             keyboardDevice(std::make_unique<KeyboardDevice>(*this, getNextDeviceId())),
                             mouseDevice(std::make_unique<MouseDevice>(*this, getNextDeviceId())),
                             touchpadDevice(std::make_unique<TouchpadDevice>(*this, getNextDeviceId(), true))
    {
        defaultCursor = LoadCursor(nullptr, IDC_ARROW);
        if (!defaultCursor)
            throw std::system_error(GetLastError(), std::system_category(), "Failed to load cursor");

        HINSTANCE instance = GetModuleHandleW(nullptr);
        if (!instance)
            throw std::system_error(GetLastError(), std::system_category(), "Failed to get module handle");

        void* directInputPointer;
        if (const auto result = DirectInput8Create(instance, DIRECTINPUT_VERSION, IID_IDirectInput8W, &directInputPointer, nullptr); FAILED(result))
            throw std::system_error(result, errorCategory, "Failed to initialize DirectInput");

        directInput = static_cast<IDirectInput8W*>(directInputPointer);

        for (DWORD userIndex = 0; userIndex < XUSER_MAX_COUNT; ++userIndex)
        {
            XINPUT_STATE state = {};
            DWORD result = XInputGetState(userIndex, &state);

            if (result == ERROR_SUCCESS)
                gamepadsXI[userIndex] = std::make_unique<GamepadDeviceXI>(*this, getNextDeviceId(), userIndex);
            else if (result != ERROR_DEVICE_NOT_CONNECTED)
                throw std::system_error(result, std::system_category(), "Failed to get state for gamepad " + std::to_string(userIndex));
        }

        if (const auto result = directInput->EnumDevices(DI8DEVCLASS_GAMECTRL, enumDevicesCallback, this, DIEDFL_ATTACHEDONLY); FAILED(result))
            throw std::system_error(result, errorCategory, "Failed to enumerate devices");
    }

    InputSystem::~InputSystem()
    {
        if (directInput) directInput->Release();
    }

    void InputSystem::executeCommand(const Command& command)
    {
        switch (command.type)
        {
            case Command::Type::startDeviceDiscovery:
                discovering = true;
                break;
            case Command::Type::stopDeviceDiscovery:
                discovering = false;
                break;
            case Command::Type::setPlayerIndex:
            {
                break;
            }
            case Command::Type::setVibration:
            {
                break;
            }
            case Command::Type::setPosition:
            {
                if (InputDevice* inputDevice = getInputDevice(command.deviceId))
                {
                    if (inputDevice == mouseDevice.get())
                        mouseDevice->setPosition(command.position);
                }
                break;
            }
            case Command::Type::initCursor:
            {
                if (command.cursorResource > cursors.size())
                    cursors.resize(command.cursorResource);

                if (command.data.empty())
                {
                    auto cursor = std::make_unique<Cursor>(command.systemCursor);
                    cursors[command.cursorResource - 1] = std::move(cursor);
                }
                else
                {
                    auto cursor = std::make_unique<Cursor>(command.data, command.size,
                                                           command.pixelFormat, command.hotSpot);
                    cursors[command.cursorResource - 1] = std::move(cursor);
                }
                break;
            }
            case Command::Type::destroyCursor:
            {
                Cursor* cursor = cursors[command.cursorResource - 1].get();

                if (mouseDevice->getCursor() == cursor)
                {
                    mouseDevice->setCursor(nullptr);
                    updateCursor();
                }

                cursors[command.cursorResource - 1].reset();
                break;
            }
            case Command::Type::setCursor:
            {
                if (InputDevice* inputDevice = getInputDevice(command.deviceId))
                {
                    if (inputDevice == mouseDevice.get())
                    {
                        if (command.cursorResource)
                            mouseDevice->setCursor(cursors[command.cursorResource - 1].get());
                        else
                            mouseDevice->setCursor(nullptr);

                        updateCursor();
                    }
                }
                break;
            }
            case Command::Type::setCursorVisible:
            {
                if (InputDevice* inputDevice = getInputDevice(command.deviceId))
                {
                    if (inputDevice == mouseDevice.get())
                        mouseDevice->setCursorVisible(command.visible);
                }
                break;
            }
            case Command::Type::setCursorLocked:
            {
                if (InputDevice* inputDevice = getInputDevice(command.deviceId))
                {
                    if (inputDevice == mouseDevice.get())
                        mouseDevice->setCursorLocked(command.locked);
                }
                break;
            }
            default:
                break;
        }
    }

    void InputSystem::update()
    {
        keyboardDevice->update();

        for (DWORD userIndex = 0; userIndex < XUSER_MAX_COUNT; ++userIndex)
        {
            if (gamepadsXI[userIndex])
            {
                try
                {
                    gamepadsXI[userIndex]->update();
                }
                catch (const std::exception&)
                {
                    gamepadsXI[userIndex].reset();
                }
            }
        }

        for (auto i = gamepadsDI.begin(); i != gamepadsDI.end();)
        {
            try
            {
                (*i)->update();
                ++i;
            }
            catch (const std::exception&)
            {
                i = gamepadsDI.erase(i);
            }
        }

        if (discovering)
        {
            for (DWORD userIndex = 0; userIndex < XUSER_MAX_COUNT; ++userIndex)
            {
                if (!gamepadsXI[userIndex])
                {
                    XINPUT_STATE state = {};

                    if (const auto result = XInputGetState(userIndex, &state); result == ERROR_SUCCESS)
                        gamepadsXI[userIndex] = std::make_unique<GamepadDeviceXI>(*this, getNextDeviceId(), userIndex);
                    else if (result != ERROR_DEVICE_NOT_CONNECTED)
                        throw std::system_error(result, std::system_category(), "Failed to get state for gamepad " + std::to_string(userIndex));
                }
            }

            if (const auto result = directInput->EnumDevices(DI8DEVCLASS_GAMECTRL, enumDevicesCallback, this, DIEDFL_ATTACHEDONLY); FAILED(result))
                throw std::system_error(result, errorCategory, "Failed to enumerate devices");
        }
    }

    void InputSystem::handleDeviceConnect(const DIDEVICEINSTANCEW* didInstance)
    {
        bool isXInputDevice = false;

        void* wbemLocatorPointer;
        if (const auto result = CoCreateInstance(__uuidof(WbemLocator), nullptr, CLSCTX_INPROC_SERVER,
                                                 __uuidof(IWbemLocator), &wbemLocatorPointer); FAILED(result))
            throw std::system_error(result, std::system_category(), "Failed to create WMI locator instance");

        const auto wbemLocator = static_cast<IWbemLocator*>(wbemLocatorPointer);

        using SysFreeStringFunction = void(*)(BSTR*);
        std::unique_ptr<BSTR, SysFreeStringFunction> namespaceStr{SysAllocString(L"\\\\.\\root\\cimv2"), &SysFreeString};
        std::unique_ptr<BSTR, SysFreeStringFunction> className{SysAllocString(L"Win32_PNPEntity"), &SysFreeString};
        std::unique_ptr<BSTR, SysFreeStringFunction> deviceID{SysAllocString(L"DeviceID"), &SysFreeString};

        if (className && namespaceStr && deviceID)
        {
            IWbemServices* wbemServices = nullptr;
            if (const auto result = wbemLocator->ConnectServer(namespaceStr, nullptr, nullptr, 0L,
                                                               0L, nullptr, nullptr, &wbemServices); FAILED(result))
                throw std::system_error(result, errorCategory, "Failed to create a connection to the WMI namespace");

            if (const auto result = CoSetProxyBlanket(wbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr,
                                                      RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE); FAILED(result))
                throw std::system_error(result, errorCategory, "Failed to set authentication information");

            IEnumWbemClassObject* enumDevices = nullptr;
            if (const auto result = wbemServices->CreateInstanceEnum(className, 0, nullptr, &enumDevices); FAILED(result))
                throw std::system_error(result, errorCategory, "Failed to create the device enumerator");

            // Get 20 at a time
            ULONG returned = 0;
            IWbemClassObject* devices[20];
            while (enumDevices->Next(10000, 20, devices, &returned) == WBEM_S_NO_ERROR)
            {
                for (ULONG device = 0; device < returned; ++device)
                {
                    // For each device, get its device ID
                    VARIANT var;
                    const auto result = devices[device]->Get(deviceID, 0L, &var, nullptr, nullptr);
                    if (SUCCEEDED(result) && var.vt == VT_BSTR && var.bstrVal != nullptr)
                    {
                        // Check if the device ID contains "IG_". If it does, then it's an XInput device
                        // This information can not be found from DirectInput
                        if (wcsstr(var.bstrVal, L"IG_"))
                        {
                            // If it does, then get the VID/PID from var.bstrVal
                            DWORD dwPid = 0;
                            DWORD dwVid = 0;
                            WCHAR* strVid = wcsstr(var.bstrVal, L"VID_");
                            if (strVid && swscanf(strVid, L"VID_%4X", &dwVid) != 1) dwVid = 0;
                            WCHAR* strPid = wcsstr(var.bstrVal, L"PID_");
                            if (strPid && swscanf(strPid, L"PID_%4X", &dwPid) != 1) dwPid = 0;

                            // Compare the VID/PID to the DInput device
                            const auto dwVidPid = static_cast<DWORD>(MAKELONG(dwVid, dwPid));
                            if (dwVidPid == didInstance->guidProduct.Data1)
                                isXInputDevice = true;
                        }
                    }

                    devices[device]->Release();
                }
            }

            enumDevices->Release();
            wbemServices->Release();
        }

        wbemLocator->Release();

        if (!isXInputDevice)
        {
            bool found = false;

            for (auto i = gamepadsDI.begin(); i != gamepadsDI.end();)
            {
                if ((*i)->getInstance()->guidInstance == didInstance->guidInstance)
                {
                    found = true;
                    break;
                }
            }

            if (!found)
            {
                const auto windowWin = static_cast<core::windows::NativeWindow*>(engine->getWindow()->getNativeWindow());

                gamepadsDI.emplace_back(std::make_unique<GamepadDeviceDI>(*this, getNextDeviceId(),
                                                                          didInstance, directInput,
                                                                          windowWin->getNativeWindow()));
            }
        }
    }

    void InputSystem::updateCursor() const
    {
        if (mouseDevice->isCursorVisible())
        {
            if (mouseDevice->getCursor())
                SetCursor(mouseDevice->getCursor()->getCursor());
            else
                SetCursor(defaultCursor);
        }
        else
            SetCursor(nullptr);
    }
}
<commit_msg>Add the missing get()<commit_after>// Ouzel by Elviss Strazdins

#pragma push_macro("WIN32_LEAN_AND_MEAN")
#pragma push_macro("NOMINMAX")
#ifndef WIN32_LEAN_AND_MEAN
#  define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#  define NOMINMAX
#endif
#include <Windows.h>
#include <WbemIdl.h>
#include <OleAuto.h>
#pragma pop_macro("WIN32_LEAN_AND_MEAN")
#pragma pop_macro("NOMINMAX")

#include "InputSystemWin.hpp"
#include "DIErrorCategory.hpp"
#include "GamepadDeviceDI.hpp"
#include "GamepadDeviceXI.hpp"
#include "CursorWin.hpp"
#include "../../core/Engine.hpp"
#include "../../core/windows/NativeWindowWin.hpp"
#include "../../utils/Log.hpp"

namespace ouzel::input::windows
{
    namespace
    {
        const ErrorCategory errorCategory{};

        BOOL CALLBACK enumDevicesCallback(const DIDEVICEINSTANCEW* didInstance, VOID* context)
        {
            const auto inputSystemWin = static_cast<InputSystem*>(context);
            inputSystemWin->handleDeviceConnect(didInstance);

            return DIENUM_CONTINUE;
        }
    }

    const std::error_category& getErrorCategory() noexcept
    {
        return errorCategory;
    }

    InputSystem::InputSystem(const std::function<std::future<bool>(const Event&)>& initCallback):
                             input::InputSystem(initCallback),
                             keyboardDevice(std::make_unique<KeyboardDevice>(*this, getNextDeviceId())),
                             mouseDevice(std::make_unique<MouseDevice>(*this, getNextDeviceId())),
                             touchpadDevice(std::make_unique<TouchpadDevice>(*this, getNextDeviceId(), true))
    {
        defaultCursor = LoadCursor(nullptr, IDC_ARROW);
        if (!defaultCursor)
            throw std::system_error(GetLastError(), std::system_category(), "Failed to load cursor");

        HINSTANCE instance = GetModuleHandleW(nullptr);
        if (!instance)
            throw std::system_error(GetLastError(), std::system_category(), "Failed to get module handle");

        void* directInputPointer;
        if (const auto result = DirectInput8Create(instance, DIRECTINPUT_VERSION, IID_IDirectInput8W, &directInputPointer, nullptr); FAILED(result))
            throw std::system_error(result, errorCategory, "Failed to initialize DirectInput");

        directInput = static_cast<IDirectInput8W*>(directInputPointer);

        for (DWORD userIndex = 0; userIndex < XUSER_MAX_COUNT; ++userIndex)
        {
            XINPUT_STATE state = {};
            DWORD result = XInputGetState(userIndex, &state);

            if (result == ERROR_SUCCESS)
                gamepadsXI[userIndex] = std::make_unique<GamepadDeviceXI>(*this, getNextDeviceId(), userIndex);
            else if (result != ERROR_DEVICE_NOT_CONNECTED)
                throw std::system_error(result, std::system_category(), "Failed to get state for gamepad " + std::to_string(userIndex));
        }

        if (const auto result = directInput->EnumDevices(DI8DEVCLASS_GAMECTRL, enumDevicesCallback, this, DIEDFL_ATTACHEDONLY); FAILED(result))
            throw std::system_error(result, errorCategory, "Failed to enumerate devices");
    }

    InputSystem::~InputSystem()
    {
        if (directInput) directInput->Release();
    }

    void InputSystem::executeCommand(const Command& command)
    {
        switch (command.type)
        {
            case Command::Type::startDeviceDiscovery:
                discovering = true;
                break;
            case Command::Type::stopDeviceDiscovery:
                discovering = false;
                break;
            case Command::Type::setPlayerIndex:
            {
                break;
            }
            case Command::Type::setVibration:
            {
                break;
            }
            case Command::Type::setPosition:
            {
                if (InputDevice* inputDevice = getInputDevice(command.deviceId))
                {
                    if (inputDevice == mouseDevice.get())
                        mouseDevice->setPosition(command.position);
                }
                break;
            }
            case Command::Type::initCursor:
            {
                if (command.cursorResource > cursors.size())
                    cursors.resize(command.cursorResource);

                if (command.data.empty())
                {
                    auto cursor = std::make_unique<Cursor>(command.systemCursor);
                    cursors[command.cursorResource - 1] = std::move(cursor);
                }
                else
                {
                    auto cursor = std::make_unique<Cursor>(command.data, command.size,
                                                           command.pixelFormat, command.hotSpot);
                    cursors[command.cursorResource - 1] = std::move(cursor);
                }
                break;
            }
            case Command::Type::destroyCursor:
            {
                Cursor* cursor = cursors[command.cursorResource - 1].get();

                if (mouseDevice->getCursor() == cursor)
                {
                    mouseDevice->setCursor(nullptr);
                    updateCursor();
                }

                cursors[command.cursorResource - 1].reset();
                break;
            }
            case Command::Type::setCursor:
            {
                if (InputDevice* inputDevice = getInputDevice(command.deviceId))
                {
                    if (inputDevice == mouseDevice.get())
                    {
                        if (command.cursorResource)
                            mouseDevice->setCursor(cursors[command.cursorResource - 1].get());
                        else
                            mouseDevice->setCursor(nullptr);

                        updateCursor();
                    }
                }
                break;
            }
            case Command::Type::setCursorVisible:
            {
                if (InputDevice* inputDevice = getInputDevice(command.deviceId))
                {
                    if (inputDevice == mouseDevice.get())
                        mouseDevice->setCursorVisible(command.visible);
                }
                break;
            }
            case Command::Type::setCursorLocked:
            {
                if (InputDevice* inputDevice = getInputDevice(command.deviceId))
                {
                    if (inputDevice == mouseDevice.get())
                        mouseDevice->setCursorLocked(command.locked);
                }
                break;
            }
            default:
                break;
        }
    }

    void InputSystem::update()
    {
        keyboardDevice->update();

        for (DWORD userIndex = 0; userIndex < XUSER_MAX_COUNT; ++userIndex)
        {
            if (gamepadsXI[userIndex])
            {
                try
                {
                    gamepadsXI[userIndex]->update();
                }
                catch (const std::exception&)
                {
                    gamepadsXI[userIndex].reset();
                }
            }
        }

        for (auto i = gamepadsDI.begin(); i != gamepadsDI.end();)
        {
            try
            {
                (*i)->update();
                ++i;
            }
            catch (const std::exception&)
            {
                i = gamepadsDI.erase(i);
            }
        }

        if (discovering)
        {
            for (DWORD userIndex = 0; userIndex < XUSER_MAX_COUNT; ++userIndex)
            {
                if (!gamepadsXI[userIndex])
                {
                    XINPUT_STATE state = {};

                    if (const auto result = XInputGetState(userIndex, &state); result == ERROR_SUCCESS)
                        gamepadsXI[userIndex] = std::make_unique<GamepadDeviceXI>(*this, getNextDeviceId(), userIndex);
                    else if (result != ERROR_DEVICE_NOT_CONNECTED)
                        throw std::system_error(result, std::system_category(), "Failed to get state for gamepad " + std::to_string(userIndex));
                }
            }

            if (const auto result = directInput->EnumDevices(DI8DEVCLASS_GAMECTRL, enumDevicesCallback, this, DIEDFL_ATTACHEDONLY); FAILED(result))
                throw std::system_error(result, errorCategory, "Failed to enumerate devices");
        }
    }

    void InputSystem::handleDeviceConnect(const DIDEVICEINSTANCEW* didInstance)
    {
        bool isXInputDevice = false;

        void* wbemLocatorPointer;
        if (const auto result = CoCreateInstance(__uuidof(WbemLocator), nullptr, CLSCTX_INPROC_SERVER,
                                                 __uuidof(IWbemLocator), &wbemLocatorPointer); FAILED(result))
            throw std::system_error(result, std::system_category(), "Failed to create WMI locator instance");

        const auto wbemLocator = static_cast<IWbemLocator*>(wbemLocatorPointer);

        using SysFreeStringFunction = void(*)(BSTR*);
        std::unique_ptr<BSTR, SysFreeStringFunction> namespaceStr{SysAllocString(L"\\\\.\\root\\cimv2"), &SysFreeString};
        std::unique_ptr<BSTR, SysFreeStringFunction> className{SysAllocString(L"Win32_PNPEntity"), &SysFreeString};
        std::unique_ptr<BSTR, SysFreeStringFunction> deviceID{SysAllocString(L"DeviceID"), &SysFreeString};

        if (className && namespaceStr && deviceID)
        {
            IWbemServices* wbemServices = nullptr;
            if (const auto result = wbemLocator->ConnectServer(namespaceStr.get(), nullptr, nullptr, 0L,
                                                               0L, nullptr, nullptr, &wbemServices); FAILED(result))
                throw std::system_error(result, errorCategory, "Failed to create a connection to the WMI namespace");

            if (const auto result = CoSetProxyBlanket(wbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr,
                                                      RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE); FAILED(result))
                throw std::system_error(result, errorCategory, "Failed to set authentication information");

            IEnumWbemClassObject* enumDevices = nullptr;
            if (const auto result = wbemServices->CreateInstanceEnum(className.get(), 0, nullptr, &enumDevices); FAILED(result))
                throw std::system_error(result, errorCategory, "Failed to create the device enumerator");

            // Get 20 at a time
            ULONG returned = 0;
            IWbemClassObject* devices[20];
            while (enumDevices->Next(10000, 20, devices, &returned) == WBEM_S_NO_ERROR)
            {
                for (ULONG device = 0; device < returned; ++device)
                {
                    // For each device, get its device ID
                    VARIANT var;
                    const auto result = devices[device]->Get(deviceID.get(), 0L, &var, nullptr, nullptr);
                    if (SUCCEEDED(result) && var.vt == VT_BSTR && var.bstrVal != nullptr)
                    {
                        // Check if the device ID contains "IG_". If it does, then it's an XInput device
                        // This information can not be found from DirectInput
                        if (wcsstr(var.bstrVal, L"IG_"))
                        {
                            // If it does, then get the VID/PID from var.bstrVal
                            DWORD dwPid = 0;
                            DWORD dwVid = 0;
                            WCHAR* strVid = wcsstr(var.bstrVal, L"VID_");
                            if (strVid && swscanf(strVid, L"VID_%4X", &dwVid) != 1) dwVid = 0;
                            WCHAR* strPid = wcsstr(var.bstrVal, L"PID_");
                            if (strPid && swscanf(strPid, L"PID_%4X", &dwPid) != 1) dwPid = 0;

                            // Compare the VID/PID to the DInput device
                            const auto dwVidPid = static_cast<DWORD>(MAKELONG(dwVid, dwPid));
                            if (dwVidPid == didInstance->guidProduct.Data1)
                                isXInputDevice = true;
                        }
                    }

                    devices[device]->Release();
                }
            }

            enumDevices->Release();
            wbemServices->Release();
        }

        wbemLocator->Release();

        if (!isXInputDevice)
        {
            bool found = false;

            for (auto i = gamepadsDI.begin(); i != gamepadsDI.end();)
            {
                if ((*i)->getInstance()->guidInstance == didInstance->guidInstance)
                {
                    found = true;
                    break;
                }
            }

            if (!found)
            {
                const auto windowWin = static_cast<core::windows::NativeWindow*>(engine->getWindow()->getNativeWindow());

                gamepadsDI.emplace_back(std::make_unique<GamepadDeviceDI>(*this, getNextDeviceId(),
                                                                          didInstance, directInput,
                                                                          windowWin->getNativeWindow()));
            }
        }
    }

    void InputSystem::updateCursor() const
    {
        if (mouseDevice->isCursorVisible())
        {
            if (mouseDevice->getCursor())
                SetCursor(mouseDevice->getCursor()->getCursor());
            else
                SetCursor(defaultCursor);
        }
        else
            SetCursor(nullptr);
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"
#include "core/css/parser/CSSPropertyParser.h"

#include "core/css/CSSValueList.h"
#include "core/css/parser/CSSParser.h"
#include "wtf/dtoa/utils.h"

#include <gtest/gtest.h>

namespace blink {

static unsigned computeNumberOfTracks(CSSValueList* valueList)
{
    unsigned numberOfTracks = 0;
    for (CSSValueListIterator i = valueList; i.hasMore(); i.advance()) {
        if (i.value()->isGridLineNamesValue())
            continue;
        ++numberOfTracks;
    }
    return numberOfTracks;
}

TEST(CSSPropertyParserTest, GridTrackLimits)
{
    struct {
        const CSSPropertyID propertyID;
        const char* input;
        const size_t output;
    } testCases[] = {
        {CSSPropertyGridTemplateColumns, "grid-template-columns: repeat(999999, 20px);", 999999},
        {CSSPropertyGridTemplateRows, "grid-template-rows: repeat(999999, 20px);", 999999},
        {CSSPropertyGridTemplateColumns, "grid-template-columns: repeat(1000000, 10%);", 1000000},
        {CSSPropertyGridTemplateRows, "grid-template-rows: repeat(1000000, 10%);", 1000000},
        {CSSPropertyGridTemplateColumns, "grid-template-columns: repeat(1000000, (first) min-content (last));", 1000000},
        {CSSPropertyGridTemplateRows, "grid-template-rows: repeat(1000000, (first) min-content (last));", 1000000},
        {CSSPropertyGridTemplateColumns, "grid-template-columns: repeat(1000001, auto);", 1000000},
        {CSSPropertyGridTemplateRows, "grid-template-rows: repeat(1000001, auto);", 1000000},
        {CSSPropertyGridTemplateColumns, "grid-template-columns: repeat(400000, 2em minmax(10px, max-content) 0.5fr);", 999999},
        {CSSPropertyGridTemplateRows, "grid-template-rows: repeat(400000, 2em minmax(10px, max-content) 0.5fr);", 999999},
        {CSSPropertyGridTemplateColumns, "grid-template-columns: repeat(600000, (first) 3vh 10% 2fr (nav) 10px auto 1fr 6em (last));", 999999},
        {CSSPropertyGridTemplateRows, "grid-template-rows: repeat(600000, (first) 3vh 10% 2fr (nav) 10px auto 1fr 6em (last));", 999999},
    };

    CSSParser parser(strictCSSParserContext());
    RefPtrWillBeRawPtr<MutableStylePropertySet> propertySet = MutableStylePropertySet::create();

    for (unsigned i = 0; i < ARRAY_SIZE(testCases); ++i) {
        ASSERT_TRUE(parser.parseDeclaration(propertySet.get(), testCases[i].input, 0, 0));
        RefPtrWillBeRawPtr<CSSValue> value = propertySet->getPropertyCSSValue(testCases[i].propertyID);

        ASSERT_TRUE(value->isValueList());
        EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value.get())), testCases[i].output);
    }
}

} // namespace blink
<commit_msg>Small clean-up to GridTrackLimits test<commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"
#include "core/css/parser/CSSPropertyParser.h"

#include "core/css/CSSValueList.h"
#include "core/css/parser/CSSParser.h"

#include <gtest/gtest.h>

namespace blink {

static unsigned computeNumberOfTracks(CSSValueList* valueList)
{
    unsigned numberOfTracks = 0;
    for (CSSValueListIterator i = valueList; i.hasMore(); i.advance()) {
        if (i.value()->isGridLineNamesValue())
            continue;
        ++numberOfTracks;
    }
    return numberOfTracks;
}

TEST(CSSPropertyParserTest, GridTrackLimits)
{
    struct {
        const CSSPropertyID propertyID;
        const char* input;
        const size_t output;
    } testCases[] = {
        {CSSPropertyGridTemplateColumns, "repeat(999999, 20px)", 999999},
        {CSSPropertyGridTemplateRows, "repeat(999999, 20px)", 999999},
        {CSSPropertyGridTemplateColumns, "repeat(1000000, 10%)", 1000000},
        {CSSPropertyGridTemplateRows, "repeat(1000000, 10%)", 1000000},
        {CSSPropertyGridTemplateColumns, "repeat(1000000, (first) min-content (last))", 1000000},
        {CSSPropertyGridTemplateRows, "repeat(1000000, (first) min-content (last))", 1000000},
        {CSSPropertyGridTemplateColumns, "repeat(1000001, auto)", 1000000},
        {CSSPropertyGridTemplateRows, "repeat(1000001, auto)", 1000000},
        {CSSPropertyGridTemplateColumns, "repeat(400000, 2em minmax(10px, max-content) 0.5fr)", 999999},
        {CSSPropertyGridTemplateRows, "repeat(400000, 2em minmax(10px, max-content) 0.5fr)", 999999},
        {CSSPropertyGridTemplateColumns, "repeat(600000, (first) 3vh 10% 2fr (nav) 10px auto 1fr 6em (last))", 999999},
        {CSSPropertyGridTemplateRows, "repeat(600000, (first) 3vh 10% 2fr (nav) 10px auto 1fr 6em (last))", 999999},
    };

    for (unsigned i = 0; i < WTF_ARRAY_LENGTH(testCases); ++i) {
        RefPtrWillBeRawPtr<CSSValue> value = CSSParser::parseSingleValue(testCases[i].propertyID, testCases[i].input);
        ASSERT_TRUE(value);
        ASSERT_TRUE(value->isValueList());
        EXPECT_EQ(computeNumberOfTracks(toCSSValueList(value.get())), testCases[i].output);
    }
}

} // namespace blink
<|endoftext|>