Logo Search packages:      
Sourcecode: blender version File versions

KX_IpoActuator.cpp

/**
 * Do Ipo stuff
 *
 * $Id: KX_IpoActuator.cpp,v 1.12 2004/12/01 08:43:58 kester Exp $
 *
 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
 *
 * 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. The Blender
 * Foundation also sells licenses for use in proprietary software under
 * the Blender License.  See http://www.blender.org/BL/ for information
 * about this.
 *
 * 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.
 *
 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
 * All rights reserved.
 *
 * The Original Code is: all of this file.
 *
 * Contributor(s): none yet.
 *
 * ***** END GPL/BL DUAL LICENSE BLOCK *****
 */

#if defined (__sgi)
#include <math.h>
#else
#include <cmath>
#endif
 
#include "KX_IpoActuator.h"
#include "KX_GameObject.h"

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "KX_KetsjiEngine.h"

/* ------------------------------------------------------------------------- */
/* Type strings                                                              */
/* ------------------------------------------------------------------------- */

STR_String KX_IpoActuator::S_KX_ACT_IPO_PLAY_STRING      = "Play";
STR_String KX_IpoActuator::S_KX_ACT_IPO_PINGPONG_STRING  = "PingPong";
STR_String KX_IpoActuator::S_KX_ACT_IPO_FLIPPER_STRING   = "Flipper";
STR_String KX_IpoActuator::S_KX_ACT_IPO_LOOPSTOP_STRING  = "LoopStop";
STR_String KX_IpoActuator::S_KX_ACT_IPO_LOOPEND_STRING   = "LoopEnd";
STR_String KX_IpoActuator::S_KX_ACT_IPO_KEY2KEY_STRING   = "Key2key";
STR_String KX_IpoActuator::S_KX_ACT_IPO_FROM_PROP_STRING = "FromProp";

/* ------------------------------------------------------------------------- */
/* Native functions                                                          */
/* ------------------------------------------------------------------------- */
/** Another poltergeist? This seems to be a very transient class... */
00066 class CIpoAction : public CAction
{
      float       m_curtime;
      bool        m_resurse;
      KX_GameObject* m_gameobj;
      bool        m_ipo_as_force;
      bool        m_force_ipo_local;

public:
      CIpoAction(KX_GameObject* gameobj,
            float curtime,
            bool recurse, 
            bool ipo_as_force,
            bool force_ipo_local) :
        m_curtime(curtime) ,
        m_resurse(recurse),
        m_gameobj(gameobj),
        m_ipo_as_force(ipo_as_force),
        m_force_ipo_local(force_ipo_local) 
        {
              /* intentionally empty */
        };

      virtual void Execute() const
      {
            m_gameobj->UpdateIPO(
                  m_curtime, 
                  m_resurse, 
                  m_ipo_as_force, 
                  m_force_ipo_local);
      };

};

KX_IpoActuator::KX_IpoActuator(SCA_IObject* gameobj,
                                             const STR_String& propname,
                                             float starttime,
                                             float endtime,
                                             bool recurse,
                                             int acttype,
                                             bool ipo_as_force,
                                             bool force_ipo_local,
                                             PyTypeObject* T) 
      : SCA_IActuator(gameobj,T),
      m_bNegativeEvent(false),
      m_startframe (starttime),
      m_endframe(endtime),
      m_recurse(recurse),
      m_localtime(starttime),
      m_starttime(-1.0),
      m_direction(1),
      m_propname(propname),
      m_ipo_as_force(ipo_as_force),
      m_force_ipo_local(force_ipo_local),
      m_type((IpoActType)acttype)
{
      // intentionally empty
}

void KX_IpoActuator::SetStart(float starttime) 
{ 
      m_startframe=starttime;
}

void KX_IpoActuator::SetEnd(float endtime) 
{ 
      m_endframe=endtime;
}

bool KX_IpoActuator::ClampLocalTime()
{
      if (m_startframe < m_endframe)
      {
            if (m_localtime < m_startframe)
            {
                  m_localtime = m_startframe;
                  return true;
            } 
            else if (m_localtime > m_endframe)
            {
                  m_localtime = m_endframe;
                  return true;
            }
      } else {
            if (m_localtime > m_startframe)
            {
                  m_localtime = m_startframe;
                  return true;
            }
            else if (m_localtime < m_endframe)
            {
                  m_localtime = m_endframe;
                  return true;
            }
      }
      return false;
}

void KX_IpoActuator::SetStartTime(float curtime)
{
      float direction = m_startframe < m_endframe ? 1.0 : -1.0;
      
      if (m_direction > 0)
            m_starttime = curtime - direction*(m_localtime - m_startframe)/KX_FIXED_FRAME_PER_SEC;
      else
            m_starttime = curtime - direction*(m_endframe - m_localtime)/KX_FIXED_FRAME_PER_SEC;
}

void KX_IpoActuator::SetLocalTime(float curtime)
{
      float delta_time = (curtime - m_starttime)*KX_FIXED_FRAME_PER_SEC;
      
      if (m_endframe < m_startframe)
            delta_time = -delta_time;

      if (m_direction > 0)
            m_localtime = m_startframe + delta_time;
      else
            m_localtime = m_endframe - delta_time;
}

bool KX_IpoActuator::Update(double curtime, bool frame)
{
      // result = true if animation has to be continued, false if animation stops
      // maybe there are events for us in the queue !
      bool bNegativeEvent = false;
      int numevents = m_events.size();

      if (frame)
      {
            for (vector<CValue*>::iterator i=m_events.end(); !(i==m_events.begin());)
            {
                  --i;
                  if ((*i)->GetNumber() == 0.0f)
                        bNegativeEvent = true;
                  
                  (*i)->Release();
            }
            m_events.clear();
      
            if (bNegativeEvent)
            {
                  RemoveAllEvents();
            }
      }
      
      double  start_smaller_then_end = ( m_startframe < m_endframe ? 1.0 : -1.0);

      bool result=true;
      if (m_starttime < 0.0)
            m_starttime = curtime;
      
      switch (m_type)
      {
            
      case KX_ACT_IPO_PLAY:
      {
            // Check if playing forwards.  result = ! finished
            if (start_smaller_then_end > 0.0)
                  result = (m_localtime < m_endframe && !(m_localtime == m_startframe && bNegativeEvent));
            else
                  result = (m_localtime > m_endframe && !(m_localtime == m_startframe && bNegativeEvent));
            
            if (result)
            {
                  SetLocalTime(curtime);
            
                  /* Perform clamping */
                  ClampLocalTime();
                  
                  CIpoAction ipoaction(
                        (KX_GameObject*)GetParent(), 
                        m_localtime, 
                        m_recurse, 
                        m_ipo_as_force,
                        m_force_ipo_local);
                  GetParent()->Execute(ipoaction);
            } else
            {
                  m_localtime=m_startframe;
                  m_starttime=curtime;
                  m_direction=1;
            }
            break;
      }
      case KX_ACT_IPO_PINGPONG:
      {
            result = true;
            if (bNegativeEvent && ((m_localtime == m_startframe )|| (m_localtime == m_endframe)))
                  result = false;
            else
                  SetLocalTime(curtime);
                  
            if (ClampLocalTime())
            {
                  result = false;
                  m_direction = -m_direction;
            }
            
            CIpoAction ipoaction(
                  (KX_GameObject*) GetParent(),
                  m_localtime,
                  m_recurse, 
                  m_ipo_as_force,
                  m_force_ipo_local);
            GetParent()->Execute(ipoaction);
            break;
      }
      case KX_ACT_IPO_FLIPPER:
      {
            result = true;
            if (numevents)
            {
                  if (bNegativeEvent)
                        m_direction = -1;
                  else
                        m_direction = 1;
                  SetStartTime(curtime);
            }
            
            SetLocalTime(curtime);
            
            if (ClampLocalTime() && m_localtime == m_startframe)
                  result = false;
                  
            CIpoAction ipoaction(
                  (KX_GameObject*) GetParent(),
                  m_localtime,
                  m_recurse,
                  m_ipo_as_force,
                  m_force_ipo_local);
            GetParent()->Execute(ipoaction);
            break;
      }

      case KX_ACT_IPO_LOOPSTOP:
      {
            if (numevents)
            {
                  if (bNegativeEvent)
                  {
                        result = false;
                        m_bNegativeEvent = false;
                        numevents = 0;
                  }
                  SetStartTime(curtime);
            } // fall through to loopend, and quit the ipo animation immediatly 
      }
      case KX_ACT_IPO_LOOPEND:
      {
            if (numevents){
                  if (bNegativeEvent){
                        m_bNegativeEvent = true;
                  }
            }
            
            if (bNegativeEvent && m_localtime == m_startframe){
                  result = false;
            } 
            else
            {
                  if (m_localtime*start_smaller_then_end < m_endframe*start_smaller_then_end)
                  {
                        SetLocalTime(curtime);
                  }
                  else{
                        if (!m_bNegativeEvent){
                              /* Perform wraparound */
                              SetLocalTime(curtime);
                              m_localtime = m_startframe + fmod(m_localtime, m_startframe - m_endframe);
                              SetStartTime(curtime);
                        }
                        else
                        {     
                              /* Perform clamping */
                              m_localtime=m_endframe;
                              result = false;
                              m_bNegativeEvent = false;
                        }
                  }
            }
            
            CIpoAction ipoaction(
                  (KX_GameObject*) GetParent(),
                  m_localtime,
                  m_recurse,
                  m_ipo_as_force,
                  m_force_ipo_local);
            GetParent()->Execute(ipoaction);
            break;
      }
      
      case KX_ACT_IPO_KEY2KEY:
      {
            // not implemented yet
            result = false;
            break;
      }
      
      case KX_ACT_IPO_FROM_PROP:
      {
            result = !bNegativeEvent;

            CValue* propval = GetParent()->GetProperty(m_propname);
            if (propval)
            {
                  float target = propval->GetNumber(); 
                  float delta_time = (curtime - m_starttime)*KX_FIXED_FRAME_PER_SEC;
                  if (target > m_localtime)
                  {
                        m_localtime += delta_time;
                        if (m_localtime > target)
                              m_localtime = target;
                  }
                  else
                  {
                        m_localtime -= delta_time;
                        if (m_localtime < target)
                              m_localtime = target;
                  }
      
                  CIpoAction ipoaction(
                        (KX_GameObject*) GetParent(),
                        m_localtime,
                        m_recurse,
                        m_ipo_as_force,
                        m_force_ipo_local);
                  GetParent()->Execute(ipoaction);

            } else
            {
                  result = false;
            }
            break;
      }
            
      default:
            result = false;
      }
      
      if (!result && m_type != KX_ACT_IPO_LOOPSTOP)
            m_starttime = -1.0;

      return result;
}

KX_IpoActuator::IpoActType KX_IpoActuator::string2mode(char* modename) {
      IpoActType res = KX_ACT_IPO_NODEF;

      if (modename == S_KX_ACT_IPO_PLAY_STRING) { 
            res = KX_ACT_IPO_PLAY;
      } else if (modename == S_KX_ACT_IPO_PINGPONG_STRING) {
            res = KX_ACT_IPO_PINGPONG;
      } else if (modename == S_KX_ACT_IPO_FLIPPER_STRING) {
            res = KX_ACT_IPO_FLIPPER;
      } else if (modename == S_KX_ACT_IPO_LOOPSTOP_STRING) {
            res = KX_ACT_IPO_LOOPSTOP;
      } else if (modename == S_KX_ACT_IPO_LOOPEND_STRING) {
            res = KX_ACT_IPO_LOOPEND;
      } else if (modename == S_KX_ACT_IPO_KEY2KEY_STRING) {
            res = KX_ACT_IPO_KEY2KEY;
      } else if (modename == S_KX_ACT_IPO_FROM_PROP_STRING) {
            res = KX_ACT_IPO_FROM_PROP;
      }

      return res;
}

/* ------------------------------------------------------------------------- */
/* Python functions                                                          */
/* ------------------------------------------------------------------------- */



/* Integration hooks ------------------------------------------------------- */
PyTypeObject KX_IpoActuator::Type = {
      PyObject_HEAD_INIT(&PyType_Type)
      0,
      "KX_IpoActuator",
      sizeof(KX_IpoActuator),
      0,
      PyDestructor,
      0,
      __getattr,
      __setattr,
      0, //&MyPyCompare,
      __repr,
      0, //&cvalue_as_number,
      0,
      0,
      0,
      0
};

PyParentObject KX_IpoActuator::Parents[] = {
      &KX_IpoActuator::Type,
      &SCA_IActuator::Type,
      &SCA_ILogicBrick::Type,
      &CValue::Type,
      NULL
};

PyMethodDef KX_IpoActuator::Methods[] = {
      {"set", (PyCFunction) KX_IpoActuator::sPySet, 
            METH_VARARGS, Set_doc},
      {"setProperty", (PyCFunction) KX_IpoActuator::sPySetProperty, 
            METH_VARARGS, SetProperty_doc},
      {"setStart", (PyCFunction) KX_IpoActuator::sPySetStart, 
            METH_VARARGS, SetStart_doc},
      {"getStart", (PyCFunction) KX_IpoActuator::sPyGetStart, 
            METH_VARARGS, GetStart_doc},
      {"setEnd", (PyCFunction) KX_IpoActuator::sPySetEnd, 
            METH_VARARGS, SetEnd_doc},
      {"getEnd", (PyCFunction) KX_IpoActuator::sPyGetEnd, 
            METH_VARARGS, GetEnd_doc},
      {"setIpoAsForce", (PyCFunction) KX_IpoActuator::sPySetIpoAsForce, 
            METH_VARARGS, SetIpoAsForce_doc},
      {"getIpoAsForce", (PyCFunction) KX_IpoActuator::sPyGetIpoAsForce, 
            METH_VARARGS, GetIpoAsForce_doc},
      {"setType", (PyCFunction) KX_IpoActuator::sPySetType, 
            METH_VARARGS, SetType_doc},
      {"getType", (PyCFunction) KX_IpoActuator::sPyGetType, 
            METH_VARARGS, GetType_doc},   
      {"setForceIpoActsLocal", (PyCFunction) KX_IpoActuator::sPySetForceIpoActsLocal,
            METH_VARARGS, SetForceIpoActsLocal_doc},
      {"getForceIpoActsLocal", (PyCFunction) KX_IpoActuator::sPyGetForceIpoActsLocal,
            METH_VARARGS, GetForceIpoActsLocal_doc},
      {NULL,NULL} //Sentinel
};

PyObject* KX_IpoActuator::_getattr(const STR_String& attr) {
      _getattr_up(SCA_IActuator);
}



/* set --------------------------------------------------------------------- */
char KX_IpoActuator::Set_doc[] = 
"set(mode, startframe, endframe, force?)\n"
"\t - mode:       Play, PingPong, Flipper, LoopStop, LoopEnd or FromProp (string)\n"
"\t - startframe: first frame to use (int)\n"
"\t - endframe  : last frame to use (int)\n"
"\t - force?    : interpret this ipo as a force? (KX_TRUE, KX_FALSE)"
"\tSet the properties of the actuator.\n";
PyObject* KX_IpoActuator::PySet(PyObject* self, 
                                                PyObject* args, 
                                                PyObject* kwds) {
      /* sets modes PLAY, PINGPONG, FLIPPER, LOOPSTOP, LOOPEND                 */
      /* arg 1 = mode string, arg 2 = startframe, arg3 = stopframe,            */
      /* arg4 = force toggle                                                   */
      char* mode;
      int forceToggle;
      IpoActType modenum;
      int startFrame, stopFrame;
      if(!PyArg_ParseTuple(args, "siii", &mode, &startFrame, 
                                     &stopFrame, &forceToggle)) {
            return NULL;
      }
      modenum = string2mode(mode);
      
      switch (modenum) {
      case KX_ACT_IPO_PLAY:
      case KX_ACT_IPO_PINGPONG:
      case KX_ACT_IPO_FLIPPER:
      case KX_ACT_IPO_LOOPSTOP:
      case KX_ACT_IPO_LOOPEND:
            m_type         = modenum;
            m_startframe    = startFrame;
            m_endframe      = stopFrame;
            m_ipo_as_force = PyArgToBool(forceToggle);
            break;
      default:
            ; /* error */
      }

      Py_Return;
}

/* set property  ----------------------------------------------------------- */
char KX_IpoActuator::SetProperty_doc[] = 
"setProperty(propname)\n"
"\t - propname: name of the property (string)\n"
"\tSet the property to be used in FromProp mode.\n";
PyObject* KX_IpoActuator::PySetProperty(PyObject* self, 
                                                            PyObject* args, 
                                                            PyObject* kwds) {
      /* mode is implicit here, but not supported yet... */
      /* args: property */
      char *propertyName;
      if(!PyArg_ParseTuple(args, "s", &propertyName)) {
            return NULL;
      }

      m_propname = propertyName;
      
      Py_Return;
}

/* 4. setStart:                                                              */
char KX_IpoActuator::SetStart_doc[] = 
"setStart(frame)\n"
"\t - frame: first frame to use (int)\n"
"\tSet the frame from which the ipo starts playing.\n";
PyObject* KX_IpoActuator::PySetStart(PyObject* self, 
                                                       PyObject* args, 
                                                       PyObject* kwds) {
      float startArg;
      if(!PyArg_ParseTuple(args, "f", &startArg)) {
            return NULL;            
      }
      
      m_startframe = startArg;

      Py_Return;
}
/* 5. getStart:                                                              */
char KX_IpoActuator::GetStart_doc[] = 
"getStart()\n"
"\tReturns the frame from which the ipo starts playing.\n";
PyObject* KX_IpoActuator::PyGetStart(PyObject* self, 
                                                       PyObject* args, 
                                                       PyObject* kwds) {
      return PyFloat_FromDouble(m_startframe);
}

/* 6. setEnd:                                                                */
char KX_IpoActuator::SetEnd_doc[] = 
"setEnd(frame)\n"
"\t - frame: last frame to use (int)\n"
"\tSet the frame at which the ipo stops playing.\n";
PyObject* KX_IpoActuator::PySetEnd(PyObject* self, 
                                                   PyObject* args, 
                                                   PyObject* kwds) {
      float endArg;
      if(!PyArg_ParseTuple(args, "f", &endArg)) {
            return NULL;            
      }
      
      m_endframe = endArg;

      Py_Return;
}
/* 7. getEnd:                                                                */
char KX_IpoActuator::GetEnd_doc[] = 
"getEnd()\n"
"\tReturns the frame at which the ipo stops playing.\n";
PyObject* KX_IpoActuator::PyGetEnd(PyObject* self, 
                                                   PyObject* args, 
                                                   PyObject* kwds) {
      return PyFloat_FromDouble(m_endframe);
}

/* 6. setIpoAsForce:                                                           */
char KX_IpoActuator::SetIpoAsForce_doc[] = 
"setIpoAsForce(force?)\n"
"\t - force?    : interpret this ipo as a force? (KX_TRUE, KX_FALSE)\n"
"\tSet whether to interpret the ipo as a force rather than a displacement.\n";
PyObject* KX_IpoActuator::PySetIpoAsForce(PyObject* self, 
                                                              PyObject* args, 
                                                              PyObject* kwds) { 
      int boolArg;
      
      if (!PyArg_ParseTuple(args, "i", &boolArg)) {
            return NULL;
      }

      m_ipo_as_force = PyArgToBool(boolArg);
      
      Py_Return;  
}
/* 7. getIpoAsForce:                                                         */
char KX_IpoActuator::GetIpoAsForce_doc[] = 
"getIpoAsForce()\n"
"\tReturns whether to interpret the ipo as a force rather than a displacement.\n";
PyObject* KX_IpoActuator::PyGetIpoAsForce(PyObject* self, 
                                                              PyObject* args, 
                                                              PyObject* kwds) {
      return BoolToPyArg(m_ipo_as_force);
}

/* 8. setType:                                                               */
char KX_IpoActuator::SetType_doc[] = 
"setType(mode)\n"
"\t - mode: Play, PingPong, Flipper, LoopStop, LoopEnd or FromProp (string)\n"
"\tSet the operation mode of the actuator.\n";
PyObject* KX_IpoActuator::PySetType(PyObject* self, 
                                                      PyObject* args, 
                                                      PyObject* kwds) {
      int typeArg;
      
      if (!PyArg_ParseTuple(args, "i", &typeArg)) {
            return NULL;
      }
      
      if ( (typeArg > KX_ACT_IPO_NODEF) 
             && (typeArg < KX_ACT_IPO_KEY2KEY) ) {
            m_type = (IpoActType) typeArg;
      }
      
      Py_Return;
}
/* 9. getType:                                                               */
char KX_IpoActuator::GetType_doc[] = 
"getType()\n"
"\tReturns the operation mode of the actuator.\n";
PyObject* KX_IpoActuator::PyGetType(PyObject* self, 
                                                      PyObject* args, 
                                                      PyObject* kwds) {
      return PyInt_FromLong(m_type);
}

/* 10. setForceIpoActsLocal:                                                 */
char KX_IpoActuator::SetForceIpoActsLocal_doc[] = 
"setForceIpoActsLocal(local?)\n"
"\t - local?    : Apply the ipo-as-force in the object's local\n"
"\t               coordinates? (KX_TRUE, KX_FALSE)\n"
"\tSet whether to apply the force in the object's local\n"
"\tcoordinates rather than the world global coordinates.\n";
PyObject* KX_IpoActuator::PySetForceIpoActsLocal(PyObject* self, 
                                                                     PyObject* args, 
                                                                       PyObject* kwds) { 
      int boolArg;
      
      if (!PyArg_ParseTuple(args, "i", &boolArg)) {
            return NULL;
      }

      m_force_ipo_local = PyArgToBool(boolArg);
      
      Py_Return;  
}
/* 11. getForceIpoActsLocal:                                                */
char KX_IpoActuator::GetForceIpoActsLocal_doc[] = 
"getForceIpoActsLocal()\n"
"\tReturn whether to apply the force in the object's local\n"
"\tcoordinates rather than the world global coordinates.\n";
PyObject* KX_IpoActuator::PyGetForceIpoActsLocal(PyObject* self, 
                                                                     PyObject* args, 
                                                                     PyObject* kwds) {
      return BoolToPyArg(m_force_ipo_local);
}


/* eof */

Generated by  Doxygen 1.6.0   Back to index