<commit_before>#define DEBUG 1
/**
 * File    : F.cpp
 * Author  : Kazune Takahashi
 * Created : 2020/6/23 5:42:51
 * Powered by Visual Studio Code
 */
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <chrono>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// ----- boost -----
#include <boost/integer/common_factor_rt.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/rational.hpp>
// ----- using directives and manipulations -----
using namespace std;
using boost::rational;
using boost::integer::gcd; // for C++14 or for cpp_int
using boost::integer::lcm; // for C++14 or for cpp_int
using boost::multiprecision::cpp_int;
using ll = long long;
using ld = long double;
template <typename T>
using max_heap = priority_queue<T>;
template <typename T>
using min_heap = priority_queue<T, vector<T>, greater<T>>;
// ----- constexpr for Mint and Combination -----
constexpr ll MOD{1'000'000'007LL};
// constexpr ll MOD{998'244'353LL}; // be careful
constexpr ll MAX_SIZE{3'000'010LL};
// constexpr ll MAX_SIZE{30'000'010LL}; // if 10^7 is needed
// ----- ch_max and ch_min -----
template <typename T>
bool ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
    return true;
  }
  return false;
}
template <typename T>
bool ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
    return true;
  }
  return false;
}
// ----- Mint -----
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{(x % MOD + MOD) % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(Mint const &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(Mint const &a) { return *this += -a; }
  Mint &operator++() { return *this += 1; }
  Mint operator++(int)
  {
    Mint tmp{*this};
    ++*this;
    return tmp;
  }
  Mint &operator--() { return *this -= 1; }
  Mint operator--(int)
  {
    Mint tmp{*this};
    --*this;
    return tmp;
  }
  Mint &operator*=(Mint const &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(Mint const &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(Mint const &a) const { return Mint(*this) += a; }
  Mint operator-(Mint const &a) const { return Mint(*this) -= a; }
  Mint operator*(Mint const &a) const { return Mint(*this) *= a; }
  Mint operator/(Mint const &a) const { return Mint(*this) /= a; }
  bool operator<(Mint const &a) const { return x < a.x; }
  bool operator<=(Mint const &a) const { return x <= a.x; }
  bool operator>(Mint const &a) const { return x > a.x; }
  bool operator>=(Mint const &a) const { return x >= a.x; }
  bool operator==(Mint const &a) const { return x == a.x; }
  bool operator!=(Mint const &a) const { return !(*this == a); }
  Mint power(ll N) const
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, Mint<MOD> const &rhs) { return rhs + lhs; }
template <ll MOD>
Mint<MOD> operator-(ll lhs, Mint<MOD> const &rhs) { return -rhs + lhs; }
template <ll MOD>
Mint<MOD> operator*(ll lhs, Mint<MOD> const &rhs) { return rhs * lhs; }
template <ll MOD>
Mint<MOD> operator/(ll lhs, Mint<MOD> const &rhs) { return Mint<MOD>{lhs} / rhs; }
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a) { return stream >> a.x; }
template <ll MOD>
ostream &operator<<(ostream &stream, Mint<MOD> const &a) { return stream << a.x; }
// ----- Combination -----
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i{2LL}; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i{1LL}; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// ----- for C++14 -----
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
// ----- for C++17 -----
template <typename T, typename enable_if<is_integral<T>::value>::type * = nullptr>
size_t popcount(T x) { return bitset<64>(x).count(); }
size_t popcount(string const &S) { return bitset<200010>{S}.count(); }
// ----- Infty -----
template <typename T>
constexpr T Infty() { return numeric_limits<T>::max(); }
template <typename T>
constexpr T mInfty() { return numeric_limits<T>::min(); }
// ----- frequently used constexpr -----
// constexpr double epsilon{1e-10};
// constexpr ll infty{1'000'000'000'000'010LL}; // or
// constexpr int infty{1'000'000'010};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
// ----- Yes() and No() -----
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "No" << endl;
  exit(0);
}

// ----- ReadGraph -----
// Referring to ymatsux-san's source code: https://atcoder.jp/contests/abc138/submissions/7016619

struct Edge
{
  int src, dst, id, rev;
  // ll cost;
  Edge() {}
  Edge(int src, int dst, int id, int rev) : src{src}, dst{dst}, id{id}, rev{rev} {}

  void added_edge(vector<vector<Edge>> &V)
  {
    V[src].push_back(*this);
  }

  void added_rev(vector<vector<Edge>> &V)
  {
    V[dst].push_back(rev_edge());
  }

  Edge rev_edge()
  {
    Edge edge{*this};
    swap(edge.src, edge.dst);
    swap(edge.id, edge.rev);
    return edge;
  }
};

enum class GraphType
{
  Undirected,
  Directed,
  RevEdge,
};

tuple<vector<vector<Edge>>, vector<Edge>> ReadGraphWithEdges(int N, int M, GraphType type = GraphType::Undirected, bool is_one_indexed = true)
{
  vector<vector<Edge>> V(N);
  vector<Edge> E;
  for (auto i = 0; i < M; ++i)
  {
    int v, w;
    cin >> v >> w;
    if (is_one_indexed)
    {
      --v;
      --w;
    }
    switch (type)
    {
    case GraphType::Undirected:
    {
      Edge edge{v, w, static_cast<int>(E.size()), static_cast<int>(E.size())};
      edge.added_edge(V);
      edge.added_rev(V);
      E.push_back(edge);
      break;
    }
    case GraphType::Directed:
    {
      Edge edge{v, w, static_cast<int>(E.size()), static_cast<int>(E.size())};
      edge.added_edge(V);
      E.push_back(edge);
      break;
    }
    case GraphType::RevEdge:
    {
      Edge edge{v, w, static_cast<int>(E.size()), static_cast<int>(E.size()) + 1};
      edge.added_edge(V);
      edge.added_rev(V);
      E.push_back(edge);
      E.push_back(edge.rev_edge());
      break;
    }
    default:
      break;
    }
  }
  return make_tuple(V, E);
}

vector<vector<Edge>> ReadGraph(int N, int M, GraphType type = GraphType::Undirected, bool is_one_indexed = true)
{
  return get<0>(ReadGraphWithEdges(N, M, type, is_one_indexed));
}

tuple<vector<vector<Edge>>, vector<Edge>> ReadTreeWithEdges(int N, GraphType type = GraphType::Undirected, bool is_one_indexed = true)
{
  return ReadGraphWithEdges(N, N - 1, type, is_one_indexed);
}

vector<vector<Edge>> ReadTree(int N, GraphType type = GraphType::Undirected, bool is_one_indexed = true)
{
  return ReadGraph(N, N - 1, type, is_one_indexed);
}

// ----- Solve -----

struct SubTree
{
  ll id, size;
};

class Solve
{
  ll N, id;
  vector<queue<SubTree>> Q;
  vector<ll> C;
  vector<vector<Edge>> V;
  vector<vector<ll>> S;
  vector<ll> color_to_count;

public:
  Solve(ll N) : N{N}, id{0}, Q(N), C(N), S(N), color_to_count(N, 0)
  {
    for (auto i{0}; i < N; ++i)
    {
      cin >> C[i];
      C[i]--;
      color_to_count[C[i]]++;
    }
    V = ReadTree(N);
  }

  void flush()
  {
    dfs();
    for (auto i{0}; i < N; ++i)
    {
      auto sum{accumulate(S[i].begin(), S[i].end(), 0)};
      S[i].push_back(N - sum - color_to_count[i]);
      ll ans{0};
      for (auto e : S[i])
      {
        ans += e * (e + 1) / 2;
      }
#if DEBUG == 1
      cerr << "S[" << i << "] : ";
      for (auto e : S[i])
      {
        cerr << e << ", ";
      }
      cerr << endl;
#endif
      cout << N * (N + 1) / 2 - ans << endl;
    }
  }

private:
  ll dfs(ll src = 0, ll parent = -1)
  {
    auto src_id{id++};
#if DEBUG == 1
    cerr << "dfs(" << src << ")" << endl;
#endif
    auto &subtree_queue{Q[C[src]]};
    for (auto const &e : V[src])
    {
      if (e.dst == parent)
      {
        continue;
      }
      auto colorless_tree_size{dfs(e.dst, src)};
      while (!subtree_queue.empty() && subtree_queue.front().id > src_id)
      {
        colorless_tree_size -= subtree_queue.front().size;
        subtree_queue.pop();
      }
      S[C[src]].push_back(colorless_tree_size);
    }
    auto subtree_size{id - src_id};
    subtree_queue.push(SubTree{src_id, subtree_size});
    return subtree_size;
  }
};

// ----- main() -----

int main()
{
  ll N;
  cin >> N;
  Solve solve(N);
  solve.flush();
}
<commit_msg>tried F.cpp to 'F'<commit_after>#define DEBUG 1
/**
 * File    : F.cpp
 * Author  : Kazune Takahashi
 * Created : 2020/6/23 5:42:51
 * Powered by Visual Studio Code
 */
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <chrono>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// ----- boost -----
#include <boost/integer/common_factor_rt.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/rational.hpp>
// ----- using directives and manipulations -----
using namespace std;
using boost::rational;
using boost::integer::gcd; // for C++14 or for cpp_int
using boost::integer::lcm; // for C++14 or for cpp_int
using boost::multiprecision::cpp_int;
using ll = long long;
using ld = long double;
template <typename T>
using max_heap = priority_queue<T>;
template <typename T>
using min_heap = priority_queue<T, vector<T>, greater<T>>;
// ----- constexpr for Mint and Combination -----
constexpr ll MOD{1'000'000'007LL};
// constexpr ll MOD{998'244'353LL}; // be careful
constexpr ll MAX_SIZE{3'000'010LL};
// constexpr ll MAX_SIZE{30'000'010LL}; // if 10^7 is needed
// ----- ch_max and ch_min -----
template <typename T>
bool ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
    return true;
  }
  return false;
}
template <typename T>
bool ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
    return true;
  }
  return false;
}
// ----- Mint -----
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{(x % MOD + MOD) % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(Mint const &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(Mint const &a) { return *this += -a; }
  Mint &operator++() { return *this += 1; }
  Mint operator++(int)
  {
    Mint tmp{*this};
    ++*this;
    return tmp;
  }
  Mint &operator--() { return *this -= 1; }
  Mint operator--(int)
  {
    Mint tmp{*this};
    --*this;
    return tmp;
  }
  Mint &operator*=(Mint const &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(Mint const &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(Mint const &a) const { return Mint(*this) += a; }
  Mint operator-(Mint const &a) const { return Mint(*this) -= a; }
  Mint operator*(Mint const &a) const { return Mint(*this) *= a; }
  Mint operator/(Mint const &a) const { return Mint(*this) /= a; }
  bool operator<(Mint const &a) const { return x < a.x; }
  bool operator<=(Mint const &a) const { return x <= a.x; }
  bool operator>(Mint const &a) const { return x > a.x; }
  bool operator>=(Mint const &a) const { return x >= a.x; }
  bool operator==(Mint const &a) const { return x == a.x; }
  bool operator!=(Mint const &a) const { return !(*this == a); }
  Mint power(ll N) const
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, Mint<MOD> const &rhs) { return rhs + lhs; }
template <ll MOD>
Mint<MOD> operator-(ll lhs, Mint<MOD> const &rhs) { return -rhs + lhs; }
template <ll MOD>
Mint<MOD> operator*(ll lhs, Mint<MOD> const &rhs) { return rhs * lhs; }
template <ll MOD>
Mint<MOD> operator/(ll lhs, Mint<MOD> const &rhs) { return Mint<MOD>{lhs} / rhs; }
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a) { return stream >> a.x; }
template <ll MOD>
ostream &operator<<(ostream &stream, Mint<MOD> const &a) { return stream << a.x; }
// ----- Combination -----
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i{2LL}; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i{1LL}; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// ----- for C++14 -----
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
// ----- for C++17 -----
template <typename T, typename enable_if<is_integral<T>::value>::type * = nullptr>
size_t popcount(T x) { return bitset<64>(x).count(); }
size_t popcount(string const &S) { return bitset<200010>{S}.count(); }
// ----- Infty -----
template <typename T>
constexpr T Infty() { return numeric_limits<T>::max(); }
template <typename T>
constexpr T mInfty() { return numeric_limits<T>::min(); }
// ----- frequently used constexpr -----
// constexpr double epsilon{1e-10};
// constexpr ll infty{1'000'000'000'000'010LL}; // or
// constexpr int infty{1'000'000'010};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
// ----- Yes() and No() -----
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "No" << endl;
  exit(0);
}

// ----- ReadGraph -----
// Referring to ymatsux-san's source code: https://atcoder.jp/contests/abc138/submissions/7016619

struct Edge
{
  int src, dst, id, rev;
  // ll cost;
  Edge() {}
  Edge(int src, int dst, int id, int rev) : src{src}, dst{dst}, id{id}, rev{rev} {}

  void added_edge(vector<vector<Edge>> &V)
  {
    V[src].push_back(*this);
  }

  void added_rev(vector<vector<Edge>> &V)
  {
    V[dst].push_back(rev_edge());
  }

  Edge rev_edge()
  {
    Edge edge{*this};
    swap(edge.src, edge.dst);
    swap(edge.id, edge.rev);
    return edge;
  }
};

enum class GraphType
{
  Undirected,
  Directed,
  RevEdge,
};

tuple<vector<vector<Edge>>, vector<Edge>> ReadGraphWithEdges(int N, int M, GraphType type = GraphType::Undirected, bool is_one_indexed = true)
{
  vector<vector<Edge>> V(N);
  vector<Edge> E;
  for (auto i = 0; i < M; ++i)
  {
    int v, w;
    cin >> v >> w;
    if (is_one_indexed)
    {
      --v;
      --w;
    }
    switch (type)
    {
    case GraphType::Undirected:
    {
      Edge edge{v, w, static_cast<int>(E.size()), static_cast<int>(E.size())};
      edge.added_edge(V);
      edge.added_rev(V);
      E.push_back(edge);
      break;
    }
    case GraphType::Directed:
    {
      Edge edge{v, w, static_cast<int>(E.size()), static_cast<int>(E.size())};
      edge.added_edge(V);
      E.push_back(edge);
      break;
    }
    case GraphType::RevEdge:
    {
      Edge edge{v, w, static_cast<int>(E.size()), static_cast<int>(E.size()) + 1};
      edge.added_edge(V);
      edge.added_rev(V);
      E.push_back(edge);
      E.push_back(edge.rev_edge());
      break;
    }
    default:
      break;
    }
  }
  return make_tuple(V, E);
}

vector<vector<Edge>> ReadGraph(int N, int M, GraphType type = GraphType::Undirected, bool is_one_indexed = true)
{
  return get<0>(ReadGraphWithEdges(N, M, type, is_one_indexed));
}

tuple<vector<vector<Edge>>, vector<Edge>> ReadTreeWithEdges(int N, GraphType type = GraphType::Undirected, bool is_one_indexed = true)
{
  return ReadGraphWithEdges(N, N - 1, type, is_one_indexed);
}

vector<vector<Edge>> ReadTree(int N, GraphType type = GraphType::Undirected, bool is_one_indexed = true)
{
  return ReadGraph(N, N - 1, type, is_one_indexed);
}

// ----- Solve -----

struct SubTree
{
  ll id, size;
};

class Solve
{
  ll N, id;
  vector<queue<SubTree>> Q;
  vector<ll> C;
  vector<vector<Edge>> V;
  vector<vector<ll>> S;
  vector<ll> color_to_count;

public:
  Solve(ll N) : N{N}, id{0}, Q(N), C(N), S(N), color_to_count(N, 0)
  {
    for (auto i{0}; i < N; ++i)
    {
      cin >> C[i];
      C[i]--;
      color_to_count[C[i]]++;
    }
    V = ReadTree(N);
  }

  void flush()
  {
    dfs();
    for (auto i{0}; i < N; ++i)
    {
      auto sum{accumulate(S[i].begin(), S[i].end(), 0)};
      S[i].push_back(N - sum - color_to_count[i]);
      ll ans{0};
      for (auto e : S[i])
      {
        ans += e * (e + 1) / 2;
      }
#if DEBUG == 1
      cerr << "S[" << i << "] : ";
      for (auto e : S[i])
      {
        cerr << e << ", ";
      }
      cerr << endl;
#endif
      cout << N * (N + 1) / 2 - ans << endl;
    }
  }

private:
  ll dfs(ll src = 0, ll parent = -1)
  {
    auto src_id{id++};
#if DEBUG == 1
    cout << "dfs(" << src << ")" << endl;
#endif
    auto &subtree_queue{Q[C[src]]};
    for (auto const &e : V[src])
    {
      if (e.dst == parent)
      {
        continue;
      }
      auto colorless_tree_size{dfs(e.dst, src)};
      while (!subtree_queue.empty() && subtree_queue.front().id > src_id)
      {
        colorless_tree_size -= subtree_queue.front().size;
        subtree_queue.pop();
      }
      S[C[src]].push_back(colorless_tree_size);
    }
    auto subtree_size{id - src_id};
    subtree_queue.push(SubTree{src_id, subtree_size});
    return subtree_size;
  }
};

// ----- main() -----

int main()
{
  ll N;
  cin >> N;
  Solve solve(N);
  solve.flush();
}
<|endoftext|>


<commit_before>#include "MS5611.h"

namespace flyhero {

MS5611& MS5611::Instance() {
	static MS5611 instance;

	return instance;
}

MS5611::MS5611() {
	this->spi = NULL;
	std::memset(this->c, 0, 6);
	this->d1 = 0;
	this->d2 = 0;
}

esp_err_t MS5611::spi_init() {
    esp_err_t ret;

    spi_bus_config_t buscfg;
    buscfg.miso_io_num = GPIO_NUM_25;
    buscfg.mosi_io_num = GPIO_NUM_23;
    buscfg.sclk_io_num = GPIO_NUM_19;
    buscfg.quadwp_io_num = -1;
    buscfg.quadhd_io_num = -1;
    buscfg.max_transfer_sz = 0;

    spi_device_interface_config_t devcfg;
    devcfg.command_bits = 8;
    devcfg.address_bits = 0;
    devcfg.dummy_bits = 0;
    devcfg.mode = 0;
    devcfg.duty_cycle_pos = 128;
    devcfg.cs_ena_pretrans = 0;
    devcfg.cs_ena_posttrans = 0;
    devcfg.clock_speed_hz = 20000000;
    devcfg.spics_io_num = GPIO_NUM_22;
    devcfg.flags = 0;
    devcfg.queue_size = 7;
    devcfg.pre_cb = 0;
    devcfg.post_cb = 0;

    //Initialize the SPI bus
    if ( (ret = spi_bus_initialize(HSPI_HOST, &buscfg, 0)) )
    	return ret;

    if ( (ret = spi_bus_add_device(HSPI_HOST, &devcfg, &this->spi)) )
    	return ret;

    return ESP_OK;
}

esp_err_t MS5611::reset()
{
	esp_err_t ret;

	spi_transaction_t trans;
	trans.flags = 0;
	trans.cmd = 0x1E;
	trans.addr = 0;
	trans.length = 0;
	trans.rxlength = 0;
	trans.user = 0;
	trans.tx_buffer = NULL;
	trans.rx_buffer = NULL;

	if ( (ret = spi_device_transmit(this->spi, &trans)) )
		return ret;

	return ESP_OK;
}

esp_err_t MS5611::load_prom() {
	esp_err_t ret;

	spi_transaction_t trans;
	trans.flags = SPI_TRANS_USE_RXDATA;
	trans.cmd = 0;
	trans.addr = 0;
	trans.length = 16;
	trans.rxlength = 16;
	trans.user = 0;
	trans.tx_buffer = NULL;

	for (uint8_t i = 0; i < 6; i++) {
		trans.cmd = 0xA2 + i * 2;

		if ( (ret = spi_device_transmit(this->spi, &trans)) )
			return ret;

		this->c[i] = trans.rx_data[0] << 8;
		this->c[i] |= trans.rx_data[1];
	}

	return ESP_OK;
}

esp_err_t MS5611::read_d1() {
	esp_err_t ret;

	// convert D1 (OSR = 4096)
	spi_transaction_t trans;
	trans.flags = 0;
	trans.cmd = 0x48;
	trans.addr = 0;
	trans.length = 0;
	trans.rxlength = 0;
	trans.user = 0;
	trans.rx_buffer = NULL;
	trans.tx_buffer = NULL;

	if ( (ret = spi_device_transmit(this->spi, &trans)) )
		return ret;

	// not supported yet
	//TickType_t current_ticks = xTaskGetTickCount();
	//vTaskDelayUntil(&current_ticks, 10 / portTICK_RATE_MS);

	// wait until conversion done
	vTaskDelay(10 / portTICK_RATE_MS);

	// read converted D1 value
	trans.flags = SPI_TRANS_USE_RXDATA;
	trans.cmd = 0x00;
	trans.addr = 0;
	trans.length = 24;
	trans.rxlength = 24;
	trans.user = 0;
	trans.tx_buffer = NULL;

	if ( (ret = spi_device_transmit(this->spi, &trans)) )
		return ret;

	this->d1 = trans.rx_data[0] << 16;
	this->d1 |= trans.rx_data[1] << 8;
	this->d1 |= trans.rx_data[2];

	return ESP_OK;
}

esp_err_t MS5611::read_d2() {
	esp_err_t ret;

	// convert D2 (OSR = 4096)
	spi_transaction_t trans;
	trans.flags = 0;
	trans.cmd = 0x58;
	trans.addr = 0;
	trans.length = 0;
	trans.rxlength = 0;
	trans.user = 0;
	trans.rx_buffer = NULL;
	trans.tx_buffer = NULL;

	if ( (ret = spi_device_transmit(this->spi, &trans)) )
		return ret;

	// wait until conversion done
	vTaskDelay(10 / portTICK_RATE_MS);

	// not supported yet
	//TickType_t current_ticks = xTaskGetTickCount();
	//vTaskDelayUntil(&current_ticks, 10 / portTICK_RATE_MS);

	// read converted D2 value
	trans.flags = SPI_TRANS_USE_RXDATA;
	trans.cmd = 0x00;
	trans.addr = 0;
	trans.length = 24;
	trans.rxlength = 24;
	trans.user = 0;
	trans.tx_buffer = NULL;

	if ( (ret = spi_device_transmit(this->spi, &trans)) )
		return ret;

	this->d2 = trans.rx_data[0] << 16;
	this->d2 |= trans.rx_data[1] << 8;
	this->d2 |= trans.rx_data[2];

	return ESP_OK;
}

esp_err_t MS5611::Init()
{
	esp_err_t ret;

	if ( (ret = this->spi_init()) )
		return ret;

	if ( (ret = this->reset()) )
		return ret;

	// wait until reset done
	vTaskDelay(20 / portTICK_RATE_MS);

	if ( (ret = this->load_prom()) )
		return ret;

	return ESP_OK;
}

esp_err_t MS5611::Get_Data(int32_t& temperature, int32_t& pressure)
{
	esp_err_t ret;

	if ( (ret = this->read_d1()) )
		return ret;

	if ( (ret = this->read_d2()) )
		return ret;

	int32_t d_t = this->d2 - (uint32_t)this->c[4] * 256;
	int32_t temp = 2000 + ((int64_t)d_t * this->c[5]) / 8388608;

	int64_t off = (int64_t)this->c[1] * 65536 + (int64_t)this->c[3] * d_t / 128;
	int64_t sens = (int64_t)this->c[0] * 32768 + (int64_t)this->c[2] * d_t / 256;

	int32_t temp_2 = 0;
	int64_t off_2 = 0;
	int64_t sens_2 = 0;

	if (temp < 2000) {
		temp_2 = ((int64_t)d_t * d_t) / 2147483648;
		off_2 = 5 * ((temp - 2000) * (temp - 2000)) / 2;
		sens_2 = 5 * ((temp - 2000) * (temp - 2000)) / 4;
	}
	if (temp < -1500) {
		off_2 = off_2 + 7 * (temp + 1500) * (temp + 1500);
		sens_2 = sens_2 + 11 * (temp + 1500) * (temp + 1500) / 2;
	}

	temp -= temp_2;
	off -= off_2;
	sens -= sens_2;

	int32_t p = (this->d1 * sens / 2097152 - off) / 32768;

	temperature = temp;
	pressure = p;

	return ESP_OK;
}

}
<commit_msg>(MS5611): change pins used by sensor; change SPI host<commit_after>#include "MS5611.h"

namespace flyhero {

MS5611& MS5611::Instance() {
	static MS5611 instance;

	return instance;
}

MS5611::MS5611() {
	this->spi = NULL;
	std::memset(this->c, 0, 6);
	this->d1 = 0;
	this->d2 = 0;
}

esp_err_t MS5611::spi_init() {
    esp_err_t ret;

    spi_bus_config_t buscfg;
    buscfg.miso_io_num = GPIO_NUM_4;
    buscfg.mosi_io_num = GPIO_NUM_17;
    buscfg.sclk_io_num = GPIO_NUM_5;
    buscfg.quadwp_io_num = -1;
    buscfg.quadhd_io_num = -1;
    buscfg.max_transfer_sz = 0;

    spi_device_interface_config_t devcfg;
    devcfg.command_bits = 8;
    devcfg.address_bits = 0;
    devcfg.dummy_bits = 0;
    devcfg.mode = 0;
    devcfg.duty_cycle_pos = 128;
    devcfg.cs_ena_pretrans = 0;
    devcfg.cs_ena_posttrans = 0;
    devcfg.clock_speed_hz = 20000000;
    devcfg.spics_io_num = GPIO_NUM_16;
    devcfg.flags = 0;
    devcfg.queue_size = 7;
    devcfg.pre_cb = 0;
    devcfg.post_cb = 0;

    //Initialize the SPI bus
    if ( (ret = spi_bus_initialize(VSPI_HOST, &buscfg, 0)) )
    	return ret;

    if ( (ret = spi_bus_add_device(VSPI_HOST, &devcfg, &this->spi)) )
    	return ret;

    return ESP_OK;
}

esp_err_t MS5611::reset()
{
	esp_err_t ret;

	spi_transaction_t trans;
	trans.flags = 0;
	trans.cmd = 0x1E;
	trans.addr = 0;
	trans.length = 0;
	trans.rxlength = 0;
	trans.user = 0;
	trans.tx_buffer = NULL;
	trans.rx_buffer = NULL;

	if ( (ret = spi_device_transmit(this->spi, &trans)) )
		return ret;

	return ESP_OK;
}

esp_err_t MS5611::load_prom() {
	esp_err_t ret;

	spi_transaction_t trans;
	trans.flags = SPI_TRANS_USE_RXDATA;
	trans.cmd = 0;
	trans.addr = 0;
	trans.length = 16;
	trans.rxlength = 16;
	trans.user = 0;
	trans.tx_buffer = NULL;

	for (uint8_t i = 0; i < 6; i++) {
		trans.cmd = 0xA2 + i * 2;

		if ( (ret = spi_device_transmit(this->spi, &trans)) )
			return ret;

		this->c[i] = trans.rx_data[0] << 8;
		this->c[i] |= trans.rx_data[1];
	}

	return ESP_OK;
}

esp_err_t MS5611::read_d1() {
	esp_err_t ret;

	// convert D1 (OSR = 4096)
	spi_transaction_t trans;
	trans.flags = 0;
	trans.cmd = 0x48;
	trans.addr = 0;
	trans.length = 0;
	trans.rxlength = 0;
	trans.user = 0;
	trans.rx_buffer = NULL;
	trans.tx_buffer = NULL;

	if ( (ret = spi_device_transmit(this->spi, &trans)) )
		return ret;

	// not supported yet
	//TickType_t current_ticks = xTaskGetTickCount();
	//vTaskDelayUntil(&current_ticks, 10 / portTICK_RATE_MS);

	// wait until conversion done
	vTaskDelay(10 / portTICK_RATE_MS);

	// read converted D1 value
	trans.flags = SPI_TRANS_USE_RXDATA;
	trans.cmd = 0x00;
	trans.addr = 0;
	trans.length = 24;
	trans.rxlength = 24;
	trans.user = 0;
	trans.tx_buffer = NULL;

	if ( (ret = spi_device_transmit(this->spi, &trans)) )
		return ret;

	this->d1 = trans.rx_data[0] << 16;
	this->d1 |= trans.rx_data[1] << 8;
	this->d1 |= trans.rx_data[2];

	return ESP_OK;
}

esp_err_t MS5611::read_d2() {
	esp_err_t ret;

	// convert D2 (OSR = 4096)
	spi_transaction_t trans;
	trans.flags = 0;
	trans.cmd = 0x58;
	trans.addr = 0;
	trans.length = 0;
	trans.rxlength = 0;
	trans.user = 0;
	trans.rx_buffer = NULL;
	trans.tx_buffer = NULL;

	if ( (ret = spi_device_transmit(this->spi, &trans)) )
		return ret;

	// wait until conversion done
	vTaskDelay(10 / portTICK_RATE_MS);

	// not supported yet
	//TickType_t current_ticks = xTaskGetTickCount();
	//vTaskDelayUntil(&current_ticks, 10 / portTICK_RATE_MS);

	// read converted D2 value
	trans.flags = SPI_TRANS_USE_RXDATA;
	trans.cmd = 0x00;
	trans.addr = 0;
	trans.length = 24;
	trans.rxlength = 24;
	trans.user = 0;
	trans.tx_buffer = NULL;

	if ( (ret = spi_device_transmit(this->spi, &trans)) )
		return ret;

	this->d2 = trans.rx_data[0] << 16;
	this->d2 |= trans.rx_data[1] << 8;
	this->d2 |= trans.rx_data[2];

	return ESP_OK;
}

esp_err_t MS5611::Init()
{
	esp_err_t ret;

	if ( (ret = this->spi_init()) )
		return ret;

	if ( (ret = this->reset()) )
		return ret;

	// wait until reset done
	vTaskDelay(20 / portTICK_RATE_MS);

	if ( (ret = this->load_prom()) )
		return ret;

	return ESP_OK;
}

esp_err_t MS5611::Get_Data(int32_t& temperature, int32_t& pressure)
{
	esp_err_t ret;

	if ( (ret = this->read_d1()) )
		return ret;

	if ( (ret = this->read_d2()) )
		return ret;

	int32_t d_t = this->d2 - (uint32_t)this->c[4] * 256;
	int32_t temp = 2000 + ((int64_t)d_t * this->c[5]) / 8388608;

	int64_t off = (int64_t)this->c[1] * 65536 + (int64_t)this->c[3] * d_t / 128;
	int64_t sens = (int64_t)this->c[0] * 32768 + (int64_t)this->c[2] * d_t / 256;

	int32_t temp_2 = 0;
	int64_t off_2 = 0;
	int64_t sens_2 = 0;

	if (temp < 2000) {
		temp_2 = ((int64_t)d_t * d_t) / 2147483648;
		off_2 = 5 * ((temp - 2000) * (temp - 2000)) / 2;
		sens_2 = 5 * ((temp - 2000) * (temp - 2000)) / 4;
	}
	if (temp < -1500) {
		off_2 = off_2 + 7 * (temp + 1500) * (temp + 1500);
		sens_2 = sens_2 + 11 * (temp + 1500) * (temp + 1500) / 2;
	}

	temp -= temp_2;
	off -= off_2;
	sens -= sens_2;

	int32_t p = (this->d1 * sens / 2097152 - off) / 32768;

	temperature = temp;
	pressure = p;

	return ESP_OK;
}

}
<|endoftext|>


<commit_before>#include "HotkeyManager.h"
#include "Logger.h"

HotkeyManager *HotkeyManager::instance = NULL;

HotkeyManager *HotkeyManager::Instance() {
    return instance;
}

HotkeyManager *HotkeyManager::Instance(HWND notifyWnd) {
    if (instance == NULL) {
        instance = new HotkeyManager();
        instance->Hook();
        instance->_notifyWnd = notifyWnd;
    }

    return instance;
}

bool HotkeyManager::Hook() {
    _mouseHook = SetWindowsHookEx(WH_MOUSE_LL,
        LowLevelMouseProc, NULL, NULL);

    _keyHook = SetWindowsHookEx(WH_KEYBOARD_LL,
        LowLevelKeyboardProc, NULL, NULL);

    return _mouseHook && _keyHook;
}

bool HotkeyManager::Unhook() {
    BOOL unMouse = UnhookWindowsHookEx(_mouseHook);
    BOOL unKey = UnhookWindowsHookEx(_keyHook);
    return unMouse && unKey;
}

void HotkeyManager::Register(int keyCombination) {
    if (_keyCombinations.count(keyCombination) > 0) {
        CLOG(L"Hotkey combination [%d] already registered", keyCombination);
        return;
    } else {
        _keyCombinations.insert(keyCombination);
    }

    /* get VK_* value; includes unused bits */
    int vk = 0xFFFF & keyCombination;

    if ((keyCombination >> 20) > 0 /* uses a HKM_MOUSE_* flag */
        || vk == VK_LBUTTON
        || vk == VK_RBUTTON
        || vk == VK_MBUTTON) {

        /* mouse-based hotkeys; we are done */
        CLOG(L"Registered new mouse-based hotkey: %d", keyCombination);
        return;
    }

    /* keyboard-only hotkeys; use WinAPI */
    int mods = (0xF0000 & keyCombination) >> 16;
    if (!RegisterHotKey(_notifyWnd, keyCombination, mods, vk)) {
        CLOG(L"Failed to register hotkey combination: %d", keyCombination);
        return;
    }

    CLOG(L"Registered new keyboard-based hotkey: %d", keyCombination);
}

void HotkeyManager::Unregister(int keyCombination) {
    CLOG(L"Unregistering hotkey combination: %d", keyCombination);

    if (_keyCombinations.count(keyCombination) <= 0) {
        QCLOG(L"Hotkey combination [%d] was not previously registered",
            keyCombination);
        return;
    }

    _keyCombinations.erase(keyCombination);
    if ((keyCombination >> 20) == 0) {
        /* This hotkey isn't mouse-based; unregister with Windows */
        if (!UnregisterHotKey(_notifyWnd, keyCombination)) {
            CLOG(L"Failed to unregister hotkey: %d", keyCombination);
            return;
        }
    }
}

int HotkeyManager::Modifiers() {
    int mods = 0;
    mods += (GetKeyState(VK_MENU) & 0x8000) << 1;
    mods += (GetKeyState(VK_CONTROL) & 0x8000) << 2;
    mods += (GetKeyState(VK_SHIFT) & 0x8000) << 3;
    mods += (GetKeyState(VK_LWIN) & 0x8000) << 4;
    mods += (GetKeyState(VK_RWIN) & 0x8000) << 4;
    return mods;
}

LRESULT CALLBACK
HotkeyManager::KeyProc(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode >= 0) {
        if (wParam == WM_KEYUP) {
            KBDLLHOOKSTRUCT *kbInfo = (KBDLLHOOKSTRUCT*) lParam;
            if ((kbInfo->vkCode == VK_LWIN || kbInfo->vkCode == VK_RWIN)
                && _fixWin) {
                /* WIN+Mouse combination used; we need to prevent the
                 * system from only seeing a WIN keypress (and usually
                 * popping up the start menu).  We simulate WIN+VK_NONAME. */

                INPUT input = { 0 };
                input.type = INPUT_KEYBOARD;

                input.ki.wVk = VK_NONAME;
                input.ki.wScan = 0;
                input.ki.dwFlags = 0;
                input.ki.time = 1;
                input.ki.dwExtraInfo = GetMessageExtraInfo();

                /* key down: */
                SendInput(1, &input, sizeof(INPUT));

                input.ki.dwFlags = KEYEVENTF_KEYUP;
                /* key up: */
                SendInput(1, &input, sizeof(INPUT));

                _fixWin = false;
            }
        }
    }

    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

LRESULT CALLBACK
HotkeyManager::MouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode >= 0) {
        int mouseState = 0;
        MSLLHOOKSTRUCT *msInfo;

        switch (wParam) {

            case WM_LBUTTONDOWN:
                mouseState += VK_LBUTTON;
                break;

            case WM_MBUTTONDOWN:
                mouseState += VK_MBUTTON;
                break;

            case WM_RBUTTONDOWN:
                mouseState += VK_RBUTTON;
                break;

            case WM_XBUTTONDOWN: {
                msInfo = (MSLLHOOKSTRUCT*) lParam;

                int button = msInfo->mouseData >> 16 & 0xFFFF;
                if (button == 1)
                    mouseState += HKM_MOUSE_XB1;
                else if (button == 2)
                    mouseState += HKM_MOUSE_XB2;

                break;
            }

            case WM_MOUSEWHEEL: {
                msInfo = (MSLLHOOKSTRUCT*) lParam;

                if ((int) msInfo->mouseData > 0) {
                    mouseState += HKM_MOUSE_WHUP;
                } else {
                    mouseState += HKM_MOUSE_WHDN;
                }

                break;
            }
        }

        if (mouseState > 0) {
            mouseState += Modifiers();

            if (_keyCombinations.count(mouseState) > 0) {
                PostMessage(_notifyWnd, WM_HOTKEY,
                    mouseState, mouseState & 0xF0000);

                if (mouseState & HKM_MOD_WIN) {
                    _fixWin = true; /* enable fix right before WIN goes up */
                }

                return 1; /* processed the message; eat it */
            }
        }
    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

LRESULT CALLBACK
HotkeyManager::LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
    return HotkeyManager::Instance()->MouseProc(nCode, wParam, lParam);
}

LRESULT CALLBACK
HotkeyManager::LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
    return HotkeyManager::Instance()->KeyProc(nCode, wParam, lParam);
}<commit_msg>Add more information to failed hotkey registration log messages<commit_after>#include "HotkeyManager.h"
#include "Logger.h"

HotkeyManager *HotkeyManager::instance = NULL;

HotkeyManager *HotkeyManager::Instance() {
    return instance;
}

HotkeyManager *HotkeyManager::Instance(HWND notifyWnd) {
    if (instance == NULL) {
        instance = new HotkeyManager();
        instance->Hook();
        instance->_notifyWnd = notifyWnd;
    }

    return instance;
}

bool HotkeyManager::Hook() {
    _mouseHook = SetWindowsHookEx(WH_MOUSE_LL,
        LowLevelMouseProc, NULL, NULL);

    _keyHook = SetWindowsHookEx(WH_KEYBOARD_LL,
        LowLevelKeyboardProc, NULL, NULL);

    return _mouseHook && _keyHook;
}

bool HotkeyManager::Unhook() {
    BOOL unMouse = UnhookWindowsHookEx(_mouseHook);
    BOOL unKey = UnhookWindowsHookEx(_keyHook);
    return unMouse && unKey;
}

void HotkeyManager::Register(int keyCombination) {
    if (_keyCombinations.count(keyCombination) > 0) {
        CLOG(L"Hotkey combination [%d] already registered", keyCombination);
        return;
    } else {
        _keyCombinations.insert(keyCombination);
    }

    /* get VK_* value; includes unused bits */
    int vk = 0xFFFF & keyCombination;

    if ((keyCombination >> 20) > 0 /* uses a HKM_MOUSE_* flag */
        || vk == VK_LBUTTON
        || vk == VK_RBUTTON
        || vk == VK_MBUTTON) {

        /* mouse-based hotkeys; we are done */
        CLOG(L"Registered new mouse-based hotkey: %d", keyCombination);
        return;
    }

    /* keyboard-only hotkeys; use WinAPI */
    int mods = (0xF0000 & keyCombination) >> 16;
    if (!RegisterHotKey(_notifyWnd, keyCombination, mods, vk)) {
        CLOG(L"Failed to register hotkey [%d]\n"
            L"Mods: %d, VK: %d", keyCombination, GetLastError(),
            mods, vk);
        return;
    }

    CLOG(L"Registered new keyboard-based hotkey: %d", keyCombination);
}

void HotkeyManager::Unregister(int keyCombination) {
    CLOG(L"Unregistering hotkey combination: %d", keyCombination);

    if (_keyCombinations.count(keyCombination) <= 0) {
        QCLOG(L"Hotkey combination [%d] was not previously registered",
            keyCombination);
        return;
    }

    _keyCombinations.erase(keyCombination);
    if ((keyCombination >> 20) == 0) {
        /* This hotkey isn't mouse-based; unregister with Windows */
        if (!UnregisterHotKey(_notifyWnd, keyCombination)) {
            CLOG(L"Failed to unregister hotkey: %d", keyCombination);
            return;
        }
    }
}

int HotkeyManager::Modifiers() {
    int mods = 0;
    mods += (GetKeyState(VK_MENU) & 0x8000) << 1;
    mods += (GetKeyState(VK_CONTROL) & 0x8000) << 2;
    mods += (GetKeyState(VK_SHIFT) & 0x8000) << 3;
    mods += (GetKeyState(VK_LWIN) & 0x8000) << 4;
    mods += (GetKeyState(VK_RWIN) & 0x8000) << 4;
    return mods;
}

LRESULT CALLBACK
HotkeyManager::KeyProc(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode >= 0) {
        if (wParam == WM_KEYUP) {
            KBDLLHOOKSTRUCT *kbInfo = (KBDLLHOOKSTRUCT*) lParam;
            if ((kbInfo->vkCode == VK_LWIN || kbInfo->vkCode == VK_RWIN)
                && _fixWin) {
                /* WIN+Mouse combination used; we need to prevent the
                 * system from only seeing a WIN keypress (and usually
                 * popping up the start menu).  We simulate WIN+VK_NONAME. */

                INPUT input = { 0 };
                input.type = INPUT_KEYBOARD;

                input.ki.wVk = VK_NONAME;
                input.ki.wScan = 0;
                input.ki.dwFlags = 0;
                input.ki.time = 1;
                input.ki.dwExtraInfo = GetMessageExtraInfo();

                /* key down: */
                SendInput(1, &input, sizeof(INPUT));

                input.ki.dwFlags = KEYEVENTF_KEYUP;
                /* key up: */
                SendInput(1, &input, sizeof(INPUT));

                _fixWin = false;
            }
        }
    }

    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

LRESULT CALLBACK
HotkeyManager::MouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode >= 0) {
        int mouseState = 0;
        MSLLHOOKSTRUCT *msInfo;

        switch (wParam) {

            case WM_LBUTTONDOWN:
                mouseState += VK_LBUTTON;
                break;

            case WM_MBUTTONDOWN:
                mouseState += VK_MBUTTON;
                break;

            case WM_RBUTTONDOWN:
                mouseState += VK_RBUTTON;
                break;

            case WM_XBUTTONDOWN: {
                msInfo = (MSLLHOOKSTRUCT*) lParam;

                int button = msInfo->mouseData >> 16 & 0xFFFF;
                if (button == 1)
                    mouseState += HKM_MOUSE_XB1;
                else if (button == 2)
                    mouseState += HKM_MOUSE_XB2;

                break;
            }

            case WM_MOUSEWHEEL: {
                msInfo = (MSLLHOOKSTRUCT*) lParam;

                if ((int) msInfo->mouseData > 0) {
                    mouseState += HKM_MOUSE_WHUP;
                } else {
                    mouseState += HKM_MOUSE_WHDN;
                }

                break;
            }
        }

        if (mouseState > 0) {
            mouseState += Modifiers();

            if (_keyCombinations.count(mouseState) > 0) {
                PostMessage(_notifyWnd, WM_HOTKEY,
                    mouseState, mouseState & 0xF0000);

                if (mouseState & HKM_MOD_WIN) {
                    _fixWin = true; /* enable fix right before WIN goes up */
                }

                return 1; /* processed the message; eat it */
            }
        }
    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

LRESULT CALLBACK
HotkeyManager::LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
    return HotkeyManager::Instance()->MouseProc(nCode, wParam, lParam);
}

LRESULT CALLBACK
HotkeyManager::LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
    return HotkeyManager::Instance()->KeyProc(nCode, wParam, lParam);
}<|endoftext|>


<commit_before>#include "VolumeOSD.h"

#include <Shlwapi.h>
#include <string>

#include "..\HotkeyInfo.h"
#include "..\Monitor.h"
#include "..\Skin.h"
#include "..\Slider\VolumeSlider.h"

#define MENU_SETTINGS 0
#define MENU_MIXER 1
#define MENU_EXIT 2
#define MENU_DEVICE 0xF000

VolumeOSD::VolumeOSD() :
OSD(L"3RVX-VolumeDispatcher"),
_mWnd(L"3RVX-MasterVolumeOSD", L"3RVX-MasterVolumeOSD"),
_muteWnd(L"3RVX-MasterMuteOSD", L"3RVX-MasterMuteOSD")
{
    LoadSkin();
    Settings *settings = Settings::Instance();

    /* Start the volume controller */
    _volumeCtrl = new CoreAudio(_hWnd);
    std::wstring device = settings->AudioDeviceID();
    _volumeCtrl->Init(device);
    _selectedDesc = _volumeCtrl->DeviceDesc();

    /* Create the slider */
    _volumeSlider = new VolumeSlider(*_volumeCtrl);

    /* Set up context menu */
    if (settings->NotifyIconEnabled()) {
        _menu = CreatePopupMenu();
        _deviceMenu = CreatePopupMenu();

        InsertMenu(_menu, -1, MF_ENABLED, MENU_SETTINGS, L"Settings");
        InsertMenu(_menu, -1, MF_POPUP, UINT(_deviceMenu), L"Audio Device");
        InsertMenu(_menu, -1, MF_ENABLED, MENU_MIXER, L"Mixer");
        InsertMenu(_menu, -1, MF_ENABLED, MENU_EXIT, L"Exit");

        _menuFlags = TPM_RIGHTBUTTON;
        if (GetSystemMetrics(SM_MENUDROPALIGNMENT) != 0) {
            _menuFlags |= TPM_RIGHTALIGN;
        } else {
            _menuFlags |= TPM_LEFTALIGN;
        }

        UpdateDeviceMenu();
    }

    FadeOut *fOut = new FadeOut();
    _mWnd.HideAnimation(fOut);
    _mWnd.VisibleDuration(settings->HideDelay());
    _muteWnd.HideAnimation(fOut);
    _muteWnd.VisibleDuration(settings->HideDelay());

    UpdateIcon();
    float v = _volumeCtrl->Volume();
    MeterLevels(v);
    _volumeSlider->MeterLevels(v);

    /* TODO: check whether we should show the OSD on startup or not. If so, post
     * a MSG_VOL_CHNG so that the volume level (or mute) is displayed: */
    SendMessage(_hWnd, MSG_VOL_CHNG, NULL, NULL);
}

VolumeOSD::~VolumeOSD() {

    /* DestroyIcon() */
}

void VolumeOSD::UpdateDeviceMenu() {
    /* Remove any devices currently in the menu first */
    for (unsigned int i = 0; i < _deviceList.size(); ++i) {
        RemoveMenu(_deviceMenu, 0, MF_BYPOSITION);
    }
    _deviceList.clear();

    std::list<VolumeController::DeviceInfo> devices
        = _volumeCtrl->ListDevices();
    std::wstring currentDeviceId = _volumeCtrl->DeviceId();

    int menuItem = MENU_DEVICE;
    for (VolumeController::DeviceInfo device : devices) {
        unsigned int flags = MF_ENABLED;
        if (currentDeviceId == device.id) {
            flags |= MF_CHECKED;
        }

        InsertMenu(_deviceMenu, -1, flags, menuItem++, device.name.c_str());
        _deviceList.push_back(device);
    }
}

void VolumeOSD::LoadSkin() {
    Skin *skin = Settings::Instance()->CurrentSkin();

    Gdiplus::Bitmap *bg = skin->OSDBgImg("volume");
    _mWnd.BackgroundImage(bg);

    std::list<Meter*> meters = skin->VolumeMeters();
    for (Meter *m : meters) {
        _mWnd.AddMeter(m);
    }

    /* Default volume increment */
    _defaultIncrement = (float) (10000 / skin->DefaultVolumeUnits()) / 10000.0f;
    CLOG(L"Default volume increment: %f", _defaultIncrement);

    HMONITOR monitor = Monitor::Primary();

    _mWnd.Update();
    PositionWindow(monitor, _mWnd);

    _muteBg = skin->OSDBgImg("mute");
    _muteWnd.BackgroundImage(_muteBg);
    _muteWnd.Update();
    PositionWindow(monitor, _muteWnd);

    /* Set up notification icon */
    _iconImages = skin->Iconset("volume");
    if (_iconImages.size() > 0) {
        _icon = new NotifyIcon(_hWnd, L"3RVX", _iconImages[0]);
    }
}

void VolumeOSD::MeterLevels(float level) {
    _mWnd.MeterLevels(level);
    _mWnd.Update();
}

void VolumeOSD::Hide() {
    _mWnd.Hide(false);
    _muteWnd.Hide(false);
}

void VolumeOSD::HideIcon() {
    delete _icon;
}

void VolumeOSD::UpdateIcon() {
    UpdateIconImage();
    UpdateIconTip();
}

void VolumeOSD::UpdateIconImage() {
    if (_icon == NULL) {
        return;
    }

    int icon = 0;
    if (_volumeCtrl->Muted() == false) {
        int vUnits = _iconImages.size() - 1;
        icon = (int) ceil(_volumeCtrl->Volume() * vUnits);
    }

    if (icon != _lastIcon) {
        _icon->UpdateIcon(_iconImages[icon]);
        _lastIcon = icon;
    }
}

void VolumeOSD::UpdateIconTip() {
    if (_icon == NULL) {
        return;
    }

    if (_volumeCtrl->Muted()) {
        _icon->UpdateToolTip(_selectedDesc + L": Muted");
    } else {
        float v = _volumeCtrl->Volume();
        std::wstring perc = std::to_wstring((int) (v * 100.0f));
        std::wstring level = _selectedDesc + L": " + perc + L"%";
        _icon->UpdateToolTip(level);
    }
}

void VolumeOSD::UnMute() {
    if (_volumeCtrl->Muted() == true) {
        _volumeCtrl->Muted(false);
    }
}

void VolumeOSD::ProcessHotkeys(HotkeyInfo &hki) {
    float currentVol = _volumeCtrl->Volume();
    switch (hki.action) {
    case HotkeyInfo::IncreaseVolume:
        UnMute();
        _volumeCtrl->Volume(currentVol + _defaultIncrement);
        SendMessage(_hWnd, MSG_VOL_CHNG, NULL, NULL);
        break;

    case HotkeyInfo::DecreaseVolume:
        UnMute();
        _volumeCtrl->Volume(currentVol - _defaultIncrement - 0.0001f);
        SendMessage(_hWnd, MSG_VOL_CHNG, NULL, NULL);
        break;

    case HotkeyInfo::Mute:
        _volumeCtrl->ToggleMute();
        break;
    }
}

LRESULT
VolumeOSD::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    if (message == MSG_VOL_CHNG) {
        float v = _volumeCtrl->Volume();

        _volumeSlider->MeterLevels(v);

        if (_volumeSlider->Visible() == false) {
            if (_volumeCtrl->Muted() || v == 0.0f) {
                _muteWnd.Show();
                _mWnd.Hide(false);
            } else {
                MeterLevels(v);
                _mWnd.Show();
                _muteWnd.Hide(false);
            }
            HideOthers(Volume);
        }

        UpdateIcon();
    } else if (message == MSG_VOL_DEVCHNG) {
        CLOG(L"Volume device change detected.");
        if (_selectedDevice == L"") {
            _volumeCtrl->SelectDefaultDevice();
        } else {
            HRESULT hr = _volumeCtrl->SelectDevice(_selectedDevice);
            if (FAILED(hr)) {
                _volumeCtrl->SelectDefaultDevice();
            }
        }
        _selectedDesc = _volumeCtrl->DeviceDesc();
        UpdateDeviceMenu();
    } else if (message == MSG_NOTIFYICON) {
        if (lParam == WM_LBUTTONUP) {
            _volumeSlider->Show();
        } else if (lParam == WM_RBUTTONUP) {
            POINT p;
            GetCursorPos(&p);
            SetForegroundWindow(hWnd);
            TrackPopupMenuEx(_menu, _menuFlags, p.x, p.y, _hWnd, NULL);
            PostMessage(hWnd, WM_NULL, 0, 0);
        }
    } else if (message == WM_COMMAND) {
        int menuItem = LOWORD(wParam);
        switch (menuItem) {
        case MENU_SETTINGS:
            Settings::LaunchSettingsApp();
            break;

        case MENU_MIXER: {
            CLOG(L"Menu: Mixer");
            HINSTANCE code = ShellExecute(NULL, L"open", L"sndvol",
                NULL, NULL, SW_SHOWNORMAL);
            break;
        }

        case MENU_EXIT:
            CLOG(L"Menu: Exit: %d", (int) _masterWnd);
            SendMessage(_masterWnd, WM_CLOSE, NULL, NULL);
            break;
        }

        /* Device menu items */
        if ((menuItem & MENU_DEVICE) > 0) {
            int device = menuItem & 0x0FFF;
            VolumeController::DeviceInfo selectedDev = _deviceList[device];
            if (selectedDev.id != _volumeCtrl->DeviceId()) {
                /* A different device has been selected */
                CLOG(L"Changing to volume device: %s",
                    selectedDev.name.c_str());
                _volumeCtrl->SelectDevice(selectedDev.id);
                UpdateDeviceMenu();
            }
        }
    }

    return DefWindowProc(hWnd, message, wParam, lParam);
}<commit_msg>Only update the device menu if it exists<commit_after>#include "VolumeOSD.h"

#include <Shlwapi.h>
#include <string>

#include "..\HotkeyInfo.h"
#include "..\Monitor.h"
#include "..\Skin.h"
#include "..\Slider\VolumeSlider.h"

#define MENU_SETTINGS 0
#define MENU_MIXER 1
#define MENU_EXIT 2
#define MENU_DEVICE 0xF000

VolumeOSD::VolumeOSD() :
OSD(L"3RVX-VolumeDispatcher"),
_mWnd(L"3RVX-MasterVolumeOSD", L"3RVX-MasterVolumeOSD"),
_muteWnd(L"3RVX-MasterMuteOSD", L"3RVX-MasterMuteOSD")
{
    LoadSkin();
    Settings *settings = Settings::Instance();

    /* Start the volume controller */
    _volumeCtrl = new CoreAudio(_hWnd);
    std::wstring device = settings->AudioDeviceID();
    _volumeCtrl->Init(device);
    _selectedDesc = _volumeCtrl->DeviceDesc();

    /* Create the slider */
    _volumeSlider = new VolumeSlider(*_volumeCtrl);

    /* Set up context menu */
    if (settings->NotifyIconEnabled()) {
        _menu = CreatePopupMenu();
        _deviceMenu = CreatePopupMenu();

        InsertMenu(_menu, -1, MF_ENABLED, MENU_SETTINGS, L"Settings");
        InsertMenu(_menu, -1, MF_POPUP, UINT(_deviceMenu), L"Audio Device");
        InsertMenu(_menu, -1, MF_ENABLED, MENU_MIXER, L"Mixer");
        InsertMenu(_menu, -1, MF_ENABLED, MENU_EXIT, L"Exit");

        _menuFlags = TPM_RIGHTBUTTON;
        if (GetSystemMetrics(SM_MENUDROPALIGNMENT) != 0) {
            _menuFlags |= TPM_RIGHTALIGN;
        } else {
            _menuFlags |= TPM_LEFTALIGN;
        }

        UpdateDeviceMenu();
    }

    FadeOut *fOut = new FadeOut();
    _mWnd.HideAnimation(fOut);
    _mWnd.VisibleDuration(settings->HideDelay());
    _muteWnd.HideAnimation(fOut);
    _muteWnd.VisibleDuration(settings->HideDelay());

    UpdateIcon();
    float v = _volumeCtrl->Volume();
    MeterLevels(v);
    _volumeSlider->MeterLevels(v);

    /* TODO: check whether we should show the OSD on startup or not. If so, post
     * a MSG_VOL_CHNG so that the volume level (or mute) is displayed: */
    SendMessage(_hWnd, MSG_VOL_CHNG, NULL, NULL);
}

VolumeOSD::~VolumeOSD() {

    /* DestroyIcon() */
}

void VolumeOSD::UpdateDeviceMenu() {
    if (_menu == NULL || _deviceMenu == NULL) {
        return;
    }

    /* Remove any devices currently in the menu first */
    for (unsigned int i = 0; i < _deviceList.size(); ++i) {
        RemoveMenu(_deviceMenu, 0, MF_BYPOSITION);
    }
    _deviceList.clear();

    std::list<VolumeController::DeviceInfo> devices
        = _volumeCtrl->ListDevices();
    std::wstring currentDeviceId = _volumeCtrl->DeviceId();

    int menuItem = MENU_DEVICE;
    for (VolumeController::DeviceInfo device : devices) {
        unsigned int flags = MF_ENABLED;
        if (currentDeviceId == device.id) {
            flags |= MF_CHECKED;
        }

        InsertMenu(_deviceMenu, -1, flags, menuItem++, device.name.c_str());
        _deviceList.push_back(device);
    }
}

void VolumeOSD::LoadSkin() {
    Skin *skin = Settings::Instance()->CurrentSkin();

    Gdiplus::Bitmap *bg = skin->OSDBgImg("volume");
    _mWnd.BackgroundImage(bg);

    std::list<Meter*> meters = skin->VolumeMeters();
    for (Meter *m : meters) {
        _mWnd.AddMeter(m);
    }

    /* Default volume increment */
    _defaultIncrement = (float) (10000 / skin->DefaultVolumeUnits()) / 10000.0f;
    CLOG(L"Default volume increment: %f", _defaultIncrement);

    HMONITOR monitor = Monitor::Primary();

    _mWnd.Update();
    PositionWindow(monitor, _mWnd);

    _muteBg = skin->OSDBgImg("mute");
    _muteWnd.BackgroundImage(_muteBg);
    _muteWnd.Update();
    PositionWindow(monitor, _muteWnd);

    /* Set up notification icon */
    _iconImages = skin->Iconset("volume");
    if (_iconImages.size() > 0) {
        _icon = new NotifyIcon(_hWnd, L"3RVX", _iconImages[0]);
    }
}

void VolumeOSD::MeterLevels(float level) {
    _mWnd.MeterLevels(level);
    _mWnd.Update();
}

void VolumeOSD::Hide() {
    _mWnd.Hide(false);
    _muteWnd.Hide(false);
}

void VolumeOSD::HideIcon() {
    delete _icon;
}

void VolumeOSD::UpdateIcon() {
    UpdateIconImage();
    UpdateIconTip();
}

void VolumeOSD::UpdateIconImage() {
    if (_icon == NULL) {
        return;
    }

    int icon = 0;
    if (_volumeCtrl->Muted() == false) {
        int vUnits = _iconImages.size() - 1;
        icon = (int) ceil(_volumeCtrl->Volume() * vUnits);
    }

    if (icon != _lastIcon) {
        _icon->UpdateIcon(_iconImages[icon]);
        _lastIcon = icon;
    }
}

void VolumeOSD::UpdateIconTip() {
    if (_icon == NULL) {
        return;
    }

    if (_volumeCtrl->Muted()) {
        _icon->UpdateToolTip(_selectedDesc + L": Muted");
    } else {
        float v = _volumeCtrl->Volume();
        std::wstring perc = std::to_wstring((int) (v * 100.0f));
        std::wstring level = _selectedDesc + L": " + perc + L"%";
        _icon->UpdateToolTip(level);
    }
}

void VolumeOSD::UnMute() {
    if (_volumeCtrl->Muted() == true) {
        _volumeCtrl->Muted(false);
    }
}

void VolumeOSD::ProcessHotkeys(HotkeyInfo &hki) {
    float currentVol = _volumeCtrl->Volume();
    switch (hki.action) {
    case HotkeyInfo::IncreaseVolume:
        UnMute();
        _volumeCtrl->Volume(currentVol + _defaultIncrement);
        SendMessage(_hWnd, MSG_VOL_CHNG, NULL, NULL);
        break;

    case HotkeyInfo::DecreaseVolume:
        UnMute();
        _volumeCtrl->Volume(currentVol - _defaultIncrement - 0.0001f);
        SendMessage(_hWnd, MSG_VOL_CHNG, NULL, NULL);
        break;

    case HotkeyInfo::Mute:
        _volumeCtrl->ToggleMute();
        break;
    }
}

LRESULT
VolumeOSD::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    if (message == MSG_VOL_CHNG) {
        float v = _volumeCtrl->Volume();

        _volumeSlider->MeterLevels(v);

        if (_volumeSlider->Visible() == false) {
            if (_volumeCtrl->Muted() || v == 0.0f) {
                _muteWnd.Show();
                _mWnd.Hide(false);
            } else {
                MeterLevels(v);
                _mWnd.Show();
                _muteWnd.Hide(false);
            }
            HideOthers(Volume);
        }

        UpdateIcon();
    } else if (message == MSG_VOL_DEVCHNG) {
        CLOG(L"Volume device change detected.");
        if (_selectedDevice == L"") {
            _volumeCtrl->SelectDefaultDevice();
        } else {
            HRESULT hr = _volumeCtrl->SelectDevice(_selectedDevice);
            if (FAILED(hr)) {
                _volumeCtrl->SelectDefaultDevice();
            }
        }
        _selectedDesc = _volumeCtrl->DeviceDesc();
        UpdateDeviceMenu();
    } else if (message == MSG_NOTIFYICON) {
        if (lParam == WM_LBUTTONUP) {
            _volumeSlider->Show();
        } else if (lParam == WM_RBUTTONUP) {
            POINT p;
            GetCursorPos(&p);
            SetForegroundWindow(hWnd);
            TrackPopupMenuEx(_menu, _menuFlags, p.x, p.y, _hWnd, NULL);
            PostMessage(hWnd, WM_NULL, 0, 0);
        }
    } else if (message == WM_COMMAND) {
        int menuItem = LOWORD(wParam);
        switch (menuItem) {
        case MENU_SETTINGS:
            Settings::LaunchSettingsApp();
            break;

        case MENU_MIXER: {
            CLOG(L"Menu: Mixer");
            HINSTANCE code = ShellExecute(NULL, L"open", L"sndvol",
                NULL, NULL, SW_SHOWNORMAL);
            break;
        }

        case MENU_EXIT:
            CLOG(L"Menu: Exit: %d", (int) _masterWnd);
            SendMessage(_masterWnd, WM_CLOSE, NULL, NULL);
            break;
        }

        /* Device menu items */
        if ((menuItem & MENU_DEVICE) > 0) {
            int device = menuItem & 0x0FFF;
            VolumeController::DeviceInfo selectedDev = _deviceList[device];
            if (selectedDev.id != _volumeCtrl->DeviceId()) {
                /* A different device has been selected */
                CLOG(L"Changing to volume device: %s",
                    selectedDev.name.c_str());
                _volumeCtrl->SelectDevice(selectedDev.id);
                UpdateDeviceMenu();
            }
        }
    }

    return DefWindowProc(hWnd, message, wParam, lParam);
}<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* bzflag special common - 1st one */
#include "common.h"

#include <iostream>

#include "ActionBinding.h"
#include "CommandManager.h"
#include "KeyManager.h"

// initialize the singleton
template <>
ActionBinding* Singleton<ActionBinding>::_instance = (ActionBinding*)0;

ActionBinding::ActionBinding() {
  wayToBindActions.insert(std::make_pair(std::string("quit"), press));
  wayToBindActions.insert(std::make_pair(std::string("fire"), both));
  wayToBindActions.insert(std::make_pair(std::string("drop"), press));
  wayToBindActions.insert(std::make_pair(std::string("identify"), press));
  wayToBindActions.insert(std::make_pair(std::string("jump"), press));
  wayToBindActions.insert(std::make_pair(std::string("send all"), press));
  wayToBindActions.insert(std::make_pair(std::string("send team"), press));
  wayToBindActions.insert(std::make_pair(std::string("send nemesis"), press));
  wayToBindActions.insert(std::make_pair(std::string("send recipient"), press));
	wayToBindActions.insert(std::make_pair(std::string("send admin"), press));
  wayToBindActions.insert(std::make_pair(std::string("toggle displayScore"), press));
  wayToBindActions.insert(std::make_pair(std::string("toggle displayBinoculars"), press));
  wayToBindActions.insert(std::make_pair(std::string("pause"), press));
  wayToBindActions.insert(std::make_pair(std::string("fullscreen"), press));
  wayToBindActions.insert(std::make_pair(std::string("iconify"), press));
#ifdef SNAPPING
  wayToBindActions.insert(std::make_pair(std::string("screenshot"), press));
#endif
  wayToBindActions.insert(std::make_pair(std::string("time backward"), press));
  wayToBindActions.insert(std::make_pair(std::string("time forward"), press));
  wayToBindActions.insert(std::make_pair(std::string("toggleFlags radar"), press));
  wayToBindActions.insert(std::make_pair(std::string("toggleFlags main"), press));
  wayToBindActions.insert(std::make_pair(std::string("silence"), press));
  wayToBindActions.insert(std::make_pair(std::string("toggle displayLabels"), press));
  wayToBindActions.insert(std::make_pair(std::string("destruct"), press));

  // Movement keys
  wayToBindActions.insert(std::make_pair(std::string("turn left"), both));
  wayToBindActions.insert(std::make_pair(std::string("turn right"), both));
  wayToBindActions.insert(std::make_pair(std::string("drive forward"), both));
  wayToBindActions.insert(std::make_pair(std::string("drive reverse"), both));
  // End movement keys

  wayToBindActions.insert(std::make_pair(std::string("roam cycle subject backward"),
					 press));
  wayToBindActions.insert(std::make_pair(std::string("roam cycle subject forward"), press));
  wayToBindActions.insert(std::make_pair(std::string("roam cycle type forward"), press));
  wayToBindActions.insert(std::make_pair(std::string("roam zoom in"), both));
  wayToBindActions.insert(std::make_pair(std::string("roam zoom out"), both));
  wayToBindActions.insert(std::make_pair(std::string("roam zoom normal"), both));
  wayToBindActions.insert(std::make_pair(std::string("servercommand"), press));
  wayToBindActions.insert(std::make_pair(std::string("toggle displayFlagHelp"), press));
  wayToBindActions.insert(std::make_pair(std::string("scrollpanel up"), press));
  wayToBindActions.insert(std::make_pair(std::string("scrollpanel down"), press));
  wayToBindActions.insert(std::make_pair(std::string("set displayRadarRange 0.25"), press));
  wayToBindActions.insert(std::make_pair(std::string("set displayRadarRange 0.5"), press));
  wayToBindActions.insert(std::make_pair(std::string("set displayRadarRange 1.0"), press));
  wayToBindActions.insert(std::make_pair(std::string("toggle slowKeyboard"), press));
  wayToBindActions.insert(std::make_pair(std::string("hunt"), press));
  wayToBindActions.insert(std::make_pair(std::string("restart"), release));
  wayToBindActions.insert(std::make_pair(std::string("autopilot"), press));

  defaultBinding.insert(std::make_pair(std::string("F12"), std::string("quit")));
  defaultBinding.insert(std::make_pair(std::string("Left Mouse"), std::string("fire")));
  defaultBinding.insert(std::make_pair(std::string("Enter"), std::string("fire")));
  defaultBinding.insert(std::make_pair(std::string("Middle Mouse"), std::string("drop")));
  defaultBinding.insert(std::make_pair(std::string("Space"), std::string("drop")));
  defaultBinding.insert(std::make_pair(std::string("Right Mouse"), std::string("identify")));
  defaultBinding.insert(std::make_pair(std::string("I"), std::string("identify")));
  defaultBinding.insert(std::make_pair(std::string("Tab"), std::string("jump")));
  defaultBinding.insert(std::make_pair(std::string("N"), std::string("send all")));
  defaultBinding.insert(std::make_pair(std::string("M"), std::string("send team")));
  defaultBinding.insert(std::make_pair(std::string(","), std::string("send nemesis")));
  defaultBinding.insert(std::make_pair(std::string("."), std::string("send recipient")));
	defaultBinding.insert(std::make_pair(std::string("Z"), std::string("send admin")));
  defaultBinding.insert(std::make_pair(std::string("S"), std::string("toggle displayScore")));
  defaultBinding.insert(std::make_pair(std::string("B"), std::string("toggle displayBinoculars")));
  defaultBinding.insert(std::make_pair(std::string("Pause"), std::string("pause")));
  defaultBinding.insert(std::make_pair(std::string("P"), std::string("pause")));
  defaultBinding.insert(std::make_pair(std::string("F1"),
				       std::string("fullscreen")));
  defaultBinding.insert(std::make_pair(std::string("F4"), std::string("iconify")));
#ifdef SNAPPING
  defaultBinding.insert(std::make_pair(std::string("F5"), std::string("screenshot")));
#endif
  defaultBinding.insert(std::make_pair(std::string("-"), std::string("time backward")));
  defaultBinding.insert(std::make_pair(std::string("="), std::string("time forward")));
  defaultBinding.insert(std::make_pair(std::string("H"), std::string("toggleFlags radar")));
  defaultBinding.insert(std::make_pair(std::string("J"), std::string("toggleFlags main")));
  defaultBinding.insert(std::make_pair(std::string("K"), std::string("silence")));
  defaultBinding.insert(std::make_pair(std::string("L"), std::string("toggle displayLabels")));
  defaultBinding.insert(std::make_pair(std::string("Delete"), std::string("destruct")));

  // Default movement keys
  defaultBinding.insert(std::make_pair(std::string("Left Arrow"),
				       std::string("turn left")));
  defaultBinding.insert(std::make_pair(std::string("Right Arrow"),
				       std::string("turn right")));
  defaultBinding.insert(std::make_pair(std::string("Up Arrow"),
				       std::string("drive forward")));
  defaultBinding.insert(std::make_pair(std::string("Down Arrow"),
				       std::string("drive reverse")));
  // End default movement keys

  defaultBinding.insert(std::make_pair(std::string("F6"), std::string("roam cycle subject backward")));
  defaultBinding.insert(std::make_pair(std::string("F7"), std::string("roam cycle subject forward")));
  defaultBinding.insert(std::make_pair(std::string("F8"), std::string("roam cycle type forward")));
  defaultBinding.insert(std::make_pair(std::string("F9"), std::string("roam zoom in")));
  defaultBinding.insert(std::make_pair(std::string("F10"), std::string("roam zoom out")));
  defaultBinding.insert(std::make_pair(std::string("F11"), std::string("roam zoom normal")));
  defaultBinding.insert(std::make_pair(std::string("O"), std::string("servercommand")));
  defaultBinding.insert(std::make_pair(std::string("F"), std::string("toggle displayFlagHelp")));
  defaultBinding.insert(std::make_pair(std::string("Page Up"), std::string("scrollpanel up")));
  defaultBinding.insert(std::make_pair(std::string("Page Down"), std::string("scrollpanel down")));
  defaultBinding.insert(std::make_pair(std::string("1"), std::string("set displayRadarRange 0.25")));
  defaultBinding.insert(std::make_pair(std::string("2"), std::string("set displayRadarRange 0.5")));
  defaultBinding.insert(std::make_pair(std::string("3"), std::string("set displayRadarRange 1.0")));
  defaultBinding.insert(std::make_pair(std::string("A"), std::string("toggle slowKeyboard")));
  defaultBinding.insert(std::make_pair(std::string("U"), std::string("hunt")));
  defaultBinding.insert(std::make_pair(std::string("Right Mouse"), std::string("restart")));
  defaultBinding.insert(std::make_pair(std::string("I"), std::string("restart")));
  defaultBinding.insert(std::make_pair(std::string("9"), std::string("autopilot")));
}

void ActionBinding::resetBindings() {
  BindingTable::const_iterator index;

  for (index = bindingTable.begin();
       index != bindingTable.end();
       ++index)
    unbind(index->second, index->first);

  bindingTable = defaultBinding;

  for (index = bindingTable.begin();
       index != bindingTable.end();
       ++index)
    bind(index->second, index->first);
}

void ActionBinding::getFromBindings() {
  bindingTable.clear();
  KEYMGR.iterate(&onScanCB, this);
}

void ActionBinding::onScanCB(const std::string& name, bool,
			     const std::string& cmd, void*)
{
  ActionBinding::instance().associate(name, cmd, false);
}

void ActionBinding::associate(std::string key,
			      std::string action,
			      bool        keyBind) {
  BindingTable::iterator index, next;
  if (!wayToBindActions.count(action))
    return;
  PressStatusBind newStatusBind = wayToBindActions[action];
  for (index = bindingTable.lower_bound( key ); index != bindingTable.upper_bound( key ); index = next) {
    next = index;
    ++next;
    if (newStatusBind == both) {
      if (keyBind)
	unbind(index->second, key);
      bindingTable.erase(index);
    } else if (newStatusBind == press) {
      if (wayToBindActions[index->second] != release) {
	if (keyBind)
	  unbind(index->second, key);
	bindingTable.erase(index);
      }
    } else {
      if (wayToBindActions[index->second] != press) {
	if (keyBind)
	  unbind(index->second, key);
	bindingTable.erase(index);
      }
    }
  }
  bindingTable.insert(std::make_pair(key, action));
  if (keyBind)
    bind(action, key);
};

void ActionBinding::deassociate(std::string action) {
  BindingTable::iterator index, next;
  for (index = bindingTable.begin();
       index != bindingTable.end();
       index = next) {
    next = index;
    ++next;
    if (index->second == action) {
      unbind(action, index->first);
      bindingTable.erase(index);
    }
  }
};

void ActionBinding::bind(std::string action, std::string key) {
  PressStatusBind statusBind = wayToBindActions[action];
  std::string command;
  if (statusBind == press || statusBind == both) {
    command = "bind \"" + key + "\" down \"" + action + "\"";
    CMDMGR.run(command);
  };
  if (statusBind == release || statusBind == both) {
    command = "bind \"" + key + "\" up \"" + action + "\"";
    CMDMGR.run(command);
  };
}

void ActionBinding::unbind(std::string action, std::string key) {
  PressStatusBind statusBind = wayToBindActions[action];
  std::string command;
  if (statusBind == press || statusBind == both) {
    command = "unbind \"" + key + "\" down";
    CMDMGR.run(command);
  };
  if (statusBind == release || statusBind == both) {
    command = "unbind \"" + key + "\" up";
    CMDMGR.run(command);
  };
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>ws<commit_after>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* bzflag special common - 1st one */
#include "common.h"

#include <iostream>

#include "ActionBinding.h"
#include "CommandManager.h"
#include "KeyManager.h"

// initialize the singleton
template <>
ActionBinding* Singleton<ActionBinding>::_instance = (ActionBinding*)0;

ActionBinding::ActionBinding() {
  wayToBindActions.insert(std::make_pair(std::string("quit"), press));
  wayToBindActions.insert(std::make_pair(std::string("fire"), both));
  wayToBindActions.insert(std::make_pair(std::string("drop"), press));
  wayToBindActions.insert(std::make_pair(std::string("identify"), press));
  wayToBindActions.insert(std::make_pair(std::string("jump"), press));
  wayToBindActions.insert(std::make_pair(std::string("send all"), press));
  wayToBindActions.insert(std::make_pair(std::string("send team"), press));
  wayToBindActions.insert(std::make_pair(std::string("send nemesis"), press));
  wayToBindActions.insert(std::make_pair(std::string("send recipient"), press));
  wayToBindActions.insert(std::make_pair(std::string("send admin"), press));
  wayToBindActions.insert(std::make_pair(std::string("toggle displayScore"), press));
  wayToBindActions.insert(std::make_pair(std::string("toggle displayBinoculars"), press));
  wayToBindActions.insert(std::make_pair(std::string("pause"), press));
  wayToBindActions.insert(std::make_pair(std::string("fullscreen"), press));
  wayToBindActions.insert(std::make_pair(std::string("iconify"), press));
#ifdef SNAPPING
  wayToBindActions.insert(std::make_pair(std::string("screenshot"), press));
#endif
  wayToBindActions.insert(std::make_pair(std::string("time backward"), press));
  wayToBindActions.insert(std::make_pair(std::string("time forward"), press));
  wayToBindActions.insert(std::make_pair(std::string("toggleFlags radar"), press));
  wayToBindActions.insert(std::make_pair(std::string("toggleFlags main"), press));
  wayToBindActions.insert(std::make_pair(std::string("silence"), press));
  wayToBindActions.insert(std::make_pair(std::string("toggle displayLabels"), press));
  wayToBindActions.insert(std::make_pair(std::string("destruct"), press));

  // Movement keys
  wayToBindActions.insert(std::make_pair(std::string("turn left"), both));
  wayToBindActions.insert(std::make_pair(std::string("turn right"), both));
  wayToBindActions.insert(std::make_pair(std::string("drive forward"), both));
  wayToBindActions.insert(std::make_pair(std::string("drive reverse"), both));
  // End movement keys

  wayToBindActions.insert(std::make_pair(std::string("roam cycle subject backward"),
					 press));
  wayToBindActions.insert(std::make_pair(std::string("roam cycle subject forward"), press));
  wayToBindActions.insert(std::make_pair(std::string("roam cycle type forward"), press));
  wayToBindActions.insert(std::make_pair(std::string("roam zoom in"), both));
  wayToBindActions.insert(std::make_pair(std::string("roam zoom out"), both));
  wayToBindActions.insert(std::make_pair(std::string("roam zoom normal"), both));
  wayToBindActions.insert(std::make_pair(std::string("servercommand"), press));
  wayToBindActions.insert(std::make_pair(std::string("toggle displayFlagHelp"), press));
  wayToBindActions.insert(std::make_pair(std::string("scrollpanel up"), press));
  wayToBindActions.insert(std::make_pair(std::string("scrollpanel down"), press));
  wayToBindActions.insert(std::make_pair(std::string("set displayRadarRange 0.25"), press));
  wayToBindActions.insert(std::make_pair(std::string("set displayRadarRange 0.5"), press));
  wayToBindActions.insert(std::make_pair(std::string("set displayRadarRange 1.0"), press));
  wayToBindActions.insert(std::make_pair(std::string("toggle slowKeyboard"), press));
  wayToBindActions.insert(std::make_pair(std::string("hunt"), press));
  wayToBindActions.insert(std::make_pair(std::string("restart"), release));
  wayToBindActions.insert(std::make_pair(std::string("autopilot"), press));

  defaultBinding.insert(std::make_pair(std::string("F12"), std::string("quit")));
  defaultBinding.insert(std::make_pair(std::string("Left Mouse"), std::string("fire")));
  defaultBinding.insert(std::make_pair(std::string("Enter"), std::string("fire")));
  defaultBinding.insert(std::make_pair(std::string("Middle Mouse"), std::string("drop")));
  defaultBinding.insert(std::make_pair(std::string("Space"), std::string("drop")));
  defaultBinding.insert(std::make_pair(std::string("Right Mouse"), std::string("identify")));
  defaultBinding.insert(std::make_pair(std::string("I"), std::string("identify")));
  defaultBinding.insert(std::make_pair(std::string("Tab"), std::string("jump")));
  defaultBinding.insert(std::make_pair(std::string("N"), std::string("send all")));
  defaultBinding.insert(std::make_pair(std::string("M"), std::string("send team")));
  defaultBinding.insert(std::make_pair(std::string(","), std::string("send nemesis")));
  defaultBinding.insert(std::make_pair(std::string("."), std::string("send recipient")));
  defaultBinding.insert(std::make_pair(std::string("Z"), std::string("send admin")));
  defaultBinding.insert(std::make_pair(std::string("S"), std::string("toggle displayScore")));
  defaultBinding.insert(std::make_pair(std::string("B"), std::string("toggle displayBinoculars")));
  defaultBinding.insert(std::make_pair(std::string("Pause"), std::string("pause")));
  defaultBinding.insert(std::make_pair(std::string("P"), std::string("pause")));
  defaultBinding.insert(std::make_pair(std::string("F1"),
				       std::string("fullscreen")));
  defaultBinding.insert(std::make_pair(std::string("F4"), std::string("iconify")));
#ifdef SNAPPING
  defaultBinding.insert(std::make_pair(std::string("F5"), std::string("screenshot")));
#endif
  defaultBinding.insert(std::make_pair(std::string("-"), std::string("time backward")));
  defaultBinding.insert(std::make_pair(std::string("="), std::string("time forward")));
  defaultBinding.insert(std::make_pair(std::string("H"), std::string("toggleFlags radar")));
  defaultBinding.insert(std::make_pair(std::string("J"), std::string("toggleFlags main")));
  defaultBinding.insert(std::make_pair(std::string("K"), std::string("silence")));
  defaultBinding.insert(std::make_pair(std::string("L"), std::string("toggle displayLabels")));
  defaultBinding.insert(std::make_pair(std::string("Delete"), std::string("destruct")));

  // Default movement keys
  defaultBinding.insert(std::make_pair(std::string("Left Arrow"),
				       std::string("turn left")));
  defaultBinding.insert(std::make_pair(std::string("Right Arrow"),
				       std::string("turn right")));
  defaultBinding.insert(std::make_pair(std::string("Up Arrow"),
				       std::string("drive forward")));
  defaultBinding.insert(std::make_pair(std::string("Down Arrow"),
				       std::string("drive reverse")));
  // End default movement keys

  defaultBinding.insert(std::make_pair(std::string("F6"), std::string("roam cycle subject backward")));
  defaultBinding.insert(std::make_pair(std::string("F7"), std::string("roam cycle subject forward")));
  defaultBinding.insert(std::make_pair(std::string("F8"), std::string("roam cycle type forward")));
  defaultBinding.insert(std::make_pair(std::string("F9"), std::string("roam zoom in")));
  defaultBinding.insert(std::make_pair(std::string("F10"), std::string("roam zoom out")));
  defaultBinding.insert(std::make_pair(std::string("F11"), std::string("roam zoom normal")));
  defaultBinding.insert(std::make_pair(std::string("O"), std::string("servercommand")));
  defaultBinding.insert(std::make_pair(std::string("F"), std::string("toggle displayFlagHelp")));
  defaultBinding.insert(std::make_pair(std::string("Page Up"), std::string("scrollpanel up")));
  defaultBinding.insert(std::make_pair(std::string("Page Down"), std::string("scrollpanel down")));
  defaultBinding.insert(std::make_pair(std::string("1"), std::string("set displayRadarRange 0.25")));
  defaultBinding.insert(std::make_pair(std::string("2"), std::string("set displayRadarRange 0.5")));
  defaultBinding.insert(std::make_pair(std::string("3"), std::string("set displayRadarRange 1.0")));
  defaultBinding.insert(std::make_pair(std::string("A"), std::string("toggle slowKeyboard")));
  defaultBinding.insert(std::make_pair(std::string("U"), std::string("hunt")));
  defaultBinding.insert(std::make_pair(std::string("Right Mouse"), std::string("restart")));
  defaultBinding.insert(std::make_pair(std::string("I"), std::string("restart")));
  defaultBinding.insert(std::make_pair(std::string("9"), std::string("autopilot")));
}

void ActionBinding::resetBindings() {
  BindingTable::const_iterator index;

  for (index = bindingTable.begin();
       index != bindingTable.end();
       ++index)
    unbind(index->second, index->first);

  bindingTable = defaultBinding;

  for (index = bindingTable.begin();
       index != bindingTable.end();
       ++index)
    bind(index->second, index->first);
}

void ActionBinding::getFromBindings() {
  bindingTable.clear();
  KEYMGR.iterate(&onScanCB, this);
}

void ActionBinding::onScanCB(const std::string& name, bool,
			     const std::string& cmd, void*)
{
  ActionBinding::instance().associate(name, cmd, false);
}

void ActionBinding::associate(std::string key,
			      std::string action,
			      bool        keyBind) {
  BindingTable::iterator index, next;
  if (!wayToBindActions.count(action))
    return;
  PressStatusBind newStatusBind = wayToBindActions[action];
  for (index = bindingTable.lower_bound( key ); index != bindingTable.upper_bound( key ); index = next) {
    next = index;
    ++next;
    if (newStatusBind == both) {
      if (keyBind)
	unbind(index->second, key);
      bindingTable.erase(index);
    } else if (newStatusBind == press) {
      if (wayToBindActions[index->second] != release) {
	if (keyBind)
	  unbind(index->second, key);
	bindingTable.erase(index);
      }
    } else {
      if (wayToBindActions[index->second] != press) {
	if (keyBind)
	  unbind(index->second, key);
	bindingTable.erase(index);
      }
    }
  }
  bindingTable.insert(std::make_pair(key, action));
  if (keyBind)
    bind(action, key);
};

void ActionBinding::deassociate(std::string action) {
  BindingTable::iterator index, next;
  for (index = bindingTable.begin();
       index != bindingTable.end();
       index = next) {
    next = index;
    ++next;
    if (index->second == action) {
      unbind(action, index->first);
      bindingTable.erase(index);
    }
  }
};

void ActionBinding::bind(std::string action, std::string key) {
  PressStatusBind statusBind = wayToBindActions[action];
  std::string command;
  if (statusBind == press || statusBind == both) {
    command = "bind \"" + key + "\" down \"" + action + "\"";
    CMDMGR.run(command);
  };
  if (statusBind == release || statusBind == both) {
    command = "bind \"" + key + "\" up \"" + action + "\"";
    CMDMGR.run(command);
  };
}

void ActionBinding::unbind(std::string action, std::string key) {
  PressStatusBind statusBind = wayToBindActions[action];
  std::string command;
  if (statusBind == press || statusBind == both) {
    command = "unbind \"" + key + "\" down";
    CMDMGR.run(command);
  };
  if (statusBind == release || statusBind == both) {
    command = "unbind \"" + key + "\" up";
    CMDMGR.run(command);
  };
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>#include "stdafx.h"

#include <graphics/dynamictexture.h>

#include "fogrenderer.h"
#include <temple/dll.h>
#include <common.h>

using namespace gfx;

#pragma pack(push, 1)
struct FogOfWarVertex {
	XMFLOAT3 pos;
	XMFLOAT2 uv;
};
#pragma pack(pop)

FogOfWarRenderer::FogOfWarRenderer(MdfMaterialFactory& mdfFactory, RenderingDevice& device)
	: mMdfFactory(mdfFactory),
	  mDevice(device),
	  mNumSubtilesX(temple::GetRef<uint32_t>(0x10820458)),
	  mNumSubtilesY(temple::GetRef<uint32_t>(0x10824490)) {

	mBlurredFogWidth = (mNumSubtilesX / 4) * 4 + 8;
	mBlurredFogHeight = (mNumSubtilesY / 4) * 4 + 8;

	mBlurredFogTexture = mDevice.CreateDynamicTexture(D3DFMT_A8, mBlurredFogWidth, mBlurredFogHeight);
	mBlurredFog.resize(mBlurredFogWidth * mBlurredFogHeight);

	auto vs = device.GetShaders().LoadVertexShader("fogofwar_vs");
	auto ps = device.GetShaders().LoadPixelShader("fogofwar_ps");
	BlendState blendState;
	blendState.blendEnable = true;
	blendState.srcBlend = D3DBLEND_SRCALPHA;
	blendState.destBlend = D3DBLEND_INVSRCALPHA;
	DepthStencilState depthStencilState;
	depthStencilState.depthEnable = false;
	RasterizerState rasterizerState;
	SamplerState samplerState;
	samplerState.addressU = D3DTADDRESS_CLAMP;
	samplerState.addressV = D3DTADDRESS_CLAMP;
	samplerState.magFilter = D3DTEXF_LINEAR;
	samplerState.minFilter = D3DTEXF_LINEAR;
	std::vector<MaterialSamplerBinding> samplers{
		MaterialSamplerBinding(mBlurredFogTexture, samplerState)
	};

	mMaterial = std::make_unique<Material>(blendState, depthStencilState, rasterizerState, samplers, vs, ps);

	uint16_t indices[6]{0, 2, 1, 2, 0, 3};
	mIndexBuffer = device.CreateIndexBuffer(indices);
	mVertexBuffer = device.CreateEmptyVertexBuffer(sizeof(FogOfWarVertex) * 4);

	mBufferBinding.AddBuffer(mVertexBuffer, 0, sizeof(FogOfWarVertex))
	              .AddElement(VertexElementType::Float3, VertexElementSemantic::Position)
	              .AddElement(VertexElementType::Float2, VertexElementSemantic::TexCoord);
}

struct FogBlurKernel {
	// 4 kernels (shifted by 0,1,2,3 pixels right), each has
	// 5 rows with 8 columns (for shift-compensation)
	uint8_t patterns[4][5][8]; // [xShift][y][x]
	FogBlurKernel() {
		memset(patterns, 0, sizeof(patterns));
	}

	static FogBlurKernel Create(uint8_t totalPatternValue);
};

void FogOfWarRenderer::Render() {
	static auto& sFoggingEnabled = temple::GetRef<uint32_t>(0x108254A0);
	if (!(sFoggingEnabled & 1)) {
		return;
	}

	// Reset the blurred buffer
	std::fill(mBlurredFog.begin(), mBlurredFog.end(), 0);

	static auto sOpaquePattern = FogBlurKernel::Create(0xFF);
	static auto sHalfTransparentPattern = FogBlurKernel::Create(0xA0);

	static auto& fogCheckData = temple::GetRef<uint8_t*>(0x108A5498);

	// Get [0,0] of the subtile data
	auto fogCheckSubtile = &fogCheckData[0];

	for (size_t y = 0; y < mNumSubtilesY; y++) {
		for (size_t x = 0; x < mNumSubtilesX; x++) {
			auto fogState = *fogCheckSubtile;

			// Bit 2 -> Currently in LoS of the party
			if (!(fogState & 2)) {
				uint8_t* patternSrc;
				// Bit 3 -> Explored
				if (fogState & 4) {
					patternSrc = &sHalfTransparentPattern.patterns[x & 3][0][0];
				} else {
					patternSrc = &sOpaquePattern.patterns[x & 3][0][0];
				}

				// Now we copy 5 rows of 2 dwords each, to apply
				// the filter-kernel to the blurred fog map
				for (auto row = 0; row < 5; ++row) {
					auto src = (uint64_t*) &patternSrc[row * 8];
					auto roundedDownX = (x / 4) * 4;
					auto dest = (uint64_t*) &mBlurredFog[(y + row) * mBlurredFogWidth + roundedDownX];
					// Due to how the kernel is layed out, the individual bytes in this 8-byte addition will never carry
					// over to the next higher byte, thus this is equivalent to 8 separate 1-byte additions
					*dest += *src;
				}
			}
			++fogCheckSubtile;
		}

		// Skips the last subtile of the row and the first of the next row
		// fogCheckSubtile += 2;

	}

	static auto& fogMinX = temple::GetRef<uint64_t>(0x10824468);
	static auto& fogMinY = temple::GetRef<uint64_t>(0x108EC4C8);

	auto mFogOriginX = (uint32_t) fogMinX;
	auto mFogOriginY = (uint32_t) fogMinY;

	mBlurredFogTexture->Update<uint8_t>({&mBlurredFog[0], mBlurredFog.size()});

	// Use only the relevant subportion of the texture
	auto umin = 2.5f / (float)mBlurredFogWidth;
	auto vmin = 2.5f / (float)mBlurredFogHeight;
	auto umax = mNumSubtilesX / (float)mBlurredFogWidth;
	auto vmax = mNumSubtilesY / (float)mBlurredFogHeight;

	FogOfWarVertex mVertices[4];
	mVertices[0].pos.x = (mFogOriginX * 3) * INCH_PER_SUBTILE;
	mVertices[0].pos.y = 0;
	mVertices[0].pos.z = (mFogOriginY * 3) * INCH_PER_SUBTILE;
	mVertices[0].uv = {umin, vmin};

	mVertices[1].pos.x = (mFogOriginX * 3 + mNumSubtilesX) * INCH_PER_SUBTILE;
	mVertices[1].pos.y = 0;
	mVertices[1].pos.z = (mFogOriginY * 3) * INCH_PER_SUBTILE;
	mVertices[1].uv = {umax, vmin};

	mVertices[2].pos.x = (mFogOriginX * 3 + mNumSubtilesX) * INCH_PER_SUBTILE;
	mVertices[2].pos.y = 0;
	mVertices[2].pos.z = (mFogOriginY * 3 + mNumSubtilesY) * INCH_PER_SUBTILE;
	mVertices[2].uv = {umax, vmax};

	mVertices[3].pos.x = (mFogOriginX * 3) * INCH_PER_SUBTILE;
	mVertices[3].pos.y = 0;
	mVertices[3].pos.z = (mFogOriginY * 3 + mNumSubtilesY) * INCH_PER_SUBTILE;
	mVertices[3].uv = {umin, vmax};

	mVertexBuffer->Update<FogOfWarVertex>(mVertices);

	mBufferBinding.Bind();
	mDevice.GetDevice()->SetIndices(mIndexBuffer->GetBuffer());

	mDevice.SetMaterial(*mMaterial);
	mDevice.SetVertexShaderConstant(0, StandardSlotSemantic::ViewProjMatrix);

	mDevice.GetDevice()->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 4, 0, 2);

}

FogBlurKernel FogBlurKernel::Create(uint8_t totalPatternValue) {

	FogBlurKernel result;

	// Precompute 5x5 inverted blur kernel for distributing the total pattern value
	float weights[5][5];
	auto weightSum = 0.0f;
	auto weightOut = &weights[0][0];
	for (auto y = -2; y <= 2; y++) {
		for (auto x = -2; x <= 2; x++) {
			auto strength = 3.0f - sqrtf((float)(x * x + y * y));
			*weightOut++ = strength;
			weightSum += strength;
		}
	}

	// Now use the computed weights to calculate the actual pattern based on the requested total value
	auto patternSum = 0;

	for (auto y = 0; y < 5; ++y) {
		for (auto x = 0; x < 5; ++x) {
			auto pixelValue = (uint8_t)(weights[y][x] / weightSum * totalPatternValue);
			result.patterns[0][y][x] = pixelValue;
			patternSum += pixelValue;
		}
	}

	// This assigns any remainder of the total pattern value (loss due to rounding down above)
	// to the center pixel of the 5x5 kernel
	result.patterns[0][2][2] += totalPatternValue - patternSum;

	// Now create 3 versions of the pattern that are shifted by 1-3 pixels to the right
	// This is for optimization reasons since addition is done using 32-bit (4 bytes) addition
	// and the resulting patterns are in reality 8 pixels wide
	for (auto xShift = 1; xShift <= 3; ++xShift) {
		for (auto y = 0; y < 5; ++y) {
			for (auto x = 0; x < 5; ++x) {
				// Output here is shifted by {1,2,3} pixels right
				result.patterns[xShift][y][x + xShift] = result.patterns[0][y][x];
			}
		}
	}

	return result;
}

<commit_msg>Texture coordinate fix<commit_after>#include "stdafx.h"

#include <graphics/dynamictexture.h>

#include "fogrenderer.h"
#include <temple/dll.h>
#include <common.h>

using namespace gfx;

#pragma pack(push, 1)
struct FogOfWarVertex {
	XMFLOAT3 pos;
	XMFLOAT2 uv;
};
#pragma pack(pop)

FogOfWarRenderer::FogOfWarRenderer(MdfMaterialFactory& mdfFactory, RenderingDevice& device)
	: mMdfFactory(mdfFactory),
	  mDevice(device),
	  mNumSubtilesX(temple::GetRef<uint32_t>(0x10820458)),
	  mNumSubtilesY(temple::GetRef<uint32_t>(0x10824490)) {

	mBlurredFogWidth = (mNumSubtilesX / 4) * 4 + 8;
	mBlurredFogHeight = (mNumSubtilesY / 4) * 4 + 8;

	mBlurredFogTexture = mDevice.CreateDynamicTexture(D3DFMT_A8, mBlurredFogWidth, mBlurredFogHeight);
	mBlurredFog.resize(mBlurredFogWidth * mBlurredFogHeight);

	auto vs = device.GetShaders().LoadVertexShader("fogofwar_vs");
	auto ps = device.GetShaders().LoadPixelShader("fogofwar_ps");
	BlendState blendState;
	blendState.blendEnable = true;
	blendState.srcBlend = D3DBLEND_SRCALPHA;
	blendState.destBlend = D3DBLEND_INVSRCALPHA;
	DepthStencilState depthStencilState;
	depthStencilState.depthEnable = false;
	RasterizerState rasterizerState;
	SamplerState samplerState;
	samplerState.addressU = D3DTADDRESS_CLAMP;
	samplerState.addressV = D3DTADDRESS_CLAMP;
	samplerState.magFilter = D3DTEXF_LINEAR;
	samplerState.minFilter = D3DTEXF_LINEAR;
	std::vector<MaterialSamplerBinding> samplers{
		MaterialSamplerBinding(mBlurredFogTexture, samplerState)
	};

	mMaterial = std::make_unique<Material>(blendState, depthStencilState, rasterizerState, samplers, vs, ps);

	uint16_t indices[6]{0, 2, 1, 2, 0, 3};
	mIndexBuffer = device.CreateIndexBuffer(indices);
	mVertexBuffer = device.CreateEmptyVertexBuffer(sizeof(FogOfWarVertex) * 4);

	mBufferBinding.AddBuffer(mVertexBuffer, 0, sizeof(FogOfWarVertex))
	              .AddElement(VertexElementType::Float3, VertexElementSemantic::Position)
	              .AddElement(VertexElementType::Float2, VertexElementSemantic::TexCoord);
}

struct FogBlurKernel {
	// 4 kernels (shifted by 0,1,2,3 pixels right), each has
	// 5 rows with 8 columns (for shift-compensation)
	uint8_t patterns[4][5][8]; // [xShift][y][x]
	FogBlurKernel() {
		memset(patterns, 0, sizeof(patterns));
	}

	static FogBlurKernel Create(uint8_t totalPatternValue);
};

void FogOfWarRenderer::Render() {
	static auto& sFoggingEnabled = temple::GetRef<uint32_t>(0x108254A0);
	if (!(sFoggingEnabled & 1)) {
		return;
	}

	// Reset the blurred buffer
	std::fill(mBlurredFog.begin(), mBlurredFog.end(), 0);

	static auto sOpaquePattern = FogBlurKernel::Create(0xFF);
	static auto sHalfTransparentPattern = FogBlurKernel::Create(0xA0);

	static auto& fogCheckData = temple::GetRef<uint8_t*>(0x108A5498);

	// Get [0,0] of the subtile data
	auto fogCheckSubtile = &fogCheckData[0];

	for (size_t y = 0; y < mNumSubtilesY; y++) {
		for (size_t x = 0; x < mNumSubtilesX; x++) {
			auto fogState = *fogCheckSubtile;

			// Bit 2 -> Currently in LoS of the party
			if (!(fogState & 2)) {
				uint8_t* patternSrc;
				// Bit 3 -> Explored
				if (fogState & 4) {
					patternSrc = &sHalfTransparentPattern.patterns[x & 3][0][0];
				} else {
					patternSrc = &sOpaquePattern.patterns[x & 3][0][0];
				}

				// Now we copy 5 rows of 2 dwords each, to apply
				// the filter-kernel to the blurred fog map
				for (auto row = 0; row < 5; ++row) {
					auto src = (uint64_t*) &patternSrc[row * 8];
					auto roundedDownX = (x / 4) * 4;
					auto dest = (uint64_t*) &mBlurredFog[(y + row) * mBlurredFogWidth + roundedDownX];
					// Due to how the kernel is layed out, the individual bytes in this 8-byte addition will never carry
					// over to the next higher byte, thus this is equivalent to 8 separate 1-byte additions
					*dest += *src;
				}
			}
			++fogCheckSubtile;
		}

		// Skips the last subtile of the row and the first of the next row
		// fogCheckSubtile += 2;

	}

	static auto& fogMinX = temple::GetRef<uint64_t>(0x10824468);
	static auto& fogMinY = temple::GetRef<uint64_t>(0x108EC4C8);

	auto mFogOriginX = (uint32_t) fogMinX;
	auto mFogOriginY = (uint32_t) fogMinY;

	mBlurredFogTexture->Update<uint8_t>({&mBlurredFog[0], mBlurredFog.size()});

	// Use only the relevant subportion of the texture
	auto umin = 2.5f / (float)mBlurredFogWidth;
	auto vmin = 2.5f / (float)mBlurredFogHeight;
	auto umax = (mNumSubtilesX - 0.5f) / (float)mBlurredFogWidth;
	auto vmax = (mNumSubtilesY - 0.5f) / (float)mBlurredFogHeight;

	FogOfWarVertex mVertices[4];
	mVertices[0].pos.x = (mFogOriginX * 3) * INCH_PER_SUBTILE;
	mVertices[0].pos.y = 0;
	mVertices[0].pos.z = (mFogOriginY * 3) * INCH_PER_SUBTILE;
	mVertices[0].uv = {umin, vmin};

	mVertices[1].pos.x = (mFogOriginX * 3 + mNumSubtilesX) * INCH_PER_SUBTILE;
	mVertices[1].pos.y = 0;
	mVertices[1].pos.z = (mFogOriginY * 3) * INCH_PER_SUBTILE;
	mVertices[1].uv = {umax, vmin};

	mVertices[2].pos.x = (mFogOriginX * 3 + mNumSubtilesX) * INCH_PER_SUBTILE;
	mVertices[2].pos.y = 0;
	mVertices[2].pos.z = (mFogOriginY * 3 + mNumSubtilesY) * INCH_PER_SUBTILE;
	mVertices[2].uv = {umax, vmax};

	mVertices[3].pos.x = (mFogOriginX * 3) * INCH_PER_SUBTILE;
	mVertices[3].pos.y = 0;
	mVertices[3].pos.z = (mFogOriginY * 3 + mNumSubtilesY) * INCH_PER_SUBTILE;
	mVertices[3].uv = {umin, vmax};

	mVertexBuffer->Update<FogOfWarVertex>(mVertices);

	mBufferBinding.Bind();
	mDevice.GetDevice()->SetIndices(mIndexBuffer->GetBuffer());

	mDevice.SetMaterial(*mMaterial);
	mDevice.SetVertexShaderConstant(0, StandardSlotSemantic::ViewProjMatrix);

	mDevice.GetDevice()->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 4, 0, 2);

}

FogBlurKernel FogBlurKernel::Create(uint8_t totalPatternValue) {

	FogBlurKernel result;

	// Precompute 5x5 inverted blur kernel for distributing the total pattern value
	float weights[5][5];
	auto weightSum = 0.0f;
	auto weightOut = &weights[0][0];
	for (auto y = -2; y <= 2; y++) {
		for (auto x = -2; x <= 2; x++) {
			auto strength = 3.0f - sqrtf((float)(x * x + y * y));
			*weightOut++ = strength;
			weightSum += strength;
		}
	}

	// Now use the computed weights to calculate the actual pattern based on the requested total value
	auto patternSum = 0;

	for (auto y = 0; y < 5; ++y) {
		for (auto x = 0; x < 5; ++x) {
			auto pixelValue = (uint8_t)(weights[y][x] / weightSum * totalPatternValue);
			result.patterns[0][y][x] = pixelValue;
			patternSum += pixelValue;
		}
	}

	// This assigns any remainder of the total pattern value (loss due to rounding down above)
	// to the center pixel of the 5x5 kernel
	result.patterns[0][2][2] += totalPatternValue - patternSum;

	// Now create 3 versions of the pattern that are shifted by 1-3 pixels to the right
	// This is for optimization reasons since addition is done using 32-bit (4 bytes) addition
	// and the resulting patterns are in reality 8 pixels wide
	for (auto xShift = 1; xShift <= 3; ++xShift) {
		for (auto y = 0; y < 5; ++y) {
			for (auto x = 0; x < 5; ++x) {
				// Output here is shifted by {1,2,3} pixels right
				result.patterns[xShift][y][x + xShift] = result.patterns[0][y][x];
			}
		}
	}

	return result;
}

<|endoftext|>