Blob Blame Raw


#include "ttimer.h"
#include "tthreadmessage.h"
#include "texception.h"

#ifdef _WIN32

#include <windows.h>
#include <mmsystem.h>
#include <cstdlib>

// moto strano: se togliamo l'include della glut non linka
#include <GL/glut.h>

//------------------------------------------------------------------------------

namespace {

void CALLBACK ElapsedTimeCB(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1,
                            DWORD dw2);
};

//------------------------------------------------------------------------------

class TTimer::Imp {
public:
  Imp(std::string name, UINT timerRes, TTimer::Type type, TTimer *timer);
  ~Imp();

  void start(UINT delay) {
    if (m_started) throw TException("The timer is already started");

    m_timerID = timeSetEvent(delay, m_timerRes, (LPTIMECALLBACK)ElapsedTimeCB,
                             (DWORD)this, m_type | TIME_CALLBACK_FUNCTION);

    m_delay = delay;
    m_ticks = 0;
    if (m_timerID == NULL) throw TException("Unable to start timer");

    m_started = true;
  }

  void stop() {
    if (m_started) timeKillEvent(m_timerID);
    m_started = false;
  }

  std::string getName() { return m_name; }
  TUINT64 getTicks() { return m_ticks; }
  UINT getDelay() { return m_delay; }

  std::string m_name;

  UINT m_timerRes;
  UINT m_type;
  TTimer *m_timer;

  UINT m_timerID;
  UINT m_delay;
  TUINT64 m_ticks;
  bool m_started;

  TGenericTimerAction *m_action;
};

//------------------------------------------------------------------------------

TTimer::Imp::Imp(std::string name, UINT timerRes, TTimer::Type type,
                 TTimer *timer)
    : m_name(name)
    , m_timerRes(timerRes)
    , m_timer(timer)
    , m_type(type)
    , m_timerID(NULL)
    , m_ticks(0)
    , m_delay(0)
    , m_started(false)
    , m_action(0) {
  TIMECAPS tc;

  if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
    throw TException("Unable to create timer");
  }

  m_timerRes = std::min((int)std::max((int)tc.wPeriodMin, (int)m_timerRes),
                        (int)tc.wPeriodMax);
  timeBeginPeriod(m_timerRes);

  switch (type) {
  case TTimer::OneShot:
    m_type = TIME_ONESHOT;
    break;

  case TTimer::Periodic:
    m_type = TIME_PERIODIC;
    break;

  default:
    throw TException("Unexpected timer type");
    break;
  }
}

//------------------------------------------------------------------------------

TTimer::Imp::~Imp() {
  stop();
  timeEndPeriod(m_timerRes);

  if (m_action) delete m_action;
}

//------------------------------------------------------------------------------

namespace {

void CALLBACK ElapsedTimeCB(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1,
                            DWORD dw2) {
  TTimer::Imp *imp = reinterpret_cast<TTimer::Imp *>(dwUser);
  imp->m_ticks++;
  if (imp->m_action) imp->m_action->sendCommand(imp->m_ticks);
}
};
#elif defined(LINUX)

#include <SDL_timer.h>
#include <SDL.h>
#include "tthread.h"
namespace {
Uint32 ElapsedTimeCB(Uint32 interval, void *param);
}

class TTimer::Imp {
public:
  Imp(std::string name, UINT timerRes, TTimer::Type type, TTimer *timer)
      : m_action(0), m_ticks(0) {}
  ~Imp() {}

  void start(UINT delay) {
    static bool first = true;
    if (first) {
      SDL_Init(SDL_INIT_TIMER);
      first = false;
    }
    m_timerID = SDL_AddTimer(delay, ElapsedTimeCB, this);
  }

  void stop() { SDL_RemoveTimer(m_timerID); }

  std::string getName() { return m_name; }
  TUINT64 getTicks() { return m_ticks; }
  UINT getDelay() { return m_delay; }

  std::string m_name;

  UINT m_timerRes;
  UINT m_type;
  TTimer *m_timer;

  SDL_TimerID m_timerID;
  UINT m_delay;
  TUINT64 m_ticks;
  bool m_started;

  TGenericTimerAction *m_action;
};

class SendCommandMSG final : public TThread::Message {
  TTimer::Imp *m_ztimp;

public:
  SendCommandMSG(TTimer::Imp *ztimp) : TThread::Message(), m_ztimp(ztimp) {}
  ~SendCommandMSG() {}
  TThread::Message *clone() const { return new SendCommandMSG(*this); }
  void onDeliver() {
    if (m_ztimp->m_action) m_ztimp->m_action->sendCommand(m_ztimp->m_ticks);
  }
};

namespace {
Uint32 ElapsedTimeCB(Uint32 interval, void *param) {
  TTimer::Imp *imp = reinterpret_cast<TTimer::Imp *>(param);
  imp->m_ticks++;
  SendCommandMSG(imp).send();
  return interval;
}
}

#elif defined(__sgi)
class TTimer::Imp {
public:
  Imp(std::string name, UINT timerRes, TTimer::Type type, TTimer *timer)
      : m_action(0) {}
  ~Imp() {}

  void start(UINT delay) {
    if (m_started) throw TException("The timer is already started");

    m_started = true;
  }

  void stop() { m_started = false; }

  std::string getName() { return m_name; }
  TUINT64 getTicks() { return m_ticks; }
  UINT getDelay() { return m_delay; }

  std::string m_name;

  UINT m_timerRes;
  UINT m_type;
  TTimer *m_timer;

  UINT m_timerID;
  UINT m_delay;
  TUINT64 m_ticks;
  bool m_started;

  TGenericTimerAction *m_action;
};
#elif defined(MACOSX)
class TTimer::Imp {
public:
  Imp(std::string name, UINT timerRes, TTimer::Type type, TTimer *timer)
      : m_action(0) {}
  ~Imp() {}

  void start(UINT delay) {
    if (m_started) throw TException("The timer is already started");
    throw TException("The timer is not yet available under MAC :(");
    m_started = true;
  }

  void stop() { m_started = false; }

  std::string getName() { return m_name; }
  TUINT64 getTicks() { return m_ticks; }
  UINT getDelay() { return m_delay; }

  std::string m_name;

  UINT m_timerRes;
  UINT m_type;
  TTimer *m_timer;

  UINT m_timerID;
  UINT m_delay;
  TUINT64 m_ticks;
  bool m_started;

  TGenericTimerAction *m_action;
};

#endif

//===============================================================================
//
//  TTimer
//
//===============================================================================

TTimer::TTimer(const std::string &name, UINT timerRes, Type type)
    : m_imp(new TTimer::Imp(name, timerRes, type, this)) {}

//--------------------------------------------------------------------------------

TTimer::~TTimer() {}

//--------------------------------------------------------------------------------

void TTimer::start(UINT delay) { m_imp->start(delay); }

//--------------------------------------------------------------------------------

bool TTimer::isStarted() const { return m_imp->m_started; }

//--------------------------------------------------------------------------------

void TTimer::stop() { m_imp->stop(); }

//--------------------------------------------------------------------------------

std::string TTimer::getName() const { return m_imp->getName(); }

//--------------------------------------------------------------------------------

TUINT64 TTimer::getTicks() const { return m_imp->getTicks(); }

//--------------------------------------------------------------------------------

UINT TTimer::getDelay() const { return m_imp->getDelay(); }

//--------------------------------------------------------------------------------

void TTimer::setAction(TGenericTimerAction *action) {
  if (m_imp->m_action) delete m_imp->m_action;

  m_imp->m_action = action;
}