<commit_before>#include "window_manager.h"

#include <algorithm>
#include <cassert>

#include "base/geometry.h"
#include "base/logging.h"
#include "base/time.h"
#include "wm/keyboard_event.h"
#include "wm/mouse_event.h"

namespace naive {
namespace wm {

namespace {

void CollectGlobalLayers(std::vector<std::unique_ptr<Layer>>& accumulator,
                         Window* window,
                         int32_t start_x,
                         int32_t start_y) {
  // When a window is not visible, its descendants are all considered hidden.
  if (!window->is_visible())
    return;
  accumulator.push_back(std::make_unique<Layer>(window, start_x, start_y));
  for (auto* w : window->children())
    CollectGlobalLayers(accumulator, w, start_x + w->geometry().x(),
                        start_y + w->geometry().y());
}

}  // namespace

// static
WindowManager* WindowManager::g_window_manager = nullptr;

// static
void WindowManager::InitializeWindowManager(
    WmEventObserver* wm_event_observer) {
  g_window_manager = new WindowManager(wm_event_observer);
}

WindowManager* WindowManager::Get() {
  assert(g_window_manager != nullptr);
  return g_window_manager;
}

// TODO: use real dimension
WindowManager::WindowManager(WmEventObserver* wm_event_observer)
    : screen_width_(2560),
      screen_height_(1440),
      mouse_position_(1280.0f, 720.0f),
      last_mouse_position_(1280.0f, 720.0f),
      wm_event_observer_(wm_event_observer) {
  wm_event_observer_->set_wm_primitives(this);
  event::EventHub::Get()->AddEventObserver(this);
}

void WindowManager::Manage(Window* window) {
  TRACE("manage: %p", window);
  // TODO: window management policy
  windows_.push_back(window);
  window->set_managed(true);
  // We'll skip popup windows for configure.
  if (window->is_popup() || window->is_transient())
    return;
  wm_event_observer_->WindowCreated(window);
}

void WindowManager::RemoveWindow(Window* window) {
  auto* top_level = window->top_level();
  if (top_level == window) {
    // We are dealing with a top level window
    auto iter = std::find(windows_.begin(), windows_.end(), window);
    if (iter != windows_.end()) {
      if (*iter == focused_window_) {
        focused_window_->LoseFocus();
        auto* next_window = NextWindow(focused_window_);
        FocusWindow(next_window);
      }
      wm_event_observer_->WindowDestroying(window);
      windows_.erase(iter);
      wm_event_observer_->WindowDestroyed(window);
      // TODO: compositor needs to be notified of this
    }
  } else {
    if (window == focused_window_) {
      LOG_ERROR << "set focus to parent" << std::endl;
      window->LoseFocus();
      FocusWindow(window->parent());
      wm_event_observer_->WindowDestroyed(window);
    }
    if (window == global_grab_window_)
      global_grab_window_ = nullptr;
  }
}

void WindowManager::AddMouseObserver(MouseObserver* observer) {
  if (std::find(mouse_observers_.begin(), mouse_observers_.end(), observer) ==
      mouse_observers_.end()) {
    mouse_observers_.push_back(observer);
  }
}

void WindowManager::RemoveMouseObserver(MouseObserver* observer) {
  auto iter =
      std::find(mouse_observers_.begin(), mouse_observers_.end(), observer);
  if (iter != mouse_observers_.end())
    mouse_observers_.erase(iter);
}

void WindowManager::AddKeyboardObserver(KeyboardObserver* observer) {
  if (std::find(keyboard_observers_.begin(), keyboard_observers_.end(),
                observer) == keyboard_observers_.end()) {
    keyboard_observers_.push_back(observer);
  }
}

void WindowManager::RemoveKeyboardObserver(KeyboardObserver* observer) {
  auto iter = std::find(keyboard_observers_.begin(), keyboard_observers_.end(),
                        observer);
  if (iter != keyboard_observers_.end())
    keyboard_observers_.erase(iter);
}

void WindowManager::GlobalGrabWindow(Window* window) {
  if (global_grab_window_)
    global_grab_window_->GrabDone();
  global_grab_window_ = window;
}

bool WindowManager::pointer_moved() {
  return last_mouse_position_.manhattan_distance(mouse_position_) >= 1.0;
}

void WindowManager::OnMouseButton(uint32_t button,
                                  bool pressed,
                                  uint32_t modifiers,
                                  event::Leds leds) {
  MouseEventData data;
  data.button = button;
  DispatchMouseEvent(std::make_unique<MouseEvent>(
      FindMouseEventTarget(),
      pressed ? MouseEventType::MouseButtonDown : MouseEventType::MouseButtonUp,
      base::Time::CurrentTimeMilliSeconds(), modifiers, data,
      mouse_position_.x(), mouse_position_.y(), leds));
}

void WindowManager::OnMouseMotion(float dx,
                                  float dy,
                                  uint32_t modifiers,
                                  event::Leds leds) {
  float new_x = mouse_position_.x() + dx;
  float new_y = mouse_position_.y() + dy;
  if (mouse_position_.x() + dx >= screen_width_)
    new_x = screen_width_ - 0.4f;
  if (mouse_position_.x() + dx < 0.0f)
    new_x = 0.4f;
  if (mouse_position_.y() + dy >= screen_height_)
    new_y = screen_height_ - 0.4f;
  if (mouse_position_.y() + dy < 0.0f)
    new_y = 0.4f;
  last_mouse_position_ = mouse_position_;
  mouse_position_ = base::geometry::FloatPoint(new_x, new_y);

  MouseEventData data;
  data.delta[0] = static_cast<int32_t>(new_x - last_mouse_position_.x());
  data.delta[1] = static_cast<int32_t>(new_y - last_mouse_position_.y());
  DispatchMouseEvent(std::make_unique<MouseEvent>(
      FindMouseEventTarget(), MouseEventType::MouseMotion,
      base::Time::CurrentTimeMilliSeconds(), modifiers, data, new_x, new_y,
      leds));
}

void WindowManager::OnMouseScroll(float x_scroll,
                                  float y_scroll,
                                  uint32_t modifiers,
                                  event::Leds locks) {
  MouseEventData data;
  data.scroll[0] = x_scroll;
  data.scroll[1] = y_scroll;
  DispatchMouseEvent(std::make_unique<MouseEvent>(
      FindMouseEventTarget(), MouseEventType::MouseAxis,
      base::Time::CurrentTimeMilliSeconds(), modifiers, data,
      mouse_position_.x(), mouse_position_.y(), locks));
}

void WindowManager::OnKey(uint32_t keycode,
                          uint32_t modifiers,
                          bool key_down,
                          event::Leds locks) {
  auto event = std::make_unique<KeyboardEvent>(
      focused_window(), keycode, locks, base::Time::CurrentTimeMilliSeconds(),
      key_down, modifiers);
  if (wm_event_observer_->OnKey(event.get()))
    return;

  if (focused_window_) {
    for (auto observer : keyboard_observers_)
      observer->OnKey(event.get());
  }
  if (keycode == 0) {
    // TODO: send modifiers event
  }
}

std::vector<std::unique_ptr<Layer>>
WindowManager::WindowsInGlobalCoordinates() {
  std::vector<std::unique_ptr<Layer>> result;
  for (auto* w : windows_)
    CollectGlobalLayers(result, w, w->wm_x(), w->wm_y());
  return result;
}

Window* WindowManager::FindMouseEventTarget() {
  std::vector<std::unique_ptr<Layer>> layers = WindowsInGlobalCoordinates();
  int32_t mouse_x = static_cast<int32_t>(mouse_position_.x());
  int32_t mouse_y = static_cast<int32_t>(mouse_position_.y());

  // TODO: establish popup grab, and send popup done when clicking is outside.
  for (auto it = layers.rbegin(); it != layers.rend(); it++) {
    TRACE("Testing %d %d, window: %p, %d %d %d %d", mouse_x, mouse_y,
          (*it)->window(), (*it)->geometry().x(), (*it)->geometry().y(),
          (*it)->geometry().width(), (*it)->geometry().height());
    if ((*it)->geometry().ContainsPoint(mouse_x, mouse_y))
      return (*it)->window();
  }

  return nullptr;
}

void WindowManager::DispatchMouseEvent(std::unique_ptr<MouseEvent> event) {
  if (wm_event_observer_->OnMouseEvent(event.get()))
    return;

  if (event->window()) {
    if (global_grab_window_ && event->window() != global_grab_window_
        && event->type() == MouseEventType::MouseButtonDown) {
      global_grab_window_->GrabDone();
      global_grab_window_ = nullptr;
    }

    // Transform pointer location to surface local coordinates.
    std::vector<Window*> window_path;
    Window* window = event->window();
    window_path.push_back(window);
    while (window->parent()) {
      window_path.push_back(window->parent());
      window = window->parent();
    }
    uint32_t coord_x = event->x();
    uint32_t coord_y = event->y();
    for (auto it = window_path.rbegin(); it != window_path.rend(); it++) {
      coord_x = coord_x - (*it)->geometry().x();
      coord_y = coord_y - (*it)->geometry().y();
    }
    // TODO: this is dirty.. try a different approach!
    // Finally, window has a transformation
    coord_x -= window_path.back()->wm_x();
    coord_y -= window_path.back()->wm_y();
    event->set_coordinates(coord_x, coord_y);
    LOG_ERROR << " dispatch final coords: " << coord_x << " " << coord_y
              << std::endl;
    for (auto mouse_observer : mouse_observers_)
      mouse_observer->OnMouseEvent(event.get());
  }
}

Window* WindowManager::NextWindow(Window* window) {
  TRACE();
  auto iter = std::find(windows_.begin(), windows_.end(), window);
  if (iter != windows_.end() && iter + 1 != windows_.end())
    return *(iter + 1);
  if (iter == windows_.end() && windows_.size() > 0)
    return windows_.front();
  return nullptr;
}

Window* WindowManager::PreviousWindow(Window* window) {
  TRACE();
  auto iter = std::find(windows_.begin(), windows_.end(), window);
  if (iter != windows_.begin())
    return *(iter - 1);
  if (iter == windows_.begin() && windows_.size() > 0)
    return windows_.back();
  return nullptr;
}

void WindowManager::FocusWindow(Window* window) {
  TRACE("%p, current_focus: %p", window, focused_window_);
  if (window == focused_window_)
    return;

  if (focused_window_)
    focused_window_->LoseFocus();
  focused_window_ = window;
  for (auto* observer : keyboard_observers_)
    observer->OnFocus(window);
  if (window) {
    window->TakeFocus();
    RaiseWindow(window);
    TRACE("top_level: %p", window->top_level());
  }
}

void WindowManager::MoveResizeWindow(Window* window,
                                     base::geometry::Rect resize) {
  // window->SetPosition(resize.x(), resize.y());
  window->WmSetPosition(resize.x(), resize.y());
  window->WmSetSize(resize.width(), resize.height());
}

void WindowManager::RaiseWindow(Window* window) {
  auto it = std::find(windows_.begin(), windows_.end(), window);
  if (it != windows_.end()) {
    windows_.erase(it);
    windows_.push_back(window);
  }
}

}  // namespace wm
}  // namespace naive
<commit_msg>add guard to window manager.<commit_after>#include "window_manager.h"

#include <algorithm>
#include <cassert>

#include "base/geometry.h"
#include "base/logging.h"
#include "base/time.h"
#include "wm/keyboard_event.h"
#include "wm/mouse_event.h"

namespace naive {
namespace wm {

namespace {

void CollectGlobalLayers(std::vector<std::unique_ptr<Layer>>& accumulator,
                         Window* window,
                         int32_t start_x,
                         int32_t start_y) {
  // When a window is not visible, its descendants are all considered hidden.
  if (!window->is_visible())
    return;
  accumulator.push_back(std::make_unique<Layer>(window, start_x, start_y));
  for (auto* w : window->children())
    CollectGlobalLayers(accumulator, w, start_x + w->geometry().x(),
                        start_y + w->geometry().y());
}

}  // namespace

// static
WindowManager* WindowManager::g_window_manager = nullptr;

// static
void WindowManager::InitializeWindowManager(
    WmEventObserver* wm_event_observer) {
  g_window_manager = new WindowManager(wm_event_observer);
}

WindowManager* WindowManager::Get() {
  assert(g_window_manager != nullptr);
  return g_window_manager;
}

// TODO: use real dimension
WindowManager::WindowManager(WmEventObserver* wm_event_observer)
    : screen_width_(2560),
      screen_height_(1440),
      mouse_position_(1280.0f, 720.0f),
      last_mouse_position_(1280.0f, 720.0f),
      wm_event_observer_(wm_event_observer) {
  wm_event_observer_->set_wm_primitives(this);
  event::EventHub::Get()->AddEventObserver(this);
}

void WindowManager::Manage(Window* window) {
  TRACE("manage: %p", window);
  // TODO: window management policy
  auto it = std::find(windows_.begin(), windows_.end(), window);
  if (it != windows_.end()) {
    TRACE("shouldn't happen. %p is already managed.", window);
    return;
  }
  windows_.push_back(window);
  window->set_managed(true);
  // We'll skip popup windows for configure.
  if (window->is_popup() || window->is_transient())
    return;
  wm_event_observer_->WindowCreated(window);
}

void WindowManager::RemoveWindow(Window* window) {
  auto* top_level = window->top_level();
  if (top_level == window) {
    // We are dealing with a top level window
    auto iter = std::find(windows_.begin(), windows_.end(), window);
    if (iter != windows_.end()) {
      if (*iter == focused_window_) {
        focused_window_->LoseFocus();
        auto* next_window = NextWindow(focused_window_);
        FocusWindow(next_window);
      }
      wm_event_observer_->WindowDestroying(window);
      windows_.erase(iter);
      wm_event_observer_->WindowDestroyed(window);
      // TODO: compositor needs to be notified of this
    }
  } else {
    if (window == focused_window_) {
      LOG_ERROR << "set focus to parent" << std::endl;
      window->LoseFocus();
      FocusWindow(window->parent());
      wm_event_observer_->WindowDestroyed(window);
    }
    if (window == global_grab_window_)
      global_grab_window_ = nullptr;
  }
}

void WindowManager::AddMouseObserver(MouseObserver* observer) {
  if (std::find(mouse_observers_.begin(), mouse_observers_.end(), observer) ==
      mouse_observers_.end()) {
    mouse_observers_.push_back(observer);
  }
}

void WindowManager::RemoveMouseObserver(MouseObserver* observer) {
  auto iter =
      std::find(mouse_observers_.begin(), mouse_observers_.end(), observer);
  if (iter != mouse_observers_.end())
    mouse_observers_.erase(iter);
}

void WindowManager::AddKeyboardObserver(KeyboardObserver* observer) {
  if (std::find(keyboard_observers_.begin(), keyboard_observers_.end(),
                observer) == keyboard_observers_.end()) {
    keyboard_observers_.push_back(observer);
  }
}

void WindowManager::RemoveKeyboardObserver(KeyboardObserver* observer) {
  auto iter = std::find(keyboard_observers_.begin(), keyboard_observers_.end(),
                        observer);
  if (iter != keyboard_observers_.end())
    keyboard_observers_.erase(iter);
}

void WindowManager::GlobalGrabWindow(Window* window) {
  if (global_grab_window_)
    global_grab_window_->GrabDone();
  global_grab_window_ = window;
}

bool WindowManager::pointer_moved() {
  return last_mouse_position_.manhattan_distance(mouse_position_) >= 1.0;
}

void WindowManager::OnMouseButton(uint32_t button,
                                  bool pressed,
                                  uint32_t modifiers,
                                  event::Leds leds) {
  MouseEventData data;
  data.button = button;
  DispatchMouseEvent(std::make_unique<MouseEvent>(
      FindMouseEventTarget(),
      pressed ? MouseEventType::MouseButtonDown : MouseEventType::MouseButtonUp,
      base::Time::CurrentTimeMilliSeconds(), modifiers, data,
      mouse_position_.x(), mouse_position_.y(), leds));
}

void WindowManager::OnMouseMotion(float dx,
                                  float dy,
                                  uint32_t modifiers,
                                  event::Leds leds) {
  float new_x = mouse_position_.x() + dx;
  float new_y = mouse_position_.y() + dy;
  if (mouse_position_.x() + dx >= screen_width_)
    new_x = screen_width_ - 0.4f;
  if (mouse_position_.x() + dx < 0.0f)
    new_x = 0.4f;
  if (mouse_position_.y() + dy >= screen_height_)
    new_y = screen_height_ - 0.4f;
  if (mouse_position_.y() + dy < 0.0f)
    new_y = 0.4f;
  last_mouse_position_ = mouse_position_;
  mouse_position_ = base::geometry::FloatPoint(new_x, new_y);

  MouseEventData data;
  data.delta[0] = static_cast<int32_t>(new_x - last_mouse_position_.x());
  data.delta[1] = static_cast<int32_t>(new_y - last_mouse_position_.y());
  DispatchMouseEvent(std::make_unique<MouseEvent>(
      FindMouseEventTarget(), MouseEventType::MouseMotion,
      base::Time::CurrentTimeMilliSeconds(), modifiers, data, new_x, new_y,
      leds));
}

void WindowManager::OnMouseScroll(float x_scroll,
                                  float y_scroll,
                                  uint32_t modifiers,
                                  event::Leds locks) {
  MouseEventData data;
  data.scroll[0] = x_scroll;
  data.scroll[1] = y_scroll;
  DispatchMouseEvent(std::make_unique<MouseEvent>(
      FindMouseEventTarget(), MouseEventType::MouseAxis,
      base::Time::CurrentTimeMilliSeconds(), modifiers, data,
      mouse_position_.x(), mouse_position_.y(), locks));
}

void WindowManager::OnKey(uint32_t keycode,
                          uint32_t modifiers,
                          bool key_down,
                          event::Leds locks) {
  auto event = std::make_unique<KeyboardEvent>(
      focused_window(), keycode, locks, base::Time::CurrentTimeMilliSeconds(),
      key_down, modifiers);
  if (wm_event_observer_->OnKey(event.get()))
    return;

  if (focused_window_) {
    for (auto observer : keyboard_observers_)
      observer->OnKey(event.get());
  }
  if (keycode == 0) {
    // TODO: send modifiers event
  }
}

std::vector<std::unique_ptr<Layer>>
WindowManager::WindowsInGlobalCoordinates() {
  std::vector<std::unique_ptr<Layer>> result;
  for (auto* w : windows_)
    CollectGlobalLayers(result, w, w->wm_x(), w->wm_y());
  return result;
}

Window* WindowManager::FindMouseEventTarget() {
  std::vector<std::unique_ptr<Layer>> layers = WindowsInGlobalCoordinates();
  int32_t mouse_x = static_cast<int32_t>(mouse_position_.x());
  int32_t mouse_y = static_cast<int32_t>(mouse_position_.y());

  // TODO: establish popup grab, and send popup done when clicking is outside.
  for (auto it = layers.rbegin(); it != layers.rend(); it++) {
    TRACE("Testing %d %d, window: %p, %d %d %d %d", mouse_x, mouse_y,
          (*it)->window(), (*it)->geometry().x(), (*it)->geometry().y(),
          (*it)->geometry().width(), (*it)->geometry().height());
    if ((*it)->geometry().ContainsPoint(mouse_x, mouse_y))
      return (*it)->window();
  }

  return nullptr;
}

void WindowManager::DispatchMouseEvent(std::unique_ptr<MouseEvent> event) {
  if (wm_event_observer_->OnMouseEvent(event.get()))
    return;

  if (event->window()) {
    if (global_grab_window_ && event->window() != global_grab_window_
        && event->type() == MouseEventType::MouseButtonDown) {
      global_grab_window_->GrabDone();
      global_grab_window_ = nullptr;
    }

    // Transform pointer location to surface local coordinates.
    std::vector<Window*> window_path;
    Window* window = event->window();
    window_path.push_back(window);
    while (window->parent()) {
      window_path.push_back(window->parent());
      window = window->parent();
    }
    uint32_t coord_x = event->x();
    uint32_t coord_y = event->y();
    for (auto it = window_path.rbegin(); it != window_path.rend(); it++) {
      coord_x = coord_x - (*it)->geometry().x();
      coord_y = coord_y - (*it)->geometry().y();
    }
    // TODO: this is dirty.. try a different approach!
    // Finally, window has a transformation
    coord_x -= window_path.back()->wm_x();
    coord_y -= window_path.back()->wm_y();
    event->set_coordinates(coord_x, coord_y);
    LOG_ERROR << " dispatch final coords: " << coord_x << " " << coord_y
              << std::endl;
    for (auto mouse_observer : mouse_observers_)
      mouse_observer->OnMouseEvent(event.get());
  }
}

Window* WindowManager::NextWindow(Window* window) {
  TRACE();
  auto iter = std::find(windows_.begin(), windows_.end(), window);
  if (iter != windows_.end() && iter + 1 != windows_.end())
    return *(iter + 1);
  if (iter == windows_.end() && windows_.size() > 0)
    return windows_.front();
  return nullptr;
}

Window* WindowManager::PreviousWindow(Window* window) {
  TRACE();
  auto iter = std::find(windows_.begin(), windows_.end(), window);
  if (iter != windows_.begin())
    return *(iter - 1);
  if (iter == windows_.begin() && windows_.size() > 0)
    return windows_.back();
  return nullptr;
}

void WindowManager::FocusWindow(Window* window) {
  TRACE("%p, current_focus: %p", window, focused_window_);
  if (window == focused_window_)
    return;

  if (focused_window_)
    focused_window_->LoseFocus();
  focused_window_ = window;
  for (auto* observer : keyboard_observers_)
    observer->OnFocus(window);
  if (window) {
    window->TakeFocus();
    RaiseWindow(window);
    TRACE("top_level: %p", window->top_level());
  }
}

void WindowManager::MoveResizeWindow(Window* window,
                                     base::geometry::Rect resize) {
  // window->SetPosition(resize.x(), resize.y());
  window->WmSetPosition(resize.x(), resize.y());
  window->WmSetSize(resize.width(), resize.height());
}

void WindowManager::RaiseWindow(Window* window) {
  auto it = std::find(windows_.begin(), windows_.end(), window);
  if (it != windows_.end()) {
    windows_.erase(it);
    windows_.push_back(window);
  }
}

}  // namespace wm
}  // namespace naive
<|endoftext|>


<commit_before>// light.cpp
// light structures

// Copyright 2015 Matthew Chandler

// 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.

// TODO: remove virtual dtors as able

#include "components/light.hpp"

#define GLM_FORCE_RADIANS
#include <glm/gtc/matrix_transform.hpp>

Light::Light(const bool enabled, const glm::vec3 & color, const bool casts_shadow):
    enabled(enabled), color(color), casts_shadow(casts_shadow)
{
}

Point_light::Point_light(const bool enabled, const glm::vec3 & color, const bool casts_shadow,
    const glm::vec3 & pos, const float const_atten, const float linear_atten,
    const float quad_atten):
    Light(enabled, color, casts_shadow), pos(pos),
    const_atten(const_atten), linear_atten(linear_atten), quad_atten(quad_atten)
{
}

glm::mat4 Point_light::shadow_view_mat(const Shadow_dir dir)
{
    glm::mat4 view_mat;
    switch(dir)
    {
    case POSITIVE_X:
        view_mat = glm::mat4(
            glm::vec4(0.0f, 0.0f, -1.0f, 0.0f),
            glm::vec4(0.0f, 1.0f, 0.0f, 0.0f),
            glm::vec4(1.0f, 0.0f, 0.0f, 0.0f),
            glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
        break;
    case NEGATIVE_X:
        view_mat = glm::mat4(
            glm::vec4(0.0f, 0.0f, 1.0f, 0.0f),
            glm::vec4(0.0f, 1.0f, 0.0f, 0.0f),
            glm::vec4(-1.0f, 0.0f, 0.0f, 0.0f),
            glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
        break;
    case POSITIVE_Y:
        view_mat = glm::mat4(
            glm::vec4(1.0f, 0.0f, 0.0f, 0.0f),
            glm::vec4(0.0f, 0.0f, -1.0f, 0.0f),
            glm::vec4(0.0f, 1.0f, 0.0f, 0.0f),
            glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
        break;
    case NEGATIVE_Y:
        view_mat = glm::mat4(
            glm::vec4(1.0f, 0.0f, 0.0f, 0.0f),
            glm::vec4(0.0f, 0.0f, 1.0f, 0.0f),
            glm::vec4(0.0f, -1.0f, 0.0f, 0.0f),
            glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
        break;
    case POSITIVE_Z:
        view_mat = glm::mat4(
            glm::vec4(-1.0f, 0.0f, 0.0f, 0.0f),
            glm::vec4(0.0f, 1.0f, 0.0f, 0.0f),
            glm::vec4(0.0f, 0.0f, -1.0f, 0.0f),
            glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
        break;
    case NEGATIVE_Z:
        view_mat = glm::mat4(
            glm::vec4(1.0f, 0.0f, 0.0f, 0.0f),
            glm::vec4(0.0f, 1.0f, 0.0f, 0.0f),
            glm::vec4(0.0f, 0.0f, 1.0f, 0.0f),
            glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
        break;
    }
    return view_mat;
}

glm::mat4 Point_light::shadow_proj_mat()
{
    return glm::perspective((float)(0.5 * M_PI), 1.0f, 0.1f, 100.0f);
}

Spot_light::Spot_light(const bool enabled, const glm::vec3 & color, const bool casts_shadow,
    const glm::vec3 & pos, const glm::vec3 & dir, const float cos_cutoff,
    const float exponent, const float const_atten, const float linear_atten,
    const float quad_atten):
    Light(enabled, color, casts_shadow), pos(pos), dir(dir), cos_cutoff(cos_cutoff),
    exponent(exponent), const_atten(const_atten), linear_atten(linear_atten), quad_atten(quad_atten)
{
}

glm::mat4 Spot_light::shadow_view_mat()
{
    // find an orthogonal vector
    glm::vec3 up = glm::normalize(glm::vec3(dir.y, -dir.x, 0.0f) + glm::vec3(-dir.z, 0.0f, dir.x));

    return glm::lookAt(pos, pos + dir, up);
}

glm::mat4 Spot_light::shadow_proj_mat()
{
    return glm::perspective(2.0f * std::acos(cos_cutoff), 1.0f, 0.1f, 100.0f);
}

Dir_light::Dir_light(const bool enabled, const glm::vec3 & color, const bool casts_shadow,
    const glm::vec3 & dir):
    Light(enabled, color, casts_shadow), dir(dir)
{
}

glm::mat4 Dir_light::shadow_view_mat()
{
    return glm::lookAt(-dir, glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f)); // TODO: should the up vector be orthogonal?
}

glm::mat4 Dir_light::shadow_proj_mat(const float width, const float height, const float depth)
{
    return glm::ortho(-0.5f * width, 0.5f * width, -0.5f * height, 0.5f * height, -0.5f * depth, 0.5f * depth);
}
<commit_msg>add PI define to light<commit_after>// light.cpp
// light structures

// Copyright 2015 Matthew Chandler

// 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.

// TODO: remove virtual dtors as able

#include "components/light.hpp"

#define _USE_MATH_DEFINES
#include <cmath>
#ifndef M_PI
#define M_PI 3.14159265358979323846264338327950288
#endif

#define GLM_FORCE_RADIANS
#include <glm/gtc/matrix_transform.hpp>

Light::Light(const bool enabled, const glm::vec3 & color, const bool casts_shadow):
    enabled(enabled), color(color), casts_shadow(casts_shadow)
{
}

Point_light::Point_light(const bool enabled, const glm::vec3 & color, const bool casts_shadow,
    const glm::vec3 & pos, const float const_atten, const float linear_atten,
    const float quad_atten):
    Light(enabled, color, casts_shadow), pos(pos),
    const_atten(const_atten), linear_atten(linear_atten), quad_atten(quad_atten)
{
}

glm::mat4 Point_light::shadow_view_mat(const Shadow_dir dir)
{
    glm::mat4 view_mat;
    switch(dir)
    {
    case POSITIVE_X:
        view_mat = glm::mat4(
            glm::vec4(0.0f, 0.0f, -1.0f, 0.0f),
            glm::vec4(0.0f, 1.0f, 0.0f, 0.0f),
            glm::vec4(1.0f, 0.0f, 0.0f, 0.0f),
            glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
        break;
    case NEGATIVE_X:
        view_mat = glm::mat4(
            glm::vec4(0.0f, 0.0f, 1.0f, 0.0f),
            glm::vec4(0.0f, 1.0f, 0.0f, 0.0f),
            glm::vec4(-1.0f, 0.0f, 0.0f, 0.0f),
            glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
        break;
    case POSITIVE_Y:
        view_mat = glm::mat4(
            glm::vec4(1.0f, 0.0f, 0.0f, 0.0f),
            glm::vec4(0.0f, 0.0f, -1.0f, 0.0f),
            glm::vec4(0.0f, 1.0f, 0.0f, 0.0f),
            glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
        break;
    case NEGATIVE_Y:
        view_mat = glm::mat4(
            glm::vec4(1.0f, 0.0f, 0.0f, 0.0f),
            glm::vec4(0.0f, 0.0f, 1.0f, 0.0f),
            glm::vec4(0.0f, -1.0f, 0.0f, 0.0f),
            glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
        break;
    case POSITIVE_Z:
        view_mat = glm::mat4(
            glm::vec4(-1.0f, 0.0f, 0.0f, 0.0f),
            glm::vec4(0.0f, 1.0f, 0.0f, 0.0f),
            glm::vec4(0.0f, 0.0f, -1.0f, 0.0f),
            glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
        break;
    case NEGATIVE_Z:
        view_mat = glm::mat4(
            glm::vec4(1.0f, 0.0f, 0.0f, 0.0f),
            glm::vec4(0.0f, 1.0f, 0.0f, 0.0f),
            glm::vec4(0.0f, 0.0f, 1.0f, 0.0f),
            glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
        break;
    }
    return view_mat;
}

glm::mat4 Point_light::shadow_proj_mat()
{
    return glm::perspective((float)(0.5 * M_PI), 1.0f, 0.1f, 100.0f);
}

Spot_light::Spot_light(const bool enabled, const glm::vec3 & color, const bool casts_shadow,
    const glm::vec3 & pos, const glm::vec3 & dir, const float cos_cutoff,
    const float exponent, const float const_atten, const float linear_atten,
    const float quad_atten):
    Light(enabled, color, casts_shadow), pos(pos), dir(dir), cos_cutoff(cos_cutoff),
    exponent(exponent), const_atten(const_atten), linear_atten(linear_atten), quad_atten(quad_atten)
{
}

glm::mat4 Spot_light::shadow_view_mat()
{
    // find an orthogonal vector
    glm::vec3 up = glm::normalize(glm::vec3(dir.y, -dir.x, 0.0f) + glm::vec3(-dir.z, 0.0f, dir.x));

    return glm::lookAt(pos, pos + dir, up);
}

glm::mat4 Spot_light::shadow_proj_mat()
{
    return glm::perspective(2.0f * std::acos(cos_cutoff), 1.0f, 0.1f, 100.0f);
}

Dir_light::Dir_light(const bool enabled, const glm::vec3 & color, const bool casts_shadow,
    const glm::vec3 & dir):
    Light(enabled, color, casts_shadow), dir(dir)
{
}

glm::mat4 Dir_light::shadow_view_mat()
{
    return glm::lookAt(-dir, glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f)); // TODO: should the up vector be orthogonal?
}

glm::mat4 Dir_light::shadow_proj_mat(const float width, const float height, const float depth)
{
    return glm::ortho(-0.5f * width, 0.5f * width, -0.5f * height, 0.5f * height, -0.5f * depth, 0.5f * depth);
}
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007-2016 musikcube team
//
// 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 the author nor the names of other 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.
//
//////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "TransportWindow.h"

#include <cursespp/Screen.h>
#include <cursespp/Colors.h>
#include <cursespp/Message.h>
#include <cursespp/Text.h>

#include <app/util/Duration.h>

#include <core/debug.h>
#include <core/library/LocalLibraryConstants.h>

#include <boost/format.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/chrono.hpp>
#include <boost/lexical_cast.hpp>

#include <algorithm>
#include <memory>

using namespace musik::core;
using namespace musik::core::audio;
using namespace musik::core::library;
using namespace musik::core::db;
using namespace musik::box;
using namespace boost::chrono;
using namespace cursespp;

#define REFRESH_TRANSPORT_READOUT 1001
#define REFRESH_INTERVAL_MS 1000
#define DEFAULT_TIME -1.0f
#define TIME_SLOP 3.0f

#define MIN_WIDTH 20
#define MIN_HEIGHT 2

#define DEBOUNCE_REFRESH(x) \
    this->RemoveMessage(REFRESH_TRANSPORT_READOUT); \
    this->PostMessage(REFRESH_TRANSPORT_READOUT, 0, 0, x);

#define DEBOUNCE_REFRESH_AND_SYNC_TIME() \
    this->lastTime = this->transport.Position(); \
    DEBOUNCE_REFRESH(0)

#define ON(w, a) if (a != -1) { wattron(w, a); }
#define OFF(w, a) if (a != -1) { wattroff(w, a); }

static std::string playingFormat = "playing $title by $artist from $album";

struct Token {
    enum Type { Normal, Placeholder };

    static std::unique_ptr<Token> New(const std::string& value, Type type) {
        return std::unique_ptr<Token>(new Token(value, type));
    }

    Token(const std::string& value, Type type) {
        this->value = value;
        this->type = type;
    }

    std::string value;
    Type type;
};

typedef std::unique_ptr<Token> TokenPtr;
typedef std::vector<TokenPtr> TokenList;

/* tokenizes an input string that has $placeholder values */
void tokenize(const std::string& format, TokenList& tokens) {
    tokens.clear();
    Token::Type type = Token::Normal;
    size_t i = 0;
    size_t start = 0;
    while (i < format.size()) {
        char c = format[i];
        if ((type == Token::Placeholder && c == ' ') ||
            (type == Token::Normal && c == '$')) {
            /* escape $ with $$ */
            if (c == '$' && i < format.size() - 1 && format[i + 1] == '$') {
                i++;
            }
            else {
                if (i > start) {
                    tokens.push_back(Token::New(format.substr(start, i - start), type));
                }
                start = i;
                type = (c == ' ')  ? Token::Normal : Token::Placeholder;
            }
        }
        ++i;
    }

    if (i > 0) {
        tokens.push_back(Token::New(format.substr(start, i - start), type));
    }
}

/* writes the colorized formatted string to the specified window. accounts for
utf8 characters and ellipsizing */
size_t writePlayingFormat(
    WINDOW *w,
    std::string title,
    std::string album,
    std::string artist,
    size_t width)
{
    TokenList tokens;
    tokenize(playingFormat, tokens);

    int64 dim = COLOR_PAIR(CURSESPP_TEXT_DISABLED);
    int64 gb = COLOR_PAIR(CURSESPP_TEXT_ACTIVE);
    size_t remaining = width;

    auto it = tokens.begin();
    while (it != tokens.end() && remaining > 0) {
        Token *token = it->get();

        int64 attr = dim;
        std::string value;

        if (token->type == Token::Placeholder) {
            attr = gb;
            if (token->value == "$title") {
                value = title;
            }
            else if (token->value == "$album") {
                value = album;
            }
            else if (token->value == "$artist") {
                value = artist;
            }
        }

        if (!value.size()) {
            value = token->value;
        }

        size_t len = u8cols(value);
        bool ellipsized = false;

        if (len > remaining) {
            std::string original = value;
            value = text::Ellipsize(value, remaining);
            ellipsized = (value != original);
            len = remaining;
        }

        /* if we're not at the last token, but there's not enough space
        to show the next token, ellipsize now and bail out of the loop */
        if (remaining - len < 3) {
            if (!ellipsized) {
                value = text::Ellipsize(value, remaining - 3);
                len = remaining;
            }
        }

        ON(w, attr);
        wprintw(w, value.c_str());
        OFF(w, attr);

        remaining -= len;
        ++it;
    }

    return (width - remaining);
}

TransportWindow::TransportWindow(musik::box::PlaybackService& playback)
: Window(NULL)
, playback(playback)
, transport(playback.GetTransport())
{
    this->SetFrameVisible(false);
    this->playback.TrackChanged.connect(this, &TransportWindow::OnPlaybackServiceTrackChanged);
    this->playback.ModeChanged.connect(this, &TransportWindow::OnPlaybackModeChanged);
    this->playback.Shuffled.connect(this, &TransportWindow::OnPlaybackShuffled);
    this->transport.VolumeChanged.connect(this, &TransportWindow::OnTransportVolumeChanged);
    this->transport.TimeChanged.connect(this, &TransportWindow::OnTransportTimeChanged);
    this->paused = false;
    this->lastTime = DEFAULT_TIME;
}

TransportWindow::~TransportWindow() {
}

void TransportWindow::Show() {
    Window::Show();
    this->Update();
}

void TransportWindow::ProcessMessage(IMessage &message) {
    int type = message.Type();

    if (type == REFRESH_TRANSPORT_READOUT) {
        this->Update();
        DEBOUNCE_REFRESH(REFRESH_INTERVAL_MS)
    }
}

void TransportWindow::OnPlaybackServiceTrackChanged(size_t index, TrackPtr track) {
    this->currentTrack = track;
    this->lastTime = DEFAULT_TIME;
    DEBOUNCE_REFRESH(0);
}

void TransportWindow::OnPlaybackModeChanged() {
    DEBOUNCE_REFRESH_AND_SYNC_TIME();
}

void TransportWindow::OnTransportVolumeChanged() {
    DEBOUNCE_REFRESH_AND_SYNC_TIME();
}

void TransportWindow::OnTransportTimeChanged(double time) {
    DEBOUNCE_REFRESH_AND_SYNC_TIME();
}

void TransportWindow::OnPlaybackShuffled(bool shuffled) {
    DEBOUNCE_REFRESH_AND_SYNC_TIME();
}

void TransportWindow::Update() {
    this->Clear();

    size_t cx = (size_t) this->GetContentWidth();

    if (cx < MIN_WIDTH || this->GetContentHeight() < MIN_HEIGHT) {
        return;
    }

    WINDOW *c = this->GetContent();
    bool paused = (transport.GetPlaybackState() == ITransport::PlaybackPaused);
    bool stopped = (transport.GetPlaybackState() == ITransport::PlaybackStopped);

    int64 gb = COLOR_PAIR(CURSESPP_TEXT_ACTIVE);
    int64 disabled = COLOR_PAIR(CURSESPP_TEXT_DISABLED);

    /* prepare the "shuffle" label */

    std::string shuffleLabel = " shuffle";
    size_t shuffleLabelLen = u8cols(shuffleLabel);

    /* playing SONG TITLE from ALBUM NAME */

    std::string duration = "0";

    if (stopped) {
        ON(c, disabled);
        wprintw(c, "playback is stopped");
        OFF(c, disabled);
    }
    else {
        std::string title, album, artist;

        if (this->currentTrack) {
            title = this->currentTrack->GetValue(constants::Track::TITLE);
            album = this->currentTrack->GetValue(constants::Track::ALBUM);
            artist = this->currentTrack->GetValue(constants::Track::ARTIST);
            duration = this->currentTrack->GetValue(constants::Track::DURATION);
        }

        title = title.size() ? title : "[song]";
        album = album.size() ? album : "[album]";
        artist = artist.size() ? artist : "[artist]";
        duration = duration.size() ? duration : "0";

        writePlayingFormat(
            c,
            title,
            album,
            artist,
            cx - shuffleLabelLen);
    }

    wmove(c, 0, cx - shuffleLabelLen);
    int64 shuffleAttrs = this->playback.IsShuffled() ? gb : disabled;
    ON(c, shuffleAttrs);
    wprintw(c, shuffleLabel.c_str());
    OFF(c, shuffleAttrs);

    wmove(c, 1, 0); /* move cursor to the second line */

    /* volume slider */

    int volumePercent = (size_t) round(this->transport.Volume() * 100.0f) - 1;
    int thumbOffset = std::min(9, (volumePercent * 10) / 100);

    std::string volume = "vol ";

    for (int i = 0; i < 10; i++) {
        volume += (i == thumbOffset) ? "■" : "─";
    }

    volume += "  ";

    wprintw(c, volume.c_str());

    /* repeat mode setup */

    PlaybackService::RepeatMode mode = this->playback.GetRepeatMode();
    std::string repeatLabel = " ∞ ";
    std::string repeatModeLabel;
    int64 repeatAttrs = -1;
    switch (mode) {
        case PlaybackService::RepeatList:
            repeatModeLabel = "list";
            repeatAttrs = gb;
            break;
        case PlaybackService::RepeatTrack:
            repeatModeLabel = "track";
            repeatAttrs = gb;
            break;
        default:
            repeatModeLabel = "off";
            repeatAttrs = disabled;
            break;
    }

    /* time slider */

    int64 timerAttrs = 0;

    if (paused) { /* blink the track if paused */
        int64 now = duration_cast<seconds>(
            system_clock::now().time_since_epoch()).count();

        if (now % 2 == 0) {
            timerAttrs = COLOR_PAIR(CURSESPP_TEXT_HIDDEN);
        }
    }

    transport.Position();

    /* calculating playback time is inexact because it's based on buffers that
    are sent to the output. here we use a simple smoothing function to hopefully
    mitigate jumping around. basically: draw the time as one second more than the
    last time we displayed, unless they are more than few seconds apart. note this
    only works if REFRESH_INTERVAL_MS is 1000. */
    double smoothedTime = this->lastTime += 1.0f; /* 1000 millis */
    double actualTime = transport.Position();

    if (paused || stopped || fabs(smoothedTime - actualTime) > TIME_SLOP) {
        smoothedTime = actualTime;
    }

    this->lastTime = smoothedTime;
    /* end time smoothing */

    int secondsCurrent = (int) round(smoothedTime);
    int secondsTotal = boost::lexical_cast<int>(duration);

    std::string currentTime = duration::Duration(std::min(secondsCurrent, secondsTotal));
    std::string totalTime = duration::Duration(secondsTotal);

    int timerWidth =
        this->GetContentWidth() -
        u8cols(volume) -
        (u8cols(repeatLabel) + u8cols(repeatModeLabel)) -
        currentTime.size() -
        totalTime.size() -
        2; /* padding */

    thumbOffset = 0;

    if (secondsTotal) {
        int progress = (secondsCurrent * 100) / secondsTotal;
        thumbOffset = std::min(timerWidth - 1, (progress * timerWidth) / 100);
    }

    std::string timerTrack = "";
    for (int i = 0; i < timerWidth; i++) {
        timerTrack += (i == thumbOffset) ? "■" : "─";
    }

    wattron(c, timerAttrs); /* blink if paused */
    wprintw(c, currentTime.c_str());
    wattroff(c, timerAttrs);

    /* using wprintw() here on large displays (1440p+) will exceed the internal
    buffer length of 512 characters, so use boost format. */
    std::string fmt = boost::str(boost::format(
        " %s %s") % timerTrack % totalTime);

    waddstr(c, fmt.c_str());

    /* repeat mode draw */
    wprintw(c, repeatLabel.c_str());
    wattron(c, repeatAttrs);
    wprintw(c, repeatModeLabel.c_str());
    wattroff(c, repeatAttrs);

    this->Repaint();
}
<commit_msg>Fixed a small edge case in TransportWindow title line ellipsizing.<commit_after>//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007-2016 musikcube team
//
// 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 the author nor the names of other 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.
//
//////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "TransportWindow.h"

#include <cursespp/Screen.h>
#include <cursespp/Colors.h>
#include <cursespp/Message.h>
#include <cursespp/Text.h>

#include <app/util/Duration.h>

#include <core/debug.h>
#include <core/library/LocalLibraryConstants.h>

#include <boost/format.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/chrono.hpp>
#include <boost/lexical_cast.hpp>

#include <algorithm>
#include <memory>

using namespace musik::core;
using namespace musik::core::audio;
using namespace musik::core::library;
using namespace musik::core::db;
using namespace musik::box;
using namespace boost::chrono;
using namespace cursespp;

#define REFRESH_TRANSPORT_READOUT 1001
#define REFRESH_INTERVAL_MS 1000
#define DEFAULT_TIME -1.0f
#define TIME_SLOP 3.0f

#define MIN_WIDTH 20
#define MIN_HEIGHT 2

#define DEBOUNCE_REFRESH(x) \
    this->RemoveMessage(REFRESH_TRANSPORT_READOUT); \
    this->PostMessage(REFRESH_TRANSPORT_READOUT, 0, 0, x);

#define DEBOUNCE_REFRESH_AND_SYNC_TIME() \
    this->lastTime = this->transport.Position(); \
    DEBOUNCE_REFRESH(0)

#define ON(w, a) if (a != -1) { wattron(w, a); }
#define OFF(w, a) if (a != -1) { wattroff(w, a); }

static std::string playingFormat = "playing $title by $artist from $album";

struct Token {
    enum Type { Normal, Placeholder };

    static std::unique_ptr<Token> New(const std::string& value, Type type) {
        return std::unique_ptr<Token>(new Token(value, type));
    }

    Token(const std::string& value, Type type) {
        this->value = value;
        this->type = type;
    }

    std::string value;
    Type type;
};

typedef std::unique_ptr<Token> TokenPtr;
typedef std::vector<TokenPtr> TokenList;

/* tokenizes an input string that has $placeholder values */
void tokenize(const std::string& format, TokenList& tokens) {
    tokens.clear();
    Token::Type type = Token::Normal;
    size_t i = 0;
    size_t start = 0;
    while (i < format.size()) {
        char c = format[i];
        if ((type == Token::Placeholder && c == ' ') ||
            (type == Token::Normal && c == '$')) {
            /* escape $ with $$ */
            if (c == '$' && i < format.size() - 1 && format[i + 1] == '$') {
                i++;
            }
            else {
                if (i > start) {
                    tokens.push_back(Token::New(format.substr(start, i - start), type));
                }
                start = i;
                type = (c == ' ')  ? Token::Normal : Token::Placeholder;
            }
        }
        ++i;
    }

    if (i > 0) {
        tokens.push_back(Token::New(format.substr(start, i - start), type));
    }
}

/* writes the colorized formatted string to the specified window. accounts for
utf8 characters and ellipsizing */
size_t writePlayingFormat(
    WINDOW *w,
    std::string title,
    std::string album,
    std::string artist,
    size_t width)
{
    TokenList tokens;
    tokenize(playingFormat, tokens);

    int64 dim = COLOR_PAIR(CURSESPP_TEXT_DISABLED);
    int64 gb = COLOR_PAIR(CURSESPP_TEXT_ACTIVE);
    size_t remaining = width;

    auto it = tokens.begin();
    while (it != tokens.end() && remaining > 0) {
        Token *token = it->get();

        int64 attr = dim;
        std::string value;

        if (token->type == Token::Placeholder) {
            attr = gb;
            if (token->value == "$title") {
                value = title;
            }
            else if (token->value == "$album") {
                value = album;
            }
            else if (token->value == "$artist") {
                value = artist;
            }
        }

        if (!value.size()) {
            value = token->value;
        }

        size_t len = u8cols(value);
        bool ellipsized = false;

        if (len > remaining) {
            std::string original = value;
            value = text::Ellipsize(value, remaining);
            ellipsized = (value != original);
            len = remaining;
        }

        /* if we're not at the last token, but there's not enough space
        to show the next token, ellipsize now and bail out of the loop */
        if (remaining - len < 3 && it + 1 != tokens.end()) {
            if (!ellipsized) {
                value = text::Ellipsize(value, remaining - 3);
                len = remaining;
            }
        }

        ON(w, attr);
        wprintw(w, value.c_str());
        OFF(w, attr);

        remaining -= len;
        ++it;
    }

    return (width - remaining);
}

TransportWindow::TransportWindow(musik::box::PlaybackService& playback)
: Window(NULL)
, playback(playback)
, transport(playback.GetTransport())
{
    this->SetFrameVisible(false);
    this->playback.TrackChanged.connect(this, &TransportWindow::OnPlaybackServiceTrackChanged);
    this->playback.ModeChanged.connect(this, &TransportWindow::OnPlaybackModeChanged);
    this->playback.Shuffled.connect(this, &TransportWindow::OnPlaybackShuffled);
    this->transport.VolumeChanged.connect(this, &TransportWindow::OnTransportVolumeChanged);
    this->transport.TimeChanged.connect(this, &TransportWindow::OnTransportTimeChanged);
    this->paused = false;
    this->lastTime = DEFAULT_TIME;
}

TransportWindow::~TransportWindow() {
}

void TransportWindow::Show() {
    Window::Show();
    this->Update();
}

void TransportWindow::ProcessMessage(IMessage &message) {
    int type = message.Type();

    if (type == REFRESH_TRANSPORT_READOUT) {
        this->Update();
        DEBOUNCE_REFRESH(REFRESH_INTERVAL_MS)
    }
}

void TransportWindow::OnPlaybackServiceTrackChanged(size_t index, TrackPtr track) {
    this->currentTrack = track;
    this->lastTime = DEFAULT_TIME;
    DEBOUNCE_REFRESH(0);
}

void TransportWindow::OnPlaybackModeChanged() {
    DEBOUNCE_REFRESH_AND_SYNC_TIME();
}

void TransportWindow::OnTransportVolumeChanged() {
    DEBOUNCE_REFRESH_AND_SYNC_TIME();
}

void TransportWindow::OnTransportTimeChanged(double time) {
    DEBOUNCE_REFRESH_AND_SYNC_TIME();
}

void TransportWindow::OnPlaybackShuffled(bool shuffled) {
    DEBOUNCE_REFRESH_AND_SYNC_TIME();
}

void TransportWindow::Update() {
    this->Clear();

    size_t cx = (size_t) this->GetContentWidth();

    if (cx < MIN_WIDTH || this->GetContentHeight() < MIN_HEIGHT) {
        return;
    }

    WINDOW *c = this->GetContent();
    bool paused = (transport.GetPlaybackState() == ITransport::PlaybackPaused);
    bool stopped = (transport.GetPlaybackState() == ITransport::PlaybackStopped);

    int64 gb = COLOR_PAIR(CURSESPP_TEXT_ACTIVE);
    int64 disabled = COLOR_PAIR(CURSESPP_TEXT_DISABLED);

    /* prepare the "shuffle" label */

    std::string shuffleLabel = " shuffle";
    size_t shuffleLabelLen = u8cols(shuffleLabel);

    /* playing SONG TITLE from ALBUM NAME */

    std::string duration = "0";

    if (stopped) {
        ON(c, disabled);
        wprintw(c, "playback is stopped");
        OFF(c, disabled);
    }
    else {
        std::string title, album, artist;

        if (this->currentTrack) {
            title = this->currentTrack->GetValue(constants::Track::TITLE);
            album = this->currentTrack->GetValue(constants::Track::ALBUM);
            artist = this->currentTrack->GetValue(constants::Track::ARTIST);
            duration = this->currentTrack->GetValue(constants::Track::DURATION);
        }

        title = title.size() ? title : "[song]";
        album = album.size() ? album : "[album]";
        artist = artist.size() ? artist : "[artist]";
        duration = duration.size() ? duration : "0";

        writePlayingFormat(
            c,
            title,
            album,
            artist,
            cx - shuffleLabelLen);
    }

    wmove(c, 0, cx - shuffleLabelLen);
    int64 shuffleAttrs = this->playback.IsShuffled() ? gb : disabled;
    ON(c, shuffleAttrs);
    wprintw(c, shuffleLabel.c_str());
    OFF(c, shuffleAttrs);

    wmove(c, 1, 0); /* move cursor to the second line */

    /* volume slider */

    int volumePercent = (size_t) round(this->transport.Volume() * 100.0f) - 1;
    int thumbOffset = std::min(9, (volumePercent * 10) / 100);

    std::string volume = "vol ";

    for (int i = 0; i < 10; i++) {
        volume += (i == thumbOffset) ? "■" : "─";
    }

    volume += "  ";

    wprintw(c, volume.c_str());

    /* repeat mode setup */

    PlaybackService::RepeatMode mode = this->playback.GetRepeatMode();
    std::string repeatLabel = " ∞ ";
    std::string repeatModeLabel;
    int64 repeatAttrs = -1;
    switch (mode) {
        case PlaybackService::RepeatList:
            repeatModeLabel = "list";
            repeatAttrs = gb;
            break;
        case PlaybackService::RepeatTrack:
            repeatModeLabel = "track";
            repeatAttrs = gb;
            break;
        default:
            repeatModeLabel = "off";
            repeatAttrs = disabled;
            break;
    }

    /* time slider */

    int64 timerAttrs = 0;

    if (paused) { /* blink the track if paused */
        int64 now = duration_cast<seconds>(
            system_clock::now().time_since_epoch()).count();

        if (now % 2 == 0) {
            timerAttrs = COLOR_PAIR(CURSESPP_TEXT_HIDDEN);
        }
    }

    transport.Position();

    /* calculating playback time is inexact because it's based on buffers that
    are sent to the output. here we use a simple smoothing function to hopefully
    mitigate jumping around. basically: draw the time as one second more than the
    last time we displayed, unless they are more than few seconds apart. note this
    only works if REFRESH_INTERVAL_MS is 1000. */
    double smoothedTime = this->lastTime += 1.0f; /* 1000 millis */
    double actualTime = transport.Position();

    if (paused || stopped || fabs(smoothedTime - actualTime) > TIME_SLOP) {
        smoothedTime = actualTime;
    }

    this->lastTime = smoothedTime;
    /* end time smoothing */

    int secondsCurrent = (int) round(smoothedTime);
    int secondsTotal = boost::lexical_cast<int>(duration);

    std::string currentTime = duration::Duration(std::min(secondsCurrent, secondsTotal));
    std::string totalTime = duration::Duration(secondsTotal);

    int timerWidth =
        this->GetContentWidth() -
        u8cols(volume) -
        (u8cols(repeatLabel) + u8cols(repeatModeLabel)) -
        currentTime.size() -
        totalTime.size() -
        2; /* padding */

    thumbOffset = 0;

    if (secondsTotal) {
        int progress = (secondsCurrent * 100) / secondsTotal;
        thumbOffset = std::min(timerWidth - 1, (progress * timerWidth) / 100);
    }

    std::string timerTrack = "";
    for (int i = 0; i < timerWidth; i++) {
        timerTrack += (i == thumbOffset) ? "■" : "─";
    }

    wattron(c, timerAttrs); /* blink if paused */
    wprintw(c, currentTime.c_str());
    wattroff(c, timerAttrs);

    /* using wprintw() here on large displays (1440p+) will exceed the internal
    buffer length of 512 characters, so use boost format. */
    std::string fmt = boost::str(boost::format(
        " %s %s") % timerTrack % totalTime);

    waddstr(c, fmt.c_str());

    /* repeat mode draw */
    wprintw(c, repeatLabel.c_str());
    wattron(c, repeatAttrs);
    wprintw(c, repeatModeLabel.c_str());
    wattroff(c, repeatAttrs);

    this->Repaint();
}
<|endoftext|>


<commit_before>// Copyright Jim Bosch 2010-2012.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)
#ifndef HALIDE_NUMPY_INTERNAL_HPP_INCLUDED
#define HALIDE_NUMPY_INTERNAL_HPP_INCLUDED

/**
 *  @file numpy/internal.hpp
 *  @brief Internal header file to include the Numpy C-API headers.
 *
 *  This should only be included by source files in the boost.numpy library itself.
 */

#include <boost/python.hpp>
#ifdef HALIDE_NUMPY_INTERNAL
#define NO_IMPORT_ARRAY
#define NO_IMPORT_UFUNC
#else
#ifndef HALIDE_NUMPY_INTERNAL_MAIN
ERROR_internal_hpp_is_for_internal_use_only
#endif
#endif
#define PY_ARRAY_UNIQUE_SYMBOL HALIDE_NUMPY_ARRAY_API
#define PY_UFUNC_UNIQUE_SYMBOL HALIDE_UFUNC_ARRAY_API
#include "numpy.hpp"
#include <numpy/arrayobject.h>
#include <numpy/ufuncobject.h>

#define NUMPY_OBJECT_MANAGER_TRAITS_IMPL(pytype, manager) \
    PyTypeObject const *object_manager_traits<manager>::get_pytype() { return &pytype; }

#endif  // !HALIDE_NUMPY_INTERNAL_HPP_INCLUDED
<commit_msg>Dont prevent .h files from compiling standalone<commit_after>// Copyright Jim Bosch 2010-2012.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)
#ifndef HALIDE_NUMPY_INTERNAL_HPP_INCLUDED
#define HALIDE_NUMPY_INTERNAL_HPP_INCLUDED

/**
 *  @file numpy/internal.hpp
 *  @brief Internal header file to include the Numpy C-API headers.
 *
 *  This should only be included by source files in the boost.numpy library itself.
 */

#include <boost/python.hpp>
#ifdef HALIDE_NUMPY_INTERNAL
#define NO_IMPORT_ARRAY
#define NO_IMPORT_UFUNC
#endif
#define PY_ARRAY_UNIQUE_SYMBOL HALIDE_NUMPY_ARRAY_API
#define PY_UFUNC_UNIQUE_SYMBOL HALIDE_UFUNC_ARRAY_API
#include "numpy.hpp"
#include <numpy/arrayobject.h>
#include <numpy/ufuncobject.h>

#define NUMPY_OBJECT_MANAGER_TRAITS_IMPL(pytype, manager) \
    PyTypeObject const *object_manager_traits<manager>::get_pytype() { return &pytype; }

#endif  // !HALIDE_NUMPY_INTERNAL_HPP_INCLUDED
<|endoftext|>


<commit_before>class Solution {
public:
    bool isHappy(int n) {
        if (n <= 0) return false;
        if (n == 1) return true;
        unordered_set<int> s;
        int target = n;
        do {
            int tmp = target;
            target = 0;
            while (tmp != 0) {
                target += (tmp % 10) * (tmp % 10);
                tmp /= 10;
            }
            if (s.find(target) != s.end()) return false;
            s.insert(target);
        } while(target != 1);
        return true;
    }
};
<commit_msg>Create code.cpp<commit_after>class Solution {
public:
    bool isHappy(int n) {
        unordered_set<int> s;
        while (s.find(n) == s.end()) {
            s.insert(n);
            int tmpn = n;
            n = 0;
            while (tmpn) {
                int tmp = tmpn % 10;
                tmpn /= 10;
                n += tmp * tmp;
            }
            if (n == 1) return true;
        }
        return false;
    }
};
<|endoftext|>


<commit_before>#include "gmock/gmock.h"

#include <sstream>

#include "Instruction.hpp"

class LedController
{
public:
  explicit LedController(std::ostream &stream) :
    out{stream}
  {
  }

  void runProgram(const Instructions &instructions)
  {
    for (const auto &instruction : instructions)
    {
      runInstruction(instruction);
    }
  }

private:
  std::ostream &out;

  void runInstruction(const Instruction & instruction)
  {
    if (instruction.type == InstructionType::OutA)
    {
      out << "........\n";
    }
  }

};

static constexpr Instruction createInstructionWithZeroValue(InstructionType type)
{
  return{type, 0};
}

using namespace ::testing;

class LedControllerTest : public Test
{
public:
  std::stringstream stream;
  LedController controller{stream};
};

TEST_F(LedControllerTest, OutInstructionShouldPrintLedState)
{
  controller.runProgram(Instructions{createInstructionWithZeroValue(InstructionType::OutA)});

  EXPECT_THAT(stream.str(), Eq("........\n"));
}

TEST_F(LedControllerTest, LdInstructionShouldNotPrintLedState)
{
  controller.runProgram(Instructions{createInstructionWithZeroValue(InstructionType::LdA)});

  EXPECT_THAT(stream.str(), Eq(""));
}

TEST_F(LedControllerTest, ShouldAcceptNoInstructions)
{
  controller.runProgram(Instructions{});

  EXPECT_THAT(stream.str(), Eq(""));
}<commit_msg>LedController can change led state by Ld<commit_after>#include "gmock/gmock.h"

#include <sstream>

#include "Instruction.hpp"

class LedController
{
public:
  explicit LedController(std::ostream &stream) :
    out{stream}
  {
  }

  void runProgram(const Instructions &instructions)
  {
    for (const auto &instruction : instructions)
    {
      runInstruction(instruction);
    }
  }

private:
  std::ostream &out;

  void runInstruction(const Instruction & instruction)
  {
    switch (instruction.type)
    {
      case InstructionType::OutA:
        out << ledState;
        break;
      case InstructionType::LdA:
        ledState = "********\n";
        break;
    }
  }

  std::string ledState{"........\n"};

};

static constexpr Instruction createInstructionWithZeroValue(InstructionType type)
{
  return{type, 0};
}

using namespace ::testing;

class LedControllerTest : public Test
{
public:
  std::stringstream stream;
  LedController controller{stream};
};

TEST_F(LedControllerTest, OutInstructionShouldPrintLedState)
{
  controller.runProgram(Instructions{createInstructionWithZeroValue(InstructionType::OutA)});

  EXPECT_THAT(stream.str(), Eq("........\n"));
}

TEST_F(LedControllerTest, LdInstructionShouldNotPrintLedState)
{
  controller.runProgram(Instructions{createInstructionWithZeroValue(InstructionType::LdA)});

  EXPECT_THAT(stream.str(), Eq(""));
}

TEST_F(LedControllerTest, ShouldAcceptNoInstructions)
{
  controller.runProgram(Instructions{});

  EXPECT_THAT(stream.str(), Eq(""));
}

TEST_F(LedControllerTest, OutInstructionShouldPrintLedStateAfterChangeByLd)
{
  controller.runProgram(Instructions{{InstructionType::LdA, 255}, createInstructionWithZeroValue(InstructionType::OutA)});

  EXPECT_THAT(stream.str(), Eq("********\n"));
}<|endoftext|>


<commit_before>#ifndef PORTABILITY_HPP
#define PORTABILITY_HPP
#ifdef MSVC && DLL_LINK
#define DllExport __declspec(dllexport)
#else
#define DllExport
#endif
#endif<commit_msg>Added Portability.hpp.  To access C++ symbols from DLL on Windows they need to be explicitly exported.  The most portable way to export a C++ class is to prefix it with __declspec(dllexport).  This header helps to keep the code clean and portable.<commit_after>#ifndef PORTABILITY_HPP
#define PORTABILITY_HPP

#if defined(MSVC) && defined(DLL_LINK)
#define DllExport __declspec(dllexport)
#else
#define DllExport
#endif

#endif
<|endoftext|>


<commit_before>#include <iostream>
#include <string>

#include "lexer.hpp"

namespace dcpu {

  const auto Lexer::kAdvancedOpcodeRegex = std::regex(
      "(jsr|int|iag|ias|rfi|iaq|hwn|hwq|hwi)", std::regex_constants::icase);
  const auto Lexer::kBasicOpcodeRegex = std::regex(
      "(set|add|sub|mul|mli|div|dvi|mod|mdi|and|bor|xor|shr|asr"
          "|shl|ifb|ifc|ife|ifn|ifg|ifa|ifl|ifu|adx|sbx|sti|std)", std::regex_constants::icase);
  const auto Lexer::kBinaryRegex = std::regex("0b([01]{1,16})");
  const auto Lexer::kColonRegex = std::regex(":");
  const auto Lexer::kCommaRegex = std::regex(",");
  const auto Lexer::kCommentRegex = std::regex("#\\s*(.*)");
  const auto Lexer::kDataRegex = std::regex("\\.data", std::regex_constants::icase);
  const auto Lexer::kDecimalRegex = std::regex("([0-9]+)");
  const auto Lexer::kHexadecimalRegex = std::regex("0x([0-9a-fA-F]{1,4})");
  const auto Lexer::kIdentifierRegex = std::regex("(\\w+)");
  const auto Lexer::kLeftBracketRegex = std::regex("\\[");
  const auto Lexer::kMinusRegex = std::regex("-");
  const auto Lexer::kNullptrRegex = std::regex("nullptr", std::regex_constants::icase);
  const auto Lexer::kPeekRegex = std::regex("peek", std::regex_constants::icase);
  const auto Lexer::kPickRegex = std::regex("pick", std::regex_constants::icase);
  const auto Lexer::kPlusRegex = std::regex("\\+");
  const auto Lexer::kPopRegex = std::regex("pop", std::regex_constants::icase);
  const auto Lexer::kPushRegex = std::regex("push", std::regex_constants::icase);
  const auto Lexer::kRightBracketRegex = std::regex("\\]");
  const auto Lexer::kSemicolonRegex = std::regex(";");
  const auto Lexer::kStringRegex = std::regex("\"(.*)\"");
  const auto Lexer::kWhitespaceRegex = std::regex("(\\s+)");

  std::ostream &operator <<(std::ostream &out, Token::Type type) {
    switch (type) {
      case Token::Type::kAdvancedOpcode: return out << "kAdvancedOpcode";
      case Token::Type::kBasicOpcode: return out << "kBasicOpcode";
      case Token::Type::kBinary: return out << "kBinary";
      case Token::Type::kColon: return out << "kColon";
      case Token::Type::kComma: return out << "kComma";
      case Token::Type::kComment: return out << "kComment";
      case Token::Type::kData: return out << "kData";
      case Token::Type::kDecimal: return out << "kDecimal";
      case Token::Type::kHexadecimal: return out << "kHexadecimal";
      case Token::Type::kIdentifier: return out << "kIdentifier";
      case Token::Type::kInvalid: return out << "kInvalid";
      case Token::Type::kLeftBracket: return out << "kLeftBracket";
      case Token::Type::kMinus: return out << "kMinus";
      case Token::Type::kNullptr: return out << "kNullptr";
      case Token::Type::kPeek: return out << "kPeek";
      case Token::Type::kPick: return out << "kPick";
      case Token::Type::kPlus: return out << "kPlus";
      case Token::Type::kPop: return out << "kPop";
      case Token::Type::kPush: return out << "kPush";
      case Token::Type::kRightBracket: return out << "kRightBracket";
      case Token::Type::kSemicolon: return out << "kSemicolon";
      case Token::Type::kString: return out << "kString";
      case Token::Type::kWhitespace: return out << "kWhitespace";
      default: return out << "?";
    }
  }

  std::ostream &operator <<(std::ostream &out, Token token) {
    return out << "{" << std::endl
    << "  .type = " << token.type << std::endl
    << "  .value = \"" << token.value << "\"" << std::endl
    << "}";
  }

  Lexer::Lexer(const std::string &input) : input(input), position(input.begin()) {}

  Token Lexer::EatToken() {
    auto new_position = std::string::const_iterator();
    auto result = SeeToken(&new_position);
    position = new_position;
    return result;
  }

  Token Lexer::SeeToken(std::string::const_iterator *new_position) {
    using Type = Token::Type;
    auto match = std::smatch();
    if (Matches(kAdvancedOpcodeRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kAdvancedOpcode, match[1].str()};
    } else if (Matches(kBasicOpcodeRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kBasicOpcode, match[1].str()};
    } else if (Matches(kBinaryRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kBinary, match[1].str()};
    } else if (Matches(kColonRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kColon, match.str()};
    } else if (Matches(kCommaRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kComma, match.str()};
    } else if (Matches(kCommentRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kComment, match[1].str()};
    } else if (Matches(kDataRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kData, match.str()};
    } else if (Matches(kHexadecimalRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kHexadecimal, match[1].str()};
    } else if (Matches(kDecimalRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kDecimal, match[1].str()};
    } else if (Matches(kLeftBracketRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kLeftBracket, match.str()};
    } else if (Matches(kMinusRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kMinus, match.str()};
    } else if (Matches(kNullptrRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kNullptr, match.str()};
    } else if (Matches(kPeekRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kPeek, match.str()};
    } else if (Matches(kPickRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kPick, match.str()};
    } else if (Matches(kPlusRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kPlus, match.str()};
    } else if (Matches(kPopRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kPop, match.str()};
    } else if (Matches(kPushRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kPush, match.str()};
    } else if (Matches(kRightBracketRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kRightBracket, match.str()};
    } else if (Matches(kSemicolonRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kSemicolon, match.str()};
    } else if (Matches(kStringRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kString, match[1].str()};
    } else if (Matches(kIdentifierRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kIdentifier, match[1].str()};
    } else if (Matches(kWhitespaceRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kWhitespace, match[1].str()};
    } else {
      return Token{Type::kInvalid};
    }
  }

  void Lexer::MaybeAdvance(const std::smatch &match, std::string::const_iterator *new_position) {
    if (new_position) {
      *new_position = match.suffix().first;
    }
  }

  bool Lexer::Matches(const std::regex &regex, std::smatch *match) {
    return std::regex_search(position, input.end(), *match, regex) && !match->prefix().length();
  }

}  // namespace dcpu
<commit_msg>Match protobuf text format. Indent for code style.<commit_after>#include <iostream>
#include <string>

#include "lexer.hpp"

namespace dcpu {

  const auto Lexer::kAdvancedOpcodeRegex = std::regex(
      "(jsr|int|iag|ias|rfi|iaq|hwn|hwq|hwi)", std::regex_constants::icase);
  const auto Lexer::kBasicOpcodeRegex = std::regex(
      "(set|add|sub|mul|mli|div|dvi|mod|mdi|and|bor|xor|shr|asr"
          "|shl|ifb|ifc|ife|ifn|ifg|ifa|ifl|ifu|adx|sbx|sti|std)", std::regex_constants::icase);
  const auto Lexer::kBinaryRegex = std::regex("0b([01]{1,16})");
  const auto Lexer::kColonRegex = std::regex(":");
  const auto Lexer::kCommaRegex = std::regex(",");
  const auto Lexer::kCommentRegex = std::regex("#\\s*(.*)");
  const auto Lexer::kDataRegex = std::regex("\\.data", std::regex_constants::icase);
  const auto Lexer::kDecimalRegex = std::regex("([0-9]+)");
  const auto Lexer::kHexadecimalRegex = std::regex("0x([0-9a-fA-F]{1,4})");
  const auto Lexer::kIdentifierRegex = std::regex("(\\w+)");
  const auto Lexer::kLeftBracketRegex = std::regex("\\[");
  const auto Lexer::kMinusRegex = std::regex("-");
  const auto Lexer::kNullptrRegex = std::regex("nullptr", std::regex_constants::icase);
  const auto Lexer::kPeekRegex = std::regex("peek", std::regex_constants::icase);
  const auto Lexer::kPickRegex = std::regex("pick", std::regex_constants::icase);
  const auto Lexer::kPlusRegex = std::regex("\\+");
  const auto Lexer::kPopRegex = std::regex("pop", std::regex_constants::icase);
  const auto Lexer::kPushRegex = std::regex("push", std::regex_constants::icase);
  const auto Lexer::kRightBracketRegex = std::regex("\\]");
  const auto Lexer::kSemicolonRegex = std::regex(";");
  const auto Lexer::kStringRegex = std::regex("\"(.*)\"");
  const auto Lexer::kWhitespaceRegex = std::regex("(\\s+)");

  std::ostream &operator <<(std::ostream &out, Token::Type type) {
    switch (type) {
      case Token::Type::kAdvancedOpcode: return out << "kAdvancedOpcode";
      case Token::Type::kBasicOpcode: return out << "kBasicOpcode";
      case Token::Type::kBinary: return out << "kBinary";
      case Token::Type::kColon: return out << "kColon";
      case Token::Type::kComma: return out << "kComma";
      case Token::Type::kComment: return out << "kComment";
      case Token::Type::kData: return out << "kData";
      case Token::Type::kDecimal: return out << "kDecimal";
      case Token::Type::kHexadecimal: return out << "kHexadecimal";
      case Token::Type::kIdentifier: return out << "kIdentifier";
      case Token::Type::kInvalid: return out << "kInvalid";
      case Token::Type::kLeftBracket: return out << "kLeftBracket";
      case Token::Type::kMinus: return out << "kMinus";
      case Token::Type::kNullptr: return out << "kNullptr";
      case Token::Type::kPeek: return out << "kPeek";
      case Token::Type::kPick: return out << "kPick";
      case Token::Type::kPlus: return out << "kPlus";
      case Token::Type::kPop: return out << "kPop";
      case Token::Type::kPush: return out << "kPush";
      case Token::Type::kRightBracket: return out << "kRightBracket";
      case Token::Type::kSemicolon: return out << "kSemicolon";
      case Token::Type::kString: return out << "kString";
      case Token::Type::kWhitespace: return out << "kWhitespace";
      default: return out << "?";
    }
  }

  std::ostream &operator <<(std::ostream &out, Token token) {
    return out << "Token {" << std::endl
        << "  type: " << token.type << std::endl
        << "  value: \"" << token.value << "\"" << std::endl
        << "}";
  }

  Lexer::Lexer(const std::string &input) : input(input), position(input.begin()) {}

  Token Lexer::EatToken() {
    auto new_position = std::string::const_iterator();
    auto result = SeeToken(&new_position);
    position = new_position;
    return result;
  }

  Token Lexer::SeeToken(std::string::const_iterator *new_position) {
    using Type = Token::Type;
    auto match = std::smatch();
    if (Matches(kAdvancedOpcodeRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kAdvancedOpcode, match[1].str()};
    } else if (Matches(kBasicOpcodeRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kBasicOpcode, match[1].str()};
    } else if (Matches(kBinaryRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kBinary, match[1].str()};
    } else if (Matches(kColonRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kColon, match.str()};
    } else if (Matches(kCommaRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kComma, match.str()};
    } else if (Matches(kCommentRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kComment, match[1].str()};
    } else if (Matches(kDataRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kData, match.str()};
    } else if (Matches(kHexadecimalRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kHexadecimal, match[1].str()};
    } else if (Matches(kDecimalRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kDecimal, match[1].str()};
    } else if (Matches(kLeftBracketRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kLeftBracket, match.str()};
    } else if (Matches(kMinusRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kMinus, match.str()};
    } else if (Matches(kNullptrRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kNullptr, match.str()};
    } else if (Matches(kPeekRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kPeek, match.str()};
    } else if (Matches(kPickRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kPick, match.str()};
    } else if (Matches(kPlusRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kPlus, match.str()};
    } else if (Matches(kPopRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kPop, match.str()};
    } else if (Matches(kPushRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kPush, match.str()};
    } else if (Matches(kRightBracketRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kRightBracket, match.str()};
    } else if (Matches(kSemicolonRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kSemicolon, match.str()};
    } else if (Matches(kStringRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kString, match[1].str()};
    } else if (Matches(kIdentifierRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kIdentifier, match[1].str()};
    } else if (Matches(kWhitespaceRegex, &match)) {
      MaybeAdvance(match, new_position);
      return Token{Type::kWhitespace, match[1].str()};
    } else {
      return Token{Type::kInvalid};
    }
  }

  void Lexer::MaybeAdvance(const std::smatch &match, std::string::const_iterator *new_position) {
    if (new_position) {
      *new_position = match.suffix().first;
    }
  }

  bool Lexer::Matches(const std::regex &regex, std::smatch *match) {
    return std::regex_search(position, input.end(), *match, regex) && !match->prefix().length();
  }

}  // namespace dcpu
<|endoftext|>


<commit_before>//
//  HUDErrorRenderer.hpp
//  G3MiOSSDK
//
//  Created by Diego Gomez Deck on 9/28/13.
//
//

#ifndef __G3MiOSSDK__HUDErrorRenderer__
#define __G3MiOSSDK__HUDErrorRenderer__

#include "ErrorRenderer.hpp"
#include "HUDImageRenderer.hpp"
#include "ImageFactory.hpp"

class HUDErrorRenderer_ImageFactory : public ImageFactory {
public:
  void create(const G3MRenderContext* rc,
              int width,
              int height,
              IImageListener* listener,
              bool deleteListener);
};

class HUDErrorRenderer : public HUDImageRenderer, ErrorRenderer {
public:
  HUDErrorRenderer() :
  HUDImageRenderer(new HUDErrorRenderer_ImageFactory())
  {

  }

  void initialize(const G3MContext* context);

  void render(const G3MRenderContext* rc,
              GLState* glState);

  bool onTouchEvent(const G3MEventContext* ec,
                    const TouchEvent* touchEvent);

  void onResizeViewportEvent(const G3MEventContext* ec,
                             int width, int height);

  void start(const G3MRenderContext* rc);

  void stop(const G3MRenderContext* rc);

  void onResume(const G3MContext* context);

  void onPause(const G3MContext* context);

  void onDestroy(const G3MContext* context);

};

#endif
<commit_msg>new ErrorRenderer mechanism - NOT YET USABLE<commit_after>//
//  HUDErrorRenderer.hpp
//  G3MiOSSDK
//
//  Created by Diego Gomez Deck on 9/28/13.
//
//

#ifndef __G3MiOSSDK__HUDErrorRenderer__
#define __G3MiOSSDK__HUDErrorRenderer__

#include "ErrorRenderer.hpp"
#include "HUDImageRenderer.hpp"
#include "ImageFactory.hpp"

class HUDErrorRenderer_ImageFactory : public ImageFactory {
public:
  void create(const G3MRenderContext* rc,
              int width,
              int height,
              IImageListener* listener,
              bool deleteListener);
};

class HUDErrorRenderer : public HUDImageRenderer, public ErrorRenderer {
public:
  HUDErrorRenderer() :
  HUDImageRenderer(new HUDErrorRenderer_ImageFactory())
  {

  }

  void initialize(const G3MContext* context);

  void render(const G3MRenderContext* rc,
              GLState* glState);

  bool onTouchEvent(const G3MEventContext* ec,
                    const TouchEvent* touchEvent);

  void onResizeViewportEvent(const G3MEventContext* ec,
                             int width, int height);

  void start(const G3MRenderContext* rc);

  void stop(const G3MRenderContext* rc);

  void onResume(const G3MContext* context);

  void onPause(const G3MContext* context);

  void onDestroy(const G3MContext* context);

};

#endif
<|endoftext|>


<commit_before>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

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

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

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

#include <fcntl.h>
#ifndef TFLITE_MCU
#include <sys/mman.h>
#endif
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <cassert>
#include <cstdarg>
#include <cstdint>
#include <cstring>
#include <utility>

#include "tensorflow/contrib/lite/allocation.h"
#include "tensorflow/contrib/lite/context.h"
#include "tensorflow/contrib/lite/error_reporter.h"
#ifndef TFLITE_MCU
#include "tensorflow/contrib/lite/nnapi_delegate.h"
#endif

namespace tflite {

#ifndef TFLITE_MCU
MMAPAllocation::MMAPAllocation(const char* filename,
                               ErrorReporter* error_reporter)
    : Allocation(error_reporter), mmapped_buffer_(MAP_FAILED) {
  mmap_fd_ = open(filename, O_RDONLY);
  if (mmap_fd_ == -1) {
    error_reporter_->Report("Could not open '%s'.", filename);
    return;
  }
  struct stat sb;
  fstat(mmap_fd_, &sb);
  buffer_size_bytes_ = sb.st_size;
  mmapped_buffer_ =
      mmap(nullptr, buffer_size_bytes_, PROT_READ, MAP_SHARED, mmap_fd_, 0);
  if (mmapped_buffer_ == MAP_FAILED) {
    error_reporter_->Report("Mmap of '%s' failed.", filename);
    return;
  }
}

MMAPAllocation::~MMAPAllocation() {
  if (valid()) {
    munmap(const_cast<void*>(mmapped_buffer_), buffer_size_bytes_);
  }
  if (mmap_fd_ != -1) close(mmap_fd_);
}

const void* MMAPAllocation::base() const { return mmapped_buffer_; }

size_t MMAPAllocation::bytes() const { return buffer_size_bytes_; }

bool MMAPAllocation::valid() const { return mmapped_buffer_ != MAP_FAILED; }

FileCopyAllocation::FileCopyAllocation(const char* filename,
                                       ErrorReporter* error_reporter)
    : Allocation(error_reporter) {
  // Obtain the file size, using an alternative method that is does not
  // require fstat for more compatibility.
  std::unique_ptr<FILE, decltype(&fclose)> file(fopen(filename, "rb"), fclose);
  if (!file) {
    error_reporter_->Report("Could not open '%s'.", filename);
    return;
  }
  // TODO(ahentz): Why did you think using fseek here was better for finding
  // the size?
  struct stat sb;
  if (fstat(fileno(file.get()), &sb) != 0) {
    error_reporter_->Report("Failed to get file size of '%s'.", filename);
    return;
  }
  buffer_size_bytes_ = sb.st_size;
  std::unique_ptr<char[]> buffer(new char[buffer_size_bytes_]);
  if (!buffer) {
    error_reporter_->Report("Malloc of buffer to hold copy of '%s' failed.",
                            filename);
    return;
  }
  size_t bytes_read =
      fread(buffer.get(), sizeof(char), buffer_size_bytes_, file.get());
  if (bytes_read != buffer_size_bytes_) {
    error_reporter_->Report("Read of '%s' failed (too few bytes read).",
                            filename);
    return;
  }
  // Versions of GCC before 6.2.0 don't support std::move from non-const char[] to
  // const char[] unique_ptrs.
  copied_buffer_.reset(const_cast<char const *>(buffer.release()));
}

FileCopyAllocation::~FileCopyAllocation() {}

const void* FileCopyAllocation::base() const { return copied_buffer_.get(); }

size_t FileCopyAllocation::bytes() const { return buffer_size_bytes_; }

bool FileCopyAllocation::valid() const { return copied_buffer_ != nullptr; }

MemoryAllocation::MemoryAllocation(const void* ptr, size_t num_bytes,
                                   ErrorReporter* error_reporter)
    : Allocation(error_reporter) {
  buffer_ = ptr;
  buffer_size_bytes_ = num_bytes;
}
#endif

MemoryAllocation::~MemoryAllocation() {}

const void* MemoryAllocation::base() const { return buffer_; }

size_t MemoryAllocation::bytes() const { return buffer_size_bytes_; }

bool MemoryAllocation::valid() const { return buffer_ != nullptr; }

}  // namespace tflite
<commit_msg>Update allocation.cc<commit_after>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

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

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

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

#include <fcntl.h>
#ifndef TFLITE_MCU
#include <sys/mman.h>
#endif
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <cassert>
#include <cstdarg>
#include <cstdint>
#include <cstring>
#include <utility>

#include "tensorflow/contrib/lite/allocation.h"
#include "tensorflow/contrib/lite/context.h"
#include "tensorflow/contrib/lite/error_reporter.h"
#ifndef TFLITE_MCU
#include "tensorflow/contrib/lite/nnapi_delegate.h"
#endif

namespace tflite {

#ifndef TFLITE_MCU
MMAPAllocation::MMAPAllocation(const char* filename,
                               ErrorReporter* error_reporter)
    : Allocation(error_reporter), mmapped_buffer_(MAP_FAILED) {
  mmap_fd_ = open(filename, O_RDONLY);
  if (mmap_fd_ == -1) {
    error_reporter_->Report("Could not open '%s'.", filename);
    return;
  }
  struct stat sb;
  fstat(mmap_fd_, &sb);
  buffer_size_bytes_ = sb.st_size;
  mmapped_buffer_ =
      mmap(nullptr, buffer_size_bytes_, PROT_READ, MAP_SHARED, mmap_fd_, 0);
  if (mmapped_buffer_ == MAP_FAILED) {
    error_reporter_->Report("Mmap of '%s' failed.", filename);
    return;
  }
}

MMAPAllocation::~MMAPAllocation() {
  if (valid()) {
    munmap(const_cast<void*>(mmapped_buffer_), buffer_size_bytes_);
  }
  if (mmap_fd_ != -1) close(mmap_fd_);
}

const void* MMAPAllocation::base() const { return mmapped_buffer_; }

size_t MMAPAllocation::bytes() const { return buffer_size_bytes_; }

bool MMAPAllocation::valid() const { return mmapped_buffer_ != MAP_FAILED; }

FileCopyAllocation::FileCopyAllocation(const char* filename,
                                       ErrorReporter* error_reporter)
    : Allocation(error_reporter) {
  // Obtain the file size, using an alternative method that is does not
  // require fstat for more compatibility.
  std::unique_ptr<FILE, decltype(&fclose)> file(fopen(filename, "rb"), fclose);
  if (!file) {
    error_reporter_->Report("Could not open '%s'.", filename);
    return;
  }
  // TODO(ahentz): Why did you think using fseek here was better for finding
  // the size?
  struct stat sb;
  if (fstat(fileno(file.get()), &sb) != 0) {
    error_reporter_->Report("Failed to get file size of '%s'.", filename);
    return;
  }
  buffer_size_bytes_ = sb.st_size;
  std::unique_ptr<char[]> buffer(new char[buffer_size_bytes_]);
  if (!buffer) {
    error_reporter_->Report("Malloc of buffer to hold copy of '%s' failed.",
                            filename);
    return;
  }
  size_t bytes_read =
      fread(buffer.get(), sizeof(char), buffer_size_bytes_, file.get());
  if (bytes_read != buffer_size_bytes_) {
    error_reporter_->Report("Read of '%s' failed (too few bytes read).",
                            filename);
    return;
  }
  // Versions of GCC before 6.2.0 don't support std::move from non-const
  // char[] to const char[] unique_ptrs.
  copied_buffer_.reset(const_cast<char const *>(buffer.release()));
}

FileCopyAllocation::~FileCopyAllocation() {}

const void* FileCopyAllocation::base() const { return copied_buffer_.get(); }

size_t FileCopyAllocation::bytes() const { return buffer_size_bytes_; }

bool FileCopyAllocation::valid() const { return copied_buffer_ != nullptr; }

MemoryAllocation::MemoryAllocation(const void* ptr, size_t num_bytes,
                                   ErrorReporter* error_reporter)
    : Allocation(error_reporter) {
  buffer_ = ptr;
  buffer_size_bytes_ = num_bytes;
}
#endif

MemoryAllocation::~MemoryAllocation() {}

const void* MemoryAllocation::base() const { return buffer_; }

size_t MemoryAllocation::bytes() const { return buffer_size_bytes_; }

bool MemoryAllocation::valid() const { return buffer_ != nullptr; }

}  // namespace tflite
<|endoftext|>


<commit_before>#include "cinder/app/App.h"
#include "cinder/app/RendererGl.h"
#include "cinder/gl/gl.h"
#include "cinder/Log.h"

#include "ui/Suite.h"
#include "mason/Hud.h"
#include "mason/Common.h"
#include "mason/Config.h"
#include "mason/Assets.h"
#include "mason/Profiling.h"

#include "HudTest.h"
#include "MiscTest.h"

#define USE_SECONDARY_SCREEN 1
#define MSAA 4
#define LIVEPP_ENABLED 1

#if LIVEPP_ENABLED

#include "mason/LivePPManager.h"

#endif

using namespace ci;
using namespace ci::app;
using namespace std;

class MasonTestsApp : public App {
  public:
	void setup() override;
	void resize() override;
	void keyDown( app::KeyEvent event ) override;
	void update() override;
	void draw() override;

	void reload();

	ui::SuiteRef	mSuite;
	bool			mDrawHud = true;
	bool			mDrawProfiling = false;
};

void MasonTestsApp::setup()
{
	ma::initialize( ma::getRepoRootPath() );

	mSuite = make_shared<ui::Suite>();

	mSuite->registerSuiteView<HudTest>( "hud" );
	mSuite->registerSuiteView<MiscTest>( "misc" );

	mSuite->getSignalSuiteViewWillChange().connect( [this] {
		CI_LOG_I( "selecting test: " << mSuite->getCurrentKey() );
	} );

	reload();
}

void MasonTestsApp::reload()
{
	// TODO: this should work without getAssetPath() too
	ma::assets()->getFile( app::getAssetPath( "config.json" ), [this]( DataSourceRef dataSource ) {
		CI_LOG_I( "config.json reloaded" );

		auto config = ma::Dictionary::convert<Json::Value>( app::loadAsset( "config.json" ) );
		ma::detail::setConfig( config );

		size_t testIndex = (size_t)ma::config()->getStrict<ma::Dictionary>( "app" ).get<int>( "test" );
		mSuite->select( testIndex );
	} );
}

void MasonTestsApp::keyDown( app::KeyEvent event )
{
	if( event.isControlDown() ) {
		if( tolower( event.getChar() ) == 'r' ) {
			CI_LOG_I( "reloading suite" );
			if( event.isShiftDown() ) {
				CI_LOG_I( "- clearing variables" );
				ma::hud()->clear();
			}
			mSuite->reload();
		}
		else if( event.getChar() == 'f' ) {
			CI_LOG_I( "toggling fullscreen" );
			setFullScreen( ! isFullScreen() );
		}
		else if( event.getChar() == 'h' ) {
			CI_LOG_I( "toggling Hud" );
			mDrawHud = ! mDrawHud;
			mSuite->setDrawUiEnabled( mDrawHud );
		}
		else if( event.getChar() == 'l' ) {
			mDrawProfiling = ! mDrawProfiling;
		}
	}
}

void MasonTestsApp::resize()
{
	CI_LOG_I( "window size: " << getWindowSize() );
}

void MasonTestsApp::update()
{
	ma::hud()->showInfo( 1, { "watches: ", to_string( FileWatcher::instance().getNumWatches() ) } );
	ma::hud()->showInfo( 2, { "watched files: ", to_string( FileWatcher::instance().getNumWatchedFiles() ) } );

	{
		CI_PROFILE( "Suite update" );
		mSuite->update();
	}

#if CI_PROFILING
	if( mDrawProfiling )
		perf::printProfiling();
#endif
}

void MasonTestsApp::draw()
{
	CI_PROFILE( "main draw" );

	gl::clear();

	{
		CI_PROFILE( "Suite draw" );
		mSuite->draw();
	}

	if( mDrawHud ) {
		CI_PROFILE( "Hud draw" );
		ma::hud()->draw();
	}

	CI_CHECK_GL();
}

void prepareSettings( App::Settings *settings )
{
#if LIVEPP_ENABLED
	bool liveppEnabled = ma::initLivePP( "../../../../../../tools/LivePP", "MasonTests" );
	CI_LOG_I( "Live++ " << string( liveppEnabled ? "enabled" : "disabled" ) );
#endif

	bool useSecondaryScreen = ( USE_SECONDARY_SCREEN && Display::getDisplays().size() > 1 );

	if( useSecondaryScreen ) {
		const auto &display = Display::getDisplays()[1];
		settings->setDisplay( display );
		settings->setFullScreen( true );
	}
	else {
#if defined( CINDER_MAC )
		ivec2 windowPos = { 0, 0 };
#else
		ivec2 windowPos = { 0, 24 };
#endif
		settings->setWindowPos( windowPos.x, windowPos.y );
		settings->setWindowSize( 960, 565 );
	}
}

CINDER_APP( MasonTestsApp, RendererGl( RendererGl::Options().msaa( MSAA ) ), prepareSettings )
<commit_msg>use latest config.h methods<commit_after>#include "cinder/app/App.h"
#include "cinder/app/RendererGl.h"
#include "cinder/gl/gl.h"
#include "cinder/Log.h"

#include "ui/Suite.h"
#include "mason/Hud.h"
#include "mason/Common.h"
#include "mason/Config.h"
#include "mason/Assets.h"
#include "mason/Profiling.h"

#include "HudTest.h"
#include "MiscTest.h"

#define USE_SECONDARY_SCREEN 1
#define MSAA 4
#define LIVEPP_ENABLED 1

#if LIVEPP_ENABLED

#include "mason/LivePPManager.h"

#endif

using namespace ci;
using namespace ci::app;
using namespace std;

class MasonTestsApp : public App {
  public:
	void setup() override;
	void resize() override;
	void keyDown( app::KeyEvent event ) override;
	void update() override;
	void draw() override;

	void reload();

	ui::SuiteRef	mSuite;
	bool			mDrawHud = true;
	bool			mDrawProfiling = false;
};

void MasonTestsApp::setup()
{
	ma::initialize( ma::getRepoRootPath() );

	mSuite = make_shared<ui::Suite>();

	mSuite->registerSuiteView<HudTest>( "hud" );
	mSuite->registerSuiteView<MiscTest>( "misc" );

	mSuite->getSignalSuiteViewWillChange().connect( [this] {
		CI_LOG_I( "selecting test: " << mSuite->getCurrentKey() );
	} );

	reload();
}

void MasonTestsApp::reload()
{
	ma::loadConfig();

	try {
		auto appConfig = ma::config()->get<ma::Dictionary>( "app" );

		size_t testIndex = appConfig["test"];
		mSuite->select( testIndex );
	}
	catch( exception &exc ) {
		CI_LOG_EXCEPTION( "failed to load reload", exc );
	}
}

void MasonTestsApp::keyDown( app::KeyEvent event )
{
	if( event.isControlDown() ) {
		if( tolower( event.getChar() ) == 'r' ) {
			CI_LOG_I( "reloading suite" );
			if( event.isShiftDown() ) {
				CI_LOG_I( "- clearing variables" );
				ma::hud()->clear();
			}
			mSuite->reload();
		}
		else if( event.getChar() == 'f' ) {
			CI_LOG_I( "toggling fullscreen" );
			setFullScreen( ! isFullScreen() );
		}
		else if( event.getChar() == 'h' ) {
			CI_LOG_I( "toggling Hud" );
			mDrawHud = ! mDrawHud;
			mSuite->setDrawUiEnabled( mDrawHud );
		}
		else if( event.getChar() == 'l' ) {
			mDrawProfiling = ! mDrawProfiling;
		}
	}
}

void MasonTestsApp::resize()
{
	CI_LOG_I( "window size: " << getWindowSize() );
}

void MasonTestsApp::update()
{
	ma::hud()->showInfo( 1, { "watches: ", to_string( FileWatcher::instance().getNumWatches() ) } );
	ma::hud()->showInfo( 2, { "watched files: ", to_string( FileWatcher::instance().getNumWatchedFiles() ) } );

	{
		CI_PROFILE( "Suite update" );
		mSuite->update();
	}

#if CI_PROFILING
	if( mDrawProfiling )
		perf::printProfiling();
#endif
}

void MasonTestsApp::draw()
{
	CI_PROFILE( "main draw" );

	gl::clear();

	{
		CI_PROFILE( "Suite draw" );
		mSuite->draw();
	}

	if( mDrawHud ) {
		CI_PROFILE( "Hud draw" );
		ma::hud()->draw();
	}

	CI_CHECK_GL();
}

void prepareSettings( App::Settings *settings )
{
#if LIVEPP_ENABLED
	bool liveppEnabled = ma::initLivePP( "../../../../../../tools/LivePP", "MasonTests" );
	CI_LOG_I( "Live++ " << string( liveppEnabled ? "enabled" : "disabled" ) );
#endif

	bool useSecondaryScreen = ( USE_SECONDARY_SCREEN && Display::getDisplays().size() > 1 );

	if( useSecondaryScreen ) {
		const auto &display = Display::getDisplays()[1];
		settings->setDisplay( display );
		settings->setFullScreen( true );
	}
	else {
#if defined( CINDER_MAC )
		ivec2 windowPos = { 0, 0 };
#else
		ivec2 windowPos = { 0, 24 };
#endif
		settings->setWindowPos( windowPos.x, windowPos.y );
		settings->setWindowSize( 960, 565 );
	}
}

CINDER_APP( MasonTestsApp, RendererGl( RendererGl::Options().msaa( MSAA ) ), prepareSettings )
<|endoftext|>