<commit_before>// Copyright (C) 2010-2014 Joshua Boyce.
// See the file COPYING for copying permission.

#include "render.hpp"

#include <cstdint>

#include <windows.h>
#include <winnt.h>
#include <winternl.h>

#include <d3d9.h>
#include <d3d11.h>
#include <d3d10.h>
#include <dxgi.h>

#include <hadesmem/detail/warning_disable_prefix.hpp>
#include <anttweakbar.h>
#include <hadesmem/detail/warning_disable_suffix.hpp>

#include <hadesmem/config.hpp>
#include <hadesmem/detail/smart_handle.hpp>

#include "callbacks.hpp"
#include "d3d9.hpp"
#include "dxgi.hpp"
#include "main.hpp"

namespace
{

hadesmem::cerberus::Callbacks<hadesmem::cerberus::OnFrameCallback>&
  GetOnFrameCallbacks()
{
  static hadesmem::cerberus::Callbacks<hadesmem::cerberus::OnFrameCallback>
    callbacks;
  return callbacks;
}

struct RenderInfoD3D11
{
  bool first_time_{true};
  bool tw_initialized_{false};
  IDXGISwapChain* swap_chain_{};
  ID3D11Device* device_;
};

RenderInfoD3D11& GetRenderInfoD3D11() HADESMEM_DETAIL_NOEXCEPT
{
  static RenderInfoD3D11 render_info;
  return render_info;
}

struct RenderInfoD3D10
{
  bool first_time_{true};
  bool tw_initialized_{false};
  IDXGISwapChain* swap_chain_{};
  ID3D10Device* device_;
};

RenderInfoD3D10& GetRenderInfoD3D10() HADESMEM_DETAIL_NOEXCEPT
{
  static RenderInfoD3D10 render_info;
  return render_info;
}

struct RenderInfoD3D9
{
  bool first_time_{true};
  bool tw_initialized_{false};
  IDirect3DDevice9* device_{};
};

RenderInfoD3D9& GetRenderInfoD3D9() HADESMEM_DETAIL_NOEXCEPT
{
  static RenderInfoD3D9 render_info;
  return render_info;
}

bool AntTweakBarInitializedAny()
{
  return GetRenderInfoD3D9().tw_initialized_ ||
         GetRenderInfoD3D10().tw_initialized_ ||
         GetRenderInfoD3D11().tw_initialized_;
}

void InitializeAntTweakBar(TwGraphAPI api, void* device, bool& initialized)
{
  if (AntTweakBarInitializedAny())
  {
    HADESMEM_DETAIL_TRACE_A(
      "WARNING! AntTweakBar is already initialized. Skipping.");
    return;
  }

  if (!TwInit(api, device))
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(hadesmem::Error{}
                                    << hadesmem::ErrorString{"TwInit failed."});
  }

  initialized = true;

  if (!TwWindowSize(800, 600))
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(
      hadesmem::Error{} << hadesmem::ErrorString{"TwWindowSize failed."});
  }

  auto const bar = TwNewBar("HadesMem");
  if (!bar)
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(
      hadesmem::Error{} << hadesmem::ErrorString{"TwNewBar failed."});
  }
}

void CleanupAntTweakBar(bool& initialized)
{
  if (initialized)
  {
    if (!TwTerminate())
    {
      HADESMEM_DETAIL_THROW_EXCEPTION(
        hadesmem::Error{} << hadesmem::ErrorString{"TwTerminate failed."});
    }

    initialized = false;
  }
}

void HandleChangedSwapChainD3D11(IDXGISwapChain* swap_chain,
                                 RenderInfoD3D11& render_info)
{
  HADESMEM_DETAIL_TRACE_FORMAT_A("Got a new swap chain. Old = %p, New = %p.",
                                 render_info.swap_chain_,
                                 swap_chain);
  render_info.swap_chain_ = swap_chain;

  render_info.device_ = nullptr;

  render_info.first_time_ = true;

  CleanupAntTweakBar(render_info.tw_initialized_);
}

void HandleChangedSwapChainD3D10(IDXGISwapChain* swap_chain,
                                 RenderInfoD3D10& render_info)
{
  HADESMEM_DETAIL_TRACE_FORMAT_A("Got a new swap chain. Old = %p, New = %p.",
                                 render_info.swap_chain_,
                                 swap_chain);
  render_info.swap_chain_ = swap_chain;

  render_info.device_ = nullptr;

  render_info.first_time_ = true;

  CleanupAntTweakBar(render_info.tw_initialized_);
}

void HandleChangedDeviceD3D9(IDirect3DDevice9* device,
                             RenderInfoD3D9& render_info)
{
  HADESMEM_DETAIL_TRACE_FORMAT_A(
    "Got a new device. Old = %p, New = %p.", render_info.device_, device);
  render_info.device_ = device;

  render_info.first_time_ = true;

  CleanupAntTweakBar(render_info.tw_initialized_);
}

void InitializeD3D11RenderInfo(RenderInfoD3D11& render_info)
{
  HADESMEM_DETAIL_TRACE_A("Initializing.");

  render_info.first_time_ = false;

  auto const get_device_hr = render_info.swap_chain_->GetDevice(
    __uuidof(render_info.device_),
    reinterpret_cast<void**>(&render_info.device_));
  if (FAILED(get_device_hr))
  {
    HADESMEM_DETAIL_TRACE_FORMAT_A(
      "WARNING! IDXGISwapChain::GetDevice failed. HR = %08X.", get_device_hr);
    return;
  }

  InitializeAntTweakBar(
    TW_DIRECT3D11, render_info.device_, render_info.tw_initialized_);

  HADESMEM_DETAIL_TRACE_A("Initialized successfully.");
}

void InitializeD3D10RenderInfo(RenderInfoD3D10& render_info)
{
  HADESMEM_DETAIL_TRACE_A("Initializing.");

  render_info.first_time_ = false;

  auto const get_device_hr = render_info.swap_chain_->GetDevice(
    __uuidof(render_info.device_),
    reinterpret_cast<void**>(&render_info.device_));
  if (FAILED(get_device_hr))
  {
    HADESMEM_DETAIL_TRACE_FORMAT_A(
      "WARNING! IDXGISwapChain::GetDevice failed. HR = %08X.", get_device_hr);
    return;
  }

  InitializeAntTweakBar(
    TW_DIRECT3D10, render_info.device_, render_info.tw_initialized_);

  HADESMEM_DETAIL_TRACE_A("Initialized successfully.");
}

void InitializeD3D9RenderInfo(RenderInfoD3D9& render_info)
{
  HADESMEM_DETAIL_TRACE_A("Initializing.");

  render_info.first_time_ = false;

  InitializeAntTweakBar(
    TW_DIRECT3D9, render_info.device_, render_info.tw_initialized_);

  HADESMEM_DETAIL_TRACE_A("Initialized successfully.");
}

void HandleOnFrameD3D11(IDXGISwapChain* swap_chain)
{
  auto& render_info = GetRenderInfoD3D11();
  if (render_info.swap_chain_ != swap_chain)
  {
    HandleChangedSwapChainD3D11(swap_chain, render_info);
  }

  if (render_info.first_time_)
  {
    InitializeD3D11RenderInfo(render_info);
  }
}

void HandleOnFrameD3D10(IDXGISwapChain* swap_chain)
{
  auto& render_info = GetRenderInfoD3D10();
  if (render_info.swap_chain_ != swap_chain)
  {
    HandleChangedSwapChainD3D10(swap_chain, render_info);
  }

  if (render_info.first_time_)
  {
    InitializeD3D10RenderInfo(render_info);
  }
}

void HandleOnFrameD3D9(IDirect3DDevice9* device)
{
  auto& render_info = GetRenderInfoD3D9();
  if (render_info.device_ != device)
  {
    HandleChangedDeviceD3D9(device, render_info);
  }

  if (render_info.first_time_)
  {
    InitializeD3D9RenderInfo(render_info);
  }
}

void OnFrameDXGI(IDXGISwapChain* swap_chain)
{
  HandleOnFrameD3D11(swap_chain);

  HandleOnFrameD3D10(swap_chain);

  auto& callbacks = GetOnFrameCallbacks();
  auto& render_interface = hadesmem::cerberus::GetRenderInterface();
  callbacks.Run(&render_interface);
}

void OnFrameD3D9(IDirect3DDevice9* device)
{
  HandleOnFrameD3D9(device);

  auto& callbacks = GetOnFrameCallbacks();
  auto& render_interface = hadesmem::cerberus::GetRenderInterface();
  callbacks.Run(&render_interface);
}

void DrawTweakBarImpl()
{
  if (!TwDraw())
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(hadesmem::Error{}
                                    << hadesmem::ErrorString{"TwDraw failed."});
  }
}

class RenderImpl : public hadesmem::cerberus::RenderInterface
{
public:
  virtual ~RenderImpl() final
  {
    bool initialized = AntTweakBarInitializedAny();
    CleanupAntTweakBar(initialized);
  }

  virtual std::size_t RegisterOnFrame(
    std::function<hadesmem::cerberus::OnFrameCallback> const& callback) final
  {
    return hadesmem::cerberus::RegisterOnFrameCallback(callback);
  }

  virtual void UnregisterOnFrame(std::size_t id) final
  {
    hadesmem::cerberus::UnregisterOnFrameCallback(id);
  }

  virtual void DrawTweakBar() final
  {
    DrawTweakBarImpl();
  }
};
}

namespace hadesmem
{

namespace cerberus
{

RenderInterface& GetRenderInterface() HADESMEM_DETAIL_NOEXCEPT
{
  static RenderImpl render_impl;
  return render_impl;
}

void InitializeRender()
{
  auto const dxgi_callback_id =
    hadesmem::cerberus::RegisterOnFrameCallbackDXGI(OnFrameDXGI);
  (void)dxgi_callback_id;

  auto const d3d9_callback_id =
    hadesmem::cerberus::RegisterOnFrameCallbackD3D9(OnFrameD3D9);
  (void)d3d9_callback_id;

  auto const draw_tweak_bar = [](RenderInterface* render)
  { render->DrawTweakBar(); };
  RegisterOnFrameCallback(draw_tweak_bar);
}

std::size_t
  RegisterOnFrameCallback(std::function<OnFrameCallback> const& callback)
{
  auto& callbacks = GetOnFrameCallbacks();
  return callbacks.Register(callback);
}

void UnregisterOnFrameCallback(std::size_t id)
{
  auto& callbacks = GetOnFrameCallbacks();
  return callbacks.Unregister(id);
}
}
}
<commit_msg>* [Cerberus] Start adding input support. Thanks to Gliderpro.<commit_after>// Copyright (C) 2010-2014 Joshua Boyce.
// See the file COPYING for copying permission.

#include "render.hpp"

#include <cstdint>

#include <windows.h>
#include <winnt.h>
#include <winternl.h>

#include <d3d9.h>
#include <d3d11.h>
#include <d3d10.h>
#include <dxgi.h>

#include <hadesmem/detail/warning_disable_prefix.hpp>
#include <anttweakbar.h>
#include <hadesmem/detail/warning_disable_suffix.hpp>

#include <hadesmem/config.hpp>
#include <hadesmem/detail/smart_handle.hpp>

#include "callbacks.hpp"
#include "d3d9.hpp"
#include "dxgi.hpp"
#include "main.hpp"

namespace
{

struct WindowInfo
{
  HWND old_hwnd_{nullptr};
  WNDPROC old_wndproc_{nullptr};
};

WindowInfo& GetWindowInfo() HADESMEM_DETAIL_NOEXCEPT
{
  static WindowInfo window_info;
  return window_info;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
  LRESULT ret = 0;
  WindowInfo& window_info = GetWindowInfo();

  // Window #0 will always exist if TwInit has completed successfully.
  if (TwWindowExists(0) && TwEventWin(hwnd, msg, wparam, lparam))
  {
    // Event has been handled by AntTweakBar.
    ret = 0;
  }
  else if (window_info.old_wndproc_ != nullptr)
  {
    ret =
      ::CallWindowProcW(window_info.old_wndproc_, hwnd, msg, wparam, lparam);
  }
  else
  {
    ret = ::DefWindowProcW(hwnd, msg, wparam, lparam);
  }

  return ret;
}

hadesmem::cerberus::Callbacks<hadesmem::cerberus::OnFrameCallback>&
  GetOnFrameCallbacks()
{
  static hadesmem::cerberus::Callbacks<hadesmem::cerberus::OnFrameCallback>
    callbacks;
  return callbacks;
}

struct RenderInfoDXGI
{
  bool first_time_{true};
  bool tw_initialized_{false};
  bool wndproc_swapped_{false};
  IDXGISwapChain* swap_chain_{};
};

struct RenderInfoD3D11 : RenderInfoDXGI
{
  ID3D11Device* device_;
};

RenderInfoD3D11& GetRenderInfoD3D11() HADESMEM_DETAIL_NOEXCEPT
{
  static RenderInfoD3D11 render_info;
  return render_info;
}

struct RenderInfoD3D10 : RenderInfoDXGI
{
  ID3D10Device* device_;
};

RenderInfoD3D10& GetRenderInfoD3D10() HADESMEM_DETAIL_NOEXCEPT
{
  static RenderInfoD3D10 render_info;
  return render_info;
}

struct RenderInfoD3D9
{
  bool first_time_{true};
  bool tw_initialized_{false};
  bool wndproc_swapped_{false};
  IDirect3DDevice9* device_{};
};

RenderInfoD3D9& GetRenderInfoD3D9() HADESMEM_DETAIL_NOEXCEPT
{
  static RenderInfoD3D9 render_info;
  return render_info;
}

bool AntTweakBarInitializedAny()
{
  return GetRenderInfoD3D9().tw_initialized_ ||
         GetRenderInfoD3D10().tw_initialized_ ||
         GetRenderInfoD3D11().tw_initialized_;
}

void InitializeWndprocHook(RenderInfoDXGI& render_info)
{
  WindowInfo& window_info = GetWindowInfo();
  if (window_info.old_wndproc_ == nullptr)
  {
    DXGI_SWAP_CHAIN_DESC desc;
    auto const get_desc_hr = render_info.swap_chain_->GetDesc(&desc);
    if (FAILED(get_desc_hr))
    {
      HADESMEM_DETAIL_THROW_EXCEPTION(
        hadesmem::Error{} << hadesmem::ErrorString{"GetDesc failed."}
                          << hadesmem::ErrorCodeWinHr{get_desc_hr});
    }
    window_info.old_hwnd_ = desc.OutputWindow;
    window_info.old_wndproc_ = reinterpret_cast<WNDPROC>(
      ::SetWindowLongPtrW(desc.OutputWindow,
                          GWLP_WNDPROC,
                          reinterpret_cast<LONG_PTR>(&WindowProc)));
    render_info.wndproc_swapped_ = true;
    HADESMEM_DETAIL_TRACE_FORMAT_A("Replaced window procedure located at %p.",
                                   window_info.old_wndproc_);
  }
}

void InitializeWndprocHook(RenderInfoD3D9& render_info)
{
  WindowInfo& window_info = GetWindowInfo();
  if (window_info.old_wndproc_ == nullptr)
  {
    IDirect3D9* d3d9 = nullptr;
    render_info.device_->GetDirect3D(&d3d9);
    D3DDEVICE_CREATION_PARAMETERS create_params;
    ::ZeroMemory(&create_params, sizeof(create_params));
    auto const get_create_params_hr =
      render_info.device_->GetCreationParameters(&create_params);
    if (FAILED(get_create_params_hr))
    {
      HADESMEM_DETAIL_THROW_EXCEPTION(
        hadesmem::Error{} << hadesmem::ErrorString{
                               "GetCreationParameters failed."}
                          << hadesmem::ErrorCodeWinHr{get_create_params_hr});
    }
    window_info.old_hwnd_ = create_params.hFocusWindow;
    window_info.old_wndproc_ = reinterpret_cast<WNDPROC>(
      ::SetWindowLongPtrW(create_params.hFocusWindow,
                          GWLP_WNDPROC,
                          reinterpret_cast<LONG_PTR>(&WindowProc)));
    render_info.wndproc_swapped_ = true;
    HADESMEM_DETAIL_TRACE_FORMAT_A("Replaced window procedure located at %p.",
                                   window_info.old_wndproc_);
  }
}

void InitializeAntTweakBar(TwGraphAPI api, void* device, bool& initialized)
{
  if (AntTweakBarInitializedAny())
  {
    HADESMEM_DETAIL_TRACE_A(
      "WARNING! AntTweakBar is already initialized. Skipping.");
    return;
  }

  if (!TwInit(api, device))
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(hadesmem::Error{}
                                    << hadesmem::ErrorString{"TwInit failed."});
  }

  initialized = true;

  auto& window_info = GetWindowInfo();
  RECT wnd_rect{0, 0, 0, 0};
  if (!window_info.old_hwnd_ ||
      !GetWindowRect(window_info.old_hwnd_, &wnd_rect))
  {
    wnd_rect = RECT{0, 0, 800, 600};
  }

  if (!TwWindowSize(wnd_rect.right, wnd_rect.bottom))
  {
    DWORD const last_error = ::GetLastError();
    HADESMEM_DETAIL_THROW_EXCEPTION(
      hadesmem::Error{} << hadesmem::ErrorString{"TwWindowSize failed."}
                        << hadesmem::ErrorCodeWinLast{last_error});
  }

  auto const bar = TwNewBar("HadesMem");
  if (!bar)
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(
      hadesmem::Error{} << hadesmem::ErrorString{"TwNewBar failed."});
  }
}

void CleanupAntTweakBar(bool& initialized)
{
  if (initialized)
  {
    if (!TwTerminate())
    {
      HADESMEM_DETAIL_THROW_EXCEPTION(
        hadesmem::Error{} << hadesmem::ErrorString{"TwTerminate failed."});
    }

    initialized = false;
  }
}

void CleanupWndproc(bool& wndproc_swapped)
{
  if (wndproc_swapped)
  {
    WindowInfo& window_info = GetWindowInfo();
    if (window_info.old_wndproc_ != nullptr)
    {
      ::SetWindowLongPtrW(window_info.old_hwnd_,
                          GWLP_WNDPROC,
                          reinterpret_cast<LONG_PTR>(window_info.old_wndproc_));
      HADESMEM_DETAIL_TRACE_FORMAT_A("Reset window procedure located at %p.",
                                     window_info.old_wndproc_);
      window_info.old_hwnd_ = nullptr;
      window_info.old_wndproc_ = nullptr;
      wndproc_swapped = false;
    }
  }
}

void HandleChangedSwapChainD3D11(IDXGISwapChain* swap_chain,
                                 RenderInfoD3D11& render_info)
{
  HADESMEM_DETAIL_TRACE_FORMAT_A("Got a new swap chain. Old = %p, New = %p.",
                                 render_info.swap_chain_,
                                 swap_chain);
  render_info.swap_chain_ = swap_chain;

  render_info.device_ = nullptr;

  render_info.first_time_ = true;

  CleanupAntTweakBar(render_info.tw_initialized_);

  CleanupWndproc(render_info.wndproc_swapped_);
}

void HandleChangedSwapChainD3D10(IDXGISwapChain* swap_chain,
                                 RenderInfoD3D10& render_info)
{
  HADESMEM_DETAIL_TRACE_FORMAT_A("Got a new swap chain. Old = %p, New = %p.",
                                 render_info.swap_chain_,
                                 swap_chain);
  render_info.swap_chain_ = swap_chain;

  render_info.device_ = nullptr;

  render_info.first_time_ = true;

  CleanupAntTweakBar(render_info.tw_initialized_);

  CleanupWndproc(render_info.wndproc_swapped_);
}

void HandleChangedDeviceD3D9(IDirect3DDevice9* device,
                             RenderInfoD3D9& render_info)
{
  HADESMEM_DETAIL_TRACE_FORMAT_A(
    "Got a new device. Old = %p, New = %p.", render_info.device_, device);
  render_info.device_ = device;

  render_info.first_time_ = true;

  CleanupAntTweakBar(render_info.tw_initialized_);

  CleanupWndproc(render_info.wndproc_swapped_);
}

void InitializeD3D11RenderInfo(RenderInfoD3D11& render_info)
{
  HADESMEM_DETAIL_TRACE_A("Initializing.");

  render_info.first_time_ = false;

  auto const get_device_hr = render_info.swap_chain_->GetDevice(
    __uuidof(render_info.device_),
    reinterpret_cast<void**>(&render_info.device_));
  if (FAILED(get_device_hr))
  {
    HADESMEM_DETAIL_TRACE_FORMAT_A(
      "WARNING! IDXGISwapChain::GetDevice failed. HR = %08X.", get_device_hr);
    return;
  }

  InitializeWndprocHook(render_info);

  InitializeAntTweakBar(
    TW_DIRECT3D11, render_info.device_, render_info.tw_initialized_);

  HADESMEM_DETAIL_TRACE_A("Initialized successfully.");
}

void InitializeD3D10RenderInfo(RenderInfoD3D10& render_info)
{
  HADESMEM_DETAIL_TRACE_A("Initializing.");

  render_info.first_time_ = false;

  auto const get_device_hr = render_info.swap_chain_->GetDevice(
    __uuidof(render_info.device_),
    reinterpret_cast<void**>(&render_info.device_));
  if (FAILED(get_device_hr))
  {
    HADESMEM_DETAIL_TRACE_FORMAT_A(
      "WARNING! IDXGISwapChain::GetDevice failed. HR = %08X.", get_device_hr);
    return;
  }

  InitializeWndprocHook(render_info);

  InitializeAntTweakBar(
    TW_DIRECT3D10, render_info.device_, render_info.tw_initialized_);

  HADESMEM_DETAIL_TRACE_A("Initialized successfully.");
}

void InitializeD3D9RenderInfo(RenderInfoD3D9& render_info)
{
  HADESMEM_DETAIL_TRACE_A("Initializing.");

  render_info.first_time_ = false;

  InitializeWndprocHook(render_info);

  InitializeAntTweakBar(
    TW_DIRECT3D9, render_info.device_, render_info.tw_initialized_);

  HADESMEM_DETAIL_TRACE_A("Initialized successfully.");
}

void HandleOnFrameD3D11(IDXGISwapChain* swap_chain)
{
  auto& render_info = GetRenderInfoD3D11();
  if (render_info.swap_chain_ != swap_chain)
  {
    HandleChangedSwapChainD3D11(swap_chain, render_info);
  }

  if (render_info.first_time_)
  {
    InitializeD3D11RenderInfo(render_info);
  }
}

void HandleOnFrameD3D10(IDXGISwapChain* swap_chain)
{
  auto& render_info = GetRenderInfoD3D10();
  if (render_info.swap_chain_ != swap_chain)
  {
    HandleChangedSwapChainD3D10(swap_chain, render_info);
  }

  if (render_info.first_time_)
  {
    InitializeD3D10RenderInfo(render_info);
  }
}

void HandleOnFrameD3D9(IDirect3DDevice9* device)
{
  auto& render_info = GetRenderInfoD3D9();
  if (render_info.device_ != device)
  {
    HandleChangedDeviceD3D9(device, render_info);
  }

  if (render_info.first_time_)
  {
    InitializeD3D9RenderInfo(render_info);
  }
}

void OnFrameDXGI(IDXGISwapChain* swap_chain)
{
  HandleOnFrameD3D11(swap_chain);

  HandleOnFrameD3D10(swap_chain);

  auto& callbacks = GetOnFrameCallbacks();
  auto& render_interface = hadesmem::cerberus::GetRenderInterface();
  callbacks.Run(&render_interface);
}

void OnFrameD3D9(IDirect3DDevice9* device)
{
  HandleOnFrameD3D9(device);

  auto& callbacks = GetOnFrameCallbacks();
  auto& render_interface = hadesmem::cerberus::GetRenderInterface();
  callbacks.Run(&render_interface);
}

void DrawTweakBarImpl()
{
  if (!TwDraw())
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(hadesmem::Error{}
                                    << hadesmem::ErrorString{"TwDraw failed."});
  }
}

class RenderImpl : public hadesmem::cerberus::RenderInterface
{
public:
  virtual ~RenderImpl() final
  {
    bool initialized = AntTweakBarInitializedAny();
    CleanupAntTweakBar(initialized);
  }

  virtual std::size_t RegisterOnFrame(
    std::function<hadesmem::cerberus::OnFrameCallback> const& callback) final
  {
    return hadesmem::cerberus::RegisterOnFrameCallback(callback);
  }

  virtual void UnregisterOnFrame(std::size_t id) final
  {
    hadesmem::cerberus::UnregisterOnFrameCallback(id);
  }

  virtual void DrawTweakBar() final
  {
    DrawTweakBarImpl();
  }
};
}

namespace hadesmem
{

namespace cerberus
{

RenderInterface& GetRenderInterface() HADESMEM_DETAIL_NOEXCEPT
{
  static RenderImpl render_impl;
  return render_impl;
}

void InitializeRender()
{
  auto const dxgi_callback_id =
    hadesmem::cerberus::RegisterOnFrameCallbackDXGI(OnFrameDXGI);
  (void)dxgi_callback_id;

  auto const d3d9_callback_id =
    hadesmem::cerberus::RegisterOnFrameCallbackD3D9(OnFrameD3D9);
  (void)d3d9_callback_id;

  auto const draw_tweak_bar = [](RenderInterface* render)
  { render->DrawTweakBar(); };
  RegisterOnFrameCallback(draw_tweak_bar);
}

std::size_t
  RegisterOnFrameCallback(std::function<OnFrameCallback> const& callback)
{
  auto& callbacks = GetOnFrameCallbacks();
  return callbacks.Register(callback);
}

void UnregisterOnFrameCallback(std::size_t id)
{
  auto& callbacks = GetOnFrameCallbacks();
  return callbacks.Unregister(id);
}
}
}
<|endoftext|>


<commit_before>/*
* 2013+ Copyright (c) Andrey Kashin <kashin.andrej@gmail.com>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*/

#include <thread>

#include "react/react.hpp"
#include "react/aggregators/recent_trees_aggregator.hpp"
#include "react/aggregators/histogram_aggregator.hpp"
#include "react/aggregators/category_filter_aggregator.hpp"
#include "react/aggregators/parent_call_tree_aggregator.hpp"
#include "react/utils.hpp"

int action_code = react_define_new_action("ACTION");

void run_recent_trees_aggregator_example() {
	react::recent_trees_aggregator_t aggregator(react::get_actions_set(), 3);
	react_activate(&aggregator);

	react_submit_progress();

	{
		react_start_action(action_code);
		react_stop_action(action_code);
		react_submit_progress();
	}

	{
		react_start_action(action_code);
		react_stop_action(action_code);
		react_start_action(action_code);
		react_stop_action(action_code);
		react_submit_progress();
	}

	{
		react_start_action(action_code);
		react_stop_action(action_code);
	}

	react_deactivate();

	print_json(aggregator);
}

void run_category_filter_aggregator_example() {
	auto important_trees_aggregator =
		std::make_shared<react::recent_trees_aggregator_t>(react::get_actions_set(), 3);

	auto unimportant_trees_aggregator =
		std::make_shared<react::recent_trees_aggregator_t>(react::get_actions_set(), 3);

	react::category_filter_aggregator_t<bool> category_filter_aggregator(
		react::get_actions_set(),
		std::make_shared<react::stat_extractor_t<bool>>("important")
	);

	category_filter_aggregator.add_category_aggregator(
		false, unimportant_trees_aggregator
	);

	category_filter_aggregator.add_category_aggregator(
		true, important_trees_aggregator
	);

	{
		react_activate(&category_filter_aggregator);
		react_add_stat_string("name", "first_tree");
		react_add_stat_bool("important", true);
		react_deactivate();
	}

	{
		react_activate(&category_filter_aggregator);
		react_add_stat_string("name", "second_tree");
		react_add_stat_bool("important", false);
		react_deactivate();
	}

	{
		react_activate(&category_filter_aggregator);
		react_add_stat_string("name", "third_tree");
		react_add_stat_bool("important", true);
		react_deactivate();
	}

	print_json(category_filter_aggregator);
}

void run_histogram_aggregator_example() {
	std::vector<int> ticks = {1, 2, 4, 8, 16, 32, 64, 128, 256};
	auto histogram_updater = std::make_shared<react::action_time_histogram_updater_t>(action_code);
	react::histogram_aggregator_t<react::histogram1D_t> histogram_aggregator(
		react::get_actions_set(), histogram_updater, ticks
	);

	{
		react_activate(&histogram_aggregator);
		react_start_action(action_code);
		react_stop_action(action_code);
		react_deactivate();
	}

	{
		react_activate(&histogram_aggregator);
		react_start_action(action_code);
		usleep(100);
		react_stop_action(action_code);
		react_deactivate();
	}

	{
		react_activate(&histogram_aggregator);
		react_start_action(action_code);
		react_stop_action(action_code);
		react_deactivate();
	}

	print_json(histogram_aggregator);
}

void run_subthread_aggregator_example() {
	const int main_thread_action = react_define_new_action("MAIN_THREAD");
	const int subthread_action = react_define_new_action("SUBTHREAD");
	react::recent_trees_aggregator_t aggregator(react::get_actions_set(), 1);

	react_activate(&aggregator);

	react_start_action(main_thread_action);

	std::thread thread(
		[&](std::shared_ptr<react::aggregator_t> aggregator) {
			react_activate(&(*aggregator));

			react_start_action(subthread_action);
			react_stop_action(subthread_action);

			react_deactivate();
		},
		react::create_subthread_aggregator()
	);
	thread.join();

	react_stop_action(main_thread_action);

	react_start_action(main_thread_action);
	react_stop_action(main_thread_action);

	react_deactivate();

	print_json(aggregator);
}

int main() {
	run_recent_trees_aggregator_example();
	run_category_filter_aggregator_example();
	run_histogram_aggregator_example();
	run_subthread_aggregator_example();
	return 0;
}
<commit_msg>examples: No lambdas :(<commit_after>/*
* 2013+ Copyright (c) Andrey Kashin <kashin.andrej@gmail.com>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*/

#include <thread>

#include "react/react.hpp"
#include "react/aggregators/recent_trees_aggregator.hpp"
#include "react/aggregators/histogram_aggregator.hpp"
#include "react/aggregators/category_filter_aggregator.hpp"
#include "react/aggregators/parent_call_tree_aggregator.hpp"
#include "react/utils.hpp"

int action_code = react_define_new_action("ACTION");

void run_recent_trees_aggregator_example() {
	react::recent_trees_aggregator_t aggregator(react::get_actions_set(), 3);
	react_activate(&aggregator);

	react_submit_progress();

	{
		react_start_action(action_code);
		react_stop_action(action_code);
		react_submit_progress();
	}

	{
		react_start_action(action_code);
		react_stop_action(action_code);
		react_start_action(action_code);
		react_stop_action(action_code);
		react_submit_progress();
	}

	{
		react_start_action(action_code);
		react_stop_action(action_code);
	}

	react_deactivate();

	print_json(aggregator);
}

void run_category_filter_aggregator_example() {
	auto important_trees_aggregator =
		std::make_shared<react::recent_trees_aggregator_t>(react::get_actions_set(), 3);

	auto unimportant_trees_aggregator =
		std::make_shared<react::recent_trees_aggregator_t>(react::get_actions_set(), 3);

	react::category_filter_aggregator_t<bool> category_filter_aggregator(
		react::get_actions_set(),
		std::make_shared<react::stat_extractor_t<bool>>("important")
	);

	category_filter_aggregator.add_category_aggregator(
		false, unimportant_trees_aggregator
	);

	category_filter_aggregator.add_category_aggregator(
		true, important_trees_aggregator
	);

	{
		react_activate(&category_filter_aggregator);
		react_add_stat_string("name", "first_tree");
		react_add_stat_bool("important", true);
		react_deactivate();
	}

	{
		react_activate(&category_filter_aggregator);
		react_add_stat_string("name", "second_tree");
		react_add_stat_bool("important", false);
		react_deactivate();
	}

	{
		react_activate(&category_filter_aggregator);
		react_add_stat_string("name", "third_tree");
		react_add_stat_bool("important", true);
		react_deactivate();
	}

	print_json(category_filter_aggregator);
}

void run_histogram_aggregator_example() {
	std::vector<int> ticks = {1, 2, 4, 8, 16, 32, 64, 128, 256};
	auto histogram_updater = std::make_shared<react::action_time_histogram_updater_t>(action_code);
	react::histogram_aggregator_t<react::histogram1D_t> histogram_aggregator(
		react::get_actions_set(), histogram_updater, ticks
	);

	{
		react_activate(&histogram_aggregator);
		react_start_action(action_code);
		react_stop_action(action_code);
		react_deactivate();
	}

	{
		react_activate(&histogram_aggregator);
		react_start_action(action_code);
		usleep(100);
		react_stop_action(action_code);
		react_deactivate();
	}

	{
		react_activate(&histogram_aggregator);
		react_start_action(action_code);
		react_stop_action(action_code);
		react_deactivate();
	}

	print_json(histogram_aggregator);
}

const int main_thread_action = react_define_new_action("MAIN_THREAD");
const int subthread_action = react_define_new_action("SUBTHREAD");

void subthread_worker(std::shared_ptr<react::aggregator_t> aggregator) {
	react_activate(&(*aggregator));

	react_start_action(subthread_action);
	react_stop_action(subthread_action);

	react_deactivate();
}

void run_subthread_aggregator_example() {
	react::recent_trees_aggregator_t aggregator(react::get_actions_set(), 1);

	react_activate(&aggregator);

	react_start_action(main_thread_action);

	std::thread thread(
		&subthread_worker,
		react::create_subthread_aggregator()
	);
	thread.join();

	react_stop_action(main_thread_action);

	react_start_action(main_thread_action);
	react_stop_action(main_thread_action);

	react_deactivate();

	print_json(aggregator);
}

int main() {
	run_recent_trees_aggregator_example();
	run_category_filter_aggregator_example();
	run_histogram_aggregator_example();
	run_subthread_aggregator_example();
	return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015 Nathan Osman
 *
 * 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 <QCommandLineOption>
#include <QCommandLineParser>
#include <QCoreApplication>
#include <QDir>
#include <QHostAddress>
#include <QStringList>

#include <QHttpEngine/QFilesystemHandler>
#include <QHttpEngine/QHttpServer>

int main(int argc, char * argv[])
{
    QCoreApplication a(argc, argv);

    // Build the command-line options
    QCommandLineParser parser;
    QCommandLineOption addressOption(
        QStringList() << "a" << "address",
        "address to bind to",
        "address",
        "127.0.0.1"
    );
    parser.addOption(addressOption);
    QCommandLineOption portOption(
        QStringList() << "p" << "port",
        "port to listen on",
        "port",
        "8000"
    );
    parser.addOption(portOption);
    QCommandLineOption dirOption(
        QStringList() << "d" << "directory",
        "directory to serve",
        "directory",
        QDir::homePath()
    );
    parser.addOption(dirOption);
    parser.addHelpOption();

    // Parse the options that were provided
    parser.process(a);

    // Obtain the values
    QHostAddress address = QHostAddress(parser.value(addressOption));
    quint16 port = parser.value(portOption).toInt();
    QString dir = parser.value(dirOption);

    // Create the filesystem handler and server
    QFilesystemHandler handler(dir);
    QHttpServer server(&handler);

    // Attempt to listen on the specified port
    if (!server.listen(address, port)) {
        qCritical("Unable to listen on the specified port.");
        return 1;
    }

    return a.exec();
}
<commit_msg>Change default path of example to current directory.<commit_after>/*
 * Copyright (c) 2015 Nathan Osman
 *
 * 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 <QCommandLineOption>
#include <QCommandLineParser>
#include <QCoreApplication>
#include <QDir>
#include <QHostAddress>
#include <QStringList>

#include <QHttpEngine/QFilesystemHandler>
#include <QHttpEngine/QHttpServer>

int main(int argc, char * argv[])
{
    QCoreApplication a(argc, argv);

    // Build the command-line options
    QCommandLineParser parser;
    QCommandLineOption addressOption(
        QStringList() << "a" << "address",
        "address to bind to",
        "address",
        "127.0.0.1"
    );
    parser.addOption(addressOption);
    QCommandLineOption portOption(
        QStringList() << "p" << "port",
        "port to listen on",
        "port",
        "8000"
    );
    parser.addOption(portOption);
    QCommandLineOption dirOption(
        QStringList() << "d" << "directory",
        "directory to serve",
        "directory",
        QDir::currentPath()
    );
    parser.addOption(dirOption);
    parser.addHelpOption();

    // Parse the options that were provided
    parser.process(a);

    // Obtain the values
    QHostAddress address = QHostAddress(parser.value(addressOption));
    quint16 port = parser.value(portOption).toInt();
    QString dir = parser.value(dirOption);

    // Create the filesystem handler and server
    QFilesystemHandler handler(dir);
    QHttpServer server(&handler);

    // Attempt to listen on the specified port
    if (!server.listen(address, port)) {
        qCritical("Unable to listen on the specified port.");
        return 1;
    }

    return a.exec();
}
<|endoftext|>


<commit_before>/*
    Copyright (C) 2010 Jochen Gerhard <gerhard@compeng.uni-frankfurt.de>
    Copyright (C) 2010-2012 Matthias Kretz <kretz@kde.org>

    Permission to use, copy, modify, and distribute this software
    and its documentation for any purpose and without fee is hereby
    granted, provided that the above copyright notice appear in all
    copies and that both that the copyright notice and this
    permission notice and warranty disclaimer appear in supporting
    documentation, and that the name of the author not be used in
    advertising or publicity pertaining to distribution of the
    software without specific, written prior permission.

    The author disclaim all warranties with regard to this
    software, including all implied warranties of merchantability
    and fitness.  In no event shall the author be liable for any
    special, indirect or consequential damages or any damages
    whatsoever resulting from loss of use, data or profits, whether
    in an action of contract, negligence or other tortious action,
    arising out of or in connection with the use or performance of
    this software.

*/

/*!
  Finite difference method example

  We calculate central differences for a given function and
  compare it to the analytical solution.

*/

#include <Vc/Vc>
#include <iostream>
#include <iomanip>
#include <cmath>
#include "../tsc.h"
#include <common/macros.h>

#define USE_SCALAR_SINCOS

enum {
  N = 10240000,
  PrintStep = 1000000
};

static const float epsilon = 1e-7f;
static const float lower = 0.f;
static const float upper = 40000.f;
static const float h = (upper - lower) / N;

// dfu is the derivative of fu. This is really easy for sine and cosine:
static inline float  fu(float x) { return ( std::sin(x) ); }
static inline float dfu(float x) { return ( std::cos(x) ); }

static inline Vc::float_v fu(Vc::float_v::AsArg x) {
#ifdef USE_SCALAR_SINCOS
  Vc::float_v r;
  for (int i = 0; i < Vc::float_v::Size; ++i) {
    r[i] = std::sin(x[i]);
  }
  return r;
#else
  return Vc::sin(x);
#endif
}

static inline Vc::float_v dfu(Vc::float_v::AsArg x) {
#ifdef USE_SCALAR_SINCOS
  Vc::float_v r;
  for (int i = 0; i < Vc::float_v::Size; ++i) {
    r[i] = std::cos(x[i]);
  }
  return r;
#else
  return Vc::cos(x);
#endif
}

using Vc::float_v;

// It is important for this example that the following variables (especially dy_points) are global
// variables. Else the compiler can optimze all calculations of dy away except for the few places
// where the value is used in printResults.
Vc::Memory<float_v, N> x_points;
Vc::Memory<float_v, N> y_points;
float *VC_RESTRICT dy_points;

void printResults()
{
    std::cout
        << "------------------------------------------------------------\n"
        << std::setw(15) << "fu(x_i)"
        << std::setw(15) << "FD fu'(x_i)"
        << std::setw(15) << "SYM fu'(x)"
        << std::setw(15) << "error %\n";
    for (int i = 0; i < N; i += PrintStep) {
        std::cout
            << std::setw(15) << y_points[i]
            << std::setw(15) << dy_points[i]
            << std::setw(15) << dfu(x_points[i])
            << std::setw(15) << std::abs((dy_points[i] - dfu(x_points[i])) / (dfu(x_points[i] + epsilon)) * 100)
            << "\n";
    }
    std::cout
        << std::setw(15) << y_points[N - 1]
        << std::setw(15) << dy_points[N - 1]
        << std::setw(15) << dfu(x_points[N - 1])
        << std::setw(15) << std::abs((dy_points[N - 1] - dfu(x_points[N - 1])) / (dfu(x_points[N - 1] + epsilon)) * 100)
        << std::endl;
}

int main()
{
    {
      float_v x_i(float_v::IndexType::IndexesFromZero());
      for ( unsigned int i = 0; i < x_points.vectorsCount(); ++i, x_i += float_v::Size ) {
        const float_v x = x_i * h;
        x_points.vector(i) = x;
        y_points.vector(i) = fu(x);
      }
    }

    dy_points = Vc::malloc<float, Vc::AlignOnVector>(N + float_v::Size - 1) + (float_v::Size - 1);

    double speedup;
    TimeStampCounter timer;

    { ///////// ignore this part - it only wakes up the CPU ////////////////////////////
        const float oneOver2h = 0.5f / h;

        // set borders explicit as up- or downdifferential
        dy_points[0] = (y_points[1] - y_points[0]) / h;
        // GCC auto-vectorizes the following loop. It is interesting to see that both Vc::Scalar and
        // Vc::SSE are faster, though.
        for ( int i = 1; i < N - 1; ++i) {
            dy_points[i] = (y_points[i + 1] - y_points[i - 1]) * oneOver2h;
        }
        dy_points[N - 1] = (y_points[N - 1] - y_points[N - 2]) / h;
    } //////////////////////////////////////////////////////////////////////////////////

    {
        std::cout << "\n" << std::setw(60) << "Classical finite difference method" << std::endl;
        timer.Start();

        const float oneOver2h = 0.5f / h;

        // set borders explicit as up- or downdifferential
        dy_points[0] = (y_points[1] - y_points[0]) / h;
        // GCC auto-vectorizes the following loop. It is interesting to see that both Vc::Scalar and
        // Vc::SSE are faster, though.
        for ( int i = 1; i < N - 1; ++i) {
            dy_points[i] = (y_points[i + 1] - y_points[i - 1]) * oneOver2h;
        }
        dy_points[N - 1] = (y_points[N - 1] - y_points[N - 2]) / h;

        timer.Stop();
        printResults();
        std::cout << "cycle count: " << timer.Cycles()
            << " | " << static_cast<double>(N * 2) / timer.Cycles() << " FLOP/cycle"
            << " | " << static_cast<double>(N * 2 * sizeof(float)) / timer.Cycles() << " Byte/cycle"
            << "\n";
    }

    speedup = timer.Cycles();
    {
        std::cout << std::setw(60) << "Vectorized finite difference method" << std::endl;
        timer.Start();

        // All the differentials require to calculate (r - l) / 2h, where we calculate 1/2h as a
        // constant before the loop to avoid unnecessary calculations. Note that a good compiler can
        // already do this for you.
        const float_v oneOver2h = 0.5f / h;

        // Calculate the left border
        dy_points[0] = (y_points[1] - y_points[0]) / h;

        // Calculate the differentials streaming through the y and dy memory. The picture below
        // should give an idea of what values in y get read and what values are written to dy in
        // each iteration:
        //
        // y  [...................................]
        //     00001111222233334444555566667777
        //       00001111222233334444555566667777
        // dy [...................................]
        //      00001111222233334444555566667777
        //
        // The loop is manually unrolled four times to improve instruction level parallelism and
        // prefetching on architectures where four vectors fill one cache line. (Note that this
        // unrolling breaks auto-vectorization of the Vc::Scalar implementation when compiling with
        // GCC.)
        const float *y_ptr = y_points;
        const float *const y_ptr_end = y_ptr + y_points.entriesCount() - 2;
        float_v y0(y_ptr, Vc::Prefetch);
#pragma noprefetch
        for (float *dy_ptr = &dy_points[1]; y_ptr < y_ptr_end; dy_ptr += 4 * float_v::Size) {
            float_v y2(y_ptr += float_v::Size, Vc::Prefetch);
            float_v y4(y_ptr += float_v::Size, Vc::Prefetch);
            float_v y6(y_ptr += float_v::Size, Vc::Prefetch);

            ((y0.shifted(2, y2) - y0) * oneOver2h).store(dy_ptr + 0 * float_v::Size, Vc::Streaming);

            y0.load(y_ptr += float_v::Size, Vc::Prefetch);

            ((y2.shifted(2, y4) - y2) * oneOver2h).store(dy_ptr + 1 * float_v::Size, Vc::Streaming);
            ((y4.shifted(2, y6) - y4) * oneOver2h).store(dy_ptr + 2 * float_v::Size, Vc::Streaming);
            ((y6.shifted(2, y0) - y6) * oneOver2h).store(dy_ptr + 3 * float_v::Size, Vc::Streaming);
        }

        /*
        for (unsigned int i = 0; i < (y_points.entriesCount() - 2) / float_v::Size; i += 4) {
            // Prefetches make sure the data which is going to be used in 24/4 iterations is already
            // in the L1 cache. The prefetchForOneRead additionally instructs the CPU to not evict
            // these cache lines to L2/L3.
            Vc::prefetchForOneRead(&y_points[(i + 24) * float_v::Size]);

            // calculate float_v::Size differentials per (left - right) / 2h
            const float_v dy0 = (y_points.vector(i + 0, 2) - y_points.vector(i + 0)) * oneOver2h;
            const float_v dy1 = (y_points.vector(i + 1, 2) - y_points.vector(i + 1)) * oneOver2h;
            const float_v dy2 = (y_points.vector(i + 2, 2) - y_points.vector(i + 2)) * oneOver2h;
            const float_v dy3 = (y_points.vector(i + 3, 2) - y_points.vector(i + 3)) * oneOver2h;

            // Use streaming stores to reduce the required memory bandwidth. Without streaming
            // stores the CPU would first have to load the cache line, where the store occurs, from
            // memory into L1, then overwrite the data, and finally write it back to memory. But
            // since we never actually need the data that the CPU fetched from memory we'd like to
            // keep that bandwidth free for real work. Streaming stores allow us to issue stores
            // which the CPU gathers in store buffers to form full cache lines, which then get
            // written back to memory directly without the costly read. Thus we make better use of
            // the available memory bandwidth.
            dy0.store(&dy_points[(i + 0) * float_v::Size + 1], Vc::Streaming);
            dy1.store(&dy_points[(i + 1) * float_v::Size + 1], Vc::Streaming);
            dy2.store(&dy_points[(i + 2) * float_v::Size + 1], Vc::Streaming);
            dy3.store(&dy_points[(i + 3) * float_v::Size + 1], Vc::Streaming);
        }
        */

        // Process the last vector. Note that this works for any N because Vc::Memory adds padding
        // to y_points and dy_points such that the last scalar value is somewhere inside lastVector.
        // The correct right border value for dy_points is overwritten in the last step unless N is
        // a multiple of float_v::Size + 2.
        // y  [...................................]
        //                                  8888
        //                                    8888
        // dy [...................................]
        //                                   8888
        {
            const size_t i = y_points.vectorsCount() - 1;
            const float_v left = y_points.vector(i, -2);
            const float_v right = y_points.lastVector();
            ((right - left) * oneOver2h).store(&dy_points[i * float_v::Size - 1], Vc::Unaligned);
        }

        // ... and finally the right border
        dy_points[N - 1] = (y_points[N - 1] - y_points[N - 2]) / h;

        timer.Stop();
        printResults();
        std::cout << "cycle count: " << timer.Cycles()
            << " | " << static_cast<double>(N * 2) / timer.Cycles() << " FLOP/cycle"
            << " | " << static_cast<double>(N * 2 * sizeof(float)) / timer.Cycles() << " Byte/cycle"
            << "\n";
    }
    speedup /= timer.Cycles();
    std::cout << "Speedup: " << speedup << "\n";

    Vc::free(dy_points - float_v::Size + 1);
    return 0;
}
<commit_msg>update finitediff example to the new possibilities, but now it does not work with float_v::Size == 1 anymore<commit_after>/*
    Copyright (C) 2010 Jochen Gerhard <gerhard@compeng.uni-frankfurt.de>
    Copyright (C) 2010-2012 Matthias Kretz <kretz@kde.org>

    Permission to use, copy, modify, and distribute this software
    and its documentation for any purpose and without fee is hereby
    granted, provided that the above copyright notice appear in all
    copies and that both that the copyright notice and this
    permission notice and warranty disclaimer appear in supporting
    documentation, and that the name of the author not be used in
    advertising or publicity pertaining to distribution of the
    software without specific, written prior permission.

    The author disclaim all warranties with regard to this
    software, including all implied warranties of merchantability
    and fitness.  In no event shall the author be liable for any
    special, indirect or consequential damages or any damages
    whatsoever resulting from loss of use, data or profits, whether
    in an action of contract, negligence or other tortious action,
    arising out of or in connection with the use or performance of
    this software.

*/

/*!
  Finite difference method example

  We calculate central differences for a given function and
  compare it to the analytical solution.

*/

#include <Vc/Vc>
#include <iostream>
#include <iomanip>
#include <cmath>
#include "../tsc.h"
#include <common/macros.h>

#define USE_SCALAR_SINCOS

enum {
  N = 10240000,
  PrintStep = 1000000
};

static const float epsilon = 1e-7f;
static const float lower = 0.f;
static const float upper = 40000.f;
static const float h = (upper - lower) / N;

// dfu is the derivative of fu. This is really easy for sine and cosine:
static inline float  fu(float x) { return ( std::sin(x) ); }
static inline float dfu(float x) { return ( std::cos(x) ); }

static inline Vc::float_v fu(Vc::float_v::AsArg x) {
#ifdef USE_SCALAR_SINCOS
  Vc::float_v r;
  for (int i = 0; i < Vc::float_v::Size; ++i) {
    r[i] = std::sin(x[i]);
  }
  return r;
#else
  return Vc::sin(x);
#endif
}

static inline Vc::float_v dfu(Vc::float_v::AsArg x) {
#ifdef USE_SCALAR_SINCOS
  Vc::float_v r;
  for (int i = 0; i < Vc::float_v::Size; ++i) {
    r[i] = std::cos(x[i]);
  }
  return r;
#else
  return Vc::cos(x);
#endif
}

using Vc::float_v;

// It is important for this example that the following variables (especially dy_points) are global
// variables. Else the compiler can optimze all calculations of dy away except for the few places
// where the value is used in printResults.
Vc::Memory<float_v, N> x_points;
Vc::Memory<float_v, N> y_points;
float *VC_RESTRICT dy_points;

void printResults()
{
    std::cout
        << "------------------------------------------------------------\n"
        << std::setw(15) << "fu(x_i)"
        << std::setw(15) << "FD fu'(x_i)"
        << std::setw(15) << "SYM fu'(x)"
        << std::setw(15) << "error %\n";
    for (int i = 0; i < N; i += PrintStep) {
        std::cout
            << std::setw(15) << y_points[i]
            << std::setw(15) << dy_points[i]
            << std::setw(15) << dfu(x_points[i])
            << std::setw(15) << std::abs((dy_points[i] - dfu(x_points[i])) / (dfu(x_points[i] + epsilon)) * 100)
            << "\n";
    }
    std::cout
        << std::setw(15) << y_points[N - 1]
        << std::setw(15) << dy_points[N - 1]
        << std::setw(15) << dfu(x_points[N - 1])
        << std::setw(15) << std::abs((dy_points[N - 1] - dfu(x_points[N - 1])) / (dfu(x_points[N - 1] + epsilon)) * 100)
        << std::endl;
}

int main()
{
    {
      float_v x_i(float_v::IndexType::IndexesFromZero());
      for ( unsigned int i = 0; i < x_points.vectorsCount(); ++i, x_i += float_v::Size ) {
        const float_v x = x_i * h;
        x_points.vector(i) = x;
        y_points.vector(i) = fu(x);
      }
    }

    dy_points = Vc::malloc<float, Vc::AlignOnVector>(N + float_v::Size - 1) + (float_v::Size - 1);

    double speedup;
    TimeStampCounter timer;

    { ///////// ignore this part - it only wakes up the CPU ////////////////////////////
        const float oneOver2h = 0.5f / h;

        // set borders explicit as up- or downdifferential
        dy_points[0] = (y_points[1] - y_points[0]) / h;
        // GCC auto-vectorizes the following loop. It is interesting to see that both Vc::Scalar and
        // Vc::SSE are faster, though.
        for ( int i = 1; i < N - 1; ++i) {
            dy_points[i] = (y_points[i + 1] - y_points[i - 1]) * oneOver2h;
        }
        dy_points[N - 1] = (y_points[N - 1] - y_points[N - 2]) / h;
    } //////////////////////////////////////////////////////////////////////////////////

    {
        std::cout << "\n" << std::setw(60) << "Classical finite difference method" << std::endl;
        timer.Start();

        const float oneOver2h = 0.5f / h;

        // set borders explicit as up- or downdifferential
        dy_points[0] = (y_points[1] - y_points[0]) / h;
        // GCC auto-vectorizes the following loop. It is interesting to see that both Vc::Scalar and
        // Vc::SSE are faster, though.
        for ( int i = 1; i < N - 1; ++i) {
            dy_points[i] = (y_points[i + 1] - y_points[i - 1]) * oneOver2h;
        }
        dy_points[N - 1] = (y_points[N - 1] - y_points[N - 2]) / h;

        timer.Stop();
        printResults();
        std::cout << "cycle count: " << timer.Cycles()
            << " | " << static_cast<double>(N * 2) / timer.Cycles() << " FLOP/cycle"
            << " | " << static_cast<double>(N * 2 * sizeof(float)) / timer.Cycles() << " Byte/cycle"
            << "\n";
    }

    speedup = timer.Cycles();
    {
        std::cout << std::setw(60) << "Vectorized finite difference method" << std::endl;
        timer.Start();

        // All the differentials require to calculate (r - l) / 2h, where we calculate 1/2h as a
        // constant before the loop to avoid unnecessary calculations. Note that a good compiler can
        // already do this for you.
        const float_v oneOver2h = 0.5f / h;

        // Calculate the left border
        dy_points[0] = (y_points[1] - y_points[0]) / h;

        // Calculate the differentials streaming through the y and dy memory. The picture below
        // should give an idea of what values in y get read and what values are written to dy in
        // each iteration:
        //
        // y  [...................................]
        //     00001111222233334444555566667777
        //       00001111222233334444555566667777
        // dy [...................................]
        //      00001111222233334444555566667777
        //
        // The loop is manually unrolled four times to improve instruction level parallelism and
        // prefetching on architectures where four vectors fill one cache line. (Note that this
        // unrolling breaks auto-vectorization of the Vc::Scalar implementation when compiling with
        // GCC.)

        // Use streaming stores to reduce the required memory bandwidth. Without streaming
        // stores the CPU would first have to load the cache line, where the store occurs, from
        // memory into L1, then overwrite the data, and finally write it back to memory. But
        // since we never actually need the data that the CPU fetched from memory we'd like to
        // keep that bandwidth free for real work. Streaming stores allow us to issue stores
        // which the CPU gathers in store buffers to form full cache lines, which then get
        // written back to memory directly without the costly read. Thus we make better use of
        // the available memory bandwidth.
        auto dy = Vc::makeIterator<float_v>(&dy_points[1], Vc::Streaming);

        // Prefetches make sure the data which is going to be used in the next iterations is already
        // in the L1 cache. The Vc::Prefetch flag provides some sensible default for loops where no
        // elements are skipped. You can use Vc::PrefetchFlag<L1, L2>() instead to set the stride of
        // L1 and L2 prefetches manually.
        auto y = y_points.begin(Vc::Prefetch);
        float_v y0 = *y++;
        const auto y_it_last = y_points.end();
#pragma noprefetch
        for (; y < y_it_last; y += 4 , dy += 4) {
            // calculate float_v::Size differentials per (left - right) / 2h
            float_v y1 = y[0];
            float_v y2 = y[1];
            float_v y3 = y[2];
            static_assert(float_v::Size >= 2, "This code requires a SIMD vector with at least two entries.");
            dy[0] = (y0.shifted(2, y1) - y0) * oneOver2h;
            y0 = y[3];
            dy[1] = (y1.shifted(2, y2) - y1) * oneOver2h;
            dy[2] = (y2.shifted(2, y3) - y2) * oneOver2h;
            dy[3] = (y3.shifted(2, y0) - y3) * oneOver2h;
        }
        /* Alternative:
         * use the STL transform algorithm. We have to rely on the compiler for unrolling, though.
         * At least ICC doesn't produce the best code from this...
         *
        std::transform(Vc::makeIterator(y_points.vector(1), Vc::Prefetch),
                y_points.end(Vc::Prefetch),
                Vc::makeIterator<float_v>(&dy_points[1], Vc::Streaming),
                [&y0,oneOver2h](float_v y1) -> float_v {
                    const auto r = (y0.shifted(2, y1) - y0) * oneOver2h;
                    y0 = y1;
                    return r;
                });
        */

        // Process the last vector. Note that this works for any N because Vc::Memory adds padding
        // to y_points and dy_points such that the last scalar value is somewhere inside lastVector.
        // The correct right border value for dy_points is overwritten in the last step unless N is
        // a multiple of float_v::Size + 2.
        // y  [...................................]
        //                                  8888
        //                                    8888
        // dy [...................................]
        //                                   8888
        {
            const size_t i = y_points.vectorsCount() - 1;
            const float_v left = y_points.vector(i, -2);
            const float_v right = y_points.lastVector();
            ((right - left) * oneOver2h).store(&dy_points[i * float_v::Size - 1], Vc::Unaligned);
        }

        // ... and finally the right border
        dy_points[N - 1] = (y_points[N - 1] - y_points[N - 2]) / h;

        timer.Stop();
        printResults();
        std::cout << "cycle count: " << timer.Cycles()
            << " | " << static_cast<double>(N * 2) / timer.Cycles() << " FLOP/cycle"
            << " | " << static_cast<double>(N * 2 * sizeof(float)) / timer.Cycles() << " Byte/cycle"
            << "\n";
    }
    speedup /= timer.Cycles();
    std::cout << "Speedup: " << speedup << "\n";

    Vc::free(dy_points - float_v::Size + 1);
    return 0;
}
<|endoftext|>


<commit_before>#include <osg/MatrixTransform>
#include <osg/Billboard>
#include <osg/Geode>
#include <osg/Group>
#include <osg/Notify>
#include <osg/Texture>

#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>

#include <osgProducer/Viewer>

#include <osgUtil/Optimizer>

// Customize the CopyOp so that we add our own verbose
// output of what's being copied.
class MyCopyOp : public osg::CopyOp
{
    public:

        inline MyCopyOp(CopyFlags flags=SHALLOW_COPY):
            osg::CopyOp(flags),
            _indent(0),
            _step(4) {}

        inline void moveIn() const { _indent += _step; }
        inline void moveOut() const { _indent -= _step; }
        inline void writeIndent() const
        {
            for(int i=0;i<_indent;++i) std::cout << " ";
        }

        virtual osg::Referenced*     operator() (const osg::Referenced* ref) const
        {
            writeIndent(); std::cout << "copying Referenced "<<ref<<std::endl;
            moveIn();
            osg::Referenced* ret_ref = CopyOp::operator()(ref);
            moveOut();
            return ret_ref;
        }

        virtual osg::Object*         operator() (const osg::Object* obj) const
        {
            writeIndent(); std::cout << "copying Object "<<obj;
            if (obj) std::cout<<" "<<obj->className();
            std::cout<<std::endl;
            moveIn();
            osg::Object* ret_obj = CopyOp::operator()(obj);
            moveOut();
            return ret_obj;
        }

        virtual osg::Node*           operator() (const osg::Node* node) const
        {
            writeIndent(); std::cout << "copying Node "<<node;
            if (node) std::cout<<" "<<node->className()<<" '"<<node->getName()<<"'";
            std::cout<<std::endl;
            moveIn();
            osg::Node* ret_node = CopyOp::operator()(node);
            moveOut();
            return ret_node;
        }

        virtual osg::Drawable*       operator() (const osg::Drawable* drawable) const
        {
            writeIndent(); std::cout << "copying Drawable "<<drawable;
            if (drawable) std::cout<<" "<<drawable->className();
            std::cout<<std::endl;
            moveIn();
            osg::Drawable* ret_drawable = CopyOp::operator()(drawable);
            moveOut();
            return ret_drawable;
        }

        virtual osg::StateSet*       operator() (const osg::StateSet* stateset) const
        {
            writeIndent(); std::cout << "copying StateSet "<<stateset;
            if (stateset) std::cout<<" "<<stateset->className();
            std::cout<<std::endl;
            moveIn();
            osg::StateSet* ret_stateset = CopyOp::operator()(stateset);
            moveOut();
            return ret_stateset;
        }

        virtual osg::StateAttribute* operator() (const osg::StateAttribute* attr) const
        {
            writeIndent(); std::cout << "copying StateAttribute "<<attr;
            if (attr) std::cout<<" "<<attr->className();
            std::cout<<std::endl;
            moveIn();
            osg::StateAttribute* ret_attr = CopyOp::operator()(attr);
            moveOut();
            return ret_attr;
        }

        virtual osg::Texture*        operator() (const osg::Texture* text) const
        {
            writeIndent(); std::cout << "copying Texture "<<text;
            if (text) std::cout<<" "<<text->className();
            std::cout<<std::endl;
            moveIn();
            osg::Texture* ret_text = CopyOp::operator()(text);
            moveOut();
            return ret_text;
        }

        virtual osg::Image*          operator() (const osg::Image* image) const
        {
            writeIndent(); std::cout << "copying Image "<<image;
            if (image) std::cout<<" "<<image->className();
            std::cout<<std::endl;
            moveIn();
            osg::Image* ret_image = CopyOp::operator()(image);
            moveOut();
            return ret_image;
        }

    protected:

        // must be mutable since CopyOp is passed around as const to
        // the various clone/copy constructors.
        mutable int _indent;
        mutable int _step;
};

int main( int argc, char **argv )
{
    // use an ArgumentParser object to manage the program arguments.
    osg::ArgumentParser arguments(&argc,argv);

    // set up the usage document, in case we need to print out how to use this program.
    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getProgramName()+" [options] filename ...");
    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");

    // initialize the viewer.
    osgProducer::Viewer viewer(arguments);

    // if user request help write it out to cout.
    if (arguments.read("-h") || arguments.read("--help"))
    {
        arguments.getApplicationUsage()->write(std::cout);
        return 1;
    }

    // any option left unread are converted into errors to write out later.
    arguments.reportRemainingOptionsAsUnrecognized();

    // report any errors if they have occured when parsing the program aguments.
    if (arguments.errors())
    {
        arguments.writeErrorMessages(std::cout);
        return 1;
    }

    // load the nodes from the commandline arguments.
    osg::Node* rootnode = osgDB::readNodeFiles(arguments);
    if (!rootnode)
    {
        return 1;
    }

    // run optimization over the scene graph
    osgUtil::Optimizer optimzer;
    optimzer.optimize(rootnode);

// -------------    Start of copy specific code -------------------------------------------------------

    // do a deep copy, using MyCopyOp to reveal whats going on under the good,
    // in your own code you'd typically just use the basic osg::CopyOp something like
    // osg::Node* mycopy = dynamic_cast<osg::Node*>(rootnode->clone(osg::CopyOp::DEEP_COPY_ALL));
    std::cout << "Doing a deep copy of scene graph"<<std::endl;
    // note, we need the dyanmic_cast because MS Visual Studio can't handle covarient
    // return types, so that clone has return just Object*.  bahh hum bug
    osg::Node* deep_copy = dynamic_cast<osg::Node*>(rootnode->clone(MyCopyOp(osg::CopyOp::DEEP_COPY_ALL)));

    std::cout << "----------------------------------------------------------------"<<std::endl;

    // do a shallow copy.
    std::cout << "Doing a shallow copy of scene graph"<<std::endl;
    osg::Node* shallow_copy = dynamic_cast<osg::Node*>(rootnode->clone(MyCopyOp(osg::CopyOp::SHALLOW_COPY)));

    // write out the various scene graphs so that they can be browsed, either
    // in an editor or using a graphics diff tool gdiff/xdiff/xxdiff.
    std::cout << std::endl << "Writing out the original scene graph as 'original.osg'"<<std::endl;
    osgDB::writeNodeFile(*rootnode,"original.osg");

    std::cout << "Writing out the deep copied scene graph as 'deep_copy.osg'"<<std::endl;
    osgDB::writeNodeFile(*deep_copy,"deep_copy.osg");

    std::cout << "Writing out the shallow copied scene graph as 'shallow_copy.osg'"<<std::endl;
    osgDB::writeNodeFile(*shallow_copy,"shallow_copy.osg");

    // You can use a bit mask to control which parts of the scene graph are shallow copied
    // vs deep copied.  The options are (from include/osg/CopyOp) :
    // enum Options {
    //        SHALLOW_COPY = 0,
    //        DEEP_COPY_OBJECTS = 1,
    //        DEEP_COPY_NODES = 2,
    //        DEEP_COPY_DRAWABLES = 4,
    //        DEEP_COPY_STATESETS = 8,
    //        DEEP_COPY_STATEATTRIBUTES = 16,
    //        DEEP_COPY_TEXTURES = 32,
    //        DEEP_COPY_IMAGES = 64,
    //        DEEP_COPY_ALL = 0xffffffff
    // };
    //
    // These options you can use together such as :
    //    osg::Node* mycopy = dynamic_cast<osg::Node*>(rootnode->clone(osg::CopyOp::DEEP_COPY_NODES | DEEP_COPY_DRAWABLES));
    // Which shares state but creates copies of all nodes and drawables (which contain the geometry).
    //
    // You may also want to subclass from CopyOp to provide finer grained control of what gets shared (shallow copy) vs
    // cloned (deep copy).

// -------------    End of copy specific code -------------------------------------------------------

    // set the scene to render
    viewer.setSceneData(rootnode);

    // create the windows and run the threads.
    viewer.realize(Producer::CameraGroup::ThreadPerCamera);

    while( !viewer.done() )
    {
        // wait for all cull and draw threads to complete.
        viewer.sync();

        // update the scene by traversing it with the the update visitor which will
        // call all node update callbacks and animations.
        viewer.update();

        // fire off the cull and draw traversals of the scene.
        viewer.frame();

    }

    return 0;
}
<commit_msg>Add osg:: infront of CopyOp instances.<commit_after>#include <osg/MatrixTransform>
#include <osg/Billboard>
#include <osg/Geode>
#include <osg/Group>
#include <osg/Notify>
#include <osg/Texture>

#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>

#include <osgProducer/Viewer>

#include <osgUtil/Optimizer>

// Customize the CopyOp so that we add our own verbose
// output of what's being copied.
class MyCopyOp : public osg::CopyOp
{
    public:

        inline MyCopyOp(CopyFlags flags=SHALLOW_COPY):
            osg::CopyOp(flags),
            _indent(0),
            _step(4) {}

        inline void moveIn() const { _indent += _step; }
        inline void moveOut() const { _indent -= _step; }
        inline void writeIndent() const
        {
            for(int i=0;i<_indent;++i) std::cout << " ";
        }

        virtual osg::Referenced*     operator() (const osg::Referenced* ref) const
        {
            writeIndent(); std::cout << "copying Referenced "<<ref<<std::endl;
            moveIn();
            osg::Referenced* ret_ref = osg::CopyOp::operator()(ref);
            moveOut();
            return ret_ref;
        }

        virtual osg::Object*         operator() (const osg::Object* obj) const
        {
            writeIndent(); std::cout << "copying Object "<<obj;
            if (obj) std::cout<<" "<<obj->className();
            std::cout<<std::endl;
            moveIn();
            osg::Object* ret_obj = osg::CopyOp::operator()(obj);
            moveOut();
            return ret_obj;
        }

        virtual osg::Node*           operator() (const osg::Node* node) const
        {
            writeIndent(); std::cout << "copying Node "<<node;
            if (node) std::cout<<" "<<node->className()<<" '"<<node->getName()<<"'";
            std::cout<<std::endl;
            moveIn();
            osg::Node* ret_node = osg::CopyOp::operator()(node);
            moveOut();
            return ret_node;
        }

        virtual osg::Drawable*       operator() (const osg::Drawable* drawable) const
        {
            writeIndent(); std::cout << "copying Drawable "<<drawable;
            if (drawable) std::cout<<" "<<drawable->className();
            std::cout<<std::endl;
            moveIn();
            osg::Drawable* ret_drawable = osg::CopyOp::operator()(drawable);
            moveOut();
            return ret_drawable;
        }

        virtual osg::StateSet*       operator() (const osg::StateSet* stateset) const
        {
            writeIndent(); std::cout << "copying StateSet "<<stateset;
            if (stateset) std::cout<<" "<<stateset->className();
            std::cout<<std::endl;
            moveIn();
            osg::StateSet* ret_stateset = osg::CopyOp::operator()(stateset);
            moveOut();
            return ret_stateset;
        }

        virtual osg::StateAttribute* operator() (const osg::StateAttribute* attr) const
        {
            writeIndent(); std::cout << "copying StateAttribute "<<attr;
            if (attr) std::cout<<" "<<attr->className();
            std::cout<<std::endl;
            moveIn();
            osg::StateAttribute* ret_attr = osg::CopyOp::operator()(attr);
            moveOut();
            return ret_attr;
        }

        virtual osg::Texture*        operator() (const osg::Texture* text) const
        {
            writeIndent(); std::cout << "copying Texture "<<text;
            if (text) std::cout<<" "<<text->className();
            std::cout<<std::endl;
            moveIn();
            osg::Texture* ret_text = osg::CopyOp::operator()(text);
            moveOut();
            return ret_text;
        }

        virtual osg::Image*          operator() (const osg::Image* image) const
        {
            writeIndent(); std::cout << "copying Image "<<image;
            if (image) std::cout<<" "<<image->className();
            std::cout<<std::endl;
            moveIn();
            osg::Image* ret_image = osg::CopyOp::operator()(image);
            moveOut();
            return ret_image;
        }

    protected:

        // must be mutable since CopyOp is passed around as const to
        // the various clone/copy constructors.
        mutable int _indent;
        mutable int _step;
};

int main( int argc, char **argv )
{
    // use an ArgumentParser object to manage the program arguments.
    osg::ArgumentParser arguments(&argc,argv);

    // set up the usage document, in case we need to print out how to use this program.
    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getProgramName()+" [options] filename ...");
    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");

    // initialize the viewer.
    osgProducer::Viewer viewer(arguments);

    // if user request help write it out to cout.
    if (arguments.read("-h") || arguments.read("--help"))
    {
        arguments.getApplicationUsage()->write(std::cout);
        return 1;
    }

    // any option left unread are converted into errors to write out later.
    arguments.reportRemainingOptionsAsUnrecognized();

    // report any errors if they have occured when parsing the program aguments.
    if (arguments.errors())
    {
        arguments.writeErrorMessages(std::cout);
        return 1;
    }

    // load the nodes from the commandline arguments.
    osg::Node* rootnode = osgDB::readNodeFiles(arguments);
    if (!rootnode)
    {
        return 1;
    }

    // run optimization over the scene graph
    osgUtil::Optimizer optimzer;
    optimzer.optimize(rootnode);

// -------------    Start of copy specific code -------------------------------------------------------

    // do a deep copy, using MyCopyOp to reveal whats going on under the good,
    // in your own code you'd typically just use the basic osg::CopyOp something like
    // osg::Node* mycopy = dynamic_cast<osg::Node*>(rootnode->clone(osg::CopyOp::DEEP_COPY_ALL));
    std::cout << "Doing a deep copy of scene graph"<<std::endl;
    // note, we need the dyanmic_cast because MS Visual Studio can't handle covarient
    // return types, so that clone has return just Object*.  bahh hum bug
    osg::Node* deep_copy = dynamic_cast<osg::Node*>(rootnode->clone(MyCopyOp(osg::CopyOp::DEEP_COPY_ALL)));

    std::cout << "----------------------------------------------------------------"<<std::endl;

    // do a shallow copy.
    std::cout << "Doing a shallow copy of scene graph"<<std::endl;
    osg::Node* shallow_copy = dynamic_cast<osg::Node*>(rootnode->clone(MyCopyOp(osg::CopyOp::SHALLOW_COPY)));

    // write out the various scene graphs so that they can be browsed, either
    // in an editor or using a graphics diff tool gdiff/xdiff/xxdiff.
    std::cout << std::endl << "Writing out the original scene graph as 'original.osg'"<<std::endl;
    osgDB::writeNodeFile(*rootnode,"original.osg");

    std::cout << "Writing out the deep copied scene graph as 'deep_copy.osg'"<<std::endl;
    osgDB::writeNodeFile(*deep_copy,"deep_copy.osg");

    std::cout << "Writing out the shallow copied scene graph as 'shallow_copy.osg'"<<std::endl;
    osgDB::writeNodeFile(*shallow_copy,"shallow_copy.osg");

    // You can use a bit mask to control which parts of the scene graph are shallow copied
    // vs deep copied.  The options are (from include/osg/CopyOp) :
    // enum Options {
    //        SHALLOW_COPY = 0,
    //        DEEP_COPY_OBJECTS = 1,
    //        DEEP_COPY_NODES = 2,
    //        DEEP_COPY_DRAWABLES = 4,
    //        DEEP_COPY_STATESETS = 8,
    //        DEEP_COPY_STATEATTRIBUTES = 16,
    //        DEEP_COPY_TEXTURES = 32,
    //        DEEP_COPY_IMAGES = 64,
    //        DEEP_COPY_ALL = 0xffffffff
    // };
    //
    // These options you can use together such as :
    //    osg::Node* mycopy = dynamic_cast<osg::Node*>(rootnode->clone(osg::CopyOp::DEEP_COPY_NODES | DEEP_COPY_DRAWABLES));
    // Which shares state but creates copies of all nodes and drawables (which contain the geometry).
    //
    // You may also want to subclass from CopyOp to provide finer grained control of what gets shared (shallow copy) vs
    // cloned (deep copy).

// -------------    End of copy specific code -------------------------------------------------------

    // set the scene to render
    viewer.setSceneData(rootnode);

    // create the windows and run the threads.
    viewer.realize(Producer::CameraGroup::ThreadPerCamera);

    while( !viewer.done() )
    {
        // wait for all cull and draw threads to complete.
        viewer.sync();

        // update the scene by traversing it with the the update visitor which will
        // call all node update callbacks and animations.
        viewer.update();

        // fire off the cull and draw traversals of the scene.
        viewer.frame();

    }

    return 0;
}
<|endoftext|>


<commit_before>//=============================================================================================================
/**
* @file     main.cpp
* @author   Jana Kiesel <jana.kiesel@tu-ilmenau.de>
*           Matti Hamalainen <msh@nmr.mgh.harvard.edu>
* @version  1.0
* @date     August, 2016
* @section  LICENSE
*
* Copyright (C) 2016, Jana Kiesel and Matti Hamalainen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that
* the following conditions are met:
*     * Redistributions of source code must retain the above copyright notice, this list of conditions and the
*       following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
*       the following disclaimer in the documentation and/or other materials provided with the distribution.
*     * Neither the name of MNE-CPP authors nor the names of its contributors may be used
*       to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*
* @brief    Example to project points on a surface and warp the surface
*
*/
//*************************************************************************************************************
//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include <mne/mne_project_to_surface.h>
#include <mne/mne.h>
#include <disp3D/view3D.h>
#include <disp3D/control/control3dwidget.h>
#include <fiff/fiff_dig_point_set.h>
#include <utils/warp.h>

//*************************************************************************************************************
//=============================================================================================================
// QT INCLUDES
//=============================================================================================================

#include <QApplication>
#include <QMainWindow>
#include <QCommandLineParser>

//*************************************************************************************************************
//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace DISP3DLIB;
using namespace MNELIB;
using namespace FIFFLIB;

//*************************************************************************************************************
//=============================================================================================================
// MAIN
//=============================================================================================================

//=============================================================================================================
/**
* The function main marks the entry point of the program.
* By default, main has the storage class extern.
*
* @param [in] argc (argument count) is an integer that indicates how many arguments were entered on the command line when the program was started.
* @param [in] argv (argument vector) is an array of pointers to arrays of character objects. The array objects are null-terminated strings, representing the arguments that were entered on the command line when the program was started.
* @return the value that was set to exit() (which is 0 if exit() is called via quit()).
*/

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // Command Line Parser
    QCommandLineParser parser;
    parser.setApplicationDescription("Projection Example");
    parser.addHelpOption();
    QCommandLineOption sampleBEMFileOption("f", "Path to BEM <file>.", "file",
                                           "D:/Studium/Master/Masterarbeit/Daten/warping/AVG3-0Years_segmented_BEM3-1824-1860-2530-bem.fif");

    parser.addOption(sampleBEMFileOption);
    parser.process(app);

    //########################################################################################
    // Read the average BEM
    QFile t_fileBem(parser.value(sampleBEMFileOption));
    MNEBem t_Bem(t_fileBem);

    // Read Patients Bem to compare
    QFile t_fileBemPatient("D:/Studium/Master/Masterarbeit/Daten/4926787/ID_4926787_act/bem/FREESURFER-5120-5120-5120-bem.fif");
    MNEBem t_BemPatient(t_fileBemPatient);

    // Read the Digitizer
    QFile t_fileDig("D:/Studium/Master/Masterarbeit/Daten/4926787/160130_151742_4926787_auditorytoneburst_raw.fif");
    FiffDigPointSet t_Dig(t_fileDig);

    MatrixXf Dig(t_Dig.size(), 3);
    for (int i = 0; i < t_Dig.size(); ++i)
    {
        Dig(i,0) = t_Dig[i].r[0];
        Dig(i,1) = t_Dig[i].r[1];
        Dig(i,2) = t_Dig[i].r[2];
    }

    // Read and apply Transformation on Average Bem (average to head)
    QFile t_fileTrans("D:/Studium/Master/Masterarbeit/Daten/4926787/AnalysisJana/NSSP_SGM_160130_151742_4926787_auditorytoneburst_raw-ave-trans.fif");
    FiffCoordTrans t_Trans (t_fileTrans);
    t_Bem.invtransform(t_Trans);

    // Read and apply Transformation on Digitizer and Average Bem (head to MRI)
    QFile t_fileTransP("D:/Studium/Master/Masterarbeit/Daten/4926787/AnalysisJana/patient-trans.fif");
    FiffCoordTrans t_transPatient (t_fileTransP);
    t_Bem.transform(t_transPatient);

    MatrixXf DigPatient(t_Dig.size(), 3);
    DigPatient=t_transPatient.apply_trans(Dig);
    FiffDigPointSet t_DigPatient(t_Dig);

    for (int i = 0; i < t_DigPatient.size(); ++i)
    {
        t_DigPatient[i].r[0] = DigPatient(i,0);
        t_DigPatient[i].r[1] = DigPatient(i,1);
        t_DigPatient[i].r[2] = DigPatient(i,2);
    }
    //Projection
    MatrixXf DigProject(t_DigPatient.size(), 3);
    VectorXi nearest;
    VectorXf dist;
    MNEProjectToSurface t_Avg4 (t_Bem[0]);

    t_Avg4.mne_find_closest_on_surface(DigPatient, t_DigPatient.size(), DigProject, nearest, dist);

    FiffDigPointSet t_DigProject(t_Dig);

    for (int i = 0; i < t_DigProject.size(); ++i)
    {
        t_DigProject[i].r[0] = DigProject(i,0);
        t_DigProject[i].r[1] = DigProject(i,1);
        t_DigProject[i].r[2] = DigProject(i,2);
    }

    // Warp
    MNEBem t_BemWarped(t_Bem);
    t_BemWarped.warp(DigProject, DigPatient);

    //Write warped file
    QFile t_fileBemWarped("D:/Studium/Master/Masterarbeit/Daten/4926787/AnalysisJana/warped_AVG3-0Years_segmented_BEM3-1824-1860-2530-bem.fif");
    t_BemWarped.write(t_fileBemWarped);
    t_fileBemWarped.close();

    //Show
    View3D::SPtr testWindow = View3D::SPtr(new View3D());
    testWindow->addBemData("AVG3-0Years", "BEM", t_Bem);
    testWindow->addBemData("warped AVG3-0Years", "BEM", t_BemWarped);
    testWindow->addBemData("4926787", "BEM", t_BemPatient);
    testWindow->addDigitizerData("Original", "Dig", t_Dig);
    testWindow->addDigitizerData("warped AVG3-0Years", "Dig", t_DigPatient);
    testWindow->addDigitizerData("AVG3-0Years", "Projected Dig", t_DigProject);

    testWindow->show();

    Control3DWidget::SPtr control3DWidget = Control3DWidget::SPtr(new Control3DWidget());
    control3DWidget->setView3D(testWindow);
    control3DWidget->show();

    return app.exec();
}
<commit_msg>[LIB-49] Writing warped bem<commit_after>//=============================================================================================================
/**
* @file     main.cpp
* @author   Jana Kiesel <jana.kiesel@tu-ilmenau.de>
*           Matti Hamalainen <msh@nmr.mgh.harvard.edu>
* @version  1.0
* @date     August, 2016
* @section  LICENSE
*
* Copyright (C) 2016, Jana Kiesel and Matti Hamalainen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that
* the following conditions are met:
*     * Redistributions of source code must retain the above copyright notice, this list of conditions and the
*       following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
*       the following disclaimer in the documentation and/or other materials provided with the distribution.
*     * Neither the name of MNE-CPP authors nor the names of its contributors may be used
*       to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*
* @brief    Example to project points on a surface and warp the surface
*
*/
//*************************************************************************************************************
//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include <mne/mne_project_to_surface.h>
#include <mne/mne.h>
#include <disp3D/view3D.h>
#include <disp3D/control/control3dwidget.h>
#include <fiff/fiff_dig_point_set.h>
#include <utils/warp.h>

//*************************************************************************************************************
//=============================================================================================================
// QT INCLUDES
//=============================================================================================================

#include <QApplication>
#include <QMainWindow>
#include <QCommandLineParser>

//*************************************************************************************************************
//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace DISP3DLIB;
using namespace MNELIB;
using namespace FIFFLIB;

//*************************************************************************************************************
//=============================================================================================================
// MAIN
//=============================================================================================================

//=============================================================================================================
/**
* The function main marks the entry point of the program.
* By default, main has the storage class extern.
*
* @param [in] argc (argument count) is an integer that indicates how many arguments were entered on the command line when the program was started.
* @param [in] argv (argument vector) is an array of pointers to arrays of character objects. The array objects are null-terminated strings, representing the arguments that were entered on the command line when the program was started.
* @return the value that was set to exit() (which is 0 if exit() is called via quit()).
*/

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // Command Line Parser
    QCommandLineParser parser;
    parser.setApplicationDescription("Projection Example");
    parser.addHelpOption();
    QCommandLineOption sampleBEMFileOption("f", "Path to BEM <file>.", "file",
                                           "D:/Studium/Master/Masterarbeit/Daten/AVG/AVG3-0Years_segmented_BEM3-1824-1860-2530-bem.fif");

    parser.addOption(sampleBEMFileOption);
    parser.process(app);

    //########################################################################################
    // Read the average BEM
    QFile t_fileBem(parser.value(sampleBEMFileOption));
    MNEBem t_Bem(t_fileBem);

    // Read Patients Bem to compare
    QFile t_fileBemPatient("D:/Studium/Master/Masterarbeit/Daten/4926787/ID_4926787_act/bem/FREESURFER-5120-5120-5120-bem.fif");
    MNEBem t_BemPatient(t_fileBemPatient);

    // Read the Digitizer
    QFile t_fileDig("D:/Studium/Master/Masterarbeit/Daten/4926787/160130_151742_4926787_auditorytoneburst_raw.fif");
    FiffDigPointSet t_Dig(t_fileDig);

    MatrixXf Dig(t_Dig.size(), 3);
    for (int i = 0; i < t_Dig.size(); ++i)
    {
        Dig(i,0) = t_Dig[i].r[0];
        Dig(i,1) = t_Dig[i].r[1];
        Dig(i,2) = t_Dig[i].r[2];
    }

    // Read and apply Transformation on Average Bem (average to head)
    QFile t_fileTrans("D:/Studium/Master/Masterarbeit/Daten/4926787/AnalysisJana/NSSP_SGM_160130_151742_4926787_auditorytoneburst_raw-ave-trans.fif");
    FiffCoordTrans t_Trans (t_fileTrans);
    t_Bem.invtransform(t_Trans);

    // Read and apply Transformation on Digitizer and Average Bem (head to MRI)
    QFile t_fileTransP("D:/Studium/Master/Masterarbeit/Daten/4926787/AnalysisJana/patient-trans.fif");
    FiffCoordTrans t_transPatient (t_fileTransP);
    t_Bem.transform(t_transPatient);

    MatrixXf DigPatient(t_Dig.size(), 3);
    DigPatient=t_transPatient.apply_trans(Dig);
    FiffDigPointSet t_DigPatient(t_Dig);

    for (int i = 0; i < t_DigPatient.size(); ++i)
    {
        t_DigPatient[i].r[0] = DigPatient(i,0);
        t_DigPatient[i].r[1] = DigPatient(i,1);
        t_DigPatient[i].r[2] = DigPatient(i,2);
    }
    //Projection
    MatrixXf DigProject(t_DigPatient.size(), 3);
    VectorXi nearest;
    VectorXf dist;
    MNEProjectToSurface t_Avg4 (t_Bem[0]);

    t_Avg4.mne_find_closest_on_surface(DigPatient, t_DigPatient.size(), DigProject, nearest, dist);

    FiffDigPointSet t_DigProject(t_Dig);

    for (int i = 0; i < t_DigProject.size(); ++i)
    {
        t_DigProject[i].r[0] = DigProject(i,0);
        t_DigProject[i].r[1] = DigProject(i,1);
        t_DigProject[i].r[2] = DigProject(i,2);
    }

    // Warp
    MNEBem t_BemWarped(t_Bem);
    t_BemWarped.warp(DigProject, DigPatient);

    //Write warped and translated Bem
    QFile t_fileBemWarped("D:/Studium/Master/Masterarbeit/Daten/4926787/AnalysisJana/warped_AVG3-0Years_segmented_BEM3-1824-1860-2530-bem.fif");
    t_BemWarped.write(t_fileBemWarped);
    t_fileBemWarped.close();

    //Write translated Bem
    QFile t_fileBemTrans("D:/Studium/Master/Masterarbeit/Daten/4926787/AnalysisJana/trans_AVG3-0Years_segmented_BEM3-1824-1860-2530-bem.fif");
    t_Bem.write(t_fileBemTrans);
    t_fileBemTrans.close();

    //Show
    View3D::SPtr testWindow = View3D::SPtr(new View3D());
    testWindow->addBemData("AVG3-0Years", "BEM", t_Bem);
    testWindow->addBemData("warped AVG3-0Years", "BEM", t_BemWarped);
    testWindow->addBemData("4926787", "BEM", t_BemPatient);
    testWindow->addDigitizerData("Original", "Dig", t_Dig);
    testWindow->addDigitizerData("warped AVG3-0Years", "Dig", t_DigPatient);
    testWindow->addDigitizerData("AVG3-0Years", "Projected Dig", t_DigProject);

    testWindow->show();

    Control3DWidget::SPtr control3DWidget = Control3DWidget::SPtr(new Control3DWidget());
    control3DWidget->setView3D(testWindow);
    control3DWidget->show();

    return app.exec();
}
<|endoftext|>