<commit_before>/*
  pvsops.c: pvs and other spectral-based opcodes

  Copyright (C) 2017 Victor Lazzarini
  This file is part of Csound.

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

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

  You should have received a copy of the GNU Lesser General Public
  License along with Csound; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  02111-1307 USA
*/
#include <algorithm>
#include <plugin.h>

struct PVTrace : csnd::FPlugin<1, 2> {
  csnd::AuxMem<float> amps;
  static constexpr char const *otypes = "f";
  static constexpr char const *itypes = "fk";

  int init() {
    if (inargs.fsig_data(0).isSliding())
      return csound->init_error(Str("sliding not supported"));

    if (inargs.fsig_data(0).fsig_format() != csnd::fsig_format::pvs &&
        inargs.fsig_data(0).fsig_format() != csnd::fsig_format::polar)
      return csound->init_error(Str("fsig format not supported"));

    amps.allocate(csound, inargs.fsig_data(0).nbins());
    csnd::Fsig &fout = outargs.fsig_data(0);
    fout.init(csound, inargs.fsig_data(0));
    framecount = 0;
    return OK;
  }

  int kperf() {
    csnd::pv_frame &fin = inargs.fsig_data(0);
    csnd::pv_frame &fout = outargs.fsig_data(0);

    if (framecount < fin.count()) {
      int n = fin.len() - (int)inargs[1];
      float thrsh;
      std::transform(fin.begin(), fin.end(), amps.begin(),
                     [](csnd::pv_bin f) { return f.amp(); });
      std::nth_element(amps.begin(), amps.begin() + n, amps.end());
      thrsh = amps[n];
      std::transform(fin.begin(), fin.end(), fout.begin(),
                     [thrsh](csnd::pv_bin f) {
                       return f.amp() >= thrsh ? f : csnd::pv_bin();
                     });
      framecount = fout.count(fin.count());
    }
    return OK;
  }
};

struct TVConv : csnd::Plugin<1, 6> {
  csnd::AuxMem<MYFLT> ir;
  csnd::AuxMem<MYFLT> in;
  csnd::AuxMem<MYFLT> insp;
  csnd::AuxMem<MYFLT> irsp;
  csnd::AuxMem<MYFLT> out;
  csnd::AuxMem<MYFLT> saved;
  uint32_t n;
  uint32_t fils;
  uint32_t pars;
  uint32_t ffts;
  uint32_t nparts;
  uint32_t pp;
  csnd::fftp fwd, inv;
  typedef std::complex<MYFLT> cmplx;

  uint32_t rpow2(uint32_t n) {
    uint32_t v = 2;
    while (v <= n)
      v <<= 1;
    if ((n - (v >> 1)) < (v - n))
      return v >> 1;
    else
      return v;
  }

  cmplx *to_cmplx(MYFLT *f) { return reinterpret_cast<cmplx *>(f); }

  cmplx real_prod(cmplx &a, cmplx &b) {
    return cmplx(a.real() * b.real(), a.imag() * b.imag());
  }

  int init() {
    pars = inargs[4];
    fils = inargs[5];
    if (pars > fils)
      std::swap(pars, fils);
    if (pars > 1) {
      pars = rpow2(pars);
      fils = rpow2(fils);
      ffts = pars * 2;
      fwd = csound->fft_setup(ffts, FFT_FWD);
      inv = csound->fft_setup(ffts, FFT_INV);
      out.allocate(csound, 2 * pars);
      insp.allocate(csound, 2 * fils);
      irsp.allocate(csound, 2 * fils);
      saved.allocate(csound, pars);
      ir.allocate(csound, 2 * fils);
      in.allocate(csound, 2 * fils);
      nparts = fils / pars;
      fils *= 2;
    } else {
      ir.allocate(csound, fils);
      in.allocate(csound, fils);
    }
    n = 0;
    pp = 0;
    return OK;
  }

  int pconv() {
    csnd::AudioSig insig(this, inargs(0));
    csnd::AudioSig irsig(this, inargs(1));
    csnd::AudioSig outsig(this, outargs(0));
    auto irp = irsig.begin();
    auto inp = insig.begin();
    MYFLT *frz1 = inargs(2);
    MYFLT *frz2 = inargs(3);
    bool inc1 = csound->is_asig(frz1);
    bool inc2 = csound->is_asig(frz2);

    for (auto &s : outsig) {
      if(*frz1 > 0) in[pp + n] = *inp;
      if(*frz2 > 0) ir[pp + n] = *irp;

      s = out[n] + saved[n];
      saved[n] = out[n + pars];
      if (++n == pars) {
        cmplx *ins, *irs, *ous = to_cmplx(out.data());
        std::copy(in.begin() + pp, in.begin() + pp + ffts, insp.begin() + pp);
        std::copy(ir.begin() + pp, ir.begin() + pp + ffts, irsp.begin() + pp);
        std::fill(out.begin(), out.end(), 0.);
        // FFT
        csound->rfft(fwd, insp.data() + pp);
        csound->rfft(fwd, irsp.data() + pp);
        pp += ffts;
        if (pp == fils)
          pp = 0;
        // spectral delay line
        for (uint32_t k = 0, kp = pp; k < nparts; k++, kp += ffts) {
          if (kp == fils)
            kp = 0;
          ins = to_cmplx(insp.data() + kp);
          irs = to_cmplx(irsp.data() + (nparts - k - 1) * ffts);
          // spectral product
          for (uint32_t i = 1; i < pars; i++)
            ous[i] += ins[i] * irs[i];
          ous[0] += real_prod(ins[0], irs[0]);
        }
        // IFFT
        csound->rfft(inv, out.data());
        n = 0;
      }
      frz1 += inc1;
      frz2 += inc2;
      irp++;
      inp++;
    }
    return OK;
  }

  int pconv_ols() {
    csnd::AudioSig insig(this, inargs(0));
    csnd::AudioSig irsig(this, inargs(1));
    csnd::AudioSig outsig(this, outargs(0));
    auto irp = irsig.begin();
    auto inp = insig.begin();
    MYFLT *frz1 = inargs(2);
    MYFLT *frz2 = inargs(3);
    bool inc1 = csound->is_asig(frz1);
    bool inc2 = csound->is_asig(frz2);

    for (auto &s : outsig) {
      if(*frz1 > 0)
	in[pp + n + pars] = *inp;
      if(*frz2 > 0)
       ir[pp + n] = *irp;

      s = out[n+pars];

      if (++n == pars) {
        cmplx *ins, *irs, *ous = to_cmplx(out.data());
	uint32_t po = pp;
        std::copy(in.begin() + pp, in.begin() + pp + ffts, insp.begin() + pp);
	std::copy(ir.begin() + pp, ir.begin() + pp + ffts, irsp.begin() + pp);
        std::fill(out.begin(), out.end(), 0.);
        // FFT
        csound->rfft(fwd, insp.data() + pp);
	csound->rfft(fwd, irsp.data() + pp);
        pp += ffts;
	if (pp == fils) pp = 0;
        // spectral delay line
        for (uint32_t k = 0, kp = pp; k < nparts; k++, kp += ffts) {
	 if (kp == fils) kp = 0;
         ins = to_cmplx(insp.data() + kp);
         irs = to_cmplx(irsp.data() + (nparts - k - 1) * ffts);
          // spectral product
          for (uint32_t i = 1; i < pars; i++)
            ous[i] += ins[i] * irs[i];
          ous[0] += real_prod(ins[0], irs[0]);
	 }
        // IFFT
        csound->rfft(inv, out.data());
	std::copy(in.begin() + po + pars, in.begin() + po + ffts, in.begin() + pp);
        n = 0;
      }
      frz1 += inc1;
      frz2 += inc2;
      irp++;
      inp++;
    }
    return OK;
  }

  int dconv() {
    csnd::AudioSig insig(this, inargs(0));
    csnd::AudioSig irsig(this, inargs(1));
    csnd::AudioSig outsig(this, outargs(0));
    auto irp = irsig.begin();
    auto inp = insig.begin();
    MYFLT *frz1 = inargs(2);
    MYFLT *frz2 = inargs(3);
    bool inc1 = csound->is_asig(frz1);
    bool inc2 = csound->is_asig(frz2);
    for (auto &s : outsig) {
      if(*frz1 > 0) in[pp] = *inp;
      if(*frz2 > 0) ir[pp] = *irp;
      pp = pp != fils - 1 ? pp + 1 : 0;
      s = 0.;
      for (uint32_t k = 0, kp = pp; k < fils; k++, kp++) {
        if (kp == fils)
          kp = 0;
        s += in[kp] * ir[fils - k - 1];
      }
      frz1 += inc1;
      frz2 += inc2;
      inp++;
      irp++;
    }
    return OK;
  }

  int aperf() {
    if (pars > 1)
      return pconv();
    else
      return dconv();
  }
};

class PrintThread : public csnd::Thread {
  std::atomic_bool splock;
  std::atomic_bool on;
  std::string message;

  void lock() {
    bool tmp = false;
    while(!splock.compare_exchange_weak(tmp,true))
      tmp = false;
  }

  void unlock() {
    splock = false;
  }

  uintptr_t run() {
    std::string old;
    while(on) {
      lock();
      if(old.compare(message)) {
       csound->message(message.c_str());
       old = message;
      }
      unlock();
    }
    return 0;
  }

public:
  PrintThread(csnd::Csound *csound)
    : Thread(csound), splock(false), on(true), message("") {};

  ~PrintThread(){
    on = false;
    join();
  }

  void set_message(const char *m) {
    lock();
    message = m;
    unlock();
  }

};

/*
struct TPrint : csnd::Plugin<0, 1> {
  static constexpr char const *otypes = "";
  static constexpr char const *itypes = "S";
  PrintThread t;

  int init() {
    csound->plugin_deinit(this);
    csnd::constr(&t, csound);
    return OK;
  }

  int deinit() {
    csnd::destr(&t);
    return OK;
  }

  int kperf() {
    t.set_message(inargs.str_data(0).data);
    return OK;
  }
};
*/

#include <modload.h>
void csnd::on_load(Csound *csound) {
  csnd::plugin<PVTrace>(csound, "pvstrace", csnd::thread::ik);
  csnd::plugin<TVConv>(csound, "tvconv", "a", "aakkii", csnd::thread::ia);
  csnd::plugin<TVConv>(csound, "tvconv", "a", "aaakii", csnd::thread::ia);
  csnd::plugin<TVConv>(csound, "tvconv", "a", "aakaii", csnd::thread::ia);
  csnd::plugin<TVConv>(csound, "tvconv", "a", "aaaaii", csnd::thread::ia);
}
<commit_msg>fix travis build<commit_after>/*
  pvsops.c: pvs and other spectral-based opcodes

  Copyright (C) 2017 Victor Lazzarini
  This file is part of Csound.

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

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

  You should have received a copy of the GNU Lesser General Public
  License along with Csound; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  02111-1307 USA
*/
#include <algorithm>
#include <plugin.h>

struct PVTrace : csnd::FPlugin<1, 2> {
  csnd::AuxMem<float> amps;
  static constexpr char const *otypes = "f";
  static constexpr char const *itypes = "fk";

  int init() {
    if (inargs.fsig_data(0).isSliding())
      return csound->init_error(Str("sliding not supported"));

    if (inargs.fsig_data(0).fsig_format() != csnd::fsig_format::pvs &&
        inargs.fsig_data(0).fsig_format() != csnd::fsig_format::polar)
      return csound->init_error(Str("fsig format not supported"));

    amps.allocate(csound, inargs.fsig_data(0).nbins());
    csnd::Fsig &fout = outargs.fsig_data(0);
    fout.init(csound, inargs.fsig_data(0));
    framecount = 0;
    return OK;
  }

  int kperf() {
    csnd::pv_frame &fin = inargs.fsig_data(0);
    csnd::pv_frame &fout = outargs.fsig_data(0);

    if (framecount < fin.count()) {
      int n = fin.len() - (int)inargs[1];
      float thrsh;
      std::transform(fin.begin(), fin.end(), amps.begin(),
                     [](csnd::pv_bin f) { return f.amp(); });
      std::nth_element(amps.begin(), amps.begin() + n, amps.end());
      thrsh = amps[n];
      std::transform(fin.begin(), fin.end(), fout.begin(),
                     [thrsh](csnd::pv_bin f) {
                       return f.amp() >= thrsh ? f : csnd::pv_bin();
                     });
      framecount = fout.count(fin.count());
    }
    return OK;
  }
};

struct TVConv : csnd::Plugin<1, 6> {
  csnd::AuxMem<MYFLT> ir;
  csnd::AuxMem<MYFLT> in;
  csnd::AuxMem<MYFLT> insp;
  csnd::AuxMem<MYFLT> irsp;
  csnd::AuxMem<MYFLT> out;
  csnd::AuxMem<MYFLT> saved;
  uint32_t n;
  uint32_t fils;
  uint32_t pars;
  uint32_t ffts;
  uint32_t nparts;
  uint32_t pp;
  csnd::fftp fwd, inv;
  typedef std::complex<MYFLT> cmplx;

  uint32_t rpow2(uint32_t n) {
    uint32_t v = 2;
    while (v <= n)
      v <<= 1;
    if ((n - (v >> 1)) < (v - n))
      return v >> 1;
    else
      return v;
  }

  cmplx *to_cmplx(MYFLT *f) { return reinterpret_cast<cmplx *>(f); }

  cmplx real_prod(cmplx &a, cmplx &b) {
    return cmplx(a.real() * b.real(), a.imag() * b.imag());
  }

  int init() {
    pars = inargs[4];
    fils = inargs[5];
    if (pars > fils)
      std::swap(pars, fils);
    if (pars > 1) {
      pars = rpow2(pars);
      fils = rpow2(fils);
      ffts = pars * 2;
      fwd = csound->fft_setup(ffts, FFT_FWD);
      inv = csound->fft_setup(ffts, FFT_INV);
      out.allocate(csound, 2 * pars);
      insp.allocate(csound, 2 * fils);
      irsp.allocate(csound, 2 * fils);
      saved.allocate(csound, pars);
      ir.allocate(csound, 2 * fils);
      in.allocate(csound, 2 * fils);
      nparts = fils / pars;
      fils *= 2;
    } else {
      ir.allocate(csound, fils);
      in.allocate(csound, fils);
    }
    n = 0;
    pp = 0;
    return OK;
  }

  int pconv() {
    csnd::AudioSig insig(this, inargs(0));
    csnd::AudioSig irsig(this, inargs(1));
    csnd::AudioSig outsig(this, outargs(0));
    auto irp = irsig.begin();
    auto inp = insig.begin();
    MYFLT *frz1 = inargs(2);
    MYFLT *frz2 = inargs(3);
    bool inc1 = csound->is_asig(frz1);
    bool inc2 = csound->is_asig(frz2);

    for (auto &s : outsig) {
      if(*frz1 > 0) in[pp + n] = *inp;
      if(*frz2 > 0) ir[pp + n] = *irp;

      s = out[n] + saved[n];
      saved[n] = out[n + pars];
      if (++n == pars) {
        cmplx *ins, *irs, *ous = to_cmplx(out.data());
        std::copy(in.begin() + pp, in.begin() + pp + ffts, insp.begin() + pp);
        std::copy(ir.begin() + pp, ir.begin() + pp + ffts, irsp.begin() + pp);
        std::fill(out.begin(), out.end(), 0.);
        // FFT
        csound->rfft(fwd, insp.data() + pp);
        csound->rfft(fwd, irsp.data() + pp);
        pp += ffts;
        if (pp == fils)
          pp = 0;
        // spectral delay line
        for (uint32_t k = 0, kp = pp; k < nparts; k++, kp += ffts) {
          if (kp == fils)
            kp = 0;
          ins = to_cmplx(insp.data() + kp);
          irs = to_cmplx(irsp.data() + (nparts - k - 1) * ffts);
          // spectral product
          for (uint32_t i = 1; i < pars; i++)
            ous[i] += ins[i] * irs[i];
          ous[0] += real_prod(ins[0], irs[0]);
        }
        // IFFT
        csound->rfft(inv, out.data());
        n = 0;
      }
      frz1 += inc1;
      frz2 += inc2;
      irp++;
      inp++;
    }
    return OK;
  }

  int pconv_ols() {
    csnd::AudioSig insig(this, inargs(0));
    csnd::AudioSig irsig(this, inargs(1));
    csnd::AudioSig outsig(this, outargs(0));
    auto irp = irsig.begin();
    auto inp = insig.begin();
    MYFLT *frz1 = inargs(2);
    MYFLT *frz2 = inargs(3);
    bool inc1 = csound->is_asig(frz1);
    bool inc2 = csound->is_asig(frz2);

    for (auto &s : outsig) {
      if(*frz1 > 0)
	in[pp + n + pars] = *inp;
      if(*frz2 > 0)
       ir[pp + n] = *irp;

      s = out[n+pars];

      if (++n == pars) {
        cmplx *ins, *irs, *ous = to_cmplx(out.data());
	uint32_t po = pp;
        std::copy(in.begin() + pp, in.begin() + pp + ffts, insp.begin() + pp);
	std::copy(ir.begin() + pp, ir.begin() + pp + ffts, irsp.begin() + pp);
        std::fill(out.begin(), out.end(), 0.);
        // FFT
        csound->rfft(fwd, insp.data() + pp);
	csound->rfft(fwd, irsp.data() + pp);
        pp += ffts;
	if (pp == fils) pp = 0;
        // spectral delay line
        for (uint32_t k = 0, kp = pp; k < nparts; k++, kp += ffts) {
	 if (kp == fils) kp = 0;
         ins = to_cmplx(insp.data() + kp);
         irs = to_cmplx(irsp.data() + (nparts - k - 1) * ffts);
          // spectral product
          for (uint32_t i = 1; i < pars; i++)
            ous[i] += ins[i] * irs[i];
          ous[0] += real_prod(ins[0], irs[0]);
	 }
        // IFFT
        csound->rfft(inv, out.data());
	std::copy(in.begin() + po + pars, in.begin() + po + ffts, in.begin() + pp);
        n = 0;
      }
      frz1 += inc1;
      frz2 += inc2;
      irp++;
      inp++;
    }
    return OK;
  }

  int dconv() {
    csnd::AudioSig insig(this, inargs(0));
    csnd::AudioSig irsig(this, inargs(1));
    csnd::AudioSig outsig(this, outargs(0));
    auto irp = irsig.begin();
    auto inp = insig.begin();
    MYFLT *frz1 = inargs(2);
    MYFLT *frz2 = inargs(3);
    bool inc1 = csound->is_asig(frz1);
    bool inc2 = csound->is_asig(frz2);
    for (auto &s : outsig) {
      if(*frz1 > 0) in[pp] = *inp;
      if(*frz2 > 0) ir[pp] = *irp;
      pp = pp != fils - 1 ? pp + 1 : 0;
      s = 0.;
      for (uint32_t k = 0, kp = pp; k < fils; k++, kp++) {
        if (kp == fils)
          kp = 0;
        s += in[kp] * ir[fils - k - 1];
      }
      frz1 += inc1;
      frz2 += inc2;
      inp++;
      irp++;
    }
    return OK;
  }

  int aperf() {
    if (pars > 1)
      return pconv();
    else
      return dconv();
  }
};

/*
class PrintThread : public csnd::Thread {
  std::atomic_bool splock;
  std::atomic_bool on;
  std::string message;

  void lock() {
    bool tmp = false;
    while(!splock.compare_exchange_weak(tmp,true))
      tmp = false;
  }

  void unlock() {
    splock = false;
  }

  uintptr_t run() {
    std::string old;
    while(on) {
      lock();
      if(old.compare(message)) {
       csound->message(message.c_str());
       old = message;
      }
      unlock();
    }
    return 0;
  }

public:
  PrintThread(csnd::Csound *csound)
    : Thread(csound), splock(false), on(true), message("") {};

  ~PrintThread(){
    on = false;
    join();
  }

  void set_message(const char *m) {
    lock();
    message = m;
    unlock();
  }

};

struct TPrint : csnd::Plugin<0, 1> {
  static constexpr char const *otypes = "";
  static constexpr char const *itypes = "S";
  PrintThread t;

  int init() {
    csound->plugin_deinit(this);
    csnd::constr(&t, csound);
    return OK;
  }

  int deinit() {
    csnd::destr(&t);
    return OK;
  }

  int kperf() {
    t.set_message(inargs.str_data(0).data);
    return OK;
  }
};
*/

#include <modload.h>
void csnd::on_load(Csound *csound) {
  csnd::plugin<PVTrace>(csound, "pvstrace", csnd::thread::ik);
  csnd::plugin<TVConv>(csound, "tvconv", "a", "aakkii", csnd::thread::ia);
  csnd::plugin<TVConv>(csound, "tvconv", "a", "aaakii", csnd::thread::ia);
  csnd::plugin<TVConv>(csound, "tvconv", "a", "aakaii", csnd::thread::ia);
  csnd::plugin<TVConv>(csound, "tvconv", "a", "aaaaii", csnd::thread::ia);
}
<|endoftext|>


<commit_before>/*****************************************************************************
Copyright (c) 2001 - 2009, The Board of Trustees of the University of Illinois.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

* Redistributions of source code must retain the above
  copyright notice, this list of conditions and the
  following disclaimer.

* Redistributions in binary form must reproduce the
  above copyright notice, this list of conditions
  and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* Neither the name of the University of Illinois
  nor the names of its contributors may be used to
  endorse or promote products derived from this
  software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/

/*****************************************************************************
written by
   Yunhong Gu, last updated 03/05/2009
*****************************************************************************/

#include "core.h"
#include "ccc.h"
#include <cmath>
#include <string.h>

CCC::CCC():
m_iSYNInterval(CUDT::m_iSYNInterval),
m_dPktSndPeriod(1.0),
m_dCWndSize(16.0),
m_pcParam(NULL),
m_iPSize(0),
m_iACKPeriod(0),
m_iACKInterval(0),
m_bUserDefinedRTO(false),
m_iRTO(-1)
{
}

CCC::~CCC()
{
   delete [] m_pcParam;
}

void CCC::setACKTimer(const int& msINT)
{
   m_iACKPeriod = msINT;

   if (m_iACKPeriod > m_iSYNInterval)
      m_iACKPeriod = m_iSYNInterval;
}

void CCC::setACKInterval(const int& pktINT)
{
   m_iACKInterval = pktINT;
}

void CCC::setRTO(const int& usRTO)
{
   m_bUserDefinedRTO = true;
   m_iRTO = usRTO;
}

void CCC::sendCustomMsg(CPacket& pkt) const
{
   CUDT* u = CUDT::getUDTHandle(m_UDT);

   if (NULL != u)
      u->m_pSndQueue->sendto(u->m_pPeerAddr, pkt);
}

const CPerfMon* CCC::getPerfInfo()
{
   CUDT* u = CUDT::getUDTHandle(m_UDT);
   if (NULL != u)
      u->sample(&m_PerfInfo, false);

   return &m_PerfInfo;
}

void CCC::setMSS(const int& mss)
{
   m_iMSS = mss;
}

void CCC::setBandwidth(const int& bw)
{
   m_iBandwidth = bw;
}

void CCC::setSndCurrSeqNo(const int32_t& seqno)
{
   m_iSndCurrSeqNo = seqno;
}

void CCC::setRcvRate(const int& rcvrate)
{
   m_iRcvRate = rcvrate;
}

void CCC::setMaxCWndSize(const int& cwnd)
{
   m_dMaxCWndSize = cwnd;
}

void CCC::setRTT(const int& rtt)
{
   m_iRTT = rtt;
}

void CCC::setUserParam(const char* param, const int& size)
{
   delete [] m_pcParam;
   m_pcParam = new char[size];
   memcpy(m_pcParam, param, size);
}

//
void CUDTCC::init()
{
   m_iRCInterval = m_iSYNInterval;
   m_LastRCTime = CTimer::getTime();
   setACKTimer(m_iRCInterval);

   m_bSlowStart = true;
   m_iLastAck = m_iSndCurrSeqNo;
   m_bLoss = false;
   m_iLastDecSeq = CSeqNo::decseq(m_iLastAck);
   m_dLastDecPeriod = 1;
   m_iAvgNAKNum = 0;
   m_iNAKCount = 0;
   m_iDecRandom = 1;

   m_dCWndSize = 16;
   m_dPktSndPeriod = 1;
}

void CUDTCC::onACK(const int32_t& ack)
{
   uint64_t currtime = CTimer::getTime();
   if (currtime - m_LastRCTime < (uint64_t)m_iRCInterval)
      return;

   m_LastRCTime = currtime;

   if (m_bSlowStart)
   {
      m_dCWndSize += CSeqNo::seqlen(m_iLastAck, ack);
      m_iLastAck = ack;

      if (m_dCWndSize > m_dMaxCWndSize)
      {
         m_bSlowStart = false;
         if (m_iRcvRate > 0)
            m_dPktSndPeriod = 1000000.0 / m_iRcvRate;
         else
            m_dPktSndPeriod = m_dCWndSize / (m_iRTT + m_iRCInterval);
      }
   }
   else
      m_dCWndSize = m_iRcvRate / 1000000.0 * (m_iRTT + m_iRCInterval) + 16;

   // During Slow Start, no rate increase
   if (m_bSlowStart)
      return;

   if (m_bLoss)
   {
      m_bLoss = false;
      return;
   }

   int64_t B = (int64_t)(m_iBandwidth - 1000000.0 / m_dPktSndPeriod);
   if ((m_dPktSndPeriod > m_dLastDecPeriod) && ((m_iBandwidth / 9) < B))
      B = m_iBandwidth / 9;

   double inc;

   if (B <= 0)
      inc = 1.0 / m_iMSS;
   else
   {
      // inc = max(10 ^ ceil(log10( B * MSS * 8 ) * Beta / MSS, 1/MSS)
      // Beta = 1.5 * 10^(-6)

      inc = pow(10.0, ceil(log10(B * m_iMSS * 8.0))) * 0.0000015 / m_iMSS;

      if (inc < 1.0/m_iMSS)
         inc = 1.0/m_iMSS;
   }

   m_dPktSndPeriod = (m_dPktSndPeriod * m_iRCInterval) / (m_dPktSndPeriod * inc + m_iRCInterval);

   //set maximum transfer rate
   if ((NULL != m_pcParam) && (m_iPSize == 8))
   {
      int64_t maxSR = *(int64_t*)m_pcParam;
      if (maxSR <= 0)
         return;

      double minSP = 1000000.0 / (double(maxSR) / m_iMSS);
      if (m_dPktSndPeriod < minSP)
         m_dPktSndPeriod = minSP;
   }
}

void CUDTCC::onLoss(const int32_t* losslist, const int&)
{
   //Slow Start stopped, if it hasn't yet
   if (m_bSlowStart)
   {
      m_bSlowStart = false;
      if (m_iRcvRate > 0)
         m_dPktSndPeriod = 1000000.0 / m_iRcvRate;
      else
         m_dPktSndPeriod = m_dCWndSize / (m_iRTT + m_iRCInterval);
   }

   m_bLoss = true;

   if (CSeqNo::seqcmp(losslist[0] & 0x7FFFFFFF, m_iLastDecSeq) > 0)
   {
      m_dLastDecPeriod = m_dPktSndPeriod;
      m_dPktSndPeriod = ceil(m_dPktSndPeriod * 1.125);

      m_iAvgNAKNum = (int)ceil(m_iAvgNAKNum * 0.875 + m_iNAKCount * 0.125);
      m_iNAKCount = 1;
      m_iDecCount = 1;

      m_iLastDecSeq = m_iSndCurrSeqNo;

      // remove global synchronization using randomization
      srand(m_iLastDecSeq);
      m_iDecRandom = (int)ceil(m_iAvgNAKNum * (double(rand()) / RAND_MAX));
      if (m_iDecRandom < 1)
         m_iDecRandom = 1;
   }
   else if ((m_iDecCount ++ < 5) && (0 == (++ m_iNAKCount % m_iDecRandom)))
   {
      // 0.875^5 = 0.51, rate should not be decreased by more than half within a congestion period
      m_dPktSndPeriod = ceil(m_dPktSndPeriod * 1.125);
      m_iLastDecSeq = m_iSndCurrSeqNo;
   }
}

void CUDTCC::onTimeout()
{
   if (m_bSlowStart)
   {
      m_bSlowStart = false;
      if (m_iRcvRate > 0)
         m_dPktSndPeriod = 1000000.0 / m_iRcvRate;
      else
         m_dPktSndPeriod = m_dCWndSize / (m_iRTT + m_iRCInterval);
   }
}
<commit_msg>*** empty log message ***<commit_after>/*****************************************************************************
Copyright (c) 2001 - 2009, The Board of Trustees of the University of Illinois.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

* Redistributions of source code must retain the above
  copyright notice, this list of conditions and the
  following disclaimer.

* Redistributions in binary form must reproduce the
  above copyright notice, this list of conditions
  and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* Neither the name of the University of Illinois
  nor the names of its contributors may be used to
  endorse or promote products derived from this
  software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/

/*****************************************************************************
written by
   Yunhong Gu, last updated 03/05/2009
*****************************************************************************/

#include "core.h"
#include "ccc.h"
#include <cmath>
#include <string.h>

CCC::CCC():
m_iSYNInterval(CUDT::m_iSYNInterval),
m_dPktSndPeriod(1.0),
m_dCWndSize(16.0),
m_pcParam(NULL),
m_iPSize(0),
m_iACKPeriod(0),
m_iACKInterval(0),
m_bUserDefinedRTO(false),
m_iRTO(-1)
{
}

CCC::~CCC()
{
   delete [] m_pcParam;
}

void CCC::setACKTimer(const int& msINT)
{
   m_iACKPeriod = msINT;

   if (m_iACKPeriod > m_iSYNInterval)
      m_iACKPeriod = m_iSYNInterval;
}

void CCC::setACKInterval(const int& pktINT)
{
   m_iACKInterval = pktINT;
}

void CCC::setRTO(const int& usRTO)
{
   m_bUserDefinedRTO = true;
   m_iRTO = usRTO;
}

void CCC::sendCustomMsg(CPacket& pkt) const
{
   CUDT* u = CUDT::getUDTHandle(m_UDT);

   if (NULL != u)
      u->m_pSndQueue->sendto(u->m_pPeerAddr, pkt);
}

const CPerfMon* CCC::getPerfInfo()
{
   CUDT* u = CUDT::getUDTHandle(m_UDT);
   if (NULL != u)
      u->sample(&m_PerfInfo, false);

   return &m_PerfInfo;
}

void CCC::setMSS(const int& mss)
{
   m_iMSS = mss;
}

void CCC::setBandwidth(const int& bw)
{
   m_iBandwidth = bw;
}

void CCC::setSndCurrSeqNo(const int32_t& seqno)
{
   m_iSndCurrSeqNo = seqno;
}

void CCC::setRcvRate(const int& rcvrate)
{
   m_iRcvRate = rcvrate;
}

void CCC::setMaxCWndSize(const int& cwnd)
{
   m_dMaxCWndSize = cwnd;
}

void CCC::setRTT(const int& rtt)
{
   m_iRTT = rtt;
}

void CCC::setUserParam(const char* param, const int& size)
{
   delete [] m_pcParam;
   m_pcParam = new char[size];
   memcpy(m_pcParam, param, size);
   m_iPSize = size;
}

//
void CUDTCC::init()
{
   m_iRCInterval = m_iSYNInterval;
   m_LastRCTime = CTimer::getTime();
   setACKTimer(m_iRCInterval);

   m_bSlowStart = true;
   m_iLastAck = m_iSndCurrSeqNo;
   m_bLoss = false;
   m_iLastDecSeq = CSeqNo::decseq(m_iLastAck);
   m_dLastDecPeriod = 1;
   m_iAvgNAKNum = 0;
   m_iNAKCount = 0;
   m_iDecRandom = 1;

   m_dCWndSize = 16;
   m_dPktSndPeriod = 1;
}

void CUDTCC::onACK(const int32_t& ack)
{
   uint64_t currtime = CTimer::getTime();
   if (currtime - m_LastRCTime < (uint64_t)m_iRCInterval)
      return;

   m_LastRCTime = currtime;

   if (m_bSlowStart)
   {
      m_dCWndSize += CSeqNo::seqlen(m_iLastAck, ack);
      m_iLastAck = ack;

      if (m_dCWndSize > m_dMaxCWndSize)
      {
         m_bSlowStart = false;
         if (m_iRcvRate > 0)
            m_dPktSndPeriod = 1000000.0 / m_iRcvRate;
         else
            m_dPktSndPeriod = m_dCWndSize / (m_iRTT + m_iRCInterval);
      }
   }
   else
      m_dCWndSize = m_iRcvRate / 1000000.0 * (m_iRTT + m_iRCInterval) + 16;

   // During Slow Start, no rate increase
   if (m_bSlowStart)
      return;

   if (m_bLoss)
   {
      m_bLoss = false;
      return;
   }

   int64_t B = (int64_t)(m_iBandwidth - 1000000.0 / m_dPktSndPeriod);
   if ((m_dPktSndPeriod > m_dLastDecPeriod) && ((m_iBandwidth / 9) < B))
      B = m_iBandwidth / 9;

   double inc;

   if (B <= 0)
      inc = 1.0 / m_iMSS;
   else
   {
      // inc = max(10 ^ ceil(log10( B * MSS * 8 ) * Beta / MSS, 1/MSS)
      // Beta = 1.5 * 10^(-6)

      inc = pow(10.0, ceil(log10(B * m_iMSS * 8.0))) * 0.0000015 / m_iMSS;

      if (inc < 1.0/m_iMSS)
         inc = 1.0/m_iMSS;
   }

   m_dPktSndPeriod = (m_dPktSndPeriod * m_iRCInterval) / (m_dPktSndPeriod * inc + m_iRCInterval);

   //set maximum transfer rate
   if ((NULL != m_pcParam) && (m_iPSize == 8))
   {
      int64_t maxSR = *(int64_t*)m_pcParam;
      if (maxSR <= 0)
         return;

      double minSP = 1000000.0 / (double(maxSR) / m_iMSS);
      if (m_dPktSndPeriod < minSP)
         m_dPktSndPeriod = minSP;
   }
}

void CUDTCC::onLoss(const int32_t* losslist, const int&)
{
   //Slow Start stopped, if it hasn't yet
   if (m_bSlowStart)
   {
      m_bSlowStart = false;
      if (m_iRcvRate > 0)
         m_dPktSndPeriod = 1000000.0 / m_iRcvRate;
      else
         m_dPktSndPeriod = m_dCWndSize / (m_iRTT + m_iRCInterval);
   }

   m_bLoss = true;

   if (CSeqNo::seqcmp(losslist[0] & 0x7FFFFFFF, m_iLastDecSeq) > 0)
   {
      m_dLastDecPeriod = m_dPktSndPeriod;
      m_dPktSndPeriod = ceil(m_dPktSndPeriod * 1.125);

      m_iAvgNAKNum = (int)ceil(m_iAvgNAKNum * 0.875 + m_iNAKCount * 0.125);
      m_iNAKCount = 1;
      m_iDecCount = 1;

      m_iLastDecSeq = m_iSndCurrSeqNo;

      // remove global synchronization using randomization
      srand(m_iLastDecSeq);
      m_iDecRandom = (int)ceil(m_iAvgNAKNum * (double(rand()) / RAND_MAX));
      if (m_iDecRandom < 1)
         m_iDecRandom = 1;
   }
   else if ((m_iDecCount ++ < 5) && (0 == (++ m_iNAKCount % m_iDecRandom)))
   {
      // 0.875^5 = 0.51, rate should not be decreased by more than half within a congestion period
      m_dPktSndPeriod = ceil(m_dPktSndPeriod * 1.125);
      m_iLastDecSeq = m_iSndCurrSeqNo;
   }
}

void CUDTCC::onTimeout()
{
   if (m_bSlowStart)
   {
      m_bSlowStart = false;
      if (m_iRcvRate > 0)
         m_dPktSndPeriod = 1000000.0 / m_iRcvRate;
      else
         m_dPktSndPeriod = m_dCWndSize / (m_iRTT + m_iRCInterval);
   }
}
<|endoftext|>


<commit_before>// @(#)root/gui:$Name:  $:$Id: TGPicture.cxx,v 1.10 2004/07/09 12:47:02 brun Exp $
// Author: Fons Rademakers   01/01/98

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/
/**************************************************************************

    This source is based on Xclass95, a Win95-looking GUI toolkit.
    Copyright (C) 1996, 1997 David Barth, Ricky Ralston, Hector Peraza.

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

**************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TGPicture & TGPicturePool                                            //
//                                                                      //
// The TGPicture class implements pictures and icons used in the        //
// different GUI elements and widgets. The TGPicturePool class          //
// implements a TGPicture cache. TGPictures are created, managed and    //
// destroyed by the TGPicturePool.                                      //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TGPicture.h"
#include "TGResourcePool.h"
#include "THashTable.h"
#include "TSystem.h"
#include "TGWindow.h"
#include "TVirtualX.h"

TGGC *TGSelectedPicture::fgSelectedGC = 0;

ClassImp(TGPicture)
ClassImp(TGSelectedPicture)
ClassImp(TGPicturePool)

//______________________________________________________________________________
const TGPicture *TGPicturePool::GetPicture(const char *name)
{
   // Get a picture from the picture pool. Picture must be freed using
   // TGPicturePool::FreePicture(). If picture is not found 0 is returned.

   if (!fPicList)
      fPicList = new THashTable(50);

   TString pname = name;

   if (pname.EndsWith(".xpm")) {
      const char *pxname = gSystem->ExpandPathName(gSystem->UnixPathName(pname));
      pname = pxname;
      delete [] pxname;
   }
   TGPicture *pic;

   pic = (TGPicture *)fPicList->FindObject(pname);
   if (pic && !pic->IsScaled()) {
      if (pic->fPic == kNone)
         return 0;
      pic->AddReference();
      return pic;
   }

   pic = new TGPicture(pname);
   pic->fAttributes.fColormap  = fClient->GetDefaultColormap();
   pic->fAttributes.fCloseness = 40000; // Allow for "similar" colors
   pic->fAttributes.fMask      = kPASize | kPAColormap | kPACloseness;

   char *picnam = gSystem->Which(fPath, pname, kReadPermission);
   if (!picnam) {
      fPicList->Add(pic);
      return 0;
   }

   if (gVirtualX->CreatePictureFromFile(fClient->GetDefaultRoot()->GetId(), picnam,
                                        pic->fPic, pic->fMask,
                                        pic->fAttributes)) {
      fPicList->Add(pic);
   } else {
      delete pic;
      pic = new TGPicture(name);
      fPicList->Add(pic);
      pic = 0;
   }

   delete [] picnam;

   return pic;
}

//______________________________________________________________________________
const TGPicture *TGPicturePool::GetPicture(const char *name,
                                           UInt_t new_width, UInt_t new_height)
{
   // Get picture with specified size from pool (picture will be scaled if
   // necessary). Picture must be freed using TGPicturePool::FreePicture(). If
   // picture is not found 0 is returned.

   if (!fPicList)
      fPicList = new THashTable(50);

   TString pname = name;

   if (pname.EndsWith(".xpm")) {
      const char *pxname = gSystem->ExpandPathName(gSystem->UnixPathName(pname));
      pname = pxname;
      delete [] pxname;
   }

   TGPicture *pic;

   const char *hname = TGPicture::HashName(pname, new_width, new_height);
   pic = (TGPicture *)fPicList->FindObject(hname);
   if (pic && pic->GetWidth() == new_width && pic->GetHeight() == new_height) {
      if (pic->fPic == kNone)
         return 0;
      pic->AddReference();
      return pic;
   }

   pic = new TGPicture(hname, kTRUE);
   pic->fAttributes.fColormap  = fClient->GetDefaultColormap();
   pic->fAttributes.fCloseness = 40000; // Allow for "similar" colors
   pic->fAttributes.fMask      = kPASize | kPAColormap | kPACloseness;

   char *picnam = gSystem->Which(fPath, pname, kReadPermission);
   if (!picnam) {
      pic->fAttributes.fWidth  = new_width;
      pic->fAttributes.fHeight = new_height;
      fPicList->Add(pic);
      return 0;
   }

   Bool_t retc = kFALSE;
   if (!gVirtualX->InheritsFrom("TGX11")) {
      // case of win32gdk and qt drivers
      retc = gVirtualX->CreatePictureFromFile(fClient->GetDefaultRoot()->GetId(),
                                              picnam, pic->fPic, pic->fMask,
                                              pic->fAttributes);
      delete [] picnam;
   } else {
      // case supported by X11 driver
      char **data;
      if (!gVirtualX->ReadPictureDataFromFile(picnam, &data)) {
         delete pic;
         delete [] picnam;
         return 0;
      }
      delete [] picnam;

      Int_t    colors, chars, headersize, totalheight;
      UInt_t   width, height;
      Double_t xscale, yscale;

      sscanf(data[0], "%u %u %d %d", &width, &height, &colors, &chars);
      headersize = colors + 1;
      yscale = (Double_t) new_height / (Double_t) height;
      xscale = (Double_t) new_width / (Double_t) width;
      totalheight = (colors + new_height + 1);

      if ((width != new_width) || (height != new_height)) {
         char **smalldata;
         Int_t    i, x1, y1, pixels;
         Double_t x, y;

         smalldata = new char* [totalheight + 1];

         smalldata[0] = new char[30];
         for (i = 1; i < headersize; i++)
            smalldata[i] = new char [strlen(data[i]) + 1];

         for (i = headersize; i < totalheight + 1; i++)
            smalldata[i] = new char[(new_width * chars) + 1];

         sprintf(smalldata[0], "%u %u %d %d", new_width, new_height, colors, chars);

         for (i = 1; i < headersize; i++) strcpy(smalldata[i], data[i]);

         y = headersize;
         for (y1 = headersize; y1 < (Int_t)new_height + headersize; y1++) {
            x = 0;
            for (x1 = 0; x1 < (Int_t)new_width; x1++) {
               for (pixels = 0; pixels < chars; pixels++)
                  smalldata[y1][x1+pixels] = data[(Int_t)y][(Int_t)x + pixels];
               x += 1.0 / xscale;
            }
            smalldata[y1][x1] = '\0';
            y += 1.0 / yscale;
         }

         retc = gVirtualX->CreatePictureFromData(fClient->GetDefaultRoot()->GetId(), smalldata,
                                                 pic->fPic, pic->fMask,
                                                 pic->fAttributes);

         for (i = 0; i < totalheight + 1; i++)
            delete [] smalldata[i];
         delete [] smalldata;

      } else {
         retc = gVirtualX->CreatePictureFromData(fClient->GetDefaultRoot()->GetId(), data,
                                                 pic->fPic, pic->fMask,
                                                 pic->fAttributes);
      }

      gVirtualX->DeletePictureData(data);
   }

   if (!retc) {
      delete pic;
      return 0;
   }

   fPicList->Add(pic);
   return pic;
}

//______________________________________________________________________________
void TGPicturePool::FreePicture(const TGPicture *fpic)
{
   // Remove picture from cache if nobody is using it anymore.

   if (!fPicList) return;

   TGPicture *pic = (TGPicture *)fPicList->FindObject(fpic);
   if (pic) {
      if (pic->RemoveReference() == 0) {
         fPicList->Remove(pic);
         delete pic;
      }
   }
}

//______________________________________________________________________________
TGPicturePool::~TGPicturePool()
{
   // Delete picture cache.

   if (fPicList) {
      fPicList->Delete();
      delete fPicList;
   }
}

//______________________________________________________________________________
void TGPicturePool::Print(Option_t *) const
{
   // List all pictures in the pool.

   if (fPicList)
      fPicList->Print();
   else
      Info("Print", "no pictures in picture pool");
}

//______________________________________________________________________________
void TGPicture::Draw(Handle_t id, GContext_t gc, Int_t x, Int_t y) const
{
   // Draw a picture.

   GCValues_t gcv;

   gcv.fMask = kGCClipMask | kGCClipXOrigin | kGCClipYOrigin;
   gcv.fClipMask = fMask;
   gcv.fClipXOrigin = x;
   gcv.fClipYOrigin = y;
   gVirtualX->ChangeGC(gc, &gcv);
   gVirtualX->CopyArea(fPic, id, gc, 0, 0, fAttributes.fWidth, fAttributes.fHeight,
                  x, y);
   gcv.fMask = kGCClipMask;
   gcv.fClipMask = kNone;
   gVirtualX->ChangeGC(gc, &gcv);
}

//______________________________________________________________________________
TGPicture::~TGPicture()
{
   // Delete picture object.

   if (fPic != kNone)
      gVirtualX->DeletePixmap(fPic);
   if (fMask != kNone)
      gVirtualX->DeletePixmap(fMask);
   if (fAttributes.fPixels)
      delete [] fAttributes.fPixels;
}

//______________________________________________________________________________
const char *TGPicture::HashName(const char *name, Int_t width, Int_t height)
{
   // Static function returning a unique name used to look up a picture.
   // The unique name has the form "name__widthxheight".

   static char hashName[256];

   sprintf(hashName, "%s__%dx%d", name, width, height);

   return hashName;
}

//______________________________________________________________________________
void TGPicture::Print(Option_t *) const
{
   // Print picture info.

   Printf("TGPicture: %s,%sref cnt = %u", GetName(),
          fScaled ? " scaled, " : " ", References());
}

//______________________________________________________________________________
TGSelectedPicture::TGSelectedPicture(const TGClient *client, const TGPicture *p) :
   TGPicture("")
{
   // Create a "selected" looking picture based on the original TGPicture.

   GCValues_t gcv;
   UInt_t     w, h;

   fClient = client;
   Window_t root  = fClient->GetDefaultRoot()->GetId();

   w = p->GetWidth();
   h = p->GetHeight();

   fPic  = gVirtualX->CreatePixmap(root, w, h);
   fMask = p->GetMask();

   fAttributes.fWidth  = w;
   fAttributes.fHeight = h;

   gVirtualX->CopyArea(p->GetPicture(), fPic, GetSelectedGC()(), 0, 0, w, h, 0, 0);

   gcv.fMask = kGCClipMask | kGCClipXOrigin | kGCClipYOrigin;
   gcv.fClipMask = p->GetMask();
   gcv.fClipXOrigin = 0;
   gcv.fClipYOrigin = 0;
   GetSelectedGC().SetAttributes(&gcv);

   gVirtualX->FillRectangle(fPic, GetSelectedGC()(), 0, 0, w, h);

   GetSelectedGC().SetClipMask(kNone);
}

//______________________________________________________________________________
TGSelectedPicture::~TGSelectedPicture()
{
   // Delete selected picture.

   // fMask was borrowed so should not be deleted by ~TGPicture.
   fMask = kNone;
}

//______________________________________________________________________________
TGGC &TGSelectedPicture::GetSelectedGC()
{
   if (!fgSelectedGC) {
      fgSelectedGC = new TGGC(*gClient->GetResourcePool()->GetFrameGC());
      fgSelectedGC->SetForeground(gClient->GetResourcePool()->GetSelectedBgndColor());
      fgSelectedGC->SetBackground(gClient->GetResourcePool()->GetBlackColor());
      fgSelectedGC->SetFillStyle(kFillStippled);
      fgSelectedGC->SetStipple(gClient->GetResourcePool()->GetCheckeredBitmap());
   }
   return *fgSelectedGC;
}
<commit_msg>ExpandPathName() returns a char* and not a const char*.<commit_after>// @(#)root/gui:$Name:  $:$Id: TGPicture.cxx,v 1.11 2004/08/21 09:32:52 rdm Exp $
// Author: Fons Rademakers   01/01/98

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/
/**************************************************************************

    This source is based on Xclass95, a Win95-looking GUI toolkit.
    Copyright (C) 1996, 1997 David Barth, Ricky Ralston, Hector Peraza.

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

**************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TGPicture & TGPicturePool                                            //
//                                                                      //
// The TGPicture class implements pictures and icons used in the        //
// different GUI elements and widgets. The TGPicturePool class          //
// implements a TGPicture cache. TGPictures are created, managed and    //
// destroyed by the TGPicturePool.                                      //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TGPicture.h"
#include "TGResourcePool.h"
#include "THashTable.h"
#include "TSystem.h"
#include "TGWindow.h"
#include "TVirtualX.h"

TGGC *TGSelectedPicture::fgSelectedGC = 0;

ClassImp(TGPicture)
ClassImp(TGSelectedPicture)
ClassImp(TGPicturePool)

//______________________________________________________________________________
const TGPicture *TGPicturePool::GetPicture(const char *name)
{
   // Get a picture from the picture pool. Picture must be freed using
   // TGPicturePool::FreePicture(). If picture is not found 0 is returned.

   if (!fPicList)
      fPicList = new THashTable(50);

   TString pname = name;

   if (pname.EndsWith(".xpm")) {
      char *pxname = gSystem->ExpandPathName(gSystem->UnixPathName(pname));
      pname = pxname;
      delete [] pxname;
   }
   TGPicture *pic;

   pic = (TGPicture *)fPicList->FindObject(pname);
   if (pic && !pic->IsScaled()) {
      if (pic->fPic == kNone)
         return 0;
      pic->AddReference();
      return pic;
   }

   pic = new TGPicture(pname);
   pic->fAttributes.fColormap  = fClient->GetDefaultColormap();
   pic->fAttributes.fCloseness = 40000; // Allow for "similar" colors
   pic->fAttributes.fMask      = kPASize | kPAColormap | kPACloseness;

   char *picnam = gSystem->Which(fPath, pname, kReadPermission);
   if (!picnam) {
      fPicList->Add(pic);
      return 0;
   }

   if (gVirtualX->CreatePictureFromFile(fClient->GetDefaultRoot()->GetId(), picnam,
                                        pic->fPic, pic->fMask,
                                        pic->fAttributes)) {
      fPicList->Add(pic);
   } else {
      delete pic;
      pic = new TGPicture(name);
      fPicList->Add(pic);
      pic = 0;
   }

   delete [] picnam;

   return pic;
}

//______________________________________________________________________________
const TGPicture *TGPicturePool::GetPicture(const char *name,
                                           UInt_t new_width, UInt_t new_height)
{
   // Get picture with specified size from pool (picture will be scaled if
   // necessary). Picture must be freed using TGPicturePool::FreePicture(). If
   // picture is not found 0 is returned.

   if (!fPicList)
      fPicList = new THashTable(50);

   TString pname = name;

   if (pname.EndsWith(".xpm")) {
      char *pxname = gSystem->ExpandPathName(gSystem->UnixPathName(pname));
      pname = pxname;
      delete [] pxname;
   }

   TGPicture *pic;

   const char *hname = TGPicture::HashName(pname, new_width, new_height);
   pic = (TGPicture *)fPicList->FindObject(hname);
   if (pic && pic->GetWidth() == new_width && pic->GetHeight() == new_height) {
      if (pic->fPic == kNone)
         return 0;
      pic->AddReference();
      return pic;
   }

   pic = new TGPicture(hname, kTRUE);
   pic->fAttributes.fColormap  = fClient->GetDefaultColormap();
   pic->fAttributes.fCloseness = 40000; // Allow for "similar" colors
   pic->fAttributes.fMask      = kPASize | kPAColormap | kPACloseness;

   char *picnam = gSystem->Which(fPath, pname, kReadPermission);
   if (!picnam) {
      pic->fAttributes.fWidth  = new_width;
      pic->fAttributes.fHeight = new_height;
      fPicList->Add(pic);
      return 0;
   }

   Bool_t retc = kFALSE;
   if (!gVirtualX->InheritsFrom("TGX11")) {
      // case of win32gdk and qt drivers
      retc = gVirtualX->CreatePictureFromFile(fClient->GetDefaultRoot()->GetId(),
                                              picnam, pic->fPic, pic->fMask,
                                              pic->fAttributes);
      delete [] picnam;
   } else {
      // case supported by X11 driver
      char **data;
      if (!gVirtualX->ReadPictureDataFromFile(picnam, &data)) {
         delete pic;
         delete [] picnam;
         return 0;
      }
      delete [] picnam;

      Int_t    colors, chars, headersize, totalheight;
      UInt_t   width, height;
      Double_t xscale, yscale;

      sscanf(data[0], "%u %u %d %d", &width, &height, &colors, &chars);
      headersize = colors + 1;
      yscale = (Double_t) new_height / (Double_t) height;
      xscale = (Double_t) new_width / (Double_t) width;
      totalheight = (colors + new_height + 1);

      if ((width != new_width) || (height != new_height)) {
         char **smalldata;
         Int_t    i, x1, y1, pixels;
         Double_t x, y;

         smalldata = new char* [totalheight + 1];

         smalldata[0] = new char[30];
         for (i = 1; i < headersize; i++)
            smalldata[i] = new char [strlen(data[i]) + 1];

         for (i = headersize; i < totalheight + 1; i++)
            smalldata[i] = new char[(new_width * chars) + 1];

         sprintf(smalldata[0], "%u %u %d %d", new_width, new_height, colors, chars);

         for (i = 1; i < headersize; i++) strcpy(smalldata[i], data[i]);

         y = headersize;
         for (y1 = headersize; y1 < (Int_t)new_height + headersize; y1++) {
            x = 0;
            for (x1 = 0; x1 < (Int_t)new_width; x1++) {
               for (pixels = 0; pixels < chars; pixels++)
                  smalldata[y1][x1+pixels] = data[(Int_t)y][(Int_t)x + pixels];
               x += 1.0 / xscale;
            }
            smalldata[y1][x1] = '\0';
            y += 1.0 / yscale;
         }

         retc = gVirtualX->CreatePictureFromData(fClient->GetDefaultRoot()->GetId(), smalldata,
                                                 pic->fPic, pic->fMask,
                                                 pic->fAttributes);

         for (i = 0; i < totalheight + 1; i++)
            delete [] smalldata[i];
         delete [] smalldata;

      } else {
         retc = gVirtualX->CreatePictureFromData(fClient->GetDefaultRoot()->GetId(), data,
                                                 pic->fPic, pic->fMask,
                                                 pic->fAttributes);
      }

      gVirtualX->DeletePictureData(data);
   }

   if (!retc) {
      delete pic;
      return 0;
   }

   fPicList->Add(pic);
   return pic;
}

//______________________________________________________________________________
void TGPicturePool::FreePicture(const TGPicture *fpic)
{
   // Remove picture from cache if nobody is using it anymore.

   if (!fPicList) return;

   TGPicture *pic = (TGPicture *)fPicList->FindObject(fpic);
   if (pic) {
      if (pic->RemoveReference() == 0) {
         fPicList->Remove(pic);
         delete pic;
      }
   }
}

//______________________________________________________________________________
TGPicturePool::~TGPicturePool()
{
   // Delete picture cache.

   if (fPicList) {
      fPicList->Delete();
      delete fPicList;
   }
}

//______________________________________________________________________________
void TGPicturePool::Print(Option_t *) const
{
   // List all pictures in the pool.

   if (fPicList)
      fPicList->Print();
   else
      Info("Print", "no pictures in picture pool");
}

//______________________________________________________________________________
void TGPicture::Draw(Handle_t id, GContext_t gc, Int_t x, Int_t y) const
{
   // Draw a picture.

   GCValues_t gcv;

   gcv.fMask = kGCClipMask | kGCClipXOrigin | kGCClipYOrigin;
   gcv.fClipMask = fMask;
   gcv.fClipXOrigin = x;
   gcv.fClipYOrigin = y;
   gVirtualX->ChangeGC(gc, &gcv);
   gVirtualX->CopyArea(fPic, id, gc, 0, 0, fAttributes.fWidth, fAttributes.fHeight,
                  x, y);
   gcv.fMask = kGCClipMask;
   gcv.fClipMask = kNone;
   gVirtualX->ChangeGC(gc, &gcv);
}

//______________________________________________________________________________
TGPicture::~TGPicture()
{
   // Delete picture object.

   if (fPic != kNone)
      gVirtualX->DeletePixmap(fPic);
   if (fMask != kNone)
      gVirtualX->DeletePixmap(fMask);
   if (fAttributes.fPixels)
      delete [] fAttributes.fPixels;
}

//______________________________________________________________________________
const char *TGPicture::HashName(const char *name, Int_t width, Int_t height)
{
   // Static function returning a unique name used to look up a picture.
   // The unique name has the form "name__widthxheight".

   static char hashName[256];

   sprintf(hashName, "%s__%dx%d", name, width, height);

   return hashName;
}

//______________________________________________________________________________
void TGPicture::Print(Option_t *) const
{
   // Print picture info.

   Printf("TGPicture: %s,%sref cnt = %u", GetName(),
          fScaled ? " scaled, " : " ", References());
}

//______________________________________________________________________________
TGSelectedPicture::TGSelectedPicture(const TGClient *client, const TGPicture *p) :
   TGPicture("")
{
   // Create a "selected" looking picture based on the original TGPicture.

   GCValues_t gcv;
   UInt_t     w, h;

   fClient = client;
   Window_t root  = fClient->GetDefaultRoot()->GetId();

   w = p->GetWidth();
   h = p->GetHeight();

   fPic  = gVirtualX->CreatePixmap(root, w, h);
   fMask = p->GetMask();

   fAttributes.fWidth  = w;
   fAttributes.fHeight = h;

   gVirtualX->CopyArea(p->GetPicture(), fPic, GetSelectedGC()(), 0, 0, w, h, 0, 0);

   gcv.fMask = kGCClipMask | kGCClipXOrigin | kGCClipYOrigin;
   gcv.fClipMask = p->GetMask();
   gcv.fClipXOrigin = 0;
   gcv.fClipYOrigin = 0;
   GetSelectedGC().SetAttributes(&gcv);

   gVirtualX->FillRectangle(fPic, GetSelectedGC()(), 0, 0, w, h);

   GetSelectedGC().SetClipMask(kNone);
}

//______________________________________________________________________________
TGSelectedPicture::~TGSelectedPicture()
{
   // Delete selected picture.

   // fMask was borrowed so should not be deleted by ~TGPicture.
   fMask = kNone;
}

//______________________________________________________________________________
TGGC &TGSelectedPicture::GetSelectedGC()
{
   if (!fgSelectedGC) {
      fgSelectedGC = new TGGC(*gClient->GetResourcePool()->GetFrameGC());
      fgSelectedGC->SetForeground(gClient->GetResourcePool()->GetSelectedBgndColor());
      fgSelectedGC->SetBackground(gClient->GetResourcePool()->GetBlackColor());
      fgSelectedGC->SetFillStyle(kFillStippled);
      fgSelectedGC->SetStipple(gClient->GetResourcePool()->GetCheckeredBitmap());
   }
   return *fgSelectedGC;
}
<|endoftext|>


<commit_before>
#include "AlembicPointsUtils.h"
#include <IParticleObjectExt.h>
#include <ParticleFlow/IParticleChannelID.h>
#include <ParticleFlow/IParticleChannelShape.h>
#include <ParticleFlow/IParticleContainer.h>
#include <ParticleFlow/IParticleGroup.h>
#include <ParticleFlow/IPFSystem.h>
#include <ParticleFlow/IPFActionList.h>
#include <ParticleFlow/PFSimpleOperator.h>
#include <ParticleFlow/IParticleChannels.h>
#include <ParticleFlow/IChannelContainer.h>
#include <ParticleFlow/IParticleChannelLifespan.h>
#include <ParticleFlow/IPFRender.h>
#include <ParticleFlow/IChannelContainer.h>
#include <ParticleFlow/IParticleContainer.h>
#include <map>
#include <vector>
#include "AlembicParticles.h"
#include "AlembicIntermediatePolyMesh3DSMax.h"
#include "AlembicWriteJob.h"

IPFRender* getIPFRender(Object* obj, TimeValue ticks)
{
	IPFActionList* particleActionList = GetPFActionListInterface(obj);
	if(!particleActionList){
		return NULL;
	}

	IPFRender* particleRender = NULL;

	int numActions = particleActionList->NumActions();
	for (int p = particleActionList->NumActions()-1; p >= 0; p -= 1)
	{
		INode *pActionNode = particleActionList->GetAction(p);
		Object *pActionObj = (pActionNode != NULL ? pActionNode->EvalWorldState(ticks).obj : NULL);

		if (pActionObj == NULL){
			continue;
		}
		//MSTR name;
		//pActionObj->GetClassName(name);

		IPFRender* particleRender = GetPFRenderInterface(pActionObj);
		if(particleRender){
			return particleRender;
		}
	}

	return NULL;
}

typedef std::map<INode*, int> groupParticleCountT;

bool getParticleSystemMesh(TimeValue ticks, Object* obj, INode* node, IntermediatePolyMesh3DSMax* mesh,
						   materialsMergeStr* pMatMerge, AlembicWriteJob * mJob, int nNumSamples)
{

    Matrix3 nodeWorldTM = node->GetObjTMAfterWSM(ticks);
    Alembic::Abc::M44d nodeWorldTrans;
    ConvertMaxMatrixToAlembicMatrix(nodeWorldTM, nodeWorldTrans);
	Alembic::Abc::M44d nodeWorldTransInv = nodeWorldTrans.inverse();

	IParticleObjectExt* particlesExt = GetParticleObjectExtInterface(obj);
	particlesExt->UpdateParticles(node, ticks);

	static NullView nullView;

	//static Mesh nullMesh;
	//I use this std::map to keep to obtain iteration index for each particle group.
	groupParticleCountT groupParticleCount;

	//TODO: currently the render operator settings will affect the export

	for(int i=0; i< particlesExt->NumParticles(); i++){
		INode *particleGroupNode = particlesExt->GetParticleGroup(i);

		Object *particleGroupObj = (particleGroupNode != NULL) ? particleGroupNode->EvalWorldState(ticks).obj : NULL;
		IParticleGroup* particleGroup = GetParticleGroupInterface(particleGroupObj);

		if( groupParticleCount.find(particleGroupNode) == groupParticleCount.end() ){
			groupParticleCount[particleGroupNode] = 0;
		}
		int meshId = groupParticleCount[particleGroupNode];
		groupParticleCount[particleGroupNode]++;

		::IObject *pCont = particleGroup->GetParticleContainer();
		::INode *pNode = particleGroup->GetParticleSystem();
		Mtl* pMtl = particleGroup->GetMaterial();

		pMatMerge->currUniqueHandle = Animatable::GetHandleByAnim(particleGroup->GetActionList());

		IPFRender* particleRender = getIPFRender(particleGroupObj, ticks);
		if(!particleRender){
			ESS_LOG_INFO("Error. Failed to obtain IPFRender interface.");
			return false;
		}

		Matrix3 meshTM;
		meshTM.IdentityMatrix();
		Interval meshValid;
		meshValid.SetInstant(ticks);

		particleRender->GetMultipleRenderMeshTM(pCont, ticks, obj, pNode, nullView, meshId, meshTM, meshValid);

		BOOL bNeedDelete = FALSE;
		Mesh* pMesh = particleRender->GetMultipleRenderMesh(pCont, ticks, obj, pNode, nullView, bNeedDelete, meshId);

		if(!pMesh || (pMesh && pMesh->numVerts == 0) ){
			ESS_LOG_INFO("Error. Null render mesh. Tick: "<<ticks<<" pid: "<<i);
			//return false;
		}

		//conpute vertex velocity, and save them immediately to final result
		//max meshes do not store per vertex velocities
		//we want the end result relative particle system space

		Imath::V4f pPosition4 = ConvertMaxPointToAlembicPoint4(*particlesExt->GetParticlePositionByIndex(i));
		Imath::V4f pVelocity4 = ConvertMaxVectorToAlembicVector4(*particlesExt->GetParticleSpeedByIndex(i));
		Alembic::Abc::Quatd pAngularVelocity(0.0, 0.0, 1.0, 0.0);
		ConvertMaxAngAxisToAlembicQuat(*particlesExt->GetParticleSpinByIndex(i), pAngularVelocity);
		Imath::M44d mAngularVelocity44 = pAngularVelocity.toMatrix44();

		//the values are returned in world space, so move them to particle space
		pPosition4 = pPosition4 * nodeWorldTransInv;
		pVelocity4 = pVelocity4 * nodeWorldTransInv;
		mAngularVelocity44 = mAngularVelocity44 * nodeWorldTransInv;

		Imath::V3f pPosition = Imath::V3f(pPosition4.x, pPosition4.y, pPosition4.z);
		Imath::V3f pVelocity = Imath::V3f(pVelocity4.x, pVelocity4.y, pVelocity4.z);
		Imath::M33d mAngularVelocity = extractRotation(mAngularVelocity44);

		for(int j=0; j<pMesh->getNumVerts(); j++){
			Imath::V3f meshVertex = ConvertMaxPointToAlembicPoint(pMesh->getVert(j) * meshTM);//the mesh vertex in particle system space
			Imath::V3f velocity = ((meshVertex - pPosition) * mAngularVelocity) + pVelocity;
			mesh->mVelocitiesVec.push_back(velocity);
		}

		if(i == 0){
			mesh->Save(mJob, ticks, pMesh, NULL, meshTM, pMtl, nNumSamples, pMatMerge);
		}
		else{
			IntermediatePolyMesh3DSMax currPolyMesh;
			currPolyMesh.Save(mJob, ticks, pMesh, NULL, meshTM, pMtl, nNumSamples, pMatMerge);
			bool bSuccess = mesh->mergeWith(currPolyMesh);
			if(!bSuccess){
				if(bNeedDelete){
					delete pMesh;
				}
				continue;
			}
		}

		if(bNeedDelete){
			delete pMesh;
		}
	}

	return true;
}

typedef std::map<INode*, IParticleGroup*> groupMapT;

void getParticleGroups(TimeValue ticks, Object* obj, INode* node, std::vector<IParticleGroup*>& groups)
{
	IParticleObjectExt* particlesExt = GetParticleObjectExtInterface(obj);
	particlesExt->UpdateParticles(node, ticks);

	groupMapT groupMap;

	for(int i=0; i< particlesExt->NumParticles(); i++){
		INode *particleGroupNode = particlesExt->GetParticleGroup(i);

		Object *particleGroupObj = (particleGroupNode != NULL) ? particleGroupNode->EvalWorldState(ticks).obj : NULL;
		IParticleGroup *particleGroup = GetParticleGroupInterface(particleGroupObj);

		groupMap[particleGroupNode] = particleGroup;
	}

	for( groupMapT::iterator it=groupMap.begin(); it!=groupMap.end(); it++)
	{
		groups.push_back((*it).second);
	}

}

void getParticleSystemRenderMeshes(TimeValue ticks, Object* obj, INode* node, std::vector<particleMeshData>& meshes)
{

	SimpleParticle* pSimpleParticle = (SimpleParticle*) obj->GetInterface(I_SIMPLEPARTICLEOBJ);
	if(pSimpleParticle){

		NullView nullView;

		AlembicParticles* pAlembicParticles = NULL;
		if(obj->CanConvertToType(ALEMBIC_SIMPLE_PARTICLE_CLASSID))
		{
			pAlembicParticles = reinterpret_cast<AlembicParticles*>(obj->ConvertToType(ticks, ALEMBIC_SIMPLE_PARTICLE_CLASSID));
		}

		if(pAlembicParticles){

			pSimpleParticle->Update(ticks, node);
			int numParticles = pSimpleParticle->parts.points.Count();

			for(int i=0; i<numParticles; i++){

				particleMeshData mdata;
				mdata.pMtl = NULL; //TODO: where get material?
				mdata.animHandle = 0; //TODO: where to get handle?
				Interval interval = FOREVER;
				pAlembicParticles->GetMultipleRenderMeshTM_Internal(ticks, NULL, nullView, i, mdata.meshTM, interval);

				//Matrix3 objectToWorld = inode->GetObjectTM( ticks );
				//mdata.meshTM = mdata.meshTM * Inverse(objectToWorld);

				mdata.pMesh = pAlembicParticles->GetMultipleRenderMesh(ticks, node /*system node or particle node?*/ , nullView, mdata.bNeedDelete, i);

				if(mdata.pMesh){
					meshes.push_back(mdata);
				}
			}
		}
		else{
			particleMeshData mdata;
			mdata.pMtl = NULL;//TODO: where to get material?
			mdata.animHandle = 0;//TODO: where to get handle?
			mdata.meshTM.IdentityMatrix();
			mdata.pMesh = pSimpleParticle->GetRenderMesh(ticks, node, nullView, mdata.bNeedDelete);
			if(mdata.pMesh){
				meshes.push_back(mdata);
			}
		}
	}
	else{

		IPFActionList* particleActionList = GetPFActionListInterface(obj);
		if(!particleActionList){
			return;
		}

		std::vector<IParticleGroup*> groups;
		getParticleGroups(ticks, obj, node, groups);

		IPFRender* particleRender = NULL;

		int numActions = particleActionList->NumActions();
		for (int p = particleActionList->NumActions()-1; p >= 0; p -= 1)
		{
			INode *pActionNode = particleActionList->GetAction(p);
			Object *pActionObj = (pActionNode != NULL ? pActionNode->EvalWorldState(ticks).obj : NULL);

			if (pActionObj == NULL){
				continue;
			}
			//MSTR name;
			//pActionObj->GetClassName(name);

			particleRender = GetPFRenderInterface(pActionObj);
			if(particleRender){
				break;
			}
		}

		if(particleRender){

			NullView nullView;

			for(int g=0; g<groups.size(); g++){

				::IObject *pCont = groups[g]->GetParticleContainer();
				::INode *pNode = groups[g]->GetParticleSystem();

				particleMeshData mdata;
				mdata.pMtl = groups[g]->GetMaterial();

				mdata.animHandle = Animatable::GetHandleByAnim(groups[g]->GetActionList());

				mdata.meshTM.IdentityMatrix();

				mdata.pMesh = particleRender->GetRenderMesh(pCont, ticks, obj, pNode, nullView, mdata.bNeedDelete);

				if(mdata.pMesh){
					meshes.push_back(mdata);
				}
			}
		}

	}
}

const Mesh* GetShapeMesh(IParticleObjectExt *pExt, int particleId, TimeValue ticks)
{

     // Go into the particle's action list
     INode *particleGroupNode = pExt->GetParticleGroup(particleId);
     Object *particleGroupObj = (particleGroupNode != NULL) ? particleGroupNode->EvalWorldState(ticks).obj : NULL;

	if (!particleGroupObj){
         return NULL;
	}

     IParticleGroup *particleGroup = GetParticleGroupInterface(particleGroupObj);
    ::IObject *pCont = particleGroup->GetParticleContainer();
    if(!pCont){
		return NULL;
	}

    IChannelContainer* chCont = GetChannelContainerInterface(pCont);
	if (!chCont){
		return NULL;
	}

	IParticleChannelMeshR* pShapeChannel = GetParticleChannelShapeRInterface(chCont);
	if(!pShapeChannel){
		return NULL;
	}

	//IParticleChannelINodeR* pNodeChannel = GetParticleChannelRefNodeRInterface(chCont);
	//if(!pNodeChannel){
	//	return;
	//}

	//int nSize = pShapeChannel->GetValueCount();
	//if(particleId >= nSize){
	//	return;
	//}

	//bool bIsShared = pShapeChannel->IsShared();//if true, particle meshes are not unique, and we should avoid writing out copies

	int nMeshIndex = pShapeChannel->GetValueIndex(particleId);
	const Mesh* pMesh = pShapeChannel->GetValueByIndex(nMeshIndex);

	if(!pMesh){
		int n=0;
		n++;
	}

	return pMesh;
}<commit_msg>- added in tick conversion factor to convert velocity to proper units - fixed incorrect rotational velocity calculation (its wrong to convert it to a quat, and then matrix)<commit_after>
#include "AlembicPointsUtils.h"
#include <IParticleObjectExt.h>
#include <ParticleFlow/IParticleChannelID.h>
#include <ParticleFlow/IParticleChannelShape.h>
#include <ParticleFlow/IParticleContainer.h>
#include <ParticleFlow/IParticleGroup.h>
#include <ParticleFlow/IPFSystem.h>
#include <ParticleFlow/IPFActionList.h>
#include <ParticleFlow/PFSimpleOperator.h>
#include <ParticleFlow/IParticleChannels.h>
#include <ParticleFlow/IChannelContainer.h>
#include <ParticleFlow/IParticleChannelLifespan.h>
#include <ParticleFlow/IPFRender.h>
#include <ParticleFlow/IChannelContainer.h>
#include <ParticleFlow/IParticleContainer.h>
#include <map>
#include <vector>
#include "AlembicParticles.h"
#include "AlembicIntermediatePolyMesh3DSMax.h"
#include "AlembicWriteJob.h"

IPFRender* getIPFRender(Object* obj, TimeValue ticks)
{
	IPFActionList* particleActionList = GetPFActionListInterface(obj);
	if(!particleActionList){
		return NULL;
	}

	IPFRender* particleRender = NULL;

	int numActions = particleActionList->NumActions();
	for (int p = particleActionList->NumActions()-1; p >= 0; p -= 1)
	{
		INode *pActionNode = particleActionList->GetAction(p);
		Object *pActionObj = (pActionNode != NULL ? pActionNode->EvalWorldState(ticks).obj : NULL);

		if (pActionObj == NULL){
			continue;
		}
		//MSTR name;
		//pActionObj->GetClassName(name);

		IPFRender* particleRender = GetPFRenderInterface(pActionObj);
		if(particleRender){
			return particleRender;
		}
	}

	return NULL;
}

typedef std::map<INode*, int> groupParticleCountT;

bool getParticleSystemMesh(TimeValue ticks, Object* obj, INode* node, IntermediatePolyMesh3DSMax* mesh,
						   materialsMergeStr* pMatMerge, AlembicWriteJob * mJob, int nNumSamples)
{

    Matrix3 nodeWorldTM = node->GetObjTMAfterWSM(ticks);
    Alembic::Abc::M44d nodeWorldTrans;
    ConvertMaxMatrixToAlembicMatrix(nodeWorldTM, nodeWorldTrans);
	Alembic::Abc::M44d nodeWorldTransInv = nodeWorldTrans.inverse();

	IParticleObjectExt* particlesExt = GetParticleObjectExtInterface(obj);
	particlesExt->UpdateParticles(node, ticks);

	static NullView nullView;

	//static Mesh nullMesh;
	//I use this std::map to keep to obtain iteration index for each particle group.
	groupParticleCountT groupParticleCount;

	//TODO: currently the render operator settings will affect the export

	static const bool ENABLE_VELOCITY_EXPORT = true;

	//static Imath::V4f prevPos(0.0, 0.0, 0.0, 0.0);

	for(int i=0; i< particlesExt->NumParticles(); i++){
		INode *particleGroupNode = particlesExt->GetParticleGroup(i);

		Object *particleGroupObj = (particleGroupNode != NULL) ? particleGroupNode->EvalWorldState(ticks).obj : NULL;
		IParticleGroup* particleGroup = GetParticleGroupInterface(particleGroupObj);

		if( groupParticleCount.find(particleGroupNode) == groupParticleCount.end() ){
			groupParticleCount[particleGroupNode] = 0;
		}
		int meshId = groupParticleCount[particleGroupNode];
		groupParticleCount[particleGroupNode]++;

		::IObject *pCont = particleGroup->GetParticleContainer();
		::INode *pNode = particleGroup->GetParticleSystem();
		Mtl* pMtl = particleGroup->GetMaterial();

		pMatMerge->currUniqueHandle = Animatable::GetHandleByAnim(particleGroup->GetActionList());

		IPFRender* particleRender = getIPFRender(particleGroupObj, ticks);
		if(!particleRender){
			ESS_LOG_INFO("Error. Failed to obtain IPFRender interface.");
			return false;
		}

		Matrix3 meshTM;
		meshTM.IdentityMatrix();
		Interval meshValid;
		meshValid.SetInstant(ticks);

		particleRender->GetMultipleRenderMeshTM(pCont, ticks, obj, pNode, nullView, meshId, meshTM, meshValid);

		BOOL bNeedDelete = FALSE;
		Mesh* pMesh = particleRender->GetMultipleRenderMesh(pCont, ticks, obj, pNode, nullView, bNeedDelete, meshId);

		if(!pMesh || (pMesh && pMesh->numVerts == 0) ){
			ESS_LOG_INFO("Error. Null render mesh. Tick: "<<ticks<<" pid: "<<i);
			//return false;
		}

		//conpute vertex velocity, and save them immediately to final result
		//max meshes do not store per vertex velocities
		//we want the end result relative particle system space

		if(ENABLE_VELOCITY_EXPORT){
			Imath::V4f pPosition4 = ConvertMaxPointToAlembicPoint4(*particlesExt->GetParticlePositionByIndex(i));
			Imath::V4f pVelocity4 = ConvertMaxVectorToAlembicVector4(*particlesExt->GetParticleSpeedByIndex(i) * 200 ); //you have the wrong units

			//Imath::V4f pVel = pPosition4 - prevPos;
			//Imath::V4f pVels = pVelocity4 * fps;
			//float factor = pVel.y / pVelocity4.y;
			//prevPos = pPosition4;

			//Alembic::Abc::Quatd pAngularVelocity(0.0, 0.0, 1.0, 0.0);
			//ConvertMaxAngAxisToAlembicQuatSpecial(*particlesExt->GetParticleSpinByIndex(i), pAngularVelocity);
			//Imath::M44d mAngularVelocity44 = pAngularVelocity.toMatrix44();//TODO: wrong!

			AngAxis angAxis = *particlesExt->GetParticleSpinByIndex(i);
			Imath::V3f pAngularVelocity = ConvertMaxNormalToAlembicNormal(angAxis.axis);
			pAngularVelocity = pAngularVelocity * angAxis.angle * 200;

			//the values are returned in world space, so move them to particle space
			pPosition4 = pPosition4 * nodeWorldTransInv;
			pVelocity4 = pVelocity4 * nodeWorldTransInv;
			//mAngularVelocity44 = mAngularVelocity44 * nodeWorldTransInv;
			pAngularVelocity = pAngularVelocity * nodeWorldTransInv;

			Imath::V3f pPosition = Imath::V3f(pPosition4.x, pPosition4.y, pPosition4.z);
			Imath::V3f pVelocity = Imath::V3f(pVelocity4.x, pVelocity4.y, pVelocity4.z);
			//Imath::M33d mAngularVelocity = extractRotation(mAngularVelocity44);

			for(int j=0; j<pMesh->getNumVerts(); j++){
				Imath::V3f meshVertex = ConvertMaxPointToAlembicPoint(pMesh->getVert(j) * meshTM);//the mesh vertex in particle system space
				Imath::V3f vVelocity = (meshVertex - pPosition) * pAngularVelocity;
				mesh->mVelocitiesVec.push_back(vVelocity + pVelocity);
			}

		}

		if(i == 0){
			mesh->Save(mJob, ticks, pMesh, NULL, meshTM, pMtl, nNumSamples, pMatMerge);
		}
		else{
			IntermediatePolyMesh3DSMax currPolyMesh;
			currPolyMesh.Save(mJob, ticks, pMesh, NULL, meshTM, pMtl, nNumSamples, pMatMerge);
			bool bSuccess = mesh->mergeWith(currPolyMesh);
			if(!bSuccess){
				if(bNeedDelete){
					delete pMesh;
				}
				continue;
			}
		}

		if(bNeedDelete){
			delete pMesh;
		}
	}

	return true;
}

typedef std::map<INode*, IParticleGroup*> groupMapT;

void getParticleGroups(TimeValue ticks, Object* obj, INode* node, std::vector<IParticleGroup*>& groups)
{
	IParticleObjectExt* particlesExt = GetParticleObjectExtInterface(obj);
	particlesExt->UpdateParticles(node, ticks);

	groupMapT groupMap;

	for(int i=0; i< particlesExt->NumParticles(); i++){
		INode *particleGroupNode = particlesExt->GetParticleGroup(i);

		Object *particleGroupObj = (particleGroupNode != NULL) ? particleGroupNode->EvalWorldState(ticks).obj : NULL;
		IParticleGroup *particleGroup = GetParticleGroupInterface(particleGroupObj);

		groupMap[particleGroupNode] = particleGroup;
	}

	for( groupMapT::iterator it=groupMap.begin(); it!=groupMap.end(); it++)
	{
		groups.push_back((*it).second);
	}

}

void getParticleSystemRenderMeshes(TimeValue ticks, Object* obj, INode* node, std::vector<particleMeshData>& meshes)
{

	SimpleParticle* pSimpleParticle = (SimpleParticle*) obj->GetInterface(I_SIMPLEPARTICLEOBJ);
	if(pSimpleParticle){

		NullView nullView;

		AlembicParticles* pAlembicParticles = NULL;
		if(obj->CanConvertToType(ALEMBIC_SIMPLE_PARTICLE_CLASSID))
		{
			pAlembicParticles = reinterpret_cast<AlembicParticles*>(obj->ConvertToType(ticks, ALEMBIC_SIMPLE_PARTICLE_CLASSID));
		}

		if(pAlembicParticles){

			pSimpleParticle->Update(ticks, node);
			int numParticles = pSimpleParticle->parts.points.Count();

			for(int i=0; i<numParticles; i++){

				particleMeshData mdata;
				mdata.pMtl = NULL; //TODO: where get material?
				mdata.animHandle = 0; //TODO: where to get handle?
				Interval interval = FOREVER;
				pAlembicParticles->GetMultipleRenderMeshTM_Internal(ticks, NULL, nullView, i, mdata.meshTM, interval);

				//Matrix3 objectToWorld = inode->GetObjectTM( ticks );
				//mdata.meshTM = mdata.meshTM * Inverse(objectToWorld);

				mdata.pMesh = pAlembicParticles->GetMultipleRenderMesh(ticks, node /*system node or particle node?*/ , nullView, mdata.bNeedDelete, i);

				if(mdata.pMesh){
					meshes.push_back(mdata);
				}
			}
		}
		else{
			particleMeshData mdata;
			mdata.pMtl = NULL;//TODO: where to get material?
			mdata.animHandle = 0;//TODO: where to get handle?
			mdata.meshTM.IdentityMatrix();
			mdata.pMesh = pSimpleParticle->GetRenderMesh(ticks, node, nullView, mdata.bNeedDelete);
			if(mdata.pMesh){
				meshes.push_back(mdata);
			}
		}
	}
	else{

		IPFActionList* particleActionList = GetPFActionListInterface(obj);
		if(!particleActionList){
			return;
		}

		std::vector<IParticleGroup*> groups;
		getParticleGroups(ticks, obj, node, groups);

		IPFRender* particleRender = NULL;

		int numActions = particleActionList->NumActions();
		for (int p = particleActionList->NumActions()-1; p >= 0; p -= 1)
		{
			INode *pActionNode = particleActionList->GetAction(p);
			Object *pActionObj = (pActionNode != NULL ? pActionNode->EvalWorldState(ticks).obj : NULL);

			if (pActionObj == NULL){
				continue;
			}
			//MSTR name;
			//pActionObj->GetClassName(name);

			particleRender = GetPFRenderInterface(pActionObj);
			if(particleRender){
				break;
			}
		}

		if(particleRender){

			NullView nullView;

			for(int g=0; g<groups.size(); g++){

				::IObject *pCont = groups[g]->GetParticleContainer();
				::INode *pNode = groups[g]->GetParticleSystem();

				particleMeshData mdata;
				mdata.pMtl = groups[g]->GetMaterial();

				mdata.animHandle = Animatable::GetHandleByAnim(groups[g]->GetActionList());

				mdata.meshTM.IdentityMatrix();

				mdata.pMesh = particleRender->GetRenderMesh(pCont, ticks, obj, pNode, nullView, mdata.bNeedDelete);

				if(mdata.pMesh){
					meshes.push_back(mdata);
				}
			}
		}

	}
}

const Mesh* GetShapeMesh(IParticleObjectExt *pExt, int particleId, TimeValue ticks)
{

     // Go into the particle's action list
     INode *particleGroupNode = pExt->GetParticleGroup(particleId);
     Object *particleGroupObj = (particleGroupNode != NULL) ? particleGroupNode->EvalWorldState(ticks).obj : NULL;

	if (!particleGroupObj){
         return NULL;
	}

     IParticleGroup *particleGroup = GetParticleGroupInterface(particleGroupObj);
    ::IObject *pCont = particleGroup->GetParticleContainer();
    if(!pCont){
		return NULL;
	}

    IChannelContainer* chCont = GetChannelContainerInterface(pCont);
	if (!chCont){
		return NULL;
	}

	IParticleChannelMeshR* pShapeChannel = GetParticleChannelShapeRInterface(chCont);
	if(!pShapeChannel){
		return NULL;
	}

	//IParticleChannelINodeR* pNodeChannel = GetParticleChannelRefNodeRInterface(chCont);
	//if(!pNodeChannel){
	//	return;
	//}

	//int nSize = pShapeChannel->GetValueCount();
	//if(particleId >= nSize){
	//	return;
	//}

	//bool bIsShared = pShapeChannel->IsShared();//if true, particle meshes are not unique, and we should avoid writing out copies

	int nMeshIndex = pShapeChannel->GetValueIndex(particleId);
	const Mesh* pMesh = pShapeChannel->GetValueByIndex(nMeshIndex);

	if(!pMesh){
		int n=0;
		n++;
	}

	return pMesh;
}<|endoftext|>


<commit_before>/** Copyright (C) 2016, 2017 European Spallation Source ERIC */

#include <cassert>
#include <common/Trace.h>
#include <cstring>
#include <multigrid/mgmesytec/Data.h>

// #undef TRC_LEVEL
// #define TRC_LEVEL TRC_L_INF

void MesytecData::mesytec_parse_n_words(uint32_t * buffer, int nWords) {
  uint32_t *datap = buffer;
  int wordsleft = nWords;

  // Sneak peek on time although it is last in packet
  int time = -1;
  uint32_t * tptr = (buffer + nWords - 1);
  if ((*tptr & 0xc0000000) == 0xc0000000) {
    time = *tptr & 0x3fffffff;
  }

  int module = -1;
  int readdata = -1;
  int bus = -1;
  int addr = -1;
  int adc = -1;

  while (wordsleft > 0) {
    auto datatype = *datap & 0xff000000;

    switch (datatype) {
      case MesytecData::mesytecHeader:
        readdata = *datap & 0x000003ff;
        assert(nWords > readdata);
        module = (*datap & 0x00ff0000) >> 16;
        DTRACE(INF, "Data len %d (words), module %d\n", readdata, module);
      break;

      case MesytecData::mesytecData:
        readouts++;
        bus = (*datap & 0x0f000000) >> 24;
        addr = (*datap & 0x00fff000) >> 12;
        adc = (*datap & 0x00000fff);
        #ifdef DUMPTOFILE
        mgdata.tofile("%d, %d, %d, %d\n", time, bus, addr, adc);
        #endif
        DTRACE(DEB, "%d, %d, %d, %d\n", time, bus, addr, adc);
      break;

      case MesytecData::mesytecTimeOffset:
        bus = (*datap & 0x0f000000) >> 24;
        DTRACE(INF, "Timeoffset (bus %d) %d\n", bus, (*datap & 0x0000ffff));
      break;

      default:
        if ((*datap & 0xc0000000) == 0xc0000000) {
            DTRACE(INF, "Timestamp: %d\n", *datap & 0x3fffffff);
          break;
        }

        if (*datap == 0x00000000) {
          //DTRACE(INF, "End of Data\n");
          break;
        }

        DTRACE(WAR, "Unknown: 0x%08x\n", *datap);
      break;
    }
    wordsleft--;
    datap++;
  }
}

int MesytecData::parse(const char *buffer, int size) {
  readouts = 0;

  int bytesleft = size;

  if (buffer[0] != 0x60) {
    return -error::EUNSUPP;
  }

  if (size < 19) {
    return -error::ESIZE;
  }

  uint32_t *datap = (uint32_t*)(buffer + 3);
  bytesleft -= 3;

  while (bytesleft > 16) {
    if ((*datap & 0x000000ff) != 0x58) {
      return -error::EUNSUPP;
    }
    auto len = ntohs((*datap & 0x00ffff00) >> 8);
    DTRACE(INF, "SIS 0x%08x,  Datalen %d\n", *datap, len);
    datap++;
    bytesleft -= 4;

    if ((*datap & 0xff000000) != sisBeginReadout) {
      return -error::EHEADER;
    }
    datap++;
    mesytec_parse_n_words(datap, len - 3);

    datap += (len - 3);
    bytesleft -= (len -3)*4;

    if (*datap != 0x87654321) {
      XTRACE(PROCESS, WAR, "Protocol mismatch, expected 0x87654321\n");
      return -error::EHEADER;
    }
    datap++;
    bytesleft -= 4;

    if ((*datap & 0xff000000) != sisEndReadout) {
      return -error::EHEADER;
    }
    datap++;
    bytesleft -= 4;
  }
  return error::OK;
}
<commit_msg>added include for ntohs<commit_after>/** Copyright (C) 2016, 2017 European Spallation Source ERIC */

#include <arpa/inet.h>
#include <cassert>
#include <common/Trace.h>
#include <cstring>
#include <multigrid/mgmesytec/Data.h>

// #undef TRC_LEVEL
// #define TRC_LEVEL TRC_L_INF

void MesytecData::mesytec_parse_n_words(uint32_t * buffer, int nWords) {
  uint32_t *datap = buffer;
  int wordsleft = nWords;

  // Sneak peek on time although it is last in packet
  int time = -1;
  uint32_t * tptr = (buffer + nWords - 1);
  if ((*tptr & 0xc0000000) == 0xc0000000) {
    time = *tptr & 0x3fffffff;
  }

  int module = -1;
  int readdata = -1;
  int bus = -1;
  int addr = -1;
  int adc = -1;

  while (wordsleft > 0) {
    auto datatype = *datap & 0xff000000;

    switch (datatype) {
      case MesytecData::mesytecHeader:
        readdata = *datap & 0x000003ff;
        assert(nWords > readdata);
        module = (*datap & 0x00ff0000) >> 16;
        DTRACE(INF, "Data len %d (words), module %d\n", readdata, module);
      break;

      case MesytecData::mesytecData:
        readouts++;
        bus = (*datap & 0x0f000000) >> 24;
        addr = (*datap & 0x00fff000) >> 12;
        adc = (*datap & 0x00000fff);
        #ifdef DUMPTOFILE
        mgdata.tofile("%d, %d, %d, %d\n", time, bus, addr, adc);
        #endif
        DTRACE(DEB, "%d, %d, %d, %d\n", time, bus, addr, adc);
      break;

      case MesytecData::mesytecTimeOffset:
        bus = (*datap & 0x0f000000) >> 24;
        DTRACE(INF, "Timeoffset (bus %d) %d\n", bus, (*datap & 0x0000ffff));
      break;

      default:
        if ((*datap & 0xc0000000) == 0xc0000000) {
            DTRACE(INF, "Timestamp: %d\n", *datap & 0x3fffffff);
          break;
        }

        if (*datap == 0x00000000) {
          //DTRACE(INF, "End of Data\n");
          break;
        }

        DTRACE(WAR, "Unknown: 0x%08x\n", *datap);
      break;
    }
    wordsleft--;
    datap++;
  }
}

int MesytecData::parse(const char *buffer, int size) {
  readouts = 0;

  int bytesleft = size;

  if (buffer[0] != 0x60) {
    return -error::EUNSUPP;
  }

  if (size < 19) {
    return -error::ESIZE;
  }

  uint32_t *datap = (uint32_t*)(buffer + 3);
  bytesleft -= 3;

  while (bytesleft > 16) {
    if ((*datap & 0x000000ff) != 0x58) {
      return -error::EUNSUPP;
    }
    auto len = ntohs((*datap & 0x00ffff00) >> 8);
    DTRACE(INF, "SIS 0x%08x,  Datalen %d\n", *datap, len);
    datap++;
    bytesleft -= 4;

    if ((*datap & 0xff000000) != sisBeginReadout) {
      return -error::EHEADER;
    }
    datap++;
    mesytec_parse_n_words(datap, len - 3);

    datap += (len - 3);
    bytesleft -= (len -3)*4;

    if (*datap != 0x87654321) {
      XTRACE(PROCESS, WAR, "Protocol mismatch, expected 0x87654321\n");
      return -error::EHEADER;
    }
    datap++;
    bytesleft -= 4;

    if ((*datap & 0xff000000) != sisEndReadout) {
      return -error::EHEADER;
    }
    datap++;
    bytesleft -= 4;
  }
  return error::OK;
}
<|endoftext|>