<commit_before>///
/// @file  S2LoadBalancer.cpp
/// @brief The S2LoadBalancer evenly distributes the work load between
///        the threads in the computation of the special leaves.
///
/// Simply parallelizing the computation of the special leaves in the
/// Lagarias-Miller-Odlyzko and Deleglise-Rivat algorithms by
/// subdividing the sieve interval by the number of threads into
/// equally sized subintervals does not scale because the distribution
/// of the special leaves is highly skewed, especially if the interval
/// size is large and if the intervals are not adjacent. Also most
/// special leaves are in the first few segments whereas later on
/// there are very few special leaves.
///
/// Based on the above observations it is clear that we need a load
/// balancer in order to scale our parallel algorithm to compute the
/// special leaves. Below are the main rules I used to develop my load
/// balancing algorithm:
///
/// 1) Start with a tiny segment size of x^(1/3) / (log x * log log x)
///    and one segment per thread. Our algorithm uses equally sized
///    intervals, the interval_size per thread is
///    segment_size * segments_per_thread and the threads process
///    adjacent intervals i.e.
///    [base + interval_size * thread_id, base + interval_size * (thread_id + 1)].
///
/// 2) If the relative standard deviation of the run times of the
///    threads is low then increase the segment size and/or segments
///    per thread, else if the relative standard deviation is large
///    then decrease the segment size and/or segments per thread. This
///    rule is derived from the fact that intervals with roughly the
///    same number of special leaves take about the same time to
///    process and the next intervals tend to have a similar
///    distribution of special leaves (especially if the interval size
///    is small).
///
/// 3) We can't use a static threshold for as to when the relative
///    standard deviation is low or large as this threshold varies for
///    different PC architectures e.g. 15 might be large relative
///    standard deviation for a quad-core CPU system whereas it is a
///    low standard deviation for a dual-socket system with 64
///    threads. So instead of using a static threshold we compare the
///    current relative standard deviation to the previous one.
///
/// Copyright (C) 2014 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <S2LoadBalancer.hpp>
#include <primecount-internal.hpp>
#include <aligned_vector.hpp>
#include <pmath.hpp>
#include <int128.hpp>

#include <stdint.h>
#include <algorithm>
#include <cmath>

using namespace std;
using namespace primecount;

namespace {

double get_average(aligned_vector<double>& timings)
{
  size_t n = timings.size();
  double sum = 0;

  for (size_t i = 0; i < n; i++)
    sum += timings[i];

  return sum / n;
}

double relative_standard_deviation(aligned_vector<double>& timings)
{
  size_t n = timings.size();
  double average = get_average(timings);
  double sum = 0;

  if (average == 0)
    return 0;

  for (size_t i = 0; i < n; i++)
  {
    double mean = timings[i] - average;
    sum += mean * mean;
  }

  double std_dev = sqrt(sum / max(1.0, n - 1.0));
  double rsd = 100 * std_dev / average;

  return rsd;
}

} // namespace

namespace primecount {

S2LoadBalancer::S2LoadBalancer(maxint_t x, int64_t z, int64_t threads) :
  x_((double) x),
  z_((double) z),
  rsd_(40),
  avg_seconds_(0),
  count_(0)
{
  double log_threads = max(1.0, log((double) threads));
  decrease_dividend_ = max(0.5, log_threads / 3);
  min_seconds_ = 0.02 * log_threads;
  max_size_ = next_power_of_2(isqrt(z));
  update_min_size(log(x_) * log(log(x_)));
}

double S2LoadBalancer::get_rsd() const
{
  return rsd_;
}

int64_t S2LoadBalancer::get_min_segment_size() const
{
  return min_size_;
}

bool S2LoadBalancer::decrease_size(double seconds, double decrease) const
{
  return seconds > min_seconds_ &&
         rsd_ > decrease;
}

bool S2LoadBalancer::increase_size(double seconds, double decrease) const
{
  return seconds < avg_seconds_ &&
        !decrease_size(seconds, decrease);
}

/// Used to decide whether to use a smaller or larger
/// segment_size and/or segments_per_thread.
///
double S2LoadBalancer::get_decrease_threshold(double seconds) const
{
  double log_seconds = max(min_seconds_, log(seconds));
  double dont_decrease = min(decrease_dividend_ / (seconds * log_seconds), rsd_);
  return rsd_ + dont_decrease;
}

void S2LoadBalancer::update_avg_seconds(double seconds)
{
  seconds = max(seconds, min_seconds_);
  double dividend = avg_seconds_ * count_ + seconds;
  avg_seconds_ = dividend / (count_ + 1);
  count_++;
}

void S2LoadBalancer::update_min_size(double divisor)
{
  double size = sqrt(z_) / max(1.0, divisor);
  min_size_ = max((int64_t) (1 << 9), (int64_t) size);
  min_size_ = next_power_of_2(min_size_);
}

/// Balance the load in the computation of the special leaves
/// by dynamically adjusting the segment_size and segments_per_thread.
/// @param timings  Timings of the threads.
///
void S2LoadBalancer::update(int64_t low,
                            int64_t threads,
                            int64_t* segment_size,
                            int64_t* segments_per_thread,
                            aligned_vector<double>& timings)
{
  double seconds = get_average(timings);
  update_avg_seconds(seconds);
  double decrease_threshold = get_decrease_threshold(seconds);
  rsd_ = max(0.1, relative_standard_deviation(timings));

  // if low > sqrt(z) we use a larger min_size_ as the
  // special leaves are distributed more evenly
  if (low > max_size_)
  {
    update_min_size(log(x_));
    *segment_size = max(*segment_size, min_size_);
  }

  // 1 segment per thread
  if (*segment_size < max_size_)
  {
    if (increase_size(seconds, decrease_threshold))
      *segment_size <<= 1;
    else if (decrease_size(seconds, decrease_threshold))
      if (*segment_size > min_size_)
        *segment_size >>= 1;

    // near sqrt(z) there is a short peak of special
    // leaves so we use the minium segment size
    int64_t high = low + *segment_size * *segments_per_thread * threads;
    if (low <= max_size_ && high > max_size_)
      *segment_size = min_size_;
  }
  else // many segments per thread
  {
    double factor = decrease_threshold / rsd_;
    factor = in_between(0.5, factor, 2);
    double n = *segments_per_thread * factor;
    n = max(1.0, n);

    if ((n < *segments_per_thread && seconds > min_seconds_) ||
        (n > *segments_per_thread && seconds < avg_seconds_))
    {
      *segments_per_thread = (int) n;
    }
  }
}

} //namespace
<commit_msg>Update documentation<commit_after>///
/// @file  S2LoadBalancer.cpp
/// @brief The S2LoadBalancer evenly distributes the work load between
///        the threads in the computation of the special leaves.
///
/// Simply parallelizing the computation of the special leaves in the
/// Lagarias-Miller-Odlyzko and Deleglise-Rivat algorithms by
/// subdividing the sieve interval by the number of threads into
/// equally sized subintervals does not scale because the distribution
/// of the special leaves is highly skewed, especially if the interval
/// size is large and if the intervals are not adjacent. Also most
/// special leaves are in the first few segments whereas later on
/// there are very few special leaves.
///
/// Based on the above observations it is clear that we need a load
/// balancer in order to scale our parallel algorithm to compute the
/// special leaves. Below are the main rules I used to develop my load
/// balancing algorithm:
///
/// 1) Start with a tiny segment size of x^(1/3) / (log x * log log x)
///    and one segment per thread. Our algorithm uses equally sized
///    intervals, for each thread the interval_size is
///    segment_size * segments_per_thread and the threads process
///    adjacent intervals i.e.
///    [base + interval_size * thread_id, base + interval_size * (thread_id + 1)].
///
/// 2) If the relative standard deviation of the run times of the
///    threads is low then increase the segment size and/or segments
///    per thread, else if the relative standard deviation is large
///    then decrease the segment size and/or segments per thread. This
///    rule is derived from the fact that intervals with roughly the
///    same number of special leaves take about the same time to
///    process and the next intervals tend to have a similar
///    distribution of special leaves (especially if the interval size
///    is small).
///
/// 3) We can't use a static threshold for as to when the relative
///    standard deviation is low or large as this threshold varies for
///    different PC architectures e.g. 15 might be large relative
///    standard deviation for a quad-core CPU system whereas it is a
///    low standard deviation for a dual-socket system with 64
///    threads. So instead of using a static threshold we compare the
///    current relative standard deviation to the previous one.
///
/// Copyright (C) 2014 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <S2LoadBalancer.hpp>
#include <primecount-internal.hpp>
#include <aligned_vector.hpp>
#include <pmath.hpp>
#include <int128.hpp>

#include <stdint.h>
#include <algorithm>
#include <cmath>

using namespace std;
using namespace primecount;

namespace {

double get_average(aligned_vector<double>& timings)
{
  size_t n = timings.size();
  double sum = 0;

  for (size_t i = 0; i < n; i++)
    sum += timings[i];

  return sum / n;
}

double relative_standard_deviation(aligned_vector<double>& timings)
{
  size_t n = timings.size();
  double average = get_average(timings);
  double sum = 0;

  if (average == 0)
    return 0;

  for (size_t i = 0; i < n; i++)
  {
    double mean = timings[i] - average;
    sum += mean * mean;
  }

  double std_dev = sqrt(sum / max(1.0, n - 1.0));
  double rsd = 100 * std_dev / average;

  return rsd;
}

} // namespace

namespace primecount {

S2LoadBalancer::S2LoadBalancer(maxint_t x, int64_t z, int64_t threads) :
  x_((double) x),
  z_((double) z),
  rsd_(40),
  avg_seconds_(0),
  count_(0)
{
  double log_threads = max(1.0, log((double) threads));
  decrease_dividend_ = max(0.5, log_threads / 3);
  min_seconds_ = 0.02 * log_threads;
  max_size_ = next_power_of_2(isqrt(z));
  update_min_size(log(x_) * log(log(x_)));
}

double S2LoadBalancer::get_rsd() const
{
  return rsd_;
}

int64_t S2LoadBalancer::get_min_segment_size() const
{
  return min_size_;
}

bool S2LoadBalancer::decrease_size(double seconds, double decrease) const
{
  return seconds > min_seconds_ &&
         rsd_ > decrease;
}

bool S2LoadBalancer::increase_size(double seconds, double decrease) const
{
  return seconds < avg_seconds_ &&
        !decrease_size(seconds, decrease);
}

/// Used to decide whether to use a smaller or larger
/// segment_size and/or segments_per_thread.
///
double S2LoadBalancer::get_decrease_threshold(double seconds) const
{
  double log_seconds = max(min_seconds_, log(seconds));
  double dont_decrease = min(decrease_dividend_ / (seconds * log_seconds), rsd_);
  return rsd_ + dont_decrease;
}

void S2LoadBalancer::update_avg_seconds(double seconds)
{
  seconds = max(seconds, min_seconds_);
  double dividend = avg_seconds_ * count_ + seconds;
  avg_seconds_ = dividend / (count_ + 1);
  count_++;
}

void S2LoadBalancer::update_min_size(double divisor)
{
  double size = sqrt(z_) / max(1.0, divisor);
  min_size_ = max((int64_t) (1 << 9), (int64_t) size);
  min_size_ = next_power_of_2(min_size_);
}

/// Balance the load in the computation of the special leaves
/// by dynamically adjusting the segment_size and segments_per_thread.
/// @param timings  Timings of the threads.
///
void S2LoadBalancer::update(int64_t low,
                            int64_t threads,
                            int64_t* segment_size,
                            int64_t* segments_per_thread,
                            aligned_vector<double>& timings)
{
  double seconds = get_average(timings);
  update_avg_seconds(seconds);
  double decrease_threshold = get_decrease_threshold(seconds);
  rsd_ = max(0.1, relative_standard_deviation(timings));

  // if low > sqrt(z) we use a larger min_size_ as the
  // special leaves are distributed more evenly
  if (low > max_size_)
  {
    update_min_size(log(x_));
    *segment_size = max(*segment_size, min_size_);
  }

  // 1 segment per thread
  if (*segment_size < max_size_)
  {
    if (increase_size(seconds, decrease_threshold))
      *segment_size <<= 1;
    else if (decrease_size(seconds, decrease_threshold))
      if (*segment_size > min_size_)
        *segment_size >>= 1;

    // near sqrt(z) there is a short peak of special
    // leaves so we use the minium segment size
    int64_t high = low + *segment_size * *segments_per_thread * threads;
    if (low <= max_size_ && high > max_size_)
      *segment_size = min_size_;
  }
  else // many segments per thread
  {
    double factor = decrease_threshold / rsd_;
    factor = in_between(0.5, factor, 2);
    double n = *segments_per_thread * factor;
    n = max(1.0, n);

    if ((n < *segments_per_thread && seconds > min_seconds_) ||
        (n > *segments_per_thread && seconds < avg_seconds_))
    {
      *segments_per_thread = (int) n;
    }
  }
}

} //namespace
<|endoftext|>


<commit_before>#include <ShapeLensConfig.h>
#include <boost/tokenizer.hpp>
#include <fstream>
#include <iostream>

using namespace std;

unsigned int ShapeLensConfig::NMAX_LOW = 0;
unsigned int ShapeLensConfig::NMAX_HIGH = 100;
data_t ShapeLensConfig::BETA_LOW = 0;
data_t ShapeLensConfig::BETA_HIGH = INFINITY;
bool ShapeLensConfig::REGULARIZE = 0;
data_t ShapeLensConfig::REG_LIMIT = 1e-5;
std::string ShapeLensConfig::UNREG_SIFFILE = "";
bool ShapeLensConfig::ALLOW_FLATTENING = 0;
bool ShapeLensConfig::FILTER_SPURIOUS = 0;
data_t ShapeLensConfig::ADD_BORDER = 0.5;

ShapeLensConfig::ShapeLensConfig() {
}

ShapeLensConfig::ShapeLensConfig(string filename) {
  // open config file
  ifstream configfile (filename.c_str());
  if (configfile.fail()) {
    cout << "ShapeLensConfig: configuration file does not exists!" << endl;
    terminate();
  }
  // read in config file
  string line;
  while(getline(configfile, line)) {
    typedef boost::tokenizer<boost::char_separator<char> > Tok;
    // split entries at tabs
    boost::char_separator<char> sep("\t");
    Tok tok(line, sep);
    // first of all we copy the token into string vector
    // though this is not too sophisticated it does not hurt and is more
    // convenient
    std::vector<std::string> column;
    for(Tok::iterator tok_iter = tok.begin(); tok_iter != tok.end(); ++tok_iter)
      column.push_back(*tok_iter);
    // exclude empty and comment lines
    if (column.size() >= 2 && column[0].compare("#") != 0) {
      if (column[0].compare("NMAX_LOW") == 0)
	NMAX_LOW = (unsigned int) atoi (column[1].c_str());
      if (column[0].compare("NMAX_HIGH") == 0)
	NMAX_HIGH = (unsigned int) atoi (column[1].c_str());
      if (column[0].compare("BETA_LOW") == 0)
	BETA_LOW = (data_t) atof (column[1].c_str());
      if (column[0].compare("BETA_HIGH") == 0)
	BETA_HIGH = (data_t) atof (column[1].c_str());
      if (column[0].compare("REGULARIZE") == 0)
	REGULARIZE = (bool) atoi (column[1].c_str());
      if (column[0].compare("REG_LIMIT") == 0)
	REG_LIMIT = (data_t) atof (column[1].c_str());
      if (column[0].compare("UNREG_SIFFILE") == 0)
	UNREG_SIFFILE = column[1];
      if (column[0].compare("ALLOW_FLATTENING") == 0)
	ALLOW_FLATTENING = (bool) atoi (column[1].c_str());
      if (column[0].compare("FILTER_SPURIOUS") == 0)
        FILTER_SPURIOUS = (bool) atoi (column[1].c_str());
      if (column[0].compare("ADD_BORDER") == 0)
        ADD_BORDER = (data_t) atof (column[1].c_str());
    }
  }
}

<commit_msg>replaced INFINITY by std::numeric_limits<double>::infinity(); in ShapeLensConfig.cc<commit_after>#include <ShapeLensConfig.h>
#include <boost/tokenizer.hpp>
#include <fstream>
#include <iostream>
#include <limits>

using namespace std;

unsigned int ShapeLensConfig::NMAX_LOW = 0;
unsigned int ShapeLensConfig::NMAX_HIGH = 100;
data_t ShapeLensConfig::BETA_LOW = 0;
data_t ShapeLensConfig::BETA_HIGH = numeric_limits<data_t>::infinity();
bool ShapeLensConfig::REGULARIZE = 0;
data_t ShapeLensConfig::REG_LIMIT = 1e-5;
std::string ShapeLensConfig::UNREG_SIFFILE = "";
bool ShapeLensConfig::ALLOW_FLATTENING = 0;
bool ShapeLensConfig::FILTER_SPURIOUS = 0;
data_t ShapeLensConfig::ADD_BORDER = 0.5;

ShapeLensConfig::ShapeLensConfig() {
}

ShapeLensConfig::ShapeLensConfig(string filename) {
  // open config file
  ifstream configfile (filename.c_str());
  if (configfile.fail()) {
    cout << "ShapeLensConfig: configuration file does not exists!" << endl;
    terminate();
  }
  // read in config file
  string line;
  while(getline(configfile, line)) {
    typedef boost::tokenizer<boost::char_separator<char> > Tok;
    // split entries at tabs
    boost::char_separator<char> sep("\t");
    Tok tok(line, sep);
    // first of all we copy the token into string vector
    // though this is not too sophisticated it does not hurt and is more
    // convenient
    std::vector<std::string> column;
    for(Tok::iterator tok_iter = tok.begin(); tok_iter != tok.end(); ++tok_iter)
      column.push_back(*tok_iter);
    // exclude empty and comment lines
    if (column.size() >= 2 && column[0].compare("#") != 0) {
      if (column[0].compare("NMAX_LOW") == 0)
	NMAX_LOW = (unsigned int) atoi (column[1].c_str());
      if (column[0].compare("NMAX_HIGH") == 0)
	NMAX_HIGH = (unsigned int) atoi (column[1].c_str());
      if (column[0].compare("BETA_LOW") == 0)
	BETA_LOW = (data_t) atof (column[1].c_str());
      if (column[0].compare("BETA_HIGH") == 0)
	BETA_HIGH = (data_t) atof (column[1].c_str());
      if (column[0].compare("REGULARIZE") == 0)
	REGULARIZE = (bool) atoi (column[1].c_str());
      if (column[0].compare("REG_LIMIT") == 0)
	REG_LIMIT = (data_t) atof (column[1].c_str());
      if (column[0].compare("UNREG_SIFFILE") == 0)
	UNREG_SIFFILE = column[1];
      if (column[0].compare("ALLOW_FLATTENING") == 0)
	ALLOW_FLATTENING = (bool) atoi (column[1].c_str());
      if (column[0].compare("FILTER_SPURIOUS") == 0)
        FILTER_SPURIOUS = (bool) atoi (column[1].c_str());
      if (column[0].compare("ADD_BORDER") == 0)
        ADD_BORDER = (data_t) atof (column[1].c_str());
    }
  }
}

<|endoftext|>


<commit_before>// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEM_LIBCEED_CONV_HPP
#define MFEM_LIBCEED_CONV_HPP

#include "integrator.hpp"
#include "../fespace.hpp"

namespace mfem
{

namespace ceed
{

/** Represent a VectorConvectionNLFIntegrator with AssemblyLevel::Partial
    using libCEED. */
class PAVectorConvectionNLFIntegrator : public PAIntegrator
{
public:
   PAVectorConvectionNLFIntegrator(const mfem::FiniteElementSpace &fes,
                                   const mfem::IntegrationRule &irm,
                                   mfem::Coefficient *coeff);
};

/** Represent a VectorConvectionNLFIntegrator with AssemblyLevel::None
    using libCEED. */
class MFVectorConvectionNLFIntegrator : public MFIntegrator
{
public:
   MFVectorConvectionNLFIntegrator(const mfem::FiniteElementSpace &fes,
                                   const mfem::IntegrationRule &irm,
                                   mfem::Coefficient *coeff);
};

}

}

#endif // MFEM_LIBCEED_CONV_HPP
<commit_msg>fix #ifdef name for nlconvection.<commit_after>// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEM_LIBCEED_NLCONV_HPP
#define MFEM_LIBCEED_NLCONV_HPP

#include "integrator.hpp"
#include "../fespace.hpp"

namespace mfem
{

namespace ceed
{

/** Represent a VectorConvectionNLFIntegrator with AssemblyLevel::Partial
    using libCEED. */
class PAVectorConvectionNLFIntegrator : public PAIntegrator
{
public:
   PAVectorConvectionNLFIntegrator(const mfem::FiniteElementSpace &fes,
                                   const mfem::IntegrationRule &irm,
                                   mfem::Coefficient *coeff);
};

/** Represent a VectorConvectionNLFIntegrator with AssemblyLevel::None
    using libCEED. */
class MFVectorConvectionNLFIntegrator : public MFIntegrator
{
public:
   MFVectorConvectionNLFIntegrator(const mfem::FiniteElementSpace &fes,
                                   const mfem::IntegrationRule &irm,
                                   mfem::Coefficient *coeff);
};

}

}

#endif // MFEM_LIBCEED_NLCONV_HPP
<|endoftext|>


<commit_before>#include "debugging.h"
#include <cstdio>
#include <cstring>
#if __ANDROID__
  #include <android/log.h>
#endif
#if _WIN32
#define WIN32_LEAN_AND_MEAN 1
#include <Windows.h>
#endif

#ifdef QUIETLOG
static LogSeverity Filter = LogSeverityWarn;
#else
static LogSeverity Filter = LogSeverityInfo;
#endif
static LogErrorCallback ErrorHandler;
static LogEventCallback EventHandler;
static LogExceptCallback ExceptHandler;
static bool DisableFunctionNames = false;

EXTERNC void SetLogErrorHandler(LogErrorCallback errorHandler)
{
    ErrorHandler = errorHandler;
}
EXTERNC void SetLogEventHandler(LogEventCallback eventHandler)
{
    EventHandler = eventHandler;
}
EXTERNC void SetLogExceptHandler(LogExceptCallback exceptFunc)
{
    ExceptHandler = exceptFunc;
}
EXTERNC void LogDisableFunctionNames()
{
    DisableFunctionNames = true;
}
EXTERNC void SetLogSeverityFilter(LogSeverity filter)
{
    Filter = filter;
}
EXTERNC LogSeverity GetLogSeverityFilter()
{
    return Filter;
}

static int SafeFormat(char* errBuf, int N, const char* format, va_list ap)
{
    int len = vsnprintf(errBuf, size_t(N-1)/*spare room for \n*/, format, ap);
    if (len < 0 || len >= N) { // err: didn't fit
        len = N-2; // try to recover gracefully
        errBuf[len] = '\0';
    }
    return len;
}

#if __linux__
// split at $ and remove /long/path/ leaving just "filename.cpp:123 func() $ message"
static void ShortFilePathMessage(char*& ptr, int& len)
{
    if (char* middle = strchr(ptr, '$')) {
        for (; middle > ptr; --middle) {
            if (*middle == '/' || *middle == '\\') {
                ++middle;
                break;
            }
        }
        len = int((ptr + len) - middle);
        ptr = middle;
        ptr[len] = '\0';
    }
}
#endif

EXTERNC void LogWriteToDefaultOutput(const char* tag, LogSeverity severity, const char* err, int len)
{
    #if __ANDROID__
        auto priority = severity == LogSeverityInfo ? ANDROID_LOG_INFO :
                        severity == LogSeverityWarn ? ANDROID_LOG_WARN :
                                                      ANDROID_LOG_ERROR;
        __android_log_write(priority, tag, err);
    #elif _WIN32
        static HANDLE winout = GetStdHandle(STD_OUTPUT_HANDLE);
        static HANDLE winerr = GetStdHandle(STD_ERROR_HANDLE);
        static const WORD colormap[] = {
            FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY, // white - Info
            FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY, // bright yellow - Warning
            FOREGROUND_RED | FOREGROUND_INTENSITY, // bright red - Error
        };
        bool is_error = severity == LogSeverityError;
        HANDLE out = is_error ? winout : winerr;
        DWORD written;

        SetConsoleTextAttribute(out, colormap[severity]);
        WriteConsoleA(out, err, len, &written, nullptr);
        WriteConsoleA(out, "\n", 1, &written, nullptr);
        SetConsoleTextAttribute(out, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
    #else
        FILE* out = (severity == LogSeverityError) ? stderr : stdout;
        fwrite(err, (size_t)len, 1, out);
        fwrite("\n", 1, 1, out);
    #endif
    (void)tag;
}

EXTERNC void LogEventToDefaultOutput(const char* tag, const char* eventName, const char* message, int len)
{
    #if __ANDROID__
        __android_log_print(ANDROID_LOG_INFO, tag, "EVT %s: %.*s", eventName, len, message);
    #else
        printf("EVT %s: %.*s\n", eventName, len, message);
    #endif
    (void)tag;
}

EXTERNC void LogFormatv(LogSeverity severity, const char* format, va_list ap)
{
    if (severity < Filter)
        return;

    char errBuf[4096];
    int len = SafeFormat(errBuf, sizeof(errBuf), format, ap);

    if (ErrorHandler)
    {
        char* ptr = errBuf;
        #ifdef __linux__
          ShortFilePathMessage(ptr, len);
        #endif
        ErrorHandler(severity, ptr, len);
    }
    else
    {
        LogWriteToDefaultOutput("ReCpp", severity, errBuf, len);
    }
}

#define WrappedLogFormatv(severity, format) \
    va_list ap; va_start(ap, format); \
    LogFormatv(severity, format, ap); \
    va_end(ap);
EXTERNC void _LogInfo(const char* format, ...) {
    WrappedLogFormatv(LogSeverityInfo, format);
}
EXTERNC void _LogWarning(const char* format, ...) {
    WrappedLogFormatv(LogSeverityWarn, format);
}
EXTERNC void _LogError(const char* format, ...) {
    WrappedLogFormatv(LogSeverityError, format);
}

EXTERNC void LogEvent(const char* eventName, const char* format, ...)
{
#if __clang__
#if __has_feature(address_sanitizer)
    return; // ASAN reports a false positive with vsnprintf
#endif
#endif
    va_list ap; va_start(ap, format);
    char messageBuf[4096];
    int len = SafeFormat(messageBuf, sizeof(messageBuf), format, ap);
    va_end(ap);

    if (EventHandler)
    {
        EventHandler(eventName, messageBuf, len);
    }
    else
    {
        LogEventToDefaultOutput("ReCpp", eventName, messageBuf, len);
    }
}

void _LogExcept(const char* exceptionWhat, const char* format, ...)
{
#if __clang__
#if __has_feature(address_sanitizer)
    return; // ASAN reports a false positive with vsnprintf
#endif
#endif
    va_list ap; va_start(ap, format);
    char messageBuf[4096];
    int len = SafeFormat(messageBuf, sizeof(messageBuf), format, ap);
    va_end(ap);

    // only MSVC requires stderr write; other platforms do it in assert
#if _MSC_VER
    fprintf(stderr, "%.*s: %s\n", len, messageBuf, exceptionWhat);
#else
    (void)len;
#endif

    if (ExceptHandler != nullptr)
    {
        ExceptHandler(messageBuf, exceptionWhat);
    }
}

EXTERNC const char* _FmtString(const char* format, ...)
{
    static thread_local char errBuf[4096];
    va_list ap; va_start(ap, format);
    SafeFormat(errBuf, sizeof(errBuf), format, ap);
    va_end(ap);
    return errBuf;
}

EXTERNC const char* _LogFilename(const char* longFilePath)
{
    if (longFilePath == nullptr) return "(null)";
    const char* eptr = longFilePath + strlen(longFilePath);
    for (int n = 1; longFilePath < eptr; --eptr)
        if (*eptr == '/' || *eptr == '\\')
            if (--n <= 0) return ++eptr;
    return eptr;
}

EXTERNC const char* _LogFuncname(const char* longFuncName)
{
    if (DisableFunctionNames) return "";
    if (longFuncName == nullptr) return "(null)";

    static thread_local char buf[64];
    static const int max = 36;

    // always skip the first ::
    const char* ptr = strchr(longFuncName, ':');
    if (ptr != nullptr) {
        if (*++ptr == ':') ++ptr;
    }
    else ptr = longFuncName;

    char ch;
    int len = 0;
    for (; len < max && (ch = *ptr) != '\0'; ++ptr) {
        if (ch == '<') {
            if (memcmp(ptr, "<<lambda", 8) == 0) { // MSVC std::invoke<<lambda_....>&>
                memcpy(&buf[len], "<lambda>", 8);
                len += 8;
                break;
            }
            if (memcmp(ptr, "<lambda", 7) == 0) {
                memcpy(&buf[len], "lambda", 6);
                len += 6;
                break;
            }
        }
        buf[len++] = ch;
    }
    if (buf[len-1] == ']')
        --len; // remove Objective-C method ending bracket
    buf[len] = '\0';
    return buf;
}

void Log(LogSeverity severity, rpp::strview message)
{
    if (severity < Filter)
        return;

    auto file = (severity == LogSeverityError) ? stderr : stdout;
    fwrite(message.str, (size_t)message.len, 1, file);
    fwrite("\n", 1, 1, file);

    if (ErrorHandler != nullptr)
    {
        ErrorHandler(severity, message.str, message.len);
    }
}
<commit_msg>Made LogWriteToDefaultOutput write atomically to stdout/stderr.<commit_after>#include "debugging.h"
#include <cstdio>
#include <cstring>
#if __ANDROID__
  #include <android/log.h>
#endif
#if _WIN32
#define WIN32_LEAN_AND_MEAN 1
#include <Windows.h>
#endif

#ifdef QUIETLOG
static LogSeverity Filter = LogSeverityWarn;
#else
static LogSeverity Filter = LogSeverityInfo;
#endif
static LogErrorCallback ErrorHandler;
static LogEventCallback EventHandler;
static LogExceptCallback ExceptHandler;
static bool DisableFunctionNames = false;

EXTERNC void SetLogErrorHandler(LogErrorCallback errorHandler)
{
    ErrorHandler = errorHandler;
}
EXTERNC void SetLogEventHandler(LogEventCallback eventHandler)
{
    EventHandler = eventHandler;
}
EXTERNC void SetLogExceptHandler(LogExceptCallback exceptFunc)
{
    ExceptHandler = exceptFunc;
}
EXTERNC void LogDisableFunctionNames()
{
    DisableFunctionNames = true;
}
EXTERNC void SetLogSeverityFilter(LogSeverity filter)
{
    Filter = filter;
}
EXTERNC LogSeverity GetLogSeverityFilter()
{
    return Filter;
}

static int SafeFormat(char* errBuf, int N, const char* format, va_list ap)
{
    int len = vsnprintf(errBuf, size_t(N-1)/*spare room for \n*/, format, ap);
    if (len < 0 || len >= N) { // err: didn't fit
        len = N-2; // try to recover gracefully
        errBuf[len] = '\0';
    }
    return len;
}

#if __linux__
// split at $ and remove /long/path/ leaving just "filename.cpp:123 func() $ message"
static void ShortFilePathMessage(char*& ptr, int& len)
{
    if (char* middle = strchr(ptr, '$')) {
        for (; middle > ptr; --middle) {
            if (*middle == '/' || *middle == '\\') {
                ++middle;
                break;
            }
        }
        len = int((ptr + len) - middle);
        ptr = middle;
        ptr[len] = '\0';
    }
}
#endif

// this ensures default output newline is atomic with the rest of the error string
#define AllocaPrintlineBuf(err, len) \
    char* buf = (char*)__alloca(len + 2); \
    memcpy(buf, err, len); \
    buf[len] = '\n'; \
    buf[len+1] = '\0';

EXTERNC void LogWriteToDefaultOutput(const char* tag, LogSeverity severity, const char* err, int len)
{
    #if __ANDROID__
        auto priority = severity == LogSeverityInfo ? ANDROID_LOG_INFO :
                        severity == LogSeverityWarn ? ANDROID_LOG_WARN :
                                                      ANDROID_LOG_ERROR;
        __android_log_write(priority, tag, err);
    #elif _WIN32
        static HANDLE winout = GetStdHandle(STD_OUTPUT_HANDLE);
        static HANDLE winerr = GetStdHandle(STD_ERROR_HANDLE);
        static const WORD colormap[] = {
            FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY, // white - Info
            FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY, // bright yellow - Warning
            FOREGROUND_RED | FOREGROUND_INTENSITY, // bright red - Error
        };
        bool is_error = severity == LogSeverityError;
        HANDLE out = is_error ? winout : winerr;
        DWORD written;

        AllocaPrintlineBuf(err, len);

        SetConsoleTextAttribute(out, colormap[severity]);
        WriteConsoleA(out, buf, len+1, &written, nullptr);
        SetConsoleTextAttribute(out, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
    #else
        AllocaPrintlineBuf(err, len);
        FILE* out = (severity == LogSeverityError) ? stderr : stdout;
        fwrite(buf, (size_t)len+1, 1, out);
    #endif
    (void)tag;
}

EXTERNC void LogEventToDefaultOutput(const char* tag, const char* eventName, const char* message, int len)
{
    #if __ANDROID__
        __android_log_print(ANDROID_LOG_INFO, tag, "EVT %s: %.*s", eventName, len, message);
    #else
        printf("EVT %s: %.*s\n", eventName, len, message);
    #endif
    (void)tag;
}

EXTERNC void LogFormatv(LogSeverity severity, const char* format, va_list ap)
{
    if (severity < Filter)
        return;

    char errBuf[4096];
    int len = SafeFormat(errBuf, sizeof(errBuf), format, ap);

    if (ErrorHandler)
    {
        char* ptr = errBuf;
        #ifdef __linux__
          ShortFilePathMessage(ptr, len);
        #endif
        ErrorHandler(severity, ptr, len);
    }
    else
    {
        LogWriteToDefaultOutput("ReCpp", severity, errBuf, len);
    }
}

#define WrappedLogFormatv(severity, format) \
    va_list ap; va_start(ap, format); \
    LogFormatv(severity, format, ap); \
    va_end(ap);
EXTERNC void _LogInfo(const char* format, ...) {
    WrappedLogFormatv(LogSeverityInfo, format);
}
EXTERNC void _LogWarning(const char* format, ...) {
    WrappedLogFormatv(LogSeverityWarn, format);
}
EXTERNC void _LogError(const char* format, ...) {
    WrappedLogFormatv(LogSeverityError, format);
}

EXTERNC void LogEvent(const char* eventName, const char* format, ...)
{
#if __clang__
#if __has_feature(address_sanitizer)
    return; // ASAN reports a false positive with vsnprintf
#endif
#endif
    va_list ap; va_start(ap, format);
    char messageBuf[4096];
    int len = SafeFormat(messageBuf, sizeof(messageBuf), format, ap);
    va_end(ap);

    if (EventHandler)
    {
        EventHandler(eventName, messageBuf, len);
    }
    else
    {
        LogEventToDefaultOutput("ReCpp", eventName, messageBuf, len);
    }
}

void _LogExcept(const char* exceptionWhat, const char* format, ...)
{
#if __clang__
#if __has_feature(address_sanitizer)
    return; // ASAN reports a false positive with vsnprintf
#endif
#endif
    va_list ap; va_start(ap, format);
    char messageBuf[4096];
    int len = SafeFormat(messageBuf, sizeof(messageBuf), format, ap);
    va_end(ap);

    // only MSVC requires stderr write; other platforms do it in assert
#if _MSC_VER
    fprintf(stderr, "%.*s: %s\n", len, messageBuf, exceptionWhat);
#else
    (void)len;
#endif

    if (ExceptHandler != nullptr)
    {
        ExceptHandler(messageBuf, exceptionWhat);
    }
}

EXTERNC const char* _FmtString(const char* format, ...)
{
    static thread_local char errBuf[4096];
    va_list ap; va_start(ap, format);
    SafeFormat(errBuf, sizeof(errBuf), format, ap);
    va_end(ap);
    return errBuf;
}

EXTERNC const char* _LogFilename(const char* longFilePath)
{
    if (longFilePath == nullptr) return "(null)";
    const char* eptr = longFilePath + strlen(longFilePath);
    for (int n = 1; longFilePath < eptr; --eptr)
        if (*eptr == '/' || *eptr == '\\')
            if (--n <= 0) return ++eptr;
    return eptr;
}

EXTERNC const char* _LogFuncname(const char* longFuncName)
{
    if (DisableFunctionNames) return "";
    if (longFuncName == nullptr) return "(null)";

    static thread_local char buf[64];
    static const int max = 36;

    // always skip the first ::
    const char* ptr = strchr(longFuncName, ':');
    if (ptr != nullptr) {
        if (*++ptr == ':') ++ptr;
    }
    else ptr = longFuncName;

    char ch;
    int len = 0;
    for (; len < max && (ch = *ptr) != '\0'; ++ptr) {
        if (ch == '<') {
            if (memcmp(ptr, "<<lambda", 8) == 0) { // MSVC std::invoke<<lambda_....>&>
                memcpy(&buf[len], "<lambda>", 8);
                len += 8;
                break;
            }
            if (memcmp(ptr, "<lambda", 7) == 0) {
                memcpy(&buf[len], "lambda", 6);
                len += 6;
                break;
            }
        }
        buf[len++] = ch;
    }
    if (buf[len-1] == ']')
        --len; // remove Objective-C method ending bracket
    buf[len] = '\0';
    return buf;
}

void Log(LogSeverity severity, rpp::strview message)
{
    if (severity < Filter)
        return;

    auto file = (severity == LogSeverityError) ? stderr : stdout;
    fwrite(message.str, (size_t)message.len, 1, file);
    fwrite("\n", 1, 1, file);

    if (ErrorHandler != nullptr)
    {
        ErrorHandler(severity, message.str, message.len);
    }
}
<|endoftext|>


<commit_before>#include "ComponentSystem.h"
#include "MeshUtility.h"
#include "ShadowAtlasMapRenderer.h"

using namespace Device;
using namespace Rendering;
using namespace Core;
using namespace Rendering::Light;
using namespace Rendering::Light::Buffer;
using namespace Rendering::Geometry;
using namespace Rendering::Shadow;
using namespace Rendering::Camera;
using namespace Rendering::Manager;
using namespace Rendering::Renderer;
using namespace Math;
using namespace Intersection;

void ComponentSystem::Initialize(DirectX& dx)
{
	GetManager_Direct<LightManager>().Initialize(dx);
	GetManager_Direct<ShadowManager>().Initialize(dx);
}

void ComponentSystem::UpdateBuffer(DirectX& dx,
	const TransformPool& transformPool,
	const ObjectManager& objectManager,
	const ShadowAtlasMapRenderer& shadowAtlasMapRenderer,
	const ObjectID::IndexHashMap& lightShaftIndexer)
{
	ShadowManager& shadowMgr	= GetManager_Direct<ShadowManager>();
	LightManager& lightMgr		= GetManager_Direct<LightManager>();
	MeshManager& meshMgr		= GetManager_Direct<MeshManager>();
	CameraManager& camMgr		= GetManager_Direct<CameraManager>();

	// Check Dirty
	{
		lightMgr.CheckDirtyLights(transformPool);
		shadowMgr.CheckDirtyWithCullShadows(camMgr, objectManager, lightMgr, transformPool);
		meshMgr.CheckDirty(transformPool, objectManager, camMgr);
	}

	bool isDirtyMesh = meshMgr.GetHasDirtyMeshes();
	if (meshMgr.GetHasDirtyMeshes())
	{
		uint value = 0xff7fffff;
		float fltMin = (*(float*)&value);

		value = 0x7f7fffff;
		float fltMax = (*(float*)&value);

		Vector3 worldMin = Vector3(fltMax, fltMax, fltMax);
		Vector3 worldMax = Vector3(fltMin, fltMin, fltMin);
		meshMgr.ComputeWorldSize(worldMin, worldMax, transformPool);
		_sceneBoundBox.SetMinMax(worldMin, worldMax);
	}

	meshMgr.UpdateTransformCB(dx, transformPool);

	// Update MainCamera
	{
		auto transform = transformPool.Find(camMgr.GetMainCamera().GetObjectID().Literal());
		assert(transform);

		camMgr.GetMainCamera().UpdateCB(dx, *transform);
		camMgr.GetMainCamera().ClassifyMesh(meshMgr.GetAllMeshPoolRefs(), objectManager, transformPool);
	}

	lightMgr.UpdateTransformBuffer(transformPool);
	lightMgr.UpdateParamBuffer(shadowMgr, lightShaftIndexer);
	lightMgr.UpdateSRBuffer(dx);

	shadowMgr.UpdateGlobalCB(dx, shadowAtlasMapRenderer);
	shadowMgr.UpdateConstBuffer(dx);
	shadowMgr.UpdateBuffer(lightMgr, transformPool, _sceneBoundBox);
	shadowMgr.UpdateSRBuffer(dx);

	// Clear Dirty
	{
		lightMgr.ClearDirty();
		shadowMgr.ClearDirty();
		meshMgr.ClearDirty();
	}
}

void ComponentSystem::Destroy()
{

}
<commit_msg>에러 수정<commit_after>#include "ComponentSystem.h"
#include "MeshUtility.h"
#include "ShadowAtlasMapRenderer.h"

using namespace Device;
using namespace Rendering;
using namespace Core;
using namespace Rendering::Light;
using namespace Rendering::Light::Buffer;
using namespace Rendering::Geometry;
using namespace Rendering::Shadow;
using namespace Rendering::Camera;
using namespace Rendering::Manager;
using namespace Rendering::Renderer;
using namespace Math;
using namespace Intersection;

void ComponentSystem::Initialize(DirectX& dx)
{
	GetManager_Direct<LightManager>().Initialize(dx);
	GetManager_Direct<ShadowManager>().Initialize(dx);
}

void ComponentSystem::UpdateBuffer(DirectX& dx,
	const TransformPool& transformPool,
	const ObjectManager& objectManager,
	const ShadowAtlasMapRenderer& shadowAtlasMapRenderer,
	const ObjectID::IndexHashMap& lightShaftIndexer)
{
	ShadowManager& shadowMgr	= GetManager_Direct<ShadowManager>();
	LightManager& lightMgr		= GetManager_Direct<LightManager>();
	MeshManager& meshMgr		= GetManager_Direct<MeshManager>();
	CameraManager& camMgr		= GetManager_Direct<CameraManager>();

	// Check Dirty
	{
		lightMgr.CheckDirtyLights(transformPool);
		shadowMgr.CheckDirtyWithCullShadows(camMgr, objectManager, lightMgr, transformPool);
		meshMgr.CheckDirty(transformPool, objectManager, camMgr);
	}

	bool isDirtyMesh = meshMgr.GetHasDirtyMeshes();
	if (meshMgr.GetHasDirtyMeshes())
	{
		uint value = 0xff7fffff;
		float fltMin = (*(float*)&value);

		value = 0x7f7fffff;
		float fltMax = (*(float*)&value);

		Vector3 worldMin = Vector3(fltMax, fltMax, fltMax);
		Vector3 worldMax = Vector3(fltMin, fltMin, fltMin);
		meshMgr.ComputeWorldSize(worldMin, worldMax, transformPool);
		_sceneBoundBox.SetMinMax(worldMin, worldMax);
	}

	meshMgr.UpdateTransformCB(dx, transformPool);

	// Update MainCamera
	{
		auto transform = transformPool.Find(camMgr.GetMainCamera().GetObjectID().Literal());
		assert(transform);

		camMgr.GetMainCamera().UpdateCB(dx, *transform);
		camMgr.GetMainCamera().ClassifyMesh(meshMgr.GetAllMeshPoolRefs(), objectManager, transformPool);
	}

	lightMgr.UpdateTransformBuffer(transformPool);
	lightMgr.UpdateParamBuffer(shadowMgr, lightShaftIndexer);
	lightMgr.UpdateSRBuffer(dx);

	shadowMgr.UpdateConstBuffer(dx, shadowAtlasMapRenderer);
	shadowMgr.UpdateBuffer(lightMgr, transformPool, _sceneBoundBox);
	shadowMgr.UpdateSRBuffer(dx);

	// Clear Dirty
	{
		lightMgr.ClearDirty();
		shadowMgr.ClearDirty();
		meshMgr.ClearDirty();
	}
}

void ComponentSystem::Destroy()
{

}
<|endoftext|>


<commit_before>/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#include <af/device.h>
#include <af/timing.h>
#include <algorithm>
#include <cmath>
#include <vector>

using namespace af;

// get current time
static inline timer time_now() {
#if defined(OS_WIN)
    timer time;
    QueryPerformanceCounter(&time.val);
#elif defined(OS_MAC)
    timer time = {mach_absolute_time()};
#elif defined(OS_LNX)
    timer time;
    gettimeofday(&time.val, NULL);
#endif
    return time;
}

// absolute difference between two times (in seconds)
static inline double time_seconds(timer start, timer end) {
#if defined(OS_WIN)
    if (start.val.QuadPart > end.val.QuadPart) {
        timer temp = end;
        end        = start;
        start      = temp;
    }
    timer system_freq;
    QueryPerformanceFrequency(&system_freq.val);
    return (double)(end.val.QuadPart - start.val.QuadPart) /
           system_freq.val.QuadPart;
#elif defined(OS_MAC)
    if (start.val > end.val) {
        timer temp = start;
        start      = end;
        end        = temp;
    }
    // calculate platform timing epoch
    thread_local mach_timebase_info_data_t info;
    mach_timebase_info(&info);
    double nano = (double)info.numer / (double)info.denom;
    return (end.val - start.val) * nano * 1e-9;
#elif defined(OS_LNX)
    struct timeval elapsed {};
    timersub(&start.val, &end.val, &elapsed);
    long sec  = elapsed.tv_sec;
    long usec = elapsed.tv_usec;
    double t  = sec + usec * 1e-6;
    return t >= 0 ? t : -t;
#endif
}

namespace af {

thread_local timer _timer_;

timer timer::start() { return _timer_ = time_now(); }
double timer::stop(timer start) { return time_seconds(start, time_now()); }
double timer::stop() { return time_seconds(_timer_, time_now()); }

double timeit(void (*fn)()) {
    // parameters
    static const int trials      = 10;  // trial runs
    static const int s_trials    = 5;   // trial runs
    static const double min_time = 1;   // seconds

    std::vector<double> sample_times(s_trials);

    // estimate time for a few samples
    for (int i = 0; i < s_trials; ++i) {
        sync();
        timer start = timer::start();
        fn();
        sync();
        sample_times[i] = timer::stop(start);
    }

    // Sort sample times and select the median time
    std::sort(sample_times.begin(), sample_times.end());

    double median_time = sample_times[s_trials / 2];

    // Run a bunch of batches of fn
    // Each batch runs trial runs before sync
    // If trials * median_time < min time,
    //   then run (min time / (trials * median_time)) batches
    // else
    //   run 1 batch
    int batches = static_cast<int>(ceilf(min_time / (trials * median_time)));
    double run_time = 0;

    for (int b = 0; b < batches; b++) {
        timer start = timer::start();
        for (int i = 0; i < trials; ++i) { fn(); }
        sync();
        run_time += timer::stop(start) / trials;
    }
    return run_time / batches;
}

}  // namespace af
<commit_msg>Improved precision of timeit<commit_after>/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#include <af/device.h>
#include <af/timing.h>
#include <algorithm>
#include <array>
#include <cmath>
#include <vector>

using namespace af;

// get current time
static inline timer time_now() {
#if defined(OS_WIN)
    timer time;
    QueryPerformanceCounter(&time.val);
#elif defined(OS_MAC)
    timer time = {mach_absolute_time()};
#elif defined(OS_LNX)
    timer time;
    gettimeofday(&time.val, NULL);
#endif
    return time;
}

// absolute difference between two times (in seconds)
static inline double time_seconds(timer start, timer end) {
#if defined(OS_WIN)
    if (start.val.QuadPart > end.val.QuadPart) {
        timer temp = end;
        end        = start;
        start      = temp;
    }
    timer system_freq;
    QueryPerformanceFrequency(&system_freq.val);
    return (double)(end.val.QuadPart - start.val.QuadPart) /
           system_freq.val.QuadPart;
#elif defined(OS_MAC)
    if (start.val > end.val) {
        timer temp = start;
        start      = end;
        end        = temp;
    }
    // calculate platform timing epoch
    thread_local mach_timebase_info_data_t info;
    mach_timebase_info(&info);
    double nano = (double)info.numer / (double)info.denom;
    return (end.val - start.val) * nano * 1e-9;
#elif defined(OS_LNX)
    struct timeval elapsed {};
    timersub(&start.val, &end.val, &elapsed);
    long sec  = elapsed.tv_sec;
    long usec = elapsed.tv_usec;
    double t  = sec + usec * 1e-6;
    return t >= 0 ? t : -t;
#endif
}

namespace af {

thread_local timer _timer_;

timer timer::start() { return _timer_ = time_now(); }
double timer::stop(timer start) { return time_seconds(start, time_now()); }
double timer::stop() { return time_seconds(_timer_, time_now()); }

double timeit(void (*fn)()) {
    // Minimum target duration to limit impact of clock precision
    constexpr double targetDurationPerTest = 0.050;
    // samples during which the nr of cycles are determined to obtain target
    // duration
    constexpr int testSamples = 2;
    // cycles needed to include CPU-GPU overlapping (if present)
    constexpr int minCycles = 3;
    // initial cycles used for the test samples
    int cycles = minCycles;
    // total number of real samples taken, of which the median is returned
    constexpr int nrSamples = 10;

    std::array<double, nrSamples> X;
    for (int s = -testSamples; s < nrSamples; ++s) {
        af::sync();
        af::timer start = af::timer::start();
        for (int i = cycles; i > 0; --i) { fn(); }
        af::sync();
        const double time = af::timer::stop(start);
        if (s >= 0) {
            // real sample, so store it for later processing
            X[s] = time;
        } else {
            // test sample, so improve nr cycles
            cycles = std::max(
                minCycles,
                static_cast<int>(trunc(targetDurationPerTest / time * cycles)));
        };
    }
    std::sort(X.begin(), X.end());
    // returns the median (iso of mean), to limit impact of outliers
    return X[nrSamples / 2] / cycles;
}

}  // namespace af
<|endoftext|>


<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2006 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.

You may alternatively use this source under the terms of a specific version of
the OGRE Unrestricted License provided you have obtained such a license from
Torus Knot Software Ltd.
-----------------------------------------------------------------------------
*/
/*
-----------------------------------------------------------------------------
Filename:    Fresnel.cpp
Description: Fresnel reflections and refractions
-----------------------------------------------------------------------------
*/

#include "ExampleApplication.h"
#include "OgreHardwarePixelBuffer.h"
// Hacky globals
Camera* theCam;
Entity* pPlaneEnt;
std::vector<Entity*> aboveWaterEnts;
std::vector<Entity*> belowWaterEnts;

// Fish!
#define NUM_FISH 30
#define NUM_FISH_WAYPOINTS 10
#define FISH_PATH_LENGTH 200
#define FISH_SCALE 1.2
AnimationState* fishAnimations[NUM_FISH];
SimpleSpline fishSplines[NUM_FISH];
Vector3 fishLastPosition[NUM_FISH];
SceneNode* fishNodes[NUM_FISH];
Real animTime = 0.0f;

Plane reflectionPlane;

class RefractionTextureListener : public RenderTargetListener
{
public:
    void preRenderTargetUpdate(const RenderTargetEvent& evt)
    {
        // Hide plane and objects above the water
        pPlaneEnt->setVisible(false);
        std::vector<Entity*>::iterator i, iend;
        iend = aboveWaterEnts.end();
        for (i = aboveWaterEnts.begin(); i != iend; ++i)
        {
            (*i)->setVisible(false);
        }

    }
    void postRenderTargetUpdate(const RenderTargetEvent& evt)
    {
        // Show plane and objects above the water
        pPlaneEnt->setVisible(true);
        std::vector<Entity*>::iterator i, iend;
        iend = aboveWaterEnts.end();
        for (i = aboveWaterEnts.begin(); i != iend; ++i)
        {
            (*i)->setVisible(true);
        }
    }

};
class ReflectionTextureListener : public RenderTargetListener
{
public:
    void preRenderTargetUpdate(const RenderTargetEvent& evt)
    {
        // Hide plane and objects below the water
        pPlaneEnt->setVisible(false);
        std::vector<Entity*>::iterator i, iend;
        iend = belowWaterEnts.end();
        for (i = belowWaterEnts.begin(); i != iend; ++i)
        {
            (*i)->setVisible(false);
        }
        theCam->enableReflection(reflectionPlane);

    }
    void postRenderTargetUpdate(const RenderTargetEvent& evt)
    {
        // Show plane and objects below the water
        pPlaneEnt->setVisible(true);
        std::vector<Entity*>::iterator i, iend;
        iend = belowWaterEnts.end();
        for (i = belowWaterEnts.begin(); i != iend; ++i)
        {
            (*i)->setVisible(true);
        }
        theCam->disableReflection();
    }

};

class FresnelFrameListener : public ExampleFrameListener
{
public:

    FresnelFrameListener(RenderWindow* win, Camera* cam)
        : ExampleFrameListener(win, cam, false, false)
    {}
    bool frameRenderingQueued(const FrameEvent &evt)
    {
        animTime += evt.timeSinceLastFrame;
        while (animTime > FISH_PATH_LENGTH)
            animTime -= FISH_PATH_LENGTH;

        for (size_t fish = 0; fish < NUM_FISH; ++fish)
        {
            // Animate the fish
            fishAnimations[fish]->addTime(evt.timeSinceLastFrame*2);
            // Move the fish
            Vector3 newPos = fishSplines[fish].interpolate(animTime / FISH_PATH_LENGTH);
            fishNodes[fish]->setPosition(newPos);
            // Work out the direction
            Vector3 direction = fishLastPosition[fish] - newPos;
            direction.normalise();
			// Test for opposite vectors
			Real d = 1.0f + Vector3::UNIT_X.dotProduct(direction);
			if (fabs(d) < 0.00001)
			{
				// Diametrically opposed vectors
				Quaternion orientation;
				orientation.FromAxes(Vector3::NEGATIVE_UNIT_X,
					Vector3::UNIT_Y, Vector3::NEGATIVE_UNIT_Z);
				fishNodes[fish]->setOrientation(orientation);
			}
			else
			{
				fishNodes[fish]->setOrientation(
					Vector3::UNIT_X.getRotationTo(direction));
			}
            fishLastPosition[fish] = newPos;

        }

        return ExampleFrameListener::frameRenderingQueued(evt);
    }

};

class FresnelApplication : public ExampleApplication
{
protected:
    RefractionTextureListener mRefractionListener;
    ReflectionTextureListener mReflectionListener;
public:
    FresnelApplication() {

    }

    ~FresnelApplication()
    {
    }
protected:

    // Just override the mandatory create scene method
    void createScene(void)
    {

        // Check prerequisites first
		const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities();
        if (!caps->hasCapability(RSC_VERTEX_PROGRAM) || !(caps->hasCapability(RSC_FRAGMENT_PROGRAM)))
        {
            OGRE_EXCEPT(1, "Your card does not support vertex and fragment programs, so cannot "
                "run this demo. Sorry!",
                "Fresnel::createScene");
        }
        else
        {
            if (!GpuProgramManager::getSingleton().isSyntaxSupported("arbfp1") &&
                !GpuProgramManager::getSingleton().isSyntaxSupported("ps_2_0") &&
				!GpuProgramManager::getSingleton().isSyntaxSupported("ps_1_4")
				)
            {
                OGRE_EXCEPT(1, "Your card does not support advanced fragment programs, "
                    "so cannot run this demo. Sorry!",
                "Fresnel::createScene");
            }
        }

        theCam = mCamera;
        theCam->setPosition(-50,125,760);
		theCam->setDirection (0,0,-1);
        // Set ambient light
        mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));

        // Create a point light
        Light* l = mSceneMgr->createLight("MainLight");
        l->setType(Light::LT_DIRECTIONAL);
        l->setDirection(-Vector3::UNIT_Y);

        Entity* pEnt;

        TexturePtr mTexture = TextureManager::getSingleton().createManual( "Refraction",
			ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D,
			512, 512, 0, PF_R8G8B8, TU_RENDERTARGET );
        //RenderTexture* rttTex = mRoot->getRenderSystem()->createRenderTexture( "Refraction", 512, 512 );
        RenderTarget *rttTex = mTexture->getBuffer()->getRenderTarget();

        {
            Viewport *v = rttTex->addViewport( mCamera );
            MaterialPtr mat = MaterialManager::getSingleton().getByName("Examples/FresnelReflectionRefraction");
            mat->getTechnique(0)->getPass(0)->getTextureUnitState(2)->setTextureName("Refraction");
            v->setOverlaysEnabled(false);
            rttTex->addListener(&mRefractionListener);
        }

		mTexture = TextureManager::getSingleton().createManual( "Reflection",
			ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D,
			512, 512, 0, PF_R8G8B8, TU_RENDERTARGET );
        //rttTex = mRoot->getRenderSystem()->createRenderTexture( "Reflection", 512, 512 );
        rttTex = mTexture->getBuffer()->getRenderTarget();
        {
            Viewport *v = rttTex->addViewport( mCamera );
            MaterialPtr mat = MaterialManager::getSingleton().getByName("Examples/FresnelReflectionRefraction");
            mat->getTechnique(0)->getPass(0)->getTextureUnitState(1)->setTextureName("Reflection");
            v->setOverlaysEnabled(false);
            rttTex->addListener(&mReflectionListener);
        }

        // Define a floor plane mesh
        reflectionPlane.normal = Vector3::UNIT_Y;
        reflectionPlane.d = 0;
        MeshManager::getSingleton().createPlane("ReflectPlane",
            ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
            reflectionPlane,
            700,1300,10,10,true,1,3,5,Vector3::UNIT_Z);
        pPlaneEnt = mSceneMgr->createEntity( "plane", "ReflectPlane" );
        pPlaneEnt->setMaterialName("Examples/FresnelReflectionRefraction");
        mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

        mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox");

        // My node to which all objects will be attached
        SceneNode* myRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();

		// above water entities
        pEnt = mSceneMgr->createEntity( "RomanBathUpper", "RomanBathUpper.mesh" );
		myRootNode->attachObject(pEnt);
        aboveWaterEnts.push_back(pEnt);

        pEnt = mSceneMgr->createEntity( "Columns", "Columns.mesh" );
		myRootNode->attachObject(pEnt);
        aboveWaterEnts.push_back(pEnt);

		Ogre::SceneNode *headNode = myRootNode->createChildSceneNode ();
		pEnt = mSceneMgr->createEntity( "OgreHead", "ogrehead.mesh" );
		pEnt->setMaterialName ("RomanBath/OgreStone");
        headNode->attachObject(pEnt);
		headNode->setPosition(-350,55,130);
		headNode->rotate(Vector3::UNIT_Y, Degree (90));
        aboveWaterEnts.push_back(pEnt);

		// below water entities
		pEnt = mSceneMgr->createEntity( "RomanBathLower", "RomanBathLower.mesh" );
        myRootNode->attachObject(pEnt);
        belowWaterEnts.push_back(pEnt);

		for (size_t fishNo = 0; fishNo < NUM_FISH; ++fishNo)
        {
            pEnt = mSceneMgr->createEntity("fish" + StringConverter::toString(fishNo), "fish.mesh");
            fishNodes[fishNo] = myRootNode->createChildSceneNode();
			fishNodes[fishNo]->setScale(FISH_SCALE, FISH_SCALE, FISH_SCALE);
            fishAnimations[fishNo] = pEnt->getAnimationState("swim");
            fishAnimations[fishNo]->setEnabled(true);
            fishNodes[fishNo]->attachObject(pEnt);
            belowWaterEnts.push_back(pEnt);

            // Generate a random selection of points for the fish to swim to
            fishSplines[fishNo].setAutoCalculate(false);
            Vector3 lastPos;
            for (size_t waypoint = 0; waypoint < NUM_FISH_WAYPOINTS; ++waypoint)
            {
                Vector3 pos = Vector3(
                    Math::SymmetricRandom() * 270, -10, Math::SymmetricRandom() * 700);
                if (waypoint > 0)
                {
                    // check this waypoint isn't too far, we don't want turbo-fish ;)
                    // since the waypoints are achieved every 5 seconds, half the length
                    // of the pond is ok
                    while ((lastPos - pos).length() > 750)
                    {
                        pos = Vector3(
                            Math::SymmetricRandom() * 270, -10, Math::SymmetricRandom() * 700);
                    }
                }
                fishSplines[fishNo].addPoint(pos);
                lastPos = pos;
            }
            // close the spline
            fishSplines[fishNo].addPoint(fishSplines[fishNo].getPoint(0));
            // recalc
            fishSplines[fishNo].recalcTangents();

        }

    }

    void createFrameListener(void)
    {
        mFrameListener= new FresnelFrameListener(mWindow, mCamera);
        mFrameListener->showDebugOverlay(true);
        mRoot->addFrameListener(mFrameListener);
    }

};

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main(int argc, char **argv)
#endif
{
    // Create application object
    FresnelApplication app;

    try {
        app.go();
    } catch( Exception& e ) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
        MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
        std::cerr << "An exception has occured: " << e.getFullDescription();
#endif
    }

    return 0;
}

#ifdef __cplusplus
}
#endif
<commit_msg>Fix license statement on Fresnel demo code - all samples are supposed to be public domain / free use.<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2006 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

You may use this sample code for anything you like, it is not covered by the
LGPL like the rest of the engine.
-----------------------------------------------------------------------------
*/
/*
-----------------------------------------------------------------------------
Filename:    Fresnel.cpp
Description: Fresnel reflections and refractions
-----------------------------------------------------------------------------
*/

#include "ExampleApplication.h"
#include "OgreHardwarePixelBuffer.h"
// Hacky globals
Camera* theCam;
Entity* pPlaneEnt;
std::vector<Entity*> aboveWaterEnts;
std::vector<Entity*> belowWaterEnts;

// Fish!
#define NUM_FISH 30
#define NUM_FISH_WAYPOINTS 10
#define FISH_PATH_LENGTH 200
#define FISH_SCALE 1.2
AnimationState* fishAnimations[NUM_FISH];
SimpleSpline fishSplines[NUM_FISH];
Vector3 fishLastPosition[NUM_FISH];
SceneNode* fishNodes[NUM_FISH];
Real animTime = 0.0f;

Plane reflectionPlane;

class RefractionTextureListener : public RenderTargetListener
{
public:
    void preRenderTargetUpdate(const RenderTargetEvent& evt)
    {
        // Hide plane and objects above the water
        pPlaneEnt->setVisible(false);
        std::vector<Entity*>::iterator i, iend;
        iend = aboveWaterEnts.end();
        for (i = aboveWaterEnts.begin(); i != iend; ++i)
        {
            (*i)->setVisible(false);
        }

    }
    void postRenderTargetUpdate(const RenderTargetEvent& evt)
    {
        // Show plane and objects above the water
        pPlaneEnt->setVisible(true);
        std::vector<Entity*>::iterator i, iend;
        iend = aboveWaterEnts.end();
        for (i = aboveWaterEnts.begin(); i != iend; ++i)
        {
            (*i)->setVisible(true);
        }
    }

};
class ReflectionTextureListener : public RenderTargetListener
{
public:
    void preRenderTargetUpdate(const RenderTargetEvent& evt)
    {
        // Hide plane and objects below the water
        pPlaneEnt->setVisible(false);
        std::vector<Entity*>::iterator i, iend;
        iend = belowWaterEnts.end();
        for (i = belowWaterEnts.begin(); i != iend; ++i)
        {
            (*i)->setVisible(false);
        }
        theCam->enableReflection(reflectionPlane);

    }
    void postRenderTargetUpdate(const RenderTargetEvent& evt)
    {
        // Show plane and objects below the water
        pPlaneEnt->setVisible(true);
        std::vector<Entity*>::iterator i, iend;
        iend = belowWaterEnts.end();
        for (i = belowWaterEnts.begin(); i != iend; ++i)
        {
            (*i)->setVisible(true);
        }
        theCam->disableReflection();
    }

};

class FresnelFrameListener : public ExampleFrameListener
{
public:

    FresnelFrameListener(RenderWindow* win, Camera* cam)
        : ExampleFrameListener(win, cam, false, false)
    {}
    bool frameRenderingQueued(const FrameEvent &evt)
    {
        animTime += evt.timeSinceLastFrame;
        while (animTime > FISH_PATH_LENGTH)
            animTime -= FISH_PATH_LENGTH;

        for (size_t fish = 0; fish < NUM_FISH; ++fish)
        {
            // Animate the fish
            fishAnimations[fish]->addTime(evt.timeSinceLastFrame*2);
            // Move the fish
            Vector3 newPos = fishSplines[fish].interpolate(animTime / FISH_PATH_LENGTH);
            fishNodes[fish]->setPosition(newPos);
            // Work out the direction
            Vector3 direction = fishLastPosition[fish] - newPos;
            direction.normalise();
			// Test for opposite vectors
			Real d = 1.0f + Vector3::UNIT_X.dotProduct(direction);
			if (fabs(d) < 0.00001)
			{
				// Diametrically opposed vectors
				Quaternion orientation;
				orientation.FromAxes(Vector3::NEGATIVE_UNIT_X,
					Vector3::UNIT_Y, Vector3::NEGATIVE_UNIT_Z);
				fishNodes[fish]->setOrientation(orientation);
			}
			else
			{
				fishNodes[fish]->setOrientation(
					Vector3::UNIT_X.getRotationTo(direction));
			}
            fishLastPosition[fish] = newPos;

        }

        return ExampleFrameListener::frameRenderingQueued(evt);
    }

};

class FresnelApplication : public ExampleApplication
{
protected:
    RefractionTextureListener mRefractionListener;
    ReflectionTextureListener mReflectionListener;
public:
    FresnelApplication() {

    }

    ~FresnelApplication()
    {
    }
protected:

    // Just override the mandatory create scene method
    void createScene(void)
    {

        // Check prerequisites first
		const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities();
        if (!caps->hasCapability(RSC_VERTEX_PROGRAM) || !(caps->hasCapability(RSC_FRAGMENT_PROGRAM)))
        {
            OGRE_EXCEPT(1, "Your card does not support vertex and fragment programs, so cannot "
                "run this demo. Sorry!",
                "Fresnel::createScene");
        }
        else
        {
            if (!GpuProgramManager::getSingleton().isSyntaxSupported("arbfp1") &&
                !GpuProgramManager::getSingleton().isSyntaxSupported("ps_2_0") &&
				!GpuProgramManager::getSingleton().isSyntaxSupported("ps_1_4")
				)
            {
                OGRE_EXCEPT(1, "Your card does not support advanced fragment programs, "
                    "so cannot run this demo. Sorry!",
                "Fresnel::createScene");
            }
        }

        theCam = mCamera;
        theCam->setPosition(-50,125,760);
		theCam->setDirection (0,0,-1);
        // Set ambient light
        mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));

        // Create a point light
        Light* l = mSceneMgr->createLight("MainLight");
        l->setType(Light::LT_DIRECTIONAL);
        l->setDirection(-Vector3::UNIT_Y);

        Entity* pEnt;

        TexturePtr mTexture = TextureManager::getSingleton().createManual( "Refraction",
			ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D,
			512, 512, 0, PF_R8G8B8, TU_RENDERTARGET );
        //RenderTexture* rttTex = mRoot->getRenderSystem()->createRenderTexture( "Refraction", 512, 512 );
        RenderTarget *rttTex = mTexture->getBuffer()->getRenderTarget();

        {
            Viewport *v = rttTex->addViewport( mCamera );
            MaterialPtr mat = MaterialManager::getSingleton().getByName("Examples/FresnelReflectionRefraction");
            mat->getTechnique(0)->getPass(0)->getTextureUnitState(2)->setTextureName("Refraction");
            v->setOverlaysEnabled(false);
            rttTex->addListener(&mRefractionListener);
        }

		mTexture = TextureManager::getSingleton().createManual( "Reflection",
			ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D,
			512, 512, 0, PF_R8G8B8, TU_RENDERTARGET );
        //rttTex = mRoot->getRenderSystem()->createRenderTexture( "Reflection", 512, 512 );
        rttTex = mTexture->getBuffer()->getRenderTarget();
        {
            Viewport *v = rttTex->addViewport( mCamera );
            MaterialPtr mat = MaterialManager::getSingleton().getByName("Examples/FresnelReflectionRefraction");
            mat->getTechnique(0)->getPass(0)->getTextureUnitState(1)->setTextureName("Reflection");
            v->setOverlaysEnabled(false);
            rttTex->addListener(&mReflectionListener);
        }

        // Define a floor plane mesh
        reflectionPlane.normal = Vector3::UNIT_Y;
        reflectionPlane.d = 0;
        MeshManager::getSingleton().createPlane("ReflectPlane",
            ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
            reflectionPlane,
            700,1300,10,10,true,1,3,5,Vector3::UNIT_Z);
        pPlaneEnt = mSceneMgr->createEntity( "plane", "ReflectPlane" );
        pPlaneEnt->setMaterialName("Examples/FresnelReflectionRefraction");
        mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt);

        mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox");

        // My node to which all objects will be attached
        SceneNode* myRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();

		// above water entities
        pEnt = mSceneMgr->createEntity( "RomanBathUpper", "RomanBathUpper.mesh" );
		myRootNode->attachObject(pEnt);
        aboveWaterEnts.push_back(pEnt);

        pEnt = mSceneMgr->createEntity( "Columns", "Columns.mesh" );
		myRootNode->attachObject(pEnt);
        aboveWaterEnts.push_back(pEnt);

		Ogre::SceneNode *headNode = myRootNode->createChildSceneNode ();
		pEnt = mSceneMgr->createEntity( "OgreHead", "ogrehead.mesh" );
		pEnt->setMaterialName ("RomanBath/OgreStone");
        headNode->attachObject(pEnt);
		headNode->setPosition(-350,55,130);
		headNode->rotate(Vector3::UNIT_Y, Degree (90));
        aboveWaterEnts.push_back(pEnt);

		// below water entities
		pEnt = mSceneMgr->createEntity( "RomanBathLower", "RomanBathLower.mesh" );
        myRootNode->attachObject(pEnt);
        belowWaterEnts.push_back(pEnt);

		for (size_t fishNo = 0; fishNo < NUM_FISH; ++fishNo)
        {
            pEnt = mSceneMgr->createEntity("fish" + StringConverter::toString(fishNo), "fish.mesh");
            fishNodes[fishNo] = myRootNode->createChildSceneNode();
			fishNodes[fishNo]->setScale(FISH_SCALE, FISH_SCALE, FISH_SCALE);
            fishAnimations[fishNo] = pEnt->getAnimationState("swim");
            fishAnimations[fishNo]->setEnabled(true);
            fishNodes[fishNo]->attachObject(pEnt);
            belowWaterEnts.push_back(pEnt);

            // Generate a random selection of points for the fish to swim to
            fishSplines[fishNo].setAutoCalculate(false);
            Vector3 lastPos;
            for (size_t waypoint = 0; waypoint < NUM_FISH_WAYPOINTS; ++waypoint)
            {
                Vector3 pos = Vector3(
                    Math::SymmetricRandom() * 270, -10, Math::SymmetricRandom() * 700);
                if (waypoint > 0)
                {
                    // check this waypoint isn't too far, we don't want turbo-fish ;)
                    // since the waypoints are achieved every 5 seconds, half the length
                    // of the pond is ok
                    while ((lastPos - pos).length() > 750)
                    {
                        pos = Vector3(
                            Math::SymmetricRandom() * 270, -10, Math::SymmetricRandom() * 700);
                    }
                }
                fishSplines[fishNo].addPoint(pos);
                lastPos = pos;
            }
            // close the spline
            fishSplines[fishNo].addPoint(fishSplines[fishNo].getPoint(0));
            // recalc
            fishSplines[fishNo].recalcTangents();

        }

    }

    void createFrameListener(void)
    {
        mFrameListener= new FresnelFrameListener(mWindow, mCamera);
        mFrameListener->showDebugOverlay(true);
        mRoot->addFrameListener(mFrameListener);
    }

};

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main(int argc, char **argv)
#endif
{
    // Create application object
    FresnelApplication app;

    try {
        app.go();
    } catch( Exception& e ) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
        MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
        std::cerr << "An exception has occured: " << e.getFullDescription();
#endif
    }

    return 0;
}

#ifdef __cplusplus
}
#endif
<|endoftext|>


<commit_before><commit_msg>Planning: fixed a bug to calculate speed limits in st_boundary_mapper.<commit_after><|endoftext|>


<commit_before>#include <iostream>

int main(int argc, char* argv[])
{
  double* n = new double[100];
  n[100] = 22; // out of bounds
  delete n; // should be delete[]
  n[0] = 5; // use after free
}

<commit_msg>remove iostream include<commit_after>int main(int argc, char* argv[])
{
  double* n = new double[100];
  n[100] = 22; // out of bounds
  delete n; // should be delete[]
  n[0] = 5; // use after free
}

<|endoftext|>


<commit_before>#include "robot_name.h"
#include <iomanip>
#include <sstream>
#include <stdexcept>

using namespace std;

namespace robot_name
{

namespace
{

string next_prefix(string prefix)
{
    string next{prefix};
    const string letters{"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"};
    if (prefix[1] == letters.back()) {
        if (prefix[0] == letters.back()) {
            throw range_error("prefix combinations exhausted");
        }
        next[1] = letters[0];
        next[0] = letters[letters.find(next[0]) + 1];
    } else {
        next[1] = letters[letters.find(next[1]) + 1];
    }
    return next;
}

string generate_name()
{
    static string prefix = "AA";
    static int unit_number = 0;
    ostringstream buff;
    if (unit_number > 999) {
        prefix = next_prefix(prefix);
        unit_number = 0;
    }
    buff << prefix << setw(3) << setfill('0') << unit_number++;
    return buff.str();
}

}

robot::robot()
    : name_(generate_name())
{
}

void robot::reset()
{
    name_ = generate_name();
}

}
<commit_msg>Refactor: Prefer input arguments by const reference<commit_after>#include "robot_name.h"
#include <iomanip>
#include <sstream>
#include <stdexcept>

using namespace std;

namespace robot_name
{

namespace
{

string next_prefix(string const &prefix)
{
    string next{prefix};
    const string letters{"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"};
    if (prefix[1] == letters.back()) {
        if (prefix[0] == letters.back()) {
            throw range_error("prefix combinations exhausted");
        }
        next[1] = letters[0];
        next[0] = letters[letters.find(next[0]) + 1];
    } else {
        next[1] = letters[letters.find(next[1]) + 1];
    }
    return next;
}

string generate_name()
{
    static string prefix = "AA";
    static int unit_number = 0;
    ostringstream buff;
    if (unit_number > 999) {
        prefix = next_prefix(prefix);
        unit_number = 0;
    }
    buff << prefix << setw(3) << setfill('0') << unit_number++;
    return buff.str();
}

}

robot::robot()
    : name_(generate_name())
{
}

void robot::reset()
{
    name_ = generate_name();
}

}
<|endoftext|>


<commit_before>// -*- coding: us-ascii-unix -*-
// Copyright 2015 Lukas Kemmer
//
// Licensed under the Apache License, Version 2.0 (the "License"); you
// may not use this file except in compliance with the License. You
// may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.

#include <string> // std::stod
#include "bitmap/bitmap.hh"
#include "geo/geo-func.hh" // floated
#include "geo/int-point.hh"
#include "geo/int-size.hh"
#include "gui/grid-dialog.hh"
#include "gui/paint-dialog.hh"
#include "gui/static-bitmap.hh"
#include "gui/ui-constants.hh"
#include "util/color-bitmap-util.hh"
#include "util-wx/fwd-wx.hh"
#include "util-wx/fwd-bind.hh"
#include "util-wx/layout-wx.hh"

namespace faint{

static coord to_coord(const utf8_string& s, coord defaultValue){
  try{
    return std::stod(s.c_str());
  }
  catch (const std::exception&){
    return defaultValue;
  }
}

Optional<Grid> show_grid_dialog(wxWindow* parent,
  const Grid& oldGrid,
  DialogContext& c)
{
  Grid grid = oldGrid;
  auto dlg = fixed_size_dialog(parent, "Grid");

  auto make_edit = [&](coord value){
    auto edit = create_text_control(dlg.get(), "");
    fit_size_to(edit, "10000");
    set_number_text(edit, value, 2_dec, Signal::NO);
    return edit;
  };

  // Spacing edit field
  auto labelSpacing = create_label(dlg.get(), "&Spacing", TextAlign::RIGHT);
  auto editSpacing = make_edit(grid.Spacing());

  // Anchor edit fields
  Point anchor = grid.Anchor();

  auto labelX = create_label(dlg, "&X", TextAlign::RIGHT);
  make_uniformly_sized({labelSpacing, labelX});
  auto editX = make_edit(anchor.x);

  auto labelY = create_label(dlg.get(), "&Y");
  auto editY = make_edit(anchor.y);

  // Dashes-checkbox
  auto dashed = create_checkbox(dlg, "&Dashed lines", grid.Dashed());

  using namespace layout;
  auto spacingRow = create_row(OuterSpacing(0), ui::item_spacing,
    {labelSpacing, raw(editSpacing)});

  auto anchorRow = create_row(OuterSpacing(0), ui::item_spacing,
    {labelX, raw(editX),
     labelY, raw(editY)});

  auto make_color_bitmap = [&](){
    return color_bitmap(grid.GetColor(), IntSize(20, 20));
  };

  auto colorLabel = create_label(dlg, "Line color");
  auto colorButton = new StaticBitmap(raw(dlg.get()), make_color_bitmap());

  events::on_mouse_left_down(colorButton,
    [&](const IntPoint&){
      show_color_only_dialog(raw(dlg.get()), "Grid color",
        grid.GetColor(), c).Visit(
          [&](const Color& c){
            grid.SetColor(c);
            colorButton->SetBitmap(make_color_bitmap());
          });
    });

  set_sizer(dlg.get(),
    create_column({
      spacingRow,
      anchorRow,
      create_row({raw(dashed)}),
      create_row({raw(colorButton), colorLabel}),
      center(create_row({create_ok_cancel_buttons(dlg.get())}))}));

  auto get_grid = [&](){
    return Grid(true, // Enabled
      to_coord(get_text(editSpacing), grid.Spacing()),
      grid.GetColor(),
      Point(to_coord(get_text(editX), anchor.x),
        to_coord(get_text(editY), anchor.y)),
      get(dashed));
  };

  center_over_parent(dlg);
  return c.ShowModal(*dlg) == DialogChoice::OK ?
    option(get_grid()) : no_option();
}

} // namespace
<commit_msg>Allow clicking text in grid dialog<commit_after>// -*- coding: us-ascii-unix -*-
// Copyright 2015 Lukas Kemmer
//
// Licensed under the Apache License, Version 2.0 (the "License"); you
// may not use this file except in compliance with the License. You
// may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.

#include <string> // std::stod
#include "bitmap/bitmap.hh"
#include "geo/geo-func.hh" // floated
#include "geo/int-point.hh"
#include "geo/int-size.hh"
#include "gui/accelerator-entry.hh"
#include "gui/grid-dialog.hh"
#include "gui/paint-dialog.hh"
#include "gui/static-bitmap.hh"
#include "gui/ui-constants.hh"
#include "util/color-bitmap-util.hh"
#include "util-wx/fwd-wx.hh"
#include "util-wx/fwd-bind.hh"
#include "util-wx/layout-wx.hh"
#include "util-wx/key-codes.hh"

namespace faint{

static coord to_coord(const utf8_string& s, coord defaultValue){
  try{
    return std::stod(s.c_str());
  }
  catch (const std::exception&){
    return defaultValue;
  }
}

Optional<Grid> show_grid_dialog(wxWindow* parent,
  const Grid& oldGrid,
  DialogContext& c)
{
  Grid grid = oldGrid;
  auto dlg = fixed_size_dialog(parent, "Grid");

  auto make_edit = [&](coord value){
    auto edit = create_text_control(dlg.get(), "");
    fit_size_to(edit, "10000");
    set_number_text(edit, value, 2_dec, Signal::NO);
    return edit;
  };

  // Spacing edit field
  auto labelSpacing = create_label(dlg.get(), "&Spacing", TextAlign::RIGHT);
  auto editSpacing = make_edit(grid.Spacing());

  // Anchor edit fields
  Point anchor = grid.Anchor();

  auto labelX = create_label(dlg, "&X", TextAlign::RIGHT);
  make_uniformly_sized({labelSpacing, labelX});
  auto editX = make_edit(anchor.x);

  auto labelY = create_label(dlg.get(), "&Y");
  auto editY = make_edit(anchor.y);

  // Dashes-checkbox
  auto dashed = create_checkbox(dlg, "&dashed lines", grid.Dashed());

  using namespace layout;
  auto spacingRow = create_row(OuterSpacing(0), ui::item_spacing,
    {labelSpacing, raw(editSpacing)});

  auto anchorRow = create_row(OuterSpacing(0), ui::item_spacing,
    {labelX, raw(editX),
     labelY, raw(editY)});

  auto make_color_bitmap = [&](){
    return color_bitmap(grid.GetColor(), IntSize(20, 20));
  };

  auto colorLabel = create_label(dlg, "&color");
  auto colorButton = new StaticBitmap(raw(dlg.get()), make_color_bitmap());
  set_size(colorButton, get_size(dashed));
  set_stock_cursor(colorButton, wxCURSOR_HAND);
  set_stock_cursor(colorLabel, wxCURSOR_HAND);

  auto pick_grid_color =  [&](){
    show_color_only_dialog(raw(dlg), "Grid color",
      grid.GetColor(), c).Visit(
        [&](const Color& c){
          grid.SetColor(c);
          colorButton->SetBitmap(make_color_bitmap());
        });
  };

  set_accelerators(raw(dlg), {
   {key::C, Alt+key::C, pick_grid_color}});

  events::on_mouse_left_down(colorButton,
    [&](const IntPoint&){
      pick_grid_color();
    });

  events::on_mouse_left_down(colorLabel,
    [&](const IntPoint&){
      pick_grid_color();
    });

  set_sizer(dlg.get(),
    create_column({
      spacingRow,
      anchorRow,
      create_row({raw(dashed)}),
      create_row({raw(colorButton), colorLabel}),
      center(create_row({create_ok_cancel_buttons(dlg.get())}))}));

  auto get_grid = [&](){
    return Grid(true, // Enabled
      to_coord(get_text(editSpacing), grid.Spacing()),
      grid.GetColor(),
      Point(to_coord(get_text(editX), anchor.x),
        to_coord(get_text(editY), anchor.y)),
      get(dashed));
  };

  center_over_parent(dlg);
  return c.ShowModal(*dlg) == DialogChoice::OK ?
    option(get_grid()) : no_option();
}

} // namespace
<|endoftext|>


<commit_before>/*
 2-12-2011
 Spark Fun Electronics 2011
 Nathan Seidle

 This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).

 This code works with the VS1053 Breakout Board and controls the VS1053 in what is called Real Time MIDI mode.
 To get the VS1053 into RT MIDI mode, power up the VS1053 breakout board with GPIO0 tied low, GPIO1 tied high.

 I use the NewSoftSerial library to send out the MIDI serial at 31250bps. This allows me to print regular messages
 for debugging to the terminal window. This helped me out a ton.

 5V : VS1053 VCC
 GND : VS1053 GND
 D3 (SoftSerial TX) : VS1053 RX
 D4 : VS1053 RESET

 Attach a headphone breakout board to the VS1053:
 VS1053 LEFT : TSH
 VS1053 RIGHT : RSH
 VS1053 GBUF : GND

 When in the drum bank (0x78), there are not different instruments, only different notes.
 To play the different sounds, select an instrument # like 5, then play notes 27 to 87.

 To play "Sticks" (31):
 talkMIDI(0xB0, 0, 0x78); //Bank select: drums
 talkMIDI(0xC0, 5, 0); //Set instrument number
 //Play note on channel 1 (0x90), some note value (note), middle velocity (60):
 noteOn(0, 31, 60);

 */
 /* NEEDED??

 */

#include "MidiDevice.h"

#include "looper/EventLooper.h"

#ifdef IS_ARDUINO_SHIM
    #include "ofxMidi.h"

ofxMidiOut midiOut;

#endif

//SoftwareSerial mySerial(2, 3);

MidiDevice::MidiDevice() {

#ifdef IS_ARDUINO_SHIM
	// print the available output ports to the console
	midiOut.listPorts(); // via instance
	//ofxMidiOut::listPorts(); // via static too

	// connect
	midiOut.openPort(0);	// by number
	//midiOut.openPort("IAC Driver Pure Data In");	// by name

#else
    #if USE_HARDWARE_SERIAL
        // Ok, the Serial object is not actually the HardwareSerial class, it's something else.
        //this->mySerial = &Serial;
        // do some tricky de-re-referencing to get around it.
        #if IS_DRUMPANTS
	        #define mySerial (&Serial2)
		#else
			#define mySerial (&Serial)
		#endif
    #else
        this->mySerial = new SoftwareSerial(2, 3, false); //Soft TX on 3, we don't use RX in this code
    #endif
#endif

	this->bank = 0x78; // start with DRUMS!
	this->instrument = 0; // was 30 for piano

	this->listener = NULL;
}

MidiDevice::~MidiDevice() {
	//delete this->mySerial;
}

void MidiDevice::setup() {
	//Serial.println("Initializing MidiDevice");

	//Serial.begin(57600);

	//Setup soft serial for MIDI control
	mySerial->begin(BAUD_RATE_MIDI);

#ifndef IS_ARDUINO_SHIM
	//Reset the VS1053
	pinMode(RESET_MIDI_PIN, OUTPUT);
	digitalWrite(RESET_MIDI_PIN, LOW);
	delay(100);
	digitalWrite(RESET_MIDI_PIN, HIGH);
	delay(100);
#endif

	this->setVolume(0, 126); //0xB0 is channel message, set channel volume to near max (127)

	// give us some reverb!
	this->talkMIDI(0xB0, 0x0c, 0xEF); // REVERB decay
	this->talkMIDI(0xB0, 0x5b, 0xA3); // REVERB level

	this->setBank(0, this->bank); //Select the bank of really fun sounds

	//For this bank 0x78, the instrument does not matter, only the note
	//setInstrument(instrument); //Set instrument number. 0xC0 is a 1 data byte command

	//Serial.println("MidiDevice now setup");
}

void MidiDevice::setBank(byte channel, byte bank, byte instrument) {
	DEBUG_PRINT_NUM("setBank: ", bank)
	talkMIDI((0xB0 | channel), 0, bank); //Select the bank of really fun sounds

	this->bank = bank;

	setInstrument(channel, instrument);
}
byte MidiDevice::getBank() {
	return bank;
}

void MidiDevice::setInstrument(byte channel, byte inst) {
	DEBUG_PRINT_NUM("setInstrument: ", inst)
	talkMIDI((0xC0 | channel), inst, 0); //Set instrument number. 0xC0 is a 1 data byte command

	this->instrument = inst;
}
byte MidiDevice::getInstrument() {
	return this->instrument;
}

void MidiDevice::setVolume(byte channel, byte vol) {
	talkMIDI((0xB0 | channel), 0x07, vol);
}

/*
void loop() {
  while(Serial.available() == 0) ;

  int note = Serial.read();
  //Good sounding notes range from 27 to 87
  //So let's take the letter and range it to 27
  note -= 'a';
  note += 57;

  Serial.print("Note=");
  Serial.println(note, DEC);

  //For this bank 0x78, the instrument does not matter, only the note
  noteOn(0, note, 60);

  //Note will dissapate automatically
}
*/

//Send a MIDI note-on message.  Like pressing a piano key
//channel ranges from 0-15
void MidiDevice::noteOn(byte channel, byte note, byte attack_velocity) {
	//DEBUG_PRINT_NUMS("MIDI noteOn: ", note, attack_velocity);

	talkMIDI( (0x90 | channel), note, attack_velocity);
}

//Send a MIDI note-off message.  Like releasing a piano key
void MidiDevice::noteOff(byte channel, byte note, byte release_velocity) {
	//DEBUG_PRINT_NUMS("MIDI noteOff: ", note, release_velocity);

 	talkMIDI( (0x80 | channel), note, release_velocity);
}

//Plays a MIDI note. Doesn't check to see that cmd is greater than 127, or that data values are less than 127
// if isSilent is true, it will not alert the listener.
void MidiDevice::talkMIDI(byte cmd, byte data1, byte data2, bool isSilent) {

    //Some commands only have one data byte. All cmds less than 0xBn have 2 data bytes
    //(sort of: http://253.ccarh.org/handout/midiprotocol/)
    //if( (cmd & 0xF0) <= 0xB0)
    bool hasSecondArg = ((cmd & 0xF0) <= 0xB0 || (cmd & 0xF0) == 0xE0);

#ifdef IS_ARDUINO_SHIM
    midiOut << cmd << data1;

    if (hasSecondArg)
        midiOut << data2;

#else
  digitalWrite(LED_PIN, HIGH);
  mySerial->write(cmd);//print(cmd, BYTE);
  mySerial->write(data1);//print(data1, BYTE);

  if (hasSecondArg)
    mySerial->write(data2);//print(data2, BYTE);

  digitalWrite(LED_PIN, LOW);
#endif

  if (!isSilent && this->listener != NULL) {
	this->listener->onSendOutput(cmd, data1, data2);
  }
}

void MidiDevice::note(bool isOn, int channel, int note, int velocity) {
	// i assumed the truncation from int to byte would take care of this.
	// ProTip: don't trust C++ to do anything reasonable.
	channel = min(channel, 127);
	note = min(note, 127);
	velocity = min(velocity, 127);

	if (isOn)
		noteOn((byte)channel, (byte)note, (byte)velocity);
	else
		noteOff((byte)channel, (byte)note, 0); //TODO: velocity or 0?
}

/*** for looper listeners ***/
void MidiDevice::setListener(EventLooper* l) {
	this->listener = l;
}

<commit_msg>Added BLE+MIDI support for beta pants<commit_after>/*
 2-12-2011
 Spark Fun Electronics 2011
 Nathan Seidle

 This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).

 This code works with the VS1053 Breakout Board and controls the VS1053 in what is called Real Time MIDI mode.
 To get the VS1053 into RT MIDI mode, power up the VS1053 breakout board with GPIO0 tied low, GPIO1 tied high.

 I use the NewSoftSerial library to send out the MIDI serial at 31250bps. This allows me to print regular messages
 for debugging to the terminal window. This helped me out a ton.

 5V : VS1053 VCC
 GND : VS1053 GND
 D3 (SoftSerial TX) : VS1053 RX
 D4 : VS1053 RESET

 Attach a headphone breakout board to the VS1053:
 VS1053 LEFT : TSH
 VS1053 RIGHT : RSH
 VS1053 GBUF : GND

 When in the drum bank (0x78), there are not different instruments, only different notes.
 To play the different sounds, select an instrument # like 5, then play notes 27 to 87.

 To play "Sticks" (31):
 talkMIDI(0xB0, 0, 0x78); //Bank select: drums
 talkMIDI(0xC0, 5, 0); //Set instrument number
 //Play note on channel 1 (0x90), some note value (note), middle velocity (60):
 noteOn(0, 31, 60);

 */
 /* NEEDED??

 */

#include "MidiDevice.h"

#include "looper/EventLooper.h"

#ifdef IS_ARDUINO_SHIM
    #include "ofxMidi.h"

ofxMidiOut midiOut;

#endif

//SoftwareSerial mySerial(2, 3);

MidiDevice::MidiDevice() {

#ifdef IS_ARDUINO_SHIM
	// print the available output ports to the console
	midiOut.listPorts(); // via instance
	//ofxMidiOut::listPorts(); // via static too

	// connect
	midiOut.openPort(0);	// by number
	//midiOut.openPort("IAC Driver Pure Data In");	// by name

#else
    #if USE_HARDWARE_SERIAL
        // Ok, the Serial object is not actually the HardwareSerial class, it's something else.
        //this->mySerial = &Serial;
        // do some tricky de-re-referencing to get around it.
        #if IS_DRUMPANTS
	        #define mySerial (&Serial2)
		#else
			#define mySerial (&Serial)
		#endif
    #else
        this->mySerial = new SoftwareSerial(2, 3, false); //Soft TX on 3, we don't use RX in this code
    #endif
#endif

	this->bank = 0x78; // start with DRUMS!
	this->instrument = 0; // was 30 for piano

	this->listener = NULL;
}

MidiDevice::~MidiDevice() {
	//delete this->mySerial;
}

void MidiDevice::setup() {
	//Serial.println("Initializing MidiDevice");

	//Serial.begin(57600);

	//Setup soft serial for MIDI control
	mySerial->begin(BAUD_RATE_MIDI);

#if IS_DRUMPANTS
	// also send to BLE
	Serial1.begin(BAUD_RATE_BLUETOOTH_LE);
#endif

#ifndef IS_ARDUINO_SHIM
	//Reset the VS1053
	pinMode(RESET_MIDI_PIN, OUTPUT);
	digitalWrite(RESET_MIDI_PIN, LOW);
	delay(100);
	digitalWrite(RESET_MIDI_PIN, HIGH);
	delay(100);
#endif

	this->setVolume(0, 126); //0xB0 is channel message, set channel volume to near max (127)

	// give us some reverb!
	this->talkMIDI(0xB0, 0x0c, 0xEF); // REVERB decay
	this->talkMIDI(0xB0, 0x5b, 0xA3); // REVERB level

	this->setBank(0, this->bank); //Select the bank of really fun sounds

	//For this bank 0x78, the instrument does not matter, only the note
	//setInstrument(instrument); //Set instrument number. 0xC0 is a 1 data byte command

	//Serial.println("MidiDevice now setup");
}

void MidiDevice::setBank(byte channel, byte bank, byte instrument) {
	DEBUG_PRINT_NUM("setBank: ", bank)
	talkMIDI((0xB0 | channel), 0, bank); //Select the bank of really fun sounds

	this->bank = bank;

	setInstrument(channel, instrument);
}
byte MidiDevice::getBank() {
	return bank;
}

void MidiDevice::setInstrument(byte channel, byte inst) {
	DEBUG_PRINT_NUM("setInstrument: ", inst)
	talkMIDI((0xC0 | channel), inst, 0); //Set instrument number. 0xC0 is a 1 data byte command

	this->instrument = inst;
}
byte MidiDevice::getInstrument() {
	return this->instrument;
}

void MidiDevice::setVolume(byte channel, byte vol) {
	talkMIDI((0xB0 | channel), 0x07, vol);
}

/*
void loop() {
  while(Serial.available() == 0) ;

  int note = Serial.read();
  //Good sounding notes range from 27 to 87
  //So let's take the letter and range it to 27
  note -= 'a';
  note += 57;

  Serial.print("Note=");
  Serial.println(note, DEC);

  //For this bank 0x78, the instrument does not matter, only the note
  noteOn(0, note, 60);

  //Note will dissapate automatically
}
*/

//Send a MIDI note-on message.  Like pressing a piano key
//channel ranges from 0-15
void MidiDevice::noteOn(byte channel, byte note, byte attack_velocity) {
	//DEBUG_PRINT_NUMS("MIDI noteOn: ", note, attack_velocity);

	talkMIDI( (0x90 | channel), note, attack_velocity);
}

//Send a MIDI note-off message.  Like releasing a piano key
void MidiDevice::noteOff(byte channel, byte note, byte release_velocity) {
	//DEBUG_PRINT_NUMS("MIDI noteOff: ", note, release_velocity);

 	talkMIDI( (0x80 | channel), note, release_velocity);
}

//Plays a MIDI note. Doesn't check to see that cmd is greater than 127, or that data values are less than 127
// if isSilent is true, it will not alert the listener.
void MidiDevice::talkMIDI(byte cmd, byte data1, byte data2, bool isSilent) {

    //Some commands only have one data byte. All cmds less than 0xBn have 2 data bytes
    //(sort of: http://253.ccarh.org/handout/midiprotocol/)
    //if( (cmd & 0xF0) <= 0xB0)
    bool hasSecondArg = ((cmd & 0xF0) <= 0xB0 || (cmd & 0xF0) == 0xE0);

#ifdef IS_ARDUINO_SHIM
    midiOut << cmd << data1;

    if (hasSecondArg)
        midiOut << data2;

#else
	digitalWrite(LED_PIN, HIGH);
	mySerial->write(cmd);//print(cmd, BYTE);
	mySerial->write(data1);//print(data1, BYTE);

	if (hasSecondArg)
		mySerial->write(data2);//print(data2, BYTE);

	#if IS_DRUMPANTS

	// also send to BLE
	Serial1.write(cmd);
	Serial1.write(data1);

	if (hasSecondArg)
		Serial1.write(data2);

	#endif

  digitalWrite(LED_PIN, LOW);
#endif

  if (!isSilent && this->listener != NULL) {
	this->listener->onSendOutput(cmd, data1, data2);
  }
}

void MidiDevice::note(bool isOn, int channel, int note, int velocity) {
	// i assumed the truncation from int to byte would take care of this.
	// ProTip: don't trust C++ to do anything reasonable.
	channel = min(channel, 127);
	note = min(note, 127);
	velocity = min(velocity, 127);

	if (isOn)
		noteOn((byte)channel, (byte)note, (byte)velocity);
	else
		noteOff((byte)channel, (byte)note, 0); //TODO: velocity or 0?
}

/*** for looper listeners ***/
void MidiDevice::setListener(EventLooper* l) {
	this->listener = l;
}

<|endoftext|>