<commit_before>// ------------------------------------------------------------------------
// audiofx_mixing.cpp: Effects for channel mixing and routing
// Copyright (C) 1999-2002,2006,2008,2009 Kai Vehmanen
//
// Attributes:
//     eca-style-version: 3 (see Ecasound Programmer's Guide)
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU 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 General Public License for more details.
//
// You should have received a copy of the GNU 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
// ------------------------------------------------------------------------

#include <kvu_dbc.h>
#include <kvu_numtostr.h>

#include "samplebuffer_iterators.h"
#include "audiofx_mixing.h"

static EFFECT_MIXING::ch_type priv_from_make_sane(EFFECT_MIXING::ch_type channel, SAMPLE_BUFFER *insample)
{
  EFFECT_MIXING::ch_type channels =
    static_cast<EFFECT_MIXING::ch_type>(insample->number_of_channels());

  if (channel < 0)
    return 0;

  if (channel >= channels)
    return channels - 1;

  return channel;
}

static EFFECT_MIXING::ch_type priv_to_make_sane(EFFECT_MIXING::ch_type channel, SAMPLE_BUFFER *insample)
{
  if (channel < 0)
    return 0;

  return channel;
}

EFFECT_MIXING::~EFFECT_MIXING(void)
{
}

EFFECT_CHANNEL_COPY::EFFECT_CHANNEL_COPY (parameter_t from,
					  parameter_t to)
{
  set_parameter(1, from);
  set_parameter(2, to);
}

int EFFECT_CHANNEL_COPY::output_channels(int i_channels) const
{
  int c = static_cast<int>(to_channel > from_channel ? to_channel : from_channel);
  ++c;
  return c > i_channels ? c : i_channels;
}

void EFFECT_CHANNEL_COPY::parameter_description(int param, struct PARAM_DESCRIPTION *pd) const
{
  pd->default_value = 1;
  pd->description = get_parameter_name(param);
  pd->bounded_above = false;
  pd->upper_bound = 0.0f;
  pd->bounded_below = true;
  pd->lower_bound = 1.0f;
  pd->toggled = false;
  pd->integer = true;
  pd->logarithmic = false;
  pd->output = false;
}

void EFFECT_CHANNEL_COPY::set_parameter(int param, CHAIN_OPERATOR::parameter_t value)
{
  switch (param) {
  case 1:
    from_channel = static_cast<ch_type>(value);
    DBC_CHECK(from_channel > 0);
    from_channel--;
    break;
  case 2:
    to_channel = static_cast<ch_type>(value);
    DBC_CHECK(to_channel > 0);
    to_channel--;
    break;
  }
}

CHAIN_OPERATOR::parameter_t EFFECT_CHANNEL_COPY::get_parameter(int param) const
{
  switch (param) {
  case 1:
    return from_channel + 1;
  case 2:
    return to_channel + 1;
  }
  return 0.0f;
}

void EFFECT_CHANNEL_COPY::init(SAMPLE_BUFFER *insample)
{
  f_iter.init(insample);
  t_iter.init(insample);
  from_channel = priv_from_make_sane(from_channel, insample);
  to_channel = priv_to_make_sane(to_channel, insample);
}

void EFFECT_CHANNEL_COPY::process(void)
{
  f_iter.begin(from_channel);
  t_iter.begin(to_channel);
  while(!f_iter.end() && !t_iter.end()) {
    *t_iter.current() = *f_iter.current();
    f_iter.next();
    t_iter.next();
  }
}

EFFECT_CHANNEL_MOVE::EFFECT_CHANNEL_MOVE (parameter_t from,
					  parameter_t to)
{
  set_parameter(1, from);
  set_parameter(2, to);
}

int EFFECT_CHANNEL_MOVE::output_channels(int i_channels) const
{
  int c = static_cast<int>(to_channel > from_channel ? to_channel : from_channel);
  ++c;
  return c > i_channels ? c : i_channels;
}

void EFFECT_CHANNEL_MOVE::parameter_description(int param, struct PARAM_DESCRIPTION *pd) const
{
  pd->default_value = 1;
  pd->description = get_parameter_name(param);
  pd->bounded_above = false;
  pd->upper_bound = 0.0f;
  pd->bounded_below = true;
  pd->lower_bound = 1.0f;
  pd->toggled = false;
  pd->integer = true;
  pd->logarithmic = false;
  pd->output = false;
}

void EFFECT_CHANNEL_MOVE::set_parameter(int param, CHAIN_OPERATOR::parameter_t value)
{
  switch (param) {
  case 1:
    from_channel = static_cast<ch_type>(value);
    DBC_CHECK(from_channel > 0);
    from_channel--;
    break;
  case 2:
    to_channel = static_cast<ch_type>(value);
    DBC_CHECK(to_channel > 0);
    to_channel--;
    break;
  }
}

CHAIN_OPERATOR::parameter_t EFFECT_CHANNEL_MOVE::get_parameter(int param) const
{
  switch (param) {
  case 1:
    return from_channel + 1;
  case 2:
    return to_channel + 1;
  }
  return 0.0;
}

void EFFECT_CHANNEL_MOVE::init(SAMPLE_BUFFER *insample)
{
  f_iter.init(insample);
  t_iter.init(insample);
  from_channel = priv_from_make_sane(from_channel, insample);
  to_channel = priv_to_make_sane(to_channel, insample);
}

void EFFECT_CHANNEL_MOVE::process(void)
{
  f_iter.begin(from_channel);
  t_iter.begin(to_channel);
  while(!f_iter.end() && !t_iter.end()) {
    *t_iter.current() = *f_iter.current();
    if (from_channel != to_channel)
      *f_iter.current() = SAMPLE_SPECS::silent_value;
    f_iter.next();
    t_iter.next();
  }
}

EFFECT_CHANNEL_MUTE::EFFECT_CHANNEL_MUTE (parameter_t channel)
  : EFFECT_AMPLIFY_CHANNEL(0, static_cast<int>(channel))
{
  set_parameter(1, channel);
}

void EFFECT_CHANNEL_MUTE::parameter_description(int param, struct PARAM_DESCRIPTION *pd) const
{
  pd->default_value = 1;
  pd->description = get_parameter_name(param);
  pd->bounded_above = false;
  pd->upper_bound = 0.0f;
  pd->bounded_below = true;
  pd->lower_bound = 1.0f;
  pd->toggled = false;
  pd->integer = true;
  pd->logarithmic = false;
  pd->output = false;
}

void EFFECT_CHANNEL_MUTE::set_parameter(int param, CHAIN_OPERATOR::parameter_t value)
{
  EFFECT_MIXING::ch_type from_channel;

  switch (param) {
  case 1:
    from_channel = static_cast<EFFECT_MIXING::ch_type>(value);
    DBC_CHECK(from_channel > 0);
    EFFECT_AMPLIFY_CHANNEL::set_parameter(2, from_channel);
    break;
  }
}

CHAIN_OPERATOR::parameter_t EFFECT_CHANNEL_MUTE::get_parameter(int param) const
{
  switch (param) {
  case 1:
    return EFFECT_AMPLIFY_CHANNEL::get_parameter(2);
  }
  return 0.0;
}

EFFECT_MIX_TO_CHANNEL::EFFECT_MIX_TO_CHANNEL (parameter_t to)
{
  set_parameter(1, to);
}

int EFFECT_MIX_TO_CHANNEL::output_channels(int i_channels) const
{
  int c = static_cast<int>(to_channel);
  ++c;
  return(c > i_channels ? c : i_channels);
}

void EFFECT_MIX_TO_CHANNEL::parameter_description(int param, struct PARAM_DESCRIPTION *pd) const
{
  pd->default_value = 1;
  pd->description = get_parameter_name(param);
  pd->bounded_above = false;
  pd->upper_bound = 0.0f;
  pd->bounded_below = true;
  pd->lower_bound = 1.0f;
  pd->toggled = false;
  pd->integer = true;
  pd->logarithmic = false;
  pd->output = false;
}

void EFFECT_MIX_TO_CHANNEL::set_parameter(int param, CHAIN_OPERATOR::parameter_t value) {
  switch (param) {
  case 1:
    to_channel = static_cast<ch_type>(value);
    DBC_CHECK(to_channel > 0);
    to_channel--;
    break;
  }
}

CHAIN_OPERATOR::parameter_t EFFECT_MIX_TO_CHANNEL::get_parameter(int param) const
{
  switch (param) {
  case 1:
    return to_channel + 1;
  }
  return 0.0f;
}

void EFFECT_MIX_TO_CHANNEL::init(SAMPLE_BUFFER *insample)
{
  i.init(insample);
  t_iter.init(insample);
  channels = insample->number_of_channels();
  to_channel = priv_to_make_sane(to_channel, insample);
}

void EFFECT_MIX_TO_CHANNEL::process(void)
{
  i.begin();
  t_iter.begin(to_channel);
  while(!t_iter.end() && !i.end()) {
    sum = SAMPLE_SPECS::silent_value;
    for (int n = 0; n < channels; n++) {
      if (i.end()) break;
      sum += (*i.current(n));
    }
    *t_iter.current() = sum / channels;
    i.next();
    t_iter.next();
  }
}

EFFECT_CHANNEL_SELECT::EFFECT_CHANNEL_SELECT (void)
  : sbuf_repp(0),
    out_channels_rep(0)
{
}

EFFECT_CHANNEL_SELECT* EFFECT_CHANNEL_SELECT::clone(void) const
{
  EFFECT_CHANNEL_SELECT *obj =
    new EFFECT_CHANNEL_SELECT();
  /* FIXME */
  DBC_NEVER_REACHED();
  return obj;
}

int EFFECT_CHANNEL_SELECT::output_channels(int i_channels) const
{
  return out_channels_rep;
}

void EFFECT_CHANNEL_SELECT::parameter_description(int param, struct PARAM_DESCRIPTION *pd) const
{
  /* these apply for all params */
  pd->default_value = 1;
  pd->description = "channel";
  pd->bounded_above = false;
  pd->upper_bound = 0.0f;
  pd->bounded_below = true;
  pd->lower_bound = 1.0f;
  pd->toggled = false;
  pd->integer = true;
  pd->logarithmic = false;
  pd->output = false;
}

void EFFECT_CHANNEL_SELECT::set_parameter(int param, CHAIN_OPERATOR::parameter_t value)
{
  int src_ch = static_cast<int>(value);
  int dst_ch = param;

  if (dst_ch > 0) {
    if (dst_ch > static_cast<int>(chsrc_map_rep.size())) {
      chsrc_map_rep.resize(dst_ch);
    }

    chsrc_map_rep[dst_ch - 1] = src_ch - 1;

    /* step: reset highest non-zero channel */
    int n;
    for(n = chsrc_map_rep.size() - 1;
	n >= 0; n--) {
      if (chsrc_map_rep[n] >= 0)
	break;
    }
    out_channels_rep = n + 1;
  }
}

CHAIN_OPERATOR::parameter_t EFFECT_CHANNEL_SELECT::get_parameter(int param) const
{

  /* note: we ignore zero-src channel at the end of
   *       chsrc_map_rep to avoid infinite loops in
   *       e.g. ECA_OBJECT_FACTORY */
  if (param > 0 &&
      param <= out_channels_rep) {

    DBC_CHECK(out_channels_rep <= static_cast<int>(chsrc_map_rep.size()));

    /* return 1...N */
    return chsrc_map_rep[param - 1] + 1;
  }

  return 0.0;
}

std::string EFFECT_CHANNEL_SELECT::parameter_names(void) const
{
  std::string params;
  int ch = 0;
  while(ch < out_channels_rep) {
    params += "src-ch-" + kvu_numtostr(ch + 1);
    ++ch;
    if (ch != out_channels_rep)
      params += ",";
  }
  return params;
  //return param_names_rep;
}

void EFFECT_CHANNEL_SELECT::init(SAMPLE_BUFFER *insample)
{
  sbuf_repp = insample;
  bouncebuf_rep.number_of_channels(sbuf_repp->number_of_channels());
  bouncebuf_rep.length_in_samples(sbuf_repp->length_in_samples());

  f_iter.init(&bouncebuf_rep);
  t_iter.init(insample);
}

void EFFECT_CHANNEL_SELECT::release(void)
{
  sbuf_repp = 0;
}

void EFFECT_CHANNEL_SELECT::process(void)
{
  /* step: copy input buffer to a temporary buffer */
  bouncebuf_rep.copy_all_content(*sbuf_repp);

  /* step: make sure output buf has exactly N channels */
  sbuf_repp->number_of_channels(out_channels_rep);

  /* step: route channels bouncebuf_rep -> sbuf_repp */
  for(int dst_ch = 0; dst_ch < out_channels_rep; dst_ch++) {
    int src_ch = chsrc_map_rep[dst_ch];

    if (src_ch >= 0 && src_ch < bouncebuf_rep.number_of_channels()) {
      f_iter.begin(src_ch);
      t_iter.begin(dst_ch);
      while(!f_iter.end() && !t_iter.end()) {
	*t_iter.current() = *f_iter.current();
	f_iter.next();
	t_iter.next();
      }
    }
    else {
      sbuf_repp->make_silent(dst_ch);
    }
  }
}
<commit_msg>Cleaned up chselect implementation<commit_after>// ------------------------------------------------------------------------
// audiofx_mixing.cpp: Effects for channel mixing and routing
// Copyright (C) 1999-2002,2006,2008,2009 Kai Vehmanen
//
// Attributes:
//     eca-style-version: 3 (see Ecasound Programmer's Guide)
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU 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 General Public License for more details.
//
// You should have received a copy of the GNU 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
// ------------------------------------------------------------------------

#include <kvu_dbc.h>
#include <kvu_numtostr.h>

#include "samplebuffer_iterators.h"
#include "audiofx_mixing.h"

static EFFECT_MIXING::ch_type priv_from_make_sane(EFFECT_MIXING::ch_type channel, SAMPLE_BUFFER *insample)
{
  EFFECT_MIXING::ch_type channels =
    static_cast<EFFECT_MIXING::ch_type>(insample->number_of_channels());

  if (channel < 0)
    return 0;

  if (channel >= channels)
    return channels - 1;

  return channel;
}

static EFFECT_MIXING::ch_type priv_to_make_sane(EFFECT_MIXING::ch_type channel, SAMPLE_BUFFER *insample)
{
  if (channel < 0)
    return 0;

  return channel;
}

EFFECT_MIXING::~EFFECT_MIXING(void)
{
}

EFFECT_CHANNEL_COPY::EFFECT_CHANNEL_COPY (parameter_t from,
					  parameter_t to)
{
  set_parameter(1, from);
  set_parameter(2, to);
}

int EFFECT_CHANNEL_COPY::output_channels(int i_channels) const
{
  int c = static_cast<int>(to_channel > from_channel ? to_channel : from_channel);
  ++c;
  return c > i_channels ? c : i_channels;
}

void EFFECT_CHANNEL_COPY::parameter_description(int param, struct PARAM_DESCRIPTION *pd) const
{
  pd->default_value = 1;
  pd->description = get_parameter_name(param);
  pd->bounded_above = false;
  pd->upper_bound = 0.0f;
  pd->bounded_below = true;
  pd->lower_bound = 1.0f;
  pd->toggled = false;
  pd->integer = true;
  pd->logarithmic = false;
  pd->output = false;
}

void EFFECT_CHANNEL_COPY::set_parameter(int param, CHAIN_OPERATOR::parameter_t value)
{
  switch (param) {
  case 1:
    from_channel = static_cast<ch_type>(value);
    DBC_CHECK(from_channel > 0);
    from_channel--;
    break;
  case 2:
    to_channel = static_cast<ch_type>(value);
    DBC_CHECK(to_channel > 0);
    to_channel--;
    break;
  }
}

CHAIN_OPERATOR::parameter_t EFFECT_CHANNEL_COPY::get_parameter(int param) const
{
  switch (param) {
  case 1:
    return from_channel + 1;
  case 2:
    return to_channel + 1;
  }
  return 0.0f;
}

void EFFECT_CHANNEL_COPY::init(SAMPLE_BUFFER *insample)
{
  f_iter.init(insample);
  t_iter.init(insample);
  from_channel = priv_from_make_sane(from_channel, insample);
  to_channel = priv_to_make_sane(to_channel, insample);
}

void EFFECT_CHANNEL_COPY::process(void)
{
  f_iter.begin(from_channel);
  t_iter.begin(to_channel);
  while(!f_iter.end() && !t_iter.end()) {
    *t_iter.current() = *f_iter.current();
    f_iter.next();
    t_iter.next();
  }
}

EFFECT_CHANNEL_MOVE::EFFECT_CHANNEL_MOVE (parameter_t from,
					  parameter_t to)
{
  set_parameter(1, from);
  set_parameter(2, to);
}

int EFFECT_CHANNEL_MOVE::output_channels(int i_channels) const
{
  int c = static_cast<int>(to_channel > from_channel ? to_channel : from_channel);
  ++c;
  return c > i_channels ? c : i_channels;
}

void EFFECT_CHANNEL_MOVE::parameter_description(int param, struct PARAM_DESCRIPTION *pd) const
{
  pd->default_value = 1;
  pd->description = get_parameter_name(param);
  pd->bounded_above = false;
  pd->upper_bound = 0.0f;
  pd->bounded_below = true;
  pd->lower_bound = 1.0f;
  pd->toggled = false;
  pd->integer = true;
  pd->logarithmic = false;
  pd->output = false;
}

void EFFECT_CHANNEL_MOVE::set_parameter(int param, CHAIN_OPERATOR::parameter_t value)
{
  switch (param) {
  case 1:
    from_channel = static_cast<ch_type>(value);
    DBC_CHECK(from_channel > 0);
    from_channel--;
    break;
  case 2:
    to_channel = static_cast<ch_type>(value);
    DBC_CHECK(to_channel > 0);
    to_channel--;
    break;
  }
}

CHAIN_OPERATOR::parameter_t EFFECT_CHANNEL_MOVE::get_parameter(int param) const
{
  switch (param) {
  case 1:
    return from_channel + 1;
  case 2:
    return to_channel + 1;
  }
  return 0.0;
}

void EFFECT_CHANNEL_MOVE::init(SAMPLE_BUFFER *insample)
{
  f_iter.init(insample);
  t_iter.init(insample);
  from_channel = priv_from_make_sane(from_channel, insample);
  to_channel = priv_to_make_sane(to_channel, insample);
}

void EFFECT_CHANNEL_MOVE::process(void)
{
  f_iter.begin(from_channel);
  t_iter.begin(to_channel);
  while(!f_iter.end() && !t_iter.end()) {
    *t_iter.current() = *f_iter.current();
    if (from_channel != to_channel)
      *f_iter.current() = SAMPLE_SPECS::silent_value;
    f_iter.next();
    t_iter.next();
  }
}

EFFECT_CHANNEL_MUTE::EFFECT_CHANNEL_MUTE (parameter_t channel)
  : EFFECT_AMPLIFY_CHANNEL(0, static_cast<int>(channel))
{
  set_parameter(1, channel);
}

void EFFECT_CHANNEL_MUTE::parameter_description(int param, struct PARAM_DESCRIPTION *pd) const
{
  pd->default_value = 1;
  pd->description = get_parameter_name(param);
  pd->bounded_above = false;
  pd->upper_bound = 0.0f;
  pd->bounded_below = true;
  pd->lower_bound = 1.0f;
  pd->toggled = false;
  pd->integer = true;
  pd->logarithmic = false;
  pd->output = false;
}

void EFFECT_CHANNEL_MUTE::set_parameter(int param, CHAIN_OPERATOR::parameter_t value)
{
  EFFECT_MIXING::ch_type from_channel;

  switch (param) {
  case 1:
    from_channel = static_cast<EFFECT_MIXING::ch_type>(value);
    DBC_CHECK(from_channel > 0);
    EFFECT_AMPLIFY_CHANNEL::set_parameter(2, from_channel);
    break;
  }
}

CHAIN_OPERATOR::parameter_t EFFECT_CHANNEL_MUTE::get_parameter(int param) const
{
  switch (param) {
  case 1:
    return EFFECT_AMPLIFY_CHANNEL::get_parameter(2);
  }
  return 0.0;
}

EFFECT_MIX_TO_CHANNEL::EFFECT_MIX_TO_CHANNEL (parameter_t to)
{
  set_parameter(1, to);
}

int EFFECT_MIX_TO_CHANNEL::output_channels(int i_channels) const
{
  int c = static_cast<int>(to_channel);
  ++c;
  return(c > i_channels ? c : i_channels);
}

void EFFECT_MIX_TO_CHANNEL::parameter_description(int param, struct PARAM_DESCRIPTION *pd) const
{
  pd->default_value = 1;
  pd->description = get_parameter_name(param);
  pd->bounded_above = false;
  pd->upper_bound = 0.0f;
  pd->bounded_below = true;
  pd->lower_bound = 1.0f;
  pd->toggled = false;
  pd->integer = true;
  pd->logarithmic = false;
  pd->output = false;
}

void EFFECT_MIX_TO_CHANNEL::set_parameter(int param, CHAIN_OPERATOR::parameter_t value) {
  switch (param) {
  case 1:
    to_channel = static_cast<ch_type>(value);
    DBC_CHECK(to_channel > 0);
    to_channel--;
    break;
  }
}

CHAIN_OPERATOR::parameter_t EFFECT_MIX_TO_CHANNEL::get_parameter(int param) const
{
  switch (param) {
  case 1:
    return to_channel + 1;
  }
  return 0.0f;
}

void EFFECT_MIX_TO_CHANNEL::init(SAMPLE_BUFFER *insample)
{
  i.init(insample);
  t_iter.init(insample);
  channels = insample->number_of_channels();
  to_channel = priv_to_make_sane(to_channel, insample);
}

void EFFECT_MIX_TO_CHANNEL::process(void)
{
  i.begin();
  t_iter.begin(to_channel);
  while(!t_iter.end() && !i.end()) {
    sum = SAMPLE_SPECS::silent_value;
    for (int n = 0; n < channels; n++) {
      if (i.end()) break;
      sum += (*i.current(n));
    }
    *t_iter.current() = sum / channels;
    i.next();
    t_iter.next();
  }
}

EFFECT_CHANNEL_SELECT::EFFECT_CHANNEL_SELECT (void)
  : sbuf_repp(0),
    out_channels_rep(0)
{
}

EFFECT_CHANNEL_SELECT* EFFECT_CHANNEL_SELECT::clone(void) const
{
  EFFECT_CHANNEL_SELECT *obj =
    new EFFECT_CHANNEL_SELECT();
  /* FIXME */
  DBC_NEVER_REACHED();
  return obj;
}

int EFFECT_CHANNEL_SELECT::output_channels(int i_channels) const
{
  return out_channels_rep;
}

void EFFECT_CHANNEL_SELECT::parameter_description(int param, struct PARAM_DESCRIPTION *pd) const
{
  /* these apply for all params */
  pd->default_value = 1;
  pd->description = "channel";
  pd->bounded_above = false;
  pd->upper_bound = 0.0f;
  pd->bounded_below = true;
  pd->lower_bound = 1.0f;
  pd->toggled = false;
  pd->integer = true;
  pd->logarithmic = false;
  pd->output = false;
}

void EFFECT_CHANNEL_SELECT::set_parameter(int param, CHAIN_OPERATOR::parameter_t value)
{
  int src_ch = static_cast<int>(value);
  int dst_ch = param;

  if (dst_ch > 0) {
    if (dst_ch > static_cast<int>(chsrc_map_rep.size())) {
      chsrc_map_rep.resize(dst_ch);
    }

    chsrc_map_rep[dst_ch - 1] = src_ch - 1;

    /* step: reset highest non-zero channel */
    int n;
    for(n = chsrc_map_rep.size() - 1;
	n >= 0; n--) {
      if (chsrc_map_rep[n] >= 0)
	break;
    }
    out_channels_rep = n + 1;
  }
}

CHAIN_OPERATOR::parameter_t EFFECT_CHANNEL_SELECT::get_parameter(int param) const
{

  /* note: we ignore zero-src channel at the end of
   *       chsrc_map_rep to avoid infinite loops in
   *       e.g. ECA_OBJECT_FACTORY */
  if (param > 0 &&
      param <= out_channels_rep) {

    DBC_CHECK(out_channels_rep <= static_cast<int>(chsrc_map_rep.size()));

    /* return 1...N */
    return chsrc_map_rep[param - 1] + 1;
  }

  return 0.0;
}

std::string EFFECT_CHANNEL_SELECT::parameter_names(void) const
{
  std::string params;
  int ch = 0;
  while(ch < out_channels_rep) {
    params += "src-ch-" + kvu_numtostr(ch + 1);
    ++ch;
    if (ch != out_channels_rep)
      params += ",";
  }
  return params;
  //return param_names_rep;
}

void EFFECT_CHANNEL_SELECT::init(SAMPLE_BUFFER *insample)
{
  sbuf_repp = insample;
  bouncebuf_rep.number_of_channels(sbuf_repp->number_of_channels());
  bouncebuf_rep.length_in_samples(sbuf_repp->length_in_samples());

  f_iter.init(&bouncebuf_rep);
  t_iter.init(insample);
}

void EFFECT_CHANNEL_SELECT::release(void)
{
  sbuf_repp = 0;
}

void EFFECT_CHANNEL_SELECT::process(void)
{
  /* step: copy input buffer to a temporary buffer */
  bouncebuf_rep.copy_all_content(*sbuf_repp);

  /* step: route channels bouncebuf_rep -> sbuf_repp */
  for(int dst_ch = 0; dst_ch < out_channels_rep; dst_ch++) {
    int src_ch = chsrc_map_rep[dst_ch];

    /* for development use only */
#if 0
    std::fprintf(stderr, "%sout#%d <-- in#%d (avail in=%d, out=%d)\n",
		 dst_ch == 0 ? "---\n" : "",
		 dst_ch, src_ch,
		 bouncebuf_rep.number_of_channels(),
		 sbuf_repp->number_of_channels());
#endif

    if (src_ch >= 0 && src_ch < bouncebuf_rep.number_of_channels()) {
      f_iter.begin(src_ch);
      t_iter.begin(dst_ch);
      while(!f_iter.end() && !t_iter.end()) {
	*t_iter.current() = *f_iter.current();
	f_iter.next();
	t_iter.next();
      }
    }
    else {
      sbuf_repp->make_silent(dst_ch);
    }
  }

  /* step: make sure output buf has exactly N channels */
  sbuf_repp->number_of_channels(out_channels_rep);
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 Intel Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "xwalk/runtime/browser/xwalk_runner.h"

#include <string>
#include <vector>
#include "base/command_line.h"
#include "base/logging.h"
#include "content/public/browser/render_process_host.h"
#include "xwalk/application/browser/application.h"
#include "xwalk/application/browser/application_service.h"
#include "xwalk/application/browser/application_system.h"
#include "xwalk/extensions/browser/xwalk_extension_service.h"
#include "xwalk/extensions/common/xwalk_extension_switches.h"
#include "xwalk/runtime/browser/application_component.h"
#include "xwalk/runtime/browser/devtools/remote_debugging_server.h"
#include "xwalk/runtime/browser/storage_component.h"
#include "xwalk/runtime/browser/sysapps_component.h"
#include "xwalk/runtime/browser/xwalk_app_extension_bridge.h"
#include "xwalk/runtime/browser/xwalk_browser_context.h"
#include "xwalk/runtime/browser/xwalk_browser_main_parts.h"
#include "xwalk/runtime/browser/xwalk_component.h"
#include "xwalk/runtime/browser/xwalk_content_browser_client.h"
#include "xwalk/runtime/common/xwalk_runtime_features.h"
#include "xwalk/runtime/common/xwalk_switches.h"

#if defined(OS_ANDROID)
#include "xwalk/runtime/browser/xwalk_runner_android.h"
#elif defined(OS_TIZEN)
#include "xwalk/runtime/browser/xwalk_runner_tizen.h"
#endif

namespace xwalk {

namespace {

XWalkRunner* g_xwalk_runner = NULL;

}  // namespace

XWalkRunner::XWalkRunner()
    : shared_process_mode_enabled_(false) {
  VLOG(1) << "Creating XWalkRunner object.";
  DCHECK(!g_xwalk_runner);
  g_xwalk_runner = this;

  XWalkRuntimeFeatures::GetInstance()->Initialize(
      CommandLine::ForCurrentProcess());

  // Initializing after the g_xwalk_runner is set to ensure
  // XWalkRunner::GetInstance() can be used in all sub objects if needed.
  content_browser_client_.reset(new XWalkContentBrowserClient(this));
}

XWalkRunner::~XWalkRunner() {
  DCHECK(g_xwalk_runner);
  g_xwalk_runner = NULL;
  VLOG(1) << "Destroying XWalkRunner object.";
}

// static
XWalkRunner* XWalkRunner::GetInstance() {
  return g_xwalk_runner;
}

application::ApplicationSystem* XWalkRunner::app_system() {
  return app_component_ ? app_component_->app_system() : NULL;
}

void XWalkRunner::PreMainMessageLoopRun() {
  browser_context_.reset(new XWalkBrowserContext);
  app_extension_bridge_.reset(new XWalkAppExtensionBridge());

  CommandLine* cmd_line = CommandLine::ForCurrentProcess();
  if (!cmd_line->HasSwitch(switches::kXWalkDisableExtensions))
    extension_service_.reset(new extensions::XWalkExtensionService(
        app_extension_bridge_.get()));

  CreateComponents();
  app_extension_bridge_->SetApplicationSystem(app_component_->app_system());
}

void XWalkRunner::PostMainMessageLoopRun() {
  DestroyComponents();
  extension_service_.reset();
  browser_context_.reset();
  DisableRemoteDebugging();
}

void XWalkRunner::CreateComponents() {
  scoped_ptr<ApplicationComponent> app_component(CreateAppComponent());
  // Keep a reference as some code still needs to call
  // XWalkRunner::app_system().
  app_component_ = app_component.get();
  AddComponent(app_component.Pass());

  if (XWalkRuntimeFeatures::isSysAppsEnabled())
    AddComponent(CreateSysAppsComponent().Pass());
  if (XWalkRuntimeFeatures::isStorageAPIEnabled())
    AddComponent(CreateStorageComponent().Pass());
}

void XWalkRunner::DestroyComponents() {
  // The ScopedVector takes care of deleting all the components. Ensure that
  // components are deleted before their dependencies by reversing the order.
  std::reverse(components_.begin(), components_.end());
  components_.clear();

  app_component_ = NULL;
}

void XWalkRunner::AddComponent(scoped_ptr<XWalkComponent> component) {
  components_.push_back(component.release());
}

scoped_ptr<ApplicationComponent> XWalkRunner::CreateAppComponent() {
  return make_scoped_ptr(new ApplicationComponent(browser_context_.get()));
}

scoped_ptr<SysAppsComponent> XWalkRunner::CreateSysAppsComponent() {
  return make_scoped_ptr(new SysAppsComponent());
}

scoped_ptr<StorageComponent> XWalkRunner::CreateStorageComponent() {
  return make_scoped_ptr(new StorageComponent());
}

void XWalkRunner::InitializeRuntimeVariablesForExtensions(
    const content::RenderProcessHost* host,
    base::ValueMap* variables) {
  application::Application* app = app_system()->application_service()->
      GetApplicationByRenderHostID(host->GetID());

  if (app)
    (*variables)["app_id"] = new base::StringValue(app->id());
}

void XWalkRunner::OnRenderProcessWillLaunch(content::RenderProcessHost* host) {
  if (!extension_service_)
    return;

  std::vector<extensions::XWalkExtension*> ui_thread_extensions;
  std::vector<extensions::XWalkExtension*> extension_thread_extensions;

  ScopedVector<XWalkComponent>::iterator it = components_.begin();
  for (; it != components_.end(); ++it) {
    XWalkComponent* component = *it;
    component->CreateUIThreadExtensions(host, &ui_thread_extensions);
    component->CreateExtensionThreadExtensions(
        host, &extension_thread_extensions);
  }

  // TODO(cmarcelo): Once functionality is moved to components, remove
  // CreateInternalExtensions*() functions from XWalkBrowserMainParts.
  XWalkBrowserMainParts* main_parts = content_browser_client_->main_parts();
  main_parts->CreateInternalExtensionsForUIThread(
      host, &ui_thread_extensions);
  main_parts->CreateInternalExtensionsForExtensionThread(
      host, &extension_thread_extensions);

  scoped_ptr<base::ValueMap> runtime_variables(new base::ValueMap);
  InitializeRuntimeVariablesForExtensions(host, runtime_variables.get());
  extension_service_->OnRenderProcessWillLaunch(
      host, &ui_thread_extensions, &extension_thread_extensions,
      runtime_variables.Pass());
}

void XWalkRunner::OnRenderProcessHostGone(content::RenderProcessHost* host) {
  if (!extension_service_)
    return;
  extension_service_->OnRenderProcessDied(host);
}

void XWalkRunner::EnableRemoteDebugging(int port) {
  const char* local_ip = "0.0.0.0";
  if (port > 0 && port < 65535) {
    remote_debugging_server_.reset(
        new RemoteDebuggingServer(browser_context(),
            local_ip, port, std::string()));
  }
}

void XWalkRunner::DisableRemoteDebugging() {
  remote_debugging_server_.reset();
}

// static
scoped_ptr<XWalkRunner> XWalkRunner::Create() {
  XWalkRunner* runner = NULL;
#if defined(OS_ANDROID)
  runner = new XWalkRunnerAndroid;
#elif defined(OS_TIZEN)
  runner = new XWalkRunnerTizen;
#else
  runner = new XWalkRunner;
#endif
  return scoped_ptr<XWalkRunner>(runner);
}

content::ContentBrowserClient* XWalkRunner::GetContentBrowserClient() {
  return content_browser_client_.get();
}

}  // namespace xwalk
<commit_msg>[Runtime] Add the initialization for |app_component_|.<commit_after>// Copyright (c) 2013 Intel Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "xwalk/runtime/browser/xwalk_runner.h"

#include <string>
#include <vector>
#include "base/command_line.h"
#include "base/logging.h"
#include "content/public/browser/render_process_host.h"
#include "xwalk/application/browser/application.h"
#include "xwalk/application/browser/application_service.h"
#include "xwalk/application/browser/application_system.h"
#include "xwalk/extensions/browser/xwalk_extension_service.h"
#include "xwalk/extensions/common/xwalk_extension_switches.h"
#include "xwalk/runtime/browser/application_component.h"
#include "xwalk/runtime/browser/devtools/remote_debugging_server.h"
#include "xwalk/runtime/browser/storage_component.h"
#include "xwalk/runtime/browser/sysapps_component.h"
#include "xwalk/runtime/browser/xwalk_app_extension_bridge.h"
#include "xwalk/runtime/browser/xwalk_browser_context.h"
#include "xwalk/runtime/browser/xwalk_browser_main_parts.h"
#include "xwalk/runtime/browser/xwalk_component.h"
#include "xwalk/runtime/browser/xwalk_content_browser_client.h"
#include "xwalk/runtime/common/xwalk_runtime_features.h"
#include "xwalk/runtime/common/xwalk_switches.h"

#if defined(OS_ANDROID)
#include "xwalk/runtime/browser/xwalk_runner_android.h"
#elif defined(OS_TIZEN)
#include "xwalk/runtime/browser/xwalk_runner_tizen.h"
#endif

namespace xwalk {

namespace {

XWalkRunner* g_xwalk_runner = NULL;

}  // namespace

XWalkRunner::XWalkRunner()
    : shared_process_mode_enabled_(false),
      app_component_(nullptr) {
  VLOG(1) << "Creating XWalkRunner object.";
  DCHECK(!g_xwalk_runner);
  g_xwalk_runner = this;

  XWalkRuntimeFeatures::GetInstance()->Initialize(
      CommandLine::ForCurrentProcess());

  // Initializing after the g_xwalk_runner is set to ensure
  // XWalkRunner::GetInstance() can be used in all sub objects if needed.
  content_browser_client_.reset(new XWalkContentBrowserClient(this));
}

XWalkRunner::~XWalkRunner() {
  DCHECK(g_xwalk_runner);
  g_xwalk_runner = NULL;
  VLOG(1) << "Destroying XWalkRunner object.";
}

// static
XWalkRunner* XWalkRunner::GetInstance() {
  return g_xwalk_runner;
}

application::ApplicationSystem* XWalkRunner::app_system() {
  return app_component_ ? app_component_->app_system() : NULL;
}

void XWalkRunner::PreMainMessageLoopRun() {
  browser_context_.reset(new XWalkBrowserContext);
  app_extension_bridge_.reset(new XWalkAppExtensionBridge());

  CommandLine* cmd_line = CommandLine::ForCurrentProcess();
  if (!cmd_line->HasSwitch(switches::kXWalkDisableExtensions))
    extension_service_.reset(new extensions::XWalkExtensionService(
        app_extension_bridge_.get()));

  CreateComponents();
  app_extension_bridge_->SetApplicationSystem(app_component_->app_system());
}

void XWalkRunner::PostMainMessageLoopRun() {
  DestroyComponents();
  extension_service_.reset();
  browser_context_.reset();
  DisableRemoteDebugging();
}

void XWalkRunner::CreateComponents() {
  scoped_ptr<ApplicationComponent> app_component(CreateAppComponent());
  // Keep a reference as some code still needs to call
  // XWalkRunner::app_system().
  app_component_ = app_component.get();
  AddComponent(app_component.Pass());

  if (XWalkRuntimeFeatures::isSysAppsEnabled())
    AddComponent(CreateSysAppsComponent().Pass());
  if (XWalkRuntimeFeatures::isStorageAPIEnabled())
    AddComponent(CreateStorageComponent().Pass());
}

void XWalkRunner::DestroyComponents() {
  // The ScopedVector takes care of deleting all the components. Ensure that
  // components are deleted before their dependencies by reversing the order.
  std::reverse(components_.begin(), components_.end());
  components_.clear();

  app_component_ = NULL;
}

void XWalkRunner::AddComponent(scoped_ptr<XWalkComponent> component) {
  components_.push_back(component.release());
}

scoped_ptr<ApplicationComponent> XWalkRunner::CreateAppComponent() {
  return make_scoped_ptr(new ApplicationComponent(browser_context_.get()));
}

scoped_ptr<SysAppsComponent> XWalkRunner::CreateSysAppsComponent() {
  return make_scoped_ptr(new SysAppsComponent());
}

scoped_ptr<StorageComponent> XWalkRunner::CreateStorageComponent() {
  return make_scoped_ptr(new StorageComponent());
}

void XWalkRunner::InitializeRuntimeVariablesForExtensions(
    const content::RenderProcessHost* host,
    base::ValueMap* variables) {
  application::Application* app = app_system()->application_service()->
      GetApplicationByRenderHostID(host->GetID());

  if (app)
    (*variables)["app_id"] = new base::StringValue(app->id());
}

void XWalkRunner::OnRenderProcessWillLaunch(content::RenderProcessHost* host) {
  if (!extension_service_)
    return;

  std::vector<extensions::XWalkExtension*> ui_thread_extensions;
  std::vector<extensions::XWalkExtension*> extension_thread_extensions;

  ScopedVector<XWalkComponent>::iterator it = components_.begin();
  for (; it != components_.end(); ++it) {
    XWalkComponent* component = *it;
    component->CreateUIThreadExtensions(host, &ui_thread_extensions);
    component->CreateExtensionThreadExtensions(
        host, &extension_thread_extensions);
  }

  // TODO(cmarcelo): Once functionality is moved to components, remove
  // CreateInternalExtensions*() functions from XWalkBrowserMainParts.
  XWalkBrowserMainParts* main_parts = content_browser_client_->main_parts();
  main_parts->CreateInternalExtensionsForUIThread(
      host, &ui_thread_extensions);
  main_parts->CreateInternalExtensionsForExtensionThread(
      host, &extension_thread_extensions);

  scoped_ptr<base::ValueMap> runtime_variables(new base::ValueMap);
  InitializeRuntimeVariablesForExtensions(host, runtime_variables.get());
  extension_service_->OnRenderProcessWillLaunch(
      host, &ui_thread_extensions, &extension_thread_extensions,
      runtime_variables.Pass());
}

void XWalkRunner::OnRenderProcessHostGone(content::RenderProcessHost* host) {
  if (!extension_service_)
    return;
  extension_service_->OnRenderProcessDied(host);
}

void XWalkRunner::EnableRemoteDebugging(int port) {
  const char* local_ip = "0.0.0.0";
  if (port > 0 && port < 65535) {
    remote_debugging_server_.reset(
        new RemoteDebuggingServer(browser_context(),
            local_ip, port, std::string()));
  }
}

void XWalkRunner::DisableRemoteDebugging() {
  remote_debugging_server_.reset();
}

// static
scoped_ptr<XWalkRunner> XWalkRunner::Create() {
  XWalkRunner* runner = NULL;
#if defined(OS_ANDROID)
  runner = new XWalkRunnerAndroid;
#elif defined(OS_TIZEN)
  runner = new XWalkRunnerTizen;
#else
  runner = new XWalkRunner;
#endif
  return scoped_ptr<XWalkRunner>(runner);
}

content::ContentBrowserClient* XWalkRunner::GetContentBrowserClient() {
  return content_browser_client_.get();
}

}  // namespace xwalk
<|endoftext|>


<commit_before>#include "Crown.h"
#include <cstdlib>
#include <GL/glu.h>

using namespace Crown;

class WndCtrl: public KeyboardListener
{
public:

	WndCtrl()
	{
		GetDevice()->GetInputManager()->RegisterKeyboardListener(this);
	}

	virtual void KeyReleased(const KeyboardEvent& event)
	{
		if (event.key == KC_ESCAPE)
		{
			GetDevice()->StopRunning();
		}
	}
};

class MainScene: public MouseListener//, public KeyboardListener
{

public:

	MainScene()
	{
		GetDevice()->GetInputManager()->RegisterMouseListener(this);
		//GetDevice()->GetInputManager()->RegisterKeyboardListener(this);

		sphereCount = 0;
	}

	virtual ~MainScene()
	{
		if (quadric)
			gluDeleteQuadric(quadric);
	}

	virtual void ButtonPressed(const MouseEvent& event)
	{
		if (event.button == MB_LEFT)
		{
			if (sphereCount < 12)
			{
				sphere[sphereCount].c = cam->GetPosition();
				velocity[sphereCount] = cam->GetLookAt() * 0.7f;
				sphereCount++;
			}
		}

		if (event.button == MB_RIGHT)
		{
			sphereCount = 0;
		}
	}

	virtual void OnLoad()
	{
		Crown::Renderer* renderer = Crown::GetDevice()->GetRenderer();
		renderer->SetClearColor(Crown::Color4(0.0f, 0.0f, 0.0f, 1.0f));

		// Add a movable camera
		cam = new MovableCamera(Vec3::ZERO, Angles::ZERO, true, 90.0f, 1.6f, 0.01, 2.5, true);

		if (cam)
		{
			cam->SetActive(true);
			cam->SetSpeed(0.1);
			cam->SetFarClipDistance(1000.0f);
			cam->SetPosition(Vec3(0, 10, 15));

		}

		grass = GetTextureManager()->Load("res/texturewhichdoesnotexists.ctex");

		dplane = GetMeshManager()->LoadPlane("3dplane", 128.0f, 128.0f);

		ray.origin = Vec3(0, 0, 10);
		ray.direction = Vec3(0, 0, -1);

		for (int i = 0; i < 12; i++)
		{
			sphere[i].r = 1.5f;
		}

		plane[0].n			= Vec3(0, 1, 0);
		plane[0].d			= 0;

		plane[1].n 			= Vec3(0, 0, 1);
		plane[1].d			= 0;

		plane[2].n			= Vec3(1, 0, 0);
		plane[2].d			= 0;

		gravity				= Vec3(0, -0.003, 0);

		quadric = gluNewQuadric();
	}

	virtual void RenderScene()
	{
		Renderer* renderer = GetDevice()->GetRenderer();

		renderer->_SetLighting(false);
		renderer->_SetBlending(false);
		renderer->_SetAlphaTest(false);
		renderer->_SetBackfaceCulling(false);
		renderer->_SetTexturing(0, false);
		renderer->_SetTexturing(1, false);
		renderer->_SetTexturing(2, false);

		cam->Render();

		for (int i = 0; i < sphereCount; i++)
		{
			velocity[i] += gravity;
			for (int j = 0; j < 3; j++)
			{
				real itt;
				Vec3 intersectionPoint;
				if (Intersection::TestDynamicSpherePlane(sphere[i], velocity[i], plane[j], itt, intersectionPoint))
				{
					real velLength = velocity[i].GetLength();

					velocity[i].Normalize();
					Vec3 nuovo = ((2.0f * (-velocity[i].Dot(plane[j].n))) * plane[j].n) + velocity[i];
					velocity[i] = nuovo * velLength * 0.7f;
				}
			}
		}

		for (int i = 0; i < sphereCount; i++)
		{
			if (velocity[i] == Vec3::ZERO)
			{
				velocity[i].Zero();
			}
			sphere[i].c += velocity[i];
		}

		if (cam->IsActive())
		{
			ray.origin = cam->GetPosition();
			ray.direction = cam->GetLookAt();
		}

		renderer->SetMatrix(MT_MODEL, Mat4::IDENTITY);

		for (int j = 0; j < sphereCount; j++)
		{
			// Draw spheres
			glColor3f(1, 0, 0);
			tr.LoadIdentity();
			tr.SetTranslation(sphere[j].c);
			renderer->SetMatrix(MT_MODEL, tr);
			gluSphere(quadric, sphere[j].r, 64, 64);
		}

//		tr.SetTranslation(sphere[1].c);
//		renderer->SetMatrix(MT_MODEL, tr);
//		gluSphere(quadric, sphere[1].r, 64, 64);

//		tr.SetTranslation(sphere[2].c);
//		renderer->SetMatrix(MT_MODEL, tr);
//		gluSphere(quadric, sphere[2].r, 64, 64);
		// End Draw spheres

//		// Draw velocity segments
//		glColor3f(1, 0, 0);
//		renderer->SetMatrix(MT_MODEL, Mat4::IDENTITY);

//		glBegin(GL_LINES);
//		glVertex3fv(sphere[0].c.ToFloatPtr());
//		glVertex3fv((sphere[0].c + velocity[0]).ToFloatPtr());
//		glEnd();

//		glBegin(GL_LINES);
//		glVertex3fv(sphere[1].c.ToFloatPtr());
//		glVertex3fv((sphere[1].c + velocity[1]).ToFloatPtr());
//		glEnd();

//		glBegin(GL_LINES);
//		glVertex3fv(sphere[2].c.ToFloatPtr());
//		glVertex3fv((sphere[2].c + velocity[2]).ToFloatPtr());
//		glEnd();
//		// End Draw velocity segments

//		// Draw end spheres
//		glColor3f(1.0, 0.0, 0.0);
//		tr.LoadIdentity();
//		tr.SetTranslation(sphere[0].c + velocity[0]);
//		renderer->SetMatrix(MT_MODEL, tr);
//		gluSphere(quadric, sphere[0].r, 64, 64);

//		tr.SetTranslation(sphere[1].c + velocity[1]);
//		renderer->SetMatrix(MT_MODEL, tr);
//		gluSphere(quadric, sphere[1].r, 64, 64);

//		tr.SetTranslation(sphere[2].c + velocity[2]);
//		renderer->SetMatrix(MT_MODEL, tr);
//		gluSphere(quadric, sphere[2].r, 64, 64);
//		// End Draw end spheres

//		// Draw spheres at collision time
//		glColor3f(0.0, 1.0, 0.0);
//		real it;
//		if (Intersection::TestDynamicSphereSphere(sphere[0], velocity[0], sphere[1], velocity[1], it))
//		{
//			tr.LoadIdentity();

//			tr.SetTranslation(sphere[0].c + (velocity[0] * it));
//			renderer->SetMatrix(MT_MODEL, tr);
//			gluSphere(quadric, sphere[0].r, 64, 64);

//			tr.SetTranslation(sphere[1].c + (velocity[1] * it));
//			renderer->SetMatrix(MT_MODEL, tr);
//			gluSphere(quadric, sphere[1].r, 64, 64);
//		}

//		if (Intersection::TestDynamicSpherePlane(sphere[2], velocity[2], plane, it))
//		{
//			tr.LoadIdentity();

//			tr.SetTranslation(sphere[2].c + (velocity[2] * it));
//			renderer->SetMatrix(MT_MODEL, tr);
//			gluSphere(quadric, sphere[2].r, 64, 64);
//		}
//		// End Draw spheres at collision time

		renderer->_SetTexture(0, grass);
		renderer->_SetTexturing(0, true);
		renderer->_SetTextureMode(0, grass->GetMode(), grass->GetBlendColor());
		renderer->_SetTextureFilter(0, grass->GetFilter());

		tr.BuildRotationX(Math::PI / 2.0f);
		tr.SetTranslation(Vec3(0, 0, 0));
		renderer->SetMatrix(MT_MODEL, tr);
		renderer->RenderVertexIndexBuffer(dplane->GetVertexBuffer(), dplane->GetIndexBuffer());

		tr.LoadIdentity();
		tr.SetTranslation(Vec3(0, 0, 0));
		renderer->SetMatrix(MT_MODEL, tr);
		renderer->RenderVertexIndexBuffer(dplane->GetVertexBuffer(), dplane->GetIndexBuffer());

		tr.BuildRotationY(Math::PI / 2.0f);
		tr.SetTranslation(Vec3(0, 0, 0));
		renderer->SetMatrix(MT_MODEL, tr);
		renderer->RenderVertexIndexBuffer(dplane->GetVertexBuffer(), dplane->GetIndexBuffer());
	}

private:

	Mesh* dplane;
	Mat4 ortho;
	Mat4 crateModel;
	Mat4 tr;
	Texture* grass;

	Ray ray;
	Plane plane[3];
	Sphere sphere[12];
	Vec3 velocity[12];
	Vec3 gravity;
	GLUquadric* quadric;
	MovableCamera* cam;
	int sphereCount;
};

int main(int argc, char** argv)
{
	int wndW = 1000;
	int wndH = 625;

	if (argc == 3)
	{
		wndW = atoi(argv[1]);
		wndH = atoi(argv[2]);
	}

	Device* mDevice = GetDevice();

	if (!mDevice->Init(wndW, wndH, 32, false))
	{
		return 0;
	}

	WndCtrl ctrl;

	MainScene scene;
	scene.OnLoad();

	mDevice->GetMainWindow()->SetTitle("Crown Engine v0.1 - Collision Test");

	while (mDevice->IsRunning())
	{
		InputManager* mInputManager = GetDevice()->GetInputManager();

		if (mInputManager)
		{
			if (mInputManager->IsMouseAvailable())
			{
				if (mInputManager->IsMouseAvailable())
				{
					mInputManager->GetMouse()->EventLoop();
				}
				if (mInputManager->IsKeyboardAvailable())
				{
					mInputManager->GetKeyboard()->EventLoop();
				}
				if (mInputManager->IsTouchAvailable())
				{
					mInputManager->GetTouch()->EventLoop();
				}
			}
		}

		mDevice->GetMainWindow()->EventLoop();

		GetDevice()->GetRenderer()->_BeginFrame();

		scene.RenderScene();

		GetDevice()->GetRenderer()->_EndFrame();

		mDevice->GetMainWindow()->Update();
	}

	mDevice->Shutdown();

	mDevice->Shutdown();

	return 0;
}

<commit_msg>Fix collision sample<commit_after>#include "Crown.h"
#include <cstdlib>
#include <GL/glu.h>

using namespace Crown;

class WndCtrl: public KeyboardListener
{
public:

	WndCtrl()
	{
		GetDevice()->GetInputManager()->RegisterKeyboardListener(this);
	}

	virtual void KeyReleased(const KeyboardEvent& event)
	{
		if (event.key == KC_ESCAPE)
		{
			GetDevice()->StopRunning();
		}
	}
};

class MainScene: public MouseListener//, public KeyboardListener
{

public:

	MainScene()
	{
		GetDevice()->GetInputManager()->RegisterMouseListener(this);
		//GetDevice()->GetInputManager()->RegisterKeyboardListener(this);

		sphereCount = 0;
	}

	virtual ~MainScene()
	{
		if (quadric)
			gluDeleteQuadric(quadric);
	}

	virtual void ButtonPressed(const MouseEvent& event)
	{
		if (event.button == MB_LEFT)
		{
			if (sphereCount < 12)
			{
				sphere[sphereCount].c = cam->GetPosition();
				velocity[sphereCount] = cam->GetLookAt() * 0.7f;
				sphereCount++;
			}
		}

		if (event.button == MB_RIGHT)
		{
			sphereCount = 0;
		}
	}

	virtual void OnLoad()
	{
		Crown::Renderer* renderer = Crown::GetDevice()->GetRenderer();
		renderer->SetClearColor(Crown::Color4(0.0f, 0.0f, 0.0f, 1.0f));

		// Add a movable camera
		cam = new MovableCamera(Vec3::ZERO, Angles::ZERO, true, 90.0f, 1.6f, 0.01, 2.5, true);

		if (cam)
		{
			cam->SetActive(true);
			cam->SetSpeed(0.1);
			cam->SetFarClipDistance(1000.0f);
			cam->SetPosition(Vec3(0, 10, 15));

		}

		grass = GetTextureManager()->Load("res/test_texture1.tga");

		dplane = GetMeshManager()->LoadPlane("3dplane", 128.0f, 128.0f);

		ray.origin = Vec3(0, 0, 10);
		ray.direction = Vec3(0, 0, -1);

		for (int i = 0; i < 12; i++)
		{
			sphere[i].r = 1.5f;
		}

		plane[0].n			= Vec3(0, 1, 0);
		plane[0].d			= 0;

		plane[1].n 			= Vec3(0, 0, 1);
		plane[1].d			= 0;

		plane[2].n			= Vec3(1, 0, 0);
		plane[2].d			= 0;

		gravity				= Vec3(0, -0.003, 0);

		quadric = gluNewQuadric();
	}

	virtual void RenderScene()
	{
		Renderer* renderer = GetDevice()->GetRenderer();

		renderer->_SetLighting(false);
		renderer->_SetBlending(false);
		renderer->_SetAlphaTest(false);
		renderer->_SetBackfaceCulling(false);
		renderer->_SetTexturing(0, false);
		renderer->_SetTexturing(1, false);
		renderer->_SetTexturing(2, false);

		cam->Render();

		for (int i = 0; i < sphereCount; i++)
		{
			velocity[i] += gravity;
			for (int j = 0; j < 3; j++)
			{
				real itt;
				Vec3 intersectionPoint;
				if (Intersection::TestDynamicSpherePlane(sphere[i], velocity[i], plane[j], itt, intersectionPoint))
				{
					real velLength = velocity[i].GetLength();

					velocity[i].Normalize();
					Vec3 nuovo = ((2.0f * (-velocity[i].Dot(plane[j].n))) * plane[j].n) + velocity[i];
					velocity[i] = nuovo * velLength * 0.7f;
				}
			}
		}

		for (int i = 0; i < sphereCount; i++)
		{
			if (velocity[i] == Vec3::ZERO)
			{
				velocity[i].Zero();
			}
			sphere[i].c += velocity[i];
		}

		if (cam->IsActive())
		{
			ray.origin = cam->GetPosition();
			ray.direction = cam->GetLookAt();
		}

		renderer->SetMatrix(MT_MODEL, Mat4::IDENTITY);

		for (int j = 0; j < sphereCount; j++)
		{
			// Draw spheres
			glColor3f(1, 0, 0);
			tr.LoadIdentity();
			tr.SetTranslation(sphere[j].c);
			renderer->SetMatrix(MT_MODEL, tr);
			gluSphere(quadric, sphere[j].r, 64, 64);
		}

//		tr.SetTranslation(sphere[1].c);
//		renderer->SetMatrix(MT_MODEL, tr);
//		gluSphere(quadric, sphere[1].r, 64, 64);

//		tr.SetTranslation(sphere[2].c);
//		renderer->SetMatrix(MT_MODEL, tr);
//		gluSphere(quadric, sphere[2].r, 64, 64);
		// End Draw spheres

//		// Draw velocity segments
//		glColor3f(1, 0, 0);
//		renderer->SetMatrix(MT_MODEL, Mat4::IDENTITY);

//		glBegin(GL_LINES);
//		glVertex3fv(sphere[0].c.ToFloatPtr());
//		glVertex3fv((sphere[0].c + velocity[0]).ToFloatPtr());
//		glEnd();

//		glBegin(GL_LINES);
//		glVertex3fv(sphere[1].c.ToFloatPtr());
//		glVertex3fv((sphere[1].c + velocity[1]).ToFloatPtr());
//		glEnd();

//		glBegin(GL_LINES);
//		glVertex3fv(sphere[2].c.ToFloatPtr());
//		glVertex3fv((sphere[2].c + velocity[2]).ToFloatPtr());
//		glEnd();
//		// End Draw velocity segments

//		// Draw end spheres
//		glColor3f(1.0, 0.0, 0.0);
//		tr.LoadIdentity();
//		tr.SetTranslation(sphere[0].c + velocity[0]);
//		renderer->SetMatrix(MT_MODEL, tr);
//		gluSphere(quadric, sphere[0].r, 64, 64);

//		tr.SetTranslation(sphere[1].c + velocity[1]);
//		renderer->SetMatrix(MT_MODEL, tr);
//		gluSphere(quadric, sphere[1].r, 64, 64);

//		tr.SetTranslation(sphere[2].c + velocity[2]);
//		renderer->SetMatrix(MT_MODEL, tr);
//		gluSphere(quadric, sphere[2].r, 64, 64);
//		// End Draw end spheres

//		// Draw spheres at collision time
//		glColor3f(0.0, 1.0, 0.0);
//		real it;
//		if (Intersection::TestDynamicSphereSphere(sphere[0], velocity[0], sphere[1], velocity[1], it))
//		{
//			tr.LoadIdentity();

//			tr.SetTranslation(sphere[0].c + (velocity[0] * it));
//			renderer->SetMatrix(MT_MODEL, tr);
//			gluSphere(quadric, sphere[0].r, 64, 64);

//			tr.SetTranslation(sphere[1].c + (velocity[1] * it));
//			renderer->SetMatrix(MT_MODEL, tr);
//			gluSphere(quadric, sphere[1].r, 64, 64);
//		}

//		if (Intersection::TestDynamicSpherePlane(sphere[2], velocity[2], plane, it))
//		{
//			tr.LoadIdentity();

//			tr.SetTranslation(sphere[2].c + (velocity[2] * it));
//			renderer->SetMatrix(MT_MODEL, tr);
//			gluSphere(quadric, sphere[2].r, 64, 64);
//		}
//		// End Draw spheres at collision time

		renderer->_SetTexture(0, grass);
		renderer->_SetTexturing(0, true);
		renderer->_SetTextureMode(0, grass->GetMode(), grass->GetBlendColor());
		renderer->_SetTextureFilter(0, grass->GetFilter());

		tr.BuildRotationX(Math::PI / 2.0f);
		tr.SetTranslation(Vec3(0, 0, 0));
		renderer->SetMatrix(MT_MODEL, tr);
		renderer->RenderVertexIndexBuffer(dplane->GetVertexBuffer(), dplane->GetIndexBuffer());

		tr.LoadIdentity();
		tr.SetTranslation(Vec3(0, 0, 0));
		renderer->SetMatrix(MT_MODEL, tr);
		renderer->RenderVertexIndexBuffer(dplane->GetVertexBuffer(), dplane->GetIndexBuffer());

		tr.BuildRotationY(Math::PI / 2.0f);
		tr.SetTranslation(Vec3(0, 0, 0));
		renderer->SetMatrix(MT_MODEL, tr);
		renderer->RenderVertexIndexBuffer(dplane->GetVertexBuffer(), dplane->GetIndexBuffer());
	}

private:

	Mesh* dplane;
	Mat4 ortho;
	Mat4 crateModel;
	Mat4 tr;
	Texture* grass;

	Ray ray;
	Plane plane[3];
	Sphere sphere[12];
	Vec3 velocity[12];
	Vec3 gravity;
	GLUquadric* quadric;
	MovableCamera* cam;
	int sphereCount;
};

int main(int argc, char** argv)
{
	Device* mDevice = GetDevice();
	EventLoop loop;

	if (!mDevice->Init(argc, argv))
	{
		return 0;
	}

	WndCtrl ctrl;

	MainScene scene;
	scene.OnLoad();

	mDevice->GetMainWindow()->SetTitle("Crown Engine v0.1 - Collision Test");

	while (mDevice->IsRunning())
	{
		InputManager* mInputManager = GetDevice()->GetInputManager();

		if (mInputManager)
		{
			if (mInputManager->IsMouseAvailable())
			{
				if (mInputManager->IsMouseAvailable())
				{
					mInputManager->GetMouse()->EventLoop();
				}
				if (mInputManager->IsKeyboardAvailable())
				{
					mInputManager->GetKeyboard()->EventLoop();
				}
				if (mInputManager->IsTouchAvailable())
				{
					mInputManager->GetTouch()->EventLoop();
				}
			}
		}

		mDevice->GetMainWindow()->EventLoop();

		GetDevice()->GetRenderer()->_BeginFrame();

		scene.RenderScene();

		GetDevice()->GetRenderer()->_EndFrame();

		mDevice->GetMainWindow()->Update();
	}

	mDevice->Shutdown();

	mDevice->Shutdown();

	return 0;
}

<|endoftext|>


<commit_before><commit_msg>ocl: fix input data for Canny perf test<commit_after><|endoftext|>


<commit_before>#include "Shipyard.h"

Shipyard::Shipyard()
{
	for (u32 i = 0; i<KEY_KEY_CODES_COUNT; ++i)
		isKeyDown[i] = false;
	isOpenDialogOpen = false;
}

void Shipyard::setupDevice(IrrlichtDevice * _device)
{
	device = _device;
	smgr = device->getSceneManager();
	collisionManager = smgr->getSceneCollisionManager();
	guiEnv = device->getGUIEnvironment();
}

void Shipyard::loop()
{
	video::IVideoDriver* driver = device->getVideoDriver();

	//add the camera
	camera = smgr->addCameraSceneNode();
	if (camera)
	{
		scene::ISceneNodeAnimator* anm = new scene::CSceneNodeAnimatorCameraCustom(device->getCursorControl());

		camera->addAnimator(anm);
		anm->drop();
	}

	smgr->setAmbientLight(SColor(150,150,150,150));

	//register our VesselSceneNode - just staticly at the moment, but will do it later
	vessels.push_back(new VesselSceneNode("C:\\Other Stuff\\Orbiter\\shipyard\\Config\\Vessels\\ProjectAlpha_ISS.cfg",
		smgr->getRootSceneNode(), smgr, 72));

	//start the loop
	while (device->run())
	{
		//see if we are pressing control o- so we can open a open file dialog
		if ((isKeyDown[KEY_LCONTROL] || isKeyDown[KEY_RCONTROL] || isKeyDown[KEY_CONTROL])
			&& isKeyDown[KEY_KEY_O] && !isOpenDialogOpen)
		{
			guiEnv->addFileOpenDialog(L"Select Config File", true, 0, -1, true);
			isOpenDialogOpen = true;
		}

		driver->beginScene(true, true, video::SColor(0, 100, 100, 100));

		smgr->drawAll();

		guiEnv->drawAll();

		driver->endScene();
	}
	//drop all vessels
	for (int i = 0; i < vessels.size(); i++)
	{
		vessels[0]->drop();
		vessels.erase(vessels.begin());
	}
}

core::vector3df Shipyard::returnMouseRelativePos()
{
	core::vector3df mouse3DPos;
	if (selectedNode != 0)
	{
		//update the absolute position
		selectedNode->updateAbsolutePosition();
		//the plane point is from the center of the node, with the normal to the camera
		core::plane3df plane = core::plane3df(selectedNode->getAbsolutePosition(),
			camera->getTarget() - camera->getPosition());

		//now do a ray from the current mouse position
		core::line3df ray = collisionManager->getRayFromScreenCoordinates(device->getCursorControl()->getPosition());
		//if they intersect, set it equal to mouse3DPos
		plane.getIntersectionWithLine(ray.start, ray.getVector(), mouse3DPos);
	}
	return mouse3DPos;
}

bool Shipyard::OnEvent(const SEvent& event)
{
	switch (event.EventType)
	{
	case EET_GUI_EVENT:
		switch (event.GUIEvent.EventType)
		{
		case gui::EGET_FILE_SELECTED:
		{
			(gui::IGUIFileOpenDialog*)event.GUIEvent.Caller;
			std::wstring uniString = std::wstring(((gui::IGUIFileOpenDialog*)event.GUIEvent.Caller)->getFileName());
			std::string filename = std::string(uniString.begin(), uniString.end());
			//create a new vessel
			vessels.push_back(new VesselSceneNode(filename, smgr->getRootSceneNode(), smgr, 72));
			isOpenDialogOpen = false;
			break;
		}
		case gui::EGET_FILE_CHOOSE_DIALOG_CANCELLED:
			isOpenDialogOpen = false;
			break;
		}
		break;
	case EET_KEY_INPUT_EVENT:
		//it's a key, store it
		isKeyDown[event.KeyInput.Key] = event.KeyInput.PressedDown;
		break;
	case EET_MOUSE_INPUT_EVENT:
		switch (event.MouseInput.Event)
		{
		case EMIE_LMOUSE_PRESSED_DOWN:
			//return if we have the dialog open
			if (isOpenDialogOpen)
				return false;
			//if we have a selected node, deselect it
			if (selectedNode != 0)
			{
				//de-show docking ports
				((VesselSceneNode*)selectedNode)->changeDockingPortVisibility(false, false);
				selectedNode = 0;
				return true;
			}
			//try to select a node
			selectedNode = 0;
			selectedNode = collisionManager->getSceneNodeFromScreenCoordinatesBB(
				device->getCursorControl()->getPosition(), 72, true);
			if (selectedNode != 0)
			{
				//set mouse position
				originalMouse3DPos = returnMouseRelativePos();
				//set old node location
				originalNodePosition = selectedNode->getPosition();

				//show docking ports
				((VesselSceneNode*)selectedNode)->changeDockingPortVisibility(true, true);
			}

			//return true if we got a node
			return (selectedNode != 0);
			break;

		case EMIE_MOUSE_MOVED:
			//see if we have a node
			if (selectedNode != 0)
			{
				//calculate new mouse pos
				core::vector3df mouse3DPos = returnMouseRelativePos();
				//move the node by the difference of the two
				selectedNode->setPosition(originalNodePosition + (mouse3DPos - originalMouse3DPos));
			}
			break;
		}
		break;
	}
	return false;
}<commit_msg>Added ability to rotate selected nodes<commit_after>#include "Shipyard.h"

Shipyard::Shipyard()
{
	for (u32 i = 0; i<KEY_KEY_CODES_COUNT; ++i)
		isKeyDown[i] = false;
	isOpenDialogOpen = false;
}

void Shipyard::setupDevice(IrrlichtDevice * _device)
{
	device = _device;
	smgr = device->getSceneManager();
	collisionManager = smgr->getSceneCollisionManager();
	guiEnv = device->getGUIEnvironment();
}

void Shipyard::loop()
{
	video::IVideoDriver* driver = device->getVideoDriver();

	//add the camera
	camera = smgr->addCameraSceneNode();
	if (camera)
	{
		scene::ISceneNodeAnimator* anm = new scene::CSceneNodeAnimatorCameraCustom(device->getCursorControl());

		camera->addAnimator(anm);
		anm->drop();
	}

	smgr->setAmbientLight(SColor(150,150,150,150));

	//register our VesselSceneNode - just staticly at the moment, but will do it later
	vessels.push_back(new VesselSceneNode("C:\\Other Stuff\\Orbiter\\shipyard\\Config\\Vessels\\ProjectAlpha_ISS.cfg",
		smgr->getRootSceneNode(), smgr, 72));

	//start the loop
	while (device->run())
	{
		//see if we are pressing control o- so we can open a open file dialog
		if ((isKeyDown[KEY_LCONTROL] || isKeyDown[KEY_RCONTROL] || isKeyDown[KEY_CONTROL])
			&& isKeyDown[KEY_KEY_O] && !isOpenDialogOpen)
		{
			guiEnv->addFileOpenDialog(L"Select Config File", true, 0, -1, true);
			isOpenDialogOpen = true;
		}

		driver->beginScene(true, true, video::SColor(0, 100, 100, 100));

		smgr->drawAll();

		guiEnv->drawAll();

		driver->endScene();
	}
	//drop all vessels
	for (int i = 0; i < vessels.size(); i++)
	{
		vessels[0]->drop();
		vessels.erase(vessels.begin());
	}
}

core::vector3df Shipyard::returnMouseRelativePos()
{
	core::vector3df mouse3DPos;
	if (selectedNode != 0)
	{
		//update the absolute position
		selectedNode->updateAbsolutePosition();
		//the plane point is from the center of the node, with the normal to the camera
		core::plane3df plane = core::plane3df(selectedNode->getAbsolutePosition(),
			camera->getTarget() - camera->getPosition());

		//now do a ray from the current mouse position
		core::line3df ray = collisionManager->getRayFromScreenCoordinates(device->getCursorControl()->getPosition());
		//if they intersect, set it equal to mouse3DPos
		plane.getIntersectionWithLine(ray.start, ray.getVector(), mouse3DPos);
	}
	return mouse3DPos;
}

bool Shipyard::OnEvent(const SEvent& event)
{
	switch (event.EventType)
	{
	case EET_GUI_EVENT:
		switch (event.GUIEvent.EventType)
		{
		case gui::EGET_FILE_SELECTED:
		{
			(gui::IGUIFileOpenDialog*)event.GUIEvent.Caller;
			std::wstring uniString = std::wstring(((gui::IGUIFileOpenDialog*)event.GUIEvent.Caller)->getFileName());
			std::string filename = std::string(uniString.begin(), uniString.end());
			//create a new vessel
			vessels.push_back(new VesselSceneNode(filename, smgr->getRootSceneNode(), smgr, 72));
			isOpenDialogOpen = false;
			break;
		}
		case gui::EGET_FILE_CHOOSE_DIALOG_CANCELLED:
			isOpenDialogOpen = false;
			break;
		}
		break;
	case EET_KEY_INPUT_EVENT:
		//it's a key, store it
		isKeyDown[event.KeyInput.Key] = event.KeyInput.PressedDown;
		//if we are dragging a node, see if it is a rotation
		if (selectedNode != 0 && event.KeyInput.PressedDown)
		{
			core::vector3df currentRotation = selectedNode->getRotation();
			switch (event.KeyInput.Key)
			{
			case KEY_KEY_A:
				currentRotation.Y -= 90;
				break;
			case KEY_KEY_D:
				currentRotation.Y += 90;
				break;
			case KEY_KEY_S:
				currentRotation.Z -= 90;
				break;
			case KEY_KEY_W:
				currentRotation.Z += 90;
				break;
			case KEY_KEY_Q:
				currentRotation.X -= 90;
				break;
			case KEY_KEY_E:
				currentRotation.X += 90;
				break;
			default:
				break;
			}
			//set rotation
			selectedNode->setRotation(currentRotation);
		}
		break;
	case EET_MOUSE_INPUT_EVENT:
		switch (event.MouseInput.Event)
		{
		case EMIE_LMOUSE_PRESSED_DOWN:
			//return if we have the dialog open
			if (isOpenDialogOpen)
				return false;
			//if we have a selected node, deselect it
			if (selectedNode != 0)
			{
				//de-show docking ports
				((VesselSceneNode*)selectedNode)->changeDockingPortVisibility(false, false);
				selectedNode = 0;
				return true;
			}
			//try to select a node
			selectedNode = 0;
			selectedNode = collisionManager->getSceneNodeFromScreenCoordinatesBB(
				device->getCursorControl()->getPosition(), 72, true);
			if (selectedNode != 0)
			{
				//set mouse position
				originalMouse3DPos = returnMouseRelativePos();
				//set old node location
				originalNodePosition = selectedNode->getPosition();

				//show docking ports
				((VesselSceneNode*)selectedNode)->changeDockingPortVisibility(true, true);
			}

			//return true if we got a node
			return (selectedNode != 0);
			break;

		case EMIE_MOUSE_MOVED:
			//see if we have a node
			if (selectedNode != 0)
			{
				//calculate new mouse pos
				core::vector3df mouse3DPos = returnMouseRelativePos();
				//move the node by the difference of the two
				selectedNode->setPosition(originalNodePosition + (mouse3DPos - originalMouse3DPos));
			}
			break;
		}
		break;
	}
	return false;
}<|endoftext|>


<commit_before>#include "MouseCtrl.h"
#include <iostream>
#include <time.h>

MouseCtrl::MouseCtrl()
{
    ZeroMemory(&mi, sizeof(MOUSEINPUT));
    lastMouseMoveX = clock() * (1000 / CLOCKS_PER_SEC);
    lastMouseMoveY = lastMouseMoveX;
    lastMouseScroll = lastMouseMoveX;
    minMoveXTimeDelta = DEFAULT_MIN_MOVE_TIME;
    minMoveYTimeDelta = DEFAULT_MIN_MOVE_TIME;
    scrollRate = DEFAULT_SCROLL_RATE;
    //std::cout << "time on mouseCtrlCreate = " << lastMouseMovement << std::endl;
}

void MouseCtrl::setScrollRate(int rate)
{
    if (rate < -WHEEL_DELTA || rate > WHEEL_DELTA)
    {
        scrollRate = DEFAULT_SCROLL_RATE;
    }
    else
    {
        scrollRate = rate;
    }
}

void MouseCtrl::setMinMoveXTimeDelta(unsigned int rate)
{
    int moveXRate = min(rate, 100);

    minMoveXTimeDelta = MAX_MOVE_TIME_DELTA - ((rate / 100.0) * MAX_MOVE_TIME_DELTA);
}

void MouseCtrl::setMinMoveYTimeDelta(unsigned int rate)
{
    int moveYRate = min(rate, 100);

    minMoveYTimeDelta = MAX_MOVE_TIME_DELTA - ((rate / 100.0) * MAX_MOVE_TIME_DELTA);
}

void MouseCtrl::sendCommand(mouseCmds mouseCmd, bool releaseIfClick, int mouseRateIfMove)
{
    ZeroMemory(&mi, sizeof(MOUSEINPUT));
    DWORD currentTime = clock() * (1000 / CLOCKS_PER_SEC);
    DWORD deltaTimeXMove = currentTime - lastMouseMoveX;
    DWORD deltaTimeYMove = currentTime - lastMouseMoveY;
    DWORD deltaTimeScroll = currentTime - lastMouseScroll;

    switch (mouseCmd)
    {
    case mouseCmds::LEFT_CLICK:
        mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
        break;
    case mouseCmds::RIGHT_CLICK:
        mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;
        break;
    case mouseCmds::MIDDLE_CLICK:
        mi.dwFlags = MOUSEEVENTF_MIDDLEDOWN;
        break;
    case mouseCmds::MOVE_LEFT:
        if (deltaTimeXMove < minMoveXTimeDelta)
            return;
        else
            lastMouseMoveX = currentTime;
        if (mouseRateIfMove >= 0)
            setMinMoveXTimeDelta(mouseRateIfMove);
        mi.dwFlags = MOUSEEVENTF_MOVE;
        mi.dx = -1;
        break;
    case mouseCmds::MOVE_RIGHT:
        if (deltaTimeXMove < minMoveXTimeDelta)
            return;
        else
            lastMouseMoveX = currentTime;
        if (mouseRateIfMove >= 0)
            setMinMoveXTimeDelta(mouseRateIfMove);
        mi.dwFlags = MOUSEEVENTF_MOVE;
        mi.dx = 1;
        break;
    case mouseCmds::MOVE_UP:
        if (deltaTimeYMove < minMoveYTimeDelta)
            return;
        else
            lastMouseMoveY = currentTime;
        if (mouseRateIfMove >= 0)
            setMinMoveYTimeDelta(mouseRateIfMove);
        mi.dwFlags = MOUSEEVENTF_MOVE;
        mi.dy = -1; // negative moves up.
        break;
    case mouseCmds::MOVE_DOWN:
        if (deltaTimeYMove < minMoveYTimeDelta)
            return;
        else
            lastMouseMoveY = currentTime;
        if (mouseRateIfMove >= 0)
            setMinMoveYTimeDelta(mouseRateIfMove);
        mi.dwFlags = MOUSEEVENTF_MOVE;
        mi.dy = 1;
        break;
    case mouseCmds::SCROLL_LEFT:
        //TODO - Not working
        mi.dwFlags = MOUSEEVENTF_HWHEEL;
        mi.mouseData = -scrollRate;
        break;
    case mouseCmds::SCROLL_RIGHT:
        //TODO - Not working
        mi.dwFlags = MOUSEEVENTF_HWHEEL;
        mi.mouseData = scrollRate;
        break;
    case mouseCmds::SCROLL_UP:
        mi.dwFlags = MOUSEEVENTF_WHEEL;
        mi.mouseData = scrollRate; // RANGE IS FROM -120 to +120 - WHEEL_DELTA = 120, which is one "wheel click"
        break;
    case mouseCmds::SCROLL_DOWN:
        mi.dwFlags = MOUSEEVENTF_WHEEL;
        mi.mouseData = -scrollRate; // RANGE IS FROM -120 to +120 - WHEEL_DELTA = 120, which is one "wheel click"
        break;
    }

    //TODO - assert if mi.dx != 0, then mi.dy == 0

    //if (mi.dwFlags == MOUSEEVENTF_MOVE &&
    //    ((lastMouseMoveX < minMoveXTimeDelta && mi.dx != 0) ||
    //    (lastMouseMoveY < minMoveYTimeDelta && mi.dy != 0))
    //    )
    //{
    //    // Not enough time has passed to move the mouse again
    //    return;
    //}
    //else
    //{
    //    if (mi.dx != 0)
    //    {
    //        lastMouseMoveX = currentTime;
    //    }
    //    if (mi.dy != 0)
    //    {
    //        lastMouseMoveY = currentTime;
    //    }
    //}

    if (deltaTimeScroll < SCROLL_MIN_TIME &&
        (mi.dwFlags == MOUSEEVENTF_WHEEL ||
        mi.dwFlags == MOUSEEVENTF_HWHEEL))
    {
        // Not enough time has passed to move the mouse again
        return;
    }
    else
    {
        lastMouseScroll = currentTime;
    }

    INPUT* in = new INPUT();
    in->type = INPUT_MOUSE;
    in->mi = mi;
    SendInput(1, in, sizeof(INPUT));

    if (releaseIfClick)
    {
        ZeroMemory(&mi, sizeof(MOUSEINPUT));
        switch (mouseCmd)
        {
        case mouseCmds::LEFT_CLICK:
            mi.dwFlags = MOUSEEVENTF_LEFTUP;
            break;
        case mouseCmds::RIGHT_CLICK:
            mi.dwFlags = MOUSEEVENTF_RIGHTUP;
            break;
        case mouseCmds::MIDDLE_CLICK:
            mi.dwFlags = MOUSEEVENTF_MIDDLEUP;
            break;
        default:
            goto done;
        }

        in->type = INPUT_MOUSE;
        in->mi = mi;
        SendInput(1, in, sizeof(INPUT));
    }

    done:
    delete in; in = NULL;
}<commit_msg>cleaned up crap code<commit_after>#include "MouseCtrl.h"
#include <iostream>
#include <time.h>

MouseCtrl::MouseCtrl()
{
    ZeroMemory(&mi, sizeof(MOUSEINPUT));
    lastMouseMoveX = clock() * (1000 / CLOCKS_PER_SEC);
    lastMouseMoveY = lastMouseMoveX;
    lastMouseScroll = lastMouseMoveX;
    minMoveXTimeDelta = DEFAULT_MIN_MOVE_TIME;
    minMoveYTimeDelta = DEFAULT_MIN_MOVE_TIME;
    scrollRate = DEFAULT_SCROLL_RATE;
    //std::cout << "time on mouseCtrlCreate = " << lastMouseMovement << std::endl;
}

void MouseCtrl::setScrollRate(int rate)
{
    if (rate < -WHEEL_DELTA || rate > WHEEL_DELTA)
    {
        scrollRate = DEFAULT_SCROLL_RATE;
    }
    else
    {
        scrollRate = rate;
    }
}

void MouseCtrl::setMinMoveXTimeDelta(unsigned int rate)
{
    int moveXRate = min(rate, 100);

    minMoveXTimeDelta = MAX_MOVE_TIME_DELTA - ((rate / 100.0) * MAX_MOVE_TIME_DELTA);
}

void MouseCtrl::setMinMoveYTimeDelta(unsigned int rate)
{
    int moveYRate = min(rate, 100);

    minMoveYTimeDelta = MAX_MOVE_TIME_DELTA - ((rate / 100.0) * MAX_MOVE_TIME_DELTA);
}

void MouseCtrl::sendCommand(mouseCmds mouseCmd, bool releaseIfClick, int mouseRateIfMove)
{
    ZeroMemory(&mi, sizeof(MOUSEINPUT));
    DWORD currentTime = clock() * (1000 / CLOCKS_PER_SEC);
    DWORD deltaTimeXMove = currentTime - lastMouseMoveX;
    DWORD deltaTimeYMove = currentTime - lastMouseMoveY;
    DWORD deltaTimeScroll = currentTime - lastMouseScroll;

    switch (mouseCmd)
    {
    case mouseCmds::LEFT_CLICK:
        mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
        break;
    case mouseCmds::RIGHT_CLICK:
        mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;
        break;
    case mouseCmds::MIDDLE_CLICK:
        mi.dwFlags = MOUSEEVENTF_MIDDLEDOWN;
        break;
    case mouseCmds::MOVE_LEFT:
        if (mouseRateIfMove >= 0)
            setMinMoveXTimeDelta(mouseRateIfMove);
        mi.dwFlags = MOUSEEVENTF_MOVE;
        mi.dx = -1;
        break;
    case mouseCmds::MOVE_RIGHT:
        if (mouseRateIfMove >= 0)
            setMinMoveXTimeDelta(mouseRateIfMove);
        mi.dwFlags = MOUSEEVENTF_MOVE;
        mi.dx = 1;
        break;
    case mouseCmds::MOVE_UP:
        if (mouseRateIfMove >= 0)
            setMinMoveYTimeDelta(mouseRateIfMove);
        mi.dwFlags = MOUSEEVENTF_MOVE;
        mi.dy = -1; // negative moves up.
        break;
    case mouseCmds::MOVE_DOWN:
        if (mouseRateIfMove >= 0)
            setMinMoveYTimeDelta(mouseRateIfMove);
        mi.dwFlags = MOUSEEVENTF_MOVE;
        mi.dy = 1;
        break;
    case mouseCmds::SCROLL_LEFT:
        //TODO - Not working
        mi.dwFlags = MOUSEEVENTF_HWHEEL;
        mi.mouseData = -scrollRate;
        break;
    case mouseCmds::SCROLL_RIGHT:
        //TODO - Not working
        mi.dwFlags = MOUSEEVENTF_HWHEEL;
        mi.mouseData = scrollRate;
        break;
    case mouseCmds::SCROLL_UP:
        mi.dwFlags = MOUSEEVENTF_WHEEL;
        mi.mouseData = scrollRate; // RANGE IS FROM -120 to +120 - WHEEL_DELTA = 120, which is one "wheel click"
        break;
    case mouseCmds::SCROLL_DOWN:
        mi.dwFlags = MOUSEEVENTF_WHEEL;
        mi.mouseData = -scrollRate; // RANGE IS FROM -120 to +120 - WHEEL_DELTA = 120, which is one "wheel click"
        break;
    }

    //TODO - assert if mi.dx != 0, then mi.dy == 0

    if (mi.dwFlags == MOUSEEVENTF_MOVE &&
        ((deltaTimeXMove < minMoveXTimeDelta && mi.dx != 0) ||
        (deltaTimeYMove < minMoveYTimeDelta && mi.dy != 0))
        )
    {
        // Not enough time has passed to move the mouse again
        return;
    }
    else
    {
        if (mi.dx != 0)
        {
            lastMouseMoveX = currentTime;
        }
        if (mi.dy != 0)
        {
            lastMouseMoveY = currentTime;
        }
    }

    if (deltaTimeScroll < SCROLL_MIN_TIME &&
        (mi.dwFlags == MOUSEEVENTF_WHEEL ||
        mi.dwFlags == MOUSEEVENTF_HWHEEL))
    {
        // Not enough time has passed to move the mouse again
        return;
    }
    else
    {
        lastMouseScroll = currentTime;
    }

    INPUT* in = new INPUT();
    in->type = INPUT_MOUSE;
    in->mi = mi;
    SendInput(1, in, sizeof(INPUT));

    if (releaseIfClick)
    {
        ZeroMemory(&mi, sizeof(MOUSEINPUT));
        switch (mouseCmd)
        {
        case mouseCmds::LEFT_CLICK:
            mi.dwFlags = MOUSEEVENTF_LEFTUP;
            break;
        case mouseCmds::RIGHT_CLICK:
            mi.dwFlags = MOUSEEVENTF_RIGHTUP;
            break;
        case mouseCmds::MIDDLE_CLICK:
            mi.dwFlags = MOUSEEVENTF_MIDDLEUP;
            break;
        default:
            goto done;
        }

        in->type = INPUT_MOUSE;
        in->mi = mi;
        SendInput(1, in, sizeof(INPUT));
    }

    done:
    delete in; in = NULL;
}<|endoftext|>


<commit_before>// Needed to have working asserts also when building in release mode
#ifdef NDEBUG
#undef NDEBUG
#endif

#include "helpers.h"
#include <cassert>
#include <iostream>
#include <tuple>

int main() {
  assert(ends_with("foobar", "bar"));
  assert(!ends_with("foobar", "foo"));

  MergeInput a("file0.root", 0);
  MergeInput b("file1.root", 1);
  assert(a.filename == "file0.root");
  assert(a.order == 0);

  MergeInputComparator comparator;
  assert(comparator(a, b) == true);

  MergeJob job1("foo.root", 1);
  assert(job1.output == "foo.root");
  MergeJob job2("bar", 1);
  assert(job2.output == "bar.root");
  MergeJob job3("bar", 2);
  assert(job3.output == "bar1.root");
  MergeJob job4("bar.root", 2);
  assert(job4.output == "bar2.root");
}
<commit_msg>Remove unneeded header<commit_after>// Needed to have working asserts also when building in release mode
#ifdef NDEBUG
#undef NDEBUG
#endif

#include "helpers.h"
#include <cassert>
#include <iostream>

int main() {
  assert(ends_with("foobar", "bar"));
  assert(!ends_with("foobar", "foo"));

  MergeInput a("file0.root", 0);
  MergeInput b("file1.root", 1);
  assert(a.filename == "file0.root");
  assert(a.order == 0);

  MergeInputComparator comparator;
  assert(comparator(a, b) == true);

  MergeJob job1("foo.root", 1);
  assert(job1.output == "foo.root");
  MergeJob job2("bar", 1);
  assert(job2.output == "bar.root");
  MergeJob job3("bar", 2);
  assert(job3.output == "bar1.root");
  MergeJob job4("bar.root", 2);
  assert(job4.output == "bar2.root");
}
<|endoftext|>


<commit_before>// Copyright 2010-2014 RethinkDB, all rights reserved.
#ifndef BUFFER_CACHE_ALT_ALT_HPP_
#define BUFFER_CACHE_ALT_ALT_HPP_

#include <map>
#include <vector>
#include <utility>

#include "buffer_cache/alt/page.hpp"
#include "buffer_cache/types.hpp"
#include "containers/two_level_array.hpp"
#include "repli_timestamp.hpp"
#include "utils.hpp"

class serializer_t;

class buf_lock_t;
class alt_cache_config_t;
class alt_cache_stats_t;
class alt_snapshot_node_t;

class alt_memory_tracker_t : public memory_tracker_t {
public:
    alt_memory_tracker_t();
    ~alt_memory_tracker_t();

private:
    friend class txn_t;

    void inform_memory_change(uint64_t in_memory_size,
                              uint64_t memory_limit);
    alt::tracker_acq_t begin_txn_or_throttle(int64_t expected_change_count);
    void end_txn(alt::tracker_acq_t acq);

    new_semaphore_t semaphore_;
    DISABLE_COPYING(alt_memory_tracker_t);
};

class cache_t : public home_thread_mixin_t {
public:
    explicit cache_t(serializer_t *serializer,
                     const alt_cache_config_t &dynamic_config,
                     perfmon_collection_t *perfmon_collection);
    ~cache_t();

    block_size_t max_block_size() const;
    // KSI: Remove this.
    block_size_t get_block_size() const { return max_block_size(); }

    // These todos come from the mirrored cache.  The real problem is that whole
    // cache account / priority thing is just one ghetto hack amidst a dozen other
    // throttling systems.  TODO: Come up with a consistent priority scheme,
    // i.e. define a "default" priority etc.  TODO: As soon as we can support it, we
    // might consider supporting a mem_cap paremeter.
    void create_cache_account(int priority, scoped_ptr_t<alt_cache_account_t> *out);

private:
    friend class txn_t;
    friend class buf_read_t;
    friend class buf_write_t;
    friend class buf_lock_t;

    alt_snapshot_node_t *matching_snapshot_node_or_null(block_id_t block_id,
                                                        block_version_t block_version);
    void add_snapshot_node(block_id_t block_id, alt_snapshot_node_t *node);
    void remove_snapshot_node(block_id_t block_id, alt_snapshot_node_t *node);

    scoped_ptr_t<alt_cache_stats_t> stats_;

    // tracker_ is used for throttling (which can cause the txn_t constructor to
    // block).  RSI: The throttling interface is bad (maybe) because it's worried
    // about transaction_t's passing one another(?) or maybe the callers are bad with
    // their use of chained mutexes.  Make sure that timestamps don't get mixed up in
    // their ordering, once they begin to play a role.
    alt_memory_tracker_t tracker_;
    alt::page_cache_t page_cache_;

    two_level_nevershrink_array_t<intrusive_list_t<alt_snapshot_node_t> > snapshot_nodes_by_block_id_;

    DISABLE_COPYING(cache_t);
};

class txn_t {
public:
    // Constructor for read-only transactions.
    txn_t(cache_conn_t *cache_conn, read_access_t read_access);

    // KSI: Remove default parameter for expected_change_count.
    // RSI: Generally speaking I don't think we use preceding_txn and we should.
    txn_t(cache_conn_t *cache_conn,
          write_durability_t durability,
          repli_timestamp_t txn_timestamp,
          int64_t expected_change_count = 2);

    ~txn_t();

    cache_t *cache() { return cache_; }
    alt::page_txn_t *page_txn() { return page_txn_.get(); }
    access_t access() const { return access_; }

    void set_account(alt_cache_account_t *cache_account);

private:
    static void inform_tracker(cache_t *cache,
                               alt::tracker_acq_t tracker_acq);

    static void pulse_and_inform_tracker(cache_t *cache,
                                         alt::tracker_acq_t tracker_acq,
                                         cond_t *pulsee);

    void help_construct(repli_timestamp_t txn_timestamp,
                        int64_t expected_change_count,
                        cache_conn_t *cache_conn);

    cache_t *const cache_;

    const access_t access_;

    // Only applicable if access_ == write.
    const write_durability_t durability_;

    scoped_ptr_t<alt::page_txn_t> page_txn_;

    DISABLE_COPYING(txn_t);
};

class buf_parent_t;

class buf_lock_t {
public:
    buf_lock_t();

    // buf_parent_t is a type that either points at a buf_lock_t (its parent) or
    // merely at a txn_t (e.g. for acquiring the superblock, which has no parent).
    // If acquiring the child for read, the constructor will wait for the parent to
    // be acquired for read.  Similarly, if acquiring the child for write, the
    // constructor will wait for the parent to be acquired for write.  Once the
    // constructor returns, you are "in line" for the block, meaning you'll acquire
    // it in the same order relative other agents as you did when acquiring the same
    // parent.  (Of course, readers can intermingle.)

    // These constructors will _not_ yield the coroutine _if_ the parent is already
    // {access}-acquired.

    // Acquires an existing block for read or write access.
    buf_lock_t(buf_parent_t parent,
               block_id_t block_id,
               access_t access);

    // Creates a new block with a specified block id, one that doesn't have a parent.
    buf_lock_t(txn_t *txn,
               block_id_t block_id,
               alt_create_t create);

    // Creates a new block with a specified block id as the child of a parent (if it's
    // not just a txn_t *).
    buf_lock_t(buf_parent_t parent,
               block_id_t block_id,
               alt_create_t create);

    // Acquires an existing block given the parent.
    buf_lock_t(buf_lock_t *parent,
               block_id_t block_id,
               access_t access);

    // Creates a block, a new child of the given parent.  It gets assigned a block id
    // from one of the unused block id's.
    buf_lock_t(buf_parent_t parent,
               alt_create_t create);

    // Creates a block, a new child of the given parent.  It gets assigned a block id
    // from one of the unused block id's.
    buf_lock_t(buf_lock_t *parent,
               alt_create_t create);

    ~buf_lock_t();

    buf_lock_t(buf_lock_t &&movee);
    buf_lock_t &operator=(buf_lock_t &&movee);

    void swap(buf_lock_t &other);
    void reset_buf_lock();
    bool empty() const {
        return txn_ == NULL;
    }

    void snapshot_subdag();

    void detach_child(block_id_t child_id);

    block_id_t block_id() const {
        guarantee(txn_ != NULL);
        return current_page_acq()->block_id();
    }

    repli_timestamp_t get_recency() const;

    access_t access() const {
        guarantee(!empty());
        return current_page_acq()->access();
    }

    signal_t *read_acq_signal() {
        guarantee(!empty());
        return current_page_acq()->read_acq_signal();
    }
    signal_t *write_acq_signal() {
        guarantee(!empty());
        return current_page_acq()->write_acq_signal();
    }

    void mark_deleted();

    txn_t *txn() const { return txn_; }
    cache_t *cache() const { return txn_->cache(); }

private:
    void help_construct(buf_parent_t parent, block_id_t block_id, access_t access);
    void help_construct(buf_parent_t parent, alt_create_t create);
    void help_construct(buf_parent_t parent, block_id_t block_id, alt_create_t create);

    static void wait_for_parent(buf_parent_t parent, access_t access);
    static alt_snapshot_node_t *
    get_or_create_child_snapshot_node(cache_t *cache,
                                      alt_snapshot_node_t *parent,
                                      block_id_t child_id);
    static void create_empty_child_snapshot_nodes(cache_t *cache,
                                                  block_version_t parent_version,
                                                  block_id_t parent_id,
                                                  block_id_t child_id);
    static void create_child_snapshot_nodes(cache_t *cache,
                                            block_version_t parent_version,
                                            block_id_t parent_id,
                                            block_id_t child_id);
    alt::current_page_acq_t *current_page_acq() const;

    friend class buf_read_t;  // for get_held_page_for_read, access_ref_count_.
    friend class buf_write_t;  // for get_held_page_for_write, access_ref_count_.

    alt::page_t *get_held_page_for_read();
    alt::page_t *get_held_page_for_write();

    txn_t *txn_;

    scoped_ptr_t<alt::current_page_acq_t> current_page_acq_;

    alt_snapshot_node_t *snapshot_node_;

    // Keeps track of how many alt_buf_{read|write}_t have been created for
    // this lock, for assertion/guarantee purposes.
    intptr_t access_ref_count_;

    DISABLE_COPYING(buf_lock_t);
};

class buf_parent_t {
public:
    buf_parent_t() : txn_(NULL), lock_or_null_(NULL) { }

    explicit buf_parent_t(buf_lock_t *lock)
        : txn_(lock->txn()), lock_or_null_(lock) {
        guarantee(lock != NULL);
        guarantee(!lock->empty());
    }

    explicit buf_parent_t(txn_t *txn)
        : txn_(txn), lock_or_null_(NULL) {
        rassert(txn != NULL);
    }

    void detach_child(block_id_t child_id) {
        if (lock_or_null_ != NULL) {
            lock_or_null_->detach_child(child_id);
        }
    }

    bool empty() const {
        return txn_ == NULL;
    }

    txn_t *txn() const {
        guarantee(!empty());
        return txn_;
    }
    cache_t *cache() const {
        guarantee(!empty());
        return txn_->cache();
    }

private:
    friend class buf_lock_t;
    txn_t *txn_;
    buf_lock_t *lock_or_null_;
};

class buf_read_t {
public:
    explicit buf_read_t(buf_lock_t *lock);
    ~buf_read_t();

    const void *get_data_read(uint32_t *block_size_out);
    const void *get_data_read() {
        uint32_t block_size;
        const void *data = get_data_read(&block_size);
        guarantee(block_size == lock_->cache()->max_block_size().value());
        return data;
    }

private:
    buf_lock_t *lock_;
    alt::page_acq_t page_acq_;

    DISABLE_COPYING(buf_read_t);
};

class buf_write_t {
public:
    explicit buf_write_t(buf_lock_t *lock);
    ~buf_write_t();

    void *get_data_write(uint32_t block_size);
    // Equivalent to passing the max_block_size.
    void *get_data_write();

private:
    buf_lock_t *lock_;
    alt::page_acq_t page_acq_;

    DISABLE_COPYING(buf_write_t);
};

#endif  // BUFFER_CACHE_ALT_ALT_HPP_
<commit_msg>Removed fixed RSI.<commit_after>// Copyright 2010-2014 RethinkDB, all rights reserved.
#ifndef BUFFER_CACHE_ALT_ALT_HPP_
#define BUFFER_CACHE_ALT_ALT_HPP_

#include <map>
#include <vector>
#include <utility>

#include "buffer_cache/alt/page.hpp"
#include "buffer_cache/types.hpp"
#include "containers/two_level_array.hpp"
#include "repli_timestamp.hpp"
#include "utils.hpp"

class serializer_t;

class buf_lock_t;
class alt_cache_config_t;
class alt_cache_stats_t;
class alt_snapshot_node_t;

class alt_memory_tracker_t : public memory_tracker_t {
public:
    alt_memory_tracker_t();
    ~alt_memory_tracker_t();

private:
    friend class txn_t;

    void inform_memory_change(uint64_t in_memory_size,
                              uint64_t memory_limit);
    alt::tracker_acq_t begin_txn_or_throttle(int64_t expected_change_count);
    void end_txn(alt::tracker_acq_t acq);

    new_semaphore_t semaphore_;
    DISABLE_COPYING(alt_memory_tracker_t);
};

class cache_t : public home_thread_mixin_t {
public:
    explicit cache_t(serializer_t *serializer,
                     const alt_cache_config_t &dynamic_config,
                     perfmon_collection_t *perfmon_collection);
    ~cache_t();

    block_size_t max_block_size() const;
    // KSI: Remove this.
    block_size_t get_block_size() const { return max_block_size(); }

    // These todos come from the mirrored cache.  The real problem is that whole
    // cache account / priority thing is just one ghetto hack amidst a dozen other
    // throttling systems.  TODO: Come up with a consistent priority scheme,
    // i.e. define a "default" priority etc.  TODO: As soon as we can support it, we
    // might consider supporting a mem_cap paremeter.
    void create_cache_account(int priority, scoped_ptr_t<alt_cache_account_t> *out);

private:
    friend class txn_t;
    friend class buf_read_t;
    friend class buf_write_t;
    friend class buf_lock_t;

    alt_snapshot_node_t *matching_snapshot_node_or_null(block_id_t block_id,
                                                        block_version_t block_version);
    void add_snapshot_node(block_id_t block_id, alt_snapshot_node_t *node);
    void remove_snapshot_node(block_id_t block_id, alt_snapshot_node_t *node);

    scoped_ptr_t<alt_cache_stats_t> stats_;

    // tracker_ is used for throttling (which can cause the txn_t constructor to
    // block).  RSI: The throttling interface is bad (maybe) because it's worried
    // about transaction_t's passing one another(?) or maybe the callers are bad with
    // their use of chained mutexes.  Make sure that timestamps don't get mixed up in
    // their ordering, once they begin to play a role.
    alt_memory_tracker_t tracker_;
    alt::page_cache_t page_cache_;

    two_level_nevershrink_array_t<intrusive_list_t<alt_snapshot_node_t> > snapshot_nodes_by_block_id_;

    DISABLE_COPYING(cache_t);
};

class txn_t {
public:
    // Constructor for read-only transactions.
    txn_t(cache_conn_t *cache_conn, read_access_t read_access);

    // KSI: Remove default parameter for expected_change_count.
    txn_t(cache_conn_t *cache_conn,
          write_durability_t durability,
          repli_timestamp_t txn_timestamp,
          int64_t expected_change_count = 2);

    ~txn_t();

    cache_t *cache() { return cache_; }
    alt::page_txn_t *page_txn() { return page_txn_.get(); }
    access_t access() const { return access_; }

    void set_account(alt_cache_account_t *cache_account);

private:
    static void inform_tracker(cache_t *cache,
                               alt::tracker_acq_t tracker_acq);

    static void pulse_and_inform_tracker(cache_t *cache,
                                         alt::tracker_acq_t tracker_acq,
                                         cond_t *pulsee);

    void help_construct(repli_timestamp_t txn_timestamp,
                        int64_t expected_change_count,
                        cache_conn_t *cache_conn);

    cache_t *const cache_;

    const access_t access_;

    // Only applicable if access_ == write.
    const write_durability_t durability_;

    scoped_ptr_t<alt::page_txn_t> page_txn_;

    DISABLE_COPYING(txn_t);
};

class buf_parent_t;

class buf_lock_t {
public:
    buf_lock_t();

    // buf_parent_t is a type that either points at a buf_lock_t (its parent) or
    // merely at a txn_t (e.g. for acquiring the superblock, which has no parent).
    // If acquiring the child for read, the constructor will wait for the parent to
    // be acquired for read.  Similarly, if acquiring the child for write, the
    // constructor will wait for the parent to be acquired for write.  Once the
    // constructor returns, you are "in line" for the block, meaning you'll acquire
    // it in the same order relative other agents as you did when acquiring the same
    // parent.  (Of course, readers can intermingle.)

    // These constructors will _not_ yield the coroutine _if_ the parent is already
    // {access}-acquired.

    // Acquires an existing block for read or write access.
    buf_lock_t(buf_parent_t parent,
               block_id_t block_id,
               access_t access);

    // Creates a new block with a specified block id, one that doesn't have a parent.
    buf_lock_t(txn_t *txn,
               block_id_t block_id,
               alt_create_t create);

    // Creates a new block with a specified block id as the child of a parent (if it's
    // not just a txn_t *).
    buf_lock_t(buf_parent_t parent,
               block_id_t block_id,
               alt_create_t create);

    // Acquires an existing block given the parent.
    buf_lock_t(buf_lock_t *parent,
               block_id_t block_id,
               access_t access);

    // Creates a block, a new child of the given parent.  It gets assigned a block id
    // from one of the unused block id's.
    buf_lock_t(buf_parent_t parent,
               alt_create_t create);

    // Creates a block, a new child of the given parent.  It gets assigned a block id
    // from one of the unused block id's.
    buf_lock_t(buf_lock_t *parent,
               alt_create_t create);

    ~buf_lock_t();

    buf_lock_t(buf_lock_t &&movee);
    buf_lock_t &operator=(buf_lock_t &&movee);

    void swap(buf_lock_t &other);
    void reset_buf_lock();
    bool empty() const {
        return txn_ == NULL;
    }

    void snapshot_subdag();

    void detach_child(block_id_t child_id);

    block_id_t block_id() const {
        guarantee(txn_ != NULL);
        return current_page_acq()->block_id();
    }

    repli_timestamp_t get_recency() const;

    access_t access() const {
        guarantee(!empty());
        return current_page_acq()->access();
    }

    signal_t *read_acq_signal() {
        guarantee(!empty());
        return current_page_acq()->read_acq_signal();
    }
    signal_t *write_acq_signal() {
        guarantee(!empty());
        return current_page_acq()->write_acq_signal();
    }

    void mark_deleted();

    txn_t *txn() const { return txn_; }
    cache_t *cache() const { return txn_->cache(); }

private:
    void help_construct(buf_parent_t parent, block_id_t block_id, access_t access);
    void help_construct(buf_parent_t parent, alt_create_t create);
    void help_construct(buf_parent_t parent, block_id_t block_id, alt_create_t create);

    static void wait_for_parent(buf_parent_t parent, access_t access);
    static alt_snapshot_node_t *
    get_or_create_child_snapshot_node(cache_t *cache,
                                      alt_snapshot_node_t *parent,
                                      block_id_t child_id);
    static void create_empty_child_snapshot_nodes(cache_t *cache,
                                                  block_version_t parent_version,
                                                  block_id_t parent_id,
                                                  block_id_t child_id);
    static void create_child_snapshot_nodes(cache_t *cache,
                                            block_version_t parent_version,
                                            block_id_t parent_id,
                                            block_id_t child_id);
    alt::current_page_acq_t *current_page_acq() const;

    friend class buf_read_t;  // for get_held_page_for_read, access_ref_count_.
    friend class buf_write_t;  // for get_held_page_for_write, access_ref_count_.

    alt::page_t *get_held_page_for_read();
    alt::page_t *get_held_page_for_write();

    txn_t *txn_;

    scoped_ptr_t<alt::current_page_acq_t> current_page_acq_;

    alt_snapshot_node_t *snapshot_node_;

    // Keeps track of how many alt_buf_{read|write}_t have been created for
    // this lock, for assertion/guarantee purposes.
    intptr_t access_ref_count_;

    DISABLE_COPYING(buf_lock_t);
};

class buf_parent_t {
public:
    buf_parent_t() : txn_(NULL), lock_or_null_(NULL) { }

    explicit buf_parent_t(buf_lock_t *lock)
        : txn_(lock->txn()), lock_or_null_(lock) {
        guarantee(lock != NULL);
        guarantee(!lock->empty());
    }

    explicit buf_parent_t(txn_t *txn)
        : txn_(txn), lock_or_null_(NULL) {
        rassert(txn != NULL);
    }

    void detach_child(block_id_t child_id) {
        if (lock_or_null_ != NULL) {
            lock_or_null_->detach_child(child_id);
        }
    }

    bool empty() const {
        return txn_ == NULL;
    }

    txn_t *txn() const {
        guarantee(!empty());
        return txn_;
    }
    cache_t *cache() const {
        guarantee(!empty());
        return txn_->cache();
    }

private:
    friend class buf_lock_t;
    txn_t *txn_;
    buf_lock_t *lock_or_null_;
};

class buf_read_t {
public:
    explicit buf_read_t(buf_lock_t *lock);
    ~buf_read_t();

    const void *get_data_read(uint32_t *block_size_out);
    const void *get_data_read() {
        uint32_t block_size;
        const void *data = get_data_read(&block_size);
        guarantee(block_size == lock_->cache()->max_block_size().value());
        return data;
    }

private:
    buf_lock_t *lock_;
    alt::page_acq_t page_acq_;

    DISABLE_COPYING(buf_read_t);
};

class buf_write_t {
public:
    explicit buf_write_t(buf_lock_t *lock);
    ~buf_write_t();

    void *get_data_write(uint32_t block_size);
    // Equivalent to passing the max_block_size.
    void *get_data_write();

private:
    buf_lock_t *lock_;
    alt::page_acq_t page_acq_;

    DISABLE_COPYING(buf_write_t);
};

#endif  // BUFFER_CACHE_ALT_ALT_HPP_
<|endoftext|>